AbstractFileBrowser.st
author Claus Gittinger <cg@exept.de>
Thu, 13 Feb 2003 13:11:48 +0100
changeset 4554 467311f7345a
parent 4535 4df3f171bcb0
child 4558 9f64535810cd
permissions -rw-r--r--
checkin from browser

"{ 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:'classAccess'!

directoryHistoryClass

    ^ AbstractFileBrowser::DirectoryHistory
!

filenameHistoryClass

    ^ FilenameHistory
! !

!AbstractFileBrowser class methodsFor:'classVarAccess'!

currentSelection

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

currentSelection:aFilenameCol

    CurrentSelection := aFilenameCol
!

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

directoryBookmarks

    DirectoryBookmarks isNil ifTrue:[                     
        DirectoryBookmarks := OrderedCollection new.
        DirectoryBookmarks add:Filename homeDirectory asAbsoluteFilename.
        DirectoryBookmarks add:Filename tempDirectory.
        DirectoryBookmarks add:Filename currentDirectory asAbsoluteFilename.
        Smalltalk systemPath do:[:path |
            ((path ~= '.') and:[path asFilename exists]) ifTrue:[
                DirectoryBookmarks add:path asFilename.
            ]
        ]
    ].
    ^ DirectoryBookmarks

"/    DirectoryBookmarks := nil
!

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

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
          )
         )
        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: #truncateSelectedFiles
            #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: #hasSelection
            #label: 'File in'
            #itemValue: #fileFileIn
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasSelection
            #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: #hasSelection
            #label: 'Changes Browser'
            #itemValue: #openChangesBrowser
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasSelection
            #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: #hasSelection
            #label: 'Editor'
            #itemValue: #openEditor
            #translateLabel: true
          )
         #(#MenuItem
            #enabled: #hasSelection
            #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: #hasSelection
                  #label: 'Image Editor'
                  #itemValue: #openImageEditor
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasSelection
                  #label: 'Image Preview'
                  #itemValue: #openImagePreview
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasSelection
                  #label: 'Image Inspector'
                  #itemValue: #openImageInspector
                  #translateLabel: true
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #enabled: #hasSelection
                  #label: 'Convert to GIF'
                  #itemValue: #convertImageToGIF
                  #translateLabel: true
                )
               #(#MenuItem
                  #enabled: #hasSelection
                  #label: 'Convert to PNG'
                  #itemValue: #convertImageToPNG
                  #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: #hasSelection
            #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:DirectoryContentsBrowser andSelector:#viewBrowserMenu
     (Menu new fromLiteralArrayEncoding:(DirectoryContentsBrowser viewBrowserMenu)) startUp
    "

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Suffix'
            #translateLabel: true
            #hideMenuOnActivated: false
            #enabled: #viewDetails
            #indication: #viewType
          )
         #(#MenuItem
            #label: 'Permissions'
            #translateLabel: true
            #hideMenuOnActivated: false
            #enabled: #viewDetails
            #indication: #viewPermissions
          )
         #(#MenuItem
            #label: 'Owner'
            #translateLabel: true
            #hideMenuOnActivated: false
            #enabled: #viewDetails
            #indication: #viewOwner
          )
         #(#MenuItem
            #label: 'Group'
            #translateLabel: true
            #hideMenuOnActivated: false
            #enabled: #viewDetails
            #indication: #viewGroup
          )
         #(#MenuItem
            #label: 'Size'
            #translateLabel: true
            #hideMenuOnActivated: false
            #enabled: #viewDetails
            #indication: #viewSize
          )
         #(#MenuItem
            #label: 'Date && Time'
            #translateLabel: true
            #hideMenuOnActivated: false
            #enabled: #viewDetails
            #indication: #viewTime
          )
         #(#MenuItem
            #label: 'File Info'
            #translateLabel: true
            #hideMenuOnActivated: false
            #enabled: #viewDetails
            #indication: #viewDescription
          )
         #(#MenuItem
            #label: 'Preview'
            #translateLabel: true
            #hideMenuOnActivated: false
            #enabled: #viewDetails
            #indication: #viewPreview
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Hidden Files'
            #translateLabel: true
            #indication: #showHiddenFiles
          )
         )
        nil
        nil
      )
