mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-22 04:55:48 +03:00
Merge branch 'master' into fix-documentation-build-process
This commit is contained in:
commit
488b964c52
148 changed files with 12975 additions and 10178 deletions
|
@ -7,6 +7,8 @@ endif()
|
|||
|
||||
project(client)
|
||||
|
||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
set(OEM_THEME_DIR "" CACHE STRING "Define directory containing a custom theme")
|
||||
if ( EXISTS ${OEM_THEME_DIR}/OEM.cmake )
|
||||
include ( ${OEM_THEME_DIR}/OEM.cmake )
|
||||
|
@ -58,9 +60,6 @@ if( UNIX AND NOT APPLE )
|
|||
endif()
|
||||
####
|
||||
|
||||
# Enable Q_ASSERT etc. in all builds
|
||||
add_definitions( -DQT_FORCE_ASSERTS )
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(DefineInstallationPaths)
|
||||
include(GenerateExportHeader)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
ChangeLog
|
||||
=========
|
||||
|
||||
version 2.3.0 (2017-0x-xx)
|
||||
* WiP!
|
||||
* WiP Switch Windows and OS X build to 5.6.2
|
||||
* WiP Performance improvements for exclude detection
|
||||
version 2.3.0 (2017-02-xx)
|
||||
* Decreased memory usage during sync
|
||||
* Overlay icons: Lower CPU usage
|
||||
* Allow to not sync the server's external storages by default
|
||||
* Switch Windows and OS X build to 5.6.2
|
||||
* Switch to new ownCloud server WebDAV endpoint
|
||||
* Chunking NG: New file upload chunking algorithmn for ownCloud server 9.2
|
||||
* Allow to sync a folder to multiple different servers (Filename change from .csync_journal.db to _sync_$HASH.db)
|
||||
|
|
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
|
@ -39,7 +39,7 @@ node('CLIENT') {
|
|||
|
||||
|
||||
stage 'Win32'
|
||||
def win32 = docker.image('deepdiver/docker-owncloud-client-win32:latest')
|
||||
def win32 = docker.image('guruz/docker-owncloud-client-win32:latest')
|
||||
win32.pull() // make sure we have the latest available from Docker Hub
|
||||
win32.inside {
|
||||
sh '''
|
||||
|
|
|
@ -9,7 +9,7 @@ ENV REFRESHED_AT 20160421
|
|||
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys refresh
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys ar http://download.opensuse.org/repositories/windows:/mingw/openSUSE_42.1/windows:mingw.repo
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys ar http://download.opensuse.org/repositories/isv:ownCloud:toolchains:mingw:win32:2.2/openSUSE_Leap_42.1/isv:ownCloud:toolchains:mingw:win32:2.2.repo
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys ar http://download.opensuse.org/repositories/isv:ownCloud:toolchains:mingw:win32:2.3/openSUSE_Leap_42.1/isv:ownCloud:toolchains:mingw:win32:2.3.repo
|
||||
RUN zypper --non-interactive --gpg-auto-import-keys install cmake make mingw32-cross-binutils mingw32-cross-cpp mingw32-cross-gcc \
|
||||
mingw32-cross-gcc-c++ mingw32-cross-pkg-config mingw32-filesystem \
|
||||
mingw32-headers mingw32-runtime site-config mingw32-libwebp \
|
||||
|
|
|
@ -3,7 +3,7 @@ StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Показати примітки
|
|||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Знайдено процес(и) ${APPLICATION_EXECUTABLE}, які необхідно зупинити.$\nХочете щоб програма установки зробила це самостійно?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Завершення процесів ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Не знайдено процеси, які необхідно зупинити!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Знайдено застарілу версію програми ${APPLICATION_NAME}. Рекомендуємо її спочатку видалити. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "У вашої системі встановлена застаріла версія додатку ${APPLICATION_NAME}. Рекомендуємо видалити її перед початком встановлення поточної версії. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Видалити перед установкою"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Не видаляти"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Установлено"
|
||||
|
|
|
@ -28,7 +28,6 @@ include(ConfigureChecks.cmake)
|
|||
|
||||
|
||||
set(SOURCE_DIR ${CMAKE_SOURCE_DIR})
|
||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
|
@ -41,7 +40,7 @@ endif (MEM_NULL_TESTS)
|
|||
add_subdirectory(src)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_UNIT_TESTING ON)
|
||||
set(WITH_TESTING ON)
|
||||
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND)
|
||||
|
|
|
@ -26,4 +26,4 @@
|
|||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||
#cmakedefine HAVE_ASPRINTF 1
|
||||
|
||||
#cmakedefine WITH_UNIT_TESTING 1
|
||||
#cmakedefine WITH_TESTING 1
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
|
||||
#include "csync_log.h"
|
||||
|
||||
#ifndef WITH_UNIT_TESTING
|
||||
#ifndef WITH_TESTING
|
||||
static
|
||||
#endif
|
||||
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
||||
|
|
|
@ -36,7 +36,7 @@ enum csync_exclude_type_e {
|
|||
};
|
||||
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
#ifdef WITH_TESTING
|
||||
int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ struct csync_s {
|
|||
|
||||
/* hooks for checking the white list (uses the update_callback_userdata) */
|
||||
int (*checkSelectiveSyncBlackListHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char*);
|
||||
int (*checkSelectiveSyncNewFolderHook)(void*, const char* /* path */, const char* /* remotePerm */);
|
||||
|
||||
|
||||
csync_vio_opendir_hook remote_opendir_hook;
|
||||
|
@ -207,7 +207,7 @@ __attribute__ ((packed))
|
|||
#endif
|
||||
;
|
||||
|
||||
void csync_file_stat_free(csync_file_stat_t *st);
|
||||
OCSYNC_EXPORT void csync_file_stat_free(csync_file_stat_t *st);
|
||||
|
||||
/*
|
||||
* context for the treewalk function
|
||||
|
|
|
@ -56,17 +56,15 @@ int csync_get_statedb_exists(CSYNC *ctx);
|
|||
*
|
||||
* @return 0 on success, less than 0 if an error occurred with errno set.
|
||||
*/
|
||||
int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
||||
OCSYNC_EXPORT int csync_statedb_load(CSYNC *ctx, const char *statedb, sqlite3 **pdb);
|
||||
|
||||
int csync_statedb_close(CSYNC *ctx);
|
||||
OCSYNC_EXPORT int csync_statedb_close(CSYNC *ctx);
|
||||
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash);
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx, uint64_t phash);
|
||||
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode);
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx, uint64_t inode);
|
||||
|
||||
csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id);
|
||||
|
||||
char *csync_statedb_get_etag(CSYNC *ctx, uint64_t jHash);
|
||||
OCSYNC_EXPORT csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx, const char *file_id);
|
||||
|
||||
/**
|
||||
* @brief Query all files metadata inside and below a path.
|
||||
|
|
|
@ -436,7 +436,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
|||
st->instruction = CSYNC_INSTRUCTION_NEW;
|
||||
|
||||
if (fs->type == CSYNC_VIO_FILE_TYPE_DIRECTORY && ctx->current == REMOTE_REPLICA && ctx->callbacks.checkSelectiveSyncNewFolderHook) {
|
||||
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path)) {
|
||||
if (ctx->callbacks.checkSelectiveSyncNewFolderHook(ctx->callbacks.update_callback_userdata, path, fs->remotePerm)) {
|
||||
csync_file_stat_free(st);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -132,11 +132,16 @@ changed and no synchronization occurs.
|
|||
In the event a file has changed on both the local and the remote repository
|
||||
since the last sync run, it can not easily be decided which version of the file
|
||||
is the one that should be used. However, changes to any side will not be lost. Instead,
|
||||
a *conflict case* is created. The client resolves this conflict by creating a
|
||||
conflict file of the older of the two files and saving the newer file under the
|
||||
original file name. Conflict files are always created on the client and never
|
||||
on the server. The conflict file uses the same name as the original file, but
|
||||
is appended with the timestamp of the conflict detection.
|
||||
a *conflict case* is created. The client resolves this conflict by renaming the
|
||||
local file, appending a conflict label and timestamp, and saving the remote file
|
||||
under the original file name.
|
||||
|
||||
Example: Assume there is a conflict in message.txt because its contents have
|
||||
changed both locally and remotely since the last sync run. The local file with
|
||||
the local changes will be renamed to message_conflict-20160101-153110.txt and
|
||||
the remote file will be downloaded and saved as message.txt.
|
||||
|
||||
Conflict files are always created on the client and never on the server.
|
||||
|
||||
|
||||
.. _ignored-files-label:
|
||||
|
@ -153,8 +158,7 @@ By default, the ownCloud Client ignores the following files:
|
|||
|
||||
* Files matched by one of the patterns defined in the Ignored Files Editor
|
||||
* Files containing characters that do not work on certain file systems ``(`\, /, :, ?, *, ", >, <, |`)``.
|
||||
* Files starting with ``._sync_xxxxxxx.db`` and the old format ``.csync_journal.db``,
|
||||
as these files are reserved for journalling.
|
||||
* Files starting with ``._sync_xxxxxxx.db`` and the old format ``.csync_journal.db``, as these files are reserved for journalling.
|
||||
|
||||
If a pattern selected using a checkbox in the `ignoredFilesEditor-label` (or if
|
||||
a line in the exclude file starts with the character ``]`` directly followed by
|
||||
|
@ -163,12 +167,12 @@ data*. These files are ignored and *removed* by the client if found in the
|
|||
synchronized folder. This is suitable for meta files created by some
|
||||
applications that have no sustainable meaning.
|
||||
|
||||
If a pattern ends with the forwardslash (``/``) character, only directories are
|
||||
If a pattern ends with the forward slash (``/``) character, only directories are
|
||||
matched. The pattern is only applied for directory components of filenames
|
||||
selected using the checkbox.
|
||||
|
||||
To match filenames against the exclude patterns, the unix standard C library
|
||||
function fnmatch is used. This process checks the filename against the
|
||||
To match filenames against the exclude patterns, the UNIX standard C library
|
||||
function ``fnmatch`` is used. This process checks the filename against the
|
||||
specified pattern using standard shell wildcard pattern matching. For more
|
||||
information, please refer to `The opengroup website
|
||||
<http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_01>`_.
|
||||
|
@ -207,9 +211,9 @@ In the communication between client and server a couple of custom WebDAV propert
|
|||
were introduced. They are either needed for sync functionality or help have a positive
|
||||
effect on synchronization performance.
|
||||
|
||||
This chapter describes additional xml elements which the server returns in response
|
||||
This chapter describes additional XML elements which the server returns in response
|
||||
to a successful PROPFIND request on a file or directory. The elements are returned in
|
||||
the namespace oc.
|
||||
the namespace ``oc``.
|
||||
|
||||
Server Side Permissions
|
||||
------------------------
|
||||
|
@ -218,27 +222,27 @@ The XML element ``<oc:permissions>`` represents the permission- and sharing stat
|
|||
item. It is a list of characters, and each of the chars has a meaning as outlined
|
||||
in the table below:
|
||||
|
||||
+----+----------------+-------------------------------------------+
|
||||
|Code| Resource | Description |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| S | File or Folder | is shared |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| R | File or Folder | can share (includes reshare) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| M | File or Folder | is mounted (like on DropBox, Samba, etc.) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| W | File | can write file |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| C | Folder |can create file in folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| K | Folder | can create folder (mkdir) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| D | File or Folder |can delete file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| N | File or Folder | can rename file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| V | File or Folder | can move file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
+------+----------------+-------------------------------------------+
|
||||
| Code | Resource | Description |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| S | File or Folder | is shared |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| R | File or Folder | can share (includes re-share) |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| M | File or Folder | is mounted (like on Dropbox, Samba, etc.) |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| W | File | can write file |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| C | Folder | can create file in folder |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| K | Folder | can create folder (mkdir) |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| D | File or Folder | can delete file or folder |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| N | File or Folder | can rename file or folder |
|
||||
+------+----------------+-------------------------------------------+
|
||||
| V | File or Folder | can move file or folder |
|
||||
+------+----------------+-------------------------------------------+
|
||||
|
||||
|
||||
Example:
|
||||
|
|
|
@ -59,7 +59,7 @@ the auto-updater entirely. The following sections describe how to disable the
|
|||
auto-update mechanism for different operating systems.
|
||||
|
||||
Preventing Automatic Updates in Windows Environments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Users may disable automatic updates by adding this line to the [General]
|
||||
section of their ``owncloud.cfg`` files::
|
||||
|
|
|
@ -77,25 +77,29 @@ To set up your build environment for development using HomeBrew_:
|
|||
|
||||
brew tap owncloud/owncloud
|
||||
|
||||
5. Install any missing dependencies::
|
||||
5. Install a Qt5 version with qtwebkit support::
|
||||
|
||||
brew install qt5 --with-qtwebkit
|
||||
|
||||
6. Install any missing dependencies::
|
||||
|
||||
brew install $(brew deps owncloud-client)
|
||||
|
||||
3. Add Qt from brew to the path::
|
||||
7. Add Qt from brew to the path::
|
||||
|
||||
export PATH=/usr/local/Cellar/qt5/5.x.y/bin:$PATH
|
||||
|
||||
Where ``x.z`` is the current version of Qt 5 that brew has installed
|
||||
Where ``x.y`` is the current version of Qt 5 that brew has installed
|
||||
on your machine.
|
||||
4. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||
8. Install qtkeychain from here: git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||
make sure you make the same install prefix as later while building the client e.g. -
|
||||
``DCMAKE_INSTALL_PREFIX=/Path/to/client-install``
|
||||
|
||||
5. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||
9. For compilation of the client, follow the :ref:`generic-build-instructions`.
|
||||
|
||||
6. Install the Packages_ package creation tool.
|
||||
10. Install the Packages_ package creation tool.
|
||||
|
||||
7. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
||||
11. In the build directory, run ``admin/osx/create_mac.sh <build_dir>
|
||||
<install_dir>``. If you have a developer signing certificate, you can specify
|
||||
its Common Name as a third parameter (use quotes) to have the package
|
||||
signed automatically.
|
||||
|
@ -106,7 +110,7 @@ To set up your build environment for development using HomeBrew_:
|
|||
work correctly.
|
||||
|
||||
Windows Development Build
|
||||
-----------------------
|
||||
-------------------------
|
||||
|
||||
If you want to test some changes and deploy them locally, you can build natively
|
||||
on Windows using MinGW. If you want to generate an installer for deployment, please
|
||||
|
@ -206,7 +210,7 @@ In order to make setup simple, you can use the provided Dockerfile to build your
|
|||
-in ${unsigned_file} \
|
||||
-out ${installer_file}
|
||||
|
||||
for ``-in``, use the URL to the time stamping server provided by your CA along with the Authenticode certificate. Alternatively,
|
||||
For ``-in``, use the URL to the time stamping server provided by your CA along with the Authenticode certificate. Alternatively,
|
||||
you may use the official Microsoft ``signtool`` utility on Microsoft Windows.
|
||||
|
||||
If you're familiar with docker, you can use the version of ``osslsigncode`` that is part of the docker image.
|
||||
|
|
|
@ -29,5 +29,5 @@ improvements. (See the `complete changelog
|
|||
* Improved user notifications about ignored files and conflicts
|
||||
* Add warnings for old server versions
|
||||
* Update of QtKeyChain to support Windows credential store
|
||||
* Packaging of dolphin overlay icon module for bleeding edge distros
|
||||
|
||||
* Packaging of dolphin overlay icon module for bleeding edge distributions
|
||||
|
||||
|
|
|
@ -236,7 +236,7 @@ also to limit download and upload bandwidth.
|
|||
|
||||
.. figure:: images/settings_network.png
|
||||
|
||||
.. _ignoredFilesEditor-label:
|
||||
.. _usingIgnoredFilesEditor-label:
|
||||
|
||||
Using the Ignored Files Editor
|
||||
------------------------------
|
||||
|
|
|
@ -25,4 +25,6 @@ The other options are:
|
|||
Clears (flushes) the log file after each write action.
|
||||
|
||||
``--confdir`` `<dirname>`
|
||||
Uses the specified configuration directory.
|
||||
Uses the specified configuration directory.
|
||||
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ OPTIONS
|
|||
Exclude list file
|
||||
|
||||
``--unsyncedfolders [file]``
|
||||
File containing the list of unsynced folders (selective sync)
|
||||
File containing the list of un-synced folders (selective sync)
|
||||
|
||||
``--max-sync-retries [n]``
|
||||
Retries maximum n times (defaults to 3)
|
||||
|
|
|
@ -49,7 +49,7 @@ Other command line switches supported by ``owncloudcmd`` include the following:
|
|||
Exclude list file
|
||||
|
||||
``--unsyncedfolders [file]``
|
||||
File containing the list of unsynced remote folders (selective sync)
|
||||
File containing the list of un-synced remote folders (selective sync)
|
||||
|
||||
``--max-sync-retries [n]``
|
||||
Retries maximum n times (defaults to 3)
|
||||
|
|
|
@ -27,7 +27,7 @@ Identifying Basic Functionality Problems
|
|||
misconfiguration of the WebDAV API.
|
||||
|
||||
The ownCloud Client uses the built-in WebDAV access of the server content.
|
||||
Verify that you can log on to ownClouds WebDAV server. To verify connectivity
|
||||
Verify that you can log on to ownCloud's WebDAV server. To verify connectivity
|
||||
with the ownCloud WebDAV server:
|
||||
|
||||
- Open a browser window and enter the address to the ownCloud WebDAV server.
|
||||
|
@ -50,6 +50,21 @@ Identifying Basic Functionality Problems
|
|||
As an example, after installing the ``cadaver`` app, you can issue the
|
||||
``propget`` command to obtain various properties pertaining to the current
|
||||
directory and also verify WebDAV server connection.
|
||||
|
||||
"CSync unknown error"
|
||||
---------------------
|
||||
|
||||
If you see this error message stop your client, delete the
|
||||
``.csync_journal.db`` file, and then restart your client.
|
||||
There is a ``.csync_journal.db`` file inside the folder of every account
|
||||
configured on your client.
|
||||
|
||||
.. NOTE::
|
||||
Please note that this will also erase some of your settings about which
|
||||
files to download.
|
||||
|
||||
See https://github.com/owncloud/client/issues/5226 for more discussion of this
|
||||
issue.
|
||||
|
||||
|
||||
Isolating other issues
|
||||
|
@ -63,17 +78,17 @@ Other issues can affect synchronization of your ownCloud files:
|
|||
|
||||
- Synchronizing the same directory with ownCloud and other synchronization
|
||||
software such as Unison, rsync, Microsoft Windows Offline Folders, or other
|
||||
cloud services such as DropBox or Microsoft SkyDrive is not supported and
|
||||
cloud services such as Dropbox or Microsoft SkyDrive is not supported and
|
||||
should not be attempted. In the worst case, it is possible that synchronizing
|
||||
folders or files using ownCloud and other synchronization software or
|
||||
services can result in data loss.
|
||||
|
||||
- If you find that only specific files are not synrchronized, the
|
||||
- If you find that only specific files are not synchronized, the
|
||||
synchronization protocol might be having an effect. Some files are
|
||||
automatically ignored because they are system files, other files might be
|
||||
ignored because their filename contains characters that are not supported on
|
||||
certain file systems. For more information about ignored files, see
|
||||
:ref:`_ignored-files-label`.
|
||||
:ref:`ignored-files-label`.
|
||||
|
||||
- If you are operating your own server, and use the local storage backend (the
|
||||
default), make sure that ownCloud has exclusive access to the directory.
|
||||
|
@ -119,7 +134,7 @@ To obtain the client log file:
|
|||
|
||||
5. Name the log file and click the 'Save' button.
|
||||
|
||||
The log file is saved in the location specifed.
|
||||
The log file is saved in the location specified.
|
||||
|
||||
Alternatively, you can launch the ownCloud Log Output window using the
|
||||
``--logwindow`` command. After issuing this command, the Log Output window
|
||||
|
@ -182,7 +197,7 @@ directly from the file system in the ownCloud server data directory.
|
|||
Webserver Log Files
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It can be helpful to view your webservers error log file to isolate any
|
||||
It can be helpful to view your webserver's error log file to isolate any
|
||||
ownCloud-related problems. For Apache on Linux, the error logs are typically
|
||||
located in the ``/var/log/apache2`` directory. Some helpful files include the
|
||||
following:
|
||||
|
|
|
@ -61,7 +61,7 @@ Where:
|
|||
desired.
|
||||
* ``Storage Usage``: Provides further details on the storage utilization on the
|
||||
ownCloud server.
|
||||
* ``Edit Ignored Files``: Provides a list of files which will be ignored, i.e.
|
||||
* ``Edit Ignored Files``: Provides a list of files which will be ignored, i.e.,
|
||||
will not sync between the client and server. The ignored files editor allows
|
||||
adding patterns for files or directories that should be excluded from the
|
||||
sync process. Besides normal characters, wild cards may be used, an asterisk
|
||||
|
@ -124,7 +124,7 @@ The tab provides several useful options:
|
|||
:scale: 50 %
|
||||
|
||||
* ``Launch on System Startup``: This option is automatically activated
|
||||
once a user has conimaged his account. Unchecking the box will cause
|
||||
once a user has conimaged his account. Un-checking the box will cause
|
||||
ownCloud client to not launch on startup for a particular user.
|
||||
* ``Show Desktop Nofications``: When checked, bubble notifications when
|
||||
a set of sync operations has been performed are provided.
|
||||
|
|
|
@ -37,6 +37,10 @@ Operating system:
|
|||
|
||||
OS language:
|
||||
|
||||
Qt version used by client package (Linux only, see also Settings dialog):
|
||||
|
||||
Client package (From ownCloud or distro) (Linux only):
|
||||
|
||||
Installation path of client:
|
||||
|
||||
### Logs
|
||||
|
|
|
@ -640,6 +640,99 @@ X-GNOME-Autostart-Delay=3
|
|||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
||||
GenericName[oc]=Dorsièr de Sincronizacion
|
||||
|
@ -665,7 +758,9 @@ Comment[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
|||
GenericName[ja_JP]=フォルダー同期
|
||||
Name[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
||||
Icon[ja_JP]=@APPLICATION_EXECUTABLE@
|
||||
Comment[el]=@ΟΝΟΜΑ_ΕΦΑΡΜΟΓΗΣ@ συγχρονισμός επιφάνειας εργασίας πελάτη
|
||||
GenericName[el]=Συγχρονισμός φακέλου
|
||||
Name[el]=@ΟΝΟΜΑ_ΕΦΑΡΜΟΓΗΣ@ συγχρονισμός επιφάνειας εργασίας πελάτη
|
||||
Icon[el]=@APPLICATION_EXECUTABLE@
|
||||
Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client
|
||||
GenericName[en_GB]=Folder Sync
|
||||
|
@ -679,10 +774,13 @@ Comment[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
|||
GenericName[de_DE]=Ordner-Synchronisation
|
||||
Name[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
||||
Icon[de_DE]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
GenericName[pl]=Folder Synchronizacji
|
||||
Name[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
Icon[pl]=@APPLICATION_EXECUTABLE@
|
||||
Comment[bg_BG]=@APPLICATION_NAME@ клиент за десктоп синхронизация
|
||||
GenericName[bg_BG]=Синхронизиране на папката
|
||||
Name[bg_BG]=@APPLICATION_NAME@ клиент десктоп синхронизация
|
||||
Icon[bg_BG]=@APPLICATION_EXECUTABLE@
|
||||
GenericName[fa]=همسان سازی پوشهها
|
||||
Name[fa]=@APPLICATION_EXECUTABLE@ نسخهی همسان سازی مشتری
|
||||
Icon[fa]=@APPLICATION_EXECUTABLE@
|
||||
Comment[fr]=@APPLICATION_NAME@ synchronisation du client
|
||||
GenericName[fr]=Dossier de Synchronisation
|
||||
Name[fr]=@APPLICATION_NAME@ synchronisation du client
|
||||
|
@ -691,6 +789,10 @@ Comment[he]=@APPLICATION_NAME@ לקוח סנכון שולחן עבודה
|
|||
GenericName[he]=סנכון תיקייה
|
||||
Name[he]=@APPLICATION_NAME@ לקוח סנכרון שולחן עבודה
|
||||
Icon[he]=@APPLICATION_EXECUTABLE@
|
||||
Comment[ia]=@APPLICATION_NAME@ cliente de synchronisation pro scriptorio
|
||||
GenericName[ia]=Synchronisar Dossier
|
||||
Name[ia]=@APPLICATION_NAME@ cliente de synchronisation pro scriptorio
|
||||
Icon[ia]=@APPLICATION_EXECUTABLE@
|
||||
Comment[id]=Klien sinkronisasi desktop @APPLICATION_NAME@
|
||||
GenericName[id]=Folder Sync
|
||||
Name[id]=Klien sync desktop @APPLICATION_NAME@
|
||||
|
@ -718,10 +820,10 @@ Comment[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
|||
GenericName[et_EE]=Kaustade sünkroonimine
|
||||
Name[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
||||
Icon[et_EE]=@APPLICATION_EXECUTABLE@
|
||||
Comment[bg_BG]=@APPLICATION_NAME@ клиент за десктоп синхронизация
|
||||
GenericName[bg_BG]=Синхронизиране на папката
|
||||
Name[bg_BG]=@APPLICATION_NAME@ клиент десктоп синхронизация
|
||||
Icon[bg_BG]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
GenericName[pl]=Folder Synchronizacji
|
||||
Name[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
Icon[pl]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pt_BR]=@APPLICATION_NAME@ cliente de sincronização do computador
|
||||
GenericName[pt_BR]=Sincronização de Pasta
|
||||
Name[pt_BR]=@APPLICATION_NAME@ cliente de sincronização de desktop
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# TODO: OSX and LIB_ONLY seem to require this to go to binary dir only
|
||||
if(NOT TOKEN_AUTH_ONLY)
|
||||
endif()
|
||||
set(BIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
set(synclib_NAME ${APPLICATION_EXECUTABLE}sync)
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
project(cmd)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
|
||||
set(cmd_NAME ${APPLICATION_EXECUTABLE}cmd)
|
||||
set(cmd_SRC
|
||||
cmd.cpp
|
||||
|
|
|
@ -3,8 +3,6 @@ set(CMAKE_AUTOMOC TRUE)
|
|||
|
||||
add_subdirectory(updater)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
|
||||
#TODO Move resources files
|
||||
qt_add_resources(MIRALL_RC_SRC ../../client.qrc)
|
||||
if ( IS_DIRECTORY ${OEM_THEME_DIR} )
|
||||
|
|
|
@ -46,11 +46,17 @@ AccountManager *AccountManager::instance()
|
|||
bool AccountManager::restore()
|
||||
{
|
||||
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
||||
if (settings->status() != QSettings::NoError) {
|
||||
qDebug() << "Could not read settings from" << settings->fileName()
|
||||
<< settings->status();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there are no accounts, check the old format.
|
||||
if (settings->childGroups().isEmpty()
|
||||
&& !settings->contains(QLatin1String(versionC))) {
|
||||
return restoreFromLegacySettings();
|
||||
restoreFromLegacySettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (const auto& accountId, settings->childGroups()) {
|
||||
|
@ -69,6 +75,9 @@ bool AccountManager::restore()
|
|||
|
||||
bool AccountManager::restoreFromLegacySettings()
|
||||
{
|
||||
qDebug() << "Migrate: restoreFromLegacySettings, checking settings group"
|
||||
<< Theme::instance()->appName();
|
||||
|
||||
// try to open the correctly themed settings
|
||||
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
||||
|
||||
|
@ -86,7 +95,7 @@ bool AccountManager::restoreFromLegacySettings()
|
|||
|
||||
QFileInfo fi( oCCfgFile );
|
||||
if( fi.isReadable() ) {
|
||||
QSettings *oCSettings = new QSettings(oCCfgFile, QSettings::IniFormat);
|
||||
std::unique_ptr<QSettings> oCSettings(new QSettings(oCCfgFile, QSettings::IniFormat));
|
||||
oCSettings->beginGroup(QLatin1String("ownCloud"));
|
||||
|
||||
// Check the theme url to see if it is the same url that the oC config was for
|
||||
|
@ -101,9 +110,7 @@ bool AccountManager::restoreFromLegacySettings()
|
|||
qDebug() << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
|
||||
<< (oCUrl == overrideUrl ? "Yes" : "No");
|
||||
if( oCUrl == overrideUrl ) {
|
||||
settings.reset( oCSettings );
|
||||
} else {
|
||||
delete oCSettings;
|
||||
settings = std::move(oCSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,8 +203,8 @@ void AccountManager::saveAccountHelper(Account* acc, QSettings& settings, bool s
|
|||
if (acc->_am) {
|
||||
CookieJar* jar = qobject_cast<CookieJar*>(acc->_am->cookieJar());
|
||||
if (jar) {
|
||||
qDebug() << "Saving cookies.";
|
||||
jar->save();
|
||||
qDebug() << "Saving cookies." << acc->cookieJarPath();
|
||||
jar->save(acc->cookieJarPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,6 +296,8 @@ void AccountManager::deleteAccount(AccountState* account)
|
|||
auto copy = *it; // keep a reference to the shared pointer so it does not delete it just yet
|
||||
_accounts.erase(it);
|
||||
|
||||
QFile::remove(account->account()->cookieJarPath());
|
||||
|
||||
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
||||
settings->remove(account->account()->id());
|
||||
|
||||
|
|
|
@ -36,7 +36,9 @@ public:
|
|||
|
||||
/**
|
||||
* Creates account objects from a given settings file.
|
||||
* return true if the account was restored
|
||||
*
|
||||
* Returns false if there was an error reading the settings,
|
||||
* but note that settings not existing is not an error.
|
||||
*/
|
||||
bool restore();
|
||||
|
||||
|
|
|
@ -675,8 +675,13 @@ void AccountSettings::refreshSelectiveSyncStatus()
|
|||
ui->selectiveSyncButtons->setVisible(true);
|
||||
ui->bigFolderUi->setVisible(false);
|
||||
} else {
|
||||
QString wholeMsg = tr("There are new folders that were not synchronized because they are too big: ") + msg;
|
||||
ui->selectiveSyncNotification->setText(wholeMsg);
|
||||
ConfigFile cfg;
|
||||
QString info =
|
||||
!cfg.confirmExternalStorage() ? tr("There are folders that were not synchronized because they are too big: ") :
|
||||
!cfg.newBigFolderSizeLimit().first ? tr("There are folders that were not synchronized because they are external storages: ") :
|
||||
tr("There are folders that were not synchronized because they are too big or external storages: ");
|
||||
|
||||
ui->selectiveSyncNotification->setText(info + msg);
|
||||
ui->selectiveSyncButtons->setVisible(false);
|
||||
ui->bigFolderUi->setVisible(true);
|
||||
shouldBeVisible = true;
|
||||
|
|
|
@ -156,7 +156,23 @@ Application::Application(int &argc, char **argv) :
|
|||
|
||||
connect(this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseMessage(QString, QObject*)));
|
||||
|
||||
AccountManager::instance()->restore();
|
||||
if (!AccountManager::instance()->restore()) {
|
||||
// If there is an error reading the account settings, try again
|
||||
// after a couple of seconds, if that fails, give up.
|
||||
// (non-existence is not an error)
|
||||
Utility::sleep(5);
|
||||
if (!AccountManager::instance()->restore()) {
|
||||
qDebug() << "Could not read the account settings, quitting";
|
||||
QMessageBox::critical(
|
||||
0,
|
||||
tr("Error accessing the configuration file"),
|
||||
tr("There was an error while accessing the configuration "
|
||||
"file at %1.").arg(ConfigFile().configFile()),
|
||||
tr("Quit ownCloud"));
|
||||
QTimer::singleShot(0, qApp, SLOT(quit()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FolderMan::instance()->setSyncEnabled(true);
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ void ShibbolethCredentials::fetchFromKeychain()
|
|||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||
job->start();
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie)
|
|||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
// we don't really care if it works...
|
||||
//connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
job->setTextData(QString::fromUtf8(cookie.toRawForm()));
|
||||
job->start();
|
||||
}
|
||||
|
@ -318,7 +318,7 @@ void ShibbolethCredentials::removeShibCookie()
|
|||
{
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
|
|
@ -52,9 +52,7 @@ Folder::Folder(const FolderDefinition& definition,
|
|||
: QObject(parent)
|
||||
, _accountState(accountState)
|
||||
, _definition(definition)
|
||||
, _csyncError(false)
|
||||
, _csyncUnavail(false)
|
||||
, _wipeDb(false)
|
||||
, _proxyDirty(true)
|
||||
, _lastSyncDuration(0)
|
||||
, _consecutiveFailingSyncs(0)
|
||||
|
@ -87,8 +85,6 @@ Folder::Folder(const FolderDefinition& definition,
|
|||
|
||||
connect(_accountState.data(), SIGNAL(isConnectedChanged()), this, SIGNAL(canSyncChanged()));
|
||||
connect(_engine.data(), SIGNAL(rootEtag(QString)), this, SLOT(etagRetreivedFromSyncEngine(QString)));
|
||||
connect(_engine.data(), SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
||||
|
||||
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
|
||||
connect(_engine.data(), SIGNAL(finished(bool)), SLOT(slotSyncFinished(bool)), Qt::QueuedConnection);
|
||||
|
@ -102,9 +98,10 @@ Folder::Folder(const FolderDefinition& definition,
|
|||
SLOT(slotAboutToRestoreBackup(bool*)));
|
||||
connect(_engine.data(), SIGNAL(folderDiscovered(bool,QString)), this, SLOT(slotFolderDiscovered(bool,QString)));
|
||||
connect(_engine.data(), SIGNAL(transmissionProgress(ProgressInfo)), this, SLOT(slotTransmissionProgress(ProgressInfo)));
|
||||
connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_engine.data(), SIGNAL(newBigFolder(QString)), this, SLOT(slotNewBigFolderDiscovered(QString)));
|
||||
connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItemPtr &)));
|
||||
connect(_engine.data(), SIGNAL(newBigFolder(QString,bool)),
|
||||
this, SLOT(slotNewBigFolderDiscovered(QString,bool)));
|
||||
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
|
||||
connect(_engine.data(), SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
||||
SLOT(slotLogPropagationStart()));
|
||||
|
@ -138,13 +135,13 @@ void Folder::checkLocalPath()
|
|||
} else {
|
||||
// Check directory again
|
||||
if( !FileSystem::fileExists(_definition.localPath, fi) ) {
|
||||
_syncResult.setErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
} else if( !fi.isDir() ) {
|
||||
_syncResult.setErrorString(tr("%1 should be a folder but is not.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("%1 should be a folder but is not.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
} else if( !fi.isReadable() ) {
|
||||
_syncResult.setErrorString(tr("%1 is not readable.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("%1 is not readable.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
}
|
||||
}
|
||||
|
@ -267,8 +264,8 @@ SyncResult Folder::syncResult() const
|
|||
|
||||
void Folder::prepareToSync()
|
||||
{
|
||||
_syncResult.reset();
|
||||
_syncResult.setStatus( SyncResult::NotYetStarted );
|
||||
_syncResult.clearErrors();
|
||||
}
|
||||
|
||||
void Folder::slotRunEtagJob()
|
||||
|
@ -322,120 +319,33 @@ void Folder::etagRetreivedFromSyncEngine(const QString& etag)
|
|||
}
|
||||
|
||||
|
||||
void Folder::bubbleUpSyncResult()
|
||||
void Folder::showSyncResultPopup()
|
||||
{
|
||||
// count new, removed and updated items
|
||||
int newItems = 0;
|
||||
int removedItems = 0;
|
||||
int updatedItems = 0;
|
||||
int ignoredItems = 0;
|
||||
int renamedItems = 0;
|
||||
int conflictItems = 0;
|
||||
int errorItems = 0;
|
||||
|
||||
SyncFileItemPtr firstItemNew;
|
||||
SyncFileItemPtr firstItemDeleted;
|
||||
SyncFileItemPtr firstItemUpdated;
|
||||
SyncFileItemPtr firstItemRenamed;
|
||||
SyncFileItemPtr firstConflictItem;
|
||||
SyncFileItemPtr firstItemError;
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
foreach (const SyncFileItemPtr &item, _syncResult.syncFileItemVector() ) {
|
||||
// Process the item to the gui
|
||||
if( item->_status == SyncFileItem::FatalError || item->_status == SyncFileItem::NormalError ) {
|
||||
//: this displays an error string (%2) for a file %1
|
||||
slotSyncError( tr("%1: %2").arg(item->_file, item->_errorString) );
|
||||
errorItems++;
|
||||
if (!firstItemError) {
|
||||
firstItemError = item;
|
||||
}
|
||||
} else if( item->_status == SyncFileItem::FileIgnored ) {
|
||||
// ignored files don't show up in notifications
|
||||
continue;
|
||||
} else if( item->_status == SyncFileItem::Conflict ) {
|
||||
conflictItems++;
|
||||
if (!firstConflictItem) {
|
||||
firstConflictItem = item;
|
||||
}
|
||||
} else {
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NEW ) {
|
||||
FolderMan::instance()->addMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_REMOVE ) {
|
||||
FolderMan::instance()->removeMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
|
||||
if (!item->hasErrorStatus() && item->_direction == SyncFileItem::Down) {
|
||||
switch (item->_instruction) {
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
case CSYNC_INSTRUCTION_TYPE_CHANGE:
|
||||
newItems++;
|
||||
if (!firstItemNew)
|
||||
firstItemNew = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
removedItems++;
|
||||
if (!firstItemDeleted)
|
||||
firstItemDeleted = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_SYNC:
|
||||
updatedItems++;
|
||||
if (!firstItemUpdated)
|
||||
firstItemUpdated = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_ERROR:
|
||||
qDebug() << "Got Instruction ERROR. " << _syncResult.errorString();
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
if (!firstItemRenamed) {
|
||||
firstItemRenamed = item;
|
||||
}
|
||||
renamedItems++;
|
||||
break;
|
||||
default:
|
||||
// nothing.
|
||||
break;
|
||||
}
|
||||
} else if( item->_direction == SyncFileItem::None ) { // ignored files counting.
|
||||
if( item->_instruction == CSYNC_INSTRUCTION_IGNORE ) {
|
||||
ignoredItems++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( _syncResult.firstItemNew() ) {
|
||||
createGuiLog( _syncResult.firstItemNew()->_file, LogStatusNew, _syncResult.numNewItems() );
|
||||
}
|
||||
if( _syncResult.firstItemDeleted() ) {
|
||||
createGuiLog( _syncResult.firstItemDeleted()->_file, LogStatusRemove, _syncResult.numRemovedItems() );
|
||||
}
|
||||
if( _syncResult.firstItemUpdated() ) {
|
||||
createGuiLog( _syncResult.firstItemUpdated()->_file, LogStatusUpdated, _syncResult.numUpdatedItems() );
|
||||
}
|
||||
|
||||
qDebug() << "Processing result list and logging took " << timer.elapsed() << " Milliseconds.";
|
||||
_syncResult.setWarnCount(ignoredItems);
|
||||
|
||||
if( firstItemNew ) {
|
||||
createGuiLog( firstItemNew->_file, LogStatusNew, newItems );
|
||||
}
|
||||
if( firstItemDeleted ) {
|
||||
createGuiLog( firstItemDeleted->_file, LogStatusRemove, removedItems );
|
||||
}
|
||||
if( firstItemUpdated ) {
|
||||
createGuiLog( firstItemUpdated->_file, LogStatusUpdated, updatedItems );
|
||||
}
|
||||
|
||||
if( firstItemRenamed ) {
|
||||
if( _syncResult.firstItemRenamed() ) {
|
||||
LogStatus status(LogStatusRename);
|
||||
// if the path changes it's rather a move
|
||||
QDir renTarget = QFileInfo(firstItemRenamed->_renameTarget).dir();
|
||||
QDir renSource = QFileInfo(firstItemRenamed->_file).dir();
|
||||
QDir renTarget = QFileInfo(_syncResult.firstItemRenamed()->_renameTarget).dir();
|
||||
QDir renSource = QFileInfo(_syncResult.firstItemRenamed()->_file).dir();
|
||||
if(renTarget != renSource) {
|
||||
status = LogStatusMove;
|
||||
}
|
||||
createGuiLog( firstItemRenamed->_originalFile, status, renamedItems, firstItemRenamed->_renameTarget );
|
||||
createGuiLog( _syncResult.firstItemRenamed()->_originalFile, status, _syncResult.numRenamedItems(), _syncResult.firstItemRenamed()->_renameTarget );
|
||||
}
|
||||
|
||||
if( firstConflictItem ) {
|
||||
createGuiLog( firstConflictItem->_file, LogStatusConflict, conflictItems );
|
||||
if( _syncResult.firstConflictItem() ) {
|
||||
createGuiLog( _syncResult.firstConflictItem()->_file, LogStatusConflict, _syncResult.numConflictItems() );
|
||||
}
|
||||
createGuiLog( firstItemError->_file, LogStatusError, errorItems );
|
||||
createGuiLog( _syncResult.firstItemError()->_file, LogStatusError, _syncResult.numErrorItems() );
|
||||
|
||||
qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status());
|
||||
}
|
||||
|
@ -574,12 +484,6 @@ void Folder::slotWatchedPathChanged(const QString& path)
|
|||
scheduleThisFolderSoon();
|
||||
}
|
||||
|
||||
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||
{
|
||||
_syncResult.setSyncFileItemVector(items);
|
||||
}
|
||||
|
||||
|
||||
void Folder::saveToSettings() const
|
||||
{
|
||||
// Remove first to make sure we don't get duplicates
|
||||
|
@ -642,9 +546,6 @@ void Folder::slotTerminateSync()
|
|||
if( _engine->isSyncRunning() ) {
|
||||
_engine->abort();
|
||||
|
||||
// Do not display an error message, user knows his own actions.
|
||||
// _errors.append( tr("The CSync thread terminated.") );
|
||||
// _csyncError = true;
|
||||
setSyncState(SyncResult::SyncAbortRequested);
|
||||
}
|
||||
}
|
||||
|
@ -692,10 +593,9 @@ bool Folder::setIgnoredFiles()
|
|||
// a QSet of files to load.
|
||||
ConfigFile cfg;
|
||||
QString systemList = cfg.excludeFile(ConfigFile::SystemScope);
|
||||
if( QFile::exists(systemList) ) {
|
||||
qDebug() << "==== adding system ignore list to csync:" << systemList;
|
||||
_engine->excludedFiles().addExcludeFilePath(systemList);
|
||||
}
|
||||
qDebug() << "==== adding system ignore list to csync:" << systemList;
|
||||
_engine->excludedFiles().addExcludeFilePath(systemList);
|
||||
|
||||
QString userList = cfg.excludeFile(ConfigFile::UserScope);
|
||||
if( QFile::exists(userList) ) {
|
||||
qDebug() << "==== adding user defined ignore list to csync:" << userList;
|
||||
|
@ -726,19 +626,17 @@ void Folder::startSync(const QStringList &pathList)
|
|||
qCritical() << "* ERROR csync is still running and new sync requested.";
|
||||
return;
|
||||
}
|
||||
_errors.clear();
|
||||
_csyncError = false;
|
||||
_csyncUnavail = false;
|
||||
|
||||
_timeSinceLastSyncStart.restart();
|
||||
_syncResult.clearErrors();
|
||||
_syncResult.setStatus( SyncResult::SyncPrepare );
|
||||
_syncResult.setSyncFileItemVector(SyncFileItemVector());
|
||||
emit syncStateChange();
|
||||
|
||||
qDebug() << "*** Start syncing " << remoteUrl().toString() << " - client version"
|
||||
<< qPrintable(Theme::instance()->version());
|
||||
|
||||
_fileLog->start(path());
|
||||
|
||||
if (!setIgnoredFiles())
|
||||
{
|
||||
slotSyncError(tr("Could not read system exclude file"));
|
||||
|
@ -748,15 +646,15 @@ void Folder::startSync(const QStringList &pathList)
|
|||
|
||||
setDirtyNetworkLimits();
|
||||
|
||||
SyncOptions opt;
|
||||
ConfigFile cfgFile;
|
||||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
||||
quint64 limit = newFolderLimit.first ? newFolderLimit.second * 1000 * 1000 : -1; // convert from MB to B
|
||||
_engine->setNewBigFolderSizeLimit(limit);
|
||||
opt._newBigFolderSizeLimit = newFolderLimit.first ? newFolderLimit.second * 1000LL * 1000LL : -1; // convert from MB to B
|
||||
opt._confirmExternalStorage = cfgFile.confirmExternalStorage();
|
||||
_engine->setSyncOptions(opt);
|
||||
|
||||
_engine->setIgnoreHiddenFiles(_definition.ignoreHiddenFiles);
|
||||
|
||||
_fileLog->start(path());
|
||||
|
||||
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
|
||||
|
||||
emit syncStarted();
|
||||
|
@ -787,8 +685,7 @@ void Folder::setDirtyNetworkLimits()
|
|||
|
||||
void Folder::slotSyncError(const QString& err)
|
||||
{
|
||||
_errors.append( err );
|
||||
_csyncError = true;
|
||||
_syncResult.appendErrorString(err);
|
||||
}
|
||||
|
||||
void Folder::slotSyncStarted()
|
||||
|
@ -810,29 +707,26 @@ void Folder::slotSyncFinished(bool success)
|
|||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
<< " SSL " << QSslSocket::sslLibraryVersionString().toUtf8().data()
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
|
||||
if( _csyncError ) {
|
||||
qDebug() << "-> SyncEngine finished with ERROR, warn count is" << _syncResult.warnCount();
|
||||
bool syncError = !_syncResult.errorStrings().isEmpty();
|
||||
if( syncError ) {
|
||||
qDebug() << "-> SyncEngine finished with ERROR";
|
||||
} else {
|
||||
qDebug() << "-> SyncEngine finished without problem.";
|
||||
}
|
||||
_fileLog->finish();
|
||||
bubbleUpSyncResult();
|
||||
showSyncResultPopup();
|
||||
|
||||
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
||||
|
||||
if (_csyncError) {
|
||||
if (syncError) {
|
||||
_syncResult.setStatus(SyncResult::Error);
|
||||
qDebug() << " ** error Strings: " << _errors;
|
||||
_syncResult.setErrorStrings( _errors );
|
||||
qDebug() << " * owncloud csync thread finished with error";
|
||||
} else if (_csyncUnavail) {
|
||||
_syncResult.setStatus(SyncResult::Error);
|
||||
qDebug() << " ** csync not available.";
|
||||
} else if( _syncResult.warnCount() > 0 ) {
|
||||
// there have been warnings on the way.
|
||||
} else if( _syncResult.foundFilesNotSynced() ) {
|
||||
_syncResult.setStatus(SyncResult::Problem);
|
||||
} else if( _definition.paused ) {
|
||||
// Maybe the sync was terminated because the user paused the folder
|
||||
|
@ -909,26 +803,28 @@ void Folder::slotFolderDiscovered(bool, QString folderName)
|
|||
// and hand the result over to the progress dispatcher.
|
||||
void Folder::slotTransmissionProgress(const ProgressInfo &pi)
|
||||
{
|
||||
if( !pi.isUpdatingEstimates() ) {
|
||||
// this is the beginning of a sync, set the warning level to 0
|
||||
_syncResult.setWarnCount(0);
|
||||
}
|
||||
emit progressInfo(pi);
|
||||
ProgressDispatcher::instance()->setProgressInfo(alias(), pi);
|
||||
}
|
||||
|
||||
// a item is completed: count the errors and forward to the ProgressDispatcher
|
||||
void Folder::slotItemCompleted(const SyncFileItem &item, const PropagatorJob& job)
|
||||
void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
{
|
||||
if (Progress::isWarningKind(item._status)) {
|
||||
// Count all error conditions.
|
||||
_syncResult.setWarnCount(_syncResult.warnCount()+1);
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NEW ) {
|
||||
FolderMan::instance()->addMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
_fileLog->logItem(item);
|
||||
emit ProgressDispatcher::instance()->itemCompleted(alias(), item, job);
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_REMOVE ) {
|
||||
FolderMan::instance()->removeMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
|
||||
_syncResult.processCompletedItem(item);
|
||||
|
||||
_fileLog->logItem(*item);
|
||||
emit ProgressDispatcher::instance()->itemCompleted(alias(), item);
|
||||
}
|
||||
|
||||
void Folder::slotNewBigFolderDiscovered(const QString &newF)
|
||||
void Folder::slotNewBigFolderDiscovered(const QString &newF, bool isExternal)
|
||||
{
|
||||
auto newFolder = newF;
|
||||
if (!newFolder.endsWith(QLatin1Char('/'))) {
|
||||
|
@ -953,9 +849,11 @@ void Folder::slotNewBigFolderDiscovered(const QString &newF)
|
|||
journal->setSelectiveSyncList(SyncJournalDb::SelectiveSyncUndecidedList, undecidedList);
|
||||
emit newBigFolderDiscovered(newFolder);
|
||||
}
|
||||
QString message = tr("A new folder larger than %1 MB has been added: %2.\n"
|
||||
"Please go in the settings to select it if you wish to download it.")
|
||||
.arg(ConfigFile().newBigFolderSizeLimit().second).arg(newF);
|
||||
QString message = !isExternal ?
|
||||
(tr("A new folder larger than %1 MB has been added: %2.\n")
|
||||
.arg(ConfigFile().newBigFolderSizeLimit().second).arg(newF))
|
||||
: (tr("A folder from an external storage has been added.\n"));
|
||||
message += tr("Please go in the settings to select it if you wish to download it.");
|
||||
|
||||
auto logger = Logger::instance();
|
||||
logger->postOptionalGuiLog(Theme::instance()->appNameGUI(), message);
|
||||
|
@ -984,19 +882,25 @@ void Folder::setSaveBackwardsCompatible(bool save)
|
|||
_saveBackwardsCompatible = save;
|
||||
}
|
||||
|
||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
|
||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel)
|
||||
{
|
||||
ConfigFile cfgFile;
|
||||
if (!cfgFile.promptDeleteFiles())
|
||||
return;
|
||||
|
||||
QString msg =
|
||||
tr("This sync would remove all the files in the sync folder '%1'.\n"
|
||||
"This might be because the folder was silently reconfigured, or that all "
|
||||
"the files were manually removed.\n"
|
||||
"Are you sure you want to perform this operation?");
|
||||
QString msg = dir == SyncFileItem::Down ?
|
||||
tr("All files in the sync folder '%1' folder were deleted on the server.\n"
|
||||
"These deletes will be synchronized to your local sync folder, making such files "
|
||||
"unavailable unless you have a right to restore. \n"
|
||||
"If you decide to keep the files, they will be re-synced with the server if you have rights to do so.\n"
|
||||
"If you decide to delete the files, they will be unavailable to you, unless you are the owner.") :
|
||||
tr("All the files in your local sync folder '%1' were deleted. These deletes will be "
|
||||
"synchronized with your server, making such files unavailable unless restored.\n"
|
||||
"Are you sure you want to sync those actions with the server?\n"
|
||||
"If this was an accident and you decide to keep your files, they will be re-synced from the server.");
|
||||
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
|
||||
msg.arg(shortGuiLocalPath()));
|
||||
msgBox.setWindowFlags(msgBox.windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
|
||||
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::AcceptRole);
|
||||
if (msgBox.exec() == -1) {
|
||||
|
@ -1005,7 +909,7 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
|
|||
}
|
||||
*cancel = msgBox.clickedButton() == keepBtn;
|
||||
if (*cancel) {
|
||||
wipe();
|
||||
journalDb()->clearFileTable();
|
||||
_lastEtag.clear();
|
||||
slotScheduleThisFolder();
|
||||
}
|
||||
|
@ -1021,6 +925,7 @@ void Folder::slotAboutToRestoreBackup(bool *restore)
|
|||
"Do you want to keep your local most recent files as conflict files?");
|
||||
QMessageBox msgBox(QMessageBox::Warning, tr("Backup detected"),
|
||||
msg.arg(shortGuiLocalPath()));
|
||||
msgBox.setWindowFlags(msgBox.windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
msgBox.addButton(tr("Normal Synchronisation"), QMessageBox::DestructiveRole);
|
||||
QPushButton* keepBtn = msgBox.addButton(tr("Keep Local Files as Conflict"), QMessageBox::AcceptRole);
|
||||
|
||||
|
|
|
@ -280,17 +280,15 @@ private slots:
|
|||
|
||||
void slotFolderDiscovered(bool local, QString folderName);
|
||||
void slotTransmissionProgress(const ProgressInfo& pi);
|
||||
void slotItemCompleted(const SyncFileItem&, const PropagatorJob&);
|
||||
void slotItemCompleted(const SyncFileItemPtr&);
|
||||
|
||||
void slotRunEtagJob();
|
||||
void etagRetreived(const QString &);
|
||||
void etagRetreivedFromSyncEngine(const QString &);
|
||||
|
||||
void slotThreadTreeWalkResult(const SyncFileItemVector& ); // after sync is done
|
||||
|
||||
void slotEmitFinishedDelayed();
|
||||
|
||||
void slotNewBigFolderDiscovered(const QString &);
|
||||
void slotNewBigFolderDiscovered(const QString &, bool isExternal);
|
||||
|
||||
void slotLogPropagationStart();
|
||||
|
||||
|
@ -302,7 +300,7 @@ private slots:
|
|||
private:
|
||||
bool setIgnoredFiles();
|
||||
|
||||
void bubbleUpSyncResult();
|
||||
void showSyncResultPopup();
|
||||
|
||||
void checkLocalPath();
|
||||
|
||||
|
@ -325,10 +323,7 @@ private:
|
|||
|
||||
SyncResult _syncResult;
|
||||
QScopedPointer<SyncEngine> _engine;
|
||||
QStringList _errors;
|
||||
bool _csyncError;
|
||||
bool _csyncUnavail;
|
||||
bool _wipeDb;
|
||||
bool _proxyDirty;
|
||||
QPointer<RequestEtagJob> _requestEtagJob;
|
||||
QString _lastEtag;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "accountmanager.h"
|
||||
#include "filesystem.h"
|
||||
#include "lockwatcher.h"
|
||||
#include "asserts.h"
|
||||
#include <syncengine.h>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
|
@ -48,7 +49,7 @@ FolderMan::FolderMan(QObject *parent) :
|
|||
_lockWatcher(new LockWatcher),
|
||||
_appRestartRequired(false)
|
||||
{
|
||||
Q_ASSERT(!_instance);
|
||||
ASSERT(!_instance);
|
||||
_instance = this;
|
||||
|
||||
_socketApi.reset(new SocketApi);
|
||||
|
@ -133,12 +134,13 @@ int FolderMan::unloadAndDeleteAllFolders()
|
|||
delete f;
|
||||
cnt++;
|
||||
}
|
||||
ASSERT(_folderMap.isEmpty());
|
||||
|
||||
_lastSyncFolder = 0;
|
||||
_currentSyncFolder = 0;
|
||||
_scheduledFolders.clear();
|
||||
emit scheduleQueueChanged();
|
||||
|
||||
Q_ASSERT(_folderMap.count() == 0);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
@ -260,7 +262,6 @@ int FolderMan::setupFoldersMigration()
|
|||
{
|
||||
ConfigFile cfg;
|
||||
QDir storageDir(cfg.configPath());
|
||||
storageDir.mkpath(QLatin1String("folders"));
|
||||
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
|
||||
|
||||
qDebug() << "* Setup folders from " << _folderConfigPath << "(migration)";
|
||||
|
@ -463,7 +464,7 @@ void FolderMan::slotFolderSyncPaused( Folder *f, bool paused )
|
|||
void FolderMan::slotFolderCanSyncChanged()
|
||||
{
|
||||
Folder *f = qobject_cast<Folder*>(sender());
|
||||
Q_ASSERT(f);
|
||||
ASSERT(f);
|
||||
if (f->canSync()) {
|
||||
_socketApi->slotRegisterPath(f->alias());
|
||||
} else {
|
||||
|
@ -1121,7 +1122,7 @@ void FolderMan::setDirtyNetworkLimits()
|
|||
|
||||
SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
||||
{
|
||||
SyncResult overallResult(SyncResult::Undefined);
|
||||
SyncResult overallResult;
|
||||
|
||||
int cnt = folders.count();
|
||||
|
||||
|
@ -1235,10 +1236,10 @@ SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
|||
return overallResult;
|
||||
}
|
||||
|
||||
QString FolderMan::statusToString( SyncResult syncStatus, bool paused ) const
|
||||
QString FolderMan::statusToString( SyncResult::Status syncStatus, bool paused ) const
|
||||
{
|
||||
QString folderMessage;
|
||||
switch( syncStatus.status() ) {
|
||||
switch( syncStatus ) {
|
||||
case SyncResult::Undefined:
|
||||
folderMessage = tr( "Undefined State." );
|
||||
break;
|
||||
|
|
|
@ -106,7 +106,7 @@ public:
|
|||
/** Creates a new and empty local directory. */
|
||||
bool startFromScratch( const QString& );
|
||||
|
||||
QString statusToString(SyncResult, bool paused ) const;
|
||||
QString statusToString(SyncResult::Status, bool paused ) const;
|
||||
|
||||
static SyncResult accountStatus( const QList<Folder*> &folders );
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "folderman.h"
|
||||
#include "accountstate.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
#include <theme.h>
|
||||
#include <account.h>
|
||||
#include "folderstatusdelegate.h"
|
||||
|
@ -29,6 +30,14 @@ Q_DECLARE_METATYPE(QPersistentModelIndex)
|
|||
namespace OCC {
|
||||
|
||||
static const char propertyParentIndexC[] = "oc_parentIndex";
|
||||
static const char propertyPermissionMap[] = "oc_permissionMap";
|
||||
|
||||
static QString removeTrailingSlash(const QString &s) {
|
||||
if (s.endsWith('/')) {
|
||||
return s.left(s.size() - 1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
FolderStatusModel::FolderStatusModel(QObject *parent)
|
||||
:QAbstractItemModel(parent), _accountState(0), _dirty(false)
|
||||
|
@ -162,7 +171,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
|||
case Qt::CheckStateRole:
|
||||
return x._checked;
|
||||
case Qt::DecorationRole:
|
||||
return QFileIconProvider().icon(QFileIconProvider::Folder);
|
||||
return QFileIconProvider().icon(x._isExternal ? QFileIconProvider::Network : QFileIconProvider::Folder);
|
||||
case Qt::ForegroundRole:
|
||||
if (x._isUndecided) {
|
||||
return QColor(Qt::red);
|
||||
|
@ -368,6 +377,9 @@ FolderStatusModel::SubFolderInfo* FolderStatusModel::infoForIndex(const QModelIn
|
|||
if (parentInfo->hasLabel()) {
|
||||
return 0;
|
||||
}
|
||||
if (index.row() >= parentInfo->_subs.size()) {
|
||||
return 0;
|
||||
}
|
||||
return &parentInfo->_subs[index.row()];
|
||||
} else {
|
||||
if (index.row() >= _folders.count()) {
|
||||
|
@ -469,14 +481,14 @@ QModelIndex FolderStatusModel::parent(const QModelIndex& child) const
|
|||
}
|
||||
auto pathIdx = static_cast<SubFolderInfo*>(child.internalPointer())->_pathIdx;
|
||||
int i = 1;
|
||||
Q_ASSERT(pathIdx.at(0) < _folders.count());
|
||||
ASSERT(pathIdx.at(0) < _folders.count());
|
||||
if (pathIdx.count() == 1) {
|
||||
return createIndex(pathIdx.at(0), 0/*, nullptr*/);
|
||||
}
|
||||
|
||||
const SubFolderInfo *info = &_folders[pathIdx.at(0)];
|
||||
while (i < pathIdx.count() - 1) {
|
||||
Q_ASSERT(pathIdx.at(i) < info->_subs.count());
|
||||
ASSERT(pathIdx.at(i) < info->_subs.count());
|
||||
info = &info->_subs[pathIdx.at(i)];
|
||||
++i;
|
||||
}
|
||||
|
@ -537,12 +549,15 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
|||
path += info->_path;
|
||||
}
|
||||
LsColJob *job = new LsColJob(_accountState->account(), path, this);
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size" << "http://owncloud.org/ns:permissions");
|
||||
job->setTimeout(60 * 1000);
|
||||
connect(job, SIGNAL(directoryListingSubfolders(QStringList)),
|
||||
SLOT(slotUpdateDirectories(QStringList)));
|
||||
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
||||
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
||||
connect(job, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||
this, SLOT(slotGatherPermissions(const QString&, const QMap<QString,QString>&)));
|
||||
|
||||
job->start();
|
||||
|
||||
QPersistentModelIndex persistentIndex(parent);
|
||||
|
@ -553,10 +568,24 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
|||
QTimer::singleShot(1000, this, SLOT(slotShowFetchProgress()));
|
||||
}
|
||||
|
||||
void FolderStatusModel::slotGatherPermissions(const QString &href, const QMap<QString,QString> &map)
|
||||
{
|
||||
auto it = map.find("permissions");
|
||||
if (it == map.end())
|
||||
return;
|
||||
|
||||
auto job = sender();
|
||||
auto permissionMap = job->property(propertyPermissionMap).toMap();
|
||||
job->setProperty(propertyPermissionMap, QVariant()); // avoid a detach of the map while it is modified
|
||||
ASSERT(!href.endsWith(QLatin1Char('/')), "LsColXMLParser::parse should remove the trailing slash before calling us.");
|
||||
permissionMap[href] = *it;
|
||||
job->setProperty(propertyPermissionMap, permissionMap);
|
||||
}
|
||||
|
||||
void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
||||
auto parentInfo = infoForIndex(idx);
|
||||
if (!parentInfo) {
|
||||
|
@ -598,6 +627,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
|||
selectiveSyncUndecidedSet.insert(str);
|
||||
}
|
||||
}
|
||||
const auto permissionMap = job->property(propertyPermissionMap).toMap();
|
||||
|
||||
QStringList sortedSubfolders = list;
|
||||
// skip the parent item (first in the list)
|
||||
|
@ -618,8 +648,8 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
|||
newInfo._folder = parentInfo->_folder;
|
||||
newInfo._pathIdx = parentInfo->_pathIdx;
|
||||
newInfo._pathIdx << newSubs.size();
|
||||
auto size = job ? job->_sizes.value(path) : 0;
|
||||
newInfo._size = size;
|
||||
newInfo._size = job->_sizes.value(path);
|
||||
newInfo._isExternal = permissionMap.value(removeTrailingSlash(path)).toString().contains("M");
|
||||
newInfo._path = relativePath;
|
||||
newInfo._name = relativePath.split('/', QString::SkipEmptyParts).last();
|
||||
|
||||
|
@ -686,7 +716,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
|||
void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
||||
if (!idx.isValid()) {
|
||||
return;
|
||||
|
@ -701,7 +731,7 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
|||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||
parentInfo->_fetched = true;
|
||||
} else {
|
||||
Q_ASSERT(!parentInfo->hasLabel());
|
||||
ASSERT(!parentInfo->hasLabel());
|
||||
beginInsertRows(idx, 0, 0);
|
||||
parentInfo->_hasError = true;
|
||||
endInsertRows();
|
||||
|
@ -981,7 +1011,7 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
|||
auto& pi = _folders[folderIndex]._progress;
|
||||
|
||||
SyncResult::Status state = f->syncResult().status();
|
||||
if (f->syncPaused()) {
|
||||
if (!f->canSync()) {
|
||||
// Reset progress info.
|
||||
pi = SubFolderInfo::Progress();
|
||||
} else if (state == SyncResult::NotYetStarted) {
|
||||
|
@ -1012,18 +1042,10 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
|||
// update the icon etc. now
|
||||
slotUpdateFolderState(f);
|
||||
|
||||
if (state == SyncResult::Success) {
|
||||
foreach (const SyncFileItemPtr &i, f->syncResult().syncFileItemVector()) {
|
||||
if (i->_isDirectory && (i->_instruction == CSYNC_INSTRUCTION_NEW
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_REMOVE
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_RENAME)) {
|
||||
// There is a new or a removed folder. reset all data
|
||||
auto & info = _folders[folderIndex];
|
||||
info.resetSubs(this, index(folderIndex));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (state == SyncResult::Success && f->syncResult().folderStructureWasChanged()) {
|
||||
// There is a new or a removed folder. reset all data
|
||||
auto & info = _folders[folderIndex];
|
||||
info.resetSubs(this, index(folderIndex));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1114,7 +1136,7 @@ void FolderStatusModel::slotSyncNoPendingBigFolders()
|
|||
void FolderStatusModel::slotNewBigFolder()
|
||||
{
|
||||
auto f = qobject_cast<Folder *>(sender());
|
||||
Q_ASSERT(f);
|
||||
ASSERT(f);
|
||||
|
||||
int folderIndex = -1;
|
||||
for (int i = 0; i < _folders.count(); ++i) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
struct SubFolderInfo {
|
||||
SubFolderInfo()
|
||||
: _folder(0), _size(0), _fetched(false), _fetching(false),
|
||||
: _folder(0), _size(0), _isExternal(false), _fetched(false), _fetching(false),
|
||||
_hasError(false), _fetchingLabel(false), _isUndecided(false), _checked(Qt::Checked) {}
|
||||
Folder *_folder;
|
||||
QString _name;
|
||||
|
@ -59,6 +59,7 @@ public:
|
|||
QVector<int> _pathIdx;
|
||||
QVector<SubFolderInfo> _subs;
|
||||
qint64 _size;
|
||||
bool _isExternal;
|
||||
|
||||
bool _fetched; // If we did the LSCOL for this folder already
|
||||
bool _fetching; // Whether a LSCOL job is currently running
|
||||
|
@ -113,6 +114,7 @@ public slots:
|
|||
|
||||
private slots:
|
||||
void slotUpdateDirectories(const QStringList &);
|
||||
void slotGatherPermissions(const QString &name, const QMap<QString,QString> &properties);
|
||||
void slotLscolFinishedWithError(QNetworkReply *r);
|
||||
void slotFolderSyncStateChange(Folder* f);
|
||||
void slotFolderScheduleQueueChanged();
|
||||
|
|
|
@ -482,9 +482,8 @@ void FolderWizardRemotePath::showWarn( const QString& msg ) const
|
|||
FolderWizardSelectiveSync::FolderWizardSelectiveSync(const AccountPtr& account)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
_treeView = new SelectiveSyncTreeView(account, this);
|
||||
layout->addWidget(new QLabel(tr("Choose What to Sync: You can optionally deselect remote subfolders you do not wish to synchronize.")));
|
||||
layout->addWidget(_treeView);
|
||||
_selectiveSync = new SelectiveSyncWidget(account, this);
|
||||
layout->addWidget(_selectiveSync);
|
||||
}
|
||||
|
||||
FolderWizardSelectiveSync::~FolderWizardSelectiveSync()
|
||||
|
@ -501,13 +500,17 @@ void FolderWizardSelectiveSync::initializePage()
|
|||
QString alias = QFileInfo(targetPath).fileName();
|
||||
if (alias.isEmpty())
|
||||
alias = Theme::instance()->appName();
|
||||
_treeView->setFolderInfo(targetPath, alias);
|
||||
QStringList initialBlacklist;
|
||||
if (Theme::instance()->wizardSelectiveSyncDefaultNothing()) {
|
||||
initialBlacklist = QStringList("/");
|
||||
}
|
||||
_selectiveSync->setFolderInfo(targetPath, alias, initialBlacklist);
|
||||
QWizardPage::initializePage();
|
||||
}
|
||||
|
||||
bool FolderWizardSelectiveSync::validatePage()
|
||||
{
|
||||
wizard()->setProperty("selectiveSyncBlackList", QVariant(_treeView->createBlackList()));
|
||||
wizard()->setProperty("selectiveSyncBlackList", QVariant(_selectiveSync->createBlackList()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -517,7 +520,7 @@ void FolderWizardSelectiveSync::cleanupPage()
|
|||
QString alias = QFileInfo(targetPath).fileName();
|
||||
if (alias.isEmpty())
|
||||
alias = Theme::instance()->appName();
|
||||
_treeView->setFolderInfo(targetPath, alias);
|
||||
_selectiveSync->setFolderInfo(targetPath, alias);
|
||||
QWizardPage::cleanupPage();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
namespace OCC {
|
||||
|
||||
class SelectiveSyncTreeView;
|
||||
class SelectiveSyncWidget;
|
||||
|
||||
class ownCloudInfo;
|
||||
|
||||
|
@ -127,7 +127,7 @@ public:
|
|||
virtual void cleanupPage() Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
SelectiveSyncTreeView *_treeView;
|
||||
SelectiveSyncWidget *_selectiveSync;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -32,12 +32,14 @@
|
|||
|
||||
#include <QNetworkProxy>
|
||||
#include <QDir>
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
GeneralSettings::GeneralSettings(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
_ui(new Ui::GeneralSettings)
|
||||
_ui(new Ui::GeneralSettings),
|
||||
_currentlyLoading(false)
|
||||
{
|
||||
_ui->setupUi(this);
|
||||
|
||||
|
@ -66,6 +68,7 @@ GeneralSettings::GeneralSettings(QWidget *parent) :
|
|||
connect(_ui->crashreporterCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||
connect(_ui->newFolderLimitCheckBox, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||
connect(_ui->newFolderLimitSpinBox, SIGNAL(valueChanged(int)), SLOT(saveMiscSettings()));
|
||||
connect(_ui->newExternalStorage, SIGNAL(toggled(bool)), SLOT(saveMiscSettings()));
|
||||
|
||||
#ifndef WITH_CRASHREPORTER
|
||||
_ui->crashreporterCheckBox->setVisible(false);
|
||||
|
@ -85,6 +88,9 @@ GeneralSettings::GeneralSettings(QWidget *parent) :
|
|||
_ui->monoIconsCheckBox->setVisible(QDir(themeDir).exists());
|
||||
|
||||
connect(_ui->ignoredFilesButton, SIGNAL(clicked()), SLOT(slotIgnoreFilesEditor()));
|
||||
|
||||
// accountAdded means the wizard was finished and the wizard might change some options.
|
||||
connect(AccountManager::instance(), SIGNAL(accountAdded(AccountState*)), this, SLOT(loadMiscSettings()));
|
||||
}
|
||||
|
||||
GeneralSettings::~GeneralSettings()
|
||||
|
@ -99,6 +105,12 @@ QSize GeneralSettings::sizeHint() const {
|
|||
|
||||
void GeneralSettings::loadMiscSettings()
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 4, 0 )
|
||||
QScopedValueRollback<bool> scope(_currentlyLoading);
|
||||
_currentlyLoading = true;
|
||||
#else
|
||||
QScopedValueRollback<bool> scope(_currentlyLoading, true);
|
||||
#endif
|
||||
ConfigFile cfgFile;
|
||||
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
||||
_ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications());
|
||||
|
@ -106,6 +118,8 @@ void GeneralSettings::loadMiscSettings()
|
|||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
||||
_ui->newFolderLimitCheckBox->setChecked(newFolderLimit.first);
|
||||
_ui->newFolderLimitSpinBox->setValue(newFolderLimit.second);
|
||||
_ui->newExternalStorage->setChecked(cfgFile.confirmExternalStorage());
|
||||
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
||||
}
|
||||
|
||||
void GeneralSettings::slotUpdateInfo()
|
||||
|
@ -130,6 +144,8 @@ void GeneralSettings::slotUpdateInfo()
|
|||
|
||||
void GeneralSettings::saveMiscSettings()
|
||||
{
|
||||
if (_currentlyLoading)
|
||||
return;
|
||||
ConfigFile cfgFile;
|
||||
bool isChecked = _ui->monoIconsCheckBox->isChecked();
|
||||
cfgFile.setMonoIcons(isChecked);
|
||||
|
@ -138,6 +154,7 @@ void GeneralSettings::saveMiscSettings()
|
|||
|
||||
cfgFile.setNewBigFolderSizeLimit(_ui->newFolderLimitCheckBox->isChecked(),
|
||||
_ui->newFolderLimitSpinBox->value());
|
||||
cfgFile.setConfirmExternalStorage(_ui->newExternalStorage->isChecked());
|
||||
}
|
||||
|
||||
void GeneralSettings::slotToggleLaunchOnStartup(bool enable)
|
||||
|
|
|
@ -45,13 +45,14 @@ private slots:
|
|||
void slotToggleOptionalDesktopNotifications(bool);
|
||||
void slotUpdateInfo();
|
||||
void slotIgnoreFilesEditor();
|
||||
void loadMiscSettings();
|
||||
|
||||
private:
|
||||
void loadMiscSettings();
|
||||
|
||||
Ui::GeneralSettings *_ui;
|
||||
QPointer<IgnoreListEditor> _ignoreEditor;
|
||||
QPointer<SyncLogDialog> _syncLogDialog;
|
||||
bool _currentlyLoading;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>706</width>
|
||||
<width>785</width>
|
||||
<height>523</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -52,33 +52,37 @@
|
|||
<property name="title">
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="ignoredFilesButton">
|
||||
<property name="text">
|
||||
<string>Edit &Ignored Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="ignoredFilesButton">
|
||||
<property name="text">
|
||||
<string>Edit &Ignored Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>555</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>555</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="newFolderLimitCheckBox">
|
||||
<property name="text">
|
||||
<string>Ask &confirmation before downloading folders larger than</string>
|
||||
<string>Ask for confirmation before synchronizing folders larger than</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
|
@ -98,7 +102,7 @@
|
|||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>MB</string>
|
||||
<string extracomment="Trailing part of "Ask confirmation before syncing folder larger than" ">MB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -117,7 +121,14 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="newExternalStorage">
|
||||
<property name="text">
|
||||
<string>Ask for confirmation before synchronizing external storages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="crashreporterCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
|
@ -130,23 +141,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "notificationwidget.h"
|
||||
#include "QProgressIndicator.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
|
@ -33,8 +34,8 @@ void NotificationWidget::setActivity(const Activity& activity)
|
|||
{
|
||||
_myActivity = activity;
|
||||
|
||||
Q_ASSERT( !activity._accName.isEmpty() );
|
||||
_accountName = activity._accName;
|
||||
ASSERT(!_accountName.isEmpty());
|
||||
|
||||
// _ui._headerLabel->setText( );
|
||||
_ui._subjectLabel->setVisible( !activity._subject.isEmpty() );
|
||||
|
|
|
@ -924,6 +924,7 @@ void ownCloudGui::setPauseOnAllFoldersHelper(bool pause)
|
|||
void ownCloudGui::slotShowGuiMessage(const QString &title, const QString &message)
|
||||
{
|
||||
QMessageBox *msgBox = new QMessageBox;
|
||||
msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
||||
msgBox->setText(message);
|
||||
msgBox->setWindowTitle(title);
|
||||
|
|
|
@ -533,9 +533,11 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
|
|||
if (f) {
|
||||
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList,
|
||||
_ocWizard->selectiveSyncBlacklist());
|
||||
// The user already accepted the selective sync dialog. everything is in the white list
|
||||
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList,
|
||||
if (!_ocWizard->isConfirmBigFolderChecked()) {
|
||||
// The user already accepted the selective sync dialog. everything is in the white list
|
||||
f->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList,
|
||||
QStringList() << QLatin1String("/"));
|
||||
}
|
||||
}
|
||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "syncfileitem.h"
|
||||
#include "folder.h"
|
||||
#include "openfilemanager.h"
|
||||
#include "owncloudpropagator.h"
|
||||
#include "activityitemdelegate.h"
|
||||
|
||||
#include "ui_protocolwidget.h"
|
||||
|
@ -45,8 +44,8 @@ ProtocolWidget::ProtocolWidget(QWidget *parent) :
|
|||
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,ProgressInfo)),
|
||||
this, SLOT(slotProgressInfo(QString,ProgressInfo)));
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString,SyncFileItem,PropagatorJob)),
|
||||
this, SLOT(slotItemCompleted(QString,SyncFileItem,PropagatorJob)));
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString,SyncFileItemPtr)),
|
||||
this, SLOT(slotItemCompleted(QString,SyncFileItemPtr)));
|
||||
|
||||
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SLOT(slotOpenFile(QTreeWidgetItem*,int)));
|
||||
|
||||
|
@ -222,15 +221,11 @@ void ProtocolWidget::slotProgressInfo( const QString& folder, const ProgressInfo
|
|||
}
|
||||
}
|
||||
|
||||
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItem &item, const PropagatorJob &job)
|
||||
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
|
||||
{
|
||||
if (qobject_cast<const PropagateDirectory*>(&job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, item);
|
||||
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, *item);
|
||||
if(line) {
|
||||
if( item.hasErrorStatus() ) {
|
||||
if( item->hasErrorStatus() ) {
|
||||
_issueItemView->insertTopLevelItem(0, line);
|
||||
emit issueItemCountUpdated(_issueItemView->topLevelItemCount());
|
||||
} else {
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
|
||||
public slots:
|
||||
void slotProgressInfo( const QString& folder, const ProgressInfo& progress );
|
||||
void slotItemCompleted( const QString& folder, const SyncFileItem& item, const PropagatorJob& job);
|
||||
void slotItemCompleted( const QString& folder, const SyncFileItemPtr& item);
|
||||
void slotOpenFile( QTreeWidgetItem* item, int );
|
||||
|
||||
protected:
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "networkjobs.h"
|
||||
#include "theme.h"
|
||||
#include "folderman.h"
|
||||
#include "configfile.h"
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTreeWidget>
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include <QScopedValueRollback>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
@ -54,32 +56,48 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
SelectiveSyncTreeView::SelectiveSyncTreeView(AccountPtr account, QWidget* parent)
|
||||
: QTreeWidget(parent), _inserting(false), _account(account)
|
||||
SelectiveSyncWidget::SelectiveSyncWidget(AccountPtr account, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, _account(account)
|
||||
, _inserting(false)
|
||||
, _folderTree(new QTreeWidget(this))
|
||||
{
|
||||
_loading = new QLabel(tr("Loading ..."), this);
|
||||
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
setColumnCount(2);
|
||||
_loading = new QLabel(tr("Loading ..."), _folderTree);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
auto header = new QLabel(this);
|
||||
header->setText(tr("Deselect remote folders you do not wish to synchronize."));
|
||||
header->setWordWrap(true);
|
||||
layout->addWidget(header);
|
||||
|
||||
layout->addWidget(_folderTree);
|
||||
|
||||
connect(_folderTree, SIGNAL(itemExpanded(QTreeWidgetItem*)),
|
||||
SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||
connect(_folderTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
|
||||
SLOT(slotItemChanged(QTreeWidgetItem*,int)));
|
||||
_folderTree->setSortingEnabled(true);
|
||||
_folderTree->sortByColumn(0, Qt::AscendingOrder);
|
||||
_folderTree->setColumnCount(2);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
|
||||
header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
|
||||
_folderTree->header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
|
||||
_folderTree->header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
|
||||
#else
|
||||
header()->resizeSection(0, sizeHint().width()/2);
|
||||
_folderTree->header()->resizeSection(0, sizeHint().width()/2);
|
||||
#endif
|
||||
header()->setStretchLastSection(true);
|
||||
headerItem()->setText(0, tr("Name"));
|
||||
headerItem()->setText(1, tr("Size"));
|
||||
_folderTree->header()->setStretchLastSection(true);
|
||||
_folderTree->headerItem()->setText(0, tr("Name"));
|
||||
_folderTree->headerItem()->setText(1, tr("Size"));
|
||||
}
|
||||
|
||||
QSize SelectiveSyncTreeView::sizeHint() const
|
||||
QSize SelectiveSyncWidget::sizeHint() const
|
||||
{
|
||||
return QTreeView::sizeHint().expandedTo(QSize(400, 400));
|
||||
return QWidget::sizeHint().expandedTo(QSize(600, 600));
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::refreshFolders()
|
||||
void SelectiveSyncWidget::refreshFolders()
|
||||
{
|
||||
LsColJob *job = new LsColJob(_account, _folderPath, this);
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
|
||||
|
@ -88,12 +106,12 @@ void SelectiveSyncTreeView::refreshFolders()
|
|||
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
||||
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
||||
job->start();
|
||||
clear();
|
||||
_folderTree->clear();
|
||||
_loading->show();
|
||||
_loading->move(10,header()->height() + 10);
|
||||
_loading->move(10, _folderTree->header()->height() + 10);
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
|
||||
void SelectiveSyncWidget::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
|
||||
{
|
||||
_folderPath = folderPath;
|
||||
if (_folderPath.startsWith(QLatin1Char('/'))) {
|
||||
|
@ -116,7 +134,7 @@ static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& t
|
|||
return 0;
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
|
||||
void SelectiveSyncWidget::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
|
||||
{
|
||||
QFileIconProvider prov;
|
||||
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
||||
|
@ -159,13 +177,13 @@ void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList
|
|||
}
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
void SelectiveSyncWidget::slotUpdateDirectories(QStringList list)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
QScopedValueRollback<bool> isInserting(_inserting);
|
||||
_inserting = true;
|
||||
|
||||
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(topLevelItem(0));
|
||||
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(_folderTree->topLevelItem(0));
|
||||
|
||||
QUrl url = _account->davUrl();
|
||||
QString pathToRemove = url.path();
|
||||
|
@ -206,15 +224,11 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
|||
}
|
||||
|
||||
if (!root) {
|
||||
root = new SelectiveSyncTreeViewItem(this);
|
||||
root = new SelectiveSyncTreeViewItem(_folderTree);
|
||||
root->setText(0, _rootName);
|
||||
root->setIcon(0, Theme::instance()->applicationIcon());
|
||||
root->setData(0, Qt::UserRole, QString());
|
||||
if (_oldBlackList.isEmpty()) {
|
||||
root->setCheckState(0, Qt::Checked);
|
||||
} else {
|
||||
root->setCheckState(0, Qt::PartiallyChecked);
|
||||
}
|
||||
root->setCheckState(0, Qt::Checked);
|
||||
qint64 size = job ? job->_sizes.value(pathToRemove, -1) : -1;
|
||||
if (size >= 0) {
|
||||
root->setText(1, Utility::octetsToString(size));
|
||||
|
@ -236,10 +250,19 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
|||
recursiveInsert(root, paths, path, size);
|
||||
}
|
||||
|
||||
// Root is partially checked if any children are not checked
|
||||
for (int i = 0; i < root->childCount(); ++i) {
|
||||
const auto child = root->child(i);
|
||||
if (child->checkState(0) != Qt::Checked) {
|
||||
root->setCheckState(0, Qt::PartiallyChecked);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
root->setExpanded(true);
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
|
||||
void SelectiveSyncWidget::slotLscolFinishedWithError(QNetworkReply *r)
|
||||
{
|
||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||
_loading->setText(tr("No subfolders currently on the server."));
|
||||
|
@ -249,7 +272,7 @@ void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
|
|||
_loading->resize(_loading->sizeHint()); // because it's not in a layout
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
|
||||
void SelectiveSyncWidget::slotItemExpanded(QTreeWidgetItem *item)
|
||||
{
|
||||
QString dir = item->data(0, Qt::UserRole).toString();
|
||||
if (dir.isEmpty()) return;
|
||||
|
@ -264,7 +287,7 @@ void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
|
|||
job->start();
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
void SelectiveSyncWidget::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
{
|
||||
if (col != 0 || _inserting)
|
||||
return;
|
||||
|
@ -322,10 +345,10 @@ void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
|
|||
}
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
|
||||
QStringList SelectiveSyncWidget::createBlackList(QTreeWidgetItem* root) const
|
||||
{
|
||||
if (!root) {
|
||||
root = topLevelItem(0);
|
||||
root = _folderTree->topLevelItem(0);
|
||||
}
|
||||
if (!root) return QStringList();
|
||||
|
||||
|
@ -354,15 +377,15 @@ QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
|
|||
return result;
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncTreeView::oldBlackList() const
|
||||
QStringList SelectiveSyncWidget::oldBlackList() const
|
||||
{
|
||||
return _oldBlackList;
|
||||
}
|
||||
|
||||
qint64 SelectiveSyncTreeView::estimatedSize(QTreeWidgetItem* root)
|
||||
qint64 SelectiveSyncWidget::estimatedSize(QTreeWidgetItem* root)
|
||||
{
|
||||
if (!root) {
|
||||
root = topLevelItem(0);
|
||||
root = _folderTree->topLevelItem(0);
|
||||
}
|
||||
if (!root) return -1;
|
||||
|
||||
|
@ -396,10 +419,10 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, Folder* folder, QWi
|
|||
_okButton(0) // defined in init()
|
||||
{
|
||||
bool ok;
|
||||
init(account, tr("Unchecked folders will be <b>removed</b> from your local file system and will not be synchronized to this computer anymore"));
|
||||
init(account);
|
||||
QStringList selectiveSyncList = _folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok);
|
||||
if( ok ) {
|
||||
_treeView->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
|
||||
_selectiveSync->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
|
||||
} else {
|
||||
_okButton->setEnabled(false);
|
||||
}
|
||||
|
@ -411,22 +434,16 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, const QString &fold
|
|||
const QStringList& blacklist, QWidget* parent, Qt::WindowFlags f)
|
||||
: QDialog(parent, f), _folder(0)
|
||||
{
|
||||
init(account,
|
||||
Theme::instance()->wizardSelectiveSyncDefaultNothing() ?
|
||||
tr("Choose What to Sync: Select remote subfolders you wish to synchronize.") :
|
||||
tr("Choose What to Sync: Deselect remote subfolders you do not wish to synchronize."));
|
||||
_treeView->setFolderInfo(folder, folder, blacklist);
|
||||
init(account);
|
||||
_selectiveSync->setFolderInfo(folder, folder, blacklist);
|
||||
}
|
||||
|
||||
void SelectiveSyncDialog::init(const AccountPtr &account, const QString &labelText)
|
||||
void SelectiveSyncDialog::init(const AccountPtr &account)
|
||||
{
|
||||
setWindowTitle(tr("Choose What to Sync"));
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
_treeView = new SelectiveSyncTreeView(account, this);
|
||||
auto label = new QLabel(labelText);
|
||||
label->setWordWrap(true);
|
||||
layout->addWidget(label);
|
||||
layout->addWidget(_treeView);
|
||||
_selectiveSync = new SelectiveSyncWidget(account, this);
|
||||
layout->addWidget(_selectiveSync);
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
|
||||
_okButton = buttonBox->addButton(QDialogButtonBox::Ok);
|
||||
connect(_okButton, SIGNAL(clicked()), this, SLOT(accept()));
|
||||
|
@ -444,7 +461,7 @@ void SelectiveSyncDialog::accept()
|
|||
if( ! ok ) {
|
||||
return;
|
||||
}
|
||||
QStringList blackList = _treeView->createBlackList();
|
||||
QStringList blackList = _selectiveSync->createBlackList();
|
||||
_folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, blackList);
|
||||
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
|
@ -467,19 +484,18 @@ void SelectiveSyncDialog::accept()
|
|||
|
||||
QStringList SelectiveSyncDialog::createBlackList() const
|
||||
{
|
||||
return _treeView->createBlackList();
|
||||
return _selectiveSync->createBlackList();
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncDialog::oldBlackList() const
|
||||
{
|
||||
return _treeView->oldBlackList();
|
||||
return _selectiveSync->oldBlackList();
|
||||
}
|
||||
|
||||
qint64 SelectiveSyncDialog::estimatedSize()
|
||||
{
|
||||
return _treeView->estimatedSize();
|
||||
return _selectiveSync->estimatedSize();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -26,40 +26,50 @@ namespace OCC {
|
|||
class Folder;
|
||||
|
||||
/**
|
||||
* @brief The SelectiveSyncTreeView class
|
||||
* @brief The SelectiveSyncWidget contains a folder tree with labels
|
||||
* @ingroup gui
|
||||
*/
|
||||
class SelectiveSyncTreeView : public QTreeWidget {
|
||||
class SelectiveSyncWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SelectiveSyncTreeView(AccountPtr account, QWidget* parent = 0);
|
||||
explicit SelectiveSyncWidget(AccountPtr account, QWidget* parent = 0);
|
||||
|
||||
/// Returns a list of blacklisted paths, each including the trailing /
|
||||
QStringList createBlackList(QTreeWidgetItem* root = 0) const;
|
||||
|
||||
/** Returns the oldBlackList passed into setFolderInfo(), except that
|
||||
* a "/" entry is expanded to all top-level folder names.
|
||||
*/
|
||||
QStringList oldBlackList() const;
|
||||
|
||||
// Estimates the total size of checked items (recursively)
|
||||
qint64 estimatedSize(QTreeWidgetItem *root = 0);
|
||||
void refreshFolders();
|
||||
|
||||
// oldBlackList is a list of excluded paths, each including a trailing /
|
||||
void setFolderInfo(const QString &folderPath, const QString &rootName,
|
||||
const QStringList &oldBlackList = QStringList());
|
||||
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
void slotUpdateDirectories(QStringList);
|
||||
void slotItemExpanded(QTreeWidgetItem *);
|
||||
void slotItemChanged(QTreeWidgetItem*,int);
|
||||
void slotLscolFinishedWithError(QNetworkReply*);
|
||||
private:
|
||||
void refreshFolders();
|
||||
void recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size);
|
||||
|
||||
AccountPtr _account;
|
||||
|
||||
QString _folderPath;
|
||||
QString _rootName;
|
||||
QStringList _oldBlackList;
|
||||
|
||||
bool _inserting; // set to true when we are inserting new items on the list
|
||||
AccountPtr _account;
|
||||
QLabel *_loading;
|
||||
|
||||
QTreeWidget *_folderTree;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -85,9 +95,9 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
void init(const AccountPtr &account, const QString &label);
|
||||
void init(const AccountPtr &account);
|
||||
|
||||
SelectiveSyncTreeView *_treeView;
|
||||
SelectiveSyncWidget *_selectiveSync;
|
||||
|
||||
Folder *_folder;
|
||||
QPushButton *_okButton;
|
||||
|
|
|
@ -229,7 +229,7 @@ void ShareLinkWidget::slotSharesFetched(const QList<QSharedPointer<Share>> &shar
|
|||
Q_FOREACH(auto share, shares) {
|
||||
|
||||
if (share->getShareType() == Share::TypeLink) {
|
||||
_share = qSharedPointerObjectCast<LinkShare>(share);
|
||||
_share = qSharedPointerDynamicCast<LinkShare>(share);
|
||||
_ui->pushButton_copy->show();
|
||||
_ui->pushButton_mail->show();
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "accountstate.h"
|
||||
#include "account.h"
|
||||
#include "capabilities.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QBitArray>
|
||||
#include <QDebug>
|
||||
|
@ -60,9 +61,6 @@
|
|||
|
||||
#define DEBUG qDebug() << "SocketApi: "
|
||||
|
||||
Q_DECLARE_METATYPE(OCC::SocketListener)
|
||||
|
||||
|
||||
static inline QString removeTrailingSlash(QString path)
|
||||
{
|
||||
Q_ASSERT(path.endsWith(QLatin1Char('/')));
|
||||
|
@ -113,7 +111,7 @@ class SocketListener {
|
|||
public:
|
||||
QIODevice* socket;
|
||||
|
||||
SocketListener(QIODevice* socket = nullptr) : socket(socket) { }
|
||||
SocketListener(QIODevice* socket = 0) : socket(socket) { }
|
||||
|
||||
void sendMessage(const QString& message, bool doWait = false) const
|
||||
{
|
||||
|
@ -216,7 +214,7 @@ SocketApi::~SocketApi()
|
|||
DEBUG << "dtor";
|
||||
_localServer.close();
|
||||
// All remaining sockets will be destroyed with _localServer, their parent
|
||||
Q_ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
|
||||
ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
|
||||
_listeners.clear();
|
||||
}
|
||||
|
||||
|
@ -231,7 +229,7 @@ void SocketApi::slotNewConnection()
|
|||
connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
|
||||
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
|
||||
connect(socket, SIGNAL(destroyed(QObject*)), this, SLOT(slotSocketDestroyed(QObject*)));
|
||||
Q_ASSERT(socket->readAll().isEmpty());
|
||||
ASSERT(socket->readAll().isEmpty());
|
||||
|
||||
_listeners.append(SocketListener(socket));
|
||||
SocketListener &listener = _listeners.last();
|
||||
|
@ -259,7 +257,7 @@ void SocketApi::slotSocketDestroyed(QObject* obj)
|
|||
void SocketApi::slotReadSocket()
|
||||
{
|
||||
QIODevice* socket = qobject_cast<QIODevice*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
ASSERT(socket);
|
||||
SocketListener *listener = &*std::find_if(_listeners.begin(), _listeners.end(), ListenerHasSocketPred(socket));
|
||||
|
||||
while(socket->canReadLine()) {
|
||||
|
|
|
@ -145,18 +145,18 @@ void SyncRunFileLog::logItem( const SyncFileItem& item )
|
|||
|
||||
const QChar L = QLatin1Char('|');
|
||||
_out << ts << L;
|
||||
_out << QString::number(item._requestDuration) << L;
|
||||
if( item.log._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
||||
_out << L;
|
||||
if( item._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
||||
_out << item._file << L;
|
||||
} else {
|
||||
_out << item._file << QLatin1String(" -> ") << item._renameTarget << L;
|
||||
}
|
||||
_out << instructionToStr( item.log._instruction ) << L;
|
||||
_out << instructionToStr( item._instruction ) << L;
|
||||
_out << directionToStr( item._direction ) << L;
|
||||
_out << QString::number(item.log._modtime) << L;
|
||||
_out << item.log._etag << L;
|
||||
_out << QString::number(item.log._size) << L;
|
||||
_out << item.log._fileId << L;
|
||||
_out << QString::number(item._modtime) << L;
|
||||
_out << item._etag << L;
|
||||
_out << QString::number(item._size) << L;
|
||||
_out << item._fileId << L;
|
||||
_out << item._status << L;
|
||||
_out << item._errorString << L;
|
||||
_out << QString::number(item._httpErrorCode) << L;
|
||||
|
|
|
@ -68,6 +68,15 @@ OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage()
|
|||
_ui.lServerIcon->setPixmap(appIcon.pixmap(48));
|
||||
_ui.lLocalIcon->setText(QString());
|
||||
_ui.lLocalIcon->setPixmap(QPixmap(Theme::hidpiFileName(":/client/resources/folder-sync.png")));
|
||||
|
||||
if (theme->wizardHideExternalStorageConfirmationCheckbox()) {
|
||||
_ui.confCheckBoxExternal->hide();
|
||||
}
|
||||
if (theme->wizardHideFolderSizeLimitCheckbox()) {
|
||||
_ui.confCheckBoxSize->hide();
|
||||
_ui.confSpinBox->hide();
|
||||
_ui.confTraillingSizeLabel->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void OwncloudAdvancedSetupPage::setupCustomization()
|
||||
|
@ -118,6 +127,12 @@ void OwncloudAdvancedSetupPage::initializePage()
|
|||
_selectiveSyncBlacklist = QStringList("/");
|
||||
QTimer::singleShot(0, this, SLOT(slotSelectiveSyncClicked()));
|
||||
}
|
||||
|
||||
ConfigFile cfgFile;
|
||||
auto newFolderLimit = cfgFile.newBigFolderSizeLimit();
|
||||
_ui.confCheckBoxSize->setChecked(newFolderLimit.first);
|
||||
_ui.confSpinBox->setValue(newFolderLimit.second);
|
||||
_ui.confCheckBoxExternal->setChecked(cfgFile.confirmExternalStorage());
|
||||
}
|
||||
|
||||
// Called if the user changes the user- or url field. Adjust the texts and
|
||||
|
@ -200,6 +215,11 @@ QStringList OwncloudAdvancedSetupPage::selectiveSyncBlacklist() const
|
|||
return _selectiveSyncBlacklist;
|
||||
}
|
||||
|
||||
bool OwncloudAdvancedSetupPage::isConfirmBigFolderChecked() const
|
||||
{
|
||||
return _ui.rSyncEverything->isChecked() && _ui.confCheckBoxSize->isChecked();
|
||||
}
|
||||
|
||||
bool OwncloudAdvancedSetupPage::validatePage()
|
||||
{
|
||||
if(!_created) {
|
||||
|
@ -208,6 +228,13 @@ bool OwncloudAdvancedSetupPage::validatePage()
|
|||
startSpinner();
|
||||
emit completeChanged();
|
||||
|
||||
if (_ui.rSyncEverything->isChecked()) {
|
||||
ConfigFile cfgFile;
|
||||
cfgFile.setNewBigFolderSizeLimit(_ui.confCheckBoxSize->isChecked(),
|
||||
_ui.confSpinBox->value());
|
||||
cfgFile.setConfirmExternalStorage(_ui.confCheckBoxExternal->isChecked());
|
||||
}
|
||||
|
||||
emit createLocalAndRemoteFolders(localFolder(), _remoteFolder);
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
bool validatePage() Q_DECL_OVERRIDE;
|
||||
QString localFolder() const;
|
||||
QStringList selectiveSyncBlacklist() const;
|
||||
bool isConfirmBigFolderChecked() const;
|
||||
void setRemoteFolder( const QString& remoteFolder);
|
||||
void setMultipleFoldersExist( bool exist );
|
||||
void directoriesCreated();
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>917</width>
|
||||
<height>493</height>
|
||||
<width>912</width>
|
||||
<height>633</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
|
@ -226,11 +226,14 @@
|
|||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rSyncEverything">
|
||||
<property name="text">
|
||||
|
@ -263,6 +266,64 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="horizontalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Minimum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="confCheckBoxSize">
|
||||
<property name="text">
|
||||
<string>Ask for confirmation before synchroni&zing folders larger than</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="confSpinBox">
|
||||
<property name="maximum">
|
||||
<number>999999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>99</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="confTraillingSizeLabel">
|
||||
<property name="text">
|
||||
<string extracomment="Trailing part of "Ask confirmation before syncing folder larger than" ">MB</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="confCheckBoxExternal">
|
||||
<property name="text">
|
||||
<string>Ask for confirmation before synchronizing e&xternal storages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
|
@ -345,5 +406,70 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>rSyncEverything</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>confCheckBoxSize</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>217</x>
|
||||
<y>78</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>298</x>
|
||||
<y>126</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>rSyncEverything</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>confSpinBox</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>311</x>
|
||||
<y>83</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>952</x>
|
||||
<y>134</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>rSyncEverything</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>confTraillingSizeLabel</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>277</x>
|
||||
<y>76</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>1076</x>
|
||||
<y>136</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>rSyncEverything</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>confCheckBoxExternal</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>181</x>
|
||||
<y>78</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>382</x>
|
||||
<y>174</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>602</width>
|
||||
<height>193</height>
|
||||
<width>506</width>
|
||||
<height>515</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -80,7 +80,7 @@
|
|||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Server &Address</string>
|
||||
<string>Ser&ver Address</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>leUrl</cstring>
|
||||
|
@ -166,10 +166,13 @@
|
|||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
|
|
|
@ -44,6 +44,7 @@ void OwncloudShibbolethCredsPage::setupBrowser()
|
|||
// i.e. if someone presses "back"
|
||||
QNetworkAccessManager *qnam = account->networkAccessManager();
|
||||
CookieJar *jar = new CookieJar;
|
||||
jar->restore(account->cookieJarPath());
|
||||
// Implicitly deletes the old cookie jar, and reparents the jar
|
||||
qnam->setCookieJar(jar);
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ OwncloudWizard::OwncloudWizard(QWidget *parent)
|
|||
setTitleFormat(Qt::RichText);
|
||||
setSubTitleFormat(Qt::RichText);
|
||||
setButtonText(QWizard::CustomButton1, tr("Skip folders configuration"));
|
||||
|
||||
}
|
||||
|
||||
void OwncloudWizard::setAccount(AccountPtr account)
|
||||
|
@ -109,6 +108,10 @@ QStringList OwncloudWizard::selectiveSyncBlacklist() const
|
|||
return _advancedSetupPage->selectiveSyncBlacklist();
|
||||
}
|
||||
|
||||
bool OwncloudWizard::isConfirmBigFolderChecked() const
|
||||
{
|
||||
return _advancedSetupPage->isConfirmBigFolderChecked();
|
||||
}
|
||||
|
||||
QString OwncloudWizard::ocUrl() const
|
||||
{
|
||||
|
|
|
@ -59,6 +59,7 @@ public:
|
|||
QString ocUrl() const;
|
||||
QString localFolder() const;
|
||||
QStringList selectiveSyncBlacklist() const;
|
||||
bool isConfirmBigFolderChecked() const;
|
||||
|
||||
void enableFinishOnResultWidget(bool enable);
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
project(libsync)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
|
||||
configure_file( version.h.in "${CMAKE_CURRENT_BINARY_DIR}/version.h" )
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
|
|
@ -172,7 +172,6 @@ void AbstractNetworkJob::slotFinished()
|
|||
|
||||
// get the Date timestamp from reply
|
||||
_responseTimestamp = _reply->rawHeader("Date");
|
||||
_duration = _durationTimer.elapsed();
|
||||
|
||||
if (_followRedirects) {
|
||||
// ### the qWarnings here should be exported via displayErrors() so they
|
||||
|
@ -206,11 +205,6 @@ void AbstractNetworkJob::slotFinished()
|
|||
}
|
||||
}
|
||||
|
||||
quint64 AbstractNetworkJob::duration()
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
|
||||
QByteArray AbstractNetworkJob::responseTimestamp()
|
||||
{
|
||||
return _responseTimestamp;
|
||||
|
@ -224,8 +218,6 @@ AbstractNetworkJob::~AbstractNetworkJob()
|
|||
void AbstractNetworkJob::start()
|
||||
{
|
||||
_timer.start();
|
||||
_durationTimer.start();
|
||||
_duration = 0;
|
||||
|
||||
const QUrl url = account()->url();
|
||||
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
||||
|
|
|
@ -55,7 +55,6 @@ public:
|
|||
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
||||
|
||||
QByteArray responseTimestamp();
|
||||
quint64 duration();
|
||||
|
||||
qint64 timeoutMsec() { return _timer.interval(); }
|
||||
|
||||
|
@ -82,8 +81,6 @@ protected:
|
|||
int maxRedirects() const { return 10; }
|
||||
virtual bool finished() = 0;
|
||||
QByteArray _responseTimestamp;
|
||||
QElapsedTimer _durationTimer;
|
||||
quint64 _duration;
|
||||
bool _timedout; // set to true when the timeout slot is received
|
||||
|
||||
// Automatically follows redirects. Note that this only works for
|
||||
|
|
|
@ -37,8 +37,11 @@ AccessManager::AccessManager(QObject* parent)
|
|||
proxy.setHostName(" ");
|
||||
setProxy(proxy);
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_LINUX
|
||||
// Atempt to workaround for https://github.com/owncloud/client/issues/3969
|
||||
setConfiguration(QNetworkConfiguration());
|
||||
#endif
|
||||
setCookieJar(new CookieJar);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "creds/abstractcredentials.h"
|
||||
#include "capabilities.h"
|
||||
#include "theme.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QMutex>
|
||||
|
@ -153,8 +154,9 @@ QUrl Account::davUrl() const
|
|||
*/
|
||||
void Account::clearCookieJar()
|
||||
{
|
||||
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
|
||||
static_cast<CookieJar*>(_am->cookieJar())->setAllCookies(QList<QNetworkCookie>());
|
||||
auto jar = qobject_cast<CookieJar*>(_am->cookieJar());
|
||||
ASSERT(jar);
|
||||
jar->setAllCookies(QList<QNetworkCookie>());
|
||||
emit wantsAccountSaved(this);
|
||||
}
|
||||
|
||||
|
@ -169,6 +171,12 @@ void Account::lendCookieJarTo(QNetworkAccessManager *guest)
|
|||
jar->setParent(oldParent); // takes it back
|
||||
}
|
||||
|
||||
QString Account::cookieJarPath()
|
||||
{
|
||||
ConfigFile cfg;
|
||||
return cfg.configPath() + "/cookies" + id() + ".db";
|
||||
}
|
||||
|
||||
void Account::resetNetworkAccessManager()
|
||||
{
|
||||
if (!_credentials || !_am) {
|
||||
|
|
|
@ -172,6 +172,7 @@ public:
|
|||
|
||||
void clearCookieJar();
|
||||
void lendCookieJarTo(QNetworkAccessManager *guest);
|
||||
QString cookieJarPath();
|
||||
|
||||
void resetNetworkAccessManager();
|
||||
QNetworkAccessManager* networkAccessManager();
|
||||
|
|
52
src/libsync/asserts.h
Normal file
52
src/libsync/asserts.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef OWNCLOUD_ASSERTS_H
|
||||
#define OWNCLOUD_ASSERTS_H
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#if defined(QT_FORCE_ASSERTS) || !defined(QT_NO_DEBUG)
|
||||
#define OC_ASSERT_MSG qFatal
|
||||
#else
|
||||
#define OC_ASSERT_MSG qWarning
|
||||
#endif
|
||||
|
||||
// For overloading macros by argument count
|
||||
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
||||
#define OC_ASSERT_CAT(A, B) A ## B
|
||||
#define OC_ASSERT_SELECT(NAME, NUM) OC_ASSERT_CAT(NAME ## _, NUM)
|
||||
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
||||
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_GET_COUNT(__VA_ARGS__, 3, 2, 1, 0)
|
||||
|
||||
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
// Default assert: If the condition is false in debug builds, terminate.
|
||||
//
|
||||
// Prints a message on failure, even in release builds.
|
||||
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
||||
#define ASSERT_1(cond) \
|
||||
if (!(cond)) { \
|
||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||
} else {}
|
||||
#define ASSERT_2(cond, message) \
|
||||
if (!(cond)) { \
|
||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||
} else {}
|
||||
|
||||
// Enforce condition to be true, even in release builds.
|
||||
//
|
||||
// Prints 'message' and aborts execution if 'cond' is false.
|
||||
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
||||
#define ENFORCE_1(cond) \
|
||||
if (!(cond)) { \
|
||||
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||
} else {}
|
||||
#define ENFORCE_2(cond, message) \
|
||||
if (!(cond)) { \
|
||||
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||
} else {}
|
||||
|
||||
// An assert that is only present in debug builds: typically used for
|
||||
// asserts that are too expensive for release mode.
|
||||
//
|
||||
// Q_ASSERT
|
||||
|
||||
#endif
|
|
@ -111,10 +111,10 @@ bool uploadChecksumEnabled()
|
|||
QByteArray contentChecksumType()
|
||||
{
|
||||
static QByteArray type = qgetenv("OWNCLOUD_CONTENT_CHECKSUM_TYPE");
|
||||
if (!type.isNull()) { // can set to "" to disable checksumming
|
||||
return type;
|
||||
if (type.isNull()) { // can set to "" to disable checksumming
|
||||
type = "SHA1";
|
||||
}
|
||||
return "SHA1";
|
||||
return type;
|
||||
}
|
||||
|
||||
ComputeChecksum::ComputeChecksum(QObject* parent)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "configfile.h"
|
||||
#include "theme.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
|
@ -67,6 +68,7 @@ static const char downloadLimitC[] = "BWLimit/downloadLimit";
|
|||
|
||||
static const char newBigFolderSizeLimitC[] = "newBigFolderSizeLimit";
|
||||
static const char useNewBigFolderSizeLimitC[] = "useNewBigFolderSizeLimit";
|
||||
static const char confirmExternalStorageC[] = "confirmExternalStorage";
|
||||
|
||||
static const char maxLogLinesC[] = "Logging/maxLogLines";
|
||||
|
||||
|
@ -138,7 +140,7 @@ void ConfigFile::setOptionalDesktopNotifications(bool show)
|
|||
void ConfigFile::saveGeometry(QWidget *w)
|
||||
{
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
Q_ASSERT(!w->objectName().isNull());
|
||||
ASSERT(!w->objectName().isNull());
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
settings.beginGroup(w->objectName());
|
||||
settings.setValue(QLatin1String(geometryC), w->saveGeometry());
|
||||
|
@ -157,7 +159,7 @@ void ConfigFile::saveGeometryHeader(QHeaderView *header)
|
|||
{
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
if(!header) return;
|
||||
Q_ASSERT(!header->objectName().isEmpty());
|
||||
ASSERT(!header->objectName().isEmpty());
|
||||
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
settings.beginGroup(header->objectName());
|
||||
|
@ -170,7 +172,7 @@ void ConfigFile::restoreGeometryHeader(QHeaderView *header)
|
|||
{
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
if(!header) return;
|
||||
Q_ASSERT(!header->objectName().isNull());
|
||||
ASSERT(!header->objectName().isNull());
|
||||
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
settings.beginGroup(header->objectName());
|
||||
|
@ -229,8 +231,8 @@ QString ConfigFile::excludeFile(Scope scope) const
|
|||
// directories.
|
||||
QFileInfo fi;
|
||||
|
||||
if (scope != SystemScope) {
|
||||
QFileInfo fi;
|
||||
switch (scope) {
|
||||
case UserScope:
|
||||
fi.setFile( configPath(), exclFile );
|
||||
|
||||
if( ! fi.isReadable() ) {
|
||||
|
@ -240,12 +242,12 @@ QString ConfigFile::excludeFile(Scope scope) const
|
|||
fi.setFile( configPath(), exclFile );
|
||||
}
|
||||
return fi.absoluteFilePath();
|
||||
} else if (scope != UserScope) {
|
||||
case SystemScope:
|
||||
return ConfigFile::excludeFileFromSystem();
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
return QString(); // unreachable
|
||||
}
|
||||
|
||||
ASSERT(false);
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString ConfigFile::excludeFileFromSystem()
|
||||
|
@ -596,6 +598,16 @@ void ConfigFile::setNewBigFolderSizeLimit(bool isChecked, quint64 mbytes)
|
|||
setValue(useNewBigFolderSizeLimitC, isChecked);
|
||||
}
|
||||
|
||||
bool ConfigFile::confirmExternalStorage() const
|
||||
{
|
||||
return getValue(confirmExternalStorageC, QString(), true).toBool();
|
||||
}
|
||||
|
||||
void ConfigFile::setConfirmExternalStorage(bool isChecked)
|
||||
{
|
||||
setValue(confirmExternalStorageC, isChecked);
|
||||
}
|
||||
|
||||
bool ConfigFile::promptDeleteFiles() const
|
||||
{
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
|
|
|
@ -105,6 +105,8 @@ public:
|
|||
/** [checked, size in MB] **/
|
||||
QPair<bool, quint64> newBigFolderSizeLimit() const;
|
||||
void setNewBigFolderSizeLimit(bool isChecked, quint64 mbytes);
|
||||
bool confirmExternalStorage() const;
|
||||
void setConfirmExternalStorage(bool);
|
||||
|
||||
static bool setConfDir(const QString &value);
|
||||
|
||||
|
|
|
@ -68,7 +68,6 @@ QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
|
|||
CookieJar::CookieJar(QObject *parent) :
|
||||
QNetworkCookieJar(parent)
|
||||
{
|
||||
restore();
|
||||
}
|
||||
|
||||
CookieJar::~CookieJar()
|
||||
|
@ -97,21 +96,21 @@ void CookieJar::clearSessionCookies()
|
|||
setAllCookies(removeExpired(allCookies()));
|
||||
}
|
||||
|
||||
void CookieJar::save()
|
||||
void CookieJar::save(const QString &fileName)
|
||||
{
|
||||
QFile file;
|
||||
file.setFileName(storagePath());
|
||||
qDebug() << storagePath();
|
||||
file.setFileName(fileName);
|
||||
qDebug() << fileName;
|
||||
file.open(QIODevice::WriteOnly);
|
||||
QDataStream stream(&file);
|
||||
stream << removeExpired(allCookies());
|
||||
file.close();
|
||||
}
|
||||
|
||||
void CookieJar::restore()
|
||||
void CookieJar::restore(const QString &fileName)
|
||||
{
|
||||
QFile file;
|
||||
file.setFileName(storagePath());
|
||||
file.setFileName(fileName);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QDataStream stream(&file);
|
||||
QList<QNetworkCookie> list;
|
||||
|
@ -131,10 +130,4 @@ QList<QNetworkCookie> CookieJar::removeExpired(const QList<QNetworkCookie> &cook
|
|||
return updatedList;
|
||||
}
|
||||
|
||||
QString CookieJar::storagePath() const
|
||||
{
|
||||
ConfigFile cfg;
|
||||
return cfg.configPath() + "/cookies.db";
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
|
|
@ -39,15 +39,13 @@ public:
|
|||
using QNetworkCookieJar::setAllCookies;
|
||||
using QNetworkCookieJar::allCookies;
|
||||
|
||||
void save();
|
||||
void save(const QString &fileName);
|
||||
void restore(const QString &fileName);
|
||||
|
||||
signals:
|
||||
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||
private:
|
||||
void restore();
|
||||
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
|
||||
QString storagePath() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
#include "asserts.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
namespace OCC
|
||||
|
@ -28,7 +28,7 @@ AbstractCredentials::AbstractCredentials()
|
|||
|
||||
void AbstractCredentials::setAccount(Account *account)
|
||||
{
|
||||
Q_ASSERT(!_account);
|
||||
ENFORCE(!_account, "should only setAccount once");
|
||||
_account = account;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,13 +13,19 @@
|
|||
*/
|
||||
|
||||
#include "discoveryphase.h"
|
||||
|
||||
#include "account.h"
|
||||
#include "theme.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <csync_private.h>
|
||||
#include <csync_rename.h>
|
||||
#include <qdebug.h>
|
||||
|
||||
#include <qdebug.h>
|
||||
#include <QUrl>
|
||||
#include "account.h"
|
||||
#include <QFileInfo>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
@ -81,14 +87,32 @@ int DiscoveryJob::isInSelectiveSyncBlackListCallback(void *data, const char *pat
|
|||
return static_cast<DiscoveryJob*>(data)->isInSelectiveSyncBlackList(path);
|
||||
}
|
||||
|
||||
bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString& path)
|
||||
bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString& path, const char *remotePerm)
|
||||
{
|
||||
// If this path or the parent is in the white list, then we do not block this file
|
||||
|
||||
if (_syncOptions._confirmExternalStorage && std::strchr(remotePerm, 'M')) {
|
||||
// 'M' in the permission means external storage.
|
||||
|
||||
/* Note: DiscoverySingleDirectoryJob::directoryListingIteratedSlot make sure that only the
|
||||
* root of a mounted storage has 'M', all sub entries have 'm' */
|
||||
|
||||
// Only allow it if the white list contains exactly this path (not parents)
|
||||
// We want to ask confirmation for external storage even if the parents where selected
|
||||
if (_selectiveSyncWhiteList.contains(path + QLatin1Char('/'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
emit newBigFolder(path, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this path or the parent is in the white list, then we do not block this file
|
||||
if (findPathInList(_selectiveSyncWhiteList, path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_newBigFolderSizeLimit < 0) {
|
||||
auto limit = _syncOptions._newBigFolderSizeLimit;
|
||||
if (limit < 0) {
|
||||
// no limit, everything is allowed;
|
||||
return false;
|
||||
}
|
||||
|
@ -102,10 +126,9 @@ bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString& path)
|
|||
_vioWaitCondition.wait(&_vioMutex);
|
||||
}
|
||||
|
||||
auto limit = _newBigFolderSizeLimit;
|
||||
if (result >= limit) {
|
||||
// we tell the UI there is a new folder
|
||||
emit newBigFolder(path);
|
||||
emit newBigFolder(path, false);
|
||||
return true;
|
||||
} else {
|
||||
// it is not too big, put it in the white list (so we will not do more query for the children)
|
||||
|
@ -119,9 +142,9 @@ bool DiscoveryJob::checkSelectiveSyncNewFolder(const QString& path)
|
|||
}
|
||||
}
|
||||
|
||||
int DiscoveryJob::checkSelectiveSyncNewFolderCallback(void *data, const char *path)
|
||||
int DiscoveryJob::checkSelectiveSyncNewFolderCallback(void *data, const char *path, const char *remotePerm)
|
||||
{
|
||||
return static_cast<DiscoveryJob*>(data)->checkSelectiveSyncNewFolder(QString::fromUtf8(path));
|
||||
return static_cast<DiscoveryJob*>(data)->checkSelectiveSyncNewFolder(QString::fromUtf8(path), remotePerm);
|
||||
}
|
||||
|
||||
|
||||
|
@ -224,7 +247,7 @@ int get_errno_from_http_errcode( int err, const QString & reason ) {
|
|||
|
||||
|
||||
DiscoverySingleDirectoryJob::DiscoverySingleDirectoryJob(const AccountPtr &account, const QString &path, QObject *parent)
|
||||
: QObject(parent), _subPath(path), _account(account), _ignoredFirst(false), _isRootPath(false)
|
||||
: QObject(parent), _subPath(path), _account(account), _ignoredFirst(false), _isRootPath(false), _isExternalStorage(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -321,7 +344,9 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
|
|||
// The first entry is for the folder itself, we should process it differently.
|
||||
_ignoredFirst = true;
|
||||
if (map.contains("permissions")) {
|
||||
emit firstDirectoryPermissions(map.value("permissions"));
|
||||
auto perm = map.value("permissions");
|
||||
emit firstDirectoryPermissions(perm);
|
||||
_isExternalStorage = perm.contains(QLatin1Char('M'));
|
||||
}
|
||||
if (map.contains("data-fingerprint")) {
|
||||
_dataFingerprint = map.value("data-fingerprint").toUtf8();
|
||||
|
@ -344,6 +369,13 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
|
|||
if (!file_stat->etag || strlen(file_stat->etag) == 0) {
|
||||
qDebug() << "WARNING: etag of" << file_stat->name << "is" << file_stat->etag << " This must not happen.";
|
||||
}
|
||||
if (_isExternalStorage) {
|
||||
/* All the entries in a external storage have 'M' in their permission. However, for all
|
||||
purposes in the desktop client, we only need to know about the mount points.
|
||||
So replace the 'M' by a 'm' for every sub entries in an external storage */
|
||||
std::replace(file_stat->remotePerm, file_stat->remotePerm + strlen(file_stat->remotePerm),
|
||||
'M', 'm');
|
||||
}
|
||||
|
||||
QStringRef fileRef(&file);
|
||||
int slashPos = file.lastIndexOf(QLatin1Char('/'));
|
||||
|
|
|
@ -34,6 +34,16 @@ class Account;
|
|||
* if the files are new, or changed.
|
||||
*/
|
||||
|
||||
struct SyncOptions {
|
||||
SyncOptions() : _newBigFolderSizeLimit(-1), _confirmExternalStorage(false) {}
|
||||
/** Maximum size (in Bytes) a folder can have without asking for confirmation.
|
||||
* -1 means infinite */
|
||||
qint64 _newBigFolderSizeLimit;
|
||||
/** If a confirmation should be asked for external storages */
|
||||
bool _confirmExternalStorage;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The FileStatPointer class
|
||||
* @ingroup libsync
|
||||
|
@ -107,6 +117,8 @@ private:
|
|||
bool _ignoredFirst;
|
||||
// Set to true if this is the root path and we need to check the data-fingerprint
|
||||
bool _isRootPath;
|
||||
// If this directory is an external storage (The first item has 'M' in its permission)
|
||||
bool _isExternalStorage;
|
||||
QPointer<LsColJob> _lsColJob;
|
||||
|
||||
public:
|
||||
|
@ -176,8 +188,8 @@ class DiscoveryJob : public QObject {
|
|||
*/
|
||||
bool isInSelectiveSyncBlackList(const char* path) const;
|
||||
static int isInSelectiveSyncBlackListCallback(void *, const char *);
|
||||
bool checkSelectiveSyncNewFolder(const QString &path);
|
||||
static int checkSelectiveSyncNewFolderCallback(void*, const char*);
|
||||
bool checkSelectiveSyncNewFolder(const QString &path, const char *remotePerm);
|
||||
static int checkSelectiveSyncNewFolderCallback(void* data, const char* path, const char* remotePerm);
|
||||
|
||||
// Just for progress
|
||||
static void update_job_update_callback (bool local,
|
||||
|
@ -197,7 +209,7 @@ class DiscoveryJob : public QObject {
|
|||
|
||||
public:
|
||||
explicit DiscoveryJob(CSYNC *ctx, QObject* parent = 0)
|
||||
: QObject(parent), _csync_ctx(ctx), _newBigFolderSizeLimit(-1) {
|
||||
: QObject(parent), _csync_ctx(ctx) {
|
||||
// We need to forward the log property as csync uses thread local
|
||||
// and updates run in another thread
|
||||
_log_callback = csync_get_log_callback();
|
||||
|
@ -207,7 +219,7 @@ public:
|
|||
|
||||
QStringList _selectiveSyncBlackList;
|
||||
QStringList _selectiveSyncWhiteList;
|
||||
qint64 _newBigFolderSizeLimit;
|
||||
SyncOptions _syncOptions;
|
||||
Q_INVOKABLE void start();
|
||||
signals:
|
||||
void finished(int result);
|
||||
|
@ -218,7 +230,7 @@ signals:
|
|||
void doGetSizeSignal(const QString &path, qint64 *result);
|
||||
|
||||
// A new folder was discovered and was not synced because of the confirmation feature
|
||||
void newBigFolder(const QString &folder);
|
||||
void newBigFolder(const QString &folder, bool isExternal);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ void ExcludedFiles::addExcludeFilePath(const QString& path)
|
|||
_excludeFiles.insert(path);
|
||||
}
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
#ifdef WITH_TESTING
|
||||
void ExcludedFiles::addExcludeExpr(const QString &expr)
|
||||
{
|
||||
_csync_exclude_add(_excludesPtr, expr.toLatin1().constData());
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
const QString& basePath,
|
||||
bool excludeHidden) const;
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
#ifdef WITH_TESTING
|
||||
void addExcludeExpr(const QString &expr);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ QString OWNCLOUDSYNC_EXPORT longWinPath( const QString& inpath );
|
|||
*/
|
||||
time_t OWNCLOUDSYNC_EXPORT getModTime(const QString& filename);
|
||||
|
||||
bool setModTime(const QString &filename, time_t modTime);
|
||||
bool OWNCLOUDSYNC_EXPORT setModTime(const QString &filename, time_t modTime);
|
||||
|
||||
/**
|
||||
* @brief Get the size for a file
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "configfile.h"
|
||||
#include "utility.h"
|
||||
#include "account.h"
|
||||
#include "asserts.h"
|
||||
#include <json.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include <QObject>
|
||||
#include <QTimerEvent>
|
||||
#include <QDebug>
|
||||
#include <qmath.h>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
@ -71,32 +73,27 @@ qint64 freeSpaceLimit()
|
|||
OwncloudPropagator::~OwncloudPropagator()
|
||||
{}
|
||||
|
||||
/* The maximum number of active jobs in parallel */
|
||||
int OwncloudPropagator::maximumActiveJob()
|
||||
{
|
||||
static int max = qgetenv("OWNCLOUD_MAX_PARALLEL").toUInt();
|
||||
if (!max) {
|
||||
max = 3; //default
|
||||
}
|
||||
|
||||
int OwncloudPropagator::maximumActiveTransferJob()
|
||||
{
|
||||
if (_downloadLimit.fetchAndAddAcquire(0) != 0 || _uploadLimit.fetchAndAddAcquire(0) != 0) {
|
||||
// disable parallelism when there is a network limit.
|
||||
return 1;
|
||||
}
|
||||
|
||||
return max;
|
||||
return qCeil(hardMaximumActiveJob()/2.);
|
||||
}
|
||||
|
||||
/* The maximum number of active jobs in parallel */
|
||||
int OwncloudPropagator::hardMaximumActiveJob()
|
||||
{
|
||||
int max = maximumActiveJob();
|
||||
return max*2;
|
||||
// FIXME: Wondering if we should hard-limit to 1 if maximumActiveJob() is 1
|
||||
// to support our old use case of limiting concurrency (when "automatic" bandwidth
|
||||
// limiting is set. But this causes https://github.com/owncloud/client/issues/4081
|
||||
static int max = qgetenv("OWNCLOUD_MAX_PARALLEL").toUInt();
|
||||
if (!max) {
|
||||
max = 6; //default (Qt cannot do more anyway)
|
||||
// TODO: increase this number when using HTTP2
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
/** Updates, creates or removes a blacklist entry for the given item.
|
||||
*
|
||||
* Returns whether the error should be suppressed.
|
||||
|
@ -172,7 +169,7 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
|
|||
|
||||
_item->_status = status;
|
||||
|
||||
emit itemCompleted(*_item, *this);
|
||||
emit itemCompleted(_item);
|
||||
emit finished(status);
|
||||
}
|
||||
|
||||
|
@ -221,7 +218,7 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
|
|||
if( newJob ) {
|
||||
newJob->setRestoreJobMsg(msg);
|
||||
_restoreJob.reset(newJob);
|
||||
connect(_restoreJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &, const PropagatorJob &)),
|
||||
connect(_restoreJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SLOT(slotRestoreJobCompleted(const SyncFileItemPtr &)));
|
||||
QMetaObject::invokeMethod(newJob, "start");
|
||||
}
|
||||
|
@ -403,8 +400,8 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
|
|||
_rootJob->append(it);
|
||||
}
|
||||
|
||||
connect(_rootJob.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_rootJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
connect(_rootJob.data(), SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
||||
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished(SyncFileItem::Status)));
|
||||
connect(_rootJob.data(), SIGNAL(ready()), this, SLOT(scheduleNextJob()), Qt::QueuedConnection);
|
||||
|
@ -524,7 +521,7 @@ void OwncloudPropagator::scheduleNextJob()
|
|||
// Down-scaling on slow networks? https://github.com/owncloud/client/issues/3382
|
||||
// Making sure we do up/down at same time? https://github.com/owncloud/client/issues/1633
|
||||
|
||||
if (_activeJobList.count() < maximumActiveJob()) {
|
||||
if (_activeJobList.count() < maximumActiveTransferJob()) {
|
||||
if (_rootJob->scheduleNextJob()) {
|
||||
QTimer::singleShot(0, this, SLOT(scheduleNextJob()));
|
||||
}
|
||||
|
@ -534,12 +531,12 @@ void OwncloudPropagator::scheduleNextJob()
|
|||
// one that is likely finished quickly, we can launch another one.
|
||||
// When a job finishes another one will "move up" to be one of the first 3 and then
|
||||
// be counted too.
|
||||
for (int i = 0; i < maximumActiveJob() && i < _activeJobList.count(); i++) {
|
||||
for (int i = 0; i < maximumActiveTransferJob() && i < _activeJobList.count(); i++) {
|
||||
if (_activeJobList.at(i)->isLikelyFinishedQuickly()) {
|
||||
likelyFinishedQuicklyCount++;
|
||||
}
|
||||
}
|
||||
if (_activeJobList.count() < maximumActiveJob() + likelyFinishedQuicklyCount) {
|
||||
if (_activeJobList.count() < maximumActiveTransferJob() + likelyFinishedQuicklyCount) {
|
||||
qDebug() << "Can pump in another request! activeJobs =" << _activeJobList.count();
|
||||
if (_rootJob->scheduleNextJob()) {
|
||||
QTimer::singleShot(0, this, SLOT(scheduleNextJob()));
|
||||
|
@ -588,17 +585,12 @@ OwncloudPropagator *PropagatorJob::propagator() const
|
|||
PropagatorJob::JobParallelism PropagateDirectory::parallelism()
|
||||
{
|
||||
// If any of the non-finished sub jobs is not parallel, we have to wait
|
||||
|
||||
// FIXME! we should probably cache this result
|
||||
|
||||
if (_firstJob && _firstJob->_state != Finished) {
|
||||
if (_firstJob->parallelism() != FullParallelism)
|
||||
return WaitForFinished;
|
||||
if (_firstJob && _firstJob->parallelism() != FullParallelism) {
|
||||
return WaitForFinished;
|
||||
}
|
||||
|
||||
// FIXME: use the cached value of finished job
|
||||
for (int i = 0; i < _subJobs.count(); ++i) {
|
||||
if (_subJobs.at(i)->_state != Finished && _subJobs.at(i)->parallelism() != FullParallelism) {
|
||||
if (_subJobs.at(i)->parallelism() != FullParallelism) {
|
||||
return WaitForFinished;
|
||||
}
|
||||
}
|
||||
|
@ -629,15 +621,8 @@ bool PropagateDirectory::scheduleNextJob()
|
|||
return false;
|
||||
}
|
||||
|
||||
// cache the value of first unfinished subjob
|
||||
bool stopAtDirectory = false;
|
||||
int i = _firstUnfinishedSubJob;
|
||||
int subJobsCount = _subJobs.count();
|
||||
while (i < subJobsCount && _subJobs.at(i)->_state == Finished) {
|
||||
_firstUnfinishedSubJob = ++i;
|
||||
}
|
||||
|
||||
for (int i = _firstUnfinishedSubJob; i < subJobsCount; ++i) {
|
||||
for (int i = 0; i < _subJobs.size(); ++i) {
|
||||
if (_subJobs.at(i)->_state == Finished) {
|
||||
continue;
|
||||
}
|
||||
|
@ -650,7 +635,7 @@ bool PropagateDirectory::scheduleNextJob()
|
|||
return true;
|
||||
}
|
||||
|
||||
Q_ASSERT(_subJobs.at(i)->_state == Running);
|
||||
ASSERT(_subJobs.at(i)->_state == Running);
|
||||
|
||||
auto paral = _subJobs.at(i)->parallelism();
|
||||
if (paral == WaitForFinished) {
|
||||
|
@ -665,8 +650,23 @@ bool PropagateDirectory::scheduleNextJob()
|
|||
|
||||
void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
|
||||
{
|
||||
PropagatorJob *subJob = static_cast<PropagatorJob *>(sender());
|
||||
ASSERT(subJob);
|
||||
|
||||
// Delete the job and remove it from our list of jobs.
|
||||
subJob->deleteLater();
|
||||
bool wasFirstJob = false;
|
||||
if (subJob == _firstJob.data()) {
|
||||
wasFirstJob = true;
|
||||
_firstJob.take();
|
||||
} else {
|
||||
int i = _subJobs.indexOf(subJob);
|
||||
ASSERT(i >= 0);
|
||||
_subJobs.remove(i);
|
||||
}
|
||||
|
||||
if (status == SyncFileItem::FatalError ||
|
||||
(sender() == _firstJob.data() && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
|
||||
(wasFirstJob && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
|
||||
abort();
|
||||
_state = Finished;
|
||||
emit finished(status);
|
||||
|
@ -674,18 +674,10 @@ void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
|
|||
} else if (status == SyncFileItem::NormalError || status == SyncFileItem::SoftError) {
|
||||
_hasError = status;
|
||||
}
|
||||
_runningNow--;
|
||||
_jobsFinished++;
|
||||
|
||||
int totalJobs = _subJobs.count();
|
||||
if (_firstJob) {
|
||||
totalJobs++;
|
||||
}
|
||||
|
||||
// We finished processing all the jobs
|
||||
// check if we finished
|
||||
if (_jobsFinished >= totalJobs) {
|
||||
Q_ASSERT(!_runningNow); // how can we be finished if there are still jobs running now
|
||||
if (!_firstJob && _subJobs.isEmpty()) {
|
||||
finalize();
|
||||
} else {
|
||||
emit ready();
|
||||
|
@ -765,7 +757,7 @@ void CleanupPollsJob::start()
|
|||
void CleanupPollsJob::slotPollFinished()
|
||||
{
|
||||
PollJob *job = qobject_cast<PollJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
if (job->_item->_status == SyncFileItem::FatalError) {
|
||||
emit aborted(job->_item->_errorString);
|
||||
deleteLater();
|
||||
|
|
|
@ -114,7 +114,7 @@ signals:
|
|||
/**
|
||||
* Emitted when one item has been completed within a job.
|
||||
*/
|
||||
void itemCompleted(const SyncFileItem &, const PropagatorJob &);
|
||||
void itemCompleted(const SyncFileItemPtr &);
|
||||
|
||||
/**
|
||||
* Emitted when all the sub-jobs have been finished and
|
||||
|
@ -192,14 +192,11 @@ public:
|
|||
|
||||
SyncFileItemPtr _item;
|
||||
|
||||
int _jobsFinished; // number of jobs that have completed
|
||||
int _runningNow; // number of subJobs running right now
|
||||
SyncFileItem::Status _hasError; // NoStatus, or NormalError / SoftError if there was an error
|
||||
int _firstUnfinishedSubJob;
|
||||
|
||||
explicit PropagateDirectory(OwncloudPropagator *propagator, const SyncFileItemPtr &item = SyncFileItemPtr(new SyncFileItem))
|
||||
: PropagatorJob(propagator)
|
||||
, _firstJob(0), _item(item), _jobsFinished(0), _runningNow(0), _hasError(SyncFileItem::NoStatus), _firstUnfinishedSubJob(0)
|
||||
, _item(item), _hasError(SyncFileItem::NoStatus)
|
||||
{ }
|
||||
|
||||
virtual ~PropagateDirectory() {
|
||||
|
@ -231,11 +228,9 @@ private slots:
|
|||
bool possiblyRunNextJob(PropagatorJob *next) {
|
||||
if (next->_state == NotYetStarted) {
|
||||
connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotSubJobFinished(SyncFileItem::Status)), Qt::QueuedConnection);
|
||||
connect(next, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(next, SIGNAL(itemCompleted(const SyncFileItemPtr &)), this, SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
connect(next, SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
||||
connect(next, SIGNAL(ready()), this, SIGNAL(ready()));
|
||||
_runningNow++;
|
||||
}
|
||||
return next->scheduleNextJob();
|
||||
}
|
||||
|
@ -306,8 +301,9 @@ public:
|
|||
/** We detected that another sync is required after this one */
|
||||
bool _anotherSyncNeeded;
|
||||
|
||||
/* the maximum number of jobs using bandwidth (uploads or downloads, in parallel) */
|
||||
int maximumActiveTransferJob();
|
||||
/* The maximum number of active jobs in parallel */
|
||||
int maximumActiveJob();
|
||||
int hardMaximumActiveJob();
|
||||
|
||||
bool isInSharedDirectory(const QString& file);
|
||||
|
@ -356,7 +352,7 @@ private slots:
|
|||
void scheduleNextJob();
|
||||
|
||||
signals:
|
||||
void itemCompleted(const SyncFileItem &, const PropagatorJob &);
|
||||
void itemCompleted(const SyncFileItemPtr &);
|
||||
void progress(const SyncFileItem&, quint64 bytes);
|
||||
void finished(bool success);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "ownsql.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#define SQLITE_SLEEP_TIME_USEC 100000
|
||||
#define SQLITE_REPEAT_COUNT 20
|
||||
|
@ -147,10 +148,8 @@ void SqlDatabase::close()
|
|||
{
|
||||
if( _db ) {
|
||||
SQLITE_DO(sqlite3_close(_db) );
|
||||
if (_errId != SQLITE_OK) {
|
||||
qWarning() << "ERROR When closing DB" << _error;
|
||||
Q_ASSERT(!"SQLite Close Error");
|
||||
}
|
||||
// Fatal because reopening an unclosed db might be problematic.
|
||||
ENFORCE(_errId == SQLITE_OK, "Error when closing DB");
|
||||
_db = 0;
|
||||
}
|
||||
}
|
||||
|
@ -223,11 +222,7 @@ int SqlQuery::prepare( const QString& sql, bool allow_failure )
|
|||
if( _errId != SQLITE_OK ) {
|
||||
_error = QString::fromUtf8(sqlite3_errmsg(_db));
|
||||
qWarning() << "Sqlite prepare statement error:" << _error << "in" <<_sql;
|
||||
if (!allow_failure) {
|
||||
qFatal("SQLITE Prepare error: %s in %s",
|
||||
_error.toLocal8Bit().data(),
|
||||
sql.toLocal8Bit().data());
|
||||
}
|
||||
ENFORCE(allow_failure, "SQLITE Prepare error");
|
||||
}
|
||||
}
|
||||
return _errId;
|
||||
|
@ -284,61 +279,63 @@ bool SqlQuery::next()
|
|||
void SqlQuery::bindValue(int pos, const QVariant& value)
|
||||
{
|
||||
int res = -1;
|
||||
Q_ASSERT(_stmt);
|
||||
if( _stmt ) {
|
||||
switch (value.type()) {
|
||||
case QVariant::Int:
|
||||
case QVariant::Bool:
|
||||
res = sqlite3_bind_int(_stmt, pos, value.toInt());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
res = sqlite3_bind_double(_stmt, pos, value.toDouble());
|
||||
break;
|
||||
case QVariant::UInt:
|
||||
case QVariant::LongLong:
|
||||
res = sqlite3_bind_int64(_stmt, pos, value.toLongLong());
|
||||
break;
|
||||
case QVariant::DateTime: {
|
||||
const QDateTime dateTime = value.toDateTime();
|
||||
const QString str = dateTime.toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::Time: {
|
||||
const QTime time = value.toTime();
|
||||
const QString str = time.toString(QLatin1String("hh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::String: {
|
||||
if( !value.toString().isNull() ) {
|
||||
// lifetime of string == lifetime of its qvariant
|
||||
const QString *str = static_cast<const QString*>(value.constData());
|
||||
res = sqlite3_bind_text16(_stmt, pos, str->utf16(),
|
||||
(str->size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
} else {
|
||||
res = sqlite3_bind_null(_stmt, pos);
|
||||
}
|
||||
break; }
|
||||
case QVariant::ByteArray: {
|
||||
auto ba = value.toByteArray();
|
||||
res = sqlite3_bind_text(_stmt, pos, ba.constData(), ba.size(), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
QString str = value.toString();
|
||||
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
break; }
|
||||
if (!_stmt) {
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (value.type()) {
|
||||
case QVariant::Int:
|
||||
case QVariant::Bool:
|
||||
res = sqlite3_bind_int(_stmt, pos, value.toInt());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
res = sqlite3_bind_double(_stmt, pos, value.toDouble());
|
||||
break;
|
||||
case QVariant::UInt:
|
||||
case QVariant::LongLong:
|
||||
res = sqlite3_bind_int64(_stmt, pos, value.toLongLong());
|
||||
break;
|
||||
case QVariant::DateTime: {
|
||||
const QDateTime dateTime = value.toDateTime();
|
||||
const QString str = dateTime.toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::Time: {
|
||||
const QTime time = value.toTime();
|
||||
const QString str = time.toString(QLatin1String("hh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::String: {
|
||||
if( !value.toString().isNull() ) {
|
||||
// lifetime of string == lifetime of its qvariant
|
||||
const QString *str = static_cast<const QString*>(value.constData());
|
||||
res = sqlite3_bind_text16(_stmt, pos, str->utf16(),
|
||||
(str->size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
} else {
|
||||
res = sqlite3_bind_null(_stmt, pos);
|
||||
}
|
||||
break; }
|
||||
case QVariant::ByteArray: {
|
||||
auto ba = value.toByteArray();
|
||||
res = sqlite3_bind_text(_stmt, pos, ba.constData(), ba.size(), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
QString str = value.toString();
|
||||
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
break; }
|
||||
}
|
||||
if (res != SQLITE_OK) {
|
||||
qDebug() << Q_FUNC_INFO << "ERROR" << value << res;
|
||||
}
|
||||
Q_ASSERT( res == SQLITE_OK );
|
||||
ASSERT( res == SQLITE_OK );
|
||||
}
|
||||
|
||||
bool SqlQuery::nullValue(int index)
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
|
||||
namespace OCC {
|
||||
|
||||
class PropagatorJob;
|
||||
|
||||
/**
|
||||
* @brief The ProgressInfo class
|
||||
* @ingroup libsync
|
||||
|
@ -252,9 +250,7 @@ signals:
|
|||
/**
|
||||
* @brief: the item was completed by a job
|
||||
*/
|
||||
void itemCompleted(const QString &folder,
|
||||
const SyncFileItem & item,
|
||||
const PropagatorJob & job);
|
||||
void itemCompleted(const QString &folder, const SyncFileItemPtr & item);
|
||||
|
||||
protected:
|
||||
void setProgressInfo(const QString& folder, const ProgressInfo& progress);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "filesystem.h"
|
||||
#include "propagatorjobs.h"
|
||||
#include "checksums.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <json.h>
|
||||
#include <QNetworkAccessManager>
|
||||
|
@ -441,7 +442,7 @@ void PropagateDownloadFile::slotGetFinished()
|
|||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
GETFileJob *job = qobject_cast<GETFileJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< job->reply()->error()
|
||||
|
@ -520,7 +521,6 @@ void PropagateDownloadFile::slotGetFinished()
|
|||
// so make sure we have the up-to-date time
|
||||
_item->_modtime = job->lastModified();
|
||||
}
|
||||
_item->_requestDuration = job->duration();
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
|
||||
_tmpFile.close();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "propagateremotedelete.h"
|
||||
#include "owncloudpropagator_p.h"
|
||||
#include "account.h"
|
||||
#include "asserts.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
@ -81,7 +82,7 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
|||
{
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
Q_ASSERT(_job);
|
||||
ASSERT(_job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< _job->reply()->error()
|
||||
|
@ -104,7 +105,6 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
|||
return;
|
||||
}
|
||||
|
||||
_item->_requestDuration = _job->duration();
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
|
||||
// A 404 reply is also considered a success here: We want to make sure
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "account.h"
|
||||
#include "syncjournalfilerecord.h"
|
||||
#include "propagateremotedelete.h"
|
||||
#include "asserts.h"
|
||||
#include <QFile>
|
||||
|
||||
namespace OCC {
|
||||
|
@ -70,7 +71,7 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
|||
{
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
Q_ASSERT(_job);
|
||||
ASSERT(_job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< _job->reply()->error()
|
||||
|
@ -99,7 +100,6 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
|||
return;
|
||||
}
|
||||
|
||||
_item->_requestDuration = _job->duration();
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
_item->_fileId = _job->reply()->rawHeader("OC-FileId");
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "account.h"
|
||||
#include "syncjournalfilerecord.h"
|
||||
#include "filesystem.h"
|
||||
#include "asserts.h"
|
||||
#include <QFile>
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
|
@ -123,7 +124,7 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
|||
{
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
Q_ASSERT(_job);
|
||||
ASSERT(_job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< _job->reply()->error()
|
||||
|
@ -145,7 +146,6 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
|||
return;
|
||||
}
|
||||
|
||||
_item->_requestDuration = _job->duration();
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
|
||||
if (_item->_httpErrorCode != 201 ) {
|
||||
|
@ -208,8 +208,8 @@ bool PropagateRemoteMove::adjustSelectiveSync(SyncJournalDb *journal, const QStr
|
|||
return false;
|
||||
|
||||
bool changed = false;
|
||||
Q_ASSERT(!from_.endsWith(QLatin1String("/")));
|
||||
Q_ASSERT(!to_.endsWith(QLatin1String("/")));
|
||||
ASSERT(!from_.endsWith(QLatin1String("/")));
|
||||
ASSERT(!to_.endsWith(QLatin1String("/")));
|
||||
QString from = from_ + QLatin1String("/");
|
||||
QString to = to_ + QLatin1String("/");
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "checksums.h"
|
||||
#include "syncengine.h"
|
||||
#include "propagateremotedelete.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <json.h>
|
||||
#include <QNetworkAccessManager>
|
||||
|
@ -224,7 +225,9 @@ void PropagateUploadFileCommon::slotComputeContentChecksum()
|
|||
// change during the checksum calculation
|
||||
_item->_modtime = FileSystem::getModTime(filePath);
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
_stopWatch.start();
|
||||
#endif
|
||||
|
||||
QByteArray checksumType = contentChecksumType();
|
||||
|
||||
|
@ -251,8 +254,10 @@ void PropagateUploadFileCommon::slotComputeTransmissionChecksum(const QByteArray
|
|||
_item->_contentChecksum = contentChecksum;
|
||||
_item->_contentChecksumType = contentChecksumType;
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
_stopWatch.addLapTime(QLatin1String("ContentChecksum"));
|
||||
_stopWatch.start();
|
||||
#endif
|
||||
|
||||
// Reuse the content checksum as the transmission checksum if possible
|
||||
const auto supportedTransmissionChecksums =
|
||||
|
@ -299,7 +304,9 @@ void PropagateUploadFileCommon::slotStartUpload(const QByteArray& transmissionCh
|
|||
done(SyncFileItem::SoftError, tr("File Removed"));
|
||||
return;
|
||||
}
|
||||
#ifdef WITH_TESTING
|
||||
_stopWatch.addLapTime(QLatin1String("TransmissionChecksum"));
|
||||
#endif
|
||||
|
||||
time_t prevModtime = _item->_modtime; // the _item value was set in PropagateUploadFile::start()
|
||||
// but a potential checksum calculation could have taken some time during which the file could
|
||||
|
@ -369,7 +376,7 @@ bool UploadDevice::prepareAndOpen(const QString& fileName, qint64 start, qint64
|
|||
|
||||
|
||||
qint64 UploadDevice::writeData(const char* , qint64 ) {
|
||||
Q_ASSERT(!"write to read only device");
|
||||
ASSERT(false, "write to read only device");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -480,7 +487,7 @@ void PropagateUploadFileCommon::startPollJob(const QString& path)
|
|||
void PropagateUploadFileCommon::slotPollFinished()
|
||||
{
|
||||
PollJob *job = qobject_cast<PollJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
|
@ -569,7 +576,6 @@ QMap<QByteArray, QByteArray> PropagateUploadFileCommon::headers()
|
|||
|
||||
void PropagateUploadFileCommon::finalize()
|
||||
{
|
||||
_item->_requestDuration = _duration.elapsed();
|
||||
_finished = true;
|
||||
|
||||
if (!propagator()->_journal->setFileRecord(SyncJournalFileRecord(*_item, propagator()->getFilePath(_item->_file)))) {
|
||||
|
|
|
@ -183,13 +183,14 @@ class PropagateUploadFileCommon : public PropagateItemJob {
|
|||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
QElapsedTimer _duration;
|
||||
QVector<AbstractNetworkJob*> _jobs; /// network jobs that are currently in transit
|
||||
bool _finished; /// Tells that all the jobs have been finished
|
||||
bool _deleteExisting;
|
||||
bool _finished BITFIELD(1); /// Tells that all the jobs have been finished
|
||||
bool _deleteExisting BITFIELD(1);
|
||||
|
||||
// measure the performance of checksum calc and upload
|
||||
#ifdef WITH_TESTING
|
||||
Utility::StopWatch _stopWatch;
|
||||
#endif
|
||||
|
||||
QByteArray _transmissionChecksum;
|
||||
QByteArray _transmissionChecksumType;
|
||||
|
@ -300,7 +301,8 @@ private:
|
|||
|
||||
// Map chunk number with its size from the PROPFIND on resume.
|
||||
// (Only used from slotPropfindIterate/slotPropfindFinished because the LsColJob use signals to report data.)
|
||||
QMap<int, quint64> _serverChunks;
|
||||
struct ServerChunkInfo { quint64 size; QString originalName; };
|
||||
QMap<int, ServerChunkInfo> _serverChunks;
|
||||
|
||||
quint64 chunkSize() const { return propagator()->chunkSize(); }
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "syncengine.h"
|
||||
#include "propagateremotemove.h"
|
||||
#include "propagateremotedelete.h"
|
||||
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QFileInfo>
|
||||
|
@ -41,7 +41,8 @@ QUrl PropagateUploadFileNG::chunkUrl(int chunk)
|
|||
+ propagator()->account()->davUser()
|
||||
+ QLatin1Char('/') + QString::number(_transferId);
|
||||
if (chunk >= 0) {
|
||||
path += QLatin1Char('/') + QString::number(chunk);
|
||||
// We need to do add leading 0 because the server orders the chunk alphabetically
|
||||
path += QLatin1Char('/') + QString::number(chunk).rightJustified(8, '0');
|
||||
}
|
||||
return Utility::concatUrlPath(propagator()->account()->url(), path);
|
||||
}
|
||||
|
@ -79,7 +80,6 @@ QUrl PropagateUploadFileNG::chunkUrl(int chunk)
|
|||
|
||||
void PropagateUploadFileNG::doStartUpload()
|
||||
{
|
||||
_duration.start();
|
||||
propagator()->_activeJobList.append(this);
|
||||
|
||||
const SyncJournalDb::UploadInfo progressInfo = propagator()->_journal->getUploadInfo(_item->_file);
|
||||
|
@ -97,6 +97,12 @@ void PropagateUploadFileNG::doStartUpload()
|
|||
this, SLOT(slotPropfindIterate(QString,QMap<QString,QString>)));
|
||||
job->start();
|
||||
return;
|
||||
} else if (progressInfo._valid) {
|
||||
// The upload info is stale. remove the stale chunks on the server
|
||||
_transferId = progressInfo._transferid;
|
||||
// Fire and forget. Any error will be ignored.
|
||||
(new DeleteJob(propagator()->account(), chunkUrl(), this))->start();
|
||||
// startNewUpload will reset the _transferId and the UploadInfo in the db.
|
||||
}
|
||||
|
||||
startNewUpload();
|
||||
|
@ -108,9 +114,11 @@ void PropagateUploadFileNG::slotPropfindIterate(const QString &name, const QMap<
|
|||
return; // skip the info about the path itself
|
||||
}
|
||||
bool ok = false;
|
||||
auto chunkId = name.mid(name.lastIndexOf('/')+1).toUInt(&ok);
|
||||
QString chunkName = name.mid(name.lastIndexOf('/')+1);
|
||||
auto chunkId = chunkName.toUInt(&ok);
|
||||
if (ok) {
|
||||
_serverChunks[chunkId] = properties["getcontentlength"].toULongLong();
|
||||
ServerChunkInfo chunkinfo = { properties["getcontentlength"].toULongLong(), chunkName };
|
||||
_serverChunks[chunkId] = chunkinfo;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +131,7 @@ void PropagateUploadFileNG::slotPropfindFinished()
|
|||
_currentChunk = 0;
|
||||
_sent = 0;
|
||||
while (_serverChunks.contains(_currentChunk)) {
|
||||
_sent += _serverChunks[_currentChunk];
|
||||
_sent += _serverChunks[_currentChunk].size;
|
||||
_serverChunks.remove(_currentChunk);
|
||||
++_currentChunk;
|
||||
}
|
||||
|
@ -141,7 +149,7 @@ void PropagateUploadFileNG::slotPropfindFinished()
|
|||
qDebug() << "Resuming "<< _item->_file << " from chunk " << _currentChunk << "; sent ="<< _sent;
|
||||
|
||||
if (!_serverChunks.isEmpty()) {
|
||||
qDebug() << "To Delete" << _serverChunks;
|
||||
qDebug() << "To Delete" << _serverChunks.keys();
|
||||
propagator()->_activeJobList.append(this);
|
||||
_removeJobError = false;
|
||||
|
||||
|
@ -149,7 +157,7 @@ void PropagateUploadFileNG::slotPropfindFinished()
|
|||
// we should remove the later chunks. Otherwise when we do dynamic chunk sizing, we may end up
|
||||
// with corruptions if there are too many chunks, or if we abort and there are still stale chunks.
|
||||
for (auto it = _serverChunks.begin(); it != _serverChunks.end(); ++it) {
|
||||
auto job = new DeleteJob(propagator()->account(), Utility::concatUrlPath(chunkUrl(), QString::number(it.key())), this);
|
||||
auto job = new DeleteJob(propagator()->account(), Utility::concatUrlPath(chunkUrl(), it->originalName), this);
|
||||
QObject::connect(job, SIGNAL(finishedSignal()), this, SLOT(slotDeleteJobFinished()));
|
||||
_jobs.append(job);
|
||||
job->start();
|
||||
|
@ -180,7 +188,7 @@ void PropagateUploadFileNG::slotPropfindFinishedWithError()
|
|||
void PropagateUploadFileNG::slotDeleteJobFinished()
|
||||
{
|
||||
auto job = qobject_cast<DeleteJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
_jobs.remove(_jobs.indexOf(job));
|
||||
|
||||
QNetworkReply::NetworkError err = job->reply()->error();
|
||||
|
@ -212,7 +220,7 @@ void PropagateUploadFileNG::slotDeleteJobFinished()
|
|||
|
||||
void PropagateUploadFileNG::startNewUpload()
|
||||
{
|
||||
Q_ASSERT(propagator()->_activeJobList.count(this) == 1);
|
||||
ASSERT(propagator()->_activeJobList.count(this) == 1);
|
||||
_transferId = qrand() ^ _item->_modtime ^ (_item->_size << 16) ^ qHash(_item->_file);
|
||||
_sent = 0;
|
||||
_currentChunk = 0;
|
||||
|
@ -262,11 +270,12 @@ void PropagateUploadFileNG::startNextChunk()
|
|||
return;
|
||||
|
||||
quint64 fileSize = _item->_size;
|
||||
Q_ASSERT(fileSize >= _sent);
|
||||
ENFORCE(fileSize >= _sent, "Sent data exceeds file size");
|
||||
|
||||
quint64 currentChunkSize = qMin(chunkSize(), fileSize - _sent);
|
||||
|
||||
if (currentChunkSize == 0) {
|
||||
Q_ASSERT(_jobs.isEmpty()); // There should be no running job anymore
|
||||
ASSERT(_jobs.isEmpty());
|
||||
_finished = true;
|
||||
// Finish with a MOVE
|
||||
QString destination = QDir::cleanPath(propagator()->account()->url().path() + QLatin1Char('/')
|
||||
|
@ -335,7 +344,8 @@ void PropagateUploadFileNG::startNextChunk()
|
|||
void PropagateUploadFileNG::slotPutFinished()
|
||||
{
|
||||
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
|
||||
slotJobDestroyed(job); // remove it from the _jobs list
|
||||
|
||||
qDebug() << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
|
@ -383,7 +393,7 @@ void PropagateUploadFileNG::slotPutFinished()
|
|||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(_sent <= _item->_size);
|
||||
ENFORCE(_sent <= _item->_size, "can't send more than size");
|
||||
bool finished = _sent == _item->_size;
|
||||
|
||||
// Check if the file still exists
|
||||
|
@ -475,14 +485,16 @@ void PropagateUploadFileNG::slotMoveJobFinished()
|
|||
}
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
// performance logging
|
||||
_item->_requestDuration = _stopWatch.stop();
|
||||
quint64 duration = _stopWatch.stop();
|
||||
qDebug() << "*==* duration UPLOAD" << _item->_size
|
||||
<< _stopWatch.durationOfLap(QLatin1String("ContentChecksum"))
|
||||
<< _stopWatch.durationOfLap(QLatin1String("TransmissionChecksum"))
|
||||
<< _item->_requestDuration;
|
||||
<< duration;
|
||||
// The job might stay alive for the whole sync, release this tiny bit of memory.
|
||||
_stopWatch.reset();
|
||||
#endif
|
||||
finalize();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "checksums.h"
|
||||
#include "syncengine.h"
|
||||
#include "propagateremotedelete.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <json.h>
|
||||
#include <QNetworkAccessManager>
|
||||
|
@ -49,7 +50,6 @@ void PropagateUploadFileV1::doStartUpload()
|
|||
}
|
||||
|
||||
_currentChunk = 0;
|
||||
_duration.start();
|
||||
|
||||
emit progress(*_item, 0);
|
||||
startNextChunk();
|
||||
|
@ -160,7 +160,7 @@ void PropagateUploadFileV1::startNextChunk()
|
|||
parallelChunkUpload = false;
|
||||
}
|
||||
|
||||
if (parallelChunkUpload && (propagator()->_activeJobList.count() < propagator()->maximumActiveJob())
|
||||
if (parallelChunkUpload && (propagator()->_activeJobList.count() < propagator()->maximumActiveTransferJob())
|
||||
&& _currentChunk < _chunkCount ) {
|
||||
startNextChunk();
|
||||
}
|
||||
|
@ -172,7 +172,8 @@ void PropagateUploadFileV1::startNextChunk()
|
|||
void PropagateUploadFileV1::slotPutFinished()
|
||||
{
|
||||
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
|
||||
slotJobDestroyed(job); // remove it from the _jobs list
|
||||
|
||||
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
|
@ -340,14 +341,16 @@ void PropagateUploadFileV1::slotPutFinished()
|
|||
done(SyncFileItem::SoftError, "Server does not support X-OC-MTime");
|
||||
}
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
// performance logging
|
||||
_item->_requestDuration = _stopWatch.stop();
|
||||
quint64 duration = _stopWatch.stop();
|
||||
qDebug() << "*==* duration UPLOAD" << _item->_size
|
||||
<< _stopWatch.durationOfLap(QLatin1String("ContentChecksum"))
|
||||
<< _stopWatch.durationOfLap(QLatin1String("TransmissionChecksum"))
|
||||
<< _item->_requestDuration;
|
||||
<< duration;
|
||||
// The job might stay alive for the whole sync, release this tiny bit of memory.
|
||||
_stopWatch.reset();
|
||||
#endif
|
||||
|
||||
finalize();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "syncfilestatus.h"
|
||||
#include "csync_private.h"
|
||||
#include "filesystem.h"
|
||||
#include "propagateremotedelete.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
|
@ -71,18 +73,18 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath,
|
|||
, _backInTimeFiles(0)
|
||||
, _uploadLimit(0)
|
||||
, _downloadLimit(0)
|
||||
, _newBigFolderSizeLimit(-1)
|
||||
, _checksum_hook(journal)
|
||||
, _anotherSyncNeeded(NoFollowUpSync)
|
||||
{
|
||||
qRegisterMetaType<SyncFileItem>("SyncFileItem");
|
||||
qRegisterMetaType<SyncFileItemPtr>("SyncFileItemPtr");
|
||||
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
|
||||
qRegisterMetaType<SyncFileStatus>("SyncFileStatus");
|
||||
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
||||
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
||||
|
||||
// Everything in the SyncEngine expects a trailing slash for the localPath.
|
||||
Q_ASSERT(localPath.endsWith(QLatin1Char('/')));
|
||||
ASSERT(localPath.endsWith(QLatin1Char('/')));
|
||||
|
||||
csync_create(&_csync_ctx, localPath.toUtf8().data());
|
||||
|
||||
|
@ -266,11 +268,11 @@ bool SyncEngine::checkErrorBlacklisting( SyncFileItem &item )
|
|||
return true;
|
||||
}
|
||||
|
||||
void SyncEngine::deleteStaleDownloadInfos()
|
||||
void SyncEngine::deleteStaleDownloadInfos(const SyncFileItemVector &syncItems)
|
||||
{
|
||||
// Find all downloadinfo paths that we want to preserve.
|
||||
QSet<QString> download_file_paths;
|
||||
foreach(const SyncFileItemPtr &it, _syncedItems) {
|
||||
foreach(const SyncFileItemPtr &it, syncItems) {
|
||||
if (it->_direction == SyncFileItem::Down
|
||||
&& it->_type == SyncFileItem::File)
|
||||
{
|
||||
|
@ -288,11 +290,11 @@ void SyncEngine::deleteStaleDownloadInfos()
|
|||
}
|
||||
}
|
||||
|
||||
void SyncEngine::deleteStaleUploadInfos()
|
||||
void SyncEngine::deleteStaleUploadInfos(const SyncFileItemVector &syncItems)
|
||||
{
|
||||
// Find all blacklisted paths that we want to preserve.
|
||||
QSet<QString> upload_file_paths;
|
||||
foreach(const SyncFileItemPtr &it, _syncedItems) {
|
||||
foreach(const SyncFileItemPtr &it, syncItems) {
|
||||
if (it->_direction == SyncFileItem::Up
|
||||
&& it->_type == SyncFileItem::File)
|
||||
{
|
||||
|
@ -301,14 +303,23 @@ void SyncEngine::deleteStaleUploadInfos()
|
|||
}
|
||||
|
||||
// Delete from journal.
|
||||
_journal->deleteStaleUploadInfos(upload_file_paths);
|
||||
auto ids = _journal->deleteStaleUploadInfos(upload_file_paths);
|
||||
|
||||
// Delete the stales chunk on the server.
|
||||
if (account()->capabilities().chunkingNg()) {
|
||||
foreach (uint transferId, ids) {
|
||||
QUrl url = Utility::concatUrlPath(account()->url(), QLatin1String("remote.php/dav/uploads/")
|
||||
+ account()->davUser() + QLatin1Char('/') + QString::number(transferId));
|
||||
(new DeleteJob(account(), url, this))->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SyncEngine::deleteStaleErrorBlacklistEntries()
|
||||
void SyncEngine::deleteStaleErrorBlacklistEntries(const SyncFileItemVector &syncItems)
|
||||
{
|
||||
// Find all blacklisted paths that we want to preserve.
|
||||
QSet<QString> blacklist_file_paths;
|
||||
foreach(const SyncFileItemPtr &it, _syncedItems) {
|
||||
foreach(const SyncFileItemPtr &it, syncItems) {
|
||||
if (it->_hasBlacklistEntry)
|
||||
blacklist_file_paths.insert(it->_file);
|
||||
}
|
||||
|
@ -343,7 +354,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||
|
||||
QTextCodec::ConverterState utf8State;
|
||||
static QTextCodec *codec = QTextCodec::codecForName("UTF-8");
|
||||
Q_ASSERT(codec);
|
||||
ASSERT(codec);
|
||||
QString fileUtf8 = codec->toUnicode(file->path, qstrlen(file->path), &utf8State);
|
||||
QString renameTarget;
|
||||
QString key = fileUtf8;
|
||||
|
@ -379,9 +390,11 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||
item->_modtime = file->modtime;
|
||||
} else {
|
||||
if (instruction != CSYNC_INSTRUCTION_NONE) {
|
||||
qDebug() << "ERROR: Instruction" << item->_instruction << "vs" << instruction << "for" << fileUtf8;
|
||||
Q_ASSERT(!"Instructions are both unequal NONE");
|
||||
return -1;
|
||||
qWarning() << "ERROR: Instruction" << item->_instruction << "vs" << instruction << "for" << fileUtf8;
|
||||
ASSERT(false);
|
||||
// Set instruction to NONE for safety.
|
||||
file->instruction = item->_instruction = instruction = CSYNC_INSTRUCTION_NONE;
|
||||
return -1; // should lead to treewalk error
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,6 +409,8 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||
}
|
||||
if (file->remotePerm && file->remotePerm[0]) {
|
||||
item->_remotePerm = QByteArray(file->remotePerm);
|
||||
if (remote)
|
||||
_remotePerms[item->_file] = item->_remotePerm;
|
||||
}
|
||||
|
||||
/* The flag "serverHasIgnoredFiles" is true if item in question is a directory
|
||||
|
@ -426,10 +441,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||
_seenFiles.insert(renameTarget);
|
||||
}
|
||||
|
||||
if (remote && file->remotePerm && file->remotePerm[0]) {
|
||||
_remotePerms[item->_file] = file->remotePerm;
|
||||
}
|
||||
|
||||
switch(file->error_status) {
|
||||
case CSYNC_STATUS_OK:
|
||||
break;
|
||||
|
@ -491,7 +502,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||
item->_status = SyncFileItem::SoftError;
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT("Non handled error-status");
|
||||
ASSERT(false, "Non handled error-status");
|
||||
/* No error string */
|
||||
}
|
||||
|
||||
|
@ -642,12 +653,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||
|
||||
_needsUpdate = true;
|
||||
|
||||
item->log._etag = file->etag;
|
||||
item->log._fileId = file->file_id;
|
||||
item->log._instruction = file->instruction;
|
||||
item->log._modtime = file->modtime;
|
||||
item->log._size = file->size;
|
||||
|
||||
item->log._other_etag = file->other.etag;
|
||||
item->log._other_fileId = file->other.file_id;
|
||||
item->log._other_instruction = file->other.instruction;
|
||||
|
@ -707,8 +712,11 @@ void SyncEngine::startSync()
|
|||
}
|
||||
}
|
||||
|
||||
Q_ASSERT(!s_anySyncRunning);
|
||||
Q_ASSERT(!_syncRunning);
|
||||
if (s_anySyncRunning || _syncRunning) {
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
s_anySyncRunning = true;
|
||||
_syncRunning = true;
|
||||
_anotherSyncNeeded = NoFollowUpSync;
|
||||
|
@ -743,7 +751,6 @@ void SyncEngine::startSync()
|
|||
qDebug() << "Could not determine free space available at" << _localPath;
|
||||
}
|
||||
|
||||
_syncedItems.clear();
|
||||
_syncItemMap.clear();
|
||||
_needsUpdate = false;
|
||||
|
||||
|
@ -830,14 +837,14 @@ void SyncEngine::startSync()
|
|||
return;
|
||||
}
|
||||
|
||||
discoveryJob->_newBigFolderSizeLimit = _newBigFolderSizeLimit;
|
||||
discoveryJob->_syncOptions = _syncOptions;
|
||||
discoveryJob->moveToThread(&_thread);
|
||||
connect(discoveryJob, SIGNAL(finished(int)), this, SLOT(slotDiscoveryJobFinished(int)));
|
||||
connect(discoveryJob, SIGNAL(folderDiscovered(bool,QString)),
|
||||
this, SIGNAL(folderDiscovered(bool,QString)));
|
||||
|
||||
connect(discoveryJob, SIGNAL(newBigFolder(QString)),
|
||||
this, SIGNAL(newBigFolder(QString)));
|
||||
connect(discoveryJob, SIGNAL(newBigFolder(QString,bool)),
|
||||
this, SIGNAL(newBigFolder(QString,bool)));
|
||||
|
||||
|
||||
// This is used for the DiscoveryJob to be able to request the main thread/
|
||||
|
@ -890,6 +897,8 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||
_hasForwardInTimeFiles = false;
|
||||
_backInTimeFiles = 0;
|
||||
bool walkOk = true;
|
||||
_remotePerms.clear();
|
||||
_remotePerms.reserve(c_rbtree_size(_csync_ctx->remote.tree));
|
||||
_seenFiles.clear();
|
||||
_temporarilyUnavailablePaths.clear();
|
||||
_renamedFolders.clear();
|
||||
|
@ -911,12 +920,12 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||
csync_commit(_csync_ctx);
|
||||
|
||||
// The map was used for merging trees, convert it to a list:
|
||||
_syncedItems = _syncItemMap.values().toVector();
|
||||
SyncFileItemVector syncItems = _syncItemMap.values().toVector();
|
||||
_syncItemMap.clear(); // free memory
|
||||
|
||||
// Adjust the paths for the renames.
|
||||
for (SyncFileItemVector::iterator it = _syncedItems.begin();
|
||||
it != _syncedItems.end(); ++it) {
|
||||
for (SyncFileItemVector::iterator it = syncItems.begin();
|
||||
it != syncItems.end(); ++it) {
|
||||
(*it)->_file = adjustRenamedPath((*it)->_file);
|
||||
}
|
||||
|
||||
|
@ -924,7 +933,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||
if (_account->serverVersionInt() < 0x080100) {
|
||||
// Server version older than 8.1 don't support these character in filename.
|
||||
static const QRegExp invalidCharRx("[\\\\:?*\"<>|]");
|
||||
for (auto it = _syncedItems.begin(); it != _syncedItems.end(); ++it) {
|
||||
for (auto it = syncItems.begin(); it != syncItems.end(); ++it) {
|
||||
if ((*it)->_direction == SyncFileItem::Up &&
|
||||
(*it)->destination().contains(invalidCharRx)) {
|
||||
(*it)->_errorString = tr("File name contains at least one invalid character");
|
||||
|
@ -936,7 +945,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||
if (!_hasNoneFiles && _hasRemoveFile) {
|
||||
qDebug() << Q_FUNC_INFO << "All the files are going to be changed, asking the user";
|
||||
bool cancel = false;
|
||||
emit aboutToRemoveAllFiles(_syncedItems.first()->_direction, &cancel);
|
||||
emit aboutToRemoveAllFiles(syncItems.first()->_direction, &cancel);
|
||||
if (cancel) {
|
||||
qDebug() << Q_FUNC_INFO << "Abort sync";
|
||||
finalize(false);
|
||||
|
@ -951,7 +960,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||
if (!databaseFingerprint.isNull()
|
||||
&& _discoveryMainThread->_dataFingerprint != databaseFingerprint) {
|
||||
qDebug() << "data fingerprint changed, assume restore from backup" << databaseFingerprint << _discoveryMainThread->_dataFingerprint;
|
||||
restoreOldFiles();
|
||||
restoreOldFiles(syncItems);
|
||||
} else if (!_hasForwardInTimeFiles && _backInTimeFiles >= 2 && _account->serverVersionInt() < 0x090100) {
|
||||
// The server before ownCloud 9.1 did not have the data-fingerprint property. So in that
|
||||
// case we use heuristics to detect restored backup. This is disabled with newer version
|
||||
|
@ -961,18 +970,18 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||
bool restore = false;
|
||||
emit aboutToRestoreBackup(&restore);
|
||||
if (restore) {
|
||||
restoreOldFiles();
|
||||
restoreOldFiles(syncItems);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort items per destination
|
||||
std::sort(_syncedItems.begin(), _syncedItems.end());
|
||||
std::sort(syncItems.begin(), syncItems.end());
|
||||
|
||||
// make sure everything is allowed
|
||||
checkForPermission();
|
||||
checkForPermission(syncItems);
|
||||
|
||||
// To announce the beginning of the sync
|
||||
emit aboutToPropagate(_syncedItems);
|
||||
emit aboutToPropagate(syncItems);
|
||||
// it's important to do this before ProgressInfo::start(), to announce start of new sync
|
||||
emit transmissionProgress(*_progressInfo);
|
||||
_progressInfo->startEstimateUpdates();
|
||||
|
@ -994,8 +1003,8 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||
|
||||
_propagator = QSharedPointer<OwncloudPropagator>(
|
||||
new OwncloudPropagator (_account, _localPath, _remotePath, _journal));
|
||||
connect(_propagator.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_propagator.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItemPtr &)));
|
||||
connect(_propagator.data(), SIGNAL(progress(const SyncFileItem &,quint64)),
|
||||
this, SLOT(slotProgress(const SyncFileItem &,quint64)));
|
||||
connect(_propagator.data(), SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)), Qt::QueuedConnection);
|
||||
|
@ -1005,16 +1014,16 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
|||
// apply the network limits to the propagator
|
||||
setNetworkLimits(_uploadLimit, _downloadLimit);
|
||||
|
||||
deleteStaleDownloadInfos();
|
||||
deleteStaleUploadInfos();
|
||||
deleteStaleErrorBlacklistEntries();
|
||||
deleteStaleDownloadInfos(syncItems);
|
||||
deleteStaleUploadInfos(syncItems);
|
||||
deleteStaleErrorBlacklistEntries(syncItems);
|
||||
_journal->commit("post stale entry removal");
|
||||
|
||||
// Emit the started signal only after the propagator has been set up.
|
||||
if (_needsUpdate)
|
||||
emit(started());
|
||||
|
||||
_propagator->start(_syncedItems);
|
||||
_propagator->start(syncItems);
|
||||
|
||||
qDebug() << "<<#### Post-Reconcile end #################################################### " << _stopWatch.addLapTime(QLatin1String("Post-Reconcile Finished"));
|
||||
}
|
||||
|
@ -1051,19 +1060,19 @@ void SyncEngine::setNetworkLimits(int upload, int download)
|
|||
}
|
||||
}
|
||||
|
||||
void SyncEngine::slotItemCompleted(const SyncFileItem &item, const PropagatorJob &job)
|
||||
void SyncEngine::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
{
|
||||
const char * instruction_str = csync_instruction_str(item._instruction);
|
||||
qDebug() << Q_FUNC_INFO << item._file << instruction_str << item._status << item._errorString;
|
||||
const char * instruction_str = csync_instruction_str(item->_instruction);
|
||||
qDebug() << Q_FUNC_INFO << item->_file << instruction_str << item->_status << item->_errorString;
|
||||
|
||||
_progressInfo->setProgressComplete(item);
|
||||
_progressInfo->setProgressComplete(*item);
|
||||
|
||||
if (item._status == SyncFileItem::FatalError) {
|
||||
emit csyncError(item._errorString);
|
||||
if (item->_status == SyncFileItem::FatalError) {
|
||||
emit csyncError(item->_errorString);
|
||||
}
|
||||
|
||||
emit transmissionProgress(*_progressInfo);
|
||||
emit itemCompleted(item, job);
|
||||
emit itemCompleted(item);
|
||||
}
|
||||
|
||||
void SyncEngine::slotFinished(bool success)
|
||||
|
@ -1084,10 +1093,11 @@ void SyncEngine::slotFinished(bool success)
|
|||
_journal->commit("All Finished.", false);
|
||||
|
||||
// Send final progress information even if no
|
||||
// files needed propagation
|
||||
// files needed propagation, but clear the lastCompletedItem
|
||||
// so we don't count this twice (like Recent Files)
|
||||
_progressInfo->_lastCompletedItem = SyncFileItem();
|
||||
emit transmissionProgress(*_progressInfo);
|
||||
|
||||
emit treeWalkResult(_syncedItems);
|
||||
finalize(success);
|
||||
}
|
||||
|
||||
|
@ -1108,6 +1118,10 @@ void SyncEngine::finalize(bool success)
|
|||
|
||||
// Delete the propagator only after emitting the signal.
|
||||
_propagator.clear();
|
||||
_remotePerms.clear();
|
||||
_seenFiles.clear();
|
||||
_temporarilyUnavailablePaths.clear();
|
||||
_renamedFolders.clear();
|
||||
|
||||
_clearTouchedFilesTimer.start();
|
||||
}
|
||||
|
@ -1137,13 +1151,13 @@ QString SyncEngine::adjustRenamedPath(const QString& original)
|
|||
* Make sure that we are allowed to do what we do by checking the permissions and the selective sync list
|
||||
*
|
||||
*/
|
||||
void SyncEngine::checkForPermission()
|
||||
void SyncEngine::checkForPermission(SyncFileItemVector &syncItems)
|
||||
{
|
||||
bool selectiveListOk;
|
||||
auto selectiveSyncBlackList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &selectiveListOk);
|
||||
std::sort(selectiveSyncBlackList.begin(), selectiveSyncBlackList.end());
|
||||
|
||||
for (SyncFileItemVector::iterator it = _syncedItems.begin(); it != _syncedItems.end(); ++it) {
|
||||
for (SyncFileItemVector::iterator it = syncItems.begin(); it != syncItems.end(); ++it) {
|
||||
if ((*it)->_direction != SyncFileItem::Up) {
|
||||
// Currently we only check server-side permissions
|
||||
continue;
|
||||
|
@ -1160,7 +1174,7 @@ void SyncEngine::checkForPermission()
|
|||
(*it)->_errorString = tr("Ignored because of the \"choose what to sync\" blacklist");
|
||||
|
||||
if ((*it)->_isDirectory) {
|
||||
for (SyncFileItemVector::iterator it_next = it + 1; it_next != _syncedItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
for (SyncFileItemVector::iterator it_next = it + 1; it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||
(*it)->_status = SyncFileItem::FileIgnored;
|
||||
|
@ -1185,7 +1199,7 @@ void SyncEngine::checkForPermission()
|
|||
(*it)->_status = SyncFileItem::NormalError;
|
||||
(*it)->_errorString = tr("Not allowed because you don't have permission to add subfolders to that folder");
|
||||
|
||||
for (SyncFileItemVector::iterator it_next = it + 1; it_next != _syncedItems.end() && (*it_next)->destination().startsWith(path); ++it_next) {
|
||||
for (SyncFileItemVector::iterator it_next = it + 1; it_next != syncItems.end() && (*it_next)->destination().startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
if ((*it)->_instruction == CSYNC_INSTRUCTION_RENAME) {
|
||||
// The file was most likely moved in this directory.
|
||||
|
@ -1245,7 +1259,7 @@ void SyncEngine::checkForPermission()
|
|||
if ((*it)->_isDirectory) {
|
||||
// restore all sub items
|
||||
for (SyncFileItemVector::iterator it_next = it + 1;
|
||||
it_next != _syncedItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
|
||||
if ((*it)->_instruction != CSYNC_INSTRUCTION_REMOVE) {
|
||||
|
@ -1271,12 +1285,12 @@ void SyncEngine::checkForPermission()
|
|||
// underneath, propagator sees that.
|
||||
if( (*it)->_isDirectory ) {
|
||||
// put a more descriptive message if a top level share dir really is removed.
|
||||
if( it == _syncedItems.begin() || !(path.startsWith((*(it-1))->_file)) ) {
|
||||
if( it == syncItems.begin() || !(path.startsWith((*(it-1))->_file)) ) {
|
||||
(*it)->_errorString = tr("Local files and share folder removed.");
|
||||
}
|
||||
|
||||
for (SyncFileItemVector::iterator it_next = it + 1;
|
||||
it_next != _syncedItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
}
|
||||
}
|
||||
|
@ -1355,7 +1369,7 @@ void SyncEngine::checkForPermission()
|
|||
|
||||
if ((*it)->_isDirectory) {
|
||||
for (SyncFileItemVector::iterator it_next = it + 1;
|
||||
it_next != _syncedItems.end() && (*it_next)->destination().startsWith(path); ++it_next) {
|
||||
it_next != syncItems.end() && (*it_next)->destination().startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_ERROR;
|
||||
(*it)->_status = SyncFileItem::NormalError;
|
||||
|
@ -1384,7 +1398,7 @@ QByteArray SyncEngine::getPermissions(const QString& file) const
|
|||
return _remotePerms.value(file);
|
||||
}
|
||||
|
||||
void SyncEngine::restoreOldFiles()
|
||||
void SyncEngine::restoreOldFiles(SyncFileItemVector &syncItems)
|
||||
{
|
||||
/* When the server is trying to send us lots of file in the past, this means that a backup
|
||||
was restored in the server. In that case, we should not simply overwrite the newer file
|
||||
|
@ -1392,7 +1406,7 @@ void SyncEngine::restoreOldFiles()
|
|||
upload the client file. But we still downloaded the old file in a conflict file just in case
|
||||
*/
|
||||
|
||||
for (auto it = _syncedItems.begin(); it != _syncedItems.end(); ++it) {
|
||||
for (auto it = syncItems.begin(); it != syncItems.end(); ++it) {
|
||||
if ((*it)->_direction != SyncFileItem::Down)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ namespace OCC {
|
|||
class SyncJournalFileRecord;
|
||||
class SyncJournalDb;
|
||||
class OwncloudPropagator;
|
||||
class PropagatorJob;
|
||||
|
||||
enum AnotherSyncNeeded
|
||||
{
|
||||
|
@ -78,10 +77,7 @@ public:
|
|||
|
||||
bool isSyncRunning() const { return _syncRunning; }
|
||||
|
||||
/* Set the maximum size a folder can have without asking for confirmation
|
||||
* -1 means infinite
|
||||
*/
|
||||
void setNewBigFolderSizeLimit(qint64 limit) { _newBigFolderSizeLimit = limit; }
|
||||
void setSyncOptions(const SyncOptions &options) { _syncOptions = options; }
|
||||
bool ignoreHiddenFiles() const { return _csync_ctx->ignore_hidden_files; }
|
||||
void setIgnoreHiddenFiles(bool ignore) { _csync_ctx->ignore_hidden_files = ignore; }
|
||||
|
||||
|
@ -122,10 +118,7 @@ signals:
|
|||
void aboutToPropagate(SyncFileItemVector&);
|
||||
|
||||
// after each item completed by a job (successful or not)
|
||||
void itemCompleted(const SyncFileItem&, const PropagatorJob&);
|
||||
|
||||
// after sync is done
|
||||
void treeWalkResult(const SyncFileItemVector&);
|
||||
void itemCompleted(const SyncFileItemPtr&);
|
||||
|
||||
void transmissionProgress( const ProgressInfo& progress );
|
||||
|
||||
|
@ -146,7 +139,7 @@ signals:
|
|||
void aboutToRestoreBackup(bool *restore);
|
||||
|
||||
// A new folder was discovered and was not synced because of the confirmation feature
|
||||
void newBigFolder(const QString &folder);
|
||||
void newBigFolder(const QString &folder, bool isExternal);
|
||||
|
||||
/** Emitted when propagation has problems with a locked file.
|
||||
*
|
||||
|
@ -156,7 +149,7 @@ signals:
|
|||
|
||||
private slots:
|
||||
void slotRootEtagReceived(const QString &);
|
||||
void slotItemCompleted(const SyncFileItem& item, const PropagatorJob & job);
|
||||
void slotItemCompleted(const SyncFileItemPtr& item);
|
||||
void slotFinished(bool success);
|
||||
void slotProgress(const SyncFileItem& item, quint64 curent);
|
||||
void slotDiscoveryJobFinished(int updateResult);
|
||||
|
@ -180,13 +173,13 @@ private:
|
|||
|
||||
// Cleans up unnecessary downloadinfo entries in the journal as well
|
||||
// as their temporary files.
|
||||
void deleteStaleDownloadInfos();
|
||||
void deleteStaleDownloadInfos(const SyncFileItemVector &syncItems);
|
||||
|
||||
// Removes stale uploadinfos from the journal.
|
||||
void deleteStaleUploadInfos();
|
||||
void deleteStaleUploadInfos(const SyncFileItemVector &syncItems);
|
||||
|
||||
// Removes stale error blacklist entries from the journal.
|
||||
void deleteStaleErrorBlacklistEntries();
|
||||
void deleteStaleErrorBlacklistEntries(const SyncFileItemVector &syncItems);
|
||||
|
||||
// cleanup and emit the finished signal
|
||||
void finalize(bool success);
|
||||
|
@ -196,10 +189,6 @@ private:
|
|||
// Must only be acessed during update and reconcile
|
||||
QMap<QString, SyncFileItemPtr> _syncItemMap;
|
||||
|
||||
// should be called _syncItems (present tense). It's the items from the _syncItemMap but
|
||||
// sorted and re-adjusted based on permissions.
|
||||
SyncFileItemVector _syncedItems;
|
||||
|
||||
AccountPtr _account;
|
||||
CSYNC *_csync_ctx;
|
||||
bool _needsUpdate;
|
||||
|
@ -241,13 +230,13 @@ private:
|
|||
* check if we are allowed to propagate everything, and if we are not, adjust the instructions
|
||||
* to recover
|
||||
*/
|
||||
void checkForPermission();
|
||||
void checkForPermission(SyncFileItemVector &syncItems);
|
||||
QByteArray getPermissions(const QString& file) const;
|
||||
|
||||
/**
|
||||
* Instead of downloading files from the server, upload the files to the server
|
||||
*/
|
||||
void restoreOldFiles();
|
||||
void restoreOldFiles(SyncFileItemVector &syncItems);
|
||||
|
||||
bool _hasNoneFiles; // true if there is at least one file which was not changed on the server
|
||||
bool _hasRemoveFile; // true if there is at leasr one file with instruction REMOVE
|
||||
|
@ -257,8 +246,7 @@ private:
|
|||
|
||||
int _uploadLimit;
|
||||
int _downloadLimit;
|
||||
/* maximum size a folder can have without asking for confirmation: -1 means infinite */
|
||||
qint64 _newBigFolderSizeLimit;
|
||||
SyncOptions _syncOptions;
|
||||
|
||||
// hash containing the permissions on the remote directory
|
||||
QHash<QString, QByteArray> _remotePerms;
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
_serverHasIgnoredFiles(false), _hasBlacklistEntry(false),
|
||||
_errorMayBeBlacklisted(false), _status(NoStatus),
|
||||
_isRestoration(false),
|
||||
_httpErrorCode(0), _requestDuration(0), _affectedItems(1),
|
||||
_httpErrorCode(0), _affectedItems(1),
|
||||
_instruction(CSYNC_INSTRUCTION_NONE), _modtime(0), _size(0), _inode(0)
|
||||
{
|
||||
}
|
||||
|
@ -160,7 +160,6 @@ public:
|
|||
quint16 _httpErrorCode;
|
||||
QString _errorString; // Contains a string only in case of error
|
||||
QByteArray _responseTimeStamp;
|
||||
quint64 _requestDuration;
|
||||
quint32 _affectedItems; // the number of affected items by the operation on this item.
|
||||
// usually this value is 1, but for removes on dirs, it might be much higher.
|
||||
|
||||
|
@ -179,15 +178,10 @@ public:
|
|||
QString _directDownloadCookies;
|
||||
|
||||
struct {
|
||||
quint64 _size;
|
||||
time_t _modtime;
|
||||
QByteArray _etag;
|
||||
QByteArray _fileId;
|
||||
quint64 _other_size;
|
||||
time_t _other_modtime;
|
||||
QByteArray _other_etag;
|
||||
QByteArray _other_fileId;
|
||||
enum csync_instructions_e _instruction BITFIELD(16);
|
||||
enum csync_instructions_e _other_instruction BITFIELD(16);
|
||||
} log;
|
||||
};
|
||||
|
@ -202,5 +196,6 @@ typedef QVector<SyncFileItemPtr> SyncFileItemVector;
|
|||
}
|
||||
|
||||
Q_DECLARE_METATYPE(OCC::SyncFileItem)
|
||||
Q_DECLARE_METATYPE(OCC::SyncFileItemPtr)
|
||||
|
||||
#endif // SYNCFILEITEM_H
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "syncengine.h"
|
||||
#include "syncjournaldb.h"
|
||||
#include "syncjournalfilerecord.h"
|
||||
#include "asserts.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
@ -77,8 +78,8 @@ SyncFileStatusTracker::SyncFileStatusTracker(SyncEngine *syncEngine)
|
|||
{
|
||||
connect(syncEngine, SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
||||
SLOT(slotAboutToPropagate(SyncFileItemVector&)));
|
||||
connect(syncEngine, SIGNAL(itemCompleted(const SyncFileItem&, const PropagatorJob&)),
|
||||
SLOT(slotItemCompleted(const SyncFileItem&)));
|
||||
connect(syncEngine, SIGNAL(itemCompleted(const SyncFileItemPtr&)),
|
||||
SLOT(slotItemCompleted(const SyncFileItemPtr&)));
|
||||
connect(syncEngine, SIGNAL(finished(bool)), SLOT(slotSyncFinished()));
|
||||
connect(syncEngine, SIGNAL(started()), SLOT(slotSyncEngineRunningChanged()));
|
||||
connect(syncEngine, SIGNAL(finished(bool)), SLOT(slotSyncEngineRunningChanged()));
|
||||
|
@ -86,7 +87,7 @@ SyncFileStatusTracker::SyncFileStatusTracker(SyncEngine *syncEngine)
|
|||
|
||||
SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& relativePath)
|
||||
{
|
||||
Q_ASSERT(!relativePath.endsWith(QLatin1Char('/')));
|
||||
ASSERT(!relativePath.endsWith(QLatin1Char('/')));
|
||||
|
||||
if (relativePath.isEmpty()) {
|
||||
// This is the root sync folder, it doesn't have an entry in the database and won't be walked by csync, so resolve manually.
|
||||
|
@ -121,62 +122,67 @@ SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& relativePath)
|
|||
void SyncFileStatusTracker::slotPathTouched(const QString& fileName)
|
||||
{
|
||||
QString folderPath = _syncEngine->localPath();
|
||||
Q_ASSERT(fileName.startsWith(folderPath));
|
||||
|
||||
ASSERT(fileName.startsWith(folderPath));
|
||||
QString localPath = fileName.mid(folderPath.size());
|
||||
_dirtyPaths.insert(localPath);
|
||||
|
||||
emit fileStatusChanged(fileName, SyncFileStatus::StatusSync);
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::incSyncCount(const QString &relativePath, EmitStatusChangeFlag emitStatusChange)
|
||||
void SyncFileStatusTracker::incSyncCountAndEmitStatusChanged(const QString &relativePath, SharedFlag sharedFlag)
|
||||
{
|
||||
// Will return 0 (and increase to 1) if the path wasn't in the map yet
|
||||
int count = _syncCount[relativePath]++;
|
||||
if (!count) {
|
||||
if (emitStatusChange)
|
||||
emit fileStatusChanged(getSystemDestination(relativePath), fileStatus(relativePath));
|
||||
SyncFileStatus status = sharedFlag == UnknownShared
|
||||
? fileStatus(relativePath)
|
||||
: resolveSyncAndErrorStatus(relativePath, sharedFlag);
|
||||
emit fileStatusChanged(getSystemDestination(relativePath), status);
|
||||
|
||||
// We passed from OK to SYNC, increment the parent to keep it marked as
|
||||
// SYNC while we propagate ourselves and our own children.
|
||||
Q_ASSERT(!relativePath.endsWith('/'));
|
||||
ASSERT(!relativePath.endsWith('/'));
|
||||
int lastSlashIndex = relativePath.lastIndexOf('/');
|
||||
if (lastSlashIndex != -1)
|
||||
incSyncCount(relativePath.left(lastSlashIndex), EmitStatusChange);
|
||||
incSyncCountAndEmitStatusChanged(relativePath.left(lastSlashIndex), UnknownShared);
|
||||
else if (!relativePath.isEmpty())
|
||||
incSyncCount(QString(), EmitStatusChange);
|
||||
incSyncCountAndEmitStatusChanged(QString(), UnknownShared);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::decSyncCount(const QString &relativePath, EmitStatusChangeFlag emitStatusChange)
|
||||
void SyncFileStatusTracker::decSyncCountAndEmitStatusChanged(const QString &relativePath, SharedFlag sharedFlag)
|
||||
{
|
||||
int count = --_syncCount[relativePath];
|
||||
if (!count) {
|
||||
// Remove from the map, same as 0
|
||||
_syncCount.remove(relativePath);
|
||||
|
||||
if (emitStatusChange)
|
||||
emit fileStatusChanged(getSystemDestination(relativePath), fileStatus(relativePath));
|
||||
SyncFileStatus status = sharedFlag == UnknownShared
|
||||
? fileStatus(relativePath)
|
||||
: resolveSyncAndErrorStatus(relativePath, sharedFlag);
|
||||
emit fileStatusChanged(getSystemDestination(relativePath), status);
|
||||
|
||||
// We passed from SYNC to OK, decrement our parent.
|
||||
Q_ASSERT(!relativePath.endsWith('/'));
|
||||
ASSERT(!relativePath.endsWith('/'));
|
||||
int lastSlashIndex = relativePath.lastIndexOf('/');
|
||||
if (lastSlashIndex != -1)
|
||||
decSyncCount(relativePath.left(lastSlashIndex), EmitStatusChange);
|
||||
decSyncCountAndEmitStatusChanged(relativePath.left(lastSlashIndex), UnknownShared);
|
||||
else if (!relativePath.isEmpty())
|
||||
decSyncCount(QString(), EmitStatusChange);
|
||||
decSyncCountAndEmitStatusChanged(QString(), UnknownShared);
|
||||
}
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
||||
{
|
||||
Q_ASSERT(_syncCount.isEmpty());
|
||||
ASSERT(_syncCount.isEmpty());
|
||||
|
||||
std::map<QString, SyncFileStatus::SyncFileStatusTag> oldProblems;
|
||||
std::swap(_syncProblems, oldProblems);
|
||||
|
||||
foreach (const SyncFileItemPtr &item, items) {
|
||||
// qDebug() << Q_FUNC_INFO << "Investigating" << item->destination() << item->_status << item->_instruction;
|
||||
_dirtyPaths.remove(item->destination());
|
||||
|
||||
if (showErrorInSocketApi(*item)) {
|
||||
_syncProblems[item->_file] = SyncFileStatus::StatusError;
|
||||
|
@ -185,18 +191,16 @@ void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
|||
_syncProblems[item->_file] = SyncFileStatus::StatusWarning;
|
||||
}
|
||||
|
||||
// Mark this path as syncing for instructions that will result in propagation,
|
||||
// but DontEmitStatusChange since we're going to emit for ourselves using the
|
||||
// info in the SyncFileItem we received, parents will still be emit if needed.
|
||||
SharedFlag sharedFlag = item->_remotePerm.contains("S") ? Shared : NotShared;
|
||||
if (item->_instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_ERROR) {
|
||||
incSyncCount(item->destination(), DontEmitStatusChange);
|
||||
// Mark this path as syncing for instructions that will result in propagation.
|
||||
incSyncCountAndEmitStatusChanged(item->destination(), sharedFlag);
|
||||
} else {
|
||||
emit fileStatusChanged(getSystemDestination(item->destination()), resolveSyncAndErrorStatus(item->destination(), sharedFlag));
|
||||
}
|
||||
|
||||
_dirtyPaths.remove(item->destination());
|
||||
emit fileStatusChanged(getSystemDestination(item->destination()), resolveSyncAndErrorStatus(item->destination(), item->_remotePerm.contains("S") ? Shared : NotShared));
|
||||
}
|
||||
|
||||
// Some metadata status won't trigger files to be synced, make sure that we
|
||||
|
@ -220,27 +224,29 @@ void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
|||
}
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotItemCompleted(const SyncFileItem &item)
|
||||
void SyncFileStatusTracker::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << item.destination() << item._status << item._instruction;
|
||||
|
||||
if (showErrorInSocketApi(item)) {
|
||||
_syncProblems[item._file] = SyncFileStatus::StatusError;
|
||||
invalidateParentPaths(item.destination());
|
||||
} else if (showWarningInSocketApi(item)) {
|
||||
_syncProblems[item._file] = SyncFileStatus::StatusWarning;
|
||||
if (showErrorInSocketApi(*item)) {
|
||||
_syncProblems[item->_file] = SyncFileStatus::StatusError;
|
||||
invalidateParentPaths(item->destination());
|
||||
} else if (showWarningInSocketApi(*item)) {
|
||||
_syncProblems[item->_file] = SyncFileStatus::StatusWarning;
|
||||
} else {
|
||||
_syncProblems.erase(item._file);
|
||||
_syncProblems.erase(item->_file);
|
||||
}
|
||||
|
||||
// decSyncCount calls *must* be symetric with incSyncCount calls in slotAboutToPropagate
|
||||
if (item._instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& item._instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
&& item._instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& item._instruction != CSYNC_INSTRUCTION_ERROR) {
|
||||
decSyncCount(item.destination(), DontEmitStatusChange);
|
||||
SharedFlag sharedFlag = item->_remotePerm.contains("S") ? Shared : NotShared;
|
||||
if (item->_instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_ERROR) {
|
||||
// decSyncCount calls *must* be symetric with incSyncCount calls in slotAboutToPropagate
|
||||
decSyncCountAndEmitStatusChanged(item->destination(), sharedFlag);
|
||||
} else {
|
||||
emit fileStatusChanged(getSystemDestination(item->destination()), resolveSyncAndErrorStatus(item->destination(), sharedFlag));
|
||||
}
|
||||
emit fileStatusChanged(getSystemDestination(item.destination()), resolveSyncAndErrorStatus(item.destination(), item._remotePerm.contains("S") ? Shared : NotShared));
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotSyncFinished()
|
||||
|
@ -257,7 +263,7 @@ void SyncFileStatusTracker::slotSyncEngineRunningChanged()
|
|||
emit fileStatusChanged(getSystemDestination(QString()), resolveSyncAndErrorStatus(QString(), NotShared));
|
||||
}
|
||||
|
||||
SyncFileStatus SyncFileStatusTracker::resolveSyncAndErrorStatus(const QString &relativePath, SharedFlag isShared, PathKnownFlag isPathKnown)
|
||||
SyncFileStatus SyncFileStatusTracker::resolveSyncAndErrorStatus(const QString &relativePath, SharedFlag sharedFlag, PathKnownFlag isPathKnown)
|
||||
{
|
||||
// If it's a new file and that we're not syncing it yet,
|
||||
// don't show any icon and wait for the filesystem watcher to trigger a sync.
|
||||
|
@ -272,7 +278,9 @@ SyncFileStatus SyncFileStatusTracker::resolveSyncAndErrorStatus(const QString &r
|
|||
status.set(problemStatus);
|
||||
}
|
||||
|
||||
if (isShared)
|
||||
ASSERT(sharedFlag != UnknownShared,
|
||||
"The shared status needs to have been fetched from a SyncFileItem or the DB at this point.");
|
||||
if (sharedFlag == Shared)
|
||||
status.setSharedWithMe(true);
|
||||
|
||||
return status;
|
||||
|
|
|
@ -46,25 +46,27 @@ signals:
|
|||
|
||||
private slots:
|
||||
void slotAboutToPropagate(SyncFileItemVector& items);
|
||||
void slotItemCompleted(const SyncFileItem& item);
|
||||
void slotItemCompleted(const SyncFileItemPtr& item);
|
||||
void slotSyncFinished();
|
||||
void slotSyncEngineRunningChanged();
|
||||
|
||||
private:
|
||||
enum SharedFlag { NotShared = 0, Shared };
|
||||
enum SharedFlag { UnknownShared, NotShared, Shared };
|
||||
enum PathKnownFlag { PathUnknown = 0, PathKnown };
|
||||
enum EmitStatusChangeFlag { DontEmitStatusChange = 0, EmitStatusChange };
|
||||
SyncFileStatus resolveSyncAndErrorStatus(const QString &relativePath, SharedFlag isShared, PathKnownFlag isPathKnown = PathKnown);
|
||||
SyncFileStatus resolveSyncAndErrorStatus(const QString &relativePath, SharedFlag sharedState, PathKnownFlag isPathKnown = PathKnown);
|
||||
|
||||
void invalidateParentPaths(const QString& path);
|
||||
QString getSystemDestination(const QString& relativePath);
|
||||
void incSyncCount(const QString &relativePath, EmitStatusChangeFlag emitStatusChange);
|
||||
void decSyncCount(const QString &relativePath, EmitStatusChangeFlag emitStatusChange);
|
||||
void incSyncCountAndEmitStatusChanged(const QString &relativePath, SharedFlag sharedState);
|
||||
void decSyncCountAndEmitStatusChanged(const QString &relativePath, SharedFlag sharedState);
|
||||
|
||||
SyncEngine* _syncEngine;
|
||||
|
||||
std::map<QString, SyncFileStatus::SyncFileStatusTag> _syncProblems;
|
||||
QSet<QString> _dirtyPaths;
|
||||
// Counts the number direct children currently being synced (has unfinished propagation jobs).
|
||||
// We'll show a file/directory as SYNC as long as its sync count is > 0.
|
||||
// A directory that starts/ends propagation will in turn increase/decrease its own parent by 1.
|
||||
QHash<QString, int> _syncCount;
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "utility.h"
|
||||
#include "version.h"
|
||||
#include "filesystem.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include "../../csync/src/std/c_jhash.h"
|
||||
|
||||
|
@ -178,7 +179,7 @@ bool SyncJournalDb::sqlFail( const QString& log, const SqlQuery& query )
|
|||
{
|
||||
commitTransaction();
|
||||
qWarning() << "SQL Error" << log << query.error();
|
||||
Q_ASSERT(!"SQL ERROR");
|
||||
ASSERT(false);
|
||||
_db.close();
|
||||
return false;
|
||||
}
|
||||
|
@ -1370,21 +1371,22 @@ void SyncJournalDb::setUploadInfo(const QString& file, const SyncJournalDb::Uplo
|
|||
}
|
||||
}
|
||||
|
||||
bool SyncJournalDb::deleteStaleUploadInfos(const QSet<QString> &keep)
|
||||
QVector<uint> SyncJournalDb::deleteStaleUploadInfos(const QSet<QString> &keep)
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
QVector<uint> ids;
|
||||
|
||||
if (!checkConnect()) {
|
||||
return false;
|
||||
return ids;
|
||||
}
|
||||
|
||||
SqlQuery query(_db);
|
||||
query.prepare("SELECT path FROM uploadinfo");
|
||||
query.prepare("SELECT path,transferid FROM uploadinfo");
|
||||
|
||||
if (!query.exec()) {
|
||||
QString err = query.error();
|
||||
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;
|
||||
return false;
|
||||
return ids;
|
||||
}
|
||||
|
||||
QStringList superfluousPaths;
|
||||
|
@ -1393,10 +1395,12 @@ bool SyncJournalDb::deleteStaleUploadInfos(const QSet<QString> &keep)
|
|||
const QString file = query.stringValue(0);
|
||||
if (!keep.contains(file)) {
|
||||
superfluousPaths.append(file);
|
||||
ids.append(query.intValue(1));
|
||||
}
|
||||
}
|
||||
|
||||
return deleteBatch(*_deleteUploadInfoQuery, superfluousPaths, "uploadinfo");
|
||||
deleteBatch(*_deleteUploadInfoQuery, superfluousPaths, "uploadinfo");
|
||||
return ids;
|
||||
}
|
||||
|
||||
SyncJournalErrorBlacklistRecord SyncJournalDb::errorBlacklistEntry( const QString& file )
|
||||
|
@ -1604,7 +1608,7 @@ void SyncJournalDb::setPollInfo(const SyncJournalDb::PollInfo& info)
|
|||
QStringList SyncJournalDb::getSelectiveSyncList(SyncJournalDb::SelectiveSyncListType type, bool *ok )
|
||||
{
|
||||
QStringList result;
|
||||
Q_ASSERT(ok);
|
||||
ASSERT(ok);
|
||||
|
||||
QMutexLocker locker(&_mutex);
|
||||
if( !checkConnect() ) {
|
||||
|
@ -1832,6 +1836,17 @@ void SyncJournalDb::setDataFingerprint(const QByteArray &dataFingerprint)
|
|||
}
|
||||
}
|
||||
|
||||
void SyncJournalDb::clearFileTable()
|
||||
{
|
||||
SqlQuery query(_db);
|
||||
query.prepare("DELETE FROM metadata;");
|
||||
if (!query.exec()) {
|
||||
qWarning() << "SQL error in clearFileTable" << query.error();
|
||||
} else {
|
||||
qDebug() << query.lastQuery() << "(" << query.numRowsAffected() << " rows)";
|
||||
}
|
||||
}
|
||||
|
||||
void SyncJournalDb::commit(const QString& context, bool startTrans)
|
||||
{
|
||||
QMutexLocker lock(&_mutex);
|
||||
|
|
|
@ -105,7 +105,8 @@ public:
|
|||
|
||||
UploadInfo getUploadInfo(const QString &file);
|
||||
void setUploadInfo(const QString &file, const UploadInfo &i);
|
||||
bool deleteStaleUploadInfos(const QSet<QString>& keep);
|
||||
// Return the list of transfer ids that were removed.
|
||||
QVector<uint> deleteStaleUploadInfos(const QSet<QString>& keep);
|
||||
|
||||
SyncJournalErrorBlacklistRecord errorBlacklistEntry( const QString& );
|
||||
bool deleteStaleErrorBlacklistEntries(const QSet<QString>& keep);
|
||||
|
@ -172,6 +173,13 @@ public:
|
|||
void setDataFingerprint(const QByteArray &dataFingerprint);
|
||||
QByteArray dataFingerprint();
|
||||
|
||||
/**
|
||||
* Delete any file entry. This will force the next sync to re-sync everything as if it was new,
|
||||
* restoring everyfile on every remote. If a file is there both on the client and server side,
|
||||
* it will be a conflict that will be automatically resolved if the file is the same.
|
||||
*/
|
||||
void clearFileTable();
|
||||
|
||||
private:
|
||||
bool updateDatabaseStructure();
|
||||
bool updateMetadataTableStructure();
|
||||
|
|
|
@ -131,7 +131,6 @@ SyncJournalErrorBlacklistRecord SyncJournalErrorBlacklistRecord::update(
|
|||
bool mayBlacklist =
|
||||
item._errorMayBeBlacklisted // explicitly flagged for blacklisting
|
||||
|| (item._httpErrorCode != 0 // or non-local error
|
||||
&& item._httpErrorCode != 507 // Don't blacklist "Insufficient Storage"
|
||||
#ifdef OWNCLOUD_5XX_NO_BLACKLIST
|
||||
&& item._httpErrorCode / 100 != 5 // In this configuration, never blacklist error 5xx
|
||||
#endif
|
||||
|
|
|
@ -13,19 +13,22 @@
|
|||
*/
|
||||
|
||||
#include "syncresult.h"
|
||||
#include "progressdispatcher.h"
|
||||
|
||||
namespace OCC
|
||||
{
|
||||
|
||||
SyncResult::SyncResult()
|
||||
: _status( Undefined ),
|
||||
_warnCount(0)
|
||||
{
|
||||
}
|
||||
: _status( Undefined )
|
||||
, _foundFilesNotSynced(false)
|
||||
, _folderStructureWasChanged(false)
|
||||
, _numNewItems(0)
|
||||
, _numRemovedItems(0)
|
||||
, _numUpdatedItems(0)
|
||||
, _numRenamedItems(0)
|
||||
, _numConflictItems(0)
|
||||
, _numErrorItems(0)
|
||||
|
||||
SyncResult::SyncResult(SyncResult::Status status )
|
||||
: _status(status),
|
||||
_warnCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,6 +37,11 @@ SyncResult::Status SyncResult::status() const
|
|||
return _status;
|
||||
}
|
||||
|
||||
void SyncResult::reset()
|
||||
{
|
||||
*this = SyncResult();
|
||||
}
|
||||
|
||||
QString SyncResult::statusString() const
|
||||
{
|
||||
QString re;
|
||||
|
@ -80,42 +88,17 @@ void SyncResult::setStatus( Status stat )
|
|||
_syncTime = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
void SyncResult::setSyncFileItemVector( const SyncFileItemVector& items )
|
||||
{
|
||||
_syncItems = items;
|
||||
}
|
||||
|
||||
SyncFileItemVector SyncResult::syncFileItemVector() const
|
||||
{
|
||||
return _syncItems;
|
||||
}
|
||||
|
||||
QDateTime SyncResult::syncTime() const
|
||||
{
|
||||
return _syncTime;
|
||||
}
|
||||
|
||||
void SyncResult::setWarnCount(int wc)
|
||||
{
|
||||
_warnCount = wc;
|
||||
}
|
||||
|
||||
int SyncResult::warnCount() const
|
||||
{
|
||||
return _warnCount;
|
||||
}
|
||||
|
||||
void SyncResult::setErrorStrings( const QStringList& list )
|
||||
{
|
||||
_errors = list;
|
||||
}
|
||||
|
||||
QStringList SyncResult::errorStrings() const
|
||||
{
|
||||
return _errors;
|
||||
}
|
||||
|
||||
void SyncResult::setErrorString( const QString& err )
|
||||
void SyncResult::appendErrorString( const QString& err )
|
||||
{
|
||||
_errors.append( err );
|
||||
}
|
||||
|
@ -141,8 +124,68 @@ QString SyncResult::folder() const
|
|||
return _folder;
|
||||
}
|
||||
|
||||
SyncResult::~SyncResult()
|
||||
void SyncResult::processCompletedItem(const SyncFileItemPtr &item)
|
||||
{
|
||||
if (Progress::isWarningKind(item->_status)) {
|
||||
// Count any error conditions, error strings will have priority anyway.
|
||||
_foundFilesNotSynced = true;
|
||||
}
|
||||
|
||||
if (item->_isDirectory && (item->_instruction == CSYNC_INSTRUCTION_NEW
|
||||
|| item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE
|
||||
|| item->_instruction == CSYNC_INSTRUCTION_REMOVE
|
||||
|| item->_instruction == CSYNC_INSTRUCTION_RENAME)) {
|
||||
_folderStructureWasChanged = true;
|
||||
}
|
||||
|
||||
// Process the item to the gui
|
||||
if( item->_status == SyncFileItem::FatalError || item->_status == SyncFileItem::NormalError ) {
|
||||
//: this displays an error string (%2) for a file %1
|
||||
appendErrorString( QObject::tr("%1: %2").arg(item->_file, item->_errorString) );
|
||||
_numErrorItems++;
|
||||
if (!_firstItemError) {
|
||||
_firstItemError = item;
|
||||
}
|
||||
} else if( item->_status == SyncFileItem::Conflict ) {
|
||||
_numConflictItems++;
|
||||
if (!_firstConflictItem) {
|
||||
_firstConflictItem = item;
|
||||
}
|
||||
} else {
|
||||
if (!item->hasErrorStatus() && item->_status != SyncFileItem::FileIgnored && item->_direction == SyncFileItem::Down) {
|
||||
switch (item->_instruction) {
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
case CSYNC_INSTRUCTION_TYPE_CHANGE:
|
||||
_numNewItems++;
|
||||
if (!_firstItemNew)
|
||||
_firstItemNew = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
_numRemovedItems++;
|
||||
if (!_firstItemDeleted)
|
||||
_firstItemDeleted = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_SYNC:
|
||||
_numUpdatedItems++;
|
||||
if (!_firstItemUpdated)
|
||||
_firstItemUpdated = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
if (!_firstItemRenamed) {
|
||||
_firstItemRenamed = item;
|
||||
}
|
||||
_numRenamedItems++;
|
||||
break;
|
||||
default:
|
||||
// nothing.
|
||||
break;
|
||||
}
|
||||
} else if( item->_direction == SyncFileItem::None ) {
|
||||
if( item->_instruction == CSYNC_INSTRUCTION_IGNORE ) {
|
||||
_foundFilesNotSynced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -47,20 +47,13 @@ public:
|
|||
};
|
||||
|
||||
SyncResult();
|
||||
SyncResult( Status status );
|
||||
~SyncResult();
|
||||
void setErrorString( const QString& );
|
||||
void setErrorStrings( const QStringList& );
|
||||
void reset();
|
||||
|
||||
void appendErrorString( const QString& );
|
||||
QString errorString() const;
|
||||
QStringList errorStrings() const;
|
||||
int warnCount() const;
|
||||
void setWarnCount(int wc);
|
||||
void clearErrors();
|
||||
|
||||
// handle a list of changed items.
|
||||
void setSyncFileItemVector( const SyncFileItemVector& );
|
||||
SyncFileItemVector syncFileItemVector() const;
|
||||
|
||||
void setStatus( Status );
|
||||
Status status() const;
|
||||
QString statusString() const;
|
||||
|
@ -68,6 +61,25 @@ public:
|
|||
void setFolder(const QString& folder);
|
||||
QString folder() const;
|
||||
|
||||
bool foundFilesNotSynced() const { return _foundFilesNotSynced; }
|
||||
bool folderStructureWasChanged() const { return _folderStructureWasChanged; }
|
||||
|
||||
int numNewItems() const { return _numNewItems; }
|
||||
int numRemovedItems() const { return _numRemovedItems; }
|
||||
int numUpdatedItems() const { return _numUpdatedItems; }
|
||||
int numRenamedItems() const { return _numRenamedItems; }
|
||||
int numConflictItems() const { return _numConflictItems; }
|
||||
int numErrorItems() const { return _numErrorItems; }
|
||||
|
||||
const SyncFileItemPtr& firstItemNew() const { return _firstItemNew; }
|
||||
const SyncFileItemPtr& firstItemDeleted() const { return _firstItemDeleted; }
|
||||
const SyncFileItemPtr& firstItemUpdated() const { return _firstItemUpdated; }
|
||||
const SyncFileItemPtr& firstItemRenamed() const { return _firstItemRenamed; }
|
||||
const SyncFileItemPtr& firstConflictItem() const { return _firstConflictItem; }
|
||||
const SyncFileItemPtr& firstItemError() const { return _firstItemError; }
|
||||
|
||||
void processCompletedItem(const SyncFileItemPtr &item);
|
||||
|
||||
private:
|
||||
Status _status;
|
||||
SyncFileItemVector _syncItems;
|
||||
|
@ -77,7 +89,23 @@ private:
|
|||
* when the sync tool support this...
|
||||
*/
|
||||
QStringList _errors;
|
||||
int _warnCount;
|
||||
bool _foundFilesNotSynced;
|
||||
bool _folderStructureWasChanged;
|
||||
|
||||
// count new, removed and updated items
|
||||
int _numNewItems;
|
||||
int _numRemovedItems;
|
||||
int _numUpdatedItems;
|
||||
int _numRenamedItems;
|
||||
int _numConflictItems;
|
||||
int _numErrorItems;
|
||||
|
||||
SyncFileItemPtr _firstItemNew;
|
||||
SyncFileItemPtr _firstItemDeleted;
|
||||
SyncFileItemPtr _firstItemUpdated;
|
||||
SyncFileItemPtr _firstItemRenamed;
|
||||
SyncFileItemPtr _firstConflictItem;
|
||||
SyncFileItemPtr _firstItemError;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue