prefs.m 18.2 KB
Newer Older
1
/*****************************************************************************
2
 * prefs.m: MacOS X module for vlc
3
 *****************************************************************************
4
 * Copyright (C) 2002-2015 VLC authors and VideoLAN
5
 * $Id$
6
 *
7
 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8
 *          Derk-Jan Hartman <hartman at videolan dot org>
9
 *          Felix Paul Kühne <fkuehne at videolan dot org>
10 11 12 13 14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
15
 *
16 17 18 19 20 21 22
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 25
 *****************************************************************************/

26
/* VLCPrefs manages the main preferences dialog
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   the class is related to wxwindows intf, PrefsPanel */
/* VLCTreeItem should contain:
   - the children of the treeitem
   - the associated prefs widgets
   - the documentview with all the prefs widgets in it
   - a saveChanges action
   - a revertChanges action
   - a redraw view action
   - the children action should generate a list of the treeitems children (to be used by VLCPrefs datasource)

   The class is sort of a mix of wxwindows intfs, PrefsTreeCtrl and ConfigTreeData
*/
/* VLCConfigControl are subclassed NSView's containing and managing individual config items
   the classes are VERY closely related to wxwindows ConfigControls */

42 43 44 45
/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
46
#include <sys/param.h>                                    /* for MAXPATHLEN */
47 48
#include <string.h>

49 50 51 52
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

53
#include <vlc_common.h>
54 55
#include <vlc_config_cat.h>

56
#import "CompatibilityFixes.h"
57
#import "VLCMain.h"
58
#import "prefs.h"
59
#import "VLCSimplePrefsController.h"
60
#import "prefs_widgets.h"
61
#import "VLCCoreInteraction.h"
62
#import <vlc_actions.h>
63
#import <vlc_modules.h>
64
#import <vlc_plugin.h>
65

66 67 68
#define LEFTMARGIN  18
#define RIGHTMARGIN 18

69 70
/* /!\ Warning: Unreadable code :/ */

71 72 73 74 75 76 77 78 79 80 81 82
@interface VLCFlippedView : NSView
@end

@implementation VLCFlippedView

- (BOOL)isFlipped
{
    return YES;
}

@end

83 84
@interface VLCTreeItem : NSObject
{
85 86
    NSString *_name;
    NSMutableArray *_children;
87
    NSMutableArray *_options;
88 89
    NSMutableArray *_subviews;
}
90
@property (readwrite, unsafe_unretained) VLCPrefs *prefsViewController;
91

92
- (id)initWithName:(NSString*)name;
93

94
- (int)numberOfChildren;
95
- (VLCTreeItem *)childAtIndex:(NSInteger)i_index;
96

97
- (NSString *)name;
98
- (NSMutableArray *)children;
99
- (NSMutableArray *)options;
100
- (void)showView;
101 102 103 104 105
- (void)applyChanges;
- (void)resetView;

@end

106
/* CONFIG_SUBCAT */
107 108 109 110
@interface VLCTreeSubCategoryItem : VLCTreeItem
{
    int _subCategory;
}
111
+ (VLCTreeSubCategoryItem *)subCategoryTreeItemWithSubCategory:(int)subCategory;
112 113 114 115
- (id)initWithSubCategory:(int)subCategory;
- (int)subCategory;
@end

116 117 118
/* Plugin daughters */
@interface VLCTreePluginItem : VLCTreeItem
{
119 120
    module_config_t * _configItems;
    unsigned int _configSize;
121 122 123
}
+ (VLCTreePluginItem *)pluginTreeItemWithPlugin:(module_t *)plugin;
- (id)initWithPlugin:(module_t *)plugin;
124 125 126

- (module_config_t *)configItems;
- (unsigned int)configSize;
127 128 129
@end

/* CONFIG_CAT */
130 131 132 133 134 135
@interface VLCTreeCategoryItem : VLCTreeItem
{
    int _category;
}
+ (VLCTreeCategoryItem *)categoryTreeItemWithCategory:(int)category;
- (id)initWithCategory:(int)category;
136

137 138 139 140
- (int)category;
- (VLCTreeSubCategoryItem *)itemRepresentingSubCategory:(int)category;
@end

