4.13 DocumentGuardian

4.13.1 Konfiguration

4.13.2 Verwalten von Dokumenten

4.13.3 Services

Viele Programme arbeiten mit Dokumenten, die der Nutzer anlegen, bearbeiten, speichern und weitergeben kann. Objekte der Klasse DocumentGuardian erleichtern Ihnen den Umgang mit solchen Dokumenten, indem Sie allgemeine Informationen, die bei der Arbeit mit Dokumenten anfallen, verwalten. Dazu zählen z.B. der Name und der Pfad zur Dokumentendatei sowie das FileHandle der offenen Datei. Außerdem können Objekte der Klasse DocumentGuardian vorhandenen Dokumente öffnen, neue Dokumente anlegen und offene Dokumente schließen. Dabei berücksichtigen sie z.B. den Dateityp und das Token, behandeln schreibgeschützte Dateien korrekt und vieles mehr. Auf diese Weise entlasten diese Objekte den BASIC-Programmierer von einer Vielzahl von Standardaufgaben.

DocumentGuardian-Objekte sind dafür ausgelegt mit der Library "DocumentTools" zusammenzuarbeiten. Diese Library bietet z.B. die zur Dateiarbeit nötigen Dialogboxen wie "Öffnen" und "Speichern unter" an. Im Handbuch "Spezielle Themen", Kapitel 15, ("Implementieren eines Dokument-Interfaces") finden Sie eine ausführliche Beschreibung wie man die Arbeit mit Dokumenten unter Verwendung der DocumentTools Library und eines DocumentGuardian-Objekts organisiert. Bitte lesen Sie dort nach, wenn Sie ausführliche Beispiele oder weitergehende Erklärungen benötigen.

Zur Vereinfachung kann der gesamte Dokument-Interface Code über ein R-BASIC Menu in ihr Programm eingebaut werden. Dazu verwenden Sie das Menü "Extras" -> "Code Bausteine" -> "Dokument-Interface". Dort können Sie auch festlegen, welche Teile des Dokumentinterfaces Sie unterstützen wollen, z.B. ob Sie Musterdokumente unterstützen wollen oder nicht.

Im Prinzip läuft die Arbeit mit DocumentGuardian-Objekten so ab:

  • Vereinbaren Sie ein DocumentGuardian-Objekt im UI-Code oder erzeugen Sie sein oder mehrere DocumentGuardian-Objekte zur Laufzeit (mit CreateObject).

  • Initialisieren Sie das Objekt durch Belegen der Instancevariablen configData und ButtonHandler.

  • Öffnen Sie ein vorhandenes Dokument mit der Methode OpenDocument oder erzeugen Sie ein neues Dokument mit CreateNewDocument.

  • Um Daten aus der Dokument-Datei zu lesen oder in die Datei zu schreiben benötigen Sie das FILE Handle der Datei. Das bekommen Sie über die Instancevariable documentHandle.

    Wichtig: Das FILE Handle der Dokumentendatei kann sich im Laufe der Zeit ändern, z.B. wenn die Datei umbenannt (Menüpunkte "Speichern unter" oder "Umbenennen") oder verschoben wird (Menüpunkt "Verschieben nach"). Deswegen sollten Sie das FILE Handle nicht irgendwo zwischenspeichern.

  • Wenn Sie Informationen über den Zustand der Datei wissen oder ändern wollen, können Sie die Instancevariable documentState und die Methode SetDocumentState verwenden. Insbesondere sollten Sie SetDocumentState rufen, wenn Sie die Datei als geändert markieren wollen.

  • Weitere wichtige Informationen über die offene Datei speichern die Instancevariablen documentName$ und documentPath$. DocumentUserData können Sie verwenden, um beliebige weitere Informationen über die Datei abzulegen.

  • Um ein Dokument zu schließen verwenden Sie die Methode CloseDocument.

  • Wenn GEOS herunterfährt bzw. wieder neu startet übernehmen die Methoden HandleShutdown und HandleRestart alle notwendigen Schritte um die Datei zu schließen und beim Neustart automatisch wieder zu öffnen.

Abstammung:

...

Objekte der Klasse DocumentGuardian sind per Default nicht sichtbar (visible = FALSE). Sie können in den generic Tree eingebunden werden. Werden sie auf visible = TRUE gesetzt verhalten sie sich wie eine Group. Die unterstützen das Geometriemanagement und können Children haben.

Spezielle Instance-Variablen:

