Manchmal wäre es wirklich nützlich, diese "Gemeinsam, privat bei Erstbenutzung"-Ordner
(Shared, private on first use = SPOFU) verwenden zu können.
Soll zum Beispiel jeder Benutzer einer
Notes-Anwendung die Möglichkeit haben, in einem Ordner seine Favoriten
zu sammeln, und hat er keine Berechtigung, alle Dokumente der Datenbank
zu verändern - es kann also nicht irgendetwas für diesen Benutzer in das
Dokument selbst eingetragen werden - dann bleiben nur noch private oder
eben "Gemeinsam, privat bei Erstbenutzung"-Ordner übrig.
Ein solcher Ordner ist auch schnell
erstellt. Die Sache hat trotzdem einen gewichtigen Haken: Hat der Benutzer
einmal auf den gemeinsamen Ordner geklickt und damit seine private Kopie
erstellt, kann man die Gestaltung dieser Kopie nicht mehr zentral aktualisieren.
Eine typische Lösung für das Problem
ist es, diesen Ordner zu löschen, so dass der Benutzer das nächste Mal,
wenn er den Ordner benutzen will, wieder eine neue private Kopie - jetzt
vom veränderten Original erstellt.
Dieser Ansatz ist aber nicht ideal:
Zum einen stellt sich die Frage, wann
die Privatkopie gelöscht werden soll. Bei jedem Verlassen der Datenbank?
Dann kann der Benutzer diesen Ordner praktisch gar nicht zum langfristigen
Sammeln benutzen, weil er zwischen zwei Sitzungen immer geleert würde.
Oder man setzt zentral irgendeine Art Signal, zum Beispiel einen bestimmten
Feldwert in einem Datenbankprofil-Dokument. Dann muss man aber immer, wenn
man die Gestaltung des Ordners verändert, daran denken, dieses Flag zu
setzen. Besser wäre es, wenn dieses Löschen automatisch immer genau dann
und nur dann passieren würde, wenn sich die Gestaltung des Originals verändert.
Zum anderen bedeutet das Löschen des
Ordners natürlich auch, dass alle Dokument-Zuordnungen verloren gehen.
Spätestens nach dem zweiten, dritten Mal wird kaum ein Benutzer den Favoritenordner
mehr verwenden, wenn der seinen Inhalt sowieso irgendwann wieder verliert.
Aber mit ein wenig "Magie"
und Fleiß lassen sich beide Probleme in den Griff bekommen...
Zuerst müssen wir die richtige Stelle finden,
wo wir das Löschen implementieren wollen. Da man den Ordner nur löschen
sollte, wenn er nicht gerade aktiv (also geöffnet) ist, ist das Datenbank-Script
wahrscheinlich der beste Kandidat. Beim Öffnen oder beim Schließen? Ich
habe mich für das Schließen der Datenbank, genauer: das QueryClose() im
Datenbank-Script entschieden, weil es nicht als so performance-kritisch
wahrgenommen wird wie das Öffnen einer Datenbank.
Jetzt müssen wir herausfinden, ob sich
die Gestaltung des Orignials verändert hat. Dazu kann man den LastModified-Zeitpunkt
des öffentlichen Ordners mit dem Created-Zeitpunkt des privaten vergleichen.
Liegt LastModified zeitlich hinter Created, muss die private Kopie aktualisiert
werden.
Also müssen wir auf beide Ordner irgendwie
zugreifen können.
Der private Ordner ist einfach: Ein
GetView(Ordnername) auf die aktuelle Datenbank und wir sind fertig. Wird
Nothing zurückgegeben, wurde die Privatkopie nicht erstellt und es muss
folglich auch nichts aktualisiert werden. Sonst haben wir jetzt die NotesView
mit ihrer Created-Eigenschaft für den Vergleich zur Verfügung.
Der gemeinsame Ordner ist da schon schwieriger.
Eine Möglichkeit, die ich gefunden habe, besteht darin, eine NotesNoteCollection
mit allen Ordnern zu erstellen, diese zu durchlaufen, und beim richtigen
Ordner, also dem nicht-privaten Ordner ($Flags enthält nicht "V")
mit dem gegebenen Namen stehen zu bleiben. Wenn der gemeinsame Ordner nicht
gelöscht oder umbenannt wurde, sollte er so auf alle Fälle gefunden werden.
Performance-mäßig ist das sicherlich nicht ganz so toll, aber wenn es nicht
zu viele Ordner gibt, sollte das noch tolerabel sein. Ich bin offen für
andere Ideen und Ansätze...
Der Rest ist trivial: Die beiden Zeitpunkte
vergleichen und gegebenenfalls den privaten Ordner mittels Remove() löschen.
Halt, da war doch noch was: Es wäre
doch toll, wenn die zugeordneten Dokumente nicht verloren gehen würden.
Dazu erstelle ich einen neuen, versteckten
Ordner und kopiere alle Dokumente des zu löschenden Ordners dort hinein.
Danach erst lösche ich den privaten Ordner.
Hier ist der Code soweit:
Sub QueryClose(source As NotesUIDatabase, continue As Variant)
Dim session As New NotesSession
Dim currentDB As NotesDatabase
Dim privateFolder As NotesView
Dim foldersColl As NotesNoteCollection
Dim folderNoteID As String
Dim folderDoc As NotesDocument
Dim i As Integer
Dim publicFolderDoc As NotesDocument
Dim helperFolderName As String
Dim allEntries As NotesViewEntryCollection
Set currentDB = session.CurrentDatabase
' get handle to private version of the favorites folder
Set privateFolder = currentDB.GetView("My favorites")
' if there is no private version of the folder --> nothing to do
If privateFolder Is Nothing Then Exit Sub
' get handle to non-private version of the favorites folder
Set publicFolderDoc = Nothing
' first create NoteCollection of all folders
Set foldersColl = currentDB.CreateNoteCollection(False)
foldersColl.SelectFolders = True
Call foldersColl.BuildCollection
' then iterate through all folders
folderNoteID = foldersColl.GetFirstNoteId
For i = 1 To foldersColl.Count
' get the folder's document
Set folderDoc = currentDB.GetDocumentByID(folderNoteID)
' if folder is "My favorites" and ...
If folderDoc.~$TITLE(0) = "My favorites" Then
' ... if it doesn't contain the "V" flag, that is, it is not private
If InStr(folderDoc.~$Flags(0), "V") = 0 Then
' then it's the public favorites folder we are looking for
Set publicFolderDoc = folderDoc
Exit For
End If
End If
folderNoteID = foldersColl.GetNextNoteId(folderNoteID)
Next
' if the public folder could not be found --> nothing to do
If publicFolderDoc Is Nothing Then Exit Sub
' if the private version of the favorites folder is created after
' the last modification of the public one, it is current --> nothing to do
If publicFolderDoc.LastModified <= privateFolder.Created Then Exit Sub
' else the private favorites folder has to be updated
helperFolderName = "(SPOFUFolderUpdateHelper-" & session.CommonUserName & ")"
Set allEntries = privateFolder.AllEntries
' put all documents in this folder into a helper folder
Call allEntries.PutAllInFolder(helperFolderName, True)
' and remove the out-dated folder
Call privateFolder.Remove()
End Sub
Und wie wird jetzt die neue Privatkopie erstellt? Per LotusScript geht das eigentlich nur über ein NotesUIWorkspace.OpenDatabase(). Nicht gerade ideal beim Schließen der Datenbank.
Ich warte einfach, bis der Benutzer selbst das nächste Mal den Favoritenordner öffnet und dadurch die neue Kopie erstellt wird!
Im PostOpen-Ereigbnis des Favoritenordners sehe ich dann nach, ob es einen versteckte Hilfsordner für den aktuellen Benutzer gibt. In diesem Fall kopiere ich die Dokumente daraus wieder in den privaten Favoritenordner zurück und lösche dann den Hilfsordner.
Hier der Code dazu:
Sub PostOpen(source As NotesUIView)
Dim session As New NotesSession
Dim currentDB As NotesDatabase
Dim helperFolderName As String
Dim updateHelperFolder As NotesView
Dim allEntries As NotesViewEntryCollection
Dim uiws As New NotesUIWorkspace
Set currentDB = session.CurrentDatabase
' if there is a FavoritesUpdateHelper folder for this user...
helperFolderName = "(SPOFUFolderUpdateHelper-" & session.CommonUserName & ")"
Set updateHelperFolder = currentDB.GetView(helperFolderName)
If Not updateHelperFolder Is Nothing Then ' helper folder found
' move all entries to current folder
Set allEntries = updateHelperFolder.AllEntries
Call allEntries.PutAllInFolder(source.ViewName, False)
' and remove helper folder
Call updateHelperFolder.Remove()
End If
' refresh view to show newly added documents
Call uiws.ViewRefresh
End Sub
Das war's schon!