AbstractFileBrowser.st
author penk
Wed, 14 Jan 2004 10:49:12 +0100
changeset 5425 fed05f7926d7
parent 5419 b1215ef43a10
child 5426 7249ccac1c22
permissions -rw-r--r--
do not destroy linked menues

"
 COPYRIGHT (c) 2002 by eXept Software AG
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

"{ Package: 'stx:libtool' }"

ApplicationModel subclass:#AbstractFileBrowser
	instanceVariableNames:'aspects'
	classVariableNames:'DirectoryHistory RuntimeAspects DirectoryBookmarks
		LastEnforcedNameSpace CommandHistory DefaultCommandPerSuffix
		CommandHistorySize LastFileDiffFile DefaultFilters RootHolder
		LastFileSelection'
	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
!

List subclass:#DirectoryHistory
	instanceVariableNames:'forwardList backList lastWasForwardPath lastBackPath lastAddPath
		backForwardList backForwardIndex'
	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:'documentation'!

copyright
"
 COPYRIGHT (c) 2002 by eXept Software AG
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
! !

!AbstractFileBrowser class methodsFor:'accessing'!

currentSelection

    LastFileSelection isNil ifTrue:[
        LastFileSelection := #().
    ].
    ^ LastFileSelection
!

currentSelection:aFilenameCol

    |newCol|

    newCol := aFilenameCol collect:[:file | file asFilename].
    LastFileSelection := newCol
!

directoryHistory

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

resetClassVars

    DirectoryHistory := nil.
    LastFileSelection := nil.
"
    AbstractFileBrowser resetClassVars
"
!

rootHolder

    ^ RootHolder
!

rootHolder:aRoot

    RootHolder := aRoot
! !

!AbstractFileBrowser class methodsFor:'accessing-bookmarks'!

addBookmark:aDirectoryPath
    |bookmarks idx|

    bookmarks := self directoryBookmarks.
    idx := bookmarks indexOf:aDirectoryPath.
    idx == 0 ifTrue:[
        bookmarks addLast:aDirectoryPath asFilename.
    ].
!

defaultBookMarksFileDirectory
    ^ Filename homeDirectory
!

defaultBookMarksFilename
    ^ '.fileBrowserBookmarks'
!

directoryBookmarks
    DirectoryBookmarks isNil ifTrue:[                     
        self loadBookmarksFrom:(self defaultBookMarksFileDirectory construct:self defaultBookMarksFilename).

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

hasBookmarks
    ^ self directoryBookmarks notEmptyOrNil
!

loadBookmarksFrom:aFileNameOrString
    |bookmarks s fileName|

    fileName := aFileNameOrString asFilename.
    FileStream openErrorSignal catch:[
        s := fileName readStream.
    ].
    s isNil ifTrue:[
        ^ self.
    ].

    bookmarks := OrderedCollection new.
    [s atEnd] whileFalse:[
        |line path|

        line := s nextLine.
        path := (Base64Coder decodingOf:line) asString.
        bookmarks add:path.
    ].
    s close.

    DirectoryBookmarks := OrderedCollection new.
    bookmarks do:[:eachPath |
        self addBookmark:eachPath asFilename
    ].
!

removeBookmark:aDirectoryPath
    |bookmarks|

    bookmarks := self directoryBookmarks.
    bookmarks isEmptyOrNil ifTrue:[ ^ self].

    bookmarks remove:aDirectoryPath ifAbsent:[].
!

saveBookmarks
    |fn|

    fn := Dialog 
            requestFileName:'Save Bookmarks'
            default:(self defaultBookMarksFilename)
            fromDirectory:(self defaultBookMarksFileDirectory).
    fn isEmptyOrNil ifTrue:[^ self].

    self saveBookmarksIn:fn
!

saveBookmarksIn:aFileNameOrString
    |bookmarks s fileName|

    bookmarks := self directoryBookmarks.
    bookmarks isEmptyOrNil ifTrue:[ ^ self].

    fileName := aFileNameOrString asFilename.
    fileName exists ifTrue:[
        fileName renameTo:(fileName withSuffix:'sav').
    ].
    s := fileName writeStream.
    bookmarks do:[:eachPath |
        |absolutePath|

        absolutePath := eachPath asFilename pathName.
        s nextPutLine:(Base64Coder encodingOf:absolutePath).
    ].
    s close.
! !

!AbstractFileBrowser class methodsFor:'accessing-classes'!

directoryHistoryClass

    ^ AbstractFileBrowser::DirectoryHistory
!

filenameHistoryClass

    ^ FilenameHistory
! !

!AbstractFileBrowser class methodsFor:'defaults'!

commandHistory

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

commandHistorySize

    "max no of entries in the HistoryList "
    CommandHistorySize isNil ifTrue:[
        CommandHistorySize := 50
    ].
    ^ CommandHistorySize
!

defaultFilterList

    DefaultFilters isNil ifTrue:[
        DefaultFilters := #(        '*'
                                    '*.st' 
                                    '*.htm*' 
                                    '*.txt' 
                                    '*.gif' 
                                    '*.xpm' 
                                    '*.jpg' 
                                    '*.[h,c]*' 
                                )
    ].
    ^ DefaultFilters.
!

initialCommandFor:fileName in:aDirectory intoBox:aBox
    "set a useful initial command in an execute box."

    |mime cmd select path suffix baseName pathName|

    path := aDirectory filenameFor:fileName.
    baseName := path baseName.
    suffix := path suffix.

    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:(path pathName , ' <arguments>').
            ^ self
        ].

        select := true.

        "some heuristics - my personal preferences ...
         (actually this should come from a configfile)"

        (baseName endsWith:'akefile') ifTrue:[
            aBox initialText:'make target' selectFrom:6 to:11.
            ^ self
        ].

        cmd := MIMETypes 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:[
                    (baseName asLowercase endsWith:'tar.z') ifTrue:[
                        cmd := 'zcat %1 | tar tvf -'.
                        select := false.
                    ] ifFalse:[
                        cmd := 'uncompress %1'
                    ].
                ].
                (suffix = 'gz') ifTrue:[
                    (baseName 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'.
        ].

        pathName := path pathName.
        OperatingSystem isUNIXlike ifTrue:[
            pathName includesSeparator ifTrue:[
                pathName := '"' , pathName , '"'
            ]
        ].

        cmd := cmd bindWith:pathName.
        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
            ].
        ]
    ]

    "Modified: / 24.9.1997 / 16:34:52 / stefan"
    "Modified: / 9.4.1998 / 17:15:57 / cg"
!

listOfRuntimeValuesToRemark

    " list of all aspects that will be saved after close of FileBrowserV2"

    ^ #(
           #filterModel
           #enableFileHistory
           #fileHistory
           #currentSortOrder
           #sortBlockProperty
      )
!

resetAspects

    RuntimeAspects := nil.

"
    self resetAspects
"
!

runtimeAspects

    RuntimeAspects isNil ifTrue:[
        RuntimeAspects := Dictionary new.
    ].
    ^ RuntimeAspects
!

userPreferencesAspectList

    " list of all aspects that will be saved with save settings
      that aspects will be image consistent if the settings are saved in Launcher
      dont forget to add a access methos in Userpreferences if you add a aspect here
    "

    ^ #(
           #viewDirsInContentsBrowser
           #showDirectoryTree  
           #showHiddenFiles          
           #viewDescription        
           #viewDetails              
           #viewDirectoryDescription
           #viewFilesInDirectoryTree
           #viewGroup                
           #viewOwner                
           #viewPermissions          
           #viewPreview              
           #viewSize                
           #viewSizeInKiloBytes                
           #viewSizeInBytes                
           #viewTime                 
           #viewType  
           #openMultipleApplicationsForType
           #filenameEntryFieldVisibleHolder
           #toolBarVisibleHolder
           #sortDirectoriesBeforeFiles
           #openAlwaysInTextEditor
           #sortCaseless
      )
! !

!AbstractFileBrowser class methodsFor:'help specs'!

