1 /*****************************************************************************
2 * prefs.m: MacOS X module for vlc
3 *****************************************************************************
4 * Copyright (C) 2002-2012 VLC authors and VideoLAN
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>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /* VLCPrefs manages the main preferences dialog
27 the class is related to wxwindows intf, PrefsPanel */
28 /* VLCTreeItem should contain:
29 - the children of the treeitem
30 - the associated prefs widgets
31 - the documentview with all the prefs widgets in it
32 - a saveChanges action
33 - a revertChanges action
34 - a redraw view action
35 - the children action should generate a list of the treeitems children (to be used by VLCPrefs datasource)
37 The class is sort of a mix of wxwindows intfs, PrefsTreeCtrl and ConfigTreeData
39 /* VLCConfigControl are subclassed NSView's containing and managing individual config items
40 the classes are VERY closely related to wxwindows ConfigControls */
42 /*****************************************************************************
44 *****************************************************************************/
45 #include <stdlib.h> /* malloc(), free() */
46 #include <sys/param.h> /* for MAXPATHLEN */
53 #include <vlc_common.h>
54 #include <vlc_config_cat.h>
56 #import "CompatibilityFixes.h"
59 #import "simple_prefs.h"
60 #import "prefs_widgets.h"
61 #import "CoreInteraction.h"
63 #import <vlc_modules.h>
64 #import <vlc_plugin.h>
66 /* /!\ Warning: Unreadable code :/ */
68 @interface VLCTreeItem : NSObject
71 NSMutableArray *_children;
72 NSMutableArray *_options;
73 NSMutableArray *_subviews;
76 - (id)initWithName:(NSString*)name;
78 - (int)numberOfChildren;
79 - (VLCTreeItem *)childAtIndex:(NSInteger)i_index;
82 - (NSMutableArray *)children;
83 - (NSMutableArray *)options;
84 - (void)showView:(NSScrollView *)o_prefs_view;
91 @interface VLCTreeSubCategoryItem : VLCTreeItem
95 + (VLCTreeSubCategoryItem *)subCategoryTreeItemWithSubCategory:(int)subCategory;
96 - (id)initWithSubCategory:(int)subCategory;
100 /* Plugin daughters */
101 @interface VLCTreePluginItem : VLCTreeItem
103 module_config_t * _configItems;
104 unsigned int _configSize;
106 + (VLCTreePluginItem *)pluginTreeItemWithPlugin:(module_t *)plugin;
107 - (id)initWithPlugin:(module_t *)plugin;
109 - (module_config_t *)configItems;
110 - (unsigned int)configSize;
114 @interface VLCTreeCategoryItem : VLCTreeItem
118 + (VLCTreeCategoryItem *)categoryTreeItemWithCategory:(int)category;
119 - (id)initWithCategory:(int)category;
122 - (VLCTreeSubCategoryItem *)itemRepresentingSubCategory:(int)category;
125 /* individual options. */
126 @interface VLCTreeLeafItem : VLCTreeItem
128 module_config_t * _configItem;
130 - (id)initWithConfigItem:(module_config_t *)configItem;
132 - (module_config_t *)configItem;
135 @interface VLCTreeMainItem : VLCTreePluginItem
138 - (VLCTreeCategoryItem *)itemRepresentingCategory:(int)category;
143 /*****************************************************************************
144 * VLCPrefs implementation
145 *****************************************************************************/
146 @implementation VLCPrefs
148 static VLCPrefs *_o_sharedMainInstance = nil;
150 + (VLCPrefs *)sharedInstance
152 return _o_sharedMainInstance ? _o_sharedMainInstance : [[self alloc] init];
157 if (_o_sharedMainInstance)
160 _o_sharedMainInstance = [super init];
162 o_empty_view = [[NSView alloc] init];
163 _rootTreeItem = [[VLCTreeMainItem alloc] init];
166 return _o_sharedMainInstance;
171 [o_empty_view release];
172 [_rootTreeItem release];
180 if (!OSX_SNOW_LEOPARD)
181 [o_prefs_window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
184 [o_prefs_view setBorderType: NSGrooveBorder];
185 [o_prefs_view setHasVerticalScroller: YES];
186 [o_prefs_view setDrawsBackground: NO];
187 [o_prefs_view setDocumentView: o_empty_view];
188 [o_tree selectRowIndexes: [NSIndexSet indexSetWithIndex: 0] byExtendingSelection: NO];
191 - (void)setTitle: (NSString *) o_title_name
193 [o_title setStringValue: o_title_name];
196 - (void)showPrefsWithLevel:(NSInteger)i_window_level
198 [o_prefs_window setLevel: i_window_level];
199 [o_prefs_window center];
200 [o_prefs_window makeKeyAndOrderFront:self];
201 [_rootTreeItem resetView];
206 [o_prefs_window setTitle: _NS("Preferences")];
207 [o_save_btn setTitle: _NS("Save")];
208 [o_cancel_btn setTitle: _NS("Cancel")];
209 [o_reset_btn setTitle: _NS("Reset All")];
210 [o_showBasic_btn setTitle: _NS("Show Basic")];
213 - (IBAction)savePrefs: (id)sender
215 /* TODO: call savePrefs on Root item */
216 [_rootTreeItem applyChanges];
217 [[VLCCoreInteraction sharedInstance] fixPreferences];
218 config_SaveConfigFile(p_intf);
219 [o_prefs_window orderOut:self];
222 - (IBAction)closePrefs: (id)sender
224 [o_prefs_window orderOut:self];
227 - (IBAction)buttonAction: (id)sender
229 [o_prefs_window orderOut: self];
230 [[[VLCMain sharedInstance] simplePreferences] showSimplePrefs];
233 - (void)loadConfigTree
237 - (void)outlineViewSelectionIsChanging:(NSNotification *)o_notification
241 /* update the document view to the view of the selected tree item */
242 - (void)outlineViewSelectionDidChange:(NSNotification *)o_notification
244 [[o_tree itemAtRow:[o_tree selectedRow]] showView: o_prefs_view];
245 [o_tree expandItem:[o_tree itemAtRow:[o_tree selectedRow]]];
250 @implementation VLCPrefs (NSTableDataSource)
252 - (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
254 return (item == nil) ? [_rootTreeItem numberOfChildren] : [item numberOfChildren];
257 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
259 return (item == nil) ? [_rootTreeItem numberOfChildren] : [item numberOfChildren];
262 - (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item
264 return (item == nil) ? (id)[_rootTreeItem childAtIndex:index]: (id)[item childAtIndex:index];
267 - (id)outlineView:(NSOutlineView *)outlineView
268 objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
270 return (item == nil) ? @"" : [item name];
276 @implementation VLCTreeMainItem
278 - (VLCTreeCategoryItem *)itemRepresentingCategory:(int)category
280 NSUInteger childrenCount = [[self children] count];
281 for (int i = 0; i < childrenCount; i++) {
282 VLCTreeCategoryItem * categoryItem = [[self children] objectAtIndex:i];
283 if ([categoryItem category] == category)
289 - (bool)isSubCategoryGeneral:(int)category
291 if (category == SUBCAT_VIDEO_GENERAL ||
292 category == SUBCAT_ADVANCED_MISC ||
293 category == SUBCAT_INPUT_GENERAL ||
294 category == SUBCAT_INTERFACE_GENERAL ||
295 category == SUBCAT_SOUT_GENERAL||
296 category == SUBCAT_PLAYLIST_GENERAL||
297 category == SUBCAT_AUDIO_GENERAL) {
303 /* Creates and returns the array of children
304 * Loads children incrementally */
305 - (NSMutableArray *)children
307 if (_children) return _children;
308 _children = [[NSMutableArray alloc] init];
310 intf_thread_t *p_intf = VLCIntf;
312 /* List the modules */
314 module_t ** modules = module_list_get(&count);
315 if (!modules) return nil;
317 /* Build a tree of the plugins */
318 /* Add the capabilities */
319 for (i = 0; i < count; i++) {
320 VLCTreeCategoryItem * categoryItem = nil;
321 VLCTreeSubCategoryItem * subCategoryItem = nil;
322 VLCTreePluginItem * pluginItem = nil;
323 module_config_t *p_configs = NULL;
325 unsigned int confsize;
327 module_t * p_module = modules[i];
329 /* Exclude empty plugins (submodules don't have config */
330 /* options, they are stored in the parent module) */
331 if (module_is_main(p_module)) {
333 _configItems = module_config_get(p_module, &confsize);
334 _configSize = confsize;
336 pluginItem = [VLCTreePluginItem pluginTreeItemWithPlugin: p_module];
337 confsize = [pluginItem configSize];
339 p_configs = [pluginItem configItems];
342 for (j = 0; j < confsize; j++) {
343 int configType = p_configs[j].i_type;
344 if (configType == CONFIG_CATEGORY) {
345 categoryItem = [self itemRepresentingCategory:p_configs[j].value.i];
347 categoryItem = [VLCTreeCategoryItem categoryTreeItemWithCategory:p_configs[j].value.i];
349 [[self children] addObject:categoryItem];
352 else if (configType == CONFIG_SUBCATEGORY) {
353 lastsubcat = p_configs[j].value.i;
354 if (categoryItem && ![self isSubCategoryGeneral:lastsubcat]) {
355 subCategoryItem = [categoryItem itemRepresentingSubCategory:lastsubcat];
356 if (!subCategoryItem) {
357 subCategoryItem = [VLCTreeSubCategoryItem subCategoryTreeItemWithSubCategory:lastsubcat];
359 [[categoryItem children] addObject:subCategoryItem];
364 if (module_is_main(p_module) && (CONFIG_ITEM(configType) || configType == CONFIG_SECTION)) {
365 if (categoryItem && [self isSubCategoryGeneral:lastsubcat])
366 [[categoryItem options] addObject:[[VLCTreeLeafItem alloc] initWithConfigItem:&p_configs[j]]];
367 else if (subCategoryItem)
368 [[subCategoryItem options] addObject:[[VLCTreeLeafItem alloc] initWithConfigItem:&p_configs[j]]];
370 else if (!module_is_main(p_module) && (CONFIG_ITEM(configType) || configType == CONFIG_SECTION)) {
371 if (![[subCategoryItem children] containsObject: pluginItem])
372 [[subCategoryItem children] addObject:pluginItem];
375 [[pluginItem options] addObject:[[VLCTreeLeafItem alloc] initWithConfigItem:&p_configs[j]]];
379 module_list_free(modules);
385 @implementation VLCTreeCategoryItem
386 + (VLCTreeCategoryItem *)categoryTreeItemWithCategory:(int)category
388 if (!config_CategoryNameGet(category)) return nil;
389 return [[[[self class] alloc] initWithCategory:category] autorelease];
392 - (id)initWithCategory:(int)category
394 NSString * name = _NS(config_CategoryNameGet(category));
395 if (self = [super initWithName:name]) {
396 _category = category;
397 //_help = [_NS(config_CategoryHelpGet(category)) retain];
402 - (VLCTreeSubCategoryItem *)itemRepresentingSubCategory:(int)subCategory
404 assert([self isKindOfClass:[VLCTreeCategoryItem class]]);
405 NSUInteger childrenCount = [[self children] count];
406 for (NSUInteger i = 0; i < childrenCount; i++) {
407 VLCTreeSubCategoryItem * subCategoryItem = [[self children] objectAtIndex:i];
408 if ([subCategoryItem subCategory] == subCategory)
409 return subCategoryItem;
421 @implementation VLCTreeSubCategoryItem
422 - (id)initWithSubCategory:(int)subCategory
424 NSString * name = _NS(config_CategoryNameGet(subCategory));
425 if (self = [super initWithName:name]) {
426 _subCategory = subCategory;
427 //_help = [_NS(config_CategoryHelpGet(subCategory)) retain];
432 + (VLCTreeSubCategoryItem *)subCategoryTreeItemWithSubCategory:(int)subCategory
434 if (!config_CategoryNameGet(subCategory))
436 return [[[[self class] alloc] initWithSubCategory:subCategory] autorelease];
447 @implementation VLCTreePluginItem
448 - (id)initWithPlugin:(module_t *)plugin
450 NSString * name = _NS(module_get_name(plugin, false));
451 if (self = [super initWithName:name]) {
452 _configItems = module_config_get(plugin, &_configSize);
454 //_help = [_NS(config_CategoryHelpGet(subCategory)) retain];
459 + (VLCTreePluginItem *)pluginTreeItemWithPlugin:(module_t *)plugin
461 return [[[[self class] alloc] initWithPlugin:plugin] autorelease];
466 module_config_free(_configItems);
470 - (module_config_t *)configItems
475 - (unsigned int)configSize
483 @implementation VLCTreeLeafItem
485 - (id)initWithConfigItem: (module_config_t *) configItem
487 NSString *name = toNSStr(configItem->psz_name);
488 self = [super initWithName:name];
490 _configItem = configItem;
495 - (module_config_t *)configItem
502 #pragma mark (Root class for all TreeItems)
503 @implementation VLCTreeItem
505 - (id)initWithName:(NSString*)name
509 _name = [name retain];
523 - (VLCTreeItem *)childAtIndex:(NSInteger)i_index
525 return [[self children] objectAtIndex:i_index];
528 - (int)numberOfChildren
530 return [[self children] count];
535 return [[_name retain] autorelease];
538 - (void)showView:(NSScrollView *)prefsView
543 [[VLCPrefs sharedInstance] setTitle: [self name]];
544 s_vrc = [[prefsView contentView] bounds]; s_vrc.size.height -= 4;
545 view = [[VLCFlippedView alloc] initWithFrame: s_vrc];
546 [view setAutoresizingMask: NSViewWidthSizable | NSViewMinYMargin | NSViewMaxYMargin];
549 _subviews = [[NSMutableArray alloc] initWithCapacity:10];
551 NSUInteger count = [[self options] count];
552 for (NSUInteger i = 0; i < count; i++) {
553 VLCTreeLeafItem * item = [[self options] objectAtIndex:i];
555 VLCConfigControl *control;
556 control = [VLCConfigControl newControl:[item configItem] withView:view];
558 [control setAutoresizingMask: NSViewMaxYMargin | NSViewWidthSizable];
559 [_subviews addObject: control];
570 NSEnumerator *enumerator = [_subviews objectEnumerator];
571 VLCConfigControl *widget;
574 while((widget = [enumerator nextObject])) {
575 if (i_max_label < [widget labelSize])
576 i_max_label = [widget labelSize];
579 enumerator = [_subviews objectEnumerator];
580 while((widget = [enumerator nextObject])) {
583 i_widget = [widget viewType];
584 i_yPos += [VLCConfigControl calcVerticalMargin:i_widget lastItem:i_lastItem];
585 [widget setYPos:i_yPos];
586 frame = [widget frame];
587 frame.size.width = [view frame].size.width - LEFTMARGIN - RIGHTMARGIN;
588 [widget setFrame:frame];
589 [widget alignWithXPosition: i_max_label];
590 i_yPos += [widget frame].size.height;
591 i_lastItem = i_widget;
592 [view addSubview:widget];
595 frame = [view frame];
596 frame.size.height = i_yPos;
597 [view setFrame:frame];
598 [prefsView setDocumentView:view];
604 NSUInteger count = [_subviews count];
605 for (i = 0 ; i < count ; i++)
606 [[_subviews objectAtIndex:i] applyChanges];
608 count = [_children count];
609 for (i = 0 ; i < count ; i++)
610 [[_children objectAtIndex:i] applyChanges];
615 NSUInteger count = [_subviews count];
616 for (NSUInteger i = 0 ; i < count ; i++)
617 [[_subviews objectAtIndex:i] resetValues];
619 count = [_options count];
620 for (NSUInteger i = 0 ; i < count ; i++)
621 [[_options objectAtIndex:i] resetView];
623 count = [_children count];
624 for (NSUInteger i = 0 ; i < count ; i++)
625 [[_children objectAtIndex:i] resetView];
629 - (NSMutableArray *)children
632 _children = [[NSMutableArray alloc] init];
636 - (NSMutableArray *)options
639 _options = [[NSMutableArray alloc] init];
645 @implementation VLCFlippedView