! !

!AbstractFileBrowser class methodsFor:'misc'!

newLock
    ^ CodeExecutionLock new
! !

!AbstractFileBrowser methodsFor:'actions'!

askForCommandFor:fileName thenDo:aBlock
    "setup and launch a querybox to ask for unix command.
     Then evaluate aBlock passing the command-string as argument."

    |box osName 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 application:#FileBrowserV2
         do:#changeFileBrowserTitleTo:                            
         withArg:aString
!

copyFileList

    | fileList stream|
    fileList := self application:#DirectoryContentsBrowser do:#descriptions.
    stream := WriteStream on:''.
    fileList do:[: item |
        stream nextPutLine:(item fileName asString).
    ].
    self window setTextSelection:stream contents.
    stream close.
!

copySelectedFilenames

    | fileList stream|
    fileList := self application:#DirectoryContentsBrowser do:#selectedFiles.
    fileList isEmpty ifTrue:[^ self].
    stream := WriteStream on:''.
    fileList do:[: file |
        stream nextPutLine:(file asString).
    ].
    self window setTextSelection:stream contents.
    stream close.
!

doAddTerminal

    | item dir directories|

    directories := self currentDirectories value.
    
    directories isEmpty ifTrue:[
        dir :=  Filename homeDirectory
    ] ifFalse:[
        dir :=  directories first.
    ].
    
    item := (DirectoryContentsBrowser itemClass fileName:dir).
    self fileApplicationDo:#openTerminalApplication: withArg:item.
!

doCompareTwoFiles

    self openDiffView.
"
    |files fileName1 fileName2 stream1 stream2 buffer1 buffer2 n1 n2 idx blockSize blockOffset|

    files := self currentFileNameHolder value.
    fileName1 := files first.
    fileName2 := files second.

    (fileName1 exists and:[fileName1 isReadable]) ifFalse:[
        Dialog warn:(resources string:'Cannot read %1' with:fileName1 pathName allBold).
        ^ self.
    ].
    (fileName2 exists and:[fileName2 isReadable]) ifFalse:[
        Dialog warn:(resources string:'Cannot read %1' with:fileName2 pathName allBold).
        ^ self.
    ].
    [
        stream1 := fileName1 readStream.
        stream2 := fileName2 readStream.

        stream1 binary. stream2 binary.

        blockSize := 8192.
        buffer1 := ByteArray new:blockSize.
        buffer2 := ByteArray new:blockSize.

        blockOffset := 0.

        [stream1 atEnd] whileFalse:[
            n1 := stream1 nextBytes:(buffer1 size) into:buffer1 startingAt:1.
            n2 := stream2 nextBytes:n1 into:buffer2 startingAt:1.

            n1 ~~ n2 ifTrue:[
self halt.
            ] ifFalse:[
                buffer1 ~= buffer2 ifTrue:[
                    idx := (1 to:n1) findFirst:[:idx | (buffer1 at:idx) ~~ (buffer2 at:idx)].
                    Dialog information:(resources 
                                            string:'Files differ at position %1 (0x%2 vs. 0x%3)' 
                                            with:(blockOffset+idx)
                                            with:((buffer1 at:idx) hexPrintString:2)
                                            with:((buffer2 at:idx) hexPrintString:2)
                                       ).
                    ^ self.
                ] 
            ].
            blockOffset := blockOffset + n1.
        ].
        stream2 atEnd ifFalse:[
    self halt.
        ].
    ] ensure:[
        stream1 notNil ifTrue:[stream1 close].
        stream2 notNil ifTrue:[stream2 close].
    ].

self halt.
"
"/    action := [:command | 
"/                self addToCommandHistory:command for:fileName.
"/                self executeCommand:command.
"/              ].
"/    self askForCommandFor:fileName thenDo:action
!

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 application:#DirectoryTreeBrowser do:#rootHolder.
        upDir := rootInTreeView value asFilename directory.
    ].
    self currentFileNameHolder value:(OrderedCollection with:upDir).
