'From Squeak3.2alpha of 3 October 2001 [latest update: #4586] on 11 December 2001 at 11:00:00 am'! "Change Set: stackFeatures-sw Date: 11 December 2001 Author: Scott Wallace Adds five new commands to the black-dot menu for a Stack. The primary intent here is to ease the importing of external data into a Squeak 'Stack': ¥ 'add cards from clipboard' - Provides a mechanism for importing records from tab- and return-delimited strings such as can be obtained from word processors, spreadsheets, etc.. The data are expected to be one card's worth per line, with the data order on each line being exactly the same as the order of the instance variables in the cardPlayer, and with values for successive fields being separated by tabs, and with return characters demarcating the lines. To get the instance variables of your card to correspond in the correct order with the data you are importing, you might need to use the next command: ¥ 'change inst var order' - Provides a ui for rearranging the order of instance variables in the uniclass of a stack. ¥ 'be defaults for new cards' - A one-touch UI for making the current values seen on a card become the defaults for their respective fields in new instances ¥ 'sort cards by...' Lets you sort the cards in the stack on any single sort key. ¥ 'delete all cards *except* this one' - Allows you quickly to cleanse a stack of unwanted cruft."! !Player methodsFor: 'slots-kernel' stamp: 'sw 12/6/2001 21:57'! absorbBackgroundDataFrom: aLine forInstanceVariables: slotNames "Fill my background fields from the substrings in a tab-delimited line of data. At the moment this only really cateres to string-valued items" slotNames doWithIndex: [:aSlotName :anIndex | aLine do: [:aValue | self instVarNamed: aSlotName put: aValue] toFieldNumber: anIndex]! ! !CardPlayer class methodsFor: 'user-defined inst vars' stamp: 'sw 12/6/2001 20:36'! resortInstanceVariables: newList "Accept a new ordering for instance variables" variableDocks _ newList collect: [:aName | variableDocks detect: [:d | d variableName = aName]]. self setNewInstVarNames: newList asOrderedCollection. self newVariableDocks: variableDocks. ! ! !CardPlayer class methodsFor: 'variable docks' stamp: 'sw 12/6/2001 21:37'! variableDockFor: aVariableName "Answer the variable dock corresponding to the given variable name" ^ self variableDocks detect: [:d | d variableName = aVariableName]! ! !StackMorph methodsFor: 'menu' stamp: 'sw 12/6/2001 22:08'! invokeBookMenu "Invoke the book's control panel menu." | aMenu | aMenu _ MenuMorph new defaultTarget: self. aMenu addTitle: 'Stack'. aMenu addStayUpItem. aMenu addList: #( ('find...' textSearch) ('find via this template' findViaTemplate) ('show designations' showDesignationsOfObjects) ('explain designations' explainDesignations) "('look inside' openInsideLook)" - ('previous card' goToPreviousCardInStack) ('next card' goToNextCardInStack) ('first card' goToFirstCardOfStack) ('last card' goToLastCardOfStack) ('go to card...' goToCard) - ('add a card of this background' insertCard) ('add a card of background...' insertCardOfBackground) ('make a new background...' makeNewBackground) - ('add cards from clipboard data' addCardsFromClipboardData) ('change inst var order' changeInstVarOrder) ('be defaults for new cards' beDefaultsForNewCards) ('sort cards by...' sortCards) - ('delete this card' deleteCard) ('delete all cards *except* this one' deleteAllCardsExceptThisOne) - ('move card to front of stack' makeCurrentCardFirstInStack) ('move card to back of stack' makeCurrentCardLastInStack) ('move card one position earlier' moveCardOnePositionEarlier) ('move card one position later' moveCardOnePositionLater) - ('scripts for this background' browseCardClass) - ('debug...' offerStackDebugMenu) ('bookish items...' offerBookishMenu)). aMenu addUpdating: #showingPageControlsString action: #toggleShowingOfPageControls. aMenu addUpdating: #showingFullScreenString action: #toggleFullScreen. aMenu popUpEvent: self world activeHand lastEvent in: self world ! ! !StackMorph methodsFor: 'background' stamp: 'sw 12/6/2001 19:33'! addCardsFromClipboardData "Using the current background, paste data from the (textual) clipboard to create new records. The fields " self addCardsFromClipboardDataForInstanceVariables: self currentCard slotNames! ! !StackMorph methodsFor: 'background' stamp: 'sw 12/6/2001 21:58'! addCardsFromClipboardDataForInstanceVariables: slotNames "Using the current background, paste data from the (textual) clipboard to create new records. The fields " | clip count | (clip _ Clipboard clipboardText) isEmptyOrNil ifTrue: [^ self beep]. count _ 0. clip asString linesDo: [:aLine | aLine size > 0 ifTrue: [count _ count + 1. self insertCardOfBackground: self currentPage withDataFrom: aLine forInstanceVariables: slotNames]]. self inform: count asString, ' card(s) added' ! ! !StackMorph methodsFor: 'background' stamp: 'sw 12/6/2001 21:26'! beDefaultsForNewCards "Make the values that I see here all be accepted as defaults for new cards" self currentPage submorphs do: [:aMorph | aMorph holdsSeparateDataForEachInstance ifTrue: [aMorph setAsDefaultValueForNewCard]]! ! !StackMorph methodsFor: 'background' stamp: 'sw 12/6/2001 21:20'! changeInstVarOrder "Change the order of the receiver's instance variables" | reply | reply _ FillInTheBlank request: 'rearrange, then accept; or cancel' initialAnswer: self currentPage player class instVarNames asString. reply isEmptyOrNil ifTrue: [^ self]. self flag: #deferred. "Error checking and graceful escape wanted" self currentPage player class resortInstanceVariables: (Compiler evaluate: reply) ! ! !StackMorph methodsFor: 'background' stamp: 'sw 12/6/2001 22:31'! sortByField: varName "Perform a simple reordering of my cards, sorting by the given field name. If there are multiple backgrounds, then sort the current one, placing all its cards first, followed by all others in unchanged order" | holdCards thisClassesInstances sortedList | holdCards _ cards copy. thisClassesInstances _ cards select: [:c | c isKindOf: self currentCard class]. sortedList _ thisClassesInstances asSortedCollection: [:a :b | (a instVarNamed: varName) asString <= (b instVarNamed: varName) asString]. sortedList _ sortedList asOrderedCollection. holdCards removeAllFoundIn: sortedList. cards _ sortedList asOrderedCollection, holdCards. self goToFirstCardOfStack ! ! !StackMorph methodsFor: 'background' stamp: 'sw 12/6/2001 22:08'! sortCards "Let the user provide an inst var on which to sort the cards of a background." | names aMenu | names _ self currentPage player class instVarNames. aMenu _ MenuMorph new defaultTarget: self. aMenu addTitle: 'Choose field by which to sort:'. names do: [:n | aMenu add: n selector: #sortByField: argument: n]. aMenu popUpInWorld! ! !StackMorph methodsFor: 'card access' stamp: 'sw 12/6/2001 21:18'! deleteAllCardsExceptThisOne "Delete all cards except the current one" cards size <= 1 ifTrue: [^ self beep]. (self confirm: 'Really delete ', cards size asString, ' card(s) and all of their data?') ifTrue: [cards _ OrderedCollection with: self currentCard].! ! !StackMorph methodsFor: 'card access' stamp: 'sw 12/6/2001 21:13'! insertCardOfBackground: aBackground withDataFrom: aLine forInstanceVariables: slotNames "Insert a new card of the given background and have it become the current card. " | newCard | newCard _ aBackground newCard. cards add: newCard after: self currentCard. newCard absorbBackgroundDataFrom: aLine forInstanceVariables: slotNames. self goToCard: newCard! ! !String methodsFor: 'accessing' stamp: 'sw 12/6/2001 16:08'! do: aBlock toFieldNumber: aNumber "Considering the receiver as a holder of tab-delimited fields, evaluate aBlock on behalf of a field in this string" | start end index | start _ 1. index _ 1. [start <= self size] whileTrue: [end _ self indexOf: Character tab startingAt: start ifAbsent: [self size + 1]. end _ end - 1. aNumber = index ifTrue: [aBlock value: (self copyFrom: start to: end). ^ self]. index _ index + 1. start _ end + 2] " 1 to: 6 do: [:aNumber | 'fred charlie elmo wimpy friml' do: [:aField | Transcript cr; show: aField] toFieldNumber: aNumber] "! ! !String methodsFor: 'accessing' stamp: 'sw 12/6/2001 21:30'! tabDelimitedFieldsDo: aBlock "Considering the receiver as a holder of tab-delimited fields, evaluate execute aBlock with each field in this string. The separatilng tabs are not included in what is passed to aBlock" | start end | "No senders but was useful enough in earlier work that it's retained for the moment." start _ 1. [start <= self size] whileTrue: [end _ self indexOf: Character tab startingAt: start ifAbsent: [self size + 1]. end _ end - 1. aBlock value: (self copyFrom: start to: end). start _ end + 2] " 'fred charlie elmo 2' tabDelimitedFieldsDo: [:aField | Transcript cr; show: aField] "! !