Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
477614b8c9 | ||
|
|
9d060e5e55 |
49
.drone.yml
@@ -237,17 +237,13 @@ name: qt-5.12
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build and test
|
- name: build and test
|
||||||
image: nextcloudci/client-5.12:client-5.12-5
|
image: nextcloudci/client-5.12:client-5.12-2
|
||||||
commands:
|
commands:
|
||||||
# Install QtKeyChain
|
# Install QtKeyChain
|
||||||
- /bin/bash -c "
|
- /bin/bash -c "
|
||||||
export CC=gcc-7 &&
|
export CC=gcc-7 &&
|
||||||
export CXX=g++-7 &&
|
export CXX=g++-7 &&
|
||||||
export QT_BASE_DIR=/opt/qt5.12.5 &&
|
source /opt/qt512/bin/qt512-env.sh &&
|
||||||
export QTDIR=\$QT_BASE_DIR &&
|
|
||||||
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
|
|
||||||
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
|
|
||||||
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
|
|
||||||
cd /tmp &&
|
cd /tmp &&
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||||
cd qtkeychain &&
|
cd qtkeychain &&
|
||||||
@@ -261,11 +257,7 @@ steps:
|
|||||||
- /bin/bash -c "
|
- /bin/bash -c "
|
||||||
export CC=gcc-7 &&
|
export CC=gcc-7 &&
|
||||||
export CXX=g++-7 &&
|
export CXX=g++-7 &&
|
||||||
export QT_BASE_DIR=/opt/qt5.12.5 &&
|
source /opt/qt512/bin/qt512-env.sh &&
|
||||||
export QTDIR=\$QT_BASE_DIR &&
|
|
||||||
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
|
|
||||||
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
|
|
||||||
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
|
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -D NO_SHIBBOLETH=1 -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=1 ../ &&
|
cmake -D NO_SHIBBOLETH=1 -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=1 ../ &&
|
||||||
@@ -286,17 +278,13 @@ name: qt-5.12-clang
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build and test
|
- name: build and test
|
||||||
image: nextcloudci/client-5.12:client-5.12-5
|
image: nextcloudci/client-5.12:client-5.12-2
|
||||||
commands:
|
commands:
|
||||||
# Install QtKeyChain
|
# Install QtKeyChain
|
||||||
- /bin/bash -c "
|
- /bin/bash -c "
|
||||||
export CC=clang-6.0 &&
|
export CC=clang-6.0 &&
|
||||||
export CXX=clang++-6.0 &&
|
export CXX=clang++-6.0 &&
|
||||||
export QT_BASE_DIR=/opt/qt5.12.5 &&
|
source /opt/qt512/bin/qt512-env.sh &&
|
||||||
export QTDIR=\$QT_BASE_DIR &&
|
|
||||||
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
|
|
||||||
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
|
|
||||||
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
|
|
||||||
cd /tmp &&
|
cd /tmp &&
|
||||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||||
cd qtkeychain &&
|
cd qtkeychain &&
|
||||||
@@ -310,11 +298,7 @@ steps:
|
|||||||
- /bin/bash -c "
|
- /bin/bash -c "
|
||||||
export CC=clang-6.0 &&
|
export CC=clang-6.0 &&
|
||||||
export CXX=clang++-6.0 &&
|
export CXX=clang++-6.0 &&
|
||||||
export QT_BASE_DIR=/opt/qt5.12.5 &&
|
source /opt/qt512/bin/qt512-env.sh &&
|
||||||
export QTDIR=\$QT_BASE_DIR &&
|
|
||||||
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
|
|
||||||
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
|
|
||||||
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
|
|
||||||
mkdir build &&
|
mkdir build &&
|
||||||
cd build &&
|
cd build &&
|
||||||
cmake -D NO_SHIBBOLETH=1 -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=1 ../ &&
|
cmake -D NO_SHIBBOLETH=1 -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=1 ../ &&
|
||||||
@@ -335,35 +319,16 @@ name: AppImage
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build
|
- name: build
|
||||||
image: nextcloudci/client-5.12:client-5.12-5
|
image: nextcloudci/client-5.12:client-5.12-2
|
||||||
commands:
|
commands:
|
||||||
- /bin/bash -c "./admin/linux/build-appimage.sh"
|
- /bin/bash -c "./admin/linux/build-appimage.sh"
|
||||||
- /bin/bash -c "./admin/linux/upload-appimage.sh"
|
|
||||||
trigger:
|
trigger:
|
||||||
branch:
|
branch:
|
||||||
- master
|
- master
|
||||||
event:
|
event:
|
||||||
- pull_request
|
- pull_request
|
||||||
- push
|
- push
|
||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
name: Debian
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build
|
|
||||||
image: nextcloudci/client-debian-ci:client-debian-ci-2
|
|
||||||
commands:
|
|
||||||
- /bin/bash -c "./admin/linux/debian/drone-build.sh"
|
|
||||||
environment:
|
|
||||||
DEBIAN_SECRET_KEY:
|
|
||||||
from_secret: DEBIAN_SECRET_KEY
|
|
||||||
DEBIAN_SECRET_IV:
|
|
||||||
from_secret: DEBIAN_SECRET_IV
|
|
||||||
trigger:
|
|
||||||
branch:
|
|
||||||
- stable-2.6
|
|
||||||
event:
|
|
||||||
- tag
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
name: Documentation
|
name: Documentation
|
||||||
|
|||||||
9
.gitignore
vendored
@@ -15,18 +15,9 @@ cscope.*
|
|||||||
tags
|
tags
|
||||||
t1.cfg
|
t1.cfg
|
||||||
|
|
||||||
## Ignore Visual Studio Code config & environment files
|
|
||||||
|
|
||||||
.vs/
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
# CMake integration on VS2019+
|
|
||||||
|
|
||||||
CMakeSettings.json
|
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
|
|||||||
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
|||||||
|
[submodule "src/3rdparty/qtmacgoodies"]
|
||||||
|
path = src/3rdparty/qtmacgoodies
|
||||||
|
url = https://github.com/camilasan/qtmacgoodies.git
|
||||||
[submodule "binary"]
|
[submodule "binary"]
|
||||||
path = binary
|
path = binary
|
||||||
url = git://github.com/owncloud/owncloud-client-binary.git
|
url = git://github.com/owncloud/owncloud-client-binary.git
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Categories=Utility;X-SuSE-SyncUtility;
|
|
||||||
Type=Application
|
|
||||||
Exec=@APPLICATION_EXECUTABLE@
|
|
||||||
Name=@APPLICATION_NAME@ desktop sync client
|
|
||||||
Comment=@APPLICATION_NAME@ desktop synchronization client
|
|
||||||
GenericName=Folder Sync
|
|
||||||
Icon=@APPLICATION_ICON_NAME@
|
|
||||||
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
|
|
||||||
X-GNOME-Autostart-Delay=3
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
Icon[cy_GB]=@APPLICATION_ICON_NAME@
|
|
||||||
Name[cy_GB]=@APPLICATION_NAME@ cleient cydweddu bwrdd gwaith
|
|
||||||
Comment[cy_GB]=@APPLICATION_NAME@ cleient cydweddu bwrdd gwaith
|
|
||||||
GenericName[cy_GB]=Cydweddu Ffolder
|
|
||||||
@@ -198,7 +198,4 @@ X-GNOME-Autostart-Delay=3
|
|||||||
|
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
Icon[el]=@APPLICATION_ICON_NAME@
|
|
||||||
Name[el]=@APPLICATION_NAME@ πρόγραμμα συγχρονισμού
|
|
||||||
Comment[el]=@APPLICATION_NAME@ πρόγραμμα συγχρονισμού
|
|
||||||
GenericName[el]=Συγχρονισμός φακέλου
|
GenericName[el]=Συγχρονισμός φακέλου
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ X-GNOME-Autostart-Delay=3
|
|||||||
|
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
Icon[hr]=@APPLICATION_ICON_NAME@
|
Name[hr]=sinkronizacija računala
|
||||||
Name[hr]=@APPLICATION_NAME@ klijent za sink. računala
|
Comment[hr]=klijent za sinkronizaciju računala
|
||||||
Comment[hr]=@APPLICATION_NAME@ klijent za sinkronizaciju računala
|
|
||||||
GenericName[hr]=Sinkronizacija mapa
|
GenericName[hr]=Sinkronizacija mapa
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Categories=Utility;X-SuSE-SyncUtility;
|
|
||||||
Type=Application
|
|
||||||
Exec=@APPLICATION_EXECUTABLE@
|
|
||||||
Name=@APPLICATION_NAME@ desktop sync client
|
|
||||||
Comment=@APPLICATION_NAME@ desktop synchronization client
|
|
||||||
GenericName=Folder Sync
|
|
||||||
Icon=@APPLICATION_ICON_NAME@
|
|
||||||
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
|
|
||||||
X-GNOME-Autostart-Delay=3
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
Icon[mk]=@APPLICATION_ICON_NAME@
|
|
||||||
Name[mk]=@APPLICATION_NAME@ клиент за синхронизација на компјутер
|
|
||||||
Comment[mk]=@APPLICATION_NAME@ клиент за синхронизација на компјутер
|
|
||||||
GenericName[mk]=Папка за синхронизација
|
|
||||||
@@ -201,4 +201,4 @@ X-GNOME-Autostart-Delay=3
|
|||||||
Icon[ro]=@APPLICATION_ICON_NAME@
|
Icon[ro]=@APPLICATION_ICON_NAME@
|
||||||
Name[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
|
Name[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
|
||||||
Comment[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
|
Comment[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
|
||||||
GenericName[ro]=Sincronizare director
|
GenericName[ro]=Sincronizare dosare
|
||||||
|
|||||||
@@ -201,4 +201,4 @@ X-GNOME-Autostart-Delay=3
|
|||||||
Icon[sk_SK]=@APPLICATION_ICON_NAME@
|
Icon[sk_SK]=@APPLICATION_ICON_NAME@
|
||||||
Name[sk_SK]=@APPLICATION_NAME@ synchronizačný klient pre PC
|
Name[sk_SK]=@APPLICATION_NAME@ synchronizačný klient pre PC
|
||||||
Comment[sk_SK]=@APPLICATION_NAME@ synchronizačný klient pre PC
|
Comment[sk_SK]=@APPLICATION_NAME@ synchronizačný klient pre PC
|
||||||
GenericName[sk_SK]=Synchronizácia priečinkov
|
GenericName[sk_SK]=Synchnonizácia priečinkov
|
||||||
|
|||||||
@@ -199,6 +199,6 @@ X-GNOME-Autostart-Delay=3
|
|||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
Icon[sl]=@APPLICATION_ICON_NAME@
|
Icon[sl]=@APPLICATION_ICON_NAME@
|
||||||
Name[sl]=@APPLICATION_NAME@ program za usklajevanje
|
Name[sl]=@APPLICATION_NAME@ odjemalec za usklajevanje
|
||||||
Comment[sl]=@APPLICATION_NAME@ program za usklajevanje
|
Comment[sl]=@APPLICATION_NAME@ odjemalec za usklajevanje
|
||||||
GenericName[sl]=Usklajevanje map
|
GenericName[sl]=Usklajevanje map
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Categories=Utility;X-SuSE-SyncUtility;
|
|
||||||
Type=Application
|
|
||||||
Exec=@APPLICATION_EXECUTABLE@
|
|
||||||
Name=@APPLICATION_NAME@ desktop sync client
|
|
||||||
Comment=@APPLICATION_NAME@ desktop synchronization client
|
|
||||||
GenericName=Folder Sync
|
|
||||||
Icon=@APPLICATION_ICON_NAME@
|
|
||||||
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
|
|
||||||
X-GNOME-Autostart-Delay=3
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
Icon[sw]=@APPLICATION_ICON_NAME@
|
|
||||||
Name[sw]=Teja ya @APPLICATION_NAME@ ya kufanana faili kwa seva na faili ziko hapa
|
|
||||||
Comment[sw]=Teja ya @APPLICATION_NAME@ ya kufanana faili kwa seva na faili ziko hapa
|
|
||||||
GenericName[sw]=Fanana Kabrasha
|
|
||||||
@@ -203,16 +203,8 @@ if( WIN32 )
|
|||||||
add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
|
add_definitions( -D__USE_MINGW_ANSI_STDIO=1 )
|
||||||
add_definitions( -DNOMINMAX )
|
add_definitions( -DNOMINMAX )
|
||||||
# Get APIs from from Vista onwards.
|
# Get APIs from from Vista onwards.
|
||||||
add_definitions( -D_WIN32_WINNT=0x0601 )
|
add_definitions( -D_WIN32_WINNT=0x0600)
|
||||||
add_definitions( -DWINVER=0x0601 )
|
add_definitions( -DWINVER=0x0600)
|
||||||
if( MSVC )
|
|
||||||
# Use automatic overload for suitable CRT safe-functions
|
|
||||||
# See https://docs.microsoft.com/de-de/cpp/c-runtime-library/security-features-in-the-crt?view=vs-2019
|
|
||||||
add_definitions( -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1 )
|
|
||||||
# Also: Disable compiler warnings because we don't use Windows CRT safe-functions explicitly and don't intend to
|
|
||||||
# as this is a pure cross-platform source the only alternative would be a ton of ifdefs with calls to the _s version
|
|
||||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS )
|
|
||||||
endif( MSVC )
|
|
||||||
endif( WIN32 )
|
endif( WIN32 )
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
|||||||
350
ChangeLog
@@ -1,138 +1,5 @@
|
|||||||
2.5 Series ChangeLog
|
ChangeLog
|
||||||
====================
|
=========
|
||||||
|
|
||||||
version 2.5.3 (release 2019-07-22)
|
|
||||||
* Fix empty file wording in error log (small)
|
|
||||||
* Add Qt-5.12 to CI
|
|
||||||
* Fix a minor typo
|
|
||||||
* Libcloudproviders: Add missing check for Qt5DBus
|
|
||||||
* Fix several memory leaks in cloudproviders and add translation support
|
|
||||||
* Share link fixing
|
|
||||||
* New drone config
|
|
||||||
* Uses configuraion to determine if it should show empty folder popup.
|
|
||||||
* Simplify cmake command to make copy-pastable
|
|
||||||
* Updated default remote poll to 5 seconds #1115
|
|
||||||
* Fix memory leak with device pointer
|
|
||||||
* Added a nice UI for the E2E-enabled account first connect
|
|
||||||
* This should fix issue #1000
|
|
||||||
* Adds parameter to retrieve shares with its reshares.
|
|
||||||
* Fixed typo
|
|
||||||
* Fixed typo in "certificate"
|
|
||||||
* WebView: Properly handle usernames with spaces and plus signs in it
|
|
||||||
* Add error category for http file lock error status 423.
|
|
||||||
* Displays the uid_owner of a shared file.
|
|
||||||
* Minor text change in the link to help in the tab 'General'.
|
|
||||||
|
|
||||||
version 2.5.2 (release 2019-04-11)
|
|
||||||
* Handle spaces in username properly in login flow
|
|
||||||
* Wizard: show an error message if there is no enough free space in the local folder
|
|
||||||
* Removed whitespace from string
|
|
||||||
* Do not add double slash to login flow url
|
|
||||||
* Fix login flow with system proxy
|
|
||||||
* Start with easier theming
|
|
||||||
* Do not display dismissed notifications
|
|
||||||
* Fixed l18n issue. Added space for separating string
|
|
||||||
* Add invalid certiticate messagebox
|
|
||||||
* Correct app passwords link
|
|
||||||
* Be less verbose with logging
|
|
||||||
* Fix typo in translation string
|
|
||||||
* Add a command line option to launch the client in the background
|
|
||||||
* Support Ubuntu Disco Dingo
|
|
||||||
* Added missing Include
|
|
||||||
* Make sure _profile and _page are deleted in the correct order
|
|
||||||
* Fix KDEInstallDirs deprecation warnings
|
|
||||||
* Removed Stylesheet
|
|
||||||
|
|
||||||
version 2.5.1 (release 2019-01-06)
|
|
||||||
* Fixup the port in server notification URLs
|
|
||||||
* GUI: let Clang-Tidy modernize nullptr & override usage
|
|
||||||
* Improve the slide show
|
|
||||||
* Libsync: let Clang-Tidy modernize nullptr & override usage
|
|
||||||
* SettingsDialog: fix a little glitch in the account tool button size
|
|
||||||
* SettingsDialog: tweak color aware icons
|
|
||||||
* More verbose error and proper app name on configuration read error
|
|
||||||
* Fix cmake build using WITH_PROVIDERS=OFF
|
|
||||||
* Debian/Ubuntu target repository update
|
|
||||||
* Change man page names and contents for nextcloud
|
|
||||||
* Share dialog alignment
|
|
||||||
* Fixed typo
|
|
||||||
* Change link to docs for NC 15
|
|
||||||
* Do not fetch activities if they are not enabled
|
|
||||||
* Do not read system exclude list if user exclude is present
|
|
||||||
* Fix the activity loop
|
|
||||||
* Write the actual folder to the log
|
|
||||||
* Fix appname for Nautilus integration script
|
|
||||||
|
|
||||||
version 2.5.0 (release 2018-11-14)
|
|
||||||
* End to end encryption
|
|
||||||
* New Web login flow
|
|
||||||
* UI improvements: Notifications
|
|
||||||
* UI improvements: refactoring of Activities
|
|
||||||
* SyncJournal: Clear etag filter before sync
|
|
||||||
* Partial local discovery: Fix scheduling logic
|
|
||||||
* Sync hidden files by default
|
|
||||||
* Larger Windows App Icon
|
|
||||||
* Show a tray message when a folder watcher becomes unreliable #6119
|
|
||||||
* Create symlinks for the small-letter application icon file names
|
|
||||||
* In setup wizard put link to nextcloud installation
|
|
||||||
* Web view scales vertically
|
|
||||||
* Add a WebFlowCredentialsAccessManager
|
|
||||||
* Mac Application Icon
|
|
||||||
* Ensure GETFileJob notices finishing #6581
|
|
||||||
* OAuth2: Try to refresh the token even if the credentials weren't ready.
|
|
||||||
* Tray workarounds #6545
|
|
||||||
* UpdateInfo: Remove unused code
|
|
||||||
* OAuth: Remove the timeout
|
|
||||||
* TestOAuth: Don't have global static QObject
|
|
||||||
* Log: Adjust update/reconcile log verbosity
|
|
||||||
* Reconcile: When detecting a local move, keep the local mtime
|
|
||||||
* Wizard enhancement
|
|
||||||
* FolderMan::checkPathValidityForNewFolder: make sure to work when fold…
|
|
||||||
* Update: Report on readdir() errors #6610
|
|
||||||
* Use encode()/decode() with Python 3 only
|
|
||||||
* Sqlite: Update bundled version to 3.24.0
|
|
||||||
* Do not require server replies to contain an mtime
|
|
||||||
* Settings: Attempt to fix rename issue on old macOS
|
|
||||||
* Support higher resolution theme icons
|
|
||||||
* OAuth: Fix infinite loop when the refresh token is expired
|
|
||||||
* Windows: Don't ignore files with FILE_ATTRIBUTE_TEMPORARY
|
|
||||||
* Data-Fingerprint: Fix backup detection when fingerprint is empty
|
|
||||||
* Nautilus: Fix GET_MENU_ITEMS with utf8 filenames #6643
|
|
||||||
* Windows: Release handle/fd when file open fails #6699
|
|
||||||
* SettingsDialog: Show the page for the newly created account
|
|
||||||
* Updates submodule qtmacgoodies.
|
|
||||||
* Fixes #665 Adds slot for confirmShare button.
|
|
||||||
* Rename INSTALL to INSTALL.md for Preview :)
|
|
||||||
* Add cmake temporary stuff
|
|
||||||
* Inform user that configuration is not writable
|
|
||||||
* Uses QByteArray to store private key.
|
|
||||||
* Fix cmake command for linux in README too
|
|
||||||
* Build fix: remove an unused QtSvg/QSvgRenderer include
|
|
||||||
* Qtkeychain: 0.8.0 -> 0.9.1
|
|
||||||
* Setup wizard: implement an animated and interactive slide show
|
|
||||||
* Theming for general settings ui
|
|
||||||
* Make the "Add Folder Sync Connection" button act like a button
|
|
||||||
* Allow to use the login flow with a self signed certificate
|
|
||||||
* Fix warning in ShareUserGroupWidget
|
|
||||||
* Copy over config file to new location on windows
|
|
||||||
* Update to translate strings
|
|
||||||
* Migrate http auth to webflow
|
|
||||||
* Margins
|
|
||||||
* Qt 5.5 compatibility patch for Xenial
|
|
||||||
* Fix cmake build of documentation
|
|
||||||
* Use Nextcloud
|
|
||||||
* Update isntaller background for OSX
|
|
||||||
* Fix ActivityWidget palette
|
|
||||||
* SettingsDialog: disable unnecessary wrapping for the about label
|
|
||||||
* Added default scheme when server returns just a host
|
|
||||||
* Removed explicit initialization; Fixed RAND_bytes not found
|
|
||||||
* Actually open the activity view on a click for more info
|
|
||||||
* Use a format that supports alpha channels for avatars
|
|
||||||
* L10n. Added space for correct grammar.
|
|
||||||
|
|
||||||
|
|
||||||
2.4 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 2.4.1 (2017-02-xx)
|
version 2.4.1 (2017-02-xx)
|
||||||
* Ignore files with file names that can't be encoded for the filesystem (#6287, #5676, #5719)
|
* Ignore files with file names that can't be encoded for the filesystem (#6287, #5676, #5719)
|
||||||
@@ -247,10 +114,6 @@ version 2.4.0 (2017-12-21)
|
|||||||
* Compile with stack-smashing protection
|
* Compile with stack-smashing protection
|
||||||
* Updater: Rudimentary support for beta channel (#6048)
|
* Updater: Rudimentary support for beta channel (#6048)
|
||||||
|
|
||||||
|
|
||||||
2.3 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 2.3.4 (2017-11-02)
|
version 2.3.4 (2017-11-02)
|
||||||
* Checksums: Use addData function to avoid endless loop CPU load issues with Office files
|
* Checksums: Use addData function to avoid endless loop CPU load issues with Office files
|
||||||
* Packaging: Require ZLIB
|
* Packaging: Require ZLIB
|
||||||
@@ -321,10 +184,6 @@ version 2.3.0 (2017-03-03)
|
|||||||
* Improved documentation
|
* Improved documentation
|
||||||
* Crash fixes
|
* Crash fixes
|
||||||
|
|
||||||
|
|
||||||
2.2 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 2.2.4 (release 2016-09-27)
|
version 2.2.4 (release 2016-09-27)
|
||||||
* Dolphin Plugin: Use the Application name for the socket path (#5172)
|
* Dolphin Plugin: Use the Application name for the socket path (#5172)
|
||||||
* SyncEngine: Fix renaming of folder when file are changed (#5195)
|
* SyncEngine: Fix renaming of folder when file are changed (#5195)
|
||||||
@@ -389,10 +248,6 @@ version 2.2.0 (release 2016-05-12)
|
|||||||
* Update of QtKeyChain to support Windows credential store
|
* Update of QtKeyChain to support Windows credential store
|
||||||
* Packaging of dolphin overlay icon module for bleeding edge distros
|
* Packaging of dolphin overlay icon module for bleeding edge distros
|
||||||
|
|
||||||
|
|
||||||
2.1 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 2.1.1 (release 2016-02-10)
|
version 2.1.1 (release 2016-02-10)
|
||||||
* UI improvements for HiDPI screens, error messages, RTL languages
|
* UI improvements for HiDPI screens, error messages, RTL languages
|
||||||
* Fix occurences of "Connection Closed" when a new unauthenticated TCP socket is used
|
* Fix occurences of "Connection Closed" when a new unauthenticated TCP socket is used
|
||||||
@@ -426,8 +281,8 @@ version 2.1 (release 2015-12-03)
|
|||||||
* Improved reconnecting after network change/disconnect (#4167 #3969 ...)
|
* Improved reconnecting after network change/disconnect (#4167 #3969 ...)
|
||||||
* Improved performance in Windows file system discovery
|
* Improved performance in Windows file system discovery
|
||||||
* Removed libneon-based propagator. As a consequence, The client can no
|
* Removed libneon-based propagator. As a consequence, The client can no
|
||||||
* longer provide bandwith limiting on Linux-distributions where it is
|
longer provide bandwith limiting on Linux-distributions where it is
|
||||||
* using Qt < 5.4
|
using Qt < 5.4
|
||||||
* Performance improvements in the logging functions
|
* Performance improvements in the logging functions
|
||||||
* Ensured that local disk space problems are handled gracefully (#2939)
|
* Ensured that local disk space problems are handled gracefully (#2939)
|
||||||
* Improved handling of checksums: transport validation, db (#3735)
|
* Improved handling of checksums: transport validation, db (#3735)
|
||||||
@@ -463,10 +318,6 @@ version 2.1 (release 2015-12-03)
|
|||||||
* Organized patches to our base Qt version into admin/qt/patches
|
* Organized patches to our base Qt version into admin/qt/patches
|
||||||
* Plus: A lot of unmentioned improvements and fixes
|
* Plus: A lot of unmentioned improvements and fixes
|
||||||
|
|
||||||
|
|
||||||
2.0 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 2.0.2 (release 2015-10-21)
|
version 2.0.2 (release 2015-10-21)
|
||||||
* csync_file_stat_s: Save a bit of memory
|
* csync_file_stat_s: Save a bit of memory
|
||||||
* Shibboleth: Add our base user agent to WebKit
|
* Shibboleth: Add our base user agent to WebKit
|
||||||
@@ -542,10 +393,6 @@ version 2.0.0 (release 2015-08-25)
|
|||||||
* Bandwidth Throttling: Provide automatic limit setting for downloads (#3084)
|
* Bandwidth Throttling: Provide automatic limit setting for downloads (#3084)
|
||||||
* Systray: Workaround for issue with Qt 5.5.0 #3656
|
* Systray: Workaround for issue with Qt 5.5.0 #3656
|
||||||
|
|
||||||
|
|
||||||
1.8 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.8.4 (release 2015-07-13)
|
version 1.8.4 (release 2015-07-13)
|
||||||
* Release to ship a security release of openSSL. No source changes of the ownCloud Client code.
|
* Release to ship a security release of openSSL. No source changes of the ownCloud Client code.
|
||||||
|
|
||||||
@@ -555,7 +402,7 @@ version 1.8.3 (release 2015-06-23)
|
|||||||
* Ignores: Force a remote discovery after ignore list change (#3172)
|
* Ignores: Force a remote discovery after ignore list change (#3172)
|
||||||
* Shibboleth: Avoid crash by letting the webview use its own QNAM (#3359)
|
* Shibboleth: Avoid crash by letting the webview use its own QNAM (#3359)
|
||||||
* System Ignores: Removed *.tmp from system ignore again. If a user
|
* System Ignores: Removed *.tmp from system ignore again. If a user
|
||||||
* wants to ignore *.tmp, it needs to be added to the user ignore list.
|
wants to ignore *.tmp, it needs to be added to the user ignore list.
|
||||||
|
|
||||||
version 1.8.2 (release 2015-06-08)
|
version 1.8.2 (release 2015-06-08)
|
||||||
* Improve reporting of server error messages (#3220)
|
* Improve reporting of server error messages (#3220)
|
||||||
@@ -568,16 +415,16 @@ version 1.8.2 (release 2015-06-08)
|
|||||||
* HTTP: Add the branding name to the UserAgent string
|
* HTTP: Add the branding name to the UserAgent string
|
||||||
* ConnectonValidator: Always run with new credentials (#3266)
|
* ConnectonValidator: Always run with new credentials (#3266)
|
||||||
* Recall Feature: Admins can trigger an upload of a file from
|
* Recall Feature: Admins can trigger an upload of a file from
|
||||||
* client to server again (#3246)
|
client to server again (#3246)
|
||||||
* Propagator: Add 'Content-Length: 0' header to MKCOL request (#3256)
|
* Propagator: Add 'Content-Length: 0' header to MKCOL request (#3256)
|
||||||
* Switch on checksum verification through branding or config
|
* Switch on checksum verification through branding or config
|
||||||
* Add ability for checksum verification of up and download
|
* Add ability for checksum verification of up and download
|
||||||
* Fix opening external links for some labels (#3135)
|
* Fix opening external links for some labels (#3135)
|
||||||
* AccountState: Run only a single validator, allow error message
|
* AccountState: Run only a single validator, allow error message
|
||||||
* overriding (#3236, #3153)
|
overriding (#3236, #3153)
|
||||||
* SyncJournalDB: Minor fixes and simplificatons
|
* SyncJournalDB: Minor fixes and simplificatons
|
||||||
* SyncEngine: Force re-read of folder Etags for upgrades from
|
* SyncEngine: Force re-read of folder Etags for upgrades from
|
||||||
* 1.8.0 and 1.8.1
|
1.8.0 and 1.8.1
|
||||||
* Propagator: Limit length of temporary file name (#2789)
|
* Propagator: Limit length of temporary file name (#2789)
|
||||||
* ShareDialog: Password ui fixes (#3189)
|
* ShareDialog: Password ui fixes (#3189)
|
||||||
* Fix startup hang by removing QSettings lock file (#3175)
|
* Fix startup hang by removing QSettings lock file (#3175)
|
||||||
@@ -598,12 +445,12 @@ version 1.8.2 (release 2015-06-08)
|
|||||||
version 1.8.1 (release 2015-05-07)
|
version 1.8.1 (release 2015-05-07)
|
||||||
* Make "operation canceled" error a soft error
|
* Make "operation canceled" error a soft error
|
||||||
* Do not throw an error for files that are scheduled to be removed,
|
* Do not throw an error for files that are scheduled to be removed,
|
||||||
* but can not be found on the server. #2919
|
but can not be found on the server. #2919
|
||||||
* Windows: Reset QNAM to proper function after hibernation. #2899 #2895 #2973
|
* Windows: Reset QNAM to proper function after hibernation. #2899 #2895 #2973
|
||||||
* Fix argument verification of --confdir #2453
|
* Fix argument verification of --confdir #2453
|
||||||
* Fix a crash when accessing a dangling UploadDevice pointer #2984
|
* Fix a crash when accessing a dangling UploadDevice pointer #2984
|
||||||
* Add-folder wizard: Make sure there is a scrollbar if folder names
|
* Add-folder wizard: Make sure there is a scrollbar if folder names
|
||||||
* are too long #2962
|
are too long #2962
|
||||||
* Add-folder Wizard: Select the newly created folder
|
* Add-folder Wizard: Select the newly created folder
|
||||||
* Activity: Correctly restore column sizes #3005
|
* Activity: Correctly restore column sizes #3005
|
||||||
* SSL Button: do not crash on empty certificate chain
|
* SSL Button: do not crash on empty certificate chain
|
||||||
@@ -611,8 +458,8 @@ version 1.8.1 (release 2015-05-07)
|
|||||||
* Lookup system proxy async to avoid hangs #2993 #2802
|
* Lookup system proxy async to avoid hangs #2993 #2802
|
||||||
* ShareDialog: Some GUI refinements
|
* ShareDialog: Some GUI refinements
|
||||||
* ShareDialog: On creation of a share always retrieve the share
|
* ShareDialog: On creation of a share always retrieve the share
|
||||||
* This makes sure that if a default expiration date is set this is reflected
|
This makes sure that if a default expiration date is set this is reflected
|
||||||
* in the dialog. #2889
|
in the dialog. #2889
|
||||||
* ShareDialog: Only show share dialog if we are connected.
|
* ShareDialog: Only show share dialog if we are connected.
|
||||||
* HttpCreds: Fill pw dialog with previous password. #2848 #2879
|
* HttpCreds: Fill pw dialog with previous password. #2848 #2879
|
||||||
* HttpCreds: Delete password from old location. #2186
|
* HttpCreds: Delete password from old location. #2186
|
||||||
@@ -621,7 +468,7 @@ version 1.8.1 (release 2015-05-07)
|
|||||||
* ProtocolWidget: Always add seconds to the DateTime locale. #2535
|
* ProtocolWidget: Always add seconds to the DateTime locale. #2535
|
||||||
* Updater: Give context as to which app is about to be updated #3040
|
* Updater: Give context as to which app is about to be updated #3040
|
||||||
* Windows: Add version information for owncloud.exe. This should help us know
|
* Windows: Add version information for owncloud.exe. This should help us know
|
||||||
* what version or build number a crash report was generated with.
|
what version or build number a crash report was generated with.
|
||||||
* Fix a crash on shutdown in ~SocketApi #3057
|
* Fix a crash on shutdown in ~SocketApi #3057
|
||||||
* SyncEngine: Show more timing measurements #3064
|
* SyncEngine: Show more timing measurements #3064
|
||||||
* Discovery: Add warning if returned etag is 0
|
* Discovery: Add warning if returned etag is 0
|
||||||
@@ -644,8 +491,8 @@ version 1.8.1 (release 2015-05-07)
|
|||||||
version 1.8.0 (release 2015-03-17)
|
version 1.8.0 (release 2015-03-17)
|
||||||
* Mac OS: HIDPI support
|
* Mac OS: HIDPI support
|
||||||
* Support Sharing from desktop: Added a share dialog that can be
|
* Support Sharing from desktop: Added a share dialog that can be
|
||||||
* opened by context menu in the file managers (Win, Mac, Nautilus)
|
opened by context menu in the file managers (Win, Mac, Nautilus)
|
||||||
* Supports public links with password enforcement
|
Supports public links with password enforcement
|
||||||
* Enhanced usage of parallel HTTP requests for ownCloud 8 servers
|
* Enhanced usage of parallel HTTP requests for ownCloud 8 servers
|
||||||
* Renamed github repository from mirall to client.
|
* Renamed github repository from mirall to client.
|
||||||
* Mac OS: Use native notification support
|
* Mac OS: Use native notification support
|
||||||
@@ -658,7 +505,7 @@ version 1.8.0 (release 2015-03-17)
|
|||||||
* Build with Qt 5.4
|
* Build with Qt 5.4
|
||||||
* Dropped libneon dependency if Qt 5.4 is available
|
* Dropped libneon dependency if Qt 5.4 is available
|
||||||
* Keep files open very short, that avoid lock problems on Windows
|
* Keep files open very short, that avoid lock problems on Windows
|
||||||
* especially with office software but also others.
|
especially with office software but also others.
|
||||||
* Merged some NetBSD patches
|
* Merged some NetBSD patches
|
||||||
* Selective sync support for owncloudcmd
|
* Selective sync support for owncloudcmd
|
||||||
* Reorganize the source repository
|
* Reorganize the source repository
|
||||||
@@ -667,17 +514,13 @@ version 1.8.0 (release 2015-03-17)
|
|||||||
* A huge amount of bug fixes in all areas of the client.
|
* A huge amount of bug fixes in all areas of the client.
|
||||||
* almost 700 commits since 1.7.1
|
* almost 700 commits since 1.7.1
|
||||||
|
|
||||||
|
|
||||||
1.7 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.7.1 (release 2014-12-18)
|
version 1.7.1 (release 2014-12-18)
|
||||||
* Documentation fixes and updates
|
* Documentation fixes and updates
|
||||||
* Nautilus Python plugin fixed for Python 3
|
* Nautilus Python plugin fixed for Python 3
|
||||||
* GUI wording fixes plus improved log messages
|
* GUI wording fixes plus improved log messages
|
||||||
* Fix hidning of the database files in the sync directories
|
* Fix hidning of the database files in the sync directories
|
||||||
* Compare http download size with the header value to avoid broken
|
* Compare http download size with the header value to avoid broken
|
||||||
* downloads, bug #2528
|
downloads, bug #2528
|
||||||
* Avoid initial ETag fetch job at startup, which is not needed.
|
* Avoid initial ETag fetch job at startup, which is not needed.
|
||||||
* Add chunk size http header to PUT requests
|
* Add chunk size http header to PUT requests
|
||||||
* Fixed deteteCookie method of our CookieJar, fix for Shibboleth
|
* Fixed deteteCookie method of our CookieJar, fix for Shibboleth
|
||||||
@@ -700,20 +543,21 @@ version 1.7.1 (release 2014-12-18)
|
|||||||
* Win32: Improve reliability of Installer, fix removal of Shell Extensions
|
* Win32: Improve reliability of Installer, fix removal of Shell Extensions
|
||||||
|
|
||||||
version 1.7.0 (release 2014-11-07)
|
version 1.7.0 (release 2014-11-07)
|
||||||
|
|
||||||
* oC7 Sharing: Handle new sharing options of ownCloud 7 correctly.
|
* oC7 Sharing: Handle new sharing options of ownCloud 7 correctly.
|
||||||
* Added Selective sync: Ability to unselect server folders which are
|
* Added Selective sync: Ability to unselect server folders which are
|
||||||
* excluded from syncing, plus GUI and setup GUI
|
excluded from syncing, plus GUI and setup GUI
|
||||||
* Added overlay icons for Windows Explorer, Mac OS Finder and GNOME Nautilus.
|
* Added overlay icons for Windows Explorer, Mac OS Finder and GNOME Nautilus.
|
||||||
* Information is provided by the client via a local socket / named pipe API
|
Information is provided by the client via a local socket / named pipe API
|
||||||
* which provides information about the sync status of files.
|
which provides information about the sync status of files.
|
||||||
* Improved local change detection: consider file size, detect files
|
* Improved local change detection: consider file size, detect files
|
||||||
* with ongoing changes and do not upload immediately
|
with ongoing changes and do not upload immediately
|
||||||
* Improved HTTP request timeout handler: all successful requests reset
|
* Improved HTTP request timeout handler: all successful requests reset
|
||||||
* the timeout counter
|
the timeout counter
|
||||||
* Improvements for syncing command line tool: netrc support, improved
|
* Improvements for syncing command line tool: netrc support, improved
|
||||||
* SSL support, non interactive mode
|
SSL support, non interactive mode
|
||||||
* Permission system: ownCloud 7 delivers file and folder permissions,
|
* Permission system: ownCloud 7 delivers file and folder permissions,
|
||||||
* added ability to deal with it for shared folders and more.
|
added ability to deal with it for shared folders and more.
|
||||||
* Ignore handling: Do not recurse into ignored or excluded directories
|
* Ignore handling: Do not recurse into ignored or excluded directories
|
||||||
* Major sync journal database improvements for more stability and performance
|
* Major sync journal database improvements for more stability and performance
|
||||||
* New library interface to sqlite3
|
* New library interface to sqlite3
|
||||||
@@ -722,40 +566,35 @@ version 1.7.0 (release 2014-11-07)
|
|||||||
* Improved logging: more useful meta info, removed noise
|
* Improved logging: more useful meta info, removed noise
|
||||||
* Updated to latest Qt5 versions on Windows and OS X
|
* Updated to latest Qt5 versions on Windows and OS X
|
||||||
* Fixed data loss when renaming a download temporary fails and there was
|
* Fixed data loss when renaming a download temporary fails and there was
|
||||||
* a conflict at the same time.
|
a conflict at the same time.
|
||||||
* Fixed missing warnings about reusing a sync folder when the back button
|
* Fixed missing warnings about reusing a sync folder when the back button
|
||||||
* was used in the advanced folder setup wizard.
|
was used in the advanced folder setup wizard.
|
||||||
* The 'Retry Sync' button now also restarts all downloads.
|
* The 'Retry Sync' button now also restarts all downloads.
|
||||||
* Clean up temporary downloads and some extra database files when wiping a
|
* Clean up temporary downloads and some extra database files when wiping a
|
||||||
* folder.
|
folder.
|
||||||
* OS X: Sparkle update to provide pkg format properly
|
* OS X: Sparkle update to provide pkg format properly
|
||||||
* OS X: Change distribution format from dmg to pkg with new installer.
|
* OS X: Change distribution format from dmg to pkg with new installer.
|
||||||
* Windows: Fix handling of filenames with trailing dot or space
|
* Windows: Fix handling of filenames with trailing dot or space
|
||||||
* Windows: Don't use the wrong way to get file mtimes in the legacy propagator.
|
* Windows: Don't use the wrong way to get file mtimes in the legacy propagator.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1.6 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.6.4 (release 2014-10-22)
|
version 1.6.4 (release 2014-10-22)
|
||||||
* Fix startup logic, fixes bug #1989
|
* Fix startup logic, fixes bug #1989
|
||||||
* Fix raise dialog on X11
|
* Fix raise dialog on X11
|
||||||
* Win32: fix overflow when computing the size of file > 4GiB
|
* Win32: fix overflow when computing the size of file > 4GiB
|
||||||
* Use a fixed function to get files modification time, the
|
* Use a fixed function to get files modification time, the
|
||||||
* original one was broken for certain timezone issues, see
|
original one was broken for certain timezone issues, see
|
||||||
* core bug #9781 for details
|
core bug #9781 for details
|
||||||
* Added some missing copyright headers
|
* Added some missing copyright headers
|
||||||
* Avoid data corruption due to wrong error handling, bug #2280
|
* Avoid data corruption due to wrong error handling, bug #2280
|
||||||
* Do improved request timeout handling to reduce the number of
|
* Do improved request timeout handling to reduce the number of
|
||||||
* timed out jobs, bug #2155
|
timed out jobs, bug #2155
|
||||||
* version 1.6.3 (release 2014-09-03)
|
version 1.6.3 (release 2014-09-03)
|
||||||
* Fixed updater on OS X
|
* Fixed updater on OS X
|
||||||
* Fixed memory leak in SSL button that could lead to quick memory draining
|
* Fixed memory leak in SSL button that could lead to quick memory draining
|
||||||
* Fixed upload problem with files >4 GB
|
* Fixed upload problem with files >4 GB
|
||||||
* MacOSX, Linux: Bring Settings window to front properly
|
* MacOSX, Linux: Bring Settings window to front properly
|
||||||
* Branded clients: If no configuration is detected, try to import the data
|
* Branded clients: If no configuration is detected, try to import the data
|
||||||
* from a previously configured community edition.
|
from a previously configured community edition.
|
||||||
|
|
||||||
version 1.6.2 (release 2014-07-28 )
|
version 1.6.2 (release 2014-07-28 )
|
||||||
* Limit the HTTP buffer size when downloading to limit memory consumption.
|
* Limit the HTTP buffer size when downloading to limit memory consumption.
|
||||||
@@ -763,7 +602,7 @@ version 1.6.2 (release 2014-07-28 )
|
|||||||
* Fix local file name clash detection for MacOSX.
|
* Fix local file name clash detection for MacOSX.
|
||||||
* Limit maximum wait time to ten seconds in network limiting.
|
* Limit maximum wait time to ten seconds in network limiting.
|
||||||
* Fix data corruption while trying to resume and the server does
|
* Fix data corruption while trying to resume and the server does
|
||||||
* not support it.
|
not support it.
|
||||||
* HTTP Credentials: Read password from legacy place if not found.
|
* HTTP Credentials: Read password from legacy place if not found.
|
||||||
* Shibboleth: Fix the waiting curser that would not disapear (#1915)
|
* Shibboleth: Fix the waiting curser that would not disapear (#1915)
|
||||||
* Limit memory usage to avoid mem wasting and crashes
|
* Limit memory usage to avoid mem wasting and crashes
|
||||||
@@ -777,18 +616,18 @@ version 1.6.1 (release 2014-06-26 )
|
|||||||
* Fix openSSL problems for windows deployment
|
* Fix openSSL problems for windows deployment
|
||||||
* Fix syncing a folder with '#' in the name
|
* Fix syncing a folder with '#' in the name
|
||||||
* Fix #1845: do not update parent directory etag before sub
|
* Fix #1845: do not update parent directory etag before sub
|
||||||
* directories are removed
|
directories are removed
|
||||||
* Fix reappearing directories if dirs are removed during its
|
* Fix reappearing directories if dirs are removed during its
|
||||||
* upload
|
upload
|
||||||
* Fix app version in settings dialog, General tab
|
* Fix app version in settings dialog, General tab
|
||||||
* Fix crash in FolderWizard when going offline
|
* Fix crash in FolderWizard when going offline
|
||||||
* Shibboleth fixes
|
* Shibboleth fixes
|
||||||
* More specific error messages (file remove during upload, open
|
* More specific error messages (file remove during upload, open
|
||||||
* local sync file)
|
local sync file)
|
||||||
* Use QSet rather than QHash in SyncEngine (save memory)
|
* Use QSet rather than QHash in SyncEngine (save memory)
|
||||||
* Fix some memory leaks
|
* Fix some memory leaks
|
||||||
* Fix some thread race problems, ie. wait for neon thread to finish
|
* Fix some thread race problems, ie. wait for neon thread to finish
|
||||||
* before the propagator is shut down
|
before the propagator is shut down
|
||||||
* Fix a lot of issues and warnings found by Coverity
|
* Fix a lot of issues and warnings found by Coverity
|
||||||
* Fix Mac some settings dialog problems
|
* Fix Mac some settings dialog problems
|
||||||
|
|
||||||
@@ -811,16 +650,16 @@ version 1.6.0 (release 2014-05-30 )
|
|||||||
* Introduce a general timeout of 300s for network operations
|
* Introduce a general timeout of 300s for network operations
|
||||||
* Improve error handling, blacklisting
|
* Improve error handling, blacklisting
|
||||||
* Job-based change propagation, enables faster parallel up/downloads
|
* Job-based change propagation, enables faster parallel up/downloads
|
||||||
* (right now only if no bandwidth limit is set and no proxy is used)
|
(right now only if no bandwidth limit is set and no proxy is used)
|
||||||
* Significantly reduced CPU load when checking for local and remote changes
|
* Significantly reduced CPU load when checking for local and remote changes
|
||||||
* Speed up file stat code on Windows
|
* Speed up file stat code on Windows
|
||||||
* Enforce Qt5 for Windows and Mac OS X builds
|
* Enforce Qt5 for Windows and Mac OS X builds
|
||||||
* Improved owncloudcmd: SSL support, documentation
|
* Improved owncloudcmd: SSL support, documentation
|
||||||
* Added advanced logging of operations (file .???.log in sync
|
* Added advanced logging of operations (file .???.log in sync
|
||||||
* directory)
|
directory)
|
||||||
* Avoid creating a temporary copy of the sync database (.ctmp)
|
* Avoid creating a temporary copy of the sync database (.ctmp)
|
||||||
* Enable support for TLS 1.2 negotiation on platforms that use
|
* Enable support for TLS 1.2 negotiation on platforms that use
|
||||||
* Qt 5.2 or later
|
Qt 5.2 or later
|
||||||
* Forward server exception messages to client error messages
|
* Forward server exception messages to client error messages
|
||||||
* Mac OS X: Support Notification Center in OS X 10.8+
|
* Mac OS X: Support Notification Center in OS X 10.8+
|
||||||
* Mac OS X: Use native settings dialog
|
* Mac OS X: Use native settings dialog
|
||||||
@@ -829,15 +668,11 @@ version 1.6.0 (release 2014-05-30 )
|
|||||||
* Remove vio abstraction in csync
|
* Remove vio abstraction in csync
|
||||||
* Avoid data loss when a client file system is not case sensitive
|
* Avoid data loss when a client file system is not case sensitive
|
||||||
|
|
||||||
|
|
||||||
1.5 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.5.3 (release 2014-03-10 )
|
version 1.5.3 (release 2014-03-10 )
|
||||||
* Fix usage of proxies after first sync run (#1502, #1524, #1459, #1521)
|
* Fix usage of proxies after first sync run (#1502, #1524, #1459, #1521)
|
||||||
* Do not wipe the credentials from config for reconnect (#1499, #1503)
|
* Do not wipe the credentials from config for reconnect (#1499, #1503)
|
||||||
* Do not erase the full account config if an old version of the client stored
|
* Do not erase the full account config if an old version of the client stored
|
||||||
* the password (related to above)
|
the password (related to above)
|
||||||
* Fix layout of the network tab (fixes #1491)
|
* Fix layout of the network tab (fixes #1491)
|
||||||
* Handle authentication requests by a Shibboleth IdP
|
* Handle authentication requests by a Shibboleth IdP
|
||||||
* Shibboleth: If no connection is available, don't open the login window
|
* Shibboleth: If no connection is available, don't open the login window
|
||||||
@@ -866,34 +701,34 @@ version 1.5.2 (release 2014-02-26 )
|
|||||||
|
|
||||||
version 1.5.1 (release 2014-02-13 )
|
version 1.5.1 (release 2014-02-13 )
|
||||||
* Added an auto updater that updates the client if a
|
* Added an auto updater that updates the client if a
|
||||||
* more recent version was found automatically (Windows, Mac OS X)
|
more recent version was found automatically (Windows, Mac OS X)
|
||||||
* Added a button to the account dialog that gives information
|
* Added a button to the account dialog that gives information
|
||||||
* about the encryption layer used for communication, plus a
|
about the encryption layer used for communication, plus a
|
||||||
* certificate information widget
|
certificate information widget
|
||||||
* Preserve the permission settings of local files rather than
|
* Preserve the permission settings of local files rather than
|
||||||
* setting them to a default (Bug #820)
|
setting them to a default (Bug #820)
|
||||||
* Handle windows lnk files correctly (Bug #1307)
|
* Handle windows lnk files correctly (Bug #1307)
|
||||||
* Detect removes and renames in read only shares and
|
* Detect removes and renames in read only shares and
|
||||||
* restore the gone away files. (Bug #1386)
|
restore the gone away files. (Bug #1386)
|
||||||
* Fixes sign in/sign out and password dialog. (Bug #1353)
|
* Fixes sign in/sign out and password dialog. (Bug #1353)
|
||||||
* Fixed error messages (Bug #1394)
|
* Fixed error messages (Bug #1394)
|
||||||
* Lots of fixes for building with Qt5
|
* Lots of fixes for building with Qt5
|
||||||
* Changes to network limits are now also applied during a
|
* Changes to network limits are now also applied during a
|
||||||
* sync run
|
sync run
|
||||||
* Fixed mem leak after via valgrind on Mac
|
* Fixed mem leak after via valgrind on Mac
|
||||||
* Imported the ocsync library into miralls repository.
|
* Imported the ocsync library into miralls repository.
|
||||||
* Adopted all build systems and packaging to that.
|
Adopted all build systems and packaging to that.
|
||||||
* Introduce a new linux packaging scheme following the
|
* Introduce a new linux packaging scheme following the
|
||||||
* debian upstream scheme
|
debian upstream scheme
|
||||||
* Use a refactored Linux file system watcher based on
|
* Use a refactored Linux file system watcher based on
|
||||||
* inotify, incl. unit tests
|
inotify, incl. unit tests
|
||||||
* Wizard: Gracefully fall back to HTTP if HTTPS connection
|
* Wizard: Gracefully fall back to HTTP if HTTPS connection
|
||||||
* fails, issuing a warning
|
fails, issuing a warning
|
||||||
* Fixed translation misses in the propagator
|
* Fixed translation misses in the propagator
|
||||||
* Fixes in proxy configuration
|
* Fixes in proxy configuration
|
||||||
* Fixes in sync journal handling
|
* Fixes in sync journal handling
|
||||||
* Fix the upload progress if the local source is still
|
* Fix the upload progress if the local source is still
|
||||||
* changing when the upload begins.
|
changing when the upload begins.
|
||||||
* Add proxy support to owncloud commandline client
|
* Add proxy support to owncloud commandline client
|
||||||
* NSIS fixes
|
* NSIS fixes
|
||||||
* A lot of other fixes and minor improvements
|
* A lot of other fixes and minor improvements
|
||||||
@@ -930,10 +765,6 @@ version 1.5.0 (release 2013-12-12 ), csync 0.91.4 required
|
|||||||
* Windows: Fix rename of temporary files
|
* Windows: Fix rename of temporary files
|
||||||
* Windows: Fix move file operation
|
* Windows: Fix move file operation
|
||||||
|
|
||||||
|
|
||||||
1.4 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.4.2 (release 2013-10-18 ), csync 0.90.4 required
|
version 1.4.2 (release 2013-10-18 ), csync 0.90.4 required
|
||||||
* Do not show the warning icon in the tray (#944)
|
* Do not show the warning icon in the tray (#944)
|
||||||
* Fix manual proxy support when switching (#1016)
|
* Fix manual proxy support when switching (#1016)
|
||||||
@@ -949,11 +780,12 @@ version 1.4.2 (release 2013-10-18 ), csync 0.90.4 required
|
|||||||
* Progress: Show number of deletes.
|
* Progress: Show number of deletes.
|
||||||
|
|
||||||
version 1.4.1 (release 2013-09-24 ), csync 0.90.1 required
|
version 1.4.1 (release 2013-09-24 ), csync 0.90.1 required
|
||||||
|
|
||||||
* Translation and documentation fixes.
|
* Translation and documentation fixes.
|
||||||
* Fixed error display in settings/status dialog, displays multi
|
* Fixed error display in settings/status dialog, displays multi
|
||||||
* line error messages now correctly.
|
line error messages now correctly.
|
||||||
* Wait up to 30 secs before complaining about missing systray
|
* Wait up to 30 secs before complaining about missing systray
|
||||||
* Fixes bug #949
|
Fixes bug #949
|
||||||
* Fixed utf8 issues with basic auth authentication, fixes bug #941
|
* Fixed utf8 issues with basic auth authentication, fixes bug #941
|
||||||
* Fixed remote folder selector, avoid recursive syncing, fixes bug #962
|
* Fixed remote folder selector, avoid recursive syncing, fixes bug #962
|
||||||
* Handle and display network problems at startup correctly.
|
* Handle and display network problems at startup correctly.
|
||||||
@@ -970,6 +802,7 @@ version 1.4.1 (release 2013-09-24 ), csync 0.90.1 required
|
|||||||
* Various minor code fixes
|
* Various minor code fixes
|
||||||
|
|
||||||
version 1.4.0 (release 2013-09-04 ), csync 0.90.0 required
|
version 1.4.0 (release 2013-09-04 ), csync 0.90.0 required
|
||||||
|
|
||||||
* New Scheduler: Only sync when there are actual changes in the server
|
* New Scheduler: Only sync when there are actual changes in the server
|
||||||
* Add a Settings Dialog, move Proxy Settings there
|
* Add a Settings Dialog, move Proxy Settings there
|
||||||
* Transform folder Status Dialog into Account Settings, provide feedback via context menu
|
* Transform folder Status Dialog into Account Settings, provide feedback via context menu
|
||||||
@@ -980,7 +813,7 @@ version 1.4.0 (release 2013-09-04 ), csync 0.90.0 required
|
|||||||
* Move ability to switch to mono icons from a switch to a Settings option
|
* Move ability to switch to mono icons from a switch to a Settings option
|
||||||
* Add "Launch on System Startup" GUI option
|
* Add "Launch on System Startup" GUI option
|
||||||
* Add "Show Desktop Nofications"GUI option (enabled by default)
|
* Add "Show Desktop Nofications"GUI option (enabled by default)
|
||||||
* top optionally disable sync notifications
|
top optionally disable sync notifications
|
||||||
* Add Help item, pointing to online reference
|
* Add Help item, pointing to online reference
|
||||||
* Implement graphical selection of remote folders in FolderWizard
|
* Implement graphical selection of remote folders in FolderWizard
|
||||||
* Allow custom ignore patterns
|
* Allow custom ignore patterns
|
||||||
@@ -999,14 +832,11 @@ version 1.4.0 (release 2013-09-04 ), csync 0.90.0 required
|
|||||||
* Require Qt 4.7
|
* Require Qt 4.7
|
||||||
* Known issue: Under certain conditions, a file will only get uploaded after up to five minutes
|
* Known issue: Under certain conditions, a file will only get uploaded after up to five minutes
|
||||||
|
|
||||||
|
|
||||||
1.3 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
|
version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
|
||||||
|
|
||||||
* Default proxy port to 8080
|
* Default proxy port to 8080
|
||||||
* Don't lose proxy settings when changing passwords
|
* Don't lose proxy settings when changing passwords
|
||||||
* Support SOCKS5 proxy (useful in combination with ssh* *D)
|
* Support SOCKS5 proxy (useful in combination with ssh *D)
|
||||||
* Propagate proxy changes to csync at runtime
|
* Propagate proxy changes to csync at runtime
|
||||||
* Improve proxy wizard
|
* Improve proxy wizard
|
||||||
* Display proxy errors
|
* Display proxy errors
|
||||||
@@ -1022,7 +852,7 @@ version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
|
|||||||
* Remove journal when reusing a directory that used to have a journal before
|
* Remove journal when reusing a directory that used to have a journal before
|
||||||
* Visual clean up of status dialog items
|
* Visual clean up of status dialog items
|
||||||
* Wizard: When changing the URL or user name, allow the user to push his data
|
* Wizard: When changing the URL or user name, allow the user to push his data
|
||||||
* to the new location or wipe the folder and start from scratch
|
to the new location or wipe the folder and start from scratch
|
||||||
* Wizard: Make setting a custom folder as a sync target work again
|
* Wizard: Make setting a custom folder as a sync target work again
|
||||||
* Fix application icon
|
* Fix application icon
|
||||||
* User-Agent now contains "Mozilla/5.0" and the Platform name (for firewall/proxy compat)
|
* User-Agent now contains "Mozilla/5.0" and the Platform name (for firewall/proxy compat)
|
||||||
@@ -1030,10 +860,6 @@ version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
|
|||||||
* New setup wizard, defaulting to root syncing (only for new setups)
|
* New setup wizard, defaulting to root syncing (only for new setups)
|
||||||
* Improved thread stop/termination
|
* Improved thread stop/termination
|
||||||
|
|
||||||
|
|
||||||
1.2 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.2.5 (release 2013-04-23 ), csync 0.70.7 required
|
version 1.2.5 (release 2013-04-23 ), csync 0.70.7 required
|
||||||
* [Fixes] NSIS installer fixes
|
* [Fixes] NSIS installer fixes
|
||||||
* [Fixes] Fix crash race by making certificateChain() thread safe
|
* [Fixes] Fix crash race by making certificateChain() thread safe
|
||||||
@@ -1099,10 +925,6 @@ version 1.2.0 (release 2013-01-24 ), csync 0.70.2 required
|
|||||||
* [Platform] cmake fixes.
|
* [Platform] cmake fixes.
|
||||||
* [Platform] Improved, more detailed error reporting.
|
* [Platform] Improved, more detailed error reporting.
|
||||||
|
|
||||||
|
|
||||||
1.1 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.1.4 (release 2012-12-19 ), csync 0.60.4 required
|
version 1.1.4 (release 2012-12-19 ), csync 0.60.4 required
|
||||||
* No changes to mirall, only csync fixes.
|
* No changes to mirall, only csync fixes.
|
||||||
|
|
||||||
@@ -1112,7 +934,7 @@ version 1.1.3 (release 2012-11-30 ), csync 0.60.3 required
|
|||||||
version 1.1.2 (release 2012-11-26 ), csync 0.60.2 required
|
version 1.1.2 (release 2012-11-26 ), csync 0.60.2 required
|
||||||
* [Fixes] Allow to properly cancel the password dialog.
|
* [Fixes] Allow to properly cancel the password dialog.
|
||||||
* [Fixes] Share folder name correctly percent encoded with old Qt
|
* [Fixes] Share folder name correctly percent encoded with old Qt
|
||||||
* * * * 4.6 builds ie. Debian.
|
4.6 builds ie. Debian.
|
||||||
* [Fixes] If local sync dir is not existing, create it.
|
* [Fixes] If local sync dir is not existing, create it.
|
||||||
* [Fixes] lots of other minor fixes.
|
* [Fixes] lots of other minor fixes.
|
||||||
* [GUI] Display error messages in status dialog.
|
* [GUI] Display error messages in status dialog.
|
||||||
@@ -1120,30 +942,30 @@ version 1.1.2 (release 2012-11-26 ), csync 0.60.2 required
|
|||||||
* [GUI] Show username for connection in statusdialog.
|
* [GUI] Show username for connection in statusdialog.
|
||||||
* [GUI] Show intro wizard on new connection setup.
|
* [GUI] Show intro wizard on new connection setup.
|
||||||
* [APP] Use CredentialStore to better support various credential
|
* [APP] Use CredentialStore to better support various credential
|
||||||
* * * backends.
|
backends.
|
||||||
* [APP] Handle missing local folder more robust: Create it if
|
* [APP] Handle missing local folder more robust: Create it if
|
||||||
* * * missing instead of ignoring.
|
missing instead of ignoring.
|
||||||
* [APP] Simplify treewalk code.
|
* [APP] Simplify treewalk code.
|
||||||
* [Platform] Fix Mac building
|
* [Platform] Fix Mac building
|
||||||
|
|
||||||
version 1.1.1 (release 2012-10-18), csync 0.60.1 required
|
version 1.1.1 (release 2012-10-18), csync 0.60.1 required
|
||||||
* [GUI]* Allow changing folder name in single folder mode
|
* [GUI] Allow changing folder name in single folder mode
|
||||||
* [GUI]* Windows: Add license to installer
|
* [GUI] Windows: Add license to installer
|
||||||
* [GUI]* owncloud --logwindow will bring up the log window
|
* [GUI] owncloud --logwindow will bring up the log window
|
||||||
* * * * in an already running instance
|
in an already running instance
|
||||||
* [Fixes] Make sure SSL errors are always handled
|
* [Fixes] Make sure SSL errors are always handled
|
||||||
* [Fixes] Allow special characters in folder alias
|
* [Fixes] Allow special characters in folder alias
|
||||||
* [Fixes] Proper workaround for Menu bug in Ubuntu
|
* [Fixes] Proper workaround for Menu bug in Ubuntu
|
||||||
* [Fixes] csync: Fix improper memory cleanup which could
|
* [Fixes] csync: Fix improper memory cleanup which could
|
||||||
* * * * cause memory leaks and crashes
|
cause memory leaks and crashes
|
||||||
* [Fixes] csync: Fix memory leak
|
* [Fixes] csync: Fix memory leak
|
||||||
* [Fixes] csync: Allow single quote (') in file names
|
* [Fixes] csync: Allow single quote (') in file names
|
||||||
* [Fixes] csync: Remove stray temporary files
|
* [Fixes] csync: Remove stray temporary files
|
||||||
|
|
||||||
* [GUI]* Reworked tray context menu.
|
* [GUI] Reworked tray context menu.
|
||||||
* [GUI]* Users can now sync the server root folder.
|
* [GUI] Users can now sync the server root folder.
|
||||||
* [Fixes] Proxy support: now supports Proxy Auto-Configuration (PAC)
|
* [Fixes] Proxy support: now supports Proxy Auto-Configuration (PAC)
|
||||||
* * * * on Windows, reliability fixes across all OSes.
|
on Windows, reliability fixes across all OSes.
|
||||||
* [Fixes] Url entry field in setup assistant handles http/https correctly.
|
* [Fixes] Url entry field in setup assistant handles http/https correctly.
|
||||||
* [Fixes] Button enable state in status dialog.
|
* [Fixes] Button enable state in status dialog.
|
||||||
* [Fixes] Crash fixed on ending the client, tray icon related.
|
* [Fixes] Crash fixed on ending the client, tray icon related.
|
||||||
@@ -1156,15 +978,11 @@ version 1.1.1 (release 2012-10-18), csync 0.60.1 required
|
|||||||
* [Platform] Windows: ownCloud gets added to autorun by default.
|
* [Platform] Windows: ownCloud gets added to autorun by default.
|
||||||
* [Platform] insert correct version info from cmake.
|
* [Platform] insert correct version info from cmake.
|
||||||
* [Platform] csync conf file and database were moved to the users app data
|
* [Platform] csync conf file and database were moved to the users app data
|
||||||
* * * * * directory, away from the .csync dir.
|
directory, away from the .csync dir.
|
||||||
** * * Renamed exclude.lst to sync-exclude.lst and moved it to
|
* Renamed exclude.lst to sync-exclude.lst and moved it to
|
||||||
* * * * /etc/appName()/ for more clean packaging. From the user path,
|
/etc/appName()/ for more clean packaging. From the user path,
|
||||||
* * * * still exclude.lst is read if sync-exclude.lst is not existing.
|
still exclude.lst is read if sync-exclude.lst is not existing.
|
||||||
** * * Placed custom.ini with customization options to /etc/appName()
|
* Placed custom.ini with customization options to /etc/appName()
|
||||||
|
|
||||||
|
|
||||||
1.0 Series ChangeLog
|
|
||||||
====================
|
|
||||||
|
|
||||||
version 1.0.5 (release 2012-08-14), csync 0.50.8 required
|
version 1.0.5 (release 2012-08-14), csync 0.50.8 required
|
||||||
* [Fixes] Fixed setup dialog: Really use https if checkbox is activated.
|
* [Fixes] Fixed setup dialog: Really use https if checkbox is activated.
|
||||||
@@ -1182,23 +1000,23 @@ version 1.0.4 (release 2012-08-10), csync 0.50.8 required
|
|||||||
* [GUI] Removed Log Window Button, log available through command line.
|
* [GUI] Removed Log Window Button, log available through command line.
|
||||||
* [GUI] Proxy configuration dialog added.
|
* [GUI] Proxy configuration dialog added.
|
||||||
* [GUI] Added Translations to languages Slovenian, Polish, Catalan,
|
* [GUI] Added Translations to languages Slovenian, Polish, Catalan,
|
||||||
* * * Portuguese (Brazil), German, Greek, Spanish, Czech, Italian, Slovak,
|
Portuguese (Brazil), German, Greek, Spanish, Czech, Italian, Slovak,
|
||||||
* * * French, Russian, Japanese, Swedish, Portuguese (Portugal)
|
French, Russian, Japanese, Swedish, Portuguese (Portugal)
|
||||||
* * * all with translation rate >90%.
|
all with translation rate >90%.
|
||||||
* [Fixes] Loading of self signed certs into Networkmanager (#oc-843)
|
* [Fixes] Loading of self signed certs into Networkmanager (#oc-843)
|
||||||
* [Fixes] Win32: Handle SSL dll loading correctly.
|
* [Fixes] Win32: Handle SSL dll loading correctly.
|
||||||
* [Fixes] Many other small fixes and improvements.
|
* [Fixes] Many other small fixes and improvements.
|
||||||
|
|
||||||
version 1.0.3 (release 2012-06-19), csync 0.50.7 required
|
version 1.0.3 (release 2012-06-19), csync 0.50.7 required
|
||||||
* [GUI] Added a log window which catches the logging if required and
|
* [GUI] Added a log window which catches the logging if required and
|
||||||
* * * allows to save for information.
|
allows to save for information.
|
||||||
* [CMI] Added options --help, --logfile and --logflush
|
* [CMI] Added options --help, --logfile and --logflush
|
||||||
* [APP] Allow to specify sync frequency in the config file.
|
* [APP] Allow to specify sync frequency in the config file.
|
||||||
* [Fixes] Do not use csync database files from a sync before.
|
* [Fixes] Do not use csync database files from a sync before.
|
||||||
* [Fixes] In Connection wizard, write the final config onyl if
|
* [Fixes] In Connection wizard, write the final config onyl if
|
||||||
* * * * the user really accepted. Also remove the former database.
|
the user really accepted. Also remove the former database.
|
||||||
* [Fixes] More user expected behaviour deletion of sync folder local
|
* [Fixes] More user expected behaviour deletion of sync folder local
|
||||||
* * * * and remote.
|
and remote.
|
||||||
* [Fixes] Allow special characters in the sync directory names
|
* [Fixes] Allow special characters in the sync directory names
|
||||||
* [Fixes] Win32: Fixed directory removal with special character dirs.
|
* [Fixes] Win32: Fixed directory removal with special character dirs.
|
||||||
* [Fixes] MacOS: Do not flood the system log any more
|
* [Fixes] MacOS: Do not flood the system log any more
|
||||||
@@ -1217,7 +1035,7 @@ version 1.0.2 (release 2012-05-18), csync 0.50.6 required
|
|||||||
* [Fixes] Dialogs comes to front on click
|
* [Fixes] Dialogs comes to front on click
|
||||||
* [Fixes] Open local sync folder from tray and status for win32
|
* [Fixes] Open local sync folder from tray and status for win32
|
||||||
* [Fixes] Load exclude.lst correctly on MacOSX
|
* [Fixes] Load exclude.lst correctly on MacOSX
|
||||||
* + csync fixes.
|
+ csync fixes.
|
||||||
|
|
||||||
version 1.0.1 (release 2012-04-18), csync 0.50.5 required
|
version 1.0.1 (release 2012-04-18), csync 0.50.5 required
|
||||||
* [Security] Support SSL Connections
|
* [Security] Support SSL Connections
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ set( APPLICATION_SHORTNAME "Nextcloud" )
|
|||||||
set( APPLICATION_EXECUTABLE "nextcloud" )
|
set( APPLICATION_EXECUTABLE "nextcloud" )
|
||||||
set( APPLICATION_DOMAIN "nextcloud.com" )
|
set( APPLICATION_DOMAIN "nextcloud.com" )
|
||||||
set( APPLICATION_VENDOR "Nextcloud GmbH" )
|
set( APPLICATION_VENDOR "Nextcloud GmbH" )
|
||||||
set( APPLICATION_UPDATE_URL "https://updates.nextcloud.org/client/" CACHE STRING "URL for updater" )
|
set( APPLICATION_UPDATE_URL "https://updates.nextcloud.org/client/" CACHE string "URL for updater" )
|
||||||
set( APPLICATION_HELP_URL "" CACHE STRING "URL for the help menu" )
|
set( APPLICATION_HELP_URL "" CACHE string "URL for the help menu" )
|
||||||
set( APPLICATION_ICON_NAME "Nextcloud" )
|
set( APPLICATION_ICON_NAME "Nextcloud" )
|
||||||
set( APPLICATION_SERVER_URL "" CACHE STRING "URL for the server to use. If entered the server can only connect to this instance" )
|
set( APPLICATION_SERVER_URL "" CACHE string "URL for the server to use. If entered the server can only connect to this instance" )
|
||||||
|
|
||||||
set( LINUX_PACKAGE_SHORTNAME "nextcloud" )
|
set( LINUX_PACKAGE_SHORTNAME "nextcloud" )
|
||||||
|
|
||||||
@@ -20,14 +20,14 @@ set( MAC_INSTALLER_BACKGROUND_FILE "${CMAKE_SOURCE_DIR}/admin/osx/installer-back
|
|||||||
# set( APPLICATION_LICENSE "${OEM_THEME_DIR}/license.txt )
|
# set( APPLICATION_LICENSE "${OEM_THEME_DIR}/license.txt )
|
||||||
|
|
||||||
option( WITH_CRASHREPORTER "Build crashreporter" OFF )
|
option( WITH_CRASHREPORTER "Build crashreporter" OFF )
|
||||||
#set( CRASHREPORTER_SUBMIT_URL "https://crash-reports.owncloud.com/submit" CACHE STRING "URL for crash reporter" )
|
#set( CRASHREPORTER_SUBMIT_URL "https://crash-reports.owncloud.com/submit" CACHE string "URL for crash reporter" )
|
||||||
#set( CRASHREPORTER_ICON ":/owncloud-icon.png" )
|
#set( CRASHREPORTER_ICON ":/owncloud-icon.png" )
|
||||||
|
|
||||||
option( WITH_PROVIDERS "Build with providers list" ON )
|
option( WITH_PROVIDERS "Build with providers list" ON )
|
||||||
|
|
||||||
|
|
||||||
## Theming options
|
## Theming options
|
||||||
set( APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR "#0082c9" CACHE STRING "Hex color of the wizard header background")
|
set( APPLICATION_WIZARD_HEADER_BACKGROUND_COLOR "#0082c9" CACHE string "Hex color of the wizard header background")
|
||||||
set( APPLICATION_WIZARD_HEADER_TITLE_COLOR "#ffffff" CACHE STRING "Hex color of the text in the wizard header")
|
set( APPLICATION_WIZARD_HEADER_TITLE_COLOR "#ffffff" CACHE string "Hex color of the text in the wizard header")
|
||||||
option( APPLICATION_WIZARD_USE_CUSTOM_LOGO "Use the logo from ':/client/theme/colored/wizard_logo.png' else the default application icon is used" ON )
|
option( APPLICATION_WIZARD_USE_CUSTOM_LOGO "Use the logo from ':/client/theme/colored/wizard_logo.png' else the default application icon is used" ON )
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
set( MIRALL_VERSION_MAJOR 2 )
|
set( MIRALL_VERSION_MAJOR 2 )
|
||||||
set( MIRALL_VERSION_MINOR 6 )
|
set( MIRALL_VERSION_MINOR 5 )
|
||||||
set( MIRALL_VERSION_PATCH 2 )
|
set( MIRALL_VERSION_PATCH 3 )
|
||||||
set( MIRALL_VERSION_YEAR 2019 )
|
set( MIRALL_VERSION_YEAR 2019 )
|
||||||
set( MIRALL_SOVERSION 0 )
|
set( MIRALL_SOVERSION 0 )
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ RUN apt-get update -q && DEBIAN_FRONTEND=noninteractive apt-get install -q -y --
|
|||||||
libsqlite3-dev \
|
libsqlite3-dev \
|
||||||
libssl-dev \
|
libssl-dev \
|
||||||
libcmocka-dev \
|
libcmocka-dev \
|
||||||
libcloudproviders-dev \
|
|
||||||
qt5-default \
|
qt5-default \
|
||||||
qttools5-dev-tools \
|
qttools5-dev-tools \
|
||||||
libqt5webkit5-dev \
|
libqt5webkit5-dev \
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ mkdir /app
|
|||||||
mkdir /build
|
mkdir /build
|
||||||
|
|
||||||
#Set Qt-5.12
|
#Set Qt-5.12
|
||||||
export QT_BASE_DIR=/opt/qt5.12.5
|
export QT_BASE_DIR=/opt/qt512
|
||||||
export QTDIR=$QT_BASE_DIR
|
export QTDIR=$QT_BASE_DIR
|
||||||
export PATH=$QT_BASE_DIR/bin:$PATH
|
export PATH=$QT_BASE_DIR/bin:$PATH
|
||||||
export LD_LIBRARY_PATH=$QT_BASE_DIR/lib/x86_64-linux-gnu:$QT_BASE_DIR/lib:$LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH=$QT_BASE_DIR/lib/x86_64-linux-gnu:$QT_BASE_DIR/lib:$LD_LIBRARY_PATH
|
||||||
@@ -66,8 +66,7 @@ rm -rf ./usr/share/nemo-python/
|
|||||||
mv ./etc/Nextcloud/sync-exclude.lst ./usr/bin/
|
mv ./etc/Nextcloud/sync-exclude.lst ./usr/bin/
|
||||||
rm -rf ./etc
|
rm -rf ./etc
|
||||||
|
|
||||||
DESKTOP_FILE=/app/usr/share/applications/${LINUX_APPLICATION_ID}.desktop
|
sed -i -e 's|Icon=nextcloud|Icon=Nextcloud|g' usr/share/applications/nextcloud.desktop # Bug in desktop file?
|
||||||
sed -i -e 's|Icon=nextcloud|Icon=Nextcloud|g' ${DESKTOP_FILE} # Bug in desktop file?
|
|
||||||
cp ./usr/share/icons/hicolor/512x512/apps/Nextcloud.png . # Workaround for linuxeployqt bug, FIXME
|
cp ./usr/share/icons/hicolor/512x512/apps/Nextcloud.png . # Workaround for linuxeployqt bug, FIXME
|
||||||
|
|
||||||
|
|
||||||
@@ -88,12 +87,17 @@ chmod a+x linuxdeployqt*.AppImage
|
|||||||
rm ./linuxdeployqt-continuous-x86_64.AppImage
|
rm ./linuxdeployqt-continuous-x86_64.AppImage
|
||||||
unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
|
unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
|
||||||
export LD_LIBRARY_PATH=/app/usr/lib/
|
export LD_LIBRARY_PATH=/app/usr/lib/
|
||||||
./squashfs-root/AppRun ${DESKTOP_FILE} -bundle-non-qt-libs
|
./squashfs-root/AppRun /app/usr/share/applications/nextcloud.desktop -bundle-non-qt-libs
|
||||||
|
|
||||||
# Set origin
|
# Set origin
|
||||||
./squashfs-root/usr/bin/patchelf --set-rpath '$ORIGIN/' /app/usr/lib/libnextcloudsync.so.0
|
./squashfs-root/usr/bin/patchelf --set-rpath '$ORIGIN/' /app/usr/lib/libnextcloudsync.so.0
|
||||||
|
|
||||||
# Build AppImage
|
# Build AppImage
|
||||||
./squashfs-root/AppRun ${DESKTOP_FILE} -appimage
|
./squashfs-root/AppRun /app/usr/share/applications/nextcloud.desktop -appimage
|
||||||
|
|
||||||
mv Nextcloud*.AppImage Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
|
mv Nextcloud*.AppImage Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
|
||||||
|
|
||||||
|
curl --upload-file $(readlink -f ./Nextcloud*.AppImage) https://transfer.sh/Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Get the AppImage at the link above!"
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
nextcloud-client (2.3.3-1.0~eoan1) eoan; urgency=medium
|
nextcloud-client (2.3.3-1.0~cosmic1) cosmic; urgency=medium
|
||||||
|
|
||||||
* Debian build support for the forked client.
|
* Debian build support for the forked client.
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Mon, 6 Nov 2017 20:20:04 +0100
|
-- István Váradi <ivaradi@varadiistvan.hu> Mon, 6 Nov 2017 20:20:04 +0100
|
||||||
|
|
||||||
nextcloud-client (2.3.1-1.0~eoan1) eoan; urgency=medium
|
nextcloud-client (2.3.1-1.0~cosmic1) cosmic; urgency=medium
|
||||||
|
|
||||||
* New upstream version
|
* New upstream version
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Thu, 23 Mar 2017 19:07:36 +0100
|
-- István Váradi <ivaradi@varadiistvan.hu> Thu, 23 Mar 2017 19:07:36 +0100
|
||||||
|
|
||||||
nextcloud-client (2.3.0-1.0~eoan1) eoan; urgency=medium
|
nextcloud-client (2.3.0-1.0~cosmic1) cosmic; urgency=medium
|
||||||
|
|
||||||
* New upstream version
|
* New upstream version
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 21 Mar 2017 19:34:13 +0100
|
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 21 Mar 2017 19:34:13 +0100
|
||||||
|
|
||||||
nextcloud-client (2.2.4-1.4~eoan1) eoan; urgency=medium
|
nextcloud-client (2.2.4-1.4~cosmic1) cosmic; urgency=medium
|
||||||
|
|
||||||
* The locale-specific icon names are correct too
|
* The locale-specific icon names are correct too
|
||||||
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
Source: nextcloud-client
|
|
||||||
Section: contrib/devel
|
|
||||||
Priority: optional
|
|
||||||
Maintainer: István Váradi <ivaradi@varadiistvan.hu>
|
|
||||||
Build-Depends: cmake,
|
|
||||||
debhelper,
|
|
||||||
cdbs,
|
|
||||||
dh-python,
|
|
||||||
extra-cmake-modules (>= 5.16),
|
|
||||||
libkf5kio-dev,
|
|
||||||
libcmocka-dev,
|
|
||||||
libcloudproviders-dev,
|
|
||||||
libdbus-1-dev,
|
|
||||||
libhttp-dav-perl,
|
|
||||||
libinotify-dev [kfreebsd-any],
|
|
||||||
libqt5svg5-dev,
|
|
||||||
libqt5webkit5-dev,
|
|
||||||
libsqlite3-dev,
|
|
||||||
libssl-dev (>= 1.1.0),
|
|
||||||
zlib1g-dev,
|
|
||||||
optipng,
|
|
||||||
pkg-kde-tools,
|
|
||||||
python-sphinx | python3-sphinx,
|
|
||||||
python3-all,
|
|
||||||
qt5keychain-dev,
|
|
||||||
qtwebengine5-dev,
|
|
||||||
qtdeclarative5-dev,
|
|
||||||
qttools5-dev,
|
|
||||||
qttools5-dev-tools,
|
|
||||||
xvfb
|
|
||||||
Standards-Version: 3.9.8
|
|
||||||
Homepage: https://github.com/nextcloud/client_theming
|
|
||||||
#Vcs-Git: git://anonscm.debian.org/collab-maint/nextcloud-client.git
|
|
||||||
#Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/nextcloud-client.git
|
|
||||||
|
|
||||||
Package: nextcloud-client
|
|
||||||
Architecture: any
|
|
||||||
Depends: libnextcloudsync0 (=${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, nextcloud-client-l10n
|
|
||||||
Description: Nextcloud desktop sync client
|
|
||||||
Use the desktop client to keep your files synchronized
|
|
||||||
between your Nextcloud server and your desktop. Select
|
|
||||||
one or more directories on your local machine and always
|
|
||||||
have access to your latest files wherever you are.
|
|
||||||
|
|
||||||
Package: libnextcloudsync0
|
|
||||||
Architecture: any
|
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
|
||||||
Description: Nextcloud sync library
|
|
||||||
Used by the Nextcloud desktop client as the synchronization engine.
|
|
||||||
|
|
||||||
Package: libnextcloudsync-dev
|
|
||||||
Architecture: any
|
|
||||||
Section: contrib/libdevel
|
|
||||||
Depends: libnextcloudsync0 (=${binary:Version}), ${misc:Depends}
|
|
||||||
Description: Nextcloud sync library development files
|
|
||||||
The headers and development library for the Nextcloud sync library.
|
|
||||||
|
|
||||||
Package: nextcloud-client-l10n
|
|
||||||
Architecture: all
|
|
||||||
Depends: ${misc:Depends}
|
|
||||||
Description: Nextcloud client internatialization files
|
|
||||||
The translation files.
|
|
||||||
|
|
||||||
Package: nextcloud-client-nautilus
|
|
||||||
Architecture: all
|
|
||||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-nautilus, nautilus, ${misc:Depends}
|
|
||||||
Description: Nautilus plugin for Nextcloud
|
|
||||||
This package contains a Nautilus plugin to display
|
|
||||||
synchronization status icons for Nextcloud files.
|
|
||||||
|
|
||||||
Package: nextcloud-client-nemo
|
|
||||||
Architecture: all
|
|
||||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-nemo | nemo-python, nemo, ${misc:Depends}
|
|
||||||
Description: Nemo plugin for Nextcloud
|
|
||||||
This package contains a Nemo plugin to display
|
|
||||||
synchronization status icons for Nextcloud files.
|
|
||||||
|
|
||||||
Package: nextcloud-client-caja
|
|
||||||
Architecture: all
|
|
||||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-caja, caja, ${misc:Depends}
|
|
||||||
Description: Caja plugin for Nextcloud
|
|
||||||
This package contains a Caja plugin to display
|
|
||||||
synchronization status icons for Nextcloud files.
|
|
||||||
|
|
||||||
Package: nextcloud-client-dolphin
|
|
||||||
Architecture: any
|
|
||||||
Depends: dolphin (>= 4:15.12.1), libnextcloudsync0 (= ${binary:Version}), nextcloud-client, ${misc:Depends}, ${shlibs:Depends}
|
|
||||||
Description: Dolphin plugin for Nextcloud
|
|
||||||
This package contains a Dolphin plugin to display
|
|
||||||
synchronization status icons for Nextcloud files.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
nextcloud-client (2.3.3-1.0~oldstable1) oldstable; urgency=medium
|
|
||||||
|
|
||||||
* Debian build support for the forked client.
|
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Mon, 6 Nov 2017 20:20:04 +0100
|
|
||||||
|
|
||||||
nextcloud-client (2.3.1-1.0) oldstable; urgency=medium
|
|
||||||
|
|
||||||
* New upstream version
|
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Thu, 23 Mar 2017 19:07:36 +0100
|
|
||||||
|
|
||||||
nextcloud-client (2.3.0-1.0) oldstable; urgency=medium
|
|
||||||
|
|
||||||
* New upstream version
|
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 21 Mar 2017 19:34:13 +0100
|
|
||||||
|
|
||||||
nextcloud-client (2.2.4-1.4) oldstable; urgency=medium
|
|
||||||
|
|
||||||
* The locale-specific icon names are correct too
|
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 7 Feb 2017 19:55:40 +0100
|
|
||||||
|
|
||||||
nextcloud-client (2.2.4-1.3) oldstable; urgency=medium
|
|
||||||
|
|
||||||
* Caja syncstate plugin is built.
|
|
||||||
* The syncstate plugin has application-specific name
|
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Fri, 27 Jan 2017 19:34:18 +0100
|
|
||||||
|
|
||||||
nextcloud-client (2.2.4-1.2) oldstable; urgency=medium
|
|
||||||
|
|
||||||
* Fixed appname in the Nemo syncstate extension.
|
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Thu, 19 Jan 2017 16:46:50 +0100
|
|
||||||
|
|
||||||
nextcloud-client (2.2.4-1.1) oldstable; urgency=medium
|
|
||||||
|
|
||||||
* Added Nautilus and Nemo syncstate extensions.
|
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 17 Jan 2017 19:55:32 +0100
|
|
||||||
|
|
||||||
nextcloud-client (2.2.4-1.0) oldstable; urgency=medium
|
|
||||||
|
|
||||||
* Initial release.
|
|
||||||
|
|
||||||
-- István Váradi <ivaradi@varadiistvan.hu> Wed, 14 Dec 2016 20:07:46 +0100
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
Source: nextcloud-client
|
|
||||||
Section: contrib/devel
|
|
||||||
Priority: optional
|
|
||||||
Maintainer: István Váradi <ivaradi@varadiistvan.hu>
|
|
||||||
Build-Depends: cmake,
|
|
||||||
debhelper,
|
|
||||||
cdbs,
|
|
||||||
dh-python,
|
|
||||||
extra-cmake-modules (>= 5.16),
|
|
||||||
kdelibs5-dev,
|
|
||||||
kio-dev,
|
|
||||||
libcmocka-dev,
|
|
||||||
libdbus-1-dev,
|
|
||||||
libhttp-dav-perl,
|
|
||||||
libinotify-dev [kfreebsd-any],
|
|
||||||
libqt5webkit5-dev,
|
|
||||||
libqt5svg5-dev,
|
|
||||||
libsqlite3-dev,
|
|
||||||
libssl-dev (>= 1.1.0),
|
|
||||||
zlib1g-dev,
|
|
||||||
optipng,
|
|
||||||
pkg-kde-tools,
|
|
||||||
python-sphinx | python3-sphinx,
|
|
||||||
python3-all,
|
|
||||||
qt5keychain-dev,
|
|
||||||
qtwebengine5-dev,
|
|
||||||
qtdeclarative5-dev,
|
|
||||||
qttools5-dev,
|
|
||||||
qttools5-dev-tools,
|
|
||||||
xvfb
|
|
||||||
Standards-Version: 3.9.8
|
|
||||||
Homepage: https://github.com/nextcloud/client_theming
|
|
||||||
#Vcs-Git: git://anonscm.debian.org/collab-maint/nextcloud-client.git
|
|
||||||
#Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/nextcloud-client.git
|
|
||||||
|
|
||||||
Package: nextcloud-client
|
|
||||||
Architecture: any
|
|
||||||
Depends: libnextcloudsync0 (=${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, nextcloud-client-l10n
|
|
||||||
Recommends: libgnome-keyring0
|
|
||||||
Description: Nextcloud desktop sync client
|
|
||||||
Use the desktop client to keep your files synchronized
|
|
||||||
between your Nextcloud server and your desktop. Select
|
|
||||||
one or more directories on your local machine and always
|
|
||||||
have access to your latest files wherever you are.
|
|
||||||
|
|
||||||
Package: libnextcloudsync0
|
|
||||||
Architecture: any
|
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
|
||||||
Description: Nextcloud sync library
|
|
||||||
Used by the Nextcloud desktop client as the synchronization engine.
|
|
||||||
|
|
||||||
Package: libnextcloudsync-dev
|
|
||||||
Architecture: any
|
|
||||||
Section: contrib/libdevel
|
|
||||||
Depends: libnextcloudsync0 (=${binary:Version}), ${misc:Depends}
|
|
||||||
Description: Nextcloud sync library development files
|
|
||||||
The headers and development library for the Nextcloud sync library.
|
|
||||||
|
|
||||||
Package: nextcloud-client-l10n
|
|
||||||
Architecture: all
|
|
||||||
Depends: ${misc:Depends}
|
|
||||||
Description: Nextcloud client internatialization files
|
|
||||||
The translation files.
|
|
||||||
|
|
||||||
Package: nextcloud-client-nautilus
|
|
||||||
Architecture: all
|
|
||||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-nautilus, nautilus, ${misc:Depends}
|
|
||||||
Description: Nautilus plugin for Nextcloud
|
|
||||||
This package contains a Nautilus plugin to display
|
|
||||||
synchronization status icons for Nextcloud files.
|
|
||||||
|
|
||||||
Package: nextcloud-client-nemo
|
|
||||||
Architecture: all
|
|
||||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-nemo, nemo, ${misc:Depends}
|
|
||||||
Description: Nemo plugin for Nextcloud
|
|
||||||
This package contains a Nemo plugin to display
|
|
||||||
synchronization status icons for Nextcloud files.
|
|
||||||
|
|
||||||
Package: nextcloud-client-caja
|
|
||||||
Architecture: all
|
|
||||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-caja, caja, ${misc:Depends}
|
|
||||||
Description: Caja plugin for Nextcloud
|
|
||||||
This package contains a Caja plugin to display
|
|
||||||
synchronization status icons for Nextcloud files.
|
|
||||||
@@ -9,10 +9,7 @@ Build-Depends: cmake,
|
|||||||
extra-cmake-modules (>= 5.16),
|
extra-cmake-modules (>= 5.16),
|
||||||
kdelibs5-dev,
|
kdelibs5-dev,
|
||||||
kio-dev,
|
kio-dev,
|
||||||
libavcodec58,
|
|
||||||
libcmocka-dev,
|
libcmocka-dev,
|
||||||
libcloudproviders-dev,
|
|
||||||
libdbus-1-dev,
|
|
||||||
libhttp-dav-perl,
|
libhttp-dav-perl,
|
||||||
libinotify-dev [kfreebsd-any],
|
libinotify-dev [kfreebsd-any],
|
||||||
libqt5webkit5-dev,
|
libqt5webkit5-dev,
|
||||||
|
|||||||
@@ -1,12 +1,40 @@
|
|||||||
--- nextcloud-client-2.5.3.orig/src/3rdparty/kmessagewidget/kmessagewidget.cpp 2019-07-26 18:40:34.949349387 +0000
|
--- nextcloud-client-2.4.0.orig/src/gui/wizard/owncloudoauthcredspage.cpp
|
||||||
+++ nextcloud-client-2.5.3/src/3rdparty/kmessagewidget/kmessagewidget.cpp 2019-07-26 18:41:39.866478051 +0000
|
+++ nextcloud-client-2.4.0/src/gui/wizard/owncloudoauthcredspage.cpp
|
||||||
@@ -105,6 +105,9 @@
|
@@ -53,10 +53,8 @@ OwncloudOAuthCredsPage::OwncloudOAuthCredsPage()
|
||||||
q->setMessageType(KMessageWidget::Information);
|
_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));
|
||||||
|
- });
|
||||||
|
+ auto action = menu->addAction(tr("Copy link to clipboard"));
|
||||||
|
+ connect(action, &QAction::triggered, this, &OwncloudOAuthCredsPage::copyLinkToClipboard);
|
||||||
|
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
menu->popup(_ui.openLinkButton->mapToGlobal(pos));
|
||||||
|
});
|
||||||
|
@@ -131,4 +129,11 @@ bool OwncloudOAuthCredsPage::isComplete() const
|
||||||
|
return false; /* We can never go forward manually */
|
||||||
}
|
}
|
||||||
|
|
||||||
+template <typename T>
|
+void OwncloudOAuthCredsPage::copyLinkToClipboard()
|
||||||
+constexpr typename std::add_const<T>::type &qAsConst(T &t) noexcept { return t; }
|
+{
|
||||||
|
+ if (_asyncAuth)
|
||||||
|
+ QApplication::clipboard()->setText(_asyncAuth->authorisationLink().toString(QUrl::FullyEncoded));
|
||||||
|
+}
|
||||||
+
|
+
|
||||||
void KMessageWidgetPrivate::createLayout()
|
+
|
||||||
{
|
} // namespace OCC
|
||||||
delete content->layout();
|
--- nextcloud-client-2.4.0.orig/src/gui/wizard/owncloudoauthcredspage.h
|
||||||
|
+++ nextcloud-client-2.4.0/src/gui/wizard/owncloudoauthcredspage.h
|
||||||
|
@@ -57,6 +57,10 @@ public:
|
||||||
|
QString _refreshToken;
|
||||||
|
QScopedPointer<OAuth> _asyncAuth;
|
||||||
|
Ui_OwncloudOAuthCredsPage _ui;
|
||||||
|
+
|
||||||
|
+protected slots:
|
||||||
|
+ void copyLinkToClipboard();
|
||||||
|
+
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace OCC
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ Build-Depends: cmake,
|
|||||||
kdelibs5-dev,
|
kdelibs5-dev,
|
||||||
libkf5kio-dev,
|
libkf5kio-dev,
|
||||||
libcmocka-dev,
|
libcmocka-dev,
|
||||||
libcloudproviders-dev,
|
|
||||||
libdbus-1-dev,
|
|
||||||
libhttp-dav-perl,
|
libhttp-dav-perl,
|
||||||
libinotify-dev [kfreebsd-any],
|
libinotify-dev [kfreebsd-any],
|
||||||
libqt5svg5-dev,
|
libqt5svg5-dev,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ if ! wget http://ppa.launchpad.net/${repo}/ubuntu/pool/main/n/nextcloud-client/n
|
|||||||
origsourceopt="-sa"
|
origsourceopt="-sa"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for distribution in xenial bionic disco eoan stable oldstable; do
|
for distribution in xenial bionic cosmic disco stable; do
|
||||||
rm -rf nextcloud-client_${basever}
|
rm -rf nextcloud-client_${basever}
|
||||||
cp -a ${DRONE_WORKSPACE} nextcloud-client_${basever}
|
cp -a ${DRONE_WORKSPACE} nextcloud-client_${basever}
|
||||||
|
|
||||||
@@ -98,46 +98,26 @@ if test "${pull_request}" = "master"; then
|
|||||||
PPA=$PPA_BETA
|
PPA=$PPA_BETA
|
||||||
OBS_PROJECT=$OBS_PROJECT_BETA
|
OBS_PROJECT=$OBS_PROJECT_BETA
|
||||||
fi
|
fi
|
||||||
|
OBS_SUBDIR="${OBS_PROJECT}/${OBS_PACKAGE}"
|
||||||
|
|
||||||
if test -f ~/.has_ppa_keys; then
|
if test -f ~/.has_ppa_keys; then
|
||||||
for changes in nextcloud-client_*~+([a-z])1_source.changes; do
|
for changes in nextcloud-client_*~+([a-z])1_source.changes; do
|
||||||
case "${changes}" in
|
dput $PPA $changes > /dev/null
|
||||||
*oldstable1*)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
dput $PPA $changes > /dev/null
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
done
|
||||||
|
|
||||||
for distribution in stable oldstable; do
|
mkdir osc
|
||||||
if test "${distribution}" = "oldstable"; then
|
cd osc
|
||||||
pkgsuffix=".${distribution}"
|
osc co ${OBS_PROJECT} ${OBS_PACKAGE}
|
||||||
pkgvertag="~${distribution}1"
|
if test "$(ls ${OBS_SUBDIR})"; then
|
||||||
else
|
osc delete ${OBS_SUBDIR}/*
|
||||||
pkgsuffix=""
|
fi
|
||||||
pkgvertag=""
|
cp ../nextcloud-client*.orig.tar.* ${OBS_SUBDIR}/
|
||||||
fi
|
cp ../nextcloud-client_*[0-9.][0-9].dsc ${OBS_SUBDIR}/
|
||||||
|
cp ../nextcloud-client_*[0-9.][0-9].debian.tar* ${OBS_SUBDIR}/
|
||||||
|
cp ../nextcloud-client_*[0-9.][0-9]_source.changes ${OBS_SUBDIR}/
|
||||||
|
osc add ${OBS_SUBDIR}/*
|
||||||
|
|
||||||
package="${OBS_PACKAGE}${pkgsuffix}"
|
cd ${OBS_SUBDIR}
|
||||||
OBS_SUBDIR="${OBS_PROJECT}/${package}"
|
osc commit -m "Travis update"
|
||||||
|
|
||||||
mkdir -p osc
|
|
||||||
pushd osc
|
|
||||||
osc co ${OBS_PROJECT} ${package}
|
|
||||||
if test "$(ls ${OBS_SUBDIR})"; then
|
|
||||||
osc delete ${OBS_SUBDIR}/*
|
|
||||||
fi
|
|
||||||
|
|
||||||
cp ../nextcloud-client*.orig.tar.* ${OBS_SUBDIR}/
|
|
||||||
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}.dsc ${OBS_SUBDIR}/
|
|
||||||
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}.debian.tar* ${OBS_SUBDIR}/
|
|
||||||
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}_source.changes ${OBS_SUBDIR}/
|
|
||||||
osc add ${OBS_SUBDIR}/*
|
|
||||||
|
|
||||||
cd ${OBS_SUBDIR}
|
|
||||||
osc commit -m "Travis update"
|
|
||||||
popd
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -70,9 +70,7 @@ def collectEntries(baseCommit, baseVersion, kind):
|
|||||||
lastVersionTag = None
|
lastVersionTag = None
|
||||||
lastCMAKEVersion = None
|
lastCMAKEVersion = None
|
||||||
for line in output.splitlines():
|
for line in output.splitlines():
|
||||||
words = line.split("\t")
|
(commit, name, email, date, revdate, subject) = line.split("\t")
|
||||||
(commit, name, email, date, revdate) = words[0:5]
|
|
||||||
subject = "\t".join(words[5:])
|
|
||||||
revdate = datetime.datetime.utcfromtimestamp(long(revdate)).strftime("%Y%m%d.%H%M%S")
|
revdate = datetime.datetime.utcfromtimestamp(long(revdate)).strftime("%Y%m%d.%H%M%S")
|
||||||
|
|
||||||
kind = "beta"
|
kind = "beta"
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#! /bin/bash
|
|
||||||
|
|
||||||
set -xe
|
|
||||||
|
|
||||||
cd /build
|
|
||||||
|
|
||||||
# Upload AppImage
|
|
||||||
APPIMAGE=$(readlink -f ./Nextcloud*.AppImage)
|
|
||||||
BASENAME=$(basename ${APPIMAGE})
|
|
||||||
|
|
||||||
if curl --max-time 900 --upload-file ${APPIMAGE} https://transfer.sh/${BASENAME}
|
|
||||||
then
|
|
||||||
echo
|
|
||||||
echo "Get the AppImage at the link above!"
|
|
||||||
else
|
|
||||||
echo
|
|
||||||
echo "Upload failed, however this is an optional step."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Don't let the Drone build fail
|
|
||||||
exit 0
|
|
||||||
@@ -49,7 +49,7 @@ fi
|
|||||||
if [ ! -z "$identity" ]; then
|
if [ ! -z "$identity" ]; then
|
||||||
echo "Will try to sign the installer"
|
echo "Will try to sign the installer"
|
||||||
pushd $install_path
|
pushd $install_path
|
||||||
productsign --timestamp --sign "$identity" "$installer_file" "$installer_file.new"
|
productsign --sign "$identity" "$installer_file" "$installer_file.new"
|
||||||
mv "$installer_file".new "$installer_file"
|
mv "$installer_file".new "$installer_file"
|
||||||
popd
|
popd
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -32,12 +32,11 @@ FRAMEWORK_SEARCH_PATH=[
|
|||||||
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
os.path.join(os.environ['HOME'], 'Library/Frameworks')
|
||||||
]
|
]
|
||||||
|
|
||||||
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.12.5/lib', '.']
|
LIBRARY_SEARCH_PATH=['/usr/local/lib', '/usr/local/Qt-5.6.2/lib', '.']
|
||||||
|
|
||||||
QT_PLUGINS = [
|
QT_PLUGINS = [
|
||||||
'sqldrivers/libqsqlite.dylib',
|
'sqldrivers/libqsqlite.dylib',
|
||||||
'platforms/libqcocoa.dylib',
|
'platforms/libqcocoa.dylib',
|
||||||
'styles/libqmacstyle.dylib',
|
|
||||||
'imageformats/libqgif.dylib',
|
'imageformats/libqgif.dylib',
|
||||||
'imageformats/libqico.dylib',
|
'imageformats/libqico.dylib',
|
||||||
'imageformats/libqjpeg.dylib',
|
'imageformats/libqjpeg.dylib',
|
||||||
@@ -47,7 +46,7 @@ QT_PLUGINS = [
|
|||||||
QT_PLUGINS_SEARCH_PATH=[
|
QT_PLUGINS_SEARCH_PATH=[
|
||||||
# os.path.join(os.environ['QTDIR'], 'plugins'),
|
# os.path.join(os.environ['QTDIR'], 'plugins'),
|
||||||
# '/usr/local/Cellar/qt/5.2.1/plugins',
|
# '/usr/local/Cellar/qt/5.2.1/plugins',
|
||||||
'/usr/local/Qt-5.12.5/plugins',
|
'/usr/local/Qt-5.6.2/plugins',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 254 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
2
binary
@@ -38,7 +38,6 @@
|
|||||||
<file>resources/copy.svg</file>
|
<file>resources/copy.svg</file>
|
||||||
<file>resources/state-sync.svg</file>
|
<file>resources/state-sync.svg</file>
|
||||||
<file>resources/add.png</file>
|
<file>resources/add.png</file>
|
||||||
<file>resources/state-info.svg</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/"/>
|
<qresource prefix="/"/>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -47,13 +47,7 @@ macro (KDE4_ADD_APP_ICON appsources pattern)
|
|||||||
endif (fn MATCHES ".*128.*")
|
endif (fn MATCHES ".*128.*")
|
||||||
if (fn MATCHES ".*256.*" )
|
if (fn MATCHES ".*256.*" )
|
||||||
list (APPEND _icons ${it})
|
list (APPEND _icons ${it})
|
||||||
endif (fn MATCHES ".*256.*")
|
endif (fn MATCHES ".*256.*")
|
||||||
if (fn MATCHES ".*512.*" )
|
|
||||||
list (APPEND _icons ${it})
|
|
||||||
endif (fn MATCHES ".*512.*")
|
|
||||||
if (fn MATCHES ".*1024.*" )
|
|
||||||
list (APPEND _icons ${it})
|
|
||||||
endif (fn MATCHES ".*1024.*")
|
|
||||||
endforeach (it)
|
endforeach (it)
|
||||||
if (_icons)
|
if (_icons)
|
||||||
add_custom_command(OUTPUT ${_outfilename}.ico ${_outfilename}.rc
|
add_custom_command(OUTPUT ${_outfilename}.ico ${_outfilename}.rc
|
||||||
@@ -110,14 +104,14 @@ macro (KDE4_ADD_APP_ICON appsources pattern)
|
|||||||
foreach (it ${files})
|
foreach (it ${files})
|
||||||
if (it MATCHES ".*sidebar-16.*")
|
if (it MATCHES ".*sidebar-16.*")
|
||||||
configure_file(${it} ${appsources}.iconset/sidebar_16x16.png COPYONLY)
|
configure_file(${it} ${appsources}.iconset/sidebar_16x16.png COPYONLY)
|
||||||
elseif (it MATCHES ".*sidebar-32.*")
|
elseif (it MATCHES ".*sidebar-18.*")
|
||||||
configure_file(${it} ${appsources}.iconset/sidebar_18x18.png COPYONLY)
|
configure_file(${it} ${appsources}.iconset/sidebar_18x18.png COPYONLY)
|
||||||
|
elseif (it MATCHES ".*sidebar-32.*")
|
||||||
configure_file(${it} ${appsources}.iconset/sidebar_16x16@2x.png COPYONLY)
|
configure_file(${it} ${appsources}.iconset/sidebar_16x16@2x.png COPYONLY)
|
||||||
elseif (it MATCHES ".*sidebar-64.*")
|
|
||||||
configure_file(${it} ${appsources}.iconset/sidebar_18x18@2x.png COPYONLY)
|
|
||||||
elseif (it MATCHES ".*sidebar-128.*")
|
|
||||||
configure_file(${it} ${appsources}.iconset/sidebar_32x32.png COPYONLY)
|
configure_file(${it} ${appsources}.iconset/sidebar_32x32.png COPYONLY)
|
||||||
elseif (it MATCHES ".*sidebar-256.*")
|
elseif (it MATCHES ".*sidebar-36.*")
|
||||||
|
configure_file(${it} ${appsources}.iconset/sidebar_18x18@2x.png COPYONLY)
|
||||||
|
elseif (it MATCHES ".*sidebar-64.*")
|
||||||
configure_file(${it} ${appsources}.iconset/sidebar_32x32@2x.png COPYONLY)
|
configure_file(${it} ${appsources}.iconset/sidebar_32x32@2x.png COPYONLY)
|
||||||
endif()
|
endif()
|
||||||
endforeach (it)
|
endforeach (it)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
#
|
#
|
||||||
# ecm_add_app_icon(<sources_var>
|
# ecm_add_app_icon(<sources_var>
|
||||||
# ICONS <icon> [<icon> [...]]
|
# ICONS <icon> [<icon> [...]]
|
||||||
# [SIDEBAR_ICONS <icon> [<icon> [...]] # Since 5.49
|
# [SIDEBAR_ICONS <icon> [<icon> [...]] # Since 5.4x
|
||||||
# [OUTFILE_BASENAME <name>]) # Since 5.49
|
# [OUTFILE_BASE <name>]) # Since 5.4x
|
||||||
# )
|
# )
|
||||||
#
|
#
|
||||||
# The given icons, whose names must match the pattern::
|
# The given icons, whose names must match the pattern::
|
||||||
@@ -27,21 +27,20 @@
|
|||||||
#
|
#
|
||||||
# ``SIDEBAR_ICONS`` can be used to add Mac OS X sidebar
|
# ``SIDEBAR_ICONS`` can be used to add Mac OS X sidebar
|
||||||
# icons to the generated iconset. They are used when a folder monitored by the
|
# icons to the generated iconset. They are used when a folder monitored by the
|
||||||
# application is dragged into Finder's sidebar. Since 5.49.
|
# application is dragged into Finder's sidebar. Since 5.4x.
|
||||||
#
|
#
|
||||||
# ``OUTFILE_BASENAME`` will be used as the basename for the icon file. If
|
# ``OUTFILE_BASE`` will be used as the basename for the icon file. If
|
||||||
# you specify it, the icon file will be called ``<OUTFILE_BASENAME>.icns`` on Mac OS X
|
# you specify it, the icon file will be called ``<OUTFILE_BASE>.icns`` on Mac OS X
|
||||||
# and ``<OUTFILE_BASENAME>.ico`` on Windows. If you don't specify it, it defaults
|
# and ``<OUTFILE_BASE>.ico`` on Windows. If you don't specify it, it defaults
|
||||||
# to ``<sources_var>.<ext>``. Since 5.49.
|
# to ``<sources_var>.<ext>``. Since 5.4x.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# Windows notes
|
# Windows notes
|
||||||
# * Icons are compiled into the executable using a resource file.
|
# * Icons are compiled into the executable using a resource file.
|
||||||
# * Icons may not show up in Windows Explorer if the executable
|
# * Icons may not show up in Windows Explorer if the executable
|
||||||
# target does not have the ``WIN32_EXECUTABLE`` property set.
|
# target does not have the ``WIN32_EXECUTABLE`` property set.
|
||||||
# * One of the tools png2ico (See :find-module:`FindPng2Ico`) or
|
# * The tool png2ico is required. See :find-module:`FindPng2Ico`.
|
||||||
# icotool (see :find-module:`FindIcoTool`) is required.
|
# * Supported sizes: 16, 32, 48, 64, 128.
|
||||||
# * Supported sizes: 16, 24, 32, 48, 64, 128, 256, 512 and 1024.
|
|
||||||
#
|
#
|
||||||
# Mac OS X notes
|
# Mac OS X notes
|
||||||
# * The executable target must have the ``MACOSX_BUNDLE`` property set.
|
# * The executable target must have the ``MACOSX_BUNDLE`` property set.
|
||||||
@@ -102,7 +101,7 @@ include(CMakeParseArguments)
|
|||||||
|
|
||||||
function(ecm_add_app_icon appsources)
|
function(ecm_add_app_icon appsources)
|
||||||
set(options)
|
set(options)
|
||||||
set(oneValueArgs OUTFILE_BASENAME)
|
set(oneValueArgs OUTFILE_BASE)
|
||||||
set(multiValueArgs ICONS SIDEBAR_ICONS)
|
set(multiValueArgs ICONS SIDEBAR_ICONS)
|
||||||
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
@@ -139,9 +138,9 @@ function(ecm_add_app_icon appsources)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
_ecm_add_app_icon_categorize_icons("${ARG_ICONS}" "icons" "16;24;32;48;64;128;256;512;1024")
|
_ecm_add_app_icon_categorize_icons("${ARG_ICONS}" "icons" "16;32;48;64;128;256;512;1024")
|
||||||
if(ARG_SIDEBAR_ICONS)
|
if(ARG_SIDEBAR_ICONS)
|
||||||
_ecm_add_app_icon_categorize_icons("${ARG_SIDEBAR_ICONS}" "sidebar_icons" "16;32;64;128;256")
|
_ecm_add_app_icon_categorize_icons("${ARG_SIDEBAR_ICONS}" "sidebar_icons" "16;18;32;36;64")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(mac_icons
|
set(mac_icons
|
||||||
@@ -152,37 +151,31 @@ function(ecm_add_app_icon appsources)
|
|||||||
${icons_at_128px}
|
${icons_at_128px}
|
||||||
${icons_at_256px}
|
${icons_at_256px}
|
||||||
${icons_at_512px}
|
${icons_at_512px}
|
||||||
${icons_at_1024px})
|
${icons_at_1024px}
|
||||||
|
|
||||||
set(mac_sidebar_icons
|
|
||||||
# Sidebar Icons: https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
|
# Sidebar Icons: https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
|
||||||
${sidebar_icons_at_16px}
|
${sidebar_icons_at_16px}
|
||||||
|
${sidebar_icons_at_18px}
|
||||||
${sidebar_icons_at_32px}
|
${sidebar_icons_at_32px}
|
||||||
${sidebar_icons_at_64px}
|
${sidebar_icons_at_36px}
|
||||||
${sidebar_icons_at_128px}
|
${sidebar_icons_at_64px})
|
||||||
${sidebar_icons_at_256px})
|
if (NOT icons_at_128px)
|
||||||
|
message(AUTHOR_WARNING "No 128px icon provided; this will not work on Mac OS X")
|
||||||
if (NOT (mac_icons OR mac_sidebar_icons))
|
|
||||||
message(AUTHOR_WARNING "No icons suitable for use on macOS provided")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
set(windows_icons ${icons_at_16px}
|
set(windows_icons ${icons_at_16px}
|
||||||
${icons_at_24px}
|
${icons_at_32px}
|
||||||
${icons_at_32px}
|
${icons_at_48px}
|
||||||
${icons_at_48px}
|
${icons_at_64px}
|
||||||
${icons_at_64px}
|
${icons_at_128px}
|
||||||
${icons_at_128px}
|
${icons_at_256px})
|
||||||
${icons_at_256px}
|
if (NOT windows_icons)
|
||||||
${icons_at_512px}
|
|
||||||
${icons_at_1024px})
|
|
||||||
|
|
||||||
if (NOT (windows_icons))
|
|
||||||
message(AUTHOR_WARNING "No icons suitable for use on Windows provided")
|
message(AUTHOR_WARNING "No icons suitable for use on Windows provided")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARG_OUTFILE_BASENAME)
|
if (ARG_OUTFILE_BASE)
|
||||||
set (_outfilebasename "${ARG_OUTFILE_BASENAME}")
|
set (_outfilebasename "${ARG_OUTFILE_BASE}")
|
||||||
else()
|
else()
|
||||||
set (_outfilebasename "${appsources}")
|
set (_outfilebasename "${appsources}")
|
||||||
endif()
|
endif()
|
||||||
@@ -192,15 +185,26 @@ function(ecm_add_app_icon appsources)
|
|||||||
set(saved_CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}")
|
set(saved_CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}")
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_FIND_MODULE_DIR})
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_FIND_MODULE_DIR})
|
||||||
find_package(Png2Ico)
|
find_package(Png2Ico)
|
||||||
find_package(IcoTool)
|
|
||||||
set(CMAKE_MODULE_PATH "${saved_CMAKE_MODULE_PATH}")
|
set(CMAKE_MODULE_PATH "${saved_CMAKE_MODULE_PATH}")
|
||||||
|
|
||||||
function(create_windows_icon_and_rc command args deps)
|
if (Png2Ico_FOUND)
|
||||||
|
if (Png2Ico_HAS_RCFILE_ARGUMENT)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${_outfilename}.rc" "${_outfilename}.ico"
|
||||||
|
COMMAND Png2Ico::Png2Ico
|
||||||
|
ARGS
|
||||||
|
--rcfile "${_outfilename}.rc"
|
||||||
|
"${_outfilename}.ico"
|
||||||
|
${windows_icons}
|
||||||
|
DEPENDS ${windows_icons}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
)
|
||||||
|
else()
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT "${_outfilename}.ico"
|
OUTPUT "${_outfilename}.ico"
|
||||||
COMMAND ${command}
|
COMMAND Png2Ico::Png2Ico
|
||||||
ARGS ${args}
|
ARGS "${_outfilename}.ico" ${windows_icons}
|
||||||
DEPENDS ${deps}
|
DEPENDS ${windows_icons}
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
)
|
)
|
||||||
# this bit's a little hacky to make the dependency stuff work
|
# this bit's a little hacky to make the dependency stuff work
|
||||||
@@ -212,72 +216,12 @@ function(ecm_add_app_icon appsources)
|
|||||||
DEPENDS "${_outfilename}.ico"
|
DEPENDS "${_outfilename}.ico"
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
)
|
)
|
||||||
endfunction()
|
endif()
|
||||||
|
|
||||||
if (IcoTool_FOUND)
|
|
||||||
list(APPEND icotool_args "-c" "-o" "${_outfilename}.ico")
|
|
||||||
|
|
||||||
# According to https://stackoverflow.com/a/40851713/2886832
|
|
||||||
# Windows always chooses the first icon above 255px, all other ones will be ignored
|
|
||||||
set(maxSize 0)
|
|
||||||
foreach(size 256 512 1024)
|
|
||||||
if(icons_at_${size}px)
|
|
||||||
set(maxSize "${size}")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
foreach(size 16 24 32 48 64 128 ${maxSize})
|
|
||||||
if(NOT icons_at_${size}px)
|
|
||||||
continue()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(icotool_icon_arg "")
|
|
||||||
if(size STREQUAL "${maxSize}")
|
|
||||||
# maxSize icon needs to be included as raw png
|
|
||||||
list(APPEND icotool_args "-r")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
foreach(icon ${icons_at_${size}px})
|
|
||||||
list(APPEND icotool_args "${icons_at_${size}px}")
|
|
||||||
endforeach()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
create_windows_icon_and_rc(IcoTool::IcoTool "${icotool_args}" "${windows_icons_modern}")
|
|
||||||
set(${appsources} "${${appsources}};${_outfilename}.rc" PARENT_SCOPE)
|
set(${appsources} "${${appsources}};${_outfilename}.rc" PARENT_SCOPE)
|
||||||
|
|
||||||
# standard png2ico has no rcfile argument
|
|
||||||
# NOTE: We generally use https://github.com/hiiamok/png2ImageMagickICO
|
|
||||||
# or similar on windows, which is why we provide resolutions >= 256px here.
|
|
||||||
# Standard png2ico will fail with this.
|
|
||||||
elseif(Png2Ico_FOUND AND NOT Png2Ico_HAS_RCFILE_ARGUMENT AND windows_icons)
|
|
||||||
set(png2ico_args)
|
|
||||||
list(APPEND png2ico_args "${_outfilename}.ico")
|
|
||||||
list(APPEND png2ico_args "${windows_icons}")
|
|
||||||
create_windows_icon_and_rc(Png2Ico::Png2Ico "${png2ico_args}" "${windows_icons}")
|
|
||||||
|
|
||||||
set(${appsources} "${${appsources}};${_outfilename}.rc" PARENT_SCOPE)
|
|
||||||
|
|
||||||
# png2ico from kdewin provides rcfile argument
|
|
||||||
elseif(Png2Ico_FOUND AND windows_icons)
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT "${_outfilename}.rc" "${_outfilename}.ico"
|
|
||||||
COMMAND Png2Ico::Png2Ico
|
|
||||||
ARGS
|
|
||||||
--rcfile "${_outfilename}.rc"
|
|
||||||
"${_outfilename}.ico"
|
|
||||||
${windows_icons}
|
|
||||||
DEPENDS ${windows_icons}
|
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
)
|
|
||||||
|
|
||||||
set(${appsources} "${${appsources}};${_outfilename}.rc" PARENT_SCOPE)
|
|
||||||
|
|
||||||
# else none of the supported tools was found
|
|
||||||
else()
|
else()
|
||||||
message(WARNING "Unable to find the png2ico or icotool utilities or icons in matching sizes - application will not have an application icon!")
|
message(WARNING "Unable to find the png2ico utility - application will not have an application icon!")
|
||||||
endif()
|
endif()
|
||||||
|
elseif (APPLE AND mac_icons)
|
||||||
elseif (APPLE AND (mac_icons OR mac_sidebar_icons))
|
|
||||||
# first generate .iconset directory structure, then convert to .icns format using the Mac OS X "iconutil" utility,
|
# first generate .iconset directory structure, then convert to .icns format using the Mac OS X "iconutil" utility,
|
||||||
# to create retina compatible icon, you need png source files in pixel resolution 16x16, 32x32, 64x64, 128x128,
|
# to create retina compatible icon, you need png source files in pixel resolution 16x16, 32x32, 64x64, 128x128,
|
||||||
# 256x256, 512x512, 1024x1024
|
# 256x256, 512x512, 1024x1024
|
||||||
@@ -302,11 +246,8 @@ function(ecm_add_app_icon appsources)
|
|||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
)
|
)
|
||||||
list(APPEND iconset_icons
|
list(APPEND iconset_icons
|
||||||
"${_outfilename}.iconset/${type}_${sizename}.png")
|
"${_outfilename}.iconset/${type}_${sizename}.png")
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
# List of supported sizes and filenames taken from:
|
|
||||||
# https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW4
|
|
||||||
foreach(size 16 32 128 256 512)
|
foreach(size 16 32 128 256 512)
|
||||||
math(EXPR double_size "2 * ${size}")
|
math(EXPR double_size "2 * ${size}")
|
||||||
foreach(file ${icons_at_${size}px})
|
foreach(file ${icons_at_${size}px})
|
||||||
@@ -317,25 +258,14 @@ function(ecm_add_app_icon appsources)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# List of supported sizes and filenames taken from:
|
foreach(size 16 18 32)
|
||||||
# https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
|
math(EXPR double_size "2 * ${size}")
|
||||||
foreach(file ${sidebar_icons_at_16px})
|
foreach(file ${sidebar_icons_at_${size}px})
|
||||||
copy_icon("${file}" "16x16" "sidebar")
|
copy_icon("${file}" "${size}x${size}" "sidebar")
|
||||||
endforeach()
|
endforeach()
|
||||||
foreach(file ${sidebar_icons_at_32px})
|
foreach(file ${sidebar_icons_at_${double_size}px})
|
||||||
copy_icon("${file}" "16x16@2x" "sidebar")
|
copy_icon("${file}" "${size}x${size}@2x" "sidebar")
|
||||||
endforeach()
|
endforeach()
|
||||||
foreach(file ${sidebar_icons_at_32px})
|
|
||||||
copy_icon("${file}" "18x18" "sidebar")
|
|
||||||
endforeach()
|
|
||||||
foreach(file ${sidebar_icons_at_64px})
|
|
||||||
copy_icon("${file}" "18x18@2x" "sidebar")
|
|
||||||
endforeach()
|
|
||||||
foreach(file ${sidebar_icons_at_128px})
|
|
||||||
copy_icon("${file}" "32x32" "sidebar")
|
|
||||||
endforeach()
|
|
||||||
foreach(file ${sidebar_icons_at_256px})
|
|
||||||
copy_icon("${file}" "32x32@2x" "sidebar")
|
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# generate .icns icon file
|
# generate .icns icon file
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>@MIRALL_VERSION_STRING@</string>
|
<string>@MIRALL_VERSION_STRING@</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>(C) 2014-2019 @APPLICATION_VENDOR@</string>
|
<string>(C) 2014-2018 @APPLICATION_VENDOR@</string>
|
||||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>SUShowReleaseNotes</key>
|
<key>SUShowReleaseNotes</key>
|
||||||
|
|||||||
@@ -3,11 +3,7 @@
|
|||||||
# For details see the accompanying COPYING* file.
|
# For details see the accompanying COPYING* file.
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wno-gnu-zero-variadic-macro-arguments")
|
||||||
# Use this only for Clang
|
|
||||||
if (CMAKE_CXX_COMPILER MATCHES "Clang")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-long-long -Wno-gnu-zero-variadic-macro-arguments")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Fix sqlite compilation on macOS
|
# Fix sqlite compilation on macOS
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers")
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ Activity
|
|||||||
.. index:: activity, recent changes, sync activity
|
.. index:: activity, recent changes, sync activity
|
||||||
|
|
||||||
The Activity window, which can be invoked either from the main menu (``Recent
|
The Activity window, which can be invoked either from the main menu (``Recent
|
||||||
Changes -> View more activity…``) or the Activity tab on the left side of the settings
|
Changes -> Details…``) or the Activity tab on the left side of the settings
|
||||||
window, provides an in-depth account of the recent sync activity. It will show
|
window, provides an in-depth account of the recent sync activity. It will show
|
||||||
files that have not been synced because they are on the ignored files list, or
|
files that have not been synced because they are on the ignored files list, or
|
||||||
because they cannot be synced in a cross-platform manner due to containing
|
because they cannot be synced in a cross-platform manner due to containing
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 4.2333 4.2333" version="1.1" height="16" width="16"><g id="g3830" transform="matrix(.87498 0 0 .87498 .26458 -255.9)"><circle id="circle3818" stroke-width=".25066" fill="#2268ab" r="2.1167" cy="294.88" cx="2.1167" /><g id="g3828" stroke-linejoin="round" stroke-linecap="round" fill="none" /></g><path style="fill:#ffffff;stroke-width:0.17859235" d="m 1.6076619,2.1122981 c 0.027682,0.068222 0.058043,0.1232286 0.115014,0.043934 0.072686,-0.047862 0.314322,-0.2548509 0.29682,-0.061078 C 1.953774,2.4553739 1.8705497,2.8125586 1.8105428,3.1738508 1.7403561,3.3728027 1.9237704,3.5430012 2.1028984,3.4078068 2.295421,3.3181535 2.4582973,3.1779584 2.6256382,3.0488362 2.599921,2.9911507 2.5809903,2.9077482 2.5191973,2.9868644 2.4356161,3.0297263 2.2566665,3.2222491 2.2163047,3.07116 2.2725613,2.681829 2.3904322,2.3041062 2.4600833,1.9170966 2.5309844,1.7376113 2.3950755,1.5200858 2.210054,1.6736753 1.985742,1.7836882 1.8010774,1.9562083 1.6076619,2.1122981 Z M 2.4041839,0.77839186 C 2.1702279,0.77446305 2.0636081,1.1609366 2.2889917,1.2561264 2.4716917,1.3236342 2.659928,1.1286114 2.6086721,0.94358974 2.5911701,0.8467927 2.5018738,0.77035521 2.4038266,0.77749894 Z" /></svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -467,7 +467,6 @@
|
|||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = FinderSyncExt/FinderSyncExt.entitlements;
|
CODE_SIGN_ENTITLEMENTS = FinderSyncExt/FinderSyncExt.entitlements;
|
||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
|
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ public:
|
|||||||
|
|
||||||
QString contextMenuTitle() const
|
QString contextMenuTitle() const
|
||||||
{
|
{
|
||||||
return _strings.value("CONTEXT_MENU_TITLE", "Nextcloud");
|
return _strings.value("CONTEXT_MENU_TITLE", "ownCloud");
|
||||||
}
|
}
|
||||||
QString shareActionTitle() const
|
QString shareActionTitle() const
|
||||||
{
|
{
|
||||||
return _strings.value("SHARE_MENU_TITLE", "Share …");
|
return _strings.value("SHARE_MENU_TITLE", "Share...");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString copyPrivateLinkTitle() const { return _strings["COPY_PRIVATE_LINK_MENU_TITLE"]; }
|
QString copyPrivateLinkTitle() const { return _strings["COPY_PRIVATE_LINK_MENU_TITLE"]; }
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ IFACEMETHODIMP OCContextMenu::Initialize(
|
|||||||
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
HDROP hDrop = static_cast<HDROP>(GlobalLock(stm.hGlobal));
|
||||||
if (hDrop) {
|
if (hDrop) {
|
||||||
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
|
||||||
for (UINT i = 0; i < nFiles; ++i) {
|
for (int i = 0; i < nFiles; ++i) {
|
||||||
// Get the path of the file.
|
// Get the path of the file.
|
||||||
wchar_t buffer[MAX_PATH];
|
wchar_t buffer[MAX_PATH];
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||||
|
|
||||||
// Note: Here was a #define for windows target version
|
#define WINVER 0x0501
|
||||||
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
|
#define _WIN32_WINNT 0x0501
|
||||||
// Unnecessary because we define both in desktop/CMakeLists.txt
|
|
||||||
|
|
||||||
#include <SDKDDKVer.h>
|
#include <SDKDDKVer.h>
|
||||||
|
|||||||
@@ -13,10 +13,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define WINVER 0x0501
|
||||||
// Note: Here was a #define for windows target version
|
#define _WIN32_WINNT 0x0501
|
||||||
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
|
|
||||||
// Unnecessary because we define both in desktop/CMakeLists.txt
|
|
||||||
|
|
||||||
#include "CommunicationSocket.h"
|
#include "CommunicationSocket.h"
|
||||||
#include "RegistryUtil.h"
|
#include "RegistryUtil.h"
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#define WINVER 0x0501
|
||||||
// Note: Here was a #define for windows target version
|
#define _WIN32_WINNT 0x0501
|
||||||
// e.g. WINVER / _WIN32_WINNT, see https://devblogs.microsoft.com/oldnewthing/20070411-00/?p=27283
|
|
||||||
// Unnecessary because we define both in desktop/CMakeLists.txt
|
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|||||||
2
src/3rdparty/libcrashreporter-qt
vendored
1
src/3rdparty/qtmacgoodies
vendored
Submodule
@@ -29,17 +29,12 @@ if(NOT MSVC)
|
|||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORTIFY_SOURCE=2")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORTIFY_SOURCE=2")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Calling Qt's qCWarning(category, ...) with no params for "..." is a GNU
|
|
||||||
# extension (C++11 §16.3/4 forbids them). Silence clang's warnings.
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
# Enable DEP & ASLR
|
# Enable DEP & ASLR
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /nxcompat /dynamicbase")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /nxcompat /dynamicbase")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase")
|
||||||
elseif(UNIX AND NOT APPLE)
|
elseif(UNIX AND NOT APPLE)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now")
|
||||||
|
|||||||
@@ -11,50 +11,43 @@
|
|||||||
|
|
||||||
// For overloading macros by argument count
|
// For overloading macros by argument count
|
||||||
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
||||||
// Bugfix 08/09/2019: Broken arg expansion led to always collapsing to 1 arg (XXXX_1 overload result)
|
#define OC_ASSERT_CAT(A, B) A##B
|
||||||
// See also: https://stackoverflow.com/questions/9183993/msvc-variadic-macro-expansion
|
#define OC_ASSERT_SELECT(NAME, NUM) OC_ASSERT_CAT(NAME##_, NUM)
|
||||||
#define OC_ASSERT_GLUE(x, y) x y
|
|
||||||
|
|
||||||
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
||||||
#define OC_ASSERT_EXPAND_ARGS(args) OC_ASSERT_GET_COUNT args
|
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_GET_COUNT(__VA_ARGS__, 3, 2, 1, 0)
|
||||||
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_EXPAND_ARGS((__VA_ARGS__, 3, 2, 1, 0))
|
|
||||||
|
|
||||||
#define OC_ASSERT_SELECT2(NAME, COUNT) NAME##COUNT
|
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__)) \
|
||||||
#define OC_ASSERT_SELECT1(NAME, COUNT) OC_ASSERT_SELECT2(NAME, COUNT)
|
(__VA_ARGS__)
|
||||||
#define OC_ASSERT_SELECT(NAME, COUNT) OC_ASSERT_SELECT1(NAME, COUNT)
|
|
||||||
|
|
||||||
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_GLUE(OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__)), \
|
|
||||||
(__VA_ARGS__))
|
|
||||||
|
|
||||||
// Default assert: If the condition is false in debug builds, terminate.
|
// Default assert: If the condition is false in debug builds, terminate.
|
||||||
//
|
//
|
||||||
// Prints a message on failure, even in release builds.
|
// Prints a message on failure, even in release builds.
|
||||||
#define ASSERT1(cond) \
|
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
||||||
|
#define ASSERT_1(cond) \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||||
} else { \
|
} else { \
|
||||||
}
|
}
|
||||||
#define ASSERT2(cond, message) \
|
#define ASSERT_2(cond, message) \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||||
} else { \
|
} else { \
|
||||||
}
|
}
|
||||||
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
|
||||||
|
|
||||||
// Enforce condition to be true, even in release builds.
|
// Enforce condition to be true, even in release builds.
|
||||||
//
|
//
|
||||||
// Prints 'message' and aborts execution if 'cond' is false.
|
// Prints 'message' and aborts execution if 'cond' is false.
|
||||||
#define ENFORCE1(cond) \
|
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
||||||
|
#define ENFORCE_1(cond) \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||||
} else { \
|
} else { \
|
||||||
}
|
}
|
||||||
#define ENFORCE2(cond, message) \
|
#define ENFORCE_2(cond, message) \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||||
} else { \
|
} else { \
|
||||||
}
|
}
|
||||||
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
|
||||||
|
|
||||||
// An assert that is only present in debug builds: typically used for
|
// An assert that is only present in debug builds: typically used for
|
||||||
// asserts that are too expensive for release mode.
|
// asserts that are too expensive for release mode.
|
||||||
|
|||||||
@@ -207,10 +207,7 @@ static inline uint64_t c_jhash64(const uint8_t *k, uint64_t length, uint64_t int
|
|||||||
/* handle the last 23 bytes */
|
/* handle the last 23 bytes */
|
||||||
c += length;
|
c += length;
|
||||||
switch(len) {
|
switch(len) {
|
||||||
// pragma only for GCC (and clang continues to pretend to be it by defining __GNUC__)
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
|
||||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
#endif
|
|
||||||
case 23: c+=((uint64_t)k[22]<<56);
|
case 23: c+=((uint64_t)k[22]<<56);
|
||||||
case 22: c+=((uint64_t)k[21]<<48);
|
case 22: c+=((uint64_t)k[21]<<48);
|
||||||
case 21: c+=((uint64_t)k[20]<<40);
|
case 21: c+=((uint64_t)k[20]<<40);
|
||||||
|
|||||||
@@ -281,8 +281,8 @@ int SqlQuery::prepare(const QByteArray &sql, bool allow_failure)
|
|||||||
*/
|
*/
|
||||||
static bool startsWithInsensitive(const QByteArray &a, const char *b)
|
static bool startsWithInsensitive(const QByteArray &a, const char *b)
|
||||||
{
|
{
|
||||||
size_t len = strlen(b);
|
int len = strlen(b);
|
||||||
return a.size() >= len && qstrnicmp(a.constData(), b, Utility::convertSizeToUint(len)) == 0;
|
return a.size() >= len && qstrnicmp(a.constData(), b, len) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SqlQuery::isSelect()
|
bool SqlQuery::isSelect()
|
||||||
|
|||||||
@@ -103,7 +103,6 @@ public:
|
|||||||
: _chunk(0)
|
: _chunk(0)
|
||||||
, _transferid(0)
|
, _transferid(0)
|
||||||
, _size(0)
|
, _size(0)
|
||||||
, _modtime(0)
|
|
||||||
, _errorCount(0)
|
, _errorCount(0)
|
||||||
, _valid(false)
|
, _valid(false)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -396,26 +396,6 @@ void Utility::crash()
|
|||||||
*a = 1;
|
*a = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this functions to retrieve uint/int (often required by Qt and WIN32) from size_t
|
|
||||||
// without compiler warnings about possible truncation
|
|
||||||
uint Utility::convertSizeToUint(size_t &convertVar)
|
|
||||||
{
|
|
||||||
if( convertVar > UINT_MAX ) {
|
|
||||||
//throw std::bad_cast();
|
|
||||||
convertVar = UINT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
|
|
||||||
}
|
|
||||||
return static_cast<uint>(convertVar);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint Utility::convertSizeToInt(size_t &convertVar)
|
|
||||||
{
|
|
||||||
if( convertVar > INT_MAX ) {
|
|
||||||
//throw std::bad_cast();
|
|
||||||
convertVar = INT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
|
|
||||||
}
|
|
||||||
return static_cast<int>(convertVar);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read the output of the owncloud --version command from the owncloud
|
// read the output of the owncloud --version command from the owncloud
|
||||||
// version that is on disk. This works for most versions of the client,
|
// version that is on disk. This works for most versions of the client,
|
||||||
// because clients that do not yet know the --version flag return the
|
// because clients that do not yet know the --version flag return the
|
||||||
|
|||||||
@@ -55,12 +55,6 @@ namespace Utility {
|
|||||||
OCSYNC_EXPORT QByteArray userAgentString();
|
OCSYNC_EXPORT QByteArray userAgentString();
|
||||||
OCSYNC_EXPORT bool hasLaunchOnStartup(const QString &appName);
|
OCSYNC_EXPORT bool hasLaunchOnStartup(const QString &appName);
|
||||||
OCSYNC_EXPORT void setLaunchOnStartup(const QString &appName, const QString &guiName, bool launch);
|
OCSYNC_EXPORT void setLaunchOnStartup(const QString &appName, const QString &guiName, bool launch);
|
||||||
OCSYNC_EXPORT uint convertSizeToUint(size_t &convertVar);
|
|
||||||
OCSYNC_EXPORT uint convertSizeToInt(size_t &convertVar);
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
OCSYNC_EXPORT DWORD convertSizeToDWORD(size_t &convertVar);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the amount of free space available.
|
* Return the amount of free space available.
|
||||||
|
|||||||
@@ -87,17 +87,9 @@ void setLaunchOnStartup_private(const QString &appName, const QString &guiName,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Right now only detection on toggle/startup, not when windows theme is switched while nextcloud is running
|
|
||||||
static inline bool hasDarkSystray_private()
|
static inline bool hasDarkSystray_private()
|
||||||
{
|
{
|
||||||
if(Utility::registryGetKeyValue( HKEY_CURRENT_USER,
|
return true;
|
||||||
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
|
|
||||||
"SystemUsesLightTheme" ) == 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant Utility::registryGetKeyValue(HKEY hRootKey, const QString &subKey, const QString &valueName)
|
QVariant Utility::registryGetKeyValue(HKEY hRootKey, const QString &subKey, const QString &valueName)
|
||||||
@@ -264,13 +256,4 @@ bool Utility::registryWalkSubKeys(HKEY hRootKey, const QString &subKey, const st
|
|||||||
return retCode != ERROR_NO_MORE_ITEMS;
|
return retCode != ERROR_NO_MORE_ITEMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD Utility::convertSizeToDWORD(size_t &convertVar)
|
|
||||||
{
|
|
||||||
if( convertVar > UINT_MAX ) {
|
|
||||||
//throw std::bad_cast();
|
|
||||||
convertVar = UINT_MAX; // intentionally default to wrong value here to not crash: exception handling TBD
|
|
||||||
}
|
|
||||||
return static_cast<DWORD>(convertVar);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ static void csync_exclude_expand_escapes(QByteArray &input)
|
|||||||
line[o++] = line[i];
|
line[o++] = line[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input.resize(OCC::Utility::convertSizeToUint(o));
|
input.resize(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
// See http://support.microsoft.com/kb/74496 and
|
// See http://support.microsoft.com/kb/74496 and
|
||||||
@@ -236,29 +236,13 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const char *path, bool excludeC
|
|||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QByteArray leftIncludeLast(const QByteArray & arr, char c)
|
|
||||||
{
|
|
||||||
// left up to and including `c`
|
|
||||||
return arr.left(arr.lastIndexOf(c, arr.size() - 2) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace OCC;
|
using namespace OCC;
|
||||||
|
|
||||||
ExcludedFiles::ExcludedFiles(QString localPath)
|
ExcludedFiles::ExcludedFiles()
|
||||||
: _localPath(std::move(localPath))
|
|
||||||
{
|
{
|
||||||
Q_ASSERT(_localPath.endsWith("/"));
|
|
||||||
// Windows used to use PathMatchSpec which allows *foo to match abc/deffoo.
|
// Windows used to use PathMatchSpec which allows *foo to match abc/deffoo.
|
||||||
_wildcardsMatchSlash = Utility::isWindows();
|
_wildcardsMatchSlash = Utility::isWindows();
|
||||||
|
|
||||||
// We're in a detached exclude probably coming from a partial sync or test
|
|
||||||
if (_localPath.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Load exclude file from base dir
|
|
||||||
QFileInfo fi(_localPath + ".sync-exclude.lst");
|
|
||||||
if (fi.isReadable())
|
|
||||||
addInTreeExcludeFilePath(fi.absoluteFilePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExcludedFiles::~ExcludedFiles()
|
ExcludedFiles::~ExcludedFiles()
|
||||||
@@ -267,13 +251,7 @@ ExcludedFiles::~ExcludedFiles()
|
|||||||
|
|
||||||
void ExcludedFiles::addExcludeFilePath(const QString &path)
|
void ExcludedFiles::addExcludeFilePath(const QString &path)
|
||||||
{
|
{
|
||||||
_excludeFiles[_localPath.toUtf8()].append(path);
|
_excludeFiles.insert(path);
|
||||||
}
|
|
||||||
|
|
||||||
void ExcludedFiles::addInTreeExcludeFilePath(const QString &path)
|
|
||||||
{
|
|
||||||
BasePathByteArray basePath = leftIncludeLast(path.toUtf8(), '/');
|
|
||||||
_excludeFiles[basePath].append(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExcludedFiles::setExcludeConflictFiles(bool onoff)
|
void ExcludedFiles::setExcludeConflictFiles(bool onoff)
|
||||||
@@ -283,22 +261,9 @@ void ExcludedFiles::setExcludeConflictFiles(bool onoff)
|
|||||||
|
|
||||||
void ExcludedFiles::addManualExclude(const QByteArray &expr)
|
void ExcludedFiles::addManualExclude(const QByteArray &expr)
|
||||||
{
|
{
|
||||||
addManualExclude(expr, _localPath.toUtf8());
|
_manualExcludes.append(expr);
|
||||||
}
|
_allExcludes.append(expr);
|
||||||
|
prepare();
|
||||||
void ExcludedFiles::addManualExclude(const QByteArray &expr, const QByteArray &basePath)
|
|
||||||
{
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
Q_ASSERT(basePath.size() >= 2 && basePath.at(1) == ':');
|
|
||||||
#else
|
|
||||||
Q_ASSERT(basePath.startsWith('/'));
|
|
||||||
#endif
|
|
||||||
Q_ASSERT(basePath.endsWith('/'));
|
|
||||||
|
|
||||||
auto key = basePath;
|
|
||||||
_manualExcludes[key].append(expr);
|
|
||||||
_allExcludes[key].append(expr);
|
|
||||||
prepare(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExcludedFiles::clearManualExcludes()
|
void ExcludedFiles::clearManualExcludes()
|
||||||
@@ -313,51 +278,26 @@ void ExcludedFiles::setWildcardsMatchSlash(bool onoff)
|
|||||||
prepare();
|
prepare();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExcludedFiles::loadExcludeFile(const QByteArray & basePath, const QString & file)
|
|
||||||
{
|
|
||||||
QFile f(file);
|
|
||||||
if (!f.open(QIODevice::ReadOnly))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
while (!f.atEnd()) {
|
|
||||||
QByteArray line = f.readLine().trimmed();
|
|
||||||
if (line.isEmpty() || line.startsWith('#'))
|
|
||||||
continue;
|
|
||||||
csync_exclude_expand_escapes(line);
|
|
||||||
_allExcludes[basePath].append(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// nothing to prepare if the user decided to not exclude anything
|
|
||||||
if(_allExcludes.size())
|
|
||||||
prepare(basePath);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExcludedFiles::reloadExcludeFiles()
|
bool ExcludedFiles::reloadExcludeFiles()
|
||||||
{
|
{
|
||||||
_allExcludes.clear();
|
_allExcludes.clear();
|
||||||
// clear all regex
|
|
||||||
_bnameTraversalRegexFile.clear();
|
|
||||||
_bnameTraversalRegexDir.clear();
|
|
||||||
_fullTraversalRegexFile.clear();
|
|
||||||
_fullTraversalRegexDir.clear();
|
|
||||||
_fullRegexFile.clear();
|
|
||||||
_fullRegexDir.clear();
|
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (const auto& basePath : _excludeFiles.keys()) {
|
foreach (const QString &file, _excludeFiles) {
|
||||||
for (const auto& file : _excludeFiles.value(basePath)) {
|
QFile f(file);
|
||||||
success = loadExcludeFile(basePath, file);
|
if (!f.open(QIODevice::ReadOnly)) {
|
||||||
|
success = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while (!f.atEnd()) {
|
||||||
|
QByteArray line = f.readLine().trimmed();
|
||||||
|
if (line.isEmpty() || line.startsWith('#'))
|
||||||
|
continue;
|
||||||
|
csync_exclude_expand_escapes(line);
|
||||||
|
_allExcludes.append(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_allExcludes.append(_manualExcludes);
|
||||||
auto endManual = _manualExcludes.cend();
|
prepare();
|
||||||
for (auto kv = _manualExcludes.cbegin(); kv != endManual; ++kv) {
|
|
||||||
_allExcludes[kv.key()].append(kv.value());
|
|
||||||
prepare(kv.key());
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,15 +311,13 @@ bool ExcludedFiles::isExcluded(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO this seems a waste, hidden files are ignored before hitting this function it seems
|
|
||||||
if (excludeHidden) {
|
if (excludeHidden) {
|
||||||
QString path = filePath;
|
QString path = filePath;
|
||||||
// Check all path subcomponents, but to *not* check the base path:
|
// Check all path subcomponents, but to *not* check the base path:
|
||||||
// We do want to be able to sync with a hidden folder as the target.
|
// We do want to be able to sync with a hidden folder as the target.
|
||||||
while (path.size() > basePath.size()) {
|
while (path.size() > basePath.size()) {
|
||||||
QFileInfo fi(path);
|
QFileInfo fi(path);
|
||||||
if (fi.fileName() != ".sync-exclude.lst"
|
if (fi.isHidden() || fi.fileName().startsWith(QLatin1Char('.'))) {
|
||||||
&& (fi.isHidden() || fi.fileName().startsWith(QLatin1Char('.')))) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,7 +340,7 @@ bool ExcludedFiles::isExcluded(
|
|||||||
return fullPatternMatch(relativePath.toUtf8(), type) != CSYNC_NOT_EXCLUDED;
|
return fullPatternMatch(relativePath.toUtf8(), type) != CSYNC_NOT_EXCLUDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemType filetype)
|
CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemType filetype) const
|
||||||
{
|
{
|
||||||
auto match = _csync_excluded_common(path, _excludeConflictFiles);
|
auto match = _csync_excluded_common(path, _excludeConflictFiles);
|
||||||
if (match != CSYNC_NOT_EXCLUDED)
|
if (match != CSYNC_NOT_EXCLUDED)
|
||||||
@@ -410,15 +348,6 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemTy
|
|||||||
if (_allExcludes.isEmpty())
|
if (_allExcludes.isEmpty())
|
||||||
return CSYNC_NOT_EXCLUDED;
|
return CSYNC_NOT_EXCLUDED;
|
||||||
|
|
||||||
// Directories are guaranteed to be visited before their files
|
|
||||||
if (filetype == ItemTypeDirectory) {
|
|
||||||
QFileInfo fi = QFileInfo(_localPath + path + "/.sync-exclude.lst");
|
|
||||||
if (fi.isReadable()) {
|
|
||||||
addInTreeExcludeFilePath(fi.absoluteFilePath());
|
|
||||||
loadExcludeFile(fi.absolutePath().toUtf8(), fi.absoluteFilePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the bname part of the path to see whether the full
|
// Check the bname part of the path to see whether the full
|
||||||
// regex should be run.
|
// regex should be run.
|
||||||
|
|
||||||
@@ -430,51 +359,33 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemTy
|
|||||||
}
|
}
|
||||||
QString bnameStr = QString::fromUtf8(bname);
|
QString bnameStr = QString::fromUtf8(bname);
|
||||||
|
|
||||||
QByteArray basePath(_localPath.toUtf8() + path);
|
QRegularExpressionMatch m;
|
||||||
while (basePath.size() > _localPath.size()) {
|
if (filetype == ItemTypeDirectory) {
|
||||||
basePath = leftIncludeLast(basePath, '/');
|
m = _bnameTraversalRegexDir.match(bnameStr);
|
||||||
QRegularExpressionMatch m;
|
} else {
|
||||||
if (filetype == ItemTypeDirectory
|
m = _bnameTraversalRegexFile.match(bnameStr);
|
||||||
&& _bnameTraversalRegexDir.contains(basePath)) {
|
}
|
||||||
m = _bnameTraversalRegexDir[basePath].match(bnameStr);
|
if (!m.hasMatch())
|
||||||
} else if (filetype == ItemTypeFile
|
return CSYNC_NOT_EXCLUDED;
|
||||||
&& _bnameTraversalRegexFile.contains(basePath)) {
|
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
|
||||||
m = _bnameTraversalRegexFile[basePath].match(bnameStr);
|
return CSYNC_FILE_EXCLUDE_LIST;
|
||||||
} else {
|
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
|
||||||
continue;
|
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
|
||||||
}
|
|
||||||
|
|
||||||
if (!m.hasMatch())
|
|
||||||
return CSYNC_NOT_EXCLUDED;
|
|
||||||
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
|
|
||||||
return CSYNC_FILE_EXCLUDE_LIST;
|
|
||||||
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
|
|
||||||
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// third capture: full path matching is triggered
|
// third capture: full path matching is triggered
|
||||||
QString pathStr = QString::fromUtf8(path);
|
QString pathStr = QString::fromUtf8(path);
|
||||||
basePath = _localPath.toUtf8() + path;
|
|
||||||
while (basePath.size() > _localPath.size()) {
|
|
||||||
basePath = leftIncludeLast(basePath, '/');
|
|
||||||
QRegularExpressionMatch m;
|
|
||||||
if (filetype == ItemTypeDirectory
|
|
||||||
&& _fullTraversalRegexDir.contains(basePath)) {
|
|
||||||
m = _fullTraversalRegexDir[basePath].match(pathStr);
|
|
||||||
} else if (filetype == ItemTypeFile
|
|
||||||
&& _fullTraversalRegexFile.contains(basePath)) {
|
|
||||||
m = _fullTraversalRegexFile[basePath].match(pathStr);
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.hasMatch()) {
|
if (filetype == ItemTypeDirectory) {
|
||||||
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
|
m = _fullTraversalRegexDir.match(pathStr);
|
||||||
return CSYNC_FILE_EXCLUDE_LIST;
|
} else {
|
||||||
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
|
m = _fullTraversalRegexFile.match(pathStr);
|
||||||
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
|
}
|
||||||
}
|
if (m.hasMatch()) {
|
||||||
|
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
|
||||||
|
return CSYNC_FILE_EXCLUDE_LIST;
|
||||||
|
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
|
||||||
|
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CSYNC_NOT_EXCLUDED;
|
return CSYNC_NOT_EXCLUDED;
|
||||||
@@ -489,38 +400,23 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::fullPatternMatch(const char *path, ItemType fi
|
|||||||
return CSYNC_NOT_EXCLUDED;
|
return CSYNC_NOT_EXCLUDED;
|
||||||
|
|
||||||
QString p = QString::fromUtf8(path);
|
QString p = QString::fromUtf8(path);
|
||||||
// `path` seems to always be relative to `_localPath`, the tests however have not been
|
QRegularExpressionMatch m;
|
||||||
// written that way... this makes the tests happy for now. TODO Fix the tests at some point
|
if (filetype == ItemTypeDirectory) {
|
||||||
if (path[0] == '/')
|
m = _fullRegexDir.match(p);
|
||||||
++path;
|
} else {
|
||||||
|
m = _fullRegexFile.match(p);
|
||||||
QByteArray basePath(_localPath.toUtf8() + path);
|
}
|
||||||
while (basePath.size() > _localPath.size()) {
|
if (m.hasMatch()) {
|
||||||
basePath = leftIncludeLast(basePath, '/');
|
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
|
||||||
QRegularExpressionMatch m;
|
return CSYNC_FILE_EXCLUDE_LIST;
|
||||||
if (filetype == ItemTypeDirectory
|
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
|
||||||
&& _fullRegexDir.contains(basePath)) {
|
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
|
||||||
m = _fullRegexDir[basePath].match(p);
|
|
||||||
} else if (filetype == ItemTypeFile
|
|
||||||
&& _fullRegexFile.contains(basePath)) {
|
|
||||||
m = _fullRegexFile[basePath].match(p);
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m.hasMatch()) {
|
|
||||||
if (m.capturedStart(QStringLiteral("exclude")) != -1) {
|
|
||||||
return CSYNC_FILE_EXCLUDE_LIST;
|
|
||||||
} else if (m.capturedStart(QStringLiteral("excluderemove")) != -1) {
|
|
||||||
return CSYNC_FILE_EXCLUDE_AND_REMOVE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSYNC_NOT_EXCLUDED;
|
return CSYNC_NOT_EXCLUDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ExcludedFiles::csyncTraversalMatchFun()
|
auto ExcludedFiles::csyncTraversalMatchFun() const
|
||||||
-> std::function<CSYNC_EXCLUDE_TYPE(const char *path, ItemType filetype)>
|
-> std::function<CSYNC_EXCLUDE_TYPE(const char *path, ItemType filetype)>
|
||||||
{
|
{
|
||||||
return [this](const char *path, ItemType filetype) { return this->traversalPatternMatch(path, filetype); };
|
return [this](const char *path, ItemType filetype) { return this->traversalPatternMatch(path, filetype); };
|
||||||
@@ -659,22 +555,6 @@ static QString extractBnameTrigger(const QString &exclude, bool wildcardsMatchSl
|
|||||||
|
|
||||||
void ExcludedFiles::prepare()
|
void ExcludedFiles::prepare()
|
||||||
{
|
{
|
||||||
// clear all regex
|
|
||||||
_bnameTraversalRegexFile.clear();
|
|
||||||
_bnameTraversalRegexDir.clear();
|
|
||||||
_fullTraversalRegexFile.clear();
|
|
||||||
_fullTraversalRegexDir.clear();
|
|
||||||
_fullRegexFile.clear();
|
|
||||||
_fullRegexDir.clear();
|
|
||||||
|
|
||||||
for (auto const & basePath : _allExcludes.keys())
|
|
||||||
prepare(basePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExcludedFiles::prepare(const BasePathByteArray & basePath)
|
|
||||||
{
|
|
||||||
Q_ASSERT(_allExcludes.contains(basePath));
|
|
||||||
|
|
||||||
// Build regular expressions for the different cases.
|
// Build regular expressions for the different cases.
|
||||||
//
|
//
|
||||||
// To compose the _bnameTraversalRegex, _fullTraversalRegex and _fullRegex
|
// To compose the _bnameTraversalRegex, _fullTraversalRegex and _fullRegex
|
||||||
@@ -716,7 +596,7 @@ void ExcludedFiles::prepare(const BasePathByteArray & basePath)
|
|||||||
pattern.append(appendMe);
|
pattern.append(appendMe);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto exclude : _allExcludes.value(basePath)) {
|
for (auto exclude : _allExcludes) {
|
||||||
if (exclude[0] == '\n')
|
if (exclude[0] == '\n')
|
||||||
continue; // empty line
|
continue; // empty line
|
||||||
if (exclude[0] == '\r')
|
if (exclude[0] == '\r')
|
||||||
@@ -738,15 +618,6 @@ void ExcludedFiles::prepare(const BasePathByteArray & basePath)
|
|||||||
auto &fullFileDir = removeExcluded ? fullFileDirRemove : fullFileDirKeep;
|
auto &fullFileDir = removeExcluded ? fullFileDirRemove : fullFileDirKeep;
|
||||||
auto &fullDir = removeExcluded ? fullDirRemove : fullDirKeep;
|
auto &fullDir = removeExcluded ? fullDirRemove : fullDirKeep;
|
||||||
|
|
||||||
if (fullPath) {
|
|
||||||
// The full pattern is matched against a path relative to _localPath, however exclude is
|
|
||||||
// relative to basePath at this point.
|
|
||||||
// We know for sure that both _localPath and basePath are absolute and that basePath is
|
|
||||||
// contained in _localPath. So we can simply remove it from the begining.
|
|
||||||
auto relPath = basePath.mid(_localPath.size());
|
|
||||||
// Make exclude relative to _localPath
|
|
||||||
exclude.prepend(relPath);
|
|
||||||
}
|
|
||||||
auto regexExclude = convertToRegexpSyntax(QString::fromUtf8(exclude), _wildcardsMatchSlash);
|
auto regexExclude = convertToRegexpSyntax(QString::fromUtf8(exclude), _wildcardsMatchSlash);
|
||||||
if (!fullPath) {
|
if (!fullPath) {
|
||||||
regexAppend(bnameFileDir, bnameDir, regexExclude, matchDirOnly);
|
regexAppend(bnameFileDir, bnameDir, regexExclude, matchDirOnly);
|
||||||
@@ -783,11 +654,11 @@ void ExcludedFiles::prepare(const BasePathByteArray & basePath)
|
|||||||
// (exclude)|(excluderemove)|(bname triggers).
|
// (exclude)|(excluderemove)|(bname triggers).
|
||||||
// If the third group matches, the fullActivatedRegex needs to be applied
|
// If the third group matches, the fullActivatedRegex needs to be applied
|
||||||
// to the full path.
|
// to the full path.
|
||||||
_bnameTraversalRegexFile[basePath].setPattern(
|
_bnameTraversalRegexFile.setPattern(
|
||||||
"^(?P<exclude>" + bnameFileDirKeep + ")$|"
|
"^(?P<exclude>" + bnameFileDirKeep + ")$|"
|
||||||
+ "^(?P<excluderemove>" + bnameFileDirRemove + ")$|"
|
+ "^(?P<excluderemove>" + bnameFileDirRemove + ")$|"
|
||||||
+ "^(?P<trigger>" + bnameTriggerFileDir + ")$");
|
+ "^(?P<trigger>" + bnameTriggerFileDir + ")$");
|
||||||
_bnameTraversalRegexDir[basePath].setPattern(
|
_bnameTraversalRegexDir.setPattern(
|
||||||
"^(?P<exclude>" + bnameFileDirKeep + "|" + bnameDirKeep + ")$|"
|
"^(?P<exclude>" + bnameFileDirKeep + "|" + bnameDirKeep + ")$|"
|
||||||
+ "^(?P<excluderemove>" + bnameFileDirRemove + "|" + bnameDirRemove + ")$|"
|
+ "^(?P<excluderemove>" + bnameFileDirRemove + "|" + bnameDirRemove + ")$|"
|
||||||
+ "^(?P<trigger>" + bnameTriggerFileDir + "|" + bnameTriggerDir + ")$");
|
+ "^(?P<trigger>" + bnameTriggerFileDir + "|" + bnameTriggerDir + ")$");
|
||||||
@@ -796,13 +667,13 @@ void ExcludedFiles::prepare(const BasePathByteArray & basePath)
|
|||||||
// the bname regex matches. Its basic form is (exclude)|(excluderemove)".
|
// the bname regex matches. Its basic form is (exclude)|(excluderemove)".
|
||||||
// This pattern can be much simpler than fullRegex since we can assume a traversal
|
// This pattern can be much simpler than fullRegex since we can assume a traversal
|
||||||
// situation and doesn't need to look for bname patterns in parent paths.
|
// situation and doesn't need to look for bname patterns in parent paths.
|
||||||
_fullTraversalRegexFile[basePath].setPattern(
|
_fullTraversalRegexFile.setPattern(
|
||||||
QLatin1String("")
|
QLatin1String("")
|
||||||
// Full patterns are anchored to the beginning
|
// Full patterns are anchored to the beginning
|
||||||
+ "^(?P<exclude>" + fullFileDirKeep + ")(?:$|/)"
|
+ "^(?P<exclude>" + fullFileDirKeep + ")(?:$|/)"
|
||||||
+ "|"
|
+ "|"
|
||||||
+ "^(?P<excluderemove>" + fullFileDirRemove + ")(?:$|/)");
|
+ "^(?P<excluderemove>" + fullFileDirRemove + ")(?:$|/)");
|
||||||
_fullTraversalRegexDir[basePath].setPattern(
|
_fullTraversalRegexDir.setPattern(
|
||||||
QLatin1String("")
|
QLatin1String("")
|
||||||
+ "^(?P<exclude>" + fullFileDirKeep + "|" + fullDirKeep + ")(?:$|/)"
|
+ "^(?P<exclude>" + fullFileDirKeep + "|" + fullDirKeep + ")(?:$|/)"
|
||||||
+ "|"
|
+ "|"
|
||||||
@@ -810,7 +681,7 @@ void ExcludedFiles::prepare(const BasePathByteArray & basePath)
|
|||||||
|
|
||||||
// The full regex is applied to the full path and incorporates both bname and
|
// The full regex is applied to the full path and incorporates both bname and
|
||||||
// full-path patterns. It has the form "(exclude)|(excluderemove)".
|
// full-path patterns. It has the form "(exclude)|(excluderemove)".
|
||||||
_fullRegexFile[basePath].setPattern(
|
_fullRegexFile.setPattern(
|
||||||
QLatin1String("(?P<exclude>")
|
QLatin1String("(?P<exclude>")
|
||||||
// Full patterns are anchored to the beginning
|
// Full patterns are anchored to the beginning
|
||||||
+ "^(?:" + fullFileDirKeep + ")(?:$|/)" + "|"
|
+ "^(?:" + fullFileDirKeep + ")(?:$|/)" + "|"
|
||||||
@@ -826,7 +697,7 @@ void ExcludedFiles::prepare(const BasePathByteArray & basePath)
|
|||||||
+ "(?:^|/)(?:" + bnameFileDirRemove + ")(?:$|/)" + "|"
|
+ "(?:^|/)(?:" + bnameFileDirRemove + ")(?:$|/)" + "|"
|
||||||
+ "(?:^|/)(?:" + bnameDirRemove + ")/"
|
+ "(?:^|/)(?:" + bnameDirRemove + ")/"
|
||||||
+ ")");
|
+ ")");
|
||||||
_fullRegexDir[basePath].setPattern(
|
_fullRegexDir.setPattern(
|
||||||
QLatin1String("(?P<exclude>")
|
QLatin1String("(?P<exclude>")
|
||||||
+ "^(?:" + fullFileDirKeep + "|" + fullDirKeep + ")(?:$|/)" + "|"
|
+ "^(?:" + fullFileDirKeep + "|" + fullDirKeep + ")(?:$|/)" + "|"
|
||||||
+ "(?:^|/)(?:" + bnameFileDirKeep + "|" + bnameDirKeep + ")(?:$|/)"
|
+ "(?:^|/)(?:" + bnameFileDirKeep + "|" + bnameDirKeep + ")(?:$|/)"
|
||||||
@@ -840,16 +711,16 @@ void ExcludedFiles::prepare(const BasePathByteArray & basePath)
|
|||||||
QRegularExpression::PatternOptions patternOptions = QRegularExpression::NoPatternOption;
|
QRegularExpression::PatternOptions patternOptions = QRegularExpression::NoPatternOption;
|
||||||
if (OCC::Utility::fsCasePreserving())
|
if (OCC::Utility::fsCasePreserving())
|
||||||
patternOptions |= QRegularExpression::CaseInsensitiveOption;
|
patternOptions |= QRegularExpression::CaseInsensitiveOption;
|
||||||
_bnameTraversalRegexFile[basePath].setPatternOptions(patternOptions);
|
_bnameTraversalRegexFile.setPatternOptions(patternOptions);
|
||||||
_bnameTraversalRegexFile[basePath].optimize();
|
_bnameTraversalRegexFile.optimize();
|
||||||
_bnameTraversalRegexDir[basePath].setPatternOptions(patternOptions);
|
_bnameTraversalRegexDir.setPatternOptions(patternOptions);
|
||||||
_bnameTraversalRegexDir[basePath].optimize();
|
_bnameTraversalRegexDir.optimize();
|
||||||
_fullTraversalRegexFile[basePath].setPatternOptions(patternOptions);
|
_fullTraversalRegexFile.setPatternOptions(patternOptions);
|
||||||
_fullTraversalRegexFile[basePath].optimize();
|
_fullTraversalRegexFile.optimize();
|
||||||
_fullTraversalRegexDir[basePath].setPatternOptions(patternOptions);
|
_fullTraversalRegexDir.setPatternOptions(patternOptions);
|
||||||
_fullTraversalRegexDir[basePath].optimize();
|
_fullTraversalRegexDir.optimize();
|
||||||
_fullRegexFile[basePath].setPatternOptions(patternOptions);
|
_fullRegexFile.setPatternOptions(patternOptions);
|
||||||
_fullRegexFile[basePath].optimize();
|
_fullRegexFile.optimize();
|
||||||
_fullRegexDir[basePath].setPatternOptions(patternOptions);
|
_fullRegexDir.setPatternOptions(patternOptions);
|
||||||
_fullRegexDir[basePath].optimize();
|
_fullRegexDir.optimize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class OCSYNC_EXPORT ExcludedFiles : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ExcludedFiles(QString localPath = "/");
|
ExcludedFiles();
|
||||||
~ExcludedFiles();
|
~ExcludedFiles();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,7 +75,6 @@ public:
|
|||||||
* Does not load the file. Use reloadExcludeFiles() afterwards.
|
* Does not load the file. Use reloadExcludeFiles() afterwards.
|
||||||
*/
|
*/
|
||||||
void addExcludeFilePath(const QString &path);
|
void addExcludeFilePath(const QString &path);
|
||||||
void addInTreeExcludeFilePath(const QString &path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether conflict files shall be excluded.
|
* Whether conflict files shall be excluded.
|
||||||
@@ -96,13 +95,12 @@ public:
|
|||||||
bool excludeHidden) const;
|
bool excludeHidden) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an exclude pattern anchored to base path
|
* Adds an exclude pattern.
|
||||||
*
|
*
|
||||||
* Primarily used in tests. Patterns added this way are preserved when
|
* Primarily used in tests. Patterns added this way are preserved when
|
||||||
* reloadExcludeFiles() is called.
|
* reloadExcludeFiles() is called.
|
||||||
*/
|
*/
|
||||||
void addManualExclude(const QByteArray &expr);
|
void addManualExclude(const QByteArray &expr);
|
||||||
void addManualExclude(const QByteArray &expr, const QByteArray &basePath);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all manually added exclude patterns.
|
* Removes all manually added exclude patterns.
|
||||||
@@ -123,7 +121,7 @@ public:
|
|||||||
* Careful: The function will only be valid for as long as this
|
* Careful: The function will only be valid for as long as this
|
||||||
* ExcludedFiles instance stays alive.
|
* ExcludedFiles instance stays alive.
|
||||||
*/
|
*/
|
||||||
auto csyncTraversalMatchFun()
|
auto csyncTraversalMatchFun() const
|
||||||
-> std::function<CSYNC_EXCLUDE_TYPE(const char *path, ItemType filetype)>;
|
-> std::function<CSYNC_EXCLUDE_TYPE(const char *path, ItemType filetype)>;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
@@ -131,10 +129,6 @@ public slots:
|
|||||||
* Reloads the exclude patterns from the registered paths.
|
* Reloads the exclude patterns from the registered paths.
|
||||||
*/
|
*/
|
||||||
bool reloadExcludeFiles();
|
bool reloadExcludeFiles();
|
||||||
/**
|
|
||||||
* Loads the exclude patterns from file the registered base paths.
|
|
||||||
*/
|
|
||||||
bool loadExcludeFile(const QByteArray & basePath, const QString & file);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@@ -162,32 +156,10 @@ private:
|
|||||||
* Note that this only matches patterns. It does not check whether the file
|
* Note that this only matches patterns. It does not check whether the file
|
||||||
* or directory pointed to is hidden (or whether it even exists).
|
* or directory pointed to is hidden (or whether it even exists).
|
||||||
*/
|
*/
|
||||||
CSYNC_EXCLUDE_TYPE traversalPatternMatch(const char *path, ItemType filetype);
|
CSYNC_EXCLUDE_TYPE traversalPatternMatch(const char *path, ItemType filetype) const;
|
||||||
|
|
||||||
// Our BasePath need to end with '/'
|
|
||||||
class BasePathByteArray : public QByteArray
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BasePathByteArray(QByteArray && other)
|
|
||||||
: QByteArray(std::move(other))
|
|
||||||
{
|
|
||||||
Q_ASSERT(this->endsWith('/'));
|
|
||||||
}
|
|
||||||
|
|
||||||
BasePathByteArray(const QByteArray & other)
|
|
||||||
: QByteArray(other)
|
|
||||||
{
|
|
||||||
Q_ASSERT(this->endsWith('/'));
|
|
||||||
}
|
|
||||||
|
|
||||||
BasePathByteArray(const char * data, int size = -1)
|
|
||||||
: BasePathByteArray(QByteArray(data, size))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate optimized regular expressions for the exclude patterns anchored to basePath.
|
* Generate optimized regular expressions for the exclude patterns.
|
||||||
*
|
*
|
||||||
* The optimization works in two steps: First, all supported patterns are put
|
* The optimization works in two steps: First, all supported patterns are put
|
||||||
* into _fullRegexFile/_fullRegexDir. These regexes can be applied to the full
|
* into _fullRegexFile/_fullRegexDir. These regexes can be applied to the full
|
||||||
@@ -215,28 +187,24 @@ private:
|
|||||||
* full matcher would exclude. Example: "b" is excluded. traversal("b/c")
|
* full matcher would exclude. Example: "b" is excluded. traversal("b/c")
|
||||||
* returns not-excluded because "c" isn't a bname activation pattern.
|
* returns not-excluded because "c" isn't a bname activation pattern.
|
||||||
*/
|
*/
|
||||||
void prepare(const BasePathByteArray & basePath);
|
|
||||||
|
|
||||||
void prepare();
|
void prepare();
|
||||||
|
|
||||||
|
|
||||||
QString _localPath;
|
|
||||||
/// Files to load excludes from
|
/// Files to load excludes from
|
||||||
QMap<BasePathByteArray, QList<QString>> _excludeFiles;
|
QSet<QString> _excludeFiles;
|
||||||
|
|
||||||
/// Exclude patterns added with addManualExclude()
|
/// Exclude patterns added with addManualExclude()
|
||||||
QMap<BasePathByteArray, QList<QByteArray>> _manualExcludes;
|
QList<QByteArray> _manualExcludes;
|
||||||
|
|
||||||
/// List of all active exclude patterns
|
/// List of all active exclude patterns
|
||||||
QMap<BasePathByteArray, QList<QByteArray>> _allExcludes;
|
QList<QByteArray> _allExcludes;
|
||||||
|
|
||||||
/// see prepare()
|
/// see prepare()
|
||||||
QMap<BasePathByteArray, QRegularExpression> _bnameTraversalRegexFile;
|
QRegularExpression _bnameTraversalRegexFile;
|
||||||
QMap<BasePathByteArray, QRegularExpression> _bnameTraversalRegexDir;
|
QRegularExpression _bnameTraversalRegexDir;
|
||||||
QMap<BasePathByteArray, QRegularExpression> _fullTraversalRegexFile;
|
QRegularExpression _fullTraversalRegexFile;
|
||||||
QMap<BasePathByteArray, QRegularExpression> _fullTraversalRegexDir;
|
QRegularExpression _fullTraversalRegexDir;
|
||||||
QMap<BasePathByteArray, QRegularExpression> _fullRegexFile;
|
QRegularExpression _fullRegexFile;
|
||||||
QMap<BasePathByteArray, QRegularExpression> _fullRegexDir;
|
QRegularExpression _fullRegexDir;
|
||||||
|
|
||||||
bool _excludeConflictFiles = true;
|
bool _excludeConflictFiles = true;
|
||||||
|
|
||||||
|
|||||||
@@ -124,9 +124,7 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
|
|||||||
* because it's a hidden file that should not be synced.
|
* because it's a hidden file that should not be synced.
|
||||||
* This code should probably be in csync_exclude, but it does not have the fs parameter.
|
* This code should probably be in csync_exclude, but it does not have the fs parameter.
|
||||||
* Keep it here for now */
|
* Keep it here for now */
|
||||||
if (ctx->ignore_hidden_files
|
if (ctx->ignore_hidden_files && (fs->is_hidden)) {
|
||||||
&& fs->is_hidden
|
|
||||||
&& !fs->path.endsWith(".sync-exclude.lst")) {
|
|
||||||
qCInfo(lcUpdate, "file excluded because it is a hidden file: %s", fs->path.constData());
|
qCInfo(lcUpdate, "file excluded because it is a hidden file: %s", fs->path.constData());
|
||||||
excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
|
excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
|
||||||
}
|
}
|
||||||
@@ -724,8 +722,7 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
|
|||||||
if (ctx->current == LOCAL_REPLICA) {
|
if (ctx->current == LOCAL_REPLICA) {
|
||||||
ASSERT(dirent->path.startsWith(ctx->local.uri)); // path is relative to uri
|
ASSERT(dirent->path.startsWith(ctx->local.uri)); // path is relative to uri
|
||||||
// "len + 1" to include the slash in-between.
|
// "len + 1" to include the slash in-between.
|
||||||
size_t uriLength = strlen(ctx->local.uri);
|
dirent->path = dirent->path.mid(strlen(ctx->local.uri) + 1);
|
||||||
dirent->path = dirent->path.mid(OCC::Utility::convertSizeToInt(uriLength) + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
previous_fs = ctx->current_fs;
|
previous_fs = ctx->current_fs;
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
#include "c_alloc.h"
|
#include "c_alloc.h"
|
||||||
#include "c_string.h"
|
#include "c_string.h"
|
||||||
#include "common/filesystembase.h"
|
#include "common/filesystembase.h"
|
||||||
#include "common/utility.h"
|
|
||||||
|
|
||||||
/* Convert a locale String to UTF8 */
|
/* Convert a locale String to UTF8 */
|
||||||
QByteArray c_utf8_from_locale(const mbchar_t *wstr)
|
QByteArray c_utf8_from_locale(const mbchar_t *wstr)
|
||||||
@@ -53,10 +52,10 @@ QByteArray c_utf8_from_locale(const mbchar_t *wstr)
|
|||||||
size_t len;
|
size_t len;
|
||||||
len = wcslen(wstr);
|
len = wcslen(wstr);
|
||||||
/* Call once to get the required size. */
|
/* Call once to get the required size. */
|
||||||
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, OCC::Utility::convertSizeToInt(len), NULL, 0, NULL, NULL);
|
size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, len, NULL, 0, NULL, NULL);
|
||||||
if (size_needed > 0) {
|
if (size_needed > 0) {
|
||||||
dst.resize(size_needed);
|
dst.resize(size_needed);
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wstr, OCC::Utility::convertSizeToInt(len), dst.data(), size_needed, NULL, NULL);
|
WideCharToMultiByte(CP_UTF8, 0, wstr, len, dst.data(), size_needed, NULL, NULL);
|
||||||
}
|
}
|
||||||
return dst;
|
return dst;
|
||||||
#else
|
#else
|
||||||
@@ -96,7 +95,7 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
|
|||||||
int size_needed;
|
int size_needed;
|
||||||
|
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, OCC::Utility::convertSizeToInt(len), NULL, 0);
|
size_needed = MultiByteToWideChar(CP_UTF8, 0, str, len, NULL, 0);
|
||||||
if (size_needed > 0) {
|
if (size_needed > 0) {
|
||||||
int size_char = (size_needed + 1) * sizeof(mbchar_t);
|
int size_char = (size_needed + 1) * sizeof(mbchar_t);
|
||||||
dst = (mbchar_t*)c_malloc(size_char);
|
dst = (mbchar_t*)c_malloc(size_char);
|
||||||
@@ -115,8 +114,7 @@ mbchar_t* c_utf8_string_to_locale(const char *str)
|
|||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
size_t strLength = strlen(str);
|
QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, strlen(str)));
|
||||||
QByteArray unc_str = OCC::FileSystem::pathtoUNC(QByteArray::fromRawData(str, OCC::Utility::convertSizeToInt(strLength)));
|
|
||||||
mbchar_t *dst = c_utf8_string_to_locale(unc_str);
|
mbchar_t *dst = c_utf8_string_to_locale(unc_str);
|
||||||
return dst;
|
return dst;
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ csync_vio_handle_t *csync_vio_local_opendir(const char *name) {
|
|||||||
handle = (dhandle_t*)c_malloc(sizeof(dhandle_t));
|
handle = (dhandle_t*)c_malloc(sizeof(dhandle_t));
|
||||||
|
|
||||||
// the file wildcard has to be attached
|
// the file wildcard has to be attached
|
||||||
size_t len_name = strlen(name);
|
int len_name = strlen(name);
|
||||||
if( len_name ) {
|
if( len_name ) {
|
||||||
char *h = NULL;
|
char *h = NULL;
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ set(client_UI_SRCS
|
|||||||
generalsettings.ui
|
generalsettings.ui
|
||||||
legalnotice.ui
|
legalnotice.ui
|
||||||
ignorelisteditor.ui
|
ignorelisteditor.ui
|
||||||
ignorelisttablewidget.ui
|
|
||||||
networksettings.ui
|
networksettings.ui
|
||||||
activitywidget.ui
|
activitywidget.ui
|
||||||
synclogdialog.ui
|
synclogdialog.ui
|
||||||
@@ -35,7 +34,6 @@ set(client_UI_SRCS
|
|||||||
addcertificatedialog.ui
|
addcertificatedialog.ui
|
||||||
proxyauthdialog.ui
|
proxyauthdialog.ui
|
||||||
mnemonicdialog.ui
|
mnemonicdialog.ui
|
||||||
wizard/flow2authwidget.ui
|
|
||||||
wizard/owncloudadvancedsetuppage.ui
|
wizard/owncloudadvancedsetuppage.ui
|
||||||
wizard/owncloudconnectionmethoddialog.ui
|
wizard/owncloudconnectionmethoddialog.ui
|
||||||
wizard/owncloudhttpcredspage.ui
|
wizard/owncloudhttpcredspage.ui
|
||||||
@@ -61,7 +59,6 @@ set(client_SRCS
|
|||||||
generalsettings.cpp
|
generalsettings.cpp
|
||||||
legalnotice.cpp
|
legalnotice.cpp
|
||||||
ignorelisteditor.cpp
|
ignorelisteditor.cpp
|
||||||
ignorelisttablewidget.cpp
|
|
||||||
lockwatcher.cpp
|
lockwatcher.cpp
|
||||||
logbrowser.cpp
|
logbrowser.cpp
|
||||||
navigationpanehelper.cpp
|
navigationpanehelper.cpp
|
||||||
@@ -102,14 +99,10 @@ set(client_SRCS
|
|||||||
servernotificationhandler.cpp
|
servernotificationhandler.cpp
|
||||||
guiutility.cpp
|
guiutility.cpp
|
||||||
elidedlabel.cpp
|
elidedlabel.cpp
|
||||||
headerbanner.cpp
|
|
||||||
iconjob.cpp
|
iconjob.cpp
|
||||||
remotewipe.cpp
|
|
||||||
creds/credentialsfactory.cpp
|
creds/credentialsfactory.cpp
|
||||||
creds/httpcredentialsgui.cpp
|
creds/httpcredentialsgui.cpp
|
||||||
creds/oauth.cpp
|
creds/oauth.cpp
|
||||||
creds/flow2auth.cpp
|
|
||||||
creds/keychainchunk.cpp
|
|
||||||
creds/webflowcredentials.cpp
|
creds/webflowcredentials.cpp
|
||||||
creds/webflowcredentialsdialog.cpp
|
creds/webflowcredentialsdialog.cpp
|
||||||
wizard/postfixlineedit.cpp
|
wizard/postfixlineedit.cpp
|
||||||
@@ -118,8 +111,6 @@ set(client_SRCS
|
|||||||
wizard/owncloudconnectionmethoddialog.cpp
|
wizard/owncloudconnectionmethoddialog.cpp
|
||||||
wizard/owncloudhttpcredspage.cpp
|
wizard/owncloudhttpcredspage.cpp
|
||||||
wizard/owncloudoauthcredspage.cpp
|
wizard/owncloudoauthcredspage.cpp
|
||||||
wizard/flow2authcredspage.cpp
|
|
||||||
wizard/flow2authwidget.cpp
|
|
||||||
wizard/owncloudsetuppage.cpp
|
wizard/owncloudsetuppage.cpp
|
||||||
wizard/owncloudwizardcommon.cpp
|
wizard/owncloudwizardcommon.cpp
|
||||||
wizard/owncloudwizard.cpp
|
wizard/owncloudwizard.cpp
|
||||||
@@ -146,6 +137,8 @@ set(updater_SRCS
|
|||||||
|
|
||||||
IF( APPLE )
|
IF( APPLE )
|
||||||
list(APPEND client_SRCS cocoainitializer_mac.mm)
|
list(APPEND client_SRCS cocoainitializer_mac.mm)
|
||||||
|
list(APPEND client_SRCS settingsdialogmac.cpp)
|
||||||
|
list(REMOVE_ITEM client_SRCS settingsdialog.cpp)
|
||||||
list(APPEND client_SRCS socketapisocket_mac.mm)
|
list(APPEND client_SRCS socketapisocket_mac.mm)
|
||||||
list(APPEND client_SRCS systray.mm)
|
list(APPEND client_SRCS systray.mm)
|
||||||
|
|
||||||
@@ -175,6 +168,14 @@ set(3rdparty_SRC
|
|||||||
../3rdparty/kmessagewidget/kmessagewidget.cpp
|
../3rdparty/kmessagewidget/kmessagewidget.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
list(APPEND 3rdparty_SRC
|
||||||
|
../3rdparty/qtmacgoodies/src/macpreferenceswindow.mm
|
||||||
|
../3rdparty/qtmacgoodies/src/macstandardicon.mm
|
||||||
|
../3rdparty/qtmacgoodies/src/macwindow.mm
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
list(APPEND 3rdparty_SRC ../3rdparty/qtlockedfile/qtlockedfile_unix.cpp)
|
list(APPEND 3rdparty_SRC ../3rdparty/qtlockedfile/qtlockedfile_unix.cpp)
|
||||||
else()
|
else()
|
||||||
@@ -243,7 +244,7 @@ if(APPLE)
|
|||||||
file(GLOB_RECURSE OWNCLOUD_SIDEBAR_ICONS "${theme_dir}/colored/*-${APPLICATION_ICON_NAME}-sidebar*")
|
file(GLOB_RECURSE OWNCLOUD_SIDEBAR_ICONS "${theme_dir}/colored/*-${APPLICATION_ICON_NAME}-sidebar*")
|
||||||
MESSAGE(STATUS "OWNCLOUD_SIDEBAR_ICONS: ${APPLICATION_ICON_NAME}: ${OWNCLOUD_SIDEBAR_ICONS}")
|
MESSAGE(STATUS "OWNCLOUD_SIDEBAR_ICONS: ${APPLICATION_ICON_NAME}: ${OWNCLOUD_SIDEBAR_ICONS}")
|
||||||
endif()
|
endif()
|
||||||
ecm_add_app_icon(final_src ICONS "${OWNCLOUD_ICONS}" SIDEBAR_ICONS "${OWNCLOUD_SIDEBAR_ICONS}" OUTFILE_BASENAME "${APPLICATION_ICON_NAME}")
|
ecm_add_app_icon(final_src ICONS "${OWNCLOUD_ICONS}" SIDEBAR_ICONS "${OWNCLOUD_SIDEBAR_ICONS}" OUTFILE_BASE "${APPLICATION_ICON_NAME}")
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE")
|
||||||
@@ -265,9 +266,6 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
|
|||||||
endforeach(_file)
|
endforeach(_file)
|
||||||
install(FILES ${client_I18N} DESTINATION ${SHAREDIR}/${APPLICATION_EXECUTABLE}/i18n)
|
install(FILES ${client_I18N} DESTINATION ${SHAREDIR}/${APPLICATION_EXECUTABLE}/i18n)
|
||||||
else()
|
else()
|
||||||
file(GLOB_RECURSE VISUAL_ELEMENTS "${theme_dir}/colored/*-${APPLICATION_ICON_NAME}-w10startmenu*")
|
|
||||||
install(FILES ${VISUAL_ELEMENTS} DESTINATION bin/visualelements)
|
|
||||||
install(FILES "${theme_dir}/${APPLICATION_EXECUTABLE}.VisualElementsManifest.xml" DESTINATION bin)
|
|
||||||
install(FILES ${client_I18N} DESTINATION i18n)
|
install(FILES ${client_I18N} DESTINATION i18n)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -330,6 +328,7 @@ ENDIF()
|
|||||||
target_include_directories(${APPLICATION_EXECUTABLE} PRIVATE
|
target_include_directories(${APPLICATION_EXECUTABLE} PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}/src/3rdparty/QProgressIndicator
|
${CMAKE_SOURCE_DIR}/src/3rdparty/QProgressIndicator
|
||||||
${CMAKE_SOURCE_DIR}/src/3rdparty/qtlockedfile
|
${CMAKE_SOURCE_DIR}/src/3rdparty/qtlockedfile
|
||||||
|
${CMAKE_SOURCE_DIR}/src/3rdparty/qtmacgoodies/src
|
||||||
${CMAKE_SOURCE_DIR}/src/3rdparty/qtsingleapplication
|
${CMAKE_SOURCE_DIR}/src/3rdparty/qtsingleapplication
|
||||||
${CMAKE_SOURCE_DIR}/src/3rdparty/kmessagewidget
|
${CMAKE_SOURCE_DIR}/src/3rdparty/kmessagewidget
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
|||||||
@@ -368,7 +368,6 @@ void AccountManager::shutdown()
|
|||||||
_accounts.clear();
|
_accounts.clear();
|
||||||
foreach (const auto &acc, accountsCopy) {
|
foreach (const auto &acc, accountsCopy) {
|
||||||
emit accountRemoved(acc.data());
|
emit accountRemoved(acc.data());
|
||||||
emit removeAccountFolders(acc.data());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
void deleteAccount(AccountState *account);
|
void deleteAccount(AccountState *account);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an account and sets up some basic handlers.
|
* Creates an account and sets up some basic handlers.
|
||||||
* Does *not* add the account to the account manager just yet.
|
* Does *not* add the account to the account manager just yet.
|
||||||
@@ -103,7 +104,6 @@ public slots:
|
|||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void accountAdded(AccountState *account);
|
void accountAdded(AccountState *account);
|
||||||
void accountRemoved(AccountState *account);
|
void accountRemoved(AccountState *account);
|
||||||
void removeAccountFolders(AccountState *account);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AccountManager() {}
|
AccountManager() {}
|
||||||
|
|||||||
@@ -35,12 +35,10 @@
|
|||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "clientsideencryptionjobs.h"
|
#include "clientsideencryptionjobs.h"
|
||||||
#include "syncresult.h"
|
#include "syncresult.h"
|
||||||
#include "ignorelisttablewidget.h"
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDialogButtonBox>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QListWidgetItem>
|
#include <QListWidgetItem>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
@@ -57,6 +55,10 @@
|
|||||||
|
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
#include "settingsdialogmac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcAccountSettings, "nextcloud.gui.account.settings", QtInfoMsg)
|
Q_LOGGING_CATEGORY(lcAccountSettings, "nextcloud.gui.account.settings", QtInfoMsg)
|
||||||
@@ -109,13 +111,13 @@ protected:
|
|||||||
|
|
||||||
AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, _ui(new Ui::AccountSettings)
|
, ui(new Ui::AccountSettings)
|
||||||
, _wasDisabledBefore(false)
|
, _wasDisabledBefore(false)
|
||||||
, _accountState(accountState)
|
, _accountState(accountState)
|
||||||
, _quotaInfo(accountState)
|
, _quotaInfo(accountState)
|
||||||
, _menuShown(false)
|
, _menuShown(false)
|
||||||
{
|
{
|
||||||
_ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
_model = new FolderStatusModel;
|
_model = new FolderStatusModel;
|
||||||
_model->setAccountState(_accountState);
|
_model->setAccountState(_accountState);
|
||||||
@@ -123,40 +125,35 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
|||||||
FolderStatusDelegate *delegate = new FolderStatusDelegate;
|
FolderStatusDelegate *delegate = new FolderStatusDelegate;
|
||||||
delegate->setParent(this);
|
delegate->setParent(this);
|
||||||
|
|
||||||
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
|
ui->_folderList->header()->hide();
|
||||||
connect(this, &AccountSettings::styleChanged, delegate, &FolderStatusDelegate::slotStyleChanged);
|
ui->_folderList->setItemDelegate(delegate);
|
||||||
|
ui->_folderList->setModel(_model);
|
||||||
_ui->_folderList->header()->hide();
|
|
||||||
_ui->_folderList->setItemDelegate(delegate);
|
|
||||||
_ui->_folderList->setModel(_model);
|
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
_ui->_folderList->setMinimumWidth(400);
|
ui->_folderList->setMinimumWidth(400);
|
||||||
#else
|
#else
|
||||||
_ui->_folderList->setMinimumWidth(300);
|
ui->_folderList->setMinimumWidth(300);
|
||||||
#endif
|
#endif
|
||||||
new ToolTipUpdater(_ui->_folderList);
|
new ToolTipUpdater(ui->_folderList);
|
||||||
|
|
||||||
auto mouseCursorChanger = new MouseCursorChanger(this);
|
auto mouseCursorChanger = new MouseCursorChanger(this);
|
||||||
mouseCursorChanger->folderList = _ui->_folderList;
|
mouseCursorChanger->folderList = ui->_folderList;
|
||||||
mouseCursorChanger->model = _model;
|
mouseCursorChanger->model = _model;
|
||||||
_ui->_folderList->setMouseTracking(true);
|
ui->_folderList->setMouseTracking(true);
|
||||||
_ui->_folderList->setAttribute(Qt::WA_Hover, true);
|
ui->_folderList->setAttribute(Qt::WA_Hover, true);
|
||||||
_ui->_folderList->installEventFilter(mouseCursorChanger);
|
ui->_folderList->installEventFilter(mouseCursorChanger);
|
||||||
|
|
||||||
createAccountToolbox();
|
createAccountToolbox();
|
||||||
connect(AccountManager::instance(), &AccountManager::accountAdded,
|
connect(AccountManager::instance(), &AccountManager::accountAdded,
|
||||||
this, &AccountSettings::slotAccountAdded);
|
this, &AccountSettings::slotAccountAdded);
|
||||||
connect(this, &AccountSettings::removeAccountFolders,
|
connect(ui->_folderList, &QWidget::customContextMenuRequested,
|
||||||
AccountManager::instance(), &AccountManager::removeAccountFolders);
|
|
||||||
connect(_ui->_folderList, &QWidget::customContextMenuRequested,
|
|
||||||
this, &AccountSettings::slotCustomContextMenuRequested);
|
this, &AccountSettings::slotCustomContextMenuRequested);
|
||||||
connect(_ui->_folderList, &QAbstractItemView::clicked,
|
connect(ui->_folderList, &QAbstractItemView::clicked,
|
||||||
this, &AccountSettings::slotFolderListClicked);
|
this, &AccountSettings::slotFolderListClicked);
|
||||||
connect(_ui->_folderList, &QTreeView::expanded, this, &AccountSettings::refreshSelectiveSyncStatus);
|
connect(ui->_folderList, &QTreeView::expanded, this, &AccountSettings::refreshSelectiveSyncStatus);
|
||||||
connect(_ui->_folderList, &QTreeView::collapsed, this, &AccountSettings::refreshSelectiveSyncStatus);
|
connect(ui->_folderList, &QTreeView::collapsed, this, &AccountSettings::refreshSelectiveSyncStatus);
|
||||||
connect(_ui->selectiveSyncNotification, &QLabel::linkActivated,
|
connect(ui->selectiveSyncNotification, &QLabel::linkActivated,
|
||||||
this, &AccountSettings::slotLinkActivated);
|
this, &AccountSettings::slotLinkActivated);
|
||||||
connect(_model, &FolderStatusModel::suggestExpand, _ui->_folderList, &QTreeView::expand);
|
connect(_model, &FolderStatusModel::suggestExpand, ui->_folderList, &QTreeView::expand);
|
||||||
connect(_model, &FolderStatusModel::dirtyChanged, this, &AccountSettings::refreshSelectiveSyncStatus);
|
connect(_model, &FolderStatusModel::dirtyChanged, this, &AccountSettings::refreshSelectiveSyncStatus);
|
||||||
refreshSelectiveSyncStatus();
|
refreshSelectiveSyncStatus();
|
||||||
connect(_model, &QAbstractItemModel::rowsInserted,
|
connect(_model, &QAbstractItemModel::rowsInserted,
|
||||||
@@ -173,21 +170,20 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
|||||||
addAction(syncNowWithRemoteDiscovery);
|
addAction(syncNowWithRemoteDiscovery);
|
||||||
|
|
||||||
|
|
||||||
connect(_ui->selectiveSyncApply, &QAbstractButton::clicked, _model, &FolderStatusModel::slotApplySelectiveSync);
|
connect(ui->selectiveSyncApply, &QAbstractButton::clicked, _model, &FolderStatusModel::slotApplySelectiveSync);
|
||||||
connect(_ui->selectiveSyncCancel, &QAbstractButton::clicked, _model, &FolderStatusModel::resetFolders);
|
connect(ui->selectiveSyncCancel, &QAbstractButton::clicked, _model, &FolderStatusModel::resetFolders);
|
||||||
connect(_ui->bigFolderApply, &QAbstractButton::clicked, _model, &FolderStatusModel::slotApplySelectiveSync);
|
connect(ui->bigFolderApply, &QAbstractButton::clicked, _model, &FolderStatusModel::slotApplySelectiveSync);
|
||||||
connect(_ui->bigFolderSyncAll, &QAbstractButton::clicked, _model, &FolderStatusModel::slotSyncAllPendingBigFolders);
|
connect(ui->bigFolderSyncAll, &QAbstractButton::clicked, _model, &FolderStatusModel::slotSyncAllPendingBigFolders);
|
||||||
connect(_ui->bigFolderSyncNone, &QAbstractButton::clicked, _model, &FolderStatusModel::slotSyncNoPendingBigFolders);
|
connect(ui->bigFolderSyncNone, &QAbstractButton::clicked, _model, &FolderStatusModel::slotSyncNoPendingBigFolders);
|
||||||
|
|
||||||
connect(FolderMan::instance(), &FolderMan::folderListChanged, _model, &FolderStatusModel::resetFolders);
|
connect(FolderMan::instance(), &FolderMan::folderListChanged, _model, &FolderStatusModel::resetFolders);
|
||||||
connect(this, &AccountSettings::folderChanged, _model, &FolderStatusModel::resetFolders);
|
connect(this, &AccountSettings::folderChanged, _model, &FolderStatusModel::resetFolders);
|
||||||
|
|
||||||
|
|
||||||
// quotaProgressBar style now set in customizeStyle()
|
QColor color = palette().highlight().color();
|
||||||
/*QColor color = palette().highlight().color();
|
ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));
|
||||||
_ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));*/
|
|
||||||
|
|
||||||
_ui->connectLabel->setText(tr("No account configured."));
|
ui->connectLabel->setText(tr("No account configured."));
|
||||||
|
|
||||||
connect(_accountState, &AccountState::stateChanged, this, &AccountSettings::slotAccountStateChanged);
|
connect(_accountState, &AccountState::stateChanged, this, &AccountSettings::slotAccountStateChanged);
|
||||||
slotAccountStateChanged();
|
slotAccountStateChanged();
|
||||||
@@ -204,10 +200,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
|||||||
{
|
{
|
||||||
slotNewMnemonicGenerated();
|
slotNewMnemonicGenerated();
|
||||||
} else {
|
} else {
|
||||||
_ui->encryptionMessage->hide();
|
ui->encryptionMessage->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
customizeStyle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -229,9 +223,9 @@ void AccountSettings::createAccountToolbox()
|
|||||||
menu->addAction(action);
|
menu->addAction(action);
|
||||||
connect(action, &QAction::triggered, this, &AccountSettings::slotDeleteAccount);
|
connect(action, &QAction::triggered, this, &AccountSettings::slotDeleteAccount);
|
||||||
|
|
||||||
_ui->_accountToolbox->setText(tr("Account") + QLatin1Char(' '));
|
ui->_accountToolbox->setText(tr("Account") + QLatin1Char(' '));
|
||||||
_ui->_accountToolbox->setMenu(menu);
|
ui->_accountToolbox->setMenu(menu);
|
||||||
_ui->_accountToolbox->setPopupMode(QToolButton::InstantPopup);
|
ui->_accountToolbox->setPopupMode(QToolButton::InstantPopup);
|
||||||
|
|
||||||
slotAccountAdded(_accountState);
|
slotAccountAdded(_accountState);
|
||||||
}
|
}
|
||||||
@@ -239,14 +233,14 @@ void AccountSettings::createAccountToolbox()
|
|||||||
|
|
||||||
void AccountSettings::slotNewMnemonicGenerated()
|
void AccountSettings::slotNewMnemonicGenerated()
|
||||||
{
|
{
|
||||||
_ui->encryptionMessage->setText(tr("This account supports end-to-end encryption"));
|
ui->encryptionMessage->setText(tr("This account supports end-to-end encryption"));
|
||||||
|
|
||||||
QAction *mnemonic = new QAction(tr("Enable encryption"), this);
|
QAction *mnemonic = new QAction(tr("Enable encryption"), this);
|
||||||
connect(mnemonic, &QAction::triggered, this, &AccountSettings::requesetMnemonic);
|
connect(mnemonic, &QAction::triggered, this, &AccountSettings::requesetMnemonic);
|
||||||
connect(mnemonic, &QAction::triggered, _ui->encryptionMessage, &KMessageWidget::hide);
|
connect(mnemonic, &QAction::triggered, ui->encryptionMessage, &KMessageWidget::hide);
|
||||||
|
|
||||||
_ui->encryptionMessage->addAction(mnemonic);
|
ui->encryptionMessage->addAction(mnemonic);
|
||||||
_ui->encryptionMessage->show();
|
ui->encryptionMessage->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotMenuBeforeShow() {
|
void AccountSettings::slotMenuBeforeShow() {
|
||||||
@@ -254,7 +248,7 @@ void AccountSettings::slotMenuBeforeShow() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto menu = _ui->_accountToolbox->menu();
|
auto menu = ui->_accountToolbox->menu();
|
||||||
|
|
||||||
// We can't check this during the initial creation as there is no account yet then
|
// We can't check this during the initial creation as there is no account yet then
|
||||||
if (_accountState->account()->capabilities().clientSideEncryptionAvaliable()) {
|
if (_accountState->account()->capabilities().clientSideEncryptionAvaliable()) {
|
||||||
@@ -269,7 +263,7 @@ void AccountSettings::slotMenuBeforeShow() {
|
|||||||
|
|
||||||
QString AccountSettings::selectedFolderAlias() const
|
QString AccountSettings::selectedFolderAlias() const
|
||||||
{
|
{
|
||||||
QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex();
|
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
|
||||||
if (!selected.isValid())
|
if (!selected.isValid())
|
||||||
return "";
|
return "";
|
||||||
return _model->data(selected, FolderStatusDelegate::FolderAliasRole).toString();
|
return _model->data(selected, FolderStatusDelegate::FolderAliasRole).toString();
|
||||||
@@ -282,7 +276,16 @@ void AccountSettings::slotOpenAccountWizard()
|
|||||||
if (qgetenv("QT_QPA_PLATFORMTHEME") == "appmenu-qt5" || QSystemTrayIcon::isSystemTrayAvailable()) {
|
if (qgetenv("QT_QPA_PLATFORMTHEME") == "appmenu-qt5" || QSystemTrayIcon::isSystemTrayAvailable()) {
|
||||||
topLevelWidget()->close();
|
topLevelWidget()->close();
|
||||||
}
|
}
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
qCDebug(lcAccountSettings) << parent() << topLevelWidget();
|
||||||
|
SettingsDialogMac *sd = qobject_cast<SettingsDialogMac *>(topLevelWidget());
|
||||||
|
|
||||||
|
if (sd) {
|
||||||
|
sd->showActivityPage();
|
||||||
|
} else {
|
||||||
|
qFatal("nope");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), nullptr);
|
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +301,7 @@ void AccountSettings::slotToggleSignInState()
|
|||||||
|
|
||||||
void AccountSettings::doExpand()
|
void AccountSettings::doExpand()
|
||||||
{
|
{
|
||||||
_ui->_folderList->expandToDepth(0);
|
ui->_folderList->expandToDepth(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotShowMnemonic(const QString &mnemonic) {
|
void AccountSettings::slotShowMnemonic(const QString &mnemonic) {
|
||||||
@@ -329,9 +332,9 @@ void AccountSettings::slotEncryptionFlagError(const QByteArray& fileId, int http
|
|||||||
|
|
||||||
void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, const QByteArray &token)
|
void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, const QByteArray &token)
|
||||||
{
|
{
|
||||||
accountsState()->account()->e2e()->setTokenForFolder(fileId, token);
|
accountsState()->account()->e2e()->setTokenForFolder(fileId, token);
|
||||||
|
|
||||||
FolderMetadata emptyMetadata(accountsState()->account());
|
FolderMetadata emptyMetadata(accountsState()->account());
|
||||||
auto encryptedMetadata = emptyMetadata.encryptedMetadata();
|
auto encryptedMetadata = emptyMetadata.encryptedMetadata();
|
||||||
if (encryptedMetadata.isEmpty()) {
|
if (encryptedMetadata.isEmpty()) {
|
||||||
//TODO: Mark the folder as unencrypted as the metadata generation failed.
|
//TODO: Mark the folder as unencrypted as the metadata generation failed.
|
||||||
@@ -343,36 +346,36 @@ void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, con
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto storeMetadataJob = new StoreMetaDataApiJob(accountsState()->account(), fileId, emptyMetadata.encryptedMetadata());
|
auto storeMetadataJob = new StoreMetaDataApiJob(accountsState()->account(), fileId, emptyMetadata.encryptedMetadata());
|
||||||
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
|
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
|
||||||
this, &AccountSettings::slotUploadMetadataSuccess);
|
this, &AccountSettings::slotUploadMetadataSuccess);
|
||||||
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
|
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
|
||||||
this, &AccountSettings::slotUpdateMetadataError);
|
this, &AccountSettings::slotUpdateMetadataError);
|
||||||
|
|
||||||
storeMetadataJob->start();
|
storeMetadataJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotUploadMetadataSuccess(const QByteArray& folderId)
|
void AccountSettings::slotUploadMetadataSuccess(const QByteArray& folderId)
|
||||||
{
|
{
|
||||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||||
this, &AccountSettings::slotUnlockFolderError);
|
this, &AccountSettings::slotUnlockFolderError);
|
||||||
unlockJob->start();
|
unlockJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode)
|
void AccountSettings::slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode)
|
||||||
{
|
{
|
||||||
Q_UNUSED(httpReturnCode);
|
Q_UNUSED(httpReturnCode);
|
||||||
|
|
||||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||||
this, &AccountSettings::slotUnlockFolderError);
|
this, &AccountSettings::slotUnlockFolderError);
|
||||||
unlockJob->start();
|
unlockJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotLockForEncryptionError(const QByteArray& fileId, int httpErrorCode)
|
void AccountSettings::slotLockForEncryptionError(const QByteArray& fileId, int httpErrorCode)
|
||||||
@@ -419,7 +422,7 @@ bool AccountSettings::canEncryptOrDecrypt (const FolderStatusModel::SubFolderInf
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotMarkSubfolderEncrypted(const FolderStatusModel::SubFolderInfo* folderInfo)
|
void AccountSettings::slotMarkSubfolderEncrpted(const FolderStatusModel::SubFolderInfo* folderInfo)
|
||||||
{
|
{
|
||||||
if (!canEncryptOrDecrypt(folderInfo)) {
|
if (!canEncryptOrDecrypt(folderInfo)) {
|
||||||
return;
|
return;
|
||||||
@@ -536,51 +539,6 @@ void AccountSettings::slotLockForDecryptionError(const QByteArray& fileId, int h
|
|||||||
qDebug() << "Error Locking for decryption";
|
qDebug() << "Error Locking for decryption";
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotEditCurrentIgnoredFiles()
|
|
||||||
{
|
|
||||||
Folder *f = FolderMan::instance()->folder(selectedFolderAlias());
|
|
||||||
if (f == nullptr)
|
|
||||||
return;
|
|
||||||
openIgnoredFilesDialog(f->path());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccountSettings::slotEditCurrentLocalIgnoredFiles()
|
|
||||||
{
|
|
||||||
QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex();
|
|
||||||
if (!selected.isValid() || _model->classify(selected) != FolderStatusModel::SubFolder)
|
|
||||||
return;
|
|
||||||
QString fileName = _model->data(selected, FolderStatusDelegate::FolderPathRole).toString();
|
|
||||||
openIgnoredFilesDialog(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccountSettings::openIgnoredFilesDialog(const QString & absFolderPath)
|
|
||||||
{
|
|
||||||
Q_ASSERT(absFolderPath.startsWith('/'));
|
|
||||||
Q_ASSERT(absFolderPath.endsWith('/'));
|
|
||||||
|
|
||||||
const QString ignoreFile = absFolderPath + ".sync-exclude.lst";
|
|
||||||
auto layout = new QVBoxLayout();
|
|
||||||
auto ignoreListWidget = new IgnoreListTableWidget(this);
|
|
||||||
ignoreListWidget->readIgnoreFile(ignoreFile);
|
|
||||||
layout->addWidget(ignoreListWidget);
|
|
||||||
|
|
||||||
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
|
||||||
layout->addWidget(buttonBox);
|
|
||||||
|
|
||||||
auto dialog = new QDialog();
|
|
||||||
dialog->setLayout(layout);
|
|
||||||
|
|
||||||
connect(buttonBox, &QDialogButtonBox::clicked, [=](QAbstractButton * button) {
|
|
||||||
if (buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
|
|
||||||
ignoreListWidget->slotWriteIgnoreFile(ignoreFile);
|
|
||||||
dialog->close();
|
|
||||||
});
|
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected,
|
|
||||||
dialog, &QDialog::close);
|
|
||||||
|
|
||||||
dialog->open();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index, const QPoint& pos)
|
void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index, const QPoint& pos)
|
||||||
{
|
{
|
||||||
Q_UNUSED(pos);
|
Q_UNUSED(pos);
|
||||||
@@ -603,22 +561,18 @@ void AccountSettings::slotSubfolderContextMenuRequested(const QModelIndex& index
|
|||||||
|
|
||||||
if (!isEncrypted) {
|
if (!isEncrypted) {
|
||||||
ac = menu.addAction(tr("Encrypt"));
|
ac = menu.addAction(tr("Encrypt"));
|
||||||
connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderEncrypted(info); });
|
connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderEncrpted(info); });
|
||||||
} else {
|
} else {
|
||||||
// Ingore decrypting for now since it only works with an empty folder
|
// Ingore decrypting for now since it only works with an empty folder
|
||||||
// connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderDecrypted(info); });
|
// connect(ac, &QAction::triggered, [this, &info] { slotMarkSubfolderDecrypted(info); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ac = menu.addAction(tr("Edit Ignored Files"));
|
|
||||||
connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentLocalIgnoredFiles);
|
|
||||||
|
|
||||||
menu.exec(QCursor::pos());
|
menu.exec(QCursor::pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
|
void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
|
||||||
{
|
{
|
||||||
QTreeView *tv = _ui->_folderList;
|
QTreeView *tv = ui->_folderList;
|
||||||
QModelIndex index = tv->indexAt(pos);
|
QModelIndex index = tv->indexAt(pos);
|
||||||
if (!index.isValid()) {
|
if (!index.isValid()) {
|
||||||
return;
|
return;
|
||||||
@@ -646,10 +600,7 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
|
|||||||
QAction *ac = menu->addAction(tr("Open folder"));
|
QAction *ac = menu->addAction(tr("Open folder"));
|
||||||
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenCurrentFolder);
|
connect(ac, &QAction::triggered, this, &AccountSettings::slotOpenCurrentFolder);
|
||||||
|
|
||||||
ac = menu->addAction(tr("Edit Ignored Files"));
|
if (!ui->_folderList->isExpanded(index)) {
|
||||||
connect(ac, &QAction::triggered, this, &AccountSettings::slotEditCurrentIgnoredFiles);
|
|
||||||
|
|
||||||
if (!_ui->_folderList->isExpanded(index)) {
|
|
||||||
ac = menu->addAction(tr("Choose what to sync"));
|
ac = menu->addAction(tr("Choose what to sync"));
|
||||||
ac->setEnabled(folderConnected);
|
ac->setEnabled(folderConnected);
|
||||||
connect(ac, &QAction::triggered, this, &AccountSettings::doExpand);
|
connect(ac, &QAction::triggered, this, &AccountSettings::doExpand);
|
||||||
@@ -688,7 +639,7 @@ void AccountSettings::slotFolderListClicked(const QModelIndex &indx)
|
|||||||
}
|
}
|
||||||
if (_model->classify(indx) == FolderStatusModel::RootFolder) {
|
if (_model->classify(indx) == FolderStatusModel::RootFolder) {
|
||||||
// tries to find if we clicked on the '...' button.
|
// tries to find if we clicked on the '...' button.
|
||||||
QTreeView *tv = _ui->_folderList;
|
QTreeView *tv = ui->_folderList;
|
||||||
auto pos = tv->mapFromGlobal(QCursor::pos());
|
auto pos = tv->mapFromGlobal(QCursor::pos());
|
||||||
if (FolderStatusDelegate::optionsButtonRect(tv->visualRect(indx), layoutDirection()).contains(pos)) {
|
if (FolderStatusDelegate::optionsButtonRect(tv->visualRect(indx), layoutDirection()).contains(pos)) {
|
||||||
slotCustomContextMenuRequested(pos);
|
slotCustomContextMenuRequested(pos);
|
||||||
@@ -701,8 +652,8 @@ void AccountSettings::slotFolderListClicked(const QModelIndex &indx)
|
|||||||
|
|
||||||
// Expand root items on single click
|
// Expand root items on single click
|
||||||
if (_accountState && _accountState->state() == AccountState::Connected) {
|
if (_accountState && _accountState->state() == AccountState::Connected) {
|
||||||
bool expanded = !(_ui->_folderList->isExpanded(indx));
|
bool expanded = !(ui->_folderList->isExpanded(indx));
|
||||||
_ui->_folderList->setExpanded(indx, expanded);
|
ui->_folderList->setExpanded(indx, expanded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -739,7 +690,7 @@ void AccountSettings::slotFolderWizardAccepted()
|
|||||||
qCInfo(lcAccountSettings) << "Creating folder" << definition.localPath;
|
qCInfo(lcAccountSettings) << "Creating folder" << definition.localPath;
|
||||||
if (!dir.mkpath(".")) {
|
if (!dir.mkpath(".")) {
|
||||||
QMessageBox::warning(this, tr("Folder creation failed"),
|
QMessageBox::warning(this, tr("Folder creation failed"),
|
||||||
tr("<p>Could not create local folder <i>%1</i>.</p>")
|
tr("<p>Could not create local folder <i>%1</i>.")
|
||||||
.arg(QDir::toNativeSeparators(definition.localPath)));
|
.arg(QDir::toNativeSeparators(definition.localPath)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -784,7 +735,7 @@ void AccountSettings::slotRemoveCurrentFolder()
|
|||||||
{
|
{
|
||||||
FolderMan *folderMan = FolderMan::instance();
|
FolderMan *folderMan = FolderMan::instance();
|
||||||
auto folder = folderMan->folder(selectedFolderAlias());
|
auto folder = folderMan->folder(selectedFolderAlias());
|
||||||
QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex();
|
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
|
||||||
if (selected.isValid() && folder) {
|
if (selected.isValid() && folder) {
|
||||||
int row = selected.row();
|
int row = selected.row();
|
||||||
|
|
||||||
@@ -826,7 +777,7 @@ void AccountSettings::slotOpenCurrentFolder()
|
|||||||
|
|
||||||
void AccountSettings::slotOpenCurrentLocalSubFolder()
|
void AccountSettings::slotOpenCurrentLocalSubFolder()
|
||||||
{
|
{
|
||||||
QModelIndex selected = _ui->_folderList->selectionModel()->currentIndex();
|
QModelIndex selected = ui->_folderList->selectionModel()->currentIndex();
|
||||||
if (!selected.isValid() || _model->classify(selected) != FolderStatusModel::SubFolder)
|
if (!selected.isValid() || _model->classify(selected) != FolderStatusModel::SubFolder)
|
||||||
return;
|
return;
|
||||||
QString fileName = _model->data(selected, FolderStatusDelegate::FolderPathRole).toString();
|
QString fileName = _model->data(selected, FolderStatusDelegate::FolderPathRole).toString();
|
||||||
@@ -840,21 +791,18 @@ void AccountSettings::showConnectionLabel(const QString &message, QStringList er
|
|||||||
"border-width: 1px; border-style: solid; border-color: #aaaaaa;"
|
"border-width: 1px; border-style: solid; border-color: #aaaaaa;"
|
||||||
"border-radius:5px;");
|
"border-radius:5px;");
|
||||||
if (errors.isEmpty()) {
|
if (errors.isEmpty()) {
|
||||||
QString msg = message;
|
ui->connectLabel->setText(message);
|
||||||
Theme::replaceLinkColorStringBackgroundAware(msg);
|
ui->connectLabel->setToolTip(QString());
|
||||||
_ui->connectLabel->setText(msg);
|
ui->connectLabel->setStyleSheet(QString());
|
||||||
_ui->connectLabel->setToolTip(QString());
|
|
||||||
_ui->connectLabel->setStyleSheet(QString());
|
|
||||||
} else {
|
} else {
|
||||||
errors.prepend(message);
|
errors.prepend(message);
|
||||||
QString msg = errors.join(QLatin1String("\n"));
|
const QString msg = errors.join(QLatin1String("\n"));
|
||||||
qCDebug(lcAccountSettings) << msg;
|
qCDebug(lcAccountSettings) << msg;
|
||||||
Theme::replaceLinkColorString(msg, QColor("#c1c8e6"));
|
ui->connectLabel->setText(msg);
|
||||||
_ui->connectLabel->setText(msg);
|
ui->connectLabel->setToolTip(QString());
|
||||||
_ui->connectLabel->setToolTip(QString());
|
ui->connectLabel->setStyleSheet(errStyle);
|
||||||
_ui->connectLabel->setStyleSheet(errStyle);
|
|
||||||
}
|
}
|
||||||
_ui->accountStatus->setVisible(!message.isEmpty());
|
ui->accountStatus->setVisible(!message.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotEnableCurrentFolder()
|
void AccountSettings::slotEnableCurrentFolder()
|
||||||
@@ -952,29 +900,29 @@ void AccountSettings::slotOpenOC()
|
|||||||
void AccountSettings::slotUpdateQuota(qint64 total, qint64 used)
|
void AccountSettings::slotUpdateQuota(qint64 total, qint64 used)
|
||||||
{
|
{
|
||||||
if (total > 0) {
|
if (total > 0) {
|
||||||
_ui->quotaProgressBar->setVisible(true);
|
ui->quotaProgressBar->setVisible(true);
|
||||||
_ui->quotaProgressBar->setEnabled(true);
|
ui->quotaProgressBar->setEnabled(true);
|
||||||
// workaround the label only accepting ints (which may be only 32 bit wide)
|
// workaround the label only accepting ints (which may be only 32 bit wide)
|
||||||
const double percent = used / (double)total * 100;
|
const double percent = used / (double)total * 100;
|
||||||
const int percentInt = qMin(qRound(percent), 100);
|
const int percentInt = qMin(qRound(percent), 100);
|
||||||
_ui->quotaProgressBar->setValue(percentInt);
|
ui->quotaProgressBar->setValue(percentInt);
|
||||||
QString usedStr = Utility::octetsToString(used);
|
QString usedStr = Utility::octetsToString(used);
|
||||||
QString totalStr = Utility::octetsToString(total);
|
QString totalStr = Utility::octetsToString(total);
|
||||||
QString percentStr = Utility::compactFormatDouble(percent, 1);
|
QString percentStr = Utility::compactFormatDouble(percent, 1);
|
||||||
QString toolTip = tr("%1 (%3%) of %2 in use. Some folders, including network mounted or shared folders, might have different limits.").arg(usedStr, totalStr, percentStr);
|
QString toolTip = tr("%1 (%3%) of %2 in use. Some folders, including network mounted or shared folders, might have different limits.").arg(usedStr, totalStr, percentStr);
|
||||||
_ui->quotaInfoLabel->setText(tr("%1 of %2 in use").arg(usedStr, totalStr));
|
ui->quotaInfoLabel->setText(tr("%1 of %2 in use").arg(usedStr, totalStr));
|
||||||
_ui->quotaInfoLabel->setToolTip(toolTip);
|
ui->quotaInfoLabel->setToolTip(toolTip);
|
||||||
_ui->quotaProgressBar->setToolTip(toolTip);
|
ui->quotaProgressBar->setToolTip(toolTip);
|
||||||
} else {
|
} else {
|
||||||
_ui->quotaProgressBar->setVisible(false);
|
ui->quotaProgressBar->setVisible(false);
|
||||||
_ui->quotaInfoLabel->setToolTip(QString());
|
ui->quotaInfoLabel->setToolTip(QString());
|
||||||
|
|
||||||
/* -1 means not computed; -2 means unknown; -3 means unlimited (#3940)*/
|
/* -1 means not computed; -2 means unknown; -3 means unlimited (#3940)*/
|
||||||
if (total == 0 || total == -1) {
|
if (total == 0 || total == -1) {
|
||||||
_ui->quotaInfoLabel->setText(tr("Currently there is no storage usage information available."));
|
ui->quotaInfoLabel->setText(tr("Currently there is no storage usage information available."));
|
||||||
} else {
|
} else {
|
||||||
QString usedStr = Utility::octetsToString(used);
|
QString usedStr = Utility::octetsToString(used);
|
||||||
_ui->quotaInfoLabel->setText(tr("%1 in use").arg(usedStr));
|
ui->quotaInfoLabel->setText(tr("%1 in use").arg(usedStr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -983,7 +931,7 @@ void AccountSettings::slotAccountStateChanged()
|
|||||||
{
|
{
|
||||||
int state = _accountState ? _accountState->state() : AccountState::Disconnected;
|
int state = _accountState ? _accountState->state() : AccountState::Disconnected;
|
||||||
if (_accountState) {
|
if (_accountState) {
|
||||||
_ui->sslButton->updateAccountState(_accountState);
|
ui->sslButton->updateAccountState(_accountState);
|
||||||
AccountPtr account = _accountState->account();
|
AccountPtr account = _accountState->account();
|
||||||
QUrl safeUrl(account->url());
|
QUrl safeUrl(account->url());
|
||||||
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
|
safeUrl.setPassword(QString()); // Remove the password from the URL to avoid showing it in the UI
|
||||||
@@ -1028,7 +976,7 @@ void AccountSettings::slotAccountStateChanged()
|
|||||||
"<a href='%1'>Click here</a> to re-open the browser.")
|
"<a href='%1'>Click here</a> to re-open the browser.")
|
||||||
.arg(url.toString(QUrl::FullyEncoded)));
|
.arg(url.toString(QUrl::FullyEncoded)));
|
||||||
} else {
|
} else {
|
||||||
showConnectionLabel(tr("Connecting to %1 …").arg(serverWithUser));
|
showConnectionLabel(tr("Connecting to %1...").arg(serverWithUser));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showConnectionLabel(tr("No connection to %1 at %2.")
|
showConnectionLabel(tr("No connection to %1 at %2.")
|
||||||
@@ -1042,14 +990,14 @@ void AccountSettings::slotAccountStateChanged()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allow to expand the item if the account is connected. */
|
/* Allow to expand the item if the account is connected. */
|
||||||
_ui->_folderList->setItemsExpandable(state == AccountState::Connected);
|
ui->_folderList->setItemsExpandable(state == AccountState::Connected);
|
||||||
|
|
||||||
if (state != AccountState::Connected) {
|
if (state != AccountState::Connected) {
|
||||||
/* check if there are expanded root items, if so, close them */
|
/* check if there are expanded root items, if so, close them */
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < _model->rowCount(); ++i) {
|
for (i = 0; i < _model->rowCount(); ++i) {
|
||||||
if (_ui->_folderList->isExpanded(_model->index(i)))
|
if (ui->_folderList->isExpanded(_model->index(i)))
|
||||||
_ui->_folderList->setExpanded(_model->index(i), false);
|
ui->_folderList->setExpanded(_model->index(i), false);
|
||||||
}
|
}
|
||||||
} else if (_model->isDirty()) {
|
} else if (_model->isDirty()) {
|
||||||
// If we connect and have pending changes, show the list.
|
// If we connect and have pending changes, show the list.
|
||||||
@@ -1093,21 +1041,21 @@ void AccountSettings::slotLinkActivated(const QString &link)
|
|||||||
// Make sure the folder itself is expanded
|
// Make sure the folder itself is expanded
|
||||||
Folder *f = FolderMan::instance()->folder(alias);
|
Folder *f = FolderMan::instance()->folder(alias);
|
||||||
QModelIndex folderIndx = _model->indexForPath(f, QString());
|
QModelIndex folderIndx = _model->indexForPath(f, QString());
|
||||||
if (!_ui->_folderList->isExpanded(folderIndx)) {
|
if (!ui->_folderList->isExpanded(folderIndx)) {
|
||||||
_ui->_folderList->setExpanded(folderIndx, true);
|
ui->_folderList->setExpanded(folderIndx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex indx = _model->indexForPath(f, myFolder);
|
QModelIndex indx = _model->indexForPath(f, myFolder);
|
||||||
if (indx.isValid()) {
|
if (indx.isValid()) {
|
||||||
// make sure all the parents are expanded
|
// make sure all the parents are expanded
|
||||||
for (auto i = indx.parent(); i.isValid(); i = i.parent()) {
|
for (auto i = indx.parent(); i.isValid(); i = i.parent()) {
|
||||||
if (!_ui->_folderList->isExpanded(i)) {
|
if (!ui->_folderList->isExpanded(i)) {
|
||||||
_ui->_folderList->setExpanded(i, true);
|
ui->_folderList->setExpanded(i, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ui->_folderList->setSelectionMode(QAbstractItemView::SingleSelection);
|
ui->_folderList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
_ui->_folderList->setCurrentIndex(indx);
|
ui->_folderList->setCurrentIndex(indx);
|
||||||
_ui->_folderList->scrollTo(indx);
|
ui->_folderList->scrollTo(indx);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(lcAccountSettings) << "Unable to find a valid index for " << myFolder;
|
qCWarning(lcAccountSettings) << "Unable to find a valid index for " << myFolder;
|
||||||
}
|
}
|
||||||
@@ -1116,7 +1064,7 @@ void AccountSettings::slotLinkActivated(const QString &link)
|
|||||||
|
|
||||||
AccountSettings::~AccountSettings()
|
AccountSettings::~AccountSettings()
|
||||||
{
|
{
|
||||||
delete _ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::refreshSelectiveSyncStatus()
|
void AccountSettings::refreshSelectiveSyncStatus()
|
||||||
@@ -1154,8 +1102,8 @@ void AccountSettings::refreshSelectiveSyncStatus()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (msg.isEmpty()) {
|
if (msg.isEmpty()) {
|
||||||
_ui->selectiveSyncButtons->setVisible(true);
|
ui->selectiveSyncButtons->setVisible(true);
|
||||||
_ui->bigFolderUi->setVisible(false);
|
ui->bigFolderUi->setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
ConfigFile cfg;
|
ConfigFile cfg;
|
||||||
QString info = !cfg.confirmExternalStorage()
|
QString info = !cfg.confirmExternalStorage()
|
||||||
@@ -1164,27 +1112,27 @@ void AccountSettings::refreshSelectiveSyncStatus()
|
|||||||
? tr("There are folders that were not synchronized because they are external storages: ")
|
? tr("There are folders that were not synchronized because they are external storages: ")
|
||||||
: tr("There are folders that were not synchronized because they are too big or external storages: ");
|
: tr("There are folders that were not synchronized because they are too big or external storages: ");
|
||||||
|
|
||||||
_ui->selectiveSyncNotification->setText(info + msg);
|
ui->selectiveSyncNotification->setText(info + msg);
|
||||||
_ui->selectiveSyncButtons->setVisible(false);
|
ui->selectiveSyncButtons->setVisible(false);
|
||||||
_ui->bigFolderUi->setVisible(true);
|
ui->bigFolderUi->setVisible(true);
|
||||||
shouldBeVisible = true;
|
shouldBeVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ui->selectiveSyncApply->setEnabled(_model->isDirty() || !msg.isEmpty());
|
ui->selectiveSyncApply->setEnabled(_model->isDirty() || !msg.isEmpty());
|
||||||
bool wasVisible = !_ui->selectiveSyncStatus->isHidden();
|
bool wasVisible = !ui->selectiveSyncStatus->isHidden();
|
||||||
if (wasVisible != shouldBeVisible) {
|
if (wasVisible != shouldBeVisible) {
|
||||||
QSize hint = _ui->selectiveSyncStatus->sizeHint();
|
QSize hint = ui->selectiveSyncStatus->sizeHint();
|
||||||
if (shouldBeVisible) {
|
if (shouldBeVisible) {
|
||||||
_ui->selectiveSyncStatus->setMaximumHeight(0);
|
ui->selectiveSyncStatus->setMaximumHeight(0);
|
||||||
_ui->selectiveSyncStatus->setVisible(true);
|
ui->selectiveSyncStatus->setVisible(true);
|
||||||
}
|
}
|
||||||
auto anim = new QPropertyAnimation(_ui->selectiveSyncStatus, "maximumHeight", _ui->selectiveSyncStatus);
|
auto anim = new QPropertyAnimation(ui->selectiveSyncStatus, "maximumHeight", ui->selectiveSyncStatus);
|
||||||
anim->setEndValue(shouldBeVisible ? hint.height() : 0);
|
anim->setEndValue(shouldBeVisible ? hint.height() : 0);
|
||||||
anim->start(QAbstractAnimation::DeleteWhenStopped);
|
anim->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
connect(anim, &QPropertyAnimation::finished, [this, shouldBeVisible]() {
|
connect(anim, &QPropertyAnimation::finished, [this, shouldBeVisible]() {
|
||||||
_ui->selectiveSyncStatus->setMaximumHeight(QWIDGETSIZE_MAX);
|
ui->selectiveSyncStatus->setMaximumHeight(QWIDGETSIZE_MAX);
|
||||||
if (!shouldBeVisible) {
|
if (!shouldBeVisible) {
|
||||||
_ui->selectiveSyncStatus->hide();
|
ui->selectiveSyncStatus->hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1244,30 +1192,12 @@ bool AccountSettings::event(QEvent *e)
|
|||||||
// Expand the folder automatically only if there's only one, see #4283
|
// Expand the folder automatically only if there's only one, see #4283
|
||||||
// The 2 is 1 folder + 1 'add folder' button
|
// The 2 is 1 folder + 1 'add folder' button
|
||||||
if (_model->rowCount() <= 2) {
|
if (_model->rowCount() <= 2) {
|
||||||
_ui->_folderList->setExpanded(_model->index(0, 0), true);
|
ui->_folderList->setExpanded(_model->index(0, 0), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QWidget::event(e);
|
return QWidget::event(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountSettings::slotStyleChanged()
|
|
||||||
{
|
|
||||||
customizeStyle();
|
|
||||||
|
|
||||||
// Notify the other widgets (Dark-/Light-Mode switching)
|
|
||||||
emit styleChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccountSettings::customizeStyle()
|
|
||||||
{
|
|
||||||
QString msg = _ui->connectLabel->text();
|
|
||||||
Theme::replaceLinkColorStringBackgroundAware(msg);
|
|
||||||
_ui->connectLabel->setText(msg);
|
|
||||||
|
|
||||||
QColor color = palette().highlight().color();
|
|
||||||
_ui->quotaProgressBar->setStyleSheet(QString::fromLatin1(progressBarStyleC).arg(color.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|
||||||
#include "accountsettings.moc"
|
#include "accountsettings.moc"
|
||||||
|
|||||||
@@ -63,14 +63,11 @@ signals:
|
|||||||
void openFolderAlias(const QString &);
|
void openFolderAlias(const QString &);
|
||||||
void showIssuesList(AccountState *account);
|
void showIssuesList(AccountState *account);
|
||||||
void requesetMnemonic();
|
void requesetMnemonic();
|
||||||
void removeAccountFolders(AccountState *account);
|
|
||||||
void styleChanged();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void slotOpenOC();
|
void slotOpenOC();
|
||||||
void slotUpdateQuota(qint64, qint64);
|
void slotUpdateQuota(qint64, qint64);
|
||||||
void slotAccountStateChanged();
|
void slotAccountStateChanged();
|
||||||
void slotStyleChanged();
|
|
||||||
|
|
||||||
AccountState *accountsState() { return _accountState; }
|
AccountState *accountsState() { return _accountState; }
|
||||||
|
|
||||||
@@ -83,8 +80,6 @@ protected slots:
|
|||||||
void slotRemoveCurrentFolder();
|
void slotRemoveCurrentFolder();
|
||||||
void slotOpenCurrentFolder(); // sync folder
|
void slotOpenCurrentFolder(); // sync folder
|
||||||
void slotOpenCurrentLocalSubFolder(); // selected subfolder in sync folder
|
void slotOpenCurrentLocalSubFolder(); // selected subfolder in sync folder
|
||||||
void slotEditCurrentIgnoredFiles();
|
|
||||||
void slotEditCurrentLocalIgnoredFiles();
|
|
||||||
void slotFolderWizardAccepted();
|
void slotFolderWizardAccepted();
|
||||||
void slotFolderWizardRejected();
|
void slotFolderWizardRejected();
|
||||||
void slotDeleteAccount();
|
void slotDeleteAccount();
|
||||||
@@ -92,7 +87,7 @@ protected slots:
|
|||||||
void slotOpenAccountWizard();
|
void slotOpenAccountWizard();
|
||||||
void slotAccountAdded(AccountState *);
|
void slotAccountAdded(AccountState *);
|
||||||
void refreshSelectiveSyncStatus();
|
void refreshSelectiveSyncStatus();
|
||||||
void slotMarkSubfolderEncrypted(const FolderStatusModel::SubFolderInfo* folderInfo);
|
void slotMarkSubfolderEncrpted(const FolderStatusModel::SubFolderInfo* folderInfo);
|
||||||
void slotMarkSubfolderDecrypted(const FolderStatusModel::SubFolderInfo* folderInfo);
|
void slotMarkSubfolderDecrypted(const FolderStatusModel::SubFolderInfo* folderInfo);
|
||||||
void slotSubfolderContextMenuRequested(const QModelIndex& idx, const QPoint& point);
|
void slotSubfolderContextMenuRequested(const QModelIndex& idx, const QPoint& point);
|
||||||
void slotCustomContextMenuRequested(const QPoint &);
|
void slotCustomContextMenuRequested(const QPoint &);
|
||||||
@@ -115,7 +110,7 @@ protected slots:
|
|||||||
void slotUploadMetadataSuccess(const QByteArray& folderId);
|
void slotUploadMetadataSuccess(const QByteArray& folderId);
|
||||||
void slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode);
|
void slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode);
|
||||||
|
|
||||||
// Remove Encryption Bit.
|
// Remove Encryotion Bit.
|
||||||
void slotLockForDecryptionSuccess(const QByteArray& folderId, const QByteArray& token);
|
void slotLockForDecryptionSuccess(const QByteArray& folderId, const QByteArray& token);
|
||||||
void slotLockForDecryptionError(const QByteArray& folderId, int httpReturnCode);
|
void slotLockForDecryptionError(const QByteArray& folderId, int httpReturnCode);
|
||||||
void slotDeleteMetadataSuccess(const QByteArray& folderId);
|
void slotDeleteMetadataSuccess(const QByteArray& folderId);
|
||||||
@@ -130,13 +125,11 @@ private:
|
|||||||
QStringList errors = QStringList());
|
QStringList errors = QStringList());
|
||||||
bool event(QEvent *) override;
|
bool event(QEvent *) override;
|
||||||
void createAccountToolbox();
|
void createAccountToolbox();
|
||||||
void openIgnoredFilesDialog(const QString & absFolderPath);
|
|
||||||
void customizeStyle();
|
|
||||||
|
|
||||||
/// Returns the alias of the selected folder, empty string if none
|
/// Returns the alias of the selected folder, empty string if none
|
||||||
QString selectedFolderAlias() const;
|
QString selectedFolderAlias() const;
|
||||||
|
|
||||||
Ui::AccountSettings *_ui;
|
Ui::AccountSettings *ui;
|
||||||
|
|
||||||
FolderStatusModel *_model;
|
FolderStatusModel *_model;
|
||||||
QUrl _OCUrl;
|
QUrl _OCUrl;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string notr="true">Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
@@ -187,7 +187,7 @@
|
|||||||
<item row="0" column="2">
|
<item row="0" column="2">
|
||||||
<widget class="QToolButton" name="_accountToolbox">
|
<widget class="QToolButton" name="_accountToolbox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
#include "accountmanager.h"
|
#include "accountmanager.h"
|
||||||
#include "remotewipe.h"
|
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "creds/abstractcredentials.h"
|
#include "creds/abstractcredentials.h"
|
||||||
#include "creds/httpcredentials.h"
|
#include "creds/httpcredentials.h"
|
||||||
@@ -25,11 +24,6 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <qfontmetrics.h>
|
#include <qfontmetrics.h>
|
||||||
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QBuffer>
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcAccountState, "nextcloud.gui.account.state", QtInfoMsg)
|
Q_LOGGING_CATEGORY(lcAccountState, "nextcloud.gui.account.state", QtInfoMsg)
|
||||||
@@ -42,12 +36,11 @@ AccountState::AccountState(AccountPtr account)
|
|||||||
, _waitingForNewCredentials(false)
|
, _waitingForNewCredentials(false)
|
||||||
, _notificationsEtagResponseHeader("*")
|
, _notificationsEtagResponseHeader("*")
|
||||||
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
|
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
|
||||||
, _remoteWipe(new RemoteWipe(_account))
|
|
||||||
{
|
{
|
||||||
qRegisterMetaType<AccountState *>("AccountState*");
|
qRegisterMetaType<AccountState *>("AccountState*");
|
||||||
|
|
||||||
connect(account.data(), &Account::invalidCredentials,
|
connect(account.data(), &Account::invalidCredentials,
|
||||||
this, &AccountState::slotHandleRemoteWipeCheck);
|
this, &AccountState::slotInvalidCredentials);
|
||||||
connect(account.data(), &Account::credentialsFetched,
|
connect(account.data(), &Account::credentialsFetched,
|
||||||
this, &AccountState::slotCredentialsFetched);
|
this, &AccountState::slotCredentialsFetched);
|
||||||
connect(account.data(), &Account::credentialsAsked,
|
connect(account.data(), &Account::credentialsAsked,
|
||||||
@@ -310,7 +303,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
|||||||
break;
|
break;
|
||||||
case ConnectionValidator::CredentialsWrong:
|
case ConnectionValidator::CredentialsWrong:
|
||||||
case ConnectionValidator::CredentialsNotReady:
|
case ConnectionValidator::CredentialsNotReady:
|
||||||
handleInvalidCredentials();
|
slotInvalidCredentials();
|
||||||
break;
|
break;
|
||||||
case ConnectionValidator::SslError:
|
case ConnectionValidator::SslError:
|
||||||
setState(SignedOut);
|
setState(SignedOut);
|
||||||
@@ -329,20 +322,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccountState::slotHandleRemoteWipeCheck()
|
void AccountState::slotInvalidCredentials()
|
||||||
{
|
|
||||||
// make sure it changes account state and icons
|
|
||||||
signOutByUi();
|
|
||||||
|
|
||||||
qCInfo(lcAccountState) << "Invalid credentials for" << _account->url().toString()
|
|
||||||
<< "checking for remote wipe request";
|
|
||||||
|
|
||||||
_waitingForNewCredentials = false;
|
|
||||||
setState(SignedOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AccountState::handleInvalidCredentials()
|
|
||||||
{
|
{
|
||||||
if (isSignedOut() || _waitingForNewCredentials)
|
if (isSignedOut() || _waitingForNewCredentials)
|
||||||
return;
|
return;
|
||||||
@@ -363,7 +343,6 @@ void AccountState::handleInvalidCredentials()
|
|||||||
account()->credentials()->askFromUser();
|
account()->credentials()->askFromUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AccountState::slotCredentialsFetched(AbstractCredentials *)
|
void AccountState::slotCredentialsFetched(AbstractCredentials *)
|
||||||
{
|
{
|
||||||
// Make a connection attempt, no matter whether the credentials are
|
// Make a connection attempt, no matter whether the credentials are
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ namespace OCC {
|
|||||||
|
|
||||||
class AccountState;
|
class AccountState;
|
||||||
class Account;
|
class Account;
|
||||||
class RemoteWipe;
|
|
||||||
|
|
||||||
typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
|
typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
|
||||||
|
|
||||||
@@ -151,9 +150,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setNavigationAppsEtagResponseHeader(const QByteArray &value);
|
void setNavigationAppsEtagResponseHeader(const QByteArray &value);
|
||||||
|
|
||||||
///Asks for user credentials
|
|
||||||
void handleInvalidCredentials();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// Triggers a ping to the server to update state and
|
/// Triggers a ping to the server to update state and
|
||||||
/// connection status and errors.
|
/// connection status and errors.
|
||||||
@@ -168,11 +164,7 @@ signals:
|
|||||||
|
|
||||||
protected Q_SLOTS:
|
protected Q_SLOTS:
|
||||||
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors);
|
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors);
|
||||||
|
void slotInvalidCredentials();
|
||||||
/// When client gets a 401 or 403 checks if server requested remote wipe
|
|
||||||
/// before asking for user credentials again
|
|
||||||
void slotHandleRemoteWipeCheck();
|
|
||||||
|
|
||||||
void slotCredentialsFetched(AbstractCredentials *creds);
|
void slotCredentialsFetched(AbstractCredentials *creds);
|
||||||
void slotCredentialsAsked(AbstractCredentials *creds);
|
void slotCredentialsAsked(AbstractCredentials *creds);
|
||||||
|
|
||||||
@@ -198,13 +190,6 @@ private:
|
|||||||
* Milliseconds for which to delay reconnection after 503/maintenance.
|
* Milliseconds for which to delay reconnection after 503/maintenance.
|
||||||
*/
|
*/
|
||||||
int _maintenanceToConnectedDelay;
|
int _maintenanceToConnectedDelay;
|
||||||
|
|
||||||
/**
|
|
||||||
* Connects remote wipe check with the account
|
|
||||||
* the log out triggers the check (loads app password -> create request)
|
|
||||||
*/
|
|
||||||
RemoteWipe *_remoteWipe;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace OCC {
|
|||||||
|
|
||||||
bool operator<(const Activity &rhs, const Activity &lhs)
|
bool operator<(const Activity &rhs, const Activity &lhs)
|
||||||
{
|
{
|
||||||
return rhs._dateTime > lhs._dateTime;
|
return rhs._dateTime.toMSecsSinceEpoch() > lhs._dateTime.toMSecsSinceEpoch();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Activity &rhs, const Activity &lhs)
|
bool operator==(const Activity &rhs, const Activity &lhs)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "activityitemdelegate.h"
|
#include "activityitemdelegate.h"
|
||||||
#include "activitylistmodel.h"
|
|
||||||
#include "folderstatusmodel.h"
|
#include "folderstatusmodel.h"
|
||||||
#include "folderman.h"
|
#include "folderman.h"
|
||||||
#include "accountstate.h"
|
#include "accountstate.h"
|
||||||
@@ -27,14 +26,6 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
#define FIXME_USE_HIGH_DPI_RATIO
|
|
||||||
#ifdef FIXME_USE_HIGH_DPI_RATIO
|
|
||||||
// FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
|
|
||||||
#include <QDesktopWidget>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define HASQT5_11 (QT_VERSION >= QT_VERSION_CHECK(5,11,0))
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
int ActivityItemDelegate::_iconHeight = 0;
|
int ActivityItemDelegate::_iconHeight = 0;
|
||||||
@@ -47,12 +38,6 @@ int ActivityItemDelegate::_buttonHeight = 0;
|
|||||||
const QString ActivityItemDelegate::_remote_share("remote_share");
|
const QString ActivityItemDelegate::_remote_share("remote_share");
|
||||||
const QString ActivityItemDelegate::_call("call");
|
const QString ActivityItemDelegate::_call("call");
|
||||||
|
|
||||||
ActivityItemDelegate::ActivityItemDelegate()
|
|
||||||
: QStyledItemDelegate()
|
|
||||||
{
|
|
||||||
customizeStyle();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ActivityItemDelegate::iconHeight()
|
int ActivityItemDelegate::iconHeight()
|
||||||
{
|
{
|
||||||
if (_iconHeight == 0) {
|
if (_iconHeight == 0) {
|
||||||
@@ -102,26 +87,10 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
int iconSize = 16;
|
int iconSize = 16;
|
||||||
int iconOffset = qRound(fm.height() / 4.0 * 7.0);
|
int iconOffset = qRound(fm.height() / 4.0 * 7.0);
|
||||||
int offset = 4;
|
int offset = 4;
|
||||||
const bool isSelected = (option.state & QStyle::State_Selected);
|
|
||||||
#ifdef FIXME_USE_HIGH_DPI_RATIO
|
|
||||||
// FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
|
|
||||||
const int device_pixel_ration = QApplication::desktop()->devicePixelRatio();
|
|
||||||
int pixel_ratio = (device_pixel_ration > 1 ? device_pixel_ration : 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// get the data
|
// get the data
|
||||||
Activity::Type activityType = qvariant_cast<Activity::Type>(index.data(ActionRole));
|
Activity::Type activityType = qvariant_cast<Activity::Type>(index.data(ActionRole));
|
||||||
QIcon actionIcon;
|
QIcon actionIcon = qvariant_cast<QIcon>(index.data(ActionIconRole));
|
||||||
const ActivityListModel::ActionIcon icn = qvariant_cast<ActivityListModel::ActionIcon>(index.data(ActionIconRole));
|
|
||||||
switch(icn.iconType) {
|
|
||||||
case ActivityListModel::ActivityIconType::iconUseCached: actionIcon = icn.cachedIcon; break;
|
|
||||||
case ActivityListModel::ActivityIconType::iconActivity: actionIcon = (isSelected ? _iconActivity_sel : _iconActivity); break;
|
|
||||||
case ActivityListModel::ActivityIconType::iconBell: actionIcon = (isSelected ? _iconBell_sel : _iconBell); break;
|
|
||||||
case ActivityListModel::ActivityIconType::iconStateError: actionIcon = _iconStateError; break;
|
|
||||||
case ActivityListModel::ActivityIconType::iconStateWarning: actionIcon = _iconStateWarning; break;
|
|
||||||
case ActivityListModel::ActivityIconType::iconStateInfo: actionIcon = _iconStateInfo; break;
|
|
||||||
case ActivityListModel::ActivityIconType::iconStateSync: actionIcon = _iconStateSync; break;
|
|
||||||
}
|
|
||||||
QString objectType = qvariant_cast<QString>(index.data(ObjectTypeRole));
|
QString objectType = qvariant_cast<QString>(index.data(ObjectTypeRole));
|
||||||
QString actionText = qvariant_cast<QString>(index.data(ActionTextRole));
|
QString actionText = qvariant_cast<QString>(index.data(ActionTextRole));
|
||||||
QString messageText = qvariant_cast<QString>(index.data(MessageRole));
|
QString messageText = qvariant_cast<QString>(index.data(MessageRole));
|
||||||
@@ -137,27 +106,15 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
|
|
||||||
// subject text rect
|
// subject text rect
|
||||||
QRect actionTextBox = actionIconRect;
|
QRect actionTextBox = actionIconRect;
|
||||||
#if (HASQT5_11)
|
|
||||||
int actionTextBoxWidth = fm.horizontalAdvance(actionText);
|
|
||||||
#else
|
|
||||||
int actionTextBoxWidth = fm.width(actionText);
|
int actionTextBoxWidth = fm.width(actionText);
|
||||||
#endif
|
|
||||||
actionTextBox.setTop(option.rect.top() + margin + offset/2);
|
actionTextBox.setTop(option.rect.top() + margin + offset/2);
|
||||||
actionTextBox.setHeight(fm.height());
|
actionTextBox.setHeight(fm.height());
|
||||||
actionTextBox.setLeft(actionIconRect.right() + margin);
|
actionTextBox.setLeft(actionIconRect.right() + margin);
|
||||||
#ifdef FIXME_USE_HIGH_DPI_RATIO
|
|
||||||
// FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
|
|
||||||
actionTextBoxWidth *= pixel_ratio;
|
|
||||||
#endif
|
|
||||||
actionTextBox.setRight(actionTextBox.left() + actionTextBoxWidth + margin);
|
actionTextBox.setRight(actionTextBox.left() + actionTextBoxWidth + margin);
|
||||||
|
|
||||||
// message text rect
|
// message text rect
|
||||||
QRect messageTextBox = actionTextBox;
|
QRect messageTextBox = actionTextBox;
|
||||||
#if (HASQT5_11)
|
|
||||||
int messageTextWidth = fm.horizontalAdvance(messageText);
|
|
||||||
#else
|
|
||||||
int messageTextWidth = fm.width(messageText);
|
int messageTextWidth = fm.width(messageText);
|
||||||
#endif
|
|
||||||
int messageTextTop = option.rect.top() + fm.height() + margin;
|
int messageTextTop = option.rect.top() + fm.height() + margin;
|
||||||
if(actionText.isEmpty()) messageTextTop = option.rect.top() + margin + offset/2;
|
if(actionText.isEmpty()) messageTextTop = option.rect.top() + margin + offset/2;
|
||||||
messageTextBox.setTop(messageTextTop);
|
messageTextBox.setTop(messageTextTop);
|
||||||
@@ -171,21 +128,14 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
|
|
||||||
// time box rect
|
// time box rect
|
||||||
QRect timeBox = messageTextBox;
|
QRect timeBox = messageTextBox;
|
||||||
#if (HASQT5_11)
|
QString timeStr = tr("%1").arg(timeText);
|
||||||
int timeTextWidth = fm.horizontalAdvance(timeText);
|
int timeTextWidth = fm.width(timeStr);
|
||||||
#else
|
|
||||||
int timeTextWidth = fm.width(timeText);
|
|
||||||
#endif
|
|
||||||
int timeTop = option.rect.top() + fm.height() + fm.height() + margin + offset/2;
|
int timeTop = option.rect.top() + fm.height() + fm.height() + margin + offset/2;
|
||||||
if(messageText.isEmpty() || actionText.isEmpty())
|
if(messageText.isEmpty() || actionText.isEmpty())
|
||||||
timeTop = option.rect.top() + fm.height() + margin;
|
timeTop = option.rect.top() + fm.height() + margin;
|
||||||
timeBox.setTop(timeTop);
|
timeBox.setTop(timeTop);
|
||||||
timeBox.setHeight(fm.height());
|
timeBox.setHeight(fm.height());
|
||||||
timeBox.setBottom(timeBox.top() + fm.height());
|
timeBox.setBottom(timeBox.top() + fm.height());
|
||||||
#ifdef FIXME_USE_HIGH_DPI_RATIO
|
|
||||||
// FIXME: Find a better way to calculate the text width on high-dpi displays (Retina).
|
|
||||||
timeTextWidth *= pixel_ratio;
|
|
||||||
#endif
|
|
||||||
timeBox.setRight(timeBox.left() + timeTextWidth + margin);
|
timeBox.setRight(timeBox.left() + timeTextWidth + margin);
|
||||||
|
|
||||||
// buttons - default values
|
// buttons - default values
|
||||||
@@ -220,9 +170,9 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
if(activityType == Activity::Type::NotificationType){
|
if(activityType == Activity::Type::NotificationType){
|
||||||
|
|
||||||
// Secondary will be 'Dismiss' or '...' multiple options button
|
// Secondary will be 'Dismiss' or '...' multiple options button
|
||||||
secondaryButton.icon = (isSelected ? _iconClose_sel : _iconClose);
|
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/close.svg"));
|
||||||
if(customList.size() > 1)
|
if(customList.size() > 1)
|
||||||
secondaryButton.icon = (isSelected ? _iconMore_sel : _iconMore);
|
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/more.svg"));
|
||||||
secondaryButton.iconSize = QSize(iconSize, iconSize);
|
secondaryButton.iconSize = QSize(iconSize, iconSize);
|
||||||
|
|
||||||
// Primary button will be 'More Information' or 'Accept'
|
// Primary button will be 'More Information' or 'Accept'
|
||||||
@@ -230,11 +180,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
if(objectType == _remote_share) primaryButton.text = tr("Accept");
|
if(objectType == _remote_share) primaryButton.text = tr("Accept");
|
||||||
if(objectType == _call) primaryButton.text = tr("Join");
|
if(objectType == _call) primaryButton.text = tr("Join");
|
||||||
|
|
||||||
#if (HASQT5_11)
|
|
||||||
primaryButton.rect.setLeft(left - margin * 2 - fm.horizontalAdvance(primaryButton.text));
|
|
||||||
#else
|
|
||||||
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
|
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
|
||||||
#endif
|
|
||||||
|
|
||||||
// save info to be able to filter mouse clicks
|
// save info to be able to filter mouse clicks
|
||||||
_buttonHeight = buttonSize;
|
_buttonHeight = buttonSize;
|
||||||
@@ -245,17 +191,12 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
} else if(activityType == Activity::SyncResultType){
|
} else if(activityType == Activity::SyncResultType){
|
||||||
|
|
||||||
// Secondary will be 'open file manager' with the folder icon
|
// Secondary will be 'open file manager' with the folder icon
|
||||||
secondaryButton.icon = _iconFolder;
|
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/folder.svg"));
|
||||||
secondaryButton.iconSize = QSize(iconSize, iconSize);
|
secondaryButton.iconSize = QSize(iconSize, iconSize);
|
||||||
|
|
||||||
// Primary button will be 'open browser'
|
// Primary button will be 'open browser'
|
||||||
primaryButton.text = tr("Open Browser");
|
primaryButton.text = tr("Open Browser");
|
||||||
|
|
||||||
#if (HASQT5_11)
|
|
||||||
primaryButton.rect.setLeft(left - margin * 2 - fm.horizontalAdvance(primaryButton.text));
|
|
||||||
#else
|
|
||||||
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
|
primaryButton.rect.setLeft(left - margin * 2 - fm.width(primaryButton.text));
|
||||||
#endif
|
|
||||||
|
|
||||||
// save info to be able to filter mouse clicks
|
// save info to be able to filter mouse clicks
|
||||||
_buttonHeight = buttonSize;
|
_buttonHeight = buttonSize;
|
||||||
@@ -266,7 +207,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
} else if(activityType == Activity::SyncFileItemType){
|
} else if(activityType == Activity::SyncFileItemType){
|
||||||
|
|
||||||
// Secondary will be 'open file manager' with the folder icon
|
// Secondary will be 'open file manager' with the folder icon
|
||||||
secondaryButton.icon = _iconFolder;
|
secondaryButton.icon = QIcon(QLatin1String(":/client/resources/folder.svg"));
|
||||||
secondaryButton.iconSize = QSize(iconSize, iconSize);
|
secondaryButton.iconSize = QSize(iconSize, iconSize);
|
||||||
|
|
||||||
// No primary button on this case
|
// No primary button on this case
|
||||||
@@ -291,7 +232,7 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
p.setCurrentColorGroup(QPalette::Disabled);
|
p.setCurrentColorGroup(QPalette::Disabled);
|
||||||
|
|
||||||
// change pen color if the line is selected
|
// change pen color if the line is selected
|
||||||
if (isSelected)
|
if (option.state & QStyle::State_Selected)
|
||||||
painter->setPen(p.color(QPalette::HighlightedText));
|
painter->setPen(p.color(QPalette::HighlightedText));
|
||||||
else
|
else
|
||||||
painter->setPen(p.color(QPalette::Text));
|
painter->setPen(p.color(QPalette::Text));
|
||||||
@@ -305,15 +246,8 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
painter->drawText(actionTextBox, elidedAction);
|
painter->drawText(actionTextBox, elidedAction);
|
||||||
|
|
||||||
// draw the buttons
|
// draw the buttons
|
||||||
if(activityType == Activity::Type::NotificationType || activityType == Activity::Type::SyncResultType) {
|
if(activityType == Activity::Type::NotificationType || activityType == Activity::Type::SyncResultType)
|
||||||
primaryButton.palette = p;
|
|
||||||
if (isSelected)
|
|
||||||
primaryButton.palette.setColor(QPalette::ButtonText, p.color(QPalette::HighlightedText));
|
|
||||||
else
|
|
||||||
primaryButton.palette.setColor(QPalette::ButtonText, p.color(QPalette::Text));
|
|
||||||
|
|
||||||
QApplication::style()->drawControl(QStyle::CE_PushButton, &primaryButton, painter);
|
QApplication::style()->drawControl(QStyle::CE_PushButton, &primaryButton, painter);
|
||||||
}
|
|
||||||
|
|
||||||
// Since they are errors on local syncing, there is nothing to do in the server
|
// Since they are errors on local syncing, there is nothing to do in the server
|
||||||
if(activityType != Activity::Type::ActivityType)
|
if(activityType != Activity::Type::ActivityType)
|
||||||
@@ -327,13 +261,13 @@ void ActivityItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
}
|
}
|
||||||
|
|
||||||
// change pen color for the time
|
// change pen color for the time
|
||||||
if (isSelected)
|
if (option.state & QStyle::State_Selected)
|
||||||
painter->setPen(p.color(QPalette::Disabled, QPalette::HighlightedText));
|
painter->setPen(p.color(QPalette::Disabled, QPalette::HighlightedText));
|
||||||
else
|
else
|
||||||
painter->setPen(p.color(QPalette::Disabled, QPalette::Text));
|
painter->setPen(p.color(QPalette::Disabled, QPalette::Text));
|
||||||
|
|
||||||
// draw the time
|
// draw the time
|
||||||
const QString elidedTime = fm.elidedText(timeText, Qt::ElideRight, spaceLeftForText);
|
const QString elidedTime = fm.elidedText(timeStr, Qt::ElideRight, spaceLeftForText);
|
||||||
painter->drawText(timeBox, elidedTime);
|
painter->drawText(timeBox, elidedTime);
|
||||||
|
|
||||||
painter->restore();
|
painter->restore();
|
||||||
@@ -376,32 +310,4 @@ bool ActivityItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
|||||||
return QStyledItemDelegate::editorEvent(event, model, option, index);
|
return QStyledItemDelegate::editorEvent(event, model, option, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityItemDelegate::slotStyleChanged()
|
|
||||||
{
|
|
||||||
customizeStyle();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActivityItemDelegate::customizeStyle()
|
|
||||||
{
|
|
||||||
QPalette pal;
|
|
||||||
pal.setColor(QPalette::Base, QColor(0,0,0)); // use dark background colour to invert icons
|
|
||||||
|
|
||||||
_iconClose = Theme::createColorAwareIcon(QLatin1String(":/client/resources/close.svg"));
|
|
||||||
_iconClose_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/close.svg"), pal);
|
|
||||||
_iconMore = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"));
|
|
||||||
_iconMore_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"), pal);
|
|
||||||
|
|
||||||
_iconFolder = QIcon(QLatin1String(":/client/resources/folder.svg"));
|
|
||||||
|
|
||||||
_iconActivity = Theme::createColorAwareIcon(QLatin1String(":/client/resources/activity.png"));
|
|
||||||
_iconActivity_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/activity.png"), pal);
|
|
||||||
_iconBell = Theme::createColorAwareIcon(QLatin1String(":/client/resources/bell.svg"));
|
|
||||||
_iconBell_sel = Theme::createColorAwareIcon(QLatin1String(":/client/resources/bell.svg"), pal);
|
|
||||||
|
|
||||||
_iconStateError = QIcon(QLatin1String(":/client/resources/state-error.svg"));
|
|
||||||
_iconStateWarning = QIcon(QLatin1String(":/client/resources/state-warning.svg"));
|
|
||||||
_iconStateInfo = QIcon(QLatin1String(":/client/resources/state-info.svg"));
|
|
||||||
_iconStateSync = QIcon(QLatin1String(":/client/resources/state-sync.svg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ public:
|
|||||||
AccountConnectedRole,
|
AccountConnectedRole,
|
||||||
SyncFileStatusRole };
|
SyncFileStatusRole };
|
||||||
|
|
||||||
ActivityItemDelegate();
|
|
||||||
|
|
||||||
void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override;
|
void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override;
|
||||||
QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override;
|
QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const override;
|
||||||
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
|
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
|
||||||
@@ -53,16 +51,11 @@ public:
|
|||||||
static int rowHeight();
|
static int rowHeight();
|
||||||
static int iconHeight();
|
static int iconHeight();
|
||||||
|
|
||||||
public slots:
|
|
||||||
void slotStyleChanged();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void primaryButtonClickedOnItemView(const QModelIndex &index);
|
void primaryButtonClickedOnItemView(const QModelIndex &index);
|
||||||
void secondaryButtonClickedOnItemView(const QModelIndex &index);
|
void secondaryButtonClickedOnItemView(const QModelIndex &index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void customizeStyle();
|
|
||||||
|
|
||||||
static int _margin;
|
static int _margin;
|
||||||
static int _iconHeight;
|
static int _iconHeight;
|
||||||
static int _primaryButtonWidth;
|
static int _primaryButtonWidth;
|
||||||
@@ -72,23 +65,6 @@ private:
|
|||||||
static int _buttonHeight;
|
static int _buttonHeight;
|
||||||
static const QString _remote_share;
|
static const QString _remote_share;
|
||||||
static const QString _call;
|
static const QString _call;
|
||||||
|
|
||||||
QIcon _iconClose;
|
|
||||||
QIcon _iconClose_sel;
|
|
||||||
QIcon _iconMore;
|
|
||||||
QIcon _iconMore_sel;
|
|
||||||
|
|
||||||
QIcon _iconFolder;
|
|
||||||
|
|
||||||
QIcon _iconActivity;
|
|
||||||
QIcon _iconActivity_sel;
|
|
||||||
QIcon _iconBell;
|
|
||||||
QIcon _iconBell_sel;
|
|
||||||
|
|
||||||
QIcon _iconStateError;
|
|
||||||
QIcon _iconStateWarning;
|
|
||||||
QIcon _iconStateInfo;
|
|
||||||
QIcon _iconStateSync;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -71,14 +71,13 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant(list.at(0));
|
return QVariant(list.at(0));
|
||||||
}
|
}
|
||||||
// File does not exist anymore? Let's try to open its path
|
// File does not exist anymore? Let's try to open its path
|
||||||
if(QFileInfo(relPath).exists()) {
|
list = FolderMan::instance()->findFileInLocalFolders(QFileInfo(relPath).path(), ast->account());
|
||||||
list = FolderMan::instance()->findFileInLocalFolders(QFileInfo(relPath).path(), ast->account());
|
if (list.count() > 0) {
|
||||||
if (list.count() > 0) {
|
return QVariant(list.at(0));
|
||||||
return QVariant(list.at(0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
break;
|
||||||
case ActivityItemDelegate::ActionsLinksRole:{
|
case ActivityItemDelegate::ActionsLinksRole:{
|
||||||
QList<QVariant> customList;
|
QList<QVariant> customList;
|
||||||
foreach (ActivityLink customItem, a._links) {
|
foreach (ActivityLink customItem, a._links) {
|
||||||
@@ -87,61 +86,60 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
|
|||||||
customList << customVariant;
|
customList << customVariant;
|
||||||
}
|
}
|
||||||
return customList;
|
return customList;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case ActivityItemDelegate::ActionIconRole:{
|
case ActivityItemDelegate::ActionIconRole:
|
||||||
ActionIcon actionIcon;
|
|
||||||
if(a._type == Activity::NotificationType){
|
if(a._type == Activity::NotificationType){
|
||||||
QIcon cachedIcon = ServerNotificationHandler::iconCache.value(a._id);
|
QIcon cachedIcon = ServerNotificationHandler::iconCache.value(a._id);
|
||||||
if(!cachedIcon.isNull()) {
|
if(!cachedIcon.isNull())
|
||||||
actionIcon.iconType = ActivityIconType::iconUseCached;
|
return cachedIcon;
|
||||||
actionIcon.cachedIcon = cachedIcon;
|
else return QIcon(QLatin1String(":/client/resources/bell.svg"));
|
||||||
} else {
|
|
||||||
actionIcon.iconType = ActivityIconType::iconBell;
|
|
||||||
}
|
|
||||||
} else if(a._type == Activity::SyncResultType){
|
} else if(a._type == Activity::SyncResultType){
|
||||||
actionIcon.iconType = ActivityIconType::iconStateError;
|
return QIcon(QLatin1String(":/client/resources/state-error.svg"));
|
||||||
} else if(a._type == Activity::SyncFileItemType){
|
} else if(a._type == Activity::SyncFileItemType){
|
||||||
if(a._status == SyncFileItem::NormalError
|
if(a._status == SyncFileItem::NormalError
|
||||||
|| a._status == SyncFileItem::FatalError
|
|| a._status == SyncFileItem::FatalError
|
||||||
|| a._status == SyncFileItem::DetailError
|
|| a._status == SyncFileItem::DetailError
|
||||||
|| a._status == SyncFileItem::BlacklistedError) {
|
|| a._status == SyncFileItem::BlacklistedError) {
|
||||||
actionIcon.iconType = ActivityIconType::iconStateError;
|
return QIcon(QLatin1String(":/client/resources/state-error.svg"));
|
||||||
} else if(a._status == SyncFileItem::SoftError
|
} else if(a._status == SyncFileItem::SoftError
|
||||||
|
|| a._status == SyncFileItem::FileIgnored
|
||||||
|| a._status == SyncFileItem::Conflict
|
|| a._status == SyncFileItem::Conflict
|
||||||
|| a._status == SyncFileItem::Restoration
|
|| a._status == SyncFileItem::Restoration
|
||||||
|| a._status == SyncFileItem::FileLocked){
|
|| a._status == SyncFileItem::FileLocked){
|
||||||
actionIcon.iconType = ActivityIconType::iconStateWarning;
|
return QIcon(QLatin1String(":/client/resources/state-warning.svg"));
|
||||||
} else if(a._status == SyncFileItem::FileIgnored){
|
|
||||||
actionIcon.iconType = ActivityIconType::iconStateInfo;
|
|
||||||
} else {
|
|
||||||
actionIcon.iconType = ActivityIconType::iconStateSync;
|
|
||||||
}
|
}
|
||||||
} else {
|
return QIcon(QLatin1String(":/client/resources/state-sync.svg"));
|
||||||
actionIcon.iconType = ActivityIconType::iconActivity;
|
|
||||||
}
|
}
|
||||||
QVariant icn;
|
return QIcon(QLatin1String(":/client/resources/activity.png"));
|
||||||
icn.setValue(actionIcon);
|
break;
|
||||||
return icn;
|
|
||||||
}
|
|
||||||
case ActivityItemDelegate::ObjectTypeRole:
|
case ActivityItemDelegate::ObjectTypeRole:
|
||||||
return a._objectType;
|
return a._objectType;
|
||||||
|
break;
|
||||||
case ActivityItemDelegate::ActionRole:{
|
case ActivityItemDelegate::ActionRole:{
|
||||||
QVariant type;
|
QVariant type;
|
||||||
type.setValue(a._type);
|
type.setValue(a._type);
|
||||||
return type;
|
return type;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case ActivityItemDelegate::ActionTextRole:
|
case ActivityItemDelegate::ActionTextRole:
|
||||||
return a._subject;
|
return a._subject;
|
||||||
|
break;
|
||||||
case ActivityItemDelegate::MessageRole:
|
case ActivityItemDelegate::MessageRole:
|
||||||
return a._message;
|
return a._message;
|
||||||
|
break;
|
||||||
case ActivityItemDelegate::LinkRole:
|
case ActivityItemDelegate::LinkRole:
|
||||||
return a._link;
|
return a._link;
|
||||||
|
break;
|
||||||
case ActivityItemDelegate::AccountRole:
|
case ActivityItemDelegate::AccountRole:
|
||||||
return a._accName;
|
return a._accName;
|
||||||
|
break;
|
||||||
case ActivityItemDelegate::PointInTimeRole:
|
case ActivityItemDelegate::PointInTimeRole:
|
||||||
return QString("%1 (%2)").arg(a._dateTime.toLocalTime().toString(Qt::DefaultLocaleShortDate), Utility::timeAgoInWords(a._dateTime.toLocalTime()));
|
return Utility::timeAgoInWords(a._dateTime);
|
||||||
|
break;
|
||||||
case ActivityItemDelegate::AccountConnectedRole:
|
case ActivityItemDelegate::AccountConnectedRole:
|
||||||
return (ast && ast->isConnected());
|
return (ast && ast->isConnected());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@@ -230,29 +228,6 @@ void ActivityListModel::addErrorToActivityList(Activity activity) {
|
|||||||
combineActivityLists();
|
combineActivityLists();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityListModel::addIgnoredFileToList(Activity newActivity) {
|
|
||||||
qCInfo(lcActivity) << "First checking for duplicates then add file to the notification list of ignored files: " << newActivity._file;
|
|
||||||
|
|
||||||
bool duplicate = false;
|
|
||||||
if(_listOfIgnoredFiles.size() == 0){
|
|
||||||
_notificationIgnoredFiles = newActivity;
|
|
||||||
_notificationIgnoredFiles._subject = tr("Files from the ignore list as well as symbolic links are not synced. This includes:");
|
|
||||||
_listOfIgnoredFiles.append(newActivity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(Activity activity, _listOfIgnoredFiles){
|
|
||||||
if(activity._file == newActivity._file){
|
|
||||||
duplicate = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!duplicate){
|
|
||||||
_notificationIgnoredFiles._message.append(", " + newActivity._file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActivityListModel::addNotificationToActivityList(Activity activity) {
|
void ActivityListModel::addNotificationToActivityList(Activity activity) {
|
||||||
qCInfo(lcActivity) << "Notification successfully added to the notification list: " << activity._subject;
|
qCInfo(lcActivity) << "Notification successfully added to the notification list: " << activity._subject;
|
||||||
_notificationLists.prepend(activity);
|
_notificationLists.prepend(activity);
|
||||||
@@ -266,7 +241,7 @@ void ActivityListModel::clearNotifications() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ActivityListModel::removeActivityFromActivityList(int row) {
|
void ActivityListModel::removeActivityFromActivityList(int row) {
|
||||||
Activity activity = _finalList.at(row);
|
Activity activity = _finalList.at(row);
|
||||||
removeActivityFromActivityList(activity);
|
removeActivityFromActivityList(activity);
|
||||||
combineActivityLists();
|
combineActivityLists();
|
||||||
}
|
}
|
||||||
@@ -300,31 +275,22 @@ void ActivityListModel::removeActivityFromActivityList(Activity activity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ActivityListModel::combineActivityLists()
|
void ActivityListModel::combineActivityLists()
|
||||||
{
|
{
|
||||||
ActivityList resultList;
|
ActivityList resultList;
|
||||||
|
|
||||||
if(_notificationErrorsLists.count() > 0) {
|
std::sort(_notificationErrorsLists.begin(), _notificationErrorsLists.end());
|
||||||
std::sort(_notificationErrorsLists.begin(), _notificationErrorsLists.end());
|
resultList.append(_notificationErrorsLists);
|
||||||
resultList.append(_notificationErrorsLists);
|
|
||||||
}
|
|
||||||
if(_listOfIgnoredFiles.size() > 0)
|
|
||||||
resultList.append(_notificationIgnoredFiles);
|
|
||||||
|
|
||||||
if(_notificationLists.count() > 0) {
|
std::sort(_notificationLists.begin(), _notificationLists.end());
|
||||||
std::sort(_notificationLists.begin(), _notificationLists.end());
|
resultList.append(_notificationLists);
|
||||||
resultList.append(_notificationLists);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_syncFileItemLists.count() > 0) {
|
std::sort(_syncFileItemLists.begin(), _syncFileItemLists.end());
|
||||||
std::sort(_syncFileItemLists.begin(), _syncFileItemLists.end());
|
resultList.append(_syncFileItemLists);
|
||||||
resultList.append(_syncFileItemLists);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_activityLists.count() > 0) {
|
std::sort(_activityLists.begin(), _activityLists.end());
|
||||||
std::sort(_activityLists.begin(), _activityLists.end());
|
resultList.append(_activityLists);
|
||||||
resultList.append(_activityLists);
|
|
||||||
}
|
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
_finalList.clear();
|
_finalList.clear();
|
||||||
|
|||||||
@@ -38,20 +38,6 @@ class ActivityListModel : public QAbstractListModel
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum ActivityIconType {
|
|
||||||
iconUseCached = 0,
|
|
||||||
iconActivity,
|
|
||||||
iconBell,
|
|
||||||
iconStateError,
|
|
||||||
iconStateWarning,
|
|
||||||
iconStateInfo,
|
|
||||||
iconStateSync
|
|
||||||
};
|
|
||||||
struct ActionIcon {
|
|
||||||
ActivityIconType iconType;
|
|
||||||
QIcon cachedIcon;
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit ActivityListModel(AccountState *accountState, QWidget *parent = nullptr);
|
explicit ActivityListModel(AccountState *accountState, QWidget *parent = nullptr);
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
@@ -65,7 +51,6 @@ public:
|
|||||||
void addNotificationToActivityList(Activity activity);
|
void addNotificationToActivityList(Activity activity);
|
||||||
void clearNotifications();
|
void clearNotifications();
|
||||||
void addErrorToActivityList(Activity activity);
|
void addErrorToActivityList(Activity activity);
|
||||||
void addIgnoredFileToList(Activity newActivity);
|
|
||||||
void addSyncFileItemToActivityList(Activity activity);
|
void addSyncFileItemToActivityList(Activity activity);
|
||||||
void removeActivityFromActivityList(int row);
|
void removeActivityFromActivityList(int row);
|
||||||
void removeActivityFromActivityList(Activity activity);
|
void removeActivityFromActivityList(Activity activity);
|
||||||
@@ -88,8 +73,6 @@ private:
|
|||||||
ActivityList _activityLists;
|
ActivityList _activityLists;
|
||||||
ActivityList _syncFileItemLists;
|
ActivityList _syncFileItemLists;
|
||||||
ActivityList _notificationLists;
|
ActivityList _notificationLists;
|
||||||
ActivityList _listOfIgnoredFiles;
|
|
||||||
Activity _notificationIgnoredFiles;
|
|
||||||
ActivityList _notificationErrorsLists;
|
ActivityList _notificationErrorsLists;
|
||||||
ActivityList _finalList;
|
ActivityList _finalList;
|
||||||
AccountState *_accountState;
|
AccountState *_accountState;
|
||||||
@@ -98,7 +81,4 @@ private:
|
|||||||
int _currentItem = 0;
|
int _currentItem = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(OCC::ActivityListModel::ActionIcon)
|
|
||||||
|
|
||||||
#endif // ACTIVITYLISTMODEL_H
|
#endif // ACTIVITYLISTMODEL_H
|
||||||
|
|||||||
@@ -89,9 +89,6 @@ ActivityWidget::ActivityWidget(AccountState *accountState, QWidget *parent)
|
|||||||
this, &ActivityWidget::addError);
|
this, &ActivityWidget::addError);
|
||||||
|
|
||||||
_removeTimer.setInterval(1000);
|
_removeTimer.setInterval(1000);
|
||||||
|
|
||||||
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
|
|
||||||
connect(this, &ActivityWidget::styleChanged, delegate, &ActivityItemDelegate::slotStyleChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivityWidget::~ActivityWidget()
|
ActivityWidget::~ActivityWidget()
|
||||||
@@ -130,12 +127,11 @@ void ActivityWidget::slotProgressInfo(const QString &folder, const ProgressInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(activity._status == SyncFileItem::FileIgnored && !QFileInfo(f->path() + activity._file).exists()) {
|
if(activity._status == SyncFileItem::FileIgnored && !QFileInfo(f->path() + activity._file).exists()){
|
||||||
_model->removeActivityFromActivityList(activity);
|
_model->removeActivityFromActivityList(activity);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(!QFileInfo(f->path() + activity._file).exists()){
|
if(!QFileInfo(f->path() + activity._file).exists()){
|
||||||
_model->removeActivityFromActivityList(activity);
|
_model->removeActivityFromActivityList(activity);
|
||||||
continue;
|
continue;
|
||||||
@@ -179,7 +175,7 @@ void ActivityWidget::slotItemCompleted(const QString &folder, const SyncFileItem
|
|||||||
Activity activity;
|
Activity activity;
|
||||||
activity._type = Activity::SyncFileItemType; //client activity
|
activity._type = Activity::SyncFileItemType; //client activity
|
||||||
activity._status = item->_status;
|
activity._status = item->_status;
|
||||||
activity._dateTime = QDateTime::currentDateTime();
|
activity._dateTime = QDateTime::fromString(QDateTime::currentDateTime().toString(), Qt::ISODate);
|
||||||
activity._message = item->_originalFile;
|
activity._message = item->_originalFile;
|
||||||
activity._link = folderInstance->accountState()->account()->url();
|
activity._link = folderInstance->accountState()->account()->url();
|
||||||
activity._accName = folderInstance->accountState()->account()->displayName();
|
activity._accName = folderInstance->accountState()->account()->displayName();
|
||||||
@@ -195,12 +191,8 @@ void ActivityWidget::slotItemCompleted(const QString &folder, const SyncFileItem
|
|||||||
qCWarning(lcActivity) << "Item " << item->_file << " retrieved resulted in error " << item->_errorString;
|
qCWarning(lcActivity) << "Item " << item->_file << " retrieved resulted in error " << item->_errorString;
|
||||||
activity._subject = item->_errorString;
|
activity._subject = item->_errorString;
|
||||||
|
|
||||||
if(item->_status == SyncFileItem::Status::FileIgnored) {
|
// add 'protocol error' to activity list
|
||||||
_model->addIgnoredFileToList(activity);
|
_model->addErrorToActivityList(activity);
|
||||||
} else {
|
|
||||||
// add 'protocol error' to activity list
|
|
||||||
_model->addErrorToActivityList(activity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -551,12 +543,6 @@ void ActivityWidget::slotNotifyServerFinished(const QString &reply, int replyCod
|
|||||||
qCInfo(lcActivity) << "Server Notification reply code" << replyCode << reply;
|
qCInfo(lcActivity) << "Server Notification reply code" << replyCode << reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityWidget::slotStyleChanged()
|
|
||||||
{
|
|
||||||
// Notify the other widgets (Dark-/Light-Mode switching)
|
|
||||||
emit styleChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
|
|
||||||
ActivitySettings::ActivitySettings(AccountState *accountState, QWidget *parent)
|
ActivitySettings::ActivitySettings(AccountState *accountState, QWidget *parent)
|
||||||
@@ -579,9 +565,6 @@ ActivitySettings::ActivitySettings(AccountState *accountState, QWidget *parent)
|
|||||||
// connect a model signal to stop the animation
|
// connect a model signal to stop the animation
|
||||||
connect(_activityWidget, &ActivityWidget::rowsInserted, _progressIndicator, &QProgressIndicator::stopAnimation);
|
connect(_activityWidget, &ActivityWidget::rowsInserted, _progressIndicator, &QProgressIndicator::stopAnimation);
|
||||||
connect(_activityWidget, &ActivityWidget::rowsInserted, this, &ActivitySettings::slotDisplayActivities);
|
connect(_activityWidget, &ActivityWidget::rowsInserted, this, &ActivitySettings::slotDisplayActivities);
|
||||||
|
|
||||||
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
|
|
||||||
connect(this, &ActivitySettings::styleChanged, _activityWidget, &ActivityWidget::slotStyleChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivitySettings::slotDisplayActivities(){
|
void ActivitySettings::slotDisplayActivities(){
|
||||||
@@ -640,14 +623,4 @@ bool ActivitySettings::event(QEvent *e)
|
|||||||
ActivitySettings::~ActivitySettings()
|
ActivitySettings::~ActivitySettings()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivitySettings::slotStyleChanged()
|
|
||||||
{
|
|
||||||
if(_progressIndicator)
|
|
||||||
_progressIndicator->setColor(QGuiApplication::palette().color(QPalette::Text));
|
|
||||||
|
|
||||||
// Notify the other widgets (Dark-/Light-Mode switching)
|
|
||||||
emit styleChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,14 +78,12 @@ public slots:
|
|||||||
void addError(const QString &folderAlias, const QString &message, ErrorCategory category);
|
void addError(const QString &folderAlias, const QString &message, ErrorCategory category);
|
||||||
void slotProgressInfo(const QString &folder, const ProgressInfo &progress);
|
void slotProgressInfo(const QString &folder, const ProgressInfo &progress);
|
||||||
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
|
void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
|
||||||
void slotStyleChanged();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void guiLog(const QString &, const QString &);
|
void guiLog(const QString &, const QString &);
|
||||||
void rowsInserted();
|
void rowsInserted();
|
||||||
void hideActivityTab(bool);
|
void hideActivityTab(bool);
|
||||||
void sendNotificationRequest(const QString &accountName, const QString &link, const QByteArray &verb, int row);
|
void sendNotificationRequest(const QString &accountName, const QString &link, const QByteArray &verb, int row);
|
||||||
void styleChanged();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotBuildNotificationDisplay(const ActivityList &list);
|
void slotBuildNotificationDisplay(const ActivityList &list);
|
||||||
@@ -98,7 +96,6 @@ private slots:
|
|||||||
void slotSecondaryButtonClickedOnListView(const QModelIndex &index);
|
void slotSecondaryButtonClickedOnListView(const QModelIndex &index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void customizeStyle();
|
|
||||||
void showLabels();
|
void showLabels();
|
||||||
QString timeString(QDateTime dt, QLocale::FormatType format) const;
|
QString timeString(QDateTime dt, QLocale::FormatType format) const;
|
||||||
Ui::ActivityWidget *_ui;
|
Ui::ActivityWidget *_ui;
|
||||||
@@ -140,7 +137,6 @@ public slots:
|
|||||||
void slotRefresh();
|
void slotRefresh();
|
||||||
void slotRemoveAccount();
|
void slotRemoveAccount();
|
||||||
void setNotificationRefreshInterval(std::chrono::milliseconds interval);
|
void setNotificationRefreshInterval(std::chrono::milliseconds interval);
|
||||||
void slotStyleChanged();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotRegularNotificationCheck();
|
void slotRegularNotificationCheck();
|
||||||
@@ -148,7 +144,6 @@ private slots:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void guiLog(const QString &, const QString &);
|
void guiLog(const QString &, const QString &);
|
||||||
void styleChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool event(QEvent *e) override;
|
bool event(QEvent *e) override;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string notr="true">Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="sizeConstraint">
|
<property name="sizeConstraint">
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">TextLabel</string>
|
<string>TextLabel</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ Application::Application(int &argc, char **argv)
|
|||||||
, _userTriggeredConnect(false)
|
, _userTriggeredConnect(false)
|
||||||
, _debugMode(false)
|
, _debugMode(false)
|
||||||
, _backgroundMode(false)
|
, _backgroundMode(false)
|
||||||
, _isQuitting(false)
|
|
||||||
{
|
{
|
||||||
_startedAt.start();
|
_startedAt.start();
|
||||||
|
|
||||||
@@ -254,9 +253,6 @@ Application::Application(int &argc, char **argv)
|
|||||||
|
|
||||||
// Cleanup at Quit.
|
// Cleanup at Quit.
|
||||||
connect(this, &QCoreApplication::aboutToQuit, this, &Application::slotCleanup);
|
connect(this, &QCoreApplication::aboutToQuit, this, &Application::slotCleanup);
|
||||||
|
|
||||||
// Allow other classes to hook into isShowingSettingsDialog() signals (re-auth widgets, for example)
|
|
||||||
connect(_gui.data(), &ownCloudGui::isShowingSettingsDialog, this, &Application::slotGuiIsShowingSettings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application()
|
Application::~Application()
|
||||||
@@ -268,8 +264,6 @@ Application::~Application()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove the account from the account manager so it can be deleted.
|
// Remove the account from the account manager so it can be deleted.
|
||||||
disconnect(AccountManager::instance(), &AccountManager::accountRemoved,
|
|
||||||
this, &Application::slotAccountStateRemoved);
|
|
||||||
AccountManager::instance()->shutdown();
|
AccountManager::instance()->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +283,7 @@ void Application::slotAccountStateRemoved(AccountState *accountState)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if there is no more account, show the wizard.
|
// if there is no more account, show the wizard.
|
||||||
if (!_isQuitting && AccountManager::instance()->accounts().isEmpty()) {
|
if (AccountManager::instance()->accounts().isEmpty()) {
|
||||||
// allow to add a new account if there is non any more. Always think
|
// allow to add a new account if there is non any more. Always think
|
||||||
// about single account theming!
|
// about single account theming!
|
||||||
OwncloudSetupWizard::runWizard(this, SLOT(slotownCloudWizardDone(int)));
|
OwncloudSetupWizard::runWizard(this, SLOT(slotownCloudWizardDone(int)));
|
||||||
@@ -312,8 +306,6 @@ void Application::slotAccountStateAdded(AccountState *accountState)
|
|||||||
|
|
||||||
void Application::slotCleanup()
|
void Application::slotCleanup()
|
||||||
{
|
{
|
||||||
_isQuitting = true;
|
|
||||||
|
|
||||||
AccountManager::instance()->save();
|
AccountManager::instance()->save();
|
||||||
FolderMan::instance()->unloadAndDeleteAllFolders();
|
FolderMan::instance()->unloadAndDeleteAllFolders();
|
||||||
|
|
||||||
@@ -651,9 +643,5 @@ void Application::showSettingsDialog()
|
|||||||
_gui->slotShowSettings();
|
_gui->slotShowSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::slotGuiIsShowingSettings()
|
|
||||||
{
|
|
||||||
emit isShowingSettingsDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ protected:
|
|||||||
signals:
|
signals:
|
||||||
void folderRemoved();
|
void folderRemoved();
|
||||||
void folderStateChanged(Folder *);
|
void folderStateChanged(Folder *);
|
||||||
void isShowingSettingsDialog();
|
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void slotParseMessage(const QString &, QObject *);
|
void slotParseMessage(const QString &, QObject *);
|
||||||
@@ -92,7 +91,6 @@ protected slots:
|
|||||||
void slotAccountStateAdded(AccountState *accountState);
|
void slotAccountStateAdded(AccountState *accountState);
|
||||||
void slotAccountStateRemoved(AccountState *accountState);
|
void slotAccountStateRemoved(AccountState *accountState);
|
||||||
void slotSystemOnlineConfigurationChanged(QNetworkConfiguration);
|
void slotSystemOnlineConfigurationChanged(QNetworkConfiguration);
|
||||||
void slotGuiIsShowingSettings();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setHelp();
|
void setHelp();
|
||||||
@@ -116,7 +114,6 @@ private:
|
|||||||
bool _userTriggeredConnect;
|
bool _userTriggeredConnect;
|
||||||
bool _debugMode;
|
bool _debugMode;
|
||||||
bool _backgroundMode;
|
bool _backgroundMode;
|
||||||
bool _isQuitting;
|
|
||||||
|
|
||||||
ClientProxy _proxy;
|
ClientProxy _proxy;
|
||||||
|
|
||||||
|
|||||||
@@ -1,271 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
|
|
||||||
* Copyright (C) by Michael Schuster <michael@nextcloud.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 <QDesktopServices>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QClipboard>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QBuffer>
|
|
||||||
#include "account.h"
|
|
||||||
#include "flow2auth.h"
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include "theme.h"
|
|
||||||
#include "networkjobs.h"
|
|
||||||
#include "configfile.h"
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcFlow2auth, "nextcloud.sync.credentials.flow2auth", QtInfoMsg)
|
|
||||||
|
|
||||||
|
|
||||||
Flow2Auth::Flow2Auth(Account *account, QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
, _account(account)
|
|
||||||
, _isBusy(false)
|
|
||||||
, _hasToken(false)
|
|
||||||
{
|
|
||||||
_pollTimer.setInterval(1000);
|
|
||||||
QObject::connect(&_pollTimer, &QTimer::timeout, this, &Flow2Auth::slotPollTimerTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
Flow2Auth::~Flow2Auth()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Flow2Auth::start()
|
|
||||||
{
|
|
||||||
// Note: All startup code is in openBrowser() to allow reinitiate a new request with
|
|
||||||
// fresh tokens. Opening the same pollEndpoint link twice triggers an expiration
|
|
||||||
// message by the server (security, intended design).
|
|
||||||
openBrowser();
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl Flow2Auth::authorisationLink() const
|
|
||||||
{
|
|
||||||
return _loginUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Flow2Auth::openBrowser()
|
|
||||||
{
|
|
||||||
fetchNewToken(TokenAction::actionOpenBrowser);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Flow2Auth::copyLinkToClipboard()
|
|
||||||
{
|
|
||||||
fetchNewToken(TokenAction::actionCopyLinkToClipboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Flow2Auth::fetchNewToken(const TokenAction action)
|
|
||||||
{
|
|
||||||
if(_isBusy)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_isBusy = true;
|
|
||||||
_hasToken = false;
|
|
||||||
|
|
||||||
emit statusChanged(PollStatus::statusFetchToken, 0);
|
|
||||||
|
|
||||||
// Step 1: Initiate a login, do an anonymous POST request
|
|
||||||
QUrl url = Utility::concatUrlPath(_account->url().toString(), QLatin1String("/index.php/login/v2"));
|
|
||||||
|
|
||||||
// add 'Content-Length: 0' header (see https://github.com/nextcloud/desktop/issues/1473)
|
|
||||||
QNetworkRequest req;
|
|
||||||
req.setHeader(QNetworkRequest::ContentLengthHeader, "0");
|
|
||||||
|
|
||||||
auto job = _account->sendRequest("POST", url, req);
|
|
||||||
job->setTimeout(qMin(30 * 1000ll, job->timeoutMsec()));
|
|
||||||
|
|
||||||
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this, action](QNetworkReply *reply) {
|
|
||||||
auto jsonData = reply->readAll();
|
|
||||||
QJsonParseError jsonParseError;
|
|
||||||
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
|
|
||||||
QString pollToken, pollEndpoint, loginUrl;
|
|
||||||
|
|
||||||
if (reply->error() == QNetworkReply::NoError && jsonParseError.error == QJsonParseError::NoError
|
|
||||||
&& !json.isEmpty()) {
|
|
||||||
pollToken = json.value("poll").toObject().value("token").toString();
|
|
||||||
pollEndpoint = json.value("poll").toObject().value("endpoint").toString();
|
|
||||||
loginUrl = json["login"].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError
|
|
||||||
|| json.isEmpty() || pollToken.isEmpty() || pollEndpoint.isEmpty() || loginUrl.isEmpty()) {
|
|
||||||
QString errorReason;
|
|
||||||
QString errorFromJson = json["error"].toString();
|
|
||||||
if (!errorFromJson.isEmpty()) {
|
|
||||||
errorReason = tr("Error returned from the server: <em>%1</em>")
|
|
||||||
.arg(errorFromJson.toHtmlEscaped());
|
|
||||||
} else if (reply->error() != QNetworkReply::NoError) {
|
|
||||||
errorReason = tr("There was an error accessing the 'token' endpoint: <br><em>%1</em>")
|
|
||||||
.arg(reply->errorString().toHtmlEscaped());
|
|
||||||
} else if (jsonParseError.error != QJsonParseError::NoError) {
|
|
||||||
errorReason = tr("Could not parse the JSON returned from the server: <br><em>%1</em>")
|
|
||||||
.arg(jsonParseError.errorString());
|
|
||||||
} else {
|
|
||||||
errorReason = tr("The reply from the server did not contain all expected fields");
|
|
||||||
}
|
|
||||||
qCWarning(lcFlow2auth) << "Error when getting the loginUrl" << json << errorReason;
|
|
||||||
emit result(Error, errorReason);
|
|
||||||
_pollTimer.stop();
|
|
||||||
_isBusy = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_loginUrl = loginUrl;
|
|
||||||
_pollToken = pollToken;
|
|
||||||
_pollEndpoint = pollEndpoint;
|
|
||||||
|
|
||||||
|
|
||||||
// Start polling
|
|
||||||
ConfigFile cfg;
|
|
||||||
std::chrono::milliseconds polltime = cfg.remotePollInterval();
|
|
||||||
qCInfo(lcFlow2auth) << "setting remote poll timer interval to" << polltime.count() << "msec";
|
|
||||||
_secondsInterval = (polltime.count() / 1000);
|
|
||||||
_secondsLeft = _secondsInterval;
|
|
||||||
emit statusChanged(PollStatus::statusPollCountdown, _secondsLeft);
|
|
||||||
|
|
||||||
if(!_pollTimer.isActive()) {
|
|
||||||
_pollTimer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch(action)
|
|
||||||
{
|
|
||||||
case actionOpenBrowser:
|
|
||||||
// Try to open Browser
|
|
||||||
if (!QDesktopServices::openUrl(authorisationLink())) {
|
|
||||||
// We cannot open the browser, then we claim we don't support Flow2Auth.
|
|
||||||
// Our UI callee will ask the user to copy and open the link.
|
|
||||||
emit result(NotSupported);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case actionCopyLinkToClipboard:
|
|
||||||
QApplication::clipboard()->setText(authorisationLink().toString(QUrl::FullyEncoded));
|
|
||||||
emit statusChanged(PollStatus::statusCopyLinkToClipboard, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_isBusy = false;
|
|
||||||
_hasToken = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Flow2Auth::slotPollTimerTimeout()
|
|
||||||
{
|
|
||||||
if(_isBusy || !_hasToken)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_isBusy = true;
|
|
||||||
|
|
||||||
_secondsLeft--;
|
|
||||||
if(_secondsLeft > 0) {
|
|
||||||
emit statusChanged(PollStatus::statusPollCountdown, _secondsLeft);
|
|
||||||
_isBusy = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
emit statusChanged(PollStatus::statusPollNow, 0);
|
|
||||||
|
|
||||||
// Step 2: Poll
|
|
||||||
QNetworkRequest req;
|
|
||||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
|
||||||
|
|
||||||
auto requestBody = new QBuffer;
|
|
||||||
QUrlQuery arguments(QString("token=%1").arg(_pollToken));
|
|
||||||
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
|
|
||||||
|
|
||||||
auto job = _account->sendRequest("POST", _pollEndpoint, req, requestBody);
|
|
||||||
job->setTimeout(qMin(30 * 1000ll, job->timeoutMsec()));
|
|
||||||
|
|
||||||
QObject::connect(job, &SimpleNetworkJob::finishedSignal, this, [this](QNetworkReply *reply) {
|
|
||||||
auto jsonData = reply->readAll();
|
|
||||||
QJsonParseError jsonParseError;
|
|
||||||
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
|
|
||||||
QUrl serverUrl;
|
|
||||||
QString loginName, appPassword;
|
|
||||||
|
|
||||||
if (reply->error() == QNetworkReply::NoError && jsonParseError.error == QJsonParseError::NoError
|
|
||||||
&& !json.isEmpty()) {
|
|
||||||
serverUrl = json["server"].toString();
|
|
||||||
loginName = json["loginName"].toString();
|
|
||||||
appPassword = json["appPassword"].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError || jsonParseError.error != QJsonParseError::NoError
|
|
||||||
|| json.isEmpty() || serverUrl.isEmpty() || loginName.isEmpty() || appPassword.isEmpty()) {
|
|
||||||
QString errorReason;
|
|
||||||
QString errorFromJson = json["error"].toString();
|
|
||||||
if (!errorFromJson.isEmpty()) {
|
|
||||||
errorReason = tr("Error returned from the server: <em>%1</em>")
|
|
||||||
.arg(errorFromJson.toHtmlEscaped());
|
|
||||||
} else if (reply->error() != QNetworkReply::NoError) {
|
|
||||||
errorReason = tr("There was an error accessing the 'token' endpoint: <br><em>%1</em>")
|
|
||||||
.arg(reply->errorString().toHtmlEscaped());
|
|
||||||
} else if (jsonParseError.error != QJsonParseError::NoError) {
|
|
||||||
errorReason = tr("Could not parse the JSON returned from the server: <br><em>%1</em>")
|
|
||||||
.arg(jsonParseError.errorString());
|
|
||||||
} else {
|
|
||||||
errorReason = tr("The reply from the server did not contain all expected fields");
|
|
||||||
}
|
|
||||||
qCDebug(lcFlow2auth) << "Error when polling for the appPassword" << json << errorReason;
|
|
||||||
|
|
||||||
// We get a 404 until authentication is done, so don't show this error in the GUI.
|
|
||||||
if(reply->error() != QNetworkReply::ContentNotFoundError)
|
|
||||||
emit result(Error, errorReason);
|
|
||||||
|
|
||||||
// Forget sensitive data
|
|
||||||
appPassword.clear();
|
|
||||||
loginName.clear();
|
|
||||||
|
|
||||||
// Failed: poll again
|
|
||||||
_secondsLeft = _secondsInterval;
|
|
||||||
_isBusy = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_pollTimer.stop();
|
|
||||||
|
|
||||||
// Success
|
|
||||||
qCInfo(lcFlow2auth) << "Success getting the appPassword for user: " << loginName << ", server: " << serverUrl.toString();
|
|
||||||
|
|
||||||
_account->setUrl(serverUrl);
|
|
||||||
|
|
||||||
emit result(LoggedIn, QString(), loginName, appPassword);
|
|
||||||
|
|
||||||
// Forget sensitive data
|
|
||||||
appPassword.clear();
|
|
||||||
loginName.clear();
|
|
||||||
|
|
||||||
_loginUrl.clear();
|
|
||||||
_pollToken.clear();
|
|
||||||
_pollEndpoint.clear();
|
|
||||||
|
|
||||||
_isBusy = false;
|
|
||||||
_hasToken = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Flow2Auth::slotPollNow()
|
|
||||||
{
|
|
||||||
// poll now if we're not already doing so
|
|
||||||
if(_isBusy || !_hasToken)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_secondsLeft = 1;
|
|
||||||
slotPollTimerTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Olivier Goffart <ogoffart@woboq.com>
|
|
||||||
* Copyright (C) by Michael Schuster <michael@nextcloud.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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <QPointer>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QTimer>
|
|
||||||
#include "accountfwd.h"
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Job that does the authorization, grants and fetches the access token via Login Flow v2
|
|
||||||
*
|
|
||||||
* See: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/LoginFlow/index.html#login-flow-v2
|
|
||||||
*/
|
|
||||||
class Flow2Auth : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum TokenAction {
|
|
||||||
actionOpenBrowser = 1,
|
|
||||||
actionCopyLinkToClipboard
|
|
||||||
};
|
|
||||||
enum PollStatus {
|
|
||||||
statusPollCountdown = 1,
|
|
||||||
statusPollNow,
|
|
||||||
statusFetchToken,
|
|
||||||
statusCopyLinkToClipboard
|
|
||||||
};
|
|
||||||
|
|
||||||
Flow2Auth(Account *account, QObject *parent);
|
|
||||||
~Flow2Auth();
|
|
||||||
|
|
||||||
enum Result { NotSupported,
|
|
||||||
LoggedIn,
|
|
||||||
Error };
|
|
||||||
Q_ENUM(Result);
|
|
||||||
void start();
|
|
||||||
void openBrowser();
|
|
||||||
void copyLinkToClipboard();
|
|
||||||
QUrl authorisationLink() const;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
/**
|
|
||||||
* The state has changed.
|
|
||||||
* when logged in, appPassword has the value of the app password.
|
|
||||||
*/
|
|
||||||
void result(Flow2Auth::Result result, const QString &errorString = QString(),
|
|
||||||
const QString &user = QString(), const QString &appPassword = QString());
|
|
||||||
|
|
||||||
void statusChanged(const PollStatus status, int secondsLeft);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void slotPollNow();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void slotPollTimerTimeout();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void fetchNewToken(const TokenAction action);
|
|
||||||
|
|
||||||
Account *_account;
|
|
||||||
QUrl _loginUrl;
|
|
||||||
QString _pollToken;
|
|
||||||
QString _pollEndpoint;
|
|
||||||
QTimer _pollTimer;
|
|
||||||
int _secondsLeft;
|
|
||||||
int _secondsInterval;
|
|
||||||
bool _isBusy;
|
|
||||||
bool _hasToken;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
@@ -1,221 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Michael Schuster <michael@nextcloud.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 "account.h"
|
|
||||||
#include "keychainchunk.h"
|
|
||||||
#include "theme.h"
|
|
||||||
#include "networkjobs.h"
|
|
||||||
#include "configfile.h"
|
|
||||||
#include "creds/abstractcredentials.h"
|
|
||||||
|
|
||||||
using namespace QKeychain;
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcKeychainChunk, "nextcloud.sync.credentials.keychainchunk", QtInfoMsg)
|
|
||||||
|
|
||||||
namespace KeychainChunk {
|
|
||||||
|
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
|
||||||
static void addSettingsToJob(Account *account, QKeychain::Job *job)
|
|
||||||
{
|
|
||||||
Q_UNUSED(account)
|
|
||||||
auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());
|
|
||||||
settings->setParent(job); // make the job parent to make setting deleted properly
|
|
||||||
job->setSettings(settings.release());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Job
|
|
||||||
*/
|
|
||||||
Job::Job(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
_serviceName = Theme::instance()->appName();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WriteJob
|
|
||||||
*/
|
|
||||||
WriteJob::WriteJob(Account *account, const QString &key, const QByteArray &data, QObject *parent)
|
|
||||||
: Job(parent)
|
|
||||||
{
|
|
||||||
_account = account;
|
|
||||||
_key = key;
|
|
||||||
|
|
||||||
// Windows workaround: Split the private key into chunks of 2048 bytes,
|
|
||||||
// to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
|
|
||||||
_chunkBuffer = data;
|
|
||||||
_chunkCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteJob::start()
|
|
||||||
{
|
|
||||||
slotWriteJobDone(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WriteJob::slotWriteJobDone(QKeychain::Job *incomingJob)
|
|
||||||
{
|
|
||||||
QKeychain::WritePasswordJob *writeJob = static_cast<QKeychain::WritePasswordJob *>(incomingJob);
|
|
||||||
|
|
||||||
// errors?
|
|
||||||
if (writeJob) {
|
|
||||||
_error = writeJob->error();
|
|
||||||
_errorString = writeJob->errorString();
|
|
||||||
|
|
||||||
if (writeJob->error() != NoError) {
|
|
||||||
qCWarning(lcKeychainChunk) << "Error while writing" << writeJob->key() << "chunk" << writeJob->errorString();
|
|
||||||
_chunkBuffer.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write a chunk if there is any in the buffer
|
|
||||||
if (!_chunkBuffer.isEmpty()) {
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
// Windows workaround: Split the data into chunks of 2048 bytes,
|
|
||||||
// to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
|
|
||||||
auto chunk = _chunkBuffer.left(KeychainChunk::ChunkSize);
|
|
||||||
|
|
||||||
_chunkBuffer = _chunkBuffer.right(_chunkBuffer.size() - chunk.size());
|
|
||||||
#else
|
|
||||||
// write full data in one chunk on non-Windows, as usual
|
|
||||||
auto chunk = _chunkBuffer;
|
|
||||||
|
|
||||||
_chunkBuffer.clear();
|
|
||||||
#endif
|
|
||||||
auto index = (_chunkCount++);
|
|
||||||
|
|
||||||
// keep the limit
|
|
||||||
if (_chunkCount > KeychainChunk::MaxChunks) {
|
|
||||||
qCWarning(lcKeychainChunk) << "Maximum chunk count exceeded while writing" << writeJob->key() << "chunk" << QString::number(index) << "cutting off after" << QString::number(KeychainChunk::MaxChunks) << "chunks";
|
|
||||||
|
|
||||||
writeJob->deleteLater();
|
|
||||||
|
|
||||||
_chunkBuffer.clear();
|
|
||||||
|
|
||||||
emit finished(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString kck = AbstractCredentials::keychainKey(
|
|
||||||
_account->url().toString(),
|
|
||||||
_key + (index > 0 ? (QString(".") + QString::number(index)) : QString()),
|
|
||||||
_account->id());
|
|
||||||
|
|
||||||
QKeychain::WritePasswordJob *job = new QKeychain::WritePasswordJob(_serviceName);
|
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
|
||||||
addSettingsToJob(_account, job);
|
|
||||||
#endif
|
|
||||||
job->setInsecureFallback(_insecureFallback);
|
|
||||||
connect(job, &QKeychain::Job::finished, this, &KeychainChunk::WriteJob::slotWriteJobDone);
|
|
||||||
// only add the key's (sub)"index" after the first element, to stay compatible with older versions and non-Windows
|
|
||||||
job->setKey(kck);
|
|
||||||
job->setBinaryData(chunk);
|
|
||||||
job->start();
|
|
||||||
|
|
||||||
chunk.clear();
|
|
||||||
} else {
|
|
||||||
emit finished(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
writeJob->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ReadJob
|
|
||||||
*/
|
|
||||||
ReadJob::ReadJob(Account *account, const QString &key, const bool &keychainMigration, QObject *parent)
|
|
||||||
: Job(parent)
|
|
||||||
{
|
|
||||||
_account = account;
|
|
||||||
_key = key;
|
|
||||||
|
|
||||||
_keychainMigration = keychainMigration;
|
|
||||||
|
|
||||||
_chunkCount = 0;
|
|
||||||
_chunkBuffer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadJob::start()
|
|
||||||
{
|
|
||||||
_chunkCount = 0;
|
|
||||||
_chunkBuffer.clear();
|
|
||||||
|
|
||||||
const QString kck = AbstractCredentials::keychainKey(
|
|
||||||
_account->url().toString(),
|
|
||||||
_key,
|
|
||||||
_keychainMigration ? QString() : _account->id());
|
|
||||||
|
|
||||||
QKeychain::ReadPasswordJob *job = new QKeychain::ReadPasswordJob(_serviceName);
|
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
|
||||||
addSettingsToJob(_account, job);
|
|
||||||
#endif
|
|
||||||
job->setInsecureFallback(_insecureFallback);
|
|
||||||
job->setKey(kck);
|
|
||||||
connect(job, &QKeychain::Job::finished, this, &KeychainChunk::ReadJob::slotReadJobDone);
|
|
||||||
job->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReadJob::slotReadJobDone(QKeychain::Job *incomingJob)
|
|
||||||
{
|
|
||||||
// Errors or next chunk?
|
|
||||||
QKeychain::ReadPasswordJob *readJob = static_cast<QKeychain::ReadPasswordJob *>(incomingJob);
|
|
||||||
|
|
||||||
if (readJob) {
|
|
||||||
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
|
|
||||||
_chunkBuffer.append(readJob->binaryData());
|
|
||||||
_chunkCount++;
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
// try to fetch next chunk
|
|
||||||
if (_chunkCount < KeychainChunk::MaxChunks) {
|
|
||||||
const QString kck = AbstractCredentials::keychainKey(
|
|
||||||
_account->url().toString(),
|
|
||||||
_key + QString(".") + QString::number(_chunkCount),
|
|
||||||
_keychainMigration ? QString() : _account->id());
|
|
||||||
|
|
||||||
QKeychain::ReadPasswordJob *job = new QKeychain::ReadPasswordJob(_serviceName);
|
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
|
||||||
addSettingsToJob(_account, job);
|
|
||||||
#endif
|
|
||||||
job->setInsecureFallback(_insecureFallback);
|
|
||||||
job->setKey(kck);
|
|
||||||
connect(job, &QKeychain::Job::finished, this, &KeychainChunk::ReadJob::slotReadJobDone);
|
|
||||||
job->start();
|
|
||||||
|
|
||||||
readJob->deleteLater();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
qCWarning(lcKeychainChunk) << "Maximum chunk count for" << readJob->key() << "reached, ignoring after" << KeychainChunk::MaxChunks;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
if (readJob->error() != QKeychain::Error::EntryNotFound ||
|
|
||||||
((readJob->error() == QKeychain::Error::EntryNotFound) && _chunkCount == 0)) {
|
|
||||||
_error = readJob->error();
|
|
||||||
_errorString = readJob->errorString();
|
|
||||||
qCWarning(lcKeychainChunk) << "Unable to read" << readJob->key() << "chunk" << QString::number(_chunkCount) << readJob->errorString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readJob->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit finished(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace KeychainChunk
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Michael Schuster <michael@nextcloud.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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#ifndef KEYCHAINCHUNK_H
|
|
||||||
#define KEYCHAINCHUNK_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <keychain.h>
|
|
||||||
#include "accountfwd.h"
|
|
||||||
|
|
||||||
// We don't support insecure fallback
|
|
||||||
// #define KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
namespace KeychainChunk {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Workaround for Windows:
|
|
||||||
*
|
|
||||||
* Split the keychain entry's data into chunks of 2048 bytes,
|
|
||||||
* to allow 4k (4096 bit) keys / large certs to be saved (see limits in webflowcredentials.h)
|
|
||||||
*/
|
|
||||||
static constexpr int ChunkSize = 2048;
|
|
||||||
static constexpr int MaxChunks = 10;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief: Abstract base class for KeychainChunk jobs.
|
|
||||||
*/
|
|
||||||
class Job : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
Job(QObject *parent = nullptr);
|
|
||||||
|
|
||||||
const QKeychain::Error error() const {
|
|
||||||
return _error;
|
|
||||||
}
|
|
||||||
const QString errorString() const {
|
|
||||||
return _errorString;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray binaryData() const {
|
|
||||||
return _chunkBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool insecureFallback() const {
|
|
||||||
return _insecureFallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we use it but don't support insecure fallback, give us nice compilation errors ;p
|
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
|
||||||
void setInsecureFallback(const bool &insecureFallback)
|
|
||||||
{
|
|
||||||
_insecureFallback = insecureFallback;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QString _serviceName;
|
|
||||||
Account *_account;
|
|
||||||
QString _key;
|
|
||||||
bool _insecureFallback = false;
|
|
||||||
bool _keychainMigration = false;
|
|
||||||
|
|
||||||
QKeychain::Error _error = QKeychain::NoError;
|
|
||||||
QString _errorString;
|
|
||||||
|
|
||||||
int _chunkCount = 0;
|
|
||||||
QByteArray _chunkBuffer;
|
|
||||||
}; // class Job
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief: Simple wrapper class for QKeychain::WritePasswordJob, splits too large keychain entry's data into chunks on Windows
|
|
||||||
*/
|
|
||||||
class WriteJob : public KeychainChunk::Job {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
WriteJob(Account *account, const QString &key, const QByteArray &data, QObject *parent = nullptr);
|
|
||||||
void start();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void finished(KeychainChunk::WriteJob *incomingJob);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void slotWriteJobDone(QKeychain::Job *incomingJob);
|
|
||||||
}; // class WriteJob
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief: Simple wrapper class for QKeychain::ReadPasswordJob, splits too large keychain entry's data into chunks on Windows
|
|
||||||
*/
|
|
||||||
class ReadJob : public KeychainChunk::Job {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
ReadJob(Account *account, const QString &key, const bool &keychainMigration, QObject *parent = nullptr);
|
|
||||||
void start();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void finished(KeychainChunk::ReadJob *incomingJob);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void slotReadJobDone(QKeychain::Job *incomingJob);
|
|
||||||
}; // class ReadJob
|
|
||||||
|
|
||||||
} // namespace KeychainChunk
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
|
|
||||||
#endif // KEYCHAINCHUNK_H
|
|
||||||
@@ -14,11 +14,9 @@
|
|||||||
|
|
||||||
#include "accessmanager.h"
|
#include "accessmanager.h"
|
||||||
#include "account.h"
|
#include "account.h"
|
||||||
#include "configfile.h"
|
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "wizard/webview.h"
|
#include "wizard/webview.h"
|
||||||
#include "webflowcredentialsdialog.h"
|
#include "webflowcredentialsdialog.h"
|
||||||
#include "keychainchunk.h"
|
|
||||||
|
|
||||||
using namespace QKeychain;
|
using namespace QKeychain;
|
||||||
|
|
||||||
@@ -26,13 +24,6 @@ namespace OCC {
|
|||||||
|
|
||||||
Q_LOGGING_CATEGORY(lcWebFlowCredentials, "sync.credentials.webflow", QtInfoMsg)
|
Q_LOGGING_CATEGORY(lcWebFlowCredentials, "sync.credentials.webflow", QtInfoMsg)
|
||||||
|
|
||||||
namespace {
|
|
||||||
const char userC[] = "user";
|
|
||||||
const char clientCertificatePEMC[] = "_clientCertificatePEM";
|
|
||||||
const char clientKeyPEMC[] = "_clientKeyPEM";
|
|
||||||
const char clientCaCertificatePEMC[] = "_clientCaCertificatePEM";
|
|
||||||
} // ns
|
|
||||||
|
|
||||||
class WebFlowCredentialsAccessManager : public AccessManager
|
class WebFlowCredentialsAccessManager : public AccessManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -46,27 +37,13 @@ protected:
|
|||||||
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) override
|
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) override
|
||||||
{
|
{
|
||||||
QNetworkRequest req(request);
|
QNetworkRequest req(request);
|
||||||
if (!req.attribute(WebFlowCredentials::DontAddCredentialsAttribute).toBool()) {
|
if (!req.attribute(HttpCredentials::DontAddCredentialsAttribute).toBool()) {
|
||||||
if (_cred && !_cred->password().isEmpty()) {
|
if (_cred && !_cred->password().isEmpty()) {
|
||||||
QByteArray credHash = QByteArray(_cred->user().toUtf8() + ":" + _cred->password().toUtf8()).toBase64();
|
QByteArray credHash = QByteArray(_cred->user().toUtf8() + ":" + _cred->password().toUtf8()).toBase64();
|
||||||
req.setRawHeader("Authorization", "Basic " + credHash);
|
req.setRawHeader("Authorization", "Basic " + credHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cred && !_cred->_clientSslKey.isNull() && !_cred->_clientSslCertificate.isNull()) {
|
|
||||||
// SSL configuration
|
|
||||||
QSslConfiguration sslConfiguration = req.sslConfiguration();
|
|
||||||
sslConfiguration.setLocalCertificate(_cred->_clientSslCertificate);
|
|
||||||
sslConfiguration.setPrivateKey(_cred->_clientSslKey);
|
|
||||||
|
|
||||||
// Merge client side CA with system CA
|
|
||||||
auto ca = sslConfiguration.systemCaCertificates();
|
|
||||||
ca.append(_cred->_clientSslCaCertificates);
|
|
||||||
sslConfiguration.setCaCertificates(ca);
|
|
||||||
|
|
||||||
req.setSslConfiguration(sslConfiguration);
|
|
||||||
}
|
|
||||||
|
|
||||||
return AccessManager::createRequest(op, req, outgoingData);
|
return AccessManager::createRequest(op, req, outgoingData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,35 +53,22 @@ private:
|
|||||||
QPointer<const WebFlowCredentials> _cred;
|
QPointer<const WebFlowCredentials> _cred;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
|
||||||
static void addSettingsToJob(Account *account, QKeychain::Job *job)
|
|
||||||
{
|
|
||||||
Q_UNUSED(account)
|
|
||||||
auto settings = ConfigFile::settingsWithGroup(Theme::instance()->appName());
|
|
||||||
settings->setParent(job); // make the job parent to make setting deleted properly
|
|
||||||
job->setSettings(settings.release());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WebFlowCredentials::WebFlowCredentials()
|
WebFlowCredentials::WebFlowCredentials()
|
||||||
: _ready(false)
|
: _ready(false)
|
||||||
, _credentialsValid(false)
|
, _credentialsValid(false)
|
||||||
, _keychainMigration(false)
|
, _keychainMigration(false)
|
||||||
, _retryOnKeyChainError(false)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WebFlowCredentials::WebFlowCredentials(const QString &user, const QString &password, const QSslCertificate &certificate, const QSslKey &key, const QList<QSslCertificate> &caCertificates)
|
WebFlowCredentials::WebFlowCredentials(const QString &user, const QString &password, const QSslCertificate &certificate, const QSslKey &key)
|
||||||
: _user(user)
|
: _user(user)
|
||||||
, _password(password)
|
, _password(password)
|
||||||
, _clientSslKey(key)
|
, _clientSslKey(key)
|
||||||
, _clientSslCertificate(certificate)
|
, _clientSslCertificate(certificate)
|
||||||
, _clientSslCaCertificates(caCertificates)
|
|
||||||
, _ready(true)
|
, _ready(true)
|
||||||
, _credentialsValid(true)
|
, _credentialsValid(true)
|
||||||
, _keychainMigration(false)
|
, _keychainMigration(false)
|
||||||
, _retryOnKeyChainError(false)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -138,50 +102,38 @@ bool WebFlowCredentials::ready() const {
|
|||||||
void WebFlowCredentials::fetchFromKeychain() {
|
void WebFlowCredentials::fetchFromKeychain() {
|
||||||
_wasFetched = true;
|
_wasFetched = true;
|
||||||
|
|
||||||
// Make sure we get the user from the config file
|
// Make sure we get the user fromt he config file
|
||||||
fetchUser();
|
fetchUser();
|
||||||
|
|
||||||
if (ready()) {
|
if (ready()) {
|
||||||
emit fetched();
|
emit fetched();
|
||||||
} else {
|
} else {
|
||||||
qCInfo(lcWebFlowCredentials()) << "Fetch from keychain!";
|
qCInfo(lcWebFlowCredentials()) << "Fetch from keyhchain!";
|
||||||
fetchFromKeychainHelper();
|
fetchFromKeychainHelper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::askFromUser() {
|
void WebFlowCredentials::askFromUser() {
|
||||||
// Determine if the old flow has to be used (GS for now)
|
_askDialog = new WebFlowCredentialsDialog();
|
||||||
// Do a DetermineAuthTypeJob to make sure that the server is still using Flow2
|
|
||||||
DetermineAuthTypeJob *job = new DetermineAuthTypeJob(_account->sharedFromThis(), this);
|
|
||||||
connect(job, &DetermineAuthTypeJob::authType, [this](DetermineAuthTypeJob::AuthType type) {
|
|
||||||
// LoginFlowV2 > WebViewFlow > OAuth > Shib > Basic
|
|
||||||
bool useFlow2 = (type != DetermineAuthTypeJob::WebViewFlow);
|
|
||||||
|
|
||||||
_askDialog = new WebFlowCredentialsDialog(_account, useFlow2);
|
QUrl url = _account->url();
|
||||||
|
QString path = url.path() + "/index.php/login/flow";
|
||||||
|
url.setPath(path);
|
||||||
|
_askDialog->setUrl(url);
|
||||||
|
|
||||||
if (!useFlow2) {
|
QString msg = tr("You have been logged out of %1 as user %2. Please login again")
|
||||||
QUrl url = _account->url();
|
.arg(_account->displayName(), _user);
|
||||||
QString path = url.path() + "/index.php/login/flow";
|
_askDialog->setInfo(msg);
|
||||||
url.setPath(path);
|
|
||||||
_askDialog->setUrl(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString msg = tr("You have been logged out of %1 as user %2. Please login again")
|
_askDialog->show();
|
||||||
.arg(_account->displayName(), _user);
|
|
||||||
_askDialog->setInfo(msg);
|
|
||||||
|
|
||||||
_askDialog->show();
|
connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided);
|
||||||
|
|
||||||
connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided);
|
|
||||||
connect(_askDialog, &WebFlowCredentialsDialog::onClose, this, &WebFlowCredentials::slotAskFromUserCancelled);
|
|
||||||
});
|
|
||||||
job->start();
|
|
||||||
|
|
||||||
qCDebug(lcWebFlowCredentials()) << "User needs to reauth!";
|
qCDebug(lcWebFlowCredentials()) << "User needs to reauth!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::slotAskFromUserCredentialsProvided(const QString &user, const QString &pass, const QString &host) {
|
void WebFlowCredentials::slotAskFromUserCredentialsProvided(const QString &user, const QString &pass, const QString &host) {
|
||||||
Q_UNUSED(host)
|
Q_UNUSED(host);
|
||||||
|
|
||||||
if (_user != user) {
|
if (_user != user) {
|
||||||
qCInfo(lcWebFlowCredentials()) << "Authed with the wrong user!";
|
qCInfo(lcWebFlowCredentials()) << "Authed with the wrong user!";
|
||||||
@@ -190,12 +142,10 @@ void WebFlowCredentials::slotAskFromUserCredentialsProvided(const QString &user,
|
|||||||
.arg(_user);
|
.arg(_user);
|
||||||
_askDialog->setError(msg);
|
_askDialog->setError(msg);
|
||||||
|
|
||||||
if (!_askDialog->isUsingFlow2()) {
|
QUrl url = _account->url();
|
||||||
QUrl url = _account->url();
|
QString path = url.path() + "/index.php/login/flow";
|
||||||
QString path = url.path() + "/index.php/login/flow";
|
url.setPath(path);
|
||||||
url.setPath(path);
|
_askDialog->setUrl(url);
|
||||||
_askDialog->setUrl(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -209,18 +159,10 @@ void WebFlowCredentials::slotAskFromUserCredentialsProvided(const QString &user,
|
|||||||
emit asked();
|
emit asked();
|
||||||
|
|
||||||
_askDialog->close();
|
_askDialog->close();
|
||||||
_askDialog->deleteLater();
|
delete _askDialog;
|
||||||
_askDialog = nullptr;
|
_askDialog = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::slotAskFromUserCancelled() {
|
|
||||||
qCDebug(lcWebFlowCredentials()) << "User cancelled reauth!";
|
|
||||||
|
|
||||||
emit asked();
|
|
||||||
|
|
||||||
_askDialog->deleteLater();
|
|
||||||
_askDialog = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WebFlowCredentials::stillValid(QNetworkReply *reply) {
|
bool WebFlowCredentials::stillValid(QNetworkReply *reply) {
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
@@ -236,130 +178,17 @@ void WebFlowCredentials::persist() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_account->setCredentialSetting(userC, _user);
|
_account->setCredentialSetting("user", _user);
|
||||||
_account->wantsAccountSaved(_account);
|
_account->wantsAccountSaved(_account);
|
||||||
|
|
||||||
// write cert if there is one
|
//TODO: Add ssl cert and key storing
|
||||||
if (!_clientSslCertificate.isNull()) {
|
|
||||||
auto *job = new KeychainChunk::WriteJob(_account,
|
|
||||||
_user + clientCertificatePEMC,
|
|
||||||
_clientSslCertificate.toPem());
|
|
||||||
connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientCertPEMJobDone);
|
|
||||||
job->start();
|
|
||||||
} else {
|
|
||||||
// no cert, just write credentials
|
|
||||||
slotWriteClientCertPEMJobDone(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::slotWriteClientCertPEMJobDone(KeychainChunk::WriteJob *writeJob)
|
|
||||||
{
|
|
||||||
if(writeJob)
|
|
||||||
writeJob->deleteLater();
|
|
||||||
|
|
||||||
// write ssl key if there is one
|
|
||||||
if (!_clientSslKey.isNull()) {
|
|
||||||
auto *job = new KeychainChunk::WriteJob(_account,
|
|
||||||
_user + clientKeyPEMC,
|
|
||||||
_clientSslKey.toPem());
|
|
||||||
connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientKeyPEMJobDone);
|
|
||||||
job->start();
|
|
||||||
} else {
|
|
||||||
// no key, just write credentials
|
|
||||||
slotWriteClientKeyPEMJobDone(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::writeSingleClientCaCertPEM()
|
|
||||||
{
|
|
||||||
// write a ca cert if there is any in the queue
|
|
||||||
if (!_clientSslCaCertificatesWriteQueue.isEmpty()) {
|
|
||||||
// grab and remove the first cert from the queue
|
|
||||||
auto cert = _clientSslCaCertificatesWriteQueue.dequeue();
|
|
||||||
|
|
||||||
auto index = (_clientSslCaCertificates.count() - _clientSslCaCertificatesWriteQueue.count()) - 1;
|
|
||||||
|
|
||||||
// keep the limit
|
|
||||||
if (index > (_clientSslCaCertificatesMaxCount - 1)) {
|
|
||||||
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while writing slot" << QString::number(index) << "cutting off after" << QString::number(_clientSslCaCertificatesMaxCount) << "certs";
|
|
||||||
|
|
||||||
_clientSslCaCertificatesWriteQueue.clear();
|
|
||||||
|
|
||||||
slotWriteClientCaCertsPEMJobDone(nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *job = new KeychainChunk::WriteJob(_account,
|
|
||||||
_user + clientCaCertificatePEMC + QString::number(index),
|
|
||||||
cert.toPem());
|
|
||||||
connect(job, &KeychainChunk::WriteJob::finished, this, &WebFlowCredentials::slotWriteClientCaCertsPEMJobDone);
|
|
||||||
job->start();
|
|
||||||
} else {
|
|
||||||
slotWriteClientCaCertsPEMJobDone(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::slotWriteClientKeyPEMJobDone(KeychainChunk::WriteJob *writeJob)
|
|
||||||
{
|
|
||||||
if(writeJob)
|
|
||||||
writeJob->deleteLater();
|
|
||||||
|
|
||||||
_clientSslCaCertificatesWriteQueue.clear();
|
|
||||||
|
|
||||||
// write ca certs if there are any
|
|
||||||
if (!_clientSslCaCertificates.isEmpty()) {
|
|
||||||
// queue the certs to avoid trouble on Windows (Workaround for CredWriteW used by QtKeychain)
|
|
||||||
_clientSslCaCertificatesWriteQueue.append(_clientSslCaCertificates);
|
|
||||||
|
|
||||||
// first ca cert
|
|
||||||
writeSingleClientCaCertPEM();
|
|
||||||
} else {
|
|
||||||
slotWriteClientCaCertsPEMJobDone(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::slotWriteClientCaCertsPEMJobDone(KeychainChunk::WriteJob *writeJob)
|
|
||||||
{
|
|
||||||
// errors / next ca cert?
|
|
||||||
if (writeJob && !_clientSslCaCertificates.isEmpty()) {
|
|
||||||
if (writeJob->error() != NoError) {
|
|
||||||
qCWarning(lcWebFlowCredentials) << "Error while writing client CA cert" << writeJob->errorString();
|
|
||||||
}
|
|
||||||
|
|
||||||
writeJob->deleteLater();
|
|
||||||
|
|
||||||
if (!_clientSslCaCertificatesWriteQueue.isEmpty()) {
|
|
||||||
// next ca cert
|
|
||||||
writeSingleClientCaCertPEM();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// done storing ca certs, time for the password
|
|
||||||
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
|
||||||
addSettingsToJob(_account, job);
|
|
||||||
#endif
|
|
||||||
job->setInsecureFallback(false);
|
job->setInsecureFallback(false);
|
||||||
connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteJobDone);
|
|
||||||
job->setKey(keychainKey(_account->url().toString(), _user, _account->id()));
|
job->setKey(keychainKey(_account->url().toString(), _user, _account->id()));
|
||||||
job->setTextData(_password);
|
job->setTextData(_password);
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::slotWriteJobDone(QKeychain::Job *job)
|
|
||||||
{
|
|
||||||
delete job->settings();
|
|
||||||
switch (job->error()) {
|
|
||||||
case NoError:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCWarning(lcWebFlowCredentials) << "Error while writing password" << job->errorString();
|
|
||||||
}
|
|
||||||
WritePasswordJob *wjob = qobject_cast<WritePasswordJob *>(job);
|
|
||||||
wjob->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::invalidateToken() {
|
void WebFlowCredentials::invalidateToken() {
|
||||||
// clear the session cookie.
|
// clear the session cookie.
|
||||||
_account->clearCookieJar();
|
_account->clearCookieJar();
|
||||||
@@ -372,14 +201,12 @@ void WebFlowCredentials::invalidateToken() {
|
|||||||
QTimer::singleShot(0, _account, &Account::clearQNAMCache);
|
QTimer::singleShot(0, _account, &Account::clearQNAMCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::forgetSensitiveData() {
|
void WebFlowCredentials::forgetSensitiveData(){
|
||||||
_password = QString();
|
_password = QString();
|
||||||
_ready = false;
|
_ready = false;
|
||||||
|
|
||||||
fetchUser();
|
fetchUser();
|
||||||
|
|
||||||
_account->deleteAppPassword();
|
|
||||||
|
|
||||||
const QString kck = keychainKey(_account->url().toString(), _user, _account->id());
|
const QString kck = keychainKey(_account->url().toString(), _user, _account->id());
|
||||||
if (kck.isEmpty()) {
|
if (kck.isEmpty()) {
|
||||||
qCDebug(lcWebFlowCredentials()) << "InvalidateToken: User is empty, bailing out!";
|
qCDebug(lcWebFlowCredentials()) << "InvalidateToken: User is empty, bailing out!";
|
||||||
@@ -389,15 +216,9 @@ void WebFlowCredentials::forgetSensitiveData() {
|
|||||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||||
job->setInsecureFallback(false);
|
job->setInsecureFallback(false);
|
||||||
job->setKey(kck);
|
job->setKey(kck);
|
||||||
connect(job, &Job::finished, this, [](QKeychain::Job *job) {
|
|
||||||
DeletePasswordJob *djob = qobject_cast<DeletePasswordJob *>(job);
|
|
||||||
djob->deleteLater();
|
|
||||||
});
|
|
||||||
job->start();
|
job->start();
|
||||||
|
|
||||||
invalidateToken();
|
invalidateToken();
|
||||||
|
|
||||||
deleteKeychainEntries();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::setAccount(Account *account) {
|
void WebFlowCredentials::setAccount(Account *account) {
|
||||||
@@ -408,12 +229,12 @@ void WebFlowCredentials::setAccount(Account *account) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString WebFlowCredentials::fetchUser() {
|
QString WebFlowCredentials::fetchUser() {
|
||||||
_user = _account->credentialSetting(userC).toString();
|
_user = _account->credentialSetting("user").toString();
|
||||||
return _user;
|
return _user;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::slotAuthentication(QNetworkReply *reply, QAuthenticator *authenticator) {
|
void WebFlowCredentials::slotAuthentication(QNetworkReply *reply, QAuthenticator *authenticator) {
|
||||||
Q_UNUSED(reply)
|
Q_UNUSED(reply);
|
||||||
|
|
||||||
if (!_ready) {
|
if (!_ready) {
|
||||||
return;
|
return;
|
||||||
@@ -435,136 +256,16 @@ void WebFlowCredentials::slotFinished(QNetworkReply *reply) {
|
|||||||
|
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
if (reply->error() == QNetworkReply::NoError) {
|
||||||
_credentialsValid = true;
|
_credentialsValid = true;
|
||||||
|
|
||||||
/// Used later for remote wipe
|
|
||||||
_account->writeAppPasswordOnce(_password);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::fetchFromKeychainHelper() {
|
void WebFlowCredentials::fetchFromKeychainHelper() {
|
||||||
// Read client cert from keychain
|
|
||||||
auto *job = new KeychainChunk::ReadJob(_account,
|
|
||||||
_user + clientCertificatePEMC,
|
|
||||||
_keychainMigration);
|
|
||||||
connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientCertPEMJobDone);
|
|
||||||
job->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::slotReadClientCertPEMJobDone(KeychainChunk::ReadJob *readJob)
|
|
||||||
{
|
|
||||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
|
|
||||||
Q_ASSERT(!readJob->insecureFallback()); // If insecureFallback is set, the next test would be pointless
|
|
||||||
if (_retryOnKeyChainError && (readJob->error() == QKeychain::NoBackendAvailable
|
|
||||||
|| readJob->error() == QKeychain::OtherError)) {
|
|
||||||
// Could be that the backend was not yet available. Wait some extra seconds.
|
|
||||||
// (Issues #4274 and #6522)
|
|
||||||
// (For kwallet, the error is OtherError instead of NoBackendAvailable, maybe a bug in QtKeychain)
|
|
||||||
qCInfo(lcWebFlowCredentials) << "Backend unavailable (yet?) Retrying in a few seconds." << readJob->errorString();
|
|
||||||
QTimer::singleShot(10000, this, &WebFlowCredentials::fetchFromKeychainHelper);
|
|
||||||
_retryOnKeyChainError = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_retryOnKeyChainError = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Store PEM in memory
|
|
||||||
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
|
|
||||||
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
|
|
||||||
if (sslCertificateList.length() >= 1) {
|
|
||||||
_clientSslCertificate = sslCertificateList.at(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readJob->deleteLater();
|
|
||||||
|
|
||||||
// Load key too
|
|
||||||
auto *job = new KeychainChunk::ReadJob(_account,
|
|
||||||
_user + clientKeyPEMC,
|
|
||||||
_keychainMigration);
|
|
||||||
connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientKeyPEMJobDone);
|
|
||||||
job->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::slotReadClientKeyPEMJobDone(KeychainChunk::ReadJob *readJob)
|
|
||||||
{
|
|
||||||
// Store key in memory
|
|
||||||
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
|
|
||||||
QByteArray clientKeyPEM = readJob->binaryData();
|
|
||||||
// FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
|
|
||||||
// load whatever we have. So we try until it works.
|
|
||||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Rsa);
|
|
||||||
if (_clientSslKey.isNull()) {
|
|
||||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Dsa);
|
|
||||||
}
|
|
||||||
if (_clientSslKey.isNull()) {
|
|
||||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Ec);
|
|
||||||
}
|
|
||||||
if (_clientSslKey.isNull()) {
|
|
||||||
qCWarning(lcWebFlowCredentials) << "Could not load SSL key into Qt!";
|
|
||||||
}
|
|
||||||
clientKeyPEM.clear();
|
|
||||||
} else {
|
|
||||||
qCWarning(lcWebFlowCredentials) << "Unable to read client key" << readJob->errorString();
|
|
||||||
}
|
|
||||||
|
|
||||||
readJob->deleteLater();
|
|
||||||
|
|
||||||
// Start fetching client CA certs
|
|
||||||
_clientSslCaCertificates.clear();
|
|
||||||
|
|
||||||
readSingleClientCaCertPEM();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::readSingleClientCaCertPEM()
|
|
||||||
{
|
|
||||||
// try to fetch a client ca cert
|
|
||||||
if (_clientSslCaCertificates.count() < _clientSslCaCertificatesMaxCount) {
|
|
||||||
auto *job = new KeychainChunk::ReadJob(_account,
|
|
||||||
_user + clientCaCertificatePEMC + QString::number(_clientSslCaCertificates.count()),
|
|
||||||
_keychainMigration);
|
|
||||||
connect(job, &KeychainChunk::ReadJob::finished, this, &WebFlowCredentials::slotReadClientCaCertsPEMJobDone);
|
|
||||||
job->start();
|
|
||||||
} else {
|
|
||||||
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while reading, ignoring after" << _clientSslCaCertificatesMaxCount;
|
|
||||||
|
|
||||||
slotReadClientCaCertsPEMJobDone(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(KeychainChunk::ReadJob *readJob) {
|
|
||||||
// Store cert in memory
|
|
||||||
if (readJob) {
|
|
||||||
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
|
|
||||||
QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData(readJob->binaryData(), QSsl::Pem);
|
|
||||||
if (sslCertificateList.length() >= 1) {
|
|
||||||
_clientSslCaCertificates.append(sslCertificateList.at(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
readJob->deleteLater();
|
|
||||||
|
|
||||||
// try next cert
|
|
||||||
readSingleClientCaCertPEM();
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (readJob->error() != QKeychain::Error::EntryNotFound ||
|
|
||||||
((readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslCaCertificates.count() == 0)) {
|
|
||||||
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot" << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readJob->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now fetch the actual server password
|
|
||||||
const QString kck = keychainKey(
|
const QString kck = keychainKey(
|
||||||
_account->url().toString(),
|
_account->url().toString(),
|
||||||
_user,
|
_user,
|
||||||
_keychainMigration ? QString() : _account->id());
|
_keychainMigration ? QString() : _account->id());
|
||||||
|
|
||||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
|
||||||
addSettingsToJob(_account, job);
|
|
||||||
#endif
|
|
||||||
job->setInsecureFallback(false);
|
job->setInsecureFallback(false);
|
||||||
job->setKey(kck);
|
job->setKey(kck);
|
||||||
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadPasswordJobDone);
|
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadPasswordJobDone);
|
||||||
@@ -572,7 +273,7 @@ void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(KeychainChunk::ReadJob
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
|
void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
|
||||||
QKeychain::ReadPasswordJob *job = qobject_cast<ReadPasswordJob *>(incomingJob);
|
QKeychain::ReadPasswordJob *job = static_cast<ReadPasswordJob *>(incomingJob);
|
||||||
QKeychain::Error error = job->error();
|
QKeychain::Error error = job->error();
|
||||||
|
|
||||||
// If we could not find the entry try the old entries
|
// If we could not find the entry try the old entries
|
||||||
@@ -582,10 +283,6 @@ void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_user.isEmpty()) {
|
|
||||||
qCWarning(lcWebFlowCredentials) << "Strange: User is empty!";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error == QKeychain::NoError) {
|
if (error == QKeychain::NoError) {
|
||||||
_password = job->textData();
|
_password = job->textData();
|
||||||
_ready = true;
|
_ready = true;
|
||||||
@@ -595,72 +292,20 @@ void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
|
|||||||
}
|
}
|
||||||
emit fetched();
|
emit fetched();
|
||||||
|
|
||||||
job->deleteLater();
|
|
||||||
|
|
||||||
// If keychain data was read from legacy location, wipe these entries and store new ones
|
// If keychain data was read from legacy location, wipe these entries and store new ones
|
||||||
if (_keychainMigration && _ready) {
|
if (_keychainMigration && _ready) {
|
||||||
_keychainMigration = false;
|
_keychainMigration = false;
|
||||||
persist();
|
persist();
|
||||||
deleteKeychainEntries(true); // true: delete old entries
|
deleteOldKeychainEntries();
|
||||||
qCInfo(lcWebFlowCredentials) << "Migrated old keychain entries";
|
qCInfo(lcWebFlowCredentials) << "Migrated old keychain entries";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentials::deleteKeychainEntries(bool oldKeychainEntries) {
|
void WebFlowCredentials::deleteOldKeychainEntries() {
|
||||||
auto startDeleteJob = [this, oldKeychainEntries](QString key) {
|
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
job->setInsecureFallback(false);
|
||||||
#if defined(KEYCHAINCHUNK_ENABLE_INSECURE_FALLBACK)
|
job->setKey(keychainKey(_account->url().toString(), _user, QString()));
|
||||||
addSettingsToJob(_account, job);
|
job->start();
|
||||||
#endif
|
|
||||||
job->setInsecureFallback(false);
|
|
||||||
job->setKey(keychainKey(_account->url().toString(),
|
|
||||||
key,
|
|
||||||
oldKeychainEntries ? QString() : _account->id()));
|
|
||||||
|
|
||||||
connect(job, &Job::finished, this, [](QKeychain::Job *job) {
|
|
||||||
DeletePasswordJob *djob = qobject_cast<DeletePasswordJob *>(job);
|
|
||||||
djob->deleteLater();
|
|
||||||
});
|
|
||||||
job->start();
|
|
||||||
};
|
|
||||||
|
|
||||||
startDeleteJob(_user);
|
|
||||||
|
|
||||||
/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
|
|
||||||
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
|
||||||
*
|
|
||||||
* Disabled as long as selecting another cert is not supported by the UI.
|
|
||||||
*
|
|
||||||
* Being able to specify a new certificate is important anyway: expiry etc.
|
|
||||||
*
|
|
||||||
* We introduce this dirty hack here, to allow deleting them upon Remote Wipe.
|
|
||||||
*/
|
|
||||||
if(_account->isRemoteWipeRequested_HACK()) {
|
|
||||||
// <-- FIXME MS@2019-12-07
|
|
||||||
startDeleteJob(_user + clientKeyPEMC);
|
|
||||||
startDeleteJob(_user + clientCertificatePEMC);
|
|
||||||
|
|
||||||
for (auto i = 0; i < _clientSslCaCertificates.count(); i++) {
|
|
||||||
startDeleteJob(_user + clientCaCertificatePEMC + QString::number(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
// Also delete key / cert sub-chunks (Windows workaround)
|
|
||||||
// The first chunk (0) has no suffix, to stay compatible with older versions and non-Windows
|
|
||||||
for (auto chunk = 1; chunk < KeychainChunk::MaxChunks; chunk++) {
|
|
||||||
const QString strChunkSuffix = QString(".") + QString::number(chunk);
|
|
||||||
|
|
||||||
startDeleteJob(_user + clientKeyPEMC + strChunkSuffix);
|
|
||||||
startDeleteJob(_user + clientCertificatePEMC + strChunkSuffix);
|
|
||||||
|
|
||||||
for (auto i = 0; i < _clientSslCaCertificates.count(); i++) {
|
|
||||||
startDeleteJob(_user + clientCaCertificatePEMC + QString::number(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// FIXME MS@2019-12-07 -->
|
|
||||||
}
|
|
||||||
// <-- FIXME MS@2019-12-07
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace OCC
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#include <QSslCertificate>
|
#include <QSslCertificate>
|
||||||
#include <QSslKey>
|
#include <QSslKey>
|
||||||
#include <QNetworkRequest>
|
|
||||||
#include <QQueue>
|
|
||||||
|
|
||||||
#include "creds/abstractcredentials.h"
|
#include "creds/abstractcredentials.h"
|
||||||
|
|
||||||
@@ -19,29 +17,14 @@ namespace QKeychain {
|
|||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
namespace KeychainChunk {
|
|
||||||
class ReadJob;
|
|
||||||
class WriteJob;
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebFlowCredentialsDialog;
|
class WebFlowCredentialsDialog;
|
||||||
|
|
||||||
class WebFlowCredentials : public AbstractCredentials
|
class WebFlowCredentials : public AbstractCredentials
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
friend class WebFlowCredentialsAccessManager;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Don't add credentials if this is set on a QNetworkRequest
|
|
||||||
static constexpr QNetworkRequest::Attribute DontAddCredentialsAttribute = QNetworkRequest::User;
|
|
||||||
|
|
||||||
explicit WebFlowCredentials();
|
explicit WebFlowCredentials();
|
||||||
WebFlowCredentials(
|
WebFlowCredentials(const QString &user, const QString &password, const QSslCertificate &certificate = QSslCertificate(), const QSslKey &key = QSslKey());
|
||||||
const QString &user,
|
|
||||||
const QString &password,
|
|
||||||
const QSslCertificate &certificate = QSslCertificate(),
|
|
||||||
const QSslKey &key = QSslKey(),
|
|
||||||
const QList<QSslCertificate> &caCertificates = QList<QSslCertificate>());
|
|
||||||
|
|
||||||
QString authType() const override;
|
QString authType() const override;
|
||||||
QString user() const override;
|
QString user() const override;
|
||||||
@@ -65,51 +48,12 @@ private slots:
|
|||||||
void slotAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);
|
void slotAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);
|
||||||
void slotFinished(QNetworkReply *reply);
|
void slotFinished(QNetworkReply *reply);
|
||||||
|
|
||||||
void slotAskFromUserCredentialsProvided(const QString &user, const QString &pass, const QString &host);
|
|
||||||
void slotAskFromUserCancelled();
|
|
||||||
|
|
||||||
void slotReadClientCertPEMJobDone(KeychainChunk::ReadJob *readJob);
|
|
||||||
void slotReadClientKeyPEMJobDone(KeychainChunk::ReadJob *readJob);
|
|
||||||
void slotReadClientCaCertsPEMJobDone(KeychainChunk::ReadJob *readJob);
|
|
||||||
void slotReadPasswordJobDone(QKeychain::Job *incomingJob);
|
void slotReadPasswordJobDone(QKeychain::Job *incomingJob);
|
||||||
|
void slotAskFromUserCredentialsProvided(const QString &user, const QString &pass, const QString &host);
|
||||||
void slotWriteClientCertPEMJobDone(KeychainChunk::WriteJob *writeJob);
|
|
||||||
void slotWriteClientKeyPEMJobDone(KeychainChunk::WriteJob *writeJob);
|
|
||||||
void slotWriteClientCaCertsPEMJobDone(KeychainChunk::WriteJob *writeJob);
|
|
||||||
void slotWriteJobDone(QKeychain::Job *);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
|
||||||
* Windows: Workaround for CredWriteW used by QtKeychain
|
|
||||||
*
|
|
||||||
* Saving all client CA's within one credential may result in:
|
|
||||||
* Error: "Credential size exceeds maximum size of 2560"
|
|
||||||
*/
|
|
||||||
void readSingleClientCaCertPEM();
|
|
||||||
void writeSingleClientCaCertPEM();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since we're limited by Windows limits, we just create our own
|
|
||||||
* limit to avoid evil things happening by endless recursion
|
|
||||||
*
|
|
||||||
* Better than storing the count and relying on maybe-hacked values
|
|
||||||
*/
|
|
||||||
static constexpr int _clientSslCaCertificatesMaxCount = 10;
|
|
||||||
QQueue<QSslCertificate> _clientSslCaCertificatesWriteQueue;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** Reads data from keychain locations
|
|
||||||
*
|
|
||||||
* Goes through
|
|
||||||
* slotReadClientCertPEMJobDone to
|
|
||||||
* slotReadClientKeyPEMJobDone to
|
|
||||||
* slotReadClientCaCertsPEMJobDone to
|
|
||||||
* slotReadJobDone
|
|
||||||
*/
|
|
||||||
void fetchFromKeychainHelper();
|
void fetchFromKeychainHelper();
|
||||||
|
void deleteOldKeychainEntries();
|
||||||
/// Wipes legacy keychain locations
|
|
||||||
void deleteKeychainEntries(bool oldKeychainEntries = false);
|
|
||||||
|
|
||||||
QString fetchUser();
|
QString fetchUser();
|
||||||
|
|
||||||
@@ -117,16 +61,14 @@ protected:
|
|||||||
QString _password;
|
QString _password;
|
||||||
QSslKey _clientSslKey;
|
QSslKey _clientSslKey;
|
||||||
QSslCertificate _clientSslCertificate;
|
QSslCertificate _clientSslCertificate;
|
||||||
QList<QSslCertificate> _clientSslCaCertificates;
|
|
||||||
|
|
||||||
bool _ready;
|
bool _ready;
|
||||||
bool _credentialsValid;
|
bool _credentialsValid;
|
||||||
bool _keychainMigration;
|
bool _keychainMigration;
|
||||||
bool _retryOnKeyChainError = true; // true if we haven't done yet any reading from keychain
|
|
||||||
|
|
||||||
WebFlowCredentialsDialog *_askDialog;
|
WebFlowCredentialsDialog *_askDialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OCC
|
}
|
||||||
|
|
||||||
#endif // WEBFLOWCREDENTIALS_H
|
#endif // WEBFLOWCREDENTIALS_H
|
||||||
|
|||||||
@@ -3,102 +3,42 @@
|
|||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
|
||||||
#include "theme.h"
|
|
||||||
#include "application.h"
|
|
||||||
#include "owncloudgui.h"
|
|
||||||
#include "headerbanner.h"
|
|
||||||
#include "wizard/owncloudwizardcommon.h"
|
|
||||||
#include "wizard/webview.h"
|
#include "wizard/webview.h"
|
||||||
#include "wizard/flow2authwidget.h"
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
WebFlowCredentialsDialog::WebFlowCredentialsDialog(Account *account, bool useFlow2, QWidget *parent)
|
WebFlowCredentialsDialog::WebFlowCredentialsDialog(QWidget *parent)
|
||||||
: QDialog(parent),
|
: QDialog(parent)
|
||||||
_useFlow2(useFlow2),
|
|
||||||
_flow2AuthWidget(nullptr),
|
|
||||||
_webView(nullptr)
|
|
||||||
{
|
{
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
||||||
|
|
||||||
_layout = new QVBoxLayout(this);
|
_layout = new QVBoxLayout(this);
|
||||||
int spacing = _layout->spacing();
|
|
||||||
int margin = _layout->margin();
|
|
||||||
_layout->setSpacing(0);
|
|
||||||
_layout->setMargin(0);
|
|
||||||
|
|
||||||
if(_useFlow2) {
|
|
||||||
_headerBanner = new HeaderBanner(this);
|
|
||||||
_layout->addWidget(_headerBanner);
|
|
||||||
Theme *theme = Theme::instance();
|
|
||||||
_headerBanner->setup(tr("Log in"), theme->wizardHeaderLogo(), theme->wizardHeaderBanner(),
|
|
||||||
Qt::AutoText, QString::fromLatin1("color:#fff;"));
|
|
||||||
}
|
|
||||||
|
|
||||||
_containerLayout = new QVBoxLayout(this);
|
|
||||||
_containerLayout->setSpacing(spacing);
|
|
||||||
_containerLayout->setMargin(margin);
|
|
||||||
|
|
||||||
|
//QString msg = tr("You have been logged out of %1 as user %2, please login again")
|
||||||
|
// .arg(_account->displayName(), _user);
|
||||||
_infoLabel = new QLabel();
|
_infoLabel = new QLabel();
|
||||||
_containerLayout->addWidget(_infoLabel);
|
_layout->addWidget(_infoLabel);
|
||||||
|
|
||||||
if (_useFlow2) {
|
_webView = new WebView();
|
||||||
_flow2AuthWidget = new Flow2AuthWidget();
|
_layout->addWidget(_webView);
|
||||||
_containerLayout->addWidget(_flow2AuthWidget);
|
|
||||||
|
|
||||||
connect(_flow2AuthWidget, &Flow2AuthWidget::authResult, this, &WebFlowCredentialsDialog::slotFlow2AuthResult);
|
|
||||||
|
|
||||||
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
|
|
||||||
connect(this, &WebFlowCredentialsDialog::styleChanged, _flow2AuthWidget, &Flow2AuthWidget::slotStyleChanged);
|
|
||||||
|
|
||||||
// allow Flow2 page to poll on window activation
|
|
||||||
connect(this, &WebFlowCredentialsDialog::onActivate, _flow2AuthWidget, &Flow2AuthWidget::slotPollNow);
|
|
||||||
|
|
||||||
_flow2AuthWidget->startAuth(account);
|
|
||||||
} else {
|
|
||||||
_webView = new WebView();
|
|
||||||
_containerLayout->addWidget(_webView);
|
|
||||||
|
|
||||||
connect(_webView, &WebView::urlCatched, this, &WebFlowCredentialsDialog::urlCatched);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto app = static_cast<Application *>(qApp);
|
|
||||||
connect(app, &Application::isShowingSettingsDialog, this, &WebFlowCredentialsDialog::slotShowSettingsDialog);
|
|
||||||
|
|
||||||
_errorLabel = new QLabel();
|
_errorLabel = new QLabel();
|
||||||
_errorLabel->hide();
|
_errorLabel->hide();
|
||||||
_containerLayout->addWidget(_errorLabel);
|
_layout->addWidget(_errorLabel);
|
||||||
|
|
||||||
WizardCommon::initErrorLabel(_errorLabel);
|
|
||||||
|
|
||||||
_layout->addLayout(_containerLayout);
|
|
||||||
setLayout(_layout);
|
setLayout(_layout);
|
||||||
|
|
||||||
customizeStyle();
|
connect(_webView, &WebView::urlCatched, this, &WebFlowCredentialsDialog::urlCatched);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentialsDialog::closeEvent(QCloseEvent* e) {
|
void WebFlowCredentialsDialog::closeEvent(QCloseEvent* e) {
|
||||||
Q_UNUSED(e)
|
Q_UNUSED(e);
|
||||||
|
|
||||||
if (_webView) {
|
// Force calling WebView::~WebView() earlier so that _profile and _page are
|
||||||
// Force calling WebView::~WebView() earlier so that _profile and _page are
|
// deleted in the correct order.
|
||||||
// deleted in the correct order.
|
delete _webView;
|
||||||
_webView->deleteLater();
|
|
||||||
_webView = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_flow2AuthWidget) {
|
|
||||||
_flow2AuthWidget->resetAuth();
|
|
||||||
_flow2AuthWidget->deleteLater();
|
|
||||||
_flow2AuthWidget = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit onClose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentialsDialog::setUrl(const QUrl &url) {
|
void WebFlowCredentialsDialog::setUrl(const QUrl &url) {
|
||||||
if (_webView)
|
_webView->setUrl(url);
|
||||||
_webView->setUrl(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentialsDialog::setInfo(const QString &msg) {
|
void WebFlowCredentialsDialog::setInfo(const QString &msg) {
|
||||||
@@ -106,14 +46,6 @@ void WebFlowCredentialsDialog::setInfo(const QString &msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentialsDialog::setError(const QString &error) {
|
void WebFlowCredentialsDialog::setError(const QString &error) {
|
||||||
// bring window to top
|
|
||||||
slotShowSettingsDialog();
|
|
||||||
|
|
||||||
if (_useFlow2 && _flow2AuthWidget) {
|
|
||||||
_flow2AuthWidget->setError(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.isEmpty()) {
|
if (error.isEmpty()) {
|
||||||
_errorLabel->hide();
|
_errorLabel->hide();
|
||||||
} else {
|
} else {
|
||||||
@@ -122,49 +54,4 @@ void WebFlowCredentialsDialog::setError(const QString &error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentialsDialog::changeEvent(QEvent *e)
|
|
||||||
{
|
|
||||||
switch (e->type()) {
|
|
||||||
case QEvent::StyleChange:
|
|
||||||
case QEvent::PaletteChange:
|
|
||||||
case QEvent::ThemeChange:
|
|
||||||
customizeStyle();
|
|
||||||
|
|
||||||
// Notify the other widgets (Dark-/Light-Mode switching)
|
|
||||||
emit styleChanged();
|
|
||||||
break;
|
|
||||||
case QEvent::ActivationChange:
|
|
||||||
if(isActiveWindow())
|
|
||||||
emit onActivate();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDialog::changeEvent(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebFlowCredentialsDialog::customizeStyle()
|
|
||||||
{
|
|
||||||
// HINT: Customize dialog's own style here, if necessary in the future (Dark-/Light-Mode switching)
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentialsDialog::slotShowSettingsDialog()
|
|
||||||
{
|
|
||||||
// bring window to top but slightly delay, to avoid being hidden behind the SettingsDialog
|
|
||||||
QTimer::singleShot(100, this, [this] {
|
|
||||||
ownCloudGui::raiseDialog(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebFlowCredentialsDialog::slotFlow2AuthResult(Flow2Auth::Result r, const QString &errorString, const QString &user, const QString &appPassword)
|
|
||||||
{
|
|
||||||
if(r == Flow2Auth::LoggedIn) {
|
|
||||||
emit urlCatched(user, appPassword, QString());
|
|
||||||
} else {
|
|
||||||
// bring window to top
|
|
||||||
slotShowSettingsDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||
|
|||||||
@@ -4,61 +4,36 @@
|
|||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "accountfwd.h"
|
|
||||||
#include "creds/flow2auth.h"
|
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
class HeaderBanner;
|
|
||||||
class WebView;
|
class WebView;
|
||||||
class Flow2AuthWidget;
|
|
||||||
|
|
||||||
class WebFlowCredentialsDialog : public QDialog
|
class WebFlowCredentialsDialog : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
WebFlowCredentialsDialog(Account *account, bool useFlow2, QWidget *parent = nullptr);
|
WebFlowCredentialsDialog(QWidget *parent = nullptr);
|
||||||
|
|
||||||
void setUrl(const QUrl &url);
|
void setUrl(const QUrl &url);
|
||||||
void setInfo(const QString &msg);
|
void setInfo(const QString &msg);
|
||||||
void setError(const QString &error);
|
void setError(const QString &error);
|
||||||
|
|
||||||
bool isUsingFlow2() const {
|
|
||||||
return _useFlow2;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent * e) override;
|
void closeEvent(QCloseEvent * e) override;
|
||||||
void changeEvent(QEvent *) override;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void slotFlow2AuthResult(Flow2Auth::Result, const QString &errorString, const QString &user, const QString &appPassword);
|
|
||||||
void slotShowSettingsDialog();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void urlCatched(const QString user, const QString pass, const QString host);
|
void urlCatched(const QString user, const QString pass, const QString host);
|
||||||
void styleChanged();
|
|
||||||
void onActivate();
|
|
||||||
void onClose();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void customizeStyle();
|
|
||||||
|
|
||||||
bool _useFlow2;
|
|
||||||
|
|
||||||
Flow2AuthWidget *_flow2AuthWidget;
|
|
||||||
WebView *_webView;
|
WebView *_webView;
|
||||||
|
|
||||||
QLabel *_errorLabel;
|
QLabel *_errorLabel;
|
||||||
QLabel *_infoLabel;
|
QLabel *_infoLabel;
|
||||||
QVBoxLayout *_layout;
|
QVBoxLayout *_layout;
|
||||||
QVBoxLayout *_containerLayout;
|
|
||||||
HeaderBanner *_headerBanner;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OCC
|
}
|
||||||
|
|
||||||
#endif // WEBFLOWCREDENTIALSDIALOG_H
|
#endif // WEBFLOWCREDENTIALSDIALOG_H
|
||||||
|
|||||||
@@ -417,13 +417,6 @@ void Folder::createGuiLog(const QString &filename, LogStatus status, int count,
|
|||||||
text = tr("%1 could not be synced due to an error. See the log for details.").arg(file);
|
text = tr("%1 could not be synced due to an error. See the log for details.").arg(file);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LogStatusFileLocked:
|
|
||||||
if (count > 1) {
|
|
||||||
text = tr("%1 and %n other file(s) are currently locked.", "", count -1).arg(file);
|
|
||||||
} else {
|
|
||||||
text = tr("%1 is currently locked.").arg(file);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text.isEmpty()) {
|
if (!text.isEmpty()) {
|
||||||
@@ -902,19 +895,13 @@ void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add new directories or remove gone away dirs to the watcher
|
// add new directories or remove gone away dirs to the watcher
|
||||||
if (_folderWatcher && item->isDirectory()) {
|
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_NEW) {
|
||||||
switch (item->_instruction) {
|
if (_folderWatcher)
|
||||||
case CSYNC_INSTRUCTION_NEW:
|
_folderWatcher->addPath(path() + item->_file);
|
||||||
_folderWatcher->addPath(path() + item->_file);
|
}
|
||||||
break;
|
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||||
case CSYNC_INSTRUCTION_REMOVE:
|
if (_folderWatcher)
|
||||||
_folderWatcher->removePath(path() + item->_file);
|
_folderWatcher->removePath(path() + item->_file);
|
||||||
break;
|
|
||||||
case CSYNC_INSTRUCTION_RENAME:
|
|
||||||
_folderWatcher->removePath(path() + item->_file);
|
|
||||||
_folderWatcher->addPath(path() + item->destination());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success and failure of sync items adjust what the next sync is
|
// Success and failure of sync items adjust what the next sync is
|
||||||
@@ -1085,20 +1072,20 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel
|
|||||||
if (!cfgFile.promptDeleteFiles())
|
if (!cfgFile.promptDeleteFiles())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QString msg = dir == SyncFileItem::Down ? tr("All files in the sync folder '%1' were deleted on the server.\n"
|
QString msg = dir == SyncFileItem::Down ? tr("All files in the sync folder '%1' folder were deleted on the server.\n"
|
||||||
"These deletes will be synchronized to your local sync folder, making such files "
|
"These deletes will be synchronized to your local sync folder, making such files "
|
||||||
"unavailable unless you have a right to restore. \n"
|
"unavailable unless you have a right to restore. \n"
|
||||||
"If you decide to restore the files, they will be re-synced with the server if you have rights to do so.\n"
|
"If you decide to keep the files, they will be re-synced with the server if you have rights to do so.\n"
|
||||||
"If you decide to delete the files, they will be unavailable to you, unless you are the owner.")
|
"If you decide to delete the files, they will be unavailable to you, unless you are the owner.")
|
||||||
: tr("All files got deleted from your local sync folder '%1'.\n"
|
: tr("All the files in your local sync folder '%1' were deleted. These deletes will be "
|
||||||
"These files will be deleted from the server and will not be available on your other devices if they "
|
"synchronized with your server, making such files unavailable unless restored.\n"
|
||||||
"will not be restored.\n"
|
"Are you sure you want to sync those actions with the server?\n"
|
||||||
"If this action was unintended you can restore the lost data now.");
|
"If this was an accident and you decide to keep your files, they will be re-synced from the server.");
|
||||||
QMessageBox msgBox(QMessageBox::Warning, tr("Delete all files?"),
|
QMessageBox msgBox(QMessageBox::Warning, tr("Download new files?"),
|
||||||
msg.arg(shortGuiLocalPath()));
|
msg.arg(shortGuiLocalPath()));
|
||||||
msgBox.setWindowFlags(msgBox.windowFlags() | Qt::WindowStaysOnTopHint);
|
msgBox.setWindowFlags(msgBox.windowFlags() | Qt::WindowStaysOnTopHint);
|
||||||
msgBox.addButton(tr("Delete all files"), QMessageBox::DestructiveRole);
|
msgBox.addButton(tr("Download new files"), QMessageBox::DestructiveRole);
|
||||||
QPushButton *keepBtn = msgBox.addButton(tr("Restore deleted files"), QMessageBox::AcceptRole);
|
QPushButton *keepBtn = msgBox.addButton(tr("Keep local files"), QMessageBox::AcceptRole);
|
||||||
if (msgBox.exec() == -1) {
|
if (msgBox.exec() == -1) {
|
||||||
*cancel = true;
|
*cancel = true;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ FolderMan::FolderMan(QObject *parent)
|
|||||||
this, &FolderMan::slotScheduleFolderByTime);
|
this, &FolderMan::slotScheduleFolderByTime);
|
||||||
_timeScheduler.start();
|
_timeScheduler.start();
|
||||||
|
|
||||||
connect(AccountManager::instance(), &AccountManager::removeAccountFolders,
|
connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||||
this, &FolderMan::slotRemoveFoldersForAccount);
|
this, &FolderMan::slotRemoveFoldersForAccount);
|
||||||
|
|
||||||
connect(_lockWatcher.data(), &LockWatcher::fileUnlocked,
|
connect(_lockWatcher.data(), &LockWatcher::fileUnlocked,
|
||||||
@@ -443,7 +443,7 @@ void FolderMan::slotFolderSyncPaused(Folder *f, bool paused)
|
|||||||
void FolderMan::slotFolderCanSyncChanged()
|
void FolderMan::slotFolderCanSyncChanged()
|
||||||
{
|
{
|
||||||
Folder *f = qobject_cast<Folder *>(sender());
|
Folder *f = qobject_cast<Folder *>(sender());
|
||||||
ASSERT(f);
|
ASSERT(f);
|
||||||
if (f->canSync()) {
|
if (f->canSync()) {
|
||||||
_socketApi->slotRegisterPath(f->alias());
|
_socketApi->slotRegisterPath(f->alias());
|
||||||
} else {
|
} else {
|
||||||
@@ -562,7 +562,7 @@ void FolderMan::slotEtagJobDestroyed(QObject * /*o*/)
|
|||||||
void FolderMan::slotRunOneEtagJob()
|
void FolderMan::slotRunOneEtagJob()
|
||||||
{
|
{
|
||||||
if (_currentEtagJob.isNull()) {
|
if (_currentEtagJob.isNull()) {
|
||||||
Folder *folder = nullptr;
|
Folder *folder;
|
||||||
foreach (Folder *f, _folderMap) {
|
foreach (Folder *f, _folderMap) {
|
||||||
if (f->etagJob()) {
|
if (f->etagJob()) {
|
||||||
// Caveat: always grabs the first folder with a job, but we think this is Ok for now and avoids us having a seperate queue.
|
// Caveat: always grabs the first folder with a job, but we think this is Ok for now and avoids us having a seperate queue.
|
||||||
@@ -1084,73 +1084,6 @@ bool FolderMan::startFromScratch(const QString &localFolder)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderMan::slotWipeFolderForAccount(AccountState *accountState)
|
|
||||||
{
|
|
||||||
QVarLengthArray<Folder *, 16> foldersToRemove;
|
|
||||||
Folder::MapIterator i(_folderMap);
|
|
||||||
while (i.hasNext()) {
|
|
||||||
i.next();
|
|
||||||
Folder *folder = i.value();
|
|
||||||
if (folder->accountState() == accountState) {
|
|
||||||
foldersToRemove.append(folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
foreach (const auto &f, foldersToRemove) {
|
|
||||||
if (!f) {
|
|
||||||
qCCritical(lcFolderMan) << "Can not remove null folder";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qCInfo(lcFolderMan) << "Removing " << f->alias();
|
|
||||||
|
|
||||||
const bool currentlyRunning = (_currentSyncFolder == f);
|
|
||||||
if (currentlyRunning) {
|
|
||||||
// abort the sync now
|
|
||||||
terminateSyncProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_scheduledFolders.removeAll(f) > 0) {
|
|
||||||
emit scheduleQueueChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wipe database
|
|
||||||
f->wipe();
|
|
||||||
|
|
||||||
// wipe data
|
|
||||||
QDir userFolder(f->path());
|
|
||||||
if (userFolder.exists()) {
|
|
||||||
success = userFolder.removeRecursively();
|
|
||||||
if (!success) {
|
|
||||||
qCWarning(lcFolderMan) << "Failed to remove existing folder " << f->path();
|
|
||||||
} else {
|
|
||||||
qCInfo(lcFolderMan) << "wipe: Removed file " << f->path();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
success = true;
|
|
||||||
qCWarning(lcFolderMan) << "folder does not exist, can not remove.";
|
|
||||||
}
|
|
||||||
|
|
||||||
f->setSyncPaused(true);
|
|
||||||
|
|
||||||
// remove the folder configuration
|
|
||||||
f->removeFromSettings();
|
|
||||||
|
|
||||||
unloadFolder(f);
|
|
||||||
if (currentlyRunning) {
|
|
||||||
delete f;
|
|
||||||
}
|
|
||||||
|
|
||||||
_navigationPaneHelper.scheduleUpdateCloudStorageRegistry();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit folderListChanged(_folderMap);
|
|
||||||
emit wipeDone(accountState, success);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolderMan::setDirtyProxy()
|
void FolderMan::setDirtyProxy()
|
||||||
{
|
{
|
||||||
foreach (Folder *f, _folderMap.values()) {
|
foreach (Folder *f, _folderMap.values()) {
|
||||||
|
|||||||
@@ -207,11 +207,6 @@ signals:
|
|||||||
*/
|
*/
|
||||||
void folderListChanged(const Folder::Map &);
|
void folderListChanged(const Folder::Map &);
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted once slotRemoveFoldersForAccount is done wiping
|
|
||||||
*/
|
|
||||||
void wipeDone(AccountState *account, bool success);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -236,9 +231,6 @@ public slots:
|
|||||||
// slot to schedule an ETag job (from Folder only)
|
// slot to schedule an ETag job (from Folder only)
|
||||||
void slotScheduleETagJob(const QString &alias, RequestEtagJob *job);
|
void slotScheduleETagJob(const QString &alias, RequestEtagJob *job);
|
||||||
|
|
||||||
/** Wipe folder */
|
|
||||||
void slotWipeFolderForAccount(AccountState *accountState);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void slotFolderSyncPaused(Folder *, bool paused);
|
void slotFolderSyncPaused(Folder *, bool paused);
|
||||||
void slotFolderCanSyncChanged();
|
void slotFolderCanSyncChanged();
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace OCC {
|
|||||||
FolderStatusDelegate::FolderStatusDelegate()
|
FolderStatusDelegate::FolderStatusDelegate()
|
||||||
: QStyledItemDelegate()
|
: QStyledItemDelegate()
|
||||||
{
|
{
|
||||||
customizeStyle();
|
m_moreIcon = QIcon(QLatin1String(":/client/resources/more.svg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FolderStatusDelegate::addFolderText()
|
QString FolderStatusDelegate::addFolderText()
|
||||||
@@ -168,7 +168,6 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString));
|
QString itemString = qvariant_cast<QString>(index.data(SyncProgressItemString));
|
||||||
int warningCount = qvariant_cast<int>(index.data(WarningCount));
|
int warningCount = qvariant_cast<int>(index.data(WarningCount));
|
||||||
bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning));
|
bool syncOngoing = qvariant_cast<bool>(index.data(SyncRunning));
|
||||||
QDateTime syncDate = qvariant_cast<QDateTime>(index.data(SyncDate));
|
|
||||||
bool syncEnabled = qvariant_cast<bool>(index.data(FolderAccountConnected));
|
bool syncEnabled = qvariant_cast<bool>(index.data(FolderAccountConnected));
|
||||||
|
|
||||||
QRect iconRect = option.rect;
|
QRect iconRect = option.rect;
|
||||||
@@ -253,7 +252,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
if (!showProgess) {
|
if (!showProgess) {
|
||||||
painter->setFont(subFont);
|
painter->setFont(subFont);
|
||||||
QString elidedRemotePathText = subFm.elidedText(
|
QString elidedRemotePathText = subFm.elidedText(
|
||||||
tr("Synchronized with local folder (%1)").arg(syncDate.toTimeSpec(Qt::LocalTime).toString(Qt::SystemLocaleShortDate)),
|
tr("Synchronized with local folder"),
|
||||||
Qt::ElideRight, remotePathRect.width());
|
Qt::ElideRight, remotePathRect.width());
|
||||||
painter->drawText(QStyle::visualRect(option.direction, option.rect, remotePathRect),
|
painter->drawText(QStyle::visualRect(option.direction, option.rect, remotePathRect),
|
||||||
textAlign, elidedRemotePathText);
|
textAlign, elidedRemotePathText);
|
||||||
@@ -273,11 +272,6 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
rect.setHeight(texts.count() * subFm.height() + 2 * margin);
|
rect.setHeight(texts.count() * subFm.height() + 2 * margin);
|
||||||
rect.setRight(option.rect.right() - margin);
|
rect.setRight(option.rect.right() - margin);
|
||||||
|
|
||||||
// save previous state to not mess up colours with the background (fixes issue: https://github.com/nextcloud/desktop/issues/1237)
|
|
||||||
auto oldBrush = painter->brush();
|
|
||||||
auto oldPen = painter->pen();
|
|
||||||
auto oldFont = painter->font();
|
|
||||||
|
|
||||||
painter->setBrush(color);
|
painter->setBrush(color);
|
||||||
painter->setPen(QColor(0xaa, 0xaa, 0xaa));
|
painter->setPen(QColor(0xaa, 0xaa, 0xaa));
|
||||||
painter->drawRoundedRect(QStyle::visualRect(option.direction, option.rect, rect),
|
painter->drawRoundedRect(QStyle::visualRect(option.direction, option.rect, rect),
|
||||||
@@ -295,11 +289,6 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
textRect.translate(0, textRect.height());
|
textRect.translate(0, textRect.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore previous state
|
|
||||||
painter->setBrush(oldBrush);
|
|
||||||
painter->setPen(oldPen);
|
|
||||||
painter->setFont(oldFont);
|
|
||||||
|
|
||||||
h = rect.bottom() + margin;
|
h = rect.bottom() + margin;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -359,7 +348,7 @@ void FolderStatusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
|
|||||||
btnOpt.arrowType = Qt::NoArrow;
|
btnOpt.arrowType = Qt::NoArrow;
|
||||||
btnOpt.subControls = QStyle::SC_ToolButton;
|
btnOpt.subControls = QStyle::SC_ToolButton;
|
||||||
btnOpt.rect = optionsButtonVisualRect;
|
btnOpt.rect = optionsButtonVisualRect;
|
||||||
btnOpt.icon = _iconMore;
|
btnOpt.icon = m_moreIcon;
|
||||||
int e = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize);
|
int e = QApplication::style()->pixelMetric(QStyle::PM_ButtonIconSize);
|
||||||
btnOpt.iconSize = QSize(e,e);
|
btnOpt.iconSize = QSize(e,e);
|
||||||
QApplication::style()->drawComplexControl(QStyle::CC_ToolButton, &btnOpt, painter);
|
QApplication::style()->drawComplexControl(QStyle::CC_ToolButton, &btnOpt, painter);
|
||||||
@@ -433,14 +422,5 @@ QRect FolderStatusDelegate::errorsListRect(QRect within)
|
|||||||
return within;
|
return within;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderStatusDelegate::slotStyleChanged()
|
|
||||||
{
|
|
||||||
customizeStyle();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolderStatusDelegate::customizeStyle()
|
|
||||||
{
|
|
||||||
_iconMore = Theme::createColorAwareIcon(QLatin1String(":/client/resources/more.svg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class FolderStatusDelegate : public QStyledItemDelegate
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
QIcon m_moreIcon;
|
||||||
FolderStatusDelegate();
|
FolderStatusDelegate();
|
||||||
|
|
||||||
enum datarole { FolderAliasRole = Qt::UserRole + 100,
|
enum datarole { FolderAliasRole = Qt::UserRole + 100,
|
||||||
@@ -43,7 +44,6 @@ public:
|
|||||||
SyncProgressItemString,
|
SyncProgressItemString,
|
||||||
WarningCount,
|
WarningCount,
|
||||||
SyncRunning,
|
SyncRunning,
|
||||||
SyncDate,
|
|
||||||
|
|
||||||
AddButton // 1 = enabled; 2 = disabled
|
AddButton // 1 = enabled; 2 = disabled
|
||||||
};
|
};
|
||||||
@@ -61,16 +61,9 @@ public:
|
|||||||
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);
|
||||||
|
|
||||||
public slots:
|
|
||||||
void slotStyleChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void customizeStyle();
|
|
||||||
|
|
||||||
static QString addFolderText();
|
static QString addFolderText();
|
||||||
QPersistentModelIndex _pressedIndex;
|
QPersistentModelIndex _pressedIndex;
|
||||||
|
|
||||||
QIcon _iconMore;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant(tr("Error while loading the list of folders from the server.")
|
return QVariant(tr("Error while loading the list of folders from the server.")
|
||||||
+ QString("\n") + x->_lastErrorString);
|
+ QString("\n") + x->_lastErrorString);
|
||||||
} else {
|
} else {
|
||||||
return tr("Fetching folder list from server …");
|
return tr("Fetching folder list from server...");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -218,8 +218,6 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
|||||||
return f->syncResult().errorStrings();
|
return f->syncResult().errorStrings();
|
||||||
case FolderStatusDelegate::SyncRunning:
|
case FolderStatusDelegate::SyncRunning:
|
||||||
return f->syncResult().status() == SyncResult::SyncRunning;
|
return f->syncResult().status() == SyncResult::SyncRunning;
|
||||||
case FolderStatusDelegate::SyncDate:
|
|
||||||
return f->syncResult().syncTime();
|
|
||||||
case FolderStatusDelegate::HeaderRole:
|
case FolderStatusDelegate::HeaderRole:
|
||||||
return f->shortGuiRemotePathOrAppName();
|
return f->shortGuiRemotePathOrAppName();
|
||||||
case FolderStatusDelegate::FolderAliasRole:
|
case FolderStatusDelegate::FolderAliasRole:
|
||||||
@@ -1099,15 +1097,15 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
|||||||
}
|
}
|
||||||
QString message;
|
QString message;
|
||||||
if (pos <= 0) {
|
if (pos <= 0) {
|
||||||
message = tr("Waiting …");
|
message = tr("Waiting...");
|
||||||
} else {
|
} else {
|
||||||
message = tr("Waiting for %n other folder(s) …", "", pos);
|
message = tr("Waiting for %n other folder(s)...", "", pos);
|
||||||
}
|
}
|
||||||
pi = SubFolderInfo::Progress();
|
pi = SubFolderInfo::Progress();
|
||||||
pi._overallSyncString = message;
|
pi._overallSyncString = message;
|
||||||
} else if (state == SyncResult::SyncPrepare) {
|
} else if (state == SyncResult::SyncPrepare) {
|
||||||
pi = SubFolderInfo::Progress();
|
pi = SubFolderInfo::Progress();
|
||||||
pi._overallSyncString = tr("Preparing to sync …");
|
pi._overallSyncString = tr("Preparing to sync...");
|
||||||
} else if (state == SyncResult::Problem || state == SyncResult::Success) {
|
} else if (state == SyncResult::Problem || state == SyncResult::Success) {
|
||||||
// Reset the progress info after a sync.
|
// Reset the progress info after a sync.
|
||||||
pi = SubFolderInfo::Progress();
|
pi = SubFolderInfo::Progress();
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
#include "folderwatcher.h"
|
#include "folderwatcher.h"
|
||||||
#include "folderwatcher_win.h"
|
#include "folderwatcher_win.h"
|
||||||
|
|
||||||
#include "common/utility.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
@@ -54,7 +52,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||||||
|
|
||||||
// QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
|
// QVarLengthArray ensures the stack-buffer is aligned like double and qint64.
|
||||||
QVarLengthArray<char, 4096 * 10> fileNotifyBuffer;
|
QVarLengthArray<char, 4096 * 10> fileNotifyBuffer;
|
||||||
fileNotifyBuffer.resize(OCC::Utility::convertSizeToInt(fileNotifyBufferSize));
|
fileNotifyBuffer.resize(fileNotifyBufferSize);
|
||||||
|
|
||||||
const size_t fileNameBufferSize = 4096;
|
const size_t fileNameBufferSize = 4096;
|
||||||
TCHAR fileNameBuffer[fileNameBufferSize];
|
TCHAR fileNameBuffer[fileNameBufferSize];
|
||||||
@@ -68,7 +66,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||||||
DWORD dwBytesReturned = 0;
|
DWORD dwBytesReturned = 0;
|
||||||
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
|
SecureZeroMemory(pFileNotifyBuffer, fileNotifyBufferSize);
|
||||||
if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer,
|
if (!ReadDirectoryChangesW(_directory, (LPVOID)pFileNotifyBuffer,
|
||||||
OCC::Utility::convertSizeToDWORD(fileNotifyBufferSize), true,
|
fileNotifyBufferSize, true,
|
||||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||||
&dwBytesReturned,
|
&dwBytesReturned,
|
||||||
&overlapped,
|
&overlapped,
|
||||||
@@ -115,7 +113,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||||||
FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer;
|
FILE_NOTIFY_INFORMATION *curEntry = pFileNotifyBuffer;
|
||||||
forever {
|
forever {
|
||||||
size_t len = curEntry->FileNameLength / 2;
|
size_t len = curEntry->FileNameLength / 2;
|
||||||
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, OCC::Utility::convertSizeToInt(len));
|
QString file = _path + "\\" + QString::fromWCharArray(curEntry->FileName, len);
|
||||||
|
|
||||||
// Unless the file was removed or renamed, get its full long name
|
// Unless the file was removed or renamed, get its full long name
|
||||||
// TODO: We could still try expanding the path in the tricky cases...
|
// TODO: We could still try expanding the path in the tricky cases...
|
||||||
@@ -124,7 +122,7 @@ void WatcherThread::watchChanges(size_t fileNotifyBufferSize,
|
|||||||
&& curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) {
|
&& curEntry->Action != FILE_ACTION_RENAMED_OLD_NAME) {
|
||||||
size_t longNameSize = GetLongPathNameW(reinterpret_cast<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
|
size_t longNameSize = GetLongPathNameW(reinterpret_cast<LPCWSTR>(file.utf16()), fileNameBuffer, fileNameBufferSize);
|
||||||
if (longNameSize > 0) {
|
if (longNameSize > 0) {
|
||||||
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), OCC::Utility::convertSizeToInt(longNameSize));
|
longfile = QString::fromUtf16(reinterpret_cast<const ushort *>(fileNameBuffer), longNameSize);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(lcFolderWatcher) << "Error converting file name to full length, keeping original name.";
|
qCWarning(lcFolderWatcher) << "Error converting file name to full length, keeping original name.";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string notr="true">Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string notr="true">Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_6">
|
<layout class="QGridLayout" name="gridLayout_6">
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
<enum>QFrame::Plain</enum>
|
<enum>QFrame::Plain</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">TextLabel</string>
|
<string>TextLabel</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat">
|
<property name="textFormat">
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "updater/updater.h"
|
#include "updater/updater.h"
|
||||||
#include "updater/ocupdater.h"
|
#include "updater/ocupdater.h"
|
||||||
#include "ignorelisteditor.h"
|
#include "ignorelisteditor.h"
|
||||||
#include "common/utility.h"
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -36,12 +35,6 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QScopedValueRollback>
|
#include <QScopedValueRollback>
|
||||||
|
|
||||||
#define QTLEGACY (QT_VERSION < QT_VERSION_CHECK(5,9,0))
|
|
||||||
|
|
||||||
#if !(QTLEGACY)
|
|
||||||
#include <QOperatingSystemVersion>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace OCC {
|
namespace OCC {
|
||||||
|
|
||||||
GeneralSettings::GeneralSettings(QWidget *parent)
|
GeneralSettings::GeneralSettings(QWidget *parent)
|
||||||
@@ -57,13 +50,6 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
|||||||
|
|
||||||
connect(_ui->showInExplorerNavigationPaneCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotShowInExplorerNavigationPane);
|
connect(_ui->showInExplorerNavigationPaneCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotShowInExplorerNavigationPane);
|
||||||
|
|
||||||
// Rename 'Explorer' appropriately on non-Windows
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
QString txt = _ui->showInExplorerNavigationPaneCheckBox->text();
|
|
||||||
txt.replace(QString::fromLatin1("Explorer"), QString::fromLatin1("Finder"));
|
|
||||||
_ui->showInExplorerNavigationPaneCheckBox->setText(txt);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_ui->autostartCheckBox->setChecked(Utility::hasLaunchOnStartup(Theme::instance()->appName()));
|
_ui->autostartCheckBox->setChecked(Utility::hasLaunchOnStartup(Theme::instance()->appName()));
|
||||||
connect(_ui->autostartCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotToggleLaunchOnStartup);
|
connect(_ui->autostartCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotToggleLaunchOnStartup);
|
||||||
|
|
||||||
@@ -77,8 +63,7 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
|||||||
connect(_ui->legalNoticeButton, &QPushButton::clicked, this, &GeneralSettings::slotShowLegalNotice);
|
connect(_ui->legalNoticeButton, &QPushButton::clicked, this, &GeneralSettings::slotShowLegalNotice);
|
||||||
|
|
||||||
loadMiscSettings();
|
loadMiscSettings();
|
||||||
// updater info now set in: customizeStyle
|
slotUpdateInfo();
|
||||||
//slotUpdateInfo();
|
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
connect(_ui->monoIconsCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::saveMiscSettings);
|
connect(_ui->monoIconsCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::saveMiscSettings);
|
||||||
@@ -94,13 +79,9 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
|||||||
// Hide on non-Windows, or WindowsVersion < 10.
|
// Hide on non-Windows, or WindowsVersion < 10.
|
||||||
// The condition should match the default value of ConfigFile::showInExplorerNavigationPane.
|
// The condition should match the default value of ConfigFile::showInExplorerNavigationPane.
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#if QTLEGACY
|
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
|
||||||
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS10)
|
|
||||||
#else
|
|
||||||
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows10)
|
|
||||||
#endif
|
|
||||||
_ui->showInExplorerNavigationPaneCheckBox->setVisible(false);
|
|
||||||
#endif
|
#endif
|
||||||
|
_ui->showInExplorerNavigationPaneCheckBox->setVisible(false);
|
||||||
|
|
||||||
/* Set the left contents margin of the layout to zero to make the checkboxes
|
/* Set the left contents margin of the layout to zero to make the checkboxes
|
||||||
* align properly vertically , fixes bug #3758
|
* align properly vertically , fixes bug #3758
|
||||||
@@ -117,8 +98,6 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
|||||||
|
|
||||||
// accountAdded means the wizard was finished and the wizard might change some options.
|
// accountAdded means the wizard was finished and the wizard might change some options.
|
||||||
connect(AccountManager::instance(), &AccountManager::accountAdded, this, &GeneralSettings::loadMiscSettings);
|
connect(AccountManager::instance(), &AccountManager::accountAdded, this, &GeneralSettings::loadMiscSettings);
|
||||||
|
|
||||||
customizeStyle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneralSettings::~GeneralSettings()
|
GeneralSettings::~GeneralSettings()
|
||||||
@@ -159,11 +138,7 @@ void GeneralSettings::slotUpdateInfo()
|
|||||||
connect(updater, &OCUpdater::downloadStateChanged, this, &GeneralSettings::slotUpdateInfo, Qt::UniqueConnection);
|
connect(updater, &OCUpdater::downloadStateChanged, this, &GeneralSettings::slotUpdateInfo, Qt::UniqueConnection);
|
||||||
connect(_ui->restartButton, &QAbstractButton::clicked, updater, &OCUpdater::slotStartInstaller, Qt::UniqueConnection);
|
connect(_ui->restartButton, &QAbstractButton::clicked, updater, &OCUpdater::slotStartInstaller, Qt::UniqueConnection);
|
||||||
connect(_ui->restartButton, &QAbstractButton::clicked, qApp, &QApplication::quit, Qt::UniqueConnection);
|
connect(_ui->restartButton, &QAbstractButton::clicked, qApp, &QApplication::quit, Qt::UniqueConnection);
|
||||||
|
_ui->updateStateLabel->setText(updater->statusString());
|
||||||
QString status = updater->statusString();
|
|
||||||
Theme::replaceLinkColorStringBackgroundAware(status);
|
|
||||||
_ui->updateStateLabel->setText(status);
|
|
||||||
|
|
||||||
_ui->restartButton->setVisible(updater->downloadState() == OCUpdater::DownloadComplete);
|
_ui->restartButton->setVisible(updater->downloadState() == OCUpdater::DownloadComplete);
|
||||||
} else {
|
} else {
|
||||||
// can't have those infos from sparkle currently
|
// can't have those infos from sparkle currently
|
||||||
@@ -209,7 +184,6 @@ void GeneralSettings::slotShowInExplorerNavigationPane(bool checked)
|
|||||||
void GeneralSettings::slotIgnoreFilesEditor()
|
void GeneralSettings::slotIgnoreFilesEditor()
|
||||||
{
|
{
|
||||||
if (_ignoreEditor.isNull()) {
|
if (_ignoreEditor.isNull()) {
|
||||||
ConfigFile cfgFile;
|
|
||||||
_ignoreEditor = new IgnoreListEditor(this);
|
_ignoreEditor = new IgnoreListEditor(this);
|
||||||
_ignoreEditor->setAttribute(Qt::WA_DeleteOnClose, true);
|
_ignoreEditor->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
_ignoreEditor->open();
|
_ignoreEditor->open();
|
||||||
@@ -225,20 +199,4 @@ void GeneralSettings::slotShowLegalNotice()
|
|||||||
delete notice;
|
delete notice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneralSettings::slotStyleChanged()
|
|
||||||
{
|
|
||||||
customizeStyle();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GeneralSettings::customizeStyle()
|
|
||||||
{
|
|
||||||
// setup about section
|
|
||||||
QString about = Theme::instance()->about();
|
|
||||||
Theme::replaceLinkColorStringBackgroundAware(about);
|
|
||||||
_ui->aboutLabel->setText(about);
|
|
||||||
|
|
||||||
// updater info
|
|
||||||
slotUpdateInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
} // namespace OCC
|
||||||
|
|||||||
@@ -39,9 +39,6 @@ public:
|
|||||||
~GeneralSettings();
|
~GeneralSettings();
|
||||||
QSize sizeHint() const override;
|
QSize sizeHint() const override;
|
||||||
|
|
||||||
public slots:
|
|
||||||
void slotStyleChanged();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void saveMiscSettings();
|
void saveMiscSettings();
|
||||||
void slotToggleLaunchOnStartup(bool);
|
void slotToggleLaunchOnStartup(bool);
|
||||||
@@ -53,8 +50,6 @@ private slots:
|
|||||||
void slotShowLegalNotice();
|
void slotShowLegalNotice();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void customizeStyle();
|
|
||||||
|
|
||||||
Ui::GeneralSettings *_ui;
|
Ui::GeneralSettings *_ui;
|
||||||
QPointer<IgnoreListEditor> _ignoreEditor;
|
QPointer<IgnoreListEditor> _ignoreEditor;
|
||||||
QPointer<SyncLogDialog> _syncLogDialog;
|
QPointer<SyncLogDialog> _syncLogDialog;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string notr="true">Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) by Michael Schuster <michael@nextcloud.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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Based on Qt sourcecode:
|
|
||||||
** qt5/qtbase/src/widgets/dialogs/qwizard.cpp
|
|
||||||
**
|
|
||||||
** https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/dialogs/qwizard.cpp?h=v5.13.0
|
|
||||||
**
|
|
||||||
** Original license:
|
|
||||||
**
|
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
** Contact: https://www.qt.io/licensing/
|
|
||||||
**
|
|
||||||
** This file is part of the QtWidgets module of the Qt Toolkit.
|
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:LGPL$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and The Qt Company. For licensing terms
|
|
||||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
||||||
** information use the contact form at https://www.qt.io/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 3 as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
||||||
** packaging of this file. Please review the following information to
|
|
||||||
** ensure the GNU Lesser General Public License version 3 requirements
|
|
||||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 2.0 or (at your option) the GNU General
|
|
||||||
** Public license version 3 or any later version approved by the KDE Free
|
|
||||||
** Qt Foundation. The licenses are as published by the Free Software
|
|
||||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
||||||
** included in the packaging of this file. Please review the following
|
|
||||||
** information to ensure the GNU General Public License requirements will
|
|
||||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
|
||||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "headerbanner.h"
|
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
|
|
||||||
#include <QPainter>
|
|
||||||
#include <QStyle>
|
|
||||||
#include <QGuiApplication>
|
|
||||||
|
|
||||||
namespace OCC {
|
|
||||||
|
|
||||||
// These fudge terms were needed a few places to obtain pixel-perfect results
|
|
||||||
const int GapBetweenLogoAndRightEdge = 5;
|
|
||||||
const int ModernHeaderTopMargin = 2;
|
|
||||||
|
|
||||||
HeaderBanner::HeaderBanner(QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
|
||||||
setBackgroundRole(QPalette::Base);
|
|
||||||
titleLabel = new QLabel(this);
|
|
||||||
titleLabel->setBackgroundRole(QPalette::Base);
|
|
||||||
logoLabel = new QLabel(this);
|
|
||||||
QFont font = titleLabel->font();
|
|
||||||
font.setBold(true);
|
|
||||||
titleLabel->setFont(font);
|
|
||||||
layout = new QGridLayout(this);
|
|
||||||
layout->setContentsMargins(QMargins());
|
|
||||||
layout->setSpacing(0);
|
|
||||||
layout->setRowMinimumHeight(3, 1);
|
|
||||||
layout->setRowStretch(4, 1);
|
|
||||||
layout->setColumnStretch(2, 1);
|
|
||||||
layout->setColumnMinimumWidth(4, 2 * GapBetweenLogoAndRightEdge);
|
|
||||||
layout->setColumnMinimumWidth(6, GapBetweenLogoAndRightEdge);
|
|
||||||
layout->addWidget(titleLabel, 1, 1, 5, 1);
|
|
||||||
layout->addWidget(logoLabel, 1, 5, 5, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeaderBanner::setup(const QString &title, const QPixmap &logo, const QPixmap &banner,
|
|
||||||
const Qt::TextFormat titleFormat, const QString &styleSheet)
|
|
||||||
{
|
|
||||||
QStyle *style = parentWidget()->style();
|
|
||||||
//const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
|
|
||||||
int topLevelMarginLeft = style->pixelMetric(QStyle::PM_LayoutLeftMargin, 0, parentWidget());
|
|
||||||
int topLevelMarginRight = style->pixelMetric(QStyle::PM_LayoutRightMargin, 0, parentWidget());
|
|
||||||
int topLevelMarginTop = style->pixelMetric(QStyle::PM_LayoutTopMargin, 0, parentWidget());
|
|
||||||
//int topLevelMarginBottom = style->pixelMetric(QStyle::PM_LayoutBottomMargin, 0, parentWidget());
|
|
||||||
|
|
||||||
layout->setRowMinimumHeight(0, ModernHeaderTopMargin);
|
|
||||||
layout->setRowMinimumHeight(1, topLevelMarginTop - ModernHeaderTopMargin - 1);
|
|
||||||
layout->setRowMinimumHeight(6, 3);
|
|
||||||
int minColumnWidth0 = topLevelMarginLeft + topLevelMarginRight;
|
|
||||||
int minColumnWidth1 = topLevelMarginLeft + topLevelMarginRight + 1;
|
|
||||||
layout->setColumnMinimumWidth(0, minColumnWidth0);
|
|
||||||
layout->setColumnMinimumWidth(1, minColumnWidth1);
|
|
||||||
titleLabel->setTextFormat(titleFormat);
|
|
||||||
titleLabel->setText(title);
|
|
||||||
if(!styleSheet.isEmpty())
|
|
||||||
titleLabel->setStyleSheet(styleSheet);
|
|
||||||
logoLabel->setPixmap(logo);
|
|
||||||
bannerPixmap = banner;
|
|
||||||
if (bannerPixmap.isNull()) {
|
|
||||||
QSize size = layout->totalMinimumSize();
|
|
||||||
setMinimumSize(size);
|
|
||||||
setMaximumSize(QWIDGETSIZE_MAX, size.height());
|
|
||||||
} else {
|
|
||||||
setFixedHeight(banner.height() + 2);
|
|
||||||
}
|
|
||||||
updateGeometry();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeaderBanner::paintEvent(QPaintEvent * /* event */)
|
|
||||||
{
|
|
||||||
QPainter painter(this);
|
|
||||||
painter.drawPixmap(0, 0, width(), bannerPixmap.height(), bannerPixmap);
|
|
||||||
int x = width() - 2;
|
|
||||||
int y = height() - 2;
|
|
||||||
const QPalette &pal = QGuiApplication::palette();
|
|
||||||
painter.setPen(pal.mid().color());
|
|
||||||
painter.drawLine(0, y, x, y);
|
|
||||||
painter.setPen(pal.base().color());
|
|
||||||
painter.drawPoint(x + 1, y);
|
|
||||||
painter.drawLine(0, y + 1, x + 1, y + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OCC
|
|
||||||