mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-24 05:55:59 +03:00
Merge branch 'master' into slideshow
This commit is contained in:
commit
e6f1d7632a
67 changed files with 39422 additions and 41851 deletions
12
.drone.yml
12
.drone.yml
|
@ -14,7 +14,7 @@ pipeline:
|
||||||
cd /tmp &&
|
cd /tmp &&
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||||
cd qtkeychain &&
|
cd qtkeychain &&
|
||||||
git checkout v0.8.0 &&
|
git checkout v0.9.1 &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake ../ &&
|
cmake ../ &&
|
||||||
|
@ -42,7 +42,7 @@ pipeline:
|
||||||
cd /tmp &&
|
cd /tmp &&
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||||
cd qtkeychain &&
|
cd qtkeychain &&
|
||||||
git checkout v0.8.0 &&
|
git checkout v0.9.1 &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake ../ &&
|
cmake ../ &&
|
||||||
|
@ -70,7 +70,7 @@ pipeline:
|
||||||
cd /tmp &&
|
cd /tmp &&
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||||
cd qtkeychain &&
|
cd qtkeychain &&
|
||||||
git checkout v0.8.0 &&
|
git checkout v0.9.1 &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake ../ &&
|
cmake ../ &&
|
||||||
|
@ -100,7 +100,7 @@ pipeline:
|
||||||
cd /tmp &&
|
cd /tmp &&
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||||
cd qtkeychain &&
|
cd qtkeychain &&
|
||||||
git checkout v0.8.0 &&
|
git checkout v0.9.1 &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake ../ &&
|
cmake ../ &&
|
||||||
|
@ -132,7 +132,7 @@ pipeline:
|
||||||
cd /tmp &&
|
cd /tmp &&
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||||
cd qtkeychain &&
|
cd qtkeychain &&
|
||||||
git checkout v0.8.0 &&
|
git checkout v0.9.1 &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake ../ &&
|
cmake ../ &&
|
||||||
|
@ -165,7 +165,7 @@ pipeline:
|
||||||
cd /tmp &&
|
cd /tmp &&
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||||
cd qtkeychain &&
|
cd qtkeychain &&
|
||||||
git checkout v0.8.0 &&
|
git checkout v0.9.1 &&
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake ../ &&
|
cmake ../ &&
|
||||||
|
|
|
@ -18,11 +18,11 @@ if [ $SUFFIX != "master" ]; then
|
||||||
SUFFIX="PR-$SUFFIX"
|
SUFFIX="PR-$SUFFIX"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#QtKeyChain 0.8.0
|
#QtKeyChain 0.9.1
|
||||||
cd /build
|
cd /build
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git
|
git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||||
cd qtkeychain
|
cd qtkeychain
|
||||||
git checkout v0.8.0
|
git checkout v0.9.1
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake -D CMAKE_INSTALL_PREFIX=/usr ../
|
cmake -D CMAKE_INSTALL_PREFIX=/usr ../
|
||||||
|
|
|
@ -272,10 +272,12 @@ bool FileSystem::openAndSeekFileSharedRead(QFile *file, QString *errorOrNull, qi
|
||||||
int fd = _open_osfhandle((intptr_t)fileHandle, _O_RDONLY);
|
int fd = _open_osfhandle((intptr_t)fileHandle, _O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
error = "could not make fd from handle";
|
error = "could not make fd from handle";
|
||||||
|
CloseHandle(fileHandle);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle)) {
|
if (!file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle)) {
|
||||||
error = file->errorString();
|
error = file->errorString();
|
||||||
|
_close(fd); // implicitly closes fileHandle
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -666,7 +666,21 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((dirent = csync_vio_readdir(ctx, dh))) {
|
while (true) {
|
||||||
|
// Get the next item in the directory
|
||||||
|
errno = 0;
|
||||||
|
dirent = csync_vio_readdir(ctx, dh);
|
||||||
|
if (!dirent) {
|
||||||
|
if (errno != 0) {
|
||||||
|
// Note: Windows vio converts any error into EACCES
|
||||||
|
qCWarning(lcUpdate, "readdir failed for file in %s - errno %d", uri, errno);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal case: End of items in directory
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Conversion error */
|
/* Conversion error */
|
||||||
if (dirent->path.isEmpty() && !dirent->original_path.isEmpty()) {
|
if (dirent->path.isEmpty() && !dirent->original_path.isEmpty()) {
|
||||||
ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS;
|
ctx->status_code = CSYNC_STATUS_INVALID_CHARACTERS;
|
||||||
|
|
|
@ -156,6 +156,7 @@ std::unique_ptr<csync_file_stat_t> csync_vio_local_readdir(csync_vio_handle_t *d
|
||||||
// might be error, check!
|
// might be error, check!
|
||||||
int dwError = GetLastError();
|
int dwError = GetLastError();
|
||||||
if (dwError != ERROR_NO_MORE_FILES) {
|
if (dwError != ERROR_NO_MORE_FILES) {
|
||||||
|
qCWarning(lcCSyncVIOLocal, "FindNextFile error %d", dwError);
|
||||||
errno = EACCES; // no more files is fine. Otherwise EACCESS
|
errno = EACCES; // no more files is fine. Otherwise EACCESS
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -53,6 +53,7 @@ set(client_SRCS
|
||||||
folderman.cpp
|
folderman.cpp
|
||||||
folderstatusmodel.cpp
|
folderstatusmodel.cpp
|
||||||
folderstatusdelegate.cpp
|
folderstatusdelegate.cpp
|
||||||
|
folderstatusview.cpp
|
||||||
folderwatcher.cpp
|
folderwatcher.cpp
|
||||||
folderwizard.cpp
|
folderwizard.cpp
|
||||||
generalsettings.cpp
|
generalsettings.cpp
|
||||||
|
|
|
@ -52,7 +52,7 @@ AccountManager *AccountManager::instance()
|
||||||
bool AccountManager::restore()
|
bool AccountManager::restore()
|
||||||
{
|
{
|
||||||
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
auto settings = ConfigFile::settingsWithGroup(QLatin1String(accountsC));
|
||||||
if (settings->status() != QSettings::NoError) {
|
if (settings->status() != QSettings::NoError || !settings->isWritable()) {
|
||||||
qCWarning(lcAccountManager) << "Could not read settings from" << settings->fileName()
|
qCWarning(lcAccountManager) << "Could not read settings from" << settings->fileName()
|
||||||
<< settings->status();
|
<< settings->status();
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -117,7 +117,7 @@
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QTreeView" name="_folderList">
|
<widget class="OCC::FolderStatusView" name="_folderList">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
|
@ -275,6 +275,11 @@
|
||||||
<extends>QToolButton</extends>
|
<extends>QToolButton</extends>
|
||||||
<header>sslbutton.h</header>
|
<header>sslbutton.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>OCC::FolderStatusView</class>
|
||||||
|
<extends>QTreeView</extends>
|
||||||
|
<header>folderstatusview.h</header>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|
|
@ -125,7 +125,8 @@ Application::Application(int &argc, char **argv)
|
||||||
setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
||||||
|
|
||||||
auto confDir = ConfigFile().configPath();
|
auto confDir = ConfigFile().configPath();
|
||||||
if (!QFileInfo(confDir).exists()) {
|
if (confDir.endsWith('/')) confDir.chop(1); // macOS 10.11.x does not like trailing slash for rename/move.
|
||||||
|
if (!QFileInfo(confDir).isDir()) {
|
||||||
// Migrate from version <= 2.4
|
// Migrate from version <= 2.4
|
||||||
setApplicationName(_theme->appNameGUI());
|
setApplicationName(_theme->appNameGUI());
|
||||||
#ifndef QT_WARNING_DISABLE_DEPRECATED // Was added in Qt 5.9
|
#ifndef QT_WARNING_DISABLE_DEPRECATED // Was added in Qt 5.9
|
||||||
|
@ -136,6 +137,7 @@ Application::Application(int &argc, char **argv)
|
||||||
// We need to use the deprecated QDesktopServices::storageLocation because of its Qt4
|
// We need to use the deprecated QDesktopServices::storageLocation because of its Qt4
|
||||||
// behavior of adding "data" to the path
|
// behavior of adding "data" to the path
|
||||||
QString oldDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
QString oldDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
|
||||||
|
if (oldDir.endsWith('/')) oldDir.chop(1); // macOS 10.11.x does not like trailing slash for rename/move.
|
||||||
QT_WARNING_POP
|
QT_WARNING_POP
|
||||||
setApplicationName(_theme->appName());
|
setApplicationName(_theme->appName());
|
||||||
if (QFileInfo(oldDir).isDir()) {
|
if (QFileInfo(oldDir).isDir()) {
|
||||||
|
|
|
@ -645,9 +645,13 @@ void Folder::startSync(const QStringList &pathList)
|
||||||
}
|
}
|
||||||
return interval;
|
return interval;
|
||||||
}();
|
}();
|
||||||
if (_folderWatcher && _folderWatcher->isReliable() && _timeSinceLastFullLocalDiscovery.isValid()
|
bool hasDoneFullLocalDiscovery = _timeSinceLastFullLocalDiscovery.isValid();
|
||||||
&& (fullLocalDiscoveryInterval.count() < 0
|
bool periodicFullLocalDiscoveryNow =
|
||||||
|| _timeSinceLastFullLocalDiscovery.hasExpired(fullLocalDiscoveryInterval.count()))) {
|
fullLocalDiscoveryInterval.count() >= 0 // negative means we don't require periodic full runs
|
||||||
|
&& _timeSinceLastFullLocalDiscovery.hasExpired(fullLocalDiscoveryInterval.count());
|
||||||
|
if (_folderWatcher && _folderWatcher->isReliable()
|
||||||
|
&& hasDoneFullLocalDiscovery
|
||||||
|
&& !periodicFullLocalDiscoveryNow) {
|
||||||
qCInfo(lcFolder) << "Allowing local discovery to read from the database";
|
qCInfo(lcFolder) << "Allowing local discovery to read from the database";
|
||||||
_engine->setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, _localDiscoveryPaths);
|
_engine->setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, _localDiscoveryPaths);
|
||||||
|
|
||||||
|
|
|
@ -1242,25 +1242,45 @@ QString FolderMan::trayTooltipStatusString(
|
||||||
return folderMessage;
|
return folderMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FolderMan::checkPathValidityForNewFolder(const QString &path, const QUrl &serverUrl, bool forNewDirectory) const
|
static QString checkPathValidityRecursive(const QString &path)
|
||||||
{
|
{
|
||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
return tr("No valid folder selected!");
|
return FolderMan::tr("No valid folder selected!");
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileInfo selFile(path);
|
QFileInfo selFile(path);
|
||||||
|
|
||||||
if (!selFile.exists()) {
|
if (!selFile.exists()) {
|
||||||
return checkPathValidityForNewFolder(selFile.dir().path(), serverUrl, true);
|
return checkPathValidityRecursive(selFile.dir().path());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!selFile.isDir()) {
|
if (!selFile.isDir()) {
|
||||||
return tr("The selected path is not a folder!");
|
return FolderMan::tr("The selected path is not a folder!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!selFile.isWritable()) {
|
if (!selFile.isWritable()) {
|
||||||
return tr("You have no permission to write to the selected folder!");
|
return FolderMan::tr("You have no permission to write to the selected folder!");
|
||||||
}
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// QFileInfo::canonicalPath returns an empty string if the file does not exist.
|
||||||
|
// This function also works with files that does not exist and resolve the symlinks in the
|
||||||
|
// parent directories.
|
||||||
|
static QString canonicalPath(const QString &path)
|
||||||
|
{
|
||||||
|
QFileInfo selFile(path);
|
||||||
|
if (!selFile.exists()) {
|
||||||
|
return canonicalPath(selFile.dir().path()) + '/' + selFile.fileName();
|
||||||
|
}
|
||||||
|
return selFile.canonicalFilePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FolderMan::checkPathValidityForNewFolder(const QString &path, const QUrl &serverUrl) const
|
||||||
|
{
|
||||||
|
QString recursiveValidity = checkPathValidityRecursive(path);
|
||||||
|
if (!recursiveValidity.isEmpty())
|
||||||
|
return recursiveValidity;
|
||||||
|
|
||||||
// check if the local directory isn't used yet in another ownCloud sync
|
// check if the local directory isn't used yet in another ownCloud sync
|
||||||
Qt::CaseSensitivity cs = Qt::CaseSensitive;
|
Qt::CaseSensitivity cs = Qt::CaseSensitive;
|
||||||
|
@ -1268,57 +1288,28 @@ QString FolderMan::checkPathValidityForNewFolder(const QString &path, const QUrl
|
||||||
cs = Qt::CaseInsensitive;
|
cs = Qt::CaseInsensitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString userDir = QDir::cleanPath(canonicalPath(path)) + '/';
|
||||||
for (auto i = _folderMap.constBegin(); i != _folderMap.constEnd(); ++i) {
|
for (auto i = _folderMap.constBegin(); i != _folderMap.constEnd(); ++i) {
|
||||||
Folder *f = static_cast<Folder *>(i.value());
|
Folder *f = static_cast<Folder *>(i.value());
|
||||||
QString folderDir = QDir(f->path()).canonicalPath();
|
QString folderDir = QDir::cleanPath(canonicalPath(f->path())) + '/';
|
||||||
if (folderDir.isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!folderDir.endsWith(QLatin1Char('/'), cs))
|
|
||||||
folderDir.append(QLatin1Char('/'));
|
|
||||||
|
|
||||||
const QString folderDirClean = QDir::cleanPath(folderDir) + '/';
|
bool differentPaths = QString::compare(folderDir, userDir, cs) != 0;
|
||||||
const QString userDirClean = QDir::cleanPath(path) + '/';
|
if (differentPaths && folderDir.startsWith(userDir, cs)) {
|
||||||
|
|
||||||
// folderDir follows sym links, path not.
|
|
||||||
bool differentPathes = !Utility::fileNamesEqual(QDir::cleanPath(folderDir), QDir::cleanPath(path));
|
|
||||||
|
|
||||||
if (!forNewDirectory && differentPathes && folderDirClean.startsWith(userDirClean, cs)) {
|
|
||||||
return tr("The local folder %1 already contains a folder used in a folder sync connection. "
|
return tr("The local folder %1 already contains a folder used in a folder sync connection. "
|
||||||
"Please pick another one!")
|
"Please pick another one!")
|
||||||
.arg(QDir::toNativeSeparators(path));
|
.arg(QDir::toNativeSeparators(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// QDir::cleanPath keeps links
|
if (differentPaths && userDir.startsWith(folderDir, cs)) {
|
||||||
// canonicalPath() remove symlinks and uses the symlink targets.
|
|
||||||
QString absCleanUserFolder = QDir::cleanPath(QDir(path).canonicalPath()) + '/';
|
|
||||||
|
|
||||||
if ((forNewDirectory || differentPathes) && userDirClean.startsWith(folderDirClean, cs)) {
|
|
||||||
return tr("The local folder %1 is already contained in a folder used in a folder sync connection. "
|
return tr("The local folder %1 is already contained in a folder used in a folder sync connection. "
|
||||||
"Please pick another one!")
|
"Please pick another one!")
|
||||||
.arg(QDir::toNativeSeparators(path));
|
.arg(QDir::toNativeSeparators(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// both follow symlinks.
|
|
||||||
bool cleanUserEqualsCleanFolder = Utility::fileNamesEqual(absCleanUserFolder, folderDirClean);
|
|
||||||
if (differentPathes && absCleanUserFolder.startsWith(folderDirClean, cs) && !cleanUserEqualsCleanFolder) {
|
|
||||||
return tr("The local folder %1 is a symbolic link. "
|
|
||||||
"The link target is already contained in a folder used in a folder sync connection. "
|
|
||||||
"Please pick another one!")
|
|
||||||
.arg(QDir::toNativeSeparators(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (differentPathes && folderDirClean.startsWith(absCleanUserFolder, cs) && !cleanUserEqualsCleanFolder && !forNewDirectory) {
|
|
||||||
return tr("The local folder %1 contains a symbolic link. "
|
|
||||||
"The link target contains an already synced folder. "
|
|
||||||
"Please pick another one!")
|
|
||||||
.arg(QDir::toNativeSeparators(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
// if both pathes are equal, the server url needs to be different
|
// if both pathes are equal, the server url needs to be different
|
||||||
// otherwise it would mean that a new connection from the same local folder
|
// otherwise it would mean that a new connection from the same local folder
|
||||||
// to the same account is added which is not wanted. The account must differ.
|
// to the same account is added which is not wanted. The account must differ.
|
||||||
if (serverUrl.isValid() && Utility::fileNamesEqual(absCleanUserFolder, folderDir)) {
|
if (serverUrl.isValid() && !differentPaths) {
|
||||||
QUrl folderUrl = f->accountState()->account()->url();
|
QUrl folderUrl = f->accountState()->account()->url();
|
||||||
QString user = f->accountState()->account()->credentials()->user();
|
QString user = f->accountState()->account()->credentials()->user();
|
||||||
folderUrl.setUserName(user);
|
folderUrl.setUserName(user);
|
||||||
|
|
|
@ -127,11 +127,9 @@ public:
|
||||||
*
|
*
|
||||||
* Note that different accounts are allowed to sync to the same folder.
|
* Note that different accounts are allowed to sync to the same folder.
|
||||||
*
|
*
|
||||||
* \a forNewDirectory is internal and is used for recursion.
|
|
||||||
*
|
|
||||||
* @returns an empty string if it is allowed, or an error if it is not allowed
|
* @returns an empty string if it is allowed, or an error if it is not allowed
|
||||||
*/
|
*/
|
||||||
QString checkPathValidityForNewFolder(const QString &path, const QUrl &serverUrl = QUrl(), bool forNewDirectory = false) const;
|
QString checkPathValidityForNewFolder(const QString &path, const QUrl &serverUrl = QUrl()) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to find a non-existing, acceptable path for creating a new sync folder.
|
* Attempts to find a non-existing, acceptable path for creating a new sync folder.
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "folderstatusdelegate.h"
|
#include "folderstatusdelegate.h"
|
||||||
#include "folderstatusmodel.h"
|
#include "folderstatusmodel.h"
|
||||||
|
#include "folderstatusview.h"
|
||||||
#include "folderman.h"
|
#include "folderman.h"
|
||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
#include <theme.h>
|
#include <theme.h>
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
#include <QFileIconProvider>
|
#include <QFileIconProvider>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
inline static QFont makeAliasFont(const QFont &normalFont)
|
inline static QFont makeAliasFont(const QFont &normalFont)
|
||||||
{
|
{
|
||||||
|
@ -110,6 +112,10 @@ int FolderStatusDelegate::rootFolderHeightWithoutErrors(const QFontMetrics &fm,
|
||||||
void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
|
if (index.data(AddButton).toBool()) {
|
||||||
|
const_cast<QStyleOptionViewItem &>(option).showDecorationSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
QStyledItemDelegate::paint(painter, option, index);
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
|
||||||
auto textAlign = Qt::AlignLeft;
|
auto textAlign = Qt::AlignLeft;
|
||||||
|
@ -129,15 +135,15 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||||
int margin = subFm.height() / 4;
|
int margin = subFm.height() / 4;
|
||||||
|
|
||||||
if (index.data(AddButton).toBool()) {
|
if (index.data(AddButton).toBool()) {
|
||||||
QSize hint = sizeHint(option, index);
|
|
||||||
QStyleOptionButton opt;
|
QStyleOptionButton opt;
|
||||||
static_cast<QStyleOption &>(opt) = option;
|
static_cast<QStyleOption &>(opt) = option;
|
||||||
opt.state &= ~QStyle::State_Selected;
|
if (opt.state & QStyle::State_Enabled && opt.state & QStyle::State_MouseOver && index == _pressedIndex) {
|
||||||
opt.state |= QStyle::State_Raised;
|
opt.state |= QStyle::State_Sunken;
|
||||||
|
} else {
|
||||||
|
opt.state |= QStyle::State_Raised;
|
||||||
|
}
|
||||||
opt.text = addFolderText();
|
opt.text = addFolderText();
|
||||||
opt.rect.setWidth(qMin(opt.rect.width(), hint.width()));
|
opt.rect = addButtonRect(option.rect, option.direction);
|
||||||
opt.rect.adjust(0, aliasMargin, 0, -aliasMargin);
|
|
||||||
opt.rect = QStyle::visualRect(option.direction, option.rect, opt.rect);
|
|
||||||
painter->save();
|
painter->save();
|
||||||
painter->setFont(qApp->font("QPushButton"));
|
painter->setFont(qApp->font("QPushButton"));
|
||||||
QApplication::style()->drawControl(QStyle::CE_PushButton, &opt, painter, option.widget);
|
QApplication::style()->drawControl(QStyle::CE_PushButton, &opt, painter, option.widget);
|
||||||
|
@ -352,6 +358,27 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
||||||
bool FolderStatusDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
bool FolderStatusDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||||
const QStyleOptionViewItem &option, const QModelIndex &index)
|
const QStyleOptionViewItem &option, const QModelIndex &index)
|
||||||
{
|
{
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::MouseButtonPress:
|
||||||
|
case QEvent::MouseMove:
|
||||||
|
if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(option.widget)) {
|
||||||
|
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
||||||
|
QModelIndex index;
|
||||||
|
if (me->buttons()) {
|
||||||
|
index = view->indexAt(me->pos());
|
||||||
|
}
|
||||||
|
if (_pressedIndex != index) {
|
||||||
|
_pressedIndex = index;
|
||||||
|
view->viewport()->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QEvent::MouseButtonRelease:
|
||||||
|
_pressedIndex = QModelIndex();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return QStyledItemDelegate::editorEvent(event, model, option, index);
|
return QStyledItemDelegate::editorEvent(event, model, option, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,6 +402,16 @@ QRect FolderStatusDelegate::optionsButtonRect(QRect within, Qt::LayoutDirection
|
||||||
return QStyle::visualRect(direction, within, r);
|
return QStyle::visualRect(direction, within, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRect FolderStatusDelegate::addButtonRect(QRect within, Qt::LayoutDirection direction)
|
||||||
|
{
|
||||||
|
QFontMetrics fm(qApp->font("QPushButton"));
|
||||||
|
QStyleOptionButton opt;
|
||||||
|
opt.text = addFolderText();
|
||||||
|
QSize size = QApplication::style()->sizeFromContents(QStyle::CT_PushButton, &opt, fm.size(Qt::TextSingleLine, opt.text)).expandedTo(QApplication::globalStrut());
|
||||||
|
QRect r(QPoint(within.left(), within.top() + within.height() / 2 - size.height() / 2), size);
|
||||||
|
return QStyle::visualRect(direction, within, r);
|
||||||
|
}
|
||||||
|
|
||||||
QRect FolderStatusDelegate::errorsListRect(QRect within)
|
QRect FolderStatusDelegate::errorsListRect(QRect within)
|
||||||
{
|
{
|
||||||
QFont font = QFont();
|
QFont font = QFont();
|
||||||
|
|
|
@ -57,11 +57,13 @@ public:
|
||||||
* return the position of the option button within the item
|
* return the position of the option button within the item
|
||||||
*/
|
*/
|
||||||
static QRect optionsButtonRect(QRect within, Qt::LayoutDirection direction);
|
static QRect optionsButtonRect(QRect within, Qt::LayoutDirection direction);
|
||||||
|
static QRect addButtonRect(QRect within, Qt::LayoutDirection direction);
|
||||||
static QRect errorsListRect(QRect within);
|
static QRect errorsListRect(QRect within);
|
||||||
static int rootFolderHeightWithoutErrors(const QFontMetrics &fm, const QFontMetrics &aliasFm);
|
static int rootFolderHeightWithoutErrors(const QFontMetrics &fm, const QFontMetrics &aliasFm);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QString addFolderText();
|
static QString addFolderText();
|
||||||
|
QPersistentModelIndex _pressedIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|
42
src/gui/folderstatusview.cpp
Normal file
42
src/gui/folderstatusview.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 by J-P Nurmi <jpnurmi@gmail.com>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "folderstatusview.h"
|
||||||
|
#include "folderstatusdelegate.h"
|
||||||
|
|
||||||
|
namespace OCC {
|
||||||
|
|
||||||
|
FolderStatusView::FolderStatusView(QWidget *parent) : QTreeView(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex FolderStatusView::indexAt(const QPoint &point) const
|
||||||
|
{
|
||||||
|
QModelIndex index = QTreeView::indexAt(point);
|
||||||
|
if (index.data(FolderStatusDelegate::AddButton).toBool() && !visualRect(index).contains(point)) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect FolderStatusView::visualRect(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QRect rect = QTreeView::visualRect(index);
|
||||||
|
if (index.data(FolderStatusDelegate::AddButton).toBool()) {
|
||||||
|
return FolderStatusDelegate::addButtonRect(rect, layoutDirection());
|
||||||
|
}
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace OCC
|
39
src/gui/folderstatusview.h
Normal file
39
src/gui/folderstatusview.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 by J-P Nurmi <jpnurmi@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FOLDERSTATUSVIEW_H
|
||||||
|
#define FOLDERSTATUSVIEW_H
|
||||||
|
|
||||||
|
#include <QTreeView>
|
||||||
|
|
||||||
|
namespace OCC {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The FolderStatusView class
|
||||||
|
* @ingroup gui
|
||||||
|
*/
|
||||||
|
class FolderStatusView : public QTreeView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FolderStatusView(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
QModelIndex indexAt(const QPoint &point) const override;
|
||||||
|
QRect visualRect(const QModelIndex &index) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace OCC
|
||||||
|
|
||||||
|
#endif // FOLDERSTATUSVIEW_H
|
|
@ -66,8 +66,10 @@ FolderWizardLocalPath::FolderWizardLocalPath(const AccountPtr &account)
|
||||||
connect(_ui.localFolderChooseBtn, &QAbstractButton::clicked, this, &FolderWizardLocalPath::slotChooseLocalFolder);
|
connect(_ui.localFolderChooseBtn, &QAbstractButton::clicked, this, &FolderWizardLocalPath::slotChooseLocalFolder);
|
||||||
_ui.localFolderChooseBtn->setToolTip(tr("Click to select a local folder to sync."));
|
_ui.localFolderChooseBtn->setToolTip(tr("Click to select a local folder to sync."));
|
||||||
|
|
||||||
|
QUrl serverUrl = _account->url();
|
||||||
|
serverUrl.setUserName(_account->credentials()->user());
|
||||||
QString defaultPath = QDir::homePath() + QLatin1Char('/') + Theme::instance()->appName();
|
QString defaultPath = QDir::homePath() + QLatin1Char('/') + Theme::instance()->appName();
|
||||||
defaultPath = FolderMan::instance()->findGoodPathForNewSyncFolder(defaultPath, account->url());
|
defaultPath = FolderMan::instance()->findGoodPathForNewSyncFolder(defaultPath, serverUrl);
|
||||||
_ui.localFolderLineEdit->setText(QDir::toNativeSeparators(defaultPath));
|
_ui.localFolderLineEdit->setText(QDir::toNativeSeparators(defaultPath));
|
||||||
_ui.localFolderLineEdit->setToolTip(tr("Enter the path to the local folder."));
|
_ui.localFolderLineEdit->setToolTip(tr("Enter the path to the local folder."));
|
||||||
|
|
||||||
|
|
|
@ -631,7 +631,7 @@ void ShareUserLine::displayPermissions()
|
||||||
|
|
||||||
// edit is independent of reshare
|
// edit is independent of reshare
|
||||||
if (perm & SharePermissionShare)
|
if (perm & SharePermissionShare)
|
||||||
_permissionReshare->setChecked(Qt::Checked);
|
_permissionReshare->setChecked(true);
|
||||||
|
|
||||||
if(!_isFile){
|
if(!_isFile){
|
||||||
_permissionCreate->setChecked(perm & SharePermissionCreate);
|
_permissionCreate->setChecked(perm & SharePermissionCreate);
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QClipboard>
|
||||||
|
|
||||||
#include "wizard/owncloudoauthcredspage.h"
|
#include "wizard/owncloudoauthcredspage.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
|
@ -48,6 +50,16 @@ OwncloudOAuthCredsPage::OwncloudOAuthCredsPage()
|
||||||
if (_asyncAuth)
|
if (_asyncAuth)
|
||||||
_asyncAuth->openBrowser();
|
_asyncAuth->openBrowser();
|
||||||
});
|
});
|
||||||
|
_ui.openLinkButton->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
QObject::connect(_ui.openLinkButton, &QWidget::customContextMenuRequested, [this](const QPoint &pos) {
|
||||||
|
auto menu = new QMenu(_ui.openLinkButton);
|
||||||
|
menu->addAction(tr("Copy link to clipboard"), this, [this] {
|
||||||
|
if (_asyncAuth)
|
||||||
|
QApplication::clipboard()->setText(_asyncAuth->authorisationLink().toString(QUrl::FullyEncoded));
|
||||||
|
});
|
||||||
|
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
menu->popup(_ui.openLinkButton->mapToGlobal(pos));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void OwncloudOAuthCredsPage::initializePage()
|
void OwncloudOAuthCredsPage::initializePage()
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QPropertyAnimation>
|
#include <QPropertyAnimation>
|
||||||
#include <QGraphicsPixmapItem>
|
#include <QGraphicsPixmapItem>
|
||||||
#include <QtSvg/QSvgRenderer>
|
|
||||||
|
|
||||||
#include "QProgressIndicator.h"
|
#include "QProgressIndicator.h"
|
||||||
|
|
||||||
|
@ -278,12 +277,19 @@ QString OwncloudSetupPage::url() const
|
||||||
bool OwncloudSetupPage::validatePage()
|
bool OwncloudSetupPage::validatePage()
|
||||||
{
|
{
|
||||||
if (!_authTypeKnown) {
|
if (!_authTypeKnown) {
|
||||||
|
QString u = url();
|
||||||
|
QUrl qurl(u);
|
||||||
|
if (!qurl.isValid() || qurl.host().isEmpty()) {
|
||||||
|
setErrorString(tr("Invalid URL"), false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
setErrorString(QString(), false);
|
setErrorString(QString(), false);
|
||||||
_checking = true;
|
_checking = true;
|
||||||
startSpinner();
|
startSpinner();
|
||||||
emit completeChanged();
|
emit completeChanged();
|
||||||
|
|
||||||
emit determineAuthType(url());
|
emit determineAuthType(u);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// connecting is running
|
// connecting is running
|
||||||
|
|
|
@ -41,6 +41,13 @@ class WebEnginePage : public QWebEnginePage {
|
||||||
public:
|
public:
|
||||||
WebEnginePage(QWebEngineProfile *profile, QObject* parent = nullptr);
|
WebEnginePage(QWebEngineProfile *profile, QObject* parent = nullptr);
|
||||||
QWebEnginePage * createWindow(QWebEnginePage::WebWindowType type) override;
|
QWebEnginePage * createWindow(QWebEnginePage::WebWindowType type) override;
|
||||||
|
void setUrl(const QUrl &url);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool certificateError(const QWebEngineCertificateError &certificateError) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QUrl _rootUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need a separate class here, since we cannot simply return the same WebEnginePage object
|
// We need a separate class here, since we cannot simply return the same WebEnginePage object
|
||||||
|
@ -146,6 +153,19 @@ QWebEnginePage * WebEnginePage::createWindow(QWebEnginePage::WebWindowType type)
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebEnginePage::setUrl(const QUrl &url) {
|
||||||
|
QWebEnginePage::setUrl(url);
|
||||||
|
_rootUrl = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebEnginePage::certificateError(const QWebEngineCertificateError &certificateError) {
|
||||||
|
if (certificateError.error() == QWebEngineCertificateError::CertificateAuthorityInvalid) {
|
||||||
|
return certificateError.url().host() == _rootUrl.host();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWebEnginePage(profile, parent) {
|
ExternalWebEnginePage::ExternalWebEnginePage(QWebEngineProfile *profile, QObject* parent) : QWebEnginePage(profile, parent) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,11 +379,12 @@ bool HttpCredentials::refreshAccessToken()
|
||||||
QJsonParseError jsonParseError;
|
QJsonParseError jsonParseError;
|
||||||
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
|
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
|
||||||
QString accessToken = json["access_token"].toString();
|
QString accessToken = json["access_token"].toString();
|
||||||
if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError || json.isEmpty()) {
|
if (jsonParseError.error != QJsonParseError::NoError || json.isEmpty()) {
|
||||||
// Network error maybe?
|
// Invalid or empty JSON: Network error maybe?
|
||||||
qCWarning(lcHttpCredentials) << "Error while refreshing the token" << reply->errorString() << jsonData << jsonParseError.errorString();
|
qCWarning(lcHttpCredentials) << "Error while refreshing the token" << reply->errorString() << jsonData << jsonParseError.errorString();
|
||||||
} else if (accessToken.isEmpty()) {
|
} else if (accessToken.isEmpty()) {
|
||||||
// The token is no longer valid.
|
// If the json was valid, but the reply did not contain an access token, the token
|
||||||
|
// is considered expired. (Usually the HTTP reply code is 400)
|
||||||
qCDebug(lcHttpCredentials) << "Expired refresh token. Logging out";
|
qCDebug(lcHttpCredentials) << "Expired refresh token. Logging out";
|
||||||
_refreshToken.clear();
|
_refreshToken.clear();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -381,13 +381,11 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
|
||||||
std::unique_ptr<csync_file_stat_t> file_stat(new csync_file_stat_t);
|
std::unique_ptr<csync_file_stat_t> file_stat(new csync_file_stat_t);
|
||||||
file_stat->path = file.toUtf8();
|
file_stat->path = file.toUtf8();
|
||||||
file_stat->size = -1;
|
file_stat->size = -1;
|
||||||
file_stat->modtime = -1;
|
|
||||||
propertyMapToFileStat(map, file_stat.get());
|
propertyMapToFileStat(map, file_stat.get());
|
||||||
if (file_stat->type == ItemTypeDirectory)
|
if (file_stat->type == ItemTypeDirectory)
|
||||||
file_stat->size = 0;
|
file_stat->size = 0;
|
||||||
if (file_stat->type == ItemTypeSkip
|
if (file_stat->type == ItemTypeSkip
|
||||||
|| file_stat->size == -1
|
|| file_stat->size == -1
|
||||||
|| file_stat->modtime == -1
|
|
||||||
|| file_stat->remotePerm.isNull()
|
|| file_stat->remotePerm.isNull()
|
||||||
|| file_stat->etag.isEmpty()
|
|| file_stat->etag.isEmpty()
|
||||||
|| file_stat->file_id.isEmpty()) {
|
|| file_stat->file_id.isEmpty()) {
|
||||||
|
|
|
@ -338,7 +338,8 @@ QString Theme::about() const
|
||||||
.arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
|
.arg("http://" MIRALL_STRINGIFY(APPLICATION_DOMAIN))
|
||||||
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN));
|
.arg(MIRALL_STRINGIFY(APPLICATION_DOMAIN));
|
||||||
|
|
||||||
devString += tr("<p>This release was supplied by the Nextcloud GmbH</p>");
|
devString += tr("<p>This release was supplied by %1</p>")
|
||||||
|
.arg(APPLICATION_VENDOR);
|
||||||
|
|
||||||
devString += gitSHA1();
|
devString += gitSHA1();
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,12 @@ private slots:
|
||||||
|
|
||||||
// Invalid paths
|
// Invalid paths
|
||||||
QVERIFY(!folderman->checkPathValidityForNewFolder("").isNull());
|
QVERIFY(!folderman->checkPathValidityForNewFolder("").isNull());
|
||||||
|
|
||||||
|
|
||||||
|
// REMOVE ownCloud2 from the filesystem, but keep a folder sync'ed to it.
|
||||||
|
QDir(dirPath + "/ownCloud2/").removeRecursively();
|
||||||
|
QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + "/ownCloud2/blublu").isNull());
|
||||||
|
QVERIFY(!folderman->checkPathValidityForNewFolder(dirPath + "/ownCloud2/sub/subsub/sub").isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
void testFindGoodPathForNewSyncFolder()
|
void testFindGoodPathForNewSyncFolder()
|
||||||
|
@ -169,6 +175,7 @@ private slots:
|
||||||
HttpCredentialsTest *cred = new HttpCredentialsTest("testuser", "secret");
|
HttpCredentialsTest *cred = new HttpCredentialsTest("testuser", "secret");
|
||||||
account->setCredentials(cred);
|
account->setCredentials(cred);
|
||||||
account->setUrl( url );
|
account->setUrl( url );
|
||||||
|
url.setUserName(cred->user());
|
||||||
|
|
||||||
AccountStatePtr newAccountState(new AccountState(account));
|
AccountStatePtr newAccountState(new AccountState(account));
|
||||||
FolderMan *folderman = FolderMan::instance();
|
FolderMan *folderman = FolderMan::instance();
|
||||||
|
@ -190,6 +197,14 @@ private slots:
|
||||||
QString(dirPath + "/ownCloud2/bar"));
|
QString(dirPath + "/ownCloud2/bar"));
|
||||||
QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath + "/sub", url),
|
QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath + "/sub", url),
|
||||||
QString(dirPath + "/sub2"));
|
QString(dirPath + "/sub2"));
|
||||||
|
|
||||||
|
// REMOVE ownCloud2 from the filesystem, but keep a folder sync'ed to it.
|
||||||
|
// We should still not suggest this folder as a new folder.
|
||||||
|
QDir(dirPath + "/ownCloud2/").removeRecursively();
|
||||||
|
QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath + "/ownCloud", url),
|
||||||
|
QString(dirPath + "/ownCloud3"));
|
||||||
|
QCOMPARE(folderman->findGoodPathForNewSyncFolder(dirPath + "/ownCloud2", url),
|
||||||
|
QString(dirPath + "/ownCloud22"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ signals:
|
||||||
void hooked(const QUrl &);
|
void hooked(const QUrl &);
|
||||||
public:
|
public:
|
||||||
DesktopServiceHook() { QDesktopServices::setUrlHandler("oauthtest", this, "hooked"); }
|
DesktopServiceHook() { QDesktopServices::setUrlHandler("oauthtest", this, "hooked"); }
|
||||||
} desktopServiceHook;
|
};
|
||||||
|
|
||||||
static const QUrl sOAuthTestServer("oauthtest://someserver/owncloud");
|
static const QUrl sOAuthTestServer("oauthtest://someserver/owncloud");
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ public:
|
||||||
class OAuthTestCase : public QObject
|
class OAuthTestCase : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
DesktopServiceHook desktopServiceHook;
|
||||||
public:
|
public:
|
||||||
enum State { StartState, BrowserOpened, TokenAsked, CustomState } state = StartState;
|
enum State { StartState, BrowserOpened, TokenAsked, CustomState } state = StartState;
|
||||||
Q_ENUM(State);
|
Q_ENUM(State);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue