AbstractFileBrowser.st
author Claus Gittinger <cg@exept.de>
Sat, 12 Oct 2002 02:48:29 +0200
changeset 3980 3f8311a42ca7
parent 3967 09ec3349210c
child 3982 fc30449d705d
permissions -rw-r--r--
menus reorganized

"{ Package: 'stx:libtool' }"

ApplicationModel subclass:#AbstractFileBrowser
	instanceVariableNames:'aspects'
	classVariableNames:'DirectoryHistory 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:'forwardList lastWasForwardAction'
	classVariableNames:'HistorySize'
	poolDictionaries:''
	privateIn:AbstractFileBrowser
!

Object subclass:#DirectoryHistoryItem
	instanceVariableNames:'path position'
	classVariableNames:''
	poolDictionaries:''
	privateIn:AbstractFileBrowser::DirectoryHistory
!

OrderedSet subclass:#FilenameHistory
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	privateIn:AbstractFileBrowser
!

Object subclass:#SaveAspectItem
	instanceVariableNames:'value isHolder'
	classVariableNames:''
	poolDictionaries:''
	privateIn:AbstractFileBrowser
!


!AbstractFileBrowser class methodsFor:'classAccess'!

directoryHistoryClass

    ^ AbstractFileBrowser::DirectoryHistory
!

filenameHistoryClass

    ^ FilenameHistory
! !

!AbstractFileBrowser class methodsFor:'classVarAccess'!

directoryHistory

    DirectoryHistory isNil ifTrue:[
        DirectoryHistory := self directoryHistoryClass new.
"/        DirectoryHistory inspect.
    ].
    ^ DirectoryHistory
!

resetClassVars

    DirectoryHistory := nil.

"
    AbstractFileBrowser resetClassVars
"
! !

!AbstractFileBrowser class methodsFor:'defaults'!

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
           #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]
!

newDirectory20x20Icon
    "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 newDirectory20x20Icon inspect
     ImageEditor openOnClass:self andSelector:#newDirectory20x20Icon
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class newDirectory20x20Icon'
        ifAbsentPut:[(Depth8Image new) width: 20; height: 20; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PDA@PDA@P@@@@@@@@@@@@@@@@@A@ HB@ HA@@@@@@@@@@@@@@@@@PHB@ HB@ HA
@@@@@@@@@@@@@@DA@PDA@PDA@P@@@@@@@@@@@@D@@PHB@ HB@ HB@ HB@@@@@ HB@P@A@ HB@ HB@ HB@ @B@@H@@ HA@@DB@ HB@ HB@ H@@ H@@ H@@ D@
@PHB@ HB@ HB@@HB@ @B@ H@@P@A@ HB@ HB@ HB@ HB@ HB@ HA@@DB@ HB@ HB@ HB@ HB@ HB@ D@@PHB@ HB@ HB@ HB@ HB@ HB@P@A@ HB@ HB@ HB
@ HB@ HB@ HA@@DB@ HB@ HB@ HB@ HB@ HB@ D@@PHB@ HB@ HB@ HB@ HB@ HB@P@A@ HB@ HB@ HB@ HB@ HB@ HA@@DA@PDA@PDA@PDA@PDA@PDA@PD@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[255 0 0 0 0 0 255 255 0]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@DQ@O:R@O9T@_<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: 'Visited Directories'
            #translateLabel: true
            #submenuChannel: #visitedDirectoriesMenu
          )
         #(#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
      )
!

sortMenu
    "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:#sortMenu
     (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser sortMenu)) startUp
    "

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'By Filename'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockHolder
            #choiceValue: #baseName
          )
         #(#MenuItem
            #label: 'By Type'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockHolder
            #choiceValue: #suffix
          )
         #(#MenuItem
            #label: 'By Permissions'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockHolder
            #choiceValue: #permissions
          )
         #(#MenuItem
            #label: 'By Owner'
            #translateLabel: true
            #hideMenuOnActivated: false
            #isVisible: #viewOwner
            #choice: #sortBlockHolder
            #choiceValue: #owner
          )
         #(#MenuItem
            #label: 'By Group'
            #translateLabel: true
            #hideMenuOnActivated: false
            #isVisible: #viewOwner
            #choice: #sortBlockHolder
            #choiceValue: #group
          )
         #(#MenuItem
            #label: 'By Size'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockHolder
            #choiceValue: #size
          )
         #(#MenuItem
            #label: 'By Date && Time'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockHolder
            #choiceValue: #modificationTime
          )
