Use TopfieldUSBEcode for received values too.
[MacTF.git] / UIElements.m
blob676997f24a755412061eb18cb624a92031039c3e
1 // MacTF Copyright 2004 Nathan Oates
3 /* 
5  * This source code is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Public License as published
7  * by the Free Software Foundation; either version 2 of the License,
8  * or (at your option) any later version.
9  *
10  * This source code is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * Please refer to the GNU Public License for more details.
14  *
15  * You should have received a copy of the GNU Public License along with
16  * this source code; if not, write to:
17  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
20 /* This file was modified by Kalle Olavi Niemitalo on 2007-10-18.  */
22 #import "UIElements.h"
23 #include <unistd.h>
25 @interface UIElements (PrivateMethods)
26 - (void) setCurrentPath:(NSString*)path;
27 @end
29 @implementation UIElements
31 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:
32         (NSApplication *)theApplication {
33     return YES;
36 - (BOOL)application:(NSApplication *)sender openFile:(NSString *)path
38         if (!connected) 
39                 [self connect:nil];
40         [self uploadPath:path toPath:[NSString stringWithString:currentPath]];
41         NSLog(@"DockUpload:%@", path);
42         return YES;
45 -(void) awakeFromNib {
46         connected = NO;
47         paused = NO;
48         highlightImageData = @"<4d4d002a 00000048 800f4f6d a2ca65ca 564b390a 69371941 1ee22622 dc04743b 7c86826e 900fcdb1 d9e5b237 3ab60647 06b0b8d8 d5151a1a 82732348 46616888 4bcd00f9 719f0100 000d0100 00030000 00010001 00000101 00030000 00010012 00000102 00030000 00030000 00ea0103 00030000 00010005 00000106 00030000 00010002 00000111 00040000 00010000 00080115 00030000 00010003 00000116 00040000 00010000 2aaa0117 00040000 00010000 003f011a 00050000 00010000 00f0011b 00050000 00010000 00f8011c 00030000 00010001 00000128 00030000 00010002 00000000 00000008 00080008 000afc80 00002710 000afc80 00002710 >";
49         [self setCurrentPath:@"\\"];
50         [currentlyField setStringValue:NSLocalizedString(@"IDLE", @"Idle")];
51         [currentlyField displayIfNeeded];
52         [tableView setDoubleAction: @selector(doubleClick:)];
53         [tableView setTarget: self];
54         [tableView registerForDraggedTypes: [NSArray arrayWithObjects: @"NSFilenamesPboardType", @"NSFilenamesPboardType", nil]];
55         tfusbc = [[TFUSBController alloc] init];
56         [tfusbc setDH:dh tableView:tableView]; //send needed items to tfusbc
57         sortAscending = TRUE;
58         [turboCB setState:0];
59         [turboCB setEnabled:NO];
60         [versionField setStringValue:[[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBundleVersion"]]; 
61         [pathBar setEnabled:YES];
62         [[pathBar cell] setSegmentCount:1];
63         [[pathBar cell] setLabel:@"Path:" forSegment:0];
64         [[pathBar cell] setWidth:0 forSegment:0];
65         [pathBar sizeToFit];
66         [[dh fileList] addObject:[NSDictionary dictionaryWithObject:NSLocalizedString(@"NOT_CONNECTED_ENTRY", @"Not connected") forKey:@"name"]];
67         [tableView reloadData];
68         prefs = [[NSUserDefaults standardUserDefaults] retain];
69         if ([prefs boolForKey:@"auto-connect"]) {
70                 [self connect:nil];
71                 [autoCB setState:1];    
72         }
75 - (BOOL)validateMenuItem:(NSMenuItem*)anItem {
76     if ([[anItem title] isEqualToString:NSLocalizedString(@"DL_MENUITEM", @"Download")] && (1 > [tableView numberOfSelectedRows])) {
77         return NO;
78     }
79         if ([[anItem title] isEqualToString:NSLocalizedString(@"DEL_MENUITEM", @"Delete")] && (1 > [tableView numberOfSelectedRows])) {
80         return NO;
81     }
82         if ([[anItem title] isEqualToString:NSLocalizedString(@"RN_MENUITEM", @"Rename")] && (1 != [tableView numberOfSelectedRows])) {
83         return NO;
84     }
85         if ([[anItem title] isEqualToString:NSLocalizedString(@"UL_MENUITEM", @"Upload")] && (! connected)) {
86         return NO;
87     }
88         if ([[anItem title] isEqualToString:NSLocalizedString(@"NF_MENUITEM", @"NewFolder")] && (! connected)) {
89         return NO;
90     }
91     return YES;
94 - (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem {
95     if ([[toolbarItem itemIdentifier] isEqual:@"ConnectTBIcon"]) {
96                 if (connected) {
97                         [toolbarItem setLabel:NSLocalizedString(@"DC_BUTTON", @"Disconnect")];
98                 } else {
99                         [toolbarItem setLabel:NSLocalizedString(@"CON_BUTTON", @"Connect")];
100                 }
101         }
102         if ([[toolbarItem itemIdentifier] isEqual:@"UploadTBIcon"] && (! connected)) {
103                 return NO;
104         }
105         if ([[toolbarItem itemIdentifier] isEqual:@"NewFolderTBIcon"] && (! connected)) {
106                 return NO;
107         }
108         if ([[toolbarItem itemIdentifier] isEqual:@"TurboTBIcon"] && (! connected)) {
109                 return NO;
110         }
111         if ([[toolbarItem itemIdentifier] isEqual:@"DownloadTBIcon"] && (1 > [tableView numberOfSelectedRows] || !connected)) {
112                 return NO;
113         }
114         if ([[toolbarItem itemIdentifier] isEqual:@"DeleteTBIcon"] && (1 > [tableView numberOfSelectedRows] || !connected)) {
115                 return NO;
116         }
117         if ([[toolbarItem itemIdentifier] isEqual:@"RenameTBIcon"] && (1 != [tableView numberOfSelectedRows] || !connected)) {
118                 return NO;
119         }
120     return YES;
124 - (void)tableViewSelectionDidChange:(NSNotification *)aNotification
126         [preview setString:@""];
127         if ([previewDrawer state] == NSDrawerClosedState) return; // don't bother getting previews if closed
128         if ([tableView numberOfSelectedRows] != 1 || !connected)
129                 return;
130         if ([tfusbc hasCurrentTransfer]) return; //for now, change to a priority transfer later?
131         id currentSelectedItem = [[dh displayedList] objectAtIndex:[tableView selectedRow]];
132         int type = [[currentSelectedItem objectForKey:@"type"] intValue];
133         if (type == 2) { //file
134                 NSString* nameOnToppy = [currentSelectedItem objectForKey:@"name"]; 
135                 if (([nameOnToppy hasSuffix:@".ini"] || [nameOnToppy hasSuffix:@".txt"] || [nameOnToppy hasSuffix:@".tgd"] || [nameOnToppy hasSuffix:@".tsv"] || [nameOnToppy hasSuffix:@".dat"] || [nameOnToppy hasSuffix:@".tap"])) {
136                         [drawerTabView selectTabViewItemAtIndex:0];
137                         NSString* tempFile = NSTemporaryDirectory(); // download preview to temp folder
138                         tempFile = [tempFile stringByAppendingPathComponent:@"MacTFTemp"];
139                         [tfusbc addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:currentSelectedItem,@"filename",currentPath,@"path",tempFile,@"savePath",[NSNumber numberWithUnsignedLongLong:0],@"offset",@"download",@"transferType",[NSNumber numberWithBool:NO],@"looping",[NSNumber numberWithInt:0],@"existingTime",nil] atIndex:-1];
140                         while ([tfusbc hasCurrentTransfer]) {
141                                 usleep(10);
142                         }
143                         [preview setString:[NSString stringWithContentsOfFile:tempFile]];
144                 } else if ([nameOnToppy hasSuffix:@".rec"]) { //display headers
145                         [drawerTabView selectTabViewItemAtIndex:1];
146                         NSString* tempFile = NSTemporaryDirectory(); // download first 64k to temp folder
147                         tempFile = [tempFile stringByAppendingPathComponent:@"MacTFTemp"];
148                         [tfusbc addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:currentSelectedItem,@"filename",currentPath,@"path",tempFile,@"savePath",[NSNumber numberWithUnsignedLongLong:0],@"offset",@"download",@"transferType",[NSNumber numberWithBool:NO],@"looping",[NSNumber numberWithInt:0],@"existingTime",nil] atIndex:-1];
149                         while ([tfusbc hasCurrentTransfer]) {
150                                 usleep(10);
151                         }
152                         NSDictionary* recData = [dh extractDataFromRecHeader:tempFile forModel:[prefs objectForKey:@"modelType"]]; //then parse and display headers
153                         [recStart setObjectValue:[recData objectForKey:@"startTime"]];
154                         [recDuration setObjectValue:[recData objectForKey:@"duration"]];
155                         [recDescription setStringValue:[recData objectForKey:@"description"]];
156                         [recName setStringValue:[recData objectForKey:@"name"]];
157                         [recExtInfo setStringValue:[recData objectForKey:@"extInfo"]];
158                         [recChannel setStringValue:[recData objectForKey:@"channel"]];
159                 }       
160                 else {
161                         [drawerTabView selectTabViewItemAtIndex:0];
162                         return;
163                 }
164         } else if (type == 1) { //folder
165                 [drawerTabView selectTabViewItemAtIndex:0];
166                 return;
167         } else {
168                 [statusField setStringValue:NSLocalizedString(@"SEL_ERROR", @"Selection error...")];
169                 return;
170         }
173 - (void) setAvailableSpace:(NSData*)input {
174         [availSpaceField setStringValue:[self prepForSizeDisplay:input]];
177 - (void) setFreeSpace:(NSData*) input {
178         [freeSpaceField setStringValue:[self prepForSizeDisplay:input]];
181 - (NSString*) prepForSizeDisplay:(NSData*) input {
182         UInt32 size_bigendian;
183         [input getBytes:&size_bigendian];
184         unsigned size = EndianU32_BtoN(size_bigendian);
185         NSString *ret = nil;
186                 if( size == 0. ) ret = NSLocalizedString( @" - ", "no file size" );
187                 else if( size > 0. && size < 1024. ) ret = [NSString stringWithFormat:NSLocalizedString( @"%.0f KB", "file size measured in kilobytes" ), size];
188                 else if( size >= 1024. && size < pow( 1024., 2. ) ) ret = [NSString stringWithFormat:NSLocalizedString( @"%.1f MB", "file size measured in megabytes" ), ( size / 1024. )];
189                 else if( size >= pow( 1024., 2. ) && size < pow( 1024., 3. ) ) ret = [NSString stringWithFormat:NSLocalizedString( @"%.2f GB", "file size measured in gigabytes" ), ( size / pow( 1024., 2. ) )];
190                 else if( size >= pow( 1024., 3. ) && size < pow( 1024., 4. ) ) ret = [NSString stringWithFormat:NSLocalizedString( @"%.3f TB", "file size measured in terabytes" ), ( size / pow( 1024., 3. ) )];
191                 else if( size >= pow( 1024., 4. ) ) ret = [NSString stringWithFormat:NSLocalizedString( @"%.4f PB", "file size measured in pentabytes" ), ( size / pow( 1024., 4. ) )];
192         return ret;
195 - (IBAction) connect: (id) sender { 
196         if (! connected) {
197                 context = [tfusbc initializeUSB];
198                 if (context == nil) {
199                         [statusField setStringValue:NSLocalizedString(@"INIT_PROBLEM", @"Message when initialization fails.")];
200                         return;
201                 }
202                 // add a check here to see if really connected...
203                 connected = YES;
204                 [[dh fileList] removeAllObjects];
205                 [[dh fileList] addObject:[NSDictionary dictionaryWithObject:NSLocalizedString(@"FETCHING", @"Fetching") forKey:@"name"]];
206                 [tableView reloadData];
207                 [tfusbc clearQueues];
208                 paused = NO;
209                 [turboCB setState:0];
210                 [turboCB setEnabled:YES];
211                 [[pathBar cell] setSegmentCount:2];
212                 [[pathBar cell] setLabel:@"Path:" forSegment:0];
213                 [[pathBar cell] setLabel:@"\\" forSegment:1];
214                 [[pathBar cell] setWidth:0 forSegment:0];
215                 [[pathBar cell] setWidth:0 forSegment:1];
216                 [pathBar sizeToFit];
217                 [pathBar setHidden:NO];
218                 [connectLight setImage:[NSImage imageNamed:@"green.tiff"]];
219                 [connectButton setTitle:NSLocalizedString(@"DC_BUTTON", @"Disconnect.")];
220                 [statusField setStringValue:[NSString stringWithFormat:NSLocalizedString(@"CONNECTED_MESSAGE", @"Message giving connection speed."), [tfusbc getSpeed]]];
221                 [NSThread detachNewThreadSelector:@selector(transfer:) toTarget:tfusbc withObject:nil];
222         } else { // already connected
223                 connected = NO;
224                 if ([tfusbc hasCurrentTransfer]) { //gives a few seconds for busy thread to notice it should not be connected before cutting the device off
225                         sleep(3);
226                 }
227                 [tfusbc closeDevice:context];
228                 [connectButton setTitle:NSLocalizedString(@"CON_BUTTON", @"Connect.")];
229                 [statusField setStringValue:NSLocalizedString(@"NO_CONNECT", @"No connection.")];
230                 [[dh fileList] removeAllObjects];
231                 [tableView reloadData];
232                 [turboCB setState:0];
233                 [turboCB setEnabled:NO];
234                 [connectLight setImage:[NSImage imageNamed:@"red.tiff"]];
235                 [self setCurrentPath:@"\\"];
236                 return;
237         }
238         int ret = [self goToPath:@"\\"];
239         if (ret == 1) { 
240                 sleep (5); //error, wait a few secs for HDD to start if need be then try again
241                 [self goToPath:@"\\"];
242         }
243         [self setCurrentPath:@"\\"];
246 - (int) goToPath:(NSString*) path {
247         [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:path,@"path",@"fileList",@"transferType",nil]];
248         // FIXME: The caller would like to know whether the operation succeeded.
249         // But it has not even finished yet.  So goToPath should somehow notify
250         // the caller on completion.
251         return 0;
254 - (void)doubleClick:(id)sender
256         if ([tableView numberOfSelectedRows] != 1)
257                 return;
258         id currentSelectedItem = [[dh displayedList] objectAtIndex:[tableView selectedRow]];
259         int type = [[currentSelectedItem objectForKey:@"type"] intValue];
260         if (type == 2) { //file
261                 [self downloadFileDoubleClickThread:nil];
262         } else if (type == 1) { //folder
263                 NSString* currentName = [currentSelectedItem objectForKey:@"name"];
264                 if ([currentName isEqualToString:@".. (Parent folder)"]) { // move up
265                         NSMutableArray* array = [NSMutableArray arrayWithArray:[currentPath componentsSeparatedByString:@"\\"]];
266                         if ([array count] > 1){ // not going to root
267                                 [array removeLastObject];
268                                 NSString* temp = [NSString stringWithString:[array componentsJoinedByString:@"\\"]];
269                                 if ([self goToPath:temp]) {// if error
270                                         [self goToPath:temp]; // hackish workaround
271                                 }
272                                 int segCount = [pathBar segmentCount]; //remember count starts at 1, not zero!
273                                 NSRect r = [pathBar frame];
274                                 [[pathBar cell] setSegmentCount:segCount-1];
275                                 [pathBar setNeedsDisplayInRect:r];
276                                 [pathBar displayIfNeeded];
277                                 [self setCurrentPath:temp];
278                                 [statusField setStringValue:NSLocalizedString(@"CONNECTED_OK", @"Connection OK")];
279                         } else {//root
280                                 [self setCurrentPath:@"\\"];
281                                 [[pathBar cell] setSegmentCount:1];
282                         }
283                 } else { //move down
284                         NSMutableString* temp = [NSMutableString stringWithString:currentPath];
285                         if (![temp isEqualToString:@"\\"])
286                                         [temp appendString:@"\\"];
287                         [temp appendString:currentName];
288                         if ([self goToPath:temp]) { // if error, try again
289                                 [self goToPath:temp]; // hackish workaround
290                 }
291                         [self setCurrentPath:temp];
292                         int segCount = [pathBar segmentCount]; //remember count starts at 1, not zero!
293                         NSRect r = [pathBar frame];
294                         [[pathBar cell] setSegmentCount:segCount+1];
295                         [[pathBar cell] setLabel:currentName forSegment:segCount];
296                         [[pathBar cell] setWidth:0 forSegment:segCount];
297                         [pathBar sizeToFit];
298                         [pathBar displayIfNeededInRect:r];
299                         [statusField setStringValue:NSLocalizedString(@"CONNECTED_OK", @"Connection OK")];
300                 }
301         } else {
302                 [statusField setStringValue:NSLocalizedString(@"SEL_ERROR", @"Selection error...")];
303                 return; 
304         }
307 - (void) downloadFileDoubleClickThread:(NSDictionary*)fileInfo {
308         if (! connected) return;
309                 [self downloadSelectedFile:nil];
310 //      [self updateHDDSize];
313 /*- (void) updateHDDSize {
314         if (! connected) return;
315         NSData* hddSizeString = [tfusbc getHDDSize:context];
316         if (hddSizeString != nil) {
317                 [self setAvailableSpace:[hddSizeString subdataWithRange:(NSRange) {8,4}]];
318                 [self setFreeSpace:[hddSizeString subdataWithRange:(NSRange) {12,4}]];
319         } 
322 - (void)tableView:(NSTableView *)tView didClickTableColumn:(NSTableColumn *)tableColumn
324         // Either reverse the sort or change the sorting column
325         NSString* columnIdentifier = [tableColumn identifier];
326         BOOL newSortAscending = !(sortAscending && [tableColumn isEqualTo:selectedColumn]);
327         
328         NSString* sortKey = nil;
329         SEL sortSelector = @selector(compare:);
330         if ([columnIdentifier isEqualToString:@"name"]) {
331                 sortKey = @"name";
332                 sortSelector = @selector(caseInsensitiveCompare:);
333         } else if ([columnIdentifier isEqualToString:@"date"]) {
334                 sortKey = @"sortdate";
335         } else if ([columnIdentifier isEqualToString:@"size"]) {
336                 sortKey = @"fileSize";
337         } else if ([columnIdentifier isEqualToString:@"icon"]) {
338                 sortKey = @"suffix";
339         }
340         if (sortKey == nil)
341                 return;
343         NSSortDescriptor* descriptor = [[[NSSortDescriptor alloc]
344                         initWithKey:sortKey ascending:newSortAscending selector:sortSelector]
345                 autorelease];
346         NSArray* sortedArray = [[dh fileList] sortedArrayUsingDescriptors:
347                 [NSArray arrayWithObject:descriptor]];
348         NSImage* indicatorImage = [NSImage imageNamed:
349                 newSortAscending ? @"NSAscendingSortIndicator" : @"NSDescendingSortIndicator"];
351         sortAscending = newSortAscending;
352         selectedColumn = tableColumn;
353         [tView setIndicatorImage: indicatorImage inTableColumn: tableColumn];
354         // remove other indicators
355         NSMutableArray* otherColumns = [NSMutableArray arrayWithArray:[tView tableColumns]];
356         [otherColumns  removeObject:tableColumn];
357         NSEnumerator* cols = [otherColumns objectEnumerator];
358         id currentCol;
359         while (currentCol = [cols nextObject]) {
360                 [tView setIndicatorImage: nil inTableColumn: currentCol];
361         }
362         [dh setFileList:sortedArray];
363         [dh search:searchField];
364         [dh reloadTable];
368 - (IBAction) downloadSelectedFile:(id)sender{
369         if (! connected)
370                 return;
371         NSLog(@"Download file starting...");
372         NSEnumerator* selected = [tableView selectedRowEnumerator];
373         id currentSelected;
374         while (currentSelected = [selected nextObject]) {
375                 id currentSelectedItem = [[dh displayedList] objectAtIndex:[currentSelected intValue]];
376                 int type = [[currentSelectedItem objectForKey:@"type"] intValue];
377                 if (type == 1) {[statusField setStringValue:NSLocalizedString(@"NO_FOLDER_DL", @"Folder download not supported yet")];}
378                 else if (type == 2) {
379                         NSString* nameOnToppy = [currentSelectedItem objectForKey:@"name"];
380                         NSSavePanel *nssave = [[NSSavePanel savePanel]retain];
381                         int retButton = [nssave runModalForDirectory:nil file:nameOnToppy];
382                         if (retButton) {
383                                 NSString* savePath= [nssave filename]; 
384                                 NSLog(savePath);
385                                 unsigned long long offset = 0;
386                                 NSFileHandle *newFileHandle = [NSFileHandle fileHandleForReadingAtPath:savePath];
387                                 if (!(newFileHandle==nil)) { // there is a file there, ask if want to resume
388                                         NSLog(@"existing file length: %qu", [newFileHandle seekToEndOfFile]);
389                                         //ask to resume, save offset if yes
390                                         //offset = [newFileHandle seekToEndOfFile];
391                                 }
392                                 [tfusbc setProgressBar:progressBar time:progressTime turbo:turboCB];
393                                 [tfusbc addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:currentSelectedItem,@"filename",currentPath,@"path",savePath,@"savePath",[NSNumber numberWithUnsignedLongLong:offset],@"offset",@"download",@"transferType",[NSNumber numberWithBool:YES],@"looping",[NSNumber numberWithInt:0],@"existingTime",nil] atIndex:-1];
394                         }
395                 }               
396         }
397         //              [self updateHDDSize];
398         }
400 - (void) finishTransfer {
401         [currentlyField setStringValue:@""];
402         [progressBar setDoubleValue:0];
403         [[NSSound soundNamed:@"Ping"] play];
404         [connectLight setImage:[NSImage imageNamed:@"green.tiff"]];
405         [currentlyField setStringValue:NSLocalizedString(@"IDLE", @"Idle")];
406         [currentlyField display];
409 - (IBAction) uploadFile: (id) sender {
410         if (! connected)
411                 return;
412         NSOpenPanel *nsop = [[NSOpenPanel openPanel]retain];
413         [nsop setAllowsMultipleSelection:YES];
414         [nsop setCanChooseFiles:YES];
415         [nsop setCanChooseDirectories:YES];
416         int retButton = [nsop runModal];
417         NSArray *returnedNames = [nsop filenames];      
418         if (retButton == NSFileHandlingPanelCancelButton) {             
419                 NSLog(@"Upload cancelled");
420                 return;
421         }
422         //get info about the chosen file - later if do folders check here and do recursive all things in folder???
423         NSEnumerator *enumerator = [returnedNames objectEnumerator];
424         id returnedName;
425 //      [statusField setStringValue:[NSLocalizedString(@"CONNECTED_OK", @"Connection OK") stringByAppendingString:NSLocalizedString(@"DOWNLOAD", @"Download")]; 
426         [connectLight setImage:[NSImage imageNamed:@"blink.tiff"]];
427         while (returnedName = [enumerator nextObject]) {
428                 NSLog(returnedName);
429                 [self uploadPath:returnedName toPath:[NSString stringWithString:currentPath]];
430         }
435 - (void) uploadPath:(NSString*) path toPath:(NSString*) toPath {
436         if (! connected)
437                 return;
438         NSFileManager* fm = [NSFileManager defaultManager];
439         NSDictionary *fattrs = [fm fileAttributesAtPath:path traverseLink:NO];
440         if (!fattrs) {
441                 NSLog(@"Path of file to upload is incorrect!");
442                 return; }
443         NSString* type = [fattrs fileType];
444         if ([type isEqualToString:@"NSFileTypeDirectory"]) {
445                 // should look to create folder on Toppy, or add stuff if already there (maybe it does this automatically?), and place in subfolders etc
446                 [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:[path lastPathComponent],@"newName",toPath,@"path",@"newFolder",@"transferType", nil]];
447                 NSArray* subPaths = [fm directoryContentsAtPath:path];
448                 NSEnumerator* e = [subPaths objectEnumerator];
449                 id object;
450                 while (object = [e nextObject]) {
451                         NSString* subPath = [NSString stringWithFormat:@"%@/%@", path, object];
452                         NSString* subToPath = [NSString stringWithFormat:@"%@\\%@", toPath, [path lastPathComponent]];
453                 //      NSLog(@"subdir: %@, %@", subPath, subToPath);
454                         if (![object isEqualToString:@".DS_Store"]) {
455                                 [self uploadPath:subPath toPath:subToPath];
456                         }
457                 }
458                 if (connected) { //may have disconnected during threaded upload (although not actually threaded here!)
459         //              [self updateHDDSize];
460                         [self goToPath:currentPath];
461                 }
462         }
463         else {
464                 NSDictionary* fileAttr = [dh extractAttributes:fattrs];         // turn Dict into a new TypeFile dict
465                 NSMutableArray* array = [NSMutableArray arrayWithArray:[path componentsSeparatedByString:@"/"]]; // cut down name
466                 NSString* fileName = [NSString stringWithString:[array lastObject]];
467                 NSData* typeFile = [dh getDataFromTFFile:fileAttr withName:fileName];
468                 [progressBar setDoubleValue:0];
469                 [currentlyField setStringValue:[NSLocalizedString(@"UPLOADING", @"Uploading") stringByAppendingString:fileName]];
470                 [currentlyField displayIfNeeded];
471                 [tfusbc setProgressBar:progressBar time:progressTime turbo:turboCB];
472                 [tfusbc addTransfer:[NSDictionary dictionaryWithObjectsAndKeys:path,@"filename",[NSNumber numberWithUnsignedLongLong:[fattrs fileSize]],@"fileSize",toPath,@"path",typeFile,@"attributes",@"upload",@"transferType",[NSNumber numberWithUnsignedLongLong:0],@"offset",[NSNumber numberWithInt:0],@"existingTime",nil] atIndex:-1];
473         }
476 -(IBAction)deleteFile:(id)sender
478         if (! connected)
479                 return;
480         if ( [tableView numberOfSelectedRows] == 0 )
481         return;
482         NSString *title = NSLocalizedString(@"WARNING", @"Warning!");
483     NSString *defaultButton = NSLocalizedString(@"DEL", @"Delete");
484     NSString *alternateButton = NSLocalizedString(@"NO_DEL", @"Don't Delete");
485     NSString *otherButton = nil;
486     NSString *message = NSLocalizedString(@"DEL_MESSAGE", @"Are you sure you want to delete the selected file(s)?");
488     NSBeep();
489     NSBeginAlertSheet(title, defaultButton, alternateButton, otherButton, mainWindow, self, @selector(sheetDidEnd:returnCode:contextInfo:), nil, nil, message);
492 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
494     if ( returnCode == NSAlertDefaultReturn ) {
495                 NSLog(@"Deleting file(s) starting...");
496                 NSEnumerator* selected = [tableView selectedRowEnumerator];
497                 id currentSelected;
498                 while (currentSelected = [selected nextObject]) {
499                         id currentSelectedItem = [[dh displayedList] objectAtIndex:[currentSelected intValue]];
500                         [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:currentSelectedItem,@"file",currentPath,@"path",@"delete",@"transferType", nil]];
501                 }
502         //      [self updateHDDSize];
503                 [self goToPath:currentPath];
504                 //should check so don't delete root folders?
505         }
508 - (IBAction)openPrefsSheet:(id)sender
510         [NSApp beginSheet:prefsWindow
511            modalForWindow:mainWindow
512                 modalDelegate:self
513            didEndSelector:@selector(mySheetDidEnd:returnCode:contextInfo:)
514           contextInfo: nil];
515         return;  // leave without doing anything else
518 - (IBAction) mySheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode
519                            contextInfo:(void *)contextInfo {
520         
521         [sheet orderOut:self];
522         if(returnCode == 0)  return;
523         // continue with application  
526 - (IBAction)closePrefsSheet:(id)sender
528         //do changes to prefs here
529         //    if (connected) {
530         [tfusbc setDebug:[debugCB state]]; 
531         //  }
532         NSLog(@"auto: %i", [autoCB state]);
533         [prefs setBool:[autoCB state] forKey:@"auto-connect"];
534 //      [prefs setBool:[epgCB state] forKey:@"epgSync"];
535         [prefs synchronize];
536         [NSApp endSheet:prefsWindow returnCode:1];
539 - (IBAction)openRenameSheet:(id)sender
541         if ( [tableView numberOfSelectedRows] != 1 )
542         return;
543         [renameOld setStringValue:[[[dh displayedList] objectAtIndex:[tableView selectedRow]] objectForKey:@"name"]];
544         [renameNew setStringValue:[renameOld stringValue]];
545 //      [renameWindow setTitleBarHeight:0.0];
546         [NSApp beginSheet: renameWindow
547            modalForWindow: mainWindow
548                 modalDelegate: nil
549            didEndSelector: nil
550                   contextInfo: nil];
551     [NSApp runModalForWindow: renameWindow];
552     // Sheet is up here.
555 - (IBAction)cancelRename:(id)sender{
556         [NSApp endSheet: renameWindow];
557     [renameWindow orderOut: self];
558         [NSApp stopModal];
561 - (IBAction)closeRenameSheet:(id)sender
563         //do changes to rename here
564         if (connected) {
565                 [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:[renameOld stringValue],@"oldName",[renameNew stringValue],@"newName", currentPath,@"path",@"rename",@"transferType",nil]];
566                 [self goToPath:currentPath];
567         }
568                 //then close up
569         [self cancelRename:sender];
573 - (IBAction)openNewFolderSheet:(id)sender
575         [NSApp beginSheet: newFolderWindow
576            modalForWindow: mainWindow
577                 modalDelegate: nil
578            didEndSelector: nil
579                   contextInfo: nil];
580     [NSApp runModalForWindow: newFolderWindow];
581     // Sheet is up here.
582         
585 - (IBAction)cancelNewFolder:(id)sender{
586         [NSApp endSheet: newFolderWindow];
587     [newFolderWindow orderOut: self];
588         [NSApp stopModal];
591 - (IBAction)closeNewFolderSheet:(id)sender
593         //do changes to make new folder here
594         if (connected) {
595                 [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:[newFolderNew stringValue],@"newName",currentPath,@"path",@"newFolder",@"transferType", nil]];
596                 [self goToPath:currentPath];
597         }
598         //then close up
599         [self cancelNewFolder:sender];
602 - (IBAction)pathBarClick:(id)sender {
603         int segCount = [pathBar segmentCount]; //remember count starts at 1, not zero!
604         int selectedSegment = [sender selectedSegment]; 
605         if (selectedSegment == segCount - 1) return; //no need to move anywhere
606         int i = 1; // remember have "path" there too 
607         NSMutableArray* pathArray = [NSMutableArray arrayWithCapacity:selectedSegment];
608         while (i<=selectedSegment) {
609                 [pathArray addObject:[[pathBar cell] labelForSegment:i]];
610                 i++;
611         } 
612         NSString* pathString = [pathArray componentsJoinedByString:@"\\"];
613         if ([pathString hasPrefix:@"\\\\"]) pathString = [pathString substringFromIndex:1];
614         [self goToPath:pathString];
615         [self setCurrentPath:pathString];
616         NSRect r = [pathBar frame];
617         [[pathBar cell] setSegmentCount:selectedSegment+1];
618         [pathBar displayIfNeededInRect:r];      
621 - (id)getTfusbc {
622         return tfusbc;
625 - (USBDeviceContext*) getContext {
626         return context;
629 - (NSNumber*) isConnected {
630         return [NSNumber numberWithBool:connected];
634 - (NSString*) currentPath {
635         return currentPath;
638 - (IBAction) toggleTurbo:(id)sender {
639         if ([tfusbc hasCurrentTransfer]) { //have a current transfer, lets toggle it
640                 [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:@"turbo",@"transferType",[NSNumber numberWithBool:[turboCB state]],@"turboOn",nil]];
641         }
644 - (IBAction) toggleTurboCB:(id)sender {
645         if (! connected)
646                 return;
647         if ([turboCB state]) { // currently on, want off
648                 [turboCB setState:0];
649         } else {
650                 [turboCB setState:1];
651         }
652         if ([tfusbc hasCurrentTransfer]) { //have a current transfer, lets toggle it
653                         [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:@"turbo",@"transferType",[NSNumber numberWithBool:[turboCB state]],@"turboOn",nil]];
654         }
657 - (IBAction) togglePreview:(id)sender {
658                 [previewDrawer toggle:sender];
661 /*- (IBAction) snapshot:(id) sender {
662         NSArray* snapshotData = [self snapshotOfPath:@"\\"];
663         [dh setSnapShot:snapshotData];
664         // show snapshot window
665         [snapshotWindow makeKeyAndOrderFront:sender];
666         [outlineView reloadData];
669 - (NSArray*) snapshotOfPath:(NSString*)path {
670         
671 NSData* hddFileData = [tfusbc getFileList:context forPath:path];
672 NSData* checkForError = [hddFileData subdataWithRange:(NSRange){4,4}];
673 const UInt32 check_bigendian = EndianU32_NtoB(USB_Fail);
674 const UInt32 check2_bigendian = EndianU32_NtoB(USB_DataHddDir);
675 if ([checkForError isEqualToData:[NSData dataWithBytes:&check_bigendian length:4]]) {
676         [statusField setStringValue:@"Connected - error on last command"];
678 if (! [checkForError isEqualToData:[NSData dataWithBytes:&check2_bigendian length:4]]) {
679         hddFileData = [tfusbc getFileList:context forPath:path]; //try again
680         if ([checkForError isEqualToData:[NSData dataWithBytes:&check_bigendian length:4]]) {
681                 [statusField setStringValue:@"Connected - error on last command"];
682         }
684 hddFileData = [hddFileData subdataWithRange:(NSRange) {8, [hddFileData length]-8}]; // cut off header and cmd 
685 int i;
686 NSMutableArray* paths = [[NSMutableArray alloc] init];
687 for (i=0; i*114 < [hddFileData length]-4; i++) { // 4 is there cause swapping sometimes adds a byte of padding  
688         NSData* temp = [hddFileData subdataWithRange:(NSRange) {i*114,114}];
689         NSMutableDictionary* tfFile = [dh newTFFileFromSwappedHexData:temp];
690         [dh convertRawDataToUseful:tfFile];
691         if (!([[tfFile objectForKey:@"name"] isEqualToString:@".."])) {
692                 if ([[tfFile objectForKey:@"type"] intValue] == 1) { //folder
693                         NSMutableString* temp = [NSMutableString stringWithString:path];
694                         if (![temp isEqualToString:@"\\"])
695                                 [temp appendString:@"\\"];
696                         [temp appendString:[tfFile objectForKey:@"name"]];
697                         [paths addObject:tfFile];
698                         [paths addObject:[self snapshotOfPath:temp]];
699                 } else {
700                         [paths addObject:tfFile];
701                 }
702         }
703         [tfFile release];
705 return paths;
710 /*- (IBAction) epg:(id) sender {
711         XMLToEPG *xmlConv = [[XMLToEPG alloc] init];
712         NSOpenPanel *nsop = [[NSOpenPanel openPanel]retain];
713     NSArray *fileType = [NSArray arrayWithObject:@"xml"];
714     [nsop setAllowsMultipleSelection:NO];
715     [nsop setCanChooseFiles:YES];
716     [nsop setCanChooseDirectories:NO];
717     [nsop runModalForTypes:fileType];
718     NSMutableArray* importedXML = [xmlConv importXML:[nsop URL]];
719         [xmlConv fixData:importedXML];
720         [xmlConv exportFixedXML:importedXML toFile:@"/Volumes/Tyr/nathan/Desktop/TV/Guides/test.tgd"];
725 /*      if ([prefs boolForKey:@"epgSync"]) {
726                         [epgCB setState:1];
727                         XMLToEPG *xmlConv = [[XMLToEPG alloc] init];
728                         NSString* path = @"/Volumes/Tyr/nathan/Desktop/TV/Guides/tv.xml";
729                         NSString* tempFile = @"/Volumes/Tyr/nathan/Desktop/TV/Guides/test.epg";
730                         NSMutableArray* importedXML = [xmlConv importXML:[NSURL fileURLWithPath:path]];
731                         [xmlConv fixData:importedXML];
732                         [xmlConv exportFixedXML:importedXML toFile:tempFile];
733                         if (! connected)
734                                 return;
735                         NSFileManager* fm = [NSFileManager defaultManager];
736                         NSDictionary *fattrs = [fm fileAttributesAtPath:tempFile traverseLink:NO];
737                         if (!fattrs) {
738                                 NSLog(@"Path of file to upload is incorrect!");
739                                 return;
740                         }
741                         NSDictionary* fileAttr = [dh extractAttributes:fattrs];
742                         NSMutableArray* array = [NSMutableArray arrayWithArray:[tempFile componentsSeparatedByString:@"/"]];
743                         NSString* fileName = [NSString stringWithString:[array lastObject]];
744                         NSData* typeFile = [dh getDataFromTFFile:fileAttr withName:fileName];
745                         [tfusbc uploadFile:tempFile ofSize:[fattrs fileSize] fromPath:@"\\Program Files\\TimerKey\\" withAttributes:typeFile toDevice:context];
746                         [self goToPath:currentPath];
747                         [self resetTurbo];
748                 } */
752 /*- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
754         if ([prefs objectForKey:@"NoRollover"] != nil) return;
755         if ([aTableView mouseOverRow] == rowIndex && ([aTableView selectedRow] != rowIndex))
756                         if ([aTableView lockFocusIfCanDraw]) {
757                                 NSRect rowRect = [aTableView rectOfRow:rowIndex];
758                                 NSRect columnRect = [aTableView rectOfColumn:[[aTableView tableColumns] indexOfObject:aTableColumn]];
760                                         if (!highlightImage) {
761                                                 highlightImage = [[NSImage alloc] initWithData:[highlightImageData propertyList]];
762                                                         [highlightImage setDataRetained:YES]; //?
763                                                         [highlightImage setCacheMode:NSImageCacheAlways]; //?
764                                         }
766                                 [highlightImage drawInRect:NSIntersectionRect(rowRect, columnRect) fromRect:NSMakeRect(0,0,1,[highlightImage size].height) operation:NSCompositeSourceOver fraction:0.3];
767                                 [aTableView unlockFocus];
768                         }
772 - (void)dealloc
774   if (highlightImage) [highlightImage release];
775 [super dealloc];
778 - (IBAction)pauseCurrentTransfer:(id)sender {
779         if (!paused) {
780         [pauseButton setImage:[NSImage imageNamed:@"DownloadResume.tif"]];
781         [pauseButton setAlternateImage:[NSImage imageNamed:@"DownloadResumePressed.tif"]];
782         //add priority "halt" to queue naming file
783         id current = [tfusbc currentTransferInfo];
784         [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:@"pause",@"transferType",[current objectForKey:@"filename"],@"filename",nil]];
785         paused = YES;
786         [currentlyField setStringValue:[NSLocalizedString(@"PAUSED", @"Paused: ") stringByAppendingString:[[current objectForKey:@"filename"]objectForKey:@"name"]]];
787         [connectLight setImage:[NSImage imageNamed:@"green.tiff"]];
788         [currentlyField displayIfNeeded];
789         } else {
790         //change image to pause
791         //add priority "resume" to queue naming file
792         [pauseButton setImage:[NSImage imageNamed:@"DownloadStop.tif"]];
793         [pauseButton setAlternateImage:[NSImage imageNamed:@"DownloadStopPressed.tif"]];
794         id current = [tfusbc firstPausedTransferInfo];//temp as for now only have 1 paused
795         [tfusbc addPriorityTransfer:[NSDictionary dictionaryWithObjectsAndKeys:@"resume",@"transferType",[current objectForKey:@"filename"],@"filename",nil]];
796         paused = NO;
797         [currentlyField setStringValue:[NSLocalizedString(@"DOWNLOADING", @"Downloading: ") stringByAppendingString:[[current objectForKey:@"filename"]objectForKey:@"name"]]];
798         [connectLight setImage:[NSImage imageNamed:@"blink.tiff"]];
799         [currentlyField displayIfNeeded];
800         }
803 - (id) selectedColumn {
804         return selectedColumn;
806 - (id) currentlyField {
807         return currentlyField;
809 - (id) connectLight {
810         return connectLight;
813 @end
815 @implementation UIElements (PrivateMethods)
817 // To ensure proper maintenance of reference counts, all updates of currentPath
818 // go via this method.
819 - (void) setCurrentPath:(NSString*)path {
820         // Retain first, in case it's the same or a related object.
821         [path retain];
822         [currentPath release];
823         currentPath = path;
826 @end