Comparar commits
2 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| b15b4fc1de | |||
| ab8c1ddfed |
@@ -1,53 +1,5 @@
|
||||
ChangeLog
|
||||
=========
|
||||
version 2.0.2 (release 2015-10-xx)
|
||||
* csync_file_stat_s: Save a bit of memory
|
||||
* Shibboleth: Add our base user agent to WebKit
|
||||
* SelectiveSync: Increase folder list timeout to 60
|
||||
* Propagation: Try another sync on 423 Locked #3387
|
||||
* Propagation: Make 423 Locked a soft error #3387
|
||||
* Propagation: Reset upload blacklist if a chunk suceeds
|
||||
* Application: Fix crash on early shutdown #3898
|
||||
* Linux: Don't show settings dialog always when launched twice #3273 #3771 #3485
|
||||
* win32 vio: Add the OPEN_REPARSE_POINTS flag to the CreateFileW call. #3813
|
||||
* AccountSettings: only expand root elements on single click.
|
||||
* AccountSettings: Do not allow to expand the folder list when disconnected.
|
||||
* Use application SHORT name for the name of the MacOSX pkg file (ownBrander).
|
||||
* FolderMan: Fix for removing a syncing folder #3843
|
||||
* ConnectionMethodDialog: Don't be insecure on close #3863
|
||||
* Updater: Ensure folders are not removed #3747
|
||||
* Folder settings: Ensure path is cleaned #3811
|
||||
* Propagator: Simplify sub job finished counting #3844
|
||||
* Share dialog: Hide settings dialog before showing #3783
|
||||
* UI: Only expand 1 level in folder list #3585
|
||||
* UI: Allow folder expanding from button click #3585
|
||||
* UI: Expand folder treeview on single click #3585
|
||||
* GUI: Change tray menu order #3657
|
||||
* GUI: Replace term "sign in" with "Log in" and friends.
|
||||
* SetupPage: Fix crash caused by uninitialized Account object.
|
||||
* Use a themable WebDAV path all over.
|
||||
* Units: Back to the "usual" mix units (JEDEC standard).
|
||||
* csync io: Full UNC path support on Win #3748
|
||||
* Tray: Don't use the tray workaround with the KDE theme #3706, #3765
|
||||
* ShareDialog: Fix folder display #3659
|
||||
* AccountSettings: Restore from legacy only once #3565
|
||||
* SSL Certificate Error Dialog: show account name #3729
|
||||
* Tray notification: Don't show a message about modified folder #3613
|
||||
* PropagateLocalRemove: remove entries from the DB even if there was an error.
|
||||
* Settings UI improvements (eg. #3713, #3721, #3619 and others)
|
||||
* Folder: Do not create the sync folder if it does not exist #3692
|
||||
* Shell integratioon: don't show share menu item for top level folders
|
||||
* Tray: Hide while modifying menus #3656 #3672
|
||||
* AddFolder: Improve remote path selection error handling #3573
|
||||
* csync_update: Use excluded_traversal() to improve performance #3638
|
||||
* csync_excluded: Add fast _traversal() function #3638
|
||||
* csync_exclude: Speed up siginificantly #3638
|
||||
* AccountSettings: Adjust quota info design #3644 #3651
|
||||
* Adjust buttons on remove folder/account questions #3654
|
||||
|
||||
version 2.0.1 (release 2015-09-01)
|
||||
* AccountWizard: fix when the theme specify a override URL (#3699)
|
||||
|
||||
version 2.0.0 (release 2015-08-25)
|
||||
* Add support for multiple accounts (#3084)
|
||||
* Do not sync down new big folders from server without users consent (#3148)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
set( MIRALL_VERSION_MAJOR 2 )
|
||||
set( MIRALL_VERSION_MINOR 1 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_VERSION_MINOR 0 )
|
||||
set( MIRALL_VERSION_PATCH 2 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
|
||||
@@ -23,7 +23,7 @@ identity="$3"
|
||||
prjfile=$build_path/admin/osx/macosx.pkgproj
|
||||
|
||||
# The name of the installer package
|
||||
installer="@APPLICATION_SHORTNAME@-@MIRALL_VERSION_FULL@@MIRALL_VERSION_SUFFIX@"
|
||||
installer="@APPLICATION_NAME@-@MIRALL_VERSION_FULL@@MIRALL_VERSION_SUFFIX@"
|
||||
installer_file="$installer.pkg"
|
||||
installer_file_tar="$installer.pkg.tar"
|
||||
installer_file_tar_bz2="$installer.pkg.tar.bz2"
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "Neodinstalov
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ji§ nainstalov no"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Zvolte, jak chcete ${APPLICATION_NAME} nainstalovat."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "NovØjç¡ verze aplikace ${APPLICATION_NAME} je ji§ nainstalov na. Instalace starç¡ verze se nedoporuŸuje. Pokud opravdu chcete tuto starç¡ verzi nainstalovat, je lepç¡ nejprve odinstalovat souŸasnou verzi. Zvolte po§adovanou operaci a kliknØte na Dalç¡ pro pokraŸov n¡."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} je ji§ nainstalov na.$\n$\nZvolte po§adovanou operaci a kliknØte na Dalç¡ pro pokraŸov n¡."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Pýidat Ÿi znovu instalovat komponenty"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Odinstalovat ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Odinstalovat ${APPLICATION_NAME}"
|
||||
@@ -41,3 +40,4 @@ StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Tento odinstal
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Slu§ba pýihl çen¡ nebا¡, ukonŸuji!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Odinstal tor je ji§ spuçtØn."
|
||||
StrCpy $SectionGroup_Shortcuts "Z stupci"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "نمایش پادداشت های انتشار نسخه"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "${APPLICATION_EXECUTABLE} پردازش (ها) که باید متوقف شوند را پیدا کرد. $\nآیا میخواهیم برنامه نصاب این پردازشها را برای شما متوقف کند ؟"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "حذف پردازشهای ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "پردازش برای از بین بردن یافت نشد!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "نسخهی قدیمی از برنامه ${APPLICATION_NAME} بر روی سیستم شما نصب شده است، پیشنهاد میشود نسخهی فعلی را قبل از نصب حذف کنید. عملیات مورد نظر را انتخاب کنید و برای ادامه روی دکمه Next کلیک کنید."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "عمل حذف را قبل از نصب انجام دهید"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "حذف نکن"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "از قبل نصب شده است"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "نحوهی نصب ${APPLICATION_NAME} را انتخاب کنید."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "نسخه جدیدتری از برنامه ${APPLICATION_NAME} بر روی سیستم شما نصب شده است، نصب نسخهی قدیمیتر پیشنهاد نمیشود. درصورتیکه میخواهید نسخهی قدیمی را نصب کنید، حذف نسخهی کنونی قبل از اجرای نصب جدید پیشنهاد میشود. عملیات مورد نظر را انتخاب و بر روی دکمهی Next کلیک کنید."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "نسخه ${VERSION} از ${APPLICATION_NAME} هماکنون نصب شده است.$↩$\nعملیات مورد نظر را انتخاب و بر روی دکمه Next کلیک کنید."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "افزودن/نصب مجدد اجزا"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "حذف ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "حذف ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "گزینه نگهداری را به منظور اجرا انتخاب کنید."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "نصب ضروریات ${APPLICATION_NAME}"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "یکپارچهسازی با Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "نصب یکپارچهساز با Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "بازکردن میانبر منو برنامه"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "افزودن میانبر ${APPLICATION_NAME} به استارت منو ."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "میانبر دسکتاپ"
|
||||
@@ -35,9 +23,21 @@ StrCpy $UNINSTALL_ABORT "عمل حذف توسط کاربر متوقف شد"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "میانبر بازکردن سریع ( N/A )"
|
||||
StrCpy $INIT_NO_DESKTOP "میانبر دسکتاپ (رونویسی وجود دارد)"
|
||||
StrCpy $UAC_ERROR_ELEVATE "مشکل در بالااوردن ، خطا : "
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "برای نصب، دسترسی مدیر سیستم نیاز است، مجددا تلاش کنید"
|
||||
StrCpy $INIT_INSTALLER_RUNNING "نصاب از قبل در حال اجراست."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "حذف برنامه نیاز به دسترسی مدیر دارد ، لطفا دوباره سعی کنید"
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "سرویس ورود اجرا نیست، درحال لغو نصب!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "حذف کننده از قبل در حال اجراست."
|
||||
StrCpy $SectionGroup_Shortcuts "میانبرها"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Found ${APPLICATION_EXECUTABLE} process(s) which need to be stopped.$\nDo you want the installer to stop these for you?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Killing ${APPLICATION_EXECUTABLE} processes."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "An older version of ${APPLICATION_NAME} is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue."
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Choose how you want to install ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "A newer version of ${APPLICATION_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it is better to uninstall the current version first. Select the operation you want to perform and click Next to continue."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Uninstall ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Uninstall ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Choose the maintenance option to perform."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Installing ${APPLICATION_NAME} essentials."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing Integration for Windows Explorer"
|
||||
StrCpy $UAC_INSTALLER_REQUIRE_ADMIN "This installer requires admin access, try again"
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "Ne pas désinstaller"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Déjà installé"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Choisissez comment installer ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Une version plus récente de ${APPLICATION_NAME} est déjà installée ! Il n'est pas recommandé d'installer une version plus ancienne. Si vous voulez vraiment installer cette version plus ancienne, il est préférable de d'abord désinstaller la version courante. Sélectionnez l'opération que vous voulez exécuter et cliquez sur Suivant pour continuer."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} est déjà installé.$\n$\nSélectionnez l'opération que vous souhaitez effectuer et cliquez sur Suivant pour continuer."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Ajouter/Réinstaller des composants"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Désinstaller ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Désinstaller ${APPLICATION_NAME}"
|
||||
@@ -41,3 +40,4 @@ StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Ce désinstallateur requiert les droits a
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Service de logon non lancé ! Abandon."
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Une désinstallation est déjà en cours."
|
||||
StrCpy $SectionGroup_Shortcuts "Raccourcis"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "Ne távolítsa el"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Már telepítve"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Válaszd ki, hogy szeretnéd telepíteni a következő alkalmazást ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Az ${APPLICATION_NAME} alklamazás egy újabb verziója már megtalálható a rendszeren. Nem ajánlott egy régebbi verzió telepítése. Ha valóban szeretné a régebbi verziót telepíteni, akkor ajánlott a jelenleg telepített verzió eltávolítása. Válassza ki milyen műveletet szeretne végrehajtani, és nyomja meg a $\"Következő$\" gombot a folytatáshoz."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "Az ${APPLICATION_NAME} alkalmazás ${VERSION} verziója már telepítve van.$↩$\nKérjük válaszd ki milyen műveletet szeretnél végrehajtani, és nyomd meg a „Következő” gombot."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Komponens hozzáadása/újratelepítése"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} eltávolítása"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} eltávolítása"
|
||||
@@ -41,3 +40,4 @@ StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Az eltávolító futtatásához adminisz
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "A bejelentkező szolgáltatás nem fut, megszakítás!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Az eltávolító már fut."
|
||||
StrCpy $SectionGroup_Shortcuts "Parancsikonok"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "インストール済"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "${APPLICATION_NAME} のインストール方法を選択する"
|
||||
StrCpy $PageReinstall_OLD_Field_1 "${APPLICATION_NAME} の最新バージョンがすでにインストールされています。\n旧バージョンのインストールはお勧めしません。旧バージョンのインストールが本当に必要な場合は、まず最新バージョンをアンインストールしてから、旧バージョンをインストールしてください。\nオペレーションを選択し、次へをクリックする。"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} は、${VERSION} が既にインストールされています。$\n$\n実行したい操作を選択し、次へをクリックする。"
|
||||
StrCpy $PageReinstall_SAME_Field_2 "追加/再インストールコンポーネント"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} をアンインストール"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} をアンインストール"
|
||||
@@ -41,3 +40,4 @@ StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "ログオンサービスが動いていません。中止します。"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "アンインストーラーは、すでに起動しています。"
|
||||
StrCpy $SectionGroup_Shortcuts "ショートカット"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "Не устанавливать"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Уже установлено"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Выберите, как вы хотите установить ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Новая версия ${APPLICATION_NAME} уже установлена! Не рекомендуется устанавливать старую версию. Если вы действительно хотите установить эту старую версию, то сначала лучше удалить текущую версию. Выберите желаемое действие и нажмите Далее для продолжения."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} уже установлен.$\n$\nУкажите действие и нажмите Далее для продолжения."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Добавить/Переустановить компоненты"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Удалить ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Удалить ${APPLICATION_NAME}"
|
||||
@@ -41,3 +40,4 @@ StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Этому деинсталлятору
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Служба входа в систему не запущена, прерывание!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Программа удаления уже выполняется."
|
||||
StrCpy $SectionGroup_Shortcuts "Ярлыки"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "不要卸载"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "已经安装"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "选择如何安装${APPLICATION_NAME}。"
|
||||
StrCpy $PageReinstall_OLD_Field_1 "较新版本的 ${APPLICATION_NAME} 已经安装!安装较旧版本的程序是不推荐的。如果您希望继续安装较旧版本,建议先卸载较新版本。选择您想要执行的操作并点击下一步以继续。"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} 已经安装。$\n$\n请选择想要执行的操作并点击下一步。"
|
||||
StrCpy $PageReinstall_SAME_Field_2 "增加/重装组件"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "卸载${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "卸载${APPLICATION_NAME}"
|
||||
@@ -40,4 +39,5 @@ StrCpy $INIT_INSTALLER_RUNNING "安装程序已经运行。"
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "卸载程序需要管理员权限,请重试"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "卸载程序已经运行。"
|
||||
StrCpy $SectionGroup_Shortcuts "快捷方式"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Logon service is not running, aborting!"
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "No desinstalar"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Ya está instalado"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "Elija cómo quiere instalar ${APPLICATION_NAME}."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "Una nueva versión de ${APPLICATION_NAME} ya está instalada. No es recomendable instalar una versión anterior. Si realmente quiere instalar esta versión anterior, es mejor que desinstale la versión actual primero. Seleccione la operación que desea realizar y pulse Siguiente para continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} ya está instalado.$\n$\nSeleccione la operación que desea realizar y haga click en Siguiente para continuar."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Añadir/Reinstalar componentes"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "Desinstalar ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstalar ${APPLICATION_NAME}"
|
||||
@@ -30,7 +29,7 @@ StrCpy $OPTION_SECTION_SC_QUICK_LAUNCH_Desc "Lanzador R
|
||||
StrCpy $UNINSTALLER_FILE_Detail "Escribiendo desinstalador"
|
||||
StrCpy $UNINSTALLER_REGISTRY_Detail "Escribiendo claves en el registro del instalador"
|
||||
StrCpy $UNINSTALLER_FINISHED_Detail "Terminado"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Parece que ${APPLICATION_NAME} no está instalado en el directorio '$INSTDIR'.$$ ¿Continuar de todos modos? (No recomendado)"
|
||||
StrCpy $UNINSTALL_MESSAGEBOX "Parece que ${APPLICATION_NAME} no está instalado en el directorio '$INSTDIR'.$$ ¿Continuar de todos modos? (No Recomendado)"
|
||||
StrCpy $UNINSTALL_ABORT "Desinstalación cancelada por el usuario"
|
||||
StrCpy $INIT_NO_QUICK_LAUNCH "Atajo de inicio rápido (N/A)"
|
||||
StrCpy $INIT_NO_DESKTOP "Atajo de escritorio (sobreescribe el existente)"
|
||||
@@ -41,3 +40,4 @@ StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "El desinstalador requiere acceso administ
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Servicio Inicio de sesión no se está ejecutando, abortando!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "El desinstalador ya se encuentra en ejecución."
|
||||
StrCpy $SectionGroup_Shortcuts "Accesos directos"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
|
||||
@@ -9,7 +9,6 @@ StrCpy $PageReinstall_NEW_Field_3 "Kald
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Zaten Yüklü"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_SUBTITLE "${APPLICATION_NAME} uygulamasýný nasýl yüklemek istediðinizi seçin."
|
||||
StrCpy $PageReinstall_OLD_Field_1 "${APPLICATION_NAME} uygulamasýnýn daha yeni sürümü zaten yüklü! Daha eski bir sürümünü yüklemeniz önerilmez. Gerçekten bu eski sürümü yüklemek isterseniz, ilk olarak geçerli sürümü kaldýrmanýz tavsiye edilir. Yapmak istediðiniz iþlemi seçin ve devam etmek üzere Ýleri týklayýn."
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} zaten yüklü.$\n$\nYapmak istediðiniz iþlemi seçin ve devam etmek için Ýleri týklayýn."
|
||||
StrCpy $PageReinstall_SAME_Field_2 "Bileþenleri ekle/yeniden yükle"
|
||||
StrCpy $PageReinstall_SAME_Field_3 "${APPLICATION_NAME} uygulamasýný kaldýr"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "${APPLICATION_NAME} uygulamasýný kaldýr"
|
||||
@@ -41,3 +40,4 @@ StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Bu kald
|
||||
StrCpy $UAC_ERROR_LOGON_SERVICE "Oturum açýlacak sunucu çalýþmadýðýndan iptal ediliyor!"
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "Kaldýrýcý zaten çalýþýyor."
|
||||
StrCpy $SectionGroup_Shortcuts "Kýsayollar"
|
||||
StrCpy $PageReinstall_SAME_Field_1 "${APPLICATION_NAME} ${VERSION} is already installed.$\r$\nSelect the operation you want to perform and click Next to continue."
|
||||
|
||||
@@ -134,7 +134,13 @@ if(NOT DEFINED CMAKE_INSTALL_LIBDIR OR (_libdir_set
|
||||
AND NOT CMAKE_CROSSCOMPILING)
|
||||
if (EXISTS "/etc/debian_version") # is this a debian system ?
|
||||
if(CMAKE_LIBRARY_ARCHITECTURE)
|
||||
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
|
||||
if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
|
||||
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
|
||||
endif()
|
||||
if(DEFINED _GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX
|
||||
AND "${_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$")
|
||||
set(__LAST_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
|
||||
endif()
|
||||
endif()
|
||||
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||
|
||||
@@ -720,6 +720,7 @@ Function .onInit
|
||||
${MementoSectionRestore}
|
||||
|
||||
UAC_TryAgain:
|
||||
ClearErrors
|
||||
!insertmacro UAC_RunElevated
|
||||
${Switch} $0
|
||||
${Case} 0
|
||||
@@ -740,6 +741,7 @@ Function .onInit
|
||||
Abort
|
||||
Quit
|
||||
${EndSwitch}
|
||||
ClearErrors
|
||||
|
||||
;Prevent multiple instances.
|
||||
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${APPLICATION_SHORTNAME}Installer") i .r1 ?e'
|
||||
@@ -770,6 +772,7 @@ Function .onInstSuccess
|
||||
${AndIf} $InstallRunIfSilent == "yes"
|
||||
Call LaunchApplication
|
||||
${EndIf}
|
||||
ClearErrors
|
||||
FunctionEnd
|
||||
|
||||
Function .onInstFailed
|
||||
@@ -785,6 +788,7 @@ Function un.onInit
|
||||
Call un.SetLang
|
||||
|
||||
UAC_TryAgain:
|
||||
ClearErrors
|
||||
!insertmacro UAC_RunElevated
|
||||
${Switch} $0
|
||||
${Case} 0
|
||||
@@ -805,6 +809,7 @@ Function un.onInit
|
||||
Abort
|
||||
Quit
|
||||
${EndSwitch}
|
||||
ClearErrors
|
||||
|
||||
;Prevent multiple instances.
|
||||
System::Call 'kernel32::CreateMutexA(i 0, i 0, t "${APPLICATION_SHORTNAME}Uninstaller") i .r1 ?e'
|
||||
@@ -818,6 +823,7 @@ Function un.onInit
|
||||
FunctionEnd
|
||||
|
||||
Function un.onUnInstSuccess
|
||||
ClearErrors
|
||||
FunctionEnd
|
||||
|
||||
Function un.onUnInstFailed
|
||||
|
||||
@@ -88,8 +88,10 @@ configure_file(csync_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/csync_version.h)
|
||||
|
||||
set(csync_HDRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/csync_version.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../config_csync.h
|
||||
csync.h
|
||||
vio/csync_vio.h
|
||||
vio/csync_vio_method.h
|
||||
vio/csync_vio_module.h
|
||||
)
|
||||
|
||||
# Statically include sqlite
|
||||
@@ -140,18 +142,12 @@ else()
|
||||
RUNTIME DESTINATION
|
||||
${BIN_INSTALL_DIR}/${APPLICATION_EXECUTABLE}
|
||||
)
|
||||
INSTALL(
|
||||
FILES
|
||||
${csync_HDRS}
|
||||
DESTINATION
|
||||
${INCLUDE_INSTALL_DIR}/${APPLICATION_NAME}
|
||||
)
|
||||
INSTALL(
|
||||
FILES
|
||||
std/c_private.h
|
||||
DESTINATION
|
||||
${INCLUDE_INSTALL_DIR}/${APPLICATION_NAME}/std
|
||||
)
|
||||
endif()
|
||||
|
||||
# INSTALL(
|
||||
# FILES
|
||||
# ${csync_HDRS}
|
||||
# DESTINATION
|
||||
# ${INCLUDE_INSTALL_DIR}/${APPLICATION_NAME}
|
||||
# )
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ enum csync_ftw_type_e {
|
||||
};
|
||||
|
||||
|
||||
#define FILE_ID_BUF_SIZE 36
|
||||
#define FILE_ID_BUF_SIZE 21
|
||||
|
||||
// currently specified at https://github.com/owncloud/core/issues/8322 are 9 to 10
|
||||
#define REMOTE_PERM_BUF_SIZE 15
|
||||
|
||||
@@ -185,11 +185,11 @@ struct csync_file_stat_s {
|
||||
size_t pathlen; /* u64 */
|
||||
uint64_t inode; /* u64 */
|
||||
mode_t mode; /* u32 */
|
||||
unsigned int type : 4;
|
||||
unsigned int child_modified : 1;
|
||||
unsigned int should_update_metadata : 1; /*specify that the etag, or the remote perm or fileid has
|
||||
int type; /* u32 */
|
||||
int child_modified;/*bool*/
|
||||
int should_update_metadata; /*bool: specify that the etag, or the remote perm or fileid has
|
||||
changed and need to be updated on the db even for INSTRUCTION_NONE */
|
||||
unsigned int has_ignored_files : 1; /* specify that a directory, or child directory contains ignored files */
|
||||
int has_ignored_files; /*bool: specify that a directory, or child directory contains ignored files */
|
||||
|
||||
char *destpath; /* for renames */
|
||||
const char *etag;
|
||||
|
||||
@@ -189,7 +189,7 @@ int csync_vio_local_stat(const char *uri, csync_vio_file_stat_t *buf) {
|
||||
mbchar_t *wuri = c_utf8_path_to_locale( uri );
|
||||
|
||||
h = CreateFileW( wuri, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS+FILE_FLAG_OPEN_REPARSE_POINT, NULL );
|
||||
FILE_ATTRIBUTE_NORMAL+FILE_FLAG_BACKUP_SEMANTICS, NULL );
|
||||
if( h == INVALID_HANDLE_VALUE ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_CRIT, "CreateFileW failed on %s", uri );
|
||||
errno = GetLastError();
|
||||
|
||||
@@ -108,7 +108,7 @@ ownCloud Client 1.1 or later. Using an incompatible time stamp-based
|
||||
synchronization mechanism can lead to data loss in rare cases, especially when
|
||||
multiple clients are involved and one utilizes a non-synchronized NTP time.
|
||||
|
||||
.. _`NTP time synchronization`: http://en.wikipedia.org/wiki/Network_Time_Protocol
|
||||
.. _`NTP time synchronisation`: http://en.wikipedia.org/wiki/Network_Time_Protocol
|
||||
.. _Etag: http://en.wikipedia.org/wiki/HTTP_ETag
|
||||
|
||||
Comparison and Conflict Cases
|
||||
|
||||
@@ -73,8 +73,8 @@ To prevent automatic updates, but allow manual overrides:
|
||||
|
||||
1. Edit these Registry keys:
|
||||
|
||||
a. (32-bit-Windows) ``HKEY_LOCAL_MACHINE\Software\ownCloud\ownCloud``
|
||||
b. (64-bit-Windows) ``HKEY_LOCAL_MACHINE\Software\Wow6432Node\ownCloud\ownCloud``
|
||||
a. (32-bit) ``HKEY_LOCAL_MACHINE\Software\ownCloud\ownCloud``
|
||||
b. (64-bit) ``HKEY_LOCAL_MACHINE\Software\Wow6432Node\ownCloud\ownCloud``
|
||||
|
||||
2. Add the key ``skipUpdateCheck`` (of type DWORD).
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ It is possible that another program is changing the modification date of the fil
|
||||
|
||||
If the file is uses the ``.eml`` extension, Windows automatically and
|
||||
continually changes all files, unless you remove
|
||||
``\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers``
|
||||
``\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers`
|
||||
from the windows registry.
|
||||
|
||||
See http://petersteier.wordpress.com/2011/10/22/windows-indexer-changes-modification-dates-of-eml-files/ for more information.
|
||||
|
||||
|
Antes Largura: | Altura: | Tamanho: 34 KiB |
|
Antes Largura: | Altura: | Tamanho: 41 KiB |
|
Antes Largura: | Altura: | Tamanho: 67 KiB |
|
Antes Largura: | Altura: | Tamanho: 63 KiB |
|
Antes Largura: | Altura: | Tamanho: 5.7 KiB |
|
Depois Largura: | Altura: | Tamanho: 20 KiB |
|
Depois Largura: | Altura: | Tamanho: 39 KiB |
|
Depois Largura: | Altura: | Tamanho: 20 KiB |
|
Depois Largura: | Altura: | Tamanho: 34 KiB |
|
Depois Largura: | Altura: | Tamanho: 22 KiB |
|
Depois Largura: | Altura: | Tamanho: 18 KiB |
|
Antes Largura: | Altura: | Tamanho: 52 KiB Depois Largura: | Altura: | Tamanho: 53 KiB |
|
Depois Largura: | Altura: | Tamanho: 41 KiB |
|
Depois Largura: | Altura: | Tamanho: 44 KiB |
|
Depois Largura: | Altura: | Tamanho: 59 KiB |
|
Antes Largura: | Altura: | Tamanho: 30 KiB Depois Largura: | Altura: | Tamanho: 34 KiB |
|
Antes Largura: | Altura: | Tamanho: 4.9 KiB Depois Largura: | Altura: | Tamanho: 40 KiB |
|
Antes Largura: | Altura: | Tamanho: 42 KiB Depois Largura: | Altura: | Tamanho: 111 KiB |
@@ -21,18 +21,56 @@ will display a notification when an update is available.
|
||||
Linux users must also have a password manager enabled, such as GNOME Keyring or
|
||||
KWallet, so that the sync client can login automatically.
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
|
||||
The 2.0 release of the ownCloud desktop sync client has many new features and
|
||||
improvements.
|
||||
|
||||
* Multi-account support
|
||||
* Many UI improvements
|
||||
* Accessibility improvements (high contrast schemes)
|
||||
* Automatic Bandwidth Throttling
|
||||
* Don't show redundant directory entries in activity log
|
||||
* Remove deleted accounts properly from toolbar
|
||||
* File manager integration: Show hidden files as ignored
|
||||
* Show wizard when last account was deleted
|
||||
* Do not sync down new big folders from server without user's consent
|
||||
* Integrate Selective Sync into the default UI
|
||||
* More reliable reconnect after timeout
|
||||
* Use SI units for the file sizes
|
||||
* Improve progress reporting during sync
|
||||
* Sharing: Do not allow sharing the root folder
|
||||
* Sharing: Show thumbnail
|
||||
* Client Updater: Check for updates periodically, not only once per run
|
||||
* Quota: Only refresh from server when UI is shown
|
||||
* SSL Button: Show more information
|
||||
* System proxy: Ask user for credentials if needed
|
||||
* Several fixes and performance improvements in the sync engine
|
||||
* OS X: Show file name in UI if file has invalid UTF-8 in file name
|
||||
* OS X: Support native finder integration for 10.10 Yosemite
|
||||
* Network: Try to use SSL session tickets/identifiers
|
||||
* Windows: Support paths >255 characters
|
||||
* Windows, OS X: Allow to not sync hidden files
|
||||
* Windows: Remove misleading option to remove sync data
|
||||
* Windows: Do not provoke Active Directory account locking if password changes
|
||||
* Windows: Fix installer when installing unprivileged
|
||||
|
||||
.. note:: When you upgrade from 1.8, restart Windows to ensure that all new
|
||||
features are visible.
|
||||
|
||||
Installation Wizard
|
||||
-------------------
|
||||
|
||||
The installation wizard takes you step-by-step through configuration options and
|
||||
account setup. First you need to enter the URL of your ownCloud server.
|
||||
|
||||
.. image:: images/client-1.png
|
||||
.. image:: images/client1.png
|
||||
:alt: form for entering ownCloud server URL
|
||||
|
||||
Enter your ownCloud login on the next screen.
|
||||
|
||||
.. image:: images/client-2.png
|
||||
.. image:: images/client2.png
|
||||
:alt: form for entering your ownCloud login
|
||||
|
||||
On the Local Folder Option screen you may sync
|
||||
@@ -40,9 +78,9 @@ all of your files on the ownCloud server, or select individual folders. The
|
||||
default local sync folder is ``ownCloud``, in your home directory. You may
|
||||
change this as well.
|
||||
|
||||
.. image:: images/client-3.png
|
||||
.. image:: images/client3.png
|
||||
:alt: Select which remote folders to sync, and which local folder to store
|
||||
them in.
|
||||
them in.
|
||||
|
||||
When you have completed selecting your sync folders, click the Connect button
|
||||
at the bottom right. The client will attempt to connect to your ownCloud
|
||||
@@ -50,8 +88,28 @@ server, and when it is successful you'll see two buttons: one to connect to
|
||||
your ownCloud Web GUI, and one to open your local folder. It will also start
|
||||
synchronizing your files.
|
||||
|
||||
.. image:: images/client-4.png
|
||||
.. image:: images/client4.png
|
||||
:alt: A successful server connection, showing a button to connect to your
|
||||
Web GUI, and one to open your local ownCloud folder
|
||||
Web GUI, and one to open your local ownCloud folder
|
||||
|
||||
Click the Finish button, and you're all done.
|
||||
Click the Finish button, and you're all done.
|
||||
|
||||
When you are in your local ownCloud folder, you can right-click any file or
|
||||
folder, and then left-click "Share with ownCloud" to create a share link. Note
|
||||
that Windows may also have a Share With option. This is not the ownCloud Share
|
||||
option. Linux users must install the ``owncloud-client-nautilus`` package to
|
||||
enable file sharing from the Nautilus file manager. The ownCloud share dialog
|
||||
looks like the following example on Ubuntu Linux:
|
||||
|
||||
.. image:: images/client5.png
|
||||
:alt: the ownCloud file share option is integrated into the normal
|
||||
right-click file menu in your file manager
|
||||
|
||||
You may change your sync options at any time by opening your ownCloud client
|
||||
and selecting which folders to sync, or to remove from synchronization.
|
||||
you saw in the installation wizard. **If you un-check any folders that
|
||||
you have already synchronized, they will be deleted from your local system.**
|
||||
|
||||
.. image:: images/client6.png
|
||||
:alt: Client dialogue to select different files to sync, or to remove from
|
||||
syncing
|
||||
|
||||
@@ -14,41 +14,4 @@ and local PC.
|
||||
|
||||
.. note:: Because of various technical issues, desktop sync clients older than
|
||||
1.7 will not allowed to connect and sync with the ownCloud 8.1 server. It is
|
||||
highly recommended to keep your client updated.
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
|
||||
The 2.0 release of the ownCloud desktop sync client has many new features and
|
||||
improvements.
|
||||
|
||||
* Multi-account support
|
||||
* Many UI improvements
|
||||
* Accessibility improvements (high contrast schemes)
|
||||
* Automatic bandwidth throttling
|
||||
* No redundant directory entries in activity log
|
||||
* Remove deleted accounts properly from toolbar
|
||||
* File manager integration: show hidden files as ignored
|
||||
* Do not sync new big folders from server without user's consent
|
||||
* Integrate selective sync into the default UI
|
||||
* More reliable reconnect after timeout
|
||||
* Improve progress reporting during sync
|
||||
* Sharing: Do not allow sharing the root folder
|
||||
* Sharing: Show thumbnail
|
||||
* Client Updater: Check for updates periodically, not only once per run
|
||||
* Quota: Only refresh from server when UI is shown
|
||||
* SSL Button: Show more information
|
||||
* System proxy: Ask user for credentials if needed
|
||||
* Several fixes and performance improvements in the sync engine
|
||||
* OS X: Show file name in UI if file has invalid UTF-8 in file name
|
||||
* OS X: Support native finder integration for 10.10 Yosemite
|
||||
* Network: Try to use SSL session tickets/identifiers
|
||||
* Windows: Support paths >255 characters
|
||||
* Windows, OS X: Allow to not sync hidden files
|
||||
* Windows: Remove misleading option to remove sync data
|
||||
* Windows: Do not provoke Active Directory account locking if password changes
|
||||
* Windows: Fix installer when installing unprivileged
|
||||
|
||||
.. note:: When you upgrade from 1.8, restart Windows to ensure that all new
|
||||
features are visible.
|
||||
|
||||
highly recommended to keep your client updated.
|
||||
@@ -9,39 +9,32 @@ in the system tray (Windows, KDE), status bar (Mac OS X), or notification area
|
||||
(Linux).
|
||||
|
||||
.. image:: images/icon.png
|
||||
:alt: Status icon, little cloud with green circle and white checkmark
|
||||
|
||||
The status indicator uses overlay icons to indicate the current status of your
|
||||
synchronization. The green circle with the white checkmark tells you that your
|
||||
synchronization is current and you are connected to your ownCloud server.
|
||||
|
||||
.. image:: images/icon-syncing.png
|
||||
:alt: Status icon, little cloud with blue circle and white semi-circles
|
||||
|
||||
The blue icon with the white semi-circles means synchronization is in progress.
|
||||
|
||||
.. image:: images/icon-paused.png
|
||||
:alt: Status icon, little cloud with yellow circle and vertical parallel
|
||||
lines
|
||||
|
||||
The yellow overlay icon with the parallel lines tells you your synchronization
|
||||
has been paused. (Most likely by you.)
|
||||
has been paused. (Most likely by you, by opening the client and clicking
|
||||
Account > Pause.)
|
||||
|
||||
.. image:: images/icon-offline.png
|
||||
:alt: Status icon, little gray cloud with gray circle and three horizontal
|
||||
white dots
|
||||
|
||||
The gray icon with three white dots means your sync client has lost its
|
||||
connection with your ownCloud server.
|
||||
|
||||
.. image:: images/icon-information.png
|
||||
:alt: Status icon, little cloud with letter "i" in white circle
|
||||
|
||||
When you see a white circle with the letter "i" that is the informational icon,
|
||||
so you should click it to see what it has to tell you.
|
||||
|
||||
.. image:: images/icon-error.png
|
||||
:alt: Status icon, little cloud with red circle and white x
|
||||
|
||||
The red circle with the white "x" indicates a configuration error, such as an
|
||||
incorrect login or server URL.
|
||||
@@ -57,6 +50,7 @@ A right-click on the icon opens a menu for quick access to multiple operations.
|
||||
The Desktop Client menu provides the following options:
|
||||
|
||||
* Open ownCloud in browser
|
||||
* Managed folder
|
||||
* Open folder [your local sync folder]
|
||||
* Up to date
|
||||
* Recent changes
|
||||
@@ -71,47 +65,18 @@ Using the Account Settings Window
|
||||
.. index:: account settings, user, password, Server URL
|
||||
|
||||
Click **Settings** in the right-click menu to see a summary of your ownCloud
|
||||
account settings, or left-click your systray icon. This shows which ownCloud
|
||||
account you are connected to (or accounts, if you have more than one) your
|
||||
account settings. This shows which ownCloud account you are connected to (or accounts, if you have more than one) your
|
||||
quota status, and a window for managing your synchronization settings.
|
||||
|
||||
.. image:: images/client6.png
|
||||
:alt: Account settings window
|
||||
|
||||
At the top of the window are tabs for each configured sync account, and three
|
||||
others for Activity, General and Network settings. On your account tabs you
|
||||
have the following features:
|
||||
|
||||
* Connection status, showing which ownCloud server you are connected to, and
|
||||
your ownCloud username.
|
||||
* A **Remove Account** button, which deletes your account but does not delete
|
||||
your data files.
|
||||
* Used and available space on the server.
|
||||
* Current synchronization status.
|
||||
* **Add Folder Sync Connection** button, which is active only when you have
|
||||
removed synchronization on an account (see **Remove Sync** below).
|
||||
|
||||
The little button with three dots that sits to the right of the sync status bar
|
||||
offers three additional options:
|
||||
|
||||
* Open Folder
|
||||
* Pause Sync
|
||||
* Remove Sync
|
||||
|
||||
**Pause Sync** pauses sync operations without making any changes to your account.
|
||||
|
||||
**Remove Sync** suspends synchronization without removing the account, and it
|
||||
removes your folder sync selection. When you're ready to resume synchronization
|
||||
click the **Add Folder Sync Connection** button, and re-select the folders you
|
||||
want to sync.
|
||||
|
||||
.. image:: images/client-7.png
|
||||
:alt: Extra options for sync operations
|
||||
At the top of the window are tabs for each configured sync account, and three others for Activity, General and Network settings.
|
||||
|
||||
The Activity window contains the log of your recent activities, including files
|
||||
downloaded and deleted, and which local folders your files went into.
|
||||
downloaded and deleted.
|
||||
|
||||
The General window has configuration options such as **Launch on System
|
||||
The General window has configuration options such as Launch on **System
|
||||
Startup**, **Use Monochrome Icons**, and **Show Desktop Notifications**. This
|
||||
is where you will find the **Edit Ignored Files** button, to launch the ignored
|
||||
files editor, and two new features: **Ask confirmation before downloading
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
From 3a26dc77f8e988ea99b23c4d5a2c831ecc31c920 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Goffart <ogoffart@woboq.com>
|
||||
Date: Thu, 17 Jul 2014 13:26:56 +0200
|
||||
Subject: [PATCH] WIP: add KOverlayIconPlugin
|
||||
|
||||
---
|
||||
.../src/kitemviews/kfileitemmodelrolesupdater.cpp | 35 ++++++++++++-
|
||||
.../src/kitemviews/kfileitemmodelrolesupdater.h | 9 ++++
|
||||
lib/konq/CMakeLists.txt | 4 +-
|
||||
lib/konq/koverlayiconplugin.cpp | 30 ++++++++++++
|
||||
lib/konq/koverlayiconplugin.desktop | 4 ++
|
||||
lib/konq/koverlayiconplugin.h | 57 ++++++++++++++++++++++
|
||||
6 files changed, 137 insertions(+), 2 deletions(-)
|
||||
create mode 100644 lib/konq/koverlayiconplugin.cpp
|
||||
create mode 100644 lib/konq/koverlayiconplugin.desktop
|
||||
create mode 100644 lib/konq/koverlayiconplugin.h
|
||||
|
||||
diff --git a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
|
||||
index 0865d40..840a65d 100644
|
||||
--- a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
|
||||
+++ b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
|
||||
@@ -28,9 +28,11 @@
|
||||
#include <KGlobal>
|
||||
#include <KIO/JobUiDelegate>
|
||||
#include <KIO/PreviewJob>
|
||||
+#include <KServiceTypeTrader>
|
||||
|
||||
#include "private/kpixmapmodifier.h"
|
||||
#include "private/kdirectorycontentscounter.h"
|
||||
+#include <koverlayiconplugin.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
@@ -129,6 +131,17 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
|
||||
m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this);
|
||||
connect(m_directoryContentsCounter, SIGNAL(result(QString,int)),
|
||||
this, SLOT(slotDirectoryContentsCountReceived(QString,int)));
|
||||
+
|
||||
+
|
||||
+ const KService::List pluginServices = KServiceTypeTrader::self()->query("KOverlayIconPlugin");
|
||||
+
|
||||
+ for (KService::List::ConstIterator it = pluginServices.constBegin(); it != pluginServices.constEnd(); ++it) {
|
||||
+ KOverlayIconPlugin* plugin = (*it)->createInstance<KOverlayIconPlugin>(this);
|
||||
+ if (plugin) {
|
||||
+ m_overlayIconsPlugin.append(plugin);
|
||||
+ connect(plugin, SIGNAL(overlaysChanged(KUrl,QStringList)), this, SLOT(slotOverlaysChanged(KUrl,QStringList)));
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
|
||||
@@ -1075,7 +1088,11 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
|
||||
data.insert("type", item.mimeComment());
|
||||
}
|
||||
|
||||
- data.insert("iconOverlays", item.overlays());
|
||||
+ QStringList overlays = item.overlays();
|
||||
+ foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
|
||||
+ overlays.append(it->getOverlays(item));
|
||||
+ }
|
||||
+ data.insert("iconOverlays", overlays);
|
||||
|
||||
#ifdef HAVE_BALOO
|
||||
if (m_balooFileMonitor) {
|
||||
@@ -1086,6 +1103,22 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
|
||||
return data;
|
||||
}
|
||||
|
||||
+void KFileItemModelRolesUpdater::slotOverlaysChanged(const KUrl& url, const QStringList &)
|
||||
+{
|
||||
+ KFileItem item = m_model->fileItem(url);
|
||||
+ if (item.isNull())
|
||||
+ return;
|
||||
+ int index = m_model->index(item);
|
||||
+ QHash <QByteArray, QVariant> data = m_model->data(index);
|
||||
+ QStringList overlays = item.overlays();
|
||||
+ foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
|
||||
+ overlays.append(it->getOverlays(item));
|
||||
+ }
|
||||
+ data.insert("iconOverlays", overlays);
|
||||
+ m_model->setData(index, data);
|
||||
+}
|
||||
+
|
||||
+
|
||||
void KFileItemModelRolesUpdater::updateAllPreviews()
|
||||
{
|
||||
if (m_state == Paused) {
|
||||
diff --git a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
|
||||
index a9e979a..6d3add0 100644
|
||||
--- a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
|
||||
+++ b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <QSize>
|
||||
#include <QStringList>
|
||||
|
||||
+class KOverlayIconPlugin;
|
||||
class KDirectoryContentsCounter;
|
||||
class KFileItemModel;
|
||||
class KJob;
|
||||
@@ -180,6 +181,12 @@ private slots:
|
||||
void slotPreviewJobFinished();
|
||||
|
||||
/**
|
||||
+ * Is invoked when one of the KOverlayIconPlugin emit the signal that an overlay has changed
|
||||
+ */
|
||||
+ void slotOverlaysChanged(const KUrl&, const QStringList&);
|
||||
+
|
||||
+
|
||||
+ /**
|
||||
* Resolves the sort role of the next item in m_pendingSortRole, applies it
|
||||
* to the model, and invokes itself if there are any pending items left. If
|
||||
* that is not the case, \a startUpdating() is called.
|
||||
@@ -331,6 +338,8 @@ private:
|
||||
|
||||
KDirectoryContentsCounter* m_directoryContentsCounter;
|
||||
|
||||
+ QList<KOverlayIconPlugin*> m_overlayIconsPlugin;
|
||||
+
|
||||
#ifdef HAVE_BALOO
|
||||
Baloo::FileMonitor* m_balooFileMonitor;
|
||||
#endif
|
||||
diff --git a/lib/konq/CMakeLists.txt b/lib/konq/CMakeLists.txt
|
||||
index 8ecbfa9..7381caf 100644
|
||||
--- a/lib/konq/CMakeLists.txt
|
||||
+++ b/lib/konq/CMakeLists.txt
|
||||
@@ -22,6 +22,7 @@ set(konq_LIB_SRCS
|
||||
konq_historyprovider.cpp
|
||||
kversioncontrolplugin.cpp # used by dolphin and its version control plugins (deprecated)
|
||||
kversioncontrolplugin2.cpp # used by dolphin and its version control plugins
|
||||
+ koverlayiconplugin.cpp
|
||||
|
||||
konq_nameandurlinputdialog.cpp # deprecated (functionality has moved to kdelibs)
|
||||
knewmenu.cpp # deprecated (functionality has moved to kdelibs)
|
||||
@@ -67,8 +68,9 @@ install( FILES
|
||||
konq_fileitemcapabilities.h
|
||||
kversioncontrolplugin.h
|
||||
kversioncontrolplugin2.h
|
||||
+ koverlayiconplugin.h
|
||||
konq_historyprovider.h
|
||||
konq_historyentry.h
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR} COMPONENT Devel
|
||||
)
|
||||
-install( FILES konqpopupmenuplugin.desktop konqdndpopupmenuplugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} )
|
||||
+install( FILES konqpopupmenuplugin.desktop konqdndpopupmenuplugin.desktop koverlayiconplugin.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR} )
|
||||
diff --git a/lib/konq/koverlayiconplugin.cpp b/lib/konq/koverlayiconplugin.cpp
|
||||
new file mode 100644
|
||||
index 0000000..6125040
|
||||
--- /dev/null
|
||||
+++ b/lib/konq/koverlayiconplugin.cpp
|
||||
@@ -0,0 +1,30 @@
|
||||
+/*****************************************************************************
|
||||
+ * Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com> *
|
||||
+ * *
|
||||
+ * This library is free software; you can redistribute it and/or *
|
||||
+ * modify it under the terms of the GNU Library General Public *
|
||||
+ * License version 2 as published by the Free Software Foundation. *
|
||||
+ * *
|
||||
+ * This library 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 *
|
||||
+ * Library General Public License for more details. *
|
||||
+ * *
|
||||
+ * You should have received a copy of the GNU Library General Public License *
|
||||
+ * along with this library; see the file COPYING.LIB. If not, write to *
|
||||
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
||||
+ * Boston, MA 02110-1301, USA. *
|
||||
+ *****************************************************************************/
|
||||
+
|
||||
+#include "koverlayiconplugin.h"
|
||||
+#include <KFileItem>
|
||||
+
|
||||
+KOverlayIconPlugin::KOverlayIconPlugin(QObject* parent) : QObject(parent)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+KOverlayIconPlugin::~KOverlayIconPlugin()
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+#include "koverlayiconplugin.moc"
|
||||
diff --git a/lib/konq/koverlayiconplugin.desktop b/lib/konq/koverlayiconplugin.desktop
|
||||
new file mode 100644
|
||||
index 0000000..65a1170
|
||||
--- /dev/null
|
||||
+++ b/lib/konq/koverlayiconplugin.desktop
|
||||
@@ -0,0 +1,4 @@
|
||||
+[Desktop Entry]
|
||||
+Type=ServiceType
|
||||
+X-KDE-ServiceType=KOverlayIconPlugin
|
||||
+Comment=Plugin to add overlay icons in Dolphin
|
||||
diff --git a/lib/konq/koverlayiconplugin.h b/lib/konq/koverlayiconplugin.h
|
||||
new file mode 100644
|
||||
index 0000000..bcdf31b
|
||||
--- /dev/null
|
||||
+++ b/lib/konq/koverlayiconplugin.h
|
||||
@@ -0,0 +1,57 @@
|
||||
+/*****************************************************************************
|
||||
+ * Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com> *
|
||||
+ * *
|
||||
+ * This library is free software; you can redistribute it and/or *
|
||||
+ * modify it under the terms of the GNU Library General Public *
|
||||
+ * License version 2 as published by the Free Software Foundation. *
|
||||
+ * *
|
||||
+ * This library 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 *
|
||||
+ * Library General Public License for more details. *
|
||||
+ * *
|
||||
+ * You should have received a copy of the GNU Library General Public License *
|
||||
+ * along with this library; see the file COPYING.LIB. If not, write to *
|
||||
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
||||
+ * Boston, MA 02110-1301, USA. *
|
||||
+ *****************************************************************************/
|
||||
+
|
||||
+
|
||||
+#ifndef OverlayIconPlugin_H
|
||||
+#define OverlayIconPlugin_H
|
||||
+
|
||||
+#include <QtCore/QObject>
|
||||
+#include <libkonq_export.h>
|
||||
+
|
||||
+class KUrl;
|
||||
+class KFileItem;
|
||||
+
|
||||
+/**
|
||||
+ * @brief Base class for overlay icon plugins.
|
||||
+ *
|
||||
+ * Enables the file manager to show custom overlay icons on files.
|
||||
+ *
|
||||
+ * To write a custom plugin you need to create a .desktop file for your plugin with
|
||||
+ * KDE-ServiceTypes=KOverlayIconPlugin
|
||||
+ */
|
||||
+class LIBKONQ_EXPORT KOverlayIconPlugin : public QObject {
|
||||
+ Q_OBJECT
|
||||
+ void *d;
|
||||
+public:
|
||||
+ explicit KOverlayIconPlugin(QObject *parent = 0);
|
||||
+ ~KOverlayIconPlugin();
|
||||
+
|
||||
+ /**
|
||||
+ * Returns a list of overlay pixmap to add to a file
|
||||
+ * This can be a path to an icon, or the icon name
|
||||
+ */
|
||||
+ virtual QStringList getOverlays(const KFileItem &item) = 0;
|
||||
+signals:
|
||||
+
|
||||
+ /**
|
||||
+ * Emit this signal when the list of overlay icon changed for a given URL
|
||||
+ */
|
||||
+ void overlaysChanged(const KUrl &url, const QStringList &overlays);
|
||||
+};
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
2.1.3
|
||||
|
||||
@@ -1,46 +1,17 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
project(dolphin-owncloud)
|
||||
find_package(KDE4 REQUIRED)
|
||||
include(KDE4Defaults)
|
||||
include(MacroLibrary)
|
||||
find_package(LibKonq REQUIRED)
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
include(FeatureSummary)
|
||||
set(QT_MIN_VERSION "5.3.0")
|
||||
set(KF5_MIN_VERSION "5.16.0")
|
||||
|
||||
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Network)
|
||||
|
||||
find_package(ECM 1.2.0 REQUIRED CONFIG)
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS CoreAddons KIO)
|
||||
|
||||
set_package_properties(DolphinVcs PROPERTIES
|
||||
DESCRIPTION "the Dolphin plugin library"
|
||||
URL "http://dolphin.kde.org/"
|
||||
TYPE REQUIRED
|
||||
PURPOSE "Provides plugin interfaces for Dolphin."
|
||||
)
|
||||
|
||||
include(KDEInstallDirs)
|
||||
include(KDECMakeSettings)
|
||||
include(KDECompilerSettings)
|
||||
include(ECMMarkNonGuiExecutable)
|
||||
include(GenerateExportHeader)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
|
||||
add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS)
|
||||
include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} )
|
||||
include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${LIBKONQ_INCLUDE_DIR} )
|
||||
|
||||
#---HELPER---
|
||||
add_library(ownclouddolphinpluginhelper SHARED ownclouddolphinpluginhelper.cpp)
|
||||
target_link_libraries(ownclouddolphinpluginhelper Qt5::Network)
|
||||
generate_export_header(ownclouddolphinpluginhelper)
|
||||
install(TARGETS ownclouddolphinpluginhelper LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
kde4_add_plugin(ownclouddolphinplugin ownclouddolphinplugin.cpp)
|
||||
|
||||
#---OVERLAY PLUGIN---
|
||||
kcoreaddons_add_plugin(ownclouddolphinoverlayplugin INSTALL_NAMESPACE "kf5/overlayicon"
|
||||
JSON ownclouddolphinoverlayplugin.json SOURCES ownclouddolphinoverlayplugin.cpp)
|
||||
target_link_libraries(ownclouddolphinoverlayplugin KF5::CoreAddons KF5::KIOCore KF5::KIOWidgets ownclouddolphinpluginhelper)
|
||||
|
||||
#---ACTION PLUGIN---
|
||||
add_library(ownclouddolphinactionplugin MODULE ownclouddolphinactionplugin.cpp)
|
||||
target_link_libraries(ownclouddolphinactionplugin KF5::CoreAddons KF5::KIOCore KF5::KIOWidgets ownclouddolphinpluginhelper)
|
||||
install(FILES ownclouddolphinactionplugin.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
|
||||
install(TARGETS ownclouddolphinactionplugin DESTINATION ${KDE_INSTALL_PLUGINDIR})
|
||||
target_link_libraries(ownclouddolphinplugin ${KDE4_KIO_LIBS} ${LIBKONQ_LIBRARY})
|
||||
install(FILES ownclouddolphinplugin.desktop DESTINATION ${SERVICES_INSTALL_DIR})
|
||||
install(TARGETS ownclouddolphinplugin DESTINATION ${PLUGIN_INSTALL_DIR})
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
- Recompile and install recent enough version of dolphin and kio (git from oct 2015)
|
||||
|
||||
|
||||
- The patch 0001-KOverlayIconPlugin.patch should be applied to kde-baseapps git repository
|
||||
(It should apply to both KDE/4.14 or Applications/14.12 branches)
|
||||
|
||||
- Recompile and install dolphin
|
||||
|
||||
- Build and install the plugin
|
||||
|
||||
- Make sure to set XDG_DATA_DIRS=$PREFIX/share, QT_PLUGIN_PATH=$PREFIX/lib64/plugins/
|
||||
|
||||
- After installing, run
|
||||
kdeinit5 --noincremental
|
||||
kdeinit4 --noincremental
|
||||
|
||||
- To test that the plugin is well installed
|
||||
ktraderclient --servicetype KOverlayIconPlugin
|
||||
It should show the Owncloud plugin
|
||||
|
||||
- restart dolphin (make sure to kill all instances)
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.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. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
******************************************************************************/
|
||||
|
||||
#include <KPluginFactory>
|
||||
#include <KPluginLoader>
|
||||
#include <KIOWidgets/kabstractfileitemactionplugin.h>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <KIOCore/kfileitem.h>
|
||||
#include <KIOCore/KFileItemListProperties>
|
||||
#include <QtWidgets/QAction>
|
||||
#include <QtCore/QTimer>
|
||||
#include "ownclouddolphinpluginhelper.h"
|
||||
|
||||
class OwncloudDolphinPluginAction : public KAbstractFileItemActionPlugin
|
||||
{
|
||||
public:
|
||||
explicit OwncloudDolphinPluginAction(QObject* parent, const QList<QVariant>&)
|
||||
: KAbstractFileItemActionPlugin(parent) { }
|
||||
|
||||
QList<QAction*> actions(const KFileItemListProperties& fileItemInfos, QWidget* parentWidget) Q_DECL_OVERRIDE
|
||||
{
|
||||
auto helper = OwncloudDolphinPluginHelper::instance();
|
||||
QList<QUrl> urls = fileItemInfos.urlList();
|
||||
if (urls.count() != 1 || !helper->isConnected())
|
||||
return {};
|
||||
|
||||
auto url = urls.first();
|
||||
if (!url.isLocalFile())
|
||||
return {};
|
||||
auto localFile = url.toLocalFile();
|
||||
|
||||
const auto paths = helper->paths();
|
||||
if (!std::any_of(paths.begin(), paths.end(), [&](const QString &s) {
|
||||
return localFile.startsWith(s);
|
||||
} ))
|
||||
return {};
|
||||
|
||||
auto act = new QAction(parentWidget);
|
||||
act->setText(helper->shareActionString());
|
||||
connect(act, &QAction::triggered, this, [localFile, helper] {
|
||||
helper->sendCommand("SHARE:"+localFile.toUtf8()+"\n");
|
||||
} );
|
||||
return { act };
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
K_PLUGIN_FACTORY(OwncloudDolphinPluginActionFactory, registerPlugin<OwncloudDolphinPluginAction>();)
|
||||
K_EXPORT_PLUGIN(OwncloudDolphinPluginActionFactory("ownclouddolhpinpluginaction"))
|
||||
|
||||
#include "ownclouddolphinactionplugin.moc"
|
||||
@@ -1,6 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
Name=OwncloudAction
|
||||
ServiceTypes=KFileItemAction/Plugin
|
||||
MimeType=application/octet-stream;inode/directory;
|
||||
X-KDE-Library=ownclouddolphinactionplugin
|
||||
@@ -1,101 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.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. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
******************************************************************************/
|
||||
|
||||
#include <KOverlayIconPlugin>
|
||||
#include <KPluginFactory>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <KIOCore/kfileitem.h>
|
||||
#include <QTimer>
|
||||
#include "ownclouddolphinpluginhelper.h"
|
||||
|
||||
class OwncloudDolphinPlugin : public KOverlayIconPlugin
|
||||
{
|
||||
Q_PLUGIN_METADATA(IID "com.owncloud.ovarlayiconplugin" FILE "ownclouddolphinoverlayplugin.json");
|
||||
Q_OBJECT
|
||||
|
||||
typedef QHash<QByteArray, QByteArray> StatusMap;
|
||||
StatusMap m_status;
|
||||
|
||||
public:
|
||||
|
||||
OwncloudDolphinPlugin() {
|
||||
auto helper = OwncloudDolphinPluginHelper::instance();
|
||||
QObject::connect(helper, &OwncloudDolphinPluginHelper::commandRecieved,
|
||||
this, &OwncloudDolphinPlugin::slotCommandRecieved);
|
||||
}
|
||||
|
||||
QStringList getOverlays(const QUrl& url) override {
|
||||
auto helper = OwncloudDolphinPluginHelper::instance();
|
||||
if (!helper->isConnected())
|
||||
return QStringList();
|
||||
if (!url.isLocalFile())
|
||||
return QStringList();
|
||||
const QByteArray localFile = url.toLocalFile().toUtf8();
|
||||
|
||||
helper->sendCommand("RETRIEVE_FILE_STATUS:" + localFile + "\n");
|
||||
|
||||
StatusMap::iterator it = m_status.find(localFile);
|
||||
if (it != m_status.constEnd()) {
|
||||
return overlaysForString(*it);
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
private:
|
||||
QStringList overlaysForString(const QByteArray &status) {
|
||||
QStringList r;
|
||||
if (status.startsWith("NOP"))
|
||||
return r;
|
||||
|
||||
if (status.startsWith("OK"))
|
||||
r << "ownCloud_ok";
|
||||
if (status.startsWith("SYNC") || status.startsWith("NEW"))
|
||||
r << "owncloud_sync";
|
||||
if (status.startsWith("IGNORE") || status.startsWith("WARN"))
|
||||
r << "owncloud_warn";
|
||||
if (status.startsWith("ERROR"))
|
||||
r << "owncloud_error";
|
||||
|
||||
if (status.contains("+SWM"))
|
||||
r << "document-share";
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void slotCommandRecieved(const QByteArray &line) {
|
||||
|
||||
QList<QByteArray> tokens = line.split(':');
|
||||
if (tokens.count() != 3)
|
||||
return;
|
||||
if (tokens[0] != "STATUS" && tokens[0] != "BROADCAST")
|
||||
return;
|
||||
if (tokens[2].isEmpty())
|
||||
return;
|
||||
|
||||
const QByteArray name = tokens[2];
|
||||
QByteArray &status = m_status[name]; // reference to the item in the hash
|
||||
if (status == tokens[1])
|
||||
return;
|
||||
status = tokens[1];
|
||||
|
||||
emit overlaysChanged(QUrl::fromLocalFile(QString::fromUtf8(name)), overlaysForString(status));
|
||||
}
|
||||
};
|
||||
|
||||
#include "ownclouddolphinoverlayplugin.moc"
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"KPlugin": {
|
||||
"Description": "Overlay icon for owncloud",
|
||||
"ServiceTypes": [
|
||||
"KOverlayIconPlugin"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.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. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
******************************************************************************/
|
||||
|
||||
#include <koverlayiconplugin.h>
|
||||
#include <KPluginFactory>
|
||||
#include <KPluginLoader>
|
||||
#include <kdebug.h>
|
||||
#include <kfileitem.h>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
|
||||
|
||||
class OwncloudDolphinPlugin : public KOverlayIconPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
QLocalSocket m_socket;
|
||||
typedef QHash<QByteArray, QByteArray> StatusMap;
|
||||
StatusMap m_status;
|
||||
QByteArray m_line;
|
||||
|
||||
public:
|
||||
explicit OwncloudDolphinPlugin(QObject* parent, const QList<QVariant>&) : KOverlayIconPlugin(parent) {
|
||||
connect(&m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
||||
tryConnect();
|
||||
}
|
||||
|
||||
virtual QStringList getOverlays(const KFileItem& item) {
|
||||
KUrl url = item.url();
|
||||
if (!url.isLocalFile())
|
||||
return QStringList();
|
||||
const QByteArray localFile = url.toLocalFile().toUtf8();
|
||||
kDebug() << localFile;
|
||||
|
||||
tryConnect();
|
||||
if (m_socket.state() == QLocalSocket::ConnectingState) {
|
||||
if (!m_socket.waitForConnected(100)) {
|
||||
kWarning() << "not connected" << m_socket.errorString();
|
||||
}
|
||||
}
|
||||
if (m_socket.state() == QLocalSocket::ConnectedState) {
|
||||
m_socket.write("RETRIEVE_FILE_STATUS:");
|
||||
m_socket.write(localFile);
|
||||
m_socket.write("\n");
|
||||
}
|
||||
|
||||
StatusMap::iterator it = m_status.find(localFile);
|
||||
if (it != m_status.constEnd()) {
|
||||
return overlaysForString(*it);
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void tryConnect() {
|
||||
if (m_socket.state() != QLocalSocket::UnconnectedState)
|
||||
return;
|
||||
QString runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
|
||||
QString socketPath = runtimeDir + "/" + "ownCloud" + "/socket";
|
||||
m_socket.connectToServer(socketPath);
|
||||
}
|
||||
|
||||
QStringList overlaysForString(const QByteArray status) {
|
||||
QStringList r;
|
||||
if (status.startsWith("NOP"))
|
||||
return r;
|
||||
|
||||
if (status.startsWith("OK"))
|
||||
r << "dialog-ok";
|
||||
if (status.startsWith("SYNC") || status.startsWith("NEW"))
|
||||
r << "view-refresh";
|
||||
|
||||
if (status.contains("+SWM"))
|
||||
r << "document-share";
|
||||
|
||||
kDebug() << status << r;
|
||||
return r;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void readyRead() {
|
||||
while (m_socket.bytesAvailable()) {
|
||||
m_line += m_socket.readLine();
|
||||
if (!m_line.endsWith("\n"))
|
||||
continue;
|
||||
QByteArray line;
|
||||
qSwap(line, m_line);
|
||||
line.chop(1);
|
||||
kDebug() << "got line " << line;
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
QList<QByteArray> tokens = line.split(':');
|
||||
if (tokens.count() != 3)
|
||||
continue;
|
||||
if (tokens[0] != "STATUS" && tokens[0] != "BROADCAST")
|
||||
continue;
|
||||
if (tokens[2].isEmpty())
|
||||
continue;
|
||||
|
||||
const QByteArray name = tokens[2];
|
||||
QByteArray &status = m_status[name]; // reference to the item in the hash
|
||||
if (status == tokens[1])
|
||||
continue;
|
||||
status = tokens[1];
|
||||
|
||||
emit this->overlaysChanged(KUrl::fromLocalFile(QString::fromUtf8(name)), overlaysForString(status));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
K_PLUGIN_FACTORY(OwncloudDolphinPluginFactory, registerPlugin<OwncloudDolphinPlugin>();)
|
||||
K_EXPORT_PLUGIN(OwncloudDolphinPluginFactory("ownclouddolhpinplugin"))
|
||||
|
||||
|
||||
#include "ownclouddolphinplugin.moc"
|
||||
@@ -0,0 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
Name=Owncloud
|
||||
X-KDE-ServiceTypes=KOverlayIconPlugin
|
||||
MimeType=text/plain;
|
||||
X-KDE-Library=ownclouddolphinplugin
|
||||
@@ -1,98 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.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. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
******************************************************************************/
|
||||
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
#include <qcoreevent.h>
|
||||
#include <QFile>
|
||||
#include "ownclouddolphinpluginhelper.h"
|
||||
|
||||
OwncloudDolphinPluginHelper* OwncloudDolphinPluginHelper::instance()
|
||||
{
|
||||
static OwncloudDolphinPluginHelper self;
|
||||
return &self;
|
||||
}
|
||||
|
||||
OwncloudDolphinPluginHelper::OwncloudDolphinPluginHelper()
|
||||
{
|
||||
connect(&_socket, &QLocalSocket::connected, this, &OwncloudDolphinPluginHelper::slotConnected);
|
||||
connect(&_socket, &QLocalSocket::readyRead, this, &OwncloudDolphinPluginHelper::slotReadyRead);
|
||||
_connectTimer.start(45 * 1000, Qt::VeryCoarseTimer, this);
|
||||
tryConnect();
|
||||
}
|
||||
|
||||
void OwncloudDolphinPluginHelper::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if (e->timerId() == _connectTimer.timerId()) {
|
||||
tryConnect();
|
||||
return;
|
||||
}
|
||||
QObject::timerEvent(e);
|
||||
}
|
||||
|
||||
bool OwncloudDolphinPluginHelper::isConnected() const
|
||||
{
|
||||
return _socket.state() == QLocalSocket::ConnectedState;
|
||||
}
|
||||
|
||||
void OwncloudDolphinPluginHelper::sendCommand(const char* data)
|
||||
{
|
||||
_socket.write(data);
|
||||
_socket.flush();
|
||||
}
|
||||
|
||||
void OwncloudDolphinPluginHelper::slotConnected()
|
||||
{
|
||||
sendCommand("SHARE_MENU_TITLE:\n");
|
||||
}
|
||||
|
||||
void OwncloudDolphinPluginHelper::tryConnect()
|
||||
{
|
||||
if (_socket.state() != QLocalSocket::UnconnectedState) {
|
||||
return;
|
||||
}
|
||||
QString runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
|
||||
QString socketPath = runtimeDir + QLatin1String("/ownCloud/socket");
|
||||
_socket.connectToServer(socketPath);
|
||||
}
|
||||
|
||||
void OwncloudDolphinPluginHelper::slotReadyRead()
|
||||
{
|
||||
while (_socket.bytesAvailable()) {
|
||||
_line += _socket.readLine();
|
||||
if (!_line.endsWith("\n"))
|
||||
continue;
|
||||
QByteArray line;
|
||||
qSwap(line, _line);
|
||||
line.chop(1);
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
|
||||
if (line.startsWith("REGISTER_PATH:")) {
|
||||
auto col = line.indexOf(':');
|
||||
QString file = QString::fromUtf8(line.constData() + col + 1, line.size() - col - 1);
|
||||
_paths.append(file);
|
||||
continue;
|
||||
} else if (line.startsWith("SHARE_MENU_TITLE:")) {
|
||||
auto col = line.indexOf(':');
|
||||
_shareActionString = QString::fromUtf8(line.constData() + col + 1, line.size() - col - 1);
|
||||
continue;
|
||||
}
|
||||
emit commandRecieved(line);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.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. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <QObject>
|
||||
#include <QBasicTimer>
|
||||
#include <QLocalSocket>
|
||||
#include "ownclouddolphinpluginhelper_export.h"
|
||||
|
||||
class OWNCLOUDDOLPHINPLUGINHELPER_EXPORT OwncloudDolphinPluginHelper : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static OwncloudDolphinPluginHelper *instance();
|
||||
|
||||
QString shareActionString() const { return _shareActionString; }
|
||||
bool isConnected() const;
|
||||
void sendCommand(const char *data);
|
||||
QVector<QString> paths() const { return _paths; }
|
||||
|
||||
signals:
|
||||
void commandRecieved(const QByteArray &cmd);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent*) override;
|
||||
|
||||
private:
|
||||
OwncloudDolphinPluginHelper();
|
||||
void slotConnected();
|
||||
void slotReadyRead();
|
||||
void tryConnect();
|
||||
QLocalSocket _socket;
|
||||
QByteArray _line;
|
||||
QVector<QString> _paths;
|
||||
QString _shareActionString;
|
||||
QBasicTimer _connectTimer;
|
||||
};
|
||||
@@ -0,0 +1,267 @@
|
||||
From d452ed613a9e02ed81eec2f3226f28babff240c8 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Goffart <ogoffart@woboq.com>
|
||||
Date: Thu, 17 Jul 2014 13:26:56 +0200
|
||||
Subject: [PATCH] WIP: add KOverlayIconPlugin
|
||||
|
||||
Conflicts:
|
||||
dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
|
||||
lib/konq/CMakeLists.txt
|
||||
---
|
||||
.../src/kitemviews/kfileitemmodelrolesupdater.cpp | 38 ++++++++++++++-
|
||||
.../src/kitemviews/kfileitemmodelrolesupdater.h | 9 ++++
|
||||
lib/konq/src/CMakeLists.txt | 4 +-
|
||||
lib/konq/src/koverlayiconplugin.cpp | 30 ++++++++++++
|
||||
lib/konq/src/koverlayiconplugin.desktop | 4 ++
|
||||
lib/konq/src/koverlayiconplugin.h | 57 ++++++++++++++++++++++
|
||||
6 files changed, 140 insertions(+), 2 deletions(-)
|
||||
create mode 100644 lib/konq/src/koverlayiconplugin.cpp
|
||||
create mode 100644 lib/konq/src/koverlayiconplugin.desktop
|
||||
create mode 100644 lib/konq/src/koverlayiconplugin.h
|
||||
|
||||
diff --git a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
|
||||
index df521e2..4d94836 100644
|
||||
--- a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
|
||||
+++ b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.cpp
|
||||
@@ -29,9 +29,11 @@
|
||||
#include <KJobWidgets>
|
||||
#include <KIO/JobUiDelegate>
|
||||
#include <KIO/PreviewJob>
|
||||
+#include <KServiceTypeTrader>
|
||||
|
||||
#include "private/kpixmapmodifier.h"
|
||||
#include "private/kdirectorycontentscounter.h"
|
||||
+#include <koverlayiconplugin.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
@@ -129,6 +131,20 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO
|
||||
m_directoryContentsCounter = new KDirectoryContentsCounter(m_model, this);
|
||||
connect(m_directoryContentsCounter, &KDirectoryContentsCounter::result,
|
||||
this, &KFileItemModelRolesUpdater::slotDirectoryContentsCountReceived);
|
||||
+
|
||||
+
|
||||
+ const KService::List pluginServices = KServiceTypeTrader::self()->query("KOverlayIconPlugin");
|
||||
+
|
||||
+ for (KService::List::ConstIterator it = pluginServices.constBegin(); it != pluginServices.constEnd(); ++it) {
|
||||
+ QString error;
|
||||
+ KOverlayIconPlugin* plugin = (*it)->createInstance<KOverlayIconPlugin>(this, QVariantList(), &error);
|
||||
+ if (plugin) {
|
||||
+ m_overlayIconsPlugin.append(plugin);
|
||||
+ connect(plugin, &KOverlayIconPlugin::overlaysChanged, this, &KFileItemModelRolesUpdater::slotOverlaysChanged);
|
||||
+ } else {
|
||||
+ qWarning() << "Could not load plugin " << (*it)->name() << ":" << error;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
|
||||
@@ -1065,7 +1081,11 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
|
||||
data.insert("type", item.mimeComment());
|
||||
}
|
||||
|
||||
- data.insert("iconOverlays", item.overlays());
|
||||
+ QStringList overlays = item.overlays();
|
||||
+ foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
|
||||
+ overlays.append(it->getOverlays(item));
|
||||
+ }
|
||||
+ data.insert("iconOverlays", overlays);
|
||||
|
||||
#ifdef HAVE_BALOO
|
||||
if (m_balooFileMonitor) {
|
||||
@@ -1076,6 +1096,22 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
|
||||
return data;
|
||||
}
|
||||
|
||||
+void KFileItemModelRolesUpdater::slotOverlaysChanged(const QUrl& url, const QStringList &)
|
||||
+{
|
||||
+ KFileItem item = m_model->fileItem(url);
|
||||
+ if (item.isNull())
|
||||
+ return;
|
||||
+ int index = m_model->index(item);
|
||||
+ QHash <QByteArray, QVariant> data = m_model->data(index);
|
||||
+ QStringList overlays = item.overlays();
|
||||
+ foreach(KOverlayIconPlugin *it, m_overlayIconsPlugin) {
|
||||
+ overlays.append(it->getOverlays(item));
|
||||
+ }
|
||||
+ data.insert("iconOverlays", overlays);
|
||||
+ m_model->setData(index, data);
|
||||
+}
|
||||
+
|
||||
+
|
||||
void KFileItemModelRolesUpdater::updateAllPreviews()
|
||||
{
|
||||
if (m_state == Paused) {
|
||||
diff --git a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
|
||||
index 6c82dbe..1e5b98e 100644
|
||||
--- a/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
|
||||
+++ b/dolphin/src/kitemviews/kfileitemmodelrolesupdater.h
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <QSize>
|
||||
#include <QStringList>
|
||||
|
||||
+class KOverlayIconPlugin;
|
||||
class KDirectoryContentsCounter;
|
||||
class KFileItemModel;
|
||||
class QPixmap;
|
||||
@@ -183,6 +184,12 @@ private slots:
|
||||
void slotPreviewJobFinished();
|
||||
|
||||
/**
|
||||
+ * Is invoked when one of the KOverlayIconPlugin emit the signal that an overlay has changed
|
||||
+ */
|
||||
+ void slotOverlaysChanged(const QUrl& url, const QStringList&);
|
||||
+
|
||||
+
|
||||
+ /**
|
||||
* Resolves the sort role of the next item in m_pendingSortRole, applies it
|
||||
* to the model, and invokes itself if there are any pending items left. If
|
||||
* that is not the case, \a startUpdating() is called.
|
||||
@@ -333,6 +340,8 @@ private:
|
||||
|
||||
KDirectoryContentsCounter* m_directoryContentsCounter;
|
||||
|
||||
+ QList<KOverlayIconPlugin*> m_overlayIconsPlugin;
|
||||
+
|
||||
#ifdef HAVE_BALOO
|
||||
Baloo::FileMonitor* m_balooFileMonitor;
|
||||
#endif
|
||||
diff --git a/lib/konq/src/CMakeLists.txt b/lib/konq/src/CMakeLists.txt
|
||||
index 9c05b9f..0ac0526 100644
|
||||
--- a/lib/konq/src/CMakeLists.txt
|
||||
+++ b/lib/konq/src/CMakeLists.txt
|
||||
@@ -15,6 +15,7 @@ set(konq_LIB_SRCS
|
||||
konq_historyprovider.cpp # konqueror and konqueror/sidebar
|
||||
kversioncontrolplugin.cpp # used by dolphin and its version control plugins (deprecated)
|
||||
kversioncontrolplugin2.cpp # used by dolphin and its version control plugins
|
||||
+ koverlayiconplugin.cpp
|
||||
)
|
||||
|
||||
add_library(KF5Konq ${konq_LIB_SRCS})
|
||||
@@ -64,13 +65,14 @@ install(FILES
|
||||
konq_popupmenuplugin.h
|
||||
kversioncontrolplugin.h
|
||||
kversioncontrolplugin2.h
|
||||
+ koverlayiconplugin.h
|
||||
${LibKonq_BINARY_DIR}/src/libkonq_export.h
|
||||
|
||||
DESTINATION ${KF5_INCLUDE_INSTALL_DIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
-install(FILES konqpopupmenuplugin.desktop konqdndpopupmenuplugin.desktop
|
||||
+install(FILES konqpopupmenuplugin.desktop konqdndpopupmenuplugin.desktop koverlayiconplugin.desktop
|
||||
DESTINATION ${SERVICETYPES_INSTALL_DIR}
|
||||
)
|
||||
|
||||
diff --git a/lib/konq/src/koverlayiconplugin.cpp b/lib/konq/src/koverlayiconplugin.cpp
|
||||
new file mode 100644
|
||||
index 0000000..6125040
|
||||
--- /dev/null
|
||||
+++ b/lib/konq/src/koverlayiconplugin.cpp
|
||||
@@ -0,0 +1,30 @@
|
||||
+/*****************************************************************************
|
||||
+ * Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com> *
|
||||
+ * *
|
||||
+ * This library is free software; you can redistribute it and/or *
|
||||
+ * modify it under the terms of the GNU Library General Public *
|
||||
+ * License version 2 as published by the Free Software Foundation. *
|
||||
+ * *
|
||||
+ * This library 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 *
|
||||
+ * Library General Public License for more details. *
|
||||
+ * *
|
||||
+ * You should have received a copy of the GNU Library General Public License *
|
||||
+ * along with this library; see the file COPYING.LIB. If not, write to *
|
||||
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
||||
+ * Boston, MA 02110-1301, USA. *
|
||||
+ *****************************************************************************/
|
||||
+
|
||||
+#include "koverlayiconplugin.h"
|
||||
+#include <KFileItem>
|
||||
+
|
||||
+KOverlayIconPlugin::KOverlayIconPlugin(QObject* parent) : QObject(parent)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+KOverlayIconPlugin::~KOverlayIconPlugin()
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+#include "koverlayiconplugin.moc"
|
||||
diff --git a/lib/konq/src/koverlayiconplugin.desktop b/lib/konq/src/koverlayiconplugin.desktop
|
||||
new file mode 100644
|
||||
index 0000000..65a1170
|
||||
--- /dev/null
|
||||
+++ b/lib/konq/src/koverlayiconplugin.desktop
|
||||
@@ -0,0 +1,4 @@
|
||||
+[Desktop Entry]
|
||||
+Type=ServiceType
|
||||
+X-KDE-ServiceType=KOverlayIconPlugin
|
||||
+Comment=Plugin to add overlay icons in Dolphin
|
||||
diff --git a/lib/konq/src/koverlayiconplugin.h b/lib/konq/src/koverlayiconplugin.h
|
||||
new file mode 100644
|
||||
index 0000000..bfdaa2f
|
||||
--- /dev/null
|
||||
+++ b/lib/konq/src/koverlayiconplugin.h
|
||||
@@ -0,0 +1,57 @@
|
||||
+/*****************************************************************************
|
||||
+ * Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.com> *
|
||||
+ * *
|
||||
+ * This library is free software; you can redistribute it and/or *
|
||||
+ * modify it under the terms of the GNU Library General Public *
|
||||
+ * License version 2 as published by the Free Software Foundation. *
|
||||
+ * *
|
||||
+ * This library 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 *
|
||||
+ * Library General Public License for more details. *
|
||||
+ * *
|
||||
+ * You should have received a copy of the GNU Library General Public License *
|
||||
+ * along with this library; see the file COPYING.LIB. If not, write to *
|
||||
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
||||
+ * Boston, MA 02110-1301, USA. *
|
||||
+ *****************************************************************************/
|
||||
+
|
||||
+
|
||||
+#ifndef OverlayIconPlugin_H
|
||||
+#define OverlayIconPlugin_H
|
||||
+
|
||||
+#include <QtCore/QObject>
|
||||
+#include <libkonq_export.h>
|
||||
+
|
||||
+class KUrl;
|
||||
+class KFileItem;
|
||||
+
|
||||
+/**
|
||||
+ * @brief Base class for overlay icon plugins.
|
||||
+ *
|
||||
+ * Enables the file manager to show custom overlay icons on files.
|
||||
+ *
|
||||
+ * To write a custom plugin you need to create a .desktop file for your plugin with
|
||||
+ * KDE-ServiceTypes=KOverlayIconPlugin
|
||||
+ */
|
||||
+class LIBKONQ_EXPORT KOverlayIconPlugin : public QObject {
|
||||
+ Q_OBJECT
|
||||
+ void *d;
|
||||
+public:
|
||||
+ explicit KOverlayIconPlugin(QObject *parent = 0);
|
||||
+ ~KOverlayIconPlugin();
|
||||
+
|
||||
+ /**
|
||||
+ * Returns a list of overlay pixmap to add to a file
|
||||
+ * This can be a path to an icon, or the icon name
|
||||
+ */
|
||||
+ virtual QStringList getOverlays(const KFileItem &item) = 0;
|
||||
+signals:
|
||||
+
|
||||
+ /**
|
||||
+ * Emit this signal when the list of overlay icon changed for a given URL
|
||||
+ */
|
||||
+ void overlaysChanged(const QUrl &url, const QStringList &overlays);
|
||||
+};
|
||||
+
|
||||
+#endif
|
||||
--
|
||||
2.2.1
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
project(dolphin-owncloud)
|
||||
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
set(QT_MIN_VERSION "5.3.0")
|
||||
|
||||
find_package(ECM 1.2.0 REQUIRED CONFIG)
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
|
||||
|
||||
include(KDEInstallDirs)
|
||||
include(KDECMakeSettings)
|
||||
include(KDECompilerSettings)
|
||||
include(ECMInstallIcons)
|
||||
include(ECMSetupVersion)
|
||||
|
||||
find_package(Qt5 CONFIG REQUIRED Core DBus Test Widgets)
|
||||
find_package(KF5 REQUIRED Archive Bookmarks CoreAddons Config ConfigWidgets DBusAddons KIO KDELibs4Support Parts Activities)
|
||||
|
||||
|
||||
find_package(KF5Konq REQUIRED)
|
||||
|
||||
add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS)
|
||||
|
||||
add_library(ownclouddolphinplugin MODULE ownclouddolphinplugin.cpp)
|
||||
target_link_libraries(ownclouddolphinplugin KF5::Konq)
|
||||
install(FILES ownclouddolphinplugin.desktop DESTINATION ${SERVICES_INSTALL_DIR})
|
||||
install(TARGETS ownclouddolphinplugin DESTINATION ${PLUGIN_INSTALL_DIR})
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
- The patch 0001-KOverlayIconPlugin.patch should be applied to kde-baseapps git repository
|
||||
(It should apply to frameworks branch)
|
||||
|
||||
- Recompile and install dolphin (frameworks branch)
|
||||
|
||||
- Build and install the plugin
|
||||
|
||||
- Make sure to set XDG_DATA_DIRS=$PREFIX/share, QT_PLUGIN_PATH=$PREFIX/lib64/plugins/
|
||||
|
||||
- After installing, run
|
||||
kdeinit5 --noincremental
|
||||
|
||||
- restart dolphin (make sure to kill all instances)
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2014 by Olivier Goffart <ogoffart@woboq.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. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
|
||||
******************************************************************************/
|
||||
|
||||
#include <koverlayiconplugin.h>
|
||||
#include <KPluginFactory>
|
||||
#include <KPluginLoader>
|
||||
#include <kdebug.h>
|
||||
#include <kfileitem.h>
|
||||
#include <QtNetwork/QLocalSocket>
|
||||
|
||||
|
||||
class OwncloudDolphinPlugin : public KOverlayIconPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
QLocalSocket m_socket;
|
||||
typedef QHash<QByteArray, QByteArray> StatusMap;
|
||||
StatusMap m_status;
|
||||
QByteArray m_line;
|
||||
|
||||
public:
|
||||
explicit OwncloudDolphinPlugin(QObject* parent, const QList<QVariant>&) : KOverlayIconPlugin(parent) {
|
||||
connect(&m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
||||
tryConnect();
|
||||
}
|
||||
|
||||
virtual QStringList getOverlays(const KFileItem& item) {
|
||||
auto url = item.url();
|
||||
if (!url.isLocalFile())
|
||||
return QStringList();
|
||||
const QByteArray localFile = url.toLocalFile().toUtf8();
|
||||
kDebug() << localFile;
|
||||
|
||||
tryConnect();
|
||||
if (m_socket.state() == QLocalSocket::ConnectingState) {
|
||||
if (!m_socket.waitForConnected(100)) {
|
||||
kWarning() << "not connected" << m_socket.errorString();
|
||||
}
|
||||
}
|
||||
if (m_socket.state() == QLocalSocket::ConnectedState) {
|
||||
m_socket.write("RETRIEVE_FILE_STATUS:");
|
||||
m_socket.write(localFile);
|
||||
m_socket.write("\n");
|
||||
}
|
||||
|
||||
StatusMap::iterator it = m_status.find(localFile);
|
||||
if (it != m_status.constEnd()) {
|
||||
return overlaysForString(*it);
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void tryConnect() {
|
||||
if (m_socket.state() != QLocalSocket::UnconnectedState)
|
||||
return;
|
||||
QString runtimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
|
||||
QString socketPath = runtimeDir + "/" + "ownCloud" + "/socket";
|
||||
m_socket.connectToServer(socketPath);
|
||||
}
|
||||
|
||||
QStringList overlaysForString(const QByteArray status) {
|
||||
QStringList r;
|
||||
if (status.startsWith("NOP"))
|
||||
return r;
|
||||
|
||||
if (status.startsWith("OK"))
|
||||
r << "dialog-ok";
|
||||
if (status.startsWith("SYNC") || status.startsWith("NEW"))
|
||||
r << "view-refresh";
|
||||
|
||||
if (status.contains("+SWM"))
|
||||
r << "document-share";
|
||||
|
||||
kDebug() << status << r;
|
||||
return r;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void readyRead() {
|
||||
while (m_socket.bytesAvailable()) {
|
||||
m_line += m_socket.readLine();
|
||||
if (!m_line.endsWith("\n"))
|
||||
continue;
|
||||
QByteArray line;
|
||||
qSwap(line, m_line);
|
||||
line.chop(1);
|
||||
kDebug() << "got line " << line;
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
QList<QByteArray> tokens = line.split(':');
|
||||
if (tokens.count() != 3)
|
||||
continue;
|
||||
if (tokens[0] != "STATUS" && tokens[0] != "BROADCAST")
|
||||
continue;
|
||||
if (tokens[2].isEmpty())
|
||||
continue;
|
||||
|
||||
const QByteArray name = tokens[2];
|
||||
QByteArray &status = m_status[name]; // reference to the item in the hash
|
||||
if (status == tokens[1])
|
||||
continue;
|
||||
status = tokens[1];
|
||||
|
||||
emit this->overlaysChanged(QUrl::fromLocalFile(QString::fromUtf8(name)), overlaysForString(status));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
K_PLUGIN_FACTORY(OwncloudDolphinPluginFactory, registerPlugin<OwncloudDolphinPlugin>();)
|
||||
K_EXPORT_PLUGIN(OwncloudDolphinPluginFactory("ownclouddolhpinplugin"))
|
||||
|
||||
|
||||
#include "ownclouddolphinplugin.moc"
|
||||
@@ -0,0 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Service
|
||||
Name=Owncloud
|
||||
X-KDE-ServiceTypes=KOverlayIconPlugin
|
||||
MimeType=text/plain;
|
||||
X-KDE-Library=ownclouddolphinplugin
|
||||
@@ -10,7 +10,6 @@ if (APPLE)
|
||||
endif()
|
||||
|
||||
add_subdirectory(libsync)
|
||||
add_subdirectory(libclient)
|
||||
if (NOT BUILD_LIBRARIES_ONLY)
|
||||
add_subdirectory(gui)
|
||||
add_subdirectory(cmd)
|
||||
|
||||
@@ -42,8 +42,6 @@
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#include <csync_private.h>
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
struct CmdOptions {
|
||||
@@ -116,11 +114,11 @@ public:
|
||||
_sslTrusted(false)
|
||||
{}
|
||||
|
||||
void askFromUser() Q_DECL_OVERRIDE {
|
||||
_password = ::queryPassword(user());
|
||||
_ready = true;
|
||||
persist();
|
||||
emit asked();
|
||||
QString queryPassword(bool *ok, const QString&) Q_DECL_OVERRIDE {
|
||||
if (ok) {
|
||||
*ok = true;
|
||||
}
|
||||
return ::queryPassword(user());
|
||||
}
|
||||
|
||||
void setSSLTrusted( bool isTrusted ) {
|
||||
|
||||
@@ -72,6 +72,7 @@ set(client_SRCS
|
||||
creds/httpcredentialsgui.cpp
|
||||
creds/shibbolethcredentials.cpp
|
||||
creds/shibboleth/shibbolethwebview.cpp
|
||||
creds/shibboleth/shibbolethrefresher.cpp
|
||||
creds/shibboleth/shibbolethuserjob.cpp
|
||||
wizard/abstractcredswizardpage.cpp
|
||||
wizard/owncloudadvancedsetuppage.cpp
|
||||
@@ -97,7 +98,6 @@ IF( APPLE )
|
||||
list(APPEND client_SRCS settingsdialogmac.cpp)
|
||||
list(APPEND client_SRCS socketapisocket_mac.mm)
|
||||
list(APPEND client_SRCS systray.mm)
|
||||
list(APPEND client_SRCS clipboard.mm)
|
||||
|
||||
if(SPARKLE_FOUND)
|
||||
# Define this, we need to check in updater.cpp
|
||||
@@ -221,7 +221,7 @@ if(NOT BUILD_OWNCLOUD_OSX_BUNDLE)
|
||||
endforeach( _file )
|
||||
endif(NOT WIN32)
|
||||
|
||||
install(FILES ${client_I18N} DESTINATION ${SHAREDIR}/${APPLICATION_EXECUTABLE}/i18n)
|
||||
install(FILES ${client_I18N} DESTINATION ${DATADIR}/${APPLICATION_EXECUTABLE}/i18n)
|
||||
|
||||
# we may not add MACOSX_BUNDLE here, if not building one
|
||||
|
||||
@@ -292,7 +292,7 @@ install(TARGETS ${APPLICATION_EXECUTABLE}
|
||||
if(BUILD_OWNCLOUD_OSX_BUNDLE AND NOT BUILD_LIBRARIES_ONLY)
|
||||
get_target_property (QT_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
|
||||
install(CODE "
|
||||
message(STATUS \"Deploying (Qt) dependencies and fixing library paths...\")
|
||||
message(STATUS \"Deploying (Qt) dependencies and fixing library pathes...\")
|
||||
execute_process(COMMAND \"${CMAKE_SOURCE_DIR}/admin/osx/macdeployqt.py\" ${CMAKE_INSTALL_PREFIX}/${OWNCLOUD_OSX_BUNDLE} ${QT_QMAKE_EXECUTABLE})
|
||||
" COMPONENT RUNTIME)
|
||||
endif()
|
||||
|
||||
@@ -36,13 +36,13 @@ public:
|
||||
void save(bool saveCredentials = true);
|
||||
|
||||
/**
|
||||
* Creates account objects from a given settings file.
|
||||
* Creates account objects from from a given settings file.
|
||||
* return true if the account was restored
|
||||
*/
|
||||
bool restore();
|
||||
|
||||
/**
|
||||
* Add this account in the list of saved accounts.
|
||||
* Add this account in the list of saved account.
|
||||
* Typically called from the wizard
|
||||
*/
|
||||
AccountState *addAccount(const AccountPtr &newAccount);
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
|
||||
/**
|
||||
* Return a list of all accounts.
|
||||
* (this is a list of QSharedPointer for internal reasons, one should normally not keep a copy of them)
|
||||
* (this is a list of QSharedPointer for internal reason, one should normaly not keep a copy of them)
|
||||
*/
|
||||
QList<AccountStatePtr> accounts() { return _accounts; }
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include <QKeySequence>
|
||||
#include <QIcon>
|
||||
#include <QVariant>
|
||||
#include <QToolTip>
|
||||
#include <qstringlistmodel.h>
|
||||
#include <qpropertyanimation.h>
|
||||
|
||||
@@ -91,8 +90,6 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
|
||||
connect(_model, SIGNAL(suggestExpand(QModelIndex)), ui->_folderList, SLOT(expand(QModelIndex)));
|
||||
connect(_model, SIGNAL(dirtyChanged()), this, SLOT(refreshSelectiveSyncStatus()));
|
||||
refreshSelectiveSyncStatus();
|
||||
connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||
this, SLOT(refreshSelectiveSyncStatus()));
|
||||
|
||||
QAction *resetFolderAction = new QAction(this);
|
||||
resetFolderAction->setShortcut(QKeySequence(Qt::Key_F5));
|
||||
@@ -104,8 +101,7 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
|
||||
connect(syncNowAction, SIGNAL(triggered()), SLOT(slotSyncCurrentFolderNow()));
|
||||
addAction(syncNowAction);
|
||||
|
||||
connect(ui->_folderList, SIGNAL(clicked(const QModelIndex &)),
|
||||
this, SLOT(slotFolderListClicked(const QModelIndex&)));
|
||||
connect(ui->_folderList, SIGNAL(clicked(QModelIndex)), SLOT(slotFolderActivated(QModelIndex)));
|
||||
|
||||
connect(ui->selectiveSyncApply, SIGNAL(clicked()), _model, SLOT(slotApplySelectiveSync()));
|
||||
connect(ui->selectiveSyncCancel, SIGNAL(clicked()), _model, SLOT(resetFolders()));
|
||||
@@ -124,8 +120,12 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
|
||||
connect( &_quotaInfo, SIGNAL(quotaUpdated(qint64,qint64)),
|
||||
this, SLOT(slotUpdateQuota(qint64,qint64)));
|
||||
|
||||
connect(ui->signInButton, SIGNAL(clicked()) , this, SLOT(slotSignInAccount()));
|
||||
connect(ui->deleteButton, SIGNAL(clicked()) , this, SLOT(slotDeleteAccount()));
|
||||
|
||||
// Expand already on single click
|
||||
ui->_folderList->setExpandsOnDoubleClick(false);
|
||||
QObject::connect(ui->_folderList, SIGNAL(clicked(const QModelIndex &)),
|
||||
ui->_folderList, SLOT(expand(const QModelIndex &)));
|
||||
}
|
||||
|
||||
void AccountSettings::doExpand()
|
||||
@@ -148,38 +148,25 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
|
||||
|
||||
tv->setCurrentIndex(index);
|
||||
bool folderPaused = _model->data( index, FolderStatusDelegate::FolderSyncPaused).toBool();
|
||||
bool folderConnected = _model->data( index, FolderStatusDelegate::FolderAccountConnected ).toBool();
|
||||
|
||||
QMenu *menu = new QMenu(tv);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QAction *ac = menu->addAction(tr("Open folder"));
|
||||
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotOpenCurrentFolder()));
|
||||
|
||||
ac = menu->addAction(tr("Choose What to Sync"));
|
||||
ac->setEnabled(folderConnected);
|
||||
connect(ac, SIGNAL(triggered(bool)), this, SLOT(doExpand()));
|
||||
|
||||
ac = menu->addAction(folderPaused ? tr("Resume sync") : tr("Pause sync"));
|
||||
ac->setEnabled(folderConnected);
|
||||
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotEnableCurrentFolder()));
|
||||
|
||||
ac = menu->addAction(tr("Remove sync"));
|
||||
connect(ac, SIGNAL(triggered(bool)), this, SLOT(slotRemoveCurrentFolder()));
|
||||
connect(menu->addAction(tr("Open folder")), SIGNAL(triggered(bool)),
|
||||
this, SLOT(slotOpenCurrentFolder()));
|
||||
connect(menu->addAction(tr("Choose What to Sync")), SIGNAL(triggered(bool)),
|
||||
this, SLOT(doExpand()));
|
||||
connect(menu->addAction(folderPaused ? tr("Resume sync") : tr("Pause sync")), SIGNAL(triggered(bool)),
|
||||
this, SLOT(slotEnableCurrentFolder()));
|
||||
connect(menu->addAction(tr("Remove sync")), SIGNAL(triggered(bool)),
|
||||
this, SLOT(slotRemoveCurrentFolder()));
|
||||
menu->exec(tv->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void AccountSettings::slotFolderListClicked(const QModelIndex& indx)
|
||||
void AccountSettings::slotFolderActivated( const QModelIndex& indx )
|
||||
{
|
||||
if (indx.data(FolderStatusDelegate::AddButton).toBool()) {
|
||||
if (indx.flags() & Qt::ItemIsEnabled) {
|
||||
slotAddFolder();
|
||||
} else {
|
||||
QToolTip::showText(
|
||||
QCursor::pos(),
|
||||
_model->data(indx, Qt::ToolTipRole).toString(),
|
||||
this);
|
||||
}
|
||||
if (indx.data(FolderStatusDelegate::AddButton).toBool()
|
||||
&& indx.flags() & Qt::ItemIsEnabled) {
|
||||
slotAddFolder();
|
||||
return;
|
||||
}
|
||||
if (_model->classify(indx) == FolderStatusModel::RootFolder) {
|
||||
@@ -188,13 +175,6 @@ void AccountSettings::slotFolderListClicked(const QModelIndex& indx)
|
||||
auto pos = tv->mapFromGlobal(QCursor::pos());
|
||||
if (FolderStatusDelegate::optionsButtonRect(tv->visualRect(indx)).contains(pos)) {
|
||||
slotCustomContextMenuRequested(pos);
|
||||
return;
|
||||
}
|
||||
|
||||
// Expand root items on single click
|
||||
if(_accountState && _accountState->state() == AccountState::Connected ) {
|
||||
bool expanded = ! (ui->_folderList->isExpanded(indx));
|
||||
ui->_folderList->setExpanded(indx, expanded);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -476,12 +456,6 @@ void AccountSettings::slotAccountStateChanged(int state)
|
||||
serverWithUser = tr("%1 as <i>%2</i>").arg(server, cred->user());
|
||||
}
|
||||
|
||||
if (state != AccountState::SignedOut && ui->signInButton->hasFocus()) {
|
||||
// The button is about to be hidden, clear the focus so the focus don't go to the
|
||||
// "remove account" button
|
||||
ui->signInButton->clearFocus();
|
||||
}
|
||||
ui->signInButton->setVisible(state == AccountState::SignedOut);
|
||||
if (state == AccountState::Connected) {
|
||||
showConnectionLabel( tr("Connected to %1.").arg(serverWithUser) );
|
||||
} else if (state == AccountState::ServiceUnavailable) {
|
||||
@@ -497,18 +471,6 @@ void AccountSettings::slotAccountStateChanged(int state)
|
||||
// ownCloud is not yet configured.
|
||||
showConnectionLabel( tr("No %1 connection configured.").arg(Theme::instance()->appNameGUI()) );
|
||||
}
|
||||
|
||||
/* Allow to expand the item if the account is connected. */
|
||||
ui->_folderList->setItemsExpandable( state == AccountState::Connected );
|
||||
|
||||
/* check if there are expanded root items, if so, close them, if the state is different from being Connected. */
|
||||
if( state != AccountState::Connected ) {
|
||||
int i;
|
||||
for (i = 0; i < _model->rowCount(); ++i) {
|
||||
if (ui->_folderList->isExpanded(_model->index(i)))
|
||||
ui->_folderList->setExpanded(_model->index(i), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AccountSettings::~AccountSettings()
|
||||
@@ -521,10 +483,8 @@ void AccountSettings::refreshSelectiveSyncStatus()
|
||||
bool shouldBeVisible = _model->isDirty();
|
||||
QStringList undecidedFolder;
|
||||
for (int i = 0; !shouldBeVisible && i < _model->rowCount(); ++i) {
|
||||
auto index = _model->index(i);
|
||||
if (ui->_folderList->isExpanded(index) && _model->rowCount(index) > 0) {
|
||||
if (ui->_folderList->isExpanded(_model->index(i)))
|
||||
shouldBeVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Folder *folder, FolderMan::instance()->map().values()) {
|
||||
@@ -566,11 +526,6 @@ void AccountSettings::refreshSelectiveSyncStatus()
|
||||
}
|
||||
}
|
||||
|
||||
void AccountSettings::slotSignInAccount()
|
||||
{
|
||||
_accountState->setSignedOut(false);
|
||||
}
|
||||
|
||||
void AccountSettings::slotDeleteAccount()
|
||||
{
|
||||
// Deleting the account potentially deletes 'this', so
|
||||
@@ -609,9 +564,6 @@ bool AccountSettings::event(QEvent* e)
|
||||
if (e->type() == QEvent::Hide || e->type() == QEvent::Show) {
|
||||
_quotaInfo.setActive(isVisible());
|
||||
}
|
||||
if (e->type() == QEvent::Show) {
|
||||
ui->_folderList->setExpanded(_model->index(0, 0), true);
|
||||
}
|
||||
return QWidget::event(e);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ signals:
|
||||
void openFolderAlias( const QString& );
|
||||
|
||||
public slots:
|
||||
void slotFolderActivated( const QModelIndex& );
|
||||
void slotOpenOC();
|
||||
void slotUpdateQuota( qint64,qint64 );
|
||||
void slotAccountStateChanged(int state);
|
||||
@@ -76,11 +77,9 @@ protected slots:
|
||||
void slotOpenCurrentFolder();
|
||||
void slotFolderWizardAccepted();
|
||||
void slotFolderWizardRejected();
|
||||
void slotSignInAccount();
|
||||
void slotDeleteAccount();
|
||||
void refreshSelectiveSyncStatus();
|
||||
void slotCustomContextMenuRequested(const QPoint&);
|
||||
void slotFolderListClicked( const QModelIndex& indx );
|
||||
void doExpand();
|
||||
|
||||
private:
|
||||
|
||||
@@ -61,22 +61,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="signInButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enter your credentials to connect to the server</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sign in</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteButton">
|
||||
<property name="sizePolicy">
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "accountmanager.h"
|
||||
#include "account.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QSettings>
|
||||
@@ -29,7 +28,6 @@ AccountState::AccountState(AccountPtr account)
|
||||
, _state(AccountState::Disconnected)
|
||||
, _connectionStatus(ConnectionValidator::Undefined)
|
||||
, _waitingForNewCredentials(false)
|
||||
, _credentialsFetchMode(Interactive)
|
||||
{
|
||||
qRegisterMetaType<AccountState*>("AccountState*");
|
||||
|
||||
@@ -37,8 +35,6 @@ AccountState::AccountState(AccountPtr account)
|
||||
SLOT(slotInvalidCredentials()));
|
||||
connect(account.data(), SIGNAL(credentialsFetched(AbstractCredentials*)),
|
||||
SLOT(slotCredentialsFetched(AbstractCredentials*)));
|
||||
connect(account.data(), SIGNAL(credentialsAsked(AbstractCredentials*)),
|
||||
SLOT(slotCredentialsAsked(AbstractCredentials*)));
|
||||
}
|
||||
|
||||
AccountState::~AccountState()
|
||||
@@ -83,7 +79,7 @@ void AccountState::setState(State state)
|
||||
_connectionStatus = ConnectionValidator::Undefined;
|
||||
_connectionErrors.clear();
|
||||
} else if (oldState == SignedOut && _state == Disconnected) {
|
||||
checkConnectivity(Interactive);
|
||||
checkConnectivity();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +131,7 @@ bool AccountState::isConnectedOrTemporarilyUnavailable() const
|
||||
return isConnected() || _state == ServiceUnavailable;
|
||||
}
|
||||
|
||||
void AccountState::checkConnectivity(CredentialFetchMode credentialsFetchMode)
|
||||
void AccountState::checkConnectivity()
|
||||
{
|
||||
if (isSignedOut() || _waitingForNewCredentials) {
|
||||
return;
|
||||
@@ -145,7 +141,6 @@ void AccountState::checkConnectivity(CredentialFetchMode credentialsFetchMode)
|
||||
qDebug() << "ConnectionValidator already running, ignoring";
|
||||
return;
|
||||
}
|
||||
_credentialsFetchMode = credentialsFetchMode;
|
||||
ConnectionValidator * conValidator = new ConnectionValidator(account());
|
||||
_connectionValidator = conValidator;
|
||||
connect(conValidator, SIGNAL(connectionResult(ConnectionValidator::Status,QStringList)),
|
||||
@@ -207,8 +202,8 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
||||
// much more likely, so keep trying to connect.
|
||||
setState(NetworkError);
|
||||
break;
|
||||
case ConnectionValidator::CredentialsMissingOrWrong:
|
||||
slotInvalidCredentials();
|
||||
case ConnectionValidator::CredentialsWrong:
|
||||
account()->handleInvalidCredentials();
|
||||
break;
|
||||
case ConnectionValidator::UserCanceledCredentials:
|
||||
setState(SignedOut);
|
||||
@@ -224,41 +219,15 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
||||
|
||||
void AccountState::slotInvalidCredentials()
|
||||
{
|
||||
if (isSignedOut() || _waitingForNewCredentials)
|
||||
if (isSignedOut()) {
|
||||
return;
|
||||
|
||||
if (account()->credentials()->ready())
|
||||
account()->credentials()->invalidateToken();
|
||||
account()->credentials()->fetchFromKeychain();
|
||||
}
|
||||
|
||||
setState(ConfigurationError);
|
||||
_waitingForNewCredentials = true;
|
||||
}
|
||||
|
||||
void AccountState::slotCredentialsFetched(AbstractCredentials* credentials)
|
||||
{
|
||||
if (!credentials->ready()) {
|
||||
// No exiting credentials found in the keychain
|
||||
if (_credentialsFetchMode == Interactive)
|
||||
credentials->askFromUser();
|
||||
else {
|
||||
Logger::instance()->postOptionalGuiLog(tr("Reauthentication required"), tr("You need to re-login to continue using the account %1.").arg(_account->displayName()));
|
||||
setState(SignedOut);
|
||||
_waitingForNewCredentials = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_waitingForNewCredentials = false;
|
||||
|
||||
// When new credentials become available we always want to restart the
|
||||
// connection validation, even if it's currently running.
|
||||
delete _connectionValidator;
|
||||
|
||||
checkConnectivity(_credentialsFetchMode);
|
||||
}
|
||||
|
||||
void AccountState::slotCredentialsAsked(AbstractCredentials* credentials)
|
||||
{
|
||||
_waitingForNewCredentials = false;
|
||||
|
||||
@@ -270,9 +239,11 @@ void AccountState::slotCredentialsAsked(AbstractCredentials* credentials)
|
||||
|
||||
// When new credentials become available we always want to restart the
|
||||
// connection validation, even if it's currently running.
|
||||
delete _connectionValidator;
|
||||
if (_connectionValidator) {
|
||||
delete _connectionValidator;
|
||||
}
|
||||
|
||||
checkConnectivity(_credentialsFetchMode);
|
||||
checkConnectivity();
|
||||
}
|
||||
|
||||
std::unique_ptr<QSettings> AccountState::settings()
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <QPointer>
|
||||
#include "utility.h"
|
||||
#include "connectionvalidator.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include <memory>
|
||||
|
||||
class QSettings;
|
||||
@@ -28,6 +27,7 @@ namespace OCC {
|
||||
|
||||
class AccountState;
|
||||
class Account;
|
||||
class AbstractCredentials;
|
||||
|
||||
/**
|
||||
* @brief Extra info about an ownCloud server account.
|
||||
@@ -59,7 +59,6 @@ public:
|
||||
/// An error like invalid credentials where retrying won't help.
|
||||
ConfigurationError
|
||||
};
|
||||
enum CredentialFetchMode { Interactive, NonInteractive };
|
||||
|
||||
/// The actual current connectivity status.
|
||||
typedef ConnectionValidator::Status ConnectionStatus;
|
||||
@@ -85,7 +84,7 @@ public:
|
||||
|
||||
/// Triggers a ping to the server to update state and
|
||||
/// connection status and errors.
|
||||
void checkConnectivity(CredentialFetchMode credentialsFetchMode);
|
||||
void checkConnectivity();
|
||||
|
||||
/** Returns a new settings object for this account, already in the right groups. */
|
||||
std::unique_ptr<QSettings> settings();
|
||||
@@ -105,7 +104,6 @@ protected Q_SLOTS:
|
||||
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList& errors);
|
||||
void slotInvalidCredentials();
|
||||
void slotCredentialsFetched(AbstractCredentials* creds);
|
||||
void slotCredentialsAsked(AbstractCredentials* creds);
|
||||
|
||||
private:
|
||||
AccountPtr _account;
|
||||
@@ -113,7 +111,6 @@ private:
|
||||
ConnectionStatus _connectionStatus;
|
||||
QStringList _connectionErrors;
|
||||
bool _waitingForNewCredentials;
|
||||
CredentialFetchMode _credentialsFetchMode;
|
||||
QPointer<ConnectionValidator> _connectionValidator;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "accountmanager.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "updater/ocupdater.h"
|
||||
#include "excludedfiles.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -102,9 +101,7 @@ Application::Application(int &argc, char **argv) :
|
||||
_userTriggeredConnect(false),
|
||||
_debugMode(false)
|
||||
{
|
||||
_startedAt.start();
|
||||
|
||||
// TODO: Can't set this without breaking current config paths
|
||||
// TODO: Can't set this without breaking current config pathes
|
||||
// setOrganizationName(QLatin1String(APPLICATION_VENDOR));
|
||||
setOrganizationDomain(QLatin1String(APPLICATION_REV_DOMAIN));
|
||||
setApplicationName( _theme->appNameGUI() );
|
||||
@@ -136,13 +133,6 @@ Application::Application(int &argc, char **argv) :
|
||||
setupLogging();
|
||||
setupTranslations();
|
||||
|
||||
// Setup global excludes
|
||||
ConfigFile cfg;
|
||||
ExcludedFiles& excludes = ExcludedFiles::instance();
|
||||
excludes.addExcludeFilePath( cfg.excludeFile(ConfigFile::SystemScope) );
|
||||
excludes.addExcludeFilePath( cfg.excludeFile(ConfigFile::UserScope) );
|
||||
excludes.reloadExcludes();
|
||||
|
||||
_folderManager.reset(new FolderMan);
|
||||
|
||||
connect(this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseMessage(QString, QObject*)));
|
||||
@@ -153,6 +143,7 @@ Application::Application(int &argc, char **argv) :
|
||||
|
||||
setQuitOnLastWindowClosed(false);
|
||||
|
||||
ConfigFile cfg;
|
||||
_theme->setSystrayUseMonoIcons(cfg.monoIcons());
|
||||
connect (_theme, SIGNAL(systrayUseMonoIconsChanged(bool)), SLOT(slotUseMonoIconsChanged(bool)));
|
||||
|
||||
@@ -179,7 +170,7 @@ Application::Application(int &argc, char **argv) :
|
||||
connect(&_checkConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCheckConnection()));
|
||||
_checkConnectionTimer.setInterval(32 * 1000); // check for connection every 32 seconds.
|
||||
_checkConnectionTimer.start();
|
||||
// Also check immediately
|
||||
// Also check immediatly
|
||||
QTimer::singleShot( 0, this, SLOT( slotCheckConnection() ));
|
||||
|
||||
// Update checks
|
||||
@@ -195,12 +186,6 @@ Application::Application(int &argc, char **argv) :
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
// Make sure all folders are gone, otherwise removing the
|
||||
// accounts will remove the associated folders from the settings.
|
||||
if (_folderManager) {
|
||||
_folderManager->unloadAndDeleteAllFolders();
|
||||
}
|
||||
|
||||
// Remove the account from the account manager so it can be deleted.
|
||||
AccountManager::instance()->shutdown();
|
||||
}
|
||||
@@ -244,7 +229,7 @@ void Application::slotCheckConnection()
|
||||
// when the error is permanent.
|
||||
if (state != AccountState::SignedOut
|
||||
&& state != AccountState::ConfigurationError) {
|
||||
accountState->checkConnectivity(AccountState::NonInteractive);
|
||||
accountState->checkConnectivity();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,12 +297,6 @@ void Application::slotParseMessage(const QString &msg, QObject*)
|
||||
parseOptions(options);
|
||||
setupLogging();
|
||||
} else if (msg.startsWith(QLatin1String("MSG_SHOWSETTINGS"))) {
|
||||
qDebug() << "Running for" << _startedAt.elapsed()/1000.0 << "sec";
|
||||
if (_startedAt.elapsed() < 10*1000) {
|
||||
// This call is mirrored with the one in int main()
|
||||
qWarning() << "Ignoring MSG_SHOWSETTINGS, possibly double-invocation of client via session restore and auto start";
|
||||
return;
|
||||
}
|
||||
showSettingsDialog();
|
||||
}
|
||||
}
|
||||
@@ -451,7 +430,7 @@ void Application::setHelp()
|
||||
|
||||
QString substLang(const QString &lang)
|
||||
{
|
||||
// Map the more appropriate script codes
|
||||
// Map the more apropriate script codes
|
||||
// to country codes as used by Qt and
|
||||
// transifex translation conventions.
|
||||
|
||||
@@ -493,7 +472,7 @@ void Application::setupTranslations()
|
||||
// Permissive approach: Qt and keychain translations
|
||||
// may be missing, but Qt translations must be there in order
|
||||
// for us to accept the language. Otherwise, we try with the next.
|
||||
// "en" is an exception as it is the default language and may not
|
||||
// "en" is an exeption as it is the default language and may not
|
||||
// have a translation file provided.
|
||||
qDebug() << Q_FUNC_INFO << "Using" << lang << "translation";
|
||||
setProperty("ui_lang", lang);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <QPointer>
|
||||
#include <QQueue>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "qtsingleapplication.h"
|
||||
|
||||
@@ -98,8 +97,6 @@ private:
|
||||
bool _helpOnly;
|
||||
bool _versionOnly;
|
||||
|
||||
QElapsedTimer _startedAt;
|
||||
|
||||
// options from command line:
|
||||
bool _showLogWindow;
|
||||
QString _logFile;
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
// https://github.com/owncloud/client/issues/3300
|
||||
void copyToPasteboard(const QString &string)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << string;
|
||||
[[NSPasteboard generalPasteboard] clearContents];
|
||||
[[NSPasteboard generalPasteboard] setString:[NSString stringWithUTF8String:string.toUtf8().data()]
|
||||
forType:NSStringPboardType];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,34 +23,24 @@ using namespace QKeychain;
|
||||
namespace OCC
|
||||
{
|
||||
|
||||
void HttpCredentialsGui::askFromUser()
|
||||
QString HttpCredentialsGui::queryPassword(bool *ok, const QString& hint)
|
||||
{
|
||||
// The rest of the code assumes that this will be done asynchronously
|
||||
QMetaObject::invokeMethod(this, "askFromUserAsync", Qt::QueuedConnection);
|
||||
}
|
||||
if (!ok) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
void HttpCredentialsGui::askFromUserAsync()
|
||||
{
|
||||
QString msg = tr("Please enter %1 password:\n"
|
||||
"\n"
|
||||
"User: %2\n"
|
||||
"Account: %3\n")
|
||||
.arg(Theme::instance()->appNameGUI(), _user, _account->displayName());
|
||||
if (!_fetchErrorString.isEmpty()) {
|
||||
msg += QLatin1String("\n") + tr("Reading from keychain failed with error: '%1'").arg(
|
||||
_fetchErrorString) + QLatin1String("\n");
|
||||
if (!hint.isEmpty()) {
|
||||
msg += QLatin1String("\n") + hint + QLatin1String("\n");
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
QString pwd = QInputDialog::getText(0, tr("Enter Password"), msg,
|
||||
return QInputDialog::getText(0, tr("Enter Password"), msg,
|
||||
QLineEdit::Password, _previousPassword,
|
||||
&ok);
|
||||
if (ok) {
|
||||
_password = pwd;
|
||||
_ready = true;
|
||||
persist();
|
||||
}
|
||||
emit asked();
|
||||
ok);
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -28,8 +28,7 @@ class HttpCredentialsGui : public HttpCredentials {
|
||||
public:
|
||||
explicit HttpCredentialsGui() : HttpCredentials() {}
|
||||
HttpCredentialsGui(const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd) : HttpCredentials(user, password, certificatePath, certificatePasswd) {}
|
||||
void askFromUser() Q_DECL_OVERRIDE;
|
||||
Q_INVOKABLE void askFromUserAsync();
|
||||
QString queryPassword(bool *ok, const QString& hint) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.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; version 2 of the License.
|
||||
*
|
||||
* 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 <QEventLoop>
|
||||
|
||||
#include "account.h"
|
||||
#include "creds/shibboleth/shibbolethrefresher.h"
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
|
||||
namespace OCC
|
||||
{
|
||||
|
||||
ShibbolethRefresher::ShibbolethRefresher(AccountPtr account, ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent)
|
||||
: QObject(parent),
|
||||
_account(account),
|
||||
_creds(creds),
|
||||
_csync_ctx(csync_ctx)
|
||||
{}
|
||||
|
||||
void ShibbolethRefresher::refresh()
|
||||
{
|
||||
QEventLoop loop;
|
||||
|
||||
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
|
||||
this, SLOT(onInvalidatedAndFetched(QByteArray)));
|
||||
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
|
||||
&loop, SLOT(quit()));
|
||||
QMetaObject::invokeMethod(_creds, "invalidateAndFetch",Qt::QueuedConnection,
|
||||
Q_ARG(AccountPtr, _account));
|
||||
loop.exec();
|
||||
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
|
||||
&loop, SLOT(quit()));
|
||||
}
|
||||
|
||||
void ShibbolethRefresher::onInvalidatedAndFetched(const QByteArray& cookies)
|
||||
{
|
||||
// "cookies" is const and its data() return const void*. We want just void*.
|
||||
QByteArray myCookies(cookies);
|
||||
|
||||
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
|
||||
this, SLOT(onInvalidatedAndFetched(QByteArray)));
|
||||
csync_set_module_property(_csync_ctx, "session_key", myCookies.data());
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
|
||||
#define MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <csync.h>
|
||||
|
||||
class QByteArray;
|
||||
|
||||
namespace OCC
|
||||
{
|
||||
|
||||
class Account;
|
||||
class ShibbolethCredentials;
|
||||
|
||||
/**
|
||||
* @brief The ShibbolethRefresher class
|
||||
* @ingroup gui
|
||||
*/
|
||||
class ShibbolethRefresher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ShibbolethRefresher(AccountPtr account, ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0);
|
||||
|
||||
void refresh();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onInvalidatedAndFetched(const QByteArray& cookieData);
|
||||
|
||||
private:
|
||||
AccountPtr _account;
|
||||
ShibbolethCredentials* _creds;
|
||||
CSYNC* _csync_ctx;
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
#endif
|
||||
@@ -36,14 +36,6 @@ namespace {
|
||||
namespace OCC
|
||||
{
|
||||
|
||||
class UserAgentWebPage : public QWebPage {
|
||||
public:
|
||||
UserAgentWebPage(QObject *parent) : QWebPage(parent) {}
|
||||
QString userAgentForUrl(const QUrl &url ) const {
|
||||
return QWebPage::userAgentForUrl(url) + " " + Utility::userAgentString();
|
||||
}
|
||||
};
|
||||
|
||||
ShibbolethWebView::ShibbolethWebView(AccountPtr account, QWidget* parent)
|
||||
: QWebView(parent)
|
||||
, _account(account)
|
||||
@@ -54,7 +46,7 @@ ShibbolethWebView::ShibbolethWebView(AccountPtr account, QWidget* parent)
|
||||
setWindowFlags(Qt::Dialog);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QWebPage* page = new UserAgentWebPage(this);
|
||||
QWebPage* page = new QWebPage(this);
|
||||
connect(page, SIGNAL(loadStarted()),
|
||||
this, SLOT(slotLoadStarted()));
|
||||
connect(page, SIGNAL(loadFinished(bool)),
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <QMutex>
|
||||
#include <QSettings>
|
||||
#include <QNetworkReply>
|
||||
#include <QMessageBox>
|
||||
@@ -20,6 +21,7 @@
|
||||
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
#include "creds/shibboleth/shibbolethwebview.h"
|
||||
#include "creds/shibboleth/shibbolethrefresher.h"
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
#include "shibboleth/shibbolethuserjob.h"
|
||||
#include "creds/credentialscommon.h"
|
||||
@@ -44,6 +46,39 @@ namespace
|
||||
const char userC[] = "shib_user";
|
||||
const char shibCookieNameC[] = "_shibsession_";
|
||||
|
||||
int shibboleth_redirect_callback(CSYNC* csync_ctx,
|
||||
const char* uri)
|
||||
{
|
||||
if (!csync_ctx || !uri) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const QString qurl(QString::fromLatin1(uri));
|
||||
QRegExp shibbolethyWords ("SAML|wayf");
|
||||
|
||||
shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive);
|
||||
if (!qurl.contains(shibbolethyWords)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
SyncEngine* engine = reinterpret_cast<SyncEngine*>(csync_get_userdata(csync_ctx));
|
||||
AccountPtr account = engine->account();
|
||||
ShibbolethCredentials* creds = qobject_cast<ShibbolethCredentials*>(account->credentials());
|
||||
if (!creds) {
|
||||
qDebug() << "Not a Shibboleth creds instance!";
|
||||
return 1;
|
||||
}
|
||||
|
||||
QMutex mutex;
|
||||
QMutexLocker locker(&mutex);
|
||||
ShibbolethRefresher refresher(account, creds, csync_ctx);
|
||||
|
||||
// blocks
|
||||
refresher.refresh();
|
||||
|
||||
return creds->ready() ? 0 : 1;
|
||||
}
|
||||
|
||||
} // ns
|
||||
|
||||
ShibbolethCredentials::ShibbolethCredentials()
|
||||
@@ -51,12 +86,14 @@ ShibbolethCredentials::ShibbolethCredentials()
|
||||
_url(),
|
||||
_ready(false),
|
||||
_stillValid(false),
|
||||
_fetchJobInProgress(false),
|
||||
_browser(0)
|
||||
{}
|
||||
|
||||
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie)
|
||||
: _ready(true),
|
||||
_stillValid(true),
|
||||
_fetchJobInProgress(false),
|
||||
_browser(0),
|
||||
_shibCookie(cookie)
|
||||
{
|
||||
@@ -93,7 +130,12 @@ QByteArray ShibbolethCredentials::prepareCookieData() const
|
||||
|
||||
void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
|
||||
{
|
||||
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
|
||||
|
||||
csync_owncloud_redirect_callback_t cb = shibboleth_redirect_callback;
|
||||
|
||||
csync_set_module_property(ctx, "session_key", prepareCookieData().data());
|
||||
csync_set_module_property(ctx, "redirect_callback", &cb);
|
||||
}
|
||||
|
||||
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const
|
||||
@@ -149,12 +191,17 @@ bool ShibbolethCredentials::ready() const
|
||||
return _ready;
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::fetchFromKeychain()
|
||||
void ShibbolethCredentials::fetch()
|
||||
{
|
||||
if(_fetchJobInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_user.isEmpty()) {
|
||||
_user = _account->credentialSetting(QLatin1String(userC)).toString();
|
||||
}
|
||||
if (_ready) {
|
||||
_fetchJobInProgress = false;
|
||||
Q_EMIT fetched();
|
||||
} else {
|
||||
_url = _account->url();
|
||||
@@ -164,14 +211,10 @@ void ShibbolethCredentials::fetchFromKeychain()
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||
job->start();
|
||||
_fetchJobInProgress = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::askFromUser()
|
||||
{
|
||||
showLoginWindow();
|
||||
}
|
||||
|
||||
bool ShibbolethCredentials::stillValid(QNetworkReply *reply)
|
||||
{
|
||||
Q_UNUSED(reply)
|
||||
@@ -186,10 +229,9 @@ void ShibbolethCredentials::persist()
|
||||
}
|
||||
}
|
||||
|
||||
// only used by Application::slotLogout(). Use invalidateAndFetch for normal usage
|
||||
void ShibbolethCredentials::invalidateToken()
|
||||
{
|
||||
_ready = false;
|
||||
|
||||
CookieJar *jar = static_cast<CookieJar*>(_account->networkAccessManager()->cookieJar());
|
||||
|
||||
// Remove the _shibCookie
|
||||
@@ -223,7 +265,7 @@ void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& shi
|
||||
void ShibbolethCredentials::slotFetchUser()
|
||||
{
|
||||
// We must first do a request to webdav so the session is enabled.
|
||||
// (because for some reason we can't access the API without that.. a bug in the server maybe?)
|
||||
// (because for some reason we wan't access the API without that.. a bug in the server maybe?)
|
||||
EntityExistsJob* job = new EntityExistsJob(_account->sharedFromThis(), _account->davPath(), this);
|
||||
connect(job, SIGNAL(exists(QNetworkReply*)), this, SLOT(slotFetchUserHelper()));
|
||||
job->setIgnoreCredentialFailure(true);
|
||||
@@ -254,14 +296,48 @@ void ShibbolethCredentials::slotUserFetched(const QString &user)
|
||||
|
||||
_stillValid = true;
|
||||
_ready = true;
|
||||
Q_EMIT asked();
|
||||
_fetchJobInProgress = false;
|
||||
Q_EMIT fetched();
|
||||
}
|
||||
|
||||
|
||||
void ShibbolethCredentials::slotBrowserRejected()
|
||||
{
|
||||
_ready = false;
|
||||
Q_EMIT asked();
|
||||
_fetchJobInProgress = false;
|
||||
Q_EMIT fetched();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::invalidateAndFetch()
|
||||
{
|
||||
_ready = false;
|
||||
_fetchJobInProgress = true;
|
||||
|
||||
// delete the credentials, then in the slot fetch them again (which will trigger browser)
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
job->setSettings(_account->settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotInvalidateAndFetchInvalidateDone(QKeychain::Job*)));
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->start();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::slotInvalidateAndFetchInvalidateDone(QKeychain::Job*)
|
||||
{
|
||||
connect (this, SIGNAL(fetched()),
|
||||
this, SLOT(onFetched()));
|
||||
_fetchJobInProgress = false;
|
||||
// small hack to support the ShibbolethRefresher hack
|
||||
// we already rand fetch() with a valid account object,
|
||||
// and hence know the url on refresh
|
||||
fetch();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::onFetched()
|
||||
{
|
||||
disconnect (this, SIGNAL(fetched()),
|
||||
this, SLOT(onFetched()));
|
||||
|
||||
Q_EMIT invalidatedAndFetched(prepareCookieData());
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
|
||||
@@ -279,10 +355,10 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
|
||||
|
||||
_ready = true;
|
||||
_stillValid = true;
|
||||
_fetchJobInProgress = false;
|
||||
Q_EMIT fetched();
|
||||
} else {
|
||||
_ready = false;
|
||||
Q_EMIT fetched();
|
||||
showLoginWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Q_OBJECT
|
||||
public:
|
||||
ShibbolethCredentials();
|
||||
|
||||
/* create credentials for an already connected account */
|
||||
/* create a credentials for an already connected account */
|
||||
ShibbolethCredentials(const QNetworkCookie &cookie);
|
||||
|
||||
void setAccount(Account* account) Q_DECL_OVERRIDE;
|
||||
@@ -55,8 +55,7 @@ public:
|
||||
QString user() const Q_DECL_OVERRIDE;
|
||||
QNetworkAccessManager* getQNAM() const Q_DECL_OVERRIDE;
|
||||
bool ready() const Q_DECL_OVERRIDE;
|
||||
void fetchFromKeychain() Q_DECL_OVERRIDE;
|
||||
void askFromUser() Q_DECL_OVERRIDE;
|
||||
void fetch() Q_DECL_OVERRIDE;
|
||||
bool stillValid(QNetworkReply *reply) Q_DECL_OVERRIDE;
|
||||
void persist() Q_DECL_OVERRIDE;
|
||||
void invalidateToken() Q_DECL_OVERRIDE;
|
||||
@@ -67,10 +66,15 @@ public:
|
||||
static QNetworkCookie findShibCookie(Account *, QList<QNetworkCookie> cookies = QList<QNetworkCookie>());
|
||||
static QByteArray shibCookieName();
|
||||
|
||||
public Q_SLOTS:
|
||||
void invalidateAndFetch() Q_DECL_OVERRIDE;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onShibbolethCookieReceived(const QNetworkCookie&);
|
||||
void slotBrowserRejected();
|
||||
void onFetched();
|
||||
void slotReadJobDone(QKeychain::Job*);
|
||||
void slotInvalidateAndFetchInvalidateDone(QKeychain::Job*);
|
||||
void slotReplyFinished(QNetworkReply*);
|
||||
void slotUserFetched(const QString& user);
|
||||
void slotFetchUser();
|
||||
@@ -78,6 +82,7 @@ private Q_SLOTS:
|
||||
|
||||
Q_SIGNALS:
|
||||
void newCookie(const QNetworkCookie& cookie);
|
||||
void invalidatedAndFetched(const QByteArray& cookieData);
|
||||
|
||||
private:
|
||||
void storeShibCookie(const QNetworkCookie &cookie);
|
||||
@@ -88,6 +93,7 @@ private:
|
||||
|
||||
bool _ready;
|
||||
bool _stillValid;
|
||||
bool _fetchJobInProgress;
|
||||
QPointer<ShibbolethWebView> _browser;
|
||||
QNetworkCookie _shibCookie;
|
||||
QString _user;
|
||||
|
||||
@@ -30,9 +30,7 @@
|
||||
#include "syncrunfilelog.h"
|
||||
#include "theme.h"
|
||||
#include "filesystem.h"
|
||||
#include "excludedfiles.h"
|
||||
|
||||
#include <csync_private.h>
|
||||
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
@@ -90,14 +88,14 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
|
||||
bool Folder::init()
|
||||
{
|
||||
// We need to reconstruct the url because the path needs to be fully decoded, as csync will re-encode the path:
|
||||
// We need to reconstruct the url because the path need to be fully decoded, as csync will re-encode the path:
|
||||
// Remember that csync will just append the filename to the path and pass it to the vio plugin.
|
||||
// csync_owncloud will then re-encode everything.
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
QUrl url = remoteUrl();
|
||||
QString url_string = url.scheme() + QLatin1String("://") + url.authority(QUrl::EncodeDelimiters) + url.path(QUrl::FullyDecoded);
|
||||
#else
|
||||
// Qt4 was broken anyway as it did not encode the '#' as it should have done (it was actually a problem when parsing the path from QUrl::setPath
|
||||
// Qt4 was broken anyway as it did not encode the '#' as it should have done (it was actually a provlem when parsing the path from QUrl::setPath
|
||||
QString url_string = remoteUrl().toString();
|
||||
#endif
|
||||
url_string = Utility::toCSyncScheme(url_string);
|
||||
@@ -158,8 +156,15 @@ void Folder::checkLocalPath()
|
||||
if( fi.isDir() && fi.isReadable() ) {
|
||||
qDebug() << "Checked local path ok";
|
||||
} else {
|
||||
if( !FileSystem::fileExists(_definition.localPath) ) {
|
||||
// try to create the local dir
|
||||
QDir d(_definition.localPath);
|
||||
if( d.mkpath(_definition.localPath) ) {
|
||||
qDebug() << "Successfully created the local dir " << _definition.localPath;
|
||||
}
|
||||
}
|
||||
// Check directory again
|
||||
if( !FileSystem::fileExists(_definition.localPath, fi) ) {
|
||||
if( !FileSystem::fileExists(_definition.localPath) ) {
|
||||
_syncResult.setErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
} else if( !fi.isDir() ) {
|
||||
@@ -702,28 +707,6 @@ void Folder::removeFromSettings() const
|
||||
settings->remove(_definition.alias);
|
||||
}
|
||||
|
||||
bool Folder::isFileExcludedAbsolute(const QString& fullPath) const
|
||||
{
|
||||
QString myFullPath = fullPath;
|
||||
if (myFullPath.endsWith(QLatin1Char('/'))) {
|
||||
myFullPath.chop(1);
|
||||
}
|
||||
|
||||
if (!myFullPath.startsWith(path())) {
|
||||
// Mark paths we're not responsible for as excluded...
|
||||
return true;
|
||||
}
|
||||
|
||||
QString relativePath = myFullPath.mid(path().size());
|
||||
auto excl = ExcludedFiles::instance().isExcluded(myFullPath, relativePath, _definition.ignoreHiddenFiles);
|
||||
return excl != CSYNC_NOT_EXCLUDED;
|
||||
}
|
||||
|
||||
bool Folder::isFileExcludedRelative(const QString& relativePath) const
|
||||
{
|
||||
return isFileExcludedAbsolute(path() + relativePath);
|
||||
}
|
||||
|
||||
void Folder::watcherSlot(QString fn)
|
||||
{
|
||||
// FIXME: On OS X we could not do this "if" since on OS X the file watcher ignores events for ourselves
|
||||
@@ -1017,14 +1000,14 @@ void Folder::slotSyncFinished()
|
||||
}
|
||||
|
||||
if (_syncResult.status() == SyncResult::Success) {
|
||||
// Clear the white list as all the folders that should be on that list are sync-ed
|
||||
// Clear the white list as all the folder that should be on that list are sync-ed
|
||||
journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList, QStringList());
|
||||
}
|
||||
|
||||
emit syncStateChange();
|
||||
|
||||
// The syncFinished result that is to be triggered here makes the folderman
|
||||
// clear the current running sync folder marker.
|
||||
// clearing the current running sync folder marker.
|
||||
// Lets wait a bit to do that because, as long as this marker is not cleared,
|
||||
// file system change notifications are ignored for that folder. And it takes
|
||||
// some time under certain conditions to make the file system notifications
|
||||
|
||||
@@ -197,16 +197,6 @@ public:
|
||||
/// Removes the folder from the account's settings.
|
||||
void removeFromSettings() const;
|
||||
|
||||
/**
|
||||
* Returns whether a file inside this folder should be excluded.
|
||||
*/
|
||||
bool isFileExcludedAbsolute(const QString& fullPath) const;
|
||||
|
||||
/**
|
||||
* Returns whether a file inside this folder should be excluded.
|
||||
*/
|
||||
bool isFileExcludedRelative(const QString& relativePath) const;
|
||||
|
||||
signals:
|
||||
void syncStateChange();
|
||||
void syncStarted();
|
||||
|
||||
@@ -60,6 +60,7 @@ FolderMan::FolderMan(QObject *parent) :
|
||||
_instance = this;
|
||||
|
||||
_socketApi = new SocketApi(this);
|
||||
_socketApi->slotReadExcludes();
|
||||
|
||||
ConfigFile cfg;
|
||||
int polltime = cfg.remotePollInterval();
|
||||
@@ -148,6 +149,10 @@ void FolderMan::registerFolderMonitor( Folder *folder )
|
||||
|
||||
if( !_folderWatchers.contains(folder->alias() ) ) {
|
||||
FolderWatcher *fw = new FolderWatcher(folder->path(), folder);
|
||||
ConfigFile cfg;
|
||||
fw->addIgnoreListFile( cfg.excludeFile(ConfigFile::SystemScope) );
|
||||
fw->addIgnoreListFile( cfg.excludeFile(ConfigFile::UserScope) );
|
||||
fw->setIgnoreHidden( folder->ignoreHiddenFiles() );
|
||||
|
||||
// Connect the pathChanged signal, which comes with the changed path,
|
||||
// to the signal mapper which maps to the folder alias. The changed path
|
||||
@@ -244,7 +249,7 @@ int FolderMan::setupFoldersMigration()
|
||||
dir.setFilter(QDir::Files | QDir::Hidden);
|
||||
QStringList list = dir.entryList();
|
||||
|
||||
// Normally there should be only one account when migrating.
|
||||
// Normaly there should be only one account when migrating.
|
||||
AccountState* accountState = AccountManager::instance()->accounts().value(0).data();
|
||||
foreach ( const QString& alias, list ) {
|
||||
Folder *f = setupFolderFromOldConfigFile( alias, accountState );
|
||||
@@ -345,8 +350,8 @@ Folder* FolderMan::setupFolderFromOldConfigFile(const QString &file, AccountStat
|
||||
|
||||
qDebug() << " ` -> setting up:" << file;
|
||||
QString escapedAlias(file);
|
||||
// check the unescaped variant (for the case when the filename comes out
|
||||
// of the directory listing). If the file does not exist, escape the
|
||||
// check the unescaped variant (for the case the filename comes out
|
||||
// of the directory listing. If the file is not existing, escape the
|
||||
// file and try again.
|
||||
QFileInfo cfgFile( _folderConfigPath, file);
|
||||
|
||||
@@ -356,7 +361,7 @@ Folder* FolderMan::setupFolderFromOldConfigFile(const QString &file, AccountStat
|
||||
cfgFile.setFile( _folderConfigPath, escapedAlias );
|
||||
}
|
||||
if( !cfgFile.isReadable() ) {
|
||||
qDebug() << "Cannot read folder definition for alias " << cfgFile.filePath();
|
||||
qDebug() << "Can not read folder definition for alias " << cfgFile.filePath();
|
||||
return folder;
|
||||
}
|
||||
|
||||
@@ -594,12 +599,12 @@ void FolderMan::slotAccountStateChanged()
|
||||
}
|
||||
}
|
||||
|
||||
// only enable or disable foldermans will schedule and do syncs.
|
||||
// only enable or disable foldermans will to schedule and do syncs.
|
||||
// this is not the same as Pause and Resume of folders.
|
||||
void FolderMan::setSyncEnabled( bool enabled )
|
||||
{
|
||||
if (!_syncEnabled && enabled && !_scheduleQueue.isEmpty()) {
|
||||
// We have things in our queue that were waiting for the connection to come back on.
|
||||
// We have things in our queue that were waiting the the connection to go back on.
|
||||
startScheduledSyncSoon();
|
||||
}
|
||||
_syncEnabled = enabled;
|
||||
@@ -691,6 +696,13 @@ void FolderMan::slotStartScheduledFolderSync()
|
||||
_currentSyncFolder = f;
|
||||
|
||||
f->startSync( QStringList() );
|
||||
|
||||
// reread the excludes of the socket api
|
||||
// FIXME: the excludes need rework.
|
||||
if( _socketApi ) {
|
||||
_socketApi->slotClearExcludesList();
|
||||
_socketApi->slotReadExcludes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,7 +841,9 @@ void FolderMan::slotRemoveFolder( Folder *f )
|
||||
|
||||
const bool currentlyRunning = (_currentSyncFolder == f);
|
||||
if( currentlyRunning ) {
|
||||
// let the folder delete itself when done and
|
||||
// abort the sync now
|
||||
connect(f, SIGNAL(syncFinished(SyncResult)), f, SLOT(deleteLater()));
|
||||
terminateSyncProcess();
|
||||
}
|
||||
|
||||
@@ -844,13 +858,7 @@ void FolderMan::slotRemoveFolder( Folder *f )
|
||||
f->removeFromSettings();
|
||||
|
||||
unloadFolder( f);
|
||||
if( currentlyRunning ) {
|
||||
// We want to schedule the next folder once this is done
|
||||
connect(f, SIGNAL(syncFinished(SyncResult)),
|
||||
SLOT(slotFolderSyncFinished(SyncResult)));
|
||||
// Let the folder delete itself when done.
|
||||
connect(f, SIGNAL(syncFinished(SyncResult)), f, SLOT(deleteLater()));
|
||||
} else {
|
||||
if( !currentlyRunning ) {
|
||||
delete f;
|
||||
}
|
||||
}
|
||||
@@ -906,7 +914,7 @@ bool FolderMan::startFromScratch( const QString& localFolder )
|
||||
_socketApi->slotUnregisterPath(f->alias());
|
||||
}
|
||||
f->journalDb()->close();
|
||||
f->slotTerminateSync(); // Normally it should not be running, but viel hilft viel
|
||||
f->slotTerminateSync(); // Normaly it should not be running, but viel hilft viel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -936,7 +944,7 @@ void FolderMan::setDirtyProxy(bool value)
|
||||
|
||||
if (f->accountState() && f->accountState()->account()
|
||||
&& f->accountState()->account()->networkAccessManager()) {
|
||||
// Need to do this so we do not use the old determined system proxy
|
||||
// Need to do this have us not use the old determined system proxy
|
||||
f->accountState()->account()->networkAccessManager()->setProxy(
|
||||
QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||
}
|
||||
@@ -962,7 +970,7 @@ SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
||||
int cnt = folders.count();
|
||||
|
||||
// if one folder: show the state of the one folder.
|
||||
// if more folders:
|
||||
// if more folder:
|
||||
// if one of them has an error -> show error
|
||||
// if one is paused, but others ok, show ok
|
||||
// do not show "problem" in the tray
|
||||
@@ -1079,7 +1087,7 @@ QString FolderMan::statusToString( SyncResult syncStatus, bool paused ) const
|
||||
folderMessage = tr( "Undefined State." );
|
||||
break;
|
||||
case SyncResult::NotYetStarted:
|
||||
folderMessage = tr( "Waiting to start syncing." );
|
||||
folderMessage = tr( "Waits to start syncing." );
|
||||
break;
|
||||
case SyncResult::SyncPrepare:
|
||||
folderMessage = tr( "Preparing for sync." );
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
|
||||
/**
|
||||
* Check if @a path is a valid path for a new folder considering the already sync'ed items.
|
||||
* Make sure that this folder, or any subfolder is not sync'ed already.
|
||||
* Make sure that this folder, or any subfolder is not sync'ed alrady.
|
||||
*
|
||||
* \a forNewDirectory is internal and is used for recursion.
|
||||
*
|
||||
@@ -123,7 +123,7 @@ signals:
|
||||
/**
|
||||
* signal to indicate a folder has changed its sync state.
|
||||
*
|
||||
* Attention: The folder may be zero. Do a general update of the state then.
|
||||
* Attention: The folder may be zero. Do a general update of the state than.
|
||||
*/
|
||||
void folderSyncStateChange(Folder*);
|
||||
|
||||
@@ -162,7 +162,7 @@ public slots:
|
||||
|
||||
// slot to add a folder to the syncing queue
|
||||
void slotScheduleSync(Folder*);
|
||||
// slot to schedule an ETag job
|
||||
// slot to scheule an ETag job
|
||||
void slotScheduleETagJob ( const QString &alias, RequestEtagJob *job);
|
||||
void slotEtagJobDestroyed (QObject*);
|
||||
void slotRunOneEtagJob();
|
||||
|
||||
@@ -33,7 +33,7 @@ QString FolderStatusDelegate::addFolderText()
|
||||
return tr("Add Folder Sync Connection");
|
||||
}
|
||||
|
||||
// allocate each item size in listview.
|
||||
//alocate each item size in listview.
|
||||
QSize FolderStatusDelegate::sizeHint(const QStyleOptionViewItem & option ,
|
||||
const QModelIndex & index) const
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ Qt::ItemFlags FolderStatusModel::flags ( const QModelIndex &index ) const
|
||||
}
|
||||
return Qt::ItemIsEnabled | ret;
|
||||
}
|
||||
case FetchLabel:
|
||||
case ErrorLabel:
|
||||
return Qt::ItemIsEnabled
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
|
||||
| Qt::ItemNeverHasChildren
|
||||
@@ -123,7 +123,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||
auto remotePath = _folders.at(0)._folder->remotePath();
|
||||
if (remotePath.isEmpty() || remotePath == QLatin1String("/")) {
|
||||
// Syncing the entire owncloud: disable the add folder button (#3438)
|
||||
return tr("Adding folder is disabled because you are already syncing all your files. "
|
||||
return tr("Adding folder is disabled because your are already syncing all your files. "
|
||||
"If you want to sync multiple folders, please remove the currently "
|
||||
"configured root folder.");
|
||||
}
|
||||
@@ -151,20 +151,11 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
case FetchLabel:
|
||||
{
|
||||
const auto x = static_cast<SubFolderInfo *>(index.internalPointer());
|
||||
case ErrorLabel:
|
||||
switch(role) {
|
||||
case Qt::DisplayRole:
|
||||
if (x->_hasError) {
|
||||
return tr("Error while loading the list of folders from the server.");
|
||||
} else {
|
||||
return tr("Fetching folder list from server...");
|
||||
}
|
||||
break;
|
||||
case Qt::DisplayRole: return tr("Error while loading the list of folders from the server.");
|
||||
default: return QVariant();
|
||||
}
|
||||
}
|
||||
case RootFolder:
|
||||
break;
|
||||
}
|
||||
@@ -201,7 +192,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||
} else if( status == SyncResult::Undefined ) {
|
||||
return theme->syncStateIcon( SyncResult::SyncRunning);
|
||||
} else {
|
||||
// keep the previous icon for the prepare phase.
|
||||
// kepp the previous icon for the prepare phase.
|
||||
if( status == SyncResult::Problem) {
|
||||
return theme->syncStateIcon( SyncResult::Success);
|
||||
} else {
|
||||
@@ -236,7 +227,7 @@ bool FolderStatusModel::setData(const QModelIndex& index, const QVariant& value,
|
||||
info->_checked = checked;
|
||||
if (checked == Qt::Checked) {
|
||||
// If we are checked, check that we may need to check the parent as well if
|
||||
// all the siblings are also checked
|
||||
// all the sibilings are also checked
|
||||
QModelIndex parent = index.parent();
|
||||
auto parentInfo = infoForIndex(parent);
|
||||
if (parentInfo && parentInfo->_checked != Qt::Checked) {
|
||||
@@ -311,7 +302,7 @@ int FolderStatusModel::rowCount(const QModelIndex& parent) const
|
||||
auto info = infoForIndex(parent);
|
||||
if (!info)
|
||||
return 0;
|
||||
if (info->hasLabel())
|
||||
if (info->_hasError)
|
||||
return 1;
|
||||
return info->_subs.count();
|
||||
}
|
||||
@@ -319,11 +310,7 @@ int FolderStatusModel::rowCount(const QModelIndex& parent) const
|
||||
FolderStatusModel::ItemType FolderStatusModel::classify(const QModelIndex& index) const
|
||||
{
|
||||
if (auto sub = static_cast<SubFolderInfo*>(index.internalPointer())) {
|
||||
if (sub->hasLabel()) {
|
||||
return FetchLabel;
|
||||
} else {
|
||||
return SubFolder;
|
||||
}
|
||||
return sub->_hasError ? ErrorLabel : SubFolder;
|
||||
}
|
||||
if (index.row() < _folders.count()) {
|
||||
return RootFolder;
|
||||
@@ -336,7 +323,8 @@ FolderStatusModel::SubFolderInfo* FolderStatusModel::infoForIndex(const QModelIn
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
if (auto parentInfo = static_cast<SubFolderInfo*>(index.internalPointer())) {
|
||||
if (parentInfo->hasLabel()) {
|
||||
if (parentInfo->_hasError) {
|
||||
// Error label
|
||||
return 0;
|
||||
}
|
||||
return &parentInfo->_subs[index.row()];
|
||||
@@ -396,21 +384,20 @@ QModelIndex FolderStatusModel::index(int row, int column, const QModelIndex& par
|
||||
}
|
||||
switch(classify(parent)) {
|
||||
case AddButton:
|
||||
case FetchLabel:
|
||||
case ErrorLabel:
|
||||
return QModelIndex();
|
||||
case RootFolder:
|
||||
if (_folders.count() <= parent.row())
|
||||
return QModelIndex(); // should not happen
|
||||
return createIndex(row, column, const_cast<SubFolderInfo *>(&_folders[parent.row()]));
|
||||
case SubFolder: {
|
||||
auto pinfo = static_cast<SubFolderInfo*>(parent.internalPointer());
|
||||
if (pinfo->_subs.count() <= parent.row())
|
||||
auto info = static_cast<SubFolderInfo*>(parent.internalPointer());
|
||||
if (info->_subs.count() <= parent.row())
|
||||
return QModelIndex(); // should not happen
|
||||
auto & info = pinfo->_subs[parent.row()];
|
||||
if (!info.hasLabel()
|
||||
&& info._subs.count() <= row)
|
||||
if (!info->_subs.at(parent.row())._hasError
|
||||
&& info->_subs.at(parent.row())._subs.count() <= row)
|
||||
return QModelIndex(); // should not happen
|
||||
return createIndex(row, column, &info);
|
||||
return createIndex(row, column, &info->_subs[parent.row()]);
|
||||
}
|
||||
}
|
||||
return QModelIndex();
|
||||
@@ -426,7 +413,7 @@ QModelIndex FolderStatusModel::parent(const QModelIndex& child) const
|
||||
case AddButton:
|
||||
return QModelIndex();
|
||||
case SubFolder:
|
||||
case FetchLabel:
|
||||
case ErrorLabel:
|
||||
break;
|
||||
}
|
||||
auto pathIdx = static_cast<SubFolderInfo*>(child.internalPointer())->_pathIdx;
|
||||
@@ -466,9 +453,6 @@ bool FolderStatusModel::hasChildren(const QModelIndex& parent) const
|
||||
|
||||
bool FolderStatusModel::canFetchMore(const QModelIndex& parent) const
|
||||
{
|
||||
if (_accountState->state() != AccountState::Connected) {
|
||||
return false;
|
||||
}
|
||||
auto info = infoForIndex(parent);
|
||||
if (!info || info->_fetched || info->_fetching)
|
||||
return false;
|
||||
@@ -483,9 +467,7 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
||||
if (!info || info->_fetched || info->_fetching)
|
||||
return;
|
||||
|
||||
info->_hasError = false;
|
||||
info->_fetching = true;
|
||||
info->_fetchingLabel = false;
|
||||
QString path = info->_folder->remotePath();
|
||||
if (info->_path != QLatin1String("/")) {
|
||||
if (!path.endsWith(QLatin1Char('/'))) {
|
||||
@@ -495,18 +477,13 @@ void FolderStatusModel::fetchMore(const QModelIndex& parent)
|
||||
}
|
||||
LsColJob *job = new LsColJob(_accountState->account(), path, this);
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "quota-used-bytes");
|
||||
job->setTimeout(60 * 1000);
|
||||
job->setTimeout(5 * 1000);
|
||||
connect(job, SIGNAL(directoryListingSubfolders(QStringList)),
|
||||
SLOT(slotUpdateDirectories(QStringList)));
|
||||
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
||||
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
||||
job->start();
|
||||
QPersistentModelIndex persistentIndex(parent);
|
||||
job->setProperty(propertyParentIndexC , QVariant::fromValue(persistentIndex));
|
||||
|
||||
// Show 'fetching data...' hint after a while.
|
||||
_fetchingItems[persistentIndex].start();
|
||||
QTimer::singleShot(1000, this, SLOT(slotShowFetchProgress()));
|
||||
job->setProperty(propertyParentIndexC , QVariant::fromValue<QPersistentModelIndex>(parent));
|
||||
}
|
||||
|
||||
void FolderStatusModel::slotUpdateDirectories(const QStringList &list_)
|
||||
@@ -519,35 +496,24 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list_)
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentInfo->hasLabel()) {
|
||||
auto list = list_;
|
||||
list.removeFirst(); // remove the parent item
|
||||
|
||||
if (parentInfo->_hasError) {
|
||||
beginRemoveRows(idx, 0 ,0);
|
||||
parentInfo->_hasError = false;
|
||||
parentInfo->_fetchingLabel = false;
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
parentInfo->_fetching = false;
|
||||
parentInfo->_fetched = true;
|
||||
|
||||
auto list = list_;
|
||||
list.removeFirst(); // remove the parent item
|
||||
beginInsertRows(idx, 0, list.count() - 1);
|
||||
|
||||
QUrl url = parentInfo->_folder->remoteUrl();
|
||||
QString pathToRemove = url.path();
|
||||
if (!pathToRemove.endsWith('/'))
|
||||
pathToRemove += '/';
|
||||
|
||||
// Drop the folder base path and check for excludes.
|
||||
QMutableListIterator<QString> it(list);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
it.value().remove(pathToRemove);
|
||||
if (parentInfo->_folder->isFileExcludedRelative(it.value())) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
beginInsertRows(idx, 0, list.count() - 1);
|
||||
parentInfo->_fetched = true;
|
||||
parentInfo->_fetching = false;
|
||||
|
||||
QStringList selectiveSyncBlackList;
|
||||
if (parentInfo->_checked == Qt::PartiallyChecked) {
|
||||
@@ -565,6 +531,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list_)
|
||||
newInfo._pathIdx << i++;
|
||||
auto size = job ? job->_sizes.value(path) : 0;
|
||||
newInfo._size = size;
|
||||
path.remove(pathToRemove);
|
||||
newInfo._path = path;
|
||||
newInfo._name = path.split('/', QString::SkipEmptyParts).last();
|
||||
|
||||
@@ -613,17 +580,14 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
||||
}
|
||||
auto parentInfo = infoForIndex(idx);
|
||||
if (parentInfo) {
|
||||
parentInfo->_fetching = false;
|
||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||
parentInfo->_fetched = true;
|
||||
} else {
|
||||
if (!parentInfo->hasLabel()) {
|
||||
beginInsertRows(idx, 0, 0);
|
||||
endInsertRows();
|
||||
}
|
||||
} else if (!parentInfo->_hasError) {
|
||||
beginInsertRows(idx, 0, 0);
|
||||
parentInfo->_hasError = true;
|
||||
endInsertRows();
|
||||
}
|
||||
parentInfo->_fetching = false;
|
||||
parentInfo->_fetchingLabel = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,7 +661,7 @@ void FolderStatusModel::slotApplySelectiveSync()
|
||||
// clear the undecided list
|
||||
folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncUndecidedList, QStringList());
|
||||
|
||||
// do the sync if there were changes
|
||||
// do the sync if there was changes
|
||||
auto changes = (oldBlackListSet - blackListSet) + (blackListSet - oldBlackListSet);
|
||||
if (!changes.isEmpty()) {
|
||||
if (folder->isBusy()) {
|
||||
@@ -760,7 +724,7 @@ void FolderStatusModel::slotSetProgress(const ProgressInfo &progress)
|
||||
<< FolderStatusDelegate::WarningCount;
|
||||
|
||||
if (!progress._currentDiscoveredFolder.isEmpty()) {
|
||||
pi->_progressString = tr("Checking for changes in '%1'").arg(progress._currentDiscoveredFolder);
|
||||
pi->_progressString = tr("Discovering '%1'").arg(progress._currentDiscoveredFolder);
|
||||
emit dataChanged(index(folderIndex), index(folderIndex), roles);
|
||||
return;
|
||||
}
|
||||
@@ -865,7 +829,7 @@ void FolderStatusModel::slotSetProgress(const ProgressInfo &progress)
|
||||
.arg(currentFile).arg(totalFileCount)
|
||||
.arg( Utility::durationToDescriptiveString(progress.totalProgress().estimatedEta) );
|
||||
} else if (totalFileCount > 0) {
|
||||
// Don't attempt to estimate the time left if there is no kb to transfer.
|
||||
// Don't attemt to estimate the time left if there is no kb to transfer.
|
||||
overallSyncString = tr("file %1 of %2") .arg(currentFile).arg(totalFileCount);
|
||||
}
|
||||
|
||||
@@ -873,7 +837,7 @@ void FolderStatusModel::slotSetProgress(const ProgressInfo &progress)
|
||||
|
||||
int overallPercent = 0;
|
||||
if( totalFileCount > 0 ) {
|
||||
// Add one 'byte' for each file so the percentage is moving when deleting or renaming files
|
||||
// Add one 'byte' for each files so the percentage is moving when deleting or renaming files
|
||||
overallPercent = qRound(double(completedSize + completedFile)/double(totalSize + totalFileCount) * 100.0);
|
||||
}
|
||||
pi->_overallPercent = qBound(0, overallPercent, 100);
|
||||
@@ -927,8 +891,13 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
||||
if (i->_isDirectory && (i->_instruction == CSYNC_INSTRUCTION_NEW
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_REMOVE)) {
|
||||
// There is a new or a removed folder. reset all data
|
||||
auto & info = _folders[folderIndex];
|
||||
info.resetSubs(this, index(folderIndex));
|
||||
_folders[folderIndex]._fetched = false;
|
||||
_folders[folderIndex]._fetching = false;
|
||||
if (!_folders.at(folderIndex)._subs.isEmpty()) {
|
||||
beginRemoveRows(index(folderIndex), 0, _folders.at(folderIndex)._subs.count() - 1);
|
||||
_folders[folderIndex]._subs.clear();
|
||||
endRemoveRows();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -964,53 +933,17 @@ void FolderStatusModel::slotNewBigFolder()
|
||||
}
|
||||
if (folderIndex < 0) { return; }
|
||||
|
||||
_folders[folderIndex].resetSubs(this, index(folderIndex));
|
||||
_folders[folderIndex]._fetched = false;
|
||||
_folders[folderIndex]._fetching = false;
|
||||
if (!_folders.at(folderIndex)._subs.isEmpty()) {
|
||||
beginRemoveRows(index(folderIndex), 0, _folders.at(folderIndex)._subs.count() - 1);
|
||||
_folders[folderIndex]._subs.clear();
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
emit suggestExpand(index(folderIndex));
|
||||
emit dirtyChanged();
|
||||
}
|
||||
|
||||
void FolderStatusModel::slotShowFetchProgress()
|
||||
{
|
||||
QMutableMapIterator<QPersistentModelIndex, QElapsedTimer> it(_fetchingItems);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value().elapsed() > 800)
|
||||
{
|
||||
auto idx = it.key();
|
||||
auto* info = infoForIndex(idx);
|
||||
if (info && info->_fetching) {
|
||||
if (!info->hasLabel()) {
|
||||
beginInsertRows(idx, 0, 0);
|
||||
endInsertRows();
|
||||
}
|
||||
info->_fetchingLabel = true;
|
||||
}
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FolderStatusModel::SubFolderInfo::hasLabel() const
|
||||
{
|
||||
return _hasError || _fetchingLabel;
|
||||
}
|
||||
|
||||
void FolderStatusModel::SubFolderInfo::resetSubs(FolderStatusModel* model, QModelIndex index)
|
||||
{
|
||||
_fetched = false;
|
||||
_fetching = false;
|
||||
if (hasLabel()) {
|
||||
model->beginRemoveRows(index, 0 ,0);
|
||||
_fetchingLabel = false;
|
||||
_hasError = false;
|
||||
model->endRemoveRows();
|
||||
} else if (!_subs.isEmpty()) {
|
||||
model->beginRemoveRows(index, 0, _subs.count() - 1);
|
||||
_subs.clear();
|
||||
model->endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <accountfwd.h>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QVector>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
|
||||
class QNetworkReply;
|
||||
namespace OCC {
|
||||
@@ -51,30 +51,20 @@ public:
|
||||
|
||||
struct SubFolderInfo {
|
||||
SubFolderInfo()
|
||||
: _folder(0), _size(0), _fetched(false), _fetching(false),
|
||||
_hasError(false), _fetchingLabel(false), _isUndecided(false), _checked(Qt::Checked) {}
|
||||
: _folder(0), _size(0), _fetched(false), _fetching(false), _isUndecided(false),
|
||||
_hasError(false), _checked(Qt::Checked) {}
|
||||
Folder *_folder;
|
||||
QString _name;
|
||||
QString _path;
|
||||
QVector<int> _pathIdx;
|
||||
QVector<SubFolderInfo> _subs;
|
||||
qint64 _size;
|
||||
|
||||
bool _fetched; // If we did the LSCOL for this folder already
|
||||
bool _fetching; // Whether a LSCOL job is currently running
|
||||
bool _fetching;
|
||||
bool _isUndecided; // undecided folder are the big folder that the user has not accepted yet
|
||||
bool _hasError; // If the last fetching job ended in an error
|
||||
bool _fetchingLabel; // Whether a 'fetching in progress' label is shown.
|
||||
|
||||
bool _isUndecided; // undecided folders are the big folders that the user has not accepted yet
|
||||
|
||||
Qt::CheckState _checked;
|
||||
|
||||
// Whether this has a FetchLabel subrow
|
||||
bool hasLabel() const;
|
||||
|
||||
// Reset all subfolders and fetch status
|
||||
void resetSubs(FolderStatusModel* model, QModelIndex index);
|
||||
|
||||
struct Progress {
|
||||
Progress() : _warningCount(0), _overallPercent(0) {}
|
||||
bool isNull() const
|
||||
@@ -89,7 +79,7 @@ public:
|
||||
|
||||
QVector<SubFolderInfo> _folders;
|
||||
|
||||
enum ItemType { RootFolder, SubFolder, AddButton, FetchLabel };
|
||||
enum ItemType { RootFolder, SubFolder, AddButton, ErrorLabel };
|
||||
ItemType classify(const QModelIndex &index) const;
|
||||
SubFolderInfo *infoForIndex(const QModelIndex &index) const;
|
||||
|
||||
@@ -98,7 +88,7 @@ public:
|
||||
|
||||
/**
|
||||
* return a QModelIndex for the given path within the given folder.
|
||||
* Note: this method returns an invalid index if the path was not fetched from the server before
|
||||
* Note: this method returns an invalid index if the path was not fetch from the server before
|
||||
*/
|
||||
QModelIndex indexForPath(Folder *f, const QString &path) const;
|
||||
|
||||
@@ -115,25 +105,12 @@ private slots:
|
||||
void slotFolderScheduleQueueChanged();
|
||||
void slotNewBigFolder();
|
||||
|
||||
/**
|
||||
* "In progress" labels for fetching data from the server are only
|
||||
* added after some time to avoid popping.
|
||||
*/
|
||||
void slotShowFetchProgress();
|
||||
|
||||
private:
|
||||
QStringList createBlackList(OCC::FolderStatusModel::SubFolderInfo* root,
|
||||
const QStringList& oldBlackList) const;
|
||||
const AccountState* _accountState;
|
||||
bool _dirty; // If the selective sync checkboxes were changed
|
||||
|
||||
/**
|
||||
* Keeps track of items that are fetching data from the server.
|
||||
*
|
||||
* See slotShowPendingFetchProgress()
|
||||
*/
|
||||
QMap<QPersistentModelIndex, QElapsedTimer> _fetchingItems;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
//the roles argument was added in Qt5
|
||||
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>())
|
||||
@@ -142,9 +119,7 @@ private:
|
||||
|
||||
signals:
|
||||
void dirtyChanged();
|
||||
void suggestExpand(const QModelIndex &); // Tell the view that this item should be expanded because it has an undecided item
|
||||
|
||||
friend struct SubFolderInfo;
|
||||
void suggestExpand(const QModelIndex &); // Tell the view that this item should be expanded because it has a undecided item
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -32,14 +32,12 @@
|
||||
#include "folderwatcher_linux.h"
|
||||
#endif
|
||||
|
||||
#include "excludedfiles.h"
|
||||
#include "folder.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
FolderWatcher::FolderWatcher(const QString &root, Folder* folder)
|
||||
: QObject(folder),
|
||||
_folder(folder)
|
||||
FolderWatcher::FolderWatcher(const QString &root, QObject *parent)
|
||||
: QObject(parent),
|
||||
_ignoreHidden(true)
|
||||
{
|
||||
_d.reset(new FolderWatcherPrivate(this, root));
|
||||
|
||||
@@ -49,17 +47,81 @@ FolderWatcher::FolderWatcher(const QString &root, Folder* folder)
|
||||
FolderWatcher::~FolderWatcher()
|
||||
{ }
|
||||
|
||||
void FolderWatcher::setIgnoreHidden(bool ignore)
|
||||
{
|
||||
_ignoreHidden = ignore;
|
||||
}
|
||||
|
||||
bool FolderWatcher::ignoreHidden()
|
||||
{
|
||||
return _ignoreHidden;
|
||||
}
|
||||
|
||||
void FolderWatcher::addIgnoreListFile( const QString& file )
|
||||
{
|
||||
if( file.isEmpty() ) return;
|
||||
|
||||
QFile infile( file );
|
||||
if (!infile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return;
|
||||
|
||||
while (!infile.atEnd()) {
|
||||
QString line = QString::fromLocal8Bit( infile.readLine() ).trimmed();
|
||||
if( !(line.startsWith( QLatin1Char('#') ) || line.isEmpty()) ) {
|
||||
_ignores.append(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList FolderWatcher::ignores() const
|
||||
{
|
||||
return _ignores;
|
||||
}
|
||||
|
||||
bool FolderWatcher::pathIsIgnored( const QString& path )
|
||||
{
|
||||
if( path.isEmpty() ) return true;
|
||||
if( !_folder ) return false;
|
||||
|
||||
#ifndef OWNCLOUD_TEST
|
||||
if (_folder->isFileExcludedAbsolute(path)) {
|
||||
qDebug() << "* Ignoring file" << path;
|
||||
return true;
|
||||
// if events caused by changes to hidden files should be ignored, a QFileInfo
|
||||
// object will tell us if the file is hidden
|
||||
if( _ignoreHidden ) {
|
||||
QFileInfo fInfo(path);
|
||||
if( fInfo.isHidden() ) {
|
||||
qDebug() << "* Discarded as is hidden!" << fInfo.filePath();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Best use csync_excluded_no_ctx() here somehow!
|
||||
foreach (QString pattern, _ignores) {
|
||||
// The leading ] is a tag and not part of the pattern.
|
||||
if (pattern.startsWith(']')) {
|
||||
pattern.remove(0, 1);
|
||||
}
|
||||
|
||||
if(pattern.endsWith('/')) {
|
||||
// directory only pattern. But since path components are
|
||||
// checked later, we cut off the trailing dir.
|
||||
pattern.chop(1);
|
||||
}
|
||||
|
||||
QRegExp regexp(pattern);
|
||||
regexp.setPatternSyntax(QRegExp::Wildcard);
|
||||
|
||||
// if the pattern contains / it needs to match the entire path
|
||||
if (pattern.contains('/') && regexp.exactMatch(path)) {
|
||||
qDebug() << "* Discarded by ignore pattern: " << path;
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList components = path.split('/');
|
||||
foreach (const QString& comp, components) {
|
||||
if(regexp.exactMatch(comp)) {
|
||||
qDebug() << "* Discarded by component ignore pattern " << comp;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -75,8 +137,8 @@ void FolderWatcher::changeDetected( const QStringList& paths )
|
||||
|
||||
// TODO: this shortcut doesn't look very reliable:
|
||||
// - why is the timeout only 1 second?
|
||||
// - what if there is more than one file being updated frequently?
|
||||
// - why do we skip the file altogether instead of e.g. reducing the upload frequency?
|
||||
// - what if there are more than one file being updated frequently?
|
||||
// - why do we skip the file alltogether instead of e.g. reducing the upload frequency?
|
||||
|
||||
// Check if the same path was reported within the last second.
|
||||
QSet<QString> pathsSet = paths.toSet();
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#ifndef MIRALL_FOLDERWATCHER_H
|
||||
#define MIRALL_FOLDERWATCHER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
@@ -28,17 +30,16 @@ class QTimer;
|
||||
namespace OCC {
|
||||
|
||||
class FolderWatcherPrivate;
|
||||
class Folder;
|
||||
|
||||
/**
|
||||
* @brief Monitors a directory recursively for changes
|
||||
* @brief Montiors a directory recursively for changes
|
||||
*
|
||||
* Folder Watcher monitors a directory and its sub directories
|
||||
* for changes in the local file system. Changes are signalled
|
||||
* through the pathChanged() signal.
|
||||
*
|
||||
* Note that if new folders are created, this folderwatcher class
|
||||
* does not automatically add them to the list of monitored
|
||||
* does not automatically adds them to the list of monitored
|
||||
* dirs. That is the responsibility of the user of this class to
|
||||
* call addPath() with the new dir.
|
||||
*
|
||||
@@ -52,13 +53,23 @@ public:
|
||||
/**
|
||||
* @param root Path of the root of the folder
|
||||
*/
|
||||
FolderWatcher(const QString &root, Folder* folder = 0L);
|
||||
FolderWatcher(const QString &root, QObject *parent = 0L);
|
||||
virtual ~FolderWatcher();
|
||||
|
||||
/**
|
||||
* Set a file name to load a file with ignore patterns.
|
||||
*
|
||||
* Valid entries do not start with a hash sign (#)
|
||||
* and may contain wildcards
|
||||
*/
|
||||
void addIgnoreListFile( const QString& );
|
||||
|
||||
QStringList ignores() const;
|
||||
|
||||
/**
|
||||
* Not all backends are recursive by default.
|
||||
* Those need to be notified when a directory is added or removed while the watcher is disabled.
|
||||
* This is a no-op for backends that are recursive
|
||||
* This is a no-op for backend that are recursive
|
||||
*/
|
||||
void addPath(const QString&);
|
||||
void removePath(const QString&);
|
||||
@@ -66,6 +77,10 @@ public:
|
||||
/* Check if the path is ignored. */
|
||||
bool pathIsIgnored( const QString& path );
|
||||
|
||||
/* set if the folderwatcher ignores events of hidden files */
|
||||
void setIgnoreHidden(bool ignore);
|
||||
bool ignoreHidden();
|
||||
|
||||
signals:
|
||||
/** Emitted when one of the watched directories or one
|
||||
* of the contained files is changed. */
|
||||
@@ -84,9 +99,10 @@ protected:
|
||||
|
||||
private:
|
||||
QScopedPointer<FolderWatcherPrivate> _d;
|
||||
QStringList _ignores;
|
||||
QTime _timer;
|
||||
QSet<QString> _lastPaths;
|
||||
Folder* _folder;
|
||||
bool _ignoreHidden;
|
||||
|
||||
friend class FolderWatcherPrivate;
|
||||
};
|
||||
|
||||
@@ -53,54 +53,6 @@
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="ignoredFilesButton">
|
||||
<property name="text">
|
||||
<string>Edit Ignored Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addAccountButton">
|
||||
<property name="text">
|
||||
<string>Add an Account</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
@@ -146,20 +98,64 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<widget class="QCheckBox" name="crashreporterCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show crash reporter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="crashreporterCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<widget class="QPushButton" name="ignoredFilesButton">
|
||||
<property name="text">
|
||||
<string>Show crash reporter</string>
|
||||
<string>Edit Ignored Files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="addAccountButton">
|
||||
<property name="text">
|
||||
<string>Add an Account</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "ignorelisteditor.h"
|
||||
#include "folderman.h"
|
||||
#include "ui_ignorelisteditor.h"
|
||||
#include "excludedfiles.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
@@ -106,29 +105,25 @@ void IgnoreListEditor::slotUpdateLocalIgnoreList()
|
||||
ignores.write(prepend+patternItem->text().toUtf8()+'\n');
|
||||
}
|
||||
}
|
||||
|
||||
// We need to force a remote discovery after a change of the ignore list.
|
||||
// Otherwise we would not download the files/directories that are no longer
|
||||
// ignored (because the remote etag did not change) (issue #3172)
|
||||
foreach (Folder* folder, FolderMan::instance()->map()) {
|
||||
folder->journalDb()->forceRemoteDiscoveryNextSync();
|
||||
}
|
||||
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("Could not open file"),
|
||||
tr("Cannot write changes to '%1'.").arg(ignoreFile));
|
||||
}
|
||||
|
||||
FolderMan * folderMan = FolderMan::instance();
|
||||
|
||||
/* handle the hidden file checkbox */
|
||||
|
||||
/* the ignoreHiddenFiles flag is a folder specific setting, but for now, it is
|
||||
* handled globally. Save it to every folder that is defined.
|
||||
*/
|
||||
folderMan->setIgnoreHiddenFiles(ignoreHiddenFiles());
|
||||
|
||||
// We need to force a remote discovery after a change of the ignore list.
|
||||
// Otherwise we would not download the files/directories that are no longer
|
||||
// ignored (because the remote etag did not change) (issue #3172)
|
||||
foreach (Folder* folder, folderMan->map()) {
|
||||
folder->journalDb()->forceRemoteDiscoveryNextSync();
|
||||
folderMan->slotScheduleSync(folder);
|
||||
}
|
||||
|
||||
ExcludedFiles::instance().reloadExcludes();
|
||||
FolderMan::instance()->setIgnoreHiddenFiles(ignoreHiddenFiles());
|
||||
}
|
||||
|
||||
void IgnoreListEditor::slotAddPattern()
|
||||
|
||||
@@ -110,7 +110,7 @@ LogBrowser::LogBrowser(QWidget *parent) :
|
||||
|
||||
setModal(false);
|
||||
|
||||
// Direct connection for log coming from this thread, and queued for the one in a different thread
|
||||
// Direct connection for log comming from this thread, and queued for the one in a different thread
|
||||
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
|
||||
|
||||
QAction *showLogWindow = new QAction(this);
|
||||
|
||||
@@ -89,7 +89,6 @@ int main(int argc, char **argv)
|
||||
if(app.isRunning()) {
|
||||
qDebug() << Q_FUNC_INFO << "Already running, exiting...";
|
||||
if (app.isSessionRestored()) {
|
||||
// This call is mirrored with the one in Application::slotParseMessage
|
||||
qDebug() << "Session was restored, don't notify app!";
|
||||
return -1;
|
||||
}
|
||||
@@ -100,9 +99,8 @@ int main(int argc, char **argv)
|
||||
if(!app.sendMessage(QLatin1String("MSG_PARSEOPTIONS:") + msg))
|
||||
return -1;
|
||||
}
|
||||
if(!app.sendMessage(QLatin1String("MSG_SHOWSETTINGS"))) {
|
||||
if(!app.sendMessage(QLatin1String("MSG_SHOWSETTINGS")))
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
if (!QSystemTrayIcon::isSystemTrayAvailable()) {
|
||||
|
||||
@@ -107,7 +107,7 @@ ownCloudGui::ownCloudGui(Application *parent) :
|
||||
|
||||
// Use this to do platform specific code to make overlay icons appear
|
||||
// in the gui
|
||||
// MacOSX: perform a AppleScript code piece to load the Finder Plugin.
|
||||
// MacOSX: perform a AppleScript code peace to load the Finder Plugin.
|
||||
|
||||
|
||||
void ownCloudGui::setupOverlayIcons()
|
||||
@@ -136,7 +136,7 @@ void ownCloudGui::setupOverlayIcons()
|
||||
p.waitForFinished(5000);
|
||||
QByteArray result = p.readAll();
|
||||
QString resultAsString(result); // if appropriate
|
||||
qDebug() << "Load Finder Overlay-Plugin: " << resultAsString << ": " << p.exitCode()
|
||||
qDebug() << "Laod Finder Overlay-Plugin: " << resultAsString << ": " << p.exitCode()
|
||||
<< (p.exitCode() != 0 ? p.errorString() : QString::null);
|
||||
} else {
|
||||
qDebug() << finderExtension << "does not exist! Finder Overlay Plugin loading failed";
|
||||
@@ -269,7 +269,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
|
||||
return;
|
||||
}
|
||||
|
||||
// display the info of the least successful sync (eg. do not just display the result of the latest sync)
|
||||
// display the info of the least successful sync (eg. not just display the result of the latest sync
|
||||
QString trayMessage;
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
Folder::Map map = folderMan->map();
|
||||
@@ -317,6 +317,18 @@ void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *men
|
||||
actionOpenoC->setProperty(propertyAccountC, QVariant::fromValue(accountState->account()));
|
||||
QObject::connect(actionOpenoC, SIGNAL(triggered(bool)), SLOT(slotOpenOwnCloud()));
|
||||
|
||||
if (separateMenu) {
|
||||
if (accountState->isSignedOut()) {
|
||||
QAction* signin = menu->addAction(tr("Log in..."));
|
||||
signin->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(signin, SIGNAL(triggered()), this, SLOT(slotLogin()));
|
||||
} else {
|
||||
QAction* signout = menu->addAction(tr("Log out"));
|
||||
signout->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(signout, SIGNAL(triggered()), this, SLOT(slotLogout()));
|
||||
}
|
||||
}
|
||||
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
bool firstFolder = true;
|
||||
bool singleSyncFolder = folderMan->map().size() == 1 && Theme::instance()->singleSyncFolder();
|
||||
@@ -343,20 +355,6 @@ void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *men
|
||||
_folderOpenActionMapper->setMapping( action, folder->alias() );
|
||||
menu->addAction(action);
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
if (separateMenu) {
|
||||
if (accountState->isSignedOut()) {
|
||||
QAction* signin = menu->addAction(tr("Log in..."));
|
||||
signin->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(signin, SIGNAL(triggered()), this, SLOT(slotLogin()));
|
||||
} else {
|
||||
QAction* signout = menu->addAction(tr("Log out"));
|
||||
signout->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(signout, SIGNAL(triggered()), this, SLOT(slotLogout()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ownCloudGui::setupContextMenu()
|
||||
@@ -412,7 +410,7 @@ void ownCloudGui::setupContextMenu()
|
||||
#endif
|
||||
}
|
||||
_contextMenu->setTitle(Theme::instance()->appNameGUI() );
|
||||
// We must call deleteLater because we might be called from the press in one of the actions.
|
||||
// We must call deleteLater because we might be called from the press in one of the action.
|
||||
foreach (auto menu, _accountMenus) { menu->deleteLater(); }
|
||||
_accountMenus.clear();
|
||||
if (accountList.count() > 1) {
|
||||
@@ -446,7 +444,7 @@ void ownCloudGui::setupContextMenu()
|
||||
_contextMenu->addSeparator();
|
||||
if (atLeastOneSignedIn) {
|
||||
if (accountList.count() > 1) {
|
||||
_actionLogout->setText(tr("Log out of all accounts"));
|
||||
_actionLogout->setText(tr("Log out everywhere"));
|
||||
} else {
|
||||
_actionLogout->setText(tr("Log out"));
|
||||
}
|
||||
@@ -454,7 +452,7 @@ void ownCloudGui::setupContextMenu()
|
||||
}
|
||||
if (atLeastOneSignedOut) {
|
||||
if (accountList.count() > 1) {
|
||||
_actionLogin->setText(tr("Log in to all accounts..."));
|
||||
_actionLogin->setText(tr("Log in everywhere..."));
|
||||
} else {
|
||||
_actionLogin->setText(tr("Log in..."));
|
||||
}
|
||||
@@ -486,7 +484,7 @@ void ownCloudGui::slotShowOptionalTrayMessage(const QString &title, const QStrin
|
||||
|
||||
|
||||
/*
|
||||
* open the folder with the given Alias
|
||||
* open the folder with the given Alais
|
||||
*/
|
||||
void ownCloudGui::slotFolderOpenAction( const QString& alias )
|
||||
{
|
||||
@@ -558,7 +556,7 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo&
|
||||
Q_UNUSED(folder);
|
||||
|
||||
if (!progress._currentDiscoveredFolder.isEmpty()) {
|
||||
_actionStatus->setText( tr("Checking for changes in '%1'")
|
||||
_actionStatus->setText( tr("Discovering '%1'")
|
||||
.arg( progress._currentDiscoveredFolder ));
|
||||
} else if (progress.totalSize() == 0 ) {
|
||||
quint64 currentFile = progress.currentFile();
|
||||
@@ -580,7 +578,7 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo&
|
||||
if (!progress._lastCompletedItem.isEmpty() && !Progress::isIgnoredKind(progress._lastCompletedItem._status)) {
|
||||
|
||||
if (Progress::isWarningKind(progress._lastCompletedItem._status)) {
|
||||
// display a warn icon if warnings happened.
|
||||
// display a warn icon if warnings happend.
|
||||
QIcon warnIcon(":/client/resources/warning");
|
||||
_actionRecent->setIcon(warnIcon);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString)
|
||||
// Reset the proxy which might had been determined previously in ConnectionValidator::checkServerAndAuth()
|
||||
// when there was a previous account.
|
||||
account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||
// Set fake credentials before we check what credential it actually is.
|
||||
// Set fake credentials beforfe we check what credential it actually is.
|
||||
account->setCredentials(CredentialsFactory::create("dummy"));
|
||||
CheckServerJob *job = new CheckServerJob(_ocWizard->account(), this);
|
||||
job->setIgnoreCredentialFailure(true);
|
||||
@@ -439,7 +439,7 @@ bool OwncloudSetupWizard::ensureStartFromScratch(const QString &localFolder) {
|
||||
return renameOk;
|
||||
}
|
||||
|
||||
// Method executed when the user end has finished the basic setup.
|
||||
// Method executed when the user ends has finished the basic setup.
|
||||
void OwncloudSetupWizard::slotAssistantFinished( int result )
|
||||
{
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
|
||||
@@ -74,7 +74,7 @@ private:
|
||||
QString keychainUsernameKey() const;
|
||||
QString keychainPasswordKey() const;
|
||||
|
||||
/// The hostname:port of the current proxy, used for detecting switches
|
||||
/// The hostname:port of the current proxy, used for detetcting switches
|
||||
/// to a different proxy.
|
||||
QString _proxy;
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ void QuotaInfo::slotCheckQuota()
|
||||
|
||||
void QuotaInfo::slotUpdateLastQuota(const QVariantMap &result)
|
||||
{
|
||||
// The server can return fractional bytes (#1374)
|
||||
// The server can return frational bytes (#1374)
|
||||
// <d:quota-available-bytes>1374532061.2</d:quota-available-bytes>
|
||||
quint64 avail = result["quota-available-bytes"].toDouble();
|
||||
_lastQuotaUsedBytes = result["quota-used-bytes"].toDouble();
|
||||
|
||||
@@ -29,7 +29,7 @@ class PropfindJob;
|
||||
*
|
||||
* It is typically owned by the AccountSetting page.
|
||||
*
|
||||
* The quota is requested if these 3 conditions are met:
|
||||
* The quota is requested if those 3 conditions are met:
|
||||
* - This object is active via setActive() (typically if the settings page is visible.)
|
||||
* - The account is connected.
|
||||
* - Every 30 seconds (defaultIntervalT) or 5 seconds in case of failure (failIntervalT)
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
/**
|
||||
* When the quotainfo is active, it requests the quota at regular interval.
|
||||
* When setting it to active it will request the quota immediately if the last time
|
||||
* When setting it to active it will request the quota imediatly if the last time
|
||||
* the quota was requested was more than the interval
|
||||
*/
|
||||
void setActive(bool active);
|
||||
@@ -75,7 +75,7 @@ private:
|
||||
qint64 _lastQuotaTotalBytes;
|
||||
qint64 _lastQuotaUsedBytes;
|
||||
QTimer _jobRestartTimer;
|
||||
QDateTime _lastQuotaRecieved; // the time at which the quota was received last
|
||||
QDateTime _lastQuotaRecieved; // the time at which de quota was recieved last
|
||||
bool _active; // if we should check at regular interval (when the UI is visible)
|
||||
QPointer<PropfindJob> _job; // the currently running job
|
||||
};
|
||||
|
||||
@@ -156,9 +156,10 @@ void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList
|
||||
}
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
void SelectiveSyncTreeView::slotUpdateDirectories(const QStringList&list)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
|
||||
QScopedValueRollback<bool> isInserting(_inserting);
|
||||
_inserting = true;
|
||||
|
||||
@@ -173,29 +174,12 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
if (!_folderPath.isEmpty())
|
||||
pathToRemove.append('/');
|
||||
|
||||
// Check for excludes.
|
||||
//
|
||||
// We would like to use Folder::isFileExcluded, but the folder doesn't
|
||||
// exist yet. So we just create one temporarily...
|
||||
FolderDefinition def;
|
||||
def.localPath = pathToRemove;
|
||||
def.ignoreHiddenFiles = FolderMan::instance()->ignoreHiddenFiles();
|
||||
Folder f(def);
|
||||
QMutableListIterator<QString> it(list);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
QString path = it.value();
|
||||
path.remove(pathToRemove);
|
||||
if (f.isFileExcludedRelative(path)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Since / cannot be in the blacklist, expand it to the actual
|
||||
// list of top-level folders as soon as possible.
|
||||
if (_oldBlackList == QStringList("/")) {
|
||||
_oldBlackList.clear();
|
||||
foreach (QString path, list) {
|
||||
path.remove(pathToRemove);
|
||||
if (path.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -221,11 +205,6 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
} else {
|
||||
root->setCheckState(0, Qt::PartiallyChecked);
|
||||
}
|
||||
qint64 size = job ? job->_sizes.value(pathToRemove, -1) : -1;
|
||||
if (size >= 0) {
|
||||
root->setText(1, Utility::octetsToString(size));
|
||||
root->setData(1, Qt::UserRole, size);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (QString path, list) {
|
||||
@@ -276,7 +255,7 @@ void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
|
||||
if (item->checkState(0) == Qt::Checked) {
|
||||
// If we are checked, check that we may need to check the parent as well if
|
||||
// all the siblings are also checked
|
||||
// all the sibilings are also checked
|
||||
QTreeWidgetItem *parent = item->parent();
|
||||
if (parent && parent->checkState(0) != Qt::Checked) {
|
||||
bool hasUnchecked = false;
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
QStringList createBlackList(QTreeWidgetItem* root = 0) const;
|
||||
QStringList oldBlackList() const;
|
||||
|
||||
// Estimates the total size of checked items (recursively)
|
||||
//Estimate the total size of checked item (recursively)
|
||||
qint64 estimatedSize(QTreeWidgetItem *root = 0);
|
||||
void refreshFolders();
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
private slots:
|
||||
void slotUpdateDirectories(QStringList);
|
||||
void slotUpdateDirectories(const QStringList &);
|
||||
void slotItemExpanded(QTreeWidgetItem *);
|
||||
void slotItemChanged(QTreeWidgetItem*,int);
|
||||
void slotLscolFinishedWithError(QNetworkReply*);
|
||||
|
||||
@@ -251,7 +251,7 @@ QIcon SettingsDialog::createColorAwareIcon(const QString &name)
|
||||
{
|
||||
QColor bg(palette().base().color());
|
||||
QImage img(name);
|
||||
// account for different sensitivity of the human eye to certain colors
|
||||
// account for different sensitivty of the human eye to certain colors
|
||||
double treshold = 1.0 - ( 0.299 * bg.red() + 0.587 * bg.green() + 0.114 * bg.blue())/255.0;
|
||||
if (treshold > 0.5) {
|
||||
img.invertPixels(QImage::InvertRgb);
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace OCC {
|
||||
SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent)
|
||||
: MacPreferencesWindow(parent), _gui(gui)
|
||||
{
|
||||
// do not show minimize button. There is no use, and restoring the
|
||||
// do not show minimize button. There is no use, and retoring the
|
||||
// dialog from minimize is broken in MacPreferencesWindow
|
||||
setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint |
|
||||
Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint);
|
||||
|
||||
@@ -29,21 +29,11 @@
|
||||
#include <QBuffer>
|
||||
#include <QFileIconProvider>
|
||||
#include <QClipboard>
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace {
|
||||
int SHARETYPE_PUBLIC = 3;
|
||||
|
||||
// int PERMISSION_READ = 1;
|
||||
int PERMISSION_UPDATE = 2;
|
||||
int PERMISSION_CREATE = 4;
|
||||
// int PERMISSION_DELETE = 8;
|
||||
// int PERMISSION_SHARE = 16;
|
||||
// int PERMISSION_ALL = 31;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace OCC {
|
||||
|
||||
ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QString &localPath, bool resharingAllowed, QWidget *parent) :
|
||||
@@ -60,10 +50,6 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
||||
setObjectName("SharingDialog"); // required as group for saveGeometry call
|
||||
|
||||
_ui->setupUi(this);
|
||||
|
||||
//Is this a file or folder?
|
||||
_isFile = QFileInfo(localPath).isFile();
|
||||
|
||||
_ui->pushButton_copy->setIcon(QIcon::fromTheme("edit-copy"));
|
||||
_ui->pushButton_copy->setEnabled(false);
|
||||
connect(_ui->pushButton_copy, SIGNAL(clicked(bool)), SLOT(slotPushButtonCopyLinkPressed()));
|
||||
@@ -78,10 +64,8 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
||||
_pi_link = new QProgressIndicator();
|
||||
_pi_password = new QProgressIndicator();
|
||||
_pi_date = new QProgressIndicator();
|
||||
_pi_editing = new QProgressIndicator();
|
||||
_ui->horizontalLayout_shareLink->addWidget(_pi_link);
|
||||
_ui->horizontalLayout_password->addWidget(_pi_password);
|
||||
_ui->horizontalLayout_editing->addWidget(_pi_editing);
|
||||
// _ui->horizontalLayout_expire->addWidget(_pi_date);
|
||||
|
||||
connect(_ui->checkBox_shareLink, SIGNAL(clicked()), this, SLOT(slotCheckBoxShareLinkClicked()));
|
||||
@@ -91,7 +75,6 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
||||
connect(_ui->pushButton_setPassword, SIGNAL(clicked(bool)), SLOT(slotPasswordReturnPressed()));
|
||||
connect(_ui->checkBox_expire, SIGNAL(clicked()), this, SLOT(slotCheckBoxExpireClicked()));
|
||||
connect(_ui->calendar, SIGNAL(dateChanged(QDate)), SLOT(slotCalendarClicked(QDate)));
|
||||
connect(_ui->checkBox_editing, SIGNAL(clicked()), this, SLOT(slotCheckBoxEditingClicked()));
|
||||
|
||||
//Disable checkbox
|
||||
_ui->checkBox_shareLink->setEnabled(false);
|
||||
@@ -134,7 +117,7 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
||||
// check if the file is already inside of a synced folder
|
||||
if( sharePath.isEmpty() ) {
|
||||
// The file is not yet in an ownCloud synced folder. We could automatically
|
||||
// copy it over, but that is skipped as not all questions can be answered that
|
||||
// copy it over, but that is skipped as not all questions can be anwered that
|
||||
// are involved in that, see https://github.com/owncloud/client/issues/2732
|
||||
//
|
||||
// _ui->checkBox_shareLink->setEnabled(false);
|
||||
@@ -159,27 +142,18 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
||||
|
||||
// Parse capabilities
|
||||
|
||||
// If password is enforced then don't allow users to disable it
|
||||
if (_account->capabilities().sharePublicLinkEnforcePassword()) {
|
||||
// If password is enforced make don't allow users to disable it
|
||||
if (_account->capabilities().publicLinkEnforcePassword()) {
|
||||
_ui->checkBox_password->setEnabled(false);
|
||||
}
|
||||
|
||||
// If expiredate is enforced do not allow disable and set max days
|
||||
if (_account->capabilities().sharePublicLinkEnforceExpireDate()) {
|
||||
if (_account->capabilities().publicLinkEnforceExpireDate()) {
|
||||
_ui->checkBox_expire->setEnabled(false);
|
||||
_ui->calendar->setMaximumDate(QDate::currentDate().addDays(
|
||||
_account->capabilities().sharePublicLinkExpireDateDays()
|
||||
_account->capabilities().publicLinkExpireDateDays()
|
||||
));
|
||||
}
|
||||
|
||||
// File can't have public upload set.
|
||||
if (_isFile) {
|
||||
_ui->checkBox_editing->setEnabled(false);
|
||||
} else {
|
||||
if (!_account->capabilities().sharePublicLinkAllowUpload()) {
|
||||
_ui->checkBox_editing->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShareDialog::done( int r ) {
|
||||
@@ -250,7 +224,7 @@ void ShareDialog::slotPasswordReturnPressed()
|
||||
|
||||
void ShareDialog::slotPasswordChanged(const QString& newText)
|
||||
{
|
||||
// disable the set-password button
|
||||
// disable the set-passwort button
|
||||
_ui->pushButton_setPassword->setEnabled( newText.length() > 0 );
|
||||
}
|
||||
|
||||
@@ -381,17 +355,6 @@ void ShareDialog::slotSharesFetched(const QVariantMap &reply)
|
||||
_ui->checkBox_expire->setChecked(false);
|
||||
}
|
||||
|
||||
if (data.value("permissions").isValid()) {
|
||||
int permissions = data.value("permissions").toInt();
|
||||
/*
|
||||
* Only directories can have public upload set
|
||||
* For public links the server sets CREATE and UPDATE permissions.
|
||||
*/
|
||||
if (!_isFile && (permissions & PERMISSION_UPDATE) && (permissions & PERMISSION_CREATE)) {
|
||||
_ui->checkBox_editing->setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
QString url;
|
||||
// From ownCloud server 8.2 the url field is always set for public shares
|
||||
if (data.contains("url")) {
|
||||
@@ -503,7 +466,7 @@ void ShareDialog::slotCheckBoxShareLinkClicked()
|
||||
* Check the capabilities if the server requires a password for a share
|
||||
* Ask for it directly
|
||||
*/
|
||||
if (_account->capabilities().sharePublicLinkEnforcePassword()) {
|
||||
if (_account->capabilities().publicLinkEnforcePassword()) {
|
||||
_pi_link->stopAnimation();
|
||||
_ui->checkBox_password->setChecked(true);
|
||||
_ui->checkBox_password->setEnabled(false);
|
||||
@@ -578,7 +541,7 @@ void ShareDialog::slotCheckBoxExpireClicked()
|
||||
if (_ui->checkBox_expire->checkState() == Qt::Checked)
|
||||
{
|
||||
const QDate date = QDate::currentDate().addDays(1);
|
||||
setExpireDate(date);
|
||||
ShareDialog::setExpireDate(date);
|
||||
_ui->calendar->setDate(date);
|
||||
_ui->calendar->setMinimumDate(date);
|
||||
_ui->calendar->setEnabled(true);
|
||||
@@ -590,55 +553,10 @@ void ShareDialog::slotCheckBoxExpireClicked()
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
extern void copyToPasteboard(const QString &string);
|
||||
#endif
|
||||
|
||||
void ShareDialog::slotPushButtonCopyLinkPressed()
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
copyToPasteboard(_shareUrl);
|
||||
#else
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setText(_shareUrl);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ShareDialog::slotCheckBoxEditingClicked()
|
||||
{
|
||||
ShareDialog::setPublicUpload(_ui->checkBox_editing->checkState() == Qt::Checked);
|
||||
}
|
||||
|
||||
void ShareDialog::setPublicUpload(bool publicUpload)
|
||||
{
|
||||
_ui->checkBox_editing->setEnabled(false);
|
||||
_pi_editing->startAnimation();
|
||||
|
||||
const QUrl url = Account::concatUrlPath(_account->url(), QString("ocs/v1.php/apps/files_sharing/api/v1/shares/%1").arg(_public_share_id));
|
||||
|
||||
QList<QPair<QString, QString> > requestParams;
|
||||
const QString value = QString::fromLatin1(publicUpload ? "true" : "false");
|
||||
requestParams.append(qMakePair(QString::fromLatin1("publicUpload"), value));
|
||||
|
||||
OcsShareJob *job = new OcsShareJob("PUT", url, _account, this);
|
||||
job->setPostParams(requestParams);
|
||||
connect(job, SIGNAL(jobFinished(QVariantMap)), this, SLOT(slotPublicUploadSet(QVariantMap)));
|
||||
|
||||
job->start();
|
||||
}
|
||||
|
||||
void ShareDialog::slotPublicUploadSet(const QVariantMap &reply)
|
||||
{
|
||||
QString message;
|
||||
int code = getJsonReturnCode(reply, message);
|
||||
if (code == 100) {
|
||||
_ui->checkBox_editing->setEnabled(true);
|
||||
} else {
|
||||
qDebug() << Q_FUNC_INFO << reply;
|
||||
displayError(code);
|
||||
}
|
||||
|
||||
_pi_editing->stopAnimation();
|
||||
}
|
||||
|
||||
void ShareDialog::setShareCheckBoxTitle(bool haveShares)
|
||||
@@ -721,7 +639,7 @@ bool ShareDialog::uploadExternalFile()
|
||||
_ui->label_sharePath->setText(tr("A sync file with the same name exists. "
|
||||
"The file cannot be registered to sync."));
|
||||
// TODO: Add a file comparison here. If the existing file is still the same
|
||||
// as the file-to-copy we can share it.
|
||||
// then the file-to-copy we can share it.
|
||||
_sharePath.clear();
|
||||
} else {
|
||||
_uploadFails = 0;
|
||||
|
||||