Variable Syntax im UI-Code Im BASIC-Code
ButtonHandler ButtonHandler = <Handler> nur schreiben
configData -- lesen, schreiben
documentState -- nur lesen
documentHandle -- nur lesen
documentName$ -- nur lesen
documentPath$ -- nur lesen
documentUserData -- lesen, schreiben

Methoden:

Methode Aufgabe
SetDocumentState Informationen über das Dokument ändern
CreateNewDocument Neues Dokument anlegen
OpenDocument Vorhandenes Dokument öffnen
CloseDocument Aktuelles Dokument schließen
HandleShutdown System-Shutdown behandeln
HandleRestart System Neustart behandeln


^

4.13.1 Konfiguration

ConfigData

Damit das DocumentGuardian seine Aufgaben, z.B. eine Datei anzulegen oder zu öffnen, erfüllen kann, benötigt es diverse Informationen. Dazu gehören der Dateityp (DOS-, GEOS-Daten- oder VM-Datei), für GEOS-Daten- und VM-Dateien das Token und einiges mehr. Außerdem arbeitet das DocumentGuardian-Objekt eng mit der "DocumentTools"-Library zusammen. Diese Library entlastet den Programmierer, indem Sie zum Beispiel die typischen Dialogboxen zum Öffnen oder "Speichern unter" von Dateien bereitstellt. Die für die Arbeit dieser Library nötigen Informationen werden ebenfalls vom DocumentGuardian-Objekt bereitgestellt.

Die Instancevariable configData enthält eine Struktur, die alle für die oben genannten Zwecke erforderlichen Informationen enthält. Die Struktur ist folgendermaßen definiert:

STRUCT DocumentConfigStruct 
  noDocumentString$  As String(32)
  templateFolder$    As String(32)
  nameForNew$        As String(32)
  fileType           As word
  token              As GeodeToken
  creatorToken       As GeodeToken
  matchMask$         As String(32)
  matchFlags         As Word
  reserved(4)        As Word
End Struct 
Bedeutung der einzelnen Felder:

noDocumentString$
NoDocumentString$ enthält den Text, den die Methode DocumentName$ zurückgeben soll, wenn kein Dokument geöffnet ist. Ein typischer Wert wäre "kein Dokument".

templateFolder$
TemplateFolder$ enthält den Unterordner im SP_TEMPLATE-Verzeichnis, in dem das Programm Templates ("Muster-Dateien") speichert. Das DocumentGuardian-Objekt stellt sicher, dass der Ordner existiert.

nameForNew$
NameForNew$ enthält den Kerntext, aus dem das DocumentGuardian-Objekt durch Hinzufügen einer Zahl von 1 bis 99 einen Namen für eine neue Datei bilden soll.

NameForNew$ hat das Format "core*.ext" oder "core".

Beispiele:

Aus "LEER*.RBF" wird "LEER1.RBF", "LEER2.RBF" bis "LEER99.RBF"
Aus "NEU*" wird "NEU2", "NEU2" bis "NEU99"
Aus "namenlos " wird "namenlos 1", "namenlos 2" bis "namenlos 99"
Wichtig: Sie sind selbst dafür zuständig, dass der nach dem oben genannten Schema gebildete Name zum Dateityp passt, für DOS-Dateien also das Format 8+3 eingehalten wird.

fileType
FileType enthält den Typ der Dokumentendatei. Gültige Werte sind GFT_VM, GFT_DATA und GFT_NOT_GEOS_FILE. Erfahrene Programmierer sollten VM-Dateien (GFT_VM) verwenden, für alle anderen empfiehlt sich GFT_DATA (GEOS-Daten-Dateien). Diese unterstützen wie die VM-Dateien die Geos-Attribute wie Token und CreatorToken. DOS-Dateien (GFT_NOT_GEOS_FILE) sollten Sie nur dann verwenden, wenn Sie einen wirklich guten Grund dafür haben.

token, creatorToken
Token und CreatorToken enthalten das Token und das CreatorToken der Datei für GEOS-Daten- und VM-Dateien. Beim Anlegen einer neuen Datei setzt das DocumentGuardian-Objekt Token und CreatorToken automatisch.

matchMask$, matchFlags
MatchMask$ und matchFlags werden vom DocumentGuardian-Objekt nicht selbst verwendet, sondern sind zur Arbeit der DocumentTools-Library notwendig. MatchFlags enthält die Information, welche Eigenschaften der Datei der im "Öffnen"-Dialog angezeigte FileSelector zum Filtern der Dateien verwenden soll. MatchMask$ enthält die Dateimaske, die verwendet wird, falls das entsprechende Bit in MatchFlags gesetzt ist.