helpSpec
    "This resource specification was automatically generated
     by the UIHelpTool of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIHelpTool may not be able to read the specification."

    "
     UIHelpTool openOnClass:AbstractFileBrowser    
    "

    <resource: #help>

    ^ super helpSpec addPairsFrom:#(

)
! !

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

    <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') ; 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 B@G0@@N8@@\\@@8N@A0G@A C@@@@@@@@@@@@@@@@@@@@@') ; 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
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class diffIcon'
        ifAbsentPut:[(Depth8Image new) width: 16; height: 15; photometric:(#palette); bitsPerSample:(#(8)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@@DA@PDA@PDA@P@@@@@@@@@A@XFA XFA XD@@@@@@@@@@PFA XF@@@@@@@@@@@@@@@DA XF@@XFA P@@@@@@@@@A@XF@@XFA XD
@@@@@@@@@@PFA @FA XFA@@@@@@@@@@DA X@A XFA P@@@@@@@@@A@XF@@XFA XD@@@@@@@@@@PFA X@A XFA@@@@@@@@@@DA XFA @@@@@@@@@@@@@@A@XF
A XFA XD@@@@@@@@@@PFA XFA XFA@@@@@@@@@@DA@PDA@PDA@P@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; 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: 16; height: 15; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@A?0G?@_<A?8G?P_=A?4G?P_?A?>G?\_<9?1 @@') ; yourself); yourself]
!

fileInIcon
    <resource: #programImage>

    ^ ToolbarIconLibrary fileIn20x20Icon3
!

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
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class goHomeIcon'
        ifAbsentPut:[(Depth4Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(4 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@D@@@@@@@@@@@@@DQ@@@@@@@@@@@@DQDP@@@@@@@@@@DQ@QD@@@@@@@@@DQH2DQ@@@@@@@@DQH4L!!DP@@@@@@DQH4QCHQD@@@@@
DQH4QDP2DQ@@@@DQH4QDQDL!!DP@@DQH4QDQDQCHQD@D"H4QBH"ADP0@A@RH#QBH"H QC@@D@@@MDIUUUADL@@@@@@4P%UUTDP0@@@@@CQBUUUPQC@@@@@@MD
IUUUADL@@@@@@4P%UUTDP0@@@@@CQBUUUPQC@@@@@@MDIUUUADL@@@@@@4P%UUTDP0@@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 192 0 0 64 0 0 128 128 128 192 192 192 100 128 255]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@A@@@C @A''0@A/8@A?<@A?>@A??@C?? G??0O??8_??<_??<_??<C?? C?? C?? C?? C?? C?? C?? C?? C?? ') ; yourself); yourself]
!

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

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class gotoDefaultDirectoryIcon'
        ifAbsentPut:[(Depth4Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(nil )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@D@@@@@@@@@@@@@DQ@@@@@@@@@@@@DQDP@@@@@@@@@@DQ@QD@@@@@@@@@DQIBDQ@@@@@@@@DQICP!!DP@@@@@@DQICL4HQD@@@@@
DQICL3MBDQ@@@@DQIFX3L3P!!DP@@DQICY#L3L6HQD@D"ICM&L3M&M@@A@RH$L3Y#M&L4@@D@@@P3L6L6L3P@@@@@ACL3Y&L3M@@@@@@DL3L6L3L4@@@@@@P3
L6X3L3P@@@@@ACL6L6L3M@@@@@@DM&L3M#L4@@@@@@Q&L3L3X3P@@@@@A&YDQDQ$Q@@@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 192 0 0 64 0 0 73 73 73 192 192 192 100 128 255 0 200 48]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@A@@@C @A''0@A/8@A?<@A?>@A??@C?? G??0O??8_??<_??<_??<C?? C?? C?? C?? C?? C?? C?? C?? C?? ') ; 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
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class hexToggle22x22Icon'
        ifAbsentPut:[(Depth8Image new) width: 14; height: 17; photometric:(#palette); bitsPerSample:(#(8)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@APTEAPTEAPTEAP@@@@@E@@@@AP@@@@TE@@@@@@TEAP@E@@TEAPT@@@@@APT@@@T@@@TEAP@@@@@EAPT@
AP@EAPTE@@@@@@T@@@@E@@TEAPT@@@@@APTEAPTEAPTEAP@@@@@E@@@@AP@@@@TE@@@@@@T@AP@E@@T@APT@@@@@AP@@@@T@@@@EAP@@@@@E@@T@AP@E@@TE
@@@@@@T@AP@E@@@@APT@@@@@APTEAPTEAPTEAP@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 105 133 190 129 129 129 194 194 194 255 0 0 255 255 255]; mask:((Depth1Image new) width: 14; height: 17; photometric:(#blackIs0); bitsPerSample:(#(1)); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@A?>G?8_?!!?>G?8_?!!?>G?8_?!!?>G?8_?!!?>G?8_? @@@@a') ; 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:'
@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@@HB@ HB@ HB@ HB@ HB@ HB@ @@@ HB@ HB@ HB@ HB@ HB@ H@@ @B@ HB@ HB@ HB@ HB@ HB@@HA
@@HB@ HB@ HB@ HB@ HB@ @B@PD@@ HB@ HB@ HB@ HB@ H@@ DA@P@@@@@@@@@@@ HB@ HB@@HA@PDA@ HB@ HB@ @B@ HB@ @B@PDA@PDA@PDA@PDB@@HB
@ H@@ DA@PDA@PDA@PDA@PH@@ HB@ @B@PDA@PDA@PDA@PDA@ @B@ HB@ @B@PDA@PDA@PDA@PDB@@HB@ HB@ @B@PDA@PHB@ HB@ H@@ HB@ HB@ @B@PDA
@@@@@@@@@@@B@ HB@ HB@ @B@PD@@ HB@ HB@ HB@ HB@ HB@ @B@P@B@ HB@ HB@ HB@ HB@ HB@ @B@@HB@ HB@ HB@ HB@ HB@ HB@ @@@ HB@ HB@ HB
@ HB@ HB@ HB@ @B@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ @a') ; colorMapFromArray:#[0 0 0 100 128 255 128 128 128]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@M@B@@@F@J@N@@@^@J@>@@A??@C??@G??OO??@O??@G??@C??@A??E@>@H@^@@@N@@@F@N@B@A@@@@') ; 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]
!

leftArrowIcon
    ^ self leftArrow20x20Icon
!

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

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

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class makeIcon'
        ifAbsentPut:[(Depth8Image new) width: 22; height: 20; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@XF@@@@@@@@@@@@@@@@@@@FA X@@@XJB X@@@@FA @@@@@@@@@FB (JA XJB (JA XEB \F@@@@@@@@A (JB (JB (JB (JB (GA @@@@@@
@@DAB (JB (JB (JB (GAPT@@@@@A XFA XJB (GAPDAB (JAPTFA X@A \JB (JB (GAPD@@@DJB (JB (JA XJB (JB (JA0DEA0DAB (JB (JB TAA XF
B (JB (EAPTEA0(JB TEAPTA@PDA@PXJB (JB (JB (JB TE@PDA@PDA@PXJB (JB (JB (JB (JA0TA@PD@@PXJB (JB (JB (JB (JB (JA D@@@HDB (J
@ HJB (JB PDA@(JB X@@@@@@P\G@PDAA (JB XA@PDFA XA@@@@@@DA@PDA@PXJB (F@PDA@PDA@P@@@@@A@PDA@PDFA0(GA D@@PDA@PD@@@@@@@DA@P@@
@PXFA D@@@@A@PD@@@@@@@@@@@@@@@DA@PDA@@@@@@@@@@@@@@@@@@@@@@@A@PDA@P@@@@@@@@@@@@@@@@@@@@@@@@DA@P@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 48 48 48 56 59 56 64 68 64 88 92 88 128 128 128 160 160 160 192 192 192 216 219 216 239 244 239 248 252 248]; mask:((Depth1Image new) width: 22; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@C@@C''#@G?? G?? G?? _??8???<???<???<???<???<_??8_??0O??0O??0O?70GO# @O @@O @@G@@') ; 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:'
@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ H@@ HB@ HB@ HB@ HB@ HB@ HB@ @@@ HB@ HB@ HB@ HB@ HB@ HB@@H@@ HB@ HB@ HB@ HB@ HB@ H@
@PH@@ HB@ HB@ HB@ HB@ HB@ @A@PH@@ HB@ HB@ H@@@@@@@@@@@DA@PH@@ HB@ HB@ @B@ HB@ HB@PDA@PH@@ HB@ HB@@HA@PDA@PDA@PDA@PH@@ HB
@ H@@ DA@PDA@PDA@PDA@PH@@ HB@ @B@PDA@PDA@PDA@PDA@ @B@ HB@@HA@PDA@PDA@PDA@PH@@ HB@ H@@ HB@ HB@ DA@PDB@@HB@ HB@ @@@@@@@@@@
@PDA@ @B@ HB@ HB@ HB@ HB@ @A@PH@@ HB@ HB@ HB@ HB@ HB@@DB@@HB@ HB@ HB@ HB@ HB@ H@@ @B@ HB@ HB@ HB@ HB@ HB@ @@@ HB@ HB@ HB
@ HB@ HB@ HB@@HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ @a') ; colorMapFromArray:#[0 0 0 100 128 255 128 128 128]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@D@@@F@H@G@@@G @@G0@O?8AO?<@O?>@O??@O??DO?>DO?<@O?8@@G0@@G @@G@@@F@@@D@J@@@@') ; yourself); yourself]
!

rightArrowIcon
    ^ self rightArrow20x20Icon
!

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 search20x20Icon "/ search28x28Icon
    "/ ^ ToolbarIconLibrary search16x16Icon "/ search28x28Icon
!

shellIcon
    <resource: #programImage>

    OperatingSystem isMSDOSlike ifTrue:[
        ^ ToolbarIconLibrary dos20x20Icon
    ].
    ^ ToolbarIconLibrary shell20x20Icon
!

shellWithoutTextIcon
    <resource: #programImage>

    OperatingSystem isMSDOSlike ifTrue:[
        ^ ToolbarIconLibrary dosWithoutText20x20Icon
    ].
    ^ ToolbarIconLibrary shellWithoutText20x20Icon
!

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:'
@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ @@@ HB@ HB@ HB@ HB@ HB@ H@@ H@@ HB@ HB@ HB@ HB@ HB@@HA
@PH@@ HB@ HB@ HB@ HB@ @B@PDA@PH@@ HB@ HB@ HB@ H@@ DA@PDA@PH@@ HB@ HB@ HB@@HA@PDA@PDA@PH@@ HB@ HB@ @B@PDA@PDA@PDA@PH@@ HB
@ H@@ DA@PDA@PDA@PDA@PH@@ HB@@@@@@@@@ DA@PDB@@@@@@@@@ HB@ HB@ @B@PDA@PH@@ HB@ HB@ HB@ HB@@HA@PDA@ @B@ HB@ HB@ HB@ H@@ DA
@PDB@@HB@ HB@ HB@ HB@ @B@PDA@PH@@ HB@ HB@ HB@ HB@@HA@PDA@ @B@ HB@ HB@ HB@ H@@ HB@ HB@@HB@ HB@ HB@ HB@ @@@@@@@@@@@ HB@ HB
@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ HB@ @a') ; colorMapFromArray:#[0 0 0 100 128 255 128 128 128]; mask:((Depth1Image new) width: 20; height: 20; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@J@@@@@F@@@O@@@_ O@?0@A?8@C?<@G?>@O??E_??(@?0@@?0@@?0N@?0A@?0@@?0@@?0K@@@A@@@@') ; yourself); yourself]
!

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

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class upArrow20x20IconOld'
        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]
!

upArrowIcon
    ^ self upArrow20x20Icon
!

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
          )
         #(#MenuItem
            #label: 'Save Bookmarks In...'
            #translateLabel: true
            #value: #saveBookmarks
          )
         )
        nil
        nil
      )
!

browserMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

    "
     MenuEditor new openOnClass:AbstractFileBrowser andSelector:#browserMenu
     (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser browserMenu)) startUp
    "

    <resource: #menu>

    ^ 
     #(Menu
        (
         (MenuItem
            label: 'Spawn'
            itemValue: doSpawn
            translateLabel: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            label: 'Add Text Editor'
            itemValue: newTextEditor
            translateLabel: true
          )
         (MenuItem
            label: 'Add Shell Terminal'
            itemValue: doAddTerminal
            translateLabel: true
          )
         (MenuItem
            label: 'Add Search Tile'
            itemValue: doOpenSearchFile
            translateLabel: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            label: 'Settings...'
            itemValue: doOpenSettings
            translateLabel: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            label: 'Exit'
            itemValue: closeRequest
            translateLabel: true
          )
         )
        nil
        nil
      )
!

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #enabled: #hasSelection
            #label: 'Update selected Files/Directories'
            #itemValue: #cvsUpdateSelection
            #translateLabel: true
          )
         #(#MenuItem
            #label: 'Update Directory Local'
            #itemValue: #cvsUpdateAll
            #translateLabel: true
          )
         #(#MenuItem
            #label: 'Update Directory Recursive'
            #itemValue: #cvsUpdateAllRecursive
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Commit...'
            #itemValue: #cvsCommit
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #canCvsAddAndCommit
            #label: 'Add && Commit...'
            #itemValue: #cvsAddAndCommit
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #canCvsAddAndCommit
            #label: 'Add as Binary && Commit...'
            #itemValue: #cvsAddBinaryAndCommit
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #enabled: #canRemoveCVSContainer
            #label: 'Remove File && CVS Container...'
            #itemValue: #cvsRemoveFileAndCVSContainer
            #translateLabel: true
          )
         )
        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
            #enabled: #fileListIsNotEmpty
            #label: 'Copy All Filenames'
            #itemValue: #copyFileList
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasSelection
            #label: 'Copy Selected Filenames'
            #itemValue: #copySelectedFilenames
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Settings...'
            #itemValue: #openSettingsDialog
            #translateLabel: true
          )
         )
        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
            keepLinkedMenu: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            enabled: hasSelection
            label: 'Copy'
            itemValue: copyFiles
            translateLabel: true
          )
         (MenuItem
            enabled: hasSelection
            label: 'Cut'
            itemValue: cutFiles
            translateLabel: true
          )
         (MenuItem
            enabled: canPaste
            label: 'Paste'
            itemValue: pasteFiles
            translateLabel: true
          )
         (MenuItem
            enabled: hasSelection
            label: 'Delete'
            itemValue: deleteFiles
            translateLabel: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            enabled: hasSelection
            label: 'Rename...'
            itemValue: renameSelection
            translateLabel: true
            shortcutKey: Replace
          )
         (MenuItem
            enabled: hasSelection
            label: 'Move to...'
            itemValue: moveSelection
            translateLabel: true
          )
         (MenuItem
            enabled: hasSelection
            label: 'Properties...'
            itemValue: doShowProperties
            translateLabel: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            label: 'Operations'
            translateLabel: true
            submenuChannel: fileOpMenu
            keepLinkedMenu: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            label: 'Edit'
            itemValue: doShowFileContents
            translateLabel: true
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            enabled: hasFileSelection
            label: 'FileIn'
            itemValue: fileFileIn
            translateLabel: true
            shortcutKey: Accept
          )
         (MenuItem
            enabled: hasFileSelection
            label: 'FileIn to Namespace...'
            itemValue: fileFileInToNameSpace
            translateLabel: true
          )
         (MenuItem
            label: '-'
            isVisible: javaSupportLoaded
          )
         (MenuItem
            enabled: canAddToClassPath
            label: 'Add to Java Class Path'
            translateLabel: true
            isVisible: javaSupportLoaded
          )
         (MenuItem
            enabled: canRemoveFromClassPath
            label: 'Remove from Java Class Path'
            translateLabel: true
            isVisible: javaSupportLoaded
          )
         (MenuItem
            enabled: canAddToSourcePath
            label: 'Add to Java Source Path'
            translateLabel: true
            isVisible: javaSupportLoaded
          )
         (MenuItem
            enabled: canRemoveFromSourcePath
            label: 'Remove from Java Source Path'
            translateLabel: true
            isVisible: javaSupportLoaded
          )
         (MenuItem
            label: '-'
          )
         (MenuItem
            enabled: enableFileHistory
            label: 'File History'
            translateLabel: true
            submenuChannel: menuFileHistory
          )
         )
        nil
        nil
      )
!

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Split...'
            #itemValue: #splitSelectedFiles
            #translateLabel: true
          )
         #(#MenuItem
            #label: 'Join...'
            #itemValue: #joinSelectedFiles
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Rot13...'
            #itemValue: #filterSelectedFiles:
            #translateLabel: true
            #argument: #rot13
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Truncate...'
            #itemValue: #truncateSelectedFilesToZeroSize
            #translateLabel: true
          )
         )
        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
      )
!

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Hidden Files'
            #translateLabel: true
            #indication: #showHiddenFiles
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Directory Tree'
            #translateLabel: true
            #indication: #showDirectoryTree
          )
         #(#MenuItem
            #label: 'Regular Files in TreeView (Left)'
            #translateLabel: true
            #indication: #viewFilesInDirectoryTree
          )
         #(#MenuItem
            #label: 'Directories in ContentsView (Right)'
            #translateLabel: true
            #indication: #viewDirsInContentsBrowser
          )
         #(#MenuItem
            #enabled: #enableViewNoteBookApplication
            #label: 'File Applications'
            #translateLabel: true
            #indication: #viewNoteBookApplicationHolder
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'DiskUsage'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #showDiskUsageHolder
          )
         )
        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: #sortBlockProperty
            #choiceValue: #baseName
          )
         #(#MenuItem
            #label: 'By Extension'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockProperty
            #choiceValue: #suffix
          )
         #(#MenuItem
            #label: 'By Permissions'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockProperty
            #choiceValue: #permissions
          )
         #(#MenuItem
            #label: 'By Owner'
            #translateLabel: true
            #isVisible: #viewOwner
            #hideMenuOnActivated: false
            #choice: #sortBlockProperty
            #choiceValue: #owner
          )
         #(#MenuItem
            #label: 'By Group'
            #translateLabel: true
            #isVisible: #viewOwner
            #hideMenuOnActivated: false
            #choice: #sortBlockProperty
            #choiceValue: #group
          )
         #(#MenuItem
            #label: 'By Size'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockProperty
            #choiceValue: #fileSize
          )
         #(#MenuItem
            #label: 'By Date && Time'
            #translateLabel: true
            #hideMenuOnActivated: false
            #choice: #sortBlockProperty
            #choiceValue: #modificationTime
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Ignore Case in Sort'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #sortCaseless
          )
         #(#MenuItem
            #label: 'Directories before Files'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #sortDirectoriesBeforeFiles
          )
         )
        nil
        nil
      )
!

toolsMenuSpec
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

    "
     MenuEditor new openOnClass:AbstractFileBrowser andSelector:#toolsMenuSpec
     (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser toolsMenuSpec)) startUp
    "

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Execute Command...'
            #itemValue: #doExecuteCommand
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #canDoTerminal
            #label: 'Shell Terminal'
            #itemValue: #openTerminal
            #translateLabel: true
            #isVisible: #canDoTerminalAndSystemIsUnix
          )
         #(#MenuItem
            #enabled: #canDoTerminal
            #label: 'DOS Terminal'
            #itemValue: #openTerminal
            #translateLabel: true
            #isVisible: #canDoTerminalAndSystemIsDOS
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #enabled: #hasFileSelection
            #label: 'Changes Browser'
            #itemValue: #openChangesBrowser
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasFileSelection
            #label: 'ChangeSet Browser'
            #itemValue: #openChangeSetBrowser
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasSnapshotSelection
            #label: 'Snapshot Image Browser'
            #itemValue: #openSnapshotImageBrowser
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #canCreateNewProject
            #label: 'Create Smalltalk Project'
            #itemValue: #createProjectAndOpenProjectBrowser
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #canReadAbbrevFile
            #label: 'Install Autoloaded'
            #itemValue: #readAbbrevFile
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #anySTFilesPresent
            #label: 'Install all as Autoloaded'
            #itemValue: #installAllAsAutoloaded
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'File Utilities'
            #translateLabel: true
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Editor'
                  #itemValue: #openEditor
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'HTML Reader'
                  #itemValue: #openHTMLReader
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Acroread (PDF Viewer)'
                  #itemValue: #openPDFViewer
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasASN1AndSelection
                  #label: 'ASN1 Browser'
                  #itemValue: #openASN1Browser
                  #translateLabel: true
                  #isVisible: #hasASN1
                )
               #(#MenuItem
                  #enabled: #hasCBrowser
                  #label: 'C Browser'
                  #itemValue: #openCBrowser
                  #translateLabel: true
                  #isVisible: #hasCBrowser
                )
               #(#MenuItem
                  #enabled: #hasJavaAndSelection
                  #label: 'Applet Viewer'
                  #itemValue: #openAppletViewer
                  #translateLabel: true
                  #isVisible: #hasJava
                )
               #(#MenuItem
                  #enabled: #hasMP3PlayerAndSelection
                  #label: 'MP3 Player'
                  #itemValue: #openMP3Player
                  #translateLabel: true
                  #isVisible: #hasMP3Player
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'xv (Image Viewer)'
                  #itemValue: #openXV
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #currentFilesAreInSameDirectory
                  #label: 'Slide Show'
                  #itemValue: #openSlideShow
                  #translateLabel: true
                  #isVisible: #hasSlideShow
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'gv (Postscript Viewer)'
                  #itemValue: #openGV
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'realplay (avi viewer)'
                  #itemValue: #openRP
                  #translateLabel: true
                )
               )
              nil
              nil
            )
          )
         #(#MenuItem
            #label: 'Image'
            #translateLabel: true
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Image Editor'
                  #itemValue: #openImageEditor
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Image Preview'
                  #itemValue: #openImagePreview
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Image Inspector'
                  #itemValue: #openImageInspector
                  #translateLabel: true
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Convert to GIF'
                  #itemValue: #convertImageToGIF
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Convert to PNG'
                  #itemValue: #convertImageToPNG
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Convert to XPM'
                  #itemValue: #convertImageToXPM
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasFileSelection
                  #label: 'Convert to JPG'
                  #itemValue: #convertImageToJPG
                  #translateLabel: true
                )
               )
              nil
              nil
            )
          )
         #(#MenuItem
            #enabled: #hasZipFileSelected
            #label: 'ZipFile Tool'
            #itemValue: #openZipTool
            #translateLabel: true
          )
         #(#MenuItem
            #label: 'Find'
            #translateLabel: true
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'File...'
                  #itemValue: #fileFindFile
                  #translateLabel: true
                )
               #(#MenuItem
                  #label: 'Duplicate Files'
                  #itemValue: #fileFindDuplicates
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasSelection
                  #label: 'All Duplicate Files (Recursive)'
                  #itemValue: #fileFindAllDuplicates
                  #translateLabel: true
                )
               )
              nil
              nil
            )
          )
         #(#MenuItem
            #enabled: #hasSelection
            #label: 'File Differences...'
            #itemValue: #openDiffView
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasFileSelection
            #label: 'Hex Dump'
            #itemValue: #fileHexDump
            #translateLabel: true
          )
         )
        nil
        nil
      )