!

doGotoDefaultDirectory
    self gotoFile:(Filename defaultDirectory).
!

doGotoHomeDirectory

    | home |

    home := Filename homeDirectory.
    self gotoFile:home.
!

doOpenSearchFile

    |item files|

    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 application:#DirectoryContentsBrowser do:#doShowFileContents.
!

doShowProperties

    "show long stat (file)-info"

    self fileGetInfo:true
!

fileApplicationDo:selector

    ^ self application:#FileApplicationNoteBook do:selector
!

fileApplicationDo:selector withArg:arg
    ^ self application:#FileApplicationNoteBook do:selector withArg:arg 
!

fileGetInfo:longInfo 
    "get info on selected file - show it in a box"

    |string box updater|

    string := self getFileInfoStringForFirstSelectedFile:longInfo.
    string notNil ifTrue:[
        box := InfoBox title:string.
        updater := [
                    [true] whileTrue:[
                        Delay waitForSeconds:2.
                        string := self getFileInfoStringForFirstSelectedFile:longInfo.
                        string isNil ifTrue:[ ^ self].
                        box title:string
                    ]
                ] fork.
        box showAtPointer.
        updater terminate.
        box destroy
    ]
!

gotoFile:aFilename

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

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

newTextEditor

    ^ self fileApplicationDo:#newTextEditor
!

openApplByFileItem:aItem

    ^ self fileApplicationDo:#openApplByFileItem: withArg:aItem
!

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

openCommandResultApplication

    ^ self fileApplicationDo:#openCommandResultApplication
!

openSearchFileOn:aItem

    ^ self fileApplicationDo:#openSearchFileOn: withArg:aItem
!

openTextEditorOn:aItem

    ^ self fileApplicationDo:#openTextEditorOn: withArg:aItem 
!

updateAndSelect:aColOfFiles

    DirectoryContents flushCachedDirectoryFor:(self getBestDirectory).
    self application:#DirectoryContentsBrowser do:#doUpdate.
    self application:#DirectoryTreeBrowser do:#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 addBookmark:directories.
!

addBookmark:aColOfDirectories
    |idx bookmarks|

    aColOfDirectories do:[ : path |
        bookmarks := self class directoryBookmarks.
        idx := bookmarks indexOf:path.
        idx == 0 ifTrue:[
            bookmarks addLast:path.
        ].
    ].
!

hasBookmarks
    ^ self class directoryBookmarks size > 0
!

hasBookmarksToRemove

    |bookmarks directories|

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

removeBookmark

    |bookmarks directories|

    bookmarks := self class directoryBookmarks.
    bookmarks isNil ifTrue:[ ^ self].
    directories := self currentSelectedDirectories.
    directories isEmpty ifTrue:[^ self].
    directories do:[:dir|
        bookmarks remove:dir ifAbsent:nil.
    ].
! !

!AbstractFileBrowser methodsFor:'actions history'!

addToCommandHistory:aCommandString for:aFilename
    |cmd suffix cmdHist|

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

doBack

    | fileName|

    fileName := self dirHistory 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'!

application:aApplication do:aMethod 

    " perform a Method for a application "
    |appl|

    appl := self applications at:aApplication ifAbsent:nil.
    appl notNil ifTrue:[
        ^ appl perform:aMethod.
    ].
    ^ nil.
!

application:aApplication do:aMethod withArg:arg 
    |appl|

    appl := self applications at:aApplication ifAbsent:nil.
    appl notNil ifTrue:[
        ^ appl perform:aMethod with:arg
    ].
    ^ nil
!

application:aApplication do:aMethod withArg:arg1 withArg:arg2
    |appl|

    appl := self applications at:aApplication ifAbsent:nil.
    appl notNil ifTrue:[
        (arg1 notNil and:[arg2 notNil]) ifTrue:[
            ^ appl perform:aMethod with:arg1 with:arg2
        ]
    ].
    ^ nil