141
/* individual options. */
142
@interface VLCTreeLeafItem : VLCTreeItem
143 144 145 146 147
{
    module_config_t * _configItem;
}
- (id)initWithConfigItem:(module_config_t *)configItem;
- (module_config_t *)configItem;
148 149
@end

150
@interface VLCTreeMainItem : VLCTreePluginItem
151 152 153
- (VLCTreeCategoryItem *)itemRepresentingCategory:(int)category;
@end

154 155
#pragma mark -

156
/*****************************************************************************
157
 * VLCPrefs implementation
158
 *****************************************************************************/
159 160 161

@interface VLCPrefs()
{
162
    VLCTreeMainItem *_rootTreeItem;
163
    NSView *o_emptyView;
164 165 166 167
    NSMutableDictionary *o_save_prefs;
}
@end

168 169
@implementation VLCPrefs

170 171 172
- (id)init
{
    self = [super initWithWindowNibName:@"Preferences"];
173 174 175 176
    if (self) {
        o_emptyView = [[NSView alloc] init];
        _rootTreeItem = [[VLCTreeMainItem alloc] init];
    }
177 178 179 180 181 182

    return self;
}

- (void)windowDidLoad

183
{
184 185
    [self.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
    [self.window setHidesOnDeactivate:YES];
186

187
    [self.window setTitle: _NS("Preferences")];
188 189 190 191
    [_saveButton setTitle: _NS("Save")];
    [_cancelButton setTitle: _NS("Cancel")];
    [_resetButton setTitle: _NS("Reset All")];
    [_showBasicButton setTitle: _NS("Show Basic")];
192

193 194 195 196
    [_prefsView setBorderType: NSGrooveBorder];
    [_prefsView setHasVerticalScroller: YES];
    [_prefsView setDrawsBackground: NO];
    [_prefsView setDocumentView: o_emptyView];
197
    [self.window layoutIfNeeded];
198
    [_tree selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO];
199
}
200

201 202
- (void)setTitle: (NSString *) o_title_name
{
203
    [self.titleLabel setStringValue: o_title_name];
204 205
}

206
- (void)showPrefsWithLevel:(NSInteger)iWindow_level
207
{
208 209 210
    [self.window setLevel: iWindow_level];
    [self.window center];
    [self.window makeKeyAndOrderFront:self];
211
    [_rootTreeItem resetView];
212
}
213

214 215
- (IBAction)savePrefs: (id)sender
{
216
    /* TODO: call savePrefs on Root item */
217
    [_rootTreeItem applyChanges];
218
    [[VLCCoreInteraction sharedInstance] fixIntfSettings];
219
    config_SaveConfigFile(getIntf());
220
    [self.window orderOut:self];
221
}
222

223 224
- (IBAction)closePrefs: (id)sender
{
225
    [self.window orderOut:self];
226 227
}

228
- (IBAction)showSimplePrefs: (id)sender
229
{
230
    [self.window orderOut: self];
231
    [[[VLCMain sharedInstance] simplePreferences] showSimplePrefs];
232 233
}

234 235
- (IBAction)resetPrefs:(id)sender
{
236
    [[[VLCMain sharedInstance] simplePreferences] resetPreferences:sender];
237 238
}

239 240 241 242 243 244
- (void)loadConfigTree
{
}

- (void)outlineViewSelectionIsChanging:(NSNotification *)o_notification
{
245 246
}

247
/* update the document view to the view of the selected tree item */
248 249
- (void)outlineViewSelectionDidChange:(NSNotification *)o_notification
{
250 251 252
    VLCTreeItem *treeItem = [_tree itemAtRow:[_tree selectedRow]];
    treeItem.prefsViewController = self;
    [treeItem showView];
253
    [_tree expandItem:[_tree itemAtRow:[_tree selectedRow]]];
254 255
}

256
@end
257

258
@implementation VLCPrefs (NSTableDataSource)
259

260
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
261 262
{
    return (item == nil) ? [_rootTreeItem numberOfChildren] : [item numberOfChildren];
263 264
}

265 266
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
267
    return (item == nil) ? [_rootTreeItem numberOfChildren] : [item numberOfChildren];
268 269
}

