--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PersistentFileHistory.st Wed Jul 24 08:31:09 2019 +0200
@@ -0,0 +1,320 @@
+"
+ COPYRIGHT (c) 2019 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.
+"
+"{ Package: 'stx:libbasic2' }"
+
+"{ NameSpace: Smalltalk }"
+
+Object subclass:#PersistentFileHistory
+ instanceVariableNames:'fileHistory fileHistorySizeLimit topDirectoryName applicationKey
+ topRegistryKeyName'
+ classVariableNames:''
+ poolDictionaries:''
+ category:'Interface-Framework'
+!
+
+PersistentFileHistory class instanceVariableNames:'fileHistory'
+
+"
+ No other class instance variables are inherited by this class.
+"
+!
+
+!PersistentFileHistory class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 2019 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.
+"
+!
+
+documentation
+"
+ Support code tp provide a common access layer for persistent storage for applications.
+ For example, a persistent history of previously opened files.
+ On Windows systems, this is stored in the registry.
+ On Unix systems, it is stored in the user's home folder under '.smalltalk/registry/...'.
+ Both registry and directory use the same hierarchical structure.
+
+ PersistentFileHistory new
+ applicationKey:'GDBApplication';
+ fileHistory
+
+ [author:]
+ Claus Gittinger
+"
+! !
+
+!PersistentFileHistory class methodsFor:'instance creation'!
+
+new
+ "return an initialized instance"
+
+ ^ self basicNew initialize.
+! !
+
+!PersistentFileHistory methodsFor:'accessing - configuration'!
+
+applicationKey:aString
+ "this is used as the key under which the application's values are stored.
+ In the registry, this is the last key above the history entry);
+ if files are used, this is the folder name above which history, and other files are stored.
+ By default, the name of the application without prefix is used."
+
+ applicationKey := aString.
+
+ "Modified (comment): / 23-07-2019 / 17:33:49 / Claus Gittinger"
+!
+
+fileHistorySize
+ "defines the number of remembered files in the history"
+
+ ^ fileHistorySizeLimit ? 20.
+
+ "Modified: / 23-07-2019 / 17:24:39 / Claus Gittinger"
+!
+
+fileHistorySizeLimit:something
+ fileHistorySizeLimit := something.
+!
+
+topDirectoryName:topKeyName
+ "defaults to '.smalltalk',
+ but can be changed to '.expecco'."
+
+ topDirectoryName := topKeyName.
+
+ "Created: / 23-07-2019 / 17:22:16 / Claus Gittinger"
+!
+
+topRegistryKeyName:topKeyName
+ "defaults to 'SmalltalkX',
+ but can be changed to 'Expecco'."
+
+ topRegistryKeyName := topKeyName.
+
+ "Created: / 23-07-2019 / 17:25:27 / Claus Gittinger"
+! !
+
+!PersistentFileHistory methodsFor:'accessing - file history'!
+
+addToFileHistory:aFilename
+ "remember a filename in the file history"
+
+ |fileHistory|
+
+ fileHistory := self fileHistory.
+ fileHistory synchronized:[
+ fileHistory addFirst:aFilename asFilename.
+ fileHistory size > self fileHistorySize ifTrue:[
+ fileHistory removeLast.
+ ].
+ self makeFileHistoryPersistent
+ ]
+
+ "Modified: / 09-11-2010 / 16:07:14 / cg"
+ "Modified (comment): / 29-10-2017 / 10:51:11 / cg"
+ "Modified (comment): / 23-07-2019 / 17:47:17 / Claus Gittinger"
+!
+
+fileHistory
+ "return the file history"
+
+ fileHistory isNil ifTrue:[
+ self initializeFileHistory
+ ].
+ ^ fileHistory
+
+ "Modified (comment): / 23-07-2019 / 17:47:06 / Claus Gittinger"
+!
+
+fileHistoryFilteredForStillExistingFilesDo:aBlock removeNonExisting:aBoolean
+ |history toRemove|
+
+ toRemove := OrderedCollection new.
+
+ history := self fileHistory.
+ history notEmptyOrNil ifTrue:[
+ history synchronized:[
+ history do:[:aFilename|
+ aFilename exists ifTrue:[
+ aBlock value:aFilename.
+ ] ifFalse:[
+ aBoolean ifTrue:[
+ toRemove add:aFilename.
+ ]
+ ]
+ ].
+ aBoolean ifTrue:[
+ "/ remove all non-existing history entries
+ fileHistory removeAll:toRemove.
+ ].
+ ].
+ ].
+
+ "Created: / 29-10-2017 / 10:55:46 / cg"
+ "Modified: / 23-07-2019 / 17:49:34 / Claus Gittinger"
+! !
+
+!PersistentFileHistory methodsFor:'file history support'!
+
+registryKeyForApplication
+ "HKEY_CURRENT_USER\Software\Exept\SmalltalkX\<appname>"
+
+ |k_software k_exept k_stx k_app keyName|
+
+ OperatingSystem isMSWINDOWSlike ifTrue:[
+ keyName := applicationKey.
+
+ k_software := Win32OperatingSystem registryEntry key:'HKEY_CURRENT_USER\Software\'.
+ (k_exept := k_software subKeyNamed:'Exept') isNil ifTrue:[
+ k_exept := k_software createSubKeyNamed:'Exept'
+ ].
+ (k_stx := k_exept subKeyNamed:topRegistryKeyName) isNil ifTrue:[
+ k_stx := k_exept createSubKeyNamed:topRegistryKeyName
+ ].
+ (k_app := k_stx subKeyNamed:keyName) isNil ifTrue:[
+ k_app := k_stx createSubKeyNamed:keyName
+ ].
+ ^ k_app
+ ].
+
+ ^ nil
+
+ "
+ self registryKeyForApplication
+ "
+
+ "Created: / 11-01-2011 / 19:58:26 / cg"
+ "Modified: / 24-07-2019 / 08:30:34 / Claus Gittinger"
+!
+
+registryKeyForFileHistory
+ "HKEY_CURRENT_USER\Software\Exept\SmalltalkX\<appName>\History"
+
+ |k_app k_history|
+
+ OperatingSystem isMSWINDOWSlike ifTrue:[
+ k_app := self registryKeyForApplication.
+ (k_history := k_app subKeyNamed:'History') isNil ifTrue:[
+ k_history := k_app createSubKeyNamed:'History'
+ ].
+ ^ k_history
+ ].
+
+ ^ nil
+
+ "
+ self registryKeyForFileHistory
+ "
+! !
+
+!PersistentFileHistory methodsFor:'initialization'!
+
+initialize
+ "can be set to '.expecco'"
+ topDirectoryName := '.smalltalk'.
+ topRegistryKeyName := 'SmalltalkX'.
+ fileHistorySizeLimit := 25.
+
+ "Created: / 23-07-2019 / 17:21:27 / Claus Gittinger"
+! !
+
+!PersistentFileHistory methodsFor:'private'!
+
+directoryForFileHistory
+ "the filename where the history is made persistent.
+ This depends on the owningApplication which should not be nil."
+
+ ^ Filename homeDirectory / topDirectoryName / applicationKey
+
+ "
+ self new directoryForFileHistory
+ "
+
+ "Modified (comment): / 29-10-2017 / 10:51:29 / cg"
+ "Modified: / 23-07-2019 / 17:45:22 / Claus Gittinger"
+!
+
+fetchFileHistoryFromPersistentStore
+ |k index value dir fn|
+
+ fileHistory := OrderedSet new.
+
+ OperatingSystem isMSWINDOWSlike ifTrue:[
+ k := self registryKeyForFileHistory.
+ index := 1.
+ [
+ value := k valueNamed:(index printString).
+ value notNil
+ ] whileTrue:[
+ fileHistory add:value asFilename.
+ index := index + 1
+ ].
+ k close.
+ ] ifFalse:[
+ dir := self directoryForFileHistory.
+ dir isDirectory ifTrue:[
+ fn := dir / 'history'.
+ fn exists ifTrue:[
+ fileHistory addAll:(fn contents collect:[:s | s asFilename])
+ ]
+ ]
+ ]
+
+ "Modified: / 16-05-2019 / 19:05:49 / Stefan Vogel"
+ "Modified: / 23-07-2019 / 17:20:08 / Claus Gittinger"
+!
+
+initializeFileHistory
+ fileHistory := OrderedSet new.
+ self fetchFileHistoryFromPersistentStore.
+!
+
+makeFileHistoryPersistent
+ |k index dir fn|
+
+ OperatingSystem isMSWINDOWSlike ifTrue:[
+ k := self registryKeyForFileHistory.
+ fileHistory doWithIndex:[:filePath :index |
+ k valueNamed:(index printString) put:filePath asFilename pathName.
+ ].
+
+ "/ remove the remaining keys
+ index := fileHistory size + 1.
+ [
+ k deleteValueNamed:(index printString)
+ ] whileTrue:[
+ index := index + 1
+ ].
+ ] ifFalse:[
+ (dir := self directoryForFileHistory) exists ifFalse:[
+ dir recursiveMakeDirectory
+ ].
+ fn := dir / 'history'.
+ fn contents:(fileHistory collect:[:fn | fn pathName]).
+ ]
+! !
+
+!PersistentFileHistory class methodsFor:'documentation'!
+
+version_CVS
+ ^ '$Header$'
+! !
+