]> git.sesse.net Git - vlc/blob - modules/gui/macosx/AddonManager.m
macosx: disable normvol slider if filter is disabled
[vlc] / modules / gui / macosx / AddonManager.m
1 /*****************************************************************************
2  * AddonManager.m: Addons manager for the Mac
3  ****************************************************************************
4  * Copyright (C) 2014 VideoLAN and authors
5  * Author:       Felix Paul Kühne <fkuehne # videolan.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20  *****************************************************************************/
21
22 #import "AddonManager.h"
23
24 #import <vlc_common.h>
25 #import <vlc_events.h>
26 #import <vlc_addons.h>
27 #import "intf.h"
28
29 @interface VLCAddonManager ()
30 {
31     addons_manager_t *_manager;
32     NSMutableArray *_addons;
33     NSArray *_displayedAddons;
34 }
35
36 - (void)addAddon:(addon_entry_t *)data;
37 - (void)discoveryEnded;
38 - (void)addonChanged:(addon_entry_t *)data;
39 @end
40
41 static void addonsEventsCallback( const vlc_event_t *, void * );
42
43 static void addonsEventsCallback( const vlc_event_t *event, void *data )
44 {
45     if (event->type == vlc_AddonFound)
46         [[VLCAddonManager sharedInstance] addAddon:event->u.addon_generic_event.p_entry];
47     else if (event->type == vlc_AddonsDiscoveryEnded)
48         [[VLCAddonManager sharedInstance] discoveryEnded];
49     else if (event->type == vlc_AddonChanged)
50         [[VLCAddonManager sharedInstance] addonChanged:event->u.addon_generic_event.p_entry];
51 }
52
53 @implementation VLCAddonManager
54
55 static VLCAddonManager *_o_sharedInstance = nil;
56
57 + (VLCAddonManager *)sharedInstance
58 {
59     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
60 }
61
62 #pragma mark - object handling
63
64 - (id)init
65 {
66     if (_o_sharedInstance)
67         [self dealloc];
68     else {
69         _o_sharedInstance = [super init];
70         _addons = [[NSMutableArray alloc] init];
71     }
72
73     return _o_sharedInstance;
74 }
75
76 - (void)dealloc
77 {
78     [_addons release];
79     [_displayedAddons release];
80     if ( _manager )
81         addons_manager_Delete(_manager);
82     [super dealloc];
83 }
84
85 #pragma mark - UI handling
86
87 - (void)awakeFromNib
88 {
89     [_typeSwitcher removeAllItems];
90     [_typeSwitcher addItemWithTitle:_NS("All")];
91     [[_typeSwitcher lastItem] setTag: -1];
92     /* no skins on OS X so far
93     [_typeSwitcher addItemWithTitle:_NS("Skins")];
94     [[_typeSwitcher lastItem] setTag:ADDON_SKIN2]; */
95     [_typeSwitcher addItemWithTitle:_NS("Playlist parsers")];
96     [[_typeSwitcher lastItem] setTag:ADDON_PLAYLIST_PARSER];
97     [_typeSwitcher addItemWithTitle:_NS("Service Discovery")];
98     [[_typeSwitcher lastItem] setTag:ADDON_SERVICE_DISCOVERY];
99     [_typeSwitcher addItemWithTitle:_NS("Extensions")];
100     [[_typeSwitcher lastItem] setTag:ADDON_EXTENSION];
101
102     [_localAddonsOnlyCheckbox setTitle:_NS("Show Installed Only")];
103     [_localAddonsOnlyCheckbox setState:NSOffState];
104     [_spinner setUsesThreadedAnimation:YES];
105
106     [_name setStringValue:@""];
107     [_author setStringValue:@""];
108     [_version setStringValue:@""];
109     [_description setString:@""];
110     [_window setTitle:_NS("Addons Manager")];
111
112     [[[_addonsTable tableColumnWithIdentifier:@"installed"] headerCell] setStringValue:_NS("Installed")];
113     [[[_addonsTable tableColumnWithIdentifier:@"name"] headerCell] setStringValue:_NS("Name")];
114     [[[_addonsTable tableColumnWithIdentifier:@"author"] headerCell] setStringValue:_NS("Author")];
115     [[[_addonsTable tableColumnWithIdentifier:@"type"] headerCell] setStringValue:_NS("Type")];
116
117     _manager = addons_manager_New((vlc_object_t *)VLCIntf);
118     if (!_manager)
119         return;
120
121     vlc_event_manager_t *p_em = _manager->p_event_manager;
122     vlc_event_attach(p_em, vlc_AddonFound, addonsEventsCallback, self);
123     vlc_event_attach(p_em, vlc_AddonsDiscoveryEnded, addonsEventsCallback, self);
124     vlc_event_attach(p_em, vlc_AddonChanged, addonsEventsCallback, self);
125 }
126
127 - (void)showWindow
128 {
129     [self _findNewAddons];
130     [_window makeKeyAndOrderFront:nil];
131 }
132
133 - (IBAction)switchType:(id)sender
134 {
135     [self _refactorDataModel];
136 }
137
138 - (IBAction)toggleLocalCheckbox:(id)sender
139 {
140     [self _refactorDataModel];
141 }
142
143 - (IBAction)installSelection:(id)sender
144 {
145     NSInteger selectedRow = [_addonsTable selectedRow];
146     if (selectedRow > _displayedAddons.count - 1 || selectedRow < 0)
147         return;
148
149     NSDictionary *currentItem = [_displayedAddons objectAtIndex:selectedRow];
150     [self _installAddonWithID:[[currentItem objectForKey:@"uuid"] pointerValue]];
151 }
152
153 - (IBAction)uninstallSelection:(id)sender
154 {
155     NSInteger selectedRow = [_addonsTable selectedRow];
156     if (selectedRow > _displayedAddons.count - 1 || selectedRow < 0)
157         return;
158
159     NSDictionary *currentItem = [_displayedAddons objectAtIndex:selectedRow];
160     [self _removeAddonWithID:[[currentItem objectForKey:@"uuid"] pointerValue]];
161 }
162
163 - (IBAction)refresh:(id)sender
164 {
165     [self _findNewAddons];
166 }
167
168 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
169 {
170     return [_displayedAddons count];
171 }
172
173 - (void)tableViewSelectionDidChange:(NSNotification *)aNotification
174 {
175     NSInteger selectedRow = [_addonsTable selectedRow];
176     if (selectedRow > _displayedAddons.count - 1 || selectedRow < 0) {
177         [_name setStringValue:@""];
178         [_author setStringValue:@""];
179         [_version setStringValue:@""];
180         [_description setString:@""];
181         return;
182     }
183
184     NSDictionary *currentItem = [_displayedAddons objectAtIndex:selectedRow];
185     [_name setStringValue:[currentItem objectForKey:@"name"]];
186     [_author setStringValue:[currentItem objectForKey:@"author"]];
187     [_version setStringValue:[currentItem objectForKey:@"version"]];
188     [_description setString:[currentItem objectForKey:@"description"]];
189 }
190
191 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
192 {
193     NSString *identifier = [aTableColumn identifier];
194     if ([identifier isEqualToString:@"installed"]) {
195         if ([[[_displayedAddons objectAtIndex:rowIndex] objectForKey:@"state"] intValue] == ADDON_INSTALLED)
196             return @"✔";
197         return @"✘";
198     } else if([identifier isEqualToString:@"type"])
199         return [self _getAddonType:[[[_displayedAddons objectAtIndex:rowIndex] objectForKey:@"type"] intValue]];
200
201     return [[_displayedAddons objectAtIndex:rowIndex] objectForKey:identifier];
202 }
203
204 #pragma mark - data handling
205
206 - (void)addAddon:(addon_entry_t *)p_entry
207 {
208     @autoreleasepool {
209         NSString *name = [NSString stringWithUTF8String:p_entry->psz_name ? p_entry->psz_name : ""];
210         if (p_entry->e_state == ADDON_INSTALLED)
211             name = [name stringByAppendingFormat: @" (%@)", _NS("Installed")];
212
213         NSDictionary *addonProperties = [NSDictionary dictionaryWithObjectsAndKeys:
214                                          name, @"name",
215                                          toNSStr(p_entry->psz_description), @"description",
216                                          toNSStr(p_entry->psz_author), @"author",
217                                          toNSStr(p_entry->psz_source_uri), @"uri",
218                                          toNSStr(p_entry->psz_version), @"version",
219                                          toNSStr(p_entry->psz_image_uri), @"imageuri",
220                                          [NSNumber numberWithInt:p_entry->e_state], @"state",
221                                          [NSNumber numberWithInt:p_entry->e_type], @"type",
222                                          [NSValue valueWithPointer:&p_entry->uuid], @"uuid",
223                                          nil];
224
225         /* no skin support on OS X so far */
226         if ([[addonProperties objectForKey:@"type"] intValue] != ADDON_SKIN2)
227             [_addons addObject:addonProperties];
228     }
229 }
230
231 - (void)discoveryEnded
232 {
233     [self _refactorDataModel];
234     [_spinner stopAnimation:nil];
235 }
236
237 - (void)addonChanged:(addon_entry_t *)data
238 {
239     [self _refactorDataModel];
240 }
241
242 #pragma mark - helpers
243
244 - (void)_refactorDataModel
245 {
246     BOOL installedOnly = _localAddonsOnlyCheckbox.state == NSOnState;
247     int type = [[_typeSwitcher selectedItem] tag];
248
249     NSUInteger count = _addons.count;
250     NSMutableArray *filteredItems = [[NSMutableArray alloc] initWithCapacity:count];
251     NSDictionary *currentItem;
252     for (NSUInteger x = 0; x < count; x++) {
253         currentItem = [_addons objectAtIndex:x];
254         if (type != -1) {
255             if ([[currentItem objectForKey:@"type"] intValue] == type) {
256                 if (installedOnly) {
257                     if ([[currentItem objectForKey:@"state"] intValue] == ADDON_INSTALLED)
258                         [filteredItems addObject:currentItem];
259                 } else
260                     [filteredItems addObject:currentItem];
261             }
262         } else {
263             if (installedOnly) {
264                 if ([[currentItem objectForKey:@"state"] intValue] == ADDON_INSTALLED)
265                     [filteredItems addObject:currentItem];
266             } else
267                 [filteredItems addObject:currentItem];
268         }
269     }
270
271     if (_displayedAddons)
272         [_displayedAddons release];
273     _displayedAddons = [NSArray arrayWithArray:filteredItems];
274     [_displayedAddons retain];
275     [filteredItems release];
276     [_addonsTable reloadData];
277 }
278
279 - (void)_findNewAddons
280 {
281     [_spinner startAnimation:nil];
282     addons_manager_Gather(_manager, "repo://");
283 }
284
285 /* FIXME: un-used */
286 - (void)_findDesignatedAddon:(NSString *)uri
287 {
288     addons_manager_Gather(_manager, [uri UTF8String]);
289 }
290
291 /* FIXME: un-used */
292 - (void)_findInstalled
293 {
294     addons_manager_LoadCatalog(_manager);
295 }
296
297 - (void)_installAddonWithID:(addon_uuid_t)addonid
298 {
299     addons_manager_Install(_manager, addonid);
300 }
301
302 - (void)_removeAddonWithID:(addon_uuid_t)addonid
303 {
304     addons_manager_Remove(_manager, addonid);
305 }
306
307 - (NSString *)_getAddonType:(int)i_type
308 {
309     switch (i_type)
310     {
311         case ADDON_SKIN2:
312             return _NS("Skins");
313         case ADDON_PLAYLIST_PARSER:
314             return _NS("Playlist parsers");
315         case ADDON_SERVICE_DISCOVERY:
316             return _NS("Service Discovery");
317         case ADDON_EXTENSION:
318             return _NS("Extensions");
319         default:
320             return _NS("Unknown");
321     }
322 }
323
324 @end