category changes
authorClaus Gittinger <cg@exept.de>
Wed, 23 Apr 1997 13:30:25 +0200
changeset 1162 08940832d3a8
parent 1161 4130c98f3268
child 1163 b36faf475548
category changes
FBrowser.st
FileBrowser.st
--- a/FBrowser.st	Tue Apr 22 19:33:37 1997 +0200
+++ b/FBrowser.st	Wed Apr 23 13:30:25 1997 +0200
@@ -555,12 +555,13 @@
             label := 'get'.
         ].
         (self ask:(resources at:msg) yesButton:label) ifTrue:[
+            subView modified:false.
             self doFileGet:viaDoubleClick
         ]
     ]
 
     "Created: 19.6.1996 / 09:38:35 / cg"
-    "Modified: 2.4.1997 / 23:24:40 / cg"
+    "Modified: 23.4.1997 / 13:04:11 / cg"
 !
 
 fileGetInfo
@@ -587,7 +588,7 @@
 !
 
 fileInsert
-    "insert contents of file at cursor"
+    "insert contents of file at the cursor position"
 
     |fileName|
 
@@ -596,7 +597,7 @@
         self showFile:fileName insert:true encoding:fileEncoding
     ]
 
-    "Modified: 22.2.1996 / 14:47:16 / cg"
+    "Modified: 23.4.1997 / 13:06:06 / cg"
 !
 
 fileListMenu
@@ -736,6 +737,8 @@
 !
 
 filePrint
+    "send a files contents to the printer (not in the menu)"
+
     |fileName inStream printStream line|
 
     self withWaitCursorDo:[
@@ -760,7 +763,7 @@
         0 "compiler hint"
     ]
 
-    "Modified: 9.11.1996 / 00:15:07 / cg"
+    "Modified: 23.4.1997 / 13:05:40 / cg"
 !
 
 fileRemove
@@ -799,7 +802,10 @@
 
 fileSelect:lineNr
     "selected a file - do nothing here"
+
     ^ self
+
+    "Modified: 23.4.1997 / 13:04:55 / cg"
 !
 
 fileSpawn
@@ -829,8 +835,9 @@
                     title:(resources at:'create new directory:') withCRs
                     okText:(resources at:'create')
                     action:[:newName | self doCreateDirectory:newName].
-"/    queryBox initialText:''.
     queryBox showAtPointer
+
+    "Modified: 23.4.1997 / 13:04:27 / cg"
 !
 
 newFile
@@ -845,12 +852,10 @@
     sel := subView selection.
     sel notNil ifTrue:[
         queryBox initialText:(sel asString)
-"/    ] ifFalse:[
-"/        queryBox initialText:''
     ].
     queryBox showAtPointer
 
-    "Modified: 21.2.1996 / 01:43:14 / cg"
+    "Modified: 23.4.1997 / 13:04:38 / cg"
 !
 
 openChangesBrowser
@@ -1556,6 +1561,451 @@
         yesButton:yesButtonText
 !
 
