diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewAdapter.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewAdapter.class.st new file mode 100644 index 00000000..c2a117af --- /dev/null +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewAdapter.class.st @@ -0,0 +1,68 @@ +Class { + #name : 'SpMorphicColumnViewAdapter', + #superclass : 'SpMorphicTableAdapter', + #category : 'Spec2-Adapters-Morphic-ListView', + #package : 'Spec2-Adapters-Morphic-ListView' +} + +{ #category : 'factory' } +SpMorphicColumnViewAdapter >> addModelTo: tableMorph [ + + "no search on column view (it has to be provided elsewhere)" + tableMorph disableFunction. + + self model columns do: [ :each | + tableMorph addColumn: (self newColumnFrom: each) ]. + self ensureAtLeastOneColumnIn: tableMorph. + + self isResizable + ifTrue: [ tableMorph beResizable ] + ifFalse: [ tableMorph beNotResizable ]. + + tableMorph setMultipleSelection: self model isMultipleSelection. + + self refreshShowColumnHeaders. + self refreshWidgetSelection. + + self presenter whenModelChangedDo: [ self refreshModel ]. + self presenter whenColumnsChangedDo: [ self refreshColumnsInWidget ]. + + tableMorph setBalloonText: self help. + + self configureScrolling. + + tableMorph + onAnnouncement: FTSelectionChanged + send: #selectionChanged: + to: self; + onAnnouncement: FTStrongSelectionChanged + send: #strongSelectionChanged: + to: self. + + tableMorph dataSource: self newDataSource. + + self presenter whenSearchEnabledChangedDo: [ + self updateSearch ] +] + +{ #category : 'testing' } +SpMorphicColumnViewAdapter >> isResizable [ + + ^ self presenter isResizable +] + +{ #category : 'private - factory' } +SpMorphicColumnViewAdapter >> newColumnFrom: aColumnViewColumn [ + + ^ (SpMorphicColumnViewColumn on: aColumnViewColumn) + width: aColumnViewColumn width; + yourself +] + +{ #category : 'private - factory' } +SpMorphicColumnViewAdapter >> newDataSource [ + + ^ SpMorphicColumnViewDataSource new + model: self presenter; + yourself +] diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewColumn.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewColumn.class.st new file mode 100644 index 00000000..4b600a21 --- /dev/null +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewColumn.class.st @@ -0,0 +1,30 @@ +Class { + #name : 'SpMorphicColumnViewColumn', + #superclass : 'SpMorphicTableColumn', + #category : 'Spec2-Adapters-Morphic-ListView', + #package : 'Spec2-Adapters-Morphic-ListView' +} + +{ #category : 'private' } +SpMorphicColumnViewColumn >> bindAction [ + + ^ self model bindAction +] + +{ #category : 'testing' } +SpMorphicColumnViewColumn >> isExpandable [ + + ^ self model isExpand +] + +{ #category : 'accessing' } +SpMorphicColumnViewColumn >> model: aColumnViewColumn [ + + model := aColumnViewColumn +] + +{ #category : 'private' } +SpMorphicColumnViewColumn >> setupAction [ + + ^ self model setupAction +] diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewDataSource.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewDataSource.class.st new file mode 100644 index 00000000..22182376 --- /dev/null +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicColumnViewDataSource.class.st @@ -0,0 +1,45 @@ +Class { + #name : 'SpMorphicColumnViewDataSource', + #superclass : 'SpMorphicTableDataSource', + #instVars : [ + 'rowHeights' + ], + #category : 'Spec2-Adapters-Morphic-ListView', + #package : 'Spec2-Adapters-Morphic-ListView' +} + +{ #category : 'accessing' } +SpMorphicColumnViewDataSource >> cellColumn: column row: rowIndex [ + | cell contentPresenter contentMorph | + + cell := FTCellMorph new. + + contentPresenter := column setupAction value: self model. + column bindAction + value: contentPresenter + value: (self elementAt: rowIndex). + + contentMorph := contentPresenter build. + + "register for height" + rowHeights at: rowIndex put: contentMorph height. + + self setHeaderColumnLazyProperties: column. + + ^ cell addMorphBack: contentMorph +] + +{ #category : 'initialization' } +SpMorphicColumnViewDataSource >> initialize [ + + super initialize. + rowHeights := Dictionary new +] + +{ #category : 'accessing' } +SpMorphicColumnViewDataSource >> rowHeight: index [ + + ^ rowHeights + at: index + ifAbsent: [ super rowHeight: index ] +] diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewAdapter.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewAdapter.class.st index 4c5878e1..4d74bc2d 100644 --- a/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewAdapter.class.st +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewAdapter.class.st @@ -14,8 +14,11 @@ SpMorphicListViewAdapter >> buildWidget [ datasource := self newDataSource. datasource model: self model. + widget := self newTableWith: datasource. - + "no search on list view (it has to be provided elsewhere)" + widget disableFunction. + self presenter whenModelChangedDo: [ widget refresh ]. self presenter whenSelectionChangedDo: [ self refreshWidgetSelection ]. self presenter selection whenChangedDo: [ self refreshWidgetSelection ]. @@ -36,7 +39,6 @@ SpMorphicListViewAdapter >> newDataSource [ SpMorphicListViewAdapter >> newTableWith: datasource [ ^ SpFTTableMorph new - beRowNotHomogeneous; disableFunction; dataSource: datasource; hideColumnHeaders; diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewDataSource.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewDataSource.class.st index a0a8659b..c600aaf0 100644 --- a/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewDataSource.class.st +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewDataSource.class.st @@ -24,7 +24,7 @@ SpMorphicListViewDataSource >> cellColumn: column row: rowIndex [ contentMorph := contentPresenter build. - "register wor height" + "register for height" rowHeights at: rowIndex put: contentMorph height. ^ cell addMorphBack: contentMorph diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeColumnViewAdapter.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeColumnViewAdapter.class.st new file mode 100644 index 00000000..6f38d9a7 --- /dev/null +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeColumnViewAdapter.class.st @@ -0,0 +1,24 @@ +Class { + #name : 'SpMorphicTreeColumnViewAdapter', + #superclass : 'SpMorphicTreeTableAdapter', + #category : 'Spec2-Adapters-Morphic-ListView', + #package : 'Spec2-Adapters-Morphic-ListView' +} + +{ #category : 'private - factory' } +SpMorphicTreeColumnViewAdapter >> newColumnFrom: aTableColumn [ + + ^ (SpMorphicColumnViewColumn on: aTableColumn) + width: aTableColumn width; + yourself +] + +{ #category : 'private - factory' } +SpMorphicTreeColumnViewAdapter >> newDataSource [ + + ^ SpMorphicTreeColumnViewDataSource new + model: self model; + rootItem: (self rootForItems: self model roots); + childrenBlock: [ :data :item | self model childrenFor: data ]; + yourself +] diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeColumnViewDataSource.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeColumnViewDataSource.class.st new file mode 100644 index 00000000..65de83f3 --- /dev/null +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeColumnViewDataSource.class.st @@ -0,0 +1,57 @@ +Class { + #name : 'SpMorphicTreeColumnViewDataSource', + #superclass : 'SpMorphicTreeTableDataSource', + #instVars : [ + 'rowHeights' + ], + #category : 'Spec2-Adapters-Morphic-ListView', + #package : 'Spec2-Adapters-Morphic-ListView' +} + +{ #category : 'accessing' } +SpMorphicTreeColumnViewDataSource >> cellColumn: column row: rowIndex [ + | cell item contentPresenter contentMorph | + + item := self elementAt: rowIndex. + + cell := FTIndentedCellMorph new. + (self isFirstColumn: column) ifTrue: [ + cell indentBy: (self cellIndentFor: item). + cell addMorphBack: (self buttonFor: item) ]. + + contentPresenter := column setupAction value: self model. + column bindAction + value: contentPresenter + value: item data. + + contentMorph := contentPresenter build. + + "register for height" + rowHeights at: rowIndex put: contentMorph height. + + self setHeaderColumnLazyProperties: column. + + ^ cell addMorphBack: contentMorph +] + +{ #category : 'initialization' } +SpMorphicTreeColumnViewDataSource >> initialize [ + + super initialize. + rowHeights := Dictionary new +] + +{ #category : 'accessing' } +SpMorphicTreeColumnViewDataSource >> rowHeight: index [ + + ^ rowHeights + at: index + ifAbsent: [ super rowHeight: index ] +] + +{ #category : 'testing' } +SpMorphicTreeColumnViewDataSource >> shouldDisplayExpandableArrowFor: item [ + + ^ (self canDisplayChildrenOf: item) + and: [ item hasChildren ] +] diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeListViewAdapter.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeListViewAdapter.class.st new file mode 100644 index 00000000..e525ca62 --- /dev/null +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicTreeListViewAdapter.class.st @@ -0,0 +1,85 @@ +Class { + #name : 'SpMorphicTreeListViewAdapter', + #superclass : 'SpMorphicTreeAdapter', + #category : 'Spec2-Adapters-Morphic-ListView', + #package : 'Spec2-Adapters-Morphic-ListView' +} + +{ #category : 'factory' } +SpMorphicTreeListViewAdapter >> addModelTo: tableMorph [ + + tableMorph addColumn: (self newColumnFrom: self defaultColumn). + + self presenter selection isMultipleSelection ifTrue: [ + tableMorph beMultipleSelection ]. + + self isShowingColumnHeaders + ifTrue: [ tableMorph showColumnHeaders ] + ifFalse: [ tableMorph hideColumnHeaders ]. + + self isSearchEnabled + ifTrue: [ tableMorph enableSearch ] + ifFalse: [ tableMorph disableFunction ]. + + tableMorph setBalloonText: self model help. + + tableMorph dataSource: self newDataSource. + + self presenter selection isEmpty + ifFalse: [ self updateSelectionOf: tableMorph ]. + + self presenter whenSelectionChangedDo: [ + self updateSelectionOf: tableMorph ]. + + self presenter whenRootsChangedDo: [ + tableMorph selectIndexes: #(). + tableMorph dataSource: self newDataSource ]. + + tableMorph + onAnnouncement: FTSelectionChanged + send: #selectionChanged: + to: self; + onAnnouncement: FTStrongSelectionChanged + send: #strongSelectionChanged: + to: self +] + +{ #category : 'factory' } +SpMorphicTreeListViewAdapter >> defaultColumn [ + + ^ SpColumnViewColumn new + title: self presenter headerTitle; + setup: self presenter setupAction; + bind: self presenter bindAction; + yourself +] + +{ #category : 'testing' } +SpMorphicTreeListViewAdapter >> isResizable [ + + ^ false +] + +{ #category : 'testing' } +SpMorphicTreeListViewAdapter >> isShowingColumnHeaders [ + + ^ self presenter hasHeaderTitle +] + +{ #category : 'private - factory' } +SpMorphicTreeListViewAdapter >> newColumnFrom: aTableColumn [ + + ^ (SpMorphicColumnViewColumn on: aTableColumn) + width: aTableColumn width; + yourself +] + +{ #category : 'private - factory' } +SpMorphicTreeListViewAdapter >> newDataSource [ + + ^ SpMorphicTreeColumnViewDataSource new + model: self model; + rootItem: (self rootForItems: self model roots); + childrenBlock: [ :data :item | self model childrenFor: data ]; + yourself +] diff --git a/src/Spec2-Adapters-Morphic/MorphicAPartTreeTableAdapter.class.st b/src/Spec2-Adapters-Morphic/MorphicAPartTreeTableAdapter.class.st deleted file mode 100644 index 10cf24b0..00000000 --- a/src/Spec2-Adapters-Morphic/MorphicAPartTreeTableAdapter.class.st +++ /dev/null @@ -1,13 +0,0 @@ -Class { - #name : 'MorphicAPartTreeTableAdapter', - #superclass : 'SpMorphicTreeTableAdapter', - #category : 'Spec2-Adapters-Morphic-Table', - #package : 'Spec2-Adapters-Morphic', - #tag : 'Table' -} - -{ #category : 'accessing' } -MorphicAPartTreeTableAdapter class >> adaptingName [ - - ^ #APartTreeTableAdapter -] diff --git a/src/Spec2-Adapters-Morphic/SpAbstractMorphicAdapter.class.st b/src/Spec2-Adapters-Morphic/SpAbstractMorphicAdapter.class.st index f4c4ddae..1f9411a6 100644 --- a/src/Spec2-Adapters-Morphic/SpAbstractMorphicAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpAbstractMorphicAdapter.class.st @@ -658,10 +658,9 @@ SpAbstractMorphicAdapter >> takeKeyboardFocus [ { #category : 'drag and drop' } SpAbstractMorphicAdapter >> transferFor: passenger from: source [ - ^ SpTransferPresenter new - transfer: passenger; - from: source; - yourself + ^ self presenter + dragTransferFor: passenger + from: source ] { #category : 'emulating' } diff --git a/src/Spec2-Adapters-Morphic/SpAbstractMorphicListAdapter.class.st b/src/Spec2-Adapters-Morphic/SpAbstractMorphicListAdapter.class.st index 2ba43d82..940b5c6d 100644 --- a/src/Spec2-Adapters-Morphic/SpAbstractMorphicListAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpAbstractMorphicListAdapter.class.st @@ -61,6 +61,12 @@ SpAbstractMorphicListAdapter >> elementAt: index [ ^ self widget dataSource elementAt: index ] +{ #category : 'private' } +SpAbstractMorphicListAdapter >> hasHeaderTitle [ + + ^ self presenter hasHeaderTitle +] + { #category : 'widget API' } SpAbstractMorphicListAdapter >> itemFilter [ ^ self model itemFilter diff --git a/src/Spec2-Adapters-Morphic/SpFTTableMorph.class.st b/src/Spec2-Adapters-Morphic/SpFTTableMorph.class.st index 5af9488a..0a290912 100644 --- a/src/Spec2-Adapters-Morphic/SpFTTableMorph.class.st +++ b/src/Spec2-Adapters-Morphic/SpFTTableMorph.class.st @@ -17,6 +17,13 @@ SpFTTableMorph >> acceptDroppingMorph: aTransferMorph event: anEvent [ event: anEvent ] +{ #category : 'api' } +SpFTTableMorph >> disableFunction [ + + super disableFunction + +] + { #category : 'drawing' } SpFTTableMorph >> drawKeyboardFocusOn: aCanvas [ diff --git a/src/Spec2-Adapters-Morphic/SpMorphicBaseTextAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicBaseTextAdapter.class.st index 0ae1adb6..446fdbb5 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicBaseTextAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicBaseTextAdapter.class.st @@ -104,6 +104,13 @@ SpMorphicBaseTextAdapter >> cursorPositionIndex [ { #category : 'widget API' } SpMorphicBaseTextAdapter >> cursorPositionIndex: index [ + self widgetDo: [ :w | + self cursorPositionIndex: index to: w ] +] + +{ #category : 'widget API' } +SpMorphicBaseTextAdapter >> cursorPositionIndex: index to: aWidget [ + self subclassResponsibility ] @@ -276,7 +283,8 @@ SpMorphicBaseTextAdapter >> setSelection: interval [ { #category : 'selection' } SpMorphicBaseTextAdapter >> setSelectionFromModel: aSelection [ - self widget ifNotNil: [ :w | w setSelection: aSelection ] + self widget ifNotNil: [ :w | + w setSelection: (aSelection ifNil: [ 1 to: 0 ]) ] ] { #category : 'initialization' } @@ -289,6 +297,12 @@ SpMorphicBaseTextAdapter >> showContextMenu [ in: self currentWorld ] ] ] +{ #category : 'accessing' } +SpMorphicBaseTextAdapter >> text: aString [ + + self subclassResponsibility +] + { #category : 'emulating' } SpMorphicBaseTextAdapter >> type: aString [ diff --git a/src/Spec2-Adapters-Morphic/SpMorphicListAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicListAdapter.class.st index c9fa116c..9567b891 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicListAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicListAdapter.class.st @@ -158,7 +158,7 @@ SpMorphicListAdapter >> refreshList [ { #category : 'widget API' } SpMorphicListAdapter >> refreshWidgetHeaderTitle [ - self presenter hasHeaderTitle + self hasHeaderTitle ifTrue: [ self widget columns first model title: self presenter headerTitle. self widget diff --git a/src/Spec2-Adapters-Morphic/SpMorphicTableAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicTableAdapter.class.st index 1282c9b8..e4ac1bfc 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicTableAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicTableAdapter.class.st @@ -101,6 +101,12 @@ SpMorphicTableAdapter >> ensureAtLeastOneColumnIn: tableMorph [ tableMorph addColumn: (self newColumnFrom: self defaultColumn) ] +{ #category : 'private' } +SpMorphicTableAdapter >> hasHeaderTitle [ + + ^ self presenter isShowingColumnHeaders +] + { #category : 'private' } SpMorphicTableAdapter >> ifSorted: sortedBlock ifNotSorted: notSortedBlock [ widget columns @@ -265,6 +271,7 @@ SpMorphicTableAdapter >> transferFrom: aTransferMorph event: anEvent [ rowAndColumn := self widget container rowAndColumnIndexContainingPoint: anEvent position. ^ SpDragAndDropTransferToTable new passenger: aTransferMorph passenger; + shouldCopy: aTransferMorph shouldCopy; row: (rowAndColumn first ifNil: [ 0 ]); column: (rowAndColumn second ifNil: [ 0 ]); yourself diff --git a/src/Spec2-Adapters-Morphic/SpMorphicTableColumn.class.st b/src/Spec2-Adapters-Morphic/SpMorphicTableColumn.class.st index 9811aff6..40769f3b 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicTableColumn.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicTableColumn.class.st @@ -51,7 +51,7 @@ SpMorphicTableColumn >> initialize [ addEmptySpace := false ] -{ #category : 'testing' } +{ #category : 'private' } SpMorphicTableColumn >> isExpandable [ ^ self model isExpandable @@ -118,7 +118,7 @@ SpMorphicTableColumn >> width: aNumber [ widthToAdd := addEmptySpace ifTrue: [ aNumber - self emptySpace ] ifFalse: [ aNumber ]. - (self model isExpandable and: [ aNumber isNotNil ]) + (self isExpandable and: [ aNumber isNotNil ]) ifTrue: [ self model width: widthToAdd ] ]. super width: widthToAdd ] diff --git a/src/Spec2-Adapters-Morphic/SpMorphicTextAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicTextAdapter.class.st index ea146944..d65c952c 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicTextAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicTextAdapter.class.st @@ -69,14 +69,17 @@ SpMorphicTextAdapter >> buildWidget [ self setEnabled: self presenter isEnabled to: newWidget. self setEditable: self presenter isEditable to: newWidget. self setEditingModeFor: newWidget. + self setText: self presenter text to: newWidget. self presenter selectionInterval - ifNotNil: [ :anInterval | self selectionInterval: anInterval on: newWidget ]. - + ifNotEmpty: [ :anInterval | self selectionInterval: anInterval on: newWidget ] + ifEmpty: [ + self presenter text ifNotNil: [ :aString | + self cursorPositionIndex: aString size + 1 to: newWidget. + self selectionInterval: (aString size + 1 to: aString size) on: newWidget ]. ]. + self setWrapWord: self presenter isWrapWord to: newWidget. self setUndoRedo: self presenter hasUndoRedoHistory to: newWidget. - self presenter whenTextChangedDo: [ :text | - self setText: text to: newWidget ]. self presenter whenSelectionChangedDo: [ :selectionInterval | self selectionInterval: selectionInterval ]. self presenter whenPlaceholderChangedDo: [ :text | @@ -132,9 +135,9 @@ SpMorphicTextAdapter >> cursorPosition [ ] { #category : 'widget API' } -SpMorphicTextAdapter >> cursorPositionIndex: index [ +SpMorphicTextAdapter >> cursorPositionIndex: index to: aWidget [ - self widgetDo: [ :w | w textArea pointBlock: (w textArea paragraph characterBlockForIndex: index) ] + aWidget textArea pointBlock: (aWidget textArea paragraph characterBlockForIndex: index) ] { #category : 'commands' } @@ -240,6 +243,13 @@ SpMorphicTextAdapter >> setWrapWord: aBoolean to: aWidget [ ifFalse: [ aWidget beNotWrapped ] ] +{ #category : 'accessing' } +SpMorphicTextAdapter >> text: aString [ + + self setText: aString to: widget. + self cursorPositionIndex: aString size + 1 +] + { #category : 'private' } SpMorphicTextAdapter >> updateExtentPropagationOf: string on: aWidget [ | stringMorph width height | diff --git a/src/Spec2-Adapters-Morphic/SpMorphicTextInputFieldAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicTextInputFieldAdapter.class.st index 128f6ccc..5437ba10 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicTextInputFieldAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicTextInputFieldAdapter.class.st @@ -42,8 +42,10 @@ SpMorphicTextInputFieldAdapter >> buildWidget [ yourself. self presenter selectionInterval - ifNotNil: [ :anInterval | self selectionInterval: anInterval on: newWidget ]. - self presenter whenTextChangedDo: [ :text | newWidget setText: text ]. + ifNotEmpty: [ :anInterval | self selectionInterval: anInterval on: newWidget ] + ifEmpty: [ + self presenter text ifNotNil: [ :aString | + self cursorPositionIndex: aString size + 1 to: newWidget ] ]. self presenter whenSelectionChangedDo: [ :selectionInterval | self selectionInterval: selectionInterval ]. self presenter whenPlaceholderChangedDo: [ :text | @@ -62,9 +64,9 @@ SpMorphicTextInputFieldAdapter >> buildWidget [ ] { #category : 'widget API' } -SpMorphicTextInputFieldAdapter >> cursorPositionIndex: index [ +SpMorphicTextInputFieldAdapter >> cursorPositionIndex: index to: aWidget [ - self widgetDo: [ :w | ^ w textArea editor selectAt: index ] + aWidget textArea editor selectAt: index ] { #category : 'widget API' } @@ -122,7 +124,8 @@ SpMorphicTextInputFieldAdapter >> text: aString [ widget setText: aString; - acceptTextInModel + acceptTextInModel. + self cursorPositionIndex: aString size + 1 ] { #category : 'emulating' } diff --git a/src/Spec2-Adapters-Morphic/SpMorphicTreeTableAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicTreeTableAdapter.class.st index 4558e802..6b6ce9e8 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicTreeTableAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicTreeTableAdapter.class.st @@ -493,6 +493,7 @@ SpMorphicTreeTableAdapter >> transferFrom: aTransferMorph event: anEvent [ ^ SpDragAndDropTransferToTree new passenger: aTransferMorph passenger; row: (rowAndColumn first ifNil: [ 0 ]); + shouldCopy: aTransferMorph shouldCopy; column: (rowAndColumn second ifNil: [ 0 ]); target: aTarget; yourself diff --git a/src/Spec2-Adapters-Morphic/SpMorphicTreeTableDataSource.class.st b/src/Spec2-Adapters-Morphic/SpMorphicTreeTableDataSource.class.st index fbaab1ca..c1859a6e 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicTreeTableDataSource.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicTreeTableDataSource.class.st @@ -69,14 +69,16 @@ SpMorphicTreeTableDataSource >> collapsePath: aPath [ (self itemAtPath: aPath) ifNotNil:[ :aNode | aNode collapseAll. - self tableRefresh ] + self tableRefresh. + self model selection selectPath: aPath ] ] { #category : 'accessing' } -SpMorphicTreeTableDataSource >> expandPath: anArray [ +SpMorphicTreeTableDataSource >> expandPath: aPath [ - self expandPath: anArray root: self rootItem children. - self tableRefresh + self expandPath: aPath root: self rootItem children. + self tableRefresh. + self model selection selectPath: aPath ] { #category : 'accessing' } diff --git a/src/Spec2-Adapters-Morphic/SpStyle.class.st b/src/Spec2-Adapters-Morphic/SpStyle.class.st index 1bd40a3d..31a2691b 100644 --- a/src/Spec2-Adapters-Morphic/SpStyle.class.st +++ b/src/Spec2-Adapters-Morphic/SpStyle.class.st @@ -155,7 +155,10 @@ SpStyle class >> defaultStyleSheetData [ .progressBar:label [ Draw { #color : EnvironmentColor(#selectionText) } ], .progressBar:bar [ Draw { #color: EnvironmentColor(#selection) }, - Geometry { #height: 5 } ] + Geometry { #height: 5 } ] , + .searchBox [ + Geometry { #width: 150 } + ] ] ' ] diff --git a/src/Spec2-Adapters-Morphic/SpTransferMorph.class.st b/src/Spec2-Adapters-Morphic/SpTransferMorph.class.st index ad357371..51b36d69 100644 --- a/src/Spec2-Adapters-Morphic/SpTransferMorph.class.st +++ b/src/Spec2-Adapters-Morphic/SpTransferMorph.class.st @@ -12,6 +12,15 @@ Class { #tag : 'Support' } +{ #category : 'private' } +SpTransferMorph >> initDraggedMorph [ + draggedMorph ifNotNil: [^self]. + draggedMorph := ((self valueOfProperty: #presenter) description ifNil: [ self passenger ]) asDraggableMorph. + self addMorphBack: draggedMorph. + self updateCopyIcon. + self changed; fullBounds +] + { #category : 'initialization' } SpTransferMorph >> initialize [ diff --git a/src/Spec2-Backend-Tests/SpAbstractTextAdapterTest.class.st b/src/Spec2-Backend-Tests/SpAbstractTextAdapterTest.class.st index 667c9f80..e8a76c0c 100644 --- a/src/Spec2-Backend-Tests/SpAbstractTextAdapterTest.class.st +++ b/src/Spec2-Backend-Tests/SpAbstractTextAdapterTest.class.st @@ -74,7 +74,5 @@ SpAbstractTextAdapterTest >> testSelectionIntervalNilUnselectsEverything [ self openInstance. - self - assert: presenter adapter selectionInterval - equals: (1 to: 0) + self assert: presenter adapter selectionInterval isEmpty ] diff --git a/src/Spec2-Backend-Tests/SpListCommonPropertiestTest.class.st b/src/Spec2-Backend-Tests/SpListCommonPropertiestTest.class.st index bb52fbc6..c26c3554 100644 --- a/src/Spec2-Backend-Tests/SpListCommonPropertiestTest.class.st +++ b/src/Spec2-Backend-Tests/SpListCommonPropertiestTest.class.st @@ -54,8 +54,7 @@ SpListCommonPropertiestTest >> testScrollDownToNonExistingIndexScrollsBottomToLa { #category : 'tests - scrolling' } SpListCommonPropertiestTest >> testScrollDownToPosteriorIndexScrollsBottomToIndex [ - self flag: #pharo7. - SystemVersion current major < 8 ifTrue: [ self skip. "Feature not supported in Pharo 7" ]. + presenter items: (1 to: 500). presenter verticalAlignment desiredVisibleRow: 100. @@ -82,8 +81,7 @@ SpListCommonPropertiestTest >> testScrollUpToNegativeIndexScrollsTopToFirstIndex { #category : 'tests - scrolling' } SpListCommonPropertiestTest >> testScrollUpToPreviousIndexScrollsTopToIndex [ - self flag: #pharo7. - SystemVersion current major < 8 ifTrue: [ self skip. "Feature not supported in Pharo 7" ]. + presenter items: (1 to: 500). presenter verticalAlignment desiredVisibleRow: 100. self openInstance. diff --git a/src/Spec2-Code-Commands/StCodeDoItCommand.class.st b/src/Spec2-Code-Commands/StCodeDoItCommand.class.st index c3dba337..2b865583 100644 --- a/src/Spec2-Code-Commands/StCodeDoItCommand.class.st +++ b/src/Spec2-Code-Commands/StCodeDoItCommand.class.st @@ -43,6 +43,6 @@ StCodeDoItCommand class >> order [ { #category : 'execution' } StCodeDoItCommand >> execute [ "Treat the current text selection as an expression; evaluate it." - + self evaluateSelectionAndDo: [ :result | ] ] diff --git a/src/Spec2-Core/SpAbstractAdapter.class.st b/src/Spec2-Core/SpAbstractAdapter.class.st index 3fa4afcc..7d159429 100644 --- a/src/Spec2-Core/SpAbstractAdapter.class.st +++ b/src/Spec2-Core/SpAbstractAdapter.class.st @@ -83,12 +83,6 @@ SpAbstractAdapter >> adapterWasBuilt [ "hook to add after-build opeations (for example, initial status, etc.)" ] -{ #category : 'protocol' } -SpAbstractAdapter >> add: aWidget [ - - self subclassResponsibility -] - { #category : 'initialization' } SpAbstractAdapter >> addEventsTo: aWidget [ @@ -111,24 +105,6 @@ SpAbstractAdapter >> eventHandlerReceiver: aWidget [ ^ aWidget ] -{ #category : 'protocol' } -SpAbstractAdapter >> hRigid [ - - self subclassResponsibility -] - -{ #category : 'protocol' } -SpAbstractAdapter >> hShrinkWrap [ - - self subclassResponsibility -] - -{ #category : 'protocol' } -SpAbstractAdapter >> hSpaceFill [ - - self subclassResponsibility -] - { #category : 'testing' } SpAbstractAdapter >> hasWidget: aMorphicButtonAdapter [ @@ -176,12 +152,6 @@ SpAbstractAdapter >> presenter [ ^ model ] -{ #category : 'protocol' } -SpAbstractAdapter >> removeSubWidgets [ - - self subclassResponsibility -] - { #category : 'private' } SpAbstractAdapter >> replaceLayoutWith: aLayout [ @@ -229,36 +199,6 @@ SpAbstractAdapter >> update: aSymbol with: anArray [ self perform: aSymbol withArguments: anArray ] -{ #category : 'protocol' } -SpAbstractAdapter >> useProportionalLayout [ - - self subclassResponsibility -] - -{ #category : 'protocol' } -SpAbstractAdapter >> vRigid [ - - self subclassResponsibility -] - -{ #category : 'protocol' } -SpAbstractAdapter >> vShrinkWrap [ - - self subclassResponsibility -] - -{ #category : 'protocol' } -SpAbstractAdapter >> vSpaceFill [ - - self subclassResponsibility -] - -{ #category : 'protocol' } -SpAbstractAdapter >> when: anAnnouncement do: aBlock [ - - self subclassResponsibility -] - { #category : 'accessing' } SpAbstractAdapter >> widget [ ^ widget diff --git a/src/Spec2-Core/SpAbstractListPresenter.class.st b/src/Spec2-Core/SpAbstractListPresenter.class.st index a99e5f5e..8da78a37 100644 --- a/src/Spec2-Core/SpAbstractListPresenter.class.st +++ b/src/Spec2-Core/SpAbstractListPresenter.class.st @@ -4,8 +4,8 @@ A base for list presenters, it defines basic functionality common to all lists. Class { #name : 'SpAbstractListPresenter', #superclass : 'SpAbstractWidgetPresenter', - #traits : 'SpTHaveWrappingScrollBars + SpTContextMenu + SpTAlignableColumn + SpTSelectionMode', - #classTraits : 'SpTHaveWrappingScrollBars classTrait + SpTContextMenu classTrait + SpTAlignableColumn classTrait + SpTSelectionMode classTrait', + #traits : 'SpTHaveWrappingScrollBars + SpTContextMenu + SpTAlignableColumn + SpTSelectionMode + SpTSearchable', + #classTraits : 'SpTHaveWrappingScrollBars classTrait + SpTContextMenu classTrait + SpTAlignableColumn classTrait + SpTSelectionMode classTrait + SpTSearchable classTrait', #instVars : [ '#activationBlock', '#activateOnSingleClick', @@ -125,6 +125,7 @@ SpAbstractListPresenter >> initialize [ super initialize. self initializeTHaveWrappingScrollBars. + self initializeTSearchable. activationBlock := [ ]. verticalAlignment := SpVerticalAlignment new. @@ -259,6 +260,12 @@ SpAbstractListPresenter >> registerEvents [ self withAdapterDo: [ :anAdapter | anAdapter updateMenu ] ] ] +{ #category : 'private' } +SpAbstractListPresenter >> searchValueOf: item [ + + ^ item asString +] + { #category : 'api' } SpAbstractListPresenter >> sortingBlock [ "Answer the sorting block defined to sort the model list. @@ -315,14 +322,6 @@ SpAbstractListPresenter >> whenModelChangedDo: aBlock [ model whenChangedDo: aBlock ] -{ #category : 'api - events' } -SpAbstractListPresenter >> whenSearchEnabledChangedDo: aBlock [ - "Inform when search enabled/disabled has changed. - `aBlock` receives zero arguments." - - self property: #searchEnabled whenChangedDo: aBlock -] - { #category : 'api - events' } SpAbstractListPresenter >> whenSortingBlockChangedDo: aBlock [ "Inform when sorting block changed. diff --git a/src/Spec2-Core/SpAbstractTextPresenter.class.st b/src/Spec2-Core/SpAbstractTextPresenter.class.st index f8c5e6c6..e996ac16 100644 --- a/src/Spec2-Core/SpAbstractTextPresenter.class.st +++ b/src/Spec2-Core/SpAbstractTextPresenter.class.st @@ -228,7 +228,8 @@ SpAbstractTextPresenter >> registerActions [ { #category : 'initialization' } SpAbstractTextPresenter >> registerEvents [ - self whenTextChangedDo: [ self changed: #getText ]. + self whenTextChangedDo: [ :aString | + self updateTextFromModel: aString ]. self property: #selection whenChangedDo: [ :aSelection | self updateSelectionFromModel: aSelection ] @@ -338,6 +339,13 @@ SpAbstractTextPresenter >> updateSelectionFromModel: aSelection [ anAdapter setSelectionFromModel: aSelection ] ] +{ #category : 'private' } +SpAbstractTextPresenter >> updateTextFromModel: aString [ + + self withAdapterDo: [ :anAdapter | + anAdapter text: aString ] +] + { #category : 'api - events' } SpAbstractTextPresenter >> whenEditableChangedDo: aBlock [ "Inform when editable property has changed. diff --git a/src/Spec2-Core/SpAbstractTreePresenter.class.st b/src/Spec2-Core/SpAbstractTreePresenter.class.st index 921cf6b3..8f3d20b9 100644 --- a/src/Spec2-Core/SpAbstractTreePresenter.class.st +++ b/src/Spec2-Core/SpAbstractTreePresenter.class.st @@ -204,7 +204,11 @@ SpAbstractTreePresenter >> initialize [ super initialize. self initializeTSearchable. self initializeTHaveWrappingScrollBars. + + verticalAlignment := SpVerticalAlignment new. + self withScrollBars. + self registerActions. self registerEvents ] @@ -364,6 +368,17 @@ SpAbstractTreePresenter >> searchValueOf: item [ ^ item asString ] +{ #category : 'private' } +SpAbstractTreePresenter >> selectFirst: aString [ + + self isSearchEnabled ifFalse: [ ^ self ]. + self traverseTreeDo: [ :anItem :aPath | + (self performSearch: anItem matching: aString) + ifTrue: [ + self selectPath: aPath. + ^ self ] ] +] + { #category : 'api - selection' } SpAbstractTreePresenter >> selectItem: anItem [ "Select `anItem` if it is included in model list. @@ -476,6 +491,28 @@ SpAbstractTreePresenter >> selectionMode: aMode [ selectionMode := aMode ] +{ #category : 'private' } +SpAbstractTreePresenter >> traverseTree: aCollection path: aPath do: aBlock [ + + aCollection withIndexDo: [ :anItem :index | + | itemPath | + itemPath := aPath copyWith: index. + aBlock value: anItem value: itemPath. + self + traverseTree: (self childrenFor: anItem) + path: itemPath + do: aBlock ] +] + +{ #category : 'private' } +SpAbstractTreePresenter >> traverseTreeDo: aBlock [ + + self + traverseTree: self roots + path: #() + do: aBlock +] + { #category : 'api - selection' } SpAbstractTreePresenter >> unselectAll [ "Remove all selections" diff --git a/src/Spec2-Core/SpAbstractWidgetPresenter.class.st b/src/Spec2-Core/SpAbstractWidgetPresenter.class.st index 9e5bb893..26427aeb 100644 --- a/src/Spec2-Core/SpAbstractWidgetPresenter.class.st +++ b/src/Spec2-Core/SpAbstractWidgetPresenter.class.st @@ -274,6 +274,23 @@ SpAbstractWidgetPresenter >> dragEnabled: aBoolean [ dragEnabled := aBoolean ] +{ #category : 'private - drag and drop' } +SpAbstractWidgetPresenter >> dragTransferFor: passenger from: source [ + "answer a transfer presenter ready to be dragged away from this presenter to + its destination. Allows user to modify elements of it by using the whenDragWillStartDo: + event and touching the transfer object." + | transfer | + + transfer := SpTransferPresenter new + transfer: passenger; + from: source; + yourself. + + self announce: (SpDragStartAnnouncement newTransfer: transfer). + + ^ transfer +] + { #category : 'drag and drop' } SpAbstractWidgetPresenter >> dropEnabled [ ^ dropEnabled @@ -401,6 +418,17 @@ SpAbstractWidgetPresenter >> whenBorderWidthChangedDo: aBlock [ self property: #borderWidth whenChangedDo: aBlock ] +{ #category : 'api - events' } +SpAbstractWidgetPresenter >> whenDragStartDo: aBlock [ + "Informs user a drag is taking place. + `aBlock` receives an SpDragStartAnnouncement as argument." + + self announcer + when: SpDragStartAnnouncement + do: aBlock + for: aBlock receiver +] + { #category : 'api - events' } SpAbstractWidgetPresenter >> whenEnabledChangedDo: aBlock [ "Inform when enabled status has changed. diff --git a/src/Spec2-Core/SpDragStartAnnouncement.class.st b/src/Spec2-Core/SpDragStartAnnouncement.class.st new file mode 100644 index 00000000..540b6747 --- /dev/null +++ b/src/Spec2-Core/SpDragStartAnnouncement.class.st @@ -0,0 +1,33 @@ +" +Announces when a drag starts passing to the listener a transfer presenter (that can be modified to user intents). +" +Class { + #name : 'SpDragStartAnnouncement', + #superclass : 'Announcement', + #instVars : [ + 'transfer' + ], + #category : 'Spec2-Core-Widgets', + #package : 'Spec2-Core', + #tag : 'Widgets' +} + +{ #category : 'instance creation' } +SpDragStartAnnouncement class >> newTransfer: aTransferPresenter [ + + ^ self new + transfer: aTransferPresenter; + yourself +] + +{ #category : 'accessing' } +SpDragStartAnnouncement >> transfer [ + + ^ transfer +] + +{ #category : 'accessing' } +SpDragStartAnnouncement >> transfer: aTransferPresenter [ + + transfer := aTransferPresenter +] diff --git a/src/Spec2-Core/SpDropListPresenter.class.st b/src/Spec2-Core/SpDropListPresenter.class.st index 8c9013d4..ccdfce3f 100644 --- a/src/Spec2-Core/SpDropListPresenter.class.st +++ b/src/Spec2-Core/SpDropListPresenter.class.st @@ -352,15 +352,11 @@ SpDropListPresenter >> whenSelectedItemChangedDo: aBlock [ { #category : 'api - events' } SpDropListPresenter >> whenSelectionChangedDo: aBlock [ "Inform when the selection is changed. - The method should be used only if you are interested in the fact that there was - a change, without caring about what has changed. + The method should be used only if you are interested in the fact that + there was a change, without caring about what has changed. If you are interested in the items, use `SpDropListPresenter>>#whenSelectedItemChanged:` - - `aBlock` receive 3 optional arguments: - - new value - - old value - - announcement triggered" + `aBlock` receives an optional argument with the selection object." selection whenChangedDo: aBlock ] diff --git a/src/Spec2-Core/SpListPresenter.class.st b/src/Spec2-Core/SpListPresenter.class.st index 50f5cfa9..fcaedfc6 100644 --- a/src/Spec2-Core/SpListPresenter.class.st +++ b/src/Spec2-Core/SpListPresenter.class.st @@ -13,8 +13,8 @@ A list presenter does not offer the possibility to add one item in isolation ins Class { #name : 'SpListPresenter', #superclass : 'SpAbstractListPresenter', - #traits : 'SpTSearchable + SpTDecoratedText', - #classTraits : 'SpTSearchable classTrait + SpTDecoratedText classTrait', + #traits : 'SpTDecoratedText', + #classTraits : 'SpTDecoratedText classTrait', #instVars : [ '#allowToSelect => ObservableSlot', '#autoDeselect => ObservableSlot', @@ -150,7 +150,7 @@ SpListPresenter >> iconFor: anItem [ SpListPresenter >> initialize [ super initialize. - self initializeTSearchable. + self enableSearch. autoDeselect := true. allowToSelect := true. display := [ :object | object asStringOrText ] diff --git a/src/Spec2-Core/SpTSearchable.trait.st b/src/Spec2-Core/SpTSearchable.trait.st index 6462a0d8..e5c970d9 100644 --- a/src/Spec2-Core/SpTSearchable.trait.st +++ b/src/Spec2-Core/SpTSearchable.trait.st @@ -47,6 +47,7 @@ SpTSearchable >> initializeTSearchable [ self searchMatching: [ :item :pattern | self performDefaultSearch: item matching: pattern ]. + self disableSearch ] { #category : 'testing' } diff --git a/src/Spec2-Core/SpTableColumn.class.st b/src/Spec2-Core/SpTableColumn.class.st index 87e49ae3..c8965431 100644 --- a/src/Spec2-Core/SpTableColumn.class.st +++ b/src/Spec2-Core/SpTableColumn.class.st @@ -117,6 +117,12 @@ SpTableColumn >> hasFixedWidth [ ^ (self width isNil or: [ self width = 0 ]) not ] +{ #category : 'testing' } +SpTableColumn >> hasTitle [ + + ^ self title isNotNil +] + { #category : 'initialization' } SpTableColumn >> initialize [ diff --git a/src/Spec2-Core/SpTablePresenter.class.st b/src/Spec2-Core/SpTablePresenter.class.st index 75a04a8a..dde8e674 100644 --- a/src/Spec2-Core/SpTablePresenter.class.st +++ b/src/Spec2-Core/SpTablePresenter.class.st @@ -8,8 +8,6 @@ A table has columns with a type (See column types section). Class { #name : 'SpTablePresenter', #superclass : 'SpAbstractListPresenter', - #traits : 'SpTSearchable', - #classTraits : 'SpTSearchable classTrait', #instVars : [ '#columns => ObservableSlot', '#showColumnHeaders => ObservableSlot', @@ -79,7 +77,7 @@ SpTablePresenter >> beResizable [ self isResizable: true ] -{ #category : 'emulating' } +{ #category : 'simulation' } SpTablePresenter >> clickOnColumnHeaderAt: anIndex [ self withAdapterDo: [ :tableAdapter | tableAdapter clickOnColumnHeaderAt: anIndex ] ] @@ -110,7 +108,7 @@ SpTablePresenter >> hideColumnHeaders [ SpTablePresenter >> initialize [ super initialize. - self initializeTSearchable. + self enableSearch. showColumnHeaders := true. columns := #(). isResizable := false @@ -142,12 +140,6 @@ SpTablePresenter >> removeColumn: aColumn [ columns := columns copyWithout: aColumn ] -{ #category : 'private' } -SpTablePresenter >> searchValueOf: anObject [ - - ^ anObject asString -] - { #category : 'api' } SpTablePresenter >> showColumnHeaders [ "Show column headers" diff --git a/src/Spec2-Core/SpToolbarToggleButtonPresenter.class.st b/src/Spec2-Core/SpToolbarToggleButtonPresenter.class.st index 21c05dca..b7dcbc99 100644 --- a/src/Spec2-Core/SpToolbarToggleButtonPresenter.class.st +++ b/src/Spec2-Core/SpToolbarToggleButtonPresenter.class.st @@ -93,6 +93,12 @@ SpToolbarToggleButtonPresenter >> isSelected [ ^ self state ] +{ #category : 'private' } +SpToolbarToggleButtonPresenter >> performAction [ + + self action value: self state +] + { #category : 'private' } SpToolbarToggleButtonPresenter >> setSelection: aBoolean [ diff --git a/src/Spec2-Core/SpTransferPresenter.class.st b/src/Spec2-Core/SpTransferPresenter.class.st index 8c1ef25f..f0eae6fa 100644 --- a/src/Spec2-Core/SpTransferPresenter.class.st +++ b/src/Spec2-Core/SpTransferPresenter.class.st @@ -5,6 +5,7 @@ Class { #name : 'SpTransferPresenter', #superclass : 'SpAbstractWidgetPresenter', #instVars : [ + '#description', '#passenger => ObservableSlot', '#source => ObservableSlot' ], @@ -19,6 +20,18 @@ SpTransferPresenter class >> adapterName [ ^ #TransferAdapter ] +{ #category : 'accessing' } +SpTransferPresenter >> description [ + + ^ description +] + +{ #category : 'accessing' } +SpTransferPresenter >> description: aString [ + + description := aString +] + { #category : 'accessing' } SpTransferPresenter >> from: aModel [ source := aModel diff --git a/src/Spec2-Core/SpTreePresenter.class.st b/src/Spec2-Core/SpTreePresenter.class.st index b3ed5ad8..de3e320e 100644 --- a/src/Spec2-Core/SpTreePresenter.class.st +++ b/src/Spec2-Core/SpTreePresenter.class.st @@ -112,7 +112,10 @@ SpTreePresenter >> hideColumnHeaders [ { #category : 'initialization' } SpTreePresenter >> initialize [ + super initialize. + + self enableSearch. self withScrollBars. diff --git a/src/Spec2-Core/SpTreeTablePresenter.class.st b/src/Spec2-Core/SpTreeTablePresenter.class.st index df730cc8..36067fd0 100644 --- a/src/Spec2-Core/SpTreeTablePresenter.class.st +++ b/src/Spec2-Core/SpTreeTablePresenter.class.st @@ -110,8 +110,11 @@ SpTreeTablePresenter >> hideColumnHeaders [ { #category : 'initialization' } SpTreeTablePresenter >> initialize [ + super initialize. + self enableSearch. + self withScrollBars. activationBlock := [ ]. diff --git a/src/Spec2-Core/SpWindowPresenter.class.st b/src/Spec2-Core/SpWindowPresenter.class.st index f09b6bef..0fcb2bd2 100644 --- a/src/Spec2-Core/SpWindowPresenter.class.st +++ b/src/Spec2-Core/SpWindowPresenter.class.st @@ -322,7 +322,7 @@ SpWindowPresenter >> initialize [ { #category : 'initialization' } SpWindowPresenter >> initializeWindow [ - + self presenter initializeWindow: self ] diff --git a/src/Spec2-Examples/SpExampleBrowser.class.st b/src/Spec2-Examples/SpExampleBrowser.class.st index 9b3c0bce..a15c9a78 100644 --- a/src/Spec2-Examples/SpExampleBrowser.class.st +++ b/src/Spec2-Examples/SpExampleBrowser.class.st @@ -128,7 +128,7 @@ SpExampleBrowser >> listMenuActions [ action: [ self browseSelectedExample ] ]; addActionWith: [ :item | item name: 'Run'; - enabled: runButton isEnabled; + actionEnabled: [ runButton isEnabled ]; action: [ self runSelectedExample ] ]; yourself ] diff --git a/src/Spec2-Examples/SpListPresenter.extension.st b/src/Spec2-Examples/SpListPresenter.extension.st index fb78f03d..ab7867e8 100644 --- a/src/Spec2-Examples/SpListPresenter.extension.st +++ b/src/Spec2-Examples/SpListPresenter.extension.st @@ -15,7 +15,9 @@ SpListPresenter class >> exampleDragAndDrop [ (list1 := self new) items: #( 'abc' 'def' 'xyz' ); - dragEnabled: true. + dragEnabled: true; + whenDragStartDo: [ :ann | + ann transfer description: ('Passing "{1}" element' format: ann transfer passenger) ]. (list2 := self new) dropEnabled: true; diff --git a/src/Spec2-ListView-Tests/SpColumnViewPresenterTest.class.st b/src/Spec2-ListView-Tests/SpColumnViewPresenterTest.class.st new file mode 100644 index 00000000..6a279c4e --- /dev/null +++ b/src/Spec2-ListView-Tests/SpColumnViewPresenterTest.class.st @@ -0,0 +1,27 @@ +Class { + #name : 'SpColumnViewPresenterTest', + #superclass : 'SpAbstractListPresenterTest', + #category : 'Spec2-ListView-Tests', + #package : 'Spec2-ListView-Tests' +} + +{ #category : 'testing' } +SpColumnViewPresenterTest class >> shouldInheritSelectors [ + + ^ true +] + +{ #category : 'accessing' } +SpColumnViewPresenterTest >> classToTest [ + + ^ SpColumnViewPresenter +] + +{ #category : 'initialization' } +SpColumnViewPresenterTest >> initializeTestedInstance [ + + presenter + addColumnTitle: 'Test' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :anObject | aPresenter label: anObject asString ] +] diff --git a/src/Spec2-ListView-Tests/SpEasyColumnViewPresenterTest.class.st b/src/Spec2-ListView-Tests/SpEasyColumnViewPresenterTest.class.st new file mode 100644 index 00000000..22f519be --- /dev/null +++ b/src/Spec2-ListView-Tests/SpEasyColumnViewPresenterTest.class.st @@ -0,0 +1,40 @@ +Class { + #name : 'SpEasyColumnViewPresenterTest', + #superclass : 'SpColumnViewPresenterTest', + #category : 'Spec2-ListView-Tests', + #package : 'Spec2-ListView-Tests' +} + +{ #category : 'accessing' } +SpEasyColumnViewPresenterTest >> classToTest [ + + ^ SpEasyColumnViewPresenter +] + +{ #category : 'initialization' } +SpEasyColumnViewPresenterTest >> initializeTestedInstance [ + + presenter addColumn: (SpStringTableColumn + title: 'Test' + evaluated: [ :anObject | anObject asString ]) +] + +{ #category : 'tests' } +SpEasyColumnViewPresenterTest >> testDisableActivationDuring [ + + self skip +] + +{ #category : 'tests - smoke' } +SpEasyColumnViewPresenterTest >> testSetSortingBlockBeforeItems [ + + "this does not has sense in a column (or table) view." + self skip +] + +{ #category : 'tests - smoke' } +SpEasyColumnViewPresenterTest >> testSortingBlock [ + + "this does not has sense in a column (or table) view." + self skip +] diff --git a/src/Spec2-ListView-Tests/SpEasyListViewPresenterTest.class.st b/src/Spec2-ListView-Tests/SpEasyListViewPresenterTest.class.st index e15a9981..6a5dcad6 100644 --- a/src/Spec2-ListView-Tests/SpEasyListViewPresenterTest.class.st +++ b/src/Spec2-ListView-Tests/SpEasyListViewPresenterTest.class.st @@ -5,6 +5,12 @@ Class { #package : 'Spec2-ListView-Tests' } +{ #category : 'testing' } +SpEasyListViewPresenterTest class >> shouldInheritSelectors [ + + ^ true +] + { #category : 'accessing' } SpEasyListViewPresenterTest >> classToTest [ @@ -15,6 +21,13 @@ SpEasyListViewPresenterTest >> classToTest [ SpEasyListViewPresenterTest >> initializeTestedInstance [ ] +{ #category : 'tests' } +SpEasyListViewPresenterTest >> testDisableActivationDuring [ + + "no needed here since this is private" + self skip +] + { #category : 'tests - header' } SpEasyListViewPresenterTest >> testHideHeaderTitleUnsetsTitle [ diff --git a/src/Spec2-ListView-Tests/SpEasyTreeColumnViewPresenterTest.class.st b/src/Spec2-ListView-Tests/SpEasyTreeColumnViewPresenterTest.class.st new file mode 100644 index 00000000..5f82600c --- /dev/null +++ b/src/Spec2-ListView-Tests/SpEasyTreeColumnViewPresenterTest.class.st @@ -0,0 +1,42 @@ +Class { + #name : 'SpEasyTreeColumnViewPresenterTest', + #superclass : 'SpAbstractTreePresenterTest', + #category : 'Spec2-ListView-Tests', + #package : 'Spec2-ListView-Tests' +} + +{ #category : 'testing' } +SpEasyTreeColumnViewPresenterTest class >> shouldInheritSelectors [ + + ^ true +] + +{ #category : 'accessing' } +SpEasyTreeColumnViewPresenterTest >> classToTest [ + + ^ SpEasyTreeColumnViewPresenter +] + +{ #category : 'initialization' } +SpEasyTreeColumnViewPresenterTest >> initializeTestedInstance [ + + presenter addColumn: (SpStringTableColumn title: 'Test' evaluated: #asString) +] + +{ #category : 'tests' } +SpEasyTreeColumnViewPresenterTest >> testDisableActivationDuring [ + + self skip +] + +{ #category : 'tests' } +SpEasyTreeColumnViewPresenterTest >> testPathIndexOf [ + + self skip +] + +{ #category : 'tests' } +SpEasyTreeColumnViewPresenterTest >> testPathItemOf [ + + self skip +] diff --git a/src/Spec2-ListView-Tests/SpEasyTreeListViewPresenterTest.class.st b/src/Spec2-ListView-Tests/SpEasyTreeListViewPresenterTest.class.st new file mode 100644 index 00000000..cfe5b9c1 --- /dev/null +++ b/src/Spec2-ListView-Tests/SpEasyTreeListViewPresenterTest.class.st @@ -0,0 +1,18 @@ +Class { + #name : 'SpEasyTreeListViewPresenterTest', + #superclass : 'SpEasyTreeColumnViewPresenterTest', + #category : 'Spec2-ListView-Tests', + #package : 'Spec2-ListView-Tests' +} + +{ #category : 'accessing' } +SpEasyTreeListViewPresenterTest >> classToTest [ + + ^ SpEasyTreeListViewPresenter +] + +{ #category : 'initialization' } +SpEasyTreeListViewPresenterTest >> initializeTestedInstance [ + + presenter display: [ :aClass | aClass asString ] +] diff --git a/src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st b/src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st index 74f5c638..78eba5c6 100644 --- a/src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st +++ b/src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st @@ -5,6 +5,12 @@ Class { #package : 'Spec2-ListView-Tests' } +{ #category : 'testing' } +SpListViewPresenterTest class >> shouldInheritSelectors [ + + ^ true +] + { #category : 'accessing' } SpListViewPresenterTest >> classToTest [ diff --git a/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st index eb6fab7b..d7606359 100644 --- a/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st @@ -21,7 +21,7 @@ SpAbstractEasyListViewPresenter >> findFirst: aString [ items isEmptyOrNil ifTrue: [ ^ 0 ]. (contentView selection selectedIndex max: 1) to: items size do: [ :index | - (self + (contentView performSearch: (items at: index) matching: aString) ifTrue: [ ^ index ] ]. @@ -75,6 +75,8 @@ SpAbstractEasyListViewPresenter >> selectFirst [ SpAbstractEasyListViewPresenter >> selectFirst: aString [ | index | + self isSearchEnabled ifFalse: [ ^ self ]. + index := self findFirst: aString. index = 0 ifTrue: [ ^ self ]. @@ -93,6 +95,14 @@ SpAbstractEasyListViewPresenter >> selectItem: anObject [ contentView selectItem: anObject ] +{ #category : 'api - selection' } +SpAbstractEasyListViewPresenter >> selectItem: anObject scrollToSelection: aBoolean [ + + contentView + selectItem: anObject + scrollToSelection: aBoolean +] + { #category : 'api - selection' } SpAbstractEasyListViewPresenter >> selectedIndex [ diff --git a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st index b3f7a20f..53a93c19 100644 --- a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st @@ -1,12 +1,10 @@ Class { #name : 'SpAbstractEasyPresenter', #superclass : 'SpPresenter', - #traits : 'SpTSearchable', - #classTraits : 'SpTSearchable classTrait', #instVars : [ '#contentView', - '#searchInput', - '#lastSelectedRow => WeakSlot' + '#lastSelectedRow => WeakSlot', + '#searchBox' ], #category : 'Spec2-ListView-Easy', #package : 'Spec2-ListView', @@ -40,13 +38,16 @@ SpAbstractEasyPresenter >> activateOnSingleClick [ { #category : 'private' } SpAbstractEasyPresenter >> activateSearchWith: aString [ + self isSearchEnabled ifFalse: [ ^ self ]. + + "keep last in case we need to go back there (if user cancels)" lastSelectedRow := contentView selectedItem. - searchInput text: aString. - searchInput show. - searchInput takeKeyboardFocus. - searchInput unselectAll. - searchInput cursorPositionIndex: aString size + searchBox show. + searchBox text: aString. + searchBox takeKeyboardFocus. + searchBox unselectAll. + searchBox cursorPositionIndex: aString size + 1 ] { #category : 'api' } @@ -71,18 +72,14 @@ SpAbstractEasyPresenter >> beSingleSelection [ { #category : 'initialization' } SpAbstractEasyPresenter >> connectPresenters [ - searchInput - addAction: (SpAction - newShortcutKey: Character escape asKeyCombination - action: [ self deactivateSearch: false ]); - addAction: (SpAction - newShortcutKey: Character cr asKeyCombination - action: [ self deactivateSearch: true ]); - whenTextChangedDo: [ :aString | self selectFirst: aString ]. + searchBox + whenTextChangedDo: [ :aString | self selectFirst: aString ]; + whenAcceptedDo: [ self deactivateSearch: true ]; + whenDismissedDo: [ self deactivateSearch: false ]. contentView eventHandler whenKeyDownDo: [ :event | self maybeActivateSearchOn: event ]; - whenFocusReceivedDo: [ :event | searchInput hide ] + whenFocusReceivedDo: [ :event | searchBox hide ] ] { #category : 'api - actions' } @@ -96,7 +93,7 @@ SpAbstractEasyPresenter >> deactivateSearch: acceptSelection [ | currentSelection | currentSelection := contentView selectedItem. - searchInput hide. + searchBox hide. contentView selectItem: (acceptSelection ifTrue: [ currentSelection ] ifFalse: [ lastSelectedRow ]). @@ -113,8 +110,10 @@ SpAbstractEasyPresenter >> defaultInputPort [ SpAbstractEasyPresenter >> defaultLayout [ ^ SpOverlayLayout new - child: contentView; - addOverlay: searchInput withConstraints: [ :c | c vAlignStart; hAlignEnd ]; + child: (SpBoxLayout newTopToBottom + add: contentView; + yourself); + addOverlay: searchBox withConstraints: [ :c | c vAlignStart; hAlignEnd ]; yourself ] @@ -130,12 +129,26 @@ SpAbstractEasyPresenter >> disable [ self enabled: false ] +{ #category : 'api' } +SpAbstractEasyPresenter >> disableSearch [ + "Disable searching" + + contentView disableSearch +] + { #category : 'api' } SpAbstractEasyPresenter >> enable [ self enabled: true ] +{ #category : 'api' } +SpAbstractEasyPresenter >> enableSearch [ + "Enable searching" + + contentView enableSearch +] + { #category : 'private - actions' } SpAbstractEasyPresenter >> ensureActions [ @@ -146,15 +159,14 @@ SpAbstractEasyPresenter >> ensureActions [ SpAbstractEasyPresenter >> initialize [ super initialize. - self initializeTSearchable. self registerEvents ] { #category : 'initialization' } SpAbstractEasyPresenter >> initializePresenters [ - searchInput := self newTextInput. - searchInput hide + searchBox := self instantiate: SpEasySearchBoxPresenter. + searchBox hide ] { #category : 'transmission' } @@ -179,6 +191,13 @@ SpAbstractEasyPresenter >> isActiveOnSingleClick [ ^ contentView isActiveOnSingleClick ] +{ #category : 'testing' } +SpAbstractEasyPresenter >> isSearchEnabled [ + "Answer true if search is enabled (See `SpTSearchable>>#enableSearch`)" + + ^ contentView isSearchEnabled +] + { #category : 'private' } SpAbstractEasyPresenter >> maybeActivateSearchOn: event [ @@ -187,7 +206,12 @@ SpAbstractEasyPresenter >> maybeActivateSearchOn: event [ (event anyModifierKeyPressed or: [ (event keyValue between: 32 and: 127) not ]) ifTrue: [ ^ self ]. - self activateSearchWith: event keyCharacter asString + + event wasHandled: true. + "I need to defer it beacuse in morphic this causes the event to + be passed to the box (no idea why)." + self application defer: [ + self activateSearchWith: event keyCharacter asString ] ] { #category : 'transmission' } @@ -210,10 +234,20 @@ SpAbstractEasyPresenter >> outputSelectionPort [ SpAbstractEasyPresenter >> registerEvents [ ] +{ #category : 'api' } +SpAbstractEasyPresenter >> searchMatching: aBlock [ + "Enables search and defines a block to perform a search on the model objects. + The block receives two parameters: + - item (the model element) + - pattern (the string to match)" + + contentView searchMatching: aBlock +] + { #category : 'private' } SpAbstractEasyPresenter >> selectFirst: aString [ - self subclassResponsibility + contentView selectFirst: aString ] { #category : 'api - events' } @@ -222,6 +256,17 @@ SpAbstractEasyPresenter >> whenActivatedDo: aBlock [ contentView whenActivatedDo: aBlock ] +{ #category : 'api - events' } +SpAbstractEasyPresenter >> whenSearchEnabledChangedDo: aBlock [ + "Inform when search enabled/disabled has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenSearchModeChangedDo: aBlock +] + { #category : 'api - events' } SpAbstractEasyPresenter >> whenSelectionChangedDo: aBlock [ diff --git a/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st index 4284b057..fbbcb59e 100644 --- a/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st @@ -25,6 +25,12 @@ SpAbstractEasyTreeListViewPresenter >> children: aBlock [ contentView children: aBlock ] +{ #category : 'simulation' } +SpAbstractEasyTreeListViewPresenter >> clickAtPath: aPath [ + + contentView clickAtPath: aPath +] + { #category : 'api' } SpAbstractEasyTreeListViewPresenter >> collapseAll [ "Collapse all nodes of the tree. " @@ -40,12 +46,30 @@ SpAbstractEasyTreeListViewPresenter >> collapsePath: aPath [ contentView collapsePath: aPath ] +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> contextMenu [ + + ^ contentView contextMenu +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> contextMenu: aBlock [ + + contentView contextMenu: aBlock +] + { #category : 'transmission' } SpAbstractEasyTreeListViewPresenter >> defaultInputPort [ ^ self inputRootsPort ] +{ #category : 'simulation' } +SpAbstractEasyTreeListViewPresenter >> doubleClickAtPath: aPath [ + + contentView doubleClickAtPath: aPath +] + { #category : 'api' } SpAbstractEasyTreeListViewPresenter >> expandAll [ "Expand all nodes of the tree. @@ -69,20 +93,19 @@ SpAbstractEasyTreeListViewPresenter >> expandRoots [ contentView expandRoots ] -{ #category : 'initialization' } -SpAbstractEasyTreeListViewPresenter >> initialize [ - - super initialize. - self initializeTSearchable. - self registerEvents -] - { #category : 'transmission' } SpAbstractEasyTreeListViewPresenter >> inputRootsPort [ ^ SpRootsPort newPresenter: self ] +{ #category : 'testing' } +SpAbstractEasyTreeListViewPresenter >> isExpanded: aPath [ + + ^ contentView isExpanded: aPath + +] + { #category : 'api' } SpAbstractEasyTreeListViewPresenter >> items: aCollection [ "Set the roots of a tree. This is a convenience method, synonym of `SpTreePresenter>>#roots:`" @@ -263,6 +286,12 @@ SpAbstractEasyTreeListViewPresenter >> updateRootsKeepingSelection: aCollection contentView updateRootsKeepingSelection: aCollection ] +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenMenuChangedDo: aBlock [ + + contentView whenMenuChangedDo: aBlock +] + { #category : 'api - events' } SpAbstractEasyTreeListViewPresenter >> whenMultiSelectionChangedDo: aBlock [ "Inform when selection mode has changed. diff --git a/src/Spec2-ListView/SpColumnViewColumn.class.st b/src/Spec2-ListView/SpColumnViewColumn.class.st index 2af93177..f9cdd441 100644 --- a/src/Spec2-ListView/SpColumnViewColumn.class.st +++ b/src/Spec2-ListView/SpColumnViewColumn.class.st @@ -1,3 +1,6 @@ +" +A column definition to be used with `SpColumnViewPresenter` and `SpTreeColumnViewPresenter` +" Class { #name : 'SpColumnViewColumn', #superclass : 'Object', @@ -6,7 +9,8 @@ Class { 'bind', 'setup', 'expand', - 'width' + 'width', + 'sortFunction' ], #category : 'Spec2-ListView-Widget', #package : 'Spec2-ListView', @@ -59,6 +63,12 @@ SpColumnViewColumn >> hasFixedWidth [ ^ width notNil ] +{ #category : 'testing' } +SpColumnViewColumn >> hasTitle [ + + ^ self title isNotNil +] + { #category : 'initialization' } SpColumnViewColumn >> initialize [ @@ -74,6 +84,12 @@ SpColumnViewColumn >> isExpand [ ^ expand ] +{ #category : 'testing' } +SpColumnViewColumn >> isSortable [ + + ^ self sortFunction isNotNil +] + { #category : 'api' } SpColumnViewColumn >> setup: aBlock [ @@ -86,6 +102,18 @@ SpColumnViewColumn >> setupAction [ ^ setup ] +{ #category : 'accessing' } +SpColumnViewColumn >> sortFunction [ + + ^ sortFunction +] + +{ #category : 'accessing' } +SpColumnViewColumn >> sortFunction: aSortFunction [ + + sortFunction := aSortFunction +] + { #category : 'api' } SpColumnViewColumn >> title [ diff --git a/src/Spec2-ListView/SpColumnViewPresenter.class.st b/src/Spec2-ListView/SpColumnViewPresenter.class.st index 7f656091..0266acaf 100644 --- a/src/Spec2-ListView/SpColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpColumnViewPresenter.class.st @@ -1,6 +1,11 @@ +" +A column view presenter displays tabular data. It replaces the old table presenter but is a lot more customisable, as, in opposition to the old implementation, it accepts any presenter as table cell. +" Class { #name : 'SpColumnViewPresenter', #superclass : 'SpAbstractListPresenter', + #traits : 'SpTSearchable', + #classTraits : 'SpTSearchable classTrait', #instVars : [ '#columns => ObservableSlot', '#isResizable => ObservableSlot', @@ -21,7 +26,6 @@ SpColumnViewPresenter class >> adapterName [ SpColumnViewPresenter class >> example [ ^ self new - application: (SpApplication new useBackend: #Gtk); addColumnTitle: 'Class' setup: [ :aPresenter | aPresenter newLabel ] bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; @@ -33,7 +37,7 @@ SpColumnViewPresenter class >> example [ SpColumnViewPresenter class >> exampleActivateOnDoubleClick [ ^ self new - application: (SpApplication new useBackend: #Gtk); + application: SpApplication new; isActiveOnDoubleClick; addColumnTitle: 'Class' setup: [ :aPresenter | aPresenter newLabel ] @@ -47,7 +51,7 @@ SpColumnViewPresenter class >> exampleActivateOnDoubleClick [ SpColumnViewPresenter class >> exampleResizableColumns [ ^ self new - application: (SpApplication new useBackend: #Gtk); + application: SpApplication new; beResizable; items: Smalltalk allClasses; addColumnTitle: 'Class' @@ -63,7 +67,7 @@ SpColumnViewPresenter class >> exampleResizableColumns [ SpColumnViewPresenter class >> exampleWithIcons [ ^ self new - application: (SpApplication new useBackend: #Gtk); + application: SpApplication new; addColumnTitle: 'Class' setup: [ :aPresenter | | presenter | @@ -153,7 +157,9 @@ SpColumnViewPresenter >> hideColumnHeaders [ SpColumnViewPresenter >> initialize [ super initialize. + self initializeTSearchable. self showColumnHeaders. + self beNotResizable. columns := #() ] diff --git a/src/Spec2-ListView/SpDropDownPresenter.class.st b/src/Spec2-ListView/SpDropDownPresenter.class.st index 28b59788..c57f0e7c 100644 --- a/src/Spec2-ListView/SpDropDownPresenter.class.st +++ b/src/Spec2-ListView/SpDropDownPresenter.class.st @@ -1,3 +1,7 @@ +" +A drop down presenter displays a drop down. +It replaces the old drop list presenter. +" Class { #name : 'SpDropDownPresenter', #superclass : 'SpAbstractWidgetPresenter', diff --git a/src/Spec2-ListView/SpEasyAbstractRowPresenter.class.st b/src/Spec2-ListView/SpEasyAbstractRowPresenter.class.st index f02d0077..be1962fe 100644 --- a/src/Spec2-ListView/SpEasyAbstractRowPresenter.class.st +++ b/src/Spec2-ListView/SpEasyAbstractRowPresenter.class.st @@ -6,9 +6,9 @@ Class { #instVars : [ 'listView' ], - #category : 'Spec2-ListView-Widget', + #category : 'Spec2-ListView-Easy', #package : 'Spec2-ListView', - #tag : 'Widget' + #tag : 'Easy' } { #category : 'accessing' } diff --git a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st index e3685cc4..6e42b49f 100644 --- a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st @@ -11,7 +11,7 @@ SpEasyColumnViewPresenter class >> example [ "This example show the simples list view you can make: A list with a label" self new - application: (SpApplication new useBackend: #Gtk); + application: SpApplication new; items: self environment allClasses; addColumn: (SpStringTableColumn new title: 'Class'; @@ -44,6 +44,44 @@ SpEasyColumnViewPresenter class >> exampleActivateOnDoubleClick [ open ] +{ #category : 'examples' } +SpEasyColumnViewPresenter class >> exampleResizableColumns [ + "This example show the simples list view you can make: A list with a label" + + self new + application: SpApplication new; + items: self environment allClasses; + beResizable; + addColumn: (SpStringTableColumn new + title: 'Class'; + evaluated: [ :each | each name ]; + yourself); + addColumn: (SpStringTableColumn new + title: 'Lines of code'; + evaluated: [ :each | each linesOfCode ]; + yourself); + open +] + +{ #category : 'examples' } +SpEasyColumnViewPresenter class >> exampleWithColumnWidth [ + "This example show the simples list view you can make: A list with a label" + + self new + application: SpApplication new; + items: self environment allClasses; + addColumn: (SpStringTableColumn new + title: 'Class'; + evaluated: [ :each | each name ]; + yourself); + addColumn: (SpStringTableColumn new + title: 'Lines of code'; + evaluated: [ :each | each linesOfCode ]; + width: 50; + yourself); + open +] + { #category : 'api' } SpEasyColumnViewPresenter >> addColumn: aColumn [ @@ -62,17 +100,29 @@ SpEasyColumnViewPresenter >> beResizable [ contentView beResizable ] -{ #category : 'accessing' } +{ #category : 'simulation' } +SpEasyColumnViewPresenter >> clickAtIndex: aNumber [ + + contentView clickAtIndex: aNumber +] + +{ #category : 'api' } SpEasyColumnViewPresenter >> columns: aCollection [ contentView columns: aCollection ] +{ #category : 'api' } +SpEasyColumnViewPresenter >> contextMenu [ + + ^ contentView contextMenu +] + { #category : 'api' } SpEasyColumnViewPresenter >> contextMenu: aBlock [ - self flag: #TODO. "ignored, as this is deprecated" + contentView contextMenu: aBlock ] { #category : 'private' } @@ -81,6 +131,12 @@ SpEasyColumnViewPresenter >> displayValueFor: aImage [ ^ contentView displayValueFor: aImage ] +{ #category : 'simulation' } +SpEasyColumnViewPresenter >> doubleClickAtIndex: aNumber [ + + contentView doubleClickAtIndex: aNumber +] + { #category : 'api' } SpEasyColumnViewPresenter >> hideColumnHeaders [ @@ -91,8 +147,7 @@ SpEasyColumnViewPresenter >> hideColumnHeaders [ SpEasyColumnViewPresenter >> initializePresenters [ super initializePresenters. - contentView := self newColumnView. - + contentView := self newColumnView ] { #category : 'testing' } @@ -102,6 +157,12 @@ SpEasyColumnViewPresenter >> isShowingColumnHeaders [ ^ contentView isShowingColumnHeaders ] +{ #category : 'api - selection' } +SpEasyColumnViewPresenter >> selectAll [ + + contentView selectAll +] + { #category : 'api' } SpEasyColumnViewPresenter >> showColumnHeaders [ @@ -114,6 +175,12 @@ SpEasyColumnViewPresenter >> unselectAll [ contentView unselectAll ] +{ #category : 'api' } +SpEasyColumnViewPresenter >> updateItemsKeepingSelection: aSequenceableCollection [ + + contentView updateItemsKeepingSelection: aSequenceableCollection +] + { #category : 'api - events' } SpEasyColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ @@ -121,13 +188,19 @@ SpEasyColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ ] -{ #category : 'enumerating' } +{ #category : 'api - events' } +SpEasyColumnViewPresenter >> whenMenuChangedDo: aBlock [ + + contentView whenMenuChangedDo: aBlock +] + +{ #category : 'api - events' } SpEasyColumnViewPresenter >> whenSelectedDo: aBlock [ contentView whenSelectedDo: aBlock ] -{ #category : 'enumerating' } +{ #category : 'api - events' } SpEasyColumnViewPresenter >> whenSelectedItemChangedDo: aBlock [ contentView whenSelectedItemChangedDo: aBlock diff --git a/src/Spec2-ListView/SpEasyListRowPresenter.class.st b/src/Spec2-ListView/SpEasyListRowPresenter.class.st index 364990b8..df2efe3d 100644 --- a/src/Spec2-ListView/SpEasyListRowPresenter.class.st +++ b/src/Spec2-ListView/SpEasyListRowPresenter.class.st @@ -5,9 +5,9 @@ Class { 'iconPresenter', 'textPresenter' ], - #category : 'Spec2-ListView-Widget', + #category : 'Spec2-ListView-Easy', #package : 'Spec2-ListView', - #tag : 'Widget' + #tag : 'Easy' } { #category : 'layout' } @@ -46,6 +46,7 @@ SpEasyListRowPresenter >> listView: aListView [ SpEasyListRowPresenter >> textLayout [ ^ SpBoxLayout newHorizontal + borderWidth: 2; add: textPresenter; yourself ] diff --git a/src/Spec2-ListView/SpEasyListViewPresenter.class.st b/src/Spec2-ListView/SpEasyListViewPresenter.class.st index f4683efa..51efa770 100644 --- a/src/Spec2-ListView/SpEasyListViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyListViewPresenter.class.st @@ -23,7 +23,6 @@ SpEasyListViewPresenter class >> example [ "This example show a simple list with all classes, using all the default settings." ^ self new - application: (SpApplication new useBackend: #Gtk); items: self environment allClasses; open; yourself @@ -33,7 +32,6 @@ SpEasyListViewPresenter class >> example [ SpEasyListViewPresenter class >> exampleMultipleSelection [ ^ self new - application: (SpApplication new useBackend: #Gtk); items: self environment allClasses; beMultipleSelection; open; @@ -44,7 +42,6 @@ SpEasyListViewPresenter class >> exampleMultipleSelection [ SpEasyListViewPresenter class >> exampleWithHeaderTitle [ ^ self new - application: (SpApplication new useBackend: #Gtk); items: self environment allClasses; headerTitle: 'Title'; open; @@ -56,35 +53,45 @@ SpEasyListViewPresenter class >> exampleWithIcons [ "This example show a simple list with icons." ^ self new - application: (SpApplication new useBackend: #Gtk); displayIcon: [ :e | self iconNamed: #forwardIcon ]; items: (1 to: 10) asArray; open; yourself ] +{ #category : 'simulation' } +SpEasyListViewPresenter >> clickAtIndex: aNumber [ + + contentView clickAtIndex: aNumber +] + { #category : 'initialization' } SpEasyListViewPresenter >> connectPresenters [ super connectPresenters ] +{ #category : 'api' } +SpEasyListViewPresenter >> contextMenu [ + + ^ contentView contextMenu +] + { #category : 'api' } SpEasyListViewPresenter >> contextMenu: aBlock [ - self flag: #TODO. "Ignored, as this should be deprecated" - + contentView contextMenu: aBlock ] { #category : 'layout' } SpEasyListViewPresenter >> defaultLayout [ ^ SpOverlayLayout new - child: (SpBoxLayout newVertical + child: (SpBoxLayout newTopToBottom add: headerPanel expand: false; add: contentView; yourself); - addOverlay: searchInput withConstraints: [ :c | c vAlignStart; hAlignEnd ]; + addOverlay: searchBox withConstraints: [ :c | c vAlignStart; hAlignEnd ]; yourself ] @@ -134,6 +141,12 @@ SpEasyListViewPresenter >> displayValueFor: anObject [ ^ self display value: anObject ] +{ #category : 'simulation' } +SpEasyListViewPresenter >> doubleClickAtIndex: aNumber [ + + contentView doubleClickAtIndex: aNumber +] + { #category : 'testing' } SpEasyListViewPresenter >> hasHeaderTitle [ "Answer true if the list has a title (See `SpListPresenter>>#headerTitle:`)." @@ -223,6 +236,24 @@ SpEasyListViewPresenter >> rowPresenterClass: aClass [ rowPresenterClass := aClass ] +{ #category : 'api - selection' } +SpEasyListViewPresenter >> selectAll [ + + contentView selectAll +] + +{ #category : 'api' } +SpEasyListViewPresenter >> sortingBlock: aBlock [ + + contentView sortingBlock: aBlock +] + +{ #category : 'api - selection' } +SpEasyListViewPresenter >> unselectAll [ + + contentView unselectAll +] + { #category : 'api' } SpEasyListViewPresenter >> updateItemsKeepingSelection: aCollection [ @@ -250,3 +281,15 @@ SpEasyListViewPresenter >> whenIconsChangedDo: aBlock [ self property: #displayIcon whenChangedDo: aBlock ] + +{ #category : 'api - events' } +SpEasyListViewPresenter >> whenMenuChangedDo: aBlock [ + + contentView whenMenuChangedDo: aBlock +] + +{ #category : 'api - events' } +SpEasyListViewPresenter >> whenSortingBlockChangedDo: aBlock [ + + contentView whenSortingBlockChangedDo: aBlock +] diff --git a/src/Spec2-ListView/SpEasySearchBoxAccepted.class.st b/src/Spec2-ListView/SpEasySearchBoxAccepted.class.st new file mode 100644 index 00000000..f7c0fa26 --- /dev/null +++ b/src/Spec2-ListView/SpEasySearchBoxAccepted.class.st @@ -0,0 +1,10 @@ +" +Announces that a search has been accepted (usually hitting enter) +" +Class { + #name : 'SpEasySearchBoxAccepted', + #superclass : 'Announcement', + #category : 'Spec2-ListView-Easy', + #package : 'Spec2-ListView', + #tag : 'Easy' +} diff --git a/src/Spec2-ListView/SpEasySearchBoxDismissed.class.st b/src/Spec2-ListView/SpEasySearchBoxDismissed.class.st new file mode 100644 index 00000000..68fc3851 --- /dev/null +++ b/src/Spec2-ListView/SpEasySearchBoxDismissed.class.st @@ -0,0 +1,10 @@ +" +Announces that a search box has been dismissed (by pressing a button or escaping) +" +Class { + #name : 'SpEasySearchBoxDismissed', + #superclass : 'Announcement', + #category : 'Spec2-ListView-Easy', + #package : 'Spec2-ListView', + #tag : 'Easy' +} diff --git a/src/Spec2-ListView/SpEasySearchBoxPresenter.class.st b/src/Spec2-ListView/SpEasySearchBoxPresenter.class.st new file mode 100644 index 00000000..eb25cc79 --- /dev/null +++ b/src/Spec2-ListView/SpEasySearchBoxPresenter.class.st @@ -0,0 +1,119 @@ +" +A component to display a search box (to be used with ""easy"" presenters) +" +Class { + #name : 'SpEasySearchBoxPresenter', + #superclass : 'SpPresenter', + #instVars : [ + 'textInput', + 'closeButton' + ], + #category : 'Spec2-ListView-Easy', + #package : 'Spec2-ListView', + #tag : 'Easy' +} + +{ #category : 'private' } +SpEasySearchBoxPresenter >> announceAccepted [ + + self announcer announce: SpEasySearchBoxAccepted +] + +{ #category : 'private' } +SpEasySearchBoxPresenter >> announceDismissed [ + + self announcer announce: SpEasySearchBoxDismissed +] + +{ #category : 'initialization' } +SpEasySearchBoxPresenter >> connectPresenters [ + + textInput + addAction: (SpAction + newShortcutKey: Character escape asKeyCombination + action: [ self announceDismissed ]); + addAction: (SpAction + newShortcutKey: Character cr asKeyCombination + action: [ self announceAccepted ]) +] + +{ #category : 'api' } +SpEasySearchBoxPresenter >> cursorPositionIndex: aNumber [ + + textInput cursorPositionIndex: aNumber +] + +{ #category : 'layout' } +SpEasySearchBoxPresenter >> defaultLayout [ + + ^ SpBoxLayout newLeftToRight + borderWidth: 3; + spacing: 3; + add: textInput; + add: closeButton expand: false; + yourself +] + +{ #category : 'initialization' } +SpEasySearchBoxPresenter >> initializePresenters [ + + self addStyle: 'searchBox'. + + textInput := self newSearchInput. + closeButton := self newButton + addStyle: 'small'; + addStyle: 'flat'; + icon: (self iconNamed: #close); + action: [ + self hide. + self announceDismissed ]; + yourself +] + +{ #category : 'api' } +SpEasySearchBoxPresenter >> text [ + + ^ textInput text +] + +{ #category : 'api' } +SpEasySearchBoxPresenter >> text: aString [ + + textInput text: aString +] + +{ #category : 'accessing' } +SpEasySearchBoxPresenter >> textInput [ + + ^ textInput +] + +{ #category : 'api - selection' } +SpEasySearchBoxPresenter >> unselectAll [ + + textInput unselectAll +] + +{ #category : 'api - events' } +SpEasySearchBoxPresenter >> whenAcceptedDo: aBlock [ + + self announcer + when: SpEasySearchBoxAccepted + do: aBlock + for: aBlock receiver. +] + +{ #category : 'api - events' } +SpEasySearchBoxPresenter >> whenDismissedDo: aBlock [ + + self announcer + when: SpEasySearchBoxDismissed + do: aBlock + for: aBlock receiver. +] + +{ #category : 'api - events' } +SpEasySearchBoxPresenter >> whenTextChangedDo: aBlock [ + + textInput whenTextChangedDo: aBlock +] diff --git a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st index 68b3c7f8..3443dc97 100644 --- a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st @@ -60,12 +60,6 @@ SpEasyTreeColumnViewPresenter >> columns: aCollection [ self flag: #TODO ] -{ #category : 'api' } -SpEasyTreeColumnViewPresenter >> contextMenu: aBlock [ - - "do nothing, this does not work on gtk4" -] - { #category : 'api' } SpEasyTreeColumnViewPresenter >> hideColumnHeaders [ "Hide the column headers" diff --git a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st index 215c826f..2da03e9f 100644 --- a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st @@ -18,12 +18,6 @@ SpEasyTreeListViewPresenter class >> defaultRowPresenterClass [ ^ SpEasyListRowPresenter ] -{ #category : 'api' } -SpEasyTreeListViewPresenter >> contextMenu: aBlock [ - - self flag: #TODO -] - { #category : 'layout' } SpEasyTreeListViewPresenter >> defaultLayout [ @@ -32,7 +26,7 @@ SpEasyTreeListViewPresenter >> defaultLayout [ add: headerPanel expand: false; add: contentView; yourself); - addOverlay: searchInput withConstraints: [ :c | c vAlignStart; hAlignEnd ]; + addOverlay: searchBox withConstraints: [ :c | c vAlignStart; hAlignEnd ]; yourself ] diff --git a/src/Spec2-ListView/SpTableColumn.extension.st b/src/Spec2-ListView/SpTableColumn.extension.st index 1e12dc15..232aa291 100644 --- a/src/Spec2-ListView/SpTableColumn.extension.st +++ b/src/Spec2-ListView/SpTableColumn.extension.st @@ -6,6 +6,7 @@ SpTableColumn >> asColumnViewColumn [ ^ SpColumnViewColumn new title: self title; expand: (self width isNil and: [ self isExpandable ]); + sortFunction: self sortFunction; width: self width; setup: [ :aPresenter | SpEasyColumnSetupBuilder new diff --git a/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st index 49090d81..6596ae3e 100644 --- a/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st @@ -1,3 +1,8 @@ +" +A tree column view presenter displays a tree of tabular data. +It replaces the old tree table presenter but is a lot more customisable, as, in opposition to the old implementation, it accepts any presenter as tree table cell. + +" Class { #name : 'SpTreeColumnViewPresenter', #superclass : 'SpAbstractTreePresenter', @@ -21,7 +26,7 @@ SpTreeColumnViewPresenter class >> adapterName [ SpTreeColumnViewPresenter class >> example [ ^ self new - application: (SpApplication new useBackend: #Gtk); + application: SpApplication new; addColumnTitle: 'Class' setup: [ :aPresenter | aPresenter newLabel ] bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; @@ -212,6 +217,19 @@ SpTreeColumnViewPresenter >> isShowingColumnHeaders [ ^ showColumnHeaders ] +{ #category : 'initialization' } +SpTreeColumnViewPresenter >> registerActions [ + + super registerActions. + self ensureInternalActions + addShortcutWith: [ :action | action + shortcutKey: KeyboardKey right asKeyCombination | KeyboardKey space asKeyCombination; + action: [ self expandPath: self selection selectedPath ] ]; + addShortcutWith: [ :action | action + shortcutKey: KeyboardKey left asKeyCombination; + action: [ self collapsePath: self selection selectedPath ] ] +] + { #category : 'api' } SpTreeColumnViewPresenter >> showColumnHeaders [ "Show column headers" diff --git a/src/Spec2-ListView/SpTreeListViewPresenter.class.st b/src/Spec2-ListView/SpTreeListViewPresenter.class.st index a95b2044..5b63cdce 100644 --- a/src/Spec2-ListView/SpTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpTreeListViewPresenter.class.st @@ -1,3 +1,8 @@ +" +A tree list view presenter displays a tree. +It replaces the old tree list presenter but is a lot more customisable, as, in opposition to the old implementation, it accepts any presenter as tree cell. + +" Class { #name : 'SpTreeListViewPresenter', #superclass : 'SpAbstractTreePresenter', @@ -23,7 +28,7 @@ SpTreeListViewPresenter class >> example [ "This example show the simples list view you can make: A list with a label" self new - application: (SpApplication new useBackend: #Gtk); + application: SpApplication new; items: { Object }; children: [ :aClass | aClass subclasses ]; setup: [ :aPresenter | aPresenter newLabel ]; @@ -230,7 +235,6 @@ SpTreeListViewPresenter >> initialize [ self beSingleSelection. self activateOnDoubleClick. - self registerActions. self initializeItemFactory ] @@ -242,6 +246,19 @@ SpTreeListViewPresenter >> initializeItemFactory [ self bind: [ :aPresenter :anObject | aPresenter label: anObject asString ] ] +{ #category : 'initialization' } +SpTreeListViewPresenter >> registerActions [ + + super registerActions. + self ensureInternalActions + addShortcutWith: [ :action | action + shortcutKey: KeyboardKey right asKeyCombination | KeyboardKey space asKeyCombination; + action: [ self expandPath: self selection selectedPath ] ]; + addShortcutWith: [ :action | action + shortcutKey: KeyboardKey left asKeyCombination; + action: [ self collapsePath: self selection selectedPath ] ] +] + { #category : 'initialization' } SpTreeListViewPresenter >> registerEvents [ diff --git a/src/Spec2-Tests/SpAbstractTextPresenterTest.class.st b/src/Spec2-Tests/SpAbstractTextPresenterTest.class.st index 370269aa..4cc9f02a 100644 --- a/src/Spec2-Tests/SpAbstractTextPresenterTest.class.st +++ b/src/Spec2-Tests/SpAbstractTextPresenterTest.class.st @@ -111,15 +111,14 @@ SpAbstractTextPresenterTest >> testCursorPositionIndex [ presenter text: (String loremIpsum: 80). self openInstance. "cursor position does not works if instance is not opened" - "If not defined, cursor is at begining" - self assert: presenter cursorPositionIndex equals: 1. + "If not defined, cursor is at the end of a " + self assert: presenter cursorPositionIndex equals: 81. "middle" presenter cursorPositionIndex: 20. self assert: presenter cursorPositionIndex equals: 20. "end" presenter cursorPositionIndex: 81. self assert: presenter cursorPositionIndex equals: 81 - ] { #category : 'tests' } @@ -162,6 +161,20 @@ SpAbstractTextPresenterTest >> testSelectAllWithoutOpening [ self assert: presenter selectionInterval equals: (1 to: 15) ] +{ #category : 'tests' } +SpAbstractTextPresenterTest >> testTextIsSetAndCursorPositionedCorrectly [ + + presenter text: 'aText'. + "no cursor position before is open" + self assert: presenter cursorPositionIndex equals: nil. + self openInstance. + "now it has to be placed at the end" + self assert: presenter cursorPositionIndex equals: 6. + "now change it already opened" + presenter text: 'aTextAText'. + self assert: presenter cursorPositionIndex equals: 11 +] + { #category : 'tests' } SpAbstractTextPresenterTest >> testWhenResetDo [ | reseted | diff --git a/src/Spec2-Tests/SpTextPresenterTest.class.st b/src/Spec2-Tests/SpTextPresenterTest.class.st index 865b4ea3..31c7cd10 100644 --- a/src/Spec2-Tests/SpTextPresenterTest.class.st +++ b/src/Spec2-Tests/SpTextPresenterTest.class.st @@ -113,6 +113,7 @@ SpTextPresenterTest >> testSelectLine [ with multiple lines'. self openInstance. + presenter cursorPositionIndex: 1. presenter selectLine. self assert: presenter selectionInterval equals: (1 to: 15) ]