"{ Package: 'stx:libtool' }"
AbstractFileBrowser subclass:#DirectoryContentsBrowser
instanceVariableNames:'modificationTime directory columnDescriptors iconIndex
fileDescriptionIndex iconExtent tableColumns previewIndex
updateToExternFileHolderLock inDropMode draggedItem canDropItem
viewBrowserMenu updateContentsSelection selectionInFileList
contentsBrowser browserItemList matchBlock updateTask
directoryChangeFlag directoryContentsChangeFlag filterChangeFlag
sortBlockChangeFlag isBusy changeSema filteredItems allItems'
classVariableNames:''
poolDictionaries:''
category:'Interface-Tools-File'
!
Object subclass:#DirectoryContentsItem
instanceVariableNames:'fileName fileInfo icon fileType
contentsBrowserChangeModificationTime suffix preview group owner
timeAndDate mimeType iconKey mimeTypeForContents'
classVariableNames:'LastUIDToUserNameMapping LastGIDToGroupNameMapping'
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 viewDirsInContentsBrowser value:withDirectoriesBoolean.
^ browser
"
self openIn:(Filename currentDirectory asAbsoluteFilename) withDirectories:true
"
! !
!DirectoryContentsBrowser class methodsFor:'classAccess'!
itemClass
^ DirectoryContentsItem
"
self itemClass
"
! !
!DirectoryContentsBrowser class methodsFor:'constant'!
debug
^ false
!
updateTaskCyleTime
" time for search on changed directories or changed columns in msecs "
^ 4000
!
updateTaskPriority
"returns the priority of the update task
"
^ 8
! !
!DirectoryContentsBrowser class methodsFor:'image specs'!
detailsMenuIconDown
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self detailsMenuIconDown inspect
ImageEditor openOnClass:self andSelector:#detailsMenuIconDown
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:#'DirectoryContentsBrowser class detailsMenuIconDown'
ifAbsentPut:[(Depth1Image new) width: 7; height: 5; photometric:(#palette); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255]; mask:((Depth1Image new) width: 7; height: 5; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@A@(UJ(b') ; yourself); yourself]
!
detailsMenuIconR
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self detailsMenuIconR inspect
ImageEditor openOnClass:self andSelector:#detailsMenuIconR
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:#'DirectoryContentsBrowser class detailsMenuIconR'
ifAbsentPut:[(Depth1Image new) width: 5; height: 7; photometric:(#palette); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 255 255 255]; mask:((Depth1Image new) width: 5; height: 7; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:' DB TJA@ @@a') ; yourself); yourself]
!
detailsMenuIconUp
"This resource specification was automatically generated
by the ImageEditor of ST/X."
"Do not manually edit this!! If it is corrupted,
the ImageEditor may not be able to read the specification."
"
self detailsMenuIconUp inspect
ImageEditor openOnClass:self andSelector:#detailsMenuIconUp
Icon flushCachedIcons
"
<resource: #image>
^Icon
constantNamed:#'DirectoryContentsBrowser class detailsMenuIconUp'
ifAbsentPut:[(Depth1Image new) width: 7; height: 5; photometric:(#palette); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255]; mask:((Depth1Image new) width: 7; height: 5; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'*%P(D@@b') ; yourself); yourself]
! !
!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
#label: ''
#id: #icon
#labelButtonType: #Group
#labelActionSelector: #showDetailMenu
#width: 22
#minWidth: 22
#height: 16
#model: #icon
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Filename'
#id: #filename
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortFileListsBy:
#labelActionArgument: 'baseName'
#minWidth: 150
#model: #baseName
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Suffix'
#id: #suffix
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortFileListsBy:
#labelActionArgument: 'suffix'
#width: 40
#model: #suffix
#canSelect: false
#isResizeable: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Perm'
#id: #perm
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortFileListsBy:
#labelActionArgument: 'permissions'
#width: 75
#model: #permissions
#canSelect: false
#isResizeable: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Owner'
#id: #owner
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortFileListsBy:
#labelActionArgument: 'owner'
#usePreferredWidth: true
#width: 50
#model: #owner
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Group'
#id: #group
#labelAlignment: #left
#labelButtonType: #Button
#labelActionSelector: #sortFileListsBy:
#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: #sortFileListsBy:
#labelActionArgument: 'fileSize'
#columnAlignment: #decimal
#usePreferredWidth: true
#model: #sizeString
#canSelect: false
#showRowSeparator: false
#showColSeparator: false
)
#(#DataSetColumnSpec
#label: 'Date & Time'
#id: #time
#labelAlignment: #right
#labelButtonType: #Button
#labelActionSelector: #sortFileListsBy:
#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: #sortFileListsBy:
#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 16 42 604 520)
#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: #browserItemList
#useIndex: false
#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
#dropSelector: #doDrop:
#dragArgument: #contentsbrowser
#startDragSelector: #doStartDrag:in:
#displayObjectSelector: #getDisplayObjects:
#dropObjectSelector: #getDropObjects:
#dropArgument: #browser
#canDropSelector: #canDrop:
#leaveSelector: #dropLeave:
#enterSelector: #dropEnter:
#overSelector: #dropOver:
)
)
)
)
)
! !
!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'
#itemValue: #doCopy
#translateLabel: true
#shortcutKey: #Copy
)
#(#MenuItem
#label: 'Cut'
#itemValue: #doCut
#translateLabel: true
#shortcutKey: #Cut
)
#(#MenuItem
#enabled: #canPaste
#label: 'Paste'
#itemValue: #pasteFiles
#translateLabel: true
#shortcutKey: #Paste
)
#(#MenuItem
#label: 'Delete'
#itemValue: #doDelete
#nameKey: #delete
#translateLabel: true
#shortcutKey: #Delete
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#enabled: #hasSelection
#label: 'Rename...'
#itemValue: #renameSelection
#translateLabel: true
#shortcutKey: #Replace
)
#(#MenuItem
#enabled: #hasSelection
#label: 'Properties...'
#itemValue: #doShowProperties
#translateLabel: true
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#enabled: #hasSelection
#label: 'File In'
#itemValue: #fileFileIn
#translateLabel: true
#shortcutKey: #Accept
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'New'
#translateLabel: true
#submenuChannel: #newMenu
)
#(#MenuItem
#label: 'More'
#translateLabel: true
#submenu:
#(#Menu
#(
#(#MenuItem
#enabled: #hasSelection
#label: 'File inTo Namespace...'
#itemValue: #fileFileInToNameSpace
#translateLabel: true
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#enabled: #hasSelection
#label: 'Open in Text Editor'
#itemValue: #doShowFileContents
#translateLabel: true
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Select All'
#itemValue: #selectAll
#translateLabel: true
)
#(#MenuItem
#enabled: #fileListIsNotEmpty
#label: 'Copy File List'
#itemValue: #copyFileList
#translateLabel: true
)
)
nil
nil
)
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'View'
#translateLabel: true
#submenu:
#(#Menu
#(
#(#MenuItem
#label: 'Details'
#nameKey: #View
#translateLabel: true
#submenuChannel: #viewBrowserMenu
)
#(#MenuItem
#label: 'Sort'
#nameKey: #Sort
#translateLabel: true
#submenuChannel: #sortMenu
)
#(#MenuItem
#label: 'Show'
#translateLabel: true
#submenu:
#(#Menu
#(
#(#MenuItem
#label: 'Hidden Files'
#translateLabel: true
#indication: #showHiddenFiles
)
#(#MenuItem
#label: 'Directories'
#translateLabel: true
#indication: #viewDirsInContentsBrowser
)
)
nil
nil
)
)
)
nil
nil
)
)
#(#MenuItem
#label: '-'
)
#(#MenuItem
#label: 'Update'
#itemValue: #doUpdate
#translateLabel: true
)
)
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 new fromLiteralArrayEncoding:self viewBrowserMenuSpec
!
viewBrowserMenuSpec
"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: '-'
)
#(#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: '-'
#isVisible: false
)
#(#MenuItem
#label: 'Show Hidden Files'
#translateLabel: true
#indication: #showHiddenFiles
#isVisible: false
)
#(#MenuItem
#label: 'Update'
#translateLabel: true
#value: #doUpdate
#isVisible: false
)
)
nil
nil
)
! !
!DirectoryContentsBrowser methodsFor:'accessing'!
allItems
"return the value of the instance variable 'allItems' (automatically generated)"
^ allItems
!
allItems:something
"set the value of the instance variable 'allItems' (automatically generated)"
allItems := something.
!
changeSema
"return the value of the instance variable 'changeSema' (automatically generated)"
changeSema isNil ifTrue:[
changeSema := Semaphore new.
].
^ changeSema
!
columnDescriptors
"get the column description
"
^ columnDescriptors
!
columnDescriptors:aListOfColumns
"set the column description
"
|selection|
columnDescriptors = aListOfColumns ifTrue:[
^ self
].
columnDescriptors := OrderedCollection new.
previewIndex := 0.
iconIndex := 0.
fileDescriptionIndex := 0.
iconExtent := nil.
selection := self selectedItems.
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 wakeUpForDirectoryChanged.
!
directoryChangeFlag
"return the value of the instance variable 'directoryChangeFlag' (automatically generated)"
directoryChangeFlag isNil ifTrue:[
directoryChangeFlag := false.
].
^ directoryChangeFlag
!
directoryChangeFlag:something
"set the value of the instance variable 'directoryChangeFlag' (automatically generated)"
directoryChangeFlag := something.
!
directoryContentsChangeFlag
"return the value of the instance variable 'directoryContentsChangeFlag' (automatically generated)"
directoryContentsChangeFlag isNil ifTrue:[
directoryContentsChangeFlag := false.
].
^ directoryContentsChangeFlag
!
directoryContentsChangeFlag:something
"set the value of the instance variable 'directoryContentsChangeFlag' (automatically generated)"
directoryContentsChangeFlag := something.
!
filterChangeFlag
"return the value of the instance variable 'filterChangeFlag' (automatically generated)"
filterChangeFlag isNil ifTrue:[
filterChangeFlag := false.
].
^ filterChangeFlag
!
filterChangeFlag:something
"set the value of the instance variable 'filterChangeFlag' (automatically generated)"
filterChangeFlag := something.
!
isBusy
"return the value of the instance variable 'isBusy' (automatically generated)"
isBusy isNil ifTrue:[
isBusy := false.
].
^ isBusy
!
isBusy:something
"set the value of the instance variable 'isBusy' (automatically generated)"
isBusy := something.
!
matchBlock
"return the value of the instance variable 'matchBlock' (automatically generated)"
^ matchBlock
!
matchBlock:filterBlock
matchBlock := filterBlock.
!
sortBlockChangeFlag
"return the value of the instance variable 'sortBlockChangeFlag' (automatically generated)"
sortBlockChangeFlag isNil ifTrue:[
sortBlockChangeFlag := false.
].
^ sortBlockChangeFlag
!
sortBlockChangeFlag:something
"set the value of the instance variable 'sortBlockChangeFlag' (automatically generated)"
sortBlockChangeFlag := something.
!
updateContentsSelection
"return the value of the instance variable 'updateToExternFileHolder' (automatically generated)"
updateContentsSelection isNil ifTrue:[
updateContentsSelection := self class newLock.
].
^ updateContentsSelection
!
updateToExternFileHolderLock
"return the value of the instance variable 'updateToExternFileHolder' (automatically generated)"
updateToExternFileHolderLock isNil ifTrue:[
updateToExternFileHolderLock := self class newLock.
].
^ updateToExternFileHolderLock
! !
!DirectoryContentsBrowser methodsFor:'actions'!
browserItemListAdd:addItemCol remove:remItemCol
| browserList selection|
(addItemCol isEmpty and:[remItemCol isEmpty]) ifTrue:[ ^ self].
selection := self selectedItems.
remItemCol notEmpty ifTrue:[
self browserItemList removeAll:remItemCol
].
addItemCol notEmpty ifTrue:[
browserList := self browserItemList copy.
addItemCol do:[: aNewItem |
(browserList includes:aNewItem) not ifTrue:[
browserList add:aNewItem.
browserList sort:self sortBlockHolder value.
self browserItemList add:aNewItem beforeIndex:(browserList indexOf:aNewItem).
]
].
].
"/ browserList sort:self sortBlockHolder value.
"/ self browserItemList contents:browserList asList.
self selectItems:selection.
!
currentSortOrderChanged
self viewedColumnsChanged.
!
doResizeImage
|column w h selection|
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.
"/Processor activeProcess ~~ self windowGroup process ifTrue:[self halt].
selection := self selectedItems.
browserItemList do:[:el| el resetImageFile ].
contentsBrowser columnDescriptors:(self tableColumns value).
self selectItems:selection.
self wakeUp.
!
doUpdate
DirectoryContents flushCache.
self wakeUpForDirectoryContentsChanged.
!
doubleClickedAt:anItemIndex
self withWaitCursorDo:[
self enterActionFor:(self browserItemList at:anItemIndex). "/ anItemIndex.
]
!
enterActionFor:anItem
| filename|
filename := anItem fileName.
filename baseName = '..' ifTrue:[
self currentFileNameHolder value:(OrderedCollection with:(self directory directory)).
^ self.
].
(anItem isDirectory) ifTrue:[
self currentFileNameHolder value:(OrderedCollection with:filename).
^ self.
].
self openApplByFileItem:anItem.
!
noOfAddedFiles:noOfAddedFiles noOfFiles:noOfFiles
|info filterBox clr|
noOfAddedFiles = noOfFiles ifTrue:[
info := '%1 files'.
] ifFalse:[
info := '%1 files shown (out of %2)'.
].
self shownFiles value:(resources string:info with:noOfAddedFiles with:noOfFiles).
filterBox := self filterValueBox value.
filterBox isNil ifTrue:[^ self ].
noOfAddedFiles ~= noOfFiles ifTrue:[
clr := Color red lightened lightened lightened.
[ filterBox flash] fork.
] ifFalse:[
clr := self filterBackgroundColor value.
].
filterBox backgroundColor:clr.
!
setBrowserItemList:filteredItems
|showDir directoryUpItem locItems|
showDir := self viewDirsInContentsBrowser value.
(showDir and:[self directory notNil and:[self directory isRootDirectory not]]) ifTrue:[
directoryUpItem := DirectoryContentsBrowser itemClass fileName:(self directory construct:'..').
locItems := filteredItems copy.
locItems addFirst:directoryUpItem.
] ifFalse:[
locItems := filteredItems.
].
self updateToExternFileHolderLock doLocked:[
self browserItemList contents:locItems asList.
].
"/ Transcript showCR:'after insert list', AbsoluteTime now asString.
self selectCurrentFiles.
! !
!DirectoryContentsBrowser methodsFor:'aspects'!
browserItemList
browserItemList isNil ifTrue:[
browserItemList := List new.
].
^ browserItemList
!
selectionInFileList
selectionInFileList isNil ifTrue:[
selectionInFileList := ValueHolder new.
selectionInFileList addDependent:self.
].
^ selectionInFileList
!
tableColumns
tableColumns isNil ifTrue:[
tableColumns := self class tableColumns asValue.
].
^ tableColumns.
! !
!DirectoryContentsBrowser methodsFor:'change & update'!
currentFileNameHolderChanged
"filename changed
"
| newDir currentDir aColOfFiles|
aColOfFiles := self currentFileNameHolder value.
(aColOfFiles isEmpty or:[self currentFilesAreInSameDirectory not]) ifTrue:[
self directory:nil.
^ self
].
newDir := self currentDirectories value first.
currentDir := self directory.
newDir = currentDir ifTrue:[
self selectFiles:aColOfFiles.
^ self.
] ifFalse:[
"/ change of the directory filename
self directory:newDir.
].
!
filterBlockHolderChanged
self matchBlock:self filterBlockHolder value.
self wakeUpForFilterChanged.
!
selectionChanged
| selection newCurrentFilename |
self directory isNil ifTrue:[^ self].
selection := self selectedFiles.
selection isEmpty ifTrue:[
newCurrentFilename := OrderedCollection with:self directory.
] ifFalse:[
newCurrentFilename := selection.
].
self currentFileNameHolder value ~= newCurrentFilename ifTrue:[
self currentFileNameHolder value:newCurrentFilename withoutNotifying:self
]
!
update:something with:aParameter from:aModel
"one of my models changed
"
aModel == self currentFileNameHolder ifTrue:[
super update:something with:aParameter from:aModel.
self updateContentsSelection doIfUnLocked:[
self currentFileNameHolderChanged.
].
^ self.
].
aModel == self selectionInFileList ifTrue:[
self updateToExternFileHolderLock doIfUnLocked:[
self updateContentsSelection doLocked:[
self selectionChanged.
]
].
^ self.
].
aModel == self currentSortOrder ifTrue:[
self currentSortOrderChanged.
^ self.
].
aModel == self filterBlockHolder ifTrue:[
self filterBlockHolderChanged.
^ self.
].
aModel == self sortBlockHolder ifTrue:[
self wakeUpForSortBlockChanged.
^ self.
].
aModel == self viewDirsInContentsBrowser ifTrue:[
self wakeUpForFilterChanged.
^ self
].
super update:something with:aParameter from:aModel
!
viewPreviewChanged
browserItemList do:[:el| el resetImageFile ].
self viewedColumnsChanged.
!
viewedColumnsChanged
| columns buffer currentSortOrder currentSortOrderColumn currentSortOrderReverse selection|
selection := self selectedItems.
columns := OrderedCollection new.
self class tableColumns do:[:el|
columns add:(DataSetColumnSpec new fromLiteralArrayEncoding:el).
].
buffer := columns copy.
self viewDetails value = false ifTrue:[
contentsBrowser showLabels:false.
buffer do:[:col |
(col readSelector = #baseName or:[col readSelector = #icon]) ifFalse:[
columns remove:col.
]
]
] ifFalse:[
contentsBrowser showLabels:true.
currentSortOrder := self currentSortOrder value.
currentSortOrderColumn := currentSortOrder at:#column ifAbsent:nil.
currentSortOrderReverse := currentSortOrder at:#reverse ifAbsent:nil.
buffer do:[:col |
| id |
id := col id.
id notNil ifTrue:[
(col labelActionArgument notNil and:[col labelActionArgument asSymbol == currentSortOrderColumn]) ifTrue:[
| label icon|
label := col label.
icon := currentSortOrderReverse ifTrue:[self class detailsMenuIconDown] ifFalse:[self class detailsMenuIconUp].
col label:(LabelAndIcon label:label icon:icon).
].
(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 == #time and:[self viewTime value not]) ifTrue:[
columns remove:col.
] ifFalse:[
(id == #fileInfo and:[self viewDescription value not]) ifTrue:[
columns remove:col.
]
]
]
]
]
]
]
]
]
]
]
].
self updateToExternFileHolderLock doLocked:[
self tableColumns value:columns.
].
self columnDescriptors:(self tableColumns value).
self selectItems:selection.
self wakeUp.
! !
!DirectoryContentsBrowser methodsFor:'drag & drop'!
canDrop:aContext
^ canDropItem
!
doDrop:aContext
|col destinationPath receiver|
draggedItem isNil ifTrue:[
destinationPath := self directory.
] ifFalse:[
destinationPath := self getDirWithoutFileName:(draggedItem fileName).
destinationPath baseName = '..' ifTrue:[
destinationPath := self directory directory.
]
].
self dropLeave:aContext.
aContext dropSource argument == #archivApplication ifTrue:[
receiver := aContext dropSource receiver.
receiver extractSelectedFilesTo:destinationPath askForExtractOptions:true.
^ true.
].
col := OrderedCollection new.
aContext dropObjects do:[:obj|
col add:(obj theObject).
].
self copyOrMoveFiles:col to:destinationPath.
^ true.
!
doStartDrag:aDropSource in:aView
"set the cursors before starting the drag & drop operation
"
|selectedFiles|
selectedFiles := self selectedFiles.
(selectedFiles isEmpty) ifTrue:[
^ self.
].
^ super doStartDrag:aDropSource in:aView
!
dropEnter:aContext
|dropedObjects|
self dropTargetItemChangedTo:nil in:aContext.
inDropMode := false.
self directory isNil ifTrue:[^ self].
dropedObjects := aContext dropObjects.
dropedObjects do:[:aObject|
|checkObject checkObjectString|
aObject isFileObject ifFalse:[^ self].
checkObject := aObject theObject.
checkObject isFilename not ifTrue:[^ self].
((aContext dropSource argument == #archivApplication) not) ifTrue:[
checkObject isSpecialFile ifTrue:[^ self].
checkObject isReadable ifFalse:[^ self].
].
].
inDropMode := true.
!
dropLeave:aDropContext
inDropMode ifTrue:[
self dropTargetItemChangedTo:nil in:aDropContext.
inDropMode := false.
].
!
dropOver:aContext
"send the last time, when leaving the widget
"
|lineNr newDest destinationFile|
inDropMode ifFalse:[^ self].
lineNr := self getLineNumberFor:aContext.
lineNr notNil ifTrue:[
newDest := browserItemList at:lineNr.
(newDest notNil and:[newDest isDirectory]) ifTrue:[
destinationFile := newDest fileName.
destinationFile baseName = '..' ifTrue:[
destinationFile := self directory directory.
]
].
].
newDest == draggedItem ifTrue:[^ self].
destinationFile isNil ifTrue:[
destinationFile := self directory.
].
newDest ~~ draggedItem ifTrue:[
aContext dropSource argument == #archivApplication ifTrue:[
canDropItem := true.
] ifFalse:[
canDropItem := self canDropFiles:(aContext dropObjects) for:destinationFile.
].
].
self dropTargetItemChangedTo:newDest in:aContext.
!
dropTargetItemChangedTo:anItem in:aDropContext
| current |
"/ (anItem notNil and:[anItem isDirectory]) ifTrue:[ self halt].
current := draggedItem.
"/ Transcript showCR:'current:', (current isNil ifTrue:['nil'] ifFalse:[current fileName baseName]).
"/ Transcript showCR:'anItem:', (anItem isNil ifTrue:['nil'] ifFalse:[anItem fileName baseName]).
current == anItem ifTrue:[^ self].
draggedItem := anItem.
aDropContext contentsWillChange.
current ifNotNil:[
current isDirectory ifTrue:[
current icon:(self getIconFor:current).
].
].
anItem ifNotNil:[
anItem isDirectory ifTrue:[
anItem icon:(FileBrowser iconForKeyMatching:#directoryOpenGray).
].
].
contentsBrowser shown ifTrue:[
contentsBrowser invalidateVisibleRow:current colAt:iconIndex.
contentsBrowser invalidateVisibleRow:anItem colAt:iconIndex.
contentsBrowser repairDamage.
].
!
getDisplayObjects:anArgument
| selectedFiles string fnName stream|
selectedFiles := self selectedFiles.
selectedFiles isEmpty ifTrue:[ ^ ''].
stream := WriteStream on:''.
stream nextPutAll:(selectedFiles first baseName).
selectedFiles size == 1 ifTrue:[
fnName := 'ui_menuitem.xpm'.
] ifFalse:[
fnName := 'ui_submenu_open.xpm'.
stream nextPutAll:' ... '.
stream nextPutAll:(selectedFiles last baseName).
].
string := stream contents.
stream close.
^ Array with:(LabelAndIcon icon:(Image fromFile:fnName)
string:(Text string:string emphasis:#bold)
)
!
getDropObjects:anArgument
^ self selectedFiles collect:[:file| DropObject newFile:file].
!
getLineNumberFor:aDropContext
| yVisible|
yVisible := (aDropContext targetPoint y).
^ contentsBrowser 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 == contentsBrowser) ifTrue:[
"/ (key ~= #'Alt_L') ifTrue:[self halt.].
key == #Accept ifTrue:[
self fileFileIn.
^ true.
].
key == #Paste ifTrue:[
self pasteFiles.
^ true.
].
"/ (key == #CursorLeft) ifTrue:[
"/ self doGoDirectoryUp.
"/ ^ true
"/ ].
"/ (key == #CursorRight) ifTrue:[
"/ self doBack.
"/ ^ true
"/ ].
browserItemList 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 selectedFiles).
!
doCut
"cut current selected files/directories
"
self cutFilesToClipBoard:(self selectedFiles).
!
doDelete
"delete current selected files/directories
"
self deleteFiles:(self selectedFiles).
! !
!DirectoryContentsBrowser methodsFor:'menu accessing'!
viewBrowserMenu
<resource: #programMenu >
|menu|
viewBrowserMenu isNil ifTrue:[
viewBrowserMenu := self class viewBrowserMenu.
].
viewBrowserMenu ifNil:[ ^ nil ].
viewBrowserMenu findGuiResourcesIn:self.
menu := viewBrowserMenu.
menu receiver:self.
^ menu
! !
!DirectoryContentsBrowser methodsFor:'menu actions'!
doOpenSelectedFile
| selectedItems|
selectedItems := self selectedItems.
(selectedItems size == 1) ifTrue:[
self enterActionFor:(selectedItems first).
].
!
doShowFileContents
| selectedFileItems|
selectedFileItems := self selectedFileItems.
(selectedFileItems size == 1) ifTrue:[
self openTextEditorOn:(selectedFileItems first).
].
! !
!DirectoryContentsBrowser methodsFor:'queries'!
allItemsOfCurrentDirectory
| list |
list := browserItemList copy.
self viewDirsInContentsBrowser value ifTrue:[
list removeIdentical:(browserItemList first) ifAbsent:[nil]
].
^ list.
!
fileListIsEmpty
^ browserItemList isEmpty
!
getAllFilesAsStringCollection
|files items|
items := browserItemList.
files := OrderedCollection new.
items isEmpty ifTrue:[
^ files
].
items do:[:aItem |
aItem isDirectory not ifTrue:[
files add:aItem fileName asString
].
].
^ files.
!
hasFilesFiltered
^ self allItems size ~~ browserItemList size
! !
!DirectoryContentsBrowser methodsFor:'selection'!
selectAll
| sel|
sel := browserItemList copy.
self viewDirsInContentsBrowser value ifTrue:[
sel removeIdentical:(browserItemList first) ifAbsent:[nil]
].
self selectionInFileList value:sel.
!
selectCurrentFiles
|currentSelection|
((currentSelection := self currentFileNameHolder value select:[:file| file isDirectory not]) notEmpty) ifTrue:[
self selectFiles:currentSelection.
].
!
selectFiles:aColOfFilenames
| curSel newSel|
curSel := self selectedFiles.
aColOfFilenames size = curSel size ifTrue:[
| index |
index := curSel findFirst:[:file| (aColOfFilenames includes:file) not].
index == 0 ifTrue:[ ^ self].
].
newSel := OrderedCollection new.
browserItemList do:[: item|
(aColOfFilenames includes:(item fileName)) ifTrue:[
newSel add:item.
].
].
self updateToExternFileHolderLock doLocked:[
self selectionInFileList value:newSel withoutNotifying:self.
].
!
selectItems:aColOfItems
| curSel newSel|
curSel := self selectedItems.
aColOfItems size = curSel size ifTrue:[
| index |
index := curSel findFirst:[:item| (aColOfItems includes:item) not].
index == 0 ifTrue:[ ^ self].
].
newSel := OrderedCollection new.
browserItemList do:[: item|
(aColOfItems includes:item) ifTrue:[
newSel add:item.
].
].
self updateToExternFileHolderLock doLocked:[
self selectionInFileList value:newSel withoutNotifying:self.
].
!
selectedFileItems
| sel |
sel := self selectedItems select:[:item | item isDirectory not].
^ sel
!
selectedFileNames
^ self selectedFileItems collect:[:item| item fileName].
!
selectedFiles
^ self selectedItems collect:[: item| item fileName].
!
selectedItems
| sel |
sel := self selectionInFileList value copy.
sel isNil ifTrue:[ ^ #()].
(self viewDirsInContentsBrowser value and:[browserItemList notEmpty]) ifTrue:[
sel removeIdentical:(browserItemList first) ifAbsent:[nil]
].
^ sel.
! !
!DirectoryContentsBrowser methodsFor:'startup / release'!
makeDependent
super makeDependent.
self currentFileNameHolder addDependent:self.
self currentSortOrder addDependent:self.
self viewDirsInContentsBrowser addDependent:self.
self filterBlockHolder addDependent:self.
self sortBlockHolder 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:#viewPreviewChanged to:self.
self viewSize onChangeSend:#viewedColumnsChanged to:self.
self viewTime onChangeSend:#viewedColumnsChanged to:self.
self viewType onChangeSend:#viewedColumnsChanged to:self.
!
postBuildBrowser:aWidget
contentsBrowser := aWidget scrolledView.
contentsBrowser wantsFocusWithPointerEnter.
"/ dont register icons anymore
"/ FileBrowser icons keysAndValuesDo:[:aKey :anIcon|
"/ browser registerImage:anIcon key:aKey.
"/ ].
self columnDescriptors:(self tableColumns value).
!
postOpen
self startUpdateTask.
self abstractCurrentFileNameHolderChanged.
self matchBlock:self filterBlockHolder value.
self currentFileNameHolderChanged.
self viewedColumnsChanged.
self windowGroup addPreEventHook:self.
!
postOpenAsSubcanvasWith:aBuilder
super postOpenAsSubcanvasWith:aBuilder.
self postOpen.
!
postOpenWith:aBuilder
"
only invoked if the application not started from a master
"
super postOpenWith:aBuilder.
self postOpen.
!
preBuildWith:aBuilder
self masterApplication isNil ifTrue:[
self masterApplication:nil.
].
^ super preBuildWith:aBuilder.
!
release
"release my resources
"
self stopUpdateTask.
super release.
!
releaseAsSubCanvas
self stopUpdateTask.
^ super releaseAsSubCanvas.
! !
!DirectoryContentsBrowser methodsFor:'update columns cycle'!
findNextItemFor:aBlock
^ self allItems detect:aBlock ifNone:[nil].
!
findNextVisibleItemFor:aConditionBlock
|vis idx stillSearching |
vis := contentsBrowser indexOfFirstRowShown.
vis = 0 ifTrue:[vis := 1].
idx := vis.
stillSearching := true.
[ stillSearching ] whileTrue:[
((idx <= browserItemList size) and:[ (contentsBrowser isRowVisible:idx) ]) ifFalse:[
stillSearching := false.
idx := nil.
] ifTrue:[
(aConditionBlock value:(browserItemList at:idx)) ifTrue:[
"/ found a one
stillSearching := false.
] ifFalse:[
idx := idx + 1.
]
].
].
idx isNil ifTrue:[^ nil].
^ browserItemList at:idx ifAbsent: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.
!
getIconForMimeType:mime for:aItem
| currentIcon newIcon icon|
newIcon := FileBrowser iconForKeyMatching:mime.
currentIcon := aItem icon.
(currentIcon class == MultiImage) ifTrue:[
| images |
images := currentIcon images.
images removeFirst.
images addFirst:newIcon.
icon := currentIcon.
] ifFalse:[
icon := newIcon.
].
^ icon
!
getIconForMimeTypeByContents:aItem
^ self getIconForMimeType:(aItem mimeTypeForContents) for:aItem
!
getPreviewFor:aItem
| column icon|
column := contentsBrowser 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 fileName 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:(contentsBrowser device).
icon clearMaskedPixels.
]
]
] ifFalse:[ icon := nil].
aItem preview:(icon ? '').
].
^ icon
!
updateChangesFor:aItem
aItem resetItemForChanges.
!
updateColumnsCycle
" 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 mime icon type preview|
browserItemList notEmpty ifTrue:[
"/ update item if item properties are changed
desc := self findNextVisibleItemFor:[:n| n hasBeenModified ].
desc notNil ifTrue:[
self updateChangesFor:desc.
contentsBrowser invalidateVisibleRow:desc.
self debugMessage:'item properties are changed', desc baseName.
^ true.
].
"/ update icon for visible items by suffix
desc := self findNextVisibleItemFor:[:n| n icon isNil ].
desc notNil ifTrue:[
icon := self getIconFor:desc.
desc icon:icon.
(icon notNil and:[iconIndex ~~ 0]) ifTrue:[
contentsBrowser invalidateVisibleRow:desc colAt:iconIndex
].
self debugMessage:'icon for visible items by suffix', desc baseName.
^ true
].
"/ update icon for visible items by contents
desc := self findNextVisibleItemFor:[:n|
(n iconKey == #file
and:[(mime := n mimeTypeForContents asSymbol) ~= #unknown])
].
desc notNil ifTrue:[
icon := self getIconForMimeType:mime for:desc.
"/ icon := self getIconForMimeTypeByContents:desc.
desc icon:icon.
(icon notNil and:[iconIndex ~~ 0]) ifTrue:[
contentsBrowser invalidateVisibleRow:desc colAt:iconIndex
].
^ true
].
"/ update file info for visible items if file info column is shown
fileDescriptionIndex ~~ 0 ifTrue:[
desc := self findNextVisibleItemFor:[:n| n fileType isEmpty ].
desc notNil ifTrue:[
type := self getFileInfoFor:desc.
type notNil ifTrue:[contentsBrowser invalidateVisibleRow:desc colAt:fileDescriptionIndex].
self debugMessage:'file info for visible items if file info column is shown', desc baseName.
^ true
]
].
"/ update preview for visible items if preview column is shown
previewIndex ~~ 0 ifTrue:[
desc := self findNextVisibleItemFor:[:n| n preview isNil ].
desc notNil ifTrue:[
preview := self getPreviewFor:desc.
preview notNil ifTrue:[
contentsBrowser invalidateVisibleRow:desc colAt:previewIndex
].
self debugMessage:'preview for visible items if preview column is shown', desc baseName.
^ true
]
].
].
"/ validate invisible items to make them available after scrolling
self allItems 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.
self debugMessage:'icon for invisible items by suffix', desc baseName.
^ 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.
self debugMessage:'icon for invisible items by contents', desc baseName.
^ 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.
self debugMessage:'update file info for invisible items if file info column is shown', desc baseName.
^ 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.
self debugMessage:'update preview for invisible items if preview column is shown:', desc baseName.
^ 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.
self debugMessage:'update file info for invisible items if file info column is not shown:', desc baseName.
^ true
].
].
^ false
! !
!DirectoryContentsBrowser methodsFor:'update modification cycle'!
modificationCycle
| oldModificationTime |
directory notNil ifTrue:[
directory exists not ifTrue:[
self directoryChangeFlag:true.
^ self
].
oldModificationTime := modificationTime.
modificationTime := directory modificationTime.
(directory notNil and:[oldModificationTime ~= directory modificationTime]) ifTrue:[
self wakeUpForDirectoryContentsChanged.
].
].
! !
!DirectoryContentsBrowser methodsFor:'update task'!
createItemList
"/ |filterTime sortTime getAllTime|
directory notNil ifTrue:[
modificationTime := directory modificationTime.
"/ getAllTime := Time millisecondsToRun:[
self allItems:self readDirectoryItems.
"/ ].
"/ filterTime := Time millisecondsToRun:[
filteredItems := self evaluateFilter:(self allItems).
"/ ].
"/ sortTime := Time millisecondsToRun:[
filteredItems sort:self sortBlockHolder value.
"/ ].
"/ Transcript showCR:'getAllTime:', getAllTime asString.
"/ Transcript showCR:'filterTime:', filterTime asString.
"/ Transcript showCR:'sortTime:', sortTime asString.
"/ Transcript showCR:'time after sort', AbsoluteTime now asString.
] ifFalse:[
self allItems:OrderedCollection new.
filteredItems := OrderedCollection new.
].
self
enqueueMessage:#value
for:[
self setBrowserItemList:filteredItems
]
arguments:#().
!
debugMessage:aString
self class debug ifTrue:[
Transcript showCR:aString
].
!
directoryChanged
self setBrowserItemList:#().
self createItemList.
!
directoryContentsChanged
|oldItems addItems remItems newItems newAllItems theAllItems|
directory isNil ifTrue:[^ self].
modificationTime := directory modificationTime.
newAllItems := self readDirectoryItems.
newAllItems size > 150 ifTrue:[
self createItemList.
^ self
].
newItems := self evaluateFilter:newAllItems.
oldItems := filteredItems copy.
addItems := OrderedCollection new.
remItems := OrderedCollection new.
filteredItems size == 0 ifTrue:[
remItems := oldItems.
] ifFalse:[
"/ MERGE WITH CURRENT CONTENTS
oldItems reverseDo:[:anOldItem|
"/ remove no longer valid files
(newItems detectLast:[:aNewItem| aNewItem = anOldItem] ifNone:nil) isNil ifTrue:[
remItems add:anOldItem.
oldItems removeIdentical:anOldItem
]
].
].
"/ add new files
newItems do:[:aNewItem|
(oldItems detect:[:anOldItem| anOldItem = aNewItem] ifNone:nil) isNil ifTrue:[
addItems add:aNewItem.
]
].
theAllItems := self allItems.
remItems notEmpty ifTrue:[
theAllItems removeAll:remItems
].
addItems do:[: aNewItem |
(theAllItems includes:aNewItem) not ifTrue:[
theAllItems add:aNewItem.
]
].
self
enqueueMessage:#value
for:[
self browserItemListAdd:addItems remove:remItems.
]
arguments:#().
filteredItems := newItems.
!
evaluateFilter:aItemsList
|showDir filterBlock newItemList noOfAddedFiles noOfFiles|
newItemList := OrderedCollection new.
noOfFiles := 0.
noOfAddedFiles := 0.
showDir := self viewDirsInContentsBrowser value.
filterBlock := self matchBlock.
aItemsList size ~~ 0 ifTrue:[
aItemsList do:[:aItem | |isDir|
isDir := aItem isDirectory.
isDir not ifTrue:[noOfFiles := noOfFiles + 1].
((isDir and:[showDir]) or:[isDir not and:[filterBlock value:aItem baseName]]) ifTrue:[
isDir not ifTrue:[noOfAddedFiles := noOfAddedFiles + 1].
newItemList add:aItem
]
].
].
self noOfAddedFiles:noOfAddedFiles noOfFiles:noOfFiles.
^ newItemList
!
filterChanged
filteredItems := self evaluateFilter:self allItems copy.
filteredItems sort:self sortBlockHolder value.
self
enqueueMessage:#value
for:[
self setBrowserItemList:filteredItems
]
arguments:nil.
!
readDirectoryItems
| list contents|
list := OrderedCollection new.
directory notNil ifTrue:[
directory exists ifFalse:[ ^ list ].
contents := DirectoryContents directoryNamed:directory.
contents itemsDo:[:aItem|
list add:(DirectoryContentsBrowser itemClass forInfoItem:aItem).
].
].
^ list
!
sortBlockChanged
filteredItems isNil ifTrue:[ ^ self].
filteredItems sort:self sortBlockHolder value.
self
enqueueMessage:#value
for:[
self setBrowserItemList:filteredItems
]
arguments:nil.
!
startUpdateTask
updateTask isNil ifTrue:[
updateTask := [
[true] whileTrue:[
self updateStep
]
] newProcess.
updateTask name:'DirectoryContentsBrowser updateTask'.
updateTask priorityRange:(Processor systemBackgroundPriority to:Processor activePriority).
updateTask restartable:true.
updateTask resume.
].
!
stopUpdateTask
updateTask notNil ifTrue:[
updateTask terminate.
].
!
updateBlock
^ [ : timeOut |
"/ Transcript showCR:'START'.
self isBusy:true.
[
self directoryChangeFlag ifTrue:[
self directoryChangeFlag:false.
self debugMessage:'directoryChanged'.
self directoryChanged.
].
self directoryContentsChangeFlag ifTrue:[
self directoryContentsChangeFlag:false.
self debugMessage:'directoryContentsChanged'.
self directoryContentsChanged.
].
self filterChangeFlag ifTrue:[
self filterChangeFlag:false.
self debugMessage:'filterChanged'.
self filterChanged.
].
self sortBlockChangeFlag ifTrue:[
self sortBlockChangeFlag:false.
self debugMessage:'sortBlockChanged'.
self sortBlockChanged.
].
timeOut ifTrue:[
self debugMessage:'evaluate modification'.
self modificationCycle
].
self updateColumnsCycle ifTrue:[
self debugMessage:'next time another columns update'.
self changeSema signal
].
] ensure:[
self isBusy:false.
].
"/ Transcript showCR:'STOP'.
]
!
updateStep
AbortSignal handle:[
self debugMessage:'get an abort signal'.
self directoryContentsChangeFlag:false.
self filterChangeFlag:false.
self sortBlockChangeFlag:false.
] do:[
| timeOut |
self debugMessage:'sema wait'.
timeOut := (self changeSema waitWithTimeoutMs:(self class updateTaskCyleTime)) isNil.
self debugMessage:'timeOut:', timeOut asString.
(self filterChangeFlag or:[self sortBlockChangeFlag or:[self directoryChangeFlag]]) ifTrue:[
| oldCursor |
oldCursor := self window cursor.
self showCursor:(Cursor execute).
self updateBlock value:timeOut.
self showCursor:oldCursor.
] ifFalse:[
self updateBlock value:timeOut.
]
]
! !
!DirectoryContentsBrowser methodsFor:'update task trigger'!
wakeUp
self changeSema signal.
!
wakeUpForDirectoryChanged
self isBusy ifTrue:[
updateTask interruptWith:[AbortSignal raise].
].
self directoryChangeFlag:true.
self wakeUp.
!
wakeUpForDirectoryContentsChanged
self directoryContentsChangeFlag:true.
self wakeUp.
!
wakeUpForFilterChanged
self filterChangeFlag:true.
self wakeUp.
!
wakeUpForSortBlockChanged
self sortBlockChangeFlag:true.
self wakeUp.
! !
!DirectoryContentsBrowser::DirectoryContentsItem class methodsFor:'instance creation'!
fileName:aFilename
| instance fileItem|
instance := self new.
aFilename asString = '..' ifTrue:[
instance fileName:aFilename.
^ instance.
].
fileItem := DirectoryContents contentsItemForFileName:aFilename.
fileItem notNil ifTrue:[^ self forInfoItem:fileItem].
^ nil
"
DirectoryContentsItem fileName:'..'
"
!
forInfoItem:anItem
| instance |
instance := self new.
instance fileName:anItem fileName.
anItem isRemoteDirectory ifTrue:[
instance beRemoteDirectory.
] ifFalse:[
instance fileInfo:anItem info.
].
^ instance
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'accessing'!
fileInfo:something
"set the value of the instance variable 'fileInfo' (automatically generated)"
fileInfo := something.
!
fileName
"returns the fileName
"
^ fileName
!
fileName:aFilename
"set fileName for instance
"
fileName := aFilename asFilename.
!
fileType
"returns the type of the file
"
fileType isNil ifTrue:[
fileType := ''.
].
^ 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
self isRemoteDirectory ifTrue:[^ true].
self getFileInfo.
fileInfo isNil ifTrue:[^ false].
^ fileInfo isDirectory
!
isSymbolicLink
self isRemoteDirectory ifTrue:[^ false].
self getFileInfo.
fileInfo isNil ifTrue:[^ false].
^ fileInfo isSymbolicLink
!
lastButOneSuffix
"returns the suffix of the file
"
^ self suffixes at:2
!
lastSuffix
"returns the suffix of the file
"
^ self suffixes at:1
!
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
!
preview
^ preview
!
preview:aLabel
preview := aLabel.
!
suffix
"returns the suffix of the file
"
self isDirectory ifTrue:[^''].
suffix isNil ifTrue:[
(OperatingSystem isUNIXlike and:[(self baseName at:1) == $.]) ifTrue:[
suffix := ''.
] ifFalse:[
suffix := fileName suffix.
]
].
^ suffix
!
suffixes
| lastSuff lastButOneSuff|
(fileName name occurrencesOf:$.) <= 1 ifTrue:[
^ Array with:(self suffix) with:nil.
].
(fileName baseName occurrencesOf:$.) <= 1 ifTrue:[
^ Array with:(self suffix) with:nil.
].
((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.
]
].
^ Array with:lastSuff with:lastButOneSuff
!
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
]
!
resetItemForChanges
" dont know what someone else is doing with the file - read all item properties new "
fileInfo := nil.
icon := nil.
fileType := nil.
preview := nil.
owner := nil.
group := nil.
iconKey := nil.
mimeTypeForContents := nil.
mimeType := nil.
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'change queries'!
hasBeenModified
"check if item modification time is changed
"
| time info|
self isRemoteDirectory ifTrue:[^ false].
info := fileName info.
info isNil ifTrue:[ ^ false].
time := info modificationTime.
contentsBrowserChangeModificationTime isNil ifTrue:[
contentsBrowserChangeModificationTime := time.
fileInfo := nil.
^ false.
].
((contentsBrowserChangeModificationTime = time) not) ifTrue:[
contentsBrowserChangeModificationTime := time.
fileInfo := nil.
^ 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:'presentation'!
baseName
"returns the baseName of the file
"
^ fileName baseName.
!
baseNameWithOutSuffix
"returns the baseName of the file
"
| baseNameWithOutSuff |
self isDirectory ifTrue:[^ self baseName].
baseNameWithOutSuff := self baseName asFilename withoutSuffix asString.
(baseNameWithOutSuff isEmpty or:[baseNameWithOutSuff = '.']) ifTrue:[
^ self baseName
].
^ baseNameWithOutSuff.
!
date
"returns the modTimeString
"
| modTime |
modTime := self modificationTime.
modTime isNil ifTrue:[
^ '???'
].
^ modTime asDate printString.
!
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
!
fileSize
"returns the fileSize
"
self getFileInfo.
fileInfo isNil ifTrue:[^ nil].
^ fileInfo fileSize
!
group
"returns the printable group
"
|gid|
group isNil ifTrue:[
self getFileInfo.
fileInfo isNil ifTrue:[^ '???'].
gid := fileInfo gid.
(LastGIDToGroupNameMapping notNil and:[gid == LastGIDToGroupNameMapping key]) ifTrue:[
group := LastGIDToGroupNameMapping value
] ifFalse:[
group := OperatingSystem getGroupNameFromID:gid.
LastGIDToGroupNameMapping := gid -> group.
]
].
^ group
!
modificationTime
"returns the absolute time of modification
"
self getFileInfo.
fileInfo isNil ifTrue:[^ nil].
^ fileInfo modificationTime
!
owner
"returns the printable owner
"
|uid|
owner isNil ifTrue:[
self getFileInfo.
fileInfo isNil ifTrue:[^ '???'].
uid := fileInfo uid.
(LastUIDToUserNameMapping notNil and:[uid == LastUIDToUserNameMapping key]) ifTrue:[
owner := LastUIDToUserNameMapping value
] ifFalse:[
owner := OperatingSystem getUserNameFromID:uid.
LastUIDToUserNameMapping := uid -> owner.
]
].
^ owner
!
permissions
"returns the permissions as printable string
"
|mode permissionString|
self getFileInfo.
fileInfo isNil ifTrue:[^ '???'.].
mode := fileInfo mode.
permissionString := String new:9 withAll:$-.
1 to:9 by:3 do:[:i|
(mode bitAt:i ) == 1 ifTrue:[permissionString at:10 - i put:$x].
(mode bitAt:i + 1) == 1 ifTrue:[permissionString at:9 - i put:$w].
(mode bitAt:i + 2) == 1 ifTrue:[permissionString at:8 - i put:$r].
].
^ permissionString
!
printString
^ 'a DirectoryContentsItem [', fileName asString, ']'
!
sizeString
"returns the size of the file
"
| unitString n locSize|
locSize := self fileSize.
locSize isNil ifTrue:[^ '???'].
unitString := UnitConverter fileSizeStringFor:locSize.
^ unitString withoutSeparators "/ leftPaddedTo:8.
"/ unitString := ''.
"/ 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'
"/ ].
"/ ^ (n printStringLeftPaddedTo:5) , unitString.
!
timeAndDate
"returns the date
"
|modTime|
modTime := self modificationTime.
modTime isNil ifTrue:[
^ '???'
].
Smalltalk languageTerritory == #us ifTrue:[
^ modTime printStringFormat:'%(ShortMonthName), %(dayPadded) %(yearOrTime)'.
].
^ modTime printStringFormat:'%(day)-%(ShortMonthName) %(yearOrTime)'.
"/ ^ modTime printStringFormat:'%(year)-%(mon)-%(day) %h:%m:%s'.
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'private'!
getFileInfo
fileInfo isNil ifTrue:[
self isRemoteDirectory ifTrue:[
"/ do not access, to avoid automount
] ifFalse:[
fileInfo := fileName linkInfo.
fileInfo isNil ifTrue:[
fileInfo := fileName info.
].
].
].
^ fileInfo
! !
!DirectoryContentsBrowser::DirectoryContentsItem methodsFor:'queries'!
beRemoteDirectory
fileType := #remoteDirectory.
!
exists
"returns the fileName
"
^ fileName exists
!
hasMimeType
^ (self mimeType ~= #unknown)
!
isRemoteDirectory
^ fileType == #remoteDirectory
!
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.69 2002-12-28 14:52:20 cg Exp $'
! !