^

15.4 Standard Dokument Operationen

Alle für die Dateioperationen notwendigen Dialoge werden von der DocumentTools Library bereitgestellt. Die entsprechenden Routinen liefern eine Struktur zurück, die folgendermaßen definiert ist:
STRUCT DialogReturnStruct
  fileName$ as String[32]
  retInfo As Word
End Struct
Das Feld "fileName$" enthält den vom Nutzer eingegeben bzw. ausgewählten Dateinamen. Das Feld "retInfo" enthält die Information, welchen Button im Dialog der Nutzer gedrückt hat. Dafür die folgenden Konstanten definiert:

Tabelle

^

15.4.1 Ein neues Dokument anlegen

Klickt der Nutzer im Menü auf den entsprechenden Button so wird im DocumentAndToolButtonHandler die Routine BasicCreateNewDoc gerufen.

Um eine neues, leeres Dokument anzulegen muss BasicCreateNewDoc folgende Schritte durchführen:

  1. Schließen eines eventuell noch offenen Dokuments. BasicCloseDoc(TRUE) erledigt alle dafür nötigen Schritte, einschließlich der Nachfrage beim Nutzer, ob eventuelle Änderungen gespeichert werden sollen.

  2. Wechseln in den Ordner, in dem die neue Datei angelegt werden soll.

  3. Anlegen der Datei. Alle dafür nötigen Schritte erledigt die Methode CreateNewDocument. Das DocumentGuardian-Objekt kennt sowohl den Dateityp als auch das Token der Datei und initialisiert die neue Datei entsprechend. VM-Dateien werden so initialisiert dass sie mit den Routinen aus der VMFiles Library verwendet werden kann.

  4. Für den (extrem unwahrscheinlichen) Fall, dass es beim Anlegen der Datei ein Problem gegeben hat, geben wir eine Fehlermeldung aus und verlassen die Sub.

  5. Die Datei initialisieren. Hier schreibt man die Daten in die Datei, die auch bei Leeren Dateien vorhanden sein müssen. Ob es da etwas gibt und was das genau sein muss hängt von Ihrem Programm ab.

  6. Update der UI mit DoReadDataFromDoc und DoUpdateDocButtons.
SUB BasicCreateNewDoc ()
DIM err

  err = BasicCloseDoc(TRUE)
  IF err THEN RETURN

  DoEnterDocumentPath(TRUE)
  DocumentObj.CreateNewDocument
  IF fileError THEN
    MsgBox "Fehler beim Anlegen der neuen Datei. Fehlercode: " +
            ErrorText$(fileError)
    RETURN
  End IF

  ! Datei initialisieren
  MsgBox "BasicCreateNewDoc: Hier Datei initialisieren."

  DoReadDataFromDoc
  DoUpdateDocButtons

END SUB

^

15.4.2 Öffnen einer Datei

Klickt der Nutzer im Menü auf den entsprechenden Button so wird im DocumentAndToolButtonHandler die Routine BasicOpenDoc gerufen.

BasicOpenDoc führt die folgenden Schritte aus:

  1. Wechseln in den Pfad, in dem Dokumente normalerweise abgelegt werden.

  2. Aufruf der Routine DTOpenDialog aus der DocumentTools Library. Diese Routine zeigt den "Öffnen" Dialog an. Sie liefert eine DialogReturnStruct Struktur zurück (siehe oben). Wenn der Nutzer "Abbrechen gewählt hat verlassen wir die Routine.

  3. BasicCloseDoc(TRUE) sorgt dafür, dass eine eventuell noch offene Datei jetzt geschlossen wird. Im Fehlerfall (z.B. wenn der Nutzer "Abbrechen" wählt) verlassen wir die Routine.

  4. Öffnen der ausgewählten Datei. Die Methode OpenDocument erledigt alle dazu notwendigen Schritte. Dazu gehört auch, dass schreibgeschützte Dateien schreibgeschützt geöffnet werden. Wird als zweiter Parameter "TRUE" angegeben öffnet die Methode die Datei auf jeden Fall schreibgeschützt.

  5. Sollte das Öffnen fehlschlagen geben wir eine Fehlermeldung aus.

  6. In allen Fällen updaten wir die UI mit DoReadDataFromDoc und DoUpdateDocButtons.
SUB BasicOpenDoc ()
DIM ret as DialogReturnStruct
DIM err

  DoEnterDocumentPath(FALSE)
  ret = DTOpenDialog(ConvertObjForSDK(DocumentObj), "")
  IF ret.retInfo = DRI_CANCEL THEN RETURN

  err = BasicCloseDoc(TRUE)
  IF err THEN RETURN

  IF ret.retInfo = DRI_OK THEN
    DocumentObj.OpenDocument ret.fileName$
  ELSE
    ' DRI_READ_ONLY, read-only öffnen
    DocumentObj.OpenDocument ret.fileName$, TRUE
  End IF

  IF fileError THEN
    MsgBox "Fehler beim Öffnen der Datei "+ret.fileName$+". Fehlercode: "+
            ErrorText$(fileError)
  End IF

  DoReadDataFromDoc
  DoUpdateDocButtons