"/         #(#MenuItem
"/            #label: 'By Description'
"/            #translateLabel: true
"/            #hideMenuOnActivated: false
"/            #choice: #sortBlockHolder
"/            #choiceValue: #fileType
"/          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Ignore Case in Sort'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #sortCaseless
          )
         )
        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 rootInTreeView|

    self enableDirectoryUp value ifFalse:[ ^ self].
    self currentFilesAreInSameDirectory ifTrue:[
        directories := self currentDirectories value.
        upDir := directories first directory.
    ] ifFalse:[
        rootInTreeView := self application:#DirectoryTreeBrowser do:#rootHolder.
        upDir := rootInTreeView value asFilename 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 getFileInfoStringForFirstSelectedFile:longInfo.
    string notNil ifTrue:[
        box := InfoBox title:string.
        updater := [
                    [true] whileTrue:[
                        Delay waitForSeconds:2.
                        string := self getFileInfoStringForFirstSelectedFile:longInfo.
                        string isNil ifTrue:[ ^ self].
                        box title:string
                    ]
                ] fork.
        box showAtPointer.
        updater terminate.
        box destroy
    ]
!

gotoFile:aFilename

    " select only if the file is not already in selection"
    | currentSel |

    currentSel := self currentFileNameHolder value.
    ((currentSel findFirst:[:aFile| aFile = aFilename]) == 0) ifTrue:[
        self currentFileNameHolder value:(OrderedCollection with:(aFilename asAbsoluteFilename)).
    ].
!

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.
        ].
    ].
!

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 currentSel|

    currentSel := self currentDirectories value.
    currentSel size == 1 ifTrue:[
        fileName := self dirHistory goBackFrom:(currentSel first asString).
    ] ifFalse:[
        fileName := self dirHistory goBackFrom:nil.
    ].
    fileName notNil ifTrue:[
        self gotoFile:(fileName asFilename).
    ]
!

doForward

    | fileName|

    fileName := self dirHistory goForward.
    fileName notNil ifTrue:[
        self gotoFile:(fileName asFilename).
    ]
! !

!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]
!

currentSortOrder

    " returns a Ordered Collection of all directories currently selected 
      if only a file is selected currentDirectories holds the directory of the file
    "

    ^ self aspectFor:#currentSortOrder ifAbsent:[ Dictionary new ].
