WorkspaceApplication.st
author Claus Gittinger <cg@exept.de>
Wed, 04 Sep 2002 23:07:43 +0200
changeset 3845 b4baee71ee18
parent 3812 fef8f2db9662
child 4031 4ace4ff5fbbd
permissions -rw-r--r--
no max size

"{ Package: 'stx:libtool' }"

ToolApplicationModel subclass:#WorkspaceApplication
	instanceVariableNames:'workspaces tabList selectedWorkspaceIndexHolder workspaceHolder
		autoDefineWorkspaceVariables'
	classVariableNames:'DefaultAutoDefineWorkspaceVariables LastFilterBlockString
		LastProcessingBlockString'
	poolDictionaries:''
	category:'Interface-Smalltalk'
!

!WorkspaceApplication class methodsFor:'documentation'!

documentation
"
    A simple wrapper around a WorkSpace-View, adding a pullDown menu.

    [author:]
        Claus Gittinger
"
! !

!WorkspaceApplication class methodsFor:'interface specs'!

windowSpec
    "This resource specification was automatically generated
     by the UIPainter of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the UIPainter may not be able to read the specification."

    "
     UIPainter new openOnClass:WorkspaceApplication andSelector:#windowSpec
     WorkspaceApplication new openInterface:#windowSpec
     WorkspaceApplication open
    "

    <resource: #canvas>

    ^ 
     #(#FullSpec
        #name: #windowSpec
        #window: 
       #(#WindowSpec
          #label: 'Workspace'
          #name: 'Workspace'
          #min: #(#Point 10 10)
          #bounds: #(#Rectangle 13 23 445 264)
          #menu: #mainMenu
        )
        #component: 
       #(#SpecCollection
          #collection: #(
           #(#NoteBookViewSpec
              #name: 'NoteBook1'
              #layout: #(#LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
              #model: #selectedWorkspaceIndexHolder
              #menu: #tabList
              #useIndex: true
              #accessTabMenuAction: #tabMenuAt:
              #canvas: #workspaceHolder
              #canvasInset: 0
              #canvasFrameLevel: 0
              #keepCanvasAlive: true
              #tabLevel: 2
            )
           )
         
        )
      )
! !

!WorkspaceApplication class methodsFor:'menu specs'!

mainMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

    "
     MenuEditor new openOnClass:WorkspaceApplication andSelector:#mainMenu
     (Menu new fromLiteralArrayEncoding:(WorkspaceApplication mainMenu)) startUp
    "

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'File'
            #translateLabel: true
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'New Workspace'
                  #translateLabel: true
                  #value: #newWorkspace
                )
               #(#MenuItem
                  #label: 'New SystemWorkspace'
                  #translateLabel: true
                  #value: #newSystemWorkspace
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'Load File...'
                  #translateLabel: true
                  #value: #menuLoad
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'Save As...'
                  #translateLabel: true
                  #value: #menuSaveAs
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'Exit'
                  #translateLabel: true
                  #value: #closeRequest
                )
               )
              nil
              nil
            )
          )
         #(#MenuItem
            #label: 'Buffers'
            #translateLabel: true
            #nameKey: #Buffer
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'Add Buffer'
                  #translateLabel: true
                  #value: #addWorkspace
                )
               #(#MenuItem
                  #label: 'Rename...'
                  #translateLabel: true
                  #value: #renameWorkspace
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'Remove Buffer'
                  #translateLabel: true
                  #value: #removeWorkspace
                  #enabled: #canRemoveWorkspace
                )
               )
              nil
              nil
            )
          )
         #(#MenuItem
            #label: 'Edit'
            #translateLabel: true
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'Copy'
                  #translateLabel: true
                  #value: #copySelection
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: 'Cut'
                  #translateLabel: true
                  #value: #cutSelection
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: 'Paste'
                  #translateLabel: true
                  #value: #paste
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'Filter Text...'
                  #translateLabel: true
                  #value: #filterText
                )
               #(#MenuItem
                  #label: 'Process Text...'
                  #translateLabel: true
                  #value: #processText
                )
               )
              nil
              nil
            )
          )
         #(#MenuItem
            #label: 'Workspace'
            #translateLabel: true
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'Add Workspace Variable...'
                  #translateLabel: true
                  #value: #addWorkspaceVariable
                )
               #(#MenuItem
                  #label: 'Remove Workspace Variable...'
                  #translateLabel: true
                  #value: #removeWorkspaceVariable
                  #enabled: #anyWorkspaceVariableIsDefined
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'Inspect Workspace Variables'
                  #translateLabel: true
                  #value: #inspectWorkspaceVariables
                  #enabled: #anyWorkspaceVariableIsDefined
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'Remove all Workspace Variables...'
                  #translateLabel: true
                  #value: #removeAllWorkspaceVariables
                  #enabled: #anyWorkspaceVariableIsDefined
                )
         #(#MenuItem
            #label: 'Settings'
            #translateLabel: true
            #isVisible: false
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'Autodefine Workspace Variables'
                  #translateLabel: true
                  #indication: #autoDefineWorkspaceVariables
                )
               )
              nil
              nil
            )
          )
               )
              nil
              nil
            )
          )
         #(#MenuItem
            #label: 'Smalltalk'
            #translateLabel: true
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'DoIt'
                  #translateLabel: true
                  #value: #doIt
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: 'PrintIt'
                  #translateLabel: true
                  #value: #printIt
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: 'InspectIt'
                  #translateLabel: true
                  #value: #inspectIt
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'TimeIt'
                  #translateLabel: true
                  #value: #timeIt
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: 'SpyOnIt'
                  #translateLabel: true
                  #value: #spyOnIt
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'Browse Class'
                  #translateLabel: true
                  #value: #browseIt
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: 'Browse Implementors of It'
                  #translateLabel: true
                  #value: #browseImplementorsOfIt
                  #enabled: #hasSelectionInActiveWorkspace
                )
               #(#MenuItem
                  #label: 'Browse References to It'
                  #translateLabel: true
                  #value: #browseReferencesToIt
                  #enabled: #hasSelectionInActiveWorkspace
                )
               )
              nil
              nil
            )
          )
         #(#MenuItem
            #label: 'Help'
            #translateLabel: true
            #startGroup: #right
            #submenu: 
           #(#Menu
              #(
               #(#MenuItem
                  #label: 'Documentation'
                  #translateLabel: true
                  #value: #openDocumentation
                )
               #(#MenuItem
                  #label: '-'
                )
               #(#MenuItem
                  #label: 'About this Application...'
                  #translateLabel: true
                  #value: #openAboutThisApplication
                )
               )
              nil
              nil
            )
          )
         )
        nil
        nil
      )
!

tabMenu
    "This resource specification was automatically generated
     by the MenuEditor of ST/X."

    "Do not manually edit this!! If it is corrupted,
     the MenuEditor may not be able to read the specification."

    "
     MenuEditor new openOnClass:WorkspaceApplication andSelector:#tabMenu
     (Menu new fromLiteralArrayEncoding:(WorkspaceApplication tabMenu)) startUp
    "

    <resource: #menu>

    ^ 
     #(#Menu
        #(
         #(#MenuItem
            #label: 'Add Buffer'
            #translateLabel: true
            "/ #triggerOnDown: true
            #value: #addWorkspace
          )
         #(#MenuItem
            #label: 'Rename...'
            #translateLabel: true
            "/ #triggerOnDown: true
            #value: #renameWorkspace:
          )
         #(#MenuItem
            #label: '-'
          )
         #(#MenuItem
            #label: 'Remove Buffer'
            #translateLabel: true
            "/ #triggerOnDown: true
            #value: #removeWorkspace:
            #enabled: #canRemoveWorkspace:
          )
         )
        nil
        nil
      )
! !

!WorkspaceApplication class methodsFor:'special startup'!

