1/* GWViewerShelf.h 2 * 3 * Copyright (C) 2004-2016 Free Software Foundation, Inc. 4 * 5 * Author: Enrico Sersale <enrico@imago.ro> 6 * Date: July 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 <AppKit/AppKit.h> 28 29#import "GWViewerShelf.h" 30#import "GWViewer.h" 31#import "GWorkspace.h" 32#import "FSNTextCell.h" 33#import "FSNBrowser.h" 34#import "FSNIconsView.h" 35#import "FSNIcon.h" 36#import "FSNFunctions.h" 37 38#define DEF_ICN_SIZE 48 39#define DEF_TEXT_SIZE 12 40#define DEF_ICN_POS NSImageAbove 41 42#define DEF_GRID_WIDTH 90 43#define Y_MARGIN (4) 44#define EDIT_MARGIN (4) 45 46@interface GWTextField : NSTextField 47@end 48 49@implementation GWTextField 50 51- (id) initWithFrame: (NSRect)aFrame 52{ 53 NSTextFieldCell *cell; 54 55 self = [super initWithFrame: aFrame]; 56 57 cell = [[[FSNTextCell alloc] init] autorelease]; 58 [cell setDrawsBackground: YES]; 59 60 [self setCell: cell]; 61 62 return self; 63} 64 65@end 66 67 68@implementation GWViewerShelf 69 70- (void)dealloc 71{ 72 [self unsetWatchers]; 73 RELEASE (watchedPaths); 74 RELEASE (icons); 75 RELEASE (extInfoType); 76 if (grid != NULL) 77 { 78 NSZoneFree (NSDefaultMallocZone(), grid); 79 } 80 RELEASE (dragIcon); 81 RELEASE (focusedIconLabel); 82 RELEASE (backColor); 83 RELEASE (textColor); 84 RELEASE (disabledTextColor); 85 86 [super dealloc]; 87} 88 89- (id)initWithFrame:(NSRect)frameRect 90 forViewer:(id)vwr 91{ 92 self = [super initWithFrame: frameRect]; 93 94 if (self) { 95 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 96 id defentry; 97 98 fsnodeRep = [FSNodeRep sharedInstance]; 99 100 defentry = [defaults dictionaryForKey: @"backcolor"]; 101 if (defentry) { 102 float red = [[(NSDictionary *)defentry objectForKey: @"red"] floatValue]; 103 float green = [[(NSDictionary *)defentry objectForKey: @"green"] floatValue]; 104 float blue = [[(NSDictionary *)defentry objectForKey: @"blue"] floatValue]; 105 float alpha = [[(NSDictionary *)defentry objectForKey: @"alpha"] floatValue]; 106 107 ASSIGN (backColor, [NSColor colorWithCalibratedRed: red 108 green: green 109 blue: blue 110 alpha: alpha]); 111 } else { 112 ASSIGN (backColor, [[NSColor windowBackgroundColor] colorUsingColorSpaceName: NSDeviceRGBColorSpace]); 113 } 114 115 defentry = [defaults dictionaryForKey: @"textcolor"]; 116 if (defentry) { 117 float red = [[(NSDictionary *)defentry objectForKey: @"red"] floatValue]; 118 float green = [[(NSDictionary *)defentry objectForKey: @"green"] floatValue]; 119 float blue = [[(NSDictionary *)defentry objectForKey: @"blue"] floatValue]; 120 float alpha = [[(NSDictionary *)defentry objectForKey: @"alpha"] floatValue]; 121 122 ASSIGN (textColor, [NSColor colorWithCalibratedRed: red 123 green: green 124 blue: blue 125 alpha: alpha]); 126 } else { 127 ASSIGN (textColor, [[NSColor controlTextColor] colorUsingColorSpaceName: NSDeviceRGBColorSpace]); 128 } 129 130 ASSIGN (disabledTextColor, [textColor highlightWithLevel: NSDarkGray]); 131 132 iconSize = DEF_ICN_SIZE; 133 134 defentry = [defaults objectForKey: @"labeltxtsize"]; 135 labelTextSize = defentry ? [defentry intValue] : DEF_TEXT_SIZE; 136 ASSIGN (labelFont, [NSFont systemFontOfSize: labelTextSize]); 137 138 iconPosition = DEF_ICN_POS; 139 140 defentry = [defaults objectForKey: @"fsn_info_type"]; 141 infoType = defentry ? [defentry intValue] : FSNInfoNameType; 142 extInfoType = nil; 143 144 if (infoType == FSNInfoExtendedType) { 145 defentry = [defaults objectForKey: @"extended_info_type"]; 146 147 if (defentry) { 148 NSArray *availableTypes = [fsnodeRep availableExtendedInfoNames]; 149 150 if ([availableTypes containsObject: defentry]) { 151 ASSIGN (extInfoType, defentry); 152 } 153 } 154 155 if (extInfoType == nil) { 156 infoType = FSNInfoNameType; 157 } 158 } 159 160 defentry = [defaults objectForKey: @"shelfcellswidth"]; 161 gridSize.width = defentry ? [defentry intValue] : DEF_GRID_WIDTH; 162 163 icons = [NSMutableArray new]; 164 165 viewer = vwr; 166 gworkspace = [GWorkspace gworkspace]; 167 168 dragIcon = nil; 169 focusedIcon = nil; 170 171 [self calculateGridSize]; 172 [self makeIconsGrid]; 173 174 [self registerForDraggedTypes: [NSArray arrayWithObject: NSFilenamesPboardType]]; 175 176 watchedPaths = [[NSCountedSet alloc] initWithCapacity: 1]; 177 178 focusedIconLabel = [GWTextField new]; 179 [focusedIconLabel setFont: [NSFont systemFontOfSize: 12]]; 180 [focusedIconLabel setBezeled: NO]; 181 [focusedIconLabel setAlignment: NSCenterTextAlignment]; 182 [focusedIconLabel setEditable: NO]; 183 [focusedIconLabel setSelectable: NO]; 184 [focusedIconLabel setBackgroundColor: backColor]; 185 [focusedIconLabel setTextColor: [NSColor controlTextColor]]; 186 [focusedIconLabel setFrame: NSMakeRect(0, 0, 0, 14)]; 187 } 188 189 return self; 190} 191 192- (void)setContents:(NSArray *)iconsInfo 193{ 194 FSNode *baseNode = [viewer baseNode]; 195 int i; 196 197 for (i = 0; i < [iconsInfo count]; i++) { 198 NSDictionary *info = [iconsInfo objectAtIndex: i]; 199 NSArray *paths = [info objectForKey: @"paths"]; 200 int index = [[info objectForKey: @"index"] intValue]; 201 NSMutableArray *icnnodes = [NSMutableArray array]; 202 int j; 203 204 for (j = 0; j < [paths count]; j++) { 205 FSNode *node = [FSNode nodeWithPath: [paths objectAtIndex: j]]; 206 207 if ([node isValid] && [baseNode isParentOfNode: node]) { 208 [icnnodes addObject: node]; 209 } 210 } 211 212 if ([icnnodes count] && (index != -1)) { 213 if ([icnnodes count] == 1) { 214 [self addIconForNode: [icnnodes objectAtIndex: 0] atIndex: index]; 215 } else { 216 [self addIconForSelection: icnnodes atIndex: index]; 217 } 218 } 219 } 220 221 [self tile]; 222} 223 224- (NSArray *)contentsInfo 225{ 226 NSMutableArray *iconsInfo = [NSMutableArray array]; 227 int i; 228 229 for (i = 0; i < [icons count]; i++) { 230 FSNIcon *icon = [icons objectAtIndex: i]; 231 NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 232 233 if ([icon isShowingSelection]) { 234 NSArray *selection = [icon selection]; 235 NSMutableArray *paths = [NSMutableArray array]; 236 int j; 237 238 for (j = 0; j < [selection count]; j++) { 239 [paths addObject: [[selection objectAtIndex: j] path]]; 240 } 241 242 [dict setObject: paths forKey: @"paths"]; 243 244 } else { 245 [dict setObject: [NSArray arrayWithObject: [[icon node] path]] 246 forKey: @"paths"]; 247 } 248 249 [dict setObject: [NSNumber numberWithInt: [icon gridIndex]] 250 forKey: @"index"]; 251 252 [iconsInfo addObject: dict]; 253 } 254 255 return iconsInfo; 256} 257 258- (id)addIconForNode:(FSNode *)node 259 atIndex:(int)index 260{ 261 FSNIcon *icon = [[FSNIcon alloc] initForNode: node 262 nodeInfoType: infoType 263 extendedType: extInfoType 264 iconSize: iconSize 265 iconPosition: iconPosition 266 labelFont: labelFont 267 textColor: textColor 268 gridIndex: index 269 dndSource: YES 270 acceptDnd: YES 271 slideBack: NO]; 272 [icons addObject: icon]; 273 [self addSubview: icon]; 274 RELEASE (icon); 275 276 { 277 NSString *watched = [node parentPath]; 278 279 if ([watchedPaths containsObject: watched] == NO) { 280 [self setWatcherForPath: watched]; 281 } 282 [watchedPaths addObject: watched]; 283 } 284 285 return icon; 286} 287 288- (id)addIconForSelection:(NSArray *)selection 289 atIndex:(int)index 290{ 291 FSNIcon *icon = [self addIconForNode: [selection objectAtIndex: 0] 292 atIndex: index]; 293 [icon showSelection: selection]; 294 return icon; 295} 296 297- (id)iconForNode:(FSNode *)node 298{ 299 int i; 300 301 for (i = 0; i < [icons count]; i++) { 302 FSNIcon *icon = [icons objectAtIndex: i]; 303 304 if ([[icon node] isEqual: node] && ([icon selection] == nil)) { 305 return icon; 306 } 307 } 308 309 return nil; 310} 311 312- (id)iconForPath:(NSString *)path 313{ 314 int i; 315 316 for (i = 0; i < [icons count]; i++) { 317 FSNIcon *icon = [icons objectAtIndex: i]; 318 319 if ([[[icon node] path] isEqual: path] && ([icon selection] == nil)) { 320 return icon; 321 } 322 } 323 324 return nil; 325} 326 327- (id)iconForNodesSelection:(NSArray *)selection 328{ 329 int i; 330 331 for (i = 0; i < [icons count]; i++) { 332 FSNIcon *icon = [icons objectAtIndex: i]; 333 NSArray *selnodes = [icon selection]; 334 335 if (selnodes && [selnodes isEqual: selection]) { 336 return icon; 337 } 338 } 339 340 return nil; 341} 342 343- (id)iconForPathsSelection:(NSArray *)selection 344{ 345 int i; 346 347 for (i = 0; i < [icons count]; i++) { 348 FSNIcon *icon = [icons objectAtIndex: i]; 349 NSArray *selnodes = [icon selection]; 350 351 if (selnodes) { 352 NSMutableArray *selpaths = [NSMutableArray array]; 353 int j; 354 355 for (j = 0; j < [selnodes count]; j++) { 356 [selpaths addObject: [[selnodes objectAtIndex: j] path]]; 357 } 358 359 if ([selpaths isEqual: selection]) { 360 return icon; 361 } 362 } 363 } 364 365 return nil; 366} 367 368- (void)calculateGridSize 369{ 370 NSSize highlightSize = NSZeroSize; 371 NSSize labelSize = NSZeroSize; 372 373 highlightSize.width = ceil(iconSize / 3 * 4); 374 highlightSize.height = ceil(highlightSize.width * [fsnodeRep highlightHeightFactor]); 375 if ((highlightSize.height - iconSize) < 4) { 376 highlightSize.height = iconSize + 4; 377 } 378 379 labelSize.height = myrintf([fsnodeRep heightOfFont: labelFont]); 380 labelSize.width = gridSize.width; 381 gridSize.height = highlightSize.height + labelSize.height; 382} 383 384- (void)makeIconsGrid 385{ 386 NSRect gridrect = [self bounds]; 387 NSPoint gpnt; 388 int i; 389 390 if (grid != NULL) { 391 NSZoneFree (NSDefaultMallocZone(), grid); 392 } 393 394 colcount = (int)(gridrect.size.width / gridSize.width); 395 rowcount = (int)(gridrect.size.height / gridSize.height); 396 gridcount = colcount * rowcount; 397 398 grid = NSZoneMalloc (NSDefaultMallocZone(), sizeof(NSRect) * gridcount); 399 400 gpnt.x = 0; 401 gpnt.y = gridrect.size.height - gridSize.height - Y_MARGIN; 402 403 for (i = 0; i < gridcount; i++) { 404 if (i > 0) { 405 gpnt.x += gridSize.width; 406 } 407 408 if (gpnt.x >= (gridrect.size.width - gridSize.width)) { 409 gpnt.x = 0; 410 gpnt.y -= (gridSize.height + Y_MARGIN); 411 } 412 413 grid[i].origin = gpnt; 414 grid[i].size = gridSize; 415 grid[i] = NSIntegralRect(grid[i]); 416 } 417} 418 419- (int)firstFreeGridIndex 420{ 421 int i; 422 423 for (i = 0; i < gridcount; i++) { 424 if ([self isFreeGridIndex: i]) { 425 return i; 426 } 427 } 428 429 return -1; 430} 431 432- (int)firstFreeGridIndexAfterIndex:(int)index 433{ 434 int newind = index; 435 436 while (1) { 437 newind++; 438 439 if (newind >= gridcount) { 440 return [self firstFreeGridIndex]; 441 } 442 443 if ([self isFreeGridIndex: newind]) { 444 return newind; 445 } 446 } 447 448 return -1; 449} 450 451- (BOOL)isFreeGridIndex:(int)index 452{ 453 int i; 454 455 if ((index < 0) || (index >= gridcount)) { 456 return NO; 457 } 458 459 for (i = 0; i < [icons count]; i++) { 460 if ([[icons objectAtIndex: i] gridIndex] == index) { 461 return NO; 462 } 463 } 464 465 return YES; 466} 467 468- (id)iconWithGridIndex:(int)index 469{ 470 int i; 471 472 for (i = 0; i < [icons count]; i++) { 473 FSNIcon *icon = [icons objectAtIndex: i]; 474 475 if ([icon gridIndex] == index) { 476 return icon; 477 } 478 } 479 480 return nil; 481} 482 483- (int)indexOfGridRectContainingPoint:(NSPoint)p 484{ 485 int i; 486 487 for (i = 0; i < gridcount; i++) { 488 if (NSPointInRect(p, grid[i])) { 489 return i; 490 } 491 } 492 493 return -1; 494} 495 496- (NSRect)iconBoundsInGridAtIndex:(int)index 497{ 498 NSRect icnBounds = NSMakeRect(grid[index].origin.x, grid[index].origin.y, iconSize, iconSize); 499 NSRect hlightRect = NSZeroRect; 500 501 hlightRect.size.width = ceil(iconSize / 3 * 4); 502 hlightRect.size.height = ceil(hlightRect.size.width * [fsnodeRep highlightHeightFactor]); 503 hlightRect.origin.x = ceil((gridSize.width - hlightRect.size.width) / 2); 504 hlightRect.origin.y = floor([fsnodeRep heightOfFont: labelFont]); 505 506 icnBounds.origin.x += hlightRect.origin.x + ((hlightRect.size.width - iconSize) / 2); 507 icnBounds.origin.y += hlightRect.origin.y + ((hlightRect.size.height - iconSize) / 2); 508 509 return icnBounds; 510} 511 512- (void)tile 513{ 514 NSArray *subviews = [self subviews]; 515 NSUInteger i; 516 517 [self makeIconsGrid]; 518 519 for (i = 0; i < [icons count]; i++) { 520 FSNIcon *icon = [icons objectAtIndex: i]; 521 NSUInteger index = [icon gridIndex]; 522 523 if (index < gridcount) { 524 if ([subviews containsObject: icon] == NO) { 525 [self addSubview: icon]; 526 } 527 if (NSEqualRects(grid[index], [icon frame]) == NO) { 528 [icon setFrame: grid[index]]; 529 } 530 } else { 531 if (focusedIcon == icon) { 532 focusedIcon = nil; 533 } 534 535 [icon removeFromSuperview]; 536 } 537 } 538 539 [self updateFocusedIconLabel]; 540} 541 542- (void)updateFocusedIconLabel 543{ 544 if ([[self subviews] containsObject: focusedIconLabel]) { 545 NSRect rect = [focusedIconLabel frame]; 546 547 [focusedIconLabel removeFromSuperview]; 548 [self setNeedsDisplayInRect: rect]; 549 } 550 551 if (focusedIcon) { 552 NSRect icnr = [focusedIcon frame]; 553 float centerx = icnr.origin.x + (icnr.size.width / 2); 554 NSRect edrect = [self convertRect: [focusedIcon labelRect] fromView: focusedIcon]; 555 int margin = [fsnodeRep labelMargin]; 556 float bw = [self bounds].size.width - EDIT_MARGIN; 557 NSString *nodeDescr = [focusedIcon shownInfo]; 558 float edwidth = [[focusedIconLabel font] widthOfString: nodeDescr]; 559 560 edwidth += margin; 561 562 if ((centerx + (edwidth / 2)) >= bw) { 563 centerx -= (centerx + (edwidth / 2) - bw); 564 } else if ((centerx - (edwidth / 2)) < margin) { 565 centerx += fabs(centerx - (edwidth / 2)) + margin; 566 } 567 568 edrect.origin.x = centerx - (edwidth / 2); 569 edrect.size.width = edwidth; 570 edrect = NSIntegralRect(edrect); 571 572 [focusedIconLabel setFrame: edrect]; 573 [focusedIconLabel setStringValue: nodeDescr]; 574 575 if ([focusedIcon isLocked] == NO) { 576 [focusedIconLabel setTextColor: [NSColor controlTextColor]]; 577 } else { 578 [focusedIconLabel setTextColor: [NSColor disabledControlTextColor]]; 579 } 580 581 [focusedIcon setNameEdited: YES]; 582 583 [self addSubview: focusedIconLabel]; 584 [self setNeedsDisplayInRect: edrect]; 585 } 586} 587 588- (void)setWatcherForPath:(NSString *)path 589{ 590 [gworkspace addWatcherForPath: path]; 591} 592 593- (void)unsetWatcherForPath:(NSString *)path 594{ 595 [gworkspace removeWatcherForPath: path]; 596} 597 598- (void)unsetWatchers 599{ 600 NSEnumerator *enumerator = [watchedPaths objectEnumerator]; 601 NSString *wpath; 602 603 while ((wpath = [enumerator nextObject])) { 604 [self unsetWatcherForPath: wpath]; 605 } 606} 607 608- (NSArray *)watchedPaths 609{ 610 return [watchedPaths allObjects]; 611} 612 613- (void)checkIconsAfterDotsFilesChange 614{ 615 int count = [icons count]; 616 BOOL updated = NO; 617 int i; 618 619 for (i = 0; i < count; i++) { 620 FSNIcon *icon = [icons objectAtIndex: i]; 621 int j; 622 623 if ([icon isShowingSelection] == NO) { 624 if ([[[icon node] path] rangeOfString: @"."].location != NSNotFound) { 625 [self removeRep: icon]; 626 updated = YES; 627 count--; 628 i--; 629 } 630 631 } else { 632 NSArray *iconpaths = [icon pathsSelection]; 633 634 for (j = 0; j < [iconpaths count]; j++) { 635 NSString *iconpath = [iconpaths objectAtIndex: j]; 636 637 if ([iconpath rangeOfString: @"."].location != NSNotFound) { 638 [self removeRep: icon]; 639 updated = YES; 640 count--; 641 i--; 642 break; 643 } 644 } 645 } 646 } 647 648 if (updated) { 649 [self tile]; 650 [self setNeedsDisplay: YES]; 651 } 652} 653 654- (void)checkIconsAfterHidingOfPaths:(NSArray *)hpaths 655{ 656 int count = [icons count]; 657 BOOL updated = NO; 658 int i; 659 660 for (i = 0; i < count; i++) { 661 FSNIcon *icon = [icons objectAtIndex: i]; 662 int j, m; 663 664 if ([icon isShowingSelection] == NO) { 665 NSString *iconpath = [[icon node] path]; 666 667 for (m = 0; m < [hpaths count]; m++) { 668 NSString *hpath = [hpaths objectAtIndex: m]; 669 670 if (isSubpathOfPath(hpath, iconpath) || [hpath isEqual: iconpath]) { 671 [self removeRep: icon]; 672 updated = YES; 673 count--; 674 i--; 675 break; 676 } 677 } 678 } else { 679 NSArray *iconpaths = [icon pathsSelection]; 680 BOOL removed = NO; 681 682 for (j = 0; j < [iconpaths count]; j++) { 683 NSString *iconpath = [iconpaths objectAtIndex: j]; 684 685 for (m = 0; m < [hpaths count]; m++) { 686 NSString *hpath = [hpaths objectAtIndex: m]; 687 688 if (isSubpathOfPath(hpath, iconpath) || [hpath isEqual: iconpath]) { 689 [self removeRep: icon]; 690 updated = YES; 691 count--; 692 i--; 693 removed = YES; 694 break; 695 } 696 } 697 698 if (removed) { 699 break; 700 } 701 } 702 } 703 } 704 705 if (updated) { 706 [self tile]; 707 [self setNeedsDisplay: YES]; 708 } 709} 710 711- (void)resizeWithOldSuperviewSize:(NSSize)oldFrameSize 712{ 713 [self tile]; 714} 715 716- (void)setFrame:(NSRect)frameRect 717{ 718 [super setFrame: frameRect]; 719 [self tile]; 720} 721 722- (void)drawRect:(NSRect)rect 723{ 724 [super drawRect: rect]; 725 726 if (dragIcon) { 727 [dragIcon dissolveToPoint: dragPoint fraction: 0.3]; 728 } 729} 730 731@end 732 733 734@implementation GWViewerShelf (NodeRepContainer) 735 736- (void)removeRep:(id)arep 737{ 738 NSString *watched = [[arep node] parentPath]; 739 740 if ([watchedPaths containsObject: watched]) { 741 [watchedPaths removeObject: watched]; 742 743 if ([watchedPaths containsObject: watched] == NO) { 744 [self unsetWatcherForPath: watched]; 745 } 746 } 747 748 if ([[self subviews] containsObject: arep]) { 749 [arep removeFromSuperviewWithoutNeedingDisplay]; 750 } 751 752 if (focusedIcon == arep) { 753 focusedIcon = nil; 754 [self updateFocusedIconLabel]; 755 } 756 757 [icons removeObject: arep]; 758} 759 760- (void)removeUndepositedRep:(id)arep 761{ 762 [self removeRep: arep]; 763 [self setNeedsDisplay: YES]; 764} 765 766- (void)repSelected:(id)arep 767{ 768 [viewer shelfDidSelectIcon: arep]; 769 [arep unselect]; 770} 771 772- (void)unselectOtherReps:(id)arep 773{ 774 int i; 775 776 for (i = 0; i < [icons count]; i++) { 777 FSNIcon *icon = [icons objectAtIndex: i]; 778 779 if (icon != arep) { 780 [icon unselect]; 781 } 782 } 783} 784 785- (NSArray *)selectedPaths 786{ 787 NSMutableArray *selectedPaths = [NSMutableArray array]; 788 int i, j; 789 790 for (i = 0; i < [icons count]; i++) { 791 FSNIcon *icon = [icons objectAtIndex: i]; 792 793 if ([icon isSelected]) { 794 NSArray *selection = [icon selection]; 795 796 if (selection) { 797 for (j = 0; j < [selection count]; j++) { 798 [selectedPaths addObject: [[selection objectAtIndex: j] path]]; 799 } 800 } else { 801 [selectedPaths addObject: [[icon node] path]]; 802 } 803 } 804 } 805 806 return [NSArray arrayWithArray: selectedPaths]; 807} 808 809- (void)openSelectionInNewViewer:(BOOL)newv 810{ 811 [viewer openSelectionInNewViewer: newv]; 812} 813 814- (void)nodeContentsWillChange:(NSDictionary *)info 815{ 816 [self checkLockedReps]; 817} 818 819- (void)nodeContentsDidChange:(NSDictionary *)info 820{ 821 NSString *operation = [info objectForKey: @"operation"]; 822 NSString *source = [info objectForKey: @"source"]; 823 NSString *destination = [info objectForKey: @"destination"]; 824 NSArray *files = [info objectForKey: @"files"]; 825 int i; 826 827 if ([operation isEqual: NSWorkspaceRecycleOperation]) { 828 files = [info objectForKey: @"origfiles"]; 829 } 830 831 if ([operation isEqual: @"GWorkspaceRenameOperation"]) { 832 for (i = 0; i < [icons count]; i++) { 833 FSNIcon *icon = [icons objectAtIndex: i]; 834 835 if ([icon isShowingSelection] == NO) { 836 if ([[[icon node] path] isEqual: source]) { 837 [icon setNode: [FSNode nodeWithPath: destination]]; 838 break; 839 } 840 } 841 } 842 } 843 844 if ([operation isEqual: @"GWorkspaceRenameOperation"]) { 845 files = [NSArray arrayWithObject: [source lastPathComponent]]; 846 source = [source stringByDeletingLastPathComponent]; 847 } 848 849 if ([operation isEqual: NSWorkspaceMoveOperation] 850 || [operation isEqual: NSWorkspaceDestroyOperation] 851 || [operation isEqual: @"GWorkspaceRenameOperation"] 852 || [operation isEqual: NSWorkspaceRecycleOperation] 853 || [operation isEqual: @"GWorkspaceRecycleOutOperation"] 854 || [operation isEqual: @"GWorkspaceEmptyRecyclerOperation"]) { 855 NSMutableArray *oppaths = [NSMutableArray array]; 856 int count = [icons count]; 857 BOOL updated = NO; 858 859 for (i = 0; i < [files count]; i++) { 860 NSString *fname = [files objectAtIndex: i]; 861 NSString *fpath = [source stringByAppendingPathComponent: fname]; 862 [oppaths addObject: fpath]; 863 } 864 865 for (i = 0; i < count; i++) { 866 FSNIcon *icon = [icons objectAtIndex: i]; 867 int j, m; 868 869 if ([icon isShowingSelection] == NO) { 870 NSString *iconpath = [[icon node] path]; 871 872 for (m = 0; m < [oppaths count]; m++) { 873 if ([iconpath hasPrefix: [oppaths objectAtIndex: m]]) { 874 [self removeRep: icon]; 875 updated = YES; 876 count--; 877 i--; 878 break; 879 } 880 } 881 882 } else { 883 NSArray *iconpaths = [icon pathsSelection]; 884 BOOL removed = NO; 885 886 for (j = 0; j < [iconpaths count]; j++) { 887 NSString *iconpath = [iconpaths objectAtIndex: j]; 888 889 for (m = 0; m < [oppaths count]; m++) { 890 if ([iconpath hasPrefix: [oppaths objectAtIndex: m]]) { 891 [self removeRep: icon]; 892 updated = YES; 893 count--; 894 i--; 895 removed = YES; 896 break; 897 } 898 } 899 900 if (removed) { 901 break; 902 } 903 } 904 } 905 } 906 907 if (updated) { 908 [self tile]; 909 [self setNeedsDisplay: YES]; 910 } 911 } 912} 913 914- (void)watchedPathChanged:(NSDictionary *)info 915{ 916 NSString *path = [info objectForKey: @"path"]; 917 NSString *event = [info objectForKey: @"event"]; 918 NSEnumerator *enumerator; 919 NSString *wpath; 920 BOOL contained = NO; 921 922 if ([event isEqual: @"GWFileCreatedInWatchedDirectory"]) 923 { 924 return; 925 } 926 927 enumerator = [watchedPaths objectEnumerator]; 928 929 while ((wpath = [enumerator nextObject])) 930 { 931 if (([wpath isEqual: path]) || (isSubpathOfPath(path, wpath))) 932 { 933 contained = YES; 934 break; 935 } 936 } 937 938 if (contained) 939 { 940 NSUInteger count = [icons count]; 941 BOOL updated = NO; 942 FSNIcon *icon; 943 NSUInteger i; 944 945 if ([event isEqual: @"GWWatchedPathDeleted"]) 946 { 947 for (i = 0; i < count; i++) 948 { 949 icon = [icons objectAtIndex: i]; 950 951 if ([[icon node] isSubnodeOfPath: path]) 952 { 953 [self removeRep: icon]; 954 updated = YES; 955 count--; 956 i--; 957 } 958 } 959 960 if (updated) 961 { 962 [self tile]; 963 [self setNeedsDisplay: YES]; 964 } 965 966 return; 967 } 968 969 if ([event isEqual: @"GWFileDeletedInWatchedDirectory"]) 970 { 971 NSArray *files = [info objectForKey: @"files"]; 972 973 for (i = 0; i < count; i++) 974 { 975 NSUInteger j; 976 977 icon = [icons objectAtIndex: i]; 978 979 if ([icon isShowingSelection] == NO) 980 { 981 FSNode *node = [icon node]; 982 983 for (j = 0; j < [files count]; j++) 984 { 985 NSString *fname = [files objectAtIndex: j]; 986 NSString *fpath = [path stringByAppendingPathComponent: fname]; 987 988 if ([[node path] isEqual: fpath] || [node isSubnodeOfPath: fpath]) 989 { 990 [self removeRep: icon]; 991 updated = YES; 992 count--; 993 i--; 994 break; 995 } 996 } 997 998 } 999 else 1000 { 1001 FSNode *node = [icon node]; 1002 NSArray *selection = [icon selection]; 1003 1004 for (j = 0; j < [files count]; j++) 1005 { 1006 NSString *fname = [files objectAtIndex: j]; 1007 NSString *fpath = [path stringByAppendingPathComponent: fname]; 1008 BOOL deleted = NO; 1009 NSUInteger m; 1010 1011 if (deleted) 1012 { 1013 break; 1014 } 1015 1016 if ([node isSubnodeOfPath: fpath]) 1017 { 1018 [self removeRep: icon]; 1019 updated = YES; 1020 count--; 1021 i--; 1022 break; 1023 } 1024 1025 for (m = 0; m < [selection count]; m++) 1026 { 1027 node = [selection objectAtIndex: m]; 1028 1029 if ([[node path] isEqual: fpath]) 1030 { 1031 [self removeRep: icon]; 1032 updated = YES; 1033 count--; 1034 i--; 1035 deleted = YES; 1036 break; 1037 } 1038 } 1039 } 1040 } 1041 } 1042 1043 if (updated) 1044 { 1045 [self tile]; 1046 [self setNeedsDisplay: YES]; 1047 } 1048 } 1049 } 1050} 1051 1052- (void)checkLockedReps 1053{ 1054 NSUInteger i; 1055 1056 for (i = 0; i < [icons count]; i++) 1057 { 1058 [[icons objectAtIndex: i] checkLocked]; 1059 } 1060} 1061 1062- (FSNSelectionMask)selectionMask 1063{ 1064 return NSSingleSelectionMask; 1065} 1066 1067- (void)restoreLastSelection 1068{ 1069 [self unselectOtherReps: nil]; 1070} 1071 1072- (void)setFocusedRep:(id)arep 1073{ 1074 if (arep == nil) { 1075 if (focusedIcon) { 1076 [focusedIcon setNameEdited: NO]; 1077 } 1078 } 1079 1080 focusedIcon = arep; 1081 [self updateFocusedIconLabel]; 1082} 1083 1084- (NSColor *)backgroundColor 1085{ 1086 return backColor; 1087} 1088 1089- (NSColor *)textColor 1090{ 1091 return textColor; 1092} 1093 1094- (NSColor *)disabledTextColor 1095{ 1096 return disabledTextColor; 1097} 1098 1099@end 1100 1101 1102@implementation GWViewerShelf (DraggingDestination) 1103 1104- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender 1105{ 1106 NSPasteboard *pb = [sender draggingPasteboard]; 1107 NSDragOperation sourceDragMask = [sender draggingSourceOperationMask]; 1108 1109 DESTROY (dragIcon); 1110 isDragTarget = NO; 1111 dragLocalIcon = NO; 1112 1113 if ((sourceDragMask == NSDragOperationCopy) 1114 || (sourceDragMask == NSDragOperationLink)) 1115 { 1116 return NSDragOperationNone; 1117 } 1118 1119 if (pb && [[pb types] containsObject: NSFilenamesPboardType]) 1120 { 1121 NSArray *sourcePaths = [pb propertyListForType: NSFilenamesPboardType]; 1122 NSUInteger count = [sourcePaths count]; 1123 FSNode *baseNode = [viewer baseNode]; 1124 NSString *basePath; 1125 NSUInteger i; 1126 1127 if (count == 0) 1128 { 1129 return NSDragOperationNone; 1130 } 1131 1132 for (i = 0; i < count; i++) 1133 { 1134 NSString *path = [sourcePaths objectAtIndex: i]; 1135 1136 if ([baseNode isParentOfPath: path] == NO) 1137 { 1138 return NSDragOperationNone; 1139 } 1140 } 1141 1142 basePath = [[sourcePaths objectAtIndex: 0] stringByDeletingLastPathComponent]; 1143 if ([basePath isEqual: [gworkspace trashPath]]) 1144 { 1145 return NSDragOperationNone; 1146 } 1147 1148 if (count == 1) { 1149 dragLocalIcon = ([self iconForPath: [sourcePaths objectAtIndex: 0]] != nil); 1150 } else { 1151 dragLocalIcon = ([self iconForPathsSelection: sourcePaths] != nil); 1152 } 1153 1154 isDragTarget = YES; 1155 dragPoint = NSZeroPoint; 1156 DESTROY (dragIcon); 1157 insertIndex = -1; 1158 1159 return NSDragOperationAll; 1160 } 1161 1162 return NSDragOperationNone; 1163} 1164 1165- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender 1166{ 1167 NSDragOperation sourceDragMask; 1168 NSPoint dpoint; 1169 int index; 1170 1171 if (isDragTarget == NO) { 1172 return NSDragOperationNone; 1173 } 1174 1175 sourceDragMask = [sender draggingSourceOperationMask]; 1176 1177 if ((sourceDragMask == NSDragOperationCopy) 1178 || (sourceDragMask == NSDragOperationLink)) { 1179 if (dragIcon) { 1180 DESTROY (dragIcon); 1181 if (insertIndex != -1) { 1182 [self setNeedsDisplayInRect: grid[insertIndex]]; 1183 } 1184 } 1185 return NSDragOperationNone; 1186 } 1187 1188 dpoint = [sender draggingLocation]; 1189 dpoint = [self convertPoint: dpoint fromView: nil]; 1190 index = [self indexOfGridRectContainingPoint: dpoint]; 1191 1192 if ((index != -1) && ([self isFreeGridIndex: index])) { 1193 NSImage *img = [sender draggedImage]; 1194 NSSize sz = [img size]; 1195 NSRect irect = [self iconBoundsInGridAtIndex: index]; 1196 1197 dragPoint.x = ceil(irect.origin.x + ((irect.size.width - sz.width) / 2)); 1198 dragPoint.y = ceil(irect.origin.y + ((irect.size.height - sz.height) / 2)); 1199 1200 if (dragIcon == nil) { 1201 ASSIGN (dragIcon, img); 1202 } 1203 1204 if (insertIndex != index) { 1205 [self setNeedsDisplayInRect: grid[index]]; 1206 1207 if (insertIndex != -1) { 1208 [self setNeedsDisplayInRect: grid[insertIndex]]; 1209 } 1210 } 1211 1212 insertIndex = index; 1213 1214 } else { 1215 DESTROY (dragIcon); 1216 if (insertIndex != -1) { 1217 [self setNeedsDisplayInRect: grid[insertIndex]]; 1218 } 1219 insertIndex = -1; 1220 return NSDragOperationNone; 1221 } 1222 1223 if ((sourceDragMask == NSDragOperationCopy) 1224 || (sourceDragMask == NSDragOperationLink)) { 1225 return NSDragOperationNone; 1226 } 1227 1228 return NSDragOperationAll; 1229} 1230 1231- (void)draggingExited:(id <NSDraggingInfo>)sender 1232{ 1233 DESTROY (dragIcon); 1234 if (insertIndex != -1) { 1235 [self setNeedsDisplayInRect: grid[insertIndex]]; 1236 } 1237 isDragTarget = NO; 1238} 1239 1240- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender 1241{ 1242 return isDragTarget; 1243} 1244 1245- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender 1246{ 1247 return YES; 1248} 1249 1250- (void)concludeDragOperation:(id <NSDraggingInfo>)sender 1251{ 1252 NSPasteboard *pb = [sender draggingPasteboard]; 1253 NSMutableArray *sourcePaths = [pb propertyListForType: NSFilenamesPboardType]; 1254 int count = [sourcePaths count]; 1255 id icon; 1256 1257 DESTROY (dragIcon); 1258 isDragTarget = NO; 1259 1260 if (insertIndex != -1) { 1261 if (dragLocalIcon) { 1262 if (count == 1) { 1263 icon = [self iconForPath: [sourcePaths objectAtIndex: 0]]; 1264 } else { 1265 icon = [self iconForPathsSelection: sourcePaths]; 1266 } 1267 1268 if (icon) { 1269 [icon setGridIndex: insertIndex]; 1270 } 1271 1272 } else { 1273 FSNode *baseNode = [viewer baseNode]; 1274 NSMutableArray *icnnodes = [NSMutableArray array]; 1275 int i; 1276 1277 for (i = 0; i < [sourcePaths count]; i++) { 1278 FSNode *node = [FSNode nodeWithPath: [sourcePaths objectAtIndex: i]]; 1279 1280 if ([node isValid] && [baseNode isParentOfNode: node]) { 1281 [icnnodes addObject: node]; 1282 } 1283 } 1284 1285 if ([icnnodes count]) { 1286 if ([icnnodes count] == 1) { 1287 [self addIconForNode: [icnnodes objectAtIndex: 0] atIndex: insertIndex]; 1288 } else { 1289 [self addIconForSelection: icnnodes atIndex: insertIndex]; 1290 } 1291 } 1292 } 1293 } 1294 1295 [self tile]; 1296 [self setNeedsDisplay: YES]; 1297} 1298 1299@end 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334