owncloudgui.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. /*
  2. * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
  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; version 2 of the License.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  11. * for more details.
  12. */
  13. #include "application.h"
  14. #include "owncloudgui.h"
  15. #include "theme.h"
  16. #include "folderman.h"
  17. #include "mirallconfigfile.h"
  18. #include "utility.h"
  19. #include "progressdispatcher.h"
  20. #include "owncloudsetupwizard.h"
  21. #if defined(Q_OS_MAC)
  22. # include "settingsdialogmac.h"
  23. # include "macwindow.h" // qtmacgoodies
  24. #else
  25. # include "settingsdialog.h"
  26. #endif
  27. #include "logger.h"
  28. #include "logbrowser.h"
  29. #include "account.h"
  30. #include "openfilemanager.h"
  31. #include "creds/abstractcredentials.h"
  32. #include <QDesktopServices>
  33. #include <QMessageBox>
  34. #include <QSignalMapper>
  35. #if defined(Q_OS_X11)
  36. #include <QX11Info>
  37. #endif
  38. namespace Mirall {
  39. ownCloudGui::ownCloudGui(Application *parent) :
  40. QObject(parent),
  41. _tray(0),
  42. #if defined(Q_OS_MAC)
  43. _settingsDialog(new SettingsDialogMac(this)),
  44. #else
  45. _settingsDialog(new SettingsDialog(this)),
  46. #endif
  47. _logBrowser(0),
  48. _contextMenu(0),
  49. _recentActionsMenu(0),
  50. _folderOpenActionMapper(new QSignalMapper(this)),
  51. _recentItemsMapper(new QSignalMapper(this)),
  52. _app(parent)
  53. {
  54. _tray = new Systray();
  55. _tray->setParent(this);
  56. // for the beginning, set the offline icon until the account was verified
  57. _tray->setIcon( Theme::instance()->folderOfflineIcon(true));
  58. connect(_tray.data(), SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
  59. SLOT(slotTrayClicked(QSystemTrayIcon::ActivationReason)));
  60. setupActions();
  61. setupContextMenu();
  62. _tray->show();
  63. /* use a signal mapper to map the open requests to the alias names */
  64. connect(_folderOpenActionMapper, SIGNAL(mapped(QString)),
  65. this, SLOT(slotFolderOpenAction(QString)));
  66. connect(_recentItemsMapper, SIGNAL(mapped(QString)),
  67. this, SLOT(slotOpenPath(QString)));
  68. ProgressDispatcher *pd = ProgressDispatcher::instance();
  69. connect( pd, SIGNAL(progressInfo(QString,Progress::Info)), this,
  70. SLOT(slotUpdateProgress(QString,Progress::Info)) );
  71. FolderMan *folderMan = FolderMan::instance();
  72. connect( folderMan, SIGNAL(folderSyncStateChange(QString)),
  73. this,SLOT(slotSyncStateChange(QString)));
  74. connect( Logger::instance(), SIGNAL(guiLog(QString,QString)),
  75. SLOT(slotShowTrayMessage(QString,QString)));
  76. connect( Logger::instance(), SIGNAL(optionalGuiLog(QString,QString)),
  77. SLOT(slotShowOptionalTrayMessage(QString,QString)));
  78. connect( Logger::instance(), SIGNAL(guiMessage(QString,QString)),
  79. SLOT(slotShowGuiMessage(QString,QString)));
  80. setupOverlayIcons();
  81. }
  82. // Use this to do platform specific code to make overlay icons appear
  83. // in the gui
  84. // MacOSX: perform a AppleScript code peace to load the Finder Plugin.
  85. void ownCloudGui::setupOverlayIcons()
  86. {
  87. if( Utility::isMac() && QFile::exists("/Library/ScriptingAdditions/OwnCloudFinder.osax") ) {
  88. QString aScript = QString::fromUtf8("tell application \"Finder\"\n"
  89. " try\n"
  90. " «event OWNCload»\n"
  91. " end try\n"
  92. "end tell\n");
  93. QString osascript = "/usr/bin/osascript";
  94. QStringList processArguments;
  95. // processArguments << "-l" << "AppleScript";
  96. QProcess p;
  97. p.start(osascript, processArguments);
  98. p.write(aScript.toUtf8());
  99. p.closeWriteChannel();
  100. p.waitForReadyRead(-1);
  101. QByteArray result = p.readAll();
  102. QString resultAsString(result); // if appropriate
  103. qDebug() << "Laod Finder Overlay-Plugin: " << resultAsString << ": " << p.exitCode()
  104. << (p.exitCode() != 0 ? p.errorString() : QString::null);
  105. }
  106. }
  107. // This should rather be in application.... or rather in MirallConfigFile?
  108. void ownCloudGui::slotOpenSettingsDialog( bool openSettings )
  109. {
  110. // if account is set up, start the configuration wizard.
  111. if( AccountManager::instance()->account() ) {
  112. if( openSettings ) {
  113. if (_settingsDialog.isNull() || !_settingsDialog->isVisible()) {
  114. slotShowSettings();
  115. } else {
  116. _settingsDialog->close();
  117. }
  118. }
  119. } else {
  120. qDebug() << "No configured folders yet, starting setup wizard";
  121. OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)));
  122. }
  123. }
  124. void ownCloudGui::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
  125. {
  126. // A click on the tray icon should only open the status window on Win and
  127. // Linux, not on Mac. They want a menu entry.
  128. #if !defined Q_OS_MAC
  129. if( reason == QSystemTrayIcon::Trigger ) {
  130. slotOpenSettingsDialog(true); // start settings if config is existing.
  131. }
  132. #else
  133. // On Mac, if the settings dialog is already visible but hidden
  134. // by other applications, this will bring it to the front.
  135. if( reason == QSystemTrayIcon::Trigger ) {
  136. if (!_settingsDialog.isNull() && _settingsDialog->isVisible()) {
  137. slotShowSettings();
  138. }
  139. }
  140. #endif
  141. }
  142. void ownCloudGui::slotSyncStateChange( const QString& alias )
  143. {
  144. FolderMan *folderMan = FolderMan::instance();
  145. const SyncResult& result = folderMan->syncResult( alias );
  146. slotComputeOverallSyncStatus();
  147. if( alias.isEmpty() ) {
  148. return; // Valid, just a general GUI redraw was needed.
  149. }
  150. qDebug() << "Sync state changed for folder " << alias << ": " << result.statusString();
  151. if (result.status() == SyncResult::Success || result.status() == SyncResult::Error) {
  152. Logger::instance()->enterNextLogFile();
  153. }
  154. }
  155. void ownCloudGui::slotFoldersChanged()
  156. {
  157. slotComputeOverallSyncStatus();
  158. setupContextMenu();
  159. }
  160. void ownCloudGui::slotOpenPath(const QString &path)
  161. {
  162. showInFileManager(path);
  163. }
  164. void ownCloudGui::slotAccountStateChanged()
  165. {
  166. setupContextMenu();
  167. slotComputeOverallSyncStatus();
  168. }
  169. void ownCloudGui::startupConnected( bool connected, const QStringList& fails )
  170. {
  171. FolderMan *folderMan = FolderMan::instance();
  172. if( connected ) {
  173. qDebug() << "######## connected to ownCloud Server!";
  174. folderMan->setSyncEnabled(true);
  175. // _tray->setIcon( Theme::instance()->syncStateIcon( SyncResult::NotYetStarted, true ) );
  176. // _tray->show();
  177. }
  178. _startupFails = fails; // store that for the settings dialog once it appears.
  179. if( !_settingsDialog.isNull() ) {
  180. _settingsDialog->setGeneralErrors( _startupFails );
  181. }
  182. slotComputeOverallSyncStatus();
  183. }
  184. void ownCloudGui::slotComputeOverallSyncStatus()
  185. {
  186. if (Account *a = AccountManager::instance()->account()) {
  187. if (a->state() == Account::SignedOut) {
  188. _tray->setIcon(Theme::instance()->folderOfflineIcon(true));
  189. _tray->setToolTip(tr("Please sign in"));
  190. return;
  191. }
  192. if (a->state() == Account::Disconnected) {
  193. _tray->setIcon(Theme::instance()->folderOfflineIcon(true));
  194. _tray->setToolTip(tr("Disconnected from server"));
  195. return;
  196. }
  197. }
  198. // display the info of the least successful sync (eg. not just display the result of the latest sync
  199. QString trayMessage;
  200. FolderMan *folderMan = FolderMan::instance();
  201. Folder::Map map = folderMan->map();
  202. SyncResult overallResult = FolderMan::accountStatus(map.values());
  203. // if there have been startup problems, show an error message.
  204. if( !_settingsDialog.isNull() )
  205. _settingsDialog->setGeneralErrors( _startupFails );
  206. if( !_startupFails.isEmpty() ) {
  207. trayMessage = _startupFails.join(QLatin1String("\n"));
  208. QIcon statusIcon;
  209. if (_app->_startupNetworkError) {
  210. statusIcon = Theme::instance()->syncStateIcon( SyncResult::NotYetStarted, true );
  211. } else {
  212. statusIcon = Theme::instance()->syncStateIcon( SyncResult::Error, true );
  213. }
  214. _tray->setIcon( statusIcon );
  215. _tray->setToolTip(trayMessage);
  216. } else {
  217. // create the tray blob message, check if we have an defined state
  218. if( overallResult.status() != SyncResult::Undefined ) {
  219. QStringList allStatusStrings;
  220. foreach(Folder* folder, map.values()) {
  221. qDebug() << "Folder in overallStatus Message: " << folder << " with name " << folder->alias();
  222. QString folderMessage = folderMan->statusToString(folder->syncResult().status(), folder->syncPaused());
  223. allStatusStrings += tr("Folder %1: %2").arg(folder->alias(), folderMessage);
  224. }
  225. if( ! allStatusStrings.isEmpty() )
  226. trayMessage = allStatusStrings.join(QLatin1String("\n"));
  227. else
  228. trayMessage = tr("No sync folders configured.");
  229. QIcon statusIcon = Theme::instance()->syncStateIcon( overallResult.status(), true);
  230. _tray->setIcon( statusIcon );
  231. _tray->setToolTip(trayMessage);
  232. } else {
  233. // undefined because there are no folders.
  234. QIcon icon = Theme::instance()->syncStateIcon(SyncResult::Problem);
  235. _tray->setIcon( icon );
  236. _tray->setToolTip(tr("There are no sync folders configured."));
  237. #if !defined Q_OS_MAC
  238. if( _settingsDialog ) {
  239. _settingsDialog->slotUpdateAccountIcon(icon);
  240. }
  241. #endif
  242. }
  243. }
  244. }
  245. void ownCloudGui::setupContextMenu()
  246. {
  247. FolderMan *folderMan = FolderMan::instance();
  248. Account *a = AccountManager::instance()->account();
  249. bool isConfigured = (a != 0);
  250. _actionOpenoC->setEnabled(isConfigured);
  251. bool isConnected = false;
  252. if (isConfigured) {
  253. isConnected = (a->state() == Account::Connected);
  254. }
  255. if ( _contextMenu ) {
  256. _contextMenu->clear();
  257. _recentActionsMenu->clear();
  258. _recentActionsMenu->addAction(tr("None."));
  259. _recentActionsMenu->addAction(_actionRecent);
  260. } else {
  261. _contextMenu = new QMenu(_contextMenu);
  262. _recentActionsMenu = new QMenu(tr("Recent Changes"));
  263. // this must be called only once after creating the context menu, or
  264. // it will trigger a bug in Ubuntu's SNI bridge patch (11.10, 12.04).
  265. _tray->setContextMenu(_contextMenu);
  266. }
  267. _contextMenu->setTitle(Theme::instance()->appNameGUI() );
  268. _contextMenu->addAction(_actionOpenoC);
  269. int folderCnt = folderMan->map().size();
  270. // add open actions for all sync folders to the tray menu
  271. if( Theme::instance()->singleSyncFolder() ) {
  272. // there should be exactly one folder. No sync-folder add action will be shown.
  273. QStringList li = folderMan->map().keys();
  274. if( li.size() == 1 ) {
  275. Folder *folder = folderMan->map().value(li.first());
  276. if( folder ) {
  277. // if there is singleFolder mode, a generic open action is displayed.
  278. QAction *action = new QAction( tr("Open %1 folder").arg(Theme::instance()->appNameGUI()), this);
  279. connect( action, SIGNAL(triggered()),_folderOpenActionMapper,SLOT(map()));
  280. _folderOpenActionMapper->setMapping( action, folder->alias() );
  281. _contextMenu->addAction(action);
  282. }
  283. }
  284. } else {
  285. // show a grouping with more than one folder.
  286. if ( folderCnt > 1) {
  287. _contextMenu->addAction(tr("Managed Folders:"))->setDisabled(true);
  288. }
  289. foreach (Folder *folder, folderMan->map() ) {
  290. QAction *action = new QAction( tr("Open folder '%1'").arg(folder->alias()), this );
  291. connect( action, SIGNAL(triggered()),_folderOpenActionMapper,SLOT(map()));
  292. _folderOpenActionMapper->setMapping( action, folder->alias() );
  293. _contextMenu->addAction(action);
  294. }
  295. }
  296. _contextMenu->addSeparator();
  297. if (isConfigured && isConnected) {
  298. _contextMenu->addAction(_actionQuota);
  299. _contextMenu->addSeparator();
  300. _contextMenu->addAction(_actionStatus);
  301. _contextMenu->addMenu(_recentActionsMenu);
  302. _contextMenu->addSeparator();
  303. }
  304. _contextMenu->addAction(_actionSettings);
  305. if (!Theme::instance()->helpUrl().isEmpty()) {
  306. _contextMenu->addAction(_actionHelp);
  307. }
  308. _contextMenu->addSeparator();
  309. if (isConfigured && isConnected) {
  310. _contextMenu->addAction(_actionLogout);
  311. } else {
  312. _contextMenu->addAction(_actionLogin);
  313. }
  314. _contextMenu->addAction(_actionQuit);
  315. }
  316. void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg)
  317. {
  318. if( _tray )
  319. _tray->showMessage(title, msg);
  320. else
  321. qDebug() << "Tray not ready: " << msg;
  322. }
  323. void ownCloudGui::slotShowOptionalTrayMessage(const QString &title, const QString &msg)
  324. {
  325. MirallConfigFile cfg;
  326. if (cfg.optionalDesktopNotifications()) {
  327. slotShowTrayMessage(title, msg);
  328. }
  329. }
  330. /*
  331. * open the folder with the given Alais
  332. */
  333. void ownCloudGui::slotFolderOpenAction( const QString& alias )
  334. {
  335. Folder *f = FolderMan::instance()->folder(alias);
  336. if( f ) {
  337. qDebug() << "opening local url " << f->path();
  338. QUrl url = QUrl::fromLocalFile(f->path());
  339. #ifdef Q_OS_WIN
  340. // work around a bug in QDesktopServices on Win32, see i-net
  341. QString filePath = f->path();
  342. if (filePath.startsWith(QLatin1String("\\\\")) || filePath.startsWith(QLatin1String("//")))
  343. url.setUrl(QDir::toNativeSeparators(filePath));
  344. else
  345. url = QUrl::fromLocalFile(filePath);
  346. #endif
  347. QDesktopServices::openUrl(url);
  348. }
  349. }
  350. void ownCloudGui::setupActions()
  351. {
  352. _actionOpenoC = new QAction(tr("Open %1 in browser").arg(Theme::instance()->appNameGUI()), this);
  353. QObject::connect(_actionOpenoC, SIGNAL(triggered(bool)), SLOT(slotOpenOwnCloud()));
  354. _actionQuota = new QAction(tr("Calculating quota..."), this);
  355. _actionQuota->setEnabled( false );
  356. _actionStatus = new QAction(tr("Unknown status"), this);
  357. _actionStatus->setEnabled( false );
  358. _actionSettings = new QAction(tr("Settings..."), this);
  359. _actionRecent = new QAction(tr("Details..."), this);
  360. _actionRecent->setEnabled( true );
  361. QObject::connect(_actionRecent, SIGNAL(triggered(bool)), SLOT(slotShowSyncProtocol()));
  362. QObject::connect(_actionSettings, SIGNAL(triggered(bool)), SLOT(slotShowSettings()));
  363. _actionHelp = new QAction(tr("Help"), this);
  364. QObject::connect(_actionHelp, SIGNAL(triggered(bool)), SLOT(slotHelp()));
  365. _actionQuit = new QAction(tr("Quit %1").arg(Theme::instance()->appNameGUI()), this);
  366. QObject::connect(_actionQuit, SIGNAL(triggered(bool)), _app, SLOT(quit()));
  367. _actionLogin = new QAction(tr("Sign in..."), this);
  368. connect(_actionLogin, SIGNAL(triggered()), _app, SLOT(slotLogin()));
  369. _actionLogout = new QAction(tr("Sign out"), this);
  370. connect(_actionLogout, SIGNAL(triggered()), _app, SLOT(slotLogout()));
  371. }
  372. void ownCloudGui::slotRefreshQuotaDisplay( qint64 total, qint64 used )
  373. {
  374. if (total == 0) {
  375. _actionQuota->setText(tr("Quota n/a"));
  376. return;
  377. }
  378. double percent = used/(double)total*100;
  379. QString percentFormatted = Utility::compactFormatDouble(percent, 1);
  380. QString totalFormatted = Utility::octetsToString(total);
  381. _actionQuota->setText(tr("%1% of %2 in use").arg(percentFormatted).arg(totalFormatted));
  382. }
  383. void ownCloudGui::slotRebuildRecentMenus()
  384. {
  385. _recentActionsMenu->clear();
  386. if (!_recentItemsActions.isEmpty()) {
  387. foreach(QAction *a, _recentItemsActions) {
  388. _recentActionsMenu->addAction(a);
  389. }
  390. _recentActionsMenu->addSeparator();
  391. } else {
  392. _recentActionsMenu->addAction(tr("No items synced recently"))->setEnabled(false);
  393. }
  394. // add a more... entry.
  395. _recentActionsMenu->addAction(_actionRecent);
  396. }
  397. void ownCloudGui::slotUpdateProgress(const QString &folder, const Progress::Info& progress)
  398. {
  399. Q_UNUSED(folder);
  400. if (!progress._currentDiscoveredFolder.isEmpty()) {
  401. _actionStatus->setText( tr("Discovering %1")
  402. .arg( progress._currentDiscoveredFolder ));
  403. } else if (progress._totalSize == 0 ) {
  404. quint64 currentFile = progress._completedFileCount + progress._currentItems.count();
  405. _actionStatus->setText( tr("Syncing %1 of %2 (%3 left)")
  406. .arg( currentFile ).arg( progress._totalFileCount )
  407. .arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) );
  408. } else {
  409. QString totalSizeStr = Utility::octetsToString( progress._totalSize );
  410. _actionStatus->setText( tr("Syncing %1 (%2 left)")
  411. .arg( totalSizeStr )
  412. .arg( Utility::timeToDescriptiveString(progress.totalEstimate().getEtaEstimate(), 2, " ",true) ) );
  413. }
  414. _actionRecent->setIcon( QIcon() ); // Fixme: Set a "in-progress"-item eventually.
  415. if (!progress._lastCompletedItem.isEmpty()) {
  416. if (Progress::isWarningKind(progress._lastCompletedItem._status)) {
  417. // display a warn icon if warnings happend.
  418. QIcon warnIcon(":/mirall/resources/warning-16");
  419. _actionRecent->setIcon(warnIcon);
  420. }
  421. QString kindStr = Progress::asResultString(progress._lastCompletedItem);
  422. QString timeStr = QTime::currentTime().toString("hh:mm");
  423. QString actionText = tr("%1 (%2, %3)").arg(progress._lastCompletedItem._file, kindStr, timeStr);
  424. QAction *action = new QAction(actionText, this);
  425. Folder *f = FolderMan::instance()->folder(folder);
  426. if (f) {
  427. QString fullPath = f->path() + '/' + progress._lastCompletedItem._file;
  428. if (QFile(fullPath).exists()) {
  429. _recentItemsMapper->setMapping(action, fullPath);
  430. connect(action, SIGNAL(triggered()), _recentItemsMapper, SLOT(map()));
  431. } else {
  432. action->setEnabled(false);
  433. }
  434. }
  435. if (_recentItemsActions.length() > 5) {
  436. _recentItemsActions.takeFirst()->deleteLater();
  437. }
  438. _recentItemsActions.append(action);
  439. slotRebuildRecentMenus();
  440. }
  441. if (progress._completedFileCount == progress._totalFileCount
  442. && progress._currentDiscoveredFolder.isEmpty()) {
  443. QTimer::singleShot(2000, this, SLOT(slotDisplayIdle()));
  444. }
  445. }
  446. void ownCloudGui::slotDisplayIdle()
  447. {
  448. _actionStatus->setText(tr("Up to date"));
  449. }
  450. void ownCloudGui::slotShowGuiMessage(const QString &title, const QString &message)
  451. {
  452. QMessageBox *msgBox = new QMessageBox;
  453. msgBox->setAttribute(Qt::WA_DeleteOnClose);
  454. msgBox->setText(message);
  455. msgBox->setWindowTitle(title);
  456. msgBox->setIcon(QMessageBox::Information);
  457. msgBox->open();
  458. }
  459. void ownCloudGui::slotShowSettings()
  460. {
  461. qDebug() << Q_FUNC_INFO;
  462. if (_settingsDialog.isNull()) {
  463. _settingsDialog =
  464. #if defined(Q_OS_MAC)
  465. new SettingsDialogMac(this);
  466. #else
  467. new SettingsDialog(this);
  468. #endif
  469. _settingsDialog->setAttribute( Qt::WA_DeleteOnClose, true );
  470. _settingsDialog->show();
  471. }
  472. _settingsDialog->setGeneralErrors( _startupFails );
  473. raiseDialog(_settingsDialog.data());
  474. }
  475. void ownCloudGui::slotShowSyncProtocol()
  476. {
  477. slotShowSettings();
  478. _settingsDialog->showActivityPage();
  479. }
  480. void ownCloudGui::slotShutdown()
  481. {
  482. // those do delete on close
  483. if (!_settingsDialog.isNull()) _settingsDialog->close();
  484. if (!_logBrowser.isNull()) _logBrowser->deleteLater();
  485. }
  486. void ownCloudGui::slotToggleLogBrowser()
  487. {
  488. if (_logBrowser.isNull()) {
  489. // init the log browser.
  490. _logBrowser = new LogBrowser;
  491. // ## TODO: allow new log name maybe?
  492. }
  493. if (_logBrowser->isVisible() ) {
  494. _logBrowser->hide();
  495. } else {
  496. raiseDialog(_logBrowser);
  497. }
  498. }
  499. void ownCloudGui::slotOpenOwnCloud()
  500. {
  501. if (Account *account = AccountManager::instance()->account()) {
  502. QDesktopServices::openUrl(account->url());
  503. }
  504. }
  505. void ownCloudGui::slotHelp()
  506. {
  507. QDesktopServices::openUrl(QUrl(Theme::instance()->helpUrl()));
  508. }
  509. void ownCloudGui::raiseDialog( QWidget *raiseWidget )
  510. {
  511. if( raiseWidget && raiseWidget->parentWidget() == 0) {
  512. // Qt has a bug which causes parent-less dialogs to pop-under.
  513. raiseWidget->showNormal();
  514. raiseWidget->raise();
  515. raiseWidget->activateWindow();
  516. #if defined(Q_OS_MAC)
  517. // viel hilft viel ;-)
  518. MacWindow::bringToFront(raiseWidget);
  519. #endif
  520. #if defined(Q_OS_X11)
  521. WId wid = widget->winId();
  522. NETWM::init();
  523. XEvent e;
  524. e.xclient.type = ClientMessage;
  525. e.xclient.message_type = NETWM::NET_ACTIVE_WINDOW;
  526. e.xclient.display = QX11Info::display();
  527. e.xclient.window = wid;
  528. e.xclient.format = 32;
  529. e.xclient.data.l[0] = 2;
  530. e.xclient.data.l[1] = QX11Info::appTime();
  531. e.xclient.data.l[2] = 0;
  532. e.xclient.data.l[3] = 0l;
  533. e.xclient.data.l[4] = 0l;
  534. #endif
  535. }
  536. }
  537. } // end namespace