reserved
Diese 10 Bytes sind für eventuelle spätere Erweiterungen vorgesehen. Sie dürfen diese Werte nicht verwenden.
Zur Verwendung mit matchFlags sind die folgenden Konstanten definiert:

Konstante Wert Bedeutung
DOC_MATCH_TOKEN 1 Feld "token" verwenden
DOC_MATCH_CREATOR 2 Feld "creatorToken" verwenden
DOC_MATCH_MASK 4 Feld "matchMask$" verwenden
DOC_MATCH_TYPE 8 Feld "fileType" verwenden

Für DOS-Dateien wird oft die Kombination "DOC_MATCH_TYPE + DOC_MATCH_MASK" verwendet, währen für GEOS-Daten- und VM-Dateien oft "DOC_MATCH_TOKEN" oder "DOC_MATCH_TOKEN + DOC_MATCH_CREATOR" verwendet wird. Beispiel:

SUB DoInitDocumentGuardian(guardian as object)
DIM dc as DocumentConfigStruct

  ' ButtonHandler kann hier oder im UI-Code gesetzt werden
  guardian.ButtonHandler = DocumentAndToolButtonHandler

  dc.noDocumentString$ = "kein Dokument"
  dc.templateFolder$ = "DemoTemplates"
  dc.nameForNew$ = "Unbenanntes Dokument "
 
  dc.fileType = GFT_DATA
  dc.creatorToken.tokenChars = "PHON"
  dc.creatorToken.manufid = 5
  dc.token.manufid = 5
  dc.token.tokenChars = "PHO2"
 
  ' dc.matchMask$ = "*.TXX" # nicht benötigt für GEOS-Dateien
  dc.matchFlags = DOC_MATCH_TOKEN
 
 guardian.configData = dc
END SUB


ButtonHandler

Die Instancevariable ButtonHandler enthält einen Handler, der von der DocumentTools-Library benötigt wird. Er muss als ButtonAction deklariert sein und wird gerufen, wenn der Nutzer einen Button im "Neu/Öffnen" Dialog anklickt. Dieser Dialog wird von der Routine DTNewOpenDialog aus der DocumentTools Library erzeugt. Weitere Informationen dazu finden Sie im Handbuch der Library.
Syntax UI-Code: ButtonHandler = <Handler>
     Schreiben: <obj>.ButtonHandler = <Handler>

 
Beispiel:
DocumentGuardian MyDocObj
  ButtonHandler = DocumentAndToolButtonHandler
End Object

^

4.13.2 Verwalten von Dokumenten

CreateNewDocument

Mit der Methode CreateNewDocument legt das DocumentGuardian Objekt ein neues Dokument entsprechend den in der Instancevariablen configData gespeicherten Werten an.

  • Der Name der neuen Datei wird aus configData.nameForNew und einer Zahl gebildet.

  • Der Dateityp (DOS-, GEOS-Daten- oder GEOS-VM-Datei) wird von configData.fileType bestimmt.

  • Für GEOS-Daten- und VM-Dateien wird Token (configData.token) und CreatorToken (configData.creatorToken) gesetzt.

  • VM-Dateien werden so initialisiert, dass sie mit der "VMFiles" Library verwendet werden können. Details zur Arbeit mit VM-Dateien finden Sie Im Handbuch der "VMFiles" Library

  • Achtung! Sollte das DocumentGuardian-Objekt noch eine Dokument-Datei offen haben wird sie ohne Nachfragen geschlossen.
Die neue Dokument-Datei wird im aktuellen Ordner angelegt. Die globale Variable fileError wird gesetzt (Null oder Fehlercode).
Syntax BASIC-Code: <obj>.CreateNewDocument
Beispiel:
MyDocObj.CreateNewDocument
MsgBox "Die neue Datei hat den Namen: " + MyDocObj.documentName$


OpenDocument

Mit der Methode OpenDocument öffnet das DocumentGuardian Objekt ein vorhandenes Dokument. Sollte das DocumentGuardian-Objekt noch eine Dokument-Datei offen haben wird sie ohne Nachfragen geschlossen. Die globale Variable fileError wird gesetzt (Null oder Fehlercode).
Syntax BASIC-Code: <obj>.OpenDocument "name" [, forceRO ]
           "name": Dateiname der zu öffnenden Datei
          forceRO: FALSE: normal öffnen (Default)
                    TRUE: schreibgeschützt öffnen

Beispiel:
MyDocObj.OpenDocument "MyDoc"


CloseDocument

