diff --git a/.gitignore b/.gitignore index 3bbef6e..c1165b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,75 +1,70 @@ build/ demo/3rdparty/ demo/mauikit/ *.kdev4 *.directory *.*~ *.properties .*.kate-swp .swp.* #android stuff -src/android/AndroidManifest.xml -src/android/res/* -src/android/gradle/* -src/android/gradle* -src/android/build.gradle -src/android/icons/luv-icon-theme/ +luv-icon-theme/ #third party stuff src/utils/editor/KSyntaxHighlighting/ src/utils/editor/kquicksyntaxhighlighter/ src/utils/store/attica/ src/utils/syncing/openssl/ #.* *.*~ ~*.* ~.* # C++ objects and libs *.slo *.lo *.o *.a *.la *.lai *.so *.dll *.dylib # Qt-es object_script.*.Release object_script.*.Debug *_plugin_import.cpp /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.qbs.user *.qbs.user.* *.moc moc_*.cpp moc_*.h qrc_*.cpp ui_*.h *.qmlc *.jsc Makefile* *build-* # Qt unit tests target_wrapper.* # QtCreator *.autosave # QtCreator Qml *.qmlproject.user *.qmlproject.user.* # QtCreator CMake CMakeLists.txt.user* diff --git a/CMakeLists.txt b/CMakeLists.txt index 835fa28..b0ff201 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,359 +1,81 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.12) -set(REQUIRED_QT_VERSION 5.8.0) +set(REQUIRED_QT_VERSION 5.10.0) +set(REQUIRED_KF5_VERSION 5.60.0) set(CMAKE_CXX_STANDARD 17) -set(MAUIKIT_VERSION 0.0.5) - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) +set(MAUIKIT_VERSION 1.0.0) set(AUTOMOC_MOC_OPTIONS -Muri=org.kde.maui) -set(CMAKE_INCLUDE_CURRENT_DIR ON) project(mauikit VERSION ${MAUIKIT_VERSION}) find_package(ECM 5.45.0 NO_MODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} - ${ECM_KDE_MODULE_DIR}) - + ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) + +#DEFAULT COMPONENTS DEFINITIONS +option(COMPONENT_EDITOR "Build editor component" ON) +option(COMPONENT_FM "Build filemanager component" ON) +option(COMPONENT_ACCOUNTS "Build accounts component" ON) +option(COMPONENT_TERMINAL "Build terminal component" ON) +option(COMPONENT_STORE "Build store component" ON) +option(COMPONENT_TAGGING "Build tagging component" ON) +option(COMPONENT_SYNCING "Build syncing component" ON) + include(GenerateExportHeader) include(ECMSetupVersion) include(ECMGenerateHeaders) include(CMakePackageConfigHelpers) include(ECMPoQmTools) include(ECMQMLModules) include(KDEInstallDirs) include(KDECMakeSettings) include(ECMQtDeclareLoggingCategory) include(ECMAddQch) include(KDECompilerSettings NO_POLICY_SCOPE) -#options - for the appimage find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE COMPONENTS Qml Sql Core Quick Gui Svg QuickControls2 Network DBus Xml) ecm_find_qmlmodule(QtGraphicalEffects 1.0) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/src - ${CMAKE_CURRENT_BINARY_DIR}/src - - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils - ${CMAKE_CURRENT_BINARY_DIR}/src/utils - - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/model_template - ${CMAKE_CURRENT_BINARY_DIR}/src/utils/model_template - - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/tagging - ${CMAKE_CURRENT_BINARY_DIR}/src/utils/tagging - - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/editor - ${CMAKE_CURRENT_BINARY_DIR}/src/utils/editor - - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/syncing - ${CMAKE_CURRENT_BINARY_DIR}/src/utils/syncing - - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/store - ${CMAKE_CURRENT_BINARY_DIR}/src/utils/store - - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/syncing/libwebdavclient/lib - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/syncing/libwebdavclient/lib/utils - ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/syncing/libwebdavclient/lib/dto - - ${CMAKE_CURRENT_SOURCE_DIR}/src/fm - ${CMAKE_CURRENT_BINARY_DIR}/src/fm - - ${CMAKE_CURRENT_SOURCE_DIR}/src/kde - ${CMAKE_CURRENT_BINARY_DIR}/src/kde - ) - -set(mauikit_SRCS - src/mauikit.cpp - src/utils/mauiapp.cpp - src/utils/mauiaccounts.cpp - src/utils/handy.cpp - src/utils/model_template/mauilist.cpp - src/utils/model_template/mauimodel.cpp - ) - -set(mauikit_HDRS - src/mauikit.h - src/utils.h - src/utils/handy.h - src/utils/mauiapp.h - src/utils/mauiaccounts.h - src/utils/model_template/mauilist.h - src/utils/model_template/mauimodel.h - ) - -set(editor_SRCS - src/utils/editor/documenthandler.cpp - src/utils/editor/syntaxhighlighterutil.cpp - ) - -set(editor_HDRS - src/utils/editor/documenthandler.cpp - src/utils/editor/syntaxhighlighterutil.h - ) - -set(fm_SRCS - src/fm/fm.cpp - src/fm/fmdb.cpp - src/fm/fmlist.cpp - src/fm/placeslist.cpp - src/fm/pathlist.cpp - ) - -set(fm_HDRS - src/fm/fmh.h - src/fm/fm.h - src/fm/fmdb.h - src/fm/fmlist.h - src/fm/placeslist.h - src/fm/pathlist.h - ) - -set(tagging_SRCS - src/utils/tagging/tagging.cpp - src/utils/tagging/tagdb.cpp - src/utils/tagging/tagsmodel.cpp - src/utils/tagging/tagslist.cpp - ) - -set(tagging_HDRS - src/utils/tagging/tag.h - src/utils/tagging/tagging.h - src/utils/tagging/tagdb.h - src/utils/tagging/tagsmodel.h - src/utils/tagging/tagslist.h - ) - -set(syncing_SRCS - src/utils/syncing/syncing.cpp - src/utils/syncing/libwebdavclient/lib/WebDAVClient.cpp - src/utils/syncing/libwebdavclient/lib/dto/WebDAVItem.cpp - src/utils/syncing/libwebdavclient/lib/utils/Environment.cpp - src/utils/syncing/libwebdavclient/lib/utils/NetworkHelper.cpp - src/utils/syncing/libwebdavclient/lib/utils/WebDAVReply.cpp - src/utils/syncing/libwebdavclient/lib/utils/XMLHelper.cpp - ) - -set(syncing_HDRS - src/utils/syncing/syncing.h - src/utils/syncing/libwebdavclient/lib/WebDAVClient.hpp - src/utils/syncing/libwebdavclient/lib/dto/WebDAVItem.hpp - src/utils/syncing/libwebdavclient/lib/utils/Environment.hpp - src/utils/syncing/libwebdavclient/lib/utils/NetworkHelper.hpp - src/utils/syncing/libwebdavclient/lib/utils/WebDAVReply.hpp - src/utils/syncing/libwebdavclient/lib/utils/XMLHelper.hpp - ) - -set(store_SRCS - src/utils/store/store.cpp - src/utils/store/storemodel.cpp - src/utils/store/storelist.cpp - ) - -set(store_HDRS - src/utils/store/store.h - src/utils/store/storemodel.h - src/utils/store/storelist.h - ) - - -#use dbus on linux, bsd etc, but not andoid and apple stuff -option(IS_APPIMAGE_PACKAGE "If set to true then the icons and styled is packaged as well") - -if(ANDROID OR IS_APPIMAGE_PACKAGE) - qt5_add_resources(MauiIcon_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/android/icons.qrc) - qt5_add_resources(MauiStyle_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/maui-style/style.qrc) - - if (NOT EXISTS ${CMAKE_SOURCE_DIR}/src/android/icons/luv-icon-theme/.git) - find_package(Git REQUIRED) - execute_process(COMMAND ${GIT_EXECUTABLE} clone --depth 1 https://github.com/Nitrux/luv-icon-theme.git ${CMAKE_SOURCE_DIR}/src/android/icons/luv-icon-theme) - endif() - - set(mauikit_style_QRCS - ${MauiIcon_RESOURCES} - ${MauiStyle_RESOURCES} - ) -endif() - if(ANDROID) - find_package(Qt5 REQUIRED COMPONENTS AndroidExtras Xml WebView Network) - set(MAUIANDROID_LIBS - Qt5::Xml - Qt5::AndroidExtras - Qt5::Network - Qt5::WebView - ) - - set(mauikit_Android_SRCS - src/android/mauiandroid.cpp - ) + find_package(Qt5 REQUIRED COMPONENTS AndroidExtras WebView) + find_package(Gradle REQUIRED) else() find_package(Qt5 REQUIRED COMPONENTS WebEngine) - find_package(KF5 ${KF5_VERSION} REQUIRED COMPONENTS I18n Notifications Config Service KIO ConfigWidgets Attica SyntaxHighlighting) - - set(mauikit_KDE_SRCS - src/kde/mauikde.cpp - src/kde/kdeconnect.cpp - ) - - set(mauikit_KDE_HDRS - src/kde/mauikde.h - src/kde/kdeconnect.h - ) - - set(MAUIKDE_KF5LIBS - KF5::ConfigCore - KF5::Notifications - KF5::I18n - KF5::Service - KF5::KIOCore - KF5::KIOWidgets - KF5::KIOFileWidgets - KF5::Service - KF5::KIONTLM - KF5::ConfigWidgets - KF5::Attica - KF5::SyntaxHighlighting - Qt5::WebEngine -# /usr/lib/x86_64-linux-gnu/qt5/qml/org/kde/kquicksyntaxhighlighter/libkquicksyntaxhighlighterplugin.so - ) -endif() -# set(CMAKE_AUTORCC ON) - -qt5_add_resources(mauikit_ASSETS ${CMAKE_CURRENT_SOURCE_DIR}/assets.qrc) -qt5_add_resources(tagging_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/tagging/tagging.qrc) -qt5_add_resources(fm_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/fm/fm.qrc) -qt5_add_resources(store_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/store/store.qrc) - -# qt5_add_resources(mauikit_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/mauikit.qrc) - -add_library(MauiKit - - ${fm_HDRS} - ${fm_SRCS} - ${fm_RESOURCES} - - ${editor_HDRS} - ${editor_SRCS} - - ${syncing_HDRS} - ${syncing_SRCS} - - ${store_SRCS} - ${store_HDRS} - ${store_RESOURCES} - - ${tagging_HDRS} - ${tagging_SRCS} - ${tagging_RESOURCES} - - ${mauikit_HDRS} - ${mauikit_SRCS} - ${mauikit_RESOURCES} - ${mauikit_ASSETS} - ${MauiIcon_RESOURCES} - ${MauiStyle_RESOURCES} - - ${mauikit_Android_SRCS} - - ${mauikit_KDE_HDRS} - ${mauikit_KDE_SRCS} - ) - -target_link_libraries(MauiKit - PUBLIC - Qt5::Core - Qt5::Sql - Qt5::Qml - Qt5::Quick - Qt5::QuickControls2 - Qt5::Svg - Qt5::Gui - Qt5::Network - Qt5::Xml - ${MAUIKDE_KF5LIBS} - ${MAUIANDROID_LIBS} -# # webdavclient - ) - -if(IS_APPIMAGE_PACKAGE) - target_compile_definitions(MauiKit PUBLIC APPIMAGE_PACKAGE) -endif() - -if (ANDROID) - kde_enable_exceptions(MauiKit PRIVATE) - target_include_directories(MauiKit PRIVATE src/android) - install(FILES src/android/mauiandroid.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/MauiKit COMPONENT Devel) - - install(DIRECTORY src/android/ DESTINATION ${KDE_INSTALL_DATAROOTDIR}/MauiKitAndroid COMPONENT Devel) endif() -generate_export_header(MauiKit BASE_NAME MauiKit) -install(TARGETS MauiKit EXPORT MauiKitTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) - -target_include_directories(MauiKit - INTERFACE "$") - -add_custom_target(copy) - -file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/org/kde/mauikit) -add_custom_command(TARGET copy PRE_BUILD COMMAND ${CMAKE_COMMAND} - -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/src/controls - ${CMAKE_BINARY_DIR}/bin/org/kde/mauikit/) - -add_dependencies(MauiKit copy) - -install(DIRECTORY src/controls/ DESTINATION - ${KDE_INSTALL_QMLDIR}/org/kde/mauikit) - -install(TARGETS MauiKit DESTINATION - ${KDE_INSTALL_QMLDIR}/org/kde/mauikit) - -install(FILES - ${mauikit_HDRS} - ${mauikit_KDE_HDRS} - ${tagging_HDRS} - ${fm_HDRS} - ${syncing_HDRS} - ${store_HDRS} - ${CMAKE_CURRENT_BINARY_DIR}/mauikit_export.h - DESTINATION ${KDE_INSTALL_INCLUDEDIR}/MauiKit - COMPONENT Devel) - -##INSTALL MAUI STYLE -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/maui-style DESTINATION ${KDE_INSTALL_QMLDIR}/QtQuick/Controls.2) +find_package(KF5 ${REQUIRED_KF5_VERSION} REQUIRED COMPONENTS I18n Notifications Config Service KIO ConfigWidgets) -##CMAKE PARTS +add_subdirectory(src) +##CMAKE PARTS set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/MauiKit") ecm_setup_version(${MAUIKIT_VERSION} VARIABLE_PREFIX MAUIKIT VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/mauikit_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/MauiKitConfigVersion.cmake" SOVERSION 5 ) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/MauiKitConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/MauiKitConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} PATH_VARS KF5_INCLUDE_INSTALL_DIR CMAKE_INSTALL_PREFIX ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/MauiKitConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/MauiKitConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT MauiKitTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE MauiKitTargets.cmake ) diff --git a/PKBUILD b/PKBUILD deleted file mode 100644 index 0f1a7a0..0000000 --- a/PKBUILD +++ /dev/null @@ -1,32 +0,0 @@ -pkgname=mauikit-git -pkgver=r210.32b20e6 -pkgrel=1 -pkgdesc='Utilities and "templated" controls based on Kirigami and QCC2 that follow the ongoing work on the Maui HIG' -arch=(x86_64 i686 arm armv6h armv7h aarch64) -url="https://mauikit.org/" -license=(GPL3) -depends=(qt5-base qt5-declarative qt5-svg qt5-quickcontrols2 kio) -makedepends=(git cmake extra-cmake-modules qt5-webengine) -provides=(mauikit) -conflicts=(mauikit) -source=("${pkgname}::git+https://invent.kde.org/mauikit") -sha256sums=('SKIP') - -pkgver() { - cd "$pkgname" - printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" -} - -build() { - cd "$pkgname" - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_INSTALL_LIBDIR=/usr/lib - make -} - -package() { - cd "$pkgname" - make DESTDIR="$pkgdir" install -} diff --git a/assets/tag.svg b/assets/tag.svg deleted file mode 100644 index 8e58bb4..0000000 --- a/assets/tag.svg +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/cmake/modules/FindGradle.cmake b/cmake/modules/FindGradle.cmake new file mode 100644 index 0000000..9cfe43b --- /dev/null +++ b/cmake/modules/FindGradle.cmake @@ -0,0 +1,108 @@ +#.rst: +# FindGradle +# ---------- +# +# Provides the ability to build Android AAR libraries using Gradle. +# +# This relies on the Qt provided Gradle, so a Qt for Android installation +# is required. +# +# gradle_add_aar( +# BUIDLFILE build.gradle +# NAME ) +# +# This builds an Android AAR library using the given ``build.gradle`` file. +# +# gradle_install_aar( +# DESTINATION ) +# +# Installs a Android AAR library that has been created with ``gradle_add_aar``. + +#============================================================================= +# Copyright (c) 2019 Volker Krause +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +include(CMakeParseArguments) +include(FindPackageHandleStandardArgs) + +find_package(Qt5Core REQUIRED) + +if (NOT WIN32) + set(Gradle_EXECUTABLE ${CMAKE_BINARY_DIR}/gradle/gradlew) +else() + set(Gradle_EXECUTABLE ${CMAKE_BINARY_DIR}/gradle/gradlew.bat) +endif() + +get_target_property(_qt_core_location Qt5::Core LOCATION) +get_filename_component(_qt_install_root ${_qt_core_location} DIRECTORY) +get_filename_component(_qt_install_root ${_qt_install_root}/../ ABSOLUTE) + +set(_gradle_template_dir ${CMAKE_CURRENT_LIST_DIR}) + +add_custom_command(OUTPUT ${Gradle_EXECUTABLE} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/gradle + COMMAND ${CMAKE_COMMAND} -E copy_directory ${_qt_install_root}/src/3rdparty/gradle ${CMAKE_BINARY_DIR}/gradle +) +add_custom_target(gradle DEPENDS ${Gradle_EXECUTABLE}) + +find_package_handle_standard_args(Gradle DEFAULT_MSG Gradle_EXECUTABLE) + +function(gradle_add_aar target) + cmake_parse_arguments(ARG "" "BUILDFILE;NAME" "" ${ARGN}) + + set(_build_root ${CMAKE_CURRENT_BINARY_DIR}/gradle_build/${ARG_NAME}) + configure_file(${_gradle_template_dir}/local.properties.in ${_build_root}/local.properties) + configure_file(${_gradle_template_dir}/settings.gradle.in ${_build_root}/settings.gradle) + message(Foo ${ARG_BUILDFILE} ${_build_root}) + configure_file(${ARG_BUILDFILE} ${_build_root}/build.gradle) + + if (CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]") + set(_aar_suffix "-debug") + set(_aar_gradleCmd "assembleDebug") + else() + set(_aar_suffix "-release") + set(_aar_gradleCmd "assembleRelease") + endif() + + file(GLOB_RECURSE _src_files CONFIGURE_DEPENDS "*") + add_custom_command( + OUTPUT ${_build_root}/build/outputs/aar/${ARG_NAME}${_aar_suffix}.aar + COMMAND ${Gradle_EXECUTABLE} ${_aar_gradleCmd} + DEPENDS ${Gradle_EXECUTABLE} ${_src_files} + DEPENDS gradle + WORKING_DIRECTORY ${_build_root} + ) + add_custom_target(${target} ALL DEPENDS ${_build_root}/build/outputs/aar/${ARG_NAME}${_aar_suffix}.aar) + set_target_properties(${target} PROPERTIES LOCATION ${_build_root}/build/outputs/aar/${ARG_NAME}${_aar_suffix}.aar) + set_target_properties(${target} PROPERTIES OUTPUT_NAME ${ARG_NAME}) +endfunction() + +function(gradle_install_aar target) + cmake_parse_arguments(ARG "" "DESTINATION" "" ${ARGN}) + get_target_property(_loc ${target} LOCATION) + get_target_property(_name ${target} OUTPUT_NAME) + install(FILES ${_loc} DESTINATION ${ARG_DESTINATION} RENAME ${_name}.aar) +endfunction() diff --git a/cmake/modules/local.properties.in b/cmake/modules/local.properties.in new file mode 100644 index 0000000..4f14cc3 --- /dev/null +++ b/cmake/modules/local.properties.in @@ -0,0 +1 @@ +sdk.dir=@ANDROID_SDK_ROOT@ diff --git a/cmake/modules/settings.gradle.in b/cmake/modules/settings.gradle.in new file mode 100644 index 0000000..6628d9e --- /dev/null +++ b/cmake/modules/settings.gradle.in @@ -0,0 +1 @@ +rootProject.name = '@ARG_NAME@' diff --git a/mauikit.pri b/mauikit.pri index 9055a34..c92ad8f 100644 --- a/mauikit.pri +++ b/mauikit.pri @@ -1,205 +1,311 @@ -QT += \ +QT *= \ core \ qml \ quick \ gui \ svg \ - concurrent \ + concurrent -CONFIG += c++17 +CONFIG *= c++17 + +DEFINES *= \ + MAUI_APP \ + STATIC_MAUIKIT \ + ANDROID_OPENSSL \ + MAUIKIT_STYLE + + +#REPO VARIABLES +LUV_REPO = https://github.com/milohr/luv-icon-theme +OPENSSL_REPO = https://github.com/mauikit/openssl +ATTICA_REPO = https://github.com/mauikit/attica +KQUICKSYNTAXHIGHLIGHTER_REPO = https://github.com/mauikit/kquicksyntaxhighlighter.git +KSYNTAXHIGHLIGHTING_REPO = https://github.com/mauikit/KSyntaxHighlighting.git + +#ANDROID FILES VALUES +ANDROID_FILES_DIR = $$_PRO_FILE_PWD_/android_files +ANDROID_FILES_MANIFEST = $$_PRO_FILE_PWD_/android_files/AndroidManifest.xml +ANDROID_FILES_GRADLE = $$_PRO_FILE_PWD_/android_files/build.gradle +ANDROID_FILES_RES_DIR = $$_PRO_FILE_PWD_/android_files/res linux:unix:!android { message(Building Maui helpers for Linux KDE) include($$PWD/src/kde/kde.pri) } else:android { message(Building Maui helpers for Android) - include($$PWD/src/android/android.pri) - include($$PWD/src/utils/editor/syntaxhighlighter.pri) - include($$PWD/src/utils/syncing/openssl/openssl.pri) - include($$PWD/src/utils/syncing/libwebdavclient/webdavclient.pri) - include($$PWD/src/utils/store/attica/attica.pri) - + + include($$PWD/src/android/android.pri) + + contains(DEFINES, ANDROID_OPENSSL):{ + exists($$PWD/src/utils/syncing/openssl/openssl.pri) { + message("Using OpenSSL for Android") + include($$PWD/src/utils/syncing/openssl/openssl.pri) + }else { + message("Getting OpenSSL for Android") + system(git clone $$OPENSSL_REPO $$PWD/src/utils/syncing/openssl) + include($$PWD/src/utils/syncing/openssl/openssl.pri) + } + } + + contains(DEFINES, COMPONENT_EDITOR):{ + include($$PWD/src/utils/editor/syntaxhighlighter.pri) + } + + contains(DEFINES, COMPONENT_STORE):{ + exists($$PWD/src/utils/store/attica/attica.pri):{ + message("Using Attica for Android") + include($$PWD/src/utils/store/attica/attica.pri) + }else { + message("Getting Attica for Android") + system(git clone $$ATTICA_REPO $$PWD/src/utils/store/attica) + include($$PWD/src/utils/store/attica/attica.pri) + } + } + + contains(DEFINES, COMPONENT_SYNCING):{ + include($$PWD/src/utils/syncing/libwebdavclient/webdavclient.pri) + } + } else { message("Unknown configuration") } -include($$PWD/src/utils/tagging/tagging.pri) +contains(DEFINES, COMPONENT_TAGGING):{ + message("INCLUDING TAGGING COMPONENT") + include($$PWD/src/utils/tagging/tagging.pri) +} else { + warning("SKIPPING TAGGING COMPONENT") +} + +contains(DEFINES, COMPONENT_EDITOR):{ + message("INCLUDING EDITOR COMPONENT") + + HEADERS += \ + $$PWD/src/utils/editor/documenthandler.h \ + $$PWD/src/utils/editor/syntaxhighlighterutil.h + + SOURCES += \ + $$PWD/src/utils//editor/documenthandler.cpp \ + $$PWD/src/utils/editor/syntaxhighlighterutil.cpp + + INCLUDEPATH += $$PWD/src/utils/editor +} else { + warning("SKIPPING EDITOR COMPONENT") +} + +contains(DEFINES, COMPONENT_STORE):{ + message("INCLUDING STORE COMPONENT") + + HEADERS += \ + $$PWD/src/utils/store/store.h \ + $$PWD/src/utils/store/storemodel.h \ + $$PWD/src/utils/store/storelist.h + + SOURCES += \ + $$PWD/src/utils/store/store.cpp \ + $$PWD/src/utils/store/storemodel.cpp \ + $$PWD/src/utils/store/storelist.cpp + + RESOURCES += $$PWD/src/utils/store/store.qrc + + INCLUDEPATH += $$PWD/src/utils/store +} else { + warning("SKIPPING STORE COMPONENT") +} + +contains(DEFINES, COMPONENT_SYNCING):{ + message("INCLUDING SYNCING COMPONENT") + + HEADERS += $$PWD/src/utils/syncing/syncing.h + SOURCES += $$PWD/src/utils/syncing/syncing.cpp + INCLUDEPATH += $$PWD/src/utils/syncing +} else { + warning("SKIPPING SYNCING COMPONENT") +} + +contains(DEFINES, COMPONENT_ACCOUNTS):{ + message("INCLUDING ACCOUNTS COMPONENT") + QT += sql + HEADERS += \ + $$PWD/src/utils/accounts/mauiaccounts.h \ + $$PWD/src/utils/accounts/accountsdb.h \ + + SOURCES += \ + $$PWD/src/utils/accounts/mauiaccounts.cpp\ + $$PWD/src/utils/accounts/accountsdb.cpp + + RESOURCES += $$PWD/src/utils/accounts/accounts.qrc + DISTFILES += $$PWD//src/utils/accounts/script.sql + + INCLUDEPATH += $$PWD/src/utils/accounts + DEPENDPATH += $$PWD/src/utils/accounts + +} else { + warning("SKIPPING ACCOUNTS COMPONENT") +} + +contains(DEFINES, COMPONENT_FM):{ + message("INCLUDING FM COMPONENT") + HEADERS += \ + $$PWD/src/fm/fm.h \ + $$PWD/src/fm/fmlist.h \ + $$PWD/src/fm/placeslist.h + + SOURCES += \ + $$PWD/src/fm/fm.cpp \ + $$PWD/src/fm/fmlist.cpp \ + $$PWD/src/fm/placeslist.cpp + + INCLUDEPATH += $$PWD/src/fm + DEPENDPATH += $$PWD/src/fm +} else { + warning("SKIPPING FM COMPONENT") +} RESOURCES += \ $$PWD/mauikit.qrc \ - $$PWD/assets.qrc \ - $$PWD/src/fm/fm.qrc \ - $$PWD/src/utils/store/store.qrc \ + $$PWD/assets.qrc \ $$PWD/maui-style/style.qrc HEADERS += \ + $$PWD/src/utils/fmstatic.h \ $$PWD/src/mauikit.h \ - $$PWD/src/fm/fm.h \ - $$PWD/src/fm/fmh.h \ - $$PWD/src/fm/fmdb.h \ - $$PWD/src/fm/fmlist.h \ - $$PWD/src/fm/pathlist.h \ - $$PWD/src/fm/placeslist.h \ + $$PWD/src/utils/fmh.h \ $$PWD/src/utils/model_template/mauimodel.h \ $$PWD/src/utils/model_template/mauilist.h \ - $$PWD/src/utils/editor/documenthandler.h \ - $$PWD/src/utils/editor/syntaxhighlighterutil.h \ $$PWD/src/utils/handy.h \ + $$PWD/src/utils/utils.h \ $$PWD/src/utils/mauiapp.h \ - $$PWD/src/utils/mauiaccounts.h \ - $$PWD/src/utils/syncing/syncing.h \ - $$PWD/src/utils/store/store.h \ - $$PWD/src/utils/store/storemodel.h \ - $$PWD/src/utils/store/storelist.h + $$PWD/src/utils/models/pathlist.h SOURCES += \ + $$PWD/src/utils/fmstatic.cpp \ $$PWD/src/mauikit.cpp \ - $$PWD/src/fm/fm.cpp \ - $$PWD/src/fm/fmdb.cpp \ - $$PWD/src/fm/fmlist.cpp \ - $$PWD/src/fm/pathlist.cpp \ - $$PWD/src/fm/placeslist.cpp \ $$PWD/src/utils/model_template/mauimodel.cpp \ $$PWD/src/utils/model_template/mauilist.cpp \ - $$PWD/src/utils//editor/documenthandler.cpp \ - $$PWD/src/utils/editor/syntaxhighlighterutil.cpp \ $$PWD/src/utils/handy.cpp \ $$PWD/src/utils/mauiapp.cpp \ - $$PWD/src/utils/mauiaccounts.cpp \ - $$PWD/src/utils/syncing/syncing.cpp \ - $$PWD/src/utils/store/store.cpp \ - $$PWD/src/utils/store/storemodel.cpp \ - $$PWD/src/utils/store/storelist.cpp + $$PWD/src/utils/models/pathlist.cpp DEPENDPATH += \ $$PWD/src \ - $$PWD/src/fm \ $$PWD/src/utils/model_template INCLUDEPATH += \ $$PWD/src \ - $$PWD/src/fm \ $$PWD/src/utils \ - $$PWD/src/utils/editor \ - $$PWD/src/utils/syncing \ - $$PWD/src/utils/model_template \ - $$PWD/src/utils/store - -DEFINES += \ - MAUI_APP \ - STATIC_MAUIKIT + $$PWD/src/utils/models \ + $$PWD/src/utils/model_template API_VER = 1.0 DISTFILES += \ $$PWD/CMakeLists.txt #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5KIOFileWidgets.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5KIOWidgets.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Bookmarks.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Solid.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5XmlGui.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5IconThemes.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5KIOCore.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5JobWidgets.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Service.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Completion.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ItemViews.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ConfigWidgets.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5I18n.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5WidgetsAddons.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5Codecs.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ConfigGui.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ConfigCore.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libKF5ConfigCore.so #ANDROID_EXTRA_LIBS += $$PWD/libs/bin/libdbus-1.so ##KIOFileWidgets #LIBS += -L$$PWD/libs/bin/ -lKF5KIOFileWidgets #INCLUDEPATH += $$PWD/libs/includes/KIOFileWidgets #DEPENDPATH += $$PWD/libs/includes/KIOFileWidgets ##KBookmarks #LIBS += -L$$PWD/libs/bin/ -lKF5Bookmarks #INCLUDEPATH += $$PWD/libs/includes/KBookmarks #DEPENDPATH += $$PWD/libs/includes/KBookmarks ##KSolid #LIBS += -L$$PWD//libs/bin/ -lKF5Solid #INCLUDEPATH += $$PWD//libs/includes/Solid #DEPENDPATH += $$PWD/libs/includes/Solid ##KIOWidgets #LIBS += -L$$PWD/libs/bin/ -lKF5KIOWidgets #INCLUDEPATH += $$PWD/libs/includes/KIOWidgets #DEPENDPATH += $$PWD/libs/includes/KIOWidgets ##KXmlGui #LIBS += -L$$PWD/libs/bin/ -lKF5XmlGui #INCLUDEPATH += $$PWD/libs/includes/KXmlGui #DEPENDPATH += $$PWD/libs/includes/KXmlGui ##KIconThemes #LIBS += -L$$PWD/libs/bin/ -lKF5IconThemes #INCLUDEPATH += $$PWD/libs/includes/KIconThemes #DEPENDPATH += $$PWD/libs/includes/KIconThemes ##KIOCore #LIBS += -L$$PWD/libs/bin/ -lKF5KIOCore #INCLUDEPATH += $$PWD/libs/includes/KIOCore #DEPENDPATH += $$PWD/libs/includes/KIOCore ##KJobWidgets #LIBS += -L$$PWD/libs/bin/ -lKF5JobWidgets #INCLUDEPATH += $$PWD/libs/includes/KJobWidgets #DEPENDPATH += $$PWD/libs/includes/KJobWidgets ##KService #LIBS += -L$$PWD/libs/bin/ -lKF5Service #INCLUDEPATH += $$PWD/libs/includes/KService #DEPENDPATH += $$PWD/libs/includes/KService ##KCompletion #LIBS += -L$$PWD/libs/bin/ -lKF5Completion #INCLUDEPATH += $$PWD/libs/includes/KCompletion #DEPENDPATH += $$PWD/libs/includes/KCompletion ##KItemViews #LIBS += -L$$PWD/libs/bin/ -lKF5ItemViews #INCLUDEPATH += $$PWD/libs/includes/KItemViews #DEPENDPATH += $$PWD/libs/includes/KItemViews ##KConfigWidgets #LIBS += -L$$PWD/libs/bin/ -lKF5ConfigWidgets #INCLUDEPATH += $$PWD/libs/includes/KConfigWidgets #DEPENDPATH += $$PWD/libs/includes/KConfigWidgets ##KI18n #LIBS += -L$$PWD/libs/bin/ -lKF5I18n #INCLUDEPATH += $$PWD/libs/includes/KI18n #DEPENDPATH += $$PWD/libs/includes/KI18n ##KWidgetsAddons #LIBS += -L$$PWD/libs/bin/ -lKF5WidgetsAddons #INCLUDEPATH += $$PWD/libs/includes/KWidgetsAddons #DEPENDPATH += $$PWD/libs/includes/KWidgetsAddons ##KCodecs #LIBS += -L$$PWD/libs/bin/ -lKF5Codecs #INCLUDEPATH += $$PWD/libs/includes/KCodecs #DEPENDPATH += $$PWD/libs/includes/KCodecs ##KConfigGui #LIBS += -L$$PWD/libs/bin/ -lKF5ConfigGui #INCLUDEPATH += $$PWD/libs/includes/KConfigGui #DEPENDPATH += $$PWD/libs/includes/KConfigGui ##KConfigCore #LIBS += -L$$PWD/libs/bin/ -lKF5ConfigCore #INCLUDEPATH += $$PWD/libs/includes/KConfigCore #DEPENDPATH += $$PWD/libs/includes/KConfigCore - - diff --git a/mauikit.qrc b/mauikit.qrc deleted file mode 100644 index e19d152..0000000 --- a/mauikit.qrc +++ /dev/null @@ -1,59 +0,0 @@ - - - src/controls/ToolBar.qml - src/controls/AbstractSideBar.qml - src/controls/SideBar.qml - src/controls/ApplicationWindow.qml - src/controls/Style.qml - src/controls/ShareDialog.qml - src/controls/PieButton.qml - src/controls/Page.qml - src/controls/private/PathBarDelegate.qml - src/controls/private/EdgeShadow.qml - src/controls/private/BrowserMenu.qml - src/controls/private/BrowserView.qml - src/controls/private/BrowserSettings.qml - src/controls/private/BrowserHolder.qml - src/controls/private/FileMenu.qml - src/controls/private/AudioPreview.qml - src/controls/private/ImagePreview.qml - src/controls/private/TextPreview.qml - src/controls/private/VideoPreview.qml - src/controls/private/AccountsHelper.qml - src/controls/Holder.qml - src/controls/ListDelegate.qml - src/controls/ItemDelegate.qml - src/controls/SwipeItemDelegate.qml - src/controls/GridBrowserDelegate.qml - src/controls/ListBrowserDelegate.qml - src/controls/GlobalDrawer.qml - src/controls/SelectionBar.qml - src/controls/LabelDelegate.qml - src/controls/NewDialog.qml - src/controls/TagsBar.qml - src/controls/TagsDialog.qml - src/controls/private/TagList.qml - src/controls/private/TagDelegate.qml - src/controls/ColorsBar.qml - src/controls/FileBrowser.qml - src/controls/FilePreviewer.qml - src/controls/FileDialog.qml - src/controls/ListBrowser.qml - src/controls/PathBar.qml - src/controls/GridBrowser.qml - src/controls/Dialog.qml - src/controls/AboutDialog.qml - src/controls/Popup.qml - src/controls/TextField.qml - src/controls/Badge.qml - src/controls/GridView.qml - src/controls/SyncDialog.qml - src/controls/Terminal.qml - src/controls/Editor.qml - src/controls/PlacesSidebar.qml - src/controls/PlacesListBrowser.qml - src/controls/Store.qml - src/controls/ImageViewer.qml - src/controls/private/StoreDelegate.qml - - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..45efd53 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,328 @@ +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/utils + ${CMAKE_CURRENT_BINARY_DIR}/utils + + ${CMAKE_CURRENT_SOURCE_DIR}/utils/models + ${CMAKE_CURRENT_BINARY_DIR}/utils/models + + ${CMAKE_CURRENT_SOURCE_DIR}/utils/model_template + ${CMAKE_CURRENT_BINARY_DIR}/utils/model_template + + ${CMAKE_CURRENT_SOURCE_DIR}/kde + ${CMAKE_CURRENT_BINARY_DIR}/kde + ) + +set(mauikit_SRCS + mauikit.cpp + utils/fmstatic.cpp + utils/mauiapp.cpp + utils/handy.cpp + utils/models/pathlist.cpp + utils/model_template/mauilist.cpp + utils/model_template/mauimodel.cpp + ) + +set(mauikit_HDRS + mauikit.h + utils/fmstatic.h + utils/fmh.h + utils/utils.h + utils/handy.h + utils/models/pathlist.h + utils/mauiapp.h + utils/model_template/mauilist.h + utils/model_template/mauimodel.h + ) + +if(${COMPONENT_ACCOUNTS}) + message(STATUS "INCLUDING ACCOUNTS COMPONENT") + + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/utils/accounts + ${CMAKE_CURRENT_BINARY_DIR}/utils/accounts + ) + + set(accounts_SRCS + utils/accounts/mauiaccounts.cpp + utils/accounts/accountsdb.cpp + utils/accounts/accounts.qrc + ) + + set(accounts_HDRS + utils/accounts/mauiaccounts.h + utils/accounts/accountsdb.h + ) + qt5_add_resources(accounts_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/utils/accounts/accounts.qrc) + add_compile_definitions(COMPONENT_ACCOUNTS) +endif() + +if(${COMPONENT_EDITOR}) + message(STATUS "INCLUDING EDITOR COMPONENT") + set(editor_SRCS + utils/editor/documenthandler.cpp + utils/editor/syntaxhighlighterutil.cpp + ) + + set(editor_HDRS + utils/editor/documenthandler.h + utils/editor/syntaxhighlighterutil.h + ) + + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/utils/editor + ${CMAKE_CURRENT_BINARY_DIR}/utils/editor + ) + add_compile_definitions(COMPONENT_EDITOR) +endif() + +if(${COMPONENT_FM}) + message(STATUS "INCLUDING FM COMPONENT") + + set(fm_SRCS + fm/fm.cpp + fm/fmlist.cpp + fm/placeslist.cpp + ) + + set(fm_HDRS + fm/fm.h + fm/fmlist.h + fm/placeslist.h + ) + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/fm + ${CMAKE_CURRENT_BINARY_DIR}/fm + ) + add_compile_definitions(COMPONENT_FM) +endif() + +if(${COMPONENT_TAGGING}) + message(STATUS "INCLUDING TAGGING COMPONENT") + set(tagging_SRCS + utils/tagging/tagging.cpp + utils/tagging/tagdb.cpp + utils/tagging/tagsmodel.cpp + utils/tagging/tagslist.cpp + utils/tagging/tagging.qrc + ) + + set(tagging_HDRS + utils/tagging/tag.h + utils/tagging/tagging.h + utils/tagging/tagdb.h + utils/tagging/tagsmodel.h + utils/tagging/tagslist.h + ) + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/utils/tagging + ${CMAKE_CURRENT_BINARY_DIR}/utils/tagging + ) + add_compile_definitions(COMPONENT_TAGGING) +endif() + +if(${COMPONENT_SYNCING}) + message(STATUS "INCLUDING SYNCING COMPONENT") + set(syncing_SRCS + utils/syncing/syncing.cpp + utils/syncing/libwebdavclient/lib/WebDAVClient.cpp + utils/syncing/libwebdavclient/lib/dto/WebDAVItem.cpp + utils/syncing/libwebdavclient/lib/utils/Environment.cpp + utils/syncing/libwebdavclient/lib/utils/NetworkHelper.cpp + utils/syncing/libwebdavclient/lib/utils/WebDAVReply.cpp + utils/syncing/libwebdavclient/lib/utils/XMLHelper.cpp + ) + + set(syncing_HDRS + utils/syncing/syncing.h + utils/syncing/libwebdavclient/lib/WebDAVClient.hpp + utils/syncing/libwebdavclient/lib/dto/WebDAVItem.hpp + utils/syncing/libwebdavclient/lib/utils/Environment.hpp + utils/syncing/libwebdavclient/lib/utils/NetworkHelper.hpp + utils/syncing/libwebdavclient/lib/utils/WebDAVReply.hpp + utils/syncing/libwebdavclient/lib/utils/XMLHelper.hpp + ) + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/utils/syncing + ${CMAKE_CURRENT_BINARY_DIR}/utils/syncing + ${CMAKE_CURRENT_SOURCE_DIR}/utils/syncing/libwebdavclient/lib + ${CMAKE_CURRENT_SOURCE_DIR}/utils/syncing/libwebdavclient/lib/utils + ${CMAKE_CURRENT_SOURCE_DIR}/utils/syncing/libwebdavclient/lib/dto + ) + add_compile_definitions(COMPONENT_SYNCING) +endif() + +if(${COMPONENT_STORE}) + message(STATUS "INCLUDING STORE COMPONENT") + set(store_SRCS + utils/store/store.cpp + utils/store/storemodel.cpp + utils/store/storelist.cpp + utils/store/store.qrc + ) + + set(store_HDRS + utils/store/store.h + utils/store/storemodel.h + utils/store/storelist.h + ) + + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/utils/store + ${CMAKE_CURRENT_BINARY_DIR}/utils/store + ) + add_compile_definitions(COMPONENT_STORE) +endif() +#use dbus on linux, bsd etc, but not andoid and apple stuff + +#options - for the appimage +option(IS_APPIMAGE_PACKAGE "If set to true then the icons and styled is packaged as well") + +if(ANDROID OR IS_APPIMAGE_PACKAGE OR MAUIKIT_STYLE) + if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/android/icons/luv-icon-theme/.git) + find_package(Git REQUIRED) + execute_process(COMMAND ${GIT_EXECUTABLE} clone --depth 1 https://github.com/milohr/luv-icon-theme.git ${CMAKE_CURRENT_SOURCE_DIR}/android/icons/luv-icon-theme) + endif() + + list(APPEND mauikit_SRCS android/icons.qrc) +endif() + +if (ANDROID) + add_subdirectory(android) + + set(mauikit_Android_SRCS + android/mauiandroid.cpp + ) + + kde_enable_exceptions(MauiKit PRIVATE) +else() + set(mauikit_KDE_SRCS + kde/mauikde.cpp + kde/kdeconnect.cpp + ) + + set(mauikit_KDE_HDRS + kde/mauikde.h + kde/kdeconnect.h + ) +endif() + +add_library(MauiKit + + ${fm_HDRS} + ${fm_SRCS} + + ${accounts_HDRS} + ${accounts_SRCS} + + ${editor_HDRS} + ${editor_SRCS} + + ${syncing_HDRS} + ${syncing_SRCS} + + ${store_SRCS} + ${store_HDRS} + + ${tagging_HDRS} + ${tagging_SRCS} + + ${mauikit_HDRS} + ${mauikit_SRCS} + + ${mauikit_Android_SRCS} + + ${mauikit_KDE_HDRS} + ${mauikit_KDE_SRCS} + + maui-style/style.qrc + assets.qrc + mauikit.qrc +) + +if(ANDROID) + target_link_libraries(MauiKit PRIVATE Qt5::AndroidExtras Qt5::WebView jnigraphics) + + target_include_directories(MauiKit PRIVATE android) + install(FILES android/mauiandroid.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/MauiKit COMPONENT Devel) + + install(DIRECTORY android/ DESTINATION ${KDE_INSTALL_DATAROOTDIR}/MauiKitAndroid COMPONENT Devel) + + install(FILES MauiKit-android-dependencies.xml DESTINATION ${KDE_INSTALL_LIBDIR}) + +else() + target_link_libraries(MauiKit PRIVATE Qt5::WebEngine) +endif() + +target_link_libraries(MauiKit + PUBLIC + Qt5::Core + Qt5::Sql + Qt5::Gui + KF5::Notifications + KF5::I18n + KF5::ConfigCore + KF5::KIOCore + KF5::KIOWidgets + KF5::KIOFileWidgets + + PRIVATE + Qt5::Qml + Qt5::Quick + Qt5::QuickControls2 + Qt5::Svg + Qt5::Network + Qt5::Xml + KF5::Service + KF5::KIONTLM + KF5::ConfigWidgets + ) + +if(${COMPONENT_EDITOR}) + find_package(KF5 ${REQUIRED_KF5_VERSION} REQUIRED COMPONENTS SyntaxHighlighting) + target_link_libraries(MauiKit PRIVATE KF5::SyntaxHighlighting) +endif() + +if(${COMPONENT_STORE}) + find_package(KF5 ${REQUIRED_KF5_VERSION} REQUIRED COMPONENTS Attica) + target_link_libraries(MauiKit PUBLIC KF5::Attica) +endif() + +if(IS_APPIMAGE_PACKAGE) + target_compile_definitions(MauiKit PUBLIC APPIMAGE_PACKAGE) +endif() + +generate_export_header(MauiKit BASE_NAME MauiKit) +install(TARGETS MauiKit EXPORT MauiKitTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) + +target_include_directories(MauiKit + INTERFACE "$") + +add_custom_target(copy) + +file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/org/kde/mauikit) +add_custom_command(TARGET copy PRE_BUILD COMMAND ${CMAKE_COMMAND} + -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/controls + ${CMAKE_BINARY_DIR}/bin/org/kde/mauikit/) + +add_dependencies(MauiKit copy) + +install(DIRECTORY controls/ DESTINATION + ${KDE_INSTALL_QMLDIR}/org/kde/mauikit) + +install(TARGETS MauiKit DESTINATION + ${KDE_INSTALL_QMLDIR}/org/kde/mauikit) + +install(FILES + ${mauikit_HDRS} + ${mauikit_KDE_HDRS} + ${tagging_HDRS} + ${fm_HDRS} + ${syncing_HDRS} + ${store_HDRS} + ${accounts_HDRS} + ${CMAKE_CURRENT_BINARY_DIR}/mauikit_export.h + DESTINATION ${KDE_INSTALL_INCLUDEDIR}/MauiKit + COMPONENT Devel) + +##INSTALL MAUI STYLE +install(DIRECTORY maui-style DESTINATION ${KDE_INSTALL_QMLDIR}/QtQuick/Controls.2) diff --git a/src/MauiKit-android-dependencies.xml b/src/MauiKit-android-dependencies.xml new file mode 100644 index 0000000..1dc3da4 --- /dev/null +++ b/src/MauiKit-android-dependencies.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/android/AndroidManifest.xml b/src/android/AndroidManifest.xml new file mode 100644 index 0000000..c8a9023 --- /dev/null +++ b/src/android/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/src/android/CMakeLists.txt b/src/android/CMakeLists.txt new file mode 100644 index 0000000..8002241 --- /dev/null +++ b/src/android/CMakeLists.txt @@ -0,0 +1,2 @@ +gradle_add_aar(mauikit_aar BUILDFILE ${CMAKE_CURRENT_SOURCE_DIR}/build.gradle NAME MauiKit) +gradle_install_aar(mauikit_aar DESTINATION jar) diff --git a/src/android/android.pri b/src/android/android.pri index 1437509..9f86aaa 100644 --- a/src/android/android.pri +++ b/src/android/android.pri @@ -1,21 +1,45 @@ QT += androidextras xml HEADERS += \ $$PWD/mauiandroid.h\ SOURCES += \ $$PWD/mauiandroid.cpp \ LIBS += -ljnigraphics DEPENDPATH += \ $$PWD INCLUDEPATH += \ $$PWD +#exists($$ANDROID_FILES_DIR) { +# warning("Using application android files at $${ANDROID_FILES_DIR}") +# system(cp -as $$ANDROID_FILES_DIR/. $${PWD}/) + +#}else { +# warning("Expected files: $$ANDROID_FILES_MANIFEST, $$ANDROID_FILES_GRADLE, $$ANDROID_FILES_RES_DIR") +# error("The application is missing the android files, this files are supossed to be located at $$ANDROID_FILES_DIR") +#} + +contains(DEFINES, MAUIKIT_STYLE):{ + exists($$PWD/icons/luv-icon-theme) { + message("Using Luv icon theme for Android") + }else { + message("Getting Luv icon theme for Android") + system(git clone $$LUV_REPO $$PWD/icons/luv-icon-theme) + } + + RESOURCES += $$PWD/icons.qrc +} + RESOURCES += \ - $$PWD/android.qrc \ - $$PWD/icons.qrc + $$PWD/android.qrc + +#ANDROID_PACKAGE_SOURCE_DIR += $$PWD/ -ANDROID_PACKAGE_SOURCE_DIR += $$PWD/ +#DISTFILES += \ +# $$PWD/AndroidManifest.xml \ +# $$PWD/build.gradle \ +# $$PWD/res/values/libs.xml diff --git a/src/android/build.gradle b/src/android/build.gradle new file mode 100644 index 0000000..098cfb5 --- /dev/null +++ b/src/android/build.gradle @@ -0,0 +1,39 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.2.0' + } +} + +repositories { + google() + jcenter() +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + buildToolsVersion '28.0.2' + + sourceSets { + main { + manifest.srcFile '@CMAKE_CURRENT_SOURCE_DIR@/AndroidManifest.xml' + java.srcDirs = ['@CMAKE_CURRENT_SOURCE_DIR@/src'] + } + } + + lintOptions { + abortOnError false + } + + dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) + implementation 'com.android.support:support-compat:28.0.0' + } +} + diff --git a/src/android/icons.qrc b/src/android/icons.qrc index b44c459..9b05eba 100644 --- a/src/android/icons.qrc +++ b/src/android/icons.qrc @@ -1,704 +1,702 @@ icons/luv-icon-theme/Luv/index.theme icons/luv-icon-theme/Luv/LICENSE icons/luv-icon-theme/Luv/places/16/folder-documents.svg icons/luv-icon-theme/Luv/places/16/folder-download.svg icons/luv-icon-theme/Luv/places/16/folder-images.svg icons/luv-icon-theme/Luv/places/16/folder-music.svg icons/luv-icon-theme/Luv/places/16/folder-network.svg icons/luv-icon-theme/Luv/places/16/folder-pictures.svg icons/luv-icon-theme/Luv/places/16/folder-publicshare.svg icons/luv-icon-theme/Luv/places/16/folder-red.svg icons/luv-icon-theme/Luv/places/16/folder-sound.svg icons/luv-icon-theme/Luv/places/16/folder-text.svg icons/luv-icon-theme/Luv/places/16/folder-videos.svg icons/luv-icon-theme/Luv/places/16/folder.svg icons/luv-icon-theme/Luv/places/16/network-workgroup.svg icons/luv-icon-theme/Luv/places/16/user-desktop.svg icons/luv-icon-theme/Luv/places/16/user-home.svg icons/luv-icon-theme/Luv/places/16/user-trash-full.svg icons/luv-icon-theme/Luv/places/16/user-trash.svg icons/luv-icon-theme/Luv/actions/22/album.svg icons/luv-icon-theme/Luv/actions/22/amarok_artist.svg icons/luv-icon-theme/Luv/actions/22/amarok_clock.svg icons/luv-icon-theme/Luv/actions/22/amarok_lyrics.svg icons/luv-icon-theme/Luv/actions/22/amarok_playlist_refresh.svg icons/luv-icon-theme/Luv/actions/22/application-menu.svg icons/luv-icon-theme/Luv/actions/22/archive-extract.svg icons/luv-icon-theme/Luv/actions/22/archive-insert.svg icons/luv-icon-theme/Luv/actions/22/archive-remove.svg icons/luv-icon-theme/Luv/actions/22/artist.svg icons/luv-icon-theme/Luv/actions/22/bookmark-new.svg icons/luv-icon-theme/Luv/actions/22/configure.svg icons/luv-icon-theme/Luv/actions/22/dialog-close.svg icons/luv-icon-theme/Luv/actions/22/document-close.svg icons/luv-icon-theme/Luv/actions/22/document-download.svg icons/luv-icon-theme/Luv/actions/22/document-edit.svg icons/luv-icon-theme/Luv/actions/22/document-export.svg icons/luv-icon-theme/Luv/actions/22/document-import.svg icons/luv-icon-theme/Luv/actions/22/document-launch.svg icons/luv-icon-theme/Luv/actions/22/document-new.svg icons/luv-icon-theme/Luv/actions/22/document-open.svg icons/luv-icon-theme/Luv/actions/22/document-preview-archive.svg icons/luv-icon-theme/Luv/actions/22/document-save-as.svg icons/luv-icon-theme/Luv/actions/22/document-save.svg icons/luv-icon-theme/Luv/actions/22/document-share.svg icons/luv-icon-theme/Luv/actions/22/documentinfo.svg icons/luv-icon-theme/Luv/actions/22/draw-text.svg icons/luv-icon-theme/Luv/actions/22/edit-clear.svg icons/luv-icon-theme/Luv/actions/22/edit-find.svg icons/luv-icon-theme/Luv/actions/22/edit-pin.svg icons/luv-icon-theme/Luv/actions/22/edit-redo.svg icons/luv-icon-theme/Luv/actions/22/edit-select.svg icons/luv-icon-theme/Luv/actions/22/edit-undo.svg icons/luv-icon-theme/Luv/actions/22/entry-delete.svg icons/luv-icon-theme/Luv/actions/22/filename-filetype-amarok.svg icons/luv-icon-theme/Luv/actions/22/filename-space-amarok.svg icons/luv-icon-theme/Luv/actions/22/folder-add.svg icons/luv-icon-theme/Luv/actions/22/format-text-bold.svg icons/luv-icon-theme/Luv/actions/22/format-text-italic.svg icons/luv-icon-theme/Luv/actions/22/format-text-underline.svg icons/luv-icon-theme/Luv/actions/22/format-text-uppercase.svg icons/luv-icon-theme/Luv/actions/22/games-config-options.svg icons/luv-icon-theme/Luv/actions/22/go-down.svg icons/luv-icon-theme/Luv/actions/22/go-first.svg icons/luv-icon-theme/Luv/actions/22/go-home.svg icons/luv-icon-theme/Luv/actions/22/go-last.svg icons/luv-icon-theme/Luv/actions/22/go-next.svg icons/luv-icon-theme/Luv/actions/22/go-previous.svg icons/luv-icon-theme/Luv/actions/22/go-up.svg icons/luv-icon-theme/Luv/actions/22/headphones.svg icons/luv-icon-theme/Luv/actions/22/help-contents.svg icons/luv-icon-theme/Luv/actions/22/help-contextual.svg icons/luv-icon-theme/Luv/actions/22/hint.svg icons/luv-icon-theme/Luv/actions/22/image-folder-view.svg icons/luv-icon-theme/Luv/actions/22/image-frames.svg icons/luv-icon-theme/Luv/actions/22/image-multiple.svg icons/luv-icon-theme/Luv/actions/22/image.svg icons/luv-icon-theme/Luv/actions/22/internet-amarok.svg icons/luv-icon-theme/Luv/actions/22/internet-services.svg icons/luv-icon-theme/Luv/actions/22/list-add.svg icons/luv-icon-theme/Luv/actions/22/list-remove.svg icons/luv-icon-theme/Luv/actions/22/love.svg icons/luv-icon-theme/Luv/actions/22/media-album-track.svg icons/luv-icon-theme/Luv/actions/22/media-eject.svg icons/luv-icon-theme/Luv/actions/22/media-playback-pause.svg icons/luv-icon-theme/Luv/actions/22/media-playback-start.svg icons/luv-icon-theme/Luv/actions/22/media-playlist-append.svg icons/luv-icon-theme/Luv/actions/22/media-playlist-normal.svg icons/luv-icon-theme/Luv/actions/22/media-playlist-play.svg icons/luv-icon-theme/Luv/actions/22/media-playlist-repeat.svg icons/luv-icon-theme/Luv/actions/22/media-playlist-shuffle.svg icons/luv-icon-theme/Luv/actions/22/media-skip-backward.svg icons/luv-icon-theme/Luv/actions/22/media-skip-forward.svg icons/luv-icon-theme/Luv/actions/22/musicnote.svg icons/luv-icon-theme/Luv/actions/22/nx-configure.svg icons/luv-icon-theme/Luv/actions/22/nx-home.svg icons/luv-icon-theme/Luv/actions/22/object-rotate-left.svg icons/luv-icon-theme/Luv/actions/22/object-rotate-right.svg icons/luv-icon-theme/Luv/actions/22/overflow-menu.svg icons/luv-icon-theme/Luv/actions/22/process-stop.svg icons/luv-icon-theme/Luv/actions/22/tag.svg icons/luv-icon-theme/Luv/actions/22/view-books.svg icons/luv-icon-theme/Luv/actions/22/view-fullscreen.svg icons/luv-icon-theme/Luv/actions/22/view-left-close.svg icons/luv-icon-theme/Luv/actions/22/view-links.svg icons/luv-icon-theme/Luv/actions/22/view-list-details.svg icons/luv-icon-theme/Luv/actions/22/view-list-icons.svg icons/luv-icon-theme/Luv/actions/22/view-list-tree.svg icons/luv-icon-theme/Luv/actions/22/view-media-album.svg icons/luv-icon-theme/Luv/actions/22/view-media-artist.svg icons/luv-icon-theme/Luv/actions/22/view-media-chart.svg icons/luv-icon-theme/Luv/actions/22/view-media-config.svg icons/luv-icon-theme/Luv/actions/22/view-media-favorite.svg icons/luv-icon-theme/Luv/actions/22/view-media-genre.svg icons/luv-icon-theme/Luv/actions/22/view-media-playcount.svg icons/luv-icon-theme/Luv/actions/22/view-media-playlist.svg icons/luv-icon-theme/Luv/actions/22/view-media-recent.svg icons/luv-icon-theme/Luv/actions/22/view-media-similarartists.svg icons/luv-icon-theme/Luv/actions/22/view-media-track.svg icons/luv-icon-theme/Luv/actions/22/view-notes.svg icons/luv-icon-theme/Luv/actions/22/view-preview.svg icons/luv-icon-theme/Luv/actions/22/view-refresh.svg icons/luv-icon-theme/Luv/actions/22/view-restore.svg icons/luv-icon-theme/Luv/actions/22/view-right-close.svg icons/luv-icon-theme/Luv/actions/22/view-right-new.svg icons/luv-icon-theme/Luv/actions/22/view-sort.svg icons/luv-icon-theme/Luv/actions/22/visibility.svg icons/luv-icon-theme/Luv/actions/22/window-close.svg icons/luv-icon-theme/Luv/actions/16/amarok_playlist_refresh.svg icons/luv-icon-theme/Luv/actions/16/application-exit.svg icons/luv-icon-theme/Luv/actions/16/bookmark-new.svg icons/luv-icon-theme/Luv/actions/16/configure.svg icons/luv-icon-theme/Luv/actions/16/dialog-ok-apply.svg icons/luv-icon-theme/Luv/actions/16/dialog-ok.svg icons/luv-icon-theme/Luv/actions/16/document-import.svg icons/luv-icon-theme/Luv/actions/16/document-new.svg icons/luv-icon-theme/Luv/actions/16/document-open.svg icons/luv-icon-theme/Luv/actions/16/document-revert.svg icons/luv-icon-theme/Luv/actions/16/document-save-as.svg icons/luv-icon-theme/Luv/actions/16/document-save.svg icons/luv-icon-theme/Luv/actions/16/document-share.svg icons/luv-icon-theme/Luv/actions/16/edit-copy.svg icons/luv-icon-theme/Luv/actions/16/edit-cut.svg icons/luv-icon-theme/Luv/actions/16/edit-delete.svg icons/luv-icon-theme/Luv/actions/16/edit-find.svg icons/luv-icon-theme/Luv/actions/16/edit-paste.svg icons/luv-icon-theme/Luv/actions/16/edit-redo.svg icons/luv-icon-theme/Luv/actions/16/edit-undo.svg icons/luv-icon-theme/Luv/actions/16/filename-bpm-amarok.svg icons/luv-icon-theme/Luv/actions/16/filename-title-amarok.svg icons/luv-icon-theme/Luv/actions/16/get-hot-new-stuff.svg icons/luv-icon-theme/Luv/actions/16/go-jump-today.svg icons/luv-icon-theme/Luv/actions/16/help-contents.svg icons/luv-icon-theme/Luv/actions/16/list-add.svg icons/luv-icon-theme/Luv/actions/16/list-remove.svg icons/luv-icon-theme/Luv/actions/16/media-eject.svg icons/luv-icon-theme/Luv/actions/16/system-run.svg icons/luv-icon-theme/Luv/actions/16/tab-new.svg icons/luv-icon-theme/Luv/actions/16/view-calendar-day.svg icons/luv-icon-theme/Luv/actions/16/view-calendar-month.svg icons/luv-icon-theme/Luv/actions/16/view-calendar.svg icons/luv-icon-theme/Luv/actions/16/view-filter.svg icons/luv-icon-theme/Luv/actions/16/view-left-close.svg icons/luv-icon-theme/Luv/actions/16/view-list-details.svg icons/luv-icon-theme/Luv/actions/16/view-list-icons.svg icons/luv-icon-theme/Luv/actions/16/view-list-tree.svg icons/luv-icon-theme/Luv/actions/16/view-preview.svg icons/luv-icon-theme/Luv/actions/16/view-refresh.svg icons/luv-icon-theme/Luv/actions/16/view-right-close.svg icons/luv-icon-theme/Luv/actions/16/view-right-new.svg icons/luv-icon-theme/Luv/actions/16/window-new.svg icons/luv-icon-theme/Luv/actions/32/application-exit.svg icons/luv-icon-theme/Luv/actions/32/chronometer.svg icons/luv-icon-theme/Luv/actions/32/configure-shortcuts.svg icons/luv-icon-theme/Luv/actions/32/document-open-recent.svg icons/luv-icon-theme/Luv/actions/32/edit-select.svg icons/luv-icon-theme/Luv/actions/32/flag.svg icons/luv-icon-theme/Luv/actions/32/go-home.svg icons/luv-icon-theme/Luv/actions/32/object-group.svg icons/luv-icon-theme/Luv/actions/32/system-run.svg icons/luv-icon-theme/Luv/actions/32/tools-check-spelling.svg icons/luv-icon-theme/Luv/actions/32/view-choose.svg icons/luv-icon-theme/Luv/actions/32/view-filter.svg icons/luv-icon-theme/Luv/actions/32/view-list-tree.svg icons/luv-icon-theme/Luv/actions/32/view-preview.svg icons/luv-icon-theme/Luv/actions/32/window-duplicate.svg icons/luv-icon-theme/Luv/actions/48/configure.svg icons/luv-icon-theme/Luv/actions/48/system-run.svg icons/luv-icon-theme/Luv/categories/32/applications-development.svg icons/luv-icon-theme/Luv/categories/32/applications-games.svg icons/luv-icon-theme/Luv/categories/32/applications-graphics.svg icons/luv-icon-theme/Luv/categories/32/applications-internet.svg icons/luv-icon-theme/Luv/categories/32/applications-multimedia.svg icons/luv-icon-theme/Luv/categories/32/applications-office.svg icons/luv-icon-theme/Luv/categories/32/applications-other.svg icons/luv-icon-theme/Luv/categories/32/applications-system.svg icons/luv-icon-theme/Luv/categories/32/applications-utilities.svg icons/luv-icon-theme/Luv/categories/16/applications-graphics.svg icons/luv-icon-theme/Luv/devices/16/battery.svg icons/luv-icon-theme/Luv/devices/16/camera-web.svg icons/luv-icon-theme/Luv/devices/16/computer.svg icons/luv-icon-theme/Luv/devices/16/cpu.svg icons/luv-icon-theme/Luv/devices/16/drive-harddisk.svg icons/luv-icon-theme/Luv/devices/16/drive-removable-media-usb-pendrive.svg icons/luv-icon-theme/Luv/devices/16/drive-removable-media-usb.svg icons/luv-icon-theme/Luv/devices/16/drive-removable-media.svg icons/luv-icon-theme/Luv/devices/16/media-optical.svg icons/luv-icon-theme/Luv/devices/16/multimedia-player.svg icons/luv-icon-theme/Luv/devices/16/network-card.svg icons/luv-icon-theme/Luv/devices/16/phone.svg icons/luv-icon-theme/Luv/devices/16/smartphone.svg icons/luv-icon-theme/Luv/devices/16/video-display.svg icons/luv-icon-theme/Luv/devices/32/camera-photo.svg icons/luv-icon-theme/Luv/devices/32/drive-harddisk.svg icons/luv-icon-theme/Luv/devices/32/drive-removable-media-usb-pendrive.svg icons/luv-icon-theme/Luv/devices/32/drive-removable-media-usb.svg icons/luv-icon-theme/Luv/devices/32/drive-removable-media.svg icons/luv-icon-theme/Luv/devices/32/input-keyboard.svg icons/luv-icon-theme/Luv/devices/32/input-touchpad.svg icons/luv-icon-theme/Luv/devices/32/printer.svg icons/luv-icon-theme/Luv/devices/64/drive-harddisk.svg icons/luv-icon-theme/Luv/devices/64/smartphone.svg icons/luv-icon-theme/Luv/emblems/8/emblem-mounted.svg icons/luv-icon-theme/Luv/emblems/8/emblem-symbolic-link.svg icons/luv-icon-theme/Luv/emblems/8/emblem-unmounted.svg icons/luv-icon-theme/Luv/emblems/16/emblem-added.svg icons/luv-icon-theme/Luv/emblems/16/emblem-mounted.svg icons/luv-icon-theme/Luv/emblems/16/emblem-remove.svg icons/luv-icon-theme/Luv/emblems/16/emblem-symbolic-link.svg icons/luv-icon-theme/Luv/emblems/16/emblem-unmounted.svg icons/luv-icon-theme/Luv/emblems/22/emblem-default.svg icons/luv-icon-theme/Luv/emblems/22/emblem-encrypted-locked.svg icons/luv-icon-theme/Luv/emblems/22/emblem-encrypted-unlocked.svg icons/luv-icon-theme/Luv/emblems/22/emblem-error.svg icons/luv-icon-theme/Luv/emblems/22/emblem-important.svg icons/luv-icon-theme/Luv/emblems/22/emblem-info.svg icons/luv-icon-theme/Luv/emblems/22/emblem-locked.svg icons/luv-icon-theme/Luv/emblems/22/emblem-mounted.svg icons/luv-icon-theme/Luv/emblems/22/emblem-nowrite.svg icons/luv-icon-theme/Luv/emblems/22/emblem-readonly.svg icons/luv-icon-theme/Luv/emblems/22/emblem-select-add.svg icons/luv-icon-theme/Luv/emblems/22/emblem-select-remove.svg icons/luv-icon-theme/Luv/emblems/22/emblem-symbolic-link.svg icons/luv-icon-theme/Luv/emblems/22/emblem-unlocked.svg icons/luv-icon-theme/Luv/emblems/22/emblem-unmounted.svg icons/luv-icon-theme/Luv/emblems/32/emblem-symbolic-link.svg icons/luv-icon-theme/Luv/emotes/32/face-smile.svg icons/luv-icon-theme/Luv/mimetypes/16/application-x-cd-image.svg icons/luv-icon-theme/Luv/mimetypes/16/application-x-iso.svg icons/luv-icon-theme/Luv/mimetypes/16/inode-directory.svg icons/luv-icon-theme/Luv/mimetypes/32/application-epub+zip.svg icons/luv-icon-theme/Luv/mimetypes/32/application-javascript.svg icons/luv-icon-theme/Luv/mimetypes/32/application-pdf.svg icons/luv-icon-theme/Luv/mimetypes/32/application-pkcs8+pem.svg icons/luv-icon-theme/Luv/mimetypes/32/application-pkcs10.svg icons/luv-icon-theme/Luv/mimetypes/32/application-vnd.android.package-archive.svg icons/luv-icon-theme/Luv/mimetypes/32/application-vnd.ms-excel.svg icons/luv-icon-theme/Luv/mimetypes/32/application-vnd.ms-powerpoint.svg icons/luv-icon-theme/Luv/mimetypes/32/application-vnd.ms-word.svg icons/luv-icon-theme/Luv/mimetypes/32/application-vnd.openxmlformats-officedocument.presentationml.presentation.svg icons/luv-icon-theme/Luv/mimetypes/32/application-vnd.openxmlformats-officedocument.spreadsheetml.sheet.svg icons/luv-icon-theme/Luv/mimetypes/32/application-vnd.openxmlformats-officedocument.wordprocessingml.document.svg icons/luv-icon-theme/Luv/mimetypes/32/application-wps-office.doc.svg icons/luv-icon-theme/Luv/mimetypes/32/application-wps-office.ppt.svg icons/luv-icon-theme/Luv/mimetypes/32/application-wps-office.xlsx.svg icons/luv-icon-theme/Luv/mimetypes/32/application-x-7z-compressed.svg icons/luv-icon-theme/Luv/mimetypes/32/application-x-bittorrent.svg icons/luv-icon-theme/Luv/mimetypes/32/application-x-cd-image.svg icons/luv-icon-theme/Luv/mimetypes/32/application-x-executable.svg icons/luv-icon-theme/Luv/mimetypes/32/application-x-font-ttf.svg icons/luv-icon-theme/Luv/mimetypes/32/application-x-iso.svg icons/luv-icon-theme/Luv/mimetypes/32/audio-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/32/image-svg+xml.svg icons/luv-icon-theme/Luv/mimetypes/32/image-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/32/inode-directory.svg icons/luv-icon-theme/Luv/mimetypes/32/text-plain.svg icons/luv-icon-theme/Luv/mimetypes/32/text-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/32/video-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/48/application-vnd.ms-excel.svg icons/luv-icon-theme/Luv/mimetypes/48/application-vnd.ms-powerpoint.svg icons/luv-icon-theme/Luv/mimetypes/48/application-vnd.ms-word.svg icons/luv-icon-theme/Luv/mimetypes/48/application-vnd.openxmlformats-officedocument.presentationml.presentation.svg icons/luv-icon-theme/Luv/mimetypes/48/application-vnd.openxmlformats-officedocument.spreadsheetml.sheet.svg icons/luv-icon-theme/Luv/mimetypes/48/application-vnd.openxmlformats-officedocument.wordprocessingml.document.svg icons/luv-icon-theme/Luv/mimetypes/48/application-x-cd-image.svg icons/luv-icon-theme/Luv/mimetypes/48/application-x-iso.svg icons/luv-icon-theme/Luv/mimetypes/48/inode-directory.svg icons/luv-icon-theme/Luv/mimetypes/48/text-plain.svg icons/luv-icon-theme/Luv/mimetypes/48/text-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/64/application-epub+zip.svg icons/luv-icon-theme/Luv/mimetypes/64/application-javascript.svg icons/luv-icon-theme/Luv/mimetypes/64/application-octet-stream.svg icons/luv-icon-theme/Luv/mimetypes/64/application-pdf.svg icons/luv-icon-theme/Luv/mimetypes/64/application-pkcs8+pem.svg icons/luv-icon-theme/Luv/mimetypes/64/application-pkcs10.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.android.package-archive.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.ms-excel.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.ms-powerpoint.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.ms-word.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.openxmlformats-officedocument.presentationml.presentation.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.openxmlformats-officedocument.spreadsheetml.sheet.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.openxmlformats-officedocument.wordprocessingml.document.svg icons/luv-icon-theme/Luv/mimetypes/64/application-wps-office.doc.svg icons/luv-icon-theme/Luv/mimetypes/64/application-wps-office.ppt.svg icons/luv-icon-theme/Luv/mimetypes/64/application-wps-office.xlsx.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-7z-compressed.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-bzip-compressed-tar.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-cd-image.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-compressed-tar.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-cue.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-executable.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-font-otf.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-font-ttf.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-iso.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-java-archive.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-lha.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-pem-key.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-raw-disk-image.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-ruby.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-sharedlib.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-shellscript.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-tar.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-theme.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-trash.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-zerosize.svg icons/luv-icon-theme/Luv/mimetypes/64/application-zip.svg icons/luv-icon-theme/Luv/mimetypes/64/font-ttf.svg icons/luv-icon-theme/Luv/mimetypes/64/fonts-package.svg icons/luv-icon-theme/Luv/mimetypes/64/image-bmp.svg icons/luv-icon-theme/Luv/mimetypes/64/image-jpeg.svg icons/luv-icon-theme/Luv/mimetypes/64/image-png.svg icons/luv-icon-theme/Luv/mimetypes/64/image-svg+xml-compressed.svg icons/luv-icon-theme/Luv/mimetypes/64/image-svg+xml.svg icons/luv-icon-theme/Luv/mimetypes/64/image-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/64/inode-blockdevice.svg icons/luv-icon-theme/Luv/mimetypes/64/inode-chardevice.svg icons/luv-icon-theme/Luv/mimetypes/64/inode-directory.svg icons/luv-icon-theme/Luv/mimetypes/64/package-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/64/text-css.svg icons/luv-icon-theme/Luv/mimetypes/64/text-html.svg icons/luv-icon-theme/Luv/mimetypes/64/text-markdown.svg icons/luv-icon-theme/Luv/mimetypes/64/text-plain.svg icons/luv-icon-theme/Luv/mimetypes/64/text-x-cmake.svg icons/luv-icon-theme/Luv/mimetypes/64/text-x-credits.svg icons/luv-icon-theme/Luv/mimetypes/64/text-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/64/video-mp4.svg icons/luv-icon-theme/Luv/mimetypes/64/video-x-matroska.svg icons/luv-icon-theme/Luv/mimetypes/64/video-x-msvideo.svg icons/luv-icon-theme/Luv/places/32/bookmarks.svg icons/luv-icon-theme/Luv/places/32/folder-documents.svg icons/luv-icon-theme/Luv/places/32/folder-download.svg icons/luv-icon-theme/Luv/places/32/folder-dropbox.svg icons/luv-icon-theme/Luv/places/32/folder-github.svg icons/luv-icon-theme/Luv/places/32/folder-google-drive.svg icons/luv-icon-theme/Luv/places/32/folder-launchpad.svg icons/luv-icon-theme/Luv/places/32/folder-mega.svg icons/luv-icon-theme/Luv/places/32/folder-music.svg icons/luv-icon-theme/Luv/places/32/folder-network.svg icons/luv-icon-theme/Luv/places/32/folder-pictures.svg icons/luv-icon-theme/Luv/places/32/folder-publicshare.svg icons/luv-icon-theme/Luv/places/32/folder-red.svg icons/luv-icon-theme/Luv/places/32/folder-templates.svg icons/luv-icon-theme/Luv/places/32/folder-videos.svg icons/luv-icon-theme/Luv/places/32/folder.svg icons/luv-icon-theme/Luv/places/32/network-workgroup.svg icons/luv-icon-theme/Luv/places/32/user-desktop.svg icons/luv-icon-theme/Luv/places/32/user-home.svg icons/luv-icon-theme/Luv/places/32/user-trash-full.svg icons/luv-icon-theme/Luv/places/32/user-trash.svg icons/luv-icon-theme/Luv/places/48/folder-documents.svg icons/luv-icon-theme/Luv/places/48/folder-download.svg icons/luv-icon-theme/Luv/places/48/folder-dropbox.svg icons/luv-icon-theme/Luv/places/48/folder-github.svg icons/luv-icon-theme/Luv/places/48/folder-google-drive.svg icons/luv-icon-theme/Luv/places/48/folder-launchpad.svg icons/luv-icon-theme/Luv/places/48/folder-mega.svg icons/luv-icon-theme/Luv/places/48/folder-music.svg icons/luv-icon-theme/Luv/places/48/folder-network.svg icons/luv-icon-theme/Luv/places/48/folder-pictures.svg icons/luv-icon-theme/Luv/places/48/folder-publicshare.svg icons/luv-icon-theme/Luv/places/48/folder-red.svg icons/luv-icon-theme/Luv/places/48/folder-templates.svg icons/luv-icon-theme/Luv/places/48/folder-videos.svg icons/luv-icon-theme/Luv/places/48/folder.svg icons/luv-icon-theme/Luv/places/48/network-workgroup.svg icons/luv-icon-theme/Luv/places/48/user-desktop.svg icons/luv-icon-theme/Luv/places/48/user-home.svg icons/luv-icon-theme/Luv/places/48/user-trash-full.svg icons/luv-icon-theme/Luv/places/48/user-trash.svg icons/luv-icon-theme/Luv/places/64/folder-documents.svg icons/luv-icon-theme/Luv/places/64/folder-download.svg icons/luv-icon-theme/Luv/places/64/folder-dropbox.svg icons/luv-icon-theme/Luv/places/64/folder-github.svg icons/luv-icon-theme/Luv/places/64/folder-google-drive.svg icons/luv-icon-theme/Luv/places/64/folder-launchpad.svg icons/luv-icon-theme/Luv/places/64/folder-mega.svg icons/luv-icon-theme/Luv/places/64/folder-music.svg icons/luv-icon-theme/Luv/places/64/folder-network.svg icons/luv-icon-theme/Luv/places/64/folder-pictures.svg icons/luv-icon-theme/Luv/places/64/folder-publicshare.svg icons/luv-icon-theme/Luv/places/64/folder-red.svg icons/luv-icon-theme/Luv/places/64/folder-templates.svg icons/luv-icon-theme/Luv/places/64/folder-videos.svg icons/luv-icon-theme/Luv/places/64/folder.svg icons/luv-icon-theme/Luv/places/64/network-workgroup.svg icons/luv-icon-theme/Luv/places/64/user-desktop.svg icons/luv-icon-theme/Luv/places/64/user-home.svg icons/luv-icon-theme/Luv/places/64/user-trash-full.svg icons/luv-icon-theme/Luv/places/64/user-trash.svg icons/luv-icon-theme/Luv/status/22/dialog-information.svg icons/luv-icon-theme/Luv/status/22/update-high.svg icons/luv-icon-theme/Luv/status/22/update-low.svg icons/luv-icon-theme/Luv/status/22/update-medium.svg icons/luv-icon-theme/Luv/status/22/update-none.svg icons/luv-icon-theme/Luv/status/32/security-high.svg icons/luv-icon-theme/Luv/status/32/update-none.svg icons/luv-icon-theme/Luv/status/32/user-online.svg icons/luv-icon-theme/Luv/status/32/weather-clear-night.svg icons/luv-icon-theme/Luv/status/32/weather-clear.svg icons/luv-icon-theme/Luv/status/32/weather-clouds-nights.svg icons/luv-icon-theme/Luv/status/32/weather-clouds.svg icons/luv-icon-theme/Luv/status/32/weather-few-clouds-night.svg icons/luv-icon-theme/Luv/status/32/weather-few-clouds.svg icons/luv-icon-theme/Luv/status/32/weather-freezing-rain.svg icons/luv-icon-theme/Luv/status/32/weather-hail.svg icons/luv-icon-theme/Luv/status/32/weather-many-clouds.svg icons/luv-icon-theme/Luv/status/32/weather-overcast.svg icons/luv-icon-theme/Luv/status/32/weather-showers-day.svg icons/luv-icon-theme/Luv/status/32/weather-showers-night.svg icons/luv-icon-theme/Luv/status/32/weather-showers-scattered-day.svg icons/luv-icon-theme/Luv/status/32/weather-showers-scattered-night.svg icons/luv-icon-theme/Luv/status/32/weather-showers-scattered.svg icons/luv-icon-theme/Luv/status/32/weather-showers.svg icons/luv-icon-theme/Luv/status/32/weather-snow-rain.svg icons/luv-icon-theme/Luv/status/32/weather-snow-scattered-day.svg icons/luv-icon-theme/Luv/status/32/weather-snow-scattered-night.svg icons/luv-icon-theme/Luv/status/32/weather-snow-scattered.svg icons/luv-icon-theme/Luv/status/32/weather-snow.svg icons/luv-icon-theme/Luv/status/32/weather-storm-night.svg icons/luv-icon-theme/Luv/status/32/weather-storm.svg icons/luv-icon-theme/Luv/status/48/dialog-information.svg icons/luv-icon-theme/Luv/status/64/dialog-information.svg icons/luv-icon-theme/Luv/status/128/dialog-information.svg icons/luv-icon-theme/Luv/status/128/user-identity.svg icons/luv-icon-theme/Luv/apps/22/nx-software-center.svg icons/luv-icon-theme/Luv/actions/22/checkbox.svg icons/luv-icon-theme/Luv/actions/22/configure-toolbars.svg icons/luv-icon-theme/Luv/actions/22/draw-star.svg icons/luv-icon-theme/Luv/actions/22/edit-link.svg icons/luv-icon-theme/Luv/actions/22/go-bottom.svg icons/luv-icon-theme/Luv/actions/22/go-jump.svg icons/luv-icon-theme/Luv/actions/22/go-top.svg icons/luv-icon-theme/Luv/actions/22/handle-sort.svg icons/luv-icon-theme/Luv/actions/22/image-preview.svg icons/luv-icon-theme/Luv/actions/22/item-select.svg icons/luv-icon-theme/Luv/actions/22/list-add-user.svg icons/luv-icon-theme/Luv/actions/22/ok-apply.svg icons/luv-icon-theme/Luv/actions/22/settings-configure.svg icons/luv-icon-theme/Luv/actions/22/view-calendar.svg icons/luv-icon-theme/Luv/actions/22/view-media-video.svg icons/luv-icon-theme/Luv/actions/22/zoom-fit-height.svg icons/luv-icon-theme/Luv/actions/22/zoom-fit-width.svg icons/luv-icon-theme/Luv/actions/22/zoom-in.svg icons/luv-icon-theme/Luv/actions/22/zoom-original.svg icons/luv-icon-theme/Luv/actions/22/zoom-out.svg icons/luv-icon-theme/Luv/actions/22/zoom.svg icons/luv-icon-theme/Luv/actions/22/sms.svg icons/luv-icon-theme/Luv/actions/22/email.svg - icons/luv-icon-theme/Luv/actions/22/edit-add-effect.svg - icons/luv-icon-theme/Luv/actions/22/dialer-call-start.svg - icons/luv-icon-theme/Luv/actions/22/dialer-call-pause.svg - icons/luv-icon-theme/Luv/actions/22/dialer-call-end.svg icons/luv-icon-theme/Luv/actions/22/view-pim-notes.svg icons/luv-icon-theme/Luv/actions/22/view-pim-news.svg icons/luv-icon-theme/Luv/actions/22/view-pim-journal.svg icons/luv-icon-theme/Luv/actions/22/view-pim-contacts.svg icons/luv-icon-theme/Luv/actions/22/view-contacts.svg icons/luv-icon-theme/Luv/actions/22/send-sms.svg icons/luv-icon-theme/Luv/actions/22/send-email.svg icons/luv-icon-theme/Luv/actions/22/pin.svg icons/luv-icon-theme/Luv/actions/22/media-speaker.svg icons/luv-icon-theme/Luv/actions/22/media-silence.svg icons/luv-icon-theme/Luv/actions/22/media-bluetooth.svg icons/luv-icon-theme/Luv/actions/22/folder-new.svg - icons/luv-icon-theme/Luv/actions/22/email.svg icons/luv-icon-theme/Luv/actions/22/edit-add-effect.svg icons/luv-icon-theme/Luv/actions/22/dialer-pad.svg icons/luv-icon-theme/Luv/actions/22/dialer-call.svg icons/luv-icon-theme/Luv/actions/22/dialer-call-start.svg icons/luv-icon-theme/Luv/actions/22/dialer-call-pause.svg icons/luv-icon-theme/Luv/actions/22/dialer-call-end.svg icons/luv-icon-theme/Luv/actions/22/add-image.svg icons/luv-icon-theme/Luv/apps/22/search.svg icons/luv-icon-theme/Luv/apps/22/kup.svg icons/luv-icon-theme/Luv/apps/22/appimage-store.svg icons/luv-icon-theme/Luv/apps/64/znx-gui.svg icons/luv-icon-theme/Luv/apps/64/win-launcher.svg icons/luv-icon-theme/Luv/apps/64/vvave.svg icons/luv-icon-theme/Luv/apps/64/vlc.svg icons/luv-icon-theme/Luv/apps/64/virtualbox.svg icons/luv-icon-theme/Luv/apps/64/utilities-text-editor.svg icons/luv-icon-theme/Luv/apps/64/utilities-terminal.svg icons/luv-icon-theme/Luv/apps/64/utilities-system-monitor.svg icons/luv-icon-theme/Luv/apps/64/utilities-file-archiver.svg icons/luv-icon-theme/Luv/apps/64/trash-empty.svg icons/luv-icon-theme/Luv/apps/64/systemback.svg icons/luv-icon-theme/Luv/apps/64/system-switch-user.svg icons/luv-icon-theme/Luv/apps/64/system-suspend.svg icons/luv-icon-theme/Luv/apps/64/system-suspend-hibernate.svg icons/luv-icon-theme/Luv/apps/64/system-shutdown.svg icons/luv-icon-theme/Luv/apps/64/system-reboot.svg icons/luv-icon-theme/Luv/apps/64/system-log-out.svg icons/luv-icon-theme/Luv/apps/64/system-lock-screen.svg icons/luv-icon-theme/Luv/apps/64/system-file-manager.svg icons/luv-icon-theme/Luv/apps/64/spotify-client.svg icons/luv-icon-theme/Luv/apps/64/spectacle.svg icons/luv-icon-theme/Luv/apps/64/simplescreenrecorder.svg icons/luv-icon-theme/Luv/apps/64/showimage.svg icons/luv-icon-theme/Luv/apps/64/qupzilla.svg icons/luv-icon-theme/Luv/apps/64/QtProject-qtcreator.svg icons/luv-icon-theme/Luv/apps/64/qtlogo.svg icons/luv-icon-theme/Luv/apps/64/qtlinguist.svg icons/luv-icon-theme/Luv/apps/64/qtdesigner.svg icons/luv-icon-theme/Luv/apps/64/qtcreator.svg icons/luv-icon-theme/Luv/apps/64/qtasistant.svg icons/luv-icon-theme/Luv/apps/64/qpdfview.svg icons/luv-icon-theme/Luv/apps/64/preferences-system.svg icons/luv-icon-theme/Luv/apps/64/partitionmanager.svg icons/luv-icon-theme/Luv/apps/64/okular.svg icons/luv-icon-theme/Luv/apps/64/octopi.svg icons/luv-icon-theme/Luv/apps/64/nx-software-updater.svg icons/luv-icon-theme/Luv/apps/64/nx-software-center.svg icons/luv-icon-theme/Luv/apps/64/muon.svg icons/luv-icon-theme/Luv/apps/64/maui-pix.svg icons/luv-icon-theme/Luv/apps/64/maui-nota.svg icons/luv-icon-theme/Luv/apps/64/maui-dialer.svg icons/luv-icon-theme/Luv/apps/64/maui-buho.svg icons/luv-icon-theme/Luv/apps/64/live-installer.svg icons/luv-icon-theme/Luv/apps/64/linguist-qt5.svg icons/luv-icon-theme/Luv/apps/64/lightworks.svg icons/luv-icon-theme/Luv/apps/64/libreoffice-writer.svg icons/luv-icon-theme/Luv/apps/64/libreoffice-startcenter.svg icons/luv-icon-theme/Luv/apps/64/libreoffice-math.svg icons/luv-icon-theme/Luv/apps/64/libreoffice-impress.svg icons/luv-icon-theme/Luv/apps/64/libreoffice-draw.svg icons/luv-icon-theme/Luv/apps/64/libreoffice-calc.svg icons/luv-icon-theme/Luv/apps/64/libreoffice-base.svg icons/luv-icon-theme/Luv/apps/64/latte-dock.svg icons/luv-icon-theme/Luv/apps/64/kwalletmanager.svg icons/luv-icon-theme/Luv/apps/64/kvantum.svg icons/luv-icon-theme/Luv/apps/64/kruler.svg icons/luv-icon-theme/Luv/apps/64/konqueror.svg icons/luv-icon-theme/Luv/apps/64/kmag.svg icons/luv-icon-theme/Luv/apps/64/klipper.svg icons/luv-icon-theme/Luv/apps/64/kdevelop.svg icons/luv-icon-theme/Luv/apps/64/kdenlive.svg icons/luv-icon-theme/Luv/apps/64/kdeconnect.svg icons/luv-icon-theme/Luv/apps/64/kcolorchooser.svg icons/luv-icon-theme/Luv/apps/64/kate.svg icons/luv-icon-theme/Luv/apps/64/itch-io.svg icons/luv-icon-theme/Luv/apps/64/inkscape.svg icons/luv-icon-theme/Luv/apps/64/imagewriter.svg icons/luv-icon-theme/Luv/apps/64/hwinfo.svg icons/luv-icon-theme/Luv/apps/64/htop.svg icons/luv-icon-theme/Luv/apps/64/gwenview.svg icons/luv-icon-theme/Luv/apps/64/google-chrome.svg icons/luv-icon-theme/Luv/apps/64/google-chrome-beta.svg icons/luv-icon-theme/Luv/apps/64/gimp.svg icons/luv-icon-theme/Luv/apps/64/gedit.svg icons/luv-icon-theme/Luv/apps/64/firefox.svg icons/luv-icon-theme/Luv/apps/64/designer-qt5.svg icons/luv-icon-theme/Luv/apps/64/cutemarked.svg icons/luv-icon-theme/Luv/apps/64/CMakeSetup.svg icons/luv-icon-theme/Luv/apps/64/chromium-browser.svg icons/luv-icon-theme/Luv/apps/64/calamares.svg icons/luv-icon-theme/Luv/apps/64/assistant-qt5.svg icons/luv-icon-theme/Luv/apps/64/asc-de.svg icons/luv-icon-theme/Luv/apps/64/ark.svg icons/luv-icon-theme/Luv/apps/64/anbox.svg icons/luv-icon-theme/Luv/apps/48/znx-gui.svg icons/luv-icon-theme/Luv/apps/48/vvave.svg icons/luv-icon-theme/Luv/apps/48/vlc.svg icons/luv-icon-theme/Luv/apps/48/utilities-text-editor.svg icons/luv-icon-theme/Luv/apps/48/utilities-terminal.svg icons/luv-icon-theme/Luv/apps/48/systemback.svg icons/luv-icon-theme/Luv/apps/48/system-file-manager.svg icons/luv-icon-theme/Luv/apps/48/steam.svg icons/luv-icon-theme/Luv/apps/48/spotify-client.svg icons/luv-icon-theme/Luv/apps/48/qtlogo.svg icons/luv-icon-theme/Luv/apps/48/qtdesigner.svg icons/luv-icon-theme/Luv/apps/48/qtcreator.svg icons/luv-icon-theme/Luv/apps/48/preferences-system.svg icons/luv-icon-theme/Luv/apps/48/nx-software-updater.svg icons/luv-icon-theme/Luv/apps/48/nx-software-center.svg icons/luv-icon-theme/Luv/apps/48/maui-buho.svg icons/luv-icon-theme/Luv/apps/48/libreoffice-writer.svg icons/luv-icon-theme/Luv/apps/48/libreoffice-startcenter.svg icons/luv-icon-theme/Luv/apps/48/libreoffice-math.svg icons/luv-icon-theme/Luv/apps/48/libreoffice-impress.svg icons/luv-icon-theme/Luv/apps/48/libreoffice-draw.svg icons/luv-icon-theme/Luv/apps/48/libreoffice-calc.svg icons/luv-icon-theme/Luv/apps/48/libreoffice-base.svg icons/luv-icon-theme/Luv/apps/48/ktorrent.svg icons/luv-icon-theme/Luv/apps/48/kate.svg icons/luv-icon-theme/Luv/apps/48/inkscape.svg icons/luv-icon-theme/Luv/apps/48/imagewriter.svg icons/luv-icon-theme/Luv/apps/48/google-chrome.svg icons/luv-icon-theme/Luv/apps/48/google-chrome-beta.svg icons/luv-icon-theme/Luv/apps/48/gedit.svg icons/luv-icon-theme/Luv/apps/48/firefox.svg icons/luv-icon-theme/Luv/apps/48/cutemarked.svg icons/luv-icon-theme/Luv/apps/48/chromium-browser.svg icons/luv-icon-theme/Luv/apps/48/calamares.svg icons/luv-icon-theme/Luv/apps/48/asc-de.svg icons/luv-icon-theme/Luv/apps/48/anbox.svg icons/luv-icon-theme/Luv/places/22/user-home.svg icons/luv-icon-theme/Luv/places/22/folder.svg icons/luv-icon-theme/Luv/places/22/folder-videos.svg icons/luv-icon-theme/Luv/places/22/folder-pictures.svg icons/luv-icon-theme/Luv/places/22/folder-music.svg icons/luv-icon-theme/Luv/places/22/folder-download.svg icons/luv-icon-theme/Luv/places/22/folder-documents.svg icons/luv-icon-theme/Luv/places/22/start-here.svg icons/luv-icon-theme/Luv/places/22/folder-cloud.svg icons/luv-icon-theme/Luv/places/32/folder-orange.svg icons/luv-icon-theme/Luv/places/32/folder-grey.svg icons/luv-icon-theme/Luv/places/32/folder-green.svg icons/luv-icon-theme/Luv/places/32/folder-black.svg icons/luv-icon-theme/Luv/places/32/folder-cloud.svg icons/luv-icon-theme/Luv/places/32/folder-applications.svg icons/luv-icon-theme/Luv/places/48/folder-orange.svg icons/luv-icon-theme/Luv/places/48/folder-grey.svg icons/luv-icon-theme/Luv/places/48/folder-green.svg icons/luv-icon-theme/Luv/places/48/folder-black.svg icons/luv-icon-theme/Luv/places/48/folder-cloud.svg icons/luv-icon-theme/Luv/places/48/folder-applications.svg icons/luv-icon-theme/Luv/places/64/folder-orange.svg icons/luv-icon-theme/Luv/places/64/folder-grey.svg icons/luv-icon-theme/Luv/places/64/folder-green.svg icons/luv-icon-theme/Luv/places/64/folder-black.svg icons/luv-icon-theme/Luv/places/64/folder-cloud.svg icons/luv-icon-theme/Luv/places/64/folder-applications.svg icons/luv-icon-theme/Luv/places/16/folder-open.svg icons/luv-icon-theme/Luv/places/16/folder-google-drive.svg icons/luv-icon-theme/Luv/places/16/folder-github.svg icons/luv-icon-theme/Luv/places/16/folder-cloud.svg icons/luv-icon-theme/Luv/places/16/folder-applications.svg icons/luv-icon-theme/Luv/actions/22/view-file-columns.svg icons/luv-icon-theme/Luv/actions/22/sidebar-expand.svg icons/luv-icon-theme/Luv/actions/22/sidebar-collapse.svg icons/luv-icon-theme/Luv/actions/22/edit-select-all.svg icons/luv-icon-theme/Luv/actions/16/view-split-top-bottom.svg icons/luv-icon-theme/Luv/actions/16/view-split-left-right.svg icons/luv-icon-theme/Luv/actions/16/view-sort.svg icons/luv-icon-theme/Luv/actions/16/view-side-tree.svg icons/luv-icon-theme/Luv/actions/16/view-links.svg icons/luv-icon-theme/Luv/actions/16/view-choose.svg icons/luv-icon-theme/Luv/actions/16/view-barcode.svg icons/luv-icon-theme/Luv/actions/16/tab-duplicate.svg icons/luv-icon-theme/Luv/actions/16/project-open.svg icons/luv-icon-theme/Luv/actions/16/process-stop.svg icons/luv-icon-theme/Luv/actions/16/handle-sort.svg icons/luv-icon-theme/Luv/actions/16/go-jump.svg icons/luv-icon-theme/Luv/actions/16/folder-new.svg icons/luv-icon-theme/Luv/actions/16/folder-add.svg icons/luv-icon-theme/Luv/actions/16/edit-rename.svg icons/luv-icon-theme/Luv/actions/16/edit-link.svg icons/luv-icon-theme/Luv/actions/16/edit-clear.svg icons/luv-icon-theme/Luv/actions/16/document-open-recent.svg icons/luv-icon-theme/Luv/actions/16/document-edit.svg icons/luv-icon-theme/Luv/actions/16/archive-remove.svg icons/luv-icon-theme/Luv/actions/16/archive-insert.svg icons/luv-icon-theme/Luv/actions/16/archive-extract.svg icons/luv-icon-theme/Luv/mimetypes/16/text-x-generic.svg icons/luv-icon-theme/Luv/mimetypes/16/application-x-zerosize.svg icons/luv-icon-theme/Luv/mimetypes/32/application-x-zerosize.svg icons/luv-icon-theme/Luv/mimetypes/48/application-x-zerosize.svg icons/luv-icon-theme/Luv/mimetypes/64/text-xml.svg icons/luv-icon-theme/Luv/mimetypes/64/text-x-qml.svg icons/luv-icon-theme/Luv/mimetypes/64/text-x-chdr.svg icons/luv-icon-theme/Luv/mimetypes/64/text-x-c++src.svg icons/luv-icon-theme/Luv/mimetypes/64/audio-x-mpeg.svg icons/luv-icon-theme/Luv/mimetypes/64/audio-x-flac.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-partial-download.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-rpm.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-rar.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-msdownload.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-ms-dos-executable.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-mimearchive.svg icons/luv-icon-theme/Luv/mimetypes/64/application-x-iso9660-appimage.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.debian.binary-package.svg icons/luv-icon-theme/Luv/mimetypes/64/application-vnd.appimage.svg icons/luv-icon-theme/Luv/mimetypes/64/application-rtf.svg icons/luv-icon-theme/Luv/places/22/folder-music-sidebar.svg icons/luv-icon-theme/Luv/places/22/user-home-sidebar.svg icons/luv-icon-theme/Luv/places/22/folder-videos-sidebar.svg icons/luv-icon-theme/Luv/places/22/folder-sidebar.svg icons/luv-icon-theme/Luv/places/22/folder-pictures-sidebar.svg icons/luv-icon-theme/Luv/places/22/folder-download-sidebar.svg icons/luv-icon-theme/Luv/places/22/folder-documents-sidebar.svg icons/luv-icon-theme/Luv/places/22/folder-cloud-sidebar.svg + icons/luv-icon-theme/Luv/mimetypes/64/audio-mpeg.svg + icons/luv-icon-theme/Luv/mimetypes/64/audio-mp4.svg + icons/luv-icon-theme/Luv/mimetypes/64/audio-flac.svg diff --git a/src/android/mauiandroid.cpp b/src/android/mauiandroid.cpp index 26da3db..4291ea7 100644 --- a/src/android/mauiandroid.cpp +++ b/src/android/mauiandroid.cpp @@ -1,721 +1,740 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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 "mauiandroid.h" #include #include #include #include #include #include #include #include #include #include "utils.h" #include // WindowManager.LayoutParams #define FLAG_TRANSLUCENT_STATUS 0x04000000 #define FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 0x80000000 // View #define SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 0x00002000 - +#define SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR 0x00000010 class InterfaceConnFailedException : public QException { public: void raise() const { throw *this; } InterfaceConnFailedException *clone() const { return new InterfaceConnFailedException(*this); } }; MAUIAndroid::MAUIAndroid(QObject *parent) : QObject(parent) {} MAUIAndroid::~MAUIAndroid() {} QString MAUIAndroid::getAccounts() { QAndroidJniObject str = QAndroidJniObject::callStaticObjectMethod("com/kde/maui/tools/Union", "getAccounts", "(Landroid/content/Context;)Ljava/lang/String;", QtAndroid::androidActivity().object()); return str.toString(); } QVariantList MAUIAndroid::getCallLogs() { QVariantList res; QAndroidJniObject logsObj = QAndroidJniObject::callStaticObjectMethod("com/kde/maui/tools/Union", "callLogs", "(Landroid/content/Context;)Ljava/util/List;", QtAndroid::androidActivity().object()); return MAUIAndroid::transform(logsObj); } QImage toImage(const QAndroidJniObject &bitmap) { QAndroidJniEnvironment env; AndroidBitmapInfo info; if (AndroidBitmap_getInfo(env, bitmap.object(), &info) != ANDROID_BITMAP_RESULT_SUCCESS) return QImage(); QImage::Format format; switch (info.format) { case ANDROID_BITMAP_FORMAT_RGBA_8888: format = QImage::Format_RGBA8888; break; case ANDROID_BITMAP_FORMAT_RGB_565: format = QImage::Format_RGB16; break; case ANDROID_BITMAP_FORMAT_RGBA_4444: format = QImage::Format_ARGB4444_Premultiplied; break; case ANDROID_BITMAP_FORMAT_A_8: format = QImage::Format_Alpha8; break; default: return QImage(); } void *pixels; if (AndroidBitmap_lockPixels(env, bitmap.object(), &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) return QImage(); QImage image(info.width, info.height, format); if (info.stride == uint32_t(image.bytesPerLine())) { memcpy((void*)image.constBits(), pixels, info.stride * info.height); } else { uchar *bmpPtr = static_cast(pixels); const unsigned width = std::min(info.width, (uint)image.width()); const unsigned height = std::min(info.height, (uint)image.height()); for (unsigned y = 0; y < height; y++, bmpPtr += info.stride) memcpy((void*)image.constScanLine(y), bmpPtr, width); } if (AndroidBitmap_unlockPixels(env, bitmap.object()) != ANDROID_BITMAP_RESULT_SUCCESS) return QImage(); return image; } QVariantList MAUIAndroid::getContacts() { QVariantList res; QAndroidJniObject contactsObj = QAndroidJniObject::callStaticObjectMethod("com/kde/maui/tools/Union", "fetchContacts", "(Landroid/content/Context;)Ljava/util/List;", QtAndroid::androidActivity().object()); return MAUIAndroid::transform(contactsObj); } QVariantMap MAUIAndroid::getContact(const QString &id) { QAndroidJniObject contactObj = QAndroidJniObject::callStaticObjectMethod("com/kde/maui/tools/Union", "getContact", "(Landroid/content/Context;Ljava/lang/String;)Ljava/util/HashMap;", QtAndroid::androidActivity().object(), QAndroidJniObject::fromString(id).object()); return MAUIAndroid::createVariantMap(contactObj.object()); } void MAUIAndroid::addContact(const QString &name, const QString &tel, const QString &tel2, const QString &tel3, const QString &email, const QString &title, const QString &org, const QString &photo, const QString &account, const QString &accountType) { qDebug()<< "Adding new contact to android"; QAndroidJniObject::callStaticMethod("com/kde/maui/tools/Union", "addContact", "(Landroid/content/Context;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;)V", QtAndroid::androidActivity().object(), QAndroidJniObject::fromString(name).object(), QAndroidJniObject::fromString(tel).object(), QAndroidJniObject::fromString(tel2).object(), QAndroidJniObject::fromString(tel3).object(), QAndroidJniObject::fromString(email).object(), QAndroidJniObject::fromString(title).object(), QAndroidJniObject::fromString(org).object(), QAndroidJniObject::fromString(photo).object(), QAndroidJniObject::fromString(account).object(), QAndroidJniObject::fromString(accountType).object() ); } void MAUIAndroid::updateContact(const QString &id, const QString &field, const QString &value) { QAndroidJniObject::callStaticMethod("com/kde/maui/tools/Union", "updateContact", "(Landroid/content/Context;" "Ljava/lang/String;" "Ljava/lang/String;" "Ljava/lang/String;)V", QtAndroid::androidActivity().object(), QAndroidJniObject::fromString(id).object(), QAndroidJniObject::fromString(field).object(), QAndroidJniObject::fromString(value).object() ); } void MAUIAndroid::call(const QString &tel) { QAndroidJniEnvironment _env; QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } if ( activity.isValid() ) { qDebug()<< "trying to call from senitents" << tel; QAndroidJniObject::callStaticMethod("com/kde/maui/tools/SendIntent", "call", "(Landroid/app/Activity;Ljava/lang/String;)V", activity.object(), QAndroidJniObject::fromString(tel).object()); if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } }else throw InterfaceConnFailedException(); } static QAndroidJniObject getAndroidWindow() { QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;"); window.callMethod("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.callMethod("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS); return window; } void MAUIAndroid::statusbarColor(const QString &bg, const bool &light) { if (QtAndroid::androidSdkVersion() < 23) return; QtAndroid::runOnAndroidThread([=]() { QAndroidJniObject window = getAndroidWindow(); QAndroidJniObject view = window.callObjectMethod("getDecorView", "()Landroid/view/View;"); int visibility = view.callMethod("getSystemUiVisibility", "()I"); if (light) visibility |= SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; else visibility &= ~SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; view.callMethod("setSystemUiVisibility", "(I)V", visibility); window.callMethod("setStatusBarColor", "(I)V", QColor(bg).rgba()); }); } +void MAUIAndroid::navBarColor(const QString &bg, const bool &light) +{ + if (QtAndroid::androidSdkVersion() < 23) + return; + + QtAndroid::runOnAndroidThread([=]() { + + QAndroidJniObject window = getAndroidWindow(); + QAndroidJniObject view = window.callObjectMethod("getDecorView", "()Landroid/view/View;"); + int visibility = view.callMethod("getSystemUiVisibility", "()I"); + if (light) + visibility |= SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; + else + visibility &= ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; + view.callMethod("setSystemUiVisibility", "(I)V", visibility); + window.callMethod("setNavigationBarColor", "(I)V", QColor(bg).rgba()); + }); +} + void MAUIAndroid::shareDialog(const QUrl &url) { qDebug()<< "trying to share dialog"; QAndroidJniEnvironment _env; QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } if (activity.isValid()) { QMimeDatabase mimedb; QString mimeType = mimedb.mimeTypeForFile(url.toLocalFile()).name(); QAndroidJniObject::callStaticMethod("com/kde/maui/tools/SendIntent", "share", "(Landroid/app/Activity;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", activity.object(), QAndroidJniObject::fromString(url.toLocalFile()).object(), QAndroidJniObject::fromString(mimeType).object(), QAndroidJniObject::fromString(QString("%1.fileprovider").arg(UTIL::app->organizationDomain())).object()); if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } }else throw InterfaceConnFailedException(); } void MAUIAndroid::shareText(const QString &text) { qDebug()<< "trying to share text"; QAndroidJniEnvironment _env; QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } if ( activity.isValid() ) { QAndroidJniObject::callStaticMethod("com/kde/maui/tools/SendIntent", "sendText", "(Landroid/app/Activity;Ljava/lang/String;)V", activity.object(), QAndroidJniObject::fromString(text).object()); if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } }else throw InterfaceConnFailedException(); } void MAUIAndroid::shareLink(const QString &link) { qDebug()<< "trying to share link"; QAndroidJniEnvironment _env; QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } if ( activity.isValid() ) { QAndroidJniObject::callStaticMethod("com/kde/maui/tools/SendIntent", "sendUrl", "(Landroid/app/Activity;Ljava/lang/String;)V", activity.object(), QAndroidJniObject::fromString(link).object()); if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } }else throw InterfaceConnFailedException(); } void MAUIAndroid::shareContact(const QString &id) { QAndroidJniObject::callStaticMethod("com/kde/maui/tools/Union", "shareContact", "(Landroid/content/Context;" "Ljava/lang/String;)V", QtAndroid::androidActivity().object(), QAndroidJniObject::fromString(id).object()); } void MAUIAndroid::sendSMS(const QString &tel,const QString &subject, const QString &message ) { qDebug()<< "trying to send sms text"; QAndroidJniEnvironment _env; QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } if ( activity.isValid() ) { QAndroidJniObject::callStaticMethod("com/kde/maui/tools/SendIntent", "sendSMS", "(Landroid/app/Activity;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", activity.object(), QAndroidJniObject::fromString(tel).object(), QAndroidJniObject::fromString(subject).object(), QAndroidJniObject::fromString(message).object()); if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } }else throw InterfaceConnFailedException(); } void MAUIAndroid::openUrl(const QUrl &url) { qDebug()<< "trying to open file with"; QAndroidJniEnvironment _env; QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } if (activity.isValid()) { QAndroidJniObject::callStaticMethod("com/kde/maui/tools/SendIntent", "openUrl", "(Landroid/app/Activity;Ljava/lang/String;Ljava/lang/String;)V", activity.object(), QAndroidJniObject::fromString(url.toLocalFile()).object(), QAndroidJniObject::fromString(QString("%1.fileprovider").arg(UTIL::app->organizationDomain())).object()); if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } }else throw InterfaceConnFailedException(); } QString MAUIAndroid::homePath() { QAndroidJniObject mediaDir = QAndroidJniObject::callStaticObjectMethod("android/os/Environment", "getExternalStorageDirectory", "()Ljava/io/File;"); QAndroidJniObject mediaPath = mediaDir.callObjectMethod( "getAbsolutePath", "()Ljava/lang/String;" ); return mediaPath.toString(); } QStringList MAUIAndroid::sdDirs() { // QAndroidJniObject mediaDir = QAndroidJniObject::callStaticObjectMethod("android/os/Environment", "getExternalStorageDirectory", "()Ljava/io/File;"); // QAndroidJniObject mediaPath = mediaDir.callObjectMethod( "getAbsolutePath", "()Ljava/lang/String;" ); // QString dataAbsPath = mediaPath.toString()+"/Download/"; // QAndroidJniEnvironment env; // if (env->ExceptionCheck()) { // // Handle exception here. // env->ExceptionClear(); // } // qbDebug::Instance()->msg()<<"TESTED SDPATH"<(), QAndroidJniObject::fromString(id).object()); if(bitmap != NULL) photo = toImage(bitmap); return photo; } void MAUIAndroid::setAppIcons(const QString &lowDPI, const QString &mediumDPI, const QString &highDPI) { } void MAUIAndroid::setAppInfo(const QString &appName, const QString &version, const QString &uri) { QDomDocument doc("mydocument"); QFile file(":/assets/AndroidManifest.xml"); if (!file.open(QIODevice::ReadOnly)) { qDebug("Cannot open the file"); return; } // Parse file if (!doc.setContent(&file)) { qDebug("Cannot parse the content"); file.close(); return; } file.close(); // Modify content QDomNodeList manifest = doc.elementsByTagName("manifest"); if (manifest.size() < 1) { qDebug("Cannot find manifest"); return; } //Manifest// QDomElement root = manifest.at(0).toElement(); root.setAttribute("package", uri); root.setAttribute("android:versionName", version); //Application// auto applicationNode = root.toElement().elementsByTagName("application"); if (applicationNode.size() < 1) { qDebug("Cannot find application node in manifest"); return; } auto application = applicationNode.at(0).toElement(); application.setAttribute("android:label", appName); // Activity // auto activityNode = application.toElement().elementsByTagName("activity"); if (activityNode.size() < 1) { qDebug("Cannot find activity node in manifest"); return; } auto activity = activityNode.at(0).toElement(); activity.setAttribute("android:label", appName); // Service // auto serviceNode = application.toElement().elementsByTagName("service"); if (serviceNode.size() < 1) { qDebug("Cannot find service node in manifest"); return; } auto service = activityNode.at(0).toElement(); auto serviceMetadataNode = service.elementsByTagName("meta-data"); if (serviceMetadataNode.size() < 1) { qDebug("Cannot find service metadata node in manifest"); return; } auto serviceMetadata = serviceMetadataNode.at(1).toElement(); serviceMetadata.setAttribute("android:value", appName); if(!file.open(QIODevice::Truncate | QIODevice::WriteOnly)) { qDebug("Basically, now we lost content of a file"); return; } QByteArray xml = doc.toByteArray(); file.write(xml); file.close(); } void MAUIAndroid::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) { qDebug()<< "ACTIVITY RESULTS"; jint RESULT_OK = QAndroidJniObject::getStaticField("android/app/Activity", "RESULT_OK"); if (receiverRequestCode == 42 && resultCode == RESULT_OK) { QString url = data.callObjectMethod("getData", "()Landroid/net/Uri;").callObjectMethod("getPath", "()Ljava/lang/String;").toString(); emit folderPicked(url); } } void MAUIAndroid::fileChooser() { QAndroidJniEnvironment _env; QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); //activity is valid if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } if ( activity.isValid() ) { QAndroidJniObject::callStaticMethod("com/example/android/tools/SendIntent", "fileChooser", "(Landroid/app/Activity;)V", activity.object()); if (_env->ExceptionCheck()) { _env->ExceptionClear(); throw InterfaceConnFailedException(); } }else throw InterfaceConnFailedException(); } QVariantList MAUIAndroid::transform(const QAndroidJniObject &obj) { QVariantList res; const auto size = obj.callMethod("size", "()I"); for(auto i = 0; i()); } return res; } QVariantMap MAUIAndroid::createVariantMap(jobject data) { QVariantMap res; QAndroidJniEnvironment env; /* Reference : https://community.oracle.com/thread/1549999 */ // Get the HashMap Class jclass jclass_of_hashmap = (env)->GetObjectClass(data); // Get link to Method "entrySet" jmethodID entrySetMethod = (env)->GetMethodID(jclass_of_hashmap, "entrySet", "()Ljava/util/Set;"); // Invoke the "entrySet" method on the HashMap object jobject jobject_of_entryset = env->CallObjectMethod(data, entrySetMethod); // Get the Set Class jclass jclass_of_set = (env)->FindClass("java/util/Set"); // Problem during compilation !!!!! if (jclass_of_set == 0) { qWarning() << "java/util/Set lookup failed\n"; return res; } // Get link to Method "iterator" jmethodID iteratorMethod = env->GetMethodID(jclass_of_set, "iterator", "()Ljava/util/Iterator;"); // Invoke the "iterator" method on the jobject_of_entryset variable of type Set jobject jobject_of_iterator = env->CallObjectMethod(jobject_of_entryset, iteratorMethod); // Get the "Iterator" class jclass jclass_of_iterator = (env)->FindClass("java/util/Iterator"); // Get link to Method "hasNext" jmethodID hasNextMethod = env->GetMethodID(jclass_of_iterator, "hasNext", "()Z"); jmethodID nextMethod = env->GetMethodID(jclass_of_iterator, "next", "()Ljava/lang/Object;"); while (env->CallBooleanMethod(jobject_of_iterator, hasNextMethod) ) { jobject jEntry = env->CallObjectMethod(jobject_of_iterator,nextMethod); QAndroidJniObject entry = QAndroidJniObject(jEntry); QAndroidJniObject key = entry.callObjectMethod("getKey","()Ljava/lang/Object;"); QAndroidJniObject value = entry.callObjectMethod("getValue","()Ljava/lang/Object;"); QString k = key.toString(); QVariant v = value.toString(); env->DeleteLocalRef(jEntry); if (v.isNull()) { continue; } res[k] = v; } if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear(); } env->DeleteLocalRef(jclass_of_hashmap); env->DeleteLocalRef(jobject_of_entryset); env->DeleteLocalRef(jclass_of_set); env->DeleteLocalRef(jobject_of_iterator); env->DeleteLocalRef(jclass_of_iterator); return res; } QStringList MAUIAndroid::defaultPaths() { QStringList paths; paths.append(PATHS::HomePath); paths.append(PATHS::DocumentsPath); paths.append(PATHS::MusicPath); paths.append(PATHS::VideosPath); paths.append(PATHS::PicturesPath); paths.append(PATHS::DownloadsPath); return paths; } bool MAUIAndroid::checkRunTimePermissions() { qDebug()<< "CHECKIGN PERMISSSIONS"; // QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); // if(r == QtAndroid::PermissionResult::Denied) { // QtAndroid::requestPermissionsSync( QStringList() << "android.permission.WRITE_EXTERNAL_STORAGE" ); // r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); // if(r == QtAndroid::PermissionResult::Denied) { // qDebug() << "Permission denied"; // return false; // } // } // qDebug() << "Permissions granted!"; // return true; // QAndroidJniObject::callStaticMethod("com/kde/maui/tools/SendIntent", // "requestPermission", // "(Landroid/app/Activity;)V", // QtAndroid::androidActivity().object()); QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); if(r == QtAndroid::PermissionResult::Denied) { QtAndroid::requestPermissionsSync( QStringList() << "android.permission.WRITE_EXTERNAL_STORAGE" ); r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); if(r == QtAndroid::PermissionResult::Denied) { qDebug() << "Permission denied"; return false; } } qDebug() << "Permissions granted!"; return true; // C++ // QAndroidJniObject::callStaticMethod("com/kde/maui/tools/SDCard", // "getStorageNames", // "(Landroid/app/Activity;)V", // QtAndroid::androidActivity().object()); // return (true); } diff --git a/src/android/mauiandroid.h b/src/android/mauiandroid.h index 9185f87..12f9025 100644 --- a/src/android/mauiandroid.h +++ b/src/android/mauiandroid.h @@ -1,90 +1,92 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ #ifndef MAUIANDROID_H #define MAUIANDROID_H #include #include #include #include #include #include #include #include #include #include -class MAUIAndroid : public QObject +class Q_DECL_EXPORT MAUIAndroid : public QObject { Q_OBJECT public: MAUIAndroid(QObject *parent = nullptr); ~MAUIAndroid(); void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data); static QImage contactPhoto(const QString &id); static void addContact(const QString &name, const QString &tel, const QString &tel2, const QString &tel3, const QString &email, const QString &title, const QString &org, const QString &photo, const QString &account, const QString &accountType); static void updateContact(const QString &id, const QString &field, const QString &value); static void setAppIcons(const QString &lowDPI, const QString &mediumDPI, const QString &highDPI); static void setAppInfo(const QString &appName, const QString &version, const QString &uri); static void fileChooser(); private: static QVariantList transform(const QAndroidJniObject &obj); static QVariantMap createVariantMap(jobject data); public slots: static QString getAccounts(); static QVariantList getCallLogs(); static QVariantList getContacts(); static QVariantMap getContact(const QString &id); static void statusbarColor(const QString &bg, const bool &light); + static void navBarColor(const QString &bg, const bool &light); + static void shareDialog(const QUrl &url); static void shareText(const QString &text); static void sendSMS(const QString &tel,const QString &subject, const QString &message); static void shareLink(const QString &link); static void shareContact(const QString &id); static void openUrl(const QUrl &url); static QStringList defaultPaths(); static QString homePath(); static QStringList sdDirs(); static void call(const QString &tel); static bool checkRunTimePermissions(); signals: void folderPicked(QString path); }; namespace PATHS { const QString HomePath = MAUIAndroid::homePath(); const QString PicturesPath = HomePath+"/"+QAndroidJniObject::getStaticObjectField("android/os/Environment", "DIRECTORY_PICTURES", "Ljava/lang/String;").toString(); const QString DownloadsPath = HomePath+"/"+QAndroidJniObject::getStaticObjectField("android/os/Environment", "DIRECTORY_DOWNLOADS", "Ljava/lang/String;").toString(); const QString DocumentsPath = HomePath+"/"+QAndroidJniObject::getStaticObjectField("android/os/Environment", "DIRECTORY_DOCUMENTS", "Ljava/lang/String;").toString(); const QString MusicPath = HomePath+"/"+QAndroidJniObject::getStaticObjectField("android/os/Environment", "DIRECTORY_MUSIC", "Ljava/lang/String;").toString(); const QString VideosPath = HomePath+"/"+QAndroidJniObject::getStaticObjectField("android/os/Environment", "DIRECTORY_MOVIES", "Ljava/lang/String;").toString(); } #endif // ANDROID_H diff --git a/src/android/src/SendIntent.java b/src/android/src/SendIntent.java index 10338d5..9b862cf 100644 --- a/src/android/src/SendIntent.java +++ b/src/android/src/SendIntent.java @@ -1,147 +1,146 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ package com.kde.maui.tools; import android.util.Log; -import org.qtproject.qt5.android.QtNative; import android.support.v4.content.FileProvider; import android.support.v4.app.ShareCompat; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.Manifest; import android.net.Uri; import java.io.File; import android.provider.ContactsContract; import android.database.Cursor; import android.telephony.gsm.SmsManager; import android.content.pm.PackageManager; import android.os.Build; import java.util.List; import android.content.pm.ResolveInfo; import java.util.ArrayList; import java.io.FileNotFoundException; public class SendIntent { private static final int READ_REQUEST_CODE = 42; private static final int CONTACT_PICKER_RESULT = 1001; public static void sendText(Activity context, String text) { Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, text); sendIntent.setType("text/plain"); context.startActivity(Intent.createChooser(sendIntent, text)); } public static void sendSMS(Activity context, String tel, String subject, String message) { SmsManager smsManager = SmsManager.getDefault(); smsManager.sendTextMessage(tel, null, message, null, null); } public static void sendUrl(Activity context, String text) { Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, text); sendIntent.setType("text/plain"); context.startActivity(Intent.createChooser(sendIntent, text)); } public static void requestPermission(Activity context) { context.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1); } public static void share(Activity context, String url, String mime, String authority) { File file = new File(url); System.out.println(file.exists()); Uri uri; try { uri = FileProvider.getUriForFile(context, authority, file); } catch (IllegalArgumentException e) { System.out.println("cannot be shared: "+ url+ " " +e); return; } - Intent sendIntent = ShareCompat.IntentBuilder.from(QtNative.activity()).getIntent(); + Intent sendIntent = ShareCompat.IntentBuilder.from(context).getIntent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_STREAM, uri); System.out.println(mime); sendIntent.setType(mime); - if (sendIntent.resolveActivity(QtNative.activity().getPackageManager()) != null) + if (sendIntent.resolveActivity(context.getPackageManager()) != null) { context.startActivity(Intent.createChooser(sendIntent, "Share")); } else { System.out.println( "Intent not resolved"); } } public static void openUrl(Activity context, String url, String authority) { File file = new File(url); Uri uri; try { uri = FileProvider.getUriForFile(context, authority, file); } catch (IllegalArgumentException e) { System.out.println("cannot be open: "+ url+ " " +e); return; } String mime = context.getContentResolver().getType(uri); Intent viewIntent = ShareCompat.IntentBuilder.from(context).getIntent(); viewIntent.setAction(Intent.ACTION_VIEW); viewIntent.setDataAndType(uri, mime); viewIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); viewIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); context.startActivity(viewIntent); } public static void fileChooser(Activity context) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setType("audio/*"); context.startActivityForResult(intent, READ_REQUEST_CODE); } public static void call(Activity context, String tel) { Intent callIntent = new Intent(Intent.ACTION_CALL); // callIntent.setPackage("com.android.phone"); // force native dialer (Android < 5) callIntent.setPackage("com.android.server.telecom"); // force native dialer (Android >= 5) callIntent.setData(Uri.parse("tel:" + tel)); callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(callIntent); } } diff --git a/assets.qrc b/src/assets.qrc similarity index 95% rename from assets.qrc rename to src/assets.qrc index 9655dc2..2e6923c 100644 --- a/assets.qrc +++ b/src/assets.qrc @@ -1,22 +1,21 @@ assets/face-sleeping.png assets/face-sleeping.svg - assets/tag.svg assets/maui-app.colors assets/mauikit-logo.png assets/ElectricPlug.png assets/BugSearch.png assets/MoonSki.png assets/application-x-zerosize.svg assets/animat-rocket-color.gif assets/animat-diamond-color.gif assets/animat-search-color.gif assets/opendesktop.png assets/folder-add.svg assets/view-refresh.svg assets/edit-find.svg assets/dialog-information.svg assets/cover.png diff --git a/assets/BugSearch.png b/src/assets/BugSearch.png similarity index 100% rename from assets/BugSearch.png rename to src/assets/BugSearch.png diff --git a/assets/ElectricPlug.png b/src/assets/ElectricPlug.png similarity index 100% rename from assets/ElectricPlug.png rename to src/assets/ElectricPlug.png diff --git a/assets/Grow.png b/src/assets/Grow.png similarity index 100% rename from assets/Grow.png rename to src/assets/Grow.png diff --git a/assets/MoonSki.png b/src/assets/MoonSki.png similarity index 100% rename from assets/MoonSki.png rename to src/assets/MoonSki.png diff --git a/assets/animat-diamond-color.gif b/src/assets/animat-diamond-color.gif similarity index 100% rename from assets/animat-diamond-color.gif rename to src/assets/animat-diamond-color.gif diff --git a/assets/animat-rocket-color.gif b/src/assets/animat-rocket-color.gif similarity index 100% rename from assets/animat-rocket-color.gif rename to src/assets/animat-rocket-color.gif diff --git a/assets/animat-search-color.gif b/src/assets/animat-search-color.gif similarity index 100% rename from assets/animat-search-color.gif rename to src/assets/animat-search-color.gif diff --git a/assets/application-x-zerosize.png b/src/assets/application-x-zerosize.png similarity index 100% rename from assets/application-x-zerosize.png rename to src/assets/application-x-zerosize.png diff --git a/assets/application-x-zerosize.svg b/src/assets/application-x-zerosize.svg similarity index 100% rename from assets/application-x-zerosize.svg rename to src/assets/application-x-zerosize.svg diff --git a/assets/cover.png b/src/assets/cover.png similarity index 100% rename from assets/cover.png rename to src/assets/cover.png diff --git a/assets/dialog-information.svg b/src/assets/dialog-information.svg similarity index 100% rename from assets/dialog-information.svg rename to src/assets/dialog-information.svg diff --git a/assets/edit-find.svg b/src/assets/edit-find.svg similarity index 100% rename from assets/edit-find.svg rename to src/assets/edit-find.svg diff --git a/assets/face-sleeping.png b/src/assets/face-sleeping.png similarity index 100% rename from assets/face-sleeping.png rename to src/assets/face-sleeping.png diff --git a/assets/face-sleeping.svg b/src/assets/face-sleeping.svg similarity index 100% rename from assets/face-sleeping.svg rename to src/assets/face-sleeping.svg diff --git a/assets/folder-add.svg b/src/assets/folder-add.svg similarity index 100% rename from assets/folder-add.svg rename to src/assets/folder-add.svg diff --git a/assets/kirigami-logo.png b/src/assets/kirigami-logo.png similarity index 100% rename from assets/kirigami-logo.png rename to src/assets/kirigami-logo.png diff --git a/assets/maui-app.colors b/src/assets/maui-app.colors similarity index 100% rename from assets/maui-app.colors rename to src/assets/maui-app.colors diff --git a/assets/mauikit-logo.png b/src/assets/mauikit-logo.png similarity index 100% rename from assets/mauikit-logo.png rename to src/assets/mauikit-logo.png diff --git a/assets/opendesktop.png b/src/assets/opendesktop.png similarity index 100% rename from assets/opendesktop.png rename to src/assets/opendesktop.png diff --git a/assets/view-refresh.svg b/src/assets/view-refresh.svg similarity index 100% rename from assets/view-refresh.svg rename to src/assets/view-refresh.svg diff --git a/src/controls/AboutDialog.qml b/src/controls/AboutDialog.qml index bbfae66..ceed5c1 100644 --- a/src/controls/AboutDialog.qml +++ b/src/controls/AboutDialog.qml @@ -1,171 +1,174 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Dialog { id: control - property string appName : Maui.App.name - property string appVersion : Maui.App.version - property string organizationName : Maui.App.org - property string organizationDomain : Maui.App.domain - property string appDescription : Maui.App.description - property string appLink: "www.maui-project.org" - property string appDonation: "" - property string appIcon: Maui.App.iconName - + defaultButtons: false widthHint: 0.9 heightHint: 0.8 maxWidth: Maui.Style.unit * 400 maxHeight: Maui.Style.unit * 250 page.padding: Maui.Style.space.small footBar.middleContent: ToolButton { icon.name: "link" - onClicked: Maui.FM.openUrl(control.appLink) - + onClicked: Qt.openUrlExternally(Maui.App.webPage) } footBar.rightContent: ToolButton { icon.name: "love" - onClicked: Maui.FM.openUrl(control.appDonation) + onClicked: Qt.openUrlExternally(Maui.App.donationPage) } footBar.leftContent: ToolButton { icon.name: "documentinfo" + onClicked: Qt.openUrlExternally(Maui.App.reportPage) } RowLayout { id: layout anchors.centerIn: parent width: parent.width height: parent.height * 0.7 spacing: Maui.Style.space.big Item { visible: parent.width > control.maxWidth * 0.7 Layout.fillHeight: true Layout.margins: Maui.Style.space.small Layout.alignment: Qt.AlignVCenter Layout.preferredWidth: Maui.Style.iconSizes.huge Image { anchors.centerIn: parent - source: control.appIcon + source: Maui.App.iconName width: Math.max(Maui.Style.iconSizes.huge, parent.width) height: width sourceSize.width: width sourceSize.height: height asynchronous: true fillMode: Image.PreserveAspectFit } } Kirigami.ScrollablePage { id: _descriptionItem Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignLeft | Qt.AlignTop Kirigami.Theme.backgroundColor: "transparent" padding: 0 leftPadding: padding rightPadding: padding topPadding: padding bottomPadding: padding ColumnLayout { id: _columnInfo spacing: Maui.Style.space.medium Label { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft color: Kirigami.Theme.textColor - text: appName + text: Maui.App.name font.weight: Font.Bold font.bold: true font.pointSize: Maui.Style.fontSizes.huge elide: Text.ElideRight wrapMode: Text.NoWrap - } + } Label { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft color: Qt.lighter(Kirigami.Theme.textColor, 1.2) - text: appVersion + text: Maui.App.version font.weight: Font.Light font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } Label { id: body Layout.fillWidth: true - text: appDescription + text: Maui.App.description color: Kirigami.Theme.textColor font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } + Label + { + color: Kirigami.Theme.textColor + Layout.fillWidth: true + + text: qsTr("By ") + Maui.App.org + font.pointSize: Maui.Style.fontSizes.default + elide: Text.ElideRight + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + } + Kirigami.Separator { Layout.fillWidth: true - Layout.margins: Maui.Style.space.big + Layout.margins: Maui.Style.space.tiny opacity: 0.4 } Label { color: Kirigami.Theme.textColor Layout.fillWidth: true - text: qsTr("Built with MauiKit " + Maui.App.mauikitVersion + " and Kirigami." ) + text: qsTr("Powered by") + " MauiKit " + Maui.App.mauikitVersion + " and Kirigami." font.pointSize: Maui.Style.fontSizes.default elide: Text.ElideRight wrapMode: Text.WrapAtWordBoundaryOrAnywhere } } } } } diff --git a/src/controls/AbstractSideBar.qml b/src/controls/AbstractSideBar.qml index 6be5652..353e4e1 100644 --- a/src/controls/AbstractSideBar.qml +++ b/src/controls/AbstractSideBar.qml @@ -1,82 +1,109 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Drawer { id: control edge: Qt.LeftEdge implicitHeight: parent.height - ApplicationWindow.header.height - ApplicationWindow.footer.height height: implicitHeight y: ApplicationWindow.header.height - + closePolicy: modal ? Popup.CloseOnEscape | Popup.CloseOnPressOutside : Popup.NoAutoClose visible: true property bool collapsible: false property bool collapsed: false property int collapsedSize: Maui.Style.iconSizes.medium + (Maui.Style.space.medium*4) - Maui.Style.space.tiny property int preferredWidth : Kirigami.Units.gridUnit * 12 -// dragMargin: Maui.Style.space.huge -// dim: false + enter: Transition { SmoothedAnimation { velocity: modal ? 5 : 0 } } + exit: Transition { SmoothedAnimation { velocity: modal ? 5 : 0 } } + + signal contentDropped(var drop) + + Component.onCompleted: + { + if(!modal) + { + control.enter.enabled = false; + control.visible = true; + control.position = 1; + control.enter.enabled = true; + } + } + + Behavior on width + { + enabled: control.collapsible - Behavior on width + NumberAnimation { - NumberAnimation - { - duration: Kirigami.Units.longDuration - easing.type: Easing.InOutQuad - } + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad } + } + + opacity: _dropArea.containsDrag ? 0.5 : 1 + + DropArea + { + id: _dropArea + anchors.fill: parent + onDropped: + { + control.contentDropped(drop) + } + } + + EdgeShadow + { + z: -2 + visible: control.modal + parent: control.background + edge: control.edge + anchors + { + right: control.edge == Qt.RightEdge ? parent.left : (control.edge == Qt.LeftEdge ? undefined : parent.right) + left: control.edge == Qt.LeftEdge ? parent.right : (control.edge == Qt.RightEdge ? undefined : parent.left) + top: control.edge == Qt.TopEdge ? parent.bottom : (control.edge == Qt.BottomEdge ? undefined : parent.top) + bottom: control.edge == Qt.BottomEdge ? parent.top : (control.edge == Qt.TopEdge ? undefined : parent.bottom) + } + + opacity: control.position == 0 ? 0 : 1 - EdgeShadow + Behavior on opacity { - z: -2 - visible: control.modal - parent: control.background - edge: control.edge - anchors - { - right: control.edge == Qt.RightEdge ? parent.left : (control.edge == Qt.LeftEdge ? undefined : parent.right) - left: control.edge == Qt.LeftEdge ? parent.right : (control.edge == Qt.RightEdge ? undefined : parent.left) - top: control.edge == Qt.TopEdge ? parent.bottom : (control.edge == Qt.BottomEdge ? undefined : parent.top) - bottom: control.edge == Qt.BottomEdge ? parent.top : (control.edge == Qt.TopEdge ? undefined : parent.bottom) - } - - opacity: control.position == 0 ? 0 : 1 - - Behavior on opacity + NumberAnimation { - NumberAnimation - { - duration: Kirigami.Units.longDuration - easing.type: Easing.InOutQuad - } + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad } } - + } + } diff --git a/src/controls/ApplicationWindow.qml b/src/controls/ApplicationWindow.qml index 426fe5b..361624c 100644 --- a/src/controls/ApplicationWindow.qml +++ b/src/controls/ApplicationWindow.qml @@ -1,429 +1,422 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import QtQuick.Window 2.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtQuick.Controls.Material 2.1 import "private" Kirigami.AbstractApplicationWindow { id: root visible: true width: Screen.width * (Kirigami.Settings.isMobile ? 1 : 0.4) height: Screen.height * (Kirigami.Settings.isMobile ? 1 : 0.4) contentItem.anchors.leftMargin: root.sideBar && !root.globalDrawer ? ((root.sideBar.collapsible && root.sideBar.collapsed) ? root.sideBar.collapsedSize : (root.sideBar.modal ? 0 : root.sideBar.width)) : (!root.sideBar && root.globalDrawer && (root.globalDrawer.modal === false) ? root.globalDrawer.width * root.globalDrawer.position : 0) - property bool showAccounts : true - property Maui.AbstractSideBar sideBar + property Maui.AbstractSideBar sideBar /***************************************************/ /******************** ALIASES *********************/ /*************************************************/ property alias headBar : _headBar property alias footBar: _footBar property alias dialog: dialogLoader.item property alias leftIcon : menuBtn property alias rightIcon : searchBtn property alias mainMenu : mainMenu.contentData property alias about : aboutDialog property alias accounts: _accountsDialogLoader.item property var currentAccount: Maui.App.accounts.currentAccount property alias notifyDialog: _notify property alias searchButton : searchBtn property alias menuButton : menuBtn wideScreen: isWide /***************************************************/ /*********************** UI ***********************/ /*************************************************/ property bool isWide : root.width >= Kirigami.Units.gridUnit * 30 property string colorSchemeName : Qt.application.name /***************************************************/ /********************* COLORS *********************/ /*************************************************/ property color headBarBGColor: Kirigami.Theme.backgroundColor property color headBarFGColor: Kirigami.Theme.textColor /***************************************************/ /**************** READONLY PROPS ******************/ /*************************************************/ readonly property bool isMobile : Kirigami.Settings.isMobile readonly property bool isAndroid: Qt.platform.os == "android" readonly property real screenWidth : Screen.width readonly property real screenHeight : Screen.height /***************************************************/ /******************** SIGNALS *********************/ /*************************************************/ signal menuButtonClicked(); signal searchButtonClicked(); onClosing: { if(!isMobile) { const height = root.height const width = root.width const x = root.x const y = root.y Maui.FM.saveSettings("GEOMETRY", Qt.rect(x, y, width, height), "WINDOW") } } property bool isPortrait: Screen.primaryOrientation === Qt.PortraitOrientation || Screen.primaryOrientation === Qt.InvertedPortraitOrientation onIsPortraitChanged: { if(isPortrait) { console.log("PORTARIT MODE CHANGED") width: Screen.width height: Screen.height } } // onHeadBarBGColorChanged: // { // if(!isMobile && colorSchemeName.length > 0) // Maui.KDE.setColorScheme(colorSchemeName, headBarBGColor, headBarFGColor) // else if(isAndroid && headBar.position === ToolBar.Header) // Maui.Android.statusbarColor(headBarBGColor, false) // else if(isAndroid && headBar.position === ToolBar.Footer) // Maui.Android.statusbarColor(Kirigami.Theme.viewBackgroundColor, true) // // } // // onHeadBarFGColorChanged: // { // if(!isAndroid && !isMobile && colorSchemeName.length > 0 && headBar.position === ToolBar.Header) // Maui.KDE.setColorScheme(colorSchemeName, headBarBGColor, headBarFGColor) // else if(isAndroid && headBar.position === ToolBar.Header) // Maui.Android.statusbarColor(headBarBGColor, false) // else if(isAndroid && headBar.position === ToolBar.Footer) // Maui.Android.statusbarColor(Kirigami.Theme.viewBackgroundColor, true) // } /* * background: Rectangle * { * color: bgColor } */ property Maui.ToolBar mheadBar : Maui.ToolBar { id: _headBar visible: count > 1 position: ToolBar.Header width: root.width // Kirigami.Theme.backgroundColor: headBarBGColor // Kirigami.Theme.textColor: headBarFGColor // Kirigami.Theme.inherit: true leftContent: [ ToolButton { id: menuBtn icon.name: "application-menu" icon.color: headBarFGColor icon.width: Maui.Style.iconSizes.medium icon.height: Maui.Style.iconSizes.medium checked: mainMenu.visible onClicked: { menuButtonClicked() mainMenu.visible ? mainMenu.close() : mainMenu.popup(parent, parent.x , parent.height+ Maui.Style.space.medium) } Menu { id: mainMenu modal: true z: 999 width: Maui.Style.unit * 200 MenuItem { - visible: (_accountCombobox.count > 0) && root.showAccounts + visible: (_accountCombobox.count > 0) && Maui.App.handleAccounts height: visible ? _accountCombobox.implicitHeight + Maui.Style.space.big : 0 ComboBox { id: _accountCombobox anchors.fill: parent anchors.margins: Maui.Style.space.small popup.z: 999 width: parent.width textRole: "user" flat: true model: Maui.BaseModel { list: Maui.App.accounts } onActivated: Maui.App.accounts.currentAccountIndex = index; Component.onCompleted: { if(_accountCombobox.count > 0) { _accountCombobox.currentIndex = 0 Maui.App.accounts.currentAccountIndex = _accountCombobox.currentIndex } } } } MenuItem { text: qsTr("Accounts") - visible: root.showAccounts + visible: Maui.App.handleAccounts icon.name: "list-add-user" onTriggered: { if(root.accounts) accounts.open() } } MenuSeparator { visible: _accountCombobox.visible } MenuItem { text: qsTr("About") icon.name: "documentinfo" onTriggered: aboutDialog.open() } } } ] rightContent: ToolButton { id: searchBtn icon.name: "edit-find" icon.color: headBarFGColor onClicked: searchButtonClicked() } } property Maui.ToolBar mfootBar : Maui.ToolBar { id: _footBar visible: count position: ToolBar.Footer width: root.width } header: headBar.count && headBar.position === ToolBar.Header ? headBar : undefined footer: Column { id: _footer visible : children > 0 children: { if(headBar.position === ToolBar.Footer && headBar.count && footBar.count) return [footBar , headBar] else if(headBar.position === ToolBar.Footer && headBar.count) return [headBar] else if(footBar.count) return [footBar] else return [] } } Maui.AboutDialog { id: aboutDialog } Loader { id: _accountsDialogLoader - sourceComponent: root.showAccounts ? _accountsDialogComponent : undefined - } - - Component - { - id: _accountsDialogComponent - AccountsHelper {} + source: Maui.App.handleAccounts ? "private/AccountsHelper.qml" : undefined } Maui.Dialog { id: _notify property var cb : ({}) verticalAlignment: Qt.AlignTop defaultButtons: false maxHeight: Math.max( Maui.Style.iconSizes.large + Maui.Style.space.huge, (_notifyLayout.implicitHeight)) + Maui.Style.space.big maxWidth: Kirigami.Settings.isMobile ? parent.width * 0.9 : Maui.Style.unit * 500 widthHint: 0.8 Timer { id: _notifyTimer onTriggered: { if(!_mouseArea.pressed) _notify.close() } } onClosed: _notifyTimer.stop() MouseArea { id: _mouseArea anchors.fill: parent onClicked: { if(_notify.cb) { _notify.cb() _notify.close() } } } GridLayout { anchors.fill: parent columns: 2 rows: 1 Item { Layout.fillHeight: true Layout.preferredWidth: Maui.Style.iconSizes.large + Maui.Style.space.big Layout.row: 1 Layout.column: 1 Kirigami.Icon { id: _notifyIcon width: Maui.Style.iconSizes.large height: width anchors.centerIn: parent } } Item { Layout.fillHeight: true Layout.fillWidth: true Layout.margins: Maui.Style.space.medium Layout.row: 1 Layout.column: 2 ColumnLayout { id: _notifyLayout anchors.centerIn: parent width: parent.width Label { id: _notifyTitle Layout.fillHeight: true Layout.fillWidth: true font.weight: Font.Bold font.bold: true font.pointSize:Maui.Style.fontSizes.big elide: Qt.ElideRight wrapMode: Text.NoWrap } Label { id: _notifyBody Layout.fillHeight: true Layout.fillWidth: true font.pointSize:Maui.Style.fontSizes.default elide: Qt.ElideRight wrapMode: Text.Wrap } } } } function show(callback) { _notify.cb = callback _notifyTimer.start() _notify.open() } } Loader { id: dialogLoader } Component.onCompleted: { if(isAndroid && headBar.position === ToolBar.Footer) Maui.Android.statusbarColor(Kirigami.Theme.backgroundColor, true) if(!isMobile) { const rect = Maui.FM.loadSettings("GEOMETRY", "WINDOW", Qt.rect(root.x, root.y, root.width, root.height)) root.x = rect.x root.y = rect.y root.width = rect.width root.height = rect.height } } function notify(icon, title, body, callback, timeout) { _notifyIcon.source = icon _notifyTitle.text = title _notifyBody.text = body _notifyTimer.interval = timeout ? timeout : 2500 _notify.show(callback) } } diff --git a/src/controls/Badge.qml b/src/controls/Badge.qml index ef97673..0ae2b68 100644 --- a/src/controls/Badge.qml +++ b/src/controls/Badge.qml @@ -1,105 +1,110 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import "private" Rectangle { id: control Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Complementary property alias item : loader.item property bool hovered : false property int size: Maui.Style.iconSizes.small property string iconName : "" property string text : "" signal clicked() signal pressed() signal hovered() signal released() z: parent.z+1 height: size + Maui.Style.space.small width: Math.max(implicitWidth, height) implicitWidth: (loader.sourceComponent == labelComponent ? Math.max(loader.item.implicitWidth + Maui.Style.space.small, control.height) : control.height) radius: Math.min(width, height) color: control.Kirigami.Theme.backgroundColor border.color: Qt.tint(control.Kirigami.Theme.textColor, Qt.rgba(control.Kirigami.Theme.backgroundColor.r, control.Kirigami.Theme.backgroundColor.g, control.Kirigami.Theme.backgroundColor.b, 0.7)) clip: false Loader { id: loader anchors.fill: parent sourceComponent: control.text.length && !control.iconName.length ? labelComponent : (!control.text.length && control.iconName.length ? iconComponent : undefined) } Component { id: labelComponent Label { height: parent.height width: parent.width text: control.text font.weight: Font.Bold font.bold: true font.pointSize: Maui.Style.fontSizes.default color: Kirigami.Theme.textColor verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignHCenter } } Component { id: iconComponent Kirigami.Icon { anchors.centerIn: parent source: control.iconName color: Kirigami.Theme.textColor width: control.size height: width } } MouseArea { id: mouseArea - anchors.fill: parent + readonly property int targetMargin: Kirigami.Settings.isMobile ? Maui.Style.space.big : 0 + + height: parent.height + targetMargin + width: parent.width + targetMargin + + anchors.centerIn: parent onClicked: control.clicked() onPressed: control.pressed() onReleased: control.released() hoverEnabled: true onEntered: hovered = true onExited: hovered = false } } diff --git a/src/controls/Dialog.qml b/src/controls/Dialog.qml index 4fa5756..8154d95 100644 --- a/src/controls/Dialog.qml +++ b/src/controls/Dialog.qml @@ -1,187 +1,183 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.0 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami Maui.Popup { id: control property string message : "" property string title: "" property string acceptText: "Yes" property string rejectText: "No" property bool defaultButtons: true property bool confirmationDialog: false property bool entryField: false default property alias content : page.contentData property alias acceptButton : _acceptButton property alias rejectButton : _rejectButton property alias textEntry : _textEntry property alias page : page property alias footBar : page.footBar property alias headBar: page.headBar property alias closeButton: _closeButton signal accepted() signal rejected() clip: false maxWidth: Maui.Style.unit * 300 maxHeight: (_pageContent.implicitHeight * 1.2) + page.footBar.height + Maui.Style.space.huge + page.padding widthHint: 0.9 heightHint: 0.9 Maui.Badge { id: _closeButton iconName: "window-close" Kirigami.Theme.backgroundColor: hovered ? Kirigami.Theme.negativeTextColor : Kirigami.Theme.complementaryBackgroundColor Kirigami.Theme.textColor: Kirigami.Theme.highlightedTextColor anchors { verticalCenter: parent.top horizontalCenter: parent.left horizontalCenterOffset: control.width === control.parent.width ? _closeButton.width : 0 } z: control.z+999 onClicked: close() } Maui.Page { id: page anchors.fill: parent anchors.margins: Maui.Style.unit padding: Maui.Style.space.medium footBar.visible: control.defaultButtons || footBar.count > 1 -// footBar.background: null - -// Kirigami.Theme.backgroundColor: "transparent" - property QtObject _rejectButton : Button { id: _rejectButton visible: defaultButtons Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.negativeTextColor.r, Kirigami.Theme.negativeTextColor.g, Kirigami.Theme.negativeTextColor.b, 0.2) text: rejectText onClicked: rejected() - } property QtObject _acceptButton: Button { id: _acceptButton visible: defaultButtons Kirigami.Theme.backgroundColor: Qt.rgba(Kirigami.Theme.positiveTextColor.r, Kirigami.Theme.positiveTextColor.g, Kirigami.Theme.positiveTextColor.b, 0.2) Kirigami.Theme.textColor: Kirigami.Theme.positiveTextColor text: acceptText onClicked: accepted() } Component { id: _defaultButtonsComponent Row { spacing: Maui.Style.space.big children: [_rejectButton, _acceptButton] } } footBar.rightContent: Loader { sourceComponent: control.defaultButtons ? _defaultButtonsComponent : undefined } ColumnLayout { id: _pageContent anchors.fill: parent spacing: Maui.Style.space.medium Label { width: parent.width height: visible ? implicitHeight : 0 visible: title.length > 0 Layout.fillWidth: visible Layout.alignment: Qt.AlignLeft | Qt.AlignTop color: Kirigami.Theme.textColor text: title font.weight: Font.Thin font.bold: true font.pointSize:Maui.Style.fontSizes.huge elide: Qt.ElideRight wrapMode: Text.Wrap } Kirigami.ScrollablePage { visible: message.length > 0 Layout.fillHeight: visible Layout.fillWidth: visible Kirigami.Theme.backgroundColor: "transparent" padding: 0 leftPadding: padding rightPadding: padding topPadding: padding bottomPadding: padding Layout.alignment: Qt.AlignLeft | Qt.AlignTop Label { id: body padding: 0 text: message textFormat : TextEdit.AutoText color: Kirigami.Theme.textColor font.pointSize:Maui.Style.fontSizes.default wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere elide: Text.ElideLeft } } Maui.TextField { id: _textEntry + focus: control.entryField onAccepted: control.accepted() Layout.fillWidth: entryField height: entryField ? Maui.Style.iconSizes.big : 0 visible: entryField } } } } diff --git a/src/controls/FileBrowser.qml b/src/controls/FileBrowser.qml index 3dafa1b..21191d8 100644 --- a/src/controls/FileBrowser.qml +++ b/src/controls/FileBrowser.qml @@ -1,1120 +1,1039 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import QtQml.Models 2.3 import QtQml 2.1 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Maui.Page { id: control property url currentPath onCurrentPathChanged: control.browserView.path = control.currentPath property int viewType : Maui.FMList.LIST_VIEW onViewTypeChanged: browserView.viewType = control.viewType property int currentPathType : control.currentFMList.pathType property int thumbnailsSize : Maui.Style.iconSizes.large * 1.7 property bool showThumbnails: true property var clipboardItems : [] property var indexHistory : [] property bool isCopy : false property bool isCut : false property bool selectionMode : false property bool singleSelection: false property bool group : false property bool showEmblems: true //group properties from the browser since the browser views are loaded async and //their properties can not be accesed inmediately property BrowserSettings settings : BrowserSettings {} property alias selectionBar : selectionBarLoader.item property alias browserView : _browserList.currentItem property Maui.FMList currentFMList : browserView.currentFMList property alias previewer : previewer property alias menu : browserMenu.contentData property alias itemMenu: itemMenu property alias dialog : dialogLoader.item signal itemClicked(int index) signal itemDoubleClicked(int index) signal itemRightClicked(int index) signal itemLeftEmblemClicked(int index) signal itemRightEmblemClicked(int index) signal rightClicked() signal newBookmark(var paths) signal newTag(var tag) Kirigami.Theme.colorSet: Kirigami.Theme.View Kirigami.Theme.inherit: false onGoBackTriggered: control.goBack() onGoForwardTriggered: control.goNext() focus: true - footBar.visible: false footBar.leftContent: Label { - Layout.fillWidth: true - text: qsTr("%n item(s)", "0", control.currentFMList.count) + Layout.fillWidth: true + text: qsTr("%n item(s)", "0", control.currentFMList.count) } footBar.rightContent: [ ToolButton { icon.name: "zoom-in" onClicked: zoomIn() }, ToolButton { icon.name: "zoom-out" onClicked: zoomOut() } ] - headBar.visible: currentPathType !== Maui.FMList.APPS_PATH headBar.position: Kirigami.Settings.isMobile ? ToolBar.Footer : ToolBar.Header property list t_actions: [ Action { id: _previewAction icon.name: "image-preview" text: qsTr("Show Previews") checkable: true checked: control.showThumbnails onTriggered: control.showThumbnails = !control.showThumbnails }, Action { id: _hiddenAction icon.name: "visibility" text: qsTr("Show Hidden Files") checkable: true checked: control.currentFMList.hidden onTriggered: control.currentFMList.hidden = !control.currentFMList.hidden }, Action { id: _bookmarkAction icon.name: "bookmark-new" text: qsTr("Bookmark Current Path") onTriggered: control.bookmarkFolder([currentPath]) }, Action { id: _newFolderAction icon.name: "folder-add" text: qsTr("New Folder...") onTriggered: { dialogLoader.sourceComponent= newFolderDialogComponent dialog.open() } }, Action { id: _newDocumentAction icon.name: "document-new" text: qsTr("New file...") onTriggered: { dialogLoader.sourceComponent= newFileDialogComponent dialog.open() } }, Action { id: _pasteAction text: qsTr("Paste %n File(s)", "0", browserMenu.pasteFiles) icon.name: "edit-paste" enabled: control.clipboardItems.length > 0 onTriggered: paste() }, Action { id: _selectAllAction text: qsTr("Select All") icon.name: "edit-select-all" onTriggered: selectAll() }, Action { text: qsTr("Show Status Bar") icon.name: "settings-configure" checkable: true checked: control.footBar.visible onTriggered: control.footBar.visible = !control.footBar.visible } ] Loader { id: dialogLoader } Component { id: removeDialogComponent Maui.Dialog { property var items: [] title: qsTr("Removing %n file(s)", "0", items.length) message: isAndroid ? qsTr("This action will remove your files from your system permanently. This action can not be undone.") : qsTr("You can move the file to the trash or delete it completely from your system. Which one do you prefer?") rejectButton.text: qsTr("Delete Files") acceptButton.text: qsTr("Send to Trash") acceptButton.visible: !Kirigami.Settings.isMobile page.padding: Maui.Style.space.huge onRejected: { if(control.selectionBar && control.selectionBar.visible) { control.selectionBar.clear() control.selectionBar.animate(Maui.Style.dangerColor) } control.remove(items) close() } onAccepted: { if(control.selectionBar && control.selectionBar.visible) { control.selectionBar.clear() control.selectionBar.animate(Maui.Style.dangerColor) } control.trash(items) close() } } } Component { id: newFolderDialogComponent Maui.NewDialog { title: qsTr("New Folder...") message: qsTr("Create a new folder") acceptButton.text: qsTr("Create") onFinished: control.currentFMList.createDir(text) rejectButton.visible: false textEntry.placeholderText: qsTr("Folder name...") } } Component { id: newFileDialogComponent Maui.NewDialog { title: qsTr("New File...") message: qsTr("Create a new file") acceptButton.text: qsTr("Create") onFinished: Maui.FM.createFile(control.currentPath, text) rejectButton.visible: false textEntry.placeholderText: qsTr("File name...") } } Component { id: renameDialogComponent Maui.NewDialog { title: qsTr("Rename File...") message: qsTr("Rename a file or folder") textEntry.text: itemMenu.item.label textEntry.placeholderText: qsTr("New name...") onFinished: Maui.FM.rename(itemMenu.item.path, textEntry.text) onRejected: close() acceptText: qsTr("Rename") rejectText: qsTr("Cancel") } } Component { id: shareDialogComponent Maui.ShareDialog {} } Component { id: tagsDialogComponent Maui.TagsDialog { onTagsReady: { composerList.updateToUrls(tags) if(previewer.visible) previewer.tagBar.list.refresh() control.newTag(tags) } } } BrowserMenu { id: browserMenu } Maui.FilePreviewer { id: previewer onShareButtonClicked: control.shareFiles([url]) } FileMenu { id: itemMenu width: Maui.Style.unit *200 onBookmarkClicked: control.bookmarkFolder([item.path]) onCopyClicked: { if(item) control.copy([item]) } onCutClicked: { if(item) control.cut([item]) } onTagsClicked: { if(item) { dialogLoader.sourceComponent = tagsDialogComponent dialog.composerList.urls = [item.path] dialog.open() } } onRenameClicked: { dialogLoader.sourceComponent = renameDialogComponent dialog.open() } onRemoveClicked: { dialogLoader.sourceComponent= removeDialogComponent dialog.items = [item] dialog.open() } onShareClicked: control.shareFiles([item.path]) } Connections { target: browserView.currentView + onKeyPress: + { + if(key == Qt.Key_S) + { + const item = control.currentFMList.get(browserView.currentView.currentIndex) + + if(control.selectionBar && control.selectionBar.contains(item.path)) + { + control.selectionBar.removeAtPath(item.path) + }else + { + control.addToSelection(item) + } + } + } + onItemClicked: { console.log("item clicked connections:", index) browserView.currentView.currentIndex = index indexHistory.push(index) control.itemClicked(index) } onItemDoubleClicked: { browserView.currentView.currentIndex = index indexHistory.push(index) control.itemDoubleClicked(index) } onItemRightClicked: { if(currentFMList.pathType !== Maui.FMList.TRASH_PATH && currentFMList.pathType !== Maui.FMList.REMOTE_PATH ) itemMenu.show(index) control.itemRightClicked(index) } onLeftEmblemClicked: { const item = control.currentFMList.get(index) if(control.selectionBar && control.selectionBar.contains(item.path)) { control.selectionBar.removeAtPath(item.path) }else { control.addToSelection(item) } control.itemLeftEmblemClicked(index) } onRightEmblemClicked: { isAndroid ? Maui.Android.shareDialog([control.currentFMList.get(index).path]) : shareDialog.show([control.currentFMList.get(index).path]) control.itemRightEmblemClicked(index) } onAreaClicked: { if(!Kirigami.Settings.isMobile && mouse.button === Qt.RightButton) browserMenu.show() else return control.rightClicked() } onAreaRightClicked: browserMenu.show() } headBar.rightContent:[ Kirigami.ActionToolBar { position: ToolBar.Header Layout.fillWidth: true hiddenActions: t_actions display: ToolButton.IconOnly actions: [ Action { icon.name: "view-list-icons" onTriggered: control.viewType = Maui.FMList.ICON_VIEW checkable: false checked: browserView.viewType === Maui.FMList.ICON_VIEW icon.width: Maui.Style.iconSizes.medium text: qsTr("Grid View") // autoExclusive: true }, Action { icon.name: "view-list-details" onTriggered: control.viewType = Maui.FMList.LIST_VIEW icon.width: Maui.Style.iconSizes.medium checked: browserView.viewType === Maui.FMList.LIST_VIEW text: qsTr("List View") // autoExclusive: true }, Action { icon.name: "view-file-columns" onTriggered: control.viewType = Maui.FMList.MILLERS_VIEW icon.width: Maui.Style.iconSizes.medium checked: browserView.viewType === Maui.FMList.MILLERS_VIEW text: qsTr("Column View") // autoExclusive: true }, Kirigami.Action { icon.name: "view-sort" text: qsTr("Sort By") Kirigami.Action { text: qsTr("Show Folders First") checked: control.currentFMList.foldersFirst checkable: true onTriggered: control.currentFMList.foldersFirst = !control.currentFMList.foldersFirst } Kirigami.Action { text: qsTr("Type") checked: control.currentFMList.sortBy === Maui.FMList.MIME checkable: true onTriggered: control.currentFMList.sortBy = Maui.FMList.MIME } Kirigami.Action { text: qsTr("Date") checked: control.currentFMList.sortBy === Maui.FMList.DATE checkable: true onTriggered: control.currentFMList.sortBy = Maui.FMList.DATE } Kirigami.Action { text: qsTr("Last Modified") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.MODIFIED onTriggered: control.currentFMList.sortBy = Maui.FMList.MODIFIED } Kirigami.Action { text: qsTr("Size") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.SIZE onTriggered: control.currentFMList.sortBy = Maui.FMList.SIZE } Kirigami.Action { text: qsTr("Name") checkable: true checked: control.currentFMList.sortBy === Maui.FMList.LABEL onTriggered: control.currentFMList.sortBy = Maui.FMList.LABEL } Kirigami.Action { id: groupAction text: qsTr("Group") checkable: true checked: control.group onTriggered: { control.group = !control.group if(control.group) groupBy() else browserView.currentView.section.property = "" } } }, Kirigami.Action { text: qsTr("Selection Mode") icon.name: "item-select" checkable: true checked: control.selectionMode onTriggered: control.selectionMode = !control.selectionMode } ] } ] headBar.leftContent: [ ToolButton { icon.name: "go-previous" onClicked: control.goBack() }, -// ToolButton -// { -// id: goUpButton -// visible: true -// icon.name: "go-up" -// onClicked: control.goUp() -// }, - ToolButton { icon.name: "go-next" onClicked: control.goNext() } ] Component { id: selectionBarComponent Maui.SelectionBar { anchors.fill: parent onIconClicked: _selectionBarmenu.popup() - onExitClicked: clean() - onItemClicked: removeAtIndex(index) + onExitClicked: + { + clean() + control.selectionMode = false + } + + onRightClicked: _selectionBarmenu.popup() + + onItemClicked: + { + previewer.show(itemAt(index).path) + } + + onItemPressAndHold: + { + removeAtIndex(index) + } Menu { id: _selectionBarmenu MenuItem { text: qsTr("Copy") onTriggered: if(control.selectionBar) { control.selectionBar.animate("#6fff80") control.copy(selectedItems) _selectionBarmenu.close() } } MenuItem { text: qsTr("Cut") onTriggered: if(control.selectionBar) { control.selectionBar.animate("#fff44f") control.cut(selectedItems) _selectionBarmenu.close() } } MenuItem { text: qsTr("Share...") onTriggered: { control.shareFiles(selectedPaths) _selectionBarmenu.close() } } MenuItem { text: qsTr("Tags...") onTriggered: if(control.selectionBar) { dialogLoader.sourceComponent = tagsDialogComponent dialog.composerList.urls = selectedPaths dialog.open() _selectionBarmenu.close() } } MenuSeparator{} MenuItem { text: qsTr("Remove") Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor onTriggered: { dialogLoader.sourceComponent= removeDialogComponent dialog.items = selectedItems dialog.open() _selectionBarmenu.close() } } } } } ObjectModel { id: tabsObjectModel } ColumnLayout { anchors.fill: parent spacing: 0 - TabBar - { - id: tabsBar - visible: _browserList.count > 1 - Layout.fillWidth: true - Layout.preferredHeight: visible ? Maui.Style.rowHeight : 0 - Kirigami.Theme.colorSet: Kirigami.Theme.View - Kirigami.Theme.inherit: false - - currentIndex : _browserList.currentIndex - clip: true - - ListModel { id: tabsListModel } - - background: null - - Repeater - { - id: _repeater - model: tabsListModel - - TabButton - { - id: _tabButton - readonly property int minTabWidth: 150 * Maui.Style.unit - implicitWidth: control.width / _repeater.count - implicitHeight: Maui.Style.rowHeight + Maui.TabBar + { + id: tabsBar + visible: _browserList.count > 1 + Layout.fillWidth: true + Layout.preferredHeight: tabsBar.implicitHeight + position: TabBar.Header + currentIndex : _browserList.currentIndex + + ListModel { id: tabsListModel } + + Repeater + { + id: _repeater + model: tabsListModel + + Maui.TabButton + { + id: _tabButton + implicitHeight: tabsBar.implicitHeight + implicitWidth: control.width / _repeater.count checked: index === _browserList.currentIndex + text: tabsObjectModel.get(index).currentFMList.pathName + onClicked: { _browserList.currentIndex = index - control.currentPath = tabsObjectModel.get(index).path } - background: Rectangle - { - color: "transparent" - - - Kirigami.Separator - { - z: tabsBar.z + 1 - width: Maui.Style.unit - anchors - { - bottom: parent.bottom - top: parent.top - right: parent.right - } - } - - Kirigami.Separator - { - color: Kirigami.Theme.highlightColor - z: tabsBar.z + 1 - height: Maui.Style.unit * 2 - visible: checked - anchors - { - bottom: parent.bottom - left: parent.left - right: parent.right - } - } - } - - contentItem: RowLayout - { - spacing: 0 - - Label - { - text: tabsObjectModel.get(index).currentFMList.pathName - font.pointSize: Maui.Style.fontSizes.default - Layout.fillWidth: true - Layout.fillHeight: true - Layout.margins: Maui.Style.space.small - Layout.alignment: Qt.AlignCenter - verticalAlignment: Qt.AlignVCenter - horizontalAlignment: Qt.AlignHCenter - color: checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor - wrapMode: Text.NoWrap - elide: Text.ElideRight - } - - ToolButton - { - Layout.preferredHeight: Maui.Style.iconSizes.medium - Layout.preferredWidth: Maui.Style.iconSizes.medium - icon.height: Maui.Style.iconSizes.medium - icon.width: Maui.Style.iconSizes.width - Layout.margins: Maui.Style.space.medium - Layout.alignment: Qt.AlignRight - - icon.name: "dialog-close" - - onClicked: - { - const removedIndex = index - tabsObjectModel.remove(removedIndex) - tabsListModel.remove(removedIndex) - } - } - } + onCloseClicked: + { + const removedIndex = index + tabsObjectModel.remove(removedIndex) + tabsListModel.remove(removedIndex) + } } } } - - Kirigami.Separator - { - visible: tabsBar.visible - color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) - Layout.fillWidth: true - Layout.preferredHeight: 1 - } - ListView { id: _browserList Layout.margins: 0 Layout.fillWidth: true Layout.fillHeight: true clip: true - focus: true -// Keys.onSpacePressed: previewer.show(control.currentFMList.get(browser.currentIndex).path) - orientation: ListView.Horizontal model: tabsObjectModel snapMode: ListView.SnapOneItem spacing: 0 interactive: Kirigami.Settings.isMobile && tabsObjectModel.count > 1 highlightFollowsCurrentItem: true highlightMoveDuration: 0 onMovementEnded: _browserList.currentIndex = indexAt(contentX, contentY) + +// DropArea +// { +// id: _dropArea +// anchors.fill: parent +// z: parent.z -2 +// onDropped: +// { +// const urls = drop.urls +// for(var i in urls) +// { +// const item = Maui.FM.getFileInfo(urls[i]) +// if(item.isdir == "true") +// { +// control.openTab(urls[i]) +// } +// } +// } +// } } Loader { id: selectionBarLoader Layout.fillWidth: true Layout.preferredHeight: control.selectionBar && control.selectionBar.visible ? control.selectionBar.barHeight: 0 Layout.leftMargin: Maui.Style.contentMargins * (Kirigami.Settings.isMobile ? 3 : 2) Layout.rightMargin: Maui.Style.contentMargins * (Kirigami.Settings.isMobile ? 3 : 2) Layout.bottomMargin: control.selectionBar && control.selectionBar.visible ? Maui.Style.contentMargins*2 : 0 } ProgressBar { id: _progressBar Layout.fillWidth: true Layout.alignment: Qt.AlignBottom Layout.preferredHeight: visible ? Maui.Style.iconSizes.medium : 0 visible: value > 0 } } Component.onCompleted: { openTab(Maui.FM.homePath()) // browserView.viewType = control.viewType control.setSettings() + _browserList.forceActiveFocus() } onThumbnailsSizeChanged: { if(settings.trackChanges && settings.saveDirProps) Maui.FM.setDirConf(currentPath+"/.directory", "MAUIFM", "IconSize", thumbnailsSize) else Maui.FM.saveSettings("IconSize", thumbnailsSize, "SETTINGS") if(control.viewType === Maui.FMList.ICON_VIEW) browserView.currentView.adaptGrid() } function setSettings() { if(control.currentFMList !== null) { control.currentFMList.onlyDirs= control.settings.onlyDirs control.currentFMList.filters= control.settings.filters control.currentFMList.sortBy= control.settings.sortBy control.currentFMList.filterType= control.settings.filterType control.currentFMList.trackChanges= control.settings.trackChanges control.currentFMList.saveDirProps= control.settings.saveDirProps } } function openTab(path) { const component = Qt.createComponent("private/BrowserView.qml"); if (component.status === Component.Ready) { const object = component.createObject(tabsObjectModel); tabsObjectModel.append(object); } - tabsListModel.append({ - title: qsTr("Untitled"), - path: path, - }) - + tabsListModel.append({title: qsTr("Untitled"), path: path}) _browserList.currentIndex = tabsObjectModel.count - 1 if(path) { setTabMetadata(path) - browserView.viewType = control.viewType + browserView.viewType = control.viewType openFolder(path) } } function setTabMetadata(filepath) { tabsListModel.setProperty(tabsBar.currentIndex, "path", filepath) } - function shareFiles(urls) { if(urls.length <= 0) return; if(isAndroid) { Maui.Android.shareDialog(urls[0]) } else { dialogLoader.sourceComponent= shareDialogComponent dialog.show(urls) } } function openItem(index) { const item = control.currentFMList.get(index) const path = item.path switch(currentPathType) - { - case Maui.FMList.APPS_PATH: - if(item.path.endsWith("/")) - { - populate(path) - } - else - { - Maui.FM.runApplication(path) - } - break + { case Maui.FMList.CLOUD_PATH: if(item.mime === "inode/directory") { control.openFolder(path) } else { Maui.FM.openCloudItem(item) } break; default: - if(selectionMode && !Maui.FM.isDir(item.path)) + if(selectionMode && item.mime !== "inode/directory") { if(control.selectionBar && control.selectionBar.contains(item.path)) { control.selectionBar.removeAtPath(item.path) }else { control.addToSelection(item) } } else { if(item.mime === "inode/directory") { control.openFolder(path) } - else if(Maui.FM.isApp(path)) - { - control.launchApp(path) - } else { if (Kirigami.Settings.isMobile) { previewer.show(path) } else { control.openFile(path) } } } } } - - function launchApp(path) - { - Maui.FM.runApplication(path, "") - } - function openFile(path) { Maui.FM.openUrl(path) } function openFolder(path) { - populate(Maui.FM.fileDir(path))// make sure the path is a dir // file to dir + populate(path) } function setPath(path) { control.currentPath = path + console.log("SETTING PATH") } function populate(path) { - if(!path.length) + if(!String(path).length) return; browserView.currentView.currentIndex = -1 setPath(path) - - // if(currentPathType === Maui.FMList.PLACES_PATH) - // { - // if(trackChanges && saveDirProps) - // { - // var conf = Maui.FM.dirConf(path+"/.directory") - // var iconsize = conf["iconsize"] || Maui.Style.iconSizes.large - // thumbnailsSize = parseInt(iconsize) - // }else - // { - // thumbnailsSize = parseInt(Maui.FM.loadSettings("IconSize", "SETTINGS", thumbnailsSize)) - // } - // } - // - // if(browserView.viewType == Maui.FMList.ICON_VIEW) - // browser.adaptGrid() } function goBack() { - populate(control.currentFMList.previousPath) + openFolder(control.currentFMList.previousPath) browserView.currentView.currentIndex = indexHistory.pop() } function goNext() { openFolder(control.currentFMList.posteriorPath) } function goUp() { openFolder(control.currentFMList.parentPath) } function refresh() { const pos = browserView.currentView.contentY browserView.currentView.contentY = pos } function addToSelection(item) { if(!control.selectionBar) selectionBarLoader.sourceComponent = selectionBarComponent control.selectionBar.singleSelection = control.singleSelection control.selectionBar.append(item) } function clean() { control.clipboardItems = [] - browserMenu.pasteFiles = 0 if(control.selectionBar && control.selectionBar.visible) selectionBar.clear() } function copy(items) { control.clipboardItems = items control.isCut = false control.isCopy = true } function cut(items) { control.clipboardItems = items control.isCut = true control.isCopy = false } function paste() { if(control.isCopy) - { control.currentFMList.copyInto(control.clipboardItems) + { + control.currentFMList.copyInto(control.clipboardItems) } else if(control.isCut) { control.currentFMList.cutInto(control.clipboardItems) control.clean() } } function remove(items) { for(var i in items) Maui.FM.removeFile(items[i].path) } function selectAll() //TODO for now dont select more than 100 items so things dont freeze or break { for(var i = 0; i < Math.min(control.currentFMList.count, 100); i++) addToSelection(control.currentFMList.get(i)) } function trash(items) { for(var i in items) Maui.FM.moveToTrash(items[i].path) } function bookmarkFolder(paths) //multiple paths { control.newBookmark(paths) } function zoomIn() { control.thumbnailsSize = control.thumbnailsSize + 8 } function zoomOut() { const newSize = control.thumbnailsSize - 8 if(newSize >= Maui.Style.iconSizes.small) control.thumbnailsSize = newSize } function groupBy() { var prop = "" var criteria = ViewSection.FullString switch(control.currentFMList.sortBy) { case Maui.FMList.LABEL: prop = "label" criteria = ViewSection.FirstCharacter break; case Maui.FMList.MIME: prop = "mime" break; case Maui.FMList.SIZE: prop = "size" break; case Maui.FMList.DATE: prop = "date" break; case Maui.FMList.MODIFIED: prop = "modified" break; - } - - control.browserView.viewType = Maui.FMList.LIST_VIEW + } if(!prop) { control.browserView.currentView.section.property = "" return } + control.browserView.viewType = Maui.FMList.LIST_VIEW control.browserView.currentView.section.property = prop control.browserView.currentView.section.criteria = criteria } } diff --git a/src/controls/FilePreviewer.qml b/src/controls/FilePreviewer.qml index 470f7ed..18a58f0 100644 --- a/src/controls/FilePreviewer.qml +++ b/src/controls/FilePreviewer.qml @@ -1,289 +1,306 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Maui.Dialog { id: control property url currentUrl: "" property var iteminfo : ({}) property bool isFav : false property bool isDir : false property string mimetype : "" property bool showInfo: true property alias infoModel : _infoModel property alias tagBar : _tagsBar signal shareButtonClicked(url url) maxHeight: Maui.Style.unit * 800 maxWidth: Maui.Style.unit * 500 defaultButtons: false page.padding: 0 footBar.leftContent: ToolButton { icon.name: "document-open" text: qsTr("Open...") onClicked: { openFile(control.currentUrl) control.close() } } footBar.middleContent: [ ToolButton { visible: !isDir icon.name: "document-share" text: qsTr("Share...") onClicked: { shareButtonClicked(currentUrl) close() } }, ToolButton { icon.name: "love" text: control.isFav ? qsTr("Remove from Favorites") : qsTr("Add to Favorites") checkable: true checked: control.isFav onClicked: { if(control.isFav) _tagsBar.list.removeFromUrls("fav") else _tagsBar.list.insertToUrls("fav") control.isFav = !control.isFav } } ] footBar.rightContent: ToolButton { icon.name: "documentinfo" text: qsTr("Info...") checkable: true checked: control.showInfo onClicked: control.showInfo = !control.showInfo } + Component + { + id: defaultPreview + Item + { + anchors.fill: parent + Kirigami.Icon + { + anchors.centerIn: parent + source:control.iteminfo.icon + height: Maui.Style.iconSizes.huge + width: height + } + } + } + Component { id: imagePreview ImagePreview {} } Component { id: audioPreview AudioPreview {} } Component { id: videoPreview VideoPreview {} } Component { id: textPreview TextPreview {} } ColumnLayout { anchors.fill: parent spacing: 0 Label { Layout.fillWidth: true Layout.margins: Maui.Style.space.big horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter elide: Qt.ElideMiddle wrapMode: Text.Wrap font.pointSize: Maui.Style.fontSizes.big font.weight: Font.Bold font.bold: true text: iteminfo.name color: Kirigami.Theme.textColor } Loader { id: previewLoader visible: !control.showInfo Layout.fillWidth: true Layout.fillHeight: true } Kirigami.ScrollablePage { id: _infoContent visible: control.showInfo Layout.fillWidth: true Layout.fillHeight: true Layout.margins: Maui.Style.space.big Kirigami.Theme.backgroundColor: "transparent" padding: 0 leftPadding: padding rightPadding: padding topPadding: padding bottomPadding: padding ColumnLayout { width: parent.width spacing: Maui.Style.space.large Repeater { model: ListModel { id: _infoModel } Column { spacing: Maui.Style.space.small width: parent.width Label { width: parent.width visible: _valueLabel.visible text: model.key color: Kirigami.Theme.textColor elide: Text.ElideRight wrapMode: Text.NoWrap horizontalAlignment: Qt.AlignLeft font.weight: Font.Bold font.bold: true } Label { id: _valueLabel width: parent.width visible: text.length text: model.value color: Kirigami.Theme.textColor elide: Qt.ElideMiddle wrapMode: Text.Wrap horizontalAlignment: Qt.AlignLeft font.weight: Font.Light } } } } } Maui.TagsBar { id: _tagsBar + position: ToolBar.Footer Layout.fillWidth: true Layout.margins: 0 list.urls: [control.currentUrl] allowEditMode: true onTagRemovedClicked: list.removeFromUrls(index) onTagsEdited: list.updateToUrls(tags) Kirigami.Theme.textColor: control.Kirigami.Theme.textColor Kirigami.Theme.backgroundColor: control.Kirigami.Theme.backgroundColor onAddClicked: { dialogLoader.sourceComponent = tagsDialogComponent dialog.composerList.urls = [control.currentUrl] dialog.open() } } } onClosed: { if(previewLoader.item && previewLoader.item.player != null) previewLoader.item.player.stop() previewLoader.sourceComponent = null } function show(path) { control.iteminfo = Maui.FM.getFileInfo(path) control.initModel() if(iteminfo.mime.indexOf("/")) { control.mimetype = iteminfo.mime.slice(0, iteminfo.mime.indexOf("/")) }else { control.mimetype = "" } control.isDir = mimetype === "inode" control.showInfo = control.mimetype === "audio" || control.mimetype === "image" || control.mimetype === "video" || control.mimetype === "text"? false : true control.currentUrl = path control.isFav = _tagsBar.list.contains("fav") var component; switch(mimetype) { case "audio" : component = audioPreview break case "video" : component = videoPreview break case "text" : component = textPreview break case "image" : component = imagePreview break case "inode" : default: - component = undefined + component = defaultPreview } previewLoader.sourceComponent = component open() } function initModel() { control.infoModel.clear() control.infoModel.append({key: "Type", value: iteminfo.mime}) control.infoModel.append({key: "Date", value: iteminfo.date}) control.infoModel.append({key: "Modified", value: iteminfo.modified}) control.infoModel.append({key: "Last Read", value: iteminfo.lastread}) control.infoModel.append({key: "Owner", value: iteminfo.owner}) control.infoModel.append({key: "Group", value: iteminfo.group}) control.infoModel.append({key: "Size", value: Maui.FM.formatSize(iteminfo.size)}) control.infoModel.append({key: "Symbolic Link", value: iteminfo.symlink}) control.infoModel.append({key: "Path", value: iteminfo.path}) control.infoModel.append({key: "Icon Name", value: iteminfo.icon}) } } diff --git a/src/controls/GridBrowser.qml b/src/controls/GridBrowser.qml index 7b7610e..b5c4f3f 100644 --- a/src/controls/GridBrowser.qml +++ b/src/controls/GridBrowser.qml @@ -1,104 +1,109 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ -import QtQuick 2.0 -import QtQuick.Controls 2.2 +import QtQuick 2.9 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami Maui.GridView { id: control itemSize : Maui.Style.iconSizes.large * 2 property bool showEmblem : true property bool keepEmblemOverlay : false property string rightEmblem property string leftEmblem centerContent: false adaptContent: true property bool showPreviewThumbnails: true signal itemClicked(int index) - signal itemDoubleClicked(int index) - + signal itemDoubleClicked(int index) signal rightEmblemClicked(int index) - signal leftEmblemClicked(int index) - + signal leftEmblemClicked(int index) signal itemRightClicked(int index) + onKeyPress: + { + console.log(Qt.Key_S, Qt.Key_P) + if(key == Qt.Key_Return) + control.itemClicked(currentIndex) + } + delegate: Maui.GridBrowserDelegate { id: delegate folderSize: height * 0.5 height: control.cellHeight width: control.cellWidth padding: Maui.Style.space.small showTooltip: true showEmblem: control.showEmblem keepEmblemOverlay: control.keepEmblemOverlay showThumbnails: control.showPreviewThumbnails rightEmblem: control.rightEmblem leftEmblem: control.leftEmblem Connections { target: delegate onClicked: { control.currentIndex = index itemClicked(index) } onDoubleClicked: { control.currentIndex = index itemDoubleClicked(index) } onPressAndHold: { control.currentIndex = index control.itemRightClicked(index) } onRightClicked: { control.currentIndex = index control.itemRightClicked(index) } onRightEmblemClicked: { control.currentIndex = index control.rightEmblemClicked(index) } onLeftEmblemClicked: { control.currentIndex = index control.leftEmblemClicked(index) } } } } diff --git a/src/controls/GridBrowserDelegate.qml b/src/controls/GridBrowserDelegate.qml index ca3b25e..ddf3e85 100644 --- a/src/controls/GridBrowserDelegate.qml +++ b/src/controls/GridBrowserDelegate.qml @@ -1,184 +1,207 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtGraphicalEffects 1.0 import "private" Maui.ItemDelegate { id: control - property int folderSize : iconSize + property int folderSize : Maui.Style.iconSizes.big property int emblemSize: Maui.Style.iconSizes.medium property bool showLabel : true property bool showEmblem : false property bool showTooltip : false property bool showThumbnails : false property bool isSelected : false property bool keepEmblemOverlay : false property string rightEmblem property string leftEmblem + property alias dropArea : _dropArea + isCurrentItem : GridView.isCurrentItem || isSelected signal emblemClicked(int index) signal rightEmblemClicked(int index) signal leftEmblemClicked(int index) + signal contentDropped(var drop) ToolTip.delay: 1000 ToolTip.timeout: 5000 ToolTip.visible: control.hovered && control.showTooltip ToolTip.text: model.tooltip ? model.tooltip : model.path - + + DropArea + { + id: _dropArea + anchors.fill: parent + enabled: control.draggable + + Rectangle + { + anchors.fill: parent + radius: Maui.Style.radiusV + color: control.Kirigami.Theme.highlightColor + visible: parent.containsDrag + } + + onDropped: + { + control.contentDropped(drop) + } + } + + Drag.active: mouseArea.drag.active && control.draggable + Drag.dragType: Drag.Automatic + Drag.supportedActions: Qt.CopyAction + Drag.mimeData: + { + "text/uri-list": model.path + } + + Maui.Badge { id: _leftEmblemIcon iconName: control.leftEmblem visible: (control.hovered || control.keepEmblemOverlay || control.isSelected) && control.showEmblem && control.leftEmblem anchors.top: parent.top anchors.left: parent.left onClicked: leftEmblemClicked(index) size: Maui.Style.iconSizes.small } Maui.Badge { id: _rightEmblemIcon iconName: rightEmblem visible: (control.hovered || control.keepEmblemOverlay) && control.showEmblem && control.rightEmblem z: 999 size: Maui.Style.iconSizes.medium anchors.top: parent.top anchors.right: parent.right onClicked: rightEmblemClicked(index) } Component { id: _imgComponent Item { anchors.fill: parent Image { id: img anchors.centerIn: parent source: model.thumbnail ? model.thumbnail : undefined height: Math.min (parent.height, img.implicitHeight) width: Math.min(parent.width * 0.98, img.implicitWidth) sourceSize.width: width sourceSize.height: height horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter fillMode: Image.PreserveAspectCrop cache: false asynchronous: true smooth: !Kirigami.Settings.isMobile layer.enabled: true layer.effect: OpacityMask { maskSource: Item { width: img.width height: img.height Rectangle { anchors.centerIn: parent width: img.width height: img.height radius: Maui.Style.radiusV } } } } Loader { anchors.centerIn: parent sourceComponent: img.status === Image.Ready ? undefined : _iconComponent } } } Component { id: _iconComponent Item { anchors.fill: parent Kirigami.Icon { anchors.centerIn: parent source: model.icon fallback: "qrc:/assets/application-x-zerosize.svg" height: control.folderSize width: height } } } ColumnLayout { id: _layout anchors.fill: parent spacing: Maui.Style.space.tiny opacity: (model.hidden == true || model.hidden == "true" )? 0.5 : 1 Loader { sourceComponent: model.mime ? (model.mime.indexOf("image") > -1 && control.showThumbnails ? _imgComponent : _iconComponent) : _iconComponent Layout.preferredHeight: control.folderSize Layout.fillWidth: true Layout.alignment: Qt.AlignCenter - Layout.margins: Maui.Style.unit - - Maui.Badge - { - iconName: "link" - anchors.left: parent.left - anchors.bottom: parent.bottom - visible: (model.issymlink == true) || (model.issymlink == "true") - } + Layout.margins: Maui.Style.unit } Label { id: label text: model.label Layout.margins: Maui.Style.space.tiny Layout.fillHeight: true Layout.fillWidth: true horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter elide: Qt.ElideRight wrapMode: Text.Wrap color: control.Kirigami.Theme.textColor } - } - + } } diff --git a/src/controls/GridView.qml b/src/controls/GridView.qml index 76aa2f4..819ea51 100644 --- a/src/controls/GridView.qml +++ b/src/controls/GridView.qml @@ -1,180 +1,186 @@ - /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ -import QtQuick 2.5 -import QtQuick.Controls 2.2 +import QtQuick 2.9 +import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import QtQuick.Controls.impl 2.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import QtGraphicalEffects 1.0 Kirigami.ScrollablePage { - id: control - - property int itemSize: 0 - onItemSizeChanged : gridView.size_ = itemSize - - property alias cellWidth: gridView.cellWidth - property alias cellHeight: gridView.cellHeight - property alias model : gridView.model - property alias delegate : gridView.delegate - property alias contentY: gridView.contentY - property alias currentIndex : gridView.currentIndex - property alias count : gridView.count - property alias cacheBuffer : gridView.cacheBuffer - - property alias topMargin: gridView.topMargin - property alias bottomMargin: gridView.bottomMargin - property alias rightMargin: gridView.rightMargin - property alias leftMarging: gridView.leftMargin - property alias holder : _holder - property alias gridView : gridView - - property bool centerContent: false //deprecrated - property bool adaptContent: true - - signal areaClicked(var mouse) - signal areaRightClicked() - - spacing: Maui.Style.space.medium - - Kirigami.Theme.backgroundColor: "transparent" - padding: 0 - leftPadding: control.ScrollBar.visible ? padding : control.ScrollBar.width - rightPadding: padding - topPadding: padding - bottomPadding: padding - focus: true - + id: control + + property int itemSize: 0 + onItemSizeChanged : gridView.size_ = itemSize + + property alias cellWidth: gridView.cellWidth + property alias cellHeight: gridView.cellHeight + property alias model : gridView.model + property alias delegate : gridView.delegate + property alias contentY: gridView.contentY + property alias currentIndex : gridView.currentIndex + property alias count : gridView.count + property alias cacheBuffer : gridView.cacheBuffer + + property alias topMargin: gridView.topMargin + property alias bottomMargin: gridView.bottomMargin + property alias rightMargin: gridView.rightMargin + property alias leftMarging: gridView.leftMargin + property alias holder : _holder + property alias gridView : gridView + + property bool centerContent: false //deprecrated + property bool adaptContent: true + + signal areaClicked(var mouse) + signal areaRightClicked() + signal keyPress(var key) + + spacing: Maui.Style.space.medium + + Kirigami.Theme.backgroundColor: "transparent" + padding: 0 + leftPadding: control.ScrollBar.visible ? padding : control.ScrollBar.width + rightPadding: padding + topPadding: padding + bottomPadding: padding + focus: true + Behavior on cellWidth { NumberAnimation { - duration: Kirigami.Units.shortDuration + duration: Kirigami.Units.shortDuration easing.type: Easing.InQuad } } - - GridView - { - id: gridView - - //nasty trick - property int size_ - Component.onCompleted: - { - gridView.size_ = control.itemSize - } - - flow: GridView.FlowLeftToRight - clip: true - focus: true - - cellWidth: control.itemSize - cellHeight: control.itemSize - - boundsBehavior: !Kirigami.Settings.isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds - flickableDirection: Flickable.AutoFlickDirection - snapMode: GridView.NoSnap - highlightMoveDuration: 0 - interactive: true - onWidthChanged: adaptContent? control.adaptGrid() : undefined - - Maui.Holder - { - id: _holder - anchors.fill : parent - } - - PinchArea - { - anchors.fill: parent - z: -1 - onPinchStarted: - { - console.log("pinch started") - } + + GridView + { + id: gridView - onPinchUpdated: + //nasty trick + property int size_ + Component.onCompleted: { - + gridView.size_ = control.itemSize } - onPinchFinished: + flow: GridView.FlowLeftToRight + clip: true + focus: true + + cellWidth: control.itemSize + cellHeight: control.itemSize + + boundsBehavior: !Kirigami.Settings.isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds + flickableDirection: Flickable.AutoFlickDirection + snapMode: GridView.NoSnap + highlightMoveDuration: 0 + interactive: true + onWidthChanged: adaptContent? control.adaptGrid() : undefined + + keyNavigationEnabled : bool + keyNavigationWraps : bool + Keys.onPressed: control.keyPress(event.key) + + Maui.Holder { - console.log("pinch finished") - resizeContent(pinch.scale) + id: _holder + anchors.fill : parent } - MouseArea + PinchArea { anchors.fill: parent - propagateComposedEvents: true - acceptedButtons: Qt.RightButton | Qt.LeftButton - onClicked: control.areaClicked(mouse) - onPressAndHold: control.areaRightClicked() -// scrollGestureEnabled : false + z: -1 + onPinchStarted: + { + console.log("pinch started") + } + + onPinchUpdated: + { + + } - onWheel: + onPinchFinished: { - if (wheel.modifiers & Qt.ControlModifier) + console.log("pinch finished") + resizeContent(pinch.scale) + } + + MouseArea + { + anchors.fill: parent + propagateComposedEvents: true + acceptedButtons: Qt.RightButton | Qt.LeftButton + onClicked: { - if (wheel.angleDelta.y != 0) + control.forceActiveFocus() + control.areaClicked(mouse) + } + onPressAndHold: control.areaRightClicked() + // scrollGestureEnabled : false + + onWheel: + { + if (wheel.modifiers & Qt.ControlModifier) { - var factor = 1 + wheel.angleDelta.y / 600; - control.resizeContent(factor) - } - }else - wheel.accepted = false + if (wheel.angleDelta.y != 0) + { + var factor = 1 + wheel.angleDelta.y / 600; + control.resizeContent(factor) + } + }else + wheel.accepted = false + } } } } - } - - - - function resizeContent(factor) - { - if(factor > 1) - { + + function resizeContent(factor) + { + if(factor > 1) + { gridView.size_ = gridView.size_ + 10 control.cellHeight = control.cellHeight + 10 - } - else - { + } + else + { gridView.size_ = gridView.size_ - 10 control.cellHeight = control.cellHeight - 10 - } - - if(adaptContent) - control.adaptGrid() - } - - function adaptGrid() - { - var amount = parseInt(gridView.width / (gridView.size_), 10) - var leftSpace = parseInt(gridView.width - ( amount * (gridView.size_) ), 10) + } + + if(adaptContent) + control.adaptGrid() + } + + function adaptGrid() + { + var amount = parseInt(gridView.width / (gridView.size_), 10) + var leftSpace = parseInt(gridView.width - ( amount * (gridView.size_) ), 10) var size = parseInt((gridView.size_) + (parseInt(leftSpace/amount, 10)), 10) -// size = size > gridView.size_? size : gridView.size_ + // size = size > gridView.size_? size : gridView.size_ control.cellWidth = size - } + } } diff --git a/src/controls/ItemDelegate.qml b/src/controls/ItemDelegate.qml index dce947a..89f1b21 100644 --- a/src/controls/ItemDelegate.qml +++ b/src/controls/ItemDelegate.qml @@ -1,102 +1,117 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.5 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtGraphicalEffects 1.0 import "private" ItemDelegate { id: control - - default property alias content : _content.data - + + default property alias content : _content.data + property alias mouseArea : _mouseArea property bool draggable: false property bool isCurrentItem : false - property int radius: Maui.Style.radiusV - + property int radius: Maui.Style.radiusV + //override the itemdelegate default signals to allow dragging content signal pressed(var mouse) signal pressAndHold(var mouse) - signal clicked(var mouse) + signal clicked(var mouse) signal rightClicked(var mouse) - signal doubleClicked(var mouse) - + signal doubleClicked(var mouse) + + Kirigami.Theme.backgroundColor: "transparent" + background: null hoverEnabled: !Kirigami.Settings.isMobile padding: 0 bottomPadding: padding rightPadding: padding leftPadding: padding topPadding: padding MouseArea - { + { id: _mouseArea anchors.fill: parent acceptedButtons: Qt.RightButton | Qt.LeftButton + drag.target: control.draggable && !Kirigami.Settings.isMobile ? parent : undefined + + property int startX + property int startY + onClicked: { if(!Kirigami.Settings.isMobile && mouse.button === Qt.RightButton) control.rightClicked(mouse) - else - control.clicked(mouse) + else + control.clicked(mouse) } - + onDoubleClicked: control.doubleClicked(mouse) - - onPressed: - { - if(control.draggable) - loader.grabToImage(function(result) + + onPressed: + { + if(control.draggable && !Kirigami.Settings.isMobile ) + control.grabToImage(function(result) { parent.Drag.imageSource = result.url }) - - control.pressed(mouse) + + startX = control.x + startY = control.y + control.pressed(mouse) + } + + onReleased : + { + control.x = startX + control.y = startY } - + onPressAndHold : control.pressAndHold(mouse) - } - + } + Rectangle - { + { id: _content - - anchors - { - fill: parent - topMargin: control.topPadding - bottomMargin: control.bottomPadding - leftMargin: control.leftPadding - rightMargin: control.rightPadding - margins: control.padding - } - color: control.isCurrentItem || control.hovered ? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.2) : "transparent" - - radius: control.radius - border.color: control.isCurrentItem ? Kirigami.Theme.highlightColor : "transparent" + anchors + { + fill: control + topMargin: control.topPadding + bottomMargin: control.bottomPadding + leftMargin: control.leftPadding + rightMargin: control.rightPadding + margins: control.padding + } + + color: control.isCurrentItem || control.hovered ? Qt.rgba(control.Kirigami.Theme.highlightColor.r, control.Kirigami.Theme.highlightColor.g, control.Kirigami.Theme.highlightColor.b, 0.2) : control.Kirigami.Theme.backgroundColor + + radius: control.radius + border.color: control.isCurrentItem ? control.Kirigami.Theme.highlightColor : "transparent" } -} +} diff --git a/src/controls/LabelDelegate.qml b/src/controls/LabelDelegate.qml index 81fe094..3cf8c81 100644 --- a/src/controls/LabelDelegate.qml +++ b/src/controls/LabelDelegate.qml @@ -1,73 +1,66 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" ItemDelegate { - id: control - Kirigami.Theme.backgroundColor: isSection ? "transparent" : (index % 2 === 0 ? Qt.darker(Kirigami.Theme.backgroundColor) : "transparent") - property bool isCurrentListItem : ListView.isCurrentItem - - width: parent.width - height: Maui.Style.rowHeight - + id: control + Kirigami.Theme.backgroundColor: isSection ? "transparent" : (index % 2 === 0 ? Qt.darker(Kirigami.Theme.backgroundColor) : "transparent") + + property bool isCurrentListItem : ListView.isCurrentItem + + implicitHeight: Maui.Style.rowHeight + property bool isSection : false - property bool boldLabel : false + property alias label: labelTxt.text property alias labelTxt : labelTxt - property string labelColor: ListView.isCurrentItem ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor - + background: Rectangle { - color: control.isCurrentListItem ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor - opacity: control.isCurrentListItem ? 1 : 0.1 + color: control.isCurrentListItem ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor + opacity: control.isCurrentListItem ? 1 : 0.1 } - - ColumnLayout + + Label { + id: labelTxt + anchors.margins: Maui.Style.contentMargins anchors.fill: parent - - Label - { - id: labelTxt - Layout.margins: Maui.Style.contentMargins - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - - width: parent.width - height: parent.height - - horizontalAlignment: Qt.AlignLeft - verticalAlignment: Qt.AlignVCenter - text: labelTxt.text - elide: Text.ElideRight - color: labelColor - font.pointSize: Maui.Style.fontSizes.default - - font.bold: boldLabel - font.weight : boldLabel ? Font.Bold : Font.Normal - } + + horizontalAlignment: Qt.AlignLeft + verticalAlignment: Qt.AlignVCenter + text: labelTxt.text + elide: Text.ElideRight + wrapMode: Text.NoWrap + color: control.isCurrentListItem ? control.Kirigami.Theme.highlightedTextColor : control.Kirigami.Theme.textColor + font.pointSize: Maui.Style.fontSizes.default + + font.bold: control.isSection + font.weight : control.isSection ? Font.Bold : Font.Normal } + } diff --git a/src/controls/ListBrowser.qml b/src/controls/ListBrowser.qml index f754069..c1ae2b5 100644 --- a/src/controls/ListBrowser.qml +++ b/src/controls/ListBrowser.qml @@ -1,166 +1,180 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami Kirigami.ScrollablePage { id: control property int itemSize : Maui.Style.iconSizes.big property bool showEmblem : true property bool keepEmblemOverlay : false property string rightEmblem property string leftEmblem property bool showDetailsInfo : false property bool showPreviewThumbnails: true property alias model : _listView.model property alias delegate : _listView.delegate property alias section : _listView.section property alias contentY: _listView.contentY property alias currentIndex : _listView.currentIndex property alias currentItem : _listView.currentItem property alias count : _listView.count property alias cacheBuffer : _listView.cacheBuffer property alias topMargin: _listView.topMargin property alias bottomMargin: _listView.bottomMargin property alias rightMargin: _listView.rightMargin property alias leftMarging: _listView.leftMargin property alias listView: _listView property alias holder : _holder signal itemClicked(int index) signal itemDoubleClicked(int index) signal itemRightClicked(int index) signal rightEmblemClicked(int index) signal leftEmblemClicked(int index) signal areaClicked(var mouse) signal areaRightClicked() + signal keyPress(var key) spacing: 0 focus: true Kirigami.Theme.backgroundColor: "transparent" padding: 0 leftPadding: padding rightPadding: padding topPadding: padding - bottomPadding: padding - + bottomPadding: padding + + onKeyPress: + { + if(key == Qt.Key_Return) + control.itemClicked(currentIndex) + } ListView { id: _listView focus: true + clip: true spacing: Maui.Style.space.tiny snapMode: ListView.NoSnap boundsBehavior: !Kirigami.Settings.isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds - keyNavigationEnabled: true interactive: Kirigami.Settings.isMobile highlightFollowsCurrentItem: true highlightMoveDuration: 0 + + keyNavigationEnabled : bool + keyNavigationWraps : bool + Keys.onPressed: control.keyPress(event.key) Maui.Holder { id: _holder anchors.fill : parent } delegate: Maui.ListBrowserDelegate { id: delegate width: parent.width height: itemSize + Maui.Style.space.big leftPadding: Maui.Style.space.small rightPadding: Maui.Style.space.small padding: 0 showDetailsInfo: control.showDetailsInfo folderSize : itemSize showTooltip: true showEmblem: control.showEmblem keepEmblemOverlay : control.keepEmblemOverlay showThumbnails: showPreviewThumbnails rightEmblem: control.rightEmblem leftEmblem: control.leftEmblem Connections { target: delegate onClicked: { control.currentIndex = index control.itemClicked(index) } onDoubleClicked: { control.currentIndex = index control.itemDoubleClicked(index) } onPressAndHold: { control.currentIndex = index control.itemRightClicked(index) } onRightClicked: { control.currentIndex = index control.itemRightClicked(index) } onRightEmblemClicked: { control.currentIndex = index control.rightEmblemClicked(index) } onLeftEmblemClicked: { control.currentIndex = index control.leftEmblemClicked(index) } } } MouseArea { anchors.fill: parent z: -1 acceptedButtons: Qt.RightButton | Qt.LeftButton - onClicked: control.areaClicked(mouse) + onClicked: + { + control.forceActiveFocus() + control.areaClicked(mouse) + } onPressAndHold: control.areaRightClicked() } } } diff --git a/src/controls/ListBrowserDelegate.qml b/src/controls/ListBrowserDelegate.qml index 4d09ed6..ccc3c9b 100644 --- a/src/controls/ListBrowserDelegate.qml +++ b/src/controls/ListBrowserDelegate.qml @@ -1,207 +1,228 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import QtGraphicalEffects 1.0 import "private" Maui.ItemDelegate { id: control property bool showDetailsInfo: false property int folderSize : iconSize property int emblemSize: Maui.Style.iconSizes.medium property bool showLabel : true property bool showEmblem : false property bool showTooltip : false property bool showThumbnails : false property bool isSelected : false property bool keepEmblemOverlay : false property string rightEmblem property string leftEmblem isCurrentItem : ListView.isCurrentItem || isSelected signal emblemClicked(int index) signal rightEmblemClicked(int index) - signal leftEmblemClicked(int index) + signal leftEmblemClicked(int index) + signal contentDropped(var drop) ToolTip.delay: 1000 ToolTip.timeout: 5000 ToolTip.visible: control.hovered && control.showTooltip ToolTip.text: model.tooltip ? model.tooltip : model.path + DropArea + { + id: _dropArea + anchors.fill: parent + enabled: control.draggable + + Rectangle + { + anchors.fill: parent + radius: Maui.Style.radiusV + color: control.Kirigami.Theme.highlightColor + visible: parent.containsDrag + } + + onDropped: + { + control.contentDropped(drop) + } + } + + Drag.active: mouseArea.drag.active && control.draggable + Drag.dragType: Drag.Automatic + Drag.supportedActions: Qt.CopyAction + Drag.mimeData: + { + "text/uri-list": model.path + } + Maui.Badge { id: _leftEmblemIcon iconName: control.leftEmblem visible: (control.hovered || control.keepEmblemOverlay || control.isSelected) && control.showEmblem && control.leftEmblem anchors.top: parent.top anchors.left: parent.left onClicked: leftEmblemClicked(index) size: Maui.Style.iconSizes.small } Component { id: _imgComponent Item { anchors.fill: parent Image { id: img anchors.centerIn: parent source: model.thumbnail ? model.thumbnail : undefined height: control.folderSize width: height sourceSize.width: width sourceSize.height: height horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter fillMode: Image.PreserveAspectCrop cache: false asynchronous: true smooth: !Kirigami.Settings.isMobile layer.enabled: true layer.effect: OpacityMask { maskSource: Item { width: img.width height: img.height Rectangle { anchors.centerIn: parent width: img.width height: img.height radius: Maui.Style.radiusV } } } } Loader { anchors.centerIn: parent sourceComponent: img.status === Image.Ready ? undefined : _iconComponent } } } Component { id: _iconComponent Kirigami.Icon { source: model.icon fallback: "qrc:/assets/application-x-zerosize.svg" height: control.folderSize width: height } } RowLayout { opacity: (model.hidden == true || model.hidden == "true" )? 0.5 : 1 anchors.fill: parent spacing: Maui.Style.space.small Item { Layout.preferredHeight: control.folderSize Layout.preferredWidth: control.folderSize Layout.alignment: Qt.AlignCenter Layout.leftMargin: Maui.Style.space.medium Loader { anchors.centerIn: parent sourceComponent: model.mime ? (model.mime.indexOf("image") > -1 && control.showThumbnails ? _imgComponent : _iconComponent) : _iconComponent - } - - Maui.Badge - { - iconName: "link" - anchors.left: parent.left - anchors.bottom: parent.bottom - visible: (model.issymlink == true) || (model.issymlink == "true") } } Label { id: label text: model.label Layout.margins: Maui.Style.space.tiny Layout.fillHeight: true Layout.fillWidth: true horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignVCenter elide: Qt.ElideRight wrapMode: Text.Wrap color: control.Kirigami.Theme.textColor } ColumnLayout { Layout.alignment: Qt.AlignRight Layout.rightMargin: Maui.Style.space.medium Label { Layout.alignment: Qt.AlignRight Layout.fillHeight: true horizontalAlignment: Qt.AlignRight verticalAlignment: Qt.AlignBottom elide: Qt.ElideRight wrapMode: Text.NoWrap font.pointSize: Maui.Style.fontSizes.small color: control.Kirigami.Theme.textColor opacity: control.isCurrentItem ? 1 : 0.5 text: model.mime === "inode/directory" ? (model.count ? model.count + qsTr(" items") : "") : Maui.FM.formatSize(model.size) } Label { Layout.alignment: Qt.AlignRight Layout.fillHeight: true text: Maui.FM.formatDate(model.modified, "MM/dd/yyyy") horizontalAlignment: Qt.AlignRight verticalAlignment: Qt.AlignTop elide: Qt.ElideRight wrapMode: Text.NoWrap font.pointSize: Maui.Style.fontSizes.small color: control.Kirigami.Theme.textColor opacity: control.isCurrentItem ? 1 : 0.5 } } } } diff --git a/src/controls/ListDelegate.qml b/src/controls/ListDelegate.qml index 17f727b..06b1381 100644 --- a/src/controls/ListDelegate.qml +++ b/src/controls/ListDelegate.qml @@ -1,112 +1,112 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.ItemDelegate { id: control property bool labelVisible : true property int iconSize : Maui.Style.iconSizes.medium property alias label: controlLabel.text property alias iconName: controlIcon.source implicitWidth: parent.width - implicitHeight: Math.max(control.iconSize + Maui.Style.space.big, Maui.Style.rowHeight) + implicitHeight: Math.max(control.iconSize + Maui.Style.space.tiny, Maui.Style.rowHeight) isCurrentItem : ListView.isCurrentItem padding: 0 leftPadding: Maui.Style.space.tiny rightPadding: Maui.Style.space.tiny ToolTip.delay: 1000 ToolTip.timeout: 5000 ToolTip.visible: hovered ToolTip.text: qsTr(control.label) RowLayout { anchors.fill: parent Item { Layout.fillHeight: true Layout.fillWidth: !labelVisible Layout.preferredWidth: model.icon ? parent.height : 0 visible: model.icon !== typeof("undefined") Kirigami.Icon { id: controlIcon anchors.centerIn: parent source: model.icon ? model.icon : "" color: control.Kirigami.Theme.textColor height: control.iconSize width: height } } Label { id: controlLabel visible: control.labelVisible Layout.fillHeight: true Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter verticalAlignment: Qt.AlignVCenter horizontalAlignment: Qt.AlignLeft text: model.label font.bold: false elide: Text.ElideRight wrapMode: Text.NoWrap font.pointSize: Kirigami.Settings.isMobile ? Maui.Style.fontSizes.big : Maui.Style.fontSizes.default color: control.Kirigami.Theme.textColor } Item { visible: typeof model.count !== "undefined" && model.count && model.count > 0 && control.labelVisible Layout.fillHeight: true Layout.preferredWidth: visible ? Math.max(Maui.Style.iconSizes.big + Maui.Style.space.small, _badge.implicitWidth) : 0 Layout.alignment: Qt.AlignRight Maui.Badge { id: _badge anchors.centerIn: parent text: model.count } } } function clearCount() { console.log("CLEANING SIDEBAR COUNT") model.count = 0 } } diff --git a/src/controls/Page.qml b/src/controls/Page.qml index ac171d5..5da8382 100644 --- a/src/controls/Page.qml +++ b/src/controls/Page.qml @@ -1,106 +1,106 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami import QtQuick.Layouts 1.3 import QtQuick.Window 2.3 Page { id: control - + focus: true leftPadding: control.padding rightPadding: control.padding topPadding: control.padding bottomPadding: control.padding signal goBackTriggered(); signal goForwardTriggered(); property alias headBar : _headBar property alias footBar: _footBar property Maui.ToolBar mheadBar : Maui.ToolBar { id: _headBar visible: count > 1 width: control.width height: implicitHeight position: ToolBar.Header Component { id: _titleComponent Label { text: control.title elide : Text.ElideRight font.bold : false font.weight: Font.Bold color : Kirigami.Theme.textColor font.pointSize: Maui.Style.fontSizes.big horizontalAlignment : Text.AlignHCenter verticalAlignment : Text.AlignVCenter } } middleContent: Loader { Layout.fillWidth: sourceComponent === _titleComponent Layout.fillHeight: sourceComponent === _titleComponent sourceComponent: control.title ? _titleComponent : undefined } } property Maui.ToolBar mfootBar : Maui.ToolBar { id: _footBar visible: count position: ToolBar.Footer width: control.width height: implicitHeight } header: headBar.count && headBar.position === ToolBar.Header ? headBar : undefined footer: Column { id: _footer children: { if(headBar.position === ToolBar.Footer && footBar.count) return [footBar , headBar] else if(headBar.position === ToolBar.Footer) return [headBar] else if(footBar.count) return [footBar] else return [] } } Keys.onBackPressed: { control.goBackTriggered(); event.accepted = true } Shortcut { sequence: "Forward" onActivated: control.goForwardTriggered(); } Shortcut { sequence: StandardKey.Forward onActivated: control.goForwardTriggered(); } Shortcut { sequence: StandardKey.Back onActivated: control.goBackTriggered(); } } diff --git a/src/controls/PathBar.qml b/src/controls/PathBar.qml index 9ded902..96c412f 100644 --- a/src/controls/PathBar.qml +++ b/src/controls/PathBar.qml @@ -1,234 +1,254 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Item { id: control implicitHeight: Maui.Style.iconSizes.big property string url : "" property bool pathEntry: false property alias list : _pathList property alias model : _pathModel property alias item : _loader.item signal pathChanged(string path) signal homeClicked() signal placeClicked(string path) + signal placeRightClicked(string path) onUrlChanged: append() Kirigami.Theme.colorSet: Kirigami.Theme.View Kirigami.Theme.inherit: false Rectangle { id: pathBarBG - anchors.fill: parent - - // z: -1 + anchors.fill: parent color: pathEntry ? Kirigami.Theme.backgroundColor : Kirigami.Theme.backgroundColor radius: Maui.Style.radiusV opacity: 1 border.color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) border.width: Maui.Style.unit } Loader { id: _loader anchors.fill: parent sourceComponent: pathEntry ? _pathEntryComponent : _pathCrumbsComponent onLoaded: { if(sourceComponent === _pathCrumbsComponent) control.append() } } Maui.BaseModel { id: _pathModel list: _pathList } Maui.PathList { id: _pathList } Component { id: _pathEntryComponent Maui.TextField { id: entry - anchors.fill: parent - anchors.leftMargin: Maui.Style.contentMargins - + anchors.fill: parent text: control.url Kirigami.Theme.textColor: control.Kirigami.Theme.textColor Kirigami.Theme.backgroundColor: "transparent" - // Kirigami.Theme.borderColor: "transparent" horizontalAlignment: Qt.AlignLeft onAccepted: { pathChanged(text) showEntryBar() } background: Rectangle { color: "transparent" } actions.data: ToolButton { icon.name: "go-next" icon.color: control.Kirigami.Theme.textColor onClicked: { pathChanged(entry.text) showEntryBar() } } } } Component { id: _pathCrumbsComponent RowLayout { anchors.fill: parent property alias listView: _listView spacing: 0 - Item + MouseArea { - Layout.fillHeight: true - Layout.leftMargin: Maui.Style.space.small - Layout.rightMargin: Maui.Style.space.small - Layout.preferredWidth: Maui.Style.iconSizes.medium + Layout.fillHeight: true + Layout.preferredWidth: control.height + onClicked: control.homeClicked() + hoverEnabled: true - ToolButton + Rectangle { - anchors.centerIn: parent - icon.name: Kirigami.Settings.isMobile ? "user-home-sidebar" : "user-home" - flat: true - icon.color: control.Kirigami.Theme.textColor - icon.width: Maui.Style.iconSizes.medium - onClicked: control.homeClicked() - } + anchors.fill: parent + radius: Maui.Style.radiusV + color: parent.containsMouse ? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.2) : "transparent" + Kirigami.Icon + { + anchors.centerIn: parent + source: Kirigami.Settings.isMobile ? "user-home-sidebar" : "user-home" + color: control.Kirigami.Theme.textColor + width: Maui.Style.iconSizes.medium + height: width + } + } } Kirigami.Separator { Layout.fillHeight: true color: pathBarBG.border.color } ListView { id: _listView Layout.fillHeight: true Layout.fillWidth: true orientation: ListView.Horizontal clip: true spacing: 0 focus: true interactive: true boundsBehavior: Kirigami.Settings.isMobile ? Flickable.DragOverBounds : Flickable.StopAtBounds model: _pathModel delegate: PathBarDelegate { id: delegate - height: control.height - (Maui.Style.unit*2) + height: parent.height width: Math.max(Maui.Style.iconSizes.medium * 2, implicitWidth) Connections { target: delegate onClicked: { - _listView.currentIndex = index - placeClicked(_pathList.get(index).path) + listView.currentIndex = index + control.placeClicked(_pathList.get(index).path) + + } + + onRightClicked: + { + control.placeRightClicked(_pathList.get(index).path) + + } + + onPressAndHold: + { + control.placeRightClicked(_pathList.get(index).path) } } } MouseArea { anchors.fill: parent onClicked: showEntryBar() z: -1 } } - Item + MouseArea { - Layout.fillHeight: true - Layout.leftMargin: Maui.Style.space.small - Layout.rightMargin: Maui.Style.space.small - Layout.preferredWidth: Maui.Style.iconSizes.medium - ToolButton + Layout.fillHeight: true + Layout.preferredWidth: control.height + onClicked: control.showEntryBar() + hoverEnabled: true + + Rectangle { - anchors.centerIn: parent - flat: true - icon.name: "filename-space-amarok" - icon.color: control.Kirigami.Theme.textColor - onClicked: showEntryBar() - } + anchors.fill: parent + radius: Maui.Style.radiusV + color: parent.containsMouse ? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.2) : "transparent" + Kirigami.Icon + { + anchors.centerIn: parent + source: "filename-space-amarok" + color: control.Kirigami.Theme.textColor + width: Maui.Style.iconSizes.medium + height: width + } + } } } } Component.onCompleted: control.append() function append() { _pathList.path = control.url if(_loader.sourceComponent !== _pathCrumbsComponent) return _loader.item.listView.currentIndex = _loader.item.listView.count-1 _loader.item.listView.positionViewAtEnd() } function showEntryBar() { control.pathEntry = !control.pathEntry } } diff --git a/src/controls/PlacesListBrowser.qml b/src/controls/PlacesListBrowser.qml index d1308bf..7efd300 100644 --- a/src/controls/PlacesListBrowser.qml +++ b/src/controls/PlacesListBrowser.qml @@ -1,124 +1,124 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.6 as Kirigami Maui.ListBrowser { id: control property alias list : placesList property alias itemMenu : _menu property int iconSize : Maui.Style.iconSizes.small signal placeClicked (string path) focus: true model: placesModel section.property: "type" section.criteria: ViewSection.FullString section.delegate: Maui.LabelDelegate { id: delegate label: section labelTxt.font.pointSize: Maui.Style.fontSizes.big isSection: true - boldLabel: true + width: parent.width height: Maui.Style.toolBarHeightAlt } onItemClicked: { var item = list.get(index) var path = item.path placesList.clearBadgeCount(index) placeClicked(path) } onItemRightClicked: _menu.popup() Menu { id: _menu property int index MenuItem { text: qsTr("Edit") } MenuItem { text: qsTr("Hide") } MenuItem { text: qsTr("Remove") Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor onTriggered: list.removePlace(control.currentIndex) } } Maui.BaseModel { id: placesModel list: placesList } Maui.PlacesList { id: placesList groups: [ Maui.FMList.PLACES_PATH, Maui.FMList.APPS_PATH, Maui.FMList.BOOKMARKS_PATH, Maui.FMList.DRIVES_PATH, Maui.FMList.TAGS_PATH] } Rectangle { anchors.fill: parent z: -1 color: Kirigami.Theme.backgroundColor } delegate: Maui.ListDelegate { id: itemDelegate iconSize: control.iconSize labelVisible: true leftPadding: Maui.Style.space.tiny rightPadding: Maui.Style.space.tiny radius : Maui.Style.radiusV Connections { target: itemDelegate onClicked: { control.currentIndex = index itemClicked(index) } onRightClicked: { control.currentIndex = index itemRightClicked(index) } onPressAndHold: { control.currentIndex = index itemRightClicked(index) } } } } diff --git a/src/controls/PlacesSidebar.qml b/src/controls/PlacesSidebar.qml index dc5de88..645fde9 100644 --- a/src/controls/PlacesSidebar.qml +++ b/src/controls/PlacesSidebar.qml @@ -1,81 +1,83 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.6 as Kirigami Maui.SideBar { id: control property alias list : placesList property alias itemMenu : _menu signal placeClicked (string path) focus: true model: placesModel section.property: "type" section.criteria: ViewSection.FullString section.delegate: Maui.LabelDelegate { id: delegate + width: control.width label: section - labelTxt.font.pointSize: Maui.Style.fontSizes.big - + labelTxt.font.pointSize: Maui.Style.fontSizes.big isSection: true - boldLabel: true height: Maui.Style.toolBarHeightAlt } - + onContentDropped: + { + placesList.addPlace(drop.text) + } onItemClicked: { var item = list.get(index) var path = item.path placesList.clearBadgeCount(index) placeClicked(path) } onItemRightClicked: _menu.popup() Menu { id: _menu property int index MenuItem { text: qsTr("Edit...") } MenuItem { text: qsTr("Hide") } MenuItem { text: qsTr("Remove") Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor onTriggered: list.removePlace(control.currentIndex) } } Maui.BaseModel { id: placesModel list: placesList } Maui.PlacesList { id: placesList groups: [ Maui.FMList.PLACES_PATH, Maui.FMList.APPS_PATH, Maui.FMList.BOOKMARKS_PATH, Maui.FMList.DRIVES_PATH, Maui.FMList.TAGS_PATH] } } diff --git a/src/controls/SelectionBar.qml b/src/controls/SelectionBar.qml index 467b5e7..54a6985 100644 --- a/src/controls/SelectionBar.qml +++ b/src/controls/SelectionBar.qml @@ -1,351 +1,387 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Item { id: control + focus: true + Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Complementary readonly property int barHeight : Maui.Style.iconSizes.large + Maui.Style.space.large property var selectedPaths: [] property var selectedItems: [] property alias selectionList : selectionList property alias anim : anim property alias model : selectionList.model property alias count : selectionList.count property color animColor : "black" property int position: Qt.Horizontal property string iconName : "overflow-menu" property bool iconVisible: true /** * if singleSelection is set to true then only a single item is selected * at time, and replaced with a newe item appended **/ property bool singleSelection: false signal iconClicked() signal cleared() signal exitClicked() signal itemClicked(int index) + signal itemPressAndHold(int index) signal itemAdded(var item) signal itemRemoved(var item) signal pathAdded(string path) signal pathRemoved(string path) + signal clicked(var mouse) + signal rightClicked(var mouse) + implicitHeight: if(position === Qt.Horizontal) barHeight else if(position === Qt.Vertical) parent.height else undefined implicitWidth: if(position === Qt.Horizontal) parent.width else if(position === Qt.Vertical) barHeight else undefined visible: selectionList.count > 0 Rectangle { id: bg anchors.fill: parent color: Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.6) radius: Maui.Style.radiusV opacity: 1 border.color: Kirigami.Theme.backgroundColor + MouseArea + { + anchors.fill: parent + acceptedButtons: Qt.RightButton | Qt.LeftButton + + onClicked: + { + if(!Kirigami.Settings.isMobile && mouse.button === Qt.RightButton) + control.rightClicked(mouse) + else + control.clicked(mouse) + } + + onPressAndHold : + { + if(Kirigami.Settings.isMobile) + control.rightClicked(mouse) + } + + + } SequentialAnimation { id: anim PropertyAnimation { target: bg property: "opacity" easing.type: Easing.InOutQuad from: 0.5 to: 1 duration: 600 } } } Maui.Badge { anchors.verticalCenter: parent.top anchors.horizontalCenter: parent.left iconName: "window-close" Kirigami.Theme.backgroundColor: Kirigami.Theme.negativeTextColor Kirigami.Theme.textColor: Kirigami.Theme.highlightedTextColor z: parent.z +1 onClicked: { clear() exitClicked() } } Maui.Badge { Kirigami.Theme.backgroundColor: Kirigami.Theme.highlightColor text: selectionList.count z: parent.z +1 anchors.verticalCenter: parent.top anchors.horizontalCenter: parent.right onClicked: clear() } GridLayout { anchors.fill: parent anchors.margins: Maui.Style.space.small rows: if(position === Qt.Horizontal) 1 else if(position === Qt.Vertical) 4 else undefined columns: if(position === Qt.Horizontal) 4 else if(position === Qt.Vertical) 1 else undefined Item { Layout.fillHeight: true Layout.fillWidth: true Layout.leftMargin: Maui.Style.space.small Layout.column: if(position === Qt.Horizontal) 2 else if(position === Qt.Vertical) 1 else undefined Layout.row: if(position === Qt.Horizontal) 1 else if(position === Qt.Vertical) 2 else undefined ListView { id: selectionList anchors.fill: parent highlightFollowsCurrentItem: true highlightMoveDuration: 0 keyNavigationEnabled: true interactive: Kirigami.Settings.isMobile boundsBehavior: !Kirigami.Settings.isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds orientation: if(position === Qt.Horizontal) ListView.Horizontal else if(position === Qt.Vertical) ListView.Vertical else undefined clip: true focus: true spacing: Maui.Style.space.small ScrollBar.horizontal: ScrollBar { policy: Kirigami.Settings.isMobile? Qt.ScrollBarAlwaysOff : Qt.ScrollBarAsNeeded } model: ListModel{} delegate: Maui.GridBrowserDelegate { id: delegate - anchors.verticalCenter: position === Qt.Horizontal ? parent.verticalCenter : undefined - anchors.horizontalCenter: position === Qt.Vertical ? parent.horizontalCenter : undefined isCurrentItem: ListView.isCurrentItem height: selectionList.height width: height folderSize: Maui.Style.iconSizes.big showLabel: true keepEmblemOverlay: true showEmblem: !Kirigami.Settings.isMobile showTooltip: true showThumbnails: true emblemSize: Maui.Style.iconSizes.small - Kirigami.Theme.highlightColor: Kirigami.Theme.highlightColor - Kirigami.Theme.backgroundColor: Kirigami.Theme.complementaryBackgroundColor - Kirigami.Theme.textColor: Kirigami.Theme.textColor - + Connections { target: delegate onLeftEmblemClicked: removeAtIndex(index) onClicked: control.itemClicked(index) + onPressAndHold: control.itemPressAndHold(index) } } } } Item { Layout.fillWidth: position === Qt.Vertical Layout.fillHeight: position === Qt.Horizontal Layout.preferredWidth: Maui.Style.iconSizes.medium Layout.preferredHeight: Maui.Style.iconSizes.medium Layout.column: if(position === Qt.Horizontal) 3 else if(position === Qt.Vertical) 1 else undefined Layout.row: if(position === Qt.Horizontal) 1 else if(position === Qt.Vertical) 3 else undefined Layout.margins: Maui.Style.space.medium ToolButton { visible: iconVisible anchors.centerIn: parent icon.name: control.iconName icon.color: control.Kirigami.Theme.textColor onClicked: iconClicked() } } } onVisibleChanged: { if(position === Qt.Vertical) return - - if(typeof(riseContent) === "undefined") return - - if(control.visible) - riseContent() - else - dropContent() + } + + Keys.onEscapePressed: + { + control.exitClicked(); + event.accepted = true + } + + Keys.onBackPressed: + { + control.exitClicked(); + event.accepted = true } function clear() { selectedPaths = [] selectedItems = [] selectionList.model.clear() control.cleared() } + function itemAt(index) + { + if(index < 0 || index > selectionList.count) + return + + return selectionList.model.get(index) + } + function removeAtIndex(index) { if(index < 0) return const item = selectionList.model.get(index) const path = item.path if(contains(path)) { selectedPaths.splice(index, 1) selectedItems.splice(index, 1) selectionList.model.remove(index) control.itemRemoved(item) control.pathRemoved(path) } } function removeAtPath(path) { removeAtIndex(indexOf(path)) } function indexOf(path) { return control.selectedPaths.indexOf(path) } function append(item) { const index = selectedPaths.indexOf(item.path) if(index < 0) { if(control.singleSelection) clear() selectedItems.push(item) selectedPaths.push(item.path) selectionList.model.append(item) selectionList.positionViewAtEnd() selectionList.currentIndex = selectionList.count - 1 control.itemAdded(item) control.pathAdded(item.path) }else { selectionList.currentIndex = index // notify(item.icon, qsTr("Item already selected!"), String("The item '%1' is already in the selection box").arg(item.label), null, 4000) } - + control.forceActiveFocus() animate(Kirigami.Theme.backgroundColor) } - function animate(color) + function animate(color) { animColor = color anim.running = true } function getSelectedPathsString() { return String(""+selectedPaths.join(",")) } function contains(path) { return control.selectedPaths.includes(path) } } diff --git a/src/controls/ShareDialog.qml b/src/controls/ShareDialog.qml index 5b28b72..87d43d6 100644 --- a/src/controls/ShareDialog.qml +++ b/src/controls/ShareDialog.qml @@ -1,100 +1,103 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami Maui.Dialog { id: control property var itemUrls : [] widthHint: 0.9 - maxHeight: Math.min(grid.implicitHeight, maxWidth) + (page.padding * 2) + maxHeight: Math.min(grid.implicitHeight, maxWidth) + (page.padding * 2) + headBar.height maxWidth: Maui.Style.unit * 500 verticalAlignment: Qt.AlignBottom defaultButtons: false + + page.title: qsTr("Open with") + headBar.visible: true Maui.GridBrowser { id: grid anchors.fill: parent showEmblem: false model: ListModel {} onItemClicked: { grid.currentIndex = index triggerService(index) } } onOpened: populate() function show(urls) { if(urls.length > 0) { itemUrls = urls open() } } function populate() { grid.model.clear() var services = Maui.KDE.services(itemUrls[0]) var devices = Maui.KDE.devices() grid.model.append({icon: "internet-mail", label: "Email", email: true}) if(devices.length > 0) for(var i in devices) { devices[i].icon = "smartphone" grid.model.append(devices[i]) } if(services.length > 0) for(i in services) grid.model.append(services[i]) } function triggerService(index) { var obj = grid.model.get(index) if(obj.serviceKey) Maui.KDE.sendToDevice(obj.label, obj.serviceKey, itemUrls) else if(obj.email) Maui.KDE.attachEmail(itemUrls) else Maui.KDE.openWithApp(obj.actionArgument, itemUrls) close() } } diff --git a/src/controls/SideBar.qml b/src/controls/SideBar.qml index fa85665..849ec76 100644 --- a/src/controls/SideBar.qml +++ b/src/controls/SideBar.qml @@ -1,260 +1,267 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Maui.AbstractSideBar { id: control - - // ApplicationWindow.height -ApplicationWindow.header.height - ApplicationWindow.footer.height implicitWidth: privateProperties.isCollapsed && collapsed && collapsible ? collapsedSize : preferredWidth width: implicitWidth modal: false - interactive: Kirigami.Settings.isMobile && modal && !collapsible && !collapsed + position: 1 + interactive: false default property alias content : _content.data property alias model : _listBrowser.model property alias count : _listBrowser.count property alias section : _listBrowser.section property alias currentIndex: _listBrowser.currentIndex property int iconSize : Maui.Style.iconSizes.small property bool showLabels: control.width > collapsedSize property QtObject privateProperties : QtObject { property bool isCollapsed: control.collapsed } signal itemClicked(int index) signal itemRightClicked(int index) +// Connections +// { +// target: control.Overlay.overlay +// onPressed: control.collapse() +// } + onModalChanged: visible = true visible: true onCollapsedChanged : { if(!collapsible) return if(!collapsed && modal) { modal = false } if(!modal && !collapsed) { privateProperties.isCollapsed = false } if(collapsed && !modal) { privateProperties.isCollapsed = true } } ColumnLayout { id: _content anchors.fill: parent spacing: 0 - + Maui.ListBrowser { id: _listBrowser Layout.fillHeight: true Layout.fillWidth: true Layout.topMargin: Maui.Style.space.tiny Layout.bottomMargin: Maui.Style.space.tiny Layout.margins: Maui.Style.unit listView.flickableDirection: Flickable.VerticalFlick - - verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff //this make sthe app crash + verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff //this make sthe app crash + delegate: Maui.ListDelegate { id: itemDelegate iconSize: control.iconSize labelVisible: control.showLabels iconName: model.icon + (Kirigami.Settings.isMobile ? ("-sidebar") : "") leftPadding: Maui.Style.space.tiny rightPadding: Maui.Style.space.tiny Connections { target: itemDelegate onClicked: { control.currentIndex = index control.itemClicked(index) } onRightClicked: { control.currentIndex = index control.itemRightClicked(index) } onPressAndHold: { control.currentIndex = index control.itemRightClicked(index) } } } } MouseArea { id: _handle visible: collapsible && collapsed Layout.preferredHeight: Maui.Style.toolBarHeight Layout.fillWidth: true hoverEnabled: true preventStealing: true propagateComposedEvents: false property int startX property int startY - + Rectangle { anchors.fill: parent color: _handle.containsMouse || _handle.containsPress ? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.2) : "transparent" Kirigami.Separator { anchors { left: parent.left right: parent.right top: parent.top } height: Maui.Style.unit } Kirigami.Icon { - source: privateProperties.isCollapsed ? "sidebar-expand" : "sidebar-collapse" + source: privateProperties.isCollapsed ? "sidebar-expand" : "sidebar-collapse" color: _handle.containsMouse || _handle.containsPress ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor anchors.centerIn: parent width: Maui.Style.iconSizes.medium height: width } } onPositionChanged: { if (!pressed || !control.collapsible || !control.collapsed || !Kirigami.Settings.isMobile) return - if(mouse.x > (control.collapsedSize*2)) + if(mouse.x > control.collapsedSize) { expand() - - }else - { - collapse() } + + mouse.accepted = true } onPressed: { startY = mouse.y startX = mouse.x mouse.accepted = true } onReleased: { - mouse.accepted = true - if(!control.collapsible) return if(mouse.x > control.width) - { - expand() + return - }else if(startX > control.collapsedSize && mouse.x < control.collapsedSize ) - { - collapse() - }else - { - if(privateProperties.isCollapsed) - expand() + if(privateProperties.isCollapsed) + expand() else collapse() - } + + mouse.accepted = true } } } MouseArea { z: control.modal ? applicationWindow().overlay.z + (control.position > 0 ? +1 : -1) : control.background.parent.z + 1 preventStealing: true anchors.horizontalCenter: parent.right anchors.top: parent.top anchors.bottom: parent.bottom visible: Kirigami.Settings.isMobile - enabled: control.collapsed + enabled: control.collapsed && visible width: Maui.Style.space.large + property int startX + property int startY - onReleased: + onPressed: { - if (!control.collapsible || !control.collapsed || !Kirigami.Settings.isMobile) + startY = mouse.y + startX = mouse.x + mouse.accepted = true + } + + onPositionChanged: + { + if (!pressed || !control.collapsible || !control.collapsed || !Kirigami.Settings.isMobile) return - if(mouse.x > control.width) - { - expand() - }else - { - collapse() - } + if(mouse.x > control.collapsedSize) + { + expand() + }else + { + collapse() + } + + mouse.accepted = true } } function collapse() { if(collapsible && !privateProperties.isCollapsed) { modal = false privateProperties.isCollapsed = true } } function expand() { if(collapsible && privateProperties.isCollapsed) { modal = true privateProperties.isCollapsed = false } } } diff --git a/src/controls/Style.qml b/src/controls/Style.qml index 4deb77f..aacfd13 100644 --- a/src/controls/Style.qml +++ b/src/controls/Style.qml @@ -1,93 +1,93 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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 Singleton import QtQuick 2.4 import org.kde.kirigami 2.7 as Kirigami QtObject { id: style readonly property bool isAndroid: Qt.platform.os == "android" readonly property bool isMobile : Kirigami.Settings.isMobile property color warningColor : "#FFB300" property color dangerColor : "#D81B60" property color infoColor : "#4caf50" property color suggestedColor : "#039BE5" property int unit : Kirigami.Units.devicePixelRatio property int radiusV : unit * 4 - readonly property int rowHeight: iconSizes.medium + space.big + readonly property int rowHeight: iconSizes.big readonly property int rowHeightAlt: rowHeight * 0.8 readonly property int contentMargins: space.medium readonly property int toolBarHeight: (iconSizes.medium * 2.2) /*+ space.tiny*/ readonly property int toolBarHeightAlt: toolBarHeight * 0.9 readonly property int defaultFontSize: Kirigami.Theme.defaultFont.pointSize readonly property var fontSizes: ({ tiny: defaultFontSize * 0.7, small: (isMobile ? defaultFontSize * 0.7 : defaultFontSize * 0.8), medium: (isMobile ? defaultFontSize * 0.8 : defaultFontSize * 0.9), default: (isMobile ? defaultFontSize * 0.9 : defaultFontSize), big: (isMobile ? defaultFontSize : defaultFontSize * 1.1), large: (isMobile ? defaultFontSize * 1.1 : defaultFontSize * 1.2), huge: (isMobile ? defaultFontSize * 1.2 : defaultFontSize * 1.3), enormous: (isMobile ? defaultFontSize * 1.3 : defaultFontSize * 1.4) }) readonly property var space : ({ tiny: Kirigami.Units.smallSpacing, small: Kirigami.Units.smallSpacing*2, medium: Kirigami.Units.largeSpacing, big: Kirigami.Units.largeSpacing*2, large: Kirigami.Units.largeSpacing*3, huge: Kirigami.Units.largeSpacing*4, enormous: Kirigami.Units.largeSpacing*5 }) readonly property var iconSizes : ({ tiny : 8, small : Kirigami.Units.iconSizes.small, medium : Kirigami.Units.iconSizes.smallMedium, big: Kirigami.Units.iconSizes.medium, large: Kirigami.Units.iconSizes.large, huge: Kirigami.Units.iconSizes.huge, enormous: Kirigami.Units.iconSizes.enormous }) } diff --git a/src/controls/SwipeBrowserDelegate.qml b/src/controls/SwipeBrowserDelegate.qml new file mode 100644 index 0000000..9193780 --- /dev/null +++ b/src/controls/SwipeBrowserDelegate.qml @@ -0,0 +1,208 @@ +/* + * Copyright 2018 Camilo Higuita + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, 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 Library 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. + */ + +import QtQuick 2.9 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.0 + +import org.kde.kirigami 2.7 as Kirigami +import org.kde.mauikit 1.0 as Maui + +Maui.SwipeItemDelegate +{ + id: control + + property alias label1 : _label1 + property alias label2 : _label2 + property alias label3 : _label3 + property alias label4 : _label4 + property alias iconItem : _iconLoader.item + property alias iconVisible : _iconContainer.visible + property int iconSizeHint : Maui.Style.iconSizes.big + property string imageSource + property string iconSource + + Component + { + id: _imgComponent + + Item + { + anchors.fill: parent + Image + { + id: img + anchors.centerIn: parent + source: control.imageSource + height: Math.min(parent.height, control.iconSizeHint) + width: height + sourceSize.width: width + sourceSize.height: height + horizontalAlignment: Qt.AlignHCenter + verticalAlignment: Qt.AlignVCenter + fillMode: Image.PreserveAspectCrop + cache: false + asynchronous: true + smooth: !Kirigami.Settings.isMobile + + layer.enabled: true + layer.effect: OpacityMask + { + maskSource: Item + { + width: img.width + height: img.height + Rectangle + { + anchors.centerIn: parent + width: img.width + height: img.height + radius: Maui.Style.radiusV + } + } + } + } + + Loader + { + anchors.centerIn: parent + sourceComponent: img.status === Image.Ready ? undefined : _iconComponent + } + } + } + + + Component + { + id: _iconComponent + + Kirigami.Icon + { + source: control.iconSource + anchors.centerIn: parent + fallback: "qrc:/assets/application-x-zerosize.svg" + height: Math.min(parent.height, control.iconSizeHint) + width: height + } + } + + + RowLayout + { + id: _layout + anchors.fill: parent + + spacing: Maui.Style.space.small + + Item + { + id: _iconContainer + visible: (control.width > Kirigami.Units.gridUnit * 15) + Layout.preferredWidth: Math.max(control.height, control.iconSizeHint) + Layout.fillHeight: true + + Loader + { + id: _iconLoader + anchors.fill: parent + anchors.margins: Maui.Style.space.tiny + sourceComponent: control.imageSource ? _imgComponent : (control.iconSource ? _iconComponent : undefined) + } + } + + + ColumnLayout + { + Layout.fillHeight: visible + Layout.fillWidth: visible + Layout.margins: Maui.Style.space.small + + Label + { + id: _label1 + visible: text.length + Layout.fillWidth: visible + Layout.fillHeight: visible + verticalAlignment: _label2.visible ? Qt.AlignBottom : Qt.AlignVCenter + + elide: Text.ElideMiddle + wrapMode: Text.NoWrap + color: control.Kirigami.Theme.textColor + font.weight: Font.Normal + font.pointSize: Maui.Style.fontSizes.default + } + + Label + { + id: _label2 + visible: text.length + Layout.fillWidth: visible + Layout.fillHeight: visible + font.weight: Font.Normal + font.pointSize: Maui.Style.fontSizes.medium + wrapMode: Text.NoWrap + verticalAlignment: _label1.visible ? Qt.AlignTop : Qt.AlignVCenter + elide: Text.ElideRight + color: control.Kirigami.Theme.textColor + opacity: control.isCurrentItem || hovered ? 0.8 : 0.6 + } + } + + ColumnLayout + { + visible: control.width > Kirigami.Units.gridUnit * 30 + Layout.fillHeight: visible + Layout.fillWidth: visible + Layout.margins: Maui.Style.space.small + + Label + { + id: _label3 + visible: text.length > 0 + Layout.fillHeight: visible + Layout.fillWidth: visible + Layout.alignment: Qt.AlignRight + horizontalAlignment: Qt.AlignRight + font.pointSize: Maui.Style.fontSizes.small + font.weight: Font.Light + wrapMode: Text.WrapAnywhere + elide: Text.ElideMiddle + color: control.Kirigami.Theme.textColor + } + + Label + { + id: _label4 + visible: text.length > 0 + Layout.fillHeight: visible + Layout.fillWidth: visible + Layout.alignment: Qt.AlignRight + horizontalAlignment: Qt.AlignRight + font.pointSize: Maui.Style.fontSizes.small + font.weight: Font.Light + wrapMode: Text.WrapAnywhere + elide: Text.ElideMiddle + color: control.Kirigami.Theme.textColor + } + + } + } + +} diff --git a/src/controls/SwipeItemDelegate.qml b/src/controls/SwipeItemDelegate.qml index b8871cc..2cf0b37 100644 --- a/src/controls/SwipeItemDelegate.qml +++ b/src/controls/SwipeItemDelegate.qml @@ -1,269 +1,166 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.3 import QtGraphicalEffects 1.0 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.ItemDelegate { id: control isCurrentItem : ListView.isCurrentItem - property alias quickButtons : _buttonsRow.data - property bool showMenuIcon: true - - property alias label1 : _label1 - property alias label2 : _label2 - property alias label3 : _label3 - property alias label4 : _label4 - property alias iconImg : _icon - property int radius : Maui.Style.radiusV - - SwipeDelegate - { - id: _swipeDelegate - anchors.fill: parent - hoverEnabled: true - clip: true - Kirigami.Theme.colorSet: Kirigami.Theme.Button - Kirigami.Theme.inherit: false - swipe.enabled: showMenuIcon - -// Rectangle -// { -// id: _bg -// visible: swipe.position < 0 -// Kirigami.Theme.colorSet: Kirigami.Theme.Complementary -// Kirigami.Theme.inherit: false -// anchors.fill: parent -// color: Kirigami.Theme.backgroundColor -// border.color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) -// radius: control.radius -// z: background.z -1 -// } -// -// -// DropShadow -// { -// visible: _bg.visible -// anchors.fill: background -// horizontalOffset: 5 -// verticalOffset: 0 -// radius: 8.0 -// samples: 17 -// color: Qt.darker(_bg.color, 5) -// source: background -// } - -background: null + default property alias content : _content.data + + property bool showQuickActions : true + property list quickActions + + property bool collapse : width < Kirigami.Units.gridUnit * 26 || Kirigami.Settings.isMobile + + onCollapseChanged: + { + if(_swipeDelegate.swipe.position < 0) + _swipeDelegate.swipe.close() + } - RowLayout + SwipeDelegate { - id: _layout + id: _swipeDelegate anchors.fill: parent - Item - { - visible: control.width > Kirigami.Units.gridUnit * 15 - Layout.preferredWidth: visible ? parent.height : 0 - Layout.fillHeight: visible - Layout.margins: Maui.Style.space.medium - - Kirigami.Icon - { - id: _icon - width: Maui.Style.iconSizes.large - height: width - anchors.centerIn: parent - } - } + anchors.margins: 1 + hoverEnabled: true + clip: true + onClicked: control.clicked(null) + onPressed: control.pressed(null) + onDoubleClicked: control.doubleClicked(null) + onPressAndHold: control.pressAndHold(null) - Item + swipe.enabled: control.collapse && control.showQuickActions + padding: 0 + + Rectangle { - id: _info - - Layout.fillHeight: true - Layout.fillWidth: true - - ColumnLayout - { - anchors.fill: parent - - Label - { - id: _label1 - visible: text.length - Layout.fillHeight: visible - Layout.fillWidth: visible - font.pointSize: Maui.Style.fontSizes.big - font.bold: true - font.weight: Font.Bold - elide: Text.ElideMiddle - color: Kirigami.Theme.textColor - } - - Label - { - id: _label2 - visible: text.length - Layout.fillHeight: visible - Layout.fillWidth: visible - font.pointSize: Maui.Style.fontSizes.small - font.weight: Font.Light - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - elide: Text.ElideRight - color: Kirigami.Theme.textColor - } - } + id: _bg + anchors.fill: _swipeDelegate.background + z: _swipeDelegate.background.z -1 + color: Kirigami.Theme.backgroundColor + radius: Maui.Style.radiusV + opacity: Math.abs( _swipeDelegate.swipe.position) } - Item + background: RowLayout { - visible: control.width > Kirigami.Units.gridUnit * 30 - Layout.fillHeight: visible - Layout.fillWidth: visible - clip: true + spacing: 0 + id: _background + Item + { + id: _content + Layout.fillWidth: true + Layout.fillHeight: true + } - ColumnLayout + Row { - anchors.fill: parent + id: _buttonsRow + visible: hovered && control.showQuickActions && !control.collapse + Layout.fillHeight: true + Layout.preferredWidth: Math.max(Maui.Style.space.big, _buttonsRow.implicitWidth) + Layout.alignment: Qt.AlignRight + Layout.margins: Maui.Style.space.medium - Label + Behavior on Layout.preferredWidth { - id: _label3 - visible: text.length - Layout.fillHeight: visible - Layout.fillWidth: visible - Layout.alignment: Qt.AlignRight - horizontalAlignment: Qt.AlignRight - font.pointSize: Maui.Style.fontSizes.small - font.weight: Font.Light - wrapMode: Text.WrapAnywhere - elide: Text.ElideMiddle - color: Kirigami.Theme.textColor + NumberAnimation + { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } } - Label + spacing: Maui.Style.space.medium + + Repeater { - id: _label4 - visible: text.length - Layout.fillHeight: visible - Layout.fillWidth: visible - Layout.alignment: Qt.AlignRight - horizontalAlignment: Qt.AlignRight - font.pointSize: Maui.Style.fontSizes.small - font.weight: Font.Light - wrapMode: Text.WrapAnywhere - elide: Text.ElideMiddle - color: Kirigami.Theme.textColor + model: !control.collapse && control.showQuickActions ? control.quickActions : undefined + + ToolButton + { + action: modelData + anchors.verticalCenter: parent.verticalCenter + } } } - } - - - Item - { - Layout.fillHeight: true - Layout.preferredWidth: Math.max(Maui.Style.space.big, _buttonsRow.implicitWidth) - Layout.alignment: Qt.AlignRight - Layout.margins: Maui.Style.space.big - Row + Item { - id: _buttonsRow - anchors.centerIn: parent - spacing: Maui.Style.space.medium + visible: control.collapse && control.quickActions.length > 0 && control.showQuickActions + Layout.fillHeight: true + Layout.preferredWidth: Maui.Style.iconSizes.big + Maui.Style.space.small + Layout.margins: Maui.Style.space.small + ToolButton { - visible: showMenuIcon + anchors.centerIn: parent icon.name: "overflow-menu" onClicked: _swipeDelegate.swipe.position < 0 ? _swipeDelegate.swipe.close() : _swipeDelegate.swipe.open(SwipeDelegate.Right) } } - } - } - - swipe.right: Row - { - id: _rowActions - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - spacing: Maui.Style.space.big - padding: Maui.Style.space.medium - - ToolButton - { - icon.name: "draw-star" - anchors.verticalCenter: parent.verticalCenter - // onClicked: - // { - // control.favClicked(index) - // swipe.close() - // } - // icon.color: model.fav == "1" ? "yellow" : _bg.Kirigami.Theme.textColor - } - - ToolButton - { - icon.name: "document-share" - anchors.verticalCenter: parent.verticalCenter - // onClicked: if(isAndroid) Maui.Android.shareContact(model.id) - // icon.color: _bg.Kirigami.Theme.textColor } - ToolButton - { - icon.name: "message-new" - anchors.verticalCenter: parent.verticalCenter - // icon.color: _bg.Kirigami.Theme.textColor - // onClicked: - // { - // _messageComposer.contact = list.get(index) - // _messageComposer.open() - // swipe.close() - // } - } - ToolButton + swipe.right: Row { - icon.name: "call-start" + id: _rowActions + anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - // icon.color: _bg.Kirigami.Theme.textColor + spacing: Maui.Style.space.big + padding: Maui.Style.space.medium + visible: _swipeDelegate.swipe.complete + opacity: Math.abs(_swipeDelegate.swipe.position) - // onClicked: - // { - // if(isAndroid) - // Maui.Android.call(model.tel) - // else - // Qt.openUrlExternally("call://" + model.tel) + Behavior on width + { + NumberAnimation + { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + } - // swipe.close() - // } + Repeater + { + model: control.collapse && control.showQuickActions ? control.quickActions : undefined + + ToolButton + { + action: modelData + anchors.verticalCenter: parent.verticalCenter + onClicked: _swipeDelegate.swipe.close() + } + } } } - } - } diff --git a/src/controls/SyncDialog.qml b/src/controls/SyncDialog.qml index ad77a44..6a6ceb2 100644 --- a/src/controls/SyncDialog.qml +++ b/src/controls/SyncDialog.qml @@ -1,107 +1,104 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui Maui.Dialog { - id: control + id: control - property bool customServer: false + property bool customServer: false acceptText: qsTr("Sign In") rejectText: qsTr("Cancel") - rejectButton.visible: false - - property alias serverField: serverField - property alias userField: userField - property alias passwordField: passwordField - + rejectButton.visible: false + + property alias serverField: serverField + property alias userField: userField + property alias passwordField: passwordField + maxHeight: Maui.Style.unit * 300 - maxWidth: maxHeight - + maxWidth: maxHeight + + footBar.leftContent: ToolButton + { + icon.name: "filename-space-amarok" + checkable: true + checked: customServer + onClicked: customServer = !customServer + } - footBar.leftContent: ToolButton - { - icon.name: "filename-space-amarok" - // text: qsTr("Custom server") - checkable: true - checked: customServer - onClicked: customServer = !customServer - } - - onRejected: close() Item { anchors.fill: parent ColumnLayout { anchors.centerIn: parent width: parent.width Image { - visible: !customServer - Layout.alignment: Qt.AlignCenter - Layout.preferredWidth: width - Layout.preferredHeight: height - Layout.margins: Maui.Style.space.big - - width: Maui.Style.iconSizes.huge - height: width - sourceSize.width: width - sourceSize.height: height - - source: "qrc:/assets/opendesktop.png" - } + visible: !customServer + Layout.alignment: Qt.AlignCenter + Layout.preferredWidth: width + Layout.preferredHeight: height + Layout.margins: Maui.Style.space.big + + width: Maui.Style.iconSizes.huge + height: width + sourceSize.width: width + sourceSize.height: height + + source: "qrc:/assets/opendesktop.png" + } Maui.TextField { id: serverField visible: customServer Layout.fillWidth: true placeholderText: qsTr("Server address...") text: "https://cloud.opendesktop.cc/remote.php/webdav/" } Maui.TextField { id: userField Layout.fillWidth: true placeholderText: qsTr("Username...") inputMethodHints: Qt.ImhNoAutoUppercase } Maui.TextField { id: passwordField Layout.fillWidth: true placeholderText: qsTr("Password...") echoMode: TextInput.PasswordEchoOnEdit inputMethodHints: Qt.ImhNoAutoUppercase } } } } diff --git a/src/controls/TabBar.qml b/src/controls/TabBar.qml new file mode 100644 index 0000000..826f014 --- /dev/null +++ b/src/controls/TabBar.qml @@ -0,0 +1,33 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import org.kde.kirigami 2.7 as Kirigami +import org.kde.mauikit 1.0 as Maui + +TabBar +{ + id: control + implicitHeight: Maui.Style.rowHeight + Maui.Style.space.small + Kirigami.Theme.colorSet: Kirigami.Theme.View + Kirigami.Theme.inherit: false + clip: true + + background: Rectangle + { + color: Kirigami.Theme.backgroundColor + + Kirigami.Separator + { + color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) + + anchors + { + left: parent.left + right: parent.right + top: control.position === TabBar.Footer ? parent.top : undefined + bottom: control.position == TabBar.Header ? parent.bottom : undefined + } + height: Maui.Style.unit + } + } +} diff --git a/src/controls/TabButton.qml b/src/controls/TabButton.qml new file mode 100644 index 0000000..e4dbcbe --- /dev/null +++ b/src/controls/TabButton.qml @@ -0,0 +1,76 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import org.kde.kirigami 2.7 as Kirigami +import org.kde.mauikit 1.0 as Maui + +TabButton +{ + id: control + implicitWidth: 150 * Maui.Style.unit + + signal closeClicked(int index) + + Kirigami.Separator + { + color: Kirigami.Theme.highlightColor + height: Maui.Style.unit * 2 + visible: checked + anchors + { + + bottom: parent.bottom + left: parent.left + right: parent.right + } + } + + background: Rectangle + { + color: "transparent" + + Kirigami.Separator + { + width: Maui.Style.unit + anchors + { + bottom: parent.bottom + top: parent.top + right: parent.right + } + } + } + + contentItem: RowLayout + { + anchors.fill: control + spacing: Maui.Style.space.small + anchors.margins: Maui.Style.space.small + + Label + { + text: control.text + font.pointSize: Maui.Style.fontSizes.default + Layout.fillWidth: true + Layout.fillHeight: true + verticalAlignment: Qt.AlignVCenter + horizontalAlignment: Qt.AlignHCenter + color: control.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.textColor + wrapMode: Text.NoWrap + elide: Text.ElideMiddle + } + + ToolButton + { + Layout.fillHeight: true + Layout.preferredWidth: Maui.Style.iconSizes.medium + icon.height: Maui.Style.iconSizes.medium + icon.width: width + Layout.alignment: Qt.AlignRight + + icon.name: "dialog-close" + + onClicked: control.closeClicked(index) + } + } +} diff --git a/src/controls/TagsBar.qml b/src/controls/TagsBar.qml index 48497c4..0555489 100644 --- a/src/controls/TagsBar.qml +++ b/src/controls/TagsBar.qml @@ -1,147 +1,147 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.6 as Kirigami import org.kde.mauikit 1.0 as Maui import "private" Maui.ToolBar { id: control property alias listView : tagsList property alias count : tagsList.count property bool editMode : false property bool allowEditMode : false property alias list : tagsList.list signal addClicked() signal tagRemovedClicked(int index) signal tagClicked(string tag) signal tagsEdited(var tags) - Kirigami.Theme.backgroundColor: "transparent" - background: Rectangle - { - color: control.Kirigami.Theme.backgroundColor - } +// Kirigami.Theme.backgroundColor: "transparent" +// background: Rectangle +// { +// color: control.Kirigami.Theme.backgroundColor +// } leftContent: ToolButton { Layout.alignment: Qt.AlignLeft visible: allowEditMode && tagsList.visible icon.name: "list-add" onClicked: addClicked() icon.color: control.Kirigami.Theme.textColor } middleContent : [ TagList { id: tagsList visible: !control.editMode Layout.leftMargin: Maui.Style.space.medium Layout.fillHeight: true Layout.fillWidth: true showPlaceHolder: allowEditMode showDeleteIcon: allowEditMode onTagRemoved: tagRemovedClicked(index) onTagClicked: control.tagClicked(tagsList.list.get(index).tag) Kirigami.Theme.textColor: control.Kirigami.Theme.textColor Kirigami.Theme.backgroundColor: control.Kirigami.Theme.backgroundColor MouseArea { anchors.fill: parent z: tagsList.z -1 propagateComposedEvents: true onClicked: if(allowEditMode) goEditMode() } }, Maui.TextField { id: editTagsEntry visible: control.editMode Layout.fillHeight: true Layout.fillWidth:true horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter focus: true color: Kirigami.Theme.textColor selectionColor: Kirigami.Theme.highlightColor selectedTextColor: Kirigami.Theme.highlightedTextColor onAccepted: control.saveTags() actions.data: ToolButton { Layout.alignment: Qt.AlignLeft icon.name: "checkbox" onClicked: editTagsEntry.accepted() } background: Rectangle { color: "transparent" } } ] function clear() { // tagsList.model.clear() } function goEditMode() { var currentTags = [] for(var i = 0 ; i < tagsList.count; i++) currentTags.push(list.get(i).tag) editTagsEntry.text = currentTags.join(", ") editMode = true editTagsEntry.forceActiveFocus() } function saveTags() { control.tagsEdited(control.getTags()) editMode = false } function getTags() { if(!editTagsEntry.text.length > 0) return var tags = [] if(editTagsEntry.text.trim().length > 0) { var list = editTagsEntry.text.split(",") if(list.length > 0) for(var i in list) tags.push(list[i].trim()) } return tags } } diff --git a/src/controls/TagsDialog.qml b/src/controls/TagsDialog.qml index cb22c5e..4d58e55 100644 --- a/src/controls/TagsDialog.qml +++ b/src/controls/TagsDialog.qml @@ -1,166 +1,167 @@ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import TagsModel 1.0 import TagsList 1.0 Maui.Dialog { id: control property alias taglist :_tagsList property alias listView: _listView property alias composerList: tagListComposer.list acceptText: "OK" rejectText: "Cancel" signal tagsReady(var tags) defaultButtons: true maxHeight: Maui.Style.unit * 500 page.padding: Maui.Style.space.medium + acceptButton.text: qsTr("Add") + rejectButton.text: qsTr("Cancel") + onAccepted: setTags() onRejected: close() headBar.leftContent: ToolButton { icon.name: "view-sort" onClicked: sortMenu.popup() Menu { id: sortMenu MenuItem { text: qsTr("Sort by name") checkable: true checked: _tagsList.sortBy === TagsList.TAG onTriggered: _tagsList.sortBy = TagsList.TAG } MenuItem { text: qsTr("Sort by date") checkable: true checked: _tagsList.sortBy === TagsList.ADD_DATE onTriggered: _tagsList.sortBy = TagsList.ADD_DATE } } } headBar.middleContent: Maui.TextField { id: tagText Layout.fillWidth: true placeholderText: qsTr("Add a new tag...") onAccepted: { var tags = tagText.text.split(",") for(var i in tags) { var myTag = tags[i].trim() _tagsList.insert(myTag) tagListComposer.list.append(myTag) } clear() } } headBar.rightContent: ToolButton { icon.name: "view-refresh" // text: qsTr("Refresh...") onClicked: taglist.refresh() } ColumnLayout { anchors.fill: parent Item { Layout.fillHeight: true Layout.fillWidth: true ListView { - id: _listView - clip: true - anchors.fill: parent - - signal tagClicked(int index) - - focus: true + id: _listView + anchors.fill: parent + spacing: Maui.Style.space.tiny + clip: true + focus: true interactive: true highlightFollowsCurrentItem: true highlightMoveDuration: 0 TagsModel { id: _tagsModel list: _tagsList } TagsList { id: _tagsList } Maui.Holder { id: holder emoji: "qrc:/img/assets/Electricity.png" visible: _listView.count === 0 isMask: false - title : "No tags!" - body: "Start tagging your pics" + title : qsTr("No tags!") + body: qsTr("Start by creating tags") emojiSize: Maui.Style.iconSizes.huge } model: _tagsModel delegate: Maui.ListDelegate { id: delegate label: tag radius: Maui.Style.radiusV Connections { target: delegate onClicked: { _listView.currentIndex = index tagListComposer.list.append(_tagsList.get(index).tag) } } } } } Maui.TagList { id: tagListComposer Layout.fillWidth: true - Layout.leftMargin: contentMargins - Layout.rightMargin: contentMargins - height: 64 + Layout.leftMargin: Maui.Style.contentMargins + Layout.rightMargin: Maui.Style.contentMargins + height: Maui.Style.rowHeight width: parent.width onTagRemoved: list.remove(index) placeholderText: "" } } function setTags() { var tags = [] for(var i = 0; i < tagListComposer.count; i++) tags.push(tagListComposer.list.get(i).tag) control.tagsReady(tags) close() } } diff --git a/src/controls/TextField.qml b/src/controls/TextField.qml index 9959529..9138e00 100644 --- a/src/controls/TextField.qml +++ b/src/controls/TextField.qml @@ -1,152 +1,151 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ import QtQuick 2.9 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 import QtQuick.Controls.Material 2.1 import org.kde.kirigami 2.2 as Kirigami import QtQuick.Controls.impl 2.3 import QtQuick.Controls.Material.impl 2.3 import org.kde.mauikit 1.0 as Maui import "private" TextField { id: control property alias menu : entryMenu property alias actions : _actions signal cleared() signal goBackTriggered(); signal goFowardTriggered(); // bottomPadding: Maui.Style.space.tiny rightPadding: _actions.implicitWidth + Maui.Style.space.small selectByMouse: !Kirigami.Settings.isMobile persistentSelection: true focus: true wrapMode: TextInput.NoWrap onPressAndHold: !Kirigami.Settings.isMobile ? entryMenu.popup() : undefined onPressed: { if(!Kirigami.Settings.isMobile && event.button === Qt.RightButton) entryMenu.popup() } Keys.onBackPressed: { goBackTriggered(); event.accepted = true } Shortcut { sequence: "Forward" onActivated: goFowardTriggered(); } Shortcut { sequence: StandardKey.Forward onActivated: goFowardTriggered(); } Shortcut { sequence: StandardKey.Back onActivated: goBackTriggered(); } Row { id: _actions z: parent.z + 1 anchors.right: control.right - anchors.rightMargin: Maui.Style.space.small anchors.verticalCenter: parent.verticalCenter ToolButton { id: clearButton visible: control.text.length icon.name: "edit-clear" icon.color: control.color onClicked: { control.clear() cleared() } } } Menu { id: entryMenu z: control.z +1 MenuItem { text: qsTr("Copy") onTriggered: control.copy() enabled: control.selectedText.length } MenuItem { text: qsTr("Cut") onTriggered: control.cut() enabled: control.selectedText.length } MenuItem { text: qsTr("Paste") onTriggered: { var text = control.paste() control.insert(control.cursorPosition, text) } } MenuItem { text: qsTr("Select All") onTriggered: control.selectAll() enabled: control.text.length } MenuItem { text: qsTr("Undo") onTriggered: control.undo() enabled: control.canUndo } MenuItem { text: qsTr("Redo") onTriggered: control.redo() enabled: control.canRedo } } } diff --git a/src/controls/private/AudioPreview.qml b/src/controls/private/AudioPreview.qml index dba85ef..4b8ae9c 100644 --- a/src/controls/private/AudioPreview.qml +++ b/src/controls/private/AudioPreview.qml @@ -1,85 +1,78 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtMultimedia 5.8 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami -ColumnLayout +Maui.Page { - id: control - anchors.fill: parent - property alias player: player - - - Item - { - Layout.fillHeight: true - Layout.fillWidth: true - - Image - { - anchors.centerIn: parent - width: Math.min(parent.width, 200) - height: width - source: "qrc:/assets/cover.png" - sourceSize.width: width - sourceSize.height: height - asynchronous: true - smooth: true - fillMode: Image.PerseveAspectRatio - cache: true - - MediaPlayer - { - id: player - source: currentUrl - autoLoad: true - autoPlay: true - property string title : player.metaData.title - - onTitleChanged: - { - infoModel.append({key:"Title", value: player.metaData.title}) - infoModel.append({key:"Artist", value: player.metaData.albumArtist}) - infoModel.append({key:"Album", value: player.metaData.albumTitle}) - infoModel.append({key:"Author", value: player.metaData.author}) - infoModel.append({key:"Codec", value: player.metaData.audioCodec}) - infoModel.append({key:"Copyright", value: player.metaData.copyright}) - infoModel.append({key:"Duration", value: player.metaData.duration}) - infoModel.append({key:"Track", value: player.metaData.trackNumber}) - infoModel.append({key:"Year", value: player.metaData.year}) - infoModel.append({key:"Rating", value: player.metaData.userRating}) - infoModel.append({key:"Lyrics", value: player.metaData.lyrics}) - infoModel.append({key:"Genre", value: player.metaData.genre}) - infoModel.append({key:"Artwork", value: player.metaData.coverArtUrlLarge}) - } - } - } - } - - Maui.ToolBar - { - Layout.fillWidth: true - - leftContent: ToolButton - { - icon.name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" - onClicked: player.playbackState === MediaPlayer.PlayingState ? player.pause() : player.play() - - } - - middleContent : Slider - { - id: _slider - Layout.fillWidth: true - orientation: Qt.Horizontal - from: 0 - to: 1000 - value: (1000 * player.position) / player.duration - onMoved: player.seek((_slider.value / 1000) * player.duration) - } - } + id: control + anchors.fill: parent + property alias player: player + + Item + { + anchors.fill: parent + + Image + { + anchors.centerIn: parent + width: Math.min(parent.width, 200) + height: width + source: "qrc:/assets/cover.png" + sourceSize.width: width + sourceSize.height: height + asynchronous: true + smooth: true + fillMode: Image.PerseveAspectRatio + cache: true + + MediaPlayer + { + id: player + source: currentUrl + autoLoad: true + autoPlay: true + property string title : player.metaData.title + + onTitleChanged: + { + infoModel.append({key:"Title", value: player.metaData.title}) + infoModel.append({key:"Artist", value: player.metaData.albumArtist}) + infoModel.append({key:"Album", value: player.metaData.albumTitle}) + infoModel.append({key:"Author", value: player.metaData.author}) + infoModel.append({key:"Codec", value: player.metaData.audioCodec}) + infoModel.append({key:"Copyright", value: player.metaData.copyright}) + infoModel.append({key:"Duration", value: player.metaData.duration}) + infoModel.append({key:"Track", value: player.metaData.trackNumber}) + infoModel.append({key:"Year", value: player.metaData.year}) + infoModel.append({key:"Rating", value: player.metaData.userRating}) + infoModel.append({key:"Lyrics", value: player.metaData.lyrics}) + infoModel.append({key:"Genre", value: player.metaData.genre}) + infoModel.append({key:"Artwork", value: player.metaData.coverArtUrlLarge}) + } + } + } + } + + footBar.leftContent: ToolButton + { + icon.name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" + onClicked: player.playbackState === MediaPlayer.PlayingState ? player.pause() : player.play() + + } + + footBar.middleContent : Slider + { + id: _slider + Layout.fillWidth: true + orientation: Qt.Horizontal + from: 0 + to: 1000 + value: (1000 * player.position) / player.duration + onMoved: player.seek((_slider.value / 1000) * player.duration) + } } diff --git a/src/controls/private/BrowserHolder.qml b/src/controls/private/BrowserHolder.qml index 1c30985..c7e26f3 100644 --- a/src/controls/private/BrowserHolder.qml +++ b/src/controls/private/BrowserHolder.qml @@ -1,51 +1,22 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui QtObject { property Maui.FMList browser - property bool visible: !browser.pathExists || browser.pathEmpty || !browser.contentReady - property string emoji: - { - if(browser.pathExists && browser.pathEmpty) - "qrc:/assets/folder-add.svg" - else if(!browser.pathExists) - "qrc:/assets/dialog-information.svg" - else if(!browser.contentReady && currentPathType === Maui.FMList.SEARCH_PATH) - "qrc:/assets/edit-find.svg" - else if(!browser.contentReady) - "qrc:/assets/view-refresh.svg" - } + property bool visible: browser.status.code === Maui.FMList.LOADING || browser.status.code === Maui.FMList.ERROR || ( browser.status.code === Maui.FMList.READY && browser.status.empty === true) - property string title : - { - if(browser.pathExists && browser.pathEmpty) - qsTr("Folder is empty!") - else if(!browser.pathExists) - qsTr("Folder doesn't exists!") - else if(!browser.contentReady && currentPathType === Maui.FMList.SEARCH_PATH) - qsTr("Searching for content!") - else if(!browser.contentReady) - qsTr("Loading content!") - - } - property string body: - { - if(browser.pathExists && browser.pathEmpty) - qsTr("You can add new files to it") - else if(!browser.pathExists) - qsTr("Create Folder?") - else if(!browser.contentReady && currentPathType === Maui.FMList.SEARCH_PATH) - qsTr("This might take a while!") - else if(!browser.contentReady) - qsTr("Almost ready!") - } + property string emoji: browser.status.icon + + property string title : browser.status.title + + property string body: browser.status.message property int emojiSize: Maui.Style.iconSizes.huge } diff --git a/src/controls/private/BrowserView.qml b/src/controls/private/BrowserView.qml index 2a8f8d9..7d37959 100644 --- a/src/controls/private/BrowserView.qml +++ b/src/controls/private/BrowserView.qml @@ -1,542 +1,621 @@ import QtQuick 2.9 -import QtQuick.Controls 2.3 +import QtQuick.Controls 2.9 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui Maui.Page { id: control - focus: true property url path property Maui.FMList currentFMList property alias currentView : viewLoader.item property int viewType height: _browserList.height - width: _browserList.width + width: _browserList.width function setCurrentFMList() { - control.currentFMList = currentView.currentFMList + control.currentFMList = currentView.currentFMList + currentView.forceActiveFocus() + } + + Menu + { + id: _dropMenu + property string urls + property url target + + enabled: Maui.FM.getFileInfo(target).isdir == "true" + + MenuItem + { + text: qsTr("Copy here") + onTriggered: + { + const urls = _dropMenu.urls.split(",") + for(var i in urls) + { + var sourceItem = {"path" : urls[i]} + Maui.FM.copy([sourceItem], _dropMenu.target) + } + } + } + + MenuItem + { + text: qsTr("Move here") + onTriggered: + { + const urls = _dropMenu.urls.split(",") + for(var i in urls) + { + var sourceItem = {"path" : urls[i]} + Maui.FM.cut([sourceItem], _dropMenu.target) + } + } + } + + MenuItem + { + text: qsTr("Link here") + onTriggered: + { + const urls = _dropMenu.urls.split(",") + for(var i in urls) + Maui.FM.createSymlink(_dropMenu.source[i], urls.target) + } + } } Loader { id: viewLoader anchors.fill: parent - + focus: true sourceComponent: switch(control.viewType) { case Maui.FMList.ICON_VIEW: return gridViewBrowser case Maui.FMList.LIST_VIEW: return listViewBrowser case Maui.FMList.MILLERS_VIEW: return millerViewBrowser } onLoaded: setCurrentFMList() } Maui.FMList { id: _commonFMList path: control.path foldersFirst: true onSortByChanged: if(group) groupBy() - onContentReadyChanged: console.log("CONTENT READY?", contentReady) onWarning: { notify("dialog-information", "An error happened", message) } onProgress: { if(percent === 100) _progressBar.value = 0 else _progressBar.value = percent/100 } } Component { id: listViewBrowser Maui.ListBrowser { id: _listViewBrowser property alias currentFMList : _browserModel.list topMargin: Maui.Style.contentMargins showPreviewThumbnails: showThumbnails keepEmblemOverlay: selectionMode showDetailsInfo: true - BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize model: Maui.BaseModel { id: _browserModel list: _commonFMList } section.delegate: Maui.LabelDelegate { id: delegate - label: section + width: parent.width + height: Maui.Style.toolBarHeightAlt + + label: String(section).toUpperCase() labelTxt.font.pointSize: Maui.Style.fontSizes.big - + isSection: true - boldLabel: true - height: Maui.Style.toolBarHeightAlt } delegate: Maui.ListBrowserDelegate { id: delegate - property string path : model.path - width: parent.width + width: _listViewBrowser.width height: _listViewBrowser.itemSize + Maui.Style.space.big leftPadding: Maui.Style.space.small rightPadding: Maui.Style.space.small padding: 0 showDetailsInfo: _listViewBrowser.showDetailsInfo folderSize : _listViewBrowser.itemSize showTooltip: true showEmblem: _listViewBrowser.showEmblem keepEmblemOverlay : _listViewBrowser.keepEmblemOverlay showThumbnails: _listViewBrowser.showPreviewThumbnails rightEmblem: _listViewBrowser.rightEmblem isSelected: if(selectionBar) return selectionBar.contains(model.path) leftEmblem: isSelected ? "emblem-select-remove" : "emblem-select-add" + draggable: true + + Maui.Badge + { + iconName: "link" + anchors.left: parent.left + anchors.bottom: parent.bottom + visible: (model.issymlink == true) || (model.issymlink == "true") + } Connections { target: selectionBar onPathRemoved: { - if(path === delegate.path) + if(path === model.path) delegate.isSelected = false } onPathAdded: { - if(path === delegate.path) + if(path === model.path) delegate.isSelected = true } onCleared: delegate.isSelected = false } Connections { target: delegate onClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemClicked(index) } onDoubleClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemDoubleClicked(index) } onPressAndHold: { _listViewBrowser.currentIndex = index _listViewBrowser.itemRightClicked(index) } onRightClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.itemRightClicked(index) } onRightEmblemClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.rightEmblemClicked(index) } onLeftEmblemClicked: { _listViewBrowser.currentIndex = index _listViewBrowser.leftEmblemClicked(index) } + + onContentDropped: + { + _dropMenu.urls = drop.urls.join(",") + _dropMenu.target = model.path + _dropMenu.popup() + } } } } } Component { id: gridViewBrowser Maui.GridBrowser { id: _gridViewBrowser property alias currentFMList : _browserModel.list itemSize : thumbnailsSize + Maui.Style.fontSizes.default keepEmblemOverlay: selectionMode showPreviewThumbnails: showThumbnails leftEmblem: "emblem-select-add" BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize model: Maui.BaseModel { id: _browserModel list: _commonFMList } - delegate: Maui.GridBrowserDelegate + delegate: Maui.GridBrowserDelegate { id: delegate - property string path : model.path - - folderSize: height * 0.5 - height: _gridViewBrowser.cellHeight - width: _gridViewBrowser.cellWidth - padding: Maui.Style.space.small + + folderSize: height * 0.5 + height: _gridViewBrowser.cellHeight + width: _gridViewBrowser.cellWidth + padding: Maui.Style.space.small - showTooltip: true + showTooltip: true showEmblem: _gridViewBrowser.showEmblem keepEmblemOverlay: _gridViewBrowser.keepEmblemOverlay showThumbnails: _gridViewBrowser.showPreviewThumbnails rightEmblem: _gridViewBrowser.rightEmblem isSelected: if(selectionBar) return selectionBar.contains(model.path) leftEmblem: isSelected ? "emblem-select-remove" : "emblem-select-add" + draggable: true + + Maui.Badge + { + iconName: "link" + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.bottomMargin: Maui.Style.space.big + visible: (model.issymlink == true) || (model.issymlink == "true") + } Connections { target: selectionBar onPathRemoved: { - if(path === delegate.path) + if(path === model.path) delegate.isSelected = false } onPathAdded: { - if(path === delegate.path) + if(path === model.path) delegate.isSelected = true } - onCleared: delegate.isSelected = false + onCleared: delegate.isSelected = false + } Connections { target: delegate onClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemClicked(index) } onDoubleClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemDoubleClicked(index) } onPressAndHold: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemRightClicked(index) } onRightClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.itemRightClicked(index) } onRightEmblemClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.rightEmblemClicked(index) } onLeftEmblemClicked: { _gridViewBrowser.currentIndex = index _gridViewBrowser.leftEmblemClicked(index) } + + onContentDropped: + { + _dropMenu.urls = drop.urls.join(",") + _dropMenu.target = model.path + _dropMenu.popup() + + } } - } + } } } Component { id: millerViewBrowser Item { id: _millerControl property Maui.FMList currentFMList property int currentIndex signal itemClicked(int index) signal itemDoubleClicked(int index) signal itemRightClicked(int index) signal rightEmblemClicked(int index) signal leftEmblemClicked(int index) signal areaClicked(var mouse) signal areaRightClicked() ListView { id: _millerColumns anchors.fill: parent boundsBehavior: !Kirigami.Settings.isMobile? Flickable.StopAtBounds : Flickable.OvershootBounds keyNavigationEnabled: true interactive: Kirigami.Settings.isMobile orientation: ListView.Horizontal snapMode: ListView.NoSnap ScrollBar.horizontal: ScrollBar { } onCurrentItemChanged: { _millerControl.currentFMList = currentItem.currentFMList control.setCurrentFMList() } onCountChanged: { _millerColumns.currentIndex = _millerColumns.count-1 _millerColumns.positionViewAtEnd() } Maui.PathList { id: _millerList path: control.path onPathChanged: { _millerColumns.currentIndex = _millerColumns.count-1 _millerColumns.positionViewAtEnd() } } model: Maui.BaseModel { id: _millerModel list: _millerList } delegate: Item { property alias currentFMList : _millersFMList property int _index : index width: Math.min(Kirigami.Units.gridUnit * 22, control.width) height: parent.height -// background: Rectangle -// { -// color: "transparent" -// } - Kirigami.Separator { anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right width: 1 z: 999 } Maui.FMList { id: _millersFMList path: model.path foldersFirst: true onWarning: { notify("dialog-information", "An error happened", message) } onProgress: { if(percent === 100) _progressBar.value = 0 else _progressBar.value = percent/100 } } Maui.ListBrowser { id: _millerListView anchors.fill: parent topMargin: Maui.Style.contentMargins showPreviewThumbnails: showThumbnails keepEmblemOverlay: selectionMode rightEmblem: Kirigami.Settings.isMobile ? "document-share" : "" leftEmblem: "emblem-select-add" showDetailsInfo: true // currentIndex : _millerControl.currentIndex BrowserHolder { id: _holder browser: currentFMList } holder.visible: _holder.visible holder.emoji: _holder.emoji holder.title: _holder.title holder.body: _holder.body holder.emojiSize: _holder.emojiSize onAreaClicked: { _millerColumns.currentIndex = _index _millerControl.areaClicked(mouse) } onAreaRightClicked: { _millerColumns.currentIndex = _index _millerControl.areaRightClicked() } model: Maui.BaseModel { list: _millersFMList } - section.delegate: Maui.LabelDelegate - { - id: delegate - label: section - labelTxt.font.pointSize: Maui.Style.fontSizes.big - - isSection: true - boldLabel: true - height: Maui.Style.toolBarHeightAlt - } - delegate: Maui.ListBrowserDelegate { id: delegate - property string path : model.path width: parent.width height: _millerListView.itemSize + Maui.Style.space.big leftPadding: Maui.Style.space.small rightPadding: Maui.Style.space.small padding: 0 showDetailsInfo: _millerListView.showDetailsInfo folderSize : _millerListView.itemSize showTooltip: true showEmblem: _millerListView.showEmblem keepEmblemOverlay : _millerListView.keepEmblemOverlay showThumbnails: _millerListView.showPreviewThumbnails rightEmblem: _millerListView.rightEmblem isSelected: if(selectionBar) return selectionBar.contains(model.path) leftEmblem: isSelected ? "emblem-select-remove" : "emblem-select-add" + draggable: true + + Maui.Badge + { + iconName: "link" + anchors.left: parent.left + anchors.bottom: parent.bottom + visible: (model.issymlink == true) || (model.issymlink == "true") + } Connections { target: selectionBar onPathRemoved: { - if(path === delegate.path) + if(path === model.path) delegate.isSelected = false } onPathAdded: { - if(path === delegate.path) + if(path === model.path) delegate.isSelected = true } onCleared: delegate.isSelected = false } Connections { target: delegate onClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemClicked(index) } onDoubleClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemDoubleClicked(index) } onPressAndHold: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemRightClicked(index) } onRightClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.itemRightClicked(index) } onRightEmblemClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.rightEmblemClicked(index) } onLeftEmblemClicked: { _millerColumns.currentIndex = _index _millerListView.currentIndex = index _millerControl.leftEmblemClicked(index) } + + onContentDropped: + { + _dropMenu.urls = drop.urls.join(",") + _dropMenu.target = model.path + _dropMenu.popup() + } } } } } } } } } diff --git a/src/controls/private/FileMenu.qml b/src/controls/private/FileMenu.qml index d49ac34..24f24c9 100644 --- a/src/controls/private/FileMenu.qml +++ b/src/controls/private/FileMenu.qml @@ -1,168 +1,181 @@ import QtQuick 2.9 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.2 as Kirigami Menu { id: control implicitWidth: colorBar.implicitWidth + Maui.Style.space.big property var item : ({}) property int index : -1 property bool isDir : false property bool isExec : false + property bool isFav: false signal bookmarkClicked(var item) signal removeClicked(var item) signal shareClicked(var item) signal copyClicked(var item) signal cutClicked(var item) signal renameClicked(var item) signal tagsClicked(var item) MenuItem { visible: !control.isExec text: qsTr("Select") onTriggered: - { - + { addToSelection(currentFMList.get(index)) + if(Kirigami.Settings.isMobile) + selectionMode = true + } + } + + MenuItem + { + text: control.isFav ? qsTr("UnFav") : qsTr("Fav") + onTriggered: + { + if(currentFMList.favItem(item.path)) + control.isFav = !control.isFav } } MenuSeparator{} MenuItem { visible: control.isDir text: qsTr("Open in new tab...") onTriggered: openTab(item.path) } MenuSeparator{visible: isDir} MenuItem { visible: !control.isExec text: qsTr("Copy") onTriggered: { copyClicked(control.item) close() } } MenuItem { visible: !control.isExec text: qsTr("Cut") onTriggered: { cutClicked(control.item) close() } } MenuItem { visible: !control.isExec text: qsTr("Rename...") onTriggered: { renameClicked(control.item) close() } } MenuSeparator{} MenuItem { visible: !control.isExec && control.isDir text: qsTr("Add to Bookmarks") onTriggered: { bookmarkClicked(control.item) close() } } MenuItem { visible: !control.isExec text: qsTr("Tags...") onTriggered: { tagsClicked(control.item) close() } } MenuItem { visible: !control.isExec text: qsTr("Share...") onTriggered: { shareClicked(control.item) close() } } MenuItem { visible: !control.isExec text: qsTr("Properties") onTriggered: { previewer.show(control.item.path) close() } } MenuSeparator{} MenuItem { text: qsTr("Remove") Kirigami.Theme.textColor: Kirigami.Theme.negativeTextColor onTriggered: { removeClicked(control.item) close() } } MenuSeparator{ visible: colorBar.visible } MenuItem { width: parent.width height: visible ? Maui.Style.iconSizes.medium + Maui.Style.space.big : 0 visible: control.isDir Maui.ColorsBar { id: colorBar visible: parent.visible anchors.centerIn: parent size: Maui.Style.iconSizes.medium onColorPicked: currentFMList.setDirIcon(index, color) } } function show(index) { control.item = currentFMList.get(index) if(item) { control.index = index control.isDir = item.isdir == true || item.isdir == "true" control.isExec = item.executable == true || item.executable == "true" + control.isFav = currentFMList.itemIsFav(item.path) popup() } } } diff --git a/src/controls/private/PathBarDelegate.qml b/src/controls/private/PathBarDelegate.qml index b0cc339..1caf6b1 100644 --- a/src/controls/private/PathBarDelegate.qml +++ b/src/controls/private/PathBarDelegate.qml @@ -1,45 +1,63 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import org.kde.kirigami 2.6 as Kirigami +import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui ItemDelegate { id: control property bool isCurrentListItem : ListView.isCurrentItem - property color labelColor : Kirigami.Theme.textColor - anchors.verticalCenter: parent.verticalCenter implicitWidth: _label.implicitWidth + Maui.Style.space.big + + hoverEnabled: true + background: Rectangle { - color: isCurrentListItem ? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.2) : "transparent" + color: isCurrentListItem || hovered ? Qt.rgba(Kirigami.Theme.highlightColor.r, Kirigami.Theme.highlightColor.g, Kirigami.Theme.highlightColor.b, 0.2) : "transparent" Kirigami.Separator { anchors { top: parent.top bottom: parent.bottom right: parent.right } color: pathBarBG.border.color } } + + signal rightClicked() + + MouseArea + { + id: _mouseArea + anchors.fill: parent + acceptedButtons: Qt.RightButton | Qt.LeftButton + onClicked: + { + if(!Kirigami.Settings.isMobile && mouse.button === Qt.RightButton) + control.rightClicked() + else + control.clicked() + } + + onDoubleClicked: control.doubleClicked() + onPressAndHold : control.pressAndHold() + } Label { id: _label text: model.label anchors.fill: parent rightPadding: Maui.Style.space.medium leftPadding: rightPadding horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter elide: Qt.ElideRight font.pointSize: Maui.Style.fontSizes.default - color: labelColor - } - - + color: Kirigami.Theme.textColor + } } diff --git a/src/controls/private/TagDelegate.qml b/src/controls/private/TagDelegate.qml index 64f7caa..d5d0730 100644 --- a/src/controls/private/TagDelegate.qml +++ b/src/controls/private/TagDelegate.qml @@ -1,77 +1,75 @@ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami ItemDelegate -{ - +{ id: control - + property int tagWidth: Math.max(Maui.Style.iconSizes.medium * 5, tagLabel.implicitWidth + _closeIcon.width) - property int tagHeight: Maui.Style.iconSizes.medium - property bool showDeleteIcon: true - - signal removeTag(int index) + property int tagHeight: Maui.Style.rowHeightAlt + property bool showDeleteIcon: true - hoverEnabled: !Kirigami.Settings.isMobile - height: tagHeight - width: tagWidth - - anchors.verticalCenter: parent.verticalCenter - - ToolTip.visible: hovered - ToolTip.text: model.tag - - background: Image - { - source: "qrc:/assets/tag.svg" - sourceSize.width: tagWidth - sourceSize.height: tagHeight - width: tagWidth - height: tagHeight - } - - RowLayout - { - anchors.fill: parent - - Label - { - id: tagLabel - text: tag - Layout.fillHeight: true - Layout.fillWidth: true - Layout.leftMargin: tagWidth *0.2 - verticalAlignment: Qt.AlignVCenter - horizontalAlignment: Qt.AlignHCenter - elide: Qt.ElideRight - wrapMode: Text.NoWrap - font.pointSize: Maui.Style.fontSizes.medium - color: Kirigami.Theme.textColor - } - - - Item - { + signal removeTag(int index) + + hoverEnabled: !Kirigami.Settings.isMobile + height: tagHeight + width: tagWidth + + anchors.verticalCenter: parent.verticalCenter + + ToolTip.visible: hovered + ToolTip.text: model.tag + + background: Rectangle + { + radius: Maui.Style.radiusV + color: Kirigami.Theme.backgroundColor + width: tagWidth + height: tagHeight + border.color: Qt.tint(Kirigami.Theme.textColor, Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.7)) + } + + RowLayout + { + anchors.fill: parent + anchors.margins: Maui.Style.space.small + + Label + { + id: tagLabel + text: model.tag + Layout.fillHeight: true + Layout.fillWidth: true + verticalAlignment: Qt.AlignVCenter + horizontalAlignment: Qt.AlignHCenter + elide: Qt.ElideRight + wrapMode: Text.NoWrap + font.pointSize: Maui.Style.fontSizes.medium + color: Kirigami.Theme.textColor + } + + MouseArea + { id: _closeIcon - Layout.fillHeight: true - Layout.preferredWidth: showDeleteIcon ? Maui.Style.iconSizes.small : 0 - Layout.margins: Maui.Style.space.small - Layout.alignment: Qt.AlignRight - - ToolButton - { - anchors.centerIn: parent - visible: showDeleteIcon - icon.name: "window-close" + visible: showDeleteIcon + hoverEnabled: true + + Layout.fillHeight: true + Layout.preferredWidth: showDeleteIcon ? Maui.Style.iconSizes.medium : 0 + Layout.alignment: Qt.AlignRight + onClicked: removeTag(index) + + Kirigami.Icon + { + anchors.centerIn: parent + source: "window-close" height: Maui.Style.iconSizes.small - width: height - icon.width: height - onClicked: removeTag(index) - icon.color: Kirigami.Theme.textColor - } - } - } + width: height + color: Kirigami.Theme.textColor + } + } + } } diff --git a/src/controls/private/TagList.qml b/src/controls/private/TagList.qml index f5a5330..2d78a7e 100644 --- a/src/controls/private/TagList.qml +++ b/src/controls/private/TagList.qml @@ -1,63 +1,69 @@ import QtQuick 2.0 import QtQuick.Controls 2.2 import "." import org.kde.kirigami 2.7 as Kirigami import org.kde.mauikit 1.0 as Maui import TagsList 1.0 import TagsModel 1.0 ListView { id: control orientation: ListView.Horizontal clip: true spacing: Maui.Style.contentMargins boundsBehavior: Kirigami.Settings.isMobile ? Flickable.DragOverBounds : Flickable.StopAtBounds property string placeholderText: qsTr("Add tags...") property alias list : _tagsList property bool showPlaceHolder: true property bool showDeleteIcon: true signal tagRemoved(int index) signal tagClicked(int index) TagsModel { id: _tagsModel list: _tagsList } TagsList { id: _tagsList } model: _tagsModel Label { height: parent.height width: parent.width verticalAlignment: Qt.AlignVCenter text: qsTr(control.placeholderText) opacity: 0.7 visible: count === 0 && control.showPlaceHolder color: Kirigami.Theme.textColor font.pointSize: Maui.Style.fontSizes.default } delegate: TagDelegate { id: delegate showDeleteIcon: control.showDeleteIcon Kirigami.Theme.textColor: control.Kirigami.Theme.textColor + + ListView.onAdd: + { + control.positionViewAtEnd() + } + Connections { target: delegate onRemoveTag: tagRemoved(index) onClicked: tagClicked(index) } } } diff --git a/src/controls/private/VideoPreview.qml b/src/controls/private/VideoPreview.qml index 96aeb4b..6cae82d 100644 --- a/src/controls/private/VideoPreview.qml +++ b/src/controls/private/VideoPreview.qml @@ -1,106 +1,101 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtMultimedia 5.8 import org.kde.mauikit 1.0 as Maui import org.kde.kirigami 2.7 as Kirigami -ColumnLayout +Maui.Page { id: control property alias player : player anchors.fill: parent Video { id: player - Layout.fillHeight: true - Layout.fillWidth: true - + anchors.fill: parent source: currentUrl autoLoad: true autoPlay: true loops: 3 property string codec : player.metaData.videoCodec onCodecChanged: { infoModel.append({key:"Title", value: player.metaData.title}) infoModel.append({key:"Camera", value: player.metaData.cameraModel}) infoModel.append({key:"Zoom Ratio", value: player.metaData.digitalZoomRatio}) infoModel.append({key:"Author", value: player.metaData.author}) infoModel.append({key:"Audio Codec", value: player.metaData.audioCodec}) infoModel.append({key:"Video Codec", value: player.metaData.videoCodec}) infoModel.append({key:"Copyright", value: player.metaData.copyright}) infoModel.append({key:"Duration", value: player.metaData.duration}) infoModel.append({key:"Framerate", value: player.metaData.videoFrameRate}) infoModel.append({key:"Year", value: player.metaData.year}) infoModel.append({key:"Aspect Ratio", value: player.metaData.pixelAspectRatio}) infoModel.append({key:"Resolution", value: player.metaData.resolution}) } ToolButton { visible: player.playbackState == MediaPlayer.StoppedState anchors.centerIn: parent icon.color: "transparent" flat: true icon.width: Maui.Style.iconSizes.huge icon.name: iteminfo.icon } focus: true Keys.onSpacePressed: player.playbackState == MediaPlayer.PlayingState ? player.pause() : player.play() Keys.onLeftPressed: player.seek(player.position - 5000) Keys.onRightPressed: player.seek(player.position + 5000) RowLayout { anchors.fill: parent MouseArea { Layout.fillWidth: true Layout.fillHeight: true onDoubleClicked: player.seek(player.position - 5000) } MouseArea { Layout.fillWidth: true Layout.fillHeight: true onClicked: player.playbackState === MediaPlayer.PlayingState ? player.pause() : player.play() } MouseArea { Layout.fillWidth: true Layout.fillHeight: true onDoubleClicked: player.seek(player.position + 5000) } } } - - Maui.ToolBar + + + footBar.leftContent: ToolButton { - Layout.fillWidth: true - - leftContent: ToolButton - { - icon.name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" - onClicked: player.playbackState === MediaPlayer.PlayingState ? player.pause() : player.play() - } - - middleContent : Slider - { - id: _slider - Layout.fillWidth: true - orientation: Qt.Horizontal - from: 0 - to: 1000 - value: (1000 * player.position) / player.duration - - onMoved: player.seek((_slider.value / 1000) * player.duration) - } - } + icon.name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" + onClicked: player.playbackState === MediaPlayer.PlayingState ? player.pause() : player.play() + } + + footBar.middleContent : Slider + { + id: _slider + Layout.fillWidth: true + orientation: Qt.Horizontal + from: 0 + to: 1000 + value: (1000 * player.position) / player.duration + + onMoved: player.seek((_slider.value / 1000) * player.duration) + } + } diff --git a/src/controls/qmldir b/src/controls/qmldir index f095f6f..bf847e0 100644 --- a/src/controls/qmldir +++ b/src/controls/qmldir @@ -1,53 +1,56 @@ module org.kde.mauikit plugin MauiKit classname MauiKit depends QtQuick.Controls 1.4 depends QtQuick.Controls.Private 1.0 depends QtQuick.Controls 2.0 depends QtGraphicalEffects 1.0 designersupported typeinfo plugins.qmltypes singleton Style 1.0 Style.qml ApplicationWindow 1.0 ApplicationWindow.qml ToolBar 1.0 ToolBar.qml Page 1.0 Page.qml ShareDialog 1.0 ShareDialog.qml PieButton 1.0 PieButton.qml SideBar 1.0 SideBar.qml AbstractSideBar 1.0 AbstractSideBar.qml GlobalDrawer 1.0 GlobalDrawer.qml ListDelegate 1.0 ListDelegate.qml ItemDelegate 1.0 ItemDelegate.qml SwipeItemDelegate 1.0 SwipeItemDelegate.qml +SwipeBrowserDelegate 1.0 SwipeBrowserDelegate.qml ListBrowserDelegate 1.0 ListBrowserDelegate.qml GridBrowserDelegate 1.0 GridBrowserDelegate.qml SelectionBar 1.0 SelectionBar.qml LabelDelegate 1.0 LabelDelegate.qml NewDialog 1.0 NewDialog.qml TagsBar 1.0 TagsBar.qml TagsDialog 1.0 TagsDialog.qml Taglist 1.0 private/TagList.qml GridBrowser 1.0 GridBrowser.qml ListBrowser 1.0 ListBrowser.qml FileBrowser 1.0 FileBrowser.qml FilePreviewer 1.0 FilePreviewer.qml FileDialog 1.0 FileDialog.qml PlacesSidebar 1.0 PlacesSidebar.qml PlacesListBrowser 1.0 PlacesListBrowser.qml PathBar 1.0 PathBar.qml Dialog 1.0 Dialog.qml Popup 1.0 Popup.qml AboutDialog 1.0 AboutDialog.qml TextField 1.0 TextField.qml Badge 1.0 Badge.qml GridView 1.0 GridView.qml Terminal 1.0 Terminal.qml SyncDialog 1.0 SyncDialog.qml SyncDialog 1.0 SyncDialogA.qml Editor 1.0 Editor.qml ColorsBar 1.0 ColorsBar.qml Holder 1.0 Holder.qml ImageViewer 1.0 ImageViewer.qml +TabBar 1.0 TabBar.qml +TabButton 1.0 TabButton.qml diff --git a/src/fm/fm.cpp b/src/fm/fm.cpp index 30e93a4..eb432a9 100644 --- a/src/fm/fm.cpp +++ b/src/fm/fm.cpp @@ -1,937 +1,505 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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 "fm.h" -#include "utils.h" + +#ifdef COMPONENT_TAGGING #include "tagging.h" +#endif + +#ifdef COMPONENT_SYNCING #include "syncing.h" +#endif #include #include #include #include -#include #include #include #include #include #include #include #include #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #else #include "mauikde.h" #include #include +#include +#include #include #include #include #include #include #endif -/* - * FM *FM::instance = nullptr; - * - * FM* FM::getInstance() - * { - * if(!instance) - * { - * instance = new FM(); - * qDebug() << "getInstance(): First instance\n"; - * instance->init(); - * return instance; - * } else - * { - * qDebug()<< "getInstance(): previous instance\n"; - * return instance; - * } - * }*/ +FM::FM(QObject *parent) : QObject(parent) + #ifdef COMPONENT_SYNCING + ,sync(new Syncing(this)) + #endif + #ifdef COMPONENT_TAGGING + ,tag(Tagging::getInstance()) + #endif + #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + ,dirLister(new KCoreDirLister(this)) + #endif +{ #ifdef Q_OS_ANDROID -FM::FM(QObject *parent) : FMDB(parent), -sync(new Syncing(this)), -tag(Tagging::getInstance()) -#else -FM::FM(QObject *parent) : FMDB(parent), -sync(new Syncing(this)), -tag(Tagging::getInstance()), -dirLister(new KCoreDirLister(this)) + MAUIAndroid::checkRunTimePermissions(); #endif -{ - #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) - this->dirLister->setAutoUpdate(true); - connect(dirLister, static_cast(&KCoreDirLister::completed), [&](QUrl url) - { - qDebug()<< "PATH CONTENT READY" << url; - - FMH::PATH_CONTENT res; - FMH::MODEL_LIST content; - for(const auto &kfile : dirLister->items()) - { - qDebug() << kfile.url() << kfile.name() << kfile.isDir(); - content << FMH::MODEL{ {FMH::MODEL_KEY::LABEL, kfile.name()}, - {FMH::MODEL_KEY::NAME, kfile.name()}, - {FMH::MODEL_KEY::DATE, kfile.time(KFileItem::FileTimes::CreationTime).toString(Qt::TextDate)}, - {FMH::MODEL_KEY::MODIFIED, kfile.time(KFileItem::FileTimes::ModificationTime).toString(Qt::TextDate)}, - {FMH::MODEL_KEY::LAST_READ, kfile.time(KFileItem::FileTimes::AccessTime).toString(Qt::TextDate)}, - {FMH::MODEL_KEY::PATH, kfile.url().toString()}, - {FMH::MODEL_KEY::THUMBNAIL, kfile.localPath()}, - {FMH::MODEL_KEY::SYMLINK, kfile.linkDest()}, - {FMH::MODEL_KEY::IS_SYMLINK, QVariant(kfile.isLink()).toString()}, - {FMH::MODEL_KEY::HIDDEN, QVariant(kfile.isHidden()).toString()}, - {FMH::MODEL_KEY::IS_DIR, QVariant(kfile.isDir()).toString()}, - {FMH::MODEL_KEY::IS_FILE, QVariant(kfile.isFile()).toString()}, - {FMH::MODEL_KEY::WRITABLE, QVariant(kfile.isWritable()).toString()}, - {FMH::MODEL_KEY::READABLE, QVariant(kfile.isReadable()).toString()}, - {FMH::MODEL_KEY::EXECUTABLE, QVariant(kfile.isDesktopFile()).toString()}, - {FMH::MODEL_KEY::MIME, kfile.mimetype()}, - {FMH::MODEL_KEY::GROUP, kfile.group()}, - {FMH::MODEL_KEY::ICON, kfile.iconName()}, - {FMH::MODEL_KEY::SIZE, QString::number(kfile.size())}, - {FMH::MODEL_KEY::THUMBNAIL, kfile.mostLocalUrl().toString()}, + +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + this->dirLister->setAutoUpdate(true); + connect(dirLister, static_cast(&KCoreDirLister::completed), [&](QUrl url) + { + qDebug()<< "PATH CONTENT READY" << url; + + FMH::PATH_CONTENT res; + FMH::MODEL_LIST content; + for(const auto &kfile : dirLister->items()) + { + content << FMH::MODEL{ {FMH::MODEL_KEY::LABEL, kfile.name()}, + {FMH::MODEL_KEY::NAME, kfile.name()}, + {FMH::MODEL_KEY::DATE, kfile.time(KFileItem::FileTimes::CreationTime).toString(Qt::TextDate)}, + {FMH::MODEL_KEY::MODIFIED, kfile.time(KFileItem::FileTimes::ModificationTime).toString(Qt::TextDate)}, + {FMH::MODEL_KEY::LAST_READ, kfile.time(KFileItem::FileTimes::AccessTime).toString(Qt::TextDate)}, + {FMH::MODEL_KEY::PATH, kfile.mostLocalUrl().toString()}, + {FMH::MODEL_KEY::THUMBNAIL, kfile.localPath()}, + {FMH::MODEL_KEY::SYMLINK, kfile.linkDest()}, + {FMH::MODEL_KEY::IS_SYMLINK, QVariant(kfile.isLink()).toString()}, + {FMH::MODEL_KEY::HIDDEN, QVariant(kfile.isHidden()).toString()}, + {FMH::MODEL_KEY::IS_DIR, QVariant(kfile.isDir()).toString()}, + {FMH::MODEL_KEY::IS_FILE, QVariant(kfile.isFile()).toString()}, + {FMH::MODEL_KEY::WRITABLE, QVariant(kfile.isWritable()).toString()}, + {FMH::MODEL_KEY::READABLE, QVariant(kfile.isReadable()).toString()}, + {FMH::MODEL_KEY::EXECUTABLE, QVariant(kfile.isDesktopFile()).toString()}, + {FMH::MODEL_KEY::MIME, kfile.mimetype()}, + {FMH::MODEL_KEY::GROUP, kfile.group()}, + {FMH::MODEL_KEY::ICON, kfile.iconName()}, + {FMH::MODEL_KEY::SIZE, QString::number(kfile.size())}, + {FMH::MODEL_KEY::THUMBNAIL, kfile.mostLocalUrl().toString()}, {FMH::MODEL_KEY::OWNER, kfile.user()}, +// {FMH::MODEL_KEY::FAVORITE, QVariant(this->urlTagExists(kfile.mostLocalUrl().toString(), "fav")).toString()}, {FMH::MODEL_KEY::COUNT, kfile.isLocalFile() && kfile.isDir() ? QString::number(QDir(kfile.localPath()).count() - 2) : "0"} - }; - } - - res.path = url.toString(); - res.content = content; - - emit this->pathContentReady(res); - }); - - connect(dirLister, static_cast(&KCoreDirLister::itemsAdded), [&]() - { - qDebug()<< "MORE ITEMS WERE ADDED"; - emit this->pathContentChanged(dirLister->url()); - }); - - connect(dirLister, static_cast(&KCoreDirLister::newItems), [&]() - { - qDebug()<< "MORE NEW ITEMS WERE ADDED"; - emit this->pathContentChanged(dirLister->url()); - }); - - connect(dirLister, static_cast(&KCoreDirLister::itemsDeleted), [&]() - { - qDebug()<< "ITEMS WERE DELETED"; - dirLister->updateDirectory(dirLister->url()); - // emit this->pathContentChanged(dirLister->url()); // changes when dleted items are not that important? - }); - - connect(dirLister, static_cast > &items)>(&KCoreDirLister::refreshItems), [&]() - { - qDebug()<< "ITEMS WERE REFRESHED"; - dirLister->updateDirectory(dirLister->url()); - emit this->pathContentChanged(dirLister->url()); - - }); - #endif - connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QString &url) - { - emit this->cloudServerContentReady(list, url); - }); - - connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QString &url, const Syncing::SIGNAL_TYPE &signalType) - { - switch(signalType) - { - case Syncing::SIGNAL_TYPE::OPEN: - this->openUrl(item[FMH::MODEL_KEY::PATH]); - break; - - case Syncing::SIGNAL_TYPE::DOWNLOAD: - emit this->cloudItemReady(item, url); - break; - - case Syncing::SIGNAL_TYPE::COPY: - { - QVariantMap data; - for(auto key : item.keys()) - data.insert(FMH::MODEL_NAME[key], item[key]); - - this->copy(QVariantList {data}, this->sync->getCopyTo()); - break; - } - default: return; - } - }); - - connect(this->sync, &Syncing::error, [this](const QString &message) - { - emit this->warningMessage(message); - }); - - connect(this->sync, &Syncing::progress, [this](const int &percent) - { - emit this->loadProgress(percent); - }); - - connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QString &url) - { - emit this->newItem(dir, url); - }); - - connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QString &url) - { - emit this->newItem(item, url); - }); -} + }; + } -FM::~FM() {} + res.path = url; + res.content = content; + + emit this->pathContentReady(res); + }); + + connect(dirLister, static_cast(&KCoreDirLister::itemsAdded), [&]() + { + qDebug()<< "MORE ITEMS WERE ADDED"; + emit this->pathContentChanged(dirLister->url()); + }); + + connect(dirLister, static_cast(&KCoreDirLister::newItems), [&]() + { + qDebug()<< "MORE NEW ITEMS WERE ADDED"; + emit this->pathContentChanged(dirLister->url()); + }); + + connect(dirLister, static_cast(&KCoreDirLister::itemsDeleted), [&]() + { + qDebug()<< "ITEMS WERE DELETED"; + dirLister->updateDirectory(dirLister->url()); + // emit this->pathContentChanged(dirLister->url()); // changes when dleted items are not that important? + }); + + connect(dirLister, static_cast > &items)>(&KCoreDirLister::refreshItems), [&]() + { + qDebug()<< "ITEMS WERE REFRESHED"; + dirLister->updateDirectory(dirLister->url()); + emit this->pathContentChanged(dirLister->url()); + + }); +#endif -QVariantMap FM::toMap(const FMH::MODEL& model) -{ - return FMH::toMap(model); -} -FMH::MODEL FM::toModel(const QVariantMap& map) -{ - return FMH::toModel(map); -} +#ifdef COMPONENT_SYNCING + connect(this->sync, &Syncing::listReady, [this](const FMH::MODEL_LIST &list, const QUrl &url) + { + emit this->cloudServerContentReady(list, url); + }); + + connect(this->sync, &Syncing::itemReady, [this](const FMH::MODEL &item, const QUrl &url, const Syncing::SIGNAL_TYPE &signalType) + { + switch(signalType) + { + case Syncing::SIGNAL_TYPE::OPEN: + FMStatic::openUrl(item[FMH::MODEL_KEY::PATH]); + break; + + case Syncing::SIGNAL_TYPE::DOWNLOAD: + emit this->cloudItemReady(item, url); + break; + + case Syncing::SIGNAL_TYPE::COPY: + { + QVariantMap data; + for(auto key : item.keys()) + data.insert(FMH::MODEL_NAME[key], item[key]); + + this->copy(QVariantList {data}, this->sync->getCopyTo()); + break; + } + default: return; + } + }); + + connect(this->sync, &Syncing::error, [this](const QString &message) + { + emit this->warningMessage(message); + }); + + connect(this->sync, &Syncing::progress, [this](const int &percent) + { + emit this->loadProgress(percent); + }); + + connect(this->sync, &Syncing::dirCreated, [this](const FMH::MODEL &dir, const QUrl &url) + { + emit this->newItem(dir, url); + }); + + connect(this->sync, &Syncing::uploadReady, [this](const FMH::MODEL &item, const QUrl &url) + { + emit this->newItem(item, url); + }); +#endif + } -FMH::MODEL_LIST FM::packItems(const QStringList &items, const QString &type) -{ - FMH::MODEL_LIST data; - - for(const auto &path : items) - if(FMH::fileExists(path)) - { - auto model = FMH::getFileInfoModel(path); - model.insert(FMH::MODEL_KEY::TYPE, type); - data << model; - } - - return data; -} + FM::~FM() {} -QVariantList FM::get(const QString &queryTxt) -{ - QVariantList mapList; - - auto query = this->getQuery(queryTxt); - - if(query.exec()) - { - while(query.next()) - { - QVariantMap data; - for(auto key : FMH::MODEL_NAME.keys()) - if(query.record().indexOf(FMH::MODEL_NAME[key]) > -1) - data[FMH::MODEL_NAME[key]] = query.value(FMH::MODEL_NAME[key]).toString(); - - mapList<< data; - - } - - }else qDebug()<< query.lastError()<< query.lastQuery(); - - return mapList; -} + void FM::getPathContent(const QUrl& path, const bool &hidden, const bool &onlyDirs, const QStringList& filters, const QDirIterator::IteratorFlags &iteratorFlags) + { + qDebug()<< "Getting async path contents"; +#ifdef Q_OS_ANDROID + QFutureWatcher *watcher = new QFutureWatcher; + connect(watcher, &QFutureWatcher::finished, [this, watcher = std::move(watcher)]() + { + emit this->pathContentReady(watcher->future().result()); + watcher->deleteLater(); + }); + + QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT + { + FMH::PATH_CONTENT res; + res.path = path; + + FMH::MODEL_LIST content; + + if (FMStatic::isDir(path)) + { + QDir::Filters dirFilter; + + dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : + QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); + + if(hidden) + dirFilter = dirFilter | QDir::Hidden | QDir::System; + + QDirIterator it (path.toLocalFile(), filters, dirFilter, iteratorFlags); + while (it.hasNext()) + content << FMH::getFileInfoModel(QUrl::fromLocalFile(it.next())); + } + + res.content = content; + return res; + }); + watcher->setFuture(t1); +#else + this->dirLister->setShowingDotFiles(hidden); + this->dirLister->setDirOnlyMode(onlyDirs); + this->dirLister->setNameFilter(filters.join(" ")); -void FM::getPathContent(const QUrl& path, const bool &hidden, const bool &onlyDirs, const QStringList& filters, const QDirIterator::IteratorFlags &iteratorFlags) -{ - qDebug()<< "Getting async path contents"; - - #ifdef Q_OS_ANDROID - QFutureWatcher *watcher = new QFutureWatcher; - connect(watcher, &QFutureWatcher::finished, [this, watcher = std::move(watcher)]() - { - emit this->pathContentReady(watcher->future().result()); - watcher->deleteLater(); - }); - - QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT - { - FMH::PATH_CONTENT res; - res.path = path.toString(); - - FMH::MODEL_LIST content; - - if (FM::isDir(path)) - { - QDir::Filters dirFilter; - - dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : - QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); - - if(hidden) - dirFilter = dirFilter | QDir::Hidden | QDir::System; - - QDirIterator it (path.toLocalFile(), filters, dirFilter, iteratorFlags); - while (it.hasNext()) - content << FMH::getFileInfoModel(QUrl::fromLocalFile(it.next())); - } - - res.content = content; - return res; - }); - watcher->setFuture(t1); - #else - - this->dirLister->setShowingDotFiles(hidden); - this->dirLister->setDirOnlyMode(onlyDirs); - this->dirLister->setNameFilter(filters.join(" ")); - -// if(this->dirLister->url() == path) -// { -// this->dirLister->emitChanges(); -// return; -// } - - if(this->dirLister->openUrl(path)) - qDebug()<< "GETTING PATH CONTENT" << path; - - #endif - -} + // if(this->dirLister->url() == path) + // { + // this->dirLister->emitChanges(); + // return; + // } -void FM::getTrashContent() -{ - #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) - if(this->dirLister->openUrl(QUrl("trash://"))) - qDebug()<< "TRASH CONTENT"; - #endif -} + if(this->dirLister->openUrl(path)) + qDebug()<< "GETTING PATH CONTENT" << path; -FMH::MODEL_LIST FM::getAppsContent(const QString& path) -{ - FMH::MODEL_LIST res; - #if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID)) - QUrl __url(path); - - // if(__url.scheme() == FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::APPS_PATH]) - return MAUIKDE::getApps(QString(path).replace("apps://", "")); - - #endif - return res; -} +#endif -FMH::MODEL_LIST FM::getDefaultPaths() -{ - return packItems(FMH::defaultPaths, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]); -} + } -FMH::MODEL_LIST FM::getAppsPath() -{ - #ifdef Q_OS_ANDROID - return FMH::MODEL_LIST(); - #endif - - return FMH::MODEL_LIST - { - FMH::MODEL - { - {FMH::MODEL_KEY::ICON, "system-run"}, - {FMH::MODEL_KEY::LABEL, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::APPS_PATH]}, - {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::APPS_PATH]}, - {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]} - } - }; -} + FMH::MODEL_LIST FM::getAppsPath() + { +#ifdef Q_OS_ANDROID + return FMH::MODEL_LIST(); +#endif -FMH::MODEL_LIST FM::search(const QString& query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) -{ - FMH::MODEL_LIST content; - - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file. FM::search" << path; - return content; - } - - if (FM::isDir(path)) - { - QDir::Filters dirFilter; - - dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : - QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); - - if(hidden) - dirFilter = dirFilter | QDir::Hidden | QDir::System; - - QDirIterator it (path.toLocalFile(), filters, dirFilter, QDirIterator::Subdirectories); - while (it.hasNext()) - { - auto url = it.next(); - auto info = it.fileInfo(); - if(info.completeBaseName().contains(query, Qt::CaseInsensitive)) - { - content << FMH::getFileInfoModel(QUrl::fromLocalFile(url)); - } - } - }else - qWarning() << "Search path does not exists" << path; - - qDebug()<< content; - return content; -} + return FMH::MODEL_LIST + { + FMH::MODEL + { + {FMH::MODEL_KEY::ICON, "system-run"}, + {FMH::MODEL_KEY::LABEL, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::APPS_PATH]}, + {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::APPS_PATH]}, + {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]} + } + }; + } - FMH::MODEL_LIST FM::getDevices() - { - FMH::MODEL_LIST drives; + FMH::MODEL_LIST FM::getTags(const int &limit) + { + Q_UNUSED(limit); + FMH::MODEL_LIST data; +#ifdef COMPONENT_TAGGING + if(this->tag) + { + for(const auto &tag : this->tag->getUrlsTags(false)) + { + qDebug()<< "TAG << "<< tag; + const auto label = tag.toMap().value(TAG::KEYMAP[TAG::KEYS::TAG]).toString(); + data << FMH::MODEL + { + {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::TAGS_PATH]+label}, + {FMH::MODEL_KEY::ICON, "tag"}, + {FMH::MODEL_KEY::LABEL, label}, + {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::TAGS_PATH]} + }; + } + } +#endif - #if defined(Q_OS_ANDROID) - drives << packItems(MAUIAndroid::sdDirs(), FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::DRIVES_PATH]); - return drives; - #endif + return data; + } - return drives; - } + bool FM::getCloudServerContent(const QUrl &path, const QStringList &filters, const int &depth) + { +#ifdef COMPONENT_SYNCING + const auto __list = path.toString().replace("cloud:///", "/").split("/"); -FMH::MODEL_LIST FM::getTags(const int &limit) -{ - Q_UNUSED(limit); - - FMH::MODEL_LIST data; - - if(this->tag) - { - for(const auto &tag : this->tag->getUrlsTags(false)) - { - qDebug()<< "TAG << "<< tag; - const auto label = tag.toMap().value(TAG::KEYMAP[TAG::KEYS::TAG]).toString(); - data << FMH::MODEL - { - {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::TAGS_PATH]+label}, - {FMH::MODEL_KEY::ICON, "tag"}, - {FMH::MODEL_KEY::LABEL, label}, - {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::TAGS_PATH]} - }; - } - } - - return data; -} + if(__list.isEmpty() || __list.size() < 2) + { + qWarning()<< "Could not parse username to get cloud server content"; + return false; + } -bool FM::getCloudServerContent(const QString &path, const QStringList &filters, const int &depth) -{ - const auto __list = QString(path).replace("cloud://", "/").split("/"); - - if(__list.isEmpty() || __list.size() < 2) - { - qWarning()<< "Could not parse username to get cloud server content"; - return false; - } - - auto user = __list[1]; - auto data = this->get(QString("select * from clouds where user = '%1'").arg(user)); - - if(data.isEmpty()) - return false; - - auto map = data.first().toMap(); - - user = map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString(); - auto server = map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString(); - auto password = map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString(); - this->sync->setCredentials(server, user, password); - - this->sync->listContent(path, filters, depth); - return true; -} + auto user = __list[1]; +// auto data = this->get(QString("select * from clouds where user = '%1'").arg(user)); + QVariantList data; + if(data.isEmpty()) + return false; -FMH::MODEL_LIST FM::getCloudAccounts() -{ - auto accounts = this->get("select * from clouds"); - FMH::MODEL_LIST res; - for(const auto &account : accounts) - { - auto map = account.toMap(); - res << FMH::MODEL { - {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, - {FMH::MODEL_KEY::ICON, "folder-cloud"}, - {FMH::MODEL_KEY::LABEL, map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, - {FMH::MODEL_KEY::USER, map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, - {FMH::MODEL_KEY::SERVER, map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString()}, - {FMH::MODEL_KEY::PASSWORD, map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString()}, - {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::CLOUD_PATH]}}; - } - return res; -} + auto map = data.first().toMap(); + + user = map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString(); + auto server = map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString(); + auto password = map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString(); + this->sync->setCredentials(server, user, password); + + this->sync->listContent(path, filters, depth); + return true; +#else + return false; +#endif + } void FM::createCloudDir(const QString &path, const QString &name) { +#ifdef COMPONENT_SYNCING this->sync->createDir(path, name); +#endif } void FM::openCloudItem(const QVariantMap &item) { - qDebug()<< item; - FMH::MODEL data; - for(const auto &key : item.keys()) - data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); - - this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::OPEN); -} - -void FM::getCloudItem(const QVariantMap &item) -{ - qDebug()<< item; - FMH::MODEL data; - for(const auto &key : item.keys()) - data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); - - this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::DOWNLOAD); -} +#ifdef COMPONENT_SYNCING + FMH::MODEL data; + for(const auto &key : item.keys()) + data.insert(FMH::MODEL_NAME_KEY[key], item[key].toString()); -QVariantList FM::getCloudAccountsList() -{ - QVariantList res; - - const auto data = this->getCloudAccounts(); - for(const auto &item : data) - res << FM::toMap(item); - - return res; -} - -bool FM::addCloudAccount(const QString &server, const QString &user, const QString &password) -{ - const QVariantMap account = { - {FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER], server}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::USER], user}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD], password} - }; - - if(this->insert(FMH::TABLEMAP[FMH::TABLE::CLOUDS], account)) - { - emit this->cloudAccountInserted(user); - return true; - } - - return false; + this->sync->resolveFile(data, Syncing::SIGNAL_TYPE::OPEN); +#endif } -bool FM::removeCloudAccount(const QString &server, const QString &user) -{ - FMH::DB account = { - {FMH::MODEL_KEY::SERVER, server}, - {FMH::MODEL_KEY::USER, user}, - }; - - if(this->remove(FMH::TABLEMAP[FMH::TABLE::CLOUDS], account)) - { - emit this->cloudAccountRemoved(user); - return true; - } - - return false; +void FM::getCloudItem(const QVariantMap &item) +{ +#ifdef COMPONENT_SYNCING + this->sync->resolveFile(FMH::toModel(item), Syncing::SIGNAL_TYPE::DOWNLOAD); +#endif } QString FM::resolveUserCloudCachePath(const QString &server, const QString &user) { - return FMH::CloudCachePath+"opendesktop/"+user; + return FMH::CloudCachePath+"opendesktop/"+user; } QString FM::resolveLocalCloudPath(const QString& path) { - return QString(path).replace(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+this->sync->getUser(), ""); +#ifdef COMPONENT_SYNCING + return QString(path).replace(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+this->sync->getUser(), ""); +#else + return QString(); +#endif } FMH::MODEL_LIST FM::getTagContent(const QString &tag) { - FMH::MODEL_LIST content; - - for(const auto &data : this->tag->getUrls(tag, false)) - { - const auto url = QUrl(data.toMap().value(TAG::KEYMAP[TAG::KEYS::URL]).toString()); - if(FMH::fileExists(url)) - { - auto item = FMH::getFileInfoModel(url); - content << item; - } - } - - return content; -} - -bool FM::addTagToUrl(const QString tag, const QUrl& url) -{ - return this->tag->tagUrl(url.toString(), tag); -} - -QVariantMap FM::getDirInfo(const QUrl &path, const QString &type) -{ - return FMH::getDirInfo(path, type); -} - -QVariantMap FM::getFileInfo(const QUrl &path) -{ - return FMH::getFileInfo(path); -} - -bool FM::isDefaultPath(const QString &path) -{ - return FMH::defaultPaths.contains(path); -} + FMH::MODEL_LIST content; +#ifdef COMPONENT_TAGGING + for(const auto &data : this->tag->getUrls(tag, false)) + { + const auto url = QUrl(data.toMap()[TAG::KEYMAP[TAG::KEYS::URL]].toString()); + if(url.isLocalFile() && !FMH::fileExists(url)) + continue; -QUrl FM::parentDir(const QUrl &path) -{ - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file, FM::parentDir" << path; - return path; - } - - QDir dir(path.toLocalFile()); - dir.cdUp(); - return QUrl::fromLocalFile(dir.absolutePath()); + content << FMH::getFileInfoModel(url); + } +#endif + return content; } -bool FM::isDir(const QUrl &path) +FMH::MODEL_LIST FM::getUrlTags(const QUrl &url) { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file. FM::isDir" << path; - return false; - } - - QFileInfo file(path.toLocalFile()); - return file.isDir(); + FMH::MODEL_LIST content; + #ifdef COMPONENT_TAGGING + content = FMH::toModelList(this->tag->getUrlTags(url.toString(), false)); + #endif + return content; } -bool FM::isApp(const QString& path) +bool FM::urlTagExists(const QUrl& url, const QString tag) { - return /*QFileInfo(path).isExecutable() ||*/ path.endsWith(".desktop"); + #ifdef COMPONENT_TAGGING + return this->tag->urlTagExists(url.toString(), tag, false); + #endif } -bool FM::isCloud(const QUrl &path) +bool FM::addTagToUrl(const QString tag, const QUrl& url) { - return path.scheme() == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]; +#ifdef COMPONENT_TAGGING + return this->tag->tagUrl(url.toString(), tag); +#endif } -bool FM::fileExists(const QUrl &path) +bool FM::removeTagToUrl(const QString tag, const QUrl& url) { - return FMH::fileExists(path); + #ifdef COMPONENT_TAGGING + return this->tag->removeUrlTag(url.toString(), tag); + #endif } -QString FM::fileDir(const QUrl& path) +bool FM::cut(const QVariantList &data, const QUrl &where) { - QString res = path.toString(); - if(path.isLocalFile()) - { - const QFileInfo file(path.toLocalFile()); - if(file.isDir()) - res = path.toString(); - else - res = QUrl::fromLocalFile(file.dir().absolutePath()).toString(); - }else - qWarning()<< "The path is not a local one. FM::fileDir"; - - return res; -} - + FMH::MODEL_LIST items; -void FM::saveSettings(const QString &key, const QVariant &value, const QString &group) -{ - UTIL::saveSettings(key, value, group); -} - -QVariant FM::loadSettings(const QString &key, const QString &group, const QVariant &defaultValue) -{ - return UTIL::loadSettings(key, group, defaultValue); -} - -QString FM::formatSize(const int &size) -{ - QLocale locale; - return locale.formattedDataSize(size); -} - -QString FM::formatDate(const QString &dateStr, const QString &format, const QString &initFormat) -{ - QDateTime date; - if( initFormat.isEmpty() ) - date = QDateTime::fromString(dateStr, Qt::TextDate); - else - date = QDateTime::fromString(dateStr, initFormat); - return date.toString(format); -} + for(const auto &k : data) + items << FMH::toModel(k.toMap()); -QString FM::homePath() -{ - return FMH::HomePath; -} - -bool FM::cut(const QVariantList &data, const QString &where) -{ - FMH::MODEL_LIST items; - - for(const auto &k : data) - items << FM::toModel(k.toMap()); - - - for(const auto &item : items) - { - const auto path = item[FMH::MODEL_KEY::PATH]; - - if(this->isCloud(path)) - { - this->sync->setCopyTo(where); - this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); - - }else if(FMH::fileExists(path)) - { - #ifdef Q_OS_ANDROID - QFile file(QUrl(path).toLocalFile()); - file.rename(where+"/"+QFileInfo(QUrl(path).toLocalFile()).fileName()); - #else - auto job = KIO::move(QUrl(path), QUrl(where+"/"+FMH::getFileInfoModel(path)[FMH::MODEL_KEY::LABEL])); - job->start(); - #endif - } - } - - return true; -} + for(const auto &item : items) + { + const auto path = QUrl::fromUserInput(item[FMH::MODEL_KEY::PATH]); -bool FM::copy(const QVariantList &data, const QString &where) -{ - FMH::MODEL_LIST items; - for(const auto &k : data) - items << FM::toModel(k.toMap()); - - - QStringList cloudPaths; - for(const auto &item : items) - { - const auto path = item[FMH::MODEL_KEY::PATH]; - if(this->isDir(path)) - { - FM::copyPath(path, where+"/"+QFileInfo(path).fileName(), false); - - }else if(this->isCloud(path)) - { - this->sync->setCopyTo(where); - this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); - - }else if(FMH::fileExists(path)) - { - if(this->isCloud(where)) - cloudPaths << path; - else - FM::copyPath(path, where+"/"+FMH::getFileInfoModel(path)[FMH::MODEL_KEY::LABEL], false); - } - } - - if(!cloudPaths.isEmpty()) - { - qDebug()<<"UPLOAD QUEUE" << cloudPaths; - const auto firstPath = cloudPaths.takeLast(); - this->sync->setUploadQueue(cloudPaths); - - if(where.split("/").last().contains(".")) - { - QStringList whereList = where.split("/"); - whereList.removeLast(); - auto whereDir = whereList.join("/"); - qDebug()<< "Trying ot copy to cloud" << where << whereDir; - - this->sync->upload(this->resolveLocalCloudPath(whereDir), firstPath); - } else - this->sync->upload(this->resolveLocalCloudPath(where), firstPath); - } - - return true; -} - -bool FM::copyPath(QUrl sourceDir, QUrl destinationDir, bool overWriteDirectory) -{ - #ifdef Q_OS_ANDROID - QFileInfo fileInfo(sourceDir.toLocalFile()); - if(fileInfo.isFile()) - QFile::copy(sourceDir.toLocalFile(), destinationDir.toLocalFile()); - - QDir originDirectory(sourceDir.toLocalFile()); - - if (!originDirectory.exists()) - return false; - - QDir destinationDirectory(destinationDir.toLocalFile()); - - if(destinationDirectory.exists() && !overWriteDirectory) - return false; - else if(destinationDirectory.exists() && overWriteDirectory) - destinationDirectory.removeRecursively(); - - originDirectory.mkpath(destinationDir.toLocalFile()); - - foreach(QString directoryName, originDirectory.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) - { - QString destinationPath = destinationDir.toLocalFile() + "/" + directoryName; - originDirectory.mkpath(destinationPath); - copyPath(sourceDir.toLocalFile() + "/" + directoryName, destinationPath, overWriteDirectory); - } - - foreach (QString fileName, originDirectory.entryList(QDir::Files)) - { - QFile::copy(sourceDir.toLocalFile() + "/" + fileName, destinationDir.toLocalFile() + "/" + fileName); - } - - /*! Possible race-condition mitigation? */ - QDir finalDestination(destinationDir.toLocalFile()); - finalDestination.refresh(); - - if(finalDestination.exists()) - return true; - - return false; - #else - qDebug()<< "TRYING TO COPY" << sourceDir.toLocalFile() << destinationDir.toLocalFile(); - auto job = KIO::copy(QUrl(sourceDir), QUrl(destinationDir)); - job->start(); - return true; - #endif -} - -bool FM::removeFile(const QUrl &path) -{ - if(!path.isLocalFile()) - qWarning() << "URL recived is not a local file, FM::removeFile" << path; - - qDebug()<< "TRYING TO REMOVE FILE: " << path; - - #ifdef Q_OS_ANDROID - if(QFileInfo(path.toLocalFile()).isDir()) - return removeDir(path); - else return QFile(path.toLocalFile()).remove(); - #else - auto job = KIO::del(path); - job->start(); - return true; - #endif -} + if(FMStatic::isCloud(path.toString())) + { +#ifdef COMPONENT_SYNCING + this->sync->setCopyTo(where.toString()); + this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); +#endif -void FM::moveToTrash(const QUrl &path) -{ - if(!path.isLocalFile()) - qWarning() << "URL recived is not a local file, FM::moveToTrash" << path; - - #ifdef Q_OS_ANDROID - #else - auto job = KIO::trash(path); - job->start(); - #endif -} + }else + { +#ifdef Q_OS_ANDROID + QFile file(path.toLocalFile()); + file.rename(where.toString()+"/"+QFileInfo(path.toLocalFile()).fileName()); +#else + auto job = KIO::move(path, QUrl(where.toString()+"/"+FMH::getFileInfoModel(path)[FMH::MODEL_KEY::LABEL])); + job->start(); +#endif + } + } -void FM::emptyTrash() -{ - #ifdef Q_OS_ANDROID - #else - auto job = KIO::emptyTrash(); - job->start(); - #endif + return true; } -bool FM::removeDir(const QUrl &path) +bool FM::copy(const QVariantList &data, const QUrl &where) { - bool result = true; - QDir dir(path.toLocalFile()); - qDebug()<< "TRYING TO REMOVE DIR" << path << path.toLocalFile(); - if (dir.exists()) - { - Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) - { - if (info.isDir()) - { - result = removeDir(QUrl::fromLocalFile(info.absoluteFilePath())); - } - else - { - result = QFile::remove(info.absoluteFilePath()); - } - - if (!result) - { - return result; - } - } - result = dir.rmdir(path.toLocalFile()); - } - - return result; -} + qDebug() << "TRYING TO COPY" << data << where; -bool FM::rename(const QUrl &path, const QString &name) -{ - QFile file(path.toLocalFile()); - const auto url = QFileInfo(path.toLocalFile()).dir().absolutePath(); - return file.rename(url+"/"+name); -} + FMH::MODEL_LIST items; + for(const auto &k : data) + items << FMH::toModel(k.toMap()); -bool FM::createDir(const QUrl &path, const QString &name) -{ - QFileInfo dd(path.toLocalFile()); - return QDir(path.toLocalFile()).mkdir(name); -} -bool FM::createFile(const QUrl &path, const QString &name) -{ - QFile file(path.toLocalFile() + "/" + name); - - if(file.open(QIODevice::ReadWrite)) - { - file.close(); - return true; - } - - return false; -} + QStringList cloudPaths; + for(const auto &item : items) + { + const auto path = QUrl::fromUserInput(item[FMH::MODEL_KEY::PATH]); + if(FMStatic::isDir(path)) + { + FMStatic::copyPath(path, where.toString()+"/"+QFileInfo(path.toLocalFile()).fileName(), false); -bool FM::openUrl(const QString &url) -{ -#ifdef Q_OS_ANDROID - MAUIAndroid::openUrl(url); - return true; -#else - return QDesktopServices::openUrl(QUrl::fromUserInput(url)); + }else if(FMStatic::isCloud(path)) + { +#ifdef COMPONENT_SYNCING + this->sync->setCopyTo(where.toString()); + this->sync->resolveFile(item, Syncing::SIGNAL_TYPE::COPY); #endif -} + }else + { + if(FMStatic::isCloud(where)) + cloudPaths << path.toString(); + else + FMStatic::copyPath(path, where.toString()+"/"+FMH::getFileInfoModel(path)[FMH::MODEL_KEY::LABEL], false); + } + } -void FM::openLocation(const QStringList &urls) -{ - for(auto url : urls) - QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(url).dir().absolutePath())); -} +#ifdef COMPONENT_SYNCING + if(!cloudPaths.isEmpty()) + { + qDebug()<<"UPLOAD QUEUE" << cloudPaths; + const auto firstPath = cloudPaths.takeLast(); + this->sync->setUploadQueue(cloudPaths); -void FM::runApplication(const QString& exec) -{ - #if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID)) - return MAUIKDE::launchApp(exec); - #endif -} + if(where.toString().split("/").last().contains(".")) + { + QStringList whereList = where.toString().split("/"); + whereList.removeLast(); + auto whereDir = whereList.join("/"); + qDebug()<< "Trying ot copy to cloud" << where << whereDir; + + this->sync->upload(this->resolveLocalCloudPath(whereDir), firstPath); + } else + this->sync->upload(this->resolveLocalCloudPath(where.toString()), firstPath); + } +#endif -QVariantMap FM::dirConf(const QUrl &path) -{ - return FMH::dirConf(path); + return true; } -void FM::setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value) -{ - FMH::setDirConf(path, group, key, value); -} diff --git a/src/fm/fm.h b/src/fm/fm.h index e4e32f7..130a4e0 100644 --- a/src/fm/fm.h +++ b/src/fm/fm.h @@ -1,157 +1,88 @@ #ifndef FM_H #define FM_H #include #include #include #include #include #include -#include "fmdb.h" #include "fmh.h" +#include "fmstatic.h" #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif #if defined(Q_OS_ANDROID) #include "mauiandroid.h" #endif #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) class KCoreDirLister; #endif class Syncing; class Tagging; #ifdef STATIC_MAUIKIT -class FM : public FMDB +class FM : public QObject #else -class MAUIKIT_EXPORT FM : public FMDB +class MAUIKIT_EXPORT FM : public QObject #endif { Q_OBJECT public: -// static FM *getInstance(); Syncing *sync; FM(QObject *parent = nullptr); ~FM(); FMH::MODEL_LIST getTags(const int &limit = 5); FMH::MODEL_LIST getTagContent(const QString &tag); + FMH::MODEL_LIST getUrlTags(const QUrl &url); + bool urlTagExists(const QUrl& url, const QString tag); bool addTagToUrl(const QString tag, const QUrl &url); -// FMH::MODEL_LIST getBookmarks(); - + bool removeTagToUrl(const QString tag, const QUrl &url); + /** Syncing **/ - bool getCloudServerContent(const QString &server, const QStringList &filters= QStringList(), const int &depth = 0); - FMH::MODEL_LIST getCloudAccounts(); + bool getCloudServerContent(const QUrl &server, const QStringList &filters= QStringList(), const int &depth = 0); Q_INVOKABLE void createCloudDir(const QString &path, const QString &name); - - void getTrashContent(); - - /*** START STATIC METHODS ***/ - static FMH::MODEL_LIST search(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); - - static FMH::MODEL_LIST getDevices(); - static FMH::MODEL_LIST getDefaultPaths(); - static FMH::MODEL_LIST getAppsPath(); - - static FMH::MODEL_LIST packItems(const QStringList &items, const QString &type); - + void getPathContent(const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags); -// static FMH::MODEL_LIST getPathContent(const QString &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList(), const QDirIterator::IteratorFlags &iteratorFlags = QDirIterator::NoIteratorFlags); - static FMH::MODEL_LIST getAppsContent(const QString &path); + QString resolveLocalCloudPath(const QString &path); - static bool copyPath(QUrl sourceDir, QUrl destinationDir, bool overWriteDirectory); - static bool removeDir(const QUrl &path); - - static QString resolveUserCloudCachePath(const QString &server, const QString &user); - QString resolveLocalCloudPath(const QString &path); - - /** - * only keeping this two for legacy. shoudl be removed soon - * and instead use FMH::toMap, FMH::toModel, FMH::filterModel - **/ - static QVariantMap toMap(const FMH::MODEL &model); - static FMH::MODEL toModel(const QVariantMap &map); - - /*** END STATIC METHODS ***/ + static FMH::MODEL_LIST getAppsPath(); + static QString resolveUserCloudCachePath(const QString &server, const QString &user); private: Tagging *tag; #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) KCoreDirLister *dirLister; #endif -// static FM* instance; - QVariantList get(const QString &queryTxt); signals: - void cloudAccountInserted(QString user); - void cloudAccountRemoved(QString user); - - void cloudServerContentReady(FMH::MODEL_LIST list, const QString &url); - void cloudItemReady(FMH::MODEL item, QString path); //when a item is downloaded and ready - - void trashContentReady(FMH::MODEL_LIST list); + void cloudServerContentReady(FMH::MODEL_LIST list, const QUrl &url); + void cloudItemReady(FMH::MODEL item, QUrl path); //when a item is downloaded and ready void pathContentReady(FMH::PATH_CONTENT list); void pathContentChanged(QUrl path); void warningMessage(QString message); void loadProgress(int percent); void dirCreated(FMH::MODEL dir); - void newItem(FMH::MODEL item, QString path); // when a new item is created + void newItem(FMH::MODEL item, QUrl path); // when a new item is created public slots: - QVariantList getCloudAccountsList(); - bool addCloudAccount(const QString &server, const QString &user, const QString &password); - bool removeCloudAccount(const QString &server, const QString &user); void openCloudItem(const QVariantMap &item); void getCloudItem(const QVariantMap &item); - static QString formatSize(const int &size); - static QString formatDate(const QString &dateStr, const QString &format = QString("dd/MM/yyyy"), const QString &initFormat = QString()); - static QString homePath(); - static QUrl parentDir(const QUrl &path); - - static QVariantMap getDirInfo(const QUrl &path, const QString &type); - static QVariantMap getFileInfo(const QUrl &path); - - static bool isDefaultPath(const QString &path); - static bool isDir(const QUrl &path); - static bool isApp(const QString &path); - static bool isCloud(const QUrl &path); - static bool fileExists(const QUrl &path); - - /** - * if the url is a file path then it returns its directory - * and if it is a directory returns the same path - * */ - static QString fileDir(const QUrl &path); - - /* SETTINGS */ - static void saveSettings(const QString &key, const QVariant &value, const QString &group); - static QVariant loadSettings(const QString &key, const QString &group, const QVariant &defaultValue); - - static QVariantMap dirConf(const QUrl &path); - static void setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value); - /* ACTIONS */ - bool copy(const QVariantList &data, const QString &where); - bool cut(const QVariantList &data, const QString &where); - static bool removeFile(const QUrl &path); - void moveToTrash(const QUrl &path); - static void emptyTrash(); - static bool rename(const QUrl &path, const QString &name); - static bool createDir(const QUrl &path, const QString &name); - static bool createFile(const QUrl &path, const QString &name); - - static bool openUrl(const QString &url); - static void openLocation(const QStringList &urls); - static void runApplication(const QString &exec); + bool copy(const QVariantList &data, const QUrl &where); + bool cut(const QVariantList &data, const QUrl &where); + + friend class FMStatic; }; #endif // FM_H diff --git a/src/fm/fmh.h b/src/fm/fmh.h deleted file mode 100644 index befbbe5..0000000 --- a/src/fm/fmh.h +++ /dev/null @@ -1,1133 +0,0 @@ -/* - * Copyright 2018 Camilo Higuita - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2, 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 Library 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. - */ - -#ifndef FMH_H -#define FMH_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(Q_OS_ANDROID) -#include "mauiandroid.h" -#elif defined(Q_OS_LINUX) -#include -#include -#include -#include -#endif - -namespace FMH -{ - - inline bool isAndroid() - { - #if defined(Q_OS_ANDROID) - return true; - #elif defined(Q_OS_LINUX) - return false; - #elif defined(Q_OS_WIN32) - return false; - #elif defined(Q_OS_WIN64) - return false; - #elif defined(Q_OS_MACOS) - return false; - #elif defined(Q_OS_IOS) - return false; - #elif defined(Q_OS_HAIKU) - return false; - #endif - } - - enum FILTER_TYPE : int - { - AUDIO, - VIDEO, - TEXT, - IMAGE, - DOCUMENT, - NONE - }; - - inline QStringList getMimeTypeSuffixes(const QString &hint) - { - QMimeDatabase mimedb; - return mimedb.mimeTypeForName(hint).suffixes(); - } - - static const QHash FILTER_LIST = - { - {FILTER_TYPE::AUDIO, QStringList {"*.mp3", "*.mp4", "*.wav", "*.ogg", "*.flac"}}, - {FILTER_TYPE::VIDEO, QStringList {"*.mp4", "*.mkv", "*.mov", "*.avi", "*.flv"}}, - {FILTER_TYPE::TEXT, QStringList {"*.txt", "*.cpp", "*.js", "*.doc", "*.h", "*.json", "*.html", "*.rtf", "*.qml", "*.py", "*.go"}}, - {FILTER_TYPE::DOCUMENT, QStringList {"*.pdf", "*.txt", "*.cbz", "*.cbr", "*.epub", "*.cbt", "*.cba", "*.cb7"}}, - {FILTER_TYPE::IMAGE, QStringList {"*.png", "*.jpg", "*.jpeg", "*.gif", "*.svg", "*.bmp"}}, - {FILTER_TYPE::NONE, QStringList()} - }; - - enum MODEL_KEY : int - { - ICON, - LABEL, - PATH, - URL, - TYPE, - GROUP, - OWNER, - SUFFIX, - NAME, - DATE, - SIZE, - MODIFIED, - MIME, - TAG, - PERMISSIONS, - THUMBNAIL, - THUMBNAIL_1, - THUMBNAIL_2, - THUMBNAIL_3, - HIDDEN, - ICONSIZE, - DETAILVIEW, - SHOWTHUMBNAIL, - SHOWTERMINAL, - COUNT, - SORTBY, - USER, - PASSWORD, - SERVER, - FOLDERSFIRST, - VIEWTYPE, - ADDDATE, - FAV, - FAVORITE, - COLOR, - RATE, - FORMAT, - PLACE, - LOCATION, - ALBUM, - ARTIST, - TRACK, - DURATION, - ARTWORK, - PLAYLIST, - LYRICS, - WIKI, - MOOD, - SOURCETYPE, - GENRE, - NOTE, - COMMENT, - CONTEXT, - SOURCE, - TITLE, - ID, - RELEASEDATE, - LICENSE, - DESCRIPTION, - BOOKMARK, - ACCOUNT, - ACCOUNTTYPE, - VERSION, - DOMAIN, - CATEGORY, - CONTENT, - PIN, - IMG, - PREVIEW, - LINK, - STAMP, - BOOK, - - /** ccdav keys **/ - N, - PHOTO, - GENDER, - ADR, - ADR_2, - ADR_3, - EMAIL, - EMAIL_2, - EMAIL_3, - LANG, - NICKNAME, - ORG, - PROFILE, - TZ, - TEL, - TEL_2, - TEL_3, - IM, - - /** other keys **/ - CITY, - STATE, - COUNTRY, - - /** keys from opendesktop store **/ - PACKAGE_ARCH, - PACKAGE_TYPE, - GPG_FINGERPRINT, - GPG_SIGNATURE, - PACKAGE_NAME, - PRICE, - REPOSITORY, - TAGS, - WAY, - PIC, - SMALL_PIC, - CHANGED, - COMMENTS, - CREATED, - DETAIL_PAGE, - DETAILS, - TOTAL_DOWNLOADS, - GHNS_EXCLUDED, - LANGUAGE, - PERSON_ID, - SCORE, - SUMMARY, - TYPE_ID, - TYPE_NAME, - XDG_TYPE, - - //file props - SYMLINK, - IS_SYMLINK, - IS_DIR, - IS_FILE, - IS_REMOTE, - EXECUTABLE, - READABLE, - WRITABLE, - LAST_READ, - - }; - - static const QHash MODEL_NAME = - { - {MODEL_KEY::ICON, "icon"}, - {MODEL_KEY::LABEL, "label"}, - {MODEL_KEY::PATH, "path"}, - {MODEL_KEY::URL, "url"}, - {MODEL_KEY::TYPE, "type"}, - {MODEL_KEY::GROUP, "group"}, - {MODEL_KEY::OWNER, "owner"}, - {MODEL_KEY::SUFFIX, "suffix"}, - {MODEL_KEY::NAME, "name"}, - {MODEL_KEY::DATE, "date"}, - {MODEL_KEY::MODIFIED, "modified"}, - {MODEL_KEY::MIME, "mime"}, - {MODEL_KEY::SIZE, "size"}, - {MODEL_KEY::TAG, "tag"}, - {MODEL_KEY::PERMISSIONS, "permissions"}, - {MODEL_KEY::THUMBNAIL, "thumbnail"}, - {MODEL_KEY::THUMBNAIL_1, "thumbnail_1"}, - {MODEL_KEY::THUMBNAIL_2, "thumbnail_2"}, - {MODEL_KEY::THUMBNAIL_3, "thumbnail_3"}, - {MODEL_KEY::ICONSIZE, "iconsize"}, - {MODEL_KEY::HIDDEN, "hidden"}, - {MODEL_KEY::DETAILVIEW, "detailview"}, - {MODEL_KEY::SHOWTERMINAL, "showterminal"}, - {MODEL_KEY::SHOWTHUMBNAIL, "showthumbnail"}, - {MODEL_KEY::COUNT, "count"}, - {MODEL_KEY::SORTBY, "sortby"}, - {MODEL_KEY::USER, "user"}, - {MODEL_KEY::PASSWORD, "password"}, - {MODEL_KEY::SERVER, "server"}, - {MODEL_KEY::FOLDERSFIRST, "foldersfirst"}, - {MODEL_KEY::VIEWTYPE, "viewtype"}, - {MODEL_KEY::ADDDATE, "adddate"}, - {MODEL_KEY::FAV, "fav"}, - {MODEL_KEY::FAVORITE, "favorite"}, - {MODEL_KEY::COLOR, "color"}, - {MODEL_KEY::RATE, "rate"}, - {MODEL_KEY::FORMAT, "format"}, - {MODEL_KEY::PLACE, "place"}, - {MODEL_KEY::LOCATION, "location"}, - {MODEL_KEY::ALBUM, "album"}, - {MODEL_KEY::DURATION, "duration"}, - {MODEL_KEY::RELEASEDATE, "releasedate"}, - {MODEL_KEY::ARTIST, "artist"}, - {MODEL_KEY::LYRICS, "lyrics"}, - {MODEL_KEY::TRACK, "track"}, - {MODEL_KEY::GENRE, "genre"}, - {MODEL_KEY::WIKI, "wiki"}, - {MODEL_KEY::CONTEXT, "context"}, - {MODEL_KEY::SOURCETYPE, "sourcetype"}, - {MODEL_KEY::ARTWORK, "artwork"}, - {MODEL_KEY::NOTE, "note"}, - {MODEL_KEY::MOOD, "mood"}, - {MODEL_KEY::COMMENT, "comment"}, - {MODEL_KEY::PLAYLIST, "playlist"}, - {MODEL_KEY::SOURCE, "source"}, - {MODEL_KEY::TITLE, "title"}, - {MODEL_KEY::ID, "id"}, - {MODEL_KEY::LICENSE, "license"}, - {MODEL_KEY::DESCRIPTION, "description"}, - {MODEL_KEY::BOOKMARK, "bookmark"}, - {MODEL_KEY::ACCOUNT, "account"}, - {MODEL_KEY::ACCOUNTTYPE, "accounttype"}, - {MODEL_KEY::VERSION, "version"}, - {MODEL_KEY::DOMAIN, "domain"}, - {MODEL_KEY::CATEGORY, "category"}, - {MODEL_KEY::CONTENT, "content"}, - {MODEL_KEY::PIN, "pin"}, - {MODEL_KEY::IMG, "img"}, - {MODEL_KEY::PREVIEW, "preview"}, - {MODEL_KEY::LINK, "link"}, - {MODEL_KEY::STAMP, "stamp"}, - {MODEL_KEY::BOOK, "book"}, - - /** ccdav keys **/ - {MODEL_KEY::N, "n"}, - {MODEL_KEY::IM, "im"}, - {MODEL_KEY::PHOTO, "photo"}, - {MODEL_KEY::GENDER, "gender"}, - {MODEL_KEY::ADR, "adr"}, - {MODEL_KEY::ADR_2, "adr2"}, - {MODEL_KEY::ADR_3, "adr3"}, - {MODEL_KEY::EMAIL, "email"}, - {MODEL_KEY::EMAIL_2, "email2"}, - {MODEL_KEY::EMAIL_3, "email3"}, - {MODEL_KEY::LANG, "lang"}, - {MODEL_KEY::NICKNAME, "nickname"}, - {MODEL_KEY::ORG, "org"}, - {MODEL_KEY::PROFILE, "profile"}, - {MODEL_KEY::TZ, "tz"}, - {MODEL_KEY::TEL, "tel"}, - {MODEL_KEY::TEL_2, "tel2"}, - {MODEL_KEY::TEL_3, "tel3"}, - - {MODEL_KEY::CITY, "city"}, - {MODEL_KEY::STATE, "state"}, - {MODEL_KEY::COUNTRY, "country"}, - - // opendesktop keys - {MODEL_KEY::PACKAGE_ARCH, "packagearch"}, - {MODEL_KEY::PACKAGE_TYPE, "packagetype"}, - {MODEL_KEY::GPG_FINGERPRINT, "gpgfingerprint"}, - {MODEL_KEY::GPG_SIGNATURE, "gpgsignature"}, - {MODEL_KEY::PACKAGE_NAME, "packagename"}, - {MODEL_KEY::PRICE, "price"}, - {MODEL_KEY::REPOSITORY, "repository"}, - {MODEL_KEY::TAGS, "tags"}, - {MODEL_KEY::WAY, "way"}, - {MODEL_KEY::PIC, "pic"}, - {MODEL_KEY::SMALL_PIC, "smallpic"}, - {MODEL_KEY::CHANGED, "changed"}, - {MODEL_KEY::COMMENTS, "comments"}, - {MODEL_KEY::CREATED, "created"}, - {MODEL_KEY::DETAIL_PAGE, "detailpage"}, - {MODEL_KEY::DETAILS, "details"}, - {MODEL_KEY::TOTAL_DOWNLOADS, "totaldownloads"}, - {MODEL_KEY::GHNS_EXCLUDED, "ghnsexcluded"}, - {MODEL_KEY::LANGUAGE, "language"}, - {MODEL_KEY::SCORE, "score"}, - {MODEL_KEY::SUMMARY, "summary"}, - {MODEL_KEY::TYPE_ID, "typeid"}, - {MODEL_KEY::TYPE_NAME, "typename"}, - {MODEL_KEY::XDG_TYPE, "xdgtype"}, - -//file props - {MODEL_KEY::SYMLINK, "symlink"}, - {MODEL_KEY::IS_SYMLINK, "issymlink"}, - {MODEL_KEY::LAST_READ, "lastread"}, - {MODEL_KEY::READABLE, "readable"}, - {MODEL_KEY::WRITABLE, "writeable"}, - {MODEL_KEY::IS_DIR, "isdir"}, - {MODEL_KEY::IS_FILE, "isfile"}, - {MODEL_KEY::IS_REMOTE, "isremote"}, - {MODEL_KEY::EXECUTABLE, "executable"} - - }; - - static const QHash MODEL_NAME_KEY = - { - {MODEL_NAME[MODEL_KEY::ICON], MODEL_KEY::ICON}, - {MODEL_NAME[MODEL_KEY::LABEL], MODEL_KEY::LABEL}, - {MODEL_NAME[MODEL_KEY::PATH], MODEL_KEY::PATH}, - {MODEL_NAME[MODEL_KEY::URL], MODEL_KEY::URL}, - {MODEL_NAME[MODEL_KEY::TYPE], MODEL_KEY::TYPE}, - {MODEL_NAME[MODEL_KEY::GROUP], MODEL_KEY::GROUP}, - {MODEL_NAME[MODEL_KEY::OWNER], MODEL_KEY::OWNER}, - {MODEL_NAME[MODEL_KEY::SUFFIX], MODEL_KEY::SUFFIX}, - {MODEL_NAME[MODEL_KEY::NAME], MODEL_KEY::NAME}, - {MODEL_NAME[MODEL_KEY::DATE], MODEL_KEY::DATE}, - {MODEL_NAME[MODEL_KEY::MODIFIED], MODEL_KEY::MODIFIED}, - {MODEL_NAME[MODEL_KEY::MIME], MODEL_KEY::MIME}, - {MODEL_NAME[MODEL_KEY::SIZE], MODEL_KEY::SIZE,}, - {MODEL_NAME[MODEL_KEY::TAG], MODEL_KEY::TAG}, - {MODEL_NAME[MODEL_KEY::PERMISSIONS], MODEL_KEY::PERMISSIONS}, - {MODEL_NAME[MODEL_KEY::THUMBNAIL], MODEL_KEY::THUMBNAIL}, - {MODEL_NAME[MODEL_KEY::THUMBNAIL_1], MODEL_KEY::THUMBNAIL_1}, - {MODEL_NAME[MODEL_KEY::THUMBNAIL_2], MODEL_KEY::THUMBNAIL_2}, - {MODEL_NAME[MODEL_KEY::THUMBNAIL_3], MODEL_KEY::THUMBNAIL_3}, - {MODEL_NAME[MODEL_KEY::ICONSIZE], MODEL_KEY::ICONSIZE}, - {MODEL_NAME[MODEL_KEY::HIDDEN], MODEL_KEY::HIDDEN}, - {MODEL_NAME[MODEL_KEY::DETAILVIEW], MODEL_KEY::DETAILVIEW}, - {MODEL_NAME[MODEL_KEY::SHOWTERMINAL], MODEL_KEY::SHOWTERMINAL}, - {MODEL_NAME[MODEL_KEY::SHOWTHUMBNAIL], MODEL_KEY::SHOWTHUMBNAIL}, - {MODEL_NAME[MODEL_KEY::COUNT], MODEL_KEY::COUNT}, - {MODEL_NAME[MODEL_KEY::SORTBY], MODEL_KEY::SORTBY}, - {MODEL_NAME[MODEL_KEY::USER], MODEL_KEY::USER}, - {MODEL_NAME[MODEL_KEY::PASSWORD], MODEL_KEY::PASSWORD}, - {MODEL_NAME[MODEL_KEY::SERVER], MODEL_KEY::SERVER}, - {MODEL_NAME[MODEL_KEY::VIEWTYPE], MODEL_KEY::VIEWTYPE}, - {MODEL_NAME[MODEL_KEY::ADDDATE], MODEL_KEY::ADDDATE}, - {MODEL_NAME[MODEL_KEY::FAV], MODEL_KEY::FAV}, - {MODEL_NAME[MODEL_KEY::FAVORITE], MODEL_KEY::FAVORITE}, - {MODEL_NAME[MODEL_KEY::COLOR], MODEL_KEY::COLOR}, - {MODEL_NAME[MODEL_KEY::RATE], MODEL_KEY::RATE}, - {MODEL_NAME[MODEL_KEY::FORMAT], MODEL_KEY::FORMAT}, - {MODEL_NAME[MODEL_KEY::PLACE], MODEL_KEY::PLACE}, - {MODEL_NAME[MODEL_KEY::LOCATION], MODEL_KEY::LOCATION}, - {MODEL_NAME[MODEL_KEY::ALBUM], MODEL_KEY::ALBUM}, - {MODEL_NAME[MODEL_KEY::ARTIST], MODEL_KEY::ARTIST}, - {MODEL_NAME[MODEL_KEY::DURATION], MODEL_KEY::DURATION}, - {MODEL_NAME[MODEL_KEY::TRACK], MODEL_KEY::TRACK}, - {MODEL_NAME[MODEL_KEY::GENRE], MODEL_KEY::GENRE}, - {MODEL_NAME[MODEL_KEY::LYRICS], MODEL_KEY::LYRICS}, - {MODEL_NAME[MODEL_KEY::RELEASEDATE], MODEL_KEY::RELEASEDATE}, - {MODEL_NAME[MODEL_KEY::FORMAT], MODEL_KEY::FORMAT}, - {MODEL_NAME[MODEL_KEY::WIKI], MODEL_KEY::WIKI}, - {MODEL_NAME[MODEL_KEY::SOURCETYPE], MODEL_KEY::SOURCETYPE}, - {MODEL_NAME[MODEL_KEY::ARTWORK], MODEL_KEY::ARTWORK}, - {MODEL_NAME[MODEL_KEY::NOTE], MODEL_KEY::NOTE}, - {MODEL_NAME[MODEL_KEY::MOOD], MODEL_KEY::MOOD}, - {MODEL_NAME[MODEL_KEY::COMMENT], MODEL_KEY::COMMENT}, - {MODEL_NAME[MODEL_KEY::CONTEXT], MODEL_KEY::CONTEXT}, - {MODEL_NAME[MODEL_KEY::SOURCE], MODEL_KEY::SOURCE}, - {MODEL_NAME[MODEL_KEY::TITLE], MODEL_KEY::TITLE}, - {MODEL_NAME[MODEL_KEY::ID], MODEL_KEY::ID}, - {MODEL_NAME[MODEL_KEY::LICENSE], MODEL_KEY::LICENSE}, - {MODEL_NAME[MODEL_KEY::DESCRIPTION], MODEL_KEY::DESCRIPTION}, - {MODEL_NAME[MODEL_KEY::BOOKMARK], MODEL_KEY::BOOKMARK}, - {MODEL_NAME[MODEL_KEY::ACCOUNT], MODEL_KEY::ACCOUNT}, - {MODEL_NAME[MODEL_KEY::ACCOUNTTYPE], MODEL_KEY::ACCOUNTTYPE}, - {MODEL_NAME[MODEL_KEY::VERSION], MODEL_KEY::VERSION}, - {MODEL_NAME[MODEL_KEY::DOMAIN], MODEL_KEY::DOMAIN}, - {MODEL_NAME[MODEL_KEY::CATEGORY], MODEL_KEY::CATEGORY}, - {MODEL_NAME[MODEL_KEY::CONTENT], MODEL_KEY::CONTENT}, - {MODEL_NAME[MODEL_KEY::PIN], MODEL_KEY::PIN}, - {MODEL_NAME[MODEL_KEY::IMG], MODEL_KEY::IMG}, - {MODEL_NAME[MODEL_KEY::PREVIEW], MODEL_KEY::PREVIEW}, - {MODEL_NAME[MODEL_KEY::LINK], MODEL_KEY::LINK}, - {MODEL_NAME[MODEL_KEY::STAMP], MODEL_KEY::STAMP}, - {MODEL_NAME[MODEL_KEY::BOOK], MODEL_KEY::BOOK}, - - /** ccdav keys **/ - {MODEL_NAME[MODEL_KEY::N], MODEL_KEY::N}, - {MODEL_NAME[MODEL_KEY::IM], MODEL_KEY::IM}, - {MODEL_NAME[MODEL_KEY::PHOTO], MODEL_KEY::PHOTO}, - {MODEL_NAME[MODEL_KEY::GENDER], MODEL_KEY::GENDER}, - {MODEL_NAME[MODEL_KEY::ADR], MODEL_KEY::ADR}, - {MODEL_NAME[MODEL_KEY::ADR_2], MODEL_KEY::ADR_2}, - {MODEL_NAME[MODEL_KEY::ADR_3], MODEL_KEY::ADR_3}, - {MODEL_NAME[MODEL_KEY::EMAIL], MODEL_KEY::EMAIL}, - {MODEL_NAME[MODEL_KEY::EMAIL_2], MODEL_KEY::EMAIL_2}, - {MODEL_NAME[MODEL_KEY::EMAIL_3], MODEL_KEY::EMAIL_3}, - {MODEL_NAME[MODEL_KEY::LANG], MODEL_KEY::LANG}, - {MODEL_NAME[MODEL_KEY::NICKNAME], MODEL_KEY::NICKNAME}, - {MODEL_NAME[MODEL_KEY::ORG], MODEL_KEY::ORG}, - {MODEL_NAME[MODEL_KEY::PROFILE], MODEL_KEY::PROFILE}, - {MODEL_NAME[MODEL_KEY::TZ], MODEL_KEY::TZ}, - {MODEL_NAME[MODEL_KEY::TEL], MODEL_KEY::TEL}, - {MODEL_NAME[MODEL_KEY::TEL_2], MODEL_KEY::TEL_2}, - {MODEL_NAME[MODEL_KEY::TEL_3], MODEL_KEY::TEL_3}, - - {MODEL_NAME[MODEL_KEY::CITY], MODEL_KEY::CITY}, - {MODEL_NAME[MODEL_KEY::STATE], MODEL_KEY::STATE}, - {MODEL_NAME[MODEL_KEY::COUNTRY], MODEL_KEY::COUNTRY}, - - //opendesktop store keys - {MODEL_NAME[MODEL_KEY::PACKAGE_ARCH], MODEL_KEY::PACKAGE_ARCH}, - {MODEL_NAME[MODEL_KEY::PACKAGE_TYPE], MODEL_KEY::PACKAGE_TYPE}, - {MODEL_NAME[MODEL_KEY::GPG_FINGERPRINT], MODEL_KEY::GPG_FINGERPRINT}, - {MODEL_NAME[MODEL_KEY::GPG_SIGNATURE], MODEL_KEY::GPG_SIGNATURE}, - {MODEL_NAME[MODEL_KEY::PACKAGE_NAME], MODEL_KEY::PACKAGE_NAME}, - {MODEL_NAME[MODEL_KEY::PRICE], MODEL_KEY::PRICE}, - {MODEL_NAME[MODEL_KEY::REPOSITORY], MODEL_KEY::REPOSITORY}, - {MODEL_NAME[MODEL_KEY::TAGS], MODEL_KEY::TAGS}, - {MODEL_NAME[MODEL_KEY::WAY], MODEL_KEY::WAY}, - {MODEL_NAME[MODEL_KEY::PIC], MODEL_KEY::PIC}, - {MODEL_NAME[MODEL_KEY::SMALL_PIC], MODEL_KEY::SMALL_PIC}, - {MODEL_NAME[MODEL_KEY::CHANGED], MODEL_KEY::CHANGED}, - {MODEL_NAME[MODEL_KEY::COMMENTS], MODEL_KEY::COMMENTS}, - {MODEL_NAME[MODEL_KEY::CREATED], MODEL_KEY::CREATED}, - {MODEL_NAME[MODEL_KEY::DETAIL_PAGE], MODEL_KEY::DETAIL_PAGE}, - {MODEL_NAME[MODEL_KEY::DETAILS], MODEL_KEY::DETAILS}, - {MODEL_NAME[MODEL_KEY::TOTAL_DOWNLOADS], MODEL_KEY::TOTAL_DOWNLOADS}, - {MODEL_NAME[MODEL_KEY::GHNS_EXCLUDED], MODEL_KEY::GHNS_EXCLUDED}, - {MODEL_NAME[MODEL_KEY::LANGUAGE], MODEL_KEY::LANGUAGE}, - {MODEL_NAME[MODEL_KEY::PERSON_ID], MODEL_KEY::PERSON_ID}, - {MODEL_NAME[MODEL_KEY::SCORE], MODEL_KEY::SCORE}, - {MODEL_NAME[MODEL_KEY::SUMMARY], MODEL_KEY::SUMMARY}, - {MODEL_NAME[MODEL_KEY::TYPE_ID], MODEL_KEY::TYPE_ID}, - {MODEL_NAME[MODEL_KEY::TYPE_NAME], MODEL_KEY::TYPE_NAME}, - {MODEL_NAME[MODEL_KEY::XDG_TYPE], MODEL_KEY::XDG_TYPE}, - - //file props - {MODEL_NAME[MODEL_KEY::SYMLINK], MODEL_KEY::SYMLINK}, - {MODEL_NAME[MODEL_KEY::IS_SYMLINK], MODEL_KEY::IS_SYMLINK}, - {MODEL_NAME[MODEL_KEY::LAST_READ], MODEL_KEY::LAST_READ}, - {MODEL_NAME[MODEL_KEY::READABLE], MODEL_KEY::READABLE}, - {MODEL_NAME[MODEL_KEY::WRITABLE], MODEL_KEY::WRITABLE}, - {MODEL_NAME[MODEL_KEY::IS_DIR], MODEL_KEY::IS_DIR}, - {MODEL_NAME[MODEL_KEY::IS_FILE], MODEL_KEY::IS_FILE}, - {MODEL_NAME[MODEL_KEY::IS_REMOTE], MODEL_KEY::IS_REMOTE}, - {MODEL_NAME[MODEL_KEY::EXECUTABLE], MODEL_KEY::EXECUTABLE} - }; - - typedef QHash MODEL; - typedef QVector MODEL_LIST; - - - static const inline QVariantMap toMap(const FMH::MODEL& model) - { - QVariantMap map; - for(const auto &key : model.keys()) - map.insert(FMH::MODEL_NAME[key], model[key]); - - return map; - } - - static const inline FMH::MODEL toModel(const QVariantMap& map) - { - FMH::MODEL model; - for(const auto &key : map.keys()) - model.insert(FMH::MODEL_NAME_KEY[key], map[key].toString()); - - return model; - } - - static const inline FMH::MODEL filterModel(const FMH::MODEL &model, const QVector &keys) - { - FMH::MODEL res; - for(const auto &key : keys) - if(model.contains(key)) - res[key] = model[key]; - - return res; - } - - struct PATH_CONTENT - { - QString path; - FMH::MODEL_LIST content; - }; - -#ifdef Q_OS_ANDROID - enum PATHTYPE_KEY : int - { - PLACES_PATH, - REMOTE_PATH, - DRIVES_PATH, - REMOVABLE_PATH, - TAGS_PATH, - UNKNOWN_TYPE, - APPS_PATH, - TRASH_PATH, - SEARCH_PATH, - CLOUD_PATH, - FISH_PATH, - MTP_PATH - }; -#else - enum PATHTYPE_KEY : int - { - PLACES_PATH = KFilePlacesModel::GroupType::PlacesType, - REMOTE_PATH = KFilePlacesModel::GroupType::RemoteType, - DRIVES_PATH = KFilePlacesModel::GroupType::DevicesType, - REMOVABLE_PATH = KFilePlacesModel::GroupType::RemovableDevicesType, - TAGS_PATH = KFilePlacesModel::GroupType::TagsType, - UNKNOWN_TYPE = KFilePlacesModel::GroupType::UnknownType, - APPS_PATH = 9, - TRASH_PATH = 10, - SEARCH_PATH = 11, - CLOUD_PATH = 12, - FISH_PATH = 13, - MTP_PATH = 14, - }; -#endif - static const QHash PATHTYPE_SCHEME = - { - {PATHTYPE_KEY::PLACES_PATH, "file"}, - {PATHTYPE_KEY::DRIVES_PATH, "drives"}, - {PATHTYPE_KEY::APPS_PATH, "apps"}, - {PATHTYPE_KEY::REMOTE_PATH, "remote"}, - {PATHTYPE_KEY::REMOVABLE_PATH, "removable"}, - {PATHTYPE_KEY::UNKNOWN_TYPE, "Unkown"}, - {PATHTYPE_KEY::TRASH_PATH, "trash"}, - {PATHTYPE_KEY::TAGS_PATH, "tags"}, - {PATHTYPE_KEY::SEARCH_PATH, "search"}, - {PATHTYPE_KEY::CLOUD_PATH, "cloud"}, - {PATHTYPE_KEY::FISH_PATH, "fish"}, - {PATHTYPE_KEY::MTP_PATH, "mtp"} - }; - - static const QHash PATHTYPE_URI = - { - {PATHTYPE_KEY::PLACES_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::PLACES_PATH] + "://"}, - {PATHTYPE_KEY::DRIVES_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::DRIVES_PATH] + "://"}, - {PATHTYPE_KEY::APPS_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::APPS_PATH] + ":///"}, - {PATHTYPE_KEY::REMOTE_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::REMOTE_PATH] + "://"}, - {PATHTYPE_KEY::REMOVABLE_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::REMOVABLE_PATH] + "://"}, - {PATHTYPE_KEY::UNKNOWN_TYPE, PATHTYPE_SCHEME[PATHTYPE_KEY::UNKNOWN_TYPE] + "://"}, - {PATHTYPE_KEY::TRASH_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::TRASH_PATH] + "://"}, - {PATHTYPE_KEY::TAGS_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::TAGS_PATH] + ":///"}, - {PATHTYPE_KEY::SEARCH_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::SEARCH_PATH] + "://"}, - {PATHTYPE_KEY::CLOUD_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::CLOUD_PATH] + "://"}, - {PATHTYPE_KEY::FISH_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::FISH_PATH] + "://"}, - {PATHTYPE_KEY::MTP_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::MTP_PATH] + "://"} - }; - - static const QHash PATHTYPE_LABEL = - { - {PATHTYPE_KEY::PLACES_PATH, ("Places")}, - {PATHTYPE_KEY::DRIVES_PATH, ("Drives")}, - {PATHTYPE_KEY::APPS_PATH, ("Apps")}, - {PATHTYPE_KEY::REMOTE_PATH, ("Remote")}, - {PATHTYPE_KEY::REMOVABLE_PATH, ("Removable")}, - {PATHTYPE_KEY::UNKNOWN_TYPE, ("Unknown")}, - {PATHTYPE_KEY::TRASH_PATH, ("Trash")}, - {PATHTYPE_KEY::TAGS_PATH, ("Tags")}, - {PATHTYPE_KEY::SEARCH_PATH, ("Search")}, - {PATHTYPE_KEY::CLOUD_PATH, ("Cloud")}, - {PATHTYPE_KEY::FISH_PATH, ("Remote")}, - {PATHTYPE_KEY::MTP_PATH, ("Drives")} - }; - - - const QString DataPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); - const QString CloudCachePath = FMH::DataPath+"/Cloud/"; - - #if defined(Q_OS_ANDROID) - const QString PicturesPath = QUrl::fromLocalFile(PATHS::PicturesPath).toString(); - const QString DownloadsPath = QUrl::fromLocalFile(PATHS::DownloadsPath).toString(); - const QString DocumentsPath = QUrl::fromLocalFile(PATHS::DocumentsPath).toString(); - const QString HomePath = QUrl::fromLocalFile(PATHS::HomePath).toString(); - const QString MusicPath = QUrl::fromLocalFile(PATHS::MusicPath).toString(); - const QString VideosPath = QUrl::fromLocalFile(PATHS::VideosPath).toString(); - - const QStringList defaultPaths = - { - FMH::HomePath, - FMH::DocumentsPath, - FMH::PicturesPath, - FMH::MusicPath, - FMH::VideosPath, - FMH::DownloadsPath - }; - - const QMap folderIcon - { - {PicturesPath, "folder-pictures"}, - {DownloadsPath, "folder-download"}, - {DocumentsPath, "folder-documents"}, - {HomePath, "user-home"}, - {MusicPath, "folder-music"}, - {VideosPath, "folder-videos"}, - }; - - #else - const QString PicturesPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)).toString(); - const QString DownloadsPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)).toString(); - const QString DocumentsPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).toString(); - const QString HomePath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).toString(); - const QString MusicPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MusicLocation)).toString(); - const QString VideosPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MoviesLocation)).toString(); - const QString DesktopPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)).toString(); - const QString AppsPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)).toString(); - const QString RootPath = "file:///"; - const QStringList defaultPaths = - { - FMH::HomePath, - FMH::DesktopPath, - FMH::DocumentsPath, - FMH::PicturesPath, - FMH::MusicPath, - FMH::VideosPath, - FMH::DownloadsPath, - FMH::RootPath - }; - - const QMap folderIcon - { - {PicturesPath, "folder-pictures"}, - {DownloadsPath, "folder-download"}, - {DocumentsPath, "folder-documents"}, - {HomePath, "user-home"}, - {MusicPath, "folder-music"}, - {VideosPath, "folder-videos"}, - {DesktopPath, "user-desktop"}, - {AppsPath, "system-run"}, - {RootPath, "folder-root"} - }; - - #endif - - /** - * Checks if a local file exists. - * The URL must represent a local file path, by using the scheme file:// - **/ - inline bool fileExists(const QUrl &path) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file" << path; - return false; - } - return QFileInfo::exists(path.toLocalFile()); - } - - - /** - * Return the configuration of a single directory represented - * by a QVariantMap. - * The passed path must be a local file URL. - **/ - inline QVariantMap dirConf(const QUrl &path) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file" << path; - return QVariantMap(); - } - - if(!FMH::fileExists(path)) - return QVariantMap(); - - QString icon, iconsize, hidden, detailview, showthumbnail, showterminal; - - uint count = 0, sortby = FMH::MODEL_KEY::MODIFIED, viewType = 0; - - bool foldersFirst = false; - - #ifdef Q_OS_ANDROID - QSettings file(path.toLocalFile(), QSettings::Format::NativeFormat); - file.beginGroup(QString("Desktop Entry")); - icon = file.value("Icon").toString(); - file.endGroup(); - - file.beginGroup(QString("Settings")); - hidden = file.value("HiddenFilesShown").toString(); - file.endGroup(); - - file.beginGroup(QString("MAUIFM")); - iconsize = file.value("IconSize").toString(); - detailview = file.value("DetailView").toString(); - showthumbnail = file.value("ShowThumbnail").toString(); - showterminal = file.value("ShowTerminal").toString(); - count = file.value("Count").toInt(); - sortby = file.value("SortBy").toInt(); - foldersFirst = file.value("FoldersFirst").toBool(); - viewType = file.value("ViewType").toInt(); - file.endGroup(); - - #else - - KConfig file(path.toLocalFile()); - icon = file.entryMap(QString("Desktop Entry"))["Icon"]; - hidden = file.entryMap(QString("Settings"))["HiddenFilesShown"]; - iconsize = file.entryMap(QString("MAUIFM"))["IconSize"]; - detailview = file.entryMap(QString("MAUIFM"))["DetailView"]; - showthumbnail = file.entryMap(QString("MAUIFM"))["ShowThumbnail"]; - showterminal = file.entryMap(QString("MAUIFM"))["ShowTerminal"]; - count = file.entryMap(QString("MAUIFM"))["Count"].toInt(); - sortby = file.entryMap(QString("MAUIFM"))["SortBy"].toInt(); - foldersFirst = file.entryMap(QString("MAUIFM"))["FoldersFirst"] == "true" ? true : false; - viewType = file.entryMap(QString("MAUIFM"))["ViewType"].toInt(); - - #endif - - return QVariantMap({ - {FMH::MODEL_NAME[FMH::MODEL_KEY::ICON], icon.isEmpty() ? "folder" : icon}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::ICONSIZE], iconsize}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::COUNT], count}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::SHOWTERMINAL], showterminal.isEmpty() ? "false" : showterminal}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::SHOWTHUMBNAIL], showthumbnail.isEmpty() ? "false" : showthumbnail}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::DETAILVIEW], detailview.isEmpty() ? "false" : detailview}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::HIDDEN], hidden.isEmpty() ? false : (hidden == "true" ? true : false)}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::SORTBY], sortby}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::FOLDERSFIRST], foldersFirst}, - {FMH::MODEL_NAME[FMH::MODEL_KEY::VIEWTYPE], viewType} - }); - } - - inline void setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file" << path; - return; - } - - #ifdef Q_OS_ANDROID - QSettings file(path.toLocalFile(), QSettings::Format::IniFormat); - file.beginGroup(group); - file.setValue(key, value); - file.endGroup(); - file.sync(); - #else - KConfig file(path.toLocalFile(), KConfig::SimpleConfig); - auto kgroup = file.group(group); - kgroup.writeEntry(key, value); -// file.reparseConfiguration(); - file.sync(); - #endif - } - - /** - * Returns the icon name for certain file. - * The file path must be represented as a local file URL. - * It also looks into the directory config file to get custom set icons - **/ - inline QString getIconName(const QUrl &path) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file. FMH::getIconName" << path; - } - - if(path.isLocalFile() && QFileInfo(path.toLocalFile()).isDir()) - { - if(folderIcon.contains(path.toString())) - return folderIcon[path.toString()]; - else - { - auto icon = FMH::dirConf(QString(path.toString()+"/%1").arg(".directory"))[FMH::MODEL_NAME[FMH::MODEL_KEY::ICON]].toString(); - return icon.isEmpty() ? "folder" : icon; - } - - }else { - - #if defined(Q_OS_ANDROID) - QMimeDatabase mime; - auto type = mime.mimeTypeForFile(path.toString()); - return type.iconName(); - #else - KFileItem mime(path); - return mime.iconName(); - #endif - } - } - - inline QString getMime(const QUrl &path) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file" << path; - return QString(); - } - - const QMimeDatabase mimedb; - return mimedb.mimeTypeForFile(path.toLocalFile()).name(); - } - - enum class TABLE : uint - { - BOOKMARKS, - CLOUDS - }; - - static const QMap TABLEMAP = - { - {TABLE::BOOKMARKS, "bookmarks"}, - {TABLE::CLOUDS, "clouds"} - }; - - typedef QMap DB; - - const QString FMPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)+"/maui/fm/"; - const QString DBName = "fm.db"; - - - inline FMH::MODEL getFileInfoModel(const QUrl &path) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file" << path; - return FMH::MODEL(); - } - - const QFileInfo file(path.toLocalFile()); - if(!file.exists()) - return FMH::MODEL(); - qDebug()<< "trying to get path info model. exists"; - - const auto mime = FMH::getMime(path); - return FMH::MODEL - { - {FMH::MODEL_KEY::GROUP, file.group()}, - {FMH::MODEL_KEY::OWNER, file.owner()}, - {FMH::MODEL_KEY::SUFFIX, file.completeSuffix()}, - {FMH::MODEL_KEY::LABEL, /*file.isDir() ? file.baseName() :*/ path == FMH::HomePath ? QStringLiteral("Home") : file.fileName()}, - {FMH::MODEL_KEY::NAME, file.fileName()}, - {FMH::MODEL_KEY::DATE, file.birthTime().toString(Qt::TextDate)}, - {FMH::MODEL_KEY::MODIFIED, file.lastModified().toString(Qt::TextDate)}, - {FMH::MODEL_KEY::LAST_READ, file.lastRead().toString(Qt::TextDate)}, - {FMH::MODEL_KEY::MIME, mime }, - {FMH::MODEL_KEY::SYMLINK, file.symLinkTarget() }, - {FMH::MODEL_KEY::SYMLINK, file.symLinkTarget() }, - {FMH::MODEL_KEY::IS_SYMLINK, QVariant(file.isSymLink()).toString()}, - {FMH::MODEL_KEY::IS_FILE, QVariant(file.isFile()).toString()}, - {FMH::MODEL_KEY::HIDDEN, QVariant(file.isHidden()).toString()}, - {FMH::MODEL_KEY::IS_DIR, QVariant(file.isDir()).toString()}, - {FMH::MODEL_KEY::WRITABLE, QVariant(file.isWritable()).toString()}, - {FMH::MODEL_KEY::READABLE, QVariant(file.isReadable()).toString()}, - {FMH::MODEL_KEY::EXECUTABLE, QVariant(file.suffix().endsWith(".desktop")).toString()}, - {FMH::MODEL_KEY::ICON, FMH::getIconName(path)}, - {FMH::MODEL_KEY::SIZE, QString::number(file.size()) /*locale.formattedDataSize(file.size())*/}, - {FMH::MODEL_KEY::PATH, path.toString()}, - {FMH::MODEL_KEY::THUMBNAIL, path.toString()}, - {FMH::MODEL_KEY::COUNT, file.isDir() ? QString::number(QDir(path.toLocalFile()).count() - 2) : "0"} - }; - } - - inline QVariantMap getFileInfo(const QUrl &path) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file" << path; - return QVariantMap(); - } - const QFileInfo file(path.toLocalFile()); - - if(!file.exists()) - return QVariantMap(); - - const auto data = FMH::getFileInfoModel(path); - - qDebug()<< "getting item info model" << data; - - QVariantMap res; - for(const auto &key : data.keys()) - res.insert(FMH::MODEL_NAME[key], data[key]); - - return res; - } - - inline FMH::MODEL getDirInfoModel(const QUrl &path, const QString &type = QString()) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file" << path; - return FMH::MODEL(); - } - - const QDir dir (path.toLocalFile()); - if(!dir.exists()) - return FMH::MODEL(); - - auto res = getFileInfoModel(path); - res[FMH::MODEL_KEY::LABEL] = dir.dirName(); - res[FMH::MODEL_KEY::TYPE] = type; - - return res; - } - - inline QVariantMap getDirInfo(const QUrl &path, const QString &type = QString()) - { - if(!path.isLocalFile()) - { - qWarning() << "URL recived is not a local file" << path; - return QVariantMap(); - } - - const QFileInfo file(path.toLocalFile()); - - if(!file.exists()) - return QVariantMap(); - - const auto data = FMH::getDirInfoModel(path); - - QVariantMap res; - for(const auto &key : data.keys()) - res.insert(FMH::MODEL_NAME[key], data[key]); - - return res; - } - - #ifndef STATIC_MAUIKIT - #include "mauikit_export.h" - #endif - - #ifdef STATIC_MAUIKIT - class Downloader : public QObject - #else - class MAUIKIT_EXPORT Downloader : public QObject - #endif - { - Q_OBJECT - public: - explicit Downloader(QObject *parent = 0) : QObject(parent), manager(new QNetworkAccessManager) - {} - - virtual ~Downloader() - { - qDebug()<< "DELETEING DOWNLOADER"; - this->manager->deleteLater(); -// this->reply->deleteLater(); - - } - - void setFile(const QString &fileURL, const QString &fileName = QString()) - { - QString filePath = fileURL; - - if(fileName.isEmpty() || fileURL.isEmpty()) - return; - - QNetworkRequest request; - request.setUrl(QUrl(fileURL)); - reply = manager->get(request); - - file = new QFile; - file->setFileName(fileName); - file->open(QIODevice::WriteOnly); - - connect(reply, SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(onDownloadProgress(qint64,qint64))); - connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(onFinished(QNetworkReply*))); - connect(reply, SIGNAL(readyRead()),this,SLOT(onReadyRead())); - connect(reply, SIGNAL(finished()),this,SLOT(onReplyFinished())); - } - - void getArray(const QString &fileURL, const QMap &headers = {}) - { - qDebug() << fileURL << headers; - if(fileURL.isEmpty()) - return; - - QNetworkRequest request; - request.setUrl(QUrl(fileURL)); - if(!headers.isEmpty()) - { - for(auto key: headers.keys()) - request.setRawHeader(key.toLocal8Bit(), headers[key].toLocal8Bit()); - } - - reply = manager->get(request); - - connect(reply, &QNetworkReply::readyRead, [this]() - { - switch(reply->error()) - { - case QNetworkReply::NoError: - { - this->array = reply->readAll(); - break; - } - - default: - { - qDebug() << reply->errorString(); - emit this->warning(reply->errorString()); - }; - } - }); - - connect(reply, &QNetworkReply::finished, [=]() - { - qDebug() << "Array reply is now finished"; - emit this->dataReady(this->array); - emit this->done(); - }); - } - - private: - QNetworkAccessManager *manager; - QNetworkReply *reply; - QFile *file; - QByteArray array; - - signals: - void progress(int percent); - void downloadReady(); - void fileSaved(QString path); - void warning(QString warning); - void dataReady(QByteArray array); - void done(); - - private slots: - void onDownloadProgress(qint64 bytesRead, qint64 bytesTotal) - { - emit this->progress((bytesRead * bytesTotal) / 100); - } - - void onFinished(QNetworkReply* reply) - { - switch(reply->error()) - { - case QNetworkReply::NoError: - { - qDebug("file is downloaded successfully."); - emit this->downloadReady(); - break; - } - - default: - { - emit this->warning(reply->errorString()); - }; - } - - if(file->isOpen()) - { - file->close(); - emit this->fileSaved(file->fileName()); - file->deleteLater(); - } - } - - void onReadyRead() - { - file->write(reply->readAll()); - // emit this->fileSaved(file->fileName()); - } - - void onReplyFinished() - { - if(file->isOpen()) - { - file->close(); - // emit this->fileSaved(file->fileName()); - file->deleteLater(); - } - - emit done(); - } - }; - -} - -#endif // FMH_H diff --git a/src/fm/fmlist.cpp b/src/fm/fmlist.cpp index 5ac7597..ec33717 100644 --- a/src/fm/fmlist.cpp +++ b/src/fm/fmlist.cpp @@ -1,857 +1,808 @@ /* * * Copyright (C) 2018 camilo higuita * * 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 3 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, see . */ #include "fmlist.h" #include "fm.h" #include "utils.h" #include #include -#include + +#ifdef COMPONENT_SYNCING +#include "syncing.h" +#endif #include #include #include #include FMList::FMList(QObject *parent) : MauiList(parent), fm(new FM(this)), watcher(new QFileSystemWatcher(this)) { - connect(this->fm, &FM::cloudServerContentReady, [&](const FMH::MODEL_LIST &list, const QString &url) + connect(this->fm, &FM::cloudServerContentReady, [&](const FMH::MODEL_LIST &list, const QUrl &url) { if(this->path == url) { - this->pre(); - this->list = list; - this->pathEmpty = this->list.isEmpty(); - emit this->pathEmptyChanged(); - this->count = this->list.size(); - emit this->countChanged(); - this->pos(); - this->setContentReady(true); - } - }); - - connect(this->fm, &FM::trashContentReady, [&](const FMH::MODEL_LIST &list) - { - if(this->path == "trash://") - { - this->pre(); - this->list = list; - this->pathEmpty = this->list.isEmpty(); - emit this->pathEmptyChanged(); - this->count = this->list.size(); - emit this->countChanged(); - this->pos(); - this->setContentReady(true); + this->assignList(list); } }); connect(this->fm, &FM::pathContentReady, [&](const FMH::PATH_CONTENT &res) { -// if(this->pathType != FMList::PATHTYPE::PLACES_PATH) -// return; +// if(res.path != this->path) +// return; - if(res.path != this->path) - return; - - emit this->preListChanged(); - this->list = res.content; - this->pathEmpty = this->list.isEmpty() /*&& FM::fileExists(this->path)*/; - emit this->pathEmptyChanged(); - - this->sortList(); - - this->count = this->list.size(); - emit this->countChanged(); - emit this->postListChanged(); - this->setContentReady(true); + this->assignList(res.content); }); connect(this->fm, &FM::warningMessage, [&](const QString &message) { emit this->warning(message); }); connect(this->fm, &FM::loadProgress, [&](const int &percent) { emit this->progress(percent); }); // with kio based on android it watches the directory itself, so better relay on that #ifdef Q_OS_ANDROID connect(this->watcher, &QFileSystemWatcher::directoryChanged, [&](const QString &path) { qDebug()<< "FOLDER PATH CHANGED" << path; this->reset(); }); #else connect(this->fm, &FM::pathContentChanged, [&](const QUrl &path) { qDebug()<< "FOLDER PATH CHANGED" << path; - if(path.toString() != this->path) + if(path != this->path) return; this->sortList(); }); #endif - connect(this->fm, &FM::newItem, [&] (const FMH::MODEL &item, const QString &url) + connect(this->fm, &FM::newItem, [&] (const FMH::MODEL &item, const QUrl &url) { if(this->path == url) { emit this->preItemAppended(); - this->list << item; - this->pathEmpty = this->list.isEmpty(); - emit this->pathEmptyChanged(); - emit this->postListChanged(); + this->list << item; + emit this->postItemAppended(); } }); connect(this, &FMList::pathChanged, this, &FMList::reset); - // connect(this, &FMList::hiddenChanged, this, &FMList::setList); - // connect(this, &FMList::onlyDirsChanged, this, &FMList::setList); - // connect(this, &FMList::filtersChanged, this, &FMList::setList); + const auto value = UTIL::loadSettings("SaveDirProps", "SETTINGS", this->saveDirProps).toBool(); this->setSaveDirProps(value); } FMList::~FMList() {} -void FMList::pre() -{ - emit this->preListChanged(); - // this->setContentReady(false); -} - -void FMList::pos() -{ - // this->setContentReady(true); - emit this->postListChanged(); -} - void FMList::watchPath(const QString& path, const bool& clear) { #ifdef Q_OS_ANDROID if(!this->watcher->directories().isEmpty() && clear) this->watcher->removePaths(this->watcher->directories()); - if(path.isEmpty() || !FMH::fileExists(path)) + if(path.isEmpty() || !FMH::fileExists(path) || !QUrl(path).isLocalFile()) return; this->watcher->addPath(QString(path).replace("file://", "")); qDebug()<< "WATCHING PATHS" << this->watcher->directories(); #else Q_UNUSED(path) Q_UNUSED(clear) #endif } +void FMList::assignList(const FMH::MODEL_LIST& list) +{ + emit this->preListChanged(); + this->list =list; + this->sortList(); + + this->count = this->list.size(); + emit this->countChanged(); + + this->setStatus({STATUS_CODE::READY, this->list.isEmpty() ? "Nothing here!" : "", this->list.isEmpty() ? "This place seems to be empty" : "",this->list.isEmpty() ? "folder-add" : "", this->list.isEmpty(), true}); + + emit this->postListChanged(); +} + void FMList::setList() { - this->setContentReady(true); + emit this->preListChanged(); + this->list.clear(); + emit this->postListChanged(); + + qDebug()<< "PATHTYPE FOR URL"<< pathType << path; + switch(this->pathType) - { - case FMList::PATHTYPE::FISH_PATH: - case FMList::PATHTYPE::MTP_PATH: - case FMList::PATHTYPE::DRIVES_PATH: - case FMList::PATHTYPE::REMOTE_PATH: - case FMList::PATHTYPE::PLACES_PATH: - this->list.clear(); - this->setContentReady(false); - this->fm->getPathContent(this->path, this->hidden, this->onlyDirs, this->filters); - return; //ASYNC - - case FMList::PATHTYPE::TRASH_PATH: - this->list.clear(); - this->setContentReady(false); - this->fm->getTrashContent(); - break;//ASYNC - - case FMList::PATHTYPE::SEARCH_PATH: - this->list.clear(); - this->setContentReady(false); - this->search(QString(this->path).right(this->path.length()- 1 - this->path.lastIndexOf("/")), this->searchPath, this->hidden, this->onlyDirs, this->filters); - return; //ASYNC - - case FMList::PATHTYPE::APPS_PATH: - this->list = FM::getAppsContent(this->path); - break; + { + case FMList::PATHTYPE::SEARCH_PATH: + this->search(this->path.fileName(), this->searchPath, this->hidden, this->onlyDirs, this->filters); + break; //ASYNC case FMList::PATHTYPE::TAGS_PATH: - this->list = this->fm->getTagContent(QString(this->path).right(this->path.length()- 1 - this->path.lastIndexOf("/"))); - break; + this->assignList(this->fm->getTagContent(this->path.fileName())); + break; //SYNC case FMList::PATHTYPE::CLOUD_PATH: - this->list.clear(); - if(this->fm->getCloudServerContent(this->path, this->filters, this->cloudDepth)) - { - this->setContentReady(false); - return; - }else break; - - + this->fm->getCloudServerContent(this->path.toString(), this->filters, this->cloudDepth); + break; //ASYNC + + default: + { + const bool exists = this->path.isLocalFile() ? FMH::fileExists(this->path) : true; + if(!exists) + this->setStatus({STATUS_CODE::ERROR, "Error", "This URL cannot be listed", "documentinfo", this->list.isEmpty(), exists}); + else{ + this->fm->getPathContent(this->path, this->hidden, this->onlyDirs, this->filters); + } + break;//ASYNC + } } - - this->pathEmpty = this->list.isEmpty() && FM::fileExists(this->path); - emit this->pathEmptyChanged(); - - this->sortList(); } void FMList::reset() -{ - this->pre(); - +{ switch(this->pathType) { - case FMList::PATHTYPE::APPS_PATH: - - this->hidden = false; - break; - + case FMList::PATHTYPE::APPS_PATH: case FMList::PATHTYPE::CLOUD_PATH: case FMList::PATHTYPE::SEARCH_PATH: - case FMList::PATHTYPE::TAGS_PATH: - + case FMList::PATHTYPE::TAGS_PATH: this->hidden = false; break; case FMList::PATHTYPE::PLACES_PATH: { if(this->saveDirProps) { - auto conf = FMH::dirConf(this->path+"/.directory"); + auto conf = FMH::dirConf(this->path.toString()+"/.directory"); this->hidden = conf[FMH::MODEL_NAME[FMH::MODEL_KEY::HIDDEN]].toBool(); this->foldersFirst = conf[FMH::MODEL_NAME[FMH::MODEL_KEY::FOLDERSFIRST]].toBool(); }else { this->hidden = UTIL::loadSettings("HiddenFilesShown", "SETTINGS", this->hidden).toBool(); this->foldersFirst = UTIL::loadSettings("FoldersFirst", "SETTINGS", this->foldersFirst).toBool(); } break; } default: break; } if(this->saveDirProps) { - auto conf = FMH::dirConf(this->path+"/.directory"); + auto conf = FMH::dirConf(this->path.toString()+"/.directory"); this->sort = static_cast(conf[FMH::MODEL_NAME[FMH::MODEL_KEY::SORTBY]].toInt()); }else { this->sort = static_cast(UTIL::loadSettings("SortBy", "SETTINGS", this->sort).toInt()); } emit this->sortByChanged(); emit this->hiddenChanged(); this->setList(); - this->pos(); } FMH::MODEL_LIST FMList::items() const { return this->list; } FMList::SORTBY FMList::getSortBy() const { return this->sort; } void FMList::setSortBy(const FMList::SORTBY &key) { if(this->sort == key) return; - this->pre(); + emit this->preListChanged(); this->sort = key; this->sortList(); if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) - FMH::setDirConf(this->path+"/.directory", "MAUIFM", "SortBy", this->sort); + FMH::setDirConf(this->path.toString()+"/.directory", "MAUIFM", "SortBy", this->sort); else UTIL::saveSettings("SortBy", this->sort, "SETTINGS"); emit this->sortByChanged(); - this->pos(); + emit this->postListChanged(); } void FMList::sortList() { FMH::MODEL_KEY key = static_cast(this->sort); auto index = 0; if(this->foldersFirst) { qSort(this->list.begin(), this->list.end(), [](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool { Q_UNUSED(e2) const auto key = FMH::MODEL_KEY::MIME; if(e1[key] == "inode/directory") return true; return false; }); for(auto item : this->list) if(item[FMH::MODEL_KEY::MIME] == "inode/directory") index++; else break; qSort(this->list.begin(),this->list.begin() + index, [key](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool { auto role = key; switch(role) { case FMH::MODEL_KEY::SIZE: { if(e1[role].toDouble() > e2[role].toDouble()) return true; break; } case FMH::MODEL_KEY::MODIFIED: case FMH::MODEL_KEY::DATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::LABEL: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } qSort(this->list.begin() + index, this->list.end(), [key](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool { auto role = key; switch(role) { case FMH::MODEL_KEY::MIME: if(e1[role] == "inode/directory") return true; break; case FMH::MODEL_KEY::SIZE: { if(e1[role].toDouble() > e2[role].toDouble()) return true; break; } case FMH::MODEL_KEY::MODIFIED: case FMH::MODEL_KEY::DATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::LABEL: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } QString FMList::getPathName() const { return this->pathName; } -QString FMList::getPath() const +QUrl FMList::getPath() const { return this->path; } -void FMList::setPath(const QString &path) +void FMList::setPath(const QUrl &path) { if(this->path == path) return; if(this->pathType == FMList::PATHTYPE::PLACES_PATH) this->searchPath = this->path; this->path = path; - this->setPreviousPath(this->path); - - qDebug()<< "Prev History" << this->prevHistory; + this->setPreviousPath(this->path); + + this->setStatus({STATUS_CODE::LOADING, "Loading content", "Almost ready!", "view-refresh", true, false}); - const auto __scheme = QUrl(this->path).scheme(); - qDebug()<< "CurrentPath" <<__scheme; - -// if(path.startsWith(FMH::PATHTYPE_NAME[FMH::PATHTYPE_KEY::SEARCH_PATH]+"/")) - if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::SEARCH_PATH]) + const auto __scheme = this->path.scheme(); + this->pathName = this->path.fileName(); + + if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::SEARCH_PATH]) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::SEARCH_PATH; - this->pathName = "Search"; - - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::CLOUD_PATH; - this->pathName = "Cloud"; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::APPS_PATH]) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::APPS_PATH; - this->pathName = "Apps"; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::TAGS_PATH]) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::TAGS_PATH; - emit this->pathName = "Tags"; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::TRASH_PATH]) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::TRASH_PATH; this->pathName = "Trash"; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); this->watchPath(QString()); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::PLACES_PATH]) { - this->watchPath(this->path); - this->pathExists = FMH::fileExists(this->path); + this->watchPath(this->path.toString()); this->pathType = FMList::PATHTYPE::PLACES_PATH; this->pathName = FMH::getDirInfoModel(this->path)[FMH::MODEL_KEY::LABEL]; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::MTP_PATH]) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::MTP_PATH; - this->pathName = "MTP"; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); - }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::FISH_PATH] ) + + }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::FISH_PATH] ) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::FISH_PATH; - this->pathName = "Fish"; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); - }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::REMOTE_PATH] ) + + }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::REMOTE_PATH] ) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::REMOTE_PATH; - this->pathName = "Remote"; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); - }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::DRIVES_PATH] ) + + }else if(__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::DRIVES_PATH] ) { - this->pathExists = true; this->pathType = FMList::PATHTYPE::DRIVES_PATH; - this->pathName = "Drives"; - emit this->pathExistsChanged(); - emit this->pathTypeChanged(); - } + }else + { + this->pathType = FMList::PATHTYPE::OTHER_PATH; + } - - qDebug() << "PATHTYPE IS" << this->pathType << FMH::PATHTYPE_SCHEME[static_cast(this->pathType)]; - emit this->pathChanged(); emit this->pathNameChanged(); + emit this->pathTypeChanged(); + emit this->pathChanged(); + } FMList::PATHTYPE FMList::getPathType() const { return this->pathType; } QStringList FMList::getFilters() const { return this->filters; } void FMList::setFilters(const QStringList &filters) { if(this->filters == filters) return; this->filters = filters; emit this->filtersChanged(); this->reset(); } FMList::FILTER FMList::getFilterType() const { return this->filterType; } void FMList::setFilterType(const FMList::FILTER &type) { this->filterType = type; this->filters = FMH::FILTER_LIST[static_cast(this->filterType)]; emit this->filtersChanged(); emit this->filterTypeChanged(); this->reset(); } bool FMList::getHidden() const { return this->hidden; } void FMList::setHidden(const bool &state) { if(this->hidden == state) return; this->hidden = state; if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) - FMH::setDirConf(this->path+"/.directory", "Settings", "HiddenFilesShown", this->hidden); + FMH::setDirConf(this->path.toString()+"/.directory", "Settings", "HiddenFilesShown", this->hidden); else UTIL::saveSettings("HiddenFilesShown", this->hidden, "SETTINGS"); emit this->hiddenChanged(); this->reset(); } bool FMList::getOnlyDirs() const { return this->onlyDirs; } void FMList::setOnlyDirs(const bool &state) { if(this->onlyDirs == state) return; this->onlyDirs = state; emit this->onlyDirsChanged(); this->reset(); } QVariantMap FMList::get(const int &index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); const auto model = this->list.at(index); - return FM::toMap(model); + return FMH::toMap(model); } void FMList::refresh() { emit this->pathChanged(); } void FMList::createDir(const QString& name) { - if(this->pathType == FMList::PATHTYPE::PLACES_PATH) - this->fm->createDir(this->path, name); - else if(this->pathType == FMList::PATHTYPE::CLOUD_PATH) + if(this->pathType == FMList::PATHTYPE::CLOUD_PATH) + { +#ifdef COMPONENT_SYNCING + this->fm->createCloudDir(QString(this->path.toString()).replace(FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]+"/"+this->fm->sync->getUser(), ""), name); +#endif + }else { - this->fm->createCloudDir(QString(this->path).replace(FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]+"/"+this->fm->sync->getUser(), ""), name); + FMStatic::createDir(this->path, name); } } void FMList::copyInto(const QVariantList& files) { - if(this->pathType == FMList::PATHTYPE::PLACES_PATH || this->pathType == FMList::PATHTYPE::CLOUD_PATH) this->fm->copy(files, this->path); } void FMList::cutInto(const QVariantList& files) { if(this->pathType == FMList::PATHTYPE::PLACES_PATH) this->fm->cut(files, this->path); // else if(this->pathType == FMList::PATHTYPE::CLOUD_PATH) // { // this->fm->createCloudDir(QString(this->path).replace(FMH::PATHTYPE_NAME[FMList::PATHTYPE::CLOUD_PATH]+"/"+this->fm->sync->getUser(), ""), name); // } } void FMList::setDirIcon(const int &index, const QString &iconName) { if(index >= this->list.size() || index < 0) return; const auto path = QUrl(this->list.at(index)[FMH::MODEL_KEY::PATH]); - if(!FM::isDir(path)) + if(!FMStatic::isDir(path)) return; FMH::setDirConf(path.toString()+"/.directory", "Desktop Entry", "Icon", iconName); this->list[index][FMH::MODEL_KEY::ICON] = iconName; emit this->updateModel(index, QVector {FMH::MODEL_KEY::ICON}); } -QString FMList::getParentPath() +QUrl FMList::getParentPath() { switch(this->pathType) { case FMList::PATHTYPE::PLACES_PATH: - return FM::parentDir(this->path).toString(); + return FMStatic::parentDir(this->path).toString(); default: return this->getPreviousPath(); } } -QString FMList::getPosteriorPath() +QUrl FMList::getPosteriorPath() { if(this->postHistory.isEmpty()) return this->path; return this->postHistory.takeAt(this->postHistory.length()-1); } -void FMList::setPosteriorPath(const QString& path) +void FMList::setPosteriorPath(const QUrl& path) { this->postHistory.append(path); } -QString FMList::getPreviousPath() +QUrl FMList::getPreviousPath() { if(this->prevHistory.isEmpty()) return this->path; if(this->prevHistory.length() < 2) return this->prevHistory.at(0); auto post = this->prevHistory.takeAt(this->prevHistory.length()-1); this->setPosteriorPath(post); return this->prevHistory.takeAt(this->prevHistory.length()-1); } -void FMList::setPreviousPath(const QString& path) +void FMList::setPreviousPath(const QUrl& path) { this->prevHistory.append(path); } -bool FMList::getPathEmpty() const -{ - return this->pathEmpty; -} - -bool FMList::getPathExists() const -{ - return this->pathExists; -} - bool FMList::getTrackChanges() const { return this->trackChanges; } void FMList::setTrackChanges(const bool& value) { if(this->trackChanges == value) return; this->trackChanges = value; emit this->trackChangesChanged(); } bool FMList::getFoldersFirst() const { return this->foldersFirst; } void FMList::setFoldersFirst(const bool &value) { if(this->foldersFirst == value) return; - this->pre(); + emit this->preListChanged(); this->foldersFirst = value; if(this->pathType == FMList::PATHTYPE::PLACES_PATH && this->trackChanges && this->saveDirProps) - FMH::setDirConf(this->path+"/.directory", "MAUIFM", "FoldersFirst", this->foldersFirst); + FMH::setDirConf(this->path.toString()+"/.directory", "MAUIFM", "FoldersFirst", this->foldersFirst); else UTIL::saveSettings("FoldersFirst", this->foldersFirst, "SETTINGS"); emit this->foldersFirstChanged(); this->sortList(); - this->pos(); + emit this->postListChanged(); } void FMList::setSaveDirProps(const bool& value) { if(this->saveDirProps == value) return; this->saveDirProps = value; UTIL::saveSettings("SaveDirProps", this->saveDirProps, "SETTINGS"); emit this->saveDirPropsChanged(); } bool FMList::getSaveDirProps() const { return this->saveDirProps; } -void FMList::setContentReady(const bool& value) -{ - this->contentReady = value; - emit this->contentReadyChanged(); -} - -bool FMList::getContentReady() const -{ - return this->contentReady; -} - void FMList::search(const QString& query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) { qDebug()<< "SEARCHING FOR" << query << path; if(!path.isLocalFile()) { - qWarning() << "URL recived is not a local file. search" << path; + qWarning() << "URL recived is not a local file. So search will only filter the content" << path; + this->filterContent(query, path, hidden, onlyDirs, filters); return; } QFutureWatcher *watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, [=]() { if(this->pathType != FMList::PATHTYPE::SEARCH_PATH) return; const auto res = watcher->future().result(); - if(res.path != this->searchPath) + if(res.path != this->searchPath.toString()) return; - emit this->preListChanged(); - this->list = res.content; - emit this->postListChanged(); + this->assignList(res.content); emit this->searchResultReady(); - this->pathEmpty = this->list.isEmpty() && FM::fileExists(this->path); - emit this->pathEmptyChanged(); - - this->sortList(); - - this->setContentReady(true); watcher->deleteLater(); }); QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT { FMH::PATH_CONTENT res; res.path = path.toString(); - res.content = FM::search(query, path, hidden, onlyDirs, filters); + res.content = FMStatic::search(query, path, hidden, onlyDirs, filters); return res; }); - watcher->setFuture(t1); + watcher->setFuture(t1); +} + +void FMList::filterContent(const QString &query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) +{ + QFutureWatcher *watcher = new QFutureWatcher; + connect(watcher, &QFutureWatcher::finished, [=]() + { + if(this->pathType != FMList::PATHTYPE::SEARCH_PATH) + return; + + const auto res = watcher->future().result(); + + if(res.path != this->searchPath.toString()) + return; + + this->assignList(res.content); + emit this->searchResultReady(); + + watcher->deleteLater(); + }); + + QFuture t1 = QtConcurrent::run([=]() -> FMH::PATH_CONTENT + { + FMH::MODEL_LIST m_content; + FMH::PATH_CONTENT res; + res.path = path.toString(); + res.content = m_content; + for(const auto &item : this->list) + { + if(item[FMH::MODEL_KEY::URL].contains(query) || item[FMH::MODEL_KEY::LABEL].contains(query) + || item[FMH::MODEL_KEY::SUFFIX].contains(query) || item[FMH::MODEL_KEY::MIME].contains(query)) + { + if(onlyDirs && item[FMH::MODEL_KEY::IS_DIR] == "true") + { + m_content << item; + continue; + } + + m_content << item; + } + } + return res; + }); + watcher->setFuture(t1); + } int FMList::getCloudDepth() const { return this->cloudDepth; } void FMList::setCloudDepth(const int& value) { if(this->cloudDepth == value) return; this->cloudDepth = value; emit this->cloudDepthChanged(); this->reset(); } uint FMList::getCount() const { return this->count; } +PathStatus FMList::getStatus() const +{ + return this->m_status; +} + +void FMList::setStatus(const PathStatus &status) +{ + this->m_status = status; + emit this->statusChanged(); +} + +bool FMList::itemIsFav(const QUrl &path) +{ + return this->fm->urlTagExists(path, "fav"); +} + +bool FMList::favItem(const QUrl &path) +{ + if(this->itemIsFav(path)) + return this->fm->removeTagToUrl("fav", path); + + return this->fm->addTagToUrl("fav", path); +} + + diff --git a/src/fm/fmlist.h b/src/fm/fmlist.h index 672f9fc..36dc8e1 100644 --- a/src/fm/fmlist.h +++ b/src/fm/fmlist.h @@ -1,244 +1,267 @@ /* * * Copyright (C) 2018 Camilo Higuita * * 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 3 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, see . */ #ifndef FMLIST_H #define FMLIST_H #include #include "fmh.h" #include "mauilist.h" -struct PathContent + +enum STATUS_CODE : uint_fast8_t +{ + LOADING, + ERROR, + READY +}; + +class PathStatus { - QString path; - FMH::MODEL_LIST content; + Q_GADGET + + Q_PROPERTY(STATUS_CODE code MEMBER m_code) + Q_PROPERTY(QString title MEMBER m_title) + Q_PROPERTY(QString message MEMBER m_message) + Q_PROPERTY(QString icon MEMBER m_icon) + Q_PROPERTY(bool empty MEMBER m_empty) + Q_PROPERTY(bool exists MEMBER m_exists) + +public: + + STATUS_CODE m_code; + QString m_title; + QString m_message; + QString m_icon; + bool m_empty = false; + bool m_exists = false; }; +Q_DECLARE_METATYPE(PathStatus) class FM; class QFileSystemWatcher; class FMList : public MauiList { Q_OBJECT - - Q_PROPERTY(QString path READ getPath WRITE setPath NOTIFY pathChanged) - Q_PROPERTY(QString pathName READ getPathName NOTIFY pathNameChanged) + + //writable + Q_PROPERTY(QUrl path READ getPath WRITE setPath NOTIFY pathChanged) Q_PROPERTY(bool hidden READ getHidden WRITE setHidden NOTIFY hiddenChanged) Q_PROPERTY(bool onlyDirs READ getOnlyDirs WRITE setOnlyDirs NOTIFY onlyDirsChanged) - - Q_PROPERTY(int cloudDepth READ getCloudDepth WRITE setCloudDepth NOTIFY cloudDepthChanged) - Q_PROPERTY(uint count READ getCount NOTIFY countChanged) - - Q_PROPERTY(bool contentReady READ getContentReady NOTIFY contentReadyChanged) - + Q_PROPERTY(bool foldersFirst READ getFoldersFirst WRITE setFoldersFirst NOTIFY foldersFirstChanged) + Q_PROPERTY(int cloudDepth READ getCloudDepth WRITE setCloudDepth NOTIFY cloudDepthChanged) + Q_PROPERTY(QStringList filters READ getFilters WRITE setFilters NOTIFY filtersChanged) - Q_PROPERTY(FMList::FILTER filterType READ getFilterType WRITE setFilterType NOTIFY filterTypeChanged) - + Q_PROPERTY(FMList::FILTER filterType READ getFilterType WRITE setFilterType NOTIFY filterTypeChanged) Q_PROPERTY(FMList::SORTBY sortBy READ getSortBy WRITE setSortBy NOTIFY sortByChanged) - Q_PROPERTY(bool foldersFirst READ getFoldersFirst WRITE setFoldersFirst NOTIFY foldersFirstChanged) - Q_PROPERTY(FMList::PATHTYPE pathType READ getPathType NOTIFY pathTypeChanged) Q_PROPERTY(bool trackChanges READ getTrackChanges WRITE setTrackChanges NOTIFY trackChangesChanged) Q_PROPERTY(bool saveDirProps READ getSaveDirProps WRITE setSaveDirProps NOTIFY saveDirPropsChanged) - Q_PROPERTY(bool pathExists READ getPathExists NOTIFY pathExistsChanged) - Q_PROPERTY(bool pathEmpty READ getPathEmpty NOTIFY pathEmptyChanged) - - Q_PROPERTY(QString previousPath READ getPreviousPath) - Q_PROPERTY(QString posteriorPath READ getPosteriorPath) - Q_PROPERTY(QString parentPath READ getParentPath) + //readonly + Q_PROPERTY(uint count READ getCount NOTIFY countChanged) + Q_PROPERTY(QString pathName READ getPathName NOTIFY pathNameChanged) + Q_PROPERTY(FMList::PATHTYPE pathType READ getPathType NOTIFY pathTypeChanged) + + Q_PROPERTY(PathStatus status READ getStatus NOTIFY statusChanged) //TODO status to replace pathExists, pathEmpty and handle errors messaging + + Q_PROPERTY(QUrl previousPath READ getPreviousPath) + Q_PROPERTY(QUrl posteriorPath READ getPosteriorPath) + Q_PROPERTY(QUrl parentPath READ getParentPath) public: - enum SORTBY : uint_fast8_t { SIZE = FMH::MODEL_KEY::SIZE, MODIFIED = FMH::MODEL_KEY::MODIFIED, DATE = FMH::MODEL_KEY::DATE, LABEL = FMH::MODEL_KEY::LABEL, MIME = FMH::MODEL_KEY::MIME, ADDDATE = FMH::MODEL_KEY::MIME, TITLE = FMH::MODEL_KEY::TITLE, PLACE = FMH::MODEL_KEY::PLACE, FORMAT = FMH::MODEL_KEY::FORMAT }; Q_ENUM(SORTBY) enum FILTER : uint_fast8_t { AUDIO = FMH::FILTER_TYPE::AUDIO, VIDEO= FMH::FILTER_TYPE::VIDEO, TEXT = FMH::FILTER_TYPE::TEXT, IMAGE = FMH::FILTER_TYPE::IMAGE, NONE = FMH::FILTER_TYPE::NONE }; Q_ENUM(FILTER) enum PATHTYPE : uint_fast8_t { PLACES_PATH = FMH::PATHTYPE_KEY::PLACES_PATH, FISH_PATH = FMH::PATHTYPE_KEY::FISH_PATH, MTP_PATH = FMH::PATHTYPE_KEY::MTP_PATH, REMOTE_PATH = FMH::PATHTYPE_KEY::REMOTE_PATH, DRIVES_PATH = FMH::PATHTYPE_KEY::DRIVES_PATH, REMOVABLE_PATH = FMH::PATHTYPE_KEY::REMOVABLE_PATH, TAGS_PATH = FMH::PATHTYPE_KEY::TAGS_PATH, APPS_PATH = FMH::PATHTYPE_KEY::APPS_PATH, TRASH_PATH = FMH::PATHTYPE_KEY::TRASH_PATH, SEARCH_PATH = FMH::PATHTYPE_KEY::SEARCH_PATH, - CLOUD_PATH = FMH::PATHTYPE_KEY::CLOUD_PATH + CLOUD_PATH = FMH::PATHTYPE_KEY::CLOUD_PATH, + QUICK_PATH = FMH::PATHTYPE_KEY::QUICK_PATH, + OTHER_PATH = FMH::PATHTYPE_KEY::OTHER_PATH }; Q_ENUM(PATHTYPE) enum VIEW_TYPE : uint_fast8_t { ICON_VIEW, LIST_VIEW, MILLERS_VIEW }; Q_ENUM(VIEW_TYPE) - + + Q_ENUM(STATUS_CODE) + FMList(QObject *parent = nullptr); ~FMList(); FMH::MODEL_LIST items() const final override; FMList::SORTBY getSortBy() const; void setSortBy(const FMList::SORTBY &key); - QString getPath() const; - void setPath(const QString &path); + QUrl getPath() const; + void setPath(const QUrl &path); QString getPathName() const; FMList::PATHTYPE getPathType() const; QStringList getFilters() const; void setFilters(const QStringList &filters); FMList::FILTER getFilterType() const; void setFilterType(const FMList::FILTER &type); bool getHidden() const; void setHidden(const bool &state); bool getOnlyDirs() const; void setOnlyDirs(const bool &state); - QString getParentPath(); + QUrl getParentPath(); - QString getPreviousPath(); - void setPreviousPath(const QString &path); - - QString getPosteriorPath(); - void setPosteriorPath(const QString &path); - - bool getPathEmpty() const; - bool getPathExists() const; + QUrl getPreviousPath(); + void setPreviousPath(const QUrl &path); + QUrl getPosteriorPath(); + void setPosteriorPath(const QUrl &path); + bool getTrackChanges() const; void setTrackChanges(const bool &value); bool getFoldersFirst() const; void setFoldersFirst(const bool &value); bool getSaveDirProps() const; void setSaveDirProps(const bool &value); - bool getContentReady() const; - void setContentReady(const bool &value); - int getCloudDepth() const; void setCloudDepth(const int &value); uint getCount() const; + + void setStatus(const PathStatus &status); + PathStatus getStatus() const; private: FM *fm; QFileSystemWatcher *watcher; - void pre(); - void pos(); - + void reset(); void setList(); + void assignList(const FMH::MODEL_LIST &list); void sortList(); void watchPath(const QString &path, const bool &clear = true); void search(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); - + void filterContent(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); + FMH::MODEL_LIST list = {{}}; - QString path = QString(); + QUrl path; QString pathName = QString(); QStringList filters = {}; bool onlyDirs = false; bool hidden = false; - bool pathExists = false; - bool pathEmpty = true; - bool trackChanges = true; + + bool trackChanges = true; bool foldersFirst = false; bool saveDirProps = false; - bool contentReady = false; int cloudDepth = 1; uint count = 0; - QString searchPath; + + QUrl searchPath; + + PathStatus m_status; FMList::SORTBY sort = FMList::SORTBY::MODIFIED; FMList::FILTER filterType = FMList::FILTER::NONE; FMList::PATHTYPE pathType = FMList::PATHTYPE::PLACES_PATH; - QStringList prevHistory = {}; - QStringList postHistory = {}; + QList prevHistory = {}; + QList postHistory = {}; public slots: QVariantMap get(const int &index) const; void refresh(); void createDir(const QString &name); void copyInto(const QVariantList &files); void cutInto(const QVariantList &files); void setDirIcon(const int &index, const QString &iconName); + bool itemIsFav(const QUrl &path); + bool favItem(const QUrl &path); + signals: void pathChanged(); void pathNameChanged(); void pathTypeChanged(); void filtersChanged(); void filterTypeChanged(); void hiddenChanged(); void onlyDirsChanged(); void sortByChanged(); void trackChangesChanged(); void foldersFirstChanged(); void saveDirPropsChanged(); - void contentReadyChanged(); + void statusChanged(); void cloudDepthChanged(); void countChanged(); - - void pathEmptyChanged(); - void pathExistsChanged(); - + void warning(QString message); void progress(int percent); void searchResultReady(); }; #endif // FMLIST_H diff --git a/src/fm/placeslist.cpp b/src/fm/placeslist.cpp index eb06485..16367fb 100644 --- a/src/fm/placeslist.cpp +++ b/src/fm/placeslist.cpp @@ -1,286 +1,310 @@ /* * * Copyright (C) 2018 camilo * * 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 3 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, see . */ #include "placeslist.h" #include "fm.h" #include #include #include #include #include "utils.h" +#ifdef COMPONENT_ACCOUNTS +#include "mauiaccounts.h" +#endif + #ifdef Q_OS_ANDROID #else #include #endif #ifdef Q_OS_ANDROID PlacesList::PlacesList(QObject *parent) : MauiList(parent), fm(new FM(this)), model(nullptr), watcher(new QFileSystemWatcher(this)) #else PlacesList::PlacesList(QObject *parent) : MauiList(parent), fm(new FM(this)), model(new KFilePlacesModel(this)), watcher(new QFileSystemWatcher(this)) #endif { connect(watcher, &QFileSystemWatcher::directoryChanged, [this](const QString &path) { if(this->count.contains(path)) { const auto oldCount = this->count[path]; const auto index = this->indexOf(path); const auto newCount = FMH::getFileInfoModel(path)[FMH::MODEL_KEY::COUNT].toInt(); const auto count = newCount - oldCount; this->list[index][FMH::MODEL_KEY::COUNT] = QString::number(count); emit this->updateModel(index, {FMH::MODEL_KEY::COUNT}); } - }); - connect(fm, &FM::cloudAccountInserted, this, &PlacesList::reset); - connect(fm, &FM::cloudAccountRemoved, this, &PlacesList::reset); +#ifdef COMPONENT_ACCOUNTS + connect(MauiAccounts::instance(), &MauiAccounts::accountAdded, this, &PlacesList::reset); + connect(MauiAccounts::instance(), &MauiAccounts::accountRemoved, this, &PlacesList::reset); +#endif connect(this, &PlacesList::groupsChanged, this, &PlacesList::reset); this->setList(); } void PlacesList::watchPath(const QString& path) { - if(path.isEmpty() || !FMH::fileExists(path)) + if(path.isEmpty() || !FMH::fileExists(path) || QUrl(path).isLocalFile()) return; this->watcher->addPath(path); } PlacesList::~PlacesList() {} FMH::MODEL_LIST PlacesList::items() const { return this->list; } #ifdef Q_OS_ANDROID #else static FMH::MODEL modelPlaceInfo(const KFilePlacesModel &model, const QModelIndex &index, const FMH::PATHTYPE_KEY &type) { return FMH::MODEL { {FMH::MODEL_KEY::PATH, model.url(index).toString()}, {FMH::MODEL_KEY::URL, model.url(index).toString()}, {FMH::MODEL_KEY::ICON, model.icon(index).name()}, {FMH::MODEL_KEY::LABEL, model.text(index)}, {FMH::MODEL_KEY::NAME, model.text(index)}, {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[type]} }; } #endif static FMH::MODEL_LIST getGroup(const KFilePlacesModel &model, const FMH::PATHTYPE_KEY &type) { #ifdef Q_OS_ANDROID Q_UNUSED(model) FMH::MODEL_LIST res; switch(type) { case(FMH::PATHTYPE_KEY::PLACES_PATH): - res << FM::getDefaultPaths(); - res<< FM::packItems(UTIL::loadSettings("BOOKMARKS", "PREFERENCES", {}, "FileManager").toStringList(), FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]); + res << FMStatic::getDefaultPaths(); + res<< FMStatic::packItems(UTIL::loadSettings("BOOKMARKS", "PREFERENCES", {}, "FileManager").toStringList(), FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]); break; case(FMH::PATHTYPE_KEY::DRIVES_PATH): - res = FM::getDevices(); + res = FMStatic::getDevices(); break; default: break; } return res; #else const auto group = model.groupIndexes(static_cast(type)); return std::accumulate(group.begin(), group.end(), FMH::MODEL_LIST(), [&model, &type](FMH::MODEL_LIST &list, const QModelIndex &index) -> FMH::MODEL_LIST { list << modelPlaceInfo(model, index, type); return list; }); #endif } void PlacesList::setList() { this->list.clear(); - //this are default static places + //this are default static places //TODO move to itws own PATHTYPE_KEY::QUICK this->list << FMH::MODEL { {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::TAGS_PATH]+"fav"}, {FMH::MODEL_KEY::ICON, "love"}, {FMH::MODEL_KEY::LABEL, "Favorite"}, {FMH::MODEL_KEY::TYPE, "Quick"} }; - + +#if defined Q_OS_LINUX && !defined Q_OS_ANDROID + this->list << FMH::MODEL + { + {FMH::MODEL_KEY::PATH,"recentdocuments:///"}, + {FMH::MODEL_KEY::ICON, "view-media-recent"}, + {FMH::MODEL_KEY::LABEL, "Recent"}, + {FMH::MODEL_KEY::TYPE, "Quick"} + }; + +// this->list << FMH::MODEL +// { +// {FMH::MODEL_KEY::PATH,"kdeconnect:///"}, +// {FMH::MODEL_KEY::ICON, "phone"}, +// {FMH::MODEL_KEY::LABEL, "KDEConnect"}, +// {FMH::MODEL_KEY::TYPE, "Quick"} +// }; +#endif + for(const auto &group : this->groups) switch(group) { case FMH::PATHTYPE_KEY::PLACES_PATH: this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::PLACES_PATH); break; case FMH::PATHTYPE_KEY::APPS_PATH: this->list << FM::getAppsPath(); break; case FMH::PATHTYPE_KEY::DRIVES_PATH: this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::DRIVES_PATH); break; case FMH::PATHTYPE_KEY::REMOTE_PATH: this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::REMOTE_PATH); break; case FMH::PATHTYPE_KEY::REMOVABLE_PATH: this->list << getGroup(*this->model, FMH::PATHTYPE_KEY::REMOVABLE_PATH); break; case FMH::PATHTYPE_KEY::TAGS_PATH: this->list << this->fm->getTags(); break; +#ifdef COMPONENT_ACCOUNTS case FMH::PATHTYPE_KEY::CLOUD_PATH: - this->list << this->fm->getCloudAccounts(); + this->list << MauiAccounts::instance()->getCloudAccounts(); break; +#endif } this->setCount(); } void PlacesList::setCount() { this->watcher->removePaths(this->watcher->directories()); for(auto &data : this->list) { const auto path = data[FMH::MODEL_KEY::PATH]; - if(FM::isDir(path)) + if(FMStatic::isDir(path)) { data.insert(FMH::MODEL_KEY::COUNT, "0"); const auto count = FMH::getFileInfoModel(path)[FMH::MODEL_KEY::COUNT]; this->count.insert(path, count.toInt()); this->watchPath(path); } } } int PlacesList::indexOf(const QString& path) { const auto index = std::find_if(this->list.begin(), this->list.end(), [&path](const FMH::MODEL &item) -> bool { return item[FMH::MODEL_KEY::PATH] == path; }); return std::distance(this->list.begin(), index); } void PlacesList::reset() { emit this->preListChanged(); this->setList(); emit this->postListChanged(); } QList PlacesList::getGroups() const { return this->groups; } void PlacesList::setGroups(const QList &value) { if(this->groups == value) return; this->groups = value; emit this->groupsChanged(); } QVariantMap PlacesList::get(const int& index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); const auto model = this->list.at(index); - return FM::toMap(model); + return FMH::toMap(model); } void PlacesList::refresh() { this->reset(); } void PlacesList::clearBadgeCount(const int& index) { this->list[index][FMH::MODEL_KEY::COUNT] = "0"; emit this->updateModel(index, {FMH::MODEL_KEY::COUNT}); } -void PlacesList::addPlace(const QString& path) +void PlacesList::addPlace(const QUrl& path) { const auto it = std::find_if(this->list.rbegin(), this->list.rend(), [](const FMH::MODEL &item) -> bool{ return item[FMH::MODEL_KEY::TYPE] == FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]; }); const auto index = std::distance(it, this->list.rend()); - qDebug()<< "trying to add path to places" << path<< QDir(path).dirName(); emit this->preItemAppendedAt(index); #ifdef Q_OS_ANDROID //do android stuff until cmake works with android auto bookmarks = UTIL::loadSettings("BOOKMARKS", "PREFERENCES", {}, "FileManager").toStringList(); - bookmarks << path; + bookmarks << path.toString(); UTIL::saveSettings("BOOKMARKS", bookmarks, "PREFERENCES", "FileManager"); this->list.insert(index, FMH::getDirInfoModel(path)); #else // const auto url = QStringLiteral("file://")+path; - this->model->addPlace(QDir(path).dirName(), path); + this->model->addPlace(QDir(path.toLocalFile()).dirName(), path); this->list.insert(index, modelPlaceInfo(*this->model, this->model->closestItem(path), FMH::PATHTYPE_KEY::PLACES_PATH)); #endif emit this->postItemAppended(); } void PlacesList::removePlace(const int& index) { if(index >= this->list.size() || index < 0) return; emit this->preItemRemoved(index); #ifdef Q_OS_ANDROID auto bookmarks = UTIL::loadSettings("BOOKMARKS", "PREFERENCES", {}, "FileManager").toStringList(); bookmarks.removeOne(this->list.at(index)[FMH::MODEL_KEY::PATH]); UTIL::saveSettings("BOOKMARKS", bookmarks, "PREFERENCES", "FileManager"); #else this->model->removePlace(this->model->index(index, 0)); #endif this->list.removeAt(index); emit this->postItemRemoved(); } diff --git a/src/fm/placeslist.h b/src/fm/placeslist.h index 178dcc7..81d6c5f 100644 --- a/src/fm/placeslist.h +++ b/src/fm/placeslist.h @@ -1,70 +1,70 @@ /* * * Copyright (C) 2018 camilo * * 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 3 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, see . */ #ifndef PLACESLIST_H #define PLACESLIST_H #include #include "mauilist.h" class FM; class KFilePlacesModel; class QFileSystemWatcher; class PlacesList : public MauiList { Q_OBJECT Q_PROPERTY(QList groups READ getGroups WRITE setGroups NOTIFY groupsChanged()) public: PlacesList(QObject *parent = nullptr); ~PlacesList(); FMH::MODEL_LIST items() const override; QList getGroups() const; void setGroups(const QList &value); protected: void setList(); void reset(); public slots: QVariantMap get(const int &index) const; void refresh(); void clearBadgeCount(const int &index); - void addPlace(const QString &path); + void addPlace(const QUrl &path); void removePlace(const int &index); private: FM *fm; FMH::MODEL_LIST list; KFilePlacesModel *model; QHash count; QList groups; QFileSystemWatcher *watcher; void watchPath(const QString &path); void setCount(); int indexOf(const QString &path); signals: void groupsChanged(); }; #endif // PLACESLIST_H diff --git a/src/fm/script.sql b/src/fm/script.sql deleted file mode 100644 index ea9f829..0000000 --- a/src/fm/script.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TABLE IF NOT EXISTS BOOKMARKS ( -path TEXT PRIMARY KEY, -label TEXT, -date DATE, -test TEXT -); - -CREATE TABLE IF NOT EXISTS CLOUDS ( -server TEXT, -user TEXT, -password TEXT, -PRIMARY KEY(server, user) -); - -COMMIT; diff --git a/src/kde/kde.pri b/src/kde/kde.pri index 6215c9e..f8ea1e0 100644 --- a/src/kde/kde.pri +++ b/src/kde/kde.pri @@ -1,17 +1,17 @@ -QT += KService KNotifications KNotifications KI18n -QT += KIOCore KIOFileWidgets KIOWidgets KNTLM +QT *= KService KNotifications KNotifications KI18n +QT *= KIOCore KIOFileWidgets KIOWidgets KNTLM HEADERS += \ $$PWD/mauikde.h \ $$PWD/kdeconnect.h SOURCES += \ $$PWD/mauikde.cpp \ $$PWD/kdeconnect.cpp \ DEPENDPATH += \ $$PWD \ INCLUDEPATH += \ $$PWD \ diff --git a/src/kde/mauikde.cpp b/src/kde/mauikde.cpp index 2e0f938..63f2556 100644 --- a/src/kde/mauikde.cpp +++ b/src/kde/mauikde.cpp @@ -1,322 +1,322 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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 "mauikde.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kdeconnect.h" Q_DECLARE_METATYPE(QList) MAUIKDE::MAUIKDE(QObject *parent) : QObject(parent) { } MAUIKDE::~MAUIKDE() { } static QVariantMap createActionItem(const QString &label, const QString &actionId, const QVariant &argument = QVariant()) { QVariantMap map; map["label"] = label; map["actionId"] = actionId; if (argument.isValid()) map["actionArgument"] = argument; return map; } QVariantList MAUIKDE::services(const QUrl &url) { qDebug()<<"trying to get mimes"; QVariantList list; if (url.isValid()) { auto fileItem = new KFileItem(url); fileItem->determineMimeType(); KService::List services = KMimeTypeTrader::self()->query(fileItem->mimetype(), "Application"); if (!services.isEmpty()) foreach (const KService::Ptr service, services) { const QString text = service->name().replace('&', "&&"); QVariantMap item = createActionItem(text, "_kicker_fileItem_openWith", service->entryPath()); item["icon"] = service->icon(); item["serviceExec"] = service->exec(); list << item; } list << createActionItem(i18n("Properties"), "_kicker_fileItem_properties"); return list; } else return list; } bool MAUIKDE::sendToDevice(const QString &device, const QString &id, const QStringList &urls) { for(auto url : urls) KdeConnect::sendToDevice(device, id, url); return true; } QVariantList MAUIKDE::devices() { return KdeConnect::getDevices(); } void MAUIKDE::openWithApp(const QString &exec, const QStringList &urls) { KService service(exec); KRun::runApplication(service, QUrl::fromStringList(urls), nullptr); } void MAUIKDE::attachEmail(const QStringList &urls) { if(urls.isEmpty()) return; QFileInfo file(urls[0]); KToolInvocation::invokeMailer("", "", "", file.baseName(), "Files shared... ", "", urls); // QDesktopServices::openUrl(QUrl("mailto:?subject=test&body=test&attachment;=" // + url)); } void MAUIKDE::email(const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, const QString &messageFile, const QStringList &urls) { KToolInvocation::invokeMailer(to, cc, bcc, subject, body, messageFile, urls); // QDesktopServices::openUrl(QUrl("mailto:?subject=test&body=test&attachment;=" // + url)); } void MAUIKDE::setColorScheme(const QString &schemeName, const QString &bg, const QString &fg) { const QString colorSchemeDir = FMH::DataPath+"/color-schemes/"; const QString colorsFile = colorSchemeDir+schemeName+".colors"; if(!FMH::fileExists(colorSchemeDir)) QDir(colorSchemeDir).mkpath("."); if(!FMH::fileExists(colorsFile)) { QFile color_scheme_file(":/assets/maui-app.colors"); if(color_scheme_file.copy(colorsFile)) { QFile copied_scheme_file(colorsFile); copied_scheme_file.setPermissions(QFile::ReadOwner|QFile::WriteOwner|QFile::ExeOwner|QFile::ReadGroup|QFile::ExeGroup|QFile::ReadOther|QFile::ExeOther); KConfig new_scheme_file(colorsFile); auto new_scheme_name = new_scheme_file.group("General"); new_scheme_name.writeEntry("Name", QVariant(schemeName)); new_scheme_name.writeEntry("ColorScheme", QVariant(schemeName)); } } KColorSchemeManager manager; auto schemeModel = manager.indexForScheme(schemeName); if(!schemeModel.isValid() && FMH::fileExists(colorsFile)) { qDebug()<< "COLROS FILE EXISTS BUT IS INVALID"; KConfig scheme_file(colorsFile); auto scheme_name = scheme_file.group("General"); scheme_name.writeEntry("Name", QVariant(schemeName)); scheme_name.writeEntry("ColorScheme", QVariant(schemeName)); } schemeModel = manager.indexForScheme(schemeName); if(schemeModel.isValid()) { qDebug()<<"COLRO SCHEME IS VALID"; if(!bg.isEmpty() || !fg.isEmpty()) { qDebug()<<"COLRO SCHEME FILE EXISTS"<< colorsFile; KConfig file(colorsFile); auto group = file.group("WM"); QColor color; if(!bg.isEmpty()) { color.setNamedColor(bg); QVariantList rgb = {color.red(), color.green(), color.blue()}; group.writeEntry("activeBackground", QVariant::fromValue(rgb)); group.writeEntry("inactiveBackground", QVariant::fromValue(rgb)); } if(!fg.isEmpty()) { color.setNamedColor(fg); QVariantList rgb = {color.red(), color.green(), color.blue()}; group.writeEntry("activeForeground", QVariant::fromValue(rgb)); group.writeEntry("inactiveForeground", QVariant::fromValue(rgb)); } file.group("Colors:Window"); if(!bg.isEmpty()) { color.setNamedColor(bg); QVariantList rgb = {color.red(), color.green(), color.blue()}; group.writeEntry("BackgroundNormal", QVariant::fromValue(rgb)); group.writeEntry("BackgroundAlternate", QVariant::fromValue(rgb)); } if(!fg.isEmpty()) { color.setNamedColor(fg); QVariantList rgb = {color.red(), color.green(), color.blue()}; group.writeEntry("ForegroundActive", QVariant::fromValue(rgb)); group.writeEntry("ForegroundInactive", QVariant::fromValue(rgb)); } } manager.activateScheme(schemeModel); } } FMH::MODEL_LIST MAUIKDE::getApps() { FMH::MODEL_LIST res; KServiceGroup::Ptr group = KServiceGroup::root(); bool sortByGenericName = false; KServiceGroup::List list = group->entries(true /* sorted */, true /* excludeNoDisplay */, true /* allowSeparators */, sortByGenericName /* sortByGenericName */); for (KServiceGroup::List::ConstIterator it = list.constBegin(); it != list.constEnd(); it++) { const KSycocaEntry::Ptr p = (*it); if (p->isType(KST_KServiceGroup)) { KServiceGroup::Ptr s(static_cast(p.data())); if (!s->noDisplay() && s->childCount() > 0) { qDebug()<< "Getting app"<icon(); res << FMH::MODEL { {FMH::MODEL_KEY::ICON, s->icon()}, {FMH::MODEL_KEY::LABEL, s->name()}, {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::APPS_PATH]+s->entryPath()} }; } } } return res; } FMH::MODEL_LIST MAUIKDE::getApps(const QString &groupStr) { const auto grp = QString(groupStr).replace("/", "")+"/"; qDebug() << "APP GROUDP" << groupStr<< grp; if(grp.isEmpty()) return getApps(); FMH::MODEL_LIST res; // const KServiceGroup::Ptr group(static_cast(groupStr)); auto group = new KServiceGroup(grp); KServiceGroup::List list = group->entries(true /* sorted */, true /* excludeNoDisplay */, false /* allowSeparators */, true /* sortByGenericName */); for (KServiceGroup::List::ConstIterator it = list.constBegin(); it != list.constEnd(); it++) { const KSycocaEntry::Ptr p = (*it); if (p->isType(KST_KService)) { const KService::Ptr s(static_cast(p.data())); if (s->noDisplay()) continue; res << FMH::MODEL { {FMH::MODEL_KEY::ICON, s->icon()}, {FMH::MODEL_KEY::EXECUTABLE, "true"}, {FMH::MODEL_KEY::LABEL, s->name()}, {FMH::MODEL_KEY::PATH, s->entryPath()} }; } else if (p->isType(KST_KServiceSeparator)) { qDebug()<< "separator wtf"; } else if (p->isType(KST_KServiceGroup)) { const KServiceGroup::Ptr s(static_cast(p.data())); if (s->childCount() == 0) continue; res << FMH::MODEL { {FMH::MODEL_KEY::ICON, s->icon()}, {FMH::MODEL_KEY::EXECUTABLE, "true"}, {FMH::MODEL_KEY::LABEL, s->name()}, {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::APPS_PATH]+s->entryPath()} }; } } return res; } void MAUIKDE::launchApp(const QString &app) { KService service(app); - KRun::runApplication(service,{}, nullptr); + KRun::runApplication(service, {}, nullptr); } diff --git a/maui-style/.gitignore b/src/maui-style/.gitignore similarity index 100% rename from maui-style/.gitignore rename to src/maui-style/.gitignore diff --git a/maui-style/ApplicationWindow.qml b/src/maui-style/ApplicationWindow.qml similarity index 100% rename from maui-style/ApplicationWindow.qml rename to src/maui-style/ApplicationWindow.qml diff --git a/maui-style/BusyIndicator.qml b/src/maui-style/BusyIndicator.qml similarity index 100% rename from maui-style/BusyIndicator.qml rename to src/maui-style/BusyIndicator.qml diff --git a/maui-style/Button.qml b/src/maui-style/Button.qml similarity index 100% rename from maui-style/Button.qml rename to src/maui-style/Button.qml diff --git a/maui-style/CheckBox.qml b/src/maui-style/CheckBox.qml similarity index 100% rename from maui-style/CheckBox.qml rename to src/maui-style/CheckBox.qml diff --git a/maui-style/CheckIndicator.qml b/src/maui-style/CheckIndicator.qml similarity index 100% rename from maui-style/CheckIndicator.qml rename to src/maui-style/CheckIndicator.qml diff --git a/maui-style/ComboBox.qml b/src/maui-style/ComboBox.qml similarity index 100% rename from maui-style/ComboBox.qml rename to src/maui-style/ComboBox.qml diff --git a/maui-style/Container.qml b/src/maui-style/Container.qml similarity index 100% rename from maui-style/Container.qml rename to src/maui-style/Container.qml diff --git a/maui-style/Control.qml b/src/maui-style/Control.qml similarity index 100% rename from maui-style/Control.qml rename to src/maui-style/Control.qml diff --git a/maui-style/Dial.qml b/src/maui-style/Dial.qml similarity index 100% rename from maui-style/Dial.qml rename to src/maui-style/Dial.qml diff --git a/maui-style/Dialog.qml b/src/maui-style/Dialog.qml similarity index 100% rename from maui-style/Dialog.qml rename to src/maui-style/Dialog.qml diff --git a/maui-style/DialogButtonBox.qml b/src/maui-style/DialogButtonBox.qml similarity index 100% rename from maui-style/DialogButtonBox.qml rename to src/maui-style/DialogButtonBox.qml diff --git a/maui-style/Drawer.qml b/src/maui-style/Drawer.qml similarity index 100% rename from maui-style/Drawer.qml rename to src/maui-style/Drawer.qml diff --git a/maui-style/Frame.qml b/src/maui-style/Frame.qml similarity index 100% rename from maui-style/Frame.qml rename to src/maui-style/Frame.qml diff --git a/maui-style/GroupBox.qml b/src/maui-style/GroupBox.qml similarity index 100% rename from maui-style/GroupBox.qml rename to src/maui-style/GroupBox.qml diff --git a/maui-style/ItemDelegate.qml b/src/maui-style/ItemDelegate.qml similarity index 100% rename from maui-style/ItemDelegate.qml rename to src/maui-style/ItemDelegate.qml diff --git a/maui-style/LICENSE b/src/maui-style/LICENSE similarity index 100% rename from maui-style/LICENSE rename to src/maui-style/LICENSE diff --git a/maui-style/Label.qml b/src/maui-style/Label.qml similarity index 100% rename from maui-style/Label.qml rename to src/maui-style/Label.qml diff --git a/maui-style/Menu.qml b/src/maui-style/Menu.qml similarity index 100% rename from maui-style/Menu.qml rename to src/maui-style/Menu.qml diff --git a/maui-style/MenuItem.qml b/src/maui-style/MenuItem.qml similarity index 100% rename from maui-style/MenuItem.qml rename to src/maui-style/MenuItem.qml diff --git a/maui-style/Page.qml b/src/maui-style/Page.qml similarity index 100% rename from maui-style/Page.qml rename to src/maui-style/Page.qml diff --git a/maui-style/Popup.qml b/src/maui-style/Popup.qml similarity index 100% rename from maui-style/Popup.qml rename to src/maui-style/Popup.qml diff --git a/maui-style/ProgressBar.qml b/src/maui-style/ProgressBar.qml similarity index 100% rename from maui-style/ProgressBar.qml rename to src/maui-style/ProgressBar.qml diff --git a/maui-style/README.md b/src/maui-style/README.md similarity index 100% rename from maui-style/README.md rename to src/maui-style/README.md diff --git a/maui-style/RangeSlider.qml b/src/maui-style/RangeSlider.qml similarity index 100% rename from maui-style/RangeSlider.qml rename to src/maui-style/RangeSlider.qml diff --git a/maui-style/ScrollBar.qml b/src/maui-style/ScrollBar.qml similarity index 100% rename from maui-style/ScrollBar.qml rename to src/maui-style/ScrollBar.qml diff --git a/maui-style/ScrollView.qml b/src/maui-style/ScrollView.qml similarity index 100% rename from maui-style/ScrollView.qml rename to src/maui-style/ScrollView.qml diff --git a/maui-style/Slider.qml b/src/maui-style/Slider.qml similarity index 100% rename from maui-style/Slider.qml rename to src/maui-style/Slider.qml diff --git a/maui-style/SpinBox.qml b/src/maui-style/SpinBox.qml similarity index 100% rename from maui-style/SpinBox.qml rename to src/maui-style/SpinBox.qml diff --git a/maui-style/SwipeView.qml b/src/maui-style/SwipeView.qml similarity index 100% rename from maui-style/SwipeView.qml rename to src/maui-style/SwipeView.qml diff --git a/maui-style/Switch.qml b/src/maui-style/Switch.qml similarity index 100% rename from maui-style/Switch.qml rename to src/maui-style/Switch.qml diff --git a/maui-style/SwitchDelegate.qml b/src/maui-style/SwitchDelegate.qml similarity index 100% rename from maui-style/SwitchDelegate.qml rename to src/maui-style/SwitchDelegate.qml diff --git a/maui-style/SwitchIndicator.qml b/src/maui-style/SwitchIndicator.qml similarity index 100% rename from maui-style/SwitchIndicator.qml rename to src/maui-style/SwitchIndicator.qml diff --git a/maui-style/TabBar.qml b/src/maui-style/TabBar.qml similarity index 100% rename from maui-style/TabBar.qml rename to src/maui-style/TabBar.qml diff --git a/maui-style/TabButton.qml b/src/maui-style/TabButton.qml similarity index 100% rename from maui-style/TabButton.qml rename to src/maui-style/TabButton.qml diff --git a/maui-style/TextArea.qml b/src/maui-style/TextArea.qml similarity index 100% rename from maui-style/TextArea.qml rename to src/maui-style/TextArea.qml diff --git a/maui-style/TextField.qml b/src/maui-style/TextField.qml similarity index 100% rename from maui-style/TextField.qml rename to src/maui-style/TextField.qml diff --git a/maui-style/ToolBar.qml b/src/maui-style/ToolBar.qml similarity index 100% rename from maui-style/ToolBar.qml rename to src/maui-style/ToolBar.qml diff --git a/maui-style/ToolButton.qml b/src/maui-style/ToolButton.qml similarity index 100% rename from maui-style/ToolButton.qml rename to src/maui-style/ToolButton.qml diff --git a/maui-style/ToolTip.qml b/src/maui-style/ToolTip.qml similarity index 100% rename from maui-style/ToolTip.qml rename to src/maui-style/ToolTip.qml diff --git a/maui-style/private/DefaultListItemBackground.qml b/src/maui-style/private/DefaultListItemBackground.qml similarity index 100% rename from maui-style/private/DefaultListItemBackground.qml rename to src/maui-style/private/DefaultListItemBackground.qml diff --git a/maui-style/style.qrc b/src/maui-style/style.qrc similarity index 100% rename from maui-style/style.qrc rename to src/maui-style/style.qrc diff --git a/src/mauikit.cpp b/src/mauikit.cpp index 48385e3..9a9e6f7 100644 --- a/src/mauikit.cpp +++ b/src/mauikit.cpp @@ -1,196 +1,227 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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 "mauikit.h" #include -#include "fm.h" -#include "fmh.h" - +#include "handy.h" #include "mauimodel.h" #include "mauilist.h" +#include "pathlist.h" +#include "mauiapp.h" +#include "fmstatic.h" + +#ifdef COMPONENT_ACCOUNTS +#include "mauiaccounts.h" +#endif + +#ifdef COMPONENT_FM +#include "fm.h" #include "placeslist.h" #include "fmlist.h" -#include "pathlist.h" +#endif +#ifdef COMPONENT_TAGGING #include "tagsmodel.h" #include "tagslist.h" +#endif +#ifdef COMPONENT_STORE #include "storemodel.h" #include "storelist.h" +#endif -#include "handy.h" +#ifdef COMPONENT_EDITOR #include "documenthandler.h" #include "syntaxhighlighterutil.h" -#include "mauiaccounts.h" -#include "mauiapp.h" +#ifdef STATIC_MAUIKIT +#include "kquicksyntaxhighlighter/kquicksyntaxhighlighter.h" +#endif + +#endif #ifdef Q_OS_ANDROID #include "mauiandroid.h" #else #include "mauikde.h" #endif -#if defined Q_OS_ANDROID || defined APPIMAGE_PACKAGE +#if defined Q_OS_ANDROID || defined APPIMAGE_PACKAGE || defined MAUIKIT_STYLE #include #include #endif -#ifdef STATIC_MAUIKIT -#include "kquicksyntaxhighlighter/kquicksyntaxhighlighter.h" -#endif - - - QUrl MauiKit::componentUrl(const QString &fileName) const { #ifdef MAUI_APP return QUrl(QStringLiteral("qrc:/maui/kit/") + fileName); #else return QUrl(resolveFileUrl(fileName)); #endif } void MauiKit::registerTypes(const char *uri) { - + Q_ASSERT(uri == QLatin1String("org.kde.mauikit")); qmlRegisterSingletonType(componentUrl(QStringLiteral("Style.qml")), uri, 1, 0, "Style"); qmlRegisterType(componentUrl(QStringLiteral("ToolBar.qml")), uri, 1, 0, "ToolBar"); qmlRegisterType(componentUrl(QStringLiteral("ApplicationWindow.qml")), uri, 1, 0, "ApplicationWindow"); qmlRegisterType(componentUrl(QStringLiteral("Page.qml")), uri, 1, 0, "Page"); qmlRegisterType(componentUrl(QStringLiteral("ShareDialog.qml")), uri, 1, 0, "ShareDialog"); qmlRegisterType(componentUrl(QStringLiteral("PieButton.qml")), uri, 1, 0, "PieButton"); - qmlRegisterType(componentUrl(QStringLiteral("SideBar.qml")), uri, 1, 0, "SideBar"); - qmlRegisterType(componentUrl(QStringLiteral("AbstractSideBar.qml")), uri, 1, 0, "AbstractSideBar"); - qmlRegisterType(componentUrl(QStringLiteral("Holder.qml")), uri, 1, 0, "Holder"); + qmlRegisterType(componentUrl(QStringLiteral("SideBar.qml")), uri, 1, 0, "SideBar"); + qmlRegisterType(componentUrl(QStringLiteral("AbstractSideBar.qml")), uri, 1, 0, "AbstractSideBar"); + qmlRegisterType(componentUrl(QStringLiteral("Holder.qml")), uri, 1, 0, "Holder"); qmlRegisterType(componentUrl(QStringLiteral("GlobalDrawer.qml")), uri, 1, 0, "GlobalDrawer"); qmlRegisterType(componentUrl(QStringLiteral("ListDelegate.qml")), uri, 1, 0, "ListDelegate"); qmlRegisterType(componentUrl(QStringLiteral("ListBrowserDelegate.qml")), uri, 1, 0, "ListBrowserDelegate"); - qmlRegisterType(componentUrl(QStringLiteral("SwipeItemDelegate.qml")), uri, 1, 0, "SwipeItemDelegate"); - qmlRegisterType(componentUrl(QStringLiteral("ItemDelegate.qml")), uri, 1, 0, "ItemDelegate"); - qmlRegisterType(componentUrl(QStringLiteral("GridBrowserDelegate.qml")), uri, 1, 0, "GridBrowserDelegate"); + qmlRegisterType(componentUrl(QStringLiteral("SwipeItemDelegate.qml")), uri, 1, 0, "SwipeItemDelegate"); + qmlRegisterType(componentUrl(QStringLiteral("SwipeBrowserDelegate.qml")), uri, 1, 0, "SwipeBrowserDelegate"); + qmlRegisterType(componentUrl(QStringLiteral("ItemDelegate.qml")), uri, 1, 0, "ItemDelegate"); + qmlRegisterType(componentUrl(QStringLiteral("GridBrowserDelegate.qml")), uri, 1, 0, "GridBrowserDelegate"); qmlRegisterType(componentUrl(QStringLiteral("SelectionBar.qml")), uri, 1, 0, "SelectionBar"); qmlRegisterType(componentUrl(QStringLiteral("LabelDelegate.qml")), uri, 1, 0, "LabelDelegate"); qmlRegisterType(componentUrl(QStringLiteral("NewDialog.qml")), uri, 1, 0, "NewDialog"); qmlRegisterType(componentUrl(QStringLiteral("Dialog.qml")), uri, 1, 0, "Dialog"); qmlRegisterType(componentUrl(QStringLiteral("AboutDialog.qml")), uri, 1, 0, "AboutDialog"); qmlRegisterType(componentUrl(QStringLiteral("Popup.qml")), uri, 1, 0, "Popup"); qmlRegisterType(componentUrl(QStringLiteral("TextField.qml")), uri, 1, 0, "TextField"); qmlRegisterType(componentUrl(QStringLiteral("Badge.qml")), uri, 1, 0, "Badge"); qmlRegisterType(componentUrl(QStringLiteral("GridView.qml")), uri, 1, 0, "GridView"); qmlRegisterType(componentUrl(QStringLiteral("ColorsBar.qml")), uri, 1, 0, "ColorsBar"); - qmlRegisterType(componentUrl(QStringLiteral("ImageViewer.qml")), uri, 1, 0, "ImageViewer"); + qmlRegisterType(componentUrl(QStringLiteral("ImageViewer.qml")), uri, 1, 0, "ImageViewer"); + qmlRegisterType(componentUrl(QStringLiteral("TabBar.qml")), uri, 1, 0, "TabBar"); + qmlRegisterType(componentUrl(QStringLiteral("TabButton.qml")), uri, 1, 0, "TabButton"); + + qmlRegisterType(componentUrl(QStringLiteral("PathBar.qml")), uri, 1, 0, "PathBar"); + qmlRegisterType(uri, 1, 0, "PathList"); /** STORE CONTROLS, MODELS AND INTERFACES **/ +#ifdef COMPONENT_STORE qmlRegisterType("StoreList", 1, 0, "StoreList"); qmlRegisterType("StoreModel", 1, 0, "StoreModel"); qmlRegisterType(componentUrl(QStringLiteral("private/StoreDelegate.qml")), uri, 1, 0, "StoreDelegate"); qmlRegisterType(componentUrl(QStringLiteral("Store.qml")), uri, 1, 0, "Store"); +#endif /** BROWSING CONTROLS **/ qmlRegisterType(componentUrl(QStringLiteral("ListBrowser.qml")), uri, 1, 0, "ListBrowser"); qmlRegisterType(componentUrl(QStringLiteral("GridBrowser.qml")), uri, 1, 0, "GridBrowser"); /** FM CONTROLS, MODELS AND INTERFACES **/ +#ifdef COMPONENT_FM qmlRegisterType(uri, 1, 0, "PlacesList"); qmlRegisterType(uri, 1, 0, "FMList"); - qmlRegisterType(uri, 1, 0, "PathList"); - qmlRegisterSingletonType(uri, 1, 0, "FM", - [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* { + qmlRegisterSingletonType(uri, 1, 0, "FM", + [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* { Q_UNUSED(engine) Q_UNUSED(scriptEngine) - return new FM; + return new FMStatic; }); // qmlRegisterSingletonType(componentUrl(QStringLiteral("private/FileBrowser.qml")), uri, 1, 0, "FileMenu"); qmlRegisterType(componentUrl(QStringLiteral("FileBrowser.qml")), uri, 1, 0, "FileBrowser"); - qmlRegisterType(componentUrl(QStringLiteral("PlacesSidebar.qml")), uri, 1, 0, "PlacesSidebar"); - qmlRegisterType(componentUrl(QStringLiteral("PlacesListBrowser.qml")), uri, 1, 0, "PlacesListBrowser"); - qmlRegisterType(componentUrl(QStringLiteral("FilePreviewer.qml")), uri, 1, 0, "FilePreviewer"); + qmlRegisterType(componentUrl(QStringLiteral("PlacesSidebar.qml")), uri, 1, 0, "PlacesSidebar"); + qmlRegisterType(componentUrl(QStringLiteral("PlacesListBrowser.qml")), uri, 1, 0, "PlacesListBrowser"); + qmlRegisterType(componentUrl(QStringLiteral("FilePreviewer.qml")), uri, 1, 0, "FilePreviewer"); qmlRegisterType(componentUrl(QStringLiteral("FileDialog.qml")), uri, 1, 0, "FileDialog"); - qmlRegisterType(componentUrl(QStringLiteral("PathBar.qml")), uri, 1, 0, "PathBar"); - qmlRegisterType(componentUrl(QStringLiteral("SyncDialog.qml")), uri, 1, 0, "SyncDialog"); //to be rename to accountsDialog - +#endif + +#ifdef COMPONENT_EDITOR /** EDITOR CONTROLS **/ qmlRegisterType(uri, 1, 0, "DocumentHandler"); qmlRegisterType(); qmlRegisterType(componentUrl(QStringLiteral("Editor.qml")), uri, 1, 0, "Editor"); + #ifdef STATIC_MAUIKIT qmlRegisterType("org.kde.kquicksyntaxhighlighter", 0, 1, "KQuickSyntaxHighlighter"); +#endif + #endif /** PLATFORMS SPECIFIC CONTROLS **/ #ifdef Q_OS_ANDROID qmlRegisterSingletonType(uri, 1, 0, "Android", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return new MAUIAndroid; }); #else qmlRegisterType(componentUrl(QStringLiteral("Terminal.qml")), uri, 1, 0, "Terminal"); qmlRegisterSingletonType(uri, 1, 0, "KDE", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return new MAUIKDE; }); #endif /** DATA MODELING TEMPLATED INTERFACES **/ qmlRegisterType(); //ABSTRACT BASE LIST qmlRegisterType(uri, 1, 0, "BaseModel"); //BASE MODEL /** TAGGING INTERFACES AND MODELS **/ +#ifdef COMPONENT_TAGGING qmlRegisterType("TagsList", 1, 0, "TagsList"); qmlRegisterType("TagsModel", 1, 0, "TagsModel"); qmlRegisterType(componentUrl(QStringLiteral("private/TagList.qml")), uri, 1, 0, "TagList"); qmlRegisterType(componentUrl(QStringLiteral("TagsBar.qml")), uri, 1, 0, "TagsBar"); qmlRegisterType(componentUrl(QStringLiteral("TagsDialog.qml")), uri, 1, 0, "TagsDialog"); +#endif /** MAUI APPLICATION SPECIFIC PROPS **/ + +#ifdef COMPONENT_ACCOUNTS qmlRegisterType(); + qmlRegisterType(componentUrl(QStringLiteral("SyncDialog.qml")), uri, 1, 0, "SyncDialog"); //to be rename to accountsDialog +#endif qmlRegisterUncreatableType(uri, 1, 0, "App", "Cannot be created App"); /** HELPERS **/ qmlRegisterSingletonType(uri, 1, 0, "Handy", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject* { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return new Handy; }); -#if defined Q_OS_ANDROID || defined APPIMAGE_PACKAGE - Q_INIT_RESOURCE(mauikit); - Q_INIT_RESOURCE(icons); - Q_INIT_RESOURCE(style); - QIcon::setThemeSearchPaths({":/icons/luv-icon-theme"}); +#if defined Q_OS_ANDROID || defined APPIMAGE_PACKAGE || defined MAUIKIT_STYLE + this->initResources(); +#endif + + qmlProtectModule(uri, 1); +} + +void MauiKit::initResources() +{ +#if defined QICON_H && defined QQUICKSTYLE_H + Q_INIT_RESOURCE(mauikit); + Q_INIT_RESOURCE(icons); + Q_INIT_RESOURCE(style); + QIcon::setThemeSearchPaths({":/icons/luv-icon-theme"}); QIcon::setThemeName("Luv"); QQuickStyle::setStyle(":/style"); #endif - - qmlProtectModule(uri, 1); } #include "moc_mauikit.cpp" - - diff --git a/src/mauikit.h b/src/mauikit.h index 199af7c..f7f1b58 100644 --- a/src/mauikit.h +++ b/src/mauikit.h @@ -1,76 +1,88 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ #ifndef MAUIKIT_H #define MAUIKIT_H #define MAUIKIT_VERSION "1.0.2" #include #include +#ifndef STATIC_MAUIKIT +#include "mauikit_export.h" +#endif + +class MauiAccounts; +#ifdef STATIC_MAUIKIT class MauiKit : public QQmlExtensionPlugin +#else +class MAUIKIT_EXPORT MauiKit : public QQmlExtensionPlugin +#endif { Q_OBJECT #ifndef STATIC_MAUIKIT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") #endif public: void registerTypes(const char *uri) Q_DECL_OVERRIDE; static MauiKit& getInstance() { static MauiKit instance; return instance; } static void registerTypes() { static MauiKit instance; instance.registerTypes("org.kde.mauikit"); - } + } + + void initResources(); + private: QUrl componentUrl(const QString &fileName) const; QString resolveFilePath(const QString &path) const { #ifdef STATIC_MAUIKIT return QStringLiteral(":/org/kde/mauikit/") + path; #else return baseUrl().toLocalFile() + QLatin1Char('/') + path; #endif } QString resolveFileUrl(const QString &filePath) const { #ifdef STATIC_MAUIKIT return filePath; #else return baseUrl().toString() + QLatin1Char('/') + filePath; #endif } signals: public slots: }; #endif // MAUIKIT_H diff --git a/src/mauikit.qrc b/src/mauikit.qrc new file mode 100644 index 0000000..1969c79 --- /dev/null +++ b/src/mauikit.qrc @@ -0,0 +1,62 @@ + + + controls/ToolBar.qml + controls/AbstractSideBar.qml + controls/SideBar.qml + controls/ApplicationWindow.qml + controls/Style.qml + controls/ShareDialog.qml + controls/PieButton.qml + controls/Page.qml + controls/private/PathBarDelegate.qml + controls/private/EdgeShadow.qml + controls/private/BrowserMenu.qml + controls/private/BrowserView.qml + controls/private/BrowserSettings.qml + controls/private/BrowserHolder.qml + controls/private/FileMenu.qml + controls/private/AudioPreview.qml + controls/private/ImagePreview.qml + controls/private/TextPreview.qml + controls/private/VideoPreview.qml + controls/private/AccountsHelper.qml + controls/Holder.qml + controls/ListDelegate.qml + controls/ItemDelegate.qml + controls/SwipeItemDelegate.qml + controls/SwipeBrowserDelegate.qml + controls/GridBrowserDelegate.qml + controls/ListBrowserDelegate.qml + controls/GlobalDrawer.qml + controls/SelectionBar.qml + controls/LabelDelegate.qml + controls/NewDialog.qml + controls/TagsBar.qml + controls/TagsDialog.qml + controls/private/TagList.qml + controls/private/TagDelegate.qml + controls/ColorsBar.qml + controls/FileBrowser.qml + controls/FilePreviewer.qml + controls/FileDialog.qml + controls/ListBrowser.qml + controls/PathBar.qml + controls/GridBrowser.qml + controls/Dialog.qml + controls/AboutDialog.qml + controls/Popup.qml + controls/TextField.qml + controls/Badge.qml + controls/GridView.qml + controls/SyncDialog.qml + controls/Terminal.qml + controls/Editor.qml + controls/PlacesSidebar.qml + controls/PlacesListBrowser.qml + controls/Store.qml + controls/ImageViewer.qml + controls/TabBar.qml + controls/TabButton.qml + controls/private/StoreDelegate.qml + + diff --git a/src/fm/fm.qrc b/src/utils/accounts/accounts.qrc similarity index 63% rename from src/fm/fm.qrc rename to src/utils/accounts/accounts.qrc index 032ae64..f35ef92 100644 --- a/src/fm/fm.qrc +++ b/src/utils/accounts/accounts.qrc @@ -1,5 +1,5 @@ - + script.sql diff --git a/src/fm/fmdb.cpp b/src/utils/accounts/accountsdb.cpp similarity index 79% rename from src/fm/fmdb.cpp rename to src/utils/accounts/accountsdb.cpp index f3de2b5..c7915d0 100644 --- a/src/fm/fmdb.cpp +++ b/src/utils/accounts/accountsdb.cpp @@ -1,223 +1,236 @@ -#include "fmdb.h" -#include"utils.h" +#include "accountsdb.h" +#include "utils.h" #include -FMDB::FMDB(QObject *parent) : QObject(parent) +#ifdef Q_OS_ANDROID +#include "mauiandroid.h" +#endif + +const QString FMPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)+"/maui/"; +const QString DBName = "accounts.db"; + +AccountsDB::AccountsDB(QObject *parent) : QObject(parent) { - QDir collectionDBPath_dir(FMH::FMPath); + //get permissions to read and write +#ifdef Q_OS_ANDROID + MAUIAndroid::checkRunTimePermissions(); +#endif + + qDebug()<< "TRY TO CREATE ACCOUNTS DB"; + QDir collectionDBPath_dir(FMPath); if (!collectionDBPath_dir.exists()) collectionDBPath_dir.mkpath("."); this->name = QUuid::createUuid().toString(); - if(!UTIL::fileExists(FMH::FMPath + FMH::DBName)) + if(!UTIL::fileExists(FMPath + DBName)) { this->openDB(this->name); this->prepareCollectionDB(); }else this->openDB(this->name); } -FMDB::~FMDB() +AccountsDB::~AccountsDB() { this->m_db.close(); } -void FMDB::openDB(const QString &name) +void AccountsDB::openDB(const QString &name) { if(!QSqlDatabase::contains(name)) { this->m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), name); - this->m_db.setDatabaseName(FMH::FMPath + FMH::DBName); + this->m_db.setDatabaseName(FMPath + DBName); } if (!this->m_db.isOpen()) { if(!this->m_db.open()) qDebug()<<"ERROR OPENING DB"<m_db.lastError().text()<getQuery("PRAGMA synchronous=OFF"); query.exec(); } -void FMDB::prepareCollectionDB() const +void AccountsDB::prepareCollectionDB() const { QSqlQuery query(this->m_db); - QFile file(":/fm/script.sql"); + QFile file(":/accounts/script.sql"); if (!file.exists()) { QString log = QStringLiteral("Fatal error on build database. The file '"); log.append(file.fileName() + QStringLiteral("' for database and tables creation query cannot be not found!")); qDebug()<getQuery(queryStr); if (query.exec()) { if (query.next()) return true; }else qDebug()<getQuery(queryStr); if (query.exec()) { if (query.next()) return true; }else qDebug()<m_db); return query; } -bool FMDB::insert(const QString &tableName, const QVariantMap &insertData) +bool AccountsDB::insert(const QString &tableName, const QVariantMap &insertData) { if (tableName.isEmpty()) { qDebug()<m_db); query.prepare(sqlQueryString); int k = 0; foreach (const QVariant &value, values) query.bindValue(k++, value); return query.exec(); } -bool FMDB::update(const QString &tableName, const FMH::DB &updateData, const QVariantMap &where) +bool AccountsDB::update(const QString &tableName, const FMH::MODEL &updateData, const QVariantMap &where) { if (tableName.isEmpty()) { qDebug()<getQuery(sqlQueryString); qDebug()<getQuery(queryStr); return query.exec(); } -bool FMDB::remove(const QString &tableName, const FMH::DB &removeData) +bool AccountsDB::remove(const QString &tableName, const FMH::MODEL &removeData) { if (tableName.isEmpty()) { qDebug()< 1 && igetQuery(sqlQueryString).exec(); } diff --git a/src/fm/fmdb.h b/src/utils/accounts/accountsdb.h similarity index 54% rename from src/fm/fmdb.h rename to src/utils/accounts/accountsdb.h index f281e3a..6e120d0 100644 --- a/src/fm/fmdb.h +++ b/src/utils/accounts/accountsdb.h @@ -1,61 +1,49 @@ -#ifndef FMDB_H -#define FMDB_H +#ifndef ACCOUNTSDB_H +#define ACCOUNTSDB_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fmh.h" -#ifndef STATIC_MAUIKIT -#include "mauikit_export.h" -#endif - -#ifdef STATIC_MAUIKIT -class FMDB : public QObject -#else -class MAUIKIT_EXPORT FMDB : public QObject -#endif +class AccountsDB : public QObject { Q_OBJECT private: QString name; QSqlDatabase m_db; public: /* utils*/ - Q_INVOKABLE bool checkExistance(const QString &tableName, const QString &searchId, const QString &search); - Q_INVOKABLE bool checkExistance(const QString &queryStr); - -protected: - FMDB(QObject *parent = nullptr); - ~ FMDB(); - + explicit AccountsDB(QObject *parent = nullptr); + ~ AccountsDB(); + bool checkExistance(const QString &tableName, const QString &searchId, const QString &search); + bool checkExistance(const QString &queryStr); QSqlQuery getQuery(const QString &queryTxt); void openDB(const QString &name); void prepareCollectionDB() const; bool insert(const QString &tableName, const QVariantMap &insertData); - bool update(const QString &tableName, const FMH::DB &updateData, const QVariantMap &where); + bool update(const QString &tableName, const FMH::MODEL &updateData, const QVariantMap &where); bool update(const QString &table, const QString &column, const QVariant &newValue, const QVariant &op, const QString &id); - bool remove(const QString &tableName, const FMH::DB &removeData); + bool remove(const QString &tableName, const FMH::MODEL &removeData); signals: public slots: }; - -#endif // FMDB_H +#endif // ACCOUNTSDB_H diff --git a/src/utils/accounts/mauiaccounts.cpp b/src/utils/accounts/mauiaccounts.cpp new file mode 100644 index 0000000..2c6d6f3 --- /dev/null +++ b/src/utils/accounts/mauiaccounts.cpp @@ -0,0 +1,218 @@ +/* + * + * Copyright (C) 2019 camilo + * + * 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 3 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, see . + */ + +#include "mauiaccounts.h" +#include "accountsdb.h" + +MauiAccounts::MauiAccounts(QObject *parent) : MauiList(parent), +db(new AccountsDB(parent)) +{ + this->setAccounts(); +} + +MauiAccounts::~MauiAccounts() +{ +} + +MauiAccounts *MauiAccounts::m_instance = nullptr; +MauiAccounts *MauiAccounts::instance(QObject *parent) +{ + if(MauiAccounts::m_instance == nullptr) + MauiAccounts::m_instance = new MauiAccounts(parent); + + return MauiAccounts::m_instance; +} + +FMH::MODEL_LIST MauiAccounts::items() const +{ + return this->m_data; +} + +void MauiAccounts::setAccounts() +{ + emit this->preListChanged(); + this->m_data = this->getCloudAccounts(); + qDebug()<< "ACCOUNTS LIST"<< this->m_data; + + this->m_count = this->m_data.count(); + emit this->countChanged(this->m_count); + emit this->postListChanged(); +} + +FMH::MODEL_LIST MauiAccounts::getCloudAccounts() +{ + auto accounts = this->get("select * from cloud"); + FMH::MODEL_LIST res; + for(const auto &account : accounts) + { + auto map = account.toMap(); + res << FMH::MODEL { + {FMH::MODEL_KEY::PATH, FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, + {FMH::MODEL_KEY::ICON, "folder-cloud"}, + {FMH::MODEL_KEY::LABEL, map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, + {FMH::MODEL_KEY::USER, map[FMH::MODEL_NAME[FMH::MODEL_KEY::USER]].toString()}, + {FMH::MODEL_KEY::SERVER, map[FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER]].toString()}, + {FMH::MODEL_KEY::PASSWORD, map[FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD]].toString()}, + {FMH::MODEL_KEY::TYPE, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::CLOUD_PATH]}}; +} +return res; +} + +bool MauiAccounts::addCloudAccount(const QString &server, const QString &user, const QString &password) +{ + const QVariantMap account = { + {FMH::MODEL_NAME[FMH::MODEL_KEY::SERVER], server}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::USER], user}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::PASSWORD], password} + }; + + if(this->db->insert("cloud", account)) + { + emit this->accountAdded(account); + return true; + } + + return false; +} + +bool MauiAccounts::removeCloudAccount(const QString &server, const QString &user) +{ + FMH::MODEL account = { + {FMH::MODEL_KEY::SERVER, server}, + {FMH::MODEL_KEY::USER, user}, + }; + + if(this->db->remove("cloud", account)) + { + emit this->accountRemoved(FMH::toMap(account)); + return true; + } + + return false; +} + +QVariantList MauiAccounts::get(const QString &queryTxt) +{ + QVariantList mapList; + + auto query = this->db->getQuery(queryTxt); + + if(query.exec()) + { + while(query.next()) + { + QVariantMap data; + for(auto key : FMH::MODEL_NAME.keys()) + if(query.record().indexOf(FMH::MODEL_NAME[key]) > -1) + data[FMH::MODEL_NAME[key]] = query.value(FMH::MODEL_NAME[key]).toString(); + + mapList<< data; + + } + + }else qDebug()<< query.lastError()<< query.lastQuery(); + + return mapList; +} + +int MauiAccounts::getCurrentAccountIndex() const +{ + return this->m_currentAccountIndex; +} + +QVariantMap MauiAccounts::getCurrentAccount() const +{ + return this->m_currentAccount; +} + +void MauiAccounts::registerAccount(const QVariantMap& account) +{ + // register the account to the backend needed + auto model = FMH::toModel(account); + + if(this->addCloudAccount(model[FMH::MODEL_KEY::SERVER], model[FMH::MODEL_KEY::USER], model[FMH::MODEL_KEY::PASSWORD])) + { + this->setAccounts(); + } +} + +void MauiAccounts::setCurrentAccountIndex(const int& index) +{ + if(index >= this->m_data.size() || index < 0) + return; + + //make sure the account exists + this->m_currentAccountIndex = index; + this->m_currentAccount = FMH::toMap(this->m_data.at(m_currentAccountIndex)); + + emit this->currentAccountChanged(this->m_currentAccount); + emit this->currentAccountIndexChanged(this->m_currentAccountIndex); +} + +QVariantMap MauiAccounts::get(const int& index) const +{ + if(index >= this->m_data.size() || index < 0) + return QVariantMap(); + return FMH::toMap(this->m_data.at(index)); +} + +QVariantList MauiAccounts::getCloudAccountsList() +{ + QVariantList res; + + const auto data = this->getCloudAccounts(); + for(const auto &item : data) + res << FMH::toMap(item); + + return res; +} + +uint MauiAccounts::getCount() const +{ + return this->m_count; +} + +void MauiAccounts::refresh() +{ + this->setAccounts(); +} + +void MauiAccounts::removeAccount(const int& index) +{ + if(index >= this->m_data.size() || index < 0) + return; + + if(this->removeCloudAccount(this->m_data.at(index)[FMH::MODEL_KEY::SERVER], this->m_data.at(index)[FMH::MODEL_KEY::USER])) + { + this->refresh(); + } +} + +void MauiAccounts::removeAccountAndFiles(const int& index) +{ + if(index >= this->m_data.size() || index < 0) + return; + + if(this->removeCloudAccount(this->m_data.at(index)[FMH::MODEL_KEY::SERVER], this->m_data.at(index)[FMH::MODEL_KEY::USER])) + { + this->refresh(); + } + +// FM_STATIC::removeDir(FM::resolveUserCloudCachePath(this->m_data.at(index)[FMH::MODEL_KEY::SERVER], this->m_data.at(index)[FMH::MODEL_KEY::USER])); +} + diff --git a/src/utils/mauiaccounts.h b/src/utils/accounts/mauiaccounts.h similarity index 81% rename from src/utils/mauiaccounts.h rename to src/utils/accounts/mauiaccounts.h index b9db949..462da86 100644 --- a/src/utils/mauiaccounts.h +++ b/src/utils/accounts/mauiaccounts.h @@ -1,99 +1,99 @@ /* * * Copyright (C) 2019 camilo * * 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 3 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, see . */ #ifndef MAUIACCOUNTS_H #define MAUIACCOUNTS_H #include /** * MauiAccounts * provides an interface to access the system registered accounts, * the current active account and a bridge to add account data to the host system backend solution. * This properties and functions are exposed to * all the Maui Applications that might want to use the accounts */ #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif -class FM; +class AccountsDB; #ifdef STATIC_MAUIKIT class MauiAccounts : public MauiList #else class MAUIKIT_EXPORT MauiAccounts : public MauiList #endif { Q_OBJECT Q_PROPERTY(int currentAccountIndex READ getCurrentAccountIndex WRITE setCurrentAccountIndex NOTIFY currentAccountIndexChanged) Q_PROPERTY(QVariantMap currentAccount READ getCurrentAccount NOTIFY currentAccountChanged) Q_PROPERTY(uint count READ getCount NOTIFY countChanged) -public: - /** - * Default constructor - */ - MauiAccounts(QObject *parent = nullptr); - - /** - * Destructor - */ - ~MauiAccounts(); - /** - * @todo write docs - * - * @return TODO - */ +public: + static MauiAccounts * instance(QObject *parent = nullptr); FMH::MODEL_LIST items() const final override; void setCurrentAccountIndex(const int &index); int getCurrentAccountIndex() const; QVariantMap getCurrentAccount() const; uint getCount() const; public slots: QVariantMap get(const int &index) const; + QVariantList getCloudAccountsList(); + FMH::MODEL_LIST getCloudAccounts(); void registerAccount(const QVariantMap &account); void removeAccount(const int &index); void removeAccountAndFiles(const int &index); void refresh(); private: - FM *fm; + static MauiAccounts *m_instance; + MauiAccounts(QObject *parent = nullptr); + ~MauiAccounts() override; + + AccountsDB *db; FMH::MODEL_LIST m_data; QVariantMap m_currentAccount; int m_currentAccountIndex = 1; uint m_count = 0; void setAccounts(); - + + bool addCloudAccount(const QString &server, const QString &user, const QString &password); + bool removeCloudAccount(const QString &server, const QString &user); + + QVariantList get(const QString &queryTxt); + signals: + void accountAdded(QVariantMap account); + void accountRemoved(QVariantMap account); void currentAccountChanged(QVariantMap account); void currentAccountIndexChanged(int index); void countChanged(uint count); }; #endif // MAUIACCOUNTS_H diff --git a/src/utils/accounts/script.sql b/src/utils/accounts/script.sql new file mode 100644 index 0000000..4f931e5 --- /dev/null +++ b/src/utils/accounts/script.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS CLOUD ( +server TEXT, +user TEXT, +password TEXT, +PRIMARY KEY(server, user) +); diff --git a/src/utils/editor/syntaxhighlighter.pri b/src/utils/editor/syntaxhighlighter.pri index c985096..c5941c2 100644 --- a/src/utils/editor/syntaxhighlighter.pri +++ b/src/utils/editor/syntaxhighlighter.pri @@ -1,17 +1,33 @@ -QT += core qml quick gui +QT *= core qml quick gui + +exists($$PWD/KSyntaxHighlighting) { + message("Using KSyntaxHighlighting for Android") + +}else { + warning("Getting KSyntaxHighlighting for Android") + system(git clone $$KSYNTAXHIGHLIGHTING_REPO $$PWD/KSyntaxHighlighting) +} + +exists($$PWD/kquicksyntaxhighlighter) { + message("Using kquicksyntaxhighlighter for Android") + +}else { + warning("Getting kquicksyntaxhighlighter for Android") + system(git clone $$KQUICKSYNTAXHIGHLIGHTER_REPO $$PWD/kquicksyntaxhighlighter) +} HEADERS += \ $$PWD/kquicksyntaxhighlighter/kquicksyntaxhighlighter.h\ SOURCES += \ $$PWD/kquicksyntaxhighlighter/kquicksyntaxhighlighter.cpp\ ANDROID_EXTRA_LIBS += $$PWD/KSyntaxHighlighting/libKF5SyntaxHighlighting.so LIBS += -L$$PWD/KSyntaxHighlighting/ -lKF5SyntaxHighlighting INCLUDEPATH += $$PWD/KSyntaxHighlighting/KSyntaxHighlighting / $$PWD/kquicksyntaxhighlighter DEPENDPATH += $$PWD/KSyntaxHighlighting/KSyntaxHighlighting / $$PWD/kquicksyntaxhighlighter diff --git a/src/utils/fmh.h b/src/utils/fmh.h new file mode 100644 index 0000000..915091e --- /dev/null +++ b/src/utils/fmh.h @@ -0,0 +1,1119 @@ +/* + * Copyright 2018 Camilo Higuita + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, 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 Library 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. + */ + +#ifndef FMH_H +#define FMH_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(Q_OS_ANDROID) +#include "mauiandroid.h" +#elif defined(Q_OS_LINUX) +#include +#include +#include +#include +#endif + +// #ifdef COMPONENT_TAGGING +// #include "tagging.h" +// #endif + +namespace FMH +{ +inline bool isAndroid() +{ +#if defined(Q_OS_ANDROID) + return true; +#elif defined(Q_OS_LINUX) + return false; +#elif defined(Q_OS_WIN32) + return false; +#elif defined(Q_OS_WIN64) + return false; +#elif defined(Q_OS_MACOS) + return false; +#elif defined(Q_OS_IOS) + return false; +#elif defined(Q_OS_HAIKU) + return false; +#endif +} + +enum FILTER_TYPE : int +{ + AUDIO, + VIDEO, + TEXT, + IMAGE, + DOCUMENT, + NONE +}; + +inline QStringList getMimeTypeSuffixes(const QString &hint) +{ + QMimeDatabase mimedb; + return mimedb.mimeTypeForName(hint).suffixes(); +} + +static const QHash FILTER_LIST = +{ + {FILTER_TYPE::AUDIO, QStringList {"*.mp3", "*.mp4", "*.wav", "*.ogg", "*.flac"}}, + {FILTER_TYPE::VIDEO, QStringList {"*.mp4", "*.mkv", "*.mov", "*.avi", "*.flv"}}, + {FILTER_TYPE::TEXT, QStringList {"*.txt", "*.cpp", "*.js", "*.doc", "*.h", "*.json", "*.html", "*.rtf", "*.qml", "*.py", "*.go"}}, + {FILTER_TYPE::DOCUMENT, QStringList {"*.pdf", "*.txt", "*.cbz", "*.cbr", "*.epub", "*.cbt", "*.cba", "*.cb7"}}, + {FILTER_TYPE::IMAGE, QStringList {"*.png", "*.jpg", "*.jpeg", "*.gif", "*.svg", "*.bmp"}}, + {FILTER_TYPE::NONE, QStringList()} +}; + +enum MODEL_KEY : int +{ + ICON, + LABEL, + PATH, + URL, + TYPE, + GROUP, + OWNER, + SUFFIX, + NAME, + DATE, + SIZE, + MODIFIED, + MIME, + TAG, + PERMISSIONS, + THUMBNAIL, + THUMBNAIL_1, + THUMBNAIL_2, + THUMBNAIL_3, + HIDDEN, + ICONSIZE, + DETAILVIEW, + SHOWTHUMBNAIL, + SHOWTERMINAL, + COUNT, + SORTBY, + USER, + PASSWORD, + SERVER, + FOLDERSFIRST, + VIEWTYPE, + ADDDATE, + FAV, + FAVORITE, + COLOR, + RATE, + FORMAT, + PLACE, + LOCATION, + ALBUM, + ARTIST, + TRACK, + DURATION, + ARTWORK, + PLAYLIST, + LYRICS, + WIKI, + MOOD, + SOURCETYPE, + GENRE, + NOTE, + COMMENT, + CONTEXT, + SOURCE, + TITLE, + ID, + RELEASEDATE, + LICENSE, + DESCRIPTION, + BOOKMARK, + ACCOUNT, + ACCOUNTTYPE, + VERSION, + DOMAIN, + CATEGORY, + CONTENT, + PIN, + IMG, + PREVIEW, + LINK, + STAMP, + BOOK, + + /** ccdav keys **/ + N, + PHOTO, + GENDER, + ADR, + ADR_2, + ADR_3, + EMAIL, + EMAIL_2, + EMAIL_3, + LANG, + NICKNAME, + ORG, + PROFILE, + TZ, + TEL, + TEL_2, + TEL_3, + IM, + + /** other keys **/ + CITY, + STATE, + COUNTRY, + + /** keys from opendesktop store **/ + PACKAGE_ARCH, + PACKAGE_TYPE, + GPG_FINGERPRINT, + GPG_SIGNATURE, + PACKAGE_NAME, + PRICE, + REPOSITORY, + TAGS, + WAY, + PIC, + SMALL_PIC, + CHANGED, + COMMENTS, + CREATED, + DETAIL_PAGE, + DETAILS, + TOTAL_DOWNLOADS, + GHNS_EXCLUDED, + LANGUAGE, + PERSON_ID, + SCORE, + SUMMARY, + TYPE_ID, + TYPE_NAME, + XDG_TYPE, + + //file props + SYMLINK, + IS_SYMLINK, + IS_DIR, + IS_FILE, + IS_REMOTE, + EXECUTABLE, + READABLE, + WRITABLE, + LAST_READ, + +}; + +static const QHash MODEL_NAME = +{ + {MODEL_KEY::ICON, "icon"}, + {MODEL_KEY::LABEL, "label"}, + {MODEL_KEY::PATH, "path"}, + {MODEL_KEY::URL, "url"}, + {MODEL_KEY::TYPE, "type"}, + {MODEL_KEY::GROUP, "group"}, + {MODEL_KEY::OWNER, "owner"}, + {MODEL_KEY::SUFFIX, "suffix"}, + {MODEL_KEY::NAME, "name"}, + {MODEL_KEY::DATE, "date"}, + {MODEL_KEY::MODIFIED, "modified"}, + {MODEL_KEY::MIME, "mime"}, + {MODEL_KEY::SIZE, "size"}, + {MODEL_KEY::TAG, "tag"}, + {MODEL_KEY::PERMISSIONS, "permissions"}, + {MODEL_KEY::THUMBNAIL, "thumbnail"}, + {MODEL_KEY::THUMBNAIL_1, "thumbnail_1"}, + {MODEL_KEY::THUMBNAIL_2, "thumbnail_2"}, + {MODEL_KEY::THUMBNAIL_3, "thumbnail_3"}, + {MODEL_KEY::ICONSIZE, "iconsize"}, + {MODEL_KEY::HIDDEN, "hidden"}, + {MODEL_KEY::DETAILVIEW, "detailview"}, + {MODEL_KEY::SHOWTERMINAL, "showterminal"}, + {MODEL_KEY::SHOWTHUMBNAIL, "showthumbnail"}, + {MODEL_KEY::COUNT, "count"}, + {MODEL_KEY::SORTBY, "sortby"}, + {MODEL_KEY::USER, "user"}, + {MODEL_KEY::PASSWORD, "password"}, + {MODEL_KEY::SERVER, "server"}, + {MODEL_KEY::FOLDERSFIRST, "foldersfirst"}, + {MODEL_KEY::VIEWTYPE, "viewtype"}, + {MODEL_KEY::ADDDATE, "adddate"}, + {MODEL_KEY::FAV, "fav"}, + {MODEL_KEY::FAVORITE, "favorite"}, + {MODEL_KEY::COLOR, "color"}, + {MODEL_KEY::RATE, "rate"}, + {MODEL_KEY::FORMAT, "format"}, + {MODEL_KEY::PLACE, "place"}, + {MODEL_KEY::LOCATION, "location"}, + {MODEL_KEY::ALBUM, "album"}, + {MODEL_KEY::DURATION, "duration"}, + {MODEL_KEY::RELEASEDATE, "releasedate"}, + {MODEL_KEY::ARTIST, "artist"}, + {MODEL_KEY::LYRICS, "lyrics"}, + {MODEL_KEY::TRACK, "track"}, + {MODEL_KEY::GENRE, "genre"}, + {MODEL_KEY::WIKI, "wiki"}, + {MODEL_KEY::CONTEXT, "context"}, + {MODEL_KEY::SOURCETYPE, "sourcetype"}, + {MODEL_KEY::ARTWORK, "artwork"}, + {MODEL_KEY::NOTE, "note"}, + {MODEL_KEY::MOOD, "mood"}, + {MODEL_KEY::COMMENT, "comment"}, + {MODEL_KEY::PLAYLIST, "playlist"}, + {MODEL_KEY::SOURCE, "source"}, + {MODEL_KEY::TITLE, "title"}, + {MODEL_KEY::ID, "id"}, + {MODEL_KEY::LICENSE, "license"}, + {MODEL_KEY::DESCRIPTION, "description"}, + {MODEL_KEY::BOOKMARK, "bookmark"}, + {MODEL_KEY::ACCOUNT, "account"}, + {MODEL_KEY::ACCOUNTTYPE, "accounttype"}, + {MODEL_KEY::VERSION, "version"}, + {MODEL_KEY::DOMAIN, "domain"}, + {MODEL_KEY::CATEGORY, "category"}, + {MODEL_KEY::CONTENT, "content"}, + {MODEL_KEY::PIN, "pin"}, + {MODEL_KEY::IMG, "img"}, + {MODEL_KEY::PREVIEW, "preview"}, + {MODEL_KEY::LINK, "link"}, + {MODEL_KEY::STAMP, "stamp"}, + {MODEL_KEY::BOOK, "book"}, + + /** ccdav keys **/ + {MODEL_KEY::N, "n"}, + {MODEL_KEY::IM, "im"}, + {MODEL_KEY::PHOTO, "photo"}, + {MODEL_KEY::GENDER, "gender"}, + {MODEL_KEY::ADR, "adr"}, + {MODEL_KEY::ADR_2, "adr2"}, + {MODEL_KEY::ADR_3, "adr3"}, + {MODEL_KEY::EMAIL, "email"}, + {MODEL_KEY::EMAIL_2, "email2"}, + {MODEL_KEY::EMAIL_3, "email3"}, + {MODEL_KEY::LANG, "lang"}, + {MODEL_KEY::NICKNAME, "nickname"}, + {MODEL_KEY::ORG, "org"}, + {MODEL_KEY::PROFILE, "profile"}, + {MODEL_KEY::TZ, "tz"}, + {MODEL_KEY::TEL, "tel"}, + {MODEL_KEY::TEL_2, "tel2"}, + {MODEL_KEY::TEL_3, "tel3"}, + + {MODEL_KEY::CITY, "city"}, + {MODEL_KEY::STATE, "state"}, + {MODEL_KEY::COUNTRY, "country"}, + + // opendesktop keys + {MODEL_KEY::PACKAGE_ARCH, "packagearch"}, + {MODEL_KEY::PACKAGE_TYPE, "packagetype"}, + {MODEL_KEY::GPG_FINGERPRINT, "gpgfingerprint"}, + {MODEL_KEY::GPG_SIGNATURE, "gpgsignature"}, + {MODEL_KEY::PACKAGE_NAME, "packagename"}, + {MODEL_KEY::PRICE, "price"}, + {MODEL_KEY::REPOSITORY, "repository"}, + {MODEL_KEY::TAGS, "tags"}, + {MODEL_KEY::WAY, "way"}, + {MODEL_KEY::PIC, "pic"}, + {MODEL_KEY::SMALL_PIC, "smallpic"}, + {MODEL_KEY::CHANGED, "changed"}, + {MODEL_KEY::COMMENTS, "comments"}, + {MODEL_KEY::CREATED, "created"}, + {MODEL_KEY::DETAIL_PAGE, "detailpage"}, + {MODEL_KEY::DETAILS, "details"}, + {MODEL_KEY::TOTAL_DOWNLOADS, "totaldownloads"}, + {MODEL_KEY::GHNS_EXCLUDED, "ghnsexcluded"}, + {MODEL_KEY::LANGUAGE, "language"}, + {MODEL_KEY::SCORE, "score"}, + {MODEL_KEY::SUMMARY, "summary"}, + {MODEL_KEY::TYPE_ID, "typeid"}, + {MODEL_KEY::TYPE_NAME, "typename"}, + {MODEL_KEY::XDG_TYPE, "xdgtype"}, + + //file props + {MODEL_KEY::SYMLINK, "symlink"}, + {MODEL_KEY::IS_SYMLINK, "issymlink"}, + {MODEL_KEY::LAST_READ, "lastread"}, + {MODEL_KEY::READABLE, "readable"}, + {MODEL_KEY::WRITABLE, "writeable"}, + {MODEL_KEY::IS_DIR, "isdir"}, + {MODEL_KEY::IS_FILE, "isfile"}, + {MODEL_KEY::IS_REMOTE, "isremote"}, + {MODEL_KEY::EXECUTABLE, "executable"} + +}; + +static const QHash MODEL_NAME_KEY = +{ + {MODEL_NAME[MODEL_KEY::ICON], MODEL_KEY::ICON}, + {MODEL_NAME[MODEL_KEY::LABEL], MODEL_KEY::LABEL}, + {MODEL_NAME[MODEL_KEY::PATH], MODEL_KEY::PATH}, + {MODEL_NAME[MODEL_KEY::URL], MODEL_KEY::URL}, + {MODEL_NAME[MODEL_KEY::TYPE], MODEL_KEY::TYPE}, + {MODEL_NAME[MODEL_KEY::GROUP], MODEL_KEY::GROUP}, + {MODEL_NAME[MODEL_KEY::OWNER], MODEL_KEY::OWNER}, + {MODEL_NAME[MODEL_KEY::SUFFIX], MODEL_KEY::SUFFIX}, + {MODEL_NAME[MODEL_KEY::NAME], MODEL_KEY::NAME}, + {MODEL_NAME[MODEL_KEY::DATE], MODEL_KEY::DATE}, + {MODEL_NAME[MODEL_KEY::MODIFIED], MODEL_KEY::MODIFIED}, + {MODEL_NAME[MODEL_KEY::MIME], MODEL_KEY::MIME}, + {MODEL_NAME[MODEL_KEY::SIZE], MODEL_KEY::SIZE,}, + {MODEL_NAME[MODEL_KEY::TAG], MODEL_KEY::TAG}, + {MODEL_NAME[MODEL_KEY::PERMISSIONS], MODEL_KEY::PERMISSIONS}, + {MODEL_NAME[MODEL_KEY::THUMBNAIL], MODEL_KEY::THUMBNAIL}, + {MODEL_NAME[MODEL_KEY::THUMBNAIL_1], MODEL_KEY::THUMBNAIL_1}, + {MODEL_NAME[MODEL_KEY::THUMBNAIL_2], MODEL_KEY::THUMBNAIL_2}, + {MODEL_NAME[MODEL_KEY::THUMBNAIL_3], MODEL_KEY::THUMBNAIL_3}, + {MODEL_NAME[MODEL_KEY::ICONSIZE], MODEL_KEY::ICONSIZE}, + {MODEL_NAME[MODEL_KEY::HIDDEN], MODEL_KEY::HIDDEN}, + {MODEL_NAME[MODEL_KEY::DETAILVIEW], MODEL_KEY::DETAILVIEW}, + {MODEL_NAME[MODEL_KEY::SHOWTERMINAL], MODEL_KEY::SHOWTERMINAL}, + {MODEL_NAME[MODEL_KEY::SHOWTHUMBNAIL], MODEL_KEY::SHOWTHUMBNAIL}, + {MODEL_NAME[MODEL_KEY::COUNT], MODEL_KEY::COUNT}, + {MODEL_NAME[MODEL_KEY::SORTBY], MODEL_KEY::SORTBY}, + {MODEL_NAME[MODEL_KEY::USER], MODEL_KEY::USER}, + {MODEL_NAME[MODEL_KEY::PASSWORD], MODEL_KEY::PASSWORD}, + {MODEL_NAME[MODEL_KEY::SERVER], MODEL_KEY::SERVER}, + {MODEL_NAME[MODEL_KEY::VIEWTYPE], MODEL_KEY::VIEWTYPE}, + {MODEL_NAME[MODEL_KEY::ADDDATE], MODEL_KEY::ADDDATE}, + {MODEL_NAME[MODEL_KEY::FAV], MODEL_KEY::FAV}, + {MODEL_NAME[MODEL_KEY::FAVORITE], MODEL_KEY::FAVORITE}, + {MODEL_NAME[MODEL_KEY::COLOR], MODEL_KEY::COLOR}, + {MODEL_NAME[MODEL_KEY::RATE], MODEL_KEY::RATE}, + {MODEL_NAME[MODEL_KEY::FORMAT], MODEL_KEY::FORMAT}, + {MODEL_NAME[MODEL_KEY::PLACE], MODEL_KEY::PLACE}, + {MODEL_NAME[MODEL_KEY::LOCATION], MODEL_KEY::LOCATION}, + {MODEL_NAME[MODEL_KEY::ALBUM], MODEL_KEY::ALBUM}, + {MODEL_NAME[MODEL_KEY::ARTIST], MODEL_KEY::ARTIST}, + {MODEL_NAME[MODEL_KEY::DURATION], MODEL_KEY::DURATION}, + {MODEL_NAME[MODEL_KEY::TRACK], MODEL_KEY::TRACK}, + {MODEL_NAME[MODEL_KEY::GENRE], MODEL_KEY::GENRE}, + {MODEL_NAME[MODEL_KEY::LYRICS], MODEL_KEY::LYRICS}, + {MODEL_NAME[MODEL_KEY::RELEASEDATE], MODEL_KEY::RELEASEDATE}, + {MODEL_NAME[MODEL_KEY::FORMAT], MODEL_KEY::FORMAT}, + {MODEL_NAME[MODEL_KEY::WIKI], MODEL_KEY::WIKI}, + {MODEL_NAME[MODEL_KEY::SOURCETYPE], MODEL_KEY::SOURCETYPE}, + {MODEL_NAME[MODEL_KEY::ARTWORK], MODEL_KEY::ARTWORK}, + {MODEL_NAME[MODEL_KEY::NOTE], MODEL_KEY::NOTE}, + {MODEL_NAME[MODEL_KEY::MOOD], MODEL_KEY::MOOD}, + {MODEL_NAME[MODEL_KEY::COMMENT], MODEL_KEY::COMMENT}, + {MODEL_NAME[MODEL_KEY::CONTEXT], MODEL_KEY::CONTEXT}, + {MODEL_NAME[MODEL_KEY::SOURCE], MODEL_KEY::SOURCE}, + {MODEL_NAME[MODEL_KEY::TITLE], MODEL_KEY::TITLE}, + {MODEL_NAME[MODEL_KEY::ID], MODEL_KEY::ID}, + {MODEL_NAME[MODEL_KEY::LICENSE], MODEL_KEY::LICENSE}, + {MODEL_NAME[MODEL_KEY::DESCRIPTION], MODEL_KEY::DESCRIPTION}, + {MODEL_NAME[MODEL_KEY::BOOKMARK], MODEL_KEY::BOOKMARK}, + {MODEL_NAME[MODEL_KEY::ACCOUNT], MODEL_KEY::ACCOUNT}, + {MODEL_NAME[MODEL_KEY::ACCOUNTTYPE], MODEL_KEY::ACCOUNTTYPE}, + {MODEL_NAME[MODEL_KEY::VERSION], MODEL_KEY::VERSION}, + {MODEL_NAME[MODEL_KEY::DOMAIN], MODEL_KEY::DOMAIN}, + {MODEL_NAME[MODEL_KEY::CATEGORY], MODEL_KEY::CATEGORY}, + {MODEL_NAME[MODEL_KEY::CONTENT], MODEL_KEY::CONTENT}, + {MODEL_NAME[MODEL_KEY::PIN], MODEL_KEY::PIN}, + {MODEL_NAME[MODEL_KEY::IMG], MODEL_KEY::IMG}, + {MODEL_NAME[MODEL_KEY::PREVIEW], MODEL_KEY::PREVIEW}, + {MODEL_NAME[MODEL_KEY::LINK], MODEL_KEY::LINK}, + {MODEL_NAME[MODEL_KEY::STAMP], MODEL_KEY::STAMP}, + {MODEL_NAME[MODEL_KEY::BOOK], MODEL_KEY::BOOK}, + + /** ccdav keys **/ + {MODEL_NAME[MODEL_KEY::N], MODEL_KEY::N}, + {MODEL_NAME[MODEL_KEY::IM], MODEL_KEY::IM}, + {MODEL_NAME[MODEL_KEY::PHOTO], MODEL_KEY::PHOTO}, + {MODEL_NAME[MODEL_KEY::GENDER], MODEL_KEY::GENDER}, + {MODEL_NAME[MODEL_KEY::ADR], MODEL_KEY::ADR}, + {MODEL_NAME[MODEL_KEY::ADR_2], MODEL_KEY::ADR_2}, + {MODEL_NAME[MODEL_KEY::ADR_3], MODEL_KEY::ADR_3}, + {MODEL_NAME[MODEL_KEY::EMAIL], MODEL_KEY::EMAIL}, + {MODEL_NAME[MODEL_KEY::EMAIL_2], MODEL_KEY::EMAIL_2}, + {MODEL_NAME[MODEL_KEY::EMAIL_3], MODEL_KEY::EMAIL_3}, + {MODEL_NAME[MODEL_KEY::LANG], MODEL_KEY::LANG}, + {MODEL_NAME[MODEL_KEY::NICKNAME], MODEL_KEY::NICKNAME}, + {MODEL_NAME[MODEL_KEY::ORG], MODEL_KEY::ORG}, + {MODEL_NAME[MODEL_KEY::PROFILE], MODEL_KEY::PROFILE}, + {MODEL_NAME[MODEL_KEY::TZ], MODEL_KEY::TZ}, + {MODEL_NAME[MODEL_KEY::TEL], MODEL_KEY::TEL}, + {MODEL_NAME[MODEL_KEY::TEL_2], MODEL_KEY::TEL_2}, + {MODEL_NAME[MODEL_KEY::TEL_3], MODEL_KEY::TEL_3}, + + {MODEL_NAME[MODEL_KEY::CITY], MODEL_KEY::CITY}, + {MODEL_NAME[MODEL_KEY::STATE], MODEL_KEY::STATE}, + {MODEL_NAME[MODEL_KEY::COUNTRY], MODEL_KEY::COUNTRY}, + + //opendesktop store keys + {MODEL_NAME[MODEL_KEY::PACKAGE_ARCH], MODEL_KEY::PACKAGE_ARCH}, + {MODEL_NAME[MODEL_KEY::PACKAGE_TYPE], MODEL_KEY::PACKAGE_TYPE}, + {MODEL_NAME[MODEL_KEY::GPG_FINGERPRINT], MODEL_KEY::GPG_FINGERPRINT}, + {MODEL_NAME[MODEL_KEY::GPG_SIGNATURE], MODEL_KEY::GPG_SIGNATURE}, + {MODEL_NAME[MODEL_KEY::PACKAGE_NAME], MODEL_KEY::PACKAGE_NAME}, + {MODEL_NAME[MODEL_KEY::PRICE], MODEL_KEY::PRICE}, + {MODEL_NAME[MODEL_KEY::REPOSITORY], MODEL_KEY::REPOSITORY}, + {MODEL_NAME[MODEL_KEY::TAGS], MODEL_KEY::TAGS}, + {MODEL_NAME[MODEL_KEY::WAY], MODEL_KEY::WAY}, + {MODEL_NAME[MODEL_KEY::PIC], MODEL_KEY::PIC}, + {MODEL_NAME[MODEL_KEY::SMALL_PIC], MODEL_KEY::SMALL_PIC}, + {MODEL_NAME[MODEL_KEY::CHANGED], MODEL_KEY::CHANGED}, + {MODEL_NAME[MODEL_KEY::COMMENTS], MODEL_KEY::COMMENTS}, + {MODEL_NAME[MODEL_KEY::CREATED], MODEL_KEY::CREATED}, + {MODEL_NAME[MODEL_KEY::DETAIL_PAGE], MODEL_KEY::DETAIL_PAGE}, + {MODEL_NAME[MODEL_KEY::DETAILS], MODEL_KEY::DETAILS}, + {MODEL_NAME[MODEL_KEY::TOTAL_DOWNLOADS], MODEL_KEY::TOTAL_DOWNLOADS}, + {MODEL_NAME[MODEL_KEY::GHNS_EXCLUDED], MODEL_KEY::GHNS_EXCLUDED}, + {MODEL_NAME[MODEL_KEY::LANGUAGE], MODEL_KEY::LANGUAGE}, + {MODEL_NAME[MODEL_KEY::PERSON_ID], MODEL_KEY::PERSON_ID}, + {MODEL_NAME[MODEL_KEY::SCORE], MODEL_KEY::SCORE}, + {MODEL_NAME[MODEL_KEY::SUMMARY], MODEL_KEY::SUMMARY}, + {MODEL_NAME[MODEL_KEY::TYPE_ID], MODEL_KEY::TYPE_ID}, + {MODEL_NAME[MODEL_KEY::TYPE_NAME], MODEL_KEY::TYPE_NAME}, + {MODEL_NAME[MODEL_KEY::XDG_TYPE], MODEL_KEY::XDG_TYPE}, + + //file props + {MODEL_NAME[MODEL_KEY::SYMLINK], MODEL_KEY::SYMLINK}, + {MODEL_NAME[MODEL_KEY::IS_SYMLINK], MODEL_KEY::IS_SYMLINK}, + {MODEL_NAME[MODEL_KEY::LAST_READ], MODEL_KEY::LAST_READ}, + {MODEL_NAME[MODEL_KEY::READABLE], MODEL_KEY::READABLE}, + {MODEL_NAME[MODEL_KEY::WRITABLE], MODEL_KEY::WRITABLE}, + {MODEL_NAME[MODEL_KEY::IS_DIR], MODEL_KEY::IS_DIR}, + {MODEL_NAME[MODEL_KEY::IS_FILE], MODEL_KEY::IS_FILE}, + {MODEL_NAME[MODEL_KEY::IS_REMOTE], MODEL_KEY::IS_REMOTE}, + {MODEL_NAME[MODEL_KEY::EXECUTABLE], MODEL_KEY::EXECUTABLE} +}; + +typedef QHash MODEL; +typedef QVector MODEL_LIST; + +static const inline QVariantMap toMap(const FMH::MODEL& model) +{ + QVariantMap map; + for(const auto &key : model.keys()) + map.insert(FMH::MODEL_NAME[key], model[key]); + + return map; +} + +static const inline FMH::MODEL toModel(const QVariantMap& map) +{ + FMH::MODEL model; + for(const auto &key : map.keys()) + model.insert(FMH::MODEL_NAME_KEY[key], map[key].toString()); + + return model; +} + +static const inline FMH::MODEL_LIST toModelList(const QVariantList& list) +{ + FMH::MODEL_LIST res; + + for(const auto &data : list) + res << FMH::toModel(data.toMap()); + + return res; +} + + +static const inline FMH::MODEL filterModel(const FMH::MODEL &model, const QVector &keys) +{ + FMH::MODEL res; + for(const auto &key : keys) + { + if(model.contains(key)) + res[key] = model[key]; + } + + return res; +} + +static const inline QStringList modelToList(const FMH::MODEL &model, const FMH::MODEL_KEY &key) +{ + QStringList res; + for(const auto &item : model) + if(item.contains(key)) + res << item[key]; + + return res; +} + +struct PATH_CONTENT +{ + QUrl path; // the url holding all the content + FMH::MODEL_LIST content; // the content from the url +}; + +#ifdef Q_OS_ANDROID +enum PATHTYPE_KEY : int +{ + PLACES_PATH, + REMOTE_PATH, + DRIVES_PATH, + REMOVABLE_PATH, + TAGS_PATH, + UNKNOWN_TYPE, + APPS_PATH, + TRASH_PATH, + SEARCH_PATH, + CLOUD_PATH, + FISH_PATH, + MTP_PATH, + QUICK_PATH, + OTHER_PATH, +}; +#else +enum PATHTYPE_KEY : int +{ + PLACES_PATH = KFilePlacesModel::GroupType::PlacesType, + REMOTE_PATH = KFilePlacesModel::GroupType::RemoteType, + DRIVES_PATH = KFilePlacesModel::GroupType::DevicesType, + REMOVABLE_PATH = KFilePlacesModel::GroupType::RemovableDevicesType, + TAGS_PATH = KFilePlacesModel::GroupType::TagsType, + UNKNOWN_TYPE = KFilePlacesModel::GroupType::UnknownType, + APPS_PATH = 9, + TRASH_PATH = 10, + SEARCH_PATH = 11, + CLOUD_PATH = 12, + FISH_PATH = 13, + MTP_PATH = 14, + QUICK_PATH = 15, + OTHER_PATH = 16, + +}; +#endif +static const QHash PATHTYPE_SCHEME = +{ + {PATHTYPE_KEY::PLACES_PATH, "file"}, + {PATHTYPE_KEY::DRIVES_PATH, "drives"}, + {PATHTYPE_KEY::APPS_PATH, "applications"}, + {PATHTYPE_KEY::REMOTE_PATH, "remote"}, + {PATHTYPE_KEY::REMOVABLE_PATH, "removable"}, + {PATHTYPE_KEY::UNKNOWN_TYPE, "Unkown"}, + {PATHTYPE_KEY::TRASH_PATH, "trash"}, + {PATHTYPE_KEY::TAGS_PATH, "tags"}, + {PATHTYPE_KEY::SEARCH_PATH, "search"}, + {PATHTYPE_KEY::CLOUD_PATH, "cloud"}, + {PATHTYPE_KEY::FISH_PATH, "fish"}, + {PATHTYPE_KEY::MTP_PATH, "mtp"} +}; + +static const QHash PATHTYPE_URI = +{ + {PATHTYPE_KEY::PLACES_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::PLACES_PATH] + "://"}, + {PATHTYPE_KEY::DRIVES_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::DRIVES_PATH] + "://"}, + {PATHTYPE_KEY::APPS_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::APPS_PATH] + ":///"}, + {PATHTYPE_KEY::REMOTE_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::REMOTE_PATH] + "://"}, + {PATHTYPE_KEY::REMOVABLE_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::REMOVABLE_PATH] + "://"}, + {PATHTYPE_KEY::UNKNOWN_TYPE, PATHTYPE_SCHEME[PATHTYPE_KEY::UNKNOWN_TYPE] + "://"}, + {PATHTYPE_KEY::TRASH_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::TRASH_PATH] + "://"}, + {PATHTYPE_KEY::TAGS_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::TAGS_PATH] + ":///"}, + {PATHTYPE_KEY::SEARCH_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::SEARCH_PATH] + "://"}, + {PATHTYPE_KEY::CLOUD_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::CLOUD_PATH] + ":///"}, + {PATHTYPE_KEY::FISH_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::FISH_PATH] + "://"}, + {PATHTYPE_KEY::MTP_PATH, PATHTYPE_SCHEME[PATHTYPE_KEY::MTP_PATH] + "://"} +}; + +static const QHash PATHTYPE_LABEL = +{ + {PATHTYPE_KEY::PLACES_PATH, ("Places")}, + {PATHTYPE_KEY::DRIVES_PATH, ("Drives")}, + {PATHTYPE_KEY::APPS_PATH, ("Apps")}, + {PATHTYPE_KEY::REMOTE_PATH, ("Remote")}, + {PATHTYPE_KEY::REMOVABLE_PATH, ("Removable")}, + {PATHTYPE_KEY::UNKNOWN_TYPE, ("Unknown")}, + {PATHTYPE_KEY::TRASH_PATH, ("Trash")}, + {PATHTYPE_KEY::TAGS_PATH, ("Tags")}, + {PATHTYPE_KEY::SEARCH_PATH, ("Search")}, + {PATHTYPE_KEY::CLOUD_PATH, ("Cloud")}, + {PATHTYPE_KEY::FISH_PATH, ("Remote")}, + {PATHTYPE_KEY::MTP_PATH, ("Drives")}, + {PATHTYPE_KEY::OTHER_PATH, ("Others")}, + {PATHTYPE_KEY::QUICK_PATH, ("Quick")} +}; + +const QString DataPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); +const QString CloudCachePath = FMH::DataPath+"/Cloud/"; +const QString DesktopPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)).toString(); +const QString AppsPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)).toString(); +const QString RootPath = "file:///"; + +#if defined(Q_OS_ANDROID) +const QString PicturesPath = QUrl::fromLocalFile(PATHS::PicturesPath).toString(); +const QString DownloadsPath = QUrl::fromLocalFile(PATHS::DownloadsPath).toString(); +const QString DocumentsPath = QUrl::fromLocalFile(PATHS::DocumentsPath).toString(); +const QString HomePath = QUrl::fromLocalFile(PATHS::HomePath).toString(); +const QString MusicPath = QUrl::fromLocalFile(PATHS::MusicPath).toString(); +const QString VideosPath = QUrl::fromLocalFile(PATHS::VideosPath).toString(); + +const QStringList defaultPaths = +{ + FMH::HomePath, + FMH::DocumentsPath, + FMH::PicturesPath, + FMH::MusicPath, + FMH::VideosPath, + FMH::DownloadsPath +}; + +#else +const QString PicturesPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)).toString(); +const QString DownloadsPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)).toString(); +const QString DocumentsPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)).toString(); +const QString HomePath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)).toString(); +const QString MusicPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MusicLocation)).toString(); +const QString VideosPath = QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::MoviesLocation)).toString(); + +const QStringList defaultPaths = +{ + FMH::HomePath, + FMH::DesktopPath, + FMH::DocumentsPath, + FMH::PicturesPath, + FMH::MusicPath, + FMH::VideosPath, + FMH::DownloadsPath, + FMH::RootPath +}; + +#endif + +const QMap folderIcon +{ + {PicturesPath, "folder-pictures"}, + {DownloadsPath, "folder-download"}, + {DocumentsPath, "folder-documents"}, + {HomePath, "user-home"}, + {MusicPath, "folder-music"}, + {VideosPath, "folder-videos"}, + {DesktopPath, "user-desktop"}, + {AppsPath, "system-run"}, + {RootPath, "folder-root"} +}; + +/** + * Checks if a local file exists. + * The URL must represent a local file path, by using the scheme file:// + **/ +inline bool fileExists(const QUrl &path) +{ + if(!path.isLocalFile()) + { + qWarning() << "URL recived is not a local file" << path; + return false; + } + return QFileInfo::exists(path.toLocalFile()); +} + + +/** + * Return the configuration of a single directory represented + * by a QVariantMap. + * The passed path must be a local file URL. + **/ +inline QVariantMap dirConf(const QUrl &path) +{ + if(!path.isLocalFile()) + { + qWarning() << "URL recived is not a local file" << path; + return QVariantMap(); + } + + if(!FMH::fileExists(path)) + return QVariantMap(); + + QString icon, iconsize, hidden, detailview, showthumbnail, showterminal; + + uint count = 0, sortby = FMH::MODEL_KEY::MODIFIED, viewType = 0; + + bool foldersFirst = false; + +#ifdef Q_OS_ANDROID + QSettings file(path.toLocalFile(), QSettings::Format::NativeFormat); + file.beginGroup(QString("Desktop Entry")); + icon = file.value("Icon").toString(); + file.endGroup(); + + file.beginGroup(QString("Settings")); + hidden = file.value("HiddenFilesShown").toString(); + file.endGroup(); + + file.beginGroup(QString("MAUIFM")); + iconsize = file.value("IconSize").toString(); + detailview = file.value("DetailView").toString(); + showthumbnail = file.value("ShowThumbnail").toString(); + showterminal = file.value("ShowTerminal").toString(); + count = file.value("Count").toInt(); + sortby = file.value("SortBy").toInt(); + foldersFirst = file.value("FoldersFirst").toBool(); + viewType = file.value("ViewType").toInt(); + file.endGroup(); + +#else + KConfig file(path.toLocalFile()); + icon = file.entryMap(QString("Desktop Entry"))["Icon"]; + hidden = file.entryMap(QString("Settings"))["HiddenFilesShown"]; + iconsize = file.entryMap(QString("MAUIFM"))["IconSize"]; + detailview = file.entryMap(QString("MAUIFM"))["DetailView"]; + showthumbnail = file.entryMap(QString("MAUIFM"))["ShowThumbnail"]; + showterminal = file.entryMap(QString("MAUIFM"))["ShowTerminal"]; + count = file.entryMap(QString("MAUIFM"))["Count"].toInt(); + sortby = file.entryMap(QString("MAUIFM"))["SortBy"].toInt(); + foldersFirst = file.entryMap(QString("MAUIFM"))["FoldersFirst"] == "true" ? true : false; + viewType = file.entryMap(QString("MAUIFM"))["ViewType"].toInt(); + +#endif + + return QVariantMap({ + {FMH::MODEL_NAME[FMH::MODEL_KEY::ICON], icon.isEmpty() ? "folder" : icon}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::ICONSIZE], iconsize}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::COUNT], count}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::SHOWTERMINAL], showterminal.isEmpty() ? "false" : showterminal}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::SHOWTHUMBNAIL], showthumbnail.isEmpty() ? "false" : showthumbnail}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::DETAILVIEW], detailview.isEmpty() ? "false" : detailview}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::HIDDEN], hidden.isEmpty() ? false : (hidden == "true" ? true : false)}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::SORTBY], sortby}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::FOLDERSFIRST], foldersFirst}, + {FMH::MODEL_NAME[FMH::MODEL_KEY::VIEWTYPE], viewType} + }); +} + +inline void setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value) +{ + if(!path.isLocalFile()) + { + qWarning() << "URL recived is not a local file" << path; + return; + } + +#ifdef Q_OS_ANDROID + QSettings file(path.toLocalFile(), QSettings::Format::IniFormat); + file.beginGroup(group); + file.setValue(key, value); + file.endGroup(); + file.sync(); +#else + KConfig file(path.toLocalFile(), KConfig::SimpleConfig); + auto kgroup = file.group(group); + kgroup.writeEntry(key, value); + // file.reparseConfiguration(); + file.sync(); +#endif +} + +/** + * Returns the icon name for certain file. + * The file path must be represented as a local file URL. + * It also looks into the directory config file to get custom set icons + **/ +inline QString getIconName(const QUrl &path) +{ + if(!path.isLocalFile()) + qWarning() << "URL recived is not a local file. FMH::getIconName" << path; + + if(path.isLocalFile() && QFileInfo(path.toLocalFile()).isDir()) + { + if(folderIcon.contains(path.toString())) + return folderIcon[path.toString()]; + else + { + const auto icon = FMH::dirConf(QString(path.toString()+"/%1").arg(".directory"))[FMH::MODEL_NAME[FMH::MODEL_KEY::ICON]].toString(); + return icon.isEmpty() ? "folder" : icon; + } + + }else { + +#if defined(Q_OS_ANDROID) + QMimeDatabase mime; + const auto type = mime.mimeTypeForFile(path.toString()); + return type.iconName(); +#else + KFileItem mime(path); + return mime.iconName(); +#endif + } +} + +inline QString getMime(const QUrl &path) +{ + if(!path.isLocalFile()) + { + qWarning() << "URL recived is not a local file, FMH::getMime" << path; + return QString(); + } + + const QMimeDatabase mimedb; + return mimedb.mimeTypeForFile(path.toLocalFile()).name(); +} + + +inline FMH::MODEL getFileInfoModel(const QUrl &path) +{ + FMH::MODEL res; +#ifdef Q_OS_ANDROID + const QFileInfo file(path.toLocalFile()); + if(!file.exists()) + return FMH::MODEL(); + + const auto mime = FMH::getMime(path); + res = FMH::MODEL + { + {FMH::MODEL_KEY::GROUP, file.group()}, + {FMH::MODEL_KEY::OWNER, file.owner()}, + {FMH::MODEL_KEY::SUFFIX, file.completeSuffix()}, + {FMH::MODEL_KEY::LABEL, /*file.isDir() ? file.baseName() :*/ path == FMH::HomePath ? QStringLiteral("Home") : file.fileName()}, + {FMH::MODEL_KEY::NAME, file.fileName()}, + {FMH::MODEL_KEY::DATE, file.birthTime().toString(Qt::TextDate)}, + {FMH::MODEL_KEY::MODIFIED, file.lastModified().toString(Qt::TextDate)}, + {FMH::MODEL_KEY::LAST_READ, file.lastRead().toString(Qt::TextDate)}, + {FMH::MODEL_KEY::MIME, mime }, + {FMH::MODEL_KEY::SYMLINK, file.symLinkTarget() }, + {FMH::MODEL_KEY::SYMLINK, file.symLinkTarget() }, + {FMH::MODEL_KEY::IS_SYMLINK, QVariant(file.isSymLink()).toString()}, + {FMH::MODEL_KEY::IS_FILE, QVariant(file.isFile()).toString()}, + {FMH::MODEL_KEY::HIDDEN, QVariant(file.isHidden()).toString()}, + {FMH::MODEL_KEY::IS_DIR, QVariant(file.isDir()).toString()}, + {FMH::MODEL_KEY::WRITABLE, QVariant(file.isWritable()).toString()}, + {FMH::MODEL_KEY::READABLE, QVariant(file.isReadable()).toString()}, + {FMH::MODEL_KEY::EXECUTABLE, QVariant(file.suffix().endsWith(".desktop")).toString()}, + {FMH::MODEL_KEY::ICON, FMH::getIconName(path)}, + {FMH::MODEL_KEY::SIZE, QString::number(file.size()) /*locale.formattedDataSize(file.size())*/}, + {FMH::MODEL_KEY::PATH, path.toString()}, + {FMH::MODEL_KEY::THUMBNAIL, path.toString()}, + {FMH::MODEL_KEY::COUNT, file.isDir() ? QString::number(QDir(path.toLocalFile()).count() - 2) : "0"} + }; +#else + KFileItem kfile(path, KFileItem::MimeTypeDetermination::NormalMimeTypeDetermination); + + res = FMH::MODEL + { + {FMH::MODEL_KEY::LABEL, kfile.name()}, + {FMH::MODEL_KEY::NAME, kfile.name()}, + {FMH::MODEL_KEY::DATE, kfile.time(KFileItem::FileTimes::CreationTime).toString(Qt::TextDate)}, + {FMH::MODEL_KEY::MODIFIED, kfile.time(KFileItem::FileTimes::ModificationTime).toString(Qt::TextDate)}, + {FMH::MODEL_KEY::LAST_READ, kfile.time(KFileItem::FileTimes::AccessTime).toString(Qt::TextDate)}, + {FMH::MODEL_KEY::PATH, kfile.mostLocalUrl().toString()}, + {FMH::MODEL_KEY::THUMBNAIL, kfile.localPath()}, + {FMH::MODEL_KEY::SYMLINK, kfile.linkDest()}, + {FMH::MODEL_KEY::IS_SYMLINK, QVariant(kfile.isLink()).toString()}, + {FMH::MODEL_KEY::HIDDEN, QVariant(kfile.isHidden()).toString()}, + {FMH::MODEL_KEY::IS_DIR, QVariant(kfile.isDir()).toString()}, + {FMH::MODEL_KEY::IS_FILE, QVariant(kfile.isFile()).toString()}, + {FMH::MODEL_KEY::WRITABLE, QVariant(kfile.isWritable()).toString()}, + {FMH::MODEL_KEY::READABLE, QVariant(kfile.isReadable()).toString()}, + {FMH::MODEL_KEY::EXECUTABLE, QVariant(kfile.isDesktopFile()).toString()}, + {FMH::MODEL_KEY::MIME, kfile.mimetype()}, + {FMH::MODEL_KEY::GROUP, kfile.group()}, + {FMH::MODEL_KEY::ICON, kfile.iconName()}, + {FMH::MODEL_KEY::SIZE, QString::number(kfile.size())}, + {FMH::MODEL_KEY::THUMBNAIL, kfile.mostLocalUrl().toString()}, + {FMH::MODEL_KEY::OWNER, kfile.user()}, + {FMH::MODEL_KEY::COUNT, kfile.isLocalFile() && kfile.isDir() ? QString::number(QDir(kfile.localPath()).count() - 2) : "0"} + }; +#endif + +// #ifdef COMPONENT_TAGGING +// const auto _tag = Tagging::getInstance(); +// res[FMH::MODEL_KEY::FAVORITE] = QVariant(_tag->urlTagExists(kfile.mostLocalUrl().toString(), "fav")).toString(); +// #endif + + return res; + } + + inline QVariantMap getFileInfo(const QUrl &path) + { + return FMH::toMap(FMH::getFileInfoModel(path)); + } + + inline FMH::MODEL getDirInfoModel(const QUrl &path, const QString &type = QString()) + { + auto res = getFileInfoModel(path); + res[FMH::MODEL_KEY::TYPE] = type; + return res; + } + + inline QVariantMap getDirInfo(const QUrl &path, const QString &type = QString()) + { + return FMH::toMap(FMH::getDirInfoModel(path)); + } + +#ifndef STATIC_MAUIKIT +#include "mauikit_export.h" +#endif + +#ifdef STATIC_MAUIKIT + class Downloader : public QObject + #else + class MAUIKIT_EXPORT Downloader : public QObject + #endif + { + Q_OBJECT + public: + explicit Downloader(QObject *parent = 0) : QObject(parent), manager(new QNetworkAccessManager) + {} + + virtual ~Downloader() + { + qDebug()<< "DELETEING DOWNLOADER"; + this->manager->deleteLater(); + // this->reply->deleteLater(); + + } + + void setFile(const QString &fileURL, const QString &fileName = QString()) + { + QString filePath = fileURL; + + if(fileName.isEmpty() || fileURL.isEmpty()) + return; + + QNetworkRequest request; + request.setUrl(QUrl(fileURL)); + reply = manager->get(request); + + file = new QFile; + file->setFileName(fileName); + file->open(QIODevice::WriteOnly); + + connect(reply, SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(onDownloadProgress(qint64,qint64))); + connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(onFinished(QNetworkReply*))); + connect(reply, SIGNAL(readyRead()),this,SLOT(onReadyRead())); + connect(reply, SIGNAL(finished()),this,SLOT(onReplyFinished())); + } + + void getArray(const QString &fileURL, const QMap &headers = {}) + { + qDebug() << fileURL << headers; + if(fileURL.isEmpty()) + return; + + QNetworkRequest request; + request.setUrl(QUrl(fileURL)); + if(!headers.isEmpty()) + { + for(auto key: headers.keys()) + request.setRawHeader(key.toLocal8Bit(), headers[key].toLocal8Bit()); + } + + reply = manager->get(request); + + connect(reply, &QNetworkReply::readyRead, [this]() + { + switch(reply->error()) + { + case QNetworkReply::NoError: + { + this->array = reply->readAll(); + break; + } + + default: + { + qDebug() << reply->errorString(); + emit this->warning(reply->errorString()); + }; + } + }); + + connect(reply, &QNetworkReply::finished, [=]() + { + qDebug() << "Array reply is now finished"; + emit this->dataReady(this->array); + emit this->done(); + }); + } + + private: + QNetworkAccessManager *manager; + QNetworkReply *reply; + QFile *file; + QByteArray array; + + signals: + void progress(int percent); + void downloadReady(); + void fileSaved(QString path); + void warning(QString warning); + void dataReady(QByteArray array); + void done(); + + private slots: + void onDownloadProgress(qint64 bytesRead, qint64 bytesTotal) + { + emit this->progress((bytesRead * bytesTotal) / 100); + } + + void onFinished(QNetworkReply* reply) + { + switch(reply->error()) + { + case QNetworkReply::NoError: + { + qDebug("file is downloaded successfully."); + emit this->downloadReady(); + break; + } + + default: + { + emit this->warning(reply->errorString()); + }; + } + + if(file->isOpen()) + { + file->close(); + emit this->fileSaved(file->fileName()); + file->deleteLater(); + } + } + + void onReadyRead() + { + file->write(reply->readAll()); + // emit this->fileSaved(file->fileName()); + } + + void onReplyFinished() + { + if(file->isOpen()) + { + file->close(); + // emit this->fileSaved(file->fileName()); + file->deleteLater(); + } + + emit done(); + } + }; + + } + +#endif // FMH_H diff --git a/src/utils/fmstatic.cpp b/src/utils/fmstatic.cpp new file mode 100644 index 0000000..be4f2cd --- /dev/null +++ b/src/utils/fmstatic.cpp @@ -0,0 +1,387 @@ +#include "fmstatic.h" +#include +#include "utils.h" + +#if defined(Q_OS_ANDROID) +#include "mauiandroid.h" +#else +#include "mauikde.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +FMStatic::FMStatic(QObject *parent) : QObject(parent) +{ + +} + +FMH::MODEL_LIST FMStatic::packItems(const QStringList &items, const QString &type) +{ + FMH::MODEL_LIST data; + + for(const auto &path : items) + { + if(QUrl(path).isLocalFile() && !FMH::fileExists(path)) + continue; + + auto model = FMH::getFileInfoModel(path); + model.insert(FMH::MODEL_KEY::TYPE, type); + data << model; + + } + + return data; +} + +FMH::MODEL_LIST FMStatic::getDefaultPaths() +{ + return FMStatic::packItems(FMH::defaultPaths, FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::PLACES_PATH]); +} + +FMH::MODEL_LIST FMStatic::search(const QString& query, const QUrl &path, const bool &hidden, const bool &onlyDirs, const QStringList &filters) +{ + FMH::MODEL_LIST content; + + if(!path.isLocalFile()) + { + qWarning() << "URL recived is not a local file. FM::search" << path; + return content; + } + + if (FMStatic::isDir(path)) + { + QDir::Filters dirFilter; + + dirFilter = (onlyDirs ? QDir::AllDirs | QDir::NoDotDot | QDir::NoDot : + QDir::Files | QDir::AllDirs | QDir::NoDotDot | QDir::NoDot); + + if(hidden) + dirFilter = dirFilter | QDir::Hidden | QDir::System; + + QDirIterator it (path.toLocalFile(), filters, dirFilter, QDirIterator::Subdirectories); + while (it.hasNext()) + { + auto url = it.next(); + auto info = it.fileInfo(); + if(info.completeBaseName().contains(query, Qt::CaseInsensitive)) + { + content << FMH::getFileInfoModel(QUrl::fromLocalFile(url)); + } + } + }else + qWarning() << "Search path does not exists" << path; + + qDebug()<< content; + return content; +} + +FMH::MODEL_LIST FMStatic::getDevices() +{ + FMH::MODEL_LIST drives; + +#if defined(Q_OS_ANDROID) + drives << packItems(MAUIAndroid::sdDirs(), FMH::PATHTYPE_LABEL[FMH::PATHTYPE_KEY::DRIVES_PATH]); + return drives; +#endif + + return drives; +} + + +QVariantMap FMStatic::getDirInfo(const QUrl &path, const QString &type) +{ + return FMH::getDirInfo(path, type); +} + +QVariantMap FMStatic::getFileInfo(const QUrl &path) +{ + return FMH::getFileInfo(path); +} + +bool FMStatic::isDefaultPath(const QString &path) +{ + return FMH::defaultPaths.contains(path); +} + +QUrl FMStatic::parentDir(const QUrl &path) +{ + if(!path.isLocalFile()) + { + qWarning() << "URL recived is not a local file, FM::parentDir" << path; + return path; + } + + QDir dir(path.toLocalFile()); + dir.cdUp(); + return QUrl::fromLocalFile(dir.absolutePath()); +} + +bool FMStatic::isDir(const QUrl &path) +{ + if(!path.isLocalFile()) + { + qWarning() << "URL recived is not a local file. FM::isDir" << path; + return false; + } + + QFileInfo file(path.toLocalFile()); + return file.isDir(); +} + +bool FMStatic::isApp(const QString& path) +{ + return /*QFileInfo(path).isExecutable() ||*/ path.endsWith(".desktop"); +} + +bool FMStatic::isCloud(const QUrl &path) +{ + return path.scheme() == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::CLOUD_PATH]; +} + +bool FMStatic::fileExists(const QUrl &path) +{ + return FMH::fileExists(path); +} + +QString FMStatic::fileDir(const QUrl& path) // the directory path of the file +{ + QString res = path.toString(); + if(path.isLocalFile()) + { + const QFileInfo file(path.toLocalFile()); + if(file.isDir()) + res = path.toString(); + else + res = QUrl::fromLocalFile(file.dir().absolutePath()).toString(); + }else + qWarning()<< "The path is not a local one. FM::fileDir"; + + return res; +} + +void FMStatic::saveSettings(const QString &key, const QVariant &value, const QString &group) +{ + UTIL::saveSettings(key, value, group); +} + +QVariant FMStatic::loadSettings(const QString &key, const QString &group, const QVariant &defaultValue) +{ + return UTIL::loadSettings(key, group, defaultValue); +} + +QString FMStatic::formatSize(const int &size) +{ + QLocale locale; + return locale.formattedDataSize(size); +} + +QString FMStatic::formatDate(const QString &dateStr, const QString &format, const QString &initFormat) +{ + QDateTime date; + if( initFormat.isEmpty() ) + date = QDateTime::fromString(dateStr, Qt::TextDate); + else + date = QDateTime::fromString(dateStr, initFormat); + return date.toString(format); +} + +QString FMStatic::homePath() +{ + return FMH::HomePath; +} + +bool FMStatic::copyPath(QUrl sourceDir, QUrl destinationDir, bool overWriteDirectory) +{ +#ifdef Q_OS_ANDROID + QFileInfo fileInfo(sourceDir.toLocalFile()); + if(fileInfo.isFile()) + QFile::copy(sourceDir.toLocalFile(), destinationDir.toLocalFile()); + + QDir originDirectory(sourceDir.toLocalFile()); + + if (!originDirectory.exists()) + return false; + + QDir destinationDirectory(destinationDir.toLocalFile()); + + if(destinationDirectory.exists() && !overWriteDirectory) + return false; + else if(destinationDirectory.exists() && overWriteDirectory) + destinationDirectory.removeRecursively(); + + originDirectory.mkpath(destinationDir.toLocalFile()); + + foreach(QString directoryName, originDirectory.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) + { + QString destinationPath = destinationDir.toLocalFile() + "/" + directoryName; + originDirectory.mkpath(destinationPath); + copyPath(sourceDir.toLocalFile() + "/" + directoryName, destinationPath, overWriteDirectory); + } + + foreach (QString fileName, originDirectory.entryList(QDir::Files)) + { + QFile::copy(sourceDir.toLocalFile() + "/" + fileName, destinationDir.toLocalFile() + "/" + fileName); + } + + /*! Possible race-condition mitigation? */ + QDir finalDestination(destinationDir.toLocalFile()); + finalDestination.refresh(); + + if(finalDestination.exists()) + return true; + + return false; +#else + qDebug()<< "TRYING TO COPY" << sourceDir<< destinationDir; + auto job = KIO::copy(sourceDir, destinationDir); + job->start(); + return true; +#endif +} + +bool FMStatic::removeFile(const QUrl &path) +{ + if(!path.isLocalFile()) + qWarning() << "URL recived is not a local file, FM::removeFile" << path; + + qDebug()<< "TRYING TO REMOVE FILE: " << path; + +#ifdef Q_OS_ANDROID + if(QFileInfo(path.toLocalFile()).isDir()) + return FMStatic::removeDir(path); + else return QFile(path.toLocalFile()).remove(); +#else + auto job = KIO::del(path); + job->start(); + return true; +#endif +} + +void FMStatic::moveToTrash(const QUrl &path) +{ + if(!path.isLocalFile()) + qWarning() << "URL recived is not a local file, FM::moveToTrash" << path; + +#ifdef Q_OS_ANDROID +#else + auto job = KIO::trash(path); + job->start(); +#endif +} + +void FMStatic::emptyTrash() +{ +#ifdef Q_OS_ANDROID +#else + auto job = KIO::emptyTrash(); + job->start(); +#endif +} + +bool FMStatic::removeDir(const QUrl &path) +{ + bool result = true; + QDir dir(path.toLocalFile()); + qDebug()<< "TRYING TO REMOVE DIR" << path << path.toLocalFile(); + if (dir.exists()) + { + Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) + { + if (info.isDir()) + { + result = removeDir(QUrl::fromLocalFile(info.absoluteFilePath())); + } + else + { + result = QFile::remove(info.absoluteFilePath()); + } + + if (!result) + { + return result; + } + } + result = dir.rmdir(path.toLocalFile()); + } + + return result; +} + +bool FMStatic::rename(const QUrl &path, const QString &name) +{ + QFile file(path.toLocalFile()); + const auto url = QFileInfo(path.toLocalFile()).dir().absolutePath(); + return file.rename(url+"/"+name); +} + +bool FMStatic::createDir(const QUrl &path, const QString &name) +{ +#ifdef Q_OS_ANDROID + QFileInfo dd(path.toLocalFile()); + return QDir(path.toLocalFile()).mkdir(name); +#else + const auto _path = QUrl(path.toString() + "/" + name); + auto job = KIO::mkdir(_path); + job->start(); + return true; +#endif +} + +bool FMStatic::createFile(const QUrl &path, const QString &name) +{ + QFile file(path.toLocalFile() + "/" + name); + + if(file.open(QIODevice::ReadWrite)) + { + file.close(); + return true; + } + + return false; +} + +bool FMStatic::createSymlink(const QUrl &path, const QUrl &where) +{ +#ifdef Q_OS_ANDROID + return QFile::link(path.toLocalFile(), where.toLocalFile() + "/" + QFileInfo(path.toLocalFile()).fileName()); +#else + const auto job = KIO::link({path}, where); + job->start(); + return true; +#endif +} + +bool FMStatic::openUrl(const QUrl &url) +{ +#ifdef Q_OS_ANDROID + MAUIAndroid::openUrl(url.toString()); + return true; +#else + // return QDesktopServices::openUrl(QUrl::fromUserInput(url)); + return KRun::runUrl(url, FMH::getFileInfoModel(url)[FMH::MODEL_KEY::MIME], nullptr, false, KRun::RunFlag::DeleteTemporaryFiles); +#endif +} + +void FMStatic::openLocation(const QStringList &urls) +{ + for(const auto &url : urls) + QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(url).dir().absolutePath())); +} + +QVariantMap FMStatic::dirConf(const QUrl &path) +{ + return FMH::dirConf(path); +} + +void FMStatic::setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value) +{ + FMH::setDirConf(path, group, key, value); +} diff --git a/src/utils/fmstatic.h b/src/utils/fmstatic.h new file mode 100644 index 0000000..950e8db --- /dev/null +++ b/src/utils/fmstatic.h @@ -0,0 +1,63 @@ +#ifndef FMSTATIC_H +#define FMSTATIC_H + +#include +#include "fmh.h" + +class FMStatic : public QObject +{ + Q_OBJECT +public: + explicit FMStatic(QObject *parent = nullptr); + +public slots: + static FMH::MODEL_LIST search(const QString &query, const QUrl &path, const bool &hidden = false, const bool &onlyDirs = false, const QStringList &filters = QStringList()); + + static FMH::MODEL_LIST getDevices(); + static FMH::MODEL_LIST getDefaultPaths(); + + static FMH::MODEL_LIST packItems(const QStringList &items, const QString &type); + + static bool copyPath(QUrl sourceDir, QUrl destinationDir, bool overWriteDirectory); + static bool removeDir(const QUrl &path); + + static QString formatSize(const int &size); + static QString formatDate(const QString &dateStr, const QString &format = QString("dd/MM/yyyy"), const QString &initFormat = QString()); + static QString homePath(); + static QUrl parentDir(const QUrl &path); + + static QVariantMap getDirInfo(const QUrl &path, const QString &type); + static QVariantMap getFileInfo(const QUrl &path); + + static bool isDefaultPath(const QString &path); + static bool isDir(const QUrl &path); + static bool isApp(const QString &path); + static bool isCloud(const QUrl &path); + static bool fileExists(const QUrl &path); + + /** + * if the url is a file path then it returns its directory + * and if it is a directory returns the same path + * */ + static QString fileDir(const QUrl &path); + + /* SETTINGS */ + static void saveSettings(const QString &key, const QVariant &value, const QString &group); + static QVariant loadSettings(const QString &key, const QString &group, const QVariant &defaultValue); + + static QVariantMap dirConf(const QUrl &path); + static void setDirConf(const QUrl &path, const QString &group, const QString &key, const QVariant &value); + + static bool removeFile(const QUrl &path); + static void moveToTrash(const QUrl &path); + static void emptyTrash(); + static bool rename(const QUrl &path, const QString &name); + static bool createDir(const QUrl &path, const QString &name); + static bool createFile(const QUrl &path, const QString &name); + static bool createSymlink(const QUrl &path, const QUrl &where); + + static bool openUrl(const QUrl &url); + static void openLocation(const QStringList &urls); +}; + +#endif // FMSTATIC_H diff --git a/src/utils/mauiaccounts.cpp b/src/utils/mauiaccounts.cpp deleted file mode 100644 index af5cd01..0000000 --- a/src/utils/mauiaccounts.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * - * Copyright (C) 2019 camilo - * - * 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 3 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, see . - */ - -#include "utils/mauiaccounts.h" -#include "fm.h" - -MauiAccounts::MauiAccounts(QObject *parent) : MauiList(parent), -fm(new FM(this)) -{ - this->setAccounts(); -} - -MauiAccounts::~MauiAccounts() -{ -} - -FMH::MODEL_LIST MauiAccounts::items() const -{ - return this->m_data; -} - -void MauiAccounts::setAccounts() -{ - emit this->preListChanged(); - this->m_data = this->fm->getCloudAccounts(); - qDebug()<< "ACCOUNTS LIST"<< this->m_data; - - this->m_count = this->m_data.count(); - emit this->countChanged(this->m_count); - emit this->postListChanged(); -} - -int MauiAccounts::getCurrentAccountIndex() const -{ - return this->m_currentAccountIndex; -} - -QVariantMap MauiAccounts::getCurrentAccount() const -{ - return this->m_currentAccount; -} - -void MauiAccounts::registerAccount(const QVariantMap& account) -{ - // register the account to the backend needed - auto model = FMH::toModel(account); - - if(this->fm->addCloudAccount(model[FMH::MODEL_KEY::SERVER], model[FMH::MODEL_KEY::USER], model[FMH::MODEL_KEY::PASSWORD])) - { - this->setAccounts(); - } -} - -void MauiAccounts::setCurrentAccountIndex(const int& index) -{ - if(index >= this->m_data.size() || index < 0) - return; - - //make sure the account exists - this->m_currentAccountIndex = index; - this->m_currentAccount = FMH::toMap(this->m_data.at(m_currentAccountIndex)); - - emit this->currentAccountChanged(this->m_currentAccount); - emit this->currentAccountIndexChanged(this->m_currentAccountIndex); -} - -QVariantMap MauiAccounts::get(const int& index) const -{ - if(index >= this->m_data.size() || index < 0) - return QVariantMap(); - return FMH::toMap(this->m_data.at(index)); -} - -uint MauiAccounts::getCount() const -{ - return this->m_count; -} - -void MauiAccounts::refresh() -{ - this->setAccounts(); -} - -void MauiAccounts::removeAccount(const int& index) -{ - if(index >= this->m_data.size() || index < 0) - return; - - if(this->fm->removeCloudAccount(this->m_data.at(index)[FMH::MODEL_KEY::SERVER], this->m_data.at(index)[FMH::MODEL_KEY::USER])) - { - this->refresh(); - } -} - -void MauiAccounts::removeAccountAndFiles(const int& index) -{ - if(index >= this->m_data.size() || index < 0) - return; - - if(this->fm->removeCloudAccount(this->m_data.at(index)[FMH::MODEL_KEY::SERVER], this->m_data.at(index)[FMH::MODEL_KEY::USER])) - { - this->refresh(); - } - - this->fm->removeDir(FM::resolveUserCloudCachePath(this->m_data.at(index)[FMH::MODEL_KEY::SERVER], this->m_data.at(index)[FMH::MODEL_KEY::USER])); -} - diff --git a/src/utils/mauiapp.cpp b/src/utils/mauiapp.cpp index a7982ff..91f8e91 100644 --- a/src/utils/mauiapp.cpp +++ b/src/utils/mauiapp.cpp @@ -1,58 +1,179 @@ /* * * Copyright (C) 2019 camilo * * 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 3 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, see . */ #include "mauiapp.h" #include "utils.h" + +#ifdef COMPONENT_ACCOUNTS #include "mauiaccounts.h" +#endif -MauiApp::MauiApp(QObject *parent) : QObject(parent), m_accounts(new MauiAccounts(this)) -{ - // QObject::connect(UTIL::app, &QCoreApplication::aboutToQuit, []() - // { - // delete MauiApp::m_instance; - // }); -} +MauiApp::MauiApp(QObject *parent) : QObject(parent) + #ifdef COMPONENT_ACCOUNTS + , m_accounts(MauiAccounts::instance(this)) + #else + , m_accounts(nullptr) + #endif +{} MauiApp::~MauiApp() {} MauiApp * MauiApp::m_instance = nullptr; MauiApp * MauiApp::instance() { if(MauiApp::m_instance == nullptr) MauiApp::m_instance = new MauiApp(); return MauiApp::m_instance; } +QString MauiApp::getName() +{ + return Handy::appInfo().value(FMH::MODEL_NAME[FMH::MODEL_KEY::NAME]).toString(); +} + +QString MauiApp::getVersion() +{ + return Handy::appInfo().value(FMH::MODEL_NAME[FMH::MODEL_KEY::VERSION]).toString(); +} + +QString MauiApp::getOrg() +{ + return Handy::appInfo().value(FMH::MODEL_NAME[FMH::MODEL_KEY::ORG]).toString(); +} + +QString MauiApp::getDomain() +{ + return Handy::appInfo().value(FMH::MODEL_NAME[FMH::MODEL_KEY::DOMAIN]).toString(); +} + +QString MauiApp::getMauikitVersion() +{ + return Handy::appInfo().value("mauikit_version").toString(); +} + +QString MauiApp::getQtVersion() +{ + return Handy::appInfo().value("qt_version").toString(); +} + +QString MauiApp::getDescription() const +{ + return description; +} + +void MauiApp::setDescription(const QString &value) +{ + if(description == value) + return; + + description = value; + emit this->descriptionChanged(description); +} + +QString MauiApp::getIconName() const +{ + return iconName; +} + +void MauiApp::setIconName(const QString &value) +{ + if(iconName == value) + return; + + iconName = value; + emit this->iconNameChanged(iconName); +} + +QString MauiApp::getWebPage() const +{ + return webPage; +} + +void MauiApp::setWebPage(const QString &value) +{ + if(webPage == value) + return; + + webPage = value; + emit this->webPageChanged(webPage); +} + +QString MauiApp::getDonationPage() const +{ + return donationPage; +} + +void MauiApp::setDonationPage(const QString &value) +{ + if(donationPage == value) + return; + + donationPage = value; + emit this->donationPageChanged(donationPage); +} + +QString MauiApp::getReportPage() const +{ + return reportPage; +} + +void MauiApp::setReportPage(const QString &value) +{ + if(reportPage == value) + return; + + reportPage = value; + emit this->reportPageChanged(reportPage); +} + +bool MauiApp::getHandleAccounts() const +{ + return this->handleAccounts; +} + +void MauiApp::setHandleAccounts(const bool &value) +{ +#ifdef COMPONENT_ACCOUNTS + if(this->handleAccounts == value) + return; + + this->handleAccounts = value; + emit this->handleAccountsChanged(); +#endif +} + +#ifdef COMPONENT_ACCOUNTS MauiAccounts * MauiApp::getAccounts() const { return this->m_accounts; } +#endif MauiApp * MauiApp::qmlAttachedProperties(QObject* object) { if(MauiApp::m_instance == nullptr) MauiApp::m_instance = new MauiApp(object); return MauiApp::m_instance; } diff --git a/src/utils/mauiapp.h b/src/utils/mauiapp.h index b618cf9..ccd992c 100644 --- a/src/utils/mauiapp.h +++ b/src/utils/mauiapp.h @@ -1,134 +1,132 @@ /* * * Copyright (C) 2019 camilo * * 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 3 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, see . */ #ifndef MAUIAPP_H #define MAUIAPP_H #include #include #include "handy.h" #include "fmh.h" #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif class MauiAccounts; #ifdef STATIC_MAUIKIT class MauiApp : public QObject #else class MAUIKIT_EXPORT MauiApp : public QObject #endif { Q_OBJECT Q_PROPERTY(QString name READ getName CONSTANT) Q_PROPERTY(QString version READ getVersion CONSTANT) Q_PROPERTY(QString org READ getOrg CONSTANT) Q_PROPERTY(QString domain READ getDomain CONSTANT) Q_PROPERTY(QString iconName READ getIconName WRITE setIconName NOTIFY iconNameChanged) Q_PROPERTY(QString description READ getDescription WRITE setDescription NOTIFY descriptionChanged) + Q_PROPERTY(QString webPage READ getWebPage WRITE setWebPage NOTIFY webPageChanged) + Q_PROPERTY(QString reportPage READ getReportPage WRITE setReportPage NOTIFY reportPageChanged) + Q_PROPERTY(QString donationPage READ getDonationPage WRITE setDonationPage NOTIFY donationPageChanged) Q_PROPERTY(QString mauikitVersion READ getMauikitVersion CONSTANT) Q_PROPERTY(QString qtVersion READ getQtVersion CONSTANT) + Q_PROPERTY(bool handleAccounts READ getHandleAccounts WRITE setHandleAccounts NOTIFY handleAccountsChanged) +#ifdef COMPONENT_ACCOUNTS Q_PROPERTY(MauiAccounts * accounts READ getAccounts CONSTANT FINAL) - +#endif public: static MauiApp *qmlAttachedProperties(QObject *object); static MauiApp *instance(); - static QString getName() - { - return Handy::appInfo().value(FMH::MODEL_NAME[FMH::MODEL_KEY::NAME]).toString(); - } - - static QString getVersion() - { - return Handy::appInfo().value(FMH::MODEL_NAME[FMH::MODEL_KEY::VERSION]).toString(); - } - - static QString getOrg() - { - return Handy::appInfo().value(FMH::MODEL_NAME[FMH::MODEL_KEY::ORG]).toString(); - } - - static QString getDomain() - { - return Handy::appInfo().value(FMH::MODEL_NAME[FMH::MODEL_KEY::DOMAIN]).toString(); - } - - static QString getMauikitVersion() - { - return Handy::appInfo().value("mauikit_version").toString(); - } - - static QString getQtVersion() - { - return Handy::appInfo().value("qt_version").toString(); - } - - QString getDescription() const - { - return description; - } - - void setDescription(const QString &value) - { - if(description == value) - return; - - description = value; - emit this->descriptionChanged(description); - } - - QString getIconName() const - { - return iconName; - } - - void setIconName(const QString &value) - { - if(iconName == value) - return; - - iconName = value; - emit this->iconNameChanged(iconName); - } + static QString getName(); - MauiAccounts *getAccounts() const; + static QString getVersion(); + + static QString getOrg(); + + static QString getDomain(); + + static QString getMauikitVersion(); + + static QString getQtVersion(); + + QString getDescription() const; + + void setDescription(const QString &value); + + QString getIconName() const; + + void setIconName(const QString &value); + + QString getWebPage() const; + + void setWebPage(const QString &value); + QString getDonationPage() const; + + void setDonationPage(const QString &value); + + QString getReportPage() const; + + void setReportPage(const QString &value); + + bool getHandleAccounts() const; + void setHandleAccounts(const bool &value); + +#ifdef COMPONENT_ACCOUNTS + MauiAccounts *getAccounts() const; +#endif + ~MauiApp(); private: static MauiApp *m_instance; MauiApp(QObject *parent = nullptr); MauiApp(const MauiApp &other) = delete; MauiAccounts *m_accounts; QString description; QString iconName; + QString webPage; + QString donationPage; + QString reportPage; + +#ifdef COMPONENT_ACCOUNTS + bool handleAccounts = true; +#else + bool handleAccounts = false; +#endif + signals: void iconNameChanged(QString iconName); void descriptionChanged(QString description); + void webPageChanged(QString webPage); + void donationPageChanged(QString donationPage); + void reportPageChanged(QString reportPage); + void handleAccountsChanged(); }; QML_DECLARE_TYPEINFO(MauiApp, QML_HAS_ATTACHED_PROPERTIES) #endif // MAUIAPP_H diff --git a/src/fm/pathlist.cpp b/src/utils/models/pathlist.cpp similarity index 85% rename from src/fm/pathlist.cpp rename to src/utils/models/pathlist.cpp index 03a075a..62cdd02 100644 --- a/src/fm/pathlist.cpp +++ b/src/utils/models/pathlist.cpp @@ -1,107 +1,106 @@ /* * * Copyright (C) 2019 camilo * * 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 3 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, see . */ #include "pathlist.h" -#include "fm.h" PathList::PathList(QObject *parent) : MauiList(parent) { } PathList::~PathList() {} QVariantMap PathList::get(const int& index) const { if(this->list.isEmpty() || index >= this->list.size() || index < 0) { return QVariantMap(); } const auto model = this->list.at(index); - return FM::toMap(model); + return FMH::toMap(model); } QString PathList::getPath() const { return this->m_path; } FMH::MODEL_LIST PathList::items() const { return this->list; } void PathList::setPath(const QString& path) { if(path == this->m_path) return; - if(!this->list.isEmpty() && FM::parentDir(path) == this->m_path) + if(!this->list.isEmpty() && QUrl(this->m_path).isParentOf(path)) { emit this->preItemAppended(); this->list << FMH::getDirInfoModel(path); emit this->postItemAppended(); }else{ emit this->preListChanged(); this->list.clear(); this->list << PathList::splitPath(path); emit this->postListChanged(); } this->m_path = path; - emit this->pathChanged(); - + emit this->pathChanged(); } FMH::MODEL_LIST PathList::splitPath(const QString& path) { QString __url = path; QString __scheme; if(path.contains(":")) //means it has a scheme { const auto parts = QString(path).split(":", QString::SplitBehavior::SkipEmptyParts); __url = parts[1]; __scheme = parts[0]; } - - qDebug()<< "STRING TO SPLIT"<< __url << path << __scheme; const auto paths = __url.split("/", QString::SplitBehavior::SkipEmptyParts); + qDebug()<< "STRING TO SPLIT"<< __url << path << __scheme << paths; + + if(paths.isEmpty()) { return {{{FMH::MODEL_KEY::LABEL, path}, {FMH::MODEL_KEY::PATH, path}}}; } return std::accumulate(paths.constBegin(), paths.constEnd(), FMH::MODEL_LIST(), [__scheme](FMH::MODEL_LIST &list, const QString &part) -> FMH::MODEL_LIST { - const auto url = list.isEmpty() ? QString(__scheme + (__scheme == FMH::PATHTYPE_SCHEME[FMH::PATHTYPE_KEY::PLACES_PATH] ? ":///" : "://") +part) : list.last()[FMH::MODEL_KEY::PATH] + QString("/"+part); + const auto url = list.isEmpty() ? QString(__scheme + ":///" +part) : list.last()[FMH::MODEL_KEY::PATH] + QString("/"+part); if(!url.isEmpty()) list << FMH::MODEL { {FMH::MODEL_KEY::LABEL, part}, {FMH::MODEL_KEY::PATH, url} }; return list; }); } diff --git a/src/fm/pathlist.h b/src/utils/models/pathlist.h similarity index 100% rename from src/fm/pathlist.h rename to src/utils/models/pathlist.h diff --git a/src/utils/store/storelist.cpp b/src/utils/store/storelist.cpp index 3c96439..2f31ada 100644 --- a/src/utils/store/storelist.cpp +++ b/src/utils/store/storelist.cpp @@ -1,334 +1,334 @@ /* * * Copyright (C) 2018 camilo * * 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 3 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, see . */ #include "storelist.h" #include "fm.h" StoreList::StoreList(QObject *parent) : QObject(parent) { this->store = new Store(this); this->store->setProvider(STORE::KDELOOK_API); this->store->start(); connect(this->store, &Store::contentReady, [this](const FMH::MODEL_LIST &list) { emit this->preListChanged(); this->list = list; this->sortList(); qDebug()<< "STORE LIST READY" << list; emit this->postListChanged(); this->contentReady = true; emit this->contentReadyChanged(); this->contentEmpty = this->list.isEmpty(); emit this->contentEmptyChanged(); }); connect(this->store, &Store::warning, [this](const QString warning) { emit this->warning(warning); }); connect(this->store, &Store::downloadReady, [this] (const FMH::MODEL &item) { - emit this->downloadReady(FM::toMap(item)); + emit this->downloadReady(FMH::toMap(item)); }); connect(this->store, &Store::storeReady, this, &StoreList::setList); } QVariantMap StoreList::get(const int& index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); QVariantMap res; const auto model = this->list.at(index); for(auto key : model.keys()) res.insert(FMH::MODEL_NAME[key], model[key]); return res; } void StoreList::download(const int& index) { if(index >= this->list.size() || index < 0) return; // this->store->download(this->list[index][FMH::MODEL_KEY::ID]); this->store->download(this->list[index]); } FMH::MODEL_LIST StoreList::items() const { return this->list; } void StoreList::getPersonInfo(const QString& nick) { this->store->getPersonInfo(nick); } void StoreList::setList() { emit this->preListChanged(); this->list.clear(); emit this->postListChanged(); this->contentEmpty = this->list.isEmpty(); emit this->contentEmptyChanged(); this->contentReady = false; emit this->contentReadyChanged(); this->store->searchFor(static_cast(this->category), this->query, this->limit, this->page, static_cast(this->sortBy)); } StoreList::CATEGORY StoreList::getCategory() const { return this->category; } void StoreList::setCategory(const StoreList::CATEGORY& value) { if(this->category == value) return; this->category = value; emit this->categoryChanged(); this->setList(); } int StoreList::getLimit() const { return this->limit; } void StoreList::setLimit(const int& value) { if(this->limit == value) return; this->limit = value; emit this->limitChanged(); this->setList(); } int StoreList::getPage() const { return this->page; } void StoreList::setPage(const int& value) { if(this->page == value) return; this->page = value; emit this->pageChanged(); this->setList(); } StoreList::ORDER StoreList::getOrder() const { return this->order; } void StoreList::setOrder(const StoreList::ORDER& value) { if(this->order == value) return; this->order = value; emit this->orderChanged(); } QString StoreList::getQuery() const { return this->query; } void StoreList::setQuery(const QString& value) { if(this->query == value) return; this->query = value; emit this->queryChanged(); this->page = 0; emit this->pageChanged(); this->setList(); } QVariantList StoreList::getCategoryList() { QVariantList res; auto data = STORE::CATEGORIES[static_cast(this->category)]; for(auto category : data) res << QVariantMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::LABEL], category}}; return res; } bool StoreList::getContentReady() const { return this->contentReady; } bool StoreList::getContentEmpty() const { return this->contentEmpty; } StoreList::SORTBY StoreList::getSortBy() const { return this->sortBy; } void StoreList::setSortBy(const StoreList::SORTBY& key) { if(this->sortBy == key) return; this->sortBy = key; emit this->sortByChanged(); this->setList(); } void StoreList::sortList() { qDebug()<< "TRYING TO SORT LIST" << this->list.size(); qSort(this->list.begin(), this->list.begin(), [this](const FMH::MODEL& e1, const FMH::MODEL& e2) -> bool { qDebug()<< "TRYIT LIST"; auto role = static_cast(this->sortBy);; switch(role) { case FMH::MODEL_KEY::RATE: case FMH::MODEL_KEY::COUNT: { if(e1[role].toDouble() > e2[role].toDouble()) return true; break; } case FMH::MODEL_KEY::MODIFIED: case FMH::MODEL_KEY::DATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case FMH::MODEL_KEY::LABEL: case FMH::MODEL_KEY::USER: case FMH::MODEL_KEY::OWNER: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } StoreList::PROVIDER StoreList::getProvider() const { return this->provider; } void StoreList::setProvider(const StoreList::PROVIDER &key) { if(this->provider == key) return; this->provider = key; STORE::PROVIDER value; switch(this->provider) { case StoreList::PROVIDER::KDELOOK: value = STORE::KDELOOK_API; break; case StoreList::PROVIDER::OPENDESKTOP: value = STORE::OPENDESKTOP_API; break; case StoreList::PROVIDER::OPENDESKTOPCC: value = STORE::OPENDESKTOPCC_API; break; case StoreList::PROVIDER::KRITA: value = STORE::KRITA_API; break; } this->store->setProvider(value); emit this->providerChanged(); } bool StoreList::fileExists(const int &index) { if(index >= this->list.size() || index < 0) return false; const auto url = this->list[index][FMH::MODEL_KEY::URL]; const QStringList filePathList = url.split('/'); const auto fileName = filePathList.at(filePathList.count() - 1); qDebug() << "Check if file exists" << FMH::DownloadsPath+"/"+fileName; return FMH::fileExists(FMH::DownloadsPath+"/"+fileName); } QString StoreList::itemLocalPath(const int &index) { if(!this->fileExists(index)) return QString(); const auto url = this->list[index][FMH::MODEL_KEY::URL]; const QStringList filePathList = url.split('/'); const auto fileName = filePathList.at(filePathList.count() - 1); return FMH::DownloadsPath+"/"+fileName; } diff --git a/src/utils/syncing/libwebdavclient/webdavclient.pri b/src/utils/syncing/libwebdavclient/webdavclient.pri index 2d13f22..6bf3e89 100644 --- a/src/utils/syncing/libwebdavclient/webdavclient.pri +++ b/src/utils/syncing/libwebdavclient/webdavclient.pri @@ -1,30 +1,30 @@ VERSION = $$cat($$PWD/VERSION) -QT += \ +QT *= \ core \ xml \ network \ testlib CONFIG += c++11 HEADERS += \ $$PWD/lib/WebDAVClient.hpp \ $$PWD/lib/utils/XMLHelper.hpp \ $$PWD/lib/utils/WebDAVReply.hpp \ $$PWD/lib/utils/NetworkHelper.hpp \ $$PWD/lib/utils/Environment.hpp \ $$PWD/lib/dto/WebDAVItem.hpp SOURCES += \ $$PWD/lib/WebDAVClient.cpp \ $$PWD/lib/utils/NetworkHelper.cpp \ $$PWD/lib/utils/Environment.cpp \ $$PWD/lib/utils/XMLHelper.cpp \ $$PWD/lib/utils/WebDAVReply.cpp \ $$PWD/lib/dto/WebDAVItem.cpp INCLUDEPATH += \ $$PWD/lib \ $$PWD/lib/utils \ $$PWD/lib/dto diff --git a/src/utils/syncing/syncing.cpp b/src/utils/syncing/syncing.cpp index 923aeba..2cc5411 100644 --- a/src/utils/syncing/syncing.cpp +++ b/src/utils/syncing/syncing.cpp @@ -1,405 +1,406 @@ #include "syncing.h" #include "fm.h" #include #include #include #include "WebDAVClient.hpp" #include "WebDAVItem.hpp" #include "WebDAVReply.hpp" Syncing::Syncing(QObject *parent) : QObject(parent) { this->setCredentials(this->host, this->user, this->password); } -void Syncing::listContent(const QString &path, const QStringList &filters, const int &depth) +void Syncing::listContent(const QUrl &path, const QStringList &filters, const int &depth) { this->currentPath = path; auto url = QUrl(path).path().replace(user, ""); this->listDirOutputHandler(this->client->listDir(url, static_cast(depth)), filters); } void Syncing::setCredentials(const QString &server, const QString &user, const QString &password) { this->host = server; this->user = user; this->password = password; this->client = new WebDAVClient(this->host, this->user, this->password); } void Syncing::listDirOutputHandler(WebDAVReply *reply, const QStringList &filters) { connect(reply, &WebDAVReply::listDirResponse, [=](QNetworkReply *listDirReply, QList items) { // qDebug() << "URL :" << listDirReply->url(); // qDebug() << "Received List of" << items.length() << "items"; // qDebug() << endl << "---------------------------------------"; FMH::MODEL_LIST list; for (WebDAVItem item : items) { const auto url = QUrl(item.getHref()).toString(); auto path = QString(FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]+this->user+"/")+QString(url).replace("/remote.php/webdav/", ""); auto displayName = item.getContentType().isEmpty() ? QString(url).replace("/remote.php/webdav/", "").replace("/", "") : QString(path).right(path.length()-path.lastIndexOf("/")-1); // qDebug()<< "PATHS:" << path << this->currentPath; - if(QString(url).replace("/remote.php/webdav/", "").isEmpty() || path == this->currentPath) + if(QString(url).replace("/remote.php/webdav/", "").isEmpty() || path == this->currentPath.toString()) continue; // qDebug()<< "FILTERING "<< filters << QString(displayName).right(displayName.length() - displayName.lastIndexOf(".")); if(!filters.isEmpty() && !filters.contains("*"+QString(displayName).right(displayName.length() - displayName.lastIndexOf(".")))) continue; list << FMH::MODEL { {FMH::MODEL_KEY::LABEL, displayName}, {FMH::MODEL_KEY::NAME, item.getDisplayName()}, {FMH::MODEL_KEY::DATE, item.getCreationDate().toString(Qt::TextDate)}, {FMH::MODEL_KEY::MODIFIED, item.getLastModified()}, {FMH::MODEL_KEY::MIME, item.getContentType().isEmpty() ? "inode/directory" : item.getContentType()}, {FMH::MODEL_KEY::ICON, FMH::getIconName(url)}, {FMH::MODEL_KEY::SIZE, QString::number(item.getContentLength())}, {FMH::MODEL_KEY::PATH, path}, - {FMH::MODEL_KEY::URL, url}, - {FMH::MODEL_KEY::THUMBNAIL, item.getContentType().isEmpty() ? url : this->getCacheFile(url)}}; + {FMH::MODEL_KEY::URL, url}, + {FMH::MODEL_KEY::THUMBNAIL, item.getContentType().isEmpty() ? url : this->getCacheFile(url).toString()} + }; } emit this->listReady(list, this->currentPath); }); connect(reply, &WebDAVReply::error, [=](QNetworkReply::NetworkError err) { // qDebug() << "ERROR" << err; this->emitError(err); }); } -QString Syncing::getCacheFile(const QString& path) +QUrl Syncing::getCacheFile(const QUrl &path) { - const auto directory = FM::resolveUserCloudCachePath(this->host, this->user); - const auto file = directory + QString(path).replace("remote.php/webdav/", ""); + const auto directory = FM::resolveUserCloudCachePath(this->host, this->user); + const auto file = directory + path.toString().replace("remote.php/webdav/", ""); qDebug()<< "resolving file"<< file; if(FMH::fileExists(file)) return file; else return path; } -void Syncing::download(const QString& path) +void Syncing::download(const QUrl &path) { - QString url = QString(path).replace("remote.php/webdav/", ""); + QString url = QString(path.toString()).replace("remote.php/webdav/", ""); WebDAVReply *reply = this->client->downloadFrom(url); qDebug()<< "CURRENT CREDENTIALS"<< this->host << this->user; connect(reply, &WebDAVReply::downloadResponse, [=](QNetworkReply *reply) { if (!reply->error()) { qDebug() << "\nDownload Success" << "\nURL :" << reply->url() << "\nSize :" << reply->size(); auto file = reply->readAll(); const auto directory = FMH::CloudCachePath+"opendesktop/"+this->user; QDir dir(directory); if (!dir.exists()) dir.mkpath("."); this->saveTo(file, directory+url); } else { qDebug() << "ERROR(DOWNLOAD)" << reply->error() << reply->url() <error(reply->errorString()); } }); connect(reply, &WebDAVReply::downloadProgressResponse, [=](qint64 bytesReceived, qint64 bytesTotal) { int percent = ((float)bytesReceived / bytesTotal) * 100; qDebug() << "\nReceived : " << bytesReceived << "\nTotal : " << bytesTotal << "\nPercent : " << percent; emit this->progress(percent); }); connect(reply, &WebDAVReply::error, [=](QNetworkReply::NetworkError err) { qDebug() << "ERROR" << err; }); } -void Syncing::upload(const QString &path, const QString &filePath) +void Syncing::upload(const QUrl &path, const QUrl &filePath) { if(!FMH::fileExists(filePath)) return; qDebug()<< "Copy to cloud. File exists" << path << filePath; - this->mFile.setFileName(filePath); + this->mFile.setFileName(filePath.toString()); if(this->mFile.open(QIODevice::ReadOnly)) { qDebug()<< "Copy to cloud. File could be opened"; - WebDAVReply *reply = this->client->uploadTo(path, QFileInfo(filePath).fileName(), &this->mFile); + WebDAVReply *reply = this->client->uploadTo(path.toString(), QFileInfo(filePath.toString()).fileName(), &this->mFile); connect(reply, &WebDAVReply::uploadFinished, [=](QNetworkReply *reply) { if (!reply->error()) { qDebug() << "\nUpload Success" << "\nURL :" << reply->url() << "\nSize :" << reply->size(); - auto cachePath = this->saveToCache(filePath, path); + auto cachePath = this->saveToCache(filePath.toString(), path); auto item = FMH::getFileInfoModel(cachePath); // item[FMH::MODEL_KEY::PATH] = this->currentPath+"/"+QFileInfo(filePath).fileName()+"/"; emit this->uploadReady(item, this->currentPath); } else { qDebug() << "ERROR(UPLOAD)" << reply->error(); emit this->error(reply->errorString()); } if(!this->uploadQueue.isEmpty()) { qDebug()<<"UPLOAD QUEUE" << this->uploadQueue; this->upload(path, this->uploadQueue.takeLast()); } }); connect(reply, &WebDAVReply::error, [=](QNetworkReply::NetworkError err) { qDebug() << "ERROR" << err; this->emitError(err); });} } -void Syncing::createDir(const QString &path, const QString &name) +void Syncing::createDir(const QUrl &path, const QString &name) { - WebDAVReply *reply = this->client->createDir(path, name); + WebDAVReply *reply = this->client->createDir(path.toString(), name); connect(reply, &WebDAVReply::createDirFinished, [=](QNetworkReply *reply) { if (!reply->error()) { qDebug() << "\nDir Created" << "\nURL :" << reply->url(); FMH::MODEL dir = { {FMH::MODEL_KEY::LABEL, name}, {FMH::MODEL_KEY::DATE, QDateTime::currentDateTime().toString(Qt::TextDate)}, {FMH::MODEL_KEY::MIME, "inode/directory"}, {FMH::MODEL_KEY::ICON, "folder"}, - {FMH::MODEL_KEY::PATH, this->currentPath+"/"+name+"/"} + {FMH::MODEL_KEY::PATH, this->currentPath.toString()+"/"+name+"/"} }; emit this->dirCreated(dir, this->currentPath); } else { qDebug() << "ERROR(CREATE DIR)" << reply->error(); emit this->error(reply->errorString()); } }); connect(reply, &WebDAVReply::error, [=](QNetworkReply::NetworkError err) { qDebug() << "ERROR" << err; this->emitError(err); }); } void Syncing::emitError(const QNetworkReply::NetworkError &err) { switch(err) { case QNetworkReply::AuthenticationRequiredError: emit this->error("The remote server requires authentication to serve the content but the credentials provided were not accepted (if any)"); break; case QNetworkReply::ConnectionRefusedError: emit this->error("the remote server refused the connection (the server is not accepting requests)"); break; case QNetworkReply::RemoteHostClosedError: emit this->error("the remote server closed the connection prematurely, before the entire reply was received and processed"); break; case QNetworkReply::HostNotFoundError: emit this->error("the remote host name was not found (invalid hostname)"); break; case QNetworkReply::TimeoutError: emit this->error("the connection to the remote server timed out"); break; case QNetworkReply::OperationCanceledError: emit this->error("the operation was canceled via calls to abort() or close() before it was finished."); break; case QNetworkReply::SslHandshakeFailedError: emit this->error("the SSL/TLS handshake failed and the encrypted channel could not be established. The sslErrors() signal should have been emitted."); break; case QNetworkReply::TemporaryNetworkFailureError: emit this->error("the connection was broken due to disconnection from the network, however the system has initiated roaming to another access point. The request should be resubmitted and will be processed as soon as the connection is re-established."); break; case QNetworkReply::NetworkSessionFailedError: emit this->error("the connection was broken due to disconnection from the network or failure to start the network."); break; case QNetworkReply::BackgroundRequestNotAllowedError: emit this->error("the background request is not currently allowed due to platform policy."); break; case QNetworkReply::TooManyRedirectsError: emit this->error("while following redirects, the maximum limit was reached. The limit is by default set to 50 or as set by QNetworkRequest::setMaxRedirectsAllowed(). (This value was introduced in 5.6.)"); break; case QNetworkReply::InsecureRedirectError: emit this->error("while following redirects, the network access API detected a redirect from a encrypted protocol (https) to an unencrypted one (http)."); break; case QNetworkReply::ProxyConnectionRefusedError: emit this->error("the connection to the proxy server was refused (the proxy server is not accepting requests)"); break; case QNetworkReply::ProxyConnectionClosedError: emit this->error("the proxy server closed the connection prematurely, before the entire reply was received and processed"); break; case QNetworkReply::ProxyNotFoundError: emit this->error("the proxy host name was not found (invalid proxy hostname)"); break; case QNetworkReply::ProxyTimeoutError: emit this->error("the connection to the proxy timed out or the proxy did not reply in time to the request sent"); break; case QNetworkReply::ProxyAuthenticationRequiredError: emit this->error("the proxy requires authentication in order to honour the request but did not accept any credentials offered (if any)"); break; case QNetworkReply::ContentAccessDenied: emit this->error("the access to the remote content was denied (similar to HTTP error 403)"); break; case QNetworkReply::ContentOperationNotPermittedError: emit this->error("the operation requested on the remote content is not permitted"); break; case QNetworkReply::ContentNotFoundError: emit this->error("the remote content was not found at the server (similar to HTTP error 404)"); break; case QNetworkReply::ContentReSendError: emit this->error("the request needed to be sent again, but this failed for example because the upload data could not be read a second time."); break; case QNetworkReply::ServiceUnavailableError: emit this->error("the server is unable to handle the request at this time."); break; default: emit this->error("There was an unknown error with the remote server or your internet connection."); } } -void Syncing::saveTo(const QByteArray &array, const QString& path) +void Syncing::saveTo(const QByteArray &array, const QUrl &path) { - QFile file(path); + QFile file(path.toLocalFile()); if(!file.exists()) { QDir dir; - uint cut = path.length()- path.lastIndexOf("/") -1; - auto newPath = QString(path).right(cut); - dir.mkdir(QString(path).replace(newPath, "")); + uint cut = path.toString().length()- path.toString().lastIndexOf("/") -1; + auto newPath = path.toString().right(cut); + dir.mkdir(path.toString().replace(newPath, "")); qDebug()<< newPath << cut; }else file.remove(); file.open(QIODevice::WriteOnly); file.write(array); file.close(); emit this->itemReady(FMH::getFileInfoModel(path), this->currentPath, this->signalType); // emit this->itemReady(FMH::getFileInfoModel(path)); } -QString Syncing::saveToCache(const QString& file, const QString &where) +QString Syncing::saveToCache(const QString& file, const QUrl &where) { - auto directory = FMH::CloudCachePath+"opendesktop/"+this->user+"/"+where; + const auto directory = FMH::CloudCachePath+"opendesktop/"+this->user+"/"+where.toString(); QDir dir(directory); if (!dir.exists()) dir.mkpath("."); const auto newPath = directory+"/"+QFileInfo(file).fileName(); if(QFile::copy(file, newPath)) return newPath; return QString(); } void Syncing::resolveFile(const FMH::MODEL& item, const Syncing::SIGNAL_TYPE &signalType) { this->signalType = signalType; const auto url = item[FMH::MODEL_KEY::URL]; const auto file = this->getCacheFile(url); if(FMH::fileExists(file)) { const auto cacheFile = FMH::getFileInfoModel(file); const auto dateCacheFile = QDateTime::fromString(cacheFile[FMH::MODEL_KEY::DATE], Qt::TextDate); const auto dateCloudFile = QDateTime::fromString(QString(item[FMH::MODEL_KEY::MODIFIED]).replace("GMT", "").simplified(), "ddd, dd MMM yyyy hh:mm:ss"); qDebug()<<"FILE EXISTS ON CACHE" << dateCacheFile << dateCloudFile<< QString(item[FMH::MODEL_KEY::MODIFIED]).replace("GMT", "").simplified()<< file; if(dateCloudFile > dateCacheFile) this->download(url); else emit this->itemReady(cacheFile, this->currentPath, this->signalType); } else this->download(url); } -void Syncing::setCopyTo(const QString &path) +void Syncing::setCopyTo(const QUrl &path) { if(this->copyTo == path) return; this->copyTo = path; } -QString Syncing::getCopyTo() const +QUrl Syncing::getCopyTo() const { return this->copyTo; } QString Syncing::getUser() const { return this->user; } void Syncing::setUploadQueue(const QStringList& list) { this->uploadQueue = list; } QString Syncing::localToAbstractCloudPath(const QString& url) { return QString(url).replace(FMH::CloudCachePath+"opendesktop", FMH::PATHTYPE_URI[FMH::PATHTYPE_KEY::CLOUD_PATH]); } diff --git a/src/utils/syncing/syncing.h b/src/utils/syncing/syncing.h index 520eccb..188d393 100644 --- a/src/utils/syncing/syncing.h +++ b/src/utils/syncing/syncing.h @@ -1,88 +1,88 @@ #ifndef SYNCING_H #define SYNCING_H #include #include #include "fmh.h" #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif class WebDAVClient; class WebDAVReply; #ifdef STATIC_MAUIKIT class Syncing : public QObject #else class MAUIKIT_EXPORT Syncing : public QObject #endif { Q_OBJECT public: enum SIGNAL_TYPE : uint_fast8_t { OPEN, DOWNLOAD, COPY, SAVE, CUT, DELETE, RENAME, MOVE, UPLOAD }; QStringList uploadQueue; explicit Syncing(QObject *parent = nullptr); - void listContent(const QString &path, const QStringList &filters, const int &depth = 1); + void listContent(const QUrl &path, const QStringList &filters, const int &depth = 1); void setCredentials(const QString &server, const QString &user, const QString &password); - void download(const QString &path); - void upload(const QString &path, const QString &filePath); - void createDir(const QString &path, const QString &name); + void download(const QUrl &path); + void upload(const QUrl &path, const QUrl &filePath); + void createDir(const QUrl &path, const QString &name); void resolveFile(const FMH::MODEL &item, const Syncing::SIGNAL_TYPE &signalType); - void setCopyTo(const QString &path); - QString getCopyTo() const; + void setCopyTo(const QUrl &path); + QUrl getCopyTo() const; QString getUser() const; void setUploadQueue(const QStringList &list); QString localToAbstractCloudPath(const QString &url); private: WebDAVClient *client; QString host = "https://cloud.opendesktop.cc/remote.php/webdav/"; QString user = "mauitest"; QString password = "mauitest"; void listDirOutputHandler(WebDAVReply *reply, const QStringList &filters = QStringList()); - void saveTo(const QByteArray &array, const QString& path); - QString saveToCache(const QString& file, const QString &where); - QString getCacheFile(const QString &path); + void saveTo(const QByteArray &array, const QUrl& path); + QString saveToCache(const QString& file, const QUrl &where); + QUrl getCacheFile(const QUrl &path); - QString currentPath; - QString copyTo; + QUrl currentPath; + QUrl copyTo; void emitError(const QNetworkReply::NetworkError &err); SIGNAL_TYPE signalType; QFile mFile; signals: - void listReady(FMH::MODEL_LIST data, QString url); - void itemReady(FMH::MODEL item, QString url, Syncing::SIGNAL_TYPE &signalType); - void dirCreated(FMH::MODEL item, QString url); - void uploadReady(FMH::MODEL item, QString url); + void listReady(FMH::MODEL_LIST data, QUrl url); + void itemReady(FMH::MODEL item, QUrl url, Syncing::SIGNAL_TYPE &signalType); + void dirCreated(FMH::MODEL item, QUrl url); + void uploadReady(FMH::MODEL item, QUrl url); void error(QString message); void progress(int percent); public slots: }; #endif // SYNCING_H diff --git a/src/utils/tagging/tagdb.cpp b/src/utils/tagging/tagdb.cpp index 11c2e87..2a809b6 100644 --- a/src/utils/tagging/tagdb.cpp +++ b/src/utils/tagging/tagdb.cpp @@ -1,241 +1,235 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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 "tagdb.h" #include TAGDB::TAGDB(QObject *parent) : QObject(parent) { QDir collectionDBPath_dir(TAG::TaggingPath); if (!collectionDBPath_dir.exists()) collectionDBPath_dir.mkpath("."); this->name = QUuid::createUuid().toString(); if(!UTIL::fileExists(TAG::TaggingPath + TAG::DBName)) { this->openDB(this->name); qDebug()<<"Collection doesn't exists, trying to create it" << TAG::TaggingPath + TAG::DBName; this->prepareCollectionDB(); }else this->openDB(this->name); } TAGDB::~TAGDB() { this->m_db.close(); } void TAGDB::openDB(const QString &name) { if(!QSqlDatabase::contains(name)) { this->m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), name); this->m_db.setDatabaseName(TAG::TaggingPath + TAG::DBName); } if (!this->m_db.isOpen()) { if(!this->m_db.open()) qDebug()<<"ERROR OPENING DB"<m_db.lastError().text()<getQuery("PRAGMA synchronous=OFF"); query.exec(); } void TAGDB::prepareCollectionDB() const { QSqlQuery query(this->m_db); QFile file(":/script.sql"); if (!file.exists()) { QString log = QStringLiteral("Fatal error on build database. The file '"); log.append(file.fileName() + QStringLiteral("' for database and tables creation query cannot be not found!")); qDebug()<getQuery(queryStr); - - if (query.exec()) - { - if (query.next()) return true; - }else qDebug()<checkExistance(queryStr); } bool TAGDB::checkExistance(const QString &queryStr) { + qDebug()<< "CHECKIGN QUERY TAG" << queryStr; auto query = this->getQuery(queryStr); if (query.exec()) { if (query.next()) return true; }else qDebug()<m_db); return query; } bool TAGDB::insert(const QString &tableName, const QVariantMap &insertData) { if (tableName.isEmpty()) { qDebug()<m_db); query.prepare(sqlQueryString); int k = 0; foreach (const QVariant &value, values) query.bindValue(k++, value); return query.exec(); } bool TAGDB::update(const QString &tableName, const TAG::DB &updateData, const QVariantMap &where) { if (tableName.isEmpty()) { qDebug()<getQuery(sqlQueryString); qDebug()<getQuery(queryStr); return query.exec(); } bool TAGDB::remove(const QString &tableName, const TAG::DB &removeData) { if (tableName.isEmpty()) { qDebug()< 1 && igetQuery(sqlQueryString).exec(); } diff --git a/src/utils/tagging/tagging.cpp b/src/utils/tagging/tagging.cpp index 6536019..92da433 100644 --- a/src/utils/tagging/tagging.cpp +++ b/src/utils/tagging/tagging.cpp @@ -1,362 +1,368 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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 "tagging.h" #include #include #include "utils.h" Tagging::Tagging(QObject *parent) : TAGDB(parent) { this->setApp(); } Tagging::~Tagging() { // delete this->instance; } Tagging *Tagging::instance = nullptr; Tagging *Tagging::getInstance() { if(!instance) { instance = new Tagging(); qDebug() << "getInstance(): First instance\n"; return instance; } else { qDebug()<< "getInstance(): previous instance\n"; return instance; } } QVariantList Tagging::get(const QString &queryTxt) { QVariantList mapList; auto query = this->getQuery(queryTxt); if(query.exec()) { while(query.next()) { QVariantMap data; for(auto key : TAG::KEYMAP.keys()) if(query.record().indexOf(TAG::KEYMAP[key]) > -1) data[TAG::KEYMAP[key]] = query.value(TAG::KEYMAP[key]).toString(); mapList<< data; } }else qDebug()<< query.lastError()<< query.lastQuery(); return mapList; } bool Tagging::tagExists(const QString &tag, const bool &strict) { return !strict ? this->checkExistance(TAG::TABLEMAP[TAG::TABLE::TAGS], TAG::KEYMAP[TAG::KEYS::TAG], tag) : this->checkExistance(QString("select t.tag from TAGS t inner join TAGS_USERS tu on t.tag = tu.tag inner join APPS_USERS au on au.mac = tu.mac " "where au.app = '%1' and au.uri = '%2' and t.tag = '%3'").arg(this->application, this->uri, tag)); } +bool Tagging::urlTagExists(const QString &url,const QString &tag, const bool &strict) +{ + return !strict ? this->checkExistance(QString("select * from TAGS_URLS where url = '%1' and tag = '%2'").arg(url, tag)) : + this->checkExistance(QString("select t.tag from TAGS t inner join TAGS_USERS tu on t.tag = tu.tag inner join APPS_USERS au on au.mac = tu.mac " + "where au.app = '%1' and au.uri = '%2' and t.tag = '%3'").arg(this->application, this->uri, tag)); +} void Tagging::setApp() { this->application = UTIL::app->applicationName(); this->version = UTIL::app->applicationVersion(); this->comment = QString(); this->uri = UTIL::app->organizationDomain().isEmpty() ? QString("org.maui.%1").arg(this->application) : UTIL::app->organizationDomain(); this->app(); } bool Tagging::tag(const QString &tag, const QString &color, const QString &comment) { if(tag.isEmpty()) return false; QVariantMap tag_map { {TAG::KEYMAP[TAG::KEYS::TAG], tag}, {TAG::KEYMAP[TAG::KEYS::COLOR], color}, {TAG::KEYMAP[TAG::KEYS::ADD_DATE], QDateTime::currentDateTime()}, {TAG::KEYMAP[TAG::KEYS::COMMENT], comment}, }; this->insert(TAG::TABLEMAP[TAG::TABLE::TAGS], tag_map); QVariantMap tag_user_map { {TAG::KEYMAP[TAG::KEYS::TAG], tag}, {TAG::KEYMAP[TAG::KEYS::MAC], this->id()} }; if(this->insert(TAG::TABLEMAP[TAG::TABLE::TAGS_USERS], tag_user_map)) { emit this->tagged(tag); return true; } return false; } bool Tagging::tagUrl(const QString &url, const QString &tag, const QString &color, const QString &comment) { auto myTag = tag.trimmed(); this->tag(myTag, color, comment); QMimeDatabase mimedb; auto mime = mimedb.mimeTypeForFile(url); QVariantMap tag_url_map { {TAG::KEYMAP[TAG::KEYS::URL], url}, {TAG::KEYMAP[TAG::KEYS::TAG], myTag}, {TAG::KEYMAP[TAG::KEYS::TITLE], QFileInfo(url).baseName()}, {TAG::KEYMAP[TAG::KEYS::MIME], mime.name()}, {TAG::KEYMAP[TAG::KEYS::ADD_DATE], QDateTime::currentDateTime()}, {TAG::KEYMAP[TAG::KEYS::COMMENT], comment} }; emit this->urlTagged(url, myTag); return this->insert(TAG::TABLEMAP[TAG::TABLE::TAGS_URLS], tag_url_map); } bool Tagging::tagAbstract(const QString &tag, const QString &key, const QString &lot, const QString &color, const QString &comment) { this->abstract(key, lot, comment); this->tag(tag, color, comment); QVariantMap tag_abstract_map { {TAG::KEYMAP[TAG::KEYS::APP], this->application}, {TAG::KEYMAP[TAG::KEYS::URI], this->uri}, {TAG::KEYMAP[TAG::KEYS::TAG], tag}, {TAG::KEYMAP[TAG::KEYS::KEY], key}, {TAG::KEYMAP[TAG::KEYS::LOT], lot}, {TAG::KEYMAP[TAG::KEYS::ADD_DATE], QDateTime::currentDateTime()}, {TAG::KEYMAP[TAG::KEYS::COMMENT], comment}, }; emit this->abstractTagged(key, lot, tag); return this->insert(TAG::TABLEMAP[TAG::TABLE::TAGS_ABSTRACT], tag_abstract_map); } bool Tagging::updateUrlTags(const QString &url, const QStringList &tags) { this->removeUrlTags(url); for(auto tag : tags) this->tagUrl(url, tag); return true; } bool Tagging::updateAbstractTags(const QString &key, const QString &lot, const QStringList &tags) { this->removeAbstractTags(key, lot); for(auto tag : tags) this->tagAbstract(tag, key, lot); return true; } QVariantList Tagging::getUrlsTags(const bool &strict) { auto query = QString("select distinct t.* from TAGS t inner join TAGS_USERS tu on t.tag = tu.tag " "inner join APPS_USERS au on au.mac = tu.mac " "inner join TAGS_URLS turl on turl.tag = t.tag " "where au.app = '%1' and au.uri = '%2'").arg(this->application, this->uri); qDebug()<<"URL TAGS QUEY"<get("select distinct t.* from tags t inner join TAGS_URLS turl on turl.tag = t.tag") : this->get(query); return res; } QVariantList Tagging::getAbstractsTags(const bool &strict) { auto res = !strict ? this->get("select t.* from tags t inner join TAGS_ABSTRACT tab on tab.tag = t.tag") : this->get(QString("select t.* from TAGS t inner join TAGS_USERS tu on t.tag = tu.tag " "inner join APPS_USERS au on au.mac = tu.mac " "inner join TAGS_ABSTRACT tab on tab.tag = t.tag " "where au.app = '%1' and au.uri = '%2'").arg(this->application, this->uri)); return res; } QVariantList Tagging::getAllTags(const bool &strict) { auto res = !strict ? this->get("select * from tags") : this->get(QString("select t.* from TAGS t inner join TAGS_USERS tu on t.tag = tu.tag inner join APPS_USERS au on au.mac = tu.mac " "where au.app = '%1' and au.uri = '%2'").arg(this->application, this->uri)); return res; } QVariantList Tagging::getUrls(const QString &tag, const bool &strict) { auto res = !strict ? this->get(QString("select turl.*, t.color, t.comment as tagComment from TAGS t inner join TAGS_URLS turl on turl.tag = t.tag where t.tag = '%1'").arg(tag)): this->get(QString("select distinct turl.*, t.color, t.comment as tagComment from TAGS t " "inner join TAGS_USERS tu on t.tag = tu.tag " "inner join APPS_USERS au on au.mac = tu.mac " "inner join TAGS_URLS turl on turl.tag = t.tag " "where au.app = '%1' and au.uri = '%2' " "and t.tag = '%3'").arg(this->application, this->uri, tag)); return res; } QVariantList Tagging::getUrlTags(const QString &url, const bool &strict) { auto res = !strict ? this->get(QString("select turl.*, t.color, t.comment as tagComment from tags t inner join TAGS_URLS turl on turl.tag = t.tag where turl.url = '%1'").arg(url)) : this->get(QString("select distinct t.* from TAGS t inner join TAGS_USERS tu on t.tag = tu.tag inner join APPS_USERS au on au.mac = tu.mac inner join TAGS_URLS turl on turl.tag = t.tag " "where au.app = '%1' and au.uri = '%2' and turl.url = '%3'").arg(this->application, this->uri, url)); return res; } QVariantList Tagging::getAbstractTags(const QString &key, const QString &lot, const bool &strict) { auto res = !strict ? this->get(QString("select t.* from TAGS t inner join TAGS_ABSTRACT ta on ta.tag = t.tag where ta.key = '%1' and ta.lot = '%2'").arg(key, lot)) : this->get(QString("select distinct t.* from TAGS t inner join TAGS_ABSTRACT ta on ta.tag = t.tag " "inner join TAGS_USERS tu on t.tag = tu.tag " "inner join APPS_USERS au on au.mac = tu.mac " "where au.app = '%1' and au.uri = '%2' and ta.key = '%3' and ta.lot = '%4'").arg(this->application, this->uri, key, lot)); return res; } bool Tagging::removeAbstractTag(const QString& key, const QString& lot, const QString &tag) { TAG::DB data {{TAG::KEYS::KEY, key}, {TAG::KEYS::LOT, lot}, {TAG::KEYS::TAG, tag}}; return this->remove(TAG::TABLEMAP[TAG::TABLE::TAGS_ABSTRACT], data); } bool Tagging::removeAbstractTags(const QString& key, const QString& lot) { for(auto map : this->getAbstractTags(key, lot)) { auto tag = map.toMap().value(TAG::KEYMAP[TAG::KEYS::TAG]).toString(); this->removeAbstractTag(key, lot, tag); } return true; } bool Tagging::removeUrlTags(const QString &url) { for(auto map : this->getUrlTags(url)) { auto tag = map.toMap().value(TAG::KEYMAP[TAG::KEYS::TAG]).toString(); this->removeUrlTag(url, tag); } return true; } bool Tagging::removeUrlTag(const QString& url, const QString& tag) { TAG::DB data {{TAG::KEYS::URL, url}, {TAG::KEYS::TAG, tag}}; return this->remove(TAG::TABLEMAP[TAG::TABLE::TAGS_URLS], data); } QString Tagging::mac() { QNetworkInterface mac; qDebug()<< "MAC ADDRES:"<< mac.hardwareAddress(); return mac.hardwareAddress(); } QString Tagging::device() { return QSysInfo::prettyProductName(); } QString Tagging::id() { return QSysInfo::machineHostName(); // qDebug()<< "VERSION IS LES THAN "<< QT_VERSION; //#if QT_VERSION < QT_VERSION_CHECK(5, 1, 1) // return QSysInfo::machineHostName(); //#else // return QString(QSysInfo::machineUniqueId()); //#endif } bool Tagging::app() { qDebug()<<"REGISTER APP" << this->application<< this->uri<< this->version<< this->comment; QVariantMap app_map { {TAG::KEYMAP[TAG::KEYS::APP], this->application}, {TAG::KEYMAP[TAG::KEYS::URI], this->uri}, {TAG::KEYMAP[TAG::KEYS::VERSION], this->version}, {TAG::KEYMAP[TAG::KEYS::ADD_DATE], QDateTime::currentDateTime()}, {TAG::KEYMAP[TAG::KEYS::COMMENT], this->comment}, }; this->insert(TAG::TABLEMAP[TAG::TABLE::APPS], app_map); this->user(); QVariantMap users_apps_map { {TAG::KEYMAP[TAG::KEYS::APP], this->application}, {TAG::KEYMAP[TAG::KEYS::URI], this->uri}, {TAG::KEYMAP[TAG::KEYS::MAC], this->id()}, {TAG::KEYMAP[TAG::KEYS::ADD_DATE], QDateTime::currentDateTime()}, }; return this->insert(TAG::TABLEMAP[TAG::TABLE::APPS_USERS], users_apps_map); } bool Tagging::user() { QVariantMap user_map { {TAG::KEYMAP[TAG::KEYS::MAC], this->id()}, {TAG::KEYMAP[TAG::KEYS::NAME], UTIL::whoami()}, {TAG::KEYMAP[TAG::KEYS::LAST_SYNC], QDateTime::currentDateTime()}, {TAG::KEYMAP[TAG::KEYS::ADD_DATE], QDateTime::currentDateTime()}, {TAG::KEYMAP[TAG::KEYS::DEVICE], this->device()}, }; return this->insert(TAG::TABLEMAP[TAG::TABLE::USERS], user_map); } bool Tagging::abstract(const QString &key, const QString &lot, const QString &comment) { QVariantMap abstract_map { {TAG::KEYMAP[TAG::KEYS::APP], this->application}, {TAG::KEYMAP[TAG::KEYS::URI], this->uri}, {TAG::KEYMAP[TAG::KEYS::KEY], key}, {TAG::KEYMAP[TAG::KEYS::LOT], lot}, {TAG::KEYMAP[TAG::KEYS::ADD_DATE], QDateTime::currentDateTime()}, {TAG::KEYMAP[TAG::KEYS::COMMENT], comment}, }; return this->insert(TAG::TABLEMAP[TAG::TABLE::ABSTRACT], abstract_map); } diff --git a/src/utils/tagging/tagging.h b/src/utils/tagging/tagging.h index abf6fd2..bc13a35 100644 --- a/src/utils/tagging/tagging.h +++ b/src/utils/tagging/tagging.h @@ -1,103 +1,104 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ #ifndef TAGGING_H #define TAGGING_H #include #include #include #include "tagdb.h" #ifndef STATIC_MAUIKIT #include "mauikit_export.h" #endif #ifdef STATIC_MAUIKIT class Tagging : public TAGDB #else class MAUIKIT_EXPORT Tagging : public TAGDB #endif { Q_OBJECT public: static Tagging *getInstance(); Q_INVOKABLE QVariantList get(const QString &query); - Q_INVOKABLE bool tagExists(const QString &tag, const bool &strict = false); - + Q_INVOKABLE bool tagExists(const QString &tag, const bool &strict = false); + Q_INVOKABLE bool urlTagExists(const QString &url, const QString &tag, const bool &strict = false); + /* INSERTIIONS */ Q_INVOKABLE bool tag(const QString &tag, const QString &color=QString(), const QString &comment=QString()); Q_INVOKABLE bool tagUrl(const QString &url, const QString &tag, const QString &color=QString(), const QString &comment=QString()); Q_INVOKABLE bool tagAbstract(const QString &tag, const QString &key, const QString &lot, const QString &color = QString(), const QString &comment=QString()); /* UPDATES */ Q_INVOKABLE bool updateUrlTags(const QString &url, const QStringList &tags); Q_INVOKABLE bool updateAbstractTags(const QString &key, const QString &lot, const QStringList &tags); /* QUERIES */ Q_INVOKABLE QVariantList getUrlsTags(const bool &strict = true); Q_INVOKABLE QVariantList getAbstractsTags(const bool &strict = true); Q_INVOKABLE QVariantList getAllTags(const bool &strict = true); Q_INVOKABLE QVariantList getUrls(const QString &tag, const bool &strict = true); Q_INVOKABLE QVariantList getUrlTags(const QString &url, const bool &strict = true); Q_INVOKABLE QVariantList getAbstractTags(const QString &key, const QString &lot, const bool &strict = true); /* DELETES */ Q_INVOKABLE bool removeAbstractTag(const QString &key, const QString &lot, const QString &tag); Q_INVOKABLE bool removeAbstractTags(const QString &key, const QString &lot); Q_INVOKABLE bool removeUrlTags(const QString &url); Q_INVOKABLE bool removeUrlTag(const QString &url, const QString &tag); /*STATIC METHODS*/ static QString mac(); static QString device(); static QString id(); private: Tagging(QObject *parent = nullptr); ~Tagging(); static Tagging* instance; void setApp(); QString application = QString(); QString version = QString(); QString comment = QString(); QString uri = QString(); bool app(); bool user(); protected: bool abstract(const QString &key, const QString &lot, const QString &comment); signals: void urlTagged(const QString &url, const QString &tag); void abstractTagged(const QString &key, const QString &lot, const QString &tag); void tagged(const QString &tag); public slots: }; #endif // TAGGING_H diff --git a/src/utils/tagging/tagging.pri b/src/utils/tagging/tagging.pri index 813d3fb..2d33b5d 100644 --- a/src/utils/tagging/tagging.pri +++ b/src/utils/tagging/tagging.pri @@ -1,32 +1,28 @@ -QT += \ +QT *= \ sql \ network HEADERS += \ $$PWD/tagging.h \ $$PWD/tagdb.h \ $$PWD/tag.h \ $$PWD/tagsmodel.h \ $$PWD/tagslist.h SOURCES += \ $$PWD/tagging.cpp \ $$PWD/tagdb.cpp \ $$PWD/tagsmodel.cpp \ $$PWD/tagslist.cpp DEPENDPATH += \ $$PWD INCLUDEPATH += \ $$PWD DISTFILES += \ $$PWD/script.sql \ - $$PWD/CMakeLists.txt - - -API_VER=1.0 RESOURCES += \ $$PWD/tagging.qrc diff --git a/src/utils/tagging/tagslist.cpp b/src/utils/tagging/tagslist.cpp index 6cdc606..ac24d3f 100644 --- a/src/utils/tagging/tagslist.cpp +++ b/src/utils/tagging/tagslist.cpp @@ -1,383 +1,383 @@ #include "tagslist.h" #include "tagging.h" TagsList::TagsList(QObject *parent) : QObject(parent) { this->tag = Tagging::getInstance(); this->setList(); } TAG::DB_LIST TagsList::toModel(const QVariantList& data) { TAG::DB_LIST res; for(auto item : data) { const auto map = item.toMap(); TAG::DB model; for(auto key : map.keys()) model.insert(TAG::MAPKEY[key], map[key].toString()); res << model; } return res; } void TagsList::setList() { emit this->preListChanged(); if(this->abstract) { if(this->lot.isEmpty() || this->key.isEmpty()) this->list = this->toModel(this->tag->getAbstractsTags(this->strict)); else this->list = this->toModel(this->tag->getAbstractTags(this->key, this->lot, this->strict)); }else { if(this->urls.isEmpty()) this->list = this->toModel(this->tag->getAllTags(this->strict)); else { this->list.clear(); for(const auto &url : this->urls) this->list << this->toModel(this->tag->getUrlTags(url, this->strict)); } } this->sortList(); emit this->postListChanged(); } void TagsList::sortList() { const auto key = static_cast(this->sortBy); qSort(this->list.begin(), this->list.end(), [key](const TAG::DB & e1, const TAG::DB & e2) -> bool { auto role = key; switch(role) { case TAG::KEYS::ADD_DATE: { auto currentTime = QDateTime::currentDateTime(); auto date1 = QDateTime::fromString(e1[role], Qt::TextDate); auto date2 = QDateTime::fromString(e2[role], Qt::TextDate); if(date1.secsTo(currentTime) < date2.secsTo(currentTime)) return true; break; } case TAG::KEYS::TAG: { const auto str1 = QString(e1[role]).toLower(); const auto str2 = QString(e2[role]).toLower(); if(str1 < str2) return true; break; } default: if(e1[role] < e2[role]) return true; } return false; }); } QVariantMap TagsList::get(const int &index) const { if(index >= this->list.size() || index < 0) return QVariantMap(); const auto folder = this->list.at(index); QVariantMap res; for(auto key : folder.keys()) res.insert(TAG::KEYMAP[key], folder[key]); return res; } void TagsList::refresh() { this->setList(); } bool TagsList::contains(const QString& tag) { return indexOf(tag) > -1; } int TagsList::indexOf(const QString& tag) { int i = 0; for(auto &item : this->list) { if(item.value(TAG::KEYS::TAG) == tag) return i; i ++; } return -1; } bool TagsList::insert(const QString &tag) { auto _tag = tag.trimmed(); if(this->tag->tag(_tag)) { emit this->preItemAppended(); this->list << TAG::DB {{TAG::KEYS::TAG, _tag}}; // this->sortList(); emit this->postItemAppended(); return true; } return false; } void TagsList::insertToUrls(const QString& tag) { if(this->urls.isEmpty()) return; for(const auto &url : this->urls) this->tag->tagUrl(url, tag); this->refresh(); } void TagsList::insertToAbstract(const QString& tag) { if(this->key.isEmpty() || this->lot.isEmpty()) return; if(this->tag->tagAbstract(tag, this->key, this->lot)) this->refresh(); } void TagsList::updateToUrls(const QStringList& tags) { if(this->urls.isEmpty()) return; for(auto url : this->urls) this->tag->updateUrlTags(url, tags); this->refresh(); } void TagsList::updateToAbstract(const QStringList& tags) { if(this->key.isEmpty() || this->lot.isEmpty()) return; this->tag->updateAbstractTags(this->key, this->lot, tags); this->refresh(); } void TagsList::removeFromAbstract(const int& index) { if(index >= this->list.size() || index < 0) return; if(this->key.isEmpty() || this->lot.isEmpty()) return; const auto tag = this->list[index][TAG::KEYS::TAG]; if(this->tag->removeAbstractTag(this->key, this->lot, tag)) { emit this->preItemRemoved(index); this->list.removeAt(index); emit this->postItemRemoved(); } } void TagsList::removeFromUrls(const int& index) { if(index >= this->list.size() || index < 0) return; if(this->urls.isEmpty()) return; const auto tag = this->list[index][TAG::KEYS::TAG]; for(const auto &url : this->urls) this->tag->removeUrlTag(url, tag); emit this->preItemRemoved(index); this->list.removeAt(index); emit this->postItemRemoved(); } void TagsList::removeFromUrls(const QString &tag) { const auto index = indexOf(tag); removeFromUrls(index); } bool TagsList::remove(const int& index) { if(index >= this->list.size() || index < 0) return false; emit this->preItemRemoved(index); this->list.removeAt(index); emit this->postItemRemoved(); return true; } void TagsList::removeFrom(const int& index, const QString& key, const QString& lot) { if(index >= this->list.size() || index < 0) return; if(this->tag->removeAbstractTag(key, lot, this->list[index][TAG::KEYS::TAG])) { emit this->preItemRemoved(index); this->list.removeAt(index); emit this->postItemRemoved(); } } void TagsList::removeFrom(const int& index, const QString& url) { if(index >= this->list.size() || index < 0) return; if(this->tag->removeUrlTag(url, this->list[index][TAG::KEYS::TAG])) { emit this->preItemRemoved(index); this->list.removeAt(index); emit this->postItemRemoved(); } } void TagsList::erase(const int& index) { } TAG::DB_LIST TagsList::items() const { return this->list; } TagsList::KEYS TagsList::getSortBy() const { return this->sortBy; } void TagsList::setSortBy(const TagsList::KEYS &key) { if(this->sortBy == key) return; this->sortBy = key; emit this->preListChanged(); this->sortList(); emit this->sortByChanged(); emit this->postListChanged(); } bool TagsList::getAbstract() const { return this->abstract; } void TagsList::setAbstract(const bool& value) { if(this->abstract == value) return; this->abstract = value; this->setList(); emit this->abstractChanged(); } bool TagsList::getStrict() const { return this->strict; } void TagsList::setStrict(const bool& value) { if(this->strict == value) return; this->strict = value; this->setList(); emit this->strictChanged(); } QString TagsList::getKey() const { return this->key; } void TagsList::setKey(const QString& value) { if(this->key == value) return; this->urls.clear(); this->key = value; this->setList(); emit this->keyChanged(); } QString TagsList::getLot() const { return this->lot; } void TagsList::setLot(const QString& value) { if(this->lot == value) return; this->urls.clear(); this->lot = value; this->setList(); emit this->lotChanged(); } QStringList TagsList::getUrls() const { return this->urls; } void TagsList::setUrls(const QStringList& value) { if(this->urls == value) return; this->key.clear(); this->lot.clear(); this->urls = value; this->setList(); emit this->urlsChanged(); } void TagsList::append(const QString &tag) { - if(!this->insert(tag)) + if(!this->insert(tag) && !this->contains(tag)) { emit this->preItemAppended(); this->list << TAG::DB {{TAG::KEYS::TAG, tag}}; this->sortList(); emit this->postItemAppended(); } } diff --git a/src/utils.h b/src/utils/utils.h similarity index 99% rename from src/utils.h rename to src/utils/utils.h index c986fca..4c91b1c 100644 --- a/src/utils.h +++ b/src/utils/utils.h @@ -1,80 +1,81 @@ /* * Copyright 2018 Camilo Higuita * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library 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. */ #ifndef UTILS_H #define UTILS_H #include #include #include +#include #ifdef Q_OS_ANDROID #include #else #include #endif #define MAUIKIT_MAJOR_VERSION 0 #define MAUIKIT_MINOR_VERSION 1 #define MAUIKIT_PATCH_VERSION 0 #define MAUIKIT_VERSION_STR "0.1.0" namespace UTIL { const auto app = QCoreApplication::instance(); inline bool fileExists(const QString &url) { QFileInfo path(url); if (path.exists()) return true; else return false; } inline QString whoami() { #ifdef Q_OS_UNIX return qgetenv("USER"); ///for MAc or Linux #else return qgetenv("USERNAME"); //for windows #endif } inline void saveSettings(const QString &key, const QVariant &value, const QString &group, QString app = UTIL::app->applicationName(), const QString organization = UTIL::app->organizationName()) { QSettings setting(organization.isEmpty() ? QString("org.kde.maui") : organization, app); setting.beginGroup(group); setting.setValue(key,value); setting.endGroup(); } inline QVariant loadSettings(const QString &key, const QString &group, const QVariant &defaultValue, const QString app = UTIL::app->applicationName(), const QString organization = UTIL::app->organizationName()) { QVariant variant; QSettings setting(organization.isEmpty() ? QString("org.kde.maui") : organization, app); setting.beginGroup(group); variant = setting.value(key,defaultValue); setting.endGroup(); return variant; } } #endif // UTILS_H