parent previous next question (Smalltalk Textbook 18)

EngiTextModel

Appendix 08 is a text editor (EngiTextModel) which supports text alignment,indentation, line spacing, tab, fonts and color.

'file in' Appendix 08 then evaluate example 1. You see two windows labeled 'Text'. These text editors are the same as the standard Smalltalk editor, but with additional features. The yellow-button-menu has 'file', 'style', and 'color'. 'file' has a sub-menu which contains 'new', 'open', 'save', 'print'. 'style' has a sub-menu which contains 'align', 'indent', 'lead', 'tab', 'font'. 'file > new' opens a new text editor. 'file > open' prompts for a file name and opens a text editor with it. 'file > save' prompts for a file name then saves the text you are editing to the file in BOSS (Binary Object Streaming Service) form.

Three objects are stored in the file. First is a class name (aSymbol), second is a text (aText), third is text attributes (aTextAttributes). 'file > print' is left as an exercise to the reader. An easy way to implement 'file > print' is to create a postscript file. It shouldn't be too hard for you change the 'file > save' program to 'file > print' which stores the postscript file, because you already understand about font attributes and text attributes. As an intermediate step, look up ComposedText private > hardcopy. A simple implementation for print:from: is

print: aText from: aController
        aText asComposedText hardcopy

'style > align' cycles through left-, right-, and center alignment. 'style > indent' prompts for three values (first, rest, right) used to indent the first line, the rest of the text, and the right margin. 'style > lead' prompts for a value for leading paragraph spacing. 'style > tab' sets tab stops. 'style > font' lets you choose a font using 'EngiFontModel' we made in a previous section.

The 'color' menu changes the color of highlighted text using 'EngiColorModel'.

Multiple interfaces (views and controllers) connected to the same model (text editor) are synchronized when you select 'accept' or 'save'. Otherwise editing is only local to a particular view.

There are seven utility messages for 'EngiTextModel' as shown here. Execute each message expression to see how it works.


Program-18-1: (EngiTextModel; request:, requestComposedText:, 
requestString:, selectTextAttributes)
---------------------------------------------------------------
EngiTextModel request: 'message'
EngiTextModel request: 'message' default: 'default'
EngiTextModel requestComposedText: 'message' default: 'default'
EngiTextModel requestString: 'message' default: 'default'
EngiTextModel requestText: 'message' default: 'default'
EngiTextModel selectTextAttributes
EngiTextModel selectTextAttributes: TextAttributes default
---------------------------------------------------------------

'EngiFontModel' in the last section also has 'selectTextAttributes' and 'selectTextAttributes:'. 'EngiTextModel' has more features for alignment, indentation, line spacing, and tab setting. 'EngiFontModel' uses default text attributes and only supports font attribute changes.

The argument for 'request:', though any object is allowed, is usually a prompt string. Execute following message expressions to see how other objects work.


Program-18-2: (EngiTextModel; request:)
---------------------------------------------
EngiTextModel request: Image fromUser
EngiTextModel request: Point zero
---------------------------------------------

Now, let's investigate some of the details. 'EngiTextModel' inherits instance variables 'dependents' and 'value' from superclasses 'EngiVariable' and 'Model'. 'EngiTextModel' defines no other instance variables. However 'EngiTextModel' can still hold text to edit (text) and text attributes (style). Examine the messages in the 'accessing' category to see how this is done. 'EngiVariable' allows at: and at:put: messages by creating an array and using that as the value. The actual text and the attributes are stored as the first and second items in an array. But from the outside you only see 'text', 'text:', 'style', and ' style:'. 'text:aText' and 'style:aTextAttributes' are hidden.

Messages in 'viewing' and 'adaptor' categories use pluggable MVC of 'TextView' and 'TextController'. I won't describe this now because it was covered in the 'PluggableMVC' section. The 'propagate' message in the 'private' category handles multiple views and controllers, because when an instance of 'EngiTextModel ' calls 'changed: #text', instances of 'Textview' and 'TextController' only check for '#text' but not '#style' updates.

Messages in the 'menu messages' category are invoked by the yellow button menu. You can get the text and controller by specifying a message which has two arguments (ex. align:from:) as a menu value. If you specify a message which has only one argument, you'll receive only the text as argument.

Finally, 'inspect' 'EngiTextModel example 1' instead of 'do it'. You will see two windows titled 'Text' and an inspector window which has an instance of 'EngiTextModel'. Evaluate these two message expressions one by one in the inspector.


Program-18-3: (EngiTextModel; request:, style:, selectTextAttributes)
----------------------------------------------------------
self text: (self class request: 'Text?')
self style: self class selectTextAttributes
----------------------------------------------------------

You can ascertain that more than one interface (views and controllers) will work together, even if you send messages to the model directly instead of working through several window interfaces. Testing like this is common in Smalltalk programming.


parent previous next question
Copyright (C) 1994-1996 by Atsushi Aoki
Translated by Kaoru Rin Hayashi & Brent N. Reeves