connect owncloudinfo signals more selective.
[owncloud:sebas-mirall.git] / src / mirall / application.cpp
1 /*
2  * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12  * for more details.
13  */
14
15 #define LOG_TO_CALLBACK // FIXME: This should be in csync.
16 #include <iostream>
17
18 #include "mirall/application.h"
19 #include "mirall/folder.h"
20 #include "mirall/folderwatcher.h"
21 #include "mirall/folderwizard.h"
22 #include "mirall/networklocation.h"
23 #include "mirall/unisonfolder.h"
24 #include "mirall/owncloudfolder.h"
25 #include "mirall/statusdialog.h"
26 #include "mirall/owncloudsetupwizard.h"
27 #include "mirall/owncloudinfo.h"
28 #include "mirall/theme.h"
29 #include "mirall/mirallconfigfile.h"
30 #include "mirall/updatedetector.h"
31 #include "mirall/proxydialog.h"
32
33 #include "mirall/miralltheme.h"
34 #include "mirall/owncloudtheme.h"
35
36 #include "config.h"
37
38 #ifdef WITH_CSYNC
39 #include "mirall/csyncfolder.h"
40 #endif
41 #include "mirall/inotify.h"
42
43 #include <csync.h>
44
45 #include <QtCore>
46 #include <QtGui>
47 #include <QHash>
48 #include <QHashIterator>
49 #include <QUrl>
50 #include <QDesktopServices>
51 #include <QTranslator>
52 #include <QNetworkProxy>
53 #include <QNetworkProxyFactory>
54
55 namespace Mirall {
56
57 // application logging handler.
58 void mirallLogCatcher(QtMsgType type, const char *msg)
59 {
60   Q_UNUSED(type)
61   Logger::instance()->mirallLog( msg );
62 }
63
64 void csyncLogCatcher(const char *msg)
65 {
66   Logger::instance()->csyncLog( QString::fromUtf8(msg) );
67 }
68
69 // ----------------------------------------------------------------------------------
70
71 Application::Application(int &argc, char **argv) :
72     SharedTools::QtSingleApplication(argc, argv),
73     _tray(0),
74 #if QT_VERSION >= 0x040700
75     _networkMgr(new QNetworkConfigurationManager(this)),
76 #endif
77     _contextMenu(0),
78     _updateDetector(0),
79     _helpOnly(false)
80 {
81
82 #ifdef OWNCLOUD_CLIENT
83     _theme = new ownCloudTheme();
84 #else
85     _theme = new mirallTheme();
86 #endif
87     setApplicationName( _theme->appName() );
88     setWindowIcon( _theme->applicationIcon() );
89
90     if( arguments().contains("--help")) {
91         showHelp();
92     }
93     setupLogBrowser();
94     processEvents();
95
96     QTranslator *qtTranslator = new QTranslator(this);
97     qtTranslator->load("qt_" + QLocale::system().name(),
98                       QLibraryInfo::location(QLibraryInfo::TranslationsPath));
99     installTranslator(qtTranslator);
100
101     QTranslator *mirallTranslator = new QTranslator(this);
102 #ifdef Q_OS_LINUX
103     // FIXME - proper path!
104     mirallTranslator->load("mirall_" + QLocale::system().name(), QLatin1String("/usr/share/mirall/i18n/"));
105 #endif
106 #ifdef Q_OS_MAC
107     mirallTranslator->load("mirall_" + QLocale::system().name(), applicationDirPath()+QLatin1String("/../translations") ); // path defaults to app dir.
108 #endif
109 #ifdef Q_OS_WIN32
110     mirallTranslator->load("mirall_" + QLocale::system().name()); // path defaults to app dir.
111 #endif
112
113     installTranslator(mirallTranslator);
114
115     // create folder manager for sync folder management
116     _folderMan = new FolderMan(this);
117     connect( _folderMan, SIGNAL(folderSyncStateChange(QString)),
118              this,SLOT(slotSyncStateChange(QString)));
119
120     /* use a signal mapper to map the open requests to the alias names */
121     _folderOpenActionMapper = new QSignalMapper(this);
122     connect(_folderOpenActionMapper, SIGNAL(mapped(const QString &)),
123             this, SLOT(slotFolderOpenAction(const QString &)));
124
125     setQuitOnLastWindowClosed(false);
126
127     _folderWizard = new FolderWizard( 0, _theme );
128
129     _owncloudSetupWizard = new OwncloudSetupWizard( _folderMan, _theme, this );
130     connect( _owncloudSetupWizard, SIGNAL(ownCloudWizardDone(int)), SLOT(slotStartFolderSetup(int)));
131
132     _statusDialog = new StatusDialog( _theme );
133     connect( _statusDialog, SIGNAL(addASync()), this, SLOT(slotAddFolder()) );
134
135     connect( _statusDialog, SIGNAL(removeFolderAlias( const QString&)),
136              SLOT(slotRemoveFolder(const QString&)));
137
138     connect( _statusDialog, SIGNAL(openLogBrowser()), this, SLOT(slotOpenLogBrowser()));
139
140 #if 0
141     connect( _statusDialog, SIGNAL(fetchFolderAlias(const QString&)),
142              SLOT(slotFetchFolder( const QString&)));
143     connect( _statusDialog, SIGNAL(pushFolderAlias(const QString&)),
144              SLOT(slotPushFolder( const QString&)));
145 #endif
146     connect( _statusDialog, SIGNAL(enableFolderAlias(QString,bool)),
147              SLOT(slotEnableFolder(QString,bool)));
148     connect( _statusDialog, SIGNAL(infoFolderAlias(const QString&)),
149              SLOT(slotInfoFolder( const QString&)));
150     connect( _statusDialog, SIGNAL(openFolderAlias(const QString&)),
151              SLOT(slotFolderOpenAction(QString)));
152
153 #if QT_VERSION >= 0x040700
154     qDebug() << "* Network is" << (_networkMgr->isOnline() ? "online" : "offline");
155     foreach (const QNetworkConfiguration& netCfg, _networkMgr->allConfigurations(QNetworkConfiguration::Active)) {
156         //qDebug() << "Network:" << netCfg.identifier();
157     }
158 #endif
159
160     setupActions();
161     setupSystemTray();
162     setupProxy();
163     processEvents();
164
165     QObject::connect( this, SIGNAL(messageReceived(QString)),
166                          this, SLOT(slotOpenStatus()) );
167
168     QTimer::singleShot( 0, this, SLOT( slotStartFolderSetup() ));
169
170     MirallConfigFile cfg;
171     if( !cfg.ownCloudSkipUpdateCheck() ) {
172         QTimer::singleShot( 3000, this, SLOT( slotStartUpdateDetector() ));
173     }
174
175     qDebug() << "Network Location: " << NetworkLocation::currentLocation().encoded();
176 }
177
178 Application::~Application()
179 {
180     qDebug() << "* Mirall shutdown";
181 }
182
183 void Application::slotStartUpdateDetector()
184 {
185     _updateDetector = new UpdateDetector(this);
186     _updateDetector->versionCheck(_theme);
187
188 }
189
190 void Application::slotStartFolderSetup( int result )
191 {
192     if( result == QDialog::Accepted ) {
193         if( ownCloudInfo::instance()->isConfigured() ) {
194             connect( ownCloudInfo::instance(),SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
195                      SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
196
197             connect( ownCloudInfo::instance(),SIGNAL(noOwncloudFound(QNetworkReply*)),
198                      SLOT(slotNoOwnCloudFound(QNetworkReply*)));
199
200             connect( ownCloudInfo::instance(),SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
201                      this,SLOT(slotAuthCheck(QString,QNetworkReply*)));
202
203
204             ownCloudInfo::instance()->checkInstallation();
205         } else {
206             QMessageBox::warning(0, tr("No ownCloud Configuration"),
207                                  tr("<p>No server connection has been configured for this ownCloud client.</p>"
208                                     "<p>Please right click on the ownCloud system tray icon and select <i>Configure</i> "
209                                     "to connect this client to an ownCloud server.</p>"));
210             // It was evaluated to open the config dialog from here directly but decided
211             // against because the user does not know why. The popup gives a better user
212             // guidance, even if its a click more.
213         }
214     } else {
215         qDebug() << "Setup Wizard was canceled. No reparsing of config.";
216     }
217 }
218
219 void Application::slotOwnCloudFound( const QString& url, const QString& versionStr, const QString& version, const QString& edition)
220 {
221     qDebug() << "** Application: ownCloud found: " << url << " with version " << versionStr << "(" << version << ")";
222     // now check the authentication
223     MirallConfigFile cfgFile;
224     cfgFile.setOwnCloudVersion( version );
225     // disconnect from ownCloudInfo
226     disconnect( ownCloudInfo::instance(),SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
227                 this, SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
228
229     disconnect( ownCloudInfo::instance(),SIGNAL(noOwncloudFound(QNetworkReply*)),
230                 this, SLOT(slotNoOwnCloudFound(QNetworkReply*)));
231
232     QTimer::singleShot( 0, this, SLOT( slotCheckAuthentication() ));
233 }
234
235 void Application::slotNoOwnCloudFound( QNetworkReply* reply )
236 {
237     qDebug() << "** Application: NO ownCloud found!";
238     QString msg;
239     if( reply ) {
240         QString url( reply->url().toString() );
241         url.remove( "/status.php" );
242         msg = tr("<p>The ownCloud at %1 could not be reached.</p>").arg( url );
243         msg += tr("<p>The detailed error message is<br/><tt>%1</tt></p>").arg( reply->errorString() );
244     }
245     msg += tr("<p>Please check your configuration by clicking on the tray icon.</p>");
246
247     QMessageBox::warning(0, tr("ownCloud Connection Failed"), msg );
248     _actionAddFolder->setEnabled( false );
249
250     // Disconnect.
251     disconnect( ownCloudInfo::instance(),SIGNAL(ownCloudInfoFound(QString,QString,QString,QString)),
252                 this, SLOT(slotOwnCloudFound(QString,QString,QString,QString)));
253
254     disconnect( ownCloudInfo::instance(),SIGNAL(noOwncloudFound(QNetworkReply*)),
255                 this, SLOT(slotNoOwnCloudFound(QNetworkReply*)));
256
257     disconnect( ownCloudInfo::instance(),SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
258                 this,SLOT(slotAuthCheck(QString,QNetworkReply*)));
259
260     setupContextMenu();
261 }
262
263 void Application::slotCheckAuthentication()
264 {
265     qDebug() << "# checking for authentication settings.";
266     ownCloudInfo::instance()->getRequest("/", true ); // this call needs to be authenticated.
267     // simply GET the webdav root, will fail if credentials are wrong.
268     // continue in slotAuthCheck here :-)
269 }
270
271 void Application::slotAuthCheck( const QString& ,QNetworkReply *reply )
272 {
273     if( reply->error() == QNetworkReply::AuthenticationRequiredError ) { // returned if the user is wrong.
274         qDebug() << "******** Password is wrong!";
275         QMessageBox::warning(0, tr("No ownCloud Connection"),
276                              tr("<p>Your ownCloud credentials are not correct.</p>"
277                                 "<p>Please correct them by starting the configuration dialog from the tray!</p>"));
278         _actionAddFolder->setEnabled( false );
279     } else if( reply->error() == QNetworkReply::OperationCanceledError ) {
280         // the username was wrong and ownCloudInfo was closing the request after a couple of auth tries.
281         qDebug() << "******** Username or password is wrong!";
282         QMessageBox::warning(0, tr("No ownCloud Connection"),
283                              tr("<p>Your ownCloud user name or password is not correct.</p>"
284                                 "<p>Please correct it by starting the configuration dialog from the tray!</p>"));
285         _actionAddFolder->setEnabled( false );
286     } else {
287         qDebug() << "######## Credentials are ok!";
288         int cnt = _folderMan->setupFolders();
289         if( cnt ) {
290             _tray->setIcon(_theme->applicationIcon());
291             _tray->show();
292             processEvents();
293
294             if( _tray )
295                 _tray->showMessage(tr("ownCloud Sync Started"), tr("Sync started for %1 configured sync folder(s).").arg(cnt));
296         }
297         _actionAddFolder->setEnabled( true );
298     }
299
300     // disconnect from ownCloud Info signals
301     disconnect( ownCloudInfo::instance(),SIGNAL(ownCloudDirExists(QString,QNetworkReply*)),
302              this,SLOT(slotAuthCheck(QString,QNetworkReply*)));
303     setupContextMenu();
304 }
305
306 void Application::setupActions()
307 {
308     _actionOpenoC = new QAction(tr("Open ownCloud..."), this);
309     QObject::connect(_actionOpenoC, SIGNAL(triggered(bool)), SLOT(slotOpenOwnCloud()));
310     _actionOpenStatus = new QAction(tr("Open status..."), this);
311     QObject::connect(_actionOpenStatus, SIGNAL(triggered(bool)), SLOT(slotOpenStatus()));
312     _actionAddFolder = new QAction(tr("Add folder..."), this);
313     QObject::connect(_actionAddFolder, SIGNAL(triggered(bool)), SLOT(slotAddFolder()));
314     _actionConfigure = new QAction(tr("Configure..."), this);
315     QObject::connect(_actionConfigure, SIGNAL(triggered(bool)), SLOT(slotConfigure()));
316     _actionConfigureProxy = new QAction(tr("Configure proxy..."), this);
317     QObject::connect(_actionConfigureProxy, SIGNAL(triggered(bool)), SLOT(slotConfigureProxy()));
318
319     _actionQuit = new QAction(tr("Quit"), this);
320     QObject::connect(_actionQuit, SIGNAL(triggered(bool)), SLOT(quit()));
321 }
322
323 void Application::setupSystemTray()
324 {
325     _tray = new QSystemTrayIcon(this);
326     _tray->setIcon( _theme->applicationIcon() ); // load the grey icon
327
328     connect(_tray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
329             SLOT(slotTrayClicked(QSystemTrayIcon::ActivationReason)));
330
331     setupContextMenu();
332
333     _tray->show();
334 }
335
336 void Application::setupContextMenu()
337 {
338     if( _contextMenu ) {
339         _contextMenu->clear();
340     } else {
341         _contextMenu = new QMenu();
342     }
343     _contextMenu->setTitle(_theme->appName() );
344     _contextMenu->addAction(_actionOpenStatus);
345     _contextMenu->addAction(_actionOpenoC);
346
347     _contextMenu->addSeparator();
348
349     if (!_folderMan->map().isEmpty())
350         _contextMenu->addAction(tr("Managed Folders:"))->setDisabled(true);
351
352     // here all folders should be added
353     foreach (Folder *folder, _folderMan->map() ) {
354         QAction *action = new QAction( folder->alias(), this );
355         action->setIcon( _theme->trayFolderIcon( folder->backend()) );
356
357         connect( action, SIGNAL(triggered()),_folderOpenActionMapper,SLOT(map()));
358         _folderOpenActionMapper->setMapping( action, folder->alias() );
359
360         _contextMenu->addAction(action);
361     }
362     _contextMenu->addAction(_actionAddFolder);
363
364     _contextMenu->addSeparator();
365     _contextMenu->addAction(_actionConfigure);
366     _contextMenu->addAction(_actionConfigureProxy);
367     _contextMenu->addSeparator();
368
369     _contextMenu->addAction(_actionQuit);
370     _tray->setContextMenu(_contextMenu);
371 }
372
373 void Application::setupLogBrowser()
374 {
375     // init the log browser.
376     _logBrowser = new LogBrowser;
377     qInstallMsgHandler( mirallLogCatcher );
378     csync_set_log_callback( csyncLogCatcher );
379
380     if( arguments().contains("--logwindow") || arguments().contains("-l")) {
381         slotOpenLogBrowser();
382     }
383
384     // check for command line option for a log file.
385     int lf = arguments().indexOf("--logfile");
386
387     if( lf > -1 && lf+1 < arguments().count() ) {
388         QString logfile = arguments().at( lf+1 );
389
390         bool flush = false;
391         if( arguments().contains("--logflush")) flush = true;
392
393         qDebug() << "Logging into logfile: " << logfile << " with flush " << flush;
394         _logBrowser->setLogFile( logfile, flush );
395     }
396
397     qDebug() << QString( "################## %1 %2 %3 ").arg(_theme->appName())
398                 .arg( QLocale::system().name() )
399                 .arg(_theme->version());
400 }
401
402 void Application::setupProxy()
403 {
404     //
405     // TODO: push proxy information to csync
406     //
407     Mirall::MirallConfigFile cfg;
408     switch(cfg.proxyType())
409     {
410     case QNetworkProxy::NoProxy:
411     {
412         QNetworkProxy proxy;
413         proxy.setType(QNetworkProxy::NoProxy);
414         QNetworkProxy::setApplicationProxy(proxy);
415         break;
416     }
417     case QNetworkProxy::DefaultProxy:
418     {
419         QNetworkProxyFactory::setUseSystemConfiguration(true);
420         break;
421     }
422     case QNetworkProxy::Socks5Proxy:
423     {
424         QNetworkProxy proxy;
425         proxy.setType(QNetworkProxy::Socks5Proxy);
426         proxy.setHostName(cfg.proxyHostName());
427         proxy.setPort(cfg.proxyPort());
428         proxy.setUser(cfg.proxyUser());
429         proxy.setPassword(cfg.proxyPassword());
430         QNetworkProxy::setApplicationProxy(proxy);
431         break;
432     }
433     }
434 }
435
436 /*
437  * open the folder with the given Alais
438  */
439 void Application::slotFolderOpenAction( const QString& alias )
440 {
441     Folder *f = _folderMan->folder(alias);
442     qDebug() << "opening local url " << f->path();
443     if( f ) {
444         QUrl url(f->path(), QUrl::TolerantMode);
445         url.setScheme( "file" );
446
447 #ifdef Q_OS_WIN32
448         // work around a bug in QDesktopServices on Win32, see i-net
449         QString filePath = f->path();
450
451         if (filePath.startsWith("\\\\") || filePath.startsWith("//"))
452             url.setUrl(QDir::toNativeSeparators(filePath));
453         else
454             url = QUrl::fromLocalFile(filePath);
455 #endif
456         QDesktopServices::openUrl(url);
457     }
458 }
459
460 void Application::slotOpenOwnCloud()
461 {
462   MirallConfigFile cfgFile;
463
464   QString url = cfgFile.ownCloudUrl();
465   QDesktopServices::openUrl( url );
466 }
467
468 void Application::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
469 {
470   // A click on the tray icon should only open the status window on Win and
471   // Linux, not on Mac. They want a menu entry.
472 #if defined Q_WS_WIN || defined Q_WS_X11
473   if( reason == QSystemTrayIcon::Trigger ) {
474     slotOpenStatus();
475   }
476 #endif
477 }
478
479 void Application::slotAddFolder()
480 {
481   _folderMan->disableFoldersWithRestore();
482
483   Folder::Map folderMap = _folderMan->map();
484
485   _folderWizard->setFolderMap( &folderMap );
486
487   _folderWizard->restart();
488
489   if (_folderWizard->exec() == QDialog::Accepted) {
490     qDebug() << "* Folder wizard completed";
491
492     bool goodData = true;
493
494     QString alias        = _folderWizard->field("alias").toString();
495     QString sourceFolder = _folderWizard->field("sourceFolder").toString();
496     QString backend      = QLatin1String("csync");
497     QString targetPath;
498     bool onlyThisLAN = false;
499     bool onlyOnline  = false;
500
501     if (_folderWizard->field("local?").toBool()) {
502         // setup a local csync folder
503         targetPath = _folderWizard->field("targetLocalFolder").toString();
504     } else if (_folderWizard->field("remote?").toBool()) {
505         // setup a remote csync folder
506         targetPath  = _folderWizard->field("targetURLFolder").toString();
507         onlyOnline  = _folderWizard->field("onlyOnline?").toBool();
508         onlyThisLAN = _folderWizard->field("onlyThisLAN?").toBool();
509     } else if( _folderWizard->field("OC?").toBool()) {
510         // setup a ownCloud folder
511         backend    = QLatin1String("owncloud");
512         targetPath = _folderWizard->field("targetOCFolder").toString();
513     } else {
514       qWarning() << "* Folder not local and note remote?";
515       goodData = false;
516     }
517
518     if( goodData ) {
519         _folderMan->addFolderDefinition( backend, alias, sourceFolder, targetPath, onlyThisLAN );
520         Folder *f = _folderMan->setupFolderFromConfigFile( alias );
521         if( f ) {
522             _statusDialog->slotAddFolder( f );
523             setupContextMenu();
524         }
525     }
526
527   } else {
528     qDebug() << "* Folder wizard cancelled";
529   }
530   _folderMan->restoreEnabledFolders();
531 }
532
533 void Application::slotOpenStatus()
534 {
535   if( ! _statusDialog ) return;
536
537   QWidget *raiseWidget = 0;
538
539   // check if there is a mirall.cfg already.
540   if( _owncloudSetupWizard->wizard()->isVisible() ) {
541     raiseWidget = _owncloudSetupWizard->wizard();
542   }
543
544   // if no config file is there, start the configuration wizard.
545   if( ! raiseWidget ) {
546     MirallConfigFile cfgFile;
547
548     if( !cfgFile.exists() ) {
549       qDebug() << "No configured folders yet, start the Owncloud integration dialog.";
550       _owncloudSetupWizard->startWizard();
551     } else {
552       qDebug() << "#============# Status dialog starting #=============#";
553       raiseWidget = _statusDialog;
554       _statusDialog->setFolderList( _folderMan->map() );
555     }
556   }
557
558   // viel hilft viel ;-)
559   if( raiseWidget ) {
560 #if defined(Q_WS_WIN) || defined (Q_OS_MAC)
561     Qt::WindowFlags eFlags = raiseWidget->windowFlags();
562     eFlags |= Qt::WindowStaysOnTopHint;
563     raiseWidget->setWindowFlags(eFlags);
564     raiseWidget->show();
565     eFlags &= ~Qt::WindowStaysOnTopHint;
566     raiseWidget->setWindowFlags(eFlags);
567 #endif
568     raiseWidget->show();
569     raiseWidget->raise();
570     raiseWidget->activateWindow();
571   }
572 }
573
574 void Application::slotOpenLogBrowser()
575 {
576     _logBrowser->show();
577     _logBrowser->raise();
578 }
579
580 /*
581   * the folder is to be removed. The slot is called from a signal emitted by
582   * the status dialog, which removes the folder from its list by itself.
583   */
584 void Application::slotRemoveFolder( const QString& alias )
585 {
586     int ret = QMessageBox::question( 0, tr("Confirm Folder Remove"), tr("Do you really want to remove upload folder <i>%1</i>?").arg(alias),
587                                      QMessageBox::Yes|QMessageBox::No );
588
589     if( ret == QMessageBox::No ) {
590         return;
591     }
592     Folder *f = _folderMan->folder(alias);
593     if( f && _overallStatusStrings.contains( f->alias() )) {
594         _overallStatusStrings.remove( f->alias() );
595     }
596
597     _folderMan->slotRemoveFolder( alias );
598     _statusDialog->slotRemoveSelectedFolder( );
599     computeOverallSyncStatus();
600     setupContextMenu();
601 }
602
603 void Application::slotInfoFolder( const QString& alias )
604 {
605     qDebug() << "details of folder with alias " << alias;
606
607     SyncResult folderResult = _folderMan->syncResult( alias );
608
609     bool enabled = true;
610     Folder *f = _folderMan->folder( alias );
611     if( f && ! f->syncEnabled() ) {
612         enabled = false;
613     }
614
615     QString folderMessage;
616
617     SyncResult::Status syncStatus = folderResult.status();
618     switch( syncStatus ) {
619     case SyncResult::Undefined:
620         folderMessage = tr( "Undefined Folder State" );
621         break;
622     case SyncResult::NotYetStarted:
623         folderMessage = tr( "The folder waits to start syncing." );
624         break;
625     case SyncResult::SyncRunning:
626         folderMessage = tr("Sync is running.");
627         break;
628     case SyncResult::Success:
629         folderMessage = tr("Last Sync was successful.");
630         break;
631     case SyncResult::Error:
632         folderMessage = tr( "Syncing Error." );
633         break;
634     case SyncResult::SetupError:
635         folderMessage = tr( "Setup Error." );
636         break;
637     default:
638         folderMessage = tr( "Undefined Error State." );
639     }
640     folderMessage = QLatin1String("<b>") + folderMessage + QLatin1String("</b><br/>");
641
642     QMessageBox infoBox( QMessageBox::Information, tr( "Folder information" ), alias, QMessageBox::Ok );
643     QStringList li = folderResult.errorStrings();
644     foreach( const QString& l, li ) {
645         folderMessage += QString("<p>%1</p>").arg( l );
646     }
647
648     infoBox.setText( folderMessage );
649
650     //    qDebug() << "informative text: " << infoBox.informativeText();
651
652     if ( !folderResult.syncChanges().isEmpty() ) {
653         QString details;
654         QHash < QString, QStringList > changes = folderResult.syncChanges();
655         QHash< QString, QStringList >::const_iterator change_it = changes.constBegin();
656         for(; change_it != changes.constEnd(); ++change_it ) {
657             QString changeType = tr( "Unknown" );
658             if ( change_it.key() == "changed" ) {
659             changeType = tr( "Changed files:\n" );
660             } else if ( change_it.key() == "added" ) {
661                 changeType = tr( "Added files:\n" );
662             } else if ( change_it.key() == "deleted" ) {
663             changeType = tr( "New files in the server, or files deleted locally:\n");
664             }
665
666             QStringList files = change_it.value();
667             QString fileList;
668                 foreach( const QString& file, files) {
669                     fileList += file + QChar('\n');
670             }
671             details += changeType + fileList;
672         }
673         infoBox.setDetailedText(details);
674         qDebug() << "detailed text: " << infoBox.detailedText();
675     }
676     infoBox.exec();
677 }
678
679 void Application::slotEnableFolder(const QString& alias, const bool enable)
680 {
681   qDebug() << "Application: enable folder with alias " << alias;
682
683   _folderMan->slotEnableFolder( alias, enable );
684
685   // this sets the folder status to disabled but does not interrupt it.
686   Folder *f = _folderMan->folder( alias );
687   if( f && !enable ) {
688       // check if a sync is still running and if so, ask if we should terminate.
689       if( f->isBusy() ) { // its still running
690           QMessageBox::StandardButton b = QMessageBox::question( 0, tr("Sync Running"),
691                                                                  tr("The syncing operation is running.<br/>Do you want to terminate it?"),
692                                                                  QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes );
693           if( b == QMessageBox::Yes ) {
694               _folderMan->terminateSyncProcess( alias );
695           }
696       }
697   }
698
699   _statusDialog->slotUpdateFolderState( f );
700 }
701
702 void Application::slotConfigure()
703 {
704   _folderMan->disableFoldersWithRestore();
705   _owncloudSetupWizard->startWizard();
706   _folderMan->restoreEnabledFolders();
707 }
708
709 void Application::slotConfigureProxy()
710 {
711     ProxyDialog* dlg = new ProxyDialog();
712     if (dlg->exec() == QDialog::Accepted)
713     {
714         setupProxy();
715     }
716     dlg->deleteLater();
717 }
718
719 void Application::slotSyncStateChange( const QString& alias )
720 {
721     SyncResult result = _folderMan->syncResult( alias );
722
723     // do not promote LocalSyncState to the status dialog.
724     if( !result.localRunOnly() ) {
725         _statusDialog->slotUpdateFolderState( _folderMan->folder(alias) );
726     }
727     computeOverallSyncStatus();
728
729     qDebug() << "Sync state changed for folder " << alias << ": "  << result.statusString();
730 }
731
732 void Application::computeOverallSyncStatus()
733 {
734
735     // display the info of the least successful sync (eg. not just display the result of the latest sync
736     SyncResult overallResult(SyncResult::Undefined );
737     QString trayMessage;
738     Folder::Map map = _folderMan->map();
739
740     foreach ( Folder *syncedFolder, map.values() ) {
741         QString folderMessage = _overallStatusStrings[syncedFolder->alias()];
742
743         SyncResult folderResult = syncedFolder->syncResult();
744         SyncResult::Status syncStatus = folderResult.status();
745
746         if( ! folderResult.localRunOnly() ) { // skip local runs, use the last message.
747             if( syncedFolder->syncEnabled() ) {
748                 switch( syncStatus ) {
749                 case SyncResult::Undefined:
750                     if ( overallResult.status() != SyncResult::Error ) {
751                       overallResult.setStatus(SyncResult::Error);
752                     }
753                     folderMessage = tr( "Undefined State." );
754                     break;
755                 case SyncResult::NotYetStarted:
756                     folderMessage = tr( "Waits to start syncing." );
757                     overallResult.setStatus( SyncResult::NotYetStarted );
758                     break;
759                 case SyncResult::SyncRunning:
760                     folderMessage = tr( "Sync is running." );
761                     overallResult.setStatus( SyncResult::SyncRunning );
762                     break;
763                 case SyncResult::Success:
764                     if( overallResult.status() == SyncResult::Undefined ) {
765                         folderMessage = tr( "Last Sync was successful." );
766                         overallResult.setStatus( SyncResult::Success );
767                     }
768                     break;
769                 case SyncResult::Error:
770                     overallResult.setStatus( SyncResult::Error );
771                     folderMessage = tr( "Syncing Error." );
772                     break;
773                 case SyncResult::SetupError:
774                     if ( overallResult.status() != SyncResult::Error ) {
775                         overallResult.setStatus( SyncResult::SetupError );
776                     }
777                     folderMessage = tr( "Setup Error." );
778                     break;
779                 default:
780                     folderMessage = tr( "Undefined Error State." );
781                     overallResult.setStatus( SyncResult::Error );
782                 }
783             } else {
784                 // sync is disabled.
785                 folderMessage = tr( "Sync is paused." );
786             }
787         }
788         qDebug() << "Folder in overallStatus Message: " << syncedFolder << " with name " << syncedFolder->alias();
789         QString msg = QString("Folder %1: %2").arg(syncedFolder->alias()).arg(folderMessage);
790         if( msg != _overallStatusStrings[syncedFolder->alias()] ) {
791             _overallStatusStrings[syncedFolder->alias()] = msg;
792         }
793     }
794
795     // create the tray blob message, check if we have an defined state
796     if( overallResult.status() != SyncResult::Undefined ) {
797         QStringList allStatusStrings = _overallStatusStrings.values();
798         if( ! allStatusStrings.isEmpty() )
799             trayMessage = allStatusStrings.join("\n");
800         else
801             trayMessage = tr("No sync folders configured.");
802
803         QIcon statusIcon = _theme->syncStateIcon( overallResult.status()); // size 48 before
804
805         _tray->setIcon( statusIcon );
806         _tray->setToolTip(trayMessage);
807     }
808 }
809
810 void Application::showHelp()
811 {
812     std::cout << _theme->appName().toLatin1().constData() << " version " <<
813                  _theme->version().toLatin1().constData() << std::endl << std::endl;
814     std::cout << "File synchronisation desktop utility." << std::endl << std::endl;
815     std::cout << "Options:" << std::endl;
816     std::cout << "  --logwindow          : open a window to show log output." << std::endl;
817     std::cout << "  --logfile <filename> : write log output to file <filename>." << std::endl;
818     std::cout << "  --flushlog           : flush the log file after every write." << std::endl;
819     std::cout << std::endl;
820     std::cout << "For more information, see http://www.owncloud.org" << std::endl;
821     _helpOnly = true;
822 }
823
824 bool Application::giveHelp()
825 {
826     return _helpOnly;
827 }
828 } // namespace Mirall
829