1/* GWViewerIconsPath.m
2 *
3 * Copyright (C) 2004-2016 Free Software Foundation, Inc.
4 *
5 * Author: Enrico Sersale <enrico@imago.ro>
6 *         Riccardo Mottola <rm@gnu.org>
7 * Date: July 2004
8 *
9 * This file is part of the GNUstep GWorkspace application
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
24 */
25
26#include <math.h>
27#include <sys/types.h>
28#include <unistd.h>
29
30#import <AppKit/AppKit.h>
31
32#import "FSNIcon.h"
33#import "FSNFunctions.h"
34#import "GWViewerIconsPath.h"
35#import "GWViewer.h"
36#import "GWorkspace.h"
37
38#define DEF_ICN_SIZE 48
39#define DEF_TEXT_SIZE 12
40#define DEF_ICN_POS NSImageAbove
41
42#define X_MARGIN (10)
43#define Y_MARGIN (12)
44
45#define EDIT_MARGIN (4)
46
47
48@implementation GWViewerIconsPath
49
50- (void)dealloc
51{
52  RELEASE (icons);
53  RELEASE (extInfoType);
54  RELEASE (labelFont);
55  RELEASE (backColor);
56  RELEASE (textColor);
57  RELEASE (disabledTextColor);
58
59  [super dealloc];
60}
61
62- (id)initWithFrame:(NSRect)frameRect
63       visibleIcons:(int)vicns
64          forViewer:(id)vwr
65       ownsScroller:(BOOL)ownscr
66{
67  self = [super initWithFrame: frameRect];
68
69  if (self) {
70    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
71    id defentry;
72
73    fsnodeRep = [FSNodeRep sharedInstance];
74
75    visibleIcons = vicns;
76    viewer = vwr;
77    ownScroller = ownscr;
78
79    firstVisibleIcon = 0;
80    lastVisibleIcon = visibleIcons - 1;
81    shift = 0;
82
83    defentry = [defaults dictionaryForKey: @"backcolor"];
84    if (defentry) {
85      float red = [[(NSDictionary *)defentry objectForKey: @"red"] floatValue];
86      float green = [[(NSDictionary *)defentry objectForKey: @"green"] floatValue];
87      float blue = [[(NSDictionary *)defentry objectForKey: @"blue"] floatValue];
88      float alpha = [[(NSDictionary *)defentry objectForKey: @"alpha"] floatValue];
89
90      ASSIGN (backColor, [NSColor colorWithCalibratedRed: red
91                                                   green: green
92                                                    blue: blue
93                                                   alpha: alpha]);
94    } else {
95      ASSIGN (backColor, [[NSColor windowBackgroundColor] colorUsingColorSpaceName: NSDeviceRGBColorSpace]);
96    }
97
98    defentry = [defaults dictionaryForKey: @"textcolor"];
99    if (defentry) {
100      float red = [[(NSDictionary *)defentry objectForKey: @"red"] floatValue];
101      float green = [[(NSDictionary *)defentry objectForKey: @"green"] floatValue];
102      float blue = [[(NSDictionary *)defentry objectForKey: @"blue"] floatValue];
103      float alpha = [[(NSDictionary *)defentry objectForKey: @"alpha"] floatValue];
104
105      ASSIGN (textColor, [NSColor colorWithCalibratedRed: red
106                                                   green: green
107                                                    blue: blue
108                                                   alpha: alpha]);
109    } else {
110      ASSIGN (textColor, [[NSColor controlTextColor] colorUsingColorSpaceName: NSDeviceRGBColorSpace]);
111    }
112
113    ASSIGN (disabledTextColor, [textColor highlightWithLevel: NSDarkGray]);
114
115    iconSize = DEF_ICN_SIZE;
116
117    defentry = [defaults objectForKey: @"labeltxtsize"];
118    labelTextSize = defentry ? [defentry intValue] : DEF_TEXT_SIZE;
119    ASSIGN (labelFont, [NSFont systemFontOfSize: labelTextSize]);
120
121    iconPosition = DEF_ICN_POS;
122
123    defentry = [defaults objectForKey: @"fsn_info_type"];
124    infoType = defentry ? [defentry intValue] : FSNInfoNameType;
125    extInfoType = nil;
126
127    if (infoType == FSNInfoExtendedType) {
128      defentry = [defaults objectForKey: @"extended_info_type"];
129
130      if (defentry) {
131        NSArray *availableTypes = [fsnodeRep availableExtendedInfoNames];
132
133        if ([availableTypes containsObject: defentry]) {
134          ASSIGN (extInfoType, defentry);
135        }
136      }
137
138      if (extInfoType == nil) {
139        infoType = FSNInfoNameType;
140      }
141    }
142
143    icons = [NSMutableArray new];
144
145    nameEditor = [FSNIconNameEditor new];
146    [nameEditor setDelegate: self];
147		[nameEditor setFont: labelFont];
148		[nameEditor setBezeled: NO];
149		[nameEditor setAlignment: NSCenterTextAlignment];
150	  [nameEditor setBackgroundColor: backColor];
151	  [nameEditor setTextColor: textColor];
152    [nameEditor setEditable: NO];
153    [nameEditor setSelectable: NO];
154    editIcon = nil;
155
156    [self calculateGridSize];
157  }
158
159  return self;
160}
161
162- (void)setOwnsScroller:(BOOL)ownscr
163{
164  ownScroller = ownscr;
165  [self setFrame: [[self superview] bounds]];
166  [self tile];
167}
168
169- (void)showPathComponents:(NSArray *)components
170                 selection:(NSArray *)selection
171{
172  FSNode *node = [selection objectAtIndex: 0];
173  int count = [components count];
174  FSNIcon *icon;
175  int icncount;
176  int i;
177
178  [self stopRepNameEditing];
179
180  while ([icons count] > count) {
181    icon = [self lastIcon];
182    if (icon) {
183      [self removeRep: icon];
184    }
185  }
186
187  icncount = [icons count];
188
189  for (i = 0; i < [components count]; i++) {
190    FSNode *component = [components objectAtIndex: i];
191
192    if (i < icncount) {
193      icon = [icons objectAtIndex: i];
194      [icon setNode: component];
195    } else {
196      icon = [self addRepForSubnode: component];
197    }
198
199    [icon setLeaf: NO];
200    [icon setNameEdited: NO];
201    [icon setGridIndex: i];
202  }
203
204  if ([node isEqual: [components objectAtIndex: (count -1)]] == NO) {
205    icon = [self addRepForSubnode: node];
206
207    if ([selection count] > 1) {
208      NSMutableArray *selnodes = [NSMutableArray array];
209
210      for (i = 0; i < [selection count]; i++) {
211        FSNode *selnode = [selection objectAtIndex: i];
212        [selnodes addObject: selnode];
213      }
214
215      [icon showSelection: selnodes];
216    }
217  }
218
219  icon = [self lastIcon];
220  [icon setLeaf: YES];
221  [icon select];
222
223  editIcon = nil;
224
225  [self tile];
226}
227
228- (void)setSelectableIconsRange:(NSRange)range
229{
230  int cols = range.length;
231
232  if (cols != visibleIcons) {
233    [self setFrame: [[self superview] bounds]];
234    visibleIcons = cols;
235  }
236
237  firstVisibleIcon = range.location;
238  lastVisibleIcon = firstVisibleIcon + visibleIcons - 1;
239  shift = 0;
240
241  if (([icons count] - 1) < lastVisibleIcon) {
242    shift = lastVisibleIcon - [icons count] + 1;
243  }
244
245  [self tile];
246}
247
248- (int)firstVisibleIcon
249{
250  return firstVisibleIcon;
251}
252
253- (int)lastVisibleIcon
254{
255  return lastVisibleIcon;
256}
257
258- (id)lastIcon
259{
260  int count = [icons count];
261  return (count ? [icons objectAtIndex: (count - 1)] : nil);
262}
263
264- (void)updateLastIcon
265{
266  FSNIcon *icon = [self lastIcon];
267
268  if (icon) {
269    NSArray *selection = [icon selection];
270
271    if (selection) {
272      [icon showSelection: selection];
273    } else {
274      [icon setNode: [icon node]];
275    }
276  }
277}
278
279- (void)calculateGridSize
280{
281  NSSize highlightSize = NSZeroSize;
282  NSSize labelSize = NSZeroSize;
283
284  highlightSize.width = ceil(iconSize / 3 * 4);
285  highlightSize.height = ceil(highlightSize.width * [fsnodeRep highlightHeightFactor]);
286  if ((highlightSize.height - iconSize) < 4) {
287    highlightSize.height = iconSize + 4;
288  }
289
290  labelSize.height = myrintf([fsnodeRep heightOfFont: labelFont]);
291  gridSize.height = highlightSize.height + labelSize.height;
292}
293
294- (void)tile
295{
296  NSClipView *clip = (NSClipView *)[self superview];
297  float vwidth = [clip visibleRect].size.width;
298	int count = [icons count];
299  int i;
300
301  if (ownScroller) {
302    NSRect fr = [self frame];
303    float x = [clip bounds].origin.x;
304    float y = [clip bounds].origin.y;
305    float posx = 0.0;
306
307    gridSize.width = myrintf(vwidth / visibleIcons);
308    [(NSScrollView *)[clip superview] setLineScroll: gridSize.width];
309
310    for (i = 0; i < count; i++) {
311      NSRect r = NSZeroRect;
312
313      r.size = gridSize;
314      r.origin.y = 0;
315      r.origin.x = posx;
316
317      [[icons objectAtIndex: i] setFrame: r];
318
319      posx += gridSize.width;
320    }
321
322    if (posx != fr.size.width) {
323      [self setFrame: NSMakeRect(0, fr.origin.y, posx, fr.size.height)];
324    }
325
326    if (count > visibleIcons) {
327      x += gridSize.width * count;
328      [clip scrollToPoint: NSMakePoint(x, y)];
329    }
330
331  } else {
332    vwidth -= visibleIcons;
333    gridSize.width = myrintf(vwidth / visibleIcons);
334
335    for (i = 0; i < count; i++) {
336      int n = i - firstVisibleIcon;
337      NSRect r = NSZeroRect;
338
339      r.size = gridSize;
340      r.origin.y = 0;
341
342      if (i < firstVisibleIcon) {
343        r.origin.x = (n * gridSize.width) - 8;
344      } else {
345        if (i == firstVisibleIcon) {
346          r.origin.x = (n * gridSize.width);
347        } else if (i <= lastVisibleIcon) {
348          r.origin.x = (n * gridSize.width) + n;
349        } else {
350          r.origin.x = (n * gridSize.width) + n + 8;
351        }
352	    }
353
354      if (i == lastVisibleIcon) {
355        r.size.width = [[self superview] visibleRect].size.width - r.origin.x;
356	    }
357
358      [[icons objectAtIndex: i] setFrame: r];
359    }
360  }
361
362  [self updateNameEditor];
363
364  [self setNeedsDisplay: YES];
365}
366
367- (void)resizeWithOldSuperviewSize:(NSSize)oldFrameSize
368{
369  [self tile];
370}
371
372- (NSMenu *)menuForEvent:(NSEvent *)theEvent
373{
374  NSPoint location = [theEvent locationInWindow];
375  NSPoint selfloc = [self convertPoint: location fromView: nil];
376
377  if (editIcon && [self mouse: selfloc inRect: [editIcon frame]]) {
378    NSArray *selnodes;
379    NSMenu *menu;
380    NSMenuItem *menuItem;
381    NSString *firstext;
382    NSDictionary *apps;
383    NSEnumerator *app_enum;
384    id key;
385    int i;
386
387    if ([theEvent modifierFlags] == NSControlKeyMask) {
388      return [super menuForEvent: theEvent];
389    }
390
391    selnodes = [self selectedNodes];
392
393    if ([selnodes count]) {
394      NSAutoreleasePool *pool;
395
396      firstext = [[[selnodes objectAtIndex: 0] path] pathExtension];
397
398      for (i = 0; i < [selnodes count]; i++) {
399        FSNode *snode = [selnodes objectAtIndex: i];
400        NSString *selpath = [snode path];
401        NSString *ext = [selpath pathExtension];
402
403        if ([ext isEqual: firstext] == NO) {
404          return [super menuForEvent: theEvent];
405        }
406
407        if ([snode isDirectory] == NO) {
408          if ([snode isPlain] == NO) {
409            return [super menuForEvent: theEvent];
410          }
411        } else {
412          if (([snode isPackage] == NO) || [snode isApplication]) {
413            return [super menuForEvent: theEvent];
414          }
415        }
416      }
417
418      menu = [[NSMenu alloc] initWithTitle: NSLocalizedString(@"Open with", @"")];
419      apps = [[NSWorkspace sharedWorkspace] infoForExtension: firstext];
420      app_enum = [[apps allKeys] objectEnumerator];
421
422      pool = [NSAutoreleasePool new];
423
424      while ((key = [app_enum nextObject])) {
425        menuItem = [NSMenuItem new];
426        key = [key stringByDeletingPathExtension];
427        [menuItem setTitle: key];
428        [menuItem setTarget: [GWorkspace gworkspace]];
429        [menuItem setAction: @selector(openSelectionWithApp:)];
430        [menuItem setRepresentedObject: key];
431        [menu addItem: menuItem];
432        RELEASE (menuItem);
433      }
434
435      RELEASE (pool);
436
437      return [menu autorelease];
438    }
439  }
440
441  return [super menuForEvent: theEvent];
442}
443
444//
445// scrollview delegate
446//
447- (void)gwviewerPathsScroll:(GWViewerPathsScroll *)sender
448         scrollViewScrolled:(NSClipView *)clip
449                    hitPart:(NSScrollerPart)hitpart
450{
451  if (hitpart != NSScrollerNoPart) {
452    int x = (int)[clip bounds].origin.x;
453    int y = (int)[clip bounds].origin.y;
454    int rem = x % (int)(myrintf(gridSize.width));
455
456    [self stopRepNameEditing];
457
458    if (rem != 0) {
459      if (rem <= gridSize.width / 2) {
460        x -= rem;
461      } else {
462        x += myrintf(gridSize.width) - rem;
463      }
464
465      [clip scrollToPoint: NSMakePoint(x, y)];
466      [self setNeedsDisplay: YES];
467    }
468
469    editIcon = [self lastIcon];
470    if (editIcon && NSContainsRect([editIcon visibleRect], [editIcon iconBounds])) {
471      [self updateNameEditor];
472    }
473  }
474}
475
476@end
477
478
479@implementation GWViewerIconsPath (NodeRepContainer)
480
481- (FSNode *)baseNode
482{
483  return [viewer baseNode];
484}
485
486- (id)repOfSubnode:(FSNode *)anode
487{
488  int i;
489
490  for (i = 0; i < [icons count]; i++) {
491    FSNIcon *icon = [icons objectAtIndex: i];
492
493    if ([[icon node] isEqualToNode: anode]) {
494      return icon;
495    }
496  }
497
498  return nil;
499}
500
501- (id)repOfSubnodePath:(NSString *)apath
502{
503  int i;
504
505  for (i = 0; i < [icons count]; i++) {
506    FSNIcon *icon = [icons objectAtIndex: i];
507
508    if ([[[icon node] path] isEqual: apath]) {
509      return icon;
510    }
511  }
512
513  return nil;
514}
515
516- (id)addRepForSubnode:(FSNode *)anode
517{
518  FSNIcon *icon = [[FSNIcon alloc] initForNode: anode
519                                  nodeInfoType: infoType
520                                  extendedType: extInfoType
521                                      iconSize: iconSize
522                                  iconPosition: iconPosition
523                                     labelFont: labelFont
524                                     textColor: textColor
525                                     gridIndex: -1
526                                     dndSource: YES
527                                     acceptDnd: YES
528                                     slideBack: YES];
529  [icons addObject: icon];
530  [self addSubview: icon];
531  RELEASE (icon);
532
533  return icon;
534}
535
536- (id)addRepForSubnodePath:(NSString *)apath
537{
538  FSNode *subnode = [FSNode nodeWithPath: apath];
539  return [self addRepForSubnode: subnode];
540}
541
542- (void)removeRep:(id)arep
543{
544  if (arep == editIcon) {
545    editIcon = nil;
546  }
547  [arep removeFromSuperviewWithoutNeedingDisplay];
548  [icons removeObject: arep];
549}
550
551- (void)repSelected:(id)arep
552{
553  if (([arep isShowingSelection] == NO) && ((arep == [self lastIcon]) == NO)) {
554    [viewer pathsViewDidSelectIcon: arep];
555  }
556}
557
558- (void)unselectOtherReps:(id)arep
559{
560  int i;
561
562  for (i = 0; i < [icons count]; i++) {
563    FSNIcon *icon = [icons objectAtIndex: i];
564
565    if (icon != arep) {
566      [icon unselect];
567    }
568  }
569}
570
571- (NSArray *)selectedNodes
572{
573  NSMutableArray *selectedNodes = [NSMutableArray array];
574  NSUInteger i;
575
576  for (i = 0; i < [icons count]; i++) {
577    FSNIcon *icon = [icons objectAtIndex: i];
578
579    if ([icon isSelected]) {
580      NSArray *selection = [icon selection];
581
582      if (selection) {
583        [selectedNodes addObjectsFromArray: selection];
584      } else {
585        [selectedNodes addObject: [icon node]];
586      }
587    }
588  }
589
590  return [selectedNodes makeImmutableCopyOnFail: NO];
591}
592
593- (NSArray *)selectedPaths
594{
595  NSMutableArray *selectedPaths = [NSMutableArray array];
596  NSUInteger i, j;
597
598  for (i = 0; i < [icons count]; i++) {
599    FSNIcon *icon = [icons objectAtIndex: i];
600
601    if ([icon isSelected]) {
602      NSArray *selection = [icon selection];
603
604      if (selection) {
605        for (j = 0; j < [selection count]; j++) {
606          [selectedPaths addObject: [[selection objectAtIndex: j] path]];
607        }
608      } else {
609        [selectedPaths addObject: [[icon node] path]];
610      }
611    }
612  }
613
614  return [selectedPaths makeImmutableCopyOnFail: NO];
615}
616
617- (void)checkLockedReps
618{
619  NSUInteger i;
620
621  for (i = 0; i < [icons count]; i++)
622    {
623      [[icons objectAtIndex: i] checkLocked];
624    }
625}
626
627- (FSNSelectionMask)selectionMask
628{
629  return NSSingleSelectionMask;
630}
631
632- (void)openSelectionInNewViewer:(BOOL)newv
633{
634  [viewer openSelectionInNewViewer: newv];
635}
636
637- (void)restoreLastSelection
638{
639  [[self lastIcon] select];
640  [nameEditor setBackgroundColor: [NSColor selectedControlColor]];
641}
642
643- (NSColor *)backgroundColor
644{
645  return [NSColor windowBackgroundColor];
646}
647
648- (NSColor *)textColor
649{
650  return [NSColor controlTextColor];
651}
652
653- (NSColor *)disabledTextColor
654{
655  return [NSColor disabledControlTextColor];
656}
657
658- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
659{
660  return NSDragOperationNone;
661}
662
663@end
664
665
666@implementation GWViewerIconsPath (IconNameEditing)
667
668- (void)updateNameEditor
669{
670  [self stopRepNameEditing];
671
672  editIcon = [self lastIcon];
673
674  if (editIcon && NSContainsRect([editIcon visibleRect], [editIcon iconBounds])) {
675    FSNode *ednode = [editIcon node];
676    NSString *nodeDescr = [editIcon shownInfo];
677    NSRect icnr = [editIcon frame];
678    CGFloat centerx = icnr.origin.x + (icnr.size.width / 2);
679    NSRect labr = [editIcon labelRect];
680    int margin = [fsnodeRep labelMargin];
681    CGFloat bw = [self bounds].size.width - EDIT_MARGIN;
682    CGFloat edwidth = 0.0;
683    NSRect edrect;
684
685    [editIcon setNameEdited: YES];
686
687    edwidth = [[nameEditor font] widthOfString: nodeDescr];
688    edwidth += margin;
689
690    if ((centerx + (edwidth / 2)) >= bw) {
691      centerx -= (centerx + (edwidth / 2) - bw);
692    } else if ((centerx - (edwidth / 2)) < margin) {
693      centerx += fabs(centerx - (edwidth / 2)) + margin;
694    }
695
696    edrect = [self convertRect: labr fromView: editIcon];
697    edrect.origin.x = centerx - (edwidth / 2);
698    edrect.size.width = edwidth;
699    edrect = NSIntegralRect(edrect);
700
701    [nameEditor setFrame: edrect];
702    [nameEditor setAlignment: NSCenterTextAlignment];
703
704    [nameEditor setNode: ednode
705            stringValue: nodeDescr
706                  index: 0];
707
708    [nameEditor setBackgroundColor: [NSColor selectedControlColor]];
709
710    [nameEditor setEditable: NO];
711    [nameEditor setSelectable: NO];
712    [self addSubview: nameEditor];
713  }
714}
715
716- (void)setNameEditorForRep:(id)arep
717{
718  [self updateNameEditor];
719}
720
721- (void)stopRepNameEditing
722{
723  int i;
724
725  if ([[self subviews] containsObject: nameEditor]) {
726    NSRect edrect = [nameEditor frame];
727    [nameEditor abortEditing];
728    [nameEditor setEditable: NO];
729    [nameEditor setSelectable: NO];
730    [nameEditor setNode: nil stringValue: @"" index: -1];
731    [nameEditor removeFromSuperview];
732    [self setNeedsDisplayInRect: edrect];
733  }
734
735  for (i = 0; i < [icons count]; i++) {
736    [[icons objectAtIndex: i] setNameEdited: NO];
737  }
738
739  editIcon = nil;
740}
741
742- (BOOL)canStartRepNameEditing
743{
744  return (editIcon && ([editIcon isLocked] == NO)
745                && ([editIcon isShowingSelection] == NO)
746                && ([[editIcon node] isMountPoint] == NO)
747                && (infoType == FSNInfoNameType));
748}
749
750- (void)controlTextDidChange:(NSNotification *)aNotification
751{
752  NSRect icnr = [editIcon frame];
753  float centerx = icnr.origin.x + (icnr.size.width / 2);
754  float edwidth = [[nameEditor font] widthOfString: [nameEditor stringValue]];
755  int margin = [fsnodeRep labelMargin];
756  float bw = [self bounds].size.width - EDIT_MARGIN;
757  NSRect edrect = [nameEditor frame];
758
759  edwidth += margin;
760
761  while ((centerx + (edwidth / 2)) > bw) {
762    centerx --;
763    if (centerx < EDIT_MARGIN) {
764      break;
765    }
766  }
767
768  while ((centerx - (edwidth / 2)) < EDIT_MARGIN) {
769    centerx ++;
770    if (centerx >= bw) {
771      break;
772    }
773  }
774
775  edrect.origin.x = centerx - (edwidth / 2);
776  edrect.size.width = edwidth;
777
778  [self setNeedsDisplayInRect: [nameEditor frame]];
779  [nameEditor setFrame: NSIntegralRect(edrect)];
780}
781
782- (void)controlTextDidEndEditing:(NSNotification *)aNotification
783{
784  FSNode *ednode = [nameEditor node];
785
786  if ([ednode isParentWritable] == NO)
787    {
788      showAlertNoPermission([FSNode class], [ednode parentName]);
789      [self updateNameEditor];
790      return;
791    }
792  if ([ednode isSubnodeOfPath: [[GWorkspace gworkspace] trashPath]])
793    {
794      showAlertInRecycler([FSNode class]);
795      [self updateNameEditor];
796      return;
797    }
798  else
799    {
800      NSString *newname = [nameEditor stringValue];
801      NSString *newpath = [[ednode parentPath] stringByAppendingPathComponent: newname];
802      NSString *extension = [newpath pathExtension];
803      NSCharacterSet *notAllowSet = [NSCharacterSet characterSetWithCharactersInString: @"/\\*:?\33"];
804      NSRange range = [newname rangeOfCharacterFromSet: notAllowSet];
805      NSArray *dirContents = [ednode subNodeNamesOfParent];
806      NSMutableDictionary *opinfo = [NSMutableDictionary dictionary];
807
808      if (([newname length] == 0) || (range.length > 0))
809        {
810	  showAlertInvalidName([FSNode class]);
811	  [self updateNameEditor];
812          return;
813        }
814
815      if (([extension length]
816           && ([ednode isDirectory] && ([ednode isPackage] == NO))))
817        {
818          if (showAlertExtensionChange([FSNode class], extension) == NSAlertDefaultReturn)
819            {
820	      [self updateNameEditor];
821	      return;
822	    }
823        }
824
825      if ([dirContents containsObject: newname])
826        {
827          if ([newname isEqual: [ednode name]])
828            {
829              [self updateNameEditor];
830              return;
831            }
832          else
833            {
834              showAlertNameInUse([FSNode class], newname);
835              [self updateNameEditor];
836              return;
837            }
838        }
839
840      [opinfo setObject: @"GWorkspaceRenameOperation" forKey: @"operation"];
841      [opinfo setObject: [ednode path] forKey: @"source"];
842      [opinfo setObject: newpath forKey: @"destination"];
843      [opinfo setObject: [NSArray arrayWithObject: @""] forKey: @"files"];
844
845      [self stopRepNameEditing];
846      [[GWorkspace gworkspace] performFileOperation: opinfo];
847    }
848}
849
850@end
851
852
853@implementation GWViewerPathsScroll
854
855- (void)setDelegate:(id)anObject
856{
857  delegate = anObject;
858}
859
860- (id)delegate
861{
862  return delegate;
863}
864
865- (void)reflectScrolledClipView:(NSClipView *)aClipView
866{
867  [super reflectScrolledClipView: aClipView];
868
869  if (delegate) {
870    NSScroller *scroller = [self horizontalScroller];
871    NSScrollerPart hitPart = [scroller hitPart];
872
873    [delegate gwviewerPathsScroll: self
874               scrollViewScrolled: aClipView
875                          hitPart: hitPart];
876  }
877}
878
879@end
880
881
882
883
884
885
886
887
888
889
890
891
892
893