nextcloud-desktop/src/gui/folder.h

513 lines
16 KiB
C
Raw Normal View History

2011-04-06 13:48:02 +04:00
/*
* Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
2013-07-22 22:27:42 +04:00
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
2011-04-06 13:48:02 +04:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
2011-02-17 02:21:45 +03:00
#ifndef MIRALL_FOLDER_H
#define MIRALL_FOLDER_H
#include "syncresult.h"
#include "progressdispatcher.h"
2017-09-01 19:11:43 +03:00
#include "common/syncjournaldb.h"
#include "networkjobs.h"
#include "syncoptions.h"
2011-02-17 02:21:45 +03:00
#include <QObject>
#include <QStringList>
#include <QUuid>
#include <set>
#include <chrono>
#include <memory>
2011-02-17 02:21:45 +03:00
class QThread;
2015-04-24 11:18:33 +03:00
class QSettings;
2011-02-17 02:21:45 +03:00
2014-11-10 00:34:07 +03:00
namespace OCC {
2011-02-17 02:21:45 +03:00
class Vfs;
class SyncEngine;
class AccountState;
class SyncRunFileLog;
class FolderWatcher;
class LocalDiscoveryTracker;
2015-06-29 19:56:09 +03:00
/**
* @brief The FolderDefinition class
* @ingroup gui
*/
2015-04-24 11:18:33 +03:00
class FolderDefinition
{
public:
/// The name of the folder in the ui and internally
QString alias;
/// path on local machine (always trailing /)
2015-04-24 11:18:33 +03:00
QString localPath;
/// path to the journal, usually relative to localPath
QString journalPath;
/// path on remote (usually no trailing /, exception "/")
2015-04-24 11:18:33 +03:00
QString targetPath;
/// whether the folder is paused
bool paused = false;
/// whether the folder syncs hidden files
bool ignoreHiddenFiles = false;
/// Which virtual files setting the folder uses
Vfs::Mode virtualFilesMode = Vfs::Off;
/// The CLSID where this folder appears in registry for the Explorer navigation pane entry.
QUuid navigationPaneClsid;
2015-04-24 11:18:33 +03:00
/// Whether the vfs mode shall silently be updated if possible
bool upgradeVfsMode = false;
/// Saves the folder definition into the current settings group.
2017-05-17 11:55:42 +03:00
static void save(QSettings &settings, const FolderDefinition &folder);
2015-04-24 11:18:33 +03:00
/// Reads a folder definition from the current settings group.
2017-05-17 11:55:42 +03:00
static bool load(QSettings &settings, const QString &alias,
FolderDefinition *folder);
/** The highest version in the settings that load() can read
*
* Version 1: initial version (default if value absent in settings)
* Version 2: introduction of metadata_parent hash in 2.6.0
* (version remains readable by 2.5.1)
* Version 3: introduction of new windows vfs mode in 2.6.0
*/
static int maxSettingsVersion() { return 3; }
/// Ensure / as separator and trailing /.
2017-05-17 11:55:42 +03:00
static QString prepareLocalPath(const QString &path);
/// Remove ending /, then ensure starting '/': so "/foo/bar" and "/".
2017-05-17 11:55:42 +03:00
static QString prepareTargetPath(const QString &path);
/// journalPath relative to localPath.
QString absoluteJournalPath() const;
/// Returns the relative journal path that's appropriate for this folder and account.
QString defaultJournalPath(AccountPtr account);
2015-04-24 11:18:33 +03:00
};
2015-06-29 19:56:09 +03:00
/**
* @brief The Folder class
* @ingroup gui
*/
2014-07-11 00:58:58 +04:00
class Folder : public QObject
2011-02-17 02:21:45 +03:00
{
Q_OBJECT
public:
enum class ChangeReason {
Other,
UnLock
};
Q_ENUM(ChangeReason)
/** Create a new Folder
*/
Folder(const FolderDefinition &definition, AccountState *accountState, std::unique_ptr<Vfs> vfs, QObject *parent = nullptr);
2013-07-22 22:27:42 +04:00
~Folder();
2011-02-17 02:21:45 +03:00
using Map = QMap<QString, Folder *>;
using MapIterator = QMapIterator<QString, Folder *>;
/**
* The account the folder is configured on.
*/
2017-05-17 11:55:42 +03:00
AccountState *accountState() const { return _accountState.data(); }
2011-04-06 11:52:02 +04:00
/**
* alias or nickname
*/
QString alias() const;
QString shortGuiRemotePathOrAppName() const; // since 2.0 we don't want to show aliases anymore, show the path instead
2011-04-06 11:52:02 +04:00
/**
* short local path to display on the GUI (native separators)
*/
QString shortGuiLocalPath() const;
/**
* canonical local folder path, always ends with /
*/
QString path() const;
2013-10-21 23:42:52 +04:00
/**
* cleaned canonical folder path, like path() but never ends with a /
*
* Wrapper for QDir::cleanPath(path()) except for "Z:/",
* where it returns "Z:" instead of "Z:/".
*/
QString cleanPath() const;
2013-07-22 22:27:42 +04:00
/**
* remote folder path, usually without trailing /, exception "/"
2013-07-22 22:27:42 +04:00
*/
2013-10-21 23:42:52 +04:00
QString remotePath() const;
/**
* remote folder path, always with a trailing /
*/
QString remotePathTrailingSlash() const;
void setNavigationPaneClsid(const QUuid &clsid) { _definition.navigationPaneClsid = clsid; }
QUuid navigationPaneClsid() const { return _definition.navigationPaneClsid; }
2013-10-21 23:42:52 +04:00
/**
* remote folder path with server url
*/
QUrl remoteUrl() const;
2011-10-13 18:41:24 +04:00
/**
* switch sync on or off
*/
2017-05-17 11:55:42 +03:00
void setSyncPaused(bool);
2011-10-13 18:41:24 +04:00
bool syncPaused() const;
2011-10-13 18:41:24 +04:00
/**
* Returns true when the folder may sync.
*/
bool canSync() const;
void prepareToSync();
/**
* True if the folder is busy and can't initiate
* a synchronization
*/
2013-07-22 22:27:42 +04:00
virtual bool isBusy() const;
2011-09-27 10:15:30 +04:00
/** True if the folder is currently synchronizing */
bool isSyncRunning() const;
2011-10-13 18:41:24 +04:00
/**
* return the last sync result with error message and status
*/
2017-05-17 11:55:42 +03:00
SyncResult syncResult() const;
2017-05-17 11:55:42 +03:00
/**
* This is called when the sync folder definition is removed. Do cleanups here.
*
* It removes the database, among other things.
*
* The folder is not in a valid state afterwards!
*/
virtual void wipeForRemoval();
2017-05-17 11:55:42 +03:00
void setSyncState(SyncResult::Status state);
2017-05-17 11:55:42 +03:00
void setDirtyNetworkLimits();
2017-05-17 11:55:42 +03:00
/**
* Ignore syncing of hidden files or not. This is defined in the
* folder definition
*/
2017-05-17 11:55:42 +03:00
bool ignoreHiddenFiles();
void setIgnoreHiddenFiles(bool ignore);
2017-05-17 11:55:42 +03:00
// Used by the Socket API
SyncJournalDb *journalDb() { return &_journal; }
SyncEngine &syncEngine() { return *_engine; }
Vfs &vfs() { return *_vfs; }
2017-05-17 11:55:42 +03:00
RequestEtagJob *etagJob() { return _requestEtagJob; }
std::chrono::milliseconds msecSinceLastSync() const { return std::chrono::milliseconds(_timeSinceLastSyncDone.elapsed()); }
std::chrono::milliseconds msecLastSyncDuration() const { return _lastSyncDuration; }
2017-05-17 11:55:42 +03:00
int consecutiveFollowUpSyncs() const { return _consecutiveFollowUpSyncs; }
int consecutiveFailingSyncs() const { return _consecutiveFailingSyncs; }
2017-05-17 11:55:42 +03:00
/// Saves the folder data in the account's settings.
void saveToSettings() const;
/// Removes the folder from the account's settings.
void removeFromSettings() const;
2015-04-24 11:18:33 +03:00
2017-05-17 11:55:42 +03:00
/**
* Returns whether a file inside this folder should be excluded.
*/
2017-05-17 11:55:42 +03:00
bool isFileExcludedAbsolute(const QString &fullPath) const;
2017-05-17 11:55:42 +03:00
/**
* Returns whether a file inside this folder should be excluded.
*/
2017-05-17 11:55:42 +03:00
bool isFileExcludedRelative(const QString &relativePath) const;
2017-05-17 11:55:42 +03:00
/** Calls schedules this folder on the FolderMan after a short delay.
*
* This should be used in situations where a sync should be triggered
* because a local file was modified. Syncs don't upload files that were
* modified too recently, and this delay ensures the modification is
* far enough in the past.
*
* The delay doesn't reset with subsequent calls.
*/
2017-05-17 11:55:42 +03:00
void scheduleThisFolderSoon();
2017-05-17 11:55:42 +03:00
/**
* Migration: When this flag is true, this folder will save to
* the backwards-compatible 'Folders' section in the config file.
*/
2017-05-17 11:55:42 +03:00
void setSaveBackwardsCompatible(bool save);
/** Used to have placeholders: save in placeholder config section */
void setSaveInFoldersWithPlaceholders() { _saveInFoldersWithPlaceholders = true; }
/**
* Sets up this folder's folderWatcher if possible.
*
* May be called several times.
*/
void registerFolderWatcher();
/** virtual files of some kind are enabled
*
* This is independent of whether new files will be virtual. It's possible to have this enabled
* and never have an automatic virtual file. But when it's on, the shell context menu will allow
* users to make existing files virtual.
*/
bool virtualFilesEnabled() const;
void setVirtualFilesEnabled(bool enabled);
void setRootPinState(PinState state);
/** Whether user desires a switch that couldn't be executed yet, see member */
bool isVfsOnOffSwitchPending() const { return _vfsOnOffPending; }
void setVfsOnOffSwitchPending(bool pending) { _vfsOnOffPending = pending; }
/** Whether this folder should show selective sync ui */
bool supportsSelectiveSync() const;
signals:
void syncStateChange();
void syncStarted();
void syncFinished(const SyncResult &result);
2017-05-17 11:55:42 +03:00
void progressInfo(const ProgressInfo &progress);
void newBigFolderDiscovered(const QString &); // A new folder bigger than the threshold was discovered
2017-05-17 11:55:42 +03:00
void syncPausedChanged(Folder *, bool paused);
void canSyncChanged();
/**
* Fires for each change inside this folder that wasn't caused
* by sync activity.
*/
2017-05-17 11:55:42 +03:00
void watchedFileChangedExternally(const QString &path);
2011-11-04 14:41:49 +04:00
public slots:
2017-05-17 11:55:42 +03:00
/**
* terminate the current sync run
*/
2017-05-17 11:55:42 +03:00
void slotTerminateSync();
2017-05-17 11:55:42 +03:00
// connected to the corresponding signals in the SyncEngine
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, std::function<void(bool)> callback);
2017-05-17 11:55:42 +03:00
/**
2013-07-22 22:27:42 +04:00
* Starts a sync operation
*
* If the list of changed files is known, it is passed.
*/
2017-05-17 11:55:42 +03:00
void startSync(const QStringList &pathList = QStringList());
2013-07-22 22:27:42 +04:00
2017-05-17 11:55:42 +03:00
int slotDiscardDownloadProgress();
int downloadInfoCount();
int slotWipeErrorBlacklist();
int errorBlackListEntryCount();
2017-05-17 11:55:42 +03:00
/**
* Triggered by the folder watcher when a file/dir in this folder
* changes. Needs to check whether this change should trigger a new
* sync run to be scheduled.
*/
void slotWatchedPathChanged(const QString &path, ChangeReason reason);
/**
* Mark a virtual file as being requested for download, and start a sync.
*
* "implicit" here means that this download request comes from the user wanting
* to access the file's data. The user did not change the file's pin state.
* If the file is currently OnlineOnly its state will change to Unspecified.
*
* The download request is stored by setting ItemTypeVirtualFileDownload
* in the database. This is necessary since the hydration is not driven by
* the pin state.
*
* relativepath is the folder-relative path to the file (including the extension)
*
* Note, passing directories is not supported. Files only.
*/
void implicitlyHydrateFile(const QString &relativepath);
/** Adds the path to the local discovery list
*
* A weaker version of slotNextSyncFullLocalDiscovery() that just
* schedules all parent and child items of the path for local
* discovery.
*/
void schedulePathForLocalDiscovery(const QString &relativePath);
/** Ensures that the next sync performs a full local discovery. */
void slotNextSyncFullLocalDiscovery();
2013-07-22 22:27:42 +04:00
private slots:
void slotSyncStarted();
void slotSyncFinished(bool);
2013-07-22 22:27:42 +04:00
/** Adds a error message that's not tied to a specific item.
*/
void slotSyncError(const QString &message, ErrorCategory category = ErrorCategory::Normal);
2017-05-17 11:55:42 +03:00
void slotTransmissionProgress(const ProgressInfo &pi);
void slotItemCompleted(const SyncFileItemPtr &);
void slotRunEtagJob();
void etagRetrieved(const QString &);
void etagRetrievedFromSyncEngine(const QString &);
void slotEmitFinishedDelayed();
void slotNewBigFolderDiscovered(const QString &, bool isExternal);
void slotLogPropagationStart();
/** Adds this folder to the list of scheduled folders in the
* FolderMan.
*/
void slotScheduleThisFolder();
/** Adjust sync result based on conflict data from IssuesWidget.
*
* This is pretty awkward, but IssuesWidget just keeps better track
* of conflicts across partial local discovery.
*/
void slotFolderConflicts(const QString &folder, const QStringList &conflictPaths);
/** Warn users if they create a file or folder that is selective-sync excluded */
void warnOnNewExcludedItem(const SyncJournalFileRecord &record, const QStringRef &path);
/** Warn users about an unreliable folder watcher */
void slotWatcherUnreliable(const QString &message);
/** Aborts any running sync and blocks it until hydration is finished.
*
* Hydration circumvents the regular SyncEngine and both mustn't be running
* at the same time.
*/
void slotHydrationStarts();
/** Unblocks normal sync operation */
void slotHydrationDone();
private:
void connectSyncRoot();
bool reloadExcludes();
void showSyncResultPopup();
2013-07-22 22:27:42 +04:00
void checkLocalPath();
void setSyncOptions();
enum LogStatus {
LogStatusRemove,
LogStatusRename,
LogStatusMove,
LogStatusNew,
LogStatusError,
LogStatusConflict,
LogStatusUpdated,
LogStatusFileLocked
};
2017-05-17 11:55:42 +03:00
void createGuiLog(const QString &filename, LogStatus status, int count,
const QString &renameTarget = QString());
void startVfs();
AccountStatePtr _accountState;
2015-04-24 11:18:33 +03:00
FolderDefinition _definition;
QString _canonicalLocalPath; // As returned with QFileInfo:canonicalFilePath. Always ends with "/"
2015-04-24 11:18:33 +03:00
2013-07-22 22:27:42 +04:00
SyncResult _syncResult;
QScopedPointer<SyncEngine> _engine;
QPointer<RequestEtagJob> _requestEtagJob;
2017-05-17 11:55:42 +03:00
QString _lastEtag;
2015-01-16 12:52:26 +03:00
QElapsedTimer _timeSinceLastSyncDone;
QElapsedTimer _timeSinceLastSyncStart;
QElapsedTimer _timeSinceLastFullLocalDiscovery;
std::chrono::milliseconds _lastSyncDuration;
2013-07-22 22:27:42 +04:00
/// The number of syncs that failed in a row.
/// Reset when a sync is successful.
2017-05-17 11:55:42 +03:00
int _consecutiveFailingSyncs;
2013-07-22 22:27:42 +04:00
/// The number of requested follow-up syncs.
/// Reset when no follow-up is requested.
2017-05-17 11:55:42 +03:00
int _consecutiveFollowUpSyncs;
mutable SyncJournalDb _journal;
QScopedPointer<SyncRunFileLog> _fileLog;
QTimer _scheduleSelfTimer;
/**
* When the same local path is synced to multiple accounts, only one
* of them can be stored in the settings in a way that's compatible
* with old clients that don't support it. This flag marks folders
* that shall be written in a backwards-compatible way, by being set
* on the *first* Folder instance that was configured for each local
* path.
*/
bool _saveBackwardsCompatible = false;
/** Whether the folder should be saved in that settings group
*
* If it was read from there it had virtual files enabled at some
* point and might still have db entries or suffix-virtual files even
* if they are disabled right now. This flag ensures folders that
* were in that group once never go back.
*/
bool _saveInFoldersWithPlaceholders = false;
/** Whether a vfs mode switch is pending
*
* When the user desires that vfs be switched on/off but it hasn't been
* executed yet (syncs are still running), some options should be hidden,
* disabled or different.
*/
bool _vfsOnOffPending = false;
/**
* Watches this folder's local directory for changes.
*
* Created by registerFolderWatcher(), triggers slotWatchedPathChanged()
*/
QScopedPointer<FolderWatcher> _folderWatcher;
/**
* Keeps track of locally dirty files so we can skip local discovery sometimes.
*/
QScopedPointer<LocalDiscoveryTracker> _localDiscoveryTracker;
/**
* The vfs mode instance (created by plugin) to use. Never null.
*/
QSharedPointer<Vfs> _vfs;
2011-02-17 02:21:45 +03:00
};
}
#endif