]> git.sesse.net Git - vlc/blob - modules/gui/macosx/prefs.m
* modules/gui/macosx/prefs.?:
[vlc] / modules / gui / macosx / prefs.m
1 /*****************************************************************************
2  * prefs.m: MacOS X plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id: prefs.m,v 1.31 2003/06/06 00:38:41 hartman Exp $
6  *
7  * Authors:     Jon Lech Johansen <jon-vl@nanocrew.net>
8  *              Derk-Jan Hartman <thedj at users.sf.net>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <sys/param.h>                                    /* for MAXPATHLEN */
30 #include <string.h>
31
32 #include "intf.h"
33 #include "prefs.h"
34
35 /*****************************************************************************
36  * VLCPrefs implementation
37  *****************************************************************************/
38 @implementation VLCPrefs
39
40 - (id)init
41 {
42     self = [super init];
43
44     if( self != nil )
45     {
46         o_empty_view = [[NSView alloc] init];
47     }
48
49     return( self );
50 }
51
52 - (void)dealloc
53 {
54     [o_empty_view release];
55     [super dealloc];
56 }
57
58 - (void)awakeFromNib
59 {
60     p_intf = [NSApp getIntf];
61     b_advanced = config_GetInt( p_intf, "advanced" );
62
63     [self initStrings];
64     [o_advanced_ckb setState: b_advanced];
65     [o_prefs_view setBorderType: NSGrooveBorder];
66     [o_prefs_view setHasVerticalScroller: YES];
67     [o_prefs_view setDrawsBackground: NO];
68     [o_prefs_view setRulersVisible: YES];
69     [o_prefs_view setDocumentView: o_empty_view];
70     [o_tree selectRow:0 byExtendingSelection:NO];
71 }
72
73 - (void)initStrings
74 {
75     [o_prefs_window setTitle: _NS("Preferences")];
76     [o_save_btn setTitle: _NS("Save")];
77     [o_cancel_btn setTitle: _NS("Cancel")];
78     [o_reset_btn setTitle: _NS("Reset All")];
79     [o_advanced_ckb setTitle: _NS("Advanced")];
80 }
81
82 - (void)showPrefs
83 {
84     [o_prefs_window center];
85     [o_prefs_window makeKeyAndOrderFront:self];
86 }
87
88 - (IBAction)savePrefs: (id)sender
89 {
90     config_SaveConfigFile( p_intf, NULL );
91     [o_prefs_window orderOut:self];
92 }
93
94 - (IBAction)closePrefs: (id)sender
95 {
96     [o_prefs_window orderOut:self];
97 }
98
99 - (IBAction)resetAll: (id)sender
100 {
101     NSBeginInformationalAlertSheet(_NS("Reset Preferences"), @"Cancel", @"Continue", 
102         nil, o_prefs_window, self, @selector(sheetDidEnd: returnCode: contextInfo:), NULL, nil,
103         _NS("Beware this will reset your VLC Media Player config file.\n"
104             "Are you sure you want to continue?") );
105 }
106
107 - (void)sheetDidEnd:(NSWindow *)o_sheet returnCode:(int)i_return contextInfo:(void *)o_context
108 {
109     if( i_return == NSAlertAlternateReturn )
110     {
111         config_ResetAll( p_intf );
112         [self showViewForID: [[o_tree itemAtRow:[o_tree selectedRow]] getObjectID]
113             andName: [[o_tree itemAtRow:[o_tree selectedRow]] getName]];
114     }
115 }
116
117 - (IBAction)advancedToggle: (id)sender
118 {
119     b_advanced = !b_advanced;
120     [o_advanced_ckb setState: b_advanced];
121     [self showViewForID: [[o_tree itemAtRow:[o_tree selectedRow]] getObjectID]
122         andName: [[o_tree itemAtRow:[o_tree selectedRow]] getName]];
123 }
124
125 - (void)loadConfigTree
126 {
127     
128 }
129
130 - (void)outlineViewSelectionIsChanging:(NSNotification *)o_notification
131 {
132 }
133
134 - (void)outlineViewSelectionDidChange:(NSNotification *)o_notification
135 {
136     [self showViewForID: [[o_tree itemAtRow:[o_tree selectedRow]] getObjectID]
137         andName: [[o_tree itemAtRow:[o_tree selectedRow]] getName]];
138 }
139
140 - (void)configChanged:(id)o_unknown
141 {
142     id o_vlc_config = [o_unknown isKindOfClass: [NSNotification class]] ?
143                       [o_unknown object] : o_unknown;
144
145     int i_type = [o_vlc_config configType];
146     NSString *o_name = [o_vlc_config configName];
147     char *psz_name = (char *)[o_name UTF8String];
148
149     switch( i_type )
150     {
151
152     case CONFIG_ITEM_MODULE:
153         {
154             char *psz_value;
155             module_t *p_a_module;
156             int i_id = [[o_vlc_config selectedItem] tag];
157             
158             p_a_module = (module_t *)vlc_object_get( p_intf, i_id );
159             if( p_a_module == NULL || p_a_module->i_object_type != VLC_OBJECT_MODULE )
160             {
161                 i_id = -1;
162             }
163             
164             psz_value = ( i_id == -1 ) ? "" :  p_a_module->psz_object_name ;
165             config_PutPsz( p_intf, psz_name, strdup(psz_value) );
166         }
167         break;
168
169     case CONFIG_ITEM_STRING:
170     case CONFIG_ITEM_FILE:
171     case CONFIG_ITEM_DIRECTORY:
172         {
173             char *psz_value;
174             NSString *o_value;
175
176             o_value = [o_vlc_config stringValue];
177             psz_value = (char *)[o_value UTF8String];
178
179             config_PutPsz( p_intf, psz_name, psz_value );
180         }
181         break;
182
183     case CONFIG_ITEM_INTEGER:
184     case CONFIG_ITEM_BOOL:
185         {
186             int i_value = [o_vlc_config intValue];
187
188             config_PutInt( p_intf, psz_name, i_value );
189         }
190         break;
191
192     case CONFIG_ITEM_FLOAT:
193         {
194             float f_value = [o_vlc_config floatValue];
195
196             config_PutFloat( p_intf, psz_name, f_value );
197         }
198         break;
199
200     }
201 }
202
203 - (void)showViewForID: (int)i_id andName: (NSString *)o_item_name
204 {
205     vlc_list_t *p_list;
206     module_t *p_parser;
207     module_config_t *p_item;
208     
209     int i_pos, i_module_tag, i_index;
210     
211     NSString *o_module_name;
212     NSRect s_rc;                        /* rect                         */
213     NSView *o_view;                     /* view                         */
214     NSRect s_vrc;                       /* view rect                    */
215     VLCTextField *o_text_field;         /* input field / label          */
216     
217     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
218
219     /* Get a pointer to the module */
220     p_parser = (module_t *)vlc_object_get( p_intf, i_id );
221     if( p_parser->i_object_type != VLC_OBJECT_MODULE )
222     {
223         /* 0OOoo something went really bad */
224         return;
225     }
226     
227     /* Enumerate config options and add corresponding config boxes */
228     o_module_name = [NSString stringWithUTF8String: p_parser->psz_object_name];
229     p_item = p_parser->p_config;
230
231     i_pos = 0;
232     o_view = nil;
233     i_module_tag = 3;
234
235 #define X_ORIGIN 20
236 #define Y_ORIGIN (X_ORIGIN - 10)
237
238 #define CHECK_VIEW_HEIGHT \
239     { \
240         float f_new_pos = s_rc.origin.y + s_rc.size.height + X_ORIGIN; \
241         if( f_new_pos > s_vrc.size.height ) \
242         { \
243             s_vrc.size.height = f_new_pos; \
244             [o_view setFrame: s_vrc]; \
245         } \
246     }
247
248 #define CONTROL_LABEL( label ) \
249     { \
250         s_rc.origin.x += s_rc.size.width + 10; \
251         s_rc.size.width = s_vrc.size.width - s_rc.origin.x - X_ORIGIN - 20; \
252         o_text_field = [[NSTextField alloc] initWithFrame: s_rc]; \
253         [o_text_field setDrawsBackground: NO]; \
254         [o_text_field setBordered: NO]; \
255         [o_text_field setEditable: NO]; \
256         [o_text_field setSelectable: NO]; \
257         if ( label ) \
258         { \
259             [o_text_field setStringValue: \
260                 [NSApp localizedString: label]]; \
261         } \
262         [o_text_field sizeToFit]; \
263         [o_view addSubview: [o_text_field autorelease]]; \
264     }
265
266 #define INPUT_FIELD( ctype, cname, label, w, msg, param, tip ) \
267     { \
268         char * psz_duptip = NULL; \
269         if ( p_item->psz_longtext != NULL ) \
270             psz_duptip = strdup( p_item->psz_longtext ); \
271         s_rc.size.height = 25; \
272         s_rc.size.width = w; \
273         s_rc.origin.y += 10; \
274         CHECK_VIEW_HEIGHT; \
275         o_text_field = [[VLCTextField alloc] initWithFrame: s_rc]; \
276         [o_text_field setAlignment: NSRightTextAlignment]; \
277         CONTROL_CONFIG( o_text_field, o_module_name, ctype, cname ); \
278         [o_text_field msg: param]; \
279         if ( psz_duptip != NULL ) \
280         { \
281             [o_text_field setToolTip: [NSApp wrapString: [NSApp localizedString: \
282                                        psz_duptip] toWidth: PREFS_WRAP ]]; \
283             free(psz_duptip);\
284         } \
285         [o_view addSubview: [o_text_field autorelease]]; \
286         [[NSNotificationCenter defaultCenter] addObserver: self \
287             selector: @selector(configChanged:) \
288             name: NSControlTextDidChangeNotification \
289             object: o_text_field]; \
290         CONTROL_LABEL( label ); \
291         s_rc.origin.y += s_rc.size.height; \
292         s_rc.origin.x = X_ORIGIN; \
293     }
294
295 #define INPUT_FIELD_INTEGER( name, label, w, param, tip ) \
296     INPUT_FIELD( CONFIG_ITEM_INTEGER, name, label, w, setIntValue, param, tip )
297 #define INPUT_FIELD_FLOAT( name, label, w, param, tip ) \
298     INPUT_FIELD( CONFIG_ITEM_FLOAT, name, label, w, setFloatValue, param, tip )
299 #define INPUT_FIELD_STRING( name, label, w, param, tip ) \
300     INPUT_FIELD( CONFIG_ITEM_STRING, name, label, w, setStringValue, param, tip )
301
302     /* Init View */
303     s_vrc = [[o_prefs_view contentView] bounds]; s_vrc.size.height -= 4;
304     o_view = [[VLCFlippedView alloc] initWithFrame: s_vrc];
305     s_rc.origin.x = X_ORIGIN;
306     s_rc.origin.y = Y_ORIGIN;
307     BOOL b_right_cat = FALSE;
308
309     if( p_item ) do
310     {
311         if( p_item->i_type == CONFIG_HINT_CATEGORY )
312         {
313             if( !strcmp( p_parser->psz_object_name, "main" ) &&
314                 [o_item_name isEqualToString: [NSApp localizedString: p_item->psz_text]] )
315             {
316                 b_right_cat = TRUE;
317             } else if( strcmp( p_parser->psz_object_name, "main" ) )
318             {
319                  b_right_cat = TRUE;
320             } else b_right_cat = FALSE; 
321         } else if( p_item->i_type == CONFIG_HINT_END && !strcmp( p_parser->psz_object_name, "main" ) )
322         {
323             b_right_cat = FALSE;
324         }
325         
326         if( (p_item->b_advanced && !b_advanced ) || !b_right_cat )
327         {
328             continue;
329         }
330         switch( p_item->i_type )
331         {
332             case CONFIG_ITEM_MODULE:
333             {
334                 VLCPopUpButton *o_modules;
335                 module_t *p_a_module;
336                 char * psz_duptip = NULL;
337
338                 if ( p_item->psz_longtext != NULL )
339                     psz_duptip = strdup( p_item->psz_longtext );
340
341                 s_rc.size.height = 30;
342                 s_rc.size.width = 200;
343                 s_rc.origin.y += 10;
344                 
345                 CHECK_VIEW_HEIGHT;
346     
347                 o_modules = [[VLCPopUpButton alloc] initWithFrame: s_rc];
348                 CONTROL_CONFIG( o_modules, o_module_name,
349                                     CONFIG_ITEM_MODULE, p_item->psz_name );
350                 [o_modules setTarget: self];
351                 [o_modules setAction: @selector(configChanged:)];
352                 [o_modules sendActionOn:NSLeftMouseUpMask];
353                 
354                 if ( psz_duptip != NULL )
355                 {
356                     [o_modules setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
357                     free( psz_duptip );
358                 }
359                 [o_view addSubview: [o_modules autorelease]];
360
361                 [o_modules addItemWithTitle: _NS("Default")];
362                 [[o_modules lastItem] setTag: -1];
363                 [o_modules selectItem: [o_modules lastItem]];
364
365                 /* build a list of available modules */
366                 {
367                     for( i_index = 0; i_index < p_list->i_count; i_index++ )
368                     {
369                         p_a_module = (module_t *)p_list->p_values[i_index].p_object ;
370     
371                         if( !strcmp( p_a_module->psz_capability,
372                                     p_item->psz_type ) )
373                         {
374                             NSString *o_description = [NSApp
375                                 localizedString: p_a_module->psz_longname];
376                             [o_modules addItemWithTitle: o_description];
377                             [[o_modules lastItem] setTag: p_a_module->i_object_id];
378
379                             if( p_item->psz_value &&
380                                 !strcmp( p_item->psz_value, p_a_module->psz_object_name ) )
381                             {
382                                 [o_modules selectItem:[o_modules lastItem]];
383                             }
384                         }
385                     }
386                 }
387
388                 CONTROL_LABEL( p_item->psz_text );
389                 s_rc.origin.y += s_rc.size.height;
390                 s_rc.origin.x = X_ORIGIN;
391             }
392             break;
393
394             case CONFIG_ITEM_STRING:
395             case CONFIG_ITEM_FILE:
396             case CONFIG_ITEM_DIRECTORY:
397             {
398     
399                 if( !p_item->ppsz_list )
400                 {
401                     char *psz_value = p_item->psz_value ?
402                                     p_item->psz_value : "";
403     
404                     INPUT_FIELD_STRING( p_item->psz_name, p_item->psz_text, 200,
405                                         [NSApp localizedString: psz_value],
406                                         p_item->psz_longtext );
407                 }
408                 else
409                 {
410                     int i;
411                     VLCComboBox *o_combo_box;
412                     char * psz_duptip = NULL;
413                     if ( p_item->psz_longtext != NULL )
414                         psz_duptip = strdup( p_item->psz_longtext );
415     
416                     s_rc.size.height = 27;
417                     s_rc.size.width = 200;
418                     s_rc.origin.y += 10;
419     
420                     CHECK_VIEW_HEIGHT;
421     
422                     o_combo_box = [[VLCComboBox alloc] initWithFrame: s_rc];
423                     CONTROL_CONFIG( o_combo_box, o_module_name,
424                                     CONFIG_ITEM_STRING, p_item->psz_name );
425                     [o_combo_box setTarget: self];
426                     [o_combo_box setAction: @selector(configChanged:)];
427                     [o_combo_box sendActionOn:NSLeftMouseUpMask];
428
429                     if ( psz_duptip != NULL )
430                     {
431                         [o_combo_box setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
432                         free( psz_duptip );
433                     }
434                     [o_view addSubview: [o_combo_box autorelease]];
435                     
436                     for( i=0; p_item->ppsz_list[i]; i++ )
437                     {
438                         [o_combo_box addItemWithObjectValue:
439                             [NSApp localizedString: p_item->ppsz_list[i]]];
440                     }
441                     [o_combo_box setStringValue: [NSApp localizedString: 
442                         p_item->psz_value ? p_item->psz_value : ""]];
443     
444                     CONTROL_LABEL( p_item->psz_text );
445     
446                     s_rc.origin.y += s_rc.size.height;
447                     s_rc.origin.x = X_ORIGIN;
448                 }
449     
450             }
451             break;
452     
453             case CONFIG_ITEM_INTEGER:
454             {
455                 if( p_item->i_min == p_item->i_max )
456                 {
457                     INPUT_FIELD_INTEGER( p_item->psz_name, p_item->psz_text, 70,
458                         p_item->i_value, p_item->psz_longtext );
459                 }
460                 else
461                 {
462                     /*create a slider */
463                     VLCSlider *o_slider;
464                     char * psz_duptip = NULL;
465                     if ( p_item->psz_longtext != NULL )
466                         psz_duptip = strdup( p_item->psz_longtext );
467         
468                     s_rc.size.height = 27;
469                     s_rc.size.width = 200;
470                     s_rc.origin.y += 10;
471         
472                     CHECK_VIEW_HEIGHT;
473         
474                     o_slider = [[VLCSlider alloc] initWithFrame: s_rc];
475                     [o_slider setMinValue: p_item->i_min];
476                     [o_slider setMaxValue: p_item->i_max];
477                     [o_slider setIntValue: p_item->i_value];
478
479                     if ( psz_duptip != NULL )
480                     {
481                         [o_slider setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
482                         free( psz_duptip );
483                     }
484                     [o_slider setTarget: self];
485                     [o_slider setAction: @selector(configChanged:)];
486                     [o_slider sendActionOn:NSLeftMouseUpMask];
487                     CONTROL_CONFIG( o_slider, o_module_name,
488                                     CONFIG_ITEM_INTEGER, p_item->psz_name );
489                     [o_view addSubview: [o_slider autorelease]];
490                     CONTROL_LABEL( p_item->psz_text );
491         
492                     s_rc.origin.y += s_rc.size.height;
493                     s_rc.origin.x = X_ORIGIN;
494                 }
495             }
496             break;
497     
498             case CONFIG_ITEM_FLOAT:
499             {
500                 if( p_item->f_min == p_item->f_max )
501                 {
502                     INPUT_FIELD_FLOAT( p_item->psz_name, p_item->psz_text, 70,
503                         p_item->f_value, p_item->psz_longtext );
504                 }
505                 else
506                 {
507                     /* create a slider */
508                     VLCSlider *o_slider;
509                     char * psz_duptip = NULL;
510                     if ( p_item->psz_longtext != NULL )
511                         psz_duptip = strdup( p_item->psz_longtext );
512         
513                     s_rc.size.height = 27;
514                     s_rc.size.width = 200;
515                     s_rc.origin.y += 10;
516         
517                     CHECK_VIEW_HEIGHT;
518         
519                     o_slider = [[VLCSlider alloc] initWithFrame: s_rc];
520                     [o_slider setMinValue: p_item->f_min];
521                     [o_slider setMaxValue: p_item->f_max];
522                     [o_slider setFloatValue: p_item->f_value];
523
524                     if ( psz_duptip != NULL )
525                     {
526                         [o_slider setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
527                         free( psz_duptip );
528                     }
529                     [o_slider setTarget: self];
530                     [o_slider setAction: @selector(configChanged:)];
531                     [o_slider sendActionOn:NSLeftMouseUpMask];
532                     CONTROL_CONFIG( o_slider, o_module_name,
533                                     CONFIG_ITEM_FLOAT, p_item->psz_name );
534                     [o_view addSubview: [o_slider autorelease]];
535                     CONTROL_LABEL( p_item->psz_text );
536         
537                     s_rc.origin.y += s_rc.size.height;
538                     s_rc.origin.x = X_ORIGIN;
539                 }
540             }
541             break;
542     
543             case CONFIG_ITEM_BOOL:
544             {
545                 VLCButton *o_btn_bool;
546                 char * psz_duptip = NULL;
547
548                 if ( p_item->psz_longtext != NULL )
549                     psz_duptip = strdup( p_item->psz_longtext );
550     
551                 s_rc.size.height = 27;
552                 s_rc.size.width = s_vrc.size.width - X_ORIGIN * 2 - 20;
553                 s_rc.origin.y += 10;
554     
555                 CHECK_VIEW_HEIGHT;
556     
557                 o_btn_bool = [[VLCButton alloc] initWithFrame: s_rc];
558                 [o_btn_bool setButtonType: NSSwitchButton];
559                 [o_btn_bool setIntValue: p_item->i_value];
560                 [o_btn_bool setTitle: [NSApp localizedString: p_item->psz_text]];
561                 if ( psz_duptip != NULL )
562                 {
563                     [o_btn_bool setToolTip: [NSApp wrapString: [NSApp localizedString: psz_duptip] toWidth: PREFS_WRAP]];
564                     free( psz_duptip );
565                 }
566                 [o_btn_bool setTarget: self];
567                 [o_btn_bool setAction: @selector(configChanged:)];
568                 CONTROL_CONFIG( o_btn_bool, o_module_name,
569                                 CONFIG_ITEM_BOOL, p_item->psz_name );
570                 [o_view addSubview: [o_btn_bool autorelease]];
571     
572                 s_rc.origin.y += s_rc.size.height;
573             }
574             break;
575     
576             }
577     
578     #undef INPUT_FIELD_INTEGER
579     #undef INPUT_FIELD_FLOAT
580     #undef INPUT_FIELD_STRING
581     #undef INPUT_FIELD
582     #undef CHECK_VIEW_HEIGHT
583     #undef CONTROL_LABEL
584     #undef Y_ORIGIN
585     #undef X_ORIGIN
586         }
587         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
588         vlc_list_release( p_list );
589     
590     [o_prefs_view setDocumentView: o_view];
591     [o_prefs_view setNeedsDisplay: TRUE];
592 }
593
594
595 @end
596
597 @implementation VLCPrefs (NSTableDataSource)
598
599 - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
600     return (item == nil) ? [[VLCTreeItem rootItem] numberOfChildren] : [item numberOfChildren];
601 }
602
603 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
604     return (item == nil) ? YES : ([item numberOfChildren] != -1);
605 }
606
607 - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item {
608     return (item == nil) ? [[VLCTreeItem rootItem] childAtIndex:index] : [item childAtIndex:index];
609 }
610
611 - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
612     return (item == nil) ? @"" : (id)[item getName];
613 }
614
615 @end
616
617 @implementation VLCTreeItem
618
619 static VLCTreeItem *o_root_item = nil;
620
621 #define IsALeafNode ((id)-1)
622
623 - (id)initWithName: (NSString *)o_item_name ID: (int)i_id parent:(VLCTreeItem *)o_parent_item
624 {
625     self = [super init];
626
627     if( self != nil )
628     {
629         o_name = [o_item_name copy];
630         i_object_id = i_id;
631         o_parent = o_parent_item;
632     }
633     return( self );
634 }
635
636 + (VLCTreeItem *)rootItem {
637    if (o_root_item == nil) o_root_item = [[VLCTreeItem alloc] initWithName:@"main" ID: 0 parent:nil];
638    return o_root_item;       
639 }
640
641 - (void)dealloc
642 {
643     if (o_children != IsALeafNode) [o_children release];
644     [o_name release];
645     [super dealloc];
646 }
647
648 /* Creates and returns the array of children
649  * Loads children incrementally */
650 - (NSArray *)children {
651     if (o_children == NULL) {
652         intf_thread_t *p_intf = [NSApp getIntf];
653         vlc_list_t      *p_list;
654         module_t        *p_module = NULL;
655         module_config_t *p_item;
656         int i_index,j;
657
658         /* List the plugins */
659         p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
660         if( !p_list ) return nil;
661
662         if( [[self getName] isEqualToString: @"main"] )
663         {
664             /*
665             * Build a tree of the main options
666             */
667             for( i_index = 0; i_index < p_list->i_count; i_index++ )
668             {
669                 p_module = (module_t *)p_list->p_values[i_index].p_object;
670                 if( !strcmp( p_module->psz_object_name, "main" ) )
671                     break;
672             }
673             if( p_module == NULL )
674             {
675                 msg_Err( p_intf, "Could not find the main module in our prefs" );
676                 return nil;
677             }
678             if( i_index < p_list->i_count )
679             {
680                 /* We found the main module */
681         
682                 /* Enumerate config categories and store a reference so we can
683                  * generate their config panel them when it is asked by the user. */
684                 p_item = p_module->p_config;
685                 o_children = [[NSMutableArray alloc] initWithCapacity:10];
686
687                 if( p_item ) do
688                 {
689                     NSString *o_child_name;
690                     
691                     switch( p_item->i_type )
692                     {
693                     case CONFIG_HINT_CATEGORY:
694                         o_child_name = [NSApp localizedString: p_item->psz_text];
695                         [o_children addObject:[[VLCTreeItem alloc] initWithName: o_child_name
696                             ID: p_module->i_object_id parent:self]];
697                         break;
698                     }
699                 }
700                 while( p_item->i_type != CONFIG_HINT_END && p_item++ );
701                 
702                 /* Add the plugins item */
703                 [o_children addObject:[[VLCTreeItem alloc] initWithName: _NS("Modules")
704                     ID: 0 parent:self]];
705             }
706             else
707             {
708                 o_children = IsALeafNode;
709             }
710         }
711         else if( [[self getName] isEqualToString: _NS("Modules")] )
712         {
713             /* Add the capabilities */
714             o_children = [[NSMutableArray alloc] initWithCapacity:10];
715             for( i_index = 0; i_index < p_list->i_count; i_index++ )
716             {
717                 p_module = (module_t *)p_list->p_values[i_index].p_object;
718         
719                 /* Exclude the main module */
720                 if( !strcmp( p_module->psz_object_name, "main" ) )
721                     continue;
722         
723                 /* Exclude empty plugins */
724                 p_item = p_module->p_config;
725                 if( !p_item ) continue;
726                 do
727                 {
728                     if( p_item->i_type & CONFIG_ITEM )
729                         break;
730                 }
731                 while( p_item->i_type != CONFIG_HINT_END && p_item++ );
732                 if( p_item->i_type == CONFIG_HINT_END ) continue;
733         
734                 /* Create the capability tree if it doesn't already exist */
735                 NSString *o_capability;
736                 o_capability = [NSApp localizedString: p_module->psz_capability];
737                 if( !p_module->psz_capability || !*p_module->psz_capability )
738                 {
739                     /* Empty capability ? Let's look at the submodules */
740                     module_t * p_submodule;
741                     for( j = 0; j < p_module->i_children; j++ )
742                     {
743                         p_submodule = (module_t*)p_module->pp_children[ j ];
744                         if( p_submodule->psz_capability && *p_submodule->psz_capability )
745                         {
746                             o_capability = [NSApp localizedString: p_submodule->psz_capability];
747                             BOOL b_found = FALSE;
748                             for( j = 0; j < [o_children count]; j++ )
749                             {
750                                 if( [[[o_children objectAtIndex:j] getName] isEqualToString: o_capability] )
751                                 {
752                                     b_found = TRUE;
753                                     break;
754                                 }
755                             }
756                             if( !b_found )
757                             {
758                                 [o_children addObject:[[VLCTreeItem alloc] initWithName: o_capability
759                                 ID: 0 parent:self]];
760                             }
761                         }
762                     }
763                 }
764
765                 BOOL b_found = FALSE;
766                 for( j = 0; j < [o_children count]; j++ )
767                 {
768                     if( [[[o_children objectAtIndex:j] getName] isEqualToString: o_capability] )
769                     {
770                         b_found = TRUE;
771                         break;
772                     }
773                 }
774                 if( !b_found )
775                 {
776                     [o_children addObject:[[VLCTreeItem alloc] initWithName: o_capability
777                     ID: 0 parent:self]];
778                 }
779             }
780         }
781         else if( [[o_parent getName] isEqualToString: _NS("Modules")] )
782         {
783             /* Now add the modules */
784             o_children = [[NSMutableArray alloc] initWithCapacity:10];
785             for( i_index = 0; i_index < p_list->i_count; i_index++ )
786             {
787                 p_module = (module_t *)p_list->p_values[i_index].p_object;
788         
789                 /* Exclude the main module */
790                 if( !strcmp( p_module->psz_object_name, "main" ) )
791                     continue;
792         
793                 /* Exclude empty plugins */
794                 p_item = p_module->p_config;
795                 if( !p_item ) continue;
796                 do
797                 {
798                     if( p_item->i_type & CONFIG_ITEM )
799                         break;
800                 }
801                 while( p_item->i_type != CONFIG_HINT_END && p_item++ );
802                 if( p_item->i_type == CONFIG_HINT_END ) continue;
803         
804                 /* Check the capability */
805                 NSString *o_capability;
806                 o_capability = [NSApp localizedString: p_module->psz_capability];
807                 if( !p_module->psz_capability || !*p_module->psz_capability )
808                 {
809                     /* Empty capability ? Let's look at the submodules */
810                     module_t * p_submodule;
811                     for( j = 0; j < p_module->i_children; j++ )
812                     {
813                         p_submodule = (module_t*)p_module->pp_children[ j ];
814                         if( p_submodule->psz_capability && *p_submodule->psz_capability )
815                         {
816                             o_capability = [NSApp localizedString: p_submodule->psz_capability];
817                             if( [o_capability isEqualToString: [self getName]] )
818                             {
819                             [o_children addObject:[[VLCTreeItem alloc] initWithName:
820                                 [NSApp localizedString: p_module->psz_object_name ]
821                                 ID: p_module->i_object_id parent:self]];
822                             }
823                         }
824                     }
825                 }
826                 else if( [o_capability isEqualToString: [self getName]] )
827                 {
828                     [o_children addObject:[[VLCTreeItem alloc] initWithName:
829                         [NSApp localizedString: p_module->psz_object_name ]
830                         ID: p_module->i_object_id parent:self]];
831                 }
832             }
833         }
834         else
835         {
836             /* all the other stuff are leafs */
837             o_children = IsALeafNode;
838         }
839     }
840     return o_children;
841 }
842
843 - (int)getObjectID
844 {
845     return i_object_id;
846 }
847
848 - (NSString *)getName
849 {
850     return o_name;
851 }
852
853 - (VLCTreeItem *)childAtIndex:(int)i_index {
854     return [[self children] objectAtIndex:i_index];
855 }
856
857 - (int)numberOfChildren {
858     id i_tmp = [self children];
859     return (i_tmp == IsALeafNode) ? (-1) : [i_tmp count];
860 }
861
862 - (BOOL)hasPrefs:(NSString *)o_module_name
863 {
864     intf_thread_t *p_intf = [NSApp getIntf];
865     module_t *p_parser;
866     vlc_list_t *p_list;
867     char *psz_module_name;
868     int i_index;
869
870     psz_module_name = (char *)[o_module_name UTF8String];
871
872     /* look for module */
873     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
874
875     for( i_index = 0; i_index < p_list->i_count; i_index++ )
876     {
877         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
878
879         if( !strcmp( p_parser->psz_object_name, psz_module_name ) )
880         {
881             BOOL b_has_prefs = p_parser->i_config_items != 0;
882             vlc_list_release( p_list );
883             return( b_has_prefs );
884         }
885     }
886
887     vlc_list_release( p_list );
888
889     return( NO );
890 }
891
892 @end
893
894
895 @implementation VLCFlippedView
896
897 - (BOOL)isFlipped
898 {
899     return( YES );
900 }
901
902 @end
903
904 IMPL_CONTROL_CONFIG(Button);
905 IMPL_CONTROL_CONFIG(PopUpButton);
906 IMPL_CONTROL_CONFIG(ComboBox);
907 IMPL_CONTROL_CONFIG(TextField);
908 IMPL_CONTROL_CONFIG(Slider);