1 |
/* Browser2.m |
2 |
* |
3 |
* Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
23 |
*/ |
24 |
|
25 |
#include <Foundation/Foundation.h> |
26 |
#include <AppKit/AppKit.h> |
27 |
#include "GWProtocol.h" |
28 |
#include "GWFunctions.h" |
29 |
#include "GWNotifications.h" |
30 |
#include <math.h> |
31 |
#include "Browser2.h" |
32 |
#include "BColumn.h" |
33 |
#include "BCell.h" |
34 |
#include "BIcon.h" |
35 |
#include "BNameEditor.h" |
36 |
#include "GNUstep.h" |
37 |
|
38 |
#define NSBR_VOFFSET 4 |
39 |
#define BEZEL_BORDER_SIZE NSMakeSize(2, 2) |
40 |
#define ICON_FRAME_HEIGHT 52 |
41 |
#define ICON_SIZE_WIDTH 48 |
42 |
#define ICON_VOFFSET 14 |
43 |
#define LINE_SCROLL 10 |
44 |
#define LABEL_HEIGHT 14 |
45 |
#define LABEL_MARGIN 8 |
46 |
#define EDIT_MARGIN 4 |
47 |
|
48 |
#define CHECKRECT(rct) \ |
49 |
if (rct.size.width < 0) rct.size.width = 0; \ |
50 |
if (rct.size.height < 0) rct.size.height = 0 |
51 |
|
52 |
#define CHECKSIZE(sz) \ |
53 |
if (sz.width < 0) sz.width = 0; \ |
54 |
if (sz.height < 0) sz.height = 0 |
55 |
|
56 |
#ifndef max |
57 |
#define max(a,b) ((a) >= (b) ? (a):(b)) |
58 |
#endif |
59 |
|
60 |
#ifndef min |
61 |
#define min(a,b) ((a) <= (b) ? (a):(b)) |
62 |
#endif |
63 |
|
64 |
double myrintf(double a) |
65 |
{ |
66 |
return (floor(a + 0.5)); |
67 |
} |
68 |
|
69 |
@implementation Browser2 |
70 |
|
71 |
- (void)dealloc |
72 |
{ |
73 |
RELEASE (columns); |
74 |
if (colRects != NULL) { |
75 |
NSZoneFree (NSDefaultMallocZone(), colRects); |
76 |
} |
77 |
RELEASE (cellPrototype); |
78 |
RELEASE (scroller); |
79 |
RELEASE (pathSeparator); |
80 |
RELEASE (basePath); |
81 |
RELEASE (nameEditor); |
82 |
RELEASE (editorFont); |
83 |
TEST_RELEASE (doubleClickSelection); |
84 |
TEST_RELEASE (charBuffer); |
85 |
TEST_RELEASE (waitCursor); |
86 |
[super dealloc]; |
87 |
} |
88 |
|
89 |
- (id)initWithBasePath:(NSString *)bpath |
90 |
visibleColumns:(int)vcols |
91 |
styleMask:(int)mask |
92 |
delegate:(id)anobject |
93 |
remoteHost:(NSString *)rhost |
94 |
{ |
95 |
self = [super init]; |
96 |
|
97 |
if (self) { |
98 |
#ifdef GNUSTEP |
99 |
Class gwclass = [[NSBundle mainBundle] principalClass]; |
100 |
#else |
101 |
Class gwclass = [[NSBundle mainBundle] classNamed: @"GWorkspace"]; |
102 |
#endif |
103 |
NSRect rect = NSMakeRect(0, 0, 600, 200); |
104 |
NSSize bs = BEZEL_BORDER_SIZE; |
105 |
int i; |
106 |
|
107 |
createEmptySel = @selector(createEmptyColumn); |
108 |
createEmpty = [self methodForSelector: createEmptySel]; |
109 |
|
110 |
addAndLoadSel = @selector(addAndLoadColumnForPaths:); |
111 |
addAndLoad = [self methodForSelector: addAndLoadSel]; |
112 |
|
113 |
unloadFromSel = @selector(unloadFromColumn:); |
114 |
unloadFrom = [self methodForSelector: unloadFromSel]; |
115 |
|
116 |
lastColumnSel = @selector(setLastColumn:); |
117 |
lastColumn = [self methodForSelector: lastColumnSel]; |
118 |
|
119 |
setPathsSel = @selector(setCurrentPaths:); |
120 |
setPaths = [[BColumn class] instanceMethodForSelector: setPathsSel]; |
121 |
|
122 |
gworkspace = (id<GWProtocol>)[gwclass gworkspace]; |
123 |
|
124 |
if (rhost) { |
125 |
isRemote = YES; |
126 |
ASSIGN (remoteHostName, rhost); |
127 |
waitCursor = [[NSCursor alloc] initWithImage: [NSImage imageNamed: @"watch.tiff"]]; |
128 |
[waitCursor setHotSpot: NSMakePoint(8, 8)]; |
129 |
[NSCursor setHiddenUntilMouseMoves: NO]; |
130 |
} else { |
131 |
isRemote = NO; |
132 |
remoteHostName = nil; |
133 |
} |
134 |
|
135 |
[self setFrame: rect]; |
136 |
visibleColumns = vcols; |
137 |
ASSIGN (basePath, bpath); |
138 |
delegate = anobject; |
139 |
styleMask = mask; |
140 |
canUpdateViews = YES; |
141 |
|
142 |
colRects = NULL; |
143 |
columnWidth = (rect.size.width / (float)visibleColumns); |
144 |
scrollerWidth = [NSScroller scrollerWidth]; |
145 |
iconsPathWidth = 96 - scrollerWidth; |
146 |
if (styleMask & GWColumnIconMask) { |
147 |
columnOriginY = 0; |
148 |
} else { |
149 |
columnOriginY = scrollerWidth + (4 * bs.height); |
150 |
} |
151 |
|
152 |
ASSIGN (pathSeparator, fixPath(@"/", 0)); |
153 |
|
154 |
if (styleMask & GWIconCellsMask) { |
155 |
cellPrototype = [[BCell alloc] initIconCell]; |
156 |
} else { |
157 |
cellPrototype = [[BCell alloc] init]; |
158 |
} |
159 |
|
160 |
columns = [[NSMutableArray alloc] init]; |
161 |
getSel = @selector(objectAtIndex:); |
162 |
getImp = [columns methodForSelector: getSel]; |
163 |
indexSel = @selector(indexOfObject:); |
164 |
indexImp = (intIMP)[columns methodForSelector: indexSel]; |
165 |
|
166 |
scrollerRect.origin.x = bs.width; |
167 |
if (styleMask & GWColumnIconMask) { |
168 |
scrollerRect.origin.y = [self frame].size.height - iconsPathWidth - scrollerWidth; |
169 |
} else { |
170 |
scrollerRect.origin.y = bs.height; |
171 |
} |
172 |
scrollerRect.size.width = [self frame].size.width - (2 * bs.width); |
173 |
scrollerRect.size.height = scrollerWidth; |
174 |
scroller = [[NSScroller alloc] initWithFrame: scrollerRect]; |
175 |
[scroller setTarget: self]; |
176 |
[scroller setAction: @selector(scrollViaScroller:)]; |
177 |
[self addSubview: scroller]; |
178 |
|
179 |
rect = [self frame]; |
180 |
|
181 |
for (i = 0; i < visibleColumns; i++) { |
182 |
(*createEmpty)(self, createEmptySel); |
183 |
} |
184 |
|
185 |
nameEditor = [[BNameEditor alloc] init]; |
186 |
[nameEditor setDelegate: self]; |
187 |
[nameEditor setTarget: self]; |
188 |
[nameEditor setAction: @selector(editorAction:)]; |
189 |
ASSIGN (editorFont, [NSFont systemFontOfSize: 12]); |
190 |
[nameEditor setFont: editorFont]; |
191 |
[nameEditor setBezeled: NO]; |
192 |
[nameEditor setAlignment: NSCenterTextAlignment]; |
193 |
[nameEditor setBackgroundColor: [NSColor whiteColor]]; |
194 |
edCol = nil; |
195 |
isEditingIconName = NO; |
196 |
|
197 |
firstVisibleColumn = 0; |
198 |
lastVisibleColumn = visibleColumns - 1; |
199 |
currentshift = 0; |
200 |
lastColumnLoaded = -1; |
201 |
alphaNumericalLastColumn = -1; |
202 |
|
203 |
skipUpdateScroller = NO; |
204 |
lastKeyPressed = 0.; |
205 |
charBuffer = nil; |
206 |
doubleClickSelection = nil; |
207 |
simulatingDoubleClick = NO; |
208 |
isLoaded = NO; |
209 |
} |
210 |
|
211 |
return self; |
212 |
} |
213 |
|
214 |
- (void)setPathAndSelection:(NSArray *)selection |
215 |
{ |
216 |
NSString *path; |
217 |
NSArray *subStrings; |
218 |
NSString *aStr; |
219 |
NSString *progrPath; |
220 |
unsigned numberOfSubStrings; |
221 |
unsigned i; |
222 |
int column; |
223 |
BColumn *selCol; |
224 |
|
225 |
canUpdateViews = NO; |
226 |
|
227 |
[self loadColumnZero]; |
228 |
|
229 |
if (selection == nil || [[selection objectAtIndex: 0] isEqual: basePath]) { |
230 |
canUpdateViews = YES; |
231 |
[self tile]; |
232 |
[self setNeedsDisplay: YES]; |
233 |
if (isRemote) { |
234 |
[[NSCursor arrowCursor] set]; |
235 |
} |
236 |
return; |
237 |
} |
238 |
|
239 |
if ([selection count] > 1) { |
240 |
path = [[selection objectAtIndex: 0] stringByDeletingLastPathComponent]; |
241 |
} else { |
242 |
path = [selection objectAtIndex: 0]; |
243 |
} |
244 |
|
245 |
if ([basePath isEqualToString: pathSeparator] == NO) { |
246 |
NSRange range = [path rangeOfString: basePath]; |
247 |
|
248 |
if (range.length == 0) { |
249 |
ASSIGN (basePath, pathSeparator); |
250 |
[self loadColumnZero]; |
251 |
subStrings = [path componentsSeparatedByString: pathSeparator]; |
252 |
|
253 |
} else { |
254 |
NSString *rpath = [path substringFromIndex: [basePath cStringLength]]; |
255 |
subStrings = [rpath componentsSeparatedByString: pathSeparator]; |
256 |
} |
257 |
|
258 |
} else { |
259 |
subStrings = [path componentsSeparatedByString: pathSeparator]; |
260 |
} |
261 |
|
262 |
numberOfSubStrings = [subStrings count]; |
263 |
|
264 |
// Ignore a trailing void component. |
265 |
if (numberOfSubStrings > 0 |
266 |
&& [[subStrings objectAtIndex: 0] isEqualToString: @""]) { |
267 |
numberOfSubStrings--; |
268 |
|
269 |
if (numberOfSubStrings) { |
270 |
NSRange theRange; |
271 |
|
272 |
theRange.location = 1; |
273 |
theRange.length = numberOfSubStrings; |
274 |
subStrings = [subStrings subarrayWithRange: theRange]; |
275 |
} |
276 |
|
277 |
[self loadColumnZero]; |
278 |
} |
279 |
|
280 |
column = lastColumnLoaded; |
281 |
if (column < 0) { |
282 |
column = 0; |
283 |
} |
284 |
|
285 |
progrPath = [NSString stringWithString: basePath]; |
286 |
|
287 |
for (i = 0; i < numberOfSubStrings; i++) { |
288 |
BColumn *bc = (*getImp)(columns, getSel, column + i); |
289 |
|
290 |
aStr = [subStrings objectAtIndex: i]; |
291 |
|
292 |
if ([aStr isEqualToString: @""] == NO) { |
293 |
BOOL found = NO; |
294 |
|
295 |
progrPath = [progrPath stringByAppendingPathComponent: aStr]; |
296 |
|
297 |
found = [bc selectMatrixCellsWithNames: [NSArray arrayWithObject: aStr] |
298 |
sendAction: NO]; |
299 |
|
300 |
if (found == NO) { |
301 |
NSLog(@"Browser: unable to find cell '%@' in column %d\n", aStr, column + i); |
302 |
break; |
303 |
} |
304 |
|
305 |
(*addAndLoad)(self, addAndLoadSel, [NSArray arrayWithObject: progrPath]); |
306 |
} |
307 |
} |
308 |
|
309 |
if ([selection count] > 1) { |
310 |
BColumn *bc = (*getImp)(columns, getSel, lastColumnLoaded); |
311 |
|
312 |
NSMutableArray *names = [NSMutableArray arrayWithCapacity: 1]; |
313 |
int i = 0; |
314 |
|
315 |
for (i = 0; i < [selection count]; i++) { |
316 |
[names addObject: [[selection objectAtIndex: i] lastPathComponent]]; |
317 |
} |
318 |
|
319 |
[bc selectMatrixCellsWithNames: names sendAction: NO]; |
320 |
|
321 |
(*addAndLoad)(self, addAndLoadSel, selection); |
322 |
} |
323 |
|
324 |
canUpdateViews = YES; |
325 |
[self tile]; |
326 |
[self setNeedsDisplay: YES]; |
327 |
|
328 |
selCol = [self selectedColumn]; |
329 |
if (selCol) { |
330 |
NSMatrix *matrix = [selCol cmatrix]; |
331 |
|
332 |
if (matrix) { |
333 |
[[self window] makeFirstResponder: matrix]; |
334 |
} |
335 |
} |
336 |
|
337 |
if (isRemote) { |
338 |
[[NSCursor arrowCursor] set]; |
339 |
} |
340 |
} |
341 |
|
342 |
- (void)loadColumnZero |
343 |
{ |
344 |
(*lastColumn)(self, lastColumnSel, -1); |
345 |
(*addAndLoad)(self, addAndLoadSel, [NSArray arrayWithObject: basePath]); |
346 |
isLoaded = YES; |
347 |
[self tile]; |
348 |
} |
349 |
|
350 |
- (BColumn *)createEmptyColumn |
351 |
{ |
352 |
unsigned int style = (styleMask & GWColumnIconMask) |
353 |
| (styleMask & GWIconCellsMask) |
354 |
| (styleMask & GWViewsPaksgesMask); |
355 |
|
356 |
BColumn *bc = [[BColumn alloc] initInBrowser: self |
357 |
atIndex: [columns count] |
358 |
cellPrototype: cellPrototype |
359 |
styleMask: style |
360 |
remoteHost: remoteHostName]; |
361 |
[columns addObject: bc]; |
362 |
[self addSubview: bc]; |
363 |
if (styleMask & GWColumnIconMask) { |
364 |
[self addSubview: [bc iconView]]; |
365 |
} |
366 |
RELEASE(bc); |
367 |
|
368 |
return bc; |
369 |
} |
370 |
|
371 |
- (void)addAndLoadColumnForPaths:(NSArray *)cpaths |
372 |
{ |
373 |
BColumn *bc; |
374 |
int i; |
375 |
|
376 |
if (lastColumnLoaded + 1 >= [columns count]) { |
377 |
i = (*indexImp)(columns, indexSel, (*createEmpty)(self, createEmptySel)); |
378 |
} else { |
379 |
i = lastColumnLoaded + 1; |
380 |
} |
381 |
|
382 |
bc = (*getImp)(columns, getSel, i); |
383 |
(*setPaths)(bc, setPathsSel, cpaths); |
384 |
(*lastColumn)(self, lastColumnSel, i); |
385 |
|
386 |
isLoaded = YES; |
387 |
|
388 |
[self tile]; |
389 |
|
390 |
if ((i > 0) && ((i - 1) == lastVisibleColumn)) { |
391 |
[self scrollColumnsRightBy: 1]; |
392 |
} |
393 |
} |
394 |
|
395 |
- (void)unloadFromColumn:(int)column |
396 |
{ |
397 |
BColumn *bc = nil; |
398 |
int i, count; |
399 |
|
400 |
count = [columns count]; |
401 |
|
402 |
for (i = column; i < count; ++i) { |
403 |
bc = (*getImp)(columns, getSel, i); |
404 |
|
405 |
if ([bc isLoaded]) { |
406 |
[bc setCurrentPaths: nil]; |
407 |
} |
408 |
|
409 |
if (i >= visibleColumns) { |
410 |
[bc removeFromSuperview]; |
411 |
if (styleMask & GWColumnIconMask) { |
412 |
[[bc iconView] removeFromSuperview]; |
413 |
} |
414 |
|
415 |
[columns removeObject: bc]; |
416 |
|
417 |
count--; |
418 |
i--; |
419 |
} |
420 |
} |
421 |
|
422 |
if (column == 0) { |
423 |
isLoaded = NO; |
424 |
} |
425 |
|
426 |
// Scrolls if needed. |
427 |
if (column <= lastVisibleColumn) { |
428 |
[self scrollColumnsLeftBy: lastVisibleColumn - column + 1]; |
429 |
} |
430 |
|
431 |
[self updateScroller]; |
432 |
} |
433 |
|
434 |
- (void)reloadColumnWithPath:(NSString *)cpath |
435 |
{ |
436 |
BColumn *col = [self columnWithPath: cpath]; |
437 |
|
438 |
if (col) { |
439 |
[col setCurrentPaths: [NSArray arrayWithObject: cpath]]; |
440 |
} |
441 |
} |
442 |
|
443 |
- (void)reloadFromColumnWithPath:(NSString *)cpath |
444 |
{ |
445 |
BColumn *col = [self columnWithPath: cpath]; |
446 |
|
447 |
if (col) { |
448 |
int index = [col index]; |
449 |
int i = 0; |
450 |
|
451 |
for (i = index; i < [columns count]; i++) { |
452 |
BColumn *nextcol = (*getImp)(columns, getSel, i); |
453 |
NSArray *selection = [self selectionInColumnBeforeColumn: nextcol]; |
454 |
|
455 |
if (selection) { |
456 |
[nextcol setCurrentPaths: selection]; |
457 |
|
458 |
} else { |
459 |
int last = (i > 0) ? i - 1 : 0; |
460 |
int shift = 0; |
461 |
int leftscr = 0; |
462 |
|
463 |
if (last >= visibleColumns) { |
464 |
if (last < firstVisibleColumn) { |
465 |
shift = visibleColumns - 1; |
466 |
} else if (last > lastVisibleColumn) { |
467 |
leftscr = last - lastVisibleColumn; |
468 |
} else { |
469 |
shift = lastVisibleColumn - last; |
470 |
} |
471 |
} |
472 |
|
473 |
(*lastColumn)(self, lastColumnSel, last); |
474 |
|
475 |
if (shift) { |
476 |
currentshift = 0; |
477 |
[self setShift: shift]; |
478 |
} else if (leftscr) { |
479 |
[self scrollColumnsLeftBy: leftscr]; |
480 |
} |
481 |
|
482 |
break; |
483 |
} |
484 |
} |
485 |
|
486 |
[self tile]; |
487 |
|
488 |
col = [self lastNotEmptyColumn]; |
489 |
|
490 |
if (col) { |
491 |
NSArray *selection = [col selection]; |
492 |
int index = [col index]; |
493 |
|
494 |
if (index < firstVisibleColumn) { |
495 |
[self scrollColumnToVisible: index]; |
496 |
} |
497 |
|
498 |
if (selection) { |
499 |
BColumn *nextcol = (*getImp)(columns, getSel, ([col index] + 1)); |
500 |
|
501 |
if (styleMask & GWColumnIconMask) { |
502 |
[nextcol updateIcon]; |
503 |
[nextcol selectIcon]; |
504 |
} |
505 |
|
506 |
[delegate currentSelectedPaths: selection]; |
507 |
|
508 |
} else { |
509 |
NSString *currpath = [col currentPath]; |
510 |
|
511 |
if (currpath) { |
512 |
[delegate currentSelectedPaths: [NSArray arrayWithObject: currpath]]; |
513 |
|
514 |
if (styleMask & GWColumnIconMask) { |
515 |
[col selectIcon]; |
516 |
} |
517 |
} |
518 |
} |
519 |
} |
520 |
} |
521 |
} |
522 |
|
523 |
- (void)setLastColumn:(int)column |
524 |
{ |
525 |
lastColumnLoaded = column; |
526 |
(*unloadFrom)(self, unloadFromSel, column + 1); |
527 |
} |
528 |
|
529 |
- (void)tile |
530 |
{ |
531 |
NSSize bs = BEZEL_BORDER_SIZE; |
532 |
float frameWidth; |
533 |
NSRect r; |
534 |
int i; |
535 |
|
536 |
if (canUpdateViews == NO) { |
537 |
return; |
538 |
} |
539 |
|
540 |
r = [self frame]; |
541 |
|
542 |
columnSize.height = r.size.height; |
543 |
if (styleMask & GWColumnIconMask) { |
544 |
columnOriginY = 0; |
545 |
} else { |
546 |
columnOriginY = scrollerWidth + (4 * bs.height); |
547 |
} |
548 |
|
549 |
// Horizontal scroller |
550 |
scrollerRect.origin.x = bs.width; |
551 |
if (styleMask & GWColumnIconMask) { |
552 |
scrollerRect.origin.y = r.size.height - iconsPathWidth - scrollerWidth - 1; |
553 |
} else { |
554 |
scrollerRect.origin.y = bs.height; |
555 |
} |
556 |
scrollerRect.size.width = r.size.width - (2 * bs.width); |
557 |
scrollerRect.size.height = scrollerWidth; |
558 |
|
559 |
if (styleMask & GWColumnIconMask) { |
560 |
columnSize.height -= iconsPathWidth + scrollerWidth + (3 * bs.height) + NSBR_VOFFSET; |
561 |
} else { |
562 |
columnSize.height -= scrollerWidth + (3 * bs.height) + NSBR_VOFFSET; |
563 |
} |
564 |
|
565 |
if (!NSEqualRects(scrollerRect, [scroller frame])) { |
566 |
CHECKRECT (scrollerRect); |
567 |
[scroller setFrame: scrollerRect]; |
568 |
} |
569 |
|
570 |
// Columns |
571 |
frameWidth = r.size.width - (4.0 + (float)visibleColumns); |
572 |
columnSize.width = (int)(frameWidth / (float)visibleColumns); |
573 |
CHECKSIZE (columnSize); |
574 |
|
575 |
[self makeColumnsRects]; |
576 |
|
577 |
for (i = 0; i < [columns count]; i++) { |
578 |
BColumn *bc = (*getImp)(columns, getSel, i); |
579 |
|
580 |
if (styleMask & GWColumnIconMask) { |
581 |
[[bc iconView] setFrame: NSMakeRect(colRects[i].origin.x, |
582 |
r.size.height - iconsPathWidth + (2 * bs.width), |
583 |
colRects[i].size.width, iconsPathWidth - (2 * bs.width))]; |
584 |
} |
585 |
|
586 |
[bc setFrame: colRects[i]]; |
587 |
} |
588 |
|
589 |
if (styleMask & GWColumnIconMask) { |
590 |
[self updateNameEditor]; |
591 |
} |
592 |
} |
593 |
|
594 |
- (void)makeColumnsRects |
595 |
{ |
596 |
int count = [columns count]; |
597 |
int i = 0; |
598 |
|
599 |
if (colRects != NULL) { |
600 |
NSZoneFree (NSDefaultMallocZone(), colRects); |
601 |
} |
602 |
colRects = NSZoneMalloc (NSDefaultMallocZone(), sizeof(NSRect) * count); |
603 |
|
604 |
for (i = 0; i < count; i++) { |
605 |
int n = i - firstVisibleColumn; |
606 |
|
607 |
colRects[i] = NSZeroRect; |
608 |
|
609 |
colRects[i].size = columnSize; |
610 |
|
611 |
if (i < firstVisibleColumn) { |
612 |
colRects[i].origin.x = (n * columnSize.width); |
613 |
} else { |
614 |
if (i == firstVisibleColumn) { |
615 |
colRects[i].origin.x = (n * columnSize.width) + 2; |
616 |
} else if (i <= lastVisibleColumn) { |
617 |
colRects[i].origin.x = (n * columnSize.width) + (n + 2); |
618 |
} else { |
619 |
colRects[i].origin.x = (n * columnSize.width) + (n + 8); |
620 |
} |
621 |
} |
622 |
|
623 |
if (i == lastVisibleColumn) { |
624 |
colRects[i].size.width = [self bounds].size.width - (colRects[i].origin.x + 2); |
625 |
} |
626 |
|
627 |
colRects[i].origin.y = columnOriginY; |
628 |
|
629 |
CHECKRECT (colRects[i]); |
630 |
} |
631 |
} |
632 |
|
633 |
- (void)scrollViaScroller:(NSScroller *)sender |
634 |
{ |
635 |
NSScrollerPart hit; |
636 |
|
637 |
if ([sender class] != [NSScroller class]) { |
638 |
return; |
639 |
} |
640 |
|
641 |
hit = [sender hitPart]; |
642 |
|
643 |
switch (hit) { |
644 |
// Scroll to the left |
645 |
case NSScrollerDecrementLine: |
646 |
case NSScrollerDecrementPage: |
647 |
[self scrollColumnsLeftBy: 1]; |
648 |
if (currentshift > 0) { |
649 |
(*lastColumn)(self, lastColumnSel, (lastColumnLoaded - currentshift)); |
650 |
[self setShift: currentshift - 1]; |
651 |
} |
652 |
break; |
653 |
|
654 |
// Scroll to the right |
655 |
case NSScrollerIncrementLine: |
656 |
case NSScrollerIncrementPage: |
657 |
[self scrollColumnsRightBy: 1]; |
658 |
break; |
659 |
|
660 |
// The knob or knob slot |
661 |
case NSScrollerKnob: |
662 |
case NSScrollerKnobSlot: |
663 |
{ |
664 |
float f = [sender floatValue]; |
665 |
float n = lastColumnLoaded + 1 - visibleColumns; |
666 |
|
667 |
skipUpdateScroller = YES; |
668 |
[self scrollColumnToVisible: myrintf(f * n) + visibleColumns - 1]; |
669 |
skipUpdateScroller = NO; |
670 |
|
671 |
(*lastColumn)(self, lastColumnSel, (lastColumnLoaded - currentshift)); |
672 |
currentshift = 0; |
673 |
} |
674 |
break; |
675 |
|
676 |
// NSScrollerNoPart ??? |
677 |
default: |
678 |
break; |
679 |
} |
680 |
} |
681 |
|
682 |
- (void)updateScroller |
683 |
{ |
684 |
if ((lastColumnLoaded == 0) || (lastColumnLoaded <= (visibleColumns - 1))) { |
685 |
[scroller setEnabled: NO]; |
686 |
|
687 |
} else { |
688 |
if (!skipUpdateScroller) { |
689 |
float prop = (float)visibleColumns / (float)(lastColumnLoaded + 1); |
690 |
float i = lastColumnLoaded - visibleColumns + 1; |
691 |
float f = 1 + ((lastVisibleColumn - lastColumnLoaded) / i); |
692 |
[scroller setFloatValue: f knobProportion: prop]; |
693 |
} |
694 |
|
695 |
[scroller setEnabled: YES]; |
696 |
} |
697 |
|
698 |
[scroller setNeedsDisplay: YES]; |
699 |
} |
700 |
|
701 |
- (void)scrollColumnsLeftBy:(int)shiftAmount |
702 |
{ |
703 |
// Cannot shift past the zero column |
704 |
if ((firstVisibleColumn - shiftAmount) < 0) { |
705 |
shiftAmount = firstVisibleColumn; |
706 |
} |
707 |
|
708 |
// No amount to shift then nothing to do |
709 |
if (shiftAmount <= 0) { |
710 |
return; |
711 |
} |
712 |
|
713 |
// Shift |
714 |
firstVisibleColumn = firstVisibleColumn - shiftAmount; |
715 |
lastVisibleColumn = lastVisibleColumn - shiftAmount; |
716 |
|
717 |
// Update the scroller |
718 |
[self updateScroller]; |
719 |
|
720 |
// Update the scrollviews |
721 |
[self tile]; |
722 |
} |
723 |
|
724 |
- (void)scrollColumnsRightBy:(int)shiftAmount |
725 |
{ |
726 |
// Cannot shift past the last loaded column |
727 |
if ((shiftAmount + lastVisibleColumn) > lastColumnLoaded) { |
728 |
shiftAmount = lastColumnLoaded - lastVisibleColumn; |
729 |
} |
730 |
|
731 |
// No amount to shift then nothing to do |
732 |
if (shiftAmount <= 0) { |
733 |
return; |
734 |
} |
735 |
|
736 |
// Shift |
737 |
firstVisibleColumn = firstVisibleColumn + shiftAmount; |
738 |
lastVisibleColumn = lastVisibleColumn + shiftAmount; |
739 |
|
740 |
// Update the scroller |
741 |
[self updateScroller]; |
742 |
|
743 |
// Update the scrollviews |
744 |
[self tile]; |
745 |
} |
746 |
|
747 |
- (void)scrollColumnToVisible:(int)column |
748 |
{ |
749 |
int i; |
750 |
|
751 |
// If its the last visible column then we are there already |
752 |
if (lastVisibleColumn == column) { |
753 |
return; |
754 |
} |
755 |
|
756 |
// If there are not enough columns to scroll with |
757 |
// then the column must be visible |
758 |
if (lastColumnLoaded + 1 <= visibleColumns) { |
759 |
return; |
760 |
} |
761 |
|
762 |
i = lastVisibleColumn - column; |
763 |
if (i > 0) { |
764 |
[self scrollColumnsLeftBy: i]; |
765 |
} else { |
766 |
[self scrollColumnsRightBy: (-i)]; |
767 |
} |
768 |
} |
769 |
|
770 |
- (void)moveLeft:(id)sender |
771 |
{ |
772 |
BColumn *selCol; |
773 |
int index; |
774 |
|
775 |
if (!(selCol = [self selectedColumn])) { |
776 |
return; |
777 |
} |
778 |
|
779 |
index = [selCol index]; |
780 |
|
781 |
if (index > 0) { |
782 |
(*lastColumn)(self, lastColumnSel, index); |
783 |
|
784 |
[selCol setLeaf: YES]; |
785 |
if (styleMask & GWColumnIconMask) { |
786 |
[selCol selectIcon]; |
787 |
} |
788 |
|
789 |
selCol = (*getImp)(columns, getSel, index - 1); |
790 |
[delegate currentSelectedPaths: [selCol selection]]; |
791 |
[[self window] makeFirstResponder: [selCol cmatrix]]; |
792 |
} |
793 |
} |
794 |
|
795 |
- (void)moveRight:(id)sender |
796 |
{ |
797 |
BColumn *selCol = [self selectedColumn]; |
798 |
|
799 |
if (selCol == nil) { |
800 |
selCol = (*getImp)(columns, getSel, 0); |
801 |
|
802 |
if ([selCol selectFirstCell]) { |
803 |
[[self window] makeFirstResponder: [selCol cmatrix]]; |
804 |
} |
805 |
} else { |
806 |
NSMatrix *matrix = [selCol cmatrix]; |
807 |
|
808 |
if (matrix) { |
809 |
int index = [selCol index]; |
810 |
|
811 |
[matrix sendAction]; |
812 |
|
813 |
if (index < ([columns count] - 1)) { |
814 |
selCol = (*getImp)(columns, getSel, index + 1); |
815 |
matrix = [selCol cmatrix]; |
816 |
if (matrix) { |
817 |
if ([selCol selectFirstCell]) { |
818 |
[matrix sendAction]; |
819 |
[[self window] makeFirstResponder: matrix]; |
820 |
} |
821 |
} |
822 |
} |
823 |
} |
824 |
} |
825 |
} |
826 |
|
827 |
- (void)setShift:(int)s |
828 |
{ |
829 |
int i; |
830 |
|
831 |
for (i = 0; i <= s; i++) { |
832 |
(*createEmpty)(self, createEmptySel); |
833 |
} |
834 |
|
835 |
currentshift = s; |
836 |
(*lastColumn)(self, lastColumnSel, (lastColumnLoaded + s)); |
837 |
[self scrollColumnsRightBy: s]; |
838 |
[self tile]; |
839 |
} |
840 |
|
841 |
- (NSString *)pathToLastColumn |
842 |
{ |
843 |
int i; |
844 |
|
845 |
for (i = 0; i < [columns count]; i++) { |
846 |
BColumn *col = (*getImp)(columns, getSel, i); |
847 |
|
848 |
if ([col isLeaf]) { |
849 |
NSString *cpath = [col currentPath]; |
850 |
BOOL is_dir = NO; |
851 |
|
852 |
is_dir = [gworkspace server: remoteHostName |
853 |
existsAndIsDirectoryFileAtPath: cpath]; |
854 |
if (is_dir) { |
855 |
if (([gworkspace server: remoteHostName isPakageAtPath: cpath] == NO) |
856 |
|| (styleMask & GWViewsPaksgesMask)) { |
857 |
return cpath; |
858 |
} else if (i > 0) { |
859 |
return [(*getImp)(columns, getSel, i - 1) currentPath]; |
860 |
} |
861 |
} else if (i > 0) { |
862 |
return [(*getImp)(columns, getSel, i - 1) currentPath]; |
863 |
} |
864 |
} |
865 |
} |
866 |
|
867 |
return nil; |
868 |
} |
869 |
|
870 |
- (BOOL)isShowingPath:(NSString *)path |
871 |
{ |
872 |
return ([self columnWithPath: path] ? YES : NO); |
873 |
} |
874 |
|
875 |
- (BColumn *)selectedColumn |
876 |
{ |
877 |
int i; |
878 |
|
879 |
for (i = lastColumnLoaded; i >= 0; i--) { |
880 |
BColumn *col = (*getImp)(columns, getSel, i); |
881 |
|
882 |
if ([col isSelected]) { |
883 |
return col; |
884 |
} |
885 |
} |
886 |
|
887 |
return nil; |
888 |
} |
889 |
|
890 |
- (NSArray *)selectionInColumn:(int)column |
891 |
{ |
892 |
return [(*getImp)(columns, getSel, column) selection]; |
893 |
} |
894 |
|
895 |
- (NSArray *)selectionInColumnBeforeColumn:(BColumn *)col |
896 |
{ |
897 |
int index = [col index]; |
898 |
|
899 |
if (index == 0) { |
900 |
return [NSArray arrayWithObject: basePath]; |
901 |
} |
902 |
|
903 |
return [(*getImp)(columns, getSel, (index - 1)) selection]; |
904 |
} |
905 |
|
906 |
- (void)selectCellsWithNames:(NSArray *)names |
907 |
inColumnWithPath:(NSString *)cpath |
908 |
sendAction:(BOOL)act |
909 |
{ |
910 |
BColumn *col = [self columnWithPath: cpath]; |
911 |
|
912 |
if (col) { |
913 |
[col selectMatrixCellsWithNames: names sendAction: act]; |
914 |
} |
915 |
} |
916 |
|
917 |
- (void)extendSelectionWithDimmedFiles:(NSArray *)dimmFiles |
918 |
fromColumnWithPath:(NSString *)cpath |
919 |
{ |
920 |
BColumn *col = [self columnWithPath: cpath]; |
921 |
|
922 |
if (col) { |
923 |
NSArray *selection = [col selection]; |
924 |
int i = 0; |
925 |
|
926 |
if (selection) { |
927 |
BOOL contained = NO; |
928 |
|
929 |
for (i = 0; i < [selection count]; i++) { |
930 |
NSString *selFile = [[selection objectAtIndex: i] lastPathComponent]; |
931 |
|
932 |
if ([dimmFiles containsObject: selFile]) { |
933 |
contained = YES; |
934 |
break; |
935 |
} |
936 |
} |
937 |
|
938 |
if (contained) { |
939 |
for (i = [col index] + 1; i < [columns count]; i++) { |
940 |
[(*getImp)(columns, getSel, i) lock]; |
941 |
} |
942 |
} |
943 |
} |
944 |
} |
945 |
} |
946 |
|
947 |
- (void)selectAllInLastColumn |
948 |
{ |
949 |
BColumn *col = [self lastNotEmptyColumn]; |
950 |
|
951 |
if (col) { |
952 |
[col selectAll]; |
953 |
} |
954 |
} |
955 |
|
956 |
- (void)selectForEditingInLastColumn |
957 |
{ |
958 |
// [nameEditor selectText: nil]; |
959 |
} |
960 |
|
961 |
- (void)unselectNameEditor |
962 |
{ |
963 |
[nameEditor setBackgroundColor: [NSColor windowBackgroundColor]]; |
964 |
[self setNeedsDisplayInRect: [nameEditor frame]]; |
965 |
} |
966 |
|
967 |
- (void)restoreSelectionAfterDndOfIcon:(BIcon *)dndicon |
968 |
{ |
969 |
BColumn *col = [self lastLoadedColumn]; |
970 |
|
971 |
if (col && (styleMask & GWColumnIconMask)) { |
972 |
[[col myIcon] select]; |
973 |
} |
974 |
|
975 |
[nameEditor setBackgroundColor: [NSColor whiteColor]]; |
976 |
[self updateNameEditor]; |
977 |
} |
978 |
|
979 |
- (void)renewLastIcon |
980 |
{ |
981 |
BColumn *col = [self lastLoadedColumn]; |
982 |
|
983 |
if (col && (styleMask & GWColumnIconMask)) { |
984 |
BIcon *icon = [col myIcon]; |
985 |
|
986 |
if (icon) { |
987 |
[icon renewIcon]; |
988 |
} |
989 |
} |
990 |
} |
991 |
|
992 |
- (void)addCellsWithNames:(NSArray *)names |
993 |
inColumnWithPath:(NSString *)cpath |
994 |
{ |
995 |
BColumn *col = [self columnWithPath: cpath]; |
996 |
|
997 |
if (col) { |
998 |
[col addMatrixCellsWithNames: names]; |
999 |
} |
1000 |
} |
1001 |
|
1002 |
- (void)addDimmedCellsWithNames:(NSArray *)names |
1003 |
inColumnWithPath:(NSString *)cpath |
1004 |
{ |
1005 |
BColumn *col = [self columnWithPath: cpath]; |
1006 |
|
1007 |
if (col) { |
1008 |
[col addDimmedMatrixCellsWithNames: names]; |
1009 |
} |
1010 |
} |
1011 |
|
1012 |
- (void)removeCellsWithNames:(NSArray *)names |
1013 |
inColumnWithPath:(NSString *)cpath |
1014 |
{ |
1015 |
BColumn *col = [self columnWithPath: cpath]; |
1016 |
|
1017 |
if (col) { |
1018 |
[col removeMatrixCellsWithNames: names]; |
1019 |
} |
1020 |
} |
1021 |
|
1022 |
|
1023 |
- (void)lockCellsWithNames:(NSArray *)names |
1024 |
inColumnWithPath:(NSString *)cpath |
1025 |
{ |
1026 |
BColumn *col = [self columnWithPath: cpath]; |
1027 |
|
1028 |
if (col) { |
1029 |
[col lockCellsWithNames: names]; |
1030 |
} |
1031 |
} |
1032 |
|
1033 |
- (void)unLockCellsWithNames:(NSArray *)names |
1034 |
inColumnWithPath:(NSString *)cpath |
1035 |
mustExtend:(BOOL)extend |
1036 |
{ |
1037 |
BColumn *col = [self columnWithPath: cpath]; |
1038 |
int i = 0; |
1039 |
|
1040 |
if (col) { |
1041 |
[col unLockCellsWithNames: names]; |
1042 |
|
1043 |
if (extend) { |
1044 |
for (i = [col index] + 1; i < [columns count]; i++) { |
1045 |
[(*getImp)(columns, getSel, i) unLock]; |
1046 |
} |
1047 |
} |
1048 |
} |
1049 |
} |
1050 |
|
1051 |
- (int)firstVisibleColumn |
1052 |
{ |
1053 |
return firstVisibleColumn; |
1054 |
} |
1055 |
|
1056 |
- (BColumn *)lastLoadedColumn |
1057 |
{ |
1058 |
int i; |
1059 |
|
1060 |
for (i = [columns count] - 1; i >= 0; i--) { |
1061 |
BColumn *col = (*getImp)(columns, getSel, i); |
1062 |
|
1063 |
if ([col isLoaded] && [col isLeaf]) { |
1064 |
return col; |
1065 |
} |
1066 |
} |
1067 |
|
1068 |
return nil; |
1069 |
} |
1070 |
|
1071 |
- (BColumn *)lastNotEmptyColumn |
1072 |
{ |
1073 |
int i; |
1074 |
|
1075 |
for (i = 0; i < [columns count]; i++) { |
1076 |
BColumn *col = (*getImp)(columns, getSel, i); |
1077 |
|
1078 |
if ([col isLeaf]) { |
1079 |
id matrix = [col cmatrix]; |
1080 |
|
1081 |
if (matrix && [[matrix cells] count]) { |
1082 |
return col; |
1083 |
} else if (i > 0) { |
1084 |
return (*getImp)(columns, getSel, i - 1); |
1085 |
} |
1086 |
} |
1087 |
} |
1088 |
|
1089 |
return nil; |
1090 |
} |
1091 |
|
1092 |
- (BColumn *)columnWithPath:(NSString *)cpath |
1093 |
{ |
1094 |
int i; |
1095 |
|
1096 |
for (i = 0; i < [columns count]; i++) { |
1097 |
BColumn *col = (*getImp)(columns, getSel, i); |
1098 |
|
1099 |
if ([[col currentPath] isEqual: cpath]) { |
1100 |
return col; |
1101 |
} |
1102 |
} |
1103 |
|
1104 |
return nil; |
1105 |
} |
1106 |
|
1107 |
- (BColumn *)columnBeforeColumn:(BColumn *)col |
1108 |
{ |
1109 |
int index = [col index]; |
1110 |
|
1111 |
if (index > 0) { |
1112 |
return (*getImp)(columns, getSel, index - 1); |
1113 |
} |
1114 |
|
1115 |
return nil; |
1116 |
} |
1117 |
|
1118 |
- (BColumn *)columnAfterColumn:(BColumn *)col |
1119 |
{ |
1120 |
int index = [col index]; |
1121 |
|
1122 |
if (index < ([columns count] - 1)) { |
1123 |
return (*getImp)(columns, getSel, index + 1); |
1124 |
} |
1125 |
|
1126 |
return nil; |
1127 |
} |
1128 |
|
1129 |
- (NSArray *)columnsDifferentFromColumn:(BColumn *)col |
1130 |
{ |
1131 |
NSMutableArray *arr = [NSMutableArray arrayWithCapacity: 1]; |
1132 |
int i; |
1133 |
|
1134 |
for (i = 0; i < [columns count]; i++) { |
1135 |
BColumn *bc = (*getImp)(columns, getSel, i); |
1136 |
|
1137 |
if (bc != col) { |
1138 |
[arr addObject: bc]; |
1139 |
} |
1140 |
} |
1141 |
|
1142 |
return arr; |
1143 |
} |
1144 |
|
1145 |
- (NSPoint)positionOfLastIcon |
1146 |
{ |
1147 |
BColumn *col = [self lastLoadedColumn]; |
1148 |
|
1149 |
if (col && (styleMask & GWColumnIconMask)) { |
1150 |
NSRect r = [[col iconView] frame]; |
1151 |
NSSize s = [[col myIcon] iconShift]; |
1152 |
|
1153 |
return NSMakePoint(r.origin.x + s.width, |
1154 |
r.origin.y + s.height + ICON_VOFFSET); |
1155 |
} |
1156 |
|
1157 |
return NSZeroPoint; |
1158 |
} |
1159 |
|
1160 |
- (NSPoint)positionForSlidedImage |
1161 |
{ |
1162 |
if ((lastVisibleColumn < [columns count]) && (styleMask & GWColumnIconMask)) { |
1163 |
BColumn *col = (*getImp)(columns, getSel, lastVisibleColumn); |
1164 |
NSRect r = [[col iconView] frame]; |
1165 |
NSPoint p = [self positionOfLastIcon]; |
1166 |
|
1167 |
return NSMakePoint(r.origin.x + ((r.size.width - ICON_SIZE_WIDTH) / 2), p.y); |
1168 |
} |
1169 |
|
1170 |
return NSZeroPoint; |
1171 |
} |
1172 |
|
1173 |
- (BOOL)viewsapps |
1174 |
{ |
1175 |
return (styleMask & GWViewsPaksgesMask); |
1176 |
} |
1177 |
|
1178 |
- (void)mouseDown:(NSEvent*)theEvent |
1179 |
{ |
1180 |
if (simulatingDoubleClick) { |
1181 |
NSPoint p = [[self window] mouseLocationOutsideOfEventStream]; |
1182 |
|
1183 |
if ((max(p.x, mousePointX) - min(p.x, mousePointX)) <= 3 |
1184 |
&& (max(p.y, mousePointY) - min(p.y, mousePointY)) <= 3) { |
1185 |
[delegate openSelectedPaths: doubleClickSelection newViewer: NO]; |
1186 |
} |
1187 |
} |
1188 |
|
1189 |
[super mouseDown: theEvent]; |
1190 |
} |
1191 |
|
1192 |
- (void)doubleClikTimeOut:(id)sender |
1193 |
{ |
1194 |
simulatingDoubleClick = NO; |
1195 |
} |
1196 |
|
1197 |
- (void)clickInMatrixOfColumn:(BColumn *)col |
1198 |
{ |
1199 |
int index = [col index]; |
1200 |
int pos = index - firstVisibleColumn + 1; |
1201 |
BOOL mustshift = (firstVisibleColumn > 0) ? YES : NO; |
1202 |
NSArray *selection = [col selection]; |
1203 |
|
1204 |
if ((selection == nil) || ([selection count] == 0)) { |
1205 |
[self clickOnIcon: [col myIcon] ofColumn: col]; |
1206 |
return; |
1207 |
} |
1208 |
|
1209 |
if (isRemote) { |
1210 |
[waitCursor set]; |
1211 |
} |
1212 |
|
1213 |
if ((pos == visibleColumns) && (index == ([columns count] -1))) { |
1214 |
NSTimer *timer; |
1215 |
NSPoint p; |
1216 |
|
1217 |
p = [[self window] mouseLocationOutsideOfEventStream]; |
1218 |
mousePointX = p.x; |
1219 |
mousePointY = p.y; |
1220 |
ASSIGN (doubleClickSelection, selection); |
1221 |
simulatingDoubleClick = YES; |
1222 |
|
1223 |
timer = [NSTimer scheduledTimerWithTimeInterval: 0.3 |
1224 |
target: self selector: @selector(doubleClikTimeOut:) |
1225 |
userInfo: nil repeats: NO]; |
1226 |
} |
1227 |
|
1228 |
[delegate currentSelectedPaths: selection]; |
1229 |
|
1230 |
currentshift = 0; |
1231 |
canUpdateViews = NO; |
1232 |
|
1233 |
(*lastColumn)(self, lastColumnSel, index); |
1234 |
(*addAndLoad)(self, addAndLoadSel, selection); |
1235 |
|
1236 |
if ((mustshift == YES) && (pos < (visibleColumns - 1))) { |
1237 |
[self setShift: visibleColumns - pos - 1]; |
1238 |
} |
1239 |
|
1240 |
canUpdateViews = YES; |
1241 |
[self tile]; |
1242 |
|
1243 |
if (isRemote) { |
1244 |
[[NSCursor arrowCursor] set]; |
1245 |
} |
1246 |
|
1247 |
#ifndef GNUSTEP |
1248 |
[[self window] makeFirstResponder: self]; |
1249 |
#endif |
1250 |
} |
1251 |
|
1252 |
- (void)doubleClickInMatrixOfColumn:(BColumn *)col |
1253 |
{ |
1254 |
NSArray *selection = [col selection]; |
1255 |
|
1256 |
if (selection) { |
1257 |
[delegate openSelectedPaths: selection newViewer: NO]; |
1258 |
} |
1259 |
} |
1260 |
|
1261 |
- (void)clickOnIcon:(BIcon *)icon ofColumn:(BColumn *)col |
1262 |
{ |
1263 |
BColumn *column; |
1264 |
|
1265 |
if ([icon isSinglePath] == NO) { |
1266 |
return; |
1267 |
} |
1268 |
|
1269 |
if (isRemote) { |
1270 |
[waitCursor set]; |
1271 |
} |
1272 |
|
1273 |
column = [self columnBeforeColumn: col]; |
1274 |
|
1275 |
if (column) { |
1276 |
NSString *name = [icon name]; |
1277 |
|
1278 |
if ([column selectMatrixCellsWithNames: [NSArray arrayWithObject: name] |
1279 |
sendAction: YES] == NO) { |
1280 |
(*lastColumn)(self, lastColumnSel, [column index]); |
1281 |
[delegate currentSelectedPaths: [NSArray arrayWithObject: [column currentPath]]]; |
1282 |
} |
1283 |
|
1284 |
} else { |
1285 |
(*lastColumn)(self, lastColumnSel, 0); |
1286 |
[delegate currentSelectedPaths: [NSArray arrayWithObject: basePath]]; |
1287 |
[self tile]; |
1288 |
} |
1289 |
|
1290 |
[nameEditor setBackgroundColor: [NSColor whiteColor]]; |
1291 |
|
1292 |
if (isRemote) { |
1293 |
[[NSCursor arrowCursor] set]; |
1294 |
} |
1295 |
|
1296 |
[[self window] makeFirstResponder: self]; |
1297 |
} |
1298 |
|
1299 |
- (void)doubleClickOnIcon:(BIcon *)icon |
1300 |
ofColumn:(BColumn *)col |
1301 |
newViewer:(BOOL)isnew |
1302 |
{ |
1303 |
[delegate openSelectedPaths: [icon paths] newViewer: isnew]; |
1304 |
} |
1305 |
|
1306 |
- (void)updateNameEditor |
1307 |
{ |
1308 |
BColumn *col = [self lastLoadedColumn]; |
1309 |
|
1310 |
if ([[self subviews] containsObject: nameEditor]) { |
1311 |
NSRect edr = [nameEditor frame]; |
1312 |
|
1313 |
[nameEditor abortEditing]; |
1314 |
[nameEditor setName: nil paths: nil index: -1]; |
1315 |
[nameEditor removeFromSuperview]; |
1316 |
[self setNeedsDisplayInRect: edr]; |
1317 |
edCol = nil; |
1318 |
} |
1319 |
|
1320 |
isEditingIconName = NO; |
1321 |
|
1322 |
if (col && ([col index] <= lastVisibleColumn)) { |
1323 |
BIcon *icon = [col myIcon]; |
1324 |
NSArray *paths = [icon paths]; |
1325 |
NSString *name = [icon isRootIcon] ? [icon hostname] : [icon name]; |
1326 |
BOOL locked = [icon isLocked]; |
1327 |
BOOL canedit = ((!locked) && (paths && [paths count] == 1) && (![icon isRootIcon])); |
1328 |
NSRect r = [[col iconView] frame]; |
1329 |
float bw = [self bounds].size.width - EDIT_MARGIN; |
1330 |
float centerx = r.origin.x + (r.size.width / 2); |
1331 |
float labwidth = [editorFont widthOfString: name] + LABEL_MARGIN; |
1332 |
|
1333 |
if ((centerx + (labwidth / 2)) >= bw) { |
1334 |
centerx -= (centerx + (labwidth / 2) - bw); |
1335 |
} else if ((centerx - (labwidth / 2)) < LABEL_MARGIN) { |
1336 |
centerx += fabs(centerx - (labwidth / 2)) + LABEL_MARGIN; |
1337 |
} |
1338 |
|
1339 |
[[icon label] setFrame: NSMakeRect(centerx, r.origin.y, 1, 1)]; |
1340 |
|
1341 |
r = NSMakeRect(centerx - (labwidth / 2), r.origin.y, labwidth, LABEL_HEIGHT); |
1342 |
[nameEditor setFrame: r]; |
1343 |
[nameEditor setName: name paths: paths index: [col index]]; |
1344 |
[nameEditor setBackgroundColor: [NSColor whiteColor]]; |
1345 |
[nameEditor setTextColor: (locked ? [NSColor disabledControlTextColor] |
1346 |
: [NSColor controlTextColor])]; |
1347 |
[nameEditor setEditable: canedit]; |
1348 |
[nameEditor setSelectable: canedit]; |
1349 |
[self addSubview: nameEditor]; |
1350 |
} |
1351 |
} |
1352 |
|
1353 |
- (BOOL)isEditingIconName |
1354 |
{ |
1355 |
return isEditingIconName; |
1356 |
} |
1357 |
|
1358 |
- (void)controlTextDidChange:(NSNotification *)aNotification |
1359 |
{ |
1360 |
static NSRect edr = {{0, 0}, {0, 0}}; |
1361 |
static float crx = 0; |
1362 |
static float ory = 0; |
1363 |
static float bw = 0; |
1364 |
NSString *s; |
1365 |
float labwidth; |
1366 |
float labcenter; |
1367 |
|
1368 |
if (edCol == nil) { |
1369 |
edCol = [self lastLoadedColumn]; |
1370 |
edr = [[edCol iconView] frame]; |
1371 |
crx = edr.origin.x + (edr.size.width / 2); |
1372 |
ory = edr.origin.y; |
1373 |
bw = [self bounds].size.width - EDIT_MARGIN; |
1374 |
} |
1375 |
|
1376 |
s = [nameEditor stringValue]; |
1377 |
labwidth = [editorFont widthOfString: s] + LABEL_MARGIN; |
1378 |
|
1379 |
labcenter = crx; |
1380 |
|
1381 |
while ((labcenter + (labwidth / 2)) > bw) { |
1382 |
labcenter -= EDIT_MARGIN; |
1383 |
if (labcenter < EDIT_MARGIN) { |
1384 |
break; |
1385 |
} |
1386 |
} |
1387 |
|
1388 |
while ((labcenter - (labwidth / 2)) < EDIT_MARGIN) { |
1389 |
labcenter += EDIT_MARGIN; |
1390 |
if (labcenter >= bw) { |
1391 |
break; |
1392 |
} |
1393 |
} |
1394 |
|
1395 |
[self setNeedsDisplayInRect: [nameEditor frame]]; |
1396 |
[nameEditor setFrame: NSMakeRect((labcenter - (labwidth / 2)), ory, labwidth, LABEL_HEIGHT)]; |
1397 |
} |
1398 |
|
1399 |
- (void)controlTextDidBeginEditing:(NSNotification *)aNotification |
1400 |
{ |
1401 |
isEditingIconName = YES; |
1402 |
} |
1403 |
|
1404 |
- (void)controlTextDidEndEditing:(NSNotification *)aNotification |
1405 |
{ |
1406 |
NSString *oldpath = [[nameEditor paths] objectAtIndex: 0]; |
1407 |
NSString *basepath = [oldpath stringByDeletingLastPathComponent]; |
1408 |
NSString *oldname = [nameEditor name]; |
1409 |
NSString *newname = [nameEditor stringValue]; |
1410 |
NSString *newpath = [basepath stringByAppendingPathComponent: newname]; |
1411 |
NSFileManager *fm = [NSFileManager defaultManager]; |
1412 |
|
1413 |
#define CLEAREDITING \ |
1414 |
[self updateNameEditor]; \ |
1415 |
return |
1416 |
|
1417 |
if (isRemote) { |
1418 |
[self updateNameEditor]; |
1419 |
|
1420 |
[gworkspace server: remoteHostName |
1421 |
renamePath: oldpath |
1422 |
toNewName: newpath]; |
1423 |
return; |
1424 |
} |
1425 |
|
1426 |
isEditingIconName = NO; |
1427 |
[nameEditor setAlignment: NSCenterTextAlignment]; |
1428 |
|
1429 |
if ([fm isWritableFileAtPath: oldpath] == NO) { |
1430 |
NSRunAlertPanel(NSLocalizedString(@"Error", @""), |
1431 |
[NSString stringWithFormat: @"%@\"%@\"!\n", |
1432 |
NSLocalizedString(@"You have not write permission\nfor ", @""), |
1433 |
oldpath], NSLocalizedString(@"Continue", @""), nil, nil); |
1434 |
CLEAREDITING; |
1435 |
|
1436 |
} else if ([fm isWritableFileAtPath: basepath] == NO) { |
1437 |
NSRunAlertPanel(NSLocalizedString(@"Error", @""), |
1438 |
[NSString stringWithFormat: @"%@\"%@\"!\n", |
1439 |
NSLocalizedString(@"You have not write permission\nfor ", @""), |
1440 |
basepath], NSLocalizedString(@"Continue", @""), nil, nil); |
1441 |
CLEAREDITING; |
1442 |
|
1443 |
} else { |
1444 |
NSCharacterSet *notAllowSet = [NSCharacterSet characterSetWithCharactersInString: @"/\\*$|~\'\"`^!?"]; |
1445 |
NSRange range = [newname rangeOfCharacterFromSet: notAllowSet]; |
1446 |
NSArray *dirContents = [fm directoryContentsAtPath: basepath]; |
1447 |
NSMutableDictionary *notifObj = [NSMutableDictionary dictionaryWithCapacity: 1]; |
1448 |
|
1449 |
if (range.length > 0) { |
1450 |
NSRunAlertPanel(NSLocalizedString(@"Error", @""), |
1451 |
NSLocalizedString(@"Invalid char in name", @""), |
1452 |
NSLocalizedString(@"Continue", @""), nil, nil); |
1453 |
CLEAREDITING; |
1454 |
} |
1455 |
|
1456 |
if ([dirContents containsObject: newname]) { |
1457 |
if ([newname isEqualToString: oldname]) { |
1458 |
CLEAREDITING; |
1459 |
} else { |
1460 |
NSRunAlertPanel(NSLocalizedString(@"Error", @""), |
1461 |
[NSString stringWithFormat: @"%@\"%@\" %@\n", |
1462 |
NSLocalizedString(@"The name ", @""), |
1463 |
newname, NSLocalizedString(@" is already in use!", @"")], |
1464 |
NSLocalizedString(@"Continue", @""), nil, nil); |
1465 |
CLEAREDITING; |
1466 |
} |
1467 |
} |
1468 |
|
1469 |
[notifObj setObject: GWorkspaceRenameOperation forKey: @"operation"]; |
1470 |
[notifObj setObject: oldpath forKey: @"source"]; |
1471 |
[notifObj setObject: newpath forKey: @"destination"]; |
1472 |
[notifObj setObject: [NSArray arrayWithObject: @""] forKey: @"files"]; |
1473 |
|
1474 |
[[NSNotificationCenter defaultCenter] |
1475 |
postNotificationName: GWFileSystemWillChangeNotification |
1476 |
object: notifObj]; |
1477 |
|
1478 |
[fm movePath: oldpath toPath: newpath handler: self]; |
1479 |
|
1480 |
[[NSNotificationCenter defaultCenter] |
1481 |
postNotificationName: GWFileSystemDidChangeNotification |
1482 |
object: notifObj]; |
1483 |
|
1484 |
[self updateNameEditor]; |
1485 |
} |
1486 |
} |
1487 |
|
1488 |
- (void)editorAction:(id)sender |
1489 |
{ |
1490 |
} |
1491 |
|
1492 |
- (BOOL)fileManager:(NSFileManager *)manager |
1493 |
shouldProceedAfterError:(NSDictionary *)errorDict |
1494 |
{ |
1495 |
NSString *title = NSLocalizedString(@"Error", @""); |
1496 |
NSString *msg1 = NSLocalizedString(@"Cannot rename ", @""); |
1497 |
NSString *name = [nameEditor name]; |
1498 |
NSString *msg2 = NSLocalizedString(@"Continue", @""); |
1499 |
|
1500 |
NSRunAlertPanel(title, [NSString stringWithFormat: @"%@'%@'!", msg1, name], msg2, nil, nil); |
1501 |
|
1502 |
return NO; |
1503 |
} |
1504 |
|
1505 |
- (void)fileManager:(NSFileManager *)manager willProcessPath:(NSString *)path |
1506 |
{ |
1507 |
} |
1508 |
|
1509 |
- (BOOL)acceptsFirstResponder |
1510 |
{ |
1511 |
return YES; |
1512 |
} |
1513 |
|
1514 |
- (BOOL)becomeFirstResponder |
1515 |
{ |
1516 |
BColumn *selCol; |
1517 |
NSMatrix *matrix; |
1518 |
|
1519 |
selCol = [self selectedColumn]; |
1520 |
|
1521 |
if (selCol == nil) { |
1522 |
matrix = [(*getImp)(columns, getSel, 0) cmatrix]; |
1523 |
} else { |
1524 |
matrix = [selCol cmatrix]; |
1525 |
} |
1526 |
|
1527 |
if (matrix) { |
1528 |
[[self window] makeFirstResponder: matrix]; |
1529 |
} |
1530 |
|
1531 |
return YES; |
1532 |
} |
1533 |
|
1534 |
- (void)keyDown:(NSEvent *)theEvent |
1535 |
{ |
1536 |
NSString *characters; |
1537 |
unichar character; |
1538 |
BColumn *column; |
1539 |
NSMatrix *matrix; |
1540 |
|
1541 |
if (!(column = [self selectedColumn])) { |
1542 |
return; |
1543 |
} |
1544 |
if (!(matrix = [column cmatrix])) { |
1545 |
return; |
1546 |
} |
1547 |
|
1548 |
characters = [theEvent characters]; |
1549 |
character = 0; |
1550 |
|
1551 |
if ([characters length] > 0) { |
1552 |
character = [characters characterAtIndex: 0]; |
1553 |
} |
1554 |
|
1555 |
switch (character) { |
1556 |
case NSUpArrowFunctionKey: |
1557 |
case NSDownArrowFunctionKey: |
1558 |
return; |
1559 |
|
1560 |
case NSLeftArrowFunctionKey: |
1561 |
{ |
1562 |
if ([theEvent modifierFlags] & NSControlKeyMask) { |
1563 |
[super keyDown: theEvent]; |
1564 |
} else { |
1565 |
[self moveLeft: self]; |
1566 |
} |
1567 |
} |
1568 |
return; |
1569 |
|
1570 |
case NSRightArrowFunctionKey: |
1571 |
{ |
1572 |
if ([theEvent modifierFlags] & NSControlKeyMask) { |
1573 |
[super keyDown: theEvent]; |
1574 |
} else { |
1575 |
[self moveRight: self]; |
1576 |
} |
1577 |
} |
1578 |
return; |
1579 |
|
1580 |
case 13: |
1581 |
[matrix sendDoubleAction]; |
1582 |
return; |
1583 |
|
1584 |
case NSTabCharacter: |
1585 |
{ |
1586 |
if ([theEvent modifierFlags] & NSShiftKeyMask) |
1587 |
[[self window] selectKeyViewPrecedingView: self]; |
1588 |
else |
1589 |
[[self window] selectKeyViewFollowingView: self]; |
1590 |
} |
1591 |
return; |
1592 |
break; |
1593 |
} |
1594 |
|
1595 |
if ((character < 0xF700) && ([characters length] > 0)) { |
1596 |
// column = [self lastNotEmptyColumn]; |
1597 |
column = [self selectedColumn]; |
1598 |
|
1599 |
if (column) { |
1600 |
int index = [column index]; |
1601 |
|
1602 |
matrix = [column cmatrix]; |
1603 |
|
1604 |
if (matrix == nil) { |
1605 |
return; |
1606 |
} |
1607 |
|
1608 |
if (charBuffer == nil) { |
1609 |
charBuffer = [characters substringToIndex: 1]; |
1610 |
RETAIN (charBuffer); |
1611 |
} else { |
1612 |
if (([theEvent timestamp] - lastKeyPressed < 2000.0) |
1613 |
&& (alphaNumericalLastColumn == index)) { |
1614 |
ASSIGN (charBuffer, ([charBuffer stringByAppendingString: |
1615 |
[characters substringToIndex: 1]])); |
1616 |
} else { |
1617 |
ASSIGN (charBuffer, ([characters substringToIndex: 1])); |
1618 |
} |
1619 |
} |
1620 |
|
1621 |
alphaNumericalLastColumn = index; |
1622 |
lastKeyPressed = [theEvent timestamp]; |
1623 |
|
1624 |
if ([column selectCellWithPrefix: charBuffer]) { |
1625 |
// [[self window] makeFirstResponder: matrix]; |
1626 |
return; |
1627 |
} |
1628 |
} |
1629 |
|
1630 |
lastKeyPressed = 0.; |
1631 |
} |
1632 |
|
1633 |
[super keyDown: theEvent]; |
1634 |
} |
1635 |
|
1636 |
- (void)resizeSubviewsWithOldSize:(NSSize)oldSize |
1637 |
{ |
1638 |
[self tile]; |
1639 |
} |
1640 |
|
1641 |
- (void)drawRect:(NSRect)rect |
1642 |
{ |
1643 |
NSRect r; |
1644 |
NSSize bs; |
1645 |
NSPoint p1, p2; |
1646 |
NSRect browserRect; |
1647 |
NSRect scrollerBorderRect; |
1648 |
int i; |
1649 |
|
1650 |
r = [self bounds]; |
1651 |
bs = BEZEL_BORDER_SIZE; |
1652 |
|
1653 |
NSRectClip(rect); |
1654 |
[[[self window] backgroundColor] set]; |
1655 |
NSRectFill(rect); |
1656 |
|
1657 |
if (!isLoaded) { |
1658 |
[self loadColumnZero]; |
1659 |
} |
1660 |
|
1661 |
if (styleMask & GWColumnIconMask) { |
1662 |
scrollerBorderRect = NSMakeRect(scrollerRect.origin.x, |
1663 |
scrollerRect.origin.y, scrollerRect.size.width, |
1664 |
scrollerRect.size.height + iconsPathWidth - 2); |
1665 |
|
1666 |
scrollerBorderRect.origin.x = 0; |
1667 |
scrollerBorderRect.origin.y = scrollerRect.origin.y - 1; |
1668 |
scrollerBorderRect.size.width += 2 * bs.width; |
1669 |
scrollerBorderRect.size.height += (2 * bs.height); |
1670 |
|
1671 |
} else { |
1672 |
scrollerBorderRect = scrollerRect; |
1673 |
scrollerBorderRect.origin.x = 0; |
1674 |
scrollerBorderRect.origin.y = 1; |
1675 |
scrollerBorderRect.size.width += 2 * bs.width; |
1676 |
scrollerBorderRect.size.height += (2 * bs.height) - 1; |
1677 |
} |
1678 |
|
1679 |
if (NSIntersectsRect(scrollerBorderRect, r)) { |
1680 |
p1 = NSMakePoint(scrollerBorderRect.origin.x + 2, |
1681 |
scrollerBorderRect.origin.y + scrollerRect.size.height + 2); |
1682 |
p2 = NSMakePoint(scrollerBorderRect.origin.x + scrollerBorderRect.size.width - 2, |
1683 |
scrollerBorderRect.origin.y + scrollerRect.size.height + 2); |
1684 |
|
1685 |
NSDrawGrayBezel(scrollerBorderRect, r); |
1686 |
|
1687 |
if (styleMask & GWColumnIconMask) { |
1688 |
[[NSColor blackColor] set]; |
1689 |
[NSBezierPath strokeLineFromPoint: p1 toPoint: p2]; |
1690 |
} |
1691 |
} |
1692 |
|
1693 |
if (styleMask & GWColumnIconMask) { |
1694 |
browserRect = NSMakeRect(0, -2, r.size.width, columnSize.height + 4); |
1695 |
} else { |
1696 |
browserRect = NSMakeRect(0, columnOriginY - 2, r.size.width, |
1697 |
r.size.height - columnOriginY + 2); |
1698 |
} |
1699 |
NSDrawGrayBezel(browserRect, r); |
1700 |
|
1701 |
[[NSColor blackColor] set]; |
1702 |
|
1703 |
for (i = 1; i < visibleColumns; i++) { |
1704 |
p1 = NSMakePoint((columnSize.width * i) + 2 + (i-1), |
1705 |
columnSize.height + columnOriginY); |
1706 |
p2 = NSMakePoint((columnSize.width * i) + 2 + (i-1), columnOriginY); |
1707 |
[NSBezierPath strokeLineFromPoint: p1 toPoint: p2]; |
1708 |
} |
1709 |
} |
1710 |
|
1711 |
@end |
1712 |
|
1713 |
|
1714 |
|
1715 |
|
1716 |
|
1717 |
|
1718 |
|
1719 |
|
1720 |
|
1721 |
|
1722 |
|
1723 |
|
1724 |
|
1725 |
|
1726 |
|
1727 |
|
1728 |
|
1729 |
|