Bedingungsformate erkennen und zählen

(Übersetzung von »Counting Condition Format Usage in a Document« von Rick Quatro)

Dieses Skript dient der Erstellung einer Liste aller Bedingungsformate in einem Dokument. Außerdem wird ermittelt, wie oft jedes Bedingungsformat verwendet wird. Das Skript kann so erweitert werden, dass es auch für eine Buchdatei einsetzbar ist. Die in diesem Skript verwendeten Techniken können auch in anderen Skripts eingesetzt werden, die sich mit Zeichenformatierung in FrameMaker befassen. Sie können sich die kleine FrameMaker-Datei CondTest.fm herunterladen und für diese Lektion verwenden.

Es gibt einige Einschränkungen, die Sie beachten sollten. Sobald sich zwei verschiedene Bedingungsformate überlappen, werden beide Formate erneut gezählt. Dies wird in der Abbildung unten veranschaulicht. Das Format Inserted ist in Grün dargestellt, das Format Deleted in Rot.

Das Skript gibt die verwendeten Bedingungsformate für oben genanntes Dokument folgendermaßen aus:

In der folgenden Abbildung überlappen sich dieselben beiden Bedingungen im Absatz. Der Zeichenfolge »con« (dargestellt in Violett) wurde sowohl das Format Inserted als auch das Format Deleted zugewiesen.

Das Skript gibt die verwendeten Bedingungsformate für oben genanntes Dokument folgendermaßen aus:

Dies könnten Sie bei Bedarf über die Programmierung abfangen, allerdings würde das Skript dann komplizierter werden. Bei den meisten Dokumenten stellt dies aber kein Problem dar, also machen wir uns an dieser Stelle keine weiteren Gedanken darüber.

Folgendes müssen Sie noch beachten: Wenn ein Bedingungsformat einem Text zugewiesen ist, der sich über zwei aufeinander folgende Absätze erstreckt, wird das Bedingungsformat in jedem der Absätze jeweils als ein Vorkommen gezählt.

Erstellen der Listen

Zunächst gehen wir davon aus, dass die Datei CondTest.fm geöffnet und das aktive Dokument ist. Im endgültigen Skript müssen Sie natürlich zunächst überprüfen, ob ein aktives Dokument vorhanden ist:

If ActiveDoc = 0
    MsgBox 'Kein aktives Dokument.'; 
    LeaveSub;
Else
    Set vCurrentDoc = ActiveDoc;
EndIf

Es mag Ihnen vielleicht überflüssig erscheinen, für ActiveDoc die Variable vCurrentDoc zu setzen, aber so wird das Skript erweiterbar für eine Buchdatei.

Zunächst müssen Sie einige Listenvariablen initialisieren. Die eine Variable ist eine StringList zum Speichern der Bedingungsformate im Dokument, die andere Variable ist eine IntegerList zum Speichern der Häufigkeit jedes Formats. Listenvariablen sind nützlich, um die Komponenten Ihres Skripts im Auge zu behalten.

New StringList NewVar(vCondFmts);
New IntList NewVar(vCondFmtQtys);

Mit einer Schleife können Sie die Namen der Bedingungsformate zur Liste vCondFmts hinzufügen. In derselben Schleife wird die Häufigkeit auf Null gesetzt.

Loop ForEach(CondFmt) In(vCurrentDoc) LoopVar(vCondFmt)
    Add Member(vCondFmt.Name) To(vCondFmts);
    Add Member(0) To(vCondFmtQtys);
EndLoop

Mit dem Befehl Display können Sie die Listen anzeigen.

Display vCondFmts;
Display vCondFmtQtys;


Wichtig ist hierbei die Tatsache, dass beide Listen dieselbe Anzahl von Elementen aufweisen. In unserem Beispiel befinden sich in jeder Liste 4 Elemente. Jedes Element der Integer-Liste vCondFmtQtys besitzt eine entsprechende Position in der String-Liste vCondFmts.

In einer weiteren Integer-Liste speichern Sie nun die Anzahl der verwendeten Bedingungsformate.

