AbstractFileBrowser.st
author Claus Gittinger <cg@exept.de>
Sat, 05 Apr 2003 16:13:44 +0200
changeset 4782 491c8090264c
parent 4781 08aacafe88ab
child 4785 5a3f7a0c3ff1
permissions -rw-r--r--
update fixed

"{ Package: 'stx:libtool' }"

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

currentSelection

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

currentSelection:aFilenameCol

    |newCol|

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

directoryHistory

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

resetClassVars

    DirectoryHistory := nil.
    CurrentSelection := 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
    ^ '~'
!

defaultBookMarksFilename
    ^ '.fileBrowserBookmarks'
!

directoryBookmarks
    DirectoryBookmarks isNil ifTrue:[                     
        self loadBookmarksFrom:(self defaultBookMarksFileDirectory asFilename 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 size > 0
!

loadBookmarksFrom:aFileNameOrString
    |bookmarks s fileName|

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

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

        line := s nextLine.
        path := (RFC1421Coder decode:line).
        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:(RFC1421Coder encode: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                
           #viewTime                 
           #viewType  
           #openMultipleApplicationsForType
           #filenameEntryFieldVisibleHolder
           #toolBarVisibleHolder
           #sortDirectoriesBeforeFiles
           #openAlwaysInTextEditor
           #sortCaseless
      )
! !

!AbstractFileBrowser class methodsFor:'image'!

disabledCursorImage

    DisabledCursorImage isNil ifTrue:[
        DisabledCursorImage := Image fromFile:'xpmBitmaps/cursors/no_entry.xpm'
    ].
    ^ DisabledCursorImage
!

enabledCursorImage

    EnabledCursorImage isNil ifTrue:[
        EnabledCursorImage := Image fromFile:'xpmBitmaps/cursors/double_crossHair.xpm'
    ].
    ^ EnabledCursorImage
! !

!AbstractFileBrowser class methodsFor:'image specs'!

clearHistoryIcon
    ^ Icon deleteIcon
!

closeIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

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

    "
     self closeIcon inspect
     ImageEditor openOnClass:self andSelector:#closeIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class closeIcon'
        ifAbsentPut:[(Depth8Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ H@@@@@@@@@@@@B@ @@@@@@@@@@@@HB@ @@@@@@@@@B@ H@@@@@@@@@@@@@@ HB@@@@@@@B@ H@@@@@@@@@
@@@@@@@B@ H@@@@B@ H@@@@@@@@@@@@@@@@@@@HB@ @B@ H@@@@@@@@@@@@@@@@@@@@@@ HB@ H@@@@@@@@@@@@@@@@@@@@@@@@B@ H@@@@@@@@@@@@@@@@@
@@@@@@@B@ HB@ @@@@@@@@@@@@@@@@@@@@@B@ H@@ HB@@@@@@@@@@@@@@@@@@@B@ H@@@@B@ H@@@@@@@@A@@@@@@@B@ H@@@@@@@HB@ @@@@@@@@@@@@@B
@ H@@@@@@@@@@ HB@@@@@@@@@@@@@ H@@@@@@@@@@@@B@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@A@@@@@@@@@@@@@@@@@@@@@@@@@PD@@P@@
@@DA@@@@@PD@@@DA@@@@@P@@@@D@@@D@@@D@@P@@@@D@@@D@@@D@@@@A@@@A@@@A@@@A@@@A@PDA@@@A@@@@@P@@@P@@@P@@@@D@@P@@@@@@@@DA@@DA@@@A
@P@@@PD@@@@A@P@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[255 255 255 0 0 0 255 0 0]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@A C@A0G@@8N@@\\@@N8@@G0@@C @@G0@@N8@@\\B@8N@A0G@A C@@@@@A@@@MFL0QIQHQII8QIE@M&X0@@@@') ; yourself); yourself]
!

copyIcon
    <resource: #programImage>

    ^ ToolbarIconLibrary copy20x20Icon "copy28x28Icon"
!

cutIcon
    <resource: #programImage>

    ^ ToolbarIconLibrary cut20x20Icon2 "cut28x28Icon"
!

deleteIcon
    <resource: #programImage>

    ^ ToolbarIconLibrary erase20x20Icon "/ delete28x28Icon
!

diffIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

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

    "
     self diffIcon inspect
     ImageEditor openOnClass:self andSelector:#diffIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class diffIcon'
        ifAbsentPut:[(Depth8Image new) width: 26; height: 22; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@A@PDA@PDA@PD@@@@@@@@@@@@@@@@@@@@@@@DA XFA XFA P@@@@@@@@@@@@@@@@@@@@@@@PFA XF@@@@@@@@@@@@@@@@@@@@@@@@@@@@A@XFA @F
A XD@@@@@@@@@@@@@@@@@@@@@@@DA X@A XFA P@@@@@@@@@@@@@@@@@@@@@@@PFA @FA XFA@@@@@@@@@@@@@@@@@@@@@@@A@XF@@XFA XD@@@@@@@@@@@@
@@@@@@@@@@@DA X@A XFA P@@@@@@@@@@@@@@@@@@@@@@@PFA X@A XFA@@@@@@@@@@@@@@@@@@@@@@@A@XFA X@@@@@@@@@@@@@@@@@@@@@@@@@@@@DA XF
A XFA P@@@@@@@@@@@@@@@@@@@@@@@PFA XFA XFA@@@@@@@@@@@@@@@@@@@@@@@A@PDA@PDA@PD@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 129 129 129 0 0 0 194 194 194 132 132 132 198 198 198 255 255 255]; mask:((Depth1Image new) width: 26; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@?8@@@O>@@@C? @@@?<@@@O> @@C?(@@@?:@@@O> @@C?8@@@??@@@O>8@@C?''@@@?80@@@@@@@@T[@@@DI@@@GSX@@BT$@@@%I@@@IRP@@A4$@@@@@@@@@@a') ; yourself); yourself]
!

fileInIcon
    <resource: #programImage>

    ^ ToolbarIconLibrary 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
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class hexToggle22x22Icon'
        ifAbsentPut:[(Depth8Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@EAPTEAPTEAPTE@@@@@@@@@@@@@@@@AP@@@@T@@@@EAP@@@@@@@@@@
@@@@@@TEAP@E@@TEAPT@@@@@@@@@@@@@@@@EAP@@AP@@APTE@@@@@@@@@@@@@@@@APTE@@T@APTEAP@@@@@@@@@@@@@@@@T@@@@E@@TEAPT@@@@@@@@@@@@@
@@@EAPTEAPTEAPTE@@@@@@@@@@@@@@@@AP@@@@T@@@@EAP@@@@@@@@@@@@@@@@T@AP@E@@T@APT@@@@@@@@@@@@@@@@E@@@@AP@@@@TE@@@@@@@@@@@@@@@@
AP@E@@T@AP@EAP@@@@@@@@@@@@@@@@T@AP@E@@@@APT@@@@@@@@@@@@@@@@EAPTEAPTEAPTE@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 105 133 190 129 129 129 194 194 194 255 0 0 255 255 255]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@A?>@@@@@B''Q@B$J@C&D@B$J@B''Q@') ; yourself); yourself]
!

historyIcon
    <resource: #programImage>

    ^ ToolbarIconLibrary history20x20Icon "/ history28x28Icon
!

homeIcon
    <resource: #programImage>

    ^ ToolbarIconLibrary home28x28Icon
!

htmlReloadIcon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

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

    "
     self htmlReloadIcon inspect
     ImageEditor openOnClass:self andSelector:#htmlReloadIcon
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class htmlReloadIcon'
        ifAbsentPut:[(Depth2Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(2 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@UT@@@@@EU@D@@@@UT@@@H@AUP@@@@@EU@@@@@@EU@@@@E@EU@@@@@@EU@@@@@AUUT@@@@@UUP@@@@@EU@@@@@@AT@@@@@@@P@@@@H@@@@@@@@
@@@@@@@@@@@@@@@H@@@@@@@@@@@@@@@G@@@@@@@J@@@@@@@I@@@@@@@@') ; colorMapFromArray:#[0 0 0 0 129 0]; mask:((Depth1Image new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@G<C@_?C@??#A?C3C>@;G<@KG<@CG<@C??$C_?NCO>_CG<?#C9?3A3?;@''??@@?#P@?C\A?COC>CG?<CC?8C@? C') ; yourself); yourself]
!

leftArrow
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

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

    "
     self leftArrow inspect
     ImageEditor openOnClass:self andSelector:#leftArrow
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class leftArrow'
        ifAbsentPut:[(Depth8Image new) width: 24; height: 24; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@D@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@PH@@@@@@@@@
@@@@@@@@@@@@@@@@@@@A@0D@@@@@@@@@@@@@@@@@@@@@@@@@@@DDAPH@@@@@@@@@@@@@@@@@@@@@@@@@@PX@A0D@@@@@@@@@@@@@@@@@@@@@@@@AB@@IB HK
@0LA@PDK@@@@@@@@@@@@@@DL@@@MC <P@@@@DPLR@@@@@@@@@@@@@PX@@ALTEP8PDQDVE0\R@@@@@@@@@@@AAADQD1PUEQTNF@$SFP(R@@@@@@@@@@@KB!!P[
GAPUEQT]GQ4]GP(R@@@@@@@@@@@@D (TG!!0TEA,_G1<[H@(R@@@@@@@@@@@@@AHJC!!< GQ4JB (JB"DK@@@@@@@@@@@@@@@RB 8^B DRD!!HRD!!HK@@@@@@@@
@@@@@@@@D (]H H@@@@@@@@@@@@@@@@@@@@@@@@@@AHJHPD@@@@@@@@@@@@@@@@@@@@@@@@@@@@K@PH@@@@@@@@@@@@@@@@@@@@@@@@@@@@@B0D@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@,@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@') ; colorMapFromArray:#[224 224 224 0 32 64 0 32 96 32 64 96 96 128 160 64 96 128 128 160 192 32 96 128 128 160 160 160 192 224 0 96 128 0 0 0 128 128 160 64 192 192 32 160 192 64 128 192 128 192 224 192 224 224 0 0 32 96 192 224 0 160 192 0 128 192 160 224 224 96 160 192 128 192 192 64 160 192 192 192 192 32 192 192 0 192 224 0 128 160 32 192 224 64 192 224 0 192 192 0 64 96 0 64 128]; mask:((Depth1Image new) width: 24; height: 24; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@B@@@F@@@N@@@^@@@>@@A??@C??@G??@O??@O??@G??@C??@A??@@>@@@^@@@N@@@F@@@B@@@@@@@@@@@@@@@@@@') ; yourself); yourself]
!

leftArrow20x20Icon
    "This resource specification was automatically generated
     by the ImageEditor of ST/X."

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

    "
     self leftArrow20x20Icon inspect
     ImageEditor openOnClass:self andSelector:#leftArrow20x20Icon
     Icon flushCachedIcons
    "

    <resource: #image>

    ^Icon
        constantNamed:#'AbstractFileBrowser class leftArrow20x20Icon'
        ifAbsentPut:[(Depth8Image new) width: 20; height: 20; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
@ 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: 'Settings...'
            #itemValue: #doOpenSettings
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'New Text Editor'
            #itemValue: #newTextEditor
            #translateLabel: true
          )
         #(#MenuItem
            #label: 'Search Files'
            #itemValue: #doOpenSearchFile
            #translateLabel: true
          )
         #(#MenuItem
            #label: 'Shell Terminal'
            #itemValue: #doAddTerminal
            #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
            #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
            #label: 'Copy'
            #translateLabel: true
            #value: #copyFiles
            #enabled: #hasSelection
          )
         #(#MenuItem
            #label: 'Cut'
            #translateLabel: true
            #value: #cutFiles
            #enabled: #hasSelection
          )
         #(#MenuItem
            #label: 'Paste'
            #translateLabel: true
            #value: #pasteFiles
            #enabled: #canPaste
          )
         #(#MenuItem
            #label: 'Delete'
            #translateLabel: true
            #value: #deleteFiles
            #enabled: #hasSelection
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Copy All Filenames'
            #translateLabel: true
            #value: #copyFileList
            #enabled: #fileListIsNotEmpty
          )
         #(#MenuItem
            #label: 'Copy Selected Filenames'
            #translateLabel: true
            #value: #copySelectedFilenames
            #enabled: #hasSelection
          )
         )
        nil
        nil
      )
!

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

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

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

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'New'
            #translateLabel: true
            #submenuChannel: #newMenu
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #enabled: #hasSelection
            #label: 'Rename...'
            #itemValue: #renameSelection
            #translateLabel: true
            #shortcutKey: #Replace
          )
         #(#MenuItem
            #enabled: #hasSelection
            #label: 'Properties...'
            #itemValue: #doShowProperties
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Truncate...'
            #itemValue: #truncateSelectedFilesToZeroSize
            #translateLabel: true
          )
         #(#MenuItem
            #label: 'Split...'
            #itemValue: #splitSelectedFiles
            #translateLabel: true
          )
         #(#MenuItem
            #label: 'Join...'
            #itemValue: #joinSelectedFiles
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Edit'
            #itemValue: #doShowFileContents
            #translateLabel: true
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #enabled: #hasFileSelection
            #label: 'File in'
            #itemValue: #fileFileIn
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasFileSelection
            #label: 'File in 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
          )
         )
        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 Type'
            #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
            #enabled: #hasFileSelection
            #label: 'Editor'
            #itemValue: #openEditor
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasFileSelection
            #label: 'HTML Reader'
            #itemValue: #openHTMLReader
            #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
            #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: #hasMP3PlayerAndSelection
            #label: 'MP3 Player'
            #itemValue: #openMP3Player
            #translateLabel: true
            #isVisible: #hasMP3Player
          )
         #(#MenuItem
            #enabled: #hasZipFileSelected
            #label: 'ZipFile Tool'
            #itemValue: #openZipTool
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #currentFilesAreInSameDirectory
            #label: 'Slide Show'
            #itemValue: #openSlideShow
            #translateLabel: true
            #isVisible: #hasSlideShow
          )
         #(#MenuItem
            #label: 'Find'
            #translateLabel: true
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'Find a File...'
                  #itemValue: #fileFindFile
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasSelection
                  #label: 'Find All Duplicate Files (Recursive)'
                  #itemValue: #fileFindAllDuplicates
                  #translateLabel: true
                )
               #(#MenuItem
                  #label: 'Find Duplicate Files'
                  #itemValue: #fileFindDuplicates
                  #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: 'Details'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #viewDetails
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #enabled: #viewDetails
            #label: 'Suffix'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #viewType
          )
         #(#MenuItem
            #enabled: #viewDetails
            #label: 'Permissions'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #viewPermissions
          )
         #(#MenuItem
            #enabled: #viewDetails
            #label: 'Owner'
            #translateLabel: true
            #isVisible: #userContextAvailable
            #hideMenuOnActivated: false
            #indication: #viewOwner
          )
         #(#MenuItem
            #enabled: #viewDetails
            #label: 'Group'
            #translateLabel: true
            #isVisible: #userContextAvailable
            #hideMenuOnActivated: false
            #indication: #viewGroup
          )
         #(#MenuItem
            #enabled: #viewDetails
            #label: 'Size'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #viewSize
          )
         #(#MenuItem
            #enabled: #viewDetails
            #label: 'Date && Time'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #viewTime
          )
         #(#MenuItem
            #enabled: #viewDetails
            #label: 'File Info'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #viewDescription
          )
         #(#MenuItem
            #enabled: #viewDetails
            #label: 'Preview'
            #translateLabel: true
            #hideMenuOnActivated: false
            #indication: #viewPreview
          )
         #(#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 (%1 b). 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 showAtPointer.
    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 
        do:[:app | app changeFileBrowserTitleTo:aString]
