Integrate libcloudproviders support

This commit integrates support for libcloudproviders
desktop integration API. If build with the library it
will check on startup if the DBus interface is available
and then use it instead of the legacy status icon.

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl 2017-07-23 20:58:00 +02:00 committed by Roeland Jago Douma
parent 09fa5966da
commit 1cedb1919f
No known key found for this signature in database
GPG key ID: F941078878347C0C
19 changed files with 804 additions and 0 deletions

View file

@ -200,6 +200,9 @@ if(BUILD_CLIENT)
endif() endif()
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_package(GLib2)
find_package(Gio)
find_package(Libcloudproviders)
endif() endif()
if (NOT DEFINED APPLICATION_ICON_NAME) if (NOT DEFINED APPLICATION_ICON_NAME)

View file

View file

@ -0,0 +1,35 @@
# FindGLib2.cmake
# GLib2_FOUND - System has GLib2
# GLib2_INCLUDES - The GLib2 include directories
# GLib2_LIBRARIES - The libraries needed to use GLib2
# GLib2_DEFINITIONS - Compiler switches required for using GLib2
find_package(PkgConfig)
pkg_check_modules(GLib2 QUIET glib-2.0)
set(GLib2_DEFINITIONS ${GLib2_CFLAGS_OTHER})
find_path(GLib2_INCLUDE_DIR
NAMES glib.h glib-object.h
HINTS ${GLib2_INCLUDEDIR} ${GLib2_INCLUDE_DIRS}
PATH_SUFFIXES glib-2.0)
find_path(GLIBCONFIG_INCLUDE_DIR
NAMES glibconfig.h
HINTS ${LIBDIR} ${LIBRARY_DIRS} ${_GLib2_LIBRARY_DIR}
${GLib2_INCLUDEDIR} ${GLib2_INCLUDE_DIRS}
${CMAKE_EXTRA_INCLUDES} ${CMAKE_EXTRA_LIBRARIES}
PATH_SUFFIXES glib-2.0 glib-2.0/include)
list(APPEND GLib2_INCLUDE_DIR ${GLIBCONFIG_INCLUDE_DIR})
find_library(GLib2_LIBRARY
NAMES glib-2.0 libglib-2.0
HINTS ${GLib2_LIBDIR} ${GLib2_LIBRARY_DIRS})
set(GLib2_LIBRARIES ${GLib2_LIBRARY})
set(GLib2_INCLUDE_DIRS ${GLib2_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GLib2 DEFAULT_MSG
GLib2_LIBRARY GLib2_INCLUDE_DIR)
mark_as_advanced(GLib2_INCLUDE_DIR GLib2_LIBRARY)

View file

@ -0,0 +1,61 @@
# - Try to find Gio
# Once done this will define
#
# GIO_FOUND - system has Gio
# GIO_INCLUDE_DIR - the Gio include directory
# GIO_LIBRARIES - the libraries needed to use Gio
# GIO_DEFINITIONS - Compiler switches required for using Gio
IF (GIO_INCLUDE_DIR AND GIO_LIBRARIES)
# in cache already
SET(Gio_FIND_QUIETLY TRUE)
ELSE (GIO_INCLUDE_DIR AND GIO_LIBRARIES)
SET(Gio_FIND_QUIETLY FALSE)
ENDIF (GIO_INCLUDE_DIR AND GIO_LIBRARIES)
IF (NOT WIN32)
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(GIO gio-2.0)
#MESSAGE(STATUS "DEBUG: Gio include directory = ${GIO_INCLUDE_DIRS}")
#MESSAGE(STATUS "DEBUG: Gio link directory = ${GIO_LIBRARY_DIRS}")
#MESSAGE(STATUS "DEBUG: Gio CFlags = ${GIO_CFLAGS}")
SET(GIO_DEFINITIONS ${GIO_CFLAGS_OTHER})
ENDIF (NOT WIN32)
FIND_PATH(GIO_INCLUDE_DIR gio.h
PATHS
${GIO_INCLUDEDIR}
${GIO_INCLUDE_DIRS}
PATH_SUFFIXES glib-2.0/gio/
)
FIND_LIBRARY(_GioLibs NAMES gio-2.0 libgio-2.0
PATHS
${GIO_LIBDIR}
${GIO_LIBRARY_DIRS}
)
SET( GIO_LIBRARIES ${_GioLibs} )
SET( GIO_INCLUDE_DIRS ${GIO_INCLUDE_DIR} )
IF (GIO_INCLUDE_DIR AND GIO_LIBRARIES)
SET(GIO_FOUND TRUE)
ELSE (GIO_INCLUDE_DIR AND GIO_LIBRARIES)
SET(GIO_FOUND FALSE)
ENDIF (GIO_INCLUDE_DIR AND GIO_LIBRARIES)
IF (GIO_FOUND)
IF (NOT Gio_FIND_QUIETLY)
MESSAGE(STATUS "Found Gio libraries: ${GIO_LIBRARIES}")
MESSAGE(STATUS "Found Gio includes : ${GIO_INCLUDE_DIR}")
ENDIF (NOT Gio_FIND_QUIETLY)
ELSE (GIO_FOUND)
IF (Gio_FIND_REQUIRED)
MESSAGE(STATUS "Could NOT find Gio")
ENDIF(Gio_FIND_REQUIRED)
ENDIF (GIO_FOUND)
MARK_AS_ADVANCED(GIO_INCLUDE_DIR _GioLibs)

View file

@ -0,0 +1,22 @@
# FindLibcloudproviders.cmake
find_path(LIBCLOUDPROVIDERS_INCLUDE_DIR
NAMES cloudprovidersproviderexporter.h cloudprovidersaccountexporter.h
PATH_SUFFIXES cloudproviders
)
find_library(LIBCLOUDPROVIDERS_LIBRARY
NAMES
libcloudproviders
cloudproviders
HINTS
/usr/lib
/usr/lib/${CMAKE_ARCH_TRIPLET}
/usr/local/lib
/opt/local/lib
${CMAKE_LIBRARY_PATH}
${CMAKE_INSTALL_PREFIX}/lib
)
message("================> ${LIBCLOUDPROVIDERS_LIBRARY}")
find_package_handle_standard_args(LIBCLOUDPROVIDERS DEFAULT_MSG LIBCLOUDPROVIDERS_INCLUDE_DIR LIBCLOUDPROVIDERS_LIBRARY)

View file

@ -20,4 +20,6 @@ if( UNIX AND NOT APPLE )
message("Dolphin plugin disabled: KDE Frameworks 5.16 not found") message("Dolphin plugin disabled: KDE Frameworks 5.16 not found")
endif() endif()
endif() endif()
add_subdirectory(libcloudproviders)
endif() endif()

View file

@ -0,0 +1,57 @@
include(UsePkgConfig)
MACRO(PKGCONFIG_GETVAR _package _var _output_variable)
SET(${_output_variable})
# if pkg-config has been found
IF (PKGCONFIG_EXECUTABLE)
EXEC_PROGRAM(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --exists RETURN_VALUE _return_VALUE OUTPUT_VARIABLE _pkgconfigDevNull)
# and if the package of interest also exists for pkg-config, then get the information
IF (NOT _return_VALUE)
EXEC_PROGRAM(${PKGCONFIG_EXECUTABLE} ARGS ${_package} --variable ${_var} OUTPUT_VARIABLE ${_output_variable})
ENDIF (NOT _return_VALUE)
ENDIF (PKGCONFIG_EXECUTABLE)
ENDMACRO(PKGCONFIG_GETVAR _package _var _output_variable)
macro(dbus_add_activation_service _sources)
PKGCONFIG_GETVAR(dbus-1 session_bus_services_dir _install_dir)
foreach (_i ${_sources})
get_filename_component(_service_file ${_i} ABSOLUTE)
string(REGEX REPLACE "\\.service.*$" ".service" _output_file ${_i})
set(_target ${CMAKE_CURRENT_BINARY_DIR}/${_output_file})
configure_file(${_service_file} ${_target})
install(FILES ${_target} DESTINATION ${_install_dir} RENAME "${LIBCLOUDPROVIDERS_DBUS_BUS_NAME}.service")
endforeach (_i ${ARGN})
endmacro(dbus_add_activation_service _sources)
macro(libcloudproviders_add_config _sources)
set(_install_dir "${CMAKE_INSTALL_PREFIX}/share/cloud-providers")
foreach (_i ${_sources})
get_filename_component(_service_file ${_i} ABSOLUTE)
string(REGEX REPLACE "\\.ini.*$" ".ini" _output_file ${_i})
set(_target ${CMAKE_CURRENT_BINARY_DIR}/${_output_file})
configure_file(${_service_file} ${_target})
install(FILES ${_target} DESTINATION ${_install_dir} RENAME "${LIBCLOUDPROVIDERS_DBUS_BUS_NAME}.ini")
endforeach (_i ${ARGN})
endmacro(libcloudproviders_add_config _sources)
IF (UNIX AND WITH_DBUS AND LIBCLOUDPROVIDERS_FOUND)
STRING(TOLOWER "${APPLICATION_VENDOR}" DBUS_VENDOR)
STRING(REGEX REPLACE "[^A-z0-9]" "" DBUS_VENDOR "${DBUS_VENDOR}")
STRING(REGEX REPLACE "[^A-z0-9]" "" DBUS_APPLICATION_NAME "${APPLICATION_SHORTNAME}")
if (NOT DBUS_PREFIX)
set(DBUS_PREFIX "com")
endif ()
set(LIBCLOUDPROVIDERS_DBUS_BUS_NAME "${DBUS_PREFIX}.${DBUS_VENDOR}.${DBUS_APPLICATION_NAME}")
set(LIBCLOUDPROVIDERS_DBUS_OBJECT_PATH "/${DBUS_PREFIX}/${DBUS_VENDOR}/${DBUS_APPLICATION_NAME}")
dbus_add_activation_service(org.freedesktop.CloudProviders.service.in)
libcloudproviders_add_config(org.freedesktop.CloudProviders.ini.in)
ENDIF ()

View file

@ -0,0 +1,4 @@
[Cloud Providers]
BusName=@LIBCLOUDPROVIDERS_DBUS_BUS_NAME@
ObjectPath=@LIBCLOUDPROVIDERS_DBUS_OBJECT_PATH@
Version=1

View file

@ -0,0 +1,4 @@
[D-BUS Service]
Name=@LIBCLOUDPROVIDERS_DBUS_BUS_NAME@
Exec=@APPLICATION_EXECUTABLE@

View file

@ -182,6 +182,20 @@ set(3rdparty_INC
include_directories(${3rdparty_INC}) include_directories(${3rdparty_INC})
IF( NOT WIN32 AND NOT APPLE AND WITH_DBUS AND LIBCLOUDPROVIDERS_FOUND)
message("Building with libcloudproviderssupport")
add_definitions(-DWITH_LIBCLOUDPROVIDERS)
set(client_SRCS ${client_SRCS} cloudproviders/cloudprovidermanager.cpp)
set(client_SRCS ${client_SRCS} cloudproviders/cloudproviderwrapper.cpp)
include_directories(${GLib2_INCLUDE_DIRS})
include_directories(${GIO_INCLUDE_DIRS})
include_directories(${LIBCLOUDPROVIDERS_INCLUDE_DIR})
ENDIF()
# csync is required. # csync is required.
include_directories(${CMAKE_SOURCE_DIR}/src/csync include_directories(${CMAKE_SOURCE_DIR}/src/csync
${CMAKE_BINARY_DIR}/src/csync ${CMAKE_BINARY_DIR}/src/csync
@ -309,6 +323,20 @@ target_link_libraries( ${APPLICATION_EXECUTABLE} ${QT_LIBRARIES} )
target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} ) target_link_libraries( ${APPLICATION_EXECUTABLE} ${synclib_NAME} )
target_link_libraries( ${APPLICATION_EXECUTABLE} updater ) target_link_libraries( ${APPLICATION_EXECUTABLE} updater )
target_link_libraries( ${APPLICATION_EXECUTABLE} ${OS_SPECIFIC_LINK_LIBRARIES} ) target_link_libraries( ${APPLICATION_EXECUTABLE} ${OS_SPECIFIC_LINK_LIBRARIES} )
IF( LIBCLOUDPROVIDERS_FOUND )
string(TOLOWER "${APPLICATION_VENDOR}" DBUS_VENDOR)
string(REGEX REPLACE "[^A-z0-9]" "" DBUS_VENDOR "${DBUS_VENDOR}")
string(REGEX REPLACE "[^A-z0-9]" "" DBUS_APPLICATION_NAME "${APPLICATION_SHORTNAME}")
if(NOT DBUS_PREFIX)
set(DBUS_PREFIX "com")
endif(NOT DBUS_PREFIX)
set(LIBCLOUDPROVIDERS_DBUS_BUS_NAME "${DBUS_PREFIX}.${DBUS_VENDOR}.${DBUS_APPLICATION_NAME}")
set(LIBCLOUDPROVIDERS_DBUS_OBJECT_PATH "/${DBUS_PREFIX}/${DBUS_VENDOR}/${DBUS_APPLICATION_NAME}")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cloudproviders/cloudproviderconfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/cloudproviderconfig.h)
target_link_libraries( ${APPLICATION_EXECUTABLE} ${GLib2_LDFLAGS} ${GIO_LDFLAGS} ${LIBCLOUDPROVIDERS_LIBRARY} )
ENDIF()
if(WITH_CRASHREPORTER) if(WITH_CRASHREPORTER)
target_link_libraries( ${APPLICATION_EXECUTABLE} crashreporter-handler) target_link_libraries( ${APPLICATION_EXECUTABLE} crashreporter-handler)

View file

@ -201,6 +201,9 @@ Application::Application(int &argc, char **argv)
if (_showLogWindow) { if (_showLogWindow) {
_gui->slotToggleLogBrowser(); // _showLogWindow is set in parseOptions. _gui->slotToggleLogBrowser(); // _showLogWindow is set in parseOptions.
} }
#if WITH_LIBCLOUDPROVIDERS
_gui->setupCloudProviders();
#endif
// Enable word wrapping of QInputDialog (#4197) // Enable word wrapping of QInputDialog (#4197)
setStyleSheet("QInputDialog QLabel { qproperty-wordWrap:1; }"); setStyleSheet("QInputDialog QLabel { qproperty-wordWrap:1; }");

View file

@ -0,0 +1,21 @@
/*
* Copyright (C) by Julius Härtl <jus@bitgrid.net>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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.
*/
#ifndef CLOUDPROVIDERCONFIG_H_IN
#define CLOUDPROVIDERCONFIG_H_IN
#cmakedefine LIBCLOUDPROVIDERS_DBUS_BUS_NAME "@LIBCLOUDPROVIDERS_DBUS_BUS_NAME@"
#cmakedefine LIBCLOUDPROVIDERS_DBUS_OBJECT_PATH "@LIBCLOUDPROVIDERS_DBUS_OBJECT_PATH@"
#endif // CLOUDPROVIDERCONFIG_H_IN

View file

@ -0,0 +1,71 @@
/*
* Copyright (C) by Julius Härtl <jus@bitgrid.net>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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.
*/
extern "C" {
#include <glib.h>
#include <gio.h>
#include <cloudprovidersproviderexporter.h>
}
#include "cloudproviderwrapper.h"
#include "cloudprovidermanager.h"
#include "account.h"
#include "cloudproviderconfig.h"
CloudProvidersProviderExporter *_providerExporter;
void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data)
{
Q_UNUSED(name);
CloudProviderManager *self;
self = static_cast<CloudProviderManager*>(user_data);
_providerExporter = cloud_providers_provider_exporter_new(connection, LIBCLOUDPROVIDERS_DBUS_BUS_NAME, LIBCLOUDPROVIDERS_DBUS_OBJECT_PATH);
cloud_providers_provider_exporter_set_name (_providerExporter, APPLICATION_NAME);
self->registerSignals();
}
void CloudProviderManager::registerSignals()
{
OCC::FolderMan *folderManager = OCC::FolderMan::instance();
connect(folderManager, SIGNAL(folderListChanged(const Folder::Map &)), SLOT(slotFolderListChanged(const Folder::Map &)));
slotFolderListChanged(folderManager->map());
}
CloudProviderManager::CloudProviderManager(QObject *parent) : QObject(parent)
{
_map = new QMap<QString, CloudProviderWrapper*>();
QString busName = QString(LIBCLOUDPROVIDERS_DBUS_BUS_NAME);
g_bus_own_name (G_BUS_TYPE_SESSION, busName.toAscii().data(), G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, NULL, NULL, this, NULL);
}
void CloudProviderManager::slotFolderListChanged(const Folder::Map &folderMap)
{
QMapIterator<QString, CloudProviderWrapper*> i(*_map);
while (i.hasNext()) {
i.next();
if (!folderMap.contains(i.key())) {
cloud_providers_provider_exporter_remove_account(_providerExporter, i.value()->accountExporter());
delete _map->find(i.key()).value();
_map->remove(i.key());
}
}
Folder::MapIterator j(folderMap);
while (j.hasNext()) {
j.next();
if (!_map->contains(j.key())) {
auto *cpo = new CloudProviderWrapper(this, j.value(), _providerExporter);
_map->insert(j.key(), cpo);
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (C) by Julius Härtl <jus@bitgrid.net>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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.
*/
#ifndef CLOUDPROVIDERMANAGER_H
#define CLOUDPROVIDERMANAGER_H
#include <QObject>
#include "folder.h"
using namespace OCC;
class CloudProviderWrapper;
class CloudProviderManager : public QObject
{
Q_OBJECT
public:
explicit CloudProviderManager(QObject *parent = nullptr);
void registerSignals();
signals:
public slots:
void slotFolderListChanged(const Folder::Map &folderMap);
private:
QMap<QString, CloudProviderWrapper*> *_map;
};
#endif // CLOUDPROVIDERMANAGER_H

View file

@ -0,0 +1,349 @@
/*
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
* Copyright (C) by Julius Härtl <jus@bitgrid.net>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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.
*/
extern "C" {
#include <glib.h>
#include <gio.h>
#include <cloudprovidersaccountexporter.h>
#include <cloudprovidersproviderexporter.h>
}
#include "cloudproviderwrapper.h"
#include <account.h>
#include <folder.h>
#include <accountstate.h>
#include <QDesktopServices>
#include "openfilemanager.h"
#include "owncloudgui.h"
#include "application.h"
using namespace OCC;
GSimpleActionGroup *actionGroup = NULL;
static
gchar* qstring_to_gchar(const QString &string)
{
QByteArray ba = string.toUtf8();
char* data = ba.data();
return g_strdup(data);
}
CloudProviderWrapper::CloudProviderWrapper(QObject *parent, Folder *folder, CloudProvidersProviderExporter* cloudprovider) : QObject(parent)
, _folder(folder)
{
_recentlyChanged = new QList<QPair<QString, QString>>();
gchar *accountName = g_strdup_printf ("Account%sFolder%s",
qstring_to_gchar(folder->alias()),
qstring_to_gchar(folder->accountState()->account()->id()));
_cloudProvider = CLOUD_PROVIDERS_PROVIDER_EXPORTER(cloudprovider);
_cloudProviderAccount = cloud_providers_account_exporter_new(_cloudProvider, accountName);
gchar* folderName = qstring_to_gchar(folder->shortGuiLocalPath());
gchar* folderPath = qstring_to_gchar(folder->cleanPath());
cloud_providers_account_exporter_set_name (_cloudProviderAccount, folderName);
cloud_providers_account_exporter_set_icon (_cloudProviderAccount, g_icon_new_for_string(APPLICATION_ICON_NAME, NULL));
cloud_providers_account_exporter_set_path (_cloudProviderAccount, folderPath);
cloud_providers_account_exporter_set_status (_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_IDLE);
cloud_providers_account_exporter_set_menu_model (_cloudProviderAccount, getMenuModel());
cloud_providers_account_exporter_set_action_group (_cloudProviderAccount, getActionGroup());
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString, ProgressInfo)), this, SLOT(slotUpdateProgress(QString, ProgressInfo)));
connect(_folder, SIGNAL(syncStarted()), this, SLOT(slotSyncStarted()));
connect(_folder, SIGNAL(syncFinished(SyncResult)), this, SLOT(slotSyncFinished(const SyncResult)));
connect(_folder, SIGNAL(syncPausedChanged(Folder*,bool)), this, SLOT(slotSyncPausedChanged(Folder*, bool)));
_paused = _folder->syncPaused();
updatePauseStatus();
g_free(accountName);
g_free(folderName);
g_free(folderPath);
}
CloudProviderWrapper::~CloudProviderWrapper()
{
g_object_unref(_cloudProviderAccount);
g_object_unref(_mainMenu);
g_object_unref(actionGroup);
}
CloudProvidersAccountExporter* CloudProviderWrapper::accountExporter()
{
return _cloudProviderAccount;
}
static bool shouldShowInRecentsMenu(const SyncFileItem &item)
{
return !Progress::isIgnoredKind(item._status)
&& item._instruction != CSYNC_INSTRUCTION_EVAL
&& item._instruction != CSYNC_INSTRUCTION_NONE;
}
void CloudProviderWrapper::slotUpdateProgress(const QString &folder, const ProgressInfo &progress)
{
// Only update progress for the current folder
Folder *f = FolderMan::instance()->folder(folder);
if (f != _folder)
return;
// Build recently changed files list
if (!progress._lastCompletedItem.isEmpty() && shouldShowInRecentsMenu(progress._lastCompletedItem)) {
QString kindStr = Progress::asResultString(progress._lastCompletedItem);
QString timeStr = QTime::currentTime().toString("hh:mm");
QString actionText = tr("%1 (%2, %3)").arg(progress._lastCompletedItem._file, kindStr, timeStr);
if (f) {
QString fullPath = f->path() + '/' + progress._lastCompletedItem._file;
if (QFile(fullPath).exists()) {
if (_recentlyChanged->length() > 5)
_recentlyChanged->removeFirst();
_recentlyChanged->append(qMakePair(actionText, fullPath));
} else {
_recentlyChanged->append(qMakePair(actionText, QString("")));
}
}
}
// Build status details text
QString msg;
if (!progress._currentDiscoveredFolder.isEmpty()) {
msg = tr("Checking for changes in '%1'").arg(progress._currentDiscoveredFolder);
} else if (progress.totalSize() == 0) {
quint64 currentFile = progress.currentFile();
quint64 totalFileCount = qMax(progress.totalFiles(), currentFile);
if (progress.trustEta()) {
msg = tr("Syncing %1 of %2 (%3 left)")
.arg(currentFile)
.arg(totalFileCount)
.arg(Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta));
} else {
msg = tr("Syncing %1 of %2")
.arg(currentFile)
.arg(totalFileCount);
}
} else {
QString totalSizeStr = Utility::octetsToString(progress.totalSize());
if (progress.trustEta()) {
msg = tr("Syncing %1 (%2 left)")
.arg(totalSizeStr, Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta));
} else {
msg = tr("Syncing %1")
.arg(totalSizeStr);
}
}
updateStatusText(msg);
if (!progress._lastCompletedItem.isEmpty()
&& shouldShowInRecentsMenu(progress._lastCompletedItem)) {
GMenuItem* item;
g_menu_remove_all (G_MENU(_recentMenu));
if(!_recentlyChanged->isEmpty()) {
QList<QPair<QString, QString>>::iterator i;
for (i = _recentlyChanged->begin(); i != _recentlyChanged->end(); i++) {
gchar *file;
QString label = i->first;
QString fullPath = i->second;
file = g_strdup(qstring_to_gchar(label));
item = g_menu_item_new(file, "cloudprovider.showfile");
g_menu_item_set_action_and_target_value(item, "cloudprovider.showfile", g_variant_new_string(qstring_to_gchar(fullPath)));
g_menu_append_item(_recentMenu, item);
}
} else {
item = g_menu_item_new("No recently changed files", NULL);
g_menu_append_item(_recentMenu, item);
}
}
}
void CloudProviderWrapper::updateStatusText(QString statusText)
{
char* state = qstring_to_gchar(_folder->accountState()->stateString(_folder->accountState()->state()));
char* statusChar = qstring_to_gchar(statusText);
char* status = g_strdup_printf("%s - %s", state, statusChar);
cloud_providers_account_exporter_set_status_details(_cloudProviderAccount, status);
g_free(state);
g_free(statusChar);
g_free(status);
}
void CloudProviderWrapper::updatePauseStatus()
{
if (_paused) {
updateStatusText(tr("Sync paused"));
cloud_providers_account_exporter_set_status (_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_ERROR);
} else {
updateStatusText(tr("Syncing"));
cloud_providers_account_exporter_set_status (_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_SYNCING);
}
}
Folder* CloudProviderWrapper::folder()
{
return _folder;
}
void CloudProviderWrapper::slotSyncStarted()
{
cloud_providers_account_exporter_set_status(_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_SYNCING);
}
void CloudProviderWrapper::slotSyncFinished(const SyncResult &result)
{
if (result.status() == result.Success || result.status() == result.Problem)
{
cloud_providers_account_exporter_set_status(_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_IDLE);
updateStatusText(result.statusString());
return;
}
cloud_providers_account_exporter_set_status(_cloudProviderAccount, CLOUD_PROVIDERS_ACCOUNT_STATUS_ERROR);
updateStatusText(result.statusString());
}
GMenuModel* CloudProviderWrapper::getMenuModel() {
GMenu* section;
GMenuItem* item;
_mainMenu = g_menu_new();
section = g_menu_new();
item = g_menu_item_new("Open website", "cloudprovider.openwebsite");
g_menu_append_item(section, item);
g_menu_append_section(_mainMenu, NULL, G_MENU_MODEL(section));
_recentMenu = g_menu_new();
item = g_menu_item_new("No recently changed files", NULL);
g_menu_append_item(_recentMenu, item);
section = g_menu_new();
item = g_menu_item_new_submenu("Recently changed", G_MENU_MODEL(_recentMenu));
g_menu_append_item(section, item);
g_menu_append_section(_mainMenu, NULL, G_MENU_MODEL(section));
section = g_menu_new();
item = g_menu_item_new("Pause synchronization", "cloudprovider.pause");
g_menu_append_item(section, item);
g_menu_append_section(_mainMenu, NULL, G_MENU_MODEL(section));
section = g_menu_new();
item = g_menu_item_new("Help", "cloudprovider.openhelp");
g_menu_append_item(section, item);
item = g_menu_item_new("Settings", "cloudprovider.opensettings");
g_menu_append_item(section, item);
item = g_menu_item_new("Log out", "cloudprovider.logout");
g_menu_append_item(section, item);
item = g_menu_item_new("Quit sync client", "cloudprovider.quit");
g_menu_append_item(section, item);
g_menu_append_section(_mainMenu, NULL, G_MENU_MODEL(section));
return G_MENU_MODEL(_mainMenu);
}
static void
activate_action_open (GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
Q_UNUSED(parameter);
const gchar *name = g_action_get_name(G_ACTION(action));
auto *self = static_cast<CloudProviderWrapper*>(user_data);
auto *gui = dynamic_cast<ownCloudGui*>(self->parent()->parent());
if(g_str_equal(name, "openhelp")) {
gui->slotHelp();
}
if(g_str_equal(name, "opensettings")) {
gui->slotShowSettings();
}
if(g_str_equal(name, "openwebsite")) {
QDesktopServices::openUrl(self->folder()->accountState()->account()->url());
}
if(g_str_equal(name, "openfolder")) {
showInFileManager(self->folder()->cleanPath());
}
if(g_str_equal(name, "showfile")) {
gchar *path;
g_variant_get (parameter, "s", &path);
g_print("showfile => %s\n", path);
showInFileManager(QString(path));
}
if(g_str_equal(name, "logout")) {
self->folder()->accountState()->signOutByUi();
}
if(g_str_equal(name, "quit")) {
qApp->quit();
}
}
static void
activate_action_openrecentfile (GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
Q_UNUSED(action);
Q_UNUSED(parameter);
auto *self = static_cast<CloudProviderWrapper*>(user_data);
QDesktopServices::openUrl(self->folder()->accountState()->account()->url());
}
static void
activate_action_pause (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
Q_UNUSED(parameter);
auto *self = static_cast<CloudProviderWrapper*>(user_data);
GVariant *old_state, *new_state;
old_state = g_action_get_state (G_ACTION (action));
new_state = g_variant_new_boolean (!(bool)g_variant_get_boolean (old_state));
self->folder()->setSyncPaused((bool)g_variant_get_boolean(new_state));
g_simple_action_set_state (action, new_state);
g_variant_unref (old_state);
}
static GActionEntry actions[] = {
{ "openwebsite", activate_action_open, NULL, NULL, NULL, {0,0,0}},
{ "quit", activate_action_open, NULL, NULL, NULL, {0,0,0}},
{ "logout", activate_action_open, NULL, NULL, NULL, {0,0,0}},
{ "openfolder", activate_action_open, NULL, NULL, NULL, {0,0,0}},
{ "showfile", activate_action_open, "s", NULL, NULL, {0,0,0}},
{ "openhelp", activate_action_open, NULL, NULL, NULL, {0,0,0}},
{ "opensettings", activate_action_open, NULL, NULL, NULL, {0,0,0}},
{ "openrecentfile", activate_action_openrecentfile, "s", NULL, NULL, {0,0,0}},
{ "pause", activate_action_pause, NULL, "false", NULL, {0,0,0}}
};
GActionGroup* CloudProviderWrapper::getActionGroup()
{
actionGroup = g_simple_action_group_new ();
g_action_map_add_action_entries (G_ACTION_MAP (actionGroup), actions, G_N_ELEMENTS (actions), this);
bool state = _folder->syncPaused();
GAction *pause = g_action_map_lookup_action(G_ACTION_MAP(actionGroup), "pause");
g_simple_action_set_state(G_SIMPLE_ACTION(pause), g_variant_new_boolean(state));
return G_ACTION_GROUP (actionGroup);
}
void CloudProviderWrapper::slotSyncPausedChanged(Folder *folder, bool state)
{
Q_UNUSED(folder);
_paused = state;
GAction *pause = g_action_map_lookup_action(G_ACTION_MAP(actionGroup), "pause");
g_simple_action_set_state (G_SIMPLE_ACTION(pause), g_variant_new_boolean(state));
updatePauseStatus();
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (C) by Julius Härtl <jus@bitgrid.net>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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.
*/
#ifndef CLOUDPROVIDER_H
#define CLOUDPROVIDER_H
#include <QObject>
#include "folderman.h"
/* Forward declaration required since gio header files interfere with QObject headers */
struct _CloudProvidersProviderExporter;
typedef _CloudProvidersProviderExporter CloudProvidersProviderExporter;
struct _CloudProvidersAccountExporter;
typedef _CloudProvidersAccountExporter CloudProvidersAccountExporter;
struct _GMenuModel;
typedef _GMenuModel GMenuModel;
struct _GMenu;
typedef _GMenu GMenu;
struct _GActionGroup;
typedef _GActionGroup GActionGroup;
typedef char gchar;
typedef void* gpointer;
using namespace OCC;
class CloudProviderWrapper : public QObject
{
Q_OBJECT
public:
explicit CloudProviderWrapper(QObject *parent = nullptr, Folder *folder = nullptr, CloudProvidersProviderExporter* cloudprovider = nullptr);
~CloudProviderWrapper();
CloudProvidersAccountExporter* accountExporter();
Folder* folder();
GMenuModel* getMenuModel();
GActionGroup* getActionGroup();
void updateStatusText(QString statusText);
void updatePauseStatus();
public slots:
void slotSyncStarted();
void slotSyncFinished(const SyncResult &);
void slotUpdateProgress(const QString &folder, const ProgressInfo &progress);
void slotSyncPausedChanged(Folder*, bool);
private:
Folder *_folder;
CloudProvidersProviderExporter *_cloudProvider;
CloudProvidersAccountExporter *_cloudProviderAccount;
QList<QPair<QString, QString>> *_recentlyChanged;
bool _paused;
GMenu* _mainMenu = NULL;
GMenu* _recentMenu = NULL;
};
#endif // CLOUDPROVIDER_H

View file

@ -763,6 +763,7 @@ void FolderMan::slotRemoveFoldersForAccount(AccountState *accountState)
foreach (const auto &f, foldersToRemove) { foreach (const auto &f, foldersToRemove) {
removeFolder(f); removeFolder(f);
} }
emit folderListChanged(_folderMap);
} }
void FolderMan::slotForwardFolderSyncStateChange() void FolderMan::slotForwardFolderSyncStateChange()

