1 SelectionBrowser subclass:#FileSelectionBrowser |
|
2 instanceVariableNames:'selectedFileFilter fileName readTask' |
|
3 classVariableNames:'' |
|
4 poolDictionaries:'' |
|
5 category:'Interface-Advanced-Tools' |
|
6 ! |
|
7 |
|
8 Object subclass:#Row |
|
9 instanceVariableNames:'fileName size modified iconKey group owner permissions baseName' |
|
10 classVariableNames:'' |
|
11 poolDictionaries:'' |
|
12 privateIn:FileSelectionBrowser |
|
13 ! |
|
14 |
|
15 |
|
16 !FileSelectionBrowser class methodsFor:'instance creation'! |
|
17 |
|
18 requestFileName |
|
19 |
|
20 ^self new title: 'Select a file'; open |
|
21 |
|
22 ! |
|
23 |
|
24 requestFileName: aFileName fileFilters: fileFilters |
|
25 |
|
26 ^self new |
|
27 fileName: aFileName; |
|
28 listOfFileFilters: fileFilters; |
|
29 open |
|
30 ! |
|
31 |
|
32 title: aTitle requestFileName: aFileName fileFilters: fileFilters |
|
33 |
|
34 ^self new |
|
35 title: aTitle; |
|
36 fileName: aFileName; |
|
37 listOfFileFilters: fileFilters; |
|
38 open |
|
39 ! ! |
|
40 |
|
41 !FileSelectionBrowser class methodsFor:'accessing'! |
|
42 |
|
43 loadImageFileNameFilters |
|
44 ^self saveImageFileNameFilters addAll: #('*.jpeg' '*.jpg'); yourself |
|
45 |
|
46 ! |
|
47 |
|
48 saveImageFileNameFilters |
|
49 ^Array withAll: #('*.xpm' '*.xbm' '*.gif' '*.tif' '*.tiff') |
|
50 |
|
51 ! ! |
|
52 |
|
53 !FileSelectionBrowser class methodsFor:'interface specs'! |
|
54 |
|
55 windowSpec |
|
56 "this window spec was automatically generated by the ST/X UIPainter" |
|
57 |
|
58 "do not manually edit this - the painter/builder may not be able to |
|
59 handle the specification if its corrupted." |
|
60 |
|
61 " |
|
62 UIPainter new openOnClass:FileSelectionBrowser andSelector:#windowSpec |
|
63 FileSelectionBrowser new openInterface:#windowSpec |
|
64 " |
|
65 "FileSelectionBrowser open" |
|
66 |
|
67 <resource: #canvas> |
|
68 |
|
69 ^ |
|
70 |
|
71 #(#FullSpec |
|
72 #'window:' |
|
73 #(#WindowSpec |
|
74 #'name:' 'File Selection Browser' |
|
75 #'layout:' #(#LayoutFrame 301 0 222 0 700 0 521 0) |
|
76 #'label:' 'File Selection Browser' |
|
77 #'min:' #(#Point 10 10) |
|
78 #'max:' #(#Point 1152 900) |
|
79 #'bounds:' #(#Rectangle 301 222 701 522) |
|
80 #'usePreferredExtent:' false |
|
81 ) |
|
82 #'component:' |
|
83 #(#SpecCollection |
|
84 #'collection:' |
|
85 #( |
|
86 #(#ViewSpec |
|
87 #'name:' 'view' |
|
88 #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 -40 1.0) |
|
89 #'component:' |
|
90 #(#SpecCollection |
|
91 #'collection:' |
|
92 #( |
|
93 #(#VariableHorizontalPanelSpec |
|
94 #'name:' 'panel' |
|
95 #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 -1 1.0) |
|
96 #'component:' |
|
97 #(#SpecCollection |
|
98 #'collection:' |
|
99 #( |
|
100 #(#ViewSpec |
|
101 #'name:' 'view1' |
|
102 #'component:' |
|
103 #(#SpecCollection |
|
104 #'collection:' |
|
105 #( |
|
106 #(#FileSelectionTreeSpec |
|
107 #'name:' 'directoryTreeView' |
|
108 #'layout:' #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0) |
|
109 #'model:' #selectionOfDirectory |
|
110 #'hasHorizontalScrollBar:' true |
|
111 #'hasVerticalScrollBar:' true |
|
112 #'miniScrollerHorizontal:' true |
|
113 #'showRoot:' false |
|
114 #'showDirectoryIndicator:' true |
|
115 #'valueChangeSelector:' #readDirectory |
|
116 #'hierarchicalList:' #rootOfDirectory |
|
117 #'itemClass:' 'Directory' |
|
118 ) |
|
119 ) |
|
120 ) |
|
121 #'level:' -1 |
|
122 ) |
|
123 #(#ViewSpec |
|
124 #'name:' 'view2' |
|
125 #'component:' |
|
126 #(#SpecCollection |
|
127 #'collection:' |
|
128 #( |
|
129 #(#DataSetSpec |
|
130 #'name:' 'filesDataSetView' |
|
131 #'layout:' #(#LayoutFrame 0 0.0 24 0.0 0 1.0 -23 1.0) |
|
132 #'model:' #selectionOfFile |
|
133 #'hasHorizontalScrollBar:' true |
|
134 #'hasVerticalScrollBar:' true |
|
135 #'miniScrollerHorizontal:' true |
|
136 #'dataList:' #listOfFiles |
|
137 #'useIndex:' false |
|
138 #'level:' 1 |
|
139 #'doubleClickSelector:' #fileDoubleClicked |
|
140 #'valueChangeSelector:' #fileSelected |
|
141 #'verticalSpacing:' 1 |
|
142 #'columns:' |
|
143 #( |
|
144 #(#DataSetColumnSpec |
|
145 #'label:' '' |
|
146 #'width:' 30 |
|
147 #'printSelector:' #'iconOn:' |
|
148 #'canSelect:' false |
|
149 ) |
|
150 #(#DataSetColumnSpec |
|
151 #'label:' 'file name' |
|
152 #'minWidth:' 100 |
|
153 #'model:' #baseName |
|
154 ) |
|
155 #(#DataSetColumnSpec |
|
156 #'label:' 'size' |
|
157 #'width:' 50 |
|
158 #'model:' #size |
|
159 #'canSelect:' false |
|
160 ) |
|
161 #(#DataSetColumnSpec |
|
162 #'label:' 'modified' |
|
163 #'model:' #modified |
|
164 ) |
|
165 #(#DataSetColumnSpec |
|
166 #'label:' 'permissions' |
|
167 #'width:' 85 |
|
168 #'model:' #permissions |
|
169 #'canSelect:' false |
|
170 ) |
|
171 #(#DataSetColumnSpec |
|
172 #'label:' 'owner' |
|
173 #'width:' 50 |
|
174 #'model:' #owner |
|
175 #'canSelect:' false |
|
176 ) |
|
177 #(#DataSetColumnSpec |
|
178 #'label:' 'group' |
|
179 #'width:' 50 |
|
180 #'model:' #group |
|
181 #'canSelect:' false |
|
182 ) |
|
183 ) |
|
184 ) |
|
185 #(#ComboBoxSpec |
|
186 #'name:' 'formatComboBox' |
|
187 #'layout:' #(#LayoutFrame 0 0.0 2 0 0 1.0 24 0) |
|
188 #'model:' #selectionOfFileFilter |
|
189 #'immediateAccept:' false |
|
190 #'acceptOnTab:' false |
|
191 #'comboList:' #listOfFileFilters |
|
192 ) |
|
193 #(#InputFieldSpec |
|
194 #'name:' 'EditField' |
|
195 #'layout:' #(#LayoutFrame 0 0.0 -22 1 0 1.0 0 1) |
|
196 #'model:' #valueOfFileName |
|
197 #'acceptOnReturn:' false |
|
198 #'acceptOnTab:' false |
|
199 ) |
|
200 ) |
|
201 ) |
|
202 #'level:' -1 |
|
203 ) |
|
204 ) |
|
205 ) |
|
206 #'handles:' #(#Any 0.5 1.0) |
|
207 ) |
|
208 ) |
|
209 ) |
|
210 ) |
|
211 #(#HorizontalPanelViewSpec |
|
212 #'name:' 'horizontalPanelView' |
|
213 #'layout:' #(#LayoutFrame 0 0.0 -40 1 0 1.0 0 1.0) |
|
214 #'component:' |
|
215 #(#SpecCollection |
|
216 #'collection:' |
|
217 #( |
|
218 #(#ActionButtonSpec |
|
219 #'name:' 'cancelButton' |
|
220 #'label:' 'Cancel' |
|
221 #'model:' #cancel |
|
222 #'extent:' #(#Point 100 22) |
|
223 ) |
|
224 #(#ActionButtonSpec |
|
225 #'name:' 'okButton' |
|
226 #'label:' 'OK' |
|
227 #'model:' #accept |
|
228 #'extent:' #(#Point 100 22) |
|
229 ) |
|
230 ) |
|
231 ) |
|
232 #'level:' 1 |
|
233 #'horizontalLayout:' #center |
|
234 #'verticalLayout:' #center |
|
235 #'horizontalSpace:' 3 |
|
236 #'verticalSpace:' 3 |
|
237 ) |
|
238 ) |
|
239 ) |
|
240 ) |
|
241 ! ! |
|
242 |
|
243 !FileSelectionBrowser methodsFor:'accessing'! |
|
244 |
|
245 fileName |
|
246 |
|
247 (fileName notNil and: [(fileName name ~= self valueOfFileName value and: [self valueOfFileName value notNil])]) |
|
248 ifTrue: [^(LastFileSelectionDirectory, Filename separator, self valueOfFileName value) asFilename]. |
|
249 ^fileName |
|
250 ! |
|
251 |
|
252 fileName: aFileName |
|
253 |
|
254 fileName := aFileName |
|
255 ! |
|
256 |
|
257 title: aString |
|
258 |
|
259 title := aString |
|
260 ! ! |
|
261 |
|
262 !FileSelectionBrowser methodsFor:'actions'! |
|
263 |
|
264 closeCancel |
|
265 |
|
266 readTask notNil ifTrue: [readTask terminate]. |
|
267 fileName := nil. |
|
268 super closeCancel |
|
269 ! |
|
270 |
|
271 closeRequest |
|
272 |
|
273 readTask notNil ifTrue: [readTask terminate]. |
|
274 super closeRequest |
|
275 ! |
|
276 |
|
277 closeWindow |
|
278 |
|
279 readTask notNil ifTrue: [readTask terminate]. |
|
280 super closeWindow |
|
281 ! |
|
282 |
|
283 fileDoubleClicked |
|
284 |
|
285 self valueOfFileName value: self selectionOfFile value baseName. |
|
286 fileName := self selectionOfFile value fileName. |
|
287 accept value: true. |
|
288 self close |
|
289 ! |
|
290 |
|
291 fileSelected |
|
292 |
|
293 self valueOfFileName value: self selectionOfFile value baseName. |
|
294 fileName := self selectionOfFile value fileName. |
|
295 ! |
|
296 |
|
297 readDirectory |
|
298 |
|
299 | file list dir lst| |
|
300 self selectionOfDirectory value isNil ifTrue: [^nil]. |
|
301 readTask notNil ifTrue: [readTask terminate]. |
|
302 readTask := [ |
|
303 |
|
304 file := (builder componentAt: #directoryTreeView) selectedPathname asFilename. |
|
305 builder window label: 'Reading: ''', file name, ''''. |
|
306 self class lastSelection: file name. |
|
307 (file isReadable and:[file isExecutable]) ifTrue:[ |
|
308 list := self listOfFiles. |
|
309 list removeAll. |
|
310 lst := OrderedCollection new. |
|
311 self listOfFileFilters value |
|
312 do: [:filter| |
|
313 (file filesMatchingWithoutDotDirs: filter) do: |
|
314 [:aFileName| |
|
315 lst add: (Row new fileName: (file name, Filename separator, aFileName) asFilename) |
|
316 ]. |
|
317 ]. |
|
318 lst := lst asSortedCollection: [:r1 :r2| r1 baseName < r2 baseName]. |
|
319 list addAll:lst beforeIndex:1]. |
|
320 self selectionOfFile value: (self listOfFiles detect: [:r| r fileName = fileName] ifNone: [nil]). |
|
321 self setLabel. |
|
322 ] forkAt: Processor userBackgroundPriority |
|
323 ! ! |
|
324 |
|
325 !FileSelectionBrowser methodsFor:'aspects'! |
|
326 |
|
327 listOfFileFilters |
|
328 |
|
329 |holder| |
|
330 (holder := builder bindingAt:#listOfFileFilters) isNil ifTrue:[ |
|
331 builder aspectAt:#listOfFileFilters put:(holder := List with: '*.*'). |
|
332 ]. |
|
333 ^ holder |
|
334 ! |
|
335 |
|
336 listOfFileFilters: aCollection |
|
337 self listOfFileFilters contents: aCollection. |
|
338 ! |
|
339 |
|
340 listOfFiles |
|
341 |
|
342 |holder| |
|
343 (holder := builder bindingAt:#listOfFiles) isNil ifTrue:[ |
|
344 builder aspectAt:#listOfFiles put:(holder := List new). |
|
345 ]. |
|
346 ^ holder |
|
347 |
|
348 ! |
|
349 |
|
350 rootOfDirectory |
|
351 |
|
352 |holder| |
|
353 (holder := builder bindingAt:#rootOfDirectory) isNil ifTrue:[ |
|
354 builder aspectAt:#rootOfDirectory put: (holder := ValueHolder with: Filename rootDirectory name). |
|
355 ]. |
|
356 ^ holder |
|
357 |
|
358 ! |
|
359 |
|
360 selectionOfDirectory |
|
361 |
|
362 |holder| |
|
363 (holder := builder bindingAt:#selectionOfDirectory) isNil ifTrue:[ |
|
364 builder aspectAt:#selectionOfDirectory put: (holder := ValueHolder new) |
|
365 ]. |
|
366 ^ holder |
|
367 |
|
368 ! |
|
369 |
|
370 selectionOfFile |
|
371 |
|
372 |holder| |
|
373 (holder := builder bindingAt:#selectionOfFile) isNil ifTrue:[ |
|
374 builder aspectAt:#selectionOfFile put:(holder := ValueHolder new). |
|
375 ]. |
|
376 ^ holder |
|
377 |
|
378 ! |
|
379 |
|
380 selectionOfFileFilter |
|
381 |
|
382 |holder| |
|
383 (holder := builder bindingAt:#selectionOfFileFilter) isNil ifTrue:[ |
|
384 builder aspectAt:#selectionOfFileFilter put: |
|
385 (holder := AspectAdaptor new subject:self; forAspect:#selectedFileFilter). |
|
386 selectedFileFilter := '*.*'. |
|
387 ]. |
|
388 ^ holder |
|
389 ! |
|
390 |
|
391 valueOfFileName |
|
392 |
|
393 |holder| |
|
394 (holder := builder bindingAt:#valueOfFileName) isNil ifTrue:[ |
|
395 builder aspectAt:#valueOfFileName put:(holder := ValueHolder new). |
|
396 ]. |
|
397 ^ holder |
|
398 ! ! |
|
399 |
|
400 !FileSelectionBrowser methodsFor:'initialization'! |
|
401 |
|
402 open |
|
403 |
|
404 super open. |
|
405 accept value |
|
406 ifTrue: |
|
407 [ |
|
408 ^(self selectionOfDirectory value ? '') , Filename separator, (self valueOfFileName value ? '') |
|
409 ]. |
|
410 ^nil |
|
411 |
|
412 |
|
413 |
|
414 ! |
|
415 |
|
416 postBuildWith:aBuilder |
|
417 |
|
418 (fileName notNil and: [fileName asFilename exists]) |
|
419 ifTrue: |
|
420 [ |
|
421 self class lastSelection: fileName asFilename asAbsoluteFilename directoryName. |
|
422 self valueOfFileName value: fileName asFilename baseName |
|
423 ]. |
|
424 (builder componentAt: #directoryTreeView) selectPathname: self class lastSelection. |
|
425 self selectionOfFileFilter value: (self listOfFileFilters at: 1 ifAbsent: [nil]). |
|
426 self readDirectory. |
|
427 (builder componentAt: #directoryTreeView) monitoring: true. |
|
428 ^super postBuildWith:aBuilder |
|
429 ! ! |
|
430 |
|
431 !FileSelectionBrowser methodsFor:'selection'! |
|
432 |
|
433 selectedFileFilter |
|
434 |
|
435 ^selectedFileFilter |
|
436 ! |
|
437 |
|
438 selectedFileFilter: aString |
|
439 |
|
440 selectedFileFilter := aString. |
|
441 self valueOfFileName value: (fileName := |
|
442 ((self valueOfFileName value ? 'unknown') readStream upTo: $.), '.', |
|
443 (selectedFileFilter reversed readStream upTo: $.) reversed). |
|
444 |
|
445 self readDirectory. |
|
446 |
|
447 |
|
448 ! ! |
|
449 |
|
450 !FileSelectionBrowser::Row methodsFor:'accessing'! |
|
451 |
|
452 baseName |
|
453 baseName isNil ifTrue: [baseName := fileName baseName]. |
|
454 ^ baseName |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 ! |
|
461 |
|
462 fileName |
|
463 ^ fileName |
|
464 |
|
465 ! |
|
466 |
|
467 fileName: aFileName |
|
468 fileName := aFileName |
|
469 |
|
470 ! |
|
471 |
|
472 group |
|
473 group isNil ifTrue:[ |
|
474 self validateAttributes |
|
475 ]. |
|
476 ^ group |
|
477 ! |
|
478 |
|
479 iconOn:aGC |
|
480 |icon| |
|
481 |
|
482 iconKey isNil ifTrue:[ |
|
483 self validateAttributes. |
|
484 ]. |
|
485 (iconKey == #image) | (iconKey == #imageFile) |
|
486 ifTrue: |
|
487 [ |
|
488 Object errorSignal handle: [:ex|] |
|
489 do: |
|
490 [ |
|
491 ((size < 5000) and: [(icon := Image fromFile: fileName name) notNil]) |
|
492 ifTrue: [aGC registerImage: icon key:(iconKey :=fileName name asSymbol).] |
|
493 ]. |
|
494 ]. |
|
495 (icon := aGC registeredImageAt:iconKey) isNil ifTrue:[ |
|
496 self registerIconsOn:aGC. |
|
497 icon := aGC registeredImageAt:iconKey. |
|
498 ]. |
|
499 ^ icon |
|
500 |
|
501 |
|
502 |
|
503 ! |
|
504 |
|
505 modified |
|
506 ^ modified |
|
507 |
|
508 ! |
|
509 |
|
510 owner |
|
511 owner isNil ifTrue:[ |
|
512 self validateAttributes |
|
513 ]. |
|
514 ^ owner |
|
515 |
|
516 |
|
517 ! |
|
518 |
|
519 permissions |
|
520 permissions isNil ifTrue:[ |
|
521 self validateAttributes |
|
522 ]. |
|
523 ^ permissions |
|
524 |
|
525 |
|
526 ! |
|
527 |
|
528 size |
|
529 size isNil ifTrue:[ |
|
530 self validateAttributes |
|
531 ]. |
|
532 ^ size |
|
533 |
|
534 ! ! |
|
535 |
|
536 !FileSelectionBrowser::Row methodsFor:'private'! |
|
537 |
|
538 registerIconsOn:aGC |
|
539 "register all file icons on the gc |
|
540 " |
|
541 |directory| |
|
542 |
|
543 directory := 'xpmBitmaps/document_images/'. |
|
544 |
|
545 #( |
|
546 (#file 'tiny_file_plain.xpm' ) |
|
547 (#fileLink 'tiny_file_link.xpm' ) |
|
548 (#fileLocked 'tiny_file_lock.xpm' ) |
|
549 (#imageFile 'tiny_file_pix.xpm' ) |
|
550 |
|
551 ) do:[:el| |
|
552 aGC registerImage:(Image fromFile:(directory, el last)) key:(el first) |
|
553 ]. |
|
554 |
|
555 |
|
556 |
|
557 |
|
558 |
|
559 ! |
|
560 |
|
561 validateAttributes |
|
562 |info mode| |
|
563 |
|
564 permissions := String new:9 withAll:$-. |
|
565 |
|
566 (info := fileName info) isNil ifTrue:[ |
|
567 iconKey := #fileLocked. |
|
568 size := owner := group := '?'. |
|
569 ^ self |
|
570 ]. |
|
571 size := info size. |
|
572 modified := info modified printString. |
|
573 owner := OperatingSystem getUserNameFromID:(info uid). |
|
574 group := OperatingSystem getGroupNameFromID:(info gid). |
|
575 mode := info mode. |
|
576 |
|
577 1 to:9 by:3 do:[:i| |
|
578 (mode bitAt:i ) == 1 ifTrue:[permissions at:10 - i put:$x]. |
|
579 (mode bitAt:i + 1) == 1 ifTrue:[permissions at:9 - i put:$w]. |
|
580 (mode bitAt:i + 2) == 1 ifTrue:[permissions at:8 - i put:$r]. |
|
581 ]. |
|
582 |
|
583 fileName isReadable ifTrue:[ |
|
584 info type == #symbolicLink ifTrue:[ |
|
585 iconKey == #fileLink |
|
586 ] ifFalse:[ |
|
587 (Image isImageFileSuffix:(fileName suffix)) ifTrue:[ |
|
588 iconKey := #imageFile |
|
589 ] ifFalse:[ |
|
590 iconKey := #file |
|
591 ] |
|
592 ] |
|
593 ] ifFalse:[ |
|
594 iconKey := #fileLocked |
|
595 ]. |
|
596 |
|
597 ! ! |
|
598 |
|
599 !FileSelectionBrowser class methodsFor:'documentation'! |
|
600 |
|
601 version |
|
602 ^ '$Header$' |
|
603 ! ! |
|