Zeit ist Geld

Zeiterfassung mit OOBase

01.03.2008 Die OpenOffice-Komponenten Base und Basic fristen ein Schattendasein – zu Unrecht, wie unser Workshop beweist.

OpenOffice.org Basic genießt nicht gerade den Ruf eines professionellen Werkzeugs und hält tatsächlich dem Vergleich mit Programmiersprachen wie C++, Java oder Python kaum stand. Das heißt aber nicht, dass man mit OOoBasic keine mächtigen und flexiblen Lösungen programmieren könnte. Seit die Skriptsprache in der Lage ist, die Anwendungen aus OpenOffice miteinander zu verbinden, taugt sie sogar perfekt zum Selbstbau individueller Werkzeuge. Wir beweisen Ihnen das an einem Tool für professionelle, nach Stundensätzen bezahlte Schreiber. Für die ist es wichtig zu wissen, wieviel Zeit sie für einzelne Dokumente benötigen, damit sie diese ihren Auftraggebern in Rechnung stellen können.

Man könnte eine Calc-Tabelle für solche Berechnungen verwenden, in die man Dokumentenname, Datum, benötigte Zeit und weitere Informationen von Hand einträgt. Besonders effizient erscheint das in Zeiten automatischer Datenverarbeitung aber nicht. Stattdessen kann man mit OpenOffice.org Basic ein Werkzeug anfertigen, das die Zeit, , die man für ein Writer-Dokument braucht, selbständig im Auge behält. Die trägt es Tool dann automatisch in eine Base-Datenbank ein, die nachher für die Rechnungsstellung alle benötigten Informationen liefert.

Ein Anwender ohne Programmierkenntnisse mag sich von einer solchen Aufgabenstellung einschüchtern lassen – um dieses nützliche Helferlein anzufertigen, benötigt man jedoch nichts weiter als ein Makro und eine einfache Base-Datenbank.

Datenbank in Base anlegen

Bevor Sie sich um das Makro kümmern, legen Sie in Base eine einfache Datenbank an, in der das Makro anschließend die wichtigsten Daten über das Erstellen der Dokumente ablegt. Starten Sie OpenOffice.org, klicken Sie auf Neues Dokument | Datenbank und danach auf Öffnen: Damit starten Sie den Datenbank-Assistenten. Übernehmen Sie die Option Neue Datenbank erstellen und klicken Sie auf Fertig stellen. Vergeben Sie einen Namen, zum Beispiel Zeiterfassung. Mit OK legen Sie die Datenbank an.

Nun klicken Sie im Arbeitsfenster von Base auf Tabellen und danach auf Tabelle in der Entwurfsansicht erstellen. Es öffnet sich ein neues Fenster, in dem Sie die Felder Ihrer Zeiterfassung definieren. Welche das sein sollen, hängt davon ab, was Sie dort später sehen möchten. Mindestens sollten Sie aber vier Felder für Datenbankschlüssel, Dokument, Datum und Zeit dort eintragen (Tabelle "Feldnamen" und Abbildung 1).

Feldnamen

Feldname

Feldtyp

Beschreibung

ID Integer [INTEGER] Primärschlüssel (für jeden Datensatz einzigartig und eindeutig)
Dateiname Text [VARCHAR] Name des erfassten Office-Dokuments
Zeit Integer [INTEGER] Dauer für das Erstellen des aktuellen Dokuments
Datum Datum [DATE] Tag, an dem Sie den Datensatz hinzugefügt haben

Abbildung 1: Als Basis Ihrer Zeiterfassung erstellen Sie in Base eine einfache Tabelle.

Klicken Sie mit der rechten Maustaste auf das kleine Feld links neben dem Feldnamen ID und wählen Sie aus dem Kontextmenü Primärschlüssel. Base fügt dem Feld ein kleines Schlüsselsymbol hinzu. Stellen Sie in den Feldeigenschaften bei Auto-Wert Ja ein, damit Base diesen Wert später automatisch hochzählt. Haben Sie alle Felder erstellt, speichern Sie die Tabelle zum Beispiel unter dem Namen time und schließen die Entwurfsansicht. Klicken Sie auch im Datenbankfenster von Base auf Datei | Speichern, um die gesamte Datenbank bis hierher zu sichern.

Im nächsten Schritt registrieren Sie Ihre Datenbank als Datenquelle, auf die Sie mit anderen OpenOffice-Anwendungen zugreifen wollen. Dafür wählen Sie aus dem Menü Extras die Optionen und im Bereich OpenOffice.org Base die Datenbanken (Abbildung 2). Taucht die Datenbank in der Liste der registrierten Datenbanken nicht auf, klicken Sie auf Neu sowie Durchsuchen, wählen die Zeiterfassung per Doppelklick und OK aus und schließen das Menü.