openSystemWorkspace
    |wsApp licenceView path needRemove|

    needRemove := true.

    wsApp := self new.
    wsApp allButOpen.
    wsApp window extent:640@400.

    path := (Smalltalk getSystemFileName:'README') ?  '../../README'.
    (path notNil and:[path asFilename exists]) ifTrue:[
        wsApp addWindow:(HVScrollableView for:Workspace) named:'README' asFirst:false.
        wsApp loadFile:path.
        wsApp removeWorkspace:1.  "/ the original Workspace
        needRemove := false.
    ].

"/    path := (Smalltalk getSystemFileName:'doc/online/english/LICENCE_STX.html') ?  '../../doc/online/english/LICENCE_STX.html'.
"/    path asFilename exists ifTrue:[
"/        wsApp addWindow:(licenceView := HVScrollableView for:HTMLDocumentView) named:'License' asFirst:false.
"/        licenceView homeDocument:'../../doc/online/english/LICENCE_STX.html'.
"/        licenceView updateLabelFlag:false.
"/        needRemove ifTrue:[wsApp removeWorkspace:1].  "/ the original Workspace
"/        needRemove := false.
"/    ].

    path := (Smalltalk getSystemFileName:'Keyboard.wsp').
    (path notNil and:[path asFilename exists]) ifTrue:[
        wsApp addWindow:(HVScrollableView for:Workspace) named:'Keyboard' asFirst:false.
        wsApp loadFile:path.
        needRemove ifTrue:[wsApp removeWorkspace:1].  "/ the original Workspace
        needRemove := false.
    ].

    path := (Smalltalk getSystemFileName:'Hello.wsp').
    (path notNil and:[path asFilename exists]) ifTrue:[
        wsApp addWindow:(HVScrollableView for:Workspace) named:'Welcome' asFirst:false.
        wsApp loadFile:path.
        needRemove ifTrue:[wsApp removeWorkspace:1].  "/ the original Workspace
        needRemove := false.
    ].

    wsApp openWindow

    "
     self openSystemWorkspace
    "
! !

!WorkspaceApplication methodsFor:'accessing'!

selectedWorkspace
    |wsIndex|

    workspaces isNil ifTrue:[
        workspaces := OrderedCollection new.
    ].
    wsIndex := self selectedWorkspaceIndexHolder value.
    wsIndex == 0 ifTrue:[
        ^ nil
    ].

    workspaces size < wsIndex ifTrue:[
        workspaces grow:wsIndex.
        workspaces at:wsIndex put:(HVScrollableView for:Workspace).
    ].
    ^ workspaces at:wsIndex
!

