Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement import of WebDAV folders #5914

Merged
merged 43 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
698e123
Add a qtwebdav vcpkg port
nirvn Dec 25, 2024
9d331aa
Rely on modernized qtwebdav cmake configuration
nirvn Dec 25, 2024
dc0c5ec
Make better sense of application vs app data directories on windows/l…
nirvn Jan 3, 2025
065a2f2
wip
nirvn Jan 3, 2025
fabb9c1
Implement a webdav connection object, add paths fetching functionality
nirvn Jan 4, 2025
6f8d0fb
Implement import webdav folder functionality
nirvn Jan 4, 2025
c389566
Implement blocking progress overlay when importing webdav folder
nirvn Jan 4, 2025
44bea2b
Basic error handling by throwing toasters
nirvn Jan 4, 2025
0ce4154
More error handling, avoid showing root directory when wrong user/pas…
nirvn Jan 4, 2025
affbefe
Clear access authentication cache when changing user/password
nirvn Jan 4, 2025
361eb99
Implement mechanism to remember password across sessions
nirvn Jan 4, 2025
f494a33
Harmonize QfTextField with generic Material input items
nirvn Jan 4, 2025
78413a9
Add missing qtwebdav patch
nirvn Jan 4, 2025
99b6e5f
Further tweak
nirvn Jan 4, 2025
db687bc
Remove qDebug() crumbs
nirvn Jan 4, 2025
947c073
Use raw material text fields within dialogs, it just looks more immer…
nirvn Jan 4, 2025
fb7d4ad
Further tiny tweaks to QfTextField
nirvn Jan 4, 2025
9cee854
Update QtWebDAV to see if it fixes windows builds
nirvn Jan 5, 2025
58851aa
Add a qfield_webdav_settings.json file when importing folder
nirvn Jan 5, 2025
f591173
Implement webdav configuration awareness into the local files model
nirvn Jan 5, 2025
e8ef676
Fix item/folder deletion permission
nirvn Jan 5, 2025
2c1e82c
Attach last modified date value to imported files
nirvn Jan 5, 2025
275f820
Implement download from webdav folder functionality
nirvn Jan 5, 2025
c39f2be
Implement upload to webdav folder funcationality
nirvn Jan 5, 2025
fdab399
Insure paths exists remotely prior to uploading files
nirvn Jan 5, 2025
906a3f3
Silence the flood of debug info
nirvn Jan 5, 2025
81951fe
Have uploaded files adapt their last modified to match server to avoi…
nirvn Jan 5, 2025
2adb4ab
Implement non-stored webdav download/upload
nirvn Jan 5, 2025
84c4e8a
Cleanup QtWebDAV port by updating to 2.1
nirvn Jan 5, 2025
3d03800
Relocate the component into the loader
nirvn Jan 5, 2025
8da7814
Implement a webdav upload/download of project content
nirvn Jan 5, 2025
ea5772d
Remove some ... when not relevant
nirvn Jan 5, 2025
a43e1c9
Let's be conservative and ask for people to confirm download/upload o…
nirvn Jan 5, 2025
4527232
Papercut fix: open the imported webdav folder when finished for a muc…
nirvn Jan 10, 2025
13796a4
Add a refresh folders button within the import webdav folder dialog
nirvn Jan 11, 2025
8607ed7
Add a show pasword button in the import webdav folder and download/up…
nirvn Jan 11, 2025
8acf564
Only show favorites that exists, sort them by display name
nirvn Jan 11, 2025
5e3e612
Avoid complex showing/hiding panels, just stack them properly
nirvn Jan 11, 2025
5ea14b4
Another tiny focus stack fix
nirvn Jan 11, 2025
a6f50b3
Remove last qDebug() call
nirvn Jan 11, 2025
7448bc3
Fix rebase gone wrong
nirvn Jan 12, 2025
492feaa
Fix main menu location when opening from dashboard
nirvn Jan 13, 2025
e4cfc09
Fix missing translation string
nirvn Jan 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ set(QFIELD_CORE_SRCS
valuemapmodel.cpp
valuemapmodelbase.cpp
vertexmodel.cpp
viewstatus.cpp)
viewstatus.cpp
webdavconnection.cpp)