!

copyFileList
    "copy the fileList to the clipBoard"

    |itemList|

    itemList := self 
                    applicationNamed:#DirectoryContentsBrowser 
                    do:[:app | app browserItemList].
    self copyItemListToClipBoard:itemList.
!

copyItemListToClipBoard:itemList
    "copy the itemList to the clipBoard"

    |stream|

    itemList isEmpty ifTrue:[^ self].

    stream := WriteStream on:''.
    itemList do:[:item |
        stream nextPutLine:(item fileName asString).
    ].
    self window setTextSelection:stream contents.
    stream close.
!

copySelectedFilenames
    "copy the selected fileNames to the clipBoard"

    |itemList|

    itemList := self 
                    applicationNamed:#DirectoryContentsBrowser 
                    do:[:appl | appl selectedItems].

    self copyItemListToClipBoard:itemList.
!

doAddTerminal
    |dir directories|

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

    self applicationNamed:#FileApplicationNoteBook
        do:[: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.
        upDir := directories first directory.
    ] ifFalse:[
        rootInTreeView := self 
                            applicationNamed:#DirectoryTreeBrowser 
                            do:[: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 do:[:appl | appl doShowFileContents].
!

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

gotoFile:aFilename

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

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

newTextEditor
    ^ self applicationNamed:#FileApplicationNoteBook
        do:[:appl | appl newTextEditor]
!

openApplByFileItem:aItem

    ^ self applicationNamed:#FileApplicationNoteBook
        do:[:appl | appl openApplByFileItem:aItem]
!

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

openCommandResultApplication

    ^ self applicationNamed:#FileApplicationNoteBook
        do:[:appl | appl openCommandResultApplication]
!

openSearchFileOn:aItem

    ^ self applicationNamed:#FileApplicationNoteBook
        do:[:appl | appl openSearchFileOn:aItem]
!

openTextEditorOn:aItem

    ^ self applicationNamed:#FileApplicationNoteBook
        do:[:appl | appl openTextEditorOn:aItem ]
!

openTextEditorOn:aItem type:aDirDescrOrFile
    ^ self applicationNamed:#FileApplicationNoteBook
        do:[:appl | appl openTextEditorOn:aItem type:aDirDescrOrFile]
!

updateAndSelect:aColOfFiles
    DirectoryContents flushCachedDirectoryFor:(self getBestDirectory).

    self applicationNamed:#DirectoryContentsBrowser do:[:appl | appl doUpdate].
    self applicationNamed:#DirectoryTreeBrowser     do:[:appl | appl doUpdate].
    
    aColOfFiles notNil ifTrue:[ 
        self currentFileNameHolder value:aColOfFiles 
    ].
!

updateCurrentDirectory

    self updateAndSelect:nil
!

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 asFilename 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 do: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 ].
!

currentFileNameHolder

    " returns a OrderedCollection of all files that are selected
      if no file but a directory is selected it contains the directories 
      in contrast to currentDirectories which have only the directories 
    "
    ^ self aspectFor:#currentFileNameHolder ifAbsent:[
            | currentSel |    
            currentSel := self class currentSelection.
            currentSel notEmpty ifTrue:[
                currentSel asValue
            ] ifFalse:[
                (OrderedCollection with:(Filename currentDirectory asAbsoluteFilename)) asValue
            ]
        ] notPresentDo:[:holder|
            | filenames newFilenames|
            filenames := holder value.
            newFilenames := Set new.
            filenames do:[:filename |  | fn |
                fn := filename.                              
                [fn exists not] whileTrue:[
                    fn := fn directory.
                ].
                newFilenames add:fn.
            ].
            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
aString = 'nil' ifTrue:[self halt].
    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
    "
    |holder saveAspectItem aspect|

    holder := aspects at:something ifAbsent:[
        saveAspectItem := self runtimeAspectValueFor:something.
        saveAspectItem notNil ifTrue:[
            saveAspectItem isHolder ifTrue:[
                holder := ValueHolder with:saveAspectItem value 
            ] ifFalse:[
                holder := saveAspectItem value 
            ].
        ] ifFalse:[
            aspect := self userPreferencesAspectValueFor:something.
            aspect notNil ifTrue:[ 
                holder := aspect asValue
            ] ifFalse:[
                holder := aBlock value.
            ]
        ].
        holder notNil ifTrue:[        
            aspects at:something put:holder
        ]
    ].
    ^ holder
!

aspectFor:something ifAbsent:aBlock notPresentDo:notPresentBlock
    "returns the model for an aspect
    "
    |holder saveAspectItem aspect|

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

aspects
    ^ aspects
!

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

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
    "get the user preferences for show file description row in DirectoryContentsBrowser"

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

viewDetails
    "get the user preferences for view more file properties in rows in DirectoryContentsBrowser 
    "

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

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 row in DirectoryContentsBrowser "

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

viewNoteBookApplicationHolder

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

viewOwner

    " aspect for show owner information row in DirectoryContentsBrowser "

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

viewPermissions

    " aspect for show permission information row in DirectoryContentsBrowser "

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

viewPreview

    " aspect for show image previev row in DirectoryContentsBrowser "

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

viewSize

    " aspect for show size information row in DirectoryContentsBrowser "

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

viewTime

    " aspect for show time information row in DirectoryContentsBrowser "

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

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

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

!AbstractFileBrowser methodsFor:'background processing'!

executeCommand:cmd

    self executeCommand:cmd inDirectory:nil
!

executeCommand:cmd inDirectory:aDir

    | nameString executionBlock|

    executionBlock := self getExecutionBlockForCommand:cmd inDirectory:aDir.
    nameString := '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] 
                    valueNowOrOnUnwindDo:[
                        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'!

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 
                            do:[:appl | appl rootHolder].
        rootInTreeView := rootInTreeView notNil ifTrue:[rootInTreeView value].
        self enableDirectoryUp value:(((size == 1) and:[newDirectories first isRootDirectory not]) or:[(rootInTreeView notNil and:[rootInTreeView value asFilename isRootDirectory not])]).
        newDirectories notEmpty ifTrue:[
            self dirHistory addToHistory:(newDirectories first asString).
        ].
        self enableHome value:((newDirectories includes:(Filename homeDirectory))not).
        self enableGotoDefault value:((newDirectories includes:(Filename defaultDirectory))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'!

canDropArchiv:dropedObjects for:filename 

    (filename isDirectory 
    and:[filename isWritable and:[dropedObjects notEmpty]])  ifTrue:[
        ^ true
    ].
    ^ false
!

canDropFiles:dropedObjects for:filename 
    | checkObject filenameDirString checkObjectString filenameDir|

    dropedObjects isEmpty ifTrue:[^ false].
    filenameDir := self getDirWithoutFileName:filename.
    filenameDir isWritable not ifTrue:[^ false].
    filenameDirString := filenameDir asString.
    dropedObjects do:[:aObject | 
        checkObject := aObject theObject.
        checkObjectString := checkObject asString.
        checkObject isDirectory ifTrue:[
            (self fileName:filenameDirString startsWith:checkObjectString) ifTrue:[
                " can not drop a directory in his parents "
                ^ false
            ]
        ] ifFalse:[
            (filenameDirString = checkObject directory asString 
            or:[ filenameDirString = checkObject physicalPathName asFilename directory asString ]) ifTrue:[
                " can not drop a file in same directory "
                ^ false
            ]
        ]
    ].
    ^ true
!

doStartDrag:aDropSource in:aView
    "set the cursors before starting the drag & drop operation
    "
    |hdl|

    hdl := DragAndDropManager new.

    hdl disabledCursor:self class disabledCursorImage.
    hdl enabledCursor:self class enabledCursorImage.
    hdl alienCursor:nil.

    hdl startDragFrom:aView dropSource:aDropSource offset:#topLeft.

! !

!AbstractFileBrowser methodsFor:'file operations'!

copyFile:aSourceFile to:aDestFile
    "copy to
    "
    |copy|

    copy := FileOperation copy copyFile:aSourceFile to:aDestFile withOverWriteWarning:true copyFileIfSame:true.
    copy result ifTrue:[
        self 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 copy 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
    "
    |delete|

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

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

    |move|

    move := FileOperation move moveFile:aSourceFile to:aDestFile.
    move result ifTrue:[
        self 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 withWaitCursorDo:[
        move := FileOperation move moveFiles:aColOfSourceFiles to:aDirectory.
        move result ifFalse:[
            self notify:move errorString.
        ].
        self updateCurrentDirectory.
    ].
    ^ move colOfMovedFiles
!

newDirectory
    "ask for and create a new directory"

    |selectedFiles singleSelectedFile defaultAnswer directories directory createOp newFile mime|

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

    "/ clever default if selection is an archive...
    selectedFiles := self selectedFiles.
    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 isArchive ifTrue:[
                defaultAnswer := defaultAnswer asFilename withoutSuffix baseName
            ].
        ].
    ].

    createOp := FileOperation create 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 directories directory create file|

    directories := self currentDirectories value.
    (directories size ~= 1) ifTrue:[^ self].
    directory := directories first.
    curFile := self firstSelectedFile.
    curFile notNil ifTrue:[
        file := curFile.
    ] ifFalse:[
        file := directory.
    ].
    create := FileOperation create createFileIn:file.
    create result ifFalse:[ ^ self].
    self updateAndSelect:(OrderedCollection with:(create createdFile)).
!

newHardLink
    "ask for and create a hard link (unix only)"

    self newLink:false.
!

newLink:symbolic

    "ask for and create a symbolic if symbolic is true otherwise a hard link (unix only)"

    | sel create createdFile|

    sel := self currentFileNameHolder value.
    (sel size ~= 1) ifTrue:[^ self].
    symbolic ifTrue:[
        create := FileOperation create createSoftLinkIn:(sel first).
    ] ifFalse:[
        create := FileOperation create createHardLinkIn:(sel first).
    ].
    create result ifFalse:[ ^ self].
    createdFile := create createdFile.
    createdFile notNil ifTrue:[
        self updateAndSelect:(OrderedCollection with:createdFile).
    ].
!

newSoftLink
    "ask for and create a soft link (unix only)"

    self newLink:true.
!

pasteFiles
    "defete current selected files/directories
    "
    | buffer destination files directories copiedFiles|

    files := self clipboard files.
    (files isNil or:[files isEmpty]) ifTrue:[ ^ self ].
    buffer := self clipboard copy.
    directories := self 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 showAtPointer
    ] ifFalse:[
        destination := directories first.
    ].
    copiedFiles := self copyFiles:(buffer files) to:destination.
    
    (self clipboard method == #cut) ifTrue:[
        self deleteFiles:copiedFiles.
    ] 
!

renameFile:aFile 
    "rename the selected file(s)"

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

renameFile:filename to:newFileString update:aBoolean
    "rename filename to newFileString"

    |rename|

    rename := FileOperation rename renameFile:filename to:newFileString.
    rename result ifTrue:[
        aBoolean ifTrue:[
            self updateAndSelect:(rename renamedFiles).
        ].
    ] ifFalse:[
        self notify:rename errorString.
    ].
    ^ rename result
!

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

    |rename|

    rename := FileOperation rename 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 copy)
! !

!AbstractFileBrowser methodsFor:'menu accessing'!

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

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

    "
     MenuEditor new openOnClass:FileBrowser andSelector:#bookmarksMenuSpec
     (Menu new fromLiteralArrayEncoding:(AbstractFileBrowser bookmarksMenuSpec)) startUp
    "
    <resource: #programMenu>

    |menu bookmarks|

    menu := self class baseBookmarksMenuSpec decodeAsLiteralArray.
    menu findGuiResourcesIn:self.
    menu receiver:self.
    bookmarks := self class directoryBookmarks.
    "/ add the bookmark items ...

    bookmarks size > 0 ifTrue:[
        menu addItem:(MenuItem labeled:'-').
        bookmarks do:[:dirName |
            menu addItem:((MenuItem label:dirName asString value:[
                (self currentDirectories value includes:dirName) ifFalse:[
                    self currentFileNameHolder value:(OrderedCollection with:dirName).
                ].
            ])).
        ].
    ].
    ^ menu

    "Modified: / 17.8.1998 / 10:13:05 / cg"
!

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
    ^self class viewDetailsMenuSpec
!

viewInContentsBrowserMenu
    ^ self applicationNamed:#DirectoryContentsBrowser do:[:appl | appl viewBrowserMenu]
!

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

openAboutThisApplication
    "opens an about box for this application."

    DialogBox aboutClass:self class.
!

openHTMLDocument:relativeDocPath
    HTMLDocumentView openFullOnDocumentationFile:relativeDocPath
! !

!AbstractFileBrowser methodsFor:'menu actions cvs'!

cvsAddAndCommit

    |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.
                ]
            ] 
        ]
    ].
    nameString := 'Command> cvs add and commit'.
    self makeExecutionResultProcessFor:executionBlock withName:nameString.
