--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AbstractFileApplicationNoteBookComponent.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,187 @@
+"{ Package: 'stx:libtool' }"
+
+ApplicationModel subclass:#AbstractFileApplicationNoteBookComponent
+ instanceVariableNames:'sameFileIndex item type notifyChannel'
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+
+!AbstractFileApplicationNoteBookComponent class methodsFor:'defaults'!
+
+tabStringFor:aApplicationType
+
+ ^ nil
+! !
+
+!AbstractFileApplicationNoteBookComponent class methodsFor:'queries'!
+
+canOpenItem:aItem
+
+"
+ example:
+ ^ (aItem suffix == 'cc')
+"
+ ^ false
+!
+
+wantNewApplicationAnyway
+
+ ^ true
+! !
+
+!AbstractFileApplicationNoteBookComponent methodsFor:'accessing'!
+
+notifyChannel
+
+ notifyChannel isNil ifTrue:[
+ self masterApplication notNil ifTrue:[
+ notifyChannel := masterApplication notifyChannel.
+ ] ifFalse:[
+ notifyChannel := ValueHolder with:''.
+ ].
+ ].
+ ^ notifyChannel
+!
+
+sameFileIndex
+
+ ^ sameFileIndex
+!
+
+sameFileIndex:something
+
+ sameFileIndex := something.
+! !
+
+!AbstractFileApplicationNoteBookComponent methodsFor:'actions'!
+
+changeItem:aItem
+
+ ^ self item:aItem.
+!
+
+doClose
+ |master|
+
+ "/ tell the NoteBookApplication to close me
+ (master := self masterApplication) notNil ifTrue:[
+ master closeSubCanvas:self.
+ ] ifFalse:[
+ self closeRequest.
+ ].
+! !
+
+!AbstractFileApplicationNoteBookComponent methodsFor:'queries'!
+
+fileName
+
+ item notNil ifTrue:[
+ ^ item fileName.
+ ].
+ ^ nil
+!
+
+getDirWithoutFileName:aFileName
+
+ | dir |
+ aFileName isNil ifTrue:[
+ ^ aFileName.
+ ].
+ dir := aFileName asFilename.
+ dir isDirectory ifFalse:[
+ dir := dir directory.
+ ].
+ ^ dir.
+!
+
+getTabString
+
+" get the tab string from the application list on the class side "
+
+ | stream string firstString endString|
+
+ stream := WriteStream on:''.
+ firstString := self class tabStringFor:type.
+ firstString isNil ifTrue:[
+ "/ default take the class name
+ firstString := self className.
+ ].
+ stream nextPutAll:firstString.
+ endString := self getTabStringEnd.
+ endString notNil ifTrue:[
+ stream space.
+ stream nextPutAll:endString.
+ ].
+ string := stream contents.
+ stream close.
+ ^ string.
+!
+
+getTabStringEnd
+
+" get the tab string from the application list on the class side "
+
+ | stream string|
+
+ self item notNil ifTrue:[
+ stream := WriteStream on:''.
+ stream nextPutAll:self fileName baseName.
+ stream space.
+ self sameFileIndex notNil ifTrue:[
+ stream nextPutAll:self sameFileIndex asString.
+ ].
+ string := stream contents.
+ stream close.
+ ^ string.
+ ].
+ ^ nil
+!
+
+isEmbeddedApplication
+
+ ^ self masterApplication notNil
+!
+
+isModified
+
+ ^ false
+!
+
+item
+
+ ^ item
+!
+
+item:aItem
+
+ item := aItem.
+ ^ true
+!
+
+presentation
+
+ ^ nil
+!
+
+type
+
+ ^ type
+!
+
+type:aType
+
+ type := aType
+!
+
+wantChangeAnyWay
+
+ ^ (self type == #directoryDescription)
+! !
+
+!AbstractFileApplicationNoteBookComponent class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/AbstractFileApplicationNoteBookComponent.st,v 1.1 2002-09-25 08:00:15 penk Exp $'
+! !
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AbstractFileBrowser.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,4156 @@
+"{ Package: 'stx:libtool' }"
+
+ApplicationModel subclass:#AbstractFileBrowser
+ instanceVariableNames:'aspects'
+ classVariableNames:'DefaultCommandPerMIME SettingsAspects RuntimeAspects
+ DirectoryBookmarks LastEnforcedNameSpace CommandHistory
+ DefaultCommandPerSuffix CommandHistorySize LastFileDiffFile'
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+AbstractFileBrowser class instanceVariableNames:'DisabledCursorImage EnabledCursorImage'
+
+"
+ The following class instance variables are inherited by this class:
+
+ ApplicationModel - ClassResources
+ Model -
+ Object -
+"
+!
+
+Object subclass:#Clipboard
+ instanceVariableNames:'method files'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:AbstractFileBrowser
+!
+
+Object subclass:#CodeExecutionLock
+ instanceVariableNames:'locked'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:AbstractFileBrowser
+!
+
+OrderedCollection subclass:#DirectoryHistory
+ instanceVariableNames:'index'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:AbstractFileBrowser
+!
+
+OrderedSet subclass:#FilenameHistory
+ instanceVariableNames:''
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:AbstractFileBrowser
+!
+
+Object subclass:#SaveAspectItem
+ instanceVariableNames:'value isHolder'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:AbstractFileBrowser
+!
+
+
+!AbstractFileBrowser class methodsFor:'classAccess'!
+
+filenameHistoryClass
+
+ ^ FilenameHistory
+! !
+
+!AbstractFileBrowser class methodsFor:'defaults'!
+
+UnixVNCCommand
+
+ ^ 'Xvnc'
+!
+
+commandHistory
+
+ CommandHistory isNil ifTrue:[
+ CommandHistory := OrderedCollection new.
+ ].
+ ^ CommandHistory
+!
+
+commandHistorySize
+
+ CommandHistorySize isNil ifTrue:[
+ CommandHistorySize := 50
+ ].
+ ^ CommandHistorySize
+!
+
+defaultCommandPerMIME
+
+ DefaultCommandPerMIME isNil ifTrue:[
+ self initializeDefaultCommands
+ ].
+ ^ DefaultCommandPerMIME
+!
+
+defaultFilterList
+
+ DefaultFilters isNil ifTrue:[
+ DefaultFilters := #( '*'
+ '*.st'
+ '*.htm*'
+ '*.txt'
+ '*.gif'
+ '*.xpm'
+ '*.jpg'
+ '*.[h,c]*'
+ )
+ ].
+ ^ DefaultFilters.
+!
+
+directoryBookmarks
+
+ DirectoryBookmarks isNil ifTrue:[
+ DirectoryBookmarks := OrderedCollection new.
+ DirectoryBookmarks add:Filename homeDirectory asAbsoluteFilename.
+ DirectoryBookmarks add:Filename tempDirectory.
+ DirectoryBookmarks add:Filename currentDirectory asAbsoluteFilename.
+ Smalltalk systemPath do:[:path |
+ ((path ~= '.') and:[path asFilename exists]) ifTrue:[
+ DirectoryBookmarks add:path asFilename.
+ ]
+ ]
+ ].
+ ^ DirectoryBookmarks
+
+"/ DirectoryBookmarks := nil
+!
+
+initializeDefaultCommands
+ DefaultCommandPerMIME := Dictionary new.
+
+ DefaultCommandPerMIME at:'application/x-tar-compressed' put:'gunzip < %1 | tar tvf -'.
+ DefaultCommandPerMIME at:'application/pdf' put:'acroread -display %2 %1'.
+
+ "
+ self initializeDefaultCommands
+ "
+!
+
+listOfRuntimeValuesToRemark
+
+ " list of all aspects that will be saved with save settings"
+
+ ^ #(
+ #filterModel
+ #enableFileHistory
+ #enableBack
+ #enableForward
+ #dirHistory
+ #fileHistory
+ #currentFileNameHolder
+ )
+!
+
+listOfSavedSettingsAspects
+
+ " list of all aspects that will be saved with save settings"
+
+ ^ #(
+ #viewDirectoriesInDirectoryContentsBrowser
+ #sortCaseless
+ #fileHistory
+ #showDirectoryTreeHolder
+ #showHiddenFiles
+ #viewDescription
+ #viewDetails
+ #viewDirectoryDescription
+ #viewFilesInDirectoryTree
+ #viewGroup
+ #viewOwner
+ #viewPermissions
+ #viewPreview
+ #viewSize
+ #viewTime
+ #viewType
+ #enableFileHistory
+ #openMultipleApplicationsForType
+ #sortBlockHolder
+ #filenameEntryFieldVisibleHolder
+ #toolBarVisibleHolder
+ )
+!
+
+resetAspects
+
+ RuntimeAspects := nil.
+ SettingsAspects := nil.
+
+"
+ self resetAspects
+"
+!
+
+runtimeAspects
+
+ RuntimeAspects isNil ifTrue:[
+ RuntimeAspects := Dictionary new.
+ ].
+ ^ RuntimeAspects
+!
+
+settingsAspects
+
+ SettingsAspects isNil ifTrue:[
+ SettingsAspects := Dictionary new.
+ ].
+ ^ SettingsAspects
+! !
+
+!AbstractFileBrowser class methodsFor:'image'!
+
+DisabledCursorImage
+
+ DisabledCursorImage isNil ifTrue:[
+ DisabledCursorImage := Image fromFile:'xpmBitmaps/cursors/no_entry.xpm'
+ ].
+ ^ DisabledCursorImage
+!
+
+EnabledCursorImage
+
+ EnabledCursorImage isNil ifTrue:[
+ EnabledCursorImage := Image fromFile:'xpmBitmaps/cursors/double_crossHair.xpm'
+ ].
+ ^ EnabledCursorImage
+! !
+
+!AbstractFileBrowser class methodsFor:'image specs'!
+
+clearHistoryIcon
+ ^ Icon deleteIcon
+!
+
+closeIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self closeIcon inspect
+ ImageEditor openOnClass:self andSelector:#closeIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class closeIcon'
+ ifAbsentPut:[(Depth8Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ H@@@@@@@@@@@@B@ @@@@@@@@@@@@HB@ @@@@@@@@@B@ H@@@@@@@@@@@@@@ HB@@@@@@@B@ H@@@@@@@@@
+@@@@@@@B@ H@@@@B@ H@@@@@@@@@@@@@@@@@@@HB@ @B@ H@@@@@@@@@@@@@@@@@@@@@@ HB@ H@@@@@@@@@@@@@@@@@@@@@@@@B@ H@@@@@@@@@@@@@@@@@
+@@@@@@@B@ HB@ @@@@@@@@@@@@@@@@@@@@@B@ H@@ HB@@@@@@@@@@@@@@@@@@@B@ H@@@@B@ H@@@@@@@@A@@@@@@@B@ H@@@@@@@HB@ @@@@@@@@@@@@@B
+@ H@@@@@@@@@@ HB@@@@@@@@@@@@@ H@@@@@@@@@@@@B@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A@@@@@@@@@@@@@@@@@@@@@@@@@PD@@P@@
+@@DA@@@@@PD@@@DA@@@@@P@@@@D@@@D@@@D@@P@@@@D@@@D@@@D@@@@A@@@A@@@A@@@A@@@A@PDA@@@A@@@@@P@@@P@@@P@@@@D@@P@@@@@@@@DA@@DA@@@A
+@P@@@PD@@@@A@P@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[255 255 255 0 0 0 255 0 0]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@A C@A0G@@8N@@\\@@N8@@G0@@C @@G0@@N8@@\\B@8N@A0G@A C@@@@@A@@@MFL0QIQHQII8QIE@M&X0@@@@') ; yourself); yourself]
+!
+
+copyIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary copy20x20Icon "copy28x28Icon"
+!
+
+cutIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary cut20x20Icon2 "cut28x28Icon"
+!
+
+deleteIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary erase20x20Icon "/ delete28x28Icon
+!
+
+diffIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self diffIcon inspect
+ ImageEditor openOnClass:self andSelector:#diffIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class diffIcon'
+ ifAbsentPut:[(Depth8Image new) width: 26; height: 22; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@A@PDA@PDA@PD@@@@@@@@@@@@@@@@@@@@@@@DA XFA XFA P@@@@@@@@@@@@@@@@@@@@@@@PFA XF@@@@@@@@@@@@@@@@@@@@@@@@@@@@A@XFA @F
+A XD@@@@@@@@@@@@@@@@@@@@@@@DA X@A XFA P@@@@@@@@@@@@@@@@@@@@@@@PFA @FA XFA@@@@@@@@@@@@@@@@@@@@@@@A@XF@@XFA XD@@@@@@@@@@@@
+@@@@@@@@@@@DA X@A XFA P@@@@@@@@@@@@@@@@@@@@@@@PFA X@A XFA@@@@@@@@@@@@@@@@@@@@@@@A@XFA X@@@@@@@@@@@@@@@@@@@@@@@@@@@@DA XF
+A XFA P@@@@@@@@@@@@@@@@@@@@@@@PFA XFA XFA@@@@@@@@@@@@@@@@@@@@@@@A@PDA@PDA@PD@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 129 129 129 0 0 0 194 194 194 132 132 132 198 198 198 255 255 255]; mask:((Depth1Image new) width: 26; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@?8@@@O>@@@C? @@@?<@@@O> @@C?(@@@?:@@@O> @@C?8@@@??@@@O>8@@C?''@@@?80@@@@@@@@T[@@@DI@@@GSX@@BT$@@@%I@@@IRP@@A4$@@@@@@@@@@a') ; yourself); yourself]
+!
+
+fileInIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary fileIn20x20Icon
+!
+
+goHomeIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self goHomeIcon inspect
+ ImageEditor openOnClass:self andSelector:#goHomeIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class goHomeIcon'
+ ifAbsentPut:[(Depth4Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@H@@@@@@@@@@@@@I4@@@@@@@@@@@@H"]@@@@@@@@@@@H''A7P@@@@@@@@@H''FA]D@@@@@@@@I7FC W]@@@@@@@I7FCL8DWP@@@@@
+@''FCL3NA]D@@@@H''FCL3L3 WQ@@@I7FCL3L3L8E7PDPQFCL1DQL3"@@DQADXL1DQDSNH@@P@@@ 1EUUQL8 @@@@@BCDUY&D3"@@@@@@HLQU&XSNH@@@@@@ 1
+EVY!!L8 @@@@@BCDUY&D3"@@@@@@HLQU&XSNH@@@@@@ 1EVY!!L8 @@@@@BCDUY&D3"@@@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 64 0 0 255 0 0 255 255 255 129 0 0 80 194 89 60 120 60 194 0 0 161 161 161]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@A@@@C @FG0@FO8@F_<@F?>@G??@G?? G??0O??8_??<???<???<G??0G??0G??0G??0G??0G??0G??0G??0G??0') ; yourself); yourself]
+!
+
+hexToggle22x22Icon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self hexToggle22x22Icon inspect
+ ImageEditor openOnClass:self andSelector:#hexToggle22x22Icon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class hexToggle22x22Icon'
+ ifAbsentPut:[(Depth8Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@EAPTEAPTEAPTE@@@@@@@@@@@@@@@@AP@@@@T@@@@EAP@@@@@@@@@@
+@@@@@@TEAP@E@@TEAPT@@@@@@@@@@@@@@@@EAP@@AP@@APTE@@@@@@@@@@@@@@@@APTE@@T@APTEAP@@@@@@@@@@@@@@@@T@@@@E@@TEAPT@@@@@@@@@@@@@
+@@@EAPTEAPTEAPTE@@@@@@@@@@@@@@@@AP@@@@T@@@@EAP@@@@@@@@@@@@@@@@T@AP@E@@T@APT@@@@@@@@@@@@@@@@E@@@@AP@@@@TE@@@@@@@@@@@@@@@@
+AP@E@@T@AP@EAP@@@@@@@@@@@@@@@@T@AP@E@@@@APT@@@@@@@@@@@@@@@@EAPTEAPTEAPTE@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 105 133 190 129 129 129 194 194 194 255 0 0 255 255 255]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@@@@@B''Q@B$J@C&D@B$J@B''Q@') ; yourself); yourself]
+!
+
+historyIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary history20x20Icon "/ history28x28Icon
+!
+
+homeIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary home28x28Icon
+!
+
+htmlReloadIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self htmlReloadIcon inspect
+ ImageEditor openOnClass:self andSelector:#htmlReloadIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class htmlReloadIcon'
+ ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@UT@@@@@EU@D@@@@UT@@@H@AUP@@@@@EU@@@@@@EU@@@@E@EU@@@@@@EU@@@@@AUUT@@@@@UUP@@@@@EU@@@@@@AT@@@@@@@P@@@@H@@@@@@@@
+@@@@@@@@@@@@@@@H@@@@@@@@@@@@@@@G@@@@@@@J@@@@@@@I@@@@@@@@') ; colorMapFromArray:#[0 0 0 0 129 0]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@G<C@_?C@??#A?C3C>@;G<@KG<@CG<@C??$C_?NCO>_CG<?#C9?3A3?;@''??@@?#P@?C\A?COC>CG?<CC?8C@? C') ; yourself); yourself]
+!
+
+leftArrow
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self leftArrow inspect
+ ImageEditor openOnClass:self andSelector:#leftArrow
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class leftArrow'
+ ifAbsentPut:[(Depth8Image new) width: 24; height: 24; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PH@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@A@0D@@@@@@@@@@@@@@@@@@@@@@@@@@@DDAPH@@@@@@@@@@@@@@@@@@@@@@@@@@PX@A0D@@@@@@@@@@@@@@@@@@@@@@@@AB@@IB HK
+@0LA@PDK@@@@@@@@@@@@@@DL@@@MC <P@@@@DPLR@@@@@@@@@@@@@PX@@ALTEP8PDQDVE0\R@@@@@@@@@@@AAADQD1PUEQTNF@$SFP(R@@@@@@@@@@@KB!!P[
+GAPUEQT]GQ4]GP(R@@@@@@@@@@@@D (TG!!0TEA,_G1<[H@(R@@@@@@@@@@@@@AHJC!!< GQ4JB (JB"DK@@@@@@@@@@@@@@@RB 8^B DRD!!HRD!!HK@@@@@@@@
+@@@@@@@@D (]H H@@@@@@@@@@@@@@@@@@@@@@@@@@AHJHPD@@@@@@@@@@@@@@@@@@@@@@@@@@@@K@PH@@@@@@@@@@@@@@@@@@@@@@@@@@@@@B0D@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[224 224 224 0 32 64 0 32 96 32 64 96 96 128 160 64 96 128 128 160 192 32 96 128 128 160 160 160 192 224 0 96 128 0 0 0 128 128 160 64 192 192 32 160 192 64 128 192 128 192 224 192 224 224 0 0 32 96 192 224 0 160 192 0 128 192 160 224 224 96 160 192 128 192 192 64 160 192 192 192 192 32 192 192 0 192 224 0 128 160 32 192 224 64 192 224 0 192 192 0 64 96 0 64 128]; mask:((Depth1Image new) width: 24; height: 24; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@B@@@F@@@N@@@^@@@>@@A??@C??@G??@O??@O??@G??@C??@A??@@>@@@^@@@N@@@F@@@B@@@@@@@@@@@@@@@@@@') ; yourself); yourself]
+!
+
+leftArrow20x20Icon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self leftArrow20x20Icon inspect
+ ImageEditor openOnClass:self andSelector:#leftArrow20x20Icon
+ Icon flushCachedIcons
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class leftArrow20x20Icon'
+ ifAbsentPut:[(Depth8Image new) width: 20; height: 20; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@P@@@@@@@@@@@@@@@@@@@@@@@@DB@@@@@@@@@@@@@@@@@@@@@@@A@0D@@@@@@@@@@@@@@@@@@@@@@PPE
+@ @@@@@@@@@@@@@@@@@@@@DF@@\A@@@@@@@@@@@@@@@@@@@AB@@IB HK@0LA@PDK@@@@@@@@@P0@@@4NC1@@@@@Q@1H@@@@@@@DF@@@SEATNDADQE!!\GD @@
+@@@AAADQD1PUEQTNF@$SFP(R@@@@@@,JEA,\EATUEQ4]GQ4]B!!H@@@@@@AHJEA8\EAP[G1<_F2@JD @@@@@@@AHJC!!< GQ4JB (JB"DK@@@@@@@@@AHJC!!8J
+@QHRD!!HRD ,@@@@@@@@@@AHJGRHB@@@@@@@@@@@@@@@@@@@@@AHJHPD@@@@@@@@@@@@@@@@@@@@@@@,A@ @@@@@@@@@@@@@@@@@@@@@@@@,A@@@@@@@@@@@@
+@@@@@@@@@@@@@@,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[224 224 224 0 32 64 0 32 96 32 64 96 96 128 160 64 96 128 128 160 192 32 96 128 128 160 160 160 192 224 0 96 128 0 0 0 128 128 160 64 192 192 32 160 192 64 128 192 128 192 224 192 224 224 0 0 32 96 192 224 0 160 192 0 128 192 160 224 224 96 160 192 128 192 192 64 160 192 192 192 192 32 192 192 0 192 224 0 128 160 32 192 224 64 192 224 0 192 192 0 64 96 0 64 128]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@B@@@F@@@N@@@^@@@>@@A??@C??@G??@O??@O??@G??@C??@A??@@>@@@^@@@N@@@F@@@B@@@@@@') ; yourself); yourself]
+!
+
+leftArrow20x20PlusMenuIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self leftArrow20x20PlusMenuIcon inspect
+ ImageEditor openOnClass:self andSelector:#leftArrow20x20PlusMenuIcon
+ Icon flushCachedIcons
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class leftArrow20x20PlusMenuIcon'
+ ifAbsentPut:[(Depth8Image new) width: 20; height: 20; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@A@ @@@@@@@@@@@@@@@@@@@@@@@PLA@@@@@@@@@@@@@@@@@@@@@@DD
+APH@@@@@@@@@@@@@@@@@@@@AA @G@P@@@@@@@@@@@@@@@@@@@P @BP(BB0LC@PDAB0@@@@@@@@DL@@@MC <P@@@@DPLR@@@@@@@AA @@D1PUC!!@QDQXWA1H@
+@@@@@PPQDQLTEQTUC!! ID1$JD @@@@@KB!!P[GAPUEQT]GQ4]GP(R@@@@@@@RB!!P^GAPTF1<_G1, B!!H@@@@@@@@RB 8_HA4]B (JB (!!B0@@@@@@@@@RB 8^
+B DRD!!HRD!!HK@@@@@@@@@@@RB!!4"@ @@@@@@@@@@@@@@@@@@@@@RB"DA@@@@@@@@@@@KB0,KB0,K@@@K@PH@@@@@@@@@@@@KB0,KB0@@@@@K@P@@@@@@@@@@
+@@@KB0,@@@@@@@@K@@@@@@@@@@@@@@@K@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[224 224 224 0 32 64 0 32 96 32 64 96 96 128 160 64 96 128 128 160 192 32 96 128 128 160 160 160 192 224 0 96 128 0 0 0 128 128 160 64 192 192 32 160 192 64 128 192 128 192 224 192 224 224 0 0 32 96 192 224 0 160 192 0 128 192 160 224 224 96 160 192 128 192 192 64 160 192 192 192 192 32 192 192 0 192 224 0 128 160 32 192 224 64 192 224 0 192 192 0 64 96 0 64 128]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@A@@@C@@@G@@@O@@@_@@@?? A?? C?? G?? G?? C?? A?? @?? @_@@@O@@?''@@_C@@NA@@D@@@') ; yourself); yourself]
+!
+
+leftArrowPlusMenu
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self leftArrowPlusMenu inspect
+ ImageEditor openOnClass:self andSelector:#leftArrowPlusMenu
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class leftArrowPlusMenu'
+ ifAbsentPut:[(Depth8Image new) width: 24; height: 24; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PH@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@A@0D@@@@@@@@@@@@@@@@@@@@@@@@@@@DDAPH@@@@@@@@@@@@@@@@@@@@@@@@@@PX@A0D@@@@@@@@@@@@@@@@@@@@@@@@AB@@IB HK
+@0LA@PDK@@@@@@@@@@@@@@DL@@@MC <P@@@@DPLR@@@@@@@@@@@@@PX@@ALTEP8PDQDVE0\R@@@@@@@@@@@AAADQD1PUEQTNF@$SFP(R@@@@@@@@@@@KB!!P[
+GAPUEQT]GQ4]GP(R@@@@@@@@@@@@D (TG!!0TEA,_G1<[H@(R@@@@@@@@@@@@@AHJC!!< GQ4JB (JB"DK@@@@@@@@@@@@@@@RB 8^B DRD!!HRD!!HK@@@@@@@@
+@@@@@@@@D (]H H@@@@@@@@@@@@@@@@@@@@@@@@@@AHJHPD@@@@@@@@@@@@@@@@@@@@@@@@@@@@K@PH@@@@@@@@@@@@@@@@@@@@@@@@@@@@@B0D@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@,@@@@@@@@KB0,KB0,K@@@@@@@@@@@@@@@@@@@@@@@@B0,KB0,@@@@@@@@@@@@@@@@@@@@@@@@@@@,KB0@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@K@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[224 224 224 0 32 64 0 32 96 32 64 96 96 128 160 64 96 128 128 160 192 32 96 128 128 160 160 160 192 224 0 96 128 0 0 0 128 128 160 64 192 192 32 160 192 64 128 192 128 192 224 192 224 224 0 0 32 96 192 224 0 160 192 0 128 192 160 224 224 96 160 192 128 192 192 64 160 192 192 192 192 32 192 192 0 192 224 0 128 160 32 192 224 64 192 224 0 192 192 0 64 96 0 64 128]; mask:((Depth1Image new) width: 24; height: 24; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@B@@@F@@@N@@@^@@@>@@A??@C??@G??@O??@O??@G??@C??@A??@@>@@@^@@@N@@@F@@@BA?@@@>@@@\@@@H@@@@') ; yourself); yourself]
+!
+
+leftDownIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self leftDownIcon inspect
+ ImageEditor openOnClass:self andSelector:#leftDownIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class leftDownIcon'
+ ifAbsentPut:[(Depth2Image new) width: 28; height: 28; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+UUUUUUUUUUUPAUUUUUUUP@UUUUUUUPB!!UUUUUU@B*AUUUUU@B*(UUUUUPB** UUUUPB***AUUUTB***(EUUUB****%UUUR*****UUUUU@*%UUUUUUPJ)UUUU
+UUTB*UUUUUUU@*%UUUUUUPJ)UUUUUUTB*UUUUUUU@*%UUUUUUPJ)UUUUUUTB*UUUUUUU@*$@@@@AUPJ*****)UTB******UU@******%UPJ*****)UTAUUUU
+UUUU@@@@@@@AUUUUUUUUUP@a') ; colorMapFromArray:#[255 255 255 0 0 0 40 40 100 255 0 0]; mask:((Depth1Image new) width: 28; height: 28; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@ @@@@\@@@@O @@@G<@@@C? @@A?<@@@?? @@_?<@@G?? @@C<@@@@?@@@@O0@@@C<@@@@?@@@@O0@@@C<@@@@?@@@@O0@@@C??? @???8@O?
+?>@C??? @???8@O??>@@@@@@@@@@@@@a') ; yourself); yourself]
+!
+
+leftIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self leftIcon inspect
+ ImageEditor openOnClass:self andSelector:#leftIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class leftIcon'
+ ifAbsentPut:[(Depth2Image new) width: 28; height: 28; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUPUUUUUUUUPUUUUUUUUP%UUUUUUUP)UUUUUUUP*P@@@@@AP*$@@@@@@P*******
+*P********$********)J********U********%V*%UUUUUUUZ)UUUUUUUP*UUUUUUUUV%UUUUUUUUYUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
+UUUUUUUUUUUUUUUUUUUUUP@a') ; colorMapFromArray:#[255 255 255 0 0 0 40 40 100 255 0 0]; mask:((Depth1Image new) width: 28; height: 28; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@H@@@@F@@@@C @@@A8@@@@>@@@@_???0O???<G????C????0_???<C????@_???0C8@@@@^@@@@C @@@@X@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; yourself); yourself]
+!
+
+menuHistoryList9x20Icon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self menuHistoryList9x20Icon inspect
+ ImageEditor openOnClass:self andSelector:#menuHistoryList9x20Icon
+ Icon flushCachedIcons
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class menuHistoryList9x20Icon'
+ ifAbsentPut:[(Depth1Image new) width: 9; height: 20; photometric:(#palette); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@A0@G@@\@A0@G@@\@A0@G@@\@A0@G@A?@C8@G@@H@G<@@@@@@@@a') ; colorMapFromArray:#[255 255 255 0 0 0]; mask:((Depth1Image new) width: 9; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@A0@G@@\@A0@G@@\@A0@G@@\@A0@G@A?@C8@G@@H@G<@@@@@@@@a') ; yourself); yourself]
+!
+
+menuHistoryListIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self menuHistoryListIcon inspect
+ ImageEditor openOnClass:self andSelector:#menuHistoryListIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class menuHistoryListIcon'
+ ifAbsentPut:[(Depth1Image new) width: 12; height: 12; photometric:(#palette); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'??S?<O?0??C?<O?0??/?=_?0??C?<O?0') ; colorMapFromArray:#[255 255 255 0 0 0]; mask:((Depth1Image new) width: 12; height: 12; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@O@@<@C0A?8C?@G8@O@@X@@@A?8@@@') ; yourself); yourself]
+!
+
+pasteIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary paste20x20Icon "/ paste28x28Icon
+!
+
+rightArrow
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self rightArrow inspect
+ ImageEditor openOnClass:self andSelector:#rightArrow
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class rightArrow'
+ ifAbsentPut:[(Depth8Image new) width: 24; height: 24; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@P@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PH@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@0PB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PTF@ @@@@@@@@@@@@@@@@@@@@@@@@@@@0\@A@H@@@@@@@@@@@@@@@@A@PDA@PDH@P\I
+@@XB@@@@@@@@@@@@@@@AA0(@@@@@B ,LB @D@ @@@@@@@@@@@@@MB \NB ,ODADRD0(@A H@@@@@@@@@@@@M@@TTEQLQE!!\WD 0K@@PB@@@@@@@@@@@MB <W
+E1\WD!!\WD!!LYDQ(B@@@@@@@@@@@AB <[D10[GQ8QG!!$QF H@@@@@@@@@@@@AA!!(ZF!!(ZE1H^FQDZ@ @@@@@@@@@@@@@A@ HB@ HB@1DYDQ(B@@@@@@@@@@@@
+@@@@@@@@@@@@@QXQF H@@@@@@@@@@@@@@@@@@@@@@@@@@0PZ@ @@@@@@@@@@@@@@@@@@@@@@@@@@@Q(B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@0H@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@P@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[224 224 224 0 32 64 0 0 0 0 64 96 32 128 160 128 160 192 32 96 128 128 192 192 0 64 64 160 192 192 192 224 224 160 192 224 96 192 224 32 64 96 160 224 224 128 192 224 96 160 192 0 160 192 0 128 192 64 192 192 64 160 192 96 192 192 32 160 192 0 128 160 192 192 192 64 224 224 0 96 128 32 192 192 64 192 224 0 192 224 0 192 192]; mask:((Depth1Image new) width: 24; height: 24; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@D@@@F@@@G@@@G @@G0@O?8@O?<@O?>@O??@O??@O?>@O?<@O?8@@G0@@G @@G@@@F@@@D@@@@@@@@@@@@@@@@@@') ; yourself); yourself]
+!
+
+rightArrow20x20Icon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self rightArrow20x20Icon inspect
+ ImageEditor openOnClass:self andSelector:#rightArrow20x20Icon
+ Icon flushCachedIcons
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class rightArrow20x20Icon'
+ ifAbsentPut:[(Depth8Image new) width: 20; height: 20; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A@@@@@@@@@@@@@@@@@@@@@@@@@@DB@@@@@@@@@@@@@@@@@@@@@@@@@0PB@@@@@@@@@@@@@@@@@@@@@@@A
+APXB@@@@@@@@@@@@@@@@@@@@@@LG@@PB@@@@@@@@@@@A@PDA@PDH@P\I@@XB@@@@@@@@@@DGB @@@@@JB00J@@PB@@@@@@@@CP(GC (KC1@QD!!LJ@@XB@@@@
+@@@M@@TTEQLQE!!\WD 0K@@PB@@@@@@4JC1\WE1\RE1\RD1$QF H@@@@@@P(OF1L\F14^DQ8YDQ(B@@@@@@@AA!!(ZF!!(ZE1H^FQDZ@ @@@@@@@@DB@ HB@ HC
+DQ$QF H@@@@@@@@@@@@@@@@@@@DVDQ(B@@@@@@@@@@@@@@@@@@@@@0PZ@ @@@@@@@@@@@@@@@@@@@@@AF H@@@@@@@@@@@@@@@@@@@@@@@LB@@@@@@@@@@@@
+@@@@@@@@@@@@@P@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[224 224 224 0 32 64 0 0 0 0 64 96 32 128 160 128 160 192 32 96 128 128 192 192 0 64 64 160 192 192 192 224 224 160 192 224 96 192 224 32 64 96 160 224 224 128 192 224 96 160 192 0 160 192 0 128 192 64 192 192 64 160 192 96 192 192 32 160 192 0 128 160 192 192 192 64 224 224 0 96 128 32 192 192 64 192 224 0 192 224 0 192 192]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@D@@@F@@@G@@@G @@G0@O?8@O?<@O?>@O??@O??@O?>@O?<@O?8@@G0@@G @@G@@@F@@@D@@@@@@') ; yourself); yourself]
+!
+
+rightArrowPlusMenu
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self rightArrowPlusMenu inspect
+ ImageEditor openOnClass:self andSelector:#rightArrowPlusMenu
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class rightArrowPlusMenu'
+ ifAbsentPut:[(Depth8Image new) width: 24; height: 24; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@P@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PH@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@0PB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PTF@ @@@@@@@@@@@@@@@@@@@@@@@@@@@0\@A@H@@@@@@@@@@@@@@@@A@PDA@PDH@P\I
+@@XB@@@@@@@@@@@@@@@AA0(@@@@@B ,LB @D@ @@@@@@@@@@@@@MB \NB ,ODADRD0(@A H@@@@@@@@@@@@M@@TTEQLQE!!\WD 0K@@PB@@@@@@@@@@@MB <W
+E1\WD!!\WD!!LYDQ(B@@@@@@@@@@@AB <[D10[GQ8QG!!$QF H@@@@@@@@@@@@AA!!(ZF!!(ZE1H^FQDZ@ @@@@@@@@@@@@@A@ HB@ HB@1DYDQ(B@@@@@@@@@@@@
+@@@@@@@@@@@@@QXQF H@@@@@@@@@@@@@@@@@@@@@@@@@@0PZ@ @@@@@@@@@@@@@@@@@@@@@@@@@@@Q(B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@0H@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@P@@@@@@@@@B@ HB@ HB@@@@@@@@@@@@@@@@@@@@@@@@@ HB@ H@@@@@@@@@@@@@@@@@@@@@@@@@@@HB@ @@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[224 224 224 0 32 64 0 0 0 0 64 96 32 128 160 128 160 192 32 96 128 128 192 192 0 64 64 160 192 192 192 224 224 160 192 224 96 192 224 32 64 96 160 224 224 128 192 224 96 160 192 0 160 192 0 128 192 64 192 192 64 160 192 96 192 192 32 160 192 0 128 160 192 192 192 64 224 224 0 96 128 32 192 192 64 192 224 0 192 224 0 192 192]; mask:((Depth1Image new) width: 24; height: 24; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@D@@@F@@@G@@@G @@G0@O?8@O?<@O?>@O??@O??@O?>@O?<@O?8@@G0@@G @@G@@@F@@@DA?@@@>@@@\@@@H@@@@') ; yourself); yourself]
+!
+
+rightArrowPlusMenu20x20Icon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self rightArrowPlusMenu20x20Icon inspect
+ ImageEditor openOnClass:self andSelector:#rightArrowPlusMenu20x20Icon
+ Icon flushCachedIcons
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class rightArrowPlusMenu20x20Icon'
+ ifAbsentPut:[(Depth8Image new) width: 20; height: 20; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@@@PH@@@@@@@@@@@@@@@@@@@@@@@@CA@H@@@@@@@@@@@@@@@@@@@@@@@DE
+A H@@@@@@@@@@@@@@@@@@@@@@0\@A@H@@@@@@@@@@@DA@PDA@P AA0$@A H@@@@@@@@@@P\J@@@@@@(KC@(@A@H@@@@@@@@MB \NB ,ODADRD0(@A H@@@@@
+@@4@AQPUD1DVE1\RC@,@A@H@@@@@CP(OE1\WE1HWE1HSFQDZ@ @@@@@AB <[D10[GQ8QG!!$QF H@@@@@@@DFF!!(ZF!!(WD!!8YDQ(B@@@@@@@@@PHB@ HB@ LQ
+FQDZ@ @@@@@@@@@@@@@@@@@@@QXQF H@@@@@@@@@@@@@@@@@@@@CAA(B@@@@@@@@@@@@@@@@@@@@@@DZ@ @@@ HB@ HB@ @@@@@@@@@@@0H@@@@@@ HB@ H@
+@@@@@@@@@@@A@@@@@@@@@ HB@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@a') ; colorMapFromArray:#[224 224 224 0 32 64 0 0 0 0 64 96 32 128 160 128 160 192 32 96 128 128 192 192 0 64 64 160 192 192 192 224 224 160 192 224 96 192 224 32 64 96 160 224 224 128 192 224 96 160 192 0 160 192 0 128 192 64 192 192 64 160 192 96 192 192 32 160 192 0 128 160 192 192 192 64 224 224 0 96 128 32 192 192 64 192 224 0 192 224 0 192 192]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@H@@@L@@@N@@@O@@@O @_?0@_?8@_?<@_?>@_?>@_?<@_?8@_?0@@O @@O@@@N_0@LO @HG@@@B@') ; yourself); yourself]
+!
+
+rightIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self rightIcon inspect
+ ImageEditor openOnClass:self andSelector:#rightIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class rightIcon'
+ ifAbsentPut:[(Depth2Image new) width: 28; height: 28; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTIUUUUUUUUB%UEUUUUUP*EP@@@@@@J)T@@@@@@B*%B*******
+*P********(J********B********P********PEUUUUUV*QEUUUUUP*PUUUUUUTJQUUUUUUUBQUUUUUUUPQUUUUUUUPAUUUUUUUTUUUUUUUUUUUUUUUUUUU
+UUUUUUUUUUUUUUUUUUUUUP@a') ; colorMapFromArray:#[255 255 255 0 0 0 50 50 100 255 0 0]; mask:((Depth1Image new) width: 28; height: 28; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@C@@@@@8@@@@O@@@@C8A????@_???8G????A????0_???<G???>A????@@@@O @@@C0@@@@8@@@@L@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; yourself); yourself]
+!
+
+searchIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary search16x16Icon "/ search28x28Icon
+!
+
+shellIcon
+ <resource: #programImage>
+
+ OperatingSystem isMSDOSlike ifTrue:[
+ ^ ToolbarIconLibrary dos20x20Icon
+ ].
+ ^ ToolbarIconLibrary shell20x20Icon
+!
+
+upArrow
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self upArrow inspect
+ ImageEditor openOnClass:self andSelector:#upArrow
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class upArrow'
+ ifAbsentPut:[(Depth8Image new) width: 24; height: 24; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PH@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@A@0PE@@@@@@@@@@@@@@@@@@@@@@@@@@DFA0 DAP@@@@@@@@@@@@@@@@@@@@@@@P$@A0(HA@T@@@@@@@@@@@@@@@@@@@@AB0@@C@4N
+C0PE@@@@@@@@@@@@@@@@@@DF@@@LB@ MD@<DAP@@@@@@@@@@@@@@@PLGDQHHD1LHE@8UA@H@@@@@@@@@@@@AE!!\XA@<SD1LHEPPYF DB@@@@@@@@@@D\@Q0A
+GA4OD1LJEPD\@Q0A@ @@@@@@@@@@@@@@@!!8^C1T_A@T@@@@@@@@@@@@@@@@@@@@@E @GHATRA@T@@@@@@@@@@@@@@@@@@@@@E @GDQT_A@T@@@@@@@@@@@@@
+@@@@@@@@@P@!!H!!TJA@T@@@@@@@@@@@@@@@@@@@@@@P\#IATTA@T@@@@@@@@@@@@@@@@@@@@@@QXXFPPDF H@@@@@@@@@@@@@@@@@@@@@@ TEAPTE@ H@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[224 224 224 0 32 64 0 0 0 96 128 160 0 96 128 0 0 32 128 160 192 192 224 224 0 160 192 128 128 160 32 192 192 128 160 160 96 192 224 0 192 224 32 192 224 32 160 192 64 224 224 160 192 224 64 192 192 0 128 192 0 192 192 0 128 160 32 64 96 64 96 128 32 96 128 0 64 128 0 64 96 192 192 192 0 32 96 32 128 192 128 192 224 64 192 224 128 192 192 160 224 224 96 192 192 96 160 192 64 160 192]; mask:((Depth1Image new) width: 24; height: 24; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@F@@@O@@@_ @@?0@A?8@C?<@G?>@O??@_?? @?0@@?0@@?0@@?0@@?0@@?0@@?0@@@@@@@@@@@@@@@@@@@@@') ; yourself); yourself]
+!
+
+upArrow20x20Icon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self upArrow20x20Icon inspect
+ ImageEditor openOnClass:self andSelector:#upArrow20x20Icon
+ Icon flushCachedIcons
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class upArrow20x20Icon'
+ ifAbsentPut:[(Depth8Image new) width: 20; height: 20; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@DB@@@@@@@@@@@@@@@@@@@@@@@A@0PE@@@@@@@@@@@@@@@@@@@@@PXG
+B@PE@@@@@@@@@@@@@@@@@@DI@@\JB@PE@@@@@@@@@@@@@@@AB0@@C@4NC0PE@@@@@@@@@@@@@PX@@@0HB@4PC0PE@@@@@@@@@@DCA1DRBALSBAPNEPPB@@@@
+@@@AE!!\XA@<SD1LHEPPYF DB@@@@@Q0AG@D\GP<SD0(U@Q0AG@DB@@@@@@@@@@H^G <UG0PE@@@@@@@@@@@@@@@@E @GHATRA@T@@@@@@@@@@@@@@@@V@@\Q
+EQ<DAP@@@@@@@@@@@@@@@@D@HRHUB PE@@@@@@@@@@@@@@@@@P\#IATTA@T@@@@@@@@@@@@@@@@AE!! YA@PZ@ @@@@@@@@@@@@@@@@HEAPTEAPHB@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[224 224 224 0 32 64 0 0 0 96 128 160 0 96 128 0 0 32 128 160 192 192 224 224 0 160 192 128 128 160 32 192 192 128 160 160 96 192 224 0 192 224 32 192 224 32 160 192 64 224 224 160 192 224 64 192 192 0 128 192 0 192 192 0 128 160 32 64 96 64 96 128 32 96 128 0 64 128 0 64 96 192 192 192 0 32 96 32 128 192 128 192 224 64 192 224 128 192 192 160 224 224 96 192 192 96 160 192 64 160 192]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@F@@@O@@@_ @@?0@A?8@C?<@G?>@O??@_?? @?0@@?0@@?0@@?0@@?0@@?0@@?0@@@@@@@@@') ; yourself); yourself]
+!
+
+upArrowPlusMenu
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self upArrowPlusMenu inspect
+ ImageEditor openOnClass:self andSelector:#upArrowPlusMenu
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'AbstractFileBrowser class upArrowPlusMenu'
+ ifAbsentPut:[(Depth8Image new) width: 24; height: 24; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PH@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@A@0PE@@@@@@@@@@@@@@@@@@@@@@@@@@DFA0 DAP@@@@@@@@@@@@@@@@@@@@@@@P$@A0(HA@T@@@@@@@@@@@@@@@@@@@@AB0@@C@4N
+C0PE@@@@@@@@@@@@@@@@@@DF@@@LB@ MD@<DAP@@@@@@@@@@@@@@@PLGDQHHD1LHE@8UA@H@@@@@@@@@@@@AE!!\XA@<SD1LHEPPYF DB@@@@@@@@@@D\@Q0A
+GA4OD1LJEPD\@Q0A@ @@@@@@@@@@@@@@@!!8^C1T_A@T@@@@@@@@@@@@@@@@@@@@@E @GHATRA@T@@@@@@@@@@@@@@@@@@@@@E @GDQT_A@T@@@@@@@@@@@@@
+@@@@@@@@@P@!!H!!TJA@T@@@@@@@@@@@@@@@@@@@@@@P\#IATTA@T@@@@@@@@@@@@@@@@@@@@@@QXXFPPDF H@@@@@@@@@@@@@@@@@@@@@@ TEAPTE@ H@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@B@ HB@ HB@@@@@@@@@@@@@@@@@@@@@@@@@ HB@ H@@@@@@@@@@@@@@@@@@@@@@@@@@@HB@ @@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[224 224 224 0 32 64 0 0 0 96 128 160 0 96 128 0 0 32 128 160 192 192 224 224 0 160 192 128 128 160 32 192 192 128 160 160 96 192 224 0 192 224 32 192 224 32 160 192 64 224 224 160 192 224 64 192 192 0 128 192 0 192 192 0 128 160 32 64 96 64 96 128 32 96 128 0 64 128 0 64 96 192 192 192 0 32 96 32 128 192 128 192 224 64 192 224 128 192 192 160 224 224 96 192 192 96 160 192 64 160 192]; mask:((Depth1Image new) width: 24; height: 24; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@F@@@O@@@_ @@?0@A?8@C?<@G?>@O??@_?? @?0@@?0@@?0@@?0@@?0@@?0@@?0@@@A?@@@>@@@\@@@H@@@@') ; yourself); yourself]
+!
+
+vt100Terminal
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary shell20x20Icon
+! !
+
+!AbstractFileBrowser class methodsFor:'menu specs'!
+
+baseBookmarksMenuSpec
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:AbstractFileBrowser andSelector:#baseBookmarksMenuSpec
+ (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser baseBookmarksMenuSpec)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Add Bookmark'
+ #translateLabel: true
+ #value: #addBookmark
+ #enabled: #currentFilesHasDirectories
+ )
+ #(#MenuItem
+ #label: 'Remove Bookmark'
+ #translateLabel: true
+ #value: #removeBookmark
+ #enabled: #hasBookmarksToRemove
+ )
+ )
+ nil
+ nil
+ )
+!
+
+directoryMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:AbstractFileBrowser andSelector:#directoryMenu
+ (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser directoryMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Up'
+ #translateLabel: true
+ #value: #doGoDirectoryUp
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Back'
+ #translateLabel: true
+ #value: #doBack
+ #activeHelpKey: #directoryBack
+ #enabled: #enableBack
+ )
+ #(#MenuItem
+ #label: 'Forward'
+ #translateLabel: true
+ #value: #doForward
+ #activeHelpKey: #directoryBack
+ #enabled: #enableForward
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Default'
+ #translateLabel: true
+ #value: #doGotoDefaultDirectory
+ )
+ #(#MenuItem
+ #label: 'Home'
+ #translateLabel: true
+ #value: #doGotoHomeDirectory
+ )
+ #(#MenuItem
+ #label: 'Bookmarks'
+ #translateLabel: true
+ #submenuChannel: #bookmarksMenuSpec
+ )
+ )
+ nil
+ nil
+ )
+!
+
+editMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:AbstractFileBrowser andSelector:#editMenu
+ (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser editMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Copy'
+ #translateLabel: true
+ #value: #copyInDirContentsBrowser
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Cut'
+ #translateLabel: true
+ #value: #cutInDirContentsBrowser
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Paste'
+ #translateLabel: true
+ #value: #pasteFiles
+ #enabled: #canPaste
+ )
+ #(#MenuItem
+ #label: 'Delete'
+ #translateLabel: true
+ #value: #deleteInDirContentsBrowser
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Copy All Filenames'
+ #translateLabel: true
+ #value: #copyFileList
+ #enabled: #fileListIsNotEmpty
+ )
+ #(#MenuItem
+ #label: 'Copy Selected Filenames'
+ #translateLabel: true
+ #value: #copySelectedFilenames
+ #enabled: #hasSelection
+ )
+ )
+ nil
+ nil
+ )
+!
+
+fileMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:AbstractFileBrowser andSelector:#fileMenu
+ (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser fileMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'New'
+ #translateLabel: true
+ #submenuChannel: #newMenu
+ )
+ #(#MenuItem
+ #label: 'Rename'
+ #translateLabel: true
+ #value: #renameSelection
+ #enabled: #hasSelection
+ #shortcutKeyCharacter: #Replace
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Show File Contents'
+ #translateLabel: true
+ #value: #doShowFileContents
+ )
+ #(#MenuItem
+ #label: 'Properties...'
+ #translateLabel: true
+ #value: #doShowProperties
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: '-'
+ #isVisible: #javaSupportLoaded
+ )
+ #(#MenuItem
+ #label: 'File In'
+ #translateLabel: true
+ #value: #fileFileIn
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'File in to NameSpace...'
+ #translateLabel: true
+ #value: #fileFileInToNameSpace
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: '-'
+ #isVisible: #javaSupportLoaded
+ )
+ #(#MenuItem
+ #label: 'Add to Java Class Path'
+ #translateLabel: true
+ #isVisible: #javaSupportLoaded
+ #enabled: #canAddToClassPath
+ )
+ #(#MenuItem
+ #label: 'Remove from Java Class Path'
+ #translateLabel: true
+ #isVisible: #javaSupportLoaded
+ #enabled: #canRemoveFromClassPath
+ )
+ #(#MenuItem
+ #label: 'Add to Java Source Path'
+ #translateLabel: true
+ #isVisible: #javaSupportLoaded
+ #enabled: #canAddToSourcePath
+ )
+ #(#MenuItem
+ #label: 'Remove from Java Source Path'
+ #translateLabel: true
+ #isVisible: #javaSupportLoaded
+ #enabled: #canRemoveFromSourcePath
+ )
+ )
+ nil
+ nil
+ )
+!
+
+newMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:DirectoryTreeBrowser andSelector:#newMenu
+ (Menu new fromLiteralArrayEncoding:(DirectoryTreeBrowser newMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Directory...'
+ #translateLabel: true
+ #value: #newDirectory
+ )
+ #(#MenuItem
+ #label: 'File...'
+ #translateLabel: true
+ #value: #newFile
+ )
+ #(#MenuItem
+ #label: 'Hard Link...'
+ #translateLabel: true
+ #isVisible: #systemIsUnix
+ #value: #newHardLink
+ )
+ #(#MenuItem
+ #label: 'Symbolic Link...'
+ #translateLabel: true
+ #isVisible: #systemIsUnix
+ #value: #newSoftLink
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!AbstractFileBrowser class methodsFor:'misc'!
+
+newLock
+ ^ CodeExecutionLock new
+! !
+
+!AbstractFileBrowser methodsFor:'actions'!
+
+askForCommandFor:fileName thenDo:aBlock
+ "setup and launch a querybox to ask for unix command.
+ Then evaluate aBlock passing the command-string as argument."
+
+ |box osName|
+
+ osName := OperatingSystem platformName.
+
+ box := FilenameEnterBox
+ title:(resources string:'Execute %1 command:' with:osName)
+ okText:(resources string:'Execute')
+ action:aBlock.
+
+ fileName notNil ifTrue:[
+ self initialCommandFor:fileName into:box.
+ ].
+ box directory:(self getDirWithoutFileName:fileName).
+ box showAtPointer.
+ box destroy.
+
+ "Modified: / 7.9.1995 / 10:31:54 / claus"
+ "Modified: / 16.9.1997 / 15:35:10 / stefan"
+ "Modified: / 14.8.1998 / 14:12:52 / cg"
+!
+
+changeFileBrowserTitleTo:aString
+
+ self application:#FileBrowserV2
+ do:#changeFileBrowserTitleTo:
+ withArg:aString
+!
+
+copyFileList
+
+ | fileList stream|
+ fileList := self application:#DirectoryContentsBrowser do:#descriptions.
+ stream := WriteStream on:''.
+ fileList do:[: item |
+ stream nextPutAll:(item fileName asString).
+ stream cr.
+ ].
+ self window setTextSelection:stream contents.
+ stream close.
+!
+
+copySelectedFilenames
+
+ | fileList stream|
+ fileList := self application:#DirectoryContentsBrowser do:#getFilesFromSelection.
+ fileList isEmpty ifTrue:[^ self].
+ stream := WriteStream on:''.
+ fileList do:[: file |
+ stream nextPutAll:(file asString).
+ stream cr.
+ ].
+ self window setTextSelection:stream contents.
+ stream close.
+!
+
+doAddTerminal
+
+ | item dir directories|
+
+ directories := self currentDirectories value.
+
+ directories isEmpty ifTrue:[
+ dir := Filename homeDirectory
+ ] ifFalse:[
+ dir := directories first.
+ ].
+
+ item := (DirectoryContentsBrowser itemClass with:dir).
+ self fileApplicationDo:#openTerminalApplication: withArg:item.
+!
+
+doExecuteCommand
+
+ | action fileName|
+ fileName := self getFirstFileFromSelection.
+ action := [:command |
+ self addToCommandHistory:command for:fileName.
+ self executeCommand:command.
+ ].
+ self askForCommandFor:fileName thenDo:action
+!
+
+doGoDirectoryUp
+ | upDir directories|
+
+ self enableDirectoryUp value ifFalse:[ ^ self].
+ self currentFilesAreInSameDirectory ifTrue:[
+ directories := self currentDirectories value.
+ upDir := directories first directory.
+ self currentFileNameHolder value:(OrderedCollection with:upDir).
+ ].
+!
+
+doGotoDefaultDirectory
+ self gotoFile:(Filename defaultDirectory).
+!
+
+doGotoHomeDirectory
+
+ | home |
+
+ home := Filename homeDirectory.
+ self gotoFile:home.
+!
+
+doOpenSearchFile
+
+ |item files|
+
+ item:= self getFirstItemFromSelection.
+ item isNil ifTrue:[
+ files := self currentFileNameHolder value.
+ files notEmpty ifTrue:[
+ item := DirectoryContentsBrowser itemClass with:(files first).
+ ] ifFalse:[
+ item := DirectoryContentsBrowser itemClass with:(Filename homeDirectory asAbsoluteFilename).
+ ].
+ ].
+ self openSearchFileOn:item.
+!
+
+doShowFileContents
+
+ ^ self application:#DirectoryContentsBrowser do:#doShowFileContents.
+!
+
+doShowProperties
+
+ "show long stat (file)-info"
+
+ self fileGetInfo:true
+!
+
+fileApplicationDo:selector
+
+ ^ self application:#FileApplicationNoteBook do:selector
+!
+
+fileApplicationDo:selector withArg:arg
+ ^ self application:#FileApplicationNoteBook do:selector withArg:arg
+!
+
+fileGetInfo:longInfo
+ "get info on selected file - show it in a box"
+
+ |string box updater|
+
+ string := self
+ application:#DirectoryContentsBrowser
+ do:#getFileInfoStringForFirstSelectedFile:
+ withArg:longInfo.
+ string notNil ifTrue:[
+ box := InfoBox title:string.
+ updater := [
+ [true] whileTrue:[
+ Delay waitForSeconds:2.
+ string := self
+ application:#DirectoryContentsBrowser
+ do:#getFileInfoStringForFirstSelectedFile:
+ withArg:longInfo.
+ box title:string
+ ]
+ ] fork.
+ box showAtPointer.
+ updater terminate.
+ box destroy
+ ]
+!
+
+gotoFile:aFilename
+
+ self currentFileNameHolder value:(OrderedCollection with:aFilename).
+!
+
+openApplByFileItem:aItem
+
+ self fileApplicationDo:#openApplByFileItem: withArg:aItem
+!
+
+openCommandResultApplication
+
+ ^ self fileApplicationDo:#openCommandResultApplication
+!
+
+openSearchFileOn:aItem
+
+ ^ self fileApplicationDo:#openSearchFileOn: withArg:aItem
+!
+
+openTextEditorOn:aItem
+
+ ^ self fileApplicationDo:#openTextEditorOn: withArg:aItem
+!
+
+updateAndSelect:aColOfFiles
+
+ self application:#DirectoryContentsBrowser do:#doUpdate.
+ self application:#DirectoryTreeBrowser do:#doUpdate.
+
+ aColOfFiles notNil ifTrue:[ self currentFileNameHolder value:aColOfFiles ].
+!
+
+updateCurrentDirectory
+
+ self updateAndSelect:nil
+! !
+
+!AbstractFileBrowser methodsFor:'actions bookmarks'!
+
+addBookmark
+
+ |directories|
+
+ self currentFilesAreInSameDirectory ifFalse:[^ self].
+ directories := self currentDirectories value.
+ self addBookmark:directories.
+!
+
+addBookmark:aColOfDirectories
+ |idx bookmarks|
+
+ aColOfDirectories do:[ : path |
+ bookmarks := self class directoryBookmarks.
+ idx := bookmarks indexOf:path.
+ idx == 0 ifTrue:[
+ bookmarks addLast:path.
+ ].
+ ].
+!
+
+bookmarksMenuSpec
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileBrowser andSelector:#bookmarksMenuSpec
+ (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser bookmarksMenuSpec)) startUp
+ "
+ <resource: #programMenu>
+
+ |menu bookmarks|
+
+ menu := self class baseBookmarksMenuSpec.
+ menu := menu decodeAsLiteralArray.
+ menu receiver:self.
+ bookmarks := self class directoryBookmarks.
+ "/ add the history items ...
+
+ bookmarks size > 0 ifTrue:[
+ menu addItem:(MenuItem labeled:'-').
+ bookmarks do:[:dirName |
+ menu addItem:((MenuItem label:dirName asString value:[
+ (self currentDirectories value includes:dirName) ifFalse:[
+ self currentFileNameHolder value:(OrderedCollection with:dirName).
+ ].
+ ])).
+ ].
+ ].
+ ^ menu
+
+ "Modified: / 17.8.1998 / 10:13:05 / cg"
+!
+
+hasBookmarks
+ ^ self class directoryBookmarks size > 0
+!
+
+hasBookmarksToRemove
+
+ |bookmarks directories|
+
+ directories := self getDirectoriesFromSelection.
+ bookmarks := self class directoryBookmarks.
+ ^ (bookmarks size > 0 and:[directories notEmpty])
+!
+
+removeBookmark
+
+ |bookmarks directories|
+
+ bookmarks := self class directoryBookmarks.
+ bookmarks isNil ifTrue:[ ^ self].
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[^ self].
+ directories do:[:dir|
+ bookmarks remove:dir ifAbsent:nil.
+ ].
+! !
+
+!AbstractFileBrowser methodsFor:'actions history'!
+
+addToCommandHistory:aCommandString for:aFilename
+ |cmd suffix cmdHist|
+
+ cmdHist := self class commandHistory.
+ (aCommandString notNil and:[aCommandString notEmpty]) ifTrue:[
+ cmdHist notNil ifTrue:[
+ cmdHist addFirst:aCommandString.
+ cmdHist size > self class commandHistorySize ifTrue:[
+ cmdHist removeLast
+ ]
+ ].
+ aFilename notNil ifTrue:[
+ cmd := aCommandString copyTo:(aCommandString indexOf:Character space ifAbsent:[aCommandString size + 1])-1.
+ DefaultCommandPerSuffix isNil ifTrue:[
+ DefaultCommandPerSuffix := Dictionary new.
+ ].
+ suffix := aFilename asFilename suffix.
+ suffix notNil ifTrue:[
+ DefaultCommandPerSuffix at:suffix put:cmd.
+ ]
+ ]
+ ]
+!
+
+doBack
+
+ | fileName |
+ fileName := self dirHistory doBack.
+ fileName notNil ifTrue:[
+ self gotoFile:fileName.
+ ]
+!
+
+doForward
+
+ | fileName |
+ fileName := self dirHistory doForward.
+ fileName notNil ifTrue:[
+ self gotoFile:fileName.
+ ]
+! !
+
+!AbstractFileBrowser methodsFor:'applications'!
+
+application:aApplication do:aMethod
+
+ |appl|
+
+ appl := self applications at:aApplication ifAbsent:nil.
+ appl notNil ifTrue:[
+ ^ appl perform:aMethod.
+ ].
+ ^ nil.
+!
+
+application:aApplication do:aMethod withArg:arg
+ |appl|
+
+ appl := self applications at:aApplication ifAbsent:nil.
+ appl notNil ifTrue:[
+ ^ appl perform:aMethod with:arg
+ ].
+ ^ nil
+!
+
+application:aApplication do:aMethod withArg:arg1 withArg:arg2
+ |appl|
+
+ appl := self applications at:aApplication ifAbsent:nil.
+ appl notNil ifTrue:[
+ (arg1 notNil and:[arg2 notNil]) ifTrue:[
+ ^ appl perform:aMethod with:arg1 with:arg2
+ ]
+ ].
+ ^ nil
+! !
+
+!AbstractFileBrowser methodsFor:'aspects'!
+
+applications
+ "returns the list of registered applications
+ "
+ ^ aspects at:#applications
+!
+
+backgroundProcesses
+
+ ^ self aspectFor:#backgroundProcesses ifAbsent:[List new]
+!
+
+browserFileList
+
+ ^ self aspectFor:#browserFileList ifAbsent:[List new]
+!
+
+currentDirectories
+
+ " returns a Ordered Collection of all directories currently selected
+ if only a file is selected currentDirectories holds the directory of the file
+ "
+
+ ^ self aspectFor:#currentDirectories ifAbsent:[ (OrderedCollection new) asValue ].
+!
+
+currentFileNameHolder
+
+ " returns a OrderedCollection of all files that are selected
+ if no file but a directory is selected it contains the directories
+ in contrast to currentDirectories wich have only the directories
+ "
+
+ ^ self aspectFor:#currentFileNameHolder ifAbsent:[(OrderedCollection with:(Filename currentDirectory asAbsoluteFilename)) asValue]
+!
+
+enableDirectoryUp
+
+ ^ self aspectFor:#enableDirectoryUp ifAbsent:[false asValue]
+!
+
+enableHome
+
+ ^ self aspectFor:#enableHome ifAbsent:[ true asValue ].
+!
+
+enableViewNoteBookApplication
+
+ ^ self aspectFor:#enableViewNoteBookApplication ifAbsent:[false asValue]
+!
+
+filterListModel
+
+ ^ self aspectFor:#filterListModel ifAbsent:[self class defaultFilterList]
+!
+
+filterModel
+
+ ^ self aspectFor:#filterModel ifAbsent:[(self filterListModel at:1) asValue]
+!
+
+hasSelection
+
+ ^ self aspectFor:#hasSelection ifAbsent:[ false asValue ].
+!
+
+notifyChannel
+
+ ^ self aspectFor:#notifyChannel ifAbsent:['' asValue]
+!
+
+selectionInFileList
+
+ ^ self aspectFor:#selectionInFileList ifAbsent:[ OrderedCollection new asValue ]
+!
+
+sortCaseless
+
+ ^ self aspectFor:#sortCaseless ifAbsent:[
+ | holder |
+ holder := (Filename isCaseSensitive not) asValue.
+ holder
+ ]
+!
+
+treeSelectionHolder
+
+ ^ self aspectFor:#treeSelectionHolder ifAbsent:[nil asValue]
+! !
+
+!AbstractFileBrowser methodsFor:'aspects handling'!
+
+aspectFor:something ifAbsent:aBlock
+ "returns the model for an aspect
+ "
+ |holder saveAspectItem|
+
+ (holder := aspects at:something ifAbsent:nil) isNil ifTrue:[
+ saveAspectItem := self settingsAspectValueFor:something.
+ saveAspectItem isNil ifTrue:[
+ saveAspectItem := self runtimeAspectValueFor:something.
+ ].
+ saveAspectItem notNil ifTrue:[
+ saveAspectItem isHolder ifTrue:[
+ holder := ValueHolder with:saveAspectItem value
+ ] ifFalse:[
+ holder := saveAspectItem value
+ ].
+ ] ifFalse:[
+ holder := aBlock value.
+ ].
+ holder notNil ifTrue:[
+ aspects at:something put:holder
+ ]
+ ].
+ ^ holder
+!
+
+aspects
+ ^ aspects
+!
+
+runtimeAspectValueFor:something
+ "returns the default aspect item from the class variable RuntimeAspects
+ "
+ ^ self class runtimeAspects at:something ifAbsent:nil.
+!
+
+saveRuntimeAspectValues
+ |savedAspects dictionary value isHolder aspect|
+
+ savedAspects := self class listOfRuntimeValuesToRemark.
+ dictionary := Dictionary new.
+ savedAspects do:[ : aspectKey |
+ aspect := self perform:aspectKey.
+ isHolder := aspect isValueModel.
+ isHolder ifTrue:[value:= aspect value] ifFalse:[ value := aspect].
+ dictionary at:aspectKey
+ put:(SaveAspectItem withValue:value isHolder:isHolder)
+ ].
+
+ RuntimeAspects := dictionary.
+!
+
+saveSettingsAspectValues
+ |savedAspects dictionary value isHolder aspect|
+
+ savedAspects := self class listOfSavedSettingsAspects.
+ dictionary := Dictionary new.
+ savedAspects do:[ : aspectKey |
+ aspect := self perform:aspectKey.
+ isHolder := aspect isValueModel.
+ isHolder ifTrue:[value:= aspect value] ifFalse:[ value := aspect].
+ dictionary at:aspectKey
+ put:(SaveAspectItem withValue:value isHolder:isHolder)
+ ].
+
+ SettingsAspects := dictionary.
+!
+
+settingsAspectValueFor:something
+ "returns the default aspect from the class variable Aspects
+ "
+ ^ self class settingsAspects at:something ifAbsent:nil.
+! !
+
+!AbstractFileBrowser methodsFor:'aspects-history'!
+
+dirHistory
+
+ ^ self aspectFor:#dirHistory ifAbsent:[DirectoryHistory new]
+!
+
+enableBack
+
+ ^ self aspectFor:#enableBack ifAbsent:[false asValue]
+!
+
+enableFileHistory
+
+ ^ self aspectFor:#enableFileHistory ifAbsent:[false asValue]
+!
+
+enableForward
+
+ ^ self aspectFor:#enableForward ifAbsent:[false asValue]
+!
+
+fileHistory
+
+ ^ self aspectFor:#fileHistory ifAbsent:[FilenameHistory new]
+! !
+
+!AbstractFileBrowser methodsFor:'aspects-visibility'!
+
+filenameEntryFieldVisibleHolder
+
+ ^ self aspectFor:#filenameEntryFieldVisibleHolder ifAbsent:[true asValue]
+!
+
+openMultipleApplicationsForType
+
+ ^ self aspectFor:#openMultipleApplicationsForType ifAbsent:[ false asValue ].
+!
+
+showDirectoryTreeHolder
+
+ | |
+
+ ^ self aspectFor:#showDirectoryTreeHolder ifAbsent:[ true asValue ]
+!
+
+showHiddenFiles
+
+ ^ self aspectFor:#showHiddenFiles ifAbsent:[ true asValue ].
+!
+
+sortBlockHolder
+
+ ^ self aspectFor:#sortBlockHolder ifAbsent:[ #baseName asValue ].
+!
+
+toolBarVisibleHolder
+
+ ^ self aspectFor:#toolBarVisibleHolder ifAbsent:[true asValue]
+!
+
+viewDescription
+
+ ^ self aspectFor:#viewDescription ifAbsent:[ false asValue ].
+!
+
+viewDetails
+
+ ^ self aspectFor:#viewDetails ifAbsent:[ false asValue ].
+!
+
+viewDirectoriesInDirectoryContentsBrowser
+
+ ^ self aspectFor:#viewDirectoriesInDirectoryContentsBrowser ifAbsent:[ false asValue ].
+!
+
+viewDirectoryDescription
+
+ ^ self aspectFor:#viewDirectoryDescription ifAbsent:[ true asValue ].
+!
+
+viewFilesInDirectoryTree
+
+ ^ self aspectFor:#viewFilesInDirectoryTree ifAbsent:[ false asValue ].
+!
+
+viewGroup
+
+ ^ self aspectFor:#viewGroup ifAbsent:[ false asValue ].
+!
+
+viewNoteBookApplicationHolder
+
+ ^ self aspectFor:#viewNoteBookApplicationHolder ifAbsent:[ false asValue].
+!
+
+viewOwner
+
+ ^ self aspectFor:#viewOwner ifAbsent:[ false asValue ].
+!
+
+viewPermissions
+
+ ^ self aspectFor:#viewPermissions ifAbsent:[ false asValue ].
+!
+
+viewPreview
+
+ ^ self aspectFor:#viewPreview ifAbsent:[ false asValue ].
+!
+
+viewSize
+
+ ^ self aspectFor:#viewSize ifAbsent:[ false asValue ].
+!
+
+viewTime
+
+ ^ self aspectFor:#viewTime ifAbsent:[ false asValue ].
+!
+
+viewType
+
+ ^ self aspectFor:#viewType ifAbsent:[ false asValue ].
+! !
+
+!AbstractFileBrowser methodsFor:'background processing'!
+
+executeCommand:cmd
+
+ self executeCommand:cmd inDirectory:nil
+!
+
+executeCommand:cmd inDirectory:aDir
+
+ | nameString executionBlock|
+
+ executionBlock := self getExecutionBlockForCommand:cmd inDirectory:aDir.
+ nameString := 'Command> ', cmd.
+ self makeExecutionResultProcessFor:executionBlock withName:nameString.
+!
+
+getExecutionBlockForCommand:cmd
+
+ ^ self getExecutionBlockForCommand:cmd inDirectory:nil
+!
+
+getExecutionBlockForCommand:cmd inDirectory:aDir
+
+ | dir dirs|
+
+ dir := aDir.
+ aDir isNil ifTrue:[
+ dirs := self getDirectoriesFromSelection.
+ dirs size ~= 1 ifTrue:[ ^ self].
+ dir := dirs anElement.
+ ].
+ ^ [:stream| stream notNil ifTrue:[
+ OperatingSystem
+ executeCommand:cmd
+ inputFrom:nil
+ outputTo:stream
+ errorTo:stream
+ inDirectory:dir
+ onError:[:status| false].
+ ]
+ ].
+!
+
+killAllRunningBackgroundProcesses
+
+ self backgroundProcesses do:[ : process |
+ self notifyChannel value:'kill ', process name.
+ process terminate.
+ ].
+!
+
+makeExecutionResultProcessFor:aBlock withName:aString
+ | stream process appl nameString|
+
+ appl := self openCommandResultApplication.
+ stream := appl resultStream.
+ nameString := aString ? 'Execution Result'.
+ appl changeTabTo:nameString.
+ process := [ [aBlock value:stream] valueNowOrOnUnwindDo:[
+ self backgroundProcesses remove:process ifAbsent:[].
+ appl process value:nil.
+ ]] newProcess.
+ process priority:(Processor userBackgroundPriority).
+ process name:nameString.
+ self backgroundProcesses add:process.
+ appl process value:process.
+ process resume.
+! !
+
+!AbstractFileBrowser methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+
+ " do here all the things that have to be done for every part of the FileBrowserV2
+ and the things that have to be done if it runs standalone "
+
+ | newDirectories oldDirectories size|
+
+ changedObject == self currentFileNameHolder ifTrue:[
+ newDirectories := self getDirectoriesForFileList:(changedObject value).
+ oldDirectories := self currentDirectories value.
+ oldDirectories ~= newDirectories ifTrue:[
+ self currentDirectories value:newDirectories.
+ size := newDirectories size.
+ newDirectories notEmpty ifTrue:[
+ self enableDirectoryUp value:(((size == 1) and:[newDirectories first isRootDirectory not])).
+ newDirectories do:[: dir |
+ self dirHistory addFile:dir.
+ ].
+ self enableForward value:self dirHistory canForward.
+ self enableBack value:self dirHistory canBack.
+ ]
+ ].
+ ^ self
+ ].
+ changedObject == self filterModel ifTrue:[
+ (self filterModel value = '') ifTrue:[
+ self filterModel value:'*'.
+ ].
+ ^ self
+ ].
+ super update:something with:aParameter from:changedObject
+! !
+
+!AbstractFileBrowser methodsFor:'clipboard'!
+
+canPaste
+
+ ^ self aspectFor:#canPaste ifAbsent:[ false asValue ].
+!
+
+clipboard
+
+ ^ self aspectFor:#clipboard ifAbsent:[Clipboard new]
+!
+
+copyFilesToClipBoard:colOfFiles
+ "defete current selected files/directories
+ "
+ self putInClipBoard:colOfFiles as:#copy.
+!
+
+cutFilesToClipBoard:colOfFiles
+ "defete current selected files/directories
+ "
+ self putInClipBoard:colOfFiles as:#cut.
+!
+
+emptyClipBoard
+
+ self clipboard files:nil.
+ self canPaste value:false.
+!
+
+putInClipBoard:colOfFiles as:aSymbol
+
+ | stream clp|
+
+ colOfFiles isEmpty ifTrue:[ ^ self].
+ clp := self clipboard.
+ clp files:nil.
+ clp method:aSymbol.
+ stream := WriteStream on:''.
+ stream nextPutAll:aSymbol asString.
+ stream nextPutAll:' <'.
+ stream nextPutAll:colOfFiles first asString.
+ colOfFiles size > 1 ifTrue:[
+ stream nextPutAll:' ...'.
+ ].
+ stream nextPutAll:'> to clipboard'.
+
+ self notifyChannel value:stream contents.
+ stream close.
+ clp files:colOfFiles.
+ self canPaste value:true.
+! !
+
+!AbstractFileBrowser methodsFor:'drag & drop'!
+
+canDropArchiv:dropedObjects for:filename
+
+ (filename isDirectory
+ and:[filename isWritable and:[dropedObjects notEmpty]]) ifTrue:[
+ ^ true
+ ].
+ ^ false
+!
+
+canDropFiles:dropedObjects for:filename
+ | checkObject filenameDirString checkObjectString filenameDir|
+
+ dropedObjects isEmpty ifTrue:[^ false].
+ filenameDir := self getDirWithoutFileName:filename.
+ filenameDir isWritable not ifTrue:[^ false].
+ filenameDirString := filenameDir asString.
+ dropedObjects do:[:aObject |
+ checkObject := aObject theObject.
+ checkObject isFilename not ifTrue:[^ false].
+ checkObject asFilename exists not ifTrue:[^ false].
+ checkObjectString := checkObject asString.
+ checkObject isDirectory ifTrue:[
+ (self fileName:filenameDirString startsWith:checkObjectString) ifTrue:[
+ " can not drop a directory in his parents "
+ ^ false
+ ]
+ ] ifFalse:[
+ (filenameDirString = checkObject directory asString
+ or:[ filenameDirString = checkObject physicalPathName asFilename directory asString ]) ifTrue:[
+ " can not drop a file in same directory "
+ ^ false
+ ]
+ ]
+ ].
+ ^ true
+!
+
+doStartDrag:aDropSource in:aView
+ "set the cursors before starting the drag & drop operation
+ "
+ |hdl|
+
+
+ hdl := DragAndDropManager new.
+
+ hdl disabledCursor:self class DisabledCursorImage.
+ hdl enabledCursor:self class EnabledCursorImage.
+ hdl alienCursor:nil.
+
+ hdl startDragFrom:aView dropSource:aDropSource offset:#topLeft
+! !
+
+!AbstractFileBrowser methodsFor:'file operations'!
+
+copyFile:aSourceFile to:aDestFile
+ "copy to
+ "
+ |copy|
+
+ copy := FileOperation copy copyFile:aSourceFile to:aDestFile withOverWriteWarning:true copyFileIfSame:true.
+ copy result ifTrue:[
+ self notifyChannel value:('copy ', aSourceFile baseName, ' to:,', aDestFile baseName).
+ ] ifFalse:[
+ self notifyChannel value:copy errorString.
+ ].
+ ^ copy result
+!
+
+copyFiles:aColOfSourceFiles to:aDirectory
+ "copy aColOfSourceFiles to aDirectory
+ "
+ |copy|
+
+ copy := FileOperation copy copyFiles:aColOfSourceFiles to:aDirectory.
+ copy result ifFalse:[
+ self notifyChannel value:copy errorString.
+ ].
+ self updateCurrentDirectory.
+ ^ copy colOfCopiedFiles
+!
+
+copyOrMoveDialog:aCol
+
+ | size stream dialog|
+
+ size := aCol size.
+ stream := WriteStream on:''.
+ stream nextPutAll:'copy or move file'.
+ size == 1 ifFalse:[
+ stream nextPutAll:'s'.
+ ].
+ stream nextPutAll:': '.
+ stream nextPutAll:aCol first baseName asString.
+ size == 1 ifFalse:[
+ stream nextPutAll:' ... '.
+ stream nextPutAll:aCol last baseName asString.
+ ].
+
+ dialog := OptionBox
+ request:stream contents
+ label:'move or copy'
+ form:(WarningBox iconBitmap)
+ buttonLabels:#('cancel' 'move' 'copy')
+ values:#(#cancel #move #copy)
+ default:#copy.
+ dialog isNil ifTrue:[dialog := #cancel].
+ ^ dialog.
+!
+
+copyOrMoveFiles:aColOfSourceFiles to:aDirectory
+ "copy aColOfSourceFiles to aDirectory
+ "
+ |dialog|
+
+ dialog := self copyOrMoveDialog:aColOfSourceFiles.
+ dialog == #copy ifTrue:[
+ self copyFiles:aColOfSourceFiles to:aDirectory.
+ ^ self.
+ ].
+ dialog == #move ifTrue:[
+ self moveFiles:aColOfSourceFiles to:aDirectory.
+ ^ self.
+ ].
+!
+
+deleteFile:aFile
+ "delete current selected files/directories
+ "
+
+ ^ self deleteFiles:(OrderedCollection with:aFile).
+!
+
+deleteFiles:colOfFiles
+ "delete current selected files/directories
+ "
+ |delete|
+
+ delete := FileOperation delete deleteFiles:colOfFiles.
+ delete result ifFalse:[
+ self notifyChannel value:delete errorString.
+ ].
+ self updateCurrentDirectory.
+ ^ delete result.
+!
+
+moveFile:aSourceFile to:aDestFile
+ "defete current selected files/directories
+ "
+
+ |move|
+
+ move := FileOperation move moveFile:aSourceFile to:aDestFile.
+ move result ifTrue:[
+ self notifyChannel value:('move ', aSourceFile asString, ' to ', aDestFile asString).
+ ] ifFalse:[
+ self notifyChannel value:move errorString.
+ ].
+ self updateCurrentDirectory.
+ ^ move result
+!
+
+moveFiles:aColOfSourceFiles to:aDirectory
+ "move aColOfSourceFiles to aDirectory
+ "
+ |move|
+
+ move := FileOperation move moveFiles:aColOfSourceFiles to:aDirectory.
+ move result ifFalse:[
+ self notifyChannel value:move errorString.
+ ].
+ self updateCurrentDirectory.
+ ^ move colOfMovedFiles
+!
+
+newDirectory
+ "ask for and create a new directory"
+
+ | directories directory create newFile|
+
+ directories := self currentDirectories value.
+ (directories size ~= 1) ifTrue:[^ self].
+ directory := directories first.
+ create := FileOperation create createDirectoryIn:directory.
+ create result ifFalse:[ ^ self].
+ newFile := create createdFile.
+ newFile notNil ifTrue:[
+ self updateAndSelect:(OrderedCollection with:newFile).
+ ]
+!
+
+newFile
+ "ask for and create a new file"
+
+ | curFile directories directory create file|
+
+ directories := self currentDirectories value.
+ (directories size ~= 1) ifTrue:[^ self].
+ directory := directories first.
+ curFile := self getFirstFileFromSelection.
+ curFile notNil ifTrue:[
+ file := curFile.
+ ] ifFalse:[
+ file := directory.
+ ].
+ create := FileOperation create createFileIn:file.
+ create result ifFalse:[ ^ self].
+ self updateAndSelect:(OrderedCollection with:(create createdFile)).
+!
+
+newHardLink
+ "ask for and create a hard link (unix only)"
+
+ self newLink:false.
+!
+
+newLink:symbolic
+
+ "ask for and create a symbolic if symbolic is true otherwise a hard link (unix only)"
+
+ | sel create createdFile|
+
+ sel := self currentFileNameHolder value.
+ (sel size ~= 1) ifTrue:[^ self].
+ symbolic ifTrue:[
+ create := FileOperation create createSoftLinkIn:(sel first).
+ ] ifFalse:[
+ create := FileOperation create createHardLinkIn:(sel first).
+ ].
+ create result ifFalse:[ ^ self].
+ createdFile := create createdFile.
+ createdFile notNil ifTrue:[
+ self updateAndSelect:(OrderedCollection with:createdFile).
+ ].
+!
+
+newSoftLink
+ "ask for and create a soft link (unix only)"
+
+ self newLink:true.
+!
+
+pasteFiles
+ "defete current selected files/directories
+ "
+ | buffer destination files directories copiedFiles|
+
+ files := self clipboard files.
+ (files isNil or:[files isEmpty]) ifTrue:[ ^ self ].
+ buffer := self clipboard copy.
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[
+ |box dirStringCol|
+ dirStringCol := directories collect:[:aDir| aDir asString].
+ box := ListSelectionBox new.
+ box title:'In which directory you want to paste ?'.
+ box list:dirStringCol.
+ box okAction:[:sel | destination := sel asFilename].
+ box showAtPointer
+ ] ifFalse:[
+ destination := directories first.
+ ].
+ copiedFiles := self copyFiles:(buffer files) to:destination.
+
+ (self clipboard method == #cut) ifTrue:[
+ self deleteFiles:copiedFiles.
+ ]
+!
+
+renameFile:aFile
+ "rename the selected file(s)"
+
+ ^ self renameFiles:(OrderedCollection with:aFile).
+!
+
+renameFile:filename to:newFileString update:aBoolean
+ "rename filename to newFileString"
+
+ |rename|
+
+ rename := FileOperation rename renameFile:filename to:newFileString.
+ rename result ifTrue:[
+ aBoolean ifTrue:[
+ self updateAndSelect:(rename renamedFiles).
+ ].
+ ] ifFalse:[
+ self notifyChannel value:rename errorString.
+ ].
+ ^ rename result
+!
+
+renameFiles:aColOfFiles
+ "rename the selected file(s)"
+
+ |rename|
+
+ rename := FileOperation rename renameFiles:aColOfFiles.
+ rename result ifFalse:[
+ self notifyChannel value:rename errorString
+ ] ifTrue:[
+ self updateAndSelect:(rename renamedFiles)
+ ].
+ ^ rename result
+!
+
+renameSelection
+ "rename the selected file(s)"
+
+ |rename|
+
+ rename := FileOperation rename renameFiles:self currentFileNameHolder value.
+ rename result ifFalse:[
+ self notifyChannel value:rename errorString
+ ] ifTrue:[
+ self updateAndSelect:(rename renamedFiles)
+ ].
+ ^ rename result
+! !
+
+!AbstractFileBrowser methodsFor:'font encoding'!
+
+fileEncoding
+ "open a dialog to allow change of the files character encoding.
+ Files are converted to internal encoding when read, and converted back
+ to this encoding when saved.
+ The default encoding is nil, which means that files are already in
+ the internal encoding (which is iso8859).
+ Notice: currently, not too many encodings are supported by the system."
+
+ |dialog list descr encodings encodingNames idx|
+
+ list := SelectionInList new.
+
+ descr := CharacterArray supportedExternalEncodings.
+ encodings := descr at:2.
+ encodingNames := descr at:1.
+
+ list list:encodingNames.
+ list selectionIndex:(encodings indexOf:(self fileEncodingHolder value) ifAbsent:1).
+ dialog := Dialog new.
+
+ dialog addTextLabel:('Specify the files encoding.\\The default (a 1-to-1 encoding) works for 7bit ascii\and iso8859 (= ANSI) encoded text files.\') withCRs.
+ dialog addVerticalSpace.
+ dialog addListBoxOn:list withNumberOfLines:5.
+
+ dialog addAbortAndOkButtons.
+ dialog open.
+
+ dialog accepted ifTrue:[
+ idx := list selectionIndex.
+ self fileEncodingHolder value:(encodings at:idx).
+"/ subView externalEncoding:fileEncoding.
+
+ self validateFontEncodingFor:(encodings at:idx) ask:true.
+ ].
+!
+
+fileEncodingHolder
+ "return/create the 'fileEncodingModel' value holder (automatically generated)"
+
+ ^ self aspectFor:#fileEncodingHolder ifAbsent:[ValueHolder new]
+!
+
+preferredFontEncodingFor:fileEncoding
+ "given a file encoding, return corresponding preferred fontEncoding
+ match pattern"
+
+ |fe|
+
+ fe := MIMETypes fontForCharset:fileEncoding.
+ fe notNil ifTrue:[^ fe].
+ ^ 'iso8859*'
+!
+
+validateFontEncodingFor:newEncoding ask:ask
+ "if required, query user if he/she wants to change to another font,
+ which is able to display text encoded as specified by newEncoding"
+
+ |fontsEncoding msg filter f defaultFont pref|
+
+"/ PENK fontsEncoding := subView font encoding.
+
+ pref := self preferredFontEncodingFor:newEncoding.
+
+ (pref match:fontsEncoding) ifTrue:[
+ ^ self
+ ].
+ "/ stupid ...
+ pref = 'ascii*' ifTrue:[
+ (fontsEncoding match:'iso8859*') ifTrue:[
+ ^ self
+ ]
+ ].
+
+ filter := [:f | |coding|
+ (coding := f encoding) notNil
+ and:[pref match:coding]].
+
+ defaultFont := TextView defaultFont onDevice:device.
+ (pref match:(defaultFont encoding)) ifFalse:[
+ defaultFont := nil.
+ ].
+
+ defaultFont isNil ifTrue:[
+ (pref = 'ascii*'
+ or:[pref = 'iso8859*']) ifTrue:[
+ defaultFont := FontDescription family:'courier' face:'medium' style:'roman' size:12
+ ]
+ ].
+
+ defaultFont isNil ifTrue:[
+ defaultFont := device
+ listOfAvailableFonts
+ detect:[:f | filter value:f]
+ ifNone:nil.
+ defaultFont isNil ifTrue:[
+
+ "/ flush list, and refetch font list
+ "/ (in case someone just changed the font path ...)
+
+ device flushListOfAvailableFonts.
+ defaultFont := device
+ listOfAvailableFonts
+ detect:[:f | filter value:f]
+ ifNone:nil.
+ ].
+
+ defaultFont isNil ifTrue:[
+ Dialog warn:'your display does not seem to provide any ' , newEncoding , '-encoded font.'.
+ ^ self.
+ ]
+ ].
+
+ msg := 'switch to a %1 encoded font ?'.
+ (ask not or:[self confirm:(resources string:msg with:pref) withCRs])
+ ifTrue:[
+ self withWaitCursorDo:[
+ f := FontPanel
+ fontFromUserInitial:defaultFont
+ title:(resources string:'font selection')
+ filter:filter.
+ f notNil ifTrue:[
+"/ PENK subView font:f
+ ]
+ ]
+ ]
+! !
+
+!AbstractFileBrowser methodsFor:'menu'!
+
+menuDirHistory:backOrForward
+ "initialize the directory menu
+ "
+ <resource: #programMenu >
+
+ |menu histCopy index text removeItem directories dir|
+
+ menu := Menu new.
+ menu receiver:self.
+
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[^ nil].
+
+ dir := directories first.
+ self dirHistory isEmpty ifTrue:[^ nil].
+ index := self dirHistory indexOf:dir.
+ index = 0 ifTrue:[^ nil].
+ text := LabelAndIcon icon:(self class clearHistoryIcon) string:'Clear History'.
+ backOrForward == #back ifTrue:[
+ histCopy := self dirHistory copyTo:index - 1.
+ removeItem := MenuItem label:text value:[
+ self dirHistory removeBack.
+ self enableBack value:self dirHistory canBack.
+ ].
+ ] ifFalse:[
+ histCopy := self dirHistory copyFrom:index + 1.
+ removeItem := MenuItem label:text value:[
+ self dirHistory removeForward.
+ self enableForward value:self dirHistory canForward.
+ ].
+ ].
+ histCopy do:[:aFile|
+ menu addItem:(MenuItem label:aFile asString value:[
+ self dirHistory setIndexTo:aFile.
+ self currentFileNameHolder value:(OrderedCollection with:aFile).
+ ]).
+ ].
+ menu addItem:(MenuItem label:'-').
+ menu addItem:removeItem.
+ ^ menu
+!
+
+menuDirHistoryBack
+ "initialize the directory menu
+ "
+ <resource: #programMenu >
+
+ ^ self menuDirHistory:#back.
+!
+
+menuDirHistoryForward
+ "initialize the directory menu
+ "
+ <resource: #programMenu >
+
+ ^ self menuDirHistory:#forward.
+! !
+
+!AbstractFileBrowser methodsFor:'menu access'!
+
+sortMenu
+
+ ^ self application:#DirectoryContentsBrowser do:#sortMenu.
+!
+
+viewFileBrowserMenu
+
+ ^ self application:#DirectoryContentsBrowser do:#viewBrowserMenu.
+! !
+
+!AbstractFileBrowser methodsFor:'menu actions cvs'!
+
+cvsAddAndCommit
+
+ self cvsAddAndCommit:true.
+!
+
+cvsAddAndCommit:withCommit
+
+ |sel log cmd dir directories executionBlock nameString block|
+
+ log := Dialog
+ requestText:(resources string:'enter initial log message')
+ lines:10
+ columns:70
+ initialAnswer:nil.
+
+ sel := self getFilesFromSelection.
+ executionBlock := [ : stream |
+ log notNil ifTrue:[
+ sel size > 0 ifTrue:[
+ sel do:[:fn |
+ dir := self getDirWithoutFileName:fn.
+ cmd := ('cvs add -m ''' , log , ''' ' , fn baseName).
+ block := self getExecutionBlockForCommand:cmd inDirectory:dir.
+ block value:stream.
+ ]
+ ] ifFalse:[
+ directories := self currentDirectories value.
+ directories do:[:dir |
+ cmd := ('cvs add -m ''' , log , ''' ' , dir baseName).
+ block := self getExecutionBlockForCommand:cmd inDirectory:dir.
+ block value:stream.
+ ]
+ ].
+ withCommit ifTrue:[
+ cmd := ('cvs commit -l -m ''' , log , '''').
+ block := self getExecutionBlockForCommand:cmd.
+ block value:stream.
+ ]
+ ]
+ ].
+ nameString := 'Command> add and commit'.
+ self makeExecutionResultProcessFor:executionBlock withName:nameString.
+!
+
+cvsCommit
+
+ |nSel log msg cmd selectedFiles|
+
+ selectedFiles:= self getFilesFromSelection.
+ nSel := selectedFiles size.
+
+ nSel == 1 ifTrue:[
+ msg := resources string:'enter log message for checkIn of ''%1''' with:(selectedFiles first baseName)
+ ] ifFalse:[
+ nSel > 1 ifTrue:[
+ msg := resources string:'enter log message for %1 files to checkIn' with:nSel printString
+ ] ifFalse:[
+ msg := resources string:'enter log message for checkIn'
+ ]
+ ].
+
+ log := Dialog
+ requestText:msg
+ lines:10
+ columns:70
+ initialAnswer:nil.
+
+ log notNil ifTrue:[
+ nSel > 0 ifTrue:[
+ selectedFiles do:[:fn |
+ cmd := ('cvs commit -m ''' , log , ''' ' , fn baseName).
+ self executeCommand:cmd.
+ ]
+ ] ifFalse:[
+ cmd := ('cvs commit -l -m ''' , log , '''').
+ self executeCommand:cmd.
+ ].
+ ]
+!
+
+cvsRemoveAndRemoveFromCVS:filesToRemove
+ "remove the selected file(s) and their CVS containers - no questions asked"
+
+ |msg toRemove updateRunning cmd executionBlock nameString|
+
+ updateRunning := self backgroundProcesses value notEmpty.
+ self killAllRunningBackgroundProcesses.
+ toRemove := OrderedCollection new.
+
+ executionBlock := [ : stream |
+ | block |
+ filesToRemove do:[:fileName |
+ OperatingSystem accessDeniedErrorSignal handle:[:ex|
+ "was not able to remove it"
+ | lastError |
+ lastError := OperatingSystem lastErrorString.
+ msg := (resources string:'cannot remove ''%1'' !!' with:fileName).
+ lastError isNil ifFalse:[
+ msg := msg , '\\(' , lastError , ')'
+ ].
+ Dialog warn:msg withCRs
+ ] do:[
+ |answer contents|
+
+ (fileName isSymbolicLink not) ifTrue:[
+ fileName remove.
+ cmd := ('cvs remove -f ' , fileName baseName).
+ block := self getExecutionBlockForCommand:cmd.
+ block value:stream.
+ ]
+ ].
+ ].
+
+ cmd := ('cvs commit -m ''removed via FileBrowser''').
+ block := self getExecutionBlockForCommand:cmd.
+ block value:stream.
+ ].
+ nameString := 'Command> remove and commit ', filesToRemove first baseName.
+ filesToRemove size > 1 ifTrue:[
+ nameString := nameString, ' ...'.
+ ].
+ self makeExecutionResultProcessFor:executionBlock withName:nameString.
+!
+
+cvsRemoveFileAndCVSContainer
+
+ |sel question aswer|
+
+ sel := self getFilesFromSelection.
+
+ sel size > 0 ifTrue:[
+ sel size > 1 ifTrue:[
+ question := resources string:'Remove %1 selected files and their CVS containers ?' with:(sel size)
+ ] ifFalse:[
+ question := resources string:'Remove ''%1'' and its CVS container ?' with:(sel first baseName allBold)
+ ].
+
+ aswer := Dialog
+ confirm:question withCRs
+ yesLabel:(resources at:'Remove')
+ noLabel:(resources at:'Cancel').
+ aswer ifTrue:[
+ self withCursor:(Cursor wait) do:[
+ self cvsRemoveAndRemoveFromCVS:sel
+ ]
+ ]
+ ]
+!
+
+cvsUpdateAll
+
+ | cmd |
+
+ cmd := 'cvs upd -l'.
+ self executeCommand:cmd.
+!
+
+cvsUpdateAllRecursive
+
+ | cmd |
+
+ cmd := 'cvs upd -d'.
+ self executeCommand:cmd.
+!
+
+cvsUpdateSelection
+
+ | selectedFiles stream|
+
+
+ selectedFiles:= self getFilesFromSelection.
+ stream := WriteStream on:''.
+ stream nextPutAll:'cvs upd '.
+ selectedFiles do:[: file |
+ stream nextPutAll:file baseName.
+ stream space.
+ ].
+ self executeCommand:stream contents.
+ stream close.
+! !
+
+!AbstractFileBrowser methodsFor:'menu actions edit'!
+
+copyInDirContentsBrowser
+
+ ^ self application:#DirectoryContentsBrowser do:#doCopy.
+!
+
+cutInDirContentsBrowser
+
+ ^ self application:#DirectoryContentsBrowser do:#doCut.
+!
+
+deleteInDirContentsBrowser
+
+ ^ self application:#DirectoryContentsBrowser do:#doDelete.
+! !
+
+!AbstractFileBrowser methodsFor:'menu actions tools'!
+
+createProjectAndOpenProjectBrowser
+ |nm f s directory|
+
+ self currentFilesAreInSameDirectory ifFalse:[^ self].
+ directory := self currentDirectories value first.
+ nm := directory baseName.
+ f := (directory construct:nm) withSuffix:'prj'.
+ f exists ifTrue:[
+ Dialog warn:'A file named ' , f baseName , ' already exists.'.
+ ^ self.
+ ].
+ s := f writeStream.
+ s nextPutAll:'
+name ''' , nm , '''
+type #classLibrary
+package #''private:' , nm , '''
+prerequisites nil
+
+classes #( )
+'.
+ s close.
+ ProjectBrowser openOnFile:f.
+!
+
+fileFileIn
+ "fileIn the selected file(s)"
+
+ self fileFileInLazy:false
+!
+
+fileFileInLazy
+ "fileIn the selected file(s). Do a quick load (no compilation)"
+
+ self fileFileInLazy:true
+!
+
+fileFileInLazy:lazy
+ "fileIn the selected file(s)"
+
+ | selectedFiles|
+
+ selectedFiles:= self getFilesFromSelection.
+ selectedFiles do:[:fileName |
+ self singleFileFileIn:fileName lazy:lazy
+ ].
+!
+
+fileFileInToNameSpace
+ "fileIn the selected file(s)<into a nameSpace"
+
+ |ns listOfKnownNameSpaces|
+
+ listOfKnownNameSpaces := Set new.
+ NameSpace
+ allNamespaces
+ do:[:eachNameSpace |
+ listOfKnownNameSpaces add:eachNameSpace name
+ ].
+ listOfKnownNameSpaces := listOfKnownNameSpaces asOrderedCollection sort.
+
+ ns := Dialog
+ request:'During fileIn, new classes are created in nameSpace:'
+ initialAnswer:(LastEnforcedNameSpace ? Class nameSpaceQuerySignal query name)
+ list:listOfKnownNameSpaces.
+ ns isEmptyOrNil ifTrue:[^ self].
+
+ LastEnforcedNameSpace := ns.
+ ns := NameSpace name:ns.
+
+ Class nameSpaceQuerySignal
+ answer:ns
+ do:[ self fileFileInLazy:false ]
+!
+
+fileFindAllDuplicates
+ "scan directory and all subdirs for duplicate files"
+
+ |fileNames dir infoDir filesBySize
+ result info dirPrefix myName stream textBox maxLength directories|
+
+
+ self withWaitCursorDo:[
+ result := Dictionary new.
+ myName := self class name asString.
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[^ self].
+
+ dir := directories first.
+"/ self label: myName, '- gathering file names ...'.
+ fileNames := dir recursiveDirectoryContents.
+ fileNames := fileNames collect:[:fn | dir construct:fn].
+ fileNames := fileNames select:[:fn | fn isDirectory not].
+
+"/ self label:myName , '- gathering sizes ...'.
+ infoDir := Dictionary new.
+ fileNames do:[:fn |
+ infoDir at:fn put:(fn fileSize)
+ ].
+
+ "/ for each, get the files size.
+ "/ in a first pass, look for files of the same size and
+ "/ compare them ...
+
+"/ self label:myName , '- preselect possible duplicates ...'.
+ filesBySize := Dictionary new.
+ infoDir keysAndValuesDo:[:fn :sz |
+ |entry|
+
+ entry := filesBySize at:sz ifAbsentPut:[Set new].
+ entry add:fn.
+ ].
+
+ "/ any of same size ?
+
+"/ self label:myName , '- checking for duplicates ...'.
+ filesBySize do:[:entry |
+ |files|
+
+ entry size > 1 ifTrue:[
+ files := entry asArray.
+ 1 to:files size-1 do:[:idx1 |
+ idx1+1 to:files size do:[:idx2 |
+ |fn1 fn2|
+
+ fn1 := files at:idx1.
+ fn2 := files at:idx2.
+
+"/ self label:myName , '- checking ' , fn1 baseName , ' vs. ' , fn2 baseName , ' ...'.
+ (result at:fn2 ifAbsent:nil) ~= fn1 ifTrue:[
+ "/ compare the files
+ (fn1 sameContentsAs:fn2) ifTrue:[
+"/ Transcript show:'Same: '; show:fn1 baseName; show:' and '; showCR:fn2 baseName.
+ result at:fn1 put:fn2.
+ ]
+ ]
+ ]
+ ]
+ ]
+ ].
+
+"/ self label:myName , '- sorting ...'.
+ dirPrefix := dir pathName.
+ result := result associations.
+ result := result collect:[:assoc |
+ |f1 f2|
+
+ f1 := assoc key name.
+ f2 := assoc value name.
+ (f1 startsWith:dirPrefix) ifTrue:[
+ f1 := f1 copyFrom:dirPrefix size + 2.
+ ].
+ (f2 startsWith:dirPrefix) ifTrue:[
+ f2 := f2 copyFrom:dirPrefix size + 2.
+ ].
+ f1 < f2 ifTrue:[
+ f2 -> f1
+ ] ifFalse:[
+ f1 -> f2
+ ]
+ ].
+ result sort:[:f1 :f2 | f2 value < f1 value].
+
+ info := OrderedCollection new.
+ result do:[:assoc |
+ info add:(assoc key , ' same as ' , assoc value)
+ ].
+ info isEmpty ifTrue:[
+ info := 'No duplicate files found.'
+ ].
+ ].
+
+ stream := WriteStream on:''.
+ info do:[:el|
+ stream nextPutAll:el.
+ stream cr.
+ ].
+ textBox := TextBox new.
+ textBox initialText:(stream contents).
+ textBox title:'File dublicates in directory: ', dir asString.
+ textBox readOnly:true.
+ textBox noCancel.
+ textBox label:'Dublicates in ', dir asString.
+ maxLength := 10.
+ info do:[: el |
+ maxLength := maxLength max:(el size).
+ ].
+ textBox extent:((maxLength * 5)@(info size * 20)); sizeFixed:false.
+ textBox showAtPointer.
+ stream close.
+"/ subView contents:info.
+"/ self label:myName.
+!
+
+fileFindDuplicates
+ "scan directory for duplicate files"
+
+ |fileNames dir infoDir filesBySize
+ result info stream textBox maxLength directories allFiles titleStream size|
+
+"/ (self askIfModified:'contents has not been saved.\\Modifications will be lost when you proceed.'
+"/ yesButton:'proceed') ifFalse:[^ self].
+
+ self withWaitCursorDo:[
+ result := Dictionary new.
+
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[^ self].
+
+ allFiles := OrderedCollection new.
+ directories do:[ : dir|
+ fileNames := dir directoryContents.
+ fileNames := fileNames collect:[:fn | dir construct:fn].
+ fileNames := fileNames select:[:fn | fn isDirectory not].
+ allFiles addAll:fileNames.
+ ].
+
+ infoDir := Dictionary new.
+ allFiles do:[:fn |
+ infoDir at:fn put:(fn info)
+ ].
+
+ "/ for each, get the files size.
+ "/ in a first pass, look for files of the same size and
+ "/ compare them ...
+
+ filesBySize := Dictionary new.
+ infoDir keysAndValuesDo:[:fn :info |
+ |sz entry|
+
+ sz := info size.
+ entry := filesBySize at:sz ifAbsentPut:[Set new].
+ entry add:fn.
+ ].
+
+ "/ any of same size ?
+
+ filesBySize do:[:entry |
+ |files|
+
+ entry size > 1 ifTrue:[
+ files := entry asArray.
+ 1 to:files size-1 do:[:idx1 |
+ idx1+1 to:files size do:[:idx2 |
+ |fn1 fn2|
+
+ fn1 := files at:idx1.
+ fn2 := files at:idx2.
+
+ (result at:fn2 ifAbsent:nil) ~= fn1 ifTrue:[
+ "/ compare the files
+ (fn1 sameContentsAs:fn2) ifTrue:[
+"/ Transcript show:'Same: '; show:fn1 baseName; show:' and '; showCR:fn2 baseName.
+ result at:fn1 put:fn2.
+ ]
+ ]
+ ]
+ ]
+ ]
+ ].
+
+ result := result associations.
+ result := result collect:[:assoc |
+ |f1 f2|
+
+ f1 := assoc key asString.
+ f2 := assoc value asString.
+ f1 < f2 ifTrue:[
+ f2 -> f1
+ ] ifFalse:[
+ f1 -> f2
+ ]
+ ].
+ result sort:[:f1 :f2 | f2 value < f1 value].
+
+ info := OrderedCollection new.
+ size := self getBestDirectory asString size.
+ result do:[:assoc |
+ |fn1 fn2|
+
+ fn1 := assoc key.
+ fn2 := assoc value.
+ size > 1 ifTrue:[
+ fn1 := ('..', (fn1 copyFrom:(size + 1))).
+ fn2 := ('..', (fn2 copyFrom:(size + 1))).
+ ].
+ (fn1 includes:Character space) ifTrue:[
+ fn1 := '"' , fn1 , '"'
+ ].
+ (fn2 includes:Character space) ifTrue:[
+ fn2 := '"' , fn2 , '"'
+ ].
+ info add:(fn1 , ' same as ' , fn2)
+ ].
+ info isEmpty ifTrue:[
+ info add:'No duplicate files found.'
+ ].
+ ].
+ stream := WriteStream on:''.
+ info do:[:el|
+ stream nextPutAll:el.
+ stream cr.
+ ].
+ titleStream := WriteStream on:''.
+ titleStream nextPutAll:'File dublicates in director'.
+ directories size == 1 ifTrue:[
+ titleStream nextPutAll:'y: ', directories first asString.
+ ] ifFalse:[
+ titleStream nextPutAll:'ies: '.
+ titleStream cr.
+ directories do:[:dir|
+ size > 1 ifTrue:[
+ titleStream nextPutAll:'..'.
+ titleStream nextPutAll:((dir asString) copyFrom:(size + 1)).
+ ] ifFalse:[
+ titleStream nextPutAll:(dir asString).
+ ].
+ titleStream cr.
+ ]
+ ].
+
+ textBox := TextBox new.
+ textBox initialText:(stream contents).
+ textBox title:(titleStream contents).
+ textBox readOnly:true.
+ textBox noCancel.
+ textBox label:'Dublicates in ', dir asString.
+ maxLength := 10.
+ info do:[: el |
+ maxLength := maxLength max:(el size).
+ ].
+ textBox extent:((maxLength * 5)@(info size * 10)); sizeFixed:false.
+ textBox showAtPointer.
+ titleStream close.
+ stream close.
+!
+
+fileFindFile
+ |filename files|
+
+ files := self currentFileNameHolder value.
+ files notEmpty ifTrue:[
+ filename := files first.
+ ] ifFalse:[
+ filename := (Filename homeDirectory).
+ ].
+ FindFileApplication openOnFileName:filename.
+!
+
+installAllAsAutoloaded
+ "install all classes found here as autoloaded classes"
+
+ self allItemsOfCurrentDirectory do:[:fileItem |
+ (fileItem hasMimeType and:[fileItem mimeType isSmalltalkSource]) ifTrue:[
+ self installAsAutoloaded:(fileItem fileName).
+ ]
+ ].
+!
+
+installAsAutoloaded:aFilename
+ "install aFilename as autoloaded class"
+
+ |chunks s|
+
+ chunks := ChangeSet fromStream:(s := aFilename asFilename readStream). s close.
+ chunks
+ select:[:eachChunk | eachChunk isClassDefinitionChange]
+ thenDo:[:eachClassChunk | eachClassChunk installAsAutoloadedClassIfNotPrivate].
+!
+
+loadImageAndPerform:aSelectorOrBlock
+
+ |img path files|
+
+ files := self getFilesFromSelection.
+ files isEmpty ifTrue:[ ^ self].
+ files do:[:fileName |
+ path := fileName.
+ path isDirectory ifFalse:[
+ img := Image fromFile:(path pathName).
+ img notNil ifTrue:[
+ aSelectorOrBlock isSymbol ifTrue:[
+ img perform:aSelectorOrBlock
+ ] ifFalse:[
+ aSelectorOrBlock value:img
+ ]
+ ] ifFalse:[
+ Dialog warn:'unknown format: ' , fileName asString
+ ]
+ ]
+ ].
+!
+
+openASN1Browser
+
+ self openTool:OSI::ASN1Browser
+!
+
+openAppletViewer
+ |numItems files|
+
+ files := self getFilesFromSelection.
+ (numItems := files size) > 2 ifTrue:[
+ (self
+ confirm:(resources string:'open for each of the %1 items ?'
+ with:numItems)) ifFalse:[^ self].
+ ].
+
+ Java startupJavaSystem.
+"/ Java markAllClassesUninitialized.
+"/ Java initAllStaticFields.
+"/ Java initAllClasses.
+
+ files do:[:fileName |
+ |p path|
+
+ path := fileName.
+ path isDirectory ifFalse:[
+ p := Java
+ javaProcessForMainOf:(Java classForName:'sun.applet.AppletViewer')
+ argumentString:path pathName.
+ p resume.
+ ]
+ ].
+!
+
+openCBrowser
+
+ |directories|
+
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[ ^ self].
+ self withWaitCursorDo:[
+ CBrowser::Browser openIn:directories first.
+ ]
+!
+
+openChangesBrowser
+ "open a change browser on the selected file(s)"
+
+ self openTool:(UserPreferences current changesBrowserClass)
+!
+
+openDiffView
+ "open a diff-view"
+
+ | name1 name2 text1 text2 f d err nm l1 files title|
+
+ files := self getFilesFromSelection.
+ files isEmpty ifTrue:[
+ Dialog warn:'you have to select a file first'.
+ ^ self.
+ ].
+ (files size == 2) ifTrue:[
+ name1 := files last.
+ name2 := files first.
+ ] ifFalse:[
+ LastFileDiffFile notNil ifTrue:[
+"/ f := self currentDirectory value asFilename construct:(LastFileDiffFile baseName).
+ (LastFileDiffFile exists
+ and:[LastFileDiffFile isReadable]) ifTrue:[
+ name1 := f.
+ ]
+ ].
+ name2 := files first.
+ title := 'show difference between ', name2 baseName.
+ name1 := FileSelectionBox requestFileName:title default:(name1 baseName) fromDirectory:(name2 asFilename pathName).
+ ].
+
+ (name1 isNil or:[name1 asString isEmpty]) ifTrue:[
+ text1 := self getAllFilesAsStringCollection asStringCollection withTabs.
+ text1 := text1 collect:[:l | l isNil ifTrue:[' '] ifFalse:[l]].
+ name1 := nil.
+ l1 := 'browser contents'
+ ] ifFalse:[
+ LastFileDiffFile := name1.
+ name1 isReadable ifFalse:[
+ nm := name1.
+ name1 exists ifFalse:[
+ err := '%1 does not exist'.
+ ] ifTrue:[
+ err := '%1 is not readable'
+ ].
+ ].
+ l1 := name1 pathName
+ ].
+
+ err isNil ifTrue:[
+ name2 isReadable ifFalse:[
+ nm := name2.
+ name2 exists ifFalse:[
+ err := '%1 does not exist'.
+ ] ifTrue:[
+ err := '%1 is not readable'
+ ].
+ ].
+ ].
+ err notNil ifTrue:[
+ Dialog warn:(resources string:err with:nm pathName).
+ ^ self
+ ].
+
+ self withWaitCursorDo:[
+ name1 notNil ifTrue:[
+ text1 := name1 contents.
+ ].
+ text2 := name2 contents.
+ text1 = text2 ifTrue:[
+ self information:'same contents'
+ ] ifFalse:[
+ d := DiffTextView
+ openOn:text1 label:l1
+ and:text2 label:name2 pathName.
+ d label:'file differences'.
+ ]
+ ]
+!
+
+openEditor
+ self openTool:EditTextView
+!
+
+openHTMLReader
+
+ self openTool:HTMLDocumentView ignoreDirectories:false
+!
+
+openImageEditor
+
+ [self loadImageAndPerform:#edit] fork
+!
+
+openImageInspector
+ [self loadImageAndPerform:#inspect] fork
+!
+
+openImagePreview
+
+ [self loadImageAndPerform:[:img |
+ |i top viewer|
+
+ top := StandardSystemView new.
+
+ viewer := ImageView origin:0.0@0.0 corner:1.0@1.0 in:top.
+ i := img.
+ top extent:200@200.
+ top label:(img fileName asFilename directoryName asFilename baseName , '/' , img fileName asFilename baseName).
+ top openAndWait.
+
+ (i width > 200 or:[i height > 200]) ifTrue:[
+ i := i magnifiedPreservingRatioTo:200@200.
+ ].
+ viewer image:i.
+ ].
+ ] fork
+!
+
+openMP3Player
+ |file|
+
+ file := self getFilesFromSelection.
+ (file isEmpty) ifTrue:[
+ ^ self.
+ ].
+ file := file first.
+ (MP3PlayerApplication ? SaugFix::MP3PlayerApplication) playSong:file.
+!
+
+openSlideShow
+
+ |directories dir|
+
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[^ self].
+
+ dir := directories first.
+ CodingExamples_GUI::SlideShow openIn:dir.
+!
+
+openSnapshotImageBrowser
+ ^ self openTool:SystemBrowser with:#openOnSnapShotImage: ignoreDirectories:true
+!
+
+openTerminal
+
+ |directories dir|
+
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[
+ dir := Filename homeDirectory.
+ ] ifFalse:[
+ dir := directories first.
+ ].
+
+ VT100TerminalView openShellIn:dir.
+!
+
+openTool:aToolClass
+ "open a tool on the selected file(s)"
+
+ ^ self openTool:aToolClass ignoreDirectories:true
+!
+
+openTool:aToolClass ignoreDirectories:ignoreDirs
+ "open a tool on the selected file(s)"
+
+ ^ self
+ openTool:aToolClass
+ with:#openOn:
+ ignoreDirectories:ignoreDirs
+!
+
+openTool:aToolClass with:aSelector ignoreDirectories:ignoreDirs
+ "open a tool on the selected file(s)"
+
+ |numItems path tool files|
+
+ aToolClass isNil ifTrue:[
+ Dialog warn:'Sorry, that tool seems to be not available'.
+ ^ nil.
+ ].
+ files := self getFilesFromSelection.
+
+ (numItems := files size) > 2 ifTrue:[
+ (self
+ confirm:(resources string:'open for each of the %1 items ?'
+ with:numItems)) ifFalse:[^ self].
+ ].
+
+ self withWaitCursorDo:[
+ files do:[:fileName |
+ (ignoreDirs not or:[fileName isDirectory not]) ifTrue:[
+ fileName isAbsolute ifTrue:[
+ path := fileName getName.
+ ] ifFalse:[
+ path := fileName pathName.
+ ].
+ tool := aToolClass perform:aSelector with:path.
+ ]
+ ].
+ ].
+ ^ tool
+!
+
+openZipTool
+ |zipTool directories dir|
+
+ (zipTool := self openTool:ZipTool) notNil ifTrue:[
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[
+ dir := directories first.
+ ] ifFalse:[
+ dir := Filename homeDirectory.
+ ].
+
+ zipTool initialExtractDirectory:dir.
+ ].
+!
+
+readAbbrevFile
+ "read the abbrev file and install classes found there as autoloaded classes"
+
+ | directories dir|
+
+ directories := self getDirectoriesFromSelection.
+ directories isEmpty ifTrue:[^ self].
+
+ dir := directories first.
+ Smalltalk installAutoloadedClassesFrom:(dir construct:'abbrev.stc').
+!
+
+singleFileFileIn:fileName lazy:lazy
+ "fileIn the selected file(s)"
+
+ |aStream wasLazy|
+
+ fileName type == #regular ifTrue:[
+
+ (ObjectFileLoader notNil
+ and:[ObjectFileLoader hasValidBinaryExtension:fileName]) ifTrue:[
+ AbortOperationRequest catch:[
+ |p|
+
+ "/
+ "/ look if already loaded ... then unload first
+ "/
+ p := fileName pathName.
+ (ObjectFileLoader loadedObjectFiles includes:p) ifTrue:[
+ (Dialog confirm:(resources
+ string:'%1 is already loaded; load anyway ?'
+ with:p)) ifFalse:[
+ ^ self
+ ].
+ Transcript showCR:'unloading old ' , p , ' ...'.
+ ObjectFileLoader unloadObjectFile:p.
+ ].
+
+ Transcript showCR:'loading ' , p , ' ...'.
+ ObjectFileLoader loadObjectFile:p.
+ Class addInfoRecord:('fileIn ' , fileName)
+ ]
+ ] ifFalse:[ ((fileName hasSuffix:'cls')
+ and:[((fileName mimeTypeOfContents ? '') startsWith:'application/x-smalltalk-source') not ]) ifTrue:[
+ "/ loading a binary class file
+ aStream := fileName readStream.
+ aStream notNil ifTrue:[
+ aStream fileInBinary.
+ ]
+ ] ifFalse:[
+ ((fileName hasSuffix:'class')
+ or:[(fileName hasSuffix:'cla')]) ifTrue:[
+ "/ loading a java class file
+ JavaClassReader notNil ifTrue:[
+ JavaClassReader loadFile:(fileName pathName)
+ ]
+ ] ifFalse:[ (fileName hasSuffix:'sif') ifTrue:[
+ "/ loading a sif (smalltalk interchange format) file
+ SmalltalkInterchangeSTXFileInManager autoload.
+ SmalltalkInterchangeFileManager newForFileIn
+ fileName: fileName pathName;
+ fileIn.
+ ] ifFalse:[ (fileName hasSuffix:'pcl') ifTrue:[
+ Parcel isNil ifTrue:[
+ Dialog warn:'Parcel support not loaded.'
+ ] ifFalse:[
+ Parcel loadParcelFrom: fileName pathName
+ ]
+ ] ifFalse:[
+ "/ loading a regular (chunk) or xml source file
+ aStream := fileName readStream.
+ aStream notNil ifTrue:[
+ Error handle:[ : ex |
+ Dialog warn:'Error on file in: ', ex errorString.
+ ] do:[
+ [
+ Class withoutUpdatingChangesDo:[
+ wasLazy := Compiler compileLazy:lazy.
+ aStream fileIn.
+ ].
+ Class addInfoRecord:('fileIn ' , fileName asString)
+ ] ensure:[
+ Compiler compileLazy:wasLazy.
+ aStream close
+ ]
+ ]
+ ]
+ ]]]
+ ]]
+ ].
+! !
+
+!AbstractFileBrowser methodsFor:'menu queries cvs'!
+
+canCvsAddAndCommit
+
+ |fileItems|
+
+ fileItems := self getFileItemsFromSelection.
+ ^ (fileItems notEmpty and:[self currentFilesAreInSameDirectory]).
+!
+
+canRemoveCVSContainer
+
+ |fileItems dirOfFile cvsDir|
+
+ fileItems := self getFileItemsFromSelection.
+ fileItems isEmpty ifTrue:[^ false].
+ ^ ((fileItems detect:[:item|
+ dirOfFile := self getDirWithoutFileName:(item fileName).
+ cvsDir := dirOfFile construct:'CVS'.
+ (cvsDir isDirectory and:[cvsDir exists])
+ ] ifNone:[nil]) notNil).
+! !
+
+!AbstractFileBrowser methodsFor:'menu queries tools'!
+
+anySTFilesPresent
+
+ ^ self anyFilesPresentWithSuffix:'st'
+!
+
+canCreateNewProject
+
+ | contents |
+
+ self currentFilesAreInSameDirectory ifFalse:[^ false].
+ contents := self getItemsFromSelection.
+ ^ [
+ (((contents detect:[:item| item lastSuffix = 'prj'] ifNone:[nil]) isNil))
+ and:[((contents detect:[:item| item lastSuffix = 'st'] ifNone:[nil]) notNil)
+ ]]
+!
+
+canDoTerminal
+
+ ^ OperatingSystem isUNIXlike
+ or:[OperatingSystem isMSWINDOWSlike]
+!
+
+canDoTerminalAndSystemIsDOS
+
+ ^ self canDoTerminal and:[OperatingSystem isMSWINDOWSlike]
+!
+
+canDoTerminalAndSystemIsUnix
+
+ ^ self canDoTerminal and:[OperatingSystem isUNIXlike]
+!
+
+canReadAbbrevFile
+
+
+ self currentFilesAreInSameDirectory ifFalse:[^ false].
+ ^ (self currentDirectories value first construct:'abbrev.stc') exists
+!
+
+canRemoveFromSourcePath
+
+ ^ false
+!
+
+hasASN1
+ ^ [ OSI::ASN1Parser notNil
+ and:[OSI::ASN1Parser isLoaded]]
+
+!
+
+hasASN1AndSelection
+ ^ [ self hasSelection value
+ and:[self getFilesFromSelection size > 0
+ and:[OSI::ASN1Parser notNil
+ and:[OSI::ASN1Parser isLoaded]]]]
+!
+
+hasCBrowser
+ ^ [ CBrowser::Browser notNil ]
+!
+
+hasJava
+
+ ^ [ JavaClassReader notNil
+ and:[JavaClassReader isLoaded]]
+!
+
+hasJavaAndSelection
+
+ ^ [ self getFilesFromSelection size > 0
+ and:[JavaClassReader notNil
+ and:[JavaClassReader isLoaded]]]
+!
+
+hasMP3Player
+
+ ^ [ MP3PlayerApplication notNil
+ or:[SaugFix::MP3PlayerApplication notNil ]]
+!
+
+hasMP3PlayerAndSelection
+
+ ^ [ self getFilesFromSelection size > 0
+ and:[ self hasMP3Player value]]
+!
+
+hasSlideShow
+
+ ^ [CodingExamples_GUI::SlideShow notNil]
+!
+
+hasSnapshotSelection
+
+ ^ [
+ | files |
+ files := self getFilesFromSelection.
+ ((files size == 1)
+ and:[ files first hasSuffix:'img' ])
+ ]
+!
+
+hasZipFileSelected
+
+ ^ [|sel item fn suff|
+
+ sel := self getItemsFromSelection.
+ sel size == 1 ifTrue:[
+ item := sel first.
+ item notNil ifTrue:[
+ suff := item suffix asLowercase.
+ suff = 'zip' or:[suff = 'jar']
+ ] ifFalse:[
+ false
+ ]
+ ] ifFalse:[
+ false
+ ]
+ ]
+!
+
+javaSupportLoaded
+
+ ^ false
+! !
+
+!AbstractFileBrowser methodsFor:'queries'!
+
+initialCommandFor:fileName into:aBox
+ "set a useful initial command for execute box."
+
+ |mime cmd select path suffix|
+
+ path := self getDirWithoutFileName:fileName.
+ suffix := fileName asFilename suffix.
+ DefaultCommandPerSuffix notNil ifTrue:[
+ cmd := DefaultCommandPerSuffix at:suffix ifAbsent:nil.
+ cmd notNil ifTrue:[
+ aBox initialText:(cmd , ' ' , fileName baseName) selectFrom:1 to:cmd size.
+ ^ self
+ ].
+ ].
+ mime := MIMETypes mimeTypeForSuffix:suffix.
+"/ mime notNil ifTrue:[
+"/ cmd := self initialCommandForMIME:mime file:path
+"/ ].
+
+ "/ XXX should be changed to take stuff from a config file
+ "/ XXX or from resources.
+
+ (path type == #regular) ifTrue:[
+ path isExecutableProgram ifTrue:[
+ aBox initialText:(fileName , ' <arguments>').
+ ^ self
+ ].
+
+ select := true.
+
+ "some heuristics - my personal preferences ...
+ (actually this should come from a configfile)"
+
+ (fileName endsWith:'akefile') ifTrue:[
+ aBox initialText:'make target' selectFrom:6 to:11.
+ ^ self
+ ].
+
+ cmd := self class defaultCommandPerMIME at:mime ifAbsent:nil.
+ cmd notNil ifTrue:[
+ select := false
+ ].
+
+ cmd isNil ifTrue:[
+
+ suffix := path suffix.
+ (suffix = 'C') ifTrue:[
+ cmd := 'g++ -c %1'.
+ select := 6.
+ ] ifFalse:[
+ suffix := suffix asLowercase.
+
+ (suffix = 'taz') ifTrue:[
+ aBox initialText:'zcat %1 | tar tvf -'.
+ select := false.
+ ].
+ (suffix = 'tar') ifTrue:[
+ cmd := 'tar tvf %1'.
+ select := 7.
+ ].
+ (suffix = 'zoo') ifTrue:[
+ cmd := 'zoo -list %1'.
+ select := 9.
+ ].
+ (suffix = 'zip') ifTrue:[
+ cmd := 'unzip -l %1'.
+ select := 8.
+ ].
+ (suffix = 'jar') ifTrue:[
+ cmd := 'unzip -l %1'.
+ select := 8.
+ ].
+ (suffix = 'z') ifTrue:[
+ (fileName asLowercase endsWith:'tar.z') ifTrue:[
+ cmd := 'zcat %1 | tar tvf -'.
+ select := false.
+ ] ifFalse:[
+ cmd := 'uncompress %1'
+ ].
+ ].
+ (suffix = 'gz') ifTrue:[
+ (fileName asLowercase endsWith:'tar.gz') ifTrue:[
+ cmd := ('gunzip < %1 | tar tvf -' ).
+ select := false.
+ ] ifFalse:[
+ cmd := 'gunzip %1'.
+ ].
+ ].
+ (suffix = 'html') ifTrue:[
+ cmd := 'netscape %1'
+ ].
+ (suffix = 'htm') ifTrue:[
+ cmd := 'netscape %1'
+ ].
+ (suffix = 'uue') ifTrue:[
+ cmd := 'uudecode %1'
+ ].
+ (suffix = 'c') ifTrue:[
+ cmd := 'cc -c %1'.
+ select := 5.
+ ].
+ (suffix = 'cc') ifTrue:[
+ cmd := 'g++ -c %1'.
+ select := 6.
+ ].
+ (suffix = 'xbm') ifTrue:[
+ cmd := 'bitmap %1'
+ ].
+ (suffix = 'ps') ifTrue:[
+ cmd := 'ghostview %1'
+ ].
+ ((suffix = '1') or:[suffix = 'man']) ifTrue:[
+ cmd := 'nroff -man %1'.
+ select := 10.
+ ].
+ ].
+ ].
+
+ cmd isNil ifTrue:[
+ DefaultCommandPerSuffix isNil ifTrue:[
+ cmd := '<cmd>'
+ ] ifFalse:[
+ cmd := DefaultCommandPerSuffix
+ at:suffix
+ ifAbsent:'<cmd>'.
+ ].
+ cmd := cmd , ' %1'.
+ ].
+
+ cmd := cmd bindWith:fileName.
+ select == false ifTrue:[
+ aBox initialText:cmd
+ ] ifFalse:[
+ select class == Interval ifTrue:[
+ aBox initialText:cmd selectFrom:select start to:select stop
+ ] ifFalse:[
+ select isInteger ifFalse:[
+ select := (cmd indexOf:Character space ifAbsent:[cmd size + 1]) - 1.
+ ].
+ aBox initialText:cmd selectFrom:1 to:select
+ ].
+ ]
+ ]
+!
+
+isAbstractFileBrowser
+
+ ^ true
+!
+
+systemIsDOS
+
+ ^ OperatingSystem isMSDOSlike
+!
+
+systemIsUnix
+ ^ OperatingSystem isUNIXlike
+! !
+
+!AbstractFileBrowser methodsFor:'queries-file'!
+
+allItemsOfCurrentDirectory
+
+ ^ self application:#DirectoryContentsBrowser do:#allItemsOfCurrentDirectory.
+!
+
+anyFilesPresentWithSuffix:suffix
+
+ | directories |
+
+ directories := self currentDirectories value.
+ directories do:[ : dir|
+ (dir directoryContents do:[:f| (f asFilename suffix = suffix) ifTrue:[ ^ true]])
+ ].
+ ^ false.
+!
+
+currentFilesAreInSameDirectory
+
+ ^ (self currentDirectories value size == 1).
+!
+
+currentFilesHasDirectories
+
+ ^ self currentDirectories value notEmpty.
+!
+
+fileListIsEmpty
+
+ ^ self application:#DirectoryContentsBrowser do:#fileListIsEmpty.
+!
+
+fileListIsNotEmpty
+
+ ^ self fileListIsEmpty not.
+!
+
+fileName:aFilename1 startsWith:aFilename2
+
+" check if aFilename2 starts with the same directories like aFilename1 "
+
+ | file1 file2 |
+
+ aFilename2 isNil ifTrue:[ ^ false].
+ file1 := aFilename1 asFilename.
+ file2 := aFilename2 asFilename.
+ file2 isRootDirectory ifTrue:[ ^ true].
+ ((file1 isDirectory)
+ and:[(file2 isDirectory)
+ and:[file1 directory = file2 directory]]) ifTrue:[
+ ^ file1 baseName = file2 baseName
+ ].
+ ^ aFilename1 startsWith:aFilename2.
+!
+
+getAllFilesAsStringCollection
+
+ ^ self application:#DirectoryContentsBrowser do:#getAllFilesAsStringCollection.
+!
+
+getBestDirectory
+
+ |selFiles stringCol firstPre|
+
+ selFiles := self currentDirectories value.
+ selFiles isEmpty ifTrue:[^ nil].
+ selFiles size == 1 ifTrue:[^ selFiles first].
+ stringCol := (selFiles collect:[: file| file asString]) asOrderedCollection.
+ firstPre := stringCol at:1.
+ stringCol from:2 do:[:el|
+ firstPre := firstPre commonPrefixWith:el.
+ ].
+ (firstPre endsWith:(OperatingSystem fileSeparator)) ifTrue:[
+ firstPre removeLast.
+ ].
+ ^ firstPre asFilename
+!
+
+getBestFile
+
+ |selFiles stringCol firtsPre|
+
+ selFiles := self currentFileNameHolder value.
+ selFiles isEmpty ifTrue:[^ nil].
+ stringCol := selFiles collect:[: file| file asString].
+ firtsPre := stringCol at:1.
+ stringCol from:2 do:[:el|
+ firtsPre := firtsPre commonPrefixWith:el.
+ ].
+ ^ firtsPre asFilename
+!
+
+getDirWithoutFileName:aFileName
+
+ | dir |
+ aFileName isNil ifTrue:[
+ ^ aFileName.
+ ].
+ dir := aFileName asFilename.
+ dir isDirectory ifFalse:[
+ dir := dir directory.
+ ].
+ ^ dir.
+!
+
+getDirectoriesForFileList:aFileCol
+
+ ^ ((aFileCol collect:[:file| self getDirWithoutFileName:file]) asSet).
+!
+
+getDirectoriesFromSelection
+
+ ^ self currentDirectories value.
+!
+
+getFileItemsFromSelection
+
+ ^ self application:#DirectoryContentsBrowser do:#getFileItemsFromSelection.
+!
+
+getFilesFromSelection
+
+ | files |
+ files := self currentFileNameHolder value.
+ ^ (files select:[: file | file isDirectory not]).
+!
+
+getFirstFileFromSelection
+
+ | files |
+ files := self currentFileNameHolder value.
+ ^ (files detect:[: file | file isDirectory not] ifNone:[nil]).
+!
+
+getFirstItemFromSelection
+
+ ^ self application:#DirectoryContentsBrowser do:#getFirstItemFromSelection.
+!
+
+getInfoItem
+ "get filename of a description-file (.dir.info, README etc.);
+ This file is automatically shown when a directory is enterred.
+ You can add more names below if you like."
+
+ |directories|
+
+ directories := self getDirectoriesFromSelection.
+ (directories size ~= 1) ifTrue:[ ^ nil].
+
+ #(
+ '.dir.info'
+ 'README'
+ 'ReadMe'
+ 'Readme'
+ 'readme'
+ 'read.me'
+ 'Read.me'
+ 'READ.ME'
+ 'README.TXT'
+ 'readme.txt'
+ 'Readme.txt'
+ 'Info.txt'
+ 'info.txt'
+ 'INFO.TXT'
+ ) do:[:f |
+ |n|
+ n := (directories first) construct:f.
+ (n isReadable and:[n isDirectory not]) ifTrue:[
+ ^ (DirectoryContentsBrowser itemClass with:n) .
+ ]
+ ].
+ ^ nil
+!
+
+getItemsFromSelection
+
+ ^ self application:#DirectoryContentsBrowser do:#getItemsFromSelection.
+! !
+
+!AbstractFileBrowser methodsFor:'startup & release'!
+
+makeDependent
+
+ "
+ never invoked here because there is no instance
+ "
+!
+
+masterApplication:anApplication
+
+ masterApplication isNil ifTrue:[
+ (anApplication notNil and:[anApplication askFor:#isAbstractFileBrowser]) ifTrue:[
+ super masterApplication:anApplication.
+ aspects := anApplication aspects
+ ] ifFalse:[
+ aspects isNil ifTrue:[
+ aspects := IdentityDictionary new.
+ aspects at:#applications put:(IdentityDictionary new).
+ ]
+ ].
+ self applications at:(self className) put:self.
+ self makeDependent.
+ ].
+!
+
+postOpenWith:aBuilder
+
+ super postOpenWith:aBuilder.
+! !
+
+!AbstractFileBrowser::Clipboard methodsFor:'accessing'!
+
+files
+ "return the value of the instance variable 'files' (automatically generated)"
+
+ ^ files
+!
+
+files:something
+ "set the value of the instance variable 'files' (automatically generated)"
+
+ files := something.
+!
+
+method
+ "return the value of the instance variable 'method' (automatically generated)"
+
+ ^ method
+!
+
+method:something
+ "set the value of the instance variable 'method' (automatically generated)"
+
+ method := something.
+! !
+
+!AbstractFileBrowser::CodeExecutionLock methodsFor:'accessing'!
+
+locked
+ "return the value of the instance variable 'locked' (automatically generated)"
+
+ locked isNil ifTrue:[
+ locked := false.
+ ].
+ ^ locked
+! !
+
+!AbstractFileBrowser::CodeExecutionLock methodsFor:'actions'!
+
+doIfUnLocked:aBlock
+
+ self locked ifFalse:[
+ aBlock value.
+ ].
+!
+
+doLocked:aBlock
+
+ locked := true.
+ aBlock value.
+ locked := false.
+! !
+
+!AbstractFileBrowser::DirectoryHistory class methodsFor:'attributes access'!
+
+HistorySize
+
+ ^ 20
+! !
+
+!AbstractFileBrowser::DirectoryHistory methodsFor:'actions'!
+
+doBack
+
+ self isEmpty ifTrue:[ ^ nil ].
+ index > 1 ifTrue:[
+ index := index - 1.
+ ^ self at:index ifAbsent:nil.
+ ].
+ ^ nil
+!
+
+doForward
+
+ self isEmpty ifTrue:[ ^ nil ].
+ index < self size ifTrue:[
+ index := index + 1.
+ ^ self at:index ifAbsent:nil.
+ ].
+ ^ nil
+!
+
+setIndexTo:aFile
+
+ index := self indexOf:aFile.
+! !
+
+!AbstractFileBrowser::DirectoryHistory methodsFor:'adding & removing'!
+
+addFile:aFilename
+
+ index notNil ifTrue:[
+ ((self at:index) = aFilename) ifTrue:[^ self].
+ ].
+ (self includes:aFilename) ifTrue:[
+ "/ remove the filename to put it later after index
+ self remove:aFilename.
+ ].
+ self size > self class HistorySize ifTrue:[
+ self removeFirst.
+ ].
+ index isNil ifTrue:[
+ self add:aFilename.
+ index := 1.
+ ] ifFalse:[
+ self add:aFilename afterIndex:index.
+ index := index + 1.
+ ].
+!
+
+remove:aFilename
+
+ | indexOfFile |
+
+ indexOfFile := self indexOf:aFilename.
+ index >= indexOfFile ifTrue:[
+ index := index - 1.
+ ].
+ super remove:aFilename.
+!
+
+removeBack
+
+ index == 1 ifTrue:[^ self].
+ self removeFromIndex:1 toIndex:index - 1.
+ index := 1.
+!
+
+removeFirst
+
+ super removeFirst.
+ index ~= 1 ifTrue:[
+ index := index - 1
+ ].
+!
+
+removeForward
+
+ self removeFromIndex:(index + 1) toIndex:(self size).
+! !
+
+!AbstractFileBrowser::DirectoryHistory methodsFor:'queries'!
+
+canBack
+
+ ^ (index notNil and:[index > 1])
+!
+
+canForward
+
+ ^ (index notNil and:[(index < self size)])
+! !
+
+!AbstractFileBrowser::FilenameHistory class methodsFor:'attributes access'!
+
+FilenameHistorySize
+
+ ^ 20
+!
+
+HistorySize
+
+ ^ 20
+! !
+
+!AbstractFileBrowser::FilenameHistory methodsFor:'adding & removing'!
+
+add:aApplItem
+
+ super add:aApplItem.
+ (self size > self class FilenameHistorySize) ifTrue:[
+ self removeLast.
+ ]
+! !
+
+!AbstractFileBrowser::SaveAspectItem class methodsFor:'instance creation'!
+
+withValue:aValue isHolder:aBoolean
+
+ | instance |
+
+ instance := self basicNew.
+ instance value:aValue.
+ instance isHolder:aBoolean.
+ ^ instance
+! !
+
+!AbstractFileBrowser::SaveAspectItem methodsFor:'accessing'!
+
+isHolder
+ "return the value of the instance variable 'isHolder' (automatically generated)"
+
+ ^ isHolder
+!
+
+isHolder:something
+ "set the value of the instance variable 'isHolder' (automatically generated)"
+
+ isHolder := something.
+!
+
+value
+ "return the value of the instance variable 'value' (automatically generated)"
+
+ ^ value
+!
+
+value:something
+ "set the value of the instance variable 'value' (automatically generated)"
+
+ value := something.
+! !
+
+!AbstractFileBrowser class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/AbstractFileBrowser.st,v 1.1 2002-09-25 07:58:48 penk Exp $'
+! !
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/DirectoryTreeBrowser.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,1053 @@
+"{ Package: 'stx:libtool' }"
+
+AbstractFileBrowser subclass:#DirectoryTreeBrowser
+ instanceVariableNames:'rootHolder dirBrowser lastResponse updateToExternFileHolderLock
+ oldDropItem expandItemTimedBlock updateTreeSelection'
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+HierarchicalFileList subclass:#DirTreeBrowserHFL
+ instanceVariableNames:'draggedItem'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:DirectoryTreeBrowser
+!
+
+!DirectoryTreeBrowser class methodsFor:'documentation'!
+
+documentation
+"
+ documentation to be added.
+
+ [author:]
+ Christian Penk (penk@bierfix)
+
+ [see also:]
+
+ [instance variables:]
+
+ [class variables:]
+"
+!
+
+examples
+"
+ Starting the application:
+ [exBegin]
+ DirectoryTreeBrowser open
+
+ [exEnd]
+
+ more examples to be added:
+ [exBegin]
+ ... add code fragment for
+ ... executable example here ...
+ [exEnd]
+"
+! !
+
+!DirectoryTreeBrowser class methodsFor:'instance creation'!
+
+open
+
+ ^ super open
+"
+ DirectoryTreeBrowser open
+"
+!
+
+openOn:aFileName
+
+ | file |
+ file := aFileName asFilename.
+ file exists ifTrue:[
+ self openOn:aFileName withFiles:(file isDirectory not)
+ ]
+
+"
+ DirectoryTreeBrowser openOn:Filename homeDirectory
+ DirectoryTreeBrowser openOn:(Filename homeDirectory construct:'.bashrc')
+"
+!
+
+openOn:aFileName withFiles:aBoolean
+
+ | instance|
+
+ instance := DirectoryTreeBrowser new.
+ instance open.
+ instance viewFilesInDirectoryTree value:aBoolean.
+ instance currentFileNameHolder value:(OrderedCollection with:aFileName).
+"
+ DirectoryTreeBrowser openOn:Filename homeDirectory
+ DirectoryTreeBrowser openOn:(Filename homeDirectory construct:'.bashrc') withFiles:false
+"
+! !
+
+!DirectoryTreeBrowser class methodsFor:'defaults'!
+
+timeForExpandOnDropInMilliseconds
+
+ ^ 1500
+! !
+
+!DirectoryTreeBrowser class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:DirectoryTreeBrowser andSelector:#windowSpec
+ DirectoryTreeBrowser new openInterface:#windowSpec
+ DirectoryTreeBrowser open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'DirectoryTreeBrowser'
+ #name: 'DirectoryTreeBrowser'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 16 42 316 342)
+ #menu: #mainMenu
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#HierarchicalListViewSpec
+ #name: 'HierarchicalListView'
+ #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+ #model: #treeSelectionHolder
+ #menu: #menu
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #miniScrollerHorizontal: false
+ #miniScrollerVertical: false
+ #listModel: #fileList
+ #multipleSelectOk: true
+ #highlightMode: #line
+ #doubleClickSelector: #doDoubleClick:
+ #indicatorSelector: #doIndicatorClick:
+ #postBuildCallback: #postBuildDirBrowser:
+ #properties:
+ #(#PropertyListDictionary
+ #dragArgument: #directoryTreeBrowser
+ #startDragSelector: #doStartDrag:in:
+ #displayObjectSelector: #getDisplayObjects:
+ #dropObjectSelector: #getDropObjects:
+ #dropArgument: #directoryTreeBrowser
+ #canDropSelector: #canDrop:argument:
+ #leaveSelector: #dropLeave:
+ #dropSelector: #doDrop:argument:
+ )
+ )
+ )
+
+ )
+ )
+! !
+
+!DirectoryTreeBrowser class methodsFor:'menu specs'!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:DirectoryTreeBrowser andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(DirectoryTreeBrowser menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Copy'
+ #translateLabel: true
+ #value: #doCopy
+ #shortcutKeyCharacter: #Copy
+ )
+ #(#MenuItem
+ #label: 'Cut'
+ #translateLabel: true
+ #value: #doCut
+ #shortcutKeyCharacter: #Cut
+ )
+ #(#MenuItem
+ #label: 'Paste'
+ #translateLabel: true
+ #value: #pasteFiles
+ #enabled: #canPaste
+ #shortcutKeyCharacter: #Paste
+ )
+ #(#MenuItem
+ #label: 'Delete'
+ #translateLabel: true
+ #nameKey: #delete
+ #value: #doDelete
+ #shortcutKeyCharacter: #Delete
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Directory Up'
+ #translateLabel: true
+ #value: #doGoDirectoryUp
+ #enabled: #enableDirectoryUp
+ #shortcutKeyCharacter: #CursorLeft
+ )
+ #(#MenuItem
+ #label: 'Set Selection Top'
+ #translateLabel: true
+ #value: #doSetSelectionToTop
+ #enabled: #selectedFileIsDirectoryAndNotRoot
+ )
+ #(#MenuItem
+ #label: 'Re-/ Expand Directory'
+ #translateLabel: true
+ #value: #expandSelectedItem
+ #shortcutKeyCharacter: #CursorRight
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'View Directory Tree'
+ #translateLabel: true
+ #isVisible: #masterIsFileBrowser
+ #indication: #showDirectoryTreeHolder
+ )
+ #(#MenuItem
+ #label: 'View Files in Directory Tree'
+ #translateLabel: true
+ #indication: #viewFilesInDirectoryTree
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'New'
+ #translateLabel: true
+ #submenuChannel: #newMenu
+ )
+ #(#MenuItem
+ #label: 'Rename...'
+ #translateLabel: true
+ #value: #treeViewFileRename
+ #shortcutKeyCharacter: #Replace
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!DirectoryTreeBrowser class methodsFor:'plugIn spec'!
+
+aspectSelectors
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this. If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "Return a description of exported aspects;
+ these can be connected to aspects of an embedding application
+ (if this app is embedded in a subCanvas)."
+
+ ^ #(
+ #selectedDirectoryModel
+ ).
+
+! !
+
+!DirectoryTreeBrowser methodsFor:'accessing'!
+
+updateToExternFileHolderLock
+ "return the value of the instance variable 'updateToExternFileHolder' (automatically generated)"
+
+ updateToExternFileHolderLock isNil ifTrue:[
+ updateToExternFileHolderLock := self class newLock.
+ ].
+ ^ updateToExternFileHolderLock
+!
+
+updateTreeSelection
+ "return the value of the instance variable 'updateToExternFileHolder' (automatically generated)"
+
+ updateTreeSelection isNil ifTrue:[
+ updateTreeSelection := self class newLock.
+ ].
+ ^ updateTreeSelection
+! !
+
+!DirectoryTreeBrowser methodsFor:'actions'!
+
+doDoubleClick:anIndex
+ "handle a doubleClick on a directory
+ "
+
+ |item file isDirectory|
+
+ item := self fileList at:anIndex ifAbsent:nil.
+ item notNil ifTrue:[
+ isDirectory := item isDirectory.
+ file := item fileName.
+ isDirectory ifTrue:[
+ (file isReadable and:[file isExecutable]) ifTrue:[
+ self doExpand:item.
+ ]
+ ] ifFalse:[
+"/ self openApplByFileItem:item.
+ ]
+ ]
+!
+
+doExpand:anItem
+" expand the item; return true the item have expanded "
+
+ (anItem notNil and:[anItem isDirectory and:[anItem isExpanded not]]) ifTrue:[
+ anItem toggleExpand.
+ ^ true.
+ ].
+ ^ false
+!
+
+doIndicatorClick:anIndex
+ "handle a click on the indicator
+ "
+
+ |item|
+
+ item := self fileList at:anIndex ifAbsent:nil.
+ self toggleExpand:item
+!
+
+doUpdate
+
+ self fileList monitoringCycle.
+"/ self updateSelectedItem
+!
+
+expandSelectedItem
+
+ |selDir|
+
+ selDir := self getFirstDirectoryItemOfSelection.
+ selDir isNil ifTrue:[^ self ].
+ self toggleExpand:selDir.
+!
+
+setMatchBlock
+
+ |list|
+
+ list := self fileList.
+ self setMatchBlockForList:list
+!
+
+setMatchBlockForList:list
+
+ self viewFilesInDirectoryTree value ifTrue:[
+ list matchBlock:[:fn :isDir| isDir or:[
+ (self showHiddenFiles value ifFalse:[
+ (fn baseName startsWith:'.') not])
+ and:[self filterModel value match:fn baseName]]]
+ ] ifFalse:[
+ list matchBlock:[:fn :isDir| isDir ].
+ ].
+!
+
+toggleExpand:anItem
+
+ (anItem notNil and:[anItem isDirectory]) ifTrue:[
+ anItem toggleExpand
+ ].
+!
+
+treeViewFileRename
+ |selectedFiles|
+
+ selectedFiles := self getFilesForSelection.
+ self renameFiles:selectedFiles.
+!
+
+updateSelectedItem
+
+ | sel |
+
+ sel := self getItemsForSelection.
+ sel isEmpty ifTrue:[ ^ self].
+ sel do:[:item|
+ self doExpand:item.
+ item invalidateRepairNow:true.
+ ]
+! !
+
+!DirectoryTreeBrowser methodsFor:'aspects'!
+
+fileList
+ "holder, which keeps the current list of file entries shown by the directory-browser
+ "
+
+ |list|
+
+ (list := builder bindingAt:#fileList) isNil ifTrue:[
+ list := DirTreeBrowserHFL new.
+ list application:self.
+ list showRoot:true.
+ self setMatchBlockForList:list.
+ list directory:(self rootHolder value).
+ builder aspectAt:#fileList put:list.
+ list monitoringTaskDelay:2
+ ].
+ ^ list
+!
+
+rootHolder
+ "holder, which keeps the current root directory
+ "
+ rootHolder isNil ifTrue:[
+ rootHolder := ValueHolder new.
+ rootHolder addDependent:self.
+ ].
+ ^ rootHolder.
+! !
+
+!DirectoryTreeBrowser methodsFor:'change & update'!
+
+changeCurrentFileNameHolder
+
+ | viewFiles curFiles sel currentFileDir|
+
+ viewFiles := self viewFilesInDirectoryTree value.
+ curFiles := self currentFileNameHolder value.
+ " if i cant select the files because viewFiles is false i cant take my
+ selction to overwrite currentFileNameHolder
+ "
+ sel := self getFilesForSelection.
+ viewFiles not ifTrue:[
+ (self currentFilesAreInSameDirectory and:[sel size == 1]) ifTrue:[
+ currentFileDir := self getDirWithoutFileName:(self currentFileNameHolder value first).
+ (sel first = currentFileDir) ifTrue:[
+ ^ self.
+ ].
+ ].
+ ].
+ self currentFileNameHolder value:sel.
+!
+
+changeSelection
+
+ |currentHolder newItem directoryName directory oldSel index viewFiles newSel newColOfItems bestFile dir|
+
+ newSel := OrderedCollection new.
+ currentHolder := self currentFileNameHolder value.
+ currentHolder isEmpty ifTrue:[
+ self treeSelectionHolder value:newSel withoutNotifying:self.
+ ^ self
+ ].
+ bestFile := self getBestFile.
+ directory := self getDirWithoutFileName:bestFile.
+ directoryName := directory asString.
+ viewFiles := self viewFilesInDirectoryTree value.
+
+
+ ((rootHolder value isNil) or:[((self fileName:directoryName startsWith:rootHolder value)) not]) ifTrue:[
+ self setNewRoot:directory.
+ ].
+ newColOfItems := Set new.
+ oldSel := self getItemsForSelection.
+ currentHolder do:[ : file |
+ oldSel notEmpty ifTrue:[
+ newItem := oldSel detect:[: item| item fileName = file] ifNone:[nil].
+ ].
+ newItem isNil ifTrue:[
+ ((viewFiles not) and:[file isDirectory not]) ifTrue:[
+ "/ select directory because cant select filename - if is not in tree
+ dir := self getDirWithoutFileName:file.
+ newItem := self recursiveGetItemFor:dir.
+ ] ifFalse:[
+ newItem := self recursiveGetItemFor:file.
+ ].
+ ].
+ newItem notNil ifTrue:[
+ newColOfItems add:newItem.
+ ].
+ ].
+ newSel := OrderedCollection new.
+ newColOfItems do:[ : item |
+ index := self fileList indexOf:item.
+ newSel add:index.
+ ].
+ self treeSelectionHolder value:newSel.
+ newColOfItems size == 1 ifTrue:[
+ | item |
+ item := newColOfItems first.
+ item isDirectory ifTrue:[
+ self doExpand:item.
+ ]
+ ]
+!
+
+recursiveGetItemFor:aDirectory
+
+ ^ self recursiveGetItemFor:aDirectory fromIndex:1
+!
+
+recursiveGetItemFor:aFile fromIndex:aStartIndex
+ |list aFileNameString startIndex retItem|
+
+ list := self fileList.
+ aFileNameString := aFile asString.
+ retItem := nil.
+ list from:aStartIndex
+ do:[:item |
+ |filename |
+
+ filename := item fileName asString.
+ (self fileName:aFileNameString startsWith:filename) ifTrue:[
+ (filename asFilename pathName = aFileNameString asFilename pathName) ifTrue:[
+ ^ item
+ ].
+ (item isExpanded not and:[item canExpand]) ifTrue:[
+ item toggleExpand.
+ startIndex := list indexOf:item.
+ retItem := self recursiveGetItemFor:aFile fromIndex:startIndex.
+ ^ retItem
+ ]
+ ]
+ ].
+ ^ retItem
+!
+
+setNewRoot:directoryPath
+
+ | listOfFiles|
+
+ "/ EXPAND THE ROOT DIR
+ self rootHolder value:directoryPath.
+ listOfFiles := self fileList.
+ (listOfFiles first isExpanded not) ifTrue:[
+ listOfFiles first toggleExpand.
+ ].
+!
+
+update:something with:aParameter from:aModel
+ "one of my models changed
+ "
+
+ |list file|
+
+ " the execution of changeSelection and changeCurrentFileNameHolder must
+ lock against each other because values dont must be the same (e.g. no files
+ in tree view)
+ "
+
+ aModel == self currentFileNameHolder ifTrue:[
+ self updateTreeSelection doIfUnLocked:[
+ self updateToExternFileHolderLock doLocked:[
+ self changeSelection.
+ ].
+ ].
+ " do not return here because the AbstractFileBrowserComponent have to do something
+ for every application "
+"/ ^ self.
+ ].
+ aModel == self treeSelectionHolder ifTrue:[
+ self updateToExternFileHolderLock doIfUnLocked:[
+ self updateTreeSelection doLocked:[
+ self changeCurrentFileNameHolder.
+ ]
+ ].
+ ^ self
+ ].
+ aModel == rootHolder ifTrue:[
+ list := self fileList.
+ file := aModel value.
+ file notNil ifTrue:[
+ file := Filename named:(file asString).
+ (file isDirectory and:[file isReadable and:[file isExecutable]]) ifTrue:[
+ list directory:file
+ ]
+ ].
+ aModel value:(list directory asString) withoutNotifying:self.
+ ^ self.
+ ].
+ aModel == self viewFilesInDirectoryTree ifTrue:[
+ self setMatchBlock.
+ "/ if changed to true select the files in currentFilenameHolder in treeview
+ aModel value ifTrue:[
+ self changeSelection.
+ ].
+ ^ self.
+ ].
+ aModel == self filterModel ifTrue:[
+ self setMatchBlock.
+ ].
+ super update:something with:aParameter from:aModel.
+ ^ self
+! !
+
+!DirectoryTreeBrowser methodsFor:'drag & drop'!
+
+canDrop:aContext argument:arg2
+ |source lineNr archivListDrop destinationItem dropToFile|
+
+ source := aContext dropSource.
+ source isNil ifTrue:[^ false ].
+ archivListDrop := (source argument == #archivApplication).
+ lineNr := self getLineNumberFor:aContext.
+ lineNr notNil ifTrue:[
+ destinationItem := self fileList at:lineNr ifAbsent:nil.
+ ].
+ destinationItem isNil ifTrue:[
+ oldDropItem notNil ifTrue:[
+ self removeExpandItemTimedBlock.
+ self enqueueChangeDraggedItem:nil with:aContext.
+ oldDropItem := nil.
+ ].
+ ^ false
+ ].
+ (destinationItem ~~ oldDropItem) ifTrue:[
+ oldDropItem := destinationItem.
+ self enqueueChangeDraggedItem:nil with:aContext.
+ destinationItem isDirectory ifTrue:[
+ self enqueueChangeDraggedItem:destinationItem with:aContext.
+ ].
+ self removeExpandItemTimedBlock.
+ (destinationItem notNil and:[destinationItem isDirectory and:[destinationItem fileName isWritable]]) ifTrue:[
+ expandItemTimedBlock := [
+ self enqueueExpandForDrop:destinationItem with:aContext
+ ].
+ Processor addTimedBlock:expandItemTimedBlock
+ afterMilliseconds:(self class timeForExpandOnDropInMilliseconds).
+ dropToFile := destinationItem fileName.
+ archivListDrop ifTrue:[
+ lastResponse := self canDropArchiv:(aContext dropObjects) for:dropToFile
+ ] ifFalse:[
+ lastResponse := self canDropFiles:(aContext dropObjects) for:dropToFile
+ ]
+ ] ifFalse:[
+ lastResponse := false
+ ]
+ ].
+ ^ lastResponse
+!
+
+changeDraggedItem:anItem with:aDropContext
+
+ self changeDraggedItem:anItem with:aDropContext saveDraw:true
+!
+
+changeDraggedItem:anItem with:aDropContext saveDraw:saveDraw
+
+ saveDraw ifTrue:[
+ aDropContext saveDraw:[
+ self fileList draggedItem:anItem.
+ self windowGroup processExposeEvents.
+ ]
+ ] ifFalse:[
+ self fileList draggedItem:anItem.
+ self windowGroup processExposeEvents.
+ ]
+!
+
+doDrop:aContext
+ |col destination destinationPath lineNr source receiver|
+
+ source := aContext dropSource.
+ lineNr := self getLineNumberFor:aContext.
+ lineNr isNil ifTrue:[
+ ^ false
+ ].
+ destination := self fileList at:lineNr.
+ destinationPath := destination fileName.
+ source argument == #archivApplication ifTrue:[
+ receiver := source receiver.
+ receiver extractSelectedFilesTo:destinationPath askForExtractOptions:true.
+ ^ true
+ ].
+ col := OrderedCollection new.
+ aContext dropObjects do:[:obj |
+ col add:(obj theObject)
+ ].
+ self enqueueCopyOrMoveFiles:col to:destinationPath.
+ ^ true
+!
+
+doDrop:aContext argument:arg2
+
+ | aBoolean |
+
+ aBoolean := self doDrop:aContext.
+ self dropLeave:aContext.
+ ^ aBoolean.
+!
+
+dropLeave:aDropContext
+ "send the last time, when leaving the widget
+ "
+ self removeExpandItemTimedBlock.
+ oldDropItem := nil.
+ self changeDraggedItem:nil with:aDropContext saveDraw:false.
+ lastResponse := nil.
+!
+
+enqueueChangeDraggedItem:anItem with:aContext
+
+ self enqueueMessage:#'changeDraggedItem:with:' for:self arguments:(Array with:anItem with:aContext)
+!
+
+enqueueCopyOrMoveFiles:col to:destinationPath
+
+ self enqueueMessage:#'copyOrMoveFiles:to:' for:self arguments:(Array with:col with:destinationPath)
+!
+
+enqueueExpandForDrop:item with:aDropContext
+
+ self enqueueMessage:#'expandForDrop:with:' for:self arguments:(Array with:item with:aDropContext)
+!
+
+expandForDrop:item with:aDropContext
+
+ aDropContext saveDraw:[
+ (self doExpand:item) ifTrue:[
+ self windowGroup processExposeEvents
+ ].
+ ]
+!
+
+getDisplayObjects:anArgument
+
+ | string fnName sel size stream|
+ sel := self getFilesForSelection.
+ size := sel size.
+ size == 0 ifTrue:[^ ''].
+ stream := WriteStream on:''.
+ stream nextPutAll:sel first baseName.
+ size == 1 ifTrue:[
+ fnName := 'ui_menuitem.xpm'.
+ ] ifFalse:[
+ fnName := 'ui_submenu_open.xpm'.
+ stream nextPutAll:' ... '.
+ stream nextPutAll:sel last baseName.
+ ].
+ string := stream contents.
+ stream close.
+
+ fnName := 'ui_menuitem.xpm'.
+ ^ Array with:(LabelAndIcon icon:(Image fromFile:fnName)
+ string:(Text string:string emphasis:#bold)
+ )
+!
+
+getDropObjects:anArgument
+
+ | sel ret|
+
+ sel := self getFilesForSelection.
+ sel isEmpty ifTrue:[ ^ self ].
+ ret := sel collect:[:file|
+ DropObject newFile:file
+ ].
+ ^ ret
+!
+
+getLineNumberFor:aDropContext
+ | yVisible|
+
+ yVisible := (aDropContext targetPoint y).
+ ^ dirBrowser yVisibleToLineNr:yVisible.
+!
+
+removeExpandItemTimedBlock
+ expandItemTimedBlock notNil ifTrue:[
+ Processor removeTimedBlock:expandItemTimedBlock.
+ expandItemTimedBlock := nil
+ ]
+! !
+
+!DirectoryTreeBrowser methodsFor:'event handling'!
+
+processEvent:anEvent
+ "filter keyboard events.
+ Return true, if I have eaten the event"
+
+ |focusView key rawKey|
+
+ anEvent isKeyPressEvent ifTrue:[
+ focusView := anEvent targetView.
+ key := anEvent key.
+ rawKey := anEvent rawKey.
+
+ (focusView isSameOrComponentOf:self window) ifTrue:[
+ focusView name = 'editField' ifTrue:[ ^ false].
+"/ (key ~= #'Alt_L') ifTrue:[self halt.].
+ (key == #CursorLeft) ifTrue:[
+ self doGoDirectoryUp.
+ ^ true
+ ].
+ (key == #CursorRight) ifTrue:[
+ self doBack.
+ ^ true
+ ].
+ (key == #Replace) ifTrue:[
+ self treeViewFileRename.
+ ^ true
+ ].
+ (key == #Delete) ifTrue:[
+ self doDelete.
+ ^ true
+ ].
+ (key == #Cut) ifTrue:[
+ self doCut.
+ ^ true
+ ].
+ (key == #Paste) ifTrue:[
+ self pasteFiles.
+ ^ true
+ ].
+ (key == #Copy) ifTrue:[
+ self doCopy.
+ ^ true
+ ].
+ ]
+ ].
+ ^ false
+! !
+
+!DirectoryTreeBrowser methodsFor:'menu - actions'!
+
+doSetSelectionToTop
+ | selDir|
+
+ selDir := self getFirstDirectoryOfSelection.
+ selDir notNil ifTrue:[
+ self rootHolder value asFilename = selDir ifTrue:[ ^ self].
+ self setNewRoot:selDir.
+ self currentFileNameHolder value:(OrderedCollection with:selDir).
+ ].
+! !
+
+!DirectoryTreeBrowser methodsFor:'queries'!
+
+getFilesForSelection
+
+ | list sel colOfFiles|
+
+ list := self fileList.
+ colOfFiles := OrderedCollection new.
+ list isEmpty ifTrue:[ ^ colOfFiles].
+ sel := self treeSelectionHolder value.
+ sel isNil ifTrue:[ ^ colOfFiles].
+
+ sel do:[: index |
+ colOfFiles add:((list at:index) fileName)
+ ].
+ ^ colOfFiles.
+!
+
+getFirstDirectoryItemOfSelection
+
+ | sel dir |
+ sel := self getItemsForSelection.
+ sel isEmpty ifTrue:[ ^ nil].
+ ^ dir := sel detect:[: el | el isDirectory ] ifNone:[nil].
+!
+
+getFirstDirectoryOfSelection
+
+ | sel dirItem |
+ sel := self getItemsForSelection.
+ sel isEmpty ifTrue:[ ^ nil].
+ dirItem := sel detect:[: el | el isDirectory ] ifNone:[nil].
+ dirItem isNil ifTrue:[^ nil].
+ ^ dirItem fileName.
+!
+
+getItemsForSelection
+
+ | list sel colOfItems|
+
+ list := self fileList.
+ colOfItems := OrderedCollection new.
+ list isEmpty ifTrue:[ ^ colOfItems].
+ sel := self treeSelectionHolder value.
+ sel isNil ifTrue:[ ^ colOfItems].
+
+ sel do:[: index |
+ colOfItems add:(list at:index)
+ ].
+ ^ colOfItems.
+!
+
+masterIsFileBrowser
+
+ ^ self masterApplication class = FileBrowserV2
+!
+
+selectedFileIsDirectoryAndNotRoot
+
+ | dir|
+
+ dir := self getFirstDirectoryOfSelection.
+ dir isNil ifTrue:[^ false].
+ ^ [(dir asString) ~= (self rootHolder value)]
+! !
+
+!DirectoryTreeBrowser methodsFor:'startup & release'!
+
+makeDependent
+
+ self currentFileNameHolder addDependent:self.
+ self notifyChannel addDependent:self.
+ self viewFilesInDirectoryTree addDependent:self.
+ self treeSelectionHolder addDependent:self.
+ self filterModel addDependent:self.
+!
+
+postBuildAsSubcanvasWith:aBuilder
+
+ super postBuildAsSubcanvasWith:aBuilder.
+!
+
+postBuildDirBrowser:aWidget
+
+ dirBrowser := aWidget scrolledView.
+ dirBrowser openEditorAction:[:ln :aGC| |field item filename newFileString rename newFilename|
+ item := self fileList at:ln.
+
+ item label isString ifFalse:[
+ field := nil
+ ] ifTrue:[
+ field := EditField new.
+ field level:0.
+ field acceptOnReturn:true.
+ field acceptAction:[:x|
+ filename := item fileName.
+ newFileString := x at:1.
+ filename baseName = newFileString ifFalse:[
+ (self renameFile:filename to:newFileString update:false) ifTrue:[
+ newFilename := filename directory construct:newFileString.
+ item fileName:newFilename.
+ self updateAndSelect:(OrderedCollection with:newFilename).
+ ].
+ ].
+ aGC closeEditor.
+ ].
+ field font:(aGC font).
+ field contents:(item label).
+ ].
+ field
+ ].
+!
+
+postBuildWith:aBuilder
+
+ super postBuildWith:aBuilder.
+!
+
+postOpenAsSubcanvasWith:aBuilder
+
+ self currentFileNameHolder changed.
+ self windowGroup addPreEventHook:self.
+ ^ super postOpenAsSubcanvasWith:aBuilder.
+!
+
+postOpenWith:aBuilder
+
+ "
+ only invoked if the application not started from a master
+ "
+ self currentFileNameHolder changed.
+ self windowGroup addPreEventHook:self.
+ ^ super postOpenWith:aBuilder
+!
+
+preBuildWith:aBuilder
+
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ ].
+ ^ super preBuildWith:aBuilder.
+!
+
+release
+
+ self fileList stopMonitoringTask.
+ ^ super release.
+! !
+
+!DirectoryTreeBrowser methodsFor:'user actions'!
+
+doCopy
+ "copy current selected files/directories
+ "
+
+ self copyFilesToClipBoard:self getFilesForSelection.
+!
+
+doCut
+ "cut current selected files/directories
+ "
+ self cutFilesToClipBoard:self getFilesForSelection.
+!
+
+doDelete
+ "delete current selected files/directories
+ "
+
+ self deleteFiles:self getFilesForSelection.
+! !
+
+!DirectoryTreeBrowser::DirTreeBrowserHFL methodsFor:'accessing'!
+
+draggedItem:anItemOrNil
+" change the item icon ; return true if changed otherwise false"
+
+ |oldItem|
+
+ (anItemOrNil isNil or:[draggedItem ~~ anItemOrNil]) ifTrue:[
+ oldItem := draggedItem.
+ draggedItem := anItemOrNil.
+
+ oldItem ifNotNil:[ oldItem iconChanged ].
+ draggedItem ifNotNil:[ draggedItem iconChanged ].
+ ^ true
+ ].
+ ^ false
+! !
+
+!DirectoryTreeBrowser::DirTreeBrowserHFL methodsFor:'protocol'!
+
+validateIcon:icon for:anItem
+
+ draggedItem == anItem ifTrue:[
+ ^ (FileBrowser iconForKeyMatching:#directoryOpenGray) ? icon.
+ ].
+ ^ icon
+! !
+
+!DirectoryTreeBrowser class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/DirectoryTreeBrowser.st,v 1.1 2002-09-25 08:00:32 penk Exp $'
+! !
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FileApplicationNoteBook.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,4455 @@
+"{ Package: 'stx:libtool' }"
+
+AbstractFileBrowser subclass:#FileApplicationNoteBook
+ instanceVariableNames:'canvasHolder selectedEditorPage listOfApplications tabMenuIndex
+ tabList selectionHistoryList privateTabList'
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+AbstractFileApplicationNoteBookComponent subclass:#ArchiveViewApplication
+ instanceVariableNames:'archiveFileList enableStopButton fileTable currentSortOrder
+ selectionHolder tableColumns commandProcess errorListHolder
+ viewErrorList temporaryDirectory enableRemoveErrorOutput
+ errorListVisibilityHolder hasListEntriesHolder archiver process
+ terminateByMe columnDescriptors'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileApplicationNoteBook
+!
+
+Object subclass:#ArchivItem
+ instanceVariableNames:'fileName size dateAndTime permissions icon ownerGroup method crc
+ compressSize ratio version type isDirectory'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileApplicationNoteBook::ArchiveViewApplication
+!
+
+AbstractFileApplicationNoteBookComponent subclass:#CommandResult
+ instanceVariableNames:'resultStream enableStopButton process labelHolder'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileApplicationNoteBook
+!
+
+AbstractFileApplicationNoteBookComponent subclass:#HtmlViewApplication
+ instanceVariableNames:'htmlView labelHolder infoLabelHolder'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileApplicationNoteBook
+!
+
+AbstractFileApplicationNoteBookComponent subclass:#ImageViewApplication
+ instanceVariableNames:'imageFile imageView image fitSize fitMode'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileApplicationNoteBook
+!
+
+AbstractFileApplicationNoteBookComponent subclass:#Terminal
+ instanceVariableNames:'terminalView'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileApplicationNoteBook
+!
+
+AbstractFileApplicationNoteBookComponent subclass:#TextEditor
+ instanceVariableNames:'fileContentsModel doSaveFile modifiedChannel editView enableSave
+ enableReload presentation changeItemProcess closeApplication
+ semaChangeItem printAsHexDump itemChanged itemRemoved
+ enableHexToggle textEditorChangeModificationTime'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileApplicationNoteBook
+!
+
+AbstractFileApplicationNoteBookComponent subclass:#XViewApplication
+ instanceVariableNames:'xView xFile vncServerPID vncPortNr vncConnection viewerPID
+ vncLock vncServerIsTerminated xItem ext'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileApplicationNoteBook
+!
+
+
+!FileApplicationNoteBook class methodsFor:'application list'!
+
+applicationList
+" returns a list of all applications to start by the NoteBookApplication with
+ #className #type
+
+ example:
+ #( #'FooEditor' nil )
+"
+
+ ^ #(
+ #( #'TextEditor' #file )
+ #( #'TextEditor' #directoryDescription )
+ #( #'HtmlViewApplication' nil )
+ #( #'FindFileApplication' nil )
+ #( #'Terminal' nil )
+ #( #'ImageViewApplication' nil )
+ #( #'ArchiveViewApplication' nil )
+ #( #'CommandResult' nil )
+ #( #'XViewApplication' nil )
+ )
+!
+
+classFor:aApplicationListItem
+ |rawName cls|
+
+ rawName := aApplicationListItem at:1.
+ (cls := self privateClassesAt:rawName) isNil ifTrue:[
+ cls := Smalltalk at:rawName.
+ ].
+ ^ cls
+!
+
+defaultApplication
+" returns the application to be started if no itemQuery returns true or no supportedSuffix is supported
+"
+
+ ^ self applicationList detect:[: applItem|
+ (((self classFor:applItem) == self textEditorClass)
+ and:[(self typeFor:applItem) == #file])
+ ] ifNone:[nil].
+!
+
+typeFor:aApplicationListItem
+
+ ^ aApplicationListItem at:2
+! !
+
+!FileApplicationNoteBook class methodsFor:'classAccess'!
+
+textEditorClass
+
+ ^ TextEditor
+! !
+
+!FileApplicationNoteBook class methodsFor:'defaults'!
+
+openAnotherApplicationOnSameItem
+
+ ^ false
+! !
+
+!FileApplicationNoteBook class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:NoteBookApplication andSelector:#windowSpec
+ NoteBookApplication new openInterface:#windowSpec
+ NoteBookApplication open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'FileBrowserV2TextEditor'
+ #name: 'FileBrowserV2TextEditor'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 16 42 316 342)
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#NoteBookViewSpec
+ #name: 'CommandAndTextEditor'
+ #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+ #model: #selectedEditorPage
+ #menu: #tabList
+ #useIndex: true
+ #accessTabMenuAction: #tabMenuAt:
+ #canvas: #canvasHolder
+ #keepCanvasAlive: true
+ )
+ )
+
+ )
+ )
+! !
+
+!FileApplicationNoteBook class methodsFor:'menu specs'!
+
+tabMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileApplicationNoteBook andSelector:#tabMenu
+ (Menu new fromLiteralArrayEncoding:(FileApplicationNoteBook tabMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #value: #doCloseApplication
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileApplicationNoteBook methodsFor:'accessing'!
+
+listOfApplications
+ "return the value of the instance variable 'listOfApplications' (automatically generated)"
+
+ listOfApplications isNil ifTrue:[
+ listOfApplications := OrderedCollection new.
+ ].
+ ^ listOfApplications
+!
+
+selectionHistoryList
+
+ selectionHistoryList isNil ifTrue:[
+ selectionHistoryList := OrderedCollection new.
+ ].
+ ^ selectionHistoryList
+!
+
+selectionHistoryList:aCol
+
+ selectionHistoryList := aCol
+! !
+
+!FileApplicationNoteBook methodsFor:'accessing applications'!
+
+getAllApplicationsByClass:aClass andType:aType
+
+ ^ self listOfApplications select:[ : appl |
+ ((appl class = aClass)
+ and:[appl type = aType])
+ ].
+!
+
+getApplicationByType:aType
+
+ ^ self listOfApplications detect:[ : appl |
+ (appl type == aType)
+ ] ifNone:[nil].
+!
+
+getIndexFor:aApplication
+
+ | index |
+
+ index := self listOfApplications indexOf:aApplication.
+ index ~~ 0 ifTrue:[
+ ^ index.
+ ].
+ ^ nil.
+!
+
+getSameApplicationsFor:aApplication
+
+ ^ self listOfApplications select:[ : appl |
+ ( (appl ~= aApplication)
+ and:[ (appl isKindOf:(aApplication class))
+ and:[ (appl item = (aApplication item))
+ and:[ (appl type == aApplication type) ]]])
+ ].
+! !
+
+!FileApplicationNoteBook methodsFor:'actions-app-common'!
+
+changeItem:aItem for:aAppl
+
+ | applIndex string|
+
+ applIndex := self getIndexFor:aAppl.
+ (aItem notNil and:[aItem isDirectory not]) ifTrue:[
+ (aAppl changeItem:aItem) ifFalse:[ ^ self].
+ self fileHistory add:aItem.
+ self enableFileHistory value:true.
+ ].
+ string := aAppl getTabString.
+ self privateTabList at:applIndex put:string.
+ self doSelect:aAppl.
+!
+
+closeSubCanvas:aApplication
+
+ | applIndex historyList localHistoryList|
+
+ applIndex := self getIndexFor:aApplication.
+ applIndex notNil ifTrue:[
+"/ "/ UPDATE THE LAST SELECTION BECAUSE SEL INDEX IS DECREMENTED FOR HIGHER INDEXES
+"/ self lastSelection:applIndex.
+
+ historyList := self selectionHistoryList.
+ historyList remove:applIndex ifAbsent:nil.
+ localHistoryList := OrderedCollection new.
+ historyList notEmpty ifTrue:[
+ self selectedEditorPage value:(historyList last).
+ ] ifFalse:[
+ self selectedEditorPage value:1.
+ ].
+ historyList do:[ : index |
+ index <= applIndex ifTrue:[
+ localHistoryList add:index
+ ] ifFalse:[
+ localHistoryList add:(index - 1)
+ ]
+ ].
+ self selectionHistoryList:localHistoryList.
+ self listOfApplications removeIndex:applIndex.
+ self privateTabList removeIndex:applIndex.
+ self privateTabList isEmpty ifTrue:[
+ self viewNoteBookApplicationHolder value:false.
+ self enableViewNoteBookApplication value:false.
+ ] ifFalse:[
+ historyList notEmpty ifTrue:[
+ self selectedEditorPage value:(self selectionHistoryList last).
+ ]
+ ]
+ ].
+
+ "/ because subCanvas was configured to keep its view,
+ "/ we must destroy it here.
+ [aApplication window destroy] fork.
+!
+
+doCloseApplication
+
+ | appl |
+
+ appl := self listOfApplications at:tabMenuIndex.
+ appl doClose.
+!
+
+openApplByFileItem:aItem
+
+" use the default class list for open of applications by item "
+
+ | applList applItem itemClass|
+
+ aItem isNil ifTrue:[ ^ self ].
+ applList := self applicationList.
+ applItem := applList detect:[: aApplItem|
+ itemClass := self class classFor:aApplItem.
+ (itemClass canOpenItem:aItem).
+ ] ifNone:[nil].
+ applItem isNil ifTrue:[ ^ self openDefaultApplicationByItem:aItem].
+ applItem notNil ifTrue:[
+ | itemType |
+ itemType := self class typeFor:applItem.
+ itemClass := self class classFor:applItem.
+ (self openApplicationClass:itemClass withItem:aItem withType:itemType) isNil ifTrue:[
+ ^ self openDefaultApplicationByItem:aItem.
+ ].
+ ].
+!
+
+openApplicationClass:aClass withItem:aItem withType:aType
+
+ | existingAppl newAppl|
+
+ " do not open not readable items "
+ (aItem notNil and:[aItem isDirectory not and:[aItem fileName isReadable not]]) ifTrue:[
+ Dialog warn:'Can not open unreadable file ', aItem fileName baseName.
+ AbortSignal raise.
+ ].
+ existingAppl := self tryToGetExistingApplFor:aClass withItem:aItem withType:aType.
+ existingAppl notNil ifTrue:[
+ self doSelect:existingAppl.
+ ^ existingAppl
+ ].
+ newAppl := aClass new.
+ newAppl type:aType.
+ (newAppl item:aItem) ifFalse:[ ^ nil ].
+ (aItem notNil and:[aItem isDirectory not]) ifTrue:[
+ self fileHistory add:aItem.
+ self enableFileHistory value:true.
+ ].
+ self setSameFileIndexFor:newAppl.
+ self startApplication:newAppl.
+ ^ newAppl
+!
+
+openDefaultApplicationByItem:aItem
+" open the default application if no application for item is available or the start of the
+ available application failed
+"
+ | applItem |
+
+ applItem := self class defaultApplication.
+ applItem notNil ifTrue:[
+ | itemType itemClass|
+ itemType := self class typeFor:applItem.
+ itemClass := self class classFor:applItem.
+ ^ self openApplicationClass:itemClass withItem:aItem withType:itemType.
+ ].
+ ^ nil
+!
+
+setSameFileIndexFor:anAppl
+
+ |sameFiles index item|
+
+ self class openAnotherApplicationOnSameItem not ifTrue:[
+ anAppl sameFileIndex:nil.
+ ^ self.
+ ].
+ item := anAppl item.
+ item notNil ifTrue:[
+ | hasSameFiles |
+ sameFiles := self getSameApplicationsFor:anAppl.
+ hasSameFiles := sameFiles notEmpty.
+ hasSameFiles ifTrue:[
+ (sameFiles size == 1 and:[sameFiles first sameFileIndex isNil]) ifTrue:[
+ anAppl sameFileIndex:1.
+ ^ self
+ ] ifFalse:[
+ index := (sameFiles collect:[:el | (el sameFileIndex ? 1)]) max.
+ anAppl sameFileIndex:index + 1.
+ ^ self
+ ]
+ ].
+ anAppl sameFileIndex:nil.
+ ].
+!
+
+startApplication:aApplication
+
+ | window|
+
+ aApplication masterApplication:self.
+ aApplication window ifNil:[
+ window := ApplicationSubView new.
+ aApplication createBuilder.
+ window client:aApplication.
+ ].
+ self listOfApplications add:aApplication.
+ self privateTabList add:(aApplication getTabString).
+ self viewNoteBookApplicationHolder value:true.
+ self enableViewNoteBookApplication value:true.
+ self doSelect:aApplication.
+ [
+ aApplication postOpenWith:aApplication builder.
+ ] forkAt:Processor activePriority.
+!
+
+tabStringAdd:aString for:aAppl
+
+ | index text stream|
+
+ index := self getIndexFor:aAppl.
+ index isNil ifTrue:[ ^ self].
+ text := self privateTabList at:index.
+ stream := WriteStream on:''.
+ stream nextPutAll:text.
+ stream space.
+ stream nextPutAll:aString.
+ self privateTabList at:index put:stream contents.
+ stream close.
+!
+
+tabStringChangeTo:aString for:aAppl
+
+ | index|
+
+ index := self getIndexFor:aAppl.
+ index isNil ifTrue:[ ^ self].
+ self privateTabList at:index put:aString.
+!
+
+tryToGetExistingApplFor:aClass withItem:aItem withType:aType
+
+
+ |sameAppl changeAppl selAppl|
+
+ aClass wantNewApplicationAnyway ifTrue:[^ nil].
+ sameAppl := self getAllApplicationsByClass:aClass andType:aType.
+ sameAppl isEmpty ifTrue:[^ nil].
+ ((aType == #directoryDescription) or:[aType == #commandResult]) ifTrue:[
+ changeAppl := sameAppl first.
+ ] ifFalse:[
+ (self openMultipleApplicationsForType value) ifTrue:[
+ "/ open more than one application for a class and a type
+ (self class openAnotherApplicationOnSameItem) ifTrue:[
+ "/ open a new application anyway, no matters if item already open
+ ^ nil
+ ] ifFalse:[
+ "/ if item already changed select the application
+ selAppl := sameAppl detect:[ : appl |
+ (appl item = aItem)
+ ] ifNone:[nil].
+ ].
+ ] ifFalse:[
+ "/ keep in same application change the first application of the same class and type - if item not changed otherwise open new
+ changeAppl := sameAppl detect:[ : appl |
+ (appl isModified not)
+ ] ifNone:[nil].
+ ].
+ ].
+ changeAppl notNil ifTrue:[
+ self changeItem:aItem for:changeAppl.
+ selAppl := changeAppl.
+ ].
+ ^ selAppl.
+! !
+
+!FileApplicationNoteBook methodsFor:'actions-app-spec'!
+
+changeDirectoryDescription
+
+ | aInfoItem|
+
+ aInfoItem := self getInfoItem.
+ aInfoItem isNil ifTrue:[ ^ self closeDirectoryDescription ].
+ self openDirectoryDescription.
+!
+
+closeDirectoryDescription
+
+ | dirContApll |
+
+ dirContApll := self getApplicationByType:#directoryDescription.
+ dirContApll notNil ifTrue:[
+ dirContApll doClose.
+ ].
+!
+
+openArchiveViewApplication:aItem
+
+ | result |
+ result := self openApplicationClass:ArchiveViewApplication withItem:aItem withType:nil.
+ result isNil ifTrue:[
+ Dialog warn:'file type of ', aItem fileName baseName, ' not yet supported'.
+ ^ self.
+ ].
+!
+
+openCommandResultApplication
+
+
+ ^ self openApplicationClass:CommandResult withItem:nil withType:#commandResult
+!
+
+openDirectoryDescription
+
+ | appl aInfoItem|
+
+ aInfoItem := self getInfoItem.
+ aInfoItem notNil ifTrue:[
+ appl := self openTextEditorOn:aInfoItem type:#directoryDescription.
+ ].
+!
+
+openSearchFileOn:aItem
+
+ ^ self openApplicationClass:FindFileApplication withItem:aItem withType:nil
+!
+
+openTerminalApplication:aItem
+
+ ^ self openApplicationClass:Terminal withItem:aItem withType:nil
+!
+
+openTextEditorOn:aItem
+
+ ^ self openTextEditorOn:aItem type:#file
+!
+
+openTextEditorOn:aItem type:aDirDescrOrFile
+
+ ^ self openApplicationClass:TextEditor withItem:aItem withType:aDirDescrOrFile
+! !
+
+!FileApplicationNoteBook methodsFor:'applicationlist access'!
+
+applicationList
+ ^ self class applicationList
+! !
+
+!FileApplicationNoteBook methodsFor:'aspects'!
+
+canvasHolder
+
+ canvasHolder isNil ifTrue:[
+ canvasHolder := ValueHolder new.
+ ].
+ ^ canvasHolder.
+!
+
+privateTabList
+
+ privateTabList isNil ifTrue:[
+ privateTabList := List new.
+ privateTabList addDependent:self.
+ ].
+ ^ privateTabList.
+!
+
+selectedEditorPage
+
+ selectedEditorPage isNil ifTrue:[
+ selectedEditorPage := ValueHolder new.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+ selectedEditorPage addDependent:self.
+"/ selectedEditorPage onChangeSend:#selectedEditorPageChanged to:self.
+ ].
+ ^ selectedEditorPage.
+!
+
+tabList
+
+ tabList isNil ifTrue:[
+ tabList := (List new) asValue.
+ ].
+ ^ tabList.
+!
+
+tabList:aValue
+
+ tabList := aValue.
+! !
+
+!FileApplicationNoteBook methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+ "Invoked when an object that I depend upon sends a change notification."
+
+ "stub code automatically generated - please change as required"
+
+ | appl sel viewDirDescr|
+
+
+ changedObject == self currentDirectories ifTrue:[
+ self viewDirectoryDescription value ifTrue:[
+ self changeDirectoryDescription.
+ ].
+ ^ self.
+ ].
+ changedObject == self viewDirectoryDescription ifTrue:[
+ viewDirDescr := changedObject value.
+ viewDirDescr ifTrue:[
+ self openDirectoryDescription.
+ ] ifFalse:[
+ self closeDirectoryDescription.
+ ].
+ ^ self.
+ ].
+ changedObject == self privateTabList ifTrue:[
+ | privateListOfTabs |
+ privateListOfTabs := changedObject.
+ privateListOfTabs size > 1 ifTrue:[
+ self tabList value:privateListOfTabs.
+ self tabList changed.
+ ] ifFalse:[
+ self tabList value:nil.
+ ].
+ ^ self
+ ].
+ changedObject == self selectedEditorPage ifTrue:[
+ | listOfEdits indexOfLastSel list |
+
+ sel := changedObject value.
+ "/ dont want the tabs with one application - thats why i have to change my tablist
+ "/ sel goes to if - i want select the last selection
+ sel = 0 ifTrue:[
+ ^ self.
+ ].
+ list := self selectionHistoryList.
+ (list includes:sel) ifTrue:[
+ list remove:sel
+ ].
+ list add:sel.
+ self selectionHistoryList:list.
+ appl := self listOfApplications at:sel.
+ self doSelect:appl.
+ ].
+
+ ^ super update:something with:aParameter from:changedObject
+! !
+
+!FileApplicationNoteBook methodsFor:'menu & actions'!
+
+tabMenuAt:aTab
+
+ |menu|
+
+ menu := Menu new fromLiteralArrayEncoding:self class tabMenu.
+ menu ifNil:[ ^ nil ].
+ tabMenuIndex := aTab.
+ menu receiver:self.
+ ^ menu
+! !
+
+!FileApplicationNoteBook methodsFor:'queries'!
+
+getSameFilesModifiedFor:aAppl
+
+ | sameFileAppl colOfChanged |
+
+ sameFileAppl := self getSameApplicationsFor:aAppl.
+ sameFileAppl notEmpty ifTrue:[
+ colOfChanged := OrderedCollection new.
+ sameFileAppl do:[ : el |
+ el modifiedChannel value ifTrue:[
+ colOfChanged add:el.
+ ]
+ ]
+ ].
+ ^ colOfChanged
+! !
+
+!FileApplicationNoteBook methodsFor:'selection'!
+
+doSelect:anAppl
+
+ | index fileName|
+
+ fileName := anAppl fileName.
+ fileName notNil ifTrue:[
+ self changeFileBrowserTitleTo:fileName baseName.
+ ].
+ index := self getIndexFor:anAppl.
+
+ index notNil ifTrue:[
+ canvasHolder value:(anAppl window).
+ self selectedEditorPage value:index.
+ ]
+! !
+
+!FileApplicationNoteBook methodsFor:'startup & release'!
+
+makeDependent
+
+ self viewDirectoryDescription addDependent:self.
+ self currentDirectories addDependent:self.
+!
+
+postOpenAsSubcanvasWith:aBuilder
+
+ self viewDirectoryDescription changed.
+ ^ super postOpenAsSubcanvasWith:aBuilder.
+!
+
+postOpenWith:aBuilder
+
+ "
+ only invoked if the application not started from a master
+ "
+ self openTextEditorOn:(DirectoryContentsBrowser itemClass with:(Filename homeDirectory construct:'.bashrc')).
+ ^ super postOpenWith:aBuilder
+!
+
+preBuildWith:aBuilder
+
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ ].
+ ^ super preBuildWith:aBuilder.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication class methodsFor:'common options'!
+
+SupportedFiles
+
+ | dict |
+ dict := Dictionary new.
+
+ #(
+ 'application/x-tar-compressed' tarGZipArchive
+ 'application/x-tar' tarArchive
+ 'application/x-gzip-compressed' gzipArchive
+ 'application/x-zip-compressed' zipArchive
+ ) pairWiseDo:[ : mimeType :classSelector |
+ dict at:mimeType put:classSelector.
+ ].
+ ^ dict
+!
+
+classSelectorFor:aItem
+
+ | class |
+ aItem hasMimeType ifFalse:[^nil].
+ class := self SupportedFiles at:(aItem mimeType) ifAbsent:nil.
+ class isNil ifTrue:[
+ (aItem lastButOneSuffix = 'tar' and:[aItem lastSuffix = 'gz']) ifTrue:[
+ class := #tarGZipArchive.
+ ].
+ ].
+ ^ class.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication class methodsFor:'defaults'!
+
+tabStringFor:aApplicationType
+
+ ^ 'Archive for:'
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication class methodsFor:'image specs'!
+
+removeError
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self removeError inspect
+ ImageEditor openOnClass:self andSelector:#removeError
+ Icon flushCachedIcons
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'FileApplicationNoteBook::ArchiveViewApplication class removeError'
+ ifAbsentPut:[(Depth8Image new) width: 28; height: 22; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@FA @@@@@@@@XF@@@@@@@@@@@@@@@@@@@@@@@@@@XF@@@@@@XF@@@@@@@@@@@@@@@@@@@@@@@@@@@@A X@@@XF@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@FA XF@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XF@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XFA X@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@XF
+@@@FA @@@@@@@@@@@@@@@@@@@@@@@@@@@@XF@@@@@@XF@@@@@@@@@@@@@@@@@@@@@@@@@@XF@@@@@@@@A X@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 8 4 8 105 133 190 121 133 157 129 129 129 194 194 194 255 0 0]; mask:((Depth1Image new) width: 28; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@LC@@@A!! @@@L0@@@A8@@@@L@@@@G @@@CL@@@A!! @@@0L@@@@@@@BY=5LAIUUT S5UU8D!!UUPAFU\#@@@@@@@LR9@@D)J @A:R(@@P$*@@CIN @@@@@@@@@a') ; yourself); yourself]
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:NoteBookApplication::ArchiveViewApplication andSelector:#windowSpec
+ NoteBookApplication::ArchiveViewApplication new openInterface:#windowSpec
+ NoteBookApplication::ArchiveViewApplication open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'Archive Application'
+ #name: 'Archive Application'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 12 22 688 514)
+ #menu: #mainMenu
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'MenuTerminal'
+ #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+ #menu: #menu
+ #textDefault: true
+ )
+ #(#'FileBrowserV2UISpecifications::PanelSpec'
+ #name: 'VerticalPanel'
+ #layout: #(#LayoutFrame 0 0.0 32 0.0 0 1.0 0 1.0)
+ #borderWidth: 1
+ #whichView: #last
+ #orientation: #vertical
+ #visibility: #errorListVisibilityHolder
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#DataSetSpec
+ #name: 'Table1'
+ #model: #selectionHolder
+ #menu: #fileListMenu
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #dataList: #archiveFileList
+ #useIndex: false
+ #has3Dsepartors: false
+ #doubleClickSelector: #dblClick
+ #columnHolder: #tableColumns
+ #multipleSelectOk: true
+ #verticalSpacing: 0
+ #postBuildCallback: #postBuildFileTable:
+ #properties:
+ #(#PropertyListDictionary
+ #dragArgument: #archivApplication
+ #startDragSelector: #doStartDrag:in:
+ #displayObjectSelector: #getDisplayObjects:
+ #dropObjectSelector: #getDropObjects:
+ #dropArgument: #archivApplication
+ #canDropSelector: #canDrop:argument:
+ #dropSelector: #doDrop:argument:
+ )
+ )
+ #(#SequenceViewSpec
+ #name: 'ErrorList'
+ #initiallyDisabled: true
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #backgroundColor: #(#Color 100.0 100.0 100.0)
+ #isMultiSelect: true
+ #useIndex: false
+ #sequenceList: #errorListHolder
+ )
+ )
+
+ )
+ #handles: #(#Any 0.5 1.0)
+ )
+ )
+
+ )
+ )
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication class methodsFor:'menu specs'!
+
+fileListMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:NoteBookApplication::ArchiveViewApplication andSelector:#fileListMenu
+ (Menu new fromLiteralArrayEncoding:(NoteBookApplication::ArchiveViewApplication fileListMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Extract to Directory'
+ #translateLabel: true
+ #value: #extractAll
+ #enabled: #hasSelectionInList
+ )
+ #(#MenuItem
+ #label: 'Delete from Archiv'
+ #translateLabel: true
+ #value: #removeFilesFromArchiv
+ #enabled: #canDelete
+ #shortcutKeyCharacter: #Delete
+ )
+ #(#MenuItem
+ #label: 'View'
+ #translateLabel: true
+ #isVisible: #isEmbeddedApplication
+ #value: #viewFile
+ #enabled: #hasOneSelectionInList
+ )
+ #(#MenuItem
+ #label: 'Copy Filenames'
+ #translateLabel: true
+ #value: #copyFilesToClipboard
+ #enabled: #hasSelectionInList
+ )
+ #(#MenuItem
+ #label: 'Select All'
+ #translateLabel: true
+ #value: #selectAll
+ #enabled: #hasListEntriesHolder
+ )
+ )
+ nil
+ nil
+ )
+!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileApplicationNoteBook::ArchiveViewApplication andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(FileApplicationNoteBook::ArchiveViewApplication menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Stop'
+ #translateLabel: true
+ #isButton: true
+ #nameKey: #Stop
+ #value: #doStopProcess
+ #enabled: #enableStopButton
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #stop22x22Icon)
+ )
+ #(#MenuItem
+ #label: 'Exctract'
+ #translateLabel: true
+ #isButton: true
+ #value: #extractAll
+ #enabled: #hasListEntriesHolder
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #extract28x28Icon)
+ )
+ #(#MenuItem
+ #label: 'Remove Output'
+ #translateLabel: true
+ #isButton: true
+ #value: #removeErrorOutput
+ #enabled: #enableRemoveErrorOutput
+ #labelImage: #(#ResourceRetriever nil #removeError)
+ )
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #isButton: true
+ #hideMenuOnActivated: false
+ #isVisible: #isEmbeddedApplication
+ #startGroup: #right
+ #value: #doClose
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #closeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication class methodsFor:'queries'!
+
+canOpenItem:aItem
+
+ ^ (aItem hasMimeType and:[(aItem mimeType isArchiv) and:[OperatingSystem isUNIXlike]])
+!
+
+wantNewApplicationAnyway
+
+ ^ false
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication class methodsFor:'tableColumns specs'!
+
+tableColumns
+ "This resource specification was automatically generated
+ by the DataSetBuilder of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the DataSetBuilder may not be able to read the specification."
+
+ "
+ DataSetBuilder new openOnClass:NoteBookApplication::ArchiveViewApplication andSelector:#tableColumns
+ "
+
+ <resource: #tableColumns>
+
+ ^#(
+ #(#DataSetColumnSpec
+ #id: 'icon'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'directory'
+ #width: 25
+ #minWidth: 20
+ #height: 16
+ #model: #icon
+ #canSelect: false
+ #isResizeable: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'File Name'
+ #id: 'fileName'
+ #labelAlignment: #left
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'fileName'
+ #model: #fileName
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Perm'
+ #id: 'permissions'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'permissions'
+ #usePreferredWidth: true
+ #width: 75
+ #model: #permissions
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Version'
+ #id: 'version'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'version'
+ #columnAlignment: #right
+ #width: 100
+ #minWidth: 50
+ #model: #version
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Type'
+ #id: 'type'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'type'
+ #columnAlignment: #right
+ #width: 100
+ #minWidth: 50
+ #model: #type
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Owner/Group'
+ #id: 'ownerGroup'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'ownerGroup'
+ #columnAlignment: #right
+ #width: 100
+ #minWidth: 50
+ #model: #ownerGroup
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Size'
+ #id: 'size'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'sizeAsNumber'
+ #columnAlignment: #right
+ #width: 80
+ #model: #size
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Date & Time'
+ #id: 'dateAndTime'
+ #labelAlignment: #right
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'dateAndTime'
+ #columnAlignment: #right
+ #usePreferredWidth: true
+ #width: 140
+ #model: #dateAndTime
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Method'
+ #id: 'method'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'method'
+ #columnAlignment: #center
+ #usePreferredWidth: true
+ #width: 140
+ #model: #method
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'CRC'
+ #id: 'crc'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'crc'
+ #usePreferredWidth: true
+ #width: 140
+ #model: #crc
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Compress Size'
+ #id: 'compressSize'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'compressSize'
+ #usePreferredWidth: true
+ #width: 140
+ #model: #compressSize
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ #(#DataSetColumnSpec
+ #label: 'Ratio'
+ #id: 'ratio'
+ #labelButtonType: #Button
+ #labelActionSelector: #sortList:
+ #labelActionArgument: 'ratio'
+ #usePreferredWidth: true
+ #width: 140
+ #model: #ratio
+ #canSelect: false
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ )
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'accessing'!
+
+archiver
+ "return the value of the instance variable 'archiver' (automatically generated)"
+
+ ^ archiver
+!
+
+archiver:something
+ "set the value of the instance variable 'archiver' (automatically generated)"
+
+ archiver := something.
+!
+
+columnDescriptors
+ "return the value of the instance variable 'columnDescriptors' (automatically generated)"
+
+ ^ columnDescriptors
+!
+
+columnDescriptors:aListOfColumns
+ "set the value of the instance variable 'columnDescriptors' (automatically generated)"
+
+ columnDescriptors = aListOfColumns ifTrue:[
+ ^ self
+ ].
+
+ columnDescriptors := OrderedCollection new.
+
+ aListOfColumns keysAndValuesDo:[:anIndex :aDesc| |col|
+ col := aDesc isSequenceable ifTrue:[DataSetColumnSpec new fromLiteralArrayEncoding:aDesc]
+ ifFalse:[aDesc].
+ columnDescriptors add:col.
+ ].
+!
+
+item:aItem
+ "set the value of the instance variable 'item' (automatically generated)"
+
+ | classSelector|
+
+ super item:aItem.
+ classSelector := self class classSelectorFor:aItem.
+ (classSelector notNil and:[(Archiver respondsTo:classSelector) notNil]) ifTrue:[
+ self makeProcessFor:[
+ self archiver:((Archiver perform:classSelector) with:(self fileName)).
+ self setColumnsForArchiver.
+ ] with:'setup archiv'.
+ ^ true
+ ].
+ ^ false
+!
+
+temporaryDirectory
+ "return the value of the instance variable 'temporaryDirectory' (automatically generated)"
+
+ temporaryDirectory isNil ifTrue:[
+ temporaryDirectory := Filename newTemporary.
+ temporaryDirectory makeDirectory.
+ ].
+ ^ temporaryDirectory
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'actions'!
+
+changeItem:aItem
+
+ self item:aItem.
+ self emptyList.
+ self listAllFilesFromArchiv.
+ ^ true
+!
+
+copyFilesToClipboard
+
+
+ |sel list stream|
+
+ sel := self selectionHolder value.
+ list := self archiveFileList.
+ (sel notNil and:[sel notEmpty]) ifTrue:[
+ stream := WriteStream on:''.
+ sel do:[: key |
+ stream nextPutAll:(key fileName asString).
+ stream cr.
+ ].
+ self window setTextSelection:stream contents.
+ stream close.
+ ].
+!
+
+dblClick
+
+ self viewFile.
+!
+
+doStopProcess
+
+ | archiver |
+ self stopProcess.
+ archiver := self archiver.
+ archiver notNil ifTrue:[
+ self archiver stopProcess.
+ ].
+ self enableStopButton value:false.
+!
+
+emptyList
+
+ self archiveFileList value removeAll.
+!
+
+removeErrorOutput
+
+ self viewErrorList value:false.
+ self errorListHolder removeAll.
+!
+
+removeTemporaryDirectory
+
+ | tmp |
+
+ temporaryDirectory notNil ifTrue:[
+ tmp := self temporaryDirectory.
+ (FileDirectory directoryNamed:(tmp directory)) removeDirectory:tmp baseName.
+ temporaryDirectory := nil.
+ ].
+!
+
+selectAll
+
+ | sel listOfFiles|
+
+ sel := OrderedCollection new.
+ listOfFiles := self archiveFileList value.
+ 1 to:(listOfFiles size) do:[ : el |
+ sel add:el
+ ].
+ self selectionHolder value:sel.
+!
+
+updateFileBrowserIfPresentWith:aDirectory
+
+ | master|
+
+ master := self masterApplication.
+ master notNil ifTrue:[
+ master updateAndSelect:(OrderedCollection with:aDirectory).
+ ].
+!
+
+viewFile
+
+ | master item file tempDir|
+
+ master := self masterApplication.
+ self selectionHolder value size = 1 ifFalse:[
+ Dialog warn:'only one file have to be selected'.
+ ^ self.
+ ].
+ tempDir := self temporaryDirectory.
+ self extractSelectedFilesTo:tempDir askForExtractOptions:false.
+ process notNil ifTrue:[
+ process waitUntilTerminated.
+ ].
+ file := tempDir construct:self selectionHolder value first fileName.
+ file exists ifTrue:[
+ item := DirectoryContentsBrowser itemClass with:file.
+ ].
+ master notNil ifTrue:[
+ master openApplByFileItem:item.
+ ].
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'aspects'!
+
+archiveFileList
+
+ archiveFileList isNil ifTrue:[
+ archiveFileList := List new.
+ archiveFileList addDependent:self.
+ ].
+ ^ archiveFileList.
+!
+
+enableRemoveErrorOutput
+ "return/create the 'enableRemoveErrorOutput' value holder (automatically generated)"
+
+ enableRemoveErrorOutput isNil ifTrue:[
+ enableRemoveErrorOutput := false asValue.
+ ].
+ ^ enableRemoveErrorOutput
+!
+
+enableStopButton
+
+ enableStopButton isNil ifTrue:[
+ enableStopButton := false asValue.
+ ].
+ ^ enableStopButton
+!
+
+errorListHolder
+
+ errorListHolder isNil ifTrue:[
+ errorListHolder := List new.
+ ].
+ ^ errorListHolder.
+!
+
+errorListVisibilityHolder
+
+ errorListVisibilityHolder isNil ifTrue:[
+ errorListVisibilityHolder := false asValue.
+ ].
+ ^ errorListVisibilityHolder
+!
+
+hasListEntriesHolder
+ "return/create the 'hasListEntriesHolder' value holder (automatically generated)"
+
+ hasListEntriesHolder isNil ifTrue:[
+ hasListEntriesHolder := false asValue.
+ ].
+ ^ hasListEntriesHolder
+!
+
+hasOneSelectionInList
+
+ | sel |
+ sel := self selectionHolder value.
+ ^ (sel notNil and:[sel notEmpty and:[sel size = 1]])
+!
+
+hasSelectionInList
+
+ | sel |
+ sel := self selectionHolder value.
+ ^ (sel notNil and:[sel notEmpty])
+!
+
+selectionHolder
+
+ selectionHolder isNil ifTrue:[
+ selectionHolder := ValueHolder new.
+ selectionHolder addDependent:self.
+ ].
+ ^ selectionHolder.
+!
+
+tableColumns
+
+ tableColumns isNil ifTrue:[
+ tableColumns := self class tableColumns asValue.
+ ].
+ ^ tableColumns.
+!
+
+viewErrorList
+ "return/create the 'viewErrorList' value holder (automatically generated)"
+
+ viewErrorList isNil ifTrue:[
+ viewErrorList := false asValue.
+ viewErrorList onChangeSend:#viewErrorListChanged to:self.
+ ].
+ ^ viewErrorList
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+ "Invoked when an object that I depend upon sends a change notification."
+
+ "stub code automatically generated - please change as required"
+
+ changedObject == self archiveFileList ifTrue:[
+ self hasListEntriesHolder value:(changedObject notEmpty).
+ ^ self
+ ].
+ super update:something with:aParameter from:changedObject
+!
+
+viewErrorListChanged
+
+ | viewListValue|
+
+ viewListValue := self viewErrorList value.
+ self enableRemoveErrorOutput value:viewListValue.
+ self errorListVisibilityHolder value:viewListValue.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'command execution'!
+
+getErrorBlock
+
+ ^
+ [: x |
+ self viewErrorList value:true.
+ self errorListHolder value add:x.
+ ]
+!
+
+getErrorStream
+
+ |errStream|
+
+ errStream := ActorStream new.
+ errStream nextPutLineBlock:(self getErrorBlock).
+ ^ errStream
+!
+
+getOutBlock
+
+ |firstLineNotReaded key|
+
+ firstLineNotReaded := true.
+ ^ [: line |
+ | words ownerGroup item archiverColumns itemWriter index itemWordCount|
+
+ (firstLineNotReaded and:[archiver class hasTitleLine]) ifTrue:[
+ firstLineNotReaded := false.
+ ]ifFalse:[
+ words := line asCollectionOfWords.
+ archiverColumns := archiver class columns.
+ item := ArchivItem new.
+ index := 1.
+ archiverColumns do:[:colDescr |
+ | itemStream |
+ itemWordCount := colDescr second.
+ itemWriter := ((colDescr first) asString, ':') asSymbol.
+ itemStream := WriteStream on:''.
+ index to:(index + itemWordCount - 1) do:[:i|
+ itemStream nextPutAll:(words at:i).
+ itemStream space.
+ ].
+ item perform:itemWriter with:(itemStream contents).
+ itemStream close.
+ index := index + itemWordCount.
+ ].
+ ((archiverColumns collect:[:el| el first]) includes:#permissions) ifTrue:[
+ (item permissions startsWith:$d) ifTrue:[
+ key := #directory.
+ item isDirectory:true.
+ ] ifFalse:[
+ key := MIMETypes mimeTypeForFilename:(item fileName asFilename baseName).
+ item isDirectory:false.
+ ].
+ ] ifFalse:[
+ key := MIMETypes mimeTypeForFilename:(item fileName asFilename baseName).
+ ].
+ item icon:(FileBrowser iconForKeyMatching:key).
+ self archiveFileList value add:item
+ ].
+ ]
+!
+
+getOutStream
+
+ |outStream|
+
+ outStream := ActorStream new.
+ outStream nextPutLineBlock:(self getOutBlock).
+ ^ outStream
+!
+
+makeProcessFor:aBlock
+
+ self makeProcessFor:aBlock with:''
+!
+
+makeProcessFor:aBlock with:string
+
+ | locBlock |
+
+ process notNil ifTrue:[
+ process waitUntilTerminated.
+ terminateByMe ifTrue:[
+ terminateByMe := false.
+ ^ self
+ ].
+ ].
+ locBlock := [ [
+ self notifyChannel value:string.
+ aBlock value.
+ self notifyChannel value:''.
+ ] valueNowOrOnUnwindDo:[
+ process := nil.
+ self enableStopButton value:false.
+ ]
+ ].
+ process := locBlock newProcess.
+ process priority:(Processor systemBackgroundPriority).
+ process name:'ArchiveApplicationProcess'.
+ self enableStopButton value:true.
+ process resume.
+!
+
+setColumnsForArchiver
+
+ | newColumns archiverColumns allColumns iconColumn|
+
+ archiverColumns := archiver class columns collect:[:el| el first].
+ allColumns := OrderedCollection new.
+ newColumns := OrderedCollection new.
+ self class tableColumns do:[:el|
+ allColumns add:(DataSetColumnSpec new fromLiteralArrayEncoding:el).
+ ].
+ iconColumn := allColumns detect:[: col | (col id asSymbol) = #icon] ifNone:[nil].
+ iconColumn notNil ifTrue:[
+ newColumns add:iconColumn.
+ ].
+ allColumns do:[:col|
+ (archiverColumns includes:(col id asSymbol)) ifTrue:[
+ newColumns add:col.
+ ].
+ ].
+ self tableColumns value:newColumns.
+ self columnDescriptors:(self tableColumns value).
+!
+
+stopProcess
+
+ |task|
+
+ terminateByMe := true.
+ (task := process) notNil ifTrue:[
+ process := nil.
+
+ Object errorSignal handle:[:ex|
+ Dialog warn:ex description.
+ ]do:[
+ task isDead ifFalse:[
+ task terminateWithAllSubprocesses.
+ task waitUntilTerminated.
+ ]
+ ]
+ ].
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'command helper'!
+
+selectDirectoryDialog
+
+ | dir directory haveDirectory|
+
+ directory := self fileName directory.
+ haveDirectory := false.
+ [haveDirectory] whileFalse:[
+ dir := Dialog requestDirectoryName:'Which directory ?' default:dir.
+ dir isEmpty ifTrue:[ ^ self].
+ dir := dir asFilename.
+ (dir isExecutable not or:[dir isWritable not]) ifTrue:[
+ Dialog warn:'cant write to: ', dir asString.
+ ].
+ haveDirectory := true.
+ ].
+ ^ dir
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'commands add'!
+
+addFilesToArchiv:colOfFiles
+
+
+ self archiver outStream:nil errorStream:(self getErrorStream) synchron:true.
+ self makeProcessFor:[
+ self archiver addFilesToArchiv:colOfFiles.
+ ] with:'add Files to archiv'.
+ (self archiver class == Archiver zipArchive) ifTrue:[
+ self listAllFilesFromArchiv.
+ ] ifFalse:[
+ self listFilesFromArchiv:colOfFiles.
+ ].
+ ^ true.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'commands extract'!
+
+extractAll
+
+ self extractSelectedFilesTo:nil withSelection:#all
+!
+
+extractSelectedFilesTo:aDirectory askForExtractOptions:askForExtractOptionsBoolean
+
+ self extractSelectedFilesTo:aDirectory withSelection:#selection askForExtractOptions:askForExtractOptionsBoolean
+!
+
+extractSelectedFilesTo:aDirectory withSelection:selectOrAll
+
+ self extractSelectedFilesTo:aDirectory withSelection:selectOrAll askForExtractOptions:true.
+!
+
+extractSelectedFilesTo:aDirectory withSelection:selectOrAll askForExtractOptions:askForExtractOptionsBoolean
+
+ | dir|
+
+ aDirectory isNil ifTrue:[
+ dir := self selectDirectoryDialog.
+ dir isNil ifTrue:[^ self].
+ ] ifFalse:[
+ dir := aDirectory.
+ ].
+ selectOrAll == #all ifTrue:[
+ self extractAllTo:dir.
+ ].
+ selectOrAll == #selection ifTrue:[
+ self extractSelectionTo:dir askForExtractOptions:askForExtractOptionsBoolean
+ ].
+ self updateFileBrowserIfPresentWith:dir.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'commands extract private'!
+
+extractAllTo:aDirectory
+
+ self archiver outStream:nil errorStream:(self getErrorStream) synchron:true.
+ self makeProcessFor:[
+ self archiver extractTo:aDirectory.
+ ] with:'extract all files'.
+ ^ true.
+!
+
+extractSelectionTo:aDirectory askForExtractOptions:askForExtractOptionsBoolean
+
+ | sel index extractWithDirectoryPart extractAllFilesInSelectedDirectories extractFiles|
+
+ extractWithDirectoryPart := true.
+ extractAllFilesInSelectedDirectories := false.
+ sel := self selectionHolder value.
+ (sel isNil or:[sel isEmpty]) ifTrue:[
+ sel := self archiveFileList value.
+ ].
+ sel := sel do:[:item|
+ item fileName: item fileName
+ ].
+ (askForExtractOptionsBoolean and:[self archiver class ~= Archiver zipArchive]) ifTrue:[
+ extractFiles := self selRemoveFilesForDirs:sel.
+ ] ifFalse:[
+ extractFiles := sel.
+ ].
+
+ askForExtractOptionsBoolean ifTrue:[
+ index := extractFiles findFirst:[: el | el hasDirectoryPart].
+ index ~= 0 ifTrue:[
+ extractWithDirectoryPart := (Dialog confirmWithCancel:'Extract with directory part?' default:true).
+ extractWithDirectoryPart isNil ifTrue:[^ false].
+ ].
+ ].
+ extractWithDirectoryPart ifTrue:[
+ self extractWithDirectoryPartTo:aDirectory with:extractFiles.
+ ] ifFalse:[
+ self extractWithOutDirectoryPartTo:aDirectory with:extractFiles.
+ ].
+ ^ true
+!
+
+extractWithDirectoryPartTo:aDirectory with:extractFiles
+
+ self archiver outStream:nil errorStream:(self getErrorStream) synchron:true.
+ self makeProcessFor:[
+ self archiver extractTo:aDirectory with:extractFiles.
+ ] with:('extract Files to ', aDirectory asString).
+ ^ true.
+!
+
+extractWithOutDirectoryPartTo:aDirectory with:extractFiles
+
+ self archiver outStream:nil errorStream:(self getErrorStream) synchron:true.
+ self makeProcessFor:[
+ self archiver extractWithOutDirectoryTo:aDirectory
+ with:(extractFiles collect:[:item| item fileName]).
+ ] with:('extract Files to ', aDirectory asString).
+ ^ true.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'commands list'!
+
+listAllFilesFromArchiv
+
+ self archiveFileList value removeAll.
+ self listFilesFromArchiv:nil
+!
+
+listFilesFromArchiv:newColOfFiles
+
+ process notNil ifTrue:[
+ process waitUntilTerminated.
+ ].
+ self archiver outStream:(self getOutStream) errorStream:(self getErrorStream) synchron:true.
+ self makeProcessFor:[
+ self archiver listFilesFromArchiv:newColOfFiles.
+ ] with:'list Files'.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'commands remove'!
+
+removeFilesFromArchiv
+
+ | sel realSel list firtsPre stringCol stringRealSel|
+
+ sel := self selectionHolder value.
+ stringCol := sel collect:[: item| item fileName].
+ firtsPre := stringCol at:1.
+ stringCol from:2 do:[:el|
+ firtsPre := firtsPre commonPrefixWith:el.
+ ].
+ list := self archiveFileList value.
+ realSel := OrderedCollection new.
+ list do:[:item|
+ ((item fileName) startsWith:firtsPre) ifTrue:[
+ realSel add:item.
+ ].
+ ].
+ stringRealSel := realSel collect:[: item| item fileName].
+
+ self archiver outStream:nil errorStream:(self getErrorStream) synchron:true.
+ self makeProcessFor:[
+ self archiver removeFilesFromArchiv:stringCol.
+ ] with:'remove files'.
+
+ self archiveFileList value removeAll:realSel
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'drag & drop'!
+
+canDrop:aContext argument:arg2
+
+
+ |arg |
+ archiver class canAddFiles ifFalse:[^ false].
+ arg := aContext dropSource argument.
+ (arg == #browser or:[arg == #directoryTreeBrowser]) ifTrue:[
+ ^ true
+ ].
+ ^ false.
+!
+
+doDrop:aContext
+
+ |col source arg objects|
+
+ source := aContext dropSource.
+ arg := source argument.
+ objects := aContext dropObjects.
+ col := OrderedCollection new.
+ objects do:[:obj|
+ col add:(obj theObject).
+ ].
+ ^ self addFilesToArchiv:col.
+!
+
+doDrop:aContext argument:arg2
+
+ | aBoolean |
+
+ aBoolean := self doDrop:aContext.
+ ^ aBoolean.
+!
+
+doStartDrag:aDropSource in:aView
+ "set the cursors before starting the drag & drop operation
+ "
+ |hdl sel|
+
+ archiver class canRemoveFiles ifFalse:[^ self].
+ sel := self selectionHolder value.
+
+ hdl := DragAndDropManager new.
+
+ hdl disabledCursor:self class DisabledCursorImage.
+ hdl enabledCursor:self class EnabledCursorImage.
+ hdl alienCursor:nil.
+
+ hdl startDragFrom:aView dropSource:aDropSource offset:#topLeft
+!
+
+getDisplayObjects:anArgument
+
+ | sel string size fnName stream|
+ sel := self selectionHolder value.
+ size := sel size.
+ size == 0 ifTrue:[^ ''].
+ stream := WriteStream on:''.
+ stream nextPutAll:(sel first fileName asFilename baseName asString).
+ size == 1 ifTrue:[
+ fnName := 'ui_menuitem.xpm'.
+ ] ifFalse:[
+ fnName := 'ui_submenu_open.xpm'.
+ stream nextPutAll:' ... '.
+ stream nextPutAll:(sel last fileName asFilename baseName asString).
+ ].
+ string := stream contents.
+ stream close.
+ ^ Array with:(LabelAndIcon icon:(Image fromFile:fnName)
+ string:(Text string:string emphasis:#bold)
+ )
+!
+
+getDropObjects:anArgument
+
+ | sel ret|
+ sel := self selectionHolder value.
+ ret := sel collect:[:el|
+ DropObject new:(el fileName)
+ ].
+ ^ ret
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'event handling'!
+
+processEvent:anEvent
+ "filter keyboard events.
+ Return true, if I have eaten the event"
+
+ |focusView key rawKey|
+
+ anEvent isKeyPressEvent ifTrue:[
+ focusView := anEvent targetView.
+ key := anEvent key.
+ rawKey := anEvent rawKey.
+
+ (focusView isSameOrComponentOf:self window) ifTrue:[
+"/ (key ~= #'Alt_L') ifTrue:[self halt.].
+ (key == #Delete) ifTrue:[
+ self removeFilesFromArchiv.
+ ^ true
+ ].
+ ]
+ ].
+ ^ false
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'initialization & release'!
+
+postBuildFileTable:aWidget
+
+ fileTable := aWidget scrolledView.
+ fileTable wantsFocusWithPointerEnter.
+"/ FileBrowser icons keysAndValuesDo:[:aKey :anIcon|
+"/ fileTable registerImage:anIcon key:aKey.
+"/ ].
+ self columnDescriptors:(self class tableColumns).
+!
+
+postOpenWith:aBuilder
+
+ | currentDir contents suffix fileName file archivItem|
+
+ self windowGroup addPreEventHook:self.
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ currentDir := Filename homeDirectory.
+ contents := currentDir directoryContents.
+ fileName := contents detect:[: file |
+ suffix := file asFilename suffix asLowercase.
+ suffix = 'tgz'
+ ] ifNone:[nil].
+ fileName isNil ifTrue:[
+ Dialog warn:'cant find a Zip file in ', currentDir asString.
+ ^ self
+ ].
+ file := currentDir construct:fileName.
+ archivItem := DirectoryContentsBrowser itemClass with:file.
+ (self item:archivItem) ifFalse:[
+ Dialog warn:'file type of ', item fileName asString, ' not supported'.
+ ^ self.
+ ].
+ ].
+ self listAllFilesFromArchiv.
+ ^ super postOpenWith:aBuilder.
+!
+
+release
+
+ self archiver release.
+ ^ super release.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'queries'!
+
+archivType
+
+ | file firstsuffix secondsuffix|
+
+ file := self fileName.
+ firstsuffix := file withoutSuffix suffix.
+ secondsuffix := file suffix.
+ (secondsuffix = 'tgz' or:[firstsuffix = 'tar' and:[secondsuffix = 'gz']]) ifTrue:[
+ ^ #tarFileCompressed
+ ].
+ (secondsuffix = 'tar') ifTrue:[
+ ^ #tarFile
+ ].
+ (secondsuffix = 'gz') ifTrue:[
+ ^ #gzipFile
+ ].
+ (secondsuffix = 'zip') ifTrue:[
+ ^ #zipFile
+ ].
+!
+
+canDelete
+
+ ^ (self hasOneSelectionInList and:[archiver class canRemoveFiles])
+!
+
+selRemoveFilesForDirs:aSel
+
+ |stringCol newSel string|
+
+ stringCol := (aSel collect:[: item| item fileName]).
+ newSel := aSel copy.
+ aSel do:[:item |
+ item isDirectory ifTrue:[
+ string := item fileName.
+ stringCol doWithIndex:[:filename : index|
+ (filename ~= string and:[filename startsWith:string]) ifTrue:[
+ newSel remove:(aSel at:index) ifAbsent:[nil].
+ ]
+ ]
+ ].
+ ].
+ ^ newSel.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication methodsFor:'sorting'!
+
+generateSortBlock:instanceName
+
+ | aSymbol cmpOp sortCaselessLocal|
+
+ aSymbol := instanceName asSymbol.
+ sortCaselessLocal := self sortCaseless value.
+ currentSortOrder isNil ifTrue:[
+ currentSortOrder := aSymbol.
+ currentSortOrder := Dictionary new.
+ currentSortOrder at:#column put:aSymbol.
+ currentSortOrder at:#reverse put:false.
+ currentSortOrder at:#sortCaseless put:sortCaselessLocal.
+ ] ifFalse:[
+ (currentSortOrder at:#column) = aSymbol ifTrue:[
+ "/ same column like before - change sort order
+ | isReverse |
+ isReverse := currentSortOrder at:#reverse.
+ currentSortOrder at:#reverse put:(isReverse not).
+ ] ifFalse:[
+ "/ another column - remark column
+ currentSortOrder at:#column put:aSymbol.
+ ]
+ ].
+ (currentSortOrder at:#reverse) ifTrue:[
+ cmpOp := #'>'
+ ] ifFalse:[
+ cmpOp := #'<'
+ ].
+ ^ [:a :b |
+ |entry1 entry2|
+
+ entry1 := (a perform:aSymbol).
+ entry2 := (b perform:aSymbol).
+ aSymbol = #fileName ifTrue:[
+ sortCaselessLocal ifTrue:[
+ entry1 := entry1 asString asLowercase.
+ entry2 := entry2 asString asLowercase.
+ ] ifFalse:[
+ entry1 := entry1 asString.
+ entry2 := entry2 asString.
+ ].
+ ].
+ entry1 perform:cmpOp with:entry2
+ ].
+!
+
+sortList:instanceName
+
+
+ |sortBlock fileList sortCol|
+
+ sortBlock := self generateSortBlock:instanceName.
+ fileList := self archiveFileList value.
+ sortCol := SortedCollection sortBlock:sortBlock.
+ sortCol addAll:fileList.
+ fileList removeAll.
+ fileList addAll:sortCol.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication::ArchivItem methodsFor:'accessing'!
+
+compressSize
+ "return the value of the instance variable 'compressSize' (automatically generated)"
+
+ ^ compressSize
+!
+
+compressSize:something
+ "set the value of the instance variable 'compressSize' (automatically generated)"
+
+ compressSize := something.
+!
+
+crc
+ "return the value of the instance variable 'crc' (automatically generated)"
+
+ ^ crc
+!
+
+crc:something
+ "set the value of the instance variable 'crc' (automatically generated)"
+
+ crc := something.
+!
+
+dateAndTime
+ "return the value of the instance variable 'dateAndTime' (automatically generated)"
+
+ ^ dateAndTime
+!
+
+dateAndTime:something
+ "set the value of the instance variable 'dateAndTime' (automatically generated)"
+
+ dateAndTime := something.
+!
+
+fileName
+ "return the value of the instance variable 'fileName' (automatically generated)"
+
+ ^ fileName
+!
+
+fileName:something
+ "set the value of the instance variable 'fileName' (automatically generated)"
+
+ fileName := something withoutSpaces.
+!
+
+icon
+ "return the value of the instance variable 'icon' (automatically generated)"
+
+ ^ icon
+!
+
+icon:something
+ "set the value of the instance variable 'icon' (automatically generated)"
+
+ icon := something.
+!
+
+isDirectory
+ "return the value of the instance variable 'directory' (automatically generated)"
+
+ ^ isDirectory
+!
+
+isDirectory:something
+ "set the value of the instance variable 'isDirectory' (automatically generated)"
+
+ isDirectory := something.
+!
+
+method
+ "return the value of the instance variable 'method' (automatically generated)"
+
+ ^ method
+!
+
+method:something
+ "set the value of the instance variable 'method' (automatically generated)"
+
+ method := something.
+!
+
+ownerGroup
+ "return the value of the instance variable 'owner' (automatically generated)"
+
+ ^ ownerGroup
+!
+
+ownerGroup:something
+ "set the value of the instance variable 'owner' (automatically generated)"
+
+ ownerGroup := something.
+!
+
+permissions
+ "return the value of the instance variable 'permissions' (automatically generated)"
+
+ ^ permissions
+!
+
+permissions:something
+ "set the value of the instance variable 'permissions' (automatically generated)"
+
+ permissions := something.
+!
+
+ratio
+ "return the value of the instance variable 'ratio' (automatically generated)"
+
+ ^ ratio
+!
+
+ratio:something
+ "set the value of the instance variable 'ratio' (automatically generated)"
+
+ ratio := something.
+!
+
+size
+ "return the value of the instance variable 'size' (automatically generated)"
+
+ ^ size
+!
+
+size:something
+ "set the value of the instance variable 'size' (automatically generated)"
+
+ size := something.
+!
+
+sizeAsNumber
+ "return the value of the instance variable 'size' (automatically generated)"
+
+ ^ size asInteger
+!
+
+type
+ "return the value of the instance variable 'type' (automatically generated)"
+
+ ^ type
+!
+
+type:something
+ "set the value of the instance variable 'type' (automatically generated)"
+
+ type := something.
+!
+
+version
+ "return the value of the instance variable 'version' (automatically generated)"
+
+ ^ version
+!
+
+version:something
+ "set the value of the instance variable 'version' (automatically generated)"
+
+ version := something.
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication::ArchivItem methodsFor:'printing'!
+
+printString
+
+ ^ self fileName asString
+! !
+
+!FileApplicationNoteBook::ArchiveViewApplication::ArchivItem methodsFor:'queries'!
+
+hasDirectoryPart
+
+ ^ self fileName asFilename components size ~= 1
+! !
+
+!FileApplicationNoteBook::CommandResult class methodsFor:'defaults'!
+
+tabStringFor:aApplicationType
+
+ ^ 'Execution result'
+!
+
+wantNewApplicationAnyway
+
+ ^ false
+! !
+
+!FileApplicationNoteBook::CommandResult class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:NoteBookApplication::CommandResult andSelector:#windowSpec
+ NoteBookApplication::CommandResult new openInterface:#windowSpec
+ NoteBookApplication::CommandResult open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'NoteBookApplication::CommandResult'
+ #name: 'NoteBookApplication::CommandResult'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 16 42 519 395)
+ #menu: #mainMenu
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'ToolBar1'
+ #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+ #menu: #menu
+ #textDefault: true
+ )
+ #(#ArbitraryComponentSpec
+ #name: 'ArbitraryComponent1'
+ #layout: #(#LayoutFrame 0 0.0 32 0 0 1.0 0 1)
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #hasBorder: false
+ #component: #TextCollector
+ #postBuildCallback: #postBuildTextCollector:
+ )
+ #(#LabelSpec
+ #label: 'FileLabel'
+ #name: 'FileLabel'
+ #layout: #(#LayoutFrame 87 0 2 0 -36 1 30 0)
+ #level: -1
+ #translateLabel: true
+ #labelChannel: #labelHolder
+ #adjust: #left
+ )
+ )
+
+ )
+ )
+! !
+
+!FileApplicationNoteBook::CommandResult class methodsFor:'menu specs'!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileApplicationNoteBook::CommandResult andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(FileApplicationNoteBook::CommandResult menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Stop'
+ #translateLabel: true
+ #isButton: true
+ #nameKey: #Stop
+ #value: #doStopProcess
+ #enabled: #enableStopButton
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #stop22x22Icon 'Stop')
+ )
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #isButton: true
+ #nameKey: #Close
+ #isVisible: #isEmbeddedApplication
+ #startGroup: #right
+ #value: #doClose
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #closeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileApplicationNoteBook::CommandResult methodsFor:'accessing'!
+
+resultStream
+ "return the value of the instance variable 'resultStream' (automatically generated)"
+
+ ^ resultStream
+!
+
+resultStream:something
+ "set the value of the instance variable 'resultStream' (automatically generated)"
+
+ resultStream := something.
+! !
+
+!FileApplicationNoteBook::CommandResult methodsFor:'actions'!
+
+changeTabTo:aString
+
+ | masterApplication |
+
+ self labelHolder value:aString.
+ masterApplication := self masterApplication.
+ masterApplication isNil ifFalse:[
+ masterApplication tabStringChangeTo:aString for:self.
+ ].
+!
+
+doStopProcess
+
+ | myProcess |
+
+ myProcess := self process value.
+ myProcess notNil ifTrue:[
+ self notifyChannel value:('kill ', myProcess name).
+ myProcess terminate.
+ self backgroundProcesses remove:myProcess ifAbsent:[].
+ ].
+! !
+
+!FileApplicationNoteBook::CommandResult methodsFor:'aspects'!
+
+enableStopButton
+
+ enableStopButton isNil ifTrue:[
+ enableStopButton := false asValue.
+ ].
+ ^ enableStopButton
+!
+
+labelHolder
+
+ labelHolder isNil ifTrue:[
+ labelHolder := '' asValue.
+ ].
+ ^ labelHolder.
+!
+
+process
+ "return/create the 'process' value holder (automatically generated)"
+
+ process isNil ifTrue:[
+ process := ValueHolder new.
+ process addDependent:self.
+ ].
+ ^ process
+! !
+
+!FileApplicationNoteBook::CommandResult methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+ "Invoked when an object that I depend upon sends a change notification."
+
+ "stub code automatically generated - please change as required"
+
+ changedObject == self process ifTrue:[
+ self enableStopButton value:changedObject value notNil.
+ ^ self
+ ].
+ super update:something with:aParameter from:changedObject
+! !
+
+!FileApplicationNoteBook::CommandResult methodsFor:'initialization & release'!
+
+postBuildTextCollector:aBuilder
+
+ self resultStream:aBuilder scrolledView.
+!
+
+postBuildWith:aBuilder
+ "This is a hook method generated by the Browser.
+ It will be invoked during the initialization of your app/dialog,
+ after all of the visual components have been built,
+ but BEFORE the top window is made visible.
+ Add any app-specific actions here (reading files, setting up values etc.)
+ See also #postOpenWith:, which is invoked after opening."
+
+ "/ add any code here ...
+
+ ^ super postBuildWith:aBuilder
+!
+
+postOpenWith:aBuilder
+ "This is a hook method generated by the Browser.
+ It will be invoked right after the applications window has been opened.
+ Add any app-specific actions here (starting background processes etc.).
+ See also #postBuildWith:, which is invoked before opening."
+
+ "/ add any code here ...
+
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ ].
+ ^ super postOpenWith:aBuilder
+!
+
+release
+
+ self doStopProcess.
+ ^ super release
+! !
+
+!FileApplicationNoteBook::CommandResult methodsFor:'printing'!
+
+printString
+
+ ^ 'CommandResult Application'
+! !
+
+!FileApplicationNoteBook::HtmlViewApplication class methodsFor:'defaults'!
+
+tabStringFor:aApplicationType
+
+ ^ 'HTML View for:'
+! !
+
+!FileApplicationNoteBook::HtmlViewApplication class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:NoteBookApplication::HtmlViewApplication andSelector:#windowSpec
+ NoteBookApplication::HtmlViewApplication new openInterface:#windowSpec
+ NoteBookApplication::HtmlViewApplication open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'NoteBookApplication::HtmlView'
+ #name: 'NoteBookApplication::HtmlView'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 16 42 692 534)
+ #menu: #mainMenu
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'MenuHtml'
+ #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+ #visibilityChannel: #isEmbeddedApplication
+ #menu: #menu
+ #textDefault: true
+ )
+ #(#ArbitraryComponentSpec
+ #name: 'HTMLView'
+ #layout: #(#LayoutFrame 0 0.0 32 0.0 0 1.0 0 1)
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #miniScrollerHorizontal: false
+ #miniScrollerVertical: false
+ #hasBorder: false
+ #component: #HTMLDocumentView
+ #postBuildCallback: #postBuildHtmlView:
+ )
+ #(#LabelSpec
+ #label: 'FileLabel'
+ #name: 'FileLabel'
+ #layout: #(#LayoutFrame 212 0 2 0 -73 1 30 0)
+ #level: -1
+ #translateLabel: true
+ #labelChannel: #labelHolder
+ #adjust: #left
+ )
+ )
+
+ )
+ )
+! !
+
+!FileApplicationNoteBook::HtmlViewApplication class methodsFor:'menu specs'!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileApplicationNoteBook::HtmlViewApplication andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(FileApplicationNoteBook::HtmlViewApplication menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Reload'
+ #translateLabel: true
+ #isButton: true
+ #value: #doReload
+ #labelImage: #(#ResourceRetriever nil #htmlReloadIcon)
+ )
+ #(#MenuItem
+ #label: 'Back'
+ #translateLabel: true
+ #isButton: true
+ #value: #doGoBack
+ #labelImage: #(#ResourceRetriever #Icon #leftIcon)
+ )
+ #(#MenuItem
+ #label: 'Print'
+ #translateLabel: true
+ #isButton: true
+ #value: #doPrint
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #printer22x22Icon)
+ )
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #isButton: true
+ #hideMenuOnActivated: false
+ #startGroup: #right
+ #value: #doClose
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #closeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileApplicationNoteBook::HtmlViewApplication class methodsFor:'queries'!
+
+canOpenItem:aItem
+
+ ^ (aItem hasMimeType and:[aItem mimeType isHtml])
+!
+
+wantNewApplicationAnyway
+
+ ^ false
+! !
+
+!FileApplicationNoteBook::HtmlViewApplication methodsFor:'accessing'!
+
+htmlView
+ "return the value of the instance variable 'imageView' (automatically generated)"
+
+ ^ htmlView
+!
+
+htmlView:something
+ "set the value of the instance variable 'imageView' (automatically generated)"
+
+ htmlView := something.
+!
+
+item:aItem
+
+ |retVal|
+
+ self labelHolder value:aItem fileName asString.
+ retVal := super item:aItem.
+ self setupHtmlView.
+ ^ retVal
+! !
+
+!FileApplicationNoteBook::HtmlViewApplication methodsFor:'actions'!
+
+doGoBack
+
+ self htmlView menu_back.
+!
+
+doGoHome
+
+ self htmlView menu_home.
+!
+
+doHelp
+
+ self htmlView menu_help.
+!
+
+doPrint
+
+ self htmlView menu_print.
+!
+
+doReload
+
+ self htmlView menu_reload.
+!
+
+setupHtmlView
+
+ | html file directory|
+
+ html := self htmlView.
+ html isNil ifTrue:[^ self].
+ file := self fileName.
+ directory := file directoryName.
+ html homeDocument:(file asString).
+ html setTopDirectoryName:directory.
+ html uriHolder:self labelHolder.
+ html infoHolder:self notifyChannel.
+ html linkButtonPanel:nil.
+ ^ html
+! !
+
+!FileApplicationNoteBook::HtmlViewApplication methodsFor:'aspects'!
+
+labelHolder
+
+ labelHolder isNil ifTrue:[
+ labelHolder := '' asValue.
+ ].
+ ^ labelHolder.
+! !
+
+!FileApplicationNoteBook::HtmlViewApplication methodsFor:'initialization & release'!
+
+postBuildHtmlView:aWidget
+
+ self htmlView: aWidget scrolledView.
+ self htmlView wantsFocusWithPointerEnter.
+!
+
+postOpenWith:aBuilder
+ "
+ only invoked if the application not started from a master
+ "
+
+ |currentDir contents suffix fileName|
+
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ currentDir := Filename homeDirectory.
+
+ contents := currentDir directoryContents.
+ fileName := contents
+ detect:[:file |
+ suffix := file asFilename suffix asLowercase.
+ suffix = 'html'
+ ]
+ ifNone:[nil].
+ fileName isNil ifTrue:[
+ Dialog warn:'cant find a HTML file in ' , currentDir asString.
+ ^ self
+ ].
+ self item:(DirectoryContentsBrowser itemClass with:('../../doc/online/english/TOP.html' asFilename)).
+ ].
+ self setupHtmlView.
+ ^ super postOpenWith:aBuilder
+! !
+
+!FileApplicationNoteBook::ImageViewApplication class methodsFor:'defaults'!
+
+tabStringFor:aApplicationType
+
+ ^ 'Image for:'
+! !
+
+!FileApplicationNoteBook::ImageViewApplication class methodsFor:'image specs'!
+
+fitSize20x20Icon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self fitSize20x20Icon inspect
+ ImageEditor openOnClass:self andSelector:#fitSize20x20Icon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'FileApplicationNoteBook::ImageViewApplication class fitSize20x20Icon'
+ ifAbsentPut:[(Depth4Image new) width: 20; height: 20; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@DQDQDQDQDP@@@PDQDQDQDQ@P@A@ADQDQDQDP@PD@@PDQDQDPD@@QDQ@ADQDQ@@DQDQD@@@@@@@@@DQDQDPQDQDQ@DQDQDQDDQUUTPADQDQDQAEUUUT@QDQ
+DQDPQEUUQ@DQDQDQDDQFQDPADQDQDQADQ$QD@QDQDQDPL3X3Q@DQDQDQDCL3L3LADQDQD@@@@@@@@@DQDQD@DQDQDP@QDQ@@DADQDQDA@@DA@ADQDQDQDP@P
+@@@QDQDQDQDA@@@ADQDQDQDQD@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 255 255 0 0 0 0 137 0 174 218 230 0 206 0 133 60 36]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+8@A00@@0(@APE@J@C@L@G?>@A?8@A?8@A?8@A?8@A?8@A?8@A?8@A?8@G?>@C@L@E@J@(@AP0@@08@A0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; yourself); yourself]
+! !
+
+!FileApplicationNoteBook::ImageViewApplication class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:FileApplicationNoteBook::ImageViewApplication andSelector:#windowSpec
+ FileApplicationNoteBook::ImageViewApplication new openInterface:#windowSpec
+ FileApplicationNoteBook::ImageViewApplication open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'ImageViewer'
+ #name: 'ImageViewer'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 16 42 692 534)
+ #menu: #mainMenu
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'MenuTerminal'
+ #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+ #visibilityChannel: #isEmbeddedApplication
+ #menu: #menu
+ #textDefault: true
+ )
+ #(#ArbitraryComponentSpec
+ #name: 'TerminalView'
+ #layout: #(#LayoutFrame 0 0.0 32 0.0 0 1.0 0 1.0)
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #miniScrollerHorizontal: false
+ #miniScrollerVertical: false
+ #hasBorder: false
+ #component: #ImageView
+ #postBuildCallback: #postBuildImageView:
+ )
+ )
+
+ )
+ )
+! !
+
+!FileApplicationNoteBook::ImageViewApplication class methodsFor:'menu specs'!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileApplicationNoteBook::ImageViewApplication andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(FileApplicationNoteBook::ImageViewApplication menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Edit'
+ #translateLabel: true
+ #isButton: true
+ #nameKey: #EditImage
+ #value: #editImage
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'FitSize'
+ #translateLabel: true
+ #isButton: true
+ #triggerOnDown: true
+ #labelImage: #(#ResourceRetriever #'FileApplicationNoteBook::ImageViewApplication' #fitSize20x20Icon)
+ #indication: #fitSize
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #isButton: true
+ #hideMenuOnActivated: false
+ #startGroup: #right
+ #value: #doClose
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #closeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileApplicationNoteBook::ImageViewApplication class methodsFor:'queries'!
+
+canOpenItem:aItem
+
+ ^ (aItem hasMimeType and:[aItem mimeType isImage])
+!
+
+wantNewApplicationAnyway
+
+ ^ false
+! !
+
+!FileApplicationNoteBook::ImageViewApplication methodsFor:'accessing'!
+
+image:something
+ "set the value of the instance variable 'image' (automatically generated)"
+
+ image := something.
+!
+
+imageView
+ "return the value of the instance variable 'imageView' (automatically generated)"
+
+ ^ imageView
+!
+
+imageView:something
+ "set the value of the instance variable 'imageView' (automatically generated)"
+
+ imageView := something.
+! !
+
+!FileApplicationNoteBook::ImageViewApplication methodsFor:'actions'!
+
+changeItem:aItem
+
+ self item:aItem.
+ self setupImageView.
+ ^ true
+!
+
+editImage
+ |img|
+
+ img := self image.
+ img notNil ifTrue:[
+ img edit.
+ ].
+!
+
+image
+ |img fn e|
+
+ fn := self fileName.
+ img := Image fromFile:fn.
+ img isNil ifTrue:[
+ fn exists ifTrue:[
+ e := 'Unknown/unsupported image format'
+ ] ifFalse:[
+ e := 'No such image'
+ ].
+ Dialog warn:e.
+ ^ nil
+ ].
+ ^ img.
+!
+
+setupImageView
+ |img|
+
+ self window topView withWaitCursorDo:[
+ img := self image.
+ img notNil ifTrue:[
+ self image:img.
+ imageView image:img
+ ]
+ ]
+! !
+
+!FileApplicationNoteBook::ImageViewApplication methodsFor:'aspects'!
+
+fitSize
+ "return/create the 'fitSize' value holder (automatically generated)"
+
+ fitSize isNil ifTrue:[
+ fitSize := ValueHolder new.
+ fitSize addDependent:self.
+ ].
+ ^ fitSize
+! !
+
+!FileApplicationNoteBook::ImageViewApplication methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+ changedObject == self fitSize ifTrue:[
+ changedObject value ifTrue:[
+ imageView adjust:#fitBig.
+ ] ifFalse:[
+ imageView adjust:nil.
+ ].
+ ^ self
+ ].
+ super update:something with:aParameter from:changedObject
+! !
+
+!FileApplicationNoteBook::ImageViewApplication methodsFor:'initialization & release'!
+
+postBuildImageView:aWidget
+
+ self imageView: aWidget scrolledView.
+ self imageView wantsFocusWithPointerEnter.
+!
+
+postOpenWith:aBuilder
+ "
+ only invoked if the application not started from a master
+ "
+
+ |currentDir contents suffix fileName|
+
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ currentDir := Filename currentDirectory.
+ contents := currentDir directoryContents.
+ fileName := contents
+ detect:[:file |
+ suffix := file asFilename suffix asLowercase.
+ Image isImageFileSuffix:suffix
+ ]
+ ifNone:[nil].
+ fileName isNil ifTrue:[
+ Dialog warn:'cant find a Image in ' , currentDir asString.
+ ^ self
+ ].
+ self item:(DirectoryContentsBrowser itemClass with:(currentDir construct:fileName))
+ ].
+ self setupImageView.
+ ^ super postOpenWith:aBuilder
+! !
+
+!FileApplicationNoteBook::Terminal class methodsFor:'defaults'!
+
+tabStringFor:aApplicationType
+
+ ^ 'Terminal in:'
+! !
+
+!FileApplicationNoteBook::Terminal class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:NoteBookApplication::Terminal andSelector:#windowSpec
+ NoteBookApplication::Terminal new openInterface:#windowSpec
+ NoteBookApplication::Terminal open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'NoteBookApplication::Terminal'
+ #name: 'NoteBookApplication::Terminal'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 16 42 692 534)
+ #menu: #mainMenu
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'MenuTerminal'
+ #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+ #menu: #menu
+ #textDefault: true
+ )
+ #(#ArbitraryComponentSpec
+ #name: 'TerminalView'
+ #layout: #(#LayoutFrame 0 0.0 32 0.0 0 1.0 0 1.0)
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #miniScrollerHorizontal: false
+ #miniScrollerVertical: false
+ #hasBorder: false
+ #component: #terminalView
+ )
+ )
+
+ )
+ )
+! !
+
+!FileApplicationNoteBook::Terminal class methodsFor:'menu specs'!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileApplicationNoteBook::Terminal andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(FileApplicationNoteBook::Terminal menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Save'
+ #translateLabel: true
+ #isButton: true
+ #nameKey: #Save
+ #value: #saveAs
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #saveToFile28x22Icon)
+ )
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #isButton: true
+ #hideMenuOnActivated: false
+ #isVisible: #isEmbeddedApplication
+ #startGroup: #right
+ #value: #doClose
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #closeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileApplicationNoteBook::Terminal methodsFor:'accessing'!
+
+terminalView
+
+ terminalView isNil ifTrue:[
+ terminalView := VT100TerminalView new.
+ ].
+ ^ terminalView.
+! !
+
+!FileApplicationNoteBook::Terminal methodsFor:'actions'!
+
+saveAs
+
+ self terminalView save.
+! !
+
+!FileApplicationNoteBook::Terminal methodsFor:'initialization & release'!
+
+postBuildWith:aBuilder
+
+ ^ super postBuildWith:aBuilder
+!
+
+shellFinished
+
+ | master text string|
+
+ master := self masterApplication.
+ master notNil ifTrue:[
+ string := ' - closed'.
+ master tabStringAdd:string for:self.
+ ].
+ self notifyChannel value:'shell in ' , self fileName asString, ' finished'.
+ terminalView cr.
+ text := '>> shell closed' asText allBold.
+ text colorizeAllWith:Color red.
+ terminalView nextPutAll:text.
+!
+
+startShell
+ |vt100|
+
+ vt100 := self terminalView.
+ vt100 shellTerminateAction:[ self shellFinished ].
+ vt100 startShellIn:(self fileName).
+! !
+
+!FileApplicationNoteBook::Terminal methodsFor:'printing'!
+
+printString
+
+ ^ ('Terminal on:', self fileName baseName)
+! !
+
+!FileApplicationNoteBook::Terminal methodsFor:'queries'!
+
+getTabStringEnd
+
+" get the tab string from the application list on the class side "
+
+ ^ '..', OperatingSystem fileSeparator, self fileName baseName, OperatingSystem fileSeparator
+! !
+
+!FileApplicationNoteBook::Terminal methodsFor:'startup & release'!
+
+postOpenWith:aBuilder
+
+ "
+ only invoked if the application not started from a master
+ "
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ self item:(DirectoryContentsBrowser itemClass with:(Filename currentDirectory asAbsoluteFilename)).
+ ].
+ self startShell.
+ ^ super postOpenWith:aBuilder.
+! !
+
+!FileApplicationNoteBook::TextEditor class methodsFor:'defaults'!
+
+tabStringFor:aApplicationType
+
+ aApplicationType == #directoryDescription ifTrue:[
+ ^ 'Directory description for:'
+ ] ifFalse:[
+ ^ 'Editor on:'
+ ].
+!
+
+wantNewApplicationAnyway
+
+ ^ false
+! !
+
+!FileApplicationNoteBook::TextEditor class methodsFor:'interface - specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:NoteBookApplication::TextEditor andSelector:#windowSpec
+ NoteBookApplication::TextEditor new openInterface:#windowSpec
+ NoteBookApplication::TextEditor open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'TextEditor'
+ #name: 'TextEditor'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 12 22 662 322)
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'MenuTextEditor'
+ #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+ #menu: #menu
+ #textDefault: true
+ )
+ #(#TextEditorSpec
+ #name: 'TextEditor'
+ #layout: #(#LayoutFrame 0 0.0 32 0 0 1.0 0 1.0)
+ #model: #fileContentsModel
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #modifiedChannel: #modifiedChannel
+ #acceptCallBack: #accept
+ #postBuildCallback: #postBuildTextEditor:
+ )
+ )
+
+ )
+ )
+! !
+
+!FileApplicationNoteBook::TextEditor class methodsFor:'menu specs'!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileApplicationNoteBook::TextEditor andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(FileApplicationNoteBook::TextEditor menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Save'
+ #translateLabel: true
+ #isButton: true
+ #nameKey: #Save
+ #value: #accept
+ #enabled: #enableSave
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #saveToFile28x22Icon)
+ )
+ #(#MenuItem
+ #label: 'Reload'
+ #translateLabel: true
+ #isButton: true
+ #nameKey: #Reload
+ #value: #reload
+ #enabled: #enableReload
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #reloadFromFile28x22Icon)
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'Print'
+ #translateLabel: true
+ #isButton: true
+ #nameKey: #Print
+ #value: #doPrint
+ #enabled: #enableHexToggle
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #printer22x22Icon)
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'Hex'
+ #translateLabel: true
+ #isButton: true
+ #enabled: #enableHexToggle
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #hexToggle22x22Icon)
+ #indication: #printAsHexDump
+ )
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #isButton: true
+ #hideMenuOnActivated: false
+ #isVisible: #isEmbeddedApplication
+ #startGroup: #right
+ #value: #doClose
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #closeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileApplicationNoteBook::TextEditor methodsFor:'accessing'!
+
+item:aDirContentsItem
+
+
+ self stopChangeItemProcess.
+ super item:aDirContentsItem.
+ (self askForChange) isNil ifTrue:[ ^ false].
+ self setContents.
+ self startChangeItemProcess.
+ ^ true
+!
+
+presentation
+ "return the value of the instance variable 'presentation' (automatically generated)"
+
+ presentation isNil ifTrue:[
+ presentation := #asText.
+ ].
+ ^ presentation
+!
+
+presentation:something
+ "set the value of the instance variable 'presentation' (automatically generated)"
+
+ presentation := something.
+!
+
+semaChangeItem
+
+ semaChangeItem isNil ifTrue:[
+ semaChangeItem := Semaphore forMutualExclusion.
+ ].
+ ^ semaChangeItem
+! !
+
+!FileApplicationNoteBook::TextEditor methodsFor:'actions'!
+
+accept
+
+ | dir |
+
+ self masterApplication class openAnotherApplicationOnSameItem ifTrue:[
+ self updateSameFiles ifFalse:[ ^ self ].
+ ].
+ self notifyChannel value:self fileName asString, ' saved'.
+ dir := self fileName directory.
+ dir exists not ifTrue:[
+ dir recursiveMakeDirectory.
+ ].
+ editView saveAs:(self fileName).
+ self notifyChannel value:self fileName asString, ' saved'.
+ self semaChangeItem critical:[
+ self item resetItemForTextEditorChange.
+ textEditorChangeModificationTime := nil.
+ self itemChanged value:false.
+ ].
+ self modifiedChannel value:false.
+ self itemRemoved value:false.
+!
+
+askForChange
+ "ask for save changes
+ "
+
+ |answer string|
+
+ answer := false.
+ self modifiedChannel value ifTrue:[
+ self itemChanged value ifTrue:[
+ string := self fileName asString , ' was changed by someone else'
+ , Character cr , 'want to save your changes anyway ?'
+ ].
+ self itemRemoved value ifTrue:[
+ string := self fileName asString , ' was removed by someone else'
+ , Character cr , 'want to save your changes anyway ?'
+ ].
+ string := 'save changed file ' , self fileName asString , ' ?'
+ ].
+ string notNil ifTrue:[
+ answer := (Dialog confirmWithCancel:string).
+ answer isNil ifTrue:[^ answer].
+ answer == true ifTrue:[
+ self accept
+ ] ifFalse:[
+ self setContents.
+ ]
+ ].
+ ^ answer
+!
+
+changeInformation
+
+ | stream |
+
+ stream := WriteStream with:(self getTabString).
+ masterApplication isNil ifTrue:[
+ self window label:stream contents.
+
+ ] ifFalse:[
+ masterApplication tabStringChangeTo:stream contents for:self.
+ ].
+ stream close.
+!
+
+doClose
+
+ (self askForChange) isNil ifTrue:[ ^ false].
+ self masterApplication notNil ifTrue:[
+ super doClose
+ ].
+ ^ true
+!
+
+doPrint
+ "print the contents
+ "
+ (Dialog confirm:'printing ?') ifTrue:[
+ editView doPrint.
+ ].
+!
+
+reload
+
+ self setContents.
+!
+
+setContents
+
+
+ |file contents present|
+
+ file := self fileName.
+ RecursionInterruptSignal handle:[ : ex |
+ Dialog warn:file asString, ' is too big to be loaded !!'.
+ ^ false.
+ ] do:[
+ present := self presentation.
+ present == #asText ifTrue:[
+ contents := file contents.
+ ] ifFalse:[
+ present == #hexDump ifTrue:[
+ contents := self getFileHexContents:file.
+ ]
+ ]
+ ].
+ self fileContentsModel value:contents.
+ self enableReload value:false.
+ self itemChanged value:false.
+ self modifiedChannel setValue:false.
+ self modifiedChannel changed.
+ ^ true
+!
+
+updateSameFiles
+
+ | master modifiedApplications stream filename action|
+
+ master := self masterApplication.
+ master notNil ifTrue:[
+ modifiedApplications := master getSameFilesModifiedFor:self.
+ (modifiedApplications isNil or:[modifiedApplications isEmpty]) ifTrue:[^ true ].
+ filename := self fileName asString.
+ stream := WriteStream on:''.
+ stream nextPutAll:filename.
+ stream nextPutAll:' is modified in tab'.
+ modifiedApplications size > 1 ifTrue:[
+ stream nextPutAll:'s'.
+ ].
+ stream cr.
+ modifiedApplications do:[ : el |
+ stream space.
+ stream nextPutAll:filename.
+ stream space.
+ el sameFileIndex notNil ifTrue:[
+ stream nextPutAll:el sameFileIndex asString.
+ ].
+ stream cr.
+ ].
+ stream nextPutAll:'forget changes on other tab'.
+ modifiedApplications size > 1 ifTrue:[
+ stream nextPutAll:'s'.
+ ].
+ stream nextPutAll:' ?'.
+ action := Dialog
+ choose:stream contents
+ labels:#('cancel' 'no' 'yes')
+ values:#(#cancel #no #yes)
+ default:#cancel.
+
+ stream close.
+ action == #cancel ifTrue:[ ^ false ].
+ action == #yes ifTrue:[
+ "/ here force reload for other applications
+ modifiedApplications do:[ : el |
+ el reload.
+ ]
+ ].
+ ].
+ ^ true.
+! !
+
+!FileApplicationNoteBook::TextEditor methodsFor:'aspects'!
+
+doSaveFile
+
+ doSaveFile isNil ifTrue:[
+ doSaveFile := ValueHolder new.
+ ].
+ ^ doSaveFile.
+!
+
+enableHexToggle
+
+ enableHexToggle isNil ifTrue:[
+ enableHexToggle := true asValue.
+ ].
+ ^ enableHexToggle
+!
+
+enableReload
+
+ enableReload isNil ifTrue:[
+ enableReload := false asValue.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+"/ enableReload addDependent:self.
+"/ enableReload onChangeSend:#enableReloadChanged to:self.
+ ].
+ ^ enableReload.
+!
+
+enableSave
+
+ enableSave isNil ifTrue:[
+ enableSave := false asValue.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+"/ enableSave addDependent:self.
+"/ enableSave onChangeSend:#enableSaveChanged to:self.
+ ].
+ ^ enableSave.
+!
+
+fileContentsModel
+
+ fileContentsModel isNil ifTrue:[
+ fileContentsModel := ValueHolder new.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+"/ fileContentsModel addDependent:self.
+"/ fileContentsModel onChangeSend:#fileContentsModelChanged to:self.
+ ].
+ ^ fileContentsModel.
+!
+
+itemChanged
+
+ itemChanged isNil ifTrue:[
+ itemChanged := false asValue.
+ itemChanged addDependent:self.
+ ].
+ ^ itemChanged
+!
+
+itemRemoved
+
+ itemRemoved isNil ifTrue:[
+ itemRemoved := false asValue.
+ itemRemoved addDependent:self.
+ ].
+ ^ itemRemoved
+!
+
+modifiedChannel
+
+ modifiedChannel isNil ifTrue:[
+ modifiedChannel := false asValue.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+ modifiedChannel addDependent:self.
+"/ modifiedChannel onChangeSend:#modifiedChannelChanged to:self.
+ ].
+ ^ modifiedChannel.
+!
+
+printAsHexDump
+
+ printAsHexDump isNil ifTrue:[
+ printAsHexDump := false asValue.
+ printAsHexDump addDependent:self.
+ ].
+ ^ printAsHexDump.
+! !
+
+!FileApplicationNoteBook::TextEditor methodsFor:'change & update'!
+
+changeEnableReload
+
+ | modified changed removed |
+
+ modified := self modifiedChannel value.
+ changed := self itemChanged value.
+ removed := self itemRemoved value.
+
+ self enableReload value:((modified or:[changed]) and:[removed not]).
+!
+
+update:something with:aParameter from:changedObject
+ "Invoked when an object that I depend upon sends a change notification."
+
+ "stub code automatically generated - please change as required"
+
+ |modified itemRem|
+
+ changedObject == self modifiedChannel ifTrue:[
+ modified := changedObject value.
+ self enableSave value:modified.
+ self changeEnableReload.
+ ^ self
+ ].
+ changedObject == self itemRemoved ifTrue:[
+ itemRem := changedObject value.
+ itemRem == true ifTrue:[
+ self enableSave value:true.
+ ].
+ self enableHexToggle value:itemRem not.
+ self changeEnableReload.
+ ^ self
+ ].
+ changedObject == self itemChanged ifTrue:[
+ self changeEnableReload.
+ changedObject value == true ifTrue:[
+ self enableSave value:true.
+ ].
+ ^ self
+ ].
+ changedObject == self printAsHexDump ifTrue:[
+ (self askForChange) isNil ifTrue:[
+ self printAsHexDump value:changedObject value not withoutNotifying:self.
+ ^ self
+ ].
+ changedObject value ifTrue:[
+ self presentation:#hexDump.
+ ] ifFalse:[
+ self presentation:#asText.
+ ].
+ self changeInformation.
+ self setContents.
+ (self presentation == #hexDump) ifTrue:[
+ editView readOnly:true.
+ ] ifFalse:[
+ editView readOnly:false.
+ ].
+ ^ self
+ ].
+
+ super update:something with:aParameter from:changedObject
+! !
+
+!FileApplicationNoteBook::TextEditor methodsFor:'printing'!
+
+printString
+
+ ^ ('TextEditor for:', self fileName baseName)
+! !
+
+!FileApplicationNoteBook::TextEditor methodsFor:'privat-process'!
+
+checkMyItemForChanges
+
+ | dir exist myItem|
+
+ dir := self fileName directory.
+ myItem := self item.
+ exist := myItem exists.
+ self itemRemoved value:(exist not).
+ exist ifTrue:[
+ self semaChangeItem critical:[
+ | time info|
+ info := self fileName asAbsoluteFilename info.
+ time := info modified.
+ textEditorChangeModificationTime isNil ifTrue:[
+ textEditorChangeModificationTime := time.
+ ].
+ ((textEditorChangeModificationTime = time) not) ifTrue:[
+ "/ contents changed by someone else
+ textEditorChangeModificationTime := time.
+ self notifyChannel value:item fileName asString, ' was changed by someone else'.
+ self itemChanged value:true.
+ ].
+ ]
+ ]
+!
+
+getFileHexContents:f
+
+ |fileName stream data offs
+ addrDigits col line lineStream asciiLineStream lines|
+
+ fileName := f baseName.
+ f isDirectory ifTrue:[
+ ^ Dialog warn:(resources string:'%1 is a directory.' with:fileName).
+ ].
+ f exists ifFalse:[
+ Dialog warn:(resources string:'oops, ''%1'' is gone or unreadable.' with:fileName).
+ ^ self
+ ].
+ f isReadable ifFalse:[
+ Dialog warn:(resources string:'''%1'' is unreadable.' with:fileName).
+ ^ self
+ ].
+ f fileSize > (512*1024) ifTrue:[
+ (Dialog confirm:'Warning: the file is big (', (f fileSize//1024) printString , 'Kb). Show anyway ?')
+ ifFalse:[
+ ^ self
+ ]
+ ].
+ stream := f readStream binary.
+ data := stream contents.
+ stream close.
+
+"/ subView list:nil.
+ col := 1.
+ offs := 0.
+ lines := StringCollection new.
+
+ addrDigits := ((f fileSize + 1) log:16) truncated + 1.
+
+ lineStream := '' writeStream.
+ asciiLineStream := '' writeStream.
+
+ lineStream nextPutAll:(offs hexPrintString:addrDigits).
+ lineStream nextPutAll:': '.
+
+ data do:[:byte |
+ lineStream nextPutAll:(byte hexPrintString:2).
+ (byte between:32 and:127) ifTrue:[
+ asciiLineStream nextPut:(Character value:byte)
+ ] ifFalse:[
+ asciiLineStream nextPut:$.
+ ].
+
+ offs := offs + 1.
+ col := col + 1.
+ col > 16 ifTrue:[
+ lineStream nextPutAll:' '.
+ lineStream nextPutAll:asciiLineStream contents.
+ lines add:(lineStream contents).
+ (offs bitAnd:16rFF) == 0 ifTrue:[
+ lines add:nil
+ ].
+ lineStream reset.
+ asciiLineStream reset.
+
+ lineStream nextPutAll:(offs hexPrintString:addrDigits).
+ lineStream nextPutAll:': '.
+ col := 1.
+ ] ifFalse:[
+ lineStream space
+ ]
+ ].
+ line := lineStream contents paddedTo:(3*16 + addrDigits + 1).
+ lines add:(line , ' ' , asciiLineStream contents).
+ ^ lines
+!
+
+startChangeItemProcess
+
+ changeItemProcess isNil ifTrue:[
+ self itemRemoved value:false.
+ self itemChanged value:false.
+ changeItemProcess := Process for:[ [ [true] whileTrue:[
+
+ self checkMyItemForChanges.
+ Delay waitForSeconds:1.0
+ ]
+ ] valueNowOrOnUnwindDo:[
+ changeItemProcess := nil.
+ textEditorChangeModificationTime := nil.
+ ]
+ ]
+ priority:(Processor systemBackgroundPriority).
+
+ changeItemProcess name:('TextEditorLookForModify[', self fileName baseName, ']').
+ changeItemProcess resume.
+ ].
+!
+
+stopChangeItemProcess
+
+ | task |
+
+ task := changeItemProcess.
+ task notNil ifTrue:[
+ changeItemProcess := nil.
+
+ Object errorSignal handle:[:ex|
+ Dialog warn:ex description.
+ ]do:[
+ task isDead ifFalse:[
+ task terminate.
+ task waitUntilTerminated.
+ ]
+ ]
+ ].
+! !
+
+!FileApplicationNoteBook::TextEditor methodsFor:'queries'!
+
+isModified
+
+ ^ self modifiedChannel value
+! !
+
+!FileApplicationNoteBook::TextEditor methodsFor:'startup & release'!
+
+closeRequest
+
+ (self doClose) ifTrue:[
+ ^ super closeRequest.
+ ].
+!
+
+postBuildTextEditor:aWidget
+
+ editView := aWidget scrolledView.
+!
+
+postBuildWith:aBuilder
+
+ super postBuildWith:aBuilder.
+!
+
+postOpenWith:aBuilder
+
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ self item:(DirectoryContentsBrowser itemClass with:(Filename homeDirectory construct:'/lala/.bashrc')).
+ ].
+ self setUpTextView.
+ self changeInformation.
+ ^ super postOpenWith:aBuilder
+!
+
+release
+ "release my resources
+ "
+ self stopChangeItemProcess.
+ super release.
+!
+
+setUpTextView
+
+ |paranthesis col|
+
+ self item hasMimeType ifFalse:[^nil].
+ (self item mimeType isHtml) ifTrue:[
+ paranthesis := editView parenthesisSpecification.
+ ((paranthesis at:#open) includes:$<) ifFalse:[
+ col := (paranthesis at:#open) asOrderedCollection add:$<.
+ paranthesis at:#open put:col.
+ ].
+ ((paranthesis at:#close) includes:$>) ifFalse:[
+ col := (paranthesis at:#close) asOrderedCollection add:$>.
+ paranthesis at:#close put:col.
+ ]
+ ].
+! !
+
+!FileApplicationNoteBook::XViewApplication class methodsFor:'defaults'!
+
+maxNumberOfVNCRestarts
+
+ ^ 10
+!
+
+mimeTypeUnixApplicationMapping
+
+" here insert the application and mime type pairs to open by XviewApplication
+"
+
+ ^
+ #(
+ #(#'application/postscript' #gv )
+ #(#'application/pdf' #acroread )
+ )
+!
+
+tabStringFor:aApplicationType
+
+ ^ 'VNC for:'
+!
+
+wantNewApplicationAnyway
+
+ ^ false
+! !
+
+!FileApplicationNoteBook::XViewApplication class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:NoteBookApplication::XViewApplication andSelector:#windowSpec
+ NoteBookApplication::XViewApplication new openInterface:#windowSpec
+ NoteBookApplication::XViewApplication open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'XView'
+ #name: 'XView'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 12 22 688 514)
+ #menu: #mainMenu
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'MenuTerminal'
+ #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+ #visibilityChannel: #isEmbeddedApplication
+ #menu: #menu
+ #textDefault: true
+ )
+ #(#ArbitraryComponentSpec
+ #name: 'TerminalView'
+ #layout: #(#LayoutFrame 0 0.0 32 0.0 0 1.0 0 1.0)
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #miniScrollerHorizontal: false
+ #miniScrollerVertical: false
+ #hasBorder: false
+ #component: #VNCFrameBufferView
+ #postBuildCallback: #postBuildXView:
+ )
+ )
+
+ )
+ )
+! !
+
+!FileApplicationNoteBook::XViewApplication class methodsFor:'menu specs'!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:NoteBookApplication::ImageViewApplication andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(NoteBookApplication::ImageViewApplication menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #isButton: true
+ #hideMenuOnActivated: false
+ #startGroup: #right
+ #value: #doClose
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #closeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileApplicationNoteBook::XViewApplication class methodsFor:'queries'!
+
+canOpenItem:aItem
+
+ | keySym canOpen|
+
+ keySym := aItem mimeType asSymbol.
+ (OperatingSystem isUNIXlike) not ifTrue:[^ false].
+ canOpen := self mimeTypeUnixApplicationMapping detect:[ : el | (el at:1) == keySym ] ifNone:[nil].
+ canOpen isNil ifTrue:[^ false].
+ (OperatingSystem executeCommand:('which ', self UnixVNCCommand)) ifTrue:[
+ ^ true
+ ] ifFalse:[
+ (Dialog warn:'cant start viewer for '
+ , aItem fileName baseName
+ )
+ ].
+ ^ false.
+! !
+
+!FileApplicationNoteBook::XViewApplication methodsFor:'accessing'!
+
+xView
+ "return the value of the instance variable 'imageView' (automatically generated)"
+
+ ^ xView
+!
+
+xView:something
+ "set the value of the instance variable 'imageView' (automatically generated)"
+
+ xView := something.
+! !
+
+!FileApplicationNoteBook::XViewApplication methodsFor:'actions'!
+
+changeInformation
+
+ | stream|
+
+ stream := WriteStream on:''.
+ stream nextPutAll:'XView on: '.
+ stream nextPutAll:self fileName baseName.
+ masterApplication isNil ifTrue:[
+ self window label:stream contents.
+
+ ] ifFalse:[
+ masterApplication tabStringChangeTo:stream contents for:self.
+ ].
+ stream close.
+!
+
+setupXView
+
+ |xExt yExt fileBrowserWindow|
+
+ self startVNCserver.
+ xExt := self xView width asString.
+ fileBrowserWindow := self application:#FileBrowserV2 do:#window.
+ fileBrowserWindow isNil ifTrue:[
+ yExt := self xView height asString.
+ ] ifFalse:[
+ yExt := fileBrowserWindow height asString.
+ ].
+ ext := xExt, 'x', yExt.
+ self startViewer.
+! !
+
+!FileApplicationNoteBook::XViewApplication methodsFor:'actions VNC'!
+
+setupView
+ | renderer view|
+
+ view := xView.
+ renderer := VNCRenderer for:vncConnection targetWindow:view device:xView device.
+
+ view renderer:renderer.
+ view connection:vncConnection.
+
+ VNCException handle:[:ex|
+ self stopViewer.
+ ] do:[
+ vncConnection
+ startMessageHandlerProcessForRenderer:renderer
+ errorHandler:[:ex | self stopViewer].
+ ].
+!
+
+startVNCserver
+ |cmd blocked connected numberOfVncStarts|
+
+ connected := false.
+ numberOfVncStarts isNil ifTrue:[
+ numberOfVncStarts := 1.
+ ] ifFalse:[
+ numberOfVncStarts := numberOfVncStarts + 1.
+ ].
+
+ vncLock isNil ifTrue:[vncLock := Semaphore forMutualExclusion].
+
+ vncServerPID isNil ifTrue:[
+ cmd := ('/usr/X11R6/bin/', self class UnixVNCCommand).
+ cmd asFilename exists ifFalse:[
+ cmd := self class UnixVNCCommand.
+ ].
+ vncPortNr isNil ifTrue:[
+ vncPortNr := 29
+ ].
+ cmd := cmd , ' :' , vncPortNr printString , ' nologo -nevershared -localhost -depth 16 -geometry 1024x1024'.
+
+ blocked := OperatingSystem blockInterrupts.
+
+ vncServerPID := Processor
+ monitor:[
+ vncServerIsTerminated := false.
+ OperatingSystem
+ exec:'/bin/sh'
+ withArguments:(Array with:'sh' with:'-c' with:cmd)
+ fileDescriptors:#()
+ closeDescriptors:#()
+ fork:true
+ newPgrp:true
+ inDirectory:nil.
+ ]
+ action:[:status |
+ status stillAlive ifFalse:[
+ OperatingSystem closePid:vncServerPID.
+ vncLock critical:[
+ vncServerPID := nil.
+ self vncServerTerminated.
+ ].
+ ].
+ ].
+
+ blocked ifFalse:[
+ OperatingSystem unblockInterrupts
+ ].
+ ].
+
+ self waitForTerminationOfServer ifTrue:[
+"/ Transcript showCR:'server has terminated really - try with next port'.
+ (numberOfVncStarts < self class maxNumberOfVNCRestarts) ifTrue:[
+ vncPortNr := vncPortNr + 1.
+"/ Transcript showCR:'try next port ', vncPortNr asString.
+ self startVNCserver.
+ ] ifFalse:[
+ Dialog warn:'have started servers from port '
+ , (vncPortNr - self class maxNumberOfVNCRestarts) asString
+ , ' to '
+ , vncPortNr
+ , ' - cant connect anyway'.
+"/ Transcript showCR:'have started servers from port ', vncPortNr - self class maxNumberOfVNCRestarts, ' to ', vncPortNr.
+ ].
+ ] ifFalse:[
+ vncLock critical:[
+ vncServerPID isNil ifTrue:[
+ Dialog warn:'Cannot start Xvnc'.
+ ] ifFalse:[
+ VNCAuthenticationFailure handle:[:ex |
+ Dialog warn:'Wrong password'.
+ ] do:[
+ connected := self vncConnect.
+ ].
+ connected ifTrue:[self setupView].
+ ].
+ ].
+ ].
+!
+
+stopVNCServer
+
+ vncServerPID notNil ifTrue:[
+ OperatingSystem terminateProcess:vncServerPID.
+ Delay waitForSeconds:0.2.
+ vncServerPID notNil ifTrue:[
+ OperatingSystem killProcess:vncServerPID.
+ vncServerPID := nil.
+ ].
+ ].
+ self vncServerTerminated.
+!
+
+vncConnect
+ | tryConnects|
+
+ vncConnection notNil ifTrue:[
+ vncConnection close
+ ].
+
+ vncConnection := VNCServerConnection new.
+ tryConnects := 1.
+ [tryConnects < 3] whileTrue:[
+ VNCConnectionFailure handle:[:ex |
+ Delay waitForSeconds:0.5.
+ tryConnects := tryConnects + 1.
+ ] do:[
+ vncConnection connectTo:'localhost' port:vncPortNr.
+ ^ true.
+ ].
+ ].
+ ^ false
+!
+
+vncServerTerminated
+"/ Transcript showCR:'vnc server has terminated'.
+"/ 'vnc server has terminated' errorPrintCR.
+ "/ Dialog information:'vnc server has terminated'.
+
+ self stopViewer.
+ vncConnection notNil ifTrue:[
+ vncConnection close.
+ vncConnection := nil
+ ].
+ vncServerIsTerminated := true.
+!
+
+waitForTerminationOfServer
+ | cycles |
+
+ cycles := 1.
+ [vncServerIsTerminated] whileFalse:[
+ (cycles > 3) ifTrue:[^ false].
+ cycles := cycles + 1.
+ Delay waitForSeconds:0.5.
+ ].
+ ^ true
+! !
+
+!FileApplicationNoteBook::XViewApplication methodsFor:'actions viewer'!
+
+startViewer
+ |cmd keySym applItem |
+
+ keySym := self item mimeType asSymbol.
+ applItem := self class mimeTypeUnixApplicationMapping detect:[ : el | (el at:1) == keySym ] ifNone:[nil].
+ applItem isNil ifTrue:[ ^ self].
+
+ cmd := (applItem at:2) asString, ' -geometry ', ext, ' -display :' , vncPortNr printString , ' ' , self fileName asString.
+ self startViewer:cmd
+!
+
+startViewer:viewerCommand
+ |blocked|
+
+ viewerPID notNil ifTrue:[
+ ^ self
+ ].
+
+ blocked := OperatingSystem blockInterrupts.
+
+ viewerPID := Processor
+ monitor:[
+ OperatingSystem
+ exec:'/bin/sh'
+ withArguments:(Array with:'sh' with:'-c' with:viewerCommand)
+ fileDescriptors:#()
+ closeDescriptors:#()
+ fork:true
+ newPgrp:true
+ inDirectory:nil.
+ ]
+ action:[:status |
+ status stillAlive ifFalse:[
+ OperatingSystem closePid:viewerPID.
+ viewerPID := nil.
+ self viewerTerminated.
+ ].
+ ].
+
+ blocked ifFalse:[
+ OperatingSystem unblockInterrupts
+ ].
+
+ viewerPID isNil ifTrue:[
+ Dialog warn:'Cannot start ', viewerCommand.
+ ].
+!
+
+startXterm
+ |cmd|
+
+ cmd := 'xterm -geometry 600x800 -display :' , vncPortNr printString.
+ self startViewer:cmd
+!
+
+stopViewer
+ viewerPID notNil ifTrue:[
+ OperatingSystem terminateProcess:viewerPID.
+ Delay waitForSeconds:0.2.
+ viewerPID notNil ifTrue:[
+ OperatingSystem killProcess:viewerPID.
+ viewerPID := nil.
+ ]
+ ].
+!
+
+viewerTerminated
+"/ Transcript showCR:'viewer has terminated'.
+"/ 'viewer has terminated' errorPrintCR.
+ "/ Dialog information:'viewer has terminated'.
+! !
+
+!FileApplicationNoteBook::XViewApplication methodsFor:'initialization & release'!
+
+postBuildXView:aWidget
+
+ self xView:aWidget scrolledView.
+ self xView wantsFocusWithPointerEnter.
+ aWidget autoHideScrollBars:true.
+!
+
+postOpenWith:aBuilder
+ "
+ only invoked if the application not started from a master
+ "
+
+ |currentDir contents suffix fileName|
+
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ currentDir := Filename homeDirectory.
+ contents := currentDir directoryContents.
+ fileName := contents
+ detect:[:file |
+ suffix := file asFilename suffix asLowercase.
+ suffix = 'pdf'
+ ]
+ ifNone:[nil].
+ fileName isNil ifTrue:[
+ Dialog warn:'cant find a PDF File in ' , currentDir asString.
+ ^ self
+ ].
+ self item:(DirectoryContentsBrowser itemClass with:(currentDir construct:fileName)).
+ ].
+ self changeInformation.
+ self setupXView.
+ ^ super postOpenWith:aBuilder
+!
+
+release
+"/Transcript showCR:'release'.
+ self stopViewer.
+ self stopVNCServer.
+ ^ super release
+! !
+
+!FileApplicationNoteBook class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/FileApplicationNoteBook.st,v 1.1 2002-09-25 07:59:29 penk Exp $'
+! !
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FileBrowserV2.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,1372 @@
+"
+ COPYRIGHT (c) 1991 by Claus Gittinger
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+"
+
+"{ Package: 'stx:libtool' }"
+
+AbstractFileBrowser subclass:#FileBrowserV2
+ instanceVariableNames:'fileEntryFieldHolder'
+ classVariableNames:'Icons'
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+!FileBrowserV2 class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 1991 by Claus Gittinger
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+"
+!
+
+documentation
+"
+ FileBrowserV2 is based on Filebrowser created by Claus Gittinger
+
+ WARNING: files edited with FileBrowser will have leading spaces (multiple-8)
+ being replaced by tabs. If tabs are to be preserved at other
+ positions (for example, sendmail-config files) they will be
+ corrupt after being written.
+
+ [instance variables]:
+
+ checkDelta <Integer> number of seconds of check interval
+ (looks ever so often if shown directory
+ has changed). You may make this number
+ higher, if your network-times are
+ incorrect and thus, the filebrowser
+ checks too often.
+
+ compressTabs <Boolean> if true, leading spaces will be
+ replaced by tabs when saving text
+
+ some of the defaults (long/short list etc.) can be set by the resource file;
+ see FileBrowser>>initialize for more details..
+
+ [author:]
+ Christian Penk
+
+ [start with:]
+ FileBrowserV2 open
+"
+! !
+
+!FileBrowserV2 class methodsFor:'instance creation'!
+
+on:aDirectoryPath
+ "return a new FileBrowserV2 in a pathname"
+
+ | instance|
+ instance := self new.
+ instance currentFileNameHolder value:(Array with:aDirectoryPath).
+ ^ instance
+
+"/ | instance builder|
+"/
+"/ builder := super open.
+"/ instance := builder application.
+"/ instance currentFileNameHolder value:aDirectoryPath.
+"/ ^ instance
+
+ "
+ (FileBrowserV2 on:'/usr/local/bin') open
+ (FileBrowserV2 on:'/etc' ) open
+ (FileBrowserV2 on:'..' ) open
+ (FileBrowserV2 on:'.' ) open
+ "
+!
+
+open
+ "start a new FileBrowserV2"
+
+ | instance |
+ instance := self new.
+ instance open.
+ ^ instance
+ "
+ FileBrowserV2 openOn:'/etc' withExtent:800@600
+ FileBrowserV2 openOn:'..' withExtent:200@300
+ FileBrowserV2 openOn:'.' withExtent:1024@768
+ "
+!
+
+openOn:aDirectoryPath
+ "start a new FileBrowserV2 in a pathname"
+
+ | instance|
+ instance := self on:aDirectoryPath asFilename.
+ ^ instance open.
+ "
+ FileBrowserV2 openOn:'/etc'
+ FileBrowserV2 openOn:'..'
+ FileBrowserV2 openOn:'.'
+ "
+!
+
+openOn:aDirectoryPath withExtent:extent
+ "start a new FileBrowserV2 in a pathname"
+
+ | instance builder|
+ instance := self on:aDirectoryPath.
+ builder := instance open.
+ builder window extent:extent.
+ ^ instance
+ "
+ FileBrowserV2 openOn:'/etc' withExtent:800@600
+ FileBrowserV2 openOn:'..' withExtent:200@300
+ FileBrowserV2 openOn:'.' withExtent:1024@768
+ "
+!
+
+openWithAspects:someAspects withExtent:extent
+ "start a new FileBrowserV2 in a pathname"
+
+ |dir clone|
+
+ dir := someAspects at:#currentFileNameHolder ifAbsent:nil.
+ clone := self openOn:(dir value) withExtent:extent.
+
+ "
+ FileBrowserV2 openOn:'/etc' withExtent:800@600
+ FileBrowserV2 openOn:'..' withExtent:200@300
+ FileBrowserV2 openOn:'.' withExtent:1024@768
+ "
+! !
+
+!FileBrowserV2 class methodsFor:'class initialization'!
+
+clearHistoryIcon
+ ^ Icon deleteIcon
+!
+
+initialize
+
+ self installInLauncher.
+!
+
+initializeDefaultCommands
+ DefaultCommandPerMIME := Dictionary new.
+
+ DefaultCommandPerMIME at:'application/x-tar-compressed' put:'gunzip < %1 | tar tvf -'.
+ DefaultCommandPerMIME at:'application/pdf' put:'acroread %1'.
+
+ "
+ self initializeDefaultCommands
+ "
+!
+
+installInLauncher
+ "add myself to the launcher menu and toolBar"
+
+ |menuItem icon action|
+
+ FileBrowserV2 isNil ifTrue:[^ self].
+
+ action := [FileBrowserV2 open].
+
+ icon := self defaultIcon magnifiedTo:28@28.
+
+ menuItem := MenuItem new
+ label: 'FileBrowser V2';
+ value: action;
+ isButton: false;
+ labelImage: (LabelAndIcon icon:icon string:'FileBrowser V2');
+ nameKey: #fileBrowserV2;
+ activeHelpKey: #fileBrowserV2;
+ submenuChannel: #menuFileHistory;
+ showBusyCursorWhilePerforming:true.
+
+ NewLauncher addMenuItem:menuItem in:'menu.file' position:#( #before #fileBrowser) space:true.
+
+ menuItem := MenuItem new
+ label: 'FileBrowser V2';
+ value: action;
+ isButton: true;
+ labelImage: icon;
+ nameKey: #fileBrowserV2;
+ activeHelpKey: #fileBrowserV2;
+ submenuChannel: #menuFileHistory;
+ showBusyCursorWhilePerforming:true.
+
+ NewLauncher addMenuItem:menuItem in:'toolbar' position:#( #before #fileBrowser) space:false.
+
+ "
+ self installInLauncher
+ self removeFromLauncher
+ "
+!
+
+removeFromLauncher
+ "/
+ "/ remove myself from the launcher menu
+ "/
+
+ NewLauncher isNil ifTrue:[^ self].
+ NewLauncher removeUserTool:#fileBrowserV2
+
+ "
+ self removeFromLauncher
+ "
+! !
+
+!FileBrowserV2 class methodsFor:'defaults'!
+
+entryFieldEndStringForMultipleSelection
+
+ ^ ('[*]')
+! !
+
+!FileBrowserV2 class methodsFor:'help specs'!
+
+flyByHelpSpec
+ <resource: #help>
+
+ |spec|
+
+ spec := super flyByHelpSpec addPairsFrom:#(
+
+#addTerminal
+'Shell Terminal'
+
+#searchFile
+'Search a File'
+
+#directoryUp
+'Up'
+
+#directoryBack
+'Back'
+
+#copyFile
+'CopyFile'
+
+#cutFile
+'CutFile'
+
+#fileHome
+'Home'
+
+#pasteFile
+'PasteFile'
+
+#deleteFile
+'DeleteFile'
+
+#fileIn
+'FileIn'
+
+#directoryForward
+'Forward'
+
+#directoryHistory
+'Directory'
+
+#fileHistory
+'History'
+
+#hideToolBar
+'Hide Toolbar'
+
+#hideFilenameEntryField
+'Hide Filename Field'
+
+).
+
+ ^ spec.
+! !
+
+!FileBrowserV2 class methodsFor:'icon'!
+
+defaultIcon
+ "This resource specification was automatically generated
+ by the ImageEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the ImageEditor may not be able to read the specification."
+
+ "
+ self defaultIcon inspect
+ ImageEditor openOnClass:self andSelector:#defaultIcon
+ "
+
+ <resource: #image>
+
+ ^Icon
+ constantNamed:#'FileBrowserV2 class defaultIcon'
+ ifAbsentPut:[(Depth4Image new) width: 28; height: 28; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@@@@@@@@@@CLA&Y&Y&Y&X@@ADP@@@L0F@@@@@@A @ADAD@@@3@XN;.;.8F@ADPDQ@@CLA ;.@@@@@@D@@@D@@L0FC.8O[6=/@QDADP@@3@X@;
+[6=/[0DPDP@@CLA DNC6<@@F<ADP@@@L0F@A@F= [0= @@@@@@3@X@@P=/[6=/@@@@@@CLA @@A/[6=/X@@@@@@L0FC0@O[6=/[0@@@@@@3@XF<@@@@@@@@@
+@@@@CLA = @@@@@@@@@@@@@L0FA/[6=/A @@@@@@@@3@XO[6=/XF@@@@@@@@CLA @@@@@@X@@@@@@@@L0FY&Y&Y&Y @@@@@@@@C@Y&Y&Y&Y&@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@N@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@C @b') ; colorMapFromArray:#[0 0 0 255 255 255 255 0 0 0 255 0 0 0 255 0 255 255 255 255 0 255 0 255 127 0 0 0 127 0 0 0 127 0 127 127 127 127 0 127 0 127 127 127 127 170 170 170]; mask:((Depth1Image new) width: 28; height: 28; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+O??# C??9<@??>? O???<C????@????0O???8C???<@???>@O??<@C???@@???0@O??<@C??8@@??>@@O?? @C??8@@??>@@G?? @@??8@@@@@@@G.P=0AAD
+HP@PQBD@GDP8 AADHD@PQBA@DN^=0@@a') ; yourself); yourself]
+!
+
+hideFilenameEntryFieldIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary hideToolbarIconH14
+!
+
+hideToolBarIcon
+ <resource: #programImage>
+
+ ^ ToolbarIconLibrary hideToolbarIconH26
+! !
+
+!FileBrowserV2 class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:FileBrowserV2 andSelector:#windowSpec
+ FileBrowserV2 new openInterface:#windowSpec
+ FileBrowserV2 open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: #FileBrowser
+ #name: #FileBrowser
+ #min: #(#Point 10 10)
+ #max: #(#Point 1152 864)
+ #bounds: #(#Rectangle 16 42 816 642)
+ #menu: #mainMenu
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#ViewSpec
+ #name: 'ToolbarBox'
+ #layout: #(#LayoutFrame 0 0 0 0 0 1 30 0)
+ #level: 0
+ #visibilityChannel: #toolBarVisibleHolder
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#ActionButtonSpec
+ #label: 'hideToolBarIcon'
+ #name: 'HideToolBarButton'
+ #layout: #(#LayoutFrame 0 0 0 0 13 0 30 0)
+ #activeHelpKey: #hideToolBar
+ #hasCharacterOrientedLabel: false
+ #translateLabel: true
+ #model: #hideToolbar
+ #postBuildCallback: #hideToolBarButtonCreated:
+ )
+ #(#MenuPanelSpec
+ #name: 'ToolBar'
+ #layout: #(#LayoutFrame 13 0 0 0 0 1 30 0)
+ #menu: #toolBarMainMenu
+ #textDefault: true
+ )
+ )
+
+ )
+ )
+ #(#ViewSpec
+ #name: 'FilenameEntryFieldBox'
+ #layout: #(#LayoutFrame 0 0 30 0 0 1 55 0)
+ #level: 0
+ #visibilityChannel: #filenameEntryFieldVisibleHolder
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#ActionButtonSpec
+ #label: 'hideFilenameEntryFieldIcon'
+ #name: 'HideFilenameEntryFieldButton'
+ #layout: #(#LayoutFrame 0 0 0 0 13 0 0 1)
+ #activeHelpKey: #hideFilenameEntryField
+ #hasCharacterOrientedLabel: false
+ #translateLabel: true
+ #model: #hideFilenameEntryField
+ #postBuildCallback: #hideFilenameEntryFieldButtonCreated:
+ )
+ #(#ViewSpec
+ #name: 'Box1'
+ #layout: #(#LayoutFrame 13 0.0 0 0.0 0 1.0 0 1.0)
+ #level: 1
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#VariableHorizontalPanelSpec
+ #name: 'VariableHorizontalPanel1'
+ #layout: #(#LayoutFrame 1 0.0 1 0.0 -1 1.0 -1 1.0)
+ #level: 0
+ #showHandle: true
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#FilenameInputFieldSpec
+ #name: 'FilenameEntryField'
+ #level: 1
+ #model: #fileEntryFieldHolder
+ #acceptOnPointerLeave: false
+ #postBuildCallback: #postBuildPathField:
+ )
+ #(#ViewSpec
+ #name: 'FilterBox'
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#LabelSpec
+ #label: 'Filter:'
+ #name: 'Filter'
+ #layout: #(#LayoutFrame 0 0 0 0 40 0 0 1)
+ #translateLabel: true
+ #adjust: #left
+ #postBuildCallback: #postBuildPathViewBox:
+ )
+ #(#ComboBoxSpec
+ #name: 'FilterSelectionBox'
+ #layout: #(#LayoutFrame 40 0 0 0 0 1 0 1)
+ #model: #filterModel
+ #immediateAccept: true
+ #acceptOnPointerLeave: false
+ #comboList: #filterListModel
+ )
+ )
+
+ )
+ #postBuildCallback: #postBuildPathViewBox:
+ )
+ )
+
+ )
+ #handles: #(#Any 0.8 1.0)
+ #postBuildCallback: #postBuildPathViewBox:
+ )
+ )
+
+ )
+ #postBuildCallback: #postBuildPathViewBox:
+ )
+ )
+
+ )
+ )
+ #(#ViewSpec
+ #name: 'BrowserBox'
+ #layout: #(#LayoutFrame 0 0.0 55 0 0 1.0 -20 1)
+ #level: 0
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#'FileBrowserV2UISpecifications::PanelSpec'
+ #name: 'VerticalPanel'
+ #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+ #level: 0
+ #whichView: #last
+ #orientation: #vertical
+ #visibility: #viewNoteBookApplicationHolder
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#'FileBrowserV2UISpecifications::PanelSpec'
+ #name: 'HorizontalPanel'
+ #level: 0
+ #whichView: #first
+ #orientation: #horizontal
+ #visibility: #showDirectoryTreeHolder
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#SubCanvasSpec
+ #name: 'DirectoryTreeBrowser'
+ #hasHorizontalScrollBar: false
+ #hasVerticalScrollBar: false
+ #majorKey: #DirectoryTreeBrowser
+ #createNewApplication: true
+ #createNewBuilder: true
+ )
+ #(#SubCanvasSpec
+ #name: 'DirectoryContentsBrowser'
+ #hasHorizontalScrollBar: false
+ #hasVerticalScrollBar: false
+ #majorKey: #DirectoryContentsBrowser
+ #createNewApplication: true
+ #createNewBuilder: true
+ )
+ )
+
+ )
+ #handles: #(#Any 0.229621 1.0)
+ )
+ #(#SubCanvasSpec
+ #name: 'FileApplicationNoteBook'
+ #hasHorizontalScrollBar: false
+ #hasVerticalScrollBar: false
+ #majorKey: #FileApplicationNoteBook
+ #createNewApplication: true
+ #createNewBuilder: true
+ )
+ )
+
+ )
+ #handles: #(#Any 0.5 1.0)
+ )
+ )
+
+ )
+ )
+ #(#ViewSpec
+ #name: 'Box2'
+ #layout: #(#LayoutFrame 0 0 -20 1 0 1 0 1)
+ #level: 0
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#LabelSpec
+ #label: 'NotifyLabel'
+ #name: 'NotifyLabel'
+ #layout: #(#LayoutFrame 1 0.0 1 0.0 1 1.0 1 1.0)
+ #level: -1
+ #translateLabel: true
+ #labelChannel: #notifyChannel
+ #adjust: #left
+ )
+ )
+
+ )
+ )
+ )
+
+ )
+ )
+! !
+
+!FileBrowserV2 class methodsFor:'menu specs'!
+
+browserMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileBrowserV2 andSelector:#browserMenu
+ (Menu new fromLiteralArrayEncoding:(FileBrowserV2 browserMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Spawn'
+ #translateLabel: true
+ #value: #doSpawn
+ )
+ #(#MenuItem
+ #label: 'Save Settings'
+ #translateLabel: true
+ #value: #saveSettingsAspectValues
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Search File'
+ #translateLabel: true
+ #value: #doOpenSearchFile
+ )
+ #(#MenuItem
+ #label: 'Terminal View'
+ #translateLabel: true
+ #value: #doAddTerminal
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Exit'
+ #translateLabel: true
+ #value: #closeRequest
+ )
+ )
+ nil
+ nil
+ )
+!
+
+mainMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileBrowserV2 andSelector:#mainMenu
+ (Menu new fromLiteralArrayEncoding:(FileBrowserV2 mainMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Browser'
+ #translateLabel: true
+ #submenuChannel: #browserMenu
+ )
+ #(#MenuItem
+ #label: 'Directory'
+ #translateLabel: true
+ #submenuChannel: #directoryMenu
+ )
+ #(#MenuItem
+ #label: 'File'
+ #translateLabel: true
+ #submenuChannel: #fileMenu
+ )
+ #(#MenuItem
+ #label: 'Edit'
+ #translateLabel: true
+ #submenuChannel: #editMenu
+ )
+ #(#MenuItem
+ #label: 'View'
+ #translateLabel: true
+ #submenu:
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'View File List'
+ #translateLabel: true
+ #submenuChannel: #viewFileBrowserMenu
+ )
+ #(#MenuItem
+ #label: 'Sort File List'
+ #translateLabel: true
+ #submenuChannel: #sortMenu
+ )
+ #(#MenuItem
+ #label: 'View Tree View'
+ #translateLabel: true
+ #indication: #showDirectoryTreeHolder
+ )
+ #(#MenuItem
+ #label: 'View Directory Description'
+ #translateLabel: true
+ #indication: #viewDirectoryDescription
+ )
+ #(#MenuItem
+ #label: 'View Files in Tree View'
+ #translateLabel: true
+ #indication: #viewFilesInDirectoryTree
+ )
+ #(#MenuItem
+ #label: 'View Directories in Contents View'
+ #translateLabel: true
+ #indication: #viewDirectoriesInDirectoryContentsBrowser
+ )
+ #(#MenuItem
+ #label: 'View Notebook Applications'
+ #translateLabel: true
+ #enabled: #enableViewNoteBookApplication
+ #indication: #viewNoteBookApplicationHolder
+ )
+ #(#MenuItem
+ #label: 'Open Multiple Applications'
+ #translateLabel: true
+ #indication: #openMultipleApplicationsForType
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Toolbar'
+ #translateLabel: true
+ #hideMenuOnActivated: false
+ #indication: #toolBarVisibleHolder
+ )
+ #(#MenuItem
+ #label: 'Pathname '
+ #translateLabel: true
+ #hideMenuOnActivated: false
+ #indication: #filenameEntryFieldVisibleHolder
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Update'
+ #translateLabel: true
+ )
+ )
+ nil
+ nil
+ )
+ )
+ #(#MenuItem
+ #label: 'Tools'
+ #translateLabel: true
+ #submenuChannel: #toolsMenuSpec
+ )
+ #(#MenuItem
+ #label: 'CVS'
+ #translateLabel: true
+ #submenu:
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Update selected Files/Directories'
+ #translateLabel: true
+ #value: #cvsUpdateSelection
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Update Directory Local'
+ #translateLabel: true
+ #value: #cvsUpdateAll
+ )
+ #(#MenuItem
+ #label: 'Update Directory Recursive'
+ #translateLabel: true
+ #value: #cvsUpdateAllRecursive
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Commit...'
+ #translateLabel: true
+ #value: #cvsCommit
+ )
+ #(#MenuItem
+ #label: 'Add && Commit...'
+ #translateLabel: true
+ #value: #cvsAddAndCommit
+ #enabled: #canCvsAddAndCommit
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Remove File && CVS Container...'
+ #translateLabel: true
+ #value: #cvsRemoveFileAndCVSContainer
+ #enabled: #canRemoveCVSContainer
+ )
+ )
+ nil
+ nil
+ )
+ )
+ #(#MenuItem
+ #label: 'Help'
+ #translateLabel: true
+ #startGroup: #right
+ #submenu:
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'FileBrowser Documentation'
+ #translateLabel: true
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'About FileBrowser...'
+ #translateLabel: true
+ )
+ )
+ nil
+ nil
+ )
+ )
+ )
+ nil
+ nil
+ )
+!
+
+toolBarMainMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileBrowserV2 andSelector:#toolBarMainMenu
+ (Menu new fromLiteralArrayEncoding:(FileBrowserV2 toolBarMainMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'DirectoryUp'
+ #translateLabel: true
+ #isButton: true
+ #value: #doGoDirectoryUp
+ #activeHelpKey: #directoryUp
+ #enabled: #enableDirectoryUp
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #upArrow20x20Icon)
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'Back'
+ #translateLabel: true
+ #isButton: true
+ #value: #doBack
+ #activeHelpKey: #directoryBack
+ #enabled: #enableBack
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #leftArrow20x20PlusMenuIcon)
+ #submenuChannel: #menuDirHistoryBack
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'Forward'
+ #translateLabel: true
+ #isButton: true
+ #value: #doForward
+ #activeHelpKey: #directoryForward
+ #enabled: #enableForward
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #rightArrowPlusMenu20x20Icon)
+ #submenuChannel: #menuFileHistory
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'Home'
+ #translateLabel: true
+ #isButton: true
+ #value: #doGotoHomeDirectory
+ #activeHelpKey: #fileHome
+ #enabled: #enableHome
+ #labelImage: #(#ResourceRetriever nil #goHomeIcon)
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'File History'
+ #translateLabel: true
+ #isButton: true
+ #activeHelpKey: #fileHistory
+ #enabled: #enableFileHistory
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #history20x20Icon)
+ #submenuChannel: #menuFileHistory
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'Copy'
+ #translateLabel: true
+ #isButton: true
+ #value: #copyInDirContentsBrowser
+ #activeHelpKey: #copyFile
+ #enabled: #hasSelection
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #copy20x20Icon)
+ )
+ #(#MenuItem
+ #label: 'Cut'
+ #translateLabel: true
+ #isButton: true
+ #value: #cutInDirContentsBrowser
+ #activeHelpKey: #cutFile
+ #enabled: #hasSelection
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #cut20x20Icon2)
+ )
+ #(#MenuItem
+ #label: 'Paste'
+ #translateLabel: true
+ #isButton: true
+ #value: #pasteFiles
+ #activeHelpKey: #pasteFile
+ #enabled: #canPaste
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #paste20x20Icon)
+ )
+ #(#MenuItem
+ #label: 'Delete'
+ #translateLabel: true
+ #isButton: true
+ #value: #deleteInDirContentsBrowser
+ #activeHelpKey: #deleteFile
+ #enabled: #hasSelection
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #erase20x20Icon)
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'File In'
+ #translateLabel: true
+ #isButton: true
+ #value: #fileFileIn
+ #activeHelpKey: #fileIn
+ #enabled: #hasSelection
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #fileIn20x20Icon3)
+ )
+ #(#MenuItem
+ #label: ''
+ )
+ #(#MenuItem
+ #label: 'Search File'
+ #translateLabel: true
+ #isButton: true
+ #value: #doOpenSearchFile
+ #activeHelpKey: #searchFile
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #search20x20Icon)
+ )
+ #(#MenuItem
+ #label: 'VT100'
+ #translateLabel: true
+ #isButton: true
+ #value: #doAddTerminal
+ #activeHelpKey: #addTerminal
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #shell20x20WithoutTextIcon)
+ )
+ )
+ nil
+ nil
+ )
+!
+
+toolsMenuSpec
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileBrowserV2 andSelector:#toolsMenuSpec
+ (Menu new fromLiteralArrayEncoding:(FileBrowserV2 toolsMenuSpec)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Execute Command...'
+ #translateLabel: true
+ #value: #doExecuteCommand
+ )
+ #(#MenuItem
+ #label: 'Shell Terminal'
+ #translateLabel: true
+ #isVisible: #canDoTerminalAndSystemIsUnix
+ #value: #openTerminal
+ #enabled: #canDoTerminal
+ )
+ #(#MenuItem
+ #label: 'DOS Terminal'
+ #translateLabel: true
+ #isVisible: #canDoTerminalAndSystemIsDOS
+ #value: #openTerminal
+ #enabled: #canDoTerminal
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Changes Browser'
+ #translateLabel: true
+ #value: #openChangesBrowser
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Snapshot Image Browser'
+ #translateLabel: true
+ #value: #openSnapshotImageBrowser
+ #enabled: #hasSnapshotSelection
+ )
+ #(#MenuItem
+ #label: 'Create Smalltalk Project'
+ #translateLabel: true
+ #value: #createProjectAndOpenProjectBrowser
+ #enabled: #canCreateNewProject
+ )
+ #(#MenuItem
+ #label: 'Install Autoloaded'
+ #translateLabel: true
+ #value: #readAbbrevFile
+ #enabled: #canReadAbbrevFile
+ )
+ #(#MenuItem
+ #label: 'Install all as Autoloaded'
+ #translateLabel: true
+ #value: #installAllAsAutoloaded
+ #enabled: #anySTFilesPresent
+ )
+ #(#MenuItem
+ #label: 'Editor'
+ #translateLabel: true
+ #value: #openEditor
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'HTML Reader'
+ #translateLabel: true
+ #value: #openHTMLReader
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'ASN1 Browser'
+ #translateLabel: true
+ #isVisible: #hasASN1
+ #value: #openASN1Browser
+ #enabled: #hasASN1AndSelection
+ )
+ #(#MenuItem
+ #label: 'C Browser'
+ #translateLabel: true
+ #isVisible: #hasCBrowser
+ #value: #openCBrowser
+ #enabled: #hasCBrowser
+ )
+ #(#MenuItem
+ #label: 'Applet Viewer'
+ #translateLabel: true
+ #isVisible: #hasJava
+ #value: #openAppletViewer
+ #enabled: #hasJavaAndSelection
+ )
+ #(#MenuItem
+ #label: 'Image Inspector'
+ #translateLabel: true
+ #value: #openImageInspector
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Image Preview'
+ #translateLabel: true
+ #value: #openImagePreview
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Image Editor'
+ #translateLabel: true
+ #value: #openImageEditor
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'MP3 Player'
+ #translateLabel: true
+ #isVisible: #hasMP3Player
+ #value: #openMP3Player
+ #enabled: #hasMP3PlayerAndSelection
+ )
+ #(#MenuItem
+ #label: 'ZipFile Tool'
+ #translateLabel: true
+ #value: #openZipTool
+ #enabled: #hasZipFileSelected
+ )
+ #(#MenuItem
+ #label: 'Slide Show'
+ #translateLabel: true
+ #isVisible: #hasSlideShow
+ #value: #openSlideShow
+ #enabled: #currentFilesAreInSameDirectory
+ )
+ #(#MenuItem
+ #label: 'File Differences...'
+ #translateLabel: true
+ #value: #openDiffView
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Find Duplicate Files'
+ #translateLabel: true
+ #value: #fileFindDuplicates
+ )
+ #(#MenuItem
+ #label: 'Find All Duplicate Files (Recursive)'
+ #translateLabel: true
+ #value: #fileFindAllDuplicates
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Find a File...'
+ #translateLabel: true
+ #value: #fileFindFile
+ )
+ #(#MenuItem
+ #label: 'Hex Dump'
+ #translateLabel: true
+ #value: #fileHexDump
+ #enabled: #hasSelection
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileBrowserV2 methodsFor:'actions'!
+
+changeFileBrowserTitleTo:aString
+
+ |string|
+
+ string := 'FileBrowser ', aString.
+ self window label:string.
+!
+
+doSpawn
+
+ self saveRuntimeAspectValues.
+ self class openWithAspects:aspects withExtent:self builder window extent.
+!
+
+hideFilenameEntryField
+ self filenameEntryFieldVisibleHolder value:false.
+!
+
+hideToolbar
+ self toolBarVisibleHolder value:false.
+! !
+
+!FileBrowserV2 methodsFor:'aspects'!
+
+fileEntryFieldHolder
+
+ fileEntryFieldHolder isNil ifTrue:[
+ fileEntryFieldHolder := ValueHolder new.
+ fileEntryFieldHolder addDependent:self.
+ ].
+ ^ fileEntryFieldHolder.
+! !
+
+!FileBrowserV2 methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+
+
+ changedObject == self fileEntryFieldHolder ifTrue:[
+ (fileEntryFieldHolder value asFilename exists) ifFalse:[^ self].
+ self currentFileNameHolder value:(OrderedCollection with:(fileEntryFieldHolder value asFilename)) withoutNotifying:self.
+ ].
+ changedObject == self currentFileNameHolder ifTrue:[
+ | files newDir|
+ files := self currentFileNameHolder value.
+
+ (files isEmpty) ifTrue:[
+ self fileEntryFieldHolder value:nil withoutNotifying:self.
+ self hasSelection value:false.
+ ] ifFalse:[
+ self hasSelection value:true.
+ files size == 1 ifTrue:[
+ self fileEntryFieldHolder value:(files first) withoutNotifying:self.
+ ] ifFalse:[
+ self fileEntryFieldHolder value:self getBestFile withoutNotifying:self.
+ ].
+ ].
+ " do not return here because the AbstractFileBrowserComponent have to do something
+ for every application "
+"/ ^ self.
+ ].
+ (changedObject == self toolBarVisibleHolder
+ or:[changedObject == self filenameEntryFieldVisibleHolder]) ifTrue:[
+ self updateToolVisibility.
+ ^ self.
+ ].
+
+ ^ super update:something with:aParameter from:changedObject.
+!
+
+updateToolVisibility
+ |builder toolBar filenameEntryField vPanel topOffset visible d|
+
+ builder := self builder.
+
+ topOffset := 0.
+ visible := self toolBarVisibleHolder value.
+ visible ifTrue:[
+ toolBar := builder componentAt:#ToolbarBox.
+ topOffset := topOffset + toolBar height.
+ ].
+
+ visible := self filenameEntryFieldVisibleHolder value.
+ visible ifTrue:[
+ filenameEntryField := builder componentAt:#FilenameEntryFieldBox.
+ d := filenameEntryField layout bottomOffset - filenameEntryField layout topOffset.
+ filenameEntryField layout topOffset:topOffset bottomOffset:topOffset + d.
+ topOffset := topOffset + filenameEntryField height.
+ filenameEntryField container notNil ifTrue:[
+ filenameEntryField containerChangedSize.
+ ].
+ ].
+
+ vPanel := builder componentAt:#BrowserBox.
+ vPanel layout topOffset:topOffset+1.
+ vPanel container notNil ifTrue:[
+ vPanel containerChangedSize.
+ ].
+! !
+
+!FileBrowserV2 methodsFor:'menu'!
+
+canBack
+
+ ^ self dirHistory canBack.
+!
+
+canForward
+
+ ^ self dirHistory canForward.
+!
+
+menuFileHistory
+ "initialize the file history menu
+ "
+ <resource: #programMenu >
+
+ |menu hist text removeItem removeCol|
+
+ menu := Menu new.
+ menu receiver:self.
+
+ hist := self fileHistory.
+ hist isEmpty ifTrue:[^ nil].
+ text := LabelAndIcon icon:(self class clearHistoryIcon) string:'Clear File History'.
+ removeCol := OrderedCollection new.
+ hist do:[:aFileItem|
+ aFileItem fileName exists ifTrue:[
+ menu addItem:(MenuItem label: aFileItem fileName asString value:[
+ self currentFileNameHolder value:(OrderedCollection with:(aFileItem fileName)).
+ self openApplByFileItem:aFileItem
+ ]).
+ ] ifFalse:[
+ removeCol add:aFileItem.
+ ]
+ ].
+ "/ remove all not existing history entries
+ removeCol do:[ : el |
+ hist remove:el.
+ ].
+ removeItem := MenuItem label:text value:[
+ self fileHistory removeAll.
+ self enableFileHistory value:false.
+ ].
+ menu addItem:(MenuItem label:'-').
+ menu addItem:removeItem.
+ ^ menu
+! !
+
+!FileBrowserV2 methodsFor:'startup & release'!
+
+hideFilenameEntryFieldButtonCreated:aButton
+
+ aButton passiveLevel:(MenuPanel defaultLevel).
+ aButton activeLevel:-1.
+ aButton backgroundColor:(MenuPanel defaultBackgroundColor).
+!
+
+hideToolBarButtonCreated:aButton
+
+ aButton passiveLevel:(MenuPanel defaultLevel).
+ aButton activeLevel:-1.
+ aButton backgroundColor:(MenuPanel defaultBackgroundColor).
+!
+
+initialize
+
+ self masterApplication:nil.
+!
+
+makeDependent
+
+ self currentFileNameHolder addDependent:self.
+ self notifyChannel addDependent:self.
+ self viewNoteBookApplicationHolder addDependent:self.
+ self filenameEntryFieldVisibleHolder addDependent:self.
+ self toolBarVisibleHolder addDependent:self.
+!
+
+postBuildPathField:aWidget
+ "
+ set the pramters that not can be changed in the window spec
+ "
+
+ |sClr lClr|
+
+ aWidget level:-1.
+
+"/ sClr := aWidget shadowColor.
+"/ lClr := aWidget lightColor.
+"/ sClr := (self builder componentAt:#ToolBar) shadowColor.
+"/ lClr := (self builder componentAt:#ToolBar) lightColor.
+
+"/ aWidget backgroundColor:(aWidget superView viewBackground).
+"/ aWidget shadowColor:sClr.
+!
+
+postBuildPathViewBox:aWidget
+
+ aWidget backgroundColor:(MenuPanel defaultBackgroundColor).
+!
+
+postBuildWith:aBuilder
+
+ super postBuildWith:aBuilder.
+ self updateToolVisibility
+!
+
+postOpenWith:aBuilder
+
+ self currentFileNameHolder changed.
+ self showDirectoryTreeHolder changed.
+ self viewNoteBookApplicationHolder changed.
+ ^ super postOpenWith:aBuilder
+!
+
+release
+
+ self saveRuntimeAspectValues.
+ ^ super release
+! !
+
+!FileBrowserV2 class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/FileBrowserV2.st,v 1.1 2002-09-25 07:59:46 penk Exp $'
+! !
+
+FileBrowserV2 initialize!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FileBrowserV2PanelView.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,194 @@
+"
+ COPYRIGHT (c) 2002 by eXept Software AG
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+
+
+"
+
+"{ Package: 'stx:libtool' }"
+
+VariablePanel subclass:#FileBrowserV2PanelView
+ instanceVariableNames:'whichView visibilityHolder oldOrigin oldCorner'
+ classVariableNames:'BarHeight'
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+!FileBrowserV2PanelView class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 2002 by eXept Software AG
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+
+
+"
+!
+
+documentation
+
+"
+ copy of the Panel from CBrowser , if a better HorizontalPanel and VerticalPanel is available
+ the new version can be used here
+"
+! !
+
+!FileBrowserV2PanelView methodsFor:'accessing'!
+
+visible:aState
+ |view1 view2 state|
+
+ state := aState ? true.
+
+ (state == self isVisible or:[subViews size ~~ 2]) ifTrue:[
+ ^ self
+ ].
+
+ view1 := subViews at:1.
+ view2 := subViews at:2.
+
+ state ifTrue:[
+ "
+ MAKE VISIBLE
+ "
+ barHeight := BarHeight.
+ view1 origin:0.0@0.0 corner:oldCorner.
+ view2 origin:oldOrigin corner:1.0@1.0.
+ self resizeSubviews.
+ ] ifFalse:[
+ "
+ MAKE INVISIBLE
+ "
+ BarHeight := barHeight.
+ barHeight := 0.
+ oldCorner := view1 relativeCorner.
+ oldOrigin := view2 relativeOrigin.
+
+ orientation == #vertical ifTrue:[
+ whichView == #first ifTrue:[
+ view1 origin:0.0@0.0 corner:1.0@0.0.
+ view2 origin:0.0@0.0 corner:(view2 corner).
+ ] ifFalse:[
+ view1 origin:0.0@0.0 corner:1.0@1.0.
+ view2 origin:0.0@1.0 corner:(view2 corner).
+ ].
+ ] ifFalse:[
+ whichView == #first ifTrue:[
+ view1 origin:0.0@0.0 corner:0.0@1.0.
+ view2 origin:0.0@0.0 corner:1.0@1.0.
+ ] ifFalse:[
+ view1 origin:0.0@0.0 corner:1.0@1.0.
+ view2 origin:1.0@0.0 corner:1.0@1.0.
+ ]
+ ]
+ ].
+ visibilityHolder notNil ifTrue:[visibilityHolder value:state]
+!
+
+whichView
+ "return the value of the instance variable 'whichView' (automatically generated)"
+
+ ^ whichView
+!
+
+whichView:something
+ "set the value of the instance variable 'whichView' (automatically generated)"
+
+ whichView := something.
+! !
+
+!FileBrowserV2PanelView methodsFor:'accessing mvc'!
+
+visibilityHolder
+ ^ visibilityHolder
+!
+
+visibilityHolder:aHolder
+ visibilityHolder removeDependent:self.
+
+ (visibilityHolder := aHolder) notNil ifTrue:[
+ visibilityHolder addDependent:self.
+
+ realized ifTrue:[
+ self visible:(visibilityHolder value)
+ ]
+ ]
+! !
+
+!FileBrowserV2PanelView methodsFor:'actions'!
+
+toggleVisibility
+
+ self visible:(self isVisible not)
+! !
+
+!FileBrowserV2PanelView methodsFor:'change & update'!
+
+update:what with:aPara from:chgObj
+
+ chgObj == visibilityHolder ifTrue:[
+ ^ self visible:(chgObj value)
+ ].
+ ^ super update:what with:aPara from:chgObj
+
+! !
+
+!FileBrowserV2PanelView methodsFor:'initialization'!
+
+destroy
+ visibilityHolder removeDependent:self.
+ super destroy
+!
+
+initialize
+ orientation := #vertical.
+ whichView := #first.
+
+ super initialize
+!
+
+realize
+ super realize.
+
+ visibilityHolder notNil ifTrue:[
+ self visible:(visibilityHolder value)
+ ]
+! !
+
+!FileBrowserV2PanelView methodsFor:'queries'!
+
+anyNonRelativeSubviews
+ "return true, if any of my subviews has no relative origin/extent"
+
+ "/ cg asking ca: "whats the reason for this ?"
+ "/ ^ subViews notNil
+ ^ super anyNonRelativeSubviews.
+!
+
+isVisible
+ ^ barHeight ~~ 0
+!
+
+specClass
+ ^ FileBrowserV2UISpecifications panelSpecClass
+! !
+
+!FileBrowserV2PanelView class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/FileBrowserV2PanelView.st,v 1.1 2002-09-25 07:58:30 penk Exp $'
+! !
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FileBrowserV2Tests.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,116 @@
+"{ Package: 'stx:libtool' }"
+
+TestCase subclass:#FileBrowserV2Tests
+ instanceVariableNames:''
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+!FileBrowserV2Tests class methodsFor:'documentation'!
+
+documentation
+"
+ documentation to be added.
+
+ [author:]
+ Christian Penk (penk@bierfix)
+
+ [instance variables:]
+
+ [class variables:]
+
+ [see also:]
+
+"
+!
+
+history
+ "Created: / 31.7.2002 / 11:59:23 / penk"
+! !
+
+!FileBrowserV2Tests methodsFor:'initialize / release'!
+
+setUp
+ "common setup - invoked before testing"
+
+ super setUp
+!
+
+tearDown
+ "common cleanup - invoked after testing"
+
+ super tearDown
+! !
+
+!FileBrowserV2Tests methodsFor:'tests'!
+
+testFileItem
+ "Just a demonstration testCase.
+ Double click on the TestCase class or open a TestRunner to see me checking...
+ - please add more methods like this..."
+
+ | file item|
+
+ file := Filename homeDirectory construct:'work/stx/doc/online/english/index.html'.
+ file exists ifTrue:[
+ item := DirectoryContentsBrowser itemClass with:file.
+ self should:(item mimeType = 'text/html').
+ ].
+
+ "
+ self run:#testFileItem
+ "
+!
+
+testHardLink
+ "Just a demonstration testCase.
+ Double click on the TestCase class or open a TestRunner to see me checking...
+ - please add more methods like this..."
+
+ |browser|
+
+ browser := FileBrowserV2 new.
+
+ self should: ( browser isKindOf:AbstractFileBrowser ).
+ self should: ( browser respondsTo:#newHardLink ).
+
+"/ self should: [ o at:0 ] raise:Error.
+
+ "
+ self run:#testHardLink
+ "
+!
+
+testHistory
+ "Just a demonstration testCase.
+ Double click on the TestCase class or open a TestRunner to see me checking...
+ - please add more methods like this..."
+
+ |history item1 item2 item3|
+
+ history := AbstractFileBrowser filenameHistoryClass new.
+ item1 := DirectoryContentsBrowser itemClass with:(Filename homeDirectory construct:'.bashrc').
+ item2 := DirectoryContentsBrowser itemClass with:(Filename homeDirectory construct:'home').
+ item3 := DirectoryContentsBrowser itemClass with:(Filename homeDirectory construct:'.bashrc').
+
+ self should: (item1 = item3).
+ history add:item1.
+ self assert: ( history size == 1 ).
+ history add:item2.
+ self assert: ( history size == 2 ).
+ history add:item3.
+ self assert: ( history size == 2 ).
+
+"/ self should: [ o at:0 ] raise:Error.
+
+ "
+ self run:#testHistory
+ "
+! !
+
+!FileBrowserV2Tests class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/FileBrowserV2Tests.st,v 1.1 2002-09-25 07:58:41 penk Exp $'
+! !
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FileBrowserV2UISpecifications.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,551 @@
+"
+ COPYRIGHT (c) 2002 by eXept Software AG
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+
+
+"
+
+"{ Package: 'stx:libtool' }"
+
+Object subclass:#FileBrowserV2UISpecifications
+ instanceVariableNames:''
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+VariablePanelSpec subclass:#PanelSpec
+ instanceVariableNames:'whichView orientation visibility'
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:FileBrowserV2UISpecifications
+!
+
+!FileBrowserV2UISpecifications class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 2002 by eXept Software AG
+ All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice. This software may not
+ be provided or otherwise made available to, or used by, any
+ other person. No title to or ownership of the software is
+ hereby transferred.
+
+
+"
+!
+
+documentation
+"
+ copy of the Panel from CBrowser , if a better HorizontalPanel and VerticalPanel is available
+ the new version can be used here
+"
+! !
+
+!FileBrowserV2UISpecifications class methodsFor:'classAccess'!
+
+panelSpecClass
+
+ ^ PanelSpec
+! !
+
+!FileBrowserV2UISpecifications class methodsFor:'interface specs'!
+
+listSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:FileBrowserV2UISpecifications andSelector:#listSpec
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #listSpec
+ #window:
+ #(#WindowSpec
+ #label: 'Graphs'
+ #name: 'Graphs'
+ #layout: #(#LayoutFrame 7 0 129 0 441 0 316 0)
+ #level: 0
+ #min: #(#Point 10 10)
+ #max: #(#Point 1280 1024)
+ #bounds: #(#Rectangle 7 129 442 317)
+ #usePreferredExtent: false
+ #returnIsOKInDialog: true
+ #escapeIsCancelInDialog: true
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#HierarchicalListViewSpec
+ #name: 'HierarchicalListModel'
+ #layout: #(#LayoutFrame 225 0 7 0 398 0 79 0)
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #miniScrollerHorizontal: true
+ #highlightMode: #line
+ )
+ #(#LabelSpec
+ #label: 'HierarchicalList'
+ #name: 'HierarchicalListLabel'
+ #layout: #(#Point 252 15)
+ #style: #(#FontDescription #helvetica #medium #roman 10)
+ #resizeForLabel: true
+ #adjust: #left
+ #canUIDrag: false
+ )
+ #(#SelectionInListModelViewSpec
+ #name: 'SelectionInListModel'
+ #layout: #(#LayoutFrame 6 0 7 0 179 0 79 0)
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #miniScrollerHorizontal: true
+ #highlightMode: #line
+ )
+ #(#LabelSpec
+ #label: 'SelectionInList'
+ #name: 'SelectionInListLabel'
+ #layout: #(#Point 33 15)
+ #style: #(#FontDescription #helvetica #medium #roman 10)
+ #resizeForLabel: true
+ #adjust: #left
+ #canUIDrag: false
+ )
+ #(#ListModelViewSpec
+ #name: 'ListModel'
+ #layout: #(#LayoutFrame 6 0 100 0 179 0 172 0)
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #miniScrollerHorizontal: true
+ )
+ #(#LabelSpec
+ #label: 'ListModel'
+ #name: 'ListModelLabel'
+ #layout: #(#Point 33 109)
+ #style: #(#FontDescription #helvetica #medium #roman 10)
+ #resizeForLabel: true
+ #adjust: #left
+ #canUIDrag: false
+ )
+ )
+
+ )
+ )
+!
+
+othersSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:FileBrowserV2UISpecifications andSelector:#othersSpec
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #othersSpec
+ #window:
+ #(#WindowSpec
+ #label: 'Panel Specs'
+ #name: 'Panel Specs'
+ #layout: #(#LayoutFrame 119 0 66 0 536 0 215 0)
+ #level: 0
+ #min: #(#Point 10 10)
+ #max: #(#Point 1280 1024)
+ #bounds: #(#Rectangle 119 66 537 216)
+ #usePreferredExtent: false
+ #returnIsOKInDialog: true
+ #escapeIsCancelInDialog: true
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#LabelSpec
+ #label: 'Wrapper'
+ #name: 'WrapperLabel'
+ #layout: #(#Point 9 6)
+ #style: #(#FontDescription #helvetica #medium #roman 10)
+ #resizeForLabel: true
+ #adjust: #left
+ #canUIDrag: false
+ )
+ #(#'FileBrowserV2UISpecifications::WrapperSpec'
+ #name: 'Wrapper'
+ #layout: #(#LayoutFrame 6 0 26 0 179 0 98 0)
+ )
+ #(#LabelSpec
+ #label: 'Panel'
+ #name: 'PanelLabel'
+ #layout: #(#Point 201 6)
+ #style: #(#FontDescription #helvetica #medium #roman 10)
+ #resizeForLabel: true
+ #adjust: #left
+ #canUIDrag: false
+ )
+
+ #(#'FileBrowserV2UISpecifications::PanelSpec'
+ #name: 'Panel'
+ #layout: #(#LayoutFrame 198 0 26 0 376 0 98 0)
+ #level: 0
+ #whichView: #first
+ #orientation: #vertical
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#LabelSpec
+ #label: 'A'
+ #name: 'Label1'
+ #layout: #(#LayoutFrame 0 0.0 0 0.0 0 0.5 0 1.0)
+ #level: 2
+ #canUIDrag: false
+ )
+ #(#LabelSpec
+ #label: 'B'
+ #name: 'Label2'
+ #layout: #(#LayoutFrame 0 0.5 0 0.0 0 1.0 0 1.0)
+ #level: 2
+ #canUIDrag: false
+ )
+ )
+
+ )
+ )
+ )
+
+ )
+ )
+! !
+
+!FileBrowserV2UISpecifications class methodsFor:'setup'!
+
+setup
+"
+FileBrowserV2UISpecifications setup.
+
+"
+ |listSpec othersSpec|
+
+ UISelectionPanel galleryClass removeUserSpecWithLabel:'Graphs'.
+ UISelectionPanel galleryClass removeUserSpecWithLabel:'Clocks etc.'.
+ UISelectionPanel galleryClass removeUserSpecWithLabel:'Business Graphics'.
+ UISelectionPanel galleryClass removeUserSpecWithLabel:'C-Lists'.
+ UISelectionPanel galleryClass removeUserSpecWithLabel:'C-Others'.
+
+ listSpec := ValueHolder new.
+ listSpec value:(self listSpec).
+
+ UISelectionPanel galleryClass addUserSpecHolder:listSpec
+ label:'C-Lists'.
+
+ othersSpec := ValueHolder new.
+ othersSpec value:(self othersSpec).
+
+ UISelectionPanel galleryClass addUserSpecHolder:othersSpec
+ label:'C-Others'.
+! !
+
+!FileBrowserV2UISpecifications::PanelSpec class methodsFor:'interface - painter'!
+
+addBindingsTo:env for:anInstance channel:aChannel
+ "add bindings as required to allow the GUI Painter to operate on an instance of me"
+
+ super addBindingsTo:env for:anInstance channel:aChannel.
+
+ self adaptApects:#( visibility ) to:env for:anInstance channel:aChannel converter:#symbolOrNil.
+ self adaptApects:#( whichView orientation ) to:env for:anInstance channel:aChannel.
+
+ env at:#whichViewList put:#( #first #last ) asValue.
+ env at:#orientationList put:#( #horizontal #vertical ) asValue.
+
+
+
+! !
+
+!FileBrowserV2UISpecifications::PanelSpec class methodsFor:'interface - specs'!
+
+detailsEditSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:FileBrowserV2UISpecifications::PanelSpec andSelector:#detailsEditSpec
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #detailsEditSpec
+ #window:
+ #(#WindowSpec
+ #label: 'Panel Detail Spec'
+ #name: 'Panel Detail Spec'
+ #layout: #(#LayoutFrame 5 0 66 0 442 0 341 0)
+ #level: 0
+ #min: #(#Point 10 10)
+ #max: #(#Point 1160 870)
+ #bounds: #(#Rectangle 5 66 443 342)
+ #usePreferredExtent: false
+ #returnIsOKInDialog: true
+ #escapeIsCancelInDialog: true
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#UISubSpecification
+ #name: 'SubSpecification1'
+ #layout: #(#LayoutFrame 1 0 0 0.0 0 1.0 183 0)
+ #majorKey: #ViewSpec
+ #minorKey: #detailsEditSpec
+ )
+ #(#FramedBoxSpec
+ #label: 'Visibility'
+ #name: 'FramedBox1'
+ #layout: #(#LayoutFrame 0 0.0 177 0 0 1.0 261 0)
+ #labelPosition: #topLeft
+ #translateLabel: true
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#LabelSpec
+ #label: 'orientation:'
+ #name: 'orientation'
+ #layout: #(#AlignmentOrigin 85 0 13 0 1 0.5)
+ #activeHelpKey: #borderWidth
+ #resizeForLabel: true
+ #adjust: #left
+ )
+ #(#ComboListSpec
+ #name: 'orientationList'
+ #layout: #(#LayoutFrame 85 0 2 0 194 0 24 0)
+ #model: #orientation
+ #comboList: #orientationList
+ #useIndex: false
+ )
+ #(#LabelSpec
+ #label: 'which:'
+ #name: 'visibilityOf'
+ #layout: #(#AlignmentOrigin 248 0 13 0 1 0.5)
+ #activeHelpKey: #borderWidth
+ #resizeForLabel: true
+ #adjust: #left
+ )
+ #(#ComboListSpec
+ #name: 'whichViewList'
+ #layout: #(#LayoutFrame 247 0 2 0 0 1.0 24 0)
+ #model: #whichView
+ #comboList: #whichViewList
+ #useIndex: false
+ )
+ #(#InputFieldSpec
+ #name: 'visibility'
+ #layout: #(#LayoutFrame 85 0 29 0 0 1.0 51 0)
+ #activeHelpKey: #canvas
+ #model: #visibility
+ #group: #inputGroup
+ #acceptChannel: #acceptChannel
+ #modifiedChannel: #modifiedChannel
+ #acceptOnPointerLeave: false
+ )
+ #(#LabelSpec
+ #label: 'visibility:'
+ #name: 'visibilityLabel'
+ #layout: #(#AlignmentOrigin 85 0 40 0 1 0.5)
+ #resizeForLabel: true
+ )
+ )
+
+ )
+ )
+ )
+
+ )
+ )
+! !
+
+!FileBrowserV2UISpecifications::PanelSpec methodsFor:'accessing'!
+
+orientation
+ "return the value of the instance variable 'orientation' (automatically generated)"
+
+ ^ orientation ? #vertical
+!
+
+orientation:something
+ "set the value of the instance variable 'orientation' (automatically generated)"
+ something notNil ifTrue:[
+ orientation := something asSymbol
+ ] ifFalse:[
+ orientation := something.
+ ]
+!
+
+visibility
+ "return the value of the instance variable 'orientation' (automatically generated)"
+
+ ^ visibility
+!
+
+visibility:something
+ "set the value of the instance variable 'visibility' (automatically generated)"
+
+ visibility := something.
+!
+
+whichView
+ "return the value of the instance variable 'whichView' (automatically generated)"
+
+ ^ whichView ? #first
+!
+
+whichView:something
+ "set the value of the instance variable 'whichView' (automatically generated)"
+
+ whichView := something.
+! !
+
+!FileBrowserV2UISpecifications::PanelSpec methodsFor:'building'!
+
+aspectSelectors
+ "add more aspect selectors
+ "
+ |more|
+
+ more := super aspectSelectors.
+ visibility notNil ifTrue:[more add:visibility].
+ ^ more
+
+!
+
+setAttributesIn:aView with:aBuilder
+ "set my attributes to aView
+ "
+ super setAttributesIn:aView with:aBuilder.
+
+ aView whichView:(self whichView).
+ aView orientation:(self orientation).
+ aView visibilityHolder:(self getBindingIn:aBuilder binding:visibility).
+
+
+
+! !
+
+!FileBrowserV2UISpecifications::PanelSpec methodsFor:'computation'!
+
+recomputeHandlesIn:aPanel
+ |subs isVertical|
+
+ (subs := aPanel subViews) notNil ifTrue:[
+ isVertical := self isVertical.
+ ^ subs
+ collect:
+ [:v | |rel|
+ rel := v relativeCorner.
+ isVertical ifTrue:[ rel y] ifFalse:[ rel x ].
+ ]
+ ].
+ ^ nil
+!
+
+setLayoutsInLayoutContainer:aPanel
+ |x y subs isVertical|
+
+ ((subs := aPanel subViews) notNil and:[subs size == handles size]) ifTrue:[
+ isVertical := self isVertical.
+ y := x := 0.0.
+ subs keysAndValuesDo:[:i :v|
+ isVertical ifTrue:[
+ v relativeOrigin:(0.0 @ y).
+ y := handles at:i.
+ v relativeCorner:(1.0 @ y).
+ ] ifFalse:[
+ v relativeOrigin:(x @ 0.0).
+ x := handles at:i.
+ v relativeCorner:(x @ 1.0).
+ ]
+ ]
+ ]
+!
+
+setupInitialLayoutFor:aView
+ |superView|
+
+ aView geometryLayout:nil.
+
+ ( aView relativeOrigin isNil
+ or:[aView relativeExtent isNil
+ and:[aView relativeCorner isNil]]
+ ) ifTrue:[
+ superView := aView superView.
+
+ self isVertical ifTrue:[
+ aView corner:0@0.
+ aView origin:0.0@0.0.
+ aView extent:1.0@0.3.
+ superView notNil ifTrue:[
+ superView setupSubviews.
+ superView resizeSubviews.
+ ]
+ ] ifFalse:[
+ aView origin:0.0@0.0.
+ aView extent:0.3@1.0.
+ superView notNil ifTrue:[
+ superView setupSubviews
+ ]
+ ]
+ ]
+! !
+
+!FileBrowserV2UISpecifications::PanelSpec methodsFor:'converting'!
+
+skippedInLiteralEncoding
+ |l|
+
+ l := super skippedInLiteralEncoding asOrderedCollection.
+ visibility isNil ifTrue:[l add:#visibility].
+ ^ l
+! !
+
+!FileBrowserV2UISpecifications::PanelSpec methodsFor:'queries'!
+
+isVertical
+ ^ self orientation == #vertical
+
+!
+
+viewClass
+ "return the corresponding view class of the spec"
+
+ ^ FileBrowserV2PanelView
+! !
+
+!FileBrowserV2UISpecifications class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/FileBrowserV2UISpecifications.st,v 1.1 2002-09-25 07:59:55 penk Exp $'
+! !
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FileDialog.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,885 @@
+"{ Package: 'stx:libtool' }"
+
+SimpleDialog subclass:#FileDialog
+ instanceVariableNames:'aspects treeBrowser enableBack enableDirectoryUp enableForward
+ enableHome directory pattern filterHolder initialText
+ cancelLabelHolder okLabelHolder startFilename result filterField
+ filenameField viewFiles'
+ classVariableNames:'LastFileSelectionDirectory'
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+!FileDialog class methodsFor:'documentation'!
+
+documentation
+"
+ documentation to be added.
+
+ [author:]
+ Martin Walser (martin@vercingetorix)
+
+ [instance variables:]
+
+ [class variables:]
+
+ [see also:]
+
+"
+!
+
+examples
+"
+ Starting the application:
+ [exBegin]
+ FileDialog open
+
+ [exEnd]
+
+ more examples to be added:
+ [exBegin]
+ ... add code fragment for
+ ... executable example here ...
+ [exEnd]
+"
+!
+
+history
+ "Created: / 19.9.2002 / 13:05:28 / martin"
+! !
+
+!FileDialog class methodsFor:'instance creation'!
+
+requestDirectoryName:title default:aFileName ifFail:failBlock
+ "same as requestFileName, but only show directories"
+
+ ^ self requestDirectoryName:title
+ default:aFileName
+ ok:nil
+ abort:nil
+ version:nil
+ pattern:nil
+ fromDirectory:nil
+ ifFail:failBlock
+ whenBoxCreatedEvaluate:nil.
+
+ "
+ Dialog
+ requestDirectoryName:'which directory ?'
+ default:'/etc'
+ ifFail:'none'
+ "
+!
+
+requestDirectoryName:title default:aFileName ok:okText abort:abortText version:versionSymbol pattern:pattern fromDirectory:aDirectoryPath ifFail:failBlock whenBoxCreatedEvaluate:boxCreatedCallback
+ "same as requestFileName, but only show directories"
+
+ |enteredFileName instance defaultNm defaultDir enteredFileNameString defaultFile|
+
+ defaultNm := aFileName.
+ defaultDir := aDirectoryPath.
+ defaultDir isNil ifTrue:[
+ defaultNm notNil ifTrue:[
+ defaultDir := defaultNm asFilename directory.
+ ] ifFalse:[
+ defaultDir := FileSelectionBox lastFileSelectionDirectory.
+ defaultDir isNil ifTrue:[
+ defaultDir := Filename currentDirectory asAbsoluteFilename.
+ ].
+ ]
+ ].
+ defaultDir := defaultDir asFilename.
+ [defaultDir exists not] whileTrue:[
+ defaultDir := defaultDir directory.
+ ].
+ defaultNm isNil ifTrue:[
+ defaultFile := defaultDir.
+ ] ifFalse:[
+ defaultFile := defaultNm asFilename.
+ ].
+ instance := self new.
+"/ defaultDir notNil ifTrue:[instance directory:(defaultDir asFilename)].
+ defaultDir notNil ifTrue:[instance directory:defaultFile].
+ instance startFilename:defaultFile.
+ instance initialText:title.
+ instance pattern:((pattern isNil or:[pattern isEmpty]) ifTrue:['*'] ifFalse:[pattern]).
+ instance okLabelHolder value:okText.
+ instance cancelLabelHolder value:abortText.
+ instance viewFiles:false.
+
+ instance allButOpenInterface:#windowSpec.
+ boxCreatedCallback notNil ifTrue:[boxCreatedCallback value:instance].
+ instance openWindowModal.
+
+ enteredFileNameString := instance result.
+ enteredFileNameString isNil ifTrue:[
+ ^ failBlock value
+ ].
+ enteredFileName := enteredFileNameString asFilename.
+ enteredFileNameString := enteredFileName asString.
+ (enteredFileName notNil
+ and:[enteredFileNameString notEmpty]) ifTrue:[
+ versionSymbol isNil ifTrue:[ ^ enteredFileNameString].
+ versionSymbol == #mustBeNew ifTrue:[
+ "/ file may not exist
+ enteredFileName exists ifTrue:[^ ''].
+ ].
+ versionSymbol == #new ifTrue:[
+ "/ file may not exist
+ enteredFileName exists ifTrue:[
+ (Dialog confirm:(self classResources string:'''%1'' exists.\\Continue anyway ?' with:enteredFileNameString) withCRs)
+ ifFalse:[^ ''].
+ ].
+ ].
+ versionSymbol == #mustBeOld ifTrue:[
+ enteredFileName exists ifFalse:[^ ''].
+ ].
+ versionSymbol == #old ifTrue:[
+ "/ file may not exist
+ enteredFileName exists ifFalse:[
+ (self confirm:(self classResources string:'''%1'' does not exist yet.\\Continue anyway ?' with:enteredFileNameString) withCRs)
+ ifFalse:[^ ''].
+ ].
+ ].
+ FileSelectionBox lastFileSelectionDirectory:(enteredFileNameString).
+ ].
+ ^ enteredFileNameString
+
+ "
+ FileDialog
+ requestDirectoryName:'which directory ?'
+ default:'/etc'
+ ifFail:nil
+ "
+!
+
+requestFileName:titleString default:defaultName ok:okText abort:abortText pattern:pattern fromDirectory:aDirectoryPathOrNil whenBoxCreatedEvaluate:boxCreatedCallback
+
+ ^ self requestFileName:titleString
+ default:defaultName
+ ok:okText
+ abort:abortText
+ version:nil
+ ifFail:nil
+ pattern:pattern
+ fromDirectory:aDirectoryPathOrNil
+ whenBoxCreatedEvaluate:boxCreatedCallback
+!
+
+requestFileName:titleString default:defaultName ok:okText abort:abortText version:versionSymbol ifFail:failBlock pattern:pattern fromDirectory:aDirectoryPath whenBoxCreatedEvaluate:boxCreatedCallback
+ "launch a Dialog, which allows user to enter a filename.
+ The files presented initially are those in aDirectoryPathOrNil, or the
+ last fileBox directory (default: current directory) (if a nil path is given).
+ The box will show okText in its okButton, abortText in the abortButton.
+ The matchPattern is set to pattern initially.
+ Return the string, or nil if cancel was pressed
+ The version argument allows validation of the files existance;
+ it may be any of:
+ #mustBeNew - fail (return empty string) if the file exists
+ #new - confirm if the file exists
+ #mustBeOld - fail if the file does not exist
+ #old - confirm if the file does not exist
+ #any (other) - no validation
+ "
+
+
+ | defaultDir defaultNm instance enteredFileName enteredFileNameString defaultFile|
+
+ defaultNm := defaultName.
+ defaultDir := aDirectoryPath.
+ defaultDir isNil ifTrue:[
+ defaultDir := FileSelectionBox lastFileSelectionDirectory.
+ defaultDir isNil ifTrue:[
+ defaultDir := Filename currentDirectory asAbsoluteFilename.
+ ].
+ ].
+ defaultDir := defaultDir asFilename.
+ [defaultDir exists not] whileTrue:[
+ defaultDir := defaultDir directory.
+ ].
+ (defaultName notNil and:[defaultName asFilename withoutSuffix baseName ~= '*']) ifTrue:[
+ defaultFile := defaultDir construct:defaultName.
+ ] ifFalse:[
+ defaultFile := defaultDir.
+ ].
+ instance := self new.
+ defaultDir notNil ifTrue:[instance directory:(defaultDir asFilename)].
+ instance startFilename:defaultFile.
+ instance pattern:((pattern isNil or:[pattern isEmpty]) ifTrue:['*'] ifFalse:[pattern]).
+ instance initialText:titleString.
+ instance okLabelHolder value:okText.
+ instance cancelLabelHolder value:abortText.
+ instance viewFiles:true.
+
+ instance allButOpenInterface:#windowSpec.
+ boxCreatedCallback notNil ifTrue:[boxCreatedCallback value:instance].
+ instance openWindowModal.
+
+ enteredFileNameString := instance result.
+ enteredFileNameString isNil ifTrue:[
+ ^ failBlock value
+ ].
+ enteredFileName := enteredFileNameString asFilename.
+ enteredFileNameString := enteredFileName asString.
+ (enteredFileName notNil
+ and:[enteredFileNameString notEmpty]) ifTrue:[
+ versionSymbol isNil ifTrue:[ ^ enteredFileNameString].
+ versionSymbol == #mustBeNew ifTrue:[
+ "/ file may not exist
+ enteredFileName exists ifTrue:[^ ''].
+ ].
+ versionSymbol == #new ifTrue:[
+ "/ file may not exist
+ enteredFileName exists ifTrue:[
+ (Dialog confirm:(self classResources string:'''%1'' exists.\\Continue anyway ?' with:enteredFileNameString) withCRs)
+ ifFalse:[^ ''].
+ ].
+ ].
+ versionSymbol == #mustBeOld ifTrue:[
+ enteredFileName exists ifFalse:[^ ''].
+ ].
+ versionSymbol == #old ifTrue:[
+ "/ file may not exist
+ enteredFileName exists ifFalse:[
+ (self confirm:(self classResources string:'''%1'' does not exist yet.\\Continue anyway ?' with:enteredFileNameString) withCRs)
+ ifFalse:[^ ''].
+ ].
+ ].
+ FileSelectionBox lastFileSelectionDirectory:(enteredFileName directoryName).
+ ].
+ ^ enteredFileNameString
+!
+
+requestFileName:titleString default:defaultName version:versionSymbol ifFail:failBlock pattern:pattern fromDirectory:aDirectoryPathOrNil whenBoxCreatedEvaluate:boxCreatedCallback
+
+ ^ self requestFileName:titleString
+ default:defaultName
+ ok:nil
+ abort:nil
+ version:versionSymbol
+ ifFail:failBlock
+ pattern:pattern
+ fromDirectory:aDirectoryPathOrNil
+ whenBoxCreatedEvaluate:boxCreatedCallback
+
+ "
+ FileDialog
+ requestFileName:'enter a fileName:'
+ default:''
+ version:nil
+ ifFail:['none']
+ pattern:'*.conf'
+ fromDirectory:'/etc'
+ whenBoxCreatedEvaluate:nil.
+ Dialog
+ requestFileName:'enter a fileName:'
+ default:''
+ version:nil
+ ifFail:['none']
+ pattern:'*.conf'
+ fromDirectory:'/etc'
+ whenBoxCreatedEvaluate:nil
+ "
+ "
+ FileDialog
+ requestFileName:'enter a fileName:'
+ default:''
+ version:#old
+ ifFail:['none']
+ pattern:'*.conf'
+ fromDirectory:'/etc'
+ whenBoxCreatedEvaluate:nil
+ "
+ "
+ FileDialog
+ requestFileName:'enter a fileName:'
+ default:''
+ version:#mustBeNew
+ ifFail:['none']
+ pattern:'*.conf'
+ fromDirectory:'/etc'
+ whenBoxCreatedEvaluate:nil
+ "
+! !
+
+!FileDialog class methodsFor:'accessing'!
+
+lastFileSelectionDirectory
+ "return the name of the directory used in the previous
+ fileSelection dialog. This will be used as default for the next dialog,
+ if no explicit path is specified (see requestFileName:* methods)"
+
+ |f|
+
+ LastFileSelectionDirectory notNil ifTrue:[
+ ((f := LastFileSelectionDirectory asFilename) exists
+ and:[f isDirectory]) ifFalse:[
+ LastFileSelectionDirectory := nil.
+ ]
+ ].
+ ^ LastFileSelectionDirectory
+!
+
+lastFileSelectionDirectory:aDirectoryString
+ "set the name of the directory used in the previous
+ fileSelection dialog. This will be used as default for the next dialog,
+ if no explicit path is specified (see requestFileName:* methods)"
+
+ LastFileSelectionDirectory := aDirectoryString
+! !
+
+!FileDialog class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:FileDialog andSelector:#windowSpec
+ FileDialog new openInterface:#windowSpec
+ FileDialog open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'FileDialog'
+ #name: 'FileDialog'
+ #min: #(#Point 10 10)
+ #max: #(#Point 1024 768)
+ #bounds: #(#Rectangle 16 42 416 442)
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'ToolBar1'
+ #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 30 0)
+ #tabable: true
+ #menu: #toolBarMenu
+ #textDefault: true
+ )
+ #(#SubCanvasSpec
+ #name: 'DirectoryTreeBrowser'
+ #layout: #(#LayoutFrame 0 0.0 30 0 0 1.0 -107 1)
+ #tabable: true
+ #hasHorizontalScrollBar: false
+ #hasVerticalScrollBar: false
+ #majorKey: #DirectoryTreeBrowser
+ #createNewApplication: true
+ #createNewBuilder: true
+ #postBuildCallback: #postBuildTreeBrowser:
+ )
+ #(#LabelSpec
+ #label: 'Filename:'
+ #name: 'FilenameLabel'
+ #layout: #(#LayoutFrame 3 0 -97 1 73 0 -77 1)
+ #translateLabel: true
+ #adjust: #left
+ )
+ #(#FilenameInputFieldSpec
+ #name: 'FilenameEntryField'
+ #layout: #(#LayoutFrame 70 0 -96 1 -10 1 -76 1)
+ #tabable: true
+ #model: #filenameHolder
+ #acceptOnPointerLeave: false
+ #postBuildCallback: #postBuildFileNameField:
+ )
+ #(#LabelSpec
+ #label: 'Filter:'
+ #name: 'FilterLabel'
+ #layout: #(#LayoutFrame 3 0 -70 1 67 0 -50 1)
+ #translateLabel: true
+ #adjust: #left
+ )
+ #(#InputFieldSpec
+ #name: 'FilterEntryField'
+ #layout: #(#LayoutFrame 70 0 -69 1 -10 1 -49 1)
+ #model: #filterHolder
+ #immediateAccept: true
+ #acceptOnReturn: true
+ #acceptOnTab: true
+ #acceptOnLostFocus: true
+ #acceptOnPointerLeave: false
+ #postBuildCallback: #postBuildFilterField:
+ )
+ #(#HorizontalPanelViewSpec
+ #name: 'ButtonPanel'
+ #layout: #(#LayoutFrame 0 0.0 -40 1 0 1 0 1)
+ #horizontalLayout: #spreadSpace
+ #verticalLayout: #center
+ #horizontalSpace: 3
+ #verticalSpace: 3
+ #reverseOrderIfOKAtLeft: true
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#ActionButtonSpec
+ #label: 'Cancel'
+ #name: 'cancelButton'
+ #translateLabel: true
+ #labelChannel: #cancelLabelHolder
+ #tabable: true
+ #model: #doCancel
+ #extent: #(#Point 150 21)
+ )
+ #(#ActionButtonSpec
+ #label: 'OK'
+ #name: 'okButton'
+ #translateLabel: true
+ #labelChannel: #okLabelHolder
+ #tabable: true
+ #model: #doAccept
+ #isDefault: true
+ #extent: #(#Point 150 22)
+ )
+ )
+
+ )
+ )
+ )
+
+ )
+ )
+! !
+
+!FileDialog class methodsFor:'menu specs'!
+
+toolBarMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FileDialog andSelector:#toolBarMenu
+ (Menu new fromLiteralArrayEncoding:(FileDialog toolBarMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'DirectoryUp'
+ #translateLabel: true
+ #isButton: true
+ #value: #doGoDirectoryUp
+ #activeHelpKey: #directoryUp
+ #enabled: #enableDirectoryUp
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #upArrow20x20Icon)
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Back'
+ #translateLabel: true
+ #isButton: true
+ #value: #doBack
+ #activeHelpKey: #directoryBack
+ #enabled: #enableBack
+ #submenuChannel: #menuDirHistoryBack
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #leftArrow20x20PlusMenuIcon)
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Forward'
+ #translateLabel: true
+ #isButton: true
+ #value: #doForward
+ #activeHelpKey: #directoryForward
+ #submenuChannel: #menuDirHistoryForward
+ #enabled: #enableForward
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #rightArrowPlusMenu20x20Icon)
+ )
+ #(#MenuItem
+ #label: '-'
+ )
+ #(#MenuItem
+ #label: 'Home'
+ #translateLabel: true
+ #isButton: true
+ #value: #doGotoHomeDirectory
+ #activeHelpKey: #fileHome
+ #enabled: #enableHome
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #goHomeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FileDialog methodsFor:'accessing'!
+
+directory
+ "return the value of the instance variable 'directory' (automatically generated)"
+
+ ^ directory
+!
+
+directory:something
+ "set the value of the instance variable 'directory' (automatically generated)"
+
+ directory := something.
+!
+
+initialText
+ "return the value of the instance variable 'initialText' (automatically generated)"
+
+ ^ initialText
+!
+
+initialText:something
+ "set the value of the instance variable 'initialText' (automatically generated)"
+
+ initialText := something.
+!
+
+pattern
+ "return the value of the instance variable 'pattern' (automatically generated)"
+
+ ^ pattern
+!
+
+pattern:something
+ "set the value of the instance variable 'pattern' (automatically generated)"
+
+ pattern := something.
+!
+
+result
+ "return the value of the instance variable 'result' (automatically generated)"
+
+ ^ result
+!
+
+result:something
+ "set the value of the instance variable 'result' (automatically generated)"
+
+ result := something.
+!
+
+startFilename
+ "return the value of the instance variable 'startFilename' (automatically generated)"
+
+ startFilename isNil ifTrue:[
+ startFilename := Filename currentDirectory asAbsoluteFilename.
+ ].
+ ^ startFilename
+!
+
+startFilename:something
+ "set the value of the instance variable 'startFilename' (automatically generated)"
+
+ startFilename := something.
+!
+
+viewFiles
+ "return the value of the instance variable 'viewFiles' (automatically generated)"
+
+ ^ viewFiles
+!
+
+viewFiles:something
+ "set the value of the instance variable 'viewFiles' (automatically generated)"
+
+ viewFiles := something.
+! !
+
+!FileDialog methodsFor:'aspects'!
+
+cancelLabelHolder
+ "automatically generated by UIPainter ..."
+
+ "*** the code below creates a default model when invoked."
+ "*** (which may not be the one you wanted)"
+ "*** Please change as required and accept it in the browser."
+ "*** (and replace this comment by something more useful ;-)"
+
+ cancelLabelHolder isNil ifTrue:[
+ cancelLabelHolder := 'Cancel' asValue.
+ ].
+ ^ cancelLabelHolder.
+!
+
+enableBack
+ "Return a value holder for the input string.
+ "
+ enableBack isNil ifTrue:[
+ enableBack := treeBrowser enableBack.
+ ].
+ ^ enableBack
+!
+
+enableDirectoryUp
+
+ enableDirectoryUp isNil ifTrue:[
+ enableDirectoryUp := treeBrowser enableDirectoryUp.
+ ].
+ ^ enableDirectoryUp
+!
+
+enableForward
+ "Return a value holder for the input string.
+ "
+ enableForward isNil ifTrue:[
+ enableForward := treeBrowser enableForward.
+ ].
+ ^ enableForward
+!
+
+enableHome
+ "Return a value holder for the input string.
+ "
+ enableHome isNil ifTrue:[
+ enableHome := treeBrowser enableHome.
+ ].
+ ^ enableHome
+!
+
+filenameHolder
+ "Return a value holder with the filename.
+ Shown in the filename input-field.
+ Being the selection in the tree.
+ "
+ |holder|
+ holder := builder bindingAt:#filenameHolder.
+
+ holder ifNil:[
+ holder := ValueHolder new.
+ holder addDependent:self.
+ builder aspectAt:#filenameHolder
+ put:holder.
+ ].
+
+ ^ holder.
+!
+
+filterHolder
+ "Return a value holder for the input string.
+ "
+
+ filterHolder isNil ifTrue:[
+ filterHolder := treeBrowser filterModel.
+ self pattern notNil ifTrue:[
+ filterHolder value:pattern.
+ ]
+ ].
+ ^ filterHolder
+!
+
+okLabelHolder
+ "automatically generated by UIPainter ..."
+
+ "*** the code below creates a default model when invoked."
+ "*** (which may not be the one you wanted)"
+ "*** Please change as required and accept it in the browser."
+ "*** (and replace this comment by something more useful ;-)"
+
+ okLabelHolder isNil ifTrue:[
+ okLabelHolder := 'OK' asValue.
+ ].
+ ^ okLabelHolder.
+! !
+
+!FileDialog methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+ "Invoked when an object that I depend upon sends a change notification."
+
+ "stub code automatically generated - please change as required"
+
+ changedObject == treeBrowser currentFileNameHolder ifTrue:[
+ | files newDir|
+ files := treeBrowser currentFileNameHolder value.
+
+ (files isEmpty) ifTrue:[
+ self filenameHolder value:nil withoutNotifying:self.
+ treeBrowser hasSelection value:false.
+ ] ifFalse:[
+ treeBrowser hasSelection value:true.
+ files size == 1 ifTrue:[
+ self filenameHolder value:(files first) withoutNotifying:self.
+ ] ifFalse:[
+ self filenameHolder value:'' withoutNotifying:self.
+ ].
+ ].
+ ].
+ changedObject == self filenameHolder ifTrue:[
+ (changedObject value asFilename exists not) ifTrue:[^ self].
+ treeBrowser currentFileNameHolder value:(OrderedCollection with:(changedObject value asFilename)) withoutNotifying:self.
+ ].
+ changedObject == treeBrowser enableBack ifTrue:[
+ self enableBack value:changedObject value.
+ ^ self.
+ ].
+ changedObject == treeBrowser enableForward ifTrue:[
+ self enableForward value:changedObject value.
+ ^ self.
+ ].
+ changedObject == treeBrowser enableHome ifTrue:[
+ self enableHome value:changedObject value.
+ ^ self.
+ ].
+ changedObject == treeBrowser enableDirectoryUp ifTrue:[
+ self enableDirectoryUp value:changedObject value.
+ ^ self.
+ ].
+ ^ super update:something with:aParameter from:changedObject
+! !
+
+!FileDialog methodsFor:'event handling'!
+
+processEvent:anEvent
+ "filter keyboard events.
+ Return true, if I have eaten the event"
+
+ |focusView key rawKey|
+
+ anEvent isKeyPressEvent ifTrue:[
+ focusView := anEvent targetView.
+ key := anEvent key.
+ rawKey := anEvent rawKey.
+
+ (focusView == filterField) ifTrue:[
+ ^ false.
+ ].
+ (focusView == filenameField) ifTrue:[
+ ^ false.
+ ].
+ ].
+ ^ false
+! !
+
+!FileDialog methodsFor:'initialization & release'!
+
+postBuildFileNameField:aWidget
+
+ filenameField := aWidget.
+!
+
+postBuildFilterField:aWidget
+
+ filterField := aWidget.
+!
+
+postBuildTreeBrowser:aSubCanvasView
+
+ treeBrowser := aSubCanvasView client.
+!
+
+postBuildWith:aBuilder
+ "This is a hook method generated by the Browser.
+ It will be invoked during the initialization of your app/dialog,
+ after all of the visual components have been built,
+ but BEFORE the top window is made visible.
+ Add any app-specific actions here (reading files, setting up values etc.)
+ See also #postOpenWith:, which is invoked after opening."
+
+ "/ add any code here ...
+
+ ^ super postBuildWith:aBuilder
+!
+
+postOpenWith:aBuilder
+ "This is a hook method generated by the Browser.
+ It will be invoked right after the applications window has been opened.
+ Add any app-specific actions here (starting background processes etc.).
+ See also #postBuildWith:, which is invoked before opening."
+
+ "/ add any code here ...
+
+
+"/ self windowGroup addPreEventHook:self.
+ treeBrowser currentFileNameHolder addDependent:self.
+ treeBrowser enableBack addDependent:self.
+ treeBrowser enableForward addDependent:self.
+ treeBrowser enableHome addDependent:self.
+ treeBrowser enableDirectoryUp addDependent:self.
+ treeBrowser setNewRoot:((self directory) ? (Filename currentDirectory asAbsoluteFilename)).
+ treeBrowser viewFilesInDirectoryTree value:(viewFiles ? true).
+ treeBrowser currentFileNameHolder value:(OrderedCollection with:(self startFilename)).
+ self filenameHolder value:(self startFilename asString).
+ self window label:(self initialText) ? 'File Dialog'.
+ ^ super postOpenWith:aBuilder
+! !
+
+!FileDialog methodsFor:'user actions'!
+
+doAccept
+ "force accept - ignore in filterField"
+
+ |ev|
+
+ ev := self windowGroup lastEvent.
+ (ev notNil
+ and:[ev isKeyEvent
+ and:[ev key == #Return
+ and:[( ev targetView isSameOrComponentOf:filterField)
+ or:[ev targetView isSameOrComponentOf:filenameField]]]]) ifTrue:[
+ ^ self
+ ].
+ self result:(self filenameHolder value).
+
+ ^ super doAccept
+!
+
+doBack
+
+ treeBrowser doBack.
+!
+
+doCancel
+
+ self result:nil.
+ ^ super doCancel.
+!
+
+doForward
+
+ treeBrowser doForward.
+!
+
+doGoDirectoryUp
+
+ treeBrowser doGoDirectoryUp.
+!
+
+doGotoHomeDirectory
+
+ treeBrowser doGotoHomeDirectory.
+!
+
+menuDirHistory:backOrForward
+
+ ^ treeBrowser menuDirHistory:backOrForward.
+!
+
+menuDirHistoryBack
+
+ ^ treeBrowser menuDirHistory:#back.
+!
+
+menuDirHistoryForward
+
+ ^ treeBrowser menuDirHistory:#forward.
+! !
+
+!FileDialog class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/FileDialog.st,v 1.1 2002-09-25 08:00:23 penk Exp $'
+! !
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FindFileApplication.st Wed Sep 25 10:00:32 2002 +0200
@@ -0,0 +1,863 @@
+"{ Package: 'stx:libtool' }"
+
+AbstractFileApplicationNoteBookComponent subclass:#FindFileApplication
+ instanceVariableNames:'contentsPatternHolder ignoreCaseInName notSearchForSameContents
+ namePatternHolder ignoreCaseInContents searchDirectoryHolder
+ findFileView searchResultTable resultList enableStop enableSearch
+ stopSignal accessLock searchTask expanded searchRecursively
+ selectionHolder hasListEntries'
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Interface-Tools-File'
+!
+
+
+!FindFileApplication class methodsFor:'instance creation'!
+
+open
+
+ ^ self openOnFileName:(Filename currentDirectory asAbsoluteFilename)
+!
+
+openOnFileName:aFileName
+
+ | instance builder|
+
+ builder := super open.
+ instance := builder application.
+ instance item:(DirectoryContentsBrowser itemClass with:aFileName).
+ ^ builder
+!
+
+openOnFileName:aFileName for:aTargetApplication
+
+ | instance builder|
+
+ builder := super open.
+ instance := builder application.
+ instance item:(DirectoryContentsBrowser itemClass with:aFileName).
+ ^ builder
+! !
+
+!FindFileApplication class methodsFor:'defaults'!
+
+tabStringFor:aApplicationType
+
+ ^ 'Find file in:'
+! !
+
+!FindFileApplication class methodsFor:'interface specs'!
+
+windowSpec
+ "This resource specification was automatically generated
+ by the UIPainter of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the UIPainter may not be able to read the specification."
+
+ "
+ UIPainter new openOnClass:FindFileApplication andSelector:#windowSpec
+ FindFileApplication new openInterface:#windowSpec
+ FindFileApplication open
+ "
+
+ <resource: #canvas>
+
+ ^
+ #(#FullSpec
+ #name: #windowSpec
+ #window:
+ #(#WindowSpec
+ #label: 'File Search'
+ #name: 'File Search'
+ #min: #(#Point 377 131)
+ #max: #(#Point 1280 1024)
+ #bounds: #(#Rectangle 16 42 681 374)
+ )
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#MenuPanelSpec
+ #name: 'ToolBar1'
+ #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0)
+ #menu: #searchMenu
+ #textDefault: true
+ )
+ #(#ViewSpec
+ #name: 'Box1'
+ #layout: #(#LayoutFrame 0 0.0 32 0 0 1.0 126 0)
+ #component:
+ #(#SpecCollection
+ #collection: #(
+ #(#LabelSpec
+ #label: 'Search files named:'
+ #name: 'Label1'
+ #layout: #(#LayoutFrame 3 0 7 0 148 0 24 0)
+ #translateLabel: true
+ #adjust: #left
+ )
+ #(#InputFieldSpec
+ #name: 'EntryField1'
+ #layout: #(#LayoutFrame 140 0 4 0 -115 1 24 0)
+ #tabable: true
+ #model: #namePatternHolder
+ #immediateAccept: true
+ #acceptOnLeave: false
+ #acceptOnPointerLeave: false
+ )
+ #(#CheckBoxSpec
+ #label: 'Ignore case'
+ #name: 'CheckBox1'
+ #layout: #(#LayoutFrame -97 1 5 0 1 1 28 0)
+ #tabable: true
+ #model: #ignoreCaseInName
+ #translateLabel: true
+ )
+ #(#LabelSpec
+ #label: 'Containing the string:'
+ #name: 'Label2'
+ #layout: #(#LayoutFrame 4 0 31 0 136 0 48 0)
+ #translateLabel: true
+ #adjust: #left
+ )
+ #(#InputFieldSpec
+ #name: 'EntryField2'
+ #layout: #(#LayoutFrame 140 0 29 0 -115 1 49 0)
+ #enableChannel: #notSearchForSameContents
+ #tabable: true
+ #model: #contentsPatternHolder
+ #immediateAccept: true
+ #acceptOnPointerLeave: false
+ )
+ #(#CheckBoxSpec
+ #label: 'Ignore case'
+ #name: 'CheckBox2'
+ #layout: #(#LayoutFrame -97 1 30 0 4 1 50 0)
+ #enableChannel: #notSearchForSameContents
+ #tabable: true
+ #model: #ignoreCaseInContents
+ #translateLabel: true
+ )
+ #(#LabelSpec
+ #label: 'Directory:'
+ #name: 'Directory'
+ #layout: #(#LayoutFrame 4 0 57 0 136 0 74 0)
+ #translateLabel: true
+ #adjust: #left
+ )
+ #(#FilenameInputFieldSpec
+ #name: 'FilenameEntryField1'
+ #layout: #(#LayoutFrame 140 0 54 0 -115 1 74 0)
+ #model: #searchDirectoryHolder
+ #immediateAccept: true
+ #acceptOnPointerLeave: false
+ )
+ #(#CheckBoxSpec
+ #label: 'Recursively'
+ #name: 'CheckBox3'
+ #layout: #(#LayoutFrame -97 1 54 0 1 1 77 0)
+ #tabable: true
+ #model: #searchRecursively
+ #translateLabel: true
+ )
+ )
+
+ )
+ )
+ #(#SequenceViewSpec
+ #name: 'List1'
+ #layout: #(#LayoutFrame 0 0.0 117 0 0 1.0 0 1)
+ #model: #selectionHolder
+ #menu: #menu
+ #hasHorizontalScrollBar: true
+ #hasVerticalScrollBar: true
+ #isMultiSelect: true
+ #doubleClickSelector: #selectInBrowser
+ #useIndex: true
+ #sequenceList: #resultList
+ )
+ )
+
+ )
+ )
+! !
+
+!FindFileApplication class methodsFor:'menu specs'!
+
+menu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FindFileApplication andSelector:#menu
+ (Menu new fromLiteralArrayEncoding:(FindFileApplication menu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Select in Browser'
+ #translateLabel: true
+ #isVisible: #isEmbeddedApplication
+ #value: #selectInBrowser
+ #enabled: #hasOneFileSelected
+ )
+ #(#MenuItem
+ #label: 'Copy Selected Files'
+ #translateLabel: true
+ #value: #copySelectedFiles
+ #enabled: #hasSelectionInResultList
+ )
+ #(#MenuItem
+ #label: 'Open in New File Browser'
+ #translateLabel: true
+ #value: #openInNewBrowser
+ #enabled: #hasOneFileSelected
+ )
+ #(#MenuItem
+ #label: 'Remove selected Files'
+ #translateLabel: true
+ #value: #removeFromList
+ #enabled: #hasSelection
+ )
+ #(#MenuItem
+ #label: 'Remove all Files'
+ #translateLabel: true
+ #value: #removeAllFromList
+ #enabled: #hasListEntries
+ )
+ )
+ nil
+ nil
+ )
+!
+
+searchMenu
+ "This resource specification was automatically generated
+ by the MenuEditor of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the MenuEditor may not be able to read the specification."
+
+ "
+ MenuEditor new openOnClass:FindFileApplication andSelector:#searchMenu
+ (Menu new fromLiteralArrayEncoding:(FindFileApplication searchMenu)) startUp
+ "
+
+ <resource: #menu>
+
+ ^
+ #(#Menu
+ #(
+ #(#MenuItem
+ #label: 'Search'
+ #translateLabel: true
+ #isButton: true
+ #value: #doSearch
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #search20x20Icon)
+ )
+ #(#MenuItem
+ #label: 'Stop'
+ #translateLabel: true
+ #isButton: true
+ #value: #stop
+ #enabled: #enableStop
+ #labelImage: #(#ResourceRetriever #ToolbarIconLibrary #stop22x22Icon)
+ )
+ #(#MenuItem
+ #label: 'Clean Up'
+ #translateLabel: true
+ #isButton: true
+ #value: #removeAllFromList
+ #enabled: #hasListEntries
+ #labelImage: #(#ResourceRetriever #Icon #deleteIcon)
+ )
+ #(#MenuItem
+ #label: 'Close'
+ #translateLabel: true
+ #isButton: true
+ #startGroup: #right
+ #value: #doClose
+ #labelImage: #(#ResourceRetriever #AbstractFileBrowser #closeIcon)
+ )
+ )
+ nil
+ nil
+ )
+! !
+
+!FindFileApplication class methodsFor:'tableColumns specs'!
+
+searchResultTable
+ "This resource specification was automatically generated
+ by the DataSetBuilder of ST/X."
+
+ "Do not manually edit this!! If it is corrupted,
+ the DataSetBuilder may not be able to read the specification."
+
+ "
+ DataSetBuilder new openOnClass:FindFileApplication andSelector:#searchResultTable
+ "
+
+ <resource: #tableColumns>
+
+ ^#(
+ #(#DataSetColumnSpec
+ #label: 'Filename'
+ #id: 'FileName'
+ #labelButtonType: #Button
+ #model: #fileName
+ #showRowSeparator: false
+ #showColSeparator: false
+ )
+ )
+
+! !
+
+!FindFileApplication methodsFor:'accessing'!
+
+accessLock
+ "return the value of the instance variable 'accessLock' (automatically generated)"
+
+ accessLock isNil ifTrue:[
+ accessLock := Semaphore forMutualExclusion name:'accessLock'.
+ ].
+ ^ accessLock
+!
+
+stopSignal
+
+ stopSignal isNil ifTrue:[
+ stopSignal := Signal new.
+ ].
+ ^ stopSignal
+! !
+
+!FindFileApplication methodsFor:'actions'!
+
+changeInformationTo:aString
+
+ self changeInformationTo:aString toTab:false
+!
+
+changeInformationTo:aString toTab:aBoolean
+
+ masterApplication isNil ifTrue:[
+ findFileView label:aString
+ ] ifFalse:[
+ aBoolean ifTrue:[
+ masterApplication tabStringChangeTo:aString for:self
+ ]
+ ].
+!
+
+copySelectedFiles
+ |sel list stream|
+
+ sel := self selectionHolder value.
+ list := self resultList.
+ (sel notNil and:[sel notEmpty]) ifTrue:[
+ stream := WriteStream on:''.
+ sel do:[: key |
+ stream nextPutAll:(list at:key).
+ stream cr.
+ ].
+ self window setTextSelection:stream contents.
+ stream close.
+ ].
+!
+
+doSearch
+
+ | namePattern namePatterns contentsPattern dir|
+
+"/ self changeExtentToSeeSearchResult.
+
+ dir := self searchDirectoryHolder value.
+ dir isNil ifTrue:[
+ Dialog warn:'please type in a Directory first'.
+ ^ self.
+ ].
+ dir asFilename exists not ifTrue:[
+ Dialog warn:dir, 'not exists'.
+ ^ self.
+ ].
+
+ searchTask notNil ifTrue:[
+ (Dialog
+ confirm:(resources string:'there is already a find file running !!') withCRs
+ yesLabel:(resources at:'Stop and continue')
+ noLabel:(resources at:'Cancel'))
+ ifFalse:[^ self].
+ self stop.
+ ].
+ self enableStop value:true.
+
+ namePattern := self namePatternHolder value.
+ namePattern size == 0 ifTrue:[
+ namePatterns := nil
+ ] ifFalse:[
+ ignoreCaseInName value ifTrue:[
+ namePattern := namePattern asLowercase
+ ].
+ namePatterns := namePattern asCollectionOfSubstringsSeparatedBy:$;
+ ].
+ contentsPattern := self contentsPatternHolder value.
+ contentsPattern size == 0 ifTrue:[
+ contentsPattern := nil
+ ] ifFalse:[
+ self ignoreCaseInContents value ifTrue:[
+ contentsPattern := contentsPattern asLowercase
+ ]
+ ].
+ searchTask := Process for:[
+ [
+ (self stopSignal) catch:[
+ self resultList removeAll.
+ self changeInformationTo:'Find File ' , '- search started ' toTab:true.
+ self
+ doFindFileNamed:namePatterns
+ ignoreCase:self ignoreCaseInName value
+ containingString:contentsPattern
+ ignoreCaseInContents:self ignoreCaseInContents value
+ sameContentsAsFile:nil
+ sameContentsAs:nil
+ in:self searchDirectoryHolder value.
+ self enableStop value:false.
+ self enableSearch value:true.
+ self changeInformationTo:'Find File ' , '- search finished' toTab:true.
+ ].
+ ] valueNowOrOnUnwindDo:[
+ searchTask := nil.
+ self enableStop value:false.
+ ]
+ ] priority:(Processor systemBackgroundPriority).
+
+ searchTask name:('FindFile[', self searchDirectoryHolder value asFilename baseName, ']').
+ searchTask resume.
+!
+
+openInNewBrowser
+ |sel|
+
+ sel := self selectionHolder value.
+ (sel notNil and:[sel notEmpty]) ifTrue:[
+ FileBrowserV2 openOn:(self resultList at:sel first) asFilename
+ ].
+!
+
+removeAllFromList
+
+ self resultList removeAll.
+!
+
+removeFromList
+ |sel list|
+
+ sel := self selectionHolder value.
+ list := self resultList.
+ (sel notNil and:[sel notEmpty]) ifTrue:[
+ sel reverseDo:[: key |
+ list removeAtIndex:key
+ ]
+ ].
+!
+
+selectInBrowser
+ |sel entry application|
+
+ sel := self selectionHolder value.
+ (sel notNil and:[sel notEmpty]) ifTrue:[
+ entry := self resultList at:sel first.
+ ].
+ application := self masterApplication.
+ application notNil ifTrue:[
+ application gotoFile:(entry asFilename).
+ ].
+!
+
+stop
+
+ searchTask notNil ifTrue:[
+ self accessLock critical:[
+ searchTask interruptWith:[stopSignal raiseRequest].
+ ]
+ ].
+ self enableStop value:false.
+ self enableSearch value:true.
+ self changeInformationTo:'Find File ' , '- search stopped' toTab:true.
+!
+
+stopSearchTask
+ |task|
+
+ (task := searchTask) notNil ifTrue:[
+ searchTask := nil.
+
+ Object errorSignal handle:[:ex|
+ Dialog warn:ex description.
+ ]do:[
+ task isDead ifFalse:[
+ task terminateWithAllSubprocesses.
+ task waitUntilTerminated.
+ ]
+ ]
+ ].
+! !
+
+!FindFileApplication methodsFor:'aspects'!
+
+contentsPatternHolder
+
+ contentsPatternHolder isNil ifTrue:[
+ contentsPatternHolder := nil asValue.
+ ].
+ ^ contentsPatternHolder.
+!
+
+enableSearch
+
+ enableSearch isNil ifTrue:[
+ enableSearch := true asValue.
+ ].
+ ^ enableSearch.
+!
+
+enableStop
+
+ enableStop isNil ifTrue:[
+ enableStop := true asValue.
+ ].
+ ^ enableStop.
+!
+
+hasListEntries
+
+ hasListEntries isNil ifTrue:[
+ hasListEntries := false asValue.
+ ].
+ ^ hasListEntries.
+!
+
+ignoreCaseInContents
+ ignoreCaseInContents isNil ifTrue:[
+ ignoreCaseInContents := false asValue.
+ ].
+ ^ ignoreCaseInContents.
+!
+
+ignoreCaseInName
+
+ ignoreCaseInName isNil ifTrue:[
+ ignoreCaseInName := false asValue.
+ ].
+ ^ ignoreCaseInName.
+!
+
+namePatternHolder
+
+ namePatternHolder isNil ifTrue:[
+ namePatternHolder := '*' asValue.
+ ].
+ ^ namePatternHolder.
+!
+
+notSearchForSameContents
+
+ notSearchForSameContents isNil ifTrue:[
+ notSearchForSameContents := true asValue.
+ ].
+ ^ notSearchForSameContents.
+!
+
+resultList
+
+ resultList isNil ifTrue:[
+ resultList := List new.
+ resultList addDependent:self.
+ ].
+ ^ resultList.
+!
+
+searchDirectoryHolder
+
+ searchDirectoryHolder isNil ifTrue:[
+ searchDirectoryHolder := ValueHolder new.
+ ].
+ ^ searchDirectoryHolder.
+!
+
+searchRecursively
+
+ searchRecursively isNil ifTrue:[
+ searchRecursively := true asValue.
+ ].
+ ^ searchRecursively.
+!
+
+searchResultTable
+
+ searchResultTable isNil ifTrue:[
+ searchResultTable := self class searchResultTable asValue.
+ ].
+ ^ searchResultTable.
+!
+
+selectionHolder
+
+ selectionHolder isNil ifTrue:[
+ selectionHolder := ValueHolder new
+ ].
+ ^ selectionHolder
+! !
+
+!FindFileApplication methodsFor:'change & update'!
+
+update:something with:aParameter from:changedObject
+ "Invoked when an object that I depend upon sends a change notification."
+
+ "stub code automatically generated - please change as required"
+
+ changedObject == self resultList ifTrue:[
+ self hasListEntries value:(self resultList notEmpty).
+ ^ self
+ ].
+ super update:something with:aParameter from:changedObject
+! !
+
+!FindFileApplication methodsFor:'event handling'!
+
+processEvent:anEvent
+ "filter keyboard events.
+ Return true, if I have eaten the event"
+
+ |focusView key rawKey|
+
+ anEvent isKeyPressEvent ifTrue:[
+ focusView := anEvent targetView.
+ key := anEvent key.
+ rawKey := anEvent rawKey.
+
+ (focusView isSameOrComponentOf:self window) ifTrue:[
+ (key == #Return) ifTrue:[
+ (focusView name ~= 'selectionInListView') ifTrue:[
+ self doSearch.
+ ] ifFalse:[
+ self hasOneFileSelected ifTrue:[
+ self isEmbeddedApplication ifTrue:[
+ self selectInBrowser.
+ ] ifFalse:[
+ self openInNewBrowser.
+ ]
+ ]
+ ].
+ ^ true
+ ].
+ ]
+ ].
+ ^ false
+! !
+
+!FindFileApplication methodsFor:'private'!
+
+changeExtentToSeeSearchResult
+
+ | extent window|
+
+ expanded isNil ifTrue:[
+ window := self builder window.
+ window ifNotNil:[
+ window := window topView.
+ extent := window extent.
+ window extent:((extent x) @ (extent y + 300)).
+ expanded := true.
+ window containerChangedSize.
+ ].
+ ].
+! !
+
+!FindFileApplication methodsFor:'private - file stuff'!
+
+doFindFileNamed:namePatterns ignoreCase:ignCaseInName containingString:contentsString ignoreCaseInContents:ignCaseInString sameContentsAsFile:filenameToCompareContentsOrNil sameContentsAs:bytesToCompareContentsOrNil in:aDirectory
+
+ |dir subDirs nameMatches contentsMatches lines contentsToCompare list|
+
+ list := self resultList.
+ bytesToCompareContentsOrNil notNil ifTrue:[
+ contentsToCompare := bytesToCompareContentsOrNil
+ ].
+
+ subDirs := OrderedCollection new.
+
+ dir := aDirectory asFilename.
+ self changeInformationTo:'Find File ' , '- searching .' , ((dir name) copyFrom:(self searchDirectoryHolder value asString size + 1)) toTab:false.
+ (dir directoryContents ? #()) sort do:[:fn |
+ |f|
+
+ f := dir construct:fn.
+ f isDirectory ifTrue:[
+ f isSymbolicLink ifFalse:[
+ subDirs add:f
+ ]
+ ] ifFalse:[
+ (nameMatches := namePatterns isNil) ifFalse:[
+ ignCaseInName ifTrue:[
+ nameMatches := namePatterns contains:[:aPattern | aPattern match:(fn asLowercase)]
+ ] ifFalse:[
+ nameMatches := namePatterns contains:[:aPattern | aPattern match:fn]
+ ]
+ ].
+ nameMatches ifTrue:[
+ filenameToCompareContentsOrNil notNil ifTrue:[
+ "/ contents compare ...
+ contentsMatches := false.
+ f pathName ~= filenameToCompareContentsOrNil pathName ifTrue:[
+ f fileSize == filenameToCompareContentsOrNil fileSize ifTrue:[
+ contentsToCompare isNil ifTrue:[
+ filenameToCompareContentsOrNil fileSize < (512*1024) ifTrue:[
+ contentsToCompare := filenameToCompareContentsOrNil binaryContentsOfEntireFile
+ ]
+ ].
+ contentsToCompare isNil ifTrue:[
+ "/ too large - compare block-wise ...
+ contentsMatches := (filenameToCompareContentsOrNil sameContentsAs:f).
+ ] ifFalse:[
+ contentsMatches := contentsToCompare = (f binaryContentsOfEntireFile).
+ ]
+ ].
+ ] ifFalse:[
+ f isSymbolicLink ifTrue:[
+ list add: (f name , ' is a symbolic link to ' , f pathName).
+ ]
+ ]
+ ] ifFalse:[
+ "/ string search ...
+ (contentsMatches := contentsString isNil) ifFalse:[
+ (f exists and:[f isReadable]) ifFalse:[
+ list add: (('*** ' , f pathName , ' skipped - unreadable or bad symbolic link ***') asText colorizeAllWith:(Color red darkened)).
+ ] ifTrue:[
+ f fileSize > (4024*1024) ifTrue:[
+ list add: (('*** ' , f pathName , ' skipped - too large ***') asText colorizeAllWith:(Color red darkened)).
+ ] ifFalse:[
+ Stream lineTooLongErrorSignal handle:[:ex |
+ |cont|
+
+ "/ this typically happens, when a binary file is read linewise ...
+ cont := f readStream binary contentsOfEntireFile asString.
+ ignCaseInString ifTrue:[
+ contentsMatches := cont asLowercase includesString:contentsString asLowercase
+ ] ifFalse:[
+ contentsMatches := cont includesString:contentsString
+ ].
+ ] do:[
+ lines := f contents ? #().
+ ignCaseInString ifTrue:[
+ contentsMatches := (lines findFirst:[:l | l asLowercase includesString:contentsString asLowercase]) ~~ 0
+ ] ifFalse:[
+ contentsMatches := (lines findFirst:[:l | l includesString:contentsString]) ~~ 0
+ ].
+ ].
+ ].
+ ].
+ ].
+ ].
+ contentsMatches ifTrue:[
+ list add: f asString.
+ ]
+ ]
+ ]
+ ].
+
+ self searchRecursively value ifTrue:[
+ subDirs do:[:dir |
+ self
+ doFindFileNamed:namePatterns
+ ignoreCase:ignCaseInName
+ containingString:contentsString
+ ignoreCaseInContents:ignCaseInString
+ sameContentsAsFile:filenameToCompareContentsOrNil
+ sameContentsAs:contentsToCompare
+ in:dir
+ ].
+ ]
+! !
+
+!FindFileApplication methodsFor:'queries'!
+
+getTabStringEnd
+
+" get the tab string from the application list on the class side "
+
+ ^ self fileName directory asString
+!
+
+hasOneFileSelected
+ | sel |
+ sel := self selectionHolder value.
+ ^ (sel notNil and:[sel notEmpty and:[sel size = 1]])
+!
+
+hasSelectionInResultList
+ | sel |
+ sel := self selectionHolder value.
+ ^ (sel notNil and:[sel notEmpty])
+! !
+
+!FindFileApplication methodsFor:'startup & release'!
+
+initialize:aFile
+
+ self searchDirectoryHolder value:(self getDirWithoutFileName:aFile).
+ aFile isDirectory ifTrue:[
+ self namePatternHolder value:'*'.
+ ] ifFalse:[
+ self namePatternHolder value:aFile baseName.
+ ].
+ self enableStop value:false.
+ self enableSearch value:true.
+!
+
+item:aItem
+
+ |file|
+
+ super item:aItem.
+ file := self fileName.
+ self searchDirectoryHolder value:(self getDirWithoutFileName:file).
+ file isDirectory ifTrue:[
+ self namePatternHolder value:'*'.
+ ] ifFalse:[
+ self namePatternHolder value:file baseName.
+ ].
+ self enableStop value:false.
+ self enableSearch value:true.
+ ^ true.
+!
+
+postOpenWith:aBuilder
+
+ self masterApplication isNil ifTrue:[
+ self masterApplication:nil.
+ ].
+ findFileView := aBuilder window.
+ self windowGroup addPreEventHook:self.
+ ^ super postOpenWith:aBuilder.
+!
+
+release
+
+ self stopSearchTask.
+ ^ super release
+! !
+
+!FindFileApplication class methodsFor:'documentation'!
+
+version
+ ^ '$Header: /cvs/stx/stx/libtool/FindFileApplication.st,v 1.1 2002-09-25 08:00:04 penk Exp $'
+! !