270
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
271 272
{
    return (item == nil) ? (id)[_rootTreeItem childAtIndex:index]: (id)[item childAtIndex:index];
273 274
}

275 276 277
- (id)outlineView:(NSOutlineView *)outlineView
    objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
278
    return (item == nil) ? @"" : [item name];
279
}
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301

#pragma mark -
#pragma mark split view delegate
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex
{
    return 300.;
}

- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)dividerIndex
{
    return 100.;
}

- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview
{
    return NO;
}

- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)subview
{
    return [splitView.subviews objectAtIndex:0] != subview;
}
302

303
@end
304

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
#pragma mark -
#pragma mark (Root class for all TreeItems)
@implementation VLCTreeItem

- (id)initWithName:(NSString*)name
{
    self = [super init];
    if (self != nil)
        _name = name;

    return self;
}

- (VLCTreeItem *)childAtIndex:(NSInteger)i_index
{
    return [[self children] objectAtIndex:i_index];
}

- (int)numberOfChildren
{
    return [[self children] count];
}

- (NSString *)name
{
    return _name;
}

333
- (void)showView
334
{
335
    NSScrollView *prefsView = self.prefsViewController.prefsView;
336 337 338
    NSRect s_vrc;
    NSView *view;

339
    [self.prefsViewController setTitle: [self name]];
340
    s_vrc = [[prefsView contentView] bounds]; s_vrc.size.height -= 4;
341
    view = [[VLCFlippedView alloc] initWithFrame: s_vrc];
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
    [view setAutoresizingMask: NSViewWidthSizable | NSViewMinYMargin | NSViewMaxYMargin];

    if (!_subviews) {
        _subviews = [[NSMutableArray alloc] initWithCapacity:10];

        NSUInteger count = [[self options] count];
        for (NSUInteger i = 0; i < count; i++) {
            VLCTreeLeafItem * item = [[self options] objectAtIndex:i];

            VLCConfigControl *control;
            control = [VLCConfigControl newControl:[item configItem] withView:view];
            if (control) {
                [control setAutoresizingMask: NSViewMaxYMargin | NSViewWidthSizable];
                [_subviews addObject: control];
            }
        }
    }

    assert(view);

    int i_lastItem = 0;
    int i_yPos = -2;
    int i_max_label = 0;

    NSEnumerator *enumerator = [_subviews objectEnumerator];
    VLCConfigControl *widget;
    NSRect frame;

    while((widget = [enumerator nextObject])) {
        if (i_max_label < [widget labelSize])
            i_max_label = [widget labelSize];
    }

    enumerator = [_subviews objectEnumerator];
    while((widget = [enumerator nextObject])) {
        int i_widget;

        i_widget = [widget viewType];
        i_yPos += [VLCConfigControl calcVerticalMargin:i_widget lastItem:i_lastItem];
        [widget setYPos:i_yPos];
        frame = [widget frame];
        frame.size.width = [view frame].size.width - LEFTMARGIN - RIGHTMARGIN;
        [widget setFrame:frame];
        [widget alignWithXPosition: i_max_label];
        i_yPos += [widget frame].size.height;
        i_lastItem = i_widget;
        [view addSubview:widget];
    }

    frame = [view frame];
    frame.size.height = i_yPos;
    [view setFrame:frame];
    [prefsView setDocumentView:view];
}

- (void)applyChanges
{
    NSUInteger i;
    NSUInteger count = [_subviews count];
    for (i = 0 ; i < count ; i++)
        [[_subviews objectAtIndex:i] applyChanges];

    count = [_children count];
    for (i = 0 ; i < count ; i++)
        [[_children objectAtIndex:i] applyChanges];
}

- (void)resetView
{
    NSUInteger count = [_subviews count];
    for (NSUInteger i = 0 ; i < count ; i++)
        [[_subviews objectAtIndex:i] resetValues];

    count = [_options count];
    for (NSUInteger i = 0 ; i < count ; i++)
        [[_options objectAtIndex:i] resetView];

    count = [_children count];
    for (NSUInteger i = 0 ; i < count ; i++)
        [[_children objectAtIndex:i] resetView];

}

- (NSMutableArray *)children
{
    if (!_children)
        _children = [[NSMutableArray alloc] init];
    return _children;
}