END SUB

^

15.4.3 Speichern der geänderten Daten

Klickt der Nutzer im Menü auf den Speichern-Button im Menü oder in der Toolbar so wird im DocumentAndToolButtonHandler die Routine BasicSaveDoc gerufen.

BasicSaveDoc dient als Verteiler für die verschiedenen möglichen Fälle:

Wenn die Datei ungeändert ist ((docState AND DOCS_MODIFIED)=0) kehrt die Routine ohne weitere Aktion zurück. Diese Abfrage greift auch dann, wenn gar keine Datei offen ist (docState = 0).

Ist die Datei noch unbenannt (docState AND DOCS_UNTITLED ist nicht Null) wird die Datei automatisch unter einem neuen Namen gespeichert. BasicSaveAsDoc() erledigt alle dafür notwendigen Aufgaben.

Read-Only-Dateien kann man nicht speichern. Deswegen fragen wir den Nutzer ob er die Datei unter einem anderen Namen speichern möchte und starten gegebenenfalls wieder BasicSaveAsDoc().

In allen anderen Fällen rufen wir DoSaveDataToDoc (DocumentObj.documentHandle). Diese Routine erledigt die eigentliche Arbeit. Sie wurde weiter oben (Kapitel 15.3) beschrieben.

Wichtig ist, dass wir den "modified" Status des Dokuments zurücksetzen. Das erledigt die Routine DoSetDocModified(FALSE). Abschließend updaten wir mit DoUpdateDocButtons die Menüs und ggf. andere wichtige UI.