!

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 class directoryHistory
!

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 rootInTreeView|

    changedObject == self currentFileNameHolder ifTrue:[
        self hasSelection value:(self currentFileNameHolder value isEmpty not).
        newDirectories := self getDirectoriesForFileList:(changedObject value).
        oldDirectories := self currentDirectories value.
        oldDirectories ~= newDirectories ifTrue:[
            self currentDirectories value:newDirectories.
            size := newDirectories size.
            rootInTreeView := self application:#DirectoryTreeBrowser do:#rootHolder.
            rootInTreeView := rootInTreeView notNil ifTrue:[rootInTreeView value].
            self enableDirectoryUp value:(((size == 1) and:[newDirectories first isRootDirectory not]) or:[(rootInTreeView notNil and:[rootInTreeView value asFilename isRootDirectory not])]).
            oldDirectories notEmpty ifTrue:[
                oldDirectories do:[: dir |
                    self dirHistory addToHistory:(dir asString).
                ].
            ].
            self enableHome value:((newDirectories includes:(Filename homeDirectory))not).
            self enableForward value:self canForward.
            self enableBack value:self 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.
        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'!

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"
!

canBack

    | currentSelection |

    currentSelection := self currentDirectories value.
    currentSelection size ~~ 1 ifTrue:[ ^ false].

    ^ self dirHistory canBackFrom:(currentSelection first asString).
!

canForward

"/    | currentSelection |
"/
"/    currentSelection := self currentDirectories value.
"/    currentSelection size ~~ 1 ifTrue:[ ^ false].
    
    ^ self dirHistory canForward.
!

menuDirHistory:backOrForward
    "initialize the directory menu
    "
    <resource: #programMenu >

    |menu pathList currentSel currentPath|

    menu := Menu new.
    menu receiver:self.

    self dirHistory isEmpty ifTrue:[^ nil].
    backOrForward == #back ifTrue:[
        currentSel := self currentDirectories value.
        currentSel size == 1 ifTrue:[
            currentPath := currentSel first asString.
        ] ifFalse:[
            currentPath := nil.
        ].
        pathList := self dirHistory getBackCollectionFrom:currentPath.
    ] ifFalse:[
        pathList := self dirHistory getForwardCollection.
    ].
    pathList do:[:aPath| 
        | menuItem |
        menuItem := MenuItem new.
        menuItem label:aPath.
        menuItem value:[
            self currentFileNameHolder value:(OrderedCollection with:(aPath asFilename)).
        ].
        menu addItem:menuItem.
    ].
    ^ menu
!

menuDirHistoryBack
    "initialize the directory menu
    "
    <resource: #programMenu >

    ^ self menuDirHistory:#back.
!

menuDirHistoryForward
    "initialize the directory menu
    "
    <resource: #programMenu >

    ^ self menuDirHistory:#forward.
!

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
!

visitedDirectoriesMenu

    <resource: #programMenu >

    |menu histCopy text removeItem|

    menu := Menu new.
    menu receiver:self.

    self dirHistory isEmpty ifTrue:[^ nil].
    text := LabelAndIcon icon:(self class clearHistoryIcon) string:'Clear History'.
    removeItem := MenuItem new.
    removeItem label:text.
    removeItem value:[
        self dirHistory removeAll.
        self enableForward value:self canForward.
        self enableBack value:self canBack.
    ].
    histCopy := self dirHistory.
    histCopy do:[:aFile| 
        menu addItem:(MenuItem label:aFile asString value:[
            self currentFileNameHolder value:(OrderedCollection with:(aFile path asFilename)).
        ]).
    ].
    menu addItem:(MenuItem label:'-').
    menu addItem:removeItem.
    ^ menu
! !

!AbstractFileBrowser methodsFor:'menu access'!

viewDetailsMenuSpec

    ^ self application:#DirectoryContentsBrowser do:#viewDetailsMenuSpec
!

viewInContentsBrowserMenu

    ^ self application:#DirectoryContentsBrowser do:#viewBrowserMenu
! !

!AbstractFileBrowser methodsFor:'menu accessing'!

sortMenu

    <resource: #programMenu >

    |menu|

    menu :=  Menu new fromLiteralArrayEncoding:self class sortMenu.
    menu ifNil:[ ^ nil ].
    menu receiver:self.
    ^ menu
! !

!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 asFilename pathName) 
            ]
        ] 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:'presentation'!

getModeString:modeBits
    "convert file-mode bits into a more user-friendly string.
     This is wrong here - should be moved into OperatingSystem."

    ^ self getModeString:modeBits 
                    with:#( 'owner:' $r $w $x 
                            ' group:' $r $w $x 
                            ' others:' $r $w $x )
!

getModeString:modeBits with:texts
    "convert file-mode bits into a more user-friendly string.
     This is wrong here - should be moved into OperatingSystem."

    |bits modeString|

    bits := modeBits bitAnd:8r777.
    modeString := ''.

    #( nil 8r400 8r200 8r100 nil 8r040 8r020 8r010 nil 8r004 8r002 8r001 ) 
    with: texts do:[:bitMask :access |
        |ch|

        bitMask isNil ifTrue:[
            modeString := modeString , access
        ] ifFalse:[
            (bits bitAnd:bitMask) == 0 ifTrue:[
                ch := $-
            ] ifFalse:[
                ch := access
            ].
            modeString := modeString copyWith:ch 
        ]
    ].
    ^ modeString
