1/* HiddenFilesPref.m
2 *
3 * Copyright (C) 2003-2016 Free Software Foundation, Inc.
4 *
5 * Author: Enrico Sersale <enrico@imago.ro>
6 * Date: August 2001
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
26#import <Foundation/Foundation.h>
27#import <AppKit/AppKit.h>
28#import <GNUstepBase/GNUstep.h>
29
30#import "FSNodeRep.h"
31#import "FSNFunctions.h"
32#import "HiddenFilesPref.h"
33#import "GWorkspace.h"
34
35
36static NSString *nibName = @"HiddenFilesPref";
37
38#define ICON_SIZE 48
39#define LINEH 20
40
41#define CHECKSIZE(sz) \
42if (sz.width < 0) sz.width = 0; \
43if (sz.height < 0) sz.height = 0
44
45@implementation HiddenFilesPref
46
47- (void)dealloc
48{
49  [[NSNotificationCenter defaultCenter] removeObserver: self];
50  RELEASE (prefbox);
51  RELEASE (currentNode);
52  RELEASE (hiddenPaths);
53  RELEASE (leftMatrix);
54  RELEASE (rightMatrix);
55  RELEASE (dirsMatrix);
56  RELEASE (cellPrototipe);
57  [super dealloc];
58}
59
60- (id)init
61{
62  self = [super init];
63
64  if (self) {
65		if ([NSBundle loadNibNamed: nibName owner: self] == NO) {
66      NSLog(@"failed to load %@!", nibName);
67    } else {
68      NSArray *hpaths;
69      NSArray *selection;
70      FSNode *node;
71      NSImage *icon;
72
73      RETAIN (prefbox);
74      RELEASE (win);
75
76      gw = [GWorkspace gworkspace];
77		  fm = [NSFileManager defaultManager];
78      ws = [NSWorkspace sharedWorkspace];
79
80      selection = [gw selectedPaths];
81      node = [FSNode nodeWithPath: [selection objectAtIndex: 0]];
82
83      if ([selection count] > 1) {
84        node = [FSNode nodeWithPath: [node parentPath]];
85      } else {
86        if ([node isDirectory] == NO) {
87          node = [FSNode nodeWithPath: [node parentPath]];
88        } else if ([node isPackage]) {
89          node = [FSNode nodeWithPath: [node parentPath]];
90        }
91      }
92
93      ASSIGN (currentNode, node);
94
95      icon = [[FSNodeRep sharedInstance] iconOfSize: ICON_SIZE
96                                            forNode: currentNode];
97      [iconView setImage: icon];
98
99      cellPrototipe = [NSBrowserCell new];
100
101      [leftScroll setBorderType: NSBezelBorder];
102		  [leftScroll setHasHorizontalScroller: NO];
103  	  [leftScroll setHasVerticalScroller: YES];
104
105		  [rightScroll setBorderType: NSBezelBorder];
106      [rightScroll setHasHorizontalScroller: NO];
107  	  [rightScroll setHasVerticalScroller: YES];
108
109      leftMatrix = nil;
110      rightMatrix = nil;
111
112		  [addButt setImage: [NSImage imageNamed: @"common_ArrowLeftH.tiff"]];
113		  [removeButt setImage: [NSImage imageNamed: @"common_ArrowRightH.tiff"]];
114
115		  [setButt setEnabled: NO];
116
117      [[NSNotificationCenter defaultCenter] addObserver: self
118                					  selector: @selector(selectionChanged:)
119                						    name: @"GWCurrentSelectionChangedNotification"
120                					    object: nil];
121
122      [hiddenDirsScroll setBorderType: NSBezelBorder];
123		  [hiddenDirsScroll setHasHorizontalScroller: NO];
124  	  [hiddenDirsScroll setHasVerticalScroller: YES];
125
126      hiddenPaths = [NSMutableArray new];
127      hpaths = [[FSNodeRep sharedInstance] hiddenPaths];
128
129      if ([hpaths count]) {
130        NSSize cs, ms;
131        NSUInteger i;
132
133        [hiddenPaths addObjectsFromArray: hpaths];
134
135        dirsMatrix = [[NSMatrix alloc] initWithFrame: NSMakeRect(0, 0, 100, 100)
136				            			        mode: NSListModeMatrix prototype: cellPrototipe
137			       											              numberOfRows: 0 numberOfColumns: 0];
138        [dirsMatrix setIntercellSpacing: NSZeroSize];
139        [dirsMatrix setCellSize: NSMakeSize(130, LINEH)];
140        [dirsMatrix setAutoscroll: YES];
141	      [dirsMatrix setAllowsEmptySelection: YES];
142        cs = [hiddenDirsScroll contentSize];
143        ms = [dirsMatrix cellSize];
144        ms.width = cs.width;
145        CHECKSIZE (ms);
146        [dirsMatrix setCellSize: ms];
147	      [hiddenDirsScroll setDocumentView: dirsMatrix];
148
149        [dirsMatrix addColumn];
150        for (i = 0; i < [hiddenPaths count]; ++i) {
151          id cell;
152
153          if (i != 0) {
154		        [dirsMatrix insertRow: i];
155          }
156          cell = [dirsMatrix cellAtRow: i column: 0];
157          [cell setStringValue: [hiddenPaths objectAtIndex: i]];
158          [cell setLeaf: YES];
159        }
160        [dirsMatrix sizeToCells];
161      } else {
162        dirsMatrix = nil;
163      }
164
165      [setDirButt setEnabled: NO];
166
167      /* Internationalization */
168      {
169        NSInteger tabindex;
170        NSTabViewItem *item;
171
172        tabindex = [tabView indexOfTabViewItemWithIdentifier: @"Files"];
173        item = [tabView tabViewItemAtIndex: tabindex];
174        [item setLabel: NSLocalizedString(@"Files", @"")];
175
176        tabindex = [tabView indexOfTabViewItemWithIdentifier: @"Folders"];
177        item = [tabView tabViewItemAtIndex: tabindex];
178        [item setLabel: NSLocalizedString(@"Folders", @"")];
179
180        [setButt setTitle: NSLocalizedString(@"Activate changes", @"")];
181        [loadButt setTitle: NSLocalizedString(@"Load", @"")];
182        [hiddenlabel setStringValue: NSLocalizedString(@"Hidden files", @"")];
183        [shownlabel setStringValue: NSLocalizedString(@"Shown files", @"")];
184        [labelinfo setStringValue: NSLocalizedString(@"Select and move the files to hide or to show", @"")];
185        [hiddenDirslabel setStringValue: NSLocalizedString(@"Hidden directories", @"")];
186        [addDirButt setTitle: NSLocalizedString(@"Add", @"")];
187        [removeDirButt setTitle: NSLocalizedString(@"Remove", @"")];
188        [setDirButt setTitle: NSLocalizedString(@"Activate changes", @"")];
189      }
190    }
191  }
192
193  return self;
194}
195
196- (NSView *)prefView
197{
198  return prefbox;
199}
200
201- (NSString *)prefName
202{
203  return NSLocalizedString(@"Hidden Files", @"");
204}
205
206- (void)selectionChanged:(NSNotification *)n
207{
208  NSArray *selection;
209  FSNode *node;
210  NSImage *icon;
211
212  selection = [gw selectedPaths];
213  node = [FSNode nodeWithPath: [selection objectAtIndex: 0]];
214
215  if ([selection count] > 1) {
216    node = [FSNode nodeWithPath: [node parentPath]];
217  } else {
218    if ([node isDirectory] == NO) {
219      node = [FSNode nodeWithPath: [node parentPath]];
220    } else if ([node isPackage]) {
221      node = [FSNode nodeWithPath: [node parentPath]];
222    }
223  }
224
225  ASSIGN (currentNode, node);
226
227  icon = [[FSNodeRep sharedInstance] iconOfSize: ICON_SIZE
228                                            forNode: currentNode];
229  [iconView setImage: icon];
230
231  [pathField setStringValue: [currentNode name]];
232
233  [self clearAll];
234
235  [prefbox setNeedsDisplay: YES];
236}
237
238- (void)clearAll
239{
240  NSSize cs, ms;
241
242  if (leftMatrix) {
243    [leftMatrix removeFromSuperview];
244    [leftScroll setDocumentView: nil];
245    DESTROY (leftMatrix);
246  }
247
248  leftMatrix = [[NSMatrix alloc] initWithFrame: NSMakeRect(0, 0, 100, 100)
249				            			    mode: NSListModeMatrix prototype: cellPrototipe
250			       											          numberOfRows: 0 numberOfColumns: 0];
251  [leftMatrix setIntercellSpacing: NSZeroSize];
252  [leftMatrix setCellSize: NSMakeSize(130, LINEH)];
253  [leftMatrix setAutoscroll: YES];
254	[leftMatrix setAllowsEmptySelection: YES];
255  cs = [leftScroll contentSize];
256  ms = [leftMatrix cellSize];
257  ms.width = cs.width;
258  CHECKSIZE (ms);
259  [leftMatrix setCellSize: ms];
260	[leftScroll setDocumentView: leftMatrix];
261
262  if (rightMatrix) {
263    [rightMatrix removeFromSuperview];
264    [rightScroll setDocumentView: nil];
265    DESTROY (rightMatrix);
266  }
267
268  rightMatrix = [[NSMatrix alloc] initWithFrame: NSMakeRect(0, 0, 100, 100)
269				            			    mode: NSListModeMatrix prototype: cellPrototipe
270			       											          numberOfRows: 0 numberOfColumns: 0];
271  [rightMatrix setIntercellSpacing: NSZeroSize];
272  [rightMatrix setCellSize: NSMakeSize(130, LINEH)];
273  [rightMatrix setAutoscroll: YES];
274	[rightMatrix setAllowsEmptySelection: YES];
275  cs = [rightScroll contentSize];
276  ms = [rightMatrix cellSize];
277  ms.width = cs.width;
278  CHECKSIZE (ms);
279  [rightMatrix setCellSize: ms];
280	[rightScroll setDocumentView: rightMatrix];
281
282  [setButt setEnabled: NO];
283}
284
285- (IBAction)loadContents:(id)sender
286{
287  NSArray *subNodes;
288  NSMutableArray *hiddenFiles;
289  BOOL hideSysFiles;
290  NSString *h;
291  NSUInteger i, count;
292
293  [self clearAll];
294
295  subNodes = [currentNode subNodes];
296
297  h = [[currentNode path] stringByAppendingPathComponent: @".hidden"];
298
299  if ([fm fileExistsAtPath: h]) {
300	  h = [NSString stringWithContentsOfFile: h];
301	  hiddenFiles = [[h componentsSeparatedByString: @"\n"] mutableCopy];
302
303    count = [hiddenFiles count];
304    for (i = 0; i < count; i++) {
305      NSString *s = [hiddenFiles objectAtIndex: i];
306
307      if ([s length] == 0) {
308        [hiddenFiles removeObject: s];
309        count--;
310        i--;
311      }
312    }
313
314  } else {
315    hiddenFiles = nil;
316  }
317	hideSysFiles = [[FSNodeRep sharedInstance] hideSysFiles];
318
319	if (hiddenFiles != nil  ||  hideSysFiles) {
320		NSMutableArray *mutableNodes = AUTORELEASE ([subNodes mutableCopy]);
321
322    if (hiddenFiles) {
323      NSUInteger count = [mutableNodes count];
324
325      for (i = 0; i < count; i++) {
326        FSNode *node = [mutableNodes objectAtIndex: i];
327
328        if ([hiddenFiles containsObject: [node name]]) {
329          [mutableNodes removeObject: node];
330          count--;
331          i--;
332        }
333      }
334    }
335
336    if (hideSysFiles) {
337	    int j = [mutableNodes count] - 1;
338
339	    while (j >= 0) {
340				NSString *file = [(FSNode *)[mutableNodes objectAtIndex: j] name];
341
342				if ([file hasPrefix: @"."]) {
343		    	[mutableNodes removeObjectAtIndex: j];
344		  	}
345				j--;
346			}
347	  }
348
349		subNodes = mutableNodes;
350	}
351
352  count = [subNodes count];
353  if (count == 0) {
354    TEST_RELEASE (hiddenFiles);
355		return;
356	}
357
358  [rightMatrix addColumn];
359  for (i = 0; i < count; ++i) {
360    id cell;
361
362    if (i != 0) {
363		  [rightMatrix insertRow: i];
364    }
365    cell = [rightMatrix cellAtRow: i column: 0];
366    [cell setStringValue: [(FSNode *)[subNodes objectAtIndex: i] name]];
367    [cell setLeaf: YES];
368  }
369  [rightMatrix sizeToCells];
370
371  if (hiddenFiles != nil) {
372    count = [hiddenFiles count];
373    if (count == 0) {
374      TEST_RELEASE (hiddenFiles);
375		  return;
376	  }
377
378    [leftMatrix addColumn];
379    for (i = 0; i < count; ++i) {
380      id cell;
381
382      if (i != 0) {
383		    [leftMatrix insertRow: i];
384      }
385      cell = [leftMatrix cellAtRow: i column: 0];
386      [cell setStringValue: [hiddenFiles objectAtIndex: i]];
387      [cell setLeaf: YES];
388    }
389    [leftMatrix sizeToCells];
390  }
391
392  TEST_RELEASE (hiddenFiles);
393}
394
395- (IBAction)moveToHidden:(id)sender
396{
397  NSArray *cells = [rightMatrix selectedCells];
398
399  if (cells) {
400    NSMutableArray *names = [NSMutableArray arrayWithCapacity: 1];
401    NSUInteger i;
402
403    for (i = 0; i < [cells count]; i++) {
404      NSString *name = [[cells objectAtIndex: i] stringValue];
405      [names addObject: name];
406    }
407
408    [self removeCellsWithNames: names inMatrix: rightMatrix];
409    [self addCellsWithNames: names inMatrix: leftMatrix];
410
411    [setButt setEnabled: YES];
412  }
413}
414
415- (IBAction)moveToShown:(id)sender
416{
417  NSArray *cells = [leftMatrix selectedCells];
418
419  if (cells) {
420    NSMutableArray *names = [NSMutableArray arrayWithCapacity: 1];
421    NSUInteger i;
422
423    for (i = 0; i < [cells count]; i++) {
424      NSString *name = [[cells objectAtIndex: i] stringValue];
425      [names addObject: name];
426    }
427
428    [self removeCellsWithNames: names inMatrix: leftMatrix];
429    [self addCellsWithNames: names inMatrix: rightMatrix];
430
431    [setButt setEnabled: YES];
432  }
433}
434
435- (IBAction)activateChanges:(id)sender
436{
437  if ([currentNode isWritable] == NO)
438    {
439      NSString *message = NSLocalizedString(@"You have not write permission\nfor","");
440      message = [message stringByAppendingString: [currentNode name]];
441
442      NSRunAlertPanel(NSLocalizedString(@"Error", @""),
443                      message,
444                      NSLocalizedString(@"Continue", @""),
445                      nil, nil);
446      return;
447    }
448  else {
449    NSString *base = [currentNode path];
450    NSMutableArray *paths = [NSMutableArray array];
451    NSArray *cells = [leftMatrix cells];
452
453    if (cells) {
454      NSMutableArray *names;
455      NSString *hconts;
456      NSString *h;
457      NSUInteger i;
458
459      names = [NSMutableArray arrayWithCapacity: 1];
460      for (i = 0; i < [cells count]; i++) {
461        id cell = [cells objectAtIndex: i];
462        NSString *name = [cell stringValue];
463
464        [names addObject: name];
465        [paths addObject: [base stringByAppendingPathComponent: name]];
466      }
467
468      hconts = [names componentsJoinedByString: @"\n"];
469      h = [[currentNode path] stringByAppendingPathComponent: @".hidden"];
470      [hconts writeToFile: h atomically: YES];
471      [gw hiddenFilesDidChange: paths];
472      [setButt setEnabled: NO];
473    }
474  }
475}
476
477- (IBAction)addDir:(id)sender
478{
479  NSOpenPanel *openPanel;
480  NSString *hidePath;
481  NSInteger result;
482
483  openPanel = [NSOpenPanel openPanel];
484  [openPanel setTitle: _(@"Hide")];
485  [openPanel setAllowsMultipleSelection: NO];
486  [openPanel setCanChooseFiles: NO];
487  [openPanel setCanChooseDirectories: YES];
488
489  result = [openPanel runModalForDirectory: path_separator()
490                                      file: nil
491                                     types: nil];
492  if(result != NSOKButton)
493    return;
494
495  hidePath = [NSString stringWithString: [openPanel filename]];
496
497  if ([hiddenPaths containsObject: hidePath] == NO) {
498    NSSize cs, ms;
499    NSUInteger i;
500
501    [hiddenPaths addObject: hidePath];
502
503    if (dirsMatrix) {
504      [dirsMatrix removeFromSuperview];
505      [hiddenDirsScroll setDocumentView: nil];
506      DESTROY (dirsMatrix);
507    }
508
509    dirsMatrix = [[NSMatrix alloc] initWithFrame: NSMakeRect(0, 0, 100, 100)
510				            			    mode: NSListModeMatrix prototype: cellPrototipe
511			       											          numberOfRows: 0 numberOfColumns: 0];
512    [dirsMatrix setIntercellSpacing: NSZeroSize];
513    [dirsMatrix setCellSize: NSMakeSize(130, LINEH)];
514    [dirsMatrix setAutoscroll: YES];
515    [dirsMatrix setAllowsEmptySelection: YES];
516    cs = [hiddenDirsScroll contentSize];
517    ms = [dirsMatrix cellSize];
518    ms.width = cs.width;
519    CHECKSIZE (ms);
520    [dirsMatrix setCellSize: ms];
521	  [hiddenDirsScroll setDocumentView: dirsMatrix];
522
523    [dirsMatrix addColumn];
524    for (i = 0; i < [hiddenPaths count]; ++i) {
525      id cell;
526
527      if (i != 0) {
528		    [dirsMatrix insertRow: i];
529      }
530      cell = [dirsMatrix cellAtRow: i column: 0];
531      [cell setStringValue: [hiddenPaths objectAtIndex: i]];
532      [cell setLeaf: YES];
533    }
534    [dirsMatrix sizeToCells];
535
536    [setDirButt setEnabled: YES];
537  }
538}
539
540- (IBAction)removeDir:(id)sender
541{
542  NSArray *cells = [dirsMatrix selectedCells];
543
544  if (cells) {
545    NSMutableArray *paths = [NSMutableArray arrayWithCapacity: 1];
546    NSUInteger i;
547
548    for (i = 0; i < [cells count]; i++) {
549      NSString *path = [[cells objectAtIndex: i] stringValue];
550      [hiddenPaths removeObject: path];
551      [paths addObject: path];
552    }
553
554    [self removeCellsWithNames: paths inMatrix: dirsMatrix];
555    [setDirButt setEnabled: YES];
556  }
557}
558
559- (IBAction)activateDirChanges:(id)sender
560{
561  [[FSNodeRep sharedInstance] setHiddenPaths: hiddenPaths];
562  [gw hiddenFilesDidChange: hiddenPaths];
563  [setDirButt setEnabled: NO];
564}
565
566- (void)addCellsWithNames:(NSArray *)names inMatrix:(NSMatrix *)matrix
567{
568  id cell;
569  NSSize cs, ms;
570  NSUInteger i;
571
572  [matrix setIntercellSpacing: NSMakeSize(0, 0)];
573
574  for (i = 0; i < [names count]; i++) {
575    [matrix addRow];
576    cell = [matrix cellAtRow: [[matrix cells] count] -1 column: 0];
577    [cell setStringValue: [names objectAtIndex: i]];
578		[cell setLeaf: YES];
579  }
580
581  if (matrix == leftMatrix) {
582    cs = [leftScroll contentSize];
583  } else {
584    cs = [rightScroll contentSize];
585  }
586  ms = [matrix cellSize];
587  ms.width = cs.width;
588  CHECKSIZE (ms);
589  [matrix setCellSize: ms];
590  [matrix sizeToCells];
591
592  [self selectCellsWithNames: names inMatrix: matrix];
593
594  [matrix setNeedsDisplay: YES];
595}
596
597- (void)removeCellsWithNames:(NSArray *)names inMatrix:(NSMatrix *)matrix
598{
599  id cell;
600  NSUInteger i;
601
602  for (i = 0; i < [names count]; i++) {
603    cell = [self cellWithTitle: [names objectAtIndex: i] inMatrix: matrix];
604
605    if (cell != nil) {
606      NSInteger row, col;
607
608      [matrix getRow: &row column: &col ofCell: cell];
609      [matrix removeRow: row];
610    }
611  }
612
613  [matrix sizeToCells];
614  [matrix setNeedsDisplay: YES];
615}
616
617- (void)selectCellsWithNames:(NSArray *)names inMatrix:(NSMatrix *)matrix
618{
619  NSUInteger i, count;
620  NSInteger max;
621  NSInteger *selectedIndexes = NULL;
622  NSMutableArray *cells;
623
624  cells = [NSMutableArray arrayWithCapacity: 1];
625  for (i = 0; i < [names count]; i++) {
626    NSString *name = [names objectAtIndex: i];
627    id cell = [self cellWithTitle: name inMatrix: matrix];
628
629    if (cell) {
630      [cells addObject: cell];
631    }
632  }
633
634  count = [cells count];
635  max = [matrix numberOfRows];
636  selectedIndexes = NSZoneMalloc(NSDefaultMallocZone(), sizeof(NSInteger) * count);
637
638  for (i = 0; i < count; i++) {
639    NSCell *cell;
640    NSInteger sRow, sColumn;
641
642    cell = [cells objectAtIndex: i];
643    [matrix getRow: &sRow column: &sColumn ofCell: cell];
644    selectedIndexes[i] = sRow;
645  }
646
647  for (i = 0; i < count; i++) {
648    if (selectedIndexes[i] > max) {
649      break;
650    }
651    [matrix selectCellAtRow: selectedIndexes[i] column: 0];
652  }
653
654  NSZoneFree(NSDefaultMallocZone(), selectedIndexes);
655}
656
657- (id)cellWithTitle:(NSString *)title inMatrix:(NSMatrix *)matrix
658{
659  NSArray *cells;
660  id cell;
661  NSUInteger i;
662
663  cells = [matrix cells];
664  if (cells) {
665    for (i = 0; i < [cells count]; i++) {
666      cell = [cells objectAtIndex: i];
667      if ([[cell stringValue] isEqualToString: title]) {
668        return cell;
669      }
670    }
671  }
672
673  return nil;
674}
675
676@end
677