mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-15 21:44:07 +02:00
Compare commits
76 Commits
v1.3.0-bet
...
v1.3.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b206a3b8e2 | ||
|
|
3bff5a061b | ||
|
|
0bc9b6f44e | ||
|
|
905f70a186 | ||
|
|
a8707b681d | ||
|
|
5d8f9f5346 | ||
|
|
a441b1d562 | ||
|
|
6e2042cd55 | ||
|
|
bb8b58dc66 | ||
|
|
9cd099056b | ||
|
|
0adbc032ae | ||
|
|
22a679fb8c | ||
|
|
35a67fab0a | ||
|
|
fdc8117211 | ||
|
|
24208e6137 | ||
|
|
46c7026726 | ||
|
|
01ad3c4d81 | ||
|
|
4ac98bde73 | ||
|
|
f42a6d6ef6 | ||
|
|
9055c6ade7 | ||
|
|
1356a5bbaa | ||
|
|
3c320c2736 | ||
|
|
969757199e | ||
|
|
60f1c65a48 | ||
|
|
b87b0e16e6 | ||
|
|
8ed0b1be55 | ||
|
|
91b5f1076f | ||
|
|
8ec2457965 | ||
|
|
82d79b1188 | ||
|
|
e33601becd | ||
|
|
334443adbb | ||
|
|
99579e8a2a | ||
|
|
89438f7ace | ||
|
|
d323ec5dd9 | ||
|
|
bb5cf37330 | ||
|
|
4b0bdd648c | ||
|
|
5588fbe695 | ||
|
|
12ea381205 | ||
|
|
99fbf25fb2 | ||
|
|
b37645e14d | ||
|
|
1ec5a1aaa2 | ||
|
|
3eb7acde25 | ||
|
|
e53e39cfad | ||
|
|
1a17f40233 | ||
|
|
10094a997a | ||
|
|
2af38b093f | ||
|
|
b03c168175 | ||
|
|
1c6bc84d2d | ||
|
|
541239c17b | ||
|
|
74b4ade15a | ||
|
|
205502fd3b | ||
|
|
54e4217216 | ||
|
|
d2579a7754 | ||
|
|
76580840dd | ||
|
|
779e59156c | ||
|
|
b0f0d0b1cd | ||
|
|
858dcb53bd | ||
|
|
9d7db88fcb | ||
|
|
2099b7c6a0 | ||
|
|
4442564ad2 | ||
|
|
12148b5c9b | ||
|
|
d7d77a49fc | ||
|
|
b70c2f5c20 | ||
|
|
033249423f | ||
|
|
0c959e8661 | ||
|
|
79785241ea | ||
|
|
0090862313 | ||
|
|
a4a68c6622 | ||
|
|
49b4c341ae | ||
|
|
7c1f91abdd | ||
|
|
1f2ba7e254 | ||
|
|
8014bcb7c4 | ||
|
|
b1c8bf5954 | ||
|
|
0eb6740bac | ||
|
|
96531b548a | ||
|
|
f3371360ed |
@@ -1,6 +1,6 @@
|
|||||||
set( VERSION_MAJOR 1 )
|
set( VERSION_MAJOR 1 )
|
||||||
set( VERSION_MINOR 3 )
|
set( VERSION_MINOR 3 )
|
||||||
set( VERSION_PATCH 0 )
|
set( VERSION_PATCH 0 )
|
||||||
set( VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX}beta2)
|
set( VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX}beta4)
|
||||||
set( SOVERSION 0 )
|
set( SOVERSION 0 )
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ master_doc = 'index'
|
|||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'ownCloud Client Manual'
|
project = u'ownCloud Client Manual'
|
||||||
copyright = u'2012, The ownCloud developers'
|
copyright = u'2013, The ownCloud developers'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
@@ -215,8 +215,6 @@ latex_documents = [
|
|||||||
man_pages = [
|
man_pages = [
|
||||||
('owncloud.1', 'owncloud', u'File synchronisation desktop utility.',
|
('owncloud.1', 'owncloud', u'File synchronisation desktop utility.',
|
||||||
[u'The ownCloud developers'], 1),
|
[u'The ownCloud developers'], 1),
|
||||||
('mirall.1', 'mirall', u'File synchronisation desktop utility.',
|
|
||||||
[u'The ownCloud developers'], 1)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
@@ -250,7 +248,7 @@ texinfo_documents = [
|
|||||||
epub_title = u'ownCloud Client Manual'
|
epub_title = u'ownCloud Client Manual'
|
||||||
epub_author = u'The ownCloud developers'
|
epub_author = u'The ownCloud developers'
|
||||||
epub_publisher = u'The ownCloud developers'
|
epub_publisher = u'The ownCloud developers'
|
||||||
epub_copyright = u'2012, The ownCloud developers'
|
epub_copyright = u'2013, The ownCloud developers'
|
||||||
|
|
||||||
# The language of the text. It defaults to the language option
|
# The language of the text. It defaults to the language option
|
||||||
# or en if the language is not set.
|
# or en if the language is not set.
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ It contains settings in the ini file format known from Windows.
|
|||||||
|
|
||||||
.. note:: Changes may be overwritten by using ownCloud's configuration dialog.
|
.. note:: Changes may be overwritten by using ownCloud's configuration dialog.
|
||||||
|
|
||||||
.. note:: The new version is less precise in this regard.
|
|
||||||
|
|
||||||
These are config settings that may be changed:
|
These are config settings that may be changed:
|
||||||
|
|
||||||
``remotePollinterval`` (default: ``30000``)
|
``remotePollinterval`` (default: ``30000``)
|
||||||
@@ -26,6 +24,3 @@ These are config settings that may be changed:
|
|||||||
``maxLogLines`` (default: ``20000``)
|
``maxLogLines`` (default: ``20000``)
|
||||||
Maximum count of log lines shown in the log window
|
Maximum count of log lines shown in the log window
|
||||||
|
|
||||||
``remotePollinterval``
|
|
||||||
The frequency used for polling for remote changes on the ownCloud Server.
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Mac OS X
|
|||||||
Installing the ownCloud client on your Mac follows the normal app installation
|
Installing the ownCloud client on your Mac follows the normal app installation
|
||||||
pattern:
|
pattern:
|
||||||
|
|
||||||
1. Download the installation file Click ownCloud-1.1.1.dmg, a window with the
|
1. Download the installation file Click ownCloud-x.y.z.dmg, a window with the
|
||||||
2. ownCloud icon opens In that window, drag the ownCloud application into the
|
2. ownCloud icon opens In that window, drag the ownCloud application into the
|
||||||
3. ‘Applications’ folder on the right hand side From ‘Applications’, choose
|
3. ‘Applications’ folder on the right hand side From ‘Applications’, choose
|
||||||
ownCloud
|
ownCloud
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
mirall(1)
|
|
||||||
---------
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
========
|
|
||||||
|
|
||||||
*mirall* [`OPTIONS`...]
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
===========
|
|
||||||
|
|
||||||
mirall is a file synchronisation desktop utility.
|
|
||||||
It synchronizes files on your local machine with an ownCloud Server. If you
|
|
||||||
make a change to the files on one computer, it will flow across the others
|
|
||||||
using this desktop sync clients.
|
|
||||||
|
|
||||||
Normally you start the client by click on the desktop icon or start from the
|
|
||||||
application menu. After starting an ownCloud icon appears in the system tray.
|
|
||||||
|
|
||||||
Options
|
|
||||||
=======
|
|
||||||
.. include:: options.rst
|
|
||||||
|
|
||||||
Config File
|
|
||||||
===========
|
|
||||||
.. include:: conffile.rst
|
|
||||||
|
|
||||||
BUGS
|
|
||||||
====
|
|
||||||
|
|
||||||
Please report bugs at https://github.com/owncloud/core/issues.
|
|
||||||
|
|
||||||
|
|
||||||
SEE ALSO
|
|
||||||
========
|
|
||||||
`csync(1)`, `mirall(1)`
|
|
||||||
|
|
||||||
@@ -3,8 +3,11 @@ ownCloud Client supports the following command line switches:
|
|||||||
``--logwindow``
|
``--logwindow``
|
||||||
open a window to show log output at startup.
|
open a window to show log output at startup.
|
||||||
|
|
||||||
``--logfile`` `<filename>`
|
``--logfile`` `<file>`
|
||||||
write log output to file.
|
write log output to a single file
|
||||||
|
|
||||||
|
``--logdir`` `<dir>`
|
||||||
|
write log output to dir, one for each sync run.
|
||||||
|
|
||||||
``--flushlog``
|
``--flushlog``
|
||||||
flush the log file after every write.
|
flush the log file after every write.
|
||||||
@@ -12,4 +15,3 @@ ownCloud Client supports the following command line switches:
|
|||||||
``--monoicons``
|
``--monoicons``
|
||||||
Use black/white pictograms for systray.
|
Use black/white pictograms for systray.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ SYNOPSIS
|
|||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
===========
|
===========
|
||||||
owncloud is a file synchronisation desktop utility it is based on mirall.
|
ownCloud is a file synchronisation desktop utility based on mirall.
|
||||||
It synchronizes files on your local machine with an ownCloud Server. If you
|
It synchronizes files on your local machine with an ownCloud Server. If you
|
||||||
make a change to the files on one computer, it will flow across the others
|
make a change to the files on one computer, it will flow across the others
|
||||||
using this desktop sync clients.
|
using this desktop sync clients.
|
||||||
@@ -33,5 +33,5 @@ Please report bugs at https://github.com/owncloud/core/issues.
|
|||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
========
|
========
|
||||||
`csync(1)`, `mirall(1)`
|
`csync(1)`
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ Doc Build Convenience Scripts
|
|||||||
* ``htmlhelp.sh``: A script to install Microsoft HTML Workshop on Linux or Mac OS using Wine, along with some dependencies.
|
* ``htmlhelp.sh``: A script to install Microsoft HTML Workshop on Linux or Mac OS using Wine, along with some dependencies.
|
||||||
* ``htmlhelp.reg``: Registry file to override some DLLs with their native version and set the right Windows version.
|
* ``htmlhelp.reg``: Registry file to override some DLLs with their native version and set the right Windows version.
|
||||||
|
|
||||||
Those files have been taken from the HTML Help Project (http://code.google.com/p/htmlhelp/wiki/HHW4Wine).
|
Those files have been taken from the `HTML Help Project`_.
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
The HTML Help Project has licensed its software under LGPLv3 terms.
|
The HTML Help Project has licensed_ its software under LGPLv2.1 terms
|
||||||
|
|
||||||
|
.. _HTML Help Project: http://code.google.com/p/htmlhelp/wiki/HHW4Wine
|
||||||
|
.. _licensed: https://code.google.com/p/htmlhelp/source/browse/trunk/pyhtmlhelp/COPYING
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ basic reasons: Either the server setup has a problem or the client
|
|||||||
has a bug. When reporting bugs, it is crucial to find out what part
|
has a bug. When reporting bugs, it is crucial to find out what part
|
||||||
of the system causes the problem.
|
of the system causes the problem.
|
||||||
|
|
||||||
Here are a couple of useful steps to isolate the problem.
|
Identifying basic functionality problems
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
:A general ownCloud Server test:
|
:Perform a general ownCloud Server test:
|
||||||
A very first check is to verify that you can log on to ownClouds web
|
A very first check is to verify that you can log on to ownClouds web
|
||||||
application. Assuming your ownCloud instance is installed at
|
application. Assuming your ownCloud instance is installed at
|
||||||
``http://yourserver.com/owncloud``, type
|
``http://yourserver.com/owncloud``, type
|
||||||
@@ -18,8 +19,12 @@ Here are a couple of useful steps to isolate the problem.
|
|||||||
see a red warning box on the page, your server setup is not correct or needs
|
see a red warning box on the page, your server setup is not correct or needs
|
||||||
fixes. Please verify that your server installation is working correctly.
|
fixes. Please verify that your server installation is working correctly.
|
||||||
|
|
||||||
:All desktop clients fail to connect to ownCloud:
|
:Ensure the WebDAV API is working:
|
||||||
The ownCloud syncing use the built in WebDAV server of ownCloud.
|
If all desktop clients fail to connect to ownCloud, but the access via the
|
||||||
|
web interface works, the problem often is a mis-configuration 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. Assuming your ownCloud
|
Verify that you can log on to ownClouds WebDAV server. Assuming your ownCloud
|
||||||
instance is installed at ``http://yourserver.com/owncloud``, type
|
instance is installed at ``http://yourserver.com/owncloud``, type
|
||||||
``http://yourserver.com/owncloud/remote.php/webdav`` into your browsers
|
``http://yourserver.com/owncloud/remote.php/webdav`` into your browsers
|
||||||
@@ -31,17 +36,38 @@ Here are a couple of useful steps to isolate the problem.
|
|||||||
|
|
||||||
:Use a WebDAV command line tool to test:
|
:Use a WebDAV command line tool to test:
|
||||||
A more sophisticated test is to use a WebDAV command line client and log
|
A more sophisticated test is to use a WebDAV command line client and log
|
||||||
into the ownCloud WebDAV server, such as a little app called cadaver, available
|
into the ownCloud WebDAV server, such as a little app called cadaver,
|
||||||
on Linux. It can be used to further verify that the WebDAV server is running
|
available on Linux. It can be used to further verify that the WebDAV server is
|
||||||
properly, for example by performing PROPFIND calls:
|
running properly, for example by performing PROPFIND calls:
|
||||||
|
|
||||||
``propget .`` called within cadaver will return some properties of the current
|
``propget .`` called within cadaver will return some properties of the current
|
||||||
directory and thus be a successful WebDAV connect.
|
directory and thus be a successful WebDAV connect.
|
||||||
|
|
||||||
|
Isolating other issues
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
If the sync result is unreliable, please ensure that the folder synced with
|
||||||
|
ownCloud is not shared with other syncing apps.
|
||||||
|
|
||||||
|
.. note:: Syncing the same directory with ownCloud and other sync software such
|
||||||
|
as Unison, rsync, Microsoft Windows Offline Folders or cloud services
|
||||||
|
such as DropBox or Microsoft SkyDrive is not supported and should
|
||||||
|
not be attempted. In the worst case, doing so can result in data
|
||||||
|
loss.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
.. note:: The data directory on the server is exclusive to ownCloud and must
|
||||||
|
not be modified manually.
|
||||||
|
|
||||||
|
If you are using a different backend, you can try to exclude a bug in the
|
||||||
|
backend by reverting to the local backend.
|
||||||
|
|
||||||
Logfiles
|
Logfiles
|
||||||
========
|
========
|
||||||
|
|
||||||
Doing effective debugging requires to provide as much as relevant logfiles as
|
Doing effective debugging requires to provide as much as relevant logs as
|
||||||
possible. The log output can help you with tracking down problem, and if you
|
possible. The log output can help you with tracking down problem, and if you
|
||||||
report a bug, you're advised to include the output.
|
report a bug, you're advised to include the output.
|
||||||
|
|
||||||
@@ -57,23 +83,27 @@ starting the client again with this parameter. Syntax:
|
|||||||
* Mac OS X: ``/Applications/owncloud.app/Contents/MacOS/owncloud --logwindow``
|
* Mac OS X: ``/Applications/owncloud.app/Contents/MacOS/owncloud --logwindow``
|
||||||
* Linux: ``owncloud --logwindow``
|
* Linux: ``owncloud --logwindow``
|
||||||
|
|
||||||
It is also possible to directly log into a file, which is an useful option
|
It is also possible to directly log to a directory, which is an useful option
|
||||||
in case the problem only happens ocassionally. In that case it is better to
|
in case the problem only happens ocassionally. In that case it is better to
|
||||||
create a huge logfile than piping the whole log through the log window.
|
create a huge amount of data, as the log window has a limited buffer.
|
||||||
|
|
||||||
To create a log file, start the client with ``--logfile <filename>``.
|
To write logs to disk, start the client with ``--logfile <file>``, where
|
||||||
|
``<file`` is the file you want to log to, or ``--logdir <dir>``, where ``<dir>``
|
||||||
|
is an existing directory. In case of ``--logdir``, each sync run will create a
|
||||||
|
new file.
|
||||||
|
|
||||||
:ownCloud server Logfile:
|
:ownCloud server Logfile:
|
||||||
The ownCloud server maintains an ownCloud specific logfile as well. It can and
|
The ownCloud server maintains an ownCloud specific logfile as well. It can and
|
||||||
must be enabled through the ownCloud Administration page. There you can adjust
|
must be enabled through the ownCloud Administration page. There you can adjust
|
||||||
the loglevel. It is advisable to set it to a verbose level like ``Debug`` or ``Info``.
|
the loglevel. It is advisable to set it to a verbose level like ``Debug`` or
|
||||||
|
``Info``.
|
||||||
|
|
||||||
The logfile can be viewed either in the web interface or can be found in the
|
The logfile can be viewed either in the web interface or can be found in the
|
||||||
filesystem in the ownCloud server data dir.
|
filesystem in the ownCloud server data dir.
|
||||||
|
|
||||||
:Webserver Logfiles:
|
:Webserver Logfiles:
|
||||||
Also, please take a look at your webservers error log file to check if there
|
Also, please take a look at your webservers error log file to check if there
|
||||||
are problems. For apache on linux, the error logs usually can be found at
|
are problems. For Apache on Linux, the error logs usually can be found at
|
||||||
``/var/log/apache2``. A file called ``error_log`` shows errors like PHP code
|
``/var/log/apache2``. A file called ``error_log`` shows errors like PHP code
|
||||||
problems. A file called ``access_log`` usually records all requests handled
|
problems. A file called ``access_log`` usually records all requests handled
|
||||||
by the server. Especially the access_log is a very good debugging tool as the
|
by the server. Especially the access_log is a very good debugging tool as the
|
||||||
@@ -82,4 +112,3 @@ log line contains a lot of information of every request and it's result.
|
|||||||
More information about the apache logging can be found at
|
More information about the apache logging can be found at
|
||||||
``http://httpd.apache.org/docs/current/logs.html``.
|
``http://httpd.apache.org/docs/current/logs.html``.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,42 @@ application menu. In the system tray, an ownCloud icon appears.
|
|||||||
|
|
||||||
.. index:: start application
|
.. index:: start application
|
||||||
|
|
||||||
A left click on the tray icon open a status dialog which gives an overview on
|
Overview
|
||||||
the configured sync folders and allows to add and remove more sync folder
|
--------
|
||||||
connections as well as pausing a sync connection.
|
|
||||||
|
|
||||||
A right click on the tray icon gives other configuration options.
|
ownCloud is represented by an icon in the Desktop's system tray, also known
|
||||||
|
as notification area.
|
||||||
|
|
||||||
|
The clients menu is accessed with a right click (Windows, Linux) or left click
|
||||||
|
(Mac OS).
|
||||||
|
|
||||||
|
The status of the current sync can be observed in the Status dialog, available
|
||||||
|
trough the ``Open status...`` option. On Windows, a left click on the tray icon
|
||||||
|
also opens the status dialog.
|
||||||
|
|
||||||
|
.. note:: Until the intial setup has finished, the Connection Wizard will be
|
||||||
|
shown instead when left-clicking on Windows.
|
||||||
|
|
||||||
|
The dialog provides an overview on the configured sync folders and allows to add
|
||||||
|
and remove more sync folder connections as well as pausing a sync connection.
|
||||||
|
|
||||||
|
Changing your password
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Use the ``Configure`` option. It will open the Connection Wizard, which next to
|
||||||
|
reconfiguring your connection to use a different user or server also will allow
|
||||||
|
to change the password for the local account, or to switch from HTTP to HTTPS.
|
||||||
|
|
||||||
|
Setting up a proxy
|
||||||
|
------------------
|
||||||
|
|
||||||
|
By default, the configured system proxy will be picked up. This may not be
|
||||||
|
working reliable on some Linux distributions, as only the ``http_proxy``
|
||||||
|
variable gets parsed. You can configure a proxy different from your
|
||||||
|
system default by choosing ``Configure proxy...`` from the menu.
|
||||||
|
|
||||||
|
By default, ownCloud expects a HTTP proxy. If you want to specify a SOCKS5
|
||||||
|
proxy instead, tick the "Use as SOCKSv5 proxy" option.
|
||||||
|
|
||||||
Options
|
Options
|
||||||
-------
|
-------
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ PHP version:
|
|||||||
|
|
||||||
ownCloud version:
|
ownCloud version:
|
||||||
|
|
||||||
|
Storage backend:
|
||||||
|
|
||||||
### Client configuration
|
### Client configuration
|
||||||
Client version:
|
Client version:
|
||||||
|
|
||||||
@@ -31,18 +33,14 @@ Installation path of client:
|
|||||||
|
|
||||||
### Logs
|
### Logs
|
||||||
|
|
||||||
#### output of `owncloud --logwindow` or `owncloud --logfile log.txt`
|
Please use Gist (https://gist.github.com/) or a similar code paster for longer
|
||||||
```
|
logs.
|
||||||
Insert your log output here
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Web server error log
|
```Template for output < 10 lines```
|
||||||
```
|
|
||||||
Insert your webserver log here
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ownCloud log (data/owncloud.log)
|
1. Output of `owncloud --logwindow` or `owncloud --logfile log.txt`
|
||||||
```
|
|
||||||
Insert your ownCloud log here
|
2. Web server error log:
|
||||||
```
|
|
||||||
|
3. ownCloud log (data/owncloud.log):
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<file>resources/folder-grey.png</file>
|
<file>resources/folder-grey.png</file>
|
||||||
<file>resources/task-ongoing.png</file>
|
<file>resources/task-ongoing.png</file>
|
||||||
<file>resources/view-refresh.png</file>
|
<file>resources/view-refresh.png</file>
|
||||||
|
<file>resources/warning-16.png</file>
|
||||||
<file>resources/owncloud_logo_blue.png</file>
|
<file>resources/owncloud_logo_blue.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
BIN
resources/warning-16.png
Normal file
BIN
resources/warning-16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 596 B |
22
src/3rdparty/LGPL_EXCEPTION.txt
vendored
Normal file
22
src/3rdparty/LGPL_EXCEPTION.txt
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Digia Qt LGPL Exception version 1.1
|
||||||
|
|
||||||
|
As an additional permission to the GNU Lesser General Public License version
|
||||||
|
2.1, the object code form of a "work that uses the Library" may incorporate
|
||||||
|
material from a header file that is part of the Library. You may distribute
|
||||||
|
such object code under terms of your choice, provided that:
|
||||||
|
(i) the header files of the Library have not been modified; and
|
||||||
|
(ii) the incorporated material is limited to numerical parameters, data
|
||||||
|
structure layouts, accessors, macros, inline functions and
|
||||||
|
templates; and
|
||||||
|
(iii) you comply with the terms of Section 6 of the GNU Lesser General
|
||||||
|
Public License version 2.1.
|
||||||
|
|
||||||
|
Moreover, you may apply this exception to a modified version of the Library,
|
||||||
|
provided that such modification does not involve copying material from the
|
||||||
|
Library into the modified Library's header files unless such material is
|
||||||
|
limited to (i) numerical parameters; (ii) data structure layouts;
|
||||||
|
(iii) accessors; and (iv) small macros, templates and inline functions of
|
||||||
|
five lines or less in length.
|
||||||
|
|
||||||
|
Furthermore, you are not required to apply this additional permission to a
|
||||||
|
modified version of the Library.
|
||||||
@@ -34,6 +34,10 @@
|
|||||||
|
|
||||||
#include "mirall/inotify.h"
|
#include "mirall/inotify.h"
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
@@ -50,10 +54,26 @@ namespace Mirall {
|
|||||||
void mirallLogCatcher(QtMsgType type, const char *msg)
|
void mirallLogCatcher(QtMsgType type, const char *msg)
|
||||||
{
|
{
|
||||||
Q_UNUSED(type)
|
Q_UNUSED(type)
|
||||||
Logger::instance()->mirallLog( QString::fromUtf8(msg) );
|
// qDebug() exports to local8Bit, which is not always UTF-8
|
||||||
|
Logger::instance()->mirallLog( QString::fromLocal8Bit(msg) );
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
static const char optionsC[] =
|
||||||
|
"Options:\n"
|
||||||
|
" -h --help : show this help screen.\n"
|
||||||
|
" --logwindow : open a window to show log output.\n"
|
||||||
|
" --logfile <filename> : write log output to file <filename>.\n"
|
||||||
|
" --logdir <name> : write each sync log output in a new file\n"
|
||||||
|
" in directory <name>.\n"
|
||||||
|
" --logexpire <hours> : removes logs older than <hours> hours.\n"
|
||||||
|
" (to be used with --logdir)\n"
|
||||||
|
" --logflush : flush the log file after every write.\n"
|
||||||
|
" --monoicons : Use black/white pictograms for systray.\n"
|
||||||
|
" --confdir <dirname> : Use the given configuration directory.\n"
|
||||||
|
;
|
||||||
|
|
||||||
QString applicationTrPath()
|
QString applicationTrPath()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
@@ -82,11 +102,13 @@ Application::Application(int &argc, char **argv) :
|
|||||||
_theme(Theme::instance()),
|
_theme(Theme::instance()),
|
||||||
_updateDetector(0),
|
_updateDetector(0),
|
||||||
_logBrowser(0),
|
_logBrowser(0),
|
||||||
|
_logExpire(0),
|
||||||
_showLogWindow(false),
|
_showLogWindow(false),
|
||||||
_logFlush(false),
|
_logFlush(false),
|
||||||
_helpOnly(false),
|
_helpOnly(false),
|
||||||
_fileItemDialog(0),
|
_fileItemDialog(0),
|
||||||
_statusDialog(0)
|
_statusDialog(0),
|
||||||
|
_folderWizard(0)
|
||||||
{
|
{
|
||||||
setApplicationName( _theme->appNameGUI() );
|
setApplicationName( _theme->appNameGUI() );
|
||||||
setWindowIcon( _theme->applicationIcon() );
|
setWindowIcon( _theme->applicationIcon() );
|
||||||
@@ -113,12 +135,6 @@ Application::Application(int &argc, char **argv) :
|
|||||||
|
|
||||||
setQuitOnLastWindowClosed(false);
|
setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
_folderWizard = new FolderWizard;
|
|
||||||
|
|
||||||
_owncloudSetupWizard = new OwncloudSetupWizard( _folderMan, _theme, this );
|
|
||||||
connect( _owncloudSetupWizard, SIGNAL(ownCloudWizardDone(int)),
|
|
||||||
this, SLOT(slotownCloudWizardDone(int)));
|
|
||||||
|
|
||||||
_statusDialog = new StatusDialog( _theme );
|
_statusDialog = new StatusDialog( _theme );
|
||||||
connect( _statusDialog, SIGNAL(addASync()), this, SLOT(slotAddFolder()) );
|
connect( _statusDialog, SIGNAL(addASync()), this, SLOT(slotAddFolder()) );
|
||||||
|
|
||||||
@@ -190,7 +206,7 @@ void Application::slotStartFolderSetup( int result )
|
|||||||
|
|
||||||
ownCloudInfo::instance()->checkInstallation();
|
ownCloudInfo::instance()->checkInstallation();
|
||||||
} else {
|
} else {
|
||||||
_owncloudSetupWizard->startWizard();
|
slotConfigure();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Setup Wizard was canceled. No reparsing of config.";
|
qDebug() << "Setup Wizard was canceled. No reparsing of config.";
|
||||||
@@ -246,23 +262,28 @@ void Application::slotFetchCredentials()
|
|||||||
{
|
{
|
||||||
QString trayMessage;
|
QString trayMessage;
|
||||||
|
|
||||||
if( CredentialStore::instance()->canTryAgain() ) {
|
if( CredentialStore::instance()->state() == CredentialStore::Ok ) {
|
||||||
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
|
// the credentials are still valid and ok.
|
||||||
this, SLOT(slotCredentialsFetched(bool)) );
|
slotCredentialsFetched( true );
|
||||||
CredentialStore::instance()->fetchCredentials();
|
|
||||||
if( CredentialStore::instance()->state() == CredentialStore::TooManyAttempts ) {
|
|
||||||
trayMessage = tr("Too many incorrect password attempts.");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Can not try again to fetch Credentials.";
|
if( CredentialStore::instance()->canTryAgain() ) {
|
||||||
trayMessage = tr("%1 user credentials are wrong. Please check configuration.")
|
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
|
||||||
.arg(Theme::instance()->appNameGUI());
|
this, SLOT(slotCredentialsFetched(bool)) );
|
||||||
}
|
CredentialStore::instance()->fetchCredentials();
|
||||||
|
if( CredentialStore::instance()->state() == CredentialStore::TooManyAttempts ) {
|
||||||
|
trayMessage = tr("Too many incorrect password attempts.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "Can not try again to fetch Credentials.";
|
||||||
|
trayMessage = tr("%1 user credentials are wrong. Please check configuration.")
|
||||||
|
.arg(Theme::instance()->appNameGUI());
|
||||||
|
}
|
||||||
|
|
||||||
if( !trayMessage.isEmpty() ) {
|
if( !trayMessage.isEmpty() ) {
|
||||||
_tray->showMessage(tr("Credentials"), trayMessage);
|
_tray->showMessage(tr("Credentials"), trayMessage);
|
||||||
_actionOpenStatus->setEnabled( false );
|
_actionOpenStatus->setEnabled( false );
|
||||||
_actionAddFolder->setEnabled( false );
|
_actionAddFolder->setEnabled( false );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,8 +373,6 @@ void Application::slotAuthCheck( const QString& ,QNetworkReply *reply )
|
|||||||
_actionAddFolder->setEnabled( true );
|
_actionAddFolder->setEnabled( true );
|
||||||
_actionOpenStatus->setEnabled( true );
|
_actionOpenStatus->setEnabled( true );
|
||||||
setupContextMenu();
|
setupContextMenu();
|
||||||
} else {
|
|
||||||
slotFetchCredentials();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,6 +421,7 @@ void Application::slotownCloudWizardDone( int res )
|
|||||||
}
|
}
|
||||||
_folderMan->setSyncEnabled( true );
|
_folderMan->setSyncEnabled( true );
|
||||||
slotStartFolderSetup( res );
|
slotStartFolderSetup( res );
|
||||||
|
_owncloudSetupWizard.reset(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setupActions()
|
void Application::setupActions()
|
||||||
@@ -521,7 +541,9 @@ void Application::setupLogBrowser()
|
|||||||
_logBrowser = new LogBrowser;
|
_logBrowser = new LogBrowser;
|
||||||
qInstallMsgHandler( mirallLogCatcher );
|
qInstallMsgHandler( mirallLogCatcher );
|
||||||
// ## TODO: allow new log name maybe?
|
// ## TODO: allow new log name maybe?
|
||||||
if (!_logFile.isEmpty()) {
|
if (!_logDirectory.isEmpty()) {
|
||||||
|
enterNextLogFile();
|
||||||
|
} else if (!_logFile.isEmpty()) {
|
||||||
qDebug() << "Logging into logfile: " << _logFile << " with flush " << _logFlush;
|
qDebug() << "Logging into logfile: " << _logFile << " with flush " << _logFlush;
|
||||||
_logBrowser->setLogFile( _logFile, _logFlush );
|
_logBrowser->setLogFile( _logFile, _logFlush );
|
||||||
}
|
}
|
||||||
@@ -537,6 +559,37 @@ void Application::setupLogBrowser()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::enterNextLogFile()
|
||||||
|
{
|
||||||
|
if (_logBrowser && !_logDirectory.isEmpty()) {
|
||||||
|
QDir dir(_logDirectory);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkpath(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find out what is the file with the highest nymber if any
|
||||||
|
QStringList files = dir.entryList(QStringList("owncloud.log.*"),
|
||||||
|
QDir::Files);
|
||||||
|
QRegExp rx("owncloud.log.(\\d+)");
|
||||||
|
uint maxNumber = 0;
|
||||||
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
|
foreach(const QString &s, files) {
|
||||||
|
if (rx.exactMatch(s)) {
|
||||||
|
maxNumber = qMax(maxNumber, rx.cap(1).toUInt());
|
||||||
|
if (_logExpire > 0) {
|
||||||
|
QFileInfo fileInfo = dir.absoluteFilePath(s);
|
||||||
|
if (fileInfo.lastModified().addSecs(60*60 * _logExpire) < now) {
|
||||||
|
dir.remove(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString filename = _logDirectory + "/owncloud.log." + QString::number(maxNumber+1);
|
||||||
|
_logBrowser->setLogFile(filename , _logFlush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QNetworkProxy proxyFromConfig(const MirallConfigFile& cfg)
|
QNetworkProxy proxyFromConfig(const MirallConfigFile& cfg)
|
||||||
{
|
{
|
||||||
QNetworkProxy proxy;
|
QNetworkProxy proxy;
|
||||||
@@ -618,7 +671,7 @@ void Application::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
|
|||||||
slotFetchCredentials();
|
slotFetchCredentials();
|
||||||
}
|
}
|
||||||
#if defined Q_WS_WIN || defined Q_WS_X11
|
#if defined Q_WS_WIN || defined Q_WS_X11
|
||||||
if( reason == QSystemTrayIcon::Trigger && _actionOpenStatus->isEnabled() ) {
|
if( reason == QSystemTrayIcon::Trigger ) {
|
||||||
slotOpenStatus();
|
slotOpenStatus();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -626,44 +679,58 @@ void Application::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
|
|||||||
|
|
||||||
void Application::slotAddFolder()
|
void Application::slotAddFolder()
|
||||||
{
|
{
|
||||||
_folderMan->setSyncEnabled(false); // do not start more syncs.
|
/** Helper class to ensure sync is always switched back on */
|
||||||
|
class SyncDisabler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SyncDisabler(Application *app) : _app(app)
|
||||||
|
{
|
||||||
|
_app->_folderMan->setSyncEnabled(false);
|
||||||
|
}
|
||||||
|
~SyncDisabler() {
|
||||||
|
_app->_folderMan->setSyncEnabled(true);
|
||||||
|
_app->computeOverallSyncStatus();
|
||||||
|
_app->_folderMan->slotScheduleAllFolders();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Application *_app;
|
||||||
|
};
|
||||||
|
|
||||||
Folder::Map folderMap = _folderMan->map();
|
if (_folderWizard) {
|
||||||
|
raiseDialog(_folderWizard);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_folderWizard->setFolderMap( &folderMap );
|
// disables sync queuing while in scope
|
||||||
|
SyncDisabler disableSync(this);
|
||||||
|
|
||||||
_folderWizard->restart();
|
Folder::Map folderMap = _folderMan->map();
|
||||||
|
_folderWizard = new FolderWizard;
|
||||||
|
_folderWizard->setFolderMap( &folderMap );
|
||||||
|
|
||||||
if (_folderWizard->exec() == QDialog::Accepted) {
|
if (_folderWizard->exec() == QDialog::Accepted) {
|
||||||
qDebug() << "* Folder wizard completed";
|
qDebug() << "* Folder wizard completed";
|
||||||
|
|
||||||
bool goodData = true;
|
QString alias = _folderWizard->field(QLatin1String("alias")).toString();
|
||||||
|
QString sourceFolder = _folderWizard->field(QLatin1String("sourceFolder")).toString();
|
||||||
|
QString targetPath = _folderWizard->field(QLatin1String("OCFolderLineEdit")).toString();
|
||||||
|
QString backend = QLatin1String("owncloud");
|
||||||
|
|
||||||
QString alias = _folderWizard->field(QLatin1String("alias")).toString();
|
if (!FolderMan::ensureJournalGone( sourceFolder ))
|
||||||
QString sourceFolder = _folderWizard->field(QLatin1String("sourceFolder")).toString();
|
return;
|
||||||
QString backend = QLatin1String("owncloud");
|
_folderMan->addFolderDefinition( backend, alias, sourceFolder, targetPath, false );
|
||||||
QString targetPath;
|
|
||||||
bool onlyThisLAN = false;
|
|
||||||
|
|
||||||
targetPath = _folderWizard->field(QLatin1String("OCFolderLineEdit")).toString();
|
|
||||||
|
|
||||||
_folderMan->setSyncEnabled(true); // do start sync again.
|
|
||||||
|
|
||||||
if( goodData ) {
|
|
||||||
_folderMan->addFolderDefinition( backend, alias, sourceFolder, targetPath, onlyThisLAN );
|
|
||||||
Folder *f = _folderMan->setupFolderFromConfigFile( alias );
|
Folder *f = _folderMan->setupFolderFromConfigFile( alias );
|
||||||
if( f ) {
|
if( f ) {
|
||||||
_statusDialog->slotAddFolder( f );
|
_statusDialog->slotAddFolder( f );
|
||||||
_statusDialog->buttonsSetEnabled();
|
_statusDialog->buttonsSetEnabled();
|
||||||
setupContextMenu();
|
setupContextMenu();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "* Folder wizard cancelled";
|
qDebug() << "* Folder wizard cancelled";
|
||||||
}
|
}
|
||||||
_folderMan->setSyncEnabled(true);
|
_folderWizard->deleteLater();
|
||||||
_folderMan->slotScheduleAllFolders();
|
_folderWizard = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::slotOpenStatus()
|
void Application::slotOpenStatus()
|
||||||
@@ -673,7 +740,7 @@ void Application::slotOpenStatus()
|
|||||||
QWidget *raiseWidget = 0;
|
QWidget *raiseWidget = 0;
|
||||||
|
|
||||||
// check if there is a mirall.cfg already.
|
// check if there is a mirall.cfg already.
|
||||||
if( _owncloudSetupWizard->wizard()->isVisible() ) {
|
if( _owncloudSetupWizard && _owncloudSetupWizard->wizard()->isVisible() ) {
|
||||||
raiseWidget = _owncloudSetupWizard->wizard();
|
raiseWidget = _owncloudSetupWizard->wizard();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,8 +750,7 @@ void Application::slotOpenStatus()
|
|||||||
|
|
||||||
if( !cfgFile.exists() ) {
|
if( !cfgFile.exists() ) {
|
||||||
qDebug() << "No configured folders yet, start the Owncloud integration dialog.";
|
qDebug() << "No configured folders yet, start the Owncloud integration dialog.";
|
||||||
_folderMan->setSyncEnabled(false);
|
slotConfigure();
|
||||||
_owncloudSetupWizard->startWizard();
|
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "#============# Status dialog starting #=============#";
|
qDebug() << "#============# Status dialog starting #=============#";
|
||||||
raiseWidget = _statusDialog;
|
raiseWidget = _statusDialog;
|
||||||
@@ -731,16 +797,14 @@ void Application::slotAbout()
|
|||||||
void Application::slotRemoveFolder( const QString& alias )
|
void Application::slotRemoveFolder( const QString& alias )
|
||||||
{
|
{
|
||||||
int ret = QMessageBox::question( 0, tr("Confirm Folder Remove"),
|
int ret = QMessageBox::question( 0, tr("Confirm Folder Remove"),
|
||||||
tr("Do you really want to remove upload folder <i>%1</i>?").arg(alias),
|
tr("<p>Do you really want to stop syncing the upload folder <i>%1</i>?</p>"
|
||||||
|
"<p><b>Note:</b> This will not remove the files from your client.</p>").arg(alias),
|
||||||
QMessageBox::Yes|QMessageBox::No );
|
QMessageBox::Yes|QMessageBox::No );
|
||||||
|
|
||||||
if( ret == QMessageBox::No ) {
|
if( ret == QMessageBox::No ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Folder *f = _folderMan->folder(alias);
|
Folder *f = _folderMan->folder(alias);
|
||||||
if( f && _overallStatusStrings.contains( f->alias() )) {
|
|
||||||
_overallStatusStrings.remove( f->alias() );
|
|
||||||
}
|
|
||||||
|
|
||||||
_folderMan->slotRemoveFolder( alias );
|
_folderMan->slotRemoveFolder( alias );
|
||||||
_statusDialog->slotRemoveSelectedFolder( );
|
_statusDialog->slotRemoveSelectedFolder( );
|
||||||
@@ -794,11 +858,17 @@ void Application::slotEnableFolder(const QString& alias, const bool enable)
|
|||||||
|
|
||||||
void Application::slotConfigure()
|
void Application::slotConfigure()
|
||||||
{
|
{
|
||||||
_folderMan->setSyncEnabled(false); // do not start more syncs.
|
if (_owncloudSetupWizard && !_owncloudSetupWizard->wizard()->isVisible()) {
|
||||||
if (!_owncloudSetupWizard->wizard()->isVisible())
|
|
||||||
_owncloudSetupWizard->startWizard();
|
|
||||||
else
|
|
||||||
raiseDialog(_owncloudSetupWizard->wizard());
|
raiseDialog(_owncloudSetupWizard->wizard());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_owncloudSetupWizard.reset(new OwncloudSetupWizard( _folderMan, _theme, this ));;
|
||||||
|
connect( _owncloudSetupWizard.data(), SIGNAL(ownCloudWizardDone(int)),
|
||||||
|
this, SLOT(slotownCloudWizardDone(int)));
|
||||||
|
|
||||||
|
_folderMan->setSyncEnabled(false); // do not start more syncs.
|
||||||
|
_owncloudSetupWizard->startWizard();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::slotConfigureProxy()
|
void Application::slotConfigureProxy()
|
||||||
@@ -834,6 +904,10 @@ void Application::slotSyncStateChange( const QString& alias )
|
|||||||
computeOverallSyncStatus();
|
computeOverallSyncStatus();
|
||||||
|
|
||||||
qDebug() << "Sync state changed for folder " << alias << ": " << result.statusString();
|
qDebug() << "Sync state changed for folder " << alias << ": " << result.statusString();
|
||||||
|
|
||||||
|
if (result.status() == SyncResult::Success || result.status() == SyncResult::Error) {
|
||||||
|
enterNextLogFile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::parseOptions(const QStringList &options)
|
void Application::parseOptions(const QStringList &options)
|
||||||
@@ -857,6 +931,18 @@ void Application::parseOptions(const QStringList &options)
|
|||||||
} else {
|
} else {
|
||||||
setHelp();
|
setHelp();
|
||||||
}
|
}
|
||||||
|
} else if (option == QLatin1String("--logdir")) {
|
||||||
|
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
|
_logDirectory = it.next();
|
||||||
|
} else {
|
||||||
|
setHelp();
|
||||||
|
}
|
||||||
|
} else if (option == QLatin1String("--logexpire")) {
|
||||||
|
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
||||||
|
_logExpire = it.next().toInt();
|
||||||
|
} else {
|
||||||
|
setHelp();
|
||||||
|
}
|
||||||
} else if (option == QLatin1String("--logflush")) {
|
} else if (option == QLatin1String("--logflush")) {
|
||||||
_logFlush = true;
|
_logFlush = true;
|
||||||
} else if (option == QLatin1String("--monoicons")) {
|
} else if (option == QLatin1String("--monoicons")) {
|
||||||
@@ -880,11 +966,12 @@ void Application::computeOverallSyncStatus()
|
|||||||
|
|
||||||
// display the info of the least successful sync (eg. not just display the result of the latest sync
|
// display the info of the least successful sync (eg. not just display the result of the latest sync
|
||||||
SyncResult overallResult(SyncResult::Undefined );
|
SyncResult overallResult(SyncResult::Undefined );
|
||||||
|
QMap<QString, QString> overallStatusStrings;
|
||||||
QString trayMessage;
|
QString trayMessage;
|
||||||
Folder::Map map = _folderMan->map();
|
Folder::Map map = _folderMan->map();
|
||||||
|
|
||||||
foreach ( Folder *syncedFolder, map.values() ) {
|
foreach ( Folder *syncedFolder, map.values() ) {
|
||||||
QString folderMessage = _overallStatusStrings[syncedFolder->alias()];
|
QString folderMessage;
|
||||||
|
|
||||||
SyncResult folderResult = syncedFolder->syncResult();
|
SyncResult folderResult = syncedFolder->syncResult();
|
||||||
SyncResult::Status syncStatus = folderResult.status();
|
SyncResult::Status syncStatus = folderResult.status();
|
||||||
@@ -914,9 +1001,9 @@ void Application::computeOverallSyncStatus()
|
|||||||
break;
|
break;
|
||||||
case SyncResult::Success:
|
case SyncResult::Success:
|
||||||
if( overallResult.status() == SyncResult::Undefined ) {
|
if( overallResult.status() == SyncResult::Undefined ) {
|
||||||
folderMessage = tr( "Last Sync was successful." );
|
|
||||||
overallResult.setStatus( SyncResult::Success );
|
overallResult.setStatus( SyncResult::Success );
|
||||||
}
|
}
|
||||||
|
folderMessage = tr( "Last Sync was successful." );
|
||||||
break;
|
break;
|
||||||
case SyncResult::Error:
|
case SyncResult::Error:
|
||||||
overallResult.setStatus( SyncResult::Error );
|
overallResult.setStatus( SyncResult::Error );
|
||||||
@@ -938,15 +1025,13 @@ void Application::computeOverallSyncStatus()
|
|||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Folder in overallStatus Message: " << syncedFolder << " with name " << syncedFolder->alias();
|
qDebug() << "Folder in overallStatus Message: " << syncedFolder << " with name " << syncedFolder->alias();
|
||||||
QString msg = QString::fromLatin1("Folder %1: %2").arg(syncedFolder->alias()).arg(folderMessage);
|
QString msg = tr("Folder %1: %2").arg(syncedFolder->alias(), folderMessage);
|
||||||
if( msg != _overallStatusStrings[syncedFolder->alias()] ) {
|
overallStatusStrings[syncedFolder->alias()] = msg;
|
||||||
_overallStatusStrings[syncedFolder->alias()] = msg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the tray blob message, check if we have an defined state
|
// create the tray blob message, check if we have an defined state
|
||||||
if( overallResult.status() != SyncResult::Undefined ) {
|
if( overallResult.status() != SyncResult::Undefined ) {
|
||||||
QStringList allStatusStrings = _overallStatusStrings.values();
|
QStringList allStatusStrings = overallStatusStrings.values();
|
||||||
if( ! allStatusStrings.isEmpty() )
|
if( ! allStatusStrings.isEmpty() )
|
||||||
trayMessage = allStatusStrings.join(QLatin1String("\n"));
|
trayMessage = allStatusStrings.join(QLatin1String("\n"));
|
||||||
else
|
else
|
||||||
@@ -959,22 +1044,48 @@ void Application::computeOverallSyncStatus()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helpers for displaying messages. Note that there is no console on Windows.
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// Format as <pre> HTML
|
||||||
|
static inline void toHtml(QString &t)
|
||||||
|
{
|
||||||
|
t.replace(QLatin1Char('&'), QLatin1String("&"));
|
||||||
|
t.replace(QLatin1Char('<'), QLatin1String("<"));
|
||||||
|
t.replace(QLatin1Char('>'), QLatin1String(">"));
|
||||||
|
t.insert(0, QLatin1String("<html><pre>"));
|
||||||
|
t.append(QLatin1String("</pre></html>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void displayHelpText(QString t) // No console on Windows.
|
||||||
|
{
|
||||||
|
toHtml(t);
|
||||||
|
QMessageBox::information(0, Theme::instance()->appNameGUI(), t);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void displayHelpText(const QString &t)
|
||||||
|
{
|
||||||
|
std::cout << qPrintable(t);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Application::showHelp()
|
void Application::showHelp()
|
||||||
{
|
{
|
||||||
setHelp();
|
setHelp();
|
||||||
std::cout << _theme->appName().toLatin1().constData() << " version " <<
|
QString helpText;
|
||||||
_theme->version().toLatin1().constData() << std::endl << std::endl;
|
QTextStream stream(&helpText);
|
||||||
std::cout << "File synchronisation desktop utility." << std::endl << std::endl;
|
stream << _theme->appName().toLatin1().constData()
|
||||||
std::cout << "Options:" << std::endl;
|
<< QLatin1String(" version ")
|
||||||
std::cout << " -h --help : show this help screen." << std::endl;
|
<< _theme->version().toLatin1().constData() << endl;
|
||||||
std::cout << " --logwindow : open a window to show log output." << std::endl;
|
|
||||||
std::cout << " --logfile <filename> : write log output to file <filename>." << std::endl;
|
stream << QLatin1String("File synchronisation desktop utility.") << endl << endl
|
||||||
std::cout << " --logflush : flush the log file after every write." << std::endl;
|
<< QLatin1String(optionsC);
|
||||||
std::cout << " --monoicons : Use black/white pictograms for systray." << std::endl;
|
|
||||||
std::cout << " --confdir <dirname> : Use the given configuration directory." << std::endl;
|
|
||||||
std::cout << std::endl;
|
|
||||||
if (_theme->appName() == QLatin1String("ownCloud"))
|
if (_theme->appName() == QLatin1String("ownCloud"))
|
||||||
std::cout << "For more information, see http://www.owncloud.org" << std::endl;
|
stream << endl << "For more information, see http://www.owncloud.org" << endl;
|
||||||
|
|
||||||
|
displayHelpText(helpText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setHelp()
|
void Application::setHelp()
|
||||||
@@ -982,6 +1093,30 @@ void Application::setHelp()
|
|||||||
_helpOnly = true;
|
_helpOnly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
bool Application::winEventFilter(MSG *pMsg, long *result)
|
||||||
|
{
|
||||||
|
if (pMsg->message == WM_POWERBROADCAST) {
|
||||||
|
switch(pMsg->wParam) {
|
||||||
|
case PBT_APMPOWERSTATUSCHANGE:
|
||||||
|
qDebug() << "WM_POWERBROADCAST: Power state changed";
|
||||||
|
break;
|
||||||
|
case PBT_APMSUSPEND:
|
||||||
|
qDebug() << "WM_POWERBROADCAST: Entering low power state";
|
||||||
|
break;
|
||||||
|
case PBT_APMRESUMEAUTOMATIC:
|
||||||
|
qDebug() << "WM_POWERBROADCAST: Resuming from low power state";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SharedTools::QtSingleApplication::winEventFilter(pMsg, result);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QString substLang(const QString &lang)
|
QString substLang(const QString &lang)
|
||||||
{
|
{
|
||||||
// Map the more apropriate script codes
|
// Map the more apropriate script codes
|
||||||
|
|||||||
@@ -79,10 +79,16 @@ protected:
|
|||||||
void setupContextMenu();
|
void setupContextMenu();
|
||||||
void setupLogBrowser();
|
void setupLogBrowser();
|
||||||
void setupProxy();
|
void setupProxy();
|
||||||
|
void enterNextLogFile();
|
||||||
|
|
||||||
//folders have to be disabled while making config changes
|
//folders have to be disabled while making config changes
|
||||||
void computeOverallSyncStatus();
|
void computeOverallSyncStatus();
|
||||||
|
|
||||||
|
// reimplemented
|
||||||
|
#if defined(Q_WS_WIN)
|
||||||
|
bool winEventFilter( MSG * message, long * result );
|
||||||
|
#endif
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void slotTrayClicked( QSystemTrayIcon::ActivationReason );
|
void slotTrayClicked( QSystemTrayIcon::ActivationReason );
|
||||||
void slotFolderOpenAction(const QString & );
|
void slotFolderOpenAction(const QString & );
|
||||||
@@ -118,7 +124,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
FolderWizard *_folderWizard;
|
FolderWizard *_folderWizard;
|
||||||
OwncloudSetupWizard *_owncloudSetupWizard;
|
QScopedPointer<OwncloudSetupWizard> _owncloudSetupWizard;
|
||||||
SslErrorDialog *_sslErrorDialog;
|
SslErrorDialog *_sslErrorDialog;
|
||||||
|
|
||||||
// tray's menu
|
// tray's menu
|
||||||
@@ -130,9 +136,10 @@ private:
|
|||||||
Theme *_theme;
|
Theme *_theme;
|
||||||
QSignalMapper *_folderOpenActionMapper;
|
QSignalMapper *_folderOpenActionMapper;
|
||||||
UpdateDetector *_updateDetector;
|
UpdateDetector *_updateDetector;
|
||||||
QMap<QString, QString> _overallStatusStrings;
|
|
||||||
LogBrowser *_logBrowser;
|
LogBrowser *_logBrowser;
|
||||||
QString _logFile;
|
QString _logFile;
|
||||||
|
QString _logDirectory;
|
||||||
|
int _logExpire;
|
||||||
bool _showLogWindow;
|
bool _showLogWindow;
|
||||||
bool _logFlush;
|
bool _logFlush;
|
||||||
bool _helpOnly;
|
bool _helpOnly;
|
||||||
|
|||||||
@@ -69,15 +69,12 @@ CredentialStore::CredState CredentialStore::state()
|
|||||||
|
|
||||||
bool CredentialStore::canTryAgain()
|
bool CredentialStore::canTryAgain()
|
||||||
{
|
{
|
||||||
bool canDoIt = false;
|
|
||||||
|
|
||||||
if( _tries > MAX_LOGIN_ATTEMPTS ) {
|
if( _tries > MAX_LOGIN_ATTEMPTS ) {
|
||||||
qDebug() << "canTryAgain: Max attempts reached.";
|
qDebug() << "canTryAgain: Max attempts reached.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Since QtKeyChain is required now, it makes to only
|
/* Since QtKeyChain is required now, it makes sense to only query once. */
|
||||||
* query once. */
|
|
||||||
if( _state == NotFetched || _state == AsyncWriting ) {
|
if( _state == NotFetched || _state == AsyncWriting ) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@@ -126,7 +123,7 @@ void CredentialStore::fetchCredentials()
|
|||||||
_inputDialog->setTextEchoMode( QLineEdit::Password );
|
_inputDialog->setTextEchoMode( QLineEdit::Password );
|
||||||
|
|
||||||
connect(_inputDialog, SIGNAL(finished(int)), SLOT(slotUserDialogDone(int)));
|
connect(_inputDialog, SIGNAL(finished(int)), SLOT(slotUserDialogDone(int)));
|
||||||
_inputDialog->exec();
|
_inputDialog->open();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CredentialStore::Settings: {
|
case CredentialStore::Settings: {
|
||||||
@@ -363,9 +360,9 @@ void CredentialStore::slotKeyChainWriteFinished( QKeychain::Job *job )
|
|||||||
qDebug() << "Error with keychain: " << pwdJob->errorString();
|
qDebug() << "Error with keychain: " << pwdJob->errorString();
|
||||||
if( err == NoBackendAvailable || err == NotImplemented ||
|
if( err == NoBackendAvailable || err == NotImplemented ||
|
||||||
pwdJob->errorString().contains(QLatin1String("Could not open wallet"))) {
|
pwdJob->errorString().contains(QLatin1String("Could not open wallet"))) {
|
||||||
|
_state = NoKeychainBackend;
|
||||||
_type = Settings;
|
_type = Settings;
|
||||||
saveCredentials();
|
saveCredentials();
|
||||||
_state = NoKeychainBackend;
|
|
||||||
} else {
|
} else {
|
||||||
_state = Error;
|
_state = Error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ CSyncThread::~CSyncThread()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Convert an error code from csync to a user readable string.
|
||||||
|
// Keep that function thread safe as it can be called from the sync thread or the main thread
|
||||||
QString CSyncThread::csyncErrorToString( CSYNC_ERROR_CODE err, const char *errString )
|
QString CSyncThread::csyncErrorToString( CSYNC_ERROR_CODE err, const char *errString )
|
||||||
{
|
{
|
||||||
QString errStr;
|
QString errStr;
|
||||||
@@ -106,8 +108,6 @@ QString CSyncThread::csyncErrorToString( CSYNC_ERROR_CODE err, const char *errSt
|
|||||||
break;
|
break;
|
||||||
case CSYNC_ERR_ACCESS_FAILED:
|
case CSYNC_ERR_ACCESS_FAILED:
|
||||||
errStr = tr("<p>The target directory does not exist.</p><p>Please check the sync setup.</p>");
|
errStr = tr("<p>The target directory does not exist.</p><p>Please check the sync setup.</p>");
|
||||||
// this is critical. The database has to be removed.
|
|
||||||
emit wipeDb();
|
|
||||||
break;
|
break;
|
||||||
case CSYNC_ERR_REMOTE_CREATE:
|
case CSYNC_ERR_REMOTE_CREATE:
|
||||||
case CSYNC_ERR_REMOTE_STAT:
|
case CSYNC_ERR_REMOTE_STAT:
|
||||||
@@ -191,6 +191,11 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
|||||||
|
|
||||||
int re = 0;
|
int re = 0;
|
||||||
|
|
||||||
|
if (file->instruction != CSYNC_INSTRUCTION_IGNORE
|
||||||
|
&& file->instruction != CSYNC_INSTRUCTION_REMOVE) {
|
||||||
|
_hasFiles = true;
|
||||||
|
}
|
||||||
|
|
||||||
switch(file->instruction) {
|
switch(file->instruction) {
|
||||||
case CSYNC_INSTRUCTION_NONE:
|
case CSYNC_INSTRUCTION_NONE:
|
||||||
case CSYNC_INSTRUCTION_IGNORE:
|
case CSYNC_INSTRUCTION_IGNORE:
|
||||||
@@ -245,8 +250,8 @@ int CSyncThread::treewalkError(TREE_WALK_FILE* file)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if( file &&
|
if( file &&
|
||||||
file->instruction == CSYNC_INSTRUCTION_STAT_ERROR ||
|
(file->instruction == CSYNC_INSTRUCTION_STAT_ERROR ||
|
||||||
file->instruction == CSYNC_INSTRUCTION_ERROR ) {
|
file->instruction == CSYNC_INSTRUCTION_ERROR) ) {
|
||||||
_mutex.lock();
|
_mutex.lock();
|
||||||
_syncedItems[indx]._instruction = file->instruction;
|
_syncedItems[indx]._instruction = file->instruction;
|
||||||
_mutex.unlock();
|
_mutex.unlock();
|
||||||
@@ -310,6 +315,7 @@ void CSyncThread::startSync()
|
|||||||
// cleans up behind us and emits finished() to ease error handling
|
// cleans up behind us and emits finished() to ease error handling
|
||||||
CSyncRunScopeHelper helper(_csync_ctx, this);
|
CSyncRunScopeHelper helper(_csync_ctx, this);
|
||||||
|
|
||||||
|
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
|
||||||
csync_set_userdata(_csync_ctx, this);
|
csync_set_userdata(_csync_ctx, this);
|
||||||
|
|
||||||
// csync_set_auth_callback( _csync_ctx, getauth );
|
// csync_set_auth_callback( _csync_ctx, getauth );
|
||||||
@@ -327,6 +333,7 @@ void CSyncThread::startSync()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hasFiles = false;
|
||||||
bool walkOk = true;
|
bool walkOk = true;
|
||||||
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
|
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
|
||||||
qDebug() << "Error in local treewalk.";
|
qDebug() << "Error in local treewalk.";
|
||||||
@@ -336,6 +343,16 @@ void CSyncThread::startSync()
|
|||||||
qDebug() << "Error in remote treewalk.";
|
qDebug() << "Error in remote treewalk.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_hasFiles && !_syncedItems.isEmpty()) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "All the files are going to be removed, asking the user";
|
||||||
|
bool cancel = true;
|
||||||
|
emit aboutToRemoveAllFiles(_syncedItems.first()._dir, &cancel);
|
||||||
|
if (cancel) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "Abort sync";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_needsUpdate)
|
if (_needsUpdate)
|
||||||
emit(started());
|
emit(started());
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
CSyncThread(CSYNC *);
|
CSyncThread(CSYNC *);
|
||||||
~CSyncThread();
|
~CSyncThread();
|
||||||
|
|
||||||
QString csyncErrorToString( CSYNC_ERROR_CODE, const char * );
|
static QString csyncErrorToString( CSYNC_ERROR_CODE, const char * );
|
||||||
|
|
||||||
Q_INVOKABLE void startSync();
|
Q_INVOKABLE void startSync();
|
||||||
|
|
||||||
@@ -56,6 +56,8 @@ signals:
|
|||||||
void finished();
|
void finished();
|
||||||
void started();
|
void started();
|
||||||
|
|
||||||
|
void aboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleSyncError(CSYNC *ctx, const char *state);
|
void handleSyncError(CSYNC *ctx, const char *state);
|
||||||
static void progress(const char *remote_url,
|
static void progress(const char *remote_url,
|
||||||
@@ -79,6 +81,8 @@ private:
|
|||||||
CSYNC *_csync_ctx;
|
CSYNC *_csync_ctx;
|
||||||
bool _needsUpdate;
|
bool _needsUpdate;
|
||||||
|
|
||||||
|
bool _hasFiles; // true if there is at least one file that is not ignored or removed
|
||||||
|
|
||||||
friend class CSyncRunScopeHelper;
|
friend class CSyncRunScopeHelper;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,10 @@ void FileItemDialog::slotSetFolderMessage()
|
|||||||
QDateTime now = QDateTime::currentDateTime();
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
int secs = _lastSyncTime.secsTo(now);
|
int secs = _lastSyncTime.secsTo(now);
|
||||||
|
|
||||||
_timelabel->setText(tr("%1 (finished %n sec. ago)", "", secs).arg(_folderMessage));
|
if (secs < 60)
|
||||||
|
_timelabel->setText(tr("%1 (last finished %n sec. ago)", "", secs).arg(_folderMessage));
|
||||||
|
else
|
||||||
|
_timelabel->setText(tr("%1 (last finished %n min. ago)", "", secs/60).arg(_folderMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileItemDialog::copyToClipboard()
|
void FileItemDialog::copyToClipboard()
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
@@ -79,20 +80,28 @@ void FolderMan::slotReparseConfiguration()
|
|||||||
setupKnownFolders();
|
setupKnownFolders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int FolderMan::unloadAllFolders()
|
||||||
|
{
|
||||||
|
// first terminate sync jobs.
|
||||||
|
terminateCurrentSync();
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
// clear the list of existing folders.
|
||||||
|
Folder::MapIterator i(_folderMap);
|
||||||
|
while (i.hasNext()) {
|
||||||
|
i.next();
|
||||||
|
delete _folderMap.take( i.key() );
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
int FolderMan::setupKnownFolders()
|
int FolderMan::setupKnownFolders()
|
||||||
{
|
{
|
||||||
qDebug() << "* Setup folders from " << _folderConfigPath;
|
qDebug() << "* Setup folders from " << _folderConfigPath;
|
||||||
|
|
||||||
// first terminate sync jobs.
|
unloadAllFolders();
|
||||||
terminateCurrentSync();
|
|
||||||
|
|
||||||
// clear the list of existing folders.
|
|
||||||
Folder::MapIterator i(_folderMap);
|
|
||||||
while (i.hasNext()) {
|
|
||||||
i.next();
|
|
||||||
delete _folderMap.take( i.key() );
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir dir( _folderConfigPath );
|
QDir dir( _folderConfigPath );
|
||||||
dir.setFilter(QDir::Files);
|
dir.setFilter(QDir::Files);
|
||||||
@@ -117,6 +126,25 @@ void FolderMan::wipeAllJournals()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FolderMan::ensureJournalGone(const QString &localPath)
|
||||||
|
{
|
||||||
|
|
||||||
|
// remove old .csync_journal file
|
||||||
|
QString stateDbFile = localPath+QLatin1String("/.csync_journal.db");
|
||||||
|
while (QFile::exists(stateDbFile) && !QFile::remove(stateDbFile)) {
|
||||||
|
int ret = QMessageBox::warning(0, tr("Could not reset folder state"),
|
||||||
|
tr("An old sync journal '%1' was found, "
|
||||||
|
"but could not be removed. Please make sure "
|
||||||
|
"that no application is currently using it.")
|
||||||
|
.arg(QDir::fromNativeSeparators(QDir::cleanPath(stateDbFile))),
|
||||||
|
QMessageBox::Retry|QMessageBox::Abort);
|
||||||
|
if (ret == QMessageBox::Abort) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void FolderMan::terminateCurrentSync()
|
void FolderMan::terminateCurrentSync()
|
||||||
{
|
{
|
||||||
if( !_currentSyncFolder.isEmpty() ) {
|
if( !_currentSyncFolder.isEmpty() ) {
|
||||||
@@ -235,7 +263,7 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
|
|||||||
folder->setConfigFile(file);
|
folder->setConfigFile(file);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "unknown backend" << backend;
|
qWarning() << "unknown backend" << backend;
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,12 +303,18 @@ void FolderMan::slotEnableFolder( const QString& alias, bool enable )
|
|||||||
// csync still remains in a stable state, regardless of that.
|
// csync still remains in a stable state, regardless of that.
|
||||||
void FolderMan::terminateSyncProcess( const QString& alias )
|
void FolderMan::terminateSyncProcess( const QString& alias )
|
||||||
{
|
{
|
||||||
Folder *f = _folderMap[alias];
|
QString folderAlias = alias;
|
||||||
if( f ) {
|
if( alias.isEmpty() ) {
|
||||||
f->slotTerminateSync();
|
folderAlias = _currentSyncFolder;
|
||||||
|
}
|
||||||
|
if( ! folderAlias.isEmpty() ) {
|
||||||
|
Folder *f = _folderMap[folderAlias];
|
||||||
|
if( f ) {
|
||||||
|
f->slotTerminateSync();
|
||||||
|
|
||||||
if(_currentSyncFolder == alias )
|
if(_currentSyncFolder == folderAlias )
|
||||||
_currentSyncFolder = QString::null;
|
_currentSyncFolder = QString::null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,6 +471,8 @@ void FolderMan::removeFolder( const QString& alias )
|
|||||||
{
|
{
|
||||||
Folder *f = 0;
|
Folder *f = 0;
|
||||||
|
|
||||||
|
_scheduleQueue.removeAll(alias);
|
||||||
|
|
||||||
if( _folderMap.contains( alias )) {
|
if( _folderMap.contains( alias )) {
|
||||||
qDebug() << "Removing " << alias;
|
qDebug() << "Removing " << alias;
|
||||||
f = _folderMap.take( alias );
|
f = _folderMap.take( alias );
|
||||||
@@ -464,7 +500,7 @@ QString FolderMan::getBackupName( const QString& fullPathName ) const
|
|||||||
int cnt = 1;
|
int cnt = 1;
|
||||||
do {
|
do {
|
||||||
if( fi.exists() ) {
|
if( fi.exists() ) {
|
||||||
newName += fullPathName + QString( ".oC_bak_%1").arg(cnt++);
|
newName = fullPathName + QString( ".oC_bak_%1").arg(cnt++);
|
||||||
fi.setFile(newName);
|
fi.setFile(newName);
|
||||||
}
|
}
|
||||||
} while( fi.exists() );
|
} while( fi.exists() );
|
||||||
@@ -479,6 +515,13 @@ bool FolderMan::startFromScratch( const QString& localFolder )
|
|||||||
QFileInfo fi( localFolder );
|
QFileInfo fi( localFolder );
|
||||||
if( fi.exists() && fi.isDir() ) {
|
if( fi.exists() && fi.isDir() ) {
|
||||||
QDir file = fi.dir();
|
QDir file = fi.dir();
|
||||||
|
|
||||||
|
// check if there are files in the directory.
|
||||||
|
if( file.count() == 0 ) {
|
||||||
|
// directory is existing, but its empty. Use it.
|
||||||
|
qDebug() << "startFromScratch: Directory is empty!";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
QString newName = getBackupName( fi.absoluteFilePath() );
|
QString newName = getBackupName( fi.absoluteFilePath() );
|
||||||
|
|
||||||
if( file.rename( fi.absoluteFilePath(), newName )) {
|
if( file.rename( fi.absoluteFilePath(), newName )) {
|
||||||
|
|||||||
@@ -76,6 +76,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void wipeAllJournals();
|
void wipeAllJournals();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that a given directory does not contain a .csync_journal.
|
||||||
|
*
|
||||||
|
* @returns false if the journal could not be removed, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool ensureJournalGone(const QString &path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new and empty local directory.
|
* Creates a new and empty local directory.
|
||||||
*/
|
*/
|
||||||
@@ -102,7 +109,10 @@ public slots:
|
|||||||
|
|
||||||
void slotReparseConfiguration();
|
void slotReparseConfiguration();
|
||||||
|
|
||||||
void terminateSyncProcess( const QString& );
|
void terminateSyncProcess( const QString& alias = QString::null );
|
||||||
|
|
||||||
|
/* delete all folder objects */
|
||||||
|
int unloadAllFolders();
|
||||||
|
|
||||||
// if enabled is set to false, no new folders will start to sync.
|
// if enabled is set to false, no new folders will start to sync.
|
||||||
// the current one will finish.
|
// the current one will finish.
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ FolderWizardSourcePage::FolderWizardSourcePage()
|
|||||||
{
|
{
|
||||||
_ui.setupUi(this);
|
_ui.setupUi(this);
|
||||||
registerField(QLatin1String("sourceFolder*"), _ui.localFolderLineEdit);
|
registerField(QLatin1String("sourceFolder*"), _ui.localFolderLineEdit);
|
||||||
_ui.localFolderLineEdit->setText( QString::fromLatin1( "%1/%2").arg( QDir::homePath() ).arg(Theme::instance()->appName() ) );
|
QString defaultPath = QString::fromLatin1( "%1/%2").arg( QDir::homePath() ).arg(Theme::instance()->appName() );
|
||||||
|
_ui.localFolderLineEdit->setText( QDir::toNativeSeparators( defaultPath ) );
|
||||||
registerField(QLatin1String("alias*"), _ui.aliasLineEdit);
|
registerField(QLatin1String("alias*"), _ui.aliasLineEdit);
|
||||||
_ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() );
|
_ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() );
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ void FolderWizardSourcePage::cleanupPage()
|
|||||||
|
|
||||||
bool FolderWizardSourcePage::isComplete() const
|
bool FolderWizardSourcePage::isComplete() const
|
||||||
{
|
{
|
||||||
QFileInfo selFile( _ui.localFolderLineEdit->text() );
|
QFileInfo selFile( QDir::fromNativeSeparators(_ui.localFolderLineEdit->text()) );
|
||||||
QString userInput = selFile.canonicalFilePath();
|
QString userInput = selFile.canonicalFilePath();
|
||||||
|
|
||||||
QString warnString;
|
QString warnString;
|
||||||
@@ -94,7 +95,8 @@ bool FolderWizardSourcePage::isComplete() const
|
|||||||
qDebug() << "Checking local path: " << folderDir << " <-> " << userInput;
|
qDebug() << "Checking local path: " << folderDir << " <-> " << userInput;
|
||||||
if( QFileInfo( f->path() ) == userInput ) {
|
if( QFileInfo( f->path() ) == userInput ) {
|
||||||
isOk = false;
|
isOk = false;
|
||||||
warnString.append( tr("The local path %1 is already an upload folder.<br/>Please pick another one!").arg(userInput) );
|
warnString.append( tr("The local path %1 is already an upload folder.<br/>Please pick another one!")
|
||||||
|
.arg(QDir::toNativeSeparators(userInput)) );
|
||||||
}
|
}
|
||||||
if( isOk && folderDir.startsWith( userInput )) {
|
if( isOk && folderDir.startsWith( userInput )) {
|
||||||
qDebug() << "A already configured folder is child of the current selected";
|
qDebug() << "A already configured folder is child of the current selected";
|
||||||
@@ -148,7 +150,7 @@ void FolderWizardSourcePage::on_localFolderChooseBtn_clicked()
|
|||||||
tr("Select the source folder"),
|
tr("Select the source folder"),
|
||||||
QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
|
QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
|
||||||
if (!dir.isEmpty()) {
|
if (!dir.isEmpty()) {
|
||||||
_ui.localFolderLineEdit->setText(dir);
|
_ui.localFolderLineEdit->setText(QDir::toNativeSeparators(dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,9 +98,7 @@ public:
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
Page_Source,
|
Page_Source,
|
||||||
Page_Target,
|
Page_Target
|
||||||
Page_Network,
|
|
||||||
Page_Owncloud
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FolderWizard(QWidget *parent = 0);
|
FolderWizard(QWidget *parent = 0);
|
||||||
|
|||||||
@@ -113,15 +113,12 @@ LogBrowser::LogBrowser(QWidget *parent) :
|
|||||||
|
|
||||||
setModal(false);
|
setModal(false);
|
||||||
|
|
||||||
// needs to be a queued connection as logs from other threads come in
|
// Direct connection for log comming from this thread, and queued for the one in a different thread
|
||||||
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::QueuedConnection);
|
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogBrowser::~LogBrowser()
|
LogBrowser::~LogBrowser()
|
||||||
{
|
{
|
||||||
if( _logstream ) {
|
|
||||||
_logFile.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogBrowser::slotNewLog( const QString& msg )
|
void LogBrowser::slotNewLog( const QString& msg )
|
||||||
@@ -138,6 +135,9 @@ void LogBrowser::slotNewLog( const QString& msg )
|
|||||||
|
|
||||||
void LogBrowser::setLogFile( const QString & name, bool flush )
|
void LogBrowser::setLogFile( const QString & name, bool flush )
|
||||||
{
|
{
|
||||||
|
if( _logstream ) {
|
||||||
|
_logFile.close();
|
||||||
|
}
|
||||||
_logFile.setFileName( name );
|
_logFile.setFileName( name );
|
||||||
|
|
||||||
if(!_logFile.open(QIODevice::WriteOnly)) {
|
if(!_logFile.open(QIODevice::WriteOnly)) {
|
||||||
@@ -150,7 +150,7 @@ void LogBrowser::setLogFile( const QString & name, bool flush )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_doFileFlush = flush;
|
_doFileFlush = flush;
|
||||||
_logstream = new QTextStream( &_logFile );
|
_logstream.reset(new QTextStream( &_logFile ));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogBrowser::slotFind()
|
void LogBrowser::slotFind()
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ private:
|
|||||||
|
|
||||||
QFile _logFile;
|
QFile _logFile;
|
||||||
bool _doFileFlush;
|
bool _doFileFlush;
|
||||||
QTextStream *_logstream;
|
QScopedPointer<QTextStream> _logstream;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -374,26 +374,23 @@ QString MirallConfigFile::ownCloudPasswd( const QString& connection ) const
|
|||||||
settings.setIniCodec( "UTF-8" );
|
settings.setIniCodec( "UTF-8" );
|
||||||
settings.beginGroup( con );
|
settings.beginGroup( con );
|
||||||
|
|
||||||
QString pwd;
|
|
||||||
|
|
||||||
QByteArray pwdba = settings.value(QLatin1String("passwd")).toByteArray();
|
QByteArray pwdba = settings.value(QLatin1String("passwd")).toByteArray();
|
||||||
if( pwdba.isEmpty() ) {
|
if( !pwdba.isEmpty() ) {
|
||||||
// check the password entry, cleartext from before
|
return QString::fromUtf8( QByteArray::fromBase64(pwdba) );
|
||||||
// read it and convert to base64, delete the cleartext entry.
|
|
||||||
QString p = settings.value(QLatin1String("password")).toString();
|
|
||||||
|
|
||||||
if( ! p.isEmpty() ) {
|
|
||||||
// its there, save base64-encoded and delete.
|
|
||||||
|
|
||||||
pwdba = p.toUtf8();
|
|
||||||
settings.setValue( QLatin1String("passwd"), QVariant(pwdba.toBase64()) );
|
|
||||||
settings.remove( QLatin1String("password") );
|
|
||||||
settings.sync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pwd = QString::fromUtf8( QByteArray::fromBase64(pwdba) );
|
|
||||||
|
|
||||||
return pwd;
|
// check the password entry, cleartext from before
|
||||||
|
// read it and convert to base64, delete the cleartext entry.
|
||||||
|
QString p = settings.value(QLatin1String("password")).toString();
|
||||||
|
|
||||||
|
if( ! p.isEmpty() ) {
|
||||||
|
// its there, save base64-encoded and delete.
|
||||||
|
pwdba = p.toUtf8();
|
||||||
|
settings.setValue( QLatin1String("passwd"), QVariant(pwdba.toBase64()) );
|
||||||
|
settings.remove( QLatin1String("password") );
|
||||||
|
settings.sync();
|
||||||
|
}
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::ownCloudVersion() const
|
QString MirallConfigFile::ownCloudVersion() const
|
||||||
@@ -562,7 +559,7 @@ int MirallConfigFile::proxyPort() const
|
|||||||
|
|
||||||
bool MirallConfigFile::proxyNeedsAuth() const
|
bool MirallConfigFile::proxyNeedsAuth() const
|
||||||
{
|
{
|
||||||
return getValue(QLatin1String("needsAuth"), QLatin1String("proxy")).toInt();
|
return getValue(QLatin1String("needsAuth"), QLatin1String("proxy")).toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MirallConfigFile::proxyUser() const
|
QString MirallConfigFile::proxyUser() const
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkProxyFactory>
|
#include <QNetworkProxyFactory>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
namespace Mirall {
|
namespace Mirall {
|
||||||
|
|
||||||
@@ -67,7 +69,6 @@ ownCloudFolder::ownCloudFolder(const QString &alias,
|
|||||||
, _csync(0)
|
, _csync(0)
|
||||||
, _csyncError(false)
|
, _csyncError(false)
|
||||||
, _csyncUnavail(false)
|
, _csyncUnavail(false)
|
||||||
, _wipeDb(false)
|
|
||||||
{
|
{
|
||||||
ServerActionNotifier *notifier = new ServerActionNotifier(this);
|
ServerActionNotifier *notifier = new ServerActionNotifier(this);
|
||||||
connect(notifier, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
|
connect(notifier, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
|
||||||
@@ -97,7 +98,9 @@ ownCloudFolder::ownCloudFolder(const QString &alias,
|
|||||||
csync_set_auth_callback( _csync_ctx, getauth );
|
csync_set_auth_callback( _csync_ctx, getauth );
|
||||||
|
|
||||||
if( csync_init( _csync_ctx ) < 0 ) {
|
if( csync_init( _csync_ctx ) < 0 ) {
|
||||||
qDebug() << "Could not initialize csync!";
|
qDebug() << "Could not initialize csync!" << csync_get_error(_csync_ctx) << csync_get_error_string(_csync_ctx);
|
||||||
|
slotCSyncError(CSyncThread::csyncErrorToString(csync_get_error(_csync_ctx), csync_get_error_string(_csync_ctx)));
|
||||||
|
csync_destroy(_csync_ctx);
|
||||||
_csync_ctx = 0;
|
_csync_ctx = 0;
|
||||||
}
|
}
|
||||||
setProxy();
|
setProxy();
|
||||||
@@ -112,6 +115,7 @@ ownCloudFolder::~ownCloudFolder()
|
|||||||
csync_request_abort(_csync_ctx);
|
csync_request_abort(_csync_ctx);
|
||||||
_thread->wait();
|
_thread->wait();
|
||||||
}
|
}
|
||||||
|
delete _csync;
|
||||||
// Destroy csync here.
|
// Destroy csync here.
|
||||||
csync_destroy(_csync_ctx);
|
csync_destroy(_csync_ctx);
|
||||||
}
|
}
|
||||||
@@ -257,6 +261,13 @@ void ownCloudFolder::startSync()
|
|||||||
|
|
||||||
void ownCloudFolder::startSync(const QStringList &pathList)
|
void ownCloudFolder::startSync(const QStringList &pathList)
|
||||||
{
|
{
|
||||||
|
if (!_csync_ctx) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "_csync_ctx is empty. probably because csync_init has failed.";
|
||||||
|
// the error should already be set
|
||||||
|
QMetaObject::invokeMethod(this, "slotCSyncFinished", Qt::QueuedConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_thread && _thread->isRunning()) {
|
if (_thread && _thread->isRunning()) {
|
||||||
qCritical() << "* ERROR csync is still running and new sync requested.";
|
qCritical() << "* ERROR csync is still running and new sync requested.";
|
||||||
return;
|
return;
|
||||||
@@ -268,7 +279,6 @@ void ownCloudFolder::startSync(const QStringList &pathList)
|
|||||||
_errors.clear();
|
_errors.clear();
|
||||||
_csyncError = false;
|
_csyncError = false;
|
||||||
_csyncUnavail = false;
|
_csyncUnavail = false;
|
||||||
_wipeDb = false;
|
|
||||||
|
|
||||||
MirallConfigFile cfgFile;
|
MirallConfigFile cfgFile;
|
||||||
|
|
||||||
@@ -283,6 +293,8 @@ void ownCloudFolder::startSync(const QStringList &pathList)
|
|||||||
_csync->moveToThread(_thread);
|
_csync->moveToThread(_thread);
|
||||||
|
|
||||||
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
||||||
|
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
||||||
|
|
||||||
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||||
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
||||||
|
|
||||||
@@ -290,6 +302,11 @@ void ownCloudFolder::startSync(const QStringList &pathList)
|
|||||||
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
|
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
|
||||||
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), Qt::QueuedConnection);
|
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), Qt::QueuedConnection);
|
||||||
connect(_csync, SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
|
connect(_csync, SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
//blocking connection so the message box happens in this thread, but block the csync thread.
|
||||||
|
connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
|
||||||
|
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
_thread->start();
|
_thread->start();
|
||||||
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
|
||||||
emit syncStarted();
|
emit syncStarted();
|
||||||
@@ -323,7 +340,6 @@ void ownCloudFolder::slotCSyncFinished()
|
|||||||
qDebug() << " ** error Strings: " << _errors;
|
qDebug() << " ** error Strings: " << _errors;
|
||||||
_syncResult.setErrorStrings( _errors );
|
_syncResult.setErrorStrings( _errors );
|
||||||
qDebug() << " * owncloud csync thread finished with error";
|
qDebug() << " * owncloud csync thread finished with error";
|
||||||
if( _wipeDb ) wipe();
|
|
||||||
} else if (_csyncUnavail) {
|
} else if (_csyncUnavail) {
|
||||||
_syncResult.setStatus(SyncResult::Unavailable);
|
_syncResult.setStatus(SyncResult::Unavailable);
|
||||||
} else {
|
} else {
|
||||||
@@ -417,7 +433,6 @@ void ownCloudFolder::wipe()
|
|||||||
if( ctmpFile.exists() ) {
|
if( ctmpFile.exists() ) {
|
||||||
ctmpFile.remove();
|
ctmpFile.remove();
|
||||||
}
|
}
|
||||||
_wipeDb = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerActionNotifier::ServerActionNotifier(QObject *parent)
|
ServerActionNotifier::ServerActionNotifier(QObject *parent)
|
||||||
@@ -488,5 +503,30 @@ void ServerActionNotifier::slotSyncFinished(const SyncResult &result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ownCloudFolder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
|
||||||
|
{
|
||||||
|
QString msg = direction == SyncFileItem::Down ?
|
||||||
|
tr("This sync would remove all the files in the local sync folder '%1'.\n"
|
||||||
|
"If you or your administrator have reset your account on the server, choose"
|
||||||
|
"\"Keep files\". If you want your data to be removed, choose \"Remove all files\".") :
|
||||||
|
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 file were manually removed.\n"
|
||||||
|
"Are you sure you want to perform this operation?");
|
||||||
|
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
|
||||||
|
msg.arg(alias()));
|
||||||
|
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
|
||||||
|
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::ActionRole);
|
||||||
|
if (msgBox.exec() == -1) {
|
||||||
|
*cancel = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*cancel = msgBox.clickedButton() == keepBtn;
|
||||||
|
if (*cancel) {
|
||||||
|
wipe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // ns
|
} // ns
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void startSync();
|
void startSync();
|
||||||
void slotTerminateSync();
|
void slotTerminateSync();
|
||||||
|
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void slotLocalPathChanged( const QString& );
|
void slotLocalPathChanged( const QString& );
|
||||||
|
|||||||
@@ -483,7 +483,10 @@ bool ownCloudInfo::certsUntrusted()
|
|||||||
|
|
||||||
void ownCloudInfo::slotError( QNetworkReply::NetworkError err)
|
void ownCloudInfo::slotError( QNetworkReply::NetworkError err)
|
||||||
{
|
{
|
||||||
qDebug() << "ownCloudInfo Network Error: " << err;
|
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
|
qDebug() << "ownCloudInfo Network Error"
|
||||||
|
<< err << ":" << reply->errorString();
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case QNetworkReply::ProxyConnectionRefusedError:
|
case QNetworkReply::ProxyConnectionRefusedError:
|
||||||
|
|||||||
@@ -124,34 +124,50 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
|
|||||||
qDebug() << "The User has changed, same as url change.";
|
qDebug() << "The User has changed, same as url change.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the user credentials and afterwards clear the cred store.
|
|
||||||
cfg.acceptCustomConfig();
|
|
||||||
|
|
||||||
// Now write the resulting folder definition if folder names are set.
|
|
||||||
const QString localFolder = _ocWizard->localFolder();
|
const QString localFolder = _ocWizard->localFolder();
|
||||||
if( !( localFolder.isEmpty() || _remoteFolder.isEmpty() ) ) { // both variables are set.
|
bool acceptCfg = true;
|
||||||
if( urlHasChanged ) {
|
|
||||||
_folderMan->removeAllFolderDefinitions();
|
|
||||||
_folderMan->addFolderDefinition( QLatin1String("owncloud"), Theme::instance()->appName(),
|
|
||||||
localFolder, _remoteFolder, false );
|
|
||||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
|
||||||
|
|
||||||
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
|
if( urlHasChanged ) {
|
||||||
if( startFromScratch ) {
|
_folderMan->unloadAllFolders();
|
||||||
// clean the entire directory.
|
|
||||||
if( _folderMan->startFromScratch( localFolder ) ) {
|
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
|
||||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully prepared syncing from scratch!</font>"));
|
if( startFromScratch ) {
|
||||||
} else {
|
// first try to rename (backup) the current local dir.
|
||||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"red\">Failed to prepare syncing from scratch!</font>"));
|
bool renameOk = false;
|
||||||
|
while( !renameOk ) {
|
||||||
|
renameOk = _folderMan->startFromScratch(localFolder);
|
||||||
|
if( ! renameOk ) {
|
||||||
|
QMessageBox::StandardButton but;
|
||||||
|
but = QMessageBox::question( 0, tr("Folder rename failed"),
|
||||||
|
tr("Can't remove and back up the folder because the folder or a file in it is open in another program."
|
||||||
|
"Please close the folder or file and hit retry or cancel the setup."), QMessageBox::Retry | QMessageBox::Abort, QMessageBox::Retry);
|
||||||
|
if( but == QMessageBox::Abort ) {
|
||||||
|
renameOk = true;
|
||||||
|
acceptCfg = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// url is unchanged. Only the password was changed.
|
|
||||||
qDebug() << "Only password was changed, no changes to folder configuration.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
// save the user credentials and afterwards clear the cred store.
|
||||||
qDebug() << "WRN: Got unknown dialog result code " << result;
|
if( acceptCfg ) {
|
||||||
|
cfg.acceptCustomConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now write the resulting folder definition if folder names are set.
|
||||||
|
if( acceptCfg && urlHasChanged ) {
|
||||||
|
_folderMan->removeAllFolderDefinitions();
|
||||||
|
_folderMan->addFolderDefinition( QLatin1String("owncloud"), Theme::instance()->appName(),
|
||||||
|
localFolder, _remoteFolder, false );
|
||||||
|
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
|
||||||
|
} else {
|
||||||
|
// url is unchanged. Only the password was changed.
|
||||||
|
if( acceptCfg ) {
|
||||||
|
qDebug() << "Only password was changed, no changes to folder configuration.";
|
||||||
|
} else {
|
||||||
|
qDebug() << "User interrupted change of configuration.";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the custom config handle
|
// clear the custom config handle
|
||||||
@@ -219,10 +235,8 @@ void OwncloudSetupWizard::testOwnCloudConnect()
|
|||||||
// If there is already a config, take its proxy config.
|
// If there is already a config, take its proxy config.
|
||||||
if( ownCloudInfo::instance()->isConfigured() ) {
|
if( ownCloudInfo::instance()->isConfigured() ) {
|
||||||
MirallConfigFile prevCfg;
|
MirallConfigFile prevCfg;
|
||||||
if( prevCfg.proxyType() != QNetworkProxy::DefaultProxy ) {
|
cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(),
|
||||||
cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(),
|
prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() );
|
||||||
prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// now start ownCloudInfo to check the connection.
|
// now start ownCloudInfo to check the connection.
|
||||||
|
|||||||
@@ -15,12 +15,14 @@
|
|||||||
#include "owncloudtheme.h"
|
#include "owncloudtheme.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDebug>
|
#include <QVariant>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include "mirall/version.h"
|
#include "mirall/version.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -78,32 +80,6 @@ QString ownCloudTheme::about() const
|
|||||||
.arg(devString);
|
.arg(devString);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap ownCloudTheme::splashScreen() const
|
|
||||||
{
|
|
||||||
return QPixmap(QLatin1String(":/mirall/resources/owncloud_splash.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon ownCloudTheme::folderIcon( const QString& backend ) const
|
|
||||||
{
|
|
||||||
QString name;
|
|
||||||
|
|
||||||
if( backend == QLatin1String("owncloud")) {
|
|
||||||
name = QLatin1String( "owncloud-framed" );
|
|
||||||
}
|
|
||||||
if( backend == QLatin1String("unison" )) {
|
|
||||||
name = QLatin1String( "folder-sync" );
|
|
||||||
}
|
|
||||||
if( backend == QLatin1String("csync" )) {
|
|
||||||
name = QLatin1String( "folder-remote" );
|
|
||||||
}
|
|
||||||
if( backend.isEmpty() || backend == QLatin1String("none") ) {
|
|
||||||
name = QLatin1String("folder-grey");
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "==> load folder icon " << name;
|
|
||||||
return themeIcon( name );
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon ownCloudTheme::trayFolderIcon( const QString& ) const
|
QIcon ownCloudTheme::trayFolderIcon( const QString& ) const
|
||||||
{
|
{
|
||||||
QPixmap fallback = qApp->style()->standardPixmap(QStyle::SP_FileDialogNewFolder);
|
QPixmap fallback = qApp->style()->standardPixmap(QStyle::SP_FileDialogNewFolder);
|
||||||
@@ -121,6 +97,18 @@ QIcon ownCloudTheme::applicationIcon( ) const
|
|||||||
return themeIcon( QLatin1String("owncloud-icon") );
|
return themeIcon( QLatin1String("owncloud-icon") );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant ownCloudTheme::customMedia(Theme::CustomMediaType type)
|
||||||
|
{
|
||||||
|
if (type == Theme::oCSetupTop) {
|
||||||
|
return QCoreApplication::translate("ownCloudTheme",
|
||||||
|
"If you don't have an ownCloud server yet, "
|
||||||
|
"see <a href=\"https://owncloud.com\">owncloud.com</a> for more info.",
|
||||||
|
"Top text in setup wizard. Keep short!");
|
||||||
|
} else {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QColor ownCloudTheme::wizardHeaderBackgroundColor() const
|
QColor ownCloudTheme::wizardHeaderBackgroundColor() const
|
||||||
{
|
{
|
||||||
return QColor("#1d2d42");
|
return QColor("#1d2d42");
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ public:
|
|||||||
QIcon folderDisabledIcon() const;
|
QIcon folderDisabledIcon() const;
|
||||||
QIcon applicationIcon() const;
|
QIcon applicationIcon() const;
|
||||||
|
|
||||||
|
QVariant customMedia(CustomMediaType type);
|
||||||
|
|
||||||
QColor wizardHeaderBackgroundColor() const;
|
QColor wizardHeaderBackgroundColor() const;
|
||||||
QColor wizardHeaderTitleColor() const;
|
QColor wizardHeaderTitleColor() const;
|
||||||
|
|
||||||
|
|||||||
@@ -130,16 +130,12 @@ void OwncloudSetupPage::setServerUrl( const QString& newUrl )
|
|||||||
void OwncloudSetupPage::setupCustomization()
|
void OwncloudSetupPage::setupCustomization()
|
||||||
{
|
{
|
||||||
// set defaults for the customize labels.
|
// set defaults for the customize labels.
|
||||||
|
_ui.topLabel->hide();
|
||||||
// _ui.topLabel->hide();
|
|
||||||
_ui.bottomLabel->hide();
|
_ui.bottomLabel->hide();
|
||||||
|
|
||||||
Theme *theme = Theme::instance();
|
Theme *theme = Theme::instance();
|
||||||
QVariant variant = theme->customMedia( Theme::oCSetupTop );
|
QVariant variant = theme->customMedia( Theme::oCSetupTop );
|
||||||
if( variant.isNull() ) {
|
if( !variant.isNull() ) {
|
||||||
_ui.topLabel->setOpenExternalLinks(true);
|
|
||||||
_ui.topLabel->setText("If you don't have an ownCloud server yet, see <a href=\"https://owncloud.com\">owncloud.com</a> for more info.");
|
|
||||||
} else {
|
|
||||||
setupCustomMedia( variant, _ui.topLabel );
|
setupCustomMedia( variant, _ui.topLabel );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,6 +192,9 @@ void OwncloudSetupPage::initializePage()
|
|||||||
_checking = false;
|
_checking = false;
|
||||||
_multipleFoldersExist = false;
|
_multipleFoldersExist = false;
|
||||||
|
|
||||||
|
// call to init label
|
||||||
|
slotHandleUserInput();
|
||||||
|
|
||||||
if( _configExists ) {
|
if( _configExists ) {
|
||||||
_ui.lePassword->setFocus();
|
_ui.lePassword->setFocus();
|
||||||
} else {
|
} else {
|
||||||
@@ -260,7 +259,7 @@ void OwncloudSetupPage::slotHandleUserInput()
|
|||||||
t = tr("Change the Password for your configured account.");
|
t = tr("Change the Password for your configured account.");
|
||||||
} else {
|
} else {
|
||||||
// Complete new setup.
|
// Complete new setup.
|
||||||
_ui.pbSelectLocalFolder->setText(locFolder);
|
_ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(locFolder));
|
||||||
|
|
||||||
if( _remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/") ) {
|
if( _remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/") ) {
|
||||||
t = tr("Your entire account will be synced to the local folder '%1'.")
|
t = tr("Your entire account will be synced to the local folder '%1'.")
|
||||||
@@ -404,8 +403,11 @@ void OwncloudWizard::setMultipleFoldersExist(bool exist)
|
|||||||
void OwncloudSetupPage::setConfigExists( bool config )
|
void OwncloudSetupPage::setConfigExists( bool config )
|
||||||
{
|
{
|
||||||
_configExists = config;
|
_configExists = config;
|
||||||
setSubTitle( tr("<font color=\"%1\">Change your user credentials</font>")
|
|
||||||
.arg(Theme::instance()->wizardHeaderTitleColor().name()));
|
if (config == true) {
|
||||||
|
setSubTitle( tr("<font color=\"%1\">Change your user credentials</font>")
|
||||||
|
.arg(Theme::instance()->wizardHeaderTitleColor().name()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================================
|
// ======================================================================
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ Mirall::ProxyDialog::ProxyDialog( QWidget* parent )
|
|||||||
}
|
}
|
||||||
|
|
||||||
hostLineEdit->setText(cfgFile.proxyHostName());
|
hostLineEdit->setText(cfgFile.proxyHostName());
|
||||||
portSpinBox->setValue(cfgFile.proxyPort());
|
int port = cfgFile.proxyPort();
|
||||||
|
if (port == 0) port = 8080;
|
||||||
|
portSpinBox->setValue(port);
|
||||||
if (!cfgFile.proxyUser().isEmpty())
|
if (!cfgFile.proxyUser().isEmpty())
|
||||||
{
|
{
|
||||||
authRequiredcheckBox->setChecked(true);
|
authRequiredcheckBox->setChecked(true);
|
||||||
|
|||||||
@@ -64,40 +64,33 @@ FolderViewDelegate::~FolderViewDelegate()
|
|||||||
QSize FolderViewDelegate::sizeHint(const QStyleOptionViewItem & option ,
|
QSize FolderViewDelegate::sizeHint(const QStyleOptionViewItem & option ,
|
||||||
const QModelIndex & index) const
|
const QModelIndex & index) const
|
||||||
{
|
{
|
||||||
int w = 0;
|
Q_UNUSED(option)
|
||||||
|
QFont aliasFont = option.font;
|
||||||
QString p = qvariant_cast<QString>(index.data(FolderPathRole));
|
QFont font = option.font;
|
||||||
QFont aliasFont = QApplication::font();
|
|
||||||
QFont font = QApplication::font();
|
|
||||||
aliasFont.setPointSize( font.pointSize() +2 );
|
aliasFont.setPointSize( font.pointSize() +2 );
|
||||||
|
|
||||||
QFontMetrics fm(font);
|
QFontMetrics fm(font);
|
||||||
QFontMetrics aliasFm(aliasFont);
|
QFontMetrics aliasFm(aliasFont);
|
||||||
|
|
||||||
int margin = aliasFm.height()/2;
|
int aliasMargin = aliasFm.height()/2;
|
||||||
|
int margin = fm.height()/4;
|
||||||
w = 8 + fm.boundingRect( p ).width();
|
|
||||||
|
|
||||||
// calc height
|
// calc height
|
||||||
|
|
||||||
int h = margin; // margin to top
|
int h = aliasMargin; // margin to top
|
||||||
h += aliasFm.height(); // alias
|
h += aliasFm.height(); // alias
|
||||||
h += fm.height()/2; // between alias and local path
|
h += margin; // between alias and local path
|
||||||
h += fm.height(); // local path
|
h += fm.height(); // local path
|
||||||
h += fm.height()/2; // between local and remote path
|
h += margin; // between local and remote path
|
||||||
h += fm.height(); // remote path
|
h += fm.height(); // remote path
|
||||||
h += margin; // bottom margin
|
h += aliasMargin; // bottom margin
|
||||||
|
|
||||||
int minHeight = 48 + margin + margin; // icon + margins
|
|
||||||
|
|
||||||
if( h < minHeight ) h = minHeight;
|
|
||||||
|
|
||||||
// add some space to show an error condition.
|
// add some space to show an error condition.
|
||||||
if( ! qvariant_cast<QString>(index.data(FolderErrorMsg)).isEmpty() ) {
|
if( ! qvariant_cast<QString>(index.data(FolderErrorMsg)).isEmpty() ) {
|
||||||
h += margin+fm.height();
|
h += aliasMargin*2+fm.height();
|
||||||
}
|
}
|
||||||
|
|
||||||
return QSize( w, h );
|
return QSize( 0, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
@@ -107,8 +100,8 @@ void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
|||||||
|
|
||||||
painter->save();
|
painter->save();
|
||||||
|
|
||||||
QFont aliasFont = QApplication::font();
|
QFont aliasFont = option.font;
|
||||||
QFont subFont = QApplication::font();
|
QFont subFont = option.font;
|
||||||
QFont errorFont = subFont;
|
QFont errorFont = subFont;
|
||||||
|
|
||||||
//font.setPixelSize(font.weight()+);
|
//font.setPixelSize(font.weight()+);
|
||||||
@@ -117,10 +110,11 @@ void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
|||||||
|
|
||||||
QFontMetrics subFm( subFont );
|
QFontMetrics subFm( subFont );
|
||||||
QFontMetrics aliasFm( aliasFont );
|
QFontMetrics aliasFm( aliasFont );
|
||||||
int margin = aliasFm.height()/2;
|
|
||||||
|
|
||||||
QIcon folderIcon = qvariant_cast<QIcon>(index.data(FolderIconRole));
|
int aliasMargin = aliasFm.height()/2;
|
||||||
QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIcon));
|
int margin = subFm.height()/4;
|
||||||
|
|
||||||
|
QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIconRole));
|
||||||
QString aliasText = qvariant_cast<QString>(index.data(FolderAliasRole));
|
QString aliasText = qvariant_cast<QString>(index.data(FolderAliasRole));
|
||||||
QString pathText = qvariant_cast<QString>(index.data(FolderPathRole));
|
QString pathText = qvariant_cast<QString>(index.data(FolderPathRole));
|
||||||
QString remotePath = qvariant_cast<QString>(index.data(FolderSecondPathRole));
|
QString remotePath = qvariant_cast<QString>(index.data(FolderSecondPathRole));
|
||||||
@@ -130,72 +124,80 @@ void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
|||||||
bool syncEnabled = index.data(FolderSyncEnabled).toBool();
|
bool syncEnabled = index.data(FolderSyncEnabled).toBool();
|
||||||
// QString syncStatus = syncEnabled? tr( "Enabled" ) : tr( "Disabled" );
|
// QString syncStatus = syncEnabled? tr( "Enabled" ) : tr( "Disabled" );
|
||||||
|
|
||||||
QSize iconsize(48, 48); // = icon.actualSize(option.decorationSize);
|
|
||||||
|
|
||||||
QRect aliasRect = option.rect;
|
|
||||||
QRect iconRect = option.rect;
|
QRect iconRect = option.rect;
|
||||||
|
QRect aliasRect = option.rect;
|
||||||
|
|
||||||
iconRect.setLeft( margin );
|
iconRect.setLeft( aliasMargin );
|
||||||
iconRect.setWidth( 48 );
|
iconRect.setTop( iconRect.top() + aliasMargin ); // (iconRect.height()-iconsize.height())/2);
|
||||||
iconRect.setTop( iconRect.top() + margin ); // (iconRect.height()-iconsize.height())/2);
|
|
||||||
|
|
||||||
QRect statusRect = iconRect;
|
// local directory box
|
||||||
statusRect.setLeft( option.rect.right() - margin - 48 );
|
aliasRect.setTop(aliasRect.top() + aliasMargin );
|
||||||
statusRect.setRight( option.rect.right() - margin );
|
aliasRect.setBottom(aliasRect.top() + aliasFm.height());
|
||||||
|
aliasRect.setRight(aliasRect.right() - aliasMargin );
|
||||||
aliasRect.setLeft(iconRect.right()+margin);
|
|
||||||
|
|
||||||
aliasRect.setTop(aliasRect.top() + aliasFm.height()/2 );
|
|
||||||
aliasRect.setBottom(aliasRect.top()+aliasFm.height());
|
|
||||||
|
|
||||||
// local directory box
|
// local directory box
|
||||||
QRect localPathRect = aliasRect;
|
QRect localPathRect = aliasRect;
|
||||||
localPathRect.setTop(aliasRect.bottom() + margin / 3);
|
localPathRect.setTop(aliasRect.bottom() + margin );
|
||||||
localPathRect.setBottom(localPathRect.top()+subFm.height());
|
localPathRect.setBottom(localPathRect.top() + subFm.height());
|
||||||
|
|
||||||
// remote directory box
|
// remote directory box
|
||||||
QRect remotePathRect = localPathRect;
|
QRect remotePathRect = localPathRect;
|
||||||
remotePathRect.setTop( localPathRect.bottom() + subFm.height()/2 );
|
remotePathRect.setTop( localPathRect.bottom() + margin );
|
||||||
remotePathRect.setBottom( remotePathRect.top() + subFm.height());
|
remotePathRect.setBottom( remotePathRect.top() + subFm.height());
|
||||||
|
|
||||||
iconRect.setBottom(remotePathRect.bottom());
|
iconRect.setBottom(remotePathRect.bottom());
|
||||||
|
iconRect.setWidth(iconRect.height());
|
||||||
|
|
||||||
//painter->drawPixmap(QPoint(iconRect.right()/2,iconRect.top()/2),icon.pixmap(iconsize.width(),iconsize.height()));
|
int nextToIcon = iconRect.right()+aliasMargin;
|
||||||
if( syncEnabled ) {
|
aliasRect.setLeft(nextToIcon);
|
||||||
painter->drawPixmap(QPoint(iconRect.left(),iconRect.top()), folderIcon.pixmap(iconsize.width(),iconsize.height()));
|
localPathRect.setLeft(nextToIcon);
|
||||||
|
remotePathRect.setLeft(nextToIcon);
|
||||||
|
|
||||||
|
int iconSize = iconRect.width();
|
||||||
|
|
||||||
|
QPixmap pm = statusIcon.pixmap(iconSize, iconSize, syncEnabled ? QIcon::Normal : QIcon::Disabled );
|
||||||
|
painter->drawPixmap(QPoint(iconRect.left(), iconRect.top()), pm);
|
||||||
|
|
||||||
|
if ((option.state & QStyle::State_Selected)
|
||||||
|
&& (option.state & QStyle::State_Active)
|
||||||
|
// Hack: Windows Vista's light blue is not contrasting enough for white
|
||||||
|
&& !Application::style()->inherits("QWindowsVistaStyle")) {
|
||||||
|
painter->setPen(option.palette.color(QPalette::HighlightedText));
|
||||||
} else {
|
} else {
|
||||||
painter->drawPixmap(QPoint(iconRect.left(),iconRect.top()), folderIcon.pixmap(iconsize.width(),iconsize.height(), QIcon::Disabled ));
|
painter->setPen(option.palette.color(QPalette::Text));
|
||||||
}
|
}
|
||||||
|
QString elidedAlias = aliasFm.elidedText(aliasText, Qt::ElideRight, aliasRect.width());
|
||||||
painter->drawPixmap(QPoint(statusRect.left(), statusRect.top()), statusIcon.pixmap(48,48));
|
|
||||||
|
|
||||||
painter->setFont(aliasFont);
|
painter->setFont(aliasFont);
|
||||||
painter->drawText(aliasRect, aliasText);
|
painter->drawText(aliasRect, elidedAlias);
|
||||||
|
|
||||||
painter->setFont(subFont);
|
painter->setFont(subFont);
|
||||||
painter->drawText(localPathRect.left(),localPathRect.top()+17, pathText);
|
QString elidedPathText = subFm.elidedText(pathText, Qt::ElideMiddle, localPathRect.width());
|
||||||
painter->drawText(remotePathRect, tr("Remote path: %1").arg(remotePath));
|
painter->drawText(localPathRect, elidedPathText);
|
||||||
|
QString elidedRemotePathText = subFm.elidedText(tr("Remote path: %1").arg(remotePath),
|
||||||
|
Qt::ElideMiddle, remotePathRect.width());
|
||||||
|
painter->drawText(remotePathRect, elidedRemotePathText);
|
||||||
|
|
||||||
// paint an error overlay if there is an error string
|
// paint an error overlay if there is an error string
|
||||||
if( !errorText.isEmpty() ) {
|
if( !errorText.isEmpty() ) {
|
||||||
QRect errorRect = localPathRect;
|
QRect errorRect = localPathRect;
|
||||||
errorRect.setLeft( iconRect.left());
|
errorRect.setLeft( iconRect.left());
|
||||||
errorRect.setTop( iconRect.bottom()+subFm.height()/2 );
|
errorRect.setTop( iconRect.bottom()+subFm.height()/2 );
|
||||||
errorRect.setHeight(subFm.height()+margin);
|
errorRect.setHeight(subFm.height()+aliasMargin);
|
||||||
errorRect.setRight( statusRect.right() );
|
errorRect.setRight( option.rect.right()-aliasMargin );
|
||||||
|
|
||||||
painter->setBrush( QColor(0xbb, 0x4d, 0x4d) );
|
painter->setBrush( QColor(0xbb, 0x4d, 0x4d) );
|
||||||
painter->setPen( QColor(0xaa, 0xaa, 0xaa));
|
painter->setPen( QColor(0xaa, 0xaa, 0xaa));
|
||||||
painter->drawRoundedRect( errorRect, 4, 4 );
|
painter->drawRoundedRect( errorRect, 4, 4 );
|
||||||
|
|
||||||
QIcon warnIcon(":/mirall/resources/warning-16");
|
QIcon warnIcon(":/mirall/resources/warning-16");
|
||||||
painter->drawPixmap( QPoint(errorRect.left()+2, errorRect.top()+2), warnIcon.pixmap(QSize(16,16)));
|
QPoint warnPos(errorRect.left()+aliasMargin/2, errorRect.top()+aliasMargin/2);
|
||||||
|
painter->drawPixmap( warnPos, warnIcon.pixmap(QSize(16,16)));
|
||||||
|
|
||||||
painter->setPen( Qt::white );
|
painter->setPen( Qt::white );
|
||||||
painter->setFont(errorFont);
|
painter->setFont(errorFont);
|
||||||
QRect errorTextRect = errorRect;
|
QRect errorTextRect = errorRect;
|
||||||
errorTextRect.setLeft( errorTextRect.left()+margin/2 +16);
|
errorTextRect.setLeft( errorTextRect.left()+aliasMargin +16);
|
||||||
errorTextRect.setTop( errorTextRect.top()+margin/2 );
|
errorTextRect.setTop( errorTextRect.top()+aliasMargin/2 );
|
||||||
|
|
||||||
int linebreak = errorText.indexOf(QLatin1String("<br"));
|
int linebreak = errorText.indexOf(QLatin1String("<br"));
|
||||||
QString eText = errorText;
|
QString eText = errorText;
|
||||||
@@ -236,17 +238,11 @@ StatusDialog::StatusDialog( Theme *theme, QWidget *parent) :
|
|||||||
connect(_ButtonClose, SIGNAL(clicked()), this, SLOT(accept()));
|
connect(_ButtonClose, SIGNAL(clicked()), this, SLOT(accept()));
|
||||||
connect(_ButtonRemove, SIGNAL(clicked()), this, SLOT(slotRemoveFolder()));
|
connect(_ButtonRemove, SIGNAL(clicked()), this, SLOT(slotRemoveFolder()));
|
||||||
|
|
||||||
// hide these two for now...
|
|
||||||
_ButtonFetch->setVisible( false );
|
|
||||||
_ButtonPush->setVisible( false );
|
|
||||||
|
|
||||||
connect(_ButtonEnable, SIGNAL(clicked()), this, SLOT(slotEnableFolder()));
|
connect(_ButtonEnable, SIGNAL(clicked()), this, SLOT(slotEnableFolder()));
|
||||||
connect(_ButtonInfo, SIGNAL(clicked()), this, SLOT(slotInfoFolder()));
|
connect(_ButtonInfo, SIGNAL(clicked()), this, SLOT(slotInfoFolder()));
|
||||||
connect(_ButtonAdd, SIGNAL(clicked()), this, SLOT(slotAddSync()));
|
connect(_ButtonAdd, SIGNAL(clicked()), this, SLOT(slotAddSync()));
|
||||||
|
|
||||||
_ButtonRemove->setEnabled(false);
|
_ButtonRemove->setEnabled(false);
|
||||||
_ButtonFetch->setEnabled(false);
|
|
||||||
_ButtonPush->setEnabled(false);
|
|
||||||
_ButtonEnable->setEnabled(false);
|
_ButtonEnable->setEnabled(false);
|
||||||
_ButtonInfo->setEnabled(false);
|
_ButtonInfo->setEnabled(false);
|
||||||
_ButtonAdd->setEnabled(true);
|
_ButtonAdd->setEnabled(true);
|
||||||
@@ -268,8 +264,6 @@ void StatusDialog::slotFolderActivated( const QModelIndex& indx )
|
|||||||
bool state = indx.isValid();
|
bool state = indx.isValid();
|
||||||
|
|
||||||
_ButtonRemove->setEnabled( state );
|
_ButtonRemove->setEnabled( state );
|
||||||
_ButtonFetch->setEnabled( state );
|
|
||||||
_ButtonPush->setEnabled( state );
|
|
||||||
_ButtonEnable->setEnabled( state );
|
_ButtonEnable->setEnabled( state );
|
||||||
_ButtonInfo->setEnabled( state );
|
_ButtonInfo->setEnabled( state );
|
||||||
|
|
||||||
@@ -336,9 +330,7 @@ void StatusDialog::buttonsSetEnabled()
|
|||||||
|
|
||||||
_ButtonEnable->setEnabled(isSelected);
|
_ButtonEnable->setEnabled(isSelected);
|
||||||
_ButtonRemove->setEnabled(isSelected);
|
_ButtonRemove->setEnabled(isSelected);
|
||||||
_ButtonFetch->setEnabled(isSelected);
|
|
||||||
_ButtonInfo->setEnabled(isSelected);
|
_ButtonInfo->setEnabled(isSelected);
|
||||||
_ButtonPush->setEnabled(isSelected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatusDialog::slotUpdateFolderState( Folder *folder )
|
void StatusDialog::slotUpdateFolderState( Folder *folder )
|
||||||
@@ -369,8 +361,6 @@ void StatusDialog::folderToModelItem( QStandardItem *item, Folder *f )
|
|||||||
{
|
{
|
||||||
if( ! item || !f ) return;
|
if( ! item || !f ) return;
|
||||||
|
|
||||||
QIcon icon = _theme->folderIcon( f->backend() );
|
|
||||||
item->setData( icon, FolderViewDelegate::FolderIconRole );
|
|
||||||
item->setData( f->nativePath(), FolderViewDelegate::FolderPathRole );
|
item->setData( f->nativePath(), FolderViewDelegate::FolderPathRole );
|
||||||
item->setData( f->secondPath(), FolderViewDelegate::FolderSecondPathRole );
|
item->setData( f->secondPath(), FolderViewDelegate::FolderSecondPathRole );
|
||||||
item->setData( f->alias(), FolderViewDelegate::FolderAliasRole );
|
item->setData( f->alias(), FolderViewDelegate::FolderAliasRole );
|
||||||
@@ -383,9 +373,9 @@ void StatusDialog::folderToModelItem( QStandardItem *item, Folder *f )
|
|||||||
|
|
||||||
item->setData( _theme->statusHeaderText( status ), Qt::ToolTipRole );
|
item->setData( _theme->statusHeaderText( status ), Qt::ToolTipRole );
|
||||||
if( f->syncEnabled() ) {
|
if( f->syncEnabled() ) {
|
||||||
item->setData( _theme->syncStateIcon( status ), FolderViewDelegate::FolderStatusIcon );
|
item->setData( _theme->syncStateIcon( status ), FolderViewDelegate::FolderStatusIconRole );
|
||||||
} else {
|
} else {
|
||||||
item->setData( _theme->folderDisabledIcon( ), FolderViewDelegate::FolderStatusIcon ); // size 48 before
|
item->setData( _theme->folderDisabledIcon( ), FolderViewDelegate::FolderStatusIconRole ); // size 48 before
|
||||||
}
|
}
|
||||||
item->setData( _theme->statusHeaderText( status ), FolderViewDelegate::FolderStatus );
|
item->setData( _theme->statusHeaderText( status ), FolderViewDelegate::FolderStatus );
|
||||||
item->setData( errors, FolderViewDelegate::FolderErrorMsg );
|
item->setData( errors, FolderViewDelegate::FolderErrorMsg );
|
||||||
@@ -416,30 +406,6 @@ void StatusDialog::slotRemoveSelectedFolder()
|
|||||||
slotCheckConnection();
|
slotCheckConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatusDialog::slotFetchFolder()
|
|
||||||
{
|
|
||||||
QModelIndex selected = _folderList->selectionModel()->currentIndex();
|
|
||||||
if( selected.isValid() ) {
|
|
||||||
QString alias = _model->data( selected, FolderViewDelegate::FolderAliasRole ).toString();
|
|
||||||
qDebug() << "Fetch Folder alias " << alias;
|
|
||||||
if( !alias.isEmpty() ) {
|
|
||||||
emit(fetchFolderAlias( alias ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusDialog::slotPushFolder()
|
|
||||||
{
|
|
||||||
QModelIndex selected = _folderList->selectionModel()->currentIndex();
|
|
||||||
if( selected.isValid() ) {
|
|
||||||
QString alias = _model->data( selected, FolderViewDelegate::FolderAliasRole ).toString();
|
|
||||||
qDebug() << "Push Folder alias " << alias;
|
|
||||||
if( !alias.isEmpty() ) {
|
|
||||||
emit(pushFolderAlias( alias ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StatusDialog::slotEnableFolder()
|
void StatusDialog::slotEnableFolder()
|
||||||
{
|
{
|
||||||
QModelIndex selected = _folderList->selectionModel()->currentIndex();
|
QModelIndex selected = _folderList->selectionModel()->currentIndex();
|
||||||
|
|||||||
@@ -45,15 +45,14 @@ class FolderViewDelegate : public QStyledItemDelegate
|
|||||||
FolderViewDelegate();
|
FolderViewDelegate();
|
||||||
virtual ~FolderViewDelegate();
|
virtual ~FolderViewDelegate();
|
||||||
|
|
||||||
enum datarole { FolderAliasRole = Qt::UserRole + 100,
|
enum datarole { FolderAliasRole = Qt::UserRole + 100,
|
||||||
FolderPathRole = Qt::UserRole + 101,
|
FolderPathRole,
|
||||||
FolderSecondPathRole = Qt::UserRole + 102,
|
FolderSecondPathRole,
|
||||||
FolderIconRole = Qt::UserRole + 103,
|
FolderRemotePath,
|
||||||
FolderRemotePath = Qt::UserRole + 104,
|
FolderStatus,
|
||||||
FolderStatus = Qt::UserRole + 105,
|
FolderErrorMsg,
|
||||||
FolderErrorMsg = Qt::UserRole + 106,
|
FolderSyncEnabled,
|
||||||
FolderStatusIcon = Qt::UserRole + 107,
|
FolderStatusIconRole
|
||||||
FolderSyncEnabled = Qt::UserRole + 108
|
|
||||||
};
|
};
|
||||||
void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
|
void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
|
||||||
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
|
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
|
||||||
@@ -73,8 +72,6 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void removeFolderAlias( const QString& );
|
void removeFolderAlias( const QString& );
|
||||||
void fetchFolderAlias( const QString& );
|
|
||||||
void pushFolderAlias( const QString& );
|
|
||||||
void enableFolderAlias( const QString&, const bool );
|
void enableFolderAlias( const QString&, const bool );
|
||||||
void infoFolderAlias( const QString& );
|
void infoFolderAlias( const QString& );
|
||||||
void openFolderAlias( const QString& );
|
void openFolderAlias( const QString& );
|
||||||
@@ -85,8 +82,6 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
void slotRemoveFolder();
|
void slotRemoveFolder();
|
||||||
void slotRemoveSelectedFolder();
|
void slotRemoveSelectedFolder();
|
||||||
void slotFetchFolder();
|
|
||||||
void slotPushFolder();
|
|
||||||
void slotFolderActivated( const QModelIndex& );
|
void slotFolderActivated( const QModelIndex& );
|
||||||
void slotOpenOC();
|
void slotOpenOC();
|
||||||
void slotEnableFolder();
|
void slotEnableFolder();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>544</width>
|
<width>544</width>
|
||||||
<height>308</height>
|
<height>313</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -49,23 +49,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="_ButtonFetch">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Fetch...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="_ButtonPush">
|
|
||||||
<property name="text">
|
|
||||||
<string>Push...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="_ButtonEnable">
|
<widget class="QPushButton" name="_ButtonEnable">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ QString Theme::version() const
|
|||||||
|
|
||||||
QIcon Theme::trayFolderIcon( const QString& backend ) const
|
QIcon Theme::trayFolderIcon( const QString& backend ) const
|
||||||
{
|
{
|
||||||
return folderIcon( backend );
|
Q_UNUSED(backend)
|
||||||
|
return applicationIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual QString configFileName() const = 0;
|
virtual QString configFileName() const = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* get a folder icon for a given backend in a given size.
|
|
||||||
*/
|
|
||||||
virtual QIcon folderIcon( const QString& ) const = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the icon that is shown in the tray context menu left of the folder name
|
* the icon that is shown in the tray context menu left of the folder name
|
||||||
*/
|
*/
|
||||||
@@ -86,7 +81,6 @@ public:
|
|||||||
virtual QIcon syncStateIcon( SyncResult::Status, bool sysTray = false ) const;
|
virtual QIcon syncStateIcon( SyncResult::Status, bool sysTray = false ) const;
|
||||||
|
|
||||||
virtual QIcon folderDisabledIcon() const = 0;
|
virtual QIcon folderDisabledIcon() const = 0;
|
||||||
virtual QPixmap splashScreen() const = 0;
|
|
||||||
|
|
||||||
virtual QIcon applicationIcon() const = 0;
|
virtual QIcon applicationIcon() const = 0;
|
||||||
|
|
||||||
|
|||||||
48
test/scripts/README.rst
Normal file
48
test/scripts/README.rst
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
Torture for Mirall
|
||||||
|
==================
|
||||||
|
|
||||||
|
This is a set of scripts comprising of two parts:
|
||||||
|
|
||||||
|
* ``torture_gen_layout.pl``: Generation of layout files (random)
|
||||||
|
* ``torture_create_files.pl``: Generation of a real file tree based on the
|
||||||
|
layout files (deterministic)
|
||||||
|
|
||||||
|
These scripts allow to produce a data set with the following criteria:
|
||||||
|
|
||||||
|
* realistic in naming
|
||||||
|
* realistic in file size
|
||||||
|
* realistic in structural size
|
||||||
|
|
||||||
|
without checking in the actual data. Instead, a layout file that gets generated
|
||||||
|
once (reference.lay) is checked in. This makes it possible to produce
|
||||||
|
standardized benchmarks for mirall. It allows allows to check for files gone
|
||||||
|
missing in action and other kinds of corruption produced during sync run.
|
||||||
|
|
||||||
|
``torture_create_files.pl`` can be fine tuned via variables in the script
|
||||||
|
header. It sources its file names from ``dict`` wordlist, file extensions and
|
||||||
|
other parameters can be added as needed. The defaults should be reasonable
|
||||||
|
in terms of size.
|
||||||
|
|
||||||
|
The ``references/`` directory contains default folder layouts.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
In order to create a reference layout and create a tree from it::
|
||||||
|
|
||||||
|
./torture_gen_layout.pl > reference.lay
|
||||||
|
./torture_create_files.pl reference.lay <targetdir>
|
||||||
|
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
|
||||||
|
* Based on the layout file, write a validator that checks files for existence
|
||||||
|
and size without requiring a full reference tree to be created via
|
||||||
|
``./torture_gen_layout.pl``.
|
||||||
|
|
||||||
|
* The current file naming is fairly tame (i.e. almost within ASCII range).
|
||||||
|
Extending it randomly is dangerous, we first need to filter all
|
||||||
|
characters forbidden by various OSes. Or maybe not, because we want to
|
||||||
|
see what happens? :-). Anyway, you have been warned.
|
||||||
|
|
||||||
|
|
||||||
6698
test/scripts/references/default.lay
Normal file
6698
test/scripts/references/default.lay
Normal file
File diff suppressed because it is too large
Load Diff
23
test/scripts/torture_create_files.pl
Executable file
23
test/scripts/torture_create_files.pl
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
use strict;
|
||||||
|
use File::Path qw(make_path);
|
||||||
|
use File::Basename qw(dirname);
|
||||||
|
|
||||||
|
if (scalar @ARGV < 2) {
|
||||||
|
print "Usage: $0 input.lay <offsetdir>\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
my ($file, $offset_dir) = @ARGV;
|
||||||
|
|
||||||
|
open FILE, "<", $file or die $!;
|
||||||
|
while (<FILE>) {
|
||||||
|
my ($fillfile, $size) = split(/:/, $_);
|
||||||
|
$fillfile = $offset_dir . '/' . $fillfile;
|
||||||
|
my $dir = dirname $fillfile;
|
||||||
|
if (!-d $dir) { make_path $dir; }
|
||||||
|
open FILLFILE, ">", $fillfile;
|
||||||
|
print "writing $fillfile with $size bytes\n...";
|
||||||
|
print FILLFILE 0x01 x $size;
|
||||||
|
close FILLFILE;
|
||||||
|
}
|
||||||
71
test/scripts/torture_gen_layout.pl
Executable file
71
test/scripts/torture_gen_layout.pl
Executable file
@@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
use strict;
|
||||||
|
use Data::Random::WordList;
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
# Which extensions to randomly assign
|
||||||
|
my @exts = ('txt', 'pdf', 'html', 'docx', 'xlsx', 'pptx', 'odt', 'ods', 'odp');
|
||||||
|
# Maximum depth of the target structure
|
||||||
|
my $depth = 4;
|
||||||
|
# Maximum amount of subfolders within a folder
|
||||||
|
my $max_subfolder = 10;
|
||||||
|
# Maximum amount of files within a folder
|
||||||
|
my $max_files_per_folder = 100;
|
||||||
|
# Maximum file size
|
||||||
|
my $max_file_size = 1024**2;
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
sub gen_entries($)
|
||||||
|
{
|
||||||
|
my ($count) = @_;
|
||||||
|
my $wl = new Data::Random::WordList( wordlist => '/usr/share/dict/words' );
|
||||||
|
my @rand_words = $wl->get_words($count);
|
||||||
|
foreach(@rand_words) {
|
||||||
|
$_ =~ s/\'//g;
|
||||||
|
}
|
||||||
|
$wl->close();
|
||||||
|
return @rand_words;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub create_subdir($)
|
||||||
|
{
|
||||||
|
my ($depth) = @_;
|
||||||
|
$depth--;
|
||||||
|
my %dir_tree = ( );
|
||||||
|
|
||||||
|
my @dirs = gen_entries(int(rand($max_subfolders)));
|
||||||
|
my @files = gen_entries(int(rand($max_files_per_folder)));
|
||||||
|
|
||||||
|
foreach my $file(@files) {
|
||||||
|
$dir_tree{$file} = int(rand($max_file_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($depth > 0) {
|
||||||
|
foreach my $dir(@dirs) {
|
||||||
|
$dir_tree{$dir} = create_subdir($depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return \%dir_tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub create_dir_listing(@)
|
||||||
|
{
|
||||||
|
my ($tree, $prefix) = @_;
|
||||||
|
foreach my $key(keys %$tree) {
|
||||||
|
my $entry = $tree->{$key};
|
||||||
|
#print "$entry:".scalar $entry.":".ref $entry."\n";
|
||||||
|
if (ref $entry eq "HASH") {
|
||||||
|
create_dir_listing($tree->{$key}, "$prefix/$key");
|
||||||
|
} else {
|
||||||
|
my $ext = @exts[rand @exts];
|
||||||
|
print "$prefix/$key.$ext:$entry\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srand();
|
||||||
|
my $dir = create_subdir($depth);
|
||||||
|
create_dir_listing($dir, '.');
|
||||||
Reference in New Issue
Block a user