!

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

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

"/    [
        skipSignal := Signal new.

        self withActivityIndicationDo:[
            self currentFileNameHolder value do:[:fileName |
                |imageOrNil inFile outFile eachConversionSuffixCommandPair doneWithThisFile
                 eachConversionSuffix eachConversionCommand tempFileTemplate|

                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 isNil ifTrue:[
                            chainOfConversions := self conversionChainFrom:(fileName suffix) to:outSuffix.
                        ] ifFalse:[
                            writer := MIMETypes imageReaderForSuffix:outSuffix.
                            (writer notNil and:[writer canRepresent:image]) ifTrue:[
                                writer save:image onFile:outFile.
                                skipSignal raise.
                            ].
                        ].

                        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 requestor: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 showAtPointer.
    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 * 10)); sizeFixed:false.
    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
                do:[:appl | appl openTextEditorWithHexPresentationOn:item].
    ].
!

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
!

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

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

    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
!

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 %2 ?\\WARNING: contents of file is lost !!\This cannot be undone.'.
    numFiles > 1 ifTrue:[
        msg := 'Really truncate %1 files ?\\WARNING: contents of files is lost !!\This cannot be undone.'.
    ].

    (Dialog 
        confirm:(msg bindWith:numFiles with:selectedFiles first baseName) 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

    |selectedFiles dirOfFile cvsDir|

    selectedFiles := self currentSelectedFiles.
    selectedFiles isEmpty ifTrue:[^ false].
    ^ ((selectedFiles detect:[:fileName|
        dirOfFile := self getDirWithoutFileName:fileName.
        cvsDir := dirOfFile construct:'CVS'.
        (cvsDir isDirectory and:[cvsDir exists])
    ] ifNone:[nil]) notNil).
! !

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

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) not) ifTrue:[ ^ nil].
    filename := selFiles first.

    buffer := '' asText writeStream.

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

    isLink := filename isSymbolicLink.
    isLink ifTrue:[
        buffer 
            nextPutAll:'symbolic link to: ';
            nextPutLine:(filename linkInfo path).
    ].

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

    s := ('type:   ').
    fileOutput isNil ifTrue:[
        s := s ,  type asString
    ] ifFalse:[
        s := s , 'regular (' , fileOutput , ')'
    ].
    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 
        do:[:app | app allItemsOfCurrentDirectory].
