From 9aad3994cbc130674fc9898a62493552ff3db16c Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Mon, 29 Apr 2024 17:21:45 +0200 Subject: [PATCH 01/58] fix removed selector --- src/Spec2-Transmission/SpTransmission.class.st | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Spec2-Transmission/SpTransmission.class.st b/src/Spec2-Transmission/SpTransmission.class.st index 7223a2c4..4fb0a8a3 100644 --- a/src/Spec2-Transmission/SpTransmission.class.st +++ b/src/Spec2-Transmission/SpTransmission.class.st @@ -140,7 +140,8 @@ SpTransmission >> from: aPresenter port: aSymbol to: anotherPresenter transform: SpTransmission >> from: aPresenter port: aSymbol to: anotherPresenter transform: aValuable postTransmission: anotherValuable [ self - from: aPresenter port: aSymbol; + from: aPresenter; + fromPort: aSymbol; to: anotherPresenter; transform: aValuable; postTransmission: anotherValuable; From a3f0205e0163a9817529147308e458f3b6152fa0 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Mon, 10 Jun 2024 13:10:41 +0200 Subject: [PATCH 02/58] add tree family of components (treelist. treecolumn, easy*), still not completely there. --- .../SpAbstractTreePresenter.extension.st | 6 - ...AbstractEasyTreeListViewPresenter.class.st | 345 ++++++++++++++++++ .../SpAbstractListPresenter.class.st | 1 + .../SpAbstractTreePresenter.class.st | 79 ++-- .../SpComponentListPresenter.class.st | 1 + src/Spec2-Core/SpDropListPresenter.class.st | 16 +- .../SpEditableListPresenter.class.st | 6 +- src/Spec2-Core/SpJobListPresenter.class.st | 6 - src/Spec2-Core/SpStringTableColumn.class.st | 6 +- src/Spec2-Core/SpTPresenterBuilder.trait.st | 12 +- .../SpTreeSingleSelectionMode.class.st | 2 +- src/Spec2-Core/SpTreeTablePresenter.class.st | 12 +- .../SpAbstractMessageDialog.class.st | 2 +- .../SpAbstractEasyListViewPresenter.class.st | 147 ++++++++ .../SpAbstractEasyPresenter.class.st | 221 +++++++++++ ...AbstractEasyTreeListViewPresenter.class.st | 345 ++++++++++++++++++ .../SpApplicationBackend.extension.st | 33 ++ .../SpColumnViewColumn.class.st | 110 ++++++ .../SpColumnViewPresenter.class.st | 165 +++++++++ .../SpDropDownPresenter.class.st | 12 + .../SpEasyColumnViewPresenter.class.st | 89 +++++ .../SpEasyListViewPresenter.class.st | 256 +------------ .../SpEasyTreeColumnViewPresenter.class.st | 125 +++++++ .../SpEasyTreeListViewPresenter.class.st | 6 + .../SpImageTableColumn.extension.st | 13 + .../SpListViewPresenter.class.st | 49 ++- .../SpMorphicBackend.extension.st | 31 ++ .../SpTPresenterBuilder.extension.st | 36 ++ src/Spec2-ListView/SpTableColumn.extension.st | 13 + .../SpTreeColumnViewPresenter.class.st | 229 ++++++++++++ .../SpTreeListViewPresenter.class.st | 271 ++++++++++++++ .../SpecGtkBackend.extension.st | 31 ++ .../SpAbstractTreePresenter.extension.st | 31 -- 33 files changed, 2361 insertions(+), 346 deletions(-) delete mode 100644 src/Spec2-Commander2/SpAbstractTreePresenter.extension.st create mode 100644 src/Spec2-Core/SpAbstractEasyTreeListViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpAbstractEasyPresenter.class.st create mode 100644 src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpApplicationBackend.extension.st create mode 100644 src/Spec2-ListView/SpColumnViewColumn.class.st create mode 100644 src/Spec2-ListView/SpColumnViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpEasyColumnViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpImageTableColumn.extension.st create mode 100644 src/Spec2-ListView/SpMorphicBackend.extension.st create mode 100644 src/Spec2-ListView/SpTableColumn.extension.st create mode 100644 src/Spec2-ListView/SpTreeColumnViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpTreeListViewPresenter.class.st create mode 100644 src/Spec2-ListView/SpecGtkBackend.extension.st delete mode 100644 src/Spec2-Transmission/SpAbstractTreePresenter.extension.st diff --git a/src/Spec2-Commander2/SpAbstractTreePresenter.extension.st b/src/Spec2-Commander2/SpAbstractTreePresenter.extension.st deleted file mode 100644 index bb2ff41a..00000000 --- a/src/Spec2-Commander2/SpAbstractTreePresenter.extension.st +++ /dev/null @@ -1,6 +0,0 @@ -Extension { #name : 'SpAbstractTreePresenter' } - -{ #category : '*Spec2-Commander2' } -SpAbstractTreePresenter >> contextMenuFromCommandsGroup: aValuable [ - self contextMenu: [ aValuable value beRoot asMenuPresenter ] -] diff --git a/src/Spec2-Core/SpAbstractEasyTreeListViewPresenter.class.st b/src/Spec2-Core/SpAbstractEasyTreeListViewPresenter.class.st new file mode 100644 index 00000000..f1fc9786 --- /dev/null +++ b/src/Spec2-Core/SpAbstractEasyTreeListViewPresenter.class.st @@ -0,0 +1,345 @@ +" +A base for tree presenters, it defines basic functionality common to all trees. +" +Class { + #name : 'SpAbstractEasyTreeListViewPresenter', + #superclass : 'SpAbstractEasyPresenter', + #classTraits : 'SpTSearchable classTrait', + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'testing' } +SpAbstractEasyTreeListViewPresenter class >> isAbstract [ + + ^ super isAbstract or: [ self = SpAbstractTreePresenter ] +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> children: aBlock [ + "Set a block to answer the children of a node when it is expanded. + `aBlock` receives one argument, the node element to expand. + If there are no children to answer, `aBlock` needs to answer an empty collection." + + contentView children: aBlock +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> collapseAll [ + "Collapse all nodes of the tree. " + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter collapseAll ] +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> collapsePath: aPath [ + "Collapse the tree path. + `aPath` is the path to collapse. A path is an array of node indexes (e.g. #(1 2 3))" + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter collapsePath: aPath ] +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> defaultInputPort [ + + ^ self inputRootsPort +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> defaultOutputPort [ + + ^ self outputSelectionPort +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> expandAll [ + "Expand all nodes of the tree. + WARNING: If your tree is big, this operation can be slow." + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter expandAll ] +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> expandPath: aPath [ + "Expand the tree path. + `aPath` is the path to expand. A path is an array of node indexes (e.g. #(1 2 3))" + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter expandPath: aPath ] +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> expandRoots [ + "Expand all roots of the tree" + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter expandRoots ] +] + +{ #category : 'initialization' } +SpAbstractEasyTreeListViewPresenter >> initialize [ + + super initialize. + self initializeTSearchable. + self registerEvents +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> inputRootsPort [ + + ^ SpRootsPort newPresenter: self +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> items: aCollection [ + "Set the roots of a tree. This is a convenience method, synonym of `SpTreePresenter>>#roots:`" + + self roots: aCollection +] + +{ #category : 'private' } +SpAbstractEasyTreeListViewPresenter >> lazilyComputeChildren: aBoolean [ + + self flag: #TODO. +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> outputActivationPort [ + + ^ SpActivationPort newPresenter: self +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> outputSelectionPort [ + + ^ SpSelectionPort newPresenter: self +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> refresh [ + "Forces a refresh of the tree. + This is useful when some model contents has changed, but we do not want to reset the whole list + (and losing selections with it)" + + self withAdapterDo: [ :anAdapter | anAdapter refreshTree ] +] + +{ #category : 'initialization' } +SpAbstractEasyTreeListViewPresenter >> registerEvents [ + + "self whenMenuChangedDo: [ + self withAdapterDo: [ :anAdapter | anAdapter updateMenu ] ]" +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> roots [ + "Answer the roots of the tree" + + ^ contentView roots +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> roots: aCollection [ + "Set the roots of the tree table. + This is the starting point from where the whole tree will be shown." + + contentView roots: aCollection +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectItem: anItem [ + "Select `anItem` if it is included in model list. + It does not scrolls to selected element." + + self selection selectItem: anItem +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectItems: aListOfItem [ + "Select items included in `aCollection` if they are included in model list. + NOTE: In single selection mode it will select the first element of `aCollection` + It does not scrolls to selected element." + + self selection selectItems: aListOfItem +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPath: aPath [ + "Selects element in `aPath` + `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3)). + It does not scrolls to selected element." + + self selection selectPath: aPath +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPath: aPath scrollToSelection: shouldScrollToSelection [ + "Selects element in `aPath` + `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3)). + If `shouldScrollToSelection` is true, it will scroll to selected element. + IMPORTANT: Scrolling to selection just has sense when the widget is already shown, because before it + is displayed it does not has real bounds. In morphic (and gtk) it has a minimal extent assigned, + but that will change as soon as the widget is inserted in a container and the container applies its + layout." + + contentView + selectPath: aPath + scrollToSelection: shouldScrollToSelection +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPathByItems: pathArray [ + + self selectPathByItems: pathArray scrollToSelection: false +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPathByItems: pathArray scrollToSelection: aBoolean [ + "IMPORTANT: Scrolling to selection just has sense when the widget is already shown, because before it + is displayed it does not has real bounds. In morphic (and gtk) it has a minimal extent assigned, + but that will change as soon as the widget is inserted in a container and the container applies its + layout." + | pathIndexes | + + pathIndexes := self pathIndexOf: pathArray. + pathIndexes size > 1 ifTrue: [ + self expandPath: pathIndexes allButLast ]. + self + selectPath: pathIndexes + scrollToSelection: aBoolean +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPaths: pathArray [ + "Selects all elements in `pathsArray`` + `pathsArray` is an array of paths. A path is an array of node indexes (e.g. #(1 2 3))" + + self selection selectPaths: pathArray +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectedItem [ + "Return selected item." + + ^ self selection selectedItem +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectedItems [ + "Return all the selected items in the case of a multiple selection list" + + ^ self selection selectedItems +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selection [ + "Answer the selection object (an instance of `SpSingleSelectionMode` or `SpMultipleSelectionMode`). + This is not the item selected, but the selection container (it may contain one or many selected + items)" + + ^ contentView selection +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> selectionMode [ + "Answer the selection object (an instance of `SpSingleSelectionMode` or `SpMultipleSelectionMode`). + This is not the item selected, but the selection container (it may contain one or many selected + items). + This is the same as `SpAbstractListPresenter>>#selection`" + + ^ contentView selectionMode +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> unselectAll [ + "Remove all selections" + + self selection unselectAll +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> unselectItem: anItem [ + "Remove selection of element `anItem`" + + self selection unselectItem: anItem +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> unselectPath: aPath [ + "Unselects element in `aPath` + `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3))" + + self selection unselectPath: aPath +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> updateRootsKeepingSelection: aCollection [ + "Update tree roots keeping current selection. + WARNING: aCollection must includes the elements selected." + + contentView updateRootsKeepingSelection: aCollection +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenMultiSelectionChangedDo: aBlock [ + "Inform when selection mode has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenMultiSelectionChangedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenRootsChangedDo: aBlock [ + "Inform when roots have changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenRootsChangedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenSelectedIndexChangedDo: aBlock [ + "Inform when selected index has changed. + `aBlock` receives one optional argument (the new element)." + + contentView whenSelectedIndexChangedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenSelectedItemChangedDo: aBlock [ + "Inform when selected index has changed. + `aBlock` receives one optional argument (the new element)." + + contentView whenSelectedItemChangedDo: aBlock + +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenSelectionChangedDo: aBlock [ + "Inform when selection has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenSelectionChangedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenShowColumnHeadersChangedDo: aBlock [ + "Inform when showColumnHeaders property has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenShowColumnHeadersChangedDo: aBlock +] diff --git a/src/Spec2-Core/SpAbstractListPresenter.class.st b/src/Spec2-Core/SpAbstractListPresenter.class.st index 83755284..988a8eb1 100644 --- a/src/Spec2-Core/SpAbstractListPresenter.class.st +++ b/src/Spec2-Core/SpAbstractListPresenter.class.st @@ -126,6 +126,7 @@ SpAbstractListPresenter >> disableActivationDuring: aBlock [ SpAbstractListPresenter >> doActivateAtIndex: anIndex [ "Activate only if there is an item at that position" + activationBlock ifNil: [ ^ self ]. self model at: anIndex ifAbsent: [ ^ self ]. activationBlock cull: ((SpSingleSelectionMode on: self) diff --git a/src/Spec2-Core/SpAbstractTreePresenter.class.st b/src/Spec2-Core/SpAbstractTreePresenter.class.st index e36f761c..238aa005 100644 --- a/src/Spec2-Core/SpAbstractTreePresenter.class.st +++ b/src/Spec2-Core/SpAbstractTreePresenter.class.st @@ -25,7 +25,7 @@ SpAbstractTreePresenter class >> isAbstract [ ^ super isAbstract or: [ self = SpAbstractTreePresenter ] ] -{ #category : 'api' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> activateOnDoubleClick [ "Configure the list to trigger activation on double click. An element on a list can be 'activated', meaning it will trigger an event to execute an @@ -36,7 +36,7 @@ SpAbstractTreePresenter >> activateOnDoubleClick [ activateOnSingleClick := false ] -{ #category : 'api' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> activateOnSingleClick [ "Configure the list to trigger activation on single click. An element on a list can be 'activated', meaning it will trigger an event to execute an @@ -47,7 +47,7 @@ SpAbstractTreePresenter >> activateOnSingleClick [ activateOnSingleClick := true ] -{ #category : 'testing' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> activatesOnDoubleClick [ "Answer true if activation event is triggered on double click" @@ -58,7 +58,7 @@ SpAbstractTreePresenter >> activatesOnDoubleClick [ ^ activateOnSingleClick not ] -{ #category : 'testing' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> activatesOnSingleClick [ "Answer true if activation event is triggered on single click" @@ -69,21 +69,21 @@ SpAbstractTreePresenter >> activatesOnSingleClick [ ^ activateOnSingleClick ] -{ #category : 'api' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> beMultipleSelection [ "Enable multiple selection." self selectionMode: (SpTreeMultipleSelectionMode on: self) ] -{ #category : 'api' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> beSingleSelection [ "Enable single selection (this is the default)." self selectionMode: (SpTreeSingleSelectionMode on: self) ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> children [ ^ childrenBlock @@ -98,13 +98,13 @@ SpAbstractTreePresenter >> children: aBlock [ childrenBlock := aBlock ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> childrenFor: anObject [ ^ self children value: anObject ] -{ #category : 'simulation' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> clickAtPath: aPath [ self selectPaths: { aPath }. @@ -130,7 +130,7 @@ SpAbstractTreePresenter >> collapsePath: aPath [ anAdapter collapsePath: aPath ] ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> disableActivationDuring: aBlock [ | oldActivate | @@ -140,17 +140,31 @@ SpAbstractTreePresenter >> disableActivationDuring: aBlock [ activationBlock := oldActivate ] ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> doActivateAtPath: aPath [ "Activate only if there is an item at that position" + activationBlock ifNil: [ ^ self ]. self itemAtPath: aPath ifAbsent: [ ^ self ]. activationBlock cull: ((SpTreeSingleSelectionMode on: self) selectPath: aPath; yourself) ] -{ #category : 'simulation' } +{ #category : 'as yet unclassified' } +SpAbstractTreePresenter >> doActivateSelected [ + "Activate only if there is an item at that position" + | selectedPath | + + activationBlock ifNil: [ ^ self ]. + selectedPath := self selection selectedPath. + selectedPath ifNil: [ ^ self ]. + activationBlock cull: ((SpTreeSingleSelectionMode on: self) + selectPath: selectedPath; + yourself) +] + +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> doubleClickAtPath: aPath [ self selectPath: aPath. @@ -189,24 +203,25 @@ SpAbstractTreePresenter >> initialize [ super initialize. self initializeTSearchable. - self initializeTHaveWrappingScrollBars + self initializeTHaveWrappingScrollBars. + self withScrollBars ] -{ #category : 'testing' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> isActiveOnDoubleClick [ "Answer true if activation event is triggered on double click" ^ activateOnSingleClick not ] -{ #category : 'testing' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> isActiveOnSingleClick [ "Answer true if activation event is triggered on single click" ^ activateOnSingleClick ] -{ #category : 'testing' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> isExpanded: aPath [ self withAdapterDo: [ :anAdapter | @@ -215,7 +230,7 @@ SpAbstractTreePresenter >> isExpanded: aPath [ ^ false ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> itemAt: index of: anArray then: path [ "dives into elements of tree to find the one that corresponds to path" | element | @@ -231,7 +246,7 @@ SpAbstractTreePresenter >> itemAt: index of: anArray then: path [ element ] ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> itemAtPath: anArray [ self withAdapterDo: [ :anAdapter | @@ -243,7 +258,7 @@ SpAbstractTreePresenter >> itemAtPath: anArray [ then: anArray allButFirst ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> itemAtPath: anArray ifAbsent: aBlock [ ^ [ self itemAtPath: anArray ] on: SubscriptOutOfBounds @@ -257,7 +272,7 @@ SpAbstractTreePresenter >> items: aCollection [ self roots: aCollection ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> pathIndexOf: anArrayOfElements [ ^ self @@ -265,7 +280,7 @@ SpAbstractTreePresenter >> pathIndexOf: anArrayOfElements [ in: self roots ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> pathIndexOf: pathArray in: aCollection [ | pathElement | @@ -278,7 +293,7 @@ SpAbstractTreePresenter >> pathIndexOf: pathArray in: aCollection [ ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> pathItemOf: aPath [ "answer an array of items following a path. e.g. #(1 2 3) = { item1. item2. item3 }" @@ -288,7 +303,7 @@ SpAbstractTreePresenter >> pathItemOf: aPath [ in: self roots ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> pathItemOf: pathArray in: aCollection [ | pathElement | @@ -333,7 +348,7 @@ SpAbstractTreePresenter >> roots: aCollection [ self selection clearSelection ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> searchValueOf: item [ ^ item asString @@ -433,7 +448,17 @@ SpAbstractTreePresenter >> selection [ ^ selectionMode value ] -{ #category : 'private' } +{ #category : 'api' } +SpAbstractTreePresenter >> selectionMode [ + "Answer the selection object (an instance of `SpSingleSelectionMode` or `SpMultipleSelectionMode`). + This is not the item selected, but the selection container (it may contain one or many selected + items). + This is the same as `SpAbstractListPresenter>>#selection`" + + ^ selectionMode +] + +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> selectionMode: aMode [ selectionMode ifNotNil: [ @@ -477,12 +502,12 @@ SpAbstractTreePresenter >> updateRootsKeepingSelection: aCollection [ self selectPaths: (selectedPaths collect: [ :each | self pathIndexOf: each ]) ] ] ] -{ #category : 'private' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> verticalAlignment [ ^ verticalAlignment ] -{ #category : 'api - events' } +{ #category : 'as yet unclassified' } SpAbstractTreePresenter >> whenActivatedDo: aBlock [ "Inform when an element has been 'activated'. `aBlock` receives one argument (a selection object, see `SpAbstractSelectionMode`)" diff --git a/src/Spec2-Core/SpComponentListPresenter.class.st b/src/Spec2-Core/SpComponentListPresenter.class.st index f7dbce81..05eaa677 100644 --- a/src/Spec2-Core/SpComponentListPresenter.class.st +++ b/src/Spec2-Core/SpComponentListPresenter.class.st @@ -33,6 +33,7 @@ SpComponentListPresenter >> addPresenter: aPresenter [ SpComponentListPresenter >> doActivateAtIndex: index [ "Activate only if there is an item at that position" + activationBlock ifNil: [ ^ self ]. self presenters at: index ifAbsent: [ ^ self ]. activationBlock cull: ((SpSingleSelectionMode on: self) diff --git a/src/Spec2-Core/SpDropListPresenter.class.st b/src/Spec2-Core/SpDropListPresenter.class.st index 728ed958..55aa548b 100644 --- a/src/Spec2-Core/SpDropListPresenter.class.st +++ b/src/Spec2-Core/SpDropListPresenter.class.st @@ -257,7 +257,13 @@ SpDropListPresenter >> resetSelection [ self selection unselectAll ] -{ #category : 'api' } +{ #category : 'api - selection' } +SpDropListPresenter >> selectFirst [ + + self selectIndex: 1 +] + +{ #category : 'api - selection' } SpDropListPresenter >> selectIndex: anInteger [ "Select the element at position `anInteger` and executes the action associated with it." @@ -268,7 +274,7 @@ SpDropListPresenter >> selectIndex: anInteger [ self selection selectedItem value ] -{ #category : 'api' } +{ #category : 'api - selection' } SpDropListPresenter >> selectItem: anItem [ "Select the element `anItem` if it is in the list. It executes the action associated with the item if it is defined." @@ -284,7 +290,7 @@ SpDropListPresenter >> selectItem: anItem [ realItem value ] -{ #category : 'api' } +{ #category : 'api - selection' } SpDropListPresenter >> selectedIndex [ "Answer the index of selected item. You usually do not need to use this method but `SpDropListPresenter>>#selectedItem`." @@ -292,7 +298,7 @@ SpDropListPresenter >> selectedIndex [ ^ self getIndex ] -{ #category : 'api' } +{ #category : 'api - selection' } SpDropListPresenter >> selectedItem [ "Answer selected item" @@ -300,7 +306,7 @@ SpDropListPresenter >> selectedItem [ ifNotNil: [ :anItem | anItem model ] ] -{ #category : 'api' } +{ #category : 'api - selection' } SpDropListPresenter >> selection [ "Answer selection model, an instance of `SpSingleSelectionMode`." diff --git a/src/Spec2-Core/SpEditableListPresenter.class.st b/src/Spec2-Core/SpEditableListPresenter.class.st index d124c2a8..eafd01aa 100644 --- a/src/Spec2-Core/SpEditableListPresenter.class.st +++ b/src/Spec2-Core/SpEditableListPresenter.class.st @@ -148,7 +148,7 @@ SpEditableListPresenter >> initializeDialogWindow: aWindow [ { #category : 'initialization' } SpEditableListPresenter >> initializePresenters [ label := self newLabel. - list := self newList. + list := self newEasyListView. addButton := self newButton. removeButton := self newButton. upButton := self newButton. @@ -312,6 +312,6 @@ SpEditableListPresenter >> upButton [ ] { #category : 'api' } -SpEditableListPresenter >> whenSelectionChangedDo: aBlockClosure [ - list whenSelectionChangedDo: aBlockClosure +SpEditableListPresenter >> whenSelectionChangedDo: aBlock [ + list whenSelectionChangedDo: aBlock ] diff --git a/src/Spec2-Core/SpJobListPresenter.class.st b/src/Spec2-Core/SpJobListPresenter.class.st index 079f9d3b..d18cb74e 100644 --- a/src/Spec2-Core/SpJobListPresenter.class.st +++ b/src/Spec2-Core/SpJobListPresenter.class.st @@ -120,12 +120,6 @@ SpJobListPresenter >> jobEnd: ann [ self removeJobPresenter: ann job ] ] -{ #category : 'private' } -SpJobListPresenter >> jobPresenterHeight [ - - ^ 80 -] - { #category : 'private - events' } SpJobListPresenter >> jobStart: ann [ diff --git a/src/Spec2-Core/SpStringTableColumn.class.st b/src/Spec2-Core/SpStringTableColumn.class.st index 730826b5..d68995f7 100644 --- a/src/Spec2-Core/SpStringTableColumn.class.st +++ b/src/Spec2-Core/SpStringTableColumn.class.st @@ -125,7 +125,7 @@ SpStringTableColumn >> onAcceptEdition: aBlock [ acceptAction := aBlock ] -{ #category : #api } +{ #category : 'api' } SpStringTableColumn >> onTextChanged: aBlock [ "Set the block to execute when cell edition is edited. `aBlock` receives two arguments: @@ -135,7 +135,7 @@ SpStringTableColumn >> onTextChanged: aBlock [ textChanged := aBlock ] -{ #category : #api } +{ #category : 'api' } SpStringTableColumn >> sortFunction [ ^ super sortFunction ifNil: [ self evaluation ascending ] @@ -156,7 +156,7 @@ SpStringTableColumn >> sortFunction: aBlockOrSortFunction [ self isSortable: aBlockOrSortFunction isNotNil ] -{ #category : #accessing } +{ #category : 'accessing' } SpStringTableColumn >> textChanged [ ^ textChanged diff --git a/src/Spec2-Core/SpTPresenterBuilder.trait.st b/src/Spec2-Core/SpTPresenterBuilder.trait.st index ef41427d..dce2778d 100644 --- a/src/Spec2-Core/SpTPresenterBuilder.trait.st +++ b/src/Spec2-Core/SpTPresenterBuilder.trait.st @@ -82,7 +82,8 @@ SpTPresenterBuilder >> newDiff [ { #category : 'scripting - widgets' } SpTPresenterBuilder >> newDropList [ - ^ self instantiate: SpDropListPresenter + + ^ self instantiate: self application backend dropListClass ] { #category : 'scripting - widgets' } @@ -124,7 +125,8 @@ SpTPresenterBuilder >> newLink [ { #category : 'scripting - widgets' } SpTPresenterBuilder >> newList [ - ^ self instantiate: SpListPresenter + + ^ self instantiate: self application backend listClass ] { #category : 'scripting - widgets' } @@ -254,7 +256,7 @@ SpTPresenterBuilder >> newStatusBar [ { #category : 'scripting - widgets' } SpTPresenterBuilder >> newTable [ - ^ self instantiate: SpTablePresenter + ^ self instantiate: self application backend tableClass ] { #category : 'scripting - widgets' } @@ -306,11 +308,11 @@ SpTPresenterBuilder >> newToolbarToggleButton [ { #category : 'scripting - widgets' } SpTPresenterBuilder >> newTree [ - ^ self instantiate: SpTreePresenter + ^ self instantiate: self application backend treeClass ] { #category : 'scripting - widgets' } SpTPresenterBuilder >> newTreeTable [ - ^ self instantiate: SpTreeTablePresenter + ^ self instantiate: self application backend treeTableClass ] diff --git a/src/Spec2-Core/SpTreeSingleSelectionMode.class.st b/src/Spec2-Core/SpTreeSingleSelectionMode.class.st index 2ce3cfaf..215e5d73 100644 --- a/src/Spec2-Core/SpTreeSingleSelectionMode.class.st +++ b/src/Spec2-Core/SpTreeSingleSelectionMode.class.st @@ -20,7 +20,7 @@ SpTreeSingleSelectionMode >> selectPath: aPath [ presenter itemAtPath: aPath ifAbsent: [ ^ self ]. - selection := aPath. + selection := aPath ] diff --git a/src/Spec2-Core/SpTreeTablePresenter.class.st b/src/Spec2-Core/SpTreeTablePresenter.class.st index 1e3e9b8d..a3bee84e 100644 --- a/src/Spec2-Core/SpTreeTablePresenter.class.st +++ b/src/Spec2-Core/SpTreeTablePresenter.class.st @@ -65,7 +65,7 @@ SpTreeTablePresenter >> addColumn: aColumn [ columns := self columns copyWith: aColumn ] -{ #category : 'drawing' } +{ #category : 'api' } SpTreeTablePresenter >> alternateRowsColor [ " Will alternate Rows color for a better reading: one row lighter, the next row darker" self withAdapterPerformOrDefer: [ :tableAdapter | tableAdapter alternateRowsColor ]. @@ -161,16 +161,6 @@ SpTreeTablePresenter >> lazilyComputeChildren: aBoolean [ lazilyComputeChildren := aBoolean ] -{ #category : 'api' } -SpTreeTablePresenter >> selectionMode [ - "Answer the selection object (an instance of `SpSingleSelectionMode` or `SpMultipleSelectionMode`). - This is not the item selected, but the selection container (it may contain one or many selected - items). - This is the same as `SpAbstractListPresenter>>#selection`" - - ^ selectionMode -] - { #category : 'private' } SpTreeTablePresenter >> shouldLazilyComputeChildren [ ^ lazilyComputeChildren diff --git a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st index 8b41e2f0..0fa88212 100644 --- a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st +++ b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st @@ -113,7 +113,7 @@ SpAbstractMessageDialog >> initializeDialogWindow: aDialogWindowPresenter [ SpAbstractMessageDialog >> initializePresenters [ image := self newImage image: self defaultIcon. - label := self newDialogLabel. + label := self newDialogLabel ] { #category : 'initialization' } diff --git a/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st new file mode 100644 index 00000000..cef37325 --- /dev/null +++ b/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st @@ -0,0 +1,147 @@ +Class { + #name : 'SpAbstractEasyListViewPresenter', + #superclass : 'SpAbstractEasyPresenter', + #classTraits : 'SpTSearchable classTrait', + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> addScrollBarStyle: aStyle [ + + contentView addScrollBarStyle: aStyle +] + +{ #category : 'private' } +SpAbstractEasyListViewPresenter >> findFirst: aString [ + | items | + + items := contentView items. + items isEmptyOrNil ifTrue: [ ^ 0 ]. + + (contentView selection selectedIndex max: 1) to: items size do: [ :index | + (self + performSearch: (items at: index) + matching: aString) + ifTrue: [ ^ index ] ]. + + ^ 0 +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> items [ + + ^ contentView items +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> items: aCollection [ + + contentView items: aCollection +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> model [ + + ^ contentView model +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> removeScrollBarStyle: aStyle [ + + ^ contentView removeScrollBarStyle: aStyle +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> scrollBarStyles [ + + ^ contentView scrollBarStyles +] + +{ #category : 'selection' } +SpAbstractEasyListViewPresenter >> selectFirst [ + + contentView selectFirst +] + +{ #category : 'private' } +SpAbstractEasyListViewPresenter >> selectFirst: aString [ + | index | + + index := self findFirst: aString. + index = 0 ifTrue: [ ^ self ]. + + contentView selectIndex: index scrollToSelection: true +] + +{ #category : 'accessing' } +SpAbstractEasyListViewPresenter >> selectIndex: anInteger [ + + contentView selectIndex: anInteger +] + +{ #category : 'api - selection' } +SpAbstractEasyListViewPresenter >> selectItem: anObject [ + + contentView selectItem: anObject +] + +{ #category : 'api - selection' } +SpAbstractEasyListViewPresenter >> selectedIndex [ + + ^ contentView selectedIndex + +] + +{ #category : 'api - selection' } +SpAbstractEasyListViewPresenter >> selectedItem [ + + ^ contentView selectedItem +] + +{ #category : 'accessing' } +SpAbstractEasyListViewPresenter >> selectedItems [ + + ^ contentView selectedItems +] + +{ #category : 'accessing' } +SpAbstractEasyListViewPresenter >> selection [ + + ^ contentView selection +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> showColumnHeaders [ + + self flag: #TODO +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> sortingBlock: aBlock [ + + self model sortingBlock: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyListViewPresenter >> whenDisplayChangedDo: aBlock [ + "Inform when the display block has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + self property: #display whenChangedDo: aBlock +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> withScrollBars [ + + contentView withScrollBars +] + +{ #category : 'api' } +SpAbstractEasyListViewPresenter >> withoutScrollBars [ + + contentView withoutScrollBars +] diff --git a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st new file mode 100644 index 00000000..f489307f --- /dev/null +++ b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st @@ -0,0 +1,221 @@ +Class { + #name : 'SpAbstractEasyPresenter', + #superclass : 'SpPresenter', + #traits : 'SpTSearchable', + #classTraits : 'SpTSearchable classTrait', + #instVars : [ + '#contentView', + '#searchInput', + '#lastSelectedRow => WeakSlot' + ], + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'api - actions' } +SpAbstractEasyPresenter >> actionGroup [ + + ^ contentView actionGroup +] + +{ #category : 'api - actions' } +SpAbstractEasyPresenter >> actionGroup: aSpCommandGroup [ + + contentView actionGroup: aSpCommandGroup +] + +{ #category : 'api' } +SpAbstractEasyPresenter >> activateOnDoubleClick [ + + contentView activateOnDoubleClick +] + +{ #category : 'api' } +SpAbstractEasyPresenter >> activateOnSingleClick [ + + contentView activateOnSingleClick +] + +{ #category : 'private' } +SpAbstractEasyPresenter >> activateSearchWith: aString [ + + lastSelectedRow := contentView selectedItem. + + searchInput text: aString. + searchInput show. + searchInput takeKeyboardFocus. + searchInput unselectAll. + searchInput cursorPositionIndex: aString size +] + +{ #category : 'api - actions' } +SpAbstractEasyPresenter >> addAction: aSpCommand [ + + contentView addAction: aSpCommand +] + +{ #category : 'api' } +SpAbstractEasyPresenter >> beMultipleSelection [ + + contentView beMultipleSelection +] + +{ #category : 'api' } +SpAbstractEasyPresenter >> beSingleSelection [ + + contentView beSingleSelection +] + +{ #category : 'initialization' } +SpAbstractEasyPresenter >> connectPresenters [ + + searchInput + addAction: (SpAction + newShortcut: Character escape asKeyCombination + action: [ self deactivateSearch: false ]); + addAction: (SpAction + newShortcut: Character cr asKeyCombination + action: [ self deactivateSearch: true ]); + whenTextChangedDo: [ :aString | self selectFirst: aString ]. + + contentView eventHandler + whenKeyDownDo: [ :event | self maybeActivateSearchOn: event ]; + whenFocusReceivedDo: [ :event | searchInput hide ] +] + +{ #category : 'as yet unclassified' } +SpAbstractEasyPresenter >> contextMenuFromCommandsGroup: aValuable [ + + self flag: #TODO +] + +{ #category : 'private' } +SpAbstractEasyPresenter >> deactivateSearch: acceptSelection [ + | currentSelection | + + currentSelection := contentView selectedItem. + searchInput hide. + contentView selectItem: (acceptSelection + ifTrue: [ currentSelection ] + ifFalse: [ lastSelectedRow ]). + contentView takeKeyboardFocus +] + +{ #category : 'transmission' } +SpAbstractEasyPresenter >> defaultInputPort [ + + ^ self inputItemsPort +] + +{ #category : 'layout' } +SpAbstractEasyPresenter >> defaultLayout [ + + ^ SpOverlayLayout new + child: contentView; + addOverlay: searchInput withConstraints: [ :c | c vAlignStart; hAlignEnd ]; + yourself +] + +{ #category : 'transmission' } +SpAbstractEasyPresenter >> defaultOutputPort [ + + ^ self outputSelectionPort +] + +{ #category : 'api' } +SpAbstractEasyPresenter >> disable [ + + self enabled: false +] + +{ #category : 'api' } +SpAbstractEasyPresenter >> enable [ + + self enabled: true +] + +{ #category : 'initialization' } +SpAbstractEasyPresenter >> initialize [ + + super initialize. + self initializeTSearchable. + self registerEvents +] + +{ #category : 'initialization' } +SpAbstractEasyPresenter >> initializePresenters [ + + searchInput := self newTextInput. + searchInput hide +] + +{ #category : 'transmission' } +SpAbstractEasyPresenter >> inputItemsPort [ + + ^ (SpListItemsPort newPresenter: self) + delegateTo: [ contentView ]; + yourself +] + +{ #category : 'testing' } +SpAbstractEasyPresenter >> isActiveOnDoubleClick [ + "Answer true if activation event is triggered on double click" + + ^ contentView isActiveOnDoubleClick +] + +{ #category : 'testing' } +SpAbstractEasyPresenter >> isActiveOnSingleClick [ + "Answer true if activation event is triggered on single click" + + ^ contentView isActiveOnSingleClick +] + +{ #category : 'private' } +SpAbstractEasyPresenter >> maybeActivateSearchOn: event [ + + self isSearchEnabled ifFalse: [ ^ self ]. + "any modifier other than shift?" + (event anyModifierKeyPressed + or: [ (event keyValue between: 32 and: 127) not ]) + ifTrue: [ ^ self ]. + self activateSearchWith: event keyCharacter asString +] + +{ #category : 'transmission' } +SpAbstractEasyPresenter >> outputActivationPort [ + + ^ (SpActivationPort newPresenter: self) + delegateTo: [ contentView ]; + yourself +] + +{ #category : 'transmission' } +SpAbstractEasyPresenter >> outputSelectionPort [ + + ^ (SpSelectionPort newPresenter: self) + delegateTo: [ contentView ]; + yourself +] + +{ #category : 'initialization' } +SpAbstractEasyPresenter >> registerEvents [ +] + +{ #category : 'private' } +SpAbstractEasyPresenter >> selectFirst: aString [ + + self subclassResponsibility +] + +{ #category : 'api - events' } +SpAbstractEasyPresenter >> whenActivatedDo: aBlock [ + + contentView whenActivatedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyPresenter >> whenSelectionChangedDo: aBlock [ + + contentView whenSelectionChangedDo: aBlock +] diff --git a/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st new file mode 100644 index 00000000..f1fc9786 --- /dev/null +++ b/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st @@ -0,0 +1,345 @@ +" +A base for tree presenters, it defines basic functionality common to all trees. +" +Class { + #name : 'SpAbstractEasyTreeListViewPresenter', + #superclass : 'SpAbstractEasyPresenter', + #classTraits : 'SpTSearchable classTrait', + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'testing' } +SpAbstractEasyTreeListViewPresenter class >> isAbstract [ + + ^ super isAbstract or: [ self = SpAbstractTreePresenter ] +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> children: aBlock [ + "Set a block to answer the children of a node when it is expanded. + `aBlock` receives one argument, the node element to expand. + If there are no children to answer, `aBlock` needs to answer an empty collection." + + contentView children: aBlock +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> collapseAll [ + "Collapse all nodes of the tree. " + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter collapseAll ] +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> collapsePath: aPath [ + "Collapse the tree path. + `aPath` is the path to collapse. A path is an array of node indexes (e.g. #(1 2 3))" + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter collapsePath: aPath ] +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> defaultInputPort [ + + ^ self inputRootsPort +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> defaultOutputPort [ + + ^ self outputSelectionPort +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> expandAll [ + "Expand all nodes of the tree. + WARNING: If your tree is big, this operation can be slow." + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter expandAll ] +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> expandPath: aPath [ + "Expand the tree path. + `aPath` is the path to expand. A path is an array of node indexes (e.g. #(1 2 3))" + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter expandPath: aPath ] +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> expandRoots [ + "Expand all roots of the tree" + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter expandRoots ] +] + +{ #category : 'initialization' } +SpAbstractEasyTreeListViewPresenter >> initialize [ + + super initialize. + self initializeTSearchable. + self registerEvents +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> inputRootsPort [ + + ^ SpRootsPort newPresenter: self +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> items: aCollection [ + "Set the roots of a tree. This is a convenience method, synonym of `SpTreePresenter>>#roots:`" + + self roots: aCollection +] + +{ #category : 'private' } +SpAbstractEasyTreeListViewPresenter >> lazilyComputeChildren: aBoolean [ + + self flag: #TODO. +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> outputActivationPort [ + + ^ SpActivationPort newPresenter: self +] + +{ #category : 'transmission' } +SpAbstractEasyTreeListViewPresenter >> outputSelectionPort [ + + ^ SpSelectionPort newPresenter: self +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> refresh [ + "Forces a refresh of the tree. + This is useful when some model contents has changed, but we do not want to reset the whole list + (and losing selections with it)" + + self withAdapterDo: [ :anAdapter | anAdapter refreshTree ] +] + +{ #category : 'initialization' } +SpAbstractEasyTreeListViewPresenter >> registerEvents [ + + "self whenMenuChangedDo: [ + self withAdapterDo: [ :anAdapter | anAdapter updateMenu ] ]" +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> roots [ + "Answer the roots of the tree" + + ^ contentView roots +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> roots: aCollection [ + "Set the roots of the tree table. + This is the starting point from where the whole tree will be shown." + + contentView roots: aCollection +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectItem: anItem [ + "Select `anItem` if it is included in model list. + It does not scrolls to selected element." + + self selection selectItem: anItem +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectItems: aListOfItem [ + "Select items included in `aCollection` if they are included in model list. + NOTE: In single selection mode it will select the first element of `aCollection` + It does not scrolls to selected element." + + self selection selectItems: aListOfItem +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPath: aPath [ + "Selects element in `aPath` + `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3)). + It does not scrolls to selected element." + + self selection selectPath: aPath +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPath: aPath scrollToSelection: shouldScrollToSelection [ + "Selects element in `aPath` + `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3)). + If `shouldScrollToSelection` is true, it will scroll to selected element. + IMPORTANT: Scrolling to selection just has sense when the widget is already shown, because before it + is displayed it does not has real bounds. In morphic (and gtk) it has a minimal extent assigned, + but that will change as soon as the widget is inserted in a container and the container applies its + layout." + + contentView + selectPath: aPath + scrollToSelection: shouldScrollToSelection +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPathByItems: pathArray [ + + self selectPathByItems: pathArray scrollToSelection: false +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPathByItems: pathArray scrollToSelection: aBoolean [ + "IMPORTANT: Scrolling to selection just has sense when the widget is already shown, because before it + is displayed it does not has real bounds. In morphic (and gtk) it has a minimal extent assigned, + but that will change as soon as the widget is inserted in a container and the container applies its + layout." + | pathIndexes | + + pathIndexes := self pathIndexOf: pathArray. + pathIndexes size > 1 ifTrue: [ + self expandPath: pathIndexes allButLast ]. + self + selectPath: pathIndexes + scrollToSelection: aBoolean +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectPaths: pathArray [ + "Selects all elements in `pathsArray`` + `pathsArray` is an array of paths. A path is an array of node indexes (e.g. #(1 2 3))" + + self selection selectPaths: pathArray +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectedItem [ + "Return selected item." + + ^ self selection selectedItem +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selectedItems [ + "Return all the selected items in the case of a multiple selection list" + + ^ self selection selectedItems +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> selection [ + "Answer the selection object (an instance of `SpSingleSelectionMode` or `SpMultipleSelectionMode`). + This is not the item selected, but the selection container (it may contain one or many selected + items)" + + ^ contentView selection +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> selectionMode [ + "Answer the selection object (an instance of `SpSingleSelectionMode` or `SpMultipleSelectionMode`). + This is not the item selected, but the selection container (it may contain one or many selected + items). + This is the same as `SpAbstractListPresenter>>#selection`" + + ^ contentView selectionMode +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> unselectAll [ + "Remove all selections" + + self selection unselectAll +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> unselectItem: anItem [ + "Remove selection of element `anItem`" + + self selection unselectItem: anItem +] + +{ #category : 'api - selection' } +SpAbstractEasyTreeListViewPresenter >> unselectPath: aPath [ + "Unselects element in `aPath` + `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3))" + + self selection unselectPath: aPath +] + +{ #category : 'api' } +SpAbstractEasyTreeListViewPresenter >> updateRootsKeepingSelection: aCollection [ + "Update tree roots keeping current selection. + WARNING: aCollection must includes the elements selected." + + contentView updateRootsKeepingSelection: aCollection +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenMultiSelectionChangedDo: aBlock [ + "Inform when selection mode has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenMultiSelectionChangedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenRootsChangedDo: aBlock [ + "Inform when roots have changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenRootsChangedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenSelectedIndexChangedDo: aBlock [ + "Inform when selected index has changed. + `aBlock` receives one optional argument (the new element)." + + contentView whenSelectedIndexChangedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenSelectedItemChangedDo: aBlock [ + "Inform when selected index has changed. + `aBlock` receives one optional argument (the new element)." + + contentView whenSelectedItemChangedDo: aBlock + +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenSelectionChangedDo: aBlock [ + "Inform when selection has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenSelectionChangedDo: aBlock +] + +{ #category : 'api - events' } +SpAbstractEasyTreeListViewPresenter >> whenShowColumnHeadersChangedDo: aBlock [ + "Inform when showColumnHeaders property has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenShowColumnHeadersChangedDo: aBlock +] diff --git a/src/Spec2-ListView/SpApplicationBackend.extension.st b/src/Spec2-ListView/SpApplicationBackend.extension.st new file mode 100644 index 00000000..45552f6b --- /dev/null +++ b/src/Spec2-ListView/SpApplicationBackend.extension.st @@ -0,0 +1,33 @@ +Extension { #name : 'SpApplicationBackend' } + +{ #category : '*Spec2-ListView' } +SpApplicationBackend >> dropListClass [ + + self subclassResponsibility +] + +{ #category : '*Spec2-ListView' } +SpApplicationBackend >> listClass [ + + self subclassResponsibility + +] + +{ #category : '*Spec2-ListView' } +SpApplicationBackend >> tableClass [ + + self subclassResponsibility +] + +{ #category : '*Spec2-ListView' } +SpApplicationBackend >> treeClass [ + + self subclassResponsibility + +] + +{ #category : '*Spec2-ListView' } +SpApplicationBackend >> treeTableClass [ + + self subclassResponsibility +] diff --git a/src/Spec2-ListView/SpColumnViewColumn.class.st b/src/Spec2-ListView/SpColumnViewColumn.class.st new file mode 100644 index 00000000..6ab42d6e --- /dev/null +++ b/src/Spec2-ListView/SpColumnViewColumn.class.st @@ -0,0 +1,110 @@ +Class { + #name : 'SpColumnViewColumn', + #superclass : 'Object', + #instVars : [ + 'title', + 'bind', + 'setup', + 'expand', + 'width' + ], + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'instance creation' } +SpColumnViewColumn class >> newTitle: aTitle setup: setupBlock bind: bindBlock [ + + ^ self new + title: aTitle; + setup: setupBlock; + bind: bindBlock; + yourself +] + +{ #category : 'accessing' } +SpColumnViewColumn >> beExpandable [ + + self expand: true +] + +{ #category : 'accessing' } +SpColumnViewColumn >> beNotExpandable [ + + self expand: false +] + +{ #category : 'api' } +SpColumnViewColumn >> bind: aBlock [ + + bind := aBlock +] + +{ #category : 'accessing' } +SpColumnViewColumn >> bindAction [ + + ^ bind +] + +{ #category : 'accessing' } +SpColumnViewColumn >> expand: aBoolean [ + + expand := aBoolean +] + +{ #category : 'testing' } +SpColumnViewColumn >> hasFixedWidth [ + + ^ width notNil +] + +{ #category : 'initialization' } +SpColumnViewColumn >> initialize [ + + super initialize. + self beExpandable. + self setup: [ :aPresenter | aPresenter newLabel ]. + self bind: [ :aPresenter :anObject | aPresenter label: anObject asString ] +] + +{ #category : 'testing' } +SpColumnViewColumn >> isExpand [ + + ^ expand +] + +{ #category : 'api' } +SpColumnViewColumn >> setup: aBlock [ + + setup := aBlock +] + +{ #category : 'accessing' } +SpColumnViewColumn >> setupAction [ + + ^ setup +] + +{ #category : 'api' } +SpColumnViewColumn >> title [ + + ^ title +] + +{ #category : 'api' } +SpColumnViewColumn >> title: aString [ + + title := aString +] + +{ #category : 'accessing' } +SpColumnViewColumn >> width [ + + ^ width +] + +{ #category : 'accessing' } +SpColumnViewColumn >> width: aNumber [ + + width := aNumber +] diff --git a/src/Spec2-ListView/SpColumnViewPresenter.class.st b/src/Spec2-ListView/SpColumnViewPresenter.class.st new file mode 100644 index 00000000..710f1c5a --- /dev/null +++ b/src/Spec2-ListView/SpColumnViewPresenter.class.st @@ -0,0 +1,165 @@ +Class { + #name : 'SpColumnViewPresenter', + #superclass : 'SpAbstractListPresenter', + #instVars : [ + '#columns => ObservableSlot', + '#isResizable => ObservableSlot' + ], + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'specs' } +SpColumnViewPresenter class >> adapterName [ + + ^ #ColumnViewAdapter +] + +{ #category : 'examples' } +SpColumnViewPresenter class >> example [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + addColumnTitle: 'Class' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + items: Smalltalk allClasses; + open +] + +{ #category : 'examples' } +SpColumnViewPresenter class >> exampleActivateOnDoubleClick [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + isActiveOnDoubleClick; + addColumnTitle: 'Class' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + items: Smalltalk allClasses; + whenActivatedDo: [ :selection | selection selectedItem crTrace ]; + open +] + +{ #category : 'examples' } +SpColumnViewPresenter class >> exampleResizableColumns [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + beResizable; + items: Smalltalk allClasses; + addColumnTitle: 'Class' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + addColumnTitle: 'Lines of code' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass linesOfCode asString ]; + open +] + +{ #category : 'examples' } +SpColumnViewPresenter class >> exampleWithIcons [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + addColumnTitle: 'Class' + setup: [ :aPresenter | + | presenter | + (presenter := aPresenter newPresenter) + layout: (SpBoxLayout newHorizontal + spacing: 5; + add: presenter newImage expand: false; + add: presenter newLabel; + yourself); + yourself ] + bind: [ :aPresenter :aClass | | icon image label | + icon := Smalltalk ui icons iconNamed: aClass systemIconName. + image := aPresenter layout children first. + image image: icon. + label := aPresenter layout children second. + label label: aClass name ]; + items: Smalltalk allClasses; + open +] + +{ #category : 'api' } +SpColumnViewPresenter >> addColumn: aColumn [ + "Add a column to the table. A column should be an instance of `SpTableColumn`" + + columns := columns copyWith: aColumn +] + +{ #category : 'api' } +SpColumnViewPresenter >> addColumnTitle: aTitle setup: setupBlock bind: bindBlock [ + + ^ self addColumn: (SpColumnViewColumn + newTitle: aTitle + setup: setupBlock + bind: bindBlock) +] + +{ #category : 'api' } +SpColumnViewPresenter >> addColumns: aCollection [ + "Add a list of columns. + `aCollection` is a list of instances of `SpTableColumn`" + + aCollection do: [ :each | self addColumn: each ] +] + +{ #category : 'api' } +SpColumnViewPresenter >> beNotResizable [ + + self isResizable: false +] + +{ #category : 'api' } +SpColumnViewPresenter >> beResizable [ + + self isResizable: true +] + +{ #category : 'accessing' } +SpColumnViewPresenter >> columns [ + ^ columns +] + +{ #category : 'initialization' } +SpColumnViewPresenter >> initialize [ + + super initialize. + columns := #() +] + +{ #category : 'testing' } +SpColumnViewPresenter >> isResizable [ + + ^ isResizable +] + +{ #category : 'private' } +SpColumnViewPresenter >> isResizable: aBoolean [ + + isResizable := aBoolean +] + +{ #category : 'api - events' } +SpColumnViewPresenter >> whenColumnsChangedDo: aBlock [ + "Inform when columns have changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + self property: #columns whenChangedDo: aBlock +] + +{ #category : 'api - events' } +SpColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ + "Inform when resizable property has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + self property: #isResizable whenChangedDo: aBlock +] diff --git a/src/Spec2-ListView/SpDropDownPresenter.class.st b/src/Spec2-ListView/SpDropDownPresenter.class.st index 5f2446b6..9e783890 100644 --- a/src/Spec2-ListView/SpDropDownPresenter.class.st +++ b/src/Spec2-ListView/SpDropDownPresenter.class.st @@ -186,6 +186,12 @@ SpDropDownPresenter >> outputSelectionPort [ ^ SpDropDownSelectionPort newPresenter: self ] +{ #category : 'api - selection' } +SpDropDownPresenter >> resetSelection [ + + self selection unselectAll +] + { #category : 'api - selection' } SpDropDownPresenter >> selectFirst [ "Select first element in list. @@ -245,6 +251,12 @@ SpDropDownPresenter >> setupAction [ ^ setupAction ] +{ #category : 'api' } +SpDropDownPresenter >> sortingBlock: aBlock [ + + self flag: #TODO. +] + { #category : 'api - events' } SpDropDownPresenter >> whenSelectedDo: aBlock [ "Inform when an item was selected (a real object in the items list). diff --git a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st new file mode 100644 index 00000000..98468476 --- /dev/null +++ b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st @@ -0,0 +1,89 @@ +Class { + #name : 'SpEasyColumnViewPresenter', + #superclass : 'SpAbstractEasyListViewPresenter', + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'examples' } +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); + 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 ]; + yourself); + open +] + +{ #category : 'examples' } +SpEasyColumnViewPresenter class >> exampleActivateOnDoubleClick [ + "This example show the simples list view you can make: A list with a label" + + self new + application: (SpApplication new useBackend: #Gtk); + 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 ]; + yourself); + activateOnDoubleClick; + whenActivatedDo: [ :selection| selection selectedItem crTrace ]; + open +] + +{ #category : 'api' } +SpEasyColumnViewPresenter >> addColumn: aColumn [ + + contentView addColumn: aColumn asColumnViewColumn +] + +{ #category : 'drawing' } +SpEasyColumnViewPresenter >> alternateRowsColor [ + + self flag: #TODO +] + +{ #category : 'api' } +SpEasyColumnViewPresenter >> beNotResizable [ + + contentView beNotResizable +] + +{ #category : 'api' } +SpEasyColumnViewPresenter >> beResizable [ + + contentView beResizable +] + +{ #category : 'api' } +SpEasyColumnViewPresenter >> hideColumnHeaders [ + + self flag: #TODO +] + +{ #category : 'initialization' } +SpEasyColumnViewPresenter >> initializePresenters [ + + super initializePresenters. + contentView := self newColumnView. + +] + +{ #category : 'api - events' } +SpEasyColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ + + contentView whenIsResizableChangedDo: aBlock + +] diff --git a/src/Spec2-ListView/SpEasyListViewPresenter.class.st b/src/Spec2-ListView/SpEasyListViewPresenter.class.st index 426559dc..382a0901 100644 --- a/src/Spec2-ListView/SpEasyListViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyListViewPresenter.class.st @@ -1,15 +1,10 @@ Class { #name : 'SpEasyListViewPresenter', - #superclass : 'SpPresenter', - #traits : 'SpTSearchable', - #classTraits : 'SpTSearchable classTrait', + #superclass : 'SpAbstractEasyListViewPresenter', #instVars : [ '#display => ObservableSlot', '#displayIcon => ObservableSlot', - '#searchInput', - '#listView', - '#headerPanel', - '#lastSelectedRow => WeakSlot' + '#headerPanel' ], #category : 'Spec2-ListView', #package : 'Spec2-ListView' @@ -26,7 +21,7 @@ SpEasyListViewPresenter class >> example [ "This example show a simple list with all classes, using all the default settings." ^ self new - "application: (SpApplication new useBackend: #Gtk);" + application: (SpApplication new useBackend: #Gtk); items: self environment allClasses; open; yourself @@ -66,99 +61,10 @@ SpEasyListViewPresenter class >> exampleWithIcons [ yourself ] -{ #category : 'api - actions' } -SpEasyListViewPresenter >> actionGroup [ - - ^ listView actionGroup -] - -{ #category : 'api - actions' } -SpEasyListViewPresenter >> actionGroup: aSpCommandGroup [ - - listView actionGroup: aSpCommandGroup -] - -{ #category : 'api' } -SpEasyListViewPresenter >> activateOnDoubleClick [ - - listView activateOnDoubleClick -] - -{ #category : 'api' } -SpEasyListViewPresenter >> activateOnSingleClick [ - - listView activateOnSingleClick -] - -{ #category : 'private' } -SpEasyListViewPresenter >> activateSearchWith: aString [ - - lastSelectedRow := listView selectedItem. - - searchInput text: aString. - searchInput show. - searchInput takeKeyboardFocus. - searchInput unselectAll. - searchInput cursorPositionIndex: aString size -] - -{ #category : 'api - actions' } -SpEasyListViewPresenter >> addAction: aSpCommand [ - - listView addAction: aSpCommand -] - -{ #category : 'api' } -SpEasyListViewPresenter >> addScrollBarStyle: aStyle [ - - listView addScrollBarStyle: aStyle -] - -{ #category : 'api' } -SpEasyListViewPresenter >> beMultipleSelection [ - - listView beMultipleSelection -] - -{ #category : 'api' } -SpEasyListViewPresenter >> beSingleSelection [ - - listView beSingleSelection -] - { #category : 'initialization' } SpEasyListViewPresenter >> connectPresenters [ - searchInput - addAction: (SpAction - newShortcut: Character escape asKeyCombination - action: [ self deactivateSearch: false ]); - addAction: (SpAction - newShortcut: Character cr asKeyCombination - action: [ self deactivateSearch: true ]); - whenTextChangedDo: [ :aString | self selectFirst: aString ]. - - listView eventHandler - whenKeyDownDo: [ :event | self maybeActivateSearchOn: event ]; - whenFocusReceivedDo: [ :event | searchInput hide ] -] - -{ #category : 'private' } -SpEasyListViewPresenter >> deactivateSearch: acceptSelection [ - | currentSelection | - - currentSelection := listView selectedItem. - searchInput hide. - listView selectItem: (acceptSelection - ifTrue: [ currentSelection ] - ifFalse: [ lastSelectedRow ]). - listView takeKeyboardFocus -] - -{ #category : 'transmission' } -SpEasyListViewPresenter >> defaultInputPort [ - - ^ self inputItemsPort + super connectPresenters ] { #category : 'layout' } @@ -167,24 +73,12 @@ SpEasyListViewPresenter >> defaultLayout [ ^ SpOverlayLayout new child: (SpBoxLayout newVertical add: headerPanel expand: false; - add: listView; + add: contentView; yourself); addOverlay: searchInput withConstraints: [ :c | c vAlignStart; hAlignEnd ]; yourself ] -{ #category : 'transmission' } -SpEasyListViewPresenter >> defaultOutputPort [ - - ^ self outputSelectionPort -] - -{ #category : 'api' } -SpEasyListViewPresenter >> disable [ - - self enabled: false -] - { #category : 'api' } SpEasyListViewPresenter >> display [ "Answer the display block that will transform the objects from `SpAbstractListPresenter>>#model` into a @@ -231,28 +125,6 @@ SpEasyListViewPresenter >> displayValueFor: anObject [ ^ self display value: anObject ] -{ #category : 'api' } -SpEasyListViewPresenter >> enable [ - - self enabled: true -] - -{ #category : 'private' } -SpEasyListViewPresenter >> findFirst: aString [ - | items | - - items := listView items. - items isEmptyOrNil ifTrue: [ ^ 0 ]. - - (listView selection selectedIndex max: 1) to: items size do: [ :index | - (self - performSearch: (items at: index) - matching: aString) - ifTrue: [ ^ index ] ]. - - ^ 0 -] - { #category : 'testing' } SpEasyListViewPresenter >> hasHeaderTitle [ "Answer true if the list has a title (See `SpListPresenter>>#headerTitle:`)." @@ -302,15 +174,16 @@ SpEasyListViewPresenter >> iconFor: anItem [ SpEasyListViewPresenter >> initialize [ super initialize. - self initializeTSearchable. display := [ :object | object asString ] ] { #category : 'initialization' } SpEasyListViewPresenter >> initializePresenters [ + super initializePresenters. + headerPanel := self newLabel. - listView := self newListView + contentView := self newListView setup: [ :aPresenter | (aPresenter instantiate: SpEasyListRowPresenter) listView: self; @@ -318,116 +191,21 @@ SpEasyListViewPresenter >> initializePresenters [ bind: [ :aPresenter :anObject | aPresenter model: anObject ]; yourself. - searchInput := self newTextInput. - - headerPanel hide. - searchInput hide -] - -{ #category : 'transmission' } -SpEasyListViewPresenter >> inputItemsPort [ - - ^ (SpListItemsPort newPresenter: self) - delegateTo: [ listView ]; - yourself -] - -{ #category : 'api' } -SpEasyListViewPresenter >> items [ - - ^ listView items -] - -{ #category : 'api' } -SpEasyListViewPresenter >> items: anOrderedCollection [ - - listView items: anOrderedCollection -] - -{ #category : 'private' } -SpEasyListViewPresenter >> maybeActivateSearchOn: event [ - self isSearchEnabled ifFalse: [ ^ self ]. - "any modifier other than shift?" - (event anyModifierKeyPressed - or: [ (event keyValue between: 32 and: 127) not ]) - ifTrue: [ ^ self ]. - self activateSearchWith: event keyCharacter asString -] - -{ #category : 'api' } -SpEasyListViewPresenter >> model [ - - ^ listView model -] - -{ #category : 'transmission' } -SpEasyListViewPresenter >> outputActivationPort [ - - ^ (SpActivationPort newPresenter: self) - delegateTo: [ listView ]; - yourself -] - -{ #category : 'transmission' } -SpEasyListViewPresenter >> outputSelectionPort [ - - ^ (SpSelectionPort newPresenter: self) - delegateTo: [ listView ]; - yourself + headerPanel hide ] { #category : 'initialization' } SpEasyListViewPresenter >> registerEvents [ super registerEvents. - - self whenDisplayChangedDo: [ listView refresh ] -] - -{ #category : 'api' } -SpEasyListViewPresenter >> removeScrollBarStyle: aStyle [ - - ^ listView removeScrollBarStyle: aStyle -] - -{ #category : 'api' } -SpEasyListViewPresenter >> scrollBarStyles [ - - ^ listView scrollBarStyles -] - -{ #category : 'private' } -SpEasyListViewPresenter >> selectFirst: aString [ - | index | - - index := self findFirst: aString. - index = 0 ifTrue: [ ^ self ]. - - listView selectIndex: index scrollToSelection: true -] - -{ #category : 'api - selection' } -SpEasyListViewPresenter >> selectedItem [ - - ^ listView selectedItem + self whenDisplayChangedDo: [ contentView refresh ] ] { #category : 'api' } SpEasyListViewPresenter >> updateItemsKeepingSelection: aCollection [ - listView updateItemsKeepingSelection: aCollection -] - -{ #category : 'api - events' } -SpEasyListViewPresenter >> whenDisplayChangedDo: aBlock [ - "Inform when the display block has changed. - `aBlock` has three optional arguments: - - new value - - old value - - the announcement triggering this action" - - self property: #display whenChangedDo: aBlock + contentView updateItemsKeepingSelection: aCollection ] { #category : 'api - events' } @@ -440,15 +218,3 @@ SpEasyListViewPresenter >> whenIconsChangedDo: aBlock [ self property: #displayIcon whenChangedDo: aBlock ] - -{ #category : 'api' } -SpEasyListViewPresenter >> withScrollBars [ - - listView withScrollBars -] - -{ #category : 'api' } -SpEasyListViewPresenter >> withoutScrollBars [ - - listView withoutScrollBars -] diff --git a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st new file mode 100644 index 00000000..57ddb9d9 --- /dev/null +++ b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st @@ -0,0 +1,125 @@ +Class { + #name : 'SpEasyTreeColumnViewPresenter', + #superclass : 'SpAbstractEasyTreeListViewPresenter', + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'examples' } +SpEasyTreeColumnViewPresenter class >> example [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + addColumn: (SpCompositeTableColumn new + title: 'Classes'; + addColumn: (SpImageTableColumn new + evaluated: [ :aClass | self iconNamed: aClass systemIconName]; + width: 50); + addColumn: (SpStringTableColumn evaluated: #name); + yourself); + roots: { Object }; + children: [ :aClass | aClass subclasses ]; + open +] + +{ #category : 'api' } +SpEasyTreeColumnViewPresenter >> addColumn: aColumn [ + "Add a column to the table. A column should be an instance of `SpTableColumn`" + + contentView addColumn: aColumn asColumnViewColumn +] + +{ #category : 'api' } +SpEasyTreeColumnViewPresenter >> alternateRowsColor [ + " Will alternate Rows color for a better reading: one row lighter, the next row darker" + self flag: #TODO. +] + +{ #category : 'api' } +SpEasyTreeColumnViewPresenter >> beNotResizable [ + "Mark the table as 'not resizable', which means there will be not possibility to resize the + columns of it." + + contentView beNotResizable +] + +{ #category : 'api' } +SpEasyTreeColumnViewPresenter >> beResizable [ + "Mark the table as 'resizable', which means there will be a slider to resize the columns." + + contentView beResizable +] + +{ #category : 'api' } +SpEasyTreeColumnViewPresenter >> columns [ + "Answer the columns composing this table." + + ^ contentView columns +] + +{ #category : 'api' } +SpEasyTreeColumnViewPresenter >> columns: aCollection [ + "Set all columns at once. + `aCollection` is a list of instances of `SpTableColumn`" + + self flag: #TODO +] + +{ #category : 'api' } +SpEasyTreeColumnViewPresenter >> hideColumnHeaders [ + "Hide the column headers" + + self flag: #TODO +] + +{ #category : 'initialization' } +SpEasyTreeColumnViewPresenter >> initializePresenters [ + + super initializePresenters. + contentView := self newTreeColumnView +] + +{ #category : 'testing' } +SpEasyTreeColumnViewPresenter >> isResizable [ + "Answer true if table allows resizing of its columns." + + ^ contentView isResizable +] + +{ #category : 'testing' } +SpEasyTreeColumnViewPresenter >> isShowingColumnHeaders [ + "Answer true if the table is configured to show column headers." + + self flag: #TODO. + ^ true +] + +{ #category : 'api' } +SpEasyTreeColumnViewPresenter >> showColumnHeaders [ + "Show column headers" + + self flag: #TODO +] + +{ #category : 'api - events' } +SpEasyTreeColumnViewPresenter >> whenColumnsChangedDo: aBlock [ + "Inform when columns have changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + + contentView whenColumnsChangedDo: aBlock +] + +{ #category : 'api - events' } +SpEasyTreeColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ + "Inform when resizable property has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + contentView whenIsResizableChangedDo: aBlock +] diff --git a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st new file mode 100644 index 00000000..90845878 --- /dev/null +++ b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st @@ -0,0 +1,6 @@ +Class { + #name : 'SpEasyTreeListViewPresenter', + #superclass : 'SpAbstractEasyTreeListViewPresenter', + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} diff --git a/src/Spec2-ListView/SpImageTableColumn.extension.st b/src/Spec2-ListView/SpImageTableColumn.extension.st new file mode 100644 index 00000000..5175a9c0 --- /dev/null +++ b/src/Spec2-ListView/SpImageTableColumn.extension.st @@ -0,0 +1,13 @@ +Extension { #name : 'SpImageTableColumn' } + +{ #category : '*Spec2-ListView' } +SpImageTableColumn >> asColumnViewColumn [ + + ^ SpColumnViewColumn new + title: self title; + expand: (self width isNil and: [ self isExpandable ]); + width: self width; + setup: [ :aPresenter | aPresenter newImage ]; + bind: [ :aPresenter :item | aPresenter image: (self readObject: item) ]; + yourself +] diff --git a/src/Spec2-ListView/SpListViewPresenter.class.st b/src/Spec2-ListView/SpListViewPresenter.class.st index 77a2ed22..f9d8aaac 100644 --- a/src/Spec2-ListView/SpListViewPresenter.class.st +++ b/src/Spec2-ListView/SpListViewPresenter.class.st @@ -30,6 +30,20 @@ SpListViewPresenter class >> example [ ] { #category : 'examples' } +SpListViewPresenter class >> exampleActivateOnDoubleClick [ + "This example show the simples list view you can make: A list with a label" + + self new + application: (SpApplication new useBackend: #Gtk); + isActiveOnDoubleClick; + items: self environment allClasses; + setup: [ :aPresenter | aPresenter newLabel ]; + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + whenActivatedDo: [ 'OK' crTrace ]; + open +] + +{ #category : 'as yet unclassified' } SpListViewPresenter class >> exampleReplaceItems [ "This example shows how to replace dynamically the list of elements." | presenter listView button items | @@ -123,6 +137,38 @@ SpListViewPresenter class >> exampleWithIcons [ ] { #category : 'examples' } +SpListViewPresenter class >> exampleWithIconsAndMorph [ + "This example shows how to construct a list with icons. + It shows also the fact you can put any presenter inside, giving a huge power + to your lists." + + ^ self new + application: (SpApplication new useBackend: #Gtk); + items: self environment allClasses; + setup: [ :aPresenter | + | presenter | + (presenter := aPresenter newPresenter) + layout: (SpBoxLayout newHorizontal + spacing: 5; + add: presenter newImage expand: false; + add: presenter newLabel; + add: (presenter newMorph + morph: SimpleButtonMorph new; + yourself); + yourself); + yourself ]; + bind: [ :aPresenter :aClass | | icon image label morph | + icon := Smalltalk ui icons iconNamed: aClass systemIconName. + image := aPresenter layout children first. + image image: icon. + label := aPresenter layout children second. + label label: aClass name. + morph := aPresenter layout children third. + morph morph label: aClass name ]; + open +] + +{ #category : 'as yet unclassified' } SpListViewPresenter class >> exampleWithIconsAndSelectedItem [ "This example shows how to construct a list with icons. It shows also the fact you can put any presenter inside, giving a huge power @@ -150,7 +196,7 @@ SpListViewPresenter class >> exampleWithIconsAndSelectedItem [ open ] -{ #category : 'examples' } +{ #category : 'as yet unclassified' } SpListViewPresenter class >> exampleWithIconsMultipleSelection [ "This example shows how to construct a list with multiple selection available. It shows also the fact you can put any presenter inside, giving a huge power @@ -241,7 +287,6 @@ SpListViewPresenter >> registerActions [ SpListViewPresenter >> registerEvents [ super registerEvents. - self property: #headerTitle whenChangedDo: [ diff --git a/src/Spec2-ListView/SpMorphicBackend.extension.st b/src/Spec2-ListView/SpMorphicBackend.extension.st new file mode 100644 index 00000000..a171d8a0 --- /dev/null +++ b/src/Spec2-ListView/SpMorphicBackend.extension.st @@ -0,0 +1,31 @@ +Extension { #name : 'SpMorphicBackend' } + +{ #category : '*Spec2-ListView' } +SpMorphicBackend >> dropListClass [ + + ^ SpDropListPresenter +] + +{ #category : '*Spec2-ListView' } +SpMorphicBackend >> listClass [ + + ^ SpListPresenter +] + +{ #category : '*Spec2-ListView' } +SpMorphicBackend >> tableClass [ + + ^ SpTablePresenter +] + +{ #category : '*Spec2-ListView' } +SpMorphicBackend >> treeClass [ + + ^ SpTreePresenter +] + +{ #category : '*Spec2-ListView' } +SpMorphicBackend >> treeTableClass [ + + ^ SpTreeTablePresenter +] diff --git a/src/Spec2-ListView/SpTPresenterBuilder.extension.st b/src/Spec2-ListView/SpTPresenterBuilder.extension.st index fc1242dc..39b3c10e 100644 --- a/src/Spec2-ListView/SpTPresenterBuilder.extension.st +++ b/src/Spec2-ListView/SpTPresenterBuilder.extension.st @@ -1,19 +1,55 @@ Extension { #name : 'SpTPresenterBuilder' } +{ #category : '*Spec2-ListView' } +SpTPresenterBuilder >> newColumnView [ + + ^ self instantiate: SpColumnViewPresenter +] + { #category : '*Spec2-ListView' } SpTPresenterBuilder >> newDropDown [ ^ self instantiate: SpDropDownPresenter ] +{ #category : '*Spec2-ListView' } +SpTPresenterBuilder >> newEasyColumnView [ + + ^ self instantiate: SpEasyColumnViewPresenter +] + { #category : '*Spec2-ListView' } SpTPresenterBuilder >> newEasyListView [ ^ self instantiate: SpEasyListViewPresenter ] +{ #category : '*Spec2-ListView' } +SpTPresenterBuilder >> newEasyTreeColumnView [ + + ^ self instantiate: SpEasyTreeColumnViewPresenter +] + +{ #category : '*Spec2-ListView' } +SpTPresenterBuilder >> newEasyTreeListView [ + + ^ self instantiate: SpEasyTreeListViewPresenter +] + { #category : '*Spec2-ListView' } SpTPresenterBuilder >> newListView [ ^ self instantiate: SpListViewPresenter ] + +{ #category : '*Spec2-ListView' } +SpTPresenterBuilder >> newTreeColumnView [ + + ^ self instantiate: SpTreeColumnViewPresenter +] + +{ #category : '*Spec2-ListView' } +SpTPresenterBuilder >> newTreeListView [ + + ^ self instantiate: SpTreeListViewPresenter +] diff --git a/src/Spec2-ListView/SpTableColumn.extension.st b/src/Spec2-ListView/SpTableColumn.extension.st new file mode 100644 index 00000000..859410ed --- /dev/null +++ b/src/Spec2-ListView/SpTableColumn.extension.st @@ -0,0 +1,13 @@ +Extension { #name : 'SpTableColumn' } + +{ #category : '*Spec2-ListView' } +SpTableColumn >> asColumnViewColumn [ + + ^ SpColumnViewColumn new + title: self title; + expand: (self width isNil and: [ self isExpandable ]); + width: self width; + setup: [ :aPresenter | aPresenter newLabel ]; + bind: [ :aPresenter :item | aPresenter label: (self readObject: item) asString ]; + yourself +] diff --git a/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st new file mode 100644 index 00000000..be4635e0 --- /dev/null +++ b/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st @@ -0,0 +1,229 @@ +Class { + #name : 'SpTreeColumnViewPresenter', + #superclass : 'SpAbstractTreePresenter', + #instVars : [ + '#columns => ObservableSlot', + '#isResizable => ObservableSlot' + ], + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'specs' } +SpTreeColumnViewPresenter class >> adapterName [ + + ^ #TreeColumnViewAdapter +] + +{ #category : 'examples' } +SpTreeColumnViewPresenter class >> example [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + addColumnTitle: 'Class' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + addColumnTitle: 'Lines of code' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass linesOfCode asString ]; + items: { Object }; + children: [ :aClass | aClass subclasses ]; + open +] + +{ #category : 'examples' } +SpTreeColumnViewPresenter class >> exampleActivateOnDoubleClick [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + activateOnDoubleClick; + addColumnTitle: 'Class' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + addColumnTitle: 'Lines of code' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass linesOfCode asString ]; + items: { Object }; + children: [ :aClass | aClass subclasses ]; + whenActivatedDo: [ :selection | selection selectedItem crTrace ]; + open +] + +{ #category : 'examples' } +SpTreeColumnViewPresenter class >> exampleRefreshList [ + "this example just shows how the tree is refreshed when changing the model" + | presenter button tree | + + presenter := SpPresenter new. + presenter application: (SpApplication new useBackend: #Gtk). + + presenter layout: (SpBoxLayout newHorizontal + add: (button := presenter newButton); + add: (tree := presenter newTreeColumnView); + yourself). + + tree + roots: #(); + children: [ :aClass | aClass subclasses ]. + + tree + addColumnTitle: 'Class' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + addColumnTitle: 'Lines of code' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass linesOfCode asString ]. + + button + label: 'Click'; + action: [ + | allClasses roots | + allClasses := Smalltalk allClasses. + roots := (1 to: 10) collect: [ :index | allClasses atRandom ]. + tree roots: roots ]. + + presenter open +] + +{ #category : 'examples' } +SpTreeColumnViewPresenter class >> exampleResizableColumns [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + beResizable; + items: { Object }; + children: [ :aClass | aClass subclasses ]; + addColumnTitle: 'Class' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + addColumnTitle: 'Lines of code' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass linesOfCode asString ]; + open +] + +{ #category : 'examples' } +SpTreeColumnViewPresenter class >> exampleWithIcons [ + + ^ self new + application: (SpApplication new useBackend: #Gtk); + addColumnTitle: 'Class' + setup: [ :aPresenter | + | presenter | + (presenter := aPresenter newPresenter) + layout: (SpBoxLayout newHorizontal + spacing: 5; + add: presenter newImage expand: false; + add: presenter newLabel; + yourself); + yourself ] + bind: [ :aPresenter :aClass | | icon image label | + icon := Smalltalk ui icons iconNamed: aClass systemIconName. + image := aPresenter layout children first. + image image: icon. + label := aPresenter layout children second. + label label: aClass name ]; + addColumnTitle: 'Lines of code' + setup: [ :aPresenter | aPresenter newLabel ] + bind: [ :aPresenter :aClass | aPresenter label: aClass linesOfCode asString ]; + items: { Object }; + children: [ :aClass | aClass subclasses ]; + open +] + +{ #category : 'api' } +SpTreeColumnViewPresenter >> addColumn: aColumn [ + "Add a column to the table. A column should be an instance of `SpTableColumn`" + + columns := columns copyWith: aColumn +] + +{ #category : 'api' } +SpTreeColumnViewPresenter >> addColumnTitle: aTitle setup: setupBlock bind: bindBlock [ + + ^ self addColumn: (SpColumnViewColumn + newTitle: aTitle + setup: setupBlock + bind: bindBlock) +] + +{ #category : 'api' } +SpTreeColumnViewPresenter >> addColumns: aCollection [ + "Add a list of columns. + `aCollection` is a list of instances of `SpTableColumn`" + + aCollection do: [ :each | self addColumn: each ] +] + +{ #category : 'api' } +SpTreeColumnViewPresenter >> beNotResizable [ + + self isResizable: false +] + +{ #category : 'api' } +SpTreeColumnViewPresenter >> beResizable [ + + self isResizable: true +] + +{ #category : 'accessing' } +SpTreeColumnViewPresenter >> columns [ + ^ columns +] + +{ #category : 'initialization' } +SpTreeColumnViewPresenter >> initialize [ + + super initialize. + columns := #(). + + self beSingleSelection. + self activateOnDoubleClick. + self beResizable. + + self registerActions +] + +{ #category : 'testing' } +SpTreeColumnViewPresenter >> isResizable [ + + ^ isResizable +] + +{ #category : 'private' } +SpTreeColumnViewPresenter >> isResizable: aBoolean [ + + isResizable := aBoolean +] + +{ #category : 'initialization' } +SpTreeColumnViewPresenter >> registerActions [ + + self addActionWith: [ :action | action + beShortcutOnly; + shortcut: $t ctrl unix | $t ctrl win | $t command mac; + action: [ self showContextMenu ] ] +] + +{ #category : 'api - events' } +SpTreeColumnViewPresenter >> whenColumnsChangedDo: aBlock [ + "Inform when columns have changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + self property: #columns whenChangedDo: aBlock +] + +{ #category : 'api - events' } +SpTreeColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ + "Inform when resizable property has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + self property: #isResizable whenChangedDo: aBlock +] diff --git a/src/Spec2-ListView/SpTreeListViewPresenter.class.st b/src/Spec2-ListView/SpTreeListViewPresenter.class.st new file mode 100644 index 00000000..9597cb3f --- /dev/null +++ b/src/Spec2-ListView/SpTreeListViewPresenter.class.st @@ -0,0 +1,271 @@ +Class { + #name : 'SpTreeListViewPresenter', + #superclass : 'SpAbstractTreePresenter', + #classTraits : 'SpTActionContainer classTrait', + #instVars : [ + '#setupAction', + '#bindAction', + '#headerTitle => ObservableSlot' + ], + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'specs' } +SpTreeListViewPresenter class >> adapterName [ + + ^ #TreeListViewAdapter +] + +{ #category : 'examples' } +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); + items: { Object }; + children: [ :aClass | aClass subclasses ]; + setup: [ :aPresenter | aPresenter newLabel ]; + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + open +] + +{ #category : 'examples' } +SpTreeListViewPresenter class >> exampleActivateOnDoubleClick [ + "This example show the simples list view you can make: A list with a label" + | presenter | + + (presenter := self new) + application: (SpApplication new useBackend: #Gtk); + activateOnDoubleClick; + items: { Object }; + children: [ :aClass | aClass subclasses ]; + setup: [ :aPresenter | aPresenter newLabel ]; + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + whenActivatedDo: [ presenter selectedItem crTrace ]; + open +] + +{ #category : 'examples' } +SpTreeListViewPresenter class >> exampleRefreshList [ + "this example just shows how the tree is refreshed when changing the model" + | presenter button tree | + + presenter := SpPresenter new. + presenter application: (SpApplication new useBackend: #Gtk). + + presenter layout: (SpBoxLayout newHorizontal + add: (button := presenter newButton); + add: (tree := presenter newTreeListView); + yourself). + + tree + roots: #(); + children: [ :aClass | aClass subclasses ]. + + button + label: 'Click'; + action: [ + | allClasses roots | + allClasses := Smalltalk allClasses. + roots := (1 to: 10) collect: [ :index | allClasses atRandom ]. + tree roots: roots ]. + + presenter open +] + +{ #category : 'examples' } +SpTreeListViewPresenter class >> exampleWithActions [ + "This example show the simples list view you can make: A list with a label" + + self new + application: (SpApplication new useBackend: #Gtk); + items: { Object }; + children: [ :aClass | aClass subclasses ]; + setup: [ :aPresenter | aPresenter newLabel ]; + bind: [ :aPresenter :aClass | aPresenter label: aClass name ]; + actionsWith: [ :rootGroup | rootGroup + addGroupWith: [ :aGroup | aGroup + name: 'Group 1'; + beDisplayedAsGroup; + addActionWith: [ :act | act + name: 'Test 1'; + shortcut: $a ctrl; + action: [ 'Test 1.1' crTrace ] ]; + addActionWith: [ :act | act + name: 'Test 2'; + action: [ 'Test 1.2' crTrace ] ] ]; + addGroupWith: [ :subGroup1 | subGroup1 + name: 'Group 2'; + addActionWith: [ :act | act + name: 'Test 1'; + shortcut: $y ctrl; + action: [ 'Test 2.1' crTrace ]; + actionEnabled: [ false ] ]; + addActionWith: [ :act | act + name: 'Test 2'; + action: [ 'Test 2.2' crTrace ] ] ]; + addActionWith: [ :act | act + name: 'Test 3'; + shortcut: $a ctrl; + action: [ 'Test 3' crTrace ] ]; + addActionWith: [ :act | act + name: 'Test 4'; + shortcut: Character escape asKeyCombination; + action: [ 'Test 4' crTrace ] ] ]; + open +] + +{ #category : 'examples' } +SpTreeListViewPresenter class >> exampleWithIcons [ + "This example shows how to construct a list with icons. + It shows also the fact you can put any presenter inside, giving a huge power + to your lists." + + ^ self new + application: (SpApplication new useBackend: #Gtk); + items: { Object }; + children: [ :aClass | aClass subclasses ]; + setup: [ :aPresenter | + | presenter | + (presenter := aPresenter newPresenter) + layout: (SpBoxLayout newHorizontal + spacing: 5; + add: presenter newImage expand: false; + add: presenter newLabel; + yourself); + yourself ]; + bind: [ :aPresenter :aClass | | icon image label | + icon := Smalltalk ui icons iconNamed: aClass systemIconName. + image := aPresenter layout children first. + image image: icon. + label := aPresenter layout children second. + label label: aClass name ]; + open +] + +{ #category : 'examples' } +SpTreeListViewPresenter class >> exampleWithIconsAndMorph [ + "This example shows how to construct a list with icons. + It shows also the fact you can put any presenter inside, giving a huge power + to your lists." + + ^ self new + application: (SpApplication new useBackend: #Gtk); + items: { Object }; + children: [ :aClass | aClass subclasses ]; + setup: [ :aPresenter | + | presenter | + (presenter := aPresenter newPresenter) + layout: (SpBoxLayout newHorizontal + spacing: 5; + add: presenter newImage expand: false; + add: presenter newLabel; + add: (presenter newMorph + morph: SimpleButtonMorph new; + yourself); + yourself); + yourself ]; + bind: [ :aPresenter :aClass | | icon image label morph | + icon := Smalltalk ui icons iconNamed: aClass systemIconName. + image := aPresenter layout children first. + image image: icon. + label := aPresenter layout children second. + label label: aClass name. + morph := aPresenter layout children third. + morph morph label: aClass name ]; + open +] + +{ #category : 'api' } +SpTreeListViewPresenter >> bind: aBlock [ + + bindAction := aBlock +] + +{ #category : 'private' } +SpTreeListViewPresenter >> bindAction [ + + ^ bindAction +] + +{ #category : 'testing' } +SpTreeListViewPresenter >> hasHeaderTitle [ + "Answer true if the list has a title (See `SpListPresenter>>#headerTitle:`)." + + ^ headerTitle isEmptyOrNil not +] + +{ #category : 'api' } +SpTreeListViewPresenter >> headerTitle [ + "Answer the header title." + + ^ headerTitle +] + +{ #category : 'api' } +SpTreeListViewPresenter >> headerTitle: aString [ + "Set the header title." + + headerTitle := aString +] + +{ #category : 'initialization' } +SpTreeListViewPresenter >> initialize [ + + super initialize. + + childrenBlock := [ :item | #() ]. + + self beSingleSelection. + self activateOnDoubleClick. + + self registerActions. + self initializeItemFactory +] + +{ #category : 'initialization' } +SpTreeListViewPresenter >> initializeItemFactory [ + "Just set up the defaults (to ensure we have a working list at any moment)" + + self setup: [ :aPresenter | aPresenter newLabel ]. + self bind: [ :aPresenter :anObject | aPresenter label: anObject asString ] +] + +{ #category : 'initialization' } +SpTreeListViewPresenter >> registerActions [ + + self addActionWith: [ :action | action + beShortcutOnly; + shortcut: $t ctrl unix | $t ctrl win | $t command mac; + action: [ self showContextMenu ] ] +] + +{ #category : 'initialization' } +SpTreeListViewPresenter >> registerEvents [ + + super registerEvents. + self + property: #headerTitle + whenChangedDo: [ + self withAdapterDo: [ :anAdapter | anAdapter refreshList ] ] +] + +{ #category : 'api' } +SpTreeListViewPresenter >> setup: aBlock [ + + setupAction := aBlock +] + +{ #category : 'private' } +SpTreeListViewPresenter >> setupAction [ + + ^ setupAction +] + +{ #category : 'api' } +SpTreeListViewPresenter >> showContextMenu [ + "If the presenter is displayed, shows the associated context menu" + + self withAdapterDo: [ :anAdapter | anAdapter showContextMenu ] +] diff --git a/src/Spec2-ListView/SpecGtkBackend.extension.st b/src/Spec2-ListView/SpecGtkBackend.extension.st new file mode 100644 index 00000000..b4c8b941 --- /dev/null +++ b/src/Spec2-ListView/SpecGtkBackend.extension.st @@ -0,0 +1,31 @@ +Extension { #name : 'SpecGtkBackend' } + +{ #category : '*Spec2-ListView' } +SpecGtkBackend >> dropListClass [ + + ^ SpDropDownPresenter +] + +{ #category : '*Spec2-ListView' } +SpecGtkBackend >> listClass [ + + ^ SpEasyListViewPresenter +] + +{ #category : '*Spec2-ListView' } +SpecGtkBackend >> tableClass [ + + ^ SpEasyColumnViewPresenter +] + +{ #category : '*Spec2-ListView' } +SpecGtkBackend >> treeClass [ + + ^ SpEasyTreeListViewPresenter +] + +{ #category : '*Spec2-ListView' } +SpecGtkBackend >> treeTableClass [ + + ^ SpEasyTreeColumnViewPresenter +] diff --git a/src/Spec2-Transmission/SpAbstractTreePresenter.extension.st b/src/Spec2-Transmission/SpAbstractTreePresenter.extension.st deleted file mode 100644 index c82c662d..00000000 --- a/src/Spec2-Transmission/SpAbstractTreePresenter.extension.st +++ /dev/null @@ -1,31 +0,0 @@ -Extension { #name : 'SpAbstractTreePresenter' } - -{ #category : '*Spec2-Transmission' } -SpAbstractTreePresenter >> defaultInputPort [ - - ^ self inputRootsPort -] - -{ #category : '*Spec2-Transmission' } -SpAbstractTreePresenter >> defaultOutputPort [ - - ^ self outputSelectionPort -] - -{ #category : '*Spec2-Transmission' } -SpAbstractTreePresenter >> inputRootsPort [ - - ^ SpRootsPort newPresenter: self -] - -{ #category : '*Spec2-Transmission' } -SpAbstractTreePresenter >> outputActivationPort [ - - ^ SpActivationPort newPresenter: self -] - -{ #category : '*Spec2-Transmission' } -SpAbstractTreePresenter >> outputSelectionPort [ - - ^ SpSelectionPort newPresenter: self -] From 1cf9ea2cac1f6397f738bfbbf804deafb0ebc500 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Mon, 10 Jun 2024 15:58:49 +0200 Subject: [PATCH 03/58] this should not be here --- ...AbstractEasyTreeListViewPresenter.class.st | 345 ------------------ 1 file changed, 345 deletions(-) delete mode 100644 src/Spec2-Core/SpAbstractEasyTreeListViewPresenter.class.st diff --git a/src/Spec2-Core/SpAbstractEasyTreeListViewPresenter.class.st b/src/Spec2-Core/SpAbstractEasyTreeListViewPresenter.class.st deleted file mode 100644 index f1fc9786..00000000 --- a/src/Spec2-Core/SpAbstractEasyTreeListViewPresenter.class.st +++ /dev/null @@ -1,345 +0,0 @@ -" -A base for tree presenters, it defines basic functionality common to all trees. -" -Class { - #name : 'SpAbstractEasyTreeListViewPresenter', - #superclass : 'SpAbstractEasyPresenter', - #classTraits : 'SpTSearchable classTrait', - #category : 'Spec2-ListView', - #package : 'Spec2-ListView' -} - -{ #category : 'testing' } -SpAbstractEasyTreeListViewPresenter class >> isAbstract [ - - ^ super isAbstract or: [ self = SpAbstractTreePresenter ] -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> children: aBlock [ - "Set a block to answer the children of a node when it is expanded. - `aBlock` receives one argument, the node element to expand. - If there are no children to answer, `aBlock` needs to answer an empty collection." - - contentView children: aBlock -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> collapseAll [ - "Collapse all nodes of the tree. " - - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter collapseAll ] -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> collapsePath: aPath [ - "Collapse the tree path. - `aPath` is the path to collapse. A path is an array of node indexes (e.g. #(1 2 3))" - - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter collapsePath: aPath ] -] - -{ #category : 'transmission' } -SpAbstractEasyTreeListViewPresenter >> defaultInputPort [ - - ^ self inputRootsPort -] - -{ #category : 'transmission' } -SpAbstractEasyTreeListViewPresenter >> defaultOutputPort [ - - ^ self outputSelectionPort -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> expandAll [ - "Expand all nodes of the tree. - WARNING: If your tree is big, this operation can be slow." - - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter expandAll ] -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> expandPath: aPath [ - "Expand the tree path. - `aPath` is the path to expand. A path is an array of node indexes (e.g. #(1 2 3))" - - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter expandPath: aPath ] -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> expandRoots [ - "Expand all roots of the tree" - - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter expandRoots ] -] - -{ #category : 'initialization' } -SpAbstractEasyTreeListViewPresenter >> initialize [ - - super initialize. - self initializeTSearchable. - self registerEvents -] - -{ #category : 'transmission' } -SpAbstractEasyTreeListViewPresenter >> inputRootsPort [ - - ^ SpRootsPort newPresenter: self -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> items: aCollection [ - "Set the roots of a tree. This is a convenience method, synonym of `SpTreePresenter>>#roots:`" - - self roots: aCollection -] - -{ #category : 'private' } -SpAbstractEasyTreeListViewPresenter >> lazilyComputeChildren: aBoolean [ - - self flag: #TODO. -] - -{ #category : 'transmission' } -SpAbstractEasyTreeListViewPresenter >> outputActivationPort [ - - ^ SpActivationPort newPresenter: self -] - -{ #category : 'transmission' } -SpAbstractEasyTreeListViewPresenter >> outputSelectionPort [ - - ^ SpSelectionPort newPresenter: self -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> refresh [ - "Forces a refresh of the tree. - This is useful when some model contents has changed, but we do not want to reset the whole list - (and losing selections with it)" - - self withAdapterDo: [ :anAdapter | anAdapter refreshTree ] -] - -{ #category : 'initialization' } -SpAbstractEasyTreeListViewPresenter >> registerEvents [ - - "self whenMenuChangedDo: [ - self withAdapterDo: [ :anAdapter | anAdapter updateMenu ] ]" -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> roots [ - "Answer the roots of the tree" - - ^ contentView roots -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> roots: aCollection [ - "Set the roots of the tree table. - This is the starting point from where the whole tree will be shown." - - contentView roots: aCollection -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectItem: anItem [ - "Select `anItem` if it is included in model list. - It does not scrolls to selected element." - - self selection selectItem: anItem -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectItems: aListOfItem [ - "Select items included in `aCollection` if they are included in model list. - NOTE: In single selection mode it will select the first element of `aCollection` - It does not scrolls to selected element." - - self selection selectItems: aListOfItem -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectPath: aPath [ - "Selects element in `aPath` - `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3)). - It does not scrolls to selected element." - - self selection selectPath: aPath -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectPath: aPath scrollToSelection: shouldScrollToSelection [ - "Selects element in `aPath` - `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3)). - If `shouldScrollToSelection` is true, it will scroll to selected element. - IMPORTANT: Scrolling to selection just has sense when the widget is already shown, because before it - is displayed it does not has real bounds. In morphic (and gtk) it has a minimal extent assigned, - but that will change as soon as the widget is inserted in a container and the container applies its - layout." - - contentView - selectPath: aPath - scrollToSelection: shouldScrollToSelection -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectPathByItems: pathArray [ - - self selectPathByItems: pathArray scrollToSelection: false -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectPathByItems: pathArray scrollToSelection: aBoolean [ - "IMPORTANT: Scrolling to selection just has sense when the widget is already shown, because before it - is displayed it does not has real bounds. In morphic (and gtk) it has a minimal extent assigned, - but that will change as soon as the widget is inserted in a container and the container applies its - layout." - | pathIndexes | - - pathIndexes := self pathIndexOf: pathArray. - pathIndexes size > 1 ifTrue: [ - self expandPath: pathIndexes allButLast ]. - self - selectPath: pathIndexes - scrollToSelection: aBoolean -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectPaths: pathArray [ - "Selects all elements in `pathsArray`` - `pathsArray` is an array of paths. A path is an array of node indexes (e.g. #(1 2 3))" - - self selection selectPaths: pathArray -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectedItem [ - "Return selected item." - - ^ self selection selectedItem -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selectedItems [ - "Return all the selected items in the case of a multiple selection list" - - ^ self selection selectedItems -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> selection [ - "Answer the selection object (an instance of `SpSingleSelectionMode` or `SpMultipleSelectionMode`). - This is not the item selected, but the selection container (it may contain one or many selected - items)" - - ^ contentView selection -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> selectionMode [ - "Answer the selection object (an instance of `SpSingleSelectionMode` or `SpMultipleSelectionMode`). - This is not the item selected, but the selection container (it may contain one or many selected - items). - This is the same as `SpAbstractListPresenter>>#selection`" - - ^ contentView selectionMode -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> unselectAll [ - "Remove all selections" - - self selection unselectAll -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> unselectItem: anItem [ - "Remove selection of element `anItem`" - - self selection unselectItem: anItem -] - -{ #category : 'api - selection' } -SpAbstractEasyTreeListViewPresenter >> unselectPath: aPath [ - "Unselects element in `aPath` - `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3))" - - self selection unselectPath: aPath -] - -{ #category : 'api' } -SpAbstractEasyTreeListViewPresenter >> updateRootsKeepingSelection: aCollection [ - "Update tree roots keeping current selection. - WARNING: aCollection must includes the elements selected." - - contentView updateRootsKeepingSelection: aCollection -] - -{ #category : 'api - events' } -SpAbstractEasyTreeListViewPresenter >> whenMultiSelectionChangedDo: aBlock [ - "Inform when selection mode has changed. - `aBlock` has three optional arguments: - - new value - - old value - - the announcement triggering this action" - - contentView whenMultiSelectionChangedDo: aBlock -] - -{ #category : 'api - events' } -SpAbstractEasyTreeListViewPresenter >> whenRootsChangedDo: aBlock [ - "Inform when roots have changed. - `aBlock` has three optional arguments: - - new value - - old value - - the announcement triggering this action" - - contentView whenRootsChangedDo: aBlock -] - -{ #category : 'api - events' } -SpAbstractEasyTreeListViewPresenter >> whenSelectedIndexChangedDo: aBlock [ - "Inform when selected index has changed. - `aBlock` receives one optional argument (the new element)." - - contentView whenSelectedIndexChangedDo: aBlock -] - -{ #category : 'api - events' } -SpAbstractEasyTreeListViewPresenter >> whenSelectedItemChangedDo: aBlock [ - "Inform when selected index has changed. - `aBlock` receives one optional argument (the new element)." - - contentView whenSelectedItemChangedDo: aBlock - -] - -{ #category : 'api - events' } -SpAbstractEasyTreeListViewPresenter >> whenSelectionChangedDo: aBlock [ - "Inform when selection has changed. - `aBlock` has three optional arguments: - - new value - - old value - - the announcement triggering this action" - - contentView whenSelectionChangedDo: aBlock -] - -{ #category : 'api - events' } -SpAbstractEasyTreeListViewPresenter >> whenShowColumnHeadersChangedDo: aBlock [ - "Inform when showColumnHeaders property has changed. - `aBlock` has three optional arguments: - - new value - - old value - - the announcement triggering this action" - - contentView whenShowColumnHeadersChangedDo: aBlock -] From fcadd6c699cf0404f61b2219fd278e42daf41946 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Mon, 10 Jun 2024 15:59:40 +0200 Subject: [PATCH 04/58] add application accessor to the builder (because it may be needed) --- src/Spec2-Core/SpPresenterBuilder.class.st | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Spec2-Core/SpPresenterBuilder.class.st b/src/Spec2-Core/SpPresenterBuilder.class.st index 69fef3d1..256ee7bf 100644 --- a/src/Spec2-Core/SpPresenterBuilder.class.st +++ b/src/Spec2-Core/SpPresenterBuilder.class.st @@ -14,11 +14,26 @@ Class { #superclass : 'Object', #traits : 'SpTPresenterBuilder', #classTraits : 'SpTPresenterBuilder classTrait', + #instVars : [ + 'application' + ], #category : 'Spec2-Core-Base', #package : 'Spec2-Core', #tag : 'Base' } +{ #category : 'accessing' } +SpPresenterBuilder >> application [ + + ^ application +] + +{ #category : 'accessing' } +SpPresenterBuilder >> application: anApplication [ + + application := anApplication +] + { #category : 'instance creation' } SpPresenterBuilder >> instantiate: aPresenterClass [ "Instantiate a SpPresenter subclass and set its instance owner" From 804523c9079d826b81d5cb71dff4f665376053a7 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Mon, 10 Jun 2024 15:59:52 +0200 Subject: [PATCH 05/58] add creator --- src/Spec2-Core/SpPresenterBuilder.class.st | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Spec2-Core/SpPresenterBuilder.class.st b/src/Spec2-Core/SpPresenterBuilder.class.st index 256ee7bf..cabd9586 100644 --- a/src/Spec2-Core/SpPresenterBuilder.class.st +++ b/src/Spec2-Core/SpPresenterBuilder.class.st @@ -22,6 +22,14 @@ Class { #tag : 'Base' } +{ #category : 'instance creation' } +SpPresenterBuilder class >> newApplication: anApplication [ + + ^ self new + application: anApplication; + yourself +] + { #category : 'accessing' } SpPresenterBuilder >> application [ From 71a0db153af70442ff8a0f3ebec6033dc5b8a470 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 11 Jun 2024 13:59:15 +0200 Subject: [PATCH 06/58] label is just visible if actually used (because many times we don't) --- src/Spec2-Dialogs/SpAbstractMessageDialog.class.st | 6 ++++-- src/Spec2-Dialogs/SpRequestTextDialog.class.st | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st index 0fa88212..1e7200c1 100644 --- a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st +++ b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st @@ -113,7 +113,8 @@ SpAbstractMessageDialog >> initializeDialogWindow: aDialogWindowPresenter [ SpAbstractMessageDialog >> initializePresenters [ image := self newImage image: self defaultIcon. - label := self newDialogLabel + label := self newDialogLabel. + label hide ] { #category : 'initialization' } @@ -127,7 +128,8 @@ SpAbstractMessageDialog >> initializeWindow: aWindowPresenter [ { #category : 'api' } SpAbstractMessageDialog >> label: aString [ - label text: aString asText trim + label text: aString asText trim. + label show ] { #category : 'private' } diff --git a/src/Spec2-Dialogs/SpRequestTextDialog.class.st b/src/Spec2-Dialogs/SpRequestTextDialog.class.st index 9fd0f309..960a4475 100644 --- a/src/Spec2-Dialogs/SpRequestTextDialog.class.st +++ b/src/Spec2-Dialogs/SpRequestTextDialog.class.st @@ -58,4 +58,6 @@ SpRequestTextDialog >> initializePresenters [ label := self newDialogLabel. textInput := self newTextInput. errorLabel := self newLabel. + + label hide ] From 57e16f80c296904925e63f154abe6c77be61c329 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 11 Jun 2024 14:00:55 +0200 Subject: [PATCH 07/58] implement alternateRowColor (in gtk4, it just activates the row separator, but it does its job :P) --- src/Spec2-ListView/SpAbstractEasyPresenter.class.st | 7 +++++++ src/Spec2-ListView/SpColumnViewPresenter.class.st | 9 +++++++++ src/Spec2-ListView/SpEasyColumnViewPresenter.class.st | 6 ------ .../SpEasyTreeColumnViewPresenter.class.st | 2 +- src/Spec2-ListView/SpTreeListViewPresenter.class.st | 9 +++++++++ 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st index f489307f..c3295a46 100644 --- a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st @@ -54,6 +54,13 @@ SpAbstractEasyPresenter >> addAction: aSpCommand [ contentView addAction: aSpCommand ] +{ #category : 'drawing' } +SpAbstractEasyPresenter >> alternateRowsColor [ + + contentView alternateRowsColor + +] + { #category : 'api' } SpAbstractEasyPresenter >> beMultipleSelection [ diff --git a/src/Spec2-ListView/SpColumnViewPresenter.class.st b/src/Spec2-ListView/SpColumnViewPresenter.class.st index 710f1c5a..84e8160a 100644 --- a/src/Spec2-ListView/SpColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpColumnViewPresenter.class.st @@ -106,6 +106,15 @@ SpColumnViewPresenter >> addColumns: aCollection [ aCollection do: [ :each | self addColumn: each ] ] +{ #category : 'api' } +SpColumnViewPresenter >> alternateRowsColor [ + "Will alternate Rows color for a better reading: one row lighter, the next row darker. + NOTE: Behavior in different backends may be slightly different." + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter alternateRowsColor ] +] + { #category : 'api' } SpColumnViewPresenter >> beNotResizable [ diff --git a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st index 98468476..cb9cd9d1 100644 --- a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st @@ -49,12 +49,6 @@ SpEasyColumnViewPresenter >> addColumn: aColumn [ contentView addColumn: aColumn asColumnViewColumn ] -{ #category : 'drawing' } -SpEasyColumnViewPresenter >> alternateRowsColor [ - - self flag: #TODO -] - { #category : 'api' } SpEasyColumnViewPresenter >> beNotResizable [ diff --git a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st index 57ddb9d9..ac232f12 100644 --- a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st @@ -32,7 +32,7 @@ SpEasyTreeColumnViewPresenter >> addColumn: aColumn [ { #category : 'api' } SpEasyTreeColumnViewPresenter >> alternateRowsColor [ " Will alternate Rows color for a better reading: one row lighter, the next row darker" - self flag: #TODO. + contentView alternateRowsColor ] { #category : 'api' } diff --git a/src/Spec2-ListView/SpTreeListViewPresenter.class.st b/src/Spec2-ListView/SpTreeListViewPresenter.class.st index 9597cb3f..36829a31 100644 --- a/src/Spec2-ListView/SpTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpTreeListViewPresenter.class.st @@ -177,6 +177,15 @@ SpTreeListViewPresenter class >> exampleWithIconsAndMorph [ open ] +{ #category : 'api' } +SpTreeListViewPresenter >> alternateRowsColor [ + "Will alternate Rows color for a better reading: one row lighter, the next row darker. + NOTE: Behavior in different backends may be slightly different." + + self withAdapterPerformOrDefer: [ :anAdapter | + anAdapter alternateRowsColor ] +] + { #category : 'api' } SpTreeListViewPresenter >> bind: aBlock [ From d2887b47adfa2744a589990f51a863a41e07e74e Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 11 Jun 2024 14:01:27 +0200 Subject: [PATCH 08/58] pushed up --- .../SpAbstractEasyListViewPresenter.class.st | 11 ----------- src/Spec2-ListView/SpEasyListViewPresenter.class.st | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st index cef37325..8b1a069b 100644 --- a/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyListViewPresenter.class.st @@ -123,17 +123,6 @@ SpAbstractEasyListViewPresenter >> sortingBlock: aBlock [ self model sortingBlock: aBlock ] -{ #category : 'api - events' } -SpAbstractEasyListViewPresenter >> whenDisplayChangedDo: aBlock [ - "Inform when the display block has changed. - `aBlock` has three optional arguments: - - new value - - old value - - the announcement triggering this action" - - self property: #display whenChangedDo: aBlock -] - { #category : 'api' } SpAbstractEasyListViewPresenter >> withScrollBars [ diff --git a/src/Spec2-ListView/SpEasyListViewPresenter.class.st b/src/Spec2-ListView/SpEasyListViewPresenter.class.st index 382a0901..d6ce324f 100644 --- a/src/Spec2-ListView/SpEasyListViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyListViewPresenter.class.st @@ -208,6 +208,17 @@ SpEasyListViewPresenter >> updateItemsKeepingSelection: aCollection [ contentView updateItemsKeepingSelection: aCollection ] +{ #category : 'api - events' } +SpEasyListViewPresenter >> whenDisplayChangedDo: aBlock [ + "Inform when the display block has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + self property: #display whenChangedDo: aBlock +] + { #category : 'api - events' } SpEasyListViewPresenter >> whenIconsChangedDo: aBlock [ "Inform when the icons block has changed. From 60c1951082d4386b5a762caf90405927bf5763eb Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 11 Jun 2024 14:01:59 +0200 Subject: [PATCH 09/58] implement easy tree --- .../SpEasyTreeListViewPresenter.class.st | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st index 90845878..c61b224b 100644 --- a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st @@ -1,6 +1,174 @@ Class { #name : 'SpEasyTreeListViewPresenter', #superclass : 'SpAbstractEasyTreeListViewPresenter', + #instVars : [ + '#headerPanel', + '#display => ObservableSlot', + '#displayIcon => ObservableSlot' + ], #category : 'Spec2-ListView', #package : 'Spec2-ListView' } + +{ #category : 'api' } +SpEasyTreeListViewPresenter >> children: aBlock [ + + contentView children: aBlock +] + +{ #category : 'layout' } +SpEasyTreeListViewPresenter >> defaultLayout [ + + ^ SpOverlayLayout new + child: (SpBoxLayout newVertical + add: headerPanel expand: false; + add: contentView; + yourself); + addOverlay: searchInput withConstraints: [ :c | c vAlignStart; hAlignEnd ]; + yourself +] + +{ #category : 'api' } +SpEasyTreeListViewPresenter >> display [ + "Answer the display block that will transform the objects from `SpAbstractListPresenter>>#model` into a + displayable string." + + ^ display +] + +{ #category : 'api' } +SpEasyTreeListViewPresenter >> display: aBlock [ + "Set the block that will be applied on each of the list items. + The result of the block will be used to display the item on the screen. + `aBlock` receives one argument. + Here is the typical example: + + initializePresenters + ... + fontFamilyList := self newTree. + fontFamilyList display: [ :fontFamily | fontFamily familyName ] + ... + " + + display := aBlock +] + +{ #category : 'api' } +SpEasyTreeListViewPresenter >> displayIcon [ + "Return the block used to return an icon that will be displayed in the list" + + ^ displayIcon +] + +{ #category : 'api' } +SpEasyTreeListViewPresenter >> displayIcon: aBlock [ + "Set a block which takes an item as argument and returns the icon to display in the list. + `aBlock` receives one argument" + + displayIcon := aBlock +] + +{ #category : 'private' } +SpEasyTreeListViewPresenter >> displayValueFor: anObject [ + + ^ self display value: anObject +] + +{ #category : 'testing' } +SpEasyTreeListViewPresenter >> hasHeaderTitle [ + "Answer true if the list has a title (See `SpListPresenter>>#headerTitle:`)." + + ^ headerPanel isVisible +] + +{ #category : 'testing' } +SpEasyTreeListViewPresenter >> hasIcons [ + "Answer true if the list has an icon provider (See `SpListPresenter>>#icons:`)." + + ^ self displayIcon notNil +] + +{ #category : 'api' } +SpEasyTreeListViewPresenter >> headerTitle [ + "Answer the header title." + + ^ headerPanel label +] + +{ #category : 'api' } +SpEasyTreeListViewPresenter >> headerTitle: aString [ + "Set the header title." + + headerPanel label:( aString ifNil: [ '' ]). + aString isEmptyOrNil + ifTrue: [ headerPanel hide ] + ifFalse: [ headerPanel show ] +] + +{ #category : 'api' } +SpEasyTreeListViewPresenter >> hideHeaderTitle [ + + headerPanel hide +] + +{ #category : 'private' } +SpEasyTreeListViewPresenter >> iconFor: anItem [ + + ^ self displayIcon + cull: anItem + cull: self +] + +{ #category : 'initialization' } +SpEasyTreeListViewPresenter >> initialize [ + + super initialize. + display := [ :object | object asString ] +] + +{ #category : 'initialization' } +SpEasyTreeListViewPresenter >> initializePresenters [ + + super initializePresenters. + + headerPanel := self newLabel. + contentView := self newTreeListView + setup: [ :aPresenter | + (aPresenter instantiate: SpEasyListRowPresenter) + listView: self; + yourself ]; + bind: [ :aPresenter :anObject | + aPresenter model: anObject ]; + yourself. + + headerPanel hide +] + +{ #category : 'initialization' } +SpEasyTreeListViewPresenter >> registerEvents [ + + super registerEvents. + self whenDisplayChangedDo: [ contentView refresh ] +] + +{ #category : 'api - events' } +SpEasyTreeListViewPresenter >> whenDisplayChangedDo: aBlock [ + "Inform when the display block has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + self property: #display whenChangedDo: aBlock +] + +{ #category : 'api - events' } +SpEasyTreeListViewPresenter >> whenIconsChangedDo: aBlock [ + "Inform when the icons block has changed. + `aBlock` has three optional arguments: + - new value + - old value + - the announcement triggering this action" + + self property: #displayIcon whenChangedDo: aBlock +] From 1678e399532f7f4f094a7531f99f4f88c17faed0 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 11 Jun 2024 14:02:28 +0200 Subject: [PATCH 10/58] add transmissions for trees From 63b841e1471c1dced20f0da24a8760dad5fb593d Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Wed, 12 Jun 2024 21:41:52 +0200 Subject: [PATCH 11/58] make actionbar able to be fillWith: commands --- .../SpActionBarPresenter.extension.st | 22 +++++++++++++++++++ .../SpActionBarPresenterBuilder.class.st | 1 + 2 files changed, 23 insertions(+) create mode 100644 src/Spec2-Commander2/SpActionBarPresenter.extension.st diff --git a/src/Spec2-Commander2/SpActionBarPresenter.extension.st b/src/Spec2-Commander2/SpActionBarPresenter.extension.st new file mode 100644 index 00000000..ebccda0a --- /dev/null +++ b/src/Spec2-Commander2/SpActionBarPresenter.extension.st @@ -0,0 +1,22 @@ +Extension { #name : 'SpActionBarPresenter' } + +{ #category : '*Spec2-Commander2' } +SpActionBarPresenter >> addItemLeft: anItem [ + + self add: anItem +] + +{ #category : '*Spec2-Commander2' } +SpActionBarPresenter >> addItemRight: anItem [ + + self addLast: anItem +] + +{ #category : '*Spec2-Commander2' } +SpActionBarPresenter >> fillWith: aCommandGroup [ + + items removeAll. + SpActionBarPresenterBuilder new + actionBarPresenter: self; + visit: aCommandGroup +] diff --git a/src/Spec2-Commander2/SpActionBarPresenterBuilder.class.st b/src/Spec2-Commander2/SpActionBarPresenterBuilder.class.st index 04f99327..f6cf7759 100644 --- a/src/Spec2-Commander2/SpActionBarPresenterBuilder.class.st +++ b/src/Spec2-Commander2/SpActionBarPresenterBuilder.class.st @@ -32,6 +32,7 @@ SpActionBarPresenterBuilder >> initialize [ { #category : 'visiting' } SpActionBarPresenterBuilder >> visitCommand: aCmCommandEntry [ + aCmCommandEntry positionStrategy addButton: aCmCommandEntry asButtonPresenter toActionBar: self actionBarPresenter From c265eb2b40c49d300d9ffcd4fac4748d88e4d0d2 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Wed, 12 Jun 2024 21:43:06 +0200 Subject: [PATCH 12/58] add centerPresenter to action bars (this needs to be added to the morphic backend) --- src/Spec2-Core/SpActionBarPresenter.class.st | 23 +++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Spec2-Core/SpActionBarPresenter.class.st b/src/Spec2-Core/SpActionBarPresenter.class.st index bae49bfe..2dbfe884 100644 --- a/src/Spec2-Core/SpActionBarPresenter.class.st +++ b/src/Spec2-Core/SpActionBarPresenter.class.st @@ -8,7 +8,8 @@ Class { #name : 'SpActionBarPresenter', #superclass : 'SpAbstractWidgetPresenter', #instVars : [ - 'items' + '#items', + '#centerPresenter => ObservableSlot' ], #category : 'Spec2-Core-Widgets', #package : 'Spec2-Core', @@ -31,6 +32,7 @@ SpActionBarPresenter class >> documentFactoryMethodSelector [ SpActionBarPresenter >> add: aButtonPresenter [ "Add a button presenter to be shown at the start of the action bar (at the left)." + aButtonPresenter owner: self. (items at: #start ifAbsentPut: [ OrderedCollection new ] ) @@ -41,12 +43,25 @@ SpActionBarPresenter >> add: aButtonPresenter [ SpActionBarPresenter >> addLast: aButtonPresenter [ "Add a button presenter to be shown at the end of the action bar (at the right)." + aButtonPresenter owner: self. (items at: #end ifAbsentPut: [ OrderedCollection new ] ) add: aButtonPresenter ] +{ #category : 'api' } +SpActionBarPresenter >> centerPresenter [ + + ^ centerPresenter +] + +{ #category : 'api' } +SpActionBarPresenter >> centerPresenter: aPresenter [ + + centerPresenter := aPresenter +] + { #category : 'initialization' } SpActionBarPresenter >> initialize [ @@ -81,3 +96,9 @@ SpActionBarPresenter >> traverseInFocusOrderDo: aBlock excluding: excludes [ self presentersInFocusOrder do: [ :each | each traverseInFocusOrderDo: aBlock excluding: excludes ] ] + +{ #category : 'api - events' } +SpActionBarPresenter >> whenCenterPresenterChangedDo: aBlock [ + + self property: #centerPresenter whenChangedDo: aBlock +] From 5e881493a01d79445697c7c2e2bb6938b7586563 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Wed, 12 Jun 2024 21:43:25 +0200 Subject: [PATCH 13/58] add flat style --- src/Spec2-Core/SpEditableListPresenter.class.st | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Spec2-Core/SpEditableListPresenter.class.st b/src/Spec2-Core/SpEditableListPresenter.class.st index eafd01aa..84469027 100644 --- a/src/Spec2-Core/SpEditableListPresenter.class.st +++ b/src/Spec2-Core/SpEditableListPresenter.class.st @@ -147,6 +147,7 @@ SpEditableListPresenter >> initializeDialogWindow: aWindow [ { #category : 'initialization' } SpEditableListPresenter >> initializePresenters [ + label := self newLabel. list := self newEasyListView. addButton := self newButton. @@ -157,26 +158,32 @@ SpEditableListPresenter >> initializePresenters [ bottomButton := self newButton. addButton addStyle: 'small'; + addStyle: 'flat'; icon: (self iconNamed: #add); help: 'Add a new item to the list'. removeButton addStyle: 'small'; + addStyle: 'flat'; icon: (self iconNamed: #remove); help: 'Remove a item from the list'. upButton addStyle: 'small'; + addStyle: 'flat'; icon: (self iconNamed: #up); help: 'Move this item up from one element'. downButton addStyle: 'small'; + addStyle: 'flat'; icon: (self iconNamed: #down); help: 'Move this item down from one element'. topButton addStyle: 'small'; + addStyle: 'flat'; icon: (self iconNamed: #top); help: 'Move this item on the first position of the list'. bottomButton addStyle: 'small'; + addStyle: 'flat'; icon: (self iconNamed: #bottom); help: 'Move this item on the last position of the list' ] From d50c5e2c7b61f4e2aa835d37bb483d734ee28b5a Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Wed, 12 Jun 2024 21:51:59 +0200 Subject: [PATCH 14/58] traverse needs to be applied also to child presenters --- src/Spec2-Core/SpActionBarPresenter.class.st | 10 ++++++++++ src/Spec2-Core/SpToolbarPresenter.class.st | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Spec2-Core/SpActionBarPresenter.class.st b/src/Spec2-Core/SpActionBarPresenter.class.st index 2dbfe884..521da114 100644 --- a/src/Spec2-Core/SpActionBarPresenter.class.st +++ b/src/Spec2-Core/SpActionBarPresenter.class.st @@ -97,6 +97,16 @@ SpActionBarPresenter >> traverseInFocusOrderDo: aBlock excluding: excludes [ each traverseInFocusOrderDo: aBlock excluding: excludes ] ] +{ #category : 'private - traversing' } +SpActionBarPresenter >> traversePresentersDo: aBlock excluding: excludes [ + + super traversePresentersDo: aBlock excluding: excludes. + self presenters do: [ :each | + each traversePresentersDo: aBlock excluding: excludes ]. + self centerPresenter ifNotNil: [ :aPresenter | + aPresenter traversePresentersDo: aBlock excluding: excludes ] +] + { #category : 'api - events' } SpActionBarPresenter >> whenCenterPresenterChangedDo: aBlock [ diff --git a/src/Spec2-Core/SpToolbarPresenter.class.st b/src/Spec2-Core/SpToolbarPresenter.class.st index 4133566a..57a77823 100644 --- a/src/Spec2-Core/SpToolbarPresenter.class.st +++ b/src/Spec2-Core/SpToolbarPresenter.class.st @@ -198,6 +198,14 @@ SpToolbarPresenter >> traverseInFocusOrderDo: aBlock excluding: excludes [ each traverseInFocusOrderDo: aBlock excluding: excludes ] ] +{ #category : 'private - traversing' } +SpToolbarPresenter >> traversePresentersDo: aBlock excluding: excludes [ + + super traversePresentersDo: aBlock excluding: excludes. + self presenters do: [ :each | + each traversePresentersDo: aBlock excluding: excludes ] +] + { #category : 'events' } SpToolbarPresenter >> whenItemsChangeDo: aBlockClosure [ From da5e410bbd3968d340d911ea6a440bb6223ee80c Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Wed, 12 Jun 2024 21:52:35 +0200 Subject: [PATCH 15/58] cleanup --- src/Spec2-Core/SpEditableListPresenter.class.st | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Spec2-Core/SpEditableListPresenter.class.st b/src/Spec2-Core/SpEditableListPresenter.class.st index 84469027..134e3a8b 100644 --- a/src/Spec2-Core/SpEditableListPresenter.class.st +++ b/src/Spec2-Core/SpEditableListPresenter.class.st @@ -49,10 +49,10 @@ SpEditableListPresenter class >> layoutWithOrdering: useOrdering [ ifTrue: [ listLayout add: (SpBoxLayout newTopToBottom - add: #topButton expand: false fill: false padding: 0; - add: #upButton expand: false fill: false padding: 0; - add: #downButton expand: false fill: false padding: 0; - add: #bottomButton expand: false fill: false padding: 0; + add: #topButton expand: false; + add: #upButton expand: false; + add: #downButton expand: false; + add: #bottomButton expand: false; yourself) expand: false ]. From 552029613a07d6ca5232b0755aa3def24cc25653 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 13 Jun 2024 11:06:39 +0200 Subject: [PATCH 16/58] recategorize --- src/Spec2-Dialogs/SpSelectDialog.class.st | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Spec2-Dialogs/SpSelectDialog.class.st b/src/Spec2-Dialogs/SpSelectDialog.class.st index 5f12e5d0..8a2e5239 100644 --- a/src/Spec2-Dialogs/SpSelectDialog.class.st +++ b/src/Spec2-Dialogs/SpSelectDialog.class.st @@ -165,25 +165,25 @@ SpSelectDialog >> openModal [ ifFalse: [ nil ] ] -{ #category : 'api' } +{ #category : 'api - selection' } SpSelectDialog >> selectFirst [ list selectFirst ] -{ #category : 'api' } +{ #category : 'api - selection' } SpSelectDialog >> selectIndex: aNumber [ list selectIndex: aNumber ] -{ #category : 'api' } +{ #category : 'api - selection' } SpSelectDialog >> selectItem: anObject [ list selectItem: anObject ] -{ #category : 'api' } +{ #category : 'api - selection' } SpSelectDialog >> selectedItem [ ^ list selectedItem From 83a4c55b2027556f96e156df4c85590fe61fef48 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 13 Jun 2024 11:07:01 +0200 Subject: [PATCH 17/58] add test for label --- src/Spec2-Core/SpAbstractFormButtonPresenter.class.st | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Spec2-Core/SpAbstractFormButtonPresenter.class.st b/src/Spec2-Core/SpAbstractFormButtonPresenter.class.st index 2d241a09..3a086d24 100644 --- a/src/Spec2-Core/SpAbstractFormButtonPresenter.class.st +++ b/src/Spec2-Core/SpAbstractFormButtonPresenter.class.st @@ -28,6 +28,12 @@ SpAbstractFormButtonPresenter >> click [ self toggleState ] +{ #category : 'testing' } +SpAbstractFormButtonPresenter >> hasLabel [ + + ^ self label isEmptyOrNil not +] + { #category : 'initialization' } SpAbstractFormButtonPresenter >> initialize [ super initialize. From 640e5e24faf742c869f4dc85d9da38199c3ecb9e Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 20 Jun 2024 10:10:32 +0200 Subject: [PATCH 18/58] fixes https://github.com/pharo-spec/Spec/issues/1524 --- .../SpMorphicLabelAdapter.class.st | 11 ++++++++++- src/Spec2-Backend-Tests/SpLabelAdapterTest.class.st | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Spec2-Adapters-Morphic/SpMorphicLabelAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicLabelAdapter.class.st index 08082386..0028f51e 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicLabelAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicLabelAdapter.class.st @@ -26,6 +26,8 @@ SpMorphicLabelAdapter >> applyDecorationsTo: aString [ self presenter displayUnderline ifNotNil: [ :block | (block cull: aString) ifTrue: [ text addAttribute: TextEmphasis underlined ] ]. + "this in fact does not work (background in LabelMorph objects). + See applyStyle instead" self presenter displayBackgroundColor ifNotNil: [ :block | (block cull: aString) ifNotNil: [ :aColor | text addAttribute: (TextBackgroundColor color: aColor) ] ]. @@ -42,7 +44,14 @@ SpMorphicLabelAdapter >> applyStyle: aMorph [ height is smaller than current height of morph, we need to take care about this even if this means we cannot have a label smaller than the font :(" aMorph height < aMorph font height - ifTrue: [ aMorph height: aMorph font height ] + ifTrue: [ aMorph height: aMorph font height ]. + + "I need to check background here because a LabelMorph is uncapable of apply a + background color (because meh... morphic+polymorph)" + self presenter displayBackgroundColor ifNotNil: [ :block | + (block cull: self presenter label) ifNotNil: [ :aColor | + aMorph backgroundColor: aColor ] ]. + ] { #category : 'factory' } diff --git a/src/Spec2-Backend-Tests/SpLabelAdapterTest.class.st b/src/Spec2-Backend-Tests/SpLabelAdapterTest.class.st index 4b780954..e395df78 100644 --- a/src/Spec2-Backend-Tests/SpLabelAdapterTest.class.st +++ b/src/Spec2-Backend-Tests/SpLabelAdapterTest.class.st @@ -14,6 +14,16 @@ SpLabelAdapterTest >> classToTest [ ^ SpLabelPresenter ] +{ #category : 'tests' } +SpLabelAdapterTest >> testBackgroundColorChangesColor [ + "test this issue: https://github.com/pharo-spec/Spec/issues/1524" + + presenter label: 'Test'. + presenter displayBackgroundColor: [ Color green ]. + self openInstance. + self assert: self adapter widget backgroundColor equals: Color green +] + { #category : 'tests' } SpLabelAdapterTest >> testSetLabelInPresenterAffectsWidget [ presenter label: 'something'. From 125fece323ff10142b6cddb8a9052e96f898e850 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 20 Jun 2024 11:49:59 +0200 Subject: [PATCH 19/58] taskbarIcon needs to take into account the windowIcon defined by the presenter (if any) fixes https://github.com/pharo-project/pharo/pull/16792 --- src/Spec2-Adapters-Morphic/SpWindow.class.st | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Spec2-Adapters-Morphic/SpWindow.class.st b/src/Spec2-Adapters-Morphic/SpWindow.class.st index b34ed7be..13bf97db 100644 --- a/src/Spec2-Adapters-Morphic/SpWindow.class.st +++ b/src/Spec2-Adapters-Morphic/SpWindow.class.st @@ -80,12 +80,20 @@ SpWindow >> okToChange [ ^ self model okToChange ] +{ #category : 'private' } +SpWindow >> taskbarIcon [ + + ^ self model windowIcon + ifNil: [ super taskbarIcon ] +] + { #category : 'accessing' } SpWindow >> taskbarTask [ "Answer a taskbar task for the receiver. Answer nil if not required." - (self valueOfProperty: #noTaskbarTask ifAbsent: [false]) ifTrue: [^nil]. + (self valueOfProperty: #noTaskbarTask ifAbsent: [false]) ifTrue: [ ^ nil ]. + taskbarTask := TaskbarTask morph: self state: self taskbarState From b2845043c76b49ab86116b9bed98bdc5d49d36fd Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 20 Jun 2024 11:50:57 +0200 Subject: [PATCH 20/58] invert send order --- src/Spec2-Core/SpAbstractListPresenter.class.st | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Spec2-Core/SpAbstractListPresenter.class.st b/src/Spec2-Core/SpAbstractListPresenter.class.st index 988a8eb1..a4bd2890 100644 --- a/src/Spec2-Core/SpAbstractListPresenter.class.st +++ b/src/Spec2-Core/SpAbstractListPresenter.class.st @@ -212,8 +212,8 @@ SpAbstractListPresenter >> items: aSequenceableCollection [ `aSequenceableCollection` is a collection of your domain specific items. This resets the collection model and unselects any previously selected item." - model collection: aSequenceableCollection. - self unselectAll + self unselectAll. + model collection: aSequenceableCollection ] { #category : 'private' } From 24f99f91ccce72b637813763fa5eb364a2d3dad3 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 20 Jun 2024 14:58:15 +0200 Subject: [PATCH 21/58] add button decoration api for dialogs (show, not show) --- .../SpDialogWindowMorph.class.st | 31 ++++++++++---- .../SpMorphicDialogWindowAdapter.class.st | 19 +++++++-- .../SpDialogWindowPresenter.class.st | 41 ++++++++++++++++--- 3 files changed, 74 insertions(+), 17 deletions(-) diff --git a/src/Spec2-Adapters-Morphic/SpDialogWindowMorph.class.st b/src/Spec2-Adapters-Morphic/SpDialogWindowMorph.class.st index 64446ffb..53c1c252 100644 --- a/src/Spec2-Adapters-Morphic/SpDialogWindowMorph.class.st +++ b/src/Spec2-Adapters-Morphic/SpDialogWindowMorph.class.st @@ -6,7 +6,8 @@ Class { #name : 'SpDialogWindowMorph', #superclass : 'DialogWindowMorph', #instVars : [ - 'toolbar' + 'toolbar', + 'toolbarMorph' ], #category : 'Spec2-Adapters-Morphic-Support', #package : 'Spec2-Adapters-Morphic', @@ -75,6 +76,13 @@ SpDialogWindowMorph >> okAction: aBlock [ self toolbar okAction: aBlock ] +{ #category : 'accessing' } +SpDialogWindowMorph >> removeToolbar [ + + toolbarMorph ifNil: [ ^ self ]. + self submorphs last removeMorph: toolbarMorph +] + { #category : 'protocol' } SpDialogWindowMorph >> setToolbarFrom: aBlock [ | newToolbar | @@ -95,11 +103,18 @@ SpDialogWindowMorph >> toolbar: anObject [ | content | toolbar := anObject. - self removeMorph: (content := self submorphs last). - self - addMorph: (self newDialogPanel - addMorphBack: content; - addMorphBack: self newButtonRow; - yourself) - frame: (0 @ 0 corner: 1 @ 1) + toolbarMorph + ifNotNil: [ + self removeToolbar. + toolbarMorph := self newButtonRow. + self submorphs last addMorphBack: toolbarMorph ] + ifNil: [ + toolbarMorph := self newButtonRow. + self removeMorph: (content := self submorphs last). + self + addMorph: (self newDialogPanel + addMorphBack: content; + addMorphBack: toolbarMorph; + yourself) + frame: (0 @ 0 corner: 1 @ 1) ] ] diff --git a/src/Spec2-Adapters-Morphic/SpMorphicDialogWindowAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicDialogWindowAdapter.class.st index beb3a0cd..ace79163 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicDialogWindowAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicDialogWindowAdapter.class.st @@ -9,16 +9,27 @@ Class { #tag : 'Base' } +{ #category : 'private' } +SpMorphicDialogWindowAdapter >> addButtonsDecorationTo: widgetToBuild [ + + widgetToBuild setToolbarFrom: [ self buildButtonBar ]. + self model buttons ifNotEmpty: [ + self presenter defaultButton + ifNotNil: [ :aButton | aButton adapter setAsDefault ] ] +] + { #category : 'private' } SpMorphicDialogWindowAdapter >> addPresenterIn: widgetToBuild withSpecLayout: aSpec [ "I replace the mainPanel (which contains contents and button bar) because like that I get the status bar at the end (where it belongs)" super addPresenterIn: widgetToBuild withSpecLayout: aSpec. - self model buttons ifNotEmpty: [ - widgetToBuild setToolbarFrom: [ self buildButtonBar ]. - self presenter defaultButton - ifNotNil: [ :aButton | aButton adapter setAsDefault ] ] + self presenter hasButtonDecorations + ifTrue: [ self addButtonsDecorationTo: widgetToBuild ]. + self presenter whenButtonDecorationsChangedDo: [ :aBoolean | + aBoolean + ifTrue: [ self addButtonsDecorationTo: widgetToBuild ] + ifFalse: [ widgetToBuild removeToolbar ] ] ] { #category : 'factory' } diff --git a/src/Spec2-Core/SpDialogWindowPresenter.class.st b/src/Spec2-Core/SpDialogWindowPresenter.class.st index ac05a9e6..9f0bcf2a 100644 --- a/src/Spec2-Core/SpDialogWindowPresenter.class.st +++ b/src/Spec2-Core/SpDialogWindowPresenter.class.st @@ -32,11 +32,12 @@ Class { #name : 'SpDialogWindowPresenter', #superclass : 'SpWindowPresenter', #instVars : [ - 'buttons', - 'okAction', - 'cancelAction', - 'cancelled', - 'defaultButton' + '#buttons', + '#okAction', + '#cancelAction', + '#cancelled', + '#defaultButton', + '#buttonDecorations => ObservableSlot' ], #category : 'Spec2-Core-Windows', #package : 'Spec2-Core', @@ -165,6 +166,12 @@ SpDialogWindowPresenter >> executeDefaultAction [ defaultButton action cull: self ] +{ #category : 'testing' } +SpDialogWindowPresenter >> hasButtonDecorations [ + + ^ buttonDecorations and: [ self buttons isNotEmpty ] +] + { #category : 'testing' } SpDialogWindowPresenter >> hasDefaultButton [ @@ -177,7 +184,9 @@ SpDialogWindowPresenter >> initialize [ super initialize. buttons := OrderedCollection new. cancelled := true. + self withButtons. self initializeDefaultActions + ] { #category : 'initialization' } @@ -273,3 +282,25 @@ SpDialogWindowPresenter >> triggerOkAction [ okAction ifNil: [ ^ nil ]. ^ okAction cull: self ] + +{ #category : 'api - events' } +SpDialogWindowPresenter >> whenButtonDecorationsChangedDo: aBlock [ + + self + property: #buttonDecorations + whenChangedDo: aBlock +] + +{ #category : 'api' } +SpDialogWindowPresenter >> withButtons [ + "Show buttons" + + buttonDecorations := true +] + +{ #category : 'api' } +SpDialogWindowPresenter >> withoutButtons [ + "Remove all previously added buttons" + + buttonDecorations := false +] From 397d9b707916896302d82e86caa3ea64d4349d12 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 20 Jun 2024 15:36:54 +0200 Subject: [PATCH 22/58] apply deprecations --- src/Spec2-Core/SpJob.class.st | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spec2-Core/SpJob.class.st b/src/Spec2-Core/SpJob.class.st index 167fd45a..13d9e6a1 100644 --- a/src/Spec2-Core/SpJob.class.st +++ b/src/Spec2-Core/SpJob.class.st @@ -344,7 +344,7 @@ SpJob >> value: aNumber [ { #category : 'events' } SpJob >> whenChangedDo: aBlock [ - self announcer when: JobChange do: aBlock + self announcer when: JobChange do: aBlock for: aBlock receiver ] { #category : 'events' } From 7466db0eaf8c0cec04e69b0eea81efbaf919ffa2 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 20 Jun 2024 15:38:21 +0200 Subject: [PATCH 23/58] extracted --- src/Spec2-Dialogs/SpAbstractMessageDialog.class.st | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st index 41542cff..c0802551 100644 --- a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st +++ b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st @@ -103,9 +103,7 @@ SpAbstractMessageDialog >> initialize [ SpAbstractMessageDialog >> initializeDialogWindow: aDialogWindowPresenter [ super initializeDialogWindow: aDialogWindowPresenter. - - aDialogWindowPresenter initialExtent: - (self adjustExtentToLabelHeight: self class defaultExtent). + self initializeWindowExtent: aDialogWindowPresenter. self addButtonsTo: aDialogWindowPresenter ] @@ -125,6 +123,13 @@ SpAbstractMessageDialog >> initializeWindow: aWindowPresenter [ initialExtent: self extent ] +{ #category : 'initialization' } +SpAbstractMessageDialog >> initializeWindowExtent: aDialogWindowPresenter [ + + aDialogWindowPresenter initialExtent: + (self adjustExtentToLabelHeight: self class defaultExtent) +] + { #category : 'api' } SpAbstractMessageDialog >> label [ ^ label text From 228fd920621de289f5bcdfb4cf1d788bbd037ce3 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Thu, 20 Jun 2024 15:39:13 +0200 Subject: [PATCH 24/58] label could be nil, in that case I do not want to show it --- src/Spec2-Dialogs/SpAbstractMessageDialog.class.st | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st index c0802551..810c144c 100644 --- a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st +++ b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st @@ -139,7 +139,7 @@ SpAbstractMessageDialog >> label [ SpAbstractMessageDialog >> label: aString [ label text: aString asText trim. - label show + aString ifNotNil: [ label show ] ] { #category : 'private' } From 2e33ef6836720cf7746784a2b3232c1135c39d15 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 09:36:19 +0200 Subject: [PATCH 25/58] add some ways to configure commands as different kind of buttons (because just clicking is too restrictive) --- src/Spec2-Commander2/SpCommand.class.st | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Spec2-Commander2/SpCommand.class.st b/src/Spec2-Commander2/SpCommand.class.st index acee0a9a..93886371 100644 --- a/src/Spec2-Commander2/SpCommand.class.st +++ b/src/Spec2-Commander2/SpCommand.class.st @@ -20,6 +20,17 @@ Class { #tag : 'Core' } +{ #category : 'converting' } +SpCommand >> asActionButtonPresenter [ + + ^ SpButtonPresenter new + owner: self context; + help: self description; + icon: self icon; + action: [ self execute ]; + yourself +] + { #category : 'converting' } SpCommand >> asButtonPresenter [ self flag: #TODO. "Needs to use inform user display strategy when available, no other available strategy can be used in this context. See issue #705" @@ -27,6 +38,26 @@ SpCommand >> asButtonPresenter [ ^ self buildPresenter ] +{ #category : 'converting' } +SpCommand >> asLabeledButtonPresenter [ + + ^ self asActionButtonPresenter + label: self name; + yourself +] + +{ #category : 'converting' } +SpCommand >> asToggleButtonPresenter [ + + ^ SpToggleButtonPresenter new + owner: self context; + help: self description; + icon: self icon; + whenActivatedDo: [ self execute ]; + whenDeactivatedDo: [ self execute ]; + yourself +] + { #category : 'presenter building' } SpCommand >> buildPresenter [ ^ presenter := self buildPresenterBlock value: self From bffc1b17a7fb00d8ec89b001508a926cc0d94a2a Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 09:45:54 +0200 Subject: [PATCH 26/58] in fact this is the same as `asButtonPresenter` --- src/Spec2-Commander2/SpCommand.class.st | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Spec2-Commander2/SpCommand.class.st b/src/Spec2-Commander2/SpCommand.class.st index 93886371..2dc70c2d 100644 --- a/src/Spec2-Commander2/SpCommand.class.st +++ b/src/Spec2-Commander2/SpCommand.class.st @@ -38,14 +38,6 @@ SpCommand >> asButtonPresenter [ ^ self buildPresenter ] -{ #category : 'converting' } -SpCommand >> asLabeledButtonPresenter [ - - ^ self asActionButtonPresenter - label: self name; - yourself -] - { #category : 'converting' } SpCommand >> asToggleButtonPresenter [ From 86bc695c6f44d4c09270c2c7026b487cf3148279 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 09:49:43 +0200 Subject: [PATCH 27/58] refactor to reuse --- src/Spec2-Commander2/SpCommand.class.st | 40 +++++++++++-------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/Spec2-Commander2/SpCommand.class.st b/src/Spec2-Commander2/SpCommand.class.st index 2dc70c2d..528f0362 100644 --- a/src/Spec2-Commander2/SpCommand.class.st +++ b/src/Spec2-Commander2/SpCommand.class.st @@ -23,11 +23,8 @@ Class { { #category : 'converting' } SpCommand >> asActionButtonPresenter [ - ^ SpButtonPresenter new - owner: self context; - help: self description; - icon: self icon; - action: [ self execute ]; + ^ self asButtonPresenter + label: nil; yourself ] @@ -41,13 +38,8 @@ SpCommand >> asButtonPresenter [ { #category : 'converting' } SpCommand >> asToggleButtonPresenter [ - ^ SpToggleButtonPresenter new - owner: self context; - help: self description; - icon: self icon; - whenActivatedDo: [ self execute ]; - whenDeactivatedDo: [ self execute ]; - yourself + self configureAsButtonOfClass: SpToggleButtonPresenter. + ^ self buildPresenter ] { #category : 'presenter building' } @@ -67,25 +59,29 @@ SpCommand >> buildPresenterBlock: anObject [ { #category : 'presenter building' } SpCommand >> configureAsButton [ + self configureAsButtonOfClass: SpButtonPresenter ] { #category : 'presenter building' } SpCommand >> configureAsButtonOfClass: aButtonClass [ - self - buildPresenterBlock: [ :specCommand | - aButtonClass new - label: specCommand name; - help: specCommand description; - in: [ :button | - specCommand hasIcon - ifTrue: [ button icon: specCommand icon ] ]; - action: [ specCommand execute ]; - yourself ] + + self buildPresenterBlock: [ :specCommand | + aButtonClass new + label: specCommand name; + help: specCommand description; + in: [ :button | + specCommand hasIcon + ifTrue: [ button icon: specCommand icon ] ]; + action: [ + specCommand canBeExecuted + ifTrue: [ specCommand execute ] ]; + yourself ] ] { #category : 'presenter building' } SpCommand >> configureAsToolBarToggleButton [ + self configureAsButtonOfClass: SpToolbarToggleButtonPresenter ] From 5384aff9537298239da0a57a041357689bbb17cd Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 14:26:05 +0200 Subject: [PATCH 28/58] verify label is not nil (because it can) --- src/Spec2-Adapters-Morphic/SpMorphicButtonAdapter.class.st | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Spec2-Adapters-Morphic/SpMorphicButtonAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicButtonAdapter.class.st index f74e4456..16a73b07 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicButtonAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicButtonAdapter.class.st @@ -147,9 +147,13 @@ SpMorphicButtonAdapter >> keyStroke: anEvent fromMorph: aMorph [ { #category : 'widget API' } SpMorphicButtonAdapter >> label [ + | labelString | + + labelString := self presenter label + ifNotNil: [ :aString | aString withAccentuatedCharacter: self presenter shortcutCharacter ]. ^ self - buildLabel: (self presenter label withAccentuatedCharacter: self presenter shortcutCharacter) + buildLabel: labelString withIcon: self presenter icon ] From c6d547791f6602b5a78513556bd504dda6cf5913 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 14:27:55 +0200 Subject: [PATCH 29/58] add a switch presenter (in morphic backend it fallbacks to checkbox for the moment, as we need to actually create the morph and no point on doing it) --- src/Spec2-Core/SpSwitchPresenter.class.st | 35 +++++++++++++++++++ src/Spec2-Core/SpTPresenterBuilder.trait.st | 7 ++++ .../SpApplicationBackend.extension.st | 6 ++++ .../SpMorphicBackend.extension.st | 6 ++++ 4 files changed, 54 insertions(+) create mode 100644 src/Spec2-Core/SpSwitchPresenter.class.st diff --git a/src/Spec2-Core/SpSwitchPresenter.class.st b/src/Spec2-Core/SpSwitchPresenter.class.st new file mode 100644 index 00000000..eedc998d --- /dev/null +++ b/src/Spec2-Core/SpSwitchPresenter.class.st @@ -0,0 +1,35 @@ +" +A Checkbox Button that can be activated/deactivated. + +" +Class { + #name : 'SpSwitchPresenter', + #superclass : 'SpAbstractFormButtonPresenter', + #category : 'Spec2-Core-Widgets', + #package : 'Spec2-Core', + #tag : 'Widgets' +} + +{ #category : 'specs' } +SpSwitchPresenter class >> adapterName [ + + ^ #SwitchAdapter +] + +{ #category : 'documentation' } +SpSwitchPresenter class >> documentFactoryMethodSelector [ + + ^ #newSwitch +] + +{ #category : 'specs' } +SpSwitchPresenter class >> title [ + + ^ 'Switch Button' +] + +{ #category : 'api' } +SpSwitchPresenter >> label: aString [ + + self error: 'Switches can''t have labels' +] diff --git a/src/Spec2-Core/SpTPresenterBuilder.trait.st b/src/Spec2-Core/SpTPresenterBuilder.trait.st index dce2778d..2b001cc3 100644 --- a/src/Spec2-Core/SpTPresenterBuilder.trait.st +++ b/src/Spec2-Core/SpTPresenterBuilder.trait.st @@ -67,6 +67,7 @@ SpTPresenterBuilder >> newButtonBar [ { #category : 'scripting - widgets' } SpTPresenterBuilder >> newCheckBox [ + ^ self instantiate: SpCheckBoxPresenter ] @@ -253,6 +254,12 @@ SpTPresenterBuilder >> newStatusBar [ ^ self instantiate: SpStatusBarPresenter ] +{ #category : 'scripting - widgets' } +SpTPresenterBuilder >> newSwitch [ + + ^ self instantiate: self application backend switchClass +] + { #category : 'scripting - widgets' } SpTPresenterBuilder >> newTable [ diff --git a/src/Spec2-ListView/SpApplicationBackend.extension.st b/src/Spec2-ListView/SpApplicationBackend.extension.st index 45552f6b..77aab870 100644 --- a/src/Spec2-ListView/SpApplicationBackend.extension.st +++ b/src/Spec2-ListView/SpApplicationBackend.extension.st @@ -13,6 +13,12 @@ SpApplicationBackend >> listClass [ ] +{ #category : '*Spec2-ListView' } +SpApplicationBackend >> switchClass [ + + self subclassResponsibility +] + { #category : '*Spec2-ListView' } SpApplicationBackend >> tableClass [ diff --git a/src/Spec2-ListView/SpMorphicBackend.extension.st b/src/Spec2-ListView/SpMorphicBackend.extension.st index a171d8a0..eaa81a88 100644 --- a/src/Spec2-ListView/SpMorphicBackend.extension.st +++ b/src/Spec2-ListView/SpMorphicBackend.extension.st @@ -12,6 +12,12 @@ SpMorphicBackend >> listClass [ ^ SpListPresenter ] +{ #category : '*Spec2-ListView' } +SpMorphicBackend >> switchClass [ + + ^ SpCheckBoxPresenter +] + { #category : '*Spec2-ListView' } SpMorphicBackend >> tableClass [ From b6891d4c3e1c4312e521503828ced1838058e909 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 14:28:28 +0200 Subject: [PATCH 30/58] ensure aText is a Text :) --- src/Spec2-Dialogs/SpAbstractMessageDialog.class.st | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st index 810c144c..32cdb974 100644 --- a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st +++ b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st @@ -55,7 +55,7 @@ SpAbstractMessageDialog >> calculateLabelHeightForTextWithoutMargin: aText forEx "We have a minimal height " aText ifEmpty: [ ^ self singleLineDefaultHeight ]. - ^ (aText lineHeightsWrappingAtWidth: anExtent x - 20) sum + ^ (aText asText lineHeightsWrappingAtWidth: anExtent x - 20) sum ] From cf527d8c93924642fe9998f178a9190c7dbe83ab Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 14:36:22 +0200 Subject: [PATCH 31/58] add switchClass for gtk4 backend --- src/Spec2-ListView/SpecGtkBackend.extension.st | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Spec2-ListView/SpecGtkBackend.extension.st b/src/Spec2-ListView/SpecGtkBackend.extension.st index b4c8b941..34c4cc2b 100644 --- a/src/Spec2-ListView/SpecGtkBackend.extension.st +++ b/src/Spec2-ListView/SpecGtkBackend.extension.st @@ -12,6 +12,12 @@ SpecGtkBackend >> listClass [ ^ SpEasyListViewPresenter ] +{ #category : '*Spec2-ListView' } +SpecGtkBackend >> switchClass [ + + ^ SpSwitchPresenter +] + { #category : '*Spec2-ListView' } SpecGtkBackend >> tableClass [ From 1f7b61907a372a531a3eed57a579dfc4c1976f1c Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 14:37:57 +0200 Subject: [PATCH 32/58] add missing method (probably to be removed later) --- src/Spec2-Commander2/SpAbstractTreePresenter.extension.st | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/Spec2-Commander2/SpAbstractTreePresenter.extension.st diff --git a/src/Spec2-Commander2/SpAbstractTreePresenter.extension.st b/src/Spec2-Commander2/SpAbstractTreePresenter.extension.st new file mode 100644 index 00000000..bb2ff41a --- /dev/null +++ b/src/Spec2-Commander2/SpAbstractTreePresenter.extension.st @@ -0,0 +1,6 @@ +Extension { #name : 'SpAbstractTreePresenter' } + +{ #category : '*Spec2-Commander2' } +SpAbstractTreePresenter >> contextMenuFromCommandsGroup: aValuable [ + self contextMenu: [ aValuable value beRoot asMenuPresenter ] +] From 19ef655a427ecad6e92e3e6aa03ceb743b8227c6 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 14:38:22 +0200 Subject: [PATCH 33/58] add method stubs (not doing anything for the moment) --- .../SpMorphicLabelAdapter.class.st | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Spec2-Adapters-Morphic/SpMorphicLabelAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicLabelAdapter.class.st index 0028f51e..910a39de 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicLabelAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicLabelAdapter.class.st @@ -54,10 +54,27 @@ SpMorphicLabelAdapter >> applyStyle: aMorph [ ] +{ #category : 'accessing' } +SpMorphicLabelAdapter >> beJustifyCenter [ +] + +{ #category : 'accessing' } +SpMorphicLabelAdapter >> beJustifyLeft [ + +] + +{ #category : 'accessing' } +SpMorphicLabelAdapter >> beJustifyRight [ +] + +{ #category : 'accessing' } +SpMorphicLabelAdapter >> beWrap [ +] + { #category : 'factory' } SpMorphicLabelAdapter >> buildWidget [ - | label | + label := LabelMorph new model: self. label getEnabledSelector: #enabled; From d120146f64d0ac946e04659242f3b424e7e025b2 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 14:38:48 +0200 Subject: [PATCH 34/58] added for polymorphism for toolbars --- .../SpMorphicDropListAdapter.class.st | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Spec2-Adapters-Morphic/SpMorphicDropListAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicDropListAdapter.class.st index fccd4853..d6ef35a5 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicDropListAdapter.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicDropListAdapter.class.st @@ -88,6 +88,12 @@ SpMorphicDropListAdapter >> setIndex: anIndex [ self presenter selectIndex: anIndex ] +{ #category : 'accessing' } +SpMorphicDropListAdapter >> styleName: aString [ + + "for compatibility with tool buttons, but not used at the moment" +] + { #category : 'factory' } SpMorphicDropListAdapter >> verifyInitialStatus [ From 4cd5ab01b0df8f54bb2457705059c3f5a6dfa50f Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 21 Jun 2024 14:39:19 +0200 Subject: [PATCH 35/58] missing methods on the easy lists --- src/Spec2-ListView/SpEasyColumnViewPresenter.class.st | 6 ++++++ src/Spec2-ListView/SpTreeColumnViewPresenter.class.st | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st index cb9cd9d1..70267266 100644 --- a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st @@ -61,6 +61,12 @@ SpEasyColumnViewPresenter >> beResizable [ contentView beResizable ] +{ #category : 'private' } +SpEasyColumnViewPresenter >> displayValueFor: aImage [ + + ^ contentView displayValueFor: aImage +] + { #category : 'api' } SpEasyColumnViewPresenter >> hideColumnHeaders [ diff --git a/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st index be4635e0..64342572 100644 --- a/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st @@ -206,6 +206,12 @@ SpTreeColumnViewPresenter >> registerActions [ action: [ self showContextMenu ] ] ] +{ #category : 'private' } +SpTreeColumnViewPresenter >> showContextMenu [ + + self withAdapterDo: [ :anAdapter | anAdapter showContextMenu ] +] + { #category : 'api - events' } SpTreeColumnViewPresenter >> whenColumnsChangedDo: aBlock [ "Inform when columns have changed. From a7e2a90ca89d4da820cf7e3e569e86ab2e49bd3e Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Mon, 24 Jun 2024 14:19:45 +0200 Subject: [PATCH 36/58] add SpFileDialog builder to be able to execute some dialogs without an infinite family of selectors --- .../SpMorphicBackend.class.st | 64 +++++++-- src/Spec2-Core/SpApplicationBackend.class.st | 12 +- src/Spec2-Dialogs/SpApplication.extension.st | 15 +- src/Spec2-Dialogs/SpFileDialog.class.st | 133 ++++++++++++++++++ 4 files changed, 205 insertions(+), 19 deletions(-) create mode 100644 src/Spec2-Dialogs/SpFileDialog.class.st diff --git a/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st b/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st index 3b347afc..ffaaf3e4 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st @@ -33,6 +33,35 @@ SpMorphicBackend >> defer: aBlock [ UIManager default defer: aBlock ] +{ #category : 'private - dialogs' } +SpMorphicBackend >> executeOpenDirectoryDialog: aFileDialog [ + + ^ StOpenDirectoryPresenter new + defaultFolder: (aFileDialog path ifNil: [ StFileSystemModel defaultDirectory ]); + title: (aFileDialog title ifNil: [ 'Choose Directory' translated ]); + openModal; + selectedEntry +] + +{ #category : 'private - dialogs' } +SpMorphicBackend >> executeOpenFileDialog: aFileDialog [ + | dialog | + + dialog := self newFileDialogFor: aFileDialog. + ^ dialog openModal answer + ifNotNil: [ :aString | aString asFileReference ] +] + +{ #category : 'private - dialogs' } +SpMorphicBackend >> executeSaveFileDialog: aFileDialog [ + | dialog | + + dialog := self newFileDialogFor: aFileDialog. + dialog answerSaveFile. + ^ dialog openModal answer + ifNotNil: [ :aString | aString asFileReference ] +] + { #category : 'deferred message' } SpMorphicBackend >> forceDefer: aBlock [ @@ -48,6 +77,25 @@ SpMorphicBackend >> inform: aString [ contents: aString ] +{ #category : 'private - dialogs' } +SpMorphicBackend >> newFileDialogFor: aFileDialog [ + | dialog | + + dialog := FileDialogWindow basicNew + previewType: false; + initialize; + title: (aFileDialog title ifNil: [ 'Select File...' ]); + answerPathName. + + aFileDialog filters ifNotEmpty: [ :filters | + dialog validExtensions: filters ]. + aFileDialog path ifNotNil: [ :path | + dialog fileNameText: path path fullName. + dialog selectPath: path fullName ]. + + ^ dialog +] + { #category : 'private - notifying' } SpMorphicBackend >> notifyError: aSpecNotification [ @@ -67,18 +115,12 @@ SpMorphicBackend >> notifyInfo: aSpecNotification [ ] { #category : 'ui - dialogs' } -SpMorphicBackend >> selectDirectoryTitle: aString [ - - ^ UIManager default chooseDirectory: aString path: '' -] - -{ #category : 'ui - dialogs' } -SpMorphicBackend >> selectFileTitle: aString [ +SpMorphicBackend >> openFileDialog: aFileDialog [ - ^ UIManager default - chooseExistingFileReference: aString - extensions: nil - path: '' + aFileDialog isOpenFile ifTrue: [ ^ self executeOpenFileDialog: aFileDialog ]. + aFileDialog isOpenDirectory ifTrue: [ ^ self executeOpenDirectoryDialog: aFileDialog ]. + + ^ self executeSaveFileDialog: aFileDialog ] { #category : 'display' } diff --git a/src/Spec2-Core/SpApplicationBackend.class.st b/src/Spec2-Core/SpApplicationBackend.class.st index 840ecab3..430be7a8 100644 --- a/src/Spec2-Core/SpApplicationBackend.class.st +++ b/src/Spec2-Core/SpApplicationBackend.class.st @@ -80,16 +80,16 @@ SpApplicationBackend >> notifyInfo: aSpecNotification [ self subclassResponsibility ] -{ #category : 'initialization' } -SpApplicationBackend >> resetAdapterBindings [ +{ #category : 'ui - dialogs' } +SpApplicationBackend >> openFileDialog: aFileDialog [ - adapterBindings := self adapterBindingsClass new + self subclassResponsibility ] -{ #category : 'ui - dialogs' } -SpApplicationBackend >> selectFileTitle: aString [ +{ #category : 'initialization' } +SpApplicationBackend >> resetAdapterBindings [ - self subclassResponsibility + adapterBindings := self adapterBindingsClass new ] { #category : 'ui' } diff --git a/src/Spec2-Dialogs/SpApplication.extension.st b/src/Spec2-Dialogs/SpApplication.extension.st index b179a566..28b9c25e 100644 --- a/src/Spec2-Dialogs/SpApplication.extension.st +++ b/src/Spec2-Dialogs/SpApplication.extension.st @@ -80,6 +80,12 @@ SpApplication >> newJobList [ ^ SpJobListPresenter newApplication: self ] +{ #category : '*Spec2-Dialogs' } +SpApplication >> newOpenFile [ + + ^ SpFileDialog newApplication: self +] + { #category : '*Spec2-Dialogs' } SpApplication >> newRequest [ @@ -119,11 +125,16 @@ SpApplication >> notify: aString [ { #category : '*Spec2-Dialogs' } SpApplication >> selectDirectoryTitle: aString [ - ^ self backend selectDirectoryTitle: aString + ^ self newOpenFile + title: aString; + beOpenDirectory; + openModal ] { #category : '*Spec2-Dialogs' } SpApplication >> selectFileTitle: aString [ - ^ self backend selectFileTitle: aString + ^ self newOpenFile + title: aString; + openModal ] diff --git a/src/Spec2-Dialogs/SpFileDialog.class.st b/src/Spec2-Dialogs/SpFileDialog.class.st new file mode 100644 index 00000000..b9310343 --- /dev/null +++ b/src/Spec2-Dialogs/SpFileDialog.class.st @@ -0,0 +1,133 @@ +" +Wrapper to show the select or save file/folder dialogs. +Unlike regular presenters, this object will delegate directly to the system file dialog (when available). + +As main vocabulary, it understands `openModal`, to provide a polymorphic entry point. +" +Class { + #name : 'SpFileDialog', + #superclass : 'Object', + #instVars : [ + 'title', + 'filters', + 'path', + 'application', + 'action' + ], + #category : 'Spec2-Dialogs', + #package : 'Spec2-Dialogs' +} + +{ #category : 'instance creation' } +SpFileDialog class >> newApplication: anApplication [ + + ^ self new + application: anApplication; + yourself +] + +{ #category : 'api' } +SpFileDialog >> addFilter: aString [ + + filters := self filters copyWith: aString +] + +{ #category : 'accessing' } +SpFileDialog >> application [ + + ^ application +] + +{ #category : 'accessing' } +SpFileDialog >> application: anApplication [ + + application := anApplication +] + +{ #category : 'api' } +SpFileDialog >> beOpenDirectory [ + + action := #openDirectory +] + +{ #category : 'api' } +SpFileDialog >> beOpenFile [ + + action := #openFile +] + +{ #category : 'api' } +SpFileDialog >> beSaveFile [ + + action := #saveFile +] + +{ #category : 'api' } +SpFileDialog >> filters [ + + ^ filters ifNil: [ #() ] +] + +{ #category : 'api' } +SpFileDialog >> filters: aCollectionOfStrings [ + "Receives a collection of file extentions. + e.g. #('jpg' 'png')" + + filters := aCollectionOfStrings +] + +{ #category : 'initialization' } +SpFileDialog >> initialize [ + + super initialize. + self beOpenFile +] + +{ #category : 'testing' } +SpFileDialog >> isOpenDirectory [ + + ^ action = #openDirectory +] + +{ #category : 'testing' } +SpFileDialog >> isOpenFile [ + + ^ action = #openFile +] + +{ #category : 'testing' } +SpFileDialog >> isSaveFile [ + + ^ action = #saveFile +] + +{ #category : 'api - showing' } +SpFileDialog >> openModal [ + + ^ self application backend openFileDialog: self +] + +{ #category : 'api' } +SpFileDialog >> path [ + + ^ path +] + +{ #category : 'api' } +SpFileDialog >> path: aStringOrFileReference [ + "initial value of the dialog" + + path := aStringOrFileReference asFileReference +] + +{ #category : 'api' } +SpFileDialog >> title [ + + ^ title +] + +{ #category : 'api' } +SpFileDialog >> title: aTitle [ + + title := aTitle +] From ca04ee1c1535c7784fe6ce6dcc73105b01ffe35e Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 28 Jun 2024 09:49:06 +0200 Subject: [PATCH 37/58] restore category --- src/Spec2-Core/SpAbstractTreePresenter.class.st | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Spec2-Core/SpAbstractTreePresenter.class.st b/src/Spec2-Core/SpAbstractTreePresenter.class.st index 238aa005..b13bbbb2 100644 --- a/src/Spec2-Core/SpAbstractTreePresenter.class.st +++ b/src/Spec2-Core/SpAbstractTreePresenter.class.st @@ -47,7 +47,7 @@ SpAbstractTreePresenter >> activateOnSingleClick [ activateOnSingleClick := true ] -{ #category : 'as yet unclassified' } +{ #category : 'api' } SpAbstractTreePresenter >> activatesOnDoubleClick [ "Answer true if activation event is triggered on double click" @@ -58,7 +58,7 @@ SpAbstractTreePresenter >> activatesOnDoubleClick [ ^ activateOnSingleClick not ] -{ #category : 'as yet unclassified' } +{ #category : 'api' } SpAbstractTreePresenter >> activatesOnSingleClick [ "Answer true if activation event is triggered on single click" From a26663c00fec6292dafa64cd30b9a674ef4daf60 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 28 Jun 2024 09:49:26 +0200 Subject: [PATCH 38/58] do not use directly --- src/Spec2-Core/SpEditableListPresenter.class.st | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Spec2-Core/SpEditableListPresenter.class.st b/src/Spec2-Core/SpEditableListPresenter.class.st index 134e3a8b..b0821c02 100644 --- a/src/Spec2-Core/SpEditableListPresenter.class.st +++ b/src/Spec2-Core/SpEditableListPresenter.class.st @@ -149,7 +149,7 @@ SpEditableListPresenter >> initializeDialogWindow: aWindow [ SpEditableListPresenter >> initializePresenters [ label := self newLabel. - list := self newEasyListView. + list := self newList. addButton := self newButton. removeButton := self newButton. upButton := self newButton. From 3759362bc7e78a3a1ea1d35e10ec3928e679200f Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 28 Jun 2024 09:51:40 +0200 Subject: [PATCH 39/58] more categorization --- src/Spec2-Core/SpJobListPresenter.class.st | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Spec2-Core/SpJobListPresenter.class.st b/src/Spec2-Core/SpJobListPresenter.class.st index d18cb74e..1cbfebdf 100644 --- a/src/Spec2-Core/SpJobListPresenter.class.st +++ b/src/Spec2-Core/SpJobListPresenter.class.st @@ -120,6 +120,12 @@ SpJobListPresenter >> jobEnd: ann [ self removeJobPresenter: ann job ] ] +{ #category : 'initialization' } +SpJobListPresenter >> jobPresenterHeight [ + + ^ 80 +] + { #category : 'private - events' } SpJobListPresenter >> jobStart: ann [ From 28b9d4dc9808ac873a1da8a5fec388cac5eebf91 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 28 Jun 2024 10:13:07 +0200 Subject: [PATCH 40/58] recategorize --- .../SpMorphicBackend.class.st | 36 +++++++++++++++++ src/Spec2-Core/SpApplicationBackend.class.st | 38 ++++++++++++++++++ .../SpApplicationBackend.extension.st | 39 ------------------- .../SpMorphicBackend.extension.st | 37 ------------------ .../SpecGtkBackend.extension.st | 37 ------------------ 5 files changed, 74 insertions(+), 113 deletions(-) delete mode 100644 src/Spec2-ListView/SpApplicationBackend.extension.st delete mode 100644 src/Spec2-ListView/SpMorphicBackend.extension.st delete mode 100644 src/Spec2-ListView/SpecGtkBackend.extension.st diff --git a/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st b/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st index ffaaf3e4..a9bc7216 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st @@ -33,6 +33,12 @@ SpMorphicBackend >> defer: aBlock [ UIManager default defer: aBlock ] +{ #category : 'accessing' } +SpMorphicBackend >> dropListClass [ + + ^ SpDropListPresenter +] + { #category : 'private - dialogs' } SpMorphicBackend >> executeOpenDirectoryDialog: aFileDialog [ @@ -77,6 +83,12 @@ SpMorphicBackend >> inform: aString [ contents: aString ] +{ #category : 'accessing' } +SpMorphicBackend >> listClass [ + + ^ SpListPresenter +] + { #category : 'private - dialogs' } SpMorphicBackend >> newFileDialogFor: aFileDialog [ | dialog | @@ -128,3 +140,27 @@ SpMorphicBackend >> showWaitCursorWhile: aBlock inApplication: anApplication [ Cursor wait showWhile: aBlock ] + +{ #category : 'accessing' } +SpMorphicBackend >> switchClass [ + + ^ SpCheckBoxPresenter +] + +{ #category : 'accessing' } +SpMorphicBackend >> tableClass [ + + ^ SpTablePresenter +] + +{ #category : 'accessing' } +SpMorphicBackend >> treeClass [ + + ^ SpTreePresenter +] + +{ #category : 'accessing' } +SpMorphicBackend >> treeTableClass [ + + ^ SpTreeTablePresenter +] diff --git a/src/Spec2-Core/SpApplicationBackend.class.st b/src/Spec2-Core/SpApplicationBackend.class.st index 430be7a8..498c0c8a 100644 --- a/src/Spec2-Core/SpApplicationBackend.class.st +++ b/src/Spec2-Core/SpApplicationBackend.class.st @@ -49,6 +49,12 @@ SpApplicationBackend >> defaultConfigurationFor: anApplication [ ^ self subclassResponsibility ] +{ #category : 'accessing' } +SpApplicationBackend >> dropListClass [ + + self subclassResponsibility +] + { #category : 'ui - dialogs' } SpApplicationBackend >> inform: aString [ @@ -62,6 +68,13 @@ SpApplicationBackend >> initialize [ self resetAdapterBindings ] +{ #category : 'accessing' } +SpApplicationBackend >> listClass [ + + self subclassResponsibility + +] + { #category : 'accessing' } SpApplicationBackend >> name [ @@ -97,3 +110,28 @@ SpApplicationBackend >> showWaitCursorWhile: aBlock inApplication: anApplication self subclassResponsibility ] + +{ #category : 'accessing' } +SpApplicationBackend >> switchClass [ + + self subclassResponsibility +] + +{ #category : 'accessing' } +SpApplicationBackend >> tableClass [ + + self subclassResponsibility +] + +{ #category : 'accessing' } +SpApplicationBackend >> treeClass [ + + self subclassResponsibility + +] + +{ #category : 'accessing' } +SpApplicationBackend >> treeTableClass [ + + self subclassResponsibility +] diff --git a/src/Spec2-ListView/SpApplicationBackend.extension.st b/src/Spec2-ListView/SpApplicationBackend.extension.st deleted file mode 100644 index 77aab870..00000000 --- a/src/Spec2-ListView/SpApplicationBackend.extension.st +++ /dev/null @@ -1,39 +0,0 @@ -Extension { #name : 'SpApplicationBackend' } - -{ #category : '*Spec2-ListView' } -SpApplicationBackend >> dropListClass [ - - self subclassResponsibility -] - -{ #category : '*Spec2-ListView' } -SpApplicationBackend >> listClass [ - - self subclassResponsibility - -] - -{ #category : '*Spec2-ListView' } -SpApplicationBackend >> switchClass [ - - self subclassResponsibility -] - -{ #category : '*Spec2-ListView' } -SpApplicationBackend >> tableClass [ - - self subclassResponsibility -] - -{ #category : '*Spec2-ListView' } -SpApplicationBackend >> treeClass [ - - self subclassResponsibility - -] - -{ #category : '*Spec2-ListView' } -SpApplicationBackend >> treeTableClass [ - - self subclassResponsibility -] diff --git a/src/Spec2-ListView/SpMorphicBackend.extension.st b/src/Spec2-ListView/SpMorphicBackend.extension.st deleted file mode 100644 index eaa81a88..00000000 --- a/src/Spec2-ListView/SpMorphicBackend.extension.st +++ /dev/null @@ -1,37 +0,0 @@ -Extension { #name : 'SpMorphicBackend' } - -{ #category : '*Spec2-ListView' } -SpMorphicBackend >> dropListClass [ - - ^ SpDropListPresenter -] - -{ #category : '*Spec2-ListView' } -SpMorphicBackend >> listClass [ - - ^ SpListPresenter -] - -{ #category : '*Spec2-ListView' } -SpMorphicBackend >> switchClass [ - - ^ SpCheckBoxPresenter -] - -{ #category : '*Spec2-ListView' } -SpMorphicBackend >> tableClass [ - - ^ SpTablePresenter -] - -{ #category : '*Spec2-ListView' } -SpMorphicBackend >> treeClass [ - - ^ SpTreePresenter -] - -{ #category : '*Spec2-ListView' } -SpMorphicBackend >> treeTableClass [ - - ^ SpTreeTablePresenter -] diff --git a/src/Spec2-ListView/SpecGtkBackend.extension.st b/src/Spec2-ListView/SpecGtkBackend.extension.st deleted file mode 100644 index 34c4cc2b..00000000 --- a/src/Spec2-ListView/SpecGtkBackend.extension.st +++ /dev/null @@ -1,37 +0,0 @@ -Extension { #name : 'SpecGtkBackend' } - -{ #category : '*Spec2-ListView' } -SpecGtkBackend >> dropListClass [ - - ^ SpDropDownPresenter -] - -{ #category : '*Spec2-ListView' } -SpecGtkBackend >> listClass [ - - ^ SpEasyListViewPresenter -] - -{ #category : '*Spec2-ListView' } -SpecGtkBackend >> switchClass [ - - ^ SpSwitchPresenter -] - -{ #category : '*Spec2-ListView' } -SpecGtkBackend >> tableClass [ - - ^ SpEasyColumnViewPresenter -] - -{ #category : '*Spec2-ListView' } -SpecGtkBackend >> treeClass [ - - ^ SpEasyTreeListViewPresenter -] - -{ #category : '*Spec2-ListView' } -SpecGtkBackend >> treeTableClass [ - - ^ SpEasyTreeColumnViewPresenter -] From 715810bb22c9a735d159841129f35f0fb1e19ab3 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 28 Jun 2024 10:43:11 +0200 Subject: [PATCH 41/58] in factm switch can have its own adapter and it works (but it stills generates a checkbox) --- src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st | 6 ------ src/Spec2-Adapters-Morphic/SpMorphicSwitchAdapter.class.st | 7 +++++++ src/Spec2-Core/SpApplicationBackend.class.st | 6 ------ src/Spec2-Core/SpTPresenterBuilder.trait.st | 2 +- 4 files changed, 8 insertions(+), 13 deletions(-) create mode 100644 src/Spec2-Adapters-Morphic/SpMorphicSwitchAdapter.class.st diff --git a/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st b/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st index a9bc7216..791e6115 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st @@ -141,12 +141,6 @@ SpMorphicBackend >> showWaitCursorWhile: aBlock inApplication: anApplication [ Cursor wait showWhile: aBlock ] -{ #category : 'accessing' } -SpMorphicBackend >> switchClass [ - - ^ SpCheckBoxPresenter -] - { #category : 'accessing' } SpMorphicBackend >> tableClass [ diff --git a/src/Spec2-Adapters-Morphic/SpMorphicSwitchAdapter.class.st b/src/Spec2-Adapters-Morphic/SpMorphicSwitchAdapter.class.st new file mode 100644 index 00000000..01486be9 --- /dev/null +++ b/src/Spec2-Adapters-Morphic/SpMorphicSwitchAdapter.class.st @@ -0,0 +1,7 @@ +Class { + #name : 'SpMorphicSwitchAdapter', + #superclass : 'SpMorphicCheckBoxAdapter', + #category : 'Spec2-Adapters-Morphic-Base', + #package : 'Spec2-Adapters-Morphic', + #tag : 'Base' +} diff --git a/src/Spec2-Core/SpApplicationBackend.class.st b/src/Spec2-Core/SpApplicationBackend.class.st index 498c0c8a..68e3b7ec 100644 --- a/src/Spec2-Core/SpApplicationBackend.class.st +++ b/src/Spec2-Core/SpApplicationBackend.class.st @@ -111,12 +111,6 @@ SpApplicationBackend >> showWaitCursorWhile: aBlock inApplication: anApplication self subclassResponsibility ] -{ #category : 'accessing' } -SpApplicationBackend >> switchClass [ - - self subclassResponsibility -] - { #category : 'accessing' } SpApplicationBackend >> tableClass [ diff --git a/src/Spec2-Core/SpTPresenterBuilder.trait.st b/src/Spec2-Core/SpTPresenterBuilder.trait.st index 2b001cc3..0d442301 100644 --- a/src/Spec2-Core/SpTPresenterBuilder.trait.st +++ b/src/Spec2-Core/SpTPresenterBuilder.trait.st @@ -257,7 +257,7 @@ SpTPresenterBuilder >> newStatusBar [ { #category : 'scripting - widgets' } SpTPresenterBuilder >> newSwitch [ - ^ self instantiate: self application backend switchClass + ^ self instantiate: SpSwitchPresenter ] { #category : 'scripting - widgets' } From 096ff67531946f72aae1a0aba8dfb40de2a47991 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 28 Jun 2024 13:55:42 +0200 Subject: [PATCH 42/58] fixed unclassified methods --- src/Spec2-Core/SpAbstractTreePresenter.class.st | 10 +++++----- src/Spec2-ListView/SpAbstractEasyPresenter.class.st | 5 +++-- src/Spec2-ListView/SpColumnViewPresenter.class.st | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Spec2-Core/SpAbstractTreePresenter.class.st b/src/Spec2-Core/SpAbstractTreePresenter.class.st index b13bbbb2..46cb1529 100644 --- a/src/Spec2-Core/SpAbstractTreePresenter.class.st +++ b/src/Spec2-Core/SpAbstractTreePresenter.class.st @@ -25,7 +25,7 @@ SpAbstractTreePresenter class >> isAbstract [ ^ super isAbstract or: [ self = SpAbstractTreePresenter ] ] -{ #category : 'as yet unclassified' } +{ #category : 'api' } SpAbstractTreePresenter >> activateOnDoubleClick [ "Configure the list to trigger activation on double click. An element on a list can be 'activated', meaning it will trigger an event to execute an @@ -36,7 +36,7 @@ SpAbstractTreePresenter >> activateOnDoubleClick [ activateOnSingleClick := false ] -{ #category : 'as yet unclassified' } +{ #category : 'api' } SpAbstractTreePresenter >> activateOnSingleClick [ "Configure the list to trigger activation on single click. An element on a list can be 'activated', meaning it will trigger an event to execute an @@ -69,21 +69,21 @@ SpAbstractTreePresenter >> activatesOnSingleClick [ ^ activateOnSingleClick ] -{ #category : 'as yet unclassified' } +{ #category : 'api' } SpAbstractTreePresenter >> beMultipleSelection [ "Enable multiple selection." self selectionMode: (SpTreeMultipleSelectionMode on: self) ] -{ #category : 'as yet unclassified' } +{ #category : 'api' } SpAbstractTreePresenter >> beSingleSelection [ "Enable single selection (this is the default)." self selectionMode: (SpTreeSingleSelectionMode on: self) ] -{ #category : 'as yet unclassified' } +{ #category : 'api' } SpAbstractTreePresenter >> children [ ^ childrenBlock diff --git a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st index c3295a46..34717176 100644 --- a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st @@ -90,10 +90,11 @@ SpAbstractEasyPresenter >> connectPresenters [ whenFocusReceivedDo: [ :event | searchInput hide ] ] -{ #category : 'as yet unclassified' } +{ #category : 'api - actions' } SpAbstractEasyPresenter >> contextMenuFromCommandsGroup: aValuable [ - self flag: #TODO + self flag: #TODO. + "this is not really to be used... we have now actionGroup: :P" ] { #category : 'private' } diff --git a/src/Spec2-ListView/SpColumnViewPresenter.class.st b/src/Spec2-ListView/SpColumnViewPresenter.class.st index 84e8160a..af545f7a 100644 --- a/src/Spec2-ListView/SpColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpColumnViewPresenter.class.st @@ -106,7 +106,7 @@ SpColumnViewPresenter >> addColumns: aCollection [ aCollection do: [ :each | self addColumn: each ] ] -{ #category : 'api' } +{ #category : 'as yet unclassified' } SpColumnViewPresenter >> alternateRowsColor [ "Will alternate Rows color for a better reading: one row lighter, the next row darker. NOTE: Behavior in different backends may be slightly different." From 0b2cf274d0f54ea1384a559de6d031cdf66fa7d8 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 28 Jun 2024 14:10:19 +0200 Subject: [PATCH 43/58] restore lost classifications --- .../SpAbstractTreePresenter.class.st | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Spec2-Core/SpAbstractTreePresenter.class.st b/src/Spec2-Core/SpAbstractTreePresenter.class.st index 46cb1529..788d83fe 100644 --- a/src/Spec2-Core/SpAbstractTreePresenter.class.st +++ b/src/Spec2-Core/SpAbstractTreePresenter.class.st @@ -98,13 +98,13 @@ SpAbstractTreePresenter >> children: aBlock [ childrenBlock := aBlock ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> childrenFor: anObject [ ^ self children value: anObject ] -{ #category : 'as yet unclassified' } +{ #category : 'simulation' } SpAbstractTreePresenter >> clickAtPath: aPath [ self selectPaths: { aPath }. @@ -130,7 +130,7 @@ SpAbstractTreePresenter >> collapsePath: aPath [ anAdapter collapsePath: aPath ] ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> disableActivationDuring: aBlock [ | oldActivate | @@ -140,7 +140,7 @@ SpAbstractTreePresenter >> disableActivationDuring: aBlock [ activationBlock := oldActivate ] ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> doActivateAtPath: aPath [ "Activate only if there is an item at that position" @@ -151,7 +151,7 @@ SpAbstractTreePresenter >> doActivateAtPath: aPath [ yourself) ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> doActivateSelected [ "Activate only if there is an item at that position" | selectedPath | @@ -207,21 +207,21 @@ SpAbstractTreePresenter >> initialize [ self withScrollBars ] -{ #category : 'as yet unclassified' } +{ #category : 'testing' } SpAbstractTreePresenter >> isActiveOnDoubleClick [ "Answer true if activation event is triggered on double click" ^ activateOnSingleClick not ] -{ #category : 'as yet unclassified' } +{ #category : 'testing' } SpAbstractTreePresenter >> isActiveOnSingleClick [ "Answer true if activation event is triggered on single click" ^ activateOnSingleClick ] -{ #category : 'as yet unclassified' } +{ #category : 'testing' } SpAbstractTreePresenter >> isExpanded: aPath [ self withAdapterDo: [ :anAdapter | @@ -230,7 +230,7 @@ SpAbstractTreePresenter >> isExpanded: aPath [ ^ false ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> itemAt: index of: anArray then: path [ "dives into elements of tree to find the one that corresponds to path" | element | @@ -246,7 +246,7 @@ SpAbstractTreePresenter >> itemAt: index of: anArray then: path [ element ] ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> itemAtPath: anArray [ self withAdapterDo: [ :anAdapter | @@ -258,7 +258,7 @@ SpAbstractTreePresenter >> itemAtPath: anArray [ then: anArray allButFirst ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> itemAtPath: anArray ifAbsent: aBlock [ ^ [ self itemAtPath: anArray ] on: SubscriptOutOfBounds @@ -272,7 +272,7 @@ SpAbstractTreePresenter >> items: aCollection [ self roots: aCollection ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> pathIndexOf: anArrayOfElements [ ^ self @@ -280,7 +280,7 @@ SpAbstractTreePresenter >> pathIndexOf: anArrayOfElements [ in: self roots ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> pathIndexOf: pathArray in: aCollection [ | pathElement | @@ -293,7 +293,7 @@ SpAbstractTreePresenter >> pathIndexOf: pathArray in: aCollection [ ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> pathItemOf: aPath [ "answer an array of items following a path. e.g. #(1 2 3) = { item1. item2. item3 }" @@ -303,7 +303,7 @@ SpAbstractTreePresenter >> pathItemOf: aPath [ in: self roots ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> pathItemOf: pathArray in: aCollection [ | pathElement | @@ -348,7 +348,7 @@ SpAbstractTreePresenter >> roots: aCollection [ self selection clearSelection ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> searchValueOf: item [ ^ item asString @@ -458,7 +458,7 @@ SpAbstractTreePresenter >> selectionMode [ ^ selectionMode ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> selectionMode: aMode [ selectionMode ifNotNil: [ @@ -502,16 +502,16 @@ SpAbstractTreePresenter >> updateRootsKeepingSelection: aCollection [ self selectPaths: (selectedPaths collect: [ :each | self pathIndexOf: each ]) ] ] ] -{ #category : 'as yet unclassified' } +{ #category : 'private' } SpAbstractTreePresenter >> verticalAlignment [ ^ verticalAlignment ] -{ #category : 'as yet unclassified' } +{ #category : 'api - events' } SpAbstractTreePresenter >> whenActivatedDo: aBlock [ "Inform when an element has been 'activated'. `aBlock` receives one argument (a selection object, see `SpAbstractSelectionMode`)" - + activationBlock := aBlock ] From 756d4ed581bfc8387046e9a35c5ec3addc0703e5 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 28 Jun 2024 14:24:06 +0200 Subject: [PATCH 44/58] again --- src/Spec2-Core/SpAbstractTreePresenter.class.st | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Spec2-Core/SpAbstractTreePresenter.class.st b/src/Spec2-Core/SpAbstractTreePresenter.class.st index 788d83fe..1005d9cc 100644 --- a/src/Spec2-Core/SpAbstractTreePresenter.class.st +++ b/src/Spec2-Core/SpAbstractTreePresenter.class.st @@ -164,10 +164,10 @@ SpAbstractTreePresenter >> doActivateSelected [ yourself) ] -{ #category : 'as yet unclassified' } +{ #category : 'simulation' } SpAbstractTreePresenter >> doubleClickAtPath: aPath [ + self selectPath: aPath. - activateOnSingleClick ifTrue: [ ^ self ]. self doActivateAtPath: aPath ] From 80d63ce57e63260fd653c2336f71fe14abfd2640 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Mon, 1 Jul 2024 12:33:04 +0200 Subject: [PATCH 45/58] moved here From e8abba0763c596ac3a9069e862af40292935eb23 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 2 Jul 2024 13:44:18 +0200 Subject: [PATCH 46/58] fix --- src/Spec2-Core/SpEditableListPresenter.class.st | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Spec2-Core/SpEditableListPresenter.class.st b/src/Spec2-Core/SpEditableListPresenter.class.st index b0821c02..20828752 100644 --- a/src/Spec2-Core/SpEditableListPresenter.class.st +++ b/src/Spec2-Core/SpEditableListPresenter.class.st @@ -234,9 +234,9 @@ SpEditableListPresenter >> moveElementAt: index to: newIndex [ SpEditableListPresenter >> newList [ "Default list collection is an Array. As this presenter aims to add / remove items from the list, we need a growable collection" - ^ (self instantiate: SpListPresenter) - items: OrderedCollection new; - yourself + ^ super newList + items: OrderedCollection new; + yourself ] { #category : 'api' } From e4a677a3944ef0b3e0fd432e6de6043863c79aa7 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 2 Jul 2024 13:44:38 +0200 Subject: [PATCH 47/58] re-added --- .../SpAbstractTreePresenter.extension.st | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/Spec2-Transmission/SpAbstractTreePresenter.extension.st diff --git a/src/Spec2-Transmission/SpAbstractTreePresenter.extension.st b/src/Spec2-Transmission/SpAbstractTreePresenter.extension.st new file mode 100644 index 00000000..c82c662d --- /dev/null +++ b/src/Spec2-Transmission/SpAbstractTreePresenter.extension.st @@ -0,0 +1,31 @@ +Extension { #name : 'SpAbstractTreePresenter' } + +{ #category : '*Spec2-Transmission' } +SpAbstractTreePresenter >> defaultInputPort [ + + ^ self inputRootsPort +] + +{ #category : '*Spec2-Transmission' } +SpAbstractTreePresenter >> defaultOutputPort [ + + ^ self outputSelectionPort +] + +{ #category : '*Spec2-Transmission' } +SpAbstractTreePresenter >> inputRootsPort [ + + ^ SpRootsPort newPresenter: self +] + +{ #category : '*Spec2-Transmission' } +SpAbstractTreePresenter >> outputActivationPort [ + + ^ SpActivationPort newPresenter: self +] + +{ #category : '*Spec2-Transmission' } +SpAbstractTreePresenter >> outputSelectionPort [ + + ^ SpSelectionPort newPresenter: self +] From 66d27dc23b87b93cb83056e18a246e0e516b19a4 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 2 Jul 2024 15:55:14 +0200 Subject: [PATCH 48/58] fix newar window : it cannot be root, since windows can be nested. --- src/Spec2-Core/SpAbstractPresenter.class.st | 22 ++++++++++++--------- src/Spec2-Core/SpWindowPresenter.class.st | 6 ++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Spec2-Core/SpAbstractPresenter.class.st b/src/Spec2-Core/SpAbstractPresenter.class.st index a5bd8695..df2d016c 100644 --- a/src/Spec2-Core/SpAbstractPresenter.class.st +++ b/src/Spec2-Core/SpAbstractPresenter.class.st @@ -295,7 +295,7 @@ SpAbstractPresenter >> hasOwner [ { #category : 'testing' } SpAbstractPresenter >> hasWindow [ - ^ self root isWindowPresenter + ^ self nearWindow notNil ] { #category : 'initialization' } @@ -352,6 +352,12 @@ SpAbstractPresenter >> layout [ self subclassResponsibility ] +{ #category : 'private' } +SpAbstractPresenter >> nearWindow [ + + ^ self owner ifNotNil: [ :anOwner | anOwner nearWindow ] +] + { #category : 'accessing' } SpAbstractPresenter >> needRebuild [ @@ -531,24 +537,22 @@ SpAbstractPresenter >> whenWillBeBuiltDo: aBlock [ { #category : 'accessing' } SpAbstractPresenter >> window [ - "Answer window containing this composition." + "Answer window containing this composition (windows can be nested, so we + need to answer the closest one)." - ^ self hasWindow - ifTrue: [ self root ] - ifFalse: [ nil ] + ^ self nearWindow ] { #category : 'private - utilities' } SpAbstractPresenter >> withAdapterDo: aValuable [ "a convenience method to avoid verify by nil all the time" - ^ self adapter ifNotNil: aValuable + ^ self adapter ifNotNil: [ :anAdapter | aValuable value: anAdapter ] ] { #category : 'private - utilities' } SpAbstractPresenter >> withWindowDo: aValuable [ - self hasWindow ifFalse: [ ^ nil ]. - "Since Presenter has window, root = window" - ^ aValuable value: self root + ^ self nearWindow + ifNotNil: [ :nearWindow | aValuable value: nearWindow ] ] diff --git a/src/Spec2-Core/SpWindowPresenter.class.st b/src/Spec2-Core/SpWindowPresenter.class.st index 45a701d2..daf29d13 100644 --- a/src/Spec2-Core/SpWindowPresenter.class.st +++ b/src/Spec2-Core/SpWindowPresenter.class.st @@ -448,6 +448,12 @@ SpWindowPresenter >> moveTo: aPoint [ ] +{ #category : 'private' } +SpWindowPresenter >> nearWindow [ + + ^ self +] + { #category : 'notifying' } SpWindowPresenter >> notify: aSpecNotification [ "Receives a notification and delivers it as required" From 7e48e91e15d808106fe941556d56761aaf0b266f Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Tue, 2 Jul 2024 15:55:35 +0200 Subject: [PATCH 49/58] item can be nil, check for it --- src/Spec2-ListView/SpTableColumn.extension.st | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Spec2-ListView/SpTableColumn.extension.st b/src/Spec2-ListView/SpTableColumn.extension.st index 859410ed..a1d0a6d1 100644 --- a/src/Spec2-ListView/SpTableColumn.extension.st +++ b/src/Spec2-ListView/SpTableColumn.extension.st @@ -8,6 +8,9 @@ SpTableColumn >> asColumnViewColumn [ expand: (self width isNil and: [ self isExpandable ]); width: self width; setup: [ :aPresenter | aPresenter newLabel ]; - bind: [ :aPresenter :item | aPresenter label: (self readObject: item) asString ]; + bind: [ :aPresenter :item | + aPresenter label: (item + ifNotNil: [ (self readObject: item) asString ] + ifNil: [ '']) ]; yourself ] From baead10bc4c1d3f677049b89c86ad8531e92a048 Mon Sep 17 00:00:00 2001 From: Christophe Demarey Date: Wed, 3 Jul 2024 12:46:37 +0200 Subject: [PATCH 50/58] Add Spec2-ListView package to Core group --- src/BaselineOfSpecCore/BaselineOfSpecCore.class.st | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/BaselineOfSpecCore/BaselineOfSpecCore.class.st b/src/BaselineOfSpecCore/BaselineOfSpecCore.class.st index 1e3aa1c5..fb32cd53 100644 --- a/src/BaselineOfSpecCore/BaselineOfSpecCore.class.st +++ b/src/BaselineOfSpecCore/BaselineOfSpecCore.class.st @@ -55,13 +55,15 @@ BaselineOfSpecCore >> baseline: spec [ 'Spec2-Core' 'Spec2-Dialogs' 'Spec2-CommandLine' - 'Spec2-Adapters-Stub' + 'Spec2-Adapters-Stub' + 'Spec2-Adapters-Morphic-ListView' + 'Spec2-ListView' 'Spec2-Interactions' 'Spec2-Commander2' ). spec group: 'Code' with: #('Core' 'Spec2-Code-Commands' 'Spec2-Code' 'Spec2-Code-Diff'). spec group: 'CodeTests' with: #('Spec2-Code-Tests' 'Spec2-Code-Diff-Tests'). spec group: 'Support' with: #('Core' 'Spec2-Examples'). - spec group: 'Tests' with: #('Core' 'Spec2-Tests' 'Spec2-Commander2-Tests'). + spec group: 'Tests' with: #('Core' 'Spec2-Tests' 'Spec2-Commander2-Tests' 'Spec2-ListView-Tests'). spec group: 'SupportTests' with: #('Support'). spec group: 'Pillar' with: #('Spec2-Pillar' ). spec group: 'Base' with: #('Core' 'Support'). From 8d94b79a012e41692e015a9677ba4f0c6d2bfd66 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Wed, 3 Jul 2024 13:58:11 +0200 Subject: [PATCH 51/58] add super call --- src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st b/src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st index f8817a95..74f5c638 100644 --- a/src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st +++ b/src/Spec2-ListView-Tests/SpListViewPresenterTest.class.st @@ -22,5 +22,6 @@ SpListViewPresenterTest >> initializeTestedInstance [ { #category : 'running' } SpListViewPresenterTest >> tearDown [ - presenter withWindowDo: [ :w | w close ] + presenter withWindowDo: [ :w | w close ]. + super tearDown ] From 57d65a7b7913da2565562d4bb56dd05c2b2152c2 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Wed, 3 Jul 2024 13:58:37 +0200 Subject: [PATCH 52/58] add unselectAll method --- src/Spec2-ListView/SpEasyColumnViewPresenter.class.st | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st index 70267266..81d35872 100644 --- a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st @@ -81,6 +81,12 @@ SpEasyColumnViewPresenter >> initializePresenters [ ] +{ #category : 'api - selection' } +SpEasyColumnViewPresenter >> unselectAll [ + + contentView unselectAll +] + { #category : 'api - events' } SpEasyColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ From c7e86e4550e1674dc669c124c9837a82f84aea40 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Wed, 3 Jul 2024 14:37:27 +0200 Subject: [PATCH 53/58] categorize --- src/Spec2-ListView/SpColumnViewPresenter.class.st | 2 +- src/Spec2-ListView/SpListViewPresenter.class.st | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Spec2-ListView/SpColumnViewPresenter.class.st b/src/Spec2-ListView/SpColumnViewPresenter.class.st index af545f7a..84e8160a 100644 --- a/src/Spec2-ListView/SpColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpColumnViewPresenter.class.st @@ -106,7 +106,7 @@ SpColumnViewPresenter >> addColumns: aCollection [ aCollection do: [ :each | self addColumn: each ] ] -{ #category : 'as yet unclassified' } +{ #category : 'api' } SpColumnViewPresenter >> alternateRowsColor [ "Will alternate Rows color for a better reading: one row lighter, the next row darker. NOTE: Behavior in different backends may be slightly different." diff --git a/src/Spec2-ListView/SpListViewPresenter.class.st b/src/Spec2-ListView/SpListViewPresenter.class.st index f9d8aaac..174fee24 100644 --- a/src/Spec2-ListView/SpListViewPresenter.class.st +++ b/src/Spec2-ListView/SpListViewPresenter.class.st @@ -43,7 +43,7 @@ SpListViewPresenter class >> exampleActivateOnDoubleClick [ open ] -{ #category : 'as yet unclassified' } +{ #category : 'examples' } SpListViewPresenter class >> exampleReplaceItems [ "This example shows how to replace dynamically the list of elements." | presenter listView button items | @@ -168,7 +168,7 @@ SpListViewPresenter class >> exampleWithIconsAndMorph [ open ] -{ #category : 'as yet unclassified' } +{ #category : 'examples' } SpListViewPresenter class >> exampleWithIconsAndSelectedItem [ "This example shows how to construct a list with icons. It shows also the fact you can put any presenter inside, giving a huge power @@ -196,7 +196,7 @@ SpListViewPresenter class >> exampleWithIconsAndSelectedItem [ open ] -{ #category : 'as yet unclassified' } +{ #category : 'examples' } SpListViewPresenter class >> exampleWithIconsMultipleSelection [ "This example shows how to construct a list with multiple selection available. It shows also the fact you can put any presenter inside, giving a huge power From 84321dad93d277630e101b4f9072026c06b847c3 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 19 Jul 2024 13:56:24 +0200 Subject: [PATCH 54/58] fix alexandrie presenter --- .../SpAlexandrieMorph.class.st | 35 +++++++++++-------- .../SpMorphicAlexandrieAdapter.class.st | 18 +++++----- .../package.st | 2 +- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/Spec2-Adapters-Morphic-Alexandrie/SpAlexandrieMorph.class.st b/src/Spec2-Adapters-Morphic-Alexandrie/SpAlexandrieMorph.class.st index 8a3c2f2c..6c1a31e4 100644 --- a/src/Spec2-Adapters-Morphic-Alexandrie/SpAlexandrieMorph.class.st +++ b/src/Spec2-Adapters-Morphic-Alexandrie/SpAlexandrieMorph.class.st @@ -1,43 +1,48 @@ Class { - #name : #SpAlexandrieMorph, - #superclass : #Morph, + #name : 'SpAlexandrieMorph', + #superclass : 'Morph', #instVars : [ 'surface', 'drawBlock', 'lastExtent' ], - #category : #'Spec2-Adapters-Morphic-Alexandrie-Base' + #category : 'Spec2-Adapters-Morphic-Alexandrie-Base', + #package : 'Spec2-Adapters-Morphic-Alexandrie', + #tag : 'Base' } -{ #category : #accessing } +{ #category : 'accessing' } SpAlexandrieMorph >> drawBlock: aBlock [ drawBlock := aBlock ] -{ #category : #drawing } +{ #category : 'drawing' } SpAlexandrieMorph >> drawOn: aMorphicCanvas [ self redraw. - self surface - displayOnMorphicCanvas: aMorphicCanvas - at: bounds origin + aMorphicCanvas + image: self surface asForm + at: self position + sourceRect: (0@0 extent: self extent) + rule: 34 ] -{ #category : #drawing } +{ #category : 'drawing' } SpAlexandrieMorph >> redraw [ + | context | - self surface drawDuring: [ :canvas | - drawBlock - cull: canvas - cull: (0@0 extent: self extent) ] + context := self surface newContext. + drawBlock + cull: context + cull: (0@0 extent: self extent) ] -{ #category : #accessing } +{ #category : 'accessing' } SpAlexandrieMorph >> surface [ lastExtent = self extent ifFalse: [ surface := nil ]. ^ surface ifNil: [ lastExtent := self extent. - surface := AthensCairoSurface extent: self extent ] + surface := AeCairoImageSurface extent: self extent ] ] diff --git a/src/Spec2-Adapters-Morphic-Alexandrie/SpMorphicAlexandrieAdapter.class.st b/src/Spec2-Adapters-Morphic-Alexandrie/SpMorphicAlexandrieAdapter.class.st index eb663dcf..b7e96776 100644 --- a/src/Spec2-Adapters-Morphic-Alexandrie/SpMorphicAlexandrieAdapter.class.st +++ b/src/Spec2-Adapters-Morphic-Alexandrie/SpMorphicAlexandrieAdapter.class.st @@ -1,14 +1,16 @@ Class { - #name : #SpMorphicAlexandrieAdapter, - #superclass : #SpAbstractMorphicAdapter, - #category : #'Spec2-Adapters-Morphic-Alexandrie-Base' + #name : 'SpMorphicAlexandrieAdapter', + #superclass : 'SpAbstractMorphicAdapter', + #category : 'Spec2-Adapters-Morphic-Alexandrie-Base', + #package : 'Spec2-Adapters-Morphic-Alexandrie', + #tag : 'Base' } -{ #category : #factory } +{ #category : 'factory' } SpMorphicAlexandrieAdapter >> buildWidget [ - | instance | - instance := SpAthensMorph new. + + instance := SpAlexandrieMorph new. self presenter whenDrawBlockChangedDo: [ :newBlock | instance drawBlock: newBlock ]. self presenter whenExtentChangedDo: [ :newExtent | @@ -21,13 +23,13 @@ SpMorphicAlexandrieAdapter >> buildWidget [ ^ instance ] -{ #category : #drawing } +{ #category : 'drawing' } SpMorphicAlexandrieAdapter >> redraw [ widget redraw ] -{ #category : #accessing } +{ #category : 'accessing' } SpMorphicAlexandrieAdapter >> surface [ ^ widget surface diff --git a/src/Spec2-Adapters-Morphic-Alexandrie/package.st b/src/Spec2-Adapters-Morphic-Alexandrie/package.st index 5422aea3..0db7df8a 100644 --- a/src/Spec2-Adapters-Morphic-Alexandrie/package.st +++ b/src/Spec2-Adapters-Morphic-Alexandrie/package.st @@ -1 +1 @@ -Package { #name : #'Spec2-Adapters-Morphic-Alexandrie' } +Package { #name : 'Spec2-Adapters-Morphic-Alexandrie' } From 23b24877b2f97b940ae097d24e1b7aafaba53eb6 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Fri, 19 Jul 2024 13:57:44 +0200 Subject: [PATCH 55/58] easy column view now use a visitor to correctly draw columns (and specialy composite columns_ --- ...AbstractEasyTreeListViewPresenter.class.st | 7 +- .../SpColumnViewPresenter.class.st | 33 ++++++++- .../SpDropDownPresenter.class.st | 6 ++ .../SpEasyColumnBindBuilder.class.st | 61 ++++++++++++++++ .../SpEasyColumnSetupBuilder.class.st | 48 ++++++++++++ .../SpEasyColumnViewPresenter.class.st | 40 +++++++++- .../SpEasyColumnVisitor.class.st | 73 +++++++++++++++++++ .../SpEasyListViewPresenter.class.st | 7 ++ .../SpEasyTreeColumnViewPresenter.class.st | 22 ++++-- .../SpEasyTreeListViewPresenter.class.st | 12 +++ .../SpImageTableColumn.extension.st | 13 ---- .../SpLinkTableColumn.extension.st | 13 ++++ .../SpListViewPresenter.class.st | 9 ++- src/Spec2-ListView/SpTableColumn.extension.st | 12 ++- .../SpTreeColumnViewPresenter.class.st | 25 ++++++- 15 files changed, 348 insertions(+), 33 deletions(-) create mode 100644 src/Spec2-ListView/SpEasyColumnBindBuilder.class.st create mode 100644 src/Spec2-ListView/SpEasyColumnSetupBuilder.class.st create mode 100644 src/Spec2-ListView/SpEasyColumnVisitor.class.st delete mode 100644 src/Spec2-ListView/SpImageTableColumn.extension.st create mode 100644 src/Spec2-ListView/SpLinkTableColumn.extension.st diff --git a/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st index f1fc9786..1ba0fc8d 100644 --- a/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st @@ -58,8 +58,7 @@ SpAbstractEasyTreeListViewPresenter >> expandAll [ "Expand all nodes of the tree. WARNING: If your tree is big, this operation can be slow." - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter expandAll ] + contentView expandAll ] { #category : 'api' } @@ -73,10 +72,8 @@ SpAbstractEasyTreeListViewPresenter >> expandPath: aPath [ { #category : 'api' } SpAbstractEasyTreeListViewPresenter >> expandRoots [ - "Expand all roots of the tree" - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter expandRoots ] + contentView expandRoots ] { #category : 'initialization' } diff --git a/src/Spec2-ListView/SpColumnViewPresenter.class.st b/src/Spec2-ListView/SpColumnViewPresenter.class.st index 84e8160a..c737a667 100644 --- a/src/Spec2-ListView/SpColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpColumnViewPresenter.class.st @@ -3,7 +3,8 @@ Class { #superclass : 'SpAbstractListPresenter', #instVars : [ '#columns => ObservableSlot', - '#isResizable => ObservableSlot' + '#isResizable => ObservableSlot', + '#showColumnHeaders => ObservableSlot' ], #category : 'Spec2-ListView', #package : 'Spec2-ListView' @@ -132,10 +133,26 @@ SpColumnViewPresenter >> columns [ ^ columns ] +{ #category : 'accessing' } +SpColumnViewPresenter >> columns: aCollection [ + + columns := #(). + aCollection do: [ :each | + self addColumn: each ] +] + +{ #category : 'api' } +SpColumnViewPresenter >> hideColumnHeaders [ + "Hide the column headers" + + showColumnHeaders := false +] + { #category : 'initialization' } SpColumnViewPresenter >> initialize [ super initialize. + self showColumnHeaders. columns := #() ] @@ -151,6 +168,20 @@ SpColumnViewPresenter >> isResizable: aBoolean [ isResizable := aBoolean ] +{ #category : 'testing' } +SpColumnViewPresenter >> isShowingColumnHeaders [ + "Answer true if the table is configured to show column headers." + + ^ showColumnHeaders +] + +{ #category : 'api' } +SpColumnViewPresenter >> showColumnHeaders [ + "Show column headers" + + showColumnHeaders := true +] + { #category : 'api - events' } SpColumnViewPresenter >> whenColumnsChangedDo: aBlock [ "Inform when columns have changed. diff --git a/src/Spec2-ListView/SpDropDownPresenter.class.st b/src/Spec2-ListView/SpDropDownPresenter.class.st index 9e783890..62fba21c 100644 --- a/src/Spec2-ListView/SpDropDownPresenter.class.st +++ b/src/Spec2-ListView/SpDropDownPresenter.class.st @@ -156,6 +156,12 @@ SpDropDownPresenter >> items: aSequenceableCollection [ model collection: aSequenceableCollection ] +{ #category : 'api' } +SpDropDownPresenter >> listSize [ + + ^ self items size +] + { #category : 'api' } SpDropDownPresenter >> model [ "Answer the model for this list. diff --git a/src/Spec2-ListView/SpEasyColumnBindBuilder.class.st b/src/Spec2-ListView/SpEasyColumnBindBuilder.class.st new file mode 100644 index 00000000..f924a474 --- /dev/null +++ b/src/Spec2-ListView/SpEasyColumnBindBuilder.class.st @@ -0,0 +1,61 @@ +Class { + #name : 'SpEasyColumnBindBuilder', + #superclass : 'SpEasyColumnVisitor', + #instVars : [ + 'item' + ], + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'accessing' } +SpEasyColumnBindBuilder >> item [ + + ^ item +] + +{ #category : 'accessing' } +SpEasyColumnBindBuilder >> item: anObject [ + + item := anObject +] + +{ #category : 'visiting' } +SpEasyColumnBindBuilder >> visitCompositeColumn: aColumn [ + | presenters visitor | + + visitor := self class new + item: self item; + yourself. + presenters := self presenter layout presenters. + aColumn columns withIndexDo: [ :each :index | + visitor + presenter: (presenters at: index); + visit: each ] +] + +{ #category : 'visiting' } +SpEasyColumnBindBuilder >> visitImageColumn: aColumn [ + + ^ self presenter image: (aColumn readObject: self item) +] + +{ #category : 'visiting' } +SpEasyColumnBindBuilder >> visitLinkColumn: aColumn [ + + self item ifNil: [ + self presenter label: ''. + ^ self ]. + + self presenter + label: (aColumn readObject: self item) asString; + action: [ aColumn action value: self item ] +] + +{ #category : 'visiting' } +SpEasyColumnBindBuilder >> visitStringColumn: aColumn [ + + ^ self presenter label: (self item + ifNotNil: [ :anObject | (aColumn readObject: anObject) asString ] + ifNil: [ '' ]) +] diff --git a/src/Spec2-ListView/SpEasyColumnSetupBuilder.class.st b/src/Spec2-ListView/SpEasyColumnSetupBuilder.class.st new file mode 100644 index 00000000..eb25e84d --- /dev/null +++ b/src/Spec2-ListView/SpEasyColumnSetupBuilder.class.st @@ -0,0 +1,48 @@ +" +Used to create the setup presenter for an ""easy"" column. +" +Class { + #name : 'SpEasyColumnSetupBuilder', + #superclass : 'SpEasyColumnVisitor', + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'visiting' } +SpEasyColumnSetupBuilder >> visitCompositeColumn: aColumn [ + | compositePresenter layout lastColumn | + + compositePresenter := self presenter newPresenter. + compositePresenter addStyle: 'easy_composite_cell'. + layout := SpBoxLayout newLeftToRight. + + lastColumn := aColumn columns last. + aColumn columns do: [ :each | + layout + add: (each acceptColumnVisitor: self) + withConstraints: [ :c | + each hasFixedWidth + ifTrue: [ c width: each width ] + ifFalse: [ c expand: (each isExpandable "or: [ each = lastColumn ]") ] ] ]. + + compositePresenter layout: layout. + ^ compositePresenter +] + +{ #category : 'visiting' } +SpEasyColumnSetupBuilder >> visitImageColumn: aColumn [ + + ^ self presenter newImage +] + +{ #category : 'visiting' } +SpEasyColumnSetupBuilder >> visitLinkColumn: aColumn [ + + ^ self presenter newLink +] + +{ #category : 'visiting' } +SpEasyColumnSetupBuilder >> visitStringColumn: aColumn [ + + ^ self presenter newLabel +] diff --git a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st index 81d35872..e2392982 100644 --- a/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyColumnViewPresenter.class.st @@ -61,6 +61,19 @@ SpEasyColumnViewPresenter >> beResizable [ contentView beResizable ] +{ #category : 'accessing' } +SpEasyColumnViewPresenter >> columns: aCollection [ + + contentView columns: aCollection + +] + +{ #category : 'api' } +SpEasyColumnViewPresenter >> contextMenu: aBlock [ + + self flag: #TODO. "ignored, as this is deprecated" +] + { #category : 'private' } SpEasyColumnViewPresenter >> displayValueFor: aImage [ @@ -70,7 +83,7 @@ SpEasyColumnViewPresenter >> displayValueFor: aImage [ { #category : 'api' } SpEasyColumnViewPresenter >> hideColumnHeaders [ - self flag: #TODO + contentView hideColumnHeaders ] { #category : 'initialization' } @@ -81,6 +94,19 @@ SpEasyColumnViewPresenter >> initializePresenters [ ] +{ #category : 'testing' } +SpEasyColumnViewPresenter >> isShowingColumnHeaders [ + "Answer true if the table is configured to show column headers." + + ^ contentView isShowingColumnHeaders +] + +{ #category : 'api' } +SpEasyColumnViewPresenter >> showColumnHeaders [ + + contentView showColumnHeaders +] + { #category : 'api - selection' } SpEasyColumnViewPresenter >> unselectAll [ @@ -93,3 +119,15 @@ SpEasyColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ contentView whenIsResizableChangedDo: aBlock ] + +{ #category : 'enumerating' } +SpEasyColumnViewPresenter >> whenSelectedDo: aBlock [ + + contentView whenSelectedDo: aBlock +] + +{ #category : 'enumerating' } +SpEasyColumnViewPresenter >> whenSelectedItemChangedDo: aBlock [ + + contentView whenSelectedItemChangedDo: aBlock +] diff --git a/src/Spec2-ListView/SpEasyColumnVisitor.class.st b/src/Spec2-ListView/SpEasyColumnVisitor.class.st new file mode 100644 index 00000000..42d929a1 --- /dev/null +++ b/src/Spec2-ListView/SpEasyColumnVisitor.class.st @@ -0,0 +1,73 @@ +" +A visitor for `SpTableColumn`. +This is uset to convert `SpTableColumn` into `SpColumnViewColumn` (needed to adapt the ""easy"" compatibility classes) +" +Class { + #name : 'SpEasyColumnVisitor', + #superclass : 'Object', + #instVars : [ + 'presenter' + ], + #category : 'Spec2-ListView', + #package : 'Spec2-ListView' +} + +{ #category : 'accessing' } +SpEasyColumnVisitor >> presenter [ + + ^ presenter +] + +{ #category : 'accessing' } +SpEasyColumnVisitor >> presenter: aPresenter [ + + presenter := aPresenter +] + +{ #category : 'visiting' } +SpEasyColumnVisitor >> visit: aColumn [ + + ^ aColumn acceptColumnVisitor: self +] + +{ #category : 'visiting' } +SpEasyColumnVisitor >> visitCheckboxColumn: aColumn [ + + self visitStringColumn: aColumn +] + +{ #category : 'visiting' } +SpEasyColumnVisitor >> visitCompositeColumn: aColumn [ + + self visitStringColumn: aColumn +] + +{ #category : 'visiting' } +SpEasyColumnVisitor >> visitDropListColumn: aColumn [ + + self visitStringColumn: aColumn +] + +{ #category : 'visiting' } +SpEasyColumnVisitor >> visitImageColumn: aColumn [ + + self visitStringColumn: aColumn +] + +{ #category : 'visiting' } +SpEasyColumnVisitor >> visitIndexColumn: aColumn [ + + self visitStringColumn: aColumn +] + +{ #category : 'visiting' } +SpEasyColumnVisitor >> visitLinkColumn: aColumn [ + + self visitStringColumn: aColumn +] + +{ #category : 'visiting' } +SpEasyColumnVisitor >> visitStringColumn: aColumn [ + + ^ self subclassResponsibility +] diff --git a/src/Spec2-ListView/SpEasyListViewPresenter.class.st b/src/Spec2-ListView/SpEasyListViewPresenter.class.st index d6ce324f..9436f26e 100644 --- a/src/Spec2-ListView/SpEasyListViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyListViewPresenter.class.st @@ -67,6 +67,13 @@ SpEasyListViewPresenter >> connectPresenters [ super connectPresenters ] +{ #category : 'api' } +SpEasyListViewPresenter >> contextMenu: aBlock [ + + self flag: #TODO. "Ignored, as this should be deprecated" + +] + { #category : 'layout' } SpEasyListViewPresenter >> defaultLayout [ diff --git a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st index ac232f12..0d736949 100644 --- a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st @@ -65,11 +65,17 @@ 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" - self flag: #TODO + contentView hideColumnHeaders ] { #category : 'initialization' } @@ -89,16 +95,15 @@ SpEasyTreeColumnViewPresenter >> isResizable [ { #category : 'testing' } SpEasyTreeColumnViewPresenter >> isShowingColumnHeaders [ "Answer true if the table is configured to show column headers." - - self flag: #TODO. - ^ true + + ^ contentView isShowingColumnHeaders ] { #category : 'api' } SpEasyTreeColumnViewPresenter >> showColumnHeaders [ - "Show column headers" + "Hide the column headers" - self flag: #TODO + contentView showColumnHeaders ] { #category : 'api - events' } @@ -123,3 +128,8 @@ SpEasyTreeColumnViewPresenter >> whenIsResizableChangedDo: aBlock [ contentView whenIsResizableChangedDo: aBlock ] + +{ #category : 'private - deferring' } +SpEasyTreeColumnViewPresenter >> withAdapterPerformOrDefer: aFullBlockClosure [ + self shouldBeImplemented. +] diff --git a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st index c61b224b..8b6f1cc9 100644 --- a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st @@ -16,6 +16,12 @@ SpEasyTreeListViewPresenter >> children: aBlock [ contentView children: aBlock ] +{ #category : 'api' } +SpEasyTreeListViewPresenter >> contextMenu: aBlock [ + + self flag: #TODO +] + { #category : 'layout' } SpEasyTreeListViewPresenter >> defaultLayout [ @@ -53,6 +59,12 @@ SpEasyTreeListViewPresenter >> display: aBlock [ display := aBlock ] +{ #category : 'api' } +SpEasyTreeListViewPresenter >> displayColor: aBlock [ + + self flag: #TODO +] + { #category : 'api' } SpEasyTreeListViewPresenter >> displayIcon [ "Return the block used to return an icon that will be displayed in the list" diff --git a/src/Spec2-ListView/SpImageTableColumn.extension.st b/src/Spec2-ListView/SpImageTableColumn.extension.st deleted file mode 100644 index 5175a9c0..00000000 --- a/src/Spec2-ListView/SpImageTableColumn.extension.st +++ /dev/null @@ -1,13 +0,0 @@ -Extension { #name : 'SpImageTableColumn' } - -{ #category : '*Spec2-ListView' } -SpImageTableColumn >> asColumnViewColumn [ - - ^ SpColumnViewColumn new - title: self title; - expand: (self width isNil and: [ self isExpandable ]); - width: self width; - setup: [ :aPresenter | aPresenter newImage ]; - bind: [ :aPresenter :item | aPresenter image: (self readObject: item) ]; - yourself -] diff --git a/src/Spec2-ListView/SpLinkTableColumn.extension.st b/src/Spec2-ListView/SpLinkTableColumn.extension.st new file mode 100644 index 00000000..bd4d0833 --- /dev/null +++ b/src/Spec2-ListView/SpLinkTableColumn.extension.st @@ -0,0 +1,13 @@ +Extension { #name : 'SpLinkTableColumn' } + +{ #category : '*Spec2-ListView' } +SpLinkTableColumn >> fillPresenter: aPresenter with: item [ + + item ifNil: [ + aPresenter label: ''. + ^ self ]. + + aPresenter + label: (self readObject: item) asString; + action: self action +] diff --git a/src/Spec2-ListView/SpListViewPresenter.class.st b/src/Spec2-ListView/SpListViewPresenter.class.st index 174fee24..2c0ce5cc 100644 --- a/src/Spec2-ListView/SpListViewPresenter.class.st +++ b/src/Spec2-ListView/SpListViewPresenter.class.st @@ -146,14 +146,19 @@ SpListViewPresenter class >> exampleWithIconsAndMorph [ application: (SpApplication new useBackend: #Gtk); items: self environment allClasses; setup: [ :aPresenter | - | presenter | + | presenter morph | (presenter := aPresenter newPresenter) layout: (SpBoxLayout newHorizontal spacing: 5; add: presenter newImage expand: false; add: presenter newLabel; add: (presenter newMorph - morph: SimpleButtonMorph new; + morph: ((morph := SimpleButtonMorph new) + color: Color blue; + target: [ + self inform: 'Clicked: ', morph label ]; + actionSelector: #value; + yourself); yourself); yourself); yourself ]; diff --git a/src/Spec2-ListView/SpTableColumn.extension.st b/src/Spec2-ListView/SpTableColumn.extension.st index a1d0a6d1..1e12dc15 100644 --- a/src/Spec2-ListView/SpTableColumn.extension.st +++ b/src/Spec2-ListView/SpTableColumn.extension.st @@ -7,10 +7,14 @@ SpTableColumn >> asColumnViewColumn [ title: self title; expand: (self width isNil and: [ self isExpandable ]); width: self width; - setup: [ :aPresenter | aPresenter newLabel ]; + setup: [ :aPresenter | + SpEasyColumnSetupBuilder new + presenter: aPresenter; + visit: self ]; bind: [ :aPresenter :item | - aPresenter label: (item - ifNotNil: [ (self readObject: item) asString ] - ifNil: [ '']) ]; + SpEasyColumnBindBuilder new + presenter: aPresenter; + item: item; + visit: self ]; yourself ] diff --git a/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st index 64342572..72ed55fe 100644 --- a/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpTreeColumnViewPresenter.class.st @@ -3,7 +3,8 @@ Class { #superclass : 'SpAbstractTreePresenter', #instVars : [ '#columns => ObservableSlot', - '#isResizable => ObservableSlot' + '#isResizable => ObservableSlot', + '#showColumnHeaders => ObservableSlot' ], #category : 'Spec2-ListView', #package : 'Spec2-ListView' @@ -172,6 +173,13 @@ SpTreeColumnViewPresenter >> columns [ ^ columns ] +{ #category : 'api' } +SpTreeColumnViewPresenter >> hideColumnHeaders [ + "Hide the column headers" + + showColumnHeaders := false +] + { #category : 'initialization' } SpTreeColumnViewPresenter >> initialize [ @@ -181,6 +189,7 @@ SpTreeColumnViewPresenter >> initialize [ self beSingleSelection. self activateOnDoubleClick. self beResizable. + self showColumnHeaders. self registerActions ] @@ -197,6 +206,13 @@ SpTreeColumnViewPresenter >> isResizable: aBoolean [ isResizable := aBoolean ] +{ #category : 'testing' } +SpTreeColumnViewPresenter >> isShowingColumnHeaders [ + "Answer true if the table is configured to show column headers." + + ^ showColumnHeaders +] + { #category : 'initialization' } SpTreeColumnViewPresenter >> registerActions [ @@ -206,6 +222,13 @@ SpTreeColumnViewPresenter >> registerActions [ action: [ self showContextMenu ] ] ] +{ #category : 'api' } +SpTreeColumnViewPresenter >> showColumnHeaders [ + "Show column headers" + + showColumnHeaders := true +] + { #category : 'private' } SpTreeColumnViewPresenter >> showContextMenu [ From a3bd8a89ef6996c9a6cbc4984207d7eadb7b20ea Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Sat, 20 Jul 2024 08:34:24 +0200 Subject: [PATCH 56/58] remove some duplicated methods and fix some bad usages --- .../SpMorphicListViewDataSource.class.st | 10 --- .../SpMorphicBackend.class.st | 22 +++---- .../SpAbstractMessageDialog.class.st | 5 -- .../SpNotificationCenterPresenter.class.st | 6 -- src/Spec2-Dialogs/SpProgressDialog.class.st | 10 --- .../SpAbstractEasyPresenter.class.st | 2 +- ...AbstractEasyTreeListViewPresenter.class.st | 63 +++++-------------- .../SpEasyTreeColumnViewPresenter.class.st | 6 -- .../SpEasyTreeListViewPresenter.class.st | 6 -- 9 files changed, 28 insertions(+), 102 deletions(-) diff --git a/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewDataSource.class.st b/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewDataSource.class.st index ccc7a632..c646efe7 100644 --- a/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewDataSource.class.st +++ b/src/Spec2-Adapters-Morphic-ListView/SpMorphicListViewDataSource.class.st @@ -21,13 +21,3 @@ SpMorphicListViewDataSource >> cellColumn: column row: rowIndex [ ^ cell addMorphBack: contentPresenter build ] - -{ #category : 'accessing' } -SpMorphicListViewDataSource >> headerColumn: column [ - - column id ifNil: [ ^ nil ]. - ^ FTCellMorph new - listCentering: #left; - addMorph: column id asMorph asReadOnlyMorph; - yourself -] diff --git a/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st b/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st index 791e6115..6501c9c6 100644 --- a/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st +++ b/src/Spec2-Adapters-Morphic/SpMorphicBackend.class.st @@ -91,19 +91,17 @@ SpMorphicBackend >> listClass [ { #category : 'private - dialogs' } SpMorphicBackend >> newFileDialogFor: aFileDialog [ - | dialog | - - dialog := FileDialogWindow basicNew - previewType: false; - initialize; - title: (aFileDialog title ifNil: [ 'Select File...' ]); - answerPathName. + | dialog dialogClass | + + dialogClass := aFileDialog isOpenFile + ifTrue: [ StOpenFilePresenter ] + ifFalse: [ StOpenDirectoryPresenter ]. + dialog := dialogClass for: aFileDialog. - aFileDialog filters ifNotEmpty: [ :filters | - dialog validExtensions: filters ]. - aFileDialog path ifNotNil: [ :path | - dialog fileNameText: path path fullName. - dialog selectPath: path fullName ]. + aFileDialog path ifNotNil: [ :folder | dialog openFolder: folder ]. + aFileDialog filters ifNotEmpty: [ :filters | + dialog fileNavigationSystem + filter: (StCustomExtensionsFilter extensions: { filters }) ]. ^ dialog ] diff --git a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st index 32cdb974..a304e415 100644 --- a/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st +++ b/src/Spec2-Dialogs/SpAbstractMessageDialog.class.st @@ -130,11 +130,6 @@ SpAbstractMessageDialog >> initializeWindowExtent: aDialogWindowPresenter [ (self adjustExtentToLabelHeight: self class defaultExtent) ] -{ #category : 'api' } -SpAbstractMessageDialog >> label [ - ^ label text -] - { #category : 'api' } SpAbstractMessageDialog >> label: aString [ diff --git a/src/Spec2-Dialogs/SpNotificationCenterPresenter.class.st b/src/Spec2-Dialogs/SpNotificationCenterPresenter.class.st index e2828556..4ca5eb5c 100644 --- a/src/Spec2-Dialogs/SpNotificationCenterPresenter.class.st +++ b/src/Spec2-Dialogs/SpNotificationCenterPresenter.class.st @@ -83,9 +83,3 @@ SpNotificationCenterPresenter >> modelChanged [ itemList items: announcingObject value items. itemList selectFirst ] - -{ #category : 'updating' } -SpNotificationCenterPresenter >> updatePresenter [ - - self modelChanged -] diff --git a/src/Spec2-Dialogs/SpProgressDialog.class.st b/src/Spec2-Dialogs/SpProgressDialog.class.st index c54791ec..7ca4f580 100644 --- a/src/Spec2-Dialogs/SpProgressDialog.class.st +++ b/src/Spec2-Dialogs/SpProgressDialog.class.st @@ -83,16 +83,6 @@ SpProgressDialog >> initialize [ maxValue := 1.0 ] -{ #category : 'initialization' } -SpProgressDialog >> initializeDialogWindow: aDialogWindowPresenter [ - - aDialogWindowPresenter whenOpenedDo: [ self afterOpenAction ]. - - self parentWindow - ifNotNil: [ :w | aDialogWindowPresenter centeredRelativeTo: w ] - ifNil: [ aDialogWindowPresenter centered ] -] - { #category : 'initialization' } SpProgressDialog >> initializePresenters [ diff --git a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st index 34717176..a8ad0fea 100644 --- a/src/Spec2-ListView/SpAbstractEasyPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyPresenter.class.st @@ -54,7 +54,7 @@ SpAbstractEasyPresenter >> addAction: aSpCommand [ contentView addAction: aSpCommand ] -{ #category : 'drawing' } +{ #category : 'api' } SpAbstractEasyPresenter >> alternateRowsColor [ contentView alternateRowsColor diff --git a/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st index 1ba0fc8d..c8d75ca8 100644 --- a/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpAbstractEasyTreeListViewPresenter.class.st @@ -28,8 +28,7 @@ SpAbstractEasyTreeListViewPresenter >> children: aBlock [ SpAbstractEasyTreeListViewPresenter >> collapseAll [ "Collapse all nodes of the tree. " - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter collapseAll ] + contentView collapseAll ] { #category : 'api' } @@ -37,8 +36,7 @@ SpAbstractEasyTreeListViewPresenter >> collapsePath: aPath [ "Collapse the tree path. `aPath` is the path to collapse. A path is an array of node indexes (e.g. #(1 2 3))" - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter collapsePath: aPath ] + contentView collapsePath: aPath ] { #category : 'transmission' } @@ -47,12 +45,6 @@ SpAbstractEasyTreeListViewPresenter >> defaultInputPort [ ^ self inputRootsPort ] -{ #category : 'transmission' } -SpAbstractEasyTreeListViewPresenter >> defaultOutputPort [ - - ^ self outputSelectionPort -] - { #category : 'api' } SpAbstractEasyTreeListViewPresenter >> expandAll [ "Expand all nodes of the tree. @@ -66,12 +58,12 @@ SpAbstractEasyTreeListViewPresenter >> expandPath: aPath [ "Expand the tree path. `aPath` is the path to expand. A path is an array of node indexes (e.g. #(1 2 3))" - self withAdapterPerformOrDefer: [ :anAdapter | - anAdapter expandPath: aPath ] + contentView expandPath: aPath ] { #category : 'api' } SpAbstractEasyTreeListViewPresenter >> expandRoots [ + "Expand all roots of the tree" contentView expandRoots ] @@ -100,7 +92,7 @@ SpAbstractEasyTreeListViewPresenter >> items: aCollection [ { #category : 'private' } SpAbstractEasyTreeListViewPresenter >> lazilyComputeChildren: aBoolean [ - self flag: #TODO. + self flag: #TOREMOVE. ] { #category : 'transmission' } @@ -121,14 +113,7 @@ SpAbstractEasyTreeListViewPresenter >> refresh [ This is useful when some model contents has changed, but we do not want to reset the whole list (and losing selections with it)" - self withAdapterDo: [ :anAdapter | anAdapter refreshTree ] -] - -{ #category : 'initialization' } -SpAbstractEasyTreeListViewPresenter >> registerEvents [ - - "self whenMenuChangedDo: [ - self withAdapterDo: [ :anAdapter | anAdapter updateMenu ] ]" + contentView refresh ] { #category : 'api' } @@ -151,7 +136,7 @@ SpAbstractEasyTreeListViewPresenter >> selectItem: anItem [ "Select `anItem` if it is included in model list. It does not scrolls to selected element." - self selection selectItem: anItem + contentView selectItem: anItem ] { #category : 'api - selection' } @@ -160,7 +145,7 @@ SpAbstractEasyTreeListViewPresenter >> selectItems: aListOfItem [ NOTE: In single selection mode it will select the first element of `aCollection` It does not scrolls to selected element." - self selection selectItems: aListOfItem + contentView selectItems: aListOfItem ] { #category : 'api - selection' } @@ -169,7 +154,7 @@ SpAbstractEasyTreeListViewPresenter >> selectPath: aPath [ `aPath` is the path to select. A path is an array of node indexes (e.g. #(1 2 3)). It does not scrolls to selected element." - self selection selectPath: aPath + contentView selectPath: aPath ] { #category : 'api - selection' } @@ -190,7 +175,8 @@ SpAbstractEasyTreeListViewPresenter >> selectPath: aPath scrollToSelection: shou { #category : 'api - selection' } SpAbstractEasyTreeListViewPresenter >> selectPathByItems: pathArray [ - self selectPathByItems: pathArray scrollToSelection: false + contentView selectPathByItems: pathArray + ] { #category : 'api - selection' } @@ -199,13 +185,9 @@ SpAbstractEasyTreeListViewPresenter >> selectPathByItems: pathArray scrollToSele is displayed it does not has real bounds. In morphic (and gtk) it has a minimal extent assigned, but that will change as soon as the widget is inserted in a container and the container applies its layout." - | pathIndexes | - - pathIndexes := self pathIndexOf: pathArray. - pathIndexes size > 1 ifTrue: [ - self expandPath: pathIndexes allButLast ]. - self - selectPath: pathIndexes + + contentView + selectPathByItems: pathArray scrollToSelection: aBoolean ] @@ -214,21 +196,21 @@ SpAbstractEasyTreeListViewPresenter >> selectPaths: pathArray [ "Selects all elements in `pathsArray`` `pathsArray` is an array of paths. A path is an array of node indexes (e.g. #(1 2 3))" - self selection selectPaths: pathArray + contentView selectPaths: pathArray ] { #category : 'api - selection' } SpAbstractEasyTreeListViewPresenter >> selectedItem [ "Return selected item." - ^ self selection selectedItem + ^ contentView selectedItem ] { #category : 'api - selection' } SpAbstractEasyTreeListViewPresenter >> selectedItems [ "Return all the selected items in the case of a multiple selection list" - ^ self selection selectedItems + ^ contentView selectedItems ] { #category : 'api - selection' } @@ -319,17 +301,6 @@ SpAbstractEasyTreeListViewPresenter >> whenSelectedItemChangedDo: aBlock [ ] -{ #category : 'api - events' } -SpAbstractEasyTreeListViewPresenter >> whenSelectionChangedDo: aBlock [ - "Inform when selection has changed. - `aBlock` has three optional arguments: - - new value - - old value - - the announcement triggering this action" - - contentView whenSelectionChangedDo: aBlock -] - { #category : 'api - events' } SpAbstractEasyTreeListViewPresenter >> whenShowColumnHeadersChangedDo: aBlock [ "Inform when showColumnHeaders property has changed. diff --git a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st index 0d736949..cbf8940a 100644 --- a/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyTreeColumnViewPresenter.class.st @@ -29,12 +29,6 @@ SpEasyTreeColumnViewPresenter >> addColumn: aColumn [ contentView addColumn: aColumn asColumnViewColumn ] -{ #category : 'api' } -SpEasyTreeColumnViewPresenter >> alternateRowsColor [ - " Will alternate Rows color for a better reading: one row lighter, the next row darker" - contentView alternateRowsColor -] - { #category : 'api' } SpEasyTreeColumnViewPresenter >> beNotResizable [ "Mark the table as 'not resizable', which means there will be not possibility to resize the diff --git a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st index 8b6f1cc9..9ef98e4b 100644 --- a/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st +++ b/src/Spec2-ListView/SpEasyTreeListViewPresenter.class.st @@ -10,12 +10,6 @@ Class { #package : 'Spec2-ListView' } -{ #category : 'api' } -SpEasyTreeListViewPresenter >> children: aBlock [ - - contentView children: aBlock -] - { #category : 'api' } SpEasyTreeListViewPresenter >> contextMenu: aBlock [ From b5c7cebadeeaa3c5eac611e4b40532d9fa2fa608 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Sat, 20 Jul 2024 08:35:43 +0200 Subject: [PATCH 57/58] add test method --- src/Spec2-Core/SpTableColumn.class.st | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Spec2-Core/SpTableColumn.class.st b/src/Spec2-Core/SpTableColumn.class.st index 039e1d4b..87e49ae3 100644 --- a/src/Spec2-Core/SpTableColumn.class.st +++ b/src/Spec2-Core/SpTableColumn.class.st @@ -111,6 +111,12 @@ SpTableColumn >> evaluation [ ^ evaluation ] +{ #category : 'testing' } +SpTableColumn >> hasFixedWidth [ + + ^ (self width isNil or: [ self width = 0 ]) not +] + { #category : 'initialization' } SpTableColumn >> initialize [ From 9aae500bc410a3a330d6448be5895e5530580cb8 Mon Sep 17 00:00:00 2001 From: Esteban Lorenzano Date: Sat, 20 Jul 2024 08:36:10 +0200 Subject: [PATCH 58/58] add parentWindow accessor --- src/Spec2-Dialogs/SpFileDialog.class.st | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Spec2-Dialogs/SpFileDialog.class.st b/src/Spec2-Dialogs/SpFileDialog.class.st index b9310343..55ca5bb1 100644 --- a/src/Spec2-Dialogs/SpFileDialog.class.st +++ b/src/Spec2-Dialogs/SpFileDialog.class.st @@ -12,6 +12,7 @@ Class { 'filters', 'path', 'application', + 'parentWindow', 'action' ], #category : 'Spec2-Dialogs', @@ -107,6 +108,18 @@ SpFileDialog >> openModal [ ^ self application backend openFileDialog: self ] +{ #category : 'accessing' } +SpFileDialog >> parentWindow [ + + ^ parentWindow +] + +{ #category : 'accessing' } +SpFileDialog >> parentWindow: anObject [ + + parentWindow := anObject +] + { #category : 'api' } SpFileDialog >> path [