PerforceSourceCodeManagementSettingsAppl.st
changeset 9837 ed120c35e09b
child 9846 646dc5b511fe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PerforceSourceCodeManagementSettingsAppl.st	Tue Apr 19 10:29:32 2011 +0200
@@ -0,0 +1,1133 @@
+"{ Package: 'stx:libtool' }"
+
+AbstractSettingsApplication subclass:#P4SourceCodeManagementSettingsAppl
+	instanceVariableNames:'sourceCacheDir listOfModules removeEnabled acceptChannel
+		selectedPerModuleRoot verboseSourceCodeAccess
+		perforceExecutableHolder listOfPerforceModules
+		defaultSettingsHolder tableColumns defaultSettingsPrototypeList'
+	classVariableNames:'RecentlyUsedCVSRoots RecentlyUsedStoreHosts
+		RecentlyUsedSmallTeamHosts LastStoreHost LastStoreUser
+		LastStorePassword'
+	poolDictionaries:''
+	category:'Interface-Smalltalk'
+!
+
+ApplicationModel subclass:#ManagerPerModuleApp
+	instanceVariableNames:'moduleHolder acceptChannel settingsHolder
+		sourceCodeManagementSettingsApp acceptEnableChannel canceled
+		defaultSettingsPrototypeList'
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:P4SourceCodeManagementSettingsAppl
+!
+
+Object subclass:#ModuleManager
+	instanceVariableNames:'manager module settings'
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:P4SourceCodeManagementSettingsAppl
+!
+
+
+!P4SourceCodeManagementSettingsAppl class methodsFor:'image specs'!
+
+defaultIcon
+    "This resource specification was automatically generated
+     by the ImageEditor of ST/X."
+
+    "Do not manually edit this!! If it is corrupted,
+     the ImageEditor may not be able to read the specification."
+
+    "
+     self defaultIcon inspect
+     ImageEditor openOnClass:self andSelector:#defaultIcon
+     Icon flushCachedIcons
+    "
+
+    <resource: #image>
+
+    ^Icon
+        constantNamed:#'AbstractSettingsApplication::SourceCodeManagementSettingsAppl class defaultIcon'
+        ifAbsentPut:[(Depth8Image new) width: 22; height: 22; photometric:(#palette); bitsPerSample:(#(8 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'
+@@@@@@@@@@@A@PHB@0P@@@@@@@@@@@@@@@@@@@HEA \HA $JB0HD@@@@@@@@@@@@@@HLA04NC0HD@@L@@ P@@@@@@@@@@@@ED@ NDP@@@@@@@@@D@@@@@@@@
+@@@BA \FAPP@@@@@@@@@@@P@@@@@@@@@AQ@RC0@@@@@@@@@@@@@@@@@@@@@@@@TGA!!DD@@@@@@@@@@@@@@@@@@@D@PDIA08OA@@@@@@@@@@@@@@@@@@@AP S
+A0XIBPXGC0P@@@@@@@@@@@@@@@@ECAPLBPXOAP@@@@@@EQX@@@@@@@@@@@TIE@XOAP@@@@@@EQ\XE @@@@@@@@@@AP$OAP@@@@@@FQ\ZE!! V@@@@@@@@@@@E
+F0@@@@@@EQ\ZF!!(VFAX@@@@@@@@@@@@@@@@ZEQ\VE!!(ZF!!XWF @@@@@@@@@@@@@@@@@@@A\ZE!!(@@@@@@@@@@@@@@@@@@@@@@@@XE!!XZ@@@@@@@@@@@@@@@@
+@@@@@@@@EQ(V@@@@@@@@@@@@@@@@@@@@@@@@EQ\VE @@@@@@@@@@@@@@@@@@@@@@EQ VE @@@@@@@@@@@@@@F @@@@@WEQ VE!!(@@@@@@@@@@@@@@@@@E!!\W
+EQXVE @@@@@@@@@@@@@@@@@@@@@@@A(Z@@@@@@@@@@@@@@@a') ; colorMapFromArray:#[0 0 0 32 64 0 0 64 0 32 32 0 0 32 0 32 96 32 96 192 128 192 224 192 160 224 160 32 128 64 64 96 64 64 96 32 32 160 64 160 224 192 64 160 96 32 128 32 224 224 224 64 128 64 160 192 160 224 224 192 32 160 96 160 160 160 64 64 64 96 96 96 128 128 128 192 192 192 32 32 32 32 64 32]; mask:((ImageMask new) width: 22; height: 22; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@O8@@?>@A??@A?C C<@0C8@PC8@@??@@??F@_>O@O<_ G8?0C1?8A#?<@C?<@@_@H@_@L@?@GC>@C?>@A?<@@_0@') ; yourself); yourself]
+! !
+
+!P4SourceCodeManagementSettingsAppl 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:P4SourceCodeManagementSettingsAppl andSelector:#windowSpec
+     P4SourceCodeManagementSettingsAppl new openInterface:#windowSpec
+     P4SourceCodeManagementSettingsAppl open
+    "
+
+    <resource: #canvas>
+
+    ^ 
+     #(FullSpec
+        name: windowSpec
+        window: 
+       (WindowSpec
+          label: 'Source Code Manager Settings'
+          name: 'Source Code Manager Settings'
+          min: (Point 10 10)
+          bounds: (Rectangle 0 0 726 653)
+        )
+        component: 
+       (SpecCollection
+          collection: (
+           (VerticalPanelViewSpec
+              name: 'VerticalPanel2'
+              layout: (LayoutFrame 0 0.0 0 0.0 0 1.0 0 1.0)
+              horizontalLayout: fit
+              verticalLayout: topSpace
+              horizontalSpace: 3
+              verticalSpace: 20
+              component: 
+             (SpecCollection
+                collection: (
+                 (VerticalPanelViewSpec
+                    name: 'VerticalPanel3'
+                    horizontalLayout: fit
+                    verticalLayout: top
+                    horizontalSpace: 3
+                    verticalSpace: 4
+                    component: 
+                   (SpecCollection
+                      collection: (
+                       (ViewSpec
+                          name: 'Box3'
+                          component: 
+                         (SpecCollection
+                            collection: (
+                             (LabelSpec
+                                label: 'Perforce Command or Path:'
+                                name: 'Label22'
+                                layout: (LayoutFrame 0 0.0 59 0 60 0.25 81 0)
+                                level: 0
+                                translateLabel: true
+                                adjust: right
+                              )
+                             (InputFieldSpec
+                                name: 'EntryField8'
+                                layout: (LayoutFrame 66 0.25 59 0 -5 1 81 0)
+                                tabable: true
+                                model: perforceExecutableHolder
+                                acceptChannel: acceptChannel
+                                acceptOnPointerLeave: true
+                              )
+                             (LabelSpec
+                                label: 'Default Perforce Root'
+                                name: ''
+                                layout: (LayoutFrame 0 0.0 22 0 60 0.25 44 0)
+                                level: 0
+                                translateLabel: true
+                                adjust: right
+                              )
+                             (LabelSpec
+                                label: 'client:user:pass@host:port '
+                                name: 'Label18'
+                                layout: (LayoutFrame 4 0.0 40 0 64 0.25 55 0)
+                                style: (FontDescription helvetica medium roman 10)
+                                level: 0
+                                translateLabel: true
+                                adjust: right
+                              )
+                             (ComboBoxSpec
+                                name: 'cvsRootComboBox'
+                                layout: (LayoutFrame 66 0.25 28 0 -5 1 50 0)
+                                tabable: true
+                                model: defaultSettingsHolder
+                                immediateAccept: true
+                                acceptOnLeave: true
+                                acceptOnReturn: true
+                                acceptOnTab: true
+                                acceptOnLostFocus: true
+                                acceptChannel: acceptChannel
+                                acceptOnPointerLeave: true
+                                comboList: defaultSettingsPrototypeList
+                              )
+                             )
+                           
+                          )
+                          extent: (Point 726 105)
+                        )
+                       (ViewSpec
+                          name: 'ManagerSetupBoxx'
+                          component: 
+                         (SpecCollection
+                            collection: (
+                             (FramedBoxSpec
+                                label: 'Per Module Manager Setup'
+                                name: 'PerModuleManagerSetup'
+                                layout: (LayoutFrame 0 0 -1 0 0 1 -3 1)
+                                labelPosition: topLeft
+                                translateLabel: true
+                                component: 
+                               (SpecCollection
+                                  collection: (
+                                   (DataSetSpec
+                                      name: 'Table1'
+                                      layout: (LayoutFrame 5 0 5 0 0 1 180 0)
+                                      model: selectedPerModuleRoot
+                                      hasHorizontalScrollBar: true
+                                      hasVerticalScrollBar: true
+                                      dataList: listOfModules
+                                      useIndex: false
+                                      columnHolder: tableColumns
+                                    )
+                                   (HorizontalPanelViewSpec
+                                      name: 'HorizontalPanel11'
+                                      layout: (LayoutFrame 5 0 -25 1 -1 1 0 1)
+                                      horizontalLayout: fitSpace
+                                      verticalLayout: center
+                                      horizontalSpace: 3
+                                      verticalSpace: 3
+                                      component: 
+                                     (SpecCollection
+                                        collection: (
+                                         (ActionButtonSpec
+                                            label: 'Add/Apply'
+                                            name: 'Button2'
+                                            translateLabel: true
+                                            tabable: true
+                                            model: addPerModuleRoot
+                                            extent: (Point 340 22)
+                                          )
+                                         (ActionButtonSpec
+                                            label: 'Remove'
+                                            name: 'Button3'
+                                            translateLabel: true
+                                            tabable: true
+                                            model: removePerModuleRoot
+                                            enableChannel: removeEnabled
+                                            extent: (Point 341 22)
+                                          )
+                                         )
+                                       
+                                      )
+                                    )
+                                   )
+                                 
+                                )
+                              )
+                             )
+                           
+                          )
+                          extent: (Point 726 250)
+                        )
+                       (FramedBoxSpec
+                          label: 'Source Cache'
+                          name: 'FramedBox2'
+                          labelPosition: topLeft
+                          translateLabel: true
+                          component: 
+                         (SpecCollection
+                            collection: (
+                             (ViewSpec
+                                name: 'Box4'
+                                layout: (LayoutFrame 0 0 0 0 0 1 30 0)
+                                component: 
+                               (SpecCollection
+                                  collection: (
+                                   (LabelSpec
+                                      label: 'Source Cache Dir:'
+                                      name: 'Label23'
+                                      layout: (LayoutFrame 0 0.0 0 0 60 0.25 22 0)
+                                      translateLabel: true
+                                      adjust: right
+                                    )
+                                   (InputFieldSpec
+                                      name: 'EntryField9'
+                                      layout: (LayoutFrame 64 0.25 0 0 0 1 22 0)
+                                      model: sourceCacheDir
+                                      immediateAccept: false
+                                      acceptOnReturn: true
+                                      acceptOnTab: true
+                                      acceptOnLostFocus: true
+                                      acceptOnPointerLeave: true
+                                    )
+                                   )
+                                 
+                                )
+                              )
+                             (HorizontalPanelViewSpec
+                                name: 'HorizontalPanel12'
+                                layout: (LayoutFrame 44 0.25 33 0 0 1 67 0)
+                                horizontalLayout: fitSpace
+                                verticalLayout: center
+                                horizontalSpace: 3
+                                verticalSpace: 3
+                                component: 
+                               (SpecCollection
+                                  collection: (
+                                   (ActionButtonSpec
+                                      label: 'Flush Cache now'
+                                      name: 'Button4'
+                                      translateLabel: true
+                                      tabable: true
+                                      model: flushSourceCache
+                                      extent: (Point 234 22)
+                                    )
+                                   (ActionButtonSpec
+                                      label: 'Condense Cache now'
+                                      name: 'Button5'
+                                      translateLabel: true
+                                      tabable: true
+                                      model: condenseSourceCache
+                                      extent: (Point 235 22)
+                                    )
+                                   )
+                                 
+                                )
+                              )
+                             )
+                           
+                          )
+                          extent: (Point 726 95)
+                        )
+                       (ViewSpec
+                          name: 'VerboseBox'
+                          component: 
+                         (SpecCollection
+                            collection: (
+                             (CheckBoxSpec
+                                label: 'Verbose (Trace Access on Transcript)'
+                                name: 'CheckBox6'
+                                layout: (LayoutFrame 30 0 5 0 -5 1 27 0)
+                                model: verboseSourceCodeAccess
+                                translateLabel: true
+                              )
+                             )
+                           
+                          )
+                          extent: (Point 726 25)
+                        )
+                       )
+                     
+                    )
+                    extent: (Point 726 768)
+                  )
+                 )
+               
+              )
+            )
+           )
+         
+        )
+      )
+! !
+
+!P4SourceCodeManagementSettingsAppl class methodsFor:'tableColumns specs'!
+
+tableColumns
+    "This resource specification was automatically generated
+     by the DataSetBuilder of ST/X."
+
+    "Do not manually edit this!! If it is corrupted,
+     the DataSetBuilder may not be able to read the specification."
+
+    "
+     DataSetBuilder new openOnClass:P4SourceCodeManagementSettingsAppl andSelector:#tableColumns
+    "
+
+    <resource: #tableColumns>
+
+    ^#(
+      (DataSetColumnSpec
+         label: 'Module'
+         labelButtonType: Button
+         usePreferredWidth: true
+         model: module
+       )
+      (DataSetColumnSpec
+         label: 'Settings'
+         labelButtonType: Button
+         editorType: InputField
+         model: settings
+         isResizeable: false
+       )
+      )
+    
+! !
+
+!P4SourceCodeManagementSettingsAppl methodsFor:'actions'!
+
+addModule:aModuleManager
+
+    |detectedManager|
+
+    detectedManager := self listOfModules detect:[:eachModuleManager| eachModuleManager module = aModuleManager module] ifNone:nil.
+    detectedManager isNil ifTrue:[
+        self listOfModules add:aModuleManager; sort.
+        self updateModifiedChannel.
+    ] ifFalse:[
+        Dialog information:'Manager for Module ', aModuleManager module, ' already exists'.
+    ].
+
+
+    "Created: / 08-11-2006 / 19:25:21 / cg"
+!
+
+addModule:module withData:data
+    (self listOfModules includes:module) ifFalse:[
+        self listOfModules add:module; sort.
+    ].
+
+    self updateModifiedChannel.
+
+    "Created: / 08-11-2006 / 19:25:21 / cg"
+!
+
+addPerModuleRoot
+
+    |app moduleManager|
+
+    app := ManagerPerModuleApp openFromSourceCodeManagementSettingsApp:self.
+    app canceled ifFalse:[
+        moduleManager := ModuleManager new.
+        app moduleHolder value isEmptyOrNil ifTrue:[
+            self information:'Adding without module name not allowed'.
+            ^ self.
+        ].
+        moduleManager module:app moduleHolder value.
+        moduleManager settings:app settingsHolder value.
+        self listOfModules add:moduleManager.
+        self updateModifiedChannel.
+    ].
+    "Modified: / 08-11-2006 / 19:27:39 / cg"
+!
+
+basicReadSettings
+    |moduleManager moduleAndSettings|
+
+    self initialize.
+
+    self defaultSettingsHolder value:PerforceSourceCodeManager getPerforceDefaultSettingsString.
+    self listOfModules removeAll.
+    moduleAndSettings := PerforceSourceCodeManager repositoryInfoPerModule copy.
+    moduleAndSettings notEmptyOrNil ifTrue:[
+        moduleAndSettings keysAndValuesDo:[:module :settings|
+            moduleManager := ModuleManager new.
+            moduleManager module:module.
+            moduleManager settings:settings.
+            self listOfModules add:moduleManager.
+        ].
+    ].
+    self listOfModules sort.
+
+    self hasManager ifTrue:[
+        self sourceCacheDir value:(PerforceSourceCodeManager cacheDirectoryName).
+    ].
+
+    self perforceExecutableHolder value:PerforceSourceCodeManager perforceExecutable.
+
+"/    self selectedPerModuleRootChanged.
+
+    "Modified: / 21-09-2006 / 16:52:47 / cg"
+!
+
+basicSaveSettings
+    |client settings repositoryInfoPerModule|
+
+    self hasManager ifTrue:[
+        | nm fn|
+
+        nm := self sourceCacheDir value.
+        nm notEmptyOrNil ifTrue:[
+            (fn := nm asFilename) exists ifFalse:[
+                (self confirm:('Perforce cache directory ''' , nm , ''' does not exist\create ?' withCRs)) ifTrue:[
+                    fn makeDirectory; 
+                       makeReadableForAll;
+                       makeWritableForAll;
+                       makeExecutableForAll.
+                ]
+            ].
+            (fn isDirectory
+            and:[fn isReadable
+            and:[fn isWritable]]) ifTrue:[
+                PerforceSourceCodeManager cacheDirectoryName:nm.
+            ] ifFalse:[
+                self warn:'Invalid sourceCache directory.'
+            ]
+        ].
+        repositoryInfoPerModule := Dictionary new.
+        self listOfModules do:[:aModuleManager|
+            repositoryInfoPerModule at:aModuleManager module put:aModuleManager settings.
+        ].
+
+        PerforceSourceCodeManager repositoryInfoPerModule:repositoryInfoPerModule.
+        PerforceSourceCodeManager perforceExecutable:((self perforceExecutableHolder value ? '') withoutSeparators).
+        client := self defaultSettingsHolder value.
+        client notNil ifTrue:[
+            settings := PerforceSourceCodeManager getPerforceSettingsFromString:client.
+            PerforceSourceCodeManager perforceClient:(settings at:#client ifAbsent:nil).
+            PerforceSourceCodeManager perforceUser:(settings at:#user ifAbsent:nil).
+            PerforceSourceCodeManager perforcePort:(settings at:#port ifAbsent:nil).
+            PerforceSourceCodeManager perforcePassword:(settings at:#password ifAbsent:nil).
+        ].
+
+    ].
+
+    self acceptChannel value.
+
+    "Modified: / 09-11-2006 / 14:56:52 / cg"
+!
+
+condenseSourceCache
+    self withWaitCursorDo:[ AbstractSourceCodeManager condenseSourceCache ].
+    Method flushSourceStreamCache.
+
+    "Modified: / 28-11-2006 / 12:21:33 / cg"
+!
+
+flushSourceCache
+    self withWaitCursorDo:[ AbstractSourceCodeManager flushSourceCache ].
+    Method flushSourceStreamCache.
+
+    "Modified: / 28-11-2006 / 12:21:21 / cg"
+!
+
+removePerModuleRoot
+
+    |module|
+
+    acceptChannel value:true.    
+    module := self selectedPerModuleRoot value.
+    self listOfModules remove:module ifAbsent:nil.
+    self updateModifiedChannel.
+! !
+
+!P4SourceCodeManagementSettingsAppl methodsFor:'aspects'!
+
+acceptChannel
+
+    acceptChannel isNil ifTrue:[
+        acceptChannel := TriggerValue new.
+    ].
+    ^ acceptChannel.
+!
+
+defaultSettingsHolder
+
+    defaultSettingsHolder isNil ifTrue:[
+        defaultSettingsHolder := ValueHolder new.
+        defaultSettingsHolder addDependent:self.
+    ].
+    ^ defaultSettingsHolder.
+!
+
+defaultSettingsPrototypeList
+
+    defaultSettingsPrototypeList isNil ifTrue:[
+        defaultSettingsPrototypeList := self perforcePrototypeList.
+    ].
+    ^ defaultSettingsPrototypeList.
+!
+
+listOfModules
+
+    listOfModules isNil ifTrue:[  
+        listOfModules := List new.
+        listOfModules addDependent:self.
+    ].
+    ^ listOfModules.
+!
+
+perforceExecutableHolder
+    perforceExecutableHolder isNil ifTrue:[
+        perforceExecutableHolder := ValueHolder new.
+        perforceExecutableHolder onChangeSend:#updateModifiedChannel to:self
+    ].
+    ^ perforceExecutableHolder.
+
+    "Created: / 21-09-2006 / 15:37:06 / cg"
+!
+
+perforcePrototypeList
+
+    |first client|
+
+    client := PerforceSourceCodeManager perforceClient.
+    client isEmptyOrNil ifTrue:[
+        client := 'workspace'.
+    ].
+    first := (client ,':', PerforceSourceCodeManager perforceUser, ':', 
+                           (PerforceSourceCodeManager perforcePassword ? 'pass'), '@',
+                           PerforceSourceCodeManager perforcePort).
+    ^ Array with:first.
+!
+
+removeEnabled
+
+    removeEnabled isNil ifTrue:[
+        removeEnabled := false asValue.
+    ].
+    ^ removeEnabled.
+!
+
+selectedPerModuleRoot
+    selectedPerModuleRoot isNil ifTrue:[
+        selectedPerModuleRoot := ValueHolder new.
+        selectedPerModuleRoot addDependent:self.
+    ].
+    ^ selectedPerModuleRoot.
+!
+
+sourceCacheDir
+    sourceCacheDir isNil ifTrue:[
+        sourceCacheDir := ValueHolder new.
+        sourceCacheDir onChangeSend:#updateModifiedChannel to:self
+    ].
+    ^ sourceCacheDir.
+!
+
+tableColumns
+    <resource: #uiAspect>
+
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept it in the browser."
+    "*** (and replace this comment by something more useful ;-)"
+
+    tableColumns isNil ifTrue:[
+        tableColumns := self class tableColumns asValue.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+"/       tableColumns addDependent:self.
+"/       tableColumns onChangeSend:#tableColumnsChanged to:self.
+    ].
+    ^ tableColumns.
+!
+
+verboseSourceCodeAccess
+    verboseSourceCodeAccess isNil ifTrue:[
+        verboseSourceCodeAccess := false asValue.
+        verboseSourceCodeAccess onChangeSend:#updateModifiedChannel to:self
+    ].
+    ^ verboseSourceCodeAccess.
+! !
+
+!P4SourceCodeManagementSettingsAppl methodsFor:'change & update'!
+
+selectedPerModuleRootChanged
+
+    self removeEnabled value:self selectedPerModuleRoot value notNil.
+!
+
+sourceDirChanged
+    | nm fn|
+
+    nm := self sourceCacheDir value.
+    nm isEmptyOrNil ifTrue:[^ self].
+
+    (fn := nm asFilename) exists ifFalse:[
+        (self confirm:('SourceCache directory ''' , nm , ''' does not exist.\Create ?' withCRs)) ifTrue:[
+            fn makeDirectory; 
+               makeReadableForAll;
+               makeWritableForAll;
+               makeExecutableForAll.
+        ] ifFalse:[
+            self sourceCacheDir value:(AbstractSourceCodeManager cacheDirectoryName).
+            ^ self.
+        ].
+    ].
+    (fn isDirectory
+    and:[fn isReadable
+    and:[fn isWritable]]) ifTrue:[
+        AbstractSourceCodeManager cacheDirectoryName:nm.
+    ] ifFalse:[
+        self warn:'Invalid sourceCache directory.'.
+        self sourceCacheDir value:(AbstractSourceCodeManager cacheDirectoryName).
+    ].
+!
+
+update:something with:aParameter from:changedObject 
+    "/ common    
+    changedObject == sourceCacheDir ifTrue:[
+        self sourceDirChanged.
+        self updateModifiedChannel.
+        ^ self
+    ].
+
+    changedObject == selectedPerModuleRoot ifTrue:[
+        self selectedPerModuleRootChanged.
+        ^ self
+    ].
+
+    changedObject == self listOfModules ifTrue:[
+        self updateModifiedChannel.
+    ].
+
+    changedObject == defaultSettingsHolder ifTrue:[
+        self updateModifiedChannel.
+    ].
+
+
+    super update:something with:aParameter from:changedObject
+
+    "Modified: / 09-11-2006 / 14:41:10 / cg"
+!
+
+updateConnectEnableHolders
+
+
+    |userPassAndHost sel|
+
+    userPassAndHost := self getStoreElementsFromSettingsString:self defaultSettingsHolder value.
+    self storeConnectEnabled 
+        value:(userPassAndHost first notEmptyOrNil
+               and:[ userPassAndHost second notEmptyOrNil
+               and:[ userPassAndHost third notEmptyOrNil ]]).
+
+    sel := self selectedPerModuleRoot value.
+    sel notEmptyOrNil ifTrue:[
+        (sel managerClass = StoreSourceCodeManager) ifTrue:[
+            userPassAndHost := self getStoreElementsFromSettingsString:sel settings.
+            self storeConnectInModuleEnabled 
+                value:(userPassAndHost first notEmptyOrNil
+                       and:[ userPassAndHost second notEmptyOrNil
+                       and:[ userPassAndHost third notEmptyOrNil ]]).
+            ^ self.
+        ].
+    ].
+! !
+
+!P4SourceCodeManagementSettingsAppl methodsFor:'help'!
+
+helpFilename
+    ^ 'Launcher/cvsSetup.html'
+! !
+
+!P4SourceCodeManagementSettingsAppl methodsFor:'initialization & release'!
+
+initialize
+    (AbstractSourceCodeManager notNil) ifTrue:[ AbstractSourceCodeManager autoload ].
+
+    sourceCacheDir := nil asValue.
+    sourceCacheDir addDependent:self.
+
+    super initialize.
+
+    "Modified: / 08-11-2006 / 19:20:32 / cg"
+! !
+
+!P4SourceCodeManagementSettingsAppl methodsFor:'queries'!
+
+hasManager
+    "true if ANY source code management class is available"
+
+    ^ PerforceSourceCodeManager notNil and:[PerforceSourceCodeManager isLoaded]
+!
+
+hasUnsavedChanges
+
+    |repositoryInfoPerModule client settings|
+
+    client := self defaultSettingsHolder value.
+    client notNil ifTrue:[
+        settings := PerforceSourceCodeManager getPerforceSettingsFromString:client.
+self halt.
+        PerforceSourceCodeManager perforceClient ~= (settings at:#client ifAbsent:nil) ifTrue:[
+            ^ true
+        ].
+        PerforceSourceCodeManager perforceUser ~= (settings at:#user ifAbsent:nil) ifTrue:[
+            ^ true
+        ].
+        PerforceSourceCodeManager perforcePort ~= (settings at:#port ifAbsent:nil) ifTrue:[
+            ^ true
+        ].
+        PerforceSourceCodeManager perforcePassword ~= (settings at:#password ifAbsent:nil) ifTrue:[
+            ^ true
+        ].
+    ].
+
+    repositoryInfoPerModule := Dictionary new.
+    self listOfModules do:[:aModuleManager|
+        repositoryInfoPerModule at:aModuleManager module put:aModuleManager settings.
+    ].
+
+    PerforceSourceCodeManager repositoryInfoPerModule keysAndValuesDo:[:module :info |
+        ((repositoryInfoPerModule includesKey:module) and:[info = (repositoryInfoPerModule at:module)])
+        ifFalse:[^ true].
+    ].
+    repositoryInfoPerModule keysAndValuesDo:[:module :info|
+        ((PerforceSourceCodeManager repositoryInfoPerModule includesKey:module) and:[(PerforceSourceCodeManager repositoryInfoPerModule at:module) = info])
+        ifFalse:[^ true].
+    ].
+            
+    ^ false
+
+    "Modified: / 09-11-2006 / 14:49:14 / cg"
+!
+
+repositoryInfoPerModuleFor:sourceCodeManager
+
+    |repositoryInfoPerModule|
+
+    repositoryInfoPerModule := Dictionary new.
+    self listOfModules do:[:aModuleManager|
+        repositoryInfoPerModule at:aModuleManager module put:aModuleManager settings.
+    ].
+    ^ repositoryInfoPerModule
+! !
+
+!P4SourceCodeManagementSettingsAppl::ManagerPerModuleApp class methodsFor:'instance creation'!
+
+openFromSourceCodeManagementSettingsApp:something
+
+    |inst|
+
+    inst := self new.
+    inst sourceCodeManagementSettingsApp:something.
+    inst openModal.
+    ^ inst
+! !
+
+!P4SourceCodeManagementSettingsAppl::ManagerPerModuleApp 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:P4SourceCodeManagementSettingsAppl::ManagerPerModuleApp andSelector:#windowSpec
+     P4SourceCodeManagementSettingsAppl::ManagerPerModuleApp new openInterface:#windowSpec
+     P4SourceCodeManagementSettingsAppl::ManagerPerModuleApp open
+    "
+
+    <resource: #canvas>
+
+    ^ 
+     #(FullSpec
+        name: windowSpec
+        window: 
+       (WindowSpec
+          label: 'Manager per Module'
+          name: 'Manager per Module'
+          min: (Point 10 10)
+          max: (Point 1024 768)
+          bounds: (Rectangle 0 0 653 100)
+        )
+        component: 
+       (SpecCollection
+          collection: (
+           (VerticalPanelViewSpec
+              name: 'VerticalPanel1'
+              layout: (LayoutFrame 0 0 0 0 -5 1 -30 1)
+              horizontalLayout: fit
+              verticalLayout: topSpace
+              horizontalSpace: 3
+              verticalSpace: 3
+              component: 
+             (SpecCollection
+                collection: (
+                 (HorizontalPanelViewSpec
+                    name: 'HorizontalPanel1'
+                    horizontalLayout: leftFit
+                    verticalLayout: center
+                    horizontalSpace: 3
+                    verticalSpace: 3
+                    component: 
+                   (SpecCollection
+                      collection: (
+                       (LabelSpec
+                          label: 'Module:'
+                          name: 'Label16'
+                          translateLabel: true
+                          adjust: right
+                          extent: (Point 180 17)
+                        )
+                       (InputFieldSpec
+                          name: 'EntryField7'
+                          tabable: true
+                          model: moduleHolder
+                          acceptChannel: acceptChannel
+                          acceptOnPointerLeave: true
+                          extent: (Point 463 22)
+                        )
+                       )
+                     
+                    )
+                    extent: (Point 648 23)
+                  )
+                 (HorizontalPanelViewSpec
+                    name: 'HorizontalPanel4'
+                    horizontalLayout: leftFit
+                    verticalLayout: topSpace
+                    horizontalSpace: 3
+                    verticalSpace: 3
+                    component: 
+                   (SpecCollection
+                      collection: (
+                       (ViewSpec
+                          name: 'Box1'
+                          component: 
+                         (SpecCollection
+                            collection: (
+                             (LabelSpec
+                                label: 'Manager Info'
+                                name: 'Label18'
+                                layout: (LayoutFrame 0 0 0 0 149 0 16 0)
+                                translateLabel: true
+                                adjust: right
+                              )
+                             (LabelSpec
+                                label: 'client:user:pass@host:port '
+                                name: 'Label19'
+                                layout: (LayoutFrame 0 0 14 0 180 0 29 0)
+                                style: (FontDescription helvetica medium roman 10)
+                                level: 0
+                                translateLabel: true
+                                adjust: right
+                              )
+                             )
+                           
+                          )
+                          extent: (Point 180 35)
+                        )
+                       (ComboListSpec
+                          name: 'ComboList1'
+                          model: settingsHolder
+                          comboList: defaultSettingsPrototypeList
+                          useIndex: false
+                          extent: (Point 463 20)
+                        )
+                       )
+                     
+                    )
+                    extent: (Point 648 35)
+                  )
+                 )
+               
+              )
+            )
+           (HorizontalPanelViewSpec
+              name: 'HorizontalPanel2'
+              layout: (LayoutFrame 0 0 -30 1 0 1 0 1)
+              horizontalLayout: fitSpace
+              verticalLayout: center
+              horizontalSpace: 3
+              verticalSpace: 3
+              component: 
+             (SpecCollection
+                collection: (
+                 (ActionButtonSpec
+                    label: 'Add'
+                    name: 'Button1'
+                    translateLabel: true
+                    model: doAccept
+                    enableChannel: acceptEnableChannel
+                    extent: (Point 322 22)
+                  )
+                 (ActionButtonSpec
+                    label: 'Cancel'
+                    name: 'Button2'
+                    translateLabel: true
+                    model: doCancel
+                    extent: (Point 322 22)
+                  )
+                 )
+               
+              )
+            )
+           )
+         
+        )
+      )
+! !
+
+!P4SourceCodeManagementSettingsAppl::ManagerPerModuleApp methodsFor:'accessing'!
+
+canceled
+    ^ canceled
+!
+
+defaultSettingsPrototypeList
+
+    defaultSettingsPrototypeList isNil ifTrue:[
+        defaultSettingsPrototypeList := sourceCodeManagementSettingsApp perforcePrototypeList.
+    ].
+    ^ defaultSettingsPrototypeList.
+!
+
+sourceCodeManagementSettingsApp
+    ^ sourceCodeManagementSettingsApp
+!
+
+sourceCodeManagementSettingsApp:something
+    sourceCodeManagementSettingsApp := something.
+! !
+
+!P4SourceCodeManagementSettingsAppl::ManagerPerModuleApp methodsFor:'aspects'!
+
+acceptChannel
+    <resource: #uiAspect>
+
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept it in the browser."
+    "*** (and replace this comment by something more useful ;-)"
+
+    acceptChannel isNil ifTrue:[
+        acceptChannel := TriggerValue new.
+    ].
+    ^ acceptChannel.
+!
+
+acceptEnableChannel
+    <resource: #uiAspect>
+
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept it in the browser."
+    "*** (and replace this comment by something more useful ;-)"
+
+    acceptEnableChannel isNil ifTrue:[
+        acceptEnableChannel := true asValue.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+"/       acceptEnableChannel addDependent:self.
+"/       acceptEnableChannel onChangeSend:#acceptEnableChannelChanged to:self.
+    ].
+    ^ acceptEnableChannel.
+!
+
+moduleHolder
+    <resource: #uiAspect>
+
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept it in the browser."
+    "*** (and replace this comment by something more useful ;-)"
+
+    moduleHolder isNil ifTrue:[
+        moduleHolder := ValueHolder new.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+        moduleHolder addDependent:self.
+"/       moduleHolder onChangeSend:#moduleHolderChanged to:self.
+    ].
+    ^ moduleHolder.
+!
+
+settingsHolder
+    <resource: #uiAspect>
+
+    "automatically generated by UIPainter ..."
+
+    "*** the code below creates a default model when invoked."
+    "*** (which may not be the one you wanted)"
+    "*** Please change as required and accept it in the browser."
+    "*** (and replace this comment by something more useful ;-)"
+
+    settingsHolder isNil ifTrue:[
+        settingsHolder := ValueHolder new.
+"/ if your app needs to be notified of changes, uncomment one of the lines below:
+"/       settingsHolder addDependent:self.
+"/       settingsHolder onChangeSend:#settingsHolderChanged to:self.
+    ].
+    ^ settingsHolder.
+! !
+
+!P4SourceCodeManagementSettingsAppl::ManagerPerModuleApp methodsFor:'initialization & release'!
+
+doCancel
+
+    canceled := true.
+    ^ super doCancel
+!
+
+postBuildWith:aBuilder
+    "This is a hook method generated by the Browser.
+     It will be invoked during the initialization of your app/dialog,
+     after all of the visual components have been built, 
+     but BEFORE the top window is made visible.
+     Add any app-specific actions here (reading files, setting up values etc.)
+     See also #postOpenWith:, which is invoked after opening."
+
+    "/ add any code here ...
+
+    canceled := false.
+    ^ super postBuildWith:aBuilder
+!
+
+postOpenWith:aBuilder
+    "This is a hook method generated by the Browser.
+     It will be invoked right after the applications window has been opened.
+     Add any app-specific actions here (starting background processes etc.).
+     See also #postBuildWith:, which is invoked before opening."
+
+    "/ add any code here ...
+
+    ^ super postOpenWith:aBuilder
+! !
+
+!P4SourceCodeManagementSettingsAppl::ModuleManager methodsFor:'accessing'!
+
+manager
+    ^ manager
+!
+
+manager:something
+    manager := something.
+!
+
+module
+    ^ module
+!
+
+module:something
+    module := something.
+!
+
+settings
+    ^ settings
+!
+
+settings:something
+    settings := something.
+! !
+
+!P4SourceCodeManagementSettingsAppl::ModuleManager methodsFor:'comparing'!
+
+< aModuleManager
+
+    ^ self module < aModuleManager module
+! !
+
+!P4SourceCodeManagementSettingsAppl::ModuleManager methodsFor:'queries'!
+
+availableManagerTypeNames
+    ^ AbstractSourceCodeManager availableManagers collect:[:cls | cls managerTypeName].
+!
+
+managerClass
+
+    ^ AbstractSourceCodeManager availableManagers detect:[:cls | cls managerTypeName = manager] ifNone:[nil].
+! !
+
+!P4SourceCodeManagementSettingsAppl class methodsFor:'documentation'!
+
+version_CVS
+    ^ '$Header: /cvs/stx/stx/libtool/PerforceSourceCodeManagementSettingsAppl.st,v 1.1 2011-04-19 08:29:32 cg Exp $'
+! !