View file

@ -34,10 +34,16 @@
#include "accountmanager.h" #include "accountmanager.h"
#include "common/syncjournalfilerecord.h" #include "common/syncjournalfilerecord.h"
#include "creds/abstractcredentials.h" #include "creds/abstractcredentials.h"
#ifdef WITH_LIBCLOUDPROVIDERS
#include "cloudproviders/cloudprovidermanager.h"
#endif
#include <QDesktopServices> #include <QDesktopServices>
#include <QDir> #include <QDir>
#include <QMessageBox> #include <QMessageBox>
#include <QSignalMapper>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusInterface>
#if defined(Q_OS_X11) #if defined(Q_OS_X11)
#include <QX11Info> #include <QX11Info>
@ -60,6 +66,7 @@ ownCloudGui::ownCloudGui(Application *parent)
#endif #endif
_logBrowser(0) _logBrowser(0)
, _contextMenuVisibleOsx(false) , _contextMenuVisibleOsx(false)
, _bus(QDBusConnection::sessionBus())
, _recentActionsMenu(0) , _recentActionsMenu(0)
, _qdbusmenuWorkaround(false) , _qdbusmenuWorkaround(false)
, _app(parent) , _app(parent)
@ -99,6 +106,28 @@ ownCloudGui::ownCloudGui(Application *parent)
this, &ownCloudGui::slotShowGuiMessage); this, &ownCloudGui::slotShowGuiMessage);
} }
#ifdef WITH_LIBCLOUDPROVIDERS
void ownCloudGui::setupCloudProviders()
{
new CloudProviderManager(this);
}
bool ownCloudGui::cloudProviderApiAvailable()
{
if (!_bus.isConnected()) {
return false;
}
QDBusInterface dbus_iface("org.freedesktop.CloudProviderManager", "/org/freedesktop/CloudProviderManager",
"org.freedesktop.CloudProvider.Manager1", _bus);
if (!dbus_iface.isValid()) {
qCInfo(lcApplication) << "DBus interface unavailable";
return false;
}
return true;
}
#endif
// This should rather be in application.... or rather in ConfigFile? // This should rather be in application.... or rather in ConfigFile?
void ownCloudGui::slotOpenSettingsDialog() void ownCloudGui::slotOpenSettingsDialog()
{ {

View file

@ -25,6 +25,7 @@
#include <QMenu> #include <QMenu>
#include <QSize> #include <QSize>
#include <QTimer> #include <QTimer>
#include <QDBusConnection>
namespace OCC { namespace OCC {
@ -52,6 +53,10 @@ public:
static void raiseDialog(QWidget *raiseWidget); static void raiseDialog(QWidget *raiseWidget);
static QSize settingsDialogSize() { return QSize(800, 500); } static QSize settingsDialogSize() { return QSize(800, 500); }
void setupOverlayIcons(); void setupOverlayIcons();
#ifdef WITH_LIBCLOUDPROVIDERS
void setupCloudProviders();
bool cloudProviderApiAvailable();
#endif
/// Whether the tray menu is visible /// Whether the tray menu is visible
bool contextMenuVisible() const; bool contextMenuVisible() const;
@ -123,6 +128,8 @@ private:
// on OSX because aboutToHide is not reliable everywhere. // on OSX because aboutToHide is not reliable everywhere.
bool _contextMenuVisibleOsx; bool _contextMenuVisibleOsx;
QDBusConnection _bus;
QMenu *_recentActionsMenu; QMenu *_recentActionsMenu;
QVector<QMenu *> _accountMenus; QVector<QMenu *> _accountMenus;
bool _qdbusmenuWorkaround; bool _qdbusmenuWorkaround;