"{ Package: 'stx:libtool' }"
AbstractFileBrowser subclass:#DirectoryContentsBrowser
instanceVariableNames:'browser updateDirectoryContentsTask modificationTime directory
columnDescriptors filterBlock iconIndex fileDescriptionIndex
iconExtent tableColumns sortBlock currentSortOrder previewIndex
allItemsList updateColumnsTask currentItemList wantSelectFiles
updateToExternFileHolderLock lastResponse oldDropItem oldItemIcon
updateTaskSema updateFromSensorTask'
classVariableNames:''
poolDictionaries:''
category:'Interface-Tools-File'
!
Object subclass:#DirectoryContentsItem
instanceVariableNames:'fileName fileInfo icon fileType link linkInfo
contentsBrowserChangeModificationTime isDirectory baseName suffix
preview group owner pathName permissions size timeAndDate date
lastButOneSuffix suffixes modificationTime modifiedByMe mimeType
iconKey'
classVariableNames:''
poolDictionaries:''
privateIn:DirectoryContentsBrowser
!
!DirectoryContentsBrowser class methodsFor:'documentation'!
documentation
"
DirectoryContentsBrowser openIn:'/home/ca/work/stx/goodies/bitmaps/xpmBitmaps'
DirectoryContentsBrowser openIn:'/home/ca/TEST'
"
! !
!DirectoryContentsBrowser class methodsFor:'instance creation'!
openIn:aDirectory
"opens a directory (standalone) for a directory
"
self openIn:aDirectory withDirectories:false
"
self openIn:(Filename currentDirectory construct:'.cvsignore')
"
!
openIn:aDirectory withDirectories:withDirectoriesBoolean
"opens a directory (standalone) for a directory
"
|browser|
browser := DirectoryContentsBrowser new.
browser open.
aDirectory notNil ifTrue:[
browser currentFileNameHolder value:(OrderedCollection with:(aDirectory asFilename))
].
browser viewDirectoriesInDirectoryContentsBrowser value:withDirectoriesBoolean.
^ browser
"
self openIn:(Filename currentDirectory asAbsoluteFilename) withDirectories:false
"
! !
!DirectoryContentsBrowser class methodsFor:'classAccess'!
itemClass
^ DirectoryContentsItem
"
self itemClass
"
! !
!DirectoryContentsBrowser class methodsFor:'constant'!
updateTaskPriority
"returns the priority of the update task
"
^ 8
! !
!DirectoryContentsBrowser class methodsFor:'interface specs'!
tableColumns
"This resource specification was automatically generated
by the DataSetBuilder of ST/X."
"Do not manually edit this!! If it is corrupted,
the DataSetBuilder may not be able to read the specification."
"
DataSetBuilder new openOnClass:DirectoryContentsBrowser andSelector:#tableColumns
"
<resource: #tableColumns>
^#(
#(#DataSetColumnSpec
#labelButtonType: #Group
#width: 22
#minWidth: 22
#height: 16
#model: #icon
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Filename'
#id: #filename
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortList:
#labelActionArgument: 'baseName'
#minWidth: 150
#model: #baseName
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Suffix'
#id: #suffix
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortList:
#labelActionArgument: 'suffix'
#width: 40
#model: #suffix
#canSelect: false
#isResizeable: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Perm'
#id: #perm
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortList:
#labelActionArgument: 'permissions'
#width: 75
#model: #permissions
#canSelect: false
#isResizeable: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Owner'
#id: #owner
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortList:
#labelActionArgument: 'owner'
#usePreferredWidth: true
#width: 50
#model: #owner
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Group'
#id: #group
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortList:
#labelActionArgument: 'group'
#usePreferredWidth: true
#width: 40
#model: #group
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Size'
#id: #size
#translateLabel: true
#labelAlignment: #right
#labelButtonType: #Button
#labelActionSelector: #sortList:
#labelActionArgument: 'size'
#columnAlignment: #right
#usePreferredWidth: true
#model: #sizeString
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Date & Time'
#id: #timeAndDate
#labelAlignment: #right
#labelButtonType: #Button
#labelActionSelector: #sortList:
#labelActionArgument: 'modificationTime'
#columnAlignment: #right
#usePreferredWidth: true
#width: 140
#model: #timeAndDate
#writeSelector: #date:
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'File Info'
#id: #fileInfo
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortList:
#labelActionArgument: 'fileType'
#width: 250
#model: #fileInfoString
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Pre +/-'
#id: #preview
#labelButtonType: #Button
#labelActionSelector: #doResizeImage
#labelActionArgument: ''
#columnAlignment: #center
#width: 45
#height: 16
#model: #preview
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
)
!
windowSpec
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this!! If it is corrupted,
the UIPainter may not be able to read the specification."
"
UIPainter new openOnClass:DirectoryContentsBrowser andSelector:#windowSpec
DirectoryContentsBrowser new openInterface:#windowSpec
DirectoryContentsBrowser open
"
<resource: #canvas>
^
#(#FullSpec
#name: #windowSpec
#window:
#(#WindowSpec
#label: 'Directory ContentsBrowser'
#name: 'Directory ContentsBrowser'
#min: #(#Point 10 10)
#max: #(#Point 1152 900)
#bounds: #(#Rectangle 723 276 1311 754)
#menu: #menu
)
#component:
#(#SpecCollection
#collection: #(
#(#DataSetSpec
#name: 'browser'
#layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
#model: #selectionInFileList
#menu: #directoryContentsBrowserMenu
#hasHorizontalScrollBar: true
#hasVerticalScrollBar: true
#miniScrollerHorizontal: false
#miniScrollerVertical: false
#dataList: #descriptions
#has3Dsepartors: false
#doubleClickSelector: #doubleClickedAt:
#columnHolder: #tableColumns
#multipleSelectOk: true
#verticalSpacing: 0
#columns:
#(#OrderedCollection
#(#DataSetColumnSpec
#labelButtonType: #Group
#width: 22
#minWidth: 22
#height: 16
#model: #icon
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'file name'
#labelAlignment: #left
#labelButtonType: #Button
#model: #baseName
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: '+/-'
#labelButtonType: #Button
#labelActionSelector: #doResizeImage
#labelActionArgument: ''
#columnAlignment: #center
#width: 30
#height: 16
#model: #preview
#canSelect: false
#showRowSeparator: false
#showSelectionHighLighted: false
#showColSeparator: false
)
)
#viewClassName: 'DirectoryContentsBrowser::Widget'
#postBuildCallback: #postBuildBrowser:
#properties:
#(#PropertyListDictionary
#dragArgument: #browser
#startDragSelector: #doStartDrag:in:
#displayObjectSelector: #getDisplayObjects:
#dropObjectSelector: #getDropObjects:
#dropArgument: #browser
#canDropSelector: #canDrop:argument:
#leaveSelector: #dropLeave:
#dropSelector: #doDrop:argument:
)
)
)
)
)
! !
!DirectoryContentsBrowser class methodsFor:'menu specs'!
directoryContentsBrowserMenu
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:DirectoryContentsBrowser andSelector:#directoryContentsBrowserMenu
(Menu new fromLiteralArrayEncoding:(DirectoryContentsBrowser directoryContentsBrowserMenu)) startUp
"
<resource: #menu>
^
#(#Menu
#(
#(#MenuItem
#label: 'Copy'
#translateLabel: true
#value: #doCopy
#shortcutKeyCharacter: #Copy
)
#(#MenuItem
#label: 'Cut'
#translateLabel: true
#value: #doCut
#shortcutKeyCharacter: #Cut
)
#(#MenuItem
#label: 'Paste'
#translateLabel: true
#value: #pasteFiles
#enabled: #canPaste
#shortcutKeyCharacter: #Paste
)
#(#MenuItem
#label: 'Delete'
#translateLabel: true
#nameKey: #delete
#value: #doDelete
#shortcutKeyCharacter: #Delete
)
#(#MenuItem
#label: 'Rename'
#translateLabel: true
#value: #renameSelection
#enabled: #hasSelection
#shortcutKeyCharacter: #Replace
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'View'
#translateLabel: true
#nameKey: #View
#submenuChannel: #viewBrowserMenu
)
#(#MenuItem
#label: 'Sort'
#translateLabel: true
#nameKey: #Sort
#submenuChannel: #sortMenu
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'New'
#translateLabel: true
#submenuChannel: #newMenu
)
#(#MenuItem
#label: 'Update'
#translateLabel: true
#value: #doUpdate
)
#(#MenuItem
#label: 'Properties...'
#translateLabel: true
#value: #doShowProperties
#enabled: #hasSelection
)
#(#MenuItem
#label: 'Others'
#submenu:
#(#Menu
#(
#(#MenuItem
#label: 'File In'
#translateLabel: true
#value: #fileFileIn
#enabled: #hasSelection
#shortcutKeyCharacter: #Accept
)
#(#MenuItem
#label: 'File in to NameSpace...'
#translateLabel: true
#value: #fileFileInToNameSpace
#enabled: #hasSelection
)
#(#MenuItem
#label: 'Directory Up'
#translateLabel: true
#value: #doGoDirectoryUp
#enabled: #enableDirectoryUp
#shortcutKeyCharacter: #CursorLeft
)
#(#MenuItem
#label: 'Open in TextEditor'
#translateLabel: true
#value: #doShowFileContents
#enabled: #hasSelection
)
#(#MenuItem
#label: 'Select All'
#translateLabel: true
#value: #doSelectAll
)
#(#MenuItem
#label: 'Copy File List'
#translateLabel: true
#value: #copyFileList
#enabled: #fileListIsNotEmpty
)
)
nil
nil
)
)
)
nil
nil
)
!
viewBrowserMenu
"This resource specification was automatically generated
by the MenuEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the MenuEditor may not be able to read the specification."
"
MenuEditor new openOnClass:DirectoryContentsBrowser andSelector:#viewBrowserMenu
(Menu new fromLiteralArrayEncoding:(DirectoryContentsBrowser viewBrowserMenu)) startUp
"
<resource: #menu>
^
#(#Menu
#(
#(#MenuItem
#label: 'View Details'
#translateLabel: true
#hideMenuOnActivated: false
#indication: #viewDetails
)
#(#MenuItem
#label: 'View Suffix'
#translateLabel: true
#hideMenuOnActivated: false
#enabled: #viewDetails
#indication: #viewType
)
#(#MenuItem
#label: 'View Permissions'
#translateLabel: true
#hideMenuOnActivated: false
#enabled: #viewDetails
#indication: #viewPermissions
)
#(#MenuItem
#label: 'View Owner'
#translateLabel: true
#hideMenuOnActivated: false
#enabled: #viewDetails
#indication: #viewOwner
)
#(#MenuItem
#label: 'View Group'
#translateLabel: true
#hideMenuOnActivated: false
#enabled: #viewDetails
#indication: #viewGroup
)
#(#MenuItem
#label: 'View Size'
#translateLabel: true
#hideMenuOnActivated: false
#enabled: #viewDetails
#indication: #viewSize
)
#(#MenuItem
#label: 'View Date && Time'
#translateLabel: true
#hideMenuOnActivated: false
#enabled: #viewDetails
#indication: #viewTime
)
#(#MenuItem
#label: 'View File Info'
#translateLabel: true
#hideMenuOnActivated: false
#enabled: #viewDetails
#indication: #viewDescription
)
#(#MenuItem
#label: 'View Preview'
#translateLabel: true
#hideMenuOnActivated: false
#enabled: #viewDetails
#indication: #viewPreview
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Show Hidden Files'
#translateLabel: true
#indication: #showHiddenFiles
)
)
nil
nil
)
! !
!DirectoryContentsBrowser methodsFor:'accessing'!
columnDescriptors
"get the column description
"
^ columnDescriptors
!
columnDescriptors:aListOfColumns
"set the column description
"
columnDescriptors = aListOfColumns ifTrue:[
^ self
].
columnDescriptors := OrderedCollection new.
previewIndex := 0.
iconIndex := 0.
fileDescriptionIndex := 0.
iconExtent := nil.
aListOfColumns keysAndValuesDo:[:anIndex :aDesc| |col|
col := aDesc isSequenceable ifTrue:[DataSetColumnSpec new fromLiteralArrayEncoding:aDesc]
ifFalse:[aDesc].
columnDescriptors add:col.
col readSelector == #preview ifTrue:[
previewIndex := anIndex.
iconExtent := Point x:(col width) y:(col height).
] ifFalse:[
col readSelector == #fileInfoString ifTrue:[
fileDescriptionIndex := anIndex.
] ifFalse:[
col readSelector == #icon ifTrue:[
iconIndex := anIndex.
]
]
]
].
!
directory
"returns the current directory or nil
"
^ directory
!
directory:aDirectory
"change the current directory and read the items
"
directory := aDirectory.
self readDirectory.
!
filterBlock
"return the value of the instance variable 'filterBlock' (automatically generated)"
^ filterBlock
!
filterBlock:something
"set the value of the instance variable 'filterBlock' (automatically generated)"
filterBlock := something.
!
oldChangedIcon
oldItemIcon isNil ifTrue:[
oldItemIcon := Association new.
].
^ oldItemIcon
!
oldItemIcon
oldItemIcon isNil ifTrue:[
oldItemIcon := Association new.
].
^ oldItemIcon
!
sortBlock
sortBlock isNil ifTrue:[
self sortBlock:[ : a : b |
self sortCaseless value ifTrue:[
a asString asLowercase < b asString asLowercase.
] ifFalse:[
a asString < b asString.
]
].
].
^ sortBlock
!
sortBlock:aSortBlock
" sort directories before files anyway "
sortBlock := [:a :b|
| res |
(self viewDirectoriesInDirectoryContentsBrowser
and:[(a isDirectory == b isDirectory) not]) ifTrue:[
res := a isDirectory
] ifFalse:[
res := aSortBlock value:a value:b.
].
res
].
^ sortBlock
!
updateColumnsTask
"return the value of the instance variable 'updateColumnsTask' (automatically generated)"
^ updateColumnsTask
!
updateColumnsTask:something
"set the value of the instance variable 'updateColumnsTask' (automatically generated)"
updateColumnsTask := something.
!
updateDirectoryContentsTask
"return the value of the instance variable 'updateDirectoryContentsTask' (automatically generated)"
^ updateDirectoryContentsTask
!
updateDirectoryContentsTask:something
"set the value of the instance variable 'updateDirectoryContentsTask' (automatically generated)"
updateDirectoryContentsTask := something.
!
updateToExternFileHolderLock
"return the value of the instance variable 'updateToExternFileHolder' (automatically generated)"
updateToExternFileHolderLock isNil ifTrue:[
updateToExternFileHolderLock := self class newLock.
].
^ updateToExternFileHolderLock
! !
!DirectoryContentsBrowser methodsFor:'actions'!
doResizeImage
|column w h|
previewIndex == 0 ifTrue:[^ self].
column := columnDescriptors at:previewIndex.
w := iconExtent x.
h := iconExtent y.
w == column width ifTrue:[
w := w * 2.
h := h * 2.
].
column width:w.
column height:h.
self updateColumnsTaskStop.
self descriptions do:[:el| el resetImageFile ].
browser columnDescriptors:columnDescriptors.
self updateColumnsTaskStart.
!
doUpdate
modificationTime := nil.
self updateDirectoryContentsTaskRestart.
!
doubleClickedAt:anIndex
|item|
item := self descriptions at:anIndex ifAbsent:nil.
self withWaitCursorDo:[
self enterActionFor:item.
]
!
enterActionFor:anItem
| filename|
filename := anItem fileName.
filename = '..' asFilename ifTrue:[
self currentFileNameHolder value:(OrderedCollection with:(self directory directory)).
^ self.
].
(anItem isRemoteDirectory
or:[filename isDirectory]) ifTrue:[
self currentFileNameHolder value:(OrderedCollection with:filename).
^ self.
].
self openApplByFileItem:anItem.
!
selectFileName:aColOfFilenames
| indexInDescriptions curSel descr index|
descr := self descriptions.
indexInDescriptions := OrderedCollection new.
aColOfFilenames do:[ : file |
index := descr findFirst:[: item |
item fileName = file.
].
index ~= 0 ifTrue:[
indexInDescriptions add:index.
]
].
curSel := self selectionInFileList value.
curSel = indexInDescriptions ifTrue:[
^ self.
].
self selectionInFileList value:indexInDescriptions withoutNotifying:self.
! !
!DirectoryContentsBrowser methodsFor:'aspects'!
descriptions
^ self browserFileList
!
descriptions:aCol
| showDir|
self updateColumnsTaskStop. "/ dont access rows while rows changed
self updateToExternFileHolderLock doLocked:[
aCol isEmpty ifTrue:[
self descriptions contents:aCol.
] ifFalse:[
showDir := self viewDirectoriesInDirectoryContentsBrowser value.
(showDir and:[self directory isRootDirectory not]) ifTrue:[
aCol addFirst:(DirectoryContentsItem with:('..' asFilename)).
].
self descriptions contents:aCol.
].
].
self updateColumnsTaskStart.
wantSelectFiles notNil ifTrue:[
self selectFileName:wantSelectFiles.
].
!
tableColumns
"automatically generated by UIPainter ..."
"*** the code below creates a default model when invoked."
"*** (which may not be the one you wanted)"
"*** Please change as required and accept it in the browser."
"*** (and replace this comment by something more useful ;-)"
tableColumns isNil ifTrue:[
tableColumns := self class tableColumns asValue.
"/ if your app needs to be notified of changes, uncomment one of the lines below:
"/ tableColumns addDependent:self.
"/ tableColumns onChangeSend:#tableColumnsChanged to:self.
].
^ tableColumns.
! !
!DirectoryContentsBrowser methodsFor:'change & update'!
fileNamesChanged:aColOfFiles
"filename changed
"
| newDir currentDir colDirectories|
wantSelectFiles := aColOfFiles. "/ set the file to the current filename to change selection if update process have added the list
aColOfFiles isEmpty ifTrue:[
self directory:nil.
^ self
].
colDirectories := self getDirectoriesForFileList:aColOfFiles.
colDirectories asSet size > 1 ifTrue:[
self directory:nil.
^ self
].
newDir := colDirectories first.
currentDir := self directory.
newDir = currentDir ifTrue:[
self selectFileName:aColOfFiles.
^ self.
] ifFalse:[
"/ change of the directory filename
self directory:newDir.
].
!
filterChanged
self filterBlock: [: el | (self showHiddenFiles value ifFalse:[
(el asString startsWith:'.') not])
and:[self filterModel value match:el]].
self evaluateFilter.
!
update:something with:aParameter from:aModel
"one of my models changed
"
| selection window sensor|
aModel == self filterModel ifTrue:[
self filterChanged.
^ self.
].
aModel == self sortBlockHolder ifTrue:[
self sortList:(self sortBlockHolder value) withReverse:false.
^ self.
].
aModel == self currentFileNameHolder ifTrue:[
window := self window.
window ifNotNil:[
sensor := window sensor.
sensor ifNotNil:[
sensor flushUserEventsFor:self withType:#updateFromModel.
sensor pushUserEvent:#updateFromModel for:self.
^ self
].
].
self fileNamesChanged:aModel value.
" do not return here because the AbstractFileBrowserComponent have to do something
for every application "
"/ ^ self.
].
aModel == self sortCaseless ifTrue:[
^ self sortList:#baseName withReverse:false.
].
aModel == self selectionInFileList ifTrue:[
self updateToExternFileHolderLock doIfUnLocked:[
self directory isNil ifTrue:[^ self].
selection := self getSelectedFiles.
selection isEmpty ifTrue:[
self currentFileNameHolder value:(OrderedCollection with:self directory) withoutNotifying:self.
] ifFalse:[
wantSelectFiles := selection.
self currentFileNameHolder value:selection withoutNotifying:self.
].
].
^ self.
].
aModel == self viewDirectoriesInDirectoryContentsBrowser ifTrue:[
self evaluateFilter.
^ self
].
super update:something with:aParameter from:aModel
!
updateFromModel
||
updateTaskSema isNil ifTrue:[
[
updateTaskSema isNil ifTrue:[
updateTaskSema := Semaphore forMutualExclusion.
].
] valueUninterruptably
].
updateTaskSema critical:[
self updateFromSensorTaskStop.
updateFromSensorTask := Process for:[ |window sensor|
[
window := self window.
window ifNotNil:[
sensor := window sensor.
sensor ifNotNil:[
sensor flushUserEventsFor:self withType:#updateFromModel.
].
].
self fileNamesChanged:(self currentFileNameHolder value).
] valueNowOrOnUnwindDo:[
updateFromSensorTask := nil
].
] priority:8.
updateFromSensorTask resume.
updateTaskSema signal.
].
!
updateFromSensorTaskStop
|task|
(task := updateFromSensorTask) notNil ifTrue:[
updateFromSensorTask := nil.
Object errorSignal handle:[:ex|
Dialog warn:ex description.
]do:[
task isDead ifFalse:[
task terminateWithAllSubprocesses.
task waitUntilTerminated.
]
]
].
!
viewedColumnsChanged
| columns buffer |
columns := OrderedCollection new.
self class tableColumns do:[:el|
columns add:(DataSetColumnSpec new fromLiteralArrayEncoding:el).
].
buffer := columns copy.
self viewDetails value = false ifTrue:[
browser showLabels:false.
buffer do:[:col |
(col readSelector = #baseName or:[col readSelector = #icon]) ifFalse:[
columns remove:col.
]
]
] ifFalse:[
browser showLabels:true.
buffer do:[:col |
| id |
id := col id.
id notNil ifTrue:[
(id == #filename) ifTrue:[
self viewType value ifTrue:[
col readSelector:#baseNameWithOutSuffix
] ifFalse:[
col readSelector:#baseName
].
] ifFalse:[
(id == #suffix and:[self viewType value not]) ifTrue:[
columns remove:col.
] ifFalse:[
(id == #group and:[self viewGroup value not]) ifTrue:[
columns remove:col.
] ifFalse:[
(id == #owner and:[self viewOwner value not]) ifTrue:[
columns remove:col.
] ifFalse:[
(id == #perm and:[self viewPermissions value not]) ifTrue:[
columns remove:col.
] ifFalse:[
(id == #preview and:[self viewPreview value not]) ifTrue:[
columns remove:col.
] ifFalse:[
(id == #size and:[self viewSize value not]) ifTrue:[
columns remove:col.
] ifFalse:[
(id == #timeAndDate and:[self viewTime value not]) ifTrue:[
columns remove:col.
] ifFalse:[
(id == #fileInfo and:[self viewDescription value not]) ifTrue:[
columns remove:col.
]
]
]
]
]
]
]
]
]
]
]
].
self tableColumns value:columns.
self columnDescriptors:(self tableColumns value).
! !
!DirectoryContentsBrowser methodsFor:'directory contents'!
evaluateFilter
| showDir|
showDir := self viewDirectoriesInDirectoryContentsBrowser value.
currentItemList := OrderedCollection new.
allItemsList size ~~ 0 ifTrue:[
self filterBlock isNil ifTrue:[
allItemsList do:[:aItem |
(showDir not and:[aItem isDirectory]) ifFalse:[
currentItemList add:aItem
]
]
] ifFalse:[
allItemsList do:[:aItem |
(showDir not and:[aItem isDirectory]) ifFalse:[
(self filterBlock value:aItem baseName) ifTrue:[currentItemList add:aItem].
]
]
].
].
self evaluateSortBlock.
!
evaluateSortBlock
| newList|
newList := SortedCollection sortBlock:(self sortBlock).
newList addAll:currentItemList.
self descriptions:(newList asList).
!
readDirectory
self updateDirectoryContentsTaskStop.
allItemsList := self readDirectoryItems.
self evaluateFilter. "/ filter makes a sort anyway
self updateDirectoryContentsTaskStart.
!
readDirectoryItems
|dir list mountPoints mountInfo|
mountPoints := OperatingSystem mountPoints.
dir := self directory.
list := OrderedCollection new.
dir notNil ifTrue:[
modificationTime := dir modificationTime.
dir directoryContentsAsFilenamesDo:[:eachFileOrDirectory |
mountInfo := mountPoints detect:[:mInfo | mInfo mountPointPath = eachFileOrDirectory name] ifNone:nil.
(mountInfo notNil and:[mountInfo isRemote]) ifTrue:[
list add:(DirectoryContentsItem withRemoteDirectory:eachFileOrDirectory).
] ifFalse:[
list add:(DirectoryContentsItem with:eachFileOrDirectory).
].
].
].
^ list
! !
!DirectoryContentsBrowser methodsFor:'drag & drop'!
canDrop:aContext argument:arg2
| dir archivListDrop source lineNr destinationItem dropToFile|
dir := self directory.
dir isNil ifTrue:[ ^ false].
source := aContext dropSource.
source isNil ifTrue:[ ^ false].
archivListDrop := (source argument == #archivApplication).
lineNr := self getLineNumberFor:aContext.
lineNr notNil ifTrue:[
destinationItem := self descriptions at:lineNr.
].
destinationItem isNil ifTrue:[
oldDropItem notNil ifTrue:[
self enqueueChangeDraggedItem:nil with:aContext.
oldDropItem := nil.
].
dropToFile := self directory.
] ifFalse:[
dropToFile := destinationItem fileName.
].
(destinationItem ~~ oldDropItem) ifTrue:[
oldDropItem := destinationItem.
self enqueueChangeDraggedItem:nil with:aContext.
(destinationItem notNil and:[destinationItem isDirectory]) ifTrue:[
self enqueueChangeDraggedItem:destinationItem with:aContext.
].
archivListDrop ifTrue:[
lastResponse := self canDropArchiv:(aContext dropObjects) for:dropToFile.
] ifFalse:[
lastResponse := self canDropFiles:(aContext dropObjects) for:dropToFile.
]
].
^ lastResponse
!
changeDraggedItem:anItem with:aDropContext
self changeDraggedItem:anItem with:aDropContext saveDraw:true
!
changeDraggedItem:anItem with:aDropContext saveDraw:saveDraw
saveDraw ifTrue:[
aDropContext saveDraw:[
self changeIconFor:anItem.
self windowGroup processExposeEvents
]
] ifFalse:[
self changeIconFor:anItem.
self windowGroup processExposeEvents
]
!
changeIconFor:anItemOrNil
|icon oldItem|
oldItem := self oldItemIcon.
(anItemOrNil isNil or:[(oldItem key) ~~ anItemOrNil]) ifTrue:[
(oldItem notNil and:[oldItem key notNil]) ifTrue:[
icon := oldItem value.
icon notNil ifTrue:[
oldItem key icon:(oldItem value).
browser invalidateVisibleRow:(oldItem key) colAt:iconIndex
].
].
oldItem key:anItemOrNil.
anItemOrNil notNil ifTrue:[
oldItem value:(anItemOrNil icon).
icon := FileBrowser iconForKeyMatching:#directoryOpenGray.
icon notNil ifTrue:[
anItemOrNil icon:icon.
browser invalidateVisibleRow:anItemOrNil colAt:iconIndex
].
].
].
!
doDrop:aContext
|col answer destinationPath source receiver lineNr destinationItem|
source := aContext dropSource.
lineNr := self getLineNumberFor:aContext.
lineNr notNil ifTrue:[
destinationItem := self descriptions at:lineNr.
].
destinationItem isNil ifTrue:[
destinationPath := self directory.
] ifFalse:[
destinationPath := self getDirWithoutFileName:(destinationItem fileName).
].
source argument == #archivApplication ifTrue:[
receiver := source receiver.
receiver extractSelectedFilesTo:destinationPath askForExtractOptions:true.
^ true.
].
col := OrderedCollection new.
aContext dropObjects do:[:obj|
col add:(obj theObject).
].
answer := self copyOrMoveDialog:col.
answer == #copy ifTrue:[
"/ copy files
self copyFiles:col to:destinationPath.
].
answer == #move ifTrue:[
"/ copy files
self moveFiles:col to:destinationPath.
].
^ true
!
doDrop:aContext argument:arg2
| aBoolean |
aBoolean := self doDrop:aContext.
self dropLeave:aContext.
^ aBoolean.
!
doStartDrag:aDropSource in:aView
"set the cursors before starting the drag & drop operation
"
|sel|
sel := self selectionInFileList value.
((((self descriptions at:(sel first)) fileName) = ('..' asFilename)) and:[ sel size == 1 ]) ifTrue:[
^ self.
].
super doStartDrag:aDropSource in:aView
!
dropLeave:aDropContext
oldDropItem := nil.
self changeDraggedItem:nil with:aDropContext saveDraw:false.
lastResponse := nil.
!
enqueueChangeDraggedItem:anItem with:aContext
self enqueueMessage:#'changeDraggedItem:with:' for:self arguments:(Array with:anItem with:aContext)
!
getDisplayObjects:anArgument
| sel string size fnName stream|
sel := self selectionInFileList value.
(((self descriptions at:(sel first)) fileName) = ('..' asFilename)) ifTrue:[
sel removeFirst.
].
size := sel size.
size == 0 ifTrue:[^ ''].
stream := WriteStream on:''.
stream nextPutAll:(self descriptions at:sel first) fileName baseName asString.
size == 1 ifTrue:[
fnName := 'ui_menuitem.xpm'.
] ifFalse:[
fnName := 'ui_submenu_open.xpm'.
stream nextPutAll:' ... '.
stream nextPutAll:(self descriptions at:sel last) fileName baseName asString.
].
string := stream contents.
stream close.
^ Array with:(LabelAndIcon icon:(Image fromFile:fnName)
string:(Text string:string emphasis:#bold)
)
!
getDropObjects:anArgument
| sel ret file|
sel := self selectionInFileList value.
ret := sel collect:[:el|
file := (self descriptions at:el) fileName.
file ~= '..' asFilename ifTrue:[
DropObject newFile:((self descriptions at:el) fileName)
]
].
^ ret
!
getLineNumberFor:aDropContext
| yVisible|
yVisible := (aDropContext targetPoint y).
^ browser yVisibleToRowNr:yVisible.
! !
!DirectoryContentsBrowser methodsFor:'event handling'!
processEvent:anEvent
"filter keyboard events.
Return true, if I have eaten the event"
|focusView key rawKey|
anEvent isKeyPressEvent ifTrue:[
focusView := anEvent targetView.
key := anEvent key.
rawKey := anEvent rawKey.
(focusView == browser) ifTrue:[
"/ (key ~= #'Alt_L') ifTrue:[self halt.].
key == #Paste ifTrue:[
self pasteFiles.
^ true.
].
(key == #CursorLeft) ifTrue:[
self doGoDirectoryUp.
^ true
].
(key == #CursorRight) ifTrue:[
self doBack.
^ true
].
self descriptions size == 0 ifTrue:[
^ false
].
key == #Copy ifTrue:[
self doCopy.
^ true.
].
(key == #Return) ifTrue:[
self doOpenSelectedFile.
^ true.
].
key == #Delete ifTrue:[
self doDelete.
^ true.
].
key == #Cut ifTrue:[
self doCut.
^ true.
].
]
].
^ false
! !
!DirectoryContentsBrowser methodsFor:'file actions'!
doCopy
"copy current selected files/directories
"
self copyFilesToClipBoard:(self getFilesFromSelection).
!
doCut
"cut current selected files/directories
"
self cutFilesToClipBoard:(self getFilesFromSelection).
!
doDelete
"delete current selected files/directories
"
self deleteFiles:(self getFilesFromSelection).
! !
!DirectoryContentsBrowser methodsFor:'menu accessing'!
viewBrowserMenu
<resource: #programMenu >
|menu|
menu := Menu new fromLiteralArrayEncoding:self class viewBrowserMenu.
menu ifNil:[ ^ nil ].
menu receiver:self.
^ menu
! !
!DirectoryContentsBrowser methodsFor:'menu actions'!
doOpenSelectedFile
| sel index item|
sel := self selectionInFileList value.
(sel notNil and:[sel notEmpty]) ifTrue:[
index := sel first.
item := self descriptions at:index ifAbsent:nil.
self enterActionFor:item.
].
!
doSelectAll
| sel |
sel := OrderedCollection new.
self descriptions keysAndValuesDo:[:index :value |
(index == 1 and:[(value fileName asString = '..')]) ifFalse:[
sel add:index.
]
].
self selectionInFileList value:sel.
!
doShowFileContents
| sel index item|
sel := self selectionInFileList value.
(sel notNil and:[sel notEmpty]) ifTrue:[
index := sel first.
item := self descriptions at:index ifAbsent:nil.
self openTextEditorOn:item.
].
! !
!DirectoryContentsBrowser methodsFor:'queries'!
allItemsOfCurrentDirectory
^ self descriptions.
!
fileListIsEmpty
^ self descriptions isEmpty
!
getAllFilesAsStringCollection
|files items|
items := self descriptions.
files := OrderedCollection new.
items isEmpty ifTrue:[
^ files
].
items do:[:aItem |
aItem isDirectory not ifTrue:[
files add:aItem fileName asString
].
].
^ files.
!
getFileItemsFromSelection
|indices files|
indices := self selectionInFileList value.
files := OrderedCollection new.
(indices isNil or:[indices isEmpty]) ifTrue:[
^ files
].
indices do:[:i |
|item|
item := self descriptions at:i.
item isDirectory not ifTrue:[
files add:item
]
].
^ files.
!
getFirstItemFromSelection
|indices|
indices := self selectionInFileList value.
(indices isNil or:[indices isEmpty]) ifTrue:[
^ nil
].
^ self descriptions at:(indices first).
!
getItemsFromSelection
|indices items|
indices := self selectionInFileList value.
items := OrderedCollection new.
(indices isNil or:[indices isEmpty]) ifTrue:[
^ items
].
indices do:[:i |
|filename|
items add:(self descriptions at:i)
].
^ items.
!
getSelectedFiles
|indices files|
indices := self selectionInFileList value.
files := OrderedCollection new.
(indices isNil or:[indices isEmpty]) ifTrue:[
^ files
].
indices do:[:i |
|filename|
filename := (self descriptions at:i) fileName.
filename asString ~= '..' ifTrue:[
files add:(self descriptions at:i) fileName
]
].
^ files.
! !
!DirectoryContentsBrowser methodsFor:'sorting'!
sortList:instanceName
self sortList:instanceName withReverse:true.
!
sortList:instanceName withReverse:aBoolean
| aSymbol cmpOp sortCaselessLocal|
aSymbol := instanceName asSymbol.
sortCaselessLocal := self sortCaseless value.
currentSortOrder isNil ifTrue:[
currentSortOrder := aSymbol, sortCaselessLocal asString.
currentSortOrder := Dictionary new.
currentSortOrder at:#column put:aSymbol.
currentSortOrder at:#reverse put:false.
currentSortOrder at:#sortCaseless put:sortCaselessLocal.
] ifFalse:[
(currentSortOrder at:#sortCaseless) ~= sortCaselessLocal ifTrue:[
"/ sort caseless changed
currentSortOrder at:#sortCaseless put:sortCaselessLocal.
] ifFalse:[
(currentSortOrder at:#column) = aSymbol ifTrue:[
"/ same column like before - change sort order ifReverse is true
aBoolean ifTrue:[
| isReverse |
isReverse := currentSortOrder at:#reverse.
currentSortOrder at:#reverse put:(isReverse not).
].
] ifFalse:[
"/ another column - remark column
currentSortOrder at:#column put:aSymbol.
]
]
].
(currentSortOrder at:#reverse) ifTrue:[
cmpOp := #'>'
] ifFalse:[
cmpOp := #'<'
].
self sortBlock: [:a :b |
|entry1 entry2|
entry1 := (a perform:aSymbol).
entry2 := (b perform:aSymbol).
((entry1 isNil) or:[entry2 isNil]) ifTrue:[
((entry1 isNil) and:[entry2 isNil]) ifTrue:[true] ifFalse:[
((entry1 notNil) and:[entry2 isNil]) ifTrue:[
(currentSortOrder at:#reverse)
].
(currentSortOrder at:#reverse) not
]
] ifFalse:[
(aSymbol = #baseName) ifTrue:[
sortCaselessLocal ifTrue:[
entry1 := entry1 asString asLowercase.
entry2 := entry2 asString asLowercase.
] ifFalse:[
entry1 := entry1 asString.
entry2 := entry2 asString.
].
].
entry1 perform:cmpOp with:entry2
]
].
self sortBlockHolder value:instanceName.
self evaluateSortBlock.
! !
!DirectoryContentsBrowser methodsFor:'startup / release'!
makeDependent
self currentFileNameHolder addDependent:self.
self viewDirectoriesInDirectoryContentsBrowser addDependent:self.
self filterModel addDependent:self.
self sortBlockHolder addDependent:self.
self selectionInFileList addDependent:self.
self sortCaseless addDependent:self.
self viewDescription onChangeSend:#viewedColumnsChanged to:self.
self viewDetails onChangeSend:#viewedColumnsChanged to:self.
self viewGroup onChangeSend:#viewedColumnsChanged to:self.
self viewOwner onChangeSend:#viewedColumnsChanged to:self.
self viewPermissions onChangeSend:#viewedColumnsChanged to:self.
self viewPreview onChangeSend:#viewedColumnsChanged to:self.
self viewSize onChangeSend:#viewedColumnsChanged to:self.
self viewTime onChangeSend:#viewedColumnsChanged to:self.
self viewType onChangeSend:#viewedColumnsChanged to:self.
self showHiddenFiles onChangeSend:#filterChanged to:self.
!
postBuildBrowser:aWidget
browser := aWidget scrolledView.
browser wantsFocusWithPointerEnter.
"/ dont register icons anymore
"/ FileBrowser icons keysAndValuesDo:[:aKey :anIcon|
"/ browser registerImage:anIcon key:aKey.
"/ ].
self columnDescriptors:(self class tableColumns).
!
postBuildWith:aBuilder
self viewedColumnsChanged.
self filterChanged.
^ super postBuildWith:aBuilder.
!
postOpenAsSubcanvasWith:aBuilder
self windowGroup addPreEventHook:self.
^ super postOpenAsSubcanvasWith:aBuilder.
!
postOpenWith:aBuilder
"
only invoked if the application not started from a master
"
self currentFileNameHolder changed.
self windowGroup addPreEventHook:self.
^ super postOpenWith:aBuilder.
!
preBuildWith:aBuilder
self masterApplication isNil ifTrue:[
self masterApplication:nil.
].
^ super preBuildWith:aBuilder.
!
release
"release my resources
"
self updateColumnsTaskStop.
self updateDirectoryContentsTaskStop.
self updateFromSensorTaskStop.
super release.
!
releaseAsSubCanvas
self updateColumnsTaskStop.
self updateDirectoryContentsTaskStop.
^ super releaseAsSubCanvas.
! !
!DirectoryContentsBrowser methodsFor:'task update columns'!
findNextBuildInDescFor:aBlock
|vis idx|
vis := browser indexOfFirstRowShown.
vis = 0 ifTrue:[vis := 1].
idx := self descriptions findFirst:aBlock startingAt:vis.
idx == 0 ifTrue:[
(idx := self descriptions findLast:aBlock startingAt:(vis - 1)) == 0 ifTrue:[
^ nil
]
].
^ self descriptions at:idx ifAbsent:nil
!
findNextItemFor:aBlock
^ allItemsList detect:aBlock ifNone:[nil].
!
getFileInfoFor:aItem
| type|
type := aItem fileName fileType.
aItem fileType:type.
^ type
!
getIconFor:aItem
| key icon|
key := aItem iconKey.
icon := FileBrowser iconForKeyMatching:key.
aItem isRemoteDirectory ifTrue:[
^ icon "/ do not query attributes
].
^ FileBrowser addOnIconsFor:(aItem fileName) to:icon.
!
getIconForMimeTypeByContents:aItem
| currentIcon newIcon icon|
newIcon := FileBrowser iconForKeyMatching:(aItem mimeTypeForContents).
currentIcon := aItem icon.
(currentIcon class == MultiImage) ifTrue:[
| images |
images := currentIcon images.
images removeFirst.
images addFirst:newIcon.
icon := currentIcon.
] ifFalse:[
icon := newIcon.
].
^ icon
!
getPreviewFor:aItem
| column icon|
column := browser columnAt:previewIndex.
column isNil ifTrue:[
previewIndex := 0.
] ifFalse:[
(aItem hasMimeType and:[aItem mimeType isImage]) ifTrue:[
Exception handle:[:ex|
icon := nil.
] do:[ |scale extent w h |
icon := Image fromFile:(aItem pathName).
icon notNil ifTrue:[
extent := icon extent.
w := column width - 4.
h := column height.
(extent x > w or:[extent y > h]) ifTrue:[
scale := extent / (w@h).
scale := scale x max:(scale y).
icon := icon magnifiedTo:((extent / scale max:8.0) asInteger).
].
icon := icon onDevice:(browser device).
icon clearMaskedPixels.
]
]
] ifFalse:[ icon := nil].
aItem preview:(icon ? '').
].
^ icon
!
updateChangesFor:aItem
aItem modifiedByMe ifTrue:[
aItem modifiedByMe:false.
] ifFalse:[
self notifyChannel value:aItem fileName asString, ' was changed by someone else'.
aItem resetItemForChangesFromSomeOneElse.
].
!
updateColumnsTaskCycle
" update items in the foolowing order
- update item if item properties are changed
- update icon for visible items by suffix
- update icon for visible items by contents
- update file info for visible items if file info column is shown
- update preview for visible items if preview column is shown
- update icon for invisible items by suffix
- update icon for invisible items by contents
- update file info for invisible items if file info column is shown
- update preview for invisible items if preview column is shown
- update file info for invisible items if file info column is not shown
"
|desc icon type preview|
currentItemList notEmpty ifTrue:[
"/ update item if item properties are changed
desc := self findNextBuildInDescFor:[:n| n changedForDirectoryContentsBrowser ].
desc notNil ifTrue:[
browser invalidateVisibleRow:desc.
self updateChangesFor:desc.
^ true.
].
"/ update icon for visible items by suffix
desc := self findNextBuildInDescFor:[:n| n icon isNil ].
desc notNil ifTrue:[
icon := self getIconFor:desc.
desc icon:icon.
(icon notNil and:[iconIndex ~~ 0]) ifTrue:[
browser invalidateVisibleRow:desc colAt:iconIndex
].
^ true
].
"/ update icon for visible items by contents
desc := self findNextBuildInDescFor:[:n|
(n iconKey == #file
and:[n mimeTypeForContents asSymbol ~= #unknown])
].
desc notNil ifTrue:[
icon := self getIconForMimeTypeByContents:desc.
desc icon:icon.
(icon notNil and:[iconIndex ~~ 0]) ifTrue:[
browser invalidateVisibleRow:desc colAt:iconIndex
].
^ true
].
"/ update file info for visible items if file info column is shown
fileDescriptionIndex ~~ 0 ifTrue:[
desc := self findNextBuildInDescFor:[:n| n fileType isNil ].
desc notNil ifTrue:[
type := self getFileInfoFor:desc.
type notNil ifTrue:[browser invalidateVisibleRow:desc colAt:fileDescriptionIndex].
^ true
]
].
"/ update preview for visible items if preview column is shown
previewIndex ~~ 0 ifTrue:[
desc := self findNextBuildInDescFor:[:n| n preview isNil ].
desc notNil ifTrue:[
preview := self getPreviewFor:desc.
preview notNil ifTrue:[
browser invalidateVisibleRow:desc colAt:previewIndex
].
^ true
]
].
].
"/ may we want to see the other items later make this items to
allItemsList notEmpty ifTrue:[
"/ update icon for invisible items by suffix
desc := self findNextItemFor:[:n| n icon isNil ].
desc notNil ifTrue:[
icon := self getIconFor:desc.
desc icon:icon.
^ true
].
"/ update icon for invisible items by contents
desc := self findNextItemFor:[:n| (n iconKey == #file and:[n mimeTypeForContents ~= #unknown])].
desc notNil ifTrue:[
icon := self getIconForMimeTypeByContents:desc.
desc icon:icon.
^ true
].
"/ update file info for invisible items if file info column is shown
fileDescriptionIndex ~~ 0 ifTrue:[
desc := self findNextItemFor:[:n| n fileType isNil ].
desc notNil ifTrue:[
self getFileInfoFor:desc.
^ true
].
].
"/ update preview for invisible items if preview column is shown
previewIndex ~~ 0 ifTrue:[
desc := self findNextItemFor:[:n| n preview isNil ].
desc notNil ifTrue:[
self getPreviewFor:desc.
^ true
].
].
"/ update file info for invisible items if file info column is not shown
desc := self findNextItemFor:[:n| n fileType isNil ].
desc notNil ifTrue:[
self getFileInfoFor:desc.
^ true
].
].
^ false
!
updateColumnsTaskRestart
self updateColumnsTaskStop.
self updateColumnsTaskStart.
!
updateColumnsTaskStart
| somethigToDo p |
somethigToDo := true.
self directory notNil ifTrue:[
p := [
[
[true] whileTrue:[
somethigToDo := false.
(browser shown and:[self directory notNil]) ifTrue:[
somethigToDo := self updateColumnsTaskCycle.
Processor yield.
].
somethigToDo ifFalse:[
Delay waitForSeconds:1.0
]
]
] valueNowOrOnUnwindDo:[
self updateColumnsTask:nil.
]
] newProcess.
p priority:(Processor systemBackgroundPriority).
self updateColumnsTask: p.
self updateColumnsTask name:('DirectoryContentsBrowser update columns[', self directory baseName, ']').
self updateColumnsTask resume.
]
!
updateColumnsTaskStop
|task|
(task := self updateColumnsTask) notNil ifTrue:[
self updateColumnsTask:nil.
Object errorSignal handle:[:ex|
Dialog warn:ex description.
]do:[
task isDead ifFalse:[
task terminateWithAllSubprocesses.
task waitUntilTerminated.
]
]
].
! !
!DirectoryContentsBrowser methodsFor:'task update dir contents'!
updateDirectoryContentsTaskCycle
| contents|
"/ DIRECTORY CONTNETS HAVE CHANGED
(modificationTime ~= self directory modificationTime) ifTrue:[
modificationTime := self directory modificationTime.
contents := self directory directoryContentsAsFilenames.
contents size == 0 ifTrue:[
allItemsList removeAll.
] ifFalse:[
"/ MERGE WITH CURRENT CONTENTS
allItemsList reverseDo:[:aDesc|
"/ remove no longer valid files
(contents detect:[:f| aDesc fileName = f] ifNone:nil) isNil ifTrue:[
allItemsList removeIdentical:aDesc
]
].
allItemsList size ~~ contents size ifTrue:[
"/ add new files
| addedFiles |
addedFiles := OrderedCollection new.
contents reverseDo:[:aFile|
(allItemsList detect:[:item| item fileName = aFile] ifNone:[nil]) isNil ifTrue:[
addedFiles add:(DirectoryContentsItem with:aFile)
]
].
allItemsList addAll:addedFiles.
]
].
self evaluateFilter.
].
!
updateDirectoryContentsTaskRestart
self updateDirectoryContentsTaskStop.
self updateDirectoryContentsTaskStart.
!
updateDirectoryContentsTaskStart
|p|
self directory notNil ifTrue:[
p := [
[
[true] whileTrue:[
(browser shown and:[self directory notNil]) ifTrue:[
self updateDirectoryContentsTaskCycle.
Processor yield.
].
Delay waitForSeconds:1.0
]
] valueNowOrOnUnwindDo:[
self updateDirectoryContentsTask:nil.
self updateColumnsTaskStop.
]
] newProcess.
p priority:(Processor systemBackgroundPriority).
self updateDirectoryContentsTask:p.
p name:('DirectoryContentsBrowser update contents[', self directory baseName, ']').
p resume.
]
!
updateDirectoryContentsTaskStop
|task|
(task := self updateDirectoryContentsTask) notNil ifTrue:[
self updateDirectoryContentsTask:nil.
Object errorSignal handle:[:ex|
Dialog warn:ex description.
]do:[
task isDead ifFalse:[
task terminateWithAllSubprocesses.
task waitUntilTerminated.
]
]
].
! !
!DirectoryContentsBrowser::DirectoryContentsItem class methodsFor:'instance creation'!
with:aFilename
| instance |
instance := self new.
instance fileName:aFilename.
instance initialize.
^ instance
!
withRemoteDirectory:aFilename
| instance |
instance := self new.
instance fileName:aFilename.
instance beRemoteDirectory.
instance initialize.
^ instance
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'accessing'!
fileName
"returns the fileName
"
^ fileName
!
fileName:aFilename
"set fileName for instance
"
fileName := aFilename.
!
fileType
"returns the type of the file
"
^ fileType
!
fileType:aType
"returns the type of the file
"
fileType := aType.
!
icon
"returns the icon assigned to the file
"
^ icon
!
icon:anIcon
icon := anIcon.
!
iconKey
"return the value of the instance variable 'iconKey' (automatically generated)"
iconKey isNil ifTrue:[
self isRemoteDirectory ifTrue:[
iconKey := FileBrowser iconKeyForRemoteDirectory:fileName.
] ifFalse:[
iconKey := FileBrowser iconKeyForFile:fileName.
]
].
^ iconKey
!
isDirectory
"return the value of the instance variable 'isDirectory' (automatically generated)"
isDirectory isNil ifTrue:[
isDirectory := self fileName isDirectory.
].
^ isDirectory
!
lastButOneSuffix
"returns the suffix of the file
"
^ self suffixes at:2
!
lastSuffix
"returns the suffix of the file
"
^ self suffixes at:1
!
link
"returns the type of the file
"
link isNil ifTrue:[
link := fileName isSymbolicLink.
].
^ link
!
linkInfo
"returns the type of the file
"
linkInfo isNil ifTrue:[
linkInfo := self fileName linkInfo.
].
^ linkInfo
!
mimeType
"return the value of the instance variable 'mimeType' (automatically generated)"
mimeType isNil ifTrue:[
mimeType := MIMETypes mimeTypeForFilename:(self fileName).
mimeType isNil ifTrue:[
mimeType := #unknown
]
].
^ mimeType
!
modifiedByMe
"return the value of the instance variable 'modifiedByMe' (automatically generated)"
^ modifiedByMe
!
modifiedByMe:something
"set the value of the instance variable 'modifiedByMe' (automatically generated)"
modifiedByMe := something.
!
preview
^ preview
!
preview:aLabel
preview := aLabel.
!
suffix
"returns the suffix of the file
"
suffix isNil ifTrue:[
(OperatingSystem isUNIXlike and:[(self baseName at:1) == $.]) ifTrue:[
suffix := ''.
] ifFalse:[
suffix := fileName suffix.
]
].
^ suffix
!
suffixes
| lastSuff lastButOneSuff|
suffixes isNil ifTrue:[
((lastSuff := self suffix) isEmpty) ifTrue:[
lastSuff := nil.
] ifFalse:[
lastSuff := lastSuff asLowercase.
].
((lastButOneSuff := fileName withoutSuffix suffix) isEmpty) ifTrue:[
lastButOneSuff := nil.
] ifFalse:[
lastButOneSuff := lastButOneSuff asLowercase.
].
(lastSuff notNil and:[lastButOneSuff notNil]) ifTrue:[
(lastSuff = 'bak' or:[lastSuff = 'sav']) ifTrue:[
lastSuff := lastButOneSuff.
lastButOneSuff := nil.
]
].
suffixes := Array with:lastSuff with:lastButOneSuff
].
^ suffixes
!
type
"returns the type of the file
"
^ self valueAt:#type
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'actions'!
resetImageFile
" if the image preview extent is changed the icon will set to nil to force the update task to reload the image "
(mimeType notNil and:[ mimeType isImage]) ifTrue:[
preview := nil
]
!
resetItemForChangesFromSomeOneElse
" dont know what someone else is doing with the file - read all item properties new "
link := nil.
linkInfo := nil.
fileInfo := nil.
size := nil.
icon := nil.
link := nil.
fileType := nil.
preview := nil.
owner := nil.
modificationTime := nil.
permissions := nil.
timeAndDate := nil.
date := nil.
group := nil.
!
resetItemForTextEditorChange
" read size and time item properties new "
size := nil.
linkInfo := nil.
fileInfo := nil.
timeAndDate := nil.
date := nil.
modificationTime := nil.
modifiedByMe := true.
"/ textEditorChangeModificationTime := nil.
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'change queries'!
changedForDirectoryContentsBrowser
"check if item modification time is changed
"
| time info|
self isRemoteDirectory ifTrue:[^ false].
info := fileName asAbsoluteFilename info.
info isNil ifTrue:[ ^ false].
time := info modified.
contentsBrowserChangeModificationTime isNil ifTrue:[
contentsBrowserChangeModificationTime := time.
^ false.
].
((contentsBrowserChangeModificationTime = time) not) ifTrue:[
contentsBrowserChangeModificationTime := time.
^ true
].
^ false
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'compare'!
= aItem
"/ Transcript showCR:(aItem species == self species).
aItem species == self species ifFalse:[ ^ false].
aItem isNil ifTrue:[ ^ false].
^ (self fileName = aItem fileName)
!
hash
^ fileName hash
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'instance creation'!
initialize
"initialize instance
"
contentsBrowserChangeModificationTime := (self valueAt:#modified). "/ remark modification to get changes of file in contents browser
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'presentation'!
baseName
"returns the baseName of the file
"
baseName isNil ifTrue:[
baseName := fileName baseName.
].
^ baseName
!
baseName:aName
"rename the file
"
^ self
!
baseNameWithOutSuffix
"returns the baseName of the file
"
| baseNameWithOutSuff |
baseNameWithOutSuff := self baseName asFilename withoutSuffix asString.
baseNameWithOutSuff isEmpty ifTrue:[
^ self baseName
].
^ baseNameWithOutSuff.
!
date
"returns the date
"
| modTime |
date isNil ifTrue:[
modTime := self valueAt:#modified.
modTime isNil ifTrue:[
date := '???'
] ifFalse:[
date := modTime asDate printString.
]
].
^ date
!
fileInfoString
"get stat info on selected file - return a string which can be
shown in a box"
| afileType |
fileName isNil ifTrue:[^ nil].
afileType := self fileType.
afileType isNil ifTrue:[
^ ''.
].
^ afileType
!
group
"returns the printable group
"
|gid|
group isNil ifTrue:[
gid := self valueAt:#gid.
group := gid notNil ifTrue:[OperatingSystem getGroupNameFromID:gid] ifFalse:[^ '???']
].
^ group
!
modificationTime
"returns the absolute time of modification
"
modificationTime isNil ifTrue:[
modificationTime := self valueAt:#modified.
].
^ modificationTime
!
owner
"returns the printable owner
"
|uid|
owner isNil ifTrue:[
uid := self valueAt:#uid.
owner := uid notNil ifTrue:[OperatingSystem getUserNameFromID:uid] ifFalse:[^ '???'].
].
^ owner
!
pathName
"returns the pathName of the file
"
pathName isNil ifTrue:[
pathName := fileName pathName.
].
^ pathName
!
permissions
"returns the permissions as printable string
"
|mode|
permissions isNil ifTrue:[
(mode := self valueAt:#mode) notNil ifTrue:[
permissions := String new:9 withAll:$-.
1 to:9 by:3 do:[:i|
(mode bitAt:i ) == 1 ifTrue:[permissions at:10 - i put:$x].
(mode bitAt:i + 1) == 1 ifTrue:[permissions at:9 - i put:$w].
(mode bitAt:i + 2) == 1 ifTrue:[permissions at:8 - i put:$r].
]
] ifFalse:[
permissions := '???'.
].
].
^ permissions
!
printString
^ fileName asString
!
size
"returns the size of the file
"
^ self valueAt:#size
!
sizeString
"returns the size of the file
"
| unitString n locSize|
size isNil ifTrue:[
unitString := ''.
locSize := self valueAt:#size.
locSize notNil ifTrue:[
locSize < (500 * 1024) ifTrue:[
locSize < 1024 ifTrue:[
n := locSize
] ifFalse:[
n := (locSize * 10 // 1024 / 10.0).
unitString := ' Kb'
]
] ifFalse:[
n := (locSize * 10 // 1024 // 1024 / 10.0).
unitString := ' Mb'
].
locSize := (n printStringLeftPaddedTo:5) , unitString.
] ifFalse:[
locSize := '???'
].
size := locSize.
].
^ size
!
timeAndDate
"returns the date
"
| date modTime stream|
timeAndDate isNil ifTrue:[
modTime := self valueAt:#modified.
modTime isNil ifTrue:[
timeAndDate := '???'
] ifFalse:[
stream := WriteStream on:''.
date := modTime asDate.
stream nextPutAll:date printString.
stream space.
modTime printOn:stream format:'%h:%m:%s'.
timeAndDate := stream contents.
stream close.
]
].
^ timeAndDate
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'private'!
valueAt:aKey
|info|
fileInfo isNil ifTrue:[
fileInfo := IdentityDictionary new.
self isRemoteDirectory ifTrue:[
"/ do not access, to avoid automount
] ifFalse:[
info := fileName linkInfo.
info notNil ifTrue:[
link := true
] ifFalse:[
info := fileName info.
].
info notNil ifTrue:[
fileInfo at:#size put:(info size).
fileInfo at:#mode put:(info mode).
fileInfo at:#type put:(info type).
fileInfo at:#uid put:(info uid).
fileInfo at:#gid put:(info gid).
fileInfo at:#accessed put:(info accessed).
fileInfo at:#modified put:(info modified).
]
]
].
^ fileInfo at:aKey ifAbsent:nil
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'queries'!
beRemoteDirectory
fileType := #remoteDirectory.
isDirectory := true.
!
exists
"returns the fileName
"
^ fileName exists
!
hasMimeType
^ (self mimeType ~= #unknown)
!
isRemoteDirectory
^ fileType == #remoteDirectory
!
mimeTypeForContents
|mimeTypeForContents|
mimeTypeForContents isNil ifTrue:[
mimeTypeForContents := MIMETypes mimeTypeOfContents:(self fileName).
mimeTypeForContents isNil ifTrue:[
mimeTypeForContents := #unknown
] ifFalse:[
" set mimeType to mimeType of contents if a better mimeType is found "
mimeType := mimeTypeForContents.
iconKey := mimeTypeForContents.
]
].
^ mimeTypeForContents
! !
!DirectoryContentsBrowser class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libtool/DirectoryContentsBrowser.st,v 1.4 2002-09-27 15:23:00 penk Exp $'
! !