AppModel.st
author claus
Sat, 09 Sep 1995 04:30:16 +0200
changeset 100 0300e64bb883
parent 96 948318b2fbd4
child 114 e577a2f332d0
permissions -rw-r--r--
.

"
 COPYRIGHT (c) 1995 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

'From Smalltalk/X, Version:2.10.5 on 24-mar-1995 at 9:31:53 am'!

Model subclass:#ApplicationModel
	 instanceVariableNames:'builder resources'
	 classVariableNames:''
	 poolDictionaries:''
	 category:'Interface-Framework'
!

ApplicationModel class instanceVariableNames:'ClassResources'!

!ApplicationModel class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1995 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

version
"
$Header: /cvs/stx/stx/libview2/Attic/AppModel.st,v 1.16 1995-09-09 02:29:25 claus Exp $
"
!

documentation
"
    Since many ST-80 classes are subclasses of ApplicationModel, this class
    is provided here to allow easier porting of ST-80 code.

    It does not (currently) provide much functionality and is NOT
    compatible to the corresponding ST80 class; therefore, manual
    changes have to be made to get those applications to run under ST/X.
    (but at least, this enables you to fileIn that code and have a superclass
     for them)

    As time goes by, ST/X applications are going to be converted to
    become subclasses of this abstract class - see NewLauncher for a
    first concrete example.

    ApplicationModel is prepared to build a view from a windowSpec, as
    created by the windowBuilder. If you subclass does not provide such
    a spec, you should at least redefine:

	openInterface   - to create a topview and open it

    you may want to redefine:

	closeRequest    - to catch window closing
	focusSequence   - to define a sequence for focus-stepping


    The classResources have been put into this class to allow ST/X
    applications (which used to be subclasses of StandardSystemView)
    to migrate smoothly into ApplicationModels (which is better design ...).

    Instance variables:
	resources    ResourcePack       language string translation

	builder      WindowBuilder      a builder who knows how to create
					a window hierarchy from a specification


    Notice: this class was implemented using protocol information
    from alpha testers and PD code - it may not be complete or compatible to
    the corresponding ST-80 class. If you encounter any incompatibilities,
    please forward a note to the ST/X team.
"
! !

!ApplicationModel class methodsFor:'initialization'!

initialize 
    self == ApplicationModel ifTrue:[
	Smalltalk addDependent:self
    ]

    "
     ApplicationModel initialize
    "
! !

!ApplicationModel class methodsFor:'instance creation'!

new
    ^ super new basicInitialize initialize
! !

!ApplicationModel class methodsFor:'startup'!

open
    "create an instance of the application and open its view"

    self new open

    "
     self open
    "
!

openOn:anApplicationModel
    "I dont really understand what this method is useful for ..."

    anApplicationModel open
!

openOnDevice:aDevice
    "create an instance of the application and open its view
     on another device.
     EXPERIMENTAL and unfinished."

    self new openOnDevice:aDevice
!

openInterface:anInterfaceSymbol
    "create an instance of the application and open a view as
     specified by anInterfaceSymbol."

    self new openInterface:anInterfaceSymbol

    "Modified: 5.9.1995 / 17:54:50 / claus"
! !

!ApplicationModel class methodsFor:'change & update'!

update:something
    "flush resources on language changes"

    something == #Language ifTrue:[
	"flush resources on language changes"
	self flushAllClassResources
    ]
! !

!ApplicationModel class methodsFor:'queries'!

interfaceSpecFor:aSelector
    "return an interface spec"

    ^ self perform:aSelector
! !

!ApplicationModel class methodsFor:'resources'!

classResources
    "if not already loaded, get the classes resourcePack
     and return it"

    ClassResources isNil ifTrue:[
	ClassResources := ResourcePack for:self.
    ].
    ^ ClassResources
!

classResources:aResourcePack
    "allow setting of the classResources"

    ClassResources := aResourcePack
!

flushAllClassResources
    "flush all classes resource translations.
     Needed after a resource file / language setting has changed."

    ResourcePack flushCachedResourcePacks.
    self flushClassResources.
    self allSubclassesDo:[:aClass |
	aClass flushClassResources.
    ]
!

flushClassResources
    "flush classes resource string translations.
     Needed whenever a resource file / language setting has changed"

    ClassResources := nil.
!

updateClassResources
    "update my classResources"

    ClassResources := nil.
    self classResources
! !

!ApplicationModel methodsFor:'initialization'!

createBuilder 
    "create a UI Builder for me.
     This method can be redefined if (eventually) there are
     spec readers for other UI languages (motif UIL ?)"

    |cls|

    (cls := UIBuilder) isNil ifTrue:[
	(cls := WindowBuilder) isNil ifTrue:[
	    ^ nil
	]
    ].
    ^ cls new
!

basicInitialize
    "initialize the application.
     Since ST-80 applications seem commonly to redefine initialize
     without doing a super initialize, the real initialization is
     done here ..."

    super initialize.

    "claus: I wanted to delay the creation & assignment of the
     builder till later, to allow setting to another builder.
     however, some ST-80 code accesses the builder right after instance
     creation ..."

"/    "
"/     Create a windowBuilder to have someone around which
"/     understands the builder protocol. Since UIBuilder is not present
"/     in all systems, this allows operation without one (unless a spec
"/     is read later ...)
"/    "
    builder := self createBuilder.
    builder notNil ifTrue:[builder application:self].
    resources := self class classResources.
!

initialize
    "nothing done here;
     but can be redefined in concrete applications"
!

