diff --git a/CMakeLists.txt b/CMakeLists.txt index 642a01f89..54b7f6993 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,248 +1,263 @@ cmake_minimum_required(VERSION 3.0 FATAL_ERROR) find_package(ECM 1.8.0 REQUIRED NOMODULE) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(SetKexiCMakePolicies NO_POLICY_SCOPE) include(SetKexiVersionInfo) project(Kexi VERSION ${PROJECT_VERSION}) # ECM include(ECMAddAppIcon) include(ECMAddTests) include(ECMGenerateHeaders) include(ECMInstallIcons) include(ECMMarkAsTest) include(ECMMarkNonGuiExecutable) include(ECMPoQmTools) include(ECMSetupVersion) include(KDEInstallDirs) include(KDECMakeSettings NO_POLICY_SCOPE) include(KDECompilerSettings NO_POLICY_SCOPE) # Own include(KexiMacros) include(KexiAddIconsRccFile) ensure_out_of_source_build("Please refer to the build instruction https://community.kde.org/Kexi/Building") get_git_revision_and_branch() detect_release_build() ####################### ######################## ## Productset setting ## ######################## ####################### # For predefined productsets see the definitions in KexiProducts.cmake and # in the files in the folder cmake/productsets. # Finding out the products & features to build is done in 5 steps: # 1. have the user define the products/features wanted, by giving a productset # 2. estimate all additional required products/features # 3. estimate which of the products/features can be build by external deps # 4. find which products/features have been temporarily disabled due to problems # 5. estimate which of the products/features can be build by internal deps # get the special macros include(CalligraProductSetMacros) -# get the definitions of products, features and product sets -include(KexiProducts.cmake) +set(PRODUCTSET_DEFAULT "DESKTOP") -set(PRODUCTSET_DEFAULT "ALL") - -if(NOT PRODUCTSET) +if(NOT PRODUCTSET OR PRODUCTSET STREQUAL "ALL") + # Force the default set also when it is "ALL" because we can't build both desktop and mobile set(PRODUCTSET ${PRODUCTSET_DEFAULT} CACHE STRING "Set of products/features to build" FORCE) endif() +# get the definitions of products, features and product sets +include(KexiProducts.cmake) + if (RELEASE_BUILD) set(KEXI_SHOULD_BUILD_STAGING FALSE) else () set(KEXI_SHOULD_BUILD_STAGING TRUE) endif () # finally choose products/features to build calligra_set_productset(${PRODUCTSET}) ########################## ########################### ## Look for Qt, KF5 ## ########################### ########################## set(REQUIRED_KF5_VERSION 5.16.0) -find_package(KF5 ${REQUIRED_KF5_VERSION} REQUIRED COMPONENTS - Archive - Codecs - Completion - Config - ConfigWidgets - CoreAddons - GuiAddons - I18n - IconThemes - ItemViews - KIO - TextEditor - TextWidgets - WidgetsAddons - XmlGui +set(REQUIRED_KF5_COMPONENTS + Archive + Codecs + Config + ConfigWidgets + CoreAddons + GuiAddons + I18n + IconThemes + ItemViews + WidgetsAddons + TextWidgets + XmlGui ) +if(SHOULD_BUILD_KEXI_DESKTOP_APP) + list(APPEND REQUIRED_KF5_COMPONENTS + Completion + KIO + TextEditor + TextWidgets + ) +endif() +find_package(KF5 ${REQUIRED_KF5_VERSION} REQUIRED COMPONENTS ${REQUIRED_KF5_COMPONENTS}) + find_package(KF5 ${REQUIRED_KF5_VERSION} QUIET OPTIONAL_COMPONENTS Crash) macro_bool_to_01(KF5Crash_FOUND HAVE_KCRASH) macro_log_feature(${KF5Crash_FOUND} "KCrash" "KDE's Crash Handler" "https://api.kde.org/frameworks/kcrash/html" FALSE "" "Optionally used to provide crash reporting on Linux") set(REQUIRED_QT_VERSION 5.4.0) find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Gui Widgets Xml Network PrintSupport Test) find_package(Qt5 ${REQUIRED_QT_VERSION} COMPONENTS UiTools WebKit WebKitWidgets) # use sane compile flags add_definitions( -DQT_NO_CAST_TO_ASCII -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DQT_NO_URL_CAST_FROM_STRING -DQT_STRICT_ITERATORS -DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS -DQT_USE_QSTRINGBUILDER ) # only with COMPILING_TESTS definition will all the FOO_TEST_EXPORT macros do something # TODO: check if this can be moved to only those places which make use of it, # to reduce global compiler definitions that would trigger a recompile of # everything on a change (like adding/removing tests to/from the build) macro_bool_to_01(BUILD_TESTING COMPILING_TESTS) # overcome some platform incompatibilities if(WIN32) find_package(KDEWin REQUIRED) endif() # set custom Kexi plugin installdir set(KEXI_PLUGIN_INSTALL_DIR ${PLUGIN_INSTALL_DIR}/${KEXI_BASE_PATH}) # TEMPORARY: for initial Qt5/KF5 build porting phase deprecation warnings are only annoying noise # remove once code porting phase starts, perhaps first locally in product subdirs #if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUC) # add_definitions(-Wno-deprecated -Wno-deprecated-declarations) #endif () ########################### ############################ ## Required dependencies ## ############################ ########################### set(KEXI_LIBS_MIN_VERSION 3.0.90) ## ## Test for KDb ## option(KEXI_DEBUG_GUI "Debugging GUI for Kexi (requires KDB_DEBUG_GUI to be set too)" OFF) if(KEXI_DEBUG_GUI) set(KDB_REQUIRED_COMPONENTS DEBUG_GUI) endif() find_package(KDb ${KEXI_LIBS_MIN_VERSION} REQUIRED COMPONENTS ${KDB_REQUIRED_COMPONENTS}) macro_log_feature(KDb_FOUND "KDb" "A database connectivity and creation framework" "http://community.kde.org/KDb" FALSE "" "Required by Kexi for data handling") ## ## Test for KReport ## find_package(KReport ${KEXI_LIBS_MIN_VERSION} REQUIRED) if (KReport_FOUND) if(NOT KREPORT_SCRIPTING) message(FATAL_ERROR "Kexi requires KReport package with scripting support enabled (KREPORT_SCRIPTING)") endif() endif() ## ## Test for KPropertyWidgets ## -find_package(KPropertyWidgets ${KEXI_LIBS_MIN_VERSION} REQUIRED COMPONENTS KF) -macro_log_feature(KPropertyWidgets_FOUND "KPropertyWidgets" "A property editing framework with editor widget" - "http://community.kde.org/KProperty" FALSE "" "Required by Kexi") - +if(SHOULD_BUILD_KEXI_DESKTOP_APP) + find_package(KPropertyWidgets ${KEXI_LIBS_MIN_VERSION} REQUIRED COMPONENTS KF) + macro_log_feature(KPropertyWidgets_FOUND "KPropertyWidgets" "A property editing framework with editor widget" + "http://community.kde.org/KProperty" FALSE "" "Required by Kexi Desktop") +else() # only KPropertyCore + find_package(KPropertyCore ${KEXI_LIBS_MIN_VERSION} REQUIRED COMPONENTS KF) + macro_log_feature(KPropertyCore_FOUND "KPropertyCore" "A property editing framework with editor widget" + "http://community.kde.org/KProperty" FALSE "" "Required by Kexi Mobile") +endif() include(CheckIfQtGuiCanBeExecuted) -include(CheckGlobalBreezeIcons) +if(SHOULD_BUILD_KEXI_DESKTOP_APP) +include(CheckGlobalBreezeIcons) +endif() ########################### ############################ ## Optional dependencies ## ############################ ########################### ## ## Test for marble ## set(MARBLE_MIN_VERSION "0.19.2") find_package(KexiMarble) if(NOT MARBLE_FOUND) set(MARBLE_INCLUDE_DIR "") else() set(HAVE_MARBLE TRUE) endif() macro_log_feature(MARBLE_FOUND "Marble" "KDE World Globe Widget library" "https://marble.kde.org/" FALSE "${MARBLE_MIN_VERSION}" "Required by Kexi form map widget") ## ## Test for Qt WebKitWidgets ## #TODO switch to Qt WebEngine macro_bool_to_01(Qt5WebKitWidgets_FOUND HAVE_QTWEBKITWIDGETS) macro_log_feature(Qt5WebKitWidgets_FOUND "Qt WebkitWidgets" "QWidgets module for Webkit, the HTML engine." "http://qt.io" FALSE "" "Required by Kexi web form widget") ################## ################### ## Helper macros ## ################### ################## include(MacroKexiAddBenchmark) include(MacroKexiAddTest) ############################################# #### Temporarily broken products #### ############################################# # If a product does not build due to some temporary brokeness disable it here, # by calling calligra_disable_product with the product id and the reason, # e.g.: # calligra_disable_product(APP_KEXI "isn't buildable at the moment") ############################################# #### Calculate buildable products #### ############################################# calligra_drop_unbuildable_products() ############################################# #### Setup product-depending vars #### ############################################# ################### #################### ## Subdirectories ## #################### ################### add_subdirectory(src) if(SHOULD_BUILD_DOC) find_package(KF5 ${KF5_DEP_VERSION} REQUIRED COMPONENTS DocTools) add_subdirectory(doc) endif() # non-app directories are moved here because they can depend on SHOULD_BUILD_{appname} variables set above add_subdirectory(cmake) if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ki18n_install(po) endif() macro_display_feature_log() calligra_product_deps_report("product_deps") calligra_log_should_build() diff --git a/KexiProducts.cmake b/KexiProducts.cmake index 334b96d47..81f283514 100644 --- a/KexiProducts.cmake +++ b/KexiProducts.cmake @@ -1,223 +1,219 @@ ### DEFINITION OF PRODUCTS, FEATURES AND PRODUCTSETS #################################################### # When building Kexi a lot of different things are created and installed. To # describe them and their internal dependencies the concepts of "product", # "feature" and "product set" are used. # A "product" is the smallest functional unit which can be created in the build # and which is useful on its own when installed. Examples are e.g. libraries, # plugins or executables. Products have external and internal required # dependencies at build-time. Internal dependencies are noted in terms of other # products or features (see below) and could be e.g. other libraries to link # against or build tools needed to generate source files. # A product gets defined by setting an identifier, a descriptive fullname and # the needed internal build-time requirements. Any other product or feature # listed as requirement must have been defined before. # A "feature" is not a standalone product, but adds abilities to one or multiple # given products. One examples is e.g. scriptability. Features have external and # internal required dependencies at build-time. Internal dependencies are noted # in terms of other products or features and could be e.g. other libraries to # link against or build tools needed to generate source files. # A feature gets defined by setting an identifier, a descriptive fullname and # the needed internal build-time requirements. Any other product or feature # listed as requirement must have been defined before. # A "productset" is a selection of products and features which should be build # together. The products and features can be either essential or optional to the # set. If essential (REQUIRES), the whole productset will not be build if a # product or feature is missing another internal or external dependency. If # optional (OPTIONAL), the rest of the set will still be build in that case. # The products and features to include in a set can be listed directly or # indirectly: they can be named explicitely, but also by including other # productsets in a set, whose products and features will then be part of the # first set as well. # Products, features and productsets can be listed as dependencies in multiple # product sets. As with dependencies for products or features, they must have # been defined before. # Products, features and product sets are in the same namespace, so a given # identifier can be only used either for a product or for a feature or for a # product set. # The ids of products and features (but not sets) are used to generate cmake # variables SHOULD_BUILD_${ID}, which then are used to control what is build and # how. ############################################# #### Product definitions #### ############################################# # For defining new products see end of this file, "How to add another product?" # IDEA: also add headers/sdk for all the libs ("_DEVEL"?) # IDEA: note external deps for products, so they are only checked if needed # There can be required or optional external deps, required will also result # in automatic disabling of product building # TODO: some products have multiple optional requirements, but need at least one. # See APP_CONVERTER, FILEMANAGER_* # features calligra_define_feature(FEATURE_SCRIPTING "Scripting feature" UNPORTED) # TODO -# apps -calligra_define_product(APP_KEXI "Kexi app (for Desktop)" REQUIRES) +# products +calligra_define_product(KEXI_CORE_APP "Kexi core app" REQUIRES) +calligra_define_product(KEXI_DESKTOP_APP "Kexi for desktop" REQUIRES KEXI_CORE_APP) +calligra_define_product(KEXI_MOBILE_APP "Kexi for mobile" REQUIRES KEXI_CORE_APP) # more plugins -calligra_define_product(PLUGIN_KEXI_SPREADSHEETMIGRATION "Import from ODS plugin for Kexi" UNPORTED REQUIRES APP_KEXI) +calligra_define_product(PLUGIN_KEXI_SPREADSHEETMIGRATION "Import from ODS plugin for Kexi" UNPORTED REQUIRES KEXI_CORE_APP) ############################################# #### Product set definitions #### ############################################# # For defining new productsets see end of this file, # "How to add another productset?" -calligra_define_productset(KEXI "Full Kexi (for Desktop)" - REQUIRES - APP_KEXI - OPTIONAL - FEATURE_SCRIPTING - PLUGIN_KEXI_SPREADSHEETMIGRATION -) +# (products sets are defined in cmake/productsets/*.cmake files) # How to add another product? # =========================== # # 1. Define the product by a call of calligra_define_product, # e.g. # # calligra_define_product(MYPRODUCT "title of product") # # For the product id use a proper prefix (LIB_, PLUGIN_, FILTER_, APP_, PART_, # ...), whatever is appropriate. # # 2. Extend that call with a REQUIRES argument section, if the product has # hard internal build-time dependencies on other products or features. # Products/features that are listed as dependencies have to be defined before # (see also the API doc in cmake/modules/CalligraProductSetMacros.cmake) # E.g. # # calligra_define_product(MYPRODUCT "title of product" REQUIRES P1 P2) # # 3. Add a rule when to not build the product, in the section "Detect which # products/features can be compiled" of the toplevel CMakeLists.txt. Each # product should have their own boolean expression when to set the build flag # to FALSE, e.g. # # if (PLATFORMX OR NOT EXTERNAL_DEP_X_FOUND) # set(SHOULD_BUILD_MYPRODUCT FALSE) # endif () # # 4. Wrap everything belonging to the product with the build flag of the product. # Ideally this is done around subdirectory inclusions, results in easier code. # e.g. # # if (SHOULD_BUILD_MYPRODUCT) # add_subdirectory(myproduct) # endif () # # 5. Tag the product as STAGING, if it is not yet ready for release, but already # integrated in the master branch, e.g. # # calligra_define_product(MYPRODUCT "title of product" STAGING REQUIRES P1) # # 6. Add the product to all products, features and product sets which have this # product as REQUIRED or OPTIONAL dependency. # # # How to add another feature? # =========================== # # 1. Define the feature by a call of calligra_define_feature, # e.g. # # calligra_define_feature(MYFEATURE "title of feature") # # For the feature id use a proper prefix (FEATURE_, ...), whatever is # appropriate. # # 2. Extend that call with a REQUIRES argument section, if the feature has # hard internal build-time dependencies on other products or features. # Products or features that are listed as dependencies have to be defined # before # (see also the API doc in cmake/modules/CalligraProductSetMacros.cmake) # E.g. # # calligra_define_feature(MYFEATURE "title of feature" REQUIRES P1 F1) # # 3. Add a rule when to not build the feature, in the section "Detect which # products/features can be compiled" of the toplevel CMakeLists.txt. Each # feature should have their own boolean expression when to set the build flag # to FALSE, e.g. # # if (PLATFORMX OR NOT EXTERNAL_DEP_X_FOUND) # set(SHOULD_BUILD_MYFEATURE FALSE) # endif () # # 4. Wrap everything belonging to the feature with the build flag of the feature. # Ideally this is done around subdirectory inclusions, results in easier code. # e.g. # # if (SHOULD_BUILD_MYFEATURE) # add_subdirectory(myproduct) # endif () # # 5. Tag the feature as STAGING, if it is not yet ready for release, but already # integrated in the master branch, e.g. # # calligra_define_product(MYFEATURE "title of feature" STAGING REQUIRES P1 F1) # # 6. Add the feature to all products, features and product sets which have this # product as REQUIRED or OPTIONAL dependency. # # # How to add another productset? # ============================== # # There are two possible places to put a productset definition. The first is to # add it to this file, which should be done for more generic sets that are # useful for many people. The second is a file of its own, in the directory # "cmake/productsets", which should be done for more special ones or for those # which should not be added to the repository. # The file must be named with the name of the productset in lowercase and have # the extension ".cmake". # # 1. Define the productset by a call of calligra_define_productset, # e.g. # # calligra_define_productset(MYPRODUCTSET "title of productset") # # 2. Extend that call with REQUIRES or OPTIONAL argument sections, if the productset # has hard or soft internal dependencies on other products, features or # productsets. # Products, features or productsets that are listed as dependencies have to # be defined before # (see also the API doc in cmake/modules/CalligraProductSetMacros.cmake) # E.g. # # calligra_define_productset(MYPRODUCT "title of product" # REQUIRES P1 P2 F1 PS1 # OPTIONAL P3 F2 PS2) # # 3. Add the productset to all product sets which have this product set as # REQUIRED or OPTIONAL dependency. # # Example for a file-based productset definition: # You want a productset "MYWORDS". For that you add a file named # "mywords.cmake" into the directory "cmake/productsets", with the content: # --- 8< --- # calligra_define_productset(MYWORDS "My Words" # REQUIRES # APP_WORDS # PLUGIN_DEFAULTTOOLS # PLUGIN_DOCKERS # PLUGIN_PATHSHAPES # PLUGIN_VARIABLES # PLUGIN_TEXTSHAPE # PLUGIN_PLUGINSHAPE # PLUGIN_FORMULASHAPE # ) # --- 8< --- diff --git a/cmake/productsets/desktop.cmake b/cmake/productsets/desktop.cmake index 4914b8fe3..f3e41e591 100644 --- a/cmake/productsets/desktop.cmake +++ b/cmake/productsets/desktop.cmake @@ -1,9 +1,9 @@ #defines the set of products commonly wanted for classic Desktop environment -calligra_define_productset(DESKTOP "Kexi for Desktop" +calligra_define_productset(DESKTOP "Desktop products" + REQUIRES + KEXI_DESKTOP_APP OPTIONAL - # apps - KEXI - # features FEATURE_SCRIPTING + PLUGIN_KEXI_SPREADSHEETMIGRATION ) diff --git a/cmake/productsets/mobile.cmake b/cmake/productsets/mobile.cmake new file mode 100644 index 000000000..be9884315 --- /dev/null +++ b/cmake/productsets/mobile.cmake @@ -0,0 +1,6 @@ +#defines the set of products commonly wanted for Mobile environment + +calligra_define_productset(MOBILE "Mobile products" + REQUIRES + KEXI_MOBILE_APP +) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 114225d97..0e6c9152d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,96 +1,98 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) -option(KEXI_MOBILE "Compile a mobile version of Kexi" OFF) - check_function_exists("uname" HAVE_UNAME) option(KEXI_SHOW_UNFINISHED "Show unfinished features in Kexi. Thus is useful for testing but may confuse end-user." OFF) option(KEXI_SHOW_UNIMPLEMENTED "Forces to show menu entries and dialogs just to give impression about development plans for Kexi. Only recommended for test/development versions." OFF) # Extra GUI features option(KEXI_AUTORISE_TABBED_TOOLBAR "Experimental: Autorise the main tabbed toolbar in Kexi" OFF) # Experimental: option(KEXI_SCRIPTS_SUPPORT "Experimental: Enable scripting in Kexi" ON) # Broken: option(KEXI_FORM_CURSOR_PROPERTY_SUPPORT "Broken: Enable \"cursor\" property in the form designer" OFF) option(KEXI_SHOW_CONTEXT_HELP "Broken: Enable context help in Kexi main window" OFF) option(KEXI_QUICK_PRINTING_SUPPORT "Broken: Enable print/print preview/print setup for tables/queries in the project navigator" OFF) option(KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT "Broken: Enable \"auto field\" form widget in the form designer" OFF) # OFF because we need to replace it with QTreeWidget which uses very different API compared to Q3ListView. Re-add QTreeWidget? option(KEXI_LIST_FORM_WIDGET_SUPPORT "Broken: Enable \"list\" form widget in the form designer" OFF) option(KEXI_PIXMAP_COLLECTIONS_SUPPORT "Broken: Enable support for pixmap collections" OFF) # Not available: option(KEXI_MACROS_SUPPORT "Experimental: Enable macros in Kexi" OFF) if(KEXI_MACROS_SUPPORT) # temp. message(FATAL_ERROR "Macros are not yet available.") endif() option(KEXI_TABLE_PRINT_SUPPORT "Experimental: Enable printing of tabular view in Kexi" OFF) # broken since Kexi 2 if(KEXI_TABLE_PRINT_SUPPORT) # temp. message(FATAL_ERROR "Table printing is not yet available.") endif() option(KEXI_PROJECT_TEMPLATES "Experimental: Enable support for project templates in Kexi" OFF) # broken since Kexi 2 if(KEXI_PROJECT_TEMPLATES) # temp. message(FATAL_ERROR "Project templates are not yet available.") endif() #See commit 1e433a54cd9, left here for reference #option(KEXI_SQLITE_MIGRATION "If defined, SQLite3 migration to some newer format is possible. Users can see a suitable question on app's startup." OFF) add_definitions(-DTRANSLATION_DOMAIN=\"kexi\") #no default: add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44010) +macro_bool_to_01(SHOULD_BUILD_KEXI_DESKTOP_APP KEXI_DESKTOP) +macro_bool_to_01(SHOULD_BUILD_KEXI_MOBILE_APP KEXI_MOBILE) configure_file(config-kexi.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kexi.h ) configure_file(KexiVersion.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/KexiVersion.h) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/core ) add_subdirectory( kexiutils ) add_subdirectory( core ) -add_subdirectory( widget ) + +if(SHOULD_BUILD_KEXI_DESKTOP_APP) + add_subdirectory( widget ) + add_subdirectory( main ) + add_subdirectory( formeditor ) + add_subdirectory( migration ) +endif() + add_subdirectory( data ) add_subdirectory( plugins ) + if (BUILD_TESTING) #TODO KEXI3 add_subdirectory( tests ) endif() -if(KEXI_MOBILE) - -else() - add_subdirectory( main ) - add_subdirectory( formeditor ) - add_subdirectory( migration ) -endif() - ########### next target ############### -if(KEXI_MOBILE) - add_subdirectory( mobile ) -else() - set(kexi_SRCS - main.cpp - Messages.sh - - # non-source: - ${CMAKE_SOURCE_DIR}/kundo2_aware_xgettext.sh - Mainpage.dox - Messages.sh - ) - kexi_add_app_icons(kexi_SRCS) - kexi_add_app_metadata_files(kexi_SRCS) - kexi_add_executable(kexi ${kexi_SRCS}) - target_link_libraries(kexi - PRIVATE - keximain - ) - install(TARGETS kexi ${INSTALL_TARGETS_DEFAULT_ARGS}) +if(SHOULD_BUILD_KEXI_DESKTOP_APP) + set(kexi_SRCS + main.cpp + Messages.sh + + # non-source: + ${CMAKE_SOURCE_DIR}/kundo2_aware_xgettext.sh + Mainpage.dox + Messages.sh + ) + kexi_add_app_icons(kexi_SRCS) + kexi_add_app_metadata_files(kexi_SRCS) + kexi_add_executable(kexi ${kexi_SRCS}) + target_link_libraries(kexi + PRIVATE + keximain + ) + install(TARGETS kexi ${INSTALL_TARGETS_DEFAULT_ARGS}) + + add_subdirectory( pics ) endif() -add_subdirectory( pics ) +if(SHOULD_BUILD_KEXI_MOBILE_APP) +# add_subdirectory( mobile ) +endif() diff --git a/src/config-kexi.h.cmake b/src/config-kexi.h.cmake index 6bb20ff01..e61c4069f 100644 --- a/src/config-kexi.h.cmake +++ b/src/config-kexi.h.cmake @@ -1,125 +1,129 @@ /* This file is part of the KDE project Copyright (C) 2006-2016 Jarosław Staniek This library 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 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KEXI_CONFIG_H #define KEXI_CONFIG_H /* config-kexi.h. Generated by cmake from config-kexi.h.cmake */ /*! @file config-kexi.h Global Kexi configuration (build time) */ #include +//! @def KEXI_DESKTOP +//! @brief If defined, a desktop version of Kexi is compiled +#cmakedefine KEXI_DESKTOP + //! @def KEXI_MOBILE -//! @brief If defined, a mobile version of Kexi if compiled +//! @brief If defined, a mobile version of Kexi is compiled #cmakedefine KEXI_MOBILE /* define if you have libreadline available */ /* TODO: detect #define HAVE_READLINE 1 */ //! @def HAVE_UNAME //! @brief If defined, uname(2) is available #cmakedefine HAVE_UNAME 1 /*! For KexiUtils::encoding() */ #cmakedefine01 HAVE_LANGINFO_H //! @def HAVE_KCRASH //! @brief if defined, KCrash is available #cmakedefine HAVE_KCRASH //! @def HAVE_MARBLE //! @brief if defined, Marble widget library is available #cmakedefine HAVE_MARBLE //! @def HAVE_QTWEBKITWIDGETS //! @brief if defined, QtWebKit widgets library is available #cmakedefine HAVE_QTWEBKITWIDGETS //! @def COMPILING_TESTS //! @brief if defined, tests are enabled #cmakedefine COMPILING_TESTS //! @def KEXI_DEBUG_GUI //! @brief If defined, a debugging GUI for Kexi is enabled #cmakedefine KEXI_DEBUG_GUI #if defined KEXI_DEBUG_GUI && !defined KDB_DEBUG_GUI # error KEXI_DEBUG_GUI requires a KDB_DEBUG_GUI cmake option to be set too in KDb. #endif //! @def KEXI_MIGRATEMANAGER_DEBUG //! @brief Defined if debugging for the migrate driver manager is enabled #cmakedefine KEXI_MIGRATEMANAGER_DEBUG /* -- Experimental -- */ //! @def KEXI_SCRIPTS_SUPPORT //! @brief If defined, scripting GUI plugin is enabled in Kexi #cmakedefine KEXI_SCRIPTS_SUPPORT //! @def KEXI_MACROS_SUPPORT //! @brief If defined, macro GUI plugin is enabled in Kexi #cmakedefine KEXI_MACROS_SUPPORT //! @def KEXI_SHOW_UNFINISHED //! @brief If defined unfinished features are enabled and presented in Kexi. //! This is useful for testing but may confuse end-users. #cmakedefine KEXI_SHOW_UNFINISHED //! @def KEXI_SHOW_UNIMPLEMENTED //! @brief If defined show menu entries and dialogs just to give impression about development plans for Kexi //! Only recommended for test/development versions. #cmakedefine KEXI_SHOW_UNIMPLEMENTED //! @def KEXI_PROJECT_TEMPLATES //! @brief If defined, support for project templates is enabled in Kexi #cmakedefine KEXI_PROJECT_TEMPLATES //! @def KEXI_AUTORISE_TABBED_TOOLBAR //! @brief If defined, tabs in the main tabbed toolbar autorise in Kexi #cmakedefine KEXI_AUTORISE_TABBED_TOOLBAR //! @def KEXI_FORM_CURSOR_PROPERTY_SUPPORT //! @brief If defined, "cursor" property is displayed in the form designer #cmakedefine KEXI_FORM_CURSOR_PROPERTY_SUPPORT //! @def KEXI_SHOW_CONTEXT_HELP //! @brief If defined, context help is displayed in Kexi main window #cmakedefine KEXI_SHOW_CONTEXT_HELP //! @def KEXI_QUICK_PRINTING_SUPPORT //! @brief If defined, print/print preview/print setup for tables/queries is enabled in the project navigator #cmakedefine KEXI_QUICK_PRINTING_SUPPORT //! @def KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT //! @brief If defined, "auto field" form widget is available in the form designer #cmakedefine KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT //! @def KEXI_LIST_FORM_WIDGET_SUPPORT //! @brief If defined, "list" form widget is available in the form designer #cmakedefine KEXI_LIST_FORM_WIDGET_SUPPORT //! @def KEXI_PIXMAP_COLLECTIONS_SUPPORT //! @brief If defined, support for pixmap collections is enabled #cmakedefine KEXI_PIXMAP_COLLECTIONS_SUPPORT #endif diff --git a/src/kexiutils/CMakeLists.txt b/src/kexiutils/CMakeLists.txt index ba5644514..c8b1c789d 100644 --- a/src/kexiutils/CMakeLists.txt +++ b/src/kexiutils/CMakeLists.txt @@ -1,92 +1,95 @@ add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44024) include_directories(completer) set(kexiutils_LIB_SRCS utils.cpp FontSettings_p.cpp InternalPropertyMap.cpp SmallToolButton.cpp KexiCommandLinkButton.cpp FlowLayout.cpp transliteration_table.cpp kmessagewidget.cpp KexiContextMessage.cpp KexiTitleLabel.cpp KexiLinkWidget.cpp KexiLinkButton.cpp KexiCloseButton.cpp KexiAssistantPage.cpp KexiAssistantWidget.cpp KexiAnimatedLayout.cpp KexiCategorizedView.cpp KexiTester.cpp KexiJsonTrader.cpp KexiPushButton.cpp KexiFadeWidgetEffect.cpp KexiPluginMetaData.cpp completer/KexiCompleter.cpp ) -if (KEXI_MOBILE) - -else () +if(SHOULD_BUILD_KEXI_MOBILE_APP) if (KEXI_DEBUG_GUI) list(APPEND kexiutils_LIB_SRCS debuggui.cpp ) endif () endif () if(BUILD_TESTING) list(APPEND kexiutils_LIB_SRCS KexiTestHandler.cpp ) endif() kexi_add_library(kexiutils SHARED ${kexiutils_LIB_SRCS}) set(kexiutils_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ) target_include_directories(kexiutils PUBLIC "$" ) target_link_libraries(kexiutils PUBLIC - KF5::KIOWidgets #for KRun... KF5::IconThemes KF5::WidgetsAddons KF5::ConfigWidgets # KStandardAction KColorScheme KF5::I18n KF5::ItemViews # KCategorizedView KCategoryDrawer KDb ) +if(SHOULD_BUILD_KEXI_DESKTOP_APP) + target_link_libraries(kexiutils + PUBLIC + KF5::KIOWidgets #for KRun... + ) #target_link_libraries(kexiutils LINK_INTERFACE_LIBRARIES KF5::KIOWidgets) +endif() if(BUILD_TESTING) target_link_libraries(kexiutils PRIVATE Qt5::Test ) endif() generate_export_header(kexiutils) install(TARGETS kexiutils ${INSTALL_TARGETS_DEFAULT_ARGS}) if(FALSE) # TODO: install when we move to independent place install( FILES tristate.h utils.h kexiutils_export.h kexiutils_global.h InternalPropertyMap.h SmallToolButton.h FlowLayout.h kmessagewidget.h KexiContextMessage.h KexiTitleLabel.h KexiAssistantPage.h KexiAssistantWidget.h KexiAnimatedLayout.h DESTINATION ${INCLUDE_INSTALL_DIR}/kexiutils COMPONENT Devel) endif() if(BUILD_TESTING) add_subdirectory(tests) endif() diff --git a/src/kexiutils/utils.cpp b/src/kexiutils/utils.cpp index 446955095..91e74fabc 100644 --- a/src/kexiutils/utils.cpp +++ b/src/kexiutils/utils.cpp @@ -1,1045 +1,1049 @@ /* This file is part of the KDE project Copyright (C) 2003-2016 Jarosław Staniek Contains code from kglobalsettings.cpp: Copyright (C) 2000, 2006 David Faure Copyright (C) 2008 Friedrich W. H. Kossebau Contains code from kdialog.cpp: Copyright (C) 1998 Thomas Tanghus (tanghus@earthling.net) Additions 1999-2000 by Espen Sand (espen@kde.org) and Holger Freyther 2005-2009 Olivier Goffart 2006 Tobias Koenig 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 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "utils.h" #include "utils_p.h" #include "FontSettings_p.h" #include "kexiutils_global.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef KEXI_MOBILE #include #include +#endif #include #include #include #include #include #if HAVE_LANGINFO_H #include #endif #ifdef Q_OS_WIN #include static QRgb qt_colorref2qrgb(COLORREF col) { return qRgb(GetRValue(col), GetGValue(col), GetBValue(col)); } #endif using namespace KexiUtils; DelayedCursorHandler::DelayedCursorHandler() : startedOrActive(false) { timer.setSingleShot(true); connect(&timer, SIGNAL(timeout()), this, SLOT(show())); } void DelayedCursorHandler::start(bool noDelay) { startedOrActive = true; timer.start(noDelay ? 0 : 1000); } void DelayedCursorHandler::stop() { startedOrActive = false; timer.stop(); QApplication::restoreOverrideCursor(); } void DelayedCursorHandler::show() { QApplication::restoreOverrideCursor(); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } Q_GLOBAL_STATIC(DelayedCursorHandler, _delayedCursorHandler) void KexiUtils::setWaitCursor(bool noDelay) { if (qobject_cast(qApp)) { _delayedCursorHandler->start(noDelay); } } void KexiUtils::removeWaitCursor() { if (qobject_cast(qApp)) { _delayedCursorHandler->stop(); } } WaitCursor::WaitCursor(bool noDelay) { setWaitCursor(noDelay); } WaitCursor::~WaitCursor() { removeWaitCursor(); } WaitCursorRemover::WaitCursorRemover() { m_reactivateCursor = _delayedCursorHandler->startedOrActive; _delayedCursorHandler->stop(); } WaitCursorRemover::~WaitCursorRemover() { if (m_reactivateCursor) _delayedCursorHandler->start(true); } //-------------------------------------------------------------------------------- QObject* KexiUtils::findFirstQObjectChild(QObject *o, const char* className, const char* objName) { if (!o) return 0; const QObjectList list(o->children()); foreach(QObject *child, list) { if (child->inherits(className) && (!objName || child->objectName() == objName)) return child; } //try children foreach(QObject *child, list) { child = findFirstQObjectChild(child, className, objName); if (child) return child; } return 0; } QMetaProperty KexiUtils::findPropertyWithSuperclasses(const QObject* object, const char* name) { const int index = object->metaObject()->indexOfProperty(name); if (index == -1) return QMetaProperty(); return object->metaObject()->property(index); } bool KexiUtils::objectIsA(QObject* object, const QList& classNames) { foreach(const QByteArray& ba, classNames) { if (objectIsA(object, ba.constData())) return true; } return false; } QList KexiUtils::methodsForMetaObject( const QMetaObject *metaObject, QFlags types, QFlags access) { const int count = metaObject ? metaObject->methodCount() : 0; QList result; for (int i = 0; i < count; i++) { QMetaMethod method(metaObject->method(i)); if (types & method.methodType() && access & method.access()) result += method; } return result; } QList KexiUtils::methodsForMetaObjectWithParents( const QMetaObject *metaObject, QFlags types, QFlags access) { QList result; while (metaObject) { const int count = metaObject->methodCount(); for (int i = 0; i < count; i++) { QMetaMethod method(metaObject->method(i)); if (types & method.methodType() && access & method.access()) result += method; } metaObject = metaObject->superClass(); } return result; } QList KexiUtils::propertiesForMetaObject( const QMetaObject *metaObject) { const int count = metaObject ? metaObject->propertyCount() : 0; QList result; for (int i = 0; i < count; i++) result += metaObject->property(i); return result; } QList KexiUtils::propertiesForMetaObjectWithInherited( const QMetaObject *metaObject) { QList result; while (metaObject) { const int count = metaObject->propertyCount(); for (int i = 0; i < count; i++) result += metaObject->property(i); metaObject = metaObject->superClass(); } return result; } QStringList KexiUtils::enumKeysForProperty(const QMetaProperty& metaProperty) { QStringList result; QMetaEnum enumerator(metaProperty.enumerator()); const int count = enumerator.keyCount(); for (int i = 0; i < count; i++) result.append(QString::fromLatin1(enumerator.key(i))); return result; } QString KexiUtils::fileDialogFilterString(const QMimeType &mime, bool kdeFormat) { if (!mime.isValid()) { return QString(); } QString str; if (kdeFormat) { if (mime.globPatterns().isEmpty()) { str = "*"; } else { str = mime.globPatterns().join(" "); } str += "|"; } str += mime.comment(); if (!mime.globPatterns().isEmpty() || !kdeFormat) { str += " ("; if (mime.globPatterns().isEmpty()) str += "*"; else str += mime.globPatterns().join("; "); str += ")"; } if (kdeFormat) str += "\n"; else str += ";;"; return str; } QString KexiUtils::fileDialogFilterString(const QString& mimeName, bool kdeFormat) { QMimeDatabase db; QMimeType mime = db.mimeTypeForName(mimeName); return fileDialogFilterString(mime, kdeFormat); } QString KexiUtils::fileDialogFilterStrings(const QStringList& mimeStrings, bool kdeFormat) { QString ret; QStringList::ConstIterator endIt = mimeStrings.constEnd(); for (QStringList::ConstIterator it = mimeStrings.constBegin(); it != endIt; ++it) ret += fileDialogFilterString(*it, kdeFormat); return ret; } //! @internal static QFileDialog* getImageDialog(QWidget *parent, const QString &caption, const QUrl &directory, const QList &supportedMimeTypes) { QFileDialog *dialog = new QFileDialog(parent, caption); dialog->setDirectoryUrl(directory); const QStringList mimeTypeFilters = KexiUtils::convertTypesUsingFunction(supportedMimeTypes); dialog->setMimeTypeFilters(mimeTypeFilters); return dialog; } QUrl KexiUtils::getOpenImageUrl(QWidget *parent, const QString &caption, const QUrl &directory) { QScopedPointer dialog( getImageDialog(parent, caption.isEmpty() ? i18n("Open") : caption, directory, QImageReader::supportedMimeTypes())); dialog->setFileMode(QFileDialog::ExistingFile); dialog->setAcceptMode(QFileDialog::AcceptOpen); dialog->exec(); return dialog->selectedUrls().value(0); } QUrl KexiUtils::getSaveImageUrl(QWidget *parent, const QString &caption, const QUrl &directory) { QScopedPointer dialog( getImageDialog(parent, caption.isEmpty() ? i18n("Save") : caption, directory, QImageWriter::supportedMimeTypes())); dialog->setAcceptMode(QFileDialog::AcceptSave); dialog->exec(); return dialog->selectedUrls().value(0); } bool KexiUtils::askForFileOverwriting(const QString& filePath, QWidget *parent) { QFileInfo fi(filePath); if (!fi.exists()) { return true; } const KMessageBox::ButtonCode res = KMessageBox::warningYesNo(parent, xi18nc("@info", "The file %1 already exists." "Do you want to overwrite it?", QDir::toNativeSeparators(filePath)), QString(), KStandardGuiItem::overwrite(), KStandardGuiItem::no()); return res == KMessageBox::Yes; } QColor KexiUtils::blendedColors(const QColor& c1, const QColor& c2, int factor1, int factor2) { return QColor( int((c1.red()*factor1 + c2.red()*factor2) / (factor1 + factor2)), int((c1.green()*factor1 + c2.green()*factor2) / (factor1 + factor2)), int((c1.blue()*factor1 + c2.blue()*factor2) / (factor1 + factor2))); } QColor KexiUtils::contrastColor(const QColor& c) { int g = qGray(c.rgb()); if (g > 110) return c.dark(200); else if (g > 80) return c.light(150); else if (g > 20) return c.light(300); return Qt::gray; } QColor KexiUtils::bleachedColor(const QColor& c, int factor) { int h, s, v; c.getHsv(&h, &s, &v); QColor c2; if (factor < 100) factor = 100; if (s >= 250 && v >= 250) //for colors like cyan or red, make the result more white s = qMax(0, s - factor - 50); else if (s <= 5 && v <= 5) v += factor - 50; c2.setHsv(h, s, qMin(255, v + factor - 100)); return c2; } QIcon KexiUtils::colorizeIconToTextColor(const QPixmap& icon, const QPalette& palette, QPalette::ColorRole role) { QPixmap pm( KIconEffect().apply(icon, KIconEffect::Colorize, 1.0f, palette.color(role), false)); KIconEffect::semiTransparent(pm); return QIcon(pm); } QPixmap KexiUtils::emptyIcon(KIconLoader::Group iconGroup) { QPixmap noIcon(IconSize(iconGroup), IconSize(iconGroup)); noIcon.fill(Qt::transparent); return noIcon; } static void drawOrScalePixmapInternal(QPainter* p, const QMargins& margins, const QRect& rect, QPixmap* pixmap, QPoint* pos, Qt::Alignment alignment, bool scaledContents, bool keepAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation) { Q_ASSERT(pos); if (pixmap->isNull()) return; const bool fast = false; const int w = rect.width() - margins.left() - margins.right(); const int h = rect.height() - margins.top() - margins.bottom(); //! @todo we can optimize painting by drawing rescaled pixmap here //! and performing detailed painting later (using QTimer) // QPixmap pixmapBuffer; // QPainter p2; // QPainter *target; // if (fast) { // target = p; // } else { // target = &p2; // } //! @todo only create buffered pixmap of the minimum size and then do not fillRect() // target->fillRect(0,0,rect.width(),rect.height(), backgroundColor); *pos = rect.topLeft() + QPoint(margins.left(), margins.top()); if (scaledContents) { if (keepAspectRatio) { QImage img(pixmap->toImage()); img = img.scaled(w, h, Qt::KeepAspectRatio, transformMode); if (img.width() < w) { if (alignment & Qt::AlignRight) pos->setX(pos->x() + w - img.width()); else if (alignment & Qt::AlignHCenter) pos->setX(pos->x() + w / 2 - img.width() / 2); } else if (img.height() < h) { if (alignment & Qt::AlignBottom) pos->setY(pos->y() + h - img.height()); else if (alignment & Qt::AlignVCenter) pos->setY(pos->y() + h / 2 - img.height() / 2); } if (p) { p->drawImage(*pos, img); } else { *pixmap = QPixmap::fromImage(img); } } else { if (!fast) { *pixmap = pixmap->scaled(w, h, Qt::IgnoreAspectRatio, transformMode); if (p) { p->drawPixmap(*pos, *pixmap); } } } } else { if (alignment & Qt::AlignRight) pos->setX(pos->x() + w - pixmap->width()); else if (alignment & Qt::AlignHCenter) pos->setX(pos->x() + w / 2 - pixmap->width() / 2); else //left, etc. pos->setX(pos->x()); if (alignment & Qt::AlignBottom) pos->setY(pos->y() + h - pixmap->height()); else if (alignment & Qt::AlignVCenter) pos->setY(pos->y() + h / 2 - pixmap->height() / 2); else //top, etc. pos->setY(pos->y()); *pos += QPoint(margins.left(), margins.top()); if (p) { p->drawPixmap(*pos, *pixmap); } } } void KexiUtils::drawPixmap(QPainter* p, const QMargins& margins, const QRect& rect, const QPixmap& pixmap, Qt::Alignment alignment, bool scaledContents, bool keepAspectRatio, Qt::TransformationMode transformMode) { QPixmap px(pixmap); QPoint pos; drawOrScalePixmapInternal(p, margins, rect, &px, &pos, alignment, scaledContents, keepAspectRatio, transformMode); } QPixmap KexiUtils::scaledPixmap(const QMargins& margins, const QRect& rect, const QPixmap& pixmap, QPoint* pos, Qt::Alignment alignment, bool scaledContents, bool keepAspectRatio, Qt::TransformationMode transformMode) { QPixmap px(pixmap); drawOrScalePixmapInternal(0, margins, rect, &px, pos, alignment, scaledContents, keepAspectRatio, transformMode); return px; } bool KexiUtils::loadPixmapFromData(QPixmap *pixmap, const QByteArray &data, const char *format) { bool ok = pixmap->loadFromData(data, format); if (ok) { return true; } if (format) { return false; } const QList commonFormats({"png", "jpg", "bmp", "tif"}); QList formats(commonFormats); for(int i=0; ;) { ok = pixmap->loadFromData(data, formats[i]); if (ok) { return true; } ++i; if (i == formats.count()) {// try harder if (i == commonFormats.count()) { formats += QImageReader::supportedImageFormats(); if (formats.count() == commonFormats.count()) { break; // sanity check } } else { break; } } } return false; } void KexiUtils::setFocusWithReason(QWidget* widget, Qt::FocusReason reason) { if (!widget) return; QFocusEvent fe(QEvent::FocusIn, reason); QCoreApplication::sendEvent(widget, &fe); } void KexiUtils::unsetFocusWithReason(QWidget* widget, Qt::FocusReason reason) { if (!widget) return; QFocusEvent fe(QEvent::FocusOut, reason); QCoreApplication::sendEvent(widget, &fe); } //-------- void KexiUtils::adjustIfRtl(QMargins *margins) { if (margins && QGuiApplication::isRightToLeft()) { const int left = margins->left(); margins->setLeft(margins->right()); margins->setRight(left); } } //--------- Q_GLOBAL_STATIC(FontSettingsData, g_fontSettings) QFont KexiUtils::smallestReadableFont() { return g_fontSettings->font(FontSettingsData::SmallestReadableFont); } //--------------------- KTextEditorFrame::KTextEditorFrame(QWidget * parent, Qt::WindowFlags f) : QFrame(parent, f) { QEvent dummy(QEvent::StyleChange); changeEvent(&dummy); } void KTextEditorFrame::changeEvent(QEvent *event) { if (event->type() == QEvent::StyleChange) { if (style()->objectName() != "oxygen") // oxygen already nicely paints the frame setFrameStyle(QFrame::Sunken | QFrame::StyledPanel); else setFrameStyle(QFrame::NoFrame); } } //--------------------- int KexiUtils::marginHint() { return QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin); } int KexiUtils::spacingHint() { return QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); } void KexiUtils::setStandardMarginsAndSpacing(QLayout *layout) { setMargins(layout, KexiUtils::marginHint()); layout->setSpacing(KexiUtils::spacingHint()); } void KexiUtils::setMargins(QLayout *layout, int value) { layout->setContentsMargins(value, value, value, value); } void KexiUtils::replaceColors(QPixmap* original, const QColor& color) { Q_ASSERT(original); QImage dest(original->toImage()); replaceColors(&dest, color); *original = QPixmap::fromImage(dest); } void KexiUtils::replaceColors(QImage* original, const QColor& color) { Q_ASSERT(original); QPainter p(original); p.setCompositionMode(QPainter::CompositionMode_SourceIn); p.fillRect(original->rect(), color); } bool KexiUtils::isLightColorScheme() { return KColorScheme(QPalette::Active, KColorScheme::Window).background().color().lightness() >= 128; } int KexiUtils::dimmedAlpha() { return 150; } QPalette KexiUtils::paletteWithDimmedColor(const QPalette &pal, QPalette::ColorGroup group, QPalette::ColorRole role) { QPalette result(pal); QColor color(result.color(group, role)); color.setAlpha(dimmedAlpha()); result.setColor(group, role, color); return result; } QPalette KexiUtils::paletteWithDimmedColor(const QPalette &pal, QPalette::ColorRole role) { QPalette result(pal); QColor color(result.color(role)); color.setAlpha(dimmedAlpha()); result.setColor(role, color); return result; } QPalette KexiUtils::paletteForReadOnly(const QPalette &palette) { QPalette p(palette); p.setBrush(QPalette::Base, palette.brush(QPalette::Disabled, QPalette::Base)); p.setBrush(QPalette::Text, palette.brush(QPalette::Disabled, QPalette::Text)); p.setBrush(QPalette::Highlight, palette.brush(QPalette::Disabled, QPalette::Highlight)); p.setBrush(QPalette::HighlightedText, palette.brush(QPalette::Disabled, QPalette::HighlightedText)); return p; } void KexiUtils::setBackgroundColor(QWidget *widget, const QColor &color) { widget->setAutoFillBackground(true); QPalette pal(widget->palette()); pal.setColor(widget->backgroundRole(), color); widget->setPalette(pal); } //--------------------- void KexiUtils::installRecursiveEventFilter(QObject *object, QObject *filter) { if (!object || !filter || !object->isWidgetType()) return; // qDebug() << "Installing event filter on widget:" << object // << "directed to" << filter->objectName(); object->installEventFilter(filter); const QObjectList list(object->children()); foreach(QObject *obj, list) { installRecursiveEventFilter(obj, filter); } } void KexiUtils::removeRecursiveEventFilter(QObject *object, QObject *filter) { object->removeEventFilter(filter); if (!object->isWidgetType()) return; const QObjectList list(object->children()); foreach(QObject *obj, list) { removeRecursiveEventFilter(obj, filter); } } PaintBlocker::PaintBlocker(QWidget* parent) : QObject(parent) , m_enabled(true) { parent->installEventFilter(this); } void PaintBlocker::setEnabled(bool set) { m_enabled = set; } bool PaintBlocker::enabled() const { return m_enabled; } bool PaintBlocker::eventFilter(QObject* watched, QEvent* event) { if (m_enabled && watched == parent() && event->type() == QEvent::Paint) { return true; } return false; } tristate KexiUtils::openHyperLink(const QUrl &url, QWidget *parent, const OpenHyperlinkOptions &options) { +#ifndef KEXI_MOBILE if (url.isLocalFile()) { QFileInfo fileInfo(url.toLocalFile()); if (!fileInfo.exists()) { KMessageBox::sorry(parent, xi18nc("@info", "The file or directory %1 does not exist.", fileInfo.absoluteFilePath())); return false; } } if (!url.isValid()) { KMessageBox::sorry(parent, xi18nc("@info", "Invalid hyperlink %1.", url.url(QUrl::PreferLocalFile))); return false; } QMimeDatabase db; QString type = db.mimeTypeForUrl(url).name(); if (!options.allowExecutable && KRun::isExecutableFile(url, type)) { KMessageBox::sorry(parent, xi18nc("@info", "Executable %1 not allowed.", url.url(QUrl::PreferLocalFile))); return false; } if (!options.allowRemote && !url.isLocalFile()) { KMessageBox::sorry(parent, xi18nc("@info", "Remote hyperlink %1 not allowed.", url.url(QUrl::PreferLocalFile))); return false; } if (KRun::isExecutableFile(url, type)) { int ret = KMessageBox::questionYesNo(parent , xi18nc("@info", "Do you want to run this file?" "Running executables can be dangerous.") , QString() , KGuiItem(xi18nc("@action:button Run script file", "Run"), koIconName("system-run")) , KStandardGuiItem::no() , "AllowRunExecutable", KMessageBox::Dangerous); if (ret != KMessageBox::Yes) { return cancelled; } } switch(options.tool) { case OpenHyperlinkOptions::DefaultHyperlinkTool: return KRun::runUrl(url, type, parent); case OpenHyperlinkOptions::BrowserHyperlinkTool: return QDesktopServices::openUrl(url); case OpenHyperlinkOptions::MailerHyperlinkTool: return QDesktopServices::openUrl(url); default:; } +#endif return false; } // ---- KexiDBDebugTreeWidget::KexiDBDebugTreeWidget(QWidget *parent) : QTreeWidget(parent) { } void KexiDBDebugTreeWidget::copy() { if (currentItem()) { qApp->clipboard()->setText(currentItem()->text(0)); } } // ---- DebugWindow::DebugWindow(QWidget * parent) : QWidget(parent, Qt::Window) { } // ---- QSize KexiUtils::comboBoxArrowSize(QStyle *style) { if (!style) { style = QApplication::style(); } QStyleOptionComboBox cbOption; return style->subControlRect(QStyle::CC_ComboBox, &cbOption, QStyle::SC_ComboBoxArrow).size(); } void KexiUtils::addDirtyFlag(QString *text) { Q_ASSERT(text); *text = xi18nc("'Dirty (modified) object' flag", "%1*", *text); } //! From klocale_kde.cpp //! @todo KEXI3 support other OS-es (use from klocale_*.cpp) static QByteArray systemCodeset() { QByteArray codeset; #if HAVE_LANGINFO_H // Qt since 4.2 always returns 'System' as codecForLocale and KDE (for example // KEncodingFileDialog) expects real encoding name. So on systems that have langinfo.h use // nl_langinfo instead, just like Qt compiled without iconv does. Windows already has its own // workaround codeset = nl_langinfo(CODESET); if ((codeset == "ANSI_X3.4-1968") || (codeset == "US-ASCII")) { // means ascii, "C"; QTextCodec doesn't know, so avoid warning codeset = "ISO-8859-1"; } #endif return codeset; } QTextCodec* g_codecForEncoding = 0; bool setEncoding(int mibEnum) { QTextCodec *codec = QTextCodec::codecForMib(mibEnum); if (codec) { g_codecForEncoding = codec; } return codec != 0; } //! From klocale_kde.cpp static void initEncoding() { if (!g_codecForEncoding) { // This all made more sense when we still had the EncodingEnum config key. QByteArray codeset = systemCodeset(); if (!codeset.isEmpty()) { QTextCodec *codec = QTextCodec::codecForName(codeset); if (codec) { setEncoding(codec->mibEnum()); } } else { setEncoding(QTextCodec::codecForLocale()->mibEnum()); } if (!g_codecForEncoding) { qWarning() << "Cannot resolve system encoding, defaulting to ISO 8859-1."; const int mibDefault = 4; // ISO 8859-1 setEncoding(mibDefault); } Q_ASSERT(g_codecForEncoding); } } QByteArray KexiUtils::encoding() { initEncoding(); return g_codecForEncoding->name(); } namespace { //! @internal for graphicEffectsLevel() class GraphicEffectsLevel { public: GraphicEffectsLevel() { KConfigGroup g(KSharedConfig::openConfig(), "KDE-Global GUI Settings"); // Asking for hasKey we do not ask for graphicEffectsLevelDefault() that can // contain some very slow code. If we can save that time, do it. (ereslibre) if (g.hasKey("GraphicEffectsLevel")) { value = ((GraphicEffects) g.readEntry("GraphicEffectsLevel", QVariant((int) NoEffects)).toInt()); return; } // For now, let always enable animations by default. The plan is to make // this code a bit smarter. (ereslibre) value = ComplexAnimationEffects; } GraphicEffects value; }; } Q_GLOBAL_STATIC(GraphicEffectsLevel, g_graphicEffectsLevel) GraphicEffects KexiUtils::graphicEffectsLevel() { return g_graphicEffectsLevel->value; } bool KexiUtils::activateItemsOnSingleClick(QWidget *widget) { const KConfigGroup mainWindowGroup = KSharedConfig::openConfig()->group("MainWindow"); #ifdef Q_OS_WIN return mainWindowGroup.readEntry("SingleClickOpensItem", true); #else if (mainWindowGroup.hasKey("SingleClickOpensItem")) { return mainWindowGroup.readEntry("SingleClickOpensItem", true); } # if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) Q_UNUSED(widget) return QApplication::styleHints()->singleClickActivation(); # else QStyle *style = widget ? widget->style() : QApplication::style(); return style->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, widget); # endif #endif } // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp QColor KexiUtils::inactiveTitleColor() { #ifdef Q_OS_WIN return qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)); #else KConfigGroup g(KSharedConfig::openConfig(), "WM"); return g.readEntry("inactiveBackground", QColor(224, 223, 222)); #endif } // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp QColor KexiUtils::inactiveTextColor() { #ifdef Q_OS_WIN return qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)); #else KConfigGroup g(KSharedConfig::openConfig(), "WM"); return g.readEntry("inactiveForeground", QColor(75, 71, 67)); #endif } // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp QColor KexiUtils::activeTitleColor() { #ifdef Q_OS_WIN return qt_colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)); #else KConfigGroup g(KSharedConfig::openConfig(), "WM"); return g.readEntry("activeBackground", QColor(48, 174, 232)); #endif } // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp QColor KexiUtils::activeTextColor() { #ifdef Q_OS_WIN return qt_colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)); #else KConfigGroup g(KSharedConfig::openConfig(), "WM"); return g.readEntry("activeForeground", QColor(255, 255, 255)); #endif } QString KexiUtils::makeStandardCaption(const QString &userCaption, CaptionFlags flags) { QString caption = KAboutData::applicationData().displayName(); if (caption.isEmpty()) { return QCoreApplication::instance()->applicationName(); } QString captionString = userCaption.isEmpty() ? caption : userCaption; // If the document is modified, add '[modified]'. if (flags & ModifiedCaption) { captionString += QString::fromUtf8(" [") + xi18n("modified") + QString::fromUtf8("]"); } if (!userCaption.isEmpty()) { // Add the application name if: // User asked for it, it's not a duplication and the app name (caption()) is not empty if (flags & AppNameCaption && !caption.isEmpty() && !userCaption.endsWith(caption)) { // TODO: check to see if this is a transient/secondary window before trying to add the app name // on platforms that need this captionString += xi18nc("Document/application separator in titlebar", " – ") + caption; } } return captionString; } QString themedIconName(const QString &name) { static bool firstUse = true; if (firstUse) { // workaround for some kde-related crash const bool _unused = KIconLoader::global()->iconPath(name, KIconLoader::NoGroup, true).isEmpty(); Q_UNUSED(_unused); firstUse = false; } // try load themed icon const QColor background = qApp->palette().background().color(); const bool useDarkIcons = background.value() > 100; return QLatin1String(useDarkIcons ? "dark_" : "light_") + name; } QIcon themedIcon(const QString &name) { const QString realName(themedIconName(name)); const QIcon icon = QIcon::fromTheme(realName); // fallback if (icon.isNull()) { return QIcon::fromTheme(name); } return icon; } QString KexiUtils::localizedStringToHtmlSubstring(const KLocalizedString& string) { return string.toString(Kuit::RichText) .remove(QLatin1String("")).remove(QLatin1String("")); } bool KexiUtils::cursorAtEnd(const QLineEdit *lineEdit) { if (!lineEdit) { return false; } if (lineEdit->inputMask().isEmpty()) { return lineEdit->cursorPosition() >= lineEdit->displayText().length(); } else { return lineEdit->cursorPosition() >= (lineEdit->displayText().length() - 1); } } diff --git a/src/mobile/CMakeLists.txt b/src/mobile/CMakeLists.txt index 4e4942400..f55b26fd6 100644 --- a/src/mobile/CMakeLists.txt +++ b/src/mobile/CMakeLists.txt @@ -1,27 +1,24 @@ cmake_minimum_required(VERSION 2.8.0) -find_package(Qt4 REQUIRED) +find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Gui) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src/core ${CMAKE_SOURCE_DIR}/src/widget ) set(KexiMobile_SRCS main.cpp KexiMobileMainWindow.cpp KexiMobileWidget.cpp KexiMobileNavigator.cpp KexiMobileToolbar.cpp ) -qt4_automoc(${KexiMobile_SRCS}) - kexi_add_executable(keximobile ${KexiMobile_SRCS}) -target_link_libraries(keximobile Qt5::Core Qt5::Gui +target_link_libraries(keximobile kexiextendedwidgets kexicore - kdeui ) install(TARGETS keximobile ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 7c2d5aa58..d09a1db81 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -1,16 +1,14 @@ add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44021) -if (KEXI_MOBILE) - -else () +if(SHOULD_BUILD_KEXI_DESKTOP_APP) add_subdirectory( tables ) add_subdirectory( queries ) add_subdirectory( forms ) add_subdirectory( reports ) add_subdirectory( migration ) add_subdirectory( importexport ) if(SHOULD_BUILD_FEATURE_SCRIPTING AND KEXI_SCRIPTS_SUPPORT) # KEXI3 TODO add_subdirectory(scripting) endif() endif () diff --git a/src/plugins/reports/CMakeLists.txt b/src/plugins/reports/CMakeLists.txt index e8782e2ab..e6313f654 100644 --- a/src/plugins/reports/CMakeLists.txt +++ b/src/plugins/reports/CMakeLists.txt @@ -1,49 +1,45 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/core ${CMAKE_SOURCE_DIR}/src/widget ) # the main plugin set(kexi_reportplugin_SRCS kexireports.cpp kexireportpart.cpp kexireportview.cpp kexireportdesignview.cpp KexiDBReportDataSource.cpp kexisourceselector.cpp krscriptfunctions.cpp ) -if (KEXI_MOBILE) - -else () +if(SHOULD_BUILD_KEXI_DESKTOP_APP) #TODO KEXI3 # list(APPEND kexi_reportplugin_SRCS # keximigratereportdata.cpp # ) endif () #TODO KEXI3 qt5_wrap_cpp(kexi_reportplugin_SRCS ../scripting/kexiscripting/kexiscriptadaptor.h) add_library(kexi_reportplugin MODULE ${kexi_reportplugin_SRCS}) kcoreaddons_desktop_to_json(kexi_reportplugin kexi_reportplugin.desktop) target_link_libraries(kexi_reportplugin PRIVATE kexiguiutils kexiextendedwidgets KReport ) -if (KEXI_MOBILE) - -else () +if(SHOULD_BUILD_KEXI_DESKTOP_APP) target_link_libraries(kexi_reportplugin PRIVATE keximain #TODO KEXI3 keximigrate ) -endif () +endif() install(TARGETS kexi_reportplugin DESTINATION ${KEXI_PLUGIN_INSTALL_DIR}) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index f61a66a89..9b12785f1 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,12 +1,10 @@ if(BUILD_TESTING) - If (KEXI_MOBILE) - - else() + if(SHOULD_BUILD_KEXI_DESKTOP_APP) add_subdirectory( newapi ) add_subdirectory( migration ) endif() #add_subdirectory( widgets ) #add_subdirectory( odf ) #add_subdirectory( mainwindow ) add_subdirectory( sqlitetest ) endif() diff --git a/src/widget/CMakeLists.txt b/src/widget/CMakeLists.txt index 0780f6547..13f2015be 100644 --- a/src/widget/CMakeLists.txt +++ b/src/widget/CMakeLists.txt @@ -1,104 +1,100 @@ add_subdirectory( dataviewcommon ) add_subdirectory( relations ) add_subdirectory( undo ) add_subdirectory( utils ) -if(KEXI_MOBILE) - -else() - add_subdirectory( tableview ) +if(SHOULD_BUILD_KEXI_DESKTOP_APP) + add_subdirectory( tableview ) endif() add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44023) include_directories(${CMAKE_SOURCE_DIR}/src/widget/tableview ${CMAKE_SOURCE_DIR}/src/core) ########### next target ############### set(kexiextendedwidgets_LIB_SRCS fields/KexiFieldComboBox.cpp fields/KexiFieldListModel.cpp fields/KexiFieldListModelItem.cpp fields/KexiFieldListView.cpp navigator/KexiProjectModel.cpp navigator/KexiProjectModelItem.cpp navigator/KexiProjectItemDelegate.cpp navigator/KexiProjectNavigator.cpp navigator/KexiProjectTreeView.cpp properties/KexiCustomPropertyFactory.cpp properties/KexiCustomPropertyFactory_p.cpp properties/KexiPropertyEditorView.cpp properties/KexiPropertyPaneViewBase.cpp kexiquerydesignersqleditor.cpp kexiqueryparameters.cpp kexisectionheader.cpp kexidbdrivercombobox.cpp kexieditor.cpp KexiDataSourceComboBox.cpp KexiObjectInfoLabel.cpp kexicharencodingcombobox.cpp KexiDBTitlePage.cpp KexiProjectSelectorWidget.cpp kexislider.cpp KexiServerDriverNotFoundMessage.cpp KexiNameWidget.cpp KexiNameDialog.cpp KexiStartupFileHandler.cpp KexiListView.cpp ) -if (KEXI_MOBILE) - -else () +if(SHOULD_BUILD_KEXI_DESKTOP_APP) list(APPEND kexiextendedwidgets_LIB_SRCS #navigator/KexiProjectListView.cpp #navigator/KexiProjectListViewItem.cpp kexidbconnectionwidget.cpp # TODO replace use of KexiProjectListView and KexiProjectListViewList (with KexiProjectNavigator) # in kexiactionselectiondialog and remove them kexiprjtypeselector.cpp KexiConnectionSelectorWidget.cpp KexiFileWidget.cpp KexiFileDialog.cpp KexiPasswordWidget.cpp KexiDBPasswordDialog.cpp ) ki18n_wrap_ui(kexiextendedwidgets_LIB_SRCS KexiConnectionSelector.ui kexidbconnectionwidget.ui kexidbconnectionwidgetdetails.ui kexiprjtypeselector.ui KexiPasswordWidget.ui ) endif () ki18n_wrap_ui(kexiextendedwidgets_LIB_SRCS KexiDBTitlePage.ui KexiProjectSelector.ui ) kexi_add_library(kexiextendedwidgets SHARED ${kexiextendedwidgets_LIB_SRCS}) generate_export_header(kexiextendedwidgets BASE_NAME kexiextwidgets) target_link_libraries(kexiextendedwidgets PRIVATE kexidataviewcommon kexiguiutils KF5::TextWidgets # KTextEdit KF5::Codecs # KCharsets PUBLIC kexicore KPropertyWidgets KF5::KIOFileWidgets # KFileWidget KF5::TextEditor ) install(TARGETS kexiextendedwidgets ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/widget/utils/CMakeLists.txt b/src/widget/utils/CMakeLists.txt index e3023697d..2aac5c7b4 100644 --- a/src/widget/utils/CMakeLists.txt +++ b/src/widget/utils/CMakeLists.txt @@ -1,31 +1,30 @@ include_directories(${CMAKE_SOURCE_DIR}/src/widget/utils) set(kexiguiutils_LIB_SRCS kexisharedactionclient.cpp kexidisplayutils.cpp kexitooltip.cpp kexicontextmenuutils.cpp kexidropdownbutton.cpp kexicomboboxdropdownbutton.cpp kexidatetimeformatter.cpp KexiDockableWidget.cpp ) -if (KEXI_MOBILE) -else () +if(SHOULD_BUILD_KEXI_DESKTOP_APP) list(APPEND kexiguiutils_LIB_SRCS kexirecordnavigator.cpp ) -endif () +endif() kexi_add_library(kexiguiutils SHARED ${kexiguiutils_LIB_SRCS}) generate_export_header(kexiguiutils) target_link_libraries(kexiguiutils kexicore KF5::KIOWidgets ) install(TARGETS kexiguiutils ${INSTALL_TARGETS_DEFAULT_ARGS})