! !

!AbstractFileBrowser methodsFor:'queries'!

getFileInfoStringForFirstSelectedFile:longInfo
    "get stat info on selected file - return a string which can be
     shown in a box"

    | selFiles filename text fileOutput type modeBits modeString s ts isLink info|

    selFiles := self currentFileNameHolder value.
    ((selFiles size == 1) not) ifTrue:[ ^ nil].
    filename := selFiles first.

    text := StringCollection new.

    text add:('filename: ', filename asString).
    isLink := filename isSymbolicLink.
    isLink ifTrue:[
        text add:('symbolic link to: ', (filename linkInfo path))
    ].

    info := filename info.
    type := info type.
    (longInfo and:[type == #regular]) ifTrue:[
        fileOutput := filename fileType.
    ].

    s := ('type:   ').
    fileOutput isNil ifTrue:[
        s := s ,  type asString
    ] ifFalse:[
        s := s , 'regular (' , fileOutput , ')'
    ].
    text add:s.
    isLink = true ifTrue:[
        info := filename linkInfo
    ] ifFalse:[
        info := filename info
    ].
    
    text add:('size:   ', (info size) printString).

    modeBits := info mode.
    modeString := self getModeString:modeBits.
    longInfo ifTrue:[
        text add:('access: ', modeString,' ', (modeBits printStringRadix:8)).
    ] ifFalse:[
        text add:('access: ', modeString)
    ].
    text add:('owner:  ',
               (OperatingSystem getUserNameFromID:(info uid))).
    longInfo ifTrue:[
        text add:('group:  ',
                   (OperatingSystem getGroupNameFromID:(info gid))).

        ts := info accessed.
        text add:('last access:       ',ts asTime printString ,' ', ts asDate printString). 

        ts := (info modified).
        text add:('last modification: ', ts asTime printString, ' ', ts asDate printString).
    ].
    ^ text asString
!

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:'sorting'!

sortList:instanceName 

    self sortList:instanceName withReverse:true
!

sortList:instanceName withReverse:aBoolean

    | aSymbol sortCaselessLocal locCurrentSortOrder|

    aSymbol := instanceName asSymbol.
    locCurrentSortOrder := self currentSortOrder.
    locCurrentSortOrder isEmpty ifTrue:[
        locCurrentSortOrder at:#column put:aSymbol.
        locCurrentSortOrder at:#reverse put:false.
        locCurrentSortOrder at:#sortCaseless put:sortCaselessLocal.
    ] ifFalse:[
        (locCurrentSortOrder at:#sortCaseless) ~= sortCaselessLocal ifTrue:[
            "/ sort caseless changed
            locCurrentSortOrder at:#sortCaseless put:sortCaselessLocal.
        ] ifFalse:[
            (locCurrentSortOrder at:#column) = aSymbol ifTrue:[
                "/ same column like before - change sort order ifReverse is true
                aBoolean ifTrue:[
                    | isReverse |
                    isReverse := locCurrentSortOrder at:#reverse.
                    locCurrentSortOrder at:#reverse put:(isReverse not).
                ].
            ] ifFalse:[
                "/ another column - remark column
                locCurrentSortOrder at:#column put:aSymbol.
            ]
        ]
    ].
    self application:#DirectoryContentsBrowser do:#sortListChangedWith:and: withArg:locCurrentSortOrder withArg:instanceName.
"/    self application:#DirectoryTreeBrowser do:#sortListChangedWith:and: withArg:true withArg:instanceName.
! !

!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:[
            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.
    ].
    ^ super masterApplication:anApplication.
!

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:'defaults'!

historySize

    ^ 20
! !

!AbstractFileBrowser::DirectoryHistory methodsFor:'accessing'!

forwardList
    "return the value of the instance variable 'forwardList' (automatically generated)"

    forwardList isNil ifTrue:[
        forwardList := OrderedCollection new.
    ].
    ^ forwardList
! !

!AbstractFileBrowser::DirectoryHistory methodsFor:'actions'!

addToHistory:aPath
    | item|

    item := self getItemFor:aPath.
    item isNil ifTrue:[
        " not already in history"
        self size >= self class historySize ifTrue:[
            self removeLast.
        ].
        item := DirectoryHistoryItem path:aPath.
        self addFirst:item
    ] ifFalse:[
        "already been there before; move the entry to
         the beginning, so it will fall out later."
        lastWasForwardAction ifTrue:[
            lastWasForwardAction := false.
        ] ifFalse:[
            self remove:item.
            self addFirst:item
        ]
    ].
!

forwardListAdd:aPath

    | index |
    index := self forwardList indexOf:aPath.
    index == 0 ifTrue:[
        " not already in history"
        self size >= self class historySize ifTrue:[
            self forwardList removeLast.
        ].
        self forwardList addFirst:aPath.
    ] ifFalse:[
        "already been there before; move the entry to
         the beginning, so it will fall out later."
        self forwardList remove:aPath.
        self forwardList addFirst:aPath
    ].
!

goBackFrom:aPath

" search the item in the list and give back the next in the list"

    | index retVal|

    self isEmpty ifTrue:[ ^ nil].
    aPath isNil ifTrue:[
        retVal := self first path
    ] ifFalse:[
        index := self findFirst:[:item| item path = aPath].
        index == 0 ifTrue:[
            retVal := self first path
        ] ifFalse:[
            index < self size ifTrue:[
                retVal := ((self at:index + 1) path).
            ]
        ].
    ].
    retVal := retVal ? self first path.
    self forwardListAdd:aPath.
    ^ retVal.
!

goForward

" return first path of forward list"

    | retVal|
    lastWasForwardAction := true.
    self forwardList isEmpty ifTrue:[ ^ nil].
    retVal := self forwardList first.
    self forwardList removeFirst.
    ^ retVal.
!

goForwardFrom:aPath

" get back first forward entry and remove him"

    | retVal|
    lastWasForwardAction := true.
    retVal := self forwardList first.
    self forwardList removeFirst.
    ^ retVal.
!

setPosition:aPosition for:aPath

    self do:[:item| 
        item path = aPath ifTrue:[
            item position:aPosition.
        ]
    ].
! !

!AbstractFileBrowser::DirectoryHistory methodsFor:'queries'!

canBackFrom:aPath

    ^ ((self findFirst:[:item| item path = aPath]) < self size).
!

canForward

    ^ self forwardList notEmpty.
!

getBackCollectionFrom:aPath

    | backCol index |
    
    backCol := OrderedCollection new.
    aPath isNil ifTrue:[
        index := 0.
    ] ifFalse:[
        index := self findFirst:[:item| item path = aPath].
    ].
    "/ if aPath is not in collection starts from 1 with collect af path
    index < self size ifTrue:[ 
        self from:(index + 1) to:(self size) do:[:item |
            backCol add:(item path).
        ].
    ].
    ^ backCol.
!

getForwardCollection

    ^ self forwardList.
!

getItemFor:aPath

    self do:[:item| item path = aPath ifTrue:[^ item]].
    ^ nil.
!

getPositionFor:aPath

    |item|

    item := self getItemFor:aPath.

    item notNil ifTrue:[
        ^ item position.
    ].
    ^ nil
!

includesPath:aPath

    self do:[:item| item path = aPath ifTrue:[^ true]].
    ^ false.
! !

!AbstractFileBrowser::DirectoryHistory::DirectoryHistoryItem class methodsFor:'instance creation'!

path:aPath

    ^ self new path:aPath
! !

!AbstractFileBrowser::DirectoryHistory::DirectoryHistoryItem methodsFor:'accessing'!

path
    "return the value of the instance variable 'path' (automatically generated)"

    ^ path
!

path:something
    "set the value of the instance variable 'path' (automatically generated)"

    path := something.
!

position
    "return the value of the instance variable 'position' (automatically generated)"

    ^ position
!

position:something
    "set the value of the instance variable 'position' (automatically generated)"

    position := something.
!

printString

    ^ self path asString
! !

!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.17 2002-10-12 00:48:29 cg Exp $'
! !