Abbildung 2: Registrieren Sie Ihre Datenbank in Base, so dass Sie von anderen OpenOffice-Anwendungen darauf zugreifen können.

OpenOffice-Makro erstellen

Alle Einzelprogramme des freien Büropakets arbeiten mit OpenOffice.org Basic zusammen. Das bedeutet: Mit welcher Applikation Sie auf den Basic-Editor zugreifen, spielt keine Rolle. Sie erreichen den Editor immer über Extras | Makros | Makros verwalten | OpenOffice.org Basic. Markieren Sie das Makro Main und klicken Sie auf Bearbeiten. Anschließend präsentiert sich der Bildschirm etwa so, wie in Abbildung 3 zu sehen. Um den unten beschriebenen Code einzufügen, scrollen Sie einfach ans Ende des Skripts.

Abbildung 3: Der Basic-Editor von OpenOffice. Hier fügen Sie den Code der Zeiterfassung ein.

Das OOoBasic-Makro, das Sie für Ihre Zeiterfassung benötigen, besteht aus zwei Teilen: Der erste startet und stoppt einen Timer und berechnet die dazwischen vergangenen Minuten, der zweite zeichnet für gleich drei Dinge zuständig: Er verschafft sich Namen und Entstehungsdatum des aktuellen Dokuments, baut eine Verbindung zur Datenbank auf und schreibt die erhobenen Daten in einen neuen Datensatz.

Starten Sie mit dem Timer, der wiederum aus zwei Subroutinen besteht: Die erste sorgt für den Beginn der Zeiterfassung, die zweite stoppt sie und misst die verbrauchte Zeit. Dazu definieren Sie in OOoBasic zunächst zwei globale Variablen: GlobalElapsedTime und GlobalStartTime (Listing 1, Zeilen 2 und 3). Sie brauchen diese Variablen, um die Werte für Start- und verbrauchte Zeit zwischen den Subroutinen für StartTime und EndTime auszutauschen. Die Subroutine für StartTiming() fällt ziemlich einfach aus (Listing 1, Zeile 6 ff.).

Listing 1
rem — Globale Variablen
Global ElapsedTime as Long
Global StartTime
rem — Timer starten
Sub StartTiming()
  If ElapsedTime <> 0 then
    Message="Es laeuft bereits eine Zeitmessung!" & Chr(13) & "Moechten Sie eine neue Messung starten?"
  Else
    Message="Moechten Sie eine Zeitmessung starten?"
  EndIf
  Answer=MsgBox(Message,4,"Zeitmessung starten?")
  If Answer=7 then End
  StartTime=Time
  ElapsedTime=Timer
End Sub

Als erstes prüft sie anhand der Variablen ElapsedTime, ob bereits eine Zeitmessung läuft. Ist der Wert der Variable Null, fordert die Subroutine den Anwender auf, eine neue Session zu starten. Um die verbrauchte Zeit zu berechnen, wenn der Anwender die Messung stoppt, verwendet die Routine die beiden Variablen StartTime und ElapsedTime. StartTime erhält ihren Wert von der Variablen Time, die wiederum die aktuelle Uhrzeit von der Systemzeit des Rechners bezieht. ElapsedTime fungiert als Timer und holt sich ihren Wert aus der gleichnamigen Funktion.

Zeit berechnen

Die Subroutine EndTiming() gestaltet sich deutlich komplexer als die Startroutine, da sie mehr zu erledigen hat, als bloß den Timer zu stoppen und die vergangene Zeit zu messen. Um die Arbeit der Routine besser zu verstehen, teilen wir sie in einzelne Abschnitte. Das erste Modul prüft wieder, ob eine Zeitmessung läuft, und fordert den Anwender im positiven Fall auf, diese zu stoppen (Listing 2, Zeilen 1 bis 7).

Als nächstes berechnet die Subroutine mithilfe der Variablen ElapsedTime aus der Subroutine StartTiming die verbrauchte Zeit. Anschließend baut sie einen Zeichenkette mit einem Meldungstext zusammen, die Start- und Endzeit der Session sowie die verbrauchte Zeit enthält und das Ergebnis in einer Messagebox ausgibt (Listing 2 ab Zeile 8).

