Hi Marcel,<br>
<br>
thanks for the feedback! Revised again and merged. :-)<br>
<br>
> Browser>>updateCodePaneIfNeeded<br>
> CodeHolder>>updateCodePaneIfNeeded<br>
> <br>
> Why is that in there?<br>
<br>
Just a changeset slip, which I have resolved now.<br>
<br>
Best,<br>
Christoph<br>
<br>
<font color="#808080">---<br>
</font><font color="#808080"><i>Sent from </i></font><font color="#808080"><i><a href="https://github.com/hpi-swa-lab/squeak-inbox-talk"><u><font color="#808080">Squeak Inbox Talk</font></u></a></i></font><br>
<br>
On 2022-07-07T10:57:30+02:00, marcel.taeumel@hpi.de wrote:<br>
<br>
> Hi Christoph --<br>
> <br>
> Thanks! Looks good except maybe for:<br>
> <br>
> Browser>>updateCodePaneIfNeeded<br>
> CodeHolder>>updateCodePaneIfNeeded<br>
> <br>
> Why is that in there?<br>
> <br>
> Maybe give your changes a fresh look with our own eyes again. And then improve the code with what you learned during the last 5 weeks. :-D<br>
> <br>
> Best,<br>
> Marcel<br>
> Am 20.05.2022 16:31:16 schrieb christoph.thiede at student.hpi.uni-potsdam.de <christoph.thiede at student.hpi.uni-potsdam.de>:<br>
> Feel free to try this out already and give feedback, but given that this includes new features, it will not be merged before the next release. :-)<br>
> <br>
> Best,<br>
> Christoph<br>
> <br>
> =============== Summary ===============<br>
> <br>
> Change Set: polish-file-dialogs<br>
> Date: 20 May 2022<br>
> Author: Christoph Thiede<br>
> <br>
> Cleans up, tests, and improves the convenience of file selection dialogs.<br>
> <br>
> UI improvements:<br>
> * Add input field for file path to all dialogs. In file dialogs, a directory path can be entered to navigate to the relevant directory in the tree.<br>
> * Update enablement of canAccept button based on input<br>
> * Improve automatic selection of filenames<br>
> * Use explicit help texts instead of filling the input field with a help message<br>
> * Fixes handling of patterns/suffixes in save dialog<br>
> * Double click a file/directory to choose it<br>
> * Save dialog: Assure that the name of an existing directory cannot be chosen as a new file name<br>
> * Small MVC improvements (however, modal invocation in MVC is still broken at the moment)<br>
> <br>
> Refactoring:<br>
> * Overall deduplication<br>
> * Consistent spelling of fileName (instead of filename)<br>
> <br>
> =============== Diff ===============<br>
> <br>
> Browser>>updateCodePaneIfNeeded {self-updating} · ct 5/20/2022 13:00<br>
> + updateCodePaneIfNeeded<br>
> +<br>
> + super updateCodePaneIfNeeded.<br>
> + <br>
> + (self didCodeChangeElsewhere and: [self hasUnacceptedEdits not])<br>
> + ifTrue:<br>
> + [self setClassDefinition.<br>
> + self contentsChanged].<br>
> <br>
> CodeHolder>>updateCodePaneIfNeeded {self-updating} · sw 2/14/2001 15:34 (changed)<br>
> updateCodePaneIfNeeded<br>
> "If the code for the currently selected method has changed underneath me, then update the contents of my code pane unless it holds unaccepted edits"<br>
> <br>
> self didCodeChangeElsewhere<br>
> ifTrue:<br>
> [self hasUnacceptedEdits<br>
> ifFalse:<br>
> [self setContentsToForceRefetch.<br>
> self contentsChanged]<br>
> ifTrue:<br>
> [self changed: #codeChangedElsewhere]]<br>
> <br>
> DirectoryChooserDialog (source same but rev changed)<br>
> FileAbstractSelectionDialog subclass: #DirectoryChooserDialog<br>
> instanceVariableNames: ''<br>
> classVariableNames: ''<br>
> poolDictionaries: ''<br>
> category: 'ToolBuilder-Morphic-Tools'<br>
> <br>
> DirectoryChooserDialog class<br>
> instanceVariableNames: ''<br>
> <br>
> "A DirectoryChooserDialog is a modal dialog to allow choosing a directory. The actual directory chosen is returned, or nil if no selection was made.<br>
> <br>
> Normal usage would be<br>
> myDirectory := DirectoryChooserDialog openOn: myApplicationDefaultDirectory label: 'Choose the directory to use'<br>
> "<br>
> <br>
> DirectoryChooserDialog>>acceptDirectory: {directory tree} · ct 5/20/2022 12:11<br>
> + acceptDirectory: dir<br>
> +<br>
> + self setDirectoryTo: dir.<br>
> + self acceptFileName.<br>
> <br>
> DirectoryChooserDialog>>acceptFileName {accessing} · ct 5/20/2022 11:47 (changed and recategorized)<br>
> acceptFileName<br>
> "User clicked to accept the current state so save the directory and close the dialog"<br>
> <br>
> + self canAccept ifFalse: [^ false].<br>
> finalChoice := directory.<br>
> - self changed: #close<br>
> + self changed: #close.<br>
> + ^ true<br>
> <br>
> DirectoryChooserDialog>>buildDirectoryTreeWith: {toolbuilder} · ct 5/20/2022 12:10 (changed)<br>
> buildDirectoryTreeWith: builder<br>
> <br>
> ^ (super buildDirectoryTreeWith: builder)<br>
> hScrollBarPolicy: #never; "Use the dialog grips to see more"<br>
> + doubleClick: #acceptDirectory:;<br>
> yourself<br>
> <br>
> DirectoryChooserDialog>>buildWith: {toolbuilder} · ct 5/19/2022 18:10 (changed)<br>
> buildWith: builder<br>
> "assemble the spec for the chooser dialog UI"<br>
> <br>
> | windowSpec window |<br>
> windowSpec := self buildWindowWith: builder specs: {<br>
> - (self frameOffsetFromTop: 0<br>
> + (self topConstantHeightFrame: self textViewHeight<br>
> fromLeft: 0<br>
> + width: 1) -> [self buildTextInputWith: builder].<br>
> + (self frameOffsetFromTop: self textViewHeight<br>
> + fromLeft: 0<br>
> width: 1<br>
> offsetFromBottom: 0) -> [self buildDirectoryTreeWith: builder].<br>
> }.<br>
> windowSpec buttons addAll: ( self buildButtonsWith: builder ).<br>
> window := builder build: windowSpec.<br>
> - window addKeyboardCaptureFilter: self.<br>
> + (window respondsTo: #addKeyboardCaptureFilter: ) ifTrue: [<br>
> + window addKeyboardCaptureFilter: self].<br>
> self changed: #selectedPath.<br>
> ^window<br>
> <br>
> <br>
> DirectoryChooserDialog>>canAccept {accessing} · ct 5/19/2022 18:03<br>
> + canAccept<br>
> +<br>
> + ^ directory notNil and: [directory exists]<br>
> <br>
> DirectoryChooserDialog>>inputText {filename} · ct 5/19/2022 17:40<br>
> + inputText<br>
> +<br>
> + ^ directory fullName<br>
> <br>
> DirectoryChooserDialog>>inputText: {filename} · ct 5/20/2022 12:52<br>
> + inputText: aText<br>
> +<br>
> + ^ self selectFileName: aText<br>
> <br>
> DirectoryChooserDialog>>selectFileName: {filename} · ct 5/20/2022 13:19<br>
> + selectFileName: aStringOrText<br>
> +<br>
> + aStringOrText ifNil: [^ self].<br>
> + self directory: ([FileDirectory on: aStringOrText asString] ifError: [^ self]).<br>
> + isUpdating := true.<br>
> + [self changed: #selectedPath]<br>
> + ensure: [isUpdating := false].<br>
> + self updateFileList.<br>
> + self changed: #canAccept.<br>
> <br>
> DirectoryChooserDialogTest<br>
> + nil subclass: #DirectoryChooserDialogTest<br>
> + instanceVariableNames: ''<br>
> + classVariableNames: ''<br>
> + poolDictionaries: ''<br>
> + category: 'MorphicTests-ToolBuilder'<br>
> +<br>
> + DirectoryChooserDialogTest class<br>
> + instanceVariableNames: ''<br>
> +<br>
> + ""<br>
> <br>
> DirectoryChooserDialogTest>>expectedFailures {failures} · ct 5/19/2022 22:16<br>
> + expectedFailures<br>
> +<br>
> + self flag: #todo. "Can only be debugged, but not run - this raises an InvalidDirectoryError which's defaultAction handles the exception silently. Should this class be a Notification instead?"<br>
> + ^ #(testChooseAbsentDirectory testTypeAndChooseAbsentDirectory)<br>
> <br>
> DirectoryChooserDialogTest>>testChooseAbsentDirectory {tests - interface} · ct 5/20/2022 12:53<br>
> + testChooseAbsentDirectory<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog acceptFileName: (self pathForFile: 'nurp').<br>
> + <br>
> + self assert: nil equals: result.<br>
> <br>
> DirectoryChooserDialogTest>>testChooseDefault {tests - interactions} · ct 5/19/2022 21:52<br>
> + testChooseDefault<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: mockDirectory equals: result.<br>
> <br>
> DirectoryChooserDialogTest>>testChooseDirectory {tests - interface} · ct 5/20/2022 12:53<br>
> + testChooseDirectory<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog acceptFileName: mockChildDirectory fullName.<br>
> + <br>
> + self assert: mockChildDirectory equals: result.<br>
> <br>
> DirectoryChooserDialogTest>>testNewDirectory {tests - interface} · ct 5/19/2022 23:57<br>
> + testNewDirectory<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + [dialog newDirectoryName] valueSupplyingAnswer: #('*name*' 'nurp').<br>
> + self assert: (mockDirectory directoryExists: 'nurp').<br>
> + self assert: mockDirectory / 'nurp' equals: dialog directory.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: mockDirectory / 'nurp' equals: result.<br>
> <br>
> DirectoryChooserDialogTest>>testSelectAndChooseDirectory {tests - interactions} · ct 5/19/2022 21:54<br>
> + testSelectAndChooseDirectory<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog setDirectoryTo: (dialog subDirectoriesOf: mockDirectory) first.<br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: mockChildDirectory equals: result.<br>
> <br>
> DirectoryChooserDialogTest>>testTypeAndChooseAbsentDirectory {tests - interactions} · ct 5/20/2022 12:52<br>
> + testTypeAndChooseAbsentDirectory<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog selectFileName: (self pathForDirectory: mockDirectory file: 'twin').<br>
> + self deny: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: nil equals: result.<br>
> <br>
> DirectoryChooserDialogTest>>testTypeAndChooseDirectory {tests - interactions} · ct 5/20/2022 12:53<br>
> + testTypeAndChooseDirectory<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog selectFileName: mockChildDirectory fullName.<br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: mockChildDirectory equals: result.<br>
> <br>
> FileAbstractSelectionDialog (changed)<br>
> Model subclass: #FileAbstractSelectionDialog<br>
> - instanceVariableNames: 'patternList directory directoryCache message listIndex fileName finalChoice nameList sizeList dateList suffixList'<br>
> + instanceVariableNames: 'patternList directory directoryCache message listIndex fileName finalChoice nameList sizeList dateList suffixList isUpdating'<br>
> classVariableNames: ''<br>
> poolDictionaries: ''<br>
> category: 'ToolBuilder-Morphic-Tools'<br>
> <br>
> FileAbstractSelectionDialog class<br>
> instanceVariableNames: ''<br>
> <br>
> "FileAbstractSelectionDialog is the abstract superclass for the file chooser & saver modal dialogs.<br>
> <br>
> The UI provides a message to the user, a text input field, a directory tree widget and a list of files within any chosen directory, and buttons to accept the selected file name/path or cancel the operation. See subclass comments and class side methods for specific usage examples.<br>
> <br>
> Instance Variables<br>
> directory: <FileDirectory> used for the currently selected directory<br>
> directoryCache: <WeakIdentityKeyDictionary> used to cache a boolean to help us more quickly populate the directory tree widget when revisiting a directory<br>
> fileName: <String|nil> the name of the currently selected file, if any<br>
> finalChoice: <String|nil> pathname of the finally chosen file, returned as the result of accepting; nil is returned otherwise<br>
> list: <Array> the list of String of filenames (and date/size) that match the current pattern<br>
> listIndex: <Integer> list index of the currently selected file<br>
> patternList: <OrderedCollection of String> the patterns are held as a collection of string that may include * or # wildcards. See FileAbstractSelectionDialog>>#parsePatternString for details<br>
> message: <String> a message to the user to explain what is expected<br>
> nameList,DateList, sizeList: <Array> the list of file names matching the pattern and the appropriate date and size values, formatted for a PluggableMultiColumnListMorph"<br>
> <br>
> FileAbstractSelectionDialog class>>todo {documentation} · ct 5/20/2022 12:46<br>
> + todo<br>
> +<br>
> + self flag: #forLater. "Possible future adventures for the file dialogs:<br>
> + <br>
> + * Allow users to enter patterns with stars to filter the current fileList (as known from Microsoft Windows file dialogs)<br>
> + * Add support for multiple file selection<br>
> + * Add MVC support (currently, modal dialog invocations windows seems not to work there). See also existing #mvc flag.<br>
> + * Normalize paths with parentDirectoryNickname"<br>
> <br>
> FileAbstractSelectionDialog>>acceptFileName {accessing} · ct 5/20/2022 12:32 (changed and recategorized)<br>
> acceptFileName<br>
> - "User clicked to accept the current state so save the filename and close the dialog"<br>
> <br>
> - finalChoice := fileName.<br>
> - self changed: #close<br>
> + self canAccept ifFalse: [^ false].<br>
> + self checkOrCorrectSuffix ifFalse: [^ false].<br>
> + ^ self basicAcceptFileName<br>
> <br>
> FileAbstractSelectionDialog>>acceptFileName: {filename} · ct 5/20/2022 12:52<br>
> + acceptFileName: aStringOrText<br>
> +<br>
> + self selectFileName: aStringOrText.<br>
> + ^ self acceptFileName<br>
> <br>
> FileAbstractSelectionDialog>>basicAcceptFileName {accessing} · ct 5/20/2022 12:32<br>
> + basicAcceptFileName<br>
> + "Accept the file name without checking for patterns or suffices."<br>
> +<br>
> + self canAccept ifFalse: [^ false].<br>
> + finalChoice := fileName.<br>
> + self changed: #close.<br>
> + ^ true<br>
> <br>
> FileAbstractSelectionDialog>>basicAcceptFileName: {filename} · ct 5/20/2022 12:54<br>
> + basicAcceptFileName: aStringOrText<br>
> + "Allow the user to press Cmd + S instead of enter to enforce a file name that does not match the pattern/suffx requirements."<br>
> +<br>
> + self selectFileName: aStringOrText.<br>
> + ^ self basicAcceptFileName<br>
> <br>
> FileAbstractSelectionDialog>>buildButtonsWith: {toolbuilder} · ct 5/19/2022 14:06 (changed)<br>
> buildButtonsWith: builder<br>
> <br>
> ^ {<br>
> builder pluggableButtonSpec new<br>
> model: self;<br>
> label: 'Accept' translated;<br>
> color: (self userInterfaceTheme get: #okColor for: #DialogWindow);<br>
> - action: #acceptFileName.<br>
> + action: #acceptFileName;<br>
> + enabled: #canAccept;<br>
> + yourself.<br>
> builder pluggableButtonSpec new<br>
> model: self;<br>
> label: 'Cancel' translated;<br>
> color: (self userInterfaceTheme get: #cancelColor for: #DialogWindow);<br>
> - action: #cancelFileChooser}<br>
> + action: #cancelFileChooser;<br>
> + yourself}<br>
> <br>
> FileAbstractSelectionDialog>>buildDirectoryTreeWith: {toolbuilder} · mt 2/10/2022 10:13 (changed)<br>
> buildDirectoryTreeWith: builder<br>
> | treeSpec |<br>
> treeSpec := builder pluggableTreeSpec new.<br>
> treeSpec<br>
> model: self ;<br>
> roots: #rootDirectoryList ;<br>
> hasChildren: #hasMoreDirectories: ;<br>
> getChildren: #subDirectoriesOf: ;<br>
> getSelectedPath: #selectedPath ;<br>
> setSelected: #setDirectoryTo: ;<br>
> getSelected: #directory;<br>
> label: #directoryNameOf: ;<br>
> menu: nil ;<br>
> autoDeselect: false .<br>
> ^ treeSpec<br>
> <br>
> FileAbstractSelectionDialog>>buildFileListWith: {toolbuilder} · ct 5/20/2022 12:08 (changed)<br>
> - buildFileListWith: builder<br>
> + buildFileListWith: builder<br>
> +<br>
> | listSpec |<br>
> listSpec := builder pluggableListSpec new.<br>
> listSpec<br>
> - model: self ;<br>
> - list: #fileList ;<br>
> - getIndex: #fileListIndex ;<br>
> - setIndex: #fileListIndex: ;<br>
> - menu: nil ;<br>
> - keyPress: nil ;<br>
> - frame:<br>
> - (self<br>
> - frameOffsetFromTop:0<br>
> - fromLeft: 0<br>
> - width: 1<br>
> - bottomFraction: 1) .<br>
> - ^listSpec<br>
> + model: self;<br>
> + list: #fileList;<br>
> + getIndex: #fileListIndex;<br>
> + setIndex: #fileListIndex:;<br>
> + doubleClick: #acceptFileName;<br>
> + keyPress: nil;<br>
> + frame:<br>
> + (self<br>
> + frameOffsetFromTop:0<br>
> + fromLeft: 0<br>
> + width: 1<br>
> + bottomFraction: 1).<br>
> + ^ listSpec<br>
> <br>
> FileAbstractSelectionDialog>>buildTextInputWith: {toolbuilder} · ct 5/20/2022 13:04 (changed)<br>
> buildTextInputWith: builder<br>
> | textSpec |<br>
> textSpec := builder pluggableInputFieldSpec new.<br>
> textSpec<br>
> model: self;<br>
> name: #inputText ;<br>
> - font: self textViewFont;<br>
> getText: #inputText;<br>
> - setText: #selectFilename:;<br>
> - selection: #contentsSelection.<br>
> - ^textSpec<br>
> + editText: #selectFileName:;<br>
> + setText: #basicAcceptFileName:;<br>
> + selection: #contentsSelection;<br>
> + help: 'Enter a filename here or choose from list' translated.<br>
> + ^textSpec<br>
> <br>
> <br>
> FileAbstractSelectionDialog>>buildWith: {toolbuilder} · ct 5/19/2022 23:58 (changed)<br>
> buildWith: builder<br>
> - "assemble the spec for the common chooser/saver dialog UI"<br>
> <br>
> - ^self subclassResponsibility<br>
> + | windowSpec window |<br>
> + windowSpec := self buildWindowWith: builder specs: {<br>
> + (self topConstantHeightFrame: self textViewHeight<br>
> + fromLeft: 0<br>
> + width: 1) -> [self buildTextInputWith: builder].<br>
> + (self frameOffsetFromTop: self textViewHeight<br>
> + fromLeft: 0.35<br>
> + width: 0.65<br>
> + offsetFromBottom: 0) -> [self buildFileListWith: builder].<br>
> + (self frameOffsetFromTop: self textViewHeight<br>
> + fromLeft: 0<br>
> + width: 0.35<br>
> + offsetFromBottom: 0) -> [self buildDirectoryTreeWith: builder].<br>
> + }.<br>
> + windowSpec buttons addAll: ( self buildButtonsWith: builder ).<br>
> + window := builder build: windowSpec.<br>
> + (window respondsTo: #addKeyboardCaptureFilter:) ifTrue: [<br>
> + window addKeyboardCaptureFilter: self].<br>
> + self changed: #selectedPath.<br>
> + self inputText: fileName.<br>
> + (window respondsTo: #positionOverWidgetNamed:) ifTrue: [<br>
> + window positionOverWidgetNamed: #inputText].<br>
> + ^window<br>
> <br>
> FileAbstractSelectionDialog>>canAccept {accessing} · ct 5/20/2022 11:53<br>
> + canAccept<br>
> +<br>
> + ^ fileName isEmptyOrNil not<br>
> + and: [self directory fileExists: fileName]<br>
> <br>
> FileAbstractSelectionDialog>>cancelFileChooser {accessing} · tpr 12/23/2017 12:35 (changed and recategorized)<br>
> cancelFileChooser<br>
> "User clicked to cancel the current state so nil the filename and close the dialog"<br>
> <br>
> directory := finalChoice := fileName := nil.<br>
> self changed: #close.<br>
> <br>
> FileAbstractSelectionDialog>>checkOrCorrectSuffix {filename} · ct 5/20/2022 12:33<br>
> + checkOrCorrectSuffix<br>
> +<br>
> + ^ patternList anySatisfy: [:each |<br>
> + each match: fileName "caseSensitive: FileDirectory default isCaseSensitive"]<br>
> <br>
> FileAbstractSelectionDialog>>contentsSelection {toolbuilder} · ct 5/20/2022 13:18<br>
> + contentsSelection<br>
> + "Initial selection covers entire initial file name/path if any"<br>
> +<br>
> + ^ 1 to: (self inputText ifNil: [0] ifNotNil: #size)<br>
> <br>
> FileAbstractSelectionDialog>>directory {directory tree} · tpr 11/21/2017 09:22 (changed)<br>
> directory<br>
> "If nobody has set a specific directory we need a plausible default"<br>
> <br>
> ^ directory ifNil: [ directory := FileDirectory default]<br>
> <br>
> FileAbstractSelectionDialog>>directory: {directory tree} · tpr 11/20/2017 18:15 (changed)<br>
> directory: aFileDirectory<br>
> "Set the path of the directory to be displayed in the directory tree pane"<br>
> <br>
> directory := aFileDirectory<br>
> <br>
> FileAbstractSelectionDialog>>entriesMatching: {file list} · ct 5/20/2022 12:44 (changed)<br>
> entriesMatching: patternList<br>
> "Answer a list of directory entries which match any of the patterns.<br>
> See #parsePatternString for the pattern rules"<br>
> <br>
> | entries |<br>
> - "This odd clause helps supports MVC projects; the file list & directory views are built from a list that includes directories. In Morphic we filter out the directories because they are entirely handled by the direcctory tree morph"<br>
> entries := Smalltalk isMorphic<br>
> - ifTrue:[self directory fileEntries ]<br>
> - ifFalse:[self directory entries].<br>
> -<br>
> + ifTrue: [self directory fileEntries]<br>
> + ifFalse:<br>
> + [self flag: #mvc. "This odd clause helps supports MVC projects; the file list & directory views are built from a list that includes directories. In Morphic we filter out the directories because they are entirely handled by the direcctory tree morph"<br>
> + self directory entries copyWith:<br>
> + (self directory entryAt: self directory class parentDirectoryNickname)].<br>
> + <br>
> (patternList anySatisfy: [:each | each = '*'])<br>
> ifTrue: [^ entries].<br>
> <br>
> - ^ entries select: [:entry | patternList anySatisfy: [:each | each match: entry name]]<br>
> + ^ entries select: [:entry |<br>
> + patternList anySatisfy: [:each |<br>
> + entry isDirectory or: [each match: entry name]]]<br>
> <br>
> FileAbstractSelectionDialog>>fileListIndex: {file list} · ct 5/20/2022 12:05 (changed)<br>
> fileListIndex: anInteger<br>
> "We've selected the file at the given index, so find the file name."<br>
> <br>
> self okToChange ifFalse: [^ self].<br>
> listIndex := anInteger.<br>
> - listIndex = 0<br>
> - ifTrue: [fileName := nil]<br>
> - ifFalse: [fileName := nameList at: anInteger]. "open the file selected"<br>
> -<br>
> + fileName := nameList at: anInteger ifAbsent: [nil].<br>
> + <br>
> + (fileName notNil and: [self directory directoryExists: fileName]) ifTrue:<br>
> + [self flag: #mvc. "file list contains directories"<br>
> + self setDirectoryTo: (self directory on: (self directory entryAt: fileName) fullName).<br>
> + self changed: #selectedPath.<br>
> + fileName := nil].<br>
> + <br>
> self<br>
> changed: #fileListIndex;<br>
> - changed: #inputText<br>
> + changed: #inputText;<br>
> + changed: #canAccept.<br>
> <br>
> FileAbstractSelectionDialog>>finalChoice {accessing} · tpr 12/23/2017 12:33 (changed and recategorized)<br>
> finalChoice<br>
> "return the chosen directory/filename that was saved by an accept click or nil; client must check for validity"<br>
> ^ finalChoice<br>
> ifNotNil: [self directory fullNameFor: finalChoice]<br>
> <br>
> FileAbstractSelectionDialog>>initialize {initialize-release} · ct 5/19/2022 17:55 (changed)<br>
> initialize<br>
> super initialize.<br>
> directoryCache := WeakIdentityKeyDictionary new.<br>
> listIndex := 0.<br>
> patternList := self defaultPatternList.<br>
> - suffixList := OrderedCollection new<br>
> + suffixList := OrderedCollection new.<br>
> + isUpdating := false.<br>
> <br>
> FileAbstractSelectionDialog>>listForPatterns: {path and pattern} · ct 5/19/2022 22:18 (changed)<br>
> listForPatterns: arrayOfPatterns<br>
> "build lists of name, date and size for those file names which match any of the patterns in the array.<br>
> We use a Set to avoid duplicates and sort them by name"<br>
> <br>
> | newList |<br>
> newList := Set new.<br>
> newList addAll: (self entriesMatching: arrayOfPatterns).<br>
> <br>
> newList := newList sorted: [:a :b|<br>
> a name <= b name].<br>
> nameList := newList collect:[:e| e name].<br>
> + <br>
> + self flag: #dead. "dates and sizes are not in use"<br>
> dateList := newList collect:[:e| ((Date fromSeconds: e modificationTime )<br>
> printFormat: #(3 2 1 $. 1 1 2)) , ' ' ,<br>
> (String streamContents: [:s |<br>
> (Time fromSeconds: e modificationTime \\ 86400)<br>
> print24: true on: s])].<br>
> - sizeList := newList collect:[:e| e fileSize asStringWithCommas]<br>
> + sizeList := newList collect:[:e| e fileSize asStringWithCommas].<br>
> <br>
> <br>
> FileAbstractSelectionDialog>>newDirectoryName {directory tree} · ct 5/19/2022 21:43 (changed)<br>
> newDirectoryName<br>
> "Create a new directory; will be a subdirectory of the current chosen directory.<br>
> If the user input is empty, or if the directory creation fails, fail this method.<br>
> Update the directory tree display afterwards and set the current directory to the newly created directory"<br>
> |userInput|<br>
> - userInput := UIManager default request: 'New directory name' translated initialAnswer: 'newDir'.<br>
> + userInput := Project uiManager request: 'New directory name' translated initialAnswer: 'newDir'.<br>
> userInput isEmptyOrNil ifTrue: [^nil].<br>
> <br>
> [self directory createDirectory: userInput] ifError:[^nil]. "I hate using ifError: - it's so indiscriminate. Really ought to be a more precise error to catch properly"<br>
> -<br>
> + <br>
> self changed: #rootDirectoryList.<br>
> self directory: (self directory / userInput).<br>
> self changed: #selectedPath<br>
> <br>
> FileAbstractSelectionDialog>>selectFileName: {filename} · ct 5/20/2022 12:52<br>
> + selectFileName: aText<br>
> +<br>
> + | result |<br>
> + fileName := aText asString.<br>
> + <br>
> + (directory class dirPathFor: aText asString) ifNotEmpty: [:otherDirPath |<br>
> + ([directory on: otherDirPath] ifError: [nil]) ifNotNil: [:otherDir |<br>
> + otherDir exists ifTrue:<br>
> + [self setDirectoryTo: otherDir.<br>
> + self changed: #selectedPath.<br>
> + fileName := directory class localNameFor: aText asString.<br>
> + self changed: #inputText.<br>
> + self changed: #canAccept.<br>
> + ^ self selectFileName: fileName]]].<br>
> + <br>
> + result := self selectExistingFileName.<br>
> + self changed: #canAccept.<br>
> + ^ result<br>
> <br>
> FileAbstractSelectionDialog>>setDirectoryTo: {directory tree} · ct 5/19/2022 23:54 (changed)<br>
> setDirectoryTo: dir<br>
> "Set the current directory shown in the FileList.<br>
> Does not allow setting the directory to nil since this blows up in various places."<br>
> <br>
> dir ifNil:[^self].<br>
> + dir isString ifTrue: [<br>
> + self flag: #mvc. "PluggableListView auto-converts all items to strings :("<br>
> + ^ self setDirectoryTo: (FileDirectory on: (Scanner new scanTokens: dir) third)].<br>
> "okToChange is probably redundant.<br>
> modelSleep/Wake is related to use of ServerDirectories, which are not yet hooked up"<br>
> self okToChange ifFalse: [ ^ self ].<br>
> self modelSleep.<br>
> self directory: dir.<br>
> self modelWakeUp.<br>
> self changed: #directory.<br>
> self updateFileList.<br>
> - self changed: #inputText<br>
> + isUpdating ifFalse: [self changed: #inputText].<br>
> <br>
> FileAbstractSelectionDialogTest<br>
> + ClassTestCase subclass: #FileAbstractSelectionDialogTest<br>
> + instanceVariableNames: 'mockDirectory mockFile1 mockFile2 mockFile3 mockChildDirectory mockChildFile dialog morph result'<br>
> + classVariableNames: ''<br>
> + poolDictionaries: ''<br>
> + category: 'MorphicTests-ToolBuilder'<br>
> +<br>
> + FileAbstractSelectionDialogTest class<br>
> + instanceVariableNames: ''<br>
> +<br>
> + ""<br>
> <br>
> FileAbstractSelectionDialogTest class>>isAbstract {testing } · ct 5/19/2022 20:57<br>
> + isAbstract<br>
> +<br>
> + ^ self = FileAbstractSelectionDialogTest<br>
> <br>
> FileAbstractSelectionDialogTest>>classToBeTested {accessing} · ct 5/19/2022 20:20<br>
> + classToBeTested<br>
> +<br>
> + ^ self dialogClass<br>
> <br>
> FileAbstractSelectionDialogTest>>createChildFile: {support} · ct 5/19/2022 21:34<br>
> + createChildFile: fileName<br>
> +<br>
> + FileStream<br>
> + fileNamed: (self pathForChildFile: fileName)<br>
> + do: [:stream | stream nextPutAll: thisContext longPrintString].<br>
> <br>
> FileAbstractSelectionDialogTest>>createFile: {support} · ct 5/19/2022 21:34<br>
> + createFile: fileName<br>
> +<br>
> + FileStream<br>
> + fileNamed: (self pathForFile: fileName)<br>
> + do: [:stream | stream nextPutAll: thisContext longPrintString].<br>
> <br>
> FileAbstractSelectionDialogTest>>dialogClass {accessing} · ct 5/19/2022 20:20<br>
> + dialogClass<br>
> +<br>
> + ^ self targetClass<br>
> <br>
> FileAbstractSelectionDialogTest>>openDialog {support} · ct 5/19/2022 20:40<br>
> + openDialog<br>
> +<br>
> + ^ morph := self toolBuilder build: dialog<br>
> <br>
> FileAbstractSelectionDialogTest>>pathForChildFile: {support} · ct 5/19/2022 21:31<br>
> + pathForChildFile: fileName<br>
> +<br>
> + ^ self pathForDirectory: mockChildDirectory file: fileName<br>
> <br>
> FileAbstractSelectionDialogTest>>pathForDirectory:file: {support} · ct 5/19/2022 21:30<br>
> + pathForDirectory: directory file: fileName<br>
> +<br>
> + ^ directory fullName, directory class slash, fileName<br>
> <br>
> FileAbstractSelectionDialogTest>>pathForFile: {support} · ct 5/19/2022 21:30<br>
> + pathForFile: fileName<br>
> +<br>
> + ^ self pathForDirectory: mockDirectory file: fileName<br>
> <br>
> FileAbstractSelectionDialogTest>>setUp {running} · ct 5/19/2022 20:45<br>
> + setUp<br>
> +<br>
> + super setUp.<br>
> + <br>
> + self setUpDirectory.<br>
> + self setUpDialog.<br>
> <br>
> FileAbstractSelectionDialogTest>>setUpDialog {running} · ct 5/19/2022 20:42<br>
> + setUpDialog<br>
> +<br>
> + dialog := self dialogClass new.<br>
> + dialog addDependent: self.<br>
> + dialog directory: mockDirectory.<br>
> <br>
> FileAbstractSelectionDialogTest>>setUpDirectory {running} · ct 5/19/2022 21:36<br>
> + setUpDirectory<br>
> +<br>
> + mockDirectory := FileDirectory default / self class asString / UUID new asString.<br>
> + mockDirectory assureExistence.<br>
> + <br>
> + {mockFile1 := 'plonk1.txt'.<br>
> + mockFile2 := 'plonk2.st'.<br>
> + mockFile3 := 'plonk3.cs'}<br>
> + do: [:file | self createFile: file].<br>
> + <br>
> + mockChildDirectory := mockDirectory / 'child'.<br>
> + mockChildDirectory assureExistence.<br>
> + <br>
> + mockChildFile := 'griffle.gif'.<br>
> + self createChildFile: mockChildFile.<br>
> <br>
> FileAbstractSelectionDialogTest>>tearDown {running} · ct 5/20/2022 13:25<br>
> + tearDown<br>
> +<br>
> + [mockDirectory ifNotNil: [mockDirectory assureAbsence].<br>
> + (FileDirectory default / self class asString) assureAbsence]<br>
> + ensure: [super tearDown].<br>
> <br>
> FileAbstractSelectionDialogTest>>testCancel {tests - interface} · ct 5/19/2022 22:17<br>
> + testCancel<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog cancelFileChooser.<br>
> + <br>
> + self assert: nil equals: result.<br>
> <br>
> FileAbstractSelectionDialogTest>>testDirectoryTree {tests - interface} · ct 5/19/2022 22:20<br>
> + testDirectoryTree<br>
> +<br>
> + | node index |<br>
> + self openDialog.<br>
> + <br>
> + node := dialog rootDirectoryList<br>
> + detect: [:root | (dialog directoryNameOf: root) = mockDirectory pathParts first]<br>
> + ifNone: [].<br>
> + self assert: node notNil.<br>
> + <br>
> + index := 2.<br>
> + [self assert: (dialog hasMoreDirectories: node).<br>
> + (dialog subDirectoriesOf: node)<br>
> + detect: [:child | (dialog directoryNameOf: child) = (mockDirectory pathParts at: index)]<br>
> + ifFound: [:child | node := child. index := index + 1]<br>
> + ifNone: [self fail]]<br>
> + doWhileFalse: [(dialog directoryNameOf: node) = mockDirectory localName].<br>
> + self assert: mockDirectory equals: dialog directory.<br>
> + <br>
> + self deny: (dialog hasMoreDirectories: mockChildDirectory).<br>
> <br>
> FileAbstractSelectionDialogTest>>toolBuilder {accessing} · ct 5/19/2022 20:25<br>
> + toolBuilder<br>
> +<br>
> + ^ self toolBuilderClass new<br>
> <br>
> FileAbstractSelectionDialogTest>>toolBuilderClass {accessing} · ct 5/19/2022 20:25<br>
> + toolBuilderClass<br>
> +<br>
> + ^ MorphicToolBuilder<br>
> <br>
> FileAbstractSelectionDialogTest>>update: {updating} · ct 5/19/2022 20:41<br>
> + update: aspect<br>
> +<br>
> + aspect = #close ifTrue:<br>
> + [result := dialog finalChoice].<br>
> <br>
> FileChooserDialog>>inputText {filename} · ct 5/19/2022 14:02<br>
> + inputText<br>
> + "return the filename to appear in the text field"<br>
> +<br>
> + ^fileName<br>
> <br>
> FileChooserDialog>>inputText: {filename} · ct 5/20/2022 13:06<br>
> + inputText: aText<br>
> + "Initialize the filename entry field to aString. If a file with that name already exists, set up to highlight it."<br>
> + aText ifNil: [^ self].<br>
> + fileName := aText asString.<br>
> + self selectExistingFileName<br>
> <br>
> FileChooserDialog>>selectExistingFileName {private} · ct 5/20/2022 13:06<br>
> + selectExistingFileName<br>
> + "Answer whether an existing file in the list matches my proposed filename, selecting it if it does."<br>
> +<br>
> + listIndex := nameList findFirst: [:each |<br>
> + fileName isEmptyOrNil not and:<br>
> + [each beginsWith: fileName "caseSensitive: FileDirectory default isCaseSensitive"]].<br>
> + fileName := nameList at: listIndex ifAbsent: [nil].<br>
> + <br>
> + self changed: #fileListIndex.<br>
> + self changed: #canAccept.<br>
> + <br>
> + ^ listIndex ~= 0<br>
> <br>
> FileChooserDialog>>userMessage {ui details} · ct 5/19/2022 17:40 (changed)<br>
> userMessage<br>
> - "return the string to present to the user in order to explain the purpose of this dialog appearing"<br>
> + "return the string to present to the user in order to explain the purpose of this dialog appearing"<br>
> <br>
> ^message ifNil: ['Choose a file name' translated]<br>
> <br>
> FileChooserDialogTest<br>
> + nil subclass: #FileChooserDialogTest<br>
> + instanceVariableNames: ''<br>
> + classVariableNames: ''<br>
> + poolDictionaries: ''<br>
> + category: 'MorphicTests-ToolBuilder'<br>
> +<br>
> + FileChooserDialogTest class<br>
> + instanceVariableNames: ''<br>
> +<br>
> + ""<br>
> <br>
> FileChooserDialogTest>>testTypeToSelect {tests - interactions} · ct 5/20/2022 12:54<br>
> + testTypeToSelect<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog selectFileName: mockFile2 allButLast.<br>
> + self assert: mockFile2 equals: (dialog fileList at: dialog fileListIndex).<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: (self pathForFile: mockFile2) equals: result.<br>
> <br>
> FileDialogTest<br>
> + nil subclass: #FileDialogTest<br>
> + instanceVariableNames: ''<br>
> + classVariableNames: ''<br>
> + poolDictionaries: ''<br>
> + category: 'MorphicTests-ToolBuilder'<br>
> +<br>
> + FileDialogTest class<br>
> + instanceVariableNames: ''<br>
> +<br>
> + ""<br>
> <br>
> FileDialogTest class>>isAbstract {testing } · ct 5/19/2022 20:57<br>
> + isAbstract<br>
> +<br>
> + ^ self = FileDialogTest<br>
> <br>
> FileDialogTest>>testChooseAbsentFile {tests - interface} · ct 5/20/2022 12:53<br>
> + testChooseAbsentFile<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog acceptFileName: mockFile2 , '.absent'.<br>
> + <br>
> + self assert: nil equals: result.<br>
> <br>
> FileDialogTest>>testChooseFile {tests - interface} · ct 5/20/2022 12:53<br>
> + testChooseFile<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog acceptFileName: mockFile2.<br>
> + <br>
> + self assert: (self pathForFile: mockFile2) equals: result.<br>
> <br>
> FileDialogTest>>testChooseNothing {tests - interactions} · ct 5/19/2022 21:03<br>
> + testChooseNothing<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + self deny: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: nil equals: result.<br>
> <br>
> FileDialogTest>>testFileList {tests - interface} · ct 5/19/2022 20:47<br>
> + testFileList<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + self assert: {mockFile1. mockFile2. mockFile3} equals: dialog fileList.<br>
> <br>
> FileDialogTest>>testFileListWithPattern {tests - interface} · ct 5/19/2022 20:47<br>
> + testFileListWithPattern<br>
> +<br>
> + dialog pattern: '*2*'.<br>
> + self openDialog.<br>
> + <br>
> + self assert: {mockFile2} equals: dialog fileList.<br>
> <br>
> FileDialogTest>>testFileListWithSuffixList {tests - interface} · ct 5/19/2022 20:49<br>
> + testFileListWithSuffixList<br>
> +<br>
> + dialog suffixList: #('cs' 'st').<br>
> + self openDialog.<br>
> + <br>
> + self assert: {mockFile2. mockFile3} equals: dialog fileList.<br>
> <br>
> FileDialogTest>>testSelectAndChooseFile {tests - interactions} · ct 5/19/2022 21:03<br>
> + testSelectAndChooseFile<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog fileListIndex: (dialog fileList indexOf: mockFile2).<br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: (self pathForFile: mockFile2) equals: result.<br>
> <br>
> FileDialogTest>>testSelectAndChooseSubFile {tests - interactions} · ct 5/19/2022 21:35<br>
> + testSelectAndChooseSubFile<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog setDirectoryTo: (dialog subDirectoriesOf: dialog directory) first.<br>
> + self assert: {mockChildFile} equals: dialog fileList.<br>
> + dialog fileListIndex: (dialog fileList indexOf: mockChildFile).<br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: (self pathForChildFile: mockChildFile) equals: result.<br>
> <br>
> FileDialogTest>>testTypeAndChooseAbsentFile {tests - interactions} · ct 5/20/2022 12:54<br>
> + testTypeAndChooseAbsentFile<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog selectFileName: mockFile2 , '.absent'.<br>
> + self deny: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: nil equals: result.<br>
> <br>
> FileDialogTest>>testTypeAndChooseFile {tests - interactions} · ct 5/20/2022 12:55<br>
> + testTypeAndChooseFile<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog selectFileName: mockFile2.<br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: (self pathForFile: mockFile2) equals: result.<br>
> <br>
> FileDialogTest>>testTypeAndChooseFullPath {tests - interactions} · ct 5/20/2022 12:55<br>
> + testTypeAndChooseFullPath<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog selectFileName: (self pathForChildFile: mockChildFile).<br>
> + self assert: mockChildDirectory equals: dialog directory.<br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: (self pathForChildFile: mockChildFile) equals: result.<br>
> <br>
> FileSaverDialog>>buildButtonsWith: {toolbuilder} · ct 5/19/2022 23:59 (changed)<br>
> buildButtonsWith: builder<br>
> - "add a 'new directory' button to the beginning of the row of buttons"<br>
> - ^{ builder pluggableButtonSpec new<br>
> +<br>
> + ^ (super buildButtonsWith: builder)<br>
> + copyWith:<br>
> + (builder pluggableButtonSpec new<br>
> model: self;<br>
> label: 'New Directory' translated;<br>
> color: (self userInterfaceTheme get: #buttonColor for: #DialogWindow);<br>
> - action: #newDirectoryName}, (super buildButtonsWith: builder)<br>
> + action: #newDirectoryName;<br>
> + yourself)<br>
> <br>
> FileSaverDialog>>canAccept {accessing} · ct 5/20/2022 11:55<br>
> + canAccept<br>
> +<br>
> + ^ fileName isEmptyOrNil not<br>
> + and: [(self directory directoryExists: fileName) not]<br>
> <br>
> FileSaverDialog>>checkOrCorrectSuffix {filename} · ct 5/20/2022 12:35<br>
> + checkOrCorrectSuffix<br>
> +<br>
> + | suffix |<br>
> + super checkOrCorrectSuffix ifTrue: [^ true].<br>
> + <br>
> + suffixList ifEmpty: [^ false].<br>
> + <br>
> + suffixList size = 1 ifTrue:<br>
> + [((suffix := '.' , suffixList anyOne)<br>
> + compare: (fileName last: (suffix size min: fileName size))<br>
> + caseSensitive: directory isCaseSensitive)<br>
> + = 2 ifFalse: [ fileName := fileName , suffix ].<br>
> + ^ true].<br>
> + <br>
> + suffix := (Project uiManager<br>
> + chooseFrom: suffixList<br>
> + values: suffixList<br>
> + title: 'Please choose the type of file to save.' translated)<br>
> + ifNil: [^ false].<br>
> + fileName := fileName , '.' , suffix.<br>
> + self acceptFileName.<br>
> + ^ true<br>
> <br>
> FileSaverDialog>>initialFilename: {accessing} · tpr 11/22/2017 16:39 (changed and recategorized)<br>
> initialFilename: aFilenameOrNil<br>
> "Set the initial choice of filename to highlight.<br>
> We split the potential filename to see if it includes a path and if so, use that as the chosen directory - the client can manually change that with a subsequent send of #directory: if wanted.<br>
> We split the root filename to find an extension and use that as the suffix - again, the client can manually change that later"<br>
> <br>
> | e f p |<br>
> aFilenameOrNil ifNil:[^self].<br>
> <br>
> p := FileDirectory dirPathFor: aFilenameOrNil.<br>
> p isEmpty ifFalse:[self directory: (FileDirectory on: p)]. <br>
> f := FileDirectory localNameFor: aFilenameOrNil.<br>
> fileName := f.<br>
> e := FileDirectory extensionFor: f.<br>
> e isEmpty ifFalse:[self suffix: e]<br>
> <br>
> FileSaverDialog>>inputText {filename} · ct 5/19/2022 14:01 (changed)<br>
> inputText<br>
> "return the filename to appear in the text field"<br>
> <br>
> - ^fileName ifNil:['Enter a filename here or choose from list' translated]<br>
> + ^fileName<br>
> <br>
> FileSaverDialog>>inputText: {filename} · ct 5/20/2022 13:06 (changed)<br>
> inputText: aText<br>
> "Initialize the filename entry field to aString. If a file with that name already exists, set up to highlight it."<br>
> aText ifNil: [^ self].<br>
> fileName := aText asString.<br>
> - self selectExistingFilename<br>
> + self selectExistingFileName<br>
> <br>
> FileSaverDialog>>selectExistingFileName {private} · ct 5/20/2022 13:06<br>
> + selectExistingFileName<br>
> + "Answer whether an existing file in the list matches my proposed filename, selecting it if it does."<br>
> +<br>
> + listIndex := nameList findFirst: [:each | each = fileName].<br>
> + self changed: #fileListIndex.<br>
> + ^ true<br>
> <br>
> FileSaverDialogTest<br>
> + nil subclass: #FileSaverDialogTest<br>
> + instanceVariableNames: ''<br>
> + classVariableNames: ''<br>
> + poolDictionaries: ''<br>
> + category: 'MorphicTests-ToolBuilder'<br>
> +<br>
> + FileSaverDialogTest class<br>
> + instanceVariableNames: ''<br>
> +<br>
> + ""<br>
> <br>
> FileSaverDialogTest>>testChooseAbsentFile {tests - interface} · ct 5/20/2022 12:53<br>
> + testChooseAbsentFile<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog acceptFileName: mockFile2 , '.absent'.<br>
> + <br>
> + self assert: (self pathForFile: mockFile2 , '.absent') equals: result.<br>
> <br>
> FileSaverDialogTest>>testChooseAbsentFileWithSuffix {tests - interface} · ct 5/20/2022 12:53<br>
> + testChooseAbsentFileWithSuffix<br>
> +<br>
> + dialog suffix: 'txt'.<br>
> + self openDialog.<br>
> + <br>
> + dialog acceptFileName: mockFile2 , '.absent'.<br>
> + <br>
> + self assert: (self pathForFile: mockFile2 , '.absent.txt') equals: result.<br>
> <br>
> FileSaverDialogTest>>testChooseDirectory {tests - interface} · ct 5/20/2022 12:53<br>
> + testChooseDirectory<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog acceptFileName: mockChildDirectory localName.<br>
> + <br>
> + self deny: dialog canAccept.<br>
> + self assert: result isNil.<br>
> <br>
> FileSaverDialogTest>>testInitialFileName {tests - interface} · ct 5/19/2022 21:08<br>
> + testInitialFileName<br>
> +<br>
> + dialog initialFilename: mockFile2.<br>
> + self openDialog.<br>
> + <br>
> + self assert: mockFile2 equals: dialog inputText.<br>
> + self assert: mockFile2 equals: (dialog fileList at: dialog fileListIndex).<br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: (self pathForFile: mockFile2) equals: result.<br>
> <br>
> FileSaverDialogTest>>testNewDirectory {tests - interface} · ct 5/20/2022 12:53<br>
> + testNewDirectory<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + [dialog newDirectoryName] valueSupplyingAnswer: #('*name*' 'nurp').<br>
> + self assert: (mockDirectory directoryExists: 'nurp').<br>
> + self assert: mockDirectory / 'nurp' equals: dialog directory.<br>
> + dialog acceptFileName: 'zonk'.<br>
> + <br>
> + self assert: (self pathForDirectory: mockDirectory / 'nurp' file: 'zonk') equals: result.<br>
> <br>
> FileSaverDialogTest>>testTypeAndChooseAbsentFile {tests - interactions} · ct 5/20/2022 12:55<br>
> + testTypeAndChooseAbsentFile<br>
> +<br>
> + self openDialog.<br>
> + <br>
> + dialog selectFileName: mockFile2 , '.absent'.<br>
> + self assert: dialog canAccept.<br>
> + dialog acceptFileName.<br>
> + <br>
> + self assert: (self pathForFile: mockFile2 , '.absent') equals: result.<br>
> <br>
> FileSaverDialogTest>>testTypeAndChooseAbsentFileWithSuffixList {tests - interactions} · ct 5/20/2022 12:55<br>
> + testTypeAndChooseAbsentFileWithSuffixList<br>
> +<br>
> + dialog suffixList: #('txt' 'cs').<br>
> + self openDialog.<br>
> + <br>
> + "suffix choice is cancellable and dialog will remain open"<br>
> + 2 timesRepeat:<br>
> + [[dialog selectFileName: mockFile2 , '.absent'.<br>
> + dialog acceptFileName]<br>
> + valueSupplyingAnswer: #('*type*' cancel)].<br>
> + <br>
> + [dialog selectFileName: mockFile2 , '.absent'.<br>
> + dialog acceptFileName]<br>
> + valueSupplyingAnswer: #('*type*' 'cs').<br>
> + <br>
> + self assert: (self pathForFile: mockFile2 , '.absent.cs') equals: result.<br>
> <br>
> ---<br>
> Sent from Squeak Inbox Talk [https://github.com/hpi-swa-lab/squeak-inbox-talk]<br>
> ["polish-file-dialogs.3.cs"]<br>
> ["DirectoryChooserDialog.png"]<br>
> ["FileChooserDialog.png"]<br>
> -------------- next part --------------<br>
> An HTML attachment was scrubbed...<br>
> URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20220707/4d4c468a/attachment-0001.html><br>
> <br>
>