- (NSMutableArray *)options
{
    if (!_options)
        _options = [[NSMutableArray alloc] init];
    return _options;
}
@end

440 441
#pragma mark -
@implementation VLCTreeMainItem
442

443
- (VLCTreeCategoryItem *)itemRepresentingCategory:(int)category
444
{
445
    NSUInteger childrenCount = [[self children] count];
446
    for (int i = 0; i < childrenCount; i++) {
447
        VLCTreeCategoryItem * categoryItem = [[self children] objectAtIndex:i];
448
        if ([categoryItem category] == category)
449
            return categoryItem;
450
    }
451
    return nil;
452
}
453

454 455
- (bool)isSubCategoryGeneral:(int)category
{
456
    if (category == SUBCAT_VIDEO_GENERAL ||
457 458 459 460 461
          category == SUBCAT_ADVANCED_MISC ||
          category == SUBCAT_INPUT_GENERAL ||
          category == SUBCAT_INTERFACE_GENERAL ||
          category == SUBCAT_SOUT_GENERAL||
          category == SUBCAT_PLAYLIST_GENERAL||
462
          category == SUBCAT_AUDIO_GENERAL) {
463 464 465 466 467
        return true;
    }
    return false;
}

468 469
/* Creates and returns the array of children
 * Loads children incrementally */
470
- (NSMutableArray *)children
471
{
472
    if (_children) return _children;
473
    _children = [[NSMutableArray alloc] init];
474

475 476
    /* List the modules */
    size_t count, i;
477 478
    module_t ** modules = module_list_get(&count);
    if (!modules) return nil;
479

480 481
    /* Build a tree of the plugins */
    /* Add the capabilities */
482
    for (i = 0; i < count; i++) {
483 484
        VLCTreeCategoryItem * categoryItem = nil;
        VLCTreeSubCategoryItem * subCategoryItem = nil;
485
        VLCTreePluginItem * pluginItem = nil;
486
        module_config_t *p_configs = NULL;
487
        int lastsubcat = 0;
488 489 490 491 492 493
        unsigned int confsize;

        module_t * p_module = modules[i];

        /* Exclude empty plugins (submodules don't have config */
        /* options, they are stored in the parent module) */
494
        if (module_is_main(p_module)) {
495
            pluginItem = self;
496
            _configItems = module_config_get(p_module, &confsize);
497 498 499 500 501 502
            _configSize = confsize;
        } else {
            pluginItem = [VLCTreePluginItem pluginTreeItemWithPlugin: p_module];
            confsize = [pluginItem configSize];
        }
        p_configs = [pluginItem configItems];
503

504
        unsigned int j;
505
        for (j = 0; j < confsize; j++) {
506
            int configType = p_configs[j].i_type;
507
            if (configType == CONFIG_CATEGORY) {
508
                categoryItem = [self itemRepresentingCategory:p_configs[j].value.i];
509
                if (!categoryItem) {
510
                    categoryItem = [VLCTreeCategoryItem categoryTreeItemWithCategory:p_configs[j].value.i];
511 512
                    if (categoryItem)
                        [[self children] addObject:categoryItem];
513
                }
514
            }
515
            else if (configType == CONFIG_SUBCATEGORY) {
516
                lastsubcat = p_configs[j].value.i;
517
                if (categoryItem && ![self isSubCategoryGeneral:lastsubcat]) {
518
                    subCategoryItem = [categoryItem itemRepresentingSubCategory:lastsubcat];
519
                    if (!subCategoryItem) {
520
                        subCategoryItem = [VLCTreeSubCategoryItem subCategoryTreeItemWithSubCategory:lastsubcat];
521 522
                        if (subCategoryItem)
                            [[categoryItem children] addObject:subCategoryItem];
523
                    }
524
                }
525
            }
526

527
            if (module_is_main(p_module) && (CONFIG_ITEM(configType) || configType == CONFIG_SECTION)) {
528
                if (categoryItem && [self isSubCategoryGeneral:lastsubcat])
529
                    [[categoryItem options] addObject:[[VLCTreeLeafItem alloc] initWithConfigItem:&p_configs[j]]];
530
                else if (subCategoryItem)
531
                    [[subCategoryItem options] addObject:[[VLCTreeLeafItem alloc] initWithConfigItem:&p_configs[j]]];
532
            }
533
            else if (!module_is_main(p_module) && (CONFIG_ITEM(configType) || configType == CONFIG_SECTION)) {
534
                if (![[subCategoryItem children] containsObject: pluginItem])
535
                    [[subCategoryItem children] addObject:pluginItem];
536 537

                if (pluginItem)
538
                    [[pluginItem options] addObject:[[VLCTreeLeafItem alloc] initWithConfigItem:&p_configs[j]]];
539
            }
540
        }
541
    }
542
    module_list_free(modules);
543
    return _children;
544
}
545
@end
546

