[GOODIE] 's Tree and TextOrganizer
Stewart MacLean
stingray at paradise.net.nz
Tue May 9 01:05:18 UTC 2000
I just noticed that when I received my post the last few lines have disappeared down a black hole!
*$!# email program.
Here is the TextOrganizer change set again ... duh!
'From Squeak2.8alpha of 6 May 2000 [latest update: #2052] on 7 May 2000 at 9:21:52 pm'!
"Change Set: Text Organizer 1.0
Date: 7 May 2000
Author: Stewart MacLean
stingray at paradise.net.nz
The text organizer application provides a way of arranging chunks of text in a hierarchical fashion.
Enjoy!!
Prerequisites:
- ObjectExplorer
- Object Explorer Fixes And Changes
- Tree
Optional:
- Doug Way's Windoze tree style with + and -
Usage:
To open a fresh organizer evaluate:
TextOrganizer open.
On the hierarchy list pane:
- left click in toggle area expands/contracts current item
- shifted left click in toggle area expands/contracts current item and all its subitems
- right click in toggle area expands/contracts current item and all siblings
- right click on item text gets menu
Menu Options:
add
interpose above
interpose below
delete
delete with parent adopting children
cut
paste below
paste before
paste after
copy
rename
find
find next
sort children
sort children recursively
load
save
Bugs:
I've been using it for a while, however testing only proves the presence of errors:)
Send any you find to me.
History:
1.0 Initial release"!
NaryTreeNode subclass: #OrganizerNode
instanceVariableNames: 'name '
classVariableNames: ''
poolDictionaries: ''
category: 'Tools-Text Organizer'!
!OrganizerNode commentStamp: '<historical>' prior: 0!
A named, n-ary tree node, whose value is String.
Used as the primary domain model for the TextOrganizer.
!
OrganizerNode class
instanceVariableNames: ''!
AbstractHierarchicalList subclass: #TextOrganizer
instanceVariableNames: 'rootObject listMorph findProcess searchString textPaneSelection '
classVariableNames: ''
poolDictionaries: ''
category: 'Tools-Text Organizer'!
!TextOrganizer commentStamp: 'SIM 5/7/2000 17:38' prior: 0!
Welcome to the Text Organizer.
It provides a way of arranging chunks of text in a hierarchical fashion.
Inspired by VisualWorks WorkspaceOrganizer and made implementable (by me!!) in Morphic by Bob Arnings ObjectExplorer. Thanks Bob.
Enjoy!!
Stewart MacLean, May 2000. e-mail: stingray at paradise.net.nz
Prerequisites:
- ObjectExplorer
- Object Explorer Fixes And Changes
- Tree
Optional:
- Doug Way's Windoze tree style with + and -
Usage:
To open a fresh organizer evaluate:
TextOrganizer open.
On the hierarchy list pane:
- left click in toggle area expands/contracts current item
- shifted left click in toggle area expands/contracts current item and all its subitems
- right click in toggle area expands/contracts current item and all siblings
- right click on item text gets menu
Menu Options:
add
interpose above
interpose below
delete
delete with parent adopting children
cut
paste below
paste before
paste after
copy
rename
find
find next
sort children
sort children recursively
load
save
Architecture:
TextOrganizer class is the application model of the "text organizer" application.
The text organizer application provides a way of arranging chunks of text
in a hierarchical fashion. The domain model class is OrganizerNode. For purposes
of user interaction these are wrappered by TextOrganizerNodeWrapper.
The user interface consists of two panes. The top one is a hierarchical list of headings
(implemented using SimpleHierarchicalListMorph) and the bottom one contains the
currently selected list item's associated text (implemented using a PluggagleTextMorph).
I was able to leverage Bob's good work on the explorer (I didn't have time to do the hard
bits myself!!). As I wanted the organizer's hierarchical list to behave differently I have had
to separate out the behaviour of SimpleHierarchicalListMorph. I have changed
SimpleHierarchicalListMorph<<mouseDown: event onItem: aMorph to delegate it's behaviour
to it's model. The main behviour change is to allow for a "very deep recursive" toggle.
This is appropriate for the organizer as the subtrees are bound, whereas with the explorer,
depending on what you were looking at, one could conceivably end up expanding with all
the objects in the image - ouch!!
In order to be able to find all the siblings of any item I found that I had
to add a parent backpointer to IndentingListItemMorph.
(The current withSiblingsDo: only includes remaining siblings in the chain).
I also fixed a couple of bugs with the explorer:
- left clicking on an expanded item (in toggle area) where a child is selected, still leaves a highlight when it contracts
- right clicking on an expanded item (in toggle area) causes a walkback
Note that the application model (TextOrganizer) is tightly bound to the list morph, and sends messages directly as well as using the changed: mvc mechanisim.
!
TextOrganizer class
instanceVariableNames: 'pasteBuffer '!
ListItemWrapper subclass: #TextOrganizerNodeWrapper
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Tools-Text Organizer'!
!TextOrganizerNodeWrapper commentStamp: '<historical>' prior: 0!
A wrapper of OrganizerNode's, used for interaction.
!
TextOrganizerNodeWrapper class
instanceVariableNames: ''!
SystemWindow subclass: #TextOrganizerWindow
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Tools-Text Organizer'!
!TextOrganizerWindow commentStamp: '<historical>' prior: 0!
Subclass SystemWindow to overide delete to check if it is ok by the model to close the window.
Current delete sends okToChange, which conflicts with changes in subpanes.!
!OrganizerNode methodsFor: 'initialize-release' stamp: 'SIM 5/7/2000 12:56'!
initialize
"Initialise the receiver's local variables."
super initialize.
name _ 'new kid on the block'.
value _ String new! !
!OrganizerNode methodsFor: 'finding' stamp: 'SIM 4/26/2000 17:38'!
find: aString for: anApplication
"Search name and the text of the reciever for occurances of aString.
If found 'callback' to anApplication with its location.
Suspend the current active process, which is the find process.
This enables the search to resume where it left off."
| index |
index _ 0.
[(index _ name
indexOfSubCollection: aString
startingAt: index + 1
ifAbsent: [0]) = 0]
whileFalse: [
anApplication foundString: aString withinNameOf: self at: index.
Processor activeProcess suspend].
index _ 0.
[(index _ self text
indexOfSubCollection: aString
startingAt: index + 1
ifAbsent: [0]) = 0]
whileFalse: [
anApplication foundString: aString withinValueOf: self at: index.
Processor activeProcess suspend].
children do: [: each | each find: aString for: anApplication]
! !
!OrganizerNode methodsFor: 'accessing' stamp: 'SIM 2/13/2000 14:54'!
name
"Answer name."
^name! !
!OrganizerNode methodsFor: 'accessing' stamp: 'SIM 3/20/2000 14:31'!
name: aString
"Set name to aString."
name _ aString! !
!OrganizerNode methodsFor: 'accessing' stamp: 'SIM 5/7/2000 12:56'!
name: aNameString text: aTextString
"Set name to aNameString and contents to aTextString."
name _ aNameString.
value _ aTextString! !
!OrganizerNode methodsFor: 'accessing' stamp: 'SIM 5/7/2000 12:56'!
text
"Answer value, which we treat here as aString"
^value! !
!OrganizerNode methodsFor: 'accessing' stamp: 'SIM 5/7/2000 12:56'!
text: aString
"Set value to aString"
value _ aString! !
!OrganizerNode methodsFor: 'printing' stamp: 'SIM 3/20/2000 14:28'!
printOn: aStream
"Write a description of the receiver on aStream."
aStream nextPutAll: name ! !
!OrganizerNode methodsFor: 'structure changes' stamp: 'SIM 4/3/2000 10:28'!
addChildNamed: aString
"Add a new child to the receiver and assign aString to it's name."
^(super addChild: self class new)
name: aString! !
!OrganizerNode methodsFor: 'structure changes' stamp: 'SIM 4/16/2000 16:12'!
interposeNewAboveNamed: aString
"Add a new child to the receiver's parent and assign aString to it's name.
The new child adopts the receiver's children."
^super interposeNewAbove name: aString
! !
!OrganizerNode methodsFor: 'structure changes' stamp: 'SIM 4/16/2000 17:08'!
interposeNewBelowNamed: aString
"Add a new child to the receiver and assign aString to it's name.
The new child adopts the receiver's children."
^super interposeNewBelow name: aString
! !
!OrganizerNode methodsFor: 'structure changes' stamp: 'SIM 5/6/2000 14:45'!
sortChildren
"Sort the receiver's children."
children _ (children
asSortedCollection: [: a : b | a name <= b name])
asOrderedCollection! !
!OrganizerNode methodsFor: 'structure changes' stamp: 'SIM 5/6/2000 14:52'!
sortChildrenRecursively
"Sort the receiver's children, recursively."
self do: [: node | node sortChildren]! !
!OrganizerNode class methodsFor: 'instance creation' stamp: 'SIM 4/18/2000 10:11'!
name: aString
"Create an OrganiserNode with name aString."
^self new name: aString! !
!OrganizerNode class methodsFor: 'instance creation' stamp: 'SIM 4/18/2000 10:14'!
name: aNameString text: aTextString
"Create an OrganiserNode with name aTextString."
^self new name: aNameString text: aTextString! !
!OrganizerNode class methodsFor: 'instance creation' stamp: 'SIM 4/18/2000 09:57'!
new
"Answer a new initialized instance of the receiver."
^super new initialize! !
!OrganizerNode class methodsFor: 'instance creation' stamp: 'SIM 4/18/2000 09:51'!
text: aString
"Create an OrganiserNode with text aString."
^self new text: aString! !
!OrganizerNode class methodsFor: 'test tree generation' stamp: 'SIM 4/18/2000 10:35'!
buildTestTree: anArray
"Build a test tree specified by anOrderedCollection where the
numbers represent the number of leaves and the parenthesis
specify the rest of the hierarchy.
OrganizerNode buildTestTree: #((( 2 5) (3)) (4 (1(1 2))6) (1) (6))
"
| new |
new _ self name: 'root'.
self subTree: anArray
of: new
label: 'sub'.
^new! !
!OrganizerNode class methodsFor: 'test tree generation' stamp: 'SIM 4/18/2000 10:35'!
buildTestTree: anArray maxLabel: anInteger
"Same as build test tree but adds variable letter length labels at random.
OrganizerNode
buildTestTree: #((( 2 5) (3)) ( 4 (1(1 2)) 6) (1) (6))
maxLabel: 10
"
| new |
new _ self name: 'root'.
self subTree: anArray
of: new
maxLabel: anInteger.
^new! !
!OrganizerNode class methodsFor: 'test tree generation' stamp: 'SIM 4/18/2000 10:26'!
getBigTree
"185 nodes.
OrganizerNode getBigTree
"
^self
buildTestTree:
#( 2 (3 (2)) ( 4 (3)) ((1((2((3((2(4 (3)(3)))1))4)1)3))1) ( 4 (3)) ((1((12(14)(1((2(4))2))1)13))5) ((1(1 (2)) (2) ((1((1((2(4)1)3))5)(3)1))3 4) 1) 5 )
maxLabel: 8! !
!OrganizerNode class methodsFor: 'test tree generation' stamp: 'SIM 4/18/2000 10:24'!
randomLabel: labelSize
"Generate and return a random set of letters >= 1 and <= labelSize."
| lab |
Seed isNil ifTrue: [Seed _ Random new].
lab _ String new: ((Seed next * 100) truncated \\ labelSize) + 1.
1 to: lab size do: [: i |
lab
at: i
put: ((Seed next * 100) truncated \\ 26 + $a asciiValue) asCharacter].
^lab! !
!OrganizerNode class methodsFor: 'test tree generation' stamp: 'SIM 4/18/2000 10:35'!
subTree: anArray of: aTreeNode label: aString
"Recursively analyze the elements of anArray and
build standard labels using aString."
| lab new i |
i _ 0.
anArray do: [: e |
(e isKindOf: Array)
ifTrue: [
lab _ aString , '.' , (i _ i + 1) printString.
new _ self name: lab.
aTreeNode addChild: new.
self subTree: e of: new label: lab]
ifFalse: [
1 to: e do: [: r |
aTreeNode addChild:
(self name: aString,'.',(i _ i + 1) printString)]]].! !
!OrganizerNode class methodsFor: 'test tree generation' stamp: 'SIM here ifTrue:
[self hasEditingConflicts: true.
^ self changed]
! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/6/2000 16:16'!
addItem
"Add a new subitem to the currently selected item."
| name |
(name _ FillInTheBlankMorph request: 'Enter name of item') isEmpty
ifTrue: [^self].
self changed: #expandCurrentSelection.
currentSelection addChildNamed: name.
self
changed: #getList;
changed: #getCurrentSelection;
changed: #text! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 4/26/2000 17:25'!
copyItem
"Copy the current selection, very deeply."
self class pasteBuffer: currentSelection veryDeepCopy
! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 4/21/2000 16:26'!
cutItem
"Cut the currently selected item.
Equivalent to deleteWithSubtree."
self deleteWithSubtree
! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 4/17/2000 21:39'!
deleteWithParentAdoptingChildren
"Delete the currently selected item.
The children of the current item are adopted by its parent."
currentSelection withoutListWrapper == rootObject
ifTrue: [^self inform: 'Cant delete root item'].
currentSelection deleteWithParentAdoptingChildren.
currentSelection _ nil.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 4/17/2000 21:40'!
deleteWithSubtree
"Delete the subtree rooted at the currently selected item."
currentSelection withoutListWrapper == rootObject
ifTrue: [^self inform: 'Cant delete root item'].
self class pasteBuffer: currentSelection.
currentSelection removeFromParent.
currentSelection _ nil.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 4/26/2000 17:25'!
inspectItem
"Inspect the current item. For debugging."
currentSelection inspect! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/7/2000 13:15'!
interposeAbove
"Add a new subitem between the currently selected item
and it's parent."
| name new |
self isIllegalRootActionCheck ifTrue: [^self].
(name _ FillInTheBlankMorph request: 'Enter name of item') isEmpty
ifTrue: [^self].
new _ currentSelection interposeNewAboveNamed: name.
currentSelection _ new.
self
changed: #getList;
changed: #getCurrentSelection;
changed: #text;
changed: #expandCurrentSelection! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/6/2000 16:16'!
interposeBelow
"Add a new subitem between the currently selected item
and it's children."
| name |
(name _ FillInTheBlankMorph request: 'Enter name of item') isEmpty
ifTrue: [^self].
self changed: #expandCurrentSelection.
currentSelection _ currentSelection interposeNewBelowNamed: name.
self
changed: #getList;
changed: #getCurrentSelection;
changed: #text;
changed: #recursiveExpandCurrentSelection! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/7/2000 21:14'!
loadOrganizer
"Load an organizer tree from disk."
| name stream file |
file _ StandardFileMenu oldFileStream.
file ifNil: [^self].
name _ file name.
rootObject _ (stream _ ReferenceStream oldFileNamed: name) next.
stream close.
currentSelection _ TextOrganizerNodeWrapper with: rootObject.
self
changed: #getList;
changed: #getCurrentSelection;
changed: #text;
changed: #expandCurrentSelection.
! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/7/2000 13:15'!
pasteItemAfter
"Add the buffered item after the currently selected item."
self isIllegalRootActionCheck ifTrue: [^self].
self class pasteBuffer ifNil: [^self inform: 'Nothing in buffer to paste'].
self changed: #expandCurrentSelection.
currentSelection addSiblingAfter: self class pasteBuffer.
self
changed: #getList;
changed: #getCurrentSelection;
changed: #text! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/7/2000 13:15'!
pasteItemBefore
"Add the buffered item before the currently selected item."
self isIllegalRootActionCheck ifTrue: [^self].
self class pasteBuffer ifNil: [^self inform: 'Nothing in buffer to paste'].
self changed: #expandCurrentSelection.
currentSelection addSiblingBefore: self class pasteBuffer.
self
changed: #getList;
changed: #getCurrentSelection;
changed: #text! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/7/2000 13:05'!
pasteItemBelow
"Add the buffered item as a child of the currently selected item."
self class pasteBuffer ifNil: [^self inform: 'Nothing in buffer to paste'].
self changed: #expandCurrentSelection.
currentSelection _ currentSelection addChild: self class pasteBuffer.
self
changed: #getList;
changed: #getCurrentSelection;
changed: #text! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/6/2000 16:17'!
rename
"Rename the currently selected item."
| name |
(name := FillInTheBlankMorph
request: 'Enter name of item'
initialAnswer: currentSelection name) isEmpty
ifTrue: [^self].
currentSelection name: name.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/7/2000 17:25'!
saveOrganizer
"Save the current organizer tree to disk.
Prompt the user for a file name.
If the user cancels then answer false,
otherwise save the organizer to disk and answer true."
| name |
(name _
FillInTheBlankMorph
request: 'Enter file name of organizer'
initialAnswer: self defaultFileName) isEmpty
ifTrue: [^false].
(ReferenceStream fileNamed: name)
nextPut: rootObject;
close.
^true
! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/6/2000 14:36'!
sortChildren
"Sort the children of the current item into alphabetical order."
currentSelection sortChildren.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text
! !
!TextOrganizer methodsFor: 'actions' stamp: 'SIM 5/6/2000 14:49'!
sortChildrenRecursively
"Sort the receiver's children recursively."
currentSelection sortChildrenRecursively.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text
! !
!TextOrganizer methodsFor: 'constants' stamp: 'SIM 4/17/2000 14:06'!
defaultFileName
^'organizer.dat'! !
!TextOrganizer methodsFor: 'finding' stamp: 'SIM 4/24/2000 20:58'!
findText
"Prompt the user for the searchString.
Expand all items.
Instantiate and fork a process which will suspend each time the searchString
is found."
findProcess ifNotNil: [findProcess terminate].
(searchString _
FillInTheBlankMorph
request: 'Enter string to find'
initialAnswer: searchString) isEmpty
ifTrue: [^self].
currentSelection _ TextOrganizerNodeWrapper with: rootObject.
self
changed: #getList;
changed: #getCurrentSelection;
changed: #text;
changed: #recursiveExpandCurrentSelection.
findProcess _
[rootObject find: searchString for: self.
findProcess _ nil.
self inform: 'No more items to search - end of find'.
Processor activeProcess terminate] fork! !
!TextOrganizer methodsFor: 'finding' stamp: 'SIM 4/24/2000 20:58'!
findTextNext
"Find the next occurance of the searchString.
Implemented by resuming the findProcess."
findProcess
ifNil: [self inform: 'Do find first']
ifNotNil: [findProcess resume]
! !
!TextOrganizer methodsFor: 'finding' stamp: 'SIM 4/26/2000 17:40'!
foundString: aString withinNameOf: aTreeNode at: aPosition
" 'Callback' from domain model notifying that aString has been found,
within aTreeNode's name.
- deselect currently selected item
- set the currentSelection and the text positions to be selected
- update the views"
currentSelection _ nil.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text.
currentSelection _ TextOrganizerNodeWrapper with: aTreeNode.
textPaneSelection _ 0 to: 0.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text! !
!TextOrganizer methodsFor: 'finding' stamp: 'SIM 4/26/2000 17:40'!
foundString: aString withinValueOf: aTreeNode at: aPosition
" 'Callback' from domain model notifying that aString has been found,
within the value of aTreeNode.
- deselect currently selected item
- set the currentSelection and the text positions to be selected
- update the views"
currentSelection _ nil.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text.
currentSelection _ TextOrganizerNodeWrapper with: aTreeNode.
textPaneSelection _ aPosition to: aPosition + aString size - 1.
self
changed: #getCurrentSelection;
changed: #getList;
changed: #text! !
!TextOrganizer methodsFor: 'hierarchical list pane' stamp: 'SIM 4/4/2000 16:44'!
getList
"Answer a collection with the wrapped rootObject as it's only member."
^Array with:
(TextOrganizerNodeWrapper with: rootObject)
! !
!TextOrganizer methodsFor: 'hierarchical list pane' stamp: 'SIM 5/7/2000 16:54'!
hierarchyMenu: aMenu
"Answer aMenu with the hierarchy pane items added."
| menu |
self changed: #modelAccept.
currentSelection
ifNil: [
menu _ aMenu.
menu
add: 'load' target: self selector: #loadOrganizer]
ifNotNil: [
menu _ aMenu.
menu
"add: 'inspect item' target: self selector: #inspectItem;"
add: 'add' target: self selector: #addItem;
add: 'interpose above' target: self selector: #interposeAbove;
add: 'interpose below' target: self selector: #interposeBelow;
addLine;
add: 'delete' target: self selector: #deleteWithSubtree;
add: 'delete with parent adopting children' target: self selector: #deleteWithParentAdoptingChildren;
addLine;
add: 'cut' target: self selector: #cutItem;
add: 'paste below' target: self selector: #pasteItemBelow;
add: 'paste before' target: self selector: #pasteItemBefore;
add: 'paste after' target: self selector: #pasteItemAfter;
add: 'copy' target: self selector: #copyItem;
addLine;
add: 'rename' target: self selector: #rename;
addLine;
add: 'find' target: self selector: #findText;
add: 'find next' target: self selector: #findTextNext;
addLine;
add: 'sort children' target: self selector: #sortChildren;
add: 'sort children recursively' target: self selector: #sortChildrenRecursively;
addLine;
add: 'load' target: self selector: #loadOrganizer;
add: 'save' target: self selector: #saveOrganizer].
^menu! !
!TextOrganizer methodsFor: 'hierarchical list pane' stamp: 'SIM 4/4/2000 16:40'!
leftButtonPressed: event onItem: aMorph
"Respond to the leftButtonPressed:onItem: event by
selecting aMorph on the hierarchical list morph."
listMorph selectMorph: aMorph! !
!TextOrganizer methodsFor: 'hierarchical list pane' stamp: 'SIM 4/4/2000 16:41'!
leftButtonPressedInToggleArea: event morph: aMorph
"If the shift button is pressed whilst the left button is pressed
within the toggle area then recursively toggle the expanded state
of the selected subtree, otherwise just toggle the expanded state
of the current item."
event shiftPressed
ifFalse: [
listMorph toggleExpandedStateOf: aMorph]
ifTrue: [
listMorph
recursiveToggleExpandedState: aMorph]! !
!TextOrganizer methodsFor: 'hierarchical list pane' stamp: 'SIM 5/6/2000 16:56'!
noteNewSelection: aTextOrganizerNodeWrapper
"Note the new selection within the hierarchical list morph:
- propogate a 'model text accept' to the text pane
- note the new selection
- update the new selection to the view
- update the text of the selection to the text pane."
self changed: #modelAccept.
currentSelection _ aTextOrganizerNodeWrapper.
textPaneSelection _ 1 to: 0.
self changed: #getCurrentSelection;
changed: #text.
currentSelection ifNotNil: [
currentSelection sendSettingMessageTo: self]
! !
!TextOrganizer methodsFor: 'hierarchical list pane' stamp: 'SIM 4/24/2000 21:17'!
rightButtonPressed: event onItem: aMorph
"Pop up the hierarchy pane menu."
listMorph yellowButtonActivity: event shiftPressed! !
!TextOrganizer methodsFor: 'hierarchical list pane' stamp: 'SIM 4/24/2000 21:18'!
rightButtonPressedInToggleArea: event morph: aMorph
"If the shift button is pressed, toggle the expanded state of all of the
siblings of aMorph."
event shiftPressed
ifFalse: [
listMorph
toggleExpandedStateOfSiblingsOf: aMorph;
selectMorph: aMorph]
ifTrue: []! !
!TextOrganizer methodsFor: 'initialise-release' stamp: 'SIM 4/24/2000 21:19'!
initialize
"Initialise the receiver's instance variables."
searchString _ ''.
textPaneSelection _ 1 to: 0 "null selection"! !
!TextOrganizer methodsFor: 'open/close' stamp: 'SIM 5/7/2000 17:23'!
okToClose
"Prompt the user to save the data before closing the window.
Give them the option to cancel the close."
(SelectionMenu confirm: 'Save Organizer before closing?'
orCancel: [^false])
ifTrue: [^self saveOrganizer].
^true
! !
!TextOrganizer methodsFor: 'open/close' stamp: 'SIM 4/25/2000 22:54'!
openOrganizerOn: anObject
"Open a TextOrganizer on anObject."
(self organizerOn: anObject) openInWorldExtent: 500 at 600.
^ self
! !
!TextOrganizer methodsFor: 'open/close' stamp: 'SIM 4/17/2000 14:36'!
organizerOn: anObject
"Instantiate and bind the text organizer components and then
open for user interaction.
See class comment.'"
| window |
rootObject _ anObject.
(window _ TextOrganizerWindow labelled: 'Organizer')
model: self;
color: Color red.
window addMorph: (listMorph _ SimpleHierarchicalListMorph
on: self
list: #getList
selected: #getCurrentSelection
changeSelected: #noteNewSelection:
menu: #hierarchyMenu:
keystroke: nil)
frame: (0 at 0 corner: 1 at 0.66).
window addMorph: ((PluggableTextMorph on: self text: #text accept: #text:
readSelection: #contentsSelection menu: #codePaneMenu:shifted:)
askBeforeDiscardingEdits: true)
frame: (0 at 0.66 corner: 1 at 1).
listMorph autoDeselect: false.
^ window! !
!TextOrganizer methodsFor: 'private' stamp: 'SIM 5/7/2000 13:17'!
isIllegalRootActionCheck
"Check if current item is the root.
If it is inform the user that operation is illegal and answer true.
Otherwise answer false."
^currentSelection withoutListWrapper == rootObject
ifTrue: [
self inform: 'Can''t perform this action with root'.
true]
ifFalse: [false]! !
!TextOrganizer methodsFor: 'text pane' stamp: 'SIM 4/4/2000 16:04'!
codePaneMenu: aMenu shifted: shifted
"Note that unless we override perform:orSendTo:,
PluggableTextController will respond to all menu items"
^StringHolder basicNew
codePaneMenu: aMenu shifted: shifted
! !
!TextOrganizer methodsFor: 'text pane' stamp: 'SIM 4/17/2000 17:35'!
contentsSelection
"Return the interval of text in the code pane to
select when I set the pane's contents"
^textPaneSelection
"^1 to: 0" "null selection"! !
!TextOrganizer methodsFor: 'text pane' stamp: 'SIM 4/4/2000 16:04'!
doItContext
"Answer the context in which a text selection can be evaluated."
^nil! !
!TextOrganizer methodsFor: 'text pane' stamp: 'SIM 4/4/2000 16:04'!
doItReceiver
"Answer the object that should be informed of the result of evaluating a
text selection."
currentSelection ifNil: [^rootObject].
^currentSelection withoutListWrapper
! !
!TextOrganizer methodsFor: 'text pane' stamp: 'SIM 4/4/2000 16:05'!
selectedClass
"Answer the class of the receiver's current selection"
^self doItReceiver class
! !
!TextOrganizer methodsFor: 'text pane' stamp: 'SIM 3/1/2000 22:55'!
text
"What goes in the bottom pane"
^currentSelection
ifNil: ['']
ifNotNil: [currentSelection text]! !
!TextOrganizer methodsFor: 'text pane' stamp: 'SIM 4/17/2000 10:10'!
text: newText
"Set the text of the currentSelection to newText."
currentSelection
ifNotNil: [currentSelection text: newText asString].
^true
! !
!TextOrganizer class methodsFor: 'pasteBuffer' stamp: 'SIM 4/17/2000 13:54'!
pasteBuffer
"Answer pasteBuffer."
^pasteBuffer! !
!TextOrganizer class methodsFor: 'pasteBuffer' stamp: 'SIM 4/17/2000 13:54'!
pasteBuffer: aTreeNode
"Set pasteBuffer to aTreeNode."
pasteBuffer _ aTreeNode! !
!TextOrganizer class methodsFor: 'comments' stamp: 'SIM 4/16/2000 20:51'!
about
"Display the receiver's comment."
StringHolder new
textContents: self comment;
openLabel: 'about ', self asString
! !
!TextOrganizer class methodsFor: 'invoking' stamp: 'SIM 5/7/2000 17:17'!
initialNode
^OrganizerNode
name: 'Rename me or load saved organizer.'
text: ''
! !
!TextOrganizer class methodsFor: 'invoking' stamp: 'SIM 4/17/2000 14:43'!
open
"Open a TextOrganizer.
TextOrganizer open.
"
TextOrganizer new openOrganizerOn: self initialNode
! !
!TextOrganizer class methodsFor: 'invoking' stamp: 'SIM 4/18/2000 10:34'!
test
"Open a TextOrganizer on an arbritary hierachy derived from
the class hierarchy of class Magnitude.
or try:
TextOrganizer new openOrganizerOn: OrganizerNode getBigTree.
(slow for adds!!)"
TextOrganizer new openOrganizerOn:
(OrganizerNode
deriveHierarchyFrom: Magnitude
parents: #superclass
children: #subclasses
do: [: proto : node |
node
name: proto printString;
text: proto printString])
! !
!TextOrganizer class methodsFor: 'instance creation' stamp: 'SIM 4/17/2000 16:08'!
new
"Answer a new initialized instance of the receiver."
^super new initialize! !
!TextOrganizerNodeWrapper methodsFor: 'copied explorer methods' stamp: 'RAA 6/21/1999 15:48'!
canBeDragged
^false! !
!TextOrganizerNodeWrapper methodsFor: 'copied explorer methods' stamp: 'SIM 3/20/2000 16:46'!
contents
^item children
inject: OrderedCollection new
into: [: answer : child |
answer
add: (
TextOrganizerNodeWrapper
with: child);
yourself].
! !
!TextOrganizerNodeWrapper methodsFor: 'copied explorer methods' stamp: 'SIM 3/6/2000 20:49'!
hasContents
^self contents isEmpty not
! !
!TextOrganizerNodeWrapper methodsFor: 'copied explorer methods' stamp: 'SIM 3/20/2000 17:17'!
item: anObject
item _ anObject
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/17/2000 10:45'!
addChild: aTreeNodeWrapper
"Add a TreeNodeWrapper's item to the reciever's wrapped item.
Inturn wrap the newly created item and answer the wrapper."
item addChild: aTreeNodeWrapper withoutListWrapper.
^aTreeNodeWrapper
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/4/2000 17:12'!
addChildNamed: aString
"Add a new child named aString to the reciever's
warpped item. Inturn wrap the newly created item
and answer the wrapper."
^TextOrganizerNodeWrapper
with: (item addChildNamed: aString)
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/21/2000 16:39'!
addSiblingAfter: aTreeNodeWrapper
"Add a TreeNodeWrapper's item after the reciever's wrapped item."
item parent addChild: aTreeNodeWrapper withoutListWrapper after: item.
^aTreeNodeWrapper
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/21/2000 16:38'!
addSiblingBefore: aTreeNodeWrapper
"Add a TreeNodeWrapper's item before the reciever's wrapped item."
item parent addChild: aTreeNodeWrapper withoutListWrapper before: item.
^aTreeNodeWrapper
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 5/7/2000 12:50'!
asString
"Answer the wrapped item's name."
^item name
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/3/2000 11:57'!
children
"Answer the children of the wrapped item."
^item children! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/3/2000 11:59'!
deleteWithParentAdoptingChildren
"Delete the wrapped item from it's parent.
The parent adopts all of the newly orphaned children."
item deleteWithParentAdoptingChildren.
item _ nil
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/16/2000 16:09'!
interposeNewAboveNamed: aString
"Add a new child named aString to the receiver's
item's parent. The new child adopts the receiver's
item's children. "
^TextOrganizerNodeWrapper
with: (item interposeNewAboveNamed: aString)
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/16/2000 17:08'!
interposeNewBelowNamed: aString
"Add a new child named aString to the receiver's
item. The new child adopts the receiver's
item's children. "
^TextOrganizerNodeWrapper
with: (item interposeNewBelowNamed: aString)
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/3/2000 12:00'!
name
"Answer the wrapped item's name."
^item name! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 5/6/2000 16:04'!
name: aString
"Set the receiver's name to aString.
Convert tab's to spaces as tabs don't get displayed using SimpleHierarchicalListMorph."
| newStream |
newStream _ WriteStream on: String new.
aString do: [: char |
char == Character tab
ifFalse: [newStream nextPut: char]
ifTrue: [newStream nextPutAll: ' ']].
^item name: newStream contents! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/4/2000 17:04'!
parent
"Answer the parent of the wrapped item."
^item parent! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/17/2000 10:43'!
removeFromParent
"Remove the wrapped item (and by association all of it's children)
from it's parent."
item removeFromParent
! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 5/6/2000 14:39'!
sortChildren
"Sort the children of the wrapped item."
^item sortChildren! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 5/6/2000 14:49'!
sortChildrenRecursively
"Sort the children of the wrapped item, recursively."
^item sortChildrenRecursively! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/3/2000 12:02'!
text
"Answer the wrapped item's text."
^item text! !
!TextOrganizerNodeWrapper methodsFor: 'organizer' stamp: 'SIM 4/3/2000 12:03'!
text: aString
"Set the wrapped item's text to aText."
^item text: aString! !
!TextOrganizerNodeWrapper class methodsFor: 'as yet unclassified' stamp: 'SIM 3/20/2000 16:44'!
with: anObject
^self new
item: anObject
! !
!TextOrganizerWindow methodsFor: 'open/close' stamp: 'SIM 5/7/2000 14:16'!
delete
"Overide delete to check if it is ok by the model to close the window.
Current delete sends okToChange, which conflicts with changes in subpanes."
model okToClose ifFalse: [^false].
super delete! !
!TextOrganizerWindow reorganize!
('open/close' delete)
!
!TextOrganizerNodeWrapper reorganize!
('copied explorer methods' canBeDragged contents hasContents item:)
('organizer' addChild: addChildNamed: addSiblingAfter: addSiblingBefore: asString children deleteWithParentAdoptingChildren interposeNewAboveNamed: interposeNewBelowNamed: name name: parent removeFromParent sortChildren sortChildrenRecursively text text:)
!
!TextOrganizer class reorganize!
('pasteBuffer' pasteBuffer pasteBuffer:)
('comments' about)
('invoking' initialNode open test)
('instance creation' new)
!
!TextOrganizer reorganize!
('actions' addItem copyItem cutItem deleteWithParentAdoptingChildren deleteWithSubtree inspectItem interposeAbove interposeBelow loadOrganizer pasteItemAfter pasteItemBefore pasteItemBelow rename saveOrganizer sortChildren sortChildrenRecursively)
('constants' defaultFileName)
('finding' findText findTextNext foundString:withinNameOf:at: foundString:withinValueOf:at:)
('hierarchical list pane' getList hierarchyMenu: leftButtonPressed:onItem: leftButtonPressedInToggleArea:morph: noteNewSelection: rightButtonPressed:onItem: rightButtonPressedInToggleArea:morph:)
('initialise-release' initialize)
('open/close' okToClose openOrganizerOn: organizerOn:)
('private' isIllegalRootActionCheck)
('text pane' codePaneMenu:shifted: contentsSelection doItContext doItReceiver selectedClass text text:)
!
"Postscript:"
TextOrganizer about.
TextOrganizer open.
!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/ms-tnef
Size: 15894 bytes
Desc: not available
Url : http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20000509/b6a015e9/attachment.bin
More information about the Squeak-dev
mailing list
|