!

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Hidden Files'
            #translateLabel: true
            #indication: #showHiddenFiles
          )
         )
        nil
        nil
      )
! !

!AbstractFileBrowser class methodsFor:'misc'!

newLock
    ^ CodeExecutionLock new
! !

!AbstractFileBrowser class methodsFor:'utilities'!

contentsOfFileAsHexDump:f
    |resources fileName stream data offs 
     addrDigits col line lineStream asciiLineStream lines|

    resources := self classResources.

    fileName := f baseName.
    f isDirectory ifTrue:[
        Dialog warn:(resources string:'%1 is a directory.' with:fileName).
        ^ nil
    ].
    f exists ifFalse:[
        Dialog warn:(resources string:'oops, ''%1'' is gone or unreadable.' with:fileName).
        ^ nil
    ].
    f isReadable ifFalse:[
        Dialog warn:(resources string:'''%1'' is unreadable.' with:fileName).
        ^ nil
    ].
    f fileSize > (512*1024) ifTrue:[
        (Dialog confirm:(resources 
                    string:'Warning: the file is big (%1b). Show anyway ?' 
                    with:(UnitConverter fileSizeStringFor:f fileSize)))
        ifFalse:[
            ^ nil
        ]
    ].

    stream := f readStream binary.
    data := stream contents.
    stream close.

    col := 1.
    offs := 0.
    lines := StringCollection new.

    addrDigits := ((f fileSize + 1) log:16) truncated + 1.

    lineStream := '' writeStream.
    asciiLineStream := '' writeStream.

    lineStream nextPutAll:(offs hexPrintString:addrDigits).
    lineStream nextPutAll:': '.

    data do:[:byte |
        lineStream nextPutAll:(byte hexPrintString:2).
        (byte between:32 and:127) ifTrue:[
            asciiLineStream nextPut:(Character value:byte)
        ] ifFalse:[
            asciiLineStream nextPut:$.
        ].

        offs := offs + 1.
        col := col + 1.
        col > 16 ifTrue:[
            lineStream nextPutAll:'        '.
            lineStream nextPutAll:asciiLineStream contents.
            lines add:(lineStream contents).
            (offs bitAnd:16rFF) == 0 ifTrue:[
                lines add:nil
            ].
            lineStream reset.
            asciiLineStream reset.

            lineStream nextPutAll:(offs hexPrintString:addrDigits).
            lineStream nextPutAll:': '.
            col := 1.
        ] ifFalse:[
            lineStream space
        ]
    ].
    line := lineStream contents paddedTo:(3*16 + addrDigits + 1).
    lines add:(line , '        ' , asciiLineStream contents).
    ^ lines
! !

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

    osName := OperatingSystem platformName.

    box := FilenameEnterBox 
                title:(resources string:'Execute %1 command:' with:osName)
               okText:(resources string:'Execute')
               action:[:cmd | commandString := cmd].

    fileName notNil ifTrue:[
        self initialCommandFor:fileName into:box.
    ].
    box directory:(self getDirWithoutFileName:fileName).
    box show.
    box destroy.

    commandString notNil ifTrue:[
        aBlock value:commandString
    ].

    "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 
        applicationNamed:#FileBrowserV2 
        ifPresentDo:[:app | app changeFileBrowserTitleTo:aString]
!

copyFileList
    "copy the fileList to the clipBoard"

    |fileList|

    fileList := self 
                    applicationNamed:#DirectoryContentsBrowser 
                    ifPresentDo:[:app | app browserFileList].

    fileList notNil ifTrue:[
        self copyFileListToClipBoard:fileList.
    ]
!

copyFileListToClipBoard:fileList
    "copy the itemList to the clipBoard"

    |stream|

    fileList isEmpty ifTrue:[^ self].

    stream := WriteStream on:''.
    fileList do:[:fileName |
        (fileName baseName ~= '..') ifTrue:[
            stream nextPutLine:(fileName asString).
        ]
    ].
    self window setTextSelection:stream contents.
    stream close.
!

copySelectedFilenames
    "copy the selected fileNames to the clipBoard"

    |fileList|

    fileList := self 
                    applicationNamed:#DirectoryContentsBrowser 
                    ifPresentDo:[:appl | appl selectedFileNames].
    fileList notNil ifTrue:[
        self copyFileListToClipBoard:fileList.
    ].
!

doAddTerminal
    |dir directories|

    directories := self currentDirectories value.
    
    directories isEmpty ifTrue:[
        dir :=  Filename homeDirectory
    ] ifFalse:[
        dir :=  directories first.
    ].

    self 
        applicationNamed:#FileApplicationNoteBook
        ifPresentDo:[:appl | appl addTerminalIn:dir].
!

doCompareTwoFiles

    self openDiffView.
!

doExecuteCommand

    | action  fileName|
    fileName := self firstSelectedFile.
    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.
        directories isEmpty ifTrue:[ ^ self].
        upDir := directories first directory.
    ] ifFalse:[
        rootInTreeView := self 
                            applicationNamed:#DirectoryTreeBrowser 
                            ifPresentDo:[:appl | appl 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|

    files := self currentFileNameHolder value.
    files notEmpty ifTrue:[
        item := DirectoryContentsBrowser itemClass fileName:(files first).
    ] ifFalse:[
        item := DirectoryContentsBrowser itemClass fileName:(Filename homeDirectory asAbsoluteFilename).
    ].
    self openSearchFileOn:item.
!

doShowFileContents
    self 
        applicationNamed:#DirectoryContentsBrowser 
        ifPresentDo:[:appl | ^ appl doShowFileContents].

    ^ nil
!

doShowProperties

    "show long stat (file)-info"

    self fileGetInfo:true
!

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 show.
        updater terminate.
        box destroy
    ]
!

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

    currentSel := self currentFileNameHolder value.
    (currentSel includes:aFilename) ifFalse:[
        self currentFileNameHolder 
            value:(OrderedCollection with:(aFilename asAbsoluteFilename)).
    ].
!

newTextEditor
    self 
        applicationNamed:#FileApplicationNoteBook
        ifPresentDo:[:appl | ^ appl newTextEditor].

    ^ nil.
!

openApplByFileItem:anItem
    ^ self 
        applicationNamed:#FileApplicationNoteBook
        ifPresentDo:[:appl | appl openApplByFileItem:anItem].
!

openApplForFile:aFilename
    ^ self openApplByFileItem:(DirectoryContentsBrowser itemClass fileName:aFilename).
!

openCommandResultApplication

    self 
        applicationNamed:#FileApplicationNoteBook
        ifPresentDo:[:appl | ^ appl openCommandResultApplication].

    ^ nil
!

openNewTextEditorOn:anItem
    self 
        applicationNamed:#FileApplicationNoteBook
        ifPresentDo:[:appl | ^ appl openNewTextEditorOn:anItem ].

    ^ nil
!

openSearchFileOn:anItem
    self 
        applicationNamed:#FileApplicationNoteBook
        ifPresentDo:[:appl | ^ appl openSearchFileOn:anItem].

    ^ nil.
!

openTextEditorForFile:aFilename
    ^ self openTextEditorOn:(DirectoryContentsBrowser itemClass fileName:aFilename).
!

openTextEditorOn:anItem
    self 
        applicationNamed:#FileApplicationNoteBook
        ifPresentDo:[:appl | ^ appl openTextEditorOn:anItem ].

    ^ nil.
!

openTextEditorOn:anItem type:aDirDescrOrFile
    self 
        applicationNamed:#FileApplicationNoteBook
        ifPresentDo:[:appl | ^ appl openTextEditorOn:anItem type:aDirDescrOrFile].

    ^ nil.
!

updateAndSelect:aColOfFiles
    self updateCurrentDirectory.
    aColOfFiles notNil ifTrue:[ 
        self currentFileNameHolder value:aColOfFiles 
    ].
!

updateCurrentDirectory
    DirectoryContents flushCachedDirectoryFor:(self getBestDirectory).

    self 
        applicationNamed:#DirectoryContentsBrowser 
        ifPresentDo:[:appl | appl doUpdate].
    self 
        applicationNamed:#DirectoryTreeBrowser     
        ifPresentDo:[:appl | appl doUpdate].
!

withActivityIndicationDo:aBlock

    self activityVisibilityChannel value:true.
    [
        aBlock value.
    ] ensure:[
        self activityVisibilityChannel value:false.
    ]
! !

!AbstractFileBrowser methodsFor:'actions bookmarks'!

addBookmark
    |directories|

    self currentFilesAreInSameDirectory ifFalse:[^ self].
    directories := self currentDirectories value.
    self addBookmarks:directories.
    self class saveBookmarksIn:(self class defaultBookMarksFileDirectory construct:self class defaultBookMarksFilename)
!

addBookmarks:aColOfDirectories
    aColOfDirectories do:[ :path |
        self class addBookmark:path
    ].
!

hasBookmarks
    ^ self class hasBookmarks
!

hasBookmarksToRemove

    |bookmarks directories|

    directories := self currentSelectedDirectories.
    bookmarks := self class directoryBookmarks.
    ^ (bookmarks size > 0 and:[directories notEmpty])
!

removeBookmark
    self currentSelectedDirectories do:[:dir|
        self class removeBookmark:dir
    ].
!

saveBookmarks
     self class saveBookmarks
! !

!AbstractFileBrowser methodsFor:'actions history'!

addToCommandHistory:aCommandString for:aFilename
    |cmd suffix cmdHist|

    cmdHist := self class commandHistory.
    (aCommandString notNil and:[aCommandString notEmpty]) ifTrue:[
        cmdHist notNil ifTrue:[
            cmdHist addFirst:aCommandString.
            cmdHist size > self class commandHistorySize ifTrue:[
                cmdHist removeLast
            ]
        ].
        aFilename notNil ifTrue:[
            cmd := aCommandString copyTo:(aCommandString indexOf:Character space ifAbsent:[aCommandString size + 1])-1.
            DefaultCommandPerSuffix isNil ifTrue:[
                DefaultCommandPerSuffix := Dictionary new.
            ].
            suffix := aFilename asFilename suffix.
            suffix notNil ifTrue:[
                DefaultCommandPerSuffix at:suffix put:cmd.
            ]
        ]
    ]
!

doBack

    | fileName|

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

doForward

    | fileName|

    fileName := self dirHistory goForward.
    fileName notNil ifTrue:[
        self gotoFile:(fileName asFilename).
    ] ifFalse:[
        self enableForward value:false.

    ].
! !

!AbstractFileBrowser methodsFor:'applications'!

applicationNamed:anApplicationName ifPresentDo:aBlock
    |appl|

    appl := self applications at:anApplicationName ifAbsent:nil.
    appl notNil ifTrue:[
        ^ aBlock value:appl
    ].
    ^ nil.
!

directoryContentsBrowser
    ^ self applications at:#DirectoryContentsBrowser ifAbsent:nil.
! !

!AbstractFileBrowser methodsFor:'aspects'!

applications
    "returns the list of registered applications
    "
    ^ aspects at:#applications
!

backgroundProcesses

    ^ self aspectFor:#backgroundProcesses ifAbsent:[List new]
!

canMake
    ^ self hasFileSelection
!

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

currentDirectory
    "return the single current directory or nil"

    |directories|

    directories := self currentDirectories value.
    (directories size ~= 1) ifTrue:[
        ^ nil
    ].
    ^ directories first.
!

currentFileNameHolder
    "return a ValueHolder with an OrderedCollection containing all selected files.
     If no file but a directory is selected it contains the directories 
     in contrast to currentDirectories which have only the directories"

    ^ self aspectFor:#currentFileNameHolder ifAbsent:[
            |currentSel|    

            currentSel := self class currentSelection.
            currentSel isEmpty ifTrue:[
                currentSel := OrderedCollection with:(Filename currentDirectory asAbsoluteFilename)
            ].
            currentSel asValue
        ] notPresentDo:[:holder|
            |filenames newFilenames|
            filenames := holder value.
            newFilenames := Set new.
            filenames do:[:eachFilename|  |existingFilename|
                existingFilename := eachFilename. 
                existingFilename notNil ifTrue:[
                    [existingFilename exists] whileFalse:[
                        existingFilename := existingFilename directory.
                    ].
                    newFilenames add:existingFilename.
                ]
            ].
            newFilenames asOrderedCollection.
        ]
!

enableDirectoryUp

    ^ self aspectFor:#enableDirectoryUp ifAbsent:[false asValue]
!

enableGotoDefault

    ^ self aspectFor:#enableGotoDefault ifAbsent:[ true asValue ].
!

enableHome

    ^ self aspectFor:#enableHome ifAbsent:[ true asValue ].
!

enableViewNoteBookApplication

    ^ self aspectFor:#enableViewNoteBookApplication ifAbsent:[false asValue]
!

hasFileSelection

    ^ self aspectFor:#hasFileSelection ifAbsent:[ false asValue ].
!

hasSelection

    ^ self aspectFor:#hasSelection ifAbsent:[ false asValue ].
!

hasTwoFilesSelectedHolder
    ^ self aspectFor:#hasTwoFilesSelectedHolder
        ifAbsent:[
            BlockValue 
                with:[self hasTwoFilesSelected]
                argument:self currentFileNameHolder
        ].
!

notify:aString
    self notifyChannel value:aString
!

notifyChannel

    ^ self aspectFor:#notifyChannel ifAbsent:['' asValue]
!

rootHolder
    "holder, which keeps the rootHolder of the treeView
    "

    ^ self aspectFor:#rootHolder ifAbsent:[
        self class rootHolder asValue.
    ].
! !

!AbstractFileBrowser methodsFor:'aspects handling'!

aspectFor:something ifAbsent:aBlock
    "returns the model for an aspect
    "
    ^ self aspectFor:something ifAbsent:aBlock notPresentDo:nil
!

aspectFor:aKey ifAbsent:aBlock notPresentDo:notPresentBlock
    "return the model for an aspect"

    |holder saveAspectItem aspect|

    holder := aspects at:aKey ifAbsent:[
        masterApplication notNil ifTrue:[
            holder := masterApplication aspectOrNil:aKey forSubApplication:self.
        ].
        holder isNil ifTrue:[
            saveAspectItem := self runtimeAspectValueFor:aKey.
            saveAspectItem notNil ifTrue:[
                saveAspectItem isHolder ifTrue:[
                    holder := ValueHolder with:saveAspectItem value 
                ] ifFalse:[
                    holder := saveAspectItem value 
                ].
            ] ifFalse:[
                aspect := self userPreferencesAspectValueFor:aKey.
                aspect notNil ifTrue:[ 
                    holder := aspect asValue
                ] ifFalse:[
                    holder := aBlock value.
                ]
            ].
        ].
        holder notNil ifTrue:[  
            notPresentBlock notNil ifTrue:[
                holder value:(notPresentBlock value:holder).
            ].
            aspects at:aKey put:holder
        ].
        holder
    ].
    ^ holder
!

aspectFor:something put:aValueHolder
    aspects at:something put:aValueHolder
!

aspects
    ^ aspects
!

runtimeAspectValueFor:something
    "returns the default aspect item from the class variable RuntimeAspects
    "
    ^ self class runtimeAspects at:something ifAbsent:nil.
!

saveAspectValues
    |saveAspects aspectValue|


    saveAspects := self class userPreferencesAspectList.
    saveAspects do:[ : aspectKey |
        aspectValue := (self perform:aspectKey) value.
        UserPreferences current perform:((aspectKey asString, ':') asSymbol) with:aspectValue.
    ].
!

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

userPreferencesAspectValueFor:something
    "returns the default aspect from the Userpreferences
    "

    (self class userPreferencesAspectList includes:something) not ifTrue:[ ^ nil].
    ^ UserPreferences current perform:something.
! !

!AbstractFileBrowser methodsFor:'aspects-filter'!

filterBackgroundColor

    ^ self aspectFor:#filterBackgroundColor ifAbsent:[Color white asValue]
!

filterBlockHolder

    ^ self aspectFor:#filterBlockHolder ifAbsent:[self getFilter asValue]
!

filterListModel

    ^ self aspectFor:#filterListModel ifAbsent:[self class defaultFilterList]
!

filterModel

    ^ self aspectFor:#filterModel ifAbsent:[(self filterListModel at:1) asValue]
!

filterValueBox

    ^ self aspectFor:#filterValueBox ifAbsent:[ValueHolder new]
!

getFilter
    | filter showHidden yesOrNo|

    filter := self filterModel value.
    filter = '' ifTrue:[filter := '*'].
    yesOrNo := true.
    (filter startsWith:'~') ifTrue:[
        yesOrNo := false.
        filter := filter copyFrom:2.
    ].
    showHidden := self showHiddenFiles value.
    showHidden ifTrue:[
        ^ [: el | (filter match:el) == yesOrNo].
    ] ifFalse:[
        ^ [: el | ((el asString startsWith:'.') not) and:[(filter match:el) == yesOrNo]].
    ]
!

shownFiles

    ^ self aspectFor:#shownFiles ifAbsent:['-/-' asValue]
! !

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

activityVisibilityChannel
    " activityVisibilityChannel switches the activity indicator on/off
    "

    ^ self aspectFor:#activityVisibilityChannel ifAbsent:[ false asValue ].
!

openAlwaysInTextEditor
    " aspect for open every file in TextEditor dont use e.g. HtmlEditor for *.html'"

    ^ self aspectFor:#openAlwaysInTextEditor ifAbsent:[ false asValue ].
!

openMultipleApplicationsForType

    " aspect for open more applications for e.g. TextEditor and not change the contents of already 
      open TextEditor "

    ^ self aspectFor:#openMultipleApplicationsForType ifAbsent:[ false asValue ].
!

showDirectoryTree

    ^ self aspectFor:#showDirectoryTree ifAbsent:[ true asValue ]
!

showDiskUsageHolder
    |holder|

    holder := self aspectFor:#showDiskUsageHolder ifAbsent:[ false asValue].
    holder addDependent:self.
    ^ holder
!

showHiddenFiles

    ^ self aspectFor:#showHiddenFiles ifAbsent:[ true asValue ].
!

userContextAvailable

    " aspect for show group and user columns in contents view
      windows provides no user context"

    ^ OperatingSystem isMSWINDOWSlike not 
!

viewDescription
    "aspect for show file description in DirectoryContentsBrowser"

    ^ self directoryContentsBrowser viewDescription
!

viewDetails
    "aspect for show more file properties in DirectoryContentsBrowser 
    "

    ^ self directoryContentsBrowser viewDetails
!

viewDirectoryDescription

    " aspect for auto open a TextView for Readme and other see getInfoItem Method files 
      on change directory "

    ^ self aspectFor:#viewDirectoryDescription ifAbsent:[ true asValue ].
!

viewDirsInContentsBrowser

    ^ self aspectFor:#viewDirsInContentsBrowser ifAbsent:[ false asValue ].
!

viewFilesInDirectoryTree

    " aspect for view files in tree view (not only directories) "

    ^ self aspectFor:#viewFilesInDirectoryTree ifAbsent:[ false asValue ].
!

viewGroup
    " aspect for show group information in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewGroup
!

viewIcon
    " aspect for show file-type icon in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewIcon
!

viewInodeNumber
    " aspect for show inode numbers in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewInodeNumber
!

viewNoteBookApplicationHolder

    ^ self aspectFor:#viewNoteBookApplicationHolder ifAbsent:[ false asValue].
!

viewOwner
    " aspect for show owner information in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewOwner
!

viewPermissions
    " aspect for show permission information in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewPermissions
!

viewPreview
    " aspect for show image previev in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewPreview
!

viewSize
    " aspect for show size information in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewSize
!

viewSizeInBytes
    " aspect for show size-in-bytes information in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewSizeInBytes
!

viewSizeInKiloBytes
    " aspect for show size-in-kilobytes information in DirectoryContentsBrowser "

    ^ self directoryContentsBrowser viewSizeInKiloBytes
!

viewTime
    " aspect for show time information in DirectoryContentsBrowser"

    ^ self directoryContentsBrowser viewTime
!

viewType
    " aspect for show suffix (type) information in DirectoryContentsBrowser"

    ^ self directoryContentsBrowser viewType
! !

!AbstractFileBrowser methodsFor:'background processing'!

executeCommand:cmd

    self executeCommand:cmd inDirectory:nil
!

executeCommand:cmd inDirectory:aDir

    | nameString executionBlock|

    executionBlock := self getExecutionBlockForCommand:cmd inDirectory:aDir.
    nameString := 'Execute: ', 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 currentSelectedDirectories.
        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 notify:'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] 
                    ensure:[
                        self backgroundProcesses remove:process ifAbsent:[].
                        appl process value:nil.

                        "/ close automatically, if there was no output.
"/                        appl resultStream contents isEmpty ifTrue:[
"/                            appl doClose.
"/                        ]
                    ]
               ] newProcess.
    process priority:(Processor userBackgroundPriority).
    process name:nameString.
    self backgroundProcesses add:process.
    appl process value:process.
    process resume.
! !

!AbstractFileBrowser methodsFor:'change & update'!

currentFileNameHolderChanged
    "/ self currentFileNameHolderChangedForCommon
!

currentFileNameHolderChangedForCommon
    |newDirectories oldDirectories size rootInTreeView selection|

    selection := self currentFileNameHolder value.
    self class currentSelection:selection.

    self hasSelection value:(selection notEmpty).
    self hasFileSelection value:(self firstSelectedFile notNil).

    newDirectories := self directoriesForFiles:selection.
    oldDirectories := self currentDirectories value.
    oldDirectories ~= newDirectories ifTrue:[
        self currentDirectories value:newDirectories.
        size := newDirectories size.
        rootInTreeView := self 
                            applicationNamed:#DirectoryTreeBrowser 
                            ifPresentDo:[:appl | appl rootHolder].
        rootInTreeView := rootInTreeView value.
        self enableDirectoryUp value:(((size == 1) and:[newDirectories first isRootDirectory not]) or:[(rootInTreeView notNil and:[rootInTreeView value asFilename isRootDirectory not])]).
        newDirectories notEmpty ifTrue:[
            self dirHistory addToHistory:(newDirectories first asString).
        ].
        self enableHome value:((newDirectories includes:(Filename homeDirectory asAbsoluteFilename))not).
        self enableGotoDefault value:((newDirectories includes:(Filename defaultDirectory asAbsoluteFilename))not).
    ].
    self enableForward value:self canForward.
    self enableBack    value:self canBackward.
!

filterModelChanged

    self filterBlockHolder value:(self getFilter).
!

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 "

    changedObject == self currentFileNameHolder ifTrue:[
        self currentFileNameHolderChangedForCommon.
        ^ self
    ].
    changedObject == self sortCaseless ifTrue:[
        self sortFileListsBy:#baseName withReverse:false.
        ^ self
    ].             
    (changedObject == self filterModel or:[changedObject == self showHiddenFiles]) ifTrue:[
        self filterModelChanged.
        ^ self
    ].
    changedObject == self rootHolder ifTrue:[
        self class rootHolder:(self rootHolder value).
        ^ self
    ].
    changedObject == self showDiskUsageHolder ifTrue:[
        self notify:''.
        ^ 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 notify:stream contents.
    stream close.
    clp files:colOfFiles.
    self canPaste value:true.
! !

!AbstractFileBrowser methodsFor:'drag & drop'!

canDropFiles:dropedObjects for:filename 
    | filenameDirString filenameDir|

    dropedObjects isEmpty ifTrue:[^ false].
    filenameDir := self getDirWithoutFileName:filename.
    filenameDir isWritable not ifTrue:[^ false].
    filenameDirString := filenameDir asString.

    dropedObjects do:[:aDropObject | 
        |dropFileName dropFileNameString|
        dropFileName := aDropObject theObject.
        dropFileNameString := dropFileName asString.
        dropFileName isDirectory ifTrue:[
            (self fileName:filenameDirString startsWith:dropFileNameString) ifTrue:[
                self notify:'Cannot drop a directory into one of its parent directories'.
                ^ false
            ]
        ] ifFalse:[
            (filenameDirString = dropFileName directory asString 
            or:[ aDropObject isFileInArchive not
                 and:[ filenameDirString = dropFileName physicalPathName asFilename directory asString] ]) ifTrue:[
                self notify:'Cannot drop a file into 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 getCopyClass copyFile:aSourceFile to:aDestFile withOverWriteWarning:true copyFileIfSame:true.
    copy result ifTrue:[
        self notify:('copy ', aSourceFile baseName, ' to:,', aDestFile baseName).
    ] ifFalse:[
        self notify:copy errorString.
    ].
    ^ copy result
!

copyFiles:aColOfSourceFiles to:aDirectory 
   "copy aColOfSourceFiles to aDirectory
   "
    |copy|

    self withWaitCursorDo:[
        copy := FileOperation getCopyClass copyFiles:aColOfSourceFiles to:aDirectory.
        copy result ifFalse:[
            self notify:copy errorString.
        ].
        self updateCurrentDirectory.
    ].
    ^ copy colOfCopiedFiles
!

copyOrMoveDialog:aCollectionOfFiles for:aDestinationDirectory
    |size stream msg answer file|

    size := aCollectionOfFiles size.

"/    stream := WriteStream on:'' asText.
"/    stream nextPutAll:'Copy or move'; cr; cr; nextPutAll:'file'.
"/    size == 1 ifFalse:[
"/        stream nextPutAll:'s'.
"/    ].
"/    stream nextPutAll:': '.
"/    stream nextPutAll:aCollectionOfFiles first baseName asString allBold.
"/    size == 1 ifFalse:[
"/        stream nextPutAll:' ... '.
"/        stream nextPutAll:aCollectionOfFiles last baseName asString.
"/    ].
"/    stream cr; nextPutAll:'to: '.
"/    stream nextPutAll:aDestinationDirectory asFilename pathName allBold.
"/    msg := stream contents
    size == 1 ifTrue:[
        file := aCollectionOfFiles first.
        msg := resources    
                stringWithCRs:'Copy or move\\%1:\    %2\to:\    %3 ?'
                with:(file type == #regular ifTrue:'file' ifFalse:[file isDirectory ifTrue:'directory' ifFalse:'object'])
                with:(file baseName allBold)
                with:(aDestinationDirectory asFilename pathName allBold).
    ] ifFalse:[
        msg := resources    
                stringWithCRs:'Copy or move\\    %1 objects\to:\    %2 ?'
                with:size
                with:(aDestinationDirectory asFilename pathName allBold).
    ].

    answer := OptionBox 
                  request:msg 
                  label:'Move or Copy'
                  form:(WarningBox iconBitmap)
                  buttonLabels:#('Cancel' 'Move' 'Copy' 'Copy As...')
                  values:#(#cancel #move #copy #copyAs)
                  default:#copy.
    answer isNil ifTrue:[answer := #cancel].
    ^ answer.
!

copyOrMoveFiles:aColOfSourceFiles to:aDestinationDirectory 
    "copy or move aColOfSourceFiles to aDirectory.
     Asks the used if a move or a copy is wanted.
     Returns true if the copyOrMove happened, false if user aborted the operation."

    |answer lastOld lastNew|

    answer := self copyOrMoveDialog:aColOfSourceFiles for:aDestinationDirectory.
    answer == #copyAs ifTrue:[
        aColOfSourceFiles do:[:eachSourceFile |
            |initial destFile srcBase dstBase|

            srcBase := eachSourceFile asFilename baseName.
            lastOld isNil ifTrue:[
                initial := srcBase
            ] ifFalse:[
                initial := DoWhatIMeanSupport
                            goodRenameDefaultForFile:srcBase lastOld:lastOld lastNew:lastNew.
            ].
            dstBase := Dialog request:('Copy %1 as:' bindWith:srcBase) initialAnswer:initial.
            dstBase isNil ifTrue:[^ false].
            self copyFile:eachSourceFile to:(aDestinationDirectory construct:dstBase).
            lastOld := srcBase.
            lastNew := dstBase.
        ].

        ^ true.
    ].
    answer == #copy ifTrue:[
        self copyFiles:aColOfSourceFiles to:aDestinationDirectory.
        ^ true.
    ].
    answer == #move ifTrue:[
        self moveFiles:aColOfSourceFiles to:aDestinationDirectory.
        ^ true.
    ].
    ^ false.
!

deleteFile:aFile
    "delete current selected files/directories
    "

    ^ self deleteFiles:(OrderedCollection with:aFile).
!

deleteFiles:colOfFiles
    "delete current selected files/directories
    "
    ^ self deleteFiles:colOfFiles confirm:true.
!

deleteFiles:colOfFiles confirm:confirm
    "delete current selected files/directories
    "
    |delete|

    self windowGroup withWaitCursorDo:[
        delete := FileOperation getDeleteClass deleteFiles:colOfFiles confirm:confirm.
        delete result ifFalse:[
            self notify:delete errorString.
        ].
        self updateCurrentDirectory.
    ].
    ^ delete result.
!

moveFile:aSourceFile to:aDestFile
    "defete current selected files/directories
    "

    |move|

    move := FileOperation getMoveClass moveFile:aSourceFile to:aDestFile.
    move result ifTrue:[
        self notify:('move ', aSourceFile asString, ' to ', aDestFile asString).
    ] ifFalse:[
        self notify:move errorString.
    ].
    self updateCurrentDirectory.
    ^ move result
!

moveFiles:aColOfSourceFiles to:aDirectory 
   "move aColOfSourceFiles to aDirectory
   "
    |move|

    self windowGroup withWaitCursorDo:[
        move := FileOperation getMoveClass moveFiles:aColOfSourceFiles to:aDirectory.
        move result ifFalse:[
            self notify:move errorString.
        ].
        self updateCurrentDirectory.
    ].
    ^ move colOfMovedFiles
!

moveSelection
    "move the selected file(s) to another directory"

    |destinationDirectory|

    destinationDirectory := Dialog 
                                requestDirectoryName:(resources at:'Move Selected Items To:') withCRs 
                                default:(self currentDirectory)
                                ok:'Move'
                                abort:nil.
    destinationDirectory isEmptyOrNil ifTrue:[^ self].

    self moveFiles:(self currentFileNameHolder value deepCopy) to:destinationDirectory asFilename
!

newDirectory
    "ask for and create a new directory"

    |selectedFiles singleSelectedFile defaultAnswer directory createOp newFile mime|

    directory := self currentDirectory.
    directory isNil ifTrue:[
        self warn:'Select a single directory to create a directory'.
        ^ self
    ].

    "/ clever default if selection is an archive...
    selectedFiles := self currentSelectedFiles.
    selectedFiles size == 1 ifTrue:[
        singleSelectedFile := selectedFiles first.

        mime := MIMETypes mimeTypeForFilename:singleSelectedFile.
        (mime notNil and:[mime isArchive]) ifTrue:[
            defaultAnswer := singleSelectedFile asFilename withoutSuffix baseName.

            mime := MIMETypes mimeTypeForFilename:defaultAnswer.
            (mime notNil and:[mime isArchive]) ifTrue:[
                defaultAnswer := defaultAnswer asFilename withoutSuffix baseName
            ].
        ].
    ].

    createOp := FileOperation getCreateClass new.
    defaultAnswer notNil ifTrue:[
        createOp createDirectoryIn:directory initialAnswer:defaultAnswer.
    ] ifFalse:[
        createOp createDirectoryIn:directory.
    ].
    createOp result ifFalse:[ ^ self].
    newFile := createOp createdFile.
    newFile notNil ifTrue:[
        self updateCurrentDirectory.
    ]
!

newFile
    "ask for and create a new file"

    | curFile directory create file|

    directory := self currentDirectory.
    directory isNil ifTrue:[
        self warn:'Select a single directory to create a file.'.
        ^ self.
    ].

    curFile := self firstSelectedFile.
    curFile notNil ifTrue:[
        file := curFile.
    ] ifFalse:[
        file := directory.
    ].
    create := FileOperation getCreateClass 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 dir create createdFile|

    sel := self currentFileNameHolder value.
    (sel size ~= 1) ifTrue:[
        self warn:'Select one directory to link'.
        ^ self
    ].
    dir := sel first.

    symbolic ifTrue:[
        create := FileOperation getCreateClass createSoftLinkIn:dir.
    ] ifFalse:[
        create := FileOperation getCreateClass createHardLinkIn:dir.
    ].
    create result ifFalse:[ ^ self].
    createdFile := create createdFile.
    createdFile notNil ifTrue:[
        symbolic ifTrue:[
            self updateCurrentDirectory.
        ] ifFalse:[
            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 currentSelectedDirectories.
    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 show.
        box destroy.
    ] ifFalse:[
        destination := directories first.
    ].
    (self clipboard method == #cut) ifTrue:[
        buffer files copy do:[:aFile|
            aFile directory = destination ifTrue:[
                buffer files remove:aFile.
            ].
        ].
    ].
    copiedFiles := self copyFiles:(buffer files) to:destination.
    (self clipboard method == #cut) ifTrue:[
        self deleteFiles:copiedFiles confirm:false.
    ]. 
!

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 getRenameClass renameFile:filename to:newFileString.
    rename result ifTrue:[
        aBoolean ifTrue:[
            self updateAndSelect:(rename renamedFiles).
        ].
    ] ifFalse:[
        self notify:rename errorString.
    ].
    ^ rename result
!

renameFiles:aColOfFiles 
    "rename the selected file(s)"

    |rename|

    rename := FileOperation getRenameClass renameFiles:aColOfFiles.
    rename result ifFalse:[
        self notify:rename errorString
    ] ifTrue:[
        self updateAndSelect:nil. "/ (rename renamedFiles)
    ].
    ^ rename result
!

renameSelection
    "rename the selected file(s)"

    self renameFiles:(self currentFileNameHolder value deepCopy)
! !

!AbstractFileBrowser methodsFor:'menu accessing'!

bookmarksMenuSpec
    <resource: #programMenu>

    |menu bookmarks|

    menu := self class baseBookmarksMenuSpec decodeAsLiteralArray.
    menu findGuiResourcesIn:self.
    menu receiver:self.

    "/ add the bookmark items ...
    bookmarks := self class directoryBookmarks.
    bookmarks notEmptyOrNil 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"
!

canBackward


    ^ self dirHistory canBackward.
!

canForward

    ^ 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 getBackCollection.
    ] ifFalse:[
        pathList := self dirHistory getForwardCollection.
    ].
    pathList isEmpty ifTrue:[ ^ nil].
    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 findGuiResourcesIn:self.
    menu receiver:self.

    hist := self fileHistory.
    hist isEmpty ifTrue:[^ nil].

    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 new.
    removeItem translateLabel:true.
    text := resources string:'Clear History'.
    "/ text := LabelAndIcon icon:(self class clearHistoryIcon) string:text.
    removeItem label:text.
    removeItem value:[
        self fileHistory removeAll.
        self enableFileHistory value:false.
    ].
    menu addItem:(MenuItem label:'-').
    menu addItem:removeItem.
    ^ menu
!

sortMenu

    <resource: #programMenu >

    |menu|

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

viewDetailsMenuSpec
    |specContentsBrowser itemsContentsBrowser specHere itemsHere spec| 

    specHere := self class viewDetailsMenuSpec.
    itemsHere := specHere at:2.

    specContentsBrowser := self directoryContentsBrowser class viewBrowserMenuSpec.
    itemsContentsBrowser := (specContentsBrowser at:2).

    spec := specHere copy.
    spec at:2 put:(itemsContentsBrowser , itemsHere).
    ^ spec
!

viewInContentsBrowserMenu
    self 
        applicationNamed:#DirectoryContentsBrowser 
        ifPresentDo:[:appl | ^ appl viewBrowserMenu].

    ^ nil.
!

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:(resources string:'Clear History').
    text := (resources string:'Clear History').
    removeItem := MenuItem new.
    removeItem translateLabel:true.
    removeItem label:text.
    removeItem value:[
        self dirHistory removeAll.
        self enableForward value:self canForward.
        self enableBack value:self canBackward.
    ].
    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 actions-cvs'!

cvsAddAndCommit
    self cvsAddAndCommitAsBinary:false
!

cvsAddAndCommitAsBinary:asBinary

    |sel log cmd dir executionBlock nameString block|

    log := Dialog
        requestText:(resources string:'Enter initial log message')
        lines:10
        columns:70
        initialAnswer:nil.

    sel := self currentSelectedFiles.
    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.

                    cmd := ('cvs commit -l -m ''' , log , ''' ' , fn baseName).
                    block := self getExecutionBlockForCommand:cmd inDirectory:dir.
                    block value:stream.

                    cmd := ('cvs admin -kb ' , fn baseName).
                    block := self getExecutionBlockForCommand:cmd inDirectory:dir.
                    block value:stream.

                    cmd := ('cvs upd ' , fn baseName).
                    block := self getExecutionBlockForCommand:cmd inDirectory:dir.
                    block value:stream.
                ]
            ] 
        ]
    ].
    nameString := 'Command> cvs add and commit'.
    self makeExecutionResultProcessFor:executionBlock withName:nameString.
!

cvsAddBinaryAndCommit
    self cvsAddAndCommitAsBinary:true
!

cvsCommit

    |nSel log msg cmd selectedFiles sel executionBlock nameString|

    selectedFiles:= self currentSelectedFiles.
    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 isNil ifTrue:[^ self].
    sel := self currentFileNameHolder value.
    sel isEmpty ifTrue:[ ^ self ].
    executionBlock := [:stream |
        log notNil ifTrue:[
            sel size > 0 ifTrue:[
                sel do:[:fn |
                    | dir block |
                    dir := fn directory.
                    cmd := ('cvs commit -m ''' , log , ''' ' , fn baseName).
                    block := self getExecutionBlockForCommand:cmd inDirectory:dir.
                    block value:stream.
                ]
            ] 
        ]
    ].
    nameString := 'Command> cvs commit'.
    self makeExecutionResultProcessFor:executionBlock withName:nameString.
!

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> cvs remove and commit ', filesToRemove first baseName.
    filesToRemove size > 1 ifTrue:[
        nameString := nameString, ' ...'.
    ].
    self makeExecutionResultProcessFor:executionBlock withName:nameString.
!

cvsRemoveFileAndCVSContainer

    |sel question aswer|

    sel := self currentSelectedFiles copy.
    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 currentSelectedFiles.
    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'!

copyFiles

    | files  dirs|

    files := self currentSelectedFiles.
    files notEmpty ifTrue:[
        self copyFilesToClipBoard:(files).        
    ] ifFalse:[
        dirs := self currentSelectedDirectories.
        dirs notEmpty ifTrue:[
            self copyFilesToClipBoard:(dirs).        
        ].
    ].
!

cutFiles

    | files  dirs|

    files := self currentSelectedFiles.
    files notEmpty ifTrue:[
        self cutFilesToClipBoard:(files).        
    ] ifFalse:[
        dirs := self currentSelectedDirectories.
        dirs notEmpty ifTrue:[
            self cutFilesToClipBoard:(dirs).        
        ].
    ].
!

deleteFiles

    | files  dirs|

    files := self currentSelectedFiles.
    files notEmpty ifTrue:[
        self deleteFiles:(files).        
    ] ifFalse:[
        dirs := self currentSelectedDirectories.
        dirs notEmpty ifTrue:[
            self deleteFiles:(dirs).        
        ].
    ].
!

openSettingsDialog
    |dialog|

    dialog := FileBrowserV2SettingsDialog new.
    dialog settingsDialog:self.
    dialog allButOpen.
    dialog doReload.
    dialog openWindow
! !

!AbstractFileBrowser methodsFor:'menu actions-help'!

openAboutThisApplication
    "opens an about box for this application."

    Dialog aboutClass:self class.
!

openHTMLDocument:relativeDocPath
    HTMLDocumentView openFullOnDocumentationFile:relativeDocPath
! !

!AbstractFileBrowser methodsFor:'menu actions-tools'!

conversionChainFrom:inSuffix to:outSuffix
    |conv|

    inSuffix = outSuffix ifTrue:[
        ^ nil
    ].

    "/ q&d hack to get my images converted for old html-browsers...
    "/ this should come from somewhere else (do we need an ImageConverter class ?).

    conv := OrderedCollection new.
    conv add:('anytopnm %1 > %2' -> 'pnm').

    outSuffix = 'png' ifTrue:[
        conv add:('pnmtopng %1 > %2' -> 'png').
        ^ conv.
    ].
    outSuffix = 'gif' ifTrue:[
        conv add:('ppmquant 256 %1 | ppmtogif > %2' -> 'gif').
        ^ conv.
    ].
    outSuffix = 'xpm' ifTrue:[
        conv add:('ppmtoxpm %1 > %2' -> 'xpm').
        ^ conv.
    ].
    outSuffix = 'jpg' ifTrue:[
        conv add:('ppmtojpeg %1 > %2' -> 'jpg').
        ^ conv.
    ].
    self error:'unimplemented conversion'.
!

convertImageToGIF
    self convertImageToSuffix:'gif'
!

convertImageToJPG
    self convertImageToSuffix:'jpg'
!

convertImageToPNG
    self convertImageToSuffix:'png'
!

convertImageToSuffix:outSuffix
    |image writer tempFileXPM chainOfConversions conversionStream skipSignal 
     inFile outFile eachConversionSuffixCommandPair doneWithThisFile
     eachConversionSuffix eachConversionCommand tempFileTemplate|

"/    [
        skipSignal := Signal new.

        self withActivityIndicationDo:[
            self currentFileNameHolder value do:[:fileName |
                skipSignal handle:[:ex | ] 
                do:[
                    |answer|

                    self notify:(resources string:'Converting: %1...' with:fileName baseName).

                    fileName isDirectory ifFalse:[
                        outFile := fileName withSuffix:outSuffix.
                        outFile exists ifTrue:[
                            answer := Dialog 
                                confirmWithCancel:(resources string:'Overwrite existing %1 ?' with:outFile baseName allBold)
                                default:false.
                            answer isNil ifTrue:[AbortSignal raise].
                            answer ifFalse:[
                                skipSignal raise.
                            ].
                        ].

                        image := Image fromFile:fileName.
                        image notNil ifTrue:[
                            writer := MIMETypes imageReaderForSuffix:outSuffix.
                            (writer notNil and:[writer canRepresent:image]) ifTrue:[
                                writer save:image onFile:outFile.
                                skipSignal raise.
                            ].
                        ].
                        chainOfConversions := self conversionChainFrom:(fileName suffix) to:outSuffix.

                        chainOfConversions isNil ifTrue:[ skipSignal raise ].
                        conversionStream := chainOfConversions readStream.

                        doneWithThisFile := false.

                        tempFileTemplate  := Filename newTemporary.

                        inFile := fileName.
                        eachConversionSuffixCommandPair := conversionStream next.
                        eachConversionCommand := eachConversionSuffixCommandPair key.

                        eachConversionCommand == #readToXPM ifTrue:[
                            image := Image fromFile:(inFile pathName).
                            image isNil ifTrue:[
                                self warn:'Unknown format/not an image: ' , inFile baseName.
                                skipSignal raise.
                            ] ifFalse:[
                                tempFileXPM  := tempFileTemplate withSuffix:'xpm'.
                                image saveOn:tempFileXPM using:XPMReader.
                                inFile := tempFileXPM.
                            ].
                            eachConversionSuffixCommandPair := conversionStream next.
                        ].

                        [
                            |command errOutput|

                            [eachConversionSuffixCommandPair notNil] whileTrue:[
                                eachConversionCommand := eachConversionSuffixCommandPair key.
                                eachConversionSuffix  := eachConversionSuffixCommandPair value.

                                self notify:(resources string:'Converting: %1 to %2...' with:fileName baseName with:eachConversionSuffix).
    
                                outFile := tempFileTemplate withSuffix:eachConversionSuffix.
                                command := eachConversionCommand 
                                                bindWith:(inFile pathName)
                                                with:(outFile pathName).

                                errOutput := '' writeStream.

                                (OperatingSystem executeCommand:command errorTo:errOutput)
                                ifFalse:[
                                    Dialog warn:(
                                            resources
                                                stringWithCRs:'Conversion of %1 to %2 using %3 failed:\\%4.' 
                                                with:inFile baseName allBold
                                                with:eachConversionSuffix
                                                with:eachConversionCommand allBold
                                                with:errOutput contents).

                                    (inFile ~= fileName) ifTrue:[inFile delete].
                                    outFile delete.
                                    skipSignal raise
                                ].
                                (inFile ~= fileName) ifTrue:[inFile delete].
                                inFile := outFile.
                                eachConversionSuffixCommandPair := conversionStream next
                            ].
                        ] ifCurtailed:[
                            (inFile ~= fileName) ifTrue:[inFile delete].
                            outFile delete.
                        ].

                        outFile moveTo:(fileName withSuffix:(chainOfConversions last value)).
                        self updateAndSelect:nil.
                    ]
                ]
            ].
            self notify:''.
        ]
"/    ] fork.
!

convertImageToXPM
    self convertImageToSuffix:'xpm'
!

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

doMake

    | cmd |

    cmd := 'make'.
    self executeCommand:cmd.
!

doOpenSettings

    | inst |

    inst := FileBrowserV2SettingsDialog new.
    inst settingsDialog:self.
    inst open.
!

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


"/    [
        self withActivityIndicationDo:[
            | selectedFiles|
            selectedFiles:= self currentSelectedFiles.
            selectedFiles do:[:fileName |
                self notify:('File in:', fileName baseName).
                self singleFileFileIn:fileName lazy:lazy
            ].
            self notify:''.
        ]
"/    ] fork.

!

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 currentSelectedDirectories.
        directories isEmpty ifTrue:[^ self].
        
        dir := directories first.
"/        self label: myName, '- gathering file names ...'.
        [
            fileNames := dir recursiveDirectoryContents.
        ] on:FileStream openErrorSignal do:[:ex|
            self warn:('Cannot access: %1\(%2)' 
                            bindWith:ex parameter printString
                            with:ex description) withCRs.
            ^ self
        ].
        fileNames := fileNames 
                        collect:[:fn | dir construct:fn]
                        thenSelect:[: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 nextPutLine:el.
    ].
    textBox := TextBox new.
    textBox initialText:(stream contents).
    textBox title:'File duplicates in directory: ', dir asString.
    textBox readOnly:true.
    textBox noCancel.
    textBox label:'Duplicates in ', dir asString.
    maxLength := 10.
    info do:[: el |
        maxLength := maxLength max:(el size).
    ].
    textBox extent:((maxLength * 5)@(info size * 20)); sizeFixed:false.
    textBox show.
    textBox destroy.
    stream close.
"/    subView contents:info.
"/    self label:myName.
!

fileFindDuplicates
    "scan directory for duplicate files"

    |fileNames 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 currentSelectedDirectories.
        directories isEmpty ifTrue:[^ self].

        allFiles := OrderedCollection new.
        directories do:[ : dir|
            [
                fileNames := dir directoryContents.
                fileNames := fileNames 
                                collect:[:fn | dir construct:fn]
                                thenSelect:[:fn | fn isDirectory not].
                allFiles addAll:fileNames.
            ] on:FileStream openErrorSignal do:[:ex|
                self warn:('Cannot access: %1\(%2)' 
                                bindWith:ex parameter printString
                                with:ex description) withCRs.
            ].
        ].

        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 nextPutLine:el.
    ].
    titleStream := WriteStream on:''.
    titleStream nextPutAll:'File duplicates in director'.
    directories size == 1 ifTrue:[
        titleStream nextPutAll:'y: ', directories first asString.
    ] ifFalse:[
        titleStream nextPutLine:'ies: '.
        directories do:[:dir|
            size > 1 ifTrue:[
                titleStream nextPutAll:'..'.
                titleStream nextPutLine:((dir asString) copyFrom:(size + 1)).
            ] ifFalse:[
                titleStream nextPutLine:(dir asString).
            ].
        ]
    ].
    
    textBox := TextBox new.
    textBox initialText:(stream contents).
    textBox title:(titleStream contents).
    textBox readOnly:true.
    textBox noCancel.
    stream := WriteStream on:'Duplicates in '.
    directories do:[ :aDirectory |
        stream nextPutAll:aDirectory baseName.
        stream space.
    ].
    textBox label:stream contents.
    maxLength := 10.
    info do:[: el |
        maxLength := maxLength max:(el size).
    ].
    textBox extent:((maxLength * 5)@((info size max:40)* 10)).
    textBox maxExtent:Screen current extent.
    textBox openModeless. "/ showAtPointer.
!

fileFindFile
    |filename files|

    files := self currentFileNameHolder value.
    files notEmpty ifTrue:[
        filename := files first.
    ] ifFalse:[
        filename := Filename homeDirectory.
    ].
    FindFileApplication openOnFileName:filename for:self.
!

fileHexDump

    | file item|

    file := self firstSelectedFile.
    file notNil ifTrue:[
        item := DirectoryContentsBrowser itemClass fileName:file.
        self 
            applicationNamed:#FileApplicationNoteBook
            ifPresentDo:[:appl | appl openTextEditorWithHexPresentationOn:item].
    ].
!

filterSelectedFiles:whichFilter
    |selectedFiles numFiles msg filterBlock|

    selectedFiles := self currentFileNameHolder value.
    (numFiles := selectedFiles size) == 0 ifTrue:[^ self].

    msg := 'Replace contents of file ''%2'' with output of %3-filter ?'.
    numFiles > 1 ifTrue:[
        msg := 'Replace contents of %1 files with output of %3-filter ?'.
    ].

    (Dialog 
        confirm:(msg bindWith:numFiles with:selectedFiles first baseName allBold with:whichFilter) withCRs
        initialAnswer:false
    ) ifFalse:[
        ^ self
    ].

    whichFilter == #rot13 ifTrue:[
        filterBlock := [:charIn | charIn rot13 ].
    ].
    "/ add more here...

    filterBlock isNil ifTrue:[
        self information:'No such filter: ' , whichFilter.
        ^ self.
    ].

    selectedFiles do:[:fileName |
        |s|

        self notify:('Processing:',  fileName baseName).
        fileName isDirectory ifFalse:[
            [
                |inFile outFile in out|

                inFile := fileName asFilename.
                outFile := (fileName pathName , '.filter') asFilename.

                [
                    |charIn charOut|

                    in := inFile readStream.
                    out := outFile writeStream.
                    [in atEnd] whileFalse:[
                        charIn := in next.
                        charOut := filterBlock value:charIn.
                        out nextPut:charOut.
                    ].
                    outFile renameTo:inFile.
                ] ensure:[
                    out notNil ifTrue:[ out close ].
                    in notNil ifTrue:[ in close ].
                    outFile delete.
                ]
            ] on:FileStream openErrorSignal do:[:ex|
                self warn:('Cannot process "%1".' bindWith:fileName baseName allBold).
            ].
        ]
    ].
    self notify:''.
!

installAllAsAutoloaded
    "install all classes found here as autoloaded classes"

    [
        self withActivityIndicationDo:[
            self allItemsOfCurrentDirectory do:[:fileItem |
                (fileItem hasMimeType and:[fileItem mimeType isSmalltalkSource]) ifTrue:[
                        
                    self notify:('Install as autoloaded:', fileItem baseName).
                    self installAsAutoloaded:(fileItem fileName).
                ]
            ].
            self notify:''.
        ]
    ] fork.
!

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

joinSelectedFiles
    |selectedFiles numFiles msg outFile outStream|

    selectedFiles := self currentFileNameHolder value.
    (numFiles := selectedFiles size) <= 1 ifTrue:[^ self].

    msg := 'Join each of the %1 files into single file named:\\Attention: order in which files were selected is relevant here !!'.
    outFile := Dialog 
        request:(msg bindWith:numFiles with:selectedFiles first baseName) withCRs.
    outFile size == 0 ifTrue:[^ self].
    outFile := selectedFiles first directory construct:outFile.

    outStream := outFile writeStream.

    selectedFiles do:[:fileName |
        |inStream|

        self notify:('Adding:',  fileName baseName).
        inStream := fileName readStream.
        inStream copyToEndInto:outStream.
        inStream close.
    ].
    outStream close.
    self notify:''.
!

loadImageAndPerform:aSelectorOrBlock

    |img path files|

    files := self currentSelectedFiles.
    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 currentSelectedFiles.
    (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 currentSelectedDirectories.
    directories isEmpty ifTrue:[ ^ self].
    self withWaitCursorDo:[
        CBrowser::Browser openIn:directories first.
    ]
!

openChangeSetBrowser
    self
        openTool:ChangeSetBrowser 
        with:#openOnFile: 
        ignoreDirectories:true
!

openChangesBrowser
    "open a change browser on the selected file(s)"

    self openTool:(UserPreferences current changesBrowserClass)
!

openDiffView
    "open a diff-view"

    | name1 name2 text1 text2 d err nm l1 files title defaultName lastFile|

    files := self currentSelectedFiles.
    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:[
            | directories |
            directories := self currentDirectories value.
            directories notEmpty ifTrue:[
                lastFile := directories first asFilename construct:(LastFileDiffFile baseName).
                (lastFile exists and:[lastFile isReadable]) ifTrue:[
                    name1 := lastFile.
                ]
            ]
        ].
        name2 := files first.
        title := 'Show differences between ', name2 baseName, ' and:'.
        defaultName := name1 notNil ifTrue:[name1 baseName] ifFalse:[nil].
        name1 := DialogBox 
                    requestFileName:title 
                    default:defaultName 
                    ok:'OK' 
                    abort:'Use File List' 
                    pattern:'*' 
                    fromDirectory:(name2 asFilename directory).
    ].

    (name1 isNil or:[name1 asString isEmpty]) ifTrue:[
        text1 := self getAllFilesAsStrings asStringCollection withTabs.
        text1 := text1 collect:[:l | l isNil ifTrue:[' '] ifFalse:[l]].
        name1 := nil.
        l1 := 'browser contents'
    ] ifFalse:[
        name1 := name1 asFilename.
        LastFileDiffFile := name1.
        name1 asFilename isReadable ifFalse:[
            nm := name1.
            name1 asFilename exists ifFalse:[
                err := '"%1" does not exist.'.
            ] ifTrue:[
                err := '"%1" is not readable.'
            ].
        ].
        l1 := name1
    ].

    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 allBold).
        ^ 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 topView label:'File Differences'.
        ]
    ]
!

openEditor
    self openTool:EditTextView
!

openGV
    self openOSCommandWithFiles:'gv'
!

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 , Filename separator asString , 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 currentSelectedFiles.
    (file isEmpty) ifTrue:[
        ^ self.
    ].
    file := file first.
    (MP3PlayerApplication ? SaugFix::MP3PlayerApplication) playSong:file.
!

openOSCommandWithFiles:command
    |files fileNames|

    files := self currentSelectedFiles.
    (files isEmpty) ifTrue:[
        ^ self.
    ].

    fileNames := files collect:[:each |
                    '"' , each asFilename pathName , '"'
                 ].

    [
        OperatingSystem 
            executeCommand:command , ' ' , fileNames asStringCollection asString
            inDirectory:(files first asFilename directory).
    ] fork
!

openPDFViewer
    |files fileNames|

    files := self currentSelectedFiles.
    (files isEmpty) ifTrue:[
        ^ self.
    ].
    fileNames := 
        files 
            collect:
                [:each |
                    '"' , each asFilename pathName , '"'
                ].

    [
        OperatingSystem 
            executeCommand:'acroread ' , fileNames asStringCollection asString.
    ] fork
!

openRP
    self openOSCommandWithFiles:'realplay'
!

openSlideShow

    |directories dir|

    directories := self currentSelectedDirectories.
    directories isEmpty ifTrue:[^ self].

    dir := directories first.
    CodingExamples_GUI::SlideShow openIn:dir.
!

openSnapshotImageBrowser
    "Sorry, for now, only the old browser can handle snapShotImages."

    ^ self openTool:SystemBrowser with:#openOnSnapShotImage: ignoreDirectories:true
!

openTerminal

    |directories dir|

    directories := self currentSelectedDirectories.
    directories isEmpty ifTrue:[
        dir := Filename homeDirectory.
    ] ifFalse:[
        dir := directories first.
    ].

    TerminalApplication notNil ifTrue:[
        TerminalApplication openIn:dir
    ] ifFalse:[
        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 currentSelectedFiles.
    
    (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
!

openXV
    self openOSCommandWithFiles:'xv'
!

openZipTool
    |zipTool directories dir|

    (zipTool := self openTool:ZipTool) notNil ifTrue:[
        directories := self currentSelectedDirectories.
        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 currentSelectedDirectories.
    directories isEmpty ifTrue:[^ self].

    dir := directories first.
    Smalltalk installAutoloadedClassesFrom:(dir construct:'abbrev.stc').
!

singleFileFileIn:fileName lazy:lazy
    "fileIn the selected file(s)"

    |aStream wasLazy notifyString|

    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
                    ].
                    notifyString := 'unloading old ' , p , ' ...'.
                    Transcript showCR:notifyString.
                    self notify:notifyString.
                    ObjectFileLoader unloadObjectFile:p. 
                ].

                notifyString := 'loading ' , p , ' ...'.
                Transcript showCR:notifyString.
                self notify:notifyString.
                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 readStreamOrNil.
            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 readStreamOrNil.
                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
                        ]
                    ]
                ]
            ]]]
        ]]
    ].
!

splitFile:infile intoPiecesOfSize:kiloBytes
    |bytesPerSplit splitIndex bufferSize buffer n
     inStream outFile outStream remaining remainingInThisOutfile|

    bufferSize := 32*1024.

    inStream := infile readStream.

    bytesPerSplit := kiloBytes * 1024.

    remaining := infile fileSize.
    splitIndex := 1.
    [remaining > 0] whileTrue:[
        outFile := infile pathName , '_' , (splitIndex printString leftPaddedTo:3 with:$0).
        outStream := outFile asFilename writeStream.
        remainingInThisOutfile := remaining min:bytesPerSplit.
        [remainingInThisOutfile > 0] whileTrue:[
            buffer := ByteArray new:bufferSize.
            n := inStream 
                    nextBytes:(bufferSize min:remainingInThisOutfile)
                    into:buffer 
                    startingAt:1.
            outStream nextPutBytes:n from:buffer startingAt:1.
            remainingInThisOutfile := remainingInThisOutfile - n.
            remaining := remaining - n.
        ].
        outStream close.
        splitIndex := splitIndex + 1.
    ].
    inStream close.
!

splitSelectedFiles
    |selectedFiles numFiles msg answer kiloBytes|

    selectedFiles := self currentFileNameHolder value.
    (numFiles := selectedFiles size) == 0 ifTrue:[^ self].

    msg := 'Split %2 into pieces of size (in kB):'.
    numFiles > 1 ifTrue:[
        msg := 'Split each of the %1 files into pieces of size (in kB):'.
    ].

    answer := Dialog 
        request:(msg bindWith:numFiles with:selectedFiles first baseName) withCRs.
    answer size == 0 ifTrue:[^ self].
    kiloBytes := Integer readFrom:answer onError:nil.
    kiloBytes isNil ifTrue:[^ self].

    selectedFiles do:[:fileName |
        self notify:('Splitting:',  fileName baseName).
        fileName isDirectory ifFalse:[
            self splitFile:fileName intoPiecesOfSize:kiloBytes.
        ]
    ].
    self notify:''.
!

truncateSelectedFilesToZeroSize
    |selectedFiles numFiles msg|

    selectedFiles := self currentFileNameHolder value.
    (numFiles := selectedFiles size) == 0 ifTrue:[^ self].

    msg := 'Really truncate file ''%2'' to zero length ?\\WARNING: contents of file is lost !!\This cannot be undone.'.
    numFiles > 1 ifTrue:[
        msg := 'Really truncate %1 files to zero length ?\\WARNING: contents of files is lost !!\This cannot be undone.'.
    ].

    (Dialog 
        confirm:(msg bindWith:numFiles with:selectedFiles first baseName allBold) withCRs
        initialAnswer:false
    ) ifFalse:[
        ^ self
    ].

    selectedFiles do:[:fileName |
        |s|

        self notify:('Truncating:',  fileName baseName).
        fileName isDirectory ifFalse:[
            [
                s := fileName writeStream.
                s close.
            ] on:FileStream openErrorSignal do:[:ex|
                self warn:('Cannot truncate "%1".' bindWith:fileName baseName allBold).
            ].
        ]
    ].
    self notify:''.
! !

!AbstractFileBrowser methodsFor:'menu queries-cvs'!

canCvsAddAndCommit

    |selectedFiles|

    selectedFiles := self currentSelectedFiles.
    ^ (selectedFiles notEmpty and:[self currentFilesAreInSameDirectory]).
!

canRemoveCVSContainer
    ^ self currentSelectedFiles 
        contains:[:fileName|
            |dirOfFile cvsDir|

            dirOfFile := self getDirWithoutFileName:fileName.
            cvsDir := dirOfFile construct:'CVS'.
            cvsDir isDirectory
        ].
! !

!AbstractFileBrowser methodsFor:'menu queries-tools'!

anySTFilesPresent

    ^ self anyFilesPresentWithSuffix:'st'
!

canCreateNewProject

    | selectedFiles |

    self currentFilesAreInSameDirectory ifFalse:[^ false].
    selectedFiles := self currentSelectedFiles.
    ^ [ 
        ((selectedFiles detect:[:fileName| | suffix|
            suffix := fileName suffix asLowercase.
            (suffix = 'prj' or:[suffix = '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 currentSelectedFiles size > 0
        and:[OSI::ASN1Parser notNil 
        and:[OSI::ASN1Parser isLoaded]]]]
!

hasCBrowser
    ^ [ CBrowser::Browser notNil ]
!

hasJava

    ^ [ JavaClassReader notNil 
        and:[JavaClassReader isLoaded]]
!

hasJavaAndSelection

    ^ [ self currentSelectedFiles size > 0
        and:[JavaClassReader notNil 
        and:[JavaClassReader isLoaded]]]
!

hasMP3Player

    ^ [ MP3PlayerApplication notNil
        or:[SaugFix::MP3PlayerApplication notNil ]]
!

hasMP3PlayerAndSelection

    ^ [ self currentSelectedFiles size > 0
        and:[ self hasMP3Player value]]
!

hasSlideShow

    ^ [CodingExamples_GUI::SlideShow notNil]
!

hasSnapshotSelection

    ^ [ 
        | files |
        files := self currentSelectedFiles.
        ((files size == 1)
        and:[ files first hasSuffix:'img' ])
      ]
!

hasZipFileSelected

    ^ [|sel fileName fn suff|

        sel := self currentSelectedFiles.
        sel size == 1 ifTrue:[
            fileName := sel first.
            fileName notNil ifTrue:[
                suff := fileName 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'!

getAllFilesAsStrings
    "raise an error: must be redefined in concrete subclass(es)"

    ^ self subclassResponsibility
!

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

    |selFiles filename fileOutput type modeBits modeString s isLink info 
     sizeString fileSize tAccess tModification buffer|

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

    buffer := '' asText writeStream.

    buffer 
        nextPutAll:'filename: '; 
        nextPutLine:filename asString.

    isLink := filename isSymbolicLink.

    buffer nextPutAll:'type:   '.

    info := filename info.
    isLink ifTrue:[
        info isNil ifTrue:[
            buffer nextPutAll:'broken '.
        ].
        buffer 
            nextPutAll:'symbolic link to: ';
            nextPutLine:(filename linkInfo path).
    ] ifFalse:[
        type := info type.
        (longInfo and:[type == #regular]) ifTrue:[
            fileOutput := filename fileType.
        ].

        fileOutput isNil ifTrue:[
            s := type asString
        ] ifFalse:[
            s := 'regular (' , fileOutput , ')'
        ].
        buffer nextPutLine:s.
    ].

    isLink = true ifTrue:[
        info := filename linkInfo
    ] ifFalse:[
        info := filename info
    ].
    
    fileSize := info fileSize.
    sizeString := 'size:   ', fileSize printString.
    longInfo ifTrue:[
        fileSize > 1024  ifTrue:[
            sizeString := sizeString , ' (' , ((fileSize / 1024) asFixedPoint:1) printString , ' K'.
            fileSize > (1024*1024)  ifTrue:[
                sizeString := sizeString , ' or ' , ((fileSize / (1024*1024)) asFixedPoint:1) printString , ' M'.
            ].
            sizeString := sizeString , ')'. 
        ].
    ].
    buffer nextPutLine:sizeString.

    modeBits := info mode.
    modeString := self getModeString:modeBits.

    buffer nextPutAll:'access: '; nextPutAll:modeString.
    longInfo ifTrue:[
        buffer space; nextPutAll:(modeBits printStringRadix:8).
    ].
    buffer
        cr;
        nextPutAll:'owner:  ';
        nextPutLine:(OperatingSystem getUserNameFromID:(info uid)).

    longInfo ifTrue:[
        buffer 
            nextPutAll:'group:  ';
            nextPutLine:(OperatingSystem getGroupNameFromID:(info gid)).

        tAccess := info accessTime.
        buffer 
            nextPutAll:'last access:       '; 
            nextPutAll:tAccess asTime printString;
            space;
            nextPutLine:tAccess asDate printString. 

        tModification := info modificationTime.
        buffer 
            nextPutAll:'last modification:       '; 
            nextPutAll:tModification asTime printString;
            space;
            nextPutLine:tModification asDate printString. 
    ].
    ^ buffer contents
!

initialCommandFor:fileName into:aBox
    "set a useful initial command for execute box."

    self class initialCommandFor:fileName in:Filename currentDirectory intoBox:aBox
!

isAbstractFileBrowser

    ^ true
!

systemIsDOS

    ^ OperatingSystem isMSDOSlike
!

systemIsUnix
    ^ OperatingSystem isUNIXlike
! !

!AbstractFileBrowser methodsFor:'queries-file'!

allItemsOfCurrentDirectory
    self 
        applicationNamed:#DirectoryContentsBrowser 
        ifPresentDo:[:app | ^ app allItemsOfCurrentDirectory].

    ^ nil
!

anyFilesPresentWithSuffix:suffix

    |directories|

    directories := self currentDirectories value.
    directories do:[:dir|
        [
            (dir directoryContents do:[:f| (f asFilename suffix = suffix) ifTrue:[ ^ true]])
        ] on:FileStream openErrorSignal do:[:ex|].
    ].
    ^ false.
!

commonPrefixOfSelectedFiles
    |selFiles stringCol firstPre|

    selFiles := self currentFileNameHolder value.
    selFiles isEmpty ifTrue:[^ nil].

    stringCol := selFiles collect:[:file | file asString].
    firstPre := stringCol at:1.
    stringCol from:2 do:[:el|
         firstPre := firstPre commonPrefixWith:el.
    ].
    ^ firstPre asFilename
!

currentFilesAreInSameDirectory

    ^ self parentDirectoriesOfCurrentFiles size < 2
!

currentFilesHasDirectories

    ^ self currentDirectories value notEmpty.
!

directoriesForFiles:aFileCol

    ^ (aFileCol collect:[:file| self getDirWithoutFileName:file]) asSet.
!

fileListIsEmpty
    self 
        applicationNamed:#DirectoryContentsBrowser 
        ifPresentDo:[:appl | ^ appl fileListIsEmpty].

    ^ nil.
!

fileListIsNotEmpty

    ^ self fileListIsEmpty not.   
!

fileName:aFilename1 startsWith:aFilename2

" check if aFilename2 starts with the same directories like aFilename1 "

    | file1 file2 |

    aFilename2 isNil ifTrue:[ ^ false].
    aFilename1 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
    ].
    ^ (file1 pathName) startsWith:(file2 pathName)
!

getAllFilesAsStringCollection
    self 
        applicationNamed:#DirectoryContentsBrowser 
        ifPresentDo:[:appl | ^ appl getAllFilesAsStringCollection].

    ^ nil
!

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
!

getDirWithoutFileName:aFileName

    | dir |
    aFileName isNil ifTrue:[
        ^ aFileName.    
    ].
    dir := aFileName asFilename.
    dir isDirectory ifFalse:[
        dir := dir directory.
    ].
    ^ dir.
!

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 currentSelectedDirectories.
    (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 dir|

        n := (directories first) construct:f.
        (n isReadable and:[n isDirectory not]) ifTrue:[
            ^ DirectoryContentsBrowser itemClass fileName:n
        ]
    ].
    ^ nil
!

parentDirectoriesOfCurrentFiles

    ^ (self currentFileNameHolder value collect:[:file | file directory]) asSet 
! !

!AbstractFileBrowser methodsFor:'selection'!

currentSelectedDirectories

    ^ self currentDirectories value.
!

currentSelectedFiles

    ^ self currentFileNameHolder value select:[:file | file isDirectory not].
!

firstSelectedFile
    ^ self currentFileNameHolder value 
        detect:[:file | file asFilename isDirectory not]
        ifNone:[].
!

hasOnlyFilesSelected

    ^ self currentFileNameHolder value conform:[:file | file isDirectory not].
!

hasTwoFilesSelected

    ^ self currentFileNameHolder value size == 2 
        and:[self hasOnlyFilesSelected]
! !

!AbstractFileBrowser methodsFor:'sorting'!

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

sortBlockHolder
    ^ self aspectFor:#sortBlockHolder ifAbsent:[
        (FileSorter directoriesBeforeFiles:(self sortDirectoriesBeforeFiles value and:[self viewDirsInContentsBrowser value]) 
                    selector:#fileName 
                    sortCaseless:self sortCaseless value 
                    sortReverse:false) asValue.
    ].
!

sortBlockProperty

    
    ^ self aspectFor:#sortBlockProperty ifAbsent:[ #baseName asValue ].
!

sortCaseless
    " aspect for sort caseless "

    ^ self aspectFor:#sortCaseless ifAbsent:[
        | holder |
        holder := (Filename isCaseSensitive not) asValue.
        holder
    ]
!

sortDirectoriesBeforeFiles

    " aspect for sort directories always before files"
    ^ self aspectFor:#sortDirectoriesBeforeFiles ifAbsent:[ true asValue ].
!

sortFileListsBy:instanceName 

    self sortFileListsBy:instanceName withReverse:true
!

sortFileListsBy:instanceName withReverse:aBoolean

    | aSymbol sortCaselessLocal currentSortOrder sorter|

    aSymbol := instanceName asSymbol.
    self sortBlockProperty setValue:instanceName asSymbol.
    sortCaselessLocal := self sortCaseless value.
    currentSortOrder := self currentSortOrder value.
    currentSortOrder isEmpty ifTrue:[
        currentSortOrder at:#column put:aSymbol.
        currentSortOrder at:#reverse put:false.
        currentSortOrder at:#sortCaseless put:sortCaselessLocal.
    ] ifFalse:[
        (currentSortOrder at:#sortCaseless) ~= sortCaselessLocal ifTrue:[
            "/ sort caseless changed
            currentSortOrder at:#sortCaseless put:sortCaselessLocal.
        ] ifFalse:[
            (currentSortOrder at:#column) = aSymbol ifTrue:[
                "/ same column like before - change sort order ifReverse is true
                aBoolean ifTrue:[
                    | isReverse |
                    isReverse := currentSortOrder at:#reverse.
                    currentSortOrder at:#reverse put:(isReverse not).
                ].
            ] ifFalse:[
                "/ another column - remark column
                currentSortOrder at:#column put:aSymbol.
            ]
        ]
    ].
    self currentSortOrder changed.
    sorter := FileSorter directoriesBeforeFiles:(self sortDirectoriesBeforeFiles value and:[self viewDirsInContentsBrowser value]) 
                            selector:instanceName 
                            sortCaseless:sortCaselessLocal 
                            sortReverse:(currentSortOrder at:#reverse).
    self sortBlockHolder value:sorter.
! !

!AbstractFileBrowser methodsFor:'startup & release'!

makeDependent
    self filterModel addDependent:self.            
    self currentFileNameHolder addDependent:self.
    self sortDirectoriesBeforeFiles addDependent:self.
    self sortCaseless addDependent:self.
    self showHiddenFiles addDependent:self.
    self rootHolder addDependent:self.
!

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

postBuildWith:aBuilder
    self makeDependent.
    super postBuildWith:aBuilder.
!

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 ensure:[
        locked := false.
    ]
! !

!AbstractFileBrowser::DirectoryHistory class methodsFor:'defaults'!

historySize

    ^ 20
! !

!AbstractFileBrowser::DirectoryHistory class methodsFor:'new'!

new

    ^ super new initialize.
! !

!AbstractFileBrowser::DirectoryHistory methodsFor:'actions'!

addToHistory:aPath
    | item|

    item := self getItemFor:aPath.
    self backForwardListAdd: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."
        self remove:item.
        self addFirst:item
    ].
!

backForwardListAdd:aPath

    |pathIndex|

    pathIndex := backForwardList indexOf:aPath.
    pathIndex == 0 ifTrue:[
        " a new path comes in remove forward paths "
        (backForwardList size) > backForwardIndex ifTrue:[
            backForwardList removeFromIndex:(backForwardIndex + 1) toIndex:(backForwardList size).    
        ].
    ] ifFalse:[
        backForwardList remove:aPath.
        pathIndex <= backForwardIndex ifTrue:[
            backForwardIndex := backForwardIndex - 1.
        ]
    ].
    backForwardList add:aPath afterIndex:backForwardIndex.
    backForwardIndex := backForwardIndex + 1.
    backForwardIndex > self class historySize ifTrue:[
        backForwardList removeFirst.
        backForwardIndex := backForwardIndex - 1.
    ].
!

goBackward
    "return the first path of the backward list;
     remove it from the back list and add it ti the forward list."

    |retPath|

    self canBackward ifTrue:[
        retPath := backForwardList at:(backForwardIndex - 1).
        backForwardIndex := backForwardIndex - 1.
    ].
    ^ retPath.
!

goForward
    "return the first path of the forward list;
     remove it from the list."

    |retPath|

    self canForward ifTrue:[
        retPath := backForwardList at:backForwardIndex + 1.
        backForwardIndex := backForwardIndex + 1.
    ].
    ^ retPath.
!

resetForwardBackward

    self initialize
!

setPosition:aPosition for:aPath

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

!AbstractFileBrowser::DirectoryHistory methodsFor:'initialization'!

initialize

    backForwardList := OrderedCollection new.
    self reverseDo:[:el|
        backForwardList add:el path.
    ].
    backForwardIndex := backForwardList size.
! !

!AbstractFileBrowser::DirectoryHistory methodsFor:'queries'!

canBackward

    ^ backForwardIndex > 1 
!

canForward

    ^ (backForwardList size >= (backForwardIndex + 1))
!

getBackCollection

    | backCol |

    backCol := OrderedCollection new.
    self canBackward ifTrue:[
        | tmpCol |
        tmpCol := backForwardList copyTo:backForwardIndex - 1.
        tmpCol reverseDo:[ :el|
            backCol add:el.
        ]
    ].
    ^ backCol
!

getForwardCollection

    | forwCol |

    forwCol := OrderedCollection new.
    self canForward ifTrue:[
        forwCol := backForwardList copyFrom:(backForwardIndex + 1)    
    ].
    ^ forwCol
!

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

nextBackwardItem
    "return the first path of the backward list"

    |retPath|

    self canBackward ifTrue:[
        retPath := backForwardList at:backForwardIndex.
    ].
    ^ retPath.
!

nextForwardItem
    "return the first path of the forward list"

    |retPath|

    self canForward ifTrue:[
        retPath := backForwardList at:backForwardIndex + 1.
    ].
    ^ retPath.
! !

!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:'accessing-attributes'!

filenameHistorySize

    ^ 20
! !

!AbstractFileBrowser::FilenameHistory methodsFor:'adding & removing'!

add:aFileItem
    (self includes:aFileItem) ifTrue:[
        self remove:aFileItem.
    ].
    self addFirst:aFileItem.
! !

!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.194 2004-01-14 09:48:57 penk Exp $'
! !