SUB BasicSaveDoc ()
DIM docState, ans

  docState = DocumentObj.documentState
  IF (docState AND DOCS_MODIFIED)=0 THEN RETURN

  IF docState AND DOCS_UNTITLED THEN
    BasicSaveAsDoc()
    RETURN
  END IF

  IF docState AND DOCS_READ_ONLY  THEN
    ans = QuestionBox ("Die Datei ist schreibgeschützt. Wollen Sie sie
                        unter einem neuen Namen speichern?")
    IF ans = YES THEN 
      BasicSaveAsDoc()
    End IF
    RETURN
  End IF

  DoSaveDataToDoc(DocumentObj.documentHandle)
  DoSetDocModified(FALSE)
  DoUpdateDocButtons

END SUB

^

15.4.4 Speichern unter neuem Namen

Klickt der Nutzer im Menü auf den entsprechenden Button so wird im DocumentAndToolButtonHandler die Routine BasicSaveAsDoc gerufen. Diese Routine wechselt in den Pfad, in dem Dokumente im Normalfall abgelegt werden und öffnet dann mit DTDaveAsDialog den "Speichern unter" Dialog. Sie ist in der DocumentTools Library definiert und kümmert sich z.B. auch darum, dass der Nutzer nur einen für den vom DocumentGuardian verwalteten Dateityp gültigen Dateinamen eingeben kann. Der Parameter "FALSE" bewirkt, dass die Dateien im FileSelector des "Speichern unter"-Dialogs nicht wie sonst unter GEOS üblich grau angezeigt werden. Dadurch kann der Nutzer z.B. die Datei, die er überschreiben möchte, anklicken.

DTSaveAsDialog wechselt in den Pfad, der im "Speichern unter" Dialog ausgewählt wurde. Sie liefert eine DialogReturnStruct-Struktur zurück (siehe oben), die unter anderem den neuen Namen für die Datei enthält.

Die eigentliche Arbeit erledigt dann die Routine InternalSaveAs, die auch von BasicSaveAsTemplate gerufen wird.

FUNCTION BasicSaveAsDoc () AS REAL
Dim err
DIM ret as DialogReturnStruct

  DoEnterDocumentPath(FALSE)

  ret = DTSaveAsDialog(ConvertObjForSDK(DocumentObj), "", FALSE)
  IF ret.retInfo = DRI_CANCEL THEN RETURN TRUE

  err = InternalSaveAs(ret)
  RETURN err

END FUNCTION
Sowohl BasicSaveAsDoc als auch InternalSaveAs liefern den Fehlerwert TRUE zurück, wenn der Nutzer den Vorgang abgebrochen hat oder ein anderer Fehler auftrat.

Die Funktion InternalSaveAs erledigt die Hauptarbeit zum Speichern einer Datei unter neuem Namen. Dabei sind die folgenden Schritte zu erledigen:

  1. Wir stellen sicher, dass die neue Datei im aktuellen Ordner nicht existiert. Die Routine DTConfirmAndDelete aus der DocumentTools Library prüft das, fragt ggf. den Nutzer, ob er die Datei überschreiben möchte und löscht diese dann. Falls das nicht möglich ist, z.B. weil der Nutzer "Abbrechen" gewählt hat oder weil die Datei in Benutzung ist, liefert dir Routine TRUE zurück und wir verlassen die Routine InternalSaveAs mit dem Returnwert TRUE.

  2. Wir fertigen mit DTCloneFile eine 1:1 Kopie des aktuell vom DocumentGuardian geöffneten Dokuments an. Für den sehr unwahrscheinlichen Fall, dass es dabei ein Problem gibt, setzt DTCloneFile die globale Variable fileError und wir brechen den Vorgang ab.

  3. Jetzt können wir die aktuelle Datei schließen. Vorher merken wir uns den modified-Status und bringen die Datei mit DoRevertDoc auf den letzten gespeicherten Stand.

  4. Nun können wir die neue Datei öffnen. War die Datei geändert speichern wir die den aktuellen Stand in der Datei und setzen den modified-Status zurück.

  5. Abschließend bringen wir die Buttons und in den Menüs auf den neuesten Stand und kehren durch "RETURN FALSE" mit der Information "alles OK" zurück.
FUNCTION InternalSaveAs (ret as DialogReturnStruct) AS Real
DIM err, modi

  err = DTConfirmAndDelete(ret.fileName$)
  IF err THEN RETURN true

  DTCloneFile(ConvertObjForSDK(DocumentObj), ret.fileName$)
  IF fileError THEN RETURN TRUE

  modi = DocumentObj.documentState AND DOCS_MODIFIED
  DoRevertDoc
  DocumentObj.CloseDocument

  DocumentObj.OpenDocument ret.fileName$
  IF modi THEN
    DocumentObj.SetDocumentState DOCS_MODIFIED, 0
    DoSaveDataToDoc(DocumentObj.documentHandle)
    DoSetDocModified(FALSE)
  END IF

  DoUpdateDocButtons
  RETURN FALSE
END FUNCTION

^

15.4.5 Schließen des Dokuments

Klickt der Nutzer im Menü auf den entsprechenden Button so wird im DocumentAndToolButtonHandler die Routine BasicCloseDoc aufgerufen. Außerdem wird BasicCloseDoc an verschiedenen anderen Stellen des Programms gerufen, z.B. wenn eine neue Datei geöffnet werden soll während noch eine andere offen ist.

Die Funktion BasicCloseDoc schließt das aktuelle Dokument und liefert im Erfolgsfall den Wert FALSE zurück. Im Fehlerfall gibt BasicCloseDoc den Fehler-Wert TRUE zurück.

Wenn ein Dokument geschlossen werden soll können vorher andere Aktionen notwendig sein. Zum Beispiel könnte es nötig sein, geänderte Daten in die Datei zu schreiben oder die Datei unter einem anderen Namen zu speichern. Da hier sehr viele Fälle möglich sind bietet die DocumentTools Library die Funktion DTConfirmClose an. Sie prüft die Instancevariable "documentState" des übergebenen DocumentGuardian-Objekts, ob das vom DocumentGuardian-Objekt geöffnete Dokument einfach geschlossen werden kann oder ob weitere Aktionen nötig sind. Im Zweifelsfall wird der Nutzer durch eine Dialogbox gefragt, wie weiter zu verfahren ist. DTConfirmClose handelt alle denkbaren Fälle und liefert einen der folgenden Werte zurück:

Tabelle


Entsprechend besteht die Routine BasicCloseDoc nur aus dem Aufruf der Routine DTConfirmClose sowie einer ON-SWICTH Anweisung, die die möglichen Fälle behandelt. Der Parameter saveData bestimmt, ob eventuell geänderte Daten in der Datei gespeichert werden sollen oder nicht. Ist er FALSE oder wählt der Nutzer "Änderungen vergessen" wird die Datei auf den letzten gespeicherten Stand zurückgesetzt und dann geschlossen.

FUNCTION  BasicCloseDoc (saveData as INTEGER) AS REAL
DIM cmd, err

  IF saveData THEN
    cmd = DTConfirmClose(ConvertObjForSDK(DocumentObj), TRUE)
  ELSE
    cmd = CLOSE_DISCARD
  END IF

  ON cmd SWITCH
  CASE CLOSE_CANCEL:   ' Abbruch
    RETURN TRUE
  CASE CLOSE_NO_FILE:  ' Keine Datei offen
    RETURN FALSE
  CASE CLOSE_DISCARD:  ' Änderungen nicht speichern
    DoRevertDoc
  END CASE
  CASE CLOSE_SAVE:     ' Änderungen speichern
    BasicSaveDoc' Handelt alle denkbaren Fälle
  END CASE
  CASE CLOSE_SAVE_AS:
    err = BasicSaveAsDoc()
    IF err THEN RETURN TRUE
  END SWITCH

  DocumentObj.CloseDocument
  RETURN FALSE

END FUNCTION

^

Weiter...