source: confclerk_git/src/gui/mainwindow.cpp @ 54a377c

qt5
Last change on this file since 54a377c was 54a377c, checked in by Philipp Spitzer <philipp@…>, 9 years ago

Prepared to show an alarm message via tray icon on non-MAEMO systems.

  • Property mode set to 100644
File size: 14.6 KB
Line 
1/*
2 * Copyright (C) 2010 Ixonos Plc.
3 * Copyright (C) 2011-2012 Philipp Spitzer, gregor herrmann, Stefan Stahl
4 *
5 * This file is part of ConfClerk.
6 *
7 * ConfClerk is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * ConfClerk is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * ConfClerk.  If not, see <http://www.gnu.org/licenses/>.
19 */
20#include "mainwindow.h"
21
22#include <QTreeView>
23#include <QFile>
24#include <QNetworkProxy>
25#include <QNetworkAccessManager>
26#include <QNetworkReply>
27
28#include "sqlengine.h"
29
30#include "track.h"
31#include "eventmodel.h"
32#include "delegate.h"
33
34#include "conference.h"
35
36#include <QDialog>
37#include <QMessageBox>
38
39#include "ui_about.h"
40#include "eventdialog.h"
41#include "daynavigatorwidget.h"
42#include "settingsdialog.h"
43#include "conferenceeditor.h"
44#include "schedulexmlparser.h"
45#include "errormessage.h"
46
47#include "tabcontainer.h"
48#include "appsettings.h"
49
50const QString PROXY_USERNAME;
51const QString PROXY_PASSWD;
52
53MainWindow::MainWindow(QWidget* parent): QMainWindow(parent) {
54    setupUi(this);
55
56    // Open database
57    sqlEngine = new SqlEngine(this);
58    searchTabContainer->setSqlEngine(sqlEngine);
59    connect(sqlEngine, SIGNAL(dbError(QString)), this, SLOT(showError(QString)));
60    sqlEngine->open();
61    sqlEngine->createOrUpdateDbSchema();
62
63    conferenceModel = new ConferenceModel(this);
64    mXmlParser = new ScheduleXmlParser(sqlEngine, this);
65    mNetworkAccessManager = new QNetworkAccessManager(this);
66    systemTrayIcon = new QSystemTrayIcon(qApp->windowIcon(), this);
67    alarmTimer = new QTimer(this);
68
69    alarmTimer->setInterval(60000);
70    alarmTimer->start();
71    saved_title = windowTitle();
72
73#ifdef N810
74    tabWidget->setTabText(1,"Favs");
75    //tabWidget->setTabText(2,"Day");
76#endif
77
78    // first time run aplication: -> let's have it direct connection in this case
79    if(!AppSettings::contains("proxyIsDirectConnection"))
80        AppSettings::setDirectConnection(true);
81
82    QNetworkProxy proxy(
83            AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
84            AppSettings::proxyAddress(),
85            AppSettings::proxyPort(),
86            PROXY_USERNAME,
87            PROXY_PASSWD);
88    QNetworkProxy::setApplicationProxy(proxy);
89
90    // event details have changed
91    connect(dayTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
92    connect(favsTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
93    connect(tracksTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
94    connect(roomsTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
95    connect(searchTabContainer, SIGNAL(eventChanged(int,bool)), SLOT(onEventChanged(int,bool)));
96
97    // date has changed
98    connect(dayNavigator, SIGNAL(dateChanged(QDate)), dayTabContainer, SLOT(redisplayDate(QDate)));
99    connect(dayNavigator, SIGNAL(dateChanged(QDate)), favsTabContainer, SLOT(redisplayDate(QDate)));
100    connect(dayNavigator, SIGNAL(dateChanged(QDate)), tracksTabContainer, SLOT(redisplayDate(QDate)));
101    connect(dayNavigator, SIGNAL(dateChanged(QDate)), roomsTabContainer, SLOT(redisplayDate(QDate)));
102    connect(dayNavigator, SIGNAL(dateChanged(QDate)), searchTabContainer, SLOT(redisplayDate(QDate)));
103
104    // search result has changed
105    connect(searchTabContainer, SIGNAL(searchResultChanged()), SLOT(onSearchResultChanged()));
106
107    // systm tray icon
108    connect(systemTrayIcon, SIGNAL(messageClicked()), SLOT(onSystemTrayMessageClicked()));
109
110    // timer
111    connect(alarmTimer, SIGNAL(timeout()), SLOT(onAlarmTimerTimeout()));
112
113    useConference(Conference::activeConference());
114    // optimization, see useConference() code
115    try {
116        initTabs();
117    } catch (const OrmException& e) {
118        qDebug() << "OrmException:" << e.text();
119        clearTabs();
120    }
121
122    connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(networkQueryFinished(QNetworkReply*)));
123    connect(mXmlParser, SIGNAL(parsingScheduleBegin()), conferenceModel, SLOT(newConferenceBegin()));
124    connect(mXmlParser, SIGNAL(parsingScheduleEnd(int)), conferenceModel, SLOT(newConferenceEnd(int)));
125}
126
127
128void MainWindow::on_aboutAction_triggered()
129{
130    QDialog dialog(this);
131    Ui::AboutDialog ui;
132    ui.setupUi(&dialog);
133    ui.labDescription->setText(ui.labDescription->text().arg(qApp->applicationVersion()));
134#ifdef N810
135    dialog.setFixedWidth(width());
136#endif
137    dialog.exec();
138}
139
140
141void MainWindow::on_reloadAction_triggered() {
142    int confId = Conference::activeConference();
143    if (confId== -1) return;
144    Conference active = Conference::getById(confId);
145    if (active.url().isEmpty()) return;
146    importFromNetwork(active.url(), confId);
147    setEnabled(false);
148}
149
150
151void MainWindow::on_nowAction_triggered() {
152    int confId = Conference::activeConference();
153    if (confId== -1) return;
154    dayNavigator->setCurDate(QDate::currentDate());
155    dayTabContainer->expandTimeGroup(QTime::currentTime(), confId);
156}
157
158
159void MainWindow::on_searchAction_triggered() {
160    if (tabWidget->currentWidget() == searchTab)
161        searchTabContainer->showSearchDialog(!searchTabContainer->searchDialogIsVisible());
162    else {
163        tabWidget->setCurrentWidget(searchTab);
164        searchTabContainer->showSearchDialog();
165    }
166}
167
168
169void MainWindow::on_expandAllAction_triggered() {
170    if (tabWidget->currentWidget() == favouritesTab) favsTabContainer->treeView->expandAll();
171    if (tabWidget->currentWidget() == dayViewTab) dayTabContainer->treeView->expandAll();
172    if (tabWidget->currentWidget() == tracksTab) tracksTabContainer->treeView->expandAll();
173    if (tabWidget->currentWidget() == roomsTab) roomsTabContainer->treeView->expandAll();
174    if (tabWidget->currentWidget() == searchTab) searchTabContainer->treeView->expandAll();
175}
176
177
178void MainWindow::on_collapseAllAction_triggered() {
179    if (tabWidget->currentWidget() == favouritesTab) favsTabContainer->treeView->collapseAll();
180    if (tabWidget->currentWidget() == dayViewTab) dayTabContainer->treeView->collapseAll();
181    if (tabWidget->currentWidget() == tracksTab) tracksTabContainer->treeView->collapseAll();
182    if (tabWidget->currentWidget() == roomsTab) roomsTabContainer->treeView->collapseAll();
183    if (tabWidget->currentWidget() == searchTab) searchTabContainer->treeView->collapseAll();
184}
185
186
187void MainWindow::onEventChanged(int aEventId, bool favouriteChanged) {
188    dayTabContainer->redisplayEvent(aEventId);
189    if (favouriteChanged) favsTabContainer->redisplayDate(dayNavigator->curDate());
190    else favsTabContainer->redisplayEvent(aEventId);
191    tracksTabContainer->redisplayEvent(aEventId);
192    roomsTabContainer->redisplayEvent(aEventId);
193    searchTabContainer->redisplayEvent(aEventId);
194}
195
196
197void MainWindow::onSearchResultChanged() {
198    // Are results found on the current date?
199    QDate date = dayNavigator->curDate();
200    int count = searchTabContainer->searchResultCount(date);
201    if (count > 0) {searchTabContainer->redisplayDate(date); return;}
202
203    // Are results found in the future?
204    for (date = date.addDays(1); date <= dayNavigator->endDate(); date = date.addDays(1)) {
205        int count = searchTabContainer->searchResultCount(date);
206        if (count > 0) {dayNavigator->setCurDate(date); return;}
207    }
208
209    // Are results found in the past?
210    for (date = dayNavigator->startDate(); date < dayNavigator->curDate(); date = date.addDays(1)) {
211        int count = searchTabContainer->searchResultCount(date);
212        if (count > 0) {dayNavigator->setCurDate(date); return;}
213    }
214    // No results were found
215    searchTabContainer->redisplayDate(dayNavigator->curDate());
216}
217
218
219void MainWindow::onSystemTrayMessageClicked() {
220    // TODO: Hide icon
221}
222
223
224void MainWindow::onAlarmTimerTimeout() {
225    // TODO: Show Message if an alarm is set on an event that's starting soon and delete the corresponding alarm.
226    /* Example:
227    systemTrayIcon->show();
228    systemTrayIcon->showMessage("title", "message", QSystemTrayIcon::Information, 1000);
229    QApplication::alert(this);
230    QApplication::beep();
231    */
232}
233
234
235void MainWindow::useConference(int conferenceId)
236{
237    if (conferenceId == -1)  // in case no conference is active
238    {
239        unsetConference();
240        return;
241    }
242    try {
243        int oldActiveConferenceId = Conference::activeConference();
244        bool switchActiveConference = conferenceId != oldActiveConferenceId;
245        if (switchActiveConference) Conference::getById(oldActiveConferenceId).update("active", 0);
246        Conference activeConference = Conference::getById(conferenceId);
247        if (switchActiveConference) activeConference.update("active",1);
248
249        // looks like it does not work at n900
250        setWindowTitle(activeConference.title());
251
252        // optimization.
253        // dont run initTabs() here
254        // it takes much CPU, making travelling between conferences in ConferenceEditor longer
255        // and is not seen in maemo WM anyway
256        // instead run it explicitly
257        // 1. at startup
258        // 2. when ConferenceEditor finished
259        // dont forget to protect the calls by try-catch!
260
261        // just in case, clear conference selection instead
262        clearTabs();
263
264        // end of optimization
265        // initTabs();
266    } catch (OrmException& e) {
267        // cannon set an active conference
268        unsetConference();   // TODO: as no active conference is now correctly managed this should be handled as a fatal error
269        return;
270    }
271
272}
273
274void MainWindow::initTabs()
275{
276    int confId = Conference::activeConference();
277    if (confId != -1)   // only init tabs if a conference is active
278    {
279        Conference active = Conference::getById(confId);
280        QDate startDate = active.start();
281        QDate endDate = active.end();
282
283        // 'dayNavigator' emits signal 'dateChanged' after setting valid START:END dates
284        dayNavigator->setDates(startDate, endDate);
285        nowAction->trigger();
286    }
287}
288
289void MainWindow::clearTabs()
290{
291    dayTabContainer->clearModel();
292    tracksTabContainer->clearModel();
293    roomsTabContainer->clearModel();
294    favsTabContainer->clearModel();
295    searchTabContainer->clearModel();
296}
297
298void MainWindow::unsetConference()
299{
300    clearTabs();
301    dayNavigator->unsetDates();
302    setWindowTitle(saved_title);
303}
304
305
306void MainWindow::showError(const QString& message) {
307    error_message(message);
308}
309
310
311void MainWindow::on_settingsAction_triggered()
312{
313    SettingsDialog dialog;
314    dialog.loadDialogData();
315    if (dialog.exec() == QDialog::Accepted) {
316        dialog.saveDialogData();
317        QNetworkProxy proxy(
318                AppSettings::isDirectConnection() ? QNetworkProxy::NoProxy : QNetworkProxy::HttpProxy,
319                AppSettings::proxyAddress(),
320                AppSettings::proxyPort(),
321                PROXY_USERNAME,
322                PROXY_PASSWD);
323        QNetworkProxy::setApplicationProxy(proxy);
324    }
325}
326
327/** Create and run ConferenceEditor dialog, making required connections for it.
328
329This method manages, which classes actually perform changes in conference list.
330
331There are several classes that modify the conferences:
332this:
333 deletion and URL update.
334this, mXmlParser and mNetworkAccessManager:
335 addition and refresh.
336*/
337void MainWindow::on_conferencesAction_triggered()
338{
339    ConferenceEditor dialog(conferenceModel, this);
340
341    connect(&dialog, SIGNAL(haveConferenceUrl(const QString&, int)), SLOT(importFromNetwork(const QString&, int)));
342    connect(&dialog, SIGNAL(haveConferenceFile(const QString&, int)), SLOT(importFromFile(const QString&, int)));
343    connect(&dialog, SIGNAL(removeConferenceRequested(int)), SLOT(removeConference(int)));
344    connect(&dialog, SIGNAL(changeUrlRequested(int, const QString&)),
345                    SLOT(changeConferenceUrl(int, const QString&)));
346
347    connect(&dialog, SIGNAL(haveConferenceSelected(int)), SLOT(useConference(int)));
348    connect(&dialog, SIGNAL(noneConferenceSelected()), SLOT(unsetConference()));
349
350    connect(mXmlParser, SIGNAL(parsingScheduleBegin()), &dialog, SLOT(importStarted()));
351    connect(mXmlParser, SIGNAL(progressStatus(int)), &dialog, SLOT(showParsingProgress(int)));
352    connect(mXmlParser, SIGNAL(parsingScheduleEnd(int)), &dialog, SLOT(importFinished(int)));
353
354    connect(this, SIGNAL(conferenceRemoved()), &dialog, SLOT(conferenceRemoved()));
355
356    dialog.exec();
357
358    // optimization, see useConference() code
359    try {
360        initTabs();
361    } catch (OrmException) {
362        clearTabs();
363    }
364}
365
366void MainWindow::networkQueryFinished(QNetworkReply *aReply) {
367    if (aReply->error() != QNetworkReply::NoError) {
368        error_message(QString("Error occured during download: ") + aReply->errorString());
369    } else {
370        QUrl redirectUrl = aReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
371        if (!redirectUrl.isEmpty()) {
372            if (redirectUrl != aReply->request().url()) {
373                importFromNetwork(redirectUrl.toString(), aReply->request().attribute(QNetworkRequest::User).toInt());
374                return; // don't enable controls
375            } else {
376                error_message(QString("Error: Cyclic redirection from %1 to itself.").arg(redirectUrl.toString()));
377            }
378        } else {
379            importData(aReply->readAll(), aReply->url().toEncoded(), aReply->request().attribute(QNetworkRequest::User).toInt());
380        }
381    }
382    setEnabled(true);
383}
384
385void MainWindow::importData(const QByteArray &aData, const QString& url, int conferenceId)
386{
387    mXmlParser->parseData(aData, url, conferenceId);
388}
389
390void MainWindow::importFromNetwork(const QString& url, int conferenceId)
391{
392    QNetworkRequest request;
393    request.setUrl(QUrl(url));
394    request.setAttribute(QNetworkRequest::User, conferenceId);
395
396    mNetworkAccessManager->setProxy(QNetworkProxy::applicationProxy());
397    mNetworkAccessManager->get(request);
398}
399
400void MainWindow::importFromFile(const QString& filename, int conferenceId)
401{
402    QFile file(filename);
403    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {   
404        static const QString format("Cannot read \"%1\": error %2");
405        error_message(format.arg(filename, QString::number(file.error())));
406    }
407
408    importData(file.readAll(), "", conferenceId);
409}
410
411
412void MainWindow::removeConference(int id) {
413    sqlEngine->deleteConference(id);
414    conferenceModel->conferenceRemoved();
415    emit conferenceRemoved();
416}
417
418
419void MainWindow::changeConferenceUrl(int id, const QString& url) {
420    Conference::getById(id).setUrl(url);
421}
422
Note: See TracBrowser for help on using the repository browser.