Mit der Methode CloseDocument schließt das DocumentGuardian Objekt das aktuell von ihm geöffnete Dokument. Ist das Dokument noch unbenannt (das Bit DOCS_UNTITLED ist gesetzt in der Instancevariablen documentState) so wird die Datei nach dem Schließen gelöscht. Für den seltenen Fall, dass Sie nicht möchten, dass unbenannte Dokumente nach dem Schließen gelöscht werden, müssen Sie FALSE als Parameter angeben. Die globale Variable fileError wird in beiden Fällen gesetzt (Null oder Fehlercode).
Syntax BASIC-Code: <obj>.CloseDocument 
                   <obj>.CloseDocument FALSE

Beispiele:
MyDocObj.CloseDocument
MyDocObj.CloseDocument FALSE


DocumentHandle

Diese Instancevariable enthält das File-Handle der aktuell vom DocumentGuardian geöffneten Datei. Ist kein Dokument geöffnet enthält documentHandle ein NullHandle.
Syntax Lesen: <fh> = <obj>.documentHandle 
              <fh>: Variable vom Typ FILE

Beispiel:
DIM fh as FILE
DIM text$
  fh = MyDocObj.documentHandle
  IF fh <> NullFile() THEN
    text$ = FileReadLine$ ( fh ) 
  End IF


DocumentName$

DocumentName$ enthält den Namen der aktuell vom DocumentGuardian geöffneten Datei. Ist kein Dokument geöffnet enthält documentName$ den Text, der im Feld "noDocumentString" der Instancevariablen configData gespeichert ist.
Syntax Lesen: <stringVar> = <obj>.documentName$ 
              <stringVar>: Variable vom Typ String

Beispiel:
MyPrimary.Caption2$ = MyDocObj.documentName$


DocumentPath$

DocumentPath$ enthält den Pfad zur aktuell vom DocumentGuardian geöffneten Datei. Ist kein Dokument geöffnet documentPath$ den Pfad zur zuletzt geöffneten Datei.
Syntax Lesen: <stringVar> = <obj>.documentPath$ 
  <stringVar>: String-Variable, die 200 Zeichen aufnehmen kann.

Normale Stringvariablen können bis zu 128 Zeichen aufnehmen. Das ist in den meisten Fällen ausreichend, kann jedoch zu wenig sein, weil Pfade bis zu 198 Zeichen lang sein können. Beispiel:
DIM path$(200)
  path$ = MyDocObj.documentPath$
  MsgBox "Das Dokument liegt im Ordner '" + path$ + "'." 


documentState, SetDocumentState

Die Instancevariable documentState enthält Informationen (Flagbits) über den aktuellen Zustand des vom DocumentGuardian-Objekt verwalteten Dokuments. DocumentState enthält den Wert Null wenn kein Dokument offen ist. Folgende Bits sind definiert:

Konstante Wert Bedeutung
DOCS_OPEN 1 Es ist ein Dokument offen
DOCS_MODIFIED 2 Das Dokument wurde geändert. (*)
DOCS_UNTITLED 4 Das Dokument ist neu und hat noch keinen vom Nutzer vergebenen Namen.
DOCS_READ_ONLY 8 Das Dokument ist schreibgeschützt
DOCS_EDIT_TEMPLATE 16 Es ist ein Muster in Bearbeitung (**)

(*) Das Bit DOCS_MODIFIED wird vom DocumentGuardian-Objekt weder automatisch gesetzt noch zurückgesetzt. Es wird von der "DocumentTools" Library benötigt. Deswegen muss der Programmierer es auf dem aktuellen Stand halten.

(**) Das Bit DOCS_EDIT_TEMPLATE wird vom DocumentGuardian-Objekt nicht automatisch gesetzt. Es wird benutzt um sicherzustellen, dass der nächste "Öffnen"-Dialog den Dokument-Ordner anzeigt, und nicht dem der aktuell offenen Datei (den Template-Ordner). Der Programmierer sollte es setzen, wenn er ein Muster zum Bearbeiten öffnet. Es wird beim Schließen dieser Datei automatisch zurückgesetzt.

Die Instancevariable documentState kann nur gelesen werden. Um sie zu ändern verwenden Sie die Methode SetDocumentState. Sie erwartet zwei Parameter: die Bits, die zu setzen sind und die Bits, die zu löschen sind. Das vereinfacht die Verwaltung des Dokumentstatus wesentlich. SetDocumentState kann nur die Bits DOCS_MODIFIED, DOCS_UNTITLED und DOCS_EDIT_TEMPLATE ändern. Wenn kein Dokument offen ist können diese Bits nicht gesetzt werden.