!

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 aspectFor:#hasSelection ifAbsent:[ false asValue ].
!

currentDirectories

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

    ^ self aspectFor:#currentDirectories ifAbsent:[ (OrderedCollection new) asValue ].
!

currentFileNameHolder

    " returns a OrderedCollection of all files that are selected
      if no file but a directory is selected it contains the directories 
      in contrast to currentDirectories wich have only the directories 
    "
    ^ self aspectFor:#currentFileNameHolder ifAbsent:[
            self class currentSelection notEmpty ifTrue:[
                self class currentSelection 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]
!

enableHome

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

enableViewNoteBookApplication

    ^ self aspectFor:#enableViewNoteBookApplication 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|

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

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:[ true asValue].
    holder onChangeEvaluate:[ self notify:'' ].
    ^ holder
!

showHiddenFiles

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

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

abstractCurrentFileNameHolderChanged
    " do here all the things that have to be done for every part of the FileBrowserV2
      and the things that have to be done if it runs standalone "

    | newDirectories oldDirectories size rootInTreeView selection |

    selection := self currentFileNameHolder value.
    self class currentSelection:selection.
    self hasSelection value:(selection notEmpty).
    newDirectories := self directoriesForFiles:selection.
    oldDirectories := self currentDirectories value.
    oldDirectories ~= newDirectories ifTrue:[
        self currentDirectories value:newDirectories.
        size := newDirectories size.
        rootInTreeView := self application:#DirectoryTreeBrowser do:#rootHolder.
        rootInTreeView := rootInTreeView notNil ifTrue:[rootInTreeView value].
        self enableDirectoryUp value:(((size == 1) and:[newDirectories first isRootDirectory not]) or:[(rootInTreeView notNil and:[rootInTreeView value asFilename isRootDirectory not])]).
        newDirectories notEmpty ifTrue:[
            self dirHistory addToHistory:(newDirectories first asString).
        ].
        self enableHome value:((newDirectories includes:(Filename homeDirectory))not).
    ].
    self enableForward value:self canForward.
    self enableBack value:self canBackward.
    ^ self
!

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

    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|

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

copyOrMoveDialog:aCol

    | size stream dialog|

    size := aCol size.
    stream := WriteStream on:''.
    stream nextPutAll:'copy or move file'.
    size == 1 ifFalse:[
        stream nextPutAll:'s'.
    ].
    stream nextPutAll:': '.
    stream nextPutAll:aCol first baseName asString.
    size == 1 ifFalse:[
        stream nextPutAll:' ... '.
        stream nextPutAll:aCol last baseName asString.
    ].

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

copyOrMoveFiles:aColOfSourceFiles to:aDestinationDirectory 
   "copy aColOfSourceFiles to aDirectory
   "
    |dialog lastOld lastNew|

    dialog := self copyOrMoveDialog:aColOfSourceFiles.
    dialog == #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:[^ self].
            self copyFile:eachSourceFile to:(aDestinationDirectory construct:dstBase).
            lastOld := srcBase.
            lastNew := dstBase.
        ].

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

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|

    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:(rename renamedFiles)
    ].
    ^ rename result
!

renameSelection
    "rename the selected file(s)"

    self renameFiles:self currentFileNameHolder value
! !

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

    |menuSpec menu bookmarks|

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

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

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

canBackward


    ^ self dirHistory canBackward.
!

canForward

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

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

    |menu pathList currentSel currentPath|

    menu := Menu new.
    menu receiver:self.

    self dirHistory isEmpty ifTrue:[^ nil].
    backOrForward == #back ifTrue:[
        currentSel := self currentDirectories value.
        currentSel size == 1 ifTrue:[
            currentPath := currentSel first asString.
        ] ifFalse:[
            currentPath := nil.
        ].
        pathList := self dirHistory 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 application:#DirectoryContentsBrowser do:#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').
    removeItem := MenuItem new.
    removeItem translateLabel:true.
    removeItem label:text.
    removeItem value:[
        self dirHistory removeAll.
        self enableForward value:self canForward.
        self enableBack value:self canBackward.
    ].
    histCopy := self dirHistory.
    histCopy do:[:aFile| 
        menu addItem:(MenuItem label:aFile asString value:[
            self currentFileNameHolder value:(OrderedCollection with:(aFile path asFilename)).
        ]).
    ].
    menu addItem:(MenuItem label:'-').
    menu addItem:removeItem.
    ^ menu
! !

!AbstractFileBrowser methodsFor:'menu actions - cvs'!

cvsAddAndCommit

    |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 notNil ifTrue:[
        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'!

convertImageToGIF
    self 
        convertImageUsingChain:
            (Array
                with:('ppm' -> 'xpmtoppm')
                with:('gif' -> 'ppmtogif')
            )
    
"/    |img tempFileXPM tempFilePPM tempFileGIF|
"/
"/    [
"/        self withActivityIndicationDo:[
"/            self currentFileNameHolder value do:[:fileName |
"/                fileName isDirectory ifFalse:[
"/                    self notify:('Convert to GIF:',  fileName baseName).
"/                    img := Image fromFile:(fileName pathName).
"/                    img notNil ifTrue:[
"/                        tempFileXPM  := Filename newTemporary withSuffix:'xpm'.
"/                        tempFilePPM := tempFileXPM withSuffix:'ppm'.
"/                        tempFileGIF := tempFileXPM withSuffix:'gif'.
"/                        [
"/                            img saveOn:tempFileXPM using:XPMReader.
"/
"/
"/                            (OperatingSystem 
"/                                    executeCommand:('xpmtoppm %1 > %2' 
"/                                                        bindWith:tempFileXPM pathName
"/                                                        with:tempFilePPM pathName))
"/                            ifFalse:[
"/                                self warn:'Cannot convert to ppm format'.
"/                            ] ifTrue:[
"/                                (OperatingSystem 
"/                                        executeCommand:('ppmtogif %1 > %2' 
"/                                                            bindWith:tempFilePPM pathName
"/                                                            with:tempFileGIF pathName))
"/                                ifFalse:[
"/                                    self warn:'Cannot convert to gif format'.
"/                                ] ifTrue:[
"/                                    tempFileGIF moveTo:(fileName withSuffix:'gif').
"/                                    self updateAndSelect:nil.
"/                                ].
"/                            ].
"/                        ] ensure:[
"/                            tempFileXPM delete.
"/                            tempFilePPM delete.
"/                            tempFileGIF delete.
"/                        ]
"/                    ] ifFalse:[
"/                        self warn:'Unknown format/not an image: ' , fileName asString
"/                    ]
"/                ]
"/            ].
"/            self notify:''.
"/        ]
"/    ] fork.
!

convertImageToPNG
    self 
        convertImageUsingChain:
            (Array
                with:('ppm' -> 'xpmtoppm')
                with:('png' -> 'ppmtopng')
            )

"/    |img tempFileXPM tempFilePPM tempFilePNG|
"/
"/    [
"/        self withActivityIndicationDo:[
"/            self currentFileNameHolder value do:[:fileName |
"/                fileName isDirectory ifFalse:[
"/                    self notify:('Convert to PNG:',  fileName baseName).
"/                    img := Image fromFile:(fileName pathName).
"/                    img notNil ifTrue:[
"/                        tempFileXPM  := Filename newTemporary withSuffix:'xpm'.
"/                        tempFilePPM := tempFileXPM withSuffix:'ppm'.
"/                        tempFilePNG := tempFileXPM withSuffix:'png'.
"/                        [
"/                            img saveOn:tempFileXPM using:XPMReader.
"/
"/
"/                            (OperatingSystem 
"/                                    executeCommand:('xpmtoppm %1 > %2' 
"/                                                        bindWith:tempFileXPM pathName
"/                                                        with:tempFilePPM pathName))
"/                            ifFalse:[
"/                                self warn:'Cannot convert to ppm format'.
"/                            ] ifTrue:[
"/                                (OperatingSystem 
"/                                        executeCommand:('ppmtopng %1 > %2' 
"/                                                            bindWith:tempFilePPM pathName
"/                                                            with:tempFilePNG pathName))
"/                                ifFalse:[
"/                                    self warn:'Cannot convert to gif format'.
"/                                ] ifTrue:[
"/                                    tempFilePNG moveTo:(fileName withSuffix:'png').
"/                                    self updateAndSelect:nil.
"/                                ].
"/                            ].
"/                        ] ensure:[
"/                            tempFileXPM delete.
"/                            tempFilePPM delete.
"/                            tempFilePNG delete.
"/                        ]
"/                    ] ifFalse:[
"/                        self warn:'Unknown format/not an image: ' , fileName asString
"/                    ]
"/                ]
"/            ].
"/            self notify:''.
"/        ]
"/    ] fork.
!

convertImageUsingChain:chainOfConversions
    |img tempFileXPM|

    [
        self withActivityIndicationDo:[
            self currentFileNameHolder value do:[:fileName |
                |inFile outFile|

                self notify:('Converting:',  fileName baseName).
                fileName isDirectory ifFalse:[
                    img := Image fromFile:(fileName pathName).
                    img notNil ifTrue:[
                        tempFileXPM  := Filename newTemporary withSuffix:'xpm'.

                        [
                            img saveOn:tempFileXPM using:XPMReader.

                            inFile := tempFileXPM.
                            chainOfConversions do:[:eachConversionSuffixCommandPair |
                                |eachConversionSuffix eachConversionCommand|

                                eachConversionSuffix := eachConversionSuffixCommandPair key.
                                eachConversionCommand := eachConversionSuffixCommandPair value.

                                self notify:('Converting to ',  eachConversionSuffix , '...').
                                outFile := Filename newTemporary withSuffix:eachConversionSuffix.
                                (OperatingSystem 
                                        executeCommand:('%1 %2 > %3' 
                                                            bindWith:eachConversionCommand
                                                            with:inFile pathName
                                                            with:outFile pathName))
                                ifFalse:[
                                    inFile delete.
                                    outFile delete.
                                    self warn:('Conversion to %1 using %2 failed.' 
                                            bindWith:eachConversionSuffix
                                            with:eachConversionCommand allBold).
                                    ^ self.
                                ].
                                inFile delete.
                                inFile := outFile.
                            ].
                        ] ensure:[
                            inFile delete.
                            outFile delete.
                        ].

                        outFile moveTo:(fileName withSuffix:(chainOfConversions last key)).
                        self updateAndSelect:nil.
                    ] ifFalse:[
                        self warn:'Unknown format/not an image: ' , fileName asString
                    ]
                ]
            ].
            self notify:''.
        ]
    ] fork.
!

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 := FileBrowserV2SettingsFrame 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.
        fileNames := fileNames collect:[:fn | dir construct:fn].
        fileNames := fileNames select:[:fn | fn isDirectory not].

"/        self label:myName , '- gathering sizes ...'.
        infoDir := Dictionary new.
        fileNames do:[:fn |
            infoDir at:fn put:(fn fileSize)
        ].

        "/ for each, get the files size.
        "/ in a first pass, look for files of the same size and
        "/ compare them ...

"/        self label:myName , '- preselect possible duplicates ...'.
        filesBySize := Dictionary new.
        infoDir keysAndValuesDo:[:fn :sz |
            |entry|

            entry := filesBySize at:sz ifAbsentPut:[Set new].
            entry add:fn.
        ].

        "/ any of same size ?

"/        self label:myName , '- checking for duplicates ...'.
        filesBySize do:[:entry |
            |files|

            entry size > 1 ifTrue:[
                files := entry asArray.
                1 to:files size-1 do:[:idx1 |
                    idx1+1 to:files size do:[:idx2 |
                        |fn1 fn2|

                        fn1 := files at:idx1.
                        fn2 := files at:idx2.

"/                        self label:myName , '- checking ' , fn1 baseName , ' vs. ' , fn2 baseName , ' ...'.
                        (result at:fn2 ifAbsent:nil) ~= fn1 ifTrue:[
                            "/ compare the files
                            (fn1 sameContentsAs:fn2) ifTrue:[
"/                                Transcript show:'Same: '; show:fn1 baseName; show:' and '; showCR:fn2 baseName.
                                result at:fn1 put:fn2.
                            ]
                        ]
                    ]
                ]
            ]
        ].

"/        self label:myName , '- sorting ...'.
        dirPrefix := dir pathName.
        result := result associations.
        result := result collect:[:assoc |
                                        |f1 f2|

                                        f1 := assoc key name.
                                        f2 := assoc value name.
                                        (f1 startsWith:dirPrefix) ifTrue:[
                                            f1 := f1 copyFrom:dirPrefix size + 2.
                                        ].
                                        (f2 startsWith:dirPrefix) ifTrue:[
                                            f2 := f2 copyFrom:dirPrefix size + 2.
                                        ].
                                        f1 < f2 ifTrue:[
                                            f2 -> f1
                                        ] ifFalse:[
                                            f1 -> f2
                                        ]
                                ].
        result sort:[:f1 :f2 | f2 value < f1 value].

        info := OrderedCollection new.
        result do:[:assoc |
            info add:(assoc key , ' same as ' , assoc value)
        ].
        info isEmpty ifTrue:[
            info := 'No duplicate files found.'
        ].
    ].

    stream := WriteStream on:''.
    info do:[:el|
        stream nextPutLine:el.
    ].
    textBox := TextBox new.
    textBox initialText:(stream contents).
    textBox title:'File dublicates in directory: ', dir asString.
    textBox readOnly:true.
    textBox noCancel.
    textBox label:'Dublicates in ', dir asString.
    maxLength := 10.
    info do:[: el |
        maxLength := maxLength max:(el size).
    ].
    textBox extent:((maxLength * 5)@(info size * 20)); sizeFixed:false.
    textBox showAtPointer.
    stream close.
"/    subView contents:info.
"/    self label:myName.
!

fileFindDuplicates
    "scan directory for duplicate files"

    |fileNames 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].
            fileNames := fileNames select:[:fn | fn isDirectory not].
            allFiles addAll:fileNames.
        ].

        infoDir := Dictionary new.
        allFiles do:[:fn |
            infoDir at:fn put:(fn info)
        ].

        "/ for each, get the files size.
        "/ in a first pass, look for files of the same size and
        "/ compare them ...

        filesBySize := Dictionary new.
        infoDir keysAndValuesDo:[:fn :info |
            |sz entry|

            sz := info size.
            entry := filesBySize at:sz ifAbsentPut:[Set new].
            entry add:fn.
        ].

        "/ any of same size ?

        filesBySize do:[:entry |
            |files|

            entry size > 1 ifTrue:[
                files := entry asArray.
                1 to:files size-1 do:[:idx1 |
                    idx1+1 to:files size do:[:idx2 |
                        |fn1 fn2|

                        fn1 := files at:idx1.
                        fn2 := files at:idx2.

                        (result at:fn2 ifAbsent:nil) ~= fn1 ifTrue:[
                            "/ compare the files
                            (fn1 sameContentsAs:fn2) ifTrue:[
"/                                Transcript show:'Same: '; show:fn1 baseName; show:' and '; showCR:fn2 baseName.
                                result at:fn1 put:fn2.
                            ]
                        ]
                    ]
                ]
            ]
        ].

        result := result associations.
        result := result collect:[:assoc |
                                        |f1 f2|

                                        f1 := assoc key asString.
                                        f2 := assoc value asString.
                                        f1 < f2 ifTrue:[
                                            f2 -> f1
                                        ] ifFalse:[
                                            f1 -> f2
                                        ]
                                ].
        result sort:[:f1 :f2 | f2 value < f1 value].

        info := OrderedCollection new.
        size := self getBestDirectory asString size.
        result do:[:assoc |
            |fn1 fn2|

            fn1 := assoc key.
            fn2 := assoc value.
            size > 1 ifTrue:[
                fn1 := ('..', (fn1 copyFrom:(size + 1))).
                fn2 := ('..', (fn2 copyFrom:(size + 1))).
            ].
            (fn1 includes:Character space) ifTrue:[
                fn1 := '"' , fn1 , '"'
            ].
            (fn2 includes:Character space) ifTrue:[
                fn2 := '"' , fn2 , '"'
            ].
            info add:(fn1 , ' same as ' , fn2)
        ].
        info isEmpty ifTrue:[
            info add:'No duplicate files found.'
        ].
    ].
    stream := WriteStream on:''.
    info do:[:el|
        stream nextPutLine:el.
    ].
    titleStream := WriteStream on:''.
    titleStream nextPutAll:'File dublicates 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:'Dublicates 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.
