1/* SearchResults.m 2 * 3 * Copyright (C) 2004-2014 Free Software Foundation, Inc. 4 * 5 * Author: Enrico Sersale <enrico@imago.ro> 6 * Date: March 2004 7 * 8 * This file is part of the GNUstep GWorkspace application 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. 23 */ 24 25#include <math.h> 26 27#import <Foundation/Foundation.h> 28#import <AppKit/AppKit.h> 29 30#import "SearchResults.h" 31#import "ResultsTableView.h" 32#import "FSNTextCell.h" 33#import "Finder.h" 34#import "FinderModulesProtocol.h" 35#import "FSNode.h" 36#import "FSNodeRep.h" 37#import "FSNPathComponentsViewer.h" 38#import "GWFunctions.h" 39#import "Dialogs/Dialogs.h" 40 41#define CELLS_HEIGHT (28.0) 42 43#define LSF_INFO(x) [x stringByAppendingPathComponent: @"lsf.info"] 44#define LSF_FOUND(x) [x stringByAppendingPathComponent: @"lsf.found"] 45 46static NSString *nibName = @"SearchResults"; 47static NSString *lsfname = @"LiveSearch.lsf"; 48 49@implementation SearchResults 50 51- (void)dealloc 52{ 53 [nc removeObserver: self]; 54 55 if (toolConn != nil) { 56 if (searchtool != nil) { 57 [searchtool terminate]; 58 } 59 DESTROY (searchtool); 60 DESTROY (toolConn); 61 } 62 63 RELEASE (win); 64 RELEASE (searchCriteria); 65 RELEASE (foundObjects); 66 RELEASE (searchPaths); 67 RELEASE (elementsStr); 68 DESTROY (conn); 69 70 [super dealloc]; 71} 72 73- (id)init 74{ 75 self = [super init]; 76 77 if (self) { 78 NSUserDefaults *defaults; 79 id entry; 80 NSRect r; 81 82 if ([NSBundle loadNibNamed: nibName owner: self] == NO) { 83 NSLog(@"failed to load %@!", nibName); 84 DESTROY (self); 85 return self; 86 } 87 88 [win setFrameUsingName: @"search_results"]; 89 [win setAcceptsMouseMovedEvents: YES]; 90 [win setDelegate: self]; 91 92 progView = [[ProgressView alloc] initWithFrame: NSMakeRect(0, 0, 16, 16) 93 refreshInterval: 0.1]; 94 [progBox setContentView: progView]; 95 RELEASE (progView); 96 97 r = [[dragIconBox contentView] bounds]; 98 documentIcon = [[DocumentIcon alloc] initWithFrame: r searchResult: self]; 99 [dragIconBox setContentView: documentIcon]; 100 RELEASE (documentIcon); 101 102 [elementsLabel setStringValue: @""]; 103 ASSIGN (elementsStr, NSLocalizedString(@"elements", @"")); 104 105 [stopButt setImage: [NSImage imageNamed: @"stop_small"]]; 106 [stopButt setEnabled: NO]; 107 [restartButt setImage: [NSImage imageNamed: @"magnify_small"]]; 108 [restartButt setEnabled: NO]; 109 110 [resultsScroll setBorderType: NSBezelBorder]; 111 [resultsScroll setHasHorizontalScroller: YES]; 112 [resultsScroll setHasVerticalScroller: YES]; 113 114 r = [[resultsScroll contentView] bounds]; 115 116 resultsView = [[ResultsTableView alloc] initWithFrame: r]; 117 [resultsView setDrawsGrid: NO]; 118 [resultsView setAllowsColumnSelection: NO]; 119 [resultsView setAllowsColumnReordering: YES]; 120 [resultsView setAllowsColumnResizing: YES]; 121 [resultsView setAllowsEmptySelection: YES]; 122 [resultsView setAllowsMultipleSelection: YES]; 123 [resultsView setRowHeight: CELLS_HEIGHT]; 124 [resultsView setIntercellSpacing: NSZeroSize]; 125 [resultsView sizeLastColumnToFit]; 126 127 nameColumn = [[NSTableColumn alloc] initWithIdentifier: @"name"]; 128 [nameColumn setDataCell: AUTORELEASE ([[FSNTextCell alloc] init])]; 129 [nameColumn setEditable: NO]; 130 [nameColumn setResizable: YES]; 131 [[nameColumn headerCell] setStringValue: NSLocalizedString(@"Name", @"")]; 132 [[nameColumn headerCell] setAlignment: NSLeftTextAlignment]; 133 [nameColumn setMinWidth: 80]; 134 [nameColumn setWidth: 140]; 135 [resultsView addTableColumn: nameColumn]; 136 RELEASE (nameColumn); 137 138 parentColumn = [[NSTableColumn alloc] initWithIdentifier: @"parent"]; 139 [parentColumn setDataCell: AUTORELEASE ([[FSNTextCell alloc] init])]; 140 [parentColumn setEditable: NO]; 141 [parentColumn setResizable: YES]; 142 [[parentColumn headerCell] setStringValue: NSLocalizedString(@"Parent", @"")]; 143 [[parentColumn headerCell] setAlignment: NSLeftTextAlignment]; 144 [parentColumn setMinWidth: 80]; 145 [parentColumn setWidth: 90]; 146 [resultsView addTableColumn: parentColumn]; 147 RELEASE (parentColumn); 148 149 dateColumn = [[NSTableColumn alloc] initWithIdentifier: @"date"]; 150 [dateColumn setDataCell: AUTORELEASE ([[FSNTextCell alloc] init])]; 151 [dateColumn setEditable: NO]; 152 [dateColumn setResizable: YES]; 153 [[dateColumn headerCell] setStringValue: NSLocalizedString(@"Date Modified", @"")]; 154 [[dateColumn headerCell] setAlignment: NSLeftTextAlignment]; 155 [dateColumn setMinWidth: 80]; 156 [dateColumn setWidth: 90]; 157 [resultsView addTableColumn: dateColumn]; 158 RELEASE (dateColumn); 159 160 sizeColumn = [[NSTableColumn alloc] initWithIdentifier: @"size"]; 161 [sizeColumn setDataCell: AUTORELEASE ([[FSNTextCell alloc] init])]; 162 [sizeColumn setEditable: NO]; 163 [sizeColumn setResizable: YES]; 164 [[sizeColumn headerCell] setStringValue: NSLocalizedString(@"Size", @"")]; 165 [[sizeColumn headerCell] setAlignment: NSLeftTextAlignment]; 166 [sizeColumn setMinWidth: 50]; 167 [sizeColumn setWidth: 50]; 168 [resultsView addTableColumn: sizeColumn]; 169 RELEASE (sizeColumn); 170 171 kindColumn = [[NSTableColumn alloc] initWithIdentifier: @"kind"]; 172 [kindColumn setDataCell: AUTORELEASE ([[FSNTextCell alloc] init])]; 173 [kindColumn setEditable: NO]; 174 [kindColumn setResizable: YES]; 175 [[kindColumn headerCell] setStringValue: NSLocalizedString(@"Type", @"")]; 176 [[kindColumn headerCell] setAlignment: NSLeftTextAlignment]; 177 [kindColumn setMinWidth: 80]; 178 [kindColumn setWidth: 80]; 179 [resultsView addTableColumn: kindColumn]; 180 RELEASE (kindColumn); 181 182 [resultsScroll setDocumentView: resultsView]; 183 RELEASE (resultsView); 184 185 [self setColumnsSizes]; 186 187 [resultsView setDataSource: self]; 188 [resultsView setDelegate: self]; 189 [resultsView setTarget: self]; 190 [resultsView setDoubleAction: @selector(doubleClickOnResultsView:)]; 191 192 foundObjects = [NSMutableArray new]; 193 194 defaults = [NSUserDefaults standardUserDefaults]; 195 196 entry = [defaults stringForKey: @"sorting_order"]; 197 if (entry) { 198 [self setCurrentOrder: [entry intValue]]; 199 } else { 200 [self setCurrentOrder: FSNInfoNameType]; 201 } 202 203 r = [[pathBox contentView] bounds]; 204 pathViewer = [[FSNPathComponentsViewer alloc] initWithFrame: r]; 205 [pathBox setContentView: pathViewer]; 206 RELEASE (pathViewer); 207 208 finder = [Finder finder]; 209 fm = [NSFileManager defaultManager]; 210 ws = [NSWorkspace sharedWorkspace]; 211 nc = [NSNotificationCenter defaultCenter]; 212 213 [nc addObserver: self 214 selector: @selector(fileSystemDidChange:) 215 name: @"GWFileSystemDidChangeNotification" 216 object: nil]; 217 } 218 219 return self; 220} 221 222- (void)activateForSelection:(NSArray *)selection 223 withSearchCriteria:(NSDictionary *)criteria 224 recursive:(BOOL)rec 225{ 226 NSString *cname; 227 NSString *cmd; 228 229 [win makeKeyAndOrderFront: nil]; 230 visibleRows = (int)([resultsScroll bounds].size.height / CELLS_HEIGHT + 1); 231 ASSIGN (searchPaths, selection); 232 ASSIGN (searchCriteria, criteria); 233 recursive = rec; 234 235 cname = [NSString stringWithFormat: @"search_%lu", [self memAddress]]; 236 237 if (conn == nil) { 238 conn = [[NSConnection alloc] initWithReceivePort: (NSPort *)[NSPort port] 239 sendPort: nil]; 240 [conn setRootObject: self]; 241 [conn registerName: cname]; 242 [conn setDelegate: self]; 243 244 [nc addObserver: self 245 selector: @selector(connectionDidDie:) 246 name: NSConnectionDidDieNotification 247 object: conn]; 248 } 249 250 if (toolConn != nil) { 251 if (searchtool != nil) { 252 [searchtool terminate]; 253 } 254 255 DESTROY (searchtool); 256 257 [nc removeObserver: self 258 name: NSConnectionDidDieNotification 259 object: toolConn]; 260 261 [toolConn invalidate]; 262 DESTROY (toolConn); 263 } 264 265 searchtool = nil; 266 searching = YES; 267 268 [NSTimer scheduledTimerWithTimeInterval: 5.0 269 target: self 270 selector: @selector(checkSearchTool:) 271 userInfo: nil 272 repeats: NO]; 273 274 cmd = [NSTask launchPathForTool: @"searchtool"]; 275 276 [NSTask launchedTaskWithLaunchPath: cmd 277 arguments: [NSArray arrayWithObject: cname]]; 278} 279 280- (BOOL)connection:(NSConnection *)ancestor 281 shouldMakeNewConnection:(NSConnection *)newConn 282{ 283 if (ancestor == conn) { 284 ASSIGN (toolConn, newConn); 285 [toolConn setDelegate: self]; 286 287 [nc addObserver: self 288 selector: @selector(connectionDidDie:) 289 name: NSConnectionDidDieNotification 290 object: toolConn]; 291 } 292 293 return YES; 294} 295 296- (void)connectionDidDie:(NSNotification *)notification 297{ 298 id diedconn = [notification object]; 299 300 [nc removeObserver: self 301 name: NSConnectionDidDieNotification 302 object: diedconn]; 303 304 if ((diedconn == conn) || (toolConn && (diedconn == toolConn))) { 305 DESTROY (searchtool); 306 DESTROY (toolConn); 307 308 if (diedconn == conn) { 309 DESTROY (conn); 310 } 311 312 if (searching) { 313 [self endOfSearch]; 314 NSRunAlertPanel(nil, 315 NSLocalizedString(@"the search tool connection died!", @""), 316 NSLocalizedString(@"Continue", @""), 317 nil, 318 nil); 319 } 320 } 321} 322 323- (void)checkSearchTool:(id)sender 324{ 325 if (searching && (searchtool == nil)) { 326 [self endOfSearch]; 327 NSRunAlertPanel(nil, 328 NSLocalizedString(@"unable to launch the search task.", @""), 329 NSLocalizedString(@"Continue", @""), 330 nil, 331 nil); 332 } 333} 334 335- (oneway void)registerSearchTool:(id)tool 336{ 337 NSDictionary *srcdict = [NSDictionary dictionaryWithObjectsAndKeys: 338 searchPaths, @"paths", searchCriteria, @"criteria", 339 [NSNumber numberWithBool: recursive], @"recursion", nil]; 340 NSData *info = [NSArchiver archivedDataWithRootObject: srcdict]; 341 342 [stopButt setEnabled: YES]; 343 [restartButt setEnabled: NO]; 344 [progView start]; 345 346 [tool setProtocolForProxy: @protocol(SearchToolProtocol)]; 347 searchtool = (id <SearchToolProtocol>)[tool retain]; 348 [searchtool searchWithInfo: info]; 349} 350 351- (void)nextResult:(NSString *)path 352{ 353 CREATE_AUTORELEASE_POOL(pool); 354 FSNode *node = [FSNode nodeWithPath: path]; 355 356 [foundObjects addObject: node]; 357 358 if ([foundObjects count] <= visibleRows) { 359 [resultsView noteNumberOfRowsChanged]; 360 } 361 362 [elementsLabel setStringValue: [NSString stringWithFormat: @"%lu %@", 363 (unsigned long)[foundObjects count], elementsStr]]; 364 RELEASE (pool); 365} 366 367- (void)endOfSearch 368{ 369 [stopButt setEnabled: NO]; 370 [restartButt setEnabled: YES]; 371 [progView stop]; 372 searching = NO; 373 374 if (searchtool) { 375 [nc removeObserver: self 376 name: NSConnectionDidDieNotification 377 object: toolConn]; 378 [searchtool terminate]; 379 DESTROY (searchtool); 380 DESTROY (toolConn); 381 } 382 383 [self updateShownData]; 384} 385 386- (BOOL)searching 387{ 388 return searching; 389} 390 391- (IBAction)stopSearch:(id)sender 392{ 393 if (searchtool) { 394 [searchtool stop]; 395 } 396} 397 398- (IBAction)restartSearch:(id)sender 399{ 400 if (searchtool == nil) { 401 [pathViewer showComponentsOfSelection: nil]; 402 [foundObjects removeAllObjects]; 403 [resultsView reloadData]; 404 [self activateForSelection: searchPaths 405 withSearchCriteria: searchCriteria 406 recursive: recursive]; 407 } 408} 409 410- (void)updateShownData 411{ 412 SEL sortingSel; 413 NSTableColumn *column; 414 415 switch(currentOrder) { 416 case FSNInfoNameType: 417 sortingSel = @selector(compareAccordingToName:); 418 column = nameColumn; 419 break; 420 case FSNInfoParentType: 421 sortingSel = @selector(compareAccordingToParent:); 422 column = parentColumn; 423 break; 424 case FSNInfoKindType: 425 sortingSel = @selector(compareAccordingToKind:); 426 column = kindColumn; 427 break; 428 case FSNInfoDateType: 429 sortingSel = @selector(compareAccordingToDate:); 430 column = dateColumn; 431 break; 432 case FSNInfoSizeType: 433 sortingSel = @selector(compareAccordingToSize:); 434 column = sizeColumn; 435 break; 436 default: 437 sortingSel = @selector(compareAccordingToName:); 438 column = nameColumn; 439 break; 440 } 441 442 [foundObjects sortUsingSelector: sortingSel]; 443 [resultsView setHighlightedTableColumn: column]; 444 [resultsView reloadData]; 445} 446 447- (void)setCurrentOrder:(FSNInfoType)order 448{ 449 currentOrder = order; 450} 451 452- (NSArray *)selectedObjects 453{ 454 NSMutableArray *selected = [NSMutableArray array]; 455 NSEnumerator *enumerator = [resultsView selectedRowEnumerator]; 456 NSNumber *row; 457 458 while ((row = [enumerator nextObject])) { 459 FSNode *node = [foundObjects objectAtIndex: [row intValue]]; 460 if ([node isValid]) { 461 [selected addObject: node]; 462 } else { 463 [foundObjects removeObject: node]; 464 [resultsView noteNumberOfRowsChanged]; 465 } 466 } 467 468 return selected; 469} 470 471- (void)doubleClickOnResultsView:(id)sender 472{ 473 [finder openFoundSelection: [self selectedObjects]]; 474} 475 476- (void)selectObjects:(NSArray *)objects 477{ 478 int i; 479 480 for (i = 0; i < [objects count]; i++) { 481 FSNode *node = [objects objectAtIndex: i]; 482 int index = [foundObjects indexOfObject: node]; 483 484 [resultsView selectRow: index byExtendingSelection: (i != 0)]; 485 } 486} 487 488- (void)fileSystemDidChange:(NSNotification *)notif 489{ 490 NSDictionary *info = [notif object]; 491 NSString *operation = [info objectForKey: @"operation"]; 492 NSString *source = [info objectForKey: @"source"]; 493 NSString *destination = [info objectForKey: @"destination"]; 494 NSArray *files = [info objectForKey: @"files"]; 495 NSMutableArray *deletedObjects = [NSMutableArray array]; 496 NSUInteger i, j; 497 498 if ([operation isEqual: @"GWorkspaceRenameOperation"]) { 499 files = [NSArray arrayWithObject: [destination lastPathComponent]]; 500 } 501 502 if ([operation isEqual: NSWorkspaceRecycleOperation]) { 503 files = [info objectForKey: @"origfiles"]; 504 } 505 506 if ([operation isEqual: NSWorkspaceMoveOperation] 507 || [operation isEqual: NSWorkspaceDestroyOperation] 508 || [operation isEqual: NSWorkspaceRecycleOperation] 509 || [operation isEqual: @"GWorkspaceRecycleOutOperation"] 510 || [operation isEqual: @"GWorkspaceEmptyRecyclerOperation"]) { 511 for (i = 0; i < [files count]; i++) { 512 NSString *fname = [files objectAtIndex: i]; 513 NSString *fullPath = [source stringByAppendingPathComponent: fname]; 514 515 for (j = 0; j < [foundObjects count]; j++) { 516 FSNode *node = [foundObjects objectAtIndex: j]; 517 NSString *path = [node path]; 518 519 if ([fullPath isEqual: path]) { 520 [deletedObjects addObject: node]; 521 } 522 } 523 } 524 525 } else if ([operation isEqual: @"GWorkspaceRenameOperation"]) { 526 for (i = 0; i < [foundObjects count]; i++) { 527 FSNode *node = [foundObjects objectAtIndex: i]; 528 NSString *path = [node path]; 529 530 if ([source isEqual: path]) { 531 [deletedObjects addObject: node]; 532 } 533 } 534 } 535 536 if ([deletedObjects count]) { 537 for (i = 0; i < [deletedObjects count]; i++) { 538 [foundObjects removeObject: [deletedObjects objectAtIndex: i]]; 539 } 540 541 [resultsView deselectAll: self]; 542 [self updateShownData]; 543 } 544} 545 546- (void)setColumnsSizes 547{ 548 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 549 NSDictionary *columnsDict = [defaults objectForKey: @"columns_sizes"]; 550 551 if (columnsDict) { 552 NSArray *columns = [resultsView tableColumns]; 553 NSMutableArray *sortedCols = [NSMutableArray array]; 554 NSArray *keys = [columnsDict keysSortedByValueUsingSelector: @selector(compareColInfo:)]; 555 int i; 556 557 for (i = 0; i < [keys count]; i++) { 558 NSString *identifier = [keys objectAtIndex: i]; 559 int col = [resultsView columnWithIdentifier: identifier]; 560 NSTableColumn *column = [columns objectAtIndex: col]; 561 NSDictionary *cdict = [columnsDict objectForKey: identifier]; 562 float width = [[cdict objectForKey: @"width"] floatValue]; 563 564 [column setWidth: width]; 565 [sortedCols insertObject: column atIndex: [sortedCols count]]; 566 } 567 568 for (i = 0; i < [sortedCols count]; i++) { 569 [resultsView removeTableColumn: [sortedCols objectAtIndex: i]]; 570 } 571 572 for (i = 0; i < [sortedCols count]; i++) { 573 [resultsView addTableColumn: [sortedCols objectAtIndex: i]]; 574 } 575 } 576} 577 578- (void)saveColumnsSizes 579{ 580 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 581 NSMutableDictionary *columnsDict = [NSMutableDictionary dictionary]; 582 NSArray *columns = [resultsView tableColumns]; 583 int i; 584 585 for (i = 0; i < [columns count]; i++) { 586 NSTableColumn *column = [columns objectAtIndex: i]; 587 NSString *identifier = [column identifier]; 588 NSNumber *cwidth = [NSNumber numberWithFloat: [column width]]; 589 NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 590 591 [dict setObject: [NSNumber numberWithInt: i] forKey: @"position"]; 592 [dict setObject: cwidth forKey: @"width"]; 593 594 [columnsDict setObject: dict forKey: identifier]; 595 } 596 597 [defaults setObject: columnsDict forKey: @"columns_sizes"]; 598 [defaults synchronize]; 599} 600 601- (NSWindow *)win 602{ 603 return win; 604} 605 606- (unsigned long)memAddress 607{ 608 return (unsigned long)self; 609} 610 611- (void)createLiveSearchFolderAtPath:(NSString *)path 612{ 613 SympleDialog *dialog; 614 NSString *folderName; 615 NSArray *contents; 616 int result; 617 618 dialog = [[SympleDialog alloc] initWithTitle: NSLocalizedString(@"New Live Search", @"") 619 editText: lsfname 620 switchTitle: nil]; 621 AUTORELEASE (dialog); 622 [dialog center]; 623 [dialog makeKeyWindow]; 624 [dialog orderFrontRegardless]; 625 626 result = [dialog runModal]; 627 if (result != NSAlertDefaultReturn) { 628 return; 629 } 630 631 folderName = [dialog getEditFieldText]; 632 633 if ([folderName length] == 0) { 634 NSString *msg = NSLocalizedString(@"No name supplied!", @""); 635 NSString *buttstr = NSLocalizedString(@"Continue", @""); 636 NSRunAlertPanel(nil, msg, buttstr, nil, nil); 637 return; 638 } 639 640 contents = [fm directoryContentsAtPath: path]; 641 642 if ([contents containsObject: folderName] == NO) { 643 NSNotificationCenter *dnc = [NSDistributedNotificationCenter defaultCenter]; 644 NSMutableDictionary *notifDict = [NSMutableDictionary dictionary]; 645 NSString *lsfpath = [path stringByAppendingPathComponent: folderName]; 646 BOOL lsfdone = YES; 647 648 [notifDict setObject: @"GWorkspaceCreateDirOperation" 649 forKey: @"operation"]; 650 [notifDict setObject: path forKey: @"source"]; 651 [notifDict setObject: path forKey: @"destination"]; 652 [notifDict setObject: [NSArray arrayWithObject: folderName] 653 forKey: @"files"]; 654 655 [dnc postNotificationName: @"GWFileSystemWillChangeNotification" 656 object: nil 657 userInfo: notifDict]; 658 659 if ([fm createDirectoryAtPath: lsfpath attributes: nil]) { 660 NSMutableArray *foundPaths = [NSMutableArray array]; 661 NSMutableDictionary *lsfdict = [NSMutableDictionary dictionary]; 662 int i; 663 664 for (i = 0; i < [foundObjects count]; i++) { 665 [foundPaths addObject: [[foundObjects objectAtIndex: i] path]]; 666 } 667 668 [lsfdict setObject: searchPaths forKey: @"searchpaths"]; 669 [lsfdict setObject: searchCriteria forKey: @"criteria"]; 670 [lsfdict setObject: [NSNumber numberWithBool: recursive] 671 forKey: @"recursion"]; 672 [lsfdict setObject: [[NSDate date] description] forKey: @"lastupdate"]; 673 674 lsfdone = [lsfdict writeToFile: LSF_INFO(lsfpath) atomically: YES]; 675 lsfdone = [foundPaths writeToFile: LSF_FOUND(lsfpath) atomically: YES]; 676 } else { 677 lsfdone = NO; 678 } 679 680 if (lsfdone) { 681 [finder addLiveSearchFolderWithPath: lsfpath createIndex: YES]; 682 } else { 683 NSString *msg = NSLocalizedString(@"can't create the Live Search folder", @""); 684 NSRunAlertPanel(NULL, msg, NSLocalizedString(@"Ok", @""), NULL, NULL); 685 } 686 687 [dnc postNotificationName: @"GWFileSystemDidChangeNotification" 688 object: nil 689 userInfo: notifDict]; 690 } else { 691 NSString *msg = [NSString stringWithFormat: @"a file named \"%@\" already exists.\nPlease rename it.", folderName]; 692 NSRunAlertPanel(NULL, msg, NSLocalizedString(@"Ok", @""), NULL, NULL); 693 } 694} 695 696- (BOOL)windowShouldClose:(id)sender 697{ 698 return !searching; 699} 700 701- (void)windowDidMove:(NSNotification *)aNotification 702{ 703 [win saveFrameUsingName: @"search_results"]; 704} 705 706- (void)windowDidBecomeKey:(NSNotification *)aNotification 707{ 708 NSArray *selected = [self selectedObjects]; 709 710 if ([selected count]) { 711 [finder foundSelectionChanged: selected]; 712 } 713} 714 715- (void)windowWillClose:(NSNotification *)aNotification 716{ 717 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 718 719 [defaults setObject: [NSNumber numberWithInt: currentOrder] 720 forKey: @"sorting_order"]; 721 [defaults synchronize]; 722 723 [self saveColumnsSizes]; 724 725 [win saveFrameUsingName: @"search_results"]; 726 [finder resultsWindowWillClose: self]; 727} 728 729 730// 731// NSTableDataSource protocol 732// 733- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView 734{ 735 return [foundObjects count]; 736} 737 738- (id)tableView:(NSTableView *)aTableView 739 objectValueForTableColumn:(NSTableColumn *)aTableColumn 740 row:(NSInteger)rowIndex 741{ 742 FSNode *node = [foundObjects objectAtIndex: rowIndex]; 743 744 if (aTableColumn == nameColumn) { 745 return [node name]; 746 } else if (aTableColumn == parentColumn) { 747 return [[node parentPath] lastPathComponent]; 748 } else if (aTableColumn == dateColumn) { 749 return [node modDateDescription]; 750 } else if (aTableColumn == sizeColumn) { 751 return [node sizeDescription]; 752 } else if (aTableColumn == kindColumn) { 753 return [node typeDescription]; 754 } 755 756 return [NSString string]; 757} 758 759- (BOOL)tableView:(NSTableView *)aTableView 760 writeRows:(NSArray *)rows 761 toPasteboard:(NSPasteboard *)pboard 762{ 763 NSMutableArray *paths = [NSMutableArray array]; 764 NSMutableArray *parentPaths = [NSMutableArray array]; 765 int i; 766 767 for (i = 0; i < [rows count]; i++) { 768 int index = [[rows objectAtIndex: i] intValue]; 769 FSNode *node = [foundObjects objectAtIndex: index]; 770 NSString *parentPath = [node parentPath]; 771 772 if (([parentPaths containsObject: parentPath] == NO) && (i != 0)) { 773 NSString *msg = NSLocalizedString(@"You can't move objects with multiple parent paths!", @""); 774 NSRunAlertPanel(nil, msg, NSLocalizedString(@"Continue", @""), nil, nil); 775 return NO; 776 } 777 778 if ([node isValid]) { 779 [paths addObject: [node path]]; 780 [parentPaths addObject: parentPath]; 781 } 782 } 783 784 [pboard declareTypes: [NSArray arrayWithObject: NSFilenamesPboardType] 785 owner: nil]; 786 [pboard setPropertyList: paths forType: NSFilenamesPboardType]; 787 788 return YES; 789} 790 791 792// 793// NSTableView delegate methods 794// 795- (void)tableViewSelectionDidChange:(NSNotification *)aNotification 796{ 797 NSArray *selected = [self selectedObjects]; 798 799 [pathViewer showComponentsOfSelection: selected]; 800 801 if ([selected count]) { 802 [finder foundSelectionChanged: selected]; 803 } 804} 805 806- (void)tableView:(NSTableView *)aTableView 807 willDisplayCell:(id)aCell 808 forTableColumn:(NSTableColumn *)aTableColumn 809 row:(NSInteger)rowIndex 810{ 811 if (aTableColumn == nameColumn) { 812 FSNTextCell *cell = (FSNTextCell *)[nameColumn dataCell]; 813 FSNode *node = [foundObjects objectAtIndex: rowIndex]; 814 815 [cell setIcon: [[FSNodeRep sharedInstance] iconOfSize: 24 forNode: node]]; 816 817 } else if (aTableColumn == dateColumn) { 818 [(FSNTextCell *)[dateColumn dataCell] setDateCell: YES]; 819 } 820} 821 822- (void)tableView:(NSTableView *)tableView 823 mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn 824{ 825 NSString *newOrderStr = [tableColumn identifier]; 826 FSNInfoType newOrder = FSNInfoNameType; 827 828 if ([newOrderStr isEqual: @"name"]) { 829 newOrder = FSNInfoNameType; 830 } else if ([newOrderStr isEqual: @"parent"]) { 831 newOrder = FSNInfoParentType; 832 } else if ([newOrderStr isEqual: @"kind"]) { 833 newOrder = FSNInfoKindType; 834 } else if ([newOrderStr isEqual: @"date"]) { 835 newOrder = FSNInfoDateType; 836 } else if ([newOrderStr isEqual: @"size"]) { 837 newOrder = FSNInfoSizeType; 838 } 839 840 if (newOrder != currentOrder) { 841 currentOrder = newOrder; 842 843 [self updateShownData]; 844 } 845 846 [tableView setHighlightedTableColumn: tableColumn]; 847} 848 849// ResultsTableView 850- (NSImage *)tableView:(NSTableView *)tableView 851 dragImageForRows:(NSArray *)dragRows 852{ 853 if ([dragRows count] > 1) { 854 return [[FSNodeRep sharedInstance] multipleSelectionIconOfSize: 24]; 855 } else { 856 int index = [[dragRows objectAtIndex: 0] intValue]; 857 FSNode *node = [foundObjects objectAtIndex: index]; 858 859 return [[FSNodeRep sharedInstance] iconOfSize: 24 forNode: node]; 860 } 861 862 return nil; 863} 864 865@end 866 867 868@implementation ProgressView 869 870#define IMAGES 8 871 872- (void)dealloc 873{ 874 RELEASE (images); 875 [super dealloc]; 876} 877 878- (id)initWithFrame:(NSRect)frameRect 879 refreshInterval:(NSTimeInterval)refresh 880{ 881 self = [super initWithFrame: frameRect]; 882 883 if (self) { 884 unsigned i; 885 886 images = [NSMutableArray new]; 887 888 for (i = 0; i < IMAGES; i++) { 889 NSString *imname = [NSString stringWithFormat: @"anim-logo-%d.tiff", i]; 890 [images addObject: [NSImage imageNamed: imname]]; 891 } 892 893 rfsh = refresh; 894 animating = NO; 895 } 896 897 return self; 898} 899 900- (void)start 901{ 902 index = 0; 903 animating = YES; 904 progTimer = [NSTimer scheduledTimerWithTimeInterval: rfsh 905 target: self selector: @selector(animate:) 906 userInfo: nil repeats: YES]; 907} 908 909- (void)stop 910{ 911 animating = NO; 912 if (progTimer && [progTimer isValid]) { 913 [progTimer invalidate]; 914 } 915 [self setNeedsDisplay: YES]; 916} 917 918- (void)animate:(id)sender 919{ 920 [self setNeedsDisplay: YES]; 921 index++; 922 if (index == [images count]) { 923 index = 0; 924 } 925} 926 927- (void)drawRect:(NSRect)rect 928{ 929 [super drawRect: rect]; 930 931 if (animating) { 932 [[images objectAtIndex: index] compositeToPoint: NSMakePoint(0, 0) 933 operation: NSCompositeSourceOver]; 934 } 935} 936 937@end 938 939 940 941@implementation DocumentIcon 942 943- (void)dealloc 944{ 945 RELEASE (icon); 946 [super dealloc]; 947} 948 949- (id)initWithFrame:(NSRect)frameRect 950 searchResult:(id)sres 951{ 952 self = [super initWithFrame: frameRect]; 953 954 if (self) { 955 ASSIGN (icon, [NSImage imageNamed: @"DragableDocument"]); 956 searchResult = sres; 957 } 958 959 return self; 960} 961 962- (void)mouseDown:(NSEvent *)theEvent 963{ 964 NSEvent *nextEvent; 965 BOOL startdnd = NO; 966 int dragdelay = 0; 967 968 969 if ([theEvent clickCount] == 1) 970 { 971 while (1) 972 { 973 nextEvent = [[self window] nextEventMatchingMask: 974 NSLeftMouseUpMask | NSLeftMouseDraggedMask]; 975 976 if ([nextEvent type] == NSLeftMouseUp) 977 { 978 [[self window] postEvent: nextEvent atStart: NO]; 979 break; 980 981 } 982 else if ([nextEvent type] == NSLeftMouseDragged) 983 { 984 if (dragdelay < 5) 985 { 986 dragdelay++; 987 } 988 else 989 { 990 startdnd = YES; 991 break; 992 } 993 } 994 } 995 996 if (startdnd == YES) 997 { 998 [self startExternalDragOnEvent: theEvent]; 999 } 1000 } 1001} 1002 1003- (void)drawRect:(NSRect)rect 1004{ 1005 [super drawRect: rect]; 1006 [icon compositeToPoint: NSMakePoint(2, 2) 1007 operation: NSCompositeSourceOver]; 1008} 1009 1010- (void)startExternalDragOnEvent:(NSEvent *)event 1011{ 1012 NSPasteboard *pb = [NSPasteboard pasteboardWithName: NSDragPboard]; 1013 NSArray *dndtypes = [NSArray arrayWithObject: @"GWLSFolderPboardType"]; 1014 NSMutableDictionary *pbDict = [NSMutableDictionary dictionary]; 1015 NSData *pbData = nil; 1016 1017 [pb declareTypes: dndtypes owner: nil]; 1018 1019 [pbDict setObject: [NSArray arrayWithObject: lsfname] 1020 forKey: @"paths"]; 1021 [pbDict setObject: [NSNumber numberWithUnsignedLong: [searchResult memAddress]] 1022 forKey: @"sender"]; 1023 1024 pbData = [NSArchiver archivedDataWithRootObject: pbDict]; 1025 [pb setData: pbData forType: @"GWLSFolderPboardType"]; 1026 1027 [self dragImage: icon 1028 at: NSZeroPoint 1029 offset: NSZeroSize 1030 event: event 1031 pasteboard: pb 1032 source: self 1033 slideBack: YES]; 1034} 1035 1036- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag 1037{ 1038 return NSDragOperationAll; 1039} 1040 1041- (BOOL)ignoreModifierKeysWhileDragging 1042{ 1043 return YES; 1044} 1045 1046- (void)draggedImage:(NSImage *)anImage 1047 endedAt:(NSPoint)aPoint 1048 deposited:(BOOL)flag 1049{ 1050 [self setNeedsDisplay: YES]; 1051} 1052 1053@end 1054 1055