Um die verbrauchte Zeit in Minuten zu erhalten, nutzt die Subroutine in Zeile 10 die Funktion CInt(). Sie rundet das Ergebnis der Berechnung ElapsedTime/60 auf die nächste Ganzzahl, um Ergebnisse wie 27,233… zu vermeiden. Bevor die Subroutine nun irgendetwas in die Datenbank schreibt, fragt sie schließlich in Zeile 15 höflich beim Anwender nach, ob er die Daten auch wirklich speichern möchte.

Listing 2
If ElapsedTime <> 0 then
  Answer=MsgBox("Laufende Zeitmessung beenden?",4,"Messung beenden?")
  If Answer=7 then End
Else
  MsgBox "Keine Zeitmessung laeuft. Nichts zu stoppen!"
  End
EndIf
EndTime=Time
ElapsedTime=Timer-ElapsedTime
ElapsedTimeMinutes=CInt(ElapsedTime/60)
Message="Verbrauchte Zeit: ~ " & ElapsedTimeMinutes & " Minuten (" &_
ElapsedTime & " Sekunden)" & Chr(13) &_
"Begonnen um " & StartTime & " - Beendet um" & EndTime
MsgBox (Message,,"Verbrauchte Zeit")
Message="Moechten Sie die Daten speichern?"
Answer=MsgBox(Message,4,"Save")
If Answer=7 then ElapsedTime=0 End

Neben den Daten des Timers speichert die Subroutine auch den Namen des aktiven Dokuments und das aktuelle Datum. Um das tun zu können, muss sie aber diese beiden Werte zunächst einmal herausfinden. Der Weg zum Dokumentennamen führt über die in OpenOffice implementierte Funktion DirectoryNameoutofPath(). Um diese aufzurufen, muss das Makro die Bibliothek öffnen, die diese Funktion enthält (Listing 3, Zeile 1 bis 3).

Anschließend benutzt die Subroutine DirectoryNameoutofPath(), um den vollständigen Pfad zum Dokument zu erhalten (Zeile 5), und die Funktion Dir(), um daraus den Dokumentnamen zu extrahieren (Zeile 6). Das aktuelle Datum erhält die Routine über Now(), das richtige Datumsformat aus Format(). Wie Sie das Datum verwenden, liegt bei Ihnen, Sie müssen nur die entsprechenden Optionen einstellen. Der Code für das Datum im ISO-Format sieht so aus, wie in Zeile 8 von Listing 3.

Listing 3
If (Not GlobalScope.BasicLibraries.isLibraryLoaded("Tools")) Then
  GlobalScope.BasicLibraries.LoadLibrary("Tools")
End If
ThisDoc=ThisComponent
DocURL=ThisDoc.getURL()
DocDir=DirectoryNameoutofPath(DocURL, GetPathSeparator())
FileName=Dir(DocURL, 0)
DateToday=Format(Year(Now), "0000") & "-" & Format(Month(Now), "00") & "-"  & Format(Day(Now), "00")

Verbindung mit der Datenbank

Nun hat die Routine alle wichtigen Daten zusammen und kann Verbindung mit der Datenbank aufnehmen, um die ermittelten Werte dort abzulegen. Das erledigen Sie die Zeilen 1 bis 3 in Listing 4. Als erstes initialisiert das Makro den UNO-Service com.sun.star.sdb.DatabaseContext, der die Verbindung zur Datenbank überhaupt erst ermöglicht. Dann spezifiziert sie die Datenbank und stellt schließlich diese Verbindung auch her.

Anschließend schreibt sie die Daten in einen neuen Datensatz (Zeilen 3 bis 6). Um mit Base-Datenbanken zu interagieren, nutzt OOoBasic die Datenbanksprache SQL [1]. Um also Daten in die Zeiterfassungsdatenbank zu schreiben, konstruiert die Subroutine ein SQL-Kommando, das auf dem Statement INSERT INTO beruht, und führt dieses Kommando auch aus.

Was nun noch zu tun bleibt, ist das Schließen der Verbindung zur Datenbank (Zeilen 7 und 8), das Zurücksetzen der Variablen ElapsedTime auf Null (Zeile 9) und das Ausgeben einer Vollzugsmeldung an den Benutzer (Zeile 10).

Listing 4
DBContext=createUnoService("com.sun.star.sdb.DatabaseContext")
DataSource=DBContext.getByName("Zeiterfassung")
ConnectToDB=DataSource.GetConnection ("","")
SQLQuery="INSERT INTO ""time"" " + "(""Dateiname"", ""Zeit"", ""Datum"") VALUES " + "('" + FileName + "','" + ElapsedTimeMinutes + "','" + DateToday  + "')"
SQLStatement=ConnectToDB.createStatement
Result=SQLStatement.executeQuery (SQLQuery)
ConnectToDB.close()
ConnectToDB.dispose()
ElapsedTime=0
MsgBox ("Die Daten sind gesichert.", , "Alles erledigt!")

TIPP

Sollten Sie mit SQL überhaupt noch nicht vertraut sein, finden Sie bei der W3School [2] eine englischsprachige Einführung. Oder Sie greifen zu Sams Teach Yourself SQL in 10 Minutes [3].

Das Makro einbinden

Das war's. Auf der Heft-CD und unserer Website [4] finden Sie den kompletten Code. Um mit dem Makro zu arbeiten, empfehlen wir Ihnen, die Subroutinen StartTiming() und EndTiming() in die Symbolleisten aufzunehmen. Starten Sie Writer und klicken Sie dort auf Extras | Anpassen. Wechseln Sie auf den Reiter Symbolleisten und klicken Sie auf Hinzufügen. Scrollen Sie im Bereich zum Eintrag OpenOffice.org Makros | Meine Makros | Standard | Module1 und wählen Sie rechts daneben bei Befehle Ihr Modul StartTiming aus. Klicken Sie noch einmal auf Hinzufügen und wiederholen Sie diesen Schritt mit dem Eintrag EndTiming. Beide Subroutinen stehen Ihnen anschließend über die Symbolleiste Standard zur Verfügung.

Verbesserungsvorschläge

Die beschriebene Lösung zur Zeitmessung ist schon nützlich, was aber nicht heißt, dass man sie nicht noch verbessern könnte. Hier noch zwei Ideen für diejenigen, die damit anfangen möchten:

  • Wenn Sie eine Datenbank in OpenOffice.org registrieren, haben Sie von jeder Office-Anwendung aus über Ansicht | Datenquellen darauf Zugriff. Von hier aus sehen Sie nicht nur die Datensätze, sondern fügen diese auch in Ihr aktuelles Dokument ein. Diese Funktion können Sie dazu nutzen, beispielsweise eine Rechnung mit diesen Daten zu erstellen. Dazu wäre eine Rechnungsvorlage mit Feldern sehr nützlich, die sich Daten direkt aus der Datenbank holt.
  • Eine Verbesserung wäre auch das Erstellen eines grafischen Frontends für die Zeiterfassungdatenbank, das Ihnen erlaubt, die Daten komfortabel zu durchsuchen und zu ändern. So könnten Sie Base zum Beispiel für einen Bericht nutzen, der Ihnen eine Übersicht über die insgesamt für alle Dokumente verbrauchte Zeit anzeigt.

Aber das ist noch nicht alles: Mit den hier beschriebenen Techniken erstellen Sie mühelos auch Ihre eigenen Lösungen. Werfen Sie zum Beispiel einen Blick auf das Listing im Kasten "Textschnipsel"[4]: Hier handelt es sich um ein einfaches Werkzeug, das Ihnen erlaubt, beliebige Textschnipsel aus Writer in der Datenbank zu speichern. Bei genauerer Betrachtung erkennen Sie, dass seine Struktur jener unserer Zeiterfassung verblüffend ähnlich sieht. Will sagen: Wenn Sie die Grundlagen kennen und verstanden haben, können Sie damit beginnen, Ihre eigenen Tools mit OpenOffice.org Basic zu entwickeln.

Textschnipsel

rem ——————————————————–
rem Makro zur Erfassung von Textabschnitten
rem aus LinuxUser Ausgabe 03/2008
rem ——————————————————–
Sub InsertTextSnippet()
  ThisDoc=ThisComponent
  TextSnippet=ThisDoc.CurrentController.getViewCursor
  If TextSnippet.String ="" then MsgBox ("Bitte markieren Sie zuerst einen Textabschnitt!", , "Attention!") : End
  DBContext=createUnoService("com.sun.star.sdb.DatabaseContext")
  DataSource=DBContext.getByName("Zeiterfassung")
  ConnectToDB=DataSource.GetConnection ("","")
  DateToday=Format(Year(Now), "0000") & "-" & Format(Month(Now), "00") & "-"  & Format(Day(Now), "00")
  SQLQuery="INSERT INTO ""basket"" " + "(""Snippet"", ""Date"") VALUES " + "('" + TextSnippet.String + "','" + DateToday + "')"
  SQLStatement=ConnectToDB.createStatement
  Result=SQLStatement.executeQuery (SQLQuery)
  ConnectToDB.close()
  ConnectToDB.dispose()
  MsgBox ("Der Textabschnitt wurde gespeichert.", , "Alles erledigt!")
End Sub
rem — Ende des Makros ————————————
Einem Freund empfehlen    Druckansicht beenden Bookmark and Share
Kommentare