!

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 currentDirectories value size == 1).
!

currentFilesHasDirectories

    ^ self currentDirectories value notEmpty.
!

directoriesForFiles:aFileCol

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

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

fileListIsNotEmpty

    ^ self fileListIsEmpty not.   
!

fileName:aFilename1 startsWith:aFilename2

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

    | file1 file2 |

    aFilename2 isNil ifTrue:[ ^ false].
    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 do:[:appl | appl getAllFilesAsStringCollection].
!

getBestDirectory

    |selFiles stringCol firstPre|

    selFiles := self currentDirectories value.
    selFiles isEmpty ifTrue:[^ nil].
    selFiles size == 1 ifTrue:[^ selFiles first].
    stringCol := (selFiles collect:[:file| file asString]) asOrderedCollection.
    firstPre := stringCol at:1.
    stringCol from:2 do:[:el|
         firstPre :=  firstPre commonPrefixWith:el.
    ].
    (firstPre endsWith:(OperatingSystem fileSeparator)) ifTrue:[
        firstPre removeLast.
    ].
    ^ firstPre asFilename
!

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

!AbstractFileBrowser methodsFor:'selection'!

currentSelectedDirectories

    ^ self currentDirectories value.
!

currentSelectedFiles

    | files |
    files := self currentFileNameHolder value.
    ^ (files select:[: file | file isDirectory not]).
!

firstSelectedFile

    | files |
    files := self currentFileNameHolder value.
    ^ (files detect:[: file | file asFilename isDirectory not] ifNone:[nil]).
!

hasOnlyFilesSelected
    | files |
    files := self currentFileNameHolder value.
    ^ (files conform:[: file | file isDirectory not]).
!

hasTwoFilesSelected
    | files |
    files := self currentFileNameHolder value.
    ^ (files 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 ].
!

makeDirectorySortBlockFor:aSortBlock

    (self sortDirectoriesBeforeFiles value and:[self viewDirsInContentsBrowser value]) ifTrue:[
        ^ [:a :b|
            |aIsDir bIsDir res|

            aIsDir := a isDirectory.
            bIsDir := b isDirectory.
            (aIsDir ~~ bIsDir) ifTrue:[
                res := aIsDir 
            ] ifFalse:[
                res := aSortBlock value:a value:b.
            ].
            res
          ].
    ] ifFalse:[
        ^ aSortBlock
    ].
!

sortBlockHolder
    |nameSortBlock|

    ^ self aspectFor:#sortBlockHolder ifAbsent:[
        self sortCaseless value ifTrue:[
            nameSortBlock := [ :a :b | a asString asLowercase < b asString asLowercase.].
        ] ifFalse:[
            nameSortBlock := [ :a :b | a asString < b asString.].
        ].
        (self makeDirectorySortBlockFor:nameSortBlock) 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 cmpOp instanceSortBlock sortReverse|

    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.
    (currentSortOrder at:#reverse) ifTrue:[
        cmpOp := #'>'
    ] ifFalse:[
        cmpOp := #'<'
    ].
    sortReverse := currentSortOrder at:#reverse.
    instanceSortBlock := [:a :b | 
        |entry1 entry2|

        entry1 := (a perform:aSymbol).
        entry2 := (b perform:aSymbol).
        ((entry1 isNil) or:[entry2 isNil]) ifTrue:[
            ((entry1 isNil) and:[entry2 isNil]) ifTrue:[true] ifFalse:[
                ((entry1 notNil) and:[entry2 isNil]) ifTrue:[
                    sortReverse
                ] ifFalse:[
                    sortReverse not
                ]
            ]
        ] ifFalse:[
            ((aSymbol = #baseName) and:[sortCaselessLocal]) ifTrue:[
                entry1 := entry1 asLowercase.
                entry2 := entry2 asLowercase.
            ].
            entry1 perform:cmpOp with:entry2
        ]
    ].
    self sortBlockHolder value:(self makeDirectorySortBlockFor:instanceSortBlock).
! !

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

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

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:aApplItem

    super add:aApplItem.
    (self size > self class filenameHistorySize) ifTrue:[
        self removeLast.
    ]
! !

!AbstractFileBrowser::SaveAspectItem class methodsFor:'instance creation'!

withValue:aValue isHolder:aBoolean

    | instance |

    instance := self basicNew.
    instance value:aValue.
    instance isHolder:aBoolean.
    ^ instance
! !

!AbstractFileBrowser::SaveAspectItem methodsFor:'accessing'!

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

    ^ isHolder
!

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

    isHolder := something.
!

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

    ^ value
!

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

    value := something.
! !

!AbstractFileBrowser class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libtool/AbstractFileBrowser.st,v 1.133 2003-04-05 14:13:44 cg Exp $'
! !