diff --git a/CMakeLists.txt b/CMakeLists.txt index 267a11240..78f881073 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,284 +1,284 @@ 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}) +project(KEXI VERSION ${PROJECT_VERSION}) include(KexiAddTests) kexi_add_tests(OFF) # 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) include(KexiGenerateDependencyGraph) 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) set(PRODUCTSET_DEFAULT "DESKTOP") 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) 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} COMPONENTS Crash) macro_bool_to_01(KF5Crash_FOUND HAVE_KCRASH) set_package_properties(KF5Crash PROPERTIES TYPE OPTIONAL PURPOSE "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 ) # overcome some platform incompatibilities if(WIN32) find_package(KDEWin REQUIRED) endif() -# set custom Kexi plugin installdir +# set custom KEXI plugin installdir set(KEXI_PLUGIN_INSTALL_DIR ${PLUGIN_INSTALL_DIR}/${KEXI_BASE_PATH}) simple_option(BUILD_EXAMPLES "Build and install examples" ON) macro_bool_to_01(BUILD_EXAMPLES COMPILING_EXAMPLES) -# set custom Kexi examples installdir +# set custom KEXI examples installdir set(KEXI_EXAMPLES_INSTALL_DIR ${SHARE_INSTALL_PREFIX}/${KEXI_BASE_PATH}/examples) # 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.95) ## ## Test for KDb ## -simple_option(KEXI_DEBUG_GUI "Debugging GUI for Kexi (requires KDB_DEBUG_GUI to be set too)" OFF) +simple_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}) set_package_properties(KDb PROPERTIES TYPE REQUIRED - PURPOSE "Required by Kexi for data handling") + PURPOSE "Required by KEXI for data handling") ## ## Test for KReport ## find_package(KReport ${KEXI_LIBS_MIN_VERSION}) set_package_properties(KReport PROPERTIES TYPE REQUIRED - PURPOSE "Required by Kexi for report handling") + PURPOSE "Required by KEXI for report handling") if (KReport_FOUND) if(NOT KREPORT_SCRIPTING) - message(FATAL_ERROR "Kexi requires KReport package with scripting support enabled (KREPORT_SCRIPTING)") + message(FATAL_ERROR "KEXI requires KReport package with scripting support enabled (KREPORT_SCRIPTING)") endif() endif() ## ## Test for KPropertyWidgets ## if(SHOULD_BUILD_KEXI_DESKTOP_APP) find_package(KPropertyWidgets ${KEXI_LIBS_MIN_VERSION} REQUIRED COMPONENTS KF) set_package_properties(KPropertyWidgets PROPERTIES TYPE REQUIRED - PURPOSE "Required by Kexi for handling properties") + PURPOSE "Required by KEXI for handling properties") else() # only KPropertyCore find_package(KPropertyCore ${KEXI_LIBS_MIN_VERSION} REQUIRED COMPONENTS KF) set_package_properties(KPropertyCore PROPERTIES TYPE REQUIRED - PURPOSE "Required by Kexi for handling properties") + PURPOSE "Required by KEXI for handling properties") endif() include(CheckIfQtGuiCanBeExecuted) if(SHOULD_BUILD_KEXI_DESKTOP_APP) include(CheckGlobalBreezeIcons) endif() ########################### ############################ ## Optional dependencies ## ############################ ########################### ## ## Test for marble ## set(MARBLE_MIN_VERSION "0.19.2") find_package(KexiMarble ${MARBLE_MIN_VERSION}) set_package_properties(KexiMarble PROPERTIES DESCRIPTION "KDE World Globe Widget library" URL "https://marble.kde.org" TYPE RECOMMENDED - PURPOSE "Required by Kexi form map widget" + PURPOSE "Required by KEXI form map widget" ) if(NOT MARBLE_FOUND) set(MARBLE_INCLUDE_DIR "") else() set(HAVE_MARBLE TRUE) endif() set_package_properties(GLIB2 PROPERTIES TYPE RECOMMENDED PURPOSE "${_REQUIRED_BY_MDB}") ## ## Test for Qt WebKitWidgets ## #TODO switch to Qt WebEngine macro_bool_to_01(Qt5WebKitWidgets_FOUND HAVE_QTWEBKITWIDGETS) set_package_properties(Qt5WebKit PROPERTIES DESCRIPTION "Webkit for Qt, the HTML engine." URL "http://qt.io" - TYPE RECOMMENDED PURPOSE "Required by Kexi web form widget" + TYPE RECOMMENDED PURPOSE "Required by KEXI web form widget" ) set_package_properties(Qt5WebKitWidgets PROPERTIES DESCRIPTION "QWidgets module for Webkit, the HTML engine." URL "http://qt.io" - TYPE RECOMMENDED PURPOSE "Required by Kexi web form widget" + TYPE RECOMMENDED PURPOSE "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() calligra_product_deps_report("product_deps") calligra_log_should_build() feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/KexiProducts.cmake b/KexiProducts.cmake index 60ed43726..c54b45cea 100644 --- a/KexiProducts.cmake +++ b/KexiProducts.cmake @@ -1,216 +1,217 @@ ### DEFINITION OF PRODUCTS, FEATURES AND PRODUCTSETS #################################################### -# When building Kexi a lot of different things are created and installed. To +# 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_* # 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) +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 KEXI_CORE_APP) +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?" # (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/modules/KexiGenerateDependencyGraph.cmake b/cmake/modules/KexiGenerateDependencyGraph.cmake index 7f0b88d36..d41ea08af 100644 --- a/cmake/modules/KexiGenerateDependencyGraph.cmake +++ b/cmake/modules/KexiGenerateDependencyGraph.cmake @@ -1,63 +1,63 @@ # Generates dependency graphs for current project # # Copyright (C) 2017 Jarosław Staniek # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if(TARGET generate_dependency_graph) return() endif() find_package(Doxygen) if(NOT DOXYGEN_DOT_EXECUTABLE) message(STATUS "Graphviz dot tool not found, won't generate dependency graphs") return() endif() set(_graph_dir ${CMAKE_BINARY_DIR}/dependencies) set(_dot_file ${_graph_dir}/graph.dot) set(_image_file "dependency-graph-${CMAKE_PROJECT_NAME}.png") -simple_option(${PROJECT_NAME_UPPER}_DEPENDENCY_GRAPH_INCLUDE_KEXI_FRAMEWORKS "Include Kexi frameworks in the dependency graph" ON) +simple_option(${PROJECT_NAME_UPPER}_DEPENDENCY_GRAPH_INCLUDE_KEXI_FRAMEWORKS "Include KEXI frameworks in the dependency graph" ON) simple_option(${PROJECT_NAME_UPPER}_DEPENDENCY_GRAPH_INCLUDE_ALL_LIBS "Include all libs in the dependency graph" OFF) configure_file(${CMAKE_CURRENT_LIST_DIR}/CMakeGraphVizOptions.cmake.in ${CMAKE_BINARY_DIR}/CMakeGraphVizOptions.cmake) add_custom_target(generate_dependency_graph) add_custom_command( TARGET generate_dependency_graph POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${_graph_dir} COMMAND cmake --graphviz=${_dot_file} . WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Generating dependency graph ${_graph_dir}/${_dot_file} for " "${CMAKE_PROJECT_NAME} project" ) add_custom_command( TARGET generate_dependency_graph POST_BUILD COMMAND ${DOXYGEN_DOT_EXECUTABLE} ${_dot_file} -T png > "${_graph_dir}/${_image_file}" WORKING_DIRECTORY ${_graph_dir} COMMENT "Generating dependency graph image ${_graph_dir}/${_image_file} for " "${CMAKE_PROJECT_NAME} project" ) add_custom_target(show_dependency_graph) if(WIN32) set(_open_command start) else() set(_open_command xdg-open) endif() add_custom_command( TARGET show_dependency_graph POST_BUILD COMMAND ${_open_command} "${_graph_dir}/${_image_file}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Show dependency graph image for ${CMAKE_PROJECT_NAME} project" ) unset(_dot_file) unset(_image_file) unset(_graph_dir) unset(_open_command) diff --git a/cmake/modules/SetKexiVersionInfo.cmake b/cmake/modules/SetKexiVersionInfo.cmake index 55a31ee4f..b0006c37d 100644 --- a/cmake/modules/SetKexiVersionInfo.cmake +++ b/cmake/modules/SetKexiVersionInfo.cmake @@ -1,77 +1,77 @@ # Copyright (C) 2003-2016 Jarosław Staniek # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. -# Define common versions of Kexi components used to generate KexiVersion.h +# Define common versions of KEXI components used to generate KexiVersion.h # update these version for every release: set(PROJECT_VERSION_STRING "3.2 Alpha") # Custom name such as "3.1 Alpha" set(PROJECT_STABLE_VERSION_MAJOR 3) # 3 for 3.x, 4 for 4.x, etc. set(PROJECT_STABLE_VERSION_MINOR 2) # 0 for 3.0, 1 for 3.1, etc. set(PROJECT_VERSION_RELEASE 90) # 90 for Alpha, increase for next test releases, set 0 for first Stable, etc. set(KEXI_ALPHA 1) # uncomment only for Alpha #set(KEXI_BETA 1) # uncomment only for Beta #set(KEXI_RC 1) # uncomment only for RC set(KEXI_YEAR 2018) # update every year # -- do not edit below this line -- set(KEXI_CUSTOM_DISTRIBUTION_VERSION "" CACHE STRING - "Custom name of Kexi version useful to construct co-installabile releases. Any nonempty directory name is accepted. If specified it will be used in KEXI_DISTRIBUTION_VERSION. If not specified, KEXI_DISTRIBUTION_VERSION will be set to PROJECT_STABLE_VERSION_MAJOR.PROJECT_STABLE_VERSION_MINOR.") + "Custom name of KEXI version useful to construct co-installabile releases. Any nonempty directory name is accepted. If specified it will be used in KEXI_DISTRIBUTION_VERSION. If not specified, KEXI_DISTRIBUTION_VERSION will be set to PROJECT_STABLE_VERSION_MAJOR.PROJECT_STABLE_VERSION_MINOR.") if(KEXI_CUSTOM_DISTRIBUTION_VERSION STREQUAL "") set(KEXI_DISTRIBUTION_VERSION "${PROJECT_STABLE_VERSION_MAJOR}.${PROJECT_STABLE_VERSION_MINOR}") else() set(KEXI_DISTRIBUTION_VERSION "${KEXI_CUSTOM_DISTRIBUTION_VERSION}") endif() # Relative path name useful to construct co-installabile file names and paths set(KEXI_BASE_PATH "kexi/${KEXI_DISTRIBUTION_VERSION}") if(NOT DEFINED KEXI_ALPHA AND NOT DEFINED KEXI_BETA AND NOT DEFINED KEXI_RC) set(KEXI_STABLE 1) endif() # PROJECT_VERSION_MAJOR is the same as PROJECT_STABLE_VERSION_MAJOR but for unstable x.0 # x is decreased by one, e.g. 3.0 Beta is 2.99. if(NOT DEFINED KEXI_STABLE AND PROJECT_STABLE_VERSION_MINOR EQUAL 0) math(EXPR PROJECT_VERSION_MAJOR "${PROJECT_STABLE_VERSION_MAJOR} - 1") else() math(EXPR PROJECT_VERSION_MAJOR ${PROJECT_STABLE_VERSION_MAJOR}) endif() # PROJECT_VERSION_MINOR is equal to PROJECT_STABLE_VERSION_MINOR for stable releases, # equal to 99 for x.0 unstable releases (e.g. it's 3.0 Beta has minor version 99), # and equal to PROJECT_STABLE_VERSION_MINOR-1 for unstable releases other than x.0. if(DEFINED KEXI_STABLE) set(PROJECT_VERSION_MINOR ${PROJECT_STABLE_VERSION_MINOR}) elseif(PROJECT_STABLE_VERSION_MINOR EQUAL 0) set(PROJECT_VERSION_MINOR 99) else() math(EXPR PROJECT_VERSION_MINOR "${PROJECT_STABLE_VERSION_MINOR} - 1") endif() # PROJECT_STABLE_VERSION_RELEASE is equal to PROJECT_VERSION_RELEASE for stable releases # and 0 for unstable ones. if(DEFINED KEXI_STABLE) set(PROJECT_STABLE_VERSION_RELEASE ${PROJECT_VERSION_RELEASE}) else() set(PROJECT_STABLE_VERSION_RELEASE 0) endif() set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_RELEASE}) -message(STATUS "Kexi version \"${PROJECT_VERSION_STRING}\" (${PROJECT_VERSION}), distribution version \"${KEXI_DISTRIBUTION_VERSION}\"") +message(STATUS "KEXI version \"${PROJECT_VERSION_STRING}\" (${PROJECT_VERSION}), distribution version \"${KEXI_DISTRIBUTION_VERSION}\"") -# Define the generic version of the Kexi libraries here -# This makes it easy to advance it when the next Kexi release comes. -# 14 was the last GENERIC_PROJECT_LIB_VERSION_MAJOR of the previous Kexi series +# Define the generic version of the KEXI libraries here +# This makes it easy to advance it when the next KEXI release comes. +# 14 was the last GENERIC_PROJECT_LIB_VERSION_MAJOR of the previous KEXI series # (2.x) so we're starting with 15 in 3.x series. if(PROJECT_STABLE_VERSION_MAJOR EQUAL 3) math(EXPR GENERIC_PROJECT_LIB_VERSION_MAJOR "${PROJECT_STABLE_VERSION_MINOR} + 15") else() # let's make sure we won't forget to update the "15" message(FATAL_ERROR "Reminder: please update offset == 15 used to compute GENERIC_PROJECT_LIB_VERSION_MAJOR to something bigger") endif() set(GENERIC_PROJECT_LIB_VERSION "${GENERIC_PROJECT_LIB_VERSION_MAJOR}.0.0") set(GENERIC_PROJECT_LIB_SOVERSION "${GENERIC_PROJECT_LIB_VERSION_MAJOR}") diff --git a/kundo2_aware_xgettext.sh b/kundo2_aware_xgettext.sh index 876a190af..315a459b4 100644 --- a/kundo2_aware_xgettext.sh +++ b/kundo2_aware_xgettext.sh @@ -1,113 +1,113 @@ # -# Helper function for extracting translatable messages from Kexi source code. +# Helper function for extracting translatable messages from KEXI source code. # Usage: kundo2_aware_xgettext # If there are no messages or the is empty, the pot file is deleted. # # Example usage that creates $podir/myapp.pot file: # kundo2_aware_xgettext myapp.pot `find . -name \*.cpp -o -name \*.h` # function kundo2_aware_xgettext() { POTFILE="$podir/$1" shift if test -n "$*"; then # we rely on last line being a 'msgstr' signaling that strings has been extracted (a header is always present) # normally it ends with 'msgstr ""' but if plural it can end with eg 'msgstr[1] ""' kundo2_aware_xgettext_internal $* | tee "${POTFILE}" | tail -n1 | grep "^msgstr" > /dev/null \ || rm -f "${POTFILE}" 2> /dev/null fi } # How to unit test: # export podir=. # cp init-sample.pot sample.pot # source krita_xgettext.sh # add_ctxt_qtundo sample.pot # # Then check that all messages in sample.pot have "(qtundo-format)" in msgctxt. function add_ctxt_qtundo() { POT_PART_QUNDOFORMAT="$1" POT_PART_QUNDOFORMAT2="`mktemp $podir/_qundoformat2_XXXXXXXX.pot`" # Prepend "(qtundo-format)" to existing msgctxt properties of messages sed -i -e 's/^msgctxt "/msgctxt "(qtundo-format) /' "${POT_PART_QUNDOFORMAT}" # Add msgctxt "(qtundo-format)" to messages not having msgctxt yet # # lastLine != "#, fuzzy" is the check for the .pot header. # If lastLine starts with '"' the msgctxt has been split on several lines and is treated by sed above, so skip it mv "${POT_PART_QUNDOFORMAT}" "${POT_PART_QUNDOFORMAT2}" cat "${POT_PART_QUNDOFORMAT2}" | awk ' /^msgid "/ { if (lastLine !~ /^\"/ && lastLine !~ /^msgctxt/ && lastLine != "#, fuzzy") { print "msgctxt \"(qtundo-format)\"" } } { print ; lastLine = $0 }' > "${POT_PART_QUNDOFORMAT}" rm -f "${POT_PART_QUNDOFORMAT2}" } function kundo2_aware_xgettext_internal() { SRC_FILES="$*" POT_PART_NORMAL="`mktemp $podir/_normal_XXXXXXXX.pot`" POT_PART_QUNDOFORMAT="`mktemp $podir/_qundoformat_XXXXXXXX.pot`" POT_MERGED="`mktemp $podir/_merged_XXXXXXXX.pot`" $XGETTEXT ${CXG_EXTRA_ARGS} ${SRC_FILES} -o "${POT_PART_NORMAL}" --force-po XGETTEXT_FLAGS_KUNDO2="\ --copyright-holder=This_file_is_part_of_KDE \ --msgid-bugs-address=http://bugs.kde.org \ --from-code=UTF-8 -C -k --kde \ -kkundo2_i18n:1 -kkundo2_i18np:1,2 -kkundo2_i18nc:1c,2 -kkundo2_i18ncp:1c,2,3 \ " $XGETTEXT_PROGRAM ${XGETTEXT_FLAGS_KUNDO2} ${CXG_EXTRA_ARGS} ${SRC_FILES} -o "${POT_PART_QUNDOFORMAT}" if [ $(cat ${POT_PART_NORMAL} ${POT_PART_QUNDOFORMAT} | grep -c \(qtundo-format\)) != 0 ]; then echo "ERROR: Context '(qtundo-format)' should not be added manually. Use kundo2_i18n*() calls instead." 1>&2 exit 17 fi if [ -s "${POT_PART_QUNDOFORMAT}" ]; then add_ctxt_qtundo "${POT_PART_QUNDOFORMAT}" fi if [ -s "${POT_PART_NORMAL}" -a -s "${POT_PART_QUNDOFORMAT}" ]; then # ensure an empty line or else KDE_HEADER search will fail # in case POT_PART_NORMAL only contains header echo "" >>${POT_PART_NORMAL} ${MSGCAT} -F "${POT_PART_NORMAL}" "${POT_PART_QUNDOFORMAT}" > ${POT_MERGED} MERGED_HEADER_LINE_COUNT=$(cat ${POT_MERGED} | grep "^$" -B 100000 --max-count=1 | wc -l) KDE_HEADER="$(cat ${POT_PART_NORMAL} | grep "^$" -B 100000 --max-count=1)" MERGED_TAIL="$(cat ${POT_MERGED} | tail -n +$MERGED_HEADER_LINE_COUNT)" # Print out the resulting .pot echo "$KDE_HEADER" echo "$MERGED_TAIL" elif [ -s "${POT_PART_NORMAL}" ]; then echo "# POT_PART_NORMAL only" cat "${POT_PART_NORMAL}" elif [ -s "${POT_PART_QUNDOFORMAT}" ]; then echo "# POT_PART_QUNDOFORMAT only" cat "${POT_PART_QUNDOFORMAT}" fi rm -f "${POT_PART_NORMAL}" "${POT_PART_QUNDOFORMAT}" "${POT_MERGED}" } # Sets EXCLUDE variable to excludes compatible with the find(1) command, e.g. '-path a -o -path b'. # To unconditionally exclude dir (with subdirs) just put an empty file .i18n in it. # To disable excluding for given file, e.g. foo.pot, add "foo.pot" line to the .i18n file. function find_exclude() { EXCLUDE="" for f in `find . -name .i18n | sed 's/\/\.i18n$//g' | sort`; do if ! grep -q "^${1}$" "$f/.i18n" ; then if [ -n "$EXCLUDE" ] ; then EXCLUDE="$EXCLUDE -o " ; fi EXCLUDE="$EXCLUDE -path $f" fi done if [ -z "$EXCLUDE" ] ; then EXCLUDE="-path __dummy__" ; fi # needed because -prune in find needs args } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 11899dbeb..6f8fee581 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,124 +1,126 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) check_function_exists("uname" HAVE_UNAME) -simple_option(KEXI_SHOW_UNFINISHED "Show unfinished features in Kexi. Thus is useful for testing but may confuse end-user." OFF) -simple_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) +simple_option(KEXI_SHOW_UNFINISHED "Show unfinished features in KEXI. Thus is useful for testing \ +but may confuse end-user." OFF) +simple_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 if(NOT KEXI_MOBILE) - simple_option(KEXI_AUTORISE_TABBED_TOOLBAR "Experimental: Autorise the main tabbed toolbar in Kexi" OFF) + simple_option(KEXI_AUTORISE_TABBED_TOOLBAR "Experimental: Autorise the main tabbed toolbar in KEXI" OFF) if(WIN32 OR APPLE) set(_KEXI_USE_KFILEWIDGET_DEFAULT OFF) else() set(_KEXI_USE_KFILEWIDGET_DEFAULT ON) endif() - simple_option(KEXI_USE_KFILEWIDGET "Use KFileWidget-based inline file browser in Kexi. If OFF, a simple \ + simple_option(KEXI_USE_KFILEWIDGET "Use KFileWidget-based inline file browser in KEXI. If OFF, a simple \ replacement file widget with native file dialogs is used. ON by default on UNIX, OFF by default on Windows \ and macOS. \ Note: Non-plasma Linux desktops still default to the simple replacement at runtime." ${_KEXI_USE_KFILEWIDGET_DEFAULT} ) endif(NOT KEXI_MOBILE) # Experimental: -simple_option(KEXI_SCRIPTS_SUPPORT "Experimental: Enable scripting in Kexi" OFF) +simple_option(KEXI_SCRIPTS_SUPPORT "Experimental: Enable scripting in KEXI" OFF) if(KEXI_SCRIPTS_SUPPORT) set(REQUIRED_QTQML_VERSION 5.8.0) # >= 5.8 because of QJSEngine::newQMetaObject() find_package(Qt5Qml ${REQUIRED_QTQML_VERSION} REQUIRED) set_package_properties(Qt5Qml PROPERTIES DESCRIPTION "A framework for developing applications and libraries with the QML and JavaScript language." URL "http://qt.io" - TYPE REQUIRED PURPOSE "Required by Kexi scripting (JavaScript)" + TYPE REQUIRED PURPOSE "Required by KEXI scripting (JavaScript)" ) endif() # Broken: simple_option(KEXI_FORM_CURSOR_PROPERTY_SUPPORT "Broken: Enable \"cursor\" property in the form designer" OFF) -simple_option(KEXI_SHOW_CONTEXT_HELP "Broken: Enable context help in Kexi main window" OFF) +simple_option(KEXI_SHOW_CONTEXT_HELP "Broken: Enable context help in KEXI main window" OFF) simple_option(KEXI_QUICK_PRINTING_SUPPORT "Broken: Enable print/print preview/print setup for tables/queries in the project navigator" OFF) simple_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? simple_option(KEXI_LIST_FORM_WIDGET_SUPPORT "Broken: Enable \"list\" form widget in the form designer" OFF) simple_option(KEXI_PIXMAP_COLLECTIONS_SUPPORT "Broken: Enable support for pixmap collections" OFF) # Not available: -simple_option(KEXI_MACROS_SUPPORT "Experimental: Enable macros in Kexi" OFF) +simple_option(KEXI_MACROS_SUPPORT "Experimental: Enable macros in KEXI" OFF) if(KEXI_MACROS_SUPPORT) # temp. message(FATAL_ERROR "Macros are not yet available.") endif() -simple_option(KEXI_TABLE_PRINT_SUPPORT "Experimental: Enable printing of tabular view in Kexi" OFF) # broken since Kexi 2 +simple_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() -simple_option(KEXI_PROJECT_TEMPLATES "Experimental: Enable support for project templates in Kexi" OFF) # broken since Kexi 2 +simple_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 ) 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() ########### next target ############### 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() if(SHOULD_BUILD_KEXI_MOBILE_APP) # add_subdirectory( mobile ) endif() if(BUILD_EXAMPLES) add_subdirectory(examples) endif() diff --git a/src/KexiVersion.h.cmake b/src/KexiVersion.h.cmake index d0d053115..a7205cd9e 100644 --- a/src/KexiVersion.h.cmake +++ b/src/KexiVersion.h.cmake @@ -1,312 +1,310 @@ /* This file is part of the KDE project - Copyright (c) 2003-2016 Kexi Team + Copyright (c) 2003-2016 KEXI Team Version information based on calligraversion.h, Copyright (c) 2003 David Faure Copyright (c) 2003 Lukas Tinkl Copyright (c) 2004 Nicolas Goutte 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 KEXIVERSION_H #define KEXIVERSION_H #include // -- WARNING: do not edit values below, instead edit constants in SetKexiVersionInfo.cmake class QString; -#define KEXI_APP_NAME "Kexi" - /** * @def KEXI_VERSION_STRING * @ingroup KexiMacros -* @brief Version of Kexi as string, at compile time +* @brief Version of KEXI as string, at compile time * -* This macro contains the Kexi version in string form. As it is a macro, +* This macro contains the KEXI version in string form. As it is a macro, * it contains the version at compile time. See Kexi::versionString() if you need * a version used at runtime. * * @note The version string might contain spaces and special characters, -* especially for development versions of Kexi. +* especially for development versions of KEXI. * If you use that macro directly for a file format (e.g. OASIS Open Document) * or for a protocol (e.g. http) be careful that it is appropriate. * (Fictional) example: "3.0 Alpha" */ #define KEXI_VERSION_STRING "@PROJECT_VERSION_STRING@" /** * @def KEXI_VERSION_MAJOR_MINOR_RELEASE * @ingroup KexiMacros * @brief Version string containing "major.minor.release" -* @brief Version of Kexi as string, at compile time +* @brief Version of KEXI as string, at compile time * -* This macro contains the Kexi version in string form. As it is a macro, +* This macro contains the KEXI version in string form. As it is a macro, * it contains the version at compile time. * * @note The version string never contains spaces or special characters. */ #define KEXI_VERSION_MAJOR_MINOR_RELEASE "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_RELEASE@" /** * @def KEXI_STABLE_VERSION_MAJOR * @ingroup KexiMacros - * @brief Major version of stable Kexi, at compile time + * @brief Major version of stable KEXI, at compile time * KEXI_VERSION_MAJOR is computed based on this value. */ #define KEXI_STABLE_VERSION_MAJOR @PROJECT_STABLE_VERSION_MAJOR@ /** * @def KEXI_VERSION_MAJOR * @ingroup KexiMacros - * @brief Major version of Kexi, at compile time + * @brief Major version of KEXI, at compile time * * Generally it's the same as KEXI_STABLE_VERSION_MAJOR but for unstable x.0 * x is decreased by one, e.g. 3.0 Beta is 2.99. */ #define KEXI_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ /** * @def KEXI_STABLE_VERSION_MINOR * @ingroup KexiMacros - * @brief Minor version of stable Kexi, at compile time + * @brief Minor version of stable KEXI, at compile time * KEXI_VERSION_MINOR is computed based on this value. */ #define KEXI_STABLE_VERSION_MINOR @PROJECT_STABLE_VERSION_MINOR@ /** * @def KEXI_VERSION_MINOR * @ingroup KexiMacros - * @brief Minor version of Kexi, at compile time + * @brief Minor version of KEXI, at compile time * * Generally it's equal to KEXI_STABLE_VERSION_MINOR for stable releases, * equal to 99 for x.0 unstable releases (e.g. it's 3.0 Beta has minor version 99), * and equal to KEXI_STABLE_VERSION_MINOR-1 for unstable releases other than x.0. */ #define KEXI_VERSION_MINOR @PROJECT_VERSION_MINOR@ /** * @def KEXI_VERSION_RELEASE * @ingroup KexiMacros - * @brief Release version of Kexi, at compile time. + * @brief Release version of KEXI, at compile time. * 89 for Alpha. */ #define KEXI_VERSION_RELEASE @PROJECT_VERSION_RELEASE@ /** * @def KEXI_STABLE_VERSION_RELEASE * @ingroup KexiMacros - * @brief Release version of Kexi, at compile time. + * @brief Release version of KEXI, at compile time. * * Equal to KEXI_VERSION_RELEASE for stable releases and 0 for unstable ones. */ #define KEXI_STABLE_VERSION_RELEASE @PROJECT_STABLE_VERSION_RELEASE@ /** * @def KEXI_ALPHA * @ingroup KexiMacros - * @brief If defined (1..9), indicates at compile time that Kexi is in alpha stage + * @brief If defined (1..9), indicates at compile time that KEXI is in alpha stage */ #cmakedefine KEXI_ALPHA @KEXI_ALPHA@ /** * @def KEXI_BETA * @ingroup KexiMacros - * @brief If defined (1..9), indicates at compile time that Kexi is in beta stage + * @brief If defined (1..9), indicates at compile time that KEXI is in beta stage */ #cmakedefine KEXI_BETA @KEXI_BETA@ /** * @def KEXI_RC * @ingroup KexiMacros - * @brief If defined (1..9), indicates at compile time that Kexi is in "release candidate" stage + * @brief If defined (1..9), indicates at compile time that KEXI is in "release candidate" stage */ #cmakedefine KEXI_RC @KEXI_RC@ /** * @def KEXI_STABLE * @ingroup KexiMacros - * @brief If defined, indicates at compile time that Kexi is in stable stage + * @brief If defined, indicates at compile time that KEXI is in stable stage */ #cmakedefine KEXI_STABLE @KEXI_STABLE@ /** * @ingroup KexiMacros - * @brief Make a number from the major, minor and release number of a Kexi version + * @brief Make a number from the major, minor and release number of a KEXI version * * This function can be used for preprocessing when KEXI_IS_VERSION is not * appropriate. */ #define KEXI_MAKE_VERSION( a,b,c ) (((a) << 16) | ((b) << 8) | (c)) /** * @ingroup KexiMacros - * @brief Version of Kexi as number, at compile time + * @brief Version of KEXI as number, at compile time * - * This macro contains the Kexi version in number form. As it is a macro, + * This macro contains the KEXI version in number form. As it is a macro, * it contains the version at compile time. See version() if you need - * the Kexi version used at runtime. + * the KEXI version used at runtime. */ #define KEXI_VERSION \ KEXI_MAKE_VERSION(KEXI_VERSION_MAJOR,KEXI_VERSION_MINOR,KEXI_VERSION_RELEASE) /** * @ingroup KexiMacros - * @brief Check if the Kexi version matches a certain version or is higher + * @brief Check if the KEXI version matches a certain version or is higher * * This macro is typically used to compile conditionally a part of code: * @code * #if KEXI_IS_VERSION(2,3,0) - * // Code for Kexi 2.3.0 + * // Code for KEXI 2.3.0 * #else - * // Code for older Kexi + * // Code for older KEXI * #endif * @endcode * - * @warning Especially during development phases of Kexi, be careful + * @warning Especially during development phases of KEXI, be careful * when choosing the version number that you are checking against. - * Otherwise you might risk to break the next Kexi release. + * Otherwise you might risk to break the next KEXI release. * Therefore be careful that development version have a * version number lower than the released version, so do not check - * e.g. for Kexi 4.3 with KEXI_IS_VERSION(4,3,0) + * e.g. for KEXI 4.3 with KEXI_IS_VERSION(4,3,0) * but with the actual version number at a time a needed feature was introduced, e.g. 4.3.2. */ #define KEXI_IS_VERSION(a,b,c) ( KEXI_VERSION >= KEXI_MAKE_VERSION(a,b,c) ) /** * @def KEXI_YEAR * @ingroup KexiMacros - * @brief Year of the Kexi release, set at compile time + * @brief Year of the KEXI release, set at compile time * * This macro is used in "About application" dialog for strings such as "© 2012-..., The Author Team". */ #cmakedefine KEXI_YEAR "@KEXI_YEAR@" /** * @def KEXI_GIT_SHA1_STRING * @ingroup KexiMacros - * @brief Indicates the git sha1 commit which was used for compilation of Kexi + * @brief Indicates the git sha1 commit which was used for compilation of KEXI */ #cmakedefine KEXI_GIT_SHA1_STRING "@KEXI_GIT_SHA1_STRING@" /** * @def KEXI_GIT_BRANCH_STRING * @ingroup KexiMacros - * @brief Indicates the git branch name which was used for compilation of Kexi + * @brief Indicates the git branch name which was used for compilation of KEXI */ #cmakedefine KEXI_GIT_BRANCH_STRING "@KEXI_GIT_BRANCH_STRING@" /** * @def KEXI_DISTRIBUTION_VERSION * @ingroup KexiMacros - * @brief Name of Kexi version useful to construct co-installabile releases + * @brief Name of KEXI version useful to construct co-installabile releases * By default is it equal to KEXI_STABLE_VERSION_MAJOR.KEXI_STABLE_VERSION_MINOR. * It can be changed at configure stage by setting the KEXI_CUSTOM_DISTRIBUTION_VERSION * CMake variable. * @see KEXI_BASE_PATH */ #cmakedefine KEXI_DISTRIBUTION_VERSION "@KEXI_DISTRIBUTION_VERSION@" /** * @def KEXI_BASE_PATH * @ingroup KexiMacros * @brief Relative path name useful to construct co-installabile file names and paths * It is equal to "kexi/N" where N is KEXI_DISTRIBUTION_VERSION. */ #cmakedefine KEXI_BASE_PATH "@KEXI_BASE_PATH@" /** - * Namespace for general Kexi functions. + * Namespace for general KEXI functions. */ namespace Kexi { /** - * Returns the encoded number of Kexi's version, see the KEXI_VERSION macro. + * Returns the encoded number of KEXI version, see the KEXI_VERSION macro. * In contrary to that macro this function returns the number of the actually - * installed Kexi version, not the number of the Kexi version that was + * installed KEXI version, not the number of the KEXI version that was * installed when the program was compiled. * @return the version number, encoded in a single int */ KEXICORE_EXPORT unsigned int version(); /** - * Returns the major number of Kexi's version, e.g. - * 1 for Kexi 1.2.3. + * Returns the major number of KEXI version, e.g. + * 1 for KEXI 1.2.3. * @return the major version number */ KEXICORE_EXPORT unsigned int versionMajor(); /** - * Returns the minor number of Kexi's version, e.g. - * 2 for Kexi 1.2.3. + * Returns the minor number of KEXI version, e.g. + * 2 for KEXI 1.2.3. * @return the minor version number */ KEXICORE_EXPORT unsigned int versionMinor(); /** - * Returns the release of Kexi's version, e.g. - * 3 for Kexi 1.2.3. + * Returns the release of KEXI version, e.g. + * 3 for KEXI 1.2.3. * @return the release number */ KEXICORE_EXPORT unsigned int versionRelease(); /** - * Returns the Kexi version as string, e.g. "1.2.3" + * Returns the KEXI version as string, e.g. "1.2.3" * Sometimes it may be even something like "1.2.3 beta 2" - * @return the Kexi version. You can keep the string forever + * @return the KEXI version. You can keep the string forever */ KEXICORE_EXPORT const char *versionString(); /** - * @return the Kexi version string (versionString()) but appends extra information + * @return the KEXI version string (versionString()) but appends extra information * such as "(git 4e06281 master)" if available. */ KEXICORE_EXPORT const char *fullVersionString(); /** - * Returns the encoded number of stable Kexi's version. + * Returns the encoded number of stable KEXI version. * For 2.3.1 it returns 2.3.1, for 2.5.70 returns 2.6.0, for 2.9.70 returns 3.0.0. * In contrary to KEXI_STABLE_VERSION macro this function returns the number - * of the actually installed Kexi version, not the number of the Kexi version that was + * of the actually installed KEXI version, not the number of the KEXI version that was * installed when the program was compiled. * @return the version number, encoded in a single int * @see Kexi::version() * @see KEXI_STABLE_VERSION */ KEXICORE_EXPORT unsigned int stableVersion(); /** - * Returns the major number of stable Kexi's version, e.g. - * 1 for Kexi 1.2.3. + * Returns the major number of stable KEXI version, e.g. + * 1 for KEXI 1.2.3. * @return the major stable version number */ KEXICORE_EXPORT unsigned int stableVersionMajor(); /** - * Returns the minor number of stable Kexi's version, e.g. - * 2 for Kexi 1.2.3. + * Returns the minor number of stable KEXI version, e.g. + * 2 for KEXI 1.2.3. * @return the minor stable version number */ KEXICORE_EXPORT unsigned int stableVersionMinor(); /** - * Returns the release of stable Kexi's version, e.g. - * 3 for Kexi 1.2.3. + * Returns the release of stable KEXI version, e.g. + * 3 for KEXI 1.2.3. * @return the release stable version number */ KEXICORE_EXPORT unsigned int stableVersionRelease(); /** - * Returns the stable Kexi version as string, e.g. "1.2.3" + * Returns the stable KEXI version as string, e.g. "1.2.3" * It never contains alpha, beta or rc part. - * @return the stable Kexi version. + * @return the stable KEXI version. */ KEXICORE_EXPORT QString stableVersionString(); } #endif diff --git a/src/config-kexi.h.cmake b/src/config-kexi.h.cmake index 9367860bb..072a610af 100644 --- a/src/config-kexi.h.cmake +++ b/src/config-kexi.h.cmake @@ -1,140 +1,140 @@ /* 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) + Global KEXI configuration (build time) */ #include //! @def KEXI_DESKTOP -//! @brief If defined, a desktop version of Kexi is compiled +//! @brief If defined, a desktop version of KEXI is compiled #cmakedefine KEXI_DESKTOP //! @def KEXI_MOBILE -//! @brief If defined, a mobile version of Kexi is 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 COMPILING_EXAMPLES //! @brief if defined, examples are enabled and installed #cmakedefine COMPILING_EXAMPLES //! @def KEXI_DEBUG_GUI -//! @brief If defined, a debugging GUI for Kexi is enabled +//! @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 +//! @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 +//! @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. +//! @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 +//! @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 +//! @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 +//! @brief If defined, tabs in the main tabbed toolbar autorise in KEXI #cmakedefine KEXI_AUTORISE_TABBED_TOOLBAR //! @def KEXI_USE_KFILEWIDGET -//! @brief If defined, KFileWidget-based inline file browser is used in Kexi. Otherwise a simple +//! @brief If defined, KFileWidget-based inline file browser is used in KEXI. Otherwise a simple //! replacement file widget with native file dialogs is used. ON by default on UNIX, OFF by default //! on Windows and macOS. //! @note Non-plasma Linux desktops still default to the simple replacement at runtime. #cmakedefine KEXI_USE_KFILEWIDGET //! @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 +//! @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/core/KexiCommandLineOptions.cpp b/src/core/KexiCommandLineOptions.cpp index bc4e0f4ab..ae5dc7996 100644 --- a/src/core/KexiCommandLineOptions.cpp +++ b/src/core/KexiCommandLineOptions.cpp @@ -1,201 +1,201 @@ /* This file is part of the KDE project Copyright (C) 2002, 2003 Lucijan Busch Copyright (C) 2002, 2003 Joseph Wenninger Copyright (C) 2003-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. */ #include "KexiCommandLineOptions.h" #include "config-kexi.h" #include #include #include #include #include KexiCommandLineOptions::KexiCommandLineOptions( QCommandLineParser *parser) // NOTE: REMEMBER TO ADD NEW OPTIONS IN KexiStartupData::parseOptions() // Options related to entire projects: : createDb("createdb", xi18nc("'createdb' command line option", "Create a new, blank project using specified database driver and database " "name and exit immediately. You will be asked for confirmation if " "overwriting is needed.")), createAndOpenDb("create-opendb", xi18nc("'create-opendb' command line option", "Like --createdb, but also open newly created database.")), dropDb("dropdb", xi18nc("'dropdb' command line option", "Drop (remove) a project using specified database driver and database name. " "You will be asked for confirmation.")), dbDriver(QStringList() << "drv" << "dbdriver", xi18nc("'dbdriver' command line option", "Name of a database driver to be used when connecting to a database project " "(\"sqlite\" by default). Ignored if a shortcut filename is provided. " "Complete KDb-specific globally unique identifier can be used, " "e.g. \"org.kde.kdb.sqlite\" to specify exact vendor of the driver."), "name_or_id"), fileType(QStringList() << "t" << "type", xi18nc("'type' command line option", "Specify the type of file provided as an argument. This option is only " "useful if the filename does not have a valid extension set and its type " "cannot be determined unambiguously by examining its contents. This option " "is ignored if no file is specified as an argument.\n" "Available file types are:\n" "- \"project\" for a project file (the default)\n" "- \"shortcut\" for a shortcut file pointing to a\n" " project.\n" "- \"connection\" for database connection data."), "name"), connectionShortcut(QStringList() << "conn" << "connection", xi18nc("'connection' command line option", "Specify a database connection shortcut .kexic file containing connection data. " "Can be used with --createdb or --create-opendb for convenience instead " "of using options such as --user, --host or --port.\n" "Note: Options like --user, --host have precedence over settings defined " "in the shortcut file."), "shortcut_filename"), readOnly("readonly", xi18nc("'readonly' command line option", "Specify that any database connections will be performed without write support. " "This option is ignored when \"createdb\" option is present, otherwise the " "database could not be created.")), userMode("user-mode", xi18nc("'user-mode' command line option", "Start project in User Mode, regardless of the project settings.")), designMode("design-mode", xi18nc("'design-mode' command line option", "Start project in Design Mode, regardless of the project settings.")), showNavigator("show-navigator", xi18nc("'show-navigator' command line option", - "Show the Project Navigator side pane even if Kexi runs in User Mode.")), + "Show the Project Navigator side pane even if KEXI runs in User Mode.")), hideMenu("hide-menu", xi18nc("'hide-menu' command line option", "Hide the main menu (the tabbed toolbar) completely. A number of commands " "from the main menu is still visible. This option is useful in User Mode.")), // Options related to opening objects within a project: open("open", xi18nc("'open' command line option", "Open object of type 'object_type' and name 'object_name' from specified " "project on application start. 'object_type' is optional, if omitted - %1 " "type is assumed. Other object types can be %2, %3, %4, %5. " - "There may by more or less types available depending on Kexi plugins " + "There may by more or less types available depending on KEXI plugins " "installed.\n" "Use \"\" characters to specify names containing spaces.\n" "Examples: --open MyTable, --open %2:\"My very big query\"", "table", "query", "form", "report", "script"), "[object_type:]object_name"), design("design", xi18nc("'design' command line option", "Like --open, but the object will be opened in Design Mode, if one is available."), "[object_type:]object_name"), editText("edittext", xi18nc("'edittext' command line option", "Like --open, but the object will be opened in Text Mode, if one is available."), "[object_type:]object_name"), execute(QStringList() << "execute" << "exec", xi18nc("'execute' command line option", "Start execution of object of type 'object_type' and name 'object_name' on " "application start. 'object_type' is optional, if omitted - %1 type is " "assumed. Object type can be also %2. There may by more or less types " - "available depending on Kexi plugins installed.\n" + "available depending on KEXI plugins installed.\n" "Use \"\" characters to specify names containing spaces.", "macro", "script"), "[object_type:]object_name"), newObject("new", xi18nc("'new' command line option", "Start design of a new object of type 'object_type'."), "object_type"), print("print", xi18nc("'print' command line option", "Open the Print dialog window for an object of type 'object_type' and " "name 'object_name' in the specified project when the application starts " "for quick printing of the object's data. 'object_type' is optional; " "if omitted, %1 type is assumed. Object type can also be %2.", "table", "query"), "[object_type:]object_name"), printPreview("print-preview", xi18nc("'print-preview' command line option", "Open the Print Preview window for an object of type 'object_type' and " "name 'object_name' in the specified project when the application starts " "to see preview of the object's data printout. 'object_type' is optional; " "if omitted, %1 type is assumed. Object type can also be %2.", "table", "query"), "[object_type:]object_name"), // Options related to database servers: user(QStringList() << "u" << "user", xi18nc("'user' command line option", "Database server's user name when connecting to a project. Ignored if the " "project is opened using a shortcut file. Default user name is the same " "as the current login (%1).", KUser().loginName())), //! @todo re-add '-h' as soon as KAboutData::setupCommandLine() stops forcibly call parser->addHelpOption() host(QStringList() /*<< "h"*/ << "host", xi18nc("'host' command line option", "Network server's (host) name to be used when connecting to a database " "project. Ignored if the project is opened using a shortcut file. Default " "host is the local computer."), "name"), port("port", xi18nc("'port' command line option", "Network server's port number to be used when connecting to a database " "project. Ignored if the project is opened using a shortcut file. " "Defaults depend on the used server type (e.g. %1, %2).", "MySQL", "PostgreSQL"), "number"), localSocket(QStringList() << "socket" << "local-socket", xi18nc("'local-socket' command line option", "Local computer's socket filename to be used when connecting to " "a database project. Ignored if the project is opened using a shortcut file. " "Defaults depend on the used server type (e.g. %1, %2).", "MySQL", "PostgreSQL"), "filename"), // Options related to the GUI: skipConnDialog("skip-conn-dialog", xi18nc("'skip-conn-dialog' command line option", "Skip displaying connection dialog window and connect directly. Available " "when opening .kexic or .kexis shortcut files.")), fullScreen(QStringList() << "f" << "fullscreen", xi18nc("'fullscreen' command line option", - "Start Kexi in full screen mode to occupy the whole screen area by hiding " + "Start KEXI in full screen mode to occupy the whole screen area by hiding " "window decorations such as title bars.")), - // Options that display configuration or state of Kexi installation. - // When used, Kexi immediately exits without showing the GUI even if other options + // Options that display configuration or state of KEXI installation. + // When used, KEXI immediately exits without showing the GUI even if other options // or arguments are present. listPlugins("list-plugins", xi18nc("'list-plugins' command line option", - "Displays list of plugins available for Kexi with their name, description, " + "Displays list of plugins available for KEXI with their name, description, " "version and filenames.")) { Q_UNUSED(parser); } QList KexiCommandLineOptions::autoopeningObjectsOptions() const { return {open, design, editText, execute, newObject #ifdef KEXI_QUICK_PRINTING_SUPPORT , print, printPreview #endif }; } diff --git a/src/core/KexiCommandLineOptions.h b/src/core/KexiCommandLineOptions.h index 60530fdf5..d8d5ae996 100644 --- a/src/core/KexiCommandLineOptions.h +++ b/src/core/KexiCommandLineOptions.h @@ -1,67 +1,67 @@ /* This file is part of the KDE project Copyright (C) 2002, 2003 Lucijan Busch Copyright (C) 2002, 2003 Joseph Wenninger Copyright (C) 2003-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 KEXICOMMANDLINEOPTIONS_H #define KEXICOMMANDLINEOPTIONS_H #include "kexicore_export.h" #include #include class QCommandLineParser; -//! Command line options for Kexi +//! Command line options for KEXI class KEXICORE_EXPORT KexiCommandLineOptions { public: explicit KexiCommandLineOptions(QCommandLineParser *parser); //! @return list of options related to "auto-opening objects" QList autoopeningObjectsOptions() const; QCommandLineOption createDb; QCommandLineOption createAndOpenDb; QCommandLineOption dropDb; QCommandLineOption dbDriver; QCommandLineOption fileType; QCommandLineOption connectionShortcut; QCommandLineOption readOnly; QCommandLineOption userMode; QCommandLineOption designMode; QCommandLineOption showNavigator; QCommandLineOption hideMenu; QCommandLineOption open; QCommandLineOption design; QCommandLineOption editText; QCommandLineOption execute; QCommandLineOption newObject; QCommandLineOption print; QCommandLineOption printPreview; QCommandLineOption user; QCommandLineOption host; QCommandLineOption port; QCommandLineOption localSocket; QCommandLineOption skipConnDialog; QCommandLineOption fullScreen; QCommandLineOption listPlugins; }; #endif diff --git a/src/core/KexiFileFilters.h b/src/core/KexiFileFilters.h index 9088c06eb..1530fb163 100644 --- a/src/core/KexiFileFilters.h +++ b/src/core/KexiFileFilters.h @@ -1,125 +1,125 @@ /* This file is part of the KDE project Copyright (C) 2003-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 KEXIFILEFILTERS_H #define KEXIFILEFILTERS_H #include "kexicore_export.h" #include class QMimeType; class QString; class QStringList; -//! A tool for handling file filters for Kexi +//! A tool for handling file filters for KEXI class KEXICORE_EXPORT KexiFileFilters { public: //! Filter mode enum Mode { Opening, //!< Opening opens existing database (or shortcut) CustomOpening, //!< Used for opening other files, like CSV SavingFileBasedDB, //!< Saving file-based database file CustomSavingFileBasedDB, //!< Used for saving other files, like CSV SavingServerBasedDB //!< Saving server-based (shortcut) file }; KexiFileFilters(); ~KexiFileFilters(); //! @return mode for the filer Mode mode() const; //! Sets mode for the filter void setMode(Mode mode); /*! Sets a default-filter, that is used when an empty filter is set. * By default, this is set to "All Supported Files" * @see defaultFilter */ void setDefaultFilter(const QString &filter); /** * @return the default filter, used when an empty filter is set. * @see setDefaultFilter */ QString defaultFilter() const; //! @return additional mime types QStringList additionalMimeTypes() const; //! Sets additional mime types, e.g. "text/x-csv" void setAdditionalMimeTypes(const QStringList &mimeTypes); //! @return excluded mime types QStringList excludedMimeTypes() const; //! Set excluded mime types void setExcludedMimeTypes(const QStringList &mimeTypes); //! @return glob patterns for all mime types for given mode //! Includes additional mime types and excludes miem types specified by excludedMimeTypes(). QStringList allGlobPatterns() const; //! @return mime types for this filter QList mimeTypes() const; //! @return mime types names for this filter QStringList mimeTypeNames() const; //! @return @c true if existing file is required //! This is true for Opening and CustomOpening modes. bool isExistingFileRequired() const; enum Format { QtFormat, //!< QFileDialog-compatible format, e.g. "Image files (*.png *.xpm *.jpg)", ";;" separators KDEFormat, //!< KDE-compatible format, e.g. "*.png *.xpm *.jpg|Image files (*.png *.xpm *.jpg)", "\\n" separators KUrlRequesterFormat //!< KUrlRequester-compatible format, e.g. "*.png *.xpm *.jpg|Image files", "\\n" separators }; static QString separator(KexiFileFilters::Format format); //! @return filters based on supplied parameters in given format QString toString(Format format) const; //! @return list of filters based on supplied parameters in given format QStringList toList(Format format) const; //! @return filter string in given format static QString toString(const QMimeType &mime, Format format); //! @overload QString toString(const QMimeType &mime, Format format); static QString toString(const QString& mimeName, Format format); //! @overload QString toString(const QMimeType &mime, Format format); static QString toString(const QStringList &patterns, const QString &comment, Format format); //! Static version of QString KexiFileFilters::toString(Format format) const static QString toString(const QStringList& mimeNames, Format format); //! Static version of QStringList toList(Format format) const static QStringList toList(const QStringList& mimeNames, Format format); private: class Private; Private * const d; }; #endif diff --git a/src/core/KexiMainWindowIface.h b/src/core/KexiMainWindowIface.h index 738b31594..1709e03da 100644 --- a/src/core/KexiMainWindowIface.h +++ b/src/core/KexiMainWindowIface.h @@ -1,293 +1,293 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2014 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 KEXIMAINWINDOWIFACE_H #define KEXIMAINWINDOWIFACE_H //#define KEXI_IMPL_WARNINGS #include #include #include #include "KexiMigrateManagerInterface.h" #include "kexisharedactionhost.h" #include "kexi.h" class KDbQuerySchema; class KexiWindow; class KexiProject; class KActionCollection; class KexiSearchableModel; class KexiUserFeedbackAgent; class KexiMigrateManagerInterface; namespace KexiPart { class Item; class Info; } class KToolBar; /** * @short Kexi's main window interface * This interface is implemented by KexiMainWindow class. * KexiMainWindow offers simple features what lowers cross-dependency (and also avoids * circular dependencies between Kexi modules). */ class KEXICORE_EXPORT KexiMainWindowIface : public KexiSharedActionHost { public: //! Used by printActionForItem() enum PrintActionType { PrintItem, PreviewItem, PageSetupForItem }; KexiMainWindowIface(); virtual ~KexiMainWindowIface(); //! \return KexiMainWindowImpl global singleton (if it is instantiated) static KexiMainWindowIface* global(); QWidget* thisWidget(); //! Project data of currently opened project or NULL if no project here yet. virtual KexiProject *project() = 0; //! @todo KEXI3 virtual KActionCollection* actionCollection() const = 0; virtual KActionCollection* actionCollection() const = 0; //! @todo KEXI3 virtual QWidget* focusWidget() const = 0; virtual QWidget* focusWidget() const = 0; /*! Registers window \a window for watching and adds it to the main window's stack. */ virtual void registerChild(KexiWindow *window) = 0; /*! \return a list of all actions defined by application. Not all of them are shared. Don't use plug these actions in your windows by hand but user methods from KexiView! */ virtual QList allActions() const = 0; /*! \return currently active window or 0 if there is no active window. */ virtual KexiWindow* currentWindow() const = 0; /*! Switches \a window to view \a mode. Activates the window if it is not the current window. */ virtual tristate switchToViewMode(KexiWindow& window, Kexi::ViewMode viewMode) = 0; /*! \return true if this window is in the User Mode. */ virtual bool userMode() const = 0; // Q_SIGNALS: //! Emitted to make sure the project can be close. //! Connect a slot here and set \a cancel to true to cancel the closing. virtual void acceptProjectClosingRequested(bool *cancel) = 0; //! Emitted before closing the project (and destroying all it's data members). //! You can do you cleanup of your structures here. virtual void beforeProjectClosing() = 0; //! Emitted after closing the project. virtual void projectClosed() = 0; // public Q_SLOTS: /*! Creates new object of type defined by \a info part info. \a openingCancelled is set to true if opening has been cancelled. \return true on success. */ virtual bool newObject(KexiPart::Info *info, bool *openingCancelled) = 0; //! Opens object pointed by \a item in a view \a viewMode virtual KexiWindow* openObject(KexiPart::Item *item, Kexi::ViewMode viewMode, bool *openingCancelled, QMap* staticObjectArgs = 0, QString* errorMessage = 0) = 0; //! For convenience virtual KexiWindow* openObject(const QString& mime, const QString& name, Kexi::ViewMode viewMode, bool *openingCancelled, QMap* staticObjectArgs = 0) = 0; /*! Closes the object for \a item. \return true on success (closing can be dealyed though), false on failure and cancelled if the object has "opening" job assigned. */ virtual tristate closeObject(KexiPart::Item* item) = 0; /*! Called to accept property butter editing. */ virtual void acceptPropertySetEditing() = 0; /*! Received information from active view that \a window has switched its property set, so property editor contents should be reloaded. If \a force is true, property editor's data is reloaded even if the currently pointed property set is the same as before. If \a preservePrevSelection is true and there was a property set set before call, previously selected item will be preselected in the editor (if found). */ virtual void propertySetSwitched(KexiWindow *window, bool force = false, bool preservePrevSelection = true, bool sortedProperties = false, const QByteArray& propertyToSelect = QByteArray()) = 0; //! Options used in saveObject() enum SaveObjectOption { DoNotAsk = 1, //!< Do not ask for confirmation of overwriting SaveObjectAs = 2 //!< Saving object with a new name }; Q_DECLARE_FLAGS(SaveObjectOptions, SaveObjectOption) /*! Saves window's \a window data. If window's data is never saved, user is asked for name and title, before saving (see getNewObjectInfo()). \return true on successul saving or false on error. If saving was cancelled by user, cancelled is returned. \a messageWhenAskingForName is a i18n'ed text that will be visible within name/caption dialog (see KexiNameDialog), which is popped up for never saved objects. Saving object with a new name is also supported here, to do so SaveObjectOption::SaveObjectAs should be added to @a options. */ virtual tristate saveObject(KexiWindow *window, const QString& messageWhenAskingForName = QString(), SaveObjectOptions options = 0) = 0; /*! Closes window \a window. If window's data (see KexiWindow::isDirty()) is unsaved, used will be asked if saving should be perforemed. \return true on successull closing or false on closing error. If closing was cancelled by user, cancelled is returned. If \a window is 0, the current one will be closed. */ virtual tristate closeWindow(KexiWindow *window) = 0; /*! Find window for a given \a identifier. \return 0 if no windows found. */ virtual KexiWindow *openedWindowFor(int identifier) = 0; /*! Find window for a given \a item. \return 0 if no windows found. */ virtual KexiWindow *openedWindowFor(const KexiPart::Item* item) = 0; /*! Parametrs for query with given id. */ virtual QList currentParametersForQuery(int queryId) const = 0; //! \return query schema currently unsaved (edited) in a window corresponding to Kexi object identified by \a identifier. /*! For implementation in plugins, default implementation returns 0. * In implementations 0 should be returned if there is no such Kexi object * in the current project or if the object's window is not opened or if * the window contains no edited query at the moment. - * If the query is "unsaved" the window displaying the corresponding Kexi object is marked as "dirty". + * If the query is "unsaved" the window displaying the corresponding KEXI object is marked as "dirty". * Currently supported type of Kexi objects are only queries being in data view. * See KexiQueryPart::unsavedQuery(int) for this implementation. * The query schema returned by this method can be used for example by data * exporting routines so users can export result of running unsaved * query without prior saving its design. * The changes to design can be even discarded without consequences this way. @note Returned pointer leads to a temporary query schema object owned by the corresponding view, * so lifetime of the object is limited to the lifetime of the view and its window. * Do not store the pointer after the window is closed to avoid dangling pointers. \see KexiPart::Part::currentQuery(KexiView*) KexiWindow::isDirty() */ virtual KDbQuerySchema* unsavedQuery(int identifier) = 0; /*! Displays a dialog for entering object's name and title. Used on new object saving. \return true on successul closing or cancelled on cancel returned. It's unlikely to have false returned here. \a messageWhenAskingForName is a i18n'ed text that will be visible within name/caption dialog (see KexiNameDialog). If \a allowOverwriting is true, user will be asked for existing object's overwriting, else it will be impossible to enter a name of existing object. You can check \a overwriteNeeded after calling this method. If it's true, user agreed on overwriting, if it's false, user picked nonexisting name, so no overwrite will be needed. If \a originalName is not empty, the dialog will make sure the entered name is different, what is useful for "Saving As" objects. */ virtual tristate getNewObjectInfo(KexiPart::Item *partItem, const QString &originalName, KexiPart::Part *part, bool allowOverwriting, bool *overwriteNeeded, const QString& messageWhenAskingForName = QString()) = 0; /*! Highlights object of mime \a mime and name \a name. This can be done in the Project Navigator or so. If a window for the object is opened (in any mode), it should be raised. */ virtual void highlightObject(const QString& mime, const QString& name) = 0; //! Shows "print" dialog for \a item. //! \return true on success. virtual tristate printItem(KexiPart::Item* item) = 0; //! Shows "print preview" window. //! \return true on success. virtual tristate printPreviewForItem(KexiPart::Item* item) = 0; //! Shows "page setup" window for \a item. //! \return true on success and cancelled when the action was cancelled. virtual tristate showPageSetupForItem(KexiPart::Item* item) = 0; /*! Executes custom action for the main window, usually provided by a plugin. Also used by KexiFormEventAction. */ virtual tristate executeCustomActionForObject(KexiPart::Item* item, const QString& actionName) = 0; //! @todo temporary solution before the tabbed toolbar framework emerges /*! Appends widget @a widget to tabbed toolbar declared as @a name. @a widget will be reparented but the ownership is not taken. */ virtual void appendWidgetToToolbar(const QString& name, QWidget* widget) = 0; //! @todo temporary solution before the tabbed toolbar framework emerges /*! Shows or hides widget in the tabbed toolbar. */ virtual void setWidgetVisibleInToolbar(QWidget* widget, bool visible) = 0; //! @todo replace with the final Actions API virtual void addToolBarAction(const QString& toolBarName, QAction *action) = 0; //! @todo replace with the final Actions API virtual KToolBar *toolBar(const QString& name) const = 0; /*! Updates info label of the property editor by reusing properties provided by the current property set. Read documentation of KexiPropertyEditorView class for information about accepted properties. If the current property is 0 and @a textToDisplayForNullSet string is not empty, this string is displayed (without icon or any other additional part). If the current property is 0 and @a textToDisplayForNullSet string is empty, the info label widget becomes hidden. */ virtual void updatePropertyEditorInfoLabel(const QString& textToDisplayForNullSet = QString()) = 0; /*! Add searchable model to the main window. This extends search to a new area. One example is Project Navigator. */ virtual void addSearchableModel(KexiSearchableModel *model) = 0; virtual KexiUserFeedbackAgent* userFeedbackAgent() const = 0; //! Interface to the migrate manager virtual KexiMigrateManagerInterface* migrateManager() = 0; //! Sets reasonable dialog size based on main window size, that is 80% of its size. virtual void setReasonableDialogSize(QDialog *dialog) = 0; protected: // Q_SLOTS: virtual void slotObjectRenamed(const KexiPart::Item &item, const QString& oldName) = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KexiMainWindowIface::SaveObjectOptions) #endif diff --git a/src/core/kexi.cpp b/src/core/kexi.cpp index a8657734d..4609bad4e 100644 --- a/src/core/kexi.cpp +++ b/src/core/kexi.cpp @@ -1,419 +1,419 @@ /* This file is part of the KDE project Copyright (C) 2003-2012 Jarosław Staniek 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 "kexi.h" #include "KexiRecentProjects.h" #include "KexiMainWindowIface.h" #include "kexipartmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kexi; //! used for speedup //! @internal class KexiInternal { public: static KexiInternal *_int; KexiInternal() : connset(0) { } ~KexiInternal() { delete connset; } static KexiInternal* self() { static bool created = false; if (!created) { _int = new KexiInternal; created = true; } return _int; } static void destroy() { delete _int; _int = 0; } KexiDBConnectionSet* connset; KexiRecentProjects recentProjects; KexiDBConnectionSet recentConnections; KDbDriverManager driverManager; KexiPart::Manager partManager; }; KexiInternal *KexiInternal::_int = 0; KexiDBConnectionSet& Kexi::connset() { //delayed if (!KexiInternal::self()->connset) { //load stored set data, OK? KexiInternal::self()->connset = new KexiDBConnectionSet(); KexiInternal::self()->connset->load(); } return *KexiInternal::self()->connset; } KexiRecentProjects* Kexi::recentProjects() { return &KexiInternal::self()->recentProjects; } KDbDriverManager& Kexi::driverManager() { return KexiInternal::self()->driverManager; } KexiPart::Manager& Kexi::partManager() { return KexiInternal::self()->partManager; } void Kexi::deleteGlobalObjects() { KexiInternal::self()->destroy(); } //temp bool _tempShowMacros = true; bool& Kexi::tempShowMacros() { #ifndef KEXI_MACROS_SUPPORT _tempShowMacros = false; #endif return _tempShowMacros; } bool _tempShowScripts = true; bool& Kexi::tempShowScripts() { #ifndef KEXI_SCRIPTS_SUPPORT _tempShowScripts = false; #endif return _tempShowScripts; } //-------------------------------------------------------------------------------- QString Kexi::nameForViewMode(ViewMode mode, bool withAmpersand) { if (!withAmpersand) return Kexi::nameForViewMode(mode, true).remove('&'); if (mode == NoViewMode) return xi18n("&No View"); else if (mode == DataViewMode) return xi18n("&Data View"); else if (mode == DesignViewMode) return xi18n("D&esign View"); else if (mode == TextViewMode) return xi18n("&Text View"); return xi18n("&Unknown"); } //-------------------------------------------------------------------------------- QString Kexi::iconNameForViewMode(ViewMode mode) { const char *const id = (mode == DataViewMode) ? KexiIconNameCStr("data-view") : (mode == DesignViewMode) ? KexiIconNameCStr("design-view") : (mode == TextViewMode) ? KexiIconNameCStr("sql-view"): 0; return QLatin1String(id); } //-------------------------------------------------------------------------------- ObjectStatus::ObjectStatus() : m_resultable(0), m_msgHandler(0) { } ObjectStatus::ObjectStatus(const QString& message, const QString& description) : m_resultable(0), m_msgHandler(0) { setStatus(message, description); } ObjectStatus::ObjectStatus(const KDbResultable* resultable, const QString& message, const QString& description) : m_resultable(0), m_msgHandler(0) { setStatus(resultable, message, description); } ObjectStatus::~ObjectStatus() { delete m_msgHandler; } const ObjectStatus& ObjectStatus::status() const { return *this; } bool ObjectStatus::error() const { return !message.isEmpty() || (m_resultable && m_resultable->result().isError()); } void ObjectStatus::setStatus(const QString& message, const QString& description) { m_resultable = 0; this->message = message; this->description = description; } void ObjectStatus::setStatus(const KDbResultable* resultable, const QString& message, const QString& description) { m_resultable = resultable; this->message = message; this->description = description; } void ObjectStatus::setStatus(KDbResultInfo* resultInfo, const QString& message, const QString& description) { if (resultInfo) { if (message.isEmpty()) { this->message = resultInfo->message; } else { this->message = message + " " + resultInfo->message; } if (description.isEmpty()) { this->description = resultInfo->description; } else { this->description = description + " " + resultInfo->description; } } else { setStatus(message, description); } } void ObjectStatus::setStatus(const KDbResultable* resultable, KDbResultInfo* resultInfo, const QString& message, const QString& description) { if (!resultable) setStatus(resultInfo, message, description); else if (!resultInfo) setStatus(resultable, message, description); else { setStatus(resultable, message, description); setStatus(resultInfo, this->message, this->description); } } void ObjectStatus::setStatus(const KDbResult &result, KDbResultInfo* resultInfo, const QString& message, const QString& description) { //! @todo KEXI3 test this if (!result.isError()) { if (resultInfo) { setStatus(resultInfo, message, description); } else { setStatus(message, description); } } else { if (resultInfo) { KDbResult r = result; r.prependMessage(message); r.prependMessage(description); setStatus(resultInfo, r.messageTitle(), r.message()); } else { setStatus(message, description); } } } void ObjectStatus::clearStatus() { message.clear(); description.clear(); } QString ObjectStatus::singleStatusString() const { if (message.isEmpty() || description.isEmpty()) return message; return message + " " + description; } void ObjectStatus::append(const ObjectStatus& otherStatus) { if (message.isEmpty()) { message = otherStatus.message; description = otherStatus.description; return; } const QString s(otherStatus.singleStatusString()); if (s.isEmpty()) return; if (description.isEmpty()) { description = s; return; } description = description + " " + s; } //! @internal class ObjectStatusMessageHandler : public KDbMessageHandler { public: explicit ObjectStatusMessageHandler(ObjectStatus *status) : KDbMessageHandler() , m_status(status) { } virtual ~ObjectStatusMessageHandler() { } virtual void showErrorMessage(KDbMessageHandler::MessageType messageType, const QString &msg, const QString &details = QString(), const QString &caption = QString()) { Q_UNUSED(messageType); Q_UNUSED(caption); m_status->setStatus(msg, details); } virtual void showErrorMessage(const KDbResult& result, KDbMessageHandler::MessageType messageType = KDbMessageHandler::Error, const QString& msg = QString(), const QString& caption = QString()) { Q_UNUSED(messageType); m_status->setStatus(result, 0, caption, msg); } ObjectStatus *m_status; }; ObjectStatus::operator KDbMessageHandler*() { if (!m_msgHandler) m_msgHandler = new ObjectStatusMessageHandler(this); return m_msgHandler; } void KEXI_UNFINISHED_INTERNAL(const QString& feature_name, const QString& extra_text, QString* line1, QString* line2) { if (feature_name.isEmpty()) *line1 = xi18n("This function is not available for version %1 of %2 application.", - QString(KEXI_VERSION_STRING), QString(KEXI_APP_NAME)); + QString(KEXI_VERSION_STRING), QApplication::applicationDisplayName()); else { QString feature_name_(feature_name); *line1 = xi18nc("@info", "%1 function is not available for version %2 of %3 application.", - feature_name_.remove('&'), QString(KEXI_VERSION_STRING), QString(KEXI_APP_NAME)); + feature_name_.remove('&'), QString(KEXI_VERSION_STRING), QApplication::applicationDisplayName()); } *line2 = extra_text; } void KEXI_UNFINISHED(const QString& feature_name, const QString& extra_text) { QString line1, line2; KEXI_UNFINISHED_INTERNAL(feature_name, extra_text, &line1, &line2); if (!line2.isEmpty()) line2.prepend("\n"); KMessageBox::sorry(0, line1 + line2); } QLabel *KEXI_UNFINISHED_LABEL(const QString& feature_name, const QString& extra_text) { QString line1, line2; KEXI_UNFINISHED_INTERNAL(feature_name, extra_text, &line1, &line2); QLabel *label = new QLabel(QLatin1String("") + line1 + QLatin1String("
") + line2); label->setAlignment(Qt::AlignCenter); label->setWordWrap(true); label->setAutoFillBackground(true); label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); return label; } //-------------------------------------------------------------------------------- QString Kexi::defaultFileBasedDriverIconName() { return KexiIconName("file-database"); } QIcon Kexi::defaultFileBasedDriverIcon() { return QIcon::fromTheme(defaultFileBasedDriverIconName()); } QString Kexi::serverIconName() { return KexiIconName("network-server-database"); } QIcon Kexi::serverIcon() { return QIcon::fromTheme(serverIconName()); } QString Kexi::appIncorrectlyInstalledMessage() { return xi18nc("@info", "%1 could have been incorrectly " "installed or started. The application will be closed.", QApplication::applicationDisplayName()); } QString Kexi::basePathForProject(const KDbConnectionData& connectionData) { KDbDriverManager manager; const KDbDriverMetaData* driverMetaData = manager.driverMetaData(connectionData.driverId()); if (driverMetaData && driverMetaData->isFileBased()) { const QFileInfo fileinfo(connectionData.databaseName()); return fileinfo.path(); } return QString(); } bool Kexi::isKexiInstance() { return KAboutData::applicationData().componentName() == QLatin1String("kexi"); } diff --git a/src/core/kexi.h b/src/core/kexi.h index 191d38d72..869c8415e 100644 --- a/src/core/kexi.h +++ b/src/core/kexi.h @@ -1,192 +1,192 @@ /* This file is part of the KDE project Copyright (C) 2003-2012 Jarosław Staniek 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. */ #ifndef KEXI_H #define KEXI_H #include #include #include "kexiprojectdata.h" #include "kexidbconnectionset.h" #include "kexiprojectset.h" class QLabel; class KDbDriverManager; class KexiRecentProjects; namespace KexiPart { class Manager; } namespace Kexi { /*! Modes of view for the dialogs. Used mostly for parts and KexiWindow. */ enum ViewMode { AllViewModes = 0, //!< Usable primarily in KexiPart::initInstanceActions() NoViewMode = 0, //!< In KexiView::afterSwitchFrom() and KexiView::beforeSwitchTo() //!< means that parent dialog of the view has not been defined yet. DataViewMode = 1, DesignViewMode = 2, TextViewMode = 4 //!< Also known as SQL View Mode }; Q_DECLARE_FLAGS(ViewModes, ViewMode) /*! @return i18n'ed name of view mode @a mode. If @a withAmpersand is true, ampersands used for accelerators are included, e.g. "&Data View".*/ KEXICORE_EXPORT QString nameForViewMode(ViewMode mode, bool withAmpersand = false); /*! @return icon name of view mode @a mode. */ KEXICORE_EXPORT QString iconNameForViewMode(ViewMode mode); //! A set of known connections KEXICORE_EXPORT KexiDBConnectionSet& connset(); //! A set available of project information KEXICORE_EXPORT KexiRecentProjects* recentProjects(); //! shared driver manager KEXICORE_EXPORT KDbDriverManager& driverManager(); //! shared part manager KEXICORE_EXPORT KexiPart::Manager& partManager(); //! can be called to delete global objects like driverManager and partManager //! (and thus, all loaded factories/plugins) //! before KLibrary::~KLibrary() do this for us KEXICORE_EXPORT void deleteGlobalObjects(); //some temporary flags //! false by default, flag loaded on main window startup KEXICORE_EXPORT bool& tempShowMacros(); //! false by default, flag loaded on main window startup KEXICORE_EXPORT bool& tempShowScripts(); //! false by default, flag loaded on main window startup KEXICORE_EXPORT bool& tempShowScripts(); /*! Helper class for storing object status. */ class KEXICORE_EXPORT ObjectStatus { public: ObjectStatus(); ObjectStatus(const QString& message, const QString& description); ObjectStatus(const KDbResultable* resultable, const QString& message, const QString& description); ~ObjectStatus(); const ObjectStatus& status() const; bool error() const; void setStatus(const QString& message, const QString& description); //! Note: for safety, \a dbObject needs to be derived from QObject, //! otherwise it won't be assigned void setStatus(const KDbResultable* resultable, const QString& message = QString(), const QString& description = QString()); void setStatus(KDbResultInfo* resultInfo, const QString& message = QString(), const QString& description = QString()); void setStatus(const KDbResultable* resultable, KDbResultInfo* resultInfo, const QString& message = QString(), const QString& description = QString()); void setStatus(const KDbResult& result, KDbResultInfo* resultInfo, const QString& message = QString(), const QString& description = QString()); void clearStatus(); QString singleStatusString() const; void append(const ObjectStatus& otherStatus); const KDbResultable* resultable() const { return m_resultable; } //! Helper returning pseudo handler that just updates this ObjectStatus object //! by receiving a message operator KDbMessageHandler*(); QString message, description; protected: const KDbResultable* m_resultable; KDbMessageHandler* m_msgHandler; }; /*! \return icon name for default file-based driver (typically icon for something like "application/x-kexiproject-sqlite"). @see KDb::defaultFileBasedDriverMimeType() */ KEXICORE_EXPORT QString defaultFileBasedDriverIconName(); /*! \return icon for default file-based driver (typically icon for something like "application/x-kexiproject-sqlite"). If contains special workaround to properly load mimetype icon according to current theme, at least needed for Breeze. @see KDb::defaultFileBasedDriverIconName() */ KEXICORE_EXPORT QIcon defaultFileBasedDriverIcon(); /*! \return icon name for database servers. */ KEXICORE_EXPORT QString serverIconName(); /*! \return icon for database servers. */ KEXICORE_EXPORT QIcon serverIcon(); /*! @return message text "Kexi could have been incorrectly installed or started. The application will be closed." useful for critical errors. */ KEXICORE_EXPORT QString appIncorrectlyInstalledMessage(); //! @return base path (without the filename for file-based connection data @a connectionData. //! Empty string is returned if @a connectionData does not point to a file-based connection with //! database name specified. KEXICORE_EXPORT QString basePathForProject(const KDbConnectionData& connectionData); //! @return @c true if this is a Kexi app instance //! @c false is returned e.g. for test apps that are based on Kexi. //! This function is useful to decide if certain actions should be performed that only -//! belong to the "real" Kexi app, for example updating a list of recent documents +//! belong to the "real" KEXI app, for example updating a list of recent documents //! or collecting usage information. //! The check is performed by comparing component name of KAboutData to the string "kexi". KEXICORE_EXPORT bool isKexiInstance(); }//namespace Kexi Q_DECLARE_OPERATORS_FOR_FLAGS(Kexi::ViewModes) //! Displays information that feature "feature_name" is not availabe in the current application version KEXICORE_EXPORT void KEXI_UNFINISHED( const QString& feature_name, const QString& extra_text = QString()); //! Like KEXI_UNFINISHED but returns new label instance with expected text KEXICORE_EXPORT QLabel *KEXI_UNFINISHED_LABEL( const QString& feature_name, const QString& extra_text = QString()); //! Like above - for use inside KexiActionProxy subclass - reuses feature name from shared action's text #define KEXI_UNFINISHED_SHARED_ACTION(action_name) \ KEXI_UNFINISHED(sharedAction(action_name) ? sharedAction(action_name)->text() : QString()) //! Implementation of plugin's entry point #define KEXI_PLUGIN_FACTORY(class_name, name) \ K_PLUGIN_FACTORY_WITH_JSON(class_name ## Factory, name, registerPlugin();) #endif diff --git a/src/core/kexiaboutdata.cpp b/src/core/kexiaboutdata.cpp index 987bc6c09..c7f336b2e 100644 --- a/src/core/kexiaboutdata.cpp +++ b/src/core/kexiaboutdata.cpp @@ -1,119 +1,119 @@ /* This file is part of the KDE project Copyright (C) 2002, 2003 Lucijan Busch Copyright (C) 2002, 2003 Joseph Wenninger Copyright (C) 2003-2015 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. */ #include "kexiaboutdata.h" #include #include static const char description[] = I18N_NOOP("Visual database applications creator"); KexiAboutData::KexiAboutData() : KAboutData( "kexi", - KEXI_APP_NAME, + "KEXI", Kexi::fullVersionString(), xi18n(description), KAboutLicense::LGPL_V2, - xi18n("© 2002-%1, The Kexi Team", QLatin1String(KEXI_YEAR)), - xi18n("This software is developed by Kexi Team - an international group " + xi18n("© 2002-%1, The KEXI Team", QLatin1String(KEXI_YEAR)), + xi18n("This software is developed by KEXI Team - an international group " "of independent developers. They form a part of the Calligra Project."), "https://www.kexi-project.org", "submit@bugs.kde.org" ) { setOrganizationDomain("kde.org"); // right dbus prefix == org.kde. // authors sorted by last nontrivial contribution date * size addAuthor( xi18n("Jarosław Staniek"), xi18n("Project maintainer & developer, overall design"), "staniek@kde.org"); addAuthor( xi18n("OpenOffice Polska LLC"), xi18n("Sponsoring and support (employer of Jarosław Staniek in 2003-2007)"), "info@openoffice.com.pl"); addAuthor( xi18n("Adam Pigg"), xi18n("PostgreSQL database driver, Migration and Reporting modules, numerous bug fixes"), "adam@piggz.co.uk"); addAuthor( xi18n("Radosław Wicik"), xi18n("Map elements for forms and reports, map flake shape"), "radoslaw@wicik.pl"); addAuthor( xi18n("Wojciech Kosowicz"), xi18n("Features and bug fixes"), "pcellix@gmail.com"); addAuthor( xi18n("Roman Shtemberko"), xi18n("Features and bug fixes"), "shtemberko@gmail.com"); addAuthor( - xi18n("Dimitrios T. Tanis"), xi18n("Users Manual for Kexi 2, main window improvements, numerous bug reports"), "dimitrios.tanis@kdemail.net"); + xi18n("Dimitrios T. Tanis"), xi18n("Users Manual for KEXI 2, main window improvements, numerous bug reports"), "dimitrios.tanis@kdemail.net"); addAuthor( xi18n("Oleg Kukharchuk"), xi18n("Several form widgets, porting to Qt 4, stabilization"), "oleg.kuh@gmail.com"); addAuthor( xi18n("Shreya Pandit"), xi18n("Web elements for forms and reports"), "shreya.pandit25@gmail.com"); addAuthor( xi18n("Sebastian Sauer"), xi18n("Scripting module (KROSS), Python language bindings, design"), "mail@dipe.org"); addAuthor( xi18n("Lorenzo Villani"), xi18n("Web Forms module"), "lvillani@binaryhelix.net"); addAuthor( xi18n("Sharan Rao"), xi18n("Sybase/MS SQL Server/ODBC database drivers, xBase migration plugin, improvements for KexiDB"), "sharanrao@gmail.com"); addAuthor( xi18n("Cédric Pasteur"), xi18n("First version of Property Editor and Form Designer"), "cedric.pasteur@free.fr"); addAuthor( xi18n("Martin Ellis"), xi18n("Contributions for MySQL and KexiDB, fixes, Migration module, MS Access file format support"), "martin.ellis@kdemail.net"); addAuthor( xi18n("Julia Sanchez-Simon"), xi18n("Oracle database driver"), "hithwen@gmail.com"); addAuthor( xi18n("Christian Nitschkowski"), xi18n("Graphics effects, helper dialogs"), "segfault_ii@web.de"); addAuthor( xi18n("Matt Rogers"), xi18n("ODBC database driver"), "mattr@kde.org"); addAuthor( xi18n("Lucijan Busch"), xi18n("Former project maintainer & developer"), "lucijan@kde.org"); addAuthor( xi18n("Peter Simonsson"), xi18n("Former developer"), "psn@linux.se"); addAuthor( xi18n("Joseph Wenninger"), xi18n("Original Form Designer, original user interface & much more"), "jowenn@kde.org"); addAuthor( xi18n("Seth Kurzenberg"), xi18n("CQL++, SQL assistance"), "seth@cql.com"); addAuthor( xi18n("Laurent Montel"), xi18n("Original code cleanings"), "montel@kde.org"); addAuthor( xi18n("Till Busch"), xi18n("Bugfixes, original Table Widget"), "till@bux.at"); addCredit( xi18n("Ian Whitfield"), xi18n("Numerous bug reports and tests"), "whitfield@telkomsa.net"); addCredit( xi18n("Scarlett Gately Clark"), xi18n("AppImage packages for Linux"), "scarlett.gately.clark@gmail.com"); addCredit( xi18n("Ian Balchin"), xi18n("Numerous bug reports and tests, handbook improvements"), "inksi@fables.co.za"); addCredit( xi18n("Robert Leleu"), xi18n("Numerous bug reports and tests"), "robert.jean.leleu@wanadoo.fr"); addCredit( xi18n("Friedrich W. H. Kossebau"), xi18n("Bug fixes, build system improvements, code cleanups"), "kossebau@kde.org"); addCredit( xi18n("Boudewijn Rempt"), xi18n("Code cleanups"), "boud@valdyas.org"); addCredit( xi18n("David Faure"), xi18n("Code cleanups"), "faure@kde.org"); addCredit( xi18n("Daniel Molkentin"), xi18n("Initial design improvements"), "molkentin@kde.org"); addCredit( xi18n("Kristof Borrey"), xi18n("Icons and user interface research"), "kristof.borrey@skynet.be"); addCredit( xi18n("Tomas Krassnig"), xi18n("Coffee sponsoring"), "tkrass05@hak1.at"); addCredit( xi18n("Paweł Wirecki / OpenOffice Polska"), xi18n("Numerous bug reports, usability tests, technical support")); setTranslator( xi18nc("NAME OF TRANSLATORS", "Your names"), xi18nc("EMAIL OF TRANSLATORS", "Your emails")); } diff --git a/src/core/kexipartmanager.cpp b/src/core/kexipartmanager.cpp index d73a5e3e7..4412b11c8 100644 --- a/src/core/kexipartmanager.cpp +++ b/src/core/kexipartmanager.cpp @@ -1,319 +1,326 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-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. */ #include "kexipartmanager.h" #include "kexipart.h" #include "kexiinternalpart.h" #include "kexipartinfo.h" //! @todo KEXI3 #include "kexistaticpart.h" #include "KexiVersion.h" #include "KexiJsonTrader.h" #include #include #include #include #include #include #include #include #include using namespace KexiPart; typedef QHash KexiInternalPartDict; Q_GLOBAL_STATIC_WITH_ARGS(KexiJsonTrader, KexiPartTrader_instance, (KEXI_BASE_PATH)) class Q_DECL_HIDDEN Manager::Private { public: explicit Private(Manager *manager_); ~Private(); Manager *manager; PartDict parts; KexiInternalPartDict internalParts; PartInfoList partlist; PartInfoDict partsByPluginId; bool lookupDone; bool lookupResult; }; Manager::Private::Private(Manager *manager_) : manager(manager_) , lookupDone(false) , lookupResult(false) { } Manager::Private::~Private() { qDeleteAll(partlist); partlist.clear(); } //--- Manager::Manager(QObject *parent) : QObject(parent), KDbResultable(), d(new Private(this)) { } Manager::~Manager() { delete d; } template PartClass* Manager::part(Info *info, QHash *partDict) { if (!info) { return 0; } clearResult(); KDbMessageGuard mg(this); if (!lookup()) { return 0; } if (!info->isValid()) { m_result = KDbResult(info->errorMessage()); return 0; } PartClass *p = partDict->value(info->pluginId()); if (p) { return p; } // actual loading KPluginFactory *factory = qobject_cast(info->instantiate()); if (!factory) { m_result = KDbResult(ERR_CANNOT_LOAD_OBJECT, - xi18nc("@info", "Could not load Kexi plugin file %1.", - info->fileName())); + xi18nc("@info", "Could not load plugin file %1 " + "for %2.", + info->fileName(), QApplication::applicationDisplayName())); QPluginLoader loader(info->fileName()); // use this to get the message (void)loader.load(); m_result.setServerMessage(loader.errorString()); info->setErrorMessage(m_result.message()); qWarning() << m_result.message() << m_result.serverMessage(); return 0; } p = factory->create(this); if (!p) { - m_result = KDbResult(ERR_CANNOT_LOAD_OBJECT, - xi18nc("@info", - "Could not open Kexi plugin %1.").arg(info->fileName())); + m_result = KDbResult( + ERR_CANNOT_LOAD_OBJECT, + xi18nc( + "@info", + "Could not open plugin %1 for %2.", + info->fileName(), QApplication::applicationDisplayName())); qWarning() << m_result.message(); return 0; } p->setInfo(info); p->setObjectName(QString("%1 plugin").arg(info->id())); partDict->insert(info->pluginId(), p); return p; } //! @return a string list @a list with removed whitespace from the beginning and end of each string. //! Empty strings are also removed. static QStringList cleanupStringList(const QStringList &list) { QStringList result; foreach(const QString &item, list) { QString cleanedItem = item.trimmed(); if (!cleanedItem.isEmpty()) { result.append(cleanedItem); } } return result; } bool Manager::lookup() { if (d->lookupDone) { return d->lookupResult; } d->lookupDone = true; d->lookupResult = false; d->partlist.clear(); d->partsByPluginId.clear(); d->parts.clear(); // load visual order of plugins KConfigGroup cg(KSharedConfig::openConfig()->group("Parts")); const QStringList orderedPluginIds = cleanupStringList( cg.readEntry("Order", "org.kexi-project.table," "org.kexi-project.query," "org.kexi-project.form," "org.kexi-project.report," "org.kexi-project.macro," "org.kexi-project.script").split(',')); QVector orderedInfos(orderedPluginIds.count()); QStringList serviceTypes; serviceTypes << "Kexi/Viewer" << "Kexi/Designer" << "Kexi/Editor" << "Kexi/Internal"; QList offers = KexiPartTrader_instance->query(serviceTypes); foreach(const QPluginLoader *loader, offers) { QScopedPointer info(new Info(*loader)); if (info->id().isEmpty()) { qWarning() << "No plugin ID specified for Kexi Part" << info->fileName() << "-- skipping!"; continue; } // check version const QString expectedVersion = KexiPart::version(); if (info->version() != expectedVersion) { qWarning() << "Kexi plugin" << info->id() << info->fileName() << "has version" << info->version() << "but version required by Kexi is" << expectedVersion << "-- skipping this plugin!"; continue; } // skip experimental types if ( (!Kexi::tempShowMacros() && info->id() == "org.kexi-project.macro") || (!Kexi::tempShowScripts() && info->id() == "org.kexi-project.script") ) { continue; } // skip duplicates if (d->partsByPluginId.contains(info->id())) { qWarning() << "More than one Kexi plugin with ID" << info->id() << info->fileName() << "-- skipping this one"; continue; } // find correct place for plugins visible in Navigator if (info->isVisibleInNavigator()) { const int index = orderedPluginIds.indexOf(info->id()); if (index != -1) { orderedInfos[index] = info.data(); } else { orderedInfos.append(info.data()); } // append later when we know order } else { // append now d->partlist.append(info.data()); } d->partsByPluginId.insert(info->pluginId(), info.data()); info.take(); } qDeleteAll(offers); offers.clear(); if (d->partsByPluginId.isEmpty()) { - m_result = KDbResult( - xi18nc("@info", "Could not find any Kexi plugins, e.g. for tables or forms. " - "Kexi would not be functional so it will exit." - "Please check if Kexi is properly installed.")); + m_result = KDbResult(xi18nc( + "@info", "Could not find any plugins for %1, e.g. for " + "tables or forms. " + "%1 would not be functional so it will exit." + "Please check if %2 is properly " + "installed.", + QApplication::applicationDisplayName())); return false; } // fill the final list using computed order for (int i = 0; i < orderedInfos.size(); i++) { Info *info = orderedInfos[i]; if (!info) { continue; } //qDebug() << "adding Kexi part info" << info->pluginId(); d->partlist.insert(i, info); } // now the d->partlist is: [ordered plugins visible in Navigator] [other plugins in unspecified order] d->lookupResult = true; return true; } Part* Manager::part(Info *info) { KDbMessageGuard mg(this); Part *p = part(info, &d->parts); if (p) { emit partLoaded(p); } return p; } static QString realPluginId(const QString &pluginId) { if (pluginId.contains('.')) { return pluginId; } else { // not like "org.kexi-project.table" - construct return QString::fromLatin1("org.kexi-project.") + QString(pluginId).remove("kexi/"); } } Part* Manager::partForPluginId(const QString &pluginId) { Info* info = infoForPluginId(pluginId); return part(info); } Info* Manager::infoForPluginId(const QString &pluginId) { KDbMessageGuard mg(this); if (!lookup()) return 0; const QString realId = realPluginId(pluginId); Info *i = realId.isEmpty() ? 0 : d->partsByPluginId.value(realId); if (i) return i; m_result = KDbResult(kxi18nc("@info", "No plugin for ID %1") .subs(realId) .toString(Kuit::VisualFormat::PlainText)); return 0; } /*! @todo KEXI3 void Manager::insertStaticPart(StaticPart* part) { if (!part) return; KDbMessageGuard mg(this); if (!lookup()) return; d->partlist.append(part->info()); if (!part->info()->pluginId().isEmpty()) d->partsByPluginId.insert(part->info()->pluginId(), part->info()); d->parts.insert(part->info()->pluginId(), part); } */ KexiInternalPart* Manager::internalPartForPluginId(const QString& pluginId) { Info* info = infoForPluginId(pluginId); if (!info || !info->serviceTypes().contains("Kexi/Internal")) { return nullptr; } return part(info, &d->internalParts); } PartInfoList* Manager::infoList() { KDbMessageGuard mg(this); if (!lookup()) { return 0; } return &d->partlist; } diff --git a/src/core/kexiproject.h b/src/core/kexiproject.h index a360a4095..d63801f61 100644 --- a/src/core/kexiproject.h +++ b/src/core/kexiproject.h @@ -1,400 +1,400 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2012 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 KEXIPROJECT_H #define KEXIPROJECT_H #include #include #include #include #include "kexiprojectdata.h" #include "kexipartitem.h" #include "kexi.h" /*! KexiProject implementation version. It is altered after every change: - major number is increased after KexiProject storage format change, - minor is increased after adding binary-incompatible change. Use KexiProject::versionMajor() and KexiProject::versionMinor() to get real project's version. */ #define KEXIPROJECT_VERSION_MAJOR 1 #define KEXIPROJECT_VERSION_MINOR 0 class QFileInfo; class KDbConnection; class KDbParser; class KexiMainWindow; class KexiWindow; namespace KexiPart { class Part; class Info; struct MissingPart { QString name; QString id; }; typedef QList MissingPartsList; } /** * @brief A single project's controller and data structure. * It contains data connection, state, etc. */ class KEXICORE_EXPORT KexiProject : public QObject, public KDbObject, public KDbResultable { Q_OBJECT public: /*! Constructor 1. Creates a new object using \a pdata. \a handler can be provided to receive error messages during entire KexiProject object's lifetime. */ explicit KexiProject(const KexiProjectData& pdata, KDbMessageHandler* handler = 0); /*! Constructor 2. Like above but sets predefined connections \a conn. The connection should be created using the same connection data as pdata->connectionData(). The connection will become owned by created KexiProject object, so do not destroy it. */ KexiProject(const KexiProjectData& pdata, KDbMessageHandler* handler, KDbConnection* conn); ~KexiProject(); /*! \return major version of KexiProject object. This information is retrieved from database when existing project is opened. */ int versionMajor() const; /*! \return minor version of KexiProject object. @see versionMajor() */ int versionMinor() const; /*! Opens existing project using project data. \return true on success */ tristate open(); /*! Like open(). \return true on success. Additional \a incompatibleWithKexi, is set to false on failure when connection for the project was successfully started bu the project is probably not compatible with Kexi - no valid "kexidb_major_ver" value in "kexi__db" table. This is often the case for native server-based databases. If so, Kexi application can propose importing the database or linking it to parent project (the latter isn't yet implemented). For other types of errors the variable is set to true. */ tristate open(bool *incompatibleWithKexi); /*! Creates new, empty project using project data. If \a forceOverwrite is true, existing database project is silently overwritten. KDbConnection is created (accessible then with KexiProject::dbConnection()). Since KexiProject inherits KDbObject, it is possible to get error message and other information on error. \return true on success, false on failure, and cancelled when database exists but \a forceOverwrite is false. */ tristate create(bool forceOverwrite = false); /** * @return true if a we are connected to a database */ bool isConnected(); /** * @return internal numeric type identifier for plugin ID @a pluginId. * -1 is returned if the ID is unknown. * While the plugin IDs are unique strings like "org.kexi-project.table", * the type identifiers are specific to the given physically stored project * because sets of plugins can differ from between various Kexi installations * and configurations. * @see pluginIdForTypeId() */ int typeIdForPluginId(const QString &pluginId) const; /** * @return plugin ID for a numeric type ID @a typeId. * Empty string is returned if the plugin ID is unknown. * @see typeIdForPluginId() */ QString pluginIdForTypeId(int typeId) const; /** * @return all items of a type \a i in this project */ KexiPart::ItemDict* items(KexiPart::Info *i); /** * @return all items of a plugin ID \a pluginId in this project * It is a convenience function. */ KexiPart::ItemDict* itemsForPluginId(const QString &pluginId); /** * Puts a list of items of a type \a i in this project into \a list. * You can then sort this list using ItemList::sort(). */ void getSortedItems(KexiPart::ItemList *list, KexiPart::Info *i); /** * Puts a sorted list of items that use a plugin ID \a pluginId into \a list. * You can then sort this list using KexiPart::ItemList::sort(). */ void getSortedItemsForPluginId(KexiPart::ItemList *list, const QString &pluginId); /** * @return item corresponding with plugin ID \a pluginId and name \a name */ KexiPart::Item* itemForPluginId(const QString &pluginId, const QString &name); /** * @return item of type \a i and name \a name */ KexiPart::Item* item(KexiPart::Info *i, const QString &name); /** * @return item for \a identifier */ KexiPart::Item* item(int identifier); /** * @return the database connection associated with this project */ KDbConnection *dbConnection() const; /** * @return the project's data */ KexiProjectData *data() const; /*! Opens object pointed by \a item in a view \a viewMode. \a staticObjectArgs can be passed for static object (only works when part for this item is of type KexiPart::StaticPart). The new widget will be a child of \a parent. */ KexiWindow* openObject(QWidget* parent, KexiPart::Item *item, Kexi::ViewMode viewMode = Kexi::DataViewMode, QMap* staticObjectArgs = 0); //! For convenience KexiWindow* openObject(QWidget* parent, const QString &pluginId, const QString& name, Kexi::ViewMode viewMode = Kexi::DataViewMode); /*! Remove a part instance pointed by \a item. \return true on success. */ bool removeObject(KexiPart::Item* item); /*! Renames a part instance pointed by \a item to a new name \a newName. \return true on success. */ bool renameObject(KexiPart::Item* item, const QString& newName); /*! Renames a part instance pointed by \a item to a new name \a newName. \return true on success. */ bool setObjectCaption(KexiPart::Item* item, const QString& newCaption); /*! Creates part item for given part \a info. Newly item will not be saved to the backend but stored in memory only (owned by project), and marked as "neverSaved" (see KexiPart::Item::neverSaved()). The item will have assigned a new unique caption like e.g. "Table15", and unique name like "table15", but no specific identifier (because id will be assigned on creation at the backend side). If \a suggestedCaption is not empty, it will be set as a caption (with number suffix, to avoid duplicated, e.g. "employees7" for "employees" sugested name). Name will be then built based on this caption using KDb::stringToIdentifier(). This method is used before creating new object. \return newly created part item or NULL on any error. */ KexiPart::Item* createPartItem(KexiPart::Info *info, const QString& suggestedCaption = QString()); //! Added for convenience. KexiPart::Item* createPartItem(KexiPart::Part *part, const QString& suggestedCaption = QString()); /*! Adds item \a item after it is successfully stored as an instance of part pointed by \a info. Also clears 'neverSaved' flag if \a item. Used by KexiWindow::storeNewData(). @internal */ void addStoredItem(KexiPart::Info *info, KexiPart::Item *item); /*! removes \a item from internal dictionaries. The item is destroyed after successful removal. Used to delete an unstored part item previously created with createPartItem(). */ void deleteUnstoredItem(KexiPart::Item *item); /** * @returns parts metioned in the project meta tables but not available locally */ KexiPart::MissingPartsList missingParts() const; KDbParser* sqlParser(); /*! Shows dialog for creating new blank project, ans creates one. Dialog is not shown if option for automatic creation is checked or KexiStartupHandler::global()->projectData() was provided from command line. \a cancelled is set to true if creation has been cancelled (e.g. user answered no when asked for database overwriting, etc. \return true if database was created, false on error or when cancel was pressed */ static KexiProject* createBlankProject(bool *cancelled, const KexiProjectData& data, KDbMessageHandler* handler = 0); /*! Drops project described by \a data. \return true on success. Use with care: Any KexiProject objects allocated for this project will become invalid! */ static tristate dropProject(const KexiProjectData& data, KDbMessageHandler* handler, bool dontAsk = false); //! Helper method to ask user "Could not open file for reading and writing. Do you want to //! open the file as read only?". @return true if user agrees, false if user cancels opening. static bool askForOpeningNonWritableFileAsReadOnly(QWidget *parent, const QFileInfo &finfo); /*! Generates ID for private "document" like Relations window. Private IDs are negative numbers (while ID regular part instance's IDs are >0) Private means that the object is not stored as-is in the project but is somewhat generated and in most cases there is at most one unique instance document of such type (part). To generate this ID, just app-wide internal counter is used. */ virtual int generatePrivateID(); //! Closes connection. @return true on success. bool closeConnection(); /*! Loads current user's data block, referenced by \a objectID and \a dataID and puts it to \a dataString. \return true on success, false on failure and cancelled when there is no such data block \sa storeUserDataBlock() removeUserDataBlock() copyUserDataBlock() KDbConnection::loadDataBlock(). */ tristate loadUserDataBlock(int objectID, const QString& dataID, QString *dataString); /*! Stores current user's data block \a dataString, referenced by \a objectID and \a dataID. The block will be stored in "kexi__userdata" table If there is already such record in the table, it's simply overwritten. \return true on success \sa loadUserDataBlock() removeUserDataBlock() copyUserDataBlock() KDbConnection::storeDataBlock(). */ bool storeUserDataBlock(int objectID, const QString& dataID, const QString &dataString); /*! Copies urrent user's data blocks referenced by \a sourceObjectID and pointed by optional \a dataID. \return true on success. Does not fail if blocks do not exist. Prior to copying, existing user data blocks are removed even if there is nothing to copy. Copied data blocks will have \a destObjectID object identifier assigned. Note that if \a dataID is not specified, all user data blocks found for the \a sourceObjectID will be copied. \sa loadUserDataBlock() storeUserDataBlock() removeUserDataBlock() KDbConnection::copyDataBlock(). */ bool copyUserDataBlock(int sourceObjectID, int destObjectID, const QString &dataID = QString()); /*! Removes current user's data block referenced by \a objectID and \a dataID. \return true on success. Does not fail if the block does not exist. Note that if \a dataID is not specified, all data blocks for this user and object will be removed. \sa loadUserDataBlock() storeUserDataBlock() copyUserDataBlock() KDbConnection::removeDataBlock(). */ bool removeUserDataBlock(int objectID, const QString& dataID = QString()); protected: /*! Creates connection using project data. The connection will be readonly if data()->isReadOnly(). \return true on success, otherwise false and appropriate error is set. */ bool createConnection(); bool initProject(); //! Used in open() and open(bool*). tristate openInternal(bool *incompatibleWithKexi); /*! Kexi itself can define a number of internal database objects (mostly data structures), usually tables for it's own purposes. Even while at KDb library level, such "system" tables, like "kexi__objects", "kexi__objectdata" are created automatically on database project creation, this is not enough: there are objects needed specifically for Kexi but not for other applications utilizing the KDb library. Example table created here for now is "kexi__blobs". This method is called on create() and open(): creates necessary objects if they are not yet existing. This especially allows to create to create these objects (on open) within a project made with previous Kexi version not supporting all currently defined structurtes. We're trying to be here as much backward compatible as possible. For this purpose, here's the complete list of currently created objects: - - "kexi__blobs" - a table containing BLOBs data that can be accessed globally at Kexi projects + - "kexi__blobs" - a table containing BLOBs data that can be accessed globally at KEXI projects from within any database-aware view (table views, forms, reports, etc.) @param insideTransaction Embed entire creation process inside a transaction \return true on successful object's creation. Objects are created only once, they are not overwritten. */ bool createInternalStructures(bool insideTransaction); /*! \return Kexi part for \a item. */ KexiPart::Part *findPartFor(const KexiPart::Item& item); //! Closes connection without altering the m_result if is actually set. @return true on success. //! Used on failed operations such as useDatabase(). bool closeConnectionInternal(); Q_SIGNALS: /** signal emitted on error */ void error(const QString &title, KDbObject *obj); /** signal emitted on error (not KDb-related) */ void error(const QString &msg, const QString &desc); /** New \a item has been stored. */ void newItemStored(KexiPart::Item *item); /** instance pointed by \a item is removed */ void itemRemoved(const KexiPart::Item &item); /** instance pointed by \a item is renamed */ void itemRenamed(const KexiPart::Item &item, const QString& oldName); /** caption for instance pointed by \a item is changed */ void itemCaptionChanged(const KexiPart::Item &item, const QString& oldCaption); protected: bool createIdForPart(const KexiPart::Info& info); private: /*! Checks whether the project's connection is read-only. If so, error message is set and false is returned. */ bool checkWritable(); /*! Retrieves basic information (pluginId, typeId, name, caption) about all items of all types for this project. @return true on success. */ bool retrieveItems(); /** * Checks project's kexi__part table. * @a singlePluginId can be provided to only check specified part. * Internal identifiers of part(s) are remembered. * * Use @ref missingParts() to get a list of missing parts. * @see typeIdForPluginId() */ bool checkProject(const QString& singlePluginId = QString()); class Private; Private * const d; friend class KexiMainWindow; friend class KexiWindow; friend class Private; }; #endif diff --git a/src/doc/dev/compile_time_options.txt b/src/doc/dev/compile_time_options.txt index fbea0b2b9..e7e6f726a 100644 --- a/src/doc/dev/compile_time_options.txt +++ b/src/doc/dev/compile_time_options.txt @@ -1,77 +1,77 @@ Compile-Time Options for Kexi ----------------------------- (c) 2005-2011, Jarosław Staniek, See http://www.kexi-project.org/wiki/wikiview/index.php@AdvancedBuildNotes.html for explanation how to conveniently set compile-time options. List of available options ------------------------- * KEXI_SHOW_UNFINISHED Type: defined/undefined Default: undefined Description: If undefined, unfinished Kexi features (for example a few features within Table Designer) will be hidded for Kexi, to avoid user confusion. * KEXI_SHOW_UNIMPLEMENTED Type: defined/undefined Default: undefined Description: If defined, forces to show menu entries and dialogs just to give -impression about development plans of Kexi Team. +impression about development plans of KEXI Team. Only recommended for test/development versions. * KEXI_SCRIPTS_SUPPORT Type: defined/undefined Description: If defined, the scripts plugin will be compiled in and loaded; else: it will be not loaded even if is compiled. Default: defined * KEXI_MACROS_SUPPORT Type: defined/undefined Like KEXI_SCRIPTS_SUPPORT macro, but for enabling macros plugin. Default: undefined * KEXI_NO_MIGRATION Type: defined/undefined Default: undefined Description: If defined, data/project migration support for Kexi (available in Tools>Migration menu) will be disabled; else: support will be enabled. * KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT Type: defined/undefined, temporary Default: undefined Description: If defined, autofield (KexiDBFieldEdit) widget will be available, nor dragging fields from "data source" will be available * KEXI_DEBUG_GUI Type: defined/undefined Default: defined (but should be undefined for final releases) Description: If defined, showInternalDebugger=true (in [General] group) can be specified to display KexiDB Debugger. In the future the window will be probably used for debugging other features like scripts or macros. This option is useful for Kexi Developers. Also shows additional "Show Form UI Code" action in form's design mode. This is useful for debugging: after executing the action, a dialog with current (after changes) and original form's GUI XML code will be presented in a tabbed dialog, so you can compare what changed and look for possible problems. The "current" XML code will be saved when "save" action is executed. TODO: it will be merged with Internal Debuger window. * KEXI_PROJECT_TEMPLATES Type: defined/undefined Default: defined Description: Defined means Kexi offers project templates. ==== Obsolete, removed, don't use ==== * KEXI_SQLITE_MIGRATION Type: defined/undefined Default: undefined Description: If defined, sqlite3 migration to some newer format is supported (users can see appropriate proposal on startup). Used in KexiStartup.cpp. diff --git a/src/doc/dev/naming_conventions.txt b/src/doc/dev/naming_conventions.txt index b5674f156..aabb404ec 100644 --- a/src/doc/dev/naming_conventions.txt +++ b/src/doc/dev/naming_conventions.txt @@ -1,129 +1,129 @@ --------------------------------------------------------- Kexi Naming Conventions - These rules apply to Kexi Team developers + These rules apply to KEXI Team developers There are also guidelines for future naming decissions. Started: 2003-10-17 - Copyright (C) 2003 Kexi Team + Copyright (C) 2003 KEXI Team Kexi home page: http://www.kexi-project.org/ --------------------------------------------------- 1. Namespaces To simplify class names and make these names shorter, we use namespaces. 1.1. KexiWindow ??? #TODO 2. Directories plugins/ any plugins such as table/query/form designers, import plugins, one subdirectory per plugin widgets/ general-purpose widgets 3rdparty/ any modules that can be considered as external (not necessarily optional) 3. Creating documentation - Doxygen (www.doxygen.org) is used for generating Kexi developer documentation. - default target directory of these docs in html format is: doc/html for all sources - one step (..) up from mentioned dirs are places for .doxygen project files used for docs generating - Single-line comments are created begginning with: //! - Multi-line comments are created begginning with /*! or /** - Style of comments (/*! of /**) for given file should be preserved Example 3.1: Comments for non-void functions, adding information about parameters: /*! Displays value of \a x. \return true if displaying is successfull */ bool display(int x); Notes for example: -\return special Doxygen's tag is used to describe that we return something in the method (\returns will not work for Doxygen!). -Clause should be started from capital letter and terminated with a dot. -"\a" special tag should be used before inserting argument names (names are equal to these from the method's definition) - the names will be therefore highlighted by Doxygen. -For more sophisticated methods (with more arguments), you can as well use \param tag, e.g.: /*! \param x horizontal position \param y vertical position \param col color of the box */ -Methods/functions should be documented in header files (.h), not in implementation files. This allows easier inspection for users of the source code. -Comments from implementation files can be turned into additional documentation, if really needed (when we use "/*!") and this also will be included to generated docs if Doxygen project has enabled appropriate option for doing this. -Classes should be also documented -comments put just as the lines before "class keyword. -to add reference to similar or related function, use \sa tag, e.g.: /*! blablabla \sa bleble */ -to mark a code fragment that someting is TO DO, you can use \todo tag, e.g.: /*! \todo (js) it is so hard to implement! */ -example above shows that adding e.g. own nick inside the brackets what can help to recognise who marked given fragment. 4. Indentation 4.1 We use 2-spaces indentation. Do not use tabs. example: QString objectName(); //wrong QString objectName(); //ok Rule: don't use many spaces or tabs between words. 4.2 To avoid many indentation levels, we can use: void mymethod() { if (!something) return; if (!something_else && .....) return; do_something(); } instead of: void mymethod() { if (something) { if(something_else && .....) { do_something; } } } This is good, because made qt and kde sources readable. 4.3 Indentation within classes declaration namespace MyNamespace { class MyClass { public: MyClass(); void method(); protected: }; } diff --git a/src/formeditor/widgetlibrary.cpp b/src/formeditor/widgetlibrary.cpp index 7da96d5a4..7fbc18f5a 100644 --- a/src/formeditor/widgetlibrary.cpp +++ b/src/formeditor/widgetlibrary.cpp @@ -1,785 +1,788 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-2015 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. */ #include "widgetlibrary.h" #include #include "WidgetInfo.h" #include "widgetfactory.h" #include "libactionwidget.h" #include "container.h" #include "form.h" #include "formIO.h" #include "FormWidgetInterface.h" #include "objecttree.h" #include "KexiJsonTrader.h" #include "KexiFormWidgetsPluginMetaData.h" #include "KexiVersion.h" #include #define KEXI_SKIP_SETUPBREEZEICONTHEME #define KEXI_SKIP_REGISTERRESOURCE #include
#include #include #include #include #include namespace KFormDesigner { Q_GLOBAL_STATIC_WITH_ARGS(KexiJsonTrader, KexiFormWidgetsPluginTrader_instance, (KEXI_BASE_PATH "/forms/widgets")) //! @internal class Q_DECL_HIDDEN WidgetLibrary::Private { public: Private(WidgetLibrary *library, const QStringList& supportedFactoryGroups) : showAdvancedProperties(true) , q(library) , m_couldNotFindAnyFormWidgetPluginsErrorDisplayed(false) , m_supportedFactoryGroups(supportedFactoryGroups.toSet()) , m_lookupDone(false) , m_lookupResult(false) , m_loadFactoriesDone(false) { q->setMessageHandler(&messageHandler); m_advancedProperties.insert("acceptDrops"); m_advancedProperties.insert("accessibleDescription"); m_advancedProperties.insert("accessibleName"); m_advancedProperties.insert("autoMask"); m_advancedProperties.insert("backgroundOrigin"); m_advancedProperties.insert("backgroundMode");//this is rather useless m_advancedProperties.insert("baseSize"); m_advancedProperties.insert("contextMenuEnabled"); m_advancedProperties.insert("contextMenuPolicy"); m_advancedProperties.insert("cursorPosition"); m_advancedProperties.insert("cursorMoveStyle"); m_advancedProperties.insert("dragEnabled"); m_advancedProperties.insert("enableSqueezedText"); m_advancedProperties.insert("layout");// too large risk to break things m_advancedProperties.insert("layoutDirection"); m_advancedProperties.insert("locale"); m_advancedProperties.insert("mouseTracking"); /*! @todo: reenable */ m_advancedProperties.insert("palette"); m_advancedProperties.insert("sizeAdjustPolicy"); //QAbstractScrollArea m_advancedProperties.insert("sizeIncrement"); m_advancedProperties.insert("sizePolicy"); m_advancedProperties.insert("statusTip"); m_advancedProperties.insert("toolTipDuration"); m_advancedProperties.insert("trapEnterKeyEvent"); m_advancedProperties.insert("windowModality"); m_advancedProperties.insert("autoExclusive"); // by providing this in propeditor m_advancedProperties.insert("minimumSize"); m_advancedProperties.insert("maximumSize"); - m_advancedProperties.insert("clickMessage"); // for backward compatibility Kexi projects created with Qt < 4.7 - m_advancedProperties.insert("showClearButton"); // for backward compatibility Kexi projects created with Qt 4 + m_advancedProperties.insert("clickMessage"); // for backward compatibility KEXI projects created with Qt < 4.7 + m_advancedProperties.insert("showClearButton"); // for backward compatibility KEXI projects created with Qt 4 #ifndef KEXI_SHOW_UNFINISHED /*! @todo reenable */ m_advancedProperties.insert("accel"); m_advancedProperties.insert("icon"); m_advancedProperties.insert("paletteBackgroundPixmap"); m_advancedProperties.insert("pixmap"); m_advancedProperties.insert("shortcut"); // renamed from "accel" in Qt 4 m_advancedProperties.insert("windowIcon"); // renamed from "icon" in Qt 4 #endif } ~Private() { qDeleteAll(m_factories); m_factories.clear(); qDeleteAll(m_pluginsMetaData); m_pluginsMetaData.clear(); } QHash widgets() { KDbMessageGuard mg(q); (void)loadFactories(); return m_widgets; } QHash factories() { KDbMessageGuard mg(q); (void)loadFactories(); return m_factories; } bool isAdvancedProperty(const QByteArray &property) const { return m_advancedProperties.contains(property); } bool showAdvancedProperties; private: //! Performs a form widget plugins lookup. @return true on success. //! @todo This method generates a few warnings, maybe we want to optionally display them somewhere (via the message handler)? bool lookup() { //! @todo Allow refreshing if (m_lookupDone) { return m_lookupResult; } m_lookupDone = true; m_lookupResult = false; q->clearResult(); QStringList serviceTypes; serviceTypes << "Kexi/FormWidget"; QList offers = KexiFormWidgetsPluginTrader_instance->query(serviceTypes); foreach(const QPluginLoader *loader, offers) { QScopedPointer metaData(new KexiFormWidgetsPluginMetaData(*loader)); if (metaData->id().isEmpty()) { qWarning() << "No plugin ID specified for Kexi Form Widgets plugin" << metaData->fileName() << "-- skipping!"; continue; } // check version const QString expectedVersion = KFormDesigner::version(); if (metaData->version() != expectedVersion) { qWarning() << "Kexi Form Widgets plugin" << metaData->id() << "has version" << metaData->majorVersion() << "but required version is" << KFormDesigner::version() << "-- skipping!"; continue; } // skip duplicates if (m_pluginsMetaData.contains(metaData->id())) { qWarning() << "More than one Kexi Form Widgets plugin with ID" << metaData->id() << metaData->fileName() << "-- skipping this one"; continue; } //qDebug() << "found factory:" << ptr->name(); if (!metaData->group().isEmpty() && !m_supportedFactoryGroups.contains(metaData->group())) { qDebug() << "Factory group" << metaData->group() << "for Form Widgets plugin" << metaData->id() << metaData->fileName() << "is not supported -- skipping!"; continue; } if (!setupPrivateIconsResourceWithMessage( QLatin1String(KEXI_BASE_PATH), QString::fromLatin1("icons/" KEXI_BASE_PATH "/%1_%2.rcc") .arg(metaData->id()).arg(supportedIconTheme), QtWarningMsg, QString::fromLatin1(":/icons/%1").arg(metaData->id()))) { continue; } m_pluginsMetaData.insert(metaData->id(), metaData.data()); metaData.take(); } qDeleteAll(offers); offers.clear(); if (m_pluginsMetaData.isEmpty()) { q->m_result = KDbResult(i18n("Could not find any form widget plugins.")); m_couldNotFindAnyFormWidgetPluginsErrorDisplayed = true; return false; } m_lookupResult = true; return true; } //! Loads all factory plugins bool loadFactories() { if (m_loadFactoriesDone) { if (m_couldNotFindAnyFormWidgetPluginsErrorDisplayed) { q->clearResult(); // show the warning only once } return m_loadFactoriesResult; } m_loadFactoriesDone = true; m_loadFactoriesResult = false; if (!lookup()) { return false; } foreach (KexiFormWidgetsPluginMetaData *pluginMetaData, m_pluginsMetaData) { WidgetFactory *factory = loadFactory(pluginMetaData); if (!factory) { continue; } //collect information about classes to be hidden if (factory->hiddenClasses()) { foreach (const QByteArray &c, *factory->hiddenClasses()) { m_hiddenClasses.insert(c); } } } //now we have factories instantiated: load widgets QList loadLater; foreach (WidgetFactory *factory, m_factories) { //ONE LEVEL, FLAT INHERITANCE, but works! //if this factory inherits from something, load its witgets later //! @todo improve if (factory->inheritsFactories()) loadLater.append(factory); else loadFactoryWidgets(factory); } //load now the rest foreach (WidgetFactory* f, loadLater) { loadFactoryWidgets(f); } m_loadFactoriesResult = true; return true; } //! Loads of a single factory. @return true on success WidgetFactory *loadFactory(KexiFormWidgetsPluginMetaData *pluginMetaData) { KPluginFactory *factory = qobject_cast(pluginMetaData->instantiate()); if (!factory) { - q->m_result = KDbResult(ERR_CANNOT_LOAD_OBJECT, - xi18nc("@info", "Could not load Kexi Form Widgets plugin file %1.", - pluginMetaData->fileName())); + q->m_result = KDbResult( + ERR_CANNOT_LOAD_OBJECT, + xi18nc("@info", "Could not load Form Widgets plugin file %1 " + "for %2.", + pluginMetaData->fileName(), QApplication::applicationDisplayName())); q->setErrorMessage(pluginMetaData, q->result().message()); qWarning() << q->result().message(); return 0; } WidgetFactory *widgetFactory = factory->create(q); if (!widgetFactory) { - q->m_result = KDbResult(ERR_CANNOT_LOAD_OBJECT, - xi18nc("@info", - "Could not open Kexi Form Widgets plugin %1.", - pluginMetaData->fileName())); + q->m_result = KDbResult( + ERR_CANNOT_LOAD_OBJECT, + xi18nc("@info", "Could not open Form Widgets plugin %1 for " + "%2.", + pluginMetaData->fileName(), QApplication::applicationDisplayName())); qWarning() << q->m_result.message(); return 0; } widgetFactory->setLibrary(q); widgetFactory->setObjectName(pluginMetaData->id()); widgetFactory->setAdvancedPropertiesVisible(showAdvancedProperties); //inherit this flag from the library m_factories.insert(pluginMetaData->id().toLatin1(), widgetFactory); return widgetFactory; } //! Loads widgets for factory @a f void loadFactoryWidgets(WidgetFactory *f) { QHash widgetsForFactory(f->classes()); foreach (WidgetInfo *w, widgetsForFactory) { if (m_hiddenClasses.contains( w->className() )) continue; //this class is hidden // check if we want to inherit a widget from a different factory if (!w->parentFactoryName().isEmpty() && !w->inheritedClassName().isEmpty()) { WidgetFactory *parentFactory = m_factories.value(w->parentFactoryName().toLower()); if (!parentFactory) { qWarning() << "class" << w->className() << ": no such parent factory" << w->parentFactoryName(); continue; } WidgetInfo* inheritedClass = parentFactory->widgetInfoForClassName(w->inheritedClassName()); if (!inheritedClass) { qWarning() << "class" << w->inheritedClassName() << " - no such class to inherit in factory" << w->parentFactoryName(); continue; } //ok: inherit properties: w->setInheritedClass( inheritedClass ); if (w->iconName().isEmpty()) w->setIconName(inheritedClass->iconName()); //ok? foreach(const QByteArray& alternateName, inheritedClass->alternateClassNames()) { w->addAlternateClassName( alternateName, inheritedClass->isOverriddenClassName(alternateName)); } if (w->includeFileName().isEmpty()) w->setIncludeFileName(inheritedClass->includeFileName()); if (w->name().isEmpty()) w->setName(inheritedClass->name()); if (w->namePrefix().isEmpty()) w->setNamePrefix(inheritedClass->namePrefix()); if (w->description().isEmpty()) w->setDescription(inheritedClass->description()); } QList cnames( w->alternateClassNames() ); cnames.prepend(w->className()); foreach (const QByteArray &wname, cnames) { WidgetInfo *widgetForClass = widgetsForFactory.value(wname); if (!widgetForClass || (widgetForClass && !widgetForClass->isOverriddenClassName(wname))) { //insert a widgetinfo, if: //1) this class has no alternate class assigned yet, or //2) this class has alternate class assigned but without 'override' flag m_widgets.insert(wname, w); } } } } WidgetLibrary *q; KexiGUIMessageHandler messageHandler; //! A map which associates a class name with a Widget class QHash m_pluginsMetaData; //!< owner bool m_couldNotFindAnyFormWidgetPluginsErrorDisplayed; QSet m_supportedFactoryGroups; QHash m_factories; //!< owner QHash m_widgets; //!< owner QSet m_advancedProperties; QSet m_hiddenClasses; bool m_lookupDone; bool m_lookupResult; bool m_loadFactoriesDone; bool m_loadFactoriesResult; }; } using namespace KFormDesigner; //------------------------------------------- WidgetLibrary::WidgetLibrary(QObject *parent, const QStringList& supportedFactoryGroups) : QObject(parent) , KDbResultable() , d(new Private(this, supportedFactoryGroups)) { } WidgetLibrary::~WidgetLibrary() { delete d; } void WidgetLibrary::createWidgetActions(ActionGroup *group) { foreach (WidgetInfo *winfo, d->widgets()) { LibActionWidget *a = new LibActionWidget(group, winfo); connect(a, SIGNAL(toggled(QByteArray)), this, SIGNAL(widgetActionToggled(QByteArray))); } } void WidgetLibrary::addCustomWidgetActions(KActionCollection *col) { if (!col) return; foreach (WidgetFactory *factory, d->factories()) { factory->createCustomActions(col); } } QWidget* WidgetLibrary::createWidget(const QByteArray &classname, QWidget *parent, const char *name, Container *c, WidgetFactory::CreateWidgetOptions options) { WidgetInfo *wclass = d->widgets().value(classname); if (!wclass) return 0; QWidget *widget = wclass->factory()->createWidget(wclass->className(), parent, name, c, options); if (!widget) { //try to instantiate from inherited class if (wclass->inheritedClass()) widget = wclass->inheritedClass()->factory()->createWidget( wclass->className(), parent, name, c, options); if (!widget) return 0; } widget->setAcceptDrops(true); if (options & WidgetFactory::DesignViewMode) { FormWidgetInterface* fwiface = dynamic_cast(widget); if (fwiface) fwiface->setDesignMode(true); } emit widgetCreated(widget); return widget; } bool WidgetLibrary::createMenuActions(const QByteArray &c, QWidget *w, QMenu *menu, KFormDesigner::Container *container) { WidgetInfo *wclass = d->widgets().value(c); if (!wclass) return false; if (wclass->factory()->createMenuActions(c, w, menu, container)) { return true; } //try from inherited class if (wclass->inheritedClass()) { return wclass->inheritedClass()->factory()->createMenuActions( wclass->className(), w, menu, container); } return false; } bool WidgetLibrary::startInlineEditing(const QByteArray &classname, QWidget *w, Container *container) { WidgetInfo *wclass = d->widgets().value(classname); if (!wclass) return false; FormWidgetInterface* fwiface = dynamic_cast(w); { KFormDesigner::WidgetFactory::InlineEditorCreationArguments args(classname, w, container); if (wclass->factory()->startInlineEditing(args)) { args.container->form()->createInlineEditor(args); if (fwiface) fwiface->setEditingMode(true); return true; } } if (wclass->inheritedClass()) { //try from inherited class KFormDesigner::WidgetFactory::InlineEditorCreationArguments args(wclass->className(), w, container); if (wclass->inheritedClass()->factory()->startInlineEditing(args)) { args.container->form()->createInlineEditor(args); if (fwiface) fwiface->setEditingMode(true); return true; } } return false; } bool WidgetLibrary::previewWidget(const QByteArray &classname, QWidget *widget, Container *container) { WidgetInfo *wclass = d->widgets().value(classname); if (!wclass) return false; FormWidgetInterface* fwiface = dynamic_cast(widget); if (fwiface) fwiface->setDesignMode(false); if (wclass->factory()->previewWidget(classname, widget, container)) return true; //try from inherited class if (wclass->inheritedClass()) return wclass->inheritedClass()->factory()->previewWidget(wclass->className(), widget, container); return false; } bool WidgetLibrary::clearWidgetContent(const QByteArray &classname, QWidget *w) { WidgetInfo *wclass = d->widgets().value(classname); if (!wclass) return false; if (wclass->factory()->clearWidgetContent(classname, w)) return true; //try from inherited class if (wclass->inheritedClass()) return wclass->inheritedClass()->factory()->clearWidgetContent(wclass->className(), w); return false; } QString WidgetLibrary::displayName(const QByteArray &classname) { WidgetInfo *wi = d->widgets().value(classname); if (wi) return wi->name(); return classname; } QString WidgetLibrary::savingName(const QByteArray &classname) { WidgetInfo *wi = d->widgets().value(classname); if (wi && !wi->savingName().isEmpty()) return wi->savingName(); return classname; } QString WidgetLibrary::namePrefix(const QByteArray &classname) { WidgetInfo *wi = d->widgets().value(classname); if (wi) return wi->namePrefix(); return classname; } QString WidgetLibrary::textForWidgetName(const QByteArray &name, const QByteArray &className) { WidgetInfo *widget = d->widgets().value(className); if (!widget) return QString(); QString newName = name; newName.remove(widget->namePrefix()); newName = widget->name() + (newName.isEmpty() ? QString() : (QLatin1String(" ") + newName)); return newName; } QByteArray WidgetLibrary::classNameForAlternate(const QByteArray &classname) { if (d->widgets().value(classname)) return classname; WidgetInfo *wi = d->widgets().value(classname); if (wi) { return wi->className(); } // widget not supported return "CustomWidget"; } QString WidgetLibrary::includeFileName(const QByteArray &classname) { WidgetInfo *wi = d->widgets().value(classname); if (wi) return wi->includeFileName(); return QString(); } QString WidgetLibrary::iconName(const QByteArray &classname) { WidgetInfo *wi = d->widgets().value(classname); if (wi) return wi->iconName(); return KexiIconName("unknown-widget"); } bool WidgetLibrary::saveSpecialProperty(const QByteArray &classname, const QString &name, const QVariant &value, QWidget *w, QDomElement &parentNode, QDomDocument &parent) { WidgetInfo *wi = d->widgets().value(classname); if (!wi) return false; if (wi->factory()->saveSpecialProperty(classname, name, value, w, parentNode, parent)) return true; //try from inherited class if (wi->inheritedClass()) return wi->inheritedClass()->factory()->saveSpecialProperty(wi->className(), name, value, w, parentNode, parent); return false; } bool WidgetLibrary::readSpecialProperty(const QByteArray &classname, QDomElement &node, QWidget *w, ObjectTreeItem *item) { WidgetInfo *wi = d->widgets().value(classname); if (!wi) return false; if (wi->factory()->readSpecialProperty(classname, node, w, item)) return true; //try from inherited class if (wi->inheritedClass()) return wi->inheritedClass()->factory()->readSpecialProperty(wi->className(), node, w, item); return false; } void WidgetLibrary::setAdvancedPropertiesVisible(bool set) { d->showAdvancedProperties = set; } bool WidgetLibrary::advancedPropertiesVisible() const { return d->showAdvancedProperties; } bool WidgetLibrary::isPropertyVisible(const QByteArray &classname, QWidget *w, const QByteArray &property, bool multiple, bool isTopLevel) { if (isTopLevel) { // no focus policy for top-level form widget... if (!d->showAdvancedProperties && property == "focusPolicy") return false; } WidgetInfo *wi = d->widgets().value(classname); if (!wi) return false; if (!d->showAdvancedProperties && d->isAdvancedProperty(property)) { //this is advanced property, should we hide it? if (!wi->internalProperty("forceShowAdvancedProperty:" + property).toBool() && (!wi->inheritedClass() || !wi->inheritedClass()->internalProperty("forceShowAdvancedProperty:" + property).toBool())) { return false; //hide it } } if (!wi->factory()->isPropertyVisible(classname, w, property, multiple, isTopLevel)) return false; //try from inherited class if (wi->inheritedClass() && !wi->inheritedClass()->factory()->isPropertyVisible(wi->className(), w, property, multiple, isTopLevel)) return false; return true; } QList WidgetLibrary::autoSaveProperties(const QByteArray &classname) { WidgetInfo *wi = d->widgets().value(classname); if (!wi) return QList(); return wi->autoSaveProperties(); } WidgetInfo* WidgetLibrary::widgetInfoForClassName(const char* classname) { return d->widgets().value(classname); } WidgetFactory* WidgetLibrary::factoryForClassName(const char* classname) { WidgetInfo *wi = widgetInfoForClassName(classname); return wi ? wi->factory() : 0; } QString WidgetLibrary::propertyDescForName(WidgetInfo *winfo, const QByteArray& propertyName) { if (!winfo || !winfo->factory()) return QString(); QString desc(winfo->factory()->propertyDescription(propertyName)); if (!desc.isEmpty()) return desc; if (winfo->parentFactoryName().isEmpty()) return QString(); //try in parent factory, if exists WidgetFactory *parentFactory = d->factories().value(winfo->parentFactoryName()); if (!parentFactory) return QString(); return parentFactory->propertyDescription(propertyName); } QString WidgetLibrary::propertyDescForValue(WidgetInfo *winfo, const QByteArray& name) { if (!winfo->factory()) return QString(); QString desc(winfo->factory()->valueDescription(name)); if (!desc.isEmpty()) return desc; if (winfo->parentFactoryName().isEmpty()) return QString(); //try in parent factory, if exists WidgetFactory *parentFactory = d->factories().value(winfo->parentFactoryName()); if (!parentFactory) return QString(); return parentFactory->valueDescription(name); } void WidgetLibrary::setPropertyOptions(KPropertySet& set, const WidgetInfo& winfo, QWidget* w) { if (!winfo.factory()) return; winfo.factory()->setPropertyOptions(set, winfo, w); if (winfo.parentFactoryName().isEmpty()) return; WidgetFactory *parentFactory = d->factories().value(winfo.parentFactoryName()); if (!parentFactory) return; parentFactory->setPropertyOptions(set, winfo, w); } WidgetFactory* WidgetLibrary::factory(const char* factoryName) const { return d->factories().value(factoryName); } QVariant WidgetLibrary::internalProperty(const QByteArray& classname, const QByteArray& property) { WidgetInfo *wclass = d->widgets().value(classname); if (!wclass) return QString(); QVariant value(wclass->internalProperty(property)); if (value.isNull() && wclass->inheritedClass()) return wclass->inheritedClass()->internalProperty(property); return value; } WidgetFactory::CreateWidgetOption WidgetLibrary::showOrientationSelectionPopup( const QByteArray &classname, QWidget* parent, const QPoint& pos) { WidgetInfo *wclass = d->widgets().value(classname); if (!wclass) return WidgetFactory::AnyOrientation; //get custom icons and strings QIcon iconHorizontal, iconVertical; QString iconName(wclass->internalProperty("orientationSelectionPopup:horizontalIcon").toString()); if (iconName.isEmpty() && wclass->inheritedClass()) iconName = wclass->inheritedClass()->internalProperty("orientationSelectionPopup:horizontalIcon").toString(); if (!iconName.isEmpty()) iconHorizontal = QIcon::fromTheme(iconName); iconName = wclass->internalProperty("orientationSelectionPopup:verticalIcon").toString(); if (iconName.isEmpty() && wclass->inheritedClass()) iconName = wclass->inheritedClass()->internalProperty("orientationSelectionPopup:verticalIcon").toString(); if (!iconName.isEmpty()) iconVertical = QIcon::fromTheme(iconName); QString textHorizontal = wclass->internalProperty("orientationSelectionPopup:horizontalText").toString(); if (textHorizontal.isEmpty() && wclass->inheritedClass()) iconName = wclass->inheritedClass()->internalProperty("orientationSelectionPopup:horizontalText").toString(); if (textHorizontal.isEmpty()) //default textHorizontal = xi18nc("Insert Horizontal Widget", "Insert Horizontal"); QString textVertical = wclass->internalProperty("orientationSelectionPopup:verticalText").toString(); if (textVertical.isEmpty() && wclass->inheritedClass()) iconName = wclass->inheritedClass()->internalProperty("orientationSelectionPopup:verticalText").toString(); if (textVertical.isEmpty()) //default textVertical = xi18nc("Insert Vertical Widget", "Insert Vertical"); QMenu popup(parent); popup.setObjectName("orientationSelectionPopup"); popup.addSection(QIcon::fromTheme(wclass->iconName()), xi18n("Insert Widget: %1", wclass->name())); QAction* horizAction = popup.addAction(iconHorizontal, textHorizontal); QAction* vertAction = popup.addAction(iconVertical, textVertical); popup.addSeparator(); popup.addAction(koIcon("dialog-cancel"), xi18n("Cancel")); QAction *a = popup.exec(pos); if (a == horizAction) return WidgetFactory::HorizontalOrientation; else if (a == vertAction) return WidgetFactory::VerticalOrientation; return WidgetFactory::AnyOrientation; //means "cancelled" } bool WidgetLibrary::propertySetShouldBeReloadedAfterPropertyChange( const QByteArray& classname, QWidget *w, const QByteArray& property) { WidgetInfo *winfo = widgetInfoForClassName(classname); if (!winfo) return false; return winfo->factory()->propertySetShouldBeReloadedAfterPropertyChange(classname, w, property); } ObjectTreeItem* WidgetLibrary::selectableItem(ObjectTreeItem* item) { //qDebug() << item->widget()->metaObject()->className(); WidgetInfo *wi = d->widgets().value(item->widget()->metaObject()->className()); if (!wi) return item; return wi->factory()->selectableItem(item); } void WidgetLibrary::setErrorMessage(KexiFormWidgetsPluginMetaData *pluginMetaData, const QString& errorMessage) { pluginMetaData->setErrorMessage(errorMessage); } diff --git a/src/kexi_global.h b/src/kexi_global.h index 8a55f6fb9..e2804380c 100644 --- a/src/kexi_global.h +++ b/src/kexi_global.h @@ -1,45 +1,45 @@ /* This file is part of the KDE project - Copyright (c) 2003-2007 Kexi Team + Copyright (c) 2003-2007 KEXI Team 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_GLOBAL_ #define _KEXI_GLOBAL_ #include #ifdef _MSC_VER #include // for WARNING #endif #ifndef futureI18n # ifdef USE_FUTURE_I18N # define futureI18n(a) i18n(a) # define futureI18nc(a, b) i18nc(b) # define futureI18nc2(a, b, c) i18nc(a, b, c) # else # define futureI18n(a) QString(a) # define futureI18nc(a, b) QString(b) # define futureI18nc2(a, b, c) QString(b) # endif #endif #ifndef FUTURE_I18N_NOOP # define FUTURE_I18N_NOOP(x) (x) #endif #endif /* _KEXI_GLOBAL_ */ diff --git a/src/main/KexiBugReportDialog.cpp b/src/main/KexiBugReportDialog.cpp index 47dcf7140..d49cd2977 100644 --- a/src/main/KexiBugReportDialog.cpp +++ b/src/main/KexiBugReportDialog.cpp @@ -1,232 +1,232 @@ /* This file is part of the KDE project Copyright (C) 2014 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. */ #include "KexiBugReportDialog.h" #include "KexiUserFeedbackAgent.h" #include #include #include #include #include #include #include #include #include #include #include /*! Make a deep copy so we can modify the version. We need to override the version since it sometimes can look like "2.9 Alpha (git 4e06281 master)" what confuses the bugs.kde.org service. KEXI_VERSION_STRING returns just 2.9 Alpha */ static KAboutData copyAboutDataWithFixedVersion() { KAboutData data = KAboutData::applicationData(); data.setVersion(KEXI_VERSION_STRING); return data; } KexiBugReportDialog::KexiBugReportDialog(QWidget *parent) : KBugReport(copyAboutDataWithFixedVersion(), parent) { setModal(true); setWindowTitle(xi18nc("@title:window", "Report a Bug or Wish")); collectData(); QWidget *title = KexiUtils::findFirstChild(this, "KTitleWidget"); if (title) { title->hide(); QVBoxLayout* lay = qobject_cast(title->layout()); lay->insertSpacing(0, 6); lay->addStretch(1); } QGridLayout *glay = KexiUtils::findFirstChild(this, "QGridLayout"); if (glay) { if (glay->itemAtPosition(0, 0) && glay->itemAtPosition(0, 0)->widget()) { glay->itemAtPosition(0, 0)->widget()->hide(); // app name label } if (glay->itemAtPosition(0, 1) && glay->itemAtPosition(0, 1)->widget()) { glay->itemAtPosition(0, 1)->widget()->hide(); // app name } QLabel *lbl; if (glay->itemAtPosition(1, 0) && ((lbl = qobject_cast(glay->itemAtPosition(1, 0)->widget())))) { lbl->setAlignment(Qt::AlignRight); } if (glay->itemAtPosition(2, 0) && ((lbl = qobject_cast(glay->itemAtPosition(2, 0)->widget())))) { lbl->setText(xi18n("Operating system & platform:")); lbl->setAlignment(Qt::AlignRight); } if (glay->itemAtPosition(2, 1) && ((lbl = qobject_cast(glay->itemAtPosition(2, 1)->widget())))) { QString op_sys = m_op_sys; QString rep_platform = m_rep_platform; if (op_sys == "other") { op_sys = xi18nc("Other operating system", "Other"); } if (rep_platform == "Other") { rep_platform = xi18nc("Other platform", "Other"); } lbl->setText(xi18nc(", ", "%1, %2", op_sys, rep_platform)); } if (glay->itemAtPosition(3, 0) && glay->itemAtPosition(3, 0)->widget()) { glay->itemAtPosition(3, 0)->widget()->hide(); // compiler label } if (glay->itemAtPosition(3, 1) && glay->itemAtPosition(3, 1)->widget()) { glay->itemAtPosition(3, 1)->widget()->hide(); // compiler } glay->addItem(new QSpacerItem(1, 10), glay->count(), 0); } //! @todo KEXI3 test it setMinimumHeight(sizeHint().height()); // WORKAROUND: prevent "cropped" kcombobox adjustSize(); } void KexiBugReportDialog::accept() { // override, based on KBugReport::accept() QUrl url("https://bugs.kde.org/enter_bug.cgi"); QUrlQuery query; query.addQueryItem("format", "guided"); // use the guided form // the string format is product/component, where component is optional query.addQueryItem("product", "kexi"); query.addQueryItem("version", KEXI_VERSION_STRING); #if 0 //! @todo add when enter_bug.cgi supports adding comments or when Kexi gets //! own Bug Report GUI and communicates using RPC. QString desc; if (0 != qstrcmp(Kexi::fullVersionString(), Kexi::versionString())) { - desc += futureI18nc("Full version of Kexi app", "Full version: %1", Kexi::fullVersionString()); + desc += futureI18nc("Full version of KEXI app", "Full version: %1", Kexi::fullVersionString()); } - body += futureI18n("(filed directly from Kexi app)"); + body += futureI18n("(filed directly from KEXI app)"); query.addQueryItem("comment", m_aboutData->version()); #endif query.addQueryItem("op_sys", m_op_sys); query.addQueryItem("rep_platform", m_rep_platform); url.setQuery(query); QDesktopServices::openUrl(url); QDialog::accept(); } void KexiBugReportDialog::collectData() { #ifdef Q_OS_LINUX m_op_sys = "Linux"; const QString linux_id = KexiMainWindowIface::global()->userFeedbackAgent()->value("linux_id").toString().toLower(); const QString linux_desc = KexiMainWindowIface::global()->userFeedbackAgent()->value("linux_desc").toString().toLower(); if (linux_id.contains("arch")) { m_rep_platform = "Archlinux Packages"; } else if (linux_id.contains("balsam")) { m_rep_platform = "Balsam Professional"; } else if (linux_id.contains("chakra")) { m_rep_platform = "Chakra"; } else if (linux_id.contains("debian")) { if (linux_id.contains("unstable")) { m_rep_platform = "Debian unstable"; } else if (linux_id.contains("testing")) { m_rep_platform = "Debian testing"; } else { m_rep_platform = "Debian stable"; } } else if (linux_id.contains("exherbo")) { m_rep_platform = "Exherbo Packages"; } else if (linux_id.contains("fedora")) { m_rep_platform = "Fedora RPMs"; } else if (linux_id.contains("gentoo")) { m_rep_platform = "Gentoo Packages"; } else if (linux_id.contains("ubuntu")) { m_rep_platform = "Ubuntu Packages"; } else if (linux_id.contains("kubuntu")) { m_rep_platform = "Kubuntu Packages"; } else if (linux_id.contains("mageia")) { m_rep_platform = "Mageia RPMs"; } else if (linux_id.contains("mint")) { if (linux_desc.contains("debian")) { m_rep_platform = "Mint (Debian based)"; } else { m_rep_platform = "Mint (Ubuntu based)"; } } else if (linux_id.contains("opensuse")) { m_rep_platform = "openSUSE RPMs"; } else if (linux_id.contains("pclinuxos")) { m_rep_platform = "PCLinuxOS"; } else if (linux_id.contains("redhat")) { m_rep_platform = "RedHat RPMs"; } else if (linux_id.contains("slackware")) { m_rep_platform = "Slackware Packages"; } else { m_rep_platform = "Other"; } #elif defined(Q_OS_FREEBSD) m_op_sys = "FreeBSD"; m_rep_platform = "FreeBSD Ports"; #elif defined(Q_OS_NETBSD) m_op_sys = "NetBSD"; m_rep_platform = "NetBSD pkgsrc"; #elif defined(Q_OS_OPENBSD) m_op_sys = "OpenBSD"; m_rep_platform = "OpenBSD Packages"; #elif defined(Q_OS_AIX) m_op_sys = "AIX"; m_rep_platform = "AIX Packages"; #elif defined(Q_OS_HPUX) m_op_sys = "HP-UX"; m_rep_platform = "Other"; #elif defined(Q_OS_IRIX) m_op_sys = "IRIX"; m_rep_platform = "Other"; #elif defined(Q_OS_OSF) m_op_sys = "Tru64"; m_rep_platform = "Tru64 Unix Packages"; #elif defined(Q_OS_SOLARIS) m_op_sys = "Solaris"; m_rep_platform = "Solaris Packages"; #elif defined(Q_OS_MACOS) m_op_sys = "OS X"; m_rep_platform = "Mac OS X Disk Images"; #elif defined(Q_OS_WIN) m_op_sys = "MS Windows"; m_rep_platform = "MS Windows"; #elif defined(Q_OS_WINCE) m_op_sys = "Windows CE"; m_rep_platform = "Windows CE"; #elif defined(Q_OS_ANDROID) m_op_sys = "Android 4.x"; m_rep_platform = "Android"; #else m_op_sys = "other"; m_rep_platform = "Other"; #endif } diff --git a/src/main/KexiMainWindow.cpp b/src/main/KexiMainWindow.cpp index b710a348a..91f796246 100644 --- a/src/main/KexiMainWindow.cpp +++ b/src/main/KexiMainWindow.cpp @@ -1,4404 +1,4406 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2017 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. */ #include "KexiMainWindow.h" #include "KexiMainWindow_p.h" #include "kexiactionproxy.h" #include "kexipartmanager.h" #include "kexipart.h" #include "kexipartinfo.h" #include "kexipartguiclient.h" #include "kexiproject.h" #include "kexiprojectdata.h" #include "kexi.h" #include "kexiinternalpart.h" #include "kexiactioncategories.h" #include "kexifinddialog.h" #include "kexisearchandreplaceiface.h" #include "KexiBugReportDialog.h" #define KEXI_SKIP_REGISTERICONSRESOURCE #define KEXI_SKIP_SETUPPRIVATEICONSRESOURCE #include "KexiRegisterResource_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "startup/KexiStartup.h" #include "startup/KexiNewProjectAssistant.h" #include "startup/KexiOpenProjectAssistant.h" #include "startup/KexiWelcomeAssistant.h" #include "startup/KexiImportExportAssistant.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 #include #include #include #include #include #include #include #include #if !defined(KexiVDebug) # define KexiVDebug if (0) qDebug() #endif #ifdef HAVE_KCRASH #include //! @todo else, add Breakpad? https://phabricator.kde.org/T1642 #endif KexiDockWidgetStyle::KexiDockWidgetStyle(const QString &baseStyleName) : QProxyStyle(baseStyleName) { } KexiDockWidgetStyle::~KexiDockWidgetStyle() { } void KexiDockWidgetStyle::polish(QWidget* widget) { baseStyle()->polish(widget); widget->setContentsMargins(0, 0, 0, 0); } class Q_DECL_HIDDEN KexiDockWidget::Private { public: Private() {} QSize hint; }; KexiDockWidget::KexiDockWidget(const QString &_tabText, QWidget *parent) : QDockWidget(parent), tabText(_tabText), d(new Private) { // No floatable dockers, Dolphin had problems, we don't want the same... // https://bugs.kde.org/show_bug.cgi?id=288629 // https://bugs.kde.org/show_bug.cgi?id=322299 setFeatures(QDockWidget::NoDockWidgetFeatures);//DockWidgetClosable); setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea); setFocusPolicy(Qt::NoFocus); if (style()->objectName().compare("windowsvista", Qt::CaseInsensitive) == 0) { // windowsvista style has broken accelerator visualization support KAcceleratorManager::setNoAccel(this); } KexiDockWidgetStyle *customStyle = new KexiDockWidgetStyle(style()->objectName()); customStyle->setParent(this); setStyle(customStyle); setTitleBarWidget(new QWidget(this)); // hide the title layout()->setContentsMargins(0, 0, 0, 0); layout()->setSpacing(0); } KexiDockWidget::~KexiDockWidget() { delete d; } void KexiDockWidget::paintEvent(QPaintEvent *pe) { Q_UNUSED(pe); QStylePainter p(this); if (isFloating()) { QStyleOptionFrame framOpt; framOpt.initFrom(this); p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt); } // Title must be painted after the frame, since the areas overlap, and // the title may wish to extend out to all sides (eg. XP style) QStyleOptionDockWidget titleOpt; initStyleOption(&titleOpt); p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt); } void KexiDockWidget::setSizeHint(const QSize& hint) { d->hint = hint; } QSize KexiDockWidget::sizeHint() const { return d->hint.isValid() ? d->hint : QDockWidget::sizeHint(); } //------------------------------------------------- KexiMainWindowTabWidget::KexiMainWindowTabWidget(QWidget *parent, KexiMainWidget* mainWidget) : QTabWidget(parent) , m_mainWidget(mainWidget) , m_tabIndex(-1) { m_closeAction = new QAction(koIcon("tab-close"), xi18n("&Close Tab"), this); m_closeAction->setToolTip(xi18n("Close the current tab")); m_closeAction->setWhatsThis(xi18n("Closes the current tab.")); m_closeAllTabsAction = new QAction(xi18n("Cl&ose All Tabs"), this); m_closeAllTabsAction->setToolTip(xi18n("Close all tabs")); m_closeAllTabsAction->setWhatsThis(xi18n("Closes all tabs.")); connect(m_closeAction, SIGNAL(triggered()), this, SLOT(closeTab())); connect(m_closeAllTabsAction, SIGNAL(triggered()), this, SLOT(closeAllTabs())); //! @todo insert window list in the corner widget as in firefox #if 0 // close-tab button: QToolButton* rightWidget = new QToolButton(this); rightWidget->setDefaultAction(m_closeAction); rightWidget->setText(QString()); rightWidget->setAutoRaise(true); rightWidget->adjustSize(); setCornerWidget(rightWidget, Qt::TopRightCorner); #endif setMovable(true); setDocumentMode(true); tabBar()->setExpanding(false); } KexiMainWindowTabWidget::~KexiMainWindowTabWidget() { } void KexiMainWindowTabWidget::paintEvent(QPaintEvent * event) { if (count() > 0) QTabWidget::paintEvent(event); else QWidget::paintEvent(event); } void KexiMainWindowTabWidget::mousePressEvent(QMouseEvent *event) { //! @todo KEXI3 test KexiMainWindowTabWidget's contextMenu event port from KTabWidget if (event->button() == Qt::RightButton) { int tab = tabBar()->tabAt(event->pos()); const QPoint realPos(tabBar()->mapToGlobal(event->pos())); if (QRect(tabBar()->mapToGlobal(QPoint(0,0)), tabBar()->mapToGlobal(QPoint(tabBar()->width()-1, tabBar()->height()-1))).contains(realPos)) { showContextMenuForTab(tab, tabBar()->mapToGlobal(event->pos())); return; } } QTabWidget::mousePressEvent(event); } void KexiMainWindowTabWidget::closeTab() { KexiMainWindow *main = dynamic_cast(KexiMainWindowIface::global()); if (main) { main->closeWindowForTab(m_tabIndex); } } tristate KexiMainWindowTabWidget::closeAllTabs() { tristate alternateResult = true; QList windowList; KexiMainWindow *main = dynamic_cast(KexiMainWindowIface::global()); if (!main) { return alternateResult; } for (int i = 0; i < count(); i++) { KexiWindow *window = main->windowForTab(i); if (window) { windowList.append(window); } } foreach (KexiWindow *window, windowList) { tristate result = main->closeWindow(window); if (result != true && result != false) { return result; } if (result == false) { alternateResult = false; } } return alternateResult; } void KexiMainWindowTabWidget::showContextMenuForTab(int index, const QPoint& point) { QMenu menu; if (index >= 0) { menu.addAction(m_closeAction); } if (count() > 0) { menu.addAction(m_closeAllTabsAction); } //! @todo add "&Detach Tab" if (menu.actions().isEmpty()) { return; } setTabIndexFromContextMenu(index); menu.exec(point); } void KexiMainWindowTabWidget::setTabIndexFromContextMenu(int clickedIndex) { if (currentIndex() == -1) { m_tabIndex = -1; return; } m_tabIndex = clickedIndex; } //------------------------------------------------- static bool setupIconTheme(KLocalizedString *errorMessage, KLocalizedString *detailsErrorMessage) { // Register kexi resource first to have priority over the standard breeze theme. // For example "table" icon exists in both resources. if (!registerResource("icons/" KEXI_BASE_PATH "/kexi_breeze.rcc", QStandardPaths::AppDataLocation, QString(), QString(), errorMessage, detailsErrorMessage) || !registerGlobalBreezeIconsResource(errorMessage, detailsErrorMessage)) { return false; } setupBreezeIconTheme(); // tell KIconLoader an co. about the theme KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); cg.writeEntry("Theme", "breeze"); cg.sync(); return true; } //! @todo 3.1 replace with KexiStyle bool setupApplication() { #if defined Q_OS_WIN || defined Q_OS_MACOS // Only this style matches current Kexi theme and can be supported/tested const char *name = "breeze"; QScopedPointer style(QStyleFactory::create(name)); if (!style || style->objectName() != name) { qWarning() << qPrintable(QString("Could not find application style %1. " - "Kexi will not start. Please check if Kexi is properly installed. ") + "Kexi will not start. Please check if KEXI is properly installed. ") .arg(name)); return false; } qApp->setStyle(style.take()); #endif return true; } //static int KexiMainWindow::create(const QStringList &arguments, const QString &componentName, const QList &extraOptions) { qApp->setQuitOnLastWindowClosed(false); KLocalizedString::setApplicationDomain("kexi"); //! @todo KEXI3 app->setAttribute(Qt::AA_UseHighDpiPixmaps, true); KexiAboutData aboutData; if (!componentName.isEmpty()) { aboutData.setComponentName(componentName); } KAboutData::setApplicationData(aboutData); if (!setupApplication()) { return 1; } #ifdef HAVE_KCRASH KCrash::initialize(); #endif KLocalizedString errorMessage; KLocalizedString detailsErrorMessage; if (!setupIconTheme(&errorMessage, &detailsErrorMessage)) { if (detailsErrorMessage.isEmpty()) { KMessageBox::error(nullptr, errorMessage.toString()); } else { KMessageBox::detailedError(nullptr, errorMessage.toString(), detailsErrorMessage.toString()); } qWarning() << qPrintable(errorMessage.toString(Kuit::PlainText)); return 1; } QApplication::setWindowIcon(koIcon("kexi")); const tristate res = KexiStartupHandler::global()->init(arguments, extraOptions); if (!res || ~res) { return (~res) ? 0 : 1; } //qDebug() << "startupActions OK"; /* Exit requested, e.g. after database removing. */ if (KexiStartupHandler::global()->action() == KexiStartupData::Exit) { return 0; } KexiMainWindow *win = new KexiMainWindow(); #ifdef KEXI_DEBUG_GUI QWidget* debugWindow = 0; KConfigGroup generalGroup = KSharedConfig::openConfig()->group("General"); if (generalGroup.readEntry("ShowInternalDebugger", false)) { debugWindow = KexiUtils::createDebugWindow(win); debugWindow->show(); } #endif if (true != win->startup()) { delete win; return 1; } win->restoreSettings(); win->show(); #ifdef KEXI_DEBUG_GUI win->raise(); static_cast(win)->activateWindow(); #endif /*foreach (QWidget *widget, QApplication::topLevelWidgets()) { qDebug() << widget; }*/ return 0; } //------------------------------------------------- KexiMainMenuActionShortcut::KexiMainMenuActionShortcut(const QKeySequence& key, QAction *action, QWidget *parent) : QShortcut(key, parent) , m_action(action) { connect(this, SIGNAL(activated()), this, SLOT(slotActivated())); } KexiMainMenuActionShortcut::~KexiMainMenuActionShortcut() { } void KexiMainMenuActionShortcut::slotActivated() { if (!m_action->isEnabled()) { return; } m_action->trigger(); } //------------------------------------------------- KexiMainWindow::KexiMainWindow(QWidget *parent) : KexiMainWindowSuper(parent) , KexiMainWindowIface() , KexiGUIMessageHandler(this) , d(new KexiMainWindow::Private(this)) { setObjectName("KexiMainWindow"); setAttribute(Qt::WA_DeleteOnClose); kexiTester() << KexiTestObject(this); if (d->userMode) qDebug() << "starting up in the User Mode"; setAsDefaultHost(); //this is default host now. //get informed connect(&Kexi::partManager(), SIGNAL(partLoaded(KexiPart::Part*)), this, SLOT(slotPartLoaded(KexiPart::Part*))); connect(&Kexi::partManager(), SIGNAL(newObjectRequested(KexiPart::Info*)), this, SLOT(newObject(KexiPart::Info*))); setAcceptDrops(true); setupActions(); setupMainWidget(); updateAppCaption(); if (!d->userMode) { setupContextHelp(); setupPropertyEditor(); } invalidateActions(); d->timer.singleShot(0, this, SLOT(slotLastActions())); if (KexiStartupHandler::global()->forcedFullScreen()) { toggleFullScreen(true); } // --- global config //! @todo move to specialized KexiConfig class KConfigGroup tablesGroup(d->config->group("Tables")); const int defaultMaxLengthForTextFields = tablesGroup.readEntry("DefaultMaxLengthForTextFields", int(-1)); if (defaultMaxLengthForTextFields >= 0) { KDbField::setDefaultMaxLength(defaultMaxLengthForTextFields); } // --- /global config } KexiMainWindow::~KexiMainWindow() { d->forceWindowClosing = true; closeProject(); delete d; Kexi::deleteGlobalObjects(); } KexiProject *KexiMainWindow::project() { return d->prj; } QList KexiMainWindow::allActions() const { return actionCollection()->actions(); } KActionCollection *KexiMainWindow::actionCollection() const { return d->actionCollection; } KexiWindow* KexiMainWindow::currentWindow() const { return windowForTab(d->mainWidget->tabWidget()->currentIndex()); } KexiWindow* KexiMainWindow::windowForTab(int tabIndex) const { if (!d->mainWidget->tabWidget()) return 0; KexiWindowContainer *windowContainer = dynamic_cast(d->mainWidget->tabWidget()->widget(tabIndex)); if (!windowContainer) return 0; return windowContainer->window; } void KexiMainWindow::setupMainMenuActionShortcut(QAction * action) { if (!action->shortcut().isEmpty()) { foreach(const QKeySequence &shortcut, action->shortcuts()) { (void)new KexiMainMenuActionShortcut(shortcut, action, this); } } } static void addThreeDotsToActionText(QAction* action) { action->setText(xi18nc("Action name with three dots...", "%1...", action->text())); } QAction * KexiMainWindow::addAction(const char *name, const QIcon &icon, const QString& text, const char *shortcut) { QAction *action = icon.isNull() ? new QAction(text, this) : new QAction(icon, text, this); actionCollection()->addAction(name, action); if (shortcut) { action->setShortcut(QKeySequence(shortcut)); QShortcut *s = new QShortcut(action->shortcut(), this); connect(s, SIGNAL(activated()), action, SLOT(trigger())); } return action; } QAction * KexiMainWindow::addAction(const char *name, const QString& text, const char *shortcut) { return addAction(name, QIcon(), text, shortcut); } void KexiMainWindow::setupActions() { KActionCollection *ac = actionCollection(); // PROJECT MENU QAction *action; ac->addAction("project_new", action = new KexiMenuWidgetAction(KStandardAction::New, this)); addThreeDotsToActionText(action); action->setShortcuts(KStandardShortcut::openNew()); action->setToolTip(xi18n("Create a new project")); action->setWhatsThis( xi18n("Creates a new project. Currently opened project is not affected.")); connect(action, SIGNAL(triggered()), this, SLOT(slotProjectNew())); setupMainMenuActionShortcut(action); ac->addAction("project_open", action = new KexiMenuWidgetAction(KStandardAction::Open, this)); action->setToolTip(xi18n("Open an existing project")); action->setWhatsThis( xi18n("Opens an existing project. Currently opened project is not affected.")); connect(action, SIGNAL(triggered()), this, SLOT(slotProjectOpen())); setupMainMenuActionShortcut(action); { ac->addAction("project_welcome", action = d->action_project_welcome = new KexiMenuWidgetAction( QIcon(), xi18n("Welcome"), this)); addThreeDotsToActionText(action); connect(action, SIGNAL(triggered()), this, SLOT(slotProjectWelcome())); setupMainMenuActionShortcut(action); action->setToolTip(xi18n("Show Welcome page")); action->setWhatsThis( xi18n("Shows Welcome page with list of recently opened projects and other information. ")); } ac->addAction("project_save", d->action_save = KStandardAction::save(this, SLOT(slotProjectSave()), this)); d->action_save->setToolTip(xi18n("Save object changes")); d->action_save->setWhatsThis(xi18n("Saves object changes from currently selected window.")); setupMainMenuActionShortcut(d->action_save); d->action_save_as = addAction("project_saveas", koIcon("document-save-as"), xi18n("Save &As...")); d->action_save_as->setToolTip(xi18n("Save object as")); d->action_save_as->setWhatsThis( xi18n("Saves object from currently selected window under a new name (within the same project).")); connect(d->action_save_as, SIGNAL(triggered()), this, SLOT(slotProjectSaveAs())); #ifdef KEXI_SHOW_UNIMPLEMENTED ac->addAction("project_properties", action = d->action_project_properties = new KexiMenuWidgetAction( koIcon("document-properties"), futureI18n("Project Properties"), this)); connect(action, SIGNAL(triggered()), this, SLOT(slotProjectProperties())); setupMainMenuActionShortcut(action); #else d->action_project_properties = d->dummy_action; #endif //! @todo replace document-import icon with something other ac->addAction("project_import_export_send", action = d->action_project_import_export_send = new KexiMenuWidgetAction( koIcon("document-import"), xi18n("&Import, Export or Send..."), this)); action->setToolTip(xi18n("Import, export or send project")); action->setWhatsThis( xi18n("Imports, exports or sends project.")); connect(action, SIGNAL(triggered()), this, SLOT(slotProjectImportExportOrSend())); setupMainMenuActionShortcut(action); ac->addAction("project_close", action = d->action_close = new KexiMenuWidgetAction( koIcon("window-close"), xi18nc("Close Project", "&Close"), this)); action->setToolTip(xi18n("Close the current project")); action->setWhatsThis(xi18n("Closes the current project.")); connect(action, SIGNAL(triggered()), this, SLOT(slotProjectClose())); setupMainMenuActionShortcut(action); ac->addAction("quit", action = new KexiMenuWidgetAction(KStandardAction::Quit, this)); connect(action, SIGNAL(triggered()), this, SLOT(slotProjectQuit())); - action->setWhatsThis(xi18n("Quits Kexi application.")); + action->setWhatsThis(xi18nc("@info:whatsthis", "Quits %1 application.", + QApplication::applicationDisplayName())); setupMainMenuActionShortcut(action); #ifdef KEXI_SHOW_UNIMPLEMENTED d->action_project_relations = addAction("project_relations", KexiIcon("database-relations"), futureI18n("&Relationships..."), "Ctrl+R"); d->action_project_relations->setToolTip(futureI18n("Project relationships")); d->action_project_relations->setWhatsThis(futureI18n("Shows project relationships.")); connect(d->action_project_relations, SIGNAL(triggered()), this, SLOT(slotProjectRelations())); #else d->action_project_relations = d->dummy_action; #endif d->action_tools_import_project = addAction("tools_import_project", KexiIcon("database-import"), xi18n("&Import Database...")); - d->action_tools_import_project->setToolTip(xi18n("Import entire database as a Kexi project")); + d->action_tools_import_project->setToolTip(xi18n("Import entire database as a KEXI project")); d->action_tools_import_project->setWhatsThis( - xi18n("Imports entire database as a Kexi project.")); + xi18n("Imports entire database as a KEXI project.")); connect(d->action_tools_import_project, SIGNAL(triggered()), this, SLOT(slotToolsImportProject())); d->action_tools_data_import = addAction("tools_import_tables", koIcon("document-import"), xi18n("Import Tables...")); d->action_tools_data_import->setToolTip(xi18n("Import data from an external source into this project")); d->action_tools_data_import->setWhatsThis(xi18n("Imports data from an external source into this project.")); connect(d->action_tools_data_import, SIGNAL(triggered()), this, SLOT(slotToolsImportTables())); d->action_tools_compact_database = addAction("tools_compact_database", //! @todo icon koIcon("application-x-compress"), xi18n("&Compact Database...")); d->action_tools_compact_database->setToolTip(xi18n("Compact the current database project")); d->action_tools_compact_database->setWhatsThis( xi18n("Compacts the current database project, so it will take less space and work faster.")); connect(d->action_tools_compact_database, SIGNAL(triggered()), this, SLOT(slotToolsCompactDatabase())); if (d->userMode) d->action_project_import_data_table = 0; else { d->action_project_import_data_table = addAction("project_import_data_table", KexiIcon("document-empty"), /*! @todo: change to "file_import" with a table or so */ xi18nc("Import->Table Data From File...", "Import Data From &File...")); d->action_project_import_data_table->setToolTip(xi18n("Import table data from a file")); d->action_project_import_data_table->setWhatsThis(xi18n("Imports table data from a file.")); connect(d->action_project_import_data_table, SIGNAL(triggered()), this, SLOT(slotProjectImportDataTable())); } d->action_project_export_data_table = addAction("project_export_data_table", KexiIcon("table"), /*! @todo: change to "file_export" with a table or so */ xi18nc("Export->Table or Query Data to File...", "Export Data to &File...")); d->action_project_export_data_table->setToolTip( xi18n("Export data from the active table or query to a file")); d->action_project_export_data_table->setWhatsThis( xi18n("Exports data from the active table or query to a file.")); connect(d->action_project_export_data_table, SIGNAL(triggered()), this, SLOT(slotProjectExportDataTable())); //! @todo new QAction(xi18n("From File..."), "document-open", 0, //! this, SLOT(slotImportFile()), actionCollection(), "project_import_file"); //! @todo new QAction(xi18n("From Server..."), "network-server-database", 0, //! this, SLOT(slotImportServer()), actionCollection(), "project_import_server"); #ifdef KEXI_QUICK_PRINTING_SUPPORT ac->addAction("project_print", d->action_project_print = KStandardAction::print(this, SLOT(slotProjectPrint()), this)); d->action_project_print->setToolTip(futureI18n("Print data from the active table or query")); d->action_project_print->setWhatsThis(futureI18n("Prints data from the active table or query.")); ac->addAction("project_print_preview", d->action_project_print_preview = KStandardAction::printPreview( this, SLOT(slotProjectPrintPreview()), this)); d->action_project_print_preview->setToolTip( futureI18n("Show print preview for the active table or query")); d->action_project_print_preview->setWhatsThis( futureI18n("Shows print preview for the active table or query.")); d->action_project_print_setup = addAction("project_print_setup", koIcon("configure"), futureI18n("Print Set&up...")); //!< @todo document-page-setup could be a better icon d->action_project_print_setup->setToolTip( futureI18n("Show print setup for the active table or query")); d->action_project_print_setup->setWhatsThis( futureI18n("Shows print setup for the active table or query.")); connect(d->action_project_print_setup, SIGNAL(triggered()), this, SLOT(slotProjectPageSetup())); #endif //EDIT MENU d->action_edit_cut = createSharedAction(KStandardAction::Cut); d->action_edit_copy = createSharedAction(KStandardAction::Copy); d->action_edit_paste = createSharedAction(KStandardAction::Paste); if (d->userMode) d->action_edit_paste_special_data_table = 0; else { d->action_edit_paste_special_data_table = addAction( "edit_paste_special_data_table", d->action_edit_paste->icon(), xi18nc("Paste Special->As Data &Table...", "Paste Special...")); d->action_edit_paste_special_data_table->setToolTip( xi18n("Paste clipboard data as a table")); d->action_edit_paste_special_data_table->setWhatsThis( xi18n("Pastes clipboard data as a table.")); connect(d->action_edit_paste_special_data_table, SIGNAL(triggered()), this, SLOT(slotEditPasteSpecialDataTable())); } d->action_edit_copy_special_data_table = addAction( "edit_copy_special_data_table", KexiIcon("table"), xi18nc("Copy Special->Table or Query Data...", "Copy Special...")); d->action_edit_copy_special_data_table->setToolTip( xi18n("Copy selected table or query data to clipboard")); d->action_edit_copy_special_data_table->setWhatsThis( xi18n("Copies selected table or query data to clipboard.")); connect(d->action_edit_copy_special_data_table, SIGNAL(triggered()), this, SLOT(slotEditCopySpecialDataTable())); d->action_edit_undo = createSharedAction(KStandardAction::Undo); d->action_edit_undo->setWhatsThis(xi18n("Reverts the most recent editing action.")); d->action_edit_redo = createSharedAction(KStandardAction::Redo); d->action_edit_redo->setWhatsThis(xi18n("Reverts the most recent undo action.")); ac->addAction("edit_find", d->action_edit_find = KStandardAction::find( this, SLOT(slotEditFind()), this)); d->action_edit_find->setToolTip(xi18n("Find text")); d->action_edit_find->setWhatsThis(xi18n("Looks up the first occurrence of a piece of text.")); ac->addAction("edit_findnext", d->action_edit_findnext = KStandardAction::findNext( this, SLOT(slotEditFindNext()), this)); ac->addAction("edit_findprevious", d->action_edit_findprev = KStandardAction::findPrev( this, SLOT(slotEditFindPrevious()), this)); d->action_edit_replace = 0; //! @todo d->action_edit_replace = KStandardAction::replace( //! this, SLOT(slotEditReplace()), actionCollection(), "project_print_preview" ); d->action_edit_replace_all = 0; //! @todo d->action_edit_replace_all = new QAction( xi18n("Replace All"), "", 0, //! this, SLOT(slotEditReplaceAll()), actionCollection(), "edit_replaceall"); d->action_edit_select_all = createSharedAction(KStandardAction::SelectAll); d->action_edit_delete = createSharedAction(xi18n("&Delete"), koIconName("edit-delete"), QKeySequence(), "edit_delete"); d->action_edit_delete->setToolTip(xi18n("Delete selected object")); d->action_edit_delete->setWhatsThis(xi18n("Deletes currently selected object.")); d->action_edit_delete_row = createSharedAction(xi18n("Delete Record"), KexiIconName("edit-table-delete-row"), QKeySequence(Qt::CTRL + Qt::Key_Delete), "edit_delete_row"); d->action_edit_delete_row->setToolTip(xi18n("Delete the current record")); d->action_edit_delete_row->setWhatsThis(xi18n("Deletes the current record.")); d->action_edit_clear_table = createSharedAction(xi18n("Clear Table Contents..."), KexiIconName("edit-table-clear"), QKeySequence(), "edit_clear_table"); d->action_edit_clear_table->setToolTip(xi18n("Clear table contents")); d->action_edit_clear_table->setWhatsThis(xi18n("Clears table contents.")); setActionVolatile(d->action_edit_clear_table, true); d->action_edit_edititem = createSharedAction(xi18n("Edit Item"), QString(), QKeySequence(), /* CONFLICT in TV: Qt::Key_F2, */ "edit_edititem"); d->action_edit_edititem->setToolTip(xi18n("Edit currently selected item")); d->action_edit_edititem->setWhatsThis(xi18n("Edits currently selected item.")); d->action_edit_insert_empty_row = createSharedAction(xi18n("&Insert Empty Row"), KexiIconName("edit-table-insert-row"), QKeySequence(Qt::SHIFT | Qt::CTRL | Qt::Key_Insert), "edit_insert_empty_row"); setActionVolatile(d->action_edit_insert_empty_row, true); d->action_edit_insert_empty_row->setToolTip(xi18n("Insert one empty row above")); d->action_edit_insert_empty_row->setWhatsThis( xi18n("Inserts one empty row above currently selected table row.")); //VIEW MENU /* UNUSED, see KexiToggleViewModeAction if (!d->userMode) { d->action_view_mode = new QActionGroup(this); ac->addAction( "view_data_mode", d->action_view_data_mode = new KToggleAction( KexiIcon("data-view"), xi18n("&Data View"), d->action_view_mode) ); // d->action_view_data_mode->setObjectName("view_data_mode"); d->action_view_data_mode->setShortcut(QKeySequence("F6")); //d->action_view_data_mode->setExclusiveGroup("view_mode"); d->action_view_data_mode->setToolTip(xi18n("Switch to data view")); d->action_view_data_mode->setWhatsThis(xi18n("Switches to data view.")); d->actions_for_view_modes.insert( Kexi::DataViewMode, d->action_view_data_mode ); connect(d->action_view_data_mode, SIGNAL(triggered()), this, SLOT(slotViewDataMode())); } else { d->action_view_mode = 0; d->action_view_data_mode = 0; } if (!d->userMode) { ac->addAction( "view_design_mode", d->action_view_design_mode = new KToggleAction( KexiIcon("design-view"), xi18n("D&esign View"), d->action_view_mode) ); // d->action_view_design_mode->setObjectName("view_design_mode"); d->action_view_design_mode->setShortcut(QKeySequence("F7")); //d->action_view_design_mode->setExclusiveGroup("view_mode"); d->action_view_design_mode->setToolTip(xi18n("Switch to design view")); d->action_view_design_mode->setWhatsThis(xi18n("Switches to design view.")); d->actions_for_view_modes.insert( Kexi::DesignViewMode, d->action_view_design_mode ); connect(d->action_view_design_mode, SIGNAL(triggered()), this, SLOT(slotViewDesignMode())); } else d->action_view_design_mode = 0; if (!d->userMode) { ac->addAction( "view_text_mode", d->action_view_text_mode = new KToggleAction( KexiIcon("sql-view"), xi18n("&Text View"), d->action_view_mode) ); d->action_view_text_mode->setObjectName("view_text_mode"); d->action_view_text_mode->setShortcut(QKeySequence("F8")); //d->action_view_text_mode->setExclusiveGroup("view_mode"); d->action_view_text_mode->setToolTip(xi18n("Switch to text view")); d->action_view_text_mode->setWhatsThis(xi18n("Switches to text view.")); d->actions_for_view_modes.insert( Kexi::TextViewMode, d->action_view_text_mode ); connect(d->action_view_text_mode, SIGNAL(triggered()), this, SLOT(slotViewTextMode())); } else d->action_view_text_mode = 0; */ if (d->isProjectNavigatorVisible) { d->action_show_nav = addAction("view_navigator", xi18n("Show Project Navigator"), "Alt+0"); d->action_show_nav->setToolTip(xi18n("Show the Project Navigator pane")); d->action_show_nav->setWhatsThis(xi18n("Shows the Project Navigator pane.")); connect(d->action_show_nav, SIGNAL(triggered()), this, SLOT(slotShowNavigator())); } else { d->action_show_nav = 0; } if (d->isProjectNavigatorVisible) { // Shortcut taken from "Activate Projects pane" http://doc.qt.io/qtcreator/creator-keyboard-shortcuts.html d->action_activate_nav = addAction("activate_navigator", xi18n("Activate Project Navigator"), "Alt+X"); d->action_activate_nav->setToolTip(xi18n("Activate the Project Navigator pane")); d->action_activate_nav->setWhatsThis(xi18n("Activates the Project Navigator pane. If it is hidden, shows it first.")); connect(d->action_activate_nav, SIGNAL(triggered()), this, SLOT(slotActivateNavigator())); } else { d->action_activate_nav = 0; } d->action_activate_mainarea = addAction("activate_mainarea", xi18n("Activate main area") // , "Alt+2"? //! @todo activate_mainarea: pressing Esc in project nav or propeditor should move back to the main area ); d->action_activate_mainarea->setToolTip(xi18n("Activate the main area")); d->action_activate_mainarea->setWhatsThis(xi18n("Activates the main area.")); connect(d->action_activate_mainarea, SIGNAL(triggered()), this, SLOT(slotActivateMainArea())); //! @todo windows with "_3" prefix have conflicting auto shortcut set to Alt+3 -> remove that! if (!d->userMode) { d->action_show_propeditor = addAction("view_propeditor", xi18n("Show Property Editor"), "Alt+3"); d->action_show_propeditor->setToolTip(xi18n("Show the Property Editor pane")); d->action_show_propeditor->setWhatsThis(xi18n("Shows the Property Editor pane.")); connect(d->action_show_propeditor, SIGNAL(triggered()), this, SLOT(slotShowPropertyEditor())); } else { d->action_show_propeditor = 0; } if (!d->userMode) { d->action_activate_propeditor = addAction("activate_propeditor", xi18n("Activate Property Editor"), "Alt+-"); d->action_activate_propeditor->setToolTip(xi18n("Activate the Property Editor pane")); d->action_activate_propeditor->setWhatsThis(xi18n("Activates the Property Editor pane. If it is hidden, shows it first.")); connect(d->action_activate_propeditor, SIGNAL(triggered()), this, SLOT(slotActivatePropertyEditor())); } else { d->action_activate_propeditor = 0; } d->action_view_global_search = addAction("view_global_search", xi18n("Switch to Global Search"), "Ctrl+K"); d->action_view_global_search->setToolTip(xi18n("Switch to Global Search box")); d->action_view_global_search->setWhatsThis(xi18n("Switches to Global Search box.")); // (connection is added elsewhere) //DATA MENU d->action_data_save_row = createSharedAction(xi18n("&Save Record"), koIconName("dialog-ok"), QKeySequence(Qt::SHIFT + Qt::Key_Return), "data_save_row"); d->action_data_save_row->setToolTip(xi18n("Save changes made to the current record")); d->action_data_save_row->setWhatsThis(xi18n("Saves changes made to the current record.")); //temp. disable because of problems with volatile actions setActionVolatile( d->action_data_save_row, true ); d->action_data_cancel_row_changes = createSharedAction(xi18n("&Cancel Record Changes"), koIconName("dialog-cancel"), QKeySequence(Qt::Key_Escape), "data_cancel_row_changes"); d->action_data_cancel_row_changes->setToolTip( xi18n("Cancel changes made to the current record")); d->action_data_cancel_row_changes->setWhatsThis( xi18n("Cancels changes made to the current record.")); //temp. disable because of problems with volatile actions setActionVolatile( d->action_data_cancel_row_changes, true ); d->action_data_execute = createSharedAction( xi18n("&Execute"), koIconName("media-playback-start"), QKeySequence(), "data_execute"); //! @todo d->action_data_execute->setToolTip(xi18n("")); //! @todo d->action_data_execute->setWhatsThis(xi18n("")); #ifdef KEXI_SHOW_UNIMPLEMENTED action = createSharedAction(futureI18n("&Filter"), koIconName("view-filter"), QKeySequence(), "data_filter"); setActionVolatile(action, true); #endif //! @todo action->setToolTip(xi18n("")); //! @todo action->setWhatsThis(xi18n("")); // - record-navigation related actions createSharedAction(KexiRecordNavigator::Actions::moveToFirstRecord(), QKeySequence(), "data_go_to_first_record"); createSharedAction(KexiRecordNavigator::Actions::moveToPreviousRecord(), QKeySequence(), "data_go_to_previous_record"); createSharedAction(KexiRecordNavigator::Actions::moveToNextRecord(), QKeySequence(), "data_go_to_next_record"); createSharedAction(KexiRecordNavigator::Actions::moveToLastRecord(), QKeySequence(), "data_go_to_last_record"); createSharedAction(KexiRecordNavigator::Actions::moveToNewRecord(), QKeySequence(), "data_go_to_new_record"); //FORMAT MENU d->action_format_font = createSharedAction(xi18n("&Font..."), koIconName("fonts-package"), QKeySequence(), "format_font"); d->action_format_font->setToolTip(xi18n("Change font for selected object")); d->action_format_font->setWhatsThis(xi18n("Changes font for selected object.")); //TOOLS MENU //WINDOW MENU //additional 'Window' menu items d->action_window_next = addAction("window_next", xi18n("&Next Window"), #ifdef Q_OS_WIN "Ctrl+Tab" #else "Alt+Right" #endif ); d->action_window_next->setToolTip(xi18n("Next window")); d->action_window_next->setWhatsThis(xi18n("Switches to the next window.")); connect(d->action_window_next, SIGNAL(triggered()), this, SLOT(activateNextWindow())); d->action_window_previous = addAction("window_previous", xi18n("&Previous Window"), #ifdef Q_OS_WIN "Ctrl+Shift+Tab" #else "Alt+Left" #endif ); d->action_window_previous->setToolTip(xi18n("Previous window")); d->action_window_previous->setWhatsThis(xi18n("Switches to the previous window.")); connect(d->action_window_previous, SIGNAL(triggered()), this, SLOT(activatePreviousWindow())); d->action_window_fullscreen = KStandardAction::fullScreen(this, SLOT(toggleFullScreen(bool)), this, ac); ac->addAction("full_screen", d->action_window_fullscreen); QList shortcuts; shortcuts << d->action_window_fullscreen->shortcut() << QKeySequence("F11"); d->action_window_fullscreen->setShortcuts(shortcuts); QShortcut *s = new QShortcut(d->action_window_fullscreen->shortcut(), this); connect(s, SIGNAL(activated()), d->action_window_fullscreen, SLOT(trigger())); if (d->action_window_fullscreen->shortcuts().count() > 1) { QShortcut *sa = new QShortcut(d->action_window_fullscreen->shortcuts().value(1), this); connect(sa, SIGNAL(activated()), d->action_window_fullscreen, SLOT(trigger())); } //SETTINGS MENU //! @todo put 'configure keys' into settings view #ifdef KEXI_SHOW_UNIMPLEMENTED //! @todo toolbars configuration will be handled in a special way #endif #ifdef KEXI_MACROS_SUPPORT Kexi::tempShowMacros() = true; #else Kexi::tempShowMacros() = false; #endif #ifdef KEXI_SCRIPTS_SUPPORT Kexi::tempShowScripts() = true; #else Kexi::tempShowScripts() = false; #endif #ifdef KEXI_SHOW_UNIMPLEMENTED //! @todo implement settings window in a specific way ac->addAction("settings", action = d->action_settings = new KexiMenuWidgetAction( KStandardAction::Preferences, this)); action->setObjectName("settings"); action->setText(futureI18n("Settings...")); - action->setToolTip(futureI18n("Show Kexi settings")); - action->setWhatsThis(futureI18n("Shows Kexi settings.")); + action->setToolTip(futureI18n("Show KEXI settings")); + action->setWhatsThis(futureI18n("Shows KEXI settings.")); connect(action, SIGNAL(triggered()), this, SLOT(slotSettings())); setupMainMenuActionShortcut(action); #else d->action_settings = d->dummy_action; #endif //! @todo reenable 'tip of the day' later #if 0 KStandardAction::tipOfDay(this, SLOT(slotTipOfTheDayAction()), actionCollection()) ->setWhatsThis(xi18n("This shows useful tips on the use of this application.")); #endif // GLOBAL d->action_show_help_menu = addAction("help_show_menu", xi18nc("Help Menu", "Help"), "Alt+H"); d->action_show_help_menu->setToolTip(xi18n("Show Help menu")); d->action_show_help_menu->setWhatsThis(xi18n("Shows Help menu.")); // (connection is added elsewhere) // ----- declare action categories, so form's "assign action to button" // (and macros in the future) will be able to recognize category // of actions and filter them ----------------------------------- //! @todo shouldn't we move this to core? Kexi::ActionCategories *acat = Kexi::actionCategories(); acat->addAction("data_execute", Kexi::PartItemActionCategory); //! @todo unused for now acat->addWindowAction("data_filter", KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addWindowAction("data_save_row", KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addWindowAction("data_cancel_row_changes", KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addWindowAction("delete_table_row", KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); //! @todo support this in KexiPart::FormObjectType as well acat->addWindowAction("data_sort_az", KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in KexiPart::FormObjectType as well acat->addWindowAction("data_sort_za", KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in KexiPart::FormObjectType as well acat->addWindowAction("edit_clear_table", KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in KexiPart::FormObjectType as well acat->addWindowAction("edit_copy_special_data_table", KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in FormObjectType as well acat->addWindowAction("project_export_data_table", KexiPart::TableObjectType, KexiPart::QueryObjectType); // GlobalActions, etc. acat->addAction("edit_copy", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory); acat->addAction("edit_cut", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory); acat->addAction("edit_paste", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory); acat->addAction("edit_delete", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_delete_row", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_edititem", Kexi::PartItemActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType); acat->addAction("edit_find", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_findnext", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_findprevious", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_replace", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_paste_special_data_table", Kexi::GlobalActionCategory); acat->addAction("help_about_app", Kexi::GlobalActionCategory); acat->addAction("help_about_kde", Kexi::GlobalActionCategory); acat->addAction("help_contents", Kexi::GlobalActionCategory); acat->addAction("help_report_bug", Kexi::GlobalActionCategory); acat->addAction("help_whats_this", Kexi::GlobalActionCategory); acat->addAction("help_donate", Kexi::GlobalActionCategory); // disabled for now acat->addAction("switch_application_language", Kexi::GlobalActionCategory); acat->addAction("options_configure_keybinding", Kexi::GlobalActionCategory); acat->addAction("project_close", Kexi::GlobalActionCategory); acat->addAction("project_import_data_table", Kexi::GlobalActionCategory); acat->addAction("project_new", Kexi::GlobalActionCategory); acat->addAction("project_open", Kexi::GlobalActionCategory); #ifdef KEXI_QUICK_PRINTING_SUPPORT //! @todo support this in FormObjectType, ReportObjectType as well as others acat->addAction("project_print", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in FormObjectType, ReportObjectType as well as others acat->addAction("project_print_preview", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in FormObjectType, ReportObjectType as well as others acat->addAction("project_print_setup", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType); #endif acat->addAction("quit", Kexi::GlobalActionCategory); acat->addAction("tools_compact_database", Kexi::GlobalActionCategory); acat->addAction("tools_import_project", Kexi::GlobalActionCategory); acat->addAction("tools_import_tables", Kexi::GlobalActionCategory); acat->addAction("view_data_mode", Kexi::GlobalActionCategory); acat->addAction("view_design_mode", Kexi::GlobalActionCategory); acat->addAction("view_text_mode", Kexi::GlobalActionCategory); acat->addAction("view_mainarea", Kexi::GlobalActionCategory); acat->addAction("view_navigator", Kexi::GlobalActionCategory); acat->addAction("activate_navigator", Kexi::GlobalActionCategory); acat->addAction("view_propeditor", Kexi::GlobalActionCategory); acat->addAction("activate_mainarea", Kexi::GlobalActionCategory); acat->addAction("activate_propeditor", Kexi::GlobalActionCategory); acat->addAction("window_close", Kexi::GlobalActionCategory | Kexi::WindowActionCategory); acat->setAllObjectTypesSupported("window_close", true); acat->addAction("window_next", Kexi::GlobalActionCategory); acat->addAction("window_previous", Kexi::GlobalActionCategory); acat->addAction("full_screen", Kexi::GlobalActionCategory); //skipped - design view only acat->addAction("format_font", Kexi::NoActionCategory); acat->addAction("project_save", Kexi::NoActionCategory); acat->addAction("edit_insert_empty_row", Kexi::NoActionCategory); //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType later acat->addAction("edit_select_all", Kexi::NoActionCategory); //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType later acat->addAction("edit_redo", Kexi::NoActionCategory); //! @todo support this in KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType later acat->addAction("edit_undo", Kexi::NoActionCategory); //record-navigation related actions acat->addAction("data_go_to_first_record", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("data_go_to_previous_record", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("data_go_to_next_record", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("data_go_to_last_record", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("data_go_to_new_record", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); //skipped - internal: acat->addAction("tablepart_create", Kexi::NoActionCategory); acat->addAction("querypart_create", Kexi::NoActionCategory); acat->addAction("formpart_create", Kexi::NoActionCategory); acat->addAction("reportpart_create", Kexi::NoActionCategory); acat->addAction("macropart_create", Kexi::NoActionCategory); acat->addAction("scriptpart_create", Kexi::NoActionCategory); } void KexiMainWindow::invalidateActions() { invalidateProjectWideActions(); invalidateSharedActions(); } void KexiMainWindow::invalidateSharedActions(QObject *o) { //! @todo enabling is more complex... /* d->action_edit_cut->setEnabled(true); d->action_edit_copy->setEnabled(true); d->action_edit_paste->setEnabled(true);*/ if (!o) o = focusWindow(); KexiSharedActionHost::invalidateSharedActions(o); } void KexiMainWindow::invalidateSharedActions() { invalidateSharedActions(0); } // unused, I think void KexiMainWindow::invalidateSharedActionsLater() { QTimer::singleShot(1, this, SLOT(invalidateSharedActions())); } void KexiMainWindow::invalidateProjectWideActions() { const bool has_window = currentWindow(); const bool window_dirty = currentWindow() && currentWindow()->isDirty(); const bool readOnly = d->prj && d->prj->dbConnection() && d->prj->dbConnection()->options()->isReadOnly(); //PROJECT MENU d->action_save->setEnabled(has_window && window_dirty && !readOnly); d->action_save_as->setEnabled(has_window && !readOnly); d->action_project_properties->setEnabled(d->prj); d->action_close->setEnabled(d->prj); d->action_project_relations->setEnabled(d->prj); //DATA MENU if (d->action_project_import_data_table) d->action_project_import_data_table->setEnabled(d->prj && !readOnly); if (d->action_tools_data_import) d->action_tools_data_import->setEnabled(d->prj && !readOnly); d->action_project_export_data_table->setEnabled( currentWindow() && currentWindow()->part()->info()->isDataExportSupported()); if (d->action_edit_paste_special_data_table) d->action_edit_paste_special_data_table->setEnabled(d->prj && !readOnly); #ifdef KEXI_QUICK_PRINTING_SUPPORT const bool printingActionsEnabled = currentWindow() && currentWindow()->part()->info()->isPrintingSupported() && !currentWindow()->neverSaved(); d->action_project_print->setEnabled(printingActionsEnabled); d->action_project_print_preview->setEnabled(printingActionsEnabled); d->action_project_print_setup->setEnabled(printingActionsEnabled); #endif //EDIT MENU //! @todo "copy special" is currently enabled only for data view mode; //! what about allowing it to enable in design view for "kexi/table" ? if (currentWindow() && currentWindow()->currentViewMode() == Kexi::DataViewMode) { KexiPart::Info *activePartInfo = currentWindow()->part()->info(); d->action_edit_copy_special_data_table->setEnabled( activePartInfo ? activePartInfo->isDataExportSupported() : false); } else { d->action_edit_copy_special_data_table->setEnabled(false); } d->action_edit_find->setEnabled(d->prj); //VIEW MENU if (d->action_show_nav) d->action_show_nav->setEnabled(d->prj); d->action_activate_mainarea->setEnabled(d->prj); if (d->action_show_propeditor) d->action_show_propeditor->setEnabled(d->prj); #ifdef KEXI_SHOW_CONTEXT_HELP d->action_show_helper->setEnabled(d->prj); #endif //CREATE MENU if (d->tabbedToolBar && d->tabbedToolBar->createWidgetToolBar()) d->tabbedToolBar->createWidgetToolBar()->setEnabled(d->prj); // DATA MENU //TOOLS MENU // "compact db" supported if there's no db or the current db supports compacting and is opened r/w: d->action_tools_compact_database->setEnabled( !d->prj || (!readOnly && d->prj && d->prj->dbConnection() && (d->prj->dbConnection()->driver()->features() & KDbDriver::CompactingDatabaseSupported)) ); //DOCKS if (d->navigator) { d->navigator->setEnabled(d->prj); } if (d->propEditor) d->propEditorTabWidget->setEnabled(d->prj); } tristate KexiMainWindow::startup() { tristate result = true; switch (KexiStartupHandler::global()->action()) { case KexiStartupHandler::CreateBlankProject: d->updatePropEditorVisibility(Kexi::NoViewMode); break; #ifdef KEXI_PROJECT_TEMPLATES case KexiStartupHandler::CreateFromTemplate: result = createProjectFromTemplate(*KexiStartupHandler::global()->projectData()); break; #endif case KexiStartupHandler::OpenProject: result = openProject(*KexiStartupHandler::global()->projectData()); break; case KexiStartupHandler::ImportProject: result = showProjectMigrationWizard( KexiStartupHandler::global()->importActionData().mimeType, KexiStartupHandler::global()->importActionData().fileName ); break; case KexiStartupHandler::ShowWelcomeScreen: //! @todo show welcome screen as soon as is available QTimer::singleShot(100, this, SLOT(slotProjectWelcome())); break; default: d->updatePropEditorVisibility(Kexi::NoViewMode); } return result; } static QString internalReason(const KDbResult &result) { const QString msg = result.message(); if (msg.isEmpty()) { return QString(); } return xi18n("
(reason: %1)", msg); } tristate KexiMainWindow::openProject(const KexiProjectData& projectData) { //qDebug() << projectData; QScopedPointer prj(createKexiProjectObject(projectData)); if (~KexiDBPasswordDialog::getPasswordIfNeeded(prj->data()->connectionData(), this)) { return cancelled; } bool incompatibleWithKexi; tristate res = prj->open(&incompatibleWithKexi); if (prj->data()->connectionData()->isPasswordNeeded()) { // password was supplied in this session, and shouldn't be stored or reused afterwards, // so let's remove it prj->data()->connectionData()->setPassword(QString()); } if (~res) { return cancelled; } else if (!res) { if (incompatibleWithKexi) { if (KMessageBox::Yes == KMessageBox::questionYesNo(this, xi18nc("@info (don't add tags around %1, it's done already)", - "Database project %1 does not appear to have been created using Kexi." - "Do you want to import it as a new Kexi project?", - projectData.infoString()), + "Database project %1 does not appear to have been created using " + "%2." + "Do you want to import it as a new KEXI project?", + projectData.infoString(), QApplication::applicationDisplayName()), QString(), KGuiItem(xi18nc("@action:button Import Database", "&Import..."), KexiIconName("database-import")), KStandardGuiItem::cancel())) { const bool anotherProjectAlreadyOpened = prj; tristate res = showProjectMigrationWizard("application/x-kexi-connectiondata", projectData.databaseName(), *projectData.connectionData()); if (!anotherProjectAlreadyOpened) //the project could have been opened within this instance return res; //always return cancelled because even if migration succeeded, new Kexi instance //will be started if user wanted to open the imported db return cancelled; } return cancelled; } return false; } // success d->prj = prj.take(); setupProjectNavigator(); d->prj->data()->setLastOpened(QDateTime::currentDateTime()); Kexi::recentProjects()->addProjectData(*d->prj->data()); updateReadOnlyState(); invalidateActions(); setMessagesEnabled(false); QTimer::singleShot(1, this, SLOT(slotAutoOpenObjectsLater())); if (d->tabbedToolBar) { d->tabbedToolBar->showTab("create");// not needed since create toolbar already shows toolbar! move when kexi starts d->tabbedToolBar->showTab("data"); d->tabbedToolBar->showTab("external"); d->tabbedToolBar->showTab("tools"); d->tabbedToolBar->hideTab("form");//temporalily until createToolbar is split d->tabbedToolBar->hideTab("report");//temporalily until createToolbar is split // make sure any tab is activated d->tabbedToolBar->setCurrentTab(0); } return true; } tristate KexiMainWindow::openProject(const KexiProjectData& data, const QString& shortcutPath, bool *opened) { if (!shortcutPath.isEmpty() && d->prj) { const tristate result = openProjectInExternalKexiInstance( shortcutPath, QString(), QString()); if (result == true) { *opened = true; } return result; } return openProject(data); } tristate KexiMainWindow::createProjectFromTemplate(const KexiProjectData& projectData) { Q_UNUSED(projectData); #ifdef KEXI_PROJECT_TEMPLATES QStringList mimetypes; mimetypes.append(KDb::defaultFileBasedDriverMimeType()); QString fname; //! @todo KEXI3 add equivalent of kfiledialog:/// const QString startDir("kfiledialog:///OpenExistingOrCreateNewProject"/*as in KexiNewProjectWizard*/); const QString caption(xi18nc("@window:title", "Select New Project's Location")); while (true) { if (fname.isEmpty() && !projectData.connectionData()->databaseName().isEmpty()) { //propose filename from db template name fname = projectData.connectionData()->databaseName(); } const bool specialDir = fname.isEmpty(); qDebug() << fname << "............."; QFileDialog dlg(specialDir ? QUrl(startDir) : QUrl(), QString(), this); dlg.setModal(true); dlg.setMimeFilter(mimetypes); if (!specialDir) dlg.selectUrl(QUrl::fromLocalFile(fname); // may also be a filename dlg.setFileMode(QFileDialog::ExistingFile); dlg.setFileMode(QFileDialog::AcceptOpen); dlg.setWindowTitle(caption); if (QDialog::Accepted != dlg.exec()) { return cancelled; } if (dlg.selectedFiles().isEmpty() { return cancelled; } fname = dlg.selectedFiles().first(); if (fname.isEmpty()) { return cancelled; } if (KexiUtils::askForFileOverwriting(fname, this)) { break; } } QFile sourceFile(projectData.connectionData()->fileName()); if (!sourceFile.copy(fname)) { //! @todo show error from with QFile::FileError return false; } return openProject(fname, 0, QString(), projectData.autoopenObjects/*copy*/); #else return false; #endif } void KexiMainWindow::updateReadOnlyState() { const bool readOnly = d->prj && d->prj->dbConnection() && d->prj->dbConnection()->options()->isReadOnly(); //! @todo KEXI3 show read-only flag in the GUI because we have no statusbar if (d->navigator) { d->navigator->setReadOnly(readOnly); } // update "insert ....." actions for every part KexiPart::PartInfoList *plist = Kexi::partManager().infoList(); if (plist) { foreach(KexiPart::Info *info, *plist) { QAction *a = info->newObjectAction(); if (a) a->setEnabled(!readOnly); } } } void KexiMainWindow::slotAutoOpenObjectsLater() { QString not_found_msg; bool openingCancelled; //ok, now open "autoopen: objects if (d->prj) { for (const KexiProjectData::ObjectInfo &info : d->prj->data()->autoopenObjects) { KexiPart::Info *i = Kexi::partManager().infoForPluginId(info.value("type")); if (!i) { not_found_msg += "
  • "; if (!info.value("name").isEmpty()) { not_found_msg += (QString("\"") + info.value("name") + "\" - "); } if (info.value("action") == "new") { not_found_msg += xi18n("cannot create object - unknown object type \"%1\"", info.value("type")); } else { not_found_msg += xi18n("unknown object type \"%1\"", info.value("type")); } not_found_msg += internalReason(Kexi::partManager().result()) + "
  • "; continue; } // * NEW if (info.value("action") == "new") { if (!newObject(i, &openingCancelled) && !openingCancelled) { not_found_msg += "
  • "; not_found_msg += (xi18n("cannot create object of type \"%1\"", info.value("type")) + internalReason(d->prj->result()) + "
  • "); } else { d->wasAutoOpen = true; } continue; } KexiPart::Item *item = d->prj->item(i, info.value("name")); if (!item) { QString taskName; if (info.value("action") == "execute") { taskName = xi18nc("\"executing object\" action", "executing"); #ifdef KEXI_QUICK_PRINTING_SUPPORT } else if (info->value("action") == "print-preview") { taskName = futureI18n("making print preview for"); } else if (info->value("action") == "print") { taskName = futureI18n("printing"); #endif } else { taskName = xi18n("opening"); } not_found_msg += (QString("
  • ") + taskName + " \"" + info.value("name") + "\" - "); if ("table" == info.value("type").toLower()) { not_found_msg += xi18n("table not found"); } else if ("query" == info.value("type").toLower()) { not_found_msg += xi18n("query not found"); } else if ("macro" == info.value("type").toLower()) { not_found_msg += xi18n("macro not found"); } else if ("script" == info.value("type").toLower()) { not_found_msg += xi18n("script not found"); } else { not_found_msg += xi18n("object not found"); } not_found_msg += (internalReason(d->prj->result()) + "
  • "); continue; } // * EXECUTE, PRINT, PRINT PREVIEW if (info.value("action") == "execute") { tristate res = executeItem(item); if (false == res) { not_found_msg += (QString("
  • \"") + info.value("name") + "\" - " + xi18n("cannot execute object") + internalReason(d->prj->result()) + "
  • "); } continue; } #ifdef KEXI_QUICK_PRINTING_SUPPORT else if (info.value("action") == "print") { tristate res = printItem(item); if (false == res) { not_found_msg += (QString("
  • \"") + info.value("name") + "\" - " + futureI18n("cannot print object") + internalReason(d->prj->result()) + "
  • "); } continue; } else if (info.value("action") == "print-preview") { tristate res = printPreviewForItem(item); if (false == res) { not_found_msg += (QString("
  • \"") + info.value("name") + "\" - " + futureI18n("cannot make print preview of object") + internalReason(d->prj->result()) + "
  • "); } continue; } #endif Kexi::ViewMode viewMode; if (info.value("action") == "open") { viewMode = Kexi::DataViewMode; } else if (info.value("action") == "design") { viewMode = Kexi::DesignViewMode; } else if (info.value("action") == "edittext") { viewMode = Kexi::TextViewMode; } else { continue; //sanity } QString openObjectMessage; if (!openObject(item, viewMode, &openingCancelled, 0, &openObjectMessage) && (!openingCancelled || !openObjectMessage.isEmpty())) { not_found_msg += (QString("
  • \"") + info.value("name") + "\" - "); if (openObjectMessage.isEmpty()) { not_found_msg += xi18n("cannot open object"); } else { not_found_msg += openObjectMessage; } not_found_msg += internalReason(d->prj->result()) + "
  • "; continue; } else { d->wasAutoOpen = true; } } } setMessagesEnabled(true); if (!not_found_msg.isEmpty()) { showErrorMessage(xi18n("You have requested selected objects to be automatically opened " "or processed on startup. Several objects cannot be opened or processed."), QString("
      %1
    ").arg(not_found_msg)); } d->updatePropEditorVisibility(currentWindow() ? currentWindow()->currentViewMode() : Kexi::NoViewMode); #if defined(KDOCKWIDGET_P) if (d->propEditor) { KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); if (ds) ds->setSeparatorPosInPercent(d->config->readEntry("RightDockPosition", 80/* % */)); } #endif updateAppCaption(); if (d->tabbedToolBar) { d->tabbedToolBar->hideMainMenu(); } qApp->processEvents(); emit projectOpened(); } tristate KexiMainWindow::closeProject() { if (d->tabbedToolBar) d->tabbedToolBar->hideMainMenu(); #ifndef KEXI_NO_PENDING_DIALOGS if (d->pendingWindowsExist()) { qDebug() << "pendingWindowsExist..."; d->actionToExecuteWhenPendingJobsAreFinished = Private::CloseProjectAction; return cancelled; } #endif //only save nav. visibility setting if there is project opened d->saveSettingsForShowProjectNavigator = d->prj && d->isProjectNavigatorVisible; if (!d->prj) return true; { // make sure the project can be closed bool cancel = false; emit acceptProjectClosingRequested(&cancel); if (cancel) return cancelled; } d->windowExistedBeforeCloseProject = currentWindow(); #if defined(KDOCKWIDGET_P) //remember docks position - will be used on storeSettings() if (d->propEditor) { KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); if (ds) d->propEditorDockSeparatorPos = ds->separatorPosInPercent(); } if (d->nav) { if (d->propEditor) { //! @todo KEXI3 if (d->openedWindowsCount() == 0) //! @todo KEXI3 makeWidgetDockVisible(d->propEditorTabWidget); KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); if (ds) ds->setSeparatorPosInPercent(80); } KDockWidget *dw = (KDockWidget *)d->nav->parentWidget(); KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); int dwWidth = dw->width(); if (ds) { if (d->openedWindowsCount() != 0 && d->propEditorTabWidget && d->propEditorTabWidget->isVisible()) { d->navDockSeparatorPos = ds->separatorPosInPercent(); } else { d->navDockSeparatorPos = (100 * dwWidth) / width(); } } } #endif //close each window, optionally asking if user wants to close (if data changed) while (currentWindow()) { tristate res = closeWindow(currentWindow()); if (!res || ~res) return res; } // now we will close for sure emit beforeProjectClosing(); if (!d->prj->closeConnection()) return false; if (d->navigator) { d->navWasVisibleBeforeProjectClosing = d->navDockWidget->isVisible(); d->navDockWidget->hide(); d->navigator->setProject(0); slotProjectNavigatorVisibilityChanged(true); // hide side tab } if (d->propEditorDockWidget) d->propEditorDockWidget->hide(); d->clearWindows(); //sanity! delete d->prj; d->prj = 0; updateReadOnlyState(); invalidateActions(); updateAppCaption(); emit projectClosed(); return true; } void KexiMainWindow::setupContextHelp() { #ifdef KEXI_SHOW_CONTEXT_HELP d->ctxHelp = new KexiContextHelp(d->mainWidget, this); //! @todo /* d->ctxHelp->setContextHelp(xi18n("Welcome"),xi18n("The KEXI team wishes you a lot of productive work, " "with this product.


    If you have found a bug or have a feature request, please don't " "hesitate to report it at our issue " "tracking system .


    If you would like to join our effort, the development documentation " "at www.kexi-project.org is a good starting point."),0); */ addToolWindow(d->ctxHelp, KDockWidget::DockBottom | KDockWidget::DockLeft, getMainDockWidget(), 20); #endif } void KexiMainWindow::setupMainWidget() { QVBoxLayout *vlyr = new QVBoxLayout(this); vlyr->setContentsMargins(0, 0, 0, 0); vlyr->setSpacing(0); if (d->isMainMenuVisible) { QWidget *tabbedToolBarContainer = new QWidget(this); vlyr->addWidget(tabbedToolBarContainer); QVBoxLayout *tabbedToolBarContainerLyr = new QVBoxLayout(tabbedToolBarContainer); tabbedToolBarContainerLyr->setSpacing(0); tabbedToolBarContainerLyr->setContentsMargins( KexiUtils::marginHint() / 2, KexiUtils::marginHint() / 2, KexiUtils::marginHint() / 2, KexiUtils::marginHint() / 2); d->tabbedToolBar = new KexiTabbedToolBar(tabbedToolBarContainer); Q_ASSERT(d->action_view_global_search); connect(d->action_view_global_search, SIGNAL(triggered()), d->tabbedToolBar, SLOT(activateSearchLineEdit())); tabbedToolBarContainerLyr->addWidget(d->tabbedToolBar); d->tabbedToolBar->hideTab("form"); //temporarily until createToolbar is split d->tabbedToolBar->hideTab("report"); //temporarily until createToolbar is split } else { d->tabbedToolBar = 0; } QWidget *mainWidgetContainer = new QWidget(); vlyr->addWidget(mainWidgetContainer, 1); QHBoxLayout *mainWidgetContainerLyr = new QHBoxLayout(mainWidgetContainer); mainWidgetContainerLyr->setContentsMargins(0, 0, 0, 0); mainWidgetContainerLyr->setSpacing(0); KMultiTabBar *mtbar = new KMultiTabBar(KMultiTabBar::Left); mtbar->setStyle(KMultiTabBar::VSNET); mainWidgetContainerLyr->addWidget(mtbar); d->multiTabBars.insert(mtbar->position(), mtbar); d->mainWidget = new KexiMainWidget(); d->mainWidget->setParent(this); d->mainWidget->tabWidget()->setTabsClosable(true); connect(d->mainWidget->tabWidget(), SIGNAL(tabCloseRequested(int)), this, SLOT(closeWindowForTab(int))); mainWidgetContainerLyr->addWidget(d->mainWidget, 1); mtbar = new KMultiTabBar(KMultiTabBar::Right); mtbar->setStyle(KMultiTabBar::VSNET); mainWidgetContainerLyr->addWidget(mtbar); d->multiTabBars.insert(mtbar->position(), mtbar); } void KexiMainWindow::slotSetProjectNavigatorVisible(bool set) { if (d->navDockWidget) d->navDockWidget->setVisible(set); } void KexiMainWindow::slotSetPropertyEditorVisible(bool set) { if (d->propEditorDockWidget) d->propEditorDockWidget->setVisible(set); } void KexiMainWindow::slotProjectNavigatorVisibilityChanged(bool visible) { d->setTabBarVisible(KMultiTabBar::Left, PROJECT_NAVIGATOR_TABBAR_ID, d->navDockWidget, !visible); } void KexiMainWindow::slotPropertyEditorVisibilityChanged(bool visible) { if (!d->enable_slotPropertyEditorVisibilityChanged) return; d->setPropertyEditorTabBarVisible(!visible); if (!visible) d->propertyEditorCollapsed = true; } void KexiMainWindow::slotMultiTabBarTabClicked(int id) { if (id == PROJECT_NAVIGATOR_TABBAR_ID) { slotProjectNavigatorVisibilityChanged(true); d->navDockWidget->show(); } else if (id == PROPERTY_EDITOR_TABBAR_ID) { slotPropertyEditorVisibilityChanged(true); d->propEditorDockWidget->show(); d->propertyEditorCollapsed = false; } } static Qt::DockWidgetArea applyRightToLeftToDockArea(Qt::DockWidgetArea area) { if (QApplication::layoutDirection() == Qt::RightToLeft) { if (area == Qt::LeftDockWidgetArea) { return Qt::RightDockWidgetArea; } else if (area == Qt::RightDockWidgetArea) { return Qt::LeftDockWidgetArea; } } return area; } void KexiMainWindow::setupProjectNavigator() { if (!d->isProjectNavigatorVisible) return; if (d->navigator) { d->navDockWidget->show(); } else { KexiDockableWidget* navDockableWidget = new KexiDockableWidget; d->navigator = new KexiProjectNavigator(navDockableWidget); kexiTester() << KexiTestObject(d->navigator, "KexiProjectNavigator"); navDockableWidget->setWidget(d->navigator); d->navDockWidget = new KexiDockWidget(d->navigator->windowTitle(), d->mainWidget); d->navDockWidget->setObjectName("ProjectNavigatorDockWidget"); d->mainWidget->addDockWidget( applyRightToLeftToDockArea(Qt::LeftDockWidgetArea), d->navDockWidget, Qt::Vertical); navDockableWidget->setParent(d->navDockWidget); d->navDockWidget->setWidget(navDockableWidget); KConfigGroup mainWindowGroup(d->config->group("MainWindow")); const QSize projectNavigatorSize = mainWindowGroup.readEntry("ProjectNavigatorSize", QSize()); if (!projectNavigatorSize.isNull()) { navDockableWidget->setSizeHint(projectNavigatorSize); } connect(d->navDockWidget, SIGNAL(visibilityChanged(bool)), this, SLOT(slotProjectNavigatorVisibilityChanged(bool))); //Nav2 Signals connect(d->navigator, SIGNAL(openItem(KexiPart::Item*,Kexi::ViewMode)), this, SLOT(openObject(KexiPart::Item*,Kexi::ViewMode))); connect(d->navigator, SIGNAL(openOrActivateItem(KexiPart::Item*,Kexi::ViewMode)), this, SLOT(openObjectFromNavigator(KexiPart::Item*,Kexi::ViewMode))); connect(d->navigator, SIGNAL(newItem(KexiPart::Info*)), this, SLOT(newObject(KexiPart::Info*))); connect(d->navigator, SIGNAL(removeItem(KexiPart::Item*)), this, SLOT(removeObject(KexiPart::Item*))); connect(d->navigator->model(), SIGNAL(renameItem(KexiPart::Item*,QString,bool*)), this, SLOT(renameObject(KexiPart::Item*,QString,bool*))); connect(d->navigator->model(), SIGNAL(changeItemCaption(KexiPart::Item*,QString,bool*)), this, SLOT(setObjectCaption(KexiPart::Item*,QString,bool*))); connect(d->navigator, SIGNAL(executeItem(KexiPart::Item*)), this, SLOT(executeItem(KexiPart::Item*))); connect(d->navigator, SIGNAL(exportItemToClipboardAsDataTable(KexiPart::Item*)), this, SLOT(copyItemToClipboardAsDataTable(KexiPart::Item*))); connect(d->navigator, SIGNAL(exportItemToFileAsDataTable(KexiPart::Item*)), this, SLOT(exportItemAsDataTable(KexiPart::Item*))); #ifdef KEXI_QUICK_PRINTING_SUPPORT connect(d->navigator, SIGNAL(printItem(KexiPart::Item*)), this, SLOT(printItem(KexiPart::Item*))); connect(d->navigator, SIGNAL(pageSetupForItem(KexiPart::Item*)), this, SLOT(showPageSetupForItem(KexiPart::Item*))); #endif connect(d->navigator, SIGNAL(selectionChanged(KexiPart::Item*)), this, SLOT(slotPartItemSelectedInNavigator(KexiPart::Item*))); } if (d->prj->isConnected()) { QString partManagerErrorMessages; if (!partManagerErrorMessages.isEmpty()) { showWarningContinueMessage(partManagerErrorMessages, QString(), "ShowWarningsRelatedToPluginsLoading"); } d->navigator->setProject(d->prj, QString()/*all classes*/, &partManagerErrorMessages); } connect(d->prj, SIGNAL(newItemStored(KexiPart::Item*)), d->navigator->model(), SLOT(slotAddItem(KexiPart::Item*))); connect(d->prj, SIGNAL(itemRemoved(KexiPart::Item)), d->navigator->model(), SLOT(slotRemoveItem(KexiPart::Item))); d->navigator->setFocus(); if (d->forceShowProjectNavigatorOnCreation) { slotShowNavigator(); d->forceShowProjectNavigatorOnCreation = false; } else if (d->forceHideProjectNavigatorOnCreation) { d->forceHideProjectNavigatorOnCreation = false; } invalidateActions(); } void KexiMainWindow::slotLastActions() { } void KexiMainWindow::setupPropertyEditor() { if (!d->propEditor) { KConfigGroup mainWindowGroup(d->config->group("MainWindow")); //! @todo FIX LAYOUT PROBLEMS d->propEditorDockWidget = new KexiDockWidget(xi18n("Property Editor"), d->mainWidget); d->propEditorDockWidget->setObjectName("PropertyEditorDockWidget"); d->mainWidget->addDockWidget( applyRightToLeftToDockArea(Qt::RightDockWidgetArea), d->propEditorDockWidget, Qt::Vertical ); connect(d->propEditorDockWidget, SIGNAL(visibilityChanged(bool)), this, SLOT(slotPropertyEditorVisibilityChanged(bool))); d->propEditorDockableWidget = new KexiDockableWidget(d->propEditorDockWidget); d->propEditorDockWidget->setWidget(d->propEditorDockableWidget); const QSize propertyEditorSize = mainWindowGroup.readEntry("PropertyEditorSize", QSize()); if (!propertyEditorSize.isNull()) { d->propEditorDockableWidget->setSizeHint(propertyEditorSize); } QWidget *propEditorDockWidgetContents = new QWidget(d->propEditorDockableWidget); d->propEditorDockableWidget->setWidget(propEditorDockWidgetContents); QVBoxLayout *propEditorDockWidgetContentsLyr = new QVBoxLayout(propEditorDockWidgetContents); propEditorDockWidgetContentsLyr->setContentsMargins(0, 0, 0, 0); d->propEditorTabWidget = new QTabWidget(propEditorDockWidgetContents); d->propEditorTabWidget->setDocumentMode(true); propEditorDockWidgetContentsLyr->addWidget(d->propEditorTabWidget); d->propEditor = new KexiPropertyEditorView(d->propEditorTabWidget); d->propEditorTabWidget->setWindowTitle(d->propEditor->windowTitle()); d->propEditorTabWidget->addTab(d->propEditor, xi18n("Properties")); //! @todo REMOVE? d->propEditor->installEventFilter(this); KConfigGroup propertyEditorGroup(d->config->group("PropertyEditor")); QFont f(KexiUtils::smallestReadableFont()); const qreal pointSizeF = propertyEditorGroup.readEntry("FontPointSize", -1.0f); // points are more accurate if (pointSizeF > 0.0) { f.setPointSizeF(pointSizeF); } else { - const int pixelSize = propertyEditorGroup.readEntry("FontSize", -1); // compatibility with Kexi 2.x + const int pixelSize = propertyEditorGroup.readEntry("FontSize", -1); // compatibility with KEXI 2.x if (pixelSize > 0) { f.setPixelSize(pixelSize); } } d->propEditorTabWidget->setFont(f); d->enable_slotPropertyEditorVisibilityChanged = false; d->propEditorDockWidget->setVisible(false); d->enable_slotPropertyEditorVisibilityChanged = true; } } void KexiMainWindow::slotPartLoaded(KexiPart::Part* p) { if (!p) return; p->createGUIClients(); } void KexiMainWindow::updateAppCaption() { //! @todo allow to set custom "static" app caption d->appCaptionPrefix.clear(); if (d->prj && d->prj->data()) {//add project name d->appCaptionPrefix = d->prj->data()->caption(); if (d->appCaptionPrefix.isEmpty()) { d->appCaptionPrefix = d->prj->data()->databaseName(); } if (d->prj->dbConnection()->options()->isReadOnly()) { d->appCaptionPrefix = xi18nc(" (read only)", "%1 (read only)", d->appCaptionPrefix); } } setWindowTitle(d->appCaptionPrefix); } bool KexiMainWindow::queryClose() { #ifndef KEXI_NO_PENDING_DIALOGS if (d->pendingWindowsExist()) { qDebug() << "pendingWindowsExist..."; d->actionToExecuteWhenPendingJobsAreFinished = Private::QuitAction; return false; } #endif const tristate res = closeProject(); if (~res) return false; if (res == true) storeSettings(); if (! ~res) { Kexi::deleteGlobalObjects(); qApp->quit(); } return ! ~res; } void KexiMainWindow::closeEvent(QCloseEvent *ev) { d->mainWidget->closeEvent(ev); } static const QSize KEXI_MIN_WINDOW_SIZE(1024, 768); void KexiMainWindow::restoreSettings() { KConfigGroup mainWindowGroup(d->config->group("MainWindow")); const bool maximize = mainWindowGroup.readEntry("Maximized", false); const QRect geometry(mainWindowGroup.readEntry("Geometry", QRect())); if (geometry.isValid()) setGeometry(geometry); else if (maximize) setWindowState(windowState() | Qt::WindowMaximized); else { QRect desk = QApplication::desktop()->screenGeometry( QApplication::desktop()->screenNumber(this)); if (desk.width() <= KEXI_MIN_WINDOW_SIZE.width() || desk.height() <= KEXI_MIN_WINDOW_SIZE.height()) { setWindowState(windowState() | Qt::WindowMaximized); } else { resize(KEXI_MIN_WINDOW_SIZE); } } // Saved settings } void KexiMainWindow::storeSettings() { //qDebug(); KConfigGroup mainWindowGroup(d->config->group("MainWindow")); if (isMaximized()) { mainWindowGroup.writeEntry("Maximized", true); mainWindowGroup.deleteEntry("Geometry"); } else { mainWindowGroup.deleteEntry("Maximized"); mainWindowGroup.writeEntry("Geometry", geometry()); } if (d->navigator) mainWindowGroup.writeEntry("ProjectNavigatorSize", d->navigator->parentWidget()->size()); if (d->propEditorDockableWidget) mainWindowGroup.writeEntry("PropertyEditorSize", d->propEditorDockableWidget->size()); d->config->sync(); } void KexiMainWindow::registerChild(KexiWindow *window) { //qDebug(); connect(window, SIGNAL(dirtyChanged(KexiWindow*)), this, SLOT(slotDirtyFlagChanged(KexiWindow*))); if (window->id() != -1) { d->insertWindow(window); } //qDebug() << "ID=" << window->id(); } void KexiMainWindow::updateCustomPropertyPanelTabs(KexiWindow *prevWindow, Kexi::ViewMode prevViewMode) { updateCustomPropertyPanelTabs( prevWindow ? prevWindow->part() : 0, prevWindow ? prevWindow->currentViewMode() : prevViewMode, currentWindow() ? currentWindow()->part() : 0, currentWindow() ? currentWindow()->currentViewMode() : Kexi::NoViewMode ); } void KexiMainWindow::updateCustomPropertyPanelTabs( KexiPart::Part *prevWindowPart, Kexi::ViewMode prevViewMode, KexiPart::Part *curWindowPart, Kexi::ViewMode curViewMode) { if (!d->propEditorTabWidget) return; if ( !curWindowPart || (/*prevWindowPart &&*/ curWindowPart && (prevWindowPart != curWindowPart || prevViewMode != curViewMode) ) ) { if (d->partForPreviouslySetupPropertyPanelTabs) { //remember current page number for this part if (( prevViewMode == Kexi::DesignViewMode && static_cast(d->partForPreviouslySetupPropertyPanelTabs) != curWindowPart) //part changed || curViewMode != Kexi::DesignViewMode) { //..or switching to other view mode d->recentlySelectedPropertyPanelPages.insert( d->partForPreviouslySetupPropertyPanelTabs, d->propEditorTabWidget->currentIndex()); } } //delete old custom tabs (other than 'property' tab) const int count = d->propEditorTabWidget->count(); for (int i = 1; i < count; i++) d->propEditorTabWidget->removeTab(1); } //don't change anything if part is not switched nor view mode changed if ((!prevWindowPart && !curWindowPart) || (prevWindowPart == curWindowPart && prevViewMode == curViewMode) || (curWindowPart && curViewMode != Kexi::DesignViewMode)) { //new part for 'previously setup tabs' d->partForPreviouslySetupPropertyPanelTabs = curWindowPart; return; } if (curWindowPart) { //recreate custom tabs curWindowPart->setupCustomPropertyPanelTabs(d->propEditorTabWidget); //restore current page number for this part if (d->recentlySelectedPropertyPanelPages.contains(curWindowPart)) { d->propEditorTabWidget->setCurrentIndex( d->recentlySelectedPropertyPanelPages[ curWindowPart ] ); } } //new part for 'previously setup tabs' d->partForPreviouslySetupPropertyPanelTabs = curWindowPart; } void KexiMainWindow::activeWindowChanged(KexiWindow *window, KexiWindow *prevWindow) { //qDebug() << "to=" << (window ? window->windowTitle() : ""); bool windowChanged = prevWindow != window; if (windowChanged) { if (prevWindow) { //inform previously activated dialog about deactivation prevWindow->deactivate(); } } updateCustomPropertyPanelTabs(prevWindow, prevWindow ? prevWindow->currentViewMode() : Kexi::NoViewMode); // inform the current view of the new dialog about property switching // (this will also call KexiMainWindow::propertySetSwitched() to update the current property editor's set if (windowChanged && currentWindow()) currentWindow()->selectedView()->propertySetSwitched(); if (windowChanged) { if (currentWindow() && currentWindow()->currentViewMode() != 0 && window) { //on opening new dialog it can be 0; we don't want this d->updatePropEditorVisibility(currentWindow()->currentViewMode()); restoreDesignTabIfNeeded(window->partItem()->pluginId(), window->currentViewMode(), prevWindow ? prevWindow->partItem()->identifier() : 0); activateDesignTabIfNeeded(window->partItem()->pluginId(), window->currentViewMode()); } } invalidateActions(); d->updateFindDialogContents(); if (window) window->setFocus(); } bool KexiMainWindow::activateWindow(int id) { #ifndef KEXI_NO_PENDING_DIALOGS Private::PendingJobType pendingType; return activateWindow(*d->openedWindowFor(id, pendingType)); #else return activateWindow(*d->openedWindowFor(id)); #endif } bool KexiMainWindow::activateWindow(KexiWindow& window) { //qDebug(); d->focus_before_popup = &window; d->mainWidget->tabWidget()->setCurrentWidget(window.parentWidget()/*container*/); window.activate(); return true; } void KexiMainWindow::activateNextWindow() { //! @todo activateNextWindow() } void KexiMainWindow::activatePreviousWindow() { //! @todo activatePreviousWindow() } void KexiMainWindow::slotSettings() { if (d->tabbedToolBar) { d->tabbedToolBar->showMainMenu("settings"); // dummy QLabel *dummy = KEXI_UNFINISHED_LABEL(actionCollection()->action("settings")->text()); d->tabbedToolBar->setMainMenuContent(dummy); } } void KexiMainWindow::slotConfigureKeys() { KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsDisallowed, this); } void KexiMainWindow::slotConfigureToolbars() { KEditToolBar edit(actionCollection()); (void) edit.exec(); } void KexiMainWindow::slotProjectNew() { createNewProject(); } KexiProject* KexiMainWindow::createKexiProjectObject(const KexiProjectData &data) { KexiProject *prj = new KexiProject(data, this); connect(prj, SIGNAL(itemRenamed(KexiPart::Item,QString)), this, SLOT(slotObjectRenamed(KexiPart::Item,QString))); if (d->navigator){ connect(prj, SIGNAL(itemRemoved(KexiPart::Item)), d->navigator->model(), SLOT(slotRemoveItem(KexiPart::Item))); } return prj; } void KexiMainWindow::createNewProject() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_new"); KexiNewProjectAssistant* assistant = new KexiNewProjectAssistant; connect(assistant, SIGNAL(createProject(KexiProjectData)), this, SLOT(createNewProject(KexiProjectData))); d->tabbedToolBar->setMainMenuContent(assistant); } tristate KexiMainWindow::createNewProject(const KexiProjectData &projectData) { QScopedPointer prj(createKexiProjectObject(projectData)); tristate res = prj->create(true /*overwrite*/); if (res != true) { return res; } //qDebug() << "new project created ---"; if (d->prj) { res = openProjectInExternalKexiInstance( prj->data()->connectionData()->databaseName(), prj->data()->connectionData(), prj->data()->databaseName()); Kexi::recentProjects()->addProjectData(*prj->data()); if (d->tabbedToolBar) { d->tabbedToolBar->hideMainMenu(); } return res; } if (d->tabbedToolBar) { d->tabbedToolBar->hideMainMenu(); } d->prj = prj.take(); setupProjectNavigator(); d->prj->data()->setLastOpened(QDateTime::currentDateTime()); Kexi::recentProjects()->addProjectData(*d->prj->data()); invalidateActions(); updateAppCaption(); return true; } void KexiMainWindow::slotProjectOpen() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_open"); KexiOpenProjectAssistant* assistant = new KexiOpenProjectAssistant; connect(assistant, SIGNAL(openProject(KexiProjectData)), this, SLOT(openProject(KexiProjectData))); connect(assistant, SIGNAL(openProject(QString)), this, SLOT(openProject(QString))); d->tabbedToolBar->setMainMenuContent(assistant); } tristate KexiMainWindow::openProject(const QString& aFileName) { return openProject(aFileName, QString(), QString()); } tristate KexiMainWindow::openProject(const QString& aFileName, const QString& fileNameForConnectionData, const QString& dbName) { if (d->prj) return openProjectInExternalKexiInstance(aFileName, fileNameForConnectionData, dbName); KDbConnectionData *cdata = 0; if (!fileNameForConnectionData.isEmpty()) { cdata = Kexi::connset().connectionDataForFileName(fileNameForConnectionData); if (!cdata) { qWarning() << "cdata?"; return false; } } return openProject(aFileName, cdata, dbName); } tristate KexiMainWindow::openProject(const QString& aFileName, KDbConnectionData *cdata, const QString& dbName, const KexiProjectData::AutoOpenObjects& autoopenObjects) { if (d->prj) { return openProjectInExternalKexiInstance(aFileName, cdata, dbName); } KexiProjectData* projectData = 0; const KexiStartupHandler *h = KexiStartupHandler::global(); bool readOnly = h->isSet(h->options().readOnly); bool deleteAfterOpen = false; if (cdata) { //server-based project if (dbName.isEmpty()) {//no database name given, ask user bool cancel; projectData = KexiStartupHandler::global()->selectProject(cdata, &cancel, this); if (cancel) return cancelled; } else { //! @todo caption arg? projectData = new KexiProjectData(*cdata, dbName); deleteAfterOpen = true; } } else { if (aFileName.isEmpty()) { qWarning() << "aFileName.isEmpty()"; return false; } //file-based project qDebug() << "Project File: " << aFileName; KDbConnectionData fileConnData; fileConnData.setDatabaseName(aFileName); QString detectedDriverId; int detectOptions = 0; if (readOnly) { detectOptions |= KexiStartupHandler::OpenReadOnly; } KexiStartupData::Import importActionData; bool forceReadOnly; const tristate res = KexiStartupHandler::detectActionForFile( &importActionData, &detectedDriverId, fileConnData.driverId(), aFileName, this, detectOptions, &forceReadOnly); if (forceReadOnly) { readOnly = true; } if (true != res) return res; if (importActionData) { //importing requested return showProjectMigrationWizard(importActionData.mimeType, importActionData.fileName); } fileConnData.setDriverId(detectedDriverId); if (fileConnData.driverId().isEmpty()) return false; //opening requested projectData = new KexiProjectData(fileConnData); deleteAfterOpen = true; } if (!projectData) return false; projectData->setReadOnly(readOnly); projectData->autoopenObjects = autoopenObjects; const tristate res = openProject(*projectData); if (deleteAfterOpen) //projectData object has been copied delete projectData; return res; } tristate KexiMainWindow::openProjectInExternalKexiInstance(const QString& aFileName, KDbConnectionData *cdata, const QString& dbName) { QString fileNameForConnectionData; if (aFileName.isEmpty()) { //try .kexic file if (cdata) fileNameForConnectionData = Kexi::connset().fileNameForConnectionData(*cdata); } return openProjectInExternalKexiInstance(aFileName, fileNameForConnectionData, dbName); } tristate KexiMainWindow::openProjectInExternalKexiInstance(const QString& aFileName, const QString& fileNameForConnectionData, const QString& dbName) { QString fileName(aFileName); QStringList args; // open a file-based project or a server connection provided as a .kexic file // (we have no other simple way to provide the startup data to a new process) if (fileName.isEmpty()) { //try .kexic file if (!fileNameForConnectionData.isEmpty()) args << "--skip-conn-dialog"; //user does not expect conn. dialog to be shown here if (dbName.isEmpty()) { //use 'kexi --skip-conn-dialog file.kexic' fileName = fileNameForConnectionData; } else { //use 'kexi --skip-conn-dialog --connection file.kexic dbName' if (fileNameForConnectionData.isEmpty()) { qWarning() << "fileNameForConnectionData?"; return false; } args << "--connection" << fileNameForConnectionData; fileName = dbName; } } if (fileName.isEmpty()) { qWarning() << "fileName?"; return false; } //! @todo use KRun //! @todo untested //Can arguments be supplied to KRun like is used here? AP args << fileName; const bool ok = QProcess::startDetached( qApp->applicationFilePath(), args, QFileInfo(fileName).absoluteDir().absolutePath()); if (!ok) { d->showStartProcessMsg(args); } if (d->tabbedToolBar) { d->tabbedToolBar->hideMainMenu(); } return ok; } void KexiMainWindow::slotProjectWelcome() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_welcome"); KexiWelcomeAssistant* assistant = new KexiWelcomeAssistant( Kexi::recentProjects(), this); connect(assistant, SIGNAL(openProject(KexiProjectData,QString,bool*)), this, SLOT(openProject(KexiProjectData,QString,bool*))); d->tabbedToolBar->setMainMenuContent(assistant); } void KexiMainWindow::slotProjectSave() { if (!currentWindow() || currentWindow()->currentViewMode() == Kexi::DataViewMode) { return; } saveObject(currentWindow()); updateAppCaption(); invalidateActions(); } void KexiMainWindow::slotProjectSaveAs() { if (!currentWindow() || currentWindow()->currentViewMode() == Kexi::DataViewMode) { return; } saveObject(currentWindow(), QString(), SaveObjectAs); updateAppCaption(); invalidateActions(); } void KexiMainWindow::slotProjectPrint() { #ifdef KEXI_QUICK_PRINTING_SUPPORT if (currentWindow() && currentWindow()->partItem()) printItem(currentWindow()->partItem()); #endif } void KexiMainWindow::slotProjectPrintPreview() { #ifdef KEXI_QUICK_PRINTING_SUPPORT if (currentWindow() && currentWindow()->partItem()) printPreviewForItem(currentWindow()->partItem()); #endif } void KexiMainWindow::slotProjectPageSetup() { #ifdef KEXI_QUICK_PRINTING_SUPPORT if (currentWindow() && currentWindow()->partItem()) showPageSetupForItem(currentWindow()->partItem()); #endif } void KexiMainWindow::slotProjectExportDataTable() { if (currentWindow() && currentWindow()->partItem()) exportItemAsDataTable(currentWindow()->partItem()); } void KexiMainWindow::slotProjectProperties() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_properties"); // dummy QLabel *dummy = KEXI_UNFINISHED_LABEL(actionCollection()->action("project_properties")->text()); d->tabbedToolBar->setMainMenuContent(dummy); //! @todo load the implementation not the ui :) // ProjectSettingsUI u(this); // u.exec(); } void KexiMainWindow::slotProjectImportExportOrSend() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_import_export_send"); KexiImportExportAssistant* assistant = new KexiImportExportAssistant( d->action_project_import_export_send, d->action_tools_import_project); connect(assistant, SIGNAL(importProject()), this, SLOT(slotToolsImportProject())); d->tabbedToolBar->setMainMenuContent(assistant); } void KexiMainWindow::slotProjectClose() { closeProject(); } void KexiMainWindow::slotProjectRelations() { if (!d->prj) return; KexiWindow *w = KexiInternalPart::createKexiWindowInstance("org.kexi-project.relations", this); activateWindow(*w); } void KexiMainWindow::slotImportFile() { KEXI_UNFINISHED("Import: " + xi18n("From File...")); } void KexiMainWindow::slotImportServer() { KEXI_UNFINISHED("Import: " + xi18n("From Server...")); } void KexiMainWindow::slotProjectQuit() { if (~ closeProject()) return; close(); } void KexiMainWindow::slotActivateNavigator() { if (!d->navigator) { return; } d->navigator->setFocus(); } void KexiMainWindow::slotActivateMainArea() { if (currentWindow()) currentWindow()->setFocus(); } void KexiMainWindow::slotActivatePropertyEditor() { if (!d->propEditor) { return; } if (d->propEditorTabWidget->currentWidget()) d->propEditorTabWidget->currentWidget()->setFocus(); } void KexiMainWindow::slotShowNavigator() { if (d->navDockWidget) d->navDockWidget->setVisible(!d->navDockWidget->isVisible()); } void KexiMainWindow::slotShowPropertyEditor() { if (d->propEditorDockWidget) d->propEditorDockWidget->setVisible(!d->propEditorDockWidget->isVisible()); } tristate KexiMainWindow::switchToViewMode(KexiWindow& window, Kexi::ViewMode viewMode) { const Kexi::ViewMode prevViewMode = currentWindow()->currentViewMode(); if (prevViewMode == viewMode) return true; if (!activateWindow(window)) return false; if (!currentWindow()) { return false; } if (&window != currentWindow()) return false; if (!currentWindow()->supportsViewMode(viewMode)) { showErrorMessage(xi18nc("@info", "Selected view is not supported for %1 object.", currentWindow()->partItem()->name()), xi18nc("@info", "Selected view (%1) is not supported by this object type (%2).", Kexi::nameForViewMode(viewMode), currentWindow()->part()->info()->name())); return false; } updateCustomPropertyPanelTabs(currentWindow()->part(), prevViewMode, currentWindow()->part(), viewMode); tristate res = currentWindow()->switchToViewMode(viewMode); if (!res) { updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert showErrorMessage(xi18n("Switching to other view failed (%1).", Kexi::nameForViewMode(viewMode)), currentWindow()); return false; } if (~res) { updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert return cancelled; } activateWindow(window); invalidateSharedActions(); invalidateProjectWideActions(); d->updateFindDialogContents(); d->updatePropEditorVisibility(viewMode); QString origTabToActivate; if (viewMode == Kexi::DesignViewMode) { // Save the orig tab: we want to back to design tab // when user moved to data view and then immediately to design view. origTabToActivate = d->tabsToActivateOnShow.value(currentWindow()->partItem()->identifier()); } restoreDesignTabIfNeeded(currentWindow()->partItem()->pluginId(), viewMode, currentWindow()->partItem()->identifier()); if (viewMode == Kexi::DesignViewMode) { activateDesignTab(currentWindow()->partItem()->pluginId()); // Restore the saved tab to the orig one. restoreDesignTabIfNeeded() saved tools tab probably. d->tabsToActivateOnShow.insert(currentWindow()->partItem()->identifier(), origTabToActivate); } return true; } void KexiMainWindow::slotViewDataMode() { if (currentWindow()) switchToViewMode(*currentWindow(), Kexi::DataViewMode); } void KexiMainWindow::slotViewDesignMode() { if (currentWindow()) switchToViewMode(*currentWindow(), Kexi::DesignViewMode); } void KexiMainWindow::slotViewTextMode() { if (currentWindow()) switchToViewMode(*currentWindow(), Kexi::TextViewMode); } //! Used to control if we're not Saving-As object under the original name class SaveAsObjectNameValidator : public KexiNameDialogValidator { public: SaveAsObjectNameValidator(const QString &originalObjectName) : m_originalObjectName(originalObjectName) { } virtual bool validate(KexiNameDialog *dialog) const { if (dialog->widget()->nameText() == m_originalObjectName) { KMessageBox::information(dialog, xi18nc("Could not save object under the original name.", "Could not save under the original name.")); return false; } return true; } private: QString m_originalObjectName; }; tristate KexiMainWindow::getNewObjectInfo( KexiPart::Item *partItem, const QString &originalName, KexiPart::Part *part, bool allowOverwriting, bool *overwriteNeeded, const QString& messageWhenAskingForName) { //data was never saved in the past -we need to create a new object at the backend KexiPart::Info *info = part->info(); if (!d->nameDialog) { d->nameDialog = new KexiNameDialog( messageWhenAskingForName, this); //check if that name is allowed d->nameDialog->widget()->addNameSubvalidator( new KDbObjectNameValidator(project()->dbConnection()->driver())); d->nameDialog->buttonBox()->button(QDialogButtonBox::Ok)->setText(xi18nc("@action:button Save object", "Save")); } else { d->nameDialog->widget()->setMessageText(messageWhenAskingForName); } d->nameDialog->widget()->setCaptionText(partItem->caption()); d->nameDialog->widget()->setNameText(partItem->name()); d->nameDialog->setWindowTitle(xi18nc("@title:window", "Save Object As")); d->nameDialog->setDialogIcon(info->iconName()); d->nameDialog->setAllowOverwriting(allowOverwriting); if (!originalName.isEmpty()) { d->nameDialog->setValidator(new SaveAsObjectNameValidator(originalName)); } if (d->nameDialog->execAndCheckIfObjectExists(*project(), *part, overwriteNeeded) != QDialog::Accepted) { return cancelled; } // close window of object that will be overwritten if (*overwriteNeeded) { KexiPart::Item* overwrittenItem = project()->item(info, d->nameDialog->widget()->nameText()); if (overwrittenItem) { KexiWindow * openedWindow = d->openedWindowFor(overwrittenItem->identifier()); if (openedWindow) { const tristate res = closeWindow(openedWindow); if (res != true) { return res; } } } } //update name and caption partItem->setName(d->nameDialog->widget()->nameText()); partItem->setCaption(d->nameDialog->widget()->captionText()); return true; } //! Used to delete part item on exit from block class PartItemDeleter : public QScopedPointer { public: explicit PartItemDeleter(KexiProject *prj) : m_prj(prj) {} ~PartItemDeleter() { if (!isNull()) { m_prj->deleteUnstoredItem(take()); } } private: KexiProject *m_prj; }; static void showSavingObjectFailedErrorMessage(KexiMainWindow *wnd, KexiPart::Item *item) { wnd->showErrorMessage( xi18nc("@info Saving object failed", "Saving %1 object failed.", item->name()), wnd->currentWindow()); } tristate KexiMainWindow::saveObject(KexiWindow *window, const QString& messageWhenAskingForName, SaveObjectOptions options) { tristate res; bool saveAs = options & SaveObjectAs; if (!saveAs && !window->neverSaved()) { //data was saved in the past -just save again res = window->storeData(options & DoNotAsk); if (!res) { showSavingObjectFailedErrorMessage(this, window->partItem()); } return res; } if (saveAs && window->neverSaved()) { //if never saved, saveAs == save saveAs = false; } const int oldItemID = window->partItem()->identifier(); KexiPart::Item *partItem; KexiView::StoreNewDataOptions storeNewDataOptions; PartItemDeleter itemDeleter(d->prj); if (saveAs) { partItem = d->prj->createPartItem(window->part()); if (!partItem) { //! @todo error return false; } itemDeleter.reset(partItem); } else { partItem = window->partItem(); } bool overwriteNeeded; res = getNewObjectInfo(partItem, saveAs ? window->partItem()->name() : QString(), window->part(), true /*allowOverwriting*/, &overwriteNeeded, messageWhenAskingForName); if (res != true) return res; if (overwriteNeeded) { storeNewDataOptions |= KexiView::OverwriteExistingData; } if (saveAs) { res = window->storeDataAs(partItem, storeNewDataOptions); } else { res = window->storeNewData(storeNewDataOptions); } if (~res) return cancelled; if (!res) { showSavingObjectFailedErrorMessage(this, partItem); return false; } d->updateWindowId(window, oldItemID); invalidateProjectWideActions(); itemDeleter.take(); return true; } tristate KexiMainWindow::closeWindow(KexiWindow *window) { return closeWindow(window ? window : currentWindow(), true); } tristate KexiMainWindow::closeCurrentWindow() { return closeWindow(0); } tristate KexiMainWindow::closeWindowForTab(int tabIndex) { KexiWindow* window = windowForTab(tabIndex); if (!window) return false; return closeWindow(window); } tristate KexiMainWindow::closeWindow(KexiWindow *window, bool layoutTaskBar, bool doNotSaveChanges) { //! @todo KEXI3 KexiMainWindow::closeWindow() ///@note Q_UNUSED layoutTaskBar Q_UNUSED(layoutTaskBar); if (!window) return true; if (d->insideCloseWindow) return true; const int previousItemId = window->partItem()->identifier(); #ifndef KEXI_NO_PENDING_DIALOGS d->addItemToPendingWindows(window->partItem(), Private::WindowClosingJob); #endif d->insideCloseWindow = true; if (window == currentWindow() && !window->isAttached()) { if (d->propEditor) { // ah, closing detached window - better switch off property buffer right now... d->propertySet = 0; d->propEditor->editor()->changeSet(0); } } bool remove_on_closing = window->partItem() ? window->partItem()->neverSaved() : false; if (window->isDirty() && !d->forceWindowClosing && !doNotSaveChanges) { //more accurate tool tips and what's this KGuiItem saveChanges(KStandardGuiItem::save()); saveChanges.setToolTip(xi18n("Save changes")); saveChanges.setWhatsThis( xi18nc("@info", "Saves all recent changes made in %1 object.", window->partItem()->name())); KGuiItem discardChanges(KStandardGuiItem::discard()); discardChanges.setWhatsThis( xi18nc("@info", "Discards all recent changes made in %1 object.", window->partItem()->name())); //dialog's data is dirty: //--adidional message, e.g. table designer will return // "Note: This table is already filled with data which will be removed." // if the window is in design view mode. const KLocalizedString additionalMessage( window->part()->i18nMessage(":additional message before saving design", window)); QString additionalMessageString; if (!additionalMessage.isEmpty()) additionalMessageString = additionalMessage.toString(); if (additionalMessageString.startsWith(':')) additionalMessageString.clear(); if (!additionalMessageString.isEmpty()) additionalMessageString = "

    " + additionalMessageString + "

    "; const KMessageBox::ButtonCode questionRes = KMessageBox::warningYesNoCancel(this, "

    " + window->part()->i18nMessage("Design of object %1 has been modified.", window) .subs(window->partItem()->name()).toString() + "

    " + xi18n("Do you want to save changes?") + "

    " + additionalMessageString /*may be empty*/, QString(), saveChanges, discardChanges); if (questionRes == KMessageBox::Cancel) { #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(window->id()); #endif d->insideCloseWindow = false; d->windowsToClose.clear(); //give up with 'close all' return cancelled; } if (questionRes == KMessageBox::Yes) { //save it tristate res = saveObject(window, QString(), DoNotAsk); if (!res || ~res) { //! @todo show error info; (retry/ignore/cancel) #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(window->id()); #endif d->insideCloseWindow = false; d->windowsToClose.clear(); //give up with 'close all' return res; } remove_on_closing = false; } } const int window_id = window->id(); //remember now, because removeObject() can destruct partitem object if (remove_on_closing) { //we won't save this object, and it was never saved -remove it if (!removeObject(window->partItem(), true)) { #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(window->id()); #endif //msg? //! @todo ask if we'd continue and return true/false d->insideCloseWindow = false; d->windowsToClose.clear(); //give up with 'close all' return false; } } else { //not dirty now if (d->navigator) { d->navigator->updateItemName(*window->partItem(), false); } } hideDesignTab(previousItemId, QString()); d->removeWindow(window_id); d->setWindowContainerExistsFor(window->partItem()->identifier(), false); QWidget *windowContainer = window->parentWidget(); d->mainWidget->tabWidget()->removeTab( d->mainWidget->tabWidget()->indexOf(windowContainer)); #ifdef KEXI_QUICK_PRINTING_SUPPORT //also remove from 'print setup dialogs' cache, if needed int printedObjectID = 0; if (d->pageSetupWindowItemID2dataItemID_map.contains(window_id)) printedObjectID = d->pageSetupWindowItemID2dataItemID_map[ window_id ]; d->pageSetupWindows.remove(printedObjectID); #endif delete windowContainer; //focus navigator if nothing else available if (d->openedWindowsCount() == 0) { if (d->navigator) { d->navigator->setFocus(); } d->updatePropEditorVisibility(Kexi::NoViewMode); } invalidateActions(); d->insideCloseWindow = false; if (!d->windowsToClose.isEmpty()) {//continue 'close all' KexiWindow* w = d->windowsToClose.takeAt(0); closeWindow(w, true); } #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(window_id); //perform pending global action that was suspended: if (!d->pendingWindowsExist()) { d->executeActionWhenPendingJobsAreFinished(); } #endif d->mainWidget->slotCurrentTabIndexChanged(d->mainWidget->tabWidget()->currentIndex()); showDesignTabIfNeeded(0); if (currentWindow()) { restoreDesignTabIfNeeded(currentWindow()->partItem()->pluginId(), currentWindow()->currentViewMode(), 0); } d->tabsToActivateOnShow.remove(previousItemId); return true; } QWidget* KexiMainWindow::findWindow(QWidget *w) { while (w && !acceptsSharedActions(w)) { if (w == d->propEditorDockWidget) return currentWindow(); w = w->parentWidget(); } return w; } KexiWindow* KexiMainWindow::openedWindowFor(int identifier) { return d->openedWindowFor(identifier); } KexiWindow* KexiMainWindow::openedWindowFor(const KexiPart::Item* item) { return item ? openedWindowFor(item->identifier()) : 0; } KDbQuerySchema* KexiMainWindow::unsavedQuery(int queryId) { KexiWindow * queryWindow = openedWindowFor(queryId); if (!queryWindow || !queryWindow->isDirty()) { return 0; } return queryWindow->part()->currentQuery(queryWindow->viewForMode(Kexi::DataViewMode)); } QList KexiMainWindow::currentParametersForQuery(int queryId) const { KexiWindow *queryWindow = d->openedWindowFor(queryId); if (!queryWindow) { return QList(); } KexiView *view = queryWindow->viewForMode(Kexi::DataViewMode); if (!view) { return QList(); } return view->currentParameters(); } bool KexiMainWindow::acceptsSharedActions(QObject *w) { return w->inherits("KexiWindow") || w->inherits("KexiView"); } bool KexiMainWindow::openingAllowed(KexiPart::Item* item, Kexi::ViewMode viewMode, QString* errorMessage) { //qDebug() << viewMode; //! @todo this can be more complex once we deliver ACLs... if (!d->userMode) return true; KexiPart::Part * part = Kexi::partManager().partForPluginId(item->pluginId()); if (!part) { if (errorMessage) { *errorMessage = Kexi::partManager().result().message(); } } //qDebug() << part << item->pluginId(); //if (part) // qDebug() << item->pluginId() << part->info()->supportedUserViewModes(); return part && (part->info()->supportedUserViewModes() & viewMode); } KexiWindow * KexiMainWindow::openObject(const QString& pluginId, const QString& name, Kexi::ViewMode viewMode, bool *openingCancelled, QMap* staticObjectArgs) { KexiPart::Item *item = d->prj->itemForPluginId(pluginId, name); if (!item) return 0; return openObject(item, viewMode, openingCancelled, staticObjectArgs); } KexiWindow * KexiMainWindow::openObject(KexiPart::Item* item, Kexi::ViewMode viewMode, bool *openingCancelled, QMap* staticObjectArgs, QString* errorMessage) { Q_ASSERT(openingCancelled); if (!d->prj || !item) { return 0; } if (!openingAllowed(item, viewMode, errorMessage)) { if (errorMessage) *errorMessage = xi18nc( "opening is not allowed in \"data view/design view/text view\" mode", "opening is not allowed in \"%1\" mode", Kexi::nameForViewMode(viewMode)); *openingCancelled = true; return 0; } //qDebug() << d->prj << item; KexiWindow *prevWindow = currentWindow(); KexiUtils::WaitCursor wait; #ifndef KEXI_NO_PENDING_DIALOGS Private::PendingJobType pendingType; KexiWindow *window = d->openedWindowFor(item, pendingType); if (pendingType != Private::NoJob) { *openingCancelled = true; return 0; } #else KexiWindow *window = openedWindowFor(item); #endif int previousItemId = currentWindow() ? currentWindow()->partItem()->identifier() : 0; *openingCancelled = false; bool alreadyOpened = false; KexiWindowContainer *windowContainer = 0; if (window) { if (viewMode != window->currentViewMode()) { if (true != switchToViewMode(*window, viewMode)) return 0; } else activateWindow(*window); alreadyOpened = true; } else { if (d->windowContainerExistsFor(item->identifier())) { // window not yet present but window container exists: return 0 and wait return 0; } KexiPart::Part *part = Kexi::partManager().partForPluginId(item->pluginId()); d->updatePropEditorVisibility(viewMode, part ? part->info() : 0); //update tabs before opening updateCustomPropertyPanelTabs(currentWindow() ? currentWindow()->part() : 0, currentWindow() ? currentWindow()->currentViewMode() : Kexi::NoViewMode, part, viewMode); // open new tab earlier windowContainer = new KexiWindowContainer(d->mainWidget->tabWidget()); d->setWindowContainerExistsFor(item->identifier(), true); const int tabIndex = d->mainWidget->tabWidget()->addTab( windowContainer, QIcon::fromTheme(part ? part->info()->iconName() : QString()), KexiWindow::windowTitleForItem(*item)); d->mainWidget->tabWidget()->setTabToolTip(tabIndex, KexiPart::fullCaptionForItem(item, part)); QString whatsThisText; if (part) { whatsThisText = xi18nc("@info", "Tab for %1 (%2).", item->captionOrName(), part->info()->name()); } else { whatsThisText = xi18nc("@info", "Tab for %1.", item->captionOrName()); } d->mainWidget->tabWidget()->setTabWhatsThis(tabIndex, whatsThisText); d->mainWidget->tabWidget()->setCurrentWidget(windowContainer); #ifndef KEXI_NO_PENDING_DIALOGS d->addItemToPendingWindows(item, Private::WindowOpeningJob); #endif window = d->prj->openObject(windowContainer, item, viewMode, staticObjectArgs); if (window) { windowContainer->setWindow(window); // update text and icon d->mainWidget->tabWidget()->setTabText( d->mainWidget->tabWidget()->indexOf(windowContainer), window->windowTitle()); d->mainWidget->tabWidget()->setTabIcon( d->mainWidget->tabWidget()->indexOf(windowContainer), window->windowIcon()); } } if (!window || !activateWindow(*window)) { #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(item->identifier()); #endif d->setWindowContainerExistsFor(item->identifier(), false); d->mainWidget->tabWidget()->removeTab( d->mainWidget->tabWidget()->indexOf(windowContainer)); delete windowContainer; updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert //! @todo add error msg... return 0; } if (viewMode != window->currentViewMode()) invalidateSharedActions(); #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(window->id()); //perform pending global action that was suspended: if (!d->pendingWindowsExist()) { d->executeActionWhenPendingJobsAreFinished(); } #endif if (window && !alreadyOpened) { // Call switchToViewMode() and propertySetSwitched() again here because // this is the time when then new window is the current one - previous call did nothing. switchToViewMode(*window, window->currentViewMode()); currentWindow()->selectedView()->propertySetSwitched(); } invalidateProjectWideActions(); restoreDesignTabIfNeeded(item->pluginId(), viewMode, previousItemId); activateDesignTabIfNeeded(item->pluginId(), viewMode); QString origTabToActivate; if (prevWindow) { // Save the orig tab for prevWindow that was stored in the restoreDesignTabIfNeeded() call above origTabToActivate = d->tabsToActivateOnShow.value(prevWindow->partItem()->identifier()); } activeWindowChanged(window, prevWindow); if (prevWindow) { // Restore the orig tab d->tabsToActivateOnShow.insert(prevWindow->partItem()->identifier(), origTabToActivate); } return window; } KexiWindow * KexiMainWindow::openObjectFromNavigator(KexiPart::Item* item, Kexi::ViewMode viewMode) { bool openingCancelled; return openObjectFromNavigator(item, viewMode, &openingCancelled); } KexiWindow * KexiMainWindow::openObjectFromNavigator(KexiPart::Item* item, Kexi::ViewMode viewMode, bool *openingCancelled) { Q_ASSERT(openingCancelled); if (!openingAllowed(item, viewMode)) { *openingCancelled = true; return 0; } if (!d->prj || !item) return 0; #ifndef KEXI_NO_PENDING_DIALOGS Private::PendingJobType pendingType; KexiWindow *window = d->openedWindowFor(item, pendingType); if (pendingType != Private::NoJob) { *openingCancelled = true; return 0; } #else KexiWindow *window = openedWindowFor(item); #endif *openingCancelled = false; if (window) { if (activateWindow(*window)) { return window; } } //if DataViewMode is not supported, try Design, then Text mode (currently useful for script part) KexiPart::Part *part = Kexi::partManager().partForPluginId(item->pluginId()); if (!part) return 0; if (viewMode == Kexi::DataViewMode && !(part->info()->supportedViewModes() & Kexi::DataViewMode)) { if (part->info()->supportedViewModes() & Kexi::DesignViewMode) return openObjectFromNavigator(item, Kexi::DesignViewMode, openingCancelled); else if (part->info()->supportedViewModes() & Kexi::TextViewMode) return openObjectFromNavigator(item, Kexi::TextViewMode, openingCancelled); } //do the same as in openObject() return openObject(item, viewMode, openingCancelled); } tristate KexiMainWindow::closeObject(KexiPart::Item* item) { #ifndef KEXI_NO_PENDING_DIALOGS Private::PendingJobType pendingType; KexiWindow *window = d->openedWindowFor(item, pendingType); if (pendingType == Private::WindowClosingJob) return true; else if (pendingType == Private::WindowOpeningJob) return cancelled; #else KexiWindow *window = openedWindowFor(item); #endif if (!window) return cancelled; return closeWindow(window); } bool KexiMainWindow::newObject(KexiPart::Info *info, bool* openingCancelled) { Q_ASSERT(openingCancelled); if (d->userMode) { *openingCancelled = true; return false; } *openingCancelled = false; if (!d->prj || !info) return false; KexiPart::Part *part = Kexi::partManager().part(info); if (!part) return false; KexiPart::Item *it = d->prj->createPartItem(info); if (!it) { //! @todo error return false; } if (!it->neverSaved()) { //only add stored objects to the browser d->navigator->model()->slotAddItem(it); } return openObject(it, Kexi::DesignViewMode, openingCancelled); } tristate KexiMainWindow::removeObject(KexiPart::Item *item, bool dontAsk) { if (d->userMode) return cancelled; if (!d->prj || !item) return false; KexiPart::Part *part = Kexi::partManager().partForPluginId(item->pluginId()); if (!part) return false; if (!dontAsk) { if (KMessageBox::No == KMessageBox::questionYesNo(this, xi18nc("@info Delete ?", "Do you want to permanently delete the following object?" "%1 %2" "If you click Delete, " "you will not be able to undo the deletion.", part->info()->name(), item->name()), xi18nc("@title:window Delete Object %1.", "Delete %1?", item->name()), KStandardGuiItem::del(), KStandardGuiItem::no(), QString(), KMessageBox::Notify | KMessageBox::Dangerous)) { return cancelled; } } tristate res = true; #ifdef KEXI_QUICK_PRINTING_SUPPORT //also close 'print setup' dialog for this item, if any KexiWindow * pageSetupWindow = d->pageSetupWindows[ item->identifier()]; const bool oldInsideCloseWindow = d->insideCloseWindow; { d->insideCloseWindow = false; if (pageSetupWindow) res = closeWindow(pageSetupWindow); } d->insideCloseWindow = oldInsideCloseWindow; if (!res || ~res) { return res; } #endif #ifndef KEXI_NO_PENDING_DIALOGS Private::PendingJobType pendingType; KexiWindow *window = d->openedWindowFor(item, pendingType); if (pendingType != Private::NoJob) { return cancelled; } #else KexiWindow *window = openedWindowFor(item); #endif if (window) {//close existing window const bool tmp = d->forceWindowClosing; d->forceWindowClosing = true; res = closeWindow(window); d->forceWindowClosing = tmp; //restore if (!res || ~res) { return res; } } #ifdef KEXI_QUICK_PRINTING_SUPPORT //in case the dialog is a 'print setup' dialog, also update d->pageSetupWindows int dataItemID = d->pageSetupWindowItemID2dataItemID_map[item->identifier()]; d->pageSetupWindowItemID2dataItemID_map.remove(item->identifier()); d->pageSetupWindows.remove(dataItemID); #endif if (!d->prj->removeObject(item)) { //! @todo better msg showSorryMessage(xi18n("Could not delete object.")); return false; } return true; } void KexiMainWindow::renameObject(KexiPart::Item *item, const QString& _newName, bool *success) { Q_ASSERT(success); if (d->userMode) { *success = false; return; } QString newName = _newName.trimmed(); if (newName.isEmpty()) { showSorryMessage(xi18n("Could not set empty name for this object.")); *success = false; return; } KexiWindow *window = openedWindowFor(item); if (window) { QString msg = xi18nc("@info", "Before renaming object %1 it should be closed." "Do you want to close it?", item->name()); KGuiItem closeAndRenameItem(KStandardGuiItem::closeWindow()); closeAndRenameItem.setText(xi18n("Close Window and Rename")); const int r = KMessageBox::questionYesNo(this, msg, QString(), closeAndRenameItem, KStandardGuiItem::cancel()); if (r != KMessageBox::Yes) { *success = false; return; } const tristate closeResult = closeWindow(window); if (closeResult != true) { *success = false; return; } } setMessagesEnabled(false); //to avoid double messages const bool res = d->prj->renameObject(item, newName); setMessagesEnabled(true); if (!res) { showErrorMessage(xi18nc("@info", "Renaming object %1 failed.", newName), d->prj); *success = false; return; } *success = true; } void KexiMainWindow::setObjectCaption(KexiPart::Item *item, const QString& _newCaption, bool *success) { Q_ASSERT(success); if (d->userMode) { *success = false; return; } QString newCaption = _newCaption.trimmed(); setMessagesEnabled(false); //to avoid double messages const bool res = d->prj->setObjectCaption(item, newCaption); setMessagesEnabled(true); if (!res) { showErrorMessage(xi18nc("@info", "Setting caption for object %1 failed.", newCaption), d->prj); *success = false; return; } *success = true; } void KexiMainWindow::slotObjectRenamed(const KexiPart::Item &item, const QString& oldName) { Q_UNUSED(oldName); #ifndef KEXI_NO_PENDING_DIALOGS Private::PendingJobType pendingType; KexiWindow *window = d->openedWindowFor(&item, pendingType); if (pendingType != Private::NoJob) return; #else KexiWindow *window = openedWindowFor(&item); #endif if (!window) return; //change item window->updateCaption(); if (static_cast(currentWindow()) == window)//optionally, update app. caption updateAppCaption(); } void KexiMainWindow::acceptPropertySetEditing() { if (d->propEditor) d->propEditor->editor()->acceptInput(); } void KexiMainWindow::propertySetSwitched(KexiWindow *window, bool force, bool preservePrevSelection, bool sortedProperties, const QByteArray& propertyToSelect) { KexiWindow* _currentWindow = currentWindow(); //qDebug() << "currentWindow(): " // << (_currentWindow ? _currentWindow->windowTitle() : QString("NULL")) // << " window: " << (window ? window->windowTitle() : QString("NULL")); if (_currentWindow && _currentWindow != window) { d->propertySet = 0; //we'll need to move to another prop. set return; } if (d->propEditor) { KPropertySet *newSet = _currentWindow ? _currentWindow->propertySet() : 0; if (!newSet || (force || static_cast(d->propertySet) != newSet)) { d->propertySet = newSet; if (preservePrevSelection || force) { KPropertyEditorView::SetOptions options; if (preservePrevSelection) { options |= KPropertyEditorView::SetOption::PreservePreviousSelection; } if (sortedProperties) { options |= KPropertyEditorView::SetOption::AlphabeticalOrder; } if (propertyToSelect.isEmpty()) { d->propEditor->editor()->changeSet(d->propertySet, options); } else { d->propEditor->editor()->changeSet(d->propertySet, propertyToSelect, options); } } } } } void KexiMainWindow::slotDirtyFlagChanged(KexiWindow* window) { KexiPart::Item *item = window->partItem(); //update text in navigator and app. caption if (!d->userMode) { d->navigator->updateItemName(*item, window->isDirty()); } invalidateActions(); updateAppCaption(); d->mainWidget->tabWidget()->setTabText( d->mainWidget->tabWidget()->indexOf(window->parentWidget()), window->windowTitle()); } void KexiMainWindow::slotTipOfTheDay() { //! @todo } void KexiMainWindow::slotReportBug() { KexiBugReportDialog bugReport(this); bugReport.exec(); } bool KexiMainWindow::userMode() const { return d->userMode; } void KexiMainWindow::setupUserActions() { } void KexiMainWindow::slotToolsImportProject() { if (d->tabbedToolBar) d->tabbedToolBar->hideMainMenu(); showProjectMigrationWizard(QString(), QString()); } void KexiMainWindow::slotToolsImportTables() { if (project()) { QMap args; QDialog *dlg = KexiInternalPart::createModalDialogInstance("org.kexi-project.migration", "importtable", this, 0, &args); if (!dlg) return; //error msg has been shown by KexiInternalPart const int result = dlg->exec(); delete dlg; if (result != QDialog::Accepted) return; QString destinationTableName(args["destinationTableName"]); if (!destinationTableName.isEmpty()) { QString pluginId = "org.kexi-project.table"; bool openingCancelled; KexiMainWindow::openObject(pluginId, destinationTableName, Kexi::DataViewMode, &openingCancelled); } } } void KexiMainWindow::slotToolsCompactDatabase() { KexiProjectData *data = 0; KDbDriver *drv = 0; const bool projectWasOpened = d->prj; if (!d->prj) { //! @todo Support compacting of non-opened projects return; #if 0 KexiStartupDialog dlg( KexiStartupDialog::OpenExisting, 0, Kexi::connset(), this); if (dlg.exec() != QDialog::Accepted) return; if (dlg.selectedFile().isEmpty()) { //! @todo add support for server based if needed? return; } KDbConnectionData cdata; cdata.setDatabaseName(dlg.selectedFile()); //detect driver name for the selected file KexiStartupData::Import detectedImportAction; QString detectedDriverId; tristate res = KexiStartupHandler::detectActionForFile( &detectedImportAction, &detectedDriverId, QString() /*suggestedDriverId*/, cdata.databaseName(), 0, KexiStartupHandler::SkipMessages | KexiStartupHandler::ThisIsAProjectFile | KexiStartupHandler::DontConvert); if (true == res && !detectedImportAction) { cdata.setDriverId(detectedDriverId); drv = Kexi::driverManager().driver(cdata.driverId()); } if (!drv || !(drv->features() & KDbDriver::CompactingDatabaseSupported)) { KMessageBox::information(this, xi18n("Compacting database file %1 is not supported.", QDir::toNativeSeparators(cdata.databaseName()))); return; } data = new KexiProjectData(cdata); #endif } else { //sanity if (!(d->prj && d->prj->dbConnection() && (d->prj->dbConnection()->driver()->features() & KDbDriver::CompactingDatabaseSupported))) return; KGuiItem yesItem(KStandardGuiItem::cont()); yesItem.setText(xi18nc("@action:button Compact database", "Compact")); if (KMessageBox::Yes != KMessageBox::questionYesNo(this, xi18n("The current project has to be closed before compacting the database. " "It will be open again after compacting.\n\nDo you want to continue?"), QString(), yesItem, KStandardGuiItem::cancel())) { return; } data = new KexiProjectData(*d->prj->data()); // a copy drv = d->prj->dbConnection()->driver(); const tristate res = closeProject(); if (~res || !res) { delete data; return; } } if (!drv->adminTools().vacuum(*data->connectionData(), data->databaseName())) { showErrorMessage(QString(), &drv->adminTools()); } if (projectWasOpened) openProject(*data); delete data; } tristate KexiMainWindow::showProjectMigrationWizard(const QString& mimeType, const QString& databaseName) { return d->showProjectMigrationWizard(mimeType, databaseName, 0); } tristate KexiMainWindow::showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData &cdata) { return d->showProjectMigrationWizard(mimeType, databaseName, &cdata); } tristate KexiMainWindow::executeItem(KexiPart::Item* item) { KexiPart::Info *info = item ? Kexi::partManager().infoForPluginId(item->pluginId()) : 0; if ((! info) || (! info->isExecuteSupported())) return false; KexiPart::Part *part = Kexi::partManager().part(info); if (!part) return false; return part->execute(item); } void KexiMainWindow::slotProjectImportDataTable() { //! @todo allow data appending (it is not possible now) if (d->userMode) return; QMap args; args.insert("sourceType", "file"); QDialog *dlg = KexiInternalPart::createModalDialogInstance( "org.kexi-project.importexport.csv", "KexiCSVImportDialog", this, 0, &args); if (!dlg) return; //error msg has been shown by KexiInternalPart dlg->exec(); delete dlg; } tristate KexiMainWindow::executeCustomActionForObject(KexiPart::Item* item, const QString& actionName) { if (actionName == "exportToCSV") return exportItemAsDataTable(item); else if (actionName == "copyToClipboardAsCSV") return copyItemToClipboardAsDataTable(item); qWarning() << "no such action:" << actionName; return false; } tristate KexiMainWindow::exportItemAsDataTable(KexiPart::Item* item) { if (!item) return false; QMap args; if (!checkForDirtyFlagOnExport(item, &args)) { return false; } //! @todo: accept record changes... args.insert("destinationType", "file"); args.insert("itemId", QString::number(item->identifier())); QDialog *dlg = KexiInternalPart::createModalDialogInstance( "org.kexi-project.importexport.csv", "KexiCSVExportWizard", this, 0, &args); if (!dlg) return false; //error msg has been shown by KexiInternalPart int result = dlg->exec(); delete dlg; return result == QDialog::Rejected ? tristate(cancelled) : tristate(true); } bool KexiMainWindow::checkForDirtyFlagOnExport(KexiPart::Item *item, QMap *args) { //! @todo: handle tables if (item->pluginId() != "org.kexi-project.query") { return true; } KexiWindow * itemWindow = openedWindowFor(item); if (itemWindow && itemWindow->isDirty()) { tristate result; if (item->neverSaved()) { result = true; } else { int prevWindowId = 0; if (!itemWindow->isVisible()) { prevWindowId = currentWindow()->id(); activateWindow(itemWindow->id()); } result = askOnExportingChangedQuery(item); if (prevWindowId != 0) { activateWindow(prevWindowId); } } if (~result) { return false; } else if (true == result) { args->insert("useTempQuery","1"); } } return true; } tristate KexiMainWindow::askOnExportingChangedQuery(KexiPart::Item *item) const { const KMessageBox::ButtonCode result = KMessageBox::warningYesNoCancel(const_cast(this), xi18nc("@info", "Design of query %1 that you want to export data" " from is changed and has not yet been saved. Do you want to use data" " from the changed query for exporting or from its original (saved)" " version?", item->captionOrName()), QString(), KGuiItem(xi18nc("@action:button Export query data", "Use the Changed Query")), KGuiItem(xi18nc("@action:button Export query data", "Use the Original Query")), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous); if (result == KMessageBox::Yes) { return true; } else if (result == KMessageBox::No) { return false; } return cancelled; } bool KexiMainWindow::printItem(KexiPart::Item* item, const QString& titleText) { //! @todo printItem(item, KexiSimplePrintingSettings::load(), titleText); Q_UNUSED(item) Q_UNUSED(titleText) return false; } tristate KexiMainWindow::printItem(KexiPart::Item* item) { return printItem(item, QString()); } bool KexiMainWindow::printPreviewForItem(KexiPart::Item* item, const QString& titleText, bool reload) { //! @todo printPreviewForItem(item, KexiSimplePrintingSettings::load(), titleText, reload); Q_UNUSED(item) Q_UNUSED(titleText) Q_UNUSED(reload) return false; } tristate KexiMainWindow::printPreviewForItem(KexiPart::Item* item) { return printPreviewForItem(item, QString(), //! @todo store cached record data? true/*reload*/); } tristate KexiMainWindow::showPageSetupForItem(KexiPart::Item* item) { Q_UNUSED(item) //! @todo check if changes to this object's design are saved, if not: ask for saving //! @todo accept record changes... //! @todo printActionForItem(item, PageSetupForItem); return false; } //! @todo reenable printItem() when ported #if 0 bool KexiMainWindow::printItem(KexiPart::Item* item, const KexiSimplePrintingSettings& settings, const QString& titleText) { //! @todo: check if changes to this object's design are saved, if not: ask for saving //! @todo: accept record changes... KexiSimplePrintingCommand cmd(this, item->identifier()); //modal return cmd.print(settings, titleText); } bool KexiMainWindow::printPreviewForItem(KexiPart::Item* item, const KexiSimplePrintingSettings& settings, const QString& titleText, bool reload) { //! @todo: check if changes to this object's design are saved, if not: ask for saving //! @todo: accept record changes... KexiSimplePrintingCommand* cmd = d->openedCustomObjectsForItem( item, "KexiSimplePrintingCommand"); if (!cmd) { d->addOpenedCustomObjectForItem( item, cmd = new KexiSimplePrintingCommand(this, item->identifier()), "KexiSimplePrintingCommand" ); } return cmd->showPrintPreview(settings, titleText, reload); } tristate KexiMainWindow::printActionForItem(KexiPart::Item* item, PrintActionType action) { if (!item) return false; KexiPart::Info *info = Kexi::partManager().infoForPluginId(item->pluginId()); if (!info->isPrintingSupported()) return false; KexiWindow *printingWindow = d->pageSetupWindows[ item->identifier()]; if (printingWindow) { if (!activateWindow(*printingWindow)) return false; if (action == PreviewItem || action == PrintItem) { QTimer::singleShot(0, printingWindow->selectedView(), (action == PreviewItem) ? SLOT(printPreview()) : SLOT(print())); } return true; } #ifndef KEXI_NO_PENDING_DIALOGS Private::PendingJobType pendingType; KexiWindow *window = d->openedWindowFor(item, pendingType); if (pendingType != Private::NoJob) return cancelled; #else KexiWindow *window = openedWindowFor(item); #endif if (window) { // accept record changes QWidget *prevFocusWidget = focusWidget(); window->setFocus(); d->action_data_save_row->activate(QAction::Trigger); if (prevFocusWidget) prevFocusWidget->setFocus(); // opened: check if changes made to this dialog are saved, if not: ask for saving if (window->neverSaved()) //sanity check return false; if (window->isDirty()) { KGuiItem saveChanges(KStandardGuiItem::save()); saveChanges.setToolTip(futureI18n("Save changes")); saveChanges.setWhatsThis( futureI18n("Pressing this button will save all recent changes made in \"%1\" object.", item->name())); KGuiItem doNotSave(KStandardGuiItem::no()); doNotSave.setWhatsThis( futureI18n("Pressing this button will ignore all unsaved changes made in \"%1\" object.", window->partItem()->name())); QString question; if (action == PrintItem) question = futureI18n("Do you want to save changes before printing?"); else if (action == PreviewItem) question = futureI18n("Do you want to save changes before making print preview?"); else if (action == PageSetupForItem) question = futureI18n("Do you want to save changes before showing page setup?"); else return false; const KMessageBox::ButtonCode questionRes = KMessageBox::warningYesNoCancel(this, "

    " + window->part()->i18nMessage("Design of object %1 has been modified.", window) .subs(item->name()) + "

    " + question + "

    ", QString(), saveChanges, doNotSave); if (KMessageBox::Cancel == questionRes) return cancelled; if (KMessageBox::Yes == questionRes) { tristate savingRes = saveObject(window, QString(), DoNotAsk); if (true != savingRes) return savingRes; } } } KexiPart::Part * printingPart = Kexi::partManager().partForClass("org.kexi-project.simpleprinting"); if (!printingPart) printingPart = new KexiSimplePrintingPart(); //hardcoded as there're no .desktop file KexiPart::Item* printingPartItem = d->prj->createPartItem( printingPart, item->name() //<-- this will look like "table1 : printing" on the window list ); QMap staticObjectArgs; staticObjectArgs["identifier"] = QString::number(item->identifier()); if (action == PrintItem) staticObjectArgs["action"] = "print"; else if (action == PreviewItem) staticObjectArgs["action"] = "printPreview"; else if (action == PageSetupForItem) staticObjectArgs["action"] = "pageSetup"; else return false; bool openingCancelled; printingWindow = openObject(printingPartItem, Kexi::DesignViewMode, &openingCancelled, &staticObjectArgs); if (openingCancelled) return cancelled; if (!printingWindow) //sanity return false; d->pageSetupWindows.insert(item->identifier(), printingWindow); d->pageSetupWindowItemID2dataItemID_map.insert( printingWindow->partItem()->identifier(), item->identifier()); return true; } #endif void KexiMainWindow::slotEditCopySpecialDataTable() { KexiPart::Item* item = d->navigator->selectedPartItem(); if (item) copyItemToClipboardAsDataTable(item); } tristate KexiMainWindow::copyItemToClipboardAsDataTable(KexiPart::Item* item) { if (!item) return false; QMap args; if (!checkForDirtyFlagOnExport(item, &args)) { return false; } args.insert("destinationType", "clipboard"); args.insert("itemId", QString::number(item->identifier())); QDialog *dlg = KexiInternalPart::createModalDialogInstance( "org.kexi-project.importexport.csv", "KexiCSVExportWizard", this, 0, &args); if (!dlg) return false; //error msg has been shown by KexiInternalPart const int result = dlg->exec(); delete dlg; return result == QDialog::Rejected ? tristate(cancelled) : tristate(true); } void KexiMainWindow::slotEditPasteSpecialDataTable() { //! @todo allow data appending (it is not possible now) if (d->userMode) return; QMap args; args.insert("sourceType", "clipboard"); QDialog *dlg = KexiInternalPart::createModalDialogInstance( "org.kexi-project.importexport.csv", "KexiCSVImportDialog", this, 0, &args); if (!dlg) return; //error msg has been shown by KexiInternalPart dlg->exec(); delete dlg; } void KexiMainWindow::slotEditFind() { KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); if (!iface) return; d->updateFindDialogContents(true/*create if does not exist*/); d->findDialog()->setReplaceMode(false); d->findDialog()->show(); d->findDialog()->activateWindow(); d->findDialog()->raise(); } void KexiMainWindow::slotEditFind(bool next) { KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); if (!iface) return; tristate res = iface->find( d->findDialog()->valueToFind(), d->findDialog()->options(), next); if (~res) return; d->findDialog()->updateMessage(true == res); //! @todo result } void KexiMainWindow::slotEditFindNext() { slotEditFind(true); } void KexiMainWindow::slotEditFindPrevious() { slotEditFind(false); } void KexiMainWindow::slotEditReplace() { KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); if (!iface) return; d->updateFindDialogContents(true/*create if does not exist*/); d->findDialog()->setReplaceMode(true); //! @todo slotEditReplace() d->findDialog()->show(); d->findDialog()->activateWindow(); } void KexiMainWindow::slotEditReplaceNext() { slotEditReplace(false); } void KexiMainWindow::slotEditReplace(bool all) { KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); if (!iface) return; //! @todo add question: "Do you want to replace every occurrence of \"%1\" with \"%2\"? //! You won't be able to undo this." + "Do not ask again". tristate res = iface->findNextAndReplace( d->findDialog()->valueToFind(), d->findDialog()->valueToReplaceWith(), d->findDialog()->options(), all); d->findDialog()->updateMessage(true == res); //! @todo result } void KexiMainWindow::slotEditReplaceAll() { slotEditReplace(true); } void KexiMainWindow::highlightObject(const QString& pluginId, const QString& name) { if (!d->prj) return; KexiPart::Item *item = d->prj->itemForPluginId(pluginId, name); if (!item) return; if (d->navigator) { slotSetProjectNavigatorVisible(true); d->navigator->selectItem(*item); } } void KexiMainWindow::slotPartItemSelectedInNavigator(KexiPart::Item* item) { Q_UNUSED(item); } KToolBar *KexiMainWindow::toolBar(const QString& name) const { return d->tabbedToolBar ? d->tabbedToolBar->toolBar(name) : 0; } void KexiMainWindow::appendWidgetToToolbar(const QString& name, QWidget* widget) { if (d->tabbedToolBar) d->tabbedToolBar->appendWidgetToToolbar(name, widget); } void KexiMainWindow::setWidgetVisibleInToolbar(QWidget* widget, bool visible) { if (d->tabbedToolBar) d->tabbedToolBar->setWidgetVisibleInToolbar(widget, visible); } void KexiMainWindow::addToolBarAction(const QString& toolBarName, QAction *action) { if (d->tabbedToolBar) d->tabbedToolBar->addAction(toolBarName, action); } void KexiMainWindow::updatePropertyEditorInfoLabel(const QString& textToDisplayForNullSet) { d->propEditor->updateInfoLabelForPropertySet(d->propertySet, textToDisplayForNullSet); } void KexiMainWindow::addSearchableModel(KexiSearchableModel *model) { if (d->tabbedToolBar) { d->tabbedToolBar->addSearchableModel(model); } } void KexiMainWindow::setReasonableDialogSize(QDialog *dialog) { dialog->setMinimumSize(600, 400); dialog->resize(size() * 0.8); } void KexiMainWindow::restoreDesignTabAndActivateIfNeeded(const QString &tabName) { if (!d->tabbedToolBar) { return; } d->tabbedToolBar->showTab(tabName); if (currentWindow() && currentWindow()->partItem() && currentWindow()->partItem()->identifier() != 0) // for unstored items id can be < 0 { const QString tabToActivate = d->tabsToActivateOnShow.value( currentWindow()->partItem()->identifier()); //qDebug() << "tabToActivate:" << tabToActivate << "tabName:" << tabName; if (tabToActivate == tabName) { d->tabbedToolBar->setCurrentTab(tabToActivate); } } } void KexiMainWindow::restoreDesignTabIfNeeded(const QString &pluginId, Kexi::ViewMode viewMode, int previousItemId) { //qDebug() << pluginId << viewMode << previousItemId; if (viewMode == Kexi::DesignViewMode) { switch (d->prj->typeIdForPluginId(pluginId)) { case KexiPart::FormObjectType: { hideDesignTab(previousItemId, "org.kexi-project.report"); restoreDesignTabAndActivateIfNeeded("form"); break; } case KexiPart::ReportObjectType: { hideDesignTab(previousItemId, "org.kexi-project.form"); restoreDesignTabAndActivateIfNeeded("report"); break; } default: hideDesignTab(previousItemId); } } else { hideDesignTab(previousItemId); } } void KexiMainWindow::activateDesignTab(const QString &pluginId) { if (!d->tabbedToolBar) { return; } switch (d->prj->typeIdForPluginId(pluginId)) { case KexiPart::FormObjectType: d->tabbedToolBar->setCurrentTab("form"); break; case KexiPart::ReportObjectType: d->tabbedToolBar->setCurrentTab("report"); break; default:; } } void KexiMainWindow::activateDesignTabIfNeeded(const QString &pluginId, Kexi::ViewMode viewMode) { if (!d->tabbedToolBar) { return; } const QString tabToActivate = d->tabsToActivateOnShow.value(currentWindow()->partItem()->identifier()); //qDebug() << pluginId << viewMode << tabToActivate; if (viewMode == Kexi::DesignViewMode && tabToActivate.isEmpty()) { activateDesignTab(pluginId); } else { d->tabbedToolBar->setCurrentTab(tabToActivate); } } void KexiMainWindow::hideDesignTab(int itemId, const QString &pluginId) { if (!d->tabbedToolBar) { return; } //qDebug() << itemId << pluginId; if ( itemId > 0 && d->tabbedToolBar->currentWidget()) { const QString currentTab = d->tabbedToolBar->currentWidget()->objectName(); //qDebug() << "d->tabsToActivateOnShow.insert" << itemId << currentTab; d->tabsToActivateOnShow.insert(itemId, currentTab); } switch (d->prj->typeIdForPluginId(pluginId)) { case KexiPart::FormObjectType: d->tabbedToolBar->hideTab("form"); break; case KexiPart::ReportObjectType: d->tabbedToolBar->hideTab("report"); break; default: d->tabbedToolBar->hideTab("form"); d->tabbedToolBar->hideTab("report"); } } void KexiMainWindow::showDesignTabIfNeeded(int previousItemId) { if (d->insideCloseWindow && d->tabbedToolBar) return; if (currentWindow()) { restoreDesignTabIfNeeded(currentWindow()->partItem()->pluginId(), currentWindow()->currentViewMode(), previousItemId); } else { hideDesignTab(previousItemId); } } KexiUserFeedbackAgent* KexiMainWindow::userFeedbackAgent() const { return &d->userFeedback; } KexiMigrateManagerInterface* KexiMainWindow::migrateManager() { if (!d->migrateManager) { d->migrateManager = dynamic_cast( KexiInternalPart::createObjectInstance( "org.kexi-project.migration", "manager", this, this, nullptr)); } return d->migrateManager; } void KexiMainWindow::toggleFullScreen(bool isFullScreen) { static bool isTabbarRolledDown; if (d->tabbedToolBar) { if (isFullScreen) { isTabbarRolledDown = !d->tabbedToolBar->isRolledUp(); if (isTabbarRolledDown) { d->tabbedToolBar->toggleRollDown(); } } else { if (isTabbarRolledDown && d->tabbedToolBar->isRolledUp()) { d->tabbedToolBar->toggleRollDown(); } } } const Qt::WindowStates s = windowState() & Qt::WindowMaximized; if (isFullScreen) { setWindowState(windowState() | Qt::WindowFullScreen | s); } else { setWindowState((windowState() & ~Qt::WindowFullScreen)); showMaximized(); } } diff --git a/src/main/KexiMainWindow_p.cpp b/src/main/KexiMainWindow_p.cpp index 6bf34af01..7a2471cb4 100644 --- a/src/main/KexiMainWindow_p.cpp +++ b/src/main/KexiMainWindow_p.cpp @@ -1,1591 +1,1597 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2015 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. */ #include "KexiMainWindow_p.h" #include #include #include #include #include #include #include #include KexiWindowContainer::KexiWindowContainer(QWidget* parent) : QWidget(parent) , window(0) , lyr(new QVBoxLayout(this)) { lyr->setContentsMargins(0, 0, 0, 0); } KexiWindowContainer::~KexiWindowContainer() { //! @todo warning if saveSettings() failed? if (window) { window->saveSettings(); delete (KexiWindow*)window; } } void KexiWindowContainer::setWindow(KexiWindow* w) { window = w; if (w) lyr->addWidget(w); } // --- EmptyMenuContentWidget::EmptyMenuContentWidget(QWidget* parent) : QWidget(parent) { setAutoFillBackground(true); alterBackground(); } void EmptyMenuContentWidget::alterBackground() { QPalette pal(palette()); QColor bg(pal.color(QPalette::Window)); bg.setAlpha(200); pal.setColor(QPalette::Window, bg); setPalette(pal); } void EmptyMenuContentWidget::changeEvent(QEvent *e) { if (e->type() == QEvent::PaletteChange) { alterBackground(); } QWidget::changeEvent(e); } //! @todo KEXI3 is KexiMenuWidgetStyle needed? #if 0 KexiMenuWidgetStyle::KexiMenuWidgetStyle(QStyle *style, QObject *parent) : KexiUtils::StyleProxy(style, parent) { } KexiMenuWidgetStyle::~KexiMenuWidgetStyle() { } void KexiMenuWidgetStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const { if (element == QStyle::CE_MenuItem && (option->state & QStyle::State_Selected) && (option->state & QStyle::State_Enabled) && parentStyle()->objectName() == QLatin1String("oxygen")) { // Ugly fix for visual glitch of oxygen; no chance for improvement since // we've forked QMenu and oxygen checks for qobject_cast directly. QColor c(option->palette.color(QPalette::Window)); int h, s, v, a; c.getHsv(&h, &s, &v, &a); // Why 0.91208791? I knew you're curious. There are some algorithms in Oxygen // to make color a bit lighter. They are not in the public API nor they are simple. // So the number was computed by me to find the proper value for the color // (the accuracy is quite OK). // It's also related to the fact that Oxygen's menus have gradient background. // A lot of computation happens under the mask... c.setHsv(h, s, v * 0.91208791, a); painter->fillRect(option->rect.x() + 6, option->rect.y() + 6, option->rect.width() - 12, option->rect.height() - 12, c); } KexiUtils::StyleProxy::drawControl(element, option, painter, widget); } #endif KexiMainMenu::KexiMainMenu(KexiTabbedToolBar *toolBar, QWidget* parent) : QWidget(parent), m_toolBar(toolBar), m_initialized(false) { m_content = 0; m_selectFirstItem = false; } KexiMainMenu::~KexiMainMenu() { delete (QWidget*)m_contentWidget; } bool KexiMainMenu::eventFilter(QObject * watched, QEvent* event) { if (event->type() == QEvent::MouseButtonPress && watched == m_content && !m_contentWidget) { emit contentAreaPressed(); } else if (event->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast(event); if ((ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) { emit hideContentsRequested(); return true; } } return QWidget::eventFilter(watched, event); } void KexiMainMenu::setContent(QWidget *contentWidget) { if (m_menuWidget && m_persistentlySelectedAction) { m_menuWidget->setPersistentlySelectedAction( m_persistentlySelectedAction, m_persistentlySelectedAction->persistentlySelected()); } /*if (m_menuWidget->persistentlySelectedAction()) qDebug() << "****" << m_menuWidget->persistentlySelectedAction()->objectName();*/ KexiFadeWidgetEffect *fadeEffect = 0; if (m_contentWidget && contentWidget) { fadeEffect = new KexiFadeWidgetEffect(m_content); } if (m_contentWidget) m_contentWidget->deleteLater(); m_contentWidget = contentWidget; if (m_contentWidget) { QPalette contentWidgetPalette(m_contentWidget->palette()); contentWidgetPalette.setBrush(QPalette::Active, QPalette::Window, contentWidgetPalette.brush(QPalette::Active, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::Window, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Window, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Active, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Active, QPalette::Text)); contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Text)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Text)); const QColor highlightDisabled(KexiUtils::blendedColors( contentWidgetPalette.color(QPalette::Active, QPalette::Highlight), contentWidgetPalette.color(QPalette::Disabled, QPalette::Window), 1, 2)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlightDisabled); const QColor highlightedTextDisabled(KexiUtils::blendedColors( contentWidgetPalette.color(QPalette::Active, QPalette::HighlightedText), contentWidgetPalette.color(QPalette::Disabled, QPalette::WindowText), 1, 2)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::HighlightedText, highlightedTextDisabled); m_contentWidget->setPalette(contentWidgetPalette); for(QAbstractScrollArea *area : m_contentWidget->findChildren()) { QPalette pal(area->viewport()->palette()); pal.setBrush(QPalette::Disabled, QPalette::Base, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base)); area->viewport()->setPalette(pal); } m_contentWidget->setAutoFillBackground(true); m_contentWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); m_contentWidget->setContentsMargins(0, 0, 0, 0); m_contentLayout->addWidget(m_contentWidget); m_contentLayout->setCurrentWidget(m_contentWidget); m_contentWidget->setFocus(); m_contentWidget->installEventFilter(this); //connect(m_contentWidget, SIGNAL(destroyed()), this, SLOT(contentWidgetDestroyed())); } if (fadeEffect) { if (m_contentWidget) m_contentLayout->update(); QTimer::singleShot(10, fadeEffect, SLOT(start())); } } const QWidget *KexiMainMenu::contentWidget() const { return m_contentWidget; } void KexiMainMenu::setPersistentlySelectedAction(KexiMenuWidgetAction* action, bool set) { m_persistentlySelectedAction = action; m_persistentlySelectedAction->setPersistentlySelected(set); } /* void KexiMainMenu::setActiveAction(QAction* action = 0) { if (!action && !m_menuWidget->actions().isEmpty()) { action = actions().first(); } if (action) { m_menuWidget->setActiveAction(action); } } */ void KexiMainMenu::selectFirstItem() { m_selectFirstItem = true; } void KexiMainMenu::showEvent(QShowEvent * event) { if (!m_initialized) { m_initialized = true; KActionCollection *ac = KexiMainWindowIface::global()->actionCollection(); QHBoxLayout *hlyr = new QHBoxLayout(this); hlyr->setSpacing(0); hlyr->setMargin(0); m_menuWidget = new KexiMenuWidget; //! @todo KEXI3 is KexiMenuWidgetStyle needed? #if 0 QString styleName(m_menuWidget->style()->objectName()); if (KDE::version() < KDE_MAKE_VERSION(4, 8, 0) // a fix is apparently needed for glitch in KDE < 4.8 && styleName == "oxygen") { KexiMenuWidgetStyle *customStyle = new KexiMenuWidgetStyle(m_menuWidget->style()->objectName(), this); m_menuWidget->setStyle(customStyle); } #endif m_menuWidget->installEventFilter(this); m_menuWidget->setFocusPolicy(Qt::StrongFocus); setFocusProxy(m_menuWidget); m_menuWidget->setFrame(false); m_menuWidget->setAutoFillBackground(true); m_menuWidget->addAction(ac->action("project_welcome")); m_menuWidget->addAction(ac->action("project_open")); m_menuWidget->addAction(ac->action("project_close")); m_menuWidget->addSeparator(); m_menuWidget->addAction(ac->action("project_new")); m_menuWidget->addAction(ac->action("project_import_export_send")); #ifdef KEXI_SHOW_UNIMPLEMENTED m_menuWidget->addAction(ac->action("project_properties")); //! @todo project information m_menuWidget->addAction(ac->action("settings")); #endif m_menuWidget->addSeparator(); m_menuWidget->addAction(ac->action("quit")); hlyr->addWidget(m_menuWidget); m_content = new EmptyMenuContentWidget; m_content->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); m_content->installEventFilter(this); m_mainContentLayout = new QVBoxLayout; hlyr->addLayout(m_mainContentLayout); m_contentLayout = new QStackedLayout(m_content); m_contentLayout->setStackingMode(QStackedLayout::StackAll); m_contentLayout->setContentsMargins(0, 0, 0, 0); m_mainContentLayout->addWidget(m_content); hlyr->setStretchFactor(m_mainContentLayout, 1); } QWidget::showEvent(event); if (m_selectFirstItem && !m_menuWidget->actions().isEmpty()) { QAction* action = m_menuWidget->actions().first(); m_menuWidget->setActiveAction(action); m_selectFirstItem = false; } } // --- KexiTabbedToolBar::Private::Private(KexiTabbedToolBar *t) : q(t), createWidgetToolBar(0) #ifdef KEXI_AUTORISE_TABBED_TOOLBAR , tabToRaise(-1) #endif , rolledUp(false) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR tabRaiseTimer.setSingleShot(true); tabRaiseTimer.setInterval(300); #endif tabBarAnimation.setPropertyName("opacity"); tabBarAnimation.setDuration(500); connect(&tabBarAnimation, SIGNAL(finished()), q, SLOT(tabBarAnimationFinished())); tabIndex = 0; lowestIndex = 2; } //! @return true if @a style name is specific regarding tab styling static bool isSpecificTabStyle(const QString &styleName) { return styleName == "oxygen" || styleName == "qtcurve" || styleName == "gtk+" || styleName == "gtk2"; } KexiTabbedToolBarStyle::KexiTabbedToolBarStyle(const QString &baseStyleName) : QProxyStyle(baseStyleName) { } KexiTabbedToolBarStyle::~KexiTabbedToolBarStyle() { } void KexiTabbedToolBarStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { const QString styleName(baseStyle()->objectName()); qreal origOpacity = -1.0; if (element == CE_TabBarTab) { const QStyleOptionTab* opt = qstyleoption_cast(option); const QTabBar* tabBar = qobject_cast(widget); KexiTabbedToolBar* tbar = tabBar ? qobject_cast(tabBar->parentWidget()) : 0; if (opt && tbar) { const int index = tabBar->tabAt(opt->rect.center()); if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) return; bool mouseOver = opt->state & QStyle::State_MouseOver; bool unselectedOrMenuVisible = !(opt->state & State_Selected) || tbar->mainMenuVisible(); if (unselectedOrMenuVisible) { if (styleName == "bespin") { unselectedOrMenuVisible = false; } } QStyleOptionTab newOpt(*opt); const bool specificStyle = isSpecificTabStyle(styleName); newOpt.text = (specificStyle ? " " : "") + tabBar->tabText(index) + (specificStyle ? " " : ""); if (!mouseOver && unselectedOrMenuVisible && index > 0) { if (tbar->mainMenuVisible()) newOpt.state &= ~QStyle::State_HasFocus; QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget); return; } else if (index == 0) { QBrush bg; newOpt.state |= State_Selected; if (tbar->mainMenuVisible()) { bg = newOpt.palette.brush(QPalette::Active, QPalette::Highlight); if (!specificStyle) { newOpt.palette.setBrush(QPalette::WindowText, newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText)); newOpt.palette.setBrush(QPalette::ButtonText, newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText)); } } else { if (styleName == "fusion") { bg = newOpt.palette.brush(QPalette::Active, QPalette::Button); } else { bg = Qt::transparent; } } QFont origFont(painter->font()); QFont f(origFont); f.setBold(true); painter->setFont(f); newOpt.palette.setBrush(QPalette::Window, bg); newOpt.palette.setBrush(QPalette::Button, // needed e.g. for Plastique style bg); QProxyStyle::drawControl(element, &newOpt, painter, widget); painter->setFont(origFont); if (!mouseOver || tbar->mainMenuVisible() || styleName == "gtk+") { return; } } if (index > 0 || mouseOver) { const QPalette::ColorGroup hbGroup = (styleName == "oxygen") ? QPalette::Active : QPalette::Inactive; const QBrush hb(newOpt.palette.brush(hbGroup, QPalette::Highlight)); newOpt.palette.setBrush(QPalette::Window, hb); newOpt.palette.setBrush(QPalette::Button, hb); // needed e.g. for Plastique style if (mouseOver && (index != tbar->currentIndex() || tbar->mainMenuVisible())) { // use lower opacity for diplaying hovered tabs origOpacity = painter->opacity(); painter->setOpacity(styleName == "qtcurve" ? 0.2 : 0.3); newOpt.state |= State_Selected; } else { if (!specificStyle) { newOpt.palette.setBrush(QPalette::WindowText, newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText)); newOpt.palette.setBrush(QPalette::ButtonText, newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText)); } } if (index == tbar->currentIndex() && styleName == "qtcurve") { origOpacity = painter->opacity(); painter->setOpacity(0.5); } (newOpt.state |= State_Active) ^= State_Active; QProxyStyle::drawControl(element, &newOpt, painter, widget); if (origOpacity != -1.0) { // restore opacity and draw labels using full this opacity painter->setOpacity(origOpacity); if (index > 0) { QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget); } } return; } } } else if (element == CE_ToolBar) { return; } QProxyStyle::drawControl(element, option, painter, widget); } void KexiTabbedToolBarStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { const QString styleName(baseStyle()->objectName()); if (element == PE_FrameTabWidget) { return; } if (element == PE_FrameTabBarBase) { const QTabBar* tabBar = qobject_cast(widget); KexiTabbedToolBar* tbar = tabBar ? qobject_cast(tabBar->parentWidget()) : 0; if (tbar && tbar->mainMenuVisible() && styleName != "bespin") { return; } } if (element == QStyle::PE_PanelToolBar || element == QStyle::PE_FrameMenu) { return; } QProxyStyle::drawPrimitive(element, option, painter, widget); } int KexiTabbedToolBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const { if (metric == QStyle::PM_SmallIconSize) return KIconLoader::SizeMedium; return QProxyStyle::pixelMetric(metric, option, widget); } // --- KexiTabbedToolBarTabBar::KexiTabbedToolBarTabBar(QWidget *parent) : QTabBar(parent) { setObjectName("tabbar"); customStyle = new KexiTabbedToolBarStyle(style()->objectName()); customStyle->setParent(this); setStyle(customStyle); installEventFilter(parent); QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); mainWindow->installEventFilter(parent); setAttribute(Qt::WA_Hover, true); } QSize KexiTabbedToolBarTabBar::originalTabSizeHint(int index) const { return QTabBar::tabSizeHint(index); } QSize KexiTabbedToolBarTabBar::tabSizeHint(int index) const { QSize s = QTabBar::tabSizeHint(index); QStyleOptionTab ot; ot.initFrom(this); QFont f(font()); f.setBold(true); ot.text = (isSpecificTabStyle(customStyle->baseStyle()->objectName()) ? " " : "") + tabText(index); ot.fontMetrics = QFontMetrics(f); int w = customStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, &ot, this); if (w <= 0) { // needed e.g. for oxygen w = fontMetrics().width(" "); } if (index == 0) { s.setWidth(QFontMetrics(f).width(ot.text) + w * 2); return s; } else if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) { // fix width of the spacer tab s.setWidth(w); } return s; } void KexiTabbedToolBar::Private::toggleMainMenu() { if (q->mainMenuVisible()) hideMainMenu(); else showMainMenu(); } void KexiTabbedToolBar::Private::showMainMenu(const char* actionName) { QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); if (!mainMenu) { mainMenu = new KexiMainMenu(q, mainWindow); connect(mainMenu, SIGNAL(contentAreaPressed()), this, SLOT(hideMainMenu())); connect(mainMenu, SIGNAL(hideContentsRequested()), this, SLOT(hideContentsOrMainMenu())); } updateMainMenuGeometry(); if (actionName) { q->selectMainMenuItem(actionName); } else { mainMenu->selectFirstItem(); } mainMenu->show(); mainMenu->setFocus(); q->update(); // tab bar could have a line that should be repainted } void KexiTabbedToolBar::Private::updateMainMenuGeometry() { if (!mainMenu) return; QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); KexiTabbedToolBarTabBar *tabBar = static_cast(q->tabBar()); QPoint pos = q->mapToGlobal(QPoint(0, tabBar->originalTabSizeHint(0).height() - 1)); // qDebug() << "1." << pos; pos = mainWindow->mapFromGlobal(pos); // qDebug() << "2." << pos; // qDebug() << "3." << q->pos(); QStyleOptionTab ot; ot.initFrom(tabBar); int overlap = tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &ot, tabBar) - tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, &ot, tabBar); // qDebug() << "4. overlap=" << overlap; mainMenu->setGeometry(0, pos.y() - overlap /*- q->y()*/, mainWindow->width(), mainWindow->height() - pos.y() + overlap /*+ q->y()*/); } void KexiTabbedToolBar::activateSearchLineEdit() { d->searchLineEdit->selectAll(); d->searchLineEdit->setFocus(); } void KexiTabbedToolBar::Private::hideMainMenu() { if (!mainMenu || !mainMenu->isVisible()) return; mainMenu->hide(); mainMenu->setContent(0); q->update(); // tab bar could have a line that should be repainted } void KexiTabbedToolBar::Private::hideContentsOrMainMenu() { if (!mainMenu || !mainMenu->isVisible()) return; if (mainMenu->contentWidget()) { mainMenu->setContent(0); } else { hideMainMenu(); } } KToolBar *KexiTabbedToolBar::Private::createToolBar(const char *name, const QString& caption) { KToolBar *tbar = new KToolBar(q, true /*main toolbar*/, false /*read config*/); tbar->setIconDimensions(22); //!< @todo make configurable or system-dependent? // needed e.g. for Windows style to remove the toolbar's frame tbar->setStyle(customTabBar->customStyle); toolbarsForName.insert(name, tbar); tbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); tbar->setObjectName(name); toolbarsCaptionForName.insert(name, caption); tabIndex = q->addTab(tbar, caption); toolbarsVisibleForIndex.append(true); toolbarsIndexForName.insert(name, tabIndex); return tbar; } KexiTabbedToolBar::KexiTabbedToolBar(QWidget *parent) : QTabWidget(parent) , d(new Private(this)) { d->customTabBar = new KexiTabbedToolBarTabBar(this); setTabBar(d->customTabBar); setStyle(d->customTabBar->customStyle); // from ktabwidget.cpp //! @todo QTabWidget::setTabBar() should be added with this code //! @todo KEXI3 Are these tabBar() connections useful to port? #if 0 connect(tabBar(), SIGNAL(contextMenu(int,QPoint)), SLOT(contextMenu(int,QPoint&))); connect(tabBar(), SIGNAL(tabDoubleClicked(int)), SLOT(mouseDoubleClick(int))); connect(tabBar(), SIGNAL(newTabRequest()), this, SIGNAL(mouseDoubleClick())); // #185487 connect(tabBar(), SIGNAL(mouseMiddleClick(int)), SLOT(mouseMiddleClick(int))); connect(tabBar(), SIGNAL(initiateDrag( int )), SLOT(initiateDrag( int ))); connect(tabBar(), SIGNAL(testCanDecode(QDragMoveEvent*,bool*)), SIGNAL(testCanDecode(QDragMoveEvent*,bool*))); connect(tabBar(), SIGNAL(receivedDropEvent(int,QDropEvent*)), SLOT(receivedDropEvent(int,QDropEvent*))); connect(tabBar(), SIGNAL(moveTab(int,int)), SLOT(moveTab(int,int))); connect(tabBar(), SIGNAL(tabCloseRequested(int)), SLOT(closeRequest(int))); #endif setMouseTracking(true); // for mouseMoveEvent() setWhatsThis(xi18n("Task-oriented toolbar. Groups commands using tabs.")); #ifdef KEXI_AUTORISE_TABBED_TOOLBAR connect(&d->tabRaiseTimer, SIGNAL(timeout()), this, SLOT(slotDelayedTabRaise())); #endif connect(tabBar(), SIGNAL(tabBarDoubleClicked(int)), this, SLOT(slotTabDoubleClicked(int))); d->ac = KexiMainWindowIface::global()->actionCollection(); QWidget *mainWin = KexiMainWindowIface::global()->thisWidget(); const bool userMode = KexiMainWindowIface::global()->userMode(); KToolBar *tbar; slotSettingsChanged(0);//KGlobalSettings::FontChanged //! @todo KEXI3 port from KGlobalSettings::Private::_k_slotNotifyChange: //! connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(slotSettingsChanged(int))); // help area QWidget *helpWidget = new QWidget(this); helpWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); QHBoxLayout *helpLyr = new QHBoxLayout(helpWidget); helpLyr->setContentsMargins(0, 0, 0, 0); // * HELP MENU // add help menu actions... (KexiTabbedToolBar depends on them) d->helpMenu = new KHelpMenu(this, KAboutData::applicationData(), true/*showWhatsThis*/); QAction* help_report_bug_action = d->helpMenu->action(KHelpMenu::menuReportBug); d->ac->addAction(help_report_bug_action->objectName(), help_report_bug_action); QObject::disconnect(help_report_bug_action, 0, 0, 0); QObject::connect(help_report_bug_action, SIGNAL(triggered()), mainWin, SLOT(slotReportBug())); - help_report_bug_action->setText(xi18nc("Report a bug or wish for Kexi application", "Report a &Bug or Wish...")); + help_report_bug_action->setText(xi18nc("Report a bug or wish for KEXI application", "Report a &Bug or Wish...")); help_report_bug_action->setIcon(koIcon("tools-report-bug")); // good icon for toolbar - help_report_bug_action->setWhatsThis(xi18n("Files a bug or wish for Kexi application.")); + help_report_bug_action->setWhatsThis(xi18nc( + "@info:whatsthis", "Files a bug or wish for %1 application.", + QApplication::applicationDisplayName())); QAction* help_whats_this_action = d->helpMenu->action(KHelpMenu::menuWhatsThis); d->ac->addAction(help_whats_this_action->objectName(), help_whats_this_action); help_whats_this_action->setWhatsThis(xi18n("Activates a \"What's This?\" tool.")); QAction* help_contents_action = d->helpMenu->action(KHelpMenu::menuHelpContents); d->ac->addAction(help_contents_action->objectName(), help_contents_action); help_contents_action->setText(xi18n("Help")); - help_contents_action->setWhatsThis(xi18n("Shows Kexi Handbook.")); + help_contents_action->setWhatsThis(xi18nc("@info:whatsthis", + "Shows %1 Handbook.", + QApplication::applicationDisplayName())); QAction* help_about_app_action = d->helpMenu->action(KHelpMenu::menuAboutApp); d->ac->addAction(help_about_app_action->objectName(), help_about_app_action); - help_about_app_action->setWhatsThis(xi18n("Shows information about Kexi application.")); + help_about_app_action->setWhatsThis( + xi18nc("@info:whatsthis", "Shows information about %1 application.", + QApplication::applicationDisplayName())); QAction* help_about_kde_action = d->helpMenu->action(KHelpMenu::menuAboutKDE); d->ac->addAction(help_about_kde_action->objectName(), help_about_kde_action); help_about_kde_action->setWhatsThis(xi18n("Shows information about KDE.")); QAction* help_switch_language_action = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); if (help_switch_language_action) { d->ac->addAction(help_switch_language_action->objectName(), help_switch_language_action); } // extra action such as help_donate may be confusing for the user or conflicting with existing so hide it QAction *extraAction = d->helpMenu->action(static_cast(KHelpMenu::menuSwitchLanguage + 1)); if (extraAction) { extraAction->setVisible(false); } QAction *action_show_help_menu = d->ac->action("help_show_menu"); KexiSmallToolButton *btn = new KexiSmallToolButton(koIcon("help-about"), QString(), helpWidget); btn->setToolButtonStyle(Qt::ToolButtonIconOnly); btn->setPopupMode(QToolButton::InstantPopup); btn->setToolTip(action_show_help_menu->toolTip()); btn->setWhatsThis(action_show_help_menu->whatsThis()); btn->setFocusPolicy(Qt::NoFocus); QStyleOptionToolButton opt; opt.initFrom(btn); int w = btn->sizeHint().width(); int wAdd = btn->style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, btn); if (w <= (2 * (wAdd + 1))) { w += wAdd + 2; } btn->setMinimumWidth(w); connect(action_show_help_menu, SIGNAL(triggered()), btn, SLOT(showMenu())); helpLyr->addWidget(btn); btn->setMenu(d->helpMenu->menu()); setCornerWidget(helpWidget, Qt::TopRightCorner); d->searchLineEdit = new KexiSearchLineEdit; kexiTester() << KexiTestObject(d->searchLineEdit, "globalSearch.lineEdit"); d->searchLineEdit->installEventFilter(this); helpLyr->addWidget(d->searchLineEdit); // needed e.g. for Windows style to remove the toolbar's frame QWidget *dummyWidgetForMainMenu = new QWidget(this); dummyWidgetForMainMenu->setObjectName("kexi"); addTab(dummyWidgetForMainMenu, KAboutData::applicationData().displayName()); d->toolbarsVisibleForIndex.append(true); addTab(new QWidget(this), QString()); // dummy for spacer d->toolbarsVisibleForIndex.append(true); if (!userMode) { d->createWidgetToolBar = d->createToolBar("create", xi18n("Create")); } tbar = d->createToolBar("data", xi18n("Data")); addAction(tbar, "edit_cut"); addAction(tbar, "edit_copy"); addAction(tbar, "edit_paste"); if (!userMode) addAction(tbar, "edit_paste_special_data_table"); //! @todo move undo/redo to quickbar: tbar = d->createToolBar("external", xi18n("External Data")); if (!userMode) { addAction(tbar, "project_import_data_table"); addAction(tbar, "tools_import_tables"); } tbar = d->createToolBar("tools", xi18n("Tools")); addAction(tbar, "tools_compact_database"); //! @todo move to form plugin tbar = d->createToolBar("form", xi18n("Form Design")); //! @todo move to report plugin tbar = d->createToolBar("report", xi18n("Report Design")); connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int))); setCurrentWidget(widget(KEXITABBEDTOOLBAR_SPACER_TAB_INDEX + 1)); // the default setFocusPolicy(Qt::NoFocus); } void KexiTabbedToolBar::Private::setCurrentTab(const QString& name) { q->setCurrentWidget(q->toolBar(name)); } void KexiTabbedToolBar::Private::hideTab(const QString& name) { q->removeTab(q->indexOf(toolbarsForName.value(name))); toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = false; } bool KexiTabbedToolBar::Private::isTabVisible(const QString& name) const { return q->indexOf(toolbarsForName.value(name)) != -1 && toolbarsVisibleForIndex[toolbarsIndexForName.value(name)]; } #ifndef NDEBUG void KexiTabbedToolBar::Private::debugToolbars() const { qDebug() << "QHash toolbarsForName:"; for (QHash::ConstIterator it(toolbarsForName.constBegin()); it!=toolbarsForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QHash toolbarsIndexForName:"; for (QHash::ConstIterator it(toolbarsIndexForName.constBegin()); it!=toolbarsIndexForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QHash toolbarsCaptionForName:"; for (QHash::ConstIterator it(toolbarsCaptionForName.constBegin()); it!=toolbarsCaptionForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QVector toolbarsVisibleForIndex:"; for (int i = 0; i < toolbarsVisibleForIndex.size(); i++) { qDebug() << i << "->" << toolbarsVisibleForIndex[i]; } } #endif void KexiTabbedToolBar::Private::showTab(const QString& name) { // qDebug() << "name:" << name; // qDebug() << "toolbarsForName.value(name):" << toolbarsForName.value(name); // qDebug() << "toolbarsIndexForName.value(name):" << toolbarsIndexForName.value(name); // qDebug() << "q->indexOf(toolbarsForName.value(name))" << q->indexOf(toolbarsForName.value(name)); #ifndef NDEBUG //debugToolbars(); #endif if (q->indexOf(toolbarsForName.value(name)) == -1) { int h = 0; // count h = invisible tabs before this for (int i = lowestIndex; i < toolbarsIndexForName.value(name); i++) { if (!toolbarsVisibleForIndex.at(i)) h++; } q->insertTab(toolbarsIndexForName.value(name) - h, toolbarsForName.value(name), toolbarsCaptionForName.value(name)); toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = true; } } // --- KexiTabbedToolBar::~KexiTabbedToolBar() { delete d; } bool KexiTabbedToolBar::mainMenuVisible() const { return d->mainMenu && d->mainMenu->isVisible(); } QRect KexiTabbedToolBar::tabRect(int index) const { return tabBar()->tabRect(index); } KHelpMenu* KexiTabbedToolBar::helpMenu() const { return d->helpMenu; } void KexiTabbedToolBar::slotSettingsChanged(int category) { Q_UNUSED(category); //! @todo if (category == KGlobalSettings::FontChanged) { //! @todo KEXI3 KGlobalSettings::menuFont() not available (using QFontDatabase::systemFont(QFontDatabase::GeneralFont) for now) //! https://community.kde.org/Frameworks/Porting_Notes#Global_Settings setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); // the toolbar acts like a menu //} } KToolBar* KexiTabbedToolBar::createWidgetToolBar() const { return d->createWidgetToolBar; } void KexiTabbedToolBar::mouseMoveEvent(QMouseEvent* event) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR QPoint p = event->pos(); int tab = tabBar()->tabAt(p); if (d->tabToRaise != -1 && (tab == -1 || tab == currentIndex())) { d->tabRaiseTimer.stop(); d->tabToRaise = -1; } else if (d->tabToRaise != tab) { d->tabRaiseTimer.start(); d->tabToRaise = tab; } #endif QTabWidget::mouseMoveEvent(event); } void KexiTabbedToolBar::leaveEvent(QEvent* event) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR d->tabRaiseTimer.stop(); d->tabToRaise = -1; #endif QTabWidget::leaveEvent(event); } bool KexiTabbedToolBar::eventFilter(QObject* watched, QEvent* event) { switch (event->type()) { case QEvent::MouseButtonPress: { QWidget *mainWin = KexiMainWindowIface::global()->thisWidget(); // qDebug() << "MouseButtonPress: watched:" << watched << "window()->focusWidget():" << window()->focusWidget(); if (watched == d->searchLineEdit) { activateSearchLineEdit(); // custom setFocus() for search box, so it's possible to focus // back on Escape key press return false; } else if (watched == tabBar()) { QMouseEvent* me = static_cast(event); QPoint p = me->pos(); KexiTabbedToolBarTabBar *tb = static_cast(tabBar()); int index = tb->tabAt(p); if (index == 0) { d->toggleMainMenu(); return true; } d->hideMainMenu(); if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) { return true; } } else if (watched == mainWin && d->mainMenu) { QMouseEvent* me = static_cast(event); if (!QRect(d->mainMenu->mapToGlobal(QPoint(0,0)), d->mainMenu->size()) .contains(mainWin->mapToGlobal(me->pos()))) { // hide if clicked outside of the menu d->hideMainMenu(); } } } break; case QEvent::KeyPress: { QKeyEvent* ke = static_cast(event); // qDebug() << "**********" << QString::number(ke->key(), 16) // << QKeySequence::mnemonic(tabText(0))[0]; if (QKeySequence::mnemonic(tabText(0)) == QKeySequence(ke->key())) { // qDebug() << "eat the &File accel"; if (!d->mainMenu || !d->mainMenu->isVisible()) { d->showMainMenu(); } /*this could be unexpected: else if (d->mainMenu && d->mainMenu->isVisible()) { d->hideMainMenu(); }*/ return true; } if (d->mainMenu && d->mainMenu->isVisible() && (ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) { d->hideContentsOrMainMenu(); return true; } break; } case QEvent::Resize: if (watched == KexiMainWindowIface::global()->thisWidget()) { d->updateMainMenuGeometry(); } break; case QEvent::Shortcut: { QShortcutEvent *se = static_cast(event); if (watched == tabBar() && QKeySequence::mnemonic(tabText(0)) == se->key()) { // qDebug() << "eat the &File accel"; if (!d->mainMenu || !d->mainMenu->isVisible()) { d->showMainMenu(); return true; } } break; } default:; } return QTabWidget::eventFilter(watched, event); } void KexiTabbedToolBar::slotCurrentChanged(int index) { if (index == indexOf(d->createWidgetToolBar) && index != -1) { if (d->createWidgetToolBar->actions().isEmpty()) { QTimer::singleShot(10, this, SLOT(setupCreateWidgetToolbar())); } } if (d->rolledUp) { // switching the tab rolls down slotTabDoubleClicked(index); } if (index == 0) { // main menu d->showMainMenu(); } else { d->hideMainMenu(); } } void KexiTabbedToolBar::slotTabDoubleClicked(int index) { if (index <= 0) { return; // main item does not count here } d->rolledUp = !d->rolledUp; d->tabBarAnimation.stop(); QWidget *w = widget(index); if (!w) { return; } w->setGraphicsEffect(&d->tabBarOpacityEffect); if (d->rolledUp) { d->tabBarOpacityEffect.setOpacity(1.0); d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect); d->tabBarAnimation.setStartValue(1.0); d->tabBarAnimation.setEndValue(0.0); d->tabBarAnimation.start(); } else { // roll down d->tabBarOpacityEffect.setOpacity(0.0); setMaximumHeight(QWIDGETSIZE_MAX); widget(d->rolledUpIndex)->show(); widget(d->rolledUpIndex)->setMaximumHeight(QWIDGETSIZE_MAX); w->setMaximumHeight(QWIDGETSIZE_MAX); w->show(); d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect); d->tabBarAnimation.setStartValue(0.0); d->tabBarAnimation.setEndValue(1.0); d->tabBarAnimation.start(); } } void KexiTabbedToolBar::tabBarAnimationFinished() { if (d->rolledUp) { // hide and collapse the area widget(currentIndex())->hide(); KexiTabbedToolBarTabBar *tb = static_cast(tabBar()); setFixedHeight(tb->tabSizeHint(currentIndex()).height()); widget(currentIndex())->setFixedHeight(0); d->rolledUpIndex = currentIndex(); } } void KexiTabbedToolBar::setupCreateWidgetToolbar() { if (!d->createWidgetToolBar->actions().isEmpty()) return; //! @todo separate core object types from custom.... KexiPart::PartInfoList *plist = Kexi::partManager().infoList(); //this list is properly sorted if (plist) { foreach(KexiPart::Info *info, *plist) { QAction* a = info->newObjectAction(); if (a) { d->createWidgetToolBar->addAction(a); } else { //! @todo err } } } } void KexiTabbedToolBar::slotDelayedTabRaise() { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR QPoint p = mapFromGlobal(QCursor::pos()); // make sure cursor is still over the tab int tab = tabBar()->tabAt(p); if (tab != d->tabToRaise) { d->tabToRaise = -1; } else if (d->tabToRaise != -1) { setCurrentIndex(d->tabToRaise); d->tabToRaise = -1; } #endif } KToolBar *KexiTabbedToolBar::toolBar(const QString& name) const { return d->toolbarsForName[name]; } void KexiTabbedToolBar::addAction(KToolBar *tbar, const char* actionName) { QAction *a = d->ac->action(actionName); if (a) tbar->addAction(a); } void KexiTabbedToolBar::addAction(const QString& toolBarName, QAction *action) { if (!action) return; KToolBar *tbar = d->toolbarsForName[toolBarName]; if (!tbar) return; tbar->addAction(action); } void KexiTabbedToolBar::addSeparatorAndAction(KToolBar *tbar, const char* actionName) { QAction *a = d->ac->action(actionName); if (a) { tbar->addSeparator(); tbar->addAction(a); } } void KexiTabbedToolBar::appendWidgetToToolbar(const QString& name, QWidget* widget) { KToolBar *tbar = d->toolbarsForName[name]; if (!tbar) { return; } QAction *action = tbar->addWidget(widget); d->extraActions.insert(widget, action); } void KexiTabbedToolBar::setWidgetVisibleInToolbar(QWidget* widget, bool visible) { QAction *action = d->extraActions[widget]; if (!action) { return; } action->setVisible(visible); } void KexiTabbedToolBar::showMainMenu(const char* actionName) { d->showMainMenu(actionName); } void KexiTabbedToolBar::hideMainMenu() { d->hideMainMenu(); } void KexiTabbedToolBar::toggleMainMenu() { d->toggleMainMenu(); } void KexiTabbedToolBar::setMainMenuContent(QWidget *w) { d->mainMenu->setContent(w); } void KexiTabbedToolBar::selectMainMenuItem(const char *actionName) { if (actionName) { KActionCollection *ac = KexiMainWindowIface::global()->actionCollection(); KexiMenuWidgetAction *a = qobject_cast(ac->action(actionName)); if (a) { d->mainMenu->setPersistentlySelectedAction(a, true); } } } void KexiTabbedToolBar::addSearchableModel(KexiSearchableModel *model) { d->searchLineEdit->addSearchableModel(model); } KToolBar* KexiTabbedToolBar::createToolBar(const char* name, const QString& caption) { return d->createToolBar(name, caption); } void KexiTabbedToolBar::setCurrentTab(const QString& name) { //qDebug() << name; d->setCurrentTab(name); } void KexiTabbedToolBar::setCurrentTab(int index) { setCurrentIndex(d->lowestIndex + index); } void KexiTabbedToolBar::hideTab(const QString& name) { //qDebug() << name; d->hideTab(name); } void KexiTabbedToolBar::showTab(const QString& name) { //qDebug() << name; d->showTab(name); } bool KexiTabbedToolBar::isTabVisible(const QString& name) const { return d->isTabVisible(name); } bool KexiTabbedToolBar::isRolledUp() { return d->rolledUp; } void KexiTabbedToolBar::toggleRollDown() { slotTabDoubleClicked(-1);//use -1 just to rolldown/up the tabbar } // --- KexiMainWidget::KexiMainWidget() : KMainWindow(0, Qt::Widget) , m_mainWindow(0) { setupCentralWidget(); } KexiMainWidget::~KexiMainWidget() { } void KexiMainWidget::setParent(KexiMainWindow* mainWindow) { KMainWindow::setParent(mainWindow); m_mainWindow = mainWindow; } KexiMainWindowTabWidget* KexiMainWidget::tabWidget() const { return m_tabWidget; } void KexiMainWidget::setupCentralWidget() { QWidget *centralWidget = new QWidget(this); QVBoxLayout *centralWidgetLyr = new QVBoxLayout(centralWidget); m_tabWidget = new KexiMainWindowTabWidget(centralWidget, this); connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentTabIndexChanged(int))); centralWidgetLyr->setContentsMargins(0, 0, 0, 0); centralWidgetLyr->setSpacing(0); centralWidgetLyr->addWidget(m_tabWidget); setCentralWidget(centralWidget); layout()->setContentsMargins(0, 0, 0, 0); layout()->setSpacing(0); } bool KexiMainWidget::queryClose() { return m_mainWindow ? m_mainWindow->queryClose() : true; } void KexiMainWidget::slotCurrentTabIndexChanged(int index) { KexiWindowContainer* cont = dynamic_cast(m_tabWidget->widget(index)); if (! cont || (KexiWindow*)m_previouslyActiveWindow == cont->window) return; if (m_mainWindow) m_mainWindow->activeWindowChanged(cont->window, (KexiWindow*)m_previouslyActiveWindow); m_previouslyActiveWindow = cont->window; emit currentTabIndexChanged(index); } //------------------------------------------ KexiMainWindow::Private::Private(KexiMainWindow* w) : wnd(w) { actionCollection = new KActionCollection(w); propEditor = 0; propEditorDockWidget = 0; navDockWidget = 0; propEditorTabWidget = 0; KexiProjectData *pdata = KexiStartupHandler::global()->projectData(); userMode = KexiStartupHandler::global()->forcedUserMode() /* <-- simply forced the user mode */ /* project has 'user mode' set as default and not 'design mode' override is found: */ || (pdata && pdata->userMode() && !KexiStartupHandler::global()->forcedDesignMode()); isProjectNavigatorVisible = KexiStartupHandler::global()->isProjectNavigatorVisible(); isMainMenuVisible = KexiStartupHandler::global()->isMainMenuVisible(); navigator = 0; prj = 0; config = KSharedConfig::openConfig(); nameDialog = 0; m_findDialog = 0; focus_before_popup = 0; action_show_nav = 0; action_show_propeditor = 0; action_activate_nav = 0; action_activate_propeditor = 0; action_welcome_projects_title_id = -1; action_welcome_connections_title_id = -1; forceWindowClosing = false; insideCloseWindow = false; #ifndef KEXI_NO_PENDING_DIALOGS actionToExecuteWhenPendingJobsAreFinished = NoAction; #endif propEditorDockSeparatorPos = -1; navDockSeparatorPos = -1; wasAutoOpen = false; windowExistedBeforeCloseProject = false; #ifndef KEXI_SHOW_UNIMPLEMENTED dummy_action = new KActionMenu(QString(), wnd); #endif forceShowProjectNavigatorOnCreation = false; forceHideProjectNavigatorOnCreation = false; navWasVisibleBeforeProjectClosing = false; saveSettingsForShowProjectNavigator = true; propertyEditorCollapsed = false; enable_slotPropertyEditorVisibilityChanged = true; migrateManager = 0; } KexiMainWindow::Private::~Private() { qDeleteAll(m_openedCustomObjectsForItem); } void KexiMainWindow::Private::insertWindow(KexiWindow *window) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.insert(window->id(), window); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.remove(window->id()); #endif } bool KexiMainWindow::Private::windowContainerExistsFor(int identifier) const { return windowContainers.contains(identifier); } void KexiMainWindow::Private::setWindowContainerExistsFor(int identifier, bool set) { if (set) { windowContainers.insert(identifier); } else { windowContainers.remove(identifier); } } void KexiMainWindow::Private::updateWindowId(KexiWindow *window, int oldItemID) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.remove(oldItemID); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.remove(oldItemID); #endif windows.insert(window->id(), window); } void KexiMainWindow::Private::removeWindow(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.remove(identifier); } int KexiMainWindow::Private::openedWindowsCount() { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return windows.count(); } //! Used in KexiMainWindowe::closeProject() void KexiMainWindow::Private::clearWindows() { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.clear(); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.clear(); #endif } void KexiMainWindow::Private::showStartProcessMsg(const QStringList& args) { wnd->showErrorMessage(xi18nc("@info", "Could not start %1 application.", - QString::fromLatin1(KEXI_APP_NAME)), + QApplication::applicationDisplayName()), xi18nc("@info", "Command %1 failed.", args.join(" "))); } void KexiMainWindow::Private::updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info) { if (!propEditorDockWidget) return; KexiWindow *currentWindow = wnd->currentWindow(); if (!info && currentWindow) { info = currentWindow->part()->info(); } const bool visible = (viewMode == Kexi::DesignViewMode) && ((currentWindow && currentWindow->propertySet()) || (info && info->isPropertyEditorAlwaysVisibleInDesignMode())); //qDebug() << "visible == " << visible; enable_slotPropertyEditorVisibilityChanged = false; if (visible && propertyEditorCollapsed) { // used when we're switching back to a window with propeditor available but collapsed propEditorDockWidget->setVisible(!visible); setPropertyEditorTabBarVisible(true); } else { propEditorDockWidget->setVisible(visible); setPropertyEditorTabBarVisible(false); } enable_slotPropertyEditorVisibilityChanged = true; } void KexiMainWindow::Private::setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id, KexiDockWidget *dockWidget, bool visible) { KMultiTabBar *mtbar = multiTabBars.value(position); if (!mtbar) { return; } if (!visible) { mtbar->removeTab(id); } else if (!mtbar->tab(id)) { mtbar->appendTab(koIcon("document-properties"), id, dockWidget->tabText); KMultiTabBarTab *tab = mtbar->tab(id); QObject::connect(tab, SIGNAL(clicked(int)), wnd, SLOT(slotMultiTabBarTabClicked(int)), Qt::UniqueConnection); } } void KexiMainWindow::Private::setPropertyEditorTabBarVisible(bool visible) { setTabBarVisible(KMultiTabBar::Right, PROPERTY_EDITOR_TABBAR_ID, propEditorDockWidget, visible); } QObject *KexiMainWindow::Private::openedCustomObjectsForItem(KexiPart::Item* item, const char* name) { if (!item || !name) { qWarning() << "!item || !name"; return 0; } QByteArray key(QByteArray::number(item->identifier()) + name); return m_openedCustomObjectsForItem.value(key); } void KexiMainWindow::Private::addOpenedCustomObjectForItem(KexiPart::Item* item, QObject* object, const char* name) { QByteArray key(QByteArray::number(item->identifier()) + name); m_openedCustomObjectsForItem.insert(key, object); } KexiFindDialog *KexiMainWindow::Private::findDialog() { if (!m_findDialog) { m_findDialog = new KexiFindDialog(wnd); m_findDialog->setActions(action_edit_findnext, action_edit_findprev, action_edit_replace, action_edit_replace_all); } return m_findDialog; } void KexiMainWindow::Private::updateFindDialogContents(bool createIfDoesNotExist) { if (!wnd->currentWindow()) return; if (!createIfDoesNotExist && (!m_findDialog || !m_findDialog->isVisible())) return; KexiSearchAndReplaceViewInterface* iface = currentViewSupportingSearchAndReplaceInterface(); if (!iface) { if (m_findDialog) { m_findDialog->setButtonsEnabled(false); m_findDialog->setLookInColumnList(QStringList(), QStringList()); } return; } //! @todo use ->caption() here, depending on global settings related to displaying captions findDialog()->setObjectNameForCaption(wnd->currentWindow()->partItem()->name()); QStringList columnNames; QStringList columnCaptions; QString currentColumnName; // for 'look in' if (!iface->setupFindAndReplace(columnNames, columnCaptions, currentColumnName)) { m_findDialog->setButtonsEnabled(false); m_findDialog->setLookInColumnList(QStringList(), QStringList()); return; } m_findDialog->setButtonsEnabled(true); const QString prevColumnName(m_findDialog->currentLookInColumnName()); m_findDialog->setLookInColumnList(columnNames, columnCaptions); m_findDialog->setCurrentLookInColumnName(prevColumnName); } KexiView *KexiMainWindow::Private::currentViewSupportingAction(const char* actionName) const { if (!wnd->currentWindow()) return 0; KexiView *view = wnd->currentWindow()->selectedView(); if (!view) return 0; QAction *action = view->sharedAction(actionName); if (!action || !action->isEnabled()) return 0; return view; } KexiSearchAndReplaceViewInterface* KexiMainWindow::Private::currentViewSupportingSearchAndReplaceInterface() const { if (!wnd->currentWindow()) return 0; KexiView *view = wnd->currentWindow()->selectedView(); if (!view) return 0; return dynamic_cast(view); } tristate KexiMainWindow::Private::showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata) { //pass arguments QMap args; args.insert("mimeType", mimeType); args.insert("databaseName", databaseName); if (cdata) { //pass KDbConnectionData serialized as a string... QString str; KDbUtils::serializeMap(cdata->toMap(), &str); args.insert("connectionData", str); } QDialog *dlg = KexiInternalPart::createModalDialogInstance("org.kexi-project.migration", "migration", wnd, 0, &args); if (!dlg) return false; //error msg has been shown by KexiInternalPart const int result = dlg->exec(); delete dlg; if (result != QDialog::Accepted) return cancelled; //open imported project in a new Kexi instance QString destinationDatabaseName(args["destinationDatabaseName"]); QString fileName, destinationConnectionShortcut; if (!destinationDatabaseName.isEmpty()) { if (args.contains("destinationConnectionShortcut")) { // server-based destinationConnectionShortcut = args["destinationConnectionShortcut"]; } else { // file-based fileName = destinationDatabaseName; destinationDatabaseName.clear(); } tristate res = wnd->openProject(fileName, destinationConnectionShortcut, destinationDatabaseName); wnd->raise(); return res; } return true; } #ifndef KEXI_NO_PENDING_DIALOGS void KexiMainWindow::Private::executeActionWhenPendingJobsAreFinished() { ActionToExecuteWhenPendingJobsAreFinished a = actionToExecuteWhenPendingJobsAreFinished; actionToExecuteWhenPendingJobsAreFinished = NoAction; switch (a) { case QuitAction: qApp->quit(); break; case CloseProjectAction: wnd->closeProject(); break; default:; } } KexiWindow *KexiMainWindow::Private::openedWindowFor(const KexiPart::Item* item, PendingJobType &pendingType) { return openedWindowFor(item->identifier(), pendingType); } KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier, PendingJobType &pendingType) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); QHash::ConstIterator it = pendingWindows.find(identifier); if (it == pendingWindows.end()) pendingType = NoJob; else pendingType = it.value(); if (pendingType == WindowOpeningJob) { return 0; } return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0; } void KexiMainWindow::Private::addItemToPendingWindows(const KexiPart::Item* item, PendingJobType jobType) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); pendingWindows.insert(item->identifier(), jobType); } bool KexiMainWindow::Private::pendingWindowsExist() { if (pendingWindows.begin() != pendingWindows.end()) qDebug() << pendingWindows.constBegin().key() << " " << (int)pendingWindows.constBegin().value(); //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return !pendingWindows.isEmpty(); } void KexiMainWindow::Private::removePendingWindow(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); pendingWindows.remove(identifier); } #else // KEXI_NO_PENDING_DIALOGS KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0; } #endif diff --git a/src/main/KexiRegisterResource_p.h b/src/main/KexiRegisterResource_p.h index 6ac58497f..8e534d2ff 100644 --- a/src/main/KexiRegisterResource_p.h +++ b/src/main/KexiRegisterResource_p.h @@ -1,347 +1,347 @@ /* This file is part of the KDE project Copyright (C) 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. */ #include #include #include #include #include #include #include #ifdef QT_ONLY #define KLocalizedString QString #else #include #include #include #endif //! @todo Support other themes const QString supportedIconTheme = QLatin1String("breeze"); //! @return true if @a path is readable static bool fileReadable(const QString &path) { return !path.isEmpty() && QFileInfo(path).isReadable(); } #ifdef Q_OS_WIN #define KPATH_SEPARATOR ';' #else #define KPATH_SEPARATOR ':' #endif //! @brief Used for a workaround: locations for QStandardPaths::AppDataLocation end with app name. //! If this is not an expected app but for example a test app, replace //! the subdir name with app name so we can find resource file(s). static QStringList correctStandardLocations(const QString &privateName, QStandardPaths::StandardLocation location, const QString &extraLocation) { QStringList result; if (!privateName.isEmpty()) { QRegularExpression re(QLatin1Char('/') + QCoreApplication::applicationName() + QLatin1Char('$')); QStringList standardLocations(QStandardPaths::standardLocations(location)); if (!extraLocation.isEmpty()) { standardLocations.append(extraLocation); } for(const QString &dir : standardLocations) { if (dir.indexOf(re) != -1) { QString realDir(dir); realDir.replace(re, QLatin1Char('/') + privateName); result.append(realDir); } } } return result; } static QString locateFile(const QString &privateName, const QString& path, QStandardPaths::StandardLocation location, const QString &extraLocation) { // let QStandardPaths handle this, it will look for app local stuff QString fullPath = QFileInfo( QStandardPaths::locate(location, path)).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } // Try extra locations if (!extraLocation.isEmpty()) { fullPath = QFileInfo(extraLocation + '/' + path).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } } // This makes the app portable and working without installation, from the build dir const QString dataDir = QFileInfo(QCoreApplication::applicationDirPath() + QStringLiteral("/data/") + path).canonicalFilePath(); if (fileReadable(dataDir)) { return dataDir; } // Try in PATH subdirs, useful for running apps from the build dir, without installing for(const QByteArray &pathDir : qgetenv("PATH").split(KPATH_SEPARATOR)) { const QString dataDirFromPath = QFileInfo(QFile::decodeName(pathDir) + QStringLiteral("/data/") + path).canonicalFilePath(); if (fileReadable(dataDirFromPath)) { return dataDirFromPath; } } const QStringList correctedStandardLocations(correctStandardLocations(privateName, location, extraLocation)); for(const QString &dir : correctedStandardLocations) { fullPath = QFileInfo(dir + QLatin1Char('/') + path).canonicalFilePath(); if (fileReadable(fullPath)) { return fullPath; } } return fullPath; } #ifndef KEXI_SKIP_REGISTERRESOURCE #ifdef KEXI_BASE_PATH #define BASE_PATH KEXI_BASE_PATH #else #define BASE_PATH QCoreApplication::applicationName() #endif static bool registerResource(const QString& path, QStandardPaths::StandardLocation location, const QString &resourceRoot, const QString &extraLocation, KLocalizedString *errorMessage, KLocalizedString *detailsErrorMessage) { const QString fullPath = locateFile(BASE_PATH, path, location, extraLocation); if (fullPath.isEmpty() || !QResource::registerResource(fullPath, resourceRoot)) { QStringList triedLocations(QStandardPaths::standardLocations(location)); if (!extraLocation.isEmpty()) { triedLocations.append(extraLocation); } const QString triedLocationsString = QLocale().createSeparatedList(triedLocations); #ifdef QT_ONLY *errorMessage = QString("Could not open icon resource file %1.").arg(path); *detailsErrorMessage = QString("Tried to find in %1.").arg(triedLocationsString); #else *errorMessage = kxi18nc("@info", "Could not open icon resource file %1." - "Kexi will not start. " - "Please check if Kexi is properly installed.") - .subs(QFileInfo(path).fileName()); + "%2 will not start. " + "Please check if it is properly installed.") + .subs(QFileInfo(path).fileName()).subs(QApplication::applicationDisplayName()); *detailsErrorMessage = kxi18nc("@info Tried to find files in ", "Tried to find in %1.").subs(triedLocationsString); #endif return false; } *errorMessage = KLocalizedString(); *detailsErrorMessage = KLocalizedString(); return true; } #endif // !KEXI_SKIP_REGISTERRESOURCE #ifndef KEXI_SKIP_SETUPBREEZEICONTHEME inline bool registerGlobalBreezeIconsResource(KLocalizedString *errorMessage, KLocalizedString *detailsErrorMessage) { QString extraLocation; #ifdef CMAKE_INSTALL_FULL_ICONDIR extraLocation = QDir::fromNativeSeparators(QFile::decodeName(CMAKE_INSTALL_FULL_ICONDIR)); if (extraLocation.endsWith("/icons")) { extraLocation.chop(QLatin1String("/icons").size()); } #endif return registerResource("icons/breeze/breeze-icons.rcc", QStandardPaths::GenericDataLocation, QStringLiteral("/icons/breeze"), extraLocation, errorMessage, detailsErrorMessage); } //! Tell Qt about the theme inline void setupBreezeIconTheme() { #ifdef QT_GUI_LIB QIcon::setThemeSearchPaths(QStringList() << QStringLiteral(":/icons")); QIcon::setThemeName(QStringLiteral("breeze")); #endif } #endif // !KEXI_SETUPBREEZEICONTHEME #ifndef KEXI_SKIP_REGISTERICONSRESOURCE /*! @brief Registers icons resource file * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param location Standard file location to use for file lookup * @param resourceRoot A resource root for QResource::registerResource() * @param errorMessage On failure it is set to a brief error message. * @param errorDescription On failure it is set to a detailed error message. * other for warning */ static bool registerIconsResource(const QString &privateName, const QString& path, QStandardPaths::StandardLocation location, const QString &resourceRoot, const QString &extraLocation, QString *errorMessage, QString *detailedErrorMessage) { const QString fullPath = locateFile(privateName, path, location, extraLocation); if (fullPath.isEmpty() || !QFileInfo(fullPath).isReadable() || !QResource::registerResource(fullPath, resourceRoot)) { QStringList triedLocations(QStandardPaths::standardLocations(location)); if (!extraLocation.isEmpty()) { triedLocations.append(extraLocation); } triedLocations.append(correctStandardLocations(privateName, location, extraLocation)); const QString triedLocationsString = QLocale().createSeparatedList(triedLocations); #ifdef QT_ONLY *errorMessage = QString("Could not open icon resource file \"%1\". Please check if application " "is properly installed.").arg(path); *detailedErrorMessage = QString("Tried to find in %1.").arg(triedLocationsString); #else *errorMessage = xi18nc( "@info", "Could not open icon resource file %1. " "Please check if %2 is properly installed.", QFileInfo(path).fileName(), QApplication::applicationDisplayName()); *detailedErrorMessage = xi18nc("@info Tried to find files in ", "Tried to find in %1.", triedLocationsString); #endif return false; } *errorMessage = QString(); *detailedErrorMessage = QString(); return true; } #endif // !KEXI_SKIP_SETUPBREEZEICONTHEME #if !defined QT_ONLY && !defined KEXI_SKIP_SETUPPRIVATEICONSRESOURCE /*! @brief Sets up a private icon resource file * @return @c false on failure and sets error message. Does not warn or exit on failure. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param themeName Icon theme to use. It affects filename. * @param errorMessage On failure it is set to a brief error message * @param errorDescription On failure it is set to a detailed error message * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ static bool setupPrivateIconsResource(const QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { // Register application's resource first to have priority over the theme. // Some icons may exists in both resources. if (!registerIconsResource(privateName, path, QStandardPaths::AppDataLocation, QString(), QString(), errorMessage, detailedErrorMessage)) { return false; } bool changeTheme = false; #ifdef QT_GUI_LIB QIcon::setThemeSearchPaths(QStringList() << prefix << QIcon::themeSearchPaths()); changeTheme = 0 != QIcon::themeName().compare(themeName, Qt::CaseInsensitive); if (changeTheme) { QIcon::setThemeName(themeName); } #endif KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); changeTheme = changeTheme || 0 != cg.readEntry("Theme", QString()).compare(themeName, Qt::CaseInsensitive); // tell KIconLoader an co. about the theme if (changeTheme) { cg.writeEntry("Theme", themeName); cg.sync(); } return true; } /*! @brief Sets up a private icon resource file * @return @c false on failure and sets error message. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param themeName Icon theme to use. It affects filename. * @param errorMessage On failure it is set to a brief error message. * @param errorDescription On failure it is set to a detailed error message. * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ static bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { if (!setupPrivateIconsResource(privateName, path, themeName, errorMessage, detailedErrorMessage, prefix)) { if (detailedErrorMessage->isEmpty()) { KMessageBox::error(nullptr, *errorMessage); } else { KMessageBox::detailedError(nullptr, *errorMessage, *detailedErrorMessage); } return false; } return true; } /*! @overload setupPrivateIconsResourceWithMessage(QString &privateName, const QString& path, const QString &themeName, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) Uses default theme name. */ static bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, QString *errorMessage, QString *detailedErrorMessage, const QString &prefix = QLatin1String(":/icons")) { return setupPrivateIconsResourceWithMessage(privateName, path, supportedIconTheme, errorMessage, detailedErrorMessage, prefix); } /*! @brief Sets up a private icon resource file * Warns on failure and returns @c false. * @param privateName Name to be used instead of application name for resource lookup * @param path Relative path to the resource file * @param messageType Type of message to use on error, QtFatalMsg for fatal exit and any * other for warning * @param prefix Resource path prefix. The default is useful for library-global resource, * other values is useful for plugins. */ static bool setupPrivateIconsResourceWithMessage(const QString &privateName, const QString& path, QtMsgType messageType, const QString &prefix = QLatin1String(":/icons")) { QString errorMessage; QString detailedErrorMessage; if (!setupPrivateIconsResourceWithMessage(privateName, path, &errorMessage, &detailedErrorMessage, prefix)) { if (messageType == QtFatalMsg) { qFatal("%s %s", qPrintable(errorMessage), qPrintable(detailedErrorMessage)); } else { qWarning() << qPrintable(errorMessage) << qPrintable(detailedErrorMessage); } return false; } return true; } #endif // !QT_ONLY && !KEXI_SKIP_SETUPPRIVATEICONSRESOURCE diff --git a/src/main/startup/KexiNewProjectAssistant.cpp b/src/main/startup/KexiNewProjectAssistant.cpp index 59e819acc..b3065803d 100644 --- a/src/main/startup/KexiNewProjectAssistant.cpp +++ b/src/main/startup/KexiNewProjectAssistant.cpp @@ -1,686 +1,689 @@ /* This file is part of the KDE project Copyright (C) 2003-2013 Jarosław Staniek Copyright (C) 2012 Dimitrios T. Tanis Copyright (C) 2014 Roman Shtemberko 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 "KexiNewProjectAssistant.h" #include "ui_KexiServerDBNamePage.h" #include "KexiAssistantMessageHandler.h" #include "KexiTemplatesModel.h" #include "KexiStartupFileHandler.h" #include "KexiStartup.h" #include "KexiPasswordPage.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 class KexiServerDBNamePage : public QWidget, public Ui::KexiServerDBNamePage { Q_OBJECT public: explicit KexiServerDBNamePage(QWidget* parent = 0); }; KexiServerDBNamePage::KexiServerDBNamePage(QWidget* parent) : QWidget(parent) { setupUi(this); } // ---- -KexiTemplateSelectionPage::KexiTemplateSelectionPage(QWidget* parent) - : KexiAssistantPage(xi18nc("@title:window", "New Project"), - xi18nc("@info", "Kexi will create a new database project. Select blank database."), - //! @todo Change to this when templates work: "Kexi will create a new database project. Select blank database or template.", - parent) +KexiTemplateSelectionPage::KexiTemplateSelectionPage(QWidget *parent) + : KexiAssistantPage(xi18nc("@title:window", "New Project"), + xi18nc("@info", "%1 will create a new database " + "project. Select blank database.", + QApplication::applicationDisplayName()), + //! @todo Change to this when templates work: "Kexi will create a new + //! database project. Select blank database or template.", + parent) { m_templatesList = new KexiCategorizedView; setFocusWidget(m_templatesList); m_templatesList->setFrameShape(QFrame::NoFrame); m_templatesList->setContentsMargins(0, 0, 0, 0); int margin = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, 0) + KexiUtils::marginHint(); //not needed in grid: m_templatesList->setSpacing(margin); m_templatesList->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); connect(m_templatesList, SIGNAL(activated(QModelIndex)), this, SLOT(slotItemClicked(QModelIndex))); KexiTemplateCategoryInfoList templateCategories; KexiTemplateCategoryInfo templateCategory; templateCategory.name = "blank"; templateCategory.caption = xi18n("Blank Projects"); KexiTemplateInfo info; info.name = "blank"; info.caption = xi18n("Blank database"); info.description = xi18n("Database project without any objects"); info.icon = KexiIcon("document-empty"); templateCategory.addTemplate(info); templateCategories.append(templateCategory); #ifdef KEXI_SHOW_UNIMPLEMENTED templateCategory = KexiTemplateCategoryInfo(); templateCategory.name = "office"; templateCategory.caption = futureI18n("Office Templates"); info = KexiTemplateInfo(); info.name = "contacts"; info.caption = xi18n("Contacts"); info.description = futureI18n("Database for collecting and managing contacts"); info.icon = koIcon("view-pim-contacts"); templateCategory.addTemplate(info); info = KexiTemplateInfo(); info.name = "movie"; info.caption = xi18n("Movie catalog"); info.description = futureI18n("Database for collecting movies"); info.icon = koIcon("video-x-generic"); templateCategory.addTemplate(info); templateCategories.append(templateCategory); #endif // KEXI_SHOW_UNIMPLEMENTED KexiTemplatesProxyModel* proxyModel = new KexiTemplatesProxyModel(m_templatesList); KexiTemplatesModel* model = new KexiTemplatesModel(templateCategories); proxyModel->setSourceModel(model); m_templatesList->setModel(proxyModel); //qDebug() << "templatesCategoryDrawer:" << m_templatesList->categoryDrawer(); setContents(m_templatesList); } void KexiTemplateSelectionPage::slotItemClicked(const QModelIndex& index) { if (!index.isValid()) return; selectedTemplate = index.data(KexiTemplatesModel::NameRole).toString(); selectedCategory = index.data(KexiTemplatesModel::CategoryRole).toString(); m_templatesList->clearSelection(); //! @todo support templates if (selectedTemplate == "blank" && selectedCategory == "blank") { next(); return; } KEXI_UNFINISHED(xi18n("Templates")); } // ---- KexiProjectStorageTypeSelectionPage::KexiProjectStorageTypeSelectionPage(QWidget* parent) : KexiAssistantPage(xi18nc("@title:window", "Storage Method"), xi18nc("@info", "Select a storage method which will be used to store the new project."), parent) , m_fileTypeSelected(true) { setBackButtonVisible(true); QWidget* contents = new QWidget; setupUi(contents); const int dsize = IconSize(KIconLoader::Desktop); btn_file->setIcon(Kexi::defaultFileBasedDriverIcon()); btn_file->setIconSize(QSize(dsize, dsize)); connect(btn_file, SIGNAL(clicked()), this, SLOT(buttonClicked())); btn_server->setIcon(Kexi::serverIcon()); btn_server->setIconSize(QSize(dsize, dsize)); connect(btn_server, SIGNAL(clicked()), this, SLOT(buttonClicked())); setFocusWidget(btn_file); setContents(contents); } KexiProjectStorageTypeSelectionPage::~KexiProjectStorageTypeSelectionPage() { } void KexiProjectStorageTypeSelectionPage::buttonClicked() { m_fileTypeSelected = sender() == btn_file; next(); } // ---- static QString defaultDatabaseName() { return xi18n("New database"); } KexiProjectTitleSelectionPage::KexiProjectTitleSelectionPage(QWidget* parent) : KexiAssistantPage(xi18nc("@title:window", "Project Caption & Filename"), xi18nc("@info", "Enter caption for the new project. " "Filename will be created automatically based on the caption. " "You can change the filename too."), parent) { setBackButtonVisible(true); setNextButtonVisible(true); contents = new KexiDBTitlePage(QString()); contents->formLayout->setSpacing(KexiUtils::spacingHint()); contents->le_title->setText(defaultDatabaseName()); contents->le_title->selectAll(); connect(contents->le_title, SIGNAL(textChanged(QString)), this, SLOT(titleTextChanged(QString))); fileHandler = new KexiStartupFileHandler( QUrl("kfiledialog:///OpenExistingOrCreateNewProject"), KexiFileFilters::SavingFileBasedDB, contents->file_requester); fileHandler->setDefaultExtension("kexi"); connect(fileHandler, SIGNAL(askForOverwriting(KexiContextMessage)), this, SLOT(askForOverwriting(KexiContextMessage))); updateUrl(); setContents(contents); } KexiProjectTitleSelectionPage::~KexiProjectTitleSelectionPage() { delete fileHandler; } void KexiProjectTitleSelectionPage::askForOverwriting(const KexiContextMessage& message) { qDebug() << message.text(); delete messageWidget; messageWidget = new KexiContextMessageWidget(this, contents->formLayout, contents->file_requester, message); messageWidget->setNextFocusWidget(contents->le_title); } void KexiProjectTitleSelectionPage::titleTextChanged(const QString & text) { Q_UNUSED(text); updateUrl(); } void KexiProjectTitleSelectionPage::updateUrl() { fileHandler->updateUrl(contents->le_title->text()); } bool KexiProjectTitleSelectionPage::isAcceptable() { delete messageWidget; if (contents->le_title->text().trimmed().isEmpty()) { messageWidget = new KexiContextMessageWidget(contents->formLayout, contents->le_title, xi18n("Enter project caption.")); contents->le_title->setText(QString()); return false; } QUrl url = contents->file_requester->url(); QFileInfo fileInfo(contents->file_requester->text()); if (fileInfo.dir().isRelative()) { messageWidget = new KexiContextMessageWidget(contents->formLayout, contents->file_requester, xi18nc("@info", "%1 is a relative path." "Enter absolute path of a file to be created.", fileInfo.filePath())); return false; } if (!url.isValid() || !url.isLocalFile() || url.fileName().isEmpty()) { messageWidget = new KexiContextMessageWidget(contents->formLayout, contents->file_requester, xi18n("Enter a valid project filename. The file should be located on this computer.")); return false; } if (fileInfo.isDir()) { messageWidget = new KexiContextMessageWidget(contents->formLayout, contents->file_requester, xi18nc("@info", "%1 is a directory name." "Enter name of a file to be created.", fileInfo.filePath())); return false; } if (!fileHandler->checkSelectedUrl()) { return false; }; QFileInfo writableChecker(fileInfo.dir().path()); if (!writableChecker.isWritable()) { messageWidget = new KexiContextMessageWidget(contents->formLayout, contents->file_requester, xi18nc("@info","Could not create database file %1." "There is no permission to create this file. " "Pick another directory or change permissions so the file can be created.", contents->file_requester->url().toLocalFile())); return false; } //urlSelected(url); // to save recent dir return true; } // ---- KexiProjectCreationPage::KexiProjectCreationPage(QWidget* parent) : KexiAssistantPage(xi18nc("@title:window", "Creating Project"), xi18nc("@info", "Please wait while the project is created."), parent) { QVBoxLayout *vlyr = new QVBoxLayout; QHBoxLayout *lyr = new QHBoxLayout; vlyr->addLayout(lyr); m_progressBar = new QProgressBar; m_progressBar->setRange(0, 0); lyr->addWidget(m_progressBar); lyr->addStretch(1); //! @todo add cancel vlyr->addStretch(1); setContents(vlyr); } KexiProjectCreationPage::~KexiProjectCreationPage() { } // ---- KexiProjectConnectionSelectionPage::KexiProjectConnectionSelectionPage(QWidget* parent) : KexiAssistantPage(xi18nc("@title:window", "Database Connection"), xi18nc("@info", "Select database server's connection you wish to use to " - "create a new Kexi project." + "create a new KEXI project." "Here you may also add, edit or delete connections " "from the list."), parent) { setBackButtonVisible(true); setNextButtonVisible(true); if (KDbDriverManager().hasDatabaseServerDrivers()) { QVBoxLayout *lyr = new QVBoxLayout; connSelector = new KexiConnectionSelectorWidget( &Kexi::connset(), QUrl("kfiledialog:///OpenExistingOrCreateNewProject"), KexiConnectionSelectorWidget::Saving); lyr->addWidget(connSelector); connSelector->showAdvancedConnection(); connect(connSelector, SIGNAL(connectionItemExecuted(ConnectionDataLVItem*)), this, SLOT(next())); connSelector->layout()->setContentsMargins(0, 0, 0, 0); connSelector->hideHelpers(); connSelector->hideDescription(); setContents(lyr); setFocusWidget(connSelector->connectionsList()); } else { setDescription(QString()); setNextButtonVisible(false); m_errorMessagePopup = new KexiServerDriverNotFoundMessage(this); setContents(m_errorMessagePopup); layout()->setAlignment(m_errorMessagePopup, Qt::AlignTop); m_errorMessagePopup->setAutoDelete(false); m_errorMessagePopup->animatedShow(); } } KexiProjectConnectionSelectionPage::~KexiProjectConnectionSelectionPage() { } // ---- KexiProjectDatabaseNameSelectionPage::KexiProjectDatabaseNameSelectionPage( KexiNewProjectAssistant* parent) : KexiAssistantPage(xi18nc("@title:window", "Project Caption & Database Name"), xi18nc("@info", "Enter caption for the new project. " "Database name will be created automatically based on the caption. " "You can change the database name too."), parent) , conndataToShow(0) , m_assistant(parent) { m_projectDataToOverwrite = 0; m_messageWidgetActionYes = 0; m_messageWidgetActionNo = new QAction(KStandardGuiItem::no().text(), this); setBackButtonVisible(true); setNextButtonVisible(true); nextButton()->setLinkText(xi18n("Create")); m_projectSetToShow = 0; m_dbNameAutofill = true; m_le_dbname_txtchanged_enabled = true; contents = new KexiServerDBNamePage; connect(contents->le_title, SIGNAL(textChanged(QString)), this, SLOT(slotTitleChanged(QString))); connect(contents->le_dbname, SIGNAL(textChanged(QString)), this, SLOT(slotNameChanged(QString))); connect(contents->le_title, SIGNAL(returnPressed()), this, SLOT(next())); connect(contents->le_dbname, SIGNAL(returnPressed()), this, SLOT(next())); contents->le_title->setText(defaultDatabaseName()); contents->le_title->selectAll(); KDbIdentifierValidator *idValidator = new KDbIdentifierValidator(this); idValidator->setLowerCaseForced(true); contents->le_dbname->setValidator(idValidator); m_projectSelector = new KexiProjectSelectorWidget( contents->frm_dblist, 0, true, // showProjectNameColumn false // showConnectionColumns ); m_projectSelector->setFocusPolicy(Qt::NoFocus); m_projectSelector->setSelectable(false); m_projectSelector->list()->setFrameStyle(QFrame::NoFrame); GLUE_WIDGET(m_projectSelector, contents->frm_dblist); contents->layout()->setContentsMargins(0, 0, 0, 0); m_projectSelector->layout()->setContentsMargins(0, 0, 0, 0); setContents(contents); setFocusWidget(contents->le_title); } KexiProjectDatabaseNameSelectionPage::~KexiProjectDatabaseNameSelectionPage() { } bool KexiProjectDatabaseNameSelectionPage::setConnection(KDbConnectionData* data) { m_projectSelector->setProjectSet(0); conndataToShow = 0; if (data) { m_projectSetToShow = new KexiProjectSet(m_assistant->messageHandler()); KDbMessageGuard mg(m_projectSetToShow); if (!m_projectSetToShow->setConnectionData(data)) { m_projectSetToShow = 0; return false; } conndataToShow = data; //-refresh projects list m_projectSelector->setProjectSet(m_projectSetToShow); } if (conndataToShow) { QString selectorLabel = xi18nc("@info", "Existing project databases on %1 (%2) database server:", conndataToShow->caption(), conndataToShow->toUserVisibleString()); m_projectSelector->label()->setText(selectorLabel); } return true; } void KexiProjectDatabaseNameSelectionPage::slotTitleChanged(const QString &capt) { if (contents->le_dbname->text().isEmpty()) m_dbNameAutofill = true; if (m_dbNameAutofill) { m_le_dbname_txtchanged_enabled = false; QString captionAsId = KDb::stringToIdentifier(capt).toLower(); contents->le_dbname->setText(captionAsId); m_projectDataToOverwrite = 0; m_le_dbname_txtchanged_enabled = true; } } void KexiProjectDatabaseNameSelectionPage::slotNameChanged(const QString &) { if (!m_le_dbname_txtchanged_enabled) return; m_projectDataToOverwrite = 0; m_dbNameAutofill = false; } QString KexiProjectDatabaseNameSelectionPage::enteredDbName() const { return contents->le_dbname->text().trimmed(); } bool KexiProjectDatabaseNameSelectionPage::isAcceptable() { delete messageWidget; if (contents->le_title->text().trimmed().isEmpty()) { messageWidget = new KexiContextMessageWidget(contents->formLayout, contents->le_title, xi18n("Enter project caption.")); contents->le_title->setText(QString()); return false; } QString dbName(enteredDbName()); if (dbName.isEmpty()) { messageWidget = new KexiContextMessageWidget(contents->formLayout, contents->le_dbname, xi18n("Enter database name.")); return false; } if (m_projectSetToShow) { KexiProjectData* projectData = m_projectSetToShow->findProject(dbName); if (projectData) { if (m_projectDataToOverwrite == projectData) { delete messageWidget; return true; } KexiContextMessage message( xi18n("Database with this name already exists. " "Do you want to delete it and create a new one?")); if (!m_messageWidgetActionYes) { m_messageWidgetActionYes = new QAction(xi18n("Delete and Create New"), this); connect(m_messageWidgetActionYes, SIGNAL(triggered()), this, SLOT(overwriteActionTriggered())); } m_messageWidgetActionNo->setText(KStandardGuiItem::no().text()); message.addAction(m_messageWidgetActionYes); message.setDefaultAction(m_messageWidgetActionNo); message.addAction(m_messageWidgetActionNo); messageWidget = new KexiContextMessageWidget( this, contents->formLayout, contents->le_dbname, message); messageWidget->setMessageType(KMessageWidget::Warning); messageWidget->setNextFocusWidget(contents->le_title); return false; } } return true; } void KexiProjectDatabaseNameSelectionPage::overwriteActionTriggered() { m_projectDataToOverwrite = m_projectSetToShow->findProject(enteredDbName()); next(); } // ---- class Q_DECL_HIDDEN KexiNewProjectAssistant::Private { public: explicit Private(KexiNewProjectAssistant *qq) : q(qq) { } ~Private() { q->setMessageHandler(0); } KexiTemplateSelectionPage* templateSelectionPage() { return page(&m_templateSelectionPage); } KexiProjectStorageTypeSelectionPage* projectStorageTypeSelectionPage() { return page(&m_projectStorageTypeSelectionPage); } KexiProjectTitleSelectionPage* titleSelectionPage() { return page(&m_titleSelectionPage); } KexiProjectCreationPage* projectCreationPage() { return page(&m_projectCreationPage); } KexiProjectConnectionSelectionPage* projectConnectionSelectionPage() { return page(&m_projectConnectionSelectionPage); } KexiProjectDatabaseNameSelectionPage* projectDatabaseNameSelectionPage() { return page(&m_projectDatabaseNameSelectionPage, q); } KexiPasswordPage* passwordPage() { return page(&m_passwordPage, q); } template C* page(QPointer* p, KexiNewProjectAssistant *parent = 0) { if (p->isNull()) { *p = new C(parent); q->addPage(*p); } return *p; } QPointer m_templateSelectionPage; QPointer m_projectStorageTypeSelectionPage; QPointer m_titleSelectionPage; QPointer m_projectCreationPage; QPointer m_projectConnectionSelectionPage; QPointer m_projectDatabaseNameSelectionPage; QPointer m_passwordPage; KexiNewProjectAssistant *q; }; // ---- KexiNewProjectAssistant::KexiNewProjectAssistant(QWidget* parent) : KexiAssistantWidget(parent) , d(new Private(this)) { setCurrentPage(d->templateSelectionPage()); setFocusProxy(d->templateSelectionPage()); setMessageHandler(this); } KexiNewProjectAssistant::~KexiNewProjectAssistant() { delete d; } void KexiNewProjectAssistant::nextPageRequested(KexiAssistantPage* page) { if (page == d->m_templateSelectionPage) { setCurrentPage(d->projectStorageTypeSelectionPage()); } else if (page == d->m_projectStorageTypeSelectionPage) { if (d->projectStorageTypeSelectionPage()->fileTypeSelected()) { setCurrentPage(d->titleSelectionPage()); } else { setCurrentPage(d->projectConnectionSelectionPage()); } } else if (page == d->m_titleSelectionPage) { if (!d->titleSelectionPage()->isAcceptable()) { return; } //file-based project KDbConnectionData cdata; cdata.setDriverId(KDb::defaultFileBasedDriverId()); cdata.setDatabaseName(d->titleSelectionPage()->contents->file_requester->url().toLocalFile()); createProject(cdata, cdata.databaseName(), d->titleSelectionPage()->contents->le_title->text()); } else if (page == d->m_projectConnectionSelectionPage) { KDbConnectionData *cdata = d->projectConnectionSelectionPage()->connSelector->selectedConnectionData(); if (cdata) { if (cdata->isPasswordNeeded()) { d->passwordPage()->setConnectionData(*cdata); setCurrentPage(d->passwordPage()); return; } if (d->projectDatabaseNameSelectionPage()->setConnection(cdata)) { setCurrentPage(d->projectDatabaseNameSelectionPage()); } } } else if (page == d->m_passwordPage) { KDbConnectionData *cdata = d->projectConnectionSelectionPage()->connSelector->selectedConnectionData(); d->passwordPage()->updateConnectionData(cdata); if (cdata && d->projectDatabaseNameSelectionPage()->setConnection(cdata)) { setCurrentPage(d->projectDatabaseNameSelectionPage()); } } else if (page == d->m_projectDatabaseNameSelectionPage) { if (!d->m_projectDatabaseNameSelectionPage->conndataToShow || !d->m_projectDatabaseNameSelectionPage->isAcceptable()) { return; } //server-based project createProject(*d->m_projectDatabaseNameSelectionPage->conndataToShow, d->m_projectDatabaseNameSelectionPage->contents->le_dbname->text().trimmed(), d->m_projectDatabaseNameSelectionPage->contents->le_title->text().trimmed()); } } void KexiNewProjectAssistant::createProject( const KDbConnectionData& cdata, const QString& databaseName, const QString& caption) { KexiProjectData new_data(cdata, databaseName, caption); setCurrentPage(d->projectCreationPage()); emit createProject(new_data); } void KexiNewProjectAssistant::cancelRequested(KexiAssistantPage* page) { Q_UNUSED(page); //! @todo } void KexiNewProjectAssistant::tryAgainActionTriggered() { messageWidget()->animatedHide(); currentPage()->next(); } void KexiNewProjectAssistant::cancelActionTriggered() { if (currentPage() == d->m_passwordPage) { d->passwordPage()->focusWidget()->setFocus(); } } const QWidget* KexiNewProjectAssistant::calloutWidget() const { return currentPage()->nextButton(); } #include "KexiNewProjectAssistant.moc" diff --git a/src/main/startup/KexiOpenExistingFile.ui b/src/main/startup/KexiOpenExistingFile.ui index fca565d0e..57b190fdf 100644 --- a/src/main/startup/KexiOpenExistingFile.ui +++ b/src/main/startup/KexiOpenExistingFile.ui @@ -1,125 +1,125 @@ KexiOpenExistingFile 0 0 328 108 0 1 5 0 0 - <b>Select existing Kexi project file to open:</b> + <b>Select existing KEXI project file to open:</b> Qt::AlignTop true false 32767 8 HLine Sunken 0 6 32767 6 0 0 0 0 &Advanced 1 1 1 0 Click "Advanced" button if you want to find an existing project on a server rather than a file. Qt::AlignTop true false btn_advanced diff --git a/src/main/startup/KexiStartup.cpp b/src/main/startup/KexiStartup.cpp index 4764d7e28..841b89d60 100644 --- a/src/main/startup/KexiStartup.cpp +++ b/src/main/startup/KexiStartup.cpp @@ -1,1042 +1,1044 @@ /* This file is part of the KDE project Copyright (C) 2003-2017 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. */ #include "KexiStartup.h" #include "kexi.h" #include "kexiproject.h" #include "kexiprojectdata.h" #include "kexiprojectset.h" #include "kexiguimsghandler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void destroyStartupHandler() { if (!KexiStartupData::global()) { return; } KexiStartupHandler* startupHandler = static_cast(KexiStartupHandler::global()); delete startupHandler; // resets KexiStartup::global() } class KexiStartupData; //--------------------------------- static bool stripQuotes(const QString &item, QString *name) { if (item.left(1) == "\"" && item.right(1) == "\"") { *name = item.mid(1, item.length() - 2); return true; } *name = item; return false; } //! @internal class Q_DECL_HIDDEN KexiStartupHandler::Private { public: Private(KexiStartupHandler *handler) : q(handler) { } ~Private() { destroyGui(); } void destroyGui() { delete passwordDialog; passwordDialog = 0; delete connDialog; connDialog = 0; } bool findAutoopenObjects() { bool atLeastOneFound = false; KexiProjectData::AutoOpenObjects *objects = q->projectData() ? &q->projectData()->autoopenObjects : nullptr; for (const QCommandLineOption &option : q->options().autoopeningObjectsOptions()) { if (findAutoopenObjects(option, objects)) { atLeastOneFound = true; } } return atLeastOneFound; } bool findAutoopenObjects(const QCommandLineOption &option, KexiProjectData::AutoOpenObjects *objects) { bool atLeastOneFound = false; for (const QString &value : q->values(option)) { QString typeName; QString objectName; int idx; bool nameRequired = true; if (option.names() == q->options().newObject.names()) { objectName.clear(); stripQuotes(value, &typeName); nameRequired = false; } else {//open, design, text... QString defaultType; if (option.names() == q->options().execute.names()) { #ifdef KEXI_MACROS_SUPPORT defaultType = "macro"; #else defaultType = "script"; #endif } else { defaultType = "table"; } //option with " " (set default type) if (stripQuotes(value, &objectName)) { typeName = defaultType; } else if ((idx = value.indexOf(':')) != -1) { //option with type name specified: typeName = value.left(idx).toLower(); objectName = value.mid(idx + 1); (void)stripQuotes(objectName, &objectName); // remove optional quotes } else { //just obj. name: set default type name objectName = value; typeName = defaultType; } } if (typeName.isEmpty()) { continue; } if (nameRequired && objectName.isEmpty()) { continue; } atLeastOneFound = true; if (objects) { KexiProjectData::ObjectInfo info; info.insert("name", objectName); info.insert("type", typeName); info.insert("action", option.names().first()); //ok, now add info for this object objects->append(info); } else { return true; //no need to find more because we do not have project anyway } } //for return atLeastOneFound; } KexiDBPasswordDialog* passwordDialog = nullptr; QString shortcutFileName; KexiDBConnShortcutFile *connShortcutFile = nullptr; KexiDBConnectionDialog *connDialog = nullptr; QString shortcutFileGroupKey; private: KexiStartupHandler* const q; }; //--------------------------------- void updateProgressBar(QProgressDialog *pd, char *buffer, int buflen) { char *p = buffer; QByteArray line; line.reserve(80); for (int i = 0; i < buflen; i++, p++) { if ((i == 0 || buffer[i-1] == '\n') && buffer[i] == '%') { bool ok; int j = 0; ++i; line.clear(); for (;i= '0' && *p <= '9'; j++, i++, p++) line += *p; --i; --p; const int percent = line.toInt(&ok); if (ok && percent >= 0 && percent <= 100 && pd->value() < percent) { // qDebug() << percent; pd->setValue(percent); qApp->processEvents(QEventLoop::AllEvents, 100); } } } } //--------------------------------- KexiStartupHandler::KexiStartupHandler() : QObject(0) , KexiStartupData() , d(new Private(this)) { connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(slotAboutToAppQuit())); } KexiStartupHandler::~KexiStartupHandler() { qRemovePostRoutine(destroyStartupHandler); // post routine is installed! delete d; } KexiStartupHandler* KexiStartupHandler::global() { if (!KexiStartupData::global()) { (void)new KexiStartupHandler; // sets KexiStartup::global() qAddPostRoutine(destroyStartupHandler); } return static_cast(KexiStartupData::global()); } void KexiStartupHandler::slotAboutToAppQuit() { d->destroyGui(); } void prettyPrintPluginMetaData(int maxWidth, const QStringList &labels, QTextStream *out, const KPluginMetaData& metaData) { #define LABEL(n) labels[n] << QString(maxWidth - labels[n].length() + 1, ' ') *out << " * " << metaData.pluginId() << endl << " " << LABEL(0) << metaData.name() << endl << " " << LABEL(1) << metaData.description() << endl << " " << LABEL(2) << metaData.version() << endl << " " << LABEL(3) << metaData.fileName() << endl; #undef LABEL } //! Nicely output a list of plugins static void prettyPrintListOfPlugins() { QTextStream out(stdout); QStringList labels; labels << i18nc("Plugin name", "Name:") << i18nc("Plugin description", "Description:") << i18nc("Plugin version", "Version:") << i18nc("Plugin fileName", "File:"); int maxWidth = -1; foreach(const QString &label, labels) { maxWidth = qMax(maxWidth, label.length()); } // 1. Kexi plugins if (Kexi::partManager().infoList()->isEmpty()) { - out << i18n("No Kexi plugins found.") << endl; + out << i18n("No KEXI plugins found.") << endl; } else { - out << i18n("Kexi plugins (%1):", Kexi::partManager().infoList()->count()) << endl; + out << i18n("KEXI plugins (%1):", Kexi::partManager().infoList()->count()) << endl; foreach(const KexiPart::Info *info, *Kexi::partManager().infoList()) { prettyPrintPluginMetaData(maxWidth, labels, &out, *info); } } // 2. KDb drivers KDbDriverManager driverManager; if (driverManager.driverIds().isEmpty()) { out << i18n("No KDb database driver plugins found.") << endl; } else { out << i18n("KDb database driver plugins (%1):", driverManager.driverIds().count()) << endl; foreach(const QString &pluginId, driverManager.driverIds()) { const KDbDriverMetaData *metaData = driverManager.driverMetaData(pluginId); if (metaData) { prettyPrintPluginMetaData(maxWidth, labels, &out, *metaData); } } } } tristate KexiStartupHandler::handleHighPriorityOptions() { if (isSet(options().listPlugins)) { prettyPrintListOfPlugins(); setAction(Exit); return true; } // option not found: return cancelled; } tristate KexiStartupHandler::init(const QStringList &arguments, const QList &extraOptions) { setAction(DoNothing); tristate res = parseOptions(arguments, extraOptions); if (res != true) { setAction(Exit); return res; } // if (isSet(options().help)) { // helpText // } res = handleHighPriorityOptions(); if (res == true || res == false) { setAction(Exit); return res; } // Other options KDbConnectionData cdata; if (isSet(options().connectionShortcut)) { KexiDBConnShortcutFile connectionShortcut(value(options().connectionShortcut)); if (!connectionShortcut.loadConnectionData(&cdata)) { //! @todo Show error message from KexiDBConnShortcutFile when there's one implemented. //! For we're displaying generic error msg. KMessageBox::sorry(0, xi18nc("@info", "Could not read connection information from connection shortcut " "file %1." "Check whether the file has valid contents.", QDir::toNativeSeparators(connectionShortcut.fileName()))); return false; } } // Set to true if user explicitly sets conn data options from command line. // In this case display login dialog and skip the standard Welcome Wizard. bool connDataOptionsSpecified = false; if (isSet(options().dbDriver)) { cdata.setDriverId(value(options().dbDriver)); connDataOptionsSpecified = true; } QString fileType; if (isSet(options().fileType)) { fileType = value(options().fileType); } if (!positionalArguments().isEmpty() && !fileType.isEmpty()) { if (fileType != "project" && fileType != "shortcut" && fileType != "connection") { KMessageBox::sorry(0, xi18nc("Please don't translate the \"type\" word, it's constant.", "%1 is not valid value for --type " "command-line option. Possible value can be %2, " "%3 or %4", fileType, "project", "shortcut", "connection")); return false; } } if (isSet(options().host)) { cdata.setHostName(value(options().host)); connDataOptionsSpecified = true; } if (isSet(options().localSocket)) { cdata.setLocalSocketFileName(value(options().localSocket)); connDataOptionsSpecified = true; } if (isSet(options().user)) { cdata.setUserName(value(options().user)); connDataOptionsSpecified = true; } bool fileDriverSelected; if (cdata.driverId().isEmpty()) fileDriverSelected = true; else { KDbDriverManager manager; const KDbDriverMetaData *driverMetaData = manager.driverMetaData(cdata.driverId()); if (!driverMetaData) { //driver id provided explicitly, but not found KMessageBox::sorry(0, manager.result().message()); return false; } fileDriverSelected = driverMetaData->isFileBased(); } bool projectFileExists = false; if (isSet(options().port)) { bool ok; const int p = value(options().port).toInt(&ok); if (ok && p > 0) { cdata.setPort(p); connDataOptionsSpecified = true; } else { KMessageBox::sorry(0, xi18n("Invalid port number %1 specified.", value(options().port))); return false; } } if (connDataOptionsSpecified && cdata.driverId().isEmpty()) { KMessageBox::sorry(0, xi18n("Could not open database. No database driver specified.")); return false; } KexiStartupData::setForcedUserMode(isSet(options().userMode)); KexiStartupData::setForcedDesignMode(isSet(options().designMode)); KexiStartupData::setProjectNavigatorVisible(isSet(options().showNavigator)); KexiStartupData::setMainMenuVisible(!isSet(options().hideMenu)); KexiStartupData::setForcedFullScreen(isSet(options().fullScreen)); bool createDB = isSet(options().createDb) || isSet(options().createAndOpenDb); const bool openExisting = !createDB && !isSet(options().dropDb); bool readOnly = isSet(options().readOnly); const QString couldnotMsg = QString::fromLatin1("\n") - + xi18n("Could not start Kexi application this way."); + + xi18nc("@info", "Could not start %1 application this way.", + QApplication::applicationDisplayName()); if (createDB && isSet(options().dropDb)) { KMessageBox::sorry(0, xi18nc("Please don't translate the \"createdb\" and \"dropdb\" words, these are constants.", "Both createdb and dropdb used in startup options.") + couldnotMsg); return false; }; if (createDB || isSet(options().dropDb)) { if (positionalArguments().isEmpty()) { KMessageBox::sorry(0, xi18n("No project name specified.")); return false; } KexiStartupData::setAction(Exit); } //! @todo add option for non-gui; integrate with KWallet; move to static KexiProject method if (!fileDriverSelected && !cdata.driverId().isEmpty() && cdata.password().isEmpty()) { if (cdata.password().isEmpty()) { delete d->passwordDialog; d->passwordDialog = new KexiDBPasswordDialog(0, cdata, KexiDBPasswordDialog::ShowDetailsButton); if (connDataOptionsSpecified) { if (cdata.userName().isEmpty()) { d->passwordDialog->setUsername(QString()); d->passwordDialog->setUsernameReadOnly(false); QLineEdit *userEdit = KexiUtils::findFirstChild(d->passwordDialog, "QLineEdit", "userEdit"); if (userEdit) { userEdit->setFocus(); } } } const int ret = d->passwordDialog->exec(); if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) { } else { KexiStartupData::setAction(Exit); return true; } } } /* qDebug() << "ARGC==" << args->count(); for (int i=0;icount();i++) { qDebug() << "ARG" <user-mode and design-mode words, these are constants.", "Both user-mode and design-mode used in startup options.") + couldnotMsg); return false; } //database filenames, shortcut filenames or db names on a server if (!positionalArguments().isEmpty()) { QString prjName; QString fileName; if (fileDriverSelected) { fileName = positionalArguments().first(); } else { prjName = positionalArguments().first(); } if (fileDriverSelected) { QFileInfo finfo(fileName); prjName = finfo.fileName(); //filename only, to avoid messy names like when Kexi is started with "../../db" arg cdata.setDatabaseName(finfo.absoluteFilePath()); projectFileExists = finfo.exists(); if (isSet(options().dropDb) && !projectFileExists) { KMessageBox::sorry(0, xi18nc("@info", "Could not delete project. The file " "%1 does not exist.", QDir::toNativeSeparators(cdata.databaseName()))); return 0; } } if (createDB) { if (cdata.driverId().isEmpty()) cdata.setDriverId(KDb::defaultFileBasedDriverId()); KexiStartupData::setProjectData(new KexiProjectData(cdata, prjName)); //dummy } else { if (fileDriverSelected) { int detectOptions = 0; if (fileType == "project") detectOptions |= ThisIsAProjectFile; else if (fileType == "shortcut") detectOptions |= ThisIsAShortcutToAProjectFile; else if (fileType == "connection") detectOptions |= ThisIsAShortcutToAConnectionData; if (isSet(options().dropDb)) detectOptions |= DontConvert; if (readOnly) detectOptions |= OpenReadOnly; QString detectedDriverId; KexiStartupData::Import importData = KexiStartupData::importActionData(); bool forceReadOnly; const tristate res = detectActionForFile(&importData, &detectedDriverId, cdata.driverId(), cdata.databaseName(), 0, detectOptions, &forceReadOnly); if (true != res) return res; if (forceReadOnly) { readOnly = true; } KexiStartupData::setImportActionData(importData); if (KexiStartupData::importActionData()) { //importing action KexiStartupData::setAction(ImportProject); return true; } //opening action cdata.setDriverId(detectedDriverId); if (cdata.driverId() == "shortcut") { //get information for a shortcut file KexiStartupData::setProjectData(new KexiProjectData()); d->shortcutFileName = cdata.databaseName(); if (!KexiStartupData::projectData()->load(d->shortcutFileName, &d->shortcutFileGroupKey)) { KMessageBox::sorry(0, xi18nc("@info", "Could not open shortcut file %1.", QDir::toNativeSeparators(cdata.databaseName()))); delete KexiStartupData::projectData(); KexiStartupData::setProjectData(0); return false; } if (KexiStartupData::projectData()->databaseName().isEmpty()) { d->connDialog = new KexiDBConnectionDialog(0, *KexiStartupData::projectData(), d->shortcutFileName); connect(d->connDialog, SIGNAL(saveChanges()), this, SLOT(slotSaveShortcutFileChanges())); int dialogRes = d->connDialog->exec(); if (dialogRes == QDialog::Accepted) { //get (possibly changed) prj data KexiStartupData::setProjectData( new KexiProjectData(d->connDialog->currentProjectData())); } delete d->connDialog; d->connDialog = 0; if (dialogRes == QDialog::Rejected) { delete KexiStartupData::projectData(); KexiStartupData::setProjectData(0); return cancelled; } } } else if (cdata.driverId() == "connection") { //get information for a connection file d->connShortcutFile = new KexiDBConnShortcutFile(cdata.databaseName()); if (!d->connShortcutFile->loadConnectionData(&cdata, &d->shortcutFileGroupKey)) { KMessageBox::sorry(0, xi18nc("@info", "Could not open connection data file %1.", QDir::toNativeSeparators(cdata.databaseName()))); delete d->connShortcutFile; d->connShortcutFile = 0; return false; } bool cancel = false; while (true) { if (isSet(options().skipConnDialog)) { //show connection dialog, so user can change parameters if (!d->connDialog) { d->connDialog = new KexiDBConnectionDialog(0, cdata, d->connShortcutFile->fileName()); connect(d->connDialog, SIGNAL(saveChanges()), this, SLOT(slotSaveShortcutFileChanges())); } const int dialogRes = d->connDialog->exec(); if (dialogRes == QDialog::Accepted) { //get (possibly changed) prj data cdata = *d->connDialog->currentProjectData().connectionData(); } else { cancel = true; break; } } KexiStartupData::setProjectData(selectProject(&cdata, &cancel)); if (KexiStartupData::projectData() || cancel || !isSet(options().skipConnDialog)) break; } delete d->connShortcutFile; d->connShortcutFile = 0; delete d->connDialog; d->connDialog = 0; if (cancel) return cancelled; } else { // !shortcut && !connection KexiStartupData::setProjectData(new KexiProjectData(cdata, prjName)); } } else { // !fileDriverSelected KexiStartupData::setProjectData(new KexiProjectData(cdata, prjName)); } } } if (positionalArguments().count() > 1) { //! @todo KRun another Kexi instance } //let's show connection details, user asked for that in the "password dialog" if (d->passwordDialog && d->passwordDialog->showConnectionDetailsRequested()) { if (KexiStartupData::projectData()) { d->connDialog = new KexiDBConnectionDialog(0, *KexiStartupData::projectData()); } else { d->connDialog = new KexiDBConnectionDialog(0, cdata); } int dialogRes = d->connDialog->exec(); if (dialogRes == QDialog::Accepted) { //get (possibly changed) prj data KexiStartupData::setProjectData(new KexiProjectData(d->connDialog->currentProjectData())); } delete d->connDialog; d->connDialog = 0; if (dialogRes == QDialog::Rejected) { delete KexiStartupData::projectData(); KexiStartupData::setProjectData(0); return cancelled; } } if (positionalArguments().isEmpty() && connDataOptionsSpecified) { bool cancel = false; KexiStartupData::setProjectData(selectProject(&cdata, &cancel)); if (!KexiStartupData::projectData() || cancel) { KexiStartupData::setProjectData(0); return false; } } //---autoopen objects: const bool atLeastOneAOOFound = d->findAutoopenObjects(); if (atLeastOneAOOFound && !openExisting) { KMessageBox::information(0, xi18n("You have specified a few database objects to be opened automatically, " "using startup options.\n" "These options will be ignored because they are not available while creating " "or dropping projects.")); } if (createDB) { bool creationCancelled; KexiGUIMessageHandler gui; KexiProject *prj = KexiProject::createBlankProject(&creationCancelled, *projectData(), &gui); bool ok = prj != 0; delete prj; if (creationCancelled) return cancelled; if (!isSet(options().createAndOpenDb)) { if (ok) { KMessageBox::information(0, xi18nc("@info", "Project %1 created successfully.", QDir::toNativeSeparators(projectData()->databaseName()))); } return ok; } } else if (isSet(options().dropDb)) { KexiGUIMessageHandler gui; res = KexiProject::dropProject(*projectData(), &gui, false/*ask*/); if (res == true) KMessageBox::information(0, xi18nc("@info", "Project %1 dropped successfully.", QDir::toNativeSeparators(projectData()->databaseName()))); return res != false; } //------ KexiPart::PartInfoList *partInfoList = Kexi::partManager().infoList(); if (!partInfoList || partInfoList->isEmpty()) { KexiGUIMessageHandler msgh; msgh.showErrorMessage(Kexi::partManager().result()); KexiStartupData::setProjectData(0); return false; } if (!KexiStartupData::projectData()) { cdata = KDbConnectionData(); //clear KexiStartupData::setAction(ShowWelcomeScreen); return true; //! @todo remove startup dialog code #if 0 if (!d->startupDialog) { //create startup dialog for reuse because it can be used again after conn err. d->startupDialog = new KexiStartupDialog( KexiStartupDialog::Everything, KexiStartupDialog::CheckBoxDoNotShowAgain, Kexi::connset(), 0); } if (d->startupDialog->exec() != QDialog::Accepted) return true; const int r = d->startupDialog->result(); if (r == KexiStartupDialog::CreateBlankResult) { KexiStartupData::setAction(CreateBlankProject); return true; } else if (r == KexiStartupDialog::ImportResult) { KexiStartupData::setAction(ImportProject); return true; } #ifdef KEXI_PROJECT_TEMPLATES else if (r == KexiStartupDialog::CreateFromTemplateResult) { const QString selFile(d->startupDialog->selectedFile()); cdata.setDatabaseName(selFile); QString detectedDriverId; KexiStartupData::Import importData = KexiStartupData::importActionData(); res = detectActionForFile(&importData, &detectedDriverId, cdata.driverId(), selFile); if (true != res) return res; KexiStartupData::setImportActionData(importData); if (KexiStartupData::importActionData() || detectedDriverId.isEmpty()) return false; cdata.setDriverId(detectedDriverId); KexiStartupData::setProjectData(new KexiProjectData(cdata, selFile)); KexiStartupData::projectData()->autoopenObjects = d->startupDialog->autoopenObjects(); KexiStartupData::setAction(CreateFromTemplate); return true; } #endif else if (r == KexiStartupDialog::OpenExistingResult) { const QString selectedFile(d->startupDialog->selectedFile()); if (!selectedFile.isEmpty()) { //file-based project cdata.setDatabaseName(selectedFile); QString detectedDriverId; KexiStartupData::Import importData = KexiStartupData::importActionData(); res = detectActionForFile(&importData, &detectedDriverId, cdata.driverId(), selectedFile); if (true != res) return res; KexiStartupData::setImportActionData(importData); if (KexiStartupData::importActionData()) { //importing action KexiStartupData::setAction(ImportProject); return true; } if (detectedDriverId.isEmpty()) return false; cdata.setDriverId(detectedDriverId); KexiStartupData::setProjectData(new KexiProjectData(cdata, selectedFile)); } else if (d->startupDialog->selectedExistingConnection()) { KDbConnectionData *cdata = d->startupDialog->selectedExistingConnection(); //ok, now we will try to show projects for this connection to the user bool cancelled; KexiStartupData::setProjectData(selectProject(cdata, &cancelled)); if ((!KexiStartupData::projectData() && !cancelled) || cancelled) { //try again return init(); } //not needed anymore delete d->startupDialog; d->startupDialog = 0; } } if (!KexiStartupData::projectData()) return true; #endif } if (KexiStartupData::projectData() && (openExisting || (createDB && isSet(options().createAndOpenDb)))) { KexiStartupData::projectData()->setReadOnly(readOnly); KexiStartupData::setAction(OpenProject); } return true; } tristate KexiStartupHandler::detectActionForFile( KexiStartupData::Import* detectedImportAction, QString *detectedDriverId, const QString& _suggestedDriverId, const QString &databaseName, QWidget *parent, int options, bool *forceReadOnly) { Q_ASSERT(detectedDriverId); *detectedImportAction = KexiStartupData::Import(); //clear if (forceReadOnly) { *forceReadOnly = false; } QString suggestedDriverId(_suggestedDriverId); //safe detectedDriverId->clear(); QFileInfo finfo(databaseName); if (databaseName.isEmpty()) { if (!(options & SkipMessages)) { KMessageBox::sorry(parent, xi18nc("@info", "Could not open file. Missing filename."), xi18nc("@title:window", "Could Not Open File")); } return false; } if (!finfo.exists()) { if (!(options & SkipMessages)) { KMessageBox::sorry(parent, xi18nc("@info", "Could not open file. " "The file %1 does not exist.", QDir::toNativeSeparators(databaseName)), xi18nc("@title:window", "Could Not Open File" )); } return false; } if (!finfo.isReadable()) { if (!(options & SkipMessages)) { KMessageBox::sorry(parent, xi18nc("@info", "Could not open file %1 for reading." "Check the file's permissions and whether it is " "already opened and locked by another application.", QDir::toNativeSeparators(databaseName)), xi18nc("@title:window", "Could Not Open File" )); } return false; } if (!(options & OpenReadOnly) && !finfo.isWritable()) { if (!KexiProject::askForOpeningNonWritableFileAsReadOnly(parent, finfo)) { return false; } if (forceReadOnly) { *forceReadOnly = true; } } QMimeType mime; QString mimename; const bool thisIsShortcut = (options & ThisIsAShortcutToAProjectFile) || (options & ThisIsAShortcutToAConnectionData); if ((options & ThisIsAProjectFile) || !thisIsShortcut) { //try this detection if "project file" mode is forced or no type is forced: QMimeDatabase db; mime = db.mimeTypeForFile(databaseName, QMimeDatabase::MatchContent); if (mime.isValid()) { mimename = mime.name(); } //qDebug() << "found mime is:" << mimename; if (mimename.isEmpty() || mimename == "application/octet-stream" || mimename == "text/plain") { //try by URL: mime = db.mimeTypeForUrl(QUrl::fromLocalFile(databaseName)); mimename = mime.name(); } } if (mimename.isEmpty() || mimename == "application/octet-stream") { // perhaps the file is locked QFile f(databaseName); if (!f.open(QIODevice::ReadOnly)) { // BTW: similar error msg is provided in SQLiteConnection::drv_useDatabase() if (!(options & SkipMessages)) { KMessageBox::sorry(parent, xi18nc("@info", "Could not open project." "The file %1 is not readable. " "Check the file's permissions and whether it is already opened " "and locked by another application.", QDir::toNativeSeparators(databaseName))); } return false; } } if ((options & ThisIsAShortcutToAProjectFile) || mimename == "application/x-kexiproject-shortcut") { *detectedDriverId = "shortcut"; return true; } if ((options & ThisIsAShortcutToAConnectionData) || mimename == "application/x-kexi-connectiondata") { *detectedDriverId = "connection"; return true; } //! @todo rather check this use migration drivers' X-KexiSupportedMimeTypes [strlist] property if (mime.isValid()) { if (mimename == "application/vnd.ms-access") { if ((options & SkipMessages) || KMessageBox::Yes != KMessageBox::questionYesNo( parent, xi18nc("@info", "%1 is an external file of type %2." - "Do you want to import the file as a Kexi project?", + "Do you want to import the file as a KEXI project?", QDir::toNativeSeparators(databaseName), mime.comment()), xi18n("Open External File"), KGuiItem(xi18nc("@action:button Import File", "Import..."), KexiIconName("database-import")), KStandardGuiItem::cancel())) { return cancelled; } detectedImportAction->mimeType = mimename; detectedImportAction->fileName = databaseName; return true; } } if (!finfo.isWritable()) { //! @todo if file is ro: change project mode (but do not care if we're jsut importing) } // "application/x-kexiproject-sqlite", etc.: const QStringList driverIdsForMimeType = Kexi::driverManager().driverIdsForMimeType(mimename); QString compatibleDatabaseDriverId; if (!driverIdsForMimeType.isEmpty()) { //! @todo if there are more drivers to pick, ask which to use compatibleDatabaseDriverId = driverIdsForMimeType.first(); } bool useDetectedDriver = suggestedDriverId.isEmpty() || suggestedDriverId.compare(*detectedDriverId, Qt::CaseInsensitive) == 0; if (!useDetectedDriver) { if (compatibleDatabaseDriverId.isEmpty()) { //! @todo error message "Could not detect database driver to use" return false; } KMessageBox::ButtonCode res = KMessageBox::Yes; if (!(options & SkipMessages)) res = KMessageBox::warningYesNoCancel(parent, xi18nc("@info", "The project file %1 is recognized as compatible with " "%2 database driver, " "while you have asked for %3 database driver to be used.\n" "Do you want to use %4 database driver?", QDir::toNativeSeparators(databaseName), compatibleDatabaseDriverId, suggestedDriverId, compatibleDatabaseDriverId)); if (KMessageBox::Yes == res) useDetectedDriver = true; else if (KMessageBox::Cancel == res) return cancelled; } if (useDetectedDriver) { *detectedDriverId = compatibleDatabaseDriverId; } else { //use the suggested driver *detectedDriverId = suggestedDriverId; } // qDebug() << "driver id:" << detectedDriverName; if (detectedDriverId->isEmpty()) { QString possibleProblemsMessage(Kexi::driverManager().possibleProblemsMessage()); if (!possibleProblemsMessage.isEmpty()) { possibleProblemsMessage = xi18n("Possible problems: %1", possibleProblemsMessage); } if (!(options & SkipMessages)) { const QString comment(mime.comment().isEmpty() ? QString() : QString::fromLatin1(" (%1)").arg(mime.comment())); KMessageBox::detailedSorry(parent, xi18nc("@info", - "The file %1 is not recognized as being supported by Kexi.", - QDir::toNativeSeparators(databaseName)), + "The file %1 is not recognized as being supported by " + "%1.", + QDir::toNativeSeparators(databaseName), QApplication::applicationDisplayName()), possibleProblemsMessage.isEmpty() ? xi18nc("@info", "Could not find plugin supporting for this file type." "Detected MIME type is %1%2.", mimename, comment) : xi18nc("@info", "Could not find plugin supporting for this file type." "Detected MIME type is %1%2.%3", mimename, comment, possibleProblemsMessage)); } return false; } return true; } KexiProjectData* KexiStartupHandler::selectProject(KDbConnectionData *cdata, bool *cancelled, QWidget *parent) { clearStatus(); *cancelled = false; if (!cdata) return 0; if (!cdata->savePassword() && cdata->password().isEmpty()) { if (!d->passwordDialog) d->passwordDialog = new KexiDBPasswordDialog(0, *cdata); const int ret = d->passwordDialog->exec(); if (d->passwordDialog->showConnectionDetailsRequested() || ret == QDialog::Accepted) { } else { *cancelled = true; return 0; } } KexiProjectData* projectData = 0; //dialog for selecting a project KexiProjectSelectorDialog prjdlg(parent, *cdata, true, false); if (!prjdlg.projectSet() || prjdlg.projectSet()->result().isError()) { KexiGUIMessageHandler msgh; QString msg(xi18n("Could not load list of available projects for %1 database server.", cdata->toUserVisibleString())); if (prjdlg.projectSet()) { msgh.showErrorMessage(msg, prjdlg.projectSet()); } else { msgh.showErrorMessage(msg, QString()); } return 0; } if (prjdlg.exec() != QDialog::Accepted) { *cancelled = true; return 0; } if (prjdlg.selectedProjectData()) { //deep copy projectData = new KexiProjectData(*prjdlg.selectedProjectData()); } return projectData; } void KexiStartupHandler::slotSaveShortcutFileChanges() { bool ok = true; QString fileName; if (!d->shortcutFileName.isEmpty()) { fileName = d->shortcutFileName; ok = d->connDialog->currentProjectData().save( d->shortcutFileName, d->connDialog->savePasswordOptionSelected(), &d->shortcutFileGroupKey); } else if (d->connShortcutFile) { fileName = d->connShortcutFile->fileName(); ok = d->connShortcutFile->saveConnectionData( *d->connDialog->currentProjectData().connectionData(), d->connDialog->savePasswordOptionSelected(), &d->shortcutFileGroupKey); } if (!ok) { KMessageBox::sorry(0, xi18n("Failed saving connection data to %1 file.", QDir::toNativeSeparators(fileName))); } } diff --git a/src/main/startup/KexiWelcomeAssistant.cpp b/src/main/startup/KexiWelcomeAssistant.cpp index dee6efe64..84f863cde 100644 --- a/src/main/startup/KexiWelcomeAssistant.cpp +++ b/src/main/startup/KexiWelcomeAssistant.cpp @@ -1,281 +1,281 @@ /* This file is part of the KDE project Copyright (C) 2011-2013 Jarosław Staniek 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 "KexiWelcomeAssistant.h" #include "KexiRecentProjectsModel.h" #include "KexiWelcomeStatusBar.h" #include "KexiPasswordPage.h" #include "KexiMainWindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KexiMainWelcomePage::KexiMainWelcomePage( KexiWelcomeAssistant* assistant, QWidget* parent) - : KexiAssistantPage(xi18nc("@title:window", "Welcome to Kexi"), + : KexiAssistantPage(xi18nc("@title:window", "Welcome to KEXI"), xi18nc("@info", "Select one of the recently used projects to open."), parent) , m_assistant(assistant) { QWidget* contents = new QWidget; QHBoxLayout* contentsLyr = new QHBoxLayout(contents); m_recentProjects = new KexiCategorizedView; // do not alter background palette QPalette pal(m_recentProjects->palette()); pal.setColor(QPalette::Disabled, QPalette::Base, pal.color(QPalette::Normal, QPalette::Base)); m_recentProjects->setPalette(pal); contentsLyr->addWidget(m_recentProjects, 1); setFocusWidget(m_recentProjects); m_recentProjects->setFrameShape(QFrame::NoFrame); m_recentProjects->setContentsMargins(0, 0, 0, 0); int margin = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, 0) + KexiUtils::marginHint(); //not needed in grid: m_recentProjects->setSpacing(margin); m_recentProjects->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); if (KexiUtils::activateItemsOnSingleClick(m_recentProjects)) { connect(m_recentProjects, SIGNAL(clicked(QModelIndex)), this, SLOT(slotItemClicked(QModelIndex))); } else { connect(m_recentProjects, SIGNAL(activated(QModelIndex)), this, SLOT(slotItemClicked(QModelIndex))); } m_statusBar = new KexiWelcomeStatusBar; contentsLyr->addWidget(m_statusBar); setContents(contents); QTimer::singleShot(100, this, SLOT(loadProjects())); } void KexiMainWelcomePage::loadProjects() { m_recentProjectsProxyModel = new KexiRecentProjectsProxyModel(m_recentProjects); KexiRecentProjectsModel* model = new KexiRecentProjectsModel(*m_assistant->projects(), this); m_recentProjectsProxyModel->setSourceModel(model); m_recentProjects->setModel(m_recentProjectsProxyModel); m_recentProjectsProxyModel->sort(0, Qt::DescendingOrder); } void KexiMainWelcomePage::slotItemClicked(const QModelIndex& index) { if (!index.isValid()) return; m_clickedIndex = index; QModelIndex sourceIndex = m_recentProjectsProxyModel->mapToSource(index); KexiProjectData *pdata = static_cast(sourceIndex.internalPointer()); //qDebug() << *pdata; if (pdata) { m_assistant->openProjectOrShowPasswordPage(pdata); } } void KexiMainWelcomePage::updateRecentProjects() { m_recentProjects->update(); } // ---- class Q_DECL_HIDDEN KexiWelcomeAssistant::Private { public: explicit Private(KexiWelcomeAssistant *qq) : q(qq) { } ~Private() { mainWindow->setRedirection(0); } KexiMainWelcomePage* mainWelcomePage() { return page(&m_mainWelcomePage, q); } KexiPasswordPage* passwordPage() { return page(&m_passwordPage, q); } template C* page(QPointer* p, KexiWelcomeAssistant *parent = 0) { if (p->isNull()) { *p = new C(parent); q->addPage(*p); } return *p; } QPointer m_mainWelcomePage; QPointer m_passwordPage; QAction* messageWidgetActionNo; QAction* messageWidgetActionTryAgain; QPointer messageWidget; KexiRecentProjects* projects; QPointer projectData; KexiMainWindow *mainWindow; KexiWelcomeAssistant *q; }; // ---- KexiWelcomeAssistant::KexiWelcomeAssistant( KexiRecentProjects* projects, KexiMainWindow* parent) : KexiAssistantWidget(parent) , d(new Private(this)) { d->mainWindow = parent; d->mainWindow->setRedirection(this); d->messageWidgetActionNo = 0; d->messageWidgetActionTryAgain = 0; d->projects = projects; setCurrentPage(d->mainWelcomePage()); setFocusProxy(d->mainWelcomePage()); } KexiWelcomeAssistant::~KexiWelcomeAssistant() { delete d; } void KexiWelcomeAssistant::nextPageRequested(KexiAssistantPage* page) { if (page == d->m_passwordPage) { if (d->projectData) { d->passwordPage()->updateConnectionData(d->projectData->connectionData()); emitOpenProject(d->projectData); } } else { d->projectData = 0; } } void KexiWelcomeAssistant::cancelRequested(KexiAssistantPage* page) { Q_UNUSED(page); //! @todo } KexiRecentProjects* KexiWelcomeAssistant::projects() { return d->projects; } void KexiWelcomeAssistant::emitOpenProject(KexiProjectData *data) { bool opened = false; emit openProject(*data, projects()->shortcutPath(*data), &opened); if (opened) { // update recent projects view data->setLastOpened(QDateTime::currentDateTime()); d->m_mainWelcomePage->updateRecentProjects(); } } void KexiWelcomeAssistant::openProjectOrShowPasswordPage(KexiProjectData *data) { KDbConnectionData *cdata = data->connectionData(); if (cdata) { if (cdata->isPasswordNeeded()) { d->projectData = data; d->passwordPage()->setConnectionData(*cdata); d->passwordPage()->showDatabaseName(true); d->passwordPage()->setDatabaseNameReadOnly(true); d->passwordPage()->setDatabaseName(data->databaseName()); setCurrentPage(d->passwordPage()); return; } else { d->projectData = 0; emitOpenProject(data); } } } void KexiWelcomeAssistant::tryAgainActionTriggered() { if (currentPage() == d->mainWelcomePage()) { d->mainWelcomePage()->slotItemClicked(d->mainWelcomePage()->clickedItem()); } else if (currentPage() == d->passwordPage()) { currentPage()->next(); } } void KexiWelcomeAssistant::cancelActionTriggered() { if (currentPage() == d->mainWelcomePage()) { d->mainWelcomePage()->recentProjectsView()->clearSelection(); } else if (currentPage() == d->passwordPage()) { d->passwordPage()->focusWidget()->setFocus(); } } const QWidget* KexiWelcomeAssistant::calloutWidget() const { if (currentPage() == d->mainWelcomePage()) { return d->mainWelcomePage()->recentProjectsView(); } else if (currentPage() == d->passwordPage()) { return currentPage()->nextButton(); } return 0; } QPoint KexiWelcomeAssistant::calloutPointerPosition() const { if (currentPage() == d->mainWelcomePage()) { const QRect clickedItemRect = d->mainWelcomePage()->recentProjectsView()->visualRect( d->mainWelcomePage()->clickedItem()); return QPoint(clickedItemRect.center().x(), clickedItemRect.bottom()); } else if (currentPage() == d->passwordPage()) { return KexiAssistantMessageHandler::calloutPointerPosition(); } return QPoint(); } KMessageWidget::CalloutPointerDirection KexiWelcomeAssistant::calloutPointerDirection() const { if (currentPage() == d->mainWelcomePage()) { return KMessageWidget::Up; } else { return KexiAssistantMessageHandler::calloutPointerDirection(); } } diff --git a/src/main/startup/KexiWelcomeStatusBar.cpp b/src/main/startup/KexiWelcomeStatusBar.cpp index 417ae27b6..aa833310a 100644 --- a/src/main/startup/KexiWelcomeStatusBar.cpp +++ b/src/main/startup/KexiWelcomeStatusBar.cpp @@ -1,1229 +1,1229 @@ /* This file is part of the KDE project Copyright (C) 2011-2012 Jarosław Staniek 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 "KexiWelcomeStatusBar.h" #include "KexiWelcomeStatusBar_p.h" #include #include #include #include #include #include "KexiUserFeedbackAgent.h" #define KEXI_SKIP_SETUPPRIVATEICONSRESOURCE #define KEXI_SKIP_SETUPBREEZEICONTHEME #define KEXI_SKIP_REGISTERICONSRESOURCE #define KEXI_SKIP_REGISTERRESOURCE #include "KexiRegisterResource_p.h" #include #include #include #include #include #include #include #include #if defined(Q_OS_WIN) || defined(Q_OS_MACOS) # include # include # include # include #else # define USE_KIO_COPY # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class QNetworkReply; class KJob; static const int GUI_UPDATE_INTERVAL = 60; // update interval for GUI, in minutes static const int DONATION_INTERVAL = 10; // donation interval, in days static const int UPDATE_FILES_LIST_SIZE_LIMIT = 1024 * 128; static const int UPDATE_FILES_COUNT_LIMIT = 128; //! @return x.y.0 static QString stableVersionStringDot0() { return QString::number(Kexi::stableVersionMajor()) + '.' + QString::number(Kexi::stableVersionMinor()) + ".0"; } static QString uiPath(const QString &fname) { KexiUserFeedbackAgent *f = KexiMainWindowIface::global()->userFeedbackAgent(); return f->serviceUrl() + QString("/ui/%1/").arg(stableVersionStringDot0()) + fname; } static QString basePath() { return QString(KEXI_BASE_PATH "/status"); } static QString findFileName(const QString &guiFileName) { QString result = locateFile(QString(), basePath() + '/' + guiFileName, QStandardPaths::GenericDataLocation, QString()); if (result.isEmpty()) { // last chance: file from the source tree result = QFileInfo(QFile::decodeName(CMAKE_CURRENT_SOURCE_DIR "/status/") + guiFileName) .canonicalFilePath(); } //qDebug() << result; return result; } // --- class Q_DECL_HIDDEN KexiWelcomeStatusBarGuiUpdater::Private : public QObject { Q_OBJECT public: Private() : configGroup(KConfigGroup(KSharedConfig::openConfig()->group("User Feedback"))) { } KConfigGroup configGroup; public Q_SLOTS: void sendRequestListFilesFinished(KJob* job) { if (job->error()) { qWarning() << "Error while receiving .list file - no files will be updated"; //! @todo error... return; } KIO::StoredTransferJob* sendJob = qobject_cast(job); QString result = sendJob->data(); if (result.length() > UPDATE_FILES_LIST_SIZE_LIMIT) { // anti-DOS protection qWarning() << "Too large .list file (" << result.length() << "); the limit is" << UPDATE_FILES_LIST_SIZE_LIMIT << "- no files will be updated"; return; } //qDebug() << result; QStringList data = result.split('\n', QString::SkipEmptyParts); result.clear(); m_fileNamesToUpdate.clear(); if (data.count() > UPDATE_FILES_COUNT_LIMIT) { // anti-DOS protection qWarning() << "Too many files to update (" << data.count() << "); the limit is" << UPDATE_FILES_COUNT_LIMIT << "- no files will be updated"; return; } // OK, try to update (stage 1: check, stage 2: checking) for (int stage = 1; stage <= 2; stage++) { int i = 0; for (QStringList::ConstIterator it(data.constBegin()); it!=data.constEnd(); ++it, i++) { const QByteArray hash((*it).left(32).toLatin1()); const QString remoteFname((*it).mid(32 + 2)); if (stage == 1) { if (hash.length() != 32) { qWarning() << "Invalid hash" << hash << "in line" << i+1 << "- no files will be updated"; return; } if ((*it).mid(32, 2) != " ") { qWarning() << "Two spaces expected but found" << (*it).mid(32, 2) << "in line" << i+1 << "- no files will be updated"; return; } if (remoteFname.contains(QRegularExpression("\\s"))) { qWarning() << "Filename expected without whitespace but found" << remoteFname << "in line" << i+1 << "- no files will be updated"; return; } } else if (stage == 2) { checkFile(hash, remoteFname, &m_fileNamesToUpdate); } } } if (m_fileNamesToUpdate.isEmpty()) { qDebug() << "No files to update."; return; } // update files QList sourceFiles; foreach (const QString &fname, m_fileNamesToUpdate) { sourceFiles.append(QUrl(uiPath(fname))); } m_tempDir.reset(new QTemporaryDir(QDir::tempPath() + "/kexi-status")); //qDebug() << m_tempDir->path(); #ifdef USE_KIO_COPY KIO::CopyJob *copyJob = KIO::copy(sourceFiles, QUrl::fromLocalFile(m_tempDir->path()), KIO::HideProgressInfo | KIO::Overwrite); connect(copyJob, &KIO::CopyJob::result, this, &Private::filesCopyFinished); #else if (!m_downloadManager) { m_downloadManager = new QNetworkAccessManager(this); connect(m_downloadManager.data(), &QNetworkAccessManager::finished, this, &Private::fileDownloadFinished); } m_sourceFilesToDownload = sourceFiles; downloadNextFile(); #endif //qDebug() << "copying from" << QUrl(uiPath(fname)) << "to" // << (dir + fname); } private Q_SLOTS: void filesCopyFinished(KJob* job) { #ifdef USE_KIO_COPY if (job->error()) { //! @todo error... qDebug() << "ERROR:" << job->errorString(); m_tempDir.reset(); return; } KIO::CopyJob* copyJob = qobject_cast(job); Q_UNUSED(copyJob) //qDebug() << "DONE" << copyJob->destUrl(); (void)copyFilesToDestinationDir(); #else Q_UNUSED(job) #endif } void fileDownloadFinished(QNetworkReply* reply) { #ifdef USE_KIO_COPY Q_UNUSED(reply) #else const bool ok = copyFile(reply); reply->deleteLater(); if (!ok) { qWarning() << "Error downloading file" << m_sourceFilesToDownload.first(); delete m_downloadManager; m_sourceFilesToDownload.clear(); m_tempDir.reset(); } m_sourceFilesToDownload.removeFirst(); downloadNextFile(); #endif } bool copyFile(QNetworkReply* reply) { #ifdef USE_KIO_COPY Q_UNUSED(reply) #else #define DOWNLOAD_BUFFER_SIZE 1024 * 50 if (reply->error() != QNetworkReply::NoError) { return false; } const QString filename(m_sourceFilesToDownload.first().fileName()); QString path(m_tempDir->path() + '/' + filename); QSaveFile f(path); if (!f.open(QIODevice::WriteOnly)) { return false; } QByteArray buf(DOWNLOAD_BUFFER_SIZE, Qt::Uninitialized); while (!reply->atEnd()) { const qint64 size = reply->read(buf.data(), buf.size()); if (size < 0) { return false; } if (f.write(buf.data(), size) != size) { return false; } } if (!f.commit()) { return false; } #endif return true; } private: #ifndef USE_KIO_COPY void downloadNextFile() { if (m_sourceFilesToDownload.isEmpty()) { // success (void)copyFilesToDestinationDir(); return; } m_downloadManager->get(QNetworkRequest(m_sourceFilesToDownload.first())); } #endif private: bool copyFilesToDestinationDir() { const QString dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + basePath() + '/'); bool ok = true; if (!QDir(dir).exists()) { if (!QDir().mkpath(dir)) { ok = false; qWarning() << "Could not create" << dir; } } if (ok) { foreach (const QString &fname, m_fileNamesToUpdate) { const QByteArray oldName(QFile::encodeName(m_tempDir->path() + '/' + fname)), newName(QFile::encodeName(dir + fname)); if (0 != ::rename(oldName.constData(), newName.constData())) { qWarning() << "cannot move" << (m_tempDir->path() + '/' + fname) << "to" << (dir + fname); } } } QDir(m_tempDir->path()).removeRecursively(); m_tempDir.reset(); m_fileNamesToUpdate.clear(); return ok; } void checkFile(const QByteArray &hash, const QString &remoteFname, QStringList *fileNamesToUpdate) { QString localFname = findFileName(remoteFname); if (localFname.isEmpty()) { fileNamesToUpdate->append(remoteFname); qDebug() << "missing filename" << remoteFname << "- download it"; return; } QFile file(localFname); if (!file.open(QIODevice::ReadOnly)) { qWarning() << "could not open file" << localFname << "- update it"; fileNamesToUpdate->append(remoteFname); return; } QCryptographicHash md5(QCryptographicHash::Md5); if (!md5.addData(&file)) { qWarning() << "could not check MD5 for file" << localFname << "- update it"; fileNamesToUpdate->append(remoteFname); return; } if (md5.result().toHex() != hash) { qDebug() << "not matching file" << localFname << "- update it"; fileNamesToUpdate->append(remoteFname); } } QStringList m_fileNamesToUpdate; QScopedPointer m_tempDir; #ifndef USE_KIO_COPY QList m_sourceFilesToDownload; QPointer m_downloadManager; #endif }; KexiWelcomeStatusBarGuiUpdater::KexiWelcomeStatusBarGuiUpdater() : QObject() , d(new Private) { } KexiWelcomeStatusBarGuiUpdater::~KexiWelcomeStatusBarGuiUpdater() { delete d; } void KexiWelcomeStatusBarGuiUpdater::update() { QDateTime lastStatusBarUpdate = d->configGroup.readEntry("LastStatusBarUpdate", QDateTime()); if (lastStatusBarUpdate.isValid()) { int minutes = lastStatusBarUpdate.secsTo(QDateTime::currentDateTime()) / 60; if (minutes < GUI_UPDATE_INTERVAL) { qDebug() << "gui updated" << minutes << "min. ago, next auto-update in" << (GUI_UPDATE_INTERVAL - minutes) << "min."; return; } } d->configGroup.writeEntry("LastStatusBarUpdate", QDateTime::currentDateTime()); KexiUserFeedbackAgent *f = KexiMainWindowIface::global()->userFeedbackAgent(); f->waitForRedirect(this, SLOT(slotRedirectLoaded())); } void KexiWelcomeStatusBarGuiUpdater::slotRedirectLoaded() { QByteArray postData = stableVersionStringDot0().toLatin1(); KIO::Job* sendJob = KIO::storedHttpPost(postData, QUrl(uiPath(".list")), KIO::HideProgressInfo); connect(sendJob, SIGNAL(result(KJob*)), d, SLOT(sendRequestListFilesFinished(KJob*))); sendJob->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded"); } // --- //! @internal class ScrollArea : public QScrollArea { Q_OBJECT public: explicit ScrollArea(QWidget *parent = 0) : QScrollArea(parent) { setFrameShape(QFrame::NoFrame); setBackgroundRole(QPalette::Base); setWidgetResizable(true); } void setEnabled(bool set) { if (set != isEnabled()) { QScrollArea::setEnabled(set); updateColors(); } } protected: virtual void changeEvent(QEvent* event) { switch (event->type()) { case QEvent::EnabledChange: case QEvent::PaletteChange: updateColors(); break; default:; } QScrollArea::changeEvent(event); } void updateColors() { if (!widget()) return; KColorScheme scheme(palette().currentColorGroup()); QColor linkColor = scheme.foreground(KColorScheme::LinkText).color(); //qDebug() << "_____________" << isEnabled(); foreach(QLabel* lbl, widget()->findChildren()) { QString t = lbl->text(); QRegularExpression re("", QRegularExpression::InvertedGreedinessOption); int pos = 0; int oldPos = 0; QString newText; QRegularExpressionMatch match = re.match(t); //qDebug() << "t:" << t; while ((pos = match.capturedStart(pos)) != -1) { //qDebug() << "pos:" << pos; //qDebug() << "newText += t.mid(oldPos, pos - oldPos)" // << t.mid(oldPos, pos - oldPos); newText += t.midRef(oldPos, pos - oldPos); //qDebug() << "newText1:" << newText; //qDebug() << lbl->objectName() << "~~~~" << t.mid(pos, re.matchedLength()); QString a = t.mid(pos, match.capturedLength()); //qDebug() << "a:" << a; int colPos = a.indexOf("color:"); if (colPos == -1) { // add color a.insert(a.length() - 1, " style=\"color:" + linkColor.name() + ";\""); } else { // replace color colPos += qstrlen("color:"); for (;colPos < a.length() && a[colPos] == ' '; colPos++) { } if (colPos < a.length() && a[colPos] == '#') { colPos++; int i = colPos; for (;i < a.length(); i++) { if (a[i] == ';' || a[i] == ' ' || a[i] == '"' || a[i] == '\'') break; } //qDebug() << "******" << a.mid(colPos, i - colPos); a.replace(colPos, i - colPos, linkColor.name().mid(1)); } } //qDebug() << "a2:" << a; newText += a; //qDebug() << "newText2:" << newText; pos += match.capturedLength(); oldPos = pos; //qDebug() << "pos2:" << pos; } //qDebug() << "oldPos:" << oldPos; newText += t.midRef(oldPos); //qDebug() << "newText3:" << newText; lbl->setText(newText); } #if 0 QString text; text = QString("%3") .arg(link).arg(linkColor.name()).arg(linkText); if (!format.isEmpty()) { text = QString(format).replace("%L", text); } q->setText(text); #endif } }; // --- class Q_DECL_HIDDEN KexiWelcomeStatusBar::Private { public: explicit Private(KexiWelcomeStatusBar* _q) : statusWidget(0), helpAction(0), shareAction(0), cancelAction(0), q(_q) { rccFname = findFileName("status.rcc"); if (!rccFname.isEmpty()) { QResource::registerResource(rccFname); } scores.insert(KexiUserFeedbackAgent::BasicArea, 4); scores.insert(KexiUserFeedbackAgent::SystemInfoArea, 4); scores.insert(KexiUserFeedbackAgent::ScreenInfoArea, 2); scores.insert(KexiUserFeedbackAgent::RegionalSettingsArea, 2); totalFeedbackScore = 0; foreach (int s, scores.values()) { totalFeedbackScore += s; } donationScore = 20; donated = false; //qDebug() << "totalFeedbackScore:" << totalFeedbackScore; } ~Private() { delete msgWidget; if (!rccFname.isEmpty()) { QResource::unregisterResource(rccFname); } } int currentFeedbackScore() const { int score = 0; KexiUserFeedbackAgent *f = KexiMainWindowIface::global()->userFeedbackAgent(); KexiUserFeedbackAgent::Areas areas = f->enabledAreas(); for (QMap::ConstIterator it(scores.constBegin()); it!=scores.constEnd(); ++it) { if (areas & it.key()) { score += it.value(); } } //qDebug() << score; return score; } template T widgetOfClass(T parent, const char *widgetName) const { T w = parent->template findChild(widgetName); if (!w) { qWarning() << "NO SUCH widget" << widgetName << "in" << parent; } return w; } QWidget* widget(QWidget *parent, const char *widgetName) const { return widgetOfClass(parent, widgetName); } QObject* object(QObject *parent, const char *objectName) const { QObject *o = parent->findChild(objectName); if (!o) { qWarning() << "NO SUCH object" << objectName << "in" << parent; } return o; } void setProperty(QWidget *parent, const char *widgetName, const char *propertyName, const QVariant &value) { QWidget *w = widget(parent, widgetName); if (w) { w->setProperty(propertyName, value); } } QVariant property(QWidget *parent, const char *widgetName, const char *propertyName) const { QWidget *w = widget(parent, widgetName); return w ? w->property(propertyName) : QVariant(); } void connect(QWidget *parent, const char *widgetName, const char *signalName, QObject *receiver, const char *slotName) { QWidget *w = widget(parent, widgetName); if (w) { QObject::connect(w, signalName, receiver, slotName); } } void animatedHide(QWidget *parent, const char *widgetName) { QWidget *w = widget(parent, widgetName); if (!w) return; KexiFadeWidgetEffect *animation = new KexiFadeWidgetEffect(w); QObject::connect(animation, SIGNAL(destroyed()), w, SLOT(hide())); animation->start(); } QWidget* loadGui(const QString &guiFileName, QWidget *parentWidget = 0) { QString fname = findFileName(guiFileName); if (fname.isEmpty()) { qWarning() << "filename" << fname << "not found"; return 0; } QFile file(fname); if (!file.open(QIODevice::ReadOnly)) { qWarning() << "could not open file" << fname; return 0; } QUiLoader loader; QWidget* widget = loader.load(&file, parentWidget); if (!widget) { qWarning() << "could load ui from file" << fname; } file.close(); return widget; } void updateStatusWidget() { QWidget *widget = loadGui("status.ui", statusScrollArea); if (!widget) { return; } int smallFontSize = qFloor((QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont).pointSizeF() + q->font().pointSizeF()) / 2.0); smallFont = q->font(); smallFont.setPointSizeF(smallFontSize); widget->setFont(smallFont); //delete statusWidget; statusWidget = widget; statusScrollArea->setWidget(statusWidget); setProperty(statusWidget, "contribution_progress", "minimumHeight", q->fontMetrics().height()); setProperty(statusWidget, "contribution_progress", "maximumHeight", q->fontMetrics().height()); label_involved_text_mask = property(statusWidget, "label_involved", "text").toString(); setProperty(statusWidget, "link_share_usage_info", "text", property(statusWidget, "link_share_usage_info", "text").toString().arg(totalFeedbackScore)); link_share_more_usage_info_mask = property(statusWidget, "link_share_more_usage_info", "text").toString(); setProperty(statusWidget, "link_donate", "text", property(statusWidget, "link_donate", "text").toString().arg(donationScore)); updateDonationInfo(); updateUserProgress(); updateContributionLinksVisibility(); // do not alter background palette QPalette pal(widget->palette()); pal.setColor(QPalette::Disabled, QPalette::Base, pal.color(QPalette::Normal, QPalette::Base)); widget->setPalette(pal); connect(statusWidget, "link_contribute_show_help", SIGNAL(linkActivated(QString)), q, SLOT(showContributionHelp())); connect(statusWidget, "link_share_usage_info", SIGNAL(linkActivated(QString)), q, SLOT(showShareUsageInfo())); connect(statusWidget, "link_share_more_usage_info", SIGNAL(linkActivated(QString)), q, SLOT(showShareUsageInfo())); connect(statusWidget, "link_show_contribution_details", SIGNAL(linkActivated(QString)), q, SLOT(showContributionDetails())); setProperty(statusWidget, "donation_url", "visible", false); connect(statusWidget, "link_donate", SIGNAL(linkActivated(QString)), q, SLOT(showDonation())); } void setUserProgress(int progress) { setProperty(statusWidget, "contribution_progress", "value", progress); setProperty(statusWidget, "label_involved", "text", label_involved_text_mask.arg(progress)); } void updateUserProgress() { int progress = 0; progress += currentFeedbackScore(); if (donated) { progress += donationScore; } setUserProgress(progress); } void updateContributionLinksVisibility() { KexiUserFeedbackAgent *f = KexiMainWindowIface::global()->userFeedbackAgent(); int availableLinks = 0; bool noneEnabled = f->enabledAreas() == KexiUserFeedbackAgent::NoAreas; bool allEnabled = f->enabledAreas() == KexiUserFeedbackAgent::AllAreas; setProperty(statusWidget, "share_usage_info", "visible", noneEnabled); if (noneEnabled) { availableLinks++; } setProperty(statusWidget, "share_more_usage_info", "visible", !noneEnabled && !allEnabled); if (!noneEnabled && !allEnabled) { availableLinks++; } setProperty(statusWidget, "link_share_more_usage_info", "text", link_share_more_usage_info_mask.arg(totalFeedbackScore - currentFeedbackScore())); setProperty(statusWidget, "lbl_contribute", "visible", availableLinks > 0); } void updateDonationInfo() { KConfigGroup configGroup(KSharedConfig::openConfig()->group("User Feedback")); QDateTime lastDonation = configGroup.readEntry("LastDonation", QDateTime()); if (lastDonation.isValid()) { int days = lastDonation.secsTo(QDateTime::currentDateTime()) / 60 / 60 / 24; if (days >= DONATION_INTERVAL) { donated = false; qDebug() << "last donation declared" << days << "days ago, next in" << (DONATION_INTERVAL - days) << "days."; } else if (days >= 0) { donated = true; } } //show always: setProperty(statusWidget, "donate", "visible", !donated); } enum CalloutAlignment { AlignToBar, AlignToWidget }; //! Aligns callout pointer position of msgWidget to widget named @a alignToWidgetName void setMessageWidgetCalloutPointerPosition( const QString& alignToWidgetName, CalloutAlignment calloutAlignment = AlignToBar) { //qDebug() << q->pos() << q->mapToGlobal(QPoint(0, 100)); QPoint p(q->mapToGlobal(QPoint(0, 100))); QWidget *alignToWidget = this->widget(statusWidget, alignToWidgetName.toLatin1()); if (alignToWidget) { p.setY( alignToWidget->mapToGlobal( QPoint(-5, alignToWidget->height() / 2)).y()); if (calloutAlignment == AlignToWidget) { p.setX(alignToWidget->mapToGlobal(QPoint(-5, 0)).x()); //qDebug() << p; } } else { qWarning() << alignToWidgetName << "not found!"; } msgWidget->setCalloutPointerPosition(p, alignToWidget); } //! Shows message widget taking maximum space within the welcome page //! Returns created layout for further use into @a layout. //! Created widge is assigned to msgWidget. //! Calls slot @a slotToCallAfterShow after animated showing, if provided. //! Call msgWidget->animatedShow() afterwards. void showMaximizedMessageWidget(const QString &alignToWidgetName, QPointer *layout, const char* slotToCallAfterShow, CalloutAlignment calloutAlignment = AlignToBar) { QWidget *alignToWidget = this->widget(statusWidget, alignToWidgetName.toLatin1()); int msgWidth; if (alignToWidget && calloutAlignment == AlignToWidget) { msgWidth = q->parentWidget()->width() - alignToWidget->width() - 10; } else { msgWidth = q->parentWidget()->width() - q->width(); } QWidget *widget = new QWidget; *layout = new QGridLayout(widget); if (msgWidth > 100) { // nice text margin (*layout)->setColumnMinimumWidth(0, 50); } //qDebug() << (q->parentWidget()->width() - q->width()) << "***"; KexiContextMessage msg(widget); if (msgWidget) { delete static_cast(msgWidget); } msgWidget = new KexiContextMessageWidget(q->parentWidget()->parentWidget(), 0, 0, msg); msgWidget->setCalloutPointerDirection(KMessageWidget::Right); msgWidget->setMessageType(KMessageWidget::Information); msgWidget->setCloseButtonVisible(true); int offset_y = 0; if (alignToWidget) { offset_y = alignToWidget->mapToGlobal(QPoint(0, 0)).y() - q->parentWidget()->mapToGlobal(QPoint(0, 0)).y(); } else { qWarning() << alignToWidgetName << "not found!"; } msgWidget->resize(msgWidth, q->parentWidget()->height() - offset_y); setMessageWidgetCalloutPointerPosition(alignToWidgetName, calloutAlignment); msgWidget->setResizeTrackingPolicy(Qt::Horizontal | Qt::Vertical); statusScrollArea->setEnabled(false); // async show to for speed up if (slotToCallAfterShow) { QObject::connect(msgWidget, SIGNAL(animatedShowFinished()), q, slotToCallAfterShow); } QObject::connect(msgWidget, SIGNAL(animatedHideFinished()), q, SLOT(slotMessageWidgetClosed())); } ScrollArea *statusScrollArea; QWidget *statusWidget; QVBoxLayout *lyr; QPointer msgWidget; QFont smallFont; QAction *helpAction; QAction *shareAction; QAction *cancelAction; QString label_involved_text_mask; QString link_share_more_usage_info_mask; QPointer contributionHelpLayout; QPointer contributionDetailsLayout; QPointer contributionDetailsWidget; QMap scores; QString countryMask; QString languageMask; bool detailsDataVisible = false; int totalFeedbackScore; int donationScore; bool donated; KexiWelcomeStatusBarGuiUpdater guiUpdater; private: QString rccFname; KexiWelcomeStatusBar *q; QMap dict; }; KexiWelcomeStatusBar::KexiWelcomeStatusBar(QWidget* parent) : QWidget(parent), d(new Private(this)) { d->lyr = new QVBoxLayout(this); init(); } KexiWelcomeStatusBar::~KexiWelcomeStatusBar() { delete d; } void KexiWelcomeStatusBar::init() { d->statusScrollArea = new ScrollArea(this); d->lyr->addWidget(d->statusScrollArea); d->updateStatusWidget(); QTimer::singleShot(10, &d->guiUpdater, SLOT(update())); } void KexiWelcomeStatusBar::showContributionHelp() { d->showMaximizedMessageWidget("link_contribute_show_help", &d->contributionHelpLayout, SLOT(slotShowContributionHelpContents())); d->msgWidget->animatedShow(); } void KexiWelcomeStatusBar::slotShowContributionHelpContents() { QWidget *helpWidget = d->loadGui("contribution_help.ui"); d->contributionHelpLayout->addWidget(helpWidget, 1, 1); d->msgWidget->setPaletteInherited(); } void KexiWelcomeStatusBar::slotMessageWidgetClosed() { d->statusScrollArea->setEnabled(true); d->updateDonationInfo(); d->updateUserProgress(); d->updateContributionLinksVisibility(); } void KexiWelcomeStatusBar::showShareUsageInfo() { if (!sender()) { return; } QWidget *widget = d->loadGui("status_strings.ui"); if (!widget) { return; } QLabel *lbl = widget->findChild("question"); if (!lbl) { return; } KexiContextMessage msg(lbl->text()); delete widget; if (!d->helpAction) { d->helpAction = new QAction(KStandardGuiItem::help().icon(), KStandardGuiItem::help().text(), this); connect(d->helpAction, SIGNAL(triggered()), this, SLOT(showContributionHelp())); } if (!d->shareAction) { d->shareAction = new QAction(KStandardGuiItem::yes().icon(), xi18n("Share"), this); connect(d->shareAction, SIGNAL(triggered()), this, SLOT(slotShareFeedback())); } if (!d->cancelAction) { d->cancelAction = new QAction(KStandardGuiItem::cancel().icon(), KStandardGuiItem::cancel().text(), this); QObject::connect(d->cancelAction, SIGNAL(triggered()), this, SLOT(slotCancelled())); } msg.addAction(d->helpAction, KexiContextMessage::AlignLeft); msg.addAction(d->shareAction); msg.addAction(d->cancelAction); if (d->msgWidget) { delete static_cast(d->msgWidget); } d->msgWidget = new KexiContextMessageWidget(parentWidget(), 0, 0, msg); d->msgWidget->setMessageType(KMessageWidget::Information); d->msgWidget->setCalloutPointerDirection(KMessageWidget::Right); d->setMessageWidgetCalloutPointerPosition(sender()->objectName()); d->statusScrollArea->setEnabled(false); d->msgWidget->setMaximumWidth(parentWidget()->width() - width()); d->msgWidget->setResizeTrackingPolicy(Qt::Horizontal); d->msgWidget->animatedShow(); } void KexiWelcomeStatusBar::showDonation() { if (!sender()) { return; } if (KMessageBox::Yes != KMessageBox::questionYesNo(this, - xi18nc("@info donate to the project", "Kexi may be totally free, but its development is costly." + xi18nc("@info donate to the project", "KEXI may be totally free, but its development is costly." "Power, hardware, office space, internet access, traveling for meetings - everything costs." - "Direct donation is the easiest and fastest way to efficiently support the Kexi Project. " + "Direct donation is the easiest and fastest way to efficiently support the KEXI Project. " "Everyone, regardless of any degree of involvement can do so." - "What do you receive for your donation? Kexi will become more feature-full and stable as " - "contributors will be able to devote more time to Kexi. Not only you can " + "What do you receive for your donation? KEXI will become more feature-full and stable as " + "contributors will be able to devote more time to KEXI. Not only you can " "expect new features, but you can also have an influence on what features are added!" "Currently we are accepting donations through BountySource (a funding platform " "for open-source software) using secure PayPal, Bitcoin and Google Wallet transfers." "Contact us at https://community.kde.org/Kexi/Contact " "for more information." "Thanks for your support!"), xi18n("Donate to the Project"), KGuiItem(xi18nc("@action:button Go to Donation", "Proceed to the Donation Web Page"), QIcon(":/icons/heart.png")), KGuiItem(xi18nc("Do not donate now", "Not Now")), QString(), KMessageBox::Notify | KMessageBox::AllowLink)) { return; } QUrl donationUrl(d->property(this, "donation_url", "text").toString()); if (donationUrl.isValid()) { QDesktopServices::openUrl(donationUrl); d->donated = true; d->updateStatusWidget(); KConfigGroup configGroup(KSharedConfig::openConfig()->group("User Feedback")); int donationsCount = configGroup.readEntry("DonationsCount", 0); configGroup.writeEntry("LastDonation", QDateTime::currentDateTime()); configGroup.writeEntry("DonationsCount", donationsCount + 1); } else { qWarning() << "Invalid donation URL" << donationUrl; } } void KexiWelcomeStatusBar::slotShareFeedback() { d->statusScrollArea->setEnabled(true); d->msgWidget->animatedHide(); KexiMainWindowIface::global()->userFeedbackAgent() ->setEnabledAreas(KexiUserFeedbackAgent::AllAreas); d->animatedHide(d->statusWidget, "share_usage_info"); d->animatedHide(d->statusWidget, "share_more_usage_info"); d->animatedHide(d->statusWidget, "lbl_contribute"); d->updateUserProgress(); } void KexiWelcomeStatusBar::slotCancelled() { d->statusScrollArea->setEnabled(true); } // Contribution Details BEGIN void KexiWelcomeStatusBar::showContributionDetails() { d->showMaximizedMessageWidget("link_show_contribution_details", &d->contributionDetailsLayout, 0, KexiWelcomeStatusBar::Private::AlignToWidget); d->contributionDetailsLayout->setColumnMinimumWidth(0, 6); // smaller d->contributionDetailsWidget = d->loadGui("contribution_details.ui"); KexiUserFeedbackAgent *f = KexiMainWindowIface::global()->userFeedbackAgent(); d->setProperty(d->contributionDetailsWidget, "group_share", "checked", f->enabledAreas() != KexiUserFeedbackAgent::NoAreas); d->setProperty(d->contributionDetailsWidget, "group_basic", "title", d->property(d->contributionDetailsWidget, "group_basic", "title") .toString().arg(d->scores.value(KexiUserFeedbackAgent::BasicArea))); updateContributionGroupCheckboxes(); d->setProperty(d->contributionDetailsWidget, "group_system", "title", d->property(d->contributionDetailsWidget, "group_system", "title") .toString().arg(d->scores.value(KexiUserFeedbackAgent::SystemInfoArea))); d->connect(d->contributionDetailsWidget, "group_system", SIGNAL(toggled(bool)), this, SLOT(slotShareContributionDetailsGroupToggled(bool))); d->setProperty(d->contributionDetailsWidget, "group_screen", "title", d->property(d->contributionDetailsWidget, "group_screen", "title") .toString().arg(d->scores.value(KexiUserFeedbackAgent::ScreenInfoArea))); d->connect(d->contributionDetailsWidget, "group_screen", SIGNAL(toggled(bool)), this, SLOT(slotShareContributionDetailsGroupToggled(bool))); d->setProperty(d->contributionDetailsWidget, "group_regional_settings", "title", d->property(d->contributionDetailsWidget, "group_regional_settings", "title") .toString().arg(d->scores.value(KexiUserFeedbackAgent::RegionalSettingsArea))); d->connect(d->contributionDetailsWidget, "group_regional_settings", SIGNAL(toggled(bool)), this, SLOT(slotShareContributionDetailsGroupToggled(bool))); d->detailsDataVisible = false; slotShareContributionDetailsToggled( d->property(d->contributionDetailsWidget, "group_share", "checked").toBool()); d->detailsDataVisible = true; // to switch off slotToggleContributionDetailsDataVisibility(); d->connect(d->contributionDetailsWidget, "group_share", SIGNAL(toggled(bool)), this, SLOT(slotShareContributionDetailsToggled(bool))); d->connect(d->contributionDetailsWidget, "link_show_shared_info", SIGNAL(linkActivated(QString)), this, SLOT(slotToggleContributionDetailsDataVisibility())); d->setProperty(d->contributionDetailsWidget, "label_where_is_info_sent", "visible", false); ScrollArea *contributionDetailsArea = new ScrollArea(d->msgWidget); d->contributionDetailsLayout->addWidget(contributionDetailsArea, 1, 1); contributionDetailsArea->setWidget(d->contributionDetailsWidget); d->msgWidget->animatedShow(); d->msgWidget->setPaletteInherited(); } void KexiWelcomeStatusBar::updateContributionGroupCheckboxes() { KexiUserFeedbackAgent *f = KexiMainWindowIface::global()->userFeedbackAgent(); d->setProperty(d->contributionDetailsWidget, "group_system", "checked", bool(f->enabledAreas() & KexiUserFeedbackAgent::SystemInfoArea)); d->setProperty(d->contributionDetailsWidget, "group_screen", "checked", bool(f->enabledAreas() & KexiUserFeedbackAgent::ScreenInfoArea)); d->setProperty(d->contributionDetailsWidget, "group_regional_settings", "checked", bool(f->enabledAreas() & KexiUserFeedbackAgent::RegionalSettingsArea)); } void KexiWelcomeStatusBar::slotShareContributionDetailsToggled(bool on) { //qDebug() << sender(); QWidget* group_share = d->widget(d->contributionDetailsWidget, "group_share"); KexiUserFeedbackAgent *f = KexiMainWindowIface::global()->userFeedbackAgent(); if (sender() == group_share) { f->setEnabledAreas(on ? KexiUserFeedbackAgent::AllAreas : KexiUserFeedbackAgent::NoAreas); updateContributionGroupCheckboxes(); } if (!group_share) { return; } for (int i=0; i < group_share->layout()->count(); i++) { QWidget *w = group_share->layout()->itemAt(i)->widget(); if (w) { w->setVisible(on); } } if (d->detailsDataVisible) { slotToggleContributionDetailsDataVisibility(); } // fill shared values QLocale locale; foreach(QLabel* lbl, d->contributionDetailsWidget->findChildren()) { if (lbl->objectName().startsWith(QLatin1String("value_"))) { QString name = lbl->objectName().mid(6); // cut "value_" QVariant value; if (name == QLatin1String("screen_size")) { value = QString("%1 x %2").arg(f->value("screen_width").toString()) .arg(f->value("screen_height").toString()); } else if (name == QLatin1String("country")) { if (d->countryMask.isEmpty()) { d->countryMask = lbl->text(); } value = d->countryMask .arg(f->value(name).toString() /*!< @todo KEXI3 port KLocale::global()->countryCodeToName(f->value(name).toString()) */) .arg(f->value(name).toString()); } else if (name == QLatin1String("language")) { if (d->languageMask.isEmpty()) { d->languageMask = lbl->text(); } value = d->languageMask .arg(f->value(name).toString() /*!< @todo KEXI3 port KLocale::global()->languageCodeToName(f->value(name).toString()) */) .arg(f->value(name).toString()); } else { value = f->value(name); } if (value.type() == QVariant::Bool) { value = value.toBool() ? KStandardGuiItem::yes().plainText() : KStandardGuiItem::no().plainText(); } if (!value.isNull()) { lbl->setText(value.toString()); } } else if (lbl->objectName().startsWith(QLatin1String("desc_"))) { lbl->setFont(d->smallFont); } } QLabel* lbl; KConfigGroup configGroup(KSharedConfig::openConfig()->group("User Feedback")); if ((lbl = d->contributionDetailsWidget->findChild("value_recent_donation"))) { QDateTime lastDonation = configGroup.readEntry("LastDonation", QDateTime()); QString recentDonation = "-"; if (lastDonation.isValid()) { int days = lastDonation.secsTo(QDateTime::currentDateTime()) / 60 / 60 / 24; if (days == 0) { recentDonation = xi18nc("Donation today", "today"); } else if (days > 0) { recentDonation = xi18ncp("Recent donation date (xx days)", "%1 (1 day)", "%1 (%2 days)", locale.toString(lastDonation), days); } } lbl->setText(recentDonation); } if ((lbl = d->contributionDetailsWidget->findChild("value_donations_count"))) { int donationsCount = configGroup.readEntry("DonationsCount", 0); if (donationsCount == 0) { lbl->setText(QString::number(donationsCount)); } else { lbl->setText(xi18nc("donations count", "%1 (thanks!)", donationsCount)); } } } static void setArea(KexiUserFeedbackAgent::Areas *areas, KexiUserFeedbackAgent::Area area, bool on) { *areas |= area; if (!on) { *areas ^= area; } } void KexiWelcomeStatusBar::slotShareContributionDetailsGroupToggled(bool on) { if (!sender()) { return; } const QString name = sender()->objectName(); KexiUserFeedbackAgent *f = KexiMainWindowIface::global()->userFeedbackAgent(); KexiUserFeedbackAgent::Areas areas = f->enabledAreas(); //qDebug() << areas; if (name == "group_system") { setArea(&areas, KexiUserFeedbackAgent::SystemInfoArea, on); } else if (name == "group_screen") { setArea(&areas, KexiUserFeedbackAgent::ScreenInfoArea, on); } else if (name == "group_regional_settings") { setArea(&areas, KexiUserFeedbackAgent::RegionalSettingsArea, on); } if (areas) { areas |= KexiUserFeedbackAgent::AnonymousIdentificationArea; } f->setEnabledAreas(areas); //qDebug() << f->enabledAreas(); } void KexiWelcomeStatusBar::slotToggleContributionDetailsDataVisibility() { QWidget* value_app_ver = d->widget(d->contributionDetailsWidget, "value_app_ver"); if (!value_app_ver) { return; } d->detailsDataVisible = !d->detailsDataVisible; if (d->detailsDataVisible) { d->setProperty(d->contributionDetailsWidget, "link_show_shared_info", "visible", false); d->setProperty(d->contributionDetailsWidget, "label_where_is_info_sent", "visible", true); } bool show = d->contributionDetailsWidget->isVisible(); QList list; d->contributionDetailsWidget->hide(); QWidget* group_basic = d->widget(d->contributionDetailsWidget, "group_basic"); if (group_basic) { list += group_basic->findChildren(); } QWidget* group_system = d->widget(d->contributionDetailsWidget, "group_system"); if (group_system) { list += group_system->findChildren(); } QWidget* group_screen = d->widget(d->contributionDetailsWidget, "group_screen"); if (group_screen) { list += group_screen->findChildren(); } QWidget* group_regional_settings = d->widget(d->contributionDetailsWidget, "group_regional_settings"); if (group_regional_settings) { list += group_regional_settings->findChildren(); } foreach (QWidget* w, list) { if (qobject_cast(w) && !w->objectName().startsWith(QLatin1String("desc_"))) { //qDebug() << "+++" << w; w->setVisible(d->detailsDataVisible); } } if (show) { d->contributionDetailsWidget->show(); } } // Contribution Details END #include "KexiWelcomeStatusBar.moc" diff --git a/src/main/status/contribution_details.ui b/src/main/status/contribution_details.ui index 8db9cbf22..a02e16e0d 100644 --- a/src/main/status/contribution_details.ui +++ b/src/main/status/contribution_details.ui @@ -1,1113 +1,1113 @@ widget 0 0 548 1076 12 0 20 75 true Your Contributions - Share usage info for Kexi + Share usage info for KEXI true true true 6 Qt::StrongFocus - <a href="show_info">Show what info is shared with the Kexi Project community to improve the application &raquo;</a> + <a href="show_info">Show what info is shared with the KEXI Project community to improve the application &raquo;</a> true Qt::StrongFocus The info will be sent to <a href="http://kexi-project.org">http://kexi-project.org</a>. true Share basic usage info (required) (+%1%) false 8 6 Anonymous identification number: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true uid Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - Kexi version: + KEXI version: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true app_ver Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Used KDE frameworks: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true kde_ver Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Operating system name: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true os Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Running desktop: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true running_desktop Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Running desktop version: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true running_desktop_version Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 50 true false - Enabling this will include your usage of Kexi in the global statistics. + Enabling this will include your usage of KEXI in the global statistics. true 0 0 Share system and hardware info (+%1%) true QLayout::SetMinimumSize 6 0 0 true - Enabling this helps the Kexi Project to identify typical operating systems and hardware that should be supported. Recommended. + Enabling this helps the KEXI Project to identify typical operating systems and hardware that should be supported. Recommended. true Linux operating system distributor: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true linux_id Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Linux operating system description: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true linux_desc Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Linux operating system release: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true linux_rel Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Operating system version: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true os_release Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Operating system machine: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true os_machine Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 Share screen information (+%1%) true QLayout::SetMinimumSize 6 0 0 true - Enabling this helps Kexi Project to better know real display parameters used with Kexi, so it can become better optimized. Recommended. + Enabling this helps KEXI Project to better know real display parameters used with KEXI, so it can become better optimized. Recommended. true Current screen size: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true screen_size Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Number of screens: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true screen_count Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 Regional settings (+%1%) true 6 0 0 true - Enabling this helps Kexi Project to know how wide support for regional settings should be. Recommended. + Enabling this helps KEXI Project to know how wide support for regional settings should be. Recommended. true Country: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true %1 (%2) Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Language: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true %1 (%2) Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Date format: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true date_format Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Short date format: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true short_date_format Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Time format: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true time_format Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Right-to-left text layout: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 75 true right_to_left Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true QGroupBox { border:none; } - Donations to the Kexi project + Donations to the KEXI project true false 8 6 0 8 16777215 8 Possible recent donation: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Possible number of donations: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true donations_count Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true recent_donation Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 0 0 true Qt::StrongFocus - This section only informs about known visits to the Donation web page from this computer. Kexi app has no access to real donation information. + This section only informs about known visits to the Donation web page from this computer. KEXI app has no access to real donation information. true 19 0 14 16777215 14 50 false Qt::Vertical 20 29 diff --git a/src/main/status/contribution_help.ui b/src/main/status/contribution_help.ui index ebe8b80db..50a2af1ee 100644 --- a/src/main/status/contribution_help.ui +++ b/src/main/status/contribution_help.ui @@ -1,68 +1,68 @@ textBrowser 0 0 400 300 QFrame::NoFrame 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Nokia Pure Text'; font-size:13pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Your Support for the Kexi Project.<br />In No Time. At No Cost.</span> </p> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Most products appreciate your close participation during beta testing stages of development. In the Kexi Project you can participate at any stage, it does not matter if it is a shiny final release or early beta, you can join us to influence the shape of your software. </p> +<p style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Your Support for the KEXI Project.<br />In No Time. At No Cost.</span> </p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Most products appreciate your close participation during beta testing stages of development. In the KEXI Project you can participate at any stage, it does not matter if it is a shiny final release or early beta, you can join us to influence the shape of your software. </p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Before going further please note one thing, this application is developed by its community, its creators <span style=" font-weight:600;">and</span> users are one group, they are not separate. We refer to this group as the Project. </p> <p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large; font-weight:600;">Power to You</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You can have substantial influence on the future releases of this software by: </p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voicing your opinion. You can share your thoughts on any function of the application. You can have your say about extras like documentation, translation or example files.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Asking for help. Yes, doing so in the application's support channel is a great way for us to understand areas for improvement.</li> <li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Telling others how you use the application. You can easily give feedback about your experience with this software, for example your favourite or missing functions. </li></ul> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">We at the Project came to the idea to reuse the capabilities of the Internet for the purpose of improving the application you use. We are using in-app connectivity with the Project web site <a href="http://www.kexi-project.org"><span style=" text-decoration: underline; color:#0057ae;">www.kexi-project.org</span></a> to allow you to quickly and easily voice your opinion, ask for help or provide feedback. All without leaving the application. The third option, providing feedback, is special. We would like you to share some of the information on how you use the application - automatically. </p> <p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large; font-weight:600;">We Adapt to You</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">While software developers of course welcome to join, it is no problem if you can't do software programming. Other members of the Project handle that for you. So equally well you may be user of the app who agrees to share any feedback regarding the app in use. </p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You can for example:</p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Share simple statistical data like software version or operating system version. </li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The shared information is anonymous if you wish it to be.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The shared information can be statistical if you wish it to be.</li> <li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The shared information may skip any regional settings like language or country settings you use on your computer. Even if you provide this data, localization like your IP number or geographic location are not shared. (Note: sharing geographic location could be offered in the future as an extra option that you can enable, e.g. if you wish to show usage of the app at your location in the global statistics)</li></ul> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">As you can imagine, the more information you give, the more chances are for the Project to take your special needs into account. </p> <p style=" margin-top:14px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large; font-weight:600;">Safe and Transparent Participation</span> </p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">We propose simple but clear ideas for the participation: </p> <ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Participation is optional. You can still use the app as before. You do not share any information just because you use the app, so nothing changes. You start later, when and if you choose to participate.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Easy opt-in. It's a no-brainer to start participation.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Easy and real opt-out at any time. When you opt-out any statistical data you shared can be removed if you want. You can also disable connecting with the Project for some time without opting-out. (Note: in version 2.4 opting-out is not available)</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You always know the reasoning. For any information you share, you know what is the benefit of doing that for the Project and directly for you.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You can always see what information will be sent.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No information is (and will never be) passed on to third-parties.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No real data from your databases or files is (and will never be) transmitted along with the &quot;usage&quot; data.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No cost. Your participation is not tied to on any payments. Neither you are expected to devote your time. This information you share can be sent automatically while you use the app.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No need to be permanently online. The feedback and statistical data can be sent when you are online. In the future, the data may be noted while you are offline and sent later.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wide availability. While at least partial access to the Internet is needed it does not matter what operating system you use or in what country. Your participation is equally welcome. Participants can contribute at any time. At initial stage it is required to communicate in English but later other languages, if there are contributors to support this option.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You decide on the level of openness. You can provide some of your personal data like real name to have better recognition for your efforts and connect with others who do the same. If you prefer you can stick with a nickname. (Note: in version 2.4 only anonymous access is possible using anonymous identification number)</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimal overhead. Only small amounts of text are transferred, usually smaller than the text you are reading now. No complex computation is performed and performance of your applications should not suffer.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You decide for yourself. If you opt-in, only you become the participant to the Project. Other users of the same computer (if there are any and assuming they use separate accounts) are unaffected -- they will have to opt-in separately to become participants.</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No limits for computers. You can use multiple computers and operating systems and use the same participant's nickname or name. You can enable participation from one computer (e.g. at home) and decide not to participate from another computer (e.g. at work).</li> <li style=" margin-top:0px; margin-bottom:10px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only for one purpose. The collected data is used only to improve the Project. </li></ul> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;">We plan to improve and extend ways of participation so stay tuned. Feel free to share you ideas on the matter by sending feedback to <a href="mailto:calligra-devel@kde.org"><span style=" text-decoration: underline; color:#0057ae;">calligra-devel@kde.org</span></a>. This is another good way to start participation!</p> -<p style=" margin-top:20px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">-- Love, the Kexi Project Team</span> </p> +<p style=" margin-top:20px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">-- Love, the KEXI Project Team</span> </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html> true diff --git a/src/main/status/status.ui b/src/main/status/status.ui index 4f9652200..b9c6a2294 100644 --- a/src/main/status/status.ui +++ b/src/main/status/status.ui @@ -1,493 +1,493 @@ Form 0 0 263 561 0 0 6 75 true - You in Kexi Project + You in KEXI Project 1 0 Qt::StrongFocus <a href="link" style="color:gray;">( ? )</a> 0 0 0 6 16777215 6 6 0 0 80 16777215 false <b>%1%</b> involved 0 0 0 12 16777215 6 75 true Contribute: 0 0 75 true :/icons/heart.png Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::StrongFocus <b><a href="link">Donate</a></b><br/><span style="color:gray;"><b>Boost development, support new features</b> (+%1%)</span> true 0 0 75 true :/icons/add.png Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::StrongFocus <a href="link">Share Usage Info</a><br/><span style="color:gray;">Let us adapt to your needs (+%1%)</span> true 0 0 75 true :/icons/add.png Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Qt::StrongFocus <a href="link">Share More Usage Info</a><br/><span style="color:gray;">Let us adapt to your needs (+%1%)</span> true 0 0 0 6 16777215 6 Qt::StrongFocus - <span style="color:gray;">Thank you for being part of Kexi!</span> + <span style="color:gray;">Thank you for being part of KEXI!</span> true 0 Qt::Horizontal QSizePolicy::Expanding 40 20 50 false Qt::StrongFocus <a href="link"><b>Details</b> &raquo;</a> Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 0 24 16777215 6 75 true Visit 50 false Qt::StrongFocus - Visit http://kexi-project home page + Visit KEXI home page <a href="http://kexi-project.org"><nobr><b>Home page &raquo;</b></nobr></a> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter true 4 6 true 50 false Qt::StrongFocus Visit http://kexi-project.org/forum <a href="http://kexi-project.org/forum/"><b>Forum</b> for help and <nobr>discussions &raquo;</nobr></a> Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter true 4 6 true https://salt.bountysource.com/checkout/amount?team=kexi Qt::Vertical 20 48 diff --git a/src/main/status/status_strings.ui b/src/main/status/status_strings.ui index 48bfe7b49..2b38c3c4e 100644 --- a/src/main/status/status_strings.ui +++ b/src/main/status/status_strings.ui @@ -1,35 +1,35 @@ Form 0 0 434 211 10 30 371 91 - <br><b>Do you want to share Kexi usage info?</b> + <br><b>Do you want to share KEXI usage info?</b> <p></p> <p>Click &quot;Help&quot; button for details.</p> diff --git a/src/migration/importtablewizard.cpp b/src/migration/importtablewizard.cpp index 84223666e..fe61be4c6 100644 --- a/src/migration/importtablewizard.cpp +++ b/src/migration/importtablewizard.cpp @@ -1,797 +1,797 @@ /* This file is part of the KDE project Copyright (C) 2009 Adam Pigg Copyright (C) 2014-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 version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "importtablewizard.h" #include "importoptionsdlg.h" #include "migratemanager.h" #include "keximigrate.h" #include "keximigratedata.h" #include "AlterSchemaWidget.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 #include #include #include #include #include #include #include #include using namespace KexiMigration; #define RECORDS_FOR_PREVIEW 3 ImportTableWizard::ImportTableWizard ( KDbConnection* curDB, QWidget* parent, QMap* args, Qt::WindowFlags flags) : KAssistantDialog ( parent, flags ), m_args(args) { m_connection = curDB; m_migrateDriver = 0; m_prjSet = 0; m_importComplete = false; m_importWasCanceled = false; m_sourceDbEncoding = QString::fromLatin1(KexiUtils::encoding()); //default KexiMainWindowIface::global()->setReasonableDialogSize(this); setupIntroPage(); setupSrcConn(); setupSrcDB(); setupTableSelectPage(); setupAlterTablePage(); setupImportingPage(); setupProgressPage(); setupFinishPage(); setValid(m_srcConnPageItem, false); connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(slot_currentPageChanged(KPageWidgetItem*,KPageWidgetItem*))); //! @todo Change this to message prompt when we move to non-dialog wizard. connect(m_srcConnSel, SIGNAL(connectionSelected(bool)), this, SLOT(slotConnPageItemSelected(bool))); connect(m_srcConnSel, &KexiConnectionSelectorWidget::connectionItemHighlighted, [this]() { setValid(m_srcConnPageItem, true); }); connect(m_srcConnSel, &KexiConnectionSelectorWidget::connectionItemExecuted, [this]() { setValid(m_srcConnPageItem, true); next(); }); } ImportTableWizard::~ImportTableWizard() { delete m_prjSet; delete m_srcConnSel; } void ImportTableWizard::back() { KAssistantDialog::back(); } void ImportTableWizard::next() { if (currentPage() == m_srcConnPageItem) { if (fileBasedSrcSelected()) { setAppropriate(m_srcDBPageItem, false); } else { setAppropriate(m_srcDBPageItem, true); } } else if (currentPage() == m_alterTablePageItem) { if (m_alterSchemaWidget->nameExists(m_alterSchemaWidget->nameWidget()->nameText())) { KMessageBox::information(this, xi18nc("@info", "%1 name is already used by an existing table. " "Enter different table name to continue.", m_alterSchemaWidget->nameWidget()->nameText()), xi18n("Name Already Used")); return; } } KAssistantDialog::next(); } void ImportTableWizard::accept() { if (m_args) { if (m_finishCheckBox->isChecked()) { m_args->insert("destinationTableName",m_alterSchemaWidget->nameWidget()->nameText()); } else { m_args->remove("destinationTableName"); } } QDialog::accept(); } void ImportTableWizard::reject() { QDialog::reject(); } //=========================================================== // void ImportTableWizard::setupIntroPage() { m_introPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(); m_introPageWidget->setLayout(vbox); KexiUtils::setStandardMarginsAndSpacing(vbox); QLabel *lblIntro = new QLabel(m_introPageWidget); lblIntro->setAlignment(Qt::AlignTop | Qt::AlignLeft); lblIntro->setWordWrap(true); lblIntro->setText( xi18nc("@info", "Table Importing Assistant allows you to import a table from an existing " - "database into the current Kexi project." + "database into the current KEXI project." "Click Next button to continue or " "Cancel button to exit this assistant.")); vbox->addWidget(lblIntro); m_introPageItem = new KPageWidgetItem(m_introPageWidget, xi18n("Welcome to the Table Importing Assistant")); addPage(m_introPageItem); } void ImportTableWizard::setupSrcConn() { m_srcConnPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(m_srcConnPageWidget); m_srcConnSel = new KexiConnectionSelectorWidget(&Kexi::connset(), QUrl("kfiledialog:///ProjectMigrationSourceDir"), KexiConnectionSelectorWidget::Opening, m_srcConnPageWidget); m_srcConnSel->hideConnectonIcon(); m_srcConnSel->showSimpleConnection(); //! @todo remove when support for kexi files as source prj is added in migration const QStringList excludedMimeTypes({ KDb::defaultFileBasedDriverMimeType(), "application/x-kexiproject-shortcut", "application/x-kexi-connectiondata"}); m_srcConnSel->setExcludedMimeTypes(excludedMimeTypes); vbox->addWidget(m_srcConnSel); m_srcConnPageItem = new KPageWidgetItem(m_srcConnPageWidget, xi18n("Select Location for Source Database")); addPage(m_srcConnPageItem); } void ImportTableWizard::setupSrcDB() { // arrivesrcdbPage creates widgets on that page m_srcDBPageWidget = new QWidget(this); m_srcDBName = NULL; m_srcDBPageItem = new KPageWidgetItem(m_srcDBPageWidget, xi18n("Select Source Database")); addPage(m_srcDBPageItem); } void ImportTableWizard::setupTableSelectPage() { m_tablesPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(m_tablesPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_tableListWidget = new QListWidget(this); m_tableListWidget->setSelectionMode(QAbstractItemView::SingleSelection); connect(m_tableListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(slotTableListWidgetSelectionChanged())); vbox->addWidget(m_tableListWidget); m_tablesPageItem = new KPageWidgetItem(m_tablesPageWidget, xi18n("Select the Table to Import")); addPage(m_tablesPageItem); } //=========================================================== // void ImportTableWizard::setupImportingPage() { m_importingPageWidget = new QWidget(this); m_importingPageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(m_importingPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_lblImportingTxt = new QLabel(m_importingPageWidget); m_lblImportingTxt->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_lblImportingTxt->setWordWrap(true); m_lblImportingErrTxt = new QLabel(m_importingPageWidget); m_lblImportingErrTxt->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_lblImportingErrTxt->setWordWrap(true); vbox->addWidget(m_lblImportingTxt); vbox->addWidget(m_lblImportingErrTxt); vbox->addStretch(1); QWidget *options_widget = new QWidget(m_importingPageWidget); vbox->addWidget(options_widget); QVBoxLayout *options_vbox = new QVBoxLayout(options_widget); options_vbox->setSpacing(KexiUtils::spacingHint()); m_importOptionsButton = new QPushButton(koIcon("configure"), xi18n("Advanced Options"), options_widget); connect(m_importOptionsButton, SIGNAL(clicked()),this, SLOT(slotOptionsButtonClicked())); options_vbox->addWidget(m_importOptionsButton); options_vbox->addStretch(1); m_importingPageWidget->show(); m_importingPageItem = new KPageWidgetItem(m_importingPageWidget, xi18n("Importing")); addPage(m_importingPageItem); } void ImportTableWizard::setupAlterTablePage() { m_alterTablePageWidget = new QWidget(this); m_alterTablePageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(m_alterTablePageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_alterSchemaWidget = new KexiMigration::AlterSchemaWidget(this); vbox->addWidget(m_alterSchemaWidget); m_alterTablePageWidget->show(); m_alterTablePageItem = new KPageWidgetItem(m_alterTablePageWidget, xi18n("Alter the Detected Table Design")); addPage(m_alterTablePageItem); } void ImportTableWizard::setupProgressPage() { m_progressPageWidget = new QWidget(this); m_progressPageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(m_progressPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_progressPageWidget->setLayout(vbox); m_progressLbl = new QLabel(m_progressPageWidget); m_progressLbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_progressLbl->setWordWrap(true); m_rowsImportedLbl = new QLabel(m_progressPageWidget); m_importingProgressBar = new QProgressBar(m_progressPageWidget); m_importingProgressBar->setMinimum(0); m_importingProgressBar->setMaximum(0); m_importingProgressBar->setValue(0); vbox->addWidget(m_progressLbl); vbox->addWidget(m_rowsImportedLbl); vbox->addWidget(m_importingProgressBar); vbox->addStretch(1); m_progressPageItem = new KPageWidgetItem(m_progressPageWidget, xi18n("Processing Import")); addPage(m_progressPageItem); } void ImportTableWizard::setupFinishPage() { m_finishPageWidget = new QWidget(this); m_finishPageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(m_finishPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_finishLbl = new QLabel(m_finishPageWidget); m_finishLbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); m_finishLbl->setWordWrap(true); vbox->addWidget(m_finishLbl); m_finishCheckBox = new QCheckBox(xi18n("Open imported table"), m_finishPageWidget); m_finishCheckBox->setChecked(true); vbox->addSpacing(KexiUtils::spacingHint()); vbox->addWidget(m_finishCheckBox); vbox->addStretch(1); m_finishPageItem = new KPageWidgetItem(m_finishPageWidget, xi18n("Success")); addPage(m_finishPageItem); } void ImportTableWizard::slot_currentPageChanged(KPageWidgetItem* curPage,KPageWidgetItem* prevPage) { Q_UNUSED(prevPage); if (curPage == m_introPageItem) { } else if (curPage == m_srcConnPageItem) { arriveSrcConnPage(); } else if (curPage == m_srcDBPageItem) { arriveSrcDBPage(); } else if (curPage == m_tablesPageItem) { arriveTableSelectPage(prevPage); } else if (curPage == m_alterTablePageItem) { if (prevPage == m_tablesPageItem) { arriveAlterTablePage(); } } else if (curPage == m_importingPageItem) { arriveImportingPage(); } else if (curPage == m_progressPageItem) { arriveProgressPage(); } else if (curPage == m_finishPageItem) { arriveFinishPage(); } } void ImportTableWizard::arriveSrcConnPage() { } void ImportTableWizard::arriveSrcDBPage() { if (fileBasedSrcSelected()) { //! @todo Back button doesn't work after selecting a file to import } else { delete m_prjSet; m_prjSet = 0; m_srcDBPageWidget->hide(); qDebug() << "Looks like we need a project selector widget!"; KDbConnectionData* conndata = m_srcConnSel->selectedConnectionData(); if (conndata) { KexiGUIMessageHandler handler; m_prjSet = new KexiProjectSet(&handler); if (!m_prjSet->setConnectionData(conndata)) { handler.showErrorMessage(m_prjSet->result()); delete m_prjSet; m_prjSet = 0; return; } if (!m_srcDBName) { QVBoxLayout *vbox = new QVBoxLayout(m_srcDBPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); m_srcDBName = new KexiProjectSelectorWidget(m_srcDBPageWidget); vbox->addWidget(m_srcDBName); m_srcDBName->label()->setText(xi18n("Select source database you wish to import:")); } m_srcDBName->setProjectSet(m_prjSet); } m_srcDBPageWidget->show(); } } void ImportTableWizard::arriveTableSelectPage(KPageWidgetItem *prevPage) { if (prevPage == m_alterTablePageItem) { if (m_tableListWidget->count() == 1) { //we was skiping it before back(); } } else { Kexi::ObjectStatus result; KexiUtils::WaitCursor wait; m_tableListWidget->clear(); m_migrateDriver = prepareImport(&result); bool ok = m_migrateDriver; if (ok) { if (!m_sourceDbEncoding.isEmpty()) { m_migrateDriver->setPropertyValue( "source_database_nonunicode_encoding", QVariant(m_sourceDbEncoding.toUpper().remove(' ')) // "CP1250", not "cp 1250" ); } ok = m_migrateDriver->connectSource(&result); } if (ok) { QStringList tableNames; if (m_migrateDriver->tableNames(&tableNames)) { m_tableListWidget->addItems(tableNames); } if (m_tableListWidget->item(0)) { m_tableListWidget->item(0)->setSelected(true); if (m_tableListWidget->count() == 1) { KexiUtils::removeWaitCursor(); next(); } } } KexiUtils::removeWaitCursor(); if (!ok) { QString errMessage =result.message.isEmpty() ? xi18n("Unknown error") : result.message; QString errDescription = result.description.isEmpty() ? errMessage : result.description; KMessageBox::error(this, errMessage, errDescription); setValid(m_tablesPageItem, false); } } } void ImportTableWizard::arriveAlterTablePage() { //! @todo handle errors if (m_tableListWidget->selectedItems().isEmpty()) return; //! @todo (js) support multiple tables? #if 0 foreach(QListWidgetItem *table, m_tableListWidget->selectedItems()) { m_importTableName = table->text(); } #else m_importTableName = m_tableListWidget->selectedItems().first()->text(); #endif QScopedPointer ts(new KDbTableSchema); if (!m_migrateDriver->readTableSchema(m_importTableName, ts.data())) { return; } setValid(m_alterTablePageItem, ts->fieldCount() > 0); if (isValid(m_alterTablePageItem)) { connect(m_alterSchemaWidget->nameWidget(), SIGNAL(textChanged()), this, SLOT(slotNameChanged()), Qt::UniqueConnection); } m_alterSchemaWidget->setTableSchema(ts.take()); if (!readFromTable()) { m_alterSchemaWidget->setTableSchema(nullptr); back(); KMessageBox::information(this, xi18nc("@info", "Could not import table %1. " "Select different table or cancel importing.", m_importTableName)); } } bool ImportTableWizard::readFromTable() { QSharedPointer tableResult = m_migrateDriver->readFromTable(m_importTableName); KDbTableSchema *newSchema = m_alterSchemaWidget->newSchema(); if (!tableResult || tableResult->lastResult().isError() || tableResult->fieldsCount() != newSchema->fieldCount()) { back(); KMessageBox::information(this, xi18nc("@info", "Could not import table %1. " "Select different table or cancel importing.", m_importTableName)); return false; } QScopedPointer> data(new QList); for (int i = 0; i < RECORDS_FOR_PREVIEW; ++i) { QSharedPointer record(tableResult->fetchRecordData()); if (!record) { if (tableResult->lastResult().isError()) { return false; } break; } data->append(record.data()); } if (data->isEmpty()) { back(); KMessageBox::information(this, xi18nc("@info", "No data has been found in table %1. " "Select different table or cancel importing.", m_importTableName)); return false; } m_alterSchemaWidget->model()->setRowCount(data->count()); m_alterSchemaWidget->setData(data.take()); return true; } void ImportTableWizard::arriveImportingPage() { m_importingPageWidget->hide(); #if 0 if (checkUserInput()) { //setNextEnabled(m_importingPageWidget, true); user2Button->setEnabled(true); } else { //setNextEnabled(m_importingPageWidget, false); user2Button->setEnabled(false); } #endif QString txt; txt = xi18nc("@info Table import wizard, final message", "All required information has now been gathered. " "Click Next button to start importing table %1." "Depending on size of the table this may take some time.", m_alterSchemaWidget->nameWidget()->nameText()); m_lblImportingTxt->setText(txt); //temp. hack for MS Access driver only //! @todo for other databases we will need KexiMigration::Connection //! and KexiMigration::Driver classes bool showOptions = false; if (fileBasedSrcSelected()) { Kexi::ObjectStatus result; KexiMigrate* sourceDriver = prepareImport(&result); if (sourceDriver) { showOptions = !result.error() && sourceDriver->propertyValue("source_database_has_nonunicode_encoding").toBool(); sourceDriver->setData(nullptr); } } if (showOptions) m_importOptionsButton->show(); else m_importOptionsButton->hide(); m_importingPageWidget->show(); setAppropriate(m_progressPageItem, true); } void ImportTableWizard::arriveProgressPage() { m_progressLbl->setText(xi18nc("@info", "Please wait while the table is imported.")); backButton()->setEnabled(false); nextButton()->setEnabled(false); connect(button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &ImportTableWizard::slotCancelClicked); QApplication::setOverrideCursor(Qt::BusyCursor); m_importComplete = doImport(); QApplication::restoreOverrideCursor(); disconnect(button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &ImportTableWizard::slotCancelClicked); next(); } void ImportTableWizard::arriveFinishPage() { if (m_importComplete) { m_finishPageItem->setHeader(xi18n("Success")); m_finishLbl->setText(xi18nc("@info", "Table %1 has been imported.", m_alterSchemaWidget->nameWidget()->nameText())); } else { m_finishPageItem->setHeader(xi18n("Failure")); m_finishLbl->setText(xi18n("An error occurred.")); } m_migrateDriver->disconnectSource(); button(QDialogButtonBox::Cancel)->setEnabled(!m_importComplete); m_finishCheckBox->setVisible(m_importComplete); finishButton()->setEnabled(m_importComplete); nextButton()->setEnabled(m_importComplete); setAppropriate(m_progressPageItem, false); } bool ImportTableWizard::fileBasedSrcSelected() const { return m_srcConnSel->selectedConnectionType() == KexiConnectionSelectorWidget::FileBased; } KexiMigrate* ImportTableWizard::prepareImport(Kexi::ObjectStatus *result) { Q_ASSERT(result); // Find a source (migration) driver name QString sourceDriverId = driverIdForSelectedSource(); if (sourceDriverId.isEmpty()) { result->setStatus(xi18n("No appropriate migration driver found."), m_migrateManager.possibleProblemsMessage()); } // Get a source (migration) driver KexiMigrate* sourceDriver = 0; if (!result->error()) { sourceDriver = m_migrateManager.driver(sourceDriverId); if (!sourceDriver || m_migrateManager.result().isError()) { qDebug() << "Import migrate driver error..."; result->setStatus(m_migrateManager.resultable()); } } // Set up source (migration) data required for connection if (sourceDriver && !result->error()) { #if 0 // Setup progress feedback for the GUI if (sourceDriver->progressSupported()) { m_progressBar->updateGeometry(); disconnect(sourceDriver, SIGNAL(progressPercent(int)), this, SLOT(progressUpdated(int))); connect(sourceDriver, SIGNAL(progressPercent(int)), this, SLOT(progressUpdated(int))); progressUpdated(0); } #endif bool keepData = true; #if 0 if (m_importTypeStructureAndDataCheckBox->isChecked()) { qDebug() << "Structure and data selected"; keepData = true; } else if (m_importTypeStructureOnlyCheckBox->isChecked()) { qDebug() << "structure only selected"; keepData = false; } else { qDebug() << "Neither radio button is selected (not possible?) presume keep data"; keepData = true; } #endif KexiMigration::Data* md = new KexiMigration::Data(); if (fileBasedSrcSelected()) { KDbConnectionData* conn_data = new KDbConnectionData(); conn_data->setDatabaseName(m_srcConnSel->selectedFile()); md->source = conn_data; md->sourceName.clear(); } else { md->source = m_srcConnSel->selectedConnectionData(); md->sourceName = m_srcDBName->selectedProjectData()->databaseName(); } md->setShouldCopyData(keepData); sourceDriver->setData(md); return sourceDriver; } return 0; } //=========================================================== // QString ImportTableWizard::driverIdForSelectedSource() { if (fileBasedSrcSelected()) { QMimeDatabase db; QMimeType mime = db.mimeTypeForFile(m_srcConnSel->selectedFile()); if (!mime.isValid() || mime.name() == "application/octet-stream" || mime.name() == "text/plain" || mime.name() == "application/zip") { //try by URL: mime = db.mimeTypeForFile(m_srcConnSel->selectedFile()); } if (!mime.isValid()) { return QString(); } const QStringList ids(m_migrateManager.driverIdsForMimeType(mime.name())); //! @todo do we want to return first migrate driver for the mime type or allow to select it? return ids.isEmpty() ? QString() : ids.first(); } return m_srcConnSel->selectedConnectionData() ? m_srcConnSel->selectedConnectionData()->databaseName() : QString(); } bool ImportTableWizard::doImport() { KexiGUIMessageHandler msg; KexiProject* project = KexiMainWindowIface::global()->project(); if (!project) { msg.showErrorMessage(KDbMessageHandler::Error, xi18n("No project available.")); return false; } KexiPart::Part *part = Kexi::partManager().partForPluginId("org.kexi-project.table"); if (!part) { msg.showErrorMessage(Kexi::partManager().result()); return false; } KDbTableSchema* newSchema = m_alterSchemaWidget->newSchema(); if (!newSchema) { msg.showErrorMessage(KDbMessageHandler::Error, xi18n("No table was selected to import.")); return false; } newSchema->setName(m_alterSchemaWidget->nameWidget()->nameText()); newSchema->setCaption(m_alterSchemaWidget->nameWidget()->captionText()); KexiPart::Item* partItemForSavedTable = project->createPartItem(part->info(), newSchema->name()); if (!partItemForSavedTable) { msg.showErrorMessage(project->result()); return false; } //Create the table if (!m_connection->createTable(newSchema, KDbConnection::CreateTableOption::Default | KDbConnection::CreateTableOption::DropDestination)) { msg.showErrorMessage(KDbMessageHandler::Error, xi18nc("@info", "Unable to create table %1.", newSchema->name())); return false; } m_alterSchemaWidget->takeTableSchema(); //m_connection takes ownership of the KDbTableSchema object //Import the data QApplication::setOverrideCursor(Qt::BusyCursor); QList row; unsigned int fieldCount = newSchema->fieldCount(); m_migrateDriver->moveFirst(); KDbTransactionGuard tg(m_connection); if (m_connection->result().isError()) { QApplication::restoreOverrideCursor(); return false; } do { for (unsigned int i = 0; i < fieldCount; ++i) { if (m_importWasCanceled) { return false; } if (i % 100 == 0) { QApplication::processEvents(); } row.append(m_migrateDriver->value(i)); } m_connection->insertRecord(newSchema, row); row.clear(); } while (m_migrateDriver->moveNext()); if (!tg.commit()) { QApplication::restoreOverrideCursor(); return false; } QApplication::restoreOverrideCursor(); //Done so save part and update gui partItemForSavedTable->setIdentifier(newSchema->id()); project->addStoredItem(part->info(), partItemForSavedTable); return true; } void ImportTableWizard::slotConnPageItemSelected(bool isSelected) { setValid(m_srcConnPageItem, isSelected); if (isSelected && fileBasedSrcSelected()) { next(); } } void ImportTableWizard::slotTableListWidgetSelectionChanged() { setValid(m_tablesPageItem, !m_tableListWidget->selectedItems().isEmpty()); } void ImportTableWizard::slotNameChanged() { setValid(m_alterTablePageItem, !m_alterSchemaWidget->nameWidget()->captionText().isEmpty()); } void ImportTableWizard::slotCancelClicked() { m_importWasCanceled = true; } void ImportTableWizard::slotOptionsButtonClicked() { OptionsDialog dlg(m_srcConnSel->selectedFile(), m_sourceDbEncoding, this); if (QDialog::Accepted == dlg.exec()) { m_sourceDbEncoding = dlg.encodingComboBox()->selectedEncoding(); } } diff --git a/src/migration/importwizard.cpp b/src/migration/importwizard.cpp index a557d9f91..000726b37 100644 --- a/src/migration/importwizard.cpp +++ b/src/migration/importwizard.cpp @@ -1,1134 +1,1134 @@ /* This file is part of the KDE project Copyright (C) 2004-2009 Adam Pigg Copyright (C) 2004-2016 Jarosław Staniek Copyright (C) 2005 Martin Ellis 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. */ #include "importwizard.h" #include "keximigrate.h" #include "importoptionsdlg.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 #include #include #include #include #include #include #include #include #include #include using namespace KexiMigration; class Q_DECL_HIDDEN ImportWizard::Private { public: Private(QMap* args_) : srcProjectSelector(0) , fileBasedDstWasPresented(false) , setupFileBasedSrcNeeded(true) , importExecuted(false) , prjSet(0) , args(args_) { } ~Private() { delete prjSet; } QWidget *introPageWidget, *srcConnPageWidget, *srcDBPageWidget, *dstTypePageWidget, *dstPageWidget, *importTypePageWidget, *importingPageWidget, *finishPageWidget; KPageWidgetItem *introPageItem, *srcConnPageItem, *srcDBPageItem, *dstTypePageItem, *dstPageItem, *importTypePageItem, *importingPageItem, *finishPageItem; QGroupBox *importTypeGroupBox; QRadioButton *importTypeStructureAndDataCheckBox; QRadioButton *importTypeStructureOnlyCheckBox; KexiDBTitlePage* dstTitlePageWidget; KPageWidgetItem *dstTitlePageItem; KexiPrjTypeSelector *dstPrjTypeSelector; KexiConnectionSelectorWidget *srcConn, *dstConn; QString driverIdForSelectedSource; QLineEdit *dstNewDBTitleLineEdit; QLabel *dstNewDBNameLabel; QLineEdit *dstNewDBNameLineEdit; QLabel *dstNewDBNameUrlLabel; KUrlRequester *dstNewDBNameUrl; KexiStartupFileHandler *dstNewDBFileHandler; KexiProjectSelectorWidget *srcProjectSelector; QLabel *lblImportingTxt, *lblImportingErrTxt, *finishLbl; QCheckBox *openImportedProjectCheckBox; bool fileBasedDstWasPresented; bool setupFileBasedSrcNeeded; bool importExecuted; //!< used in import() KexiProjectSet* prjSet; QProgressBar *progressBar; QPushButton* importOptionsButton; QMap *args; QString predefinedDatabaseName, predefinedMimeType; KDbConnectionData *predefinedConnectionData; MigrateManager migrateManager; //!< object lives here, so status messages can be globally preserved //! Encoding for source db. Currently only used for MDB driver. //! @todo Hardcoded. Move to KexiMigrate driver's impl. QString sourceDBEncoding; }; //=========================================================== // ImportWizard::ImportWizard(QWidget *parent, QMap* args) : KAssistantDialog(parent) , d(new Private(args)) { setModal(true); setWindowTitle(xi18nc("@title:window", "Import Database")); setWindowIcon(KexiIcon("database-import")); KexiMainWindowIface::global()->setReasonableDialogSize(this); parseArguments(); setupIntro(); setupSrcConn(); setupSrcDB(); setupDstType(); setupDstTitle(); setupDst(); setupImportType(); setupImporting(); setupFinish(); connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(slot_currentPageChanged(KPageWidgetItem*,KPageWidgetItem*))); connect(button(QDialogButtonBox::Help), &QPushButton::clicked, this, &ImportWizard::helpClicked); if (d->predefinedConnectionData) { // setup wizard for predefined server source d->srcConn->showAdvancedConnection(); setAppropriate(d->srcConnPageItem, false); setAppropriate(d->srcDBPageItem, false); } else if (!d->predefinedDatabaseName.isEmpty()) { // setup wizard for predefined source // (used when external project type was opened in Kexi, e.g. mdb file) setAppropriate(d->srcConnPageItem, false); setAppropriate(d->srcDBPageItem, false); d->srcConn->showSimpleConnection(); d->srcConn->setSelectedFile(d->predefinedDatabaseName); #if 0 //disable all prev pages except "welcome" page for (int i = 0; i < indexOf(d->dstTypePage); i++) { if (page(i) != d->introPage) setAppropriate(page(i), false); } #endif } d->sourceDBEncoding = QString::fromLatin1(KexiUtils::encoding()); //default } //=========================================================== // ImportWizard::~ImportWizard() { delete d; } //=========================================================== // void ImportWizard::parseArguments() { d->predefinedConnectionData = 0; if (!d->args) return; if (!(*d->args)["databaseName"].isEmpty() && !(*d->args)["mimeType"].isEmpty()) { d->predefinedDatabaseName = (*d->args)["databaseName"]; d->predefinedMimeType = (*d->args)["mimeType"]; if (d->args->contains("connectionData")) { bool ok; d->predefinedConnectionData = new KDbConnectionData( KDbUtils::deserializeMap((*d->args)["connectionData"]), &ok); if (!ok) { delete d->predefinedConnectionData; d->predefinedConnectionData = 0; } } } d->args->clear(); } QString ImportWizard::selectedSourceFileName() const { if (d->predefinedDatabaseName.isEmpty()) return d->srcConn->selectedFile(); return d->predefinedDatabaseName; } //=========================================================== // void ImportWizard::setupIntro() { d->introPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(); d->introPageWidget->setLayout(vbox); KexiUtils::setStandardMarginsAndSpacing(vbox); QLabel *lblIntro = new QLabel(d->introPageWidget); lblIntro->setAlignment(Qt::AlignTop | Qt::AlignLeft); lblIntro->setWordWrap(true); lblIntro->setTextFormat(Qt::RichText); QString msg; if (d->predefinedConnectionData) { //predefined import: server source msg = xi18nc("@info", "Database Importing Assistant is about to import %1 database " - "(connection %2) into a Kexi project.", + "(connection %2) into a KEXI project.", d->predefinedDatabaseName, d->predefinedConnectionData->toUserVisibleString()); } else if (!d->predefinedDatabaseName.isEmpty()) { //predefined import: file source //! @todo this message is currently ok for files only QMimeDatabase db; QMimeType mime = db.mimeTypeForName(d->predefinedMimeType); if (!mime.isValid()) { qWarning() << QString("'%1' mimetype not installed!").arg(d->predefinedMimeType); } d->driverIdForSelectedSource = driverIdForMimeType(mime); msg = xi18nc("@info", "Database Importing Assistant is about to import %1 file " - "of type %2 into a Kexi project.", + "of type %2 into a KEXI project.", QDir::toNativeSeparators(d->predefinedDatabaseName), mime.isValid() ? mime.comment() : "???"); } else { msg = xi18nc("@info", "Database Importing Assistant allows you to import an existing database " - "into a Kexi project."); + "into a KEXI project."); } // note: we're using .arg() here because the msg argument is already in rich-text format QString finalMessage = xi18nc("@info", "%1" "Click Next button to continue or " "Cancel button to exit this assistant.").arg(msg); lblIntro->setText(finalMessage); vbox->addWidget(lblIntro); d->introPageItem = new KPageWidgetItem(d->introPageWidget, xi18n("Welcome to the Database Importing Assistant")); addPage(d->introPageItem); } //=========================================================== // void ImportWizard::setupSrcConn() { d->srcConnPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(d->srcConnPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); d->srcConn = new KexiConnectionSelectorWidget(&Kexi::connset(), QUrl("kfiledialog:///ProjectMigrationSourceDir"), KexiConnectionSelectorWidget::Opening, d->srcConnPageWidget); d->srcConn->hideConnectonIcon(); d->srcConn->showSimpleConnection(); connect(d->srcConn, &KexiConnectionSelectorWidget::connectionSelected, this, &ImportWizard::sourceConnectionSelected); const QStringList excludedMimeTypes({ //! @todo remove when support for kexi files as source prj is added in migration KDb::defaultFileBasedDriverMimeType(), "application/x-kexiproject-shortcut", "application/x-kexi-connectiondata"}); d->srcConn->setExcludedMimeTypes(excludedMimeTypes); vbox->addWidget(d->srcConn); d->srcConnPageItem = new KPageWidgetItem(d->srcConnPageWidget, xi18n("Select Location for Source Database")); addPage(d->srcConnPageItem); } //=========================================================== // void ImportWizard::setupSrcDB() { // arrivesrcdbPage creates widgets on that page d->srcDBPageWidget = new QWidget(this); d->srcDBPageItem = new KPageWidgetItem(d->srcDBPageWidget, xi18n("Select Source Database")); addPage(d->srcDBPageItem); } //=========================================================== // void ImportWizard::setupDstType() { d->dstTypePageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(d->dstTypePageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); QHBoxLayout *hbox = new QHBoxLayout; vbox->addLayout(hbox); KexiUtils::setStandardMarginsAndSpacing(hbox); QLabel *lbl = new QLabel(xi18n("Destination database type:") /*+ ' '*/, d->dstTypePageWidget); lbl->setAlignment(Qt::AlignLeft | Qt::AlignTop); lbl->setTextFormat(Qt::RichText); hbox->addWidget(lbl); d->dstPrjTypeSelector = new KexiPrjTypeSelector(d->dstTypePageWidget); hbox->addWidget(d->dstPrjTypeSelector); d->dstPrjTypeSelector->option_file->setText(xi18n("Database project stored in a file")); d->dstPrjTypeSelector->option_server->setText(xi18n("Database project stored on a server")); hbox->addStretch(1); vbox->addStretch(1); d->dstTypePageItem = new KPageWidgetItem(d->dstTypePageWidget, xi18n("Select Destination Database Type")); addPage(d->dstTypePageItem); } //=========================================================== // void ImportWizard::setupDstTitle() { d->dstTitlePageWidget = new KexiDBTitlePage(xi18n("Destination project's caption:"), this); d->dstTitlePageWidget->layout()->setMargin(KexiUtils::marginHint()); d->dstTitlePageWidget->updateGeometry(); d->dstNewDBTitleLineEdit = d->dstTitlePageWidget->le_title; connect(d->dstNewDBTitleLineEdit, SIGNAL(textChanged(QString)), this, SLOT(destinationTitleTextChanged(QString))); d->dstNewDBNameUrlLabel = d->dstTitlePageWidget->label_requester; d->dstNewDBNameUrl = d->dstTitlePageWidget->file_requester; d->dstNewDBFileHandler = new KexiStartupFileHandler( QUrl("kfiledialog:///ProjectMigrationDestinationDir"), KexiFileFilters::SavingFileBasedDB, d->dstTitlePageWidget->file_requester); d->dstNewDBNameLabel = new QLabel(xi18n("Destination project's name:"), d->dstTitlePageWidget); d->dstTitlePageWidget->formLayout->setWidget(2, QFormLayout::LabelRole, d->dstNewDBNameLabel); d->dstNewDBNameLineEdit = new QLineEdit(d->dstTitlePageWidget); d->dstNewDBNameLineEdit->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); KDbIdentifierValidator *idValidator = new KDbIdentifierValidator(this); idValidator->setLowerCaseForced(true); d->dstNewDBNameLineEdit->setValidator(idValidator); d->dstTitlePageWidget->formLayout->setWidget(2, QFormLayout::FieldRole, d->dstNewDBNameLineEdit); d->dstTitlePageItem = new KPageWidgetItem(d->dstTitlePageWidget, xi18n("Enter Destination Database Project's Caption")); addPage(d->dstTitlePageItem); } void ImportWizard::destinationTitleTextChanged(const QString & text) { Q_UNUSED(text); updateDestinationDBFileName(); } void ImportWizard::updateDestinationDBFileName() { d->dstNewDBFileHandler->updateUrl(d->dstNewDBTitleLineEdit->text()); d->dstNewDBNameLineEdit->setText(d->dstNewDBTitleLineEdit->text()); } //=========================================================== // void ImportWizard::setupDst() { d->dstPageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(d->dstPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); d->dstConn = new KexiConnectionSelectorWidget(&Kexi::connset(), QUrl("kfiledialog:///ProjectMigrationDestinationDir"), KexiConnectionSelectorWidget::Saving, d->dstPageWidget); d->dstConn->hideHelpers(); vbox->addWidget(d->dstConn); connect(d->dstConn, SIGNAL(connectionItemExecuted(ConnectionDataLVItem*)), this, SLOT(next())); d->dstConn->showSimpleConnection(); //anyway, db files will be _saved_ d->dstConn->setFileMode(KexiFileFilters::SavingFileBasedDB); d->dstPageItem = new KPageWidgetItem(d->dstPageWidget, xi18n("Select Location for Destination Database Project")); addPage(d->dstPageItem); } //=========================================================== // void ImportWizard::setupImportType() { d->importTypePageWidget = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(d->importTypePageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); d->importTypeGroupBox = new QGroupBox(d->importTypePageWidget); vbox->addWidget(d->importTypeGroupBox); QVBoxLayout *importTypeGroupBoxLyr = new QVBoxLayout; importTypeGroupBoxLyr->addWidget( d->importTypeStructureAndDataCheckBox = new QRadioButton( xi18nc("Scope of import", "Structure and data"), d->importTypeGroupBox)); d->importTypeStructureAndDataCheckBox->setChecked(true); importTypeGroupBoxLyr->addWidget( d->importTypeStructureOnlyCheckBox = new QRadioButton( xi18nc("Scope of import", "Structure only"), d->importTypeGroupBox)); importTypeGroupBoxLyr->addStretch(1); d->importTypeGroupBox->setLayout(importTypeGroupBoxLyr); d->importTypePageItem = new KPageWidgetItem(d->importTypePageWidget, xi18n("Select Scope of Import")); addPage(d->importTypePageItem); } //=========================================================== // void ImportWizard::setupImporting() { d->importingPageWidget = new QWidget(this); d->importingPageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(d->importingPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); d->lblImportingTxt = new QLabel(d->importingPageWidget); d->lblImportingTxt->setAlignment(Qt::AlignTop | Qt::AlignLeft); d->lblImportingTxt->setWordWrap(true); d->lblImportingTxt->setTextFormat(Qt::RichText); d->lblImportingErrTxt = new QLabel(d->importingPageWidget); d->lblImportingErrTxt->setAlignment(Qt::AlignTop | Qt::AlignLeft); d->lblImportingErrTxt->setWordWrap(true); d->lblImportingErrTxt->setTextFormat(Qt::RichText); d->progressBar = new QProgressBar(d->importingPageWidget); d->progressBar->setRange(0, 100); d->progressBar->hide(); vbox->addWidget(d->lblImportingTxt); vbox->addWidget(d->lblImportingErrTxt); vbox->addStretch(1); QWidget *options_widget = new QWidget(d->importingPageWidget); vbox->addWidget(options_widget); QVBoxLayout *options_vbox = new QVBoxLayout(options_widget); options_vbox->setSpacing(KexiUtils::spacingHint()); QHBoxLayout *importOptionsButtonLyr = new QHBoxLayout; options_vbox->addLayout(importOptionsButtonLyr); d->importOptionsButton = new QPushButton(koIcon("configure"), xi18n("Advanced Options"), options_widget); connect(d->importOptionsButton, SIGNAL(clicked()), this, SLOT(slotOptionsButtonClicked())); importOptionsButtonLyr->addStretch(1); importOptionsButtonLyr->addWidget(d->importOptionsButton); importOptionsButtonLyr->addStretch(1); options_vbox->addStretch(1); vbox->addWidget(d->progressBar); vbox->addStretch(2); d->importingPageWidget->show(); d->importingPageItem = new KPageWidgetItem(d->importingPageWidget, xi18n("Importing")); addPage(d->importingPageItem); } //=========================================================== // void ImportWizard::setupFinish() { d->finishPageWidget = new QWidget(this); d->finishPageWidget->hide(); QVBoxLayout *vbox = new QVBoxLayout(d->finishPageWidget); KexiUtils::setStandardMarginsAndSpacing(vbox); d->finishLbl = new QLabel(d->finishPageWidget); d->finishLbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); d->finishLbl->setWordWrap(true); d->finishLbl->setTextFormat(Qt::RichText); vbox->addWidget(d->finishLbl); d->openImportedProjectCheckBox = new QCheckBox(xi18n("Open imported project"), d->finishPageWidget); d->openImportedProjectCheckBox->setChecked(true); vbox->addSpacing(KexiUtils::spacingHint()); vbox->addWidget(d->openImportedProjectCheckBox); vbox->addStretch(1); d->finishPageItem = new KPageWidgetItem(d->finishPageWidget, xi18n("Success")); addPage(d->finishPageItem); } //=========================================================== // bool ImportWizard::checkUserInput() { QString issues; if (d->dstNewDBTitleLineEdit->text().isEmpty()) { issues = xi18nc("@info", "No new database name was entered."); } Kexi::ObjectStatus result; KexiMigrate* sourceDriver = prepareImport(result); if (sourceDriver && sourceDriver->isSourceAndDestinationDataSourceTheSame()) { // note: we're using .arg() here because the 'issues' argument is already in rich-text format issues = xi18nc("@info", "%1Source database is the same as destination.") .arg(issues); } if (!issues.isEmpty()) { // note: we're using .arg() here because the 'issues' argument is already in rich-text format d->lblImportingErrTxt->setText( xi18nc("@info", "Following issues were found with the data you entered:" "%1" "Please click Back button and correct these issues.") .arg(issues)); return false; } return true; } void ImportWizard::arriveSrcConnPage() { d->srcConnPageWidget->hide(); /*! @todo KexiFileWidget needs "open file" and "open server" modes in addition to just "open" */ if (d->setupFileBasedSrcNeeded) { d->setupFileBasedSrcNeeded = false; d->srcConn->setFileMode(KexiFileFilters::Opening); d->srcConn->setAdditionalMimeTypes(QStringList()); } /*! @todo Support different file extensions based on MigrationDriver */ d->srcConnPageWidget->show(); } void ImportWizard::arriveSrcDBPage() { if (fileBasedSrcSelected()) { //! @todo Back button doesn't work after selecting a file to import } else { if (!d->srcProjectSelector) { QVBoxLayout *vbox = new QVBoxLayout(d->srcDBPageWidget); d->srcProjectSelector = new KexiProjectSelectorWidget(d->srcDBPageWidget); vbox->addWidget(d->srcProjectSelector); KexiUtils::setStandardMarginsAndSpacing(vbox); d->srcProjectSelector->label()->setText(xi18n("Select source database you wish to import:")); } d->srcDBPageWidget->hide(); KDbConnectionData* condata = d->srcConn->selectedConnectionData(); Q_ASSERT(condata); Q_ASSERT(d->prjSet); d->srcProjectSelector->setProjectSet(d->prjSet); d->srcDBPageWidget->show(); } } void ImportWizard::arriveDstTitlePage() { d->dstNewDBNameUrlLabel->setVisible(fileBasedDstSelected()); d->dstNewDBNameUrl->setVisible(fileBasedDstSelected()); d->dstNewDBNameLabel->setVisible(!fileBasedDstSelected()); d->dstNewDBNameLineEdit->setVisible(!fileBasedDstSelected()); if (fileBasedSrcSelected()) { const QString fname(selectedSourceFileName()); QString suggestedDBName(QFileInfo(fname).fileName()); const QFileInfo fi(suggestedDBName); suggestedDBName = suggestedDBName.left(suggestedDBName.length() - (fi.completeSuffix().isEmpty() ? 0 : (fi.completeSuffix().length() + 1))); d->dstNewDBTitleLineEdit->setText(suggestedDBName); } else { if (d->predefinedConnectionData) { // server source db is predefined d->dstNewDBTitleLineEdit->setText(d->predefinedDatabaseName); } else { if (!d->srcProjectSelector || !d->srcProjectSelector->selectedProjectData()) { back(); //!< @todo return; } d->dstNewDBTitleLineEdit->setText(d->srcProjectSelector->selectedProjectData()->databaseName()); } } d->dstNewDBTitleLineEdit->selectAll(); d->dstNewDBTitleLineEdit->setFocus(); updateDestinationDBFileName(); } void ImportWizard::arriveDstPage() { if (fileBasedDstSelected()) { d->dstPageWidget->hide(); KAssistantDialog::next(); return; } else { d->dstConn->showAdvancedConnection(); } d->dstPageWidget->show(); } void ImportWizard::arriveImportingPage() { d->importingPageWidget->hide(); nextButton()->setEnabled(checkUserInput()); d->lblImportingTxt->setText(xi18nc("@info", "All required information has now " "been gathered. Click Next button to start importing." "Depending on size of the database this may take some time." /*"Note: You may be asked for extra " "information such as field types if " "the wizard could not automatically " "determine this for you."*/)); //temp. hack for MS Access driver only //! @todo for other databases we will need KexiMigration::Connection //! and KexiMigration::Driver classes bool showOptions = false; if (fileBasedSrcSelected()) { Kexi::ObjectStatus result; KexiMigrate* sourceDriver = prepareImport(result); if (sourceDriver) { showOptions = !result.error() && sourceDriver->propertyValue("source_database_has_nonunicode_encoding").toBool(); sourceDriver->setData(nullptr); } } if (showOptions) d->importOptionsButton->show(); else d->importOptionsButton->hide(); d->importingPageWidget->show(); } void ImportWizard::arriveFinishPage() { } bool ImportWizard::fileBasedSrcSelected() const { if (d->predefinedConnectionData) return false; // qDebug() << (d->srcConn->selectedConnectionType()==KexiConnectionSelectorWidget::FileBased); return d->srcConn->selectedConnectionType() == KexiConnectionSelectorWidget::FileBased; } bool ImportWizard::fileBasedDstSelected() const { return d->dstPrjTypeSelector->option_file->isChecked(); } void ImportWizard::progressUpdated(int percent) { d->progressBar->setValue(percent); qApp->processEvents(); } QString ImportWizard::driverIdForMimeType(const QMimeType &mime) const { if (!mime.isValid()) { return QString(); } const QStringList ids(d->migrateManager.driverIdsForMimeType(mime.name())); //! @todo do we want to return first migrate driver for the mime type or allow to select it? return ids.isEmpty() ? QString() : ids.first(); } QString ImportWizard::findDriverIdForSelectedSource() { if (fileBasedSrcSelected()) { QMimeDatabase db; QMimeType mime = db.mimeTypeForFile(selectedSourceFileName()); if (!mime.isValid() || mime.name() == "application/octet-stream" || mime.name() == "text/plain" || mime.name() == "application/zip") { //try by URL: mime = db.mimeTypeForFile(selectedSourceFileName()); } return driverIdForMimeType(mime); } //server-based QString sourceDriverId; if (d->predefinedConnectionData) { sourceDriverId = d->predefinedConnectionData->driverId(); } else if (d->srcConn->selectedConnectionData()) { sourceDriverId = d->srcConn->selectedConnectionData()->driverId(); } const QStringList migrationDriverIds(d->migrateManager.driverIdsForSourceDriver(sourceDriverId)); //! @todo First found driver ID is picked. It's OK as long as there is one migration //! driver per source database type. How about allowing users to pick migration driver? return migrationDriverIds.isEmpty() ? QString() : migrationDriverIds.first(); } //=========================================================== // void ImportWizard::accept() { if (d->args) { if ((!fileBasedDstSelected() && !d->args->contains("destinationConnectionShortcut")) || !d->openImportedProjectCheckBox->isChecked()) { //do not open dest db if used didn't want it //for server connections, destinationConnectionShortcut must be defined d->args->remove("destinationDatabaseName"); } } KAssistantDialog::accept(); } KexiMigrate* ImportWizard::prepareImport(Kexi::ObjectStatus& result) { KexiUtils::WaitCursor wait; // Start with a driver manager KDbDriverManager manager; //qDebug() << "Creating destination driver..."; // Get a driver to the destination database KDbDriver *destDriver = manager.driver( d->dstConn->selectedConnectionData() ? d->dstConn->selectedConnectionData()->driverId() : KDb::defaultFileBasedDriverId()); if (!destDriver || manager.result().isError()) { result.setStatus(manager.resultable()); qWarning() << "Manager error:" << manager.result(); } // Set up destination connection data KDbConnectionData *cdata = 0; QScopedPointer cdataDeleter; QString dbname; if (!result.error()) { if (d->dstConn->selectedConnectionData()) { //server-based project qDebug() << "Server destination..."; cdata = d->dstConn->selectedConnectionData(); dbname = d->dstNewDBNameLineEdit->text(); } else { //file-based project qDebug() << "File Destination..."; cdata = new KDbConnectionData(); cdataDeleter.reset(cdata); // ownership won't be transferred cdata->setCaption(d->dstNewDBTitleLineEdit->text()); cdata->setDriverId(KDb::defaultFileBasedDriverId()); dbname = d->dstTitlePageWidget->file_requester->url().toLocalFile(); cdata->setDatabaseName(dbname); qDebug() << "Current file name:" << dbname; } } // Find a source (migration) driver name if (!result.error()) { if (d->driverIdForSelectedSource.isEmpty()) result.setStatus(xi18n("No appropriate migration driver found."), d->migrateManager.possibleProblemsMessage()); } // Get a source (migration) driver KexiMigrate* sourceDriver = 0; if (!result.error()) { sourceDriver = d->migrateManager.driver(d->driverIdForSelectedSource); if (!sourceDriver || d->migrateManager.result().isError()) { qDebug() << "Import migrate driver error..."; result.setStatus(d->migrateManager.resultable()); } } KexiUtils::removeWaitCursor(); // Set up source (migration) data required for connection if (sourceDriver && !result.error() && cdata) { // Setup progress feedback for the GUI if (sourceDriver->progressSupported()) { d->progressBar->updateGeometry(); disconnect(sourceDriver, SIGNAL(progressPercent(int)), this, SLOT(progressUpdated(int))); connect(sourceDriver, SIGNAL(progressPercent(int)), this, SLOT(progressUpdated(int))); progressUpdated(0); } bool keepData; if (d->importTypeStructureAndDataCheckBox->isChecked()) { qDebug() << "Structure and data selected"; keepData = true; } else if (d->importTypeStructureOnlyCheckBox->isChecked()) { qDebug() << "structure only selected"; keepData = false; } else { qDebug() << "Neither radio button is selected (not possible?) presume keep data"; keepData = true; } KexiMigration::Data* md = new KexiMigration::Data(); md->setDestinationProjectData(new KexiProjectData(*cdata, dbname)); if (fileBasedSrcSelected()) { KDbConnectionData* conn_data = new KDbConnectionData(); conn_data->setDatabaseName(selectedSourceFileName()); md->source = conn_data; md->sourceName.clear(); } else { if (d->predefinedConnectionData) md->source = d->predefinedConnectionData; else md->source = d->srcConn->selectedConnectionData(); if (!d->predefinedDatabaseName.isEmpty()) md->sourceName = d->predefinedDatabaseName; else md->sourceName = d->srcProjectSelector->selectedProjectData()->databaseName(); //! @todo Aah, this is so C-like. Move to performImport(). } md->setShouldCopyData(keepData); sourceDriver->setData(md); return sourceDriver; } return 0; } tristate ImportWizard::import() { d->importExecuted = true; Kexi::ObjectStatus result; KexiMigrate* sourceDriver = prepareImport(result); bool acceptingNeeded = false; // Perform import if (sourceDriver && !result.error()) { if (!d->sourceDBEncoding.isEmpty()) { sourceDriver->setPropertyValue("source_database_nonunicode_encoding", QVariant(d->sourceDBEncoding.toUpper().remove(' ')) // "CP1250", not "cp 1250" ); } if (!sourceDriver->checkIfDestinationDatabaseOverwritingNeedsAccepting(&result, &acceptingNeeded)) { qDebug() << "Abort import cause checkIfDestinationDatabaseOverwritingNeedsAccepting " "returned false."; return false; } qDebug() << sourceDriver->data()->destinationProjectData()->databaseName(); qDebug() << "Performing import..."; } if (sourceDriver && !result.error() && acceptingNeeded) { // ok, the destination-db already exists... if (KMessageBox::Yes != KMessageBox::warningYesNo(this, xi18nc("@info (don't add tags around %1, it's done already)", "Database %1 already exists." "Do you want to replace it with a new one?", KexiUtils::localizedStringToHtmlSubstring( sourceDriver->data()->destinationProjectData()->infoString())), 0, KGuiItem(xi18nc("@action:button Replace Database", "&Replace")), KStandardGuiItem::no())) { return cancelled; } } if (sourceDriver && !result.error() && sourceDriver->progressSupported()) { d->progressBar->show(); } if (sourceDriver && !result.error() && sourceDriver->performImport(&result)) { if (d->args) { d->args->insert("destinationDatabaseName", fileBasedDstSelected() ? sourceDriver->data()->destinationProjectData()->connectionData()->databaseName() : sourceDriver->data()->destinationProjectData()->databaseName()); QString destinationConnectionShortcut; if (d->dstConn->selectedConnectionData()) { destinationConnectionShortcut = Kexi::connset().fileNameForConnectionData(*d->dstConn->selectedConnectionData()); } if (!destinationConnectionShortcut.isEmpty()) { d->args->insert("destinationConnectionShortcut", destinationConnectionShortcut); } } d->finishPageItem->setHeader(xi18n("Success")); return true; } if (!sourceDriver || result.error()) { d->progressBar->setValue(0); d->progressBar->hide(); QString msg, details; KexiTextMessageHandler handler(&msg, &details); handler.showErrorMessage(&result); qDebug() << msg << "\n" << details; d->finishPageItem->setHeader(xi18n("Failure")); // note: we're using .arg() here because the msg and details arguments are already in rich-text format d->finishLbl->setText( xi18nc("@info", "Import failed." "%1" "%2" "You can click Back button and try again.") .arg(msg).arg(details)); return false; } return true; } void ImportWizard::reject() { KAssistantDialog::reject(); } //=========================================================== // void ImportWizard::next() { if (currentPage() == d->srcConnPageItem) { if (fileBasedSrcSelected() && /*! @todo use QUrl? */!QFileInfo(selectedSourceFileName()).isFile()) { KMessageBox::sorry(this, xi18n("Select source database filename.")); return; } KDbConnectionData* conndata = d->srcConn->selectedConnectionData(); if (!fileBasedSrcSelected() && !conndata) { KMessageBox::sorry(this, xi18n("Select source database.")); return; } d->driverIdForSelectedSource = findDriverIdForSelectedSource(); // cache KexiMigrate* import = d->migrateManager.driver(d->driverIdForSelectedSource); if (!import || d->migrateManager.result().isError()) { QString dbname; if (fileBasedSrcSelected()) dbname = QDir::toNativeSeparators(selectedSourceFileName()); else dbname = conndata ? conndata->toUserVisibleString() : QString(); KMessageBox::error(this, dbname.isEmpty() ? xi18n("Could not import database. This type is not supported.") : xi18nc("@info", "Could not import database %1. " "This type is not supported.", dbname)); return; } if (!fileBasedSrcSelected()) { // make sure we have password if needed tristate passwordNeeded = false; if (conndata->password().isEmpty()) { passwordNeeded = KexiDBPasswordDialog::getPasswordIfNeeded(conndata, this); } bool ok = passwordNeeded != cancelled; if (ok) { KexiGUIMessageHandler handler; d->prjSet = new KexiProjectSet(&handler); if (!d->prjSet->setConnectionData(conndata)) { handler.showErrorMessage(d->prjSet->result()); ok = false; } } if (!ok) { if (passwordNeeded == true) { conndata->setPassword(QString::null); // not clear(), we have to remove password } delete d->prjSet; d->prjSet = 0; return; } } } else if (currentPage() == d->dstTitlePageItem) { if (fileBasedDstSelected()) { if (QFileInfo::exists(d->dstNewDBNameUrl->url().toLocalFile())) { if (!KexiUtils::askForFileOverwriting(d->dstNewDBNameUrl->url().toLocalFile(), this)) { return; } } } } else if (currentPage() == d->importTypePageItem) { if (!fileBasedDstSelected()) { // make sure we have password if needed tristate passwordNeeded = false; KDbConnectionData* condata = d->dstConn->selectedConnectionData(); if (condata->password().isEmpty()) { passwordNeeded = KexiDBPasswordDialog::getPasswordIfNeeded(condata, this); } bool ok = passwordNeeded != cancelled; if (!ok) { if (passwordNeeded == true) { condata->setPassword(QString::null); // not clear(), we have to remove password } return; } } } else if (currentPage() == d->importingPageItem) { if (!d->importExecuted) { d->importOptionsButton->hide(); backButton()->setEnabled(false); nextButton()->setEnabled(false); finishButton()->setEnabled(false); d->lblImportingTxt->setText(xi18n("Importing in progress...")); tristate res = import(); if (true == res) { d->finishLbl->setText( xi18nc("@info", - "Database has been imported into Kexi project %1.", + "Database has been imported into KEXI project %1.", d->dstNewDBNameLineEdit->text())); button(QDialogButtonBox::Cancel)->setEnabled(false); backButton()->setEnabled(false); nextButton()->setEnabled(true); finishButton()->setEnabled(false); d->openImportedProjectCheckBox->show(); next(); return; } d->progressBar->hide(); button(QDialogButtonBox::Cancel)->setEnabled(true); backButton()->setEnabled(true); nextButton()->setEnabled(false); finishButton()->setEnabled(false); d->openImportedProjectCheckBox->hide(); if (!res) next(); else if (~res) { arriveImportingPage(); } d->importExecuted = false; return; } } setAppropriate(d->srcDBPageItem, !fileBasedSrcSelected() && !d->predefinedConnectionData); setAppropriate(d->dstPageItem, !fileBasedDstSelected()); KAssistantDialog::next(); } void ImportWizard::back() { setAppropriate(d->srcDBPageItem, !fileBasedSrcSelected() && !d->predefinedConnectionData); KAssistantDialog::back(); } void ImportWizard::slot_currentPageChanged(KPageWidgetItem* curPage,KPageWidgetItem* prevPage) { Q_UNUSED(prevPage); if (curPage == d->introPageItem) { } else if (curPage == d->srcConnPageItem) { arriveSrcConnPage(); } else if (curPage == d->srcDBPageItem) { arriveSrcDBPage(); } else if (curPage == d->dstTypePageItem) { } else if (curPage == d->dstTitlePageItem) { arriveDstTitlePage(); } else if (curPage == d->dstPageItem) { if (fileBasedDstSelected()) { if (prevPage == d->importTypePageItem) { KAssistantDialog::back(); } else { KAssistantDialog::next(); } } else { arriveDstPage(); } } else if (curPage == d->importingPageItem) { arriveImportingPage(); } else if (curPage == d->finishPageItem) { arriveFinishPage(); } } void ImportWizard::helpClicked() { if (currentPage() == d->introPageItem) { KMessageBox::information(this, xi18n("No help is available for this page."), xi18n("Help")); } else if (currentPage() == d->srcConnPageItem) { KMessageBox::information(this, xi18n("Here you can choose the location to import data from."), xi18n("Help")); } else if (currentPage() == d->srcDBPageItem) { KMessageBox::information(this, xi18n("Here you can choose the actual database to import data from."), xi18n("Help")); } else if (currentPage() == d->dstTypePageItem) { KMessageBox::information(this, xi18n("Here you can choose the location to save the data."), xi18n("Help")); } else if (currentPage() == d->dstPageItem) { KMessageBox::information(this, xi18n("Here you can choose the location to save the data in and the new database name."), xi18n("Help")); } else if (currentPage() == d->finishPageItem || currentPage() == d->importingPageItem) { KMessageBox::information(this, xi18n("No help is available for this page."), xi18n("Help")); } } void ImportWizard::slotOptionsButtonClicked() { OptionsDialog dlg(selectedSourceFileName(), d->sourceDBEncoding, this); if (QDialog::Accepted == dlg.exec()) { d->sourceDBEncoding = dlg.encodingComboBox()->selectedEncoding(); } } void ImportWizard::sourceConnectionSelected(bool selected) { if (selected) { next(); } } diff --git a/src/migration/mdb/src/keximdb/keximigrate_mdb.json b/src/migration/mdb/src/keximdb/keximigrate_mdb.json index 8e808da6d..fa1bbad91 100644 --- a/src/migration/mdb/src/keximdb/keximigrate_mdb.json +++ b/src/migration/mdb/src/keximdb/keximigrate_mdb.json @@ -1,63 +1,63 @@ { "KPlugin": { "Authors": [ { "Email": "kexi@kde.org", - "Name": "Kexi Team", + "Name": "KEXI Team", "Name[ca@valencia]": "L'equip del Kexi", "Name[ca]": "L'equip del Kexi", "Name[cs]": "Tým Kexi", "Name[de]": "Kexi-Team", "Name[es]": "Equipo de Kexi", "Name[fr]": "L'équipe Kexi", "Name[gl]": "Equipo de Kexi", "Name[it]": "La squadra di Kexi", "Name[nl]": "Het team van Kexi", "Name[pl]": "Zespół Kexi", "Name[pt]": "Equipa do Kexi", "Name[pt_BR]": "Equipe do Kexi", "Name[ru]": "Команда разработчиков Kexi", "Name[sk]": "Tím Kexi", "Name[sv]": "Kexi-gruppen", "Name[tr]": "Kexi Ekibi", "Name[uk]": "Команда Kexi", "Name[x-test]": "xxKexi Teamxx", "Name[zh_CN]": "Kexi 团队" } ], "Category": "", "Dependencies": [], - "Description": "MS Access (MDB) import plugin for Kexi", + "Description": "MS Access (MDB) import plugin for KEXI", "Description[ca@valencia]": "Connector d'importació del MS Access (MDB) pel Kexi", "Description[ca]": "Connector d'importació del MS Access (MDB) pel Kexi", "Description[cs]": "Modul Kexi pro import MS Access (MDB)", "Description[de]": "MS-Access-(MDB)-Importmodul für Kexi", "Description[es]": "Complemento de importación de MS Access (MDB) para Kexi", "Description[gl]": "Complemento para Kexi de importación de MS Access (MDB).", "Description[it]": "Estensione di importazione MS Access (MDB) per Kexi", "Description[nl]": "MS Access (MDB)-importplug-in voor Kexi", "Description[pl]": "Wtyczka importu MS Access (MDB) dla Kexi", "Description[pt]": "'Plugin' de importação do MS Access (MDB) para o Kexi", "Description[pt_BR]": "Plugin de importação do MS Access (MDB) para o Kexi", "Description[sk]": "MS Access (MDB) importný plugin pre Kexi", "Description[sv]": "MS Access (MDB) importinsticksprogram för Kexi", "Description[tr]": "Kexi için Access (MDB) içe aktarma eklentisi", "Description[uk]": "Додаток імпортування даних з MS Access (MDB) для Kexi", "Description[x-test]": "xxMS Access (MDB) import plugin for Kexixx", "EnabledByDefault": true, "Icon": "", "Id": "org.kexi-project.migration.mdb", "License": "LGPL", "MimeTypes": [ "application/vnd.ms-access" ], "Name": "MS Access", "Name[x-test]": "xxMS Accessxx", "ServiceTypes": [ "Kexi/MigrationDriver" ], "Version": "3.2", "Website": "http://kexi-project.org" }, "X-Kexi-FileBased": "true" } diff --git a/src/migration/mysql/keximigrate_mysql.json b/src/migration/mysql/keximigrate_mysql.json index 8a195c0bc..1000120ad 100644 --- a/src/migration/mysql/keximigrate_mysql.json +++ b/src/migration/mysql/keximigrate_mysql.json @@ -1,67 +1,67 @@ { "KPlugin": { "Authors": [ { "Email": "kexi@kde.org", - "Name": "Kexi Team", + "Name": "KEXI Team", "Name[ca@valencia]": "L'equip del Kexi", "Name[ca]": "L'equip del Kexi", "Name[cs]": "Tým Kexi", "Name[de]": "Kexi-Team", "Name[es]": "Equipo de Kexi", "Name[fr]": "L'équipe Kexi", "Name[gl]": "Equipo de Kexi", "Name[it]": "La squadra di Kexi", "Name[nl]": "Het team van Kexi", "Name[pl]": "Zespół Kexi", "Name[pt]": "Equipa do Kexi", "Name[pt_BR]": "Equipe do Kexi", "Name[ru]": "Команда разработчиков Kexi", "Name[sk]": "Tím Kexi", "Name[sv]": "Kexi-gruppen", "Name[tr]": "Kexi Ekibi", "Name[uk]": "Команда Kexi", "Name[x-test]": "xxKexi Teamxx", "Name[zh_CN]": "Kexi 团队" } ], "Category": "", "Dependencies": [ "org.kde.kdb.mysql" ], - "Description": "MySQL database import plugin for Kexi", + "Description": "MySQL database import plugin for KEXI", "Description[ca@valencia]": "Connector d'importació de la base de dades MySQL pel Kexi", "Description[ca]": "Connector d'importació de la base de dades MySQL pel Kexi", "Description[cs]": "Modul Kexi pro import databáze MySQL", "Description[de]": "MySQL-Datenbank-Importmodul für Kexi", "Description[es]": "Complemento de importación de bases de datos MySQL para Kexi", "Description[fr]": "Module d'importation de base de donnée MySQL pour Kexi", "Description[gl]": "Complemento para Kexi de importación de base de datos MySQL.", "Description[it]": "Estensione di importazione banche dati MySQL per Kexi", "Description[nl]": "MySQL database-importplug-in voor Kexi", "Description[pl]": "Wtyczka importu bazy danych MySQL dla Kexi", "Description[pt]": "'Plugin' de importação do MySQL para o Kexi", "Description[pt_BR]": "Plugin de Importação de banco de dados MySQL para o Kexi", "Description[sk]": "MySQL importný plugin pre Kexi", "Description[sv]": "Importinsticksprogram för Kexi av MySQL-databaser", "Description[tr]": "Kexi için MySQL veritabanı içe aktarma eklentisi", "Description[uk]": "Додаток імпортування баз даних з MySQL для Kexi", "Description[x-test]": "xxMySQL database import plugin for Kexixx", "EnabledByDefault": true, "Icon": "", "Id": "org.kexi-project.migration.mysql", "License": "LGPL", "MimeTypes": [], "Name": "MySQL", "Name[x-test]": "xxMySQLxx", "ServiceTypes": [ "Kexi/MigrationDriver" ], "Version": "3.2", "Website": "http://kexi-project.org" }, "X-Kexi-FileBased": "false", "X-Kexi-SupportedSourceDrivers": [ "org.kde.kdb.mysql" ] } diff --git a/src/migration/postgresql/keximigrate_postgresql.json b/src/migration/postgresql/keximigrate_postgresql.json index c51407f42..0ed5ff62f 100644 --- a/src/migration/postgresql/keximigrate_postgresql.json +++ b/src/migration/postgresql/keximigrate_postgresql.json @@ -1,67 +1,67 @@ { "KPlugin": { "Authors": [ { "Email": "kexi@kde.org", - "Name": "Kexi Team", + "Name": "KEXI Team", "Name[ca@valencia]": "L'equip del Kexi", "Name[ca]": "L'equip del Kexi", "Name[cs]": "Tým Kexi", "Name[de]": "Kexi-Team", "Name[es]": "Equipo de Kexi", "Name[fr]": "L'équipe Kexi", "Name[gl]": "Equipo de Kexi", "Name[it]": "La squadra di Kexi", "Name[nl]": "Het team van Kexi", "Name[pl]": "Zespół Kexi", "Name[pt]": "Equipa do Kexi", "Name[pt_BR]": "Equipe do Kexi", "Name[ru]": "Команда разработчиков Kexi", "Name[sk]": "Tím Kexi", "Name[sv]": "Kexi-gruppen", "Name[tr]": "Kexi Ekibi", "Name[uk]": "Команда Kexi", "Name[x-test]": "xxKexi Teamxx", "Name[zh_CN]": "Kexi 团队" } ], "Category": "", "Dependencies": [ "org.kde.kdb.postgresql" ], - "Description": "PostgreSQL database import plugin for Kexi", + "Description": "PostgreSQL database import plugin for KEXI", "Description[ca@valencia]": "Connector d'importació de la base de dades PostgreSQL pel Kexi", "Description[ca]": "Connector d'importació de la base de dades PostgreSQL pel Kexi", "Description[cs]": "Modul Kexi pro import databáze PostgreSQL", "Description[de]": "PostgreSQL-Datenbank-Importmodul für Kexi", "Description[es]": "Complemento de importación de bases de datos PostgreSQL para Kexi", "Description[fr]": "Module d'importation de base de donnée PostgreSQL pour Kexi", "Description[gl]": "Complemento para Kexi de importación de base de datos PostgreSQL.", "Description[it]": "Estensione di importazione banche dati PostgreSQL per Kexi", "Description[nl]": "PostgreSQL database-importplug-in voor Kexi", "Description[pl]": "Wtyczka importu bazy danych PostgreSQL dla Kexi", "Description[pt]": "'Plugin' de importação do PostgreSQL para o Kexi", "Description[pt_BR]": "Plugin de importação de banco de dados PostgreSQL para o Kexi", "Description[sk]": "PostgreSQL importný plugin pre Kexi", "Description[sv]": "Importinsticksprogram för Kexi av PostgreSQL-databaser", "Description[tr]": "Kexi için PostgreSQL veritabanı içe aktarma eklentisi", "Description[uk]": "Додаток імпортування баз даних з PostgreSQL для Kexi", "Description[x-test]": "xxPostgreSQL database import plugin for Kexixx", "EnabledByDefault": true, "Icon": "", "Id": "org.kexi-project.migration.postgresql", "License": "LGPL", "MimeTypes": [], "Name": "PostgreSQL", "Name[x-test]": "xxPostgreSQLxx", "ServiceTypes": [ "Kexi/MigrationDriver" ], "Version": "3.2", "Website": "http://kexi-project.org" }, "X-Kexi-FileBased": "false", "X-Kexi-SupportedSourceDrivers": [ "org.kde.kdb.postgresql" ] } diff --git a/src/migration/tests/keximigratetest.cpp b/src/migration/tests/keximigratetest.cpp index 5fbd32936..cee2189fa 100644 --- a/src/migration/tests/keximigratetest.cpp +++ b/src/migration/tests/keximigratetest.cpp @@ -1,45 +1,45 @@ /* This file is part of the KDE project Copyright (C) 2004 Adam Pigg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 #include #include #include /* This is in no way meant to compile let alone work This is very preliminary and is meant for example only This will be an example program to demonstrate how to import an existing db into a new kexi based db */ int main(int argc, char *argv[]) { QApplication app(argc, argv); - KAboutData aboutData("keximigratetest", xi18n("Kexi Migrate Test"), "2.0", QString(), + KAboutData aboutData("keximigratetest", xi18n("KEXI Migrate Test"), "2.0", QString(), KAboutLicense::GPL_V2); KAboutData::setApplicationData(aboutData); KexiMigration::ImportWizard wizard; wizard.setGeometry(300, 300, 300, 250); wizard.show(); return app.exec(); } diff --git a/src/migration/tsv/keximigrate_tsv.json b/src/migration/tsv/keximigrate_tsv.json index 8ec9aea24..fe15e927a 100644 --- a/src/migration/tsv/keximigrate_tsv.json +++ b/src/migration/tsv/keximigrate_tsv.json @@ -1,64 +1,64 @@ { "KPlugin": { "Authors": [ { "Email": "kexi@kde.org", - "Name": "Kexi Team", + "Name": "KEXI Team", "Name[ca@valencia]": "L'equip del Kexi", "Name[ca]": "L'equip del Kexi", "Name[cs]": "Tým Kexi", "Name[de]": "Kexi-Team", "Name[es]": "Equipo de Kexi", "Name[fr]": "L'équipe Kexi", "Name[gl]": "Equipo de Kexi", "Name[it]": "La squadra di Kexi", "Name[nl]": "Het team van Kexi", "Name[pl]": "Zespół Kexi", "Name[pt]": "Equipa do Kexi", "Name[pt_BR]": "Equipe do Kexi", "Name[ru]": "Команда разработчиков Kexi", "Name[sk]": "Tím Kexi", "Name[sv]": "Kexi-gruppen", "Name[tr]": "Kexi Ekibi", "Name[uk]": "Команда Kexi", "Name[x-test]": "xxKexi Teamxx", "Name[zh_CN]": "Kexi 团队" } ], "Category": "", "Dependencies": [], - "Description": "Tab Separated Values (TSV) file import plugin for Kexi", + "Description": "Tab Separated Values (TSV) file import plugin for KEXI", "Description[ca@valencia]": "Connector d'importació de fitxers amb valors separats per tabulacions (TSV) pel Kexi", "Description[ca]": "Connector d'importació de fitxers amb valors separats per tabulacions (TSV) pel Kexi", "Description[cs]": "Importní modul Kexi pro hodnoty oddělené tabulátorem (Tab Separated Values - TSV)", "Description[de]": "„Durch Tabulator getrennte Werte“-(TSV)-Datei-Importmodul für Kexi", "Description[es]": "Complemento de importación de archivos de valores separados por tabuladores (TSV) para Kexi", - "Description[fr]": "Module d'importation de ficher « séparations par tabulation » pour Kexi", + "Description[fr]": "Module d'importation de ficher « séparations par tabulation » pour Kexi", "Description[gl]": "Complemento para Kexi de importación de ficheiros de valores separados por tabulacións (TSV)", "Description[it]": "Estensione di importazione di file con valori separati da tabulazioni (TSV) per Kexi", "Description[nl]": "Plug-in voor importeren van bestand met Tab Separated Values (TSV) voor Kexi", "Description[pl]": "Wtyczka importu wartości oddzielonych tabulatorami (TSV) dla Kexi", "Description[pt]": "'Plugin' de importação de Valores Separados por Tabulações (TSV) para o Kexi", "Description[pt_BR]": "Plugin de importação de documento com \"Valores Separados por Tabulação\" para o Kexi", "Description[sk]": "Importný plugin pre Kexi pre súbory hodnôt oddelených tabulátorom (TSV)", "Description[sv]": "Importinsticksprogram för Kexi av filer med värden åtskilda av tabulatortecken (TSV)", "Description[tr]": "Kexi için Sekme ile Ayrılmış Değerler (TSV) dosyası içe aktarma eklentisi", "Description[uk]": "Додаток імпортування даних, відокремлених символами табуляції (TSV), для Kexi", "Description[x-test]": "xxTab Separated Values (TSV) file import plugin for Kexixx", "EnabledByDefault": true, "Icon": "", "Id": "org.kexi-project.migration.tsv", "License": "LGPL", "MimeTypes": [ "text/tab-separated-values" ], "Name": "TSV", "Name[x-test]": "xxTSVxx", "ServiceTypes": [ "Kexi/MigrationDriver" ], "Version": "3.2", "Website": "http://kexi-project.org" }, "X-Kexi-FileBased": "true" } diff --git a/src/mobile/main.cpp b/src/mobile/main.cpp index 9fb8be7a4..6af72e081 100644 --- a/src/mobile/main.cpp +++ b/src/mobile/main.cpp @@ -1,39 +1,39 @@ /** This file is part of the KDE project * * Copyright (C) 2011 Adam Pigg * * 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. */ #include #include #include "KexiMobileMainWindow.h" int main(int argc, char** argv) { KAboutData aboutData( "keximobile", "keximobile", - kxi18n("Kexi Mobile"), "0.2", - kxi18n("A mobile optimized version of Kexi from Calligra Suite"), + kxi18n("KEXI Mobile"), "0.2", + kxi18n("A mobile optimized version of KEXI"), KAboutData::License_LGPL, kxi18n("Copyright (c) 2014 Adam Pigg") ); KCmdLineArgs::init( argc, argv, &aboutData ); KApplication app; KexiMobileMainWindow foo; foo.show(); return app.exec(); } diff --git a/src/plugins/forms/kexi_formplugin.desktop b/src/plugins/forms/kexi_formplugin.desktop index 20f25322a..a0617ae35 100644 --- a/src/plugins/forms/kexi_formplugin.desktop +++ b/src/plugins/forms/kexi_formplugin.desktop @@ -1,65 +1,65 @@ [Desktop Entry] Name=Form Name[ca]=Formulari Name[ca@valencia]=Formulari Name[cs]=Formulář Name[de]=Formular Name[en_GB]=Form Name[es]=Formulario Name[fi]=Lomake Name[fr]=Formulaire Name[gl]=Formulario Name[ia]=Forma Name[it]=Modulo Name[ja]=フォーム Name[nb]=Skjema Name[nl]=Formulier Name[pl]=Formularz Name[pt]=Formulário Name[pt_BR]=Formulário Name[sk]=Formulár Name[sv]=Formulär Name[uk]=Форма Name[x-test]=xxFormxx Name[zh_CN]=表单 Comment=Kexi plugin for handling forms Comment[ca]=Connector del Kexi per gestionar formularis Comment[ca@valencia]=Connector del Kexi per gestionar formularis Comment[cs]=Modul Kexi pro práci s formuláři Comment[de]=Kexi-Modul für die Bearbeitung von Formularen Comment[en_GB]=Kexi plugin for handling forms Comment[es]=Complemento de Kexi para manejar formularios Comment[fi]=Kexi-liitännäinen lomakkeiden käsittelyyn Comment[fr]=Module complémentaire pour Kexi pour manipuler des formulaires Comment[gl]=Complemento para Kexi de manexo de formularios. Comment[it]=Estensione per la gestione dei moduli di Kexi Comment[nl]=Kexi-plug-in voor behandeling van formulieren Comment[pl]=Wtyczka Kexi do obsługi formularzy Comment[pt]='Plugin' do Kexi para lidar com formulários Comment[pt_BR]=Plugin do Kexi para trabalhar com formulários Comment[sk]=Kexi plugin na spracovanie formulárov Comment[sv]=Kexi-insticksprogram för att hantera formulär Comment[uk]=Додаток до Kexi для обробки форм Comment[x-test]=xxKexi plugin for handling formsxx Type=Service Icon=form Encoding=UTF-8 X-KDE-Library=kexi_formplugin X-KDE-ServiceTypes=Kexi/Viewer,Kexi/Designer -X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Author=KEXI Team X-KDE-PluginInfo-Email=kexi@kde.org X-KDE-PluginInfo-Name=org.kexi-project.form X-KDE-PluginInfo-Version=3.2 X-KDE-PluginInfo-Website=http://kexi-project.org X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=true X-Kexi-GroupName=Forms X-Kexi-TypeName=form X-Kexi-ServiceTypesInUserMode=Kexi/Viewer X-Kexi-VisibleInProjectNavigator=true X-Kexi-SupportsDataExport=true X-Kexi-SupportsPrinting=true diff --git a/src/plugins/forms/widgets/kexidbautofield.h b/src/plugins/forms/widgets/kexidbautofield.h index fc378f51c..027986270 100644 --- a/src/plugins/forms/widgets/kexidbautofield.h +++ b/src/plugins/forms/widgets/kexidbautofield.h @@ -1,218 +1,218 @@ /* This file is part of the KDE project Copyright (C) 2005 Cedric Pasteur Copyright (C) 2005 Christian Nitschkowski Copyright (C) 2005-2006 Jarosław Staniek 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. */ #ifndef KEXIDBAUTOFIELD_H #define KEXIDBAUTOFIELD_H #include "kexiformutils_export.h" #include #include #include #include #include #include #include class QLabel; -//! Universal "Auto Field" widget for Kexi forms +//! Universal "Auto Field" widget for KEXI forms /*! It acts as a container for most data-aware widgets. */ class KEXIFORMUTILS_EXPORT KexiDBAutoField : public QWidget, public KexiFormDataItemInterface, public KFormDesigner::DesignTimeDynamicChildWidgetHandler, public KFormDesigner::WidgetWithSubpropertiesInterface, public KFormDesigner::FormWidgetInterface { Q_OBJECT //'caption' is uncovered now Q_PROPERTY(QString labelCaption READ caption WRITE setCaption) Q_PROPERTY(QString caption READ caption WRITE setCaption) Q_PROPERTY(QColor foregroundLabelColor READ foregroundLabelColor WRITE setForegroundLabelColor RESET unsetPalette) Q_PROPERTY(QColor backgroundLabelColor READ backgroundLabelColor WRITE setBackgroundLabelColor RESET unsetPalette) Q_PROPERTY(bool autoCaption READ hasAutoCaption WRITE setAutoCaption) Q_PROPERTY(QString dataSource READ dataSource WRITE setDataSource) Q_PROPERTY(QString dataSourcePartClass READ dataSourcePluginId WRITE setDataSourcePluginId) Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) Q_PROPERTY(LabelPosition labelPosition READ labelPosition WRITE setLabelPosition) Q_PROPERTY(WidgetType widgetType READ widgetType WRITE setWidgetType) /*internal, for design time only*/ Q_PROPERTY(int fieldTypeInternal READ fieldTypeInternal WRITE setFieldTypeInternal STORED false) Q_PROPERTY(QString fieldCaptionInternal READ fieldCaptionInternal WRITE setFieldCaptionInternal STORED false) public: enum WidgetType { Auto = 100, Text, Integer, Double, Boolean, Date, Time, DateTime, MultiLineText, ComboBox, Image }; Q_ENUM(WidgetType) enum LabelPosition { Left = 300, Top, NoLabel }; Q_ENUM(LabelPosition) KexiDBAutoField(const QString &text, WidgetType type, LabelPosition pos, QWidget *parent = 0); explicit KexiDBAutoField(QWidget *parent = 0, LabelPosition pos = Left); virtual ~KexiDBAutoField(); inline QString dataSource() const { return KexiFormDataItemInterface::dataSource(); } inline QString dataSourcePluginId() const { return KexiFormDataItemInterface::dataSourcePluginId(); } virtual void setDataSource(const QString &ds); virtual void setDataSourcePluginId(const QString &pluginId) { KexiFormDataItemInterface::setDataSourcePluginId(pluginId); } void setColumnInfo(KDbConnection *conn, KDbQueryColumnInfo* cinfo) override; virtual void setInvalidState(const QString& text); virtual bool isReadOnly() const; virtual void setReadOnly(bool readOnly); virtual QVariant value(); virtual bool valueIsNull(); virtual bool valueIsEmpty(); virtual bool valueIsValid(); virtual bool valueChanged(); virtual void clear(); //! Reimplemented to also install \a listenter for internal editor virtual void installListener(KexiDataItemChangesListener* listener); WidgetType widgetType() const; void setWidgetType(WidgetType type); LabelPosition labelPosition() const; virtual void setLabelPosition(LabelPosition position); QString caption() const; void setCaption(const QString &caption); bool hasAutoCaption() const; void setAutoCaption(bool autoCaption); /*! If \a displayDefaultValue is true, the value set by KexiDataItemInterface::setValue() is displayed in a special way. Used by KexiFormDataProvider::fillDataItems(). \a widget is equal to 'this'. Reimplemented after KexiFormDataItemInterface. */ virtual void setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue); QWidget* editor() const; QLabel* label() const; virtual bool cursorAtStart(); virtual bool cursorAtEnd(); static WidgetType widgetTypeForFieldType(KDbField::Type type); /*! On design time it is not possible to pass a reference to KDbField object so we're just providing field type. Only used when widget type is Auto. @internal */ void setFieldTypeInternal(int kexiDBFieldType); /*! On design time it is not possible to pass a reference to KDbField object so we're just providing field caption. Only used when widget type is Auto. @internal */ void setFieldCaptionInternal(const QString& text); /*! @internal */ int fieldTypeInternal() const; /*! @internal */ QString fieldCaptionInternal() const; virtual QSize sizeHint() const; virtual void setFocusPolicy(Qt::FocusPolicy policy); //! Reimplemented to return internal editor's color. QColor paletteForegroundColor() const; //! Reimplemented to set internal editor's color. void setPaletteForegroundColor(const QColor & color); //! Reimplemented to return internal editor's color. QColor paletteBackgroundColor() const; //! Reimplemented to set internal editor's color. virtual void setPaletteBackgroundColor(const QColor & color); //! \return label's foreground color QColor foregroundLabelColor() const; //! Sets label's foreground color virtual void setForegroundLabelColor(const QColor & color); //! \return label's background color QColor backgroundLabelColor() const; //! Sets label's background color virtual void setBackgroundLabelColor(const QColor & color); //! Reimplemented to accept subproperties. @see KFormDesigner::WidgetWithSubpropertiesInterface virtual QVariant property(const char * name) const; //! Reimplemented to accept subproperties. @see KFormDesigner::WidgetWithSubpropertiesInterface virtual bool setProperty(const char * name, const QVariant & value); /*! Called by the top-level form on key press event to consume widget-specific shortcuts. */ virtual bool keyPressed(QKeyEvent *ke); public Q_SLOTS: virtual void unsetPalette(); protected Q_SLOTS: virtual void paletteChange(const QPalette& oldPal); //! Implemented for KexiDataItemInterface virtual void moveCursorToEnd(); //! Implemented for KexiDataItemInterface virtual void moveCursorToStart(); //! Implemented for KexiDataItemInterface virtual void selectAll(); protected: virtual void setValueInternal(const QVariant&add, bool removeOld); void init(const QString &text, WidgetType type, LabelPosition pos); virtual void createEditor(); void changeText(const QString &text, bool beautify = true); void updateInformationAboutUnboundField(); //! internal editor can be created too late, so certain properties should be copied void copyPropertiesToEditor(); virtual bool eventFilter(QObject *o, QEvent *e); //! Used by @ref setLabelPositionInternal(LabelPosition) void setLabelPositionInternal(LabelPosition position, bool noLabel); //! Used by KexiDBAutoField::setColumnInfo() and KexiDBComboBox::setColumnInfo() void setColumnInfoInternal(KDbQueryColumnInfo *cinfo, KDbQueryColumnInfo *visibleColumnInfo); private: class Private; Private * const d; }; #endif diff --git a/src/plugins/forms/widgets/main/kexiforms_mainwidgetsplugin.json b/src/plugins/forms/widgets/main/kexiforms_mainwidgetsplugin.json index c85eb56fd..80bb2b999 100644 --- a/src/plugins/forms/widgets/main/kexiforms_mainwidgetsplugin.json +++ b/src/plugins/forms/widgets/main/kexiforms_mainwidgetsplugin.json @@ -1,75 +1,75 @@ { "KPlugin": { "Authors": [ { "Email": "kexi@kde.org", - "Name": "Kexi Team", + "Name": "KEXI Team", "Name[ca@valencia]": "L'equip del Kexi", "Name[ca]": "L'equip del Kexi", "Name[cs]": "Tým Kexi", "Name[de]": "Kexi-Team", "Name[es]": "Equipo de Kexi", "Name[fr]": "L'équipe Kexi", "Name[gl]": "Equipo de Kexi", "Name[it]": "La squadra di Kexi", "Name[nl]": "Het team van Kexi", "Name[pl]": "Zespół Kexi", "Name[pt]": "Equipa do Kexi", "Name[pt_BR]": "Equipe do Kexi", "Name[ru]": "Команда разработчиков Kexi", "Name[sk]": "Tím Kexi", "Name[sv]": "Kexi-gruppen", "Name[tr]": "Kexi Ekibi", "Name[uk]": "Команда Kexi", "Name[x-test]": "xxKexi Teamxx", "Name[zh_CN]": "Kexi 团队" } ], "Category": "", "Dependencies": [], - "Description": "Kexi plugin providing database form widgets", + "Description": "KEXI plugin providing database form widgets", "Description[ca@valencia]": "Connector del Kexi que proporciona estris de formularis de bases de dades", "Description[ca]": "Connector del Kexi que proporciona estris de formularis de bases de dades", "Description[de]": "Kexi-Modul, das Datenbankbedienelemente bereitstellt", "Description[es]": "Complemento de Kexi que proporciona elementos gráficos de formulario para bases de datos", "Description[fr]": "Module complémentaire Kexi fournissant des composants de formulaires pour bases de données", "Description[gl]": "Complemento de Kexi que fornece trebellos de base de datos para formularios.", "Description[it]": "Estensione che fornisce gli oggetti dei moduli della banca dati per Kexi", "Description[nl]": "Kexi-plug-in levert formulierwidgets voor database", "Description[pl]": "Wtyczka Kexi dostarczająca elmenty interfejsu formularzy", "Description[pt]": "'Plugin' do Kexi que oferece elementos gráficos de formulários das bases de dados", "Description[pt_BR]": "Plugin Kexi que fornece widgets de formulário de banco de dados", "Description[sk]": "Kexi plugin poskytujúci widgety databázových formulárov", "Description[sv]": "Kexi-insticksprogram som tillhandahåller komponenter för databasformulär", "Description[tr]": "Kexi eklentisi, veri tabanı programcığı sağlar", "Description[uk]": "Додаток до Kexi, що забезпечує роботу віджетів форм бази даних", "Description[x-test]": "xxKexi plugin providing database form widgetsxx", "EnabledByDefault": true, "Icon": "form", "Id": "org.kexi-project.form.widgets.main", "License": "LGPL", "Name": "Main form widgets", "Name[ca@valencia]": "Estris de formularis principals", "Name[ca]": "Estris de formularis principals", "Name[de]": "Haupt-Bedienungselemente", "Name[es]": "Elementos gráficos del formulario principal", "Name[fr]": "Composants de formulaires principaux", "Name[gl]": "Trebellos do formulario principal", "Name[it]": "Oggetti del modulo principale", "Name[nl]": "Hoofdformulierwidgets", "Name[pl]": "Elementy interfejsu głównego formularza", "Name[pt]": "Elementos principais do formulário", "Name[pt_BR]": "Widgets do formulário principal", "Name[sk]": "Widgety hlavného formulára", "Name[sv]": "Huvudformulärets komponenter", "Name[tr]": "Ana form programcıkları", "Name[uk]": "Віджети головної форми", "Name[x-test]": "xxMain form widgetsxx", "ServiceTypes": [ "Kexi/FormWidget" ], "Version": "3.2", "Website": "http://kexi-project.org" }, "X-Kexi-FormWidgetsFactoryGroup": "" } diff --git a/src/plugins/forms/widgets/mapbrowser/kexiforms_mapwidgetplugin.desktop b/src/plugins/forms/widgets/mapbrowser/kexiforms_mapwidgetplugin.desktop index a777d5d51..2b2dd5f71 100644 --- a/src/plugins/forms/widgets/mapbrowser/kexiforms_mapwidgetplugin.desktop +++ b/src/plugins/forms/widgets/mapbrowser/kexiforms_mapwidgetplugin.desktop @@ -1,54 +1,54 @@ [Desktop Entry] Name=Map Widget Name[ca]=Estris de mapes Name[ca@valencia]=Estris de mapes Name[de]=Karten-Bedienelement Name[en_GB]=Map Widget Name[es]=Elemento gráfico de mapas Name[fi]=Karttaelementti Name[fr]=Composants carte Name[gl]=Trebello de mapa Name[it]=Oggetto mappa Name[nl]=Kaartwidget Name[pl]=Element interfejsu mapy Name[pt]=Elemento de Mapa Name[pt_BR]=Elemento de mapa Name[sk]=Widget Mapa Name[sv]=Kartkomponenter Name[uk]=Віджет карти Name[x-test]=xxMap Widgetxx Comment=Kexi plugin providing map browser form widget Comment[ca]=Connector del Kexi que proporciona estris de formularis de navegació de mapes Comment[ca@valencia]=Connector del Kexi que proporciona estris de formularis de navegació de mapes Comment[de]=Kexi-Modul, das ein Karten-Bedienelement bereitstellt Comment[en_GB]=Kexi plugin providing map browser form widget Comment[es]=Complemento de Kexi que proporciona un elemento gráfico de exploración de mapas para los formularios Comment[fi]=Kexi-liitännäinen, joka tarjoaa karttaselaimen lomake-elementin Comment[fr]=Module complémentaire Kexi fournissant des composants de formulaires navigateur de carte Comment[gl]=Complemento para Kexi que fornece un trebello de navegador de mapa para formularios. Comment[it]=Estensione che fornisce un oggetto del modulo di navigazione mappe di Kexi Comment[nl]=Kexi-plug-in levert formulierwidget voor kaartenbrowser Comment[pl]=Wtyczka Kexi dostarczająca formularze przeglądania map Comment[pt]='Plugin' do Kexi que oferece um elemento gráfico de formulários de navegação em mapas Comment[pt_BR]=Plugin do Kexi que oferece um elemento gráfico de formulários de navegação em mapas Comment[sk]=Kexi plugin poskytujúci prehliadač máp z widgetu Comment[sv]=Kexi-insticksprogram som tillhandahåller formulärkomponent med kartbläddrare Comment[uk]=Додаток до Kexi, що забезпечує роботу форми навігатора картою Comment[x-test]=xxKexi plugin providing map browser form widgetxx Type=Service Icon=form Encoding=UTF-8 X-KDE-Library=kexiforms_mapwidgetplugin X-KDE-ServiceTypes=Kexi/FormWidgets -X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Author=KEXI Team X-KDE-PluginInfo-Email=kexi@kde.org X-KDE-PluginInfo-Name=org.kexi-project.form.widgets.map X-KDE-PluginInfo-Version=3.2 X-KDE-PluginInfo-Website=http://kexi-project.org X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=true X-Kexi-FormWidgetsFactoryGroup= diff --git a/src/plugins/forms/widgets/webbrowser/kexiforms_webbrowserwidgetplugin.json b/src/plugins/forms/widgets/webbrowser/kexiforms_webbrowserwidgetplugin.json index b9d0c30e0..f25b0fb61 100644 --- a/src/plugins/forms/widgets/webbrowser/kexiforms_webbrowserwidgetplugin.json +++ b/src/plugins/forms/widgets/webbrowser/kexiforms_webbrowserwidgetplugin.json @@ -1,76 +1,76 @@ { "KPlugin": { "Authors": [ { "Email": "kexi@kde.org", - "Name": "Kexi Team", + "Name": "KEXI Team", "Name[ca@valencia]": "L'equip del Kexi", "Name[ca]": "L'equip del Kexi", "Name[cs]": "Tým Kexi", "Name[de]": "Kexi-Team", "Name[es]": "Equipo de Kexi", "Name[fr]": "L'équipe Kexi", "Name[gl]": "Equipo de Kexi", "Name[it]": "La squadra di Kexi", "Name[nl]": "Het team van Kexi", "Name[pl]": "Zespół Kexi", "Name[pt]": "Equipa do Kexi", "Name[pt_BR]": "Equipe do Kexi", "Name[ru]": "Команда разработчиков Kexi", "Name[sk]": "Tím Kexi", "Name[sv]": "Kexi-gruppen", "Name[tr]": "Kexi Ekibi", "Name[uk]": "Команда Kexi", "Name[x-test]": "xxKexi Teamxx", "Name[zh_CN]": "Kexi 团队" } ], "Category": "", "Dependencies": [], - "Description": "Kexi plugin providing web browser form widget", + "Description": "KEXI plugin providing web browser form widget", "Description[ca@valencia]": "Connector del Kexi que proporciona estris de formularis de navegació web", "Description[ca]": "Connector del Kexi que proporciona estris de formularis de navegació web", "Description[de]": "Kexi-Modul, das ein Webbrowser-Bedienelement bereitstellt", "Description[es]": "Complemento de Kexi que proporciona un elemento gráfico de formulario para navegación web", "Description[fr]": "Module complémentaire Kexi fournissant des composants de formulaires navigateur web", "Description[gl]": "Complemento para Kexi que fornece un trebello de navegador web para formularios.", "Description[it]": "Estensione che fornisce l'oggetto del browser web per Kexi", "Description[nl]": "Kexi-plug-in levert formulierwidget voor webbrowser", "Description[pl]": "Wtyczka Kexi dostarczająca elmenty interfejsu przeglądarki sieci", "Description[pt]": "'Plugin' do Kexi que oferece um elemento gráfico de navegação Web", "Description[pt_BR]": "Kexi plugin que fornece widget de formulário de navegador web ", "Description[sk]": "Kexi plugin poskytujúci webový prehliadač z widgetu", "Description[sv]": "Kexi-insticksprogram som tillhandahåller formulärkomponent med webbläsare", "Description[tr]": "Kexi eklentisi web tarayıcı programcığı sağlar", "Description[uk]": "Додаток до Kexi, що забезпечує роботу форми віджета навігатора інтернетом", "Description[x-test]": "xxKexi plugin providing web browser form widgetxx", "EnabledByDefault": true, "Icon": "kexiform-web-browser", "Id": "org.kexi-project.form.widgets.web-browser", "License": "LGPL", "Name": "Web browser widget", "Name[ca@valencia]": "Estri navegador web", "Name[ca]": "Estri navegador web", "Name[cs]": "Widget webového prohlížeče", "Name[de]": "Webbrowser-Bedienelement", "Name[es]": "Elemento gráfico de navegación web", "Name[fr]": "Composant de navigation web", "Name[gl]": "Trebello de navegador web", "Name[it]": "Oggetto del browser web", "Name[nl]": "Webbrowserwidget", "Name[pl]": "Elementy interfejsu przeglądarki sieci", "Name[pt]": "Elemento de navegação Web", "Name[pt_BR]": "Widget do navegador Web", "Name[sk]": "Widget Webový prehliadač", "Name[sv]": "Webbläsarkomponent", "Name[tr]": "Web tarayıcı programcığı", "Name[uk]": "Віджет перегляду інтернету", "Name[x-test]": "xxWeb browser widgetxx", "ServiceTypes": [ "Kexi/FormWidget" ], "Version": "3.2", "Website": "http://kexi-project.org" }, "X-Kexi-FormWidgetsFactoryGroup": "" } diff --git a/src/plugins/importexport/csv/kexi_csvimportexportplugin.desktop b/src/plugins/importexport/csv/kexi_csvimportexportplugin.desktop index e4647e75d..7ff7a9ddc 100644 --- a/src/plugins/importexport/csv/kexi_csvimportexportplugin.desktop +++ b/src/plugins/importexport/csv/kexi_csvimportexportplugin.desktop @@ -1,62 +1,62 @@ [Desktop Entry] Name=CSV import/export Name[ca]=Importació/exportació de CSV Name[ca@valencia]=Importació/exportació de CSV Name[cs]=Import/export CSV Name[de]=CSV-Import/Export Name[en_GB]=CSV import/export Name[es]=Importar/exportar CSV Name[fi]=CSV-tuonti/vienti -Name[fr]=Importation / exportation CSV +Name[fr]=Importation / exportation CSV Name[gl]=Importar ou exportar CSV Name[it]=Importazione/esportazione CSV Name[nl]=CSV importeren/exporteren Name[pl]=Importowanie/eksportowanie CSV Name[pt]=Importação/exportação de CSV Name[pt_BR]=Importação/exportação de CSV Name[sk]=CSV import/export Name[sv]=CSV-import/export Name[uk]=Імпортування і експортування CSV Name[x-test]=xxCSV import/exportxx Name[zh_CN]=CSV 导入/导出 Comment=Kexi Plugin for CSV data import/export Comment[ca]=Connector del Kexi d'importació/exportació de CSV Comment[ca@valencia]=Connector del Kexi d'importació/exportació de CSV Comment[cs]=Modul Kexi pro import a export dat CSV Comment[de]=Kexi-Modul für CSV-Daten-Import/Export Comment[en_GB]=Kexi Plugin for CSV data import/export Comment[es]=Complemento de Kexi para importar y exportar datos CSV Comment[fi]=Kexi-liitännäinen CSV-tietojen tuontiin ja vientiin -Comment[fr]=Module Kexi pour l'importation / exportation de données CSV +Comment[fr]=Module Kexi pour l'importation / exportation de données CSV Comment[gl]=Complemento para Kexi de importación e exportación de datos CSV. Comment[it]=Estensione di importazione ed esportazione di dati CSV di Kexi Comment[nl]=Kexi-plug-in voor importeren/exporteren van CSV-gegevens Comment[pl]=Wtyczka importu/eksportu danych CSV dla Kexi Comment[pt]='Plugin' do Kexi para a importação/exportação de dados em CSV Comment[pt_BR]=Plugin do Kexi para importação/exportação de dados CSV Comment[sk]=Kexi Plugin na import/export CSV dát Comment[sv]=Kexi insticksprogram för import/export av CSV-data Comment[uk]=Додаток до Kexi для імпортування та експортування даних у форматі CSV Comment[x-test]=xxKexi Plugin for CSV data import/exportxx Type=Service Icon=document-import Encoding=UTF-8 X-KDE-Library=kexi_csvimportexportplugin X-KDE-ServiceTypes=Kexi/Internal -X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Author=KEXI Team X-KDE-PluginInfo-Email=kexi@kde.org X-KDE-PluginInfo-Name=org.kexi-project.importexport.csv X-KDE-PluginInfo-Version=3.2 X-KDE-PluginInfo-Website=http://kexi-project.org X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=true X-Kexi-GroupName= X-Kexi-TypeName=csvimportexport X-Kexi-ServiceTypesInUserMode= X-Kexi-VisibleInProjectNavigator=false X-Kexi-SupportsDataExport=false X-Kexi-SupportsPrinting=false diff --git a/src/plugins/migration/kexi_migrationplugin.desktop b/src/plugins/migration/kexi_migrationplugin.desktop index b9ab3b5c1..a2a7aa2cc 100644 --- a/src/plugins/migration/kexi_migrationplugin.desktop +++ b/src/plugins/migration/kexi_migrationplugin.desktop @@ -1,59 +1,59 @@ [Desktop Entry] Name=Migration Name[ca]=Migració Name[ca@valencia]=Migració Name[cs]=Migrace Name[de]=Migration Name[en_GB]=Migration Name[es]=Migración Name[fr]=Migration Name[gl]=Migración Name[it]=Migrazione Name[nl]=Migratie Name[pl]=Przenoszenie Name[pt]=Migração Name[pt_BR]=Migration Name[sk]=Migrácia Name[sv]=Konvertering Name[uk]=Перенесення Name[x-test]=xxMigrationxx Comment=Kexi plugin for handling database migration Comment[ca]=Connector del Kexi per gestionar migracions de bases de dades Comment[ca@valencia]=Connector del Kexi per gestionar migracions de bases de dades Comment[cs]=Modul Kexi pro provádění migrace databáze Comment[de]=Kexi-Modul für die Migration von Datenbanken Comment[en_GB]=Kexi plugin for handling database migration Comment[es]=Complemento de Kexi para manejar la migración de bases de datos Comment[fr]=Module Kexi pour gérer la migration de base de données Comment[gl]=Complemento para Kexi de manexo de migracións de base de datos. Comment[it]=Estensione di Kexi per gestire la migrazione della banca dati Comment[nl]=Kexi-plug-in voor behandeling van migratie van een database Comment[pl]=Wtyczka Kexi do obsługi przenoszenia baz danych Comment[pt]='Plugin' do Kexi para lidar com tabelas Comment[pt_BR]=Plugin do Kexi para gerenciar migração de banco de dados Comment[sk]=Kexi plugin na spracovanie migrácie databáz Comment[sv]=Kexi-insticksprogram för att hantera databaskonvertering Comment[uk]=Додаток до Kexi для перенесення баз даних Comment[x-test]=xxKexi plugin for handling database migrationxx Type=Service Icon=database-import Encoding=UTF-8 X-KDE-Library=kexi_migrationplugin X-KDE-ServiceTypes=Kexi/Internal -X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Author=KEXI Team X-KDE-PluginInfo-Email=kexi@kde.org X-KDE-PluginInfo-Name=org.kexi-project.migration X-KDE-PluginInfo-Version=3.2 X-KDE-PluginInfo-Website=http://kexi-project.org X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=true X-Kexi-GroupName= X-Kexi-TypeName=migration X-Kexi-ServiceTypesInUserMode= X-Kexi-VisibleInProjectNavigator=false X-Kexi-SupportsDataExport=false X-Kexi-SupportsPrinting=false diff --git a/src/plugins/queries/kexi_queryplugin.desktop b/src/plugins/queries/kexi_queryplugin.desktop index f19aaed1c..013774396 100644 --- a/src/plugins/queries/kexi_queryplugin.desktop +++ b/src/plugins/queries/kexi_queryplugin.desktop @@ -1,65 +1,65 @@ [Desktop Entry] Name=Query Name[ca]=Consulta Name[ca@valencia]=Consulta Name[cs]=Dotaz Name[de]=Abfrage Name[en_GB]=Query Name[es]=Consulta Name[fi]=Kysely Name[fr]=Requête Name[gl]=Consulta Name[ia]=Requesta Name[it]=Interrogazione Name[ja]=クエリ Name[nb]=Spørring Name[nl]=Query Name[pl]=Zapytanie Name[pt]=Procura Name[pt_BR]=Consulta Name[sk]=Otázka Name[sv]=Fråga Name[uk]=Запит Name[x-test]=xxQueryxx Name[zh_CN]=查询 Comment=Kexi plugin for handling queries Comment[ca]=Connector del Kexi per gestionar consultes Comment[ca@valencia]=Connector del Kexi per gestionar consultes Comment[cs]=Modul Kexi pro provádění dotazů Comment[de]=Kexi-Modul für die Bearbeitung von Abfragen Comment[en_GB]=Kexi plugin for handling queries Comment[es]=Complemento de Kexi para manejar consultas Comment[fi]=Kexi-liitännäinen kyselyiden käsittelyyn Comment[fr]=Module Kexi pour gérer les requêtes Comment[gl]=Complemento para Kexi de manexo de consultas. Comment[it]=Estensione per gestire le query di Kexi Comment[nl]=Kexi-plug-in voor behandeling van queries Comment[pl]=Wtyczka Kexi do obsługi zapytań Comment[pt]='Plugin' do Kexi para lidar com pesquisas Comment[pt_BR]=Plugin do Kexi para lidar com consultas Comment[sk]=Kexi plugin na spracovanie dotazov Comment[sv]=Kexi-insticksprogram för att hantera förfrågningar Comment[uk]=Додаток до Kexi для обробки запитів Comment[x-test]=xxKexi plugin for handling queriesxx Type=Service Icon=query Encoding=UTF-8 X-KDE-Library=kexi_queryplugin X-KDE-ServiceTypes=Kexi/Viewer,Kexi/Designer,Kexi/Editor -X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Author=KEXI Team X-KDE-PluginInfo-Email=kexi@kde.org X-KDE-PluginInfo-Name=org.kexi-project.query X-KDE-PluginInfo-Version=3.2 X-KDE-PluginInfo-Website=http://kexi-project.org X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=true X-Kexi-GroupName=Queries X-Kexi-TypeName=query X-Kexi-ServiceTypesInUserMode=Kexi/Viewer X-Kexi-VisibleInProjectNavigator=true X-Kexi-SupportsDataExport=true X-Kexi-SupportsPrinting=true diff --git a/src/plugins/reports/kexi_reportplugin.desktop b/src/plugins/reports/kexi_reportplugin.desktop index 527dadff9..5a15261fb 100644 --- a/src/plugins/reports/kexi_reportplugin.desktop +++ b/src/plugins/reports/kexi_reportplugin.desktop @@ -1,64 +1,64 @@ [Desktop Entry] Name=Report Name[ca]=Informe Name[ca@valencia]=Informe Name[cs]=Hlášení Name[de]=Bericht Name[en_GB]=Report Name[es]=Informe Name[fi]=Raportti Name[fr]=Rapport Name[gl]=Informe Name[it]=Rapporto Name[ja]=レポート Name[nb]=Rapport Name[nl]=Rapport Name[pl]=Raport Name[pt]=Relatório Name[pt_BR]=Relatório Name[sk]=Výkaz Name[sv]=Rapport Name[uk]=Звіт Name[x-test]=xxReportxx Name[zh_CN]=报表 Comment=Kexi plugin for handling reports Comment[ca]=Connector del Kexi per gestionar informes Comment[ca@valencia]=Connector del Kexi per gestionar informes Comment[cs]=Modul Kexi pro provádění hlášení Comment[de]=Kexi-Modul für die Bearbeitung von Berichten Comment[en_GB]=Kexi plugin for handling reports Comment[es]=Complemento de Kexi para manejar informes Comment[fi]=Kexi-liitännäinen raporttien käsittelyyn Comment[fr]=Module Kexi pour gérer les rapports Comment[gl]=Complemento para Kexi de manexo de informes. Comment[it]=Estensione per gestire i rapporti di Kexi Comment[nl]=Kexi-plug-in voor behandeling van rapporten Comment[pl]=Wtyczka Kexi do obsługi raportów Comment[pt]='Plugin' do Kexi para lidar com relatórios Comment[pt_BR]=Plugin do Kexi para trabalhar com relatórios Comment[sk]=Kexi plugin na spracovanie správ Comment[sv]=Kexi-insticksprogram för att hantera rapporter Comment[uk]=Додаток до Kexi для обробки звітів Comment[x-test]=xxKexi plugin for handling reportsxx Type=Service Icon=report Encoding=UTF-8 X-KDE-Library=kexi_reportplugin X-KDE-ServiceTypes=Kexi/Viewer,Kexi/Designer -X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Author=KEXI Team X-KDE-PluginInfo-Email=kexi@kde.org X-KDE-PluginInfo-Name=org.kexi-project.report X-KDE-PluginInfo-Version=3.2 X-KDE-PluginInfo-Website=http://kexi-project.org X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=true X-Kexi-GroupName=Reports X-Kexi-TypeName=report X-Kexi-ServiceTypesInUserMode=Kexi/Viewer X-Kexi-VisibleInProjectNavigator=true X-Kexi-SupportsDataExport=false X-Kexi-SupportsPrinting=false diff --git a/src/plugins/reports/kexireportdesignview.cpp b/src/plugins/reports/kexireportdesignview.cpp index 5a6c1d3d5..c62eb93bb 100644 --- a/src/plugins/reports/kexireportdesignview.cpp +++ b/src/plugins/reports/kexireportdesignview.cpp @@ -1,246 +1,246 @@ /* * Kexi Report Plugin * Copyright (C) 2007-2009 by Adam Pigg * Copyright (C) 2011-2017 Jarosław Staniek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "kexireportdesignview.h" #include #include #include "kexisourceselector.h" #include #include #include #include #include #include #include #include KexiReportDesignView::KexiReportDesignView(QWidget *parent, KexiSourceSelector *s) : KexiView(parent) { m_scrollArea = new QScrollArea(this); layout()->addWidget(m_scrollArea); m_sourceSelector = s; m_reportDesigner = 0; m_editCutAction = KStandardAction::cut(this); m_editCutAction->setProperty("iconOnly", true); m_editCopyAction = KStandardAction::copy(this); m_editCopyAction->setProperty("iconOnly", true); m_editPasteAction = KStandardAction::paste(this); m_editPasteAction->setProperty("iconOnly", true); const KGuiItem del = KStandardGuiItem::del(); m_editDeleteAction = new QAction(del.icon(), del.text(), this); m_editDeleteAction->setObjectName("editdelete"); m_editDeleteAction->setToolTip(del.toolTip()); m_editDeleteAction->setWhatsThis(del.whatsThis()); m_editDeleteAction->setProperty("iconOnly", true); m_editSectionAction = new QAction(xi18n("Edit Sections"), this); m_editSectionAction->setObjectName("sectionedit"); m_itemRaiseAction = new QAction(koIcon("object-order-front"), xi18n("Raise"), this); m_itemRaiseAction->setObjectName("itemraise"); m_itemLowerAction = new QAction(koIcon("object-order-back"), xi18n("Lower"), this); m_itemLowerAction->setObjectName("itemlower"); QList al; QAction *sep = new QAction(QString(), this); sep->setSeparator(true); al << m_editCutAction << m_editCopyAction << m_editPasteAction << m_editDeleteAction << sep << m_editSectionAction << sep << m_itemLowerAction << m_itemRaiseAction; setViewActions(al); } KexiReportDesignView::~KexiReportDesignView() { } KPropertySet *KexiReportDesignView::propertySet() { return m_reportDesigner->selectedItemPropertySet(); } void KexiReportDesignView::slotDesignerPropertySetChanged() { propertySetReloaded(true); propertySetSwitched(); } KDbObject* KexiReportDesignView::storeNewData(const KDbObject& object, KexiView::StoreNewDataOptions options, bool *cancel) { KDbObject *s = KexiView::storeNewData(object, options, cancel); if (!s || *cancel) { delete s; return 0; } qDebug() << "new id:" << s->id(); if (!storeData()) { //failure: remove object's object data to avoid garbage KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); conn->removeObject(s->id()); delete s; return 0; } return s; } tristate KexiReportDesignView::storeData(bool dontAsk) { Q_UNUSED(dontAsk); QDomDocument doc("kexireport"); QDomElement root = doc.createElement("kexireport"); QDomElement conndata = connectionData(); if (conndata.isNull()) qDebug() << "Null conn data!"; root.appendChild(m_reportDesigner->document()); root.appendChild(conndata); doc.appendChild(root); QString src = doc.toString(); qDebug() << src; if (storeDataBlock(src, "layout")) { qDebug() << "Saved OK"; setDirty(false); return true; } qDebug() << "NOT Saved OK"; return false; } tristate KexiReportDesignView::beforeSwitchTo(Kexi::ViewMode mode, bool *dontStore) { qDebug() << mode; *dontStore = true; if (m_reportDesigner && mode == Kexi::DataViewMode) { qDebug() << "Saving temp data"; tempData()->reportDefinition = m_reportDesigner->document(); qDebug() << m_reportDesigner->document().toDocument().toString(); tempData()->reportSchemaChangedInPreviousView = true; } return true; } tristate KexiReportDesignView::afterSwitchFrom(Kexi::ViewMode mode) { Q_UNUSED(mode); if (tempData()->reportDefinition.isNull()) { m_reportDesigner = new KReportDesigner(this); } else { if (m_reportDesigner) { m_scrollArea->takeWidget(); delete m_reportDesigner; m_reportDesigner = 0; } m_reportDesigner = new KReportDesigner(this, tempData()->reportDefinition); setConnectionData(tempData()->connectionDefinition); m_reportDesigner->setScriptSource(qobject_cast(part())); } connect(m_reportDesigner, SIGNAL(itemInserted(QString)), this, SIGNAL(itemInserted(QString))); m_scrollArea->setWidget(m_reportDesigner); connect(m_reportDesigner, SIGNAL(propertySetChanged()), this, SLOT(slotDesignerPropertySetChanged())); connect(m_reportDesigner, SIGNAL(dirty()), this, SLOT(setDirty())); //Added default keyboard shortcuts for the actions QShortcut *cutShortcut = new QShortcut(QKeySequence(QKeySequence::Cut), m_reportDesigner); QShortcut *copyShortcut = new QShortcut(QKeySequence(QKeySequence::Copy), m_reportDesigner); QShortcut *pasteShortcut = new QShortcut(QKeySequence(QKeySequence::Paste), m_reportDesigner); QShortcut *deleteShortcut = new QShortcut(QKeySequence(QKeySequence::Delete), m_reportDesigner); connect(cutShortcut, SIGNAL(activated()), m_reportDesigner, SLOT(slotEditCut())); connect(copyShortcut, SIGNAL(activated()), m_reportDesigner, SLOT(slotEditCopy())); connect(pasteShortcut, SIGNAL(activated()), m_reportDesigner, SLOT(slotEditPaste())); connect(deleteShortcut, SIGNAL(activated()), m_reportDesigner, SLOT(slotEditDelete())); //Edit Actions connect(m_editCutAction, SIGNAL(triggered()), m_reportDesigner, SLOT(slotEditCut())); connect(m_editCopyAction, SIGNAL(triggered()), m_reportDesigner, SLOT(slotEditCopy())); connect(m_editPasteAction, SIGNAL(triggered()), m_reportDesigner, SLOT(slotEditPaste())); connect(m_editDeleteAction, SIGNAL(triggered()), m_reportDesigner, SLOT(slotEditDelete())); connect(m_editSectionAction, SIGNAL(triggered()), m_reportDesigner, SLOT(slotSectionEditor())); //Raise/Lower connect(m_itemRaiseAction, SIGNAL(triggered()), m_reportDesigner, SLOT(slotRaiseSelected())); connect(m_itemLowerAction, SIGNAL(triggered()), m_reportDesigner, SLOT(slotLowerSelected())); return true; } KexiReportPartTempData* KexiReportDesignView::tempData() const { return static_cast(window()->data()); } void KexiReportDesignView::slotDataSourceChanged() { if (m_sourceSelector->isSelectionValid()) { m_reportDesigner->setDataSource(new KexiDBReportDataSource( m_sourceSelector->selectedName(), m_sourceSelector->selectedPluginId(), tempData())); tempData()->connectionDefinition = connectionData(); } else { m_reportDesigner->setDataSource(nullptr); tempData()->connectionDefinition = QDomElement(); } setDirty(true); } void KexiReportDesignView::triggerAction(const QString &action) { m_reportDesigner->slotItem(action); } QDomElement KexiReportDesignView::connectionData() const { QDomDocument dd; QDomElement conndata = dd.createElement("connection"); conndata.setAttribute("type", "internal"); // for backward compatibility, currently always - // internal, we used to have "external" in old Kexi + // internal, we used to have "external" in old KEXI conndata.setAttribute("source", m_sourceSelector->selectedName()); conndata.setAttribute("class", m_sourceSelector->selectedPluginId()); return conndata; } void KexiReportDesignView::setConnectionData(const QDomElement &c) { qDebug() << c; if (c.attribute("type") == "internal") { QString sourceClass(c.attribute("class")); if (sourceClass != "org.kexi-project.table" && sourceClass != "org.kexi-project.query") { sourceClass.clear(); // KexiDataSourceComboBox will try to find table, then query } m_sourceSelector->setDataSource(sourceClass, c.attribute("source")); slotDataSourceChanged(); } } diff --git a/src/plugins/scripting/kexiscripting/kexi_scriptplugin.desktop b/src/plugins/scripting/kexiscripting/kexi_scriptplugin.desktop index 9abdd5a03..4c69900de 100644 --- a/src/plugins/scripting/kexiscripting/kexi_scriptplugin.desktop +++ b/src/plugins/scripting/kexiscripting/kexi_scriptplugin.desktop @@ -1,74 +1,74 @@ [Desktop Entry] GenericName=Scripts GenericName[ca]=Scripts GenericName[ca@valencia]=Scripts GenericName[cs]=Skripty GenericName[de]=Skripte GenericName[en_GB]=Scripts GenericName[es]=Guiones GenericName[fi]=Komentojonot GenericName[fr]=Scripts GenericName[gl]=Scripts GenericName[ia]=Scripts GenericName[it]=Script GenericName[ja]=スクリプト GenericName[nb]=Skripter GenericName[nl]=Scripts GenericName[pl]=Skrypty GenericName[pt]=Programas GenericName[pt_BR]=Scripts GenericName[se]=Skriptat GenericName[sk]=Skripty GenericName[sv]=Skript GenericName[uk]=Скрипти GenericName[x-test]=xxScriptsxx GenericName[zh_CN]=脚本 Name=Script Name[ca]=Script Name[ca@valencia]=Script Name[cs]=Skript Name[de]=Skript Name[en_GB]=Script Name[es]=Guion Name[fi]=Komentojono Name[fr]=Script Name[gl]=Script Name[ia]=Script Name[it]=Script Name[ja]=スクリプト Name[nb]=Skript Name[nl]=Script Name[pl]=Skrypt Name[pt]=Programa Name[pt_BR]=Script Name[sk]=Skript Name[sv]=Skript Name[uk]=Скрипт Name[x-test]=xxScriptxx Name[zh_CN]=脚本 Type=Service Icon=script Encoding=UTF-8 X-KDE-Library=kexi_scriptplugin X-KDE-ServiceTypes=Kexi/Editor -X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Author=KEXI Team X-KDE-PluginInfo-Email=kexi@kde.org X-KDE-PluginInfo-Name=org.kexi-project.script X-KDE-PluginInfo-Version=3.2 X-KDE-PluginInfo-Website=http://kexi-project.org X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=true X-Kexi-GroupName=Scripts X-Kexi-TypeName=script X-Kexi-ServiceTypesInUserMode=Kexi/Editor X-Kexi-VisibleInProjectNavigator=true X-Kexi-SupportsDataExport=false X-Kexi-SupportsPrinting=false X-Kexi-SupportsExecution=true diff --git a/src/plugins/scripting/kexiscripting/kexiscripteditor.cpp b/src/plugins/scripting/kexiscripting/kexiscripteditor.cpp index 96de2e9b5..38e56f03e 100644 --- a/src/plugins/scripting/kexiscripting/kexiscripteditor.cpp +++ b/src/plugins/scripting/kexiscripting/kexiscripteditor.cpp @@ -1,91 +1,91 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004-2005 Jarosław Staniek Copyright (C) 2005 Cedric Pasteur Copyright (C) 2005 Sebastian Sauer 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 "kexiscripteditor.h" /// \internal d-pointer class class Q_DECL_HIDDEN KexiScriptEditor::Private { public: QString scriptaction; Private() {} }; KexiScriptEditor::KexiScriptEditor(QWidget *parent) : KexiEditor(parent) , d(new Private()) { } KexiScriptEditor::~KexiScriptEditor() { delete d; } bool KexiScriptEditor::isInitialized() const { return !d->scriptaction.isEmpty(); } void KexiScriptEditor::initialize(const QString &scriptaction) { d->scriptaction = scriptaction; disconnect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged())); if (d->scriptaction.isEmpty()) { // If there is no code we just add some information. ///@todo remove after release #if 0 code = "# " + QStringList::split("\n", futureI18n( "This note will appear for a user in the script's source code " "as a comment. Keep every row not longer than 60 characters and use '\n.'", "This is Technology Preview (BETA) version of scripting\n" "support in Kexi. The scripting API may change in details\n" - "in the next Kexi version.\n" + "in the next KEXI version.\n" "For more information and documentation see\n%1", "http://www.kexi-project.org/scripting/"), true).join("\n# ") + "\n"; #endif } KexiEditor::setText(d->scriptaction); // We assume Kross and the HighlightingInterface are using same // names for the support languages... setHighlightMode("javascript"); clearUndoRedo(); KexiEditor::setDirty(false); connect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged())); } void KexiScriptEditor::slotTextChanged() { KexiEditor::setDirty(true); d->scriptaction = KexiEditor::text(); } void KexiScriptEditor::setLineNo(long lineno) { setCursorPosition(lineno, 0); } diff --git a/src/plugins/scripting/kexiscripting/kexiscriptpart.cpp b/src/plugins/scripting/kexiscripting/kexiscriptpart.cpp index 4ac4e3839..16146bf7f 100644 --- a/src/plugins/scripting/kexiscripting/kexiscriptpart.cpp +++ b/src/plugins/scripting/kexiscripting/kexiscriptpart.cpp @@ -1,223 +1,223 @@ /* This file is part of the KDE project Copyright (C) 2004 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2005 Sebastian Sauer 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. */ #include "kexiscriptpart.h" #include "kexiscriptdesignview.h" #include "kexiscriptadaptor.h" #include "../kexidb/kexidbmodule.h" #include "KexiScriptingDebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KEXI_PLUGIN_FACTORY(KexiScriptPart, "kexi_scriptplugin.json") /// \internal class Q_DECL_HIDDEN KexiScriptPart::Private { public: explicit Private(KexiScriptPart* p) : p(p) {} ~Private() { } QJSEngine engine; KexiScriptPart* p; KexiScriptAdaptor adaptor; Scripting::KexiDBModule kexidbmodule; }; KexiScriptPart::KexiScriptPart(QObject *parent, const QVariantList& l) : KexiPart::Part(parent, xi18nc("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " "Use '_' character instead of spaces. First character should be a..z character. " "If you cannot use latin characters in your language, use english word.", "script"), xi18nc("tooltip", "Create new script"), xi18nc("what's this", "Creates new script."), l) , d(new Private(this)) { d->engine.installExtensions(QJSEngine::ConsoleExtension); registerMetaObjects(); QJSValueIterator it(d->engine.globalObject()); while (it.hasNext()) { it.next(); KexiScriptingDebug() << it.name() << ": " << it.value().toString(); } } KexiScriptPart::~KexiScriptPart() { delete d; } bool KexiScriptPart::execute(KexiPart::Item* item, QObject* sender) { Q_UNUSED(sender); if (!item) { qWarning() << "Invalid item."; return false; } QString p = loadData(item); QJSValue result = execute(p); if (result.isError()) { QString errormessage = result.toString(); long lineno = result.property("lineNumber").toInt(); - QMessageBox mb(xi18n("Kexi Script"), xi18n("Error executing script at line %1:\n%2").arg(lineno).arg(errormessage), QMessageBox::Critical, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); + QMessageBox mb(xi18n("KEXI Script"), xi18n("Error executing script at line %1:\n%2").arg(lineno).arg(errormessage), QMessageBox::Critical, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); mb.exec(); return false; } return true; } QJSValue KexiScriptPart::execute(const QString& program) { QJSValue val; if (!d->engine.globalObject().hasProperty("KDb")) { val = d->engine.newQObject(&d->kexidbmodule); d->engine.globalObject().setProperty("KDb", val); } if (!program.isEmpty()) { return d->engine.evaluate(program); } return QJSValue(); } void KexiScriptPart::initPartActions() { } void KexiScriptPart::initInstanceActions() { createSharedAction(Kexi::TextViewMode, xi18n("Configure Editor..."), koIconName("configure"), QKeySequence(), "script_config_editor"); } KexiView* KexiScriptPart::createView(QWidget *parent, KexiWindow *window, KexiPart::Item *item, Kexi::ViewMode viewMode, QMap* staticObjectArgs) { Q_ASSERT(item); Q_UNUSED(window); Q_UNUSED(staticObjectArgs); QString partname = item->name(); if (! partname.isNull()) { if (viewMode == Kexi::TextViewMode) { return new KexiScriptDesignView(parent); } } return 0; } KLocalizedString KexiScriptPart::i18nMessage( const QString& englishMessage, KexiWindow* window) const { if (englishMessage == "Design of object %1 has been modified.") return kxi18nc(I18NC_NOOP("@info", "Design of script %1 has been modified.")); if (englishMessage == "Object %1 already exists.") return kxi18nc(I18NC_NOOP("@info", "Script %1 already exists.")); return Part::i18nMessage(englishMessage, window); } QString KexiScriptPart::loadData(KexiPart::Item* item) { QString data; if (!item) { return QString(); } if (true != KexiMainWindowIface::global()->project()->dbConnection()->loadDataBlock( item->identifier(), &data)) { return QString(); } QString errMsg; int errLine; int errCol; QString scriptType; QDomDocument domdoc; bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol); if (!parsed) { KexiScriptingWarning() << "XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg; return QString(); } QDomElement scriptelem = domdoc.namedItem("script").toElement(); if (scriptelem.isNull()) { KexiScriptingWarning() << "script domelement is null"; return QString(); } scriptType = scriptelem.attribute("scripttype"); if (scriptType.isEmpty()) { scriptType = "executable"; } if (scriptType == "executable") { return scriptelem.text().toUtf8(); } else { return QString(); } } void KexiScriptPart::registerMetaObjects() { QJSValue meta = d->engine.newQMetaObject(&KexiScriptAdaptor::staticMetaObject); d->engine.globalObject().setProperty("KexiScriptAdaptor", meta); meta = d->engine.newQMetaObject(&Scripting::KexiDBModule::staticMetaObject); d->engine.globalObject().setProperty("KDb", meta); } #include "kexiscriptpart.moc" diff --git a/src/plugins/tables/kexi_tableplugin.desktop b/src/plugins/tables/kexi_tableplugin.desktop index 2208b1587..feae3bc5e 100644 --- a/src/plugins/tables/kexi_tableplugin.desktop +++ b/src/plugins/tables/kexi_tableplugin.desktop @@ -1,65 +1,65 @@ [Desktop Entry] Name=Table Name[ca]=Taula Name[ca@valencia]=Taula Name[cs]=Tabulka Name[de]=Tabelle Name[en_GB]=Table Name[es]=Tabla Name[fi]=Taulu Name[fr]=Tableau Name[gl]=Táboa Name[ia]=Tabula Name[it]=Tabella Name[ja]=テーブル Name[nb]=Tabell Name[nl]=Tabel Name[pl]=Tabela Name[pt]=Tabela Name[pt_BR]=Tabela Name[sk]=Tabuľka Name[sv]=Tabell Name[uk]=Таблиця Name[x-test]=xxTablexx Name[zh_CN]=表格 Comment=Kexi plugin for handling tables Comment[ca]=Connector del Kexi per gestionar taules Comment[ca@valencia]=Connector del Kexi per gestionar taules Comment[cs]=Modul Kexi pro práci s tabulkami Comment[de]=Kexi-Modul für die Bearbeitung von Tabellen Comment[en_GB]=Kexi plugin for handling tables Comment[es]=Complemento de Kexi para manejar tablas Comment[fi]=Kexi-liitännäinen taulujen käsittelyyn Comment[fr]=Module Kexi pour gérer les tables Comment[gl]=Complemento para Kexi de manexo de táboas. Comment[it]=Estensione per gestire le tabelle di Kexi Comment[nl]=Kexi-plug-in voor behandeling van tabellen Comment[pl]=Wtyczka Kexi do obsługi tabel Comment[pt]='Plugin' do Kexi para lidar com tabelas Comment[pt_BR]=Plugin do Kexi para trabalhar com tabelas Comment[sk]=Kexi plugin na spracovanie tabuliek Comment[sv]=Kexi-insticksprogram för att hantera tabeller Comment[uk]=Додаток до Kexi для обробки таблиць Comment[x-test]=xxKexi plugin for handling tablesxx Type=Service Icon=table Encoding=UTF-8 X-KDE-Library=kexi_tableplugin X-KDE-ServiceTypes=Kexi/Viewer,Kexi/Designer -X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Author=KEXI Team X-KDE-PluginInfo-Email=kexi@kde.org X-KDE-PluginInfo-Name=org.kexi-project.table X-KDE-PluginInfo-Version=3.2 X-KDE-PluginInfo-Website=http://kexi-project.org X-KDE-PluginInfo-Category= X-KDE-PluginInfo-Depends= X-KDE-PluginInfo-License=LGPL X-KDE-PluginInfo-EnabledByDefault=true X-Kexi-GroupName=Tables X-Kexi-TypeName=table X-Kexi-ServiceTypesInUserMode=Kexi/Viewer X-Kexi-VisibleInProjectNavigator=true X-Kexi-SupportsDataExport=true X-Kexi-SupportsPrinting=true diff --git a/src/tests/migration/readertest.cpp b/src/tests/migration/readertest.cpp index c310e84cb..a6746768f 100644 --- a/src/tests/migration/readertest.cpp +++ b/src/tests/migration/readertest.cpp @@ -1,96 +1,96 @@ #include #include #include #include #include int main(int argc, char *argv[]) { - KAboutData aboutData("keximigratetest", 0, kxi18n("Kexi Migrate Test"), "2.0"); + KAboutData aboutData("keximigratetest", 0, kxi18n("KEXI Migrate Test"), "2.0"); KCmdLineArgs::init(argc, argv, &aboutData); KApplication app; KexiMigration::MigrateManager mm; qDebug() << mm.driverIds(); //Text File Test KexiMigration::KexiMigrate *m = mm.driver("Text"); KDbConnectionData cd; cd.setFileName("/home/piggz/tabdata.txt"); KexiMigration::Data d; d.source = &cd; m->setData(&d); m->connectSource(); KDbTableSchema ts; if (!m->readTableSchema("tabdata.txt", ts)) { qDebug() << "Unable to read schema"; return 0; } if (!m->readFromTable("tabdata.txt")) { qDebug() << "Unable to read from table"; return 0; } while(m->moveNext()) { qDebug() << m->value(0) << m->value(1) << m->value(2); } m->movePrevious(); qDebug() << m->value(0) << m->value(1) << m->value(2); m->moveNext(); qDebug() << m->value(0) << m->value(1) << m->value(2); m->movePrevious(); qDebug() << m->value(0) << m->value(1) << m->value(2); m->movePrevious(); qDebug() << m->value(0) << m->value(1) << m->value(2); m->movePrevious(); qDebug() << m->value(0) << m->value(1) << m->value(2); m->moveNext(); qDebug() << m->value(0) << m->value(1) << m->value(2); //KSpread file test KexiMigration::KexiMigrate *k = mm.driver("KSpread"); cd.setFileName("/home/piggz/Documents/database.fods"); k->setData(&d); k->connectSource(); QStringList tn; k->tableNames(tn); qDebug() << tn; KDbTableSchema ts2; if (!k->readTableSchema("Names", ts2)) { qDebug() << "Unable to read schema"; return 0; } k->readFromTable("Names"); while(k->moveNext()) { qDebug() << k->value(0) << k->value(1) << k->value(2); } } diff --git a/src/tests/newapi/main.cpp b/src/tests/newapi/main.cpp index 0ac858ed9..004ae98b0 100644 --- a/src/tests/newapi/main.cpp +++ b/src/tests/newapi/main.cpp @@ -1,283 +1,283 @@ /* This file is part of the KDE project Copyright (C) 2003-2010 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; QByteArray prgname; QString db_name; QString drv_name; QString test_name; int cursor_options = 0; bool db_name_required = true; QPointer project; QPointer conn; QPointer driver; KApplication *app = 0; KComponentData *instance = 0; #include "dbcreation_test.h" #include "cursors_test.h" #include "schema_test.h" #include #ifndef NO_GUI # include "tableview_test.h" #endif #include "parser_test.h" #include "dr_prop_test.h" void exitRoutine() { if (project) project->closeConnection(); delete project; } #define RETURN(code) \ exitRoutine(); \ qDebug()<< test_name << " TEST: " << (code==0?"PASSED":"ERROR"); \ return code int main(int argc, char** argv) { int minargs = 2; bool gui = false; /* if (argc < minargs) { usage(); RETURN(0); }*/ QFileInfo info = QFileInfo(argv[0]); prgname = info.baseName().toLatin1(); KAboutData aboutData(prgname, 0, kxi18n("KexiDBTest"), KEXI_VERSION_STRING, KLocalizedString(), KAboutData::License_GPL, - kxi18n("(c) 2003-2010, Kexi Team\n" + kxi18n("(c) 2003-2010, KEXI Team\n" "(c) 2003-2006, OpenOffice Software.\n"), KLocalizedString(), "http://www.kexi-project.org", "submit@bugs.kde.org"); KCmdLineArgs::init(argc, argv, &aboutData); KCmdLineOptions options; options.add("test ", kxi18n("Available tests:\n" "- cursors: test for cursors behaviour\n" "- schema: test for db schema retrieving\n" "- dbcreation: test for new db creation\n" "- tables: test for tables creation and data\n" " inserting\n" #ifndef NO_GUI "- tableview: test for KexiDataTableView data-aware\n" " widget\n" #endif "- parser: test for parsing sql statements,\n" " returns debug string for a given\n" " sql statement or error message\n" "- dr_prop: shows properties of selected driver")); options.add("buffered-cursors", kxi18n("Optional switch: turns cursors used in any tests\n" " to be buffered")); options.add("query-params ", kxi18n("Query parameters separated\n" "by '|' character that will be passed to query\n" "statement to replace [...] placeholders.")); options.add("", kxi18n(" Notes:" "1. 'dr_prop' requires db_name argument." "2. 'parser' test requires db_name," " driver_name and sql_statement arguments" "3. All other tests require db_name" " and driver_name arguments.\n" "4. 'tables' test automatically runs 'dbcreation'" " test. (new_db_name is deleted if already exists)." "5. db_name must be a valid kexi database" " e.g. created with 'tables' test.")); options.add("+driver_name", kxi18n("Driver name")); options.add("+[db_name]", kxi18n("Database name")); options.add("+[sql_statement]", kxi18n("Optional SQL statement (for parser test)")); KCmdLineArgs::addCmdLineOptions(options); KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); QStringList tests; tests << "cursors" << "schema" << "dbcreation" << "tables" << "tableview" << "parser" << "dr_prop"; if (!args->isSet("test")) { qDebug() << "No test specified. Use --help."; RETURN(1); } test_name = args->getOption("test"); if (!tests.contains(test_name)) { qDebug() << QString("No such test \"%1\". Use --help.").arg(test_name); RETURN(1); } if (test_name == "tableview") { gui = true; } else if (test_name == "parser") { minargs = 3; } else if (test_name == "dr_prop") { minargs = 1; db_name_required = false; } if ((int)args->count() < minargs) { qDebug() << QString("Not enough args (%1 required). Use --help.").arg(minargs); RETURN(1); } if (gui) { app = new KApplication(true); app->setWindowIcon(KexiIcon("table")); instance = new KComponentData(KAboutData::applicationData().displayName()); KIconLoader::global()->addAppDir("kexi"); } else { instance = new KComponentData(prgname); } drv_name = args->arg(0); KDbDriverManager manager; QStringList names = manager.driverNames(); qDebug() << "DRIVERS: "; for (QStringList::ConstIterator it = names.constBegin(); it != names.constEnd() ; ++it) qDebug() << *it; if (manager.error() || names.isEmpty()) { manager.debugError(); RETURN(1); } //get driver const KDbDriver::Info drv_info = manager.driverInfo(drv_name); driver = manager.driver(drv_name); if (drv_info.name.isEmpty() || manager.error()) { manager.debugError(); RETURN(1); } qDebug() << "MIME type for '" << drv_info.name << "': " << drv_info.fileDBMimeType; //open connection if (args->count() >= 2) db_name = args->arg(1); if (db_name_required && db_name.isEmpty()) { qDebug() << prgname << ": database name?"; RETURN(1); } if (!db_name.isEmpty()) { //additional switches: if (args->isSet("buffered-cursors")) { cursor_options |= KDbCursor::Buffered; } KexiProjectData project_data; project_data.setDatabaseName(db_name); if (drv_info.fileBased) { project_data.connectionData()->setFileName(db_name); } project_data.connectionData()->driverName = drv_name; project = new KexiProject(project_data); bool incompatibleWithKexi = false; tristate res; if (test_name == "dbcreation" || test_name == "tables") res = project->create(true /*force overwrite*/); else res = project->open(&incompatibleWithKexi); if (res != true) { if (incompatibleWithKexi) qDebug() << "incompatibleWithKexi"; project->debugError(); RETURN(1); } conn = project->dbConnection(); /* conn = driver->createConnection(conn_data); if (!conn || driver->error()) { driver->debugError(); RETURN(1); } if (!conn->connect()) { conn->debugError(); RETURN(1); }*/ } //start test: int r = 0; if (test_name == "cursors") r = cursorsTest(); else if (test_name == "schema") r = schemaTest(); else if (test_name == "dbcreation") r = dbCreationTest(); else if (test_name == "tables") r = tablesTest(); #ifndef NO_GUI else if (test_name == "tableview") r = tableViewTest(); #endif else if (test_name == "parser") { QStringList params; if (args->isSet("query-params")) params = args->getOption("query-params").split('|'); r = parserTest(QString(args->arg(2)), params); } else if (test_name == "dr_prop") r = drPropTest(); else { qWarning() << "No such test: " << test_name; // usage(); RETURN(1); } if (app && r == 0) app->exec(); if (r) qDebug() << "RECENT SQL STATEMENT: " << conn->recentSqlString(); if (project) { if (!project->closeConnection()) r = 1; delete project; } // if (conn && !conn->disconnect()) // r = 1; // qDebug() << "!!! KDbTransaction::globalcount == " << KDbTransaction::globalCount(); // qDebug() << "!!! KDbTransactionData::globalcount == " << KDbTransactionData::globalCount(); delete app; RETURN(r); } diff --git a/src/widget/KexiConnectionSelector.ui b/src/widget/KexiConnectionSelector.ui index 070b9ddb9..3d0aaefbb 100644 --- a/src/widget/KexiConnectionSelector.ui +++ b/src/widget/KexiConnectionSelector.ui @@ -1,212 +1,212 @@ KexiConnectionSelector 0 0 448 270 0 0 0 0 Qt::AlignTop false 0 0 <title>Select Existing Database Server's Connection From the List Below</title> -<para>You will see existing Kexi projects available for the selected connection. Here you may also add, edit or delete connections from the list.</para> +<para>You will see existing KEXI projects available for the selected connection. Here you may also add, edit or delete connections from the list.</para> Qt::AlignTop true list 0 0 0 60 true false true true true Name Type Server Information 0 0 Description 6 Qt::StrongFocus Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop true true Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse 0 0 &Add... 0 0 &Edit... 0 0 &Delete... Qt::Vertical QSizePolicy::Preferred 20 41 list btn_add btn_edit btn_remove diff --git a/src/widget/KexiProjectSelector.ui b/src/widget/KexiProjectSelector.ui index 310a68794..eb36e0145 100644 --- a/src/widget/KexiProjectSelector.ui +++ b/src/widget/KexiProjectSelector.ui @@ -1,127 +1,127 @@ KexiProjectSelector 0 0 549 219 0 0 0 0 0 - <b>There are Kexi projects you have recently opened.</b> Select one you wish to open: + <b>There are KEXI projects you have recently opened.</b> Select one you wish to open: Qt::AlignTop true true 0 1 0 60 true true true false Project Name true true Database true true Type true true Connection true true list