547 548 549 550
#pragma mark -
@implementation VLCTreeCategoryItem
+ (VLCTreeCategoryItem *)categoryTreeItemWithCategory:(int)category
{
551
    if (!config_CategoryNameGet(category)) return nil;
552
    return [[[self class] alloc] initWithCategory:category];
553
}
554

555
- (id)initWithCategory:(int)category
556
{
557 558
    NSString * name = _NS(config_CategoryNameGet(category));
    if (self = [super initWithName:name]) {
559
        _category = category;
560
        //_help = [_NS(config_CategoryHelpGet(category)) retain];
561 562
    }
    return self;
563
}
564

565
- (VLCTreeSubCategoryItem *)itemRepresentingSubCategory:(int)subCategory
566
{
567
    assert([self isKindOfClass:[VLCTreeCategoryItem class]]);
568
    NSUInteger childrenCount = [[self children] count];
569
    for (NSUInteger i = 0; i < childrenCount; i++) {
570
        VLCTreeSubCategoryItem * subCategoryItem = [[self children] objectAtIndex:i];
571
        if ([subCategoryItem subCategory] == subCategory)
572 573 574
            return subCategoryItem;
    }
    return nil;
575
}
576

577
- (int)category
578
{
579
    return _category;
580
}
581
@end
582

583 584 585
#pragma mark -
@implementation VLCTreeSubCategoryItem
- (id)initWithSubCategory:(int)subCategory
586
{
587 588
    NSString * name = _NS(config_CategoryNameGet(subCategory));
    if (self = [super initWithName:name]) {
589
        _subCategory = subCategory;
590
        //_help = [_NS(config_CategoryHelpGet(subCategory)) retain];
591 592
    }
    return self;
593 594
}

595
+ (VLCTreeSubCategoryItem *)subCategoryTreeItemWithSubCategory:(int)subCategory
596
{
597 598
    if (!config_CategoryNameGet(subCategory))
        return nil;
599
    return [[[self class] alloc] initWithSubCategory:subCategory];
600 601
}

602 603 604
- (int)subCategory
{
    return _subCategory;
605 606
}

607 608
@end

609 610 611 612
#pragma mark -
@implementation VLCTreePluginItem
- (id)initWithPlugin:(module_t *)plugin
{
613
    NSString * name = _NS(module_get_name(plugin, false));
614 615
    if (self = [super initWithName:name]) {
        _configItems = module_config_get(plugin, &_configSize);
616
        //_plugin = plugin;
617
        //_help = [_NS(config_CategoryHelpGet(subCategory)) retain];
618 619 620 621 622 623
    }
    return self;
}

+ (VLCTreePluginItem *)pluginTreeItemWithPlugin:(module_t *)plugin
{
624
    return [[[self class] alloc] initWithPlugin:plugin];
625 626
}

627 628
- (void)dealloc
{
629
    module_config_free(_configItems);
630 631 632 633 634 635 636 637 638 639 640 641
}

- (module_config_t *)configItems
{
    return _configItems;
}

- (unsigned int)configSize
{
    return _configSize;
}

642 643
@end

644 645
#pragma mark -
@implementation VLCTreeLeafItem
646 647 648

- (id)initWithConfigItem: (module_config_t *) configItem
{
649
    NSString *name = toNSStr(configItem->psz_name);
650
    self = [super initWithName:name];
651
    if (self != nil)
652
        _configItem = configItem;
653

654 655 656 657 658 659 660
    return self;
}

- (module_config_t *)configItem
{
    return _configItem;
}
661
@end