addTopViewsToCurrentProject
    "add all of my topViews to the current projects list of views.
     This allows hiding views on a per-project basis."

    self windowGroup topViews do:[:aView |
	aView addToCurrentProject
    ]
! !

!ApplicationModel methodsFor:'queries'!

processName
    "return a name to be shown for me in the process monitor"

    ^ 'Application'
! !

!ApplicationModel methodsFor:'startup'!

allButOpenInterface:aSymbol
    "create my views but do not open the main window"

    |spec|

    spec := self class interfaceSpecFor:aSymbol.
    self allButOpenFrom:spec.
    ^ builder
!

allButOpenFrom:aSpec
    "create my views but do not open the main window"

    |realBuilder|

"/ DISABLED; see comment in basicInitialize
"/
"/    "
"/     here, we kludge a bit: up to now, the builder was an
"/     instance of the no-op WindowBuilder. Now, it becomes
"/     a UIBuilder ....
"/     This allows for ApplicationModels without a UIBuilder
"/     if not needed.
"/    "
"/    realBuilder := UIBuilder new.
"/    builder := realBuilder.
"/    builder application:self.
"/    builder bindings:builder bindings.

    self preBuildWith:builder.
    builder buildFromSpec:aSpec.
    builder window model:self.
    builder window application:self.
    self postBuildWith:builder.
!

open
    "open a standard interface"

    self openInterface
!

openInterface
    "open a standard interface on another device.
     Subclasses which do not have an interfaceSpec 
     may want to redefine this method and create & open their view(s)
     there. (see NewLauncher as an example)."

    self openInterface:#windowSpec
!

openInterface:aSymbol
    "open an interface on another display; 
     the argument, aSymbol specifies which interface.
     Typically, applications only use one interface, 
     returned by the #windowSpec method."

    self allButOpenInterface:aSymbol.
    builder openWithExtent:nil.

    ^ builder
!

menuFor:aSymbol
    "create a new menuBuilder, to read specs and
     create a menu from it. Return this menu"

    |spec mbuilder|

    spec := self class interfaceSpecFor:aSymbol.
    mbuilder := UIBuilder new.
    mbuilder buildFromSpec:spec.

    builder componentAt:#windowMenuHolder put:(mbuilder window asValue).
    ^ mbuilder window
!

closeDownViews
    "close down the applications view"

    |wg views|

    (wg := self windowGroup) notNil ifTrue:[
	views := wg topViews.
	views notNil ifTrue:[
	    views copy do:[:aView |
		aView notNil ifTrue:[aView destroy]
	    ]
	]
    ]
!

close
    "this is sent by my topView when about to be closed
     by the program (not by the windowManager).
     Could be redefined in subclasses."

    self closeDownViews
!

closeRequest
    "this is sent by my topView when about to be closed by the
     windowmanager. Can be redefined to inform & query about unsafed
     view contents, to send #close on ok, or ignore the closeRequest."

    self closeDownViews
!

opened
    "this is sent by my topView when its finally open"

    self addTopViewsToCurrentProject.
    self postOpenWith:builder
!

restarted
    "sent by my windowGroup, when restarted from an image.
     Nothing done here, but can be redefined to perform any actions
     required to reset the application after an image-restart.
     (for example: check if application files are still around, restart
     subprocesses etc.)."
!

saveAndTerminateRequest
    "some windowManagers send this to shut down an application
     and have it save its state for restart.
     Can be redefined in subclasses"

    self closeRequest
!

preBuildWith:aBuilder
    "this is sent before an interface is built from a spec.
     Can be redefined in subclasses.
     mhmh - what should this do here ?"
!

postBuildWith:aBuilder
    "this is sent after an interface is built from a spec.
     Can be redefined in subclasses.
     mhmh - what should this do here ?"
!

postOpenWith:aBuilder
    "this is sent after the applications main window is opened.
     Can be redefined in subclasses.
     mhmh - what should this do here ?"
! !

!ApplicationModel methodsFor:'accessing'!

resources
    "return the applications resources - thats a ResourcePack containing
     language strings"

    ^ resources
!

window
    "return my topWindow"

    ^ builder window
!

windowGroup 
    "return the applications windowGroup"

    ^ builder window windowGroup
!

builder
    "return the applications builder; this one has more information
     about views, components etc."

    ^ builder
!

builder:aBuilder
    "set the applications builder. Normally, you should not set it
     directly, but depend on the default builder, as created when the application
     was created."

    builder := aBuilder
!

focusSequence
    "return a focusSequence for stepping through the applications views.
     The builder usually keeps track of so-called 'tabable' views.
     Stepping is done with the FocusNext/FocusPrevius keys, which are 
     typically bound to Meta-CursorUp/Meta-CursorDown.
     Subclasses which do not use the builder (but instead build their view
     programmatically) should redefine this method to return a collection of
     views which defines the sequence."

    builder notNil ifTrue:[
	^ builder focusSequence
    ].
    ^ nil
! !

!ApplicationModel methodsFor:'window events'!

windowEvent:anEvent from:anApplicationWindow
    ^ self
! !

!ApplicationModel methodsFor:'misc'!

withCursor:aCursor do:aBlock
    "evaluate aBlock, showing aCursor in my topView and all of its subviews.
     Return the value of aBlock."

    ^ self window withCursor:aCursor do:aBlock
!

withWaitCursorDo:aBlock
    "evaluate aBlock, showing a waitCursor in my topView and all of its subviews.
     Return the value of aBlock."

    ^ self withCursor:Cursor wait do:aBlock
! !