Prevent sending 0-byte files. Fixes #8711.
[adiumx.git] / Source / AIDockIconSelectionSheet.m
blob48074e4a59b5f55c69aa7d4d12b8e594b365b263
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6  * General Public License as published by the Free Software Foundation; either version 2 of the License,
7  * or (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
11  * Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License along with this program; if not,
14  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15  */
17 #import "AIDockController.h"
18 #import "AIDockIconSelectionSheet.h"
19 #import "AIAppearancePreferencesPlugin.h"
20 #import <Adium/AIPreferenceControllerProtocol.h>
21 #import <AIUtilities/AIFileManagerAdditions.h>
22 #import <AIUtilities/AIImageGridView.h>
23 #import <Adium/AIIconState.h>
25 #define PREF_GROUP_DOCK_ICON            @"Dock Icon"
26 #define DEFAULT_DOCK_ICON_NAME          @"Adiumy Green"
28 @interface AIDockIconSelectionSheet (PRIVATE)
29 - (void)selectIconWithName:(NSString *)selectName;
30 - (void)xtrasChanged:(NSNotification *)notification;
31 - (void)selectIconWithName:(NSString *)selectName;
32 @end
34 @implementation AIDockIconSelectionSheet
36 + (void)showDockIconSelectorOnWindow:(NSWindow *)parentWindow
38         AIDockIconSelectionSheet        *controller;
39         
40         controller = [[self alloc] initWithWindowNibName:@"DockIconSelectionSheet"];
41         
42         if (parentWindow) {
43                 [NSApp beginSheet:[controller window]
44                    modalForWindow:parentWindow
45                         modalDelegate:controller
46                    didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
47                           contextInfo:nil];
48         } else {
49                 [controller showWindow:nil];
50                 [[controller window] makeKeyAndOrderFront:nil];
51                 [NSApp activateIgnoringOtherApps:YES];
52         }
55 /*!
56  * Invoked as the sheet closes, dismiss the sheet
57  */
58 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
60     [sheet orderOut:nil];
62     [self setAnimatedDockIconAtIndex:-1];
63         [self autorelease];
66 //Setup our preference view
67 - (void)windowDidLoad
69         //Init
70         animatedIndex = -1;
71         iconArray = nil;
73         //Setup our image grid
74         [imageGridView_icons setImageSize:NSMakeSize(64,64)];
76     //Observe xtras changes
77         [[adium notificationCenter] addObserver:self
78                                                                    selector:@selector(xtrasChanged:)
79                                                                            name:AIXtrasDidChangeNotification
80                                                                          object:nil];
81         [self xtrasChanged:nil];
83         [button_OK setLocalizedString:AILocalizedStringFromTable(@"Close", @"Buttons", nil)];
85         [super windowDidLoad];
88 - (void)dealloc
90         [[adium notificationCenter] removeObserver:self];
91         [iconArray release]; iconArray = nil;
93         [super dealloc];
96 //Preference view is closing
97 - (void)windowWillClose:(id)sender
99         [super windowWillClose:sender];
100         
101     [self setAnimatedDockIconAtIndex:-1];
102         [self autorelease];
105 //When the xtras are changed, update our icons
106 - (void)xtrasChanged:(NSNotification *)notification
108         if (!notification || [[notification object] caseInsensitiveCompare:@"AdiumIcon"] == 0) {
109                 [iconArray release];
110                 iconArray = [[NSMutableArray alloc] init];
111                 
112                 //Fetch the pack previews
113                 NSEnumerator    *enumerator = [[[adium dockController] availableDockIconPacks] objectEnumerator];
114                 NSString                *path;
115                 
116                 while ((path = [enumerator nextObject])) {
117                         AIIconState             *previewState = [[adium dockController] previewStateForIconPackAtPath:path];
118                         [iconArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:path, @"Path", previewState, @"State", nil]];    
119                 }
120                 
121                 [imageGridView_icons reloadData];
122                 [self selectIconWithName:[[adium preferenceController] preferenceForKey:KEY_ACTIVE_DOCK_ICON
123                                                                                                                                                   group:PREF_GROUP_APPEARANCE]];
124         }
131 //Build an array of available icon packs
135 //- (void)_buildIconArray
137 //    NSDirectoryEnumerator     *fileEnumerator;
138 //    NSString                          *iconPath;
139 //    NSString                          *filePath;
140 //      NSEnumerator                    *enumerator;
142 //    //Create a fresh icon array
143 //    [iconArray release]; iconArray = [[NSMutableArray alloc] init];
144 //      enumerator = [[adium resourcePathsForName:FOLDER_DOCK_ICONS] objectEnumerator];
145 //      
146 //    while ((iconPath = [enumerator nextObject])) {            
147 //        fileEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:iconPath];
148 //        
149 //        //Find all the .AdiumIcon's
150 //        while ((filePath = [fileEnumerator nextObject])) {
151 //            if ([[filePath pathExtension] caseInsensitiveCompare:@"AdiumIcon"] == NSOrderedSame) {
152 //                NSString              *fullPath;
153 //                AIIconState           *previewState;
154 //                
155 //                //Get the icon pack's full path and preview state
156 //                fullPath = [iconPath stringByAppendingPathComponent:filePath];
157 //                              previewState = [[adium dockController] previewStateForIconPackAtPath:fullPath];
158 //    
159 //                //Add this icon to our icon array
160 //                [iconArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:fullPath, @"Path", previewState, @"State", previewState, @"Original State", nil]];    
161 //                      }
162 //        }
163 //    }
164 //    
165 //    //Update our view and re-select the correct icon
166 //      [imageGridView_icons reloadData];
167 //      [self selectIconWithName:[[adium preferenceController] preferenceForKey:KEY_ACTIVE_DOCK_ICON group:PREF_GROUP_APPEARANCE]];
170 //Set the selected icon by name
171 - (void)selectIconWithName:(NSString *)selectName
173         NSEnumerator    *enumerator = [iconArray objectEnumerator];
174         NSDictionary    *iconDict;
175         int                             index = 0;
176         
177         while ((iconDict = [enumerator nextObject])) {
178                 NSString        *iconName = [[[iconDict objectForKey:@"Path"] lastPathComponent] stringByDeletingPathExtension]         ;
179                 if ([iconName isEqualToString:selectName]) {
180                         [imageGridView_icons selectIndex:index];
181                         break; //we can exit early
182                 }
183                 index++;
184         }
188 //Animation ------------------------------------------------------------------------------------------------------------
189 #pragma mark Animation
190 //Start animating an icon in our grid by index (pass -1 to stop animation)
191 - (void)setAnimatedDockIconAtIndex:(int)index
193         //Schedule the old and new animating images for redraw
194         [imageGridView_icons setNeedsDisplayOfImageAtIndex:animatedIndex];
195         [imageGridView_icons setNeedsDisplayOfImageAtIndex:index];
196         
197         //Stop the current animation
198     if (animationTimer) {
199         [animationTimer invalidate];
200         [animationTimer release];
201         animationTimer = nil;
202         }
203         [animatedIconState release]; animatedIconState = nil;
204         animatedIndex = -1;
206         //Start the new animation
207         if (index != -1) {
208                 NSString        *path = [[iconArray objectAtIndex:index] objectForKey:@"Path"];
210                 animatedIconState = [[self animatedStateForDockIconAtPath:path] retain];
211                 animatedIndex = index;
212                 animationTimer = [[NSTimer scheduledTimerWithTimeInterval:[animatedIconState animationDelay]
213                                                                                                                    target:self
214                                                                                                                  selector:@selector(animate:)
215                                                                                                                  userInfo:nil
216                                                                                                                   repeats:YES] retain];
217     }
220 //Returns an animated AIIconState for the dock icon pack at the specified path
221 - (AIIconState *)animatedStateForDockIconAtPath:(NSString *)path
223         NSDictionary    *iconPackDict = [[adium dockController] iconPackAtPath:path];
224         NSDictionary    *stateDict = [iconPackDict objectForKey:@"State"];
225         
226         return [[[AIIconState alloc] initByCompositingStates:[NSArray arrayWithObjects:
227                 [stateDict objectForKey:@"Base"],
228                 [stateDict objectForKey:@"Online"],
229                 [stateDict objectForKey:@"Alert"], nil]] autorelease];
232 //Animate the hovered icon
233 - (void)animate:(NSTimer *)timer
235         [animatedIconState nextFrame];
236         [imageGridView_icons setNeedsDisplayOfImageAtIndex:animatedIndex];
239 //ImageGridView Delegate -----------------------------------------------------------------------------------------------
240 #pragma mark ImageGridView Delegate
241 - (int)numberOfImagesInImageGridView:(AIImageGridView *)imageGridView
243         return [iconArray count];
246 - (NSImage *)imageGridView:(AIImageGridView *)imageGridView imageAtIndex:(int)index
248         if (index == animatedIndex) {
249                 return [animatedIconState image];
250         } else {
251                 return [[[iconArray objectAtIndex:index] objectForKey:@"State"] image];
252         }
255 - (void)imageGridViewSelectionDidChange:(NSNotification *)notification
256 {       
257         NSDictionary    *iconDict = [iconArray objectAtIndex:[imageGridView_icons selectedIndex]];
258         NSString                *iconName = [[[iconDict objectForKey:@"Path"] lastPathComponent] stringByDeletingPathExtension];
259         
260         if (![[[adium preferenceController] preferenceForKey:KEY_ACTIVE_DOCK_ICON group:PREF_GROUP_APPEARANCE] isEqualToString:iconName])
261                 [[adium preferenceController] setPreference:iconName forKey:KEY_ACTIVE_DOCK_ICON group:PREF_GROUP_APPEARANCE];
264 - (void)imageGridView:(AIImageGridView *)imageGridView cursorIsHoveringImageAtIndex:(int)index
266         [self setAnimatedDockIconAtIndex:index];
270 //Deleting dock xtras --------------------------------------------------------------------------------------------------
271 #pragma mark Deleting dock xtras
272 //Delete the selected dock icon
273 - (void)imageGridViewDeleteSelectedImage:(AIImageGridView *)imageGridView
274 {            
275         NSString        *selectedIconPath = [[iconArray objectAtIndex:[imageGridView selectedIndex]] valueForKey:@"Path"];
276         NSString        *name = [[selectedIconPath lastPathComponent] stringByDeletingPathExtension];
277         
278         //We need atleast one icon installed, so prevent the user from deleting the default icon
279         if (![name isEqualToString:DEFAULT_DOCK_ICON_NAME]) {
280                 NSBeginAlertSheet(AILocalizedString(@"Delete Dock Icon",nil),
281                                                   AILocalizedString(@"Delete",nil),
282                                                   AILocalizedString(@"Cancel",nil),
283                                                   @"",
284                                                   [self window], 
285                                                   self, 
286                                                   @selector(trashConfirmSheetDidEnd:returnCode:contextInfo:),
287                                                   nil,
288                                                   selectedIconPath,
289                                                   AILocalizedString(@"Are you sure you want to delete the %@ Dock Icon? It will be moved to the Trash.",nil), name);
290         }
292 - (void)trashConfirmSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(NSString *)selectedIconPath
294     if (returnCode == NSOKButton) {
295                 int deletedIndex = [imageGridView_icons selectedIndex];
296                 
297                 //Deselect and stop animating
298                 [self setAnimatedDockIconAtIndex:-1];
299                 [imageGridView_icons selectIndex:-1];
300                 
301                 //Trash the file & Rebuild our icons
302                 [[NSFileManager defaultManager] trashFileAtPath:selectedIconPath];
304                 //Select the next available icon
305                 [imageGridView_icons selectIndex:deletedIndex];
306     }
309 @end