New IntList NewVar(vFoundCondFmts);

Ermitteln der verwendeten Formate

Nun folgt der wesentliche Teil des Skripts. Sie erstellen eine Schleife durch alle Absätze im Dokument und überprüfen sie auf Bedingungsformate. Zunächst zeige ich Ihnen die Hülle der Schleife, anschließend folgen die Erklärung und der Inhalt der Schleife.

Set vPgf = vCurrentDoc.FirstPgfInDoc;
Loop While(vPgf)
    ...
    (Inhalt der Schleife. Siehe folgende Erklärungen.)
    ...
    Set vPgf = vPgf.NextPgfInDoc;
EndLoop

Der Schleifeninhalt erfüllt zwei Aufgaben: Es wird jedes verwendete Bedingungsformat ermittelt und jedes gefundene Format wird zur Integer-Liste vFoundCondFmts hinzugefügt.

Get TextList InObject(vPgf) CharPropsChange NewVar(vTextList);

Die CharPropsChange-Eigenschaft listet jedes Vorkommen einer Zeichenformatänderung innerhalb des Absatzes auf. Die Änderungen werden in der String-Liste vTextList gespeichert. Wenn keine Änderungen der Zeichenformatierung im Absatz gefunden werden, wird der Variablen vTextList.Count der Wert Null zugewiesen. Wenn vTextList.Count größer ist als Null, wird eine zweite Schleife gestartet. Diese Schleife überprüft für jedes Element in vTextList, ob es sich um eine Änderung eines Bedingungsformats handelt.

Loop While(vCounter <= vTextList.Count) 
        LoopVar(vCounter) Init(1) Incr(1)
    Get Member Number(vCounter) From(vTextList) NewVar(vPropList);
    Find Member('CONDITIONTAG') InList(vPropList.TextData)
        ReturnStatus(vFound);

Wenn eine Änderung eines Bedingungsformats gefunden wird, wird an der entsprechenden Textstelle im Absatz eine Variable für die Textposition (TextLoc) erstellt, sodass Sie die Texteigenschaften überprüfen können. Die Liste vPropList gibt lediglich Auskunft darüber, dass im Absatz eine Änderung des Bedingungsformats vorhanden ist. Die eigentliche Ermittlung der Bedingungsformate erfolgt über das Abfragen der Texteigenschaften.

    If (vFound)
        New TextLoc NewVar(vTextLoc) Object(vPgf)
            Offset(vPropList.TextOffset);
        Get TextProperties TextLoc(vTextLoc) NewVar(vTextProps);

Die Variable vTextProps ist eine Liste aller Eigenschaften an der Textposition vTextLoc im Absatz. Uns interessiert besonders die InCond-Eigenschaft, bei der es sich um eine Integer-Liste der verwendeten Bedingungsformate an der Textposition vTextLoc handelt. Die InCond-Liste kann mehrere Elemente enthalten, da in FrameMaker einem einzelnen Zeichen mehrere Bedingungsformate zugewiesen werden können. InCond kann aber auch den Wert Null haben, wenn an der Textposition vTextLoc die Bedingungsformate »ausgeschaltet« sind. Beachten Sie, dass die Liste CharPropsChange jede Formatänderung enthält, also auch jegliche Deaktivierung von Bedingungsformaten.

        Loop While(vCounter2 <= vTextProps.InCond.Count)
            LoopVar(vCounter2) Init(1) Incr(1)
            Get Member Number(vCounter2) From(vTextProps.InCond)
                NewVar(vCondInt);
            Add Member(vCondInt) To(vFoundCondFmts);
        EndLoop
    EndIf
EndLoop

Zählen der Bedingungsformate

Die Integer-Liste vFoundCondFmts enthält nun jedes Vorkommen eines Bedingungsformats im Dokument. Die folgende Abbildung zeigt die Liste für unsere Beispieldatei:

Display vFoundCondFmts;

Sie können sich denken, dass diese Liste ziemlich umfangreich werden kann, wenn Ihr Dokument viel bedingten Text enthält. Damit Sie diese Liste verwenden können, müssen zwei Aufgaben durchgeführt werden. Erstens müssen Sie jeden Integer-Wert der Liste vFoundCondFmts in das entsprechende Zeichenformat-Objekt übertragen, und zweitens müssen Sie die Zählervariable in der Integer-Liste vCondFmtQtys korrekt erhöhen. Für die erste Aufgabe verwenden Sie eine gewohnte Schleife.

Loop While(vCounter3 <= vFoundCondFmts.Count) 
        LoopVar(vCounter3) Init(1) Incr(1)
    Get Member Number(vCounter3) From(vFoundCondFmts)
        NewVar(vFoundCondFmt);

Die folgende Zeile wandelt den Integer-Wert in das entsprechende Bedingungsformat-Objekt um:

    New Object IntValue(vFoundCondFmt) DocObject(vCurrentDoc)
        NewVar(vCondFmtObj);
    Run IncrementCounter Using vCondFmtName(vCondFmtObj.Name);
EndLoop

Die vorletzte Zeile ruft die Sub-Routine IncrementCounter auf, wodurch die Integer-Liste vCondFmtQtys aktualisiert wird. Obwohl Sub-Routinen stets nach dem Hauptteil des Skripts eingefügt werden sollten, folgt als Nächstes die Erklärung zu IncrementCounter.

Sub IncrementCounter
//
Find Member(vCondFmtName) InList(vCondFmts) ReturnPos(vPos);

Sie wissen, dass die Variable vCondFmts alle Bedingungsformate im Dokument enthält, also müssen Sie nicht überprüfen, ob Elemente in der Liste vorhanden sind. Sie müssen lediglich die Position in der Liste (vPos) ermitteln. Anschließend ermitteln Sie das entsprechende Element in der Liste vCondFmtQtys und erhöhen den Zähler um 1.

Get Member Number(vPos) From(vCondFmtQtys) NewVar(vQty);
Set vQty = vQty + 1;

Nun müssen Sie den erhöhten Wert wieder an der korrekte Position in die Liste einfügen.

Replace Member Number(vPos) In(vCondFmtQtys) With(vQty);
//
EndSub

Ausgeben der Häufigkeiten

Mithilfe der beiden ursprünglichen Listen vCondFmts und vCondFmtQtys können Sie jetzt die Verwendung von Bedingungsformaten ausgeben. Jedes Bedingungsformat sowie dessen Häufigkeit im Dokument wird in das Fenster der FrameMaker-Konsole geschrieben. Listen und Schleifen gehören fast immer zusammen. Dies ist auch hier nicht anders. Fügen Sie folgenden Code als Sub-Routine namens ReportCount am Ende des Skripts ein. Dabei schreiben wir die Sub-Routine so allgemein, dass sie später auch für eine ganze Buchdatei verwendet werden kann.

Sub ReportCount
//
Write Console '*** '+vItem+' in '+vObject+':';
// Diese Schleife gibt die Informationen im Konsolenfenster aus.
Loop LoopVar(vCounter4) InitVal(1) Incr(1) 
    While(vCounter4 <= vNameList.Count) 
    Get Member Number(vCounter4) From(vNameList) NewVar(vName);
    Get Member Number(vCounter4) From(vCountList)
        NewVar(vCount);
    Write Console vName+' wird '+vCount+
        ' Mal im Dokument verwendet.';
EndLoop
//
EndSub

Mit folgendem Code wird die Sub-Routine ReportCount aufgerufen. Fügen Sie diesen Code unmittelbar nach dem Hauptteil des Skripts ein, also noch vor allen anderen Sub-Routinen.

Run ReportCount vNameList(vCondFmts)
    vCountList(vCondFmtQtys)
    vObject(vCurrentDoc.Name)
    vItem('Condition formats');

Und so sieht das Konsolenfenster aus, nachdem Sie das Skript für die Datei CondTest.fm ausgeführt haben:

Das komplette Skript können Sie hier auch downloaden.

Februar 2009, Michael Müller-Hillebrand