mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-06 16:34:18 +02:00
Compare commits
48 Commits
v1.3.0-bet
...
v1.3.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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_MINOR 3 )
|
||||
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}beta3)
|
||||
set( SOVERSION 0 )
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Mac OS X
|
||||
Installing the ownCloud client on your Mac follows the normal app installation
|
||||
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
|
||||
3. ‘Applications’ folder on the right hand side From ‘Applications’, choose
|
||||
ownCloud
|
||||
|
||||
@@ -3,8 +3,8 @@ ownCloud Client supports the following command line switches:
|
||||
``--logwindow``
|
||||
open a window to show log output at startup.
|
||||
|
||||
``--logfile`` `<filename>`
|
||||
write log output to file.
|
||||
``--logdir`` `<dir>`
|
||||
write log output to dir, one for each sync run.
|
||||
|
||||
``--flushlog``
|
||||
flush the log file after every write.
|
||||
|
||||
@@ -9,7 +9,7 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
owncloud is a file synchronisation desktop utility it is based on mirall.
|
||||
ownCloud is a file synchronisation desktop utility it is based on mirall.
|
||||
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.
|
||||
|
||||
@@ -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.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
|
||||
-------
|
||||
|
||||
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
|
||||
|
||||
@@ -41,7 +41,7 @@ Here are a couple of useful steps to isolate the problem.
|
||||
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
|
||||
report a bug, you're advised to include the output.
|
||||
|
||||
@@ -57,11 +57,12 @@ starting the client again with this parameter. Syntax:
|
||||
* Mac OS X: ``/Applications/owncloud.app/Contents/MacOS/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
|
||||
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 ``--logdir <dir>``, where ``<dir>``
|
||||
is an existing directory. Each sync run will create a new file.
|
||||
|
||||
:ownCloud server Logfile:
|
||||
The ownCloud server maintains an ownCloud specific logfile as well. It can and
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<file>resources/folder-grey.png</file>
|
||||
<file>resources/task-ongoing.png</file>
|
||||
<file>resources/view-refresh.png</file>
|
||||
<file>resources/warning-16.png</file>
|
||||
<file>resources/owncloud_logo_blue.png</file>
|
||||
</qresource>
|
||||
</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"
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
#include <QHash>
|
||||
@@ -50,10 +54,26 @@ namespace Mirall {
|
||||
void mirallLogCatcher(QtMsgType type, const char *msg)
|
||||
{
|
||||
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 {
|
||||
|
||||
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()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
@@ -82,11 +102,13 @@ Application::Application(int &argc, char **argv) :
|
||||
_theme(Theme::instance()),
|
||||
_updateDetector(0),
|
||||
_logBrowser(0),
|
||||
_logExpire(0),
|
||||
_showLogWindow(false),
|
||||
_logFlush(false),
|
||||
_helpOnly(false),
|
||||
_fileItemDialog(0),
|
||||
_statusDialog(0)
|
||||
_statusDialog(0),
|
||||
_folderWizard(0)
|
||||
{
|
||||
setApplicationName( _theme->appNameGUI() );
|
||||
setWindowIcon( _theme->applicationIcon() );
|
||||
@@ -113,12 +135,6 @@ Application::Application(int &argc, char **argv) :
|
||||
|
||||
setQuitOnLastWindowClosed(false);
|
||||
|
||||
_folderWizard = new FolderWizard;
|
||||
|
||||
_owncloudSetupWizard = new OwncloudSetupWizard( _folderMan, _theme, this );
|
||||
connect( _owncloudSetupWizard, SIGNAL(ownCloudWizardDone(int)),
|
||||
this, SLOT(slotownCloudWizardDone(int)));
|
||||
|
||||
_statusDialog = new StatusDialog( _theme );
|
||||
connect( _statusDialog, SIGNAL(addASync()), this, SLOT(slotAddFolder()) );
|
||||
|
||||
@@ -190,7 +206,7 @@ void Application::slotStartFolderSetup( int result )
|
||||
|
||||
ownCloudInfo::instance()->checkInstallation();
|
||||
} else {
|
||||
_owncloudSetupWizard->startWizard();
|
||||
slotConfigure();
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Setup Wizard was canceled. No reparsing of config.";
|
||||
@@ -246,23 +262,28 @@ void Application::slotFetchCredentials()
|
||||
{
|
||||
QString trayMessage;
|
||||
|
||||
if( CredentialStore::instance()->canTryAgain() ) {
|
||||
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
|
||||
this, SLOT(slotCredentialsFetched(bool)) );
|
||||
CredentialStore::instance()->fetchCredentials();
|
||||
if( CredentialStore::instance()->state() == CredentialStore::TooManyAttempts ) {
|
||||
trayMessage = tr("Too many incorrect password attempts.");
|
||||
}
|
||||
if( CredentialStore::instance()->state() == CredentialStore::Ok ) {
|
||||
// the credentials are still valid and ok.
|
||||
slotCredentialsFetched( true );
|
||||
} else {
|
||||
qDebug() << "Can not try again to fetch Credentials.";
|
||||
trayMessage = tr("%1 user credentials are wrong. Please check configuration.")
|
||||
.arg(Theme::instance()->appNameGUI());
|
||||
}
|
||||
if( CredentialStore::instance()->canTryAgain() ) {
|
||||
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
|
||||
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() ) {
|
||||
_tray->showMessage(tr("Credentials"), trayMessage);
|
||||
_actionOpenStatus->setEnabled( false );
|
||||
_actionAddFolder->setEnabled( false );
|
||||
if( !trayMessage.isEmpty() ) {
|
||||
_tray->showMessage(tr("Credentials"), trayMessage);
|
||||
_actionOpenStatus->setEnabled( false );
|
||||
_actionAddFolder->setEnabled( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,6 +423,7 @@ void Application::slotownCloudWizardDone( int res )
|
||||
}
|
||||
_folderMan->setSyncEnabled( true );
|
||||
slotStartFolderSetup( res );
|
||||
_owncloudSetupWizard.reset(0);
|
||||
}
|
||||
|
||||
void Application::setupActions()
|
||||
@@ -521,7 +543,9 @@ void Application::setupLogBrowser()
|
||||
_logBrowser = new LogBrowser;
|
||||
qInstallMsgHandler( mirallLogCatcher );
|
||||
// ## 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;
|
||||
_logBrowser->setLogFile( _logFile, _logFlush );
|
||||
}
|
||||
@@ -537,6 +561,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 proxy;
|
||||
@@ -618,7 +673,7 @@ void Application::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
|
||||
slotFetchCredentials();
|
||||
}
|
||||
#if defined Q_WS_WIN || defined Q_WS_X11
|
||||
if( reason == QSystemTrayIcon::Trigger && _actionOpenStatus->isEnabled() ) {
|
||||
if( reason == QSystemTrayIcon::Trigger ) {
|
||||
slotOpenStatus();
|
||||
}
|
||||
#endif
|
||||
@@ -626,44 +681,58 @@ void Application::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
|
||||
|
||||
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) {
|
||||
qDebug() << "* Folder wizard completed";
|
||||
if (_folderWizard->exec() == QDialog::Accepted) {
|
||||
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();
|
||||
QString sourceFolder = _folderWizard->field(QLatin1String("sourceFolder")).toString();
|
||||
QString backend = QLatin1String("owncloud");
|
||||
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 );
|
||||
if (!FolderMan::ensureJournalGone( sourceFolder ))
|
||||
return;
|
||||
_folderMan->addFolderDefinition( backend, alias, sourceFolder, targetPath, false );
|
||||
Folder *f = _folderMan->setupFolderFromConfigFile( alias );
|
||||
if( f ) {
|
||||
_statusDialog->slotAddFolder( f );
|
||||
_statusDialog->buttonsSetEnabled();
|
||||
setupContextMenu();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << "* Folder wizard cancelled";
|
||||
}
|
||||
_folderMan->setSyncEnabled(true);
|
||||
_folderMan->slotScheduleAllFolders();
|
||||
} else {
|
||||
qDebug() << "* Folder wizard cancelled";
|
||||
}
|
||||
_folderWizard->deleteLater();
|
||||
_folderWizard = 0;
|
||||
}
|
||||
|
||||
void Application::slotOpenStatus()
|
||||
@@ -673,7 +742,7 @@ void Application::slotOpenStatus()
|
||||
QWidget *raiseWidget = 0;
|
||||
|
||||
// check if there is a mirall.cfg already.
|
||||
if( _owncloudSetupWizard->wizard()->isVisible() ) {
|
||||
if( _owncloudSetupWizard && _owncloudSetupWizard->wizard()->isVisible() ) {
|
||||
raiseWidget = _owncloudSetupWizard->wizard();
|
||||
}
|
||||
|
||||
@@ -683,8 +752,7 @@ void Application::slotOpenStatus()
|
||||
|
||||
if( !cfgFile.exists() ) {
|
||||
qDebug() << "No configured folders yet, start the Owncloud integration dialog.";
|
||||
_folderMan->setSyncEnabled(false);
|
||||
_owncloudSetupWizard->startWizard();
|
||||
slotConfigure();
|
||||
} else {
|
||||
qDebug() << "#============# Status dialog starting #=============#";
|
||||
raiseWidget = _statusDialog;
|
||||
@@ -731,16 +799,14 @@ void Application::slotAbout()
|
||||
void Application::slotRemoveFolder( const QString& alias )
|
||||
{
|
||||
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 );
|
||||
|
||||
if( ret == QMessageBox::No ) {
|
||||
return;
|
||||
}
|
||||
Folder *f = _folderMan->folder(alias);
|
||||
if( f && _overallStatusStrings.contains( f->alias() )) {
|
||||
_overallStatusStrings.remove( f->alias() );
|
||||
}
|
||||
|
||||
_folderMan->slotRemoveFolder( alias );
|
||||
_statusDialog->slotRemoveSelectedFolder( );
|
||||
@@ -794,11 +860,17 @@ void Application::slotEnableFolder(const QString& alias, const bool enable)
|
||||
|
||||
void Application::slotConfigure()
|
||||
{
|
||||
_folderMan->setSyncEnabled(false); // do not start more syncs.
|
||||
if (!_owncloudSetupWizard->wizard()->isVisible())
|
||||
_owncloudSetupWizard->startWizard();
|
||||
else
|
||||
if (_owncloudSetupWizard && !_owncloudSetupWizard->wizard()->isVisible()) {
|
||||
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()
|
||||
@@ -834,6 +906,10 @@ void Application::slotSyncStateChange( const QString& alias )
|
||||
computeOverallSyncStatus();
|
||||
|
||||
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)
|
||||
@@ -857,6 +933,18 @@ void Application::parseOptions(const QStringList &options)
|
||||
} else {
|
||||
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")) {
|
||||
_logFlush = true;
|
||||
} else if (option == QLatin1String("--monoicons")) {
|
||||
@@ -880,11 +968,12 @@ void Application::computeOverallSyncStatus()
|
||||
|
||||
// display the info of the least successful sync (eg. not just display the result of the latest sync
|
||||
SyncResult overallResult(SyncResult::Undefined );
|
||||
QMap<QString, QString> overallStatusStrings;
|
||||
QString trayMessage;
|
||||
Folder::Map map = _folderMan->map();
|
||||
|
||||
foreach ( Folder *syncedFolder, map.values() ) {
|
||||
QString folderMessage = _overallStatusStrings[syncedFolder->alias()];
|
||||
QString folderMessage;
|
||||
|
||||
SyncResult folderResult = syncedFolder->syncResult();
|
||||
SyncResult::Status syncStatus = folderResult.status();
|
||||
@@ -914,9 +1003,9 @@ void Application::computeOverallSyncStatus()
|
||||
break;
|
||||
case SyncResult::Success:
|
||||
if( overallResult.status() == SyncResult::Undefined ) {
|
||||
folderMessage = tr( "Last Sync was successful." );
|
||||
overallResult.setStatus( SyncResult::Success );
|
||||
}
|
||||
folderMessage = tr( "Last Sync was successful." );
|
||||
break;
|
||||
case SyncResult::Error:
|
||||
overallResult.setStatus( SyncResult::Error );
|
||||
@@ -938,15 +1027,13 @@ void Application::computeOverallSyncStatus()
|
||||
}
|
||||
|
||||
qDebug() << "Folder in overallStatus Message: " << syncedFolder << " with name " << syncedFolder->alias();
|
||||
QString msg = QString::fromLatin1("Folder %1: %2").arg(syncedFolder->alias()).arg(folderMessage);
|
||||
if( msg != _overallStatusStrings[syncedFolder->alias()] ) {
|
||||
_overallStatusStrings[syncedFolder->alias()] = msg;
|
||||
}
|
||||
QString msg = tr("Folder %1: %2").arg(syncedFolder->alias(), folderMessage);
|
||||
overallStatusStrings[syncedFolder->alias()] = msg;
|
||||
}
|
||||
|
||||
// create the tray blob message, check if we have an defined state
|
||||
if( overallResult.status() != SyncResult::Undefined ) {
|
||||
QStringList allStatusStrings = _overallStatusStrings.values();
|
||||
QStringList allStatusStrings = overallStatusStrings.values();
|
||||
if( ! allStatusStrings.isEmpty() )
|
||||
trayMessage = allStatusStrings.join(QLatin1String("\n"));
|
||||
else
|
||||
@@ -959,22 +1046,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()
|
||||
{
|
||||
setHelp();
|
||||
std::cout << _theme->appName().toLatin1().constData() << " version " <<
|
||||
_theme->version().toLatin1().constData() << std::endl << std::endl;
|
||||
std::cout << "File synchronisation desktop utility." << std::endl << std::endl;
|
||||
std::cout << "Options:" << std::endl;
|
||||
std::cout << " -h --help : show this help screen." << std::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;
|
||||
std::cout << " --logflush : flush the log file after every write." << std::endl;
|
||||
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;
|
||||
setHelp();
|
||||
QString helpText;
|
||||
QTextStream stream(&helpText);
|
||||
stream << _theme->appName().toLatin1().constData()
|
||||
<< QLatin1String(" version ")
|
||||
<< _theme->version().toLatin1().constData() << endl;
|
||||
|
||||
stream << QLatin1String("File synchronisation desktop utility.") << endl << endl
|
||||
<< QLatin1String(optionsC);
|
||||
|
||||
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()
|
||||
@@ -982,6 +1095,30 @@ void Application::setHelp()
|
||||
_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)
|
||||
{
|
||||
// Map the more apropriate script codes
|
||||
|
||||
@@ -79,10 +79,16 @@ protected:
|
||||
void setupContextMenu();
|
||||
void setupLogBrowser();
|
||||
void setupProxy();
|
||||
void enterNextLogFile();
|
||||
|
||||
//folders have to be disabled while making config changes
|
||||
void computeOverallSyncStatus();
|
||||
|
||||
// reimplemented
|
||||
#if defined(Q_WS_WIN)
|
||||
bool winEventFilter( MSG * message, long * result );
|
||||
#endif
|
||||
|
||||
protected slots:
|
||||
void slotTrayClicked( QSystemTrayIcon::ActivationReason );
|
||||
void slotFolderOpenAction(const QString & );
|
||||
@@ -118,7 +124,7 @@ private:
|
||||
#endif
|
||||
|
||||
FolderWizard *_folderWizard;
|
||||
OwncloudSetupWizard *_owncloudSetupWizard;
|
||||
QScopedPointer<OwncloudSetupWizard> _owncloudSetupWizard;
|
||||
SslErrorDialog *_sslErrorDialog;
|
||||
|
||||
// tray's menu
|
||||
@@ -130,9 +136,10 @@ private:
|
||||
Theme *_theme;
|
||||
QSignalMapper *_folderOpenActionMapper;
|
||||
UpdateDetector *_updateDetector;
|
||||
QMap<QString, QString> _overallStatusStrings;
|
||||
LogBrowser *_logBrowser;
|
||||
QString _logFile;
|
||||
QString _logDirectory;
|
||||
int _logExpire;
|
||||
bool _showLogWindow;
|
||||
bool _logFlush;
|
||||
bool _helpOnly;
|
||||
|
||||
@@ -69,15 +69,12 @@ CredentialStore::CredState CredentialStore::state()
|
||||
|
||||
bool CredentialStore::canTryAgain()
|
||||
{
|
||||
bool canDoIt = false;
|
||||
|
||||
if( _tries > MAX_LOGIN_ATTEMPTS ) {
|
||||
qDebug() << "canTryAgain: Max attempts reached.";
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Since QtKeyChain is required now, it makes to only
|
||||
* query once. */
|
||||
/* Since QtKeyChain is required now, it makes sense to only query once. */
|
||||
if( _state == NotFetched || _state == AsyncWriting ) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -191,6 +191,11 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
|
||||
int re = 0;
|
||||
|
||||
if (file->instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& file->instruction != CSYNC_INSTRUCTION_REMOVE) {
|
||||
_hasFiles = true;
|
||||
}
|
||||
|
||||
switch(file->instruction) {
|
||||
case CSYNC_INSTRUCTION_NONE:
|
||||
case CSYNC_INSTRUCTION_IGNORE:
|
||||
@@ -310,6 +315,7 @@ void CSyncThread::startSync()
|
||||
// cleans up behind us and emits finished() to ease error handling
|
||||
CSyncRunScopeHelper helper(_csync_ctx, this);
|
||||
|
||||
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
|
||||
csync_set_userdata(_csync_ctx, this);
|
||||
|
||||
// csync_set_auth_callback( _csync_ctx, getauth );
|
||||
@@ -327,6 +333,7 @@ void CSyncThread::startSync()
|
||||
return;
|
||||
}
|
||||
|
||||
_hasFiles = false;
|
||||
bool walkOk = true;
|
||||
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
|
||||
qDebug() << "Error in local treewalk.";
|
||||
@@ -336,6 +343,16 @@ void CSyncThread::startSync()
|
||||
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)
|
||||
emit(started());
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ signals:
|
||||
void finished();
|
||||
void started();
|
||||
|
||||
void aboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel);
|
||||
|
||||
private:
|
||||
void handleSyncError(CSYNC *ctx, const char *state);
|
||||
static void progress(const char *remote_url,
|
||||
@@ -79,6 +81,8 @@ private:
|
||||
CSYNC *_csync_ctx;
|
||||
bool _needsUpdate;
|
||||
|
||||
bool _hasFiles; // true if there is at least one file that is not ignored or removed
|
||||
|
||||
friend class CSyncRunScopeHelper;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -123,7 +123,10 @@ void FileItemDialog::slotSetFolderMessage()
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
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()
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QtCore>
|
||||
|
||||
namespace Mirall {
|
||||
@@ -79,20 +80,28 @@ void FolderMan::slotReparseConfiguration()
|
||||
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()
|
||||
{
|
||||
qDebug() << "* Setup folders from " << _folderConfigPath;
|
||||
|
||||
// first terminate sync jobs.
|
||||
terminateCurrentSync();
|
||||
|
||||
// clear the list of existing folders.
|
||||
Folder::MapIterator i(_folderMap);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
delete _folderMap.take( i.key() );
|
||||
}
|
||||
unloadAllFolders();
|
||||
|
||||
QDir dir( _folderConfigPath );
|
||||
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()
|
||||
{
|
||||
if( !_currentSyncFolder.isEmpty() ) {
|
||||
@@ -235,7 +263,7 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
|
||||
folder->setConfigFile(file);
|
||||
} else {
|
||||
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.
|
||||
void FolderMan::terminateSyncProcess( const QString& alias )
|
||||
{
|
||||
Folder *f = _folderMap[alias];
|
||||
if( f ) {
|
||||
f->slotTerminateSync();
|
||||
QString folderAlias = alias;
|
||||
if( alias.isEmpty() ) {
|
||||
folderAlias = _currentSyncFolder;
|
||||
}
|
||||
if( ! folderAlias.isEmpty() ) {
|
||||
Folder *f = _folderMap[folderAlias];
|
||||
if( f ) {
|
||||
f->slotTerminateSync();
|
||||
|
||||
if(_currentSyncFolder == alias )
|
||||
_currentSyncFolder = QString::null;
|
||||
if(_currentSyncFolder == folderAlias )
|
||||
_currentSyncFolder = QString::null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,6 +471,8 @@ void FolderMan::removeFolder( const QString& alias )
|
||||
{
|
||||
Folder *f = 0;
|
||||
|
||||
_scheduleQueue.removeAll(alias);
|
||||
|
||||
if( _folderMap.contains( alias )) {
|
||||
qDebug() << "Removing " << alias;
|
||||
f = _folderMap.take( alias );
|
||||
@@ -464,7 +500,7 @@ QString FolderMan::getBackupName( const QString& fullPathName ) const
|
||||
int cnt = 1;
|
||||
do {
|
||||
if( fi.exists() ) {
|
||||
newName += fullPathName + QString( ".oC_bak_%1").arg(cnt++);
|
||||
newName = fullPathName + QString( ".oC_bak_%1").arg(cnt++);
|
||||
fi.setFile(newName);
|
||||
}
|
||||
} while( fi.exists() );
|
||||
@@ -479,6 +515,13 @@ bool FolderMan::startFromScratch( const QString& localFolder )
|
||||
QFileInfo fi( localFolder );
|
||||
if( fi.exists() && fi.isDir() ) {
|
||||
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() );
|
||||
|
||||
if( file.rename( fi.absoluteFilePath(), newName )) {
|
||||
|
||||
@@ -76,6 +76,13 @@ public:
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -102,7 +109,10 @@ public slots:
|
||||
|
||||
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.
|
||||
// the current one will finish.
|
||||
|
||||
@@ -36,7 +36,8 @@ FolderWizardSourcePage::FolderWizardSourcePage()
|
||||
{
|
||||
_ui.setupUi(this);
|
||||
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);
|
||||
_ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() );
|
||||
|
||||
@@ -64,7 +65,7 @@ void FolderWizardSourcePage::cleanupPage()
|
||||
|
||||
bool FolderWizardSourcePage::isComplete() const
|
||||
{
|
||||
QFileInfo selFile( _ui.localFolderLineEdit->text() );
|
||||
QFileInfo selFile( QDir::fromNativeSeparators(_ui.localFolderLineEdit->text()) );
|
||||
QString userInput = selFile.canonicalFilePath();
|
||||
|
||||
QString warnString;
|
||||
@@ -94,7 +95,8 @@ bool FolderWizardSourcePage::isComplete() const
|
||||
qDebug() << "Checking local path: " << folderDir << " <-> " << userInput;
|
||||
if( QFileInfo( f->path() ) == userInput ) {
|
||||
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 )) {
|
||||
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"),
|
||||
QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
|
||||
if (!dir.isEmpty()) {
|
||||
_ui.localFolderLineEdit->setText(dir);
|
||||
_ui.localFolderLineEdit->setText(QDir::toNativeSeparators(dir));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,9 +98,7 @@ public:
|
||||
|
||||
enum {
|
||||
Page_Source,
|
||||
Page_Target,
|
||||
Page_Network,
|
||||
Page_Owncloud
|
||||
Page_Target
|
||||
};
|
||||
|
||||
FolderWizard(QWidget *parent = 0);
|
||||
|
||||
@@ -113,15 +113,12 @@ LogBrowser::LogBrowser(QWidget *parent) :
|
||||
|
||||
setModal(false);
|
||||
|
||||
// needs to be a queued connection as logs from other threads come in
|
||||
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::QueuedConnection);
|
||||
// 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::AutoConnection);
|
||||
}
|
||||
|
||||
LogBrowser::~LogBrowser()
|
||||
{
|
||||
if( _logstream ) {
|
||||
_logFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void LogBrowser::slotNewLog( const QString& msg )
|
||||
@@ -138,6 +135,9 @@ void LogBrowser::slotNewLog( const QString& msg )
|
||||
|
||||
void LogBrowser::setLogFile( const QString & name, bool flush )
|
||||
{
|
||||
if( _logstream ) {
|
||||
_logFile.close();
|
||||
}
|
||||
_logFile.setFileName( name );
|
||||
|
||||
if(!_logFile.open(QIODevice::WriteOnly)) {
|
||||
@@ -150,7 +150,7 @@ void LogBrowser::setLogFile( const QString & name, bool flush )
|
||||
return;
|
||||
}
|
||||
_doFileFlush = flush;
|
||||
_logstream = new QTextStream( &_logFile );
|
||||
_logstream.reset(new QTextStream( &_logFile ));
|
||||
}
|
||||
|
||||
void LogBrowser::slotFind()
|
||||
|
||||
@@ -67,7 +67,7 @@ private:
|
||||
|
||||
QFile _logFile;
|
||||
bool _doFileFlush;
|
||||
QTextStream *_logstream;
|
||||
QScopedPointer<QTextStream> _logstream;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkProxyFactory>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace Mirall {
|
||||
|
||||
@@ -112,6 +114,7 @@ ownCloudFolder::~ownCloudFolder()
|
||||
csync_request_abort(_csync_ctx);
|
||||
_thread->wait();
|
||||
}
|
||||
delete _csync;
|
||||
// Destroy csync here.
|
||||
csync_destroy(_csync_ctx);
|
||||
}
|
||||
@@ -283,6 +286,8 @@ void ownCloudFolder::startSync(const QStringList &pathList)
|
||||
_csync->moveToThread(_thread);
|
||||
|
||||
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
||||
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
||||
|
||||
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
||||
|
||||
@@ -290,6 +295,11 @@ void ownCloudFolder::startSync(const QStringList &pathList)
|
||||
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
|
||||
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), 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();
|
||||
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
|
||||
emit syncStarted();
|
||||
@@ -488,5 +498,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
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
public slots:
|
||||
void startSync();
|
||||
void slotTerminateSync();
|
||||
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
|
||||
|
||||
protected slots:
|
||||
void slotLocalPathChanged( const QString& );
|
||||
|
||||
@@ -124,34 +124,50 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
|
||||
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();
|
||||
if( !( localFolder.isEmpty() || _remoteFolder.isEmpty() ) ) { // both variables are set.
|
||||
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 acceptCfg = true;
|
||||
|
||||
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
|
||||
if( startFromScratch ) {
|
||||
// clean the entire directory.
|
||||
if( _folderMan->startFromScratch( localFolder ) ) {
|
||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully prepared syncing from scratch!</font>"));
|
||||
} else {
|
||||
_ocWizard->appendToConfigurationLog(tr("<font color=\"red\">Failed to prepare syncing from scratch!</font>"));
|
||||
if( urlHasChanged ) {
|
||||
_folderMan->unloadAllFolders();
|
||||
|
||||
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
|
||||
if( startFromScratch ) {
|
||||
// first try to rename (backup) the current local dir.
|
||||
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 {
|
||||
qDebug() << "WRN: Got unknown dialog result code " << result;
|
||||
// save the user credentials and afterwards clear the cred store.
|
||||
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
|
||||
|
||||
@@ -196,6 +196,9 @@ void OwncloudSetupPage::initializePage()
|
||||
_checking = false;
|
||||
_multipleFoldersExist = false;
|
||||
|
||||
// call to init label
|
||||
slotHandleUserInput();
|
||||
|
||||
if( _configExists ) {
|
||||
_ui.lePassword->setFocus();
|
||||
} else {
|
||||
@@ -260,7 +263,7 @@ void OwncloudSetupPage::slotHandleUserInput()
|
||||
t = tr("Change the Password for your configured account.");
|
||||
} else {
|
||||
// Complete new setup.
|
||||
_ui.pbSelectLocalFolder->setText(locFolder);
|
||||
_ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(locFolder));
|
||||
|
||||
if( _remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/") ) {
|
||||
t = tr("Your entire account will be synced to the local folder '%1'.")
|
||||
|
||||
@@ -54,7 +54,9 @@ Mirall::ProxyDialog::ProxyDialog( QWidget* parent )
|
||||
}
|
||||
|
||||
hostLineEdit->setText(cfgFile.proxyHostName());
|
||||
portSpinBox->setValue(cfgFile.proxyPort());
|
||||
int port = cfgFile.proxyPort();
|
||||
if (port == 0) port = 8080;
|
||||
portSpinBox->setValue(port);
|
||||
if (!cfgFile.proxyUser().isEmpty())
|
||||
{
|
||||
authRequiredcheckBox->setChecked(true);
|
||||
|
||||
@@ -64,40 +64,33 @@ FolderViewDelegate::~FolderViewDelegate()
|
||||
QSize FolderViewDelegate::sizeHint(const QStyleOptionViewItem & option ,
|
||||
const QModelIndex & index) const
|
||||
{
|
||||
int w = 0;
|
||||
|
||||
QString p = qvariant_cast<QString>(index.data(FolderPathRole));
|
||||
QFont aliasFont = QApplication::font();
|
||||
QFont font = QApplication::font();
|
||||
Q_UNUSED(option)
|
||||
QFont aliasFont = option.font;
|
||||
QFont font = option.font;
|
||||
aliasFont.setPointSize( font.pointSize() +2 );
|
||||
|
||||
QFontMetrics fm(font);
|
||||
QFontMetrics aliasFm(aliasFont);
|
||||
|
||||
int margin = aliasFm.height()/2;
|
||||
|
||||
w = 8 + fm.boundingRect( p ).width();
|
||||
int aliasMargin = aliasFm.height()/2;
|
||||
int margin = fm.height()/4;
|
||||
|
||||
// calc height
|
||||
|
||||
int h = margin; // margin to top
|
||||
int h = aliasMargin; // margin to top
|
||||
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()/2; // between local and remote path
|
||||
h += margin; // between local and remote path
|
||||
h += fm.height(); // remote path
|
||||
h += margin; // bottom margin
|
||||
|
||||
int minHeight = 48 + margin + margin; // icon + margins
|
||||
|
||||
if( h < minHeight ) h = minHeight;
|
||||
h += aliasMargin; // bottom margin
|
||||
|
||||
// add some space to show an error condition.
|
||||
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,
|
||||
@@ -107,8 +100,8 @@ void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
||||
|
||||
painter->save();
|
||||
|
||||
QFont aliasFont = QApplication::font();
|
||||
QFont subFont = QApplication::font();
|
||||
QFont aliasFont = option.font;
|
||||
QFont subFont = option.font;
|
||||
QFont errorFont = subFont;
|
||||
|
||||
//font.setPixelSize(font.weight()+);
|
||||
@@ -117,10 +110,11 @@ void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
||||
|
||||
QFontMetrics subFm( subFont );
|
||||
QFontMetrics aliasFm( aliasFont );
|
||||
int margin = aliasFm.height()/2;
|
||||
|
||||
QIcon folderIcon = qvariant_cast<QIcon>(index.data(FolderIconRole));
|
||||
QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIcon));
|
||||
int aliasMargin = aliasFm.height()/2;
|
||||
int margin = subFm.height()/4;
|
||||
|
||||
QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIconRole));
|
||||
QString aliasText = qvariant_cast<QString>(index.data(FolderAliasRole));
|
||||
QString pathText = qvariant_cast<QString>(index.data(FolderPathRole));
|
||||
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();
|
||||
// QString syncStatus = syncEnabled? tr( "Enabled" ) : tr( "Disabled" );
|
||||
|
||||
QSize iconsize(48, 48); // = icon.actualSize(option.decorationSize);
|
||||
|
||||
QRect aliasRect = option.rect;
|
||||
QRect iconRect = option.rect;
|
||||
QRect aliasRect = option.rect;
|
||||
|
||||
iconRect.setLeft( margin );
|
||||
iconRect.setWidth( 48 );
|
||||
iconRect.setTop( iconRect.top() + margin ); // (iconRect.height()-iconsize.height())/2);
|
||||
iconRect.setLeft( aliasMargin );
|
||||
iconRect.setTop( iconRect.top() + aliasMargin ); // (iconRect.height()-iconsize.height())/2);
|
||||
|
||||
QRect statusRect = iconRect;
|
||||
statusRect.setLeft( option.rect.right() - margin - 48 );
|
||||
statusRect.setRight( option.rect.right() - margin );
|
||||
|
||||
aliasRect.setLeft(iconRect.right()+margin);
|
||||
|
||||
aliasRect.setTop(aliasRect.top() + aliasFm.height()/2 );
|
||||
aliasRect.setBottom(aliasRect.top()+aliasFm.height());
|
||||
// local directory box
|
||||
aliasRect.setTop(aliasRect.top() + aliasMargin );
|
||||
aliasRect.setBottom(aliasRect.top() + aliasFm.height());
|
||||
aliasRect.setRight(aliasRect.right() - aliasMargin );
|
||||
|
||||
// local directory box
|
||||
QRect localPathRect = aliasRect;
|
||||
localPathRect.setTop(aliasRect.bottom() + margin / 3);
|
||||
localPathRect.setBottom(localPathRect.top()+subFm.height());
|
||||
localPathRect.setTop(aliasRect.bottom() + margin );
|
||||
localPathRect.setBottom(localPathRect.top() + subFm.height());
|
||||
|
||||
// remote directory box
|
||||
QRect remotePathRect = localPathRect;
|
||||
remotePathRect.setTop( localPathRect.bottom() + subFm.height()/2 );
|
||||
remotePathRect.setTop( localPathRect.bottom() + margin );
|
||||
remotePathRect.setBottom( remotePathRect.top() + subFm.height());
|
||||
|
||||
iconRect.setBottom(remotePathRect.bottom());
|
||||
iconRect.setWidth(iconRect.height());
|
||||
|
||||
//painter->drawPixmap(QPoint(iconRect.right()/2,iconRect.top()/2),icon.pixmap(iconsize.width(),iconsize.height()));
|
||||
if( syncEnabled ) {
|
||||
painter->drawPixmap(QPoint(iconRect.left(),iconRect.top()), folderIcon.pixmap(iconsize.width(),iconsize.height()));
|
||||
int nextToIcon = iconRect.right()+aliasMargin;
|
||||
aliasRect.setLeft(nextToIcon);
|
||||
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 {
|
||||
painter->drawPixmap(QPoint(iconRect.left(),iconRect.top()), folderIcon.pixmap(iconsize.width(),iconsize.height(), QIcon::Disabled ));
|
||||
painter->setPen(option.palette.color(QPalette::Text));
|
||||
}
|
||||
|
||||
painter->drawPixmap(QPoint(statusRect.left(), statusRect.top()), statusIcon.pixmap(48,48));
|
||||
|
||||
QString elidedAlias = aliasFm.elidedText(aliasText, Qt::ElideRight, aliasRect.width());
|
||||
painter->setFont(aliasFont);
|
||||
painter->drawText(aliasRect, aliasText);
|
||||
painter->drawText(aliasRect, elidedAlias);
|
||||
|
||||
painter->setFont(subFont);
|
||||
painter->drawText(localPathRect.left(),localPathRect.top()+17, pathText);
|
||||
painter->drawText(remotePathRect, tr("Remote path: %1").arg(remotePath));
|
||||
QString elidedPathText = subFm.elidedText(pathText, Qt::ElideMiddle, localPathRect.width());
|
||||
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
|
||||
if( !errorText.isEmpty() ) {
|
||||
QRect errorRect = localPathRect;
|
||||
errorRect.setLeft( iconRect.left());
|
||||
errorRect.setTop( iconRect.bottom()+subFm.height()/2 );
|
||||
errorRect.setHeight(subFm.height()+margin);
|
||||
errorRect.setRight( statusRect.right() );
|
||||
errorRect.setHeight(subFm.height()+aliasMargin);
|
||||
errorRect.setRight( option.rect.right()-aliasMargin );
|
||||
|
||||
painter->setBrush( QColor(0xbb, 0x4d, 0x4d) );
|
||||
painter->setPen( QColor(0xaa, 0xaa, 0xaa));
|
||||
painter->drawRoundedRect( errorRect, 4, 4 );
|
||||
|
||||
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->setFont(errorFont);
|
||||
QRect errorTextRect = errorRect;
|
||||
errorTextRect.setLeft( errorTextRect.left()+margin/2 +16);
|
||||
errorTextRect.setTop( errorTextRect.top()+margin/2 );
|
||||
errorTextRect.setLeft( errorTextRect.left()+aliasMargin +16);
|
||||
errorTextRect.setTop( errorTextRect.top()+aliasMargin/2 );
|
||||
|
||||
int linebreak = errorText.indexOf(QLatin1String("<br"));
|
||||
QString eText = errorText;
|
||||
@@ -370,7 +372,7 @@ void StatusDialog::folderToModelItem( QStandardItem *item, Folder *f )
|
||||
if( ! item || !f ) return;
|
||||
|
||||
QIcon icon = _theme->folderIcon( f->backend() );
|
||||
item->setData( icon, FolderViewDelegate::FolderIconRole );
|
||||
item->setData( icon, FolderViewDelegate::FolderStatusIconRole );
|
||||
item->setData( f->nativePath(), FolderViewDelegate::FolderPathRole );
|
||||
item->setData( f->secondPath(), FolderViewDelegate::FolderSecondPathRole );
|
||||
item->setData( f->alias(), FolderViewDelegate::FolderAliasRole );
|
||||
@@ -383,9 +385,9 @@ void StatusDialog::folderToModelItem( QStandardItem *item, Folder *f )
|
||||
|
||||
item->setData( _theme->statusHeaderText( status ), Qt::ToolTipRole );
|
||||
if( f->syncEnabled() ) {
|
||||
item->setData( _theme->syncStateIcon( status ), FolderViewDelegate::FolderStatusIcon );
|
||||
item->setData( _theme->syncStateIcon( status ), FolderViewDelegate::FolderStatusIconRole );
|
||||
} 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( errors, FolderViewDelegate::FolderErrorMsg );
|
||||
|
||||
@@ -45,15 +45,14 @@ class FolderViewDelegate : public QStyledItemDelegate
|
||||
FolderViewDelegate();
|
||||
virtual ~FolderViewDelegate();
|
||||
|
||||
enum datarole { FolderAliasRole = Qt::UserRole + 100,
|
||||
FolderPathRole = Qt::UserRole + 101,
|
||||
FolderSecondPathRole = Qt::UserRole + 102,
|
||||
FolderIconRole = Qt::UserRole + 103,
|
||||
FolderRemotePath = Qt::UserRole + 104,
|
||||
FolderStatus = Qt::UserRole + 105,
|
||||
FolderErrorMsg = Qt::UserRole + 106,
|
||||
FolderStatusIcon = Qt::UserRole + 107,
|
||||
FolderSyncEnabled = Qt::UserRole + 108
|
||||
enum datarole { FolderAliasRole = Qt::UserRole + 100,
|
||||
FolderPathRole,
|
||||
FolderSecondPathRole,
|
||||
FolderRemotePath,
|
||||
FolderStatus,
|
||||
FolderErrorMsg,
|
||||
FolderSyncEnabled,
|
||||
FolderStatusIconRole
|
||||
};
|
||||
void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
|
||||
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
|
||||
|
||||
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