Syntax BASIC-Code: <numVar> = <obj>.documentState


Syntax BASIC-Code: <obj>.SetDocumentState bitsToSet, bitsToClear

Beispiele:
DIM state
  state = MyDocumentGuardian.documentState
  IF state = 0 THEN MsgBox "Es ist kein Dokument offen."
  IF state AND DOCS_UNTITLED THEN MsgBox "Das Dokument ist neu."
  ' Dokumentstatus auf "geändert" setzen
  MyDocumentGuardian.SetDocumentState DOCS_MODIFIED, 0

  ' Dokumentstatus auf "ungeändert" setzen
  MyDocumentGuardian.SetDocumentState 0, DOCS_MODIFIED

^

4.13.3 Services

HandleShutdown, HandleRestart

Wenn GEOS herunterfährt muss das DocumentGuardian-Objekt das aktuelle Dokument schließen und beim Wiederhochfahren muss das gleiche Dokument wieder geöffnet werden. Darum kümmern sich die Methoden HandleShutdown und HandleRestart. Diese Methoden sollten im OnExit bzw. im OnStartup-Handler des Programms gerufen werden. Im Handbuch "Spezielle Themen", Kapitel 15, ("Implementieren eines Dokument-Interfaces") finden Sie ein ausführlicheres und kommentiertes Beispiel dazu.
Syntax BASIC-Code: <obj>.HandleShutdown
                   <obj>.HandleRestart

Beispiel:
SYSTEMACTION DocExitHandler
  IF flags AND AF_SHUTDOWN THEN
    DocumentObj.HandleShutdown
  Else
     ! Hier Dokument ggf. Speichern und normal schließen
  End IF
END ACTION

SYSTEMACTION DocStartupHandler
  IF flags AND AF_RESTORE THEN
    DocumentObj.HandleRestart
  End IF
END ACTION


documentUserData

Manchmal ist es wünschenswert, Dokumentdaten an einem sicheren Platz abzuspeichern, ohne sie in die Dokumentendatei zu schreiben. Zum Beispiel "überleben" globale Variablen eine Systemrestart nicht. Die Instancevariable documentUserData kann eine einzelne Strukturvariable (d.h. bis zu 3500 Byte) aufnehmen. Wie bei jeder anderen Instancevariablen von R-BASIC Objekten stehen die Daten nach einem Systemrestart automatisch wieder zur Verfügung.

Eine andere Anwendung wäre, wenn Sie ein Programm schreiben, dass mit mehreren offenen Dokumenten gleichzeitig umgehen kann, wobei jedes offene Dokument sein eigenes DocumentGuardian-Objekt hat. DocumentUserData könnte dann die Dokument-spezifischen Daten enthalten.

DocumentUserData ist zuweisungskompatibel mit jeder Art von Strukturvariablen. Beim Schreiben müssen Sie allerdings die Größe der Struktur extra angeben. Beim Lesen müssen Sie selbst darauf achten, dass die Strukturen kompatibel sind, R-BASIC führt weder eine Typ- noch eine Größenprüfung aus. Aber es ist sichergestellt, dass niemals mehr Bytes kopiert werden, als die Variable auf der linken Seite der Zuweisung aufnehmen kann.

Es ist zulässig mehrfach hintereinander Strukturen verschiedenen Typs und verschiedener Größe in die Instancevariable zu schreiben. R-BASIC optimiert jedes Mal den verwendeten Speicher, so dass kein Platz verschwendet wird.


Syntax Schreiben: <obj>.documentUserData = <struct>, size
        <struct>: Strukturausdruck beliebigen Typs
            size: Größe der Struktur
           Lesen: <sturctVar> = <obj>.documentUserData 
     <structVar>: Strukturvariable des Typs,
                  der beim Schreiben verwendet wurde. 

Beispiel:

Wir definieren eine Struktur, die Referenzen auf zwei Objekte enthält (ein View-Objekt und ein Display-Objekt), die zur Darstellung der Dokumentdaten Verwendung finden könnten. Dann definieren wir eine Strukturvariable, belegen diese und speichern die Informationen im DocumentGuardian Objekt.

STRUCT MyObjects
  docView as OBJECT
  docDiaplay as OBJECT
End Struct
DIM ob, ob2 as MyObjects

  ob.docView = MyView
  ob.docDisplay = MyDisplay

  guardian.documentUserData = ob, sizeof(ob)
....
  ob2 = guardian.documentUserData
.... 

^

Weiter...