cloudproviderwrapper.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. * Copyright (C) by Klaas Freitag <freitag@owncloud.com>
  3. * Copyright (C) by Julius Härtl <jus@bitgrid.net>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. * for more details.
  14. */
  15. #include <glib.h>
  16. #include <gio/gio.h>
  17. #include <cloudprovidersaccountexporter.h>
  18. #include <cloudprovidersproviderexporter.h>
  19. #include "cloudproviderwrapper.h"
  20. #include <account.h>
  21. #include <folder.h>
  22. #include <accountstate.h>
  23. #include <QDesktopServices>
  24. #include "openfilemanager.h"
  25. #include "owncloudgui.h"
  26. #include "application.h"
  27. using namespace OCC;
  28. GSimpleActionGroup *actionGroup = nullptr;
  29. CloudProviderWrapper::CloudProviderWrapper(QObject *parent, Folder *folder, int folderId, CloudProvidersProviderExporter* cloudprovider) : QObject(parent)
  30. , _folder(folder)
  31. {
  32. GMenuModel *model = nullptr;
  33. GActionGroup *action_group = nullptr;
  34. QString accountName = QString("Folder/%1").arg(folderId);
  35. _cloudProvider = CLOUD_PROVIDERS_PROVIDER_EXPORTER(cloudprovider);
  36. _cloudProviderAccount = cloud_providers_account_exporter_new(_cloudProvider, accountName.toUtf8().data());
  37. cloud_providers_account_exporter_set_name (_cloudProviderAccount, folder->shortGuiLocalPath().toUtf8().data());
  38. cloud_providers_account_exporter_set_icon (_cloudProviderAccount, g_icon_new_for_string(APPLICATION_ICON_NAME, nullptr));
  39. cloud_providers_account_exporter_set_path (_cloudProviderAccount, folder->cleanPath().toUtf8().data());
  40. cloud_providers_account_exporter_set_status (_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_IDLE);
  41. model = getMenuModel();
  42. cloud_providers_account_exporter_set_menu_model (_cloudProviderAccount, model);
  43. action_group = getActionGroup();
  44. cloud_providers_account_exporter_set_action_group (_cloudProviderAccount, action_group);
  45. connect(ProgressDispatcher::instance(), &ProgressDispatcher::progressInfo, this, &CloudProviderWrapper::slotUpdateProgress);
  46. connect(_folder, &Folder::syncStarted, this, &CloudProviderWrapper::slotSyncStarted);
  47. connect(_folder, &Folder::syncFinished, this, &CloudProviderWrapper::slotSyncFinished);
  48. connect(_folder, &Folder::syncPausedChanged, this, &CloudProviderWrapper::slotSyncPausedChanged);
  49. _paused = _folder->syncPaused();
  50. updatePauseStatus();
  51. g_clear_object (&model);
  52. g_clear_object (&action_group);
  53. }
  54. CloudProviderWrapper::~CloudProviderWrapper()
  55. {
  56. g_object_unref(_cloudProviderAccount);
  57. g_object_unref(_mainMenu);
  58. g_object_unref(actionGroup);
  59. g_object_unref(_recentMenu);
  60. }
  61. CloudProvidersAccountExporter* CloudProviderWrapper::accountExporter()
  62. {
  63. return _cloudProviderAccount;
  64. }
  65. static bool shouldShowInRecentsMenu(const SyncFileItem &item)
  66. {
  67. return !Progress::isIgnoredKind(item._status)
  68. && item._instruction != CSYNC_INSTRUCTION_EVAL
  69. && item._instruction != CSYNC_INSTRUCTION_NONE;
  70. }
  71. static GMenuItem *menu_item_new(const QString &label, const gchar *detailed_action)
  72. {
  73. return g_menu_item_new(label.toUtf8 ().data(), detailed_action);
  74. }
  75. static GMenuItem *menu_item_new_submenu(const QString &label, GMenuModel *submenu)
  76. {
  77. return g_menu_item_new_submenu(label.toUtf8 ().data(), submenu);
  78. }
  79. void CloudProviderWrapper::slotUpdateProgress(const QString &folder, const ProgressInfo &progress)
  80. {
  81. // Only update progress for the current folder
  82. Folder *f = FolderMan::instance()->folder(folder);
  83. if (f != _folder)
  84. return;
  85. // Build recently changed files list
  86. if (!progress._lastCompletedItem.isEmpty() && shouldShowInRecentsMenu(progress._lastCompletedItem)) {
  87. QString kindStr = Progress::asResultString(progress._lastCompletedItem);
  88. QString timeStr = QTime::currentTime().toString("hh:mm");
  89. QString actionText = tr("%1 (%2, %3)").arg(progress._lastCompletedItem._file, kindStr, timeStr);
  90. if (f) {
  91. QString fullPath = f->path() + '/' + progress._lastCompletedItem._file;
  92. if (QFile(fullPath).exists()) {
  93. if (_recentlyChanged.length() > 5)
  94. _recentlyChanged.removeFirst();
  95. _recentlyChanged.append(qMakePair(actionText, fullPath));
  96. } else {
  97. _recentlyChanged.append(qMakePair(actionText, QString("")));
  98. }
  99. }
  100. }
  101. // Build status details text
  102. QString msg;
  103. if (!progress._currentDiscoveredRemoteFolder.isEmpty()) {
  104. msg = tr("Checking for changes in \"%1\"").arg(progress._currentDiscoveredRemoteFolder);
  105. } else if (progress.totalSize() == 0) {
  106. qint64 currentFile = progress.currentFile();
  107. qint64 totalFileCount = qMax(progress.totalFiles(), currentFile);
  108. if (progress.trustEta()) {
  109. msg = tr("Syncing %1 of %2 (%3 left)")
  110. .arg(currentFile)
  111. .arg(totalFileCount)
  112. .arg(Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta));
  113. } else {
  114. msg = tr("Syncing %1 of %2")
  115. .arg(currentFile)
  116. .arg(totalFileCount);
  117. }
  118. } else {
  119. QString totalSizeStr = Utility::octetsToString(progress.totalSize());
  120. if (progress.trustEta()) {
  121. msg = tr("Syncing %1 (%2 left)")
  122. .arg(totalSizeStr, Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta));
  123. } else {
  124. msg = tr("Syncing %1")
  125. .arg(totalSizeStr);
  126. }
  127. }
  128. updateStatusText(msg);
  129. if (!progress._lastCompletedItem.isEmpty()
  130. && shouldShowInRecentsMenu(progress._lastCompletedItem)) {
  131. GMenuItem* item = nullptr;
  132. g_menu_remove_all (G_MENU(_recentMenu));
  133. if(!_recentlyChanged.isEmpty()) {
  134. QList<QPair<QString, QString>>::iterator i;
  135. for (i = _recentlyChanged.begin(); i != _recentlyChanged.end(); i++) {
  136. QString label = i->first;
  137. QString fullPath = i->second;
  138. item = menu_item_new(label, "cloudprovider.showfile");
  139. g_menu_item_set_action_and_target_value(item, "cloudprovider.showfile", g_variant_new_string(fullPath.toUtf8().data()));
  140. g_menu_append_item(_recentMenu, item);
  141. g_clear_object (&item);
  142. }
  143. } else {
  144. item = menu_item_new(tr("No recently changed files"), nullptr);
  145. g_menu_append_item(_recentMenu, item);
  146. g_clear_object (&item);
  147. }
  148. }
  149. }
  150. void CloudProviderWrapper::updateStatusText(QString statusText)
  151. {
  152. QString status = QString("%1 - %2").arg(_folder->accountState()->stateString(_folder->accountState()->state()), statusText);
  153. cloud_providers_account_exporter_set_status_details(_cloudProviderAccount, status.toUtf8().data());
  154. }
  155. void CloudProviderWrapper::updatePauseStatus()
  156. {
  157. if (_paused) {
  158. updateStatusText(tr("Sync paused"));
  159. cloud_providers_account_exporter_set_status (_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_ERROR);
  160. } else {
  161. updateStatusText(tr("Syncing"));
  162. cloud_providers_account_exporter_set_status (_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_SYNCING);
  163. }
  164. }
  165. Folder* CloudProviderWrapper::folder()
  166. {
  167. return _folder;
  168. }
  169. void CloudProviderWrapper::slotSyncStarted()
  170. {
  171. cloud_providers_account_exporter_set_status(_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_SYNCING);
  172. }
  173. void CloudProviderWrapper::slotSyncFinished(const SyncResult &result)
  174. {
  175. if (result.status() == result.Success || result.status() == result.Problem)
  176. {
  177. cloud_providers_account_exporter_set_status(_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_IDLE);
  178. updateStatusText(result.statusString());
  179. return;
  180. }
  181. cloud_providers_account_exporter_set_status(_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_ERROR);
  182. updateStatusText(result.statusString());
  183. }
  184. GMenuModel* CloudProviderWrapper::getMenuModel() {
  185. GMenu* section = nullptr;
  186. GMenuItem* item = nullptr;
  187. QString item_label;
  188. _mainMenu = g_menu_new();
  189. section = g_menu_new();
  190. item = menu_item_new(tr("Open website"), "cloudprovider.openwebsite");
  191. g_menu_append_item(section, item);
  192. g_clear_object (&item);
  193. g_menu_append_section(_mainMenu, nullptr, G_MENU_MODEL(section));
  194. g_clear_object (&section);
  195. _recentMenu = g_menu_new();
  196. item = menu_item_new(tr("No recently changed files"), nullptr);
  197. g_menu_append_item(_recentMenu, item);
  198. g_clear_object (&item);
  199. section = g_menu_new();
  200. item = menu_item_new_submenu(tr("Recently changed"), G_MENU_MODEL(_recentMenu));
  201. g_menu_append_item(section, item);
  202. g_clear_object (&item);
  203. g_menu_append_section(_mainMenu, nullptr, G_MENU_MODEL(section));
  204. g_clear_object (&section);
  205. section = g_menu_new();
  206. item = menu_item_new(tr("Pause synchronization"), "cloudprovider.pause");
  207. g_menu_append_item(section, item);
  208. g_clear_object (&item);
  209. g_menu_append_section(_mainMenu, nullptr, G_MENU_MODEL(section));
  210. g_clear_object (&section);
  211. section = g_menu_new();
  212. item = menu_item_new(tr("Help"), "cloudprovider.openhelp");
  213. g_menu_append_item(section, item);
  214. g_clear_object (&item);
  215. item = menu_item_new(tr("Settings"), "cloudprovider.opensettings");
  216. g_menu_append_item(section, item);
  217. g_clear_object (&item);
  218. item = menu_item_new(tr("Log out"), "cloudprovider.logout");
  219. g_menu_append_item(section, item);
  220. g_clear_object (&item);
  221. item = menu_item_new(tr("Quit sync client"), "cloudprovider.quit");
  222. g_menu_append_item(section, item);
  223. g_clear_object (&item);
  224. g_menu_append_section(_mainMenu, nullptr, G_MENU_MODEL(section));
  225. g_clear_object (&section);
  226. return G_MENU_MODEL(_mainMenu);
  227. }
  228. static void
  229. activate_action_open (GSimpleAction *action, GVariant *parameter, gpointer user_data)
  230. {
  231. Q_UNUSED(parameter);
  232. const gchar *name = g_action_get_name(G_ACTION(action));
  233. auto *self = static_cast<CloudProviderWrapper*>(user_data);
  234. auto *gui = dynamic_cast<ownCloudGui*>(self->parent()->parent());
  235. if(g_str_equal(name, "openhelp")) {
  236. gui->slotHelp();
  237. }
  238. if(g_str_equal(name, "opensettings")) {
  239. gui->slotShowSettings();
  240. }
  241. if(g_str_equal(name, "openwebsite")) {
  242. QDesktopServices::openUrl(self->folder()->accountState()->account()->url());
  243. }
  244. if(g_str_equal(name, "openfolder")) {
  245. showInFileManager(self->folder()->cleanPath());
  246. }
  247. if(g_str_equal(name, "showfile")) {
  248. const gchar *path = g_variant_get_string(parameter, nullptr);
  249. g_print("showfile => %s\n", path);
  250. showInFileManager(QString(path));
  251. }
  252. if(g_str_equal(name, "logout")) {
  253. self->folder()->accountState()->signOutByUi();
  254. }
  255. if(g_str_equal(name, "quit")) {
  256. qApp->quit();
  257. }
  258. }
  259. static void
  260. activate_action_openrecentfile (GSimpleAction *action, GVariant *parameter, gpointer user_data)
  261. {
  262. Q_UNUSED(action);
  263. Q_UNUSED(parameter);
  264. auto *self = static_cast<CloudProviderWrapper*>(user_data);
  265. QDesktopServices::openUrl(self->folder()->accountState()->account()->url());
  266. }
  267. static void
  268. activate_action_pause (GSimpleAction *action,
  269. GVariant *parameter,
  270. gpointer user_data)
  271. {
  272. Q_UNUSED(parameter);
  273. auto *self = static_cast<CloudProviderWrapper*>(user_data);
  274. GVariant *old_state = nullptr, *new_state = nullptr;
  275. old_state = g_action_get_state (G_ACTION (action));
  276. new_state = g_variant_new_boolean (!(bool)g_variant_get_boolean (old_state));
  277. self->folder()->setSyncPaused((bool)g_variant_get_boolean(new_state));
  278. g_simple_action_set_state (action, new_state);
  279. g_variant_unref (old_state);
  280. }
  281. static GActionEntry actions[] = {
  282. { "openwebsite", activate_action_open, nullptr, nullptr, nullptr, {0,0,0}},
  283. { "quit", activate_action_open, nullptr, nullptr, nullptr, {0,0,0}},
  284. { "logout", activate_action_open, nullptr, nullptr, nullptr, {0,0,0}},
  285. { "openfolder", activate_action_open, nullptr, nullptr, nullptr, {0,0,0}},
  286. { "showfile", activate_action_open, "s", nullptr, nullptr, {0,0,0}},
  287. { "openhelp", activate_action_open, nullptr, nullptr, nullptr, {0,0,0}},
  288. { "opensettings", activate_action_open, nullptr, nullptr, nullptr, {0,0,0}},
  289. { "openrecentfile", activate_action_openrecentfile, "s", nullptr, nullptr, {0,0,0}},
  290. { "pause", activate_action_pause, nullptr, "false", nullptr, {0,0,0}}
  291. };
  292. GActionGroup* CloudProviderWrapper::getActionGroup()
  293. {
  294. g_clear_object (&actionGroup);
  295. actionGroup = g_simple_action_group_new ();
  296. g_action_map_add_action_entries (G_ACTION_MAP (actionGroup), actions, G_N_ELEMENTS (actions), this);
  297. bool state = _folder->syncPaused();
  298. GAction *pause = g_action_map_lookup_action(G_ACTION_MAP(actionGroup), "pause");
  299. g_simple_action_set_state(G_SIMPLE_ACTION(pause), g_variant_new_boolean(state));
  300. return G_ACTION_GROUP (g_object_ref (actionGroup));
  301. }
  302. void CloudProviderWrapper::slotSyncPausedChanged(Folder *folder, bool state)
  303. {
  304. Q_UNUSED(folder);
  305. _paused = state;
  306. GAction *pause = g_action_map_lookup_action(G_ACTION_MAP(actionGroup), "pause");
  307. g_simple_action_set_state (G_SIMPLE_ACTION(pause), g_variant_new_boolean(state));
  308. updatePauseStatus();
  309. }