!

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

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 getAllFilesAsStringCollection 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).
        ^ 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 , '/' , 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 readStream.
            aStream notNil ifTrue:[
                aStream fileInBinary.
            ]
        ] ifFalse:[
            ((fileName hasSuffix:'class')
            or:[(fileName hasSuffix:'cla')]) ifTrue:[
                "/ loading a java class file
                JavaClassReader notNil ifTrue:[
                    JavaClassReader loadFile:(fileName pathName)
                ]
            ] ifFalse:[ (fileName hasSuffix:'sif') ifTrue:[
                "/ loading a sif (smalltalk interchange format) file
                SmalltalkInterchangeSTXFileInManager autoload.    
                SmalltalkInterchangeFileManager newForFileIn
                    fileName: fileName pathName;
                    fileIn.
            ] ifFalse:[ (fileName hasSuffix:'pcl') ifTrue:[
                Parcel isNil ifTrue:[
                    Dialog warn:'Parcel support not loaded.'
                ] ifFalse:[
                    Parcel loadParcelFrom: fileName pathName
                ]
            ] ifFalse:[
                "/ loading a regular (chunk) or xml source file
                aStream := fileName readStream.
                aStream notNil ifTrue:[
                    Error handle:[ : ex |
                        Dialog warn:'Error on file in: ', ex errorString.
                    ] do:[
                        [
                            Class withoutUpdatingChangesDo:[
                                wasLazy := Compiler compileLazy:lazy.
                                aStream fileIn.
                            ].
                            Class addInfoRecord:('fileIn ' , fileName asString) 
                        ] ensure:[
                            Compiler compileLazy:wasLazy.
                            aStream close
                        ]
                    ]
                ]
            ]]]
        ]]
    ].