set(QFIELD_CORE_HDRS
platforms/platformutilities.h
Expand Down Expand Up @@ -244,6 +245,7 @@ set(QFIELD_CORE_HDRS
valuemapmodelbase.h
vertexmodel.h
viewstatus.h
webdavconnection.h
${CMAKE_CURRENT_BINARY_DIR}/qfield.h)

list(APPEND QFIELD_CORE_SRCS permissions.cpp)
Expand Down Expand Up @@ -288,6 +290,7 @@ endif()

find_package(SQLite3 REQUIRED)
find_package(ZXing REQUIRED)
find_package(QtWebDAV REQUIRED)

add_library(qfield_core STATIC ${QFIELD_CORE_SRCS} ${QFIELD_CORE_HDRS})

Expand Down Expand Up @@ -367,7 +370,8 @@ target_link_libraries(
GDAL::GDAL
SQLite::SQLite3
Qca::qca
libzip::zip)
libzip::zip
QtWebDAV::QtWebDAV)

if(WITH_BLUETOOTH)
find_package(
Expand Down
1 change: 1 addition & 0 deletions src/core/focusstack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ void FocusStack::setFocused( QObject *object )
{
mStackList.removeAll( object );
mStackList.append( object );
QMetaObject::invokeMethod( object, "forceActiveFocus", Qt::DirectConnection );
}

void FocusStack::setUnfocused( QObject *object )
Expand Down
20 changes: 17 additions & 3 deletions src/core/localfilesmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "platformutilities.h"
#include "qfieldcloudutils.h"
#include "qgismobileapp.h"
#include "webdavconnection.h"

#include <QDir>
#include <QFile>
Expand Down Expand Up @@ -59,6 +60,7 @@ QHash<int, QByteArray> LocalFilesModel::roleNames() const
roles[ItemSizeRole] = "ItemSize";
roles[ItemHasThumbnailRole] = "ItemHasThumbnail";
roles[ItemIsFavoriteRole] = "ItemIsFavorite";
roles[ItemHasWebdavConfigurationRole] = "ItemHasWebdavConfiguration";
return roles;
}

Expand Down Expand Up @@ -177,14 +179,14 @@ bool LocalFilesModel::isDeletedAllowedInCurrentPath() const
{
const QString path = currentPath();
const QString applicationDirectory = PlatformUtilities::instance()->applicationDirectory();
if ( !applicationDirectory.isEmpty() && path.startsWith( applicationDirectory + QDir::separator() ) )
if ( !applicationDirectory.isEmpty() && path.startsWith( applicationDirectory ) )
{
return true;
}
else
{
const QStringList additionalApplicationDirectories = PlatformUtilities::instance()->additionalApplicationDirectories();
if ( std::any_of( additionalApplicationDirectories.begin(), additionalApplicationDirectories.end(), [&path]( const QString &directory ) { return ( !directory.isEmpty() && path.startsWith( directory + QDir::separator() ) ); } ) )
if ( std::any_of( additionalApplicationDirectories.begin(), additionalApplicationDirectories.end(), [&path]( const QString &directory ) { return ( !directory.isEmpty() && path.startsWith( directory ) ); } ) )
{
return true;
}
Expand Down Expand Up @@ -237,10 +239,17 @@ void LocalFilesModel::reloadModel()
}

const QStringList favorites = QSettings().value( QStringLiteral( "qfieldFavorites" ), QStringList() ).toStringList();
QList<Item> favoriteItems;
for ( const QString &item : favorites )
{
mItems << Item( ItemMetaType::Favorite, ItemType::SimpleFolder, getCurrentTitleFromPath( item ), QString(), item );
if ( QFileInfo::exists( item ) )
{
favoriteItems << Item( ItemMetaType::Favorite, ItemType::SimpleFolder, getCurrentTitleFromPath( item ), QString(), item );
}
}

std::sort( favoriteItems.begin(), favoriteItems.end(), []( const Item &a, const Item &b ) { return a.title < b.title; } );
mItems.append( favoriteItems );
}
else
{
Expand Down Expand Up @@ -332,6 +341,11 @@ QVariant LocalFilesModel::data( const QModelIndex &index, int role ) const

case ItemIsFavoriteRole:
return mFavorites.contains( mItems[index.row()].path );

case ItemHasWebdavConfigurationRole:
{
return WebdavConnection::hasWebdavConfiguration( mItems[index.row()].path );
}
}