tabMenuAt:index
    |m i ws|

    m := self class tabMenu.
    m := m decodeAsLiteralArray.
    i := m detectItem:[:item | item value == #removeWorkspace:] ifNone:nil.
    i notNil ifTrue:[
        i argument:index.
        index ~~ self selectedWorkspaceIndexHolder value ifTrue:[
            "/ for now: if that buffer is modified,
            "/ do not allow removing.
            "/ (must be brought to front, in order for check-for-modification to work)
            ws := workspaces at:index.
            (ws isKindOf:ScrollableView) ifTrue:[
                ws := ws scrolledView
            ].
            ((ws isKindOf:TextView) not
            or:[ ws modified ])
            ifTrue:[
                i disable
            ].
        ].
    ].
    i := m detectItem:[:item | item value == #renameWorkspace:] ifNone:nil.
    i notNil ifTrue:[
        i argument:index.
    ].

    m findGuiResourcesIn:self.
    ^ m
!

workspaceHolder
    workspaceHolder isNil ifTrue:[
        workspaceHolder := ValueHolder with:(self selectedWorkspace).
    ].
    ^ workspaceHolder
! !

!WorkspaceApplication methodsFor:'aspects'!

autoDefineWorkspaceVariables
    "does not work yet - needs more interaction with parser"

    autoDefineWorkspaceVariables isNil ifTrue:[
        autoDefineWorkspaceVariables := DefaultAutoDefineWorkspaceVariables asValue.
        autoDefineWorkspaceVariables onChangeSend:#autoDefineWorkspaceVariablesChanged to:self.
    ].
    ^ autoDefineWorkspaceVariables.
!

selectedWorkspaceIndexHolder
    selectedWorkspaceIndexHolder isNil ifTrue:[
        selectedWorkspaceIndexHolder := 1 asValue.
        selectedWorkspaceIndexHolder onChangeSend:#workspaceSelectionChanged to:self.
    ].
    ^ selectedWorkspaceIndexHolder.
!

tabList
    tabList isNil ifTrue:[
        tabList := List new.
    ].
    ^ tabList.
! !

!WorkspaceApplication methodsFor:'aspects - queries'!

anyWorkspaceVariableIsDefined
    ^ Workspace workspaceVariables size > 0
!

canRemoveWorkspace
    ^ self canRemoveWorkspace:(self selectedWorkspaceIndexHolder value)
!

canRemoveWorkspace:idx
    ^ self tabList size > 1
"/       and:[ (self workspacesTextViewAt:(self selectedWorkspaceIndexHolder value))
!

hasSelectionInActiveWorkspace
    ^ self selectedWorkspacesTextView selectionAsString size > 0
! !

!WorkspaceApplication methodsFor:'initialization & release'!

closeRequest
    (self askIfModified:'Text was modified. Close anyway ?' yesButton:'Close') ifFalse:[
        ^ self
    ].

    ^ super closeRequest
! !

!WorkspaceApplication methodsFor:'menu actions'!

addWindow:aWindow named:name
    self addWindow:aWindow named:name asFirst:false
!

addWindow:aWindow named:name asFirst:asFirst
    |tabList wsIndex newSelectedIndex|

    tabList := self tabList.
    wsIndex := tabList size + 1.
    wsIndex == 1 ifTrue:[
        "/ first - add a name for the first tab
        tabList add:(self window label). "/ 'Workspace'.
        wsIndex := wsIndex + 1.
    ].

    workspaces grow:wsIndex.
    asFirst ifTrue:[
        tabList addFirst:(name bindWith:wsIndex).
        workspaces replaceFrom:2 to:wsIndex with:workspaces startingAt:1.
        newSelectedIndex := 1.
    ] ifFalse:[
        tabList addLast:(name bindWith:wsIndex).
        newSelectedIndex := wsIndex.
    ].
    workspaces at:newSelectedIndex put:aWindow.
    self selectedWorkspaceIndexHolder value:newSelectedIndex.   
"/    workspaceHolder value:aWindow.
!

addWorkspace
    self addWindow:(HVScrollableView for:Workspace) named:'Workspace%1'
!

addWorkspaceVariable
    |name selection|

    selection := self selectedWorkspacesTextView selection ? ''.

    name := Dialog 
                request:'Name of new Workspace Variable:'
                initialAnswer:(selection asString string)
                okLabel:'Add'
                title:'Enter Variable Name'.
    name size == 0 ifTrue:[
        ^ self
    ].
    Workspace addWorkspaceVariable:name.
!

askForFilterBlock:message template:template rememberIn:nameOfClassVar
    |filterBlockString filterBlock dialog textHolder classVarValue|

    classVarValue := self class classVarAt:nameOfClassVar ifAbsent:nil.
    classVarValue isNil ifTrue:[
        self class classVarAt:nameOfClassVar put:template. 
        classVarValue := template.
    ].

    textHolder := ValueHolder new.
    dialog := Dialog 
                 forRequestText:(resources string:message)
                 lines:25 
                 columns:70
                 initialAnswer:classVarValue
                 model:textHolder.
    dialog addButton:(Button label:'Template' action:[textHolder value:template. textHolder changed:#value.]).
    dialog open.
    dialog accepted ifFalse:[^ nil].

    filterBlockString := textHolder value.
    self class classVarAt:nameOfClassVar put:filterBlockString. 

    filterBlock := Parser evaluate:filterBlockString.
    filterBlock isBlock ifFalse:[
        self halt:'oops - bad input'.
        ^ nil
    ].

    ^ filterBlock
!

autoDefineWorkspaceVariablesChanged
    "does not work yet - needs more interaction with parser"

    |doAutoDefine|

    doAutoDefine := autoDefineWorkspaceVariables value.

    DefaultAutoDefineWorkspaceVariables := doAutoDefine.
    workspaces do:[:each |
        each autoDefineWorkspaceVariables:doAutoDefine
    ].
!

basicInspectIt
    self inspectIt:true
!

browseImplementorsOfIt
    self selectedWorkspacesTextView browseImplementorsOfIt
!

browseIt
    self selectedWorkspacesTextView browseIt
!

browseReferencesToIt
    self selectedWorkspacesTextView browseReferencesToIt
!

copySelection
    self selectedWorkspacesTextView copySelection
!

cutSelection
    self selectedWorkspacesTextView cutSelection
!

doIt
    self selectedWorkspacesTextView doIt
!

filterText
    |template filterBlock newList oldList answer nDeleted deletedLines|

    template :=
'"/ general text filter;
"/ the following block should evaluate to true for all lines
"/ you want to keep - lines for which the block returns false will be removed.
"/ Beginner warning: Smalltalk know-how is useful here.

[:line |
     "/ any condition on line.
     "/ Notice, that line might be a Text object (i.e. non-string),
     "/ so you may want to use line string.
     "/ 
     "/ Useful queries on the line are:
     "/     - size                   the length of the line
     "/     - hasChangeOfEmphasis    any bold, italic etc.
     "/     - startsWith:someString
     "/     - endsWith:someString

     "/ example filter (removes all empty lines)
     "/
     "/ line size > 0

     "/ example filter (removes all lines which do not end with some suffix)
     "/
     "/ (line asLowercase endsWith:''foo'') not

     "/ dummy filter (keeps all lines)
     "/
     true
]
'.

    filterBlock := self askForFilterBlock:'Filter block:'
                        template:template
                        rememberIn:#LastFilterBlockString.
    filterBlock isNil ifTrue:[^ self].

    oldList := self selectedWorkspacesTextView list.
    oldList := oldList collect:[:lineOrNil | lineOrNil ? ''].
    newList := oldList select:filterBlock.
    newList := newList collect:[:line | (line isString and:[line size == 0]) ifTrue:[nil] ifFalse:[line]].
    nDeleted := oldList size - newList size.
    nDeleted == 0 ifTrue:[
        self information:'No lines were deleted.'.
        ^ self
    ].

    answer := Dialog confirmWithCancel:(resources 
                        string:'%1 lines remain (%2 deleted). Change text ?'
                        with:newList size
                        with:nDeleted)
                labels:#( 'Cancel' 'No, Show Deleted' 'Yes').
    answer isNil ifTrue:[^ self].
    answer ifFalse:[
        deletedLines := oldList reject:filterBlock.
        TextBox openOn:(deletedLines asStringCollection) title:'Filtered lines'.
        ^ self.
    ].

    self selectedWorkspacesTextView list:newList.
!

inspectIt
    self inspectIt:false
!

inspectIt:basic
    |ws obj v|

    ws := self selectedWorkspacesTextView.
    ws
        do:(ws selection) 
        withValueDo:[:result | 
                        | cls resultString|

                        basic ifFalse:[
                            cls := result inspectorClass.
                        ].
                        cls isNil ifTrue:[
                            cls := InspectorView
                        ].
                        v := cls new.
                        v inspect:result.
                        "/ v allowFollow:true.
                        result isBehavior ifTrue:[
                            resultString := result name
                        ] ifFalse:[
                            resultString := result classNameWithArticle
                        ].
                        self addWindow:v named:('Inspecting: ' , resultString).
                    ]

"/    self selectedWorkspace inspectIt
!

inspectWorkspaceVariables
    |wsvars|

    wsvars := Workspace workspaceVariables.
    wsvars size == 0 ifTrue:[
        Dialog information:'No Workspace Variables are defined'.
        ^ self
    ].
    wsvars inspect
!

loadFile:aFileName 
    |file ws lbl|

    file := aFileName asFilename.
    (ws := self selectedWorkspacesTextView) contents:file contents.
    ws modified:false.

    lbl := file withoutSuffix baseName.
    tabList size <= 1 ifTrue:[
        self window label:lbl.
    ] ifFalse:[
        tabList at:self selectedWorkspaceIndexHolder value put:lbl
    ]
!

menuLoad
    |file|

    (self askIfModified:'Text was modified. Load anyway ?' yesButton:'Load') ifFalse:[ ^ self].

    file := Dialog requestFileName:'Load file:' default:'file.wsp' pattern:'*.wsp'.
    file size > 0 ifTrue:[
        self loadFile:file
    ]
!

menuSaveAs
    |file ws doAppend|

    doAppend := false.
    Dialog aboutToOpenBoxNotificationSignal handle:[:n |
        |box|

        box := n parameter.
        box addButton:(Button label:'Append'
                            action:[doAppend := true. box okPressed]).
        n proceed.
    ] do:[
        file := Dialog requestFileName:'Save file:' default:'file.wsp'. 
    ].

    file size > 0 ifTrue:[
        (ws := self selectedWorkspacesTextView) saveAs:file doAppend:doAppend.
        ws modified:false.
    ]
!

newSystemWorkspace
    self class openSystemWorkspace
!

newWorkspace
    self class open
!

openDocumentation
    "opens the documentation file"

    self openHTMLDocument: 'tools/misc/TOP.html#WORKSPACE'
!

paste
    self selectedWorkspacesTextView paste
!

printIt
    self selectedWorkspacesTextView printIt
!

processText
    |template filterBlock newList oldList answer nChanged changedLines flags|

    template :=
'"/ general text processor;
"/ the following block should evaluate to a new line, 
"/ given the original line as argument.
"/ Beginner warning: Smalltalk know-how is useful here.

[:line |
     "/ any processing on line.
     "/ Notice, that line might be a Text object (i.e. non-string),
     "/ 
     "/ Useful operations on the line are:
     "/     - '' .... '' ,                      concatenation of any prefix/suffix
     "/     - leftPaddedTo:size                 padding
     "/     - rightPaddedTo:size                padding
     "/     - copyTo:(size min:N)               
     "/     - asUppercase 
     "/     - asLowercase

     "/ makes everything bold
     "/
     "/ line allBold

     "/ dummy filter (keeps all lines as-is)
     "/
     line
]
'.
    filterBlock := self askForFilterBlock:'Processing block:'
                        template:template
                        rememberIn:#LastProcessingBlockString.
    filterBlock isNil ifTrue:[^ self].

    oldList := self selectedWorkspacesTextView list.
    oldList := oldList collect:[:lineOrNil | lineOrNil ? ''].
    newList := oldList collect:filterBlock.
    newList := newList collect:[:line | (line isString and:[line size == 0]) ifTrue:[nil] ifFalse:[line]].

    flags := (1 to:oldList size) collect:[:i | (oldList at:i) ~= (newList at:i)].
    flags := flags select:[:flag | flag].
    nChanged := flags size.
    nChanged == 0 ifTrue:[
        self information:'No lines were changed.'.
        ^ self
    ].

    answer := Dialog confirmWithCancel:(resources 
                        string:'%1 lines changed. Change text ?'
                        with:nChanged)
                labels:#( 'Cancel' 'No, Show Changed' 'Yes').
    answer isNil ifTrue:[^ self].
    answer ifFalse:[
        changedLines := (1 to:oldList size) select:[:i | (oldList at:i) ~= (newList at:i)].
        changedLines := changedLines collect:[:i | (newList at:i)].
        TextBox openOn:(changedLines asStringCollection) title:'Changed lines'.
        ^ self.
    ].

    self selectedWorkspacesTextView list:newList.
!

removeAllWorkspaceVariables
    (Dialog confirm:'Do you really want to remove all Workspace Variables ?')
    ifTrue:[
        Workspace removeAllWorkspaceVariables
   ].
!

removeWorkspace
    self removeWorkspace:(self selectedWorkspaceIndexHolder value)
!

removeWorkspace:wsIndex
    |tabList newWsIndex|

    wsIndex == self selectedWorkspaceIndexHolder value ifTrue:[
        (self askIfModified:'Text was modified. Remove anyway ?' yesButton:'Remove') ifFalse:[
            ^ self
        ].
    ].

    tabList := self tabList.

    wsIndex == tabList size ifTrue:[
        newWsIndex := wsIndex - 1.
    ] ifFalse:[
        newWsIndex := wsIndex.
    ].

    tabList removeIndex:wsIndex.
    (workspaces at:wsIndex) destroy.
    workspaces removeIndex:wsIndex.

    tabList size == 1 ifTrue:[
        self window label:(tabList at:1).
        tabList removeIndex:1
    ].

    workspaceHolder value:(workspaces at:newWsIndex).
    self selectedWorkspaceIndexHolder value:newWsIndex.
    "/ to force change (update workspaceHolder - even if same index)
    self selectedWorkspaceIndexHolder changed:#value.   
!

removeWorkspaceVariable
    |name selection wsvars|

    wsvars := Workspace workspaceVariables.
    wsvars size == 0 ifTrue:[
        Dialog information:'No Workspace Variables are defined'.
        ^ self
    ].

    selection := self selectedWorkspacesTextView selection ? ''.

    name := Dialog 
                request:'Variable to remove:'
                initialAnswer:(selection asString string)
                okLabel:'Remove'
                title:'Enter Variable Name'
                list:(wsvars keys asOrderedCollection sort).      
    name size == 0 ifTrue:[
        ^ self
    ].
    Workspace removeWorkspaceVariable:name.
!

renameWorkspace
    self renameWorkspace:(self selectedWorkspaceIndexHolder value)
!

renameWorkspace:wsIndex
    |tabList oldName newName|

    tabList := self tabList.
    tabList isEmpty ifTrue:[
        oldName := self window label
    ] ifFalse:[
        oldName := tabList at:wsIndex.
    ].
    newName := Dialog request:(resources string:'New Name for %1:' with:oldName) initialAnswer:oldName.
    newName size == 0 ifTrue:[ ^ self].

    tabList notEmpty ifTrue:[
        tabList at:wsIndex put:newName.
    ].
    wsIndex == self selectedWorkspaceIndexHolder value ifTrue:[
        self window label:newName.
    ].
!

spyOnIt
    self selectedWorkspacesTextView spyOnIt
!

timeIt
    self selectedWorkspacesTextView timeIt
! !

!WorkspaceApplication methodsFor:'private'!

askIfModified:question yesButton:yesButtonText
    "tell user, that code has been modified - let her confirm"

    |textView|

    textView := self selectedWorkspace.
    (textView isKindOf:ScrollableView) ifTrue:[
        textView := textView scrolledView
    ].
    (textView isKindOf:TextView) ifFalse:[
        ^ true
    ].
    (textView modified not 
    or:[textView contentsWasSaved
    or:[textView contents withoutSeparators isEmpty]]) ifTrue:[
        ^ true
    ].
    (Dialog 
        confirm:(resources string:question) withCRs
        yesLabel:(resources at:yesButtonText)
        noLabel:(resources at:'Cancel'))
    ifTrue:[
        "/ reset modified flag so question is asked only once
        textView modified:false.
        ^ true
    ].
    ^ false

    "Modified: 2.10.1997 / 14:23:47 / stefan"
!

selectedWorkspacesTextView
    |textView|

    textView := self selectedWorkspace.
    (textView isKindOf:ScrollableView) ifTrue:[
        textView := textView scrolledView
    ].
    (textView isKindOf:TextView) ifTrue:[
        ^ textView
    ].
    ^ textView workspace
!

workspaceSelectionChanged
    |wsIndex windowLabel v|

    "/ self selected
    self workspaceHolder value:(v := self selectedWorkspace).
    wsIndex := self selectedWorkspaceIndexHolder value.

    wsIndex ~~ 0 ifTrue:[
        windowLabel := tabList at:wsIndex ifAbsent:nil.
        windowLabel notNil ifTrue:[self window label:windowLabel].
    ].
! !

!WorkspaceApplication class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libtool/WorkspaceApplication.st,v 1.36 2002-09-04 21:07:43 cg Exp $'
! !