!

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 isNil ifTrue:[
                self warn:('Cannot truncate "%1".' bindWith:fileName baseName allBold).
            ] ifFalse:[
                s close.
            ]
        ]
    ].
    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 text fileOutput type modeBits modeString s ts isLink info|

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

    text := StringCollection new.

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

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

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

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

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

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

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 application:#DirectoryContentsBrowser do:#allItemsOfCurrentDirectory.
!

anyFilesPresentWithSuffix:suffix

    | directories |

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

currentFilesAreInSameDirectory

    ^ (self currentDirectories value size == 1).
!

currentFilesHasDirectories

    ^ self currentDirectories value notEmpty.
!

directoriesForFiles:aFileCol

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

fileListIsEmpty

    ^ self application:#DirectoryContentsBrowser do:#fileListIsEmpty.
!

fileListIsNotEmpty

    ^ self fileListIsEmpty not.   
!

fileName:aFilename1 startsWith:aFilename2

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

    | file1 file2 |

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

getBestDirectory

    |selFiles stringCol firstPre|

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

getCommonForCurrentFiles

    |selFiles stringCol firtsPre|

    selFiles := self currentFileNameHolder value.
    selFiles isEmpty ifTrue:[^ nil].
    stringCol := selFiles collect:[: file| file asString].
    firtsPre := stringCol at:1.
    stringCol from:2 do:[:el|
         firtsPre :=  firtsPre commonPrefixWith:el.
    ].
    ^ firtsPre asFilename
!

getDirWithoutFileName:aFileName

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

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

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.92 2003-02-13 12:11:48 cg Exp $'
! !