return QVariant();
Expand Down
1 change: 1 addition & 0 deletions src/core/localfilesmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ class LocalFilesModel : public QAbstractListModel
ItemSizeRole,
ItemHasThumbnailRole,
ItemIsFavoriteRole,
ItemHasWebdavConfigurationRole,
};
Q_ENUM( Role )

Expand Down
37 changes: 27 additions & 10 deletions src/core/platforms/platformutilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <QMargins>
#include <QQuickWindow>
#include <QStandardPaths>
#include <QStorageInfo>
#include <QTimer>
#include <QUrl>
#include <QtGui/qpa/qplatformwindow.h>
Expand Down Expand Up @@ -97,14 +98,18 @@ void PlatformUtilities::afterUpdate()
const QStringList dirs = appDataDirs();
for ( const QString &dir : dirs )
{
QDir appDir( dir );
appDir.mkpath( QStringLiteral( "proj" ) );
appDir.mkpath( QStringLiteral( "auth" ) );
appDir.mkpath( QStringLiteral( "fonts" ) );
appDir.mkpath( QStringLiteral( "basemaps" ) );
appDir.mkpath( QStringLiteral( "logs" ) );
appDir.mkpath( QStringLiteral( "plugins" ) );
QDir appDataDir( dir );
appDataDir.mkpath( QStringLiteral( "proj" ) );
appDataDir.mkpath( QStringLiteral( "auth" ) );
appDataDir.mkpath( QStringLiteral( "fonts" ) );
appDataDir.mkpath( QStringLiteral( "basemaps" ) );
appDataDir.mkpath( QStringLiteral( "logs" ) );
appDataDir.mkpath( QStringLiteral( "plugins" ) );
}

QDir applicationDir( applicationDirectory() );
applicationDir.mkpath( QStringLiteral( "Imported Projects" ) );
applicationDir.mkpath( QStringLiteral( "Imported Datasets" ) );
}

QString PlatformUtilities::systemSharedDataLocation() const
Expand Down Expand Up @@ -153,7 +158,7 @@ void PlatformUtilities::loadQgsProject() const

QStringList PlatformUtilities::appDataDirs() const
{
return QStringList() << QStandardPaths::standardLocations( QStandardPaths::DocumentsLocation ).first() + QStringLiteral( "/QField/" );
return QStringList() << QStandardPaths::standardLocations( QStandardPaths::DocumentsLocation ).first() + QStringLiteral( "/QField Documents/QField/" );
}

