calDAV und iCalendar code example mit Qt, C++ und QML

Nachdem ich mich letztes Jahr schon hier und da mit Kalendern für Webseiten und dem iCalendar-Format beschäftigt hatte, habe ich letztens während dem 33C3 in Hamburg noch einen calDAV-Client in C++ und QML mit Qt geschrieben. Zweck: den Küchen-Computer um eine Kalenderansicht mit meinen anstehenden Terminen erweitern. Da ich keinen passenden Beispielcode finden konnte, der nicht entweder nur ansatzweise funktioniert oder völlig overfeatured ist, habe ich kurzerhand anhand der offiziellen Spezifikation selbst etwas geschrieben:
Screenshot
GUI-Screenshot des Beispielprojekts
Features (u.a.):
  • Verbindet sich mit calDAV-Servern (z.B. ownCloud, Nextcloud, etc.)
  • Lädt iCalendar-Dateien von Festplatte oder über HTTP und HTTPS
  • Verarbeitet Wiederholungsregeln für Terminserien und erstellt Listen von Terminen für einzelne Kalenderdaten
  • Verwaltet mehrere Kalenderquellen simultan
  • Anlegen, Editieren und Löschen von Terminen
  • ... usw. ...
Eine komplette Beschreibung und Download gibt es auf der Projektseite... Das Beispielprojekt und zugehöriger source code stehen unter CC BY-NC-SA 3.0.

Qt: bloß keine Waisenkinder instantiieren

Wenn man in Qt eine Klasse implementiert, sollte man tunlichst darauf achten, dass alle instantiierten Attribute this als parent haben. Andernfalls kann es nämlich sein, dass irgendwann der Garbage-Kollektor auf das offenbar elternlose Kind-Objekt stößt und es im Sinne von "ist das Kunst oder kann das weg" in die Tonne wirft. Und dann hat man den Salat. Ist mir hiermit passiert:
  1. class Measurement : public Object
  2. {
  3. Q_OBJECT
  4. public:
  5.   Measurement(QObject* parent = 0);
  6.   ~Measurement();
  7. };
  8. class XYPlot : public QQuickPaintedItem
  9. {
  10. Q_OBJECT
  11. public:
  12.   XYPlot(QQuickPaintedItem* parent = 0);
  13. private:
  14.   Measurement m_Measurement;
  15. };
Das Elternelement hier ist XYPlot, welches ein Attribut der Klasse Measurement besitzt. Bei mir gab es unreproduzierbare SIGSEGV segmentation faults, was immer auf irgendein Problem mit ungültigem Pointer hinweist. Beim Debuggen habe ich dann festgestellt, dass kurz zuvor der Dekonstruktor von Measurement aufgerufen wurde - obwohl das zugehörige XYPlot-Objekt noch existierte. Woran lag es? ⇒ Ich hatte vergessen, dem Kind-Objekt zu sagen wer sein parent ist. Im Konstruktor der Elternklasse XYPlot also m_Measurement mit this instantiieren:
  1. XYPlot::XYPlot( QQuickPaintedItem* parent) : QQuickPaintedItem(parent), m_Measurement(this)
  2. {
  3. }
Also besser gut aufpassen bei so was, sonst kann das Debugging richtig ätzend werden.