+getSelectedFileName
+    "returns the currently selected file; shows an error if
+     multiple files are selected"
+
+    |sel|
+
+    sel := fileListView selection.
+    (sel size > 1) ifTrue:[
+        self onlyOneSelection
+    ] ifFalse:[
+        sel notNil ifTrue:[
+            ^ fileList at:sel first
+        ]
+    ].
+    ^ nil
+!
+
+onlyOneSelection
+    "show a warning, that only one file must be selected for
+     this operation"
+
+    self warn:'exactly one file must be selected !!'
+!
+
+selectedFilesDo:aBlock
+    "evaluate aBlock on all selected files;
+     show a wait cursor while doing this"
+
+    |sel|
+
+    sel := fileListView selection.
+    sel notNil ifTrue:[
+        self withWaitCursorDo:[
+            sel do:[:aSelectionIndex |
+                aBlock value:(fileList at:aSelectionIndex )
+            ]
+        ]
+    ]
+
+!
+
+show:something
+    "show something in subview and undef acceptAction"
+
+    subView contents:something.
+    subView acceptAction:nil.
+    subView modified:false.
+    currentFileName := nil
+!
+
+showAlert:aString with:anErrorString
+    "show an alertbox, displaying the last Unix-error"
+
+    |msg|
+
+    anErrorString isNil ifTrue:[
+        msg := aString
+    ] ifFalse:[
+        msg := aString , '\\(' , anErrorString , ')'
+    ].
+    self warn:msg withCRs
+!
+
+withoutHiddenFiles:aCollection
+    "remove hidden files (i.e. those that start with '.') from
+     the list in aCollection"
+
+    |newCollection|
+
+    newCollection := aCollection species new.
+    aCollection do:[:fname |
+        |ignore|
+
+        ignore := false.
+
+        ((fname startsWith:'.') and:[fname ~= '..']) ifTrue:[
+            showDotFiles ifFalse:[
+                ignore := true
+            ]
+        ].
+        ignore ifFalse:[
+            newCollection add:fname
+        ]
+    ].
+    ^ newCollection
+
+    "Modified: 21.2.1996 / 01:33:18 / cg"
+! !
+
+!FileBrowser methodsFor:'private - actions & command execution'!
+
+binaryFileAction:aFilename
+    "for some binary files, if double clicked, we can do some useful
+     action ..."
+
+    (currentDirectory pathName , '/' , aFilename) asFilename isExecutable ifTrue:[
+        (OperatingSystem executeCommand:'cd ',currentDirectory pathName, '; ',aFilename)
+        ifTrue:[^true].
+    ].
+    ^ self imageAction:aFilename
+
+    "Modified: 19.6.1996 / 09:44:07 / cg"
+!
+
+doExecuteCommand:command replace:replace
+    "execute a unix command inserting the output of the command.
+     If replace is true, all text is replaced by the commands output;
+     otherwise, its inserted as selected text at the cursor position."
+
+    |stream line lnr myProcess myPriority startLine startCol stopSignal
+     access stillReplacing|
+
+    access := Semaphore forMutualExclusion name:'accessLock'.
+    stopSignal := Signal new.
+
+    "
+     must take killButton out of my group
+    "
+    windowGroup removeView:killButton.
+    "
+     bring it to front, and turn hidden-mode off
+    "
+    killButton raise.
+    killButton beVisible.
+    "
+     it will make me raise stopSignal when pressed
+    "
+    killButton 
+        action:[
+            stream notNil ifTrue:[
+                access critical:[
+                    myProcess interruptWith:[stopSignal raise].
+                ]
+            ]
+        ].
+    "
+     start it up under its own windowgroup
+    "
+    killButton openAutonomous.
+
+    "
+     go fork a pipe and read it
+    "
+    self label:(myName , ': executing ' , (command copyTo:(20 min:command size)) , ' ...').
+    [
+      self withWaitCursorDo:[
+        stopSignal catch:[
+            startLine := subView cursorLine.
+            startCol := subView cursorCol.
+
+            "
+             this can be a time consuming operation; therefore lower my priority
+            "
+            myProcess := Processor activeProcess.
+            myPriority := myProcess priority.
+            myProcess priority:(Processor userBackgroundPriority).
+
+            stream := PipeStream readingFrom:('cd '
+                                              , currentDirectory pathName
+                                              , '; '
+                                              , command
+                                              , ' 2>&1' ).
+            stream notNil ifTrue:[
+                [
+                    |codeView lines|
+
+                    stream buffered:true.
+                    codeView := subView.
+
+                    replace ifTrue:[
+                        codeView list:nil.
+                        lnr := 1.
+                    ].
+
+                   stillReplacing := replace.
+
+                   [stream atEnd] whileFalse:[
+                        (stream readWaitWithTimeoutMs:50) ifFalse:[
+                            "
+                             data available; read up to 100 lines
+                             and insert as a single junk. This speeds up
+                             display of long output (less line-scrolling).
+                            "
+                            lines := OrderedCollection new:100.
+                            line := stream nextLine.
+                            line notNil ifTrue:[lines add:line].
+
+                            [stream atEnd not
+                            and:[stream canReadWithoutBlocking
+                            and:[lines size < 100]]] whileTrue:[
+                                line := stream nextLine.
+                                line notNil ifTrue:[lines add:line].
+                            ].
+
+                            "
+                             need this critical section; otherwise,
+                             we could get the signal while waiting for
+                             an expose event ...
+                            "
+                            access critical:[                        
+                                lines size > 0 ifTrue:[
+                                    stillReplacing ifTrue:[
+                                        lines do:[:line |
+                                            codeView at:lnr put:line withTabsExpanded.
+                                            codeView cursorToBottom; cursorDown:1.
+                                            lnr := lnr + 1.
+                                            lnr > codeView list size ifTrue:[
+                                                stillReplacing := false
+                                            ]
+                                        ].
+                                    ] ifFalse:[
+                                        codeView insertLines:lines before:codeView cursorLine.
+                                        codeView cursorDown:lines size.
+                                    ]
+                                ].
+                            ].
+                        ].
+
+                        shown ifTrue:[windowGroup processExposeEvents].
+                        "
+                         give others running at same prio a chance too
+                         (especially other FileBrowsers doing the same)
+                        "
+                        Processor yield
+                    ].
+                ] valueNowOrOnUnwindDo:[
+                    stream shutDown "close". stream := nil.
+                ].
+
+                self updateCurrentDirectoryIfChanged
+
+            ].
+            replace ifTrue:[
+                subView modified:false.
+            ].
+        ]
+      ]
+    ] valueNowOrOnUnwindDo:[
+        |wg|
+
+        self label:myName; iconLabel:myName.
+        myProcess notNil ifTrue:[myProcess priority:myPriority].
+
+        "
+         remove the killButton from its group
+         (otherwise, it will be destroyed when we shut down the group)
+        "
+        wg := killButton windowGroup.
+        killButton windowGroup:nil.
+        "
+         shut down the windowgroup
+        "
+        wg notNil ifTrue:[
+            wg process terminate.
+        ].
+        "
+         hide the button, and make sure it will stay
+         hidden when we are realized again
+        "
+        killButton beInvisible.
+        "
+         clear its action (actually not needed, but
+         releases reference to thisContext earlier)
+        "
+        killButton action:nil.
+    ].
+
+    currentFileName isNil ifTrue:[
+        subView modified:false.
+    ].
+
+    subView size > 10000 ifTrue:[
+        self warn:'text quite large now - please cut off some lines'
+    ]
+
+    "Modified: 21.9.1995 / 11:18:46 / claus"
+    "Modified: 19.4.1997 / 15:29:54 / cg"
+!
+
+imageAction:aFilename
+    "for some image files, if double clicked, we can do some useful
+     action ..."
+
+    |img|
+
+    (Image isImageFileSuffix:(aFilename asFilename suffix))
+    ifTrue:[
+        img := Image fromFile:(currentDirectory pathName , '/' , aFilename).
+        img notNil ifTrue:[
+            img inspect.
+            ^ true
+        ]
+    ].
+    ^ false
+
+    "Created: 19.6.1996 / 09:43:50 / cg"
+    "Modified: 18.4.1997 / 14:56:04 / cg"
+!
+
+initialCommandFor:fileName into:aBox
+    "set a useful initial command for execute box."
+
+    |lcFilename cmd select|
+
+    "/ XXX should be changed to take stuff from a config file
+    "/ XXX or from resources.
+
+    ((currentDirectory typeOf:fileName) == #regular) ifTrue:[
+
+        (currentDirectory isExecutable:fileName) ifTrue:[
+            aBox initialText:(fileName , ' <arguments>').
+            ^ self
+        ].
+
+        lcFilename := fileName asLowercase.
+
+        select := true.
+
+        "some heuristics - my personal preferences ...
+         (actually this should come from a configfile)"
+
+        (fileName endsWith:'akefile') ifTrue:[
+            aBox initialText:'make target' selectFrom:6 to:11.
+            ^ self
+        ].
+        (lcFilename endsWith:'tar.z') ifTrue:[
+            cmd := 'zcat %1 | tar tvf -'.
+            select := false.
+        ].
+        (fileName endsWith:'.taz') ifTrue:[
+            aBox initialText:'zcat %1 | tar tvf -'.
+            select := false.
+        ].
+        (fileName endsWith:'.tar') ifTrue:[
+            cmd := 'tar tvf %1'.
+            select := 7.
+        ].
+        (fileName endsWith:'.zoo') ifTrue:[
+            cmd := 'zoo -list %1'.
+            select := 9.
+        ].
+        (lcFilename endsWith:'.zip') ifTrue:[
+            cmd := 'unzip -l %1'.
+            select := 8.
+        ].
+        (lcFilename endsWith:'.z') ifTrue:[
+            cmd := 'uncompress %1'
+        ].
+        (fileName endsWith:'tar.gz') ifTrue:[
+            cmd := ('gunzip < %1 | tar tvf -' ).
+            select := false.
+        ].
+        (fileName endsWith:'.tgz') ifTrue:[
+            cmd := ('gunzip < %1 | tar tvf -' ).
+            select := false.
+        ].
+        (fileName endsWith:'.gz') ifTrue:[
+            cmd := 'gunzip %1'.
+        ].
+        (lcFilename endsWith:'.html') ifTrue:[
+            cmd := 'netscape %1'
+        ].
+        (lcFilename endsWith:'.htm') ifTrue:[
+            cmd := 'netscape %1'
+        ].
+        (fileName endsWith:'.uue') ifTrue:[
+            cmd := 'uudecode %1'
+        ].
+        (fileName endsWith:'.c') ifTrue:[
+            cmd := 'cc -c %1'.
+            select := 5.
+        ].
+        (fileName endsWith:'.cc') ifTrue:[
+            cmd := 'g++ -c %1'.
+            select := 6.
+        ].
+        (fileName endsWith:'.C') ifTrue:[
+            cmd := 'g++ -c %1'.
+            select := 6.
+        ].
+        (fileName endsWith:'.xbm') ifTrue:[
+            cmd := 'bitmap %1'
+        ].
+        (lcFilename endsWith:'.ps') ifTrue:[
+            cmd := 'ghostview %1'
+        ].
+        ((fileName endsWith:'.1') 
+        or:[fileName endsWith:'.man']) ifTrue:[
+            cmd := 'nroff -man %1'.
+            select := 10.
+        ].
+
+        cmd isNil ifTrue:[
+            DefaultCommandPerSuffix isNil ifTrue:[
+                cmd := '<cmd>'
+            ] ifFalse:[
+                cmd := DefaultCommandPerSuffix 
+                        at:(lcFilename asFilename suffix)
+                        ifAbsent:'<cmd>'.
+            ].
+            cmd := cmd , ' %1'.
+        ].
+
+        cmd := cmd bindWith:fileName.
+        select == false ifTrue:[
+            aBox initialText:cmd
+        ] ifFalse:[
+            select isInteger ifFalse:[
+                select := (cmd indexOf:Character space ifAbsent:[cmd size + 1]) - 1.
+            ].
+            aBox initialText:cmd selectFrom:1 to:select
+        ]
+    ]
+
+    "Modified: 4.4.1997 / 12:26:40 / cg"
+!
+
+nonBinaryFileAction:aFilename
+    "for some nonBinary files, if double clicked, we can do some useful
+     action ..."
+
+    |fullPath lcName|
+
+    fullPath := currentDirectory pathName , '/' , aFilename.
+    lcName := aFilename asLowercase.
+    ((lcName endsWith:'.htm') or:[lcName endsWith:'.html']) ifTrue:[
+        HTMLDocumentView openOn:fullPath.
+        ^ true
+    ].
+
+    OperatingSystem isUNIXlike ifTrue:[
+        (#('.man' '.1' '.2' '.3') findFirst:[:suff | aFilename endsWith:suff]) ~~ 0 
+        ifTrue:[
+             HTMLDocumentView openFullOnText:(HTMLDocGenerator manPageForFile:fullPath).
+            ^ true
+        ]
+    ].
+    ^ self imageAction:aFilename
+
+    "Created: 19.6.1996 / 09:36:38 / cg"
+    "Modified: 4.4.1997 / 10:49:00 / cg"
+! !
+
+!FileBrowser methodsFor:'private - directory stuff'!
+
 changeToPreviousDirectory
     "if text was modified show a queryBox, 
      otherwise change immediately to previous directory."
@@ -1757,523 +2207,41 @@
     "Modified: 19.4.1997 / 15:30:32 / cg"
 !
 
-doCreateFile:newName
-    |aStream|
-
-    (currentDirectory includes:newName) ifTrue:[
-        (self
-            ask:(resources string:'%1 already exists\\truncate ?' with:newName)
-            yesButton:'truncate'
-        ) ifFalse:[^ self].
-    ].
-
-    aStream := FileStream newFileNamed:newName in:currentDirectory.
-    aStream notNil ifTrue:[
-        aStream close.
-        self updateCurrentDirectoryIfChanged
-    ] ifFalse:[
-        self showAlert:(resources string:'cannot create file ''%1'' !!' with:newName)
-                  with:(FileStream lastErrorString)
-    ]
-
-    "Modified: 19.4.1997 / 15:30:35 / cg"
-!
-
-doExecuteCommand:command replace:replace
-    "execute a unix command inserting the output of the command.
-     If replace is true, all text is replaced by the commands output;
-     otherwise, its inserted as selected text at the cursor position."
-
-    |stream line lnr myProcess myPriority startLine startCol stopSignal
-     access stillReplacing|
-
-    access := Semaphore forMutualExclusion name:'accessLock'.
-    stopSignal := Signal new.
-
-    "
-     must take killButton out of my group
-    "
-    windowGroup removeView:killButton.
-    "
-     bring it to front, and turn hidden-mode off
-    "
-    killButton raise.
-    killButton beVisible.
-    "
-     it will make me raise stopSignal when pressed
-    "
-    killButton 
-        action:[
-            stream notNil ifTrue:[
-                access critical:[
-                    myProcess interruptWith:[stopSignal raise].
-                ]
-            ]
-        ].
-    "
-     start it up under its own windowgroup
-    "
-    killButton openAutonomous.
-
-    "
-     go fork a pipe and read it
-    "
-    self label:(myName , ': executing ' , (command copyTo:(20 min:command size)) , ' ...').
-    [
-      self withWaitCursorDo:[
-        stopSignal catch:[
-            startLine := subView cursorLine.
-            startCol := subView cursorCol.
-
-            "
-             this can be a time consuming operation; therefore lower my priority
-            "
-            myProcess := Processor activeProcess.
-            myPriority := myProcess priority.
-            myProcess priority:(Processor userBackgroundPriority).
-
-            stream := PipeStream readingFrom:('cd '
-                                              , currentDirectory pathName
-                                              , '; '
-                                              , command
-                                              , ' 2>&1' ).
-            stream notNil ifTrue:[
-                [
-                    |codeView lines|
-
-                    stream buffered:true.
-                    codeView := subView.
-
-                    replace ifTrue:[
-                        codeView list:nil.
-                        lnr := 1.
-                    ].
-
-                   stillReplacing := replace.
-
-                   [stream atEnd] whileFalse:[
-                        (stream readWaitWithTimeoutMs:50) ifFalse:[
-                            "
-                             data available; read up to 100 lines
-                             and insert as a single junk. This speeds up
-                             display of long output (less line-scrolling).
-                            "
-                            lines := OrderedCollection new:100.
-                            line := stream nextLine.
-                            line notNil ifTrue:[lines add:line].
-
-                            [stream atEnd not
-                            and:[stream canReadWithoutBlocking
-                            and:[lines size < 100]]] whileTrue:[
-                                line := stream nextLine.
-                                line notNil ifTrue:[lines add:line].
-                            ].
-
-                            "
-                             need this critical section; otherwise,
-                             we could get the signal while waiting for
-                             an expose event ...
-                            "
-                            access critical:[                        
-                                lines size > 0 ifTrue:[
-                                    stillReplacing ifTrue:[
-                                        lines do:[:line |
-                                            codeView at:lnr put:line withTabsExpanded.
-                                            codeView cursorToBottom; cursorDown:1.
-                                            lnr := lnr + 1.
-                                            lnr > codeView list size ifTrue:[
-                                                stillReplacing := false
-                                            ]
-                                        ].
-                                    ] ifFalse:[
-                                        codeView insertLines:lines before:codeView cursorLine.
-                                        codeView cursorDown:lines size.
-                                    ]
-                                ].
-                            ].
-                        ].
-
-                        shown ifTrue:[windowGroup processExposeEvents].
-                        "
-                         give others running at same prio a chance too
-                         (especially other FileBrowsers doing the same)
-                        "
-                        Processor yield
-                    ].
-                ] valueNowOrOnUnwindDo:[
-                    stream shutDown "close". stream := nil.
-                ].
-
-                self updateCurrentDirectoryIfChanged
-
+setCurrentDirectory:aPathName
+    "setup for another directory"
+
+    |newDirectory|
+
+    aPathName isEmpty ifTrue:[^ self].
+    (currentDirectory isDirectory:aPathName) ifTrue:[
+        newDirectory := FileDirectory directoryNamed:aPathName in:currentDirectory.
+        newDirectory notNil ifTrue:[
+            self currentDirectory:newDirectory pathName.
+            currentFileName notNil ifTrue:[
+                fileListView contents:nil.
+                currentFileName := nil.
+            ] ifFalse:[
+                fileListView setSelection:nil.
+                fileListView scrollToTop.
             ].
-            replace ifTrue:[
-                subView modified:false.
-            ].
-        ]
-      ]
-    ] valueNowOrOnUnwindDo:[
-        |wg|
-
-        self label:myName; iconLabel:myName.
-        myProcess notNil ifTrue:[myProcess priority:myPriority].
-
-        "
-         remove the killButton from its group
-         (otherwise, it will be destroyed when we shut down the group)
-        "
-        wg := killButton windowGroup.
-        killButton windowGroup:nil.
-        "
-         shut down the windowgroup
-        "
-        wg notNil ifTrue:[
-            wg process terminate.
-        ].
-        "
-         hide the button, and make sure it will stay
-         hidden when we are realized again
-        "
-        killButton beInvisible.
-        "
-         clear its action (actually not needed, but
-         releases reference to thisContext earlier)
-        "
-        killButton action:nil.
-    ].
-
-    currentFileName isNil ifTrue:[
-        subView modified:false.
-    ].
-
-    subView size > 10000 ifTrue:[
-        self warn:'text quite large now - please cut off some lines'
-    ]
-
-    "Modified: 21.9.1995 / 11:18:46 / claus"
-    "Modified: 19.4.1997 / 15:29:54 / cg"
-!
-
-doFileGet:viaDoubleClick
-    "get selected file - show contents in subView"
-
-    |fileName iconLbl winLbl|
-
-    self withReadCursorDo:[
-        fileName := self getSelectedFileName.
-        fileName notNil ifTrue:[
-            (currentDirectory isDirectory:fileName) ifTrue:[
-                self doChangeCurrentDirectoryTo:fileName updateHistory:true.
-                winLbl := myName.
-                iconLbl := myName
-            ] ifFalse:[
-                (currentDirectory exists:fileName) ifFalse:[
-                    self warn:(resources string:'oops, ''%1'' is gone' with:fileName).
-                    ^ self
-                ].
-                timeOfFileRead := currentDirectory timeOfLastChange:fileName.
-                self showFile:fileName insert:false encoding:fileEncoding doubleClick:viaDoubleClick.
-                currentFileName := fileName.
-
-                self fileTypeSpecificActions.
-
-                subView acceptAction:[:theCode |
-                    self withCursor:(Cursor write) do:[
-                        self writeFile:fileName text:theCode encoding:fileEncoding.
-                        timeOfFileRead := currentDirectory timeOfLastChange:fileName.
-                        self label:myName , ': ' , currentFileName
-                    ]
-                ].
-
-                winLbl := myName , ': ' , fileName.
-                (currentDirectory isWritable:fileName) ifFalse:[
-                    winLbl := winLbl , ' (readonly)'
-                ].
-                iconLbl := fileName
-            ].
-            self label:winLbl.
-            self iconLabel:iconLbl.
+            self updateCurrentDirectory.
+            self showInfo.
         ]
     ]
 
-    "Created: 19.6.1996 / 09:39:07 / cg"
-    "Modified: 7.1.1997 / 20:21:44 / cg"
-!
-
-doRemove
-    "remove the selected file(s) - no questions asked"
-
-    |ok msg dir idx needUpdate toRemove updateRunning|
-
-    updateRunning := listUpdateProcess notNil.
-    self stopUpdateProcess.
-    toRemove := OrderedCollection new.
-
-    "/
-    "/ did the directory change in the meanwhile ?
-    "/
-    needUpdate := (currentDirectory timeOfLastChange > timeOfLastCheck).
-
-    lockUpdate := true.
-    [
-        self selectedFilesDo:[:fileName |
-            ok := false.
-            (currentDirectory isDirectory:fileName) ifTrue:[
-                dir := FileDirectory directoryNamed:fileName in:currentDirectory.
-                dir isEmpty ifTrue:[
-                    ok := currentDirectory removeDirectory:fileName
-                ] ifFalse:[
-                    (self 
-                        ask:(resources string:'directory ''%1'' is not empty\remove anyway ?' with:fileName)
-                        yesButton:'remove')
-                    ifFalse:[
-                        ^ self
-                    ].
-                    ok := currentDirectory removeDirectory:fileName
-                ].
-            ] ifFalse:[
-                ok := currentDirectory remove:fileName.
-            ].
-            ok ifFalse:[
-                "was not able to remove it"
-                msg := (resources string:'cannot remove ''%1'' !!' with:fileName).
-                self showAlert:msg with:(OperatingSystem lastErrorString)
-            ] ifTrue:[
-"
-                self show:nil
-"
-                idx := fileList indexOf:fileName.
-                idx ~~ 0 ifTrue:[
-                    toRemove add:idx.
-                ]
-            ]
-        ].
-    ] valueNowOrOnUnwindDo:[
-        lockUpdate := false.
-        fileListView setSelection:nil.
-
-        "/
-        "/ remove reverse - otherwise indices are wrong
-        "/
-        toRemove sort.
-        toRemove reverseDo:[:idx |
-            fileList removeIndex:idx.
-            fileListView removeIndex:idx.
-        ].
-
-        updateRunning ifTrue:[
-            self updateCurrentDirectory
-        ] ifFalse:[
-            "
-             install a new check after some time
-            "
-            needUpdate ifFalse:[timeOfLastCheck := AbsoluteTime now].
-            Processor addTimedBlock:checkBlock afterSeconds:checkDelta
-        ]
-    ]
-
-    "Modified: 19.4.1997 / 14:03:55 / cg"
-!
-
-doRename:oldName to:newName
-    (oldName notNil and:[newName notNil]) ifTrue:[
-        (oldName isBlank or:[newName isBlank]) ifFalse:[
-            currentDirectory renameFile:oldName newName:newName.
-            self updateCurrentDirectoryIfChanged.
-        ]
-    ]
-
-    "Modified: 19.4.1997 / 15:30:49 / cg"
-!
-
-fileCommentStrings
-    "return useful comment definition; based upon the fileName for now"
-
-    "/ for now,
-    "/ define comment strings, by heuristics;
-    "/ (should look for some mode= or similar string
-    "/  found in the file itself - like emacs does it)
-
-    (currentFileName = 'Make.proto'
-    or:[currentFileName = 'Makefile'
-    or:[currentFileName = 'makefile']]) ifTrue:[
-        ^ #('#' (nil nil)).
-    ].
-    ((currentFileName endsWith:'.c')
-    or:[(currentFileName endsWith:'.C')]) ifTrue:[
-        ^ #(nil ('/*' '*/')).
-    ].
-    ((currentFileName endsWith:'.cc')
-    or:[(currentFileName endsWith:'.CC')]) ifTrue:[
-        ^ #('//' ('/*' '*/')).
-    ].
-    (currentFileName endsWith:'.java') ifTrue:[
-        ^ #('//' (nil nil)).
-    ].
-
-    "/ smalltalk comments
-
-    ^ #('"/' ('"' '"')).
-
-    "Created: 7.1.1997 / 20:30:00 / cg"
-!
-
-fileTypeSpecificActions
-    "any special fileTypeSpecific actions are done here,
-     when a new file is selected"
-
-    |commentStrings|
-
-    commentStrings := self fileCommentStrings.
-    commentStrings notNil ifTrue:[
-        subView
-            commentStrings:#('#' (nil nil)).
-    ].
-
-    "Modified: 7.1.1997 / 20:30:54 / cg"
+    "Modified: 21.9.1995 / 11:22:45 / claus"
+    "Modified: 25.5.1996 / 12:27:01 / cg"
 !
 
-getFileInfoString:longInfo
-    "get stat info on selected file - return a string which can be
-     shown in a box"
-
-    |fileName f fullPath text info fileOutput type modeBits modeString s ts|
-
-    fileName := self getSelectedFileName.
-    fileName isNil ifTrue:[^ nil].
-
-    f := currentDirectory pathName asFilename construct:fileName.
-    info := f info.
-
-"/    info := currentDirectory infoOf:fileName.
-    info isNil ifTrue:[
-        self showAlert:(resources string:'cannot get info of ''%1'' !!' with:fileName)
-                  with:(OperatingSystem lastErrorString).
-        ^ nil
-    ].
-
-    text := StringCollection new.
-    f isSymbolicLink ifTrue:[
-        text add:(resources string:'symbolic link to: %1' with:(f linkInfo path))
-    ].
-
-    type := info type.
-    (longInfo and:[type == #regular]) ifTrue:[
-        fullPath := currentDirectory pathName , '/' , fileName.
-        fileOutput := fullPath asFilename fileType.
-    ].
-
-    s := (resources at:'type:   ').
-    fileOutput isNil ifTrue:[
-        s := s ,  type asString
-    ] ifFalse:[
-        s := s , 'regular (' , fileOutput , ')'
-    ].
-    text add:s.
-    text add:(resources string:'size:   %1' with:(info size) printString).
-
-    modeBits := info mode.
-    modeString := self getModeString:modeBits.
-    longInfo ifTrue:[
-        text add:(resources string:'access: %1 (%2)'
-                              with:modeString 
-                              with:(modeBits printStringRadix:8))
-    ] ifFalse:[
-        text add:(resources string:'access: %1' with:modeString)
-    ].
-    text add:(resources string:'owner:  %1'
-                          with:(OperatingSystem getUserNameFromID:(info uid))).
-    longInfo ifTrue:[
-        text add:(resources string:'group:  %1'
-                              with:(OperatingSystem getGroupNameFromID:(info gid))).
-
-        ts := info accessed.
-        text add:(resources string:'last access:       %1 %2' 
-                              with:(ts asTime printString)
-                              with:(ts asDate printString)).
-
-        ts := info modified.
-        text add:(resources string:'last modification: %1 %2'
-                              with:(ts asTime printString)
-                              with:(ts asDate printString)).
-    ].
-    ^ text asString
-
-    "Modified: 8.9.1995 / 11:59:28 / claus"
-    "Modified: 1.11.1996 / 20:47:52 / cg"
-!
-
-getInfoFile
-    "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."
-
-    #( '.dir.info'
-       'README'
-       'ReadMe'
-       'Readme'
-       'readme' 
-    ) do:[:f |
-        (currentDirectory isReadable:f) ifTrue:[
-            (currentDirectory isDirectory:f) ifFalse:[^ f].
-        ]
-    ].
-    ^ nil
-!
-
-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 , (resources string:access)
-        ] ifFalse:[
-            (bits bitAnd:bitMask) == 0 ifTrue:[
-                ch := $-
-            ] ifFalse:[
-                ch := access
-            ].
-            modeString := modeString copyWith:ch 
-        ]
-    ].
-    ^ modeString
-!
-
-getSelectedFileName
-    "returns the currently selected file; shows an error if
-     multiple files are selected"
-
-    |sel|
-
-    sel := fileListView selection.
-    (sel size > 1) ifTrue:[
-        self onlyOneSelection
-    ] ifFalse:[
-        sel notNil ifTrue:[
-            ^ fileList at:sel first
-        ]
-    ].
-    ^ nil
-!
+updateCurrentDirectoryIfChanged
+    (currentDirectory timeOfLastChange > timeOfLastCheck) ifTrue:[
+        self updateCurrentDirectory
+    ]
+
+    "Modified: 19.4.1997 / 15:30:03 / cg"
+! !
+
+!FileBrowser methodsFor:'private - encoding'!
 
 guessEncodingFrom:aBuffer
     "look for a string
@@ -2326,241 +2294,6 @@
     "Modified: 23.1.1997 / 20:39:25 / cg"
 !
 
-initialCommandFor:fileName into:aBox
-    "set a useful initial command for execute box."
-
-    |lcFilename cmd select|
-
-    "/ XXX should be changed to take stuff from a config file
-    "/ XXX or from resources.
-
-    ((currentDirectory typeOf:fileName) == #regular) ifTrue:[
-
-        (currentDirectory isExecutable:fileName) ifTrue:[
-            aBox initialText:(fileName , ' <arguments>').
-            ^ self
-        ].
-
-        lcFilename := fileName asLowercase.
-
-        select := true.
-
-        "some heuristics - my personal preferences ...
-         (actually this should come from a configfile)"
-
-        (fileName endsWith:'akefile') ifTrue:[
-            aBox initialText:'make target' selectFrom:6 to:11.
-            ^ self
-        ].
-        (lcFilename endsWith:'tar.z') ifTrue:[
-            cmd := 'zcat %1 | tar tvf -'.
-            select := false.
-        ].
-        (fileName endsWith:'.taz') ifTrue:[
-            aBox initialText:'zcat %1 | tar tvf -'.
-            select := false.
-        ].
-        (fileName endsWith:'.tar') ifTrue:[
-            cmd := 'tar tvf %1'.
-            select := 7.
-        ].
-        (fileName endsWith:'.zoo') ifTrue:[
-            cmd := 'zoo -list %1'.
-            select := 9.
-        ].
-        (lcFilename endsWith:'.zip') ifTrue:[
-            cmd := 'unzip -l %1'.
-            select := 8.
-        ].
-        (lcFilename endsWith:'.z') ifTrue:[
-            cmd := 'uncompress %1'
-        ].
-        (fileName endsWith:'tar.gz') ifTrue:[
-            cmd := ('gunzip < %1 | tar tvf -' ).
-            select := false.
-        ].
-        (fileName endsWith:'.tgz') ifTrue:[
-            cmd := ('gunzip < %1 | tar tvf -' ).
-            select := false.
-        ].
-        (fileName endsWith:'.gz') ifTrue:[
-            cmd := 'gunzip %1'.
-        ].
-        (lcFilename endsWith:'.html') ifTrue:[
-            cmd := 'netscape %1'
-        ].
-        (lcFilename endsWith:'.htm') ifTrue:[
-            cmd := 'netscape %1'
-        ].
-        (fileName endsWith:'.uue') ifTrue:[
-            cmd := 'uudecode %1'
-        ].
-        (fileName endsWith:'.c') ifTrue:[
-            cmd := 'cc -c %1'.
-            select := 5.
-        ].
-        (fileName endsWith:'.cc') ifTrue:[
-            cmd := 'g++ -c %1'.
-            select := 6.
-        ].
-        (fileName endsWith:'.C') ifTrue:[
-            cmd := 'g++ -c %1'.
-            select := 6.
-        ].
-        (fileName endsWith:'.xbm') ifTrue:[
-            cmd := 'bitmap %1'
-        ].
-        (lcFilename endsWith:'.ps') ifTrue:[
-            cmd := 'ghostview %1'
-        ].
-        ((fileName endsWith:'.1') 
-        or:[fileName endsWith:'.man']) ifTrue:[
-            cmd := 'nroff -man %1'.
-            select := 10.
-        ].
-
-        cmd isNil ifTrue:[
-            DefaultCommandPerSuffix isNil ifTrue:[
-                cmd := '<cmd>'
-            ] ifFalse:[
-                cmd := DefaultCommandPerSuffix 
-                        at:(lcFilename asFilename suffix)
-                        ifAbsent:'<cmd>'.
-            ].
-            cmd := cmd , ' %1'.
-        ].
-
-        cmd := cmd bindWith:fileName.
-        select == false ifTrue:[
-            aBox initialText:cmd
-        ] ifFalse:[
-            select isInteger ifFalse:[
-                select := (cmd indexOf:Character space ifAbsent:[cmd size + 1]) - 1.
-            ].
-            aBox initialText:cmd selectFrom:1 to:select
-        ]
-    ]
-
-    "Modified: 4.4.1997 / 12:26:40 / cg"
-!
-
-onlyOneSelection
-    "show a warning, that only one file must be selected for
-     this operation"
-
-    self warn:'exactly one file must be selected !!'
-!
-
-selectedFilesDo:aBlock
-    "evaluate aBlock on all selected files;
-     show a wait cursor while doing this"
-
-    |sel|
-
-    sel := fileListView selection.
-    sel notNil ifTrue:[
-        self withWaitCursorDo:[
-            sel do:[:aSelectionIndex |
-                aBlock value:(fileList at:aSelectionIndex )
-            ]
-        ]
-    ]
-
-!
-
-setCurrentDirectory:aPathName
-    "setup for another directory"
-
-    |newDirectory|
-
-    aPathName isEmpty ifTrue:[^ self].
-    (currentDirectory isDirectory:aPathName) ifTrue:[
-        newDirectory := FileDirectory directoryNamed:aPathName in:currentDirectory.
-        newDirectory notNil ifTrue:[
-            self currentDirectory:newDirectory pathName.
-            currentFileName notNil ifTrue:[
-                fileListView contents:nil.
-                currentFileName := nil.
-            ] ifFalse:[
-                fileListView setSelection:nil.
-                fileListView scrollToTop.
-            ].
-            self updateCurrentDirectory.
-            self showInfo.
-        ]
-    ]
-
-    "Modified: 21.9.1995 / 11:22:45 / claus"
-    "Modified: 25.5.1996 / 12:27:01 / cg"
-!
-
-show:something
-    "show something in subview and undef acceptAction"
-
-    subView contents:something.
-    subView acceptAction:nil.
-    subView modified:false.
-    currentFileName := nil
-!
-
-showAlert:aString with:anErrorString
-    "show an alertbox, displaying the last Unix-error"
-
-    |msg|
-
-    anErrorString isNil ifTrue:[
-        msg := aString
-    ] ifFalse:[
-        msg := aString , '\\(' , anErrorString , ')'
-    ].
-    self warn:msg withCRs
-!
-
-showInfo
-    "show directory info when dir has changed"
-
-    |info txt|
-
-    info := self getInfoFile.
-    info notNil ifTrue:[
-        txt := self readFile:info
-    ].
-    self show:txt.
-!
-
-sizePrintString:size
-    "helper for update-directory to return a string with a files size.
-     This one gives the size in byte, Kb or Mb depending on size.
-     If you dont like this, just uncomment the first statement below."
-
-    |unitString n|
-
-"
-    ^ size printString.
-"
-    unitString := ''.
-    size < (500 * 1024) ifTrue:[
-        size < 1024 ifTrue:[
-            n := size
-        ] ifFalse:[
-            n := (size * 10 // 1024 / 10.0).
-            unitString := ' Kb'
-        ]
-    ] ifFalse:[
-        n := (size * 10 // 1024 // 1024 / 10.0).
-        unitString := ' Mb'
-    ].
-    ^ (n printStringLeftPaddedTo:5) , unitString.
-!
-
-updateCurrentDirectoryIfChanged
-    (currentDirectory timeOfLastChange > timeOfLastCheck) ifTrue:[
-        self updateCurrentDirectory
-    ]
-
-    "Modified: 19.4.1997 / 15:30:03 / cg"
-!
-
 validateFontEncodingFor:newEncoding ask:ask
     "if required, query user if he/she wants to change to another font,
      which is able to display text encoded as specified by newEncoding"
@@ -2653,93 +2386,645 @@
     ]
 
     "Created: 26.10.1996 / 12:06:54 / cg"
+! !
+
+!FileBrowser methodsFor:'private - file stuff'!
+
+doCreateFile:newName
+    "create an empty file"
+
+    |aStream|
+
+    (currentDirectory includes:newName) ifTrue:[
+        (self
+            ask:(resources string:'%1 already exists\\truncate ?' with:newName)
+            yesButton:'truncate'
+        ) ifFalse:[^ self].
+    ].
+
+    aStream := FileStream newFileNamed:newName in:currentDirectory.
+    aStream notNil ifTrue:[
+        aStream close.
+        self updateCurrentDirectoryIfChanged
+    ] ifFalse:[
+        self showAlert:(resources string:'cannot create file ''%1'' !!' with:newName)
+                  with:(FileStream lastErrorString)
+    ]
+
+    "Modified: 23.4.1997 / 13:19:12 / cg"
 !
 
-withoutHiddenFiles:aCollection
-    "remove hidden files (i.e. those that start with '.') from
-     the list in aCollection"
-
-    |newCollection|
-
-    newCollection := aCollection species new.
-    aCollection do:[:fname |
-        |ignore|
-
-        ignore := false.
-
-        ((fname startsWith:'.') and:[fname ~= '..']) ifTrue:[
-            showDotFiles ifFalse:[
-                ignore := true
+doFileGet:viaDoubleClick
+    "get selected file - show contents in subView.
+     This is invoked either by the 'get file' menu item, or via double click.
+     When invoked via the menu (viaDoubleClick argument is false),
+     the automatic file action is not performed - instead, the file is always
+     shown in the codeView (if possible).
+     This distinction was done to allow xpm or xbm files (which ahve an automatic
+     action) to be edited."
+
+    |fileName iconLbl winLbl|
+
+    self withReadCursorDo:[
+        fileName := self getSelectedFileName.
+        fileName notNil ifTrue:[
+            (currentDirectory isDirectory:fileName) ifTrue:[
+                self doChangeCurrentDirectoryTo:fileName updateHistory:true.
+                winLbl := myName.
+                iconLbl := myName
+            ] ifFalse:[
+                (currentDirectory exists:fileName) ifFalse:[
+                    self warn:(resources string:'oops, ''%1'' is gone' with:fileName).
+                    ^ self
+                ].
+                timeOfFileRead := currentDirectory timeOfLastChange:fileName.
+                self showFile:fileName insert:false encoding:fileEncoding doubleClick:viaDoubleClick.
+                currentFileName := fileName.
+
+                self fileTypeSpecificActions.
+
+                subView acceptAction:[:theCode |
+                    self withCursor:(Cursor write) do:[
+                        self writeFile:fileName text:theCode encoding:fileEncoding.
+                        timeOfFileRead := currentDirectory timeOfLastChange:fileName.
+                        self label:myName , ': ' , currentFileName
+                    ]
+                ].
+
+                winLbl := myName , ': ' , fileName.
+                (currentDirectory isWritable:fileName) ifFalse:[
+                    winLbl := winLbl , ' (readonly)'
+                ].
+                iconLbl := fileName
+            ].
+            self label:winLbl.
+            self iconLabel:iconLbl.
+        ]
+    ]
+
+    "Created: 19.6.1996 / 09:39:07 / cg"
+    "Modified: 23.4.1997 / 13:19:01 / cg"
+!
+
+doRemove
+    "remove the selected file(s) - no questions asked"
+
+    |ok msg dir idx needUpdate toRemove updateRunning|
+
+    updateRunning := listUpdateProcess notNil.
+    self stopUpdateProcess.
+    toRemove := OrderedCollection new.
+
+    "/
+    "/ did the directory change in the meanwhile ?
+    "/
+    needUpdate := (currentDirectory timeOfLastChange > timeOfLastCheck).
+
+    lockUpdate := true.
+    [
+        self selectedFilesDo:[:fileName |
+            ok := false.
+            (currentDirectory isDirectory:fileName) ifTrue:[
+                dir := FileDirectory directoryNamed:fileName in:currentDirectory.
+                dir isEmpty ifTrue:[
+                    ok := currentDirectory removeDirectory:fileName
+                ] ifFalse:[
+                    (self 
+                        ask:(resources string:'directory ''%1'' is not empty\remove anyway ?' with:fileName)
+                        yesButton:'remove')
+                    ifFalse:[
+                        ^ self
+                    ].
+                    ok := currentDirectory removeDirectory:fileName
+                ].
+            ] ifFalse:[
+                ok := currentDirectory remove:fileName.
+            ].
+            ok ifFalse:[
+                "was not able to remove it"
+                msg := (resources string:'cannot remove ''%1'' !!' with:fileName).
+                self showAlert:msg with:(OperatingSystem lastErrorString)
+            ] ifTrue:[
+"
+                self show:nil
+"
+                idx := fileList indexOf:fileName.
+                idx ~~ 0 ifTrue:[
+                    toRemove add:idx.
+                ]
             ]
         ].
-        ignore ifFalse:[
-            newCollection add:fname
+    ] valueNowOrOnUnwindDo:[
+        lockUpdate := false.
+        fileListView setSelection:nil.
+
+        "/
+        "/ remove reverse - otherwise indices are wrong
+        "/
+        toRemove sort.
+        toRemove reverseDo:[:idx |
+            fileList removeIndex:idx.
+            fileListView removeIndex:idx.
+        ].
+
+        updateRunning ifTrue:[
+            self updateCurrentDirectory
+        ] ifFalse:[
+            "
+             install a new check after some time
+            "
+            needUpdate ifFalse:[timeOfLastCheck := AbsoluteTime now].
+            Processor addTimedBlock:checkBlock afterSeconds:checkDelta
+        ]
+    ]
+
+    "Modified: 19.4.1997 / 14:03:55 / cg"
+!
+
+doRename:oldName to:newName
+    "rename file(s) (or directories)"
+
+    (oldName notNil and:[newName notNil]) ifTrue:[
+        (oldName isBlank or:[newName isBlank]) ifFalse:[
+            currentDirectory renameFile:oldName newName:newName.
+            self updateCurrentDirectoryIfChanged.
+        ]
+    ]
+
+    "Modified: 23.4.1997 / 13:19:37 / cg"
+! !
+
+!FileBrowser methodsFor:'private - file type & info'!
+
+fileCommentStrings
+    "return a useful comment definition; based upon the fileName for now"
+
+    "/ for now,
+    "/ define comment strings, by heuristics;
+    "/ (should look for some mode= or similar string
+    "/  found in the file itself - like emacs does it)
+
+    (currentFileName = 'Make.proto'
+    or:[currentFileName = 'Makefile'
+    or:[currentFileName = 'makefile']]) ifTrue:[
+        ^ #('#' (nil nil)).
+    ].
+    ((currentFileName endsWith:'.c')
+    or:[(currentFileName endsWith:'.C')]) ifTrue:[
+        ^ #(nil ('/*' '*/')).
+    ].
+    ((currentFileName endsWith:'.cc')
+    or:[(currentFileName endsWith:'.CC')]) ifTrue:[
+        ^ #('//' ('/*' '*/')).
+    ].
+    (currentFileName endsWith:'.java') ifTrue:[
+        ^ #('//' (nil nil)).
+    ].
+
+    "/ smalltalk comments
+
+    ^ #('"/' ('"' '"')).
+
+    "Created: 7.1.1997 / 20:30:00 / cg"
+    "Modified: 23.4.1997 / 13:11:49 / cg"
+!
+
+fileTypeSpecificActions
+    "any special fileTypeSpecific actions are done here,
+     when a new file is selected"
+
+    |commentStrings|
+
+    commentStrings := self fileCommentStrings.
+    commentStrings notNil ifTrue:[
+        subView
+            commentStrings:#('#' (nil nil)).
+    ].
+
+    "Modified: 7.1.1997 / 20:30:54 / cg"
+!
+
+getFileInfoString:longInfo
+    "get stat info on selected file - return a string which can be
+     shown in a box"
+
+    |fileName f fullPath text info fileOutput type modeBits modeString s ts|
+
+    fileName := self getSelectedFileName.
+    fileName isNil ifTrue:[^ nil].
+
+    f := currentDirectory pathName asFilename construct:fileName.
+    info := f info.
+
+"/    info := currentDirectory infoOf:fileName.
+    info isNil ifTrue:[
+        self showAlert:(resources string:'cannot get info of ''%1'' !!' with:fileName)
+                  with:(OperatingSystem lastErrorString).
+        ^ nil
+    ].
+
+    text := StringCollection new.
+    f isSymbolicLink ifTrue:[
+        text add:(resources string:'symbolic link to: %1' with:(f linkInfo path))
+    ].
+
+    type := info type.
+    (longInfo and:[type == #regular]) ifTrue:[
+        fullPath := currentDirectory pathName , '/' , fileName.
+        fileOutput := fullPath asFilename fileType.
+    ].
+
+    s := (resources at:'type:   ').
+    fileOutput isNil ifTrue:[
+        s := s ,  type asString
+    ] ifFalse:[
+        s := s , 'regular (' , fileOutput , ')'
+    ].
+    text add:s.
+    text add:(resources string:'size:   %1' with:(info size) printString).
+
+    modeBits := info mode.
+    modeString := self getModeString:modeBits.
+    longInfo ifTrue:[
+        text add:(resources string:'access: %1 (%2)'
+                              with:modeString 
+                              with:(modeBits printStringRadix:8))
+    ] ifFalse:[
+        text add:(resources string:'access: %1' with:modeString)
+    ].
+    text add:(resources string:'owner:  %1'
+                          with:(OperatingSystem getUserNameFromID:(info uid))).
+    longInfo ifTrue:[
+        text add:(resources string:'group:  %1'
+                              with:(OperatingSystem getGroupNameFromID:(info gid))).
+
+        ts := info accessed.
+        text add:(resources string:'last access:       %1 %2' 
+                              with:(ts asTime printString)
+                              with:(ts asDate printString)).
+
+        ts := info modified.
+        text add:(resources string:'last modification: %1 %2'
+                              with:(ts asTime printString)
+                              with:(ts asDate printString)).
+    ].
+    ^ text asString
+
+    "Modified: 8.9.1995 / 11:59:28 / claus"
+    "Modified: 1.11.1996 / 20:47:52 / cg"
+!
+
+getInfoFile
+    "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."
+
+    #( 
+       '.dir.info'
+       'README'
+       'ReadMe'
+       'Readme'
+       'readme'
+       'read.me'
+       'Read.me'
+       'READ.ME'
+    ) do:[:f |
+        (currentDirectory isReadable:f) ifTrue:[
+            (currentDirectory isDirectory:f) ifFalse:[^ f].
         ]
     ].
-    ^ newCollection
-
-    "Modified: 21.2.1996 / 01:33:18 / cg"
-! !
-
-!FileBrowser methodsFor:'private - actions'!
-
-binaryFileAction:aFilename
-    "for some binary files, if double clicked, we can do some useful
-     action ..."
-
-    (currentDirectory pathName , '/' , aFilename) asFilename isExecutable ifTrue:[
-        (OperatingSystem executeCommand:'cd ',currentDirectory pathName, '; ',aFilename)
-        ifTrue:[^true].
-    ].
-    ^ self imageAction:aFilename
-
-    "Modified: 19.6.1996 / 09:44:07 / cg"
+    ^ nil
+
+    "Modified: 23.4.1997 / 13:12:36 / cg"
+!
+
+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 )
 !
 
-imageAction:aFilename
-    "for some image files, if double clicked, we can do some useful
-     action ..."
-
-    |img|
-
-    (Image isImageFileSuffix:(aFilename asFilename suffix))
-    ifTrue:[
-        img := Image fromFile:(currentDirectory pathName , '/' , aFilename).
-        img notNil ifTrue:[
-            img inspect.
-            ^ true
+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 , (resources string:access)
+        ] ifFalse:[
+            (bits bitAnd:bitMask) == 0 ifTrue:[
+                ch := $-
+            ] ifFalse:[
+                ch := access
+            ].
+            modeString := modeString copyWith:ch 
         ]
     ].
-    ^ false
-
-    "Created: 19.6.1996 / 09:43:50 / cg"
-    "Modified: 18.4.1997 / 14:56:04 / cg"
+    ^ modeString
+!
+
+showInfo
+    "show directory info when dir has changed"
+
+    |info txt|
+
+    info := self getInfoFile.
+    info notNil ifTrue:[
+        txt := self readFile:info
+    ].
+    self show:txt.
+!
+
+sizePrintString:size
+    "helper for update-directory to return a string with a files size.
+     This one gives the size in byte, Kb or Mb depending on size.
+     If you dont like this, just uncomment the first statement below."
+
+    |unitString n|
+
+"
+    ^ size printString.
+"
+    unitString := ''.
+    size < (500 * 1024) ifTrue:[
+        size < 1024 ifTrue:[
+            n := size
+        ] ifFalse:[
+            n := (size * 10 // 1024 / 10.0).
+            unitString := ' Kb'
+        ]
+    ] ifFalse:[
+        n := (size * 10 // 1024 // 1024 / 10.0).
+        unitString := ' Mb'
+    ].
+    ^ (n printStringLeftPaddedTo:5) , unitString.
+! !
+
+!FileBrowser methodsFor:'private - file-I/O'!
+
+readFile:fileName
+    "read in the file, answer its contents as StringCollection"
+
+    ^ self readFile:fileName lineDelimiter:Character cr encoding:nil
+
+    "Modified: 22.2.1996 / 14:57:08 / cg"
+!
+
+readFile:fileName lineDelimiter:aCharacter encoding:encoding
+    "read in the file, return its contents as StringCollection. 
+     The files lines are delimited by aCharacter.
+     If encoding is nonNil, the file is assumed to be coded according to
+     that symbol, and #decodeString: should be able to convert it."
+
+    |stream text msg sz|
+
+    stream := FileStream readonlyFileNamed:fileName in:currentDirectory.
+    stream isNil ifTrue:[
+        msg := (resources string:'cannot read file ''%1'' !!' with:fileName).
+        self showAlert:msg with:(FileStream lastErrorString).
+        ^ nil
+    ].
+
+    "
+     for very big files, give ObjectMemory a hint, to preallocate more
+    "
+    (sz := stream size) > 1000000 ifTrue:[
+        Processor activeProcess withPriority:Processor userBackgroundPriority do:[
+            ObjectMemory announceSpaceNeed:(sz + (sz // 5)) "/ add 20% for tab expansion
+        ].
+    ].
+
+    text := self readStream:stream lineDelimiter:aCharacter encoding:encoding.
+    stream close.
+    ^ text
+
+    "Created: 22.2.1996 / 14:56:48 / cg"
+    "Modified: 8.10.1996 / 21:01:57 / cg"
+!
+
+readStream:aStream
+    "read in from aStream, answer its contents as StringCollection"
+
+    ^ self readStream:aStream lineDelimiter:Character cr encoding:nil
+
+    "Modified: 22.2.1996 / 14:58:40 / cg"
 !
 
-nonBinaryFileAction:aFilename
-    "for some nonBinary files, if double clicked, we can do some useful
-     action ..."
-
-    |fullPath lcName|
-
-    fullPath := currentDirectory pathName , '/' , aFilename.
-    lcName := aFilename asLowercase.
-    ((lcName endsWith:'.htm') or:[lcName endsWith:'.html']) ifTrue:[
-        HTMLDocumentView openOn:fullPath.
-        ^ true
+readStream:aStream lineDelimiter:aCharacter encoding:encoding 
+    "read from aStream, answer its contents as StringCollection. 
+     The files lines are delimited by aCharacter.
+     If encoding is nonNil, the file is assumed to be coded according to
+     that symbol, and #decodeString: should be able to convert it."
+
+    |text line enc|
+
+    text := StringCollection new.
+
+    enc := encoding.
+    enc == #iso8859 ifTrue:[
+        enc := nil
+    ].
+
+    aCharacter == Character cr ifTrue:[
+        [aStream atEnd] whileFalse:[
+            line := aStream nextLine withTabsExpanded.
+            enc notNil ifTrue:[
+                line := line decodeFrom:enc
+            ].
+            text add:line
+        ].
+    ] ifFalse:[
+        [aStream atEnd] whileFalse:[
+            line := (aStream upTo:aCharacter) withTabsExpanded.
+            enc notNil ifTrue:[
+                line := line decodeFrom:enc
+            ].
+            text add:line
+        ].
     ].
-
-    OperatingSystem isUNIXlike ifTrue:[
-        (#('.man' '.1' '.2' '.3') findFirst:[:suff | aFilename endsWith:suff]) ~~ 0 
-        ifTrue:[
-             HTMLDocumentView openFullOnText:(HTMLDocGenerator manPageForFile:fullPath).
-            ^ true
+    ^ text
+
+    "Created: 22.2.1996 / 14:58:25 / cg"
+    "Modified: 2.4.1997 / 21:31:36 / cg"
+!
+
+showFile:fileName
+    "show contents of fileName in subView"
+
+    self showFile:fileName insert:false encoding:fileEncoding
+
+    "Modified: 22.2.1996 / 14:47:10 / cg"
+!
+
+showFile:fileName insert:insert encoding:encoding
+    "show/insert contents of fileName in subView"
+
+    ^ self 
+        showFile:fileName insert:insert encoding:encoding doubleClick:false
+
+    "Modified: 19.6.1996 / 09:40:19 / cg"
+!
+
+showFile:fileName insert:insert encoding:encoding doubleClick:viaDoubleClick
+    "show/insert contents of fileName in subView"
+
+    |buffer s n i ok convert text msg eol guess action enc|
+
+    ((currentDirectory typeOf:fileName) == #regular) ifFalse:[
+        "asked for a non-file  - ignore it ..."
+        (currentDirectory exists:fileName) ifFalse:[
+            msg := '''%1'' does not exist !!'.
+        ] ifTrue:[
+            msg := '''%1'' is not a regular file !!'.
+        ].
+        self warn:(resources string:msg with:fileName).
+        ^ self
+    ].
+
+    "/
+    "/ check if file is a text file
+    "/
+    s := FileStream readonlyFileNamed:fileName in:currentDirectory.
+    s isNil ifTrue:[
+        self showAlert:(resources string:'cannot read file ''%1'' !!' with:fileName)
+                  with:(FileStream lastErrorString).
+        ^ nil
+    ].
+
+    buffer := String new:300.
+    n := s nextBytes:300 into:buffer.
+    s close.
+
+    enc := encoding.
+    ok := true.
+    guess := self guessEncodingFrom:buffer.
+
+    guess == #binary ifTrue:[
+        ok := false.
+        viaDoubleClick ifTrue:[
+            (self binaryFileAction:fileName) ifTrue:[^ self].
+        ].
+        (self confirm:(resources string:'''%1'' seems to be a binary file - show anyway ?' with:fileName))
+        ifFalse:[^ self]
+    ] ifFalse:[
+        viaDoubleClick ifTrue:[
+            (self nonBinaryFileAction:fileName) ifTrue:[^ self].
+        ].
+
+        "/ ascii should work in any font ...
+
+        guess ~~ #ascii ifTrue:[
+            fileEncoding ~~ guess ifTrue:[
+                action := Dialog choose:(resources string:'''%1'' seems to be ' , guess , ' encoded.' with:fileName)
+                               labels:(resources array:#('cancel' 'show' 'change font'))
+                               values:#(nil #show #encoding)
+                               default:#encoding.
+                action isNil ifTrue:[^ self].
+                action == #encoding ifTrue:[
+                    fileEncoding := guess asSymbol.
+                    self validateFontEncodingFor:fileEncoding ask:false.
+                    enc := fileEncoding.
+                ]
+            ]    
+        ].
+    ].
+
+    convert := false.
+    ok ifTrue:[
+        "/
+        "/ check if line delimiter is a cr
+        "/
+        i := buffer indexOf:Character cr.
+        i == 0 ifTrue:[
+            "/
+            "/ no newline found - try cr
+            "/
+            i := buffer indexOf:(Character value:13).
+            i ~~ 0 ifTrue:[
+                convert := self confirm:(resources string:'''%1'' seems to have CR as line delimiter - convert to NL ?' with:fileName).
+            ]
         ]
     ].
-    ^ self imageAction:aFilename
-
-    "Created: 19.6.1996 / 09:36:38 / cg"
-    "Modified: 4.4.1997 / 10:49:00 / cg"
+
+    insert ifFalse:[
+        "/ release old text first 
+        "/ - we might need the memory in case of huge files
+        "/  (helps if you have a 4Mb file in the view, 
+        "/   and click on another biggy)
+
+        subView contents:nil.
+    ].
+
+    convert ifTrue:[
+        eol := Character value:13
+    ] ifFalse:[
+        eol := Character cr
+    ].
+    text := self readFile:fileName lineDelimiter:eol encoding:enc.
+
+    insert ifFalse:[
+        self show:text
+    ] ifTrue:[
+        subView insertSelectedStringAtCursor:text asString
+    ].
+
+    "Created: 19.6.1996 / 09:39:52 / cg"
+    "Modified: 23.1.1997 / 20:31:43 / cg"
+!
+
+writeFile:fileName text:someText encoding:encoding
+    |stream msg startNr nLines string|
+
+    stream := FileStream newFileNamed:fileName in:currentDirectory.
+    stream isNil ifTrue:[
+        msg := (resources string:'cannot write file ''%1'' !!' with:fileName).
+        self showAlert:msg with:(FileStream lastErrorString)
+    ] ifFalse:[
+        someText isString ifTrue:[
+            stream nextPutAll:someText.
+        ] ifFalse:[
+            "
+             on some systems, writing linewise is very slow (via NFS)
+             therefore we convert to a string and write it in chunks
+             to avoid creating huge strings, we do it in blocks of 1000 lines
+            "
+            startNr := 1.
+            nLines := someText size.
+            [startNr <= nLines] whileTrue:[
+                string := someText asStringWithCRsFrom:startNr
+                                                    to:((startNr + 1000) min:nLines)
+                                          compressTabs:compressTabs.
+                encoding notNil ifTrue:[
+                    string := string encodeInto:encoding
+                ].
+                stream nextPutAll:string.
+                startNr := startNr + 1000 + 1.
+            ].
+"/                someText do:[:line |
+"/                  line notNil ifTrue:[
+"/                      stream nextPutAll:line.
+"/                  ].
+"/                  stream cr.
+"/              ]
+        ].
+        stream close.
+        subView modified:false
+    ]
+
+    "Created: 22.2.1996 / 15:03:10 / cg"
+    "Modified: 22.2.1996 / 15:08:31 / cg"
 ! !
 
 !FileBrowser methodsFor:'private - presentation'!
@@ -3190,261 +3475,6 @@
     "Modified: 21.4.1997 / 15:01:27 / cg"
 ! !
 
-!FileBrowser methodsFor:'private-file-I/O'!
-
-readFile:fileName
-    "read in the file, answer its contents as StringCollection"
-
-    ^ self readFile:fileName lineDelimiter:Character cr encoding:nil
-
-    "Modified: 22.2.1996 / 14:57:08 / cg"
-!
-
-readFile:fileName lineDelimiter:aCharacter encoding:encoding
-    "read in the file, return its contents as StringCollection. 
-     The files lines are delimited by aCharacter.
-     If encoding is nonNil, the file is assumed to be coded according to
-     that symbol, and #decodeString: should be able to convert it."
-
-    |stream text msg sz|
-
-    stream := FileStream readonlyFileNamed:fileName in:currentDirectory.
-    stream isNil ifTrue:[
-        msg := (resources string:'cannot read file ''%1'' !!' with:fileName).
-        self showAlert:msg with:(FileStream lastErrorString).
-        ^ nil
-    ].
-
-    "
-     for very big files, give ObjectMemory a hint, to preallocate more
-    "
-    (sz := stream size) > 1000000 ifTrue:[
-        Processor activeProcess withPriority:Processor userBackgroundPriority do:[
-            ObjectMemory announceSpaceNeed:(sz + (sz // 5)) "/ add 20% for tab expansion
-        ].
-    ].
-
-    text := self readStream:stream lineDelimiter:aCharacter encoding:encoding.
-    stream close.
-    ^ text
-
-    "Created: 22.2.1996 / 14:56:48 / cg"
-    "Modified: 8.10.1996 / 21:01:57 / cg"
-!
-
-readStream:aStream
-    "read in from aStream, answer its contents as StringCollection"
-
-    ^ self readStream:aStream lineDelimiter:Character cr encoding:nil
-
-    "Modified: 22.2.1996 / 14:58:40 / cg"
-!
-
-readStream:aStream lineDelimiter:aCharacter encoding:encoding 
-    "read from aStream, answer its contents as StringCollection. 
-     The files lines are delimited by aCharacter.
-     If encoding is nonNil, the file is assumed to be coded according to
-     that symbol, and #decodeString: should be able to convert it."
-
-    |text line enc|
-
-    text := StringCollection new.
-
-    enc := encoding.
-    enc == #iso8859 ifTrue:[
-        enc := nil
-    ].
-
-    aCharacter == Character cr ifTrue:[
-        [aStream atEnd] whileFalse:[
-            line := aStream nextLine withTabsExpanded.
-            enc notNil ifTrue:[
-                line := line decodeFrom:enc
-            ].
-            text add:line
-        ].
-    ] ifFalse:[
-        [aStream atEnd] whileFalse:[
-            line := (aStream upTo:aCharacter) withTabsExpanded.
-            enc notNil ifTrue:[
-                line := line decodeFrom:enc
-            ].
-            text add:line
-        ].
-    ].
-    ^ text
-
-    "Created: 22.2.1996 / 14:58:25 / cg"
-    "Modified: 2.4.1997 / 21:31:36 / cg"
-!
-
-showFile:fileName
-    "show contents of fileName in subView"
-
-    self showFile:fileName insert:false encoding:fileEncoding
-
-    "Modified: 22.2.1996 / 14:47:10 / cg"
-!
-
-showFile:fileName insert:insert encoding:encoding
-    "show/insert contents of fileName in subView"
-
-    ^ self 
-        showFile:fileName insert:insert encoding:encoding doubleClick:false
-
-    "Modified: 19.6.1996 / 09:40:19 / cg"
-!
-
-showFile:fileName insert:insert encoding:encoding doubleClick:viaDoubleClick
-    "show/insert contents of fileName in subView"
-
-    |buffer s n i ok convert text msg eol guess action enc|
-
-    ((currentDirectory typeOf:fileName) == #regular) ifFalse:[
-        "asked for a non-file  - ignore it ..."
-        (currentDirectory exists:fileName) ifFalse:[
-            msg := '''%1'' does not exist !!'.
-        ] ifTrue:[
-            msg := '''%1'' is not a regular file !!'.
-        ].
-        self warn:(resources string:msg with:fileName).
-        ^ self
-    ].
-
-    "/
-    "/ check if file is a text file
-    "/
-    s := FileStream readonlyFileNamed:fileName in:currentDirectory.
-    s isNil ifTrue:[
-        self showAlert:(resources string:'cannot read file ''%1'' !!' with:fileName)
-                  with:(FileStream lastErrorString).
-        ^ nil
-    ].
-
-    buffer := String new:300.
-    n := s nextBytes:300 into:buffer.
-    s close.
-
-    enc := encoding.
-    ok := true.
-    guess := self guessEncodingFrom:buffer.
-
-    guess == #binary ifTrue:[
-        ok := false.
-        viaDoubleClick ifTrue:[
-            (self binaryFileAction:fileName) ifTrue:[^ self].
-        ].
-        (self confirm:(resources string:'''%1'' seems to be a binary file - show anyway ?' with:fileName))
-        ifFalse:[^ self]
-    ] ifFalse:[
-        viaDoubleClick ifTrue:[
-            (self nonBinaryFileAction:fileName) ifTrue:[^ self].
-        ].
-
-        "/ ascii should work in any font ...
-
-        guess ~~ #ascii ifTrue:[
-            fileEncoding ~~ guess ifTrue:[
-                action := Dialog choose:(resources string:'''%1'' seems to be ' , guess , ' encoded.' with:fileName)
-                               labels:(resources array:#('cancel' 'show' 'change font'))
-                               values:#(nil #show #encoding)
-                               default:#encoding.
-                action isNil ifTrue:[^ self].
-                action == #encoding ifTrue:[
-                    fileEncoding := guess asSymbol.
-                    self validateFontEncodingFor:fileEncoding ask:false.
-                    enc := fileEncoding.
-                ]
-            ]    
-        ].
-    ].
-
-    convert := false.
-    ok ifTrue:[
-        "/
-        "/ check if line delimiter is a cr
-        "/
-        i := buffer indexOf:Character cr.
-        i == 0 ifTrue:[
-            "/
-            "/ no newline found - try cr
-            "/
-            i := buffer indexOf:(Character value:13).
-            i ~~ 0 ifTrue:[
-                convert := self confirm:(resources string:'''%1'' seems to have CR as line delimiter - convert to NL ?' with:fileName).
-            ]
-        ]
-    ].
-
-    insert ifFalse:[
-        "/ release old text first 
-        "/ - we might need the memory in case of huge files
-        "/  (helps if you have a 4Mb file in the view, 
-        "/   and click on another biggy)
-
-        subView contents:nil.
-    ].
-
-    convert ifTrue:[
-        eol := Character value:13
-    ] ifFalse:[
-        eol := Character cr
-    ].
-    text := self readFile:fileName lineDelimiter:eol encoding:enc.
-
-    insert ifFalse:[
-        self show:text
-    ] ifTrue:[
-        subView insertSelectedStringAtCursor:text asString
-    ].
-
-    "Created: 19.6.1996 / 09:39:52 / cg"
-    "Modified: 23.1.1997 / 20:31:43 / cg"
-!
-
-writeFile:fileName text:someText encoding:encoding
-    |stream msg startNr nLines string|
-
-    stream := FileStream newFileNamed:fileName in:currentDirectory.
-    stream isNil ifTrue:[
-        msg := (resources string:'cannot write file ''%1'' !!' with:fileName).
-        self showAlert:msg with:(FileStream lastErrorString)
-    ] ifFalse:[
-        someText isString ifTrue:[
-            stream nextPutAll:someText.
-        ] ifFalse:[
-            "
-             on some systems, writing linewise is very slow (via NFS)
-             therefore we convert to a string and write it in chunks
-             to avoid creating huge strings, we do it in blocks of 1000 lines
-            "
-            startNr := 1.
-            nLines := someText size.
-            [startNr <= nLines] whileTrue:[
-                string := someText asStringWithCRsFrom:startNr
-                                                    to:((startNr + 1000) min:nLines)
-                                          compressTabs:compressTabs.
-                encoding notNil ifTrue:[
-                    string := string encodeInto:encoding
-                ].
-                stream nextPutAll:string.
-                startNr := startNr + 1000 + 1.
-            ].
-"/                someText do:[:line |
-"/                  line notNil ifTrue:[
-"/                      stream nextPutAll:line.
-"/                  ].
-"/                  stream cr.
-"/              ]
-        ].
-        stream close.
-        subView modified:false
-    ]
-
-    "Created: 22.2.1996 / 15:03:10 / cg"
-    "Modified: 22.2.1996 / 15:08:31 / cg"
-! !
-
 !FileBrowser methodsFor:'queries'!
 
 path
@@ -3457,6 +3487,6 @@
 !FileBrowser class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libtool/Attic/FBrowser.st,v 1.151 1997-04-21 13:03:56 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libtool/Attic/FBrowser.st,v 1.152 1997-04-23 11:30:25 cg Exp $'
 ! !
 FileBrowser initialize!
--- a/FileBrowser.st	Tue Apr 22 19:33:37 1997 +0200
+++ b/FileBrowser.st	Wed Apr 23 13:30:25 1997 +0200
@@ -555,12 +555,13 @@
             label := 'get'.
         ].
         (self ask:(resources at:msg) yesButton:label) ifTrue:[
+            subView modified:false.
             self doFileGet:viaDoubleClick
         ]
     ]
 
     "Created: 19.6.1996 / 09:38:35 / cg"
-    "Modified: 2.4.1997 / 23:24:40 / cg"
+    "Modified: 23.4.1997 / 13:04:11 / cg"
 !
 
 fileGetInfo
@@ -587,7 +588,7 @@
 !
 
 fileInsert
-    "insert contents of file at cursor"
+    "insert contents of file at the cursor position"
 
     |fileName|
 
@@ -596,7 +597,7 @@
         self showFile:fileName insert:true encoding:fileEncoding
     ]
 
-    "Modified: 22.2.1996 / 14:47:16 / cg"
+    "Modified: 23.4.1997 / 13:06:06 / cg"
 !
 
 fileListMenu
@@ -736,6 +737,8 @@
 !
 
 filePrint
+    "send a files contents to the printer (not in the menu)"
+
     |fileName inStream printStream line|
 
     self withWaitCursorDo:[
@@ -760,7 +763,7 @@
         0 "compiler hint"
     ]
 
-    "Modified: 9.11.1996 / 00:15:07 / cg"
+    "Modified: 23.4.1997 / 13:05:40 / cg"
 !
 
 fileRemove
@@ -799,7 +802,10 @@
 
 fileSelect:lineNr
     "selected a file - do nothing here"
+
     ^ self
+
+    "Modified: 23.4.1997 / 13:04:55 / cg"
 !
 
 fileSpawn
@@ -829,8 +835,9 @@
                     title:(resources at:'create new directory:') withCRs
                     okText:(resources at:'create')
                     action:[:newName | self doCreateDirectory:newName].
-"/    queryBox initialText:''.
     queryBox showAtPointer
+
+    "Modified: 23.4.1997 / 13:04:27 / cg"
 !
 
 newFile
@@ -845,12 +852,10 @@
     sel := subView selection.
     sel notNil ifTrue:[
         queryBox initialText:(sel asString)
-"/    ] ifFalse:[
-"/        queryBox initialText:''
     ].
     queryBox showAtPointer
 
-    "Modified: 21.2.1996 / 01:43:14 / cg"
+    "Modified: 23.4.1997 / 13:04:38 / cg"
 !
 
 openChangesBrowser
@@ -1556,6 +1561,451 @@
         yesButton:yesButtonText
 !
 
+getSelectedFileName
+    "returns the currently selected file; shows an error if
+     multiple files are selected"
+
+    |sel|
+
+    sel := fileListView selection.
+    (sel size > 1) ifTrue:[
+        self onlyOneSelection
+    ] ifFalse:[
+        sel notNil ifTrue:[
+            ^ fileList at:sel first
+        ]
+    ].
+    ^ nil
+!
+
+onlyOneSelection
+    "show a warning, that only one file must be selected for
+     this operation"
+
+    self warn:'exactly one file must be selected !!'
+!
+
+selectedFilesDo:aBlock
+    "evaluate aBlock on all selected files;
+     show a wait cursor while doing this"
+
+    |sel|
+
+    sel := fileListView selection.
+    sel notNil ifTrue:[
+        self withWaitCursorDo:[
+            sel do:[:aSelectionIndex |
+                aBlock value:(fileList at:aSelectionIndex )
+            ]
+        ]
+    ]
+
+!
+
+show:something
+    "show something in subview and undef acceptAction"
+
+    subView contents:something.
+    subView acceptAction:nil.
+    subView modified:false.
+    currentFileName := nil
+!
+
+showAlert:aString with:anErrorString
+    "show an alertbox, displaying the last Unix-error"
+
+    |msg|
+
+    anErrorString isNil ifTrue:[
+        msg := aString
+    ] ifFalse:[
+        msg := aString , '\\(' , anErrorString , ')'
+    ].
+    self warn:msg withCRs
+!
+
+withoutHiddenFiles:aCollection
+    "remove hidden files (i.e. those that start with '.') from
+     the list in aCollection"
+
+    |newCollection|
+
+    newCollection := aCollection species new.
+    aCollection do:[:fname |
+        |ignore|
+
+        ignore := false.
+
+        ((fname startsWith:'.') and:[fname ~= '..']) ifTrue:[
+            showDotFiles ifFalse:[
+                ignore := true
+            ]
+        ].
+        ignore ifFalse:[
+            newCollection add:fname
+        ]
+    ].
+    ^ newCollection
+
+    "Modified: 21.2.1996 / 01:33:18 / cg"
+! !
+
+!FileBrowser methodsFor:'private - actions & command execution'!
+
+binaryFileAction:aFilename
+    "for some binary files, if double clicked, we can do some useful
+     action ..."
+
+    (currentDirectory pathName , '/' , aFilename) asFilename isExecutable ifTrue:[
+        (OperatingSystem executeCommand:'cd ',currentDirectory pathName, '; ',aFilename)
+        ifTrue:[^true].
+    ].
+    ^ self imageAction:aFilename
+
+    "Modified: 19.6.1996 / 09:44:07 / cg"
+!
+
+doExecuteCommand:command replace:replace
+    "execute a unix command inserting the output of the command.
+     If replace is true, all text is replaced by the commands output;
+     otherwise, its inserted as selected text at the cursor position."
+
+    |stream line lnr myProcess myPriority startLine startCol stopSignal
+     access stillReplacing|
+
+    access := Semaphore forMutualExclusion name:'accessLock'.
+    stopSignal := Signal new.
+
+    "
+     must take killButton out of my group
+    "
+    windowGroup removeView:killButton.
+    "
+     bring it to front, and turn hidden-mode off
+    "
+    killButton raise.
+    killButton beVisible.
+    "
+     it will make me raise stopSignal when pressed
+    "
+    killButton 
+        action:[
+            stream notNil ifTrue:[
+                access critical:[
+                    myProcess interruptWith:[stopSignal raise].
+                ]
+            ]
+        ].
+    "
+     start it up under its own windowgroup
+    "
+    killButton openAutonomous.
+
+    "
+     go fork a pipe and read it
+    "
+    self label:(myName , ': executing ' , (command copyTo:(20 min:command size)) , ' ...').
+    [
+      self withWaitCursorDo:[
+        stopSignal catch:[
+            startLine := subView cursorLine.
+            startCol := subView cursorCol.
+
+            "
+             this can be a time consuming operation; therefore lower my priority
+            "
+            myProcess := Processor activeProcess.
+            myPriority := myProcess priority.
+            myProcess priority:(Processor userBackgroundPriority).
+
+            stream := PipeStream readingFrom:('cd '
+                                              , currentDirectory pathName
+                                              , '; '
+                                              , command
+                                              , ' 2>&1' ).
+            stream notNil ifTrue:[
+                [
+                    |codeView lines|
+
+                    stream buffered:true.
+                    codeView := subView.
+
+                    replace ifTrue:[
+                        codeView list:nil.
+                        lnr := 1.
+                    ].
+
+                   stillReplacing := replace.
+
+                   [stream atEnd] whileFalse:[
+                        (stream readWaitWithTimeoutMs:50) ifFalse:[
+                            "
+                             data available; read up to 100 lines
+                             and insert as a single junk. This speeds up
+                             display of long output (less line-scrolling).
+                            "
+                            lines := OrderedCollection new:100.
+                            line := stream nextLine.
+                            line notNil ifTrue:[lines add:line].
+
+                            [stream atEnd not
+                            and:[stream canReadWithoutBlocking
+                            and:[lines size < 100]]] whileTrue:[
+                                line := stream nextLine.
+                                line notNil ifTrue:[lines add:line].
+                            ].
+
+                            "
+                             need this critical section; otherwise,
+                             we could get the signal while waiting for
+                             an expose event ...
+                            "
+                            access critical:[                        
+                                lines size > 0 ifTrue:[
+                                    stillReplacing ifTrue:[
+                                        lines do:[:line |
+                                            codeView at:lnr put:line withTabsExpanded.
+                                            codeView cursorToBottom; cursorDown:1.
+                                            lnr := lnr + 1.
+                                            lnr > codeView list size ifTrue:[
+                                                stillReplacing := false
+                                            ]
+                                        ].
+                                    ] ifFalse:[
+                                        codeView insertLines:lines before:codeView cursorLine.
+                                        codeView cursorDown:lines size.
+                                    ]
+                                ].
+                            ].
+                        ].
+
+                        shown ifTrue:[windowGroup processExposeEvents].
+                        "
+                         give others running at same prio a chance too
+                         (especially other FileBrowsers doing the same)
+                        "
+                        Processor yield
+                    ].
+                ] valueNowOrOnUnwindDo:[
+                    stream shutDown "close". stream := nil.
+                ].
+
+                self updateCurrentDirectoryIfChanged
+
+            ].
+            replace ifTrue:[
+                subView modified:false.
+            ].
+        ]
+      ]
+    ] valueNowOrOnUnwindDo:[
+        |wg|
+
+        self label:myName; iconLabel:myName.
+        myProcess notNil ifTrue:[myProcess priority:myPriority].
+
+        "
+         remove the killButton from its group
+         (otherwise, it will be destroyed when we shut down the group)
+        "
+        wg := killButton windowGroup.
+        killButton windowGroup:nil.
+        "
+         shut down the windowgroup
+        "
+        wg notNil ifTrue:[
+            wg process terminate.
+        ].
+        "
+         hide the button, and make sure it will stay
+         hidden when we are realized again
+        "
+        killButton beInvisible.
+        "
+         clear its action (actually not needed, but
+         releases reference to thisContext earlier)
+        "
+        killButton action:nil.
+    ].
+
+    currentFileName isNil ifTrue:[
+        subView modified:false.
+    ].
+
+    subView size > 10000 ifTrue:[
+        self warn:'text quite large now - please cut off some lines'
+    ]
+
+    "Modified: 21.9.1995 / 11:18:46 / claus"
+    "Modified: 19.4.1997 / 15:29:54 / cg"
+!
+
+imageAction:aFilename
+    "for some image files, if double clicked, we can do some useful
+     action ..."
+
+    |img|
+
+    (Image isImageFileSuffix:(aFilename asFilename suffix))
+    ifTrue:[
+        img := Image fromFile:(currentDirectory pathName , '/' , aFilename).
+        img notNil ifTrue:[
+            img inspect.
+            ^ true
+        ]
+    ].
+    ^ false
+
+    "Created: 19.6.1996 / 09:43:50 / cg"
+    "Modified: 18.4.1997 / 14:56:04 / cg"
+!
+
+initialCommandFor:fileName into:aBox
+    "set a useful initial command for execute box."
+
+    |lcFilename cmd select|
+
+    "/ XXX should be changed to take stuff from a config file
+    "/ XXX or from resources.
+
+    ((currentDirectory typeOf:fileName) == #regular) ifTrue:[
+
+        (currentDirectory isExecutable:fileName) ifTrue:[
+            aBox initialText:(fileName , ' <arguments>').
+            ^ self
+        ].
+
+        lcFilename := fileName asLowercase.
+
+        select := true.
+
+        "some heuristics - my personal preferences ...
+         (actually this should come from a configfile)"
+
+        (fileName endsWith:'akefile') ifTrue:[
+            aBox initialText:'make target' selectFrom:6 to:11.
+            ^ self
+        ].
+        (lcFilename endsWith:'tar.z') ifTrue:[
+            cmd := 'zcat %1 | tar tvf -'.
+            select := false.
+        ].
+        (fileName endsWith:'.taz') ifTrue:[
+            aBox initialText:'zcat %1 | tar tvf -'.
+            select := false.
+        ].
+        (fileName endsWith:'.tar') ifTrue:[
+            cmd := 'tar tvf %1'.
+            select := 7.
+        ].
+        (fileName endsWith:'.zoo') ifTrue:[
+            cmd := 'zoo -list %1'.
+            select := 9.
+        ].
+        (lcFilename endsWith:'.zip') ifTrue:[
+            cmd := 'unzip -l %1'.
+            select := 8.
+        ].
+        (lcFilename endsWith:'.z') ifTrue:[
+            cmd := 'uncompress %1'
+        ].
+        (fileName endsWith:'tar.gz') ifTrue:[
+            cmd := ('gunzip < %1 | tar tvf -' ).
+            select := false.
+        ].
+        (fileName endsWith:'.tgz') ifTrue:[
+            cmd := ('gunzip < %1 | tar tvf -' ).
+            select := false.
+        ].
+        (fileName endsWith:'.gz') ifTrue:[
+            cmd := 'gunzip %1'.
+        ].
+        (lcFilename endsWith:'.html') ifTrue:[
+            cmd := 'netscape %1'
+        ].
+        (lcFilename endsWith:'.htm') ifTrue:[
+            cmd := 'netscape %1'
+        ].
+        (fileName endsWith:'.uue') ifTrue:[
+            cmd := 'uudecode %1'
+        ].
+        (fileName endsWith:'.c') ifTrue:[
+            cmd := 'cc -c %1'.
+            select := 5.
+        ].
+        (fileName endsWith:'.cc') ifTrue:[
+            cmd := 'g++ -c %1'.
+            select := 6.
+        ].
+        (fileName endsWith:'.C') ifTrue:[
+            cmd := 'g++ -c %1'.
+            select := 6.
+        ].
+        (fileName endsWith:'.xbm') ifTrue:[
+            cmd := 'bitmap %1'
+        ].
+        (lcFilename endsWith:'.ps') ifTrue:[
+            cmd := 'ghostview %1'
+        ].
+        ((fileName endsWith:'.1') 
+        or:[fileName endsWith:'.man']) ifTrue:[
+            cmd := 'nroff -man %1'.
+            select := 10.
+        ].
+
+        cmd isNil ifTrue:[
+            DefaultCommandPerSuffix isNil ifTrue:[
+                cmd := '<cmd>'
+            ] ifFalse:[
+                cmd := DefaultCommandPerSuffix 
+                        at:(lcFilename asFilename suffix)
+                        ifAbsent:'<cmd>'.
+            ].
+            cmd := cmd , ' %1'.
+        ].
+
+        cmd := cmd bindWith:fileName.
+        select == false ifTrue:[
+            aBox initialText:cmd
+        ] ifFalse:[
+            select isInteger ifFalse:[
+                select := (cmd indexOf:Character space ifAbsent:[cmd size + 1]) - 1.
+            ].
+            aBox initialText:cmd selectFrom:1 to:select
+        ]
+    ]
+
+    "Modified: 4.4.1997 / 12:26:40 / cg"
+!
+
+nonBinaryFileAction:aFilename
+    "for some nonBinary files, if double clicked, we can do some useful
+     action ..."
+
+    |fullPath lcName|
+
+    fullPath := currentDirectory pathName , '/' , aFilename.
+    lcName := aFilename asLowercase.
+    ((lcName endsWith:'.htm') or:[lcName endsWith:'.html']) ifTrue:[
+        HTMLDocumentView openOn:fullPath.
+        ^ true
+    ].
+
+    OperatingSystem isUNIXlike ifTrue:[
+        (#('.man' '.1' '.2' '.3') findFirst:[:suff | aFilename endsWith:suff]) ~~ 0 
+        ifTrue:[
+             HTMLDocumentView openFullOnText:(HTMLDocGenerator manPageForFile:fullPath).
+            ^ true
+        ]
+    ].
+    ^ self imageAction:aFilename
+
+    "Created: 19.6.1996 / 09:36:38 / cg"
+    "Modified: 4.4.1997 / 10:49:00 / cg"
+! !
+
+!FileBrowser methodsFor:'private - directory stuff'!
+
 changeToPreviousDirectory
     "if text was modified show a queryBox, 
      otherwise change immediately to previous directory."
@@ -1757,523 +2207,41 @@
     "Modified: 19.4.1997 / 15:30:32 / cg"
 !
 
-doCreateFile:newName
-    |aStream|
-
-    (currentDirectory includes:newName) ifTrue:[
-        (self
-            ask:(resources string:'%1 already exists\\truncate ?' with:newName)
-            yesButton:'truncate'
-        ) ifFalse:[^ self].
-    ].
-
-    aStream := FileStream newFileNamed:newName in:currentDirectory.
-    aStream notNil ifTrue:[
-        aStream close.
-        self updateCurrentDirectoryIfChanged
-    ] ifFalse:[
-        self showAlert:(resources string:'cannot create file ''%1'' !!' with:newName)
-                  with:(FileStream lastErrorString)
-    ]
-
-    "Modified: 19.4.1997 / 15:30:35 / cg"
-!
-
-doExecuteCommand:command replace:replace
-    "execute a unix command inserting the output of the command.
-     If replace is true, all text is replaced by the commands output;
-     otherwise, its inserted as selected text at the cursor position."
-
-    |stream line lnr myProcess myPriority startLine startCol stopSignal
-     access stillReplacing|
-
-    access := Semaphore forMutualExclusion name:'accessLock'.
-    stopSignal := Signal new.
-
-    "
-     must take killButton out of my group
-    "
-    windowGroup removeView:killButton.
-    "
-     bring it to front, and turn hidden-mode off
-    "
-    killButton raise.
-    killButton beVisible.
-    "
-     it will make me raise stopSignal when pressed
-    "
-    killButton 
-        action:[
-            stream notNil ifTrue:[
-                access critical:[
-                    myProcess interruptWith:[stopSignal raise].
-                ]
-            ]
-        ].
-    "
-     start it up under its own windowgroup
-    "
-    killButton openAutonomous.
-
-    "
-     go fork a pipe and read it
-    "
-    self label:(myName , ': executing ' , (command copyTo:(20 min:command size)) , ' ...').
-    [
-      self withWaitCursorDo:[
-        stopSignal catch:[
-            startLine := subView cursorLine.
-            startCol := subView cursorCol.
-
-            "
-             this can be a time consuming operation; therefore lower my priority
-            "
-            myProcess := Processor activeProcess.
-            myPriority := myProcess priority.
-            myProcess priority:(Processor userBackgroundPriority).
-
-            stream := PipeStream readingFrom:('cd '
-                                              , currentDirectory pathName
-                                              , '; '
-                                              , command
-                                              , ' 2>&1' ).
-            stream notNil ifTrue:[
-                [
-                    |codeView lines|
-
-                    stream buffered:true.
-                    codeView := subView.
-
-                    replace ifTrue:[
-                        codeView list:nil.
-                        lnr := 1.
-                    ].
-
-                   stillReplacing := replace.
-
-                   [stream atEnd] whileFalse:[
-                        (stream readWaitWithTimeoutMs:50) ifFalse:[
-                            "
-                             data available; read up to 100 lines
-                             and insert as a single junk. This speeds up
-                             display of long output (less line-scrolling).
-                            "
-                            lines := OrderedCollection new:100.
-                            line := stream nextLine.
-                            line notNil ifTrue:[lines add:line].
-
-                            [stream atEnd not
-                            and:[stream canReadWithoutBlocking
-                            and:[lines size < 100]]] whileTrue:[
-                                line := stream nextLine.
-                                line notNil ifTrue:[lines add:line].
-                            ].
-
-                            "
-                             need this critical section; otherwise,
-                             we could get the signal while waiting for
-                             an expose event ...
-                            "
-                            access critical:[                        
-                                lines size > 0 ifTrue:[
-                                    stillReplacing ifTrue:[
-                                        lines do:[:line |
-                                            codeView at:lnr put:line withTabsExpanded.
-                                            codeView cursorToBottom; cursorDown:1.
-                                            lnr := lnr + 1.
-                                            lnr > codeView list size ifTrue:[
-                                                stillReplacing := false
-                                            ]
-                                        ].
-                                    ] ifFalse:[
-                                        codeView insertLines:lines before:codeView cursorLine.
-                                        codeView cursorDown:lines size.
-                                    ]
-                                ].
-                            ].
-                        ].
-
-                        shown ifTrue:[windowGroup processExposeEvents].
-                        "
-                         give others running at same prio a chance too
-                         (especially other FileBrowsers doing the same)
-                        "
-                        Processor yield
-                    ].
-                ] valueNowOrOnUnwindDo:[
-                    stream shutDown "close". stream := nil.
-                ].
-
-                self updateCurrentDirectoryIfChanged
-
+setCurrentDirectory:aPathName
+    "setup for another directory"
+
+    |newDirectory|
+
+    aPathName isEmpty ifTrue:[^ self].
+    (currentDirectory isDirectory:aPathName) ifTrue:[
+        newDirectory := FileDirectory directoryNamed:aPathName in:currentDirectory.
+        newDirectory notNil ifTrue:[
+            self currentDirectory:newDirectory pathName.
+            currentFileName notNil ifTrue:[
+                fileListView contents:nil.
+                currentFileName := nil.
+            ] ifFalse:[
+                fileListView setSelection:nil.
+                fileListView scrollToTop.
             ].
-            replace ifTrue:[
-                subView modified:false.
-            ].
-        ]
-      ]
-    ] valueNowOrOnUnwindDo:[
-        |wg|
-
-        self label:myName; iconLabel:myName.
-        myProcess notNil ifTrue:[myProcess priority:myPriority].
-
-        "
-         remove the killButton from its group
-         (otherwise, it will be destroyed when we shut down the group)
-        "
-        wg := killButton windowGroup.
-        killButton windowGroup:nil.
-        "
-         shut down the windowgroup
-        "
-        wg notNil ifTrue:[
-            wg process terminate.
-        ].
-        "
-         hide the button, and make sure it will stay
-         hidden when we are realized again
-        "
-        killButton beInvisible.
-        "
-         clear its action (actually not needed, but
-         releases reference to thisContext earlier)
-        "
-        killButton action:nil.
-    ].
-
-    currentFileName isNil ifTrue:[
-        subView modified:false.
-    ].
-
-    subView size > 10000 ifTrue:[
-        self warn:'text quite large now - please cut off some lines'
-    ]
-
-    "Modified: 21.9.1995 / 11:18:46 / claus"
-    "Modified: 19.4.1997 / 15:29:54 / cg"
-!
-
-doFileGet:viaDoubleClick
-    "get selected file - show contents in subView"
-
-    |fileName iconLbl winLbl|
-
-    self withReadCursorDo:[
-        fileName := self getSelectedFileName.
-        fileName notNil ifTrue:[
-            (currentDirectory isDirectory:fileName) ifTrue:[
-                self doChangeCurrentDirectoryTo:fileName updateHistory:true.
-                winLbl := myName.
-                iconLbl := myName
-            ] ifFalse:[
-                (currentDirectory exists:fileName) ifFalse:[
-                    self warn:(resources string:'oops, ''%1'' is gone' with:fileName).
-                    ^ self
-                ].
-                timeOfFileRead := currentDirectory timeOfLastChange:fileName.
-                self showFile:fileName insert:false encoding:fileEncoding doubleClick:viaDoubleClick.
-                currentFileName := fileName.
-
-                self fileTypeSpecificActions.
-
-                subView acceptAction:[:theCode |
-                    self withCursor:(Cursor write) do:[
-                        self writeFile:fileName text:theCode encoding:fileEncoding.
-                        timeOfFileRead := currentDirectory timeOfLastChange:fileName.
-                        self label:myName , ': ' , currentFileName
-                    ]
-                ].
-
-                winLbl := myName , ': ' , fileName.
-                (currentDirectory isWritable:fileName) ifFalse:[
-                    winLbl := winLbl , ' (readonly)'
-                ].
-                iconLbl := fileName
-            ].
-            self label:winLbl.
-            self iconLabel:iconLbl.
+            self updateCurrentDirectory.
+            self showInfo.
         ]
     ]
 
-    "Created: 19.6.1996 / 09:39:07 / cg"
-    "Modified: 7.1.1997 / 20:21:44 / cg"
-!
-
-doRemove
-    "remove the selected file(s) - no questions asked"
-
-    |ok msg dir idx needUpdate toRemove updateRunning|
-
-    updateRunning := listUpdateProcess notNil.
-    self stopUpdateProcess.
-    toRemove := OrderedCollection new.
-
-    "/
-    "/ did the directory change in the meanwhile ?
-    "/
-    needUpdate := (currentDirectory timeOfLastChange > timeOfLastCheck).
-
-    lockUpdate := true.
-    [
-        self selectedFilesDo:[:fileName |
-            ok := false.
-            (currentDirectory isDirectory:fileName) ifTrue:[
-                dir := FileDirectory directoryNamed:fileName in:currentDirectory.
-                dir isEmpty ifTrue:[
-                    ok := currentDirectory removeDirectory:fileName
-                ] ifFalse:[
-                    (self 
-                        ask:(resources string:'directory ''%1'' is not empty\remove anyway ?' with:fileName)
-                        yesButton:'remove')
-                    ifFalse:[
-                        ^ self
-                    ].
-                    ok := currentDirectory removeDirectory:fileName
-                ].
-            ] ifFalse:[
-                ok := currentDirectory remove:fileName.
-            ].
-            ok ifFalse:[
-                "was not able to remove it"
-                msg := (resources string:'cannot remove ''%1'' !!' with:fileName).
-                self showAlert:msg with:(OperatingSystem lastErrorString)
-            ] ifTrue:[
-"
-                self show:nil
-"
-                idx := fileList indexOf:fileName.
-                idx ~~ 0 ifTrue:[
-                    toRemove add:idx.
-                ]
-            ]
-        ].
-    ] valueNowOrOnUnwindDo:[
-        lockUpdate := false.
-        fileListView setSelection:nil.
-
-        "/
-        "/ remove reverse - otherwise indices are wrong
-        "/
-        toRemove sort.
-        toRemove reverseDo:[:idx |
-            fileList removeIndex:idx.
-            fileListView removeIndex:idx.
-        ].
-
-        updateRunning ifTrue:[
-            self updateCurrentDirectory
-        ] ifFalse:[
-            "
-             install a new check after some time
-            "
-            needUpdate ifFalse:[timeOfLastCheck := AbsoluteTime now].
-            Processor addTimedBlock:checkBlock afterSeconds:checkDelta
-        ]
-    ]
-
-    "Modified: 19.4.1997 / 14:03:55 / cg"
-!
-
-doRename:oldName to:newName
-    (oldName notNil and:[newName notNil]) ifTrue:[
-        (oldName isBlank or:[newName isBlank]) ifFalse:[
-            currentDirectory renameFile:oldName newName:newName.
-            self updateCurrentDirectoryIfChanged.
-        ]
-    ]
-
-    "Modified: 19.4.1997 / 15:30:49 / cg"
-!
-
-fileCommentStrings
-    "return useful comment definition; based upon the fileName for now"
-
-    "/ for now,
-    "/ define comment strings, by heuristics;
-    "/ (should look for some mode= or similar string
-    "/  found in the file itself - like emacs does it)
-
-    (currentFileName = 'Make.proto'
-    or:[currentFileName = 'Makefile'
-    or:[currentFileName = 'makefile']]) ifTrue:[
-        ^ #('#' (nil nil)).
-    ].
-    ((currentFileName endsWith:'.c')
-    or:[(currentFileName endsWith:'.C')]) ifTrue:[
-        ^ #(nil ('/*' '*/')).
-    ].
-    ((currentFileName endsWith:'.cc')
-    or:[(currentFileName endsWith:'.CC')]) ifTrue:[
-        ^ #('//' ('/*' '*/')).
-    ].
-    (currentFileName endsWith:'.java') ifTrue:[
-        ^ #('//' (nil nil)).
-    ].
-
-    "/ smalltalk comments
-
-    ^ #('"/' ('"' '"')).
-
-    "Created: 7.1.1997 / 20:30:00 / cg"
-!
-
-fileTypeSpecificActions
-    "any special fileTypeSpecific actions are done here,
-     when a new file is selected"
-
-    |commentStrings|
-
-    commentStrings := self fileCommentStrings.
-    commentStrings notNil ifTrue:[
-        subView
-            commentStrings:#('#' (nil nil)).
-    ].
-
-    "Modified: 7.1.1997 / 20:30:54 / cg"
+    "Modified: 21.9.1995 / 11:22:45 / claus"
+    "Modified: 25.5.1996 / 12:27:01 / cg"
 !
 
-getFileInfoString:longInfo
-    "get stat info on selected file - return a string which can be
-     shown in a box"
-
-    |fileName f fullPath text info fileOutput type modeBits modeString s ts|
-
-    fileName := self getSelectedFileName.
-    fileName isNil ifTrue:[^ nil].
-
-    f := currentDirectory pathName asFilename construct:fileName.
-    info := f info.
-
-"/    info := currentDirectory infoOf:fileName.
-    info isNil ifTrue:[
-        self showAlert:(resources string:'cannot get info of ''%1'' !!' with:fileName)
-                  with:(OperatingSystem lastErrorString).
-        ^ nil
-    ].
-
-    text := StringCollection new.
-    f isSymbolicLink ifTrue:[
-        text add:(resources string:'symbolic link to: %1' with:(f linkInfo path))
-    ].
-
-    type := info type.
-    (longInfo and:[type == #regular]) ifTrue:[
-        fullPath := currentDirectory pathName , '/' , fileName.
-        fileOutput := fullPath asFilename fileType.
-    ].
-
-    s := (resources at:'type:   ').
-    fileOutput isNil ifTrue:[
-        s := s ,  type asString
-    ] ifFalse:[
-        s := s , 'regular (' , fileOutput , ')'
-    ].
-    text add:s.
-    text add:(resources string:'size:   %1' with:(info size) printString).
-
-    modeBits := info mode.
-    modeString := self getModeString:modeBits.
-    longInfo ifTrue:[
-        text add:(resources string:'access: %1 (%2)'
-                              with:modeString 
-                              with:(modeBits printStringRadix:8))
-    ] ifFalse:[
-        text add:(resources string:'access: %1' with:modeString)
-    ].
-    text add:(resources string:'owner:  %1'
-                          with:(OperatingSystem getUserNameFromID:(info uid))).
-    longInfo ifTrue:[
-        text add:(resources string:'group:  %1'
-                              with:(OperatingSystem getGroupNameFromID:(info gid))).
-
-        ts := info accessed.
-        text add:(resources string:'last access:       %1 %2' 
-                              with:(ts asTime printString)
-                              with:(ts asDate printString)).
-
-        ts := info modified.
-        text add:(resources string:'last modification: %1 %2'
-                              with:(ts asTime printString)
-                              with:(ts asDate printString)).
-    ].
-    ^ text asString
-
-    "Modified: 8.9.1995 / 11:59:28 / claus"
-    "Modified: 1.11.1996 / 20:47:52 / cg"
-!
-
-getInfoFile
-    "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."
-
-    #( '.dir.info'
-       'README'
-       'ReadMe'
-       'Readme'
-       'readme' 
-    ) do:[:f |
-        (currentDirectory isReadable:f) ifTrue:[
-            (currentDirectory isDirectory:f) ifFalse:[^ f].
-        ]
-    ].
-    ^ nil
-!
-
-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 , (resources string:access)
-        ] ifFalse:[
-            (bits bitAnd:bitMask) == 0 ifTrue:[
-                ch := $-
-            ] ifFalse:[
-                ch := access
-            ].
-            modeString := modeString copyWith:ch 
-        ]
-    ].
-    ^ modeString
-!
-
-getSelectedFileName
-    "returns the currently selected file; shows an error if
-     multiple files are selected"
-
-    |sel|
-
-    sel := fileListView selection.
-    (sel size > 1) ifTrue:[
-        self onlyOneSelection
-    ] ifFalse:[
-        sel notNil ifTrue:[
-            ^ fileList at:sel first
-        ]
-    ].
-    ^ nil
-!
+updateCurrentDirectoryIfChanged
+    (currentDirectory timeOfLastChange > timeOfLastCheck) ifTrue:[
+        self updateCurrentDirectory
+    ]
+
+    "Modified: 19.4.1997 / 15:30:03 / cg"
+! !
+
+!FileBrowser methodsFor:'private - encoding'!
 
 guessEncodingFrom:aBuffer
     "look for a string
@@ -2326,241 +2294,6 @@
     "Modified: 23.1.1997 / 20:39:25 / cg"
 !
 
-initialCommandFor:fileName into:aBox
-    "set a useful initial command for execute box."
-
-    |lcFilename cmd select|
-
-    "/ XXX should be changed to take stuff from a config file
-    "/ XXX or from resources.
-
-    ((currentDirectory typeOf:fileName) == #regular) ifTrue:[
-
-        (currentDirectory isExecutable:fileName) ifTrue:[
-            aBox initialText:(fileName , ' <arguments>').
-            ^ self
-        ].
-
-        lcFilename := fileName asLowercase.
-
-        select := true.
-
-        "some heuristics - my personal preferences ...
-         (actually this should come from a configfile)"
-
-        (fileName endsWith:'akefile') ifTrue:[
-            aBox initialText:'make target' selectFrom:6 to:11.
-            ^ self
-        ].
-        (lcFilename endsWith:'tar.z') ifTrue:[
-            cmd := 'zcat %1 | tar tvf -'.
-            select := false.
-        ].
-        (fileName endsWith:'.taz') ifTrue:[
-            aBox initialText:'zcat %1 | tar tvf -'.
-            select := false.
-        ].
-        (fileName endsWith:'.tar') ifTrue:[
-            cmd := 'tar tvf %1'.
-            select := 7.
-        ].
-        (fileName endsWith:'.zoo') ifTrue:[
-            cmd := 'zoo -list %1'.
-            select := 9.
-        ].
-        (lcFilename endsWith:'.zip') ifTrue:[
-            cmd := 'unzip -l %1'.
-            select := 8.
-        ].
-        (lcFilename endsWith:'.z') ifTrue:[
-            cmd := 'uncompress %1'
-        ].
-        (fileName endsWith:'tar.gz') ifTrue:[
-            cmd := ('gunzip < %1 | tar tvf -' ).
-            select := false.
-        ].
-        (fileName endsWith:'.tgz') ifTrue:[
-            cmd := ('gunzip < %1 | tar tvf -' ).
-            select := false.
-        ].
-        (fileName endsWith:'.gz') ifTrue:[
-            cmd := 'gunzip %1'.
-        ].
-        (lcFilename endsWith:'.html') ifTrue:[
-            cmd := 'netscape %1'
-        ].
-        (lcFilename endsWith:'.htm') ifTrue:[
-            cmd := 'netscape %1'
-        ].
-        (fileName endsWith:'.uue') ifTrue:[
-            cmd := 'uudecode %1'
-        ].
-        (fileName endsWith:'.c') ifTrue:[
-            cmd := 'cc -c %1'.
-            select := 5.
-        ].
-        (fileName endsWith:'.cc') ifTrue:[
-            cmd := 'g++ -c %1'.
-            select := 6.
-        ].
-        (fileName endsWith:'.C') ifTrue:[
-            cmd := 'g++ -c %1'.
-            select := 6.
-        ].
-        (fileName endsWith:'.xbm') ifTrue:[
-            cmd := 'bitmap %1'
-        ].
-        (lcFilename endsWith:'.ps') ifTrue:[
-            cmd := 'ghostview %1'
-        ].
-        ((fileName endsWith:'.1') 
-        or:[fileName endsWith:'.man']) ifTrue:[
-            cmd := 'nroff -man %1'.
-            select := 10.
-        ].
-
-        cmd isNil ifTrue:[
-            DefaultCommandPerSuffix isNil ifTrue:[
-                cmd := '<cmd>'
-            ] ifFalse:[
-                cmd := DefaultCommandPerSuffix 
-                        at:(lcFilename asFilename suffix)
-                        ifAbsent:'<cmd>'.
-            ].
-            cmd := cmd , ' %1'.
-        ].
-
-        cmd := cmd bindWith:fileName.
-        select == false ifTrue:[
-            aBox initialText:cmd
-        ] ifFalse:[
-            select isInteger ifFalse:[
-                select := (cmd indexOf:Character space ifAbsent:[cmd size + 1]) - 1.
-            ].
-            aBox initialText:cmd selectFrom:1 to:select
-        ]
-    ]
-
-    "Modified: 4.4.1997 / 12:26:40 / cg"
-!
-
-onlyOneSelection
-    "show a warning, that only one file must be selected for
-     this operation"
-
-    self warn:'exactly one file must be selected !!'
-!
-
-selectedFilesDo:aBlock
-    "evaluate aBlock on all selected files;
-     show a wait cursor while doing this"
-
-    |sel|
-
-    sel := fileListView selection.
-    sel notNil ifTrue:[
-        self withWaitCursorDo:[
-            sel do:[:aSelectionIndex |
-                aBlock value:(fileList at:aSelectionIndex )
-            ]
-        ]
-    ]
-
-!
-
-setCurrentDirectory:aPathName
-    "setup for another directory"
-
-    |newDirectory|
-
-    aPathName isEmpty ifTrue:[^ self].
-    (currentDirectory isDirectory:aPathName) ifTrue:[
-        newDirectory := FileDirectory directoryNamed:aPathName in:currentDirectory.
-        newDirectory notNil ifTrue:[
-            self currentDirectory:newDirectory pathName.
-            currentFileName notNil ifTrue:[
-                fileListView contents:nil.
-                currentFileName := nil.
-            ] ifFalse:[
-                fileListView setSelection:nil.
-                fileListView scrollToTop.
-            ].
-            self updateCurrentDirectory.
-            self showInfo.
-        ]
-    ]
-
-    "Modified: 21.9.1995 / 11:22:45 / claus"
-    "Modified: 25.5.1996 / 12:27:01 / cg"
-!
-
-show:something
-    "show something in subview and undef acceptAction"
-
-    subView contents:something.
-    subView acceptAction:nil.
-    subView modified:false.
-    currentFileName := nil
-!
-
-showAlert:aString with:anErrorString
-    "show an alertbox, displaying the last Unix-error"
-
-    |msg|
-
-    anErrorString isNil ifTrue:[
-        msg := aString
-    ] ifFalse:[
-        msg := aString , '\\(' , anErrorString , ')'
-    ].
-    self warn:msg withCRs
-!
-
-showInfo
-    "show directory info when dir has changed"
-
-    |info txt|
-
-    info := self getInfoFile.
-    info notNil ifTrue:[
-        txt := self readFile:info
-    ].
-    self show:txt.
-!
-
-sizePrintString:size
-    "helper for update-directory to return a string with a files size.
-     This one gives the size in byte, Kb or Mb depending on size.
-     If you dont like this, just uncomment the first statement below."
-
-    |unitString n|
-
-"
-    ^ size printString.
-"
-    unitString := ''.
-    size < (500 * 1024) ifTrue:[
-        size < 1024 ifTrue:[
-            n := size
-        ] ifFalse:[
-            n := (size * 10 // 1024 / 10.0).
-            unitString := ' Kb'
-        ]
-    ] ifFalse:[
-        n := (size * 10 // 1024 // 1024 / 10.0).
-        unitString := ' Mb'
-    ].
-    ^ (n printStringLeftPaddedTo:5) , unitString.
-!
-
-updateCurrentDirectoryIfChanged
-    (currentDirectory timeOfLastChange > timeOfLastCheck) ifTrue:[
-        self updateCurrentDirectory
-    ]
-
-    "Modified: 19.4.1997 / 15:30:03 / cg"
-!
-
 validateFontEncodingFor:newEncoding ask:ask
     "if required, query user if he/she wants to change to another font,
      which is able to display text encoded as specified by newEncoding"
@@ -2653,93 +2386,645 @@
     ]
 
     "Created: 26.10.1996 / 12:06:54 / cg"
+! !
+
+!FileBrowser methodsFor:'private - file stuff'!
+
+doCreateFile:newName
+    "create an empty file"
+
+    |aStream|
+
+    (currentDirectory includes:newName) ifTrue:[
+        (self
+            ask:(resources string:'%1 already exists\\truncate ?' with:newName)
+            yesButton:'truncate'
+        ) ifFalse:[^ self].
+    ].
+
+    aStream := FileStream newFileNamed:newName in:currentDirectory.
+    aStream notNil ifTrue:[
+        aStream close.
+        self updateCurrentDirectoryIfChanged
+    ] ifFalse:[
+        self showAlert:(resources string:'cannot create file ''%1'' !!' with:newName)
+                  with:(FileStream lastErrorString)
+    ]
+
+    "Modified: 23.4.1997 / 13:19:12 / cg"
 !
 
-withoutHiddenFiles:aCollection
-    "remove hidden files (i.e. those that start with '.') from
-     the list in aCollection"
-
-    |newCollection|
-
-    newCollection := aCollection species new.
-    aCollection do:[:fname |
-        |ignore|
-
-        ignore := false.
-
-        ((fname startsWith:'.') and:[fname ~= '..']) ifTrue:[
-            showDotFiles ifFalse:[
-                ignore := true
+doFileGet:viaDoubleClick
+    "get selected file - show contents in subView.
+     This is invoked either by the 'get file' menu item, or via double click.
+     When invoked via the menu (viaDoubleClick argument is false),
+     the automatic file action is not performed - instead, the file is always
+     shown in the codeView (if possible).
+     This distinction was done to allow xpm or xbm files (which ahve an automatic
+     action) to be edited."
+
+    |fileName iconLbl winLbl|
+
+    self withReadCursorDo:[
+        fileName := self getSelectedFileName.
+        fileName notNil ifTrue:[
+            (currentDirectory isDirectory:fileName) ifTrue:[
+                self doChangeCurrentDirectoryTo:fileName updateHistory:true.
+                winLbl := myName.
+                iconLbl := myName
+            ] ifFalse:[
+                (currentDirectory exists:fileName) ifFalse:[
+                    self warn:(resources string:'oops, ''%1'' is gone' with:fileName).
+                    ^ self
+                ].
+                timeOfFileRead := currentDirectory timeOfLastChange:fileName.
+                self showFile:fileName insert:false encoding:fileEncoding doubleClick:viaDoubleClick.
+                currentFileName := fileName.
+
+                self fileTypeSpecificActions.
+
+                subView acceptAction:[:theCode |
+                    self withCursor:(Cursor write) do:[
+                        self writeFile:fileName text:theCode encoding:fileEncoding.
+                        timeOfFileRead := currentDirectory timeOfLastChange:fileName.
+                        self label:myName , ': ' , currentFileName
+                    ]
+                ].
+
+                winLbl := myName , ': ' , fileName.
+                (currentDirectory isWritable:fileName) ifFalse:[
+                    winLbl := winLbl , ' (readonly)'
+                ].
+                iconLbl := fileName
+            ].
+            self label:winLbl.
+            self iconLabel:iconLbl.
+        ]
+    ]
+
+    "Created: 19.6.1996 / 09:39:07 / cg"
+    "Modified: 23.4.1997 / 13:19:01 / cg"
+!
+
+doRemove
+    "remove the selected file(s) - no questions asked"
+
+    |ok msg dir idx needUpdate toRemove updateRunning|
+
+    updateRunning := listUpdateProcess notNil.
+    self stopUpdateProcess.
+    toRemove := OrderedCollection new.
+
+    "/
+    "/ did the directory change in the meanwhile ?
+    "/
+    needUpdate := (currentDirectory timeOfLastChange > timeOfLastCheck).
+
+    lockUpdate := true.
+    [
+        self selectedFilesDo:[:fileName |
+            ok := false.
+            (currentDirectory isDirectory:fileName) ifTrue:[
+                dir := FileDirectory directoryNamed:fileName in:currentDirectory.
+                dir isEmpty ifTrue:[
+                    ok := currentDirectory removeDirectory:fileName
+                ] ifFalse:[
+                    (self 
+                        ask:(resources string:'directory ''%1'' is not empty\remove anyway ?' with:fileName)
+                        yesButton:'remove')
+                    ifFalse:[
+                        ^ self
+                    ].
+                    ok := currentDirectory removeDirectory:fileName
+                ].
+            ] ifFalse:[
+                ok := currentDirectory remove:fileName.
+            ].
+            ok ifFalse:[
+                "was not able to remove it"
+                msg := (resources string:'cannot remove ''%1'' !!' with:fileName).
+                self showAlert:msg with:(OperatingSystem lastErrorString)
+            ] ifTrue:[
+"
+                self show:nil
+"
+                idx := fileList indexOf:fileName.
+                idx ~~ 0 ifTrue:[
+                    toRemove add:idx.
+                ]
             ]
         ].
-        ignore ifFalse:[
-            newCollection add:fname
+    ] valueNowOrOnUnwindDo:[
+        lockUpdate := false.
+        fileListView setSelection:nil.
+
+        "/
+        "/ remove reverse - otherwise indices are wrong
+        "/
+        toRemove sort.
+        toRemove reverseDo:[:idx |
+            fileList removeIndex:idx.
+            fileListView removeIndex:idx.
+        ].
+
+        updateRunning ifTrue:[
+            self updateCurrentDirectory
+        ] ifFalse:[
+            "
+             install a new check after some time
+            "
+            needUpdate ifFalse:[timeOfLastCheck := AbsoluteTime now].
+            Processor addTimedBlock:checkBlock afterSeconds:checkDelta
+        ]
+    ]
+
+    "Modified: 19.4.1997 / 14:03:55 / cg"
+!
+
+doRename:oldName to:newName
+    "rename file(s) (or directories)"
+
+    (oldName notNil and:[newName notNil]) ifTrue:[
+        (oldName isBlank or:[newName isBlank]) ifFalse:[
+            currentDirectory renameFile:oldName newName:newName.
+            self updateCurrentDirectoryIfChanged.
+        ]
+    ]
+
+    "Modified: 23.4.1997 / 13:19:37 / cg"
+! !
+
+!FileBrowser methodsFor:'private - file type & info'!
+
+fileCommentStrings
+    "return a useful comment definition; based upon the fileName for now"
+
+    "/ for now,
+    "/ define comment strings, by heuristics;
+    "/ (should look for some mode= or similar string
+    "/  found in the file itself - like emacs does it)
+
+    (currentFileName = 'Make.proto'
+    or:[currentFileName = 'Makefile'
+    or:[currentFileName = 'makefile']]) ifTrue:[
+        ^ #('#' (nil nil)).
+    ].
+    ((currentFileName endsWith:'.c')
+    or:[(currentFileName endsWith:'.C')]) ifTrue:[
+        ^ #(nil ('/*' '*/')).
+    ].
+    ((currentFileName endsWith:'.cc')
+    or:[(currentFileName endsWith:'.CC')]) ifTrue:[
+        ^ #('//' ('/*' '*/')).
+    ].
+    (currentFileName endsWith:'.java') ifTrue:[
+        ^ #('//' (nil nil)).
+    ].
+
+    "/ smalltalk comments
+
+    ^ #('"/' ('"' '"')).
+
+    "Created: 7.1.1997 / 20:30:00 / cg"
+    "Modified: 23.4.1997 / 13:11:49 / cg"
+!
+
+fileTypeSpecificActions
+    "any special fileTypeSpecific actions are done here,
+     when a new file is selected"
+
+    |commentStrings|
+
+    commentStrings := self fileCommentStrings.
+    commentStrings notNil ifTrue:[
+        subView
+            commentStrings:#('#' (nil nil)).
+    ].
+
+    "Modified: 7.1.1997 / 20:30:54 / cg"
+!
+
+getFileInfoString:longInfo
+    "get stat info on selected file - return a string which can be
+     shown in a box"
+
+    |fileName f fullPath text info fileOutput type modeBits modeString s ts|
+
+    fileName := self getSelectedFileName.
+    fileName isNil ifTrue:[^ nil].
+
+    f := currentDirectory pathName asFilename construct:fileName.
+    info := f info.
+
+"/    info := currentDirectory infoOf:fileName.
+    info isNil ifTrue:[
+        self showAlert:(resources string:'cannot get info of ''%1'' !!' with:fileName)
+                  with:(OperatingSystem lastErrorString).
+        ^ nil
+    ].
+
+    text := StringCollection new.
+    f isSymbolicLink ifTrue:[
+        text add:(resources string:'symbolic link to: %1' with:(f linkInfo path))
+    ].
+
+    type := info type.
+    (longInfo and:[type == #regular]) ifTrue:[
+        fullPath := currentDirectory pathName , '/' , fileName.
+        fileOutput := fullPath asFilename fileType.
+    ].
+
+    s := (resources at:'type:   ').
+    fileOutput isNil ifTrue:[
+        s := s ,  type asString
+    ] ifFalse:[
+        s := s , 'regular (' , fileOutput , ')'
+    ].
+    text add:s.
+    text add:(resources string:'size:   %1' with:(info size) printString).
+
+    modeBits := info mode.
+    modeString := self getModeString:modeBits.
+    longInfo ifTrue:[
+        text add:(resources string:'access: %1 (%2)'
+                              with:modeString 
+                              with:(modeBits printStringRadix:8))
+    ] ifFalse:[
+        text add:(resources string:'access: %1' with:modeString)
+    ].
+    text add:(resources string:'owner:  %1'
+                          with:(OperatingSystem getUserNameFromID:(info uid))).
+    longInfo ifTrue:[
+        text add:(resources string:'group:  %1'
+                              with:(OperatingSystem getGroupNameFromID:(info gid))).
+
+        ts := info accessed.
+        text add:(resources string:'last access:       %1 %2' 
+                              with:(ts asTime printString)
+                              with:(ts asDate printString)).
+
+        ts := info modified.
+        text add:(resources string:'last modification: %1 %2'
+                              with:(ts asTime printString)
+                              with:(ts asDate printString)).
+    ].
+    ^ text asString
+
+    "Modified: 8.9.1995 / 11:59:28 / claus"
+    "Modified: 1.11.1996 / 20:47:52 / cg"
+!
+
+getInfoFile
+    "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."
+
+    #( 
+       '.dir.info'
+       'README'
+       'ReadMe'
+       'Readme'
+       'readme'
+       'read.me'
+       'Read.me'
+       'READ.ME'
+    ) do:[:f |
+        (currentDirectory isReadable:f) ifTrue:[
+            (currentDirectory isDirectory:f) ifFalse:[^ f].
         ]
     ].
-    ^ newCollection
-
-    "Modified: 21.2.1996 / 01:33:18 / cg"
-! !
-
-!FileBrowser methodsFor:'private - actions'!
-
-binaryFileAction:aFilename
-    "for some binary files, if double clicked, we can do some useful
-     action ..."
-
-    (currentDirectory pathName , '/' , aFilename) asFilename isExecutable ifTrue:[
-        (OperatingSystem executeCommand:'cd ',currentDirectory pathName, '; ',aFilename)
-        ifTrue:[^true].
-    ].
-    ^ self imageAction:aFilename
-
-    "Modified: 19.6.1996 / 09:44:07 / cg"
+    ^ nil
+
+    "Modified: 23.4.1997 / 13:12:36 / cg"
+!
+
+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 )
 !
 
-imageAction:aFilename
-    "for some image files, if double clicked, we can do some useful
-     action ..."
-
-    |img|
-
-    (Image isImageFileSuffix:(aFilename asFilename suffix))
-    ifTrue:[
-        img := Image fromFile:(currentDirectory pathName , '/' , aFilename).
-        img notNil ifTrue:[
-            img inspect.
-            ^ true
+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 , (resources string:access)
+        ] ifFalse:[
+            (bits bitAnd:bitMask) == 0 ifTrue:[
+                ch := $-
+            ] ifFalse:[
+                ch := access
+            ].
+            modeString := modeString copyWith:ch 
         ]
     ].
-    ^ false
-
-    "Created: 19.6.1996 / 09:43:50 / cg"
-    "Modified: 18.4.1997 / 14:56:04 / cg"
+    ^ modeString
+!
+
+showInfo
+    "show directory info when dir has changed"
+
+    |info txt|
+
+    info := self getInfoFile.
+    info notNil ifTrue:[
+        txt := self readFile:info
+    ].
+    self show:txt.
+!
+
+sizePrintString:size
+    "helper for update-directory to return a string with a files size.
+     This one gives the size in byte, Kb or Mb depending on size.
+     If you dont like this, just uncomment the first statement below."
+
+    |unitString n|
+
+"
+    ^ size printString.
+"
+    unitString := ''.
+    size < (500 * 1024) ifTrue:[
+        size < 1024 ifTrue:[
+            n := size
+        ] ifFalse:[
+            n := (size * 10 // 1024 / 10.0).
+            unitString := ' Kb'
+        ]
+    ] ifFalse:[
+        n := (size * 10 // 1024 // 1024 / 10.0).
+        unitString := ' Mb'
+    ].
+    ^ (n printStringLeftPaddedTo:5) , unitString.
+! !
+
+!FileBrowser methodsFor:'private - file-I/O'!
+
+readFile:fileName
+    "read in the file, answer its contents as StringCollection"
+
+    ^ self readFile:fileName lineDelimiter:Character cr encoding:nil
+
+    "Modified: 22.2.1996 / 14:57:08 / cg"
+!
+
+readFile:fileName lineDelimiter:aCharacter encoding:encoding
+    "read in the file, return its contents as StringCollection. 
+     The files lines are delimited by aCharacter.
+     If encoding is nonNil, the file is assumed to be coded according to
+     that symbol, and #decodeString: should be able to convert it."
+
+    |stream text msg sz|
+
+    stream := FileStream readonlyFileNamed:fileName in:currentDirectory.
+    stream isNil ifTrue:[
+        msg := (resources string:'cannot read file ''%1'' !!' with:fileName).
+        self showAlert:msg with:(FileStream lastErrorString).
+        ^ nil
+    ].
+
+    "
+     for very big files, give ObjectMemory a hint, to preallocate more
+    "
+    (sz := stream size) > 1000000 ifTrue:[
+        Processor activeProcess withPriority:Processor userBackgroundPriority do:[
+            ObjectMemory announceSpaceNeed:(sz + (sz // 5)) "/ add 20% for tab expansion
+        ].
+    ].
+
+    text := self readStream:stream lineDelimiter:aCharacter encoding:encoding.
+    stream close.
+    ^ text
+
+    "Created: 22.2.1996 / 14:56:48 / cg"
+    "Modified: 8.10.1996 / 21:01:57 / cg"
+!
+
+readStream:aStream
+    "read in from aStream, answer its contents as StringCollection"
+
+    ^ self readStream:aStream lineDelimiter:Character cr encoding:nil
+
+    "Modified: 22.2.1996 / 14:58:40 / cg"
 !
 
-nonBinaryFileAction:aFilename
-    "for some nonBinary files, if double clicked, we can do some useful
-     action ..."
-
-    |fullPath lcName|
-
-    fullPath := currentDirectory pathName , '/' , aFilename.
-    lcName := aFilename asLowercase.
-    ((lcName endsWith:'.htm') or:[lcName endsWith:'.html']) ifTrue:[
-        HTMLDocumentView openOn:fullPath.
-        ^ true
+readStream:aStream lineDelimiter:aCharacter encoding:encoding 
+    "read from aStream, answer its contents as StringCollection. 
+     The files lines are delimited by aCharacter.
+     If encoding is nonNil, the file is assumed to be coded according to
+     that symbol, and #decodeString: should be able to convert it."
+
+    |text line enc|
+
+    text := StringCollection new.
+
+    enc := encoding.
+    enc == #iso8859 ifTrue:[
+        enc := nil
+    ].
+
+    aCharacter == Character cr ifTrue:[
+        [aStream atEnd] whileFalse:[
+            line := aStream nextLine withTabsExpanded.
+            enc notNil ifTrue:[
+                line := line decodeFrom:enc
+            ].
+            text add:line
+        ].
+    ] ifFalse:[
+        [aStream atEnd] whileFalse:[
+            line := (aStream upTo:aCharacter) withTabsExpanded.
+            enc notNil ifTrue:[
+                line := line decodeFrom:enc
+            ].
+            text add:line
+        ].
     ].
-
-    OperatingSystem isUNIXlike ifTrue:[
-        (#('.man' '.1' '.2' '.3') findFirst:[:suff | aFilename endsWith:suff]) ~~ 0 
-        ifTrue:[
-             HTMLDocumentView openFullOnText:(HTMLDocGenerator manPageForFile:fullPath).
-            ^ true
+    ^ text
+
+    "Created: 22.2.1996 / 14:58:25 / cg"
+    "Modified: 2.4.1997 / 21:31:36 / cg"
+!
+
+showFile:fileName
+    "show contents of fileName in subView"
+
+    self showFile:fileName insert:false encoding:fileEncoding
+
+    "Modified: 22.2.1996 / 14:47:10 / cg"
+!
+
+showFile:fileName insert:insert encoding:encoding
+    "show/insert contents of fileName in subView"
+
+    ^ self 
+        showFile:fileName insert:insert encoding:encoding doubleClick:false
+
+    "Modified: 19.6.1996 / 09:40:19 / cg"
+!
+
+showFile:fileName insert:insert encoding:encoding doubleClick:viaDoubleClick
+    "show/insert contents of fileName in subView"
+
+    |buffer s n i ok convert text msg eol guess action enc|
+
+    ((currentDirectory typeOf:fileName) == #regular) ifFalse:[
+        "asked for a non-file  - ignore it ..."
+        (currentDirectory exists:fileName) ifFalse:[
+            msg := '''%1'' does not exist !!'.
+        ] ifTrue:[
+            msg := '''%1'' is not a regular file !!'.
+        ].
+        self warn:(resources string:msg with:fileName).
+        ^ self
+    ].
+
+    "/
+    "/ check if file is a text file
+    "/
+    s := FileStream readonlyFileNamed:fileName in:currentDirectory.
+    s isNil ifTrue:[
+        self showAlert:(resources string:'cannot read file ''%1'' !!' with:fileName)
+                  with:(FileStream lastErrorString).
+        ^ nil
+    ].
+
+    buffer := String new:300.
+    n := s nextBytes:300 into:buffer.
+    s close.
+
+    enc := encoding.
+    ok := true.
+    guess := self guessEncodingFrom:buffer.
+
+    guess == #binary ifTrue:[
+        ok := false.
+        viaDoubleClick ifTrue:[
+            (self binaryFileAction:fileName) ifTrue:[^ self].
+        ].
+        (self confirm:(resources string:'''%1'' seems to be a binary file - show anyway ?' with:fileName))
+        ifFalse:[^ self]
+    ] ifFalse:[
+        viaDoubleClick ifTrue:[
+            (self nonBinaryFileAction:fileName) ifTrue:[^ self].
+        ].
+
+        "/ ascii should work in any font ...
+
+        guess ~~ #ascii ifTrue:[
+            fileEncoding ~~ guess ifTrue:[
+                action := Dialog choose:(resources string:'''%1'' seems to be ' , guess , ' encoded.' with:fileName)
+                               labels:(resources array:#('cancel' 'show' 'change font'))
+                               values:#(nil #show #encoding)
+                               default:#encoding.
+                action isNil ifTrue:[^ self].
+                action == #encoding ifTrue:[
+                    fileEncoding := guess asSymbol.
+                    self validateFontEncodingFor:fileEncoding ask:false.
+                    enc := fileEncoding.
+                ]
+            ]    
+        ].
+    ].
+
+    convert := false.
+    ok ifTrue:[
+        "/
+        "/ check if line delimiter is a cr
+        "/
+        i := buffer indexOf:Character cr.
+        i == 0 ifTrue:[
+            "/
+            "/ no newline found - try cr
+            "/
+            i := buffer indexOf:(Character value:13).
+            i ~~ 0 ifTrue:[
+                convert := self confirm:(resources string:'''%1'' seems to have CR as line delimiter - convert to NL ?' with:fileName).
+            ]
         ]
     ].
-    ^ self imageAction:aFilename
-
-    "Created: 19.6.1996 / 09:36:38 / cg"
-    "Modified: 4.4.1997 / 10:49:00 / cg"
+
+    insert ifFalse:[
+        "/ release old text first 
+        "/ - we might need the memory in case of huge files
+        "/  (helps if you have a 4Mb file in the view, 
+        "/   and click on another biggy)
+
+        subView contents:nil.
+    ].
+
+    convert ifTrue:[
+        eol := Character value:13
+    ] ifFalse:[
+        eol := Character cr
+    ].
+    text := self readFile:fileName lineDelimiter:eol encoding:enc.
+
+    insert ifFalse:[
+        self show:text
+    ] ifTrue:[
+        subView insertSelectedStringAtCursor:text asString
+    ].
+
+    "Created: 19.6.1996 / 09:39:52 / cg"
+    "Modified: 23.1.1997 / 20:31:43 / cg"
+!
+
+writeFile:fileName text:someText encoding:encoding
+    |stream msg startNr nLines string|
+
+    stream := FileStream newFileNamed:fileName in:currentDirectory.
+    stream isNil ifTrue:[
+        msg := (resources string:'cannot write file ''%1'' !!' with:fileName).
+        self showAlert:msg with:(FileStream lastErrorString)
+    ] ifFalse:[
+        someText isString ifTrue:[
+            stream nextPutAll:someText.
+        ] ifFalse:[
+            "
+             on some systems, writing linewise is very slow (via NFS)
+             therefore we convert to a string and write it in chunks
+             to avoid creating huge strings, we do it in blocks of 1000 lines
+            "
+            startNr := 1.
+            nLines := someText size.
+            [startNr <= nLines] whileTrue:[
+                string := someText asStringWithCRsFrom:startNr
+                                                    to:((startNr + 1000) min:nLines)
+                                          compressTabs:compressTabs.
+                encoding notNil ifTrue:[
+                    string := string encodeInto:encoding
+                ].
+                stream nextPutAll:string.
+                startNr := startNr + 1000 + 1.
+            ].
+"/                someText do:[:line |
+"/                  line notNil ifTrue:[
+"/                      stream nextPutAll:line.
+"/                  ].
+"/                  stream cr.
+"/              ]
+        ].
+        stream close.
+        subView modified:false
+    ]
+
+    "Created: 22.2.1996 / 15:03:10 / cg"
+    "Modified: 22.2.1996 / 15:08:31 / cg"
 ! !
 
 !FileBrowser methodsFor:'private - presentation'!
@@ -3190,261 +3475,6 @@
     "Modified: 21.4.1997 / 15:01:27 / cg"
 ! !
 
-!FileBrowser methodsFor:'private-file-I/O'!
-
-readFile:fileName
-    "read in the file, answer its contents as StringCollection"
-
-    ^ self readFile:fileName lineDelimiter:Character cr encoding:nil
-
-    "Modified: 22.2.1996 / 14:57:08 / cg"
-!
-
-readFile:fileName lineDelimiter:aCharacter encoding:encoding
-    "read in the file, return its contents as StringCollection. 
-     The files lines are delimited by aCharacter.
-     If encoding is nonNil, the file is assumed to be coded according to
-     that symbol, and #decodeString: should be able to convert it."
-
-    |stream text msg sz|
-
-    stream := FileStream readonlyFileNamed:fileName in:currentDirectory.
-    stream isNil ifTrue:[
-        msg := (resources string:'cannot read file ''%1'' !!' with:fileName).
-        self showAlert:msg with:(FileStream lastErrorString).
-        ^ nil
-    ].
-
-    "
-     for very big files, give ObjectMemory a hint, to preallocate more
-    "
-    (sz := stream size) > 1000000 ifTrue:[
-        Processor activeProcess withPriority:Processor userBackgroundPriority do:[
-            ObjectMemory announceSpaceNeed:(sz + (sz // 5)) "/ add 20% for tab expansion
-        ].
-    ].
-
-    text := self readStream:stream lineDelimiter:aCharacter encoding:encoding.
-    stream close.
-    ^ text
-
-    "Created: 22.2.1996 / 14:56:48 / cg"
-    "Modified: 8.10.1996 / 21:01:57 / cg"
-!
-
-readStream:aStream
-    "read in from aStream, answer its contents as StringCollection"
-
-    ^ self readStream:aStream lineDelimiter:Character cr encoding:nil
-
-    "Modified: 22.2.1996 / 14:58:40 / cg"
-!
-
-readStream:aStream lineDelimiter:aCharacter encoding:encoding 
-    "read from aStream, answer its contents as StringCollection. 
-     The files lines are delimited by aCharacter.
-     If encoding is nonNil, the file is assumed to be coded according to
-     that symbol, and #decodeString: should be able to convert it."
-
-    |text line enc|
-
-    text := StringCollection new.
-
-    enc := encoding.
-    enc == #iso8859 ifTrue:[
-        enc := nil
-    ].
-
-    aCharacter == Character cr ifTrue:[
-        [aStream atEnd] whileFalse:[
-            line := aStream nextLine withTabsExpanded.
-            enc notNil ifTrue:[
-                line := line decodeFrom:enc
-            ].
-            text add:line
-        ].
-    ] ifFalse:[
-        [aStream atEnd] whileFalse:[
-            line := (aStream upTo:aCharacter) withTabsExpanded.
-            enc notNil ifTrue:[
-                line := line decodeFrom:enc
-            ].
-            text add:line
-        ].
-    ].
-    ^ text
-
-    "Created: 22.2.1996 / 14:58:25 / cg"
-    "Modified: 2.4.1997 / 21:31:36 / cg"
-!
-
-showFile:fileName
-    "show contents of fileName in subView"
-
-    self showFile:fileName insert:false encoding:fileEncoding
-
-    "Modified: 22.2.1996 / 14:47:10 / cg"
-!
-
-showFile:fileName insert:insert encoding:encoding
-    "show/insert contents of fileName in subView"
-
-    ^ self 
-        showFile:fileName insert:insert encoding:encoding doubleClick:false
-
-    "Modified: 19.6.1996 / 09:40:19 / cg"
-!
-
-showFile:fileName insert:insert encoding:encoding doubleClick:viaDoubleClick
-    "show/insert contents of fileName in subView"
-
-    |buffer s n i ok convert text msg eol guess action enc|
-
-    ((currentDirectory typeOf:fileName) == #regular) ifFalse:[
-        "asked for a non-file  - ignore it ..."
-        (currentDirectory exists:fileName) ifFalse:[
-            msg := '''%1'' does not exist !!'.
-        ] ifTrue:[
-            msg := '''%1'' is not a regular file !!'.
-        ].
-        self warn:(resources string:msg with:fileName).
-        ^ self
-    ].
-
-    "/
-    "/ check if file is a text file
-    "/
-    s := FileStream readonlyFileNamed:fileName in:currentDirectory.
-    s isNil ifTrue:[
-        self showAlert:(resources string:'cannot read file ''%1'' !!' with:fileName)
-                  with:(FileStream lastErrorString).
-        ^ nil
-    ].
-
-    buffer := String new:300.
-    n := s nextBytes:300 into:buffer.
-    s close.
-
-    enc := encoding.
-    ok := true.
-    guess := self guessEncodingFrom:buffer.
-
-    guess == #binary ifTrue:[
-        ok := false.
-        viaDoubleClick ifTrue:[
-            (self binaryFileAction:fileName) ifTrue:[^ self].
-        ].
-        (self confirm:(resources string:'''%1'' seems to be a binary file - show anyway ?' with:fileName))
-        ifFalse:[^ self]
-    ] ifFalse:[
-        viaDoubleClick ifTrue:[
-            (self nonBinaryFileAction:fileName) ifTrue:[^ self].
-        ].
-
-        "/ ascii should work in any font ...
-
-        guess ~~ #ascii ifTrue:[
-            fileEncoding ~~ guess ifTrue:[
-                action := Dialog choose:(resources string:'''%1'' seems to be ' , guess , ' encoded.' with:fileName)
-                               labels:(resources array:#('cancel' 'show' 'change font'))
-                               values:#(nil #show #encoding)
-                               default:#encoding.
-                action isNil ifTrue:[^ self].
-                action == #encoding ifTrue:[
-                    fileEncoding := guess asSymbol.
-                    self validateFontEncodingFor:fileEncoding ask:false.
-                    enc := fileEncoding.
-                ]
-            ]    
-        ].
-    ].
-
-    convert := false.
-    ok ifTrue:[
-        "/
-        "/ check if line delimiter is a cr
-        "/
-        i := buffer indexOf:Character cr.
-        i == 0 ifTrue:[
-            "/
-            "/ no newline found - try cr
-            "/
-            i := buffer indexOf:(Character value:13).
-            i ~~ 0 ifTrue:[
-                convert := self confirm:(resources string:'''%1'' seems to have CR as line delimiter - convert to NL ?' with:fileName).
-            ]
-        ]
-    ].
-
-    insert ifFalse:[
-        "/ release old text first 
-        "/ - we might need the memory in case of huge files
-        "/  (helps if you have a 4Mb file in the view, 
-        "/   and click on another biggy)
-
-        subView contents:nil.
-    ].
-
-    convert ifTrue:[
-        eol := Character value:13
-    ] ifFalse:[
-        eol := Character cr
-    ].
-    text := self readFile:fileName lineDelimiter:eol encoding:enc.
-
-    insert ifFalse:[
-        self show:text
-    ] ifTrue:[
-        subView insertSelectedStringAtCursor:text asString
-    ].
-
-    "Created: 19.6.1996 / 09:39:52 / cg"
-    "Modified: 23.1.1997 / 20:31:43 / cg"
-!
-
-writeFile:fileName text:someText encoding:encoding
-    |stream msg startNr nLines string|
-
-    stream := FileStream newFileNamed:fileName in:currentDirectory.
-    stream isNil ifTrue:[
-        msg := (resources string:'cannot write file ''%1'' !!' with:fileName).
-        self showAlert:msg with:(FileStream lastErrorString)
-    ] ifFalse:[
-        someText isString ifTrue:[
-            stream nextPutAll:someText.
-        ] ifFalse:[
-            "
-             on some systems, writing linewise is very slow (via NFS)
-             therefore we convert to a string and write it in chunks
-             to avoid creating huge strings, we do it in blocks of 1000 lines
-            "
-            startNr := 1.
-            nLines := someText size.
-            [startNr <= nLines] whileTrue:[
-                string := someText asStringWithCRsFrom:startNr
-                                                    to:((startNr + 1000) min:nLines)
-                                          compressTabs:compressTabs.
-                encoding notNil ifTrue:[
-                    string := string encodeInto:encoding
-                ].
-                stream nextPutAll:string.
-                startNr := startNr + 1000 + 1.
-            ].
-"/                someText do:[:line |
-"/                  line notNil ifTrue:[
-"/                      stream nextPutAll:line.
-"/                  ].
-"/                  stream cr.
-"/              ]
-        ].
-        stream close.
-        subView modified:false
-    ]
-
-    "Created: 22.2.1996 / 15:03:10 / cg"
-    "Modified: 22.2.1996 / 15:08:31 / cg"
-! !
-
 !FileBrowser methodsFor:'queries'!
 
 path
@@ -3457,6 +3487,6 @@
 !FileBrowser class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libtool/FileBrowser.st,v 1.151 1997-04-21 13:03:56 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libtool/FileBrowser.st,v 1.152 1997-04-23 11:30:25 cg Exp $'
 ! !
 FileBrowser initialize!