--- /dev/null
+*.o
+*.a
+*.pro.user
+*.blend1
+ui_*.h
+moc_*.cpp
+qrc_*.cpp
+Makefile
+src/bin/confclerk
This is the NEWS file for ConfClerk. ConfClerk is the successor of
fosdem-schedule; cf. docs/fosdem-schedule for the historic documentation.
-version 0.6.2, $DATE
+version 0.6.3, 20xx-xx-xx
* ...
+version 0.6.2, 2017-01-24
+* Event dialog: don't unconditionally assume plain text for description and
+ abstract, can be rich text as well (i.e. contain HTML tags).
+* Favourites: change from boolean to tri-strate: no favourite, weak/fallback
+ favourite, strong favourite. Adapt buttons and conflict markers.
+ Thanks to Elena ``of Valhalla'' for the bug report.
+ (Fixes: #54)
+* Handle SSL errors.
+ Present SSL error messages during download in a warning dialog and ask
+ user about how to proceed.
+ (In practice seen on Maemo due to ancient certificates.)
+
version 0.6.1, 2014-09-11
* Fix typos in documentation.
* Add Keyword entry to .desktop file.
Copyright and License:
Copyright (C) 2010 Ixonos Plc.
- Copyright (C) 2011-2015, Philipp Spitzer, gregor herrmann, Stefan Strahl
+ Copyright (C) 2011-2017, Philipp Spitzer, gregor herrmann, Stefan Strahl
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
src/icons/favourite*, src/icons/alarm*, src/icons/collapse*, src/icons/expand*:
- Copyright (C) 2012, Philipp Spitzer, Stefan Strahl
+ Copyright (C) 2012-2017, Philipp Spitzer, Stefan Strahl
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
http://www.toastfreeware.priv.at/confclerk/
-Tested pentabarf (or frab, or summit with patches) instances:
+Tested pentabarf (or frab, or summit/wafer with patches) instances:
-- 30C3: https://events.ccc.de/congress/2013/Fahrplan/schedule.xml
+- 33C3: https://fahrplan.events.ccc.de/congress/2016/Fahrplan/schedule.xml
- DebConf (2013, pentbarf): https://penta.debconf.org/dc13_schedule/schedule.en.xml
- DebConf (2014, summit): https://summit.debconf.org/debconf14.xml
+- DebConf (2015, summit): https://summit.debconf.org/debconf15.xml
+- DebConf (2016, wafer): https://debconf16.debconf.org/schedule/pentabarf.xml
- FOSDEM: http://fosdem.org/schedule/xml
-- FrOSCon (2014): http://programm.froscon.org/2014/schedule.xml
-- Grazer Linuxtage (2014): http://glt14-programm.linuxtage.at/schedule.de.xml
+- FrOSCon (2016): http://programm.froscon.org/2016/schedule.xml
+- Grazer Linuxtage (2016): https://glt16-programm.linuxtage.at/schedule.xml
changelog.CONFIG = phony
icon.target = data/$${TARGET}.png
-icon.commands = convert data/$${TARGET}.svg data/$${TARGET}.png
+icon.commands = convert -transparent white data/$${TARGET}.svg data/$${TARGET}.png
icon.depends = data/$${TARGET}.svg
man.target = data/$${TARGET}.1
=head2 Main code
Copyright (C) 2010 Ixonos Plc.
- Copyright (C) 2011-2015, Philipp Spitzer <philipp@toastfreeware.priv.at>
- Copyright (C) 2011-2015, gregor herrmann <gregor@toastfreeware.priv.at>
- Copyright (C) 2011-2015, Stefan Strahl <stefan@toastfreeware.priv.at>
+ Copyright (C) 2011-2017, Philipp Spitzer <philipp@toastfreeware.priv.at>
+ Copyright (C) 2011-2017, gregor herrmann <gregor@toastfreeware.priv.at>
+ Copyright (C) 2011-2017, Stefan Strahl <stefan@toastfreeware.priv.at>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
=item src/icons/favourite*, src/icons/alarm*, src/icons/collapse*, src/icons/expand*:
- Copyright (C) 2012, Philipp Spitzer <philipp@toastfreeware.priv.at>
- Copyright (C) 2012, Stefan Strahl <stefan@toastfreeware.priv.at>
+ Copyright (C) 2012-2017, Philipp Spitzer <philipp@toastfreeware.priv.at>
+ Copyright (C) 2012-2017, Stefan Strahl <stefan@toastfreeware.priv.at>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
* You should have received a copy of the GNU General Public License along with
* ConfClerk. If not, see <http://www.gnu.org/licenses/>.
*/
+#if defined(__GNUC__) || defined(__llvm__) || defined(__clang__)
+#include <cxxabi.h>
+#endif
+#include <exception>
+
#include "application.h"
#include "errormessage.h"
} catch (OrmException& e) {
error_message("UNCAUGHT OrmException: " + e.text());
return false;
+ } catch (std::exception& e) {
+ error_message("UNCAUGHT exception: " + QString(e.what()));
+ return false;
} catch (...) {
- error_message("UNCAUGHT EXCEPTION: unknown");
+#if defined(__GNUC__) || defined(__llvm__) || defined(__clang__)
+ int status = 0;
+ char *buff = __cxxabiv1::__cxa_demangle(
+ __cxxabiv1::__cxa_current_exception_type()->name(),
+ NULL, NULL, &status);
+ QString exception_name = QString(buff);
+ std::free(buff);
+#else
+ QString exception_name = QString("unknown");
+#endif
+ error_message("UNCAUGHT exception: " + exception_name);
return false;
}
}
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
subtitle VARCHAR,
abstract VARCHAR,
description VARCHAR,
- favourite INTEGER DEFAULT 0,
+ favourite INTEGER DEFAULT 0, -- 0 ... no favourite, 1 ... strong favourite, 2 ... weak favourite/alternative to strong favourite
alarm INTEGER DEFAULT 0,
PRIMARY KEY (xid_conference, id)
);
# USAGE: include(./global.pri)
# VERSION
-VERSION = 0.6.2
+VERSION = 0.6.3
DEFINES += VERSION=\\\"$$VERSION\\\"
# Define 'MAEMO' specific CONFIG/DEFINE
<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Copyright and license</span></p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ConfClerk is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version.</p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ConfClerk is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p>
-<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (C) 2010 Ixonos Plc.<br />Copyright (C) 2011-2015 Philipp Spitzer &amp; gregor herrmann &amp; Stefan Strahl</p></body></html></string>
+<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (C) 2010 Ixonos Plc.<br />Copyright (C) 2011-2017 Philipp Spitzer &amp; gregor herrmann &amp; Stefan Strahl</p></body></html></string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
// abstract
info += QString("<h2>%1</h2>\n").arg(tr("Abstract"));
- info += Qt::convertFromPlainText(event.abstract(), Qt::WhiteSpaceNormal);
+ if (Qt::mightBeRichText(event.abstract())) {
+ info += event.abstract();
+ } else {
+ info += Qt::convertFromPlainText(event.abstract(), Qt::WhiteSpaceNormal);
+ }
// description
info += QString("<h2>%1</h2>\n").arg(tr("Description"));
- info += Qt::convertFromPlainText(event.description(), Qt::WhiteSpaceNormal);
+ if (Qt::mightBeRichText(event.description())) {
+ info += event.description();
+ } else {
+ info += Qt::convertFromPlainText(event.description(), Qt::WhiteSpaceNormal);
+ }
// links
info += QString("<h2>%1</h2>\n<ul>\n").arg(tr("Links"));
connect(favouriteButton, SIGNAL(clicked()), SLOT(favouriteClicked()));
connect(alarmButton, SIGNAL(clicked()), SLOT(alarmClicked()));
- if(event.isFavourite())
- {
- favouriteButton->setIcon(QIcon(":/icons/favourite-on.png"));
- }
+ updateFavouriteButton(event);
if(event.hasAlarm())
{
void EventDialog::favouriteClicked()
{
Event event = Event::getById(mEventId, mConferenceId);
-
- QList<Event> conflicts = Event::conflictEvents(event.id(), mConferenceId);
- if(event.isFavourite())
- {
- event.setFavourite(false);
- favouriteButton->setIcon(QIcon(":/icons/favourite-off.png"));
- }
- else
- {
- event.setFavourite(true);
- favouriteButton->setIcon(QIcon(":/icons/favourite-on.png"));
- }
+ event.cycleFavourite();
event.update("favourite");
+ updateFavouriteButton(event);
- if(event.isFavourite())
- {
- // event has became 'favourite' and so 'conflicts' list may have changed
- conflicts = Event::conflictEvents(event.id(), mConferenceId);
- }
+ // 'conflicts' list may have changed
+ QList<Event> conflicts = Event::conflictEvents(event.id(), mConferenceId);
// have to emit 'eventChanged' signal on all events in conflict
for(int i=0; i<conflicts.count(); i++)
emit eventChanged(event.id(), false);
}
+
+void EventDialog::updateFavouriteButton(const Event& event) {
+ switch (event.favourite()) {
+ case Favourite_no: favouriteButton->setIcon(QIcon(":/icons/favourite-no.png")); break;
+ case Favourite_weak: favouriteButton->setIcon(QIcon(":/icons/favourite-weak.png")); break;
+ case Favourite_strong: favouriteButton->setIcon(QIcon(":/icons/favourite-strong.png")); break;
+ }
+}
+
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
private:
int mConferenceId;
int mEventId;
+ void updateFavouriteButton(const Event& event);
};
#endif /* EVENTDIALOG_H */
</property>
<property name="icon">
<iconset resource="../icons.qrc">
- <normaloff>:/icons/favourite-off.png</normaloff>:/icons/favourite-off.png</iconset>
+ <normaloff>:/icons/favourite-no.png</normaloff>:/icons/favourite-no.png</iconset>
</property>
<property name="iconSize">
<size>
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
#include <QNetworkProxy>
#include <QNetworkAccessManager>
#include <QNetworkReply>
+#include <QSslConfiguration>
#include "sqlengine.h"
clearTabs();
}
+ connect(mNetworkAccessManager, SIGNAL(sslErrors(QNetworkReply*, QList<QSslError>)), SLOT(sslErrors(QNetworkReply*, QList<QSslError>)));
connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
connect(mXmlParser, SIGNAL(parsingScheduleEnd(int)), conferenceModel, SLOT(newConferenceEnd(int)));
// show message
systemTrayIcon->show();
// The next two lines are to prevent a very strange position of the message box the first time at X11/aweseome (not Win32/XP)
- systemTrayIcon->showMessage("ConfClerk", "Your upcoming events", QSystemTrayIcon::Information);
+ systemTrayIcon->showMessage("ConfClerk", tr("Your upcoming events"), QSystemTrayIcon::Information);
qApp->processEvents();
systemTrayIcon->showMessage(title, message, QSystemTrayIcon::Information, 60*60*24*1000);
QApplication::alert(this);
// end of optimization
// initTabs();
- } catch (OrmException& e) {
+ } catch (const OrmException& e) {
+ qDebug() << "OrmException:" << e.text();
// cannon set an active conference
unsetConference(); // TODO: as no active conference is now correctly managed this should be handled as a fatal error
return;
// optimization, see useConference() code
try {
initTabs();
- } catch (OrmException) {
+ } catch (const OrmException& e) {
+ qDebug() << "OrmException:" << e.text();
clearTabs();
}
}
+void MainWindow::sslErrors(QNetworkReply *aReply, const QList<QSslError> &errors) {
+ QString errorString;
+ foreach (const QSslError &error, errors) {
+ if (!errorString.isEmpty()) {
+ errorString += ", ";
+ }
+ errorString += error.errorString();
+ }
+
+ if (QMessageBox::warning(
+ this,
+ tr("SSL errors"),
+ tr("One or more SSL errors have occurred: %1", 0, errors.size()).arg(errorString),
+ QMessageBox::Ignore | QMessageBox::Cancel) == QMessageBox::Ignore) {
+ aReply->ignoreSslErrors();
+ } else {
+ aReply->abort();
+ }
+}
+
void MainWindow::networkQueryFinished(QNetworkReply *aReply) {
if (aReply->error() != QNetworkReply::NoError) {
- error_message(QString("Error occured during download: ") + aReply->errorString());
+ error_message(tr("Error occurred during download: %1").arg(aReply->errorString()));
} else {
QUrl redirectUrl = aReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
if (!redirectUrl.isEmpty()) {
importFromNetwork(redirectUrl.toString(), aReply->request().attribute(QNetworkRequest::User).toInt());
return; // don't enable controls
} else {
- error_message(QString("Error: Cyclic redirection from %1 to itself.").arg(redirectUrl.toString()));
+ error_message(tr("Error: Cyclic redirection from %1 to itself.").arg(redirectUrl.toString()));
}
} else {
importData(aReply->readAll(), aReply->url().toEncoded(), aReply->request().attribute(QNetworkRequest::User).toInt());
void MainWindow::importFromNetwork(const QString& url, int conferenceId)
{
QNetworkRequest request;
+ QSslConfiguration qSslConfiguration = request.sslConfiguration();
+ qSslConfiguration.setProtocol(QSsl::AnyProtocol);
+ qSslConfiguration.setPeerVerifyMode(QSslSocket::QueryPeer);
request.setUrl(QUrl(url));
+ request.setSslConfiguration(qSslConfiguration);
request.setAttribute(QNetworkRequest::User, conferenceId);
mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
#define MAINWINDOW_H
#include <QtWidgets>
+#include <QSslError>
#include "ui_mainwindow.h"
void onEventChanged(int aEventId, bool favouriteChanged);
void onSearchResultChanged();
+ void sslErrors(QNetworkReply*,const QList<QSslError> &errors);
void networkQueryFinished(QNetworkReply*);
void importFromNetwork(const QString&, int conferenceId);
void importFromFile(const QString&, int conferenceId);
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
<file>icons/dialog-warning.png</file>
<file>icons/search.png</file>
<file>icons/today.png</file>
- <file>icons/favourite-off.png</file>
- <file>icons/favourite-on.png</file>
+ <file>icons/favourite-no.png</file>
+ <file>icons/favourite-weak.png</file>
+ <file>icons/favourite-strong.png</file>
<file>icons/alarm-on.png</file>
<file>icons/alarm-off.png</file>
</qresource>
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
if(hasParent(index))
{
+ Event *event = static_cast<Event*>(index.internalPointer());
+
+ // determine severity of conflict
+ Favourite eventTimeConflict = event->timeConflict(); // cache value as event->timeConflict is expensive
+ enum ConflictSeverity {csNone, csWeak, csStrong} conflictSeverity = csNone;
+ switch (event->favourite()) {
+ case Favourite_strong:
+ conflictSeverity = (eventTimeConflict == Favourite_strong) ? csStrong : csNone;
+ break;
+ case Favourite_weak:
+ conflictSeverity = (eventTimeConflict == Favourite_no) ? csNone : csWeak;
+ break;
+ case Favourite_no:
+ conflictSeverity = csNone;
+ break;
+ }
+
// entry horizontal layout:
// * spacer (aka y position of image)
// * image
// * rest is text, which is 1 line of title with big letters and 2 lines of Presenter and Track
- int aux = option.rect.height() - SPACER - mControls[FavouriteControlOn]->image()->height();
- Event *event = static_cast<Event*>(index.internalPointer());
+ int aux = option.rect.height() - SPACER - mControls[FavouriteControlStrong]->image()->height();
// font SMALL
QFont fontSmall = option.font;
QFontMetrics fmBigB(fontBigB);
// background (in case of time conflicts)
- if(event->hasTimeConflict()) {
- painter->setBrush(Qt::yellow);
+ if (conflictSeverity != csNone) {
+ painter->setBrush(conflictSeverity == csStrong ? Qt::yellow : QColor("lightyellow"));
painter->setPen(Qt::NoPen);
painter->drawRect(option.rect);
}
foreach(Control* c, mControls.values()) {
c->setEnabled(false);
}
- if(event->isFavourite())
- mControls[FavouriteControlOn]->paint(painter, option.rect);
- else
- mControls[FavouriteControlOff]->paint(painter, option.rect);
+ switch (event->favourite()) {
+ case Favourite_strong:
+ mControls[FavouriteControlStrong]->paint(painter, option.rect);
+ break;
+ case Favourite_weak:
+ mControls[FavouriteControlWeak]->paint(painter, option.rect);
+ break;
+ case Favourite_no:
+ mControls[FavouriteControlNo]->paint(painter, option.rect);
+ break;
+ }
if(event->hasAlarm())
mControls[AlarmControlOn]->paint(painter, option.rect);
else
mControls[AlarmControlOff]->paint(painter, option.rect);
- if(event->hasTimeConflict())
+ if(eventTimeConflict != Favourite_no)
mControls[WarningControl]->paint(painter, option.rect);
// draw texts
// it starts just below the image
// ("position of text" is lower-left angle of the first letter,
// so the first line is actually at the same height as the image)
- painter->setPen(QPen(event->hasTimeConflict() ? Qt::black : textColor));
+ painter->setPen(QPen(conflictSeverity != csNone ? Qt::black : textColor));
QPointF titlePointF(option.rect.x() + SPACER,
- option.rect.y() + SPACER + mControls[FavouriteControlOn]->image()->height());
+ option.rect.y() + SPACER + mControls[FavouriteControlStrong]->image()->height());
QTime start = event->start().time();
painter->setFont(fontBig);
painter->drawText(titlePointF,start.toString("hh:mm") + "-" + start.addSecs(event->duration()).toString("hh:mm") + ", " + event->roomName());
// draw icons
painter->setPen(QPen(textColor));
painter->setFont(fontSmall);
- QImage *image = mControls[numFav ? FavouriteControlOn : FavouriteControlOff]->image();
+ QImage *image = mControls[numFav ? FavouriteControlStrong : FavouriteControlNo]->image();
QPoint drawPoint =
option.rect.topRight()
- QPoint(
void Delegate::defineControls()
{
// FAVOURITE ICONs
- // on
- mControls.insert(FavouriteControlOn, new Control(FavouriteControlOn, QString(":icons/favourite-on.png"), NULL));
- // off
- mControls.insert(FavouriteControlOff, new Control(FavouriteControlOff, QString(":icons/favourite-off.png"), NULL));
+ // strong
+ mControls.insert(FavouriteControlStrong, new Control(FavouriteControlStrong, QString(":icons/favourite-strong.png"), NULL));
+ // weak
+ mControls.insert(FavouriteControlWeak, new Control(FavouriteControlWeak, QString(":icons/favourite-weak.png"), NULL));
+ // no
+ mControls.insert(FavouriteControlNo, new Control(FavouriteControlNo, QString(":icons/favourite-no.png"), NULL));
// ALARM ICONs
// on
mControls.insert(AlarmControlOn,
- new Control(AlarmControlOn, QString(":icons/alarm-on.png"), mControls[FavouriteControlOn]));
+ new Control(AlarmControlOn, QString(":icons/alarm-on.png"), mControls[FavouriteControlStrong]));
// off
mControls.insert(AlarmControlOff,
- new Control(AlarmControlOff, QString(":icons/alarm-off.png"), mControls[FavouriteControlOff]));
+ new Control(AlarmControlOff, QString(":icons/alarm-off.png"), mControls[FavouriteControlNo]));
// WARNING ICON
mControls.insert(WarningControl,
new Control(WarningControl, QString(":icons/dialog-warning.png"), mControls[AlarmControlOff]));
int nrofFavs = 0;
for(int i=0; i<index.model()->rowCount(index); i++)
- if(static_cast<Event*>(index.child(i,0).internalPointer())->isFavourite())
+ if(static_cast<Event*>(index.child(i,0).internalPointer())->favourite() != Favourite_no)
nrofFavs++;
return nrofFavs;
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
enum ControlId
{
ControlNone = 0,
- FavouriteControlOn,
- FavouriteControlOff,
+ FavouriteControlStrong,
+ FavouriteControlWeak,
+ FavouriteControlNo,
AlarmControlOn,
AlarmControlOff,
WarningControl
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
<< QSqlField("xid_track", QVariant::Int)
<< QSqlField("type", QVariant::String)
<< QSqlField("language", QVariant::String)
- << QSqlField("favourite", QVariant::Bool)
+ << QSqlField("favourite", QVariant::Int)
<< QSqlField("alarm", QVariant::Bool)
<< QSqlField("tag", QVariant::String)
<< QSqlField("title", QVariant::String)
query.prepare(selectQuery() + "WHERE xid_conference = :conf AND ( \
( start >= :s1 AND ( start + duration ) < :e1 ) \
OR ( ( start + duration ) > :s2 AND start < :e2 ) ) \
- AND favourite = 1 AND NOT id = :id ORDER BY start, duration");
+ AND favourite >= 1 AND NOT id = :id ORDER BY start, duration");
query.bindValue(":conf", event.conferenceId());
query.bindValue(":s1", convertToDb(event.start(), QVariant::DateTime));
query.bindValue(":e1", convertToDb(event.start().toTime_t()+event.duration(), QVariant::DateTime));
Conference conference = Conference::getById(conferenceId);
QDateTime dayStart(date, conference.dayChangeTime(), Qt::UTC);
QSqlQuery query;
- query.prepare(selectQuery() + QString("WHERE xid_conference = :conf AND start >= :start AND start < :end AND favourite = 1 ORDER BY start, duration"));
+ query.prepare(selectQuery() + QString("WHERE xid_conference = :conf AND start >= :start AND start < :end AND favourite >= 1 ORDER BY start, duration"));
query.bindValue(":conf", conferenceId);
query.bindValue(":start", dayStart.toTime_t());
query.bindValue(":end", dayStart.addDays(1).toTime_t());
return mLinksList;
}
-bool Event::hasTimeConflict() const
-{
- if(!isFavourite()) // if it's not favourite, it can't have time-conflict
- return false;
+Favourite Event::timeConflict() const {
+ if (favourite() == Favourite_no) // if it's not favourite, it can't have time-conflict
+ return Favourite_no;
+
+ QList<Event> events = conflictEvents(id(),conferenceId());
+
+ // find "strongest" conflict
+ Favourite f = Favourite_no;
+ for (int i = 0; i != events.size(); ++i) {
+ switch (events[i].favourite()) {
+ case Favourite_strong: f = Favourite_strong; break;
+ case Favourite_weak: if (f == Favourite_no) f = Favourite_weak; break;
+ case Favourite_no: break;
+ }
+ }
+ return f;
+
+}
- return conflictEvents(id(),conferenceId()).count() > 0 ? true : false;
+void Event::cycleFavourite(bool back) {
+ switch (favourite()) {
+ case Favourite_no: setFavourite(back ? Favourite_weak : Favourite_strong); break;
+ case Favourite_strong: setFavourite(back ? Favourite_no : Favourite_weak); break;
+ case Favourite_weak: setFavourite(back ? Favourite_strong : Favourite_no); break;
+ }
}
void Event::setRoom(const QString &room)
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
{
};
+
+enum Favourite {Favourite_no=0, Favourite_weak=2, Favourite_strong=1};
+
+
class Event : public OrmRecord<Event>
{
public:
int trackId() const { return value("xid_track").toInt(); }
QString type() const { return value("type").toString(); }
QString language() const { return value("language").toString(); }
- bool isFavourite() const { return value("favourite").toBool(); }
+ Favourite favourite() const { return static_cast<Favourite>(value("favourite").toInt()); }
bool hasAlarm() const { return value("alarm").toBool(); }
- bool hasTimeConflict() const;
+ Favourite timeConflict() const;
QString tag() const { return value("tag").toString(); }
QString title() const { return value("title").toString(); }
QString subtitle() const { return value("subtitle").toString(); }
void setTrackId(int trackId) { setValue("xid_track", trackId); }
void setType(const QString & type) { setValue("type", type); }
void setLanguage(const QString & language) { setValue("language", language); }
- void setFavourite(bool favourite) { setValue("favourite", (int)((favourite))); }
+ void setFavourite(Favourite favourite) { setValue("favourite", (int) favourite); }
+ void cycleFavourite(bool back = false);
void setHasAlarm(bool alarm) { setValue("alarm", (int)((alarm))); }
void setTag(const QString& tag) { setValue("tag", tag); }
void setTitle(const QString& title) { setValue("title", title); }
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
<< QSqlField(CONFERENCEID, QVariant::Int)
<< QSqlField(NAME, QVariant::String));
-class TrackInsertException : OrmSqlException
+class TrackInsertException : public OrmSqlException
{
public:
TrackInsertException(const QString& text) : OrmSqlException(text) {}
int Track::insert()
{
QSqlQuery query;
- query.prepare("INSERT INTO " + sTableName + " (" + CONFERENCEID + "," + NAME + ")" + " VALUES " + "(\"" + QString::number(conferenceid()) + "\",\"" + name() + "\")");
+ QString trackname = name();
+ query.prepare(
+ QString("INSERT INTO %1 (%2, %3) VALUES (:xid_conference, :name)")
+ .arg(sTableName, CONFERENCEID, NAME));
+ query.bindValue(":xid_conference", conferenceid());
+ query.bindValue(":name", trackname);
if (!query.exec())
{
- throw TrackInsertException("Exec Error");
+ throw TrackInsertException(
+ "Inserting track '" + trackname + "' into database failed: " +
+ query.lastError().text());
}
QVariant variant = query.lastInsertId();
if (variant.isValid())
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
QPoint point = aEvent->pos();
// test whether we have handled the mouse event
- if(!testForControlClicked(index,point))
+ if(!testForControlClicked(index, point, aEvent->button()))
{
// pass the event to the Base class, so item clicks/events are handled correctly
QTreeView::mouseReleaseEvent(aEvent);
}
// returns bool if some Control was clicked
-bool TreeView::testForControlClicked(const QModelIndex &aIndex, const QPoint &aPoint)
+bool TreeView::testForControlClicked(const QModelIndex &aIndex, const QPoint &aPoint, Qt::MouseButton button)
{
bool handled = false;
Delegate *delegate = static_cast<Delegate*>(itemDelegate(aIndex));
switch(delegate->whichControlClicked(aIndex,aPoint))
{
- case Delegate::FavouriteControlOn:
- case Delegate::FavouriteControlOff:
+ case Delegate::FavouriteControlStrong:
+ case Delegate::FavouriteControlWeak:
+ case Delegate::FavouriteControlNo:
{
// handle Favourite Control clicked
Event event = Event::getById(aIndex.data().toInt(),confId);
QList<Event> conflicts = Event::conflictEvents(event.id(),Conference::activeConference());
- event.setFavourite(!event.isFavourite());
+ event.cycleFavourite(button == Qt::RightButton);
event.update("favourite");
- if(event.isFavourite())
- {
- // event has became 'favourite' and so 'conflicts' list may have changed
- conflicts = Event::conflictEvents(event.id(),Conference::activeConference());
- }
+ // event has became 'favourite' and so 'conflicts' list may have changed
+ conflicts = Event::conflictEvents(event.id(),Conference::activeConference());
// have to emit 'eventChanged' signal on all events in conflict
for(int i=0; i<conflicts.count(); i++)
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
~TreeView() {}
private:
void mouseReleaseEvent(QMouseEvent *aEvent);
- bool testForControlClicked(const QModelIndex &aIndex, const QPoint &aPoint);
+ bool testForControlClicked(const QModelIndex &aIndex, const QPoint &aPoint, Qt::MouseButton button);
public slots:
void setAllExpanded(bool aExpanded); // (aExpanded==true) => expanded; (aExpanded==false) => collapsed
private slots:
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
#include <QStringList>
#include <QDateTime>
#include <QDebug>
+#include <stdexcept>
-class OrmException
+class OrmException : public std::runtime_error
{
public:
- OrmException(const QString& text) : mText(text) {}
+ OrmException(const QString& text) : std::runtime_error(text.toStdString()), mText(text) {}
virtual ~OrmException(){}
virtual const QString& text() const { return mText; }
private:
class OrmNoObjectException : public OrmException
{
public:
- OrmNoObjectException() : OrmException("No object exception"){}
+ OrmNoObjectException() : OrmException("SQL query expects one record but found none."){}
~OrmNoObjectException(){}
};
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
Track track;
int trackId;
QString trackName = aEvent["track"];
+ if (trackName.isEmpty()) trackName = tr("No track");
try
{
track = Track::retrieveByName(conferenceId, trackName);
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*
/*
* Copyright (C) 2010 Ixonos Plc.
- * Copyright (C) 2011-2015 Philipp Spitzer, gregor herrmann, Stefan Stahl
+ * Copyright (C) 2011-2017 Philipp Spitzer, gregor herrmann, Stefan Stahl
*
* This file is part of ConfClerk.
*