QStringList PlatformUtilities::availableGrids() const
Expand Down Expand Up @@ -208,7 +213,7 @@ bool PlatformUtilities::renameFile( const QString &oldFilePath, const QString &n

QString PlatformUtilities::applicationDirectory() const
{
return QStandardPaths::standardLocations( QStandardPaths::DocumentsLocation ).first() + QStringLiteral( "/QField/" );
return QStandardPaths::standardLocations( QStandardPaths::DocumentsLocation ).first() + QStringLiteral( "/QField Documents/" );
}

QStringList PlatformUtilities::additionalApplicationDirectories() const
Expand All @@ -218,7 +223,19 @@ QStringList PlatformUtilities::additionalApplicationDirectories() const

QStringList PlatformUtilities::rootDirectories() const
{
return QStringList() << QString();
QStringList rootDirectories;
rootDirectories << QDir::homePath();
for ( const QStorageInfo &volume : QStorageInfo::mountedVolumes() )
{
if ( volume.isReady() && !volume.isReadOnly() )
{
if ( volume.fileSystemType() != QLatin1String( "tmpfs" ) && !volume.rootPath().startsWith( QLatin1String( "/boot" ) ) )
{
rootDirectories << volume.rootPath();
}
}
}
return rootDirectories;
}

void PlatformUtilities::importProjectFolder() const
Expand Down
2 changes: 1 addition & 1 deletion src/core/platforms/platformutilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class QFIELD_CORE_EXPORT PlatformUtilities : public QObject
/**
* The main application directory within which projects and datasets can be imported.
*/
virtual QString applicationDirectory() const;
Q_INVOKABLE virtual QString applicationDirectory() const;

/**
* Secondary application directories which can be used by individual platforms.
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgismobileapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
#include "urlutils.h"
#include "valuemapmodel.h"
#include "vertexmodel.h"
#include "webdavconnection.h"

#include <QDateTime>
#include <QFileInfo>
Expand Down Expand Up @@ -511,6 +512,7 @@ void QgisMobileapp::initDeclarative( QQmlEngine *engine )
qmlRegisterType<Positioning>( "org.qfield", 1, 0, "Positioning" );
qmlRegisterType<PositioningInformationModel>( "org.qfield", 1, 0, "PositioningInformationModel" );
qmlRegisterType<PositioningDeviceModel>( "org.qfield", 1, 0, "PositioningDeviceModel" );
qmlRegisterType<WebdavConnection>( "org.qfield", 1, 0, "WebdavConnection" );
qmlRegisterType<AudioRecorder>( "org.qfield", 1, 0, "AudioRecorder" );
qmlRegisterType<BarcodeDecoder>( "org.qfield", 1, 0, "BarcodeDecoder" );
qmlRegisterType<CameraPermission>( "org.qfield", 1, 0, "QfCameraPermission" );
Expand Down
6 changes: 6 additions & 0 deletions src/core/utils/fileutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ bool FileUtils::isImageMimeTypeSupported( const QString &mimeType )
return QImageReader::supportedMimeTypes().contains( mimeType.toLatin1() );
}

QString FileUtils::absolutePath( const QString &filePath )
{
QFileInfo fileInfo( filePath );
return fileInfo.absolutePath();
}

QString FileUtils::fileName( const QString &filePath )
{
QFileInfo fileInfo( filePath );
Expand Down
6 changes: 4 additions & 2 deletions src/core/utils/fileutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ class QFIELD_CORE_EXPORT FileUtils : public QObject
Q_INVOKABLE static QString mimeTypeName( const QString &filePath );
//! Returns TRUE if the provided mimetype is a supported image
Q_INVOKABLE static bool isImageMimeTypeSupported( const QString &mimeType );
//! Returns the filename of a filepath - if no file name exists it's empty
//! Returns the filename of a \a filePath - if no file name exists it's empty
Q_INVOKABLE static QString fileName( const QString &filePath );
//! Returns true if the file exists (false if it's a directory)
//! Returns true if the \a filePath exists (false if it's a directory)
Q_INVOKABLE static bool fileExists( const QString &filePath );
//! Returns the suffix (extension)
Q_INVOKABLE static QString fileSuffix( const QString &filePath );
//! Returns a human-friendly size from bytes
Q_INVOKABLE static QString representFileSize( qint64 bytes );
//! Returns the absolute path of tghe folder containing the \a filePath.
Q_INVOKABLE static QString absolutePath( const QString &filePath );

/**
* Insures that a given image's width and height are restricted to a maximum size.
Expand Down
Loading
Loading