diff --git a/kexi/CMakeLists.txt b/kexi/CMakeLists.txt index cde5a5fc407..18db6d484e4 100644 --- a/kexi/CMakeLists.txt +++ b/kexi/CMakeLists.txt @@ -1,129 +1,130 @@ project(kexi) include(CheckFunctionExists) set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) option(KEXI_MOBILE "Compile a mobile version of Kexi" OFF) check_function_exists("uname" HAVE_UNAME) option(KEXI_DEBUG_GUI "Debugging GUI for Kexi (requires KDB_DEBUG_GUI to be set too)" OFF) option(KEXI_SHOW_UNFINISHED, "Show unfinished features in Kexi. Thus is useful for testing but may confuse end-user." OFF) option(KEXI_SHOW_UNIMPLEMENTED "Forces to show menu entries and dialogs just to give impression about development plans for Kexi. Only recommended for test/development versions." OFF) # Extra GUI features option(KEXI_AUTORISE_TABBED_TOOLBAR "Experimental: Autorise the main tabbed toolbar in Kexi" OFF) # Experimental: option(KEXI_SCRIPTS_SUPPORT "Experimental: Enable scripting in Kexi" ON) +# Broken: +option(KEXI_FORM_CURSOR_PROPERTY_SUPPORT "Broken: Enable \"cursor\" property in the form designer" OFF) +option(KEXI_SHOW_CONTEXT_HELP "Broken: Enable context help in Kexi main window" OFF) +option(KEXI_QUICK_PRINTING_SUPPORT "Broken: Enable print/print preview/print setup for tables/queries in the project navigator" OFF) +option(KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT "Broken: Enable \"auto field\" form widget in the form designer" OFF) +# OFF because we need to replace it with QTreeWidget which uses very different API compared to Q3ListView. Re-add QTreeWidget? +option(KEXI_LIST_FORM_WIDGET_SUPPORT "Broken: Enable \"list\" form widget in the form designer" OFF) +option(KEXI_PIXMAP_COLLECTIONS_SUPPORT "Broken: Enable support for pixmap collections" OFF) + # Not available: option(KEXI_MACROS_SUPPORT "Experimental: Enable macros in Kexi" OFF) if(KEXI_MACROS_SUPPORT) # temp. message(FATAL_ERROR "Macros are not yet available.") endif() option(KEXI_TABLE_PRINT_SUPPORT "Experimental: Enable printing of tabular view in Kexi" OFF) # broken since Kexi 2 if(KEXI_TABLE_PRINT_SUPPORT) # temp. message(FATAL_ERROR "Table printing is not yet available.") endif() option(KEXI_PROJECT_TEMPLATES "Experimental: Enable support for project templates in Kexi" OFF) # broken since Kexi 2 if(KEXI_PROJECT_TEMPLATES) # temp. message(FATAL_ERROR "Project templates are not yet available.") endif() #See commit 1e433a54cd9, left here for reference #option(KEXI_SQLITE_MIGRATION "If defined, SQLite3 migration to some newer format is possible. Users can see a suitable question on app's startup." OFF) -add_definitions( - -DKEXI_NO_CURSOR_PROPERTY # broken - -DKEXI_NO_CTXT_HELP # broken - -DKEXI_NO_SUBFORM # broken - -DKEXI_NO_QUICK_PRINTING # print/print preview/print setup for tables/queries in the navigator - -DKEXI_NO_AUTOFIELD_WIDGET # broken, to be removed -) - add_definitions(-DTRANSLATION_DOMAIN=\"kexi\") set(KEXI_PLUGIN_INSTALL_DIR ${PLUGIN_INSTALL_DIR}/kexi) set(KEXI_FORM_WIDGETS_PLUGIN_INSTALL_DIR ${PLUGIN_INSTALL_DIR}/kexi/forms/widgets) #no default: add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44010) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-kexi.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kexi.h ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KOMAIN_INCLUDES} ${CMAKE_SOURCE_DIR}/libs ) add_subdirectory( kexiutils ) macro_optional_find_package(MySQL) macro_log_feature(MYSQL_FOUND "libmysqlclient" "MySQL Client Library" "http://www.mysql.com" FALSE "" "Required by Kexi MySQL migration driver") set (PQXX_MIN_VERSION "3.0.0") set (PQXX_MAX_VERSION "5.0.0") macro_optional_find_package(CalligraPostgreSQL) macro_log_feature(POSTGRESQL_FOUND "libpq" "C application programmer's interface to PostgreSQL" "http://www.postgresql.org" FALSE "" "Required by Kexi PostgreSQL migration driver") pkg_check_modules (PQXX libpqxx) if (POSTGRESQL_FOUND AND PQXX_FOUND) if (PQXX_VERSION VERSION_GREATER PQXX_MIN_VERSION AND PQXX_VERSION VERSION_LESS PQXX_MAX_VERSION) macro_log_feature(PQXX_FOUND "libpqxx" "Official C++ client API for PostgreSQL" "http://pqxx.org/development/libpqxx/" FALSE "" "Required by Kexi PostgreSQL migration driver") else () macro_log_feature(FALSE "libpqxx" "Official C++ client API for PostgreSQL, version >= ${PQXX_MIN_VERSION} and older than ${PQXX_MAX_VERSION}" "http://pqxx.org/development/libpqxx/" FALSE "" "Required by Kexi PostgreSQL migration driver") endif () endif () macro_optional_find_package(FreeTDS) macro_log_feature(FREETDS_FOUND "FreeTDS" "Open source implementation of the TDS (Tabular Data Stream) protocol" "http://www.freetds.org" FALSE "" "Required by Kexi Sybase migration driver") macro_optional_find_package(XBase) macro_log_feature(XBASE_FOUND "XBase" "XBase compatible C++ class library" "http://linux.techass.com/projects/xdb" FALSE "" "Required by Kexi XBase migration driver") add_subdirectory( core ) add_subdirectory( widget ) add_subdirectory( data ) add_subdirectory( pics ) add_subdirectory( plugins ) if (BUILD_TESTING) #TODO KEXI3 add_subdirectory( tests ) endif() if(KEXI_MOBILE) else() add_subdirectory( main ) add_subdirectory( formeditor ) #TODO KEXI3 add_subdirectory( migration ) endif() ########### next target ############### if(KEXI_MOBILE) add_subdirectory( mobile ) else() set(kexi_SRCS main.cpp ) file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/pics/app/*-apps-calligrakexi.png") ecm_add_app_icon(kexi_SRCS ICONS ${ICONS_SRCS}) add_executable(kexi ${kexi_SRCS}) target_link_libraries(kexi keximain kexicore KDb ) install(TARGETS kexi ${INSTALL_TARGETS_DEFAULT_ARGS}) endif() ########### install files ############### install(PROGRAMS kexi.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(FILES kexi.appdata.xml DESTINATION ${SHARE_INSTALL_PREFIX}/appdata/) diff --git a/kexi/config-kexi.h.cmake b/kexi/config-kexi.h.cmake index 9b9608c4339..fbce99f4e5d 100644 --- a/kexi/config-kexi.h.cmake +++ b/kexi/config-kexi.h.cmake @@ -1,57 +1,100 @@ +/* This file is part of the KDE project + Copyright (C) 2006-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. +*/ + #ifndef KEXI_CONFIG_H #define KEXI_CONFIG_H /* config-kexi.h. Generated by cmake from config-kexi.h.cmake */ /*! @file config-kexi.h Global Kexi configuration (build time) */ #include //! @def KEXI_MOBILE //! @brief If defined, a mobile version of Kexi if 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 KEXI_DEBUG_GUI //! @brief If defined, a debugging GUI for Kexi is enabled #cmakedefine KEXI_DEBUG_GUI #if defined KEXI_DEBUG_GUI && !defined KDB_DEBUG_GUI # error KEXI_DEBUG_GUI requires a KDB_DEBUG_GUI cmake option to be set too in KDb. #endif /* -- Experimental -- */ //! @def KEXI_SCRIPTS_SUPPORT //! @brief If defined, scripting GUI plugin is enabled in Kexi #cmakedefine KEXI_SCRIPTS_SUPPORT //! @def KEXI_MACROS_SUPPORT //! @brief If defined, macro GUI plugin is enabled in Kexi #cmakedefine KEXI_MACROS_SUPPORT //! @def KEXI_SHOW_UNFINISHED //! @brief If defined unfinished features are enabled and presented in Kexi. //! This is useful for testing but may confuse end-users. #cmakedefine KEXI_SHOW_UNFINISHED //! @def KEXI_PROJECT_TEMPLATES //! @brief If defined, support for project templates is enabled in Kexi #cmakedefine KEXI_PROJECT_TEMPLATES //! @def KEXI_AUTORISE_TABBED_TOOLBAR //! @brief If defined, tabs in the main tabbed toolbar autorise in Kexi #cmakedefine KEXI_AUTORISE_TABBED_TOOLBAR +//! @def KEXI_FORM_CURSOR_PROPERTY_SUPPORT +//! @brief If defined, "cursor" property is displayed in the form designer +#cmakedefine KEXI_FORM_CURSOR_PROPERTY_SUPPORT + +//! @def KEXI_SHOW_CONTEXT_HELP +//! @brief If defined, context help is displayed in Kexi main window +#cmakedefine KEXI_SHOW_CONTEXT_HELP + +//! @def KEXI_QUICK_PRINTING_SUPPORT +//! @brief If defined, print/print preview/print setup for tables/queries is enabled in the project navigator +#cmakedefine KEXI_QUICK_PRINTING_SUPPORT + +//! @def KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT +//! @brief If defined, "auto field" form widget is available in the form designer +#cmakedefine KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT + +//! @def KEXI_LIST_FORM_WIDGET_SUPPORT +//! @brief If defined, "list" form widget is available in the form designer +#cmakedefine KEXI_LIST_FORM_WIDGET_SUPPORT + +//! @def KEXI_PIXMAP_COLLECTIONS_SUPPORT +//! @brief If defined, support for pixmap collections is enabled +#cmakedefine KEXI_PIXMAP_COLLECTIONS_SUPPORT + #endif diff --git a/kexi/core/KexiWindow.cpp b/kexi/core/KexiWindow.cpp index 39047820365..1c061f8a8ec 100644 --- a/kexi/core/KexiWindow.cpp +++ b/kexi/core/KexiWindow.cpp @@ -1,882 +1,882 @@ /* 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 "KexiWindow.h" #include "KexiWindowData.h" #include "KexiView.h" #include "KexiMainWindowIface.h" #include "kexipart.h" //! @todo KEXI3 #include "kexistaticpart.h" #include "kexipartitem.h" #include "kexipartinfo.h" #include "kexiproject.h" #include #include #include #include #include #include #include #include #include #include #include //---------------------------------------------------------- //! @internal class KexiWindow::Private { public: explicit Private(KexiWindow *window) : win(window) , schemaObject(0) , schemaObjectOwned(false) , isRegistered(false) , dirtyChangedEnabled(true) , switchToViewModeEnabled(true) { supportedViewModes = Kexi::NoViewMode; //will be set by KexiPart openedViewModes = Kexi::NoViewMode; currentViewMode = Kexi::NoViewMode; //no view available yet creatingViewsMode = Kexi::NoViewMode; id = -1; item = 0; } ~Private() { setSchemaObject(0); } void setSchemaObject(KDbObject* data) { if (schemaObjectOwned) { delete schemaObject; } schemaObject = data; } bool setupSchemaObject(KDbObject *object, KexiPart::Item *item, KexiView::StoreNewDataOptions options) const { object->setName(item->name()); object->setCaption(item->caption()); object->setDescription(item->description()); KexiProject *project = KexiMainWindowIface::global()->project(); KexiPart::Item* existingItem = project->item(part->info(), object->name()); if (existingItem && !(options & KexiView::OverwriteExistingData)) { KMessageBox::information(win, xi18n("Could not create new object.") + win->part()->i18nMessage("Object %1 already exists.", win) .subs(object->name()).toString()); return false; } return true; } KexiWindow *win; QVBoxLayout* mainLyr; QStackedWidget* stack; Kexi::ViewModes supportedViewModes; Kexi::ViewModes openedViewModes; Kexi::ViewMode currentViewMode; -#ifndef KEXI_NO_CTXT_HELP +#ifdef KEXI_SHOW_CONTEXT_HELP KexiContextHelpInfo *contextHelpInfo; #endif int id; QPointer part; KexiPart::Item *item; KDbObject* schemaObject; bool schemaObjectOwned; QPointer newlySelectedView; //!< Used in isDirty(), temporary set in switchToViewMode() //!< during view setup, when a new view is not yet raised. //! Used in viewThatRecentlySetDirtyFlag(), modified in dirtyChanged(). QPointer viewThatRecentlySetDirtyFlag; QPointer data; //!< temporary data shared between views /*! Created view's mode - helper for switchToViewMode(), KexiView ctor uses that info. >0 values are useful. */ Kexi::ViewMode creatingViewsMode; bool isRegistered; bool dirtyChangedEnabled; //!< used in setDirty(), affects dirtyChanged() bool switchToViewModeEnabled; //!< used internally switchToViewMode() to avoid infinite loop QMap views; }; //---------------------------------------------------------- KexiWindow::KexiWindow(QWidget *parent, Kexi::ViewModes supportedViewModes, KexiPart::Part *part, KexiPart::Item *item) : QWidget(parent) , KexiActionProxy(this, KexiMainWindowIface::global()) , d(new Private(this)) , m_destroying(false) { d->part = part; d->item = item; d->supportedViewModes = supportedViewModes; createSubwidgets(); -#ifndef KEXI_NO_CTXT_HELP +#ifdef KEXI_SHOW_CONTEXT_HELP d->contextHelpInfo = new KexiContextHelpInfo(); #endif updateCaption(); } KexiWindow::KexiWindow() : QWidget(0) , KexiActionProxy(this, KexiMainWindowIface::global()) , d(new Private(this)) , m_destroying(false) { createSubwidgets(); -#ifndef KEXI_NO_CTXT_HELP +#ifdef KEXI_SHOW_CONTEXT_HELP d->contextHelpInfo = new KexiContextHelpInfo(); #endif updateCaption(); } KexiWindow::~KexiWindow() { close(true /*force*/); m_destroying = true; delete d; d = 0; } void KexiWindow::createSubwidgets() { d->mainLyr = new QVBoxLayout(this); d->mainLyr->setContentsMargins(0, KexiUtils::marginHint() / 2, 0, 0); d->stack = new QStackedWidget(this); d->mainLyr->addWidget(d->stack); } KexiView *KexiWindow::selectedView() const { if (m_destroying) return 0; return static_cast(d->stack->currentWidget()); } KexiView *KexiWindow::viewForMode(Kexi::ViewMode mode) const { return d->views.value(mode); } void KexiWindow::addView(KexiView *view) { addView(view, Kexi::NoViewMode); } void KexiWindow::addView(KexiView *view, Kexi::ViewMode mode) { d->stack->addWidget(view); d->views.insert(mode, view); d->openedViewModes |= mode; } void KexiWindow::removeView(Kexi::ViewMode mode) { removeView(viewForMode(mode)); d->openedViewModes |= mode; d->openedViewModes ^= mode; } void KexiWindow::removeView(KexiView *view) { if (view) { d->stack->removeWidget(view); d->views.remove(view->viewMode()); d->openedViewModes |= view->viewMode(); d->openedViewModes ^= view->viewMode(); } } QSize KexiWindow::minimumSizeHint() const { KexiView *v = selectedView(); if (!v) return QWidget::minimumSizeHint(); return v->minimumSizeHint(); } QSize KexiWindow::sizeHint() const { KexiView *v = selectedView(); if (!v) return QWidget::sizeHint(); return v->preferredSizeHint(v->sizeHint()); } void KexiWindow::setId(int id) { d->id = id; } KexiPart::Part* KexiWindow::part() const { return d->part; } KexiPart::Item *KexiWindow::partItem() const { return d->item; } bool KexiWindow::supportsViewMode(Kexi::ViewMode mode) const { return d->supportedViewModes & mode; } Kexi::ViewModes KexiWindow::supportedViewModes() const { return d->supportedViewModes; } Kexi::ViewMode KexiWindow::currentViewMode() const { return d->currentViewMode; } KexiView* KexiWindow::viewThatRecentlySetDirtyFlag() const { return d->viewThatRecentlySetDirtyFlag; } void KexiWindow::registerWindow() { if (d->isRegistered) return; KexiMainWindowIface::global()->registerChild(this); d->isRegistered = true; } bool KexiWindow::isRegistered() const { return d->isRegistered; } int KexiWindow::id() const { return (partItem() && partItem()->identifier() > 0) ? partItem()->identifier() : d->id; } void KexiWindow::setContextHelp(const QString& caption, const QString& text, const QString& iconName) { -#ifdef KEXI_NO_CTXT_HELP - Q_UNUSED(caption); - Q_UNUSED(text); - Q_UNUSED(iconName); -#else +#ifdef KEXI_SHOW_CONTEXT_HELP d->contextHelpInfo->caption = caption; d->contextHelpInfo->text = text; d->contextHelpInfo->text = iconName; updateContextHelp(); +#else + Q_UNUSED(caption); + Q_UNUSED(text); + Q_UNUSED(iconName); #endif } bool KexiWindow::close(bool force) { KexiMainWindowIface::global()->acceptPropertySetEditing(); //let any view send "closing" signal QList list(findChildren()); QList< QPointer > listPtr; foreach(KexiView * view, list) { // use QPointers for sanity listPtr.append(QPointer(view)); } foreach(QPointer viewPtr, listPtr) { if (viewPtr && viewPtr->parent() == d->stack) { bool cancel = false; emit viewPtr->closing(&cancel); if (!force && cancel) { return false; } } } emit closing(); foreach(QPointer viewPtr, listPtr) { if (viewPtr && viewPtr->parent() == d->stack) { removeView(viewPtr.data()); delete viewPtr.data(); } } return true; } void KexiWindow::closeEvent(QCloseEvent * e) { if (!close(false /* !force*/)) { e->ignore(); return; } QWidget::closeEvent(e); } bool KexiWindow::isDirty() const { //look for "dirty" flag int m = d->openedViewModes; int mode = 1; while (m > 0) { if (m & 1) { KexiView *view = viewForMode(static_cast(mode)); if (view && view->isDirty()) { return true; } } m >>= 1; mode <<= 1; } return false; } void KexiWindow::setDirty(bool dirty) { d->dirtyChangedEnabled = false; int m = d->openedViewModes; int mode = 1; while (m > 0) { if (m & 1) { KexiView *view = viewForMode(static_cast(mode)); if (view) { view->setDirty(dirty); } } m >>= 1; mode <<= 1; } d->dirtyChangedEnabled = true; dirtyChanged(d->viewThatRecentlySetDirtyFlag); //update } QString KexiWindow::iconName() { if (!d->part || !d->part->info()) { KexiView *v = selectedView(); if (v) { return v->defaultIconName(); } return QString(); } return d->part->info()->iconName(); } KexiPart::GUIClient* KexiWindow::guiClient() const { if (!d->part || d->currentViewMode == 0) return 0; return d->part->instanceGuiClient(d->currentViewMode); } KexiPart::GUIClient* KexiWindow::commonGUIClient() const { if (!d->part) return 0; return d->part->instanceGuiClient(Kexi::AllViewModes); } bool KexiWindow::isDesignModePreloadedForTextModeHackUsed(Kexi::ViewMode newViewMode) const { return newViewMode == Kexi::TextViewMode && !viewForMode(Kexi::DesignViewMode) && supportsViewMode(Kexi::DesignViewMode); } tristate KexiWindow::switchToViewMode( Kexi::ViewMode newViewMode, QMap* staticObjectArgs, bool *proposeOpeningInTextViewModeBecauseOfProblems) { Q_ASSERT(proposeOpeningInTextViewModeBecauseOfProblems); KexiMainWindowIface::global()->acceptPropertySetEditing(); const bool designModePreloadedForTextModeHack = isDesignModePreloadedForTextModeHackUsed(newViewMode); tristate res = true; if (designModePreloadedForTextModeHack) { /* A HACK: open design BEFORE text mode: otherwise Query schema becames crazy */ bool _proposeOpeningInTextViewModeBecauseOfProblems = false; // used because even if opening the view failed, // text view can be opened res = switchToViewMode(Kexi::DesignViewMode, staticObjectArgs, &_proposeOpeningInTextViewModeBecauseOfProblems); if ((!res && !_proposeOpeningInTextViewModeBecauseOfProblems) || ~res) return res; } qDebug(); bool dontStore = false; KexiView *view = selectedView(); if (d->currentViewMode == newViewMode) return true; if (!supportsViewMode(newViewMode)) { qWarning() << "!" << Kexi::nameForViewMode(newViewMode); return false; } if (view) { res = true; if (view->isDataEditingInProgress()) { KGuiItem saveItem(KStandardGuiItem::save()); saveItem.setText(xi18n("Save Changes")); KGuiItem dontSaveItem(KStandardGuiItem::dontSave()); KGuiItem cancelItem(KStandardGuiItem::cancel()); cancelItem.setText(xi18n("Do Not Switch")); const int res = KMessageBox::questionYesNoCancel( selectedView(), xi18n("There are unsaved changes in object %1." "Do you want to save these changes before switching to other view?", partItem()->captionOrName()), xi18n("Confirm Saving Changes"), saveItem, dontSaveItem, cancelItem ); if (res == KMessageBox::Yes) { if (true != view->saveDataChanges()) return cancelled; } else if (res == KMessageBox::No) { if (true != view->cancelDataChanges()) return cancelled; } else { // Cancel: return cancelled; } } if (!designModePreloadedForTextModeHack) { const bool wasDirty = view->isDirty(); // remember and restore the flag if the view was clean res = view->beforeSwitchTo(newViewMode, &dontStore); if (!wasDirty) { view->setDirty(false); } } if (~res || !res) return res; if (!dontStore && view->isDirty()) { res = KexiMainWindowIface::global()->saveObject(this, xi18n("Design has been changed. " "You must save it before switching to other view.")); if (~res || !res) return res; // KMessageBox::questionYesNo(0, xi18n("Design has been changed. You must save it before switching to other view.")) // ==KMessageBox::No } } //get view for viewMode KexiView *newView = viewForMode(newViewMode); if (newView && !newView->inherits("KexiView")) { newView = 0; } if (!newView) { KexiUtils::setWaitCursor(); //ask the part to create view for the new mode d->creatingViewsMode = newViewMode; /*! @todo KEXI3 StaticPart KexiPart::StaticPart *staticPart = dynamic_cast((KexiPart::Part*)d->part); if (staticPart) newView = staticPart->createView(this, this, d->item, newViewMode, staticObjectArgs); else*/ newView = d->part->createView(this, this, d->item, newViewMode, staticObjectArgs); KexiUtils::removeWaitCursor(); if (!newView) { //js TODO error? qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " << d->currentViewMode << " restored."; return false; } d->creatingViewsMode = Kexi::NoViewMode; newView->initViewActions(); newView->initMainMenuActions(); addView(newView, newViewMode); } const Kexi::ViewMode prevViewMode = d->currentViewMode; res = true; if (designModePreloadedForTextModeHack) { d->currentViewMode = Kexi::NoViewMode; //SAFE? } bool wasDirty = newView->isDirty(); // remember and restore the flag if the view was clean res = newView->beforeSwitchTo(newViewMode, &dontStore); if (!wasDirty) { newView->setDirty(false); } *proposeOpeningInTextViewModeBecauseOfProblems = data()->proposeOpeningInTextViewModeBecauseOfProblems; if (!res) { removeView(newViewMode); delete newView; qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " << d->currentViewMode << " restored."; return false; } d->currentViewMode = newViewMode; d->newlySelectedView = newView; if (prevViewMode == Kexi::NoViewMode) d->newlySelectedView->setDirty(false); wasDirty = newView->isDirty(); // remember and restore the flag if the view was clean res = newView->afterSwitchFrom( designModePreloadedForTextModeHack ? Kexi::NoViewMode : prevViewMode); if (!wasDirty) { newView->setDirty(false); } *proposeOpeningInTextViewModeBecauseOfProblems = data()->proposeOpeningInTextViewModeBecauseOfProblems; if (!res) { removeView(newViewMode); delete newView; qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " << prevViewMode << " restored."; const Kexi::ObjectStatus status(*this); setStatus(KexiMainWindowIface::global()->project()->dbConnection(), xi18n("Switching to other view failed (%1).", Kexi::nameForViewMode(newViewMode)), ""); append(status); d->currentViewMode = prevViewMode; return false; } d->newlySelectedView = 0; if (~res) { d->currentViewMode = prevViewMode; return cancelled; } if (view) { takeActionProxyChild(view); //take current proxy child // views have distinct local toolbars, and user has switched the mode button so switch it back //view->toggleViewModeButtonBack(); } addActionProxyChild(newView); //new proxy child d->stack->setCurrentWidget(newView); newView->propertySetSwitched(); KexiMainWindowIface::global()->invalidateSharedActions(newView); newView->setFocus(); return true; } tristate KexiWindow::switchToViewModeInternal(Kexi::ViewMode newViewMode) { return KexiMainWindowIface::global()->switchToViewMode(*this, newViewMode); } tristate KexiWindow::switchToViewMode(Kexi::ViewMode newViewMode) { if (newViewMode == d->currentViewMode) return true; if (!d->switchToViewModeEnabled) return false; bool dummy; return switchToViewMode(newViewMode, 0, &dummy); } void KexiWindow::setFocus() { if (d->stack->currentWidget()) { if (d->stack->currentWidget()->inherits("KexiView")) static_cast(d->stack->currentWidget())->setFocus(); else d->stack->currentWidget()->setFocus(); } else { QWidget::setFocus(); } activate(); } KPropertySet* KexiWindow::propertySet() { KexiView *v = selectedView(); if (!v) return 0; return v->propertySet(); } void KexiWindow::setSchemaObject(KDbObject* object) { d->setSchemaObject(object); } KDbObject* KexiWindow::schemaObject() const { return d->schemaObject; } void KexiWindow::setSchemaObjectOwned(bool set) { d->schemaObjectOwned = set; } KexiWindowData *KexiWindow::data() const { return d->data; } void KexiWindow::setData(KexiWindowData* data) { if (data != d->data) delete d->data; d->data = data; } bool KexiWindow::eventFilter(QObject *obj, QEvent *e) { if (QWidget::eventFilter(obj, e)) return true; /*if (e->type()==QEvent::FocusIn) { QWidget *w = m_parentWindow->activeWindow(); w=0; }*/ if ((e->type() == QEvent::FocusIn && KexiMainWindowIface::global()->currentWindow() == this) || e->type() == QEvent::MouseButtonPress) { if (d->stack->currentWidget() && KDbUtils::hasParent(d->stack->currentWidget(), obj)) { //pass the activation activate(); } } return false; } void KexiWindow::dirtyChanged(KexiView* view) { if (!d->dirtyChangedEnabled) return; d->viewThatRecentlySetDirtyFlag = isDirty() ? view : 0; updateCaption(); emit dirtyChanged(this); } //static QString KexiWindow::windowTitleForItem(const KexiPart::Item &item) { return item.name(); } void KexiWindow::updateCaption() { if (!d->item || !d->part) return; const QString fullCapt(windowTitleForItem(*d->item)); setWindowTitle(isDirty() ? xi18nc("@title:window with dirty indicator", "%1*", fullCapt) : fullCapt); } bool KexiWindow::neverSaved() const { return d->item ? d->item->neverSaved() : true; } tristate KexiWindow::storeNewData(KexiView::StoreNewDataOptions options) { if (!neverSaved()) { return false; } if (d->schemaObject) { return false; //schema must not exist } KexiView *v = selectedView(); if (!v) { return false; } //create schema object and assign information KexiProject *project = KexiMainWindowIface::global()->project(); KDbObject object(project->typeIdForPluginId(d->part->info()->pluginId())); if (!d->setupSchemaObject(&object, d->item, options)) { return false; } bool cancel = false; d->schemaObject = v->storeNewData(object, options, &cancel); if (cancel) return cancelled; if (!d->schemaObject) { setStatus(project->dbConnection(), xi18n("Saving object's definition failed."), ""); return false; } if (project->typeIdForPluginId(part()->info()->pluginId()) < 0) { if (!project->createIdForPart(*part()->info())) return false; } /* Sets 'dirty' flag on every dialog's view. */ setDirty(false); //new object data has now ID updated to a unique value //-assign that to item's identifier d->item->setIdentifier(d->schemaObject->id()); project->addStoredItem(part()->info(), d->item); return true; } tristate KexiWindow::storeData(bool dontAsk) { if (neverSaved()) return false; KexiView *v = selectedView(); if (!v) return false; #define storeData_ERR \ setStatus(KexiMainWindowIface::global()->project()->dbConnection(), \ xi18n("Saving object's data failed."),""); //save changes using transaction KDbTransaction transaction = KexiMainWindowIface::global() ->project()->dbConnection()->beginTransaction(); if (transaction.isNull()) { storeData_ERR; return false; } KDbTransactionGuard tg(transaction); const tristate res = v->storeData(dontAsk); if (~res) //trans. will be cancelled return res; if (!res) { storeData_ERR; return res; } if (!tg.commit()) { storeData_ERR; return false; } /* Sets 'dirty' flag on every dialog's view. */ setDirty(false); return true; } tristate KexiWindow::storeDataAs(KexiPart::Item *item, KexiView::StoreNewDataOptions options) { if (neverSaved()) { qWarning() << "The data was never saved, so storeNewData() should be called instead, giving up."; return false; } KexiView *v = selectedView(); if (!v) { return false; } //create schema object and assign information KexiProject *project = KexiMainWindowIface::global()->project(); KDbObject object(project->typeIdForPluginId(d->part->info()->pluginId())); if (!d->setupSchemaObject(&object, item, options)) { return false; } bool cancel = false; KDbObject *newSchemaObject; if (isDirty()) { // full save of new data newSchemaObject = v->storeNewData(object, options, &cancel); } else { // there were no changes; full copy of the data is enough // - gives better performance (e.g. tables are copied on server side) // - works without bothering the user (no unnecessary questions) newSchemaObject = v->copyData(object, options, &cancel); } if (cancel) { return cancelled; } if (!newSchemaObject) { setStatus(project->dbConnection(), xi18n("Saving object's definition failed."), ""); return false; } setSchemaObject(newSchemaObject); // deletes previous schema if owned if (project->typeIdForPluginId(part()->info()->pluginId()) < 0) { if (!project->createIdForPart(*part()->info())) return false; } // clear 'dirty' for old window setDirty(false); // for now this Window has new item assigned d->item = item; // new object data has now ID updated to a unique value // -assign that to item's identifier item->setIdentifier(d->schemaObject->id()); project->addStoredItem(part()->info(), d->item); // set 'dirty' flag on every dialog's view setDirty(false); return true; } void KexiWindow::activate() { KexiView *v = selectedView(); //qDebug() << "focusWidget(): " << focusWidget()->name(); if (!KDbUtils::hasParent(v, KexiMainWindowIface::global()->focusWidget())) { //ah, focused widget is not in this view, move focus: if (v) v->setFocus(); } if (v) v->updateActions(true); } void KexiWindow::deactivate() { KexiView *v = selectedView(); if (v) v->updateActions(false); } void KexiWindow::sendDetachedStateToCurrentView() { KexiView *v = selectedView(); if (v) v->windowDetached(); } void KexiWindow::sendAttachedStateToCurrentView() { KexiView *v = selectedView(); if (v) v->windowAttached(); } bool KexiWindow::saveSettings() { bool result = true; for (int i = 0; i < d->stack->count(); ++i) { KexiView *view = qobject_cast(d->stack->widget(i)); if (!view->saveSettings()) { result = false; } } return result; } Kexi::ViewMode KexiWindow::creatingViewsMode() const { return d->creatingViewsMode; } QVariant KexiWindow::internalPropertyValue(const QByteArray& name, const QVariant& defaultValue) const { return d->part->internalPropertyValue(name, defaultValue); } diff --git a/kexi/core/kexistartupdata.cpp b/kexi/core/kexistartupdata.cpp index a004219f137..1049a9537b7 100644 --- a/kexi/core/kexistartupdata.cpp +++ b/kexi/core/kexistartupdata.cpp @@ -1,246 +1,246 @@ /* This file is part of the KDE project 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 "kexistartupdata.h" #include "kexi.h" #include "KexiCommandLineOptions.h" #include "config-kexi.h" #include #include #include #include class KexiStartupData::Private { public: Private(); ~Private(); QCommandLineParser parser; KexiCommandLineOptions options; KexiProjectData *projectData; Action action; KexiStartupData::Import importActionData; bool forcedUserMode; bool forcedDesignMode; bool isProjectNavigatorVisible; bool isMainMenuVisible; bool createDB; bool dropDB; bool alsoOpenDB; bool forcedFullScreen; }; KexiStartupData::Private::Private() : options(0/*&parser*/) , projectData(0), action(KexiStartupData::DoNothing), forcedUserMode(false) , forcedDesignMode(false), isProjectNavigatorVisible(false), forcedFullScreen(false) { } KexiStartupData::Private::~Private() { delete projectData; } KexiStartupData::KexiStartupData() : d(new Private) { } KexiStartupData::~KexiStartupData() { delete d; } KexiProjectData *KexiStartupData::projectData() { return d->projectData; } void KexiStartupData::setProjectData(KexiProjectData *data) { if (data != d->projectData) { delete d->projectData; } d->projectData = data; } KexiStartupData::Action KexiStartupData::action() const { return d->action; } void KexiStartupData::setAction(KexiStartupData::Action action) { d->action = action; } bool KexiStartupData::forcedUserMode() const { return d->forcedUserMode; } void KexiStartupData::setForcedUserMode(bool set) { d->forcedUserMode = set; } bool KexiStartupData::forcedDesignMode() const { return d->forcedDesignMode; } void KexiStartupData::setForcedDesignMode(bool set) { d->forcedDesignMode = set; } bool KexiStartupData::isProjectNavigatorVisible() const { if (d->forcedUserMode && !d->forcedDesignMode) return d->isProjectNavigatorVisible; return true; } void KexiStartupData::setProjectNavigatorVisible(bool set) { d->isProjectNavigatorVisible = set; } bool KexiStartupData::isMainMenuVisible() const { return d->isMainMenuVisible; } void KexiStartupData::setMainMenuVisible(bool set) { d->isMainMenuVisible = set; } KexiStartupData::Import KexiStartupData::importActionData() const { return d->importActionData; } void KexiStartupData::setImportActionData(KexiStartupData::Import import) { d->importActionData = import; } KexiStartupData::Import::Import() { } KexiStartupData::Import::operator bool() const { return !fileName.isEmpty() && !mimeType.isEmpty(); } bool KexiStartupData::forcedFullScreen() const { return d->forcedFullScreen; } void KexiStartupData::setForcedFullScreen(bool set) { d->forcedFullScreen = set; } //! Command line options KexiCommandLineOptions KexiStartupData::options() const { return d->options; } tristate KexiStartupData::parseOptions() { //KAboutData::applicationData().setupCommandLine(&d->parser); //d->parser.addHelpOption(); //d->parser.addVersionOption(); d->parser.setApplicationDescription(KAboutData::applicationData().shortDescription()); #define ADD_OPTION(o) \ if (!d->parser.addOption(d->options.o)) { \ qWarning() << "Could not add option" << d->options.o.names(); \ return false; \ } else { qDebug() << "OK" << d->options.o.names(); } ADD_OPTION(createDb) ADD_OPTION(createAndOpenDb) ADD_OPTION(dropDb) ADD_OPTION(dbDriver) ADD_OPTION(fileType) ADD_OPTION(connectionShortcut) ADD_OPTION(readOnly) ADD_OPTION(userMode) ADD_OPTION(designMode) ADD_OPTION(showNavigator) ADD_OPTION(hideMenu) ADD_OPTION(open) ADD_OPTION(design) ADD_OPTION(editText) ADD_OPTION(execute) ADD_OPTION(newObject) -#ifndef KEXI_NO_QUICK_PRINTING +#ifdef KEXI_QUICK_PRINTING_SUPPORT ADD_OPTION(print) ADD_OPTION(printPreview) #endif ADD_OPTION(user) ADD_OPTION(host) ADD_OPTION(port) ADD_OPTION(localSocket) ADD_OPTION(skipConnDialog) ADD_OPTION(fullScreen) ADD_OPTION(listPlugins) #undef ADD_OPTION d->parser.addPositionalArgument("file", xi18nc(" argument description for the command line", "Kexi database project filename, Kexi shortcut filename, or name of a Kexi " "database project on a server to open.")); qDebug() << QCoreApplication::instance()->arguments(); if (!d->parser.parse(QCoreApplication::instance()->arguments())) { return false; } KAboutData::applicationData().processCommandLine(&d->parser); return true; } bool KexiStartupData::isSet(const QCommandLineOption & option) const { return d->parser.isSet(option); } QString KexiStartupData::value(const QCommandLineOption & option) const { return d->parser.value(option); } QStringList KexiStartupData::positionalArguments() const { return d->parser.positionalArguments(); } QString KexiStartupData::helpText() const { return d->parser.helpText(); } diff --git a/kexi/doc/dev/compile_time_options.txt b/kexi/doc/dev/compile_time_options.txt index cad5d36f6b1..fbea0b2b92a 100644 --- a/kexi/doc/dev/compile_time_options.txt +++ b/kexi/doc/dev/compile_time_options.txt @@ -1,82 +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. 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_NO_SUBFORM +* KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT Type: defined/undefined, temporary -Default: defined -Description: If defined, subform widget will not be available - -* KEXI_NO_AUTOFIELD_WIDGET -Type: defined/undefined, temporary -Default: undefined for 1.x, defined for 2.x -Description: If defined, autofield (KexiDBFieldEdit) widget will not be available, +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/kexi/formeditor/CMakeLists.txt b/kexi/formeditor/CMakeLists.txt index 43054395a97..6741db3639b 100644 --- a/kexi/formeditor/CMakeLists.txt +++ b/kexi/formeditor/CMakeLists.txt @@ -1,74 +1,66 @@ add_subdirectory( factories ) include_directories(${CMAKE_SOURCE_DIR}/kexi/widget ${CMAKE_SOURCE_DIR}/kexi/widget/utils ${CMAKE_SOURCE_DIR}/kexi/widget/tableview ${CMAKE_SOURCE_DIR}/kexi/core) add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44010) -# Disable list widget because we need to replace it with QTreeWidget -# which uses very different API compared to Q3ListView. -# todo: re-add QTreeWidget? -add_definitions(-DKEXI_FORMS_NO_LIST_WIDGET) - -# Disable pixmap collections -add_definitions(-DKEXI_NO_PIXMAPCOLLECTION) - # enable to add signal/slot connections # set(KFD_SIGSLOTS true) ########### next target ############### set(kformdesigner_LIB_SRCS container.cpp resizehandle.cpp widgetfactory.cpp widgetlibrary.cpp KexiFormWidgetsPluginMetaData.cpp WidgetInfo.cpp libactionwidget.cpp form.cpp form_p.cpp objecttree.cpp formIO.cpp FormWidget.cpp FormWidgetInterface.cpp WidgetTreeWidget.cpp commands.cpp events.cpp richtextdialog.cpp tabstopdialog.cpp -#KEXI_FORMS_NO_LIST_WIDGET: editlistviewdialog.cpp +#KEXI_LIST_FORM_WIDGET_SUPPORT: editlistviewdialog.cpp utils.cpp #todo kfdpixmapedit.cpp widgetwithsubpropertiesinterface.cpp kexiformeventhandler.cpp # from libkexiformutils kexiactionselectiondialog.cpp # from libkexiformutils ) set(kformdesigner_LIBS kexiutils kexicore kexiextendedwidgets kundo2 kowidgets # KoFileDialog KDb KProperty ) if(KFD_SIGSLOTS) add_definitions( -DKFD_SIGSLOTS=1 ) list(APPEND kformdesigner_LIB_SRCS connectiondialog.cpp) list(APPEND kformdesigner_LIBS kexiextendedwidgets kexidatatable) endif() add_library(kformdesigner SHARED ${kformdesigner_LIB_SRCS}) generate_export_header(kformdesigner) target_link_libraries(kformdesigner ${kformdesigner_LIBS}) set_target_properties(kformdesigner PROPERTIES VERSION ${GENERIC_CALLIGRA_LIB_VERSION} SOVERSION ${GENERIC_CALLIGRA_LIB_SOVERSION} ) install(TARGETS kformdesigner ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/kexi/formeditor/factories/CMakeLists.txt b/kexi/formeditor/factories/CMakeLists.txt index 5dfbaf5bff8..1967e980b8c 100644 --- a/kexi/formeditor/factories/CMakeLists.txt +++ b/kexi/formeditor/factories/CMakeLists.txt @@ -1,23 +1,21 @@ include_directories(${CMAKE_SOURCE_DIR}/kexi/formeditor ${CMAKE_SOURCE_DIR}/kexi/core) -add_definitions(-DKEXI_FORMS_NO_LIST_WIDGET) - set(kexiforms_standardwidgetsplugin_SRCS KexiStandardFormWidgetsFactory.cpp KexiStandardFormWidgets.cpp KexiStandardContainerFormWidgets.cpp ) add_library(kexiforms_standardwidgetsplugin MODULE ${kexiforms_standardwidgetsplugin_SRCS}) kcoreaddons_desktop_to_json(kexiforms_standardwidgetsplugin kexiforms_standardwidgetsplugin.desktop) target_link_libraries(kexiforms_standardwidgetsplugin kformdesigner kundo2 Qt5::Core Qt5::Gui Qt5::Xml ) install(TARGETS kexiforms_standardwidgetsplugin DESTINATION ${KEXI_FORM_WIDGETS_PLUGIN_INSTALL_DIR}) diff --git a/kexi/formeditor/factories/KexiStandardContainerFormWidgets.cpp b/kexi/formeditor/factories/KexiStandardContainerFormWidgets.cpp index 22a176d935f..b87472ac9d3 100644 --- a/kexi/formeditor/factories/KexiStandardContainerFormWidgets.cpp +++ b/kexi/formeditor/factories/KexiStandardContainerFormWidgets.cpp @@ -1,456 +1,413 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2006-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 "KexiStandardContainerFormWidgets.h" #include "container.h" #include "form.h" #include "formIO.h" #include "objecttree.h" #include "widgetlibrary.h" #include "utils.h" #include "commands.h" #include #include #include #include #include #include #include ContainerWidget::ContainerWidget(QWidget *parent) : QWidget(parent) { } ContainerWidget::~ContainerWidget() { } QSize ContainerWidget::sizeHint() const { return QSize(30, 30); //default } void ContainerWidget::dragMoveEvent(QDragMoveEvent *e) { QWidget::dragMoveEvent(e); emit handleDragMoveEvent(e); } void ContainerWidget::dropEvent(QDropEvent *e) { QWidget::dropEvent(e); emit handleDropEvent(e); } //////////////////////// GroupBox::GroupBox(const QString & title, QWidget *parent) : QGroupBox(title, parent) { } GroupBox::~GroupBox() { } void GroupBox::dragMoveEvent(QDragMoveEvent *e) { QGroupBox::dragMoveEvent(e); emit handleDragMoveEvent(e); } void GroupBox::dropEvent(QDropEvent *e) { QGroupBox::dropEvent(e); emit handleDropEvent(e); } QSize GroupBox::sizeHint() const { return title().isEmpty() ? QGroupBox::sizeHint() : QSize(fontMetrics().width(title()), fontMetrics().height()*3); } //////////////////////// KFDTabWidget::KFDTabWidget(KFormDesigner::Container *container, QWidget *parent) : KFormDesigner::TabWidget(parent), m_container(container) { } KFDTabWidget::~KFDTabWidget() { } QSize KFDTabWidget::sizeHint() const { QSize s(30, 30); // default min size for (int i = 0; i < count(); i++) s = s.expandedTo(KFormDesigner::getSizeFromChildren(widget(i))); return s + QSize(10/*margin*/, tabBar()->height() + 20/*margin*/); } void KFDTabWidget::dragMoveEvent(QDragMoveEvent *e) { TabWidgetBase::dragMoveEvent(e); if (qobject_cast(currentWidget())) emit qobject_cast(currentWidget())->handleDragMoveEvent(e); emit handleDragMoveEvent(e); } void KFDTabWidget::dropEvent(QDropEvent *e) { TabWidgetBase::dropEvent(e); if (qobject_cast(currentWidget())) emit qobject_cast(currentWidget())->handleDropEvent(e); emit handleDropEvent(e); } /// Various layout widgets /////////////////: HBox::HBox(QWidget *parent) : QFrame(parent) { } HBox::~HBox() { } void HBox::paintEvent(QPaintEvent *) { if (!designMode()) return; QPainter p(this); p.setPen(QPen(Qt::red, 2, Qt::DashLine)); p.drawRect(1, 1, width() - 1, height() - 1); } VBox::VBox(QWidget *parent) : QFrame(parent) { } VBox::~VBox() { } void VBox::paintEvent(QPaintEvent *) { if (!designMode()) return; QPainter p(this); p.setPen(QPen(Qt::blue, 2, Qt::DashLine)); p.drawRect(1, 1, width() - 1, height() - 1); } Grid::Grid(QWidget *parent) : QFrame(parent) { } Grid::~Grid() { } void Grid::paintEvent(QPaintEvent *) { if (!designMode()) return; QPainter p(this); p.setPen(QPen(Qt::darkGreen, 2, Qt::DashLine)); p.drawRect(1, 1, width() - 1, height() - 1); } HFlow::HFlow(QWidget *parent) : QFrame(parent) { } HFlow::~HFlow() { } void HFlow::paintEvent(QPaintEvent *) { if (!designMode()) return; QPainter p(this); p.setPen(QPen(Qt::magenta, 2, Qt::DashLine)); p.drawRect(1, 1, width() - 1, height() - 1); } VFlow::VFlow(QWidget *parent) : QFrame(parent) { } VFlow::~VFlow() { } void VFlow::paintEvent(QPaintEvent *) { if (!designMode()) return; QPainter p(this); p.setPen(QPen(Qt::cyan, 2, Qt::DashLine)); p.drawRect(1, 1, width() - 1, height() - 1); } QSize VFlow::sizeHint() const { if (layout()) return layout()->sizeHint(); else return QSize(700, 50); // default } -/////// Sub forms ////////////////////////: - -#if 0 -SubForm::SubForm(KFormDesigner::Form *parentForm, QWidget *parent) - : QScrollArea(parent), m_parentForm(parentForm), m_form(0), m_widget(0) -{ - setFrameStyle(QFrame::WinPanel | QFrame::Sunken); - viewport()->setPaletteBackgroundColor(colorGroup().mid()); -} - -SubForm::~SubForm() -{ -} - -void -SubForm::setFormName(const QString &name) -{ - if (name.isEmpty()) - return; - - QFileInfo info(name); - if (!info.exists() || (m_parentForm && info.fileName() == m_parentForm->filename())) { -//! @todo ??? - return; // we check if this form is valid - } - - // we create the container widget - delete m_widget; - m_widget = new QWidget(viewport()); - m_widget->setObjectName("subform_widget"); - addChild(m_widget); - m_form = new KFormDesigner::Form(m_parentForm); - m_form->setObjectName(this->objectName()); - m_form->createToplevel(m_widget); - - // and load the sub form - KFormDesigner::FormIO::loadFormFromFile(m_form, m_widget, name); - m_form->setMode(KFormDesigner::Form::DesignMode); - - m_formName = name; -} -#endif //0 - ///// Internal actions AddTabAction::AddTabAction(KFormDesigner::Container *container, TabWidgetBase *receiver, QObject *parent) : QAction(koIcon("tab-new"), xi18nc("Add page to tab widget", "Add Page"), parent) , m_container(container) , m_receiver(receiver) { connect(this, SIGNAL(triggered()), this, SLOT(slotTriggered())); } void AddTabAction::slotTriggered() { if (!qobject_cast(m_receiver)) return; KFormDesigner::Command *command = new KFormDesigner::InsertPageCommand(m_container, m_receiver); if (m_receiver->count() == 0) { command->execute(); delete command; } else { m_container->form()->addCommand(command); } } RemoveTabAction::RemoveTabAction(KFormDesigner::Container *container, TabWidgetBase *receiver, QObject *parent) : QAction(koIcon("tab-close-other"), xi18nc("Remove tab widget's page", "Remove Page"), parent) , m_container(container) , m_receiver(receiver) { connect(this, SIGNAL(triggered()), this, SLOT(slotTriggered())); if (m_receiver->count() <= 1) { setEnabled(false); } } void RemoveTabAction::slotTriggered() { if (!qobject_cast(m_receiver) || m_receiver->count() == 0) return; KFormDesigner::Command *com = new KFormDesigner::RemovePageCommand(m_container, m_receiver); m_container->form()->addCommand(com); } RenameTabAction::RenameTabAction(KFormDesigner::Container *container, TabWidgetBase *receiver, QObject *parent) : QAction(koIcon("edit-rename"), xi18nc("Rename tab widget's page", "Rename Page..."), parent) , m_container(container) , m_receiver(receiver) { connect(this, SIGNAL(triggered()), this, SLOT(slotTriggered())); } void RenameTabAction::slotTriggered() { if (!qobject_cast(m_receiver)) return; QWidget *w = m_receiver->currentWidget(); bool ok; QString name = QInputDialog::getText(w->topLevelWidget(), xi18nc("@window:title", "New Page Title"), xi18n("Enter a new title for the current page:"), QLineEdit::Normal, m_receiver->tabText(m_receiver->indexOf(w)), &ok); if (ok) m_receiver->setTabText(m_receiver->indexOf(w), name); } AddStackPageAction::AddStackPageAction(KFormDesigner::Container *container, QWidget *receiver, QObject *parent) : QAction(koIcon("tab-new"), xi18nc("Add page to a stacked widget", "Add Page..."), parent) , m_container(container) , m_receiver(receiver) { connect(this, SIGNAL(triggered()), this, SLOT(slotTriggered())); } void AddStackPageAction::slotTriggered() { if ( !KexiUtils::objectIsA(m_receiver, "QStackedWidget") && /* compat */ !KexiUtils::objectIsA(m_receiver, "QWidgetStack")) { return; } KFormDesigner::Command *command = new KFormDesigner::InsertPageCommand(m_container, m_receiver); if (!qobject_cast(m_receiver)->currentWidget()) { command->execute(); delete command; } else { m_container->form()->addCommand(command); } } RemoveStackPageAction::RemoveStackPageAction(KFormDesigner::Container *container, QWidget *receiver, QObject *parent) : QAction(koIcon("tab-close-other"), xi18nc("Remove page from a stacked widget", "Remove Page"), parent) , m_container(container) , m_receiver(receiver) { connect(this, SIGNAL(triggered()), this, SLOT(slotTriggered())); if (qobject_cast(m_receiver)->count() <= 1) { setEnabled(false); } } void RemoveStackPageAction::slotTriggered() { if ( !KexiUtils::objectIsA(m_receiver, "QStackedWidget") && /* compat */ !KexiUtils::objectIsA(m_receiver, "QWidgetStack")) { return; } QStackedWidget *stack = qobject_cast(m_receiver); QWidget *page = stack->currentWidget(); QWidgetList list; list.append(page); KFormDesigner::Command *com = new KFormDesigner::DeleteWidgetCommand(*m_container->form(), list); // raise prev/next widget int index = stack->indexOf(page); if (index > 0) { index--; } else if (index < (stack->count()-1)) { index++; } else { index = -1; } if (index >= 0) { stack->setCurrentIndex(index); } stack->removeWidget(page); m_container->form()->addCommand(com); } GoToStackPageAction::GoToStackPageAction(Direction direction, KFormDesigner::Container *container, QWidget *receiver, QObject *parent) : QAction(QIcon::fromTheme(direction == Previous ? koIconName("go-previous") : koIconName("go-next")), direction == Previous ? xi18nc("Go to Previous Page of a Stacked Widget", "Go to Previous Page") : xi18nc("Go to Next Page of a Stacked Widget", "Go to Next Page"), parent) , m_direction(direction) , m_container(container) , m_receiver(receiver) { connect(this, SIGNAL(triggered()), this, SLOT(slotTriggered())); QStackedWidget *stack = qobject_cast(m_receiver); if (!stack || !stack->widget(nextWidgetIndex())) { setEnabled(false); } } int GoToStackPageAction::nextWidgetIndex() const { QStackedWidget *stack = qobject_cast(m_receiver); if (!stack) return -1; return stack->currentIndex() + (m_direction == Previous ? -1 : 1); } void GoToStackPageAction::slotTriggered() { QStackedWidget *stack = qobject_cast(m_receiver); if (stack && stack->widget(nextWidgetIndex())) { stack->setCurrentIndex(nextWidgetIndex()); } } diff --git a/kexi/formeditor/factories/KexiStandardContainerFormWidgets.h b/kexi/formeditor/factories/KexiStandardContainerFormWidgets.h index 9890f37c4e6..da6d660661f 100644 --- a/kexi/formeditor/factories/KexiStandardContainerFormWidgets.h +++ b/kexi/formeditor/factories/KexiStandardContainerFormWidgets.h @@ -1,289 +1,263 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2006-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. */ #ifndef KEXISTANDARDCONTAINERWIDGETS_H #define KEXISTANDARDCONTAINERWIDGETS_H #include "FormWidgetInterface.h" #include "utils.h" #include #include class QPaintEvent; namespace KFormDesigner { class Container; } //! Helper widget (used when using 'Lay out horizontally') class HBox : public QFrame, public KFormDesigner::FormWidgetInterface { public: explicit HBox(QWidget *parent); virtual ~HBox(); virtual void paintEvent(QPaintEvent *ev); }; //! Helper widget (used when using 'Lay out vertically') class VBox : public QFrame, public KFormDesigner::FormWidgetInterface { public: explicit VBox(QWidget *parent); virtual ~VBox(); virtual void paintEvent(QPaintEvent *ev); }; //! Helper widget (used when using 'Lay out in a grid') class Grid : public QFrame, public KFormDesigner::FormWidgetInterface { public: explicit Grid(QWidget *parent); virtual ~Grid(); virtual void paintEvent(QPaintEvent *ev); }; //! Helper widget (used when using 'Lay out with horizontal flow') class HFlow : public QFrame, public KFormDesigner::FormWidgetInterface { public: explicit HFlow(QWidget *parent); virtual ~HFlow(); virtual void paintEvent(QPaintEvent *ev); }; //! Helper widget (used when using 'Lay out with horizontal flow') class VFlow : public QFrame, public KFormDesigner::FormWidgetInterface { public: explicit VFlow(QWidget *parent); virtual ~VFlow(); virtual void paintEvent(QPaintEvent *ev); virtual QSize sizeHint() const; }; //! A simple container widget class ContainerWidget : public QWidget { Q_OBJECT friend class KFDTabWidget; public: explicit ContainerWidget(QWidget *parent); virtual ~ContainerWidget(); virtual QSize sizeHint() const; //! Used to emit handleDragMoveEvent() signal needed to control dragging over the container's surface virtual void dragMoveEvent(QDragMoveEvent *e); //! Used to emit handleDropEvent() signal needed to control dropping on the container's surface virtual void dropEvent(QDropEvent *e); Q_SIGNALS: //! Needed to control dragging over the container's surface void handleDragMoveEvent(QDragMoveEvent *e); //! Needed to control dropping on the container's surface void handleDropEvent(QDropEvent *e); }; //! Action of adding tab to a tab widget //! Keeps context expressed using container and receiver widget class AddTabAction : public QAction { Q_OBJECT public: AddTabAction(KFormDesigner::Container *container, TabWidgetBase *receiver, QObject *parent); public Q_SLOTS: void slotTriggered(); private: KFormDesigner::Container *m_container; TabWidgetBase *m_receiver; }; //! Action of removing tab from a tab widget //! Keeps context expressed using container and receiver widget class RemoveTabAction : public QAction { Q_OBJECT public: RemoveTabAction(KFormDesigner::Container *container, TabWidgetBase *receiver, QObject *parent); protected Q_SLOTS: void slotTriggered(); private: KFormDesigner::Container *m_container; TabWidgetBase *m_receiver; }; //! Action renaming tab widget's tab //! Keeps context expressed using container and receiver widget class RenameTabAction : public QAction { Q_OBJECT public: RenameTabAction(KFormDesigner::Container *container, TabWidgetBase *receiver, QObject *parent); protected Q_SLOTS: void slotTriggered(); private: KFormDesigner::Container *m_container; TabWidgetBase *m_receiver; }; //! Action of adding page to a stacked widget //! Keeps context expressed using container and receiver widget class AddStackPageAction : public QAction { Q_OBJECT public: AddStackPageAction(KFormDesigner::Container *container, QWidget *receiver, QObject *parent); protected Q_SLOTS: void slotTriggered(); private: KFormDesigner::Container *m_container; QWidget *m_receiver; }; //! Action of removing page from a stacked widget //! Keeps context expressed using container and receiver widget class RemoveStackPageAction : public QAction { Q_OBJECT public: RemoveStackPageAction(KFormDesigner::Container *container, QWidget *receiver, QObject *parent); protected Q_SLOTS: void slotTriggered(); private: KFormDesigner::Container *m_container; QWidget *m_receiver; }; //! Action of moving between pages of a stacked widget //! Keeps context expressed using container and receiver widget class GoToStackPageAction : public QAction { Q_OBJECT public: enum Direction { Previous, Next }; GoToStackPageAction(Direction direction, KFormDesigner::Container *container, QWidget *receiver, QObject *parent); protected Q_SLOTS: void slotTriggered(); private: int nextWidgetIndex() const; Direction m_direction; KFormDesigner::Container *m_container; QWidget *m_receiver; }; //! A tab widget class KFDTabWidget : public KFormDesigner::TabWidget { Q_OBJECT public: KFDTabWidget(KFormDesigner::Container *container, QWidget *parent); virtual ~KFDTabWidget(); virtual QSize sizeHint() const; //! Used to emit handleDragMoveEvent() signal needed to control dragging over the container's surface virtual void dragMoveEvent(QDragMoveEvent *e); //! Used to emit handleDropEvent() signal needed to control dropping on the container's surface virtual void dropEvent(QDropEvent *e); KFormDesigner::Container *container() const { return m_container; } Q_SIGNALS: //! Needed to control dragging over the container's surface void handleDragMoveEvent(QDragMoveEvent *e); //! Needed to control dropping on the container's surface void handleDropEvent(QDropEvent *e); private: KFormDesigner::Container *m_container; }; //! A group box widget class GroupBox : public QGroupBox { Q_OBJECT public: GroupBox(const QString & title, QWidget *parent); virtual ~GroupBox(); //! Used to emit handleDragMoveEvent() signal needed to control dragging over the container's surface virtual void dragMoveEvent(QDragMoveEvent *e); //! Used to emit handleDropEvent() signal needed to control dropping on the container's surface virtual void dropEvent(QDropEvent *e); virtual QSize sizeHint() const; Q_SIGNALS: //! Needed to control dragging over the container's surface void handleDragMoveEvent(QDragMoveEvent *e); //! Needed to control dropping on the container's surface void handleDropEvent(QDropEvent *e); }; -//! @todo SubForm -#if 0 -//! A form embedded as a widget inside other form -class SubForm : public QScrollArea -{ - Q_OBJECT - Q_PROPERTY(QString formName READ formName WRITE setFormName) - -public: - SubForm(KFormDesigner::Form *parentForm, QWidget *parent); - ~SubForm(); - - //! \return the name of the subform inside the db - QString formName() const { - return m_formName; - } - void setFormName(const QString &name); - -private: - KFormDesigner::Form *m_form; - KFormDesigner::Form *m_parentForm; - QWidget *m_widget; - QString m_formName; -}; -#endif //0 - #endif diff --git a/kexi/formeditor/factories/KexiStandardFormWidgetsFactory.cpp b/kexi/formeditor/factories/KexiStandardFormWidgetsFactory.cpp index 6b6129e0a2d..ebd81a4399e 100644 --- a/kexi/formeditor/factories/KexiStandardFormWidgetsFactory.cpp +++ b/kexi/formeditor/factories/KexiStandardFormWidgetsFactory.cpp @@ -1,1089 +1,1069 @@ /* This file is part of the KDE project Copyright (C) 2003 by Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2009-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 "KexiStandardFormWidgetsFactory.h" #include "KexiStandardFormWidgets.h" #include "KexiStandardContainerFormWidgets.h" #include "formIO.h" #include "form.h" #include "widgetlibrary.h" #include "objecttree.h" #include "WidgetInfo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT #include #endif #include #include #include #include #include #include #include #include #include #include #include #include KEXI_PLUGIN_FACTORY(KexiStandardFormWidgetsFactory, "kexiforms_standardwidgetsplugin.json") KexiStandardFormWidgetsFactory::KexiStandardFormWidgetsFactory(QObject *parent, const QVariantList &args) : KFormDesigner::WidgetFactory(parent) { Q_UNUSED(args); KFormDesigner::WidgetInfo *wFormWidget = new KFormDesigner::WidgetInfo(this); wFormWidget->setIconName(koIconName("form")); wFormWidget->setClassName("FormWidgetBase"); wFormWidget->setName(xi18n("Form")); wFormWidget->setNamePrefix( xi18nc("A prefix for identifiers of form widgets. Based on that, identifiers such as " "form1, form2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "form")); wFormWidget->setDescription(xi18n("A simple form widget")); addClass(wFormWidget); KFormDesigner::WidgetInfo *wCustomWidget = new KFormDesigner::WidgetInfo(this); wCustomWidget->setIconName(koIconName("unknown_widget")); wCustomWidget->setClassName("CustomWidget"); wCustomWidget->setName(/* no i18n needed */ "Custom Widget"); wCustomWidget->setNamePrefix(/* no i18n needed */ "customWidget"); wCustomWidget->setDescription(/* no i18n needed */ "A custom or non-supported widget"); addClass(wCustomWidget); KFormDesigner::WidgetInfo *wLabel = new KFormDesigner::WidgetInfo(this); wLabel->setIconName(koIconName("label")); wLabel->setClassName("QLabel"); wLabel->setName(/* no i18n needed */ "Text Label"); wLabel->setNamePrefix(/* no i18n needed */ "label"); wLabel->setDescription(/* no i18n needed */ "A widget to display text"); wLabel->setAutoSaveProperties(QList() << "text"); addClass(wLabel); KFormDesigner::WidgetInfo *wPixLabel = new KFormDesigner::WidgetInfo(this); wPixLabel->setIconName(koIconName("pixmaplabel")); wPixLabel->setClassName("KexiPictureLabel"); wPixLabel->setName(/* no i18n needed */ "Picture Label"); //! @todo Qt designer compatibility: maybe use this class when QLabel has a pixmap set...? wPixLabel->setSavingName("KexiPictureLabel"); wPixLabel->setNamePrefix(/* no i18n needed */ "picture"); wPixLabel->setDescription(/* no i18n needed */ "A widget to display pictures"); wPixLabel->setAutoSaveProperties(QList() << "pixmap"); addClass(wPixLabel); KFormDesigner::WidgetInfo *wLineEdit = new KFormDesigner::WidgetInfo(this); wLineEdit->setIconName(koIconName("lineedit")); wLineEdit->setClassName("QLineEdit"); wLineEdit->addAlternateClassName("KLineEdit"); wLineEdit->setIncludeFileName("qlineedit.h"); wLineEdit->setName(/* no i18n needed */ "Line Edit"); wLineEdit->setNamePrefix(/* no i18n needed */ "lineEdit"); wLineEdit->setDescription(/* no i18n needed */ "A widget to input text"); addClass(wLineEdit); KFormDesigner::WidgetInfo *wPushButton = new KFormDesigner::WidgetInfo(this); wPushButton->setIconName(koIconName("button")); wPushButton->setClassName("QPushButton"); wPushButton->addAlternateClassName("KPushButton"); wPushButton->setIncludeFileName("qpushbutton.h"); wPushButton->setName(/* no i18n needed */ "Push Button"); wPushButton->setNamePrefix(/* no i18n needed */ "button"); wPushButton->setDescription(/* no i18n needed */ "A simple push button to execute actions"); wPushButton->setAutoSaveProperties(QList() << "text"); addClass(wPushButton); KFormDesigner::WidgetInfo *wRadioButton = new KFormDesigner::WidgetInfo(this); wRadioButton->setIconName(koIconName("radio")); wRadioButton->setClassName("QRadioButton"); wRadioButton->setName(/* no i18n needed */ "Option Button"); wRadioButton->setNamePrefix(/* no i18n needed */ "option"); wRadioButton->setDescription(/* no i18n needed */ "An option button with text or pixmap label"); addClass(wRadioButton); KFormDesigner::WidgetInfo *wCheckBox = new KFormDesigner::WidgetInfo(this); wCheckBox->setIconName(koIconName("check")); wCheckBox->setClassName("QCheckBox"); wCheckBox->setName(/* no i18n needed */ "Check Box"); wCheckBox->setNamePrefix(/* no i18n needed */ "checkBox"); wCheckBox->setDescription(/* no i18n needed */ "A check box with text or pixmap label"); addClass(wCheckBox); KFormDesigner::WidgetInfo *wSpinBox = new KFormDesigner::WidgetInfo(this); wSpinBox->setIconName(koIconName("spin")); wSpinBox->setClassName("QSpinBox"); wSpinBox->addAlternateClassName("KIntSpinBox"); wSpinBox->setIncludeFileName("qspinbox.h"); wSpinBox->setName(/* no i18n needed */ "Spin Box"); wSpinBox->setNamePrefix(/* no i18n needed */ "spinBox"); wSpinBox->setDescription(/* no i18n needed */ "A spin box widget"); addClass(wSpinBox); KFormDesigner::WidgetInfo *wComboBox = new KFormDesigner::WidgetInfo(this); wComboBox->setIconName(koIconName("combo")); wComboBox->setClassName("KComboBox"); wComboBox->addAlternateClassName("QComboBox"); wComboBox->setIncludeFileName("KComboBox"); wComboBox->setName(/* no i18n needed */ "Combo Box"); wComboBox->setNamePrefix(/* no i18n needed */ "comboBox"); wComboBox->setDescription(/* no i18n needed */ "A combo box widget"); wComboBox->setAutoSaveProperties(QList() << "list_items"); addClass(wComboBox); -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT // Unused, commented-out in Kexi 2.9 to avoid unnecessary translations: // KFormDesigner::WidgetInfo *wListBox = new KFormDesigner::WidgetInfo(this); // wListBox->setIconName(koIconName("listbox")); // wListBox->setClassName("KListBox"); // wListBox->addAlternateClassName("QListBox"); // wListBox->addAlternateClassName("KListBox"); // wListBox->setIncludeFileName("qlistbox.h"); // wListBox->setName(xi18n("List Box")); // wListBox->setNamePrefix( // xi18nc("Widget name. This string will be used to name widgets of this class. " // "It must _not_ contain white spaces and non latin1 characters.", "listBox")); // wListBox->setDescription(xi18n("A simple list widget")); // wListBox->setAutoSaveProperties(QList() << "list_items"); // addClass(wListBox); // Unused, commented-out in Kexi 2.9 to avoid unnecessary translations: // KFormDesigner::WidgetInfo *wTreeWidget = new KFormDesigner::WidgetInfo(this); // wTreeWidget->setIconName(koIconName("listwidget")); // wTreeWidget->setClassName("QTreetWidget"); // //? wTreeWidget->addAlternateClassName("QListView"); // //? wTreeWidget->addAlternateClassName("KListView"); // wTreeWidget->setIncludeFileName("qtreewidget.h"); // wTreeWidget->setName(xi18n("List Widget")); // wTreeWidget->setNamePrefix( // xi18nc("Widget name. This string will be used to name widgets of this class. " // "It must _not_ contain white spaces and non latin1 characters.", "listWidget")); // wTreeWidget->setDescription(xi18n("A list (or tree) widget")); // wTreeWidget->setAutoSaveProperties(QList() << "list_contents"); // addClass(wTreeWidget); #endif KFormDesigner::WidgetInfo *wTextEdit = new KFormDesigner::WidgetInfo(this); wTextEdit->setIconName(koIconName("textedit")); wTextEdit->setClassName("KTextEdit"); wTextEdit->addAlternateClassName("QTextEdit"); wTextEdit->setIncludeFileName("KTextEdit"); wTextEdit->setName(/* no i18n needed */ "Text Editor"); wTextEdit->setNamePrefix(/* no i18n needed */ "textEditor"); wTextEdit->setDescription(/* no i18n needed */ "A simple single-page rich text editor"); wTextEdit->setAutoSaveProperties(QList() << "text"); addClass(wTextEdit); KFormDesigner::WidgetInfo *wSlider = new KFormDesigner::WidgetInfo(this); wSlider->setIconName(koIconName("slider")); wSlider->setClassName("QSlider"); wSlider->setName(/* no i18n needed */ "Slider"); wSlider->setNamePrefix(/* no i18n needed */ "slider"); wSlider->setDescription(/* no i18n needed */ "A Slider widget"); addClass(wSlider); KFormDesigner::WidgetInfo *wProgressBar = new KFormDesigner::WidgetInfo(this); wProgressBar->setIconName(koIconName("progress")); wProgressBar->setClassName("QProgressBar"); wProgressBar->setName(/* no i18n needed */ "Progress Bar"); wProgressBar->setNamePrefix(/* no i18n needed */ "progressBar"); wProgressBar->setDescription(/* no i18n needed */ "A progress indicator widget"); addClass(wProgressBar); KFormDesigner::WidgetInfo *wLine = new KFormDesigner::WidgetInfo(this); wLine->setIconName(koIconName("line")); wLine->setClassName("Line"); wLine->setName(xi18n("Line")); wLine->setNamePrefix( xi18nc("A prefix for identifiers of line widgets. Based on that, identifiers such as " "line1, line2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "line")); wLine->setDescription(xi18n("A line to be used as a separator")); wLine->setAutoSaveProperties(QList() << "orientation"); wLine->setInternalProperty("orientationSelectionPopup", true); wLine->setInternalProperty("orientationSelectionPopup:horizontalIcon", "line_horizontal"); wLine->setInternalProperty("orientationSelectionPopup:verticalIcon", "line_vertical"); wLine->setInternalProperty("orientationSelectionPopup:horizontalText", xi18n("Insert &Horizontal Line")); wLine->setInternalProperty("orientationSelectionPopup:verticalText", xi18n("Insert &Vertical Line")); addClass(wLine); KFormDesigner::WidgetInfo *wDate = new KFormDesigner::WidgetInfo(this); wDate->setIconName(koIconName("dateedit")); wDate->setClassName("QDateEdit"); wDate->addAlternateClassName("KDateWidget"); wDate->setIncludeFileName("qdateedit.h"); wDate->setName(/* no i18n needed */ "Date Widget"); wDate->setNamePrefix(/* no i18n needed */ "dateWidget"); wDate->setDescription(/* no i18n needed */ "A widget to input and display a date"); wDate->setAutoSaveProperties(QList() << "date"); addClass(wDate); KFormDesigner::WidgetInfo *wTime = new KFormDesigner::WidgetInfo(this); wTime->setIconName(koIconName("timeedit")); wTime->setClassName("QTimeEdit"); wTime->addAlternateClassName("KTimeWidget"); wTime->setIncludeFileName("qtimewidget.h"); wTime->setName(/* no i18n needed */ "Time Widget"); wTime->setNamePrefix(/* no i18n needed */ "timeWidget"); wTime->setDescription(/* no i18n needed */ "A widget to input and display a time"); wTime->setAutoSaveProperties(QList() << "time"); addClass(wTime); KFormDesigner::WidgetInfo *wDateTime = new KFormDesigner::WidgetInfo(this); wDateTime->setIconName(koIconName("datetimeedit")); wDateTime->setClassName("QDateTimeEdit"); wDateTime->addAlternateClassName("KDateTimeWidget"); wDateTime->setIncludeFileName("qdatetimewidget.h"); wDateTime->setName(/* no i18n needed */ "Date/Time Widget"); wDateTime->setNamePrefix(/* no i18n needed */ "dateTimeWidget"); wDateTime->setDescription(/* no i18n needed */ "A widget to input and display a time and a date"); wDateTime->setAutoSaveProperties(QList() << "dateTime"); addClass(wDateTime); setPropertyDescription("checkable", xi18nc("Property: Button is checkable", "On/Off")); setPropertyDescription("autoRepeat", xi18nc("Property: Button", "Auto Repeat")); setPropertyDescription("autoRepeatDelay", xi18nc("Property: Auto Repeat Button's Delay", "Auto Rep. Delay")); setPropertyDescription("autoRepeatInterval", xi18nc("Property: Auto Repeat Button's Interval", "Auto Rep. Interval")); // unused (too advanced) setPropertyDescription("autoDefault", xi18n("Auto Default")); // unused (too advanced) setPropertyDescription("default", xi18nc("Property: Button is default", "Default")); setPropertyDescription("flat", xi18nc("Property: Button is flat", "Flat")); setPropertyDescription("echoMode", xi18nc("Property: Echo mode for Line Edit widget eg. Normal, NoEcho, Password", "Echo Mode")); setPropertyDescription("indent", xi18n("Indent")); //line setPropertyDescription("orientation", xi18n("Orientation")); //checkbox setPropertyDescription("checked", xi18nc("Property: Checked checkbox", "Checked")); setPropertyDescription("tristate", xi18nc("Property: Tristate checkbox", "Tristate")); //for labels setPropertyDescription("textFormat", xi18n("Text Format")); setValueDescription("PlainText", xi18nc("For Text Format", "Plain")); setValueDescription("RichText", xi18nc("For Text Format", "Hypertext")); setValueDescription("AutoText", xi18nc("For Text Format", "Auto")); setValueDescription("LogText", xi18nc("For Text Format", "Log")); setPropertyDescription("openExternalLinks", xi18nc("property: Can open external links in label", "Open Ext. Links")); //QLineEdit setPropertyDescription("placeholderText", xi18nc("Property: line edit's placeholder text", "Placeholder Text")); setPropertyDescription("clearButtonEnabled", xi18nc("Property: Clear Button Enabled", "Clear Button")); //for EchoMode setPropertyDescription("passwordMode", xi18nc("Property: Password Mode for line edit", "Password Mode")); setPropertyDescription("squeezedTextEnabled", xi18nc("Property: Squeezed Text Mode for line edit", "Squeezed Text")); //KTextEdit setPropertyDescription("tabStopWidth", xi18n("Tab Stop Width")); setPropertyDescription("tabChangesFocus", xi18n("Tab Changes Focus")); setPropertyDescription("wrapPolicy", xi18n("Word Wrap Policy")); setValueDescription("AtWordBoundary", xi18nc("Property: For Word Wrap Policy", "At Word Boundary")); setValueDescription("Anywhere", xi18nc("Property: For Word Wrap Policy", "Anywhere")); setValueDescription("AtWordOrDocumentBoundary", xi18nc("Property: For Word Wrap Policy", "At Word Boundary If Possible")); setPropertyDescription("wordWrap", xi18n("Word Wrapping")); setPropertyDescription("wrapColumnOrWidth", xi18n("Word Wrap Position")); setValueDescription("NoWrap", xi18nc("Property: For Word Wrap Position", "None")); setValueDescription("WidgetWidth", xi18nc("Property: For Word Wrap Position", "Widget's Width")); setValueDescription("FixedPixelWidth", xi18nc("Property: For Word Wrap Position", "In Pixels")); setValueDescription("FixedColumnWidth", xi18nc("Property: For Word Wrap Position", "In Columns")); setPropertyDescription("linkUnderline", xi18n("Links Underlined")); setPropertyDescription("horizontalScrollBarPolicy", xi18n("Horizontal Scroll Bar")); setPropertyDescription("verticalScrollBarPolicy", xi18n("Vertical Scroll Bar")); //ScrollBarPolicy setValueDescription("ScrollBarAsNeeded", xi18nc("Property: Show Scroll Bar As Needed", "As Needed")); setValueDescription("ScrollBarAlwaysOff", xi18nc("Property: Scroll Bar Always Off", "Always Off")); setValueDescription("ScrollBarAlwaysOn", xi18nc("Property: Scroll Bar Always On", "Always On")); setPropertyDescription("acceptRichText", xi18nc("Property: Text Edit accepts rich text", "Rich Text")); setPropertyDescription("HTML", xi18nc("Property: HTML value of text edit", "HTML")); // --- containers --- KFormDesigner::WidgetInfo *wTabWidget = new KFormDesigner::WidgetInfo(this); wTabWidget->setIconName(koIconName("tabwidget")); wTabWidget->setClassName("KFDTabWidget"); wTabWidget->addAlternateClassName("KTabWidget"); wTabWidget->addAlternateClassName("QTabWidget"); wTabWidget->setSavingName("QTabWidget"); wTabWidget->setIncludeFileName("qtabwidget.h"); wTabWidget->setName(xi18n("Tab Widget")); wTabWidget->setNamePrefix( xi18nc("A prefix for identifiers of tab widgets. Based on that, identifiers such as " "tab1, tab2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "tabWidget")); wTabWidget->setDescription(xi18n("A widget to display multiple pages using tabs")); addClass(wTabWidget); KFormDesigner::WidgetInfo *wWidget = new KFormDesigner::WidgetInfo(this); wWidget->setIconName(koIconName("frame")); wWidget->setClassName("QWidget"); wWidget->addAlternateClassName("ContainerWidget"); wWidget->setName(/* no i18n needed */ "Basic container"); wWidget->setNamePrefix(/* no i18n needed */ "container"); wWidget->setDescription(/* no i18n needed */ "An empty container with no frame"); addClass(wWidget); KFormDesigner::WidgetInfo *wGroupBox = new KFormDesigner::WidgetInfo(this); wGroupBox->setIconName(koIconName("groupbox")); wGroupBox->setClassName("QGroupBox"); wGroupBox->addAlternateClassName("GroupBox"); wGroupBox->setName(xi18n("Group Box")); wGroupBox->setNamePrefix( xi18nc("A prefix for identifiers of group box widgets. Based on that, identifiers such as " "groupBox1, groupBox2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "groupBox")); wGroupBox->setDescription(xi18n("A container to group some widgets")); addClass(wGroupBox); KFormDesigner::WidgetInfo *wFrame = new KFormDesigner::WidgetInfo(this); wFrame->setIconName(koIconName("frame")); wFrame->setClassName("QFrame"); wFrame->setName(/* no i18n needed */ "Frame"); wFrame->setNamePrefix(/* no i18n needed */ "frame"); wFrame->setDescription(/* no i18n needed */ "A simple frame container"); addClass(wFrame); -//! @todo -#if 0 -// Unused, commented-out in Kexi 2.9 to avoid unnecessary translations: -// KFormDesigner::WidgetInfo *wSubForm = new KFormDesigner::WidgetInfo(this); -// wSubForm->setIconName(koIconName("form")); -// wSubForm->setClassName("SubForm"); -// wSubForm->setName(xi18n("Sub Form")); -// wSubForm->setNamePrefix( -// xi18nc("Widget name. This string will be used to name widgets of this class. " -// "It must _not_ contain white spaces and non latin1 characters.", "subForm")); -// wSubForm->setDescription(xi18n("A form widget included in another Form")); -// wSubForm->setAutoSyncForProperty("formName", false); -// addClass(wSubForm); -#endif - //groupbox setPropertyDescription("title", xi18nc("'Title' property for group box", "Title")); setPropertyDescription("flat", xi18nc("'Flat' property for group box", "Flat")); //tab widget setPropertyDescription("tabBarAutoHide", xi18n("Auto-hide Tabs")); setPropertyDescription("tabPosition", xi18n("Tab Position")); setPropertyDescription("currentIndex", xi18nc("'Current page' property for tab widget", "Current Page")); setPropertyDescription("tabShape", xi18n("Tab Shape")); setPropertyDescription("elideMode", xi18nc("Tab Widget's Elide Mode property", "Elide Mode")); setPropertyDescription("usesScrollButtons", xi18nc("Tab Widget's property: true if can use scroll buttons", "Scroll Buttons")); setPropertyDescription("tabsClosable", xi18n("Closable Tabs")); setPropertyDescription("movable", xi18n("Movable Tabs")); setPropertyDescription("documentMode", xi18n("Document Mode")); setValueDescription("Rounded", xi18nc("Property value for Tab Shape", "Rounded")); setValueDescription("Triangular", xi18nc("Property value for Tab Shape", "Triangular")); } KexiStandardFormWidgetsFactory::~KexiStandardFormWidgetsFactory() { } QWidget* KexiStandardFormWidgetsFactory::createWidget(const QByteArray &c, QWidget *p, const char *n, KFormDesigner::Container *container, CreateWidgetOptions options) { QWidget *w = 0; bool createContainer = false; QString text(container->form()->library()->textForWidgetName(n, c)); if (c == "QLabel") { w = new QLabel(text, p); } else if (c == "KexiPictureLabel") { w = new KexiPictureLabel(koDesktopIcon("image-x-generic"), p); } else if (c == "QLineEdit") { w = new QLineEdit(p); } else if (c == "QPushButton") { w = new QPushButton(text, p); } else if (c == "QRadioButton") { w = new QRadioButton(text, p); } else if (c == "QCheckBox") { w = new QCheckBox(text, p); } else if (c == "KIntSpinBox") { w = new QSpinBox(p); } else if (c == "KComboBox") { w = new KComboBox(p); } else if (c == "KTextEdit") { w = new KTextEdit(text, p); -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT } else if (c == "QTreeWidget") { QTreeWidget *tw = new QTreeWidget(p); w = tw; if (container->form()->interactiveMode()) { tw->setColumnCount(1); tw->setHeaderItem(new QTreeWidetItem(tw)); tw->headerItem()->setText(1, futureI18n("Column 1")); } lw->setRootIsDecorated(true); #endif } else if (c == "QSlider") { w = new QSlider(Qt::Horizontal, p); } else if (c == "QProgressBar") { w = new QProgressBar(p); } else if (c == "KDateWidget" || c == "QDateEdit") { w = new QDateEdit(QDate::currentDate(), p); } else if (c == "KTimeWidget" || c == "QTimeEdit") { w = new QTimeEdit(QTime::currentTime(), p); } else if (c == "KDateTimeWidget" || c == "QDateTimeEdit") { w = new QDateTimeEdit(QDateTime::currentDateTime(), p); } else if (c == "Line") { w = new Line(options & WidgetFactory::VerticalOrientation ? Qt::Vertical : Qt::Horizontal, p); } // --- containers --- else if (c == "KFDTabWidget") { KFDTabWidget *tab = new KFDTabWidget(container, p); w = tab; #if defined(USE_KTabWidget) tab->setTabReorderingEnabled(true); connect(tab, SIGNAL(movedTab(int,int)), this, SLOT(reorderTabs(int,int))); #endif qDebug() << "Creating ObjectTreeItem:"; container->form()->objectTree()->addItem(container->objectTree(), new KFormDesigner::ObjectTreeItem( container->form()->library()->displayName(c), n, tab, container)); } else if (c == "QWidget") { w = new ContainerWidget(p); w->setObjectName(n); new KFormDesigner::Container(container, w, p); return w; } else if (c == "QGroupBox") { QString text = container->form()->library()->textForWidgetName(n, c); w = new GroupBox(text, p); createContainer = true; } else if (c == "QFrame") { QFrame *frm = new QFrame(p); w = frm; frm->setLineWidth(2); frm->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); createContainer = true; } else if (c == "QStackedWidget" || /* compat */ c == "QWidgetStack") { QStackedWidget *stack = new QStackedWidget(p); w = stack; stack->setLineWidth(2); stack->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); qDebug() << "Creating ObjectTreeItem:"; container->form()->objectTree()->addItem(container->objectTree(), new KFormDesigner::ObjectTreeItem( container->form()->library()->displayName(c), n, stack, container)); if (container->form()->interactiveMode()) { AddStackPageAction(container, stack, 0).trigger(); // addStackPage(); } } else if (c == "HBox") { w = new HBox(p); createContainer = true; } else if (c == "VBox") { w = new VBox(p); createContainer = true; } else if (c == "Grid") { w = new Grid(p); createContainer = true; } else if (c == "HFlow") { w = new HFlow(p); createContainer = true; } else if (c == "VFlow") { w = new VFlow(p); createContainer = true; -//! @todo -#if 0 - } else if (c == "SubForm") { - w = new SubForm(container->form(), p); -#endif } if (w) { w->setObjectName(n); qDebug() << w << w->objectName() << "created"; } if (createContainer) { (void)new KFormDesigner::Container(container, w, container); } if (c == "KFDTabWidget") { // if we are loading, don't add this tab if (container->form()->interactiveMode()) { TabWidgetBase *tab = qobject_cast(w); AddTabAction(container, tab, 0).slotTriggered(); } } return w; } bool KexiStandardFormWidgetsFactory::previewWidget(const QByteArray &classname, QWidget *widget, KFormDesigner::Container *container) { if (classname == "QStackedWidget" || /* compat */ classname == "QWidgetStack") { QStackedWidget *stack = qobject_cast(widget); KFormDesigner::ObjectTreeItem *tree = container->form()->objectTree()->lookup( widget->objectName()); if (!tree->modifiedProperties()->contains("frameShape")) stack->setFrameStyle(QFrame::NoFrame); } return true; } bool KexiStandardFormWidgetsFactory::createMenuActions(const QByteArray &classname, QWidget *w, QMenu *menu, KFormDesigner::Container *container) { QWidget *pw = w->parentWidget(); if ((classname == "QLabel") || (classname == "KTextEdit")) { menu->addAction( new EditRichTextAction(container, w, menu, this) ); return true; } -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT else if (classname == "QTreeWidget") { menu->addAction(koIcon("document-properties"), xi18n("Edit Contents of List Widget"), this, SLOT(editListContents())); return true; } #endif else if (classname == "KFDTabWidget" || pw->parentWidget()->inherits("QTabWidget")) { //! @todo KEXI3 port this: setWidget(pw->parentWidget(), m_container->toplevel()); #if 0 if (pw->parentWidget()->inherits("QTabWidget")) { setWidget(pw->parentWidget(), m_container->toplevel()); } #endif TabWidgetBase *tab = qobject_cast(w); if (tab) { menu->addAction( new AddTabAction(container, tab, menu) ); menu->addAction( new RenameTabAction(container, tab, menu) ); menu->addAction( new RemoveTabAction(container, tab, menu) ); } return true; } else if ( (KexiUtils::objectIsA(pw, "QStackedWidget") || /* compat */ KexiUtils::objectIsA(pw, "QWidgetStack")) && !pw->parentWidget()->inherits("QTabWidget") ) { QStackedWidget *stack = qobject_cast(pw); //! @todo KEXI3 port this: setWidget( pw, container->form()->objectTree()->lookup(stack->objectName())->parent()->container() ); #if 0 setWidget( pw, container->form()->objectTree()->lookup(stack->objectName())->parent()->container() ); #endif KFormDesigner::Container *parentContainer = container->form()->objectTree()->lookup(stack->objectName())->parent()->container(); menu->addAction( new AddStackPageAction(parentContainer, pw, menu) ); menu->addAction( new RemoveStackPageAction(parentContainer, pw, menu) ); menu->addAction( new GoToStackPageAction(GoToStackPageAction::Previous, parentContainer, pw, menu) ); menu->addAction( new GoToStackPageAction(GoToStackPageAction::Next, parentContainer, pw, menu) ); return true; } return false; } bool KexiStandardFormWidgetsFactory::startInlineEditing(InlineEditorCreationArguments& args) { if (args.classname == "QLineEdit") { QLineEdit *lineedit = static_cast(args.widget); args.text = lineedit->text(); args.alignment = lineedit->alignment(); args.useFrame = true; return true; } else if (args.widget->inherits("QLabel")) { QLabel *label = static_cast(args.widget); if (label->textFormat() == Qt::RichText) { args.execute = false; EditRichTextAction(args.container, label, 0, this).trigger(); //! @todo } else { args.text = label->text(); args.alignment = label->alignment(); } return true; } else if (args.classname == "QPushButton") { QPushButton *push = static_cast(args.widget); QStyleOption option; option.initFrom(push); args.text = push->text(); const QRect r(push->style()->subElementRect( QStyle::SE_PushButtonContents, &option, push)); args.geometry = QRect(push->x() + r.x(), push->y() + r.y(), r.width(), r.height()); //! @todo this is typical alignment, can we get actual from the style? args.alignment = Qt::AlignCenter; args.transparentBackground = true; return true; } else if (args.classname == "QRadioButton") { QRadioButton *radio = static_cast(args.widget); QStyleOption option; option.initFrom(radio); args.text = radio->text(); const QRect r(radio->style()->subElementRect( QStyle::SE_RadioButtonContents, &option, radio)); args.geometry = QRect( radio->x() + r.x(), radio->y() + r.y(), r.width(), r.height()); return true; } else if (args.classname == "QCheckBox") { QCheckBox *check = static_cast(args.widget); QStyleOption option; option.initFrom(check); const QRect r(args.widget->style()->subElementRect( QStyle::SE_CheckBoxContents, &option, check)); args.geometry = QRect( check->x() + r.x(), check->y() + r.y(), r.width(), r.height()); return true; } else if (args.classname == "KComboBox" || args.classname == "QComboBox") { QStringList list; KComboBox *combo = qobject_cast(args.widget); for (int i = 0; i < combo->count(); i++) { list.append(combo->itemText(i)); } args.execute = false; if (editList(args.widget, list)) { qobject_cast(args.widget)->clear(); qobject_cast(args.widget)->addItems(list); } return true; } else if ( args.classname == "KTextEdit" || args.classname == "KDateTimeWidget" || args.classname == "KTimeWidget" || args.classname == "KDateWidget" || args.classname == "KIntSpinBox") { args.execute = false; disableFilter(args.widget, args.container); return true; } return false; } bool KexiStandardFormWidgetsFactory::clearWidgetContent(const QByteArray &classname, QWidget *w) { if (classname == "QLineEdit") qobject_cast(w)->clear(); -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT else if (classname == "QTreeWidget") qobject_cast(w)->clear(); #endif else if (classname == "KComboBox") qobject_cast(w)->clear(); else if (classname == "KTextEdit") qobject_cast(w)->clear(); else return false; return true; } bool KexiStandardFormWidgetsFactory::changeInlineText(KFormDesigner::Form *form, QWidget *widget, const QString &text, QString &oldText) { const QByteArray n(widget->metaObject()->className()); if (n == "KIntSpinBox") { oldText = QString::number(qobject_cast(widget)->value()); qobject_cast(widget)->setValue(text.toInt()); } else { oldText = widget->property("text").toString(); changeProperty(form, widget, "text", text); } return true; } void KexiStandardFormWidgetsFactory::resizeEditor(QWidget *editor, QWidget *widget, const QByteArray &classname) { QSize s = widget->size(); QPoint p = widget->pos(); QRect r; if (classname == "QRadioButton") { QStyleOption option; option.initFrom(widget); r = widget->style()->subElementRect( QStyle::SE_RadioButtonContents, &option, widget); p += r.topLeft(); s.setWidth(r.width()); } else if (classname == "QCheckBox") { QStyleOption option; option.initFrom(widget); r = widget->style()->subElementRect( QStyle::SE_CheckBoxContents, &option, widget); p += r.topLeft(); s.setWidth(r.width()); } else if (classname == "QPushButton") { QStyleOption option; option.initFrom(widget); r = widget->style()->subElementRect( QStyle::SE_PushButtonContents, &option, widget); p += r.topLeft(); s = r.size(); } editor->resize(s); editor->move(p); //! @todo KEXI3 /* from ContainerFactory::resizeEditor(QWidget *editor, QWidget *widget, const QByteArray &): QSize s = widget->size(); editor->move(widget->x() + 2, widget->y() - 5); editor->resize(s.width() - 20, widget->fontMetrics().height() + 10); */ } bool KexiStandardFormWidgetsFactory::saveSpecialProperty(const QByteArray &classname, const QString &name, const QVariant &, QWidget *w, QDomElement &parentNode, QDomDocument &domDoc) { if (name == "list_items" && classname == "KComboBox") { KComboBox *combo = qobject_cast(w); for (int i = 0; i < combo->count(); i++) { QDomElement item = domDoc.createElement("item"); KFormDesigner::FormIO::savePropertyElement(item, domDoc, "property", "text", combo->itemText(i)); parentNode.appendChild(item); } return true; } -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT else if (name == "list_contents" && classname == "QTreeWidget") { QTreeWidget *treewidget = qobject_cast(w); // First we save the columns QTreeWidgetItem *headerItem = treewidget->headerItem(); if (headerItem) { for (int i = 0; i < treewidget->columnCount(); i++) { QDomElement item = domDoc.createElement("column"); KFormDesigner::FormIO::savePropertyElement( item, domDoc, "property", "text", headerItem->text(i)); KFormDesigner::FormIO::savePropertyElement( item, domDoc, "property", "width", treewidget->columnWidth(i)); KFormDesigner::FormIO::savePropertyElement( item, domDoc, "property", "resizable", treewidget->header()->isResizeEnabled(i)); KFormDesigner::FormIO::savePropertyElement( item, domDoc, "property", "clickable", treewidget->header()->isClickEnabled(i)); KFormDesigner::FormIO::savePropertyElement( item, domDoc, "property", "fullwidth", treewidget->header()->isStretchEnabled(i)); parentNode.appendChild(item); } } // Then we save the list view items QTreeWidgetItem *item = listwidget->firstChild(); while (item) { saveListItem(item, parentNode, domDoc); item = item->nextSibling(); } return true; } #endif else if ((name == "title") && (w->parentWidget()->parentWidget()->inherits("QTabWidget"))) { TabWidgetBase *tab = qobject_cast(w->parentWidget()->parentWidget()); KFormDesigner::FormIO::savePropertyElement( parentNode, domDoc, "attribute", "title", tab->tabText(tab->indexOf(w))); } else if ((name == "stackIndex") && (KexiUtils::objectIsA(w->parentWidget(), "QStackedWidget") || /*compat*/ KexiUtils::objectIsA(w->parentWidget(), "QWidgetStack"))) { QStackedWidget *stack = qobject_cast(w->parentWidget()); KFormDesigner::FormIO::savePropertyElement( parentNode, domDoc, "attribute", "stackIndex", stack->indexOf(w)); } else return false; return true; } -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT void KexiStandardFormWidgetsFactory::saveListItem(QListWidgetItem *item, QDomNode &parentNode, QDomDocument &domDoc) { QDomElement element = domDoc.createElement("item"); parentNode.appendChild(element); // We save the text of each column for (int i = 0; i < item->listWidget()->columns(); i++) { KFormDesigner::FormIO::savePropertyElement( element, domDoc, "property", "text", item->text(i)); } // Then we save every sub items QListWidgetItem *child = item->firstChild(); while (child) { saveListItem(child, element, domDoc); child = child->nextSibling(); } } #endif bool KexiStandardFormWidgetsFactory::readSpecialProperty(const QByteArray &classname, QDomElement &node, QWidget *w, KFormDesigner::ObjectTreeItem *item) { const QString tag( node.tagName() ); const QString name( node.attribute("name") ); KFormDesigner::Form *form = item->container() ? item->container()->form() : item->parent()->container()->form(); if ((tag == "item") && (classname == "KComboBox")) { KComboBox *combo = qobject_cast(w); QVariant val = KFormDesigner::FormIO::readPropertyValue( form, node.firstChild().firstChild(), w, name); if (val.canConvert(QVariant::Pixmap)) combo->addItem(val.value(), QString()); else combo->addItem(val.toString()); return true; } -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT else if (tag == "column" && classname == "QTreeWidget") { QTreeWidget *tw = qobject_cast(w); int id = 0; for (QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling()) { QString prop = n.toElement().attribute("name"); QVariant val = KFormDesigner::FormIO::readPropertyValue(n.firstChild(), w, name); if (prop == "text") id = tw->addColumn(val.toString()); else if (prop == "width") tw->setColumnWidth(id, val.toInt()); else if (prop == "resizable") tw->header()->setResizeEnabled(val.toBool(), id); else if (prop == "clickable") tw->header()->setClickEnabled(val.toBool(), id); else if (prop == "fullwidth") tw->header()->setStretchEnabled(val.toBool(), id); } return true; } else if (tag == "item" && classname == "QTreeWidget") { QTreeWidget *tw = qobject_cast(w); readListItem(node, 0, tw); return true; } #endif else if ((name == "title") && (item->parent()->widget()->inherits("QTabWidget"))) { TabWidgetBase *tab = qobject_cast(w->parentWidget()); tab->addTab(w, node.firstChild().toElement().text()); item->addModifiedProperty("title", node.firstChild().toElement().text()); return true; } else if (name == "stackIndex" && (KexiUtils::objectIsA(w->parentWidget(), "QStackedWidget") || /*compat*/ KexiUtils::objectIsA(w->parentWidget(), "QWidgetStack"))) { QStackedWidget *stack = qobject_cast(w->parentWidget()); int index = KFormDesigner::FormIO::readPropertyValue(form, node.firstChild(), w, name).toInt(); stack->insertWidget(index, w); stack->setCurrentWidget(w); item->addModifiedProperty("stackIndex", index); return true; } return false; } -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT void KexiStandardFormWidgetsFactory::readTreeItem( QDomElement &node, QTreeWidgetItem *parent, QTreeWidget *treewidget) { QTreeWidgetItem *item; if (parent) item = new QTreeWidgetItem(parent); else item = new QTreeWidgetItem(treewidget); // We need to move the item at the end of the list QTreeWidgetItem *last; if (parent) last = parent->firstChild(); else last = treewidget->firstChild(); while (last->nextSibling()) last = last->nextSibling(); item->moveItem(last); int i = 0; for (QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling()) { QDomElement childEl = n.toElement(); QString prop = childEl.attribute("name"); QString tag = childEl.tagName(); // We read sub items if (tag == "item") { item->setOpen(true); readListItem(childEl, item, treewidget); } // and column texts else if (tag == "property" && prop == "text") { QVariant val = KFormDesigner::FormIO::readPropertyValue( n.firstChild(), treewidget, "item"); item->setText(i, val.toString()); i++; } } } #endif bool KexiStandardFormWidgetsFactory::isPropertyVisibleInternal(const QByteArray &classname, QWidget *w, const QByteArray &property, bool isTopLevel) { bool ok = true; if (classname == "FormWidgetBase") { if (property == "windowIconText" || property == "geometry" /*nonsense for toplevel widget*/) { return false; } } else if (classname == "CustomWidget") { } else if (classname == "KexiPictureLabel") { if ( property == "text" || property == "indent" || property == "textFormat" || property == "font" || property == "alignment") { return false; } } else if (classname == "QLabel") { if (property == "pixmap") return false; } else if (classname == "QLineEdit") { if (property == "vAlign") return false; } else if (classname == "KTextEdit") ok = KFormDesigner::WidgetFactory::advancedPropertiesVisible() || ( property != "undoDepth" && property != "undoRedoEnabled" //always true! && property != "dragAutoScroll" //always true! && property != "overwriteMode" //always false! && property != "resizePolicy" && property != "autoFormatting" //too complex #ifndef KEXI_SHOW_UNFINISHED && property != "paper" #endif ); else if (classname == "Line") { if ((property == "frameShape") || (property == "font") || (property == "margin")) return false; } else if (classname == "QCheckBox") { ok = KFormDesigner::WidgetFactory::advancedPropertiesVisible() || (property != "autoRepeat"); } else if (classname == "QRadioButton") { ok = KFormDesigner::WidgetFactory::advancedPropertiesVisible() || (property != "autoRepeat"); } else if (classname == "QPushButton") { //! @todo reenable autoDefault / default if the top level window is dialog... ok = KFormDesigner::WidgetFactory::advancedPropertiesVisible() || (property != "autoDefault" && property != "default"); } else if ( classname == "HBox" || classname == "VBox" || classname == "Grid" || classname == "HFlow" || classname == "VFlow") { return property == "objectName" || property == "geometry"; } else if (classname == "QGroupBox") { ok = #ifndef KEXI_SHOW_UNFINISHED /*! @todo Hidden for now in Kexi. "checkable" and "checked" props need adding a fake properties which will allow to properly work in design mode, otherwise child widgets become frozen when checked==true */ (KFormDesigner::WidgetFactory::advancedPropertiesVisible() || (property != "checkable" && property != "checked")) && #endif true; } else if (classname == "KFDTabWidget") { ok = (KFormDesigner::WidgetFactory::advancedPropertiesVisible() || (property != "tabReorderingEnabled" && property != "hoverCloseButton" && property != "hoverCloseButtonDelayed")); } return ok && WidgetFactory::isPropertyVisibleInternal(classname, w, property, isTopLevel); } -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT void KexiStandardFormWidgetsFactory::editListContents() { if (widget()->inherits("QTreeWidget")) editTreeWidget(qobject_cast(widget())); } #endif void KexiStandardFormWidgetsFactory::setPropertyOptions(KPropertySet& set, const KFormDesigner::WidgetInfo& info, QWidget *w) { Q_UNUSED(info); Q_UNUSED(w); if (set.contains("indent")) { set["indent"].setOption("min", -1); set["indent"].setOption("minValueText", xi18nc("default indent value", "default")); } } void KexiStandardFormWidgetsFactory::reorderTabs(int oldpos, int newpos) { KFDTabWidget *tabWidget = qobject_cast(sender()); KFormDesigner::ObjectTreeItem *tab = tabWidget->container()->form()->objectTree()->lookup(tabWidget->objectName()); if (!tab) return; tab->children()->move(oldpos, newpos); } KFormDesigner::ObjectTreeItem* KexiStandardFormWidgetsFactory::selectableItem( KFormDesigner::ObjectTreeItem* item) { if (item->parent() && item->parent()->widget()) { if (qobject_cast(item->parent()->widget())) { // tab widget's page return item->parent(); } } return item; } #include "KexiStandardFormWidgetsFactory.moc" diff --git a/kexi/formeditor/factories/KexiStandardFormWidgetsFactory.h b/kexi/formeditor/factories/KexiStandardFormWidgetsFactory.h index 92e6aa49086..28e9ef969e5 100644 --- a/kexi/formeditor/factories/KexiStandardFormWidgetsFactory.h +++ b/kexi/formeditor/factories/KexiStandardFormWidgetsFactory.h @@ -1,93 +1,93 @@ /* This file is part of the KDE project Copyright (C) 2003 by Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2009 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 KEXISTANDARDFORMWIDGETSFACTORY_H #define KEXISTANDARDFORMWIDGETSFACTORY_H #include #include #include #include #include "widgetfactory.h" #include "container.h" class QTreeWidgetItem; class QTreeWidget; class KPropertySet; //! Factory for all basic widgets, including Spring (not containers) class KexiStandardFormWidgetsFactory : public KFormDesigner::WidgetFactory { Q_OBJECT public: KexiStandardFormWidgetsFactory(QObject *parent, const QVariantList &args); ~KexiStandardFormWidgetsFactory(); virtual QWidget* createWidget(const QByteArray &classname, QWidget *parent, const char *name, KFormDesigner::Container *container, CreateWidgetOptions options = DefaultOptions); virtual bool createMenuActions(const QByteArray &classname, QWidget *w, QMenu *menu, KFormDesigner::Container *container); virtual bool startInlineEditing(InlineEditorCreationArguments& args); virtual bool previewWidget(const QByteArray &classname, QWidget *widget, KFormDesigner::Container *container); virtual bool clearWidgetContent(const QByteArray &classname, QWidget *w); virtual bool saveSpecialProperty(const QByteArray &classname, const QString &name, const QVariant &value, QWidget *w, QDomElement &parentNode, QDomDocument &parent); virtual bool readSpecialProperty(const QByteArray &classname, QDomElement &node, QWidget *w, KFormDesigner::ObjectTreeItem *item); virtual void setPropertyOptions(KPropertySet& set, const KFormDesigner::WidgetInfo& info, QWidget *w); //! Moved into public for EditRichTextAction bool editRichText(QWidget *w, QString &text) const { return KFormDesigner::WidgetFactory::editRichText(w, text); } //! Moved into public for EditRichTextAction void changeProperty(KFormDesigner::Form *form, QWidget *widget, const char *name, const QVariant &value) { KFormDesigner::WidgetFactory::changeProperty(form, widget, name, value); } public Q_SLOTS: -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT void editListContents(); #endif protected Q_SLOTS: void reorderTabs(int oldpos, int newpos); protected: KFormDesigner::ObjectTreeItem* selectableItem(KFormDesigner::ObjectTreeItem* item); virtual bool isPropertyVisibleInternal(const QByteArray &classname, QWidget *w, const QByteArray &property, bool isTopLevel); virtual bool changeInlineText(KFormDesigner::Form *form, QWidget *widget, const QString &text, QString &oldText); virtual void resizeEditor(QWidget *editor, QWidget *widget, const QByteArray &classname); -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT void saveTreeItem(QTreeWidgetItem *item, QDomNode &parentNode, QDomDocument &domDoc); void readTreeItem(QDomElement &node, QTreeWidgetItem *parent, QTreeWidget *treewidget); #endif }; #endif diff --git a/kexi/formeditor/form.cpp b/kexi/formeditor/form.cpp index c4c3084f7c3..81b2cd86397 100644 --- a/kexi/formeditor/form.cpp +++ b/kexi/formeditor/form.cpp @@ -1,2701 +1,2701 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-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 "form_p.h" #include "WidgetInfo.h" #include "FormWidget.h" #include "container.h" #include "objecttree.h" #include "formIO.h" #include "FormWidgetInterface.h" #include "widgetlibrary.h" #include "events.h" #include "utils.h" #include "widgetwithsubpropertiesinterface.h" #include "tabstopdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KFormDesigner; Form::Form(WidgetLibrary* library, Mode mode, KActionCollection &col, ActionGroup& group) : QObject(library) , d( new FormPrivate(this, library) ) { init(mode, col, group); } Form::Form(Form *parent) : QObject(parent->library()) , d( new FormPrivate(this, parent->library()) ) { init(parent->mode(), *parent->actionCollection(), *parent->widgetActionGroup()); } Form::~Form() { emit destroying(); delete d; } void Form::init(Mode mode, KActionCollection &col, KFormDesigner::ActionGroup &group) { d->mode = mode; d->features = 0; d->widgetActionGroup = &group; connect(&d->propertySet, SIGNAL(propertyChanged(KPropertySet&,KProperty&)), this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&))); connect(&d->propertySet, SIGNAL(propertyReset(KPropertySet&,KProperty&)), this, SLOT(slotPropertyReset(KPropertySet&,KProperty&))); d->collection = &col; } WidgetLibrary* Form::library() const { return d->library; } KActionCollection *Form::actionCollection() const { return d->collection; } KFormDesigner::ActionGroup* Form::widgetActionGroup() const { return d->widgetActionGroup; } void Form::setFeatures(Features features) { d->features = features; } Form::Features Form::features() const { return d->features; } QWidget* Form::widget() const { if (d->topTree) return d->topTree->widget(); else if (d->toplevel) return d->toplevel->widget(); else // preview form return d->widget; } FormWidget* Form::formWidget() const { return d->formWidget; } ObjectTree* Form::objectTree() const { return d->topTree; } QWidgetList* Form::selectedWidgets() const { return &(d->selected); } QWidget* Form::selectedWidget() const { return d->selected.count() == 1 ? d->selected.first() : 0; } void Form::setInteractiveMode(bool interactive) { d->interactive = interactive; } bool Form::interactiveMode() const { return d->interactive; } Form::Mode Form::mode() const { return d->mode; } bool Form::isModified() const { return d->modified; } void Form::setModified(bool set) { d->modified = set; emit modified(set); } int Form::gridSize() const { return d->gridSize; } void Form::setGridSize(int gridSize) { d->gridSize = gridSize; } int Form::defaultMargin() const { return 11; } int Form::defaultSpacing() const { return 6; } QString Form::filename() const { return d->filename; } void Form::setFilename(const QString &file) { d->filename = file; } void Form::clearUndoStack() { d->undoStack.clear(); } void Form::setUndoStackClean() { d->undoStack.setClean(); } #ifdef KFD_SIGSLOTS ConnectionBuffer* Form::connectionBuffer() const { return d->connBuffer; } void Form::setConnectionBuffer(ConnectionBuffer *b) { if (b != d->connBuffer) { delete d->connBuffer; } d->connBuffer = b; } #endif -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT PixmapCollection* Form::pixmapCollection() const { return d->pixcollection; } #endif void Form::setPixmapsStoredInline(bool set) { d->pixmapsStoredInline = set; } bool Form::pixmapsStoredInline() const { return d->pixmapsStoredInline; } ObjectTreeList* Form::tabStops() { return &(d->tabstops); } bool Form::autoTabStops() const { return d->autoTabstops; } void Form::setAutoTabStops(bool autoTab) { d->autoTabstops = autoTab; } QHash* Form::headerProperties() { return &d->headerProperties; } //////////////// Container -related functions /////////////////////// Container* Form::toplevelContainer() const { return d->toplevel; } void Form::createToplevel(QWidget *container, FormWidget *formWidget, const QByteArray &) { //qDebug() << "container= " << (container ? container->objectName() : "") // << " formWidget=" << formWidget; setFormWidget(formWidget); d->toplevel = new Container(0, container, this); d->toplevel->setObjectName(objectName()); d->topTree = new ObjectTree(xi18n("Form"), container->objectName(), container, d->toplevel); d->toplevel->setObjectTree(d->topTree); d->toplevel->setForm(this); //! @todo pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT d->pixcollection = new PixmapCollection(container->objectName(), this); #endif d->topTree->setWidget(container); //! @todo copy caption in Kexi from object's caption // d->topTree->addModifiedProperty("caption", name()); //d->topTree->addModifiedProperty("icon"); connect(container, SIGNAL(destroyed()), this, SLOT(formDeleted())); //qDebug() << "d->toplevel=" << d->toplevel; // alter the style delete d->designModeStyle; d->designModeStyle = 0; if (d->mode == DesignMode) { d->designModeStyle = new DesignModeStyle(d->topTree->widget()->style()->objectName()); d->designModeStyle->setParent(this); d->topTree->widget()->setStyle(d->designModeStyle); } } Container* Form::activeContainer() { if (d->selected.isEmpty()) return d->toplevel; ObjectTreeItem *it; if (d->selected.count() == 1) it = d->topTree->lookup(d->selected.last()->objectName()); else it = commonParentContainer(d->selected); if (!it) return 0; if (it->container()) return it->container(); else return it->parent()->container(); } ObjectTreeItem* Form::commonParentContainer(const QWidgetList& wlist) { // create a list of all widget parents QSet parents; foreach (QWidget *w, wlist) { parents.insert(w->parentWidget()); } QWidgetList parentsList(parents.toList()); removeChildrenFromList(parentsList); // one widget remains == the container we are looking for ObjectTreeItem *item; if (parentsList.count() == 1) { item = d->topTree->lookup(parentsList.first()->objectName()); } else { // we need to go one level up item = commonParentContainer(parentsList); } return item; } Container* Form::parentContainer(QWidget *w) const { if (!w) return 0; ObjectTreeItem *it = d->topTree->lookup(w->objectName()); if (!it || !it->parent()) return 0; if (it->parent()->container()) return it->parent()->container(); else return it->parent()->parent()->container(); } void Form::setMode(Mode mode) { d->mode = mode; if (d->mode == DesignMode) { d->designModeStyle = new DesignModeStyle(d->widget->style()->objectName()); d->designModeStyle->setParent(this); d->widget->setStyle(d->designModeStyle); return; } ObjectTreeHash hash(*(d->topTree->hash())); foreach (ObjectTreeItem *item, hash) { library()->previewWidget( item->widget()->metaObject()->className(), item->widget(), d->toplevel ); } d->widget = d->topTree->widget(); delete d->topTree; d->topTree = 0; delete d->toplevel; d->toplevel = 0; // alter the style delete d->designModeStyle; d->designModeStyle = 0; } ///////////////////////////// Selection stuff /////////////////////// void Form::selectWidget(QWidget *w, WidgetSelectionFlags flags) { if (!d->selectWidgetEnabled) return; d->selectWidgetEnabled = false; selectWidgetInternal(w, flags); d->selectWidgetEnabled = true; } void Form::selectWidgetInternal(QWidget *w, WidgetSelectionFlags flags) { if (!w) { selectWidget(widget()); return; } //qDebug() << "selected count=" << d->selected.count(); if (!d->selected.isEmpty()) { //qDebug() << "first=" << d->selected.first(); } //qDebug() << w; if (d->selected.count() == 1 && d->selected.first() == w) { return; } if (d->selected.isEmpty() || w == widget() || (d->selected.first() == widget())) { flags |= ReplacePreviousSelection; } //raise selected widget and all possible parents QWidget *wtmp = w; while (!(flags & DontRaise) && wtmp && wtmp->parentWidget() && (wtmp != widget())) { wtmp->raise(); if (d->resizeHandles.value( wtmp->objectName() )) d->resizeHandles.value( wtmp->objectName() )->raise(); wtmp = wtmp->parentWidget(); } if (wtmp) wtmp->setFocus(); if (flags & ReplacePreviousSelection) { d->selected.clear(); qDeleteAll(d->resizeHandles); d->resizeHandles.clear(); } d->selected.append(w); emitSelectionChanged(w, flags); emitActionSignals(); // WidgetStack and TabWidget pages widgets shouldn't have resize handles, but their parent //! @todo move special case to a factory? #if 0 if (!isTopLevelWidget(w) && w->parentWidget() && KexiUtils::objectIsA(w->parentWidget(), "QWidgetStack")) { w = w->parentWidget(); if (w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) w = w->parentWidget(); } #endif if (w && w != widget()) { ResizeHandleSet *handles = new ResizeHandleSet(w, this); d->resizeHandles.insert(w->objectName(), handles); connect(handles, SIGNAL(geometryChangeStarted()), parentContainer(w), SLOT(startChangingGeometryPropertyForSelectedWidget())); connect(handles, SIGNAL(geometryChanged(QRect)), parentContainer(w), SLOT(setGeometryPropertyForSelectedWidget(QRect))); } } void Form::selectWidgets(const QList& widgets, WidgetSelectionFlags flags) { int i = 0; const int count = widgets.count(); foreach (QWidget* widget, widgets) { if (i == 1) { flags |= AddToPreviousSelection; } if (i == (count - 1)) { flags = LastSelection; } selectWidget(widget, flags); } } QList Form::widgetsForNames(const QList& names) const { QList widgets; foreach (const QByteArray& name, names) { ObjectTreeItem* item = objectTree()->lookup(name); if (item) { //we're checking for item!=0 because the name could be of a form widget widgets.append(item->widget()); } } return widgets; } void Form::selectWidgets(const QList& names, WidgetSelectionFlags flags) { selectWidgets(widgetsForNames(names), flags); } bool Form::isTopLevelWidget(QWidget *w) const { /* should not be used, just check w==formWidget() instead? */ ObjectTreeItem *item = objectTree()->lookup(w->objectName()); if (!item) return true; return !item->parent(); } ResizeHandleSet* Form::resizeHandlesForWidget(QWidget* w) { return d->resizeHandles.value(w->objectName()); } void Form::deselectWidget(QWidget *w) { d->selected.removeOne(w); ResizeHandleSet *set = d->resizeHandles.take(w->objectName()); delete set; } void Form::selectFormWidget() { selectWidget(widget()); } void Form::clearSelection() { d->selected.clear(); qDeleteAll(d->resizeHandles); d->resizeHandles.clear(); emitSelectionChanged(0, DefaultWidgetSelectionFlags); emitActionSignals(); } void Form::setInsertionPoint(const QPoint &p) { d->insertionPoint = p; } QAction* Form::action(const QString& name) { if (name == KStandardAction::name(KStandardAction::Undo)) { QAction *a = d->internalCollection.action( name ); if (!a) { a = d->undoStack.createUndoAction(&d->internalCollection); // connect this action to the form instead of stack disconnect(a, SIGNAL(triggered()), &d->undoStack, SLOT(undo())); connect(a, SIGNAL(triggered()), this, SLOT(undo())); } return a; } else if (name == KStandardAction::name(KStandardAction::Redo)) { QAction *a = d->internalCollection.action( name ); if (!a) { a = d->undoStack.createRedoAction(&d->internalCollection); // connect this action to the form instead of stack disconnect(a, SIGNAL(triggered()), &d->undoStack, SLOT(redo())); connect(a, SIGNAL(triggered()), this, SLOT(redo())); } return a; } return d->collection->action(name); } void Form::emitActionSignals() { // Update menu and toolbar items if (selectedWidget()) { if (widget() == selectedWidget()) emitFormWidgetSelected(); else emitWidgetSelected( false ); } else if (selectedWidgets()) { emitWidgetSelected( true ); } } void Form::emitUndoActionSignals() { //! @todo pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT QAction *undoAction = d->collection->action(QLatin1String("edit_undo")); if (undoAction) emitUndoEnabled(undoAction->isEnabled(), undoAction->text()); QAction *redoAction = d->collection->action(QLatin1String("edit_redo")); if (redoAction) emitRedoEnabled(redoAction->isEnabled(), redoAction->text()); #endif } void Form::emitSelectionSignals() { if (!selectedWidgets()->isEmpty()) { emitSelectionChanged(selectedWidgets()->first(), DefaultWidgetSelectionFlags); } foreach (QWidget *w, *selectedWidgets()) { emitSelectionChanged(w, LastSelection); } } void Form::emitWidgetSelected(bool multiple) { enableFormActions(); // Enable edit actions d->enableAction("edit_copy", true); d->enableAction("edit_cut", true); d->enableAction("edit_delete", true); d->enableAction("clear_contents", true); // 'Align Widgets' menu d->enableAction("align_menu", multiple); d->enableAction("align_to_left", multiple); d->enableAction("align_to_right", multiple); d->enableAction("align_to_top", multiple); d->enableAction("align_to_bottom", multiple); d->enableAction("adjust_size_menu", true); d->enableAction("adjust_width_small", multiple); d->enableAction("adjust_width_big", multiple); d->enableAction("adjust_height_small", multiple); d->enableAction("adjust_height_big", multiple); d->enableAction("format_raise", true); d->enableAction("format_lower", true); QWidgetList *wlist = selectedWidgets(); bool fontEnabled = false; foreach (QWidget* w, *wlist) { if (-1 != w->metaObject()->indexOfProperty("font")) { fontEnabled = true; break; } } d->enableAction("format_font", fontEnabled); // If the widgets selected is a container, we enable layout actions if (!multiple) { if (!wlist->isEmpty()) { objectTree()->lookup(wlist->first()->objectName()); } } emit widgetSelected(true); } void Form::emitFormWidgetSelected() { d->enableAction("edit_copy", false); d->enableAction("edit_cut", false); d->enableAction("edit_delete", false); d->enableAction("clear_contents", false); // Disable format functions d->enableAction("align_menu", false); d->enableAction("align_to_left", false); d->enableAction("align_to_right", false); d->enableAction("align_to_top", false); d->enableAction("align_to_bottom", false); d->enableAction("adjust_size_menu", false); d->enableAction("format_raise", false); d->enableAction("format_lower", false); d->enableAction("format_font", false); enableFormActions(); emit formWidgetSelected(); } void Form::emitNoFormSelected() { disableWidgetActions(); // Disable 'Tools' actions d->enableAction("pixmap_collection", false); #ifdef KFD_SIGSLOTS if (d->features & EnableConnections) { d->enableAction("form_connections", false); } #endif d->enableAction("taborder", false); d->enableAction("change_style", true); // Disable items in 'File' if (d->features & EnableFileActions) { d->enableAction("file_save", false); d->enableAction("file_save_as", false); d->enableAction("preview_form", false); } emit noFormSelected(); } void Form::enableFormActions() { // Enable 'Tools' actions d->enableAction("pixmap_collection", true); #ifdef KFD_SIGSLOTS if (d->features & EnableConnections) { d->enableAction("form_connections", true); } #endif d->enableAction("taborder", true); d->enableAction("change_style", true); // Enable items in 'File' if (d->features & EnableFileActions) { d->enableAction("file_save", true); d->enableAction("file_save_as", true); d->enableAction("preview_form", true); } d->enableAction("edit_paste", true); //?? isPasteEnabled()); d->enableAction("edit_select_all", true); } void Form::disableWidgetActions() { // Disable edit actions d->enableAction("edit_copy", false); d->enableAction("edit_cut", false); d->enableAction("edit_delete", false); d->enableAction("clear_contents", false); // Disable format functions d->enableAction("align_menu", false); d->enableAction("align_to_left", false); d->enableAction("align_to_right", false); d->enableAction("align_to_top", false); d->enableAction("align_to_bottom", false); d->enableAction("adjust_size_menu", false); d->enableAction("format_raise", false); d->enableAction("format_lower", false); } /////////////////////////// Various slots and signals ///////////////////// void Form::formDeleted() { d->selected.clear(); d->resizeHandles.clear(); deleteLater(); } void Form::changeName(const QByteArray &oldname, const QByteArray &newname) { if (oldname == newname) return; if (d->topTree->rename(oldname, newname)) { #ifdef KFD_SIGSLOTS d->connBuffer->fixName(oldname, newname); #endif ResizeHandleSet *temp = d->resizeHandles.take(oldname); d->resizeHandles.insert(newname, temp); } else { // rename failed KMessageBox::sorry(widget()->topLevelWidget(), xi18n("Renaming widget \"%1\" to \"%2\" failed.", QString(oldname), QString(newname))); qWarning() << "widget" << newname << "already exists, reverting rename"; d->propertySet.changeProperty("objectName", oldname); } } void Form::emitChildAdded(ObjectTreeItem *item) { addWidgetToTabStops(item); emit childAdded(item); } void Form::emitChildRemoved(ObjectTreeItem *item) { d->tabstops.removeOne(item); #ifdef KFD_SIGSLOTS if (d->connBuffer) d->connBuffer->removeAllConnectionsForWidget(item->name()); #endif emit childRemoved(item); } const Command* Form::executingCommand() const { return d->executingCommand; } bool Form::addCommand(Command *command, AddCommandOption option) { setModified(true); if (option == DontExecuteCommand) { command->blockRedoOnce(); } const bool saveExecutingCommand = !d->executingCommand; if (saveExecutingCommand) d->executingCommand = command; d->undoStack.push(command); if (saveExecutingCommand) d->executingCommand = 0; //qDebug() << "ADDED:" << *command; return true; } void Form::emitUndoEnabled() { //! @todo pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT QAction *undoAction = d->collection->action(QLatin1String("edit_undo")); if (undoAction) emitUndoEnabled(undoAction->isEnabled(), undoAction->text()); #endif } void Form::emitRedoEnabled() { //! @todo pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT QAction *redoAction = d->collection->action(QLatin1String("edit_redo")); if (redoAction) emitRedoEnabled(redoAction->isEnabled(), redoAction->text()); #endif } void Form::slotFormRestored() { setModified(false); } /////////////////////////// Tab stops //////////////////////// void Form::addWidgetToTabStops(ObjectTreeItem *it) { QWidget *w = it->widget(); if (!w) return; if (!(w->focusPolicy() & Qt::TabFocus)) { // For composed widgets, we check if one of the child can have focus const QObjectList list(w->children()); foreach(const QObject *obj, list) { if (obj->isWidgetType()) {//QWidget::TabFocus flag will be checked later! if (!d->tabstops.contains(it)) { //qDebug() << "adding child of" << w << ":" << obj; d->tabstops.append(it); return; } } } } else if (!d->tabstops.contains(it)) { // not yet in the list //qDebug() << "adding" << w; d->tabstops.append(it); } } void Form::updateTabStopsOrder() { ObjectTreeList newList(d->tabstops); foreach (ObjectTreeItem *item, d->tabstops) { if (!(item->widget()->focusPolicy() & Qt::TabFocus)) { //qDebug() << "Widget removed because has no TabFocus:" //. << item->widget()->objectName(); newList.removeOne(item); } } d->tabstops = newList; } //! Collects all the containers reculsively. Used by Form::autoAssignTabStops(). static void collectContainers(ObjectTreeItem* item, QSet& containers) { if (!item->container()) return; if (!containers.contains(item->container())) { //qDebug() << item->container()->objectTree()->className() // << " " << item->container()->objectTree()->name(); containers.insert(item->container()); } foreach (ObjectTreeItem *child, *item->children()) { collectContainers(child, containers); } } void Form::autoAssignTabStops() { VerticalWidgetList list(toplevelContainer()->widget()); HorizontalWidgetList hlist(toplevelContainer()->widget()); // 1. Collect all the containers, as we'll be sorting widgets groupped by containers QSet containers; collectContainers(toplevelContainer()->objectTree(), containers); foreach (ObjectTreeItem *item, d->tabstops) { if (item->widget()) { //qDebug() << "Widget to sort: " << item->widget(); list.append(item->widget()); } } list.sort(); //foreach (QWidget *w, list) { // qDebug() << w->metaObject()->className() << w->objectName(); //} d->tabstops.clear(); /// We automatically sort widget from the top-left to bottom-right corner //! \todo Handle RTL layout (ie from top-right to bottom-left) for (QWidgetList::ConstIterator it(list.constBegin()); it!=list.constEnd(); ++it) { QWidget *w = *it; hlist.append(w); ++it; QWidget *nextw = it==list.constEnd() ? 0 : *it; Q_UNUSED(nextw); QObject *page_w = 0; KFormDesigner::TabWidget *tab_w = KFormDesigner::findParent( w, "KFormDesigner::TabWidget", page_w); for (; it!=list.constEnd(); ++it) { QWidget *nextw = *it; if (KDbUtils::hasParent(w, nextw)) // do not group (sort) widgets where one is a child of another break; if (nextw->y() >= (w->y() + 20)) break; if (tab_w) { QObject *page_nextw = 0; KFormDesigner::TabWidget *tab_nextw = KFormDesigner::findParent( nextw, "KFormDesigner::TabWidget", page_nextw); if (tab_w == tab_nextw) { if (page_w != page_nextw) // 'nextw' widget within different tab page break; } } hlist.append(nextw); } hlist.sort(); foreach (QWidget *w, hlist) { ObjectTreeItem *tree = d->topTree->lookup(w->objectName()); if (tree) { //qDebug() << "adding " << tree->name(); d->tabstops.append(tree); } } --it; hlist.clear(); } } int Form::formatVersion() const { return d->formatVersion; } void Form::setFormatVersion(int ver) { d->formatVersion = ver; } int Form::originalFormatVersion() const { return d->originalFormatVersion; } void Form::setOriginalFormatVersion(int ver) { d->originalFormatVersion = ver; } void Form::setFormWidget(FormWidget* w) { d->formWidget = w; if (!d->formWidget) return; d->formWidget->setForm(this); } void Form::enterWidgetInsertingState(const QByteArray &classname) { if (d->state != WidgetInserting) { enterWidgetSelectingState(); } d->state = WidgetInserting; if (toplevelContainer()) { widget()->setCursor(QCursor(Qt::CrossCursor)); } const QList list(widget()->findChildren()); foreach (QWidget *w, list) { d->cursors.insert(w, w->cursor()); w->setCursor(QCursor(Qt::CrossCursor)); } d->selectedClass = classname; QAction *pointer_action = d->collection->action(QLatin1String("edit_pointer")); if (pointer_action) { pointer_action->setChecked(false); } } QByteArray Form::selectedClass() const { return d->selectedClass; } void Form::abortWidgetInserting() { if (d->state != WidgetInserting) return; widget()->unsetCursor(); const QList list(widget()->findChildren()); foreach (QWidget *w, list) { w->unsetCursor(); } d->state = WidgetSelecting; QAction *pointer_action = d->widgetActionGroup->action(QLatin1String("edit_pointer")); if (pointer_action) { pointer_action->setChecked(true); } } void Form::enterWidgetSelectingState() { switch (d->state) { case WidgetInserting: abortWidgetInserting(); break; #ifdef KFD_SIGSLOTS case Connecting: abortCreatingConnection(); break; #endif default: break; } } #ifdef KFD_SIGSLOTS void Form::enterConnectingState() { if (!(d->features & EnableConnections)) return; enterWidgetSelectingState(); // We set a Pointing hand cursor while drawing the connection d->mouseTrackers = new QStringList(); if (toplevelContainer()) { widget()->setCursor(QCursor(Qt::PointingHandCursor)); widget()->setMouseTracking(true); } const QList list(widget()->findChildren()); foreach(QWidget *w, list) { d->cursors.insert(w, w->cursor()); w->setCursor(QCursor(Qt::PointingHandCursor)); if (w->hasMouseTracking()) d->mouseTrackers->append(w->objectName()); w->setMouseTracking(true); } delete m_connection; m_connection = new Connection(); m_drawingSlot = true; if (m_dragConnection) m_dragConnection->setChecked(true); } void Form::resetSelectedConnection() { //! @todo if (!(d->features & EnableConnections)) return; delete m_connection; m_connection = new Connection(); if (formWidget()) { formWidget()->clearForm(); } if (widget()) { widget()->repaint(); } } void Form::abortCreatingConnection() { //! @todo if (!(d->features & EnableConnections)) return; if (d->state != Connecting) return; if (formWidget()) { formWidget()->clearForm(); } widget()->unsetCursor(); widget()->setMouseTracking(false); const QList list(widget()->findChildren()); foreach (QWidget *w, list) { QHash::ConstIterator curIt(d->cursors.find(w)); if (curIt != d->cursors.constEnd()) w->setCursor(*curIt); w->setMouseTracking(d->mouseTrackers->contains(w->objectName())); } delete d->mouseTrackers; d->mouseTrackers = 0; if (m_connection->slot().isNull()) emit connectionAborted(this); delete m_connection; m_connection = 0; m_drawingSlot = false; QAction *pointer_action = d->widgetActionGroup->action(QLatin1String("edit_pointer")); if (pointer_action) { pointer_action->setChecked(true); } } #endif Form::State Form::state() const { return d->state; } void Form::addPropertyCommand(const QByteArray &wname, const QVariant &oldValue, const QVariant &value, const QByteArray &propertyName, AddCommandOption addOption, int idOfPropertyCommand) { QHash oldValues; oldValues.insert(wname, oldValue); addPropertyCommand(oldValues, value, propertyName, addOption, idOfPropertyCommand); } void Form::addPropertyCommand(const QHash &oldValues, const QVariant &value, const QByteArray &propertyName, AddCommandOption addOption, int idOfPropertyCommand) { //! @todo add to merge in PropertyCommand... #if 0 qDebug() << d->propertySet[propertyName]; qDebug() << "oldValue:" << oldValues << "value:" << value; qDebug() << "idOfPropertyCommand:" << idOfPropertyCommand; d->insideAddPropertyCommand = true; PropertyCommand *presentCommand = dynamic_cast( d->commandHistory->presentCommand() ); if ( presentCommand && d->lastCommand == presentCommand && idOfPropertyCommand > 0 && d->idOfPropertyCommand == idOfPropertyCommand) { d->lastCommand->setValue(value); // just change the value, // to avoid multiple PropertyCommands that only differ by value } else { d->lastCommand = new PropertyCommand(*this, oldValues, value, propertyName); if (!addCommand(d->lastCommand, execute)) { d->lastCommand = 0; } d->idOfPropertyCommand = idOfPropertyCommand; } d->insideAddPropertyCommand = false; #endif d->insideAddPropertyCommand = true; d->lastCommand = new PropertyCommand(*this, oldValues, value, propertyName); d->lastCommand->setUniqueId(idOfPropertyCommand); //qDebug() << "ADD:" << *d->lastCommand; if (!addCommand(d->lastCommand, addOption)) { d->lastCommand = 0; } d->insideAddPropertyCommand = false; } void Form::addPropertyCommandGroup(PropertyCommandGroup *commandGroup, AddCommandOption addOption, int idOfPropertyCommand) { //! @todo add to merge in PropertyCommand...? #if 0 if (!commandGroup || commandGroup->commands().isEmpty()) return; qDebug() << "count:" << commandGroup->commands().count(); qDebug() << "idOfPropertyCommand:" << idOfPropertyCommand; d->insideAddPropertyCommand = true; PropertyCommandGroup *presentCommand = dynamic_cast( d->commandHistory->presentCommand() ); if ( presentCommand && d->lastCommandGroup == presentCommand && idOfPropertyCommand > 0 && d->idOfPropertyCommand == idOfPropertyCommand) { presentCommand->copyPropertyValuesFrom(*commandGroup); // just change the values, // to avoid multiple CommandsGroups // that only differ by values delete commandGroup; } else { d->lastCommandGroup = commandGroup; addCommand(d->lastCommandGroup, execute); d->idOfPropertyCommand = idOfPropertyCommand; } #endif d->insideAddPropertyCommand = true; d->lastCommandGroup = commandGroup; if (!addCommand(d->lastCommandGroup, addOption)) { d->lastCommandGroup = 0; } d->idOfPropertyCommand = idOfPropertyCommand; d->insideAddPropertyCommand = false; } void Form::slotPropertyChanged(KPropertySet& set, KProperty& p) { Q_UNUSED(set); if (!d->slotPropertyChangedEnabled || !objectTree()) return; const QByteArray property( p.name() ); if (property.startsWith("this:")) return; //starts with magical prefix: it's a "meta" prop. const QVariant value( p.value() ); // check if the name is valid (ie is correct identifier) and there is no name conflict if (property == "objectName") { if (d->selected.count() != 1) { qWarning() << "changing objectName property only allowed for single selection"; return; } if (!isNameValid(value.toString())) return; } else if (property == "paletteBackgroundPixmap") { // a widget with a background pixmap should have its own origin // special types of properties handled separately } else if (property == "paletteBackgroundColor") { d->setColorProperty(p, &QWidget::backgroundRole, p.value()); return; } else if (property == "paletteForegroundColor") { d->setColorProperty(p, &QWidget::foregroundRole, p.value()); return; } else if (property == "autoFillBackground") { if (!p.value().toBool()) { // make background inherited d->setColorProperty(p, &QWidget::backgroundRole, QVariant()); } } else if (property == "hAlign" || property == "vAlign" || property == "wordbreak") { saveAlignProperty(property); return; } // make sure we are not already undoing -> avoid recursion if (d->isUndoing && !d->isRedoing) { return; } if (d->selected.count() == 1) { // one widget selected // If the last command is the same, we just change its value //! @todo add to merge in PropertyCommand if needed if (d->slotPropertyChanged_addCommandEnabled && !d->isRedoing) { addPropertyCommand(d->selected.first()->objectName().toLatin1(), p.oldValue(), value, property, DontExecuteCommand); } // If the property is changed, we add it in ObjectTreeItem modifProp ObjectTreeItem *tree = objectTree()->lookup(d->selected.first()->objectName()); if (tree && p.isModified()) { tree->addModifiedProperty(property, d->selected.first()->property(property)); } if (property == "objectName") { changeName(d->selected.first()->objectName().toLatin1(), p.value().toByteArray()); emit widgetNameChanged(d->selected.first()->objectName().toLatin1(), p.value().toByteArray()); } d->selected.first()->setProperty(property, value); handleWidgetPropertyChanged(d->selected.first(), property, value); } else { //! @todo add to merge in PropertyCommand if needed if (d->slotPropertyChanged_addCommandEnabled && !d->isRedoing) { // We store old values for each widget QHash oldValues; foreach(QWidget* widget, d->selected) { oldValues.insert(widget->objectName().toLatin1(), widget->property(property)); } addPropertyCommand(oldValues, value, property, DontExecuteCommand); } foreach(QWidget* widget, d->selected) { ObjectTreeItem *titem = objectTree()->lookup(widget->objectName()); if (titem && p.isModified()) titem->addModifiedProperty(property, widget->property(property)); widget->setProperty(property, value); handleWidgetPropertyChanged(widget, property, value); } } } void Form::slotPropertyReset(KPropertySet& set, KProperty& property) { Q_UNUSED(set); if (d->selected.count() < 2) return; // We use the old value in modifProp for each widget foreach(QWidget* widget, d->selected) { ObjectTreeItem *titem = objectTree()->lookup(widget->objectName()); if (titem && titem->modifiedProperties()->contains(property.name())) widget->setProperty( property.name(), titem->modifiedProperties()->find(property.name()).value()); } } bool Form::isNameValid(const QString &name) const { if (d->selected.isEmpty()) return false; //! @todo add to the undo buffer QWidget *w = d->selected.first(); //also update widget's name in QObject member if (!KDb::isIdentifier(name)) { KMessageBox::sorry(widget(), xi18n("Could not rename widget \"%1\" to \"%2\" because " "\"%3\" is not a valid name (identifier) for a widget.", w->objectName(), name, name)); d->slotPropertyChangedEnabled = false; d->propertySet["objectName"].resetValue(); d->slotPropertyChangedEnabled = true; return false; } if (objectTree()->lookup(name)) { KMessageBox::sorry(widget(), xi18n("Could not rename widget \"%1\" to \"%2\" " "because a widget with the name \"%3\" already exists.", w->objectName(), name, name)); d->slotPropertyChangedEnabled = false; d->propertySet["objectName"].resetValue(); d->slotPropertyChangedEnabled = true; return false; } return true; } void Form::undo() { if (!objectTree()) return; if (!d->undoStack.canUndo()) { qWarning() << "cannot redo"; return; } const bool saveExecutingCommand = !d->executingCommand; //qDebug() << "saveExecutingCommand:" << saveExecutingCommand; if (saveExecutingCommand) d->executingCommand = dynamic_cast(d->undoStack.command(0)); //qDebug() << d->undoStack.index(); //qDebug() << d->executingCommand; d->undoStack.undo(); if (saveExecutingCommand) d->executingCommand = 0; } void Form::redo() { if (!objectTree()) return; if (!d->undoStack.canRedo()) { qWarning() << "cannot redo"; return; } d->isRedoing = true; const bool saveExecutingCommand = !d->executingCommand; //qDebug() << "saveExecutingCommand:" << saveExecutingCommand; if (saveExecutingCommand) d->executingCommand = dynamic_cast(d->undoStack.command(d->undoStack.index())); //qDebug() << d->undoStack.index(); //qDebug() << *d->executingCommand; d->undoStack.redo(); if (saveExecutingCommand) d->executingCommand = 0; d->isRedoing = false; } bool Form::isRedoing() const { return d->isRedoing; } void Form::setUndoing(bool undoing) { d->isUndoing = undoing; } bool Form::isUndoing() const { return d->isUndoing; } bool Form::isPropertyVisible(const QByteArray &property, bool isTopLevel, const QByteArray &classname) const { const bool multiple = d->selected.count() >= 2; if (multiple && classname.isEmpty()) return false; QWidget *w = d->selected.first(); WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(w); QWidget *subwidget; if (subpropIface && subpropIface->findMetaSubproperty(property).isValid()) // special case - subproperty subwidget = subpropIface->subwidget(); else subwidget = w; return library()->isPropertyVisible( subwidget->metaObject()->className(), subwidget, property, multiple, isTopLevel); } void Form::addWidget(QWidget *w) { d->selected.append(w); // Reset some stuff d->lastCommand = 0; d->lastCommandGroup = 0; QByteArray classname; if (d->selected.first()->metaObject()->className() == w->metaObject()->className()) { classname = d->selected.first()->metaObject()->className(); } // show only properties shared by widget (properties chosen by factory) bool isTopLevel = isTopLevelWidget(w); for (KPropertySetIterator it(d->propertySet); it.current(); ++it) { //qDebug() << it.current(); if (!isPropertyVisible(it.current()->name(), isTopLevel, classname)) { it.current()->setVisible(false); } } if (d->selected.count() >= 2) { //second widget, update metainfo d->propertySet["this:className"].setValue("special:multiple"); d->propertySet["this:classString"].setValue( xi18n("Multiple Widgets (%1)", d->selected.count())); d->propertySet["this:iconName"].setValue("multiple_obj"); //name doesn't make sense for now d->propertySet["objectName"].setValue(""); } } void Form::createPropertiesForWidget(QWidget *w) { d->propertySet.clear(); if (!objectTree()) { qWarning() << "no object tree!"; return; } ObjectTreeItem *tree = objectTree()->lookup(w->objectName()); if (!tree) return; const QHash* modifiedProperties = tree->modifiedProperties(); QHash::ConstIterator modifiedPropertiesIt; bool isTopLevel = isTopLevelWidget(w); KProperty *newProp = 0; WidgetInfo *winfo = library()->widgetInfoForClassName(w->metaObject()->className()); if (!winfo) { qWarning() << "no widget info for class" << w->metaObject()->className(); return; } //! @todo ineffective, get property names directly const QList propList( KexiUtils::propertiesForMetaObjectWithInherited(w->metaObject())); //qDebug() << "propList.count() ==" << propList.count(); QSet propNames; foreach(const QMetaProperty& mp, propList) { propNames.insert(mp.name()); } // add subproperties if available WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(w); if (subpropIface) { const QSet subproperties(subpropIface->subproperties()); foreach(const QByteArray& propName, subproperties) { propNames.insert(propName); //qDebug() << "Added subproperty: " << propName; } } // iterate over the property list, and create Property objects foreach(const QByteArray& propName, propNames) { //qDebug() << ">> " << propName; const QMetaProperty subMeta = // special case - subproperty subpropIface ? subpropIface->findMetaSubproperty(propName) : QMetaProperty(); const QMetaProperty meta = subMeta.isValid() ? subMeta : KexiUtils::findPropertyWithSuperclasses(w, propName.constData()); if (!meta.isValid()) { //qDebug() << "!meta.isValid()"; continue; } const char* propertyName = meta.name(); QWidget *subwidget = subMeta.isValid()//subpropIface ? subpropIface->subwidget() : w; WidgetInfo *subwinfo = library()->widgetInfoForClassName( subwidget->metaObject()->className()); // qDebug() << "$$$ " << subwidget->className(); if ( subwinfo && meta.isDesignable(subwidget) && meta.isWritable() && meta.isReadable() && !d->propertySet.contains(propertyName) ) { //! \todo add another list for property description QString desc(d->propCaption.value(meta.name())); //! \todo change i18n if (desc.isEmpty()) { //try to get property description from factory desc = library()->propertyDescForName(subwinfo, propertyName); } modifiedPropertiesIt = modifiedProperties->find(propertyName); const bool oldValueExists = modifiedPropertiesIt != modifiedProperties->constEnd(); if (meta.isEnumType()) { if (qstrcmp(propertyName, "alignment") == 0) { createAlignProperty(meta, w, subwidget); continue; } QStringList keys(KexiUtils::enumKeysForProperty(meta)); newProp = new KProperty( propertyName, d->createValueList(subwinfo, keys), // assign current or older value meta.enumerator().valueToKey( oldValueExists ? modifiedPropertiesIt.value().toInt() : subwidget->property(propertyName).toInt()), desc, desc); //now set current value, so the old one is stored as old if (oldValueExists) { newProp->setValue( meta.enumerator().valueToKey(subwidget->property(propertyName).toInt())); } } else { int realType = subwinfo->customTypeForProperty(propertyName); if (realType == KProperty::Invalid || realType == KProperty::Auto) { realType = meta.type(); } newProp = new KProperty( propertyName, // assign current or older value oldValueExists ? modifiedPropertiesIt.value() : subwidget->property(propertyName), desc, desc, realType ); //now set current value, so the old one is stored as old if (oldValueExists) { newProp->setValue(subwidget->property(propertyName)); } } if (!isPropertyVisible(propertyName, isTopLevel)) newProp->setVisible(false); //! @todo if (newProp->type() == KProperty::Invalid) { newProp->setType(KProperty::String); } d->propertySet.addProperty(newProp); } // update the Property.oldValue() and isModified() using the value stored in the ObjectTreeItem updatePropertyValue(tree, propertyName, meta); } const QString paletteBackgroundColorDesc(d->propCaption.value("paletteBackgroundColor")); newProp = new KProperty("paletteBackgroundColor", w->palette().color(w->backgroundRole()), paletteBackgroundColorDesc, paletteBackgroundColorDesc); const QString paletteForegroundColorDesc(d->propCaption.value("paletteForegroundColor")); d->propertySet.addProperty(newProp); newProp = new KProperty("paletteForegroundColor", w->palette().color(w->foregroundRole()), paletteForegroundColorDesc, paletteForegroundColorDesc); d->propertySet.addProperty(newProp); d->propertySet["objectName"].setAutoSync(false); // name should be updated only when pressing Enter if (winfo) { library()->setPropertyOptions(d->propertySet, *winfo, w); d->propertySet.addProperty(newProp = new KProperty("this:classString", winfo->name())); newProp->setVisible(false); d->propertySet.addProperty(newProp = new KProperty("this:iconName", winfo->iconName())); newProp->setVisible(false); } d->propertySet.addProperty(newProp = new KProperty("this:className", w->metaObject()->className())); newProp->setVisible(false); } void Form::updatePropertyValue(ObjectTreeItem *tree, const char *property, const QMetaProperty &meta) { Q_UNUSED(tree); Q_UNUSED(property); Q_UNUSED(meta); return; //! @todo ???? #if 0 const char *propertyName = meta.isValid() ? meta.name() : property; if (!d->propertySet.contains(propertyName)) return; KProperty &p = d->propertySet[propertyName]; //! \todo what about set properties, and lists properties const QHash::ConstIterator it(tree->modifiedProperties()->find(propertyName)); if (it != tree->modifiedProperties()->constEnd()) { blockSignals(true); if (meta.isValid() && meta.isEnumType()) { p.setValue(meta.enumerator().valueToKey(it.value().toInt()), false); } else { p.setValue(it.value(), false); } p.setValue(p.value(), true); blockSignals(false); } #endif } //! @todo what about 'forceReload' arg? It's not passed to updatePropertiesForSelection() now... void Form::emitSelectionChanged(QWidget *w, WidgetSelectionFlags flags) { updatePropertiesForSelection(w, flags); emit selectionChanged(w, flags); } void Form::updatePropertiesForSelection(QWidget *w, WidgetSelectionFlags flags) { if (!w) { //! @todo clearSet()? return; } // if our list is empty,don't use add parameter value if (d->selected.isEmpty() == 0) { flags |= ReplacePreviousSelection; } QByteArray prevProperty; if (flags & ReplacePreviousSelection) { createPropertiesForWidget(w); w->installEventFilter(this); connect(w, SIGNAL(destroyed()), this, SLOT(widgetDestroyed())); } else { addWidget(w); } if (flags & LastSelection) { emit propertySetSwitched(); } } KPropertySet* Form::propertySet() { return &d->propertySet; } bool Form::isSnapToGridEnabled() const { return d->snapToGrid; } void Form::setSnapToGridEnabled(bool enabled) { d->snapToGrid = enabled; } void Form::createContextMenu(QWidget *w, Container *container, const QPoint& menuPos, ContextMenuTarget target) { if (!widget()) return; const bool toplevelWidgetSelected = widget() == w; const int widgetsCount = container->form()->selectedWidgets()->count(); const bool multiple = widgetsCount > 1; //set title QString n( container->form()->library()->displayName(w->metaObject()->className()) ); QIcon icon; QString titleText; if (!multiple) { if (w == container->form()->widget()) { icon = koIcon("form"); titleText = xi18n("%1 : Form", w->objectName()); } else { icon = QIcon::fromTheme( container->form()->library()->iconName(w->metaObject()->className())); titleText = QString(w->objectName()) + " : " + n; } } else { icon = koIcon("multiple_obj"); titleText = xi18n("Multiple Widgets (%1)", widgetsCount); } QMenu menu; menu.addSection(icon, titleText); QAction *a; #define PLUG_ACTION(_name, forceVisible) \ { a = d->collection->action(_name); \ if (a && (forceVisible || a->isEnabled())) { \ if (separatorNeeded) \ menu.addSeparator(); \ separatorNeeded = false; \ menu.addAction(a); \ } \ } bool separatorNeeded = false; PLUG_ACTION("edit_cut", !toplevelWidgetSelected); PLUG_ACTION("edit_copy", !toplevelWidgetSelected); PLUG_ACTION("edit_paste", true); PLUG_ACTION("edit_delete", !toplevelWidgetSelected); separatorNeeded = true; PLUG_ACTION("align_menu", !toplevelWidgetSelected); PLUG_ACTION("adjust_size_menu", !toplevelWidgetSelected); separatorNeeded = true; // We create the buddy menu QAction *noBuddyAction = 0; QLabel *buddyLabelWidget = 0; QList sortedItemNames; if (!multiple) { buddyLabelWidget = qobject_cast(w); if (buddyLabelWidget) { if (!buddyLabelWidget->text().contains("&") || buddyLabelWidget->textFormat() == Qt::RichText) { buddyLabelWidget = 0; } } } if (buddyLabelWidget) { // setup menu if (separatorNeeded) menu.addSeparator(); QMenu *sub = new QMenu(w); QWidget *buddy = buddyLabelWidget->buddy(); noBuddyAction = sub->addAction(xi18n("No Buddy")); if (!buddy) noBuddyAction->setChecked(true); sub->addSeparator(); // Add all the widgets that can have focus // 1. Sort by name QHash items; foreach (ObjectTreeItem *item, *container->form()->tabStops()) { items.insert(item->name().toLatin1(), item); } sortedItemNames = items.keys(); qSort(sortedItemNames); foreach (const QString& name, sortedItemNames) { ObjectTreeItem *item = items.value(name); QAction* action = sub->addAction( QIcon::fromTheme( container->form()->library()->iconName(item->className().toLatin1())), item->name() ); if (item->widget() == buddy) action->setChecked(true); } separatorNeeded = true; } #ifdef KFD_SIGSLOTS if (!multiple && (d->features & EnableEvents)) { if (separatorNeeded) menu.addSeparator(); // We create the signals menu QMenu *sigMenu = new QMenu(); const QList list( KexiUtils::methodsForMetaObjectWithParents(w->metaObject(), QMetaMethod::Signal, QMetaMethod::Public)); foreach(const QMetaMethod& m, list) { sigMenu->addAction(m.signature()); } QAction *eventsSubMenuAction = menu.addMenu(sigMenu); eventsSubMenuAction->setText(futureI18n("Events")); if (list.isEmpty()) eventsSubMenuAction->setEnabled(false); connect(sigMenu, SIGNAL(triggered(QAction*)), this, SLOT(menuSignalChosen(QAction*))); separatorNeeded = true; } #endif // Other items if (!multiple) { QAction* lastAction = 0; if (separatorNeeded) { lastAction = menu.addSeparator(); } const int oldIndex = menu.actions().count() - 1; container->form()->library() ->createMenuActions(w->metaObject()->className(), w, &menu, container); if (oldIndex == (menu.actions().count() - 1)) { //nothing added if (separatorNeeded) { menu.removeAction(lastAction); } } } //show the menu at the selected widget QPoint pos; switch (target) { case FormContextMenuTarget: { pos = w->mapToGlobal(menuPos); d->insertionPoint = menuPos; break; } case WidgetTreeContextMenuTarget: { pos = QCursor::pos(); d->insertionPoint = container->widget()->mapToGlobal(w->pos() + QPoint(10, 10)); // user may still want to paste break; } } //qDebug() << w << container->widget() << "menuPos=" << menuPos << "pos=" << pos; QAction *result = menu.exec(pos); if (!result) { // nothing to do } else if (noBuddyAction && buddyLabelWidget && result == noBuddyAction) { buddyLabelWidget->setBuddy(0); } else if (sortedItemNames.contains(result->text())) { ObjectTreeItem *item = objectTree()->lookup(result->text()); if (item && item->widget()) { buddyLabelWidget->setBuddy(item->widget()); } } d->insertionPoint = QPoint(); } void Form::deleteWidget() { if (!objectTree()) { return; } QWidgetList *list = selectedWidgets(); if (list->isEmpty()) { return; } if (widget() == list->first()) { //toplevel form is selected, cannot delete it return; } Command *com = new DeleteWidgetCommand(*this, *list); addCommand(com); } void Form::copyWidget() { if (!objectTree() || isFormWidgetSelected()) { return; } QWidgetList *list = selectedWidgets(); if (list->isEmpty()) { return; } QDomDocument doc; QHash containers; QHash parents; KFormDesigner::widgetsToXML(doc, containers, parents, *this, *list); KFormDesigner::copyToClipboard(doc.toString()); emitActionSignals(); // to update 'Paste' item state emitUndoActionSignals(); } bool Form::isFormWidgetSelected() const { return selectedWidget() && selectedWidget() == widget(); } void Form::cutWidget() { if (!objectTree() || isFormWidgetSelected()) { return; } QWidgetList *list = selectedWidgets(); if (list->isEmpty()) { return; } Command *com = new CutWidgetCommand(*this, *list); addCommand(com); } void Form::pasteWidget() { if (!objectTree()) { return; } const QMimeData *mimeData = QApplication::clipboard()->mimeData(); const bool mimeDataHasXmlUiFormat = mimeData->hasFormat( KFormDesigner::mimeType() ); if (!mimeDataHasXmlUiFormat && !mimeData->hasText()) { return; } QDomDocument doc; if (!doc.setContent( mimeDataHasXmlUiFormat ? QString::fromUtf8( mimeData->data(KFormDesigner::mimeType())) : mimeData->text() )) { return; } if (!doc.firstChildElement("UI").hasChildNodes()) { return; } Command *com = new PasteWidgetCommand(doc, *activeContainer(), d->insertionPoint); addCommand(com); } void Form::editTabOrder() { if (!objectTree()) { return; } QWidget *topLevel = widget()->topLevelWidget(); TabStopDialog dlg(topLevel); if (dlg.exec(this) == QDialog::Accepted) { d->propertySet.changePropertyIfExists("autoTabStops", dlg.autoTabStops()); //force set dirty setModified(true); } } void Form::editFormPixmapCollection() { if (!objectTree()) { return; } //! @todo pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT PixmapCollectionEditor dialog(pixmapCollection(), widget()->topLevelWidget()); dialog.exec(); #endif } void Form::editConnections() { #ifdef KFD_SIGSLOTS if (!(d->features & EnableConnections)) { return; } if (!objectTree()) { return; } ConnectionDialog dialog(this, widget()->topLevelWidget()); dialog.exec(); #endif } void Form::alignWidgets(WidgetAlignment alignment) { QWidgetList* selected = selectedWidgets(); if (!objectTree() || selected->count() < 2) { return; } QWidget *parentWidget = selected->first()->parentWidget(); foreach (QWidget *w, *selected) { if (w->parentWidget() != parentWidget) { //qDebug() << "alignment ==" << alignment << "widgets don't have the same parent widget"; return; } } Command *com = new AlignWidgetsCommand(*this, alignment, *selected); addCommand(com); } void Form::alignWidgetsToLeft() { alignWidgets(AlignToLeft); } void Form::alignWidgetsToRight() { alignWidgets(AlignToRight); } void Form::alignWidgetsToTop() { alignWidgets(AlignToTop); } void Form::alignWidgetsToBottom() { alignWidgets(AlignToBottom); } void Form::adjustWidgetSize() { if (!objectTree()) { return; } Command *com = new AdjustSizeCommand(*this, AdjustSizeCommand::SizeToFit, *selectedWidgets()); addCommand(com); } void Form::alignWidgetsToGrid() { if (!objectTree()) { return; } Command *com = new AlignWidgetsCommand(*this, AlignToGrid, *selectedWidgets()); addCommand(com); } void Form::adjustSizeToGrid() { if (!objectTree()) { return; } Command *com = new AdjustSizeCommand(*this, AdjustSizeCommand::SizeToGrid, *selectedWidgets()); addCommand(com); } void Form::adjustWidthToSmall() { if (!objectTree()) { return; } Command *com = new AdjustSizeCommand(*this, AdjustSizeCommand::SizeToSmallWidth, *selectedWidgets()); addCommand(com); } void Form::adjustWidthToBig() { if (!objectTree()) { return; } Command *com = new AdjustSizeCommand(*this, AdjustSizeCommand::SizeToBigWidth, *selectedWidgets()); addCommand(com); } void Form::adjustHeightToSmall() { if (!objectTree()) { return; } Command *com = new AdjustSizeCommand(*this, AdjustSizeCommand::SizeToSmallHeight, *selectedWidgets()); addCommand(com); } void Form::adjustHeightToBig() { if (!objectTree()) { return; } Command *com = new AdjustSizeCommand(*this, AdjustSizeCommand::SizeToBigHeight, *selectedWidgets()); addCommand(com); } void Form::bringWidgetToFront() { if (!objectTree()) { return; } foreach (QWidget *w, *selectedWidgets()) { w->raise(); } } void Form::sendWidgetToBack() { if (!objectTree()) { return; } foreach (QWidget *w, *selectedWidgets()) { w->lower(); } } void Form::selectAll() { if (!objectTree()) { return; } selectFormWidget(); int count = objectTree()->children()->count(); foreach (ObjectTreeItem *titem, *objectTree()->children()) { selectWidget( titem->widget(), AddToPreviousSelection | ((count > 1) ? MoreWillBeSelected : LastSelection) ); count--; } } void Form::clearWidgetContent() { if (!objectTree()) { return; } foreach (QWidget *w, *selectedWidgets()) { library()->clearWidgetContent(w->metaObject()->className(), w); } } // Alignment-related functions ///////////////////////////// void Form::createAlignProperty(const QMetaProperty& meta, QWidget *widget, QWidget *subwidget) { if (!objectTree()) return; const int alignment = subwidget->property("alignment").toInt(); const QList keys(meta.enumerator().valueToKeys(alignment).split('|')); //qDebug() << "keys:" << keys; const QStringList possibleValues(KexiUtils::enumKeysForProperty(meta)); //qDebug() << "possibleValues:" << possibleValues; ObjectTreeItem *tree = objectTree()->lookup(widget->objectName()); const bool isTopLevel = isTopLevelWidget(widget); if (possibleValues.contains("AlignHCenter")) { // Create the horizontal alignment property QString value; if (keys.contains("AlignHCenter") || keys.contains("AlignCenter")) value = "AlignHCenter"; else if (keys.contains("AlignRight")) value = "AlignRight"; else if (keys.contains("AlignLeft")) value = "AlignLeft"; else if (keys.contains("AlignJustify")) value = "AlignJustify"; else value = "AlignAuto"; QStringList list; list << "AlignAuto" << "AlignLeft" << "AlignRight" << "AlignHCenter" << "AlignJustify"; KProperty *p = new KProperty( "hAlign", d->createValueList(0, list), value, xi18nc("Translators: please keep this string short (less than 20 chars)", "Hor. Alignment"), xi18n("Horizontal Alignment")); d->propertySet.addProperty(p); if (!isPropertyVisible(p->name(), isTopLevel)) { p->setVisible(false); } updatePropertyValue(tree, "hAlign"); } if (possibleValues.contains("AlignTop")) { // Create the ver alignment property QString value; if (keys.contains("AlignTop")) value = "AlignTop"; else if (keys.contains("AlignBottom")) value = "AlignBottom"; else value = "AlignVCenter"; QStringList list; list << "AlignTop" << "AlignVCenter" << "AlignBottom"; KProperty *p = new KProperty( "vAlign", d->createValueList(0, list), value, xi18nc("Translators: please keep this string short (less than 20 chars)", "Ver. Alignment"), xi18n("Vertical Alignment")); d->propertySet.addProperty(p); if (!isPropertyVisible(p->name(), isTopLevel)) { p->setVisible(false); } updatePropertyValue(tree, "vAlign"); } if (possibleValues.contains("WordBreak")) { // Create the wordbreak property KProperty *p = new KProperty("wordbreak", QVariant((bool)(alignment & Qt::TextWordWrap)), xi18n("Word Break"), xi18n("Word Break")); d->propertySet.addProperty(p); updatePropertyValue(tree, "wordbreak"); if (!library()->isPropertyVisible( subwidget->metaObject()->className(), subwidget, p->name(), false/*multiple*/, isTopLevel)) { p->setVisible(false); } } } void Form::saveAlignProperty(const QString &property) { QStringList list; if (d->propertySet.contains("hAlign")) list.append(d->propertySet["hAlign"].value().toString()); if (d->propertySet.contains("vAlign")) list.append(d->propertySet["vAlign"].value().toString()); if (d->propertySet.contains("wordbreak") && d->propertySet["wordbreak"].value().toBool()) list.append("WordBreak"); WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(d->selected.first()); QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : (QWidget*)d->selected.first(); int count = subwidget->metaObject()->indexOfProperty("alignment"); const QMetaProperty meta( subwidget->metaObject()->property(count) ); const int valueForKeys = meta.enumerator().keysToValue(list.join("|").toLatin1()); subwidget->setProperty("alignment", valueForKeys); ObjectTreeItem *tree = objectTree()->lookup(d->selected.first()->objectName()); if (tree && d->propertySet[ property.toLatin1()].isModified()) { tree->addModifiedProperty( property.toLatin1(), d->propertySet[property.toLatin1()].oldValue()); } if (d->isUndoing) { return; } if (d->lastCommand && d->lastCommand->propertyName() == "alignment") { d->lastCommand->setValue(valueForKeys); } else { d->lastCommand = new PropertyCommand(*this, d->selected.first()->objectName().toLatin1(), subwidget->property("alignment"), valueForKeys, "alignment"); if (!addCommand(d->lastCommand, DontExecuteCommand)) { d->lastCommand = 0; } } } void Form::createPropertyCommandsInDesignMode(QWidget* widget, const QHash &propValues, Command *parentCommand, bool addToActiveForm) { if (!widget || propValues.isEmpty()) return; //is this widget selected? (if so, use property system) const bool widgetIsSelected = selectedWidget() == widget; d->slotPropertyChanged_addCommandEnabled = false; QHash::ConstIterator endIt = propValues.constEnd(); for (QHash::ConstIterator it = propValues.constBegin(); it != endIt; ++it) { if (!d->propertySet.contains(it.key())) { qWarning() << "\"" << it.key() << "\" property not found"; continue; } (void)new PropertyCommand(*this, widget->objectName().toLatin1(), widget->property(it.key()), it.value(), it.key(), parentCommand); if (widgetIsSelected) { d->propertySet.changeProperty(it.key(), it.value()); } else { WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(widget); QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : widget; if (subwidget && -1 != subwidget->metaObject()->indexOfProperty(it.key()) && subwidget->property(it.key()) != it.value()) { ObjectTreeItem *tree = objectTree()->lookup(widget->objectName()); if (tree) { tree->addModifiedProperty(it.key(), subwidget->property(it.key())); } subwidget->setProperty(it.key(), it.value()); handleWidgetPropertyChanged(widget, it.key(), it.value()); } } } d->lastCommand = 0; d->lastCommandGroup = 0; if (addToActiveForm) { addCommand(parentCommand, DontExecuteCommand); } d->slotPropertyChanged_addCommandEnabled = true; } void Form::handleWidgetPropertyChanged(QWidget *w, const QByteArray &name, const QVariant &value) { Q_UNUSED(w); if (name == "autoTabStops") { //update autoTabStops setting at KFD::Form level setAutoTabStops(value.toBool()); } else if (name == "geometry" && widget()) { //fall back to sizeInternal property.... d->propertySet.changePropertyIfExists("sizeInternal", value.toRect().size()); } } void Form::changeFont() { QWidgetList *wlist = selectedWidgets(); QWidgetList widgetsWithFontProperty; QFont font; bool oneFontSelected = true; foreach (QWidget* widget, *wlist) { if (library()->isPropertyVisible(widget->metaObject()->className(), widget, "font")) { widgetsWithFontProperty.append(widget); if (oneFontSelected) { if (widgetsWithFontProperty.count() == 1) font = widget->font(); else if (font != widget->font()) oneFontSelected = false; } } } if (widgetsWithFontProperty.isEmpty()) return; if (!oneFontSelected) //many different fonts selected: pick a font from toplevel conatiner font = widget()->font(); if (1 == widgetsWithFontProperty.count()) { //single widget's settings bool ok; font = QFontDialog::getFont(&ok, widget()); if (!ok) { return; } d->propertySet.changeProperty("font", font); return; } //multiple widgets //! @todo KEXI3 port KFontDialog::getFontDiff() #if 0 QFlags diffFlags = KFontChooser::NoFontDiffFlags; if (QDialog::Accepted != KFontDialog::getFontDiff( font, diffFlags, KFontChooser::NoDisplayFlags, widget()) || 0 == diffFlags) { return; } //update font foreach (QWidget* widget, widgetsWithFontProperty) { QFont prevFont(widget->font()); if (diffFlags & KFontChooser::FontDiffFamily) prevFont.setFamily(font.family()); if (diffFlags & KFontChooser::FontDiffStyle) { prevFont.setBold(font.bold()); prevFont.setItalic(font.italic()); } if (diffFlags & KFontChooser::FontDiffSize) { prevFont.setPointSize(font.pointSize()); } //! @todo this modification is not added to UNDO BUFFER: //! do it when KPropertySet supports multiple selections widget->setFont(prevFont); } //! @todo temporary fix for dirty flag setModified(true); #endif } void Form::setSlotPropertyChangedEnabled(bool set) { d->slotPropertyChangedEnabled = set; } void Form::createInlineEditor(const KFormDesigner::WidgetFactory::InlineEditorCreationArguments& args) { if (!args.execute) return; if (args.multiLine) { KTextEdit *textedit = new KTextEdit(args.widget->parentWidget()); textedit->setPlainText(args.text); textedit->setAlignment(args.alignment); if (qobject_cast(args.widget)) { textedit->setWordWrapMode(qobject_cast(args.widget)->wordWrapMode()); textedit->setLineWrapMode(qobject_cast(args.widget)->lineWrapMode()); } textedit->moveCursor(QTextCursor::End); textedit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); textedit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); //ok? textedit->setFrameShape(args.useFrame ? QFrame::StyledPanel : QFrame::NoFrame); textedit->show(); textedit->setFocus(); textedit->selectAll(); d->inlineEditor = textedit; connect(textedit, SIGNAL(textChanged()), this, SLOT(slotInlineTextChanged())); connect(args.widget, SIGNAL(destroyed()), this, SLOT(widgetDestroyed())); connect(textedit, SIGNAL(destroyed()), this, SLOT(inlineEditorDeleted())); } else { QLineEdit *editor = new QLineEdit(args.widget->parentWidget()); d->inlineEditor = editor; editor->setText(args.text); editor->setAlignment(args.alignment); editor->setFrame(args.useFrame); editor->show(); editor->setFocus(); editor->selectAll(); connect(editor, SIGNAL(textChanged(QString)), this, SLOT(changeInlineTextInternal(QString))); connect(args.widget, SIGNAL(destroyed()), this, SLOT(widgetDestroyed())); connect(editor, SIGNAL(destroyed()), this, SLOT(inlineEditorDeleted())); } d->inlineEditor->installEventFilter(this); d->inlineEditor->setFont(args.widget->font()); d->inlineEditor->setGeometry(args.geometry); // setup palette d->inlineEditor->setBackgroundRole(args.widget->backgroundRole()); QPalette pal(args.widget->palette()); QBrush baseBrush; if (args.transparentBackground) { baseBrush = QBrush(Qt::transparent); } else { baseBrush = pal.base(); QColor baseColor(baseBrush.color()); if (!args.widget->inherits("KexiCommandLinkButton")) { //! @todo HACK! any idea?? baseColor.setAlpha(120); } baseBrush.setColor(baseColor); } pal.setBrush(QPalette::Base, baseBrush); pal.setBrush(d->inlineEditor->backgroundRole(), pal.brush(args.widget->backgroundRole())); pal.setBrush(d->inlineEditor->foregroundRole(), pal.brush(args.widget->foregroundRole())); d->inlineEditor->setPalette(pal); //copy properties if available WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(args.widget); QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : args.widget; if ( -1 != d->inlineEditor->metaObject()->indexOfProperty("margin") && -1 != subwidget->metaObject()->indexOfProperty("margin")) { d->inlineEditor->setProperty("margin", subwidget->property("margin")); } ResizeHandleSet *handles = resizeHandlesForWidget(args.widget); if (handles) { handles->setEditingMode(true); handles->raise(); } ObjectTreeItem *tree = args.container->form()->objectTree()->lookup(args.widget->objectName()); if (!tree) return; tree->eventEater()->setContainer(this); d->inlineEditorContainer = args.container; d->editedWidgetClass = args.classname; d->originalInlineText = args.text; d->slotPropertyChangedEnabled = false; InlineTextEditingCommand command( // to update size of the widget *this, selectedWidget(), d->editedWidgetClass, args.text); command.execute(); d->slotPropertyChangedEnabled = true; } void Form::changeInlineTextInternal(const QString& text) { if (d->editedWidgetClass.isEmpty()) return; d->slotPropertyChangedEnabled = false; InlineTextEditingCommand *command = new InlineTextEditingCommand( *this, selectedWidget(), d->editedWidgetClass, text); addCommand(command); d->slotPropertyChangedEnabled = true; } bool Form::eventFilter(QObject *obj, QEvent *ev) { if ( (ev->type() == QEvent::Resize || ev->type() == QEvent::Move) && obj == selectedWidget() && d->inlineEditor) { // resize widget using resize handles WidgetInfo *winfo = library()->widgetInfoForClassName(obj->metaObject()->className()); if (winfo) { winfo->factory()->resizeEditor( d->inlineEditor, selectedWidget(), selectedWidget()->metaObject()->className()); } } else if ( ev->type() == QEvent::Paint && obj == selectedWidget() && d->inlineEditor && d->inlineEditorContainer) { // paint event for container edited (eg button group) return d->inlineEditorContainer->eventFilter(obj, ev); } else if ( ev->type() == QEvent::MouseButtonPress && obj == selectedWidget() && d->inlineEditor && d->inlineEditorContainer) { // click outside editor --> cancel editing resetInlineEditor(); return d->inlineEditorContainer->eventFilter(obj, ev); } if (ev->type() == QEvent::FocusOut && d->inlineEditor) { QWidget *w = d->inlineEditor; if (obj != w) return false; QWidget *focus = w->topLevelWidget()->focusWidget(); if ( focus && w != focus && !KexiUtils::findFirstChild(w, focus->objectName().toLatin1(), focus->metaObject()->className()) ) { resetInlineEditor(); } } else if (ev->type() == QEvent::KeyPress) { QWidget *w = d->inlineEditor; if (obj != w) return false; QKeyEvent *e = static_cast(ev); if ( (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) && e->modifiers() != Qt::AltModifier) { resetInlineEditor(); } if (e->key() == Qt::Key_Escape) { setInlineEditorText(d->originalInlineText); resetInlineEditor(); } } else if (ev->type() == QEvent::ContextMenu) { QWidget *w = d->inlineEditor; if (obj != w) return false; return true; } return false; } void Form::slotInlineTextChanged() { changeInlineTextInternal(inlineEditorText()); } QString Form::inlineEditorText() const { QWidget *ed = d->inlineEditor; if (!ed) return QString(); return qobject_cast(ed) ? qobject_cast(ed)->toPlainText() : qobject_cast(ed)->text(); } void Form::setInlineEditorText(const QString& text) { QWidget *ed = d->inlineEditor; if (!ed) return; if (qobject_cast(ed)) qobject_cast(ed)->setPlainText(text); else if (qobject_cast(ed)) qobject_cast(ed)->setText(text); else qWarning() << "Inline editor is neither KTextEdit nor QLineEdit"; } void Form::disableFilter(QWidget *w, Container *container) { Q_UNUSED(container); ObjectTreeItem *tree = objectTree()->lookup(w->objectName()); if (!tree) return; tree->eventEater()->setContainer(this); w->setFocus(); ResizeHandleSet *handles = resizeHandlesForWidget(w); if (handles) { handles->setEditingMode(true); handles->raise(); } d->inlineEditor = 0; d->inlineEditorContainer = 0; d->editedWidgetClass.clear(); if (!tree->isEnabled()) { //! @todo widget is disabled, so we re-enable it while editing } connect(w, SIGNAL(destroyed()), this, SLOT(widgetDestroyed())); } void Form::resetInlineEditor() { if (!d->inlineEditorContainer) { return; } d->inlineEditorContainer->stopInlineEditing(); QWidget *ed = d->inlineEditor; QWidget *widget = selectedWidget(); if (widget) { FormWidgetInterface* fwiface = dynamic_cast(widget); if (fwiface) fwiface->setEditingMode(false); ObjectTreeItem *tree = objectTree()->lookup(widget->objectName()); if (!tree) { qWarning() << "Cannot find tree item for widget" << widget->objectName(); return; } tree->eventEater()->setContainer(d->inlineEditorContainer); // "disable" the widget if needed if (!ed && !tree->isEnabled()) { widget->setPalette(KexiUtils::paletteForReadOnly(widget->palette())); } } if (ed) { d->slotPropertyChangedEnabled = false; InlineTextEditingCommand command( *this, selectedWidget(), d->editedWidgetClass, inlineEditorText()); command.execute(); d->slotPropertyChangedEnabled = true; } d->inlineEditor = 0; d->inlineEditorContainer = 0; if (ed) { disconnect(ed, 0, this, 0); ed->deleteLater(); } if (widget) { disconnect(widget, 0, this, 0); widget->update(); } ResizeHandleSet *handles = resizeHandlesForWidget(widget); if (handles) { handles->setEditingMode(false); } d->editedWidgetClass.clear(); } void Form::widgetDestroyed() { if (d->inlineEditor) { d->inlineEditor->deleteLater(); d->inlineEditor = 0; } ResizeHandleSet *handles = resizeHandlesForWidget(static_cast(sender())); if (handles) { handles->setEditingMode(false); } d->inlineEditorContainer = 0; d->editedWidgetClass.clear(); } void Form::inlineEditorDeleted() { ResizeHandleSet *handles = resizeHandlesForWidget(static_cast(sender())); if (handles) { handles->setEditingMode(false); } d->inlineEditor = 0; d->inlineEditorContainer = 0; d->editedWidgetClass.clear(); } QByteArray Form::editedWidgetClass() const { return d->editedWidgetClass; } diff --git a/kexi/formeditor/formIO.cpp b/kexi/formeditor/formIO.cpp index a3e6bea8d8d..2985f97cb4f 100644 --- a/kexi/formeditor/formIO.cpp +++ b/kexi/formeditor/formIO.cpp @@ -1,1531 +1,1531 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2005-2009 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 "kformdesigner_export.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FormWidget.h" #include "form.h" #include "container.h" #include "objecttree.h" #include "widgetlibrary.h" #include "events.h" #include "utils.h" #include "widgetwithsubpropertiesinterface.h" #include "formIO.h" //! @todo KEXI3 TODO pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT #include "pixmapcollection.h" #endif //! @return Value of attribute "name", or "objectName" in absence of "name". //! This is for compatibility with Kexi 1.x. static QString nameAttribute(const QDomElement& el) { QString res( el.attribute("name") ); if (res.isEmpty()) { res = el.attribute("objectName"); } return res; } //! A blank widget used when the class name is not supported CustomWidget::CustomWidget(const QByteArray &className, QWidget *parent) : QWidget(parent), m_className(className) { setBackgroundRole(QPalette::Dark); } CustomWidget::~CustomWidget() { } void CustomWidget::paintEvent(QPaintEvent *) { QPainter p(this); p.setBrush(palette().text()); QRect r(rect()); r.setX(r.x() + 2); p.drawText(r, Qt::AlignTop, m_className); } using namespace KFormDesigner; // FormIO itself KFORMDESIGNER_EXPORT int KFormDesigner::version() { return KFORMDESIGNER_VERSION; } ///////////////////////////////////////////////////////////////////////////// ///////////// Saving/loading functions ////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// FormIO::FormIO() { } FormIO::~FormIO() { } bool FormIO::saveFormToFile(Form *form, const QString &filename) { QString _filename; if (!form->filename().isEmpty() && filename.isEmpty()) { _filename = form->filename(); } if (filename.isEmpty()) { KoFileDialog dlg(0, KoFileDialog::SaveFile, "SaveForm"); dlg.setNameFilter("*.ui|" + xi18n("Qt Designer UI Files")); _filename = dlg.filename(); if (_filename.isEmpty()) { return false; } } else { _filename = filename; } form->setFilename(_filename); QDomDocument domDoc; if (!saveFormToDom(form, domDoc)) return false; QFile file(_filename); if (!file.open(QIODevice::WriteOnly)) return false; QTextStream stream(&file); stream << domDoc.toString(3); file.close(); return true; } bool FormIO::saveFormToByteArray(Form *form, QByteArray &dest) { QDomDocument domDoc; if (!saveFormToDom(form, domDoc)) return false; dest = domDoc.toByteArray(); return true; } bool FormIO::saveFormToString(Form *form, QString &dest, int indent) { QDomDocument domDoc; if (!saveFormToDom(form, domDoc)) return false; dest = domDoc.toString(indent); return true; } bool FormIO::saveFormToDom(Form *form, QDomDocument &domDoc) { domDoc = QDomDocument("UI"); QDomElement uiElement = domDoc.createElement("UI"); domDoc.appendChild(uiElement); uiElement.setAttribute("version", "3.1"); uiElement.setAttribute("stdsetdef", 1); //update format version information form->headerProperties()->insert("version", QString::number(form->formatVersion())); //custom properties QDomElement headerPropertiesEl = domDoc.createElement("kfd:customHeader"); QHash::ConstIterator itEnd = form->headerProperties()->constEnd(); for (QHash::ConstIterator it = form->headerProperties()->constBegin(); it != itEnd; ++it) { headerPropertiesEl.setAttribute(it.key(), it.value()); } uiElement.appendChild(headerPropertiesEl); // We save the savePixmapsInline property in the Form QDomElement inlinePix = domDoc.createElement("pixmapinproject"); uiElement.appendChild(inlinePix); // We create the top class element QDomElement baseClass = domDoc.createElement("class"); uiElement.appendChild(baseClass); QDomText baseClassV = domDoc.createTextNode("QWidget"); baseClass.appendChild(baseClassV); // Save the toplevel widgets, and so the whole Form saveWidget(form->objectTree(), uiElement, domDoc); // We then save the layoutdefaults element QDomElement layoutDefaults = domDoc.createElement("layoutDefaults"); layoutDefaults.setAttribute("spacing", QString::number(form->defaultSpacing())); layoutDefaults.setAttribute("margin", QString::number(form->defaultMargin())); uiElement.appendChild(layoutDefaults); // Save tab Stops if (form->autoTabStops()) form->autoAssignTabStops(); QDomElement tabStops = domDoc.createElement("tabstops"); uiElement.appendChild(tabStops); foreach (ObjectTreeItem *item, *form->tabStops()) { QDomElement tabstop = domDoc.createElement("tabstop"); tabStops.appendChild(tabstop); QDomText tabStopText = domDoc.createTextNode(item->name()); tabstop.appendChild(tabStopText); } //! @todo KEXI3 TODO pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT // Save the Form 's PixmapCollection form->pixmapCollection()->save(uiElement); #endif #ifdef KFD_SIGSLOTS // Save the Form connections form->connectionBuffer()->save(uiElement); #endif form->setUndoStackClean(); return true; } bool FormIO::loadFormFromByteArray(Form *form, QWidget *container, QByteArray &src, bool preview) { QString errMsg; int errLine; int errCol; QDomDocument inBuf; bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol); if (!parsed) { qDebug() << errMsg; qDebug() << "line:" << errLine << "col:" << errCol; return false; } if (!loadFormFromDom(form, container, inBuf)) { return false; } if (preview) { form->setMode(Form::DataMode); } return true; } bool FormIO::loadFormFromString(Form *form, QWidget *container, QString *src, bool preview) { QString errMsg; int errLine; int errCol; #ifdef KEXI_DEBUG_GUI form->m_recentlyLoadedUICode = src; #endif QDomDocument inBuf; bool parsed = inBuf.setContent(*src, false, &errMsg, &errLine, &errCol); if (!parsed) { qWarning() << errMsg; qWarning() << "line:" << errLine << "col: " << errCol; return false; } if (!loadFormFromDom(form, container, inBuf)) { return false; } if (preview) { form->setMode(Form::DataMode); } return true; } bool FormIO::loadFormFromFile(Form *form, QWidget *container, const QString &filename) { QString errMsg; int errLine; int errCol; QString _filename; if (filename.isEmpty()) { KoFileDialog dlg(0, KoFileDialog::OpenFile, "LoadForm"); dlg.setNameFilter("*.ui|" + xi18n("Qt Designer UI Files")); _filename = dlg.filename(); if (_filename.isEmpty()) { return false; } } else { _filename = filename; } QFile file(_filename); if (!file.open(QIODevice::ReadOnly)) { //! @todo show err msg to the user qWarning() << "Cannot open the file " << _filename; return false; } QDomDocument doc; if (!doc.setContent(&file, false/* !namespaceProcessing*/, &errMsg, &errLine, &errCol)) { //! @todo show err msg to the user qWarning() << errMsg; qWarning() << errLine << "col:" << errCol; return false; } return loadFormFromDom(form, container, doc); } bool FormIO::loadFormFromDom(Form *form, QWidget *container, QDomDocument &inBuf) { QDomElement ui = inBuf.firstChildElement("UI"); //custom properties form->headerProperties()->clear(); QDomElement headerPropertiesEl = ui.firstChildElement("kfd:customHeader"); QDomAttr attr = headerPropertiesEl.firstChild().toAttr(); while (!attr.isNull() && attr.isAttr()) { form->headerProperties()->insert(attr.name().toLatin1(), attr.value()); attr = attr.nextSibling().toAttr(); } //update format version information int ver = 1; //the default if (form->headerProperties()->contains("version")) { bool ok; int v = (*form->headerProperties())["version"].toUInt(&ok); if (ok) ver = v; } qDebug() << "original format version: " << ver; form->setOriginalFormatVersion(ver); if (ver < KFormDesigner::version()) { //! @todo We can either 1) convert from old format and later save in a new one or 2) keep old format. //! To do this we may need to look at the original format version number. qWarning() << "original format is older than current: " << KFormDesigner::version(); form->setFormatVersion(KFormDesigner::version()); } else form->setFormatVersion(ver); if (ver > KFormDesigner::version()) { //! @todo display information about too new format and that "some information will not be available". qWarning() << "original format is newer than current: " << KFormDesigner::version(); } // Load the pixmap collection form->setPixmapsStoredInline(ui.firstChildElement("pixmapinproject").isNull() || !ui.firstChildElement("images").isNull()); //! @todo pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT form->pixmapCollection()->load(ui.namedItem("collection")); #endif QDomElement element = ui.firstChildElement("widget"); createToplevelWidget(form, container, element); // Loading the tabstops QDomElement tabStops = ui.firstChildElement("tabstops"); if (!tabStops.isNull()) { int i = 0; int itemsNotFound = 0; for (QDomNode n = tabStops.firstChild(); !n.isNull(); n = n.nextSibling(), i++) { QString name = n.toElement().text(); ObjectTreeItem *item = form->objectTree()->lookup(name); if (!item) { qWarning() << "ERROR : no ObjectTreeItem "; continue; } const int index = form->tabStops()->indexOf(item); /* Compute a real destination index: "a number of not found items so far". */ const int realIndex = i - itemsNotFound; if ((index != -1) && (index != realIndex)) { // the widget is not in the same place, so we move it form->tabStops()->removeOne(item); form->tabStops()->insert(realIndex, item); } if (index == -1) { itemsNotFound++; qDebug() << "FormIO: item '" << name << "' not in list"; } } } #ifdef KFD_SIGSLOTS // Load the form connections form->connectionBuffer()->load(ui.namedItem("connections")); #endif return true; } ///////////////////////////////////////////////////////////////////////////// ///////////// Functions to save/load properties ///////////////////////////// ///////////////////////////////////////////////////////////////////////////// void FormIO::savePropertyValue(ObjectTreeItem *item, QDomElement &parentNode, QDomDocument &parent, const char *name, const QVariant &value) { // Widget specific properties and attributes // qDebug() << "Saving the property: " << name; Form *form = item->container() ? item->container()->form() : item->parent()->container()->form(); WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(item->widget()); QWidget *subwidget = item->widget(); bool addSubwidgetFlag = false; int propertyId = item->widget()->metaObject()->indexOfProperty(name); const bool propertyIsName = qstrcmp(name, "objectName") == 0 || qstrcmp(name, "name") == 0; if (!propertyIsName && propertyId == -1 && subpropIface && subpropIface->subwidget()) { // try property from subwidget subwidget = subpropIface->subwidget(); propertyId = subpropIface->subwidget()->metaObject()->indexOfProperty(name); addSubwidgetFlag = true; } if (!propertyIsName && propertyId == -1) { qDebug() << "The object doesn't have this property. Let's try the WidgetLibrary."; if (form->library()) form->library()->saveSpecialProperty(item->widget()->metaObject()->className(), name, value, item->widget(), parentNode, parent); return; } QMetaProperty meta; if (!propertyIsName) { meta = subwidget->metaObject()->property(propertyId); } if (!propertyIsName && (!meta.isValid() || !meta.isStored(subwidget))) //not storable return; QDomElement propertyE = parent.createElement("property"); propertyE.setAttribute("name", propertyIsName ? "name" /* compat with 1.x */ : name); if (addSubwidgetFlag) propertyE.setAttribute("subwidget", "true"); if (meta.isValid() && meta.isEnumType()) { // this property is enum or set type QDomElement type; QDomText valueE; if (meta.isFlagType()) { type = parent.createElement("set"); valueE = parent.createTextNode( meta.enumerator().valueToKeys(value.toInt())); type.appendChild(valueE); } else { QString s = meta.enumerator().valueToKey(value.toInt()); type = parent.createElement("enum"); valueE = parent.createTextNode(s); type.appendChild(valueE); } propertyE.appendChild(type); parentNode.appendChild(propertyE); return; } if (value.type() == QVariant::Pixmap) { QDomText valueE; QDomElement type = parent.createElement("pixmap"); QByteArray property = propertyE.attribute("name").toLatin1(); //! @todo QCString pixmapName = m_currentRecord->widget()->property("pixmapName").toCString(); if (form->pixmapsStoredInline() /* (js)too risky: || m_currentRecord->pixmapName(property).isNull() */) valueE = parent.createTextNode(saveImage(parent, value.value())); else valueE = parent.createTextNode(item->pixmapName(property)); type.appendChild(valueE); propertyE.appendChild(type); parentNode.appendChild(propertyE); return; } // Saving a "normal" property writeVariant(parent, propertyE, value); parentNode.appendChild(propertyE); } void FormIO::writeVariant(QDomDocument &parent, QDomElement &parentNode, const QVariant& value) { QDomElement type; QDomText valueE; switch (value.type()) { case QVariant::String: { type = parent.createElement("string"); valueE = parent.createTextNode(value.toString()); type.appendChild(valueE); break; } case QVariant::ByteArray: { type = parent.createElement("cstring"); valueE = parent.createTextNode(value.toString()); type.appendChild(valueE); break; } case QVariant::Rect: { type = parent.createElement("rect"); QDomElement x = parent.createElement("x"); QDomElement y = parent.createElement("y"); QDomElement w = parent.createElement("width"); QDomElement h = parent.createElement("height"); QDomText valueX = parent.createTextNode(QString::number(value.toRect().x())); QDomText valueY = parent.createTextNode(QString::number(value.toRect().y())); QDomText valueW = parent.createTextNode(QString::number(value.toRect().width())); QDomText valueH = parent.createTextNode(QString::number(value.toRect().height())); x.appendChild(valueX); y.appendChild(valueY); w.appendChild(valueW); h.appendChild(valueH); type.appendChild(x); type.appendChild(y); type.appendChild(w); type.appendChild(h); break; } case QVariant::Color: { type = parent.createElement("color"); QDomElement r = parent.createElement("red"); QDomElement g = parent.createElement("green"); QDomElement b = parent.createElement("blue"); const QColor color(value.value()); QDomText valueR = parent.createTextNode(QString::number(color.red())); QDomText valueG = parent.createTextNode(QString::number(color.green())); QDomText valueB = parent.createTextNode(QString::number(color.blue())); r.appendChild(valueR); g.appendChild(valueG); b.appendChild(valueB); type.appendChild(r); type.appendChild(g); type.appendChild(b); break; } case QVariant::Bool: { type = parent.createElement("bool"); //valueE = parent.createTextNode(QString::number(value.toBool())); valueE = parent.createTextNode(value.toBool() ? "true" : "false"); type.appendChild(valueE); break; } case QVariant::Int: case QVariant::UInt: { type = parent.createElement("number"); valueE = parent.createTextNode(QString::number(value.toInt())); type.appendChild(valueE); break; } case QVariant::Size: { type = parent.createElement("size"); QDomElement w = parent.createElement("width"); QDomElement h = parent.createElement("height"); QDomText valueW = parent.createTextNode(QString::number(value.toSize().width())); QDomText valueH = parent.createTextNode(QString::number(value.toSize().height())); w.appendChild(valueW); h.appendChild(valueH); type.appendChild(w); type.appendChild(h); break; } case QVariant::Point: { type = parent.createElement("point"); QDomElement x = parent.createElement("x"); QDomElement y = parent.createElement("y"); QDomText valueX = parent.createTextNode(QString::number(value.toPoint().x())); QDomText valueY = parent.createTextNode(QString::number(value.toPoint().y())); x.appendChild(valueX); y.appendChild(valueY); type.appendChild(x); type.appendChild(y); break; } case QVariant::Font: { type = parent.createElement("font"); QDomElement f = parent.createElement("family"); QDomElement p = parent.createElement("pointsize"); QDomElement w = parent.createElement("weight"); QDomElement b = parent.createElement("bold"); QDomElement i = parent.createElement("italic"); QDomElement u = parent.createElement("underline"); QDomElement s = parent.createElement("strikeout"); const QFont font(value.value()); QDomText valueF = parent.createTextNode(font.family()); QDomText valueP = parent.createTextNode(QString::number(font.pointSize())); QDomText valueW = parent.createTextNode(QString::number(font.weight())); QDomText valueB = parent.createTextNode(QString::number(font.bold())); QDomText valueI = parent.createTextNode(QString::number(font.italic())); QDomText valueU = parent.createTextNode(QString::number(font.underline())); QDomText valueS = parent.createTextNode(QString::number(font.strikeOut())); f.appendChild(valueF); p.appendChild(valueP); w.appendChild(valueW); b.appendChild(valueB); i.appendChild(valueI); u.appendChild(valueU); s.appendChild(valueS); type.appendChild(f); type.appendChild(p); type.appendChild(w); type.appendChild(b); type.appendChild(i); type.appendChild(u); type.appendChild(s); break; } case QVariant::Cursor: { type = parent.createElement("cursor"); valueE = parent.createTextNode(QString::number(value.value().shape())); type.appendChild(valueE); break; } case QVariant::SizePolicy: { type = parent.createElement("sizepolicy"); QDomElement h(parent.createElement("hsizetype")); QDomElement v(parent.createElement("vsizetype")); QDomElement hs(parent.createElement("horstretch")); QDomElement vs(parent.createElement("verstretch")); const QSizePolicy sizePolicy(value.value()); const QDomText valueH(parent.createTextNode(QString::number(sizePolicy.horizontalPolicy()))); const QDomText valueV(parent.createTextNode(QString::number(sizePolicy.verticalPolicy()))); const QDomText valueHS(parent.createTextNode(QString::number(sizePolicy.horizontalStretch()))); const QDomText valueVS(parent.createTextNode(QString::number(sizePolicy.verticalStretch()))); h.appendChild(valueH); v.appendChild(valueV); hs.appendChild(valueHS); vs.appendChild(valueVS); type.appendChild(h); type.appendChild(v); type.appendChild(hs); type.appendChild(vs); break; } case QVariant::Time: { type = parent.createElement("time"); QDomElement h = parent.createElement("hour"); QDomElement m = parent.createElement("minute"); QDomElement s = parent.createElement("second"); QDomText valueH = parent.createTextNode(QString::number(value.toTime().hour())); QDomText valueM = parent.createTextNode(QString::number(value.toTime().minute())); QDomText valueS = parent.createTextNode(QString::number(value.toTime().second())); h.appendChild(valueH); m.appendChild(valueM); s.appendChild(valueS); type.appendChild(h); type.appendChild(m); type.appendChild(s); break; } case QVariant::Date: { type = parent.createElement("date"); QDomElement y = parent.createElement("year"); QDomElement m = parent.createElement("month"); QDomElement d = parent.createElement("day"); QDomText valueY = parent.createTextNode(QString::number(value.toDate().year())); QDomText valueM = parent.createTextNode(QString::number(value.toDate().month())); QDomText valueD = parent.createTextNode(QString::number(value.toDate().day())); y.appendChild(valueY); m.appendChild(valueM); d.appendChild(valueD); type.appendChild(y); type.appendChild(m); type.appendChild(d); break; } case QVariant::DateTime: { type = parent.createElement("datetime"); QDomElement h = parent.createElement("hour"); QDomElement m = parent.createElement("minute"); QDomElement s = parent.createElement("second"); QDomElement y = parent.createElement("year"); QDomElement mo = parent.createElement("month"); QDomElement d = parent.createElement("day"); QDomText valueH = parent.createTextNode(QString::number(value.toDateTime().time().hour())); QDomText valueM = parent.createTextNode(QString::number(value.toDateTime().time().minute())); QDomText valueS = parent.createTextNode(QString::number(value.toDateTime().time().second())); QDomText valueY = parent.createTextNode(QString::number(value.toDateTime().date().year())); QDomText valueMo = parent.createTextNode(QString::number(value.toDateTime().date().month())); QDomText valueD = parent.createTextNode(QString::number(value.toDateTime().date().day())); h.appendChild(valueH); m.appendChild(valueM); s.appendChild(valueS); y.appendChild(valueY); mo.appendChild(valueMo); d.appendChild(valueD); type.appendChild(h); type.appendChild(m); type.appendChild(s); type.appendChild(y); type.appendChild(mo); type.appendChild(d); break; } default: break; } parentNode.appendChild(type); } void FormIO::savePropertyElement(QDomElement &parentNode, QDomDocument &domDoc, const QString &tagName, const QString &property, const QVariant &value) { QDomElement propertyE = domDoc.createElement(tagName); propertyE.setAttribute("name", property); writeVariant(domDoc, propertyE, value); parentNode.appendChild(propertyE); } QVariant FormIO::readPropertyValue(Form *form, QDomNode node, QObject *obj, const QString &name) { QDomElement tag = node.toElement(); QString text = tag.text(); QString type = tag.tagName(); if (type == "string" || type == "cstring") return text; else if (type == "rect") { QDomElement x = node.firstChildElement("x"); QDomElement y = node.firstChildElement("y"); QDomElement w = node.firstChildElement("width"); QDomElement h = node.firstChildElement("height"); int rx = x.text().toInt(); int ry = y.text().toInt(); int rw = w.text().toInt(); int rh = h.text().toInt(); return QRect(rx, ry, rw, rh); } else if (type == "color") { const QDomElement r(node.firstChildElement("red")); const QDomElement g(node.firstChildElement("green")); const QDomElement b(node.firstChildElement("blue")); return QColor(r.text().toInt(), g.text().toInt(), b.text().toInt()); } else if (type == "bool") { if (text == "true") return true; else if (text == "false") return false; return text.toInt() != 0; } else if (type == "number") { return text.toInt(); } else if (type == "size") { QDomElement w = node.firstChildElement("width"); QDomElement h = node.firstChildElement("height"); return QSize(w.text().toInt(), h.text().toInt()); } else if (type == "point") { QDomElement x = node.firstChildElement("x"); QDomElement y = node.firstChildElement("y"); return QPoint(x.text().toInt(), y.text().toInt()); } else if (type == "font") { QDomElement fa = node.firstChildElement("family"); QDomElement p = node.firstChildElement("pointsize"); QDomElement w = node.firstChildElement("weight"); QDomElement b = node.firstChildElement("bold"); QDomElement i = node.firstChildElement("italic"); QDomElement u = node.firstChildElement("underline"); QDomElement s = node.firstChildElement("strikeout"); QFont f; f.setFamily(fa.text()); f.setPointSize(p.text().toInt()); f.setWeight(w.text().toInt()); f.setBold(b.text().toInt()); f.setItalic(i.text().toInt()); f.setUnderline(u.text().toInt()); f.setStrikeOut(s.text().toInt()); return f; } else if (type == "cursor") { return QCursor((Qt::CursorShape) text.toInt()); } else if (type == "time") { QDomElement h = node.firstChildElement("hour"); QDomElement m = node.firstChildElement("minute"); QDomElement s = node.firstChildElement("second"); return QTime(h.text().toInt(), m.text().toInt(), s.text().toInt()); } else if (type == "date") { QDomElement y = node.firstChildElement("year"); QDomElement m = node.firstChildElement("month"); QDomElement d = node.firstChildElement("day"); return QDate(y.text().toInt(), m.text().toInt(), d.text().toInt()); } else if (type == "datetime") { QDomElement h = node.firstChildElement("hour"); QDomElement m = node.firstChildElement("minute"); QDomElement s = node.firstChildElement("second"); QDomElement y = node.firstChildElement("year"); QDomElement mo = node.firstChildElement("month"); QDomElement d = node.firstChildElement("day"); QTime t(h.text().toInt(), m.text().toInt(), s.text().toInt()); QDate da(y.text().toInt(), mo.text().toInt(), d.text().toInt()); return QDateTime(da, t); } else if (type == "sizepolicy") { QDomElement h = node.firstChildElement("hsizetype"); QDomElement v = node.firstChildElement("vsizetype"); QDomElement hs = node.firstChildElement("horstretch"); QDomElement vs = node.firstChildElement("verstretch"); QSizePolicy s; s.setHorizontalPolicy((QSizePolicy::Policy)h.text().toInt()); s.setVerticalPolicy((QSizePolicy::Policy)v.text().toInt()); s.setHorizontalStretch(hs.text().toInt()); s.setVerticalStretch(vs.text().toInt()); return s; } else if (type == "pixmap") { //! @todo pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT if (form->pixmapsStoredInline() || !m_currentForm || !m_currentRecord || !m_currentForm->pixmapCollection()->contains(text)) return loadImage(tag.ownerDocument(), text); else { m_currentRecord->setPixmapName(name.toLatin1(), text); return form->pixmapCollection()->getPixmap(text); } #else Q_UNUSED(form); #endif return QPixmap(); } else if (type == "enum") { return text; } else if (type == "set") { WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(obj); QObject *subobject = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : obj; const QMetaProperty meta(KexiUtils::findPropertyWithSuperclasses(subobject, name.toLatin1())); if (meta.isValid()) { if (meta.isFlagType()) { return meta.enumerator().keysToValue(text.toLatin1()); } else { // Metaproperty not found, probably because subwidget is not created. // We will return a string list here with hope that names will // be resolved and translated into an integer value later when subwidget is created, // e.g. near KexiFormView::updateValuesForSubproperties() return text.split('|'); } } } return QVariant(); } ///////////////////////////////////////////////////////////////////////////// ///////////// Functions to save/load widgets //////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void FormIO::saveWidget(ObjectTreeItem *item, QDomElement &parent, QDomDocument &domDoc, bool insideGridLayout) { if (!item) return; qDebug() << item->className() << item->widget()->objectName(); Form *form = item->container() ? item->container()->form() : item->parent()->container()->form(); WidgetLibrary *lib = form->library(); // We create the "widget" element QDomElement tclass = domDoc.createElement("widget"); parent.appendChild(tclass); if (insideGridLayout) { tclass.setAttribute("row", item->gridRow()); tclass.setAttribute("column", item->gridCol()); if (item->spanMultipleCells()) { tclass.setAttribute("rowspan", item->gridRowSpan()); tclass.setAttribute("colspan", item->gridColSpan()); } } if (!item->parent()) // Toplevel widget tclass.setAttribute("class", "QWidget"); // For compatibility, HBox, VBox and Grid are saved as "QLayoutWidget" else if (KexiUtils::objectIsA(item->widget(), QList() << "HBox" << "VBox" << "Grid" << "HFlow" << "VFlow")) tclass.setAttribute("class", "QLayoutWidget"); else if (KexiUtils::objectIsA(item->widget(), "CustomWidget")) tclass.setAttribute("class", item->className()); else // Normal widgets tclass.setAttribute("class", lib->savingName(item->widget()->metaObject()->className())); // We save every property in the modifProp list of the ObjectTreeItem QHash hash(*(item->modifiedProperties())); QStringList names(hash.keys()); savePropertyValue(item, tclass, domDoc, "objectName", item->widget()->objectName()); names.removeOne("objectName"); // Important: save dataSource property FIRST before properties like "alignment" // - needed when subproperties are defined after subwidget creation, and subwidget is created after setting "dataSource" // (this is the case for KexiDBAutoField) //! @todo more properties like "dataSource" may needed here... // if (-1 != item->widget()->metaObject()->findProperty("dataSource")) // savePropertyValue(tclass, domDoc, "dataSource", item->widget()->property("dataSource"), item->widget()); // We don't want to save the geometry if the widget is inside a layout (so parent.tagName() == "grid" for example) if (item && !item->parent()) { // save form widget size, but not its position savePropertyValue(item, tclass, domDoc, "geometry", QRect(QPoint(0, 0), item->widget()->size())); } // normal widget (if == "UI', it means we're copying widget) else if (parent.tagName() == "widget" || parent.tagName() == "UI") savePropertyValue(item, tclass, domDoc, "geometry", item->widget()->property("geometry")); names.removeOne("geometry"); names.removeOne("layout"); // Save the buddy widget for a label if ( qobject_cast(item->widget()) && qobject_cast(item->widget())->buddy()) { savePropertyElement( tclass, domDoc, "property", "buddy", qobject_cast(item->widget())->buddy()->objectName()); } if (names.contains("paletteBackgroundColor")) { savePropertyElement( tclass, domDoc, "property", "paletteBackgroundColor", item->widget()->palette().color(item->widget()->backgroundRole())); names.removeOne("paletteBackgroundColor"); } if (names.contains("paletteForegroundColor")) { savePropertyElement( tclass, domDoc, "property", "paletteForegroundColor", item->widget()->palette().color(item->widget()->foregroundRole())); names.removeOne("paletteForegroundColor"); } QStringList alignProperties; alignProperties << "hAlign" << "vAlign" << "wordbreak" << "alignment"; foreach (const QString& name, alignProperties) { if (names.contains(name)) { names.removeOne(name); savePropertyValue( item, tclass, domDoc, "alignment", item->widget()->property("alignment")); break; } } foreach (const QString& name, names) { savePropertyValue(item, tclass, domDoc, name.toLatin1(), item->widget()->property(name.toLatin1())); } hash.clear(); if (KexiUtils::objectIsA(item->widget(), "CustomWidget")) { QDomDocument doc("TEMP"); doc.setContent(item->unknownProperties()); for (QDomNode n = doc.firstChild(); !n.isNull(); n = n.nextSibling()) { tclass.appendChild(n.cloneNode()); } } // Saving container 's layout if there is one QDomElement layout; if (item->container() && item->container()->layoutType() != Form::NoLayout) { if (item->container()->layout()) { // there is a layout layout = domDoc.createElement("temp"); savePropertyValue(item, layout, domDoc, "objectName", "unnamed"); if (item->modifiedProperties()->contains("layoutMargin")) savePropertyElement(layout, domDoc, "property", "margin", item->container()->layoutMargin()); if (item->modifiedProperties()->contains("layoutSpacing")) savePropertyElement(layout, domDoc, "property", "spacing", item->container()->layoutSpacing()); tclass.appendChild(layout); } } Form::LayoutType layoutType = item->container() ? item->container()->layoutType() : Form::NoLayout; switch (layoutType) { case Form::Grid: { // grid layout layout.setTagName("grid"); foreach (ObjectTreeItem *titem, *item->children()) { saveWidget(titem, layout, domDoc, true); } break; } case Form::HBox: case Form::VBox: { // as we don't save geometry, we need to sort widgets in the right order, not creation order CustomSortableWidgetList *list; if (layout.tagName() == "hbox") { list = new HorizontalWidgetList(item->container()->form()->toplevelContainer()->widget()); layout.setTagName("hbox"); } else { list = new HorizontalWidgetList(item->container()->form()->toplevelContainer()->widget()); layout.setTagName("vbox"); } foreach (ObjectTreeItem *titem, *item->children()) { list->append(titem->widget()); } list->sort(); foreach (QWidget *w, *list) { ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup( w->objectName() ); if (item) saveWidget(titem, layout, domDoc); } delete list; break; } case Form::HFlow: case Form::VFlow: { break; } default: { foreach (ObjectTreeItem *titem, *item->children()) { saveWidget(titem, tclass, domDoc); } } } addIncludeFileName(lib->includeFileName( item->widget()->metaObject()->className()), domDoc); } void FormIO::cleanClipboard(QDomElement &uiElement) { // remove includehints element not needed if (!uiElement.firstChildElement("includehints").isNull()) uiElement.removeChild(uiElement.firstChildElement("includehints")); // and ensure images and connection are at the end if (!uiElement.firstChildElement("connections").isNull()) uiElement.insertAfter(uiElement.firstChildElement("connections"), QDomNode()); if (!uiElement.firstChildElement("images").isNull()) uiElement.insertAfter(uiElement.firstChildElement("images"), QDomNode()); } void FormIO::loadWidget(Container *container, const QDomElement &el, QWidget *parent, QHash *buddies) { Form *form = container->form(); // We first look for the widget's name QString wname; for (QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { if ( n.toElement().tagName() == "property" && nameAttribute(n.toElement()) == "name" /* compat with 1.x */) { wname = n.toElement().text(); break; } } ObjectTreeItem *item = container->form()->objectTree()->lookup(wname); if (item) { qWarning() << "Widget" << wname << "already exists! Skipping..."; return; } QByteArray classname, alternate; // check if this classname is an alternate one, and replace it if necessary classname = el.attribute("class").toLatin1(); alternate = container->form()->library()->classNameForAlternate(classname); QWidget *w; if (alternate == "CustomWidget") { w = new CustomWidget(classname, container->widget()); w->setObjectName(wname); } else { if (!alternate.isEmpty()) { classname = alternate; } WidgetFactory::CreateWidgetOptions widgetOptions = WidgetFactory::DefaultOptions; if (container->form()->mode() != Form::DesignMode) { widgetOptions ^= WidgetFactory::DesignViewMode; } if (!parent) w = container->form()->library()->createWidget(classname, container->widget(), wname.toLatin1(), container, widgetOptions); else w = container->form()->library()->createWidget(classname, parent, wname.toLatin1(), container, widgetOptions); } if (!w) return; //! @todo allow setting this for data view mode as well if (form->mode() == Form::DesignMode) { //don't generate accelerators for widgets in design mode KAcceleratorManager::setNoAccel(w); } w->show(); // We create and insert the ObjectTreeItem at the good place in the ObjectTree item = container->form()->objectTree()->lookup(wname); qDebug() << wname << item << classname << (parent ? parent->objectName() : QString()); if (!item) { // not yet created qDebug() << "Creating ObjectTreeItem:"; item = new ObjectTreeItem(container->form()->library()->displayName(classname), wname, w, container); if (parent) { ObjectTreeItem *titem = container->form()->objectTree()->lookup(parent->objectName()); if (titem) container->form()->objectTree()->addItem(titem, item); else qWarning() << "ERROR no parent widget"; } else container->form()->objectTree()->addItem(container->objectTree(), item); } //assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface //(e.g. KexiDBAutoField) if (container->form()->mode() == Form::DesignMode && dynamic_cast(w)) { dynamic_cast(w)->assignItem(item); } // if we are inside a Grid, we need to insert the widget in the good cell if (container->layoutType() == Form::Grid) { QGridLayout *layout = (QGridLayout*)container->layout(); if (el.hasAttribute("rowspan")) { // widget spans multiple cells if (layout) { layout->addWidget( w, el.attribute("row").toInt(), el.attribute("column").toInt(), el.attribute("rowspan").toInt(), el.attribute("colspan").toInt()); //! @todo alignment attribute? } item->setGridPos(el.attribute("row").toInt(), el.attribute("column").toInt(), el.attribute("rowspan").toInt(), el.attribute("colspan").toInt()); } else { if (layout) { layout->addWidget(w, el.attribute("row").toInt(), el.attribute("column").toInt()); } item->setGridPos(el.attribute("row").toInt(), el.attribute("column").toInt(), 0, 0); } } else if (container->layout()) container->layout()->addWidget(w); readChildNodes(item, container, el, w, buddies); if (item->container() && item->container()->layout()) item->container()->layout()->activate(); // add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later const QList autoSaveProperties( container->form()->library()->autoSaveProperties(w->metaObject()->className()) ); KFormDesigner::WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(w); QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w; foreach (const QByteArray &propName, autoSaveProperties) { if (subwidget && -1 != subwidget->metaObject()->indexOfProperty(propName)) { item->addModifiedProperty(propName, subwidget->property(propName)); } } const QVariant autoFillBackgroundValue = item->modifiedProperties()->value("autoFillBackground"); const QVariant paletteForegroundColorValue = item->modifiedProperties()->value("paletteForegroundColor"); if (!paletteForegroundColorValue.isNull() && autoFillBackgroundValue.isNull()) { // Sanity: force fill background if there's color but not 'fill background' set w->setAutoFillBackground(true); } } void FormIO::createToplevelWidget(Form *form, QWidget *container, QDomElement &el) { // We first look for the widget's name QString wname; for (QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { if ( n.toElement().tagName() == "property" && nameAttribute(n.toElement()) == "name" /* compat with 1.x */) { wname = n.toElement().text(); break; } } // And rename the widget and its ObjectTreeItem container->setObjectName(wname); if (form->objectTree()) form->objectTree()->rename(form->objectTree()->name(), wname); form->setInteractiveMode(false); QHash buddies; readChildNodes(form->objectTree(), form->toplevelContainer(), el, container, &buddies); // Now the Form is fully loaded, we can assign the buddies for (QHash::ConstIterator it(buddies.constBegin()); it!=buddies.constEnd(); ++it) { ObjectTreeItem *item = form->objectTree()->lookup(it.key()); if (!item || !item->widget()) { qDebug() << "Cannot assign buddy for widget " << it.value()->objectName() << " to " << it.key(); continue; } it.value()->setBuddy(item->widget()); } form->setInteractiveMode(true); } void FormIO::readChildNodes(ObjectTreeItem *item, Container *container, const QDomElement &el, QWidget *w, QHash *buddies) { QString eltag = el.tagName(); WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(w); QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w; for (QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling()) { QString tag = n.toElement().tagName(); QDomElement node = n.toElement(); if ((tag == "property") || (tag == "attribute")) { const QString name( node.attribute("name") ); const bool isQt3NameProperty = name == QLatin1String("name"); //if(name == "geometry") // hasGeometryProp = true; if ( (eltag == "grid" || eltag == "hbox" || eltag == "vbox") && (isQt3NameProperty || name == "objectName") ) { // we don't care about layout names continue; } if (node.attribute("subwidget") == "true") { //this is property for subwidget: remember it for delayed setting //because now the subwidget could be not created yet (true e.g. for KexiDBAutoField) item->addSubproperty(name.toLatin1(), readPropertyValue(container->form(), node.firstChild(), w, name)); const QVariant val(readPropertyValue(container->form(), node.firstChild(), w, name)); qDebug() << val.toStringList(); item->addSubproperty(name.toLatin1(), val); //subwidget->setProperty(name.toLatin1(), val); item->addModifiedProperty(name.toLatin1(), val); continue; } // We cannot assign the buddy now as the buddy widget may not be created yet if (name == "buddy") { if (buddies && qobject_cast(w)) { buddies->insert(readPropertyValue( container->form(), node.firstChild(), w, name).toString(), qobject_cast(w)); } } else if ( (eltag == "grid" || eltag == "hbox" || eltag == "vbox") && item->container() && item->container()->layout() ) { // We load the margin of a Layout if (name == "margin") { int margin = readPropertyValue(container->form(), node.firstChild(), w, name).toInt(); item->container()->setLayoutMargin(margin); item->container()->layout()->setMargin(margin); } // We load the spacing of a Layout else if (name == "spacing") { int spacing = readPropertyValue(container->form(), node.firstChild(), w, name).toInt(); item->container()->setLayoutSpacing(spacing); item->container()->layout()->setSpacing(spacing); } } else if (name == "paletteBackgroundColor" || name == "paletteForegroundColor") { QPalette widgetPalette(w->palette()); QVariant val(readPropertyValue(container->form(), node.firstChild(), w, name)); if (!val.isNull()) widgetPalette.setColor( name == "paletteBackgroundColor" ? w->backgroundRole() : w->foregroundRole(), val.value()); w->setPalette(widgetPalette); if (name == "paletteBackgroundColor") { w->setAutoFillBackground(val.value().isValid()); } item->addModifiedProperty(name.toLatin1(), val); } else if (!isQt3NameProperty && -1 == subwidget->metaObject()->indexOfProperty(name.toLatin1())) { // If the object doesn't have this property, we let the Factory handle it (maybe a special property) if (w->metaObject()->className() == QString::fromLatin1("CustomWidget")) item->storeUnknownProperty(node); else { bool read = container->form()->library()->readSpecialProperty( w->metaObject()->className(), node, w, item); if (!read) // the factory doesn't support this property neither item->storeUnknownProperty(node); } } else { // we have a normal property, let's load it QVariant val(readPropertyValue(container->form(), node.firstChild(), w, name)); if (name == "geometry" && dynamic_cast(w)) { //fix geometry if needed - this is top level form widget QRect r(val.toRect()); if (r.left() < 0) //negative X! r.moveLeft(0); if (r.top() < 0) //negative Y! r.moveTop(0); val = r; } QByteArray realName; if (isQt3NameProperty) { realName = "objectName"; } else { realName = name.toLatin1(); } subwidget->setProperty(realName, val); // int count = w->metaObject()->findProperty(name, true); // const QMetaProperty *meta = w->metaObject()->property(count, true); // if(meta && meta->isEnumType()) { // val = w->property(name.toLatin1()); //update: we want a numeric value of enum // } item->addModifiedProperty(realName, val); } } else if (tag == "widget") { // a child widget if (item->container()) // we are a Container loadWidget(item->container(), node, 0, buddies); else loadWidget(container, node, w, buddies); } else if (tag == "spacer") { loadWidget(container, node, w, buddies); } else if (tag == "grid") { // first, see if it is flow layout QString layoutName; for (QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) { if ( child.toElement().tagName() == "property" && child.toElement().attribute("name") == "customLayout") { layoutName = child.toElement().text(); break; } } if (layoutName == "HFlow") { } else if (layoutName == "VFlow") { } else { // grid layout item->container()->setLayoutType(Form::Grid); QGridLayout *layout = new QGridLayout(item->widget()); item->container()->setLayout((QLayout*)layout); } readChildNodes(item, container, node, w, buddies); } else if (tag == "vbox") { item->container()->setLayoutType(Form::VBox); QVBoxLayout *layout = new QVBoxLayout(item->widget()); item->container()->setLayout((QLayout*)layout); readChildNodes(item, container, node, w, buddies); } else if (tag == "hbox") { item->container()->setLayoutType(Form::HBox); QHBoxLayout *layout = new QHBoxLayout(item->widget()); item->container()->setLayout((QLayout*)layout); readChildNodes(item, container, node, w, buddies); } else {// unknown tag, we let the Factory handle it if (w->metaObject()->className() == QString::fromLatin1("CustomWidget")) item->storeUnknownProperty(node); else { bool read = container->form()->library()->readSpecialProperty( w->metaObject()->className(), node, w, item); if (!read) // the factory doesn't suport this property neither item->storeUnknownProperty(node); } } } } ///////////////////////////////////////////////////////////////////////////// ///////////// Helper functions ////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// void FormIO::addIncludeFileName(const QString &include, QDomDocument &domDoc) { if (include.isEmpty()) return; QDomElement includes; QDomElement uiEl = domDoc.firstChildElement("UI"); if (uiEl.firstChildElement("includehints").isNull()) { includes = domDoc.createElement("includehints"); uiEl.appendChild(includes); } else { includes = uiEl.firstChildElement("includehints"); } // Check if this include has already been saved, and return if it is the case for (QDomNode n = includes.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.toElement().text() == include) return; } QDomElement includeHint = domDoc.createElement("includehint"); includes.appendChild(includeHint); QDomText includeText = domDoc.createTextNode(include); includeHint.appendChild(includeText); } QString FormIO::saveImage(QDomDocument &domDoc, const QPixmap &pixmap) { QDomElement images = domDoc.firstChildElement("images"); if (images.isNull()) { images = domDoc.createElement("images"); QDomElement ui = domDoc.firstChildElement("UI"); ui.appendChild(images); } int count = images.childNodes().count(); QDomElement image = domDoc.createElement("image"); QString name = "image" + QString::number(count); image.setAttribute("name", name); const QImage img(pixmap.toImage()); QByteArray ba; QBuffer buf(&ba); buf.open(QIODevice::WriteOnly | QIODevice::Text); const QByteArray format(img.depth() > 1 ? "XPM" : "XBM"); QImageWriter imageWriter(&buf, format); imageWriter.write(img); buf.close(); const QByteArray bazip = qCompress(ba); const int len = bazip.size(); QDomElement data = domDoc.createElement("data"); data.setAttribute("format", QString(format + ".GZ")); data.setAttribute("length", ba.size()); static const char hexchars[] = "0123456789abcdef"; QString content; for (int i = 4; i < len; i++) { uchar s = (uchar) bazip[i]; content += hexchars[s >> 4]; content += hexchars[s & 0x0f]; } data.appendChild(domDoc.createTextNode(content)); image.appendChild(data); images.appendChild(image); return name; } QPixmap FormIO::loadImage(QDomDocument domDoc, const QString& name) { QDomElement images = domDoc.firstChildElement("UI").firstChildElement("images"); if (images.isNull()) return QPixmap(); QDomElement image; for (QDomNode n = images.firstChild(); !n.isNull(); n = n.nextSibling()) { if ((n.toElement().tagName() == "image") && (n.toElement().attribute("name") == name)) { image = n.toElement(); break; } } QPixmap pix; QString data(image.firstChildElement("data").text()); const int lengthOffset = 4; int baSize = data.length() / 2 + lengthOffset; uchar *ba = new uchar[baSize]; for (int i = lengthOffset; i < baSize; ++i) { char h = data[2 * (i-lengthOffset)].toLatin1(); char l = data[2 * (i-lengthOffset) + 1].toLatin1(); uchar r = 0; if (h <= '9') r += h - '0'; else r += h - 'a' + 10; r = r << 4; if (l <= '9') r += l - '0'; else r += l - 'a' + 10; ba[i] = r; } QString format = image.firstChildElement("data").attribute("format", "PNG"); if ((format == "XPM.GZ") || (format == "XBM.GZ")) { int len = image.attribute("length").toInt(); if (len < data.length() * 5) len = data.length() * 5; // qUncompress() expects the first 4 bytes to be the expected length of // the uncompressed data ba[0] = (len & 0xff000000) >> 24; ba[1] = (len & 0x00ff0000) >> 16; ba[2] = (len & 0x0000ff00) >> 8; ba[3] = (len & 0x000000ff); QByteArray baunzip = qUncompress(ba, baSize); pix.loadFromData((const uchar*)baunzip.data(), baunzip.size(), format.left(format.indexOf('.')).toLatin1()); } else pix.loadFromData((const uchar*)ba + lengthOffset, baSize - lengthOffset, format.toLatin1()); delete[] ba; return pix; } diff --git a/kexi/formeditor/form_p.h b/kexi/formeditor/form_p.h index 53c259d4629..88c1190d9cd 100644 --- a/kexi/formeditor/form_p.h +++ b/kexi/formeditor/form_p.h @@ -1,179 +1,180 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-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 KFORMDESIGNERFORM_P_H #define KFORMDESIGNERFORM_P_H #include #include +#include #include "resizehandle.h" #include "commands.h" #include "form.h" //! @todo pixmapcollection -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT #include "pixmapcollection.h" #endif #include #include #include class QStyleOption; namespace KFormDesigner { class ObjectTree; //! Used to alter the widget's style at design time class DesignModeStyle : public QProxyStyle { public: explicit DesignModeStyle(const QString &baseStyleName); //! Reimplemented to remove handling of the State_MouseOver state. virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *p, const QWidget *w = 0) const; private: QStyleOption* alterOption(ControlElement element, const QStyleOption *option) const; }; //-------------- //! @internal class FormPrivate { public: FormPrivate(Form *form, WidgetLibrary* _library); ~FormPrivate(); void enableAction(const char* name, bool enable); void initPropertiesDescription(); QString propertyCaption(const QByteArray &name); QString valueCaption(const QByteArray &name); void addPropertyCaption(const QByteArray &property, const QString &caption); void addValueCaption(const QByteArray &value, const QString &caption); KPropertyListData* createValueList(WidgetInfo *winfo, const QStringList &list); //! Sets color of selected widget(s) to value of @a p. //! @a roleMethod can be backgroundColor or foregroundColor. //! Makes background inherited if @a roleMethod if background and value is null. void setColorProperty(KProperty& p, QPalette::ColorRole (QWidget::*roleMethod)() const, const QVariant& value); Form::Mode mode; Form::State state; Form::Features features; QPoint insertionPoint; QPointer toplevel; ObjectTree *topTree; QPointer widget; KPropertySet propertySet; QWidgetList selected; ResizeHandleSet::Hash resizeHandles; QByteArray selectedClass; bool modified; bool interactive; bool isUndoing; bool isRedoing; bool snapToGrid; int gridSize; QString filename; KUndo2Stack undoStack; KActionCollection internalCollection; KActionCollection *collection; KFormDesigner::ActionGroup* widgetActionGroup; ObjectTreeList tabstops; bool autoTabstops; #ifdef KFD_SIGSLOTS ConnectionBuffer *connBuffer; #endif -#ifndef KEXI_NO_PIXMAPCOLLECTION +#ifdef KEXI_PIXMAP_COLLECTIONS_SUPPORT PixmapCollection *pixcollection; #endif //! This map is used to store cursor shapes before inserting (so we can restore them later) QHash cursors; //! This string list is used to store the widgets which hasMouseTracking() == true (eg lineedits) QStringList *mouseTrackers; FormWidget *formWidget; //! A set of head properties to be stored in a .ui file. //! This includes KFD format version. QHash headerProperties; //! Format version, set by FormIO or on creating a new form. int formatVersion; //! Format version, set by FormIO's loader or on creating a new form. int originalFormatVersion; #ifdef KFD_SIGSLOTS //! true is slot connection is curently being painted Connection *connection; #endif //! used to update command's value when undoing PropertyCommand *lastCommand; PropertyCommandGroup *lastCommandGroup; int idOfPropertyCommand; //! Command that being executed through Form::addCommand() const Command *executingCommand; bool slotPropertyChangedEnabled; bool slotPropertyChanged_addCommandEnabled; bool insideAddPropertyCommand; bool selectWidgetEnabled; // i18n stuff QMap propCaption; QMap propValCaption; QStyle *designModeStyle; QPointer inlineEditor; QPointer inlineEditorContainer; QByteArray editedWidgetClass; QString originalInlineText; bool pixmapsStoredInline; WidgetLibrary * const library; private: Form *q; }; } #endif diff --git a/kexi/formeditor/kexiactionselectiondialog.cpp b/kexi/formeditor/kexiactionselectiondialog.cpp index 9d655c7e66f..b8b83f5c91a 100644 --- a/kexi/formeditor/kexiactionselectiondialog.cpp +++ b/kexi/formeditor/kexiactionselectiondialog.cpp @@ -1,762 +1,762 @@ /* This file is part of the KDE project Copyright (C) 2005-2006 Jarosław Staniek Copyright (C) 2012 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 "kexiactionselectiondialog.h" #include "kexiactionselectiondialog_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class ActionSelectorDialogTreeItem : public QTreeWidgetItem { public: enum ActionRole{ ActionCategoryRole = Qt::UserRole + 1, ActionDataRole, ActionPluginIdRole }; ActionSelectorDialogTreeItem(QString label, QTreeWidget *parent) : QTreeWidgetItem(parent) { setText(0, label); } ActionSelectorDialogTreeItem(QString label, QTreeWidgetItem *parent) : QTreeWidgetItem(parent) { setText(0, label); } using QTreeWidgetItem::data; QVariant data(ActionRole role) { return QTreeWidgetItem::data(0, role); }; using QTreeWidgetItem::setData; void setData(ActionRole role, QVariant value) { QTreeWidgetItem::setData(0, role, value); } QIcon icon() { return QTreeWidgetItem::icon(0); } void setIcon(const QIcon& icon) { QTreeWidgetItem::setIcon(0, icon); } }; //--------------------------------------- ActionsListViewBase::ActionsListViewBase(QWidget* parent) : QTreeWidget(parent) { setColumnCount(1); setHeaderHidden(true); setRootIsDecorated(false); } ActionsListViewBase::~ActionsListViewBase() { } QTreeWidgetItem *ActionsListViewBase::itemForAction(const QString& actionName, QTreeWidgetItem* parent) { Q_UNUSED(parent); QTreeWidgetItemIterator it(this); while (*it) { ActionSelectorDialogTreeItem* itm = dynamic_cast(*it); if (itm && itm->data(ActionSelectorDialogTreeItem::ActionDataRole).toString() == actionName) return itm; ++it; } return 0; } void ActionsListViewBase::selectAction(const QString& actionName) { //qDebug() << "Selecting action:" << actionName; QTreeWidgetItem *itm = itemForAction(actionName); if (itm) { setCurrentItem(itm); itm->setSelected(true); } } //--------------------------------------- KActionsListViewBase::KActionsListViewBase(QWidget* parent) : ActionsListViewBase(parent) { } KActionsListViewBase::~KActionsListViewBase() {} void KActionsListViewBase::init() { const QPixmap noIcon(KexiUtils::emptyIcon(KIconLoader::Small)); QList sharedActions(KexiMainWindowIface::global()->allActions()); const Kexi::ActionCategories *acat = Kexi::actionCategories(); foreach(QAction *action, sharedActions) { // qDebug() << (*it)->name() << " " << (*it)->text(); //! @todo group actions //! @todo: store QAction * here? const int actionCategories = acat->actionCategories(action->objectName().toLatin1()); if (actionCategories == -1) { qWarning() << "no category declared for action \"" << action->objectName() << "\"! Fix this!"; continue; } if (!isActionVisible(action->objectName().toLatin1(), actionCategories)) continue; QString actionName; if (!action->toolTip().isEmpty()) { actionName = action->toolTip().remove("").remove(""); } else { actionName = action->text().remove('&'); } ActionSelectorDialogTreeItem *pitem = new ActionSelectorDialogTreeItem( actionName, this); pitem->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "kaction"); pitem->setData(ActionSelectorDialogTreeItem::ActionDataRole, action->objectName()); pitem->setIcon(action->icon()); if (pitem->icon().isNull()) pitem->setIcon(noIcon); } setSortingEnabled(true); } //--------------------------------------- //! @internal Used to display KActions (in column 2) class KActionsListView : public KActionsListViewBase { public: explicit KActionsListView(QWidget* parent) : KActionsListViewBase(parent) { } virtual ~KActionsListView() {} virtual bool isActionVisible(const char* actionName, int actionCategories) const { Q_UNUSED(actionName); return actionCategories & Kexi::GlobalActionCategory; } }; //! @internal Used to display KActions (in column 2) class CurrentFormActionsListView : public KActionsListViewBase { public: explicit CurrentFormActionsListView(QWidget* parent) : KActionsListViewBase(parent) { } virtual ~CurrentFormActionsListView() {} virtual bool isActionVisible(const char* actionName, int actionCategories) const { return actionCategories & Kexi::WindowActionCategory && Kexi::actionCategories()->actionSupportsObjectType(actionName, KexiPart::FormObjectType); } }; //! @internal a list view displaying action categories user can select from (column 1) class ActionCategoriesListView : public ActionsListViewBase { public: explicit ActionCategoriesListView(QWidget* parent) : ActionsListViewBase(parent) { ActionSelectorDialogTreeItem *itm = new ActionSelectorDialogTreeItem(xi18n("No action"), this ); itm->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "noaction"); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole, "noaction"); const QPixmap noIcon(KexiUtils::emptyIcon(KIconLoader::Small)); itm->setIcon(noIcon); itm = new ActionSelectorDialogTreeItem(xi18n("Application actions"), this ); itm->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "kaction"); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole, "kaction"); itm->setIcon(koIcon("calligrakexi")); KexiPart::PartInfoList *pl = Kexi::partManager().infoList(); if (pl) { foreach(KexiPart::Info *info, *pl) { KexiPart::Part *part = Kexi::partManager().part(info); if (!info->isVisibleInNavigator() || !part) continue; itm = new ActionSelectorDialogTreeItem(part->info()->name(), this ); itm->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "navObject"); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole, info->typeName()); itm->setData(ActionSelectorDialogTreeItem::ActionPluginIdRole, info->pluginId()); itm->setIcon(QIcon::fromTheme(part->info()->iconName())); } } QTreeWidgetItem *fitm = itemForAction("form"); if (fitm) { itm = new ActionSelectorDialogTreeItem(xi18nc("Current form's actions", "Current"), fitm); } else { itm = new ActionSelectorDialogTreeItem(xi18nc("Current form's actions", "Current"), this); } itm->setData(ActionSelectorDialogTreeItem::ActionCategoryRole, "currentForm"); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole, "currentForm"); itm->setIcon(koIcon("form")); expandAll(); setSortingEnabled(false); } ~ActionCategoriesListView() { } }; //! @internal Used to display list of actions available to executing (column 3) class ActionToExecuteListView : public ActionsListViewBase { public: explicit ActionToExecuteListView(QWidget* parent) : ActionsListViewBase(parent) { } ~ActionToExecuteListView() { } //! Updates actions void showActionsForPluginId(const QString& pluginId) { if (m_currentPluginId == pluginId) return; m_currentPluginId = pluginId; clear(); KexiPart::Part *part = Kexi::partManager().partForPluginId(m_currentPluginId); if (!part) return; Kexi::ViewModes supportedViewModes = part->info()->supportedViewModes(); ActionSelectorDialogTreeItem *itm; const QPixmap noIcon(KexiUtils::emptyIcon(KIconLoader::Small)); if (supportedViewModes & Kexi::DataViewMode) { itm = new ActionSelectorDialogTreeItem(xi18n("Open in Data View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "open"); itm->setIcon(koIcon("document-open")); } if (part->info()->isExecuteSupported()) { itm = new ActionSelectorDialogTreeItem(xi18n("Execute"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "execute"); itm->setIcon(koIcon("media-playback-start")); } -#ifndef KEXI_NO_QUICK_PRINTING +#ifdef KEXI_QUICK_PRINTING_SUPPORT if (part->info()->isPrintingSupported()) { ActionSelectorDialogListItem *printItem = new ActionSelectorDialogListItem( "print", this, futureI18n("Print")); printItem->setPixmap(0, koIcon("document-print")); QAction *a = KStandardAction::printPreview(0, 0, 0); item = new ActionSelectorDialogListItem("printPreview", printItem, a->text().remove('&').remove("...")); item->setPixmap(0, a->icon().pixmap(16)); delete a; item = new ActionSelectorDialogListItem( "pageSetup", printItem, futureI18n("Show Page Setup")); item->setPixmap(0, noIcon); setOpen(printItem, true); printItem->setExpandable(false); } #endif if (part->info()->isDataExportSupported()) { itm = new ActionSelectorDialogTreeItem( xi18nc("Note: use multiple rows if needed", "Export to File\nAs Data Table"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "exportToCSV"); itm->setIcon(koIcon("table")); QTreeWidgetItem *eitem = itm; itm = new ActionSelectorDialogTreeItem(xi18nc("Note: use multiple rows if needed", "Copy to Clipboard\nAs Data Table"), eitem); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "copyToClipboardAsCSV"); itm->setIcon(koIcon("table")); } itm = new ActionSelectorDialogTreeItem(xi18n("Create New Object"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "new"); itm->setIcon(koIcon("document-new")); if (supportedViewModes & Kexi::DesignViewMode) { itm = new ActionSelectorDialogTreeItem(xi18n("Open in Design View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "design"); itm->setIcon(koIcon("document-properties")); } if (supportedViewModes & Kexi::TextViewMode) { itm = new ActionSelectorDialogTreeItem(xi18n("Open in Text View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "editText"); itm->setIcon(noIcon); } itm = new ActionSelectorDialogTreeItem( xi18n("Close View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "close"); itm->setIcon(koIcon("window-close")); expandAll(); setSortingEnabled(true); } QString m_currentPluginId; }; //------------------------------------- //! @internal class KexiActionSelectionDialog::Private { public: Private() : kactionPageWidget(0), kactionListView(0), objectsListView(0) , currentFormActionsPageWidget(0) , currentFormActionsListView(0) , secondAnd3rdColumnMainWidget(0) , hideActionToExecuteListView(false) { } void raiseWidget(QWidget *w) { secondAnd3rdColumnStack->setCurrentWidget(w); } QString selectActionToBeExecutedMessage(const QString& actionType) const { QString msg; if (actionType == "noaction") return QString(); if (actionType == "kaction" || actionType == "currentForm") return xi18n("&Select action to be executed after clicking %1 button:", actionWidgetName); // hardcoded, but it's not that bad if (actionType == "org.kexi-project.macro") return xi18n("&Select macro to be executed after clicking %1 button:", actionWidgetName); if (actionType == "org.kexi-project.script") return xi18n("&Select script to be executed after clicking %1 button:", actionWidgetName); //default: org.kexi-project.table/query/form/report... return xi18n("&Select object to be opened after clicking %1 button:", actionWidgetName); } // changes 3rd column visibility void setActionToExecuteSectionVisible(bool visible) { actionToExecuteListView->setVisible(visible); actionToExecuteLbl->setVisible(visible); } QString actionWidgetName; ActionCategoriesListView* actionCategoriesListView; //!< for column #1 QWidget *kactionPageWidget; KActionsListView* kactionListView; //!< for column #2 KexiProjectNavigator* objectsListView; //!< for column #2 QWidget *currentFormActionsPageWidget; //!< for column #2 CurrentFormActionsListView* currentFormActionsListView; //!< for column #2 QWidget *emptyWidget; QLabel *selectActionToBeExecutedLabel; QLabel *kactionPageLabel; QLabel *currentFormActionsPageLabel; ActionToExecuteListView* actionToExecuteListView; QLabel *actionToExecuteLbl; QWidget *secondAnd3rdColumnMainWidget; QGridLayout *glyr; QGridLayout *secondAnd3rdColumnGrLyr; QStackedWidget *secondAnd3rdColumnStack; //, *secondColumnStack; bool hideActionToExecuteListView; QDialogButtonBox *buttonBox; }; //------------------------------------- static QLabel *createSelectActionLabel(QWidget *parent, QWidget *buddy) { QLabel *lbl = new QLabel(parent); lbl->setBuddy(buddy); lbl->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); lbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); lbl->setWordWrap(true); lbl->setMinimumHeight(lbl->fontMetrics().height()*2); return lbl; } //------------------------------------- KexiActionSelectionDialog::KexiActionSelectionDialog( QWidget *parent, const KexiFormEventAction::ActionData& action, const QString& actionWidgetName) : QDialog(parent) , d(new Private()) { setModal(true); setObjectName("actionSelectorDialog"); setWindowTitle(xi18nc("@title:window", "Assigning Action to Button")); // layout QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QWidget *mainWidget = new QWidget(this); mainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); mainLayout->addWidget(mainWidget); /* lbl 1 +------------+ +-------------------------------+ | | | [a] | | 1st column | | +----------- + +------------+ | | | | | 2nd column | | 3rd column | | | | | + + + + | | | | +------------+ +------------+ | +------------+ +-------------------------------+ \______________________________________________/ glyr [a]- QStackedWidget *secondAnd3rdColumnStack, - for displaying KActions, the stack contains d->kactionPageWidget QWidget - for displaying objects, the stack contains secondAnd3rdColumnMainWidget QWidget and QGridLayout *secondAnd3rdColumnGrLyr - kactionPageWidget contains only a QVBoxLayout and label+kactionListView */ d->glyr = new QGridLayout(mainWidget); // 2x2 KexiUtils::setStandardMarginsAndSpacing(d->glyr); d->glyr->setRowStretch(1, 1); // 1st column: action types d->actionCategoriesListView = new ActionCategoriesListView(mainWidget); d->actionCategoriesListView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); d->glyr->addWidget(d->actionCategoriesListView, 1, 0); connect(d->actionCategoriesListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotActionCategorySelected(QTreeWidgetItem*))); QLabel *lbl = new QLabel(xi18n("Action category:"), mainWidget); lbl->setBuddy(d->actionCategoriesListView); lbl->setMinimumHeight(lbl->fontMetrics().height()*2); lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); lbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); lbl->setWordWrap(true); d->glyr->addWidget(lbl, 0, 0, Qt::AlignTop | Qt::AlignLeft); // widget stack for 2nd and 3rd column d->secondAnd3rdColumnStack = new QStackedWidget(mainWidget); d->secondAnd3rdColumnStack->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); d->glyr->addWidget(d->secondAnd3rdColumnStack, 0, 1, 2, 1); d->secondAnd3rdColumnMainWidget = new QWidget(d->secondAnd3rdColumnStack); d->secondAnd3rdColumnMainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); d->secondAnd3rdColumnGrLyr = new QGridLayout(d->secondAnd3rdColumnMainWidget); //! @todo KEXI3 QDialog::resizeLayout(d->secondAnd3rdColumnGrLyr, 0, KexiUtils::spacingHint()); d->secondAnd3rdColumnGrLyr->setRowStretch(1, 2); d->secondAnd3rdColumnStack->addWidget(d->secondAnd3rdColumnMainWidget); // 2nd column: list of actions/objects d->objectsListView = new KexiProjectNavigator(d->secondAnd3rdColumnMainWidget, KexiProjectNavigator::Borders); d->secondAnd3rdColumnGrLyr->addWidget(d->objectsListView, 1, 0); d->secondAnd3rdColumnGrLyr->setColumnStretch(0,1); d->secondAnd3rdColumnGrLyr->setColumnStretch(1,1); connect(d->objectsListView, SIGNAL(selectionChanged(KexiPart::Item*)), this, SLOT(slotItemForOpeningOrExecutingSelected(KexiPart::Item*))); d->selectActionToBeExecutedLabel = createSelectActionLabel(d->secondAnd3rdColumnMainWidget, 0); d->secondAnd3rdColumnGrLyr->addWidget( d->selectActionToBeExecutedLabel, 0, 0, Qt::AlignTop | Qt::AlignLeft); d->emptyWidget = new QWidget(d->secondAnd3rdColumnStack); d->secondAnd3rdColumnStack->addWidget(d->emptyWidget); // 3rd column: actions to execute d->actionToExecuteListView = new ActionToExecuteListView(d->secondAnd3rdColumnMainWidget); d->actionToExecuteListView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); connect(d->actionToExecuteListView, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotActionToExecuteItemExecuted(QTreeWidgetItem*))); connect(d->actionToExecuteListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotActionToExecuteItemSelected(QTreeWidgetItem*))); d->secondAnd3rdColumnGrLyr->addWidget(d->actionToExecuteListView, 1, 1); d->actionToExecuteLbl = createSelectActionLabel(d->secondAnd3rdColumnMainWidget, d->actionToExecuteListView); d->actionToExecuteLbl->setText(xi18n("Action to execute:")); d->secondAnd3rdColumnGrLyr->addWidget(d->actionToExecuteLbl, 0, 1, Qt::AlignTop | Qt::AlignLeft); // temporary show all sections to avoid resizing the dialog in the future d->actionCategoriesListView->selectAction("table"); d->setActionToExecuteSectionVisible(true); adjustSize(); resize(qMax(700, width()), qMax(450, height())); bool ok; QString actionType, actionArg; KexiPart::Info* partInfo = action.decodeString(actionType, actionArg, &ok); if (ok) { d->actionCategoriesListView->selectAction(actionType); if (actionType == "kaction") { d->kactionListView->selectAction(actionArg); d->kactionListView->setFocus(); } else if (actionType == "currentForm") { d->currentFormActionsListView->selectAction(actionArg); d->currentFormActionsListView->setFocus(); } else if (partInfo && Kexi::partManager().part(partInfo)) // We use the Part Manager // to determine whether the Kexi-plugin is installed and whether we like to show // it in our list of actions. { KexiPart::Item *item = KexiMainWindowIface::global()->project()->item( partInfo, actionArg); if (d->objectsListView && item) { d->objectsListView->selectItem(*item); slotItemForOpeningOrExecutingSelected(item); QString actionOption(action.option); if (actionOption.isEmpty()) { actionOption = "open"; // for backward compatibility } d->actionToExecuteListView->selectAction(actionOption); d->objectsListView->setFocus(); } } } else {//invalid assignment or 'noaction' d->actionCategoriesListView->selectAction("noaction"); d->actionCategoriesListView->setFocus(); } // buttons d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = d->buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(d->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(d->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); d->actionWidgetName = actionWidgetName; d->buttonBox->button(QDialogButtonBox::Ok)->setText(xi18nc("Assign action", "&Assign")); //buttonBox->button(QDialogButtonBox::Ok)->setIcon(koIconName("dialog-ok")); d->buttonBox->button(QDialogButtonBox::Ok)->setToolTip(xi18n("Assign action")); mainLayout->addWidget(d->buttonBox); } KexiActionSelectionDialog::~KexiActionSelectionDialog() { delete d; } void KexiActionSelectionDialog::slotKActionItemExecuted(QTreeWidgetItem*) { accept(); } void KexiActionSelectionDialog::slotKActionItemSelected(QTreeWidgetItem*) { d->setActionToExecuteSectionVisible(false); updateOKButtonStatus(); } void KexiActionSelectionDialog::slotCurrentFormActionItemExecuted(QTreeWidgetItem*) { accept(); } void KexiActionSelectionDialog::slotCurrentFormActionItemSelected(QTreeWidgetItem*) { d->setActionToExecuteSectionVisible(false); updateOKButtonStatus(); } void KexiActionSelectionDialog::slotItemForOpeningOrExecutingSelected(KexiPart::Item* item) { d->setActionToExecuteSectionVisible(item); } void KexiActionSelectionDialog::slotActionToExecuteItemExecuted(QTreeWidgetItem* item) { if (!item) return; ActionSelectorDialogTreeItem *listItem = dynamic_cast(item); if (listItem && listItem->data(ActionSelectorDialogTreeItem::ActionDataRole).isValid()) accept(); } void KexiActionSelectionDialog::slotActionToExecuteItemSelected(QTreeWidgetItem*) { //qDebug(); updateOKButtonStatus(); } void KexiActionSelectionDialog::slotActionCategorySelected(QTreeWidgetItem* item) { ActionSelectorDialogTreeItem *categoryItm = dynamic_cast(item); // simple case: part-less item, e.g. kaction: if (categoryItm) { if (categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "kaction") { if (!d->kactionPageWidget) { //create lbl+list view with a vlayout d->kactionPageWidget = new QWidget(); d->kactionPageWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); QVBoxLayout *vlyr = new QVBoxLayout(d->kactionPageWidget); KexiUtils::setMargins(vlyr, 0); vlyr->setSpacing(KexiUtils::spacingHint()); d->kactionListView = new KActionsListView(d->kactionPageWidget); d->kactionListView->init(); d->kactionPageLabel = createSelectActionLabel(d->kactionPageWidget, d->kactionListView); vlyr->addWidget(d->kactionPageLabel); vlyr->addWidget(d->kactionListView); d->secondAnd3rdColumnStack->addWidget(d->kactionPageWidget); connect(d->kactionListView, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotKActionItemExecuted(QTreeWidgetItem*))); connect(d->kactionListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotKActionItemSelected(QTreeWidgetItem*))); } d->kactionPageLabel->setText( d->selectActionToBeExecutedMessage(categoryItm->data(ActionSelectorDialogTreeItem::ActionDataRole).toString())); d->setActionToExecuteSectionVisible(false); d->raiseWidget(d->kactionPageWidget); slotKActionItemSelected(d->kactionListView->currentItem()); //to refresh column #3 } else if (categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "currentForm") { if (!d->currentFormActionsPageWidget) { //create lbl+list view with a vlayout d->currentFormActionsPageWidget = new QWidget(); d->currentFormActionsPageWidget->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum); QVBoxLayout *vlyr = new QVBoxLayout(d->currentFormActionsPageWidget); KexiUtils::setMargins(vlyr, 0); vlyr->setSpacing(KexiUtils::spacingHint()); d->currentFormActionsListView = new CurrentFormActionsListView( d->currentFormActionsPageWidget); d->currentFormActionsListView->init(); d->currentFormActionsPageLabel = createSelectActionLabel( d->currentFormActionsPageWidget, d->currentFormActionsListView); vlyr->addWidget(d->currentFormActionsPageLabel); vlyr->addWidget(d->currentFormActionsListView); d->secondAnd3rdColumnStack->addWidget(d->currentFormActionsPageWidget); connect(d->currentFormActionsListView, SIGNAL(itemActivated(QTreeWidgetItem*)), this, SLOT(slotCurrentFormActionItemExecuted(QTreeWidgetItem*))); connect(d->currentFormActionsListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotCurrentFormActionItemSelected(QTreeWidgetItem*))); } d->currentFormActionsPageLabel->setText( d->selectActionToBeExecutedMessage(categoryItm->data(ActionSelectorDialogTreeItem::ActionDataRole).toString())); d->setActionToExecuteSectionVisible(false); d->raiseWidget(d->currentFormActionsPageWidget); slotCurrentFormActionItemSelected(d->currentFormActionsListView->currentItem()); //to refresh column #3 } else if (categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "noaction") { d->raiseWidget(d->emptyWidget); d->objectsListView->clearSelection(); //hide column #3 d->setActionToExecuteSectionVisible(false); } else if (categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "navObject") { QString pluginId = categoryItm->data(ActionSelectorDialogTreeItem::ActionPluginIdRole).toString(); d->selectActionToBeExecutedLabel->setText(d->selectActionToBeExecutedMessage(pluginId)); if (d->objectsListView->itemsPluginId() != pluginId) { QString errorString; d->objectsListView->setProject(KexiMainWindowIface::global()->project(), pluginId, &errorString, false); d->actionToExecuteListView->showActionsForPluginId(pluginId); d->setActionToExecuteSectionVisible(false); } if (d->secondAnd3rdColumnStack->currentWidget() != d->secondAnd3rdColumnMainWidget) { d->raiseWidget(d->secondAnd3rdColumnMainWidget); d->objectsListView->clearSelection(); d->setActionToExecuteSectionVisible(false); } else { d->raiseWidget(d->secondAnd3rdColumnMainWidget); } d->selectActionToBeExecutedLabel->setBuddy(d->secondAnd3rdColumnMainWidget); } d->actionCategoriesListView->update(); updateOKButtonStatus(); return; } d->actionCategoriesListView->update(); d->actionToExecuteListView->update(); updateOKButtonStatus(); } KexiFormEventAction::ActionData KexiActionSelectionDialog::currentAction() const { KexiFormEventAction::ActionData data; ActionSelectorDialogTreeItem *categoryItm = dynamic_cast(d->actionCategoriesListView->currentItem()); if (categoryItm) { QString actionCategory = categoryItm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString(); if (actionCategory == "kaction") { if (d->kactionListView->currentItem()) { data.string = QString("kaction:") + dynamic_cast(d->kactionListView->currentItem())->data(ActionSelectorDialogTreeItem::ActionDataRole).toString(); return data; } } else if (actionCategory == "currentForm") { if (d->currentFormActionsListView->currentItem()) { data.string = QString("currentForm:") + dynamic_cast( d->currentFormActionsListView->currentItem())->data(ActionSelectorDialogTreeItem::ActionDataRole).toString(); return data; } } else if (actionCategory == "noaction") { return data; } else if (actionCategory == "navObject") { ActionSelectorDialogTreeItem *actionToExecute = dynamic_cast(d->actionToExecuteListView->currentItem()); if (d->objectsListView && actionToExecute && !actionToExecute->data(ActionSelectorDialogTreeItem::ActionDataRole).toString().isEmpty()) { KexiPart::Item* partItem = d->objectsListView->selectedPartItem(); KexiPart::Info* partInfo = partItem ? Kexi::partManager().infoForPluginId(partItem->pluginId()) : 0; if (partInfo) { // opening or executing: table:name, query:name, form:name, macro:name, script:name, etc. data.string = QString("%1:%2").arg(partInfo->typeName()).arg(partItem->name()); data.option = actionToExecute->data(ActionSelectorDialogTreeItem::ActionDataRole).toString(); return data; } } } else { qWarning() << "No current category item"; } } return data; // No Action } void KexiActionSelectionDialog::updateOKButtonStatus() { ActionSelectorDialogTreeItem *itm = dynamic_cast(d->actionCategoriesListView->currentItem()); //qDebug() << "Current Action:" << currentAction().string << ":" << currentAction().option; QPushButton *btn = d->buttonBox->button(QDialogButtonBox::Ok); btn->setEnabled((itm && itm->data(ActionSelectorDialogTreeItem::ActionCategoryRole).toString() == "noaction") || !currentAction().isEmpty()); } diff --git a/kexi/formeditor/kexiformeventhandler.cpp b/kexi/formeditor/kexiformeventhandler.cpp index 19e1193eb09..0ff4208f580 100644 --- a/kexi/formeditor/kexiformeventhandler.cpp +++ b/kexi/formeditor/kexiformeventhandler.cpp @@ -1,231 +1,232 @@ /* This file is part of the KDE project Copyright (C) 2005-2006 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 "kexiformeventhandler.h" #include #include #include #include #include #include +#include #include #include #include #include #include #include KexiFormEventAction::ActionData::ActionData() { } bool KexiFormEventAction::ActionData::isEmpty() const { return string.isEmpty(); } KexiPart::Info* KexiFormEventAction::ActionData::decodeString( QString& actionType, QString& actionArg, bool *ok) const { Q_ASSERT(ok); const int idx = string.indexOf(':'); *ok = false; if (idx == -1) return 0; const QString _actionType = string.left(idx); const QString _actionArg = string.mid(idx + 1); if (_actionType.isEmpty() || _actionArg.isEmpty()) return 0; KexiPart::Info *info = 0; if (_actionType != "kaction" && _actionType != "currentForm") { info = Kexi::partManager().infoForPluginId(QString("org.kexi-project.%1").arg(_actionType)); if (!info) return 0; } actionType = _actionType; actionArg = _actionArg; *ok = true; return info; } //------------------------------------- class KexiFormEventAction::Private { public: Private(const QString& actionName_, const QString& objectName_, const QString actionOption_); ~Private(); QString actionName, objectName, actionOption; }; KexiFormEventAction::Private::Private(const QString& actionName_, const QString& objectName_, const QString actionOption_) :actionName(actionName_), objectName(objectName_), actionOption(actionOption_) { } KexiFormEventAction::Private::~Private() { } KexiFormEventAction::KexiFormEventAction(QObject* parent, const QString& actionName, const QString& objectName, const QString& actionOption) : QAction(parent) ,d(new Private(actionName, objectName, actionOption)) { connect(this, SIGNAL(triggered()), this, SLOT(trigger())); } KexiFormEventAction::~KexiFormEventAction() { delete d; } void KexiFormEventAction::slotTrigger() { qDebug() << d->actionName << d->objectName; KexiProject* project = KexiMainWindowIface::global()->project(); if (!project) return; KexiPart::Part* part = Kexi::partManager().partForPluginId( QString("org.kexi-project.%1").arg(d->actionName)); if (!part) return; KexiPart::Item* item = project->item(part->info(), d->objectName); if (!item) return; bool actionCancelled = false; if (d->actionOption.isEmpty()) { // backward compatibility (good defaults) if (part->info()->isExecuteSupported()) part->execute(item, parent()); else KexiMainWindowIface::global()->openObject(item, Kexi::DataViewMode, &actionCancelled); } else { //! @todo react on failure... if (d->actionOption == "open") KexiMainWindowIface::global()->openObject(item, Kexi::DataViewMode, &actionCancelled); else if (d->actionOption == "execute") part->execute(item, parent()); else if (d->actionOption == "print") { if (part->info()->isPrintingSupported()) KexiMainWindowIface::global()->printItem(item); } -#ifndef KEXI_NO_QUICK_PRINTING +#ifdef KEXI_QUICK_PRINTING_SUPPORT else if (d->actionOption == "printPreview") { if (part->info()->isPrintingSupported()) KexiMainWindowIface::global()->printPreviewForItem(item); } else if (d->actionOption == "pageSetup") { if (part->info()->isPrintingSupported()) KexiMainWindowIface::global()->showPageSetupForItem(item); } #endif else if (d->actionOption == "exportToCSV" || d->actionOption == "copyToClipboardAsCSV") { if (part->info()->isDataExportSupported()) KexiMainWindowIface::global()->executeCustomActionForObject(item, d->actionOption); } else if (d->actionOption == "new") KexiMainWindowIface::global()->newObject(part->info(), &actionCancelled); else if (d->actionOption == "design") KexiMainWindowIface::global()->openObject(item, Kexi::DesignViewMode, &actionCancelled); else if (d->actionOption == "editText") KexiMainWindowIface::global()->openObject(item, Kexi::TextViewMode, &actionCancelled); else if (d->actionOption == "close") { tristate res = KexiMainWindowIface::global()->closeObject(item); if (~res) actionCancelled = true; } } } //------------------------------------------ class KexiFormEventHandler::Private { public: Private(); ~Private() { } QWidget *mainWidget; }; KexiFormEventHandler::Private::Private() : mainWidget(0) { } KexiFormEventHandler::KexiFormEventHandler() : d(new Private()) { } KexiFormEventHandler::~KexiFormEventHandler() { delete d; } void KexiFormEventHandler::setMainWidgetForEventHandling(QWidget* mainWidget) { d->mainWidget = mainWidget; if (!d->mainWidget) return; //find widgets whose will work as data items //! @todo look for other widgets too QList widgets(d->mainWidget->findChildren()); foreach(QWidget *widget, widgets) { if (!widget->inherits("QPushButton") ){ continue; } bool ok; KexiFormEventAction::ActionData data; data.string = widget->property("onClickAction").toString(); data.option = widget->property("onClickActionOption").toString(); if (data.isEmpty()) continue; QString actionType, actionArg; KexiPart::Info* partInfo = data.decodeString(actionType, actionArg, &ok); if (!ok) continue; qDebug() << "actionType:" << actionType << "actionArg:" << actionArg; if (actionType == "kaction" || actionType == "currentForm") { QAction *action = KexiMainWindowIface::global()->actionCollection()->action( actionArg); if (!action) continue; QObject::disconnect(widget, SIGNAL(clicked()), action, SLOT(trigger())); //safety QObject::connect(widget, SIGNAL(clicked()), action, SLOT(trigger())); } else if (partInfo) { //'open or execute' action KexiFormEventAction* action = new KexiFormEventAction(widget, actionType, actionArg, data.option); QObject::disconnect(widget, SIGNAL(clicked()), action, SLOT(slotTrigger())); QObject::connect(widget, SIGNAL(clicked()), action, SLOT(slotTrigger())); } } } diff --git a/kexi/formeditor/widgetfactory.cpp b/kexi/formeditor/widgetfactory.cpp index 51bf30a9f4e..3c79390c77d 100644 --- a/kexi/formeditor/widgetfactory.cpp +++ b/kexi/formeditor/widgetfactory.cpp @@ -1,379 +1,379 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-2009 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 "widgetfactory.h" #include #include #include "richtextdialog.h" -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT # include "editlistviewdialog.h" #endif #include "form.h" #include "container.h" #include "objecttree.h" #include "widgetlibrary.h" #include "WidgetInfo.h" +#include "widgetwithsubpropertiesinterface.h" #include "utils.h" +#include -#include "widgetwithsubpropertiesinterface.h" #include #include -#include #include #include #include #include using namespace KFormDesigner; InternalPropertyHandlerInterface::InternalPropertyHandlerInterface() { } InternalPropertyHandlerInterface::~InternalPropertyHandlerInterface() { } ///// InlineEditorCreationArguments ////////////////////////// WidgetFactory::InlineEditorCreationArguments::InlineEditorCreationArguments( const QByteArray& _classname, QWidget *_widget, Container *_container) : classname(_classname), widget(_widget), container(_container), geometry(_widget ? _widget->geometry() : QRect()), alignment( Qt::AlignLeft ), useFrame( false ), multiLine( false ), execute( true ), transparentBackground( false ) { } ///// Widget Factory ////////////////////////// class WidgetFactory::Private { public: Private(); ~Private(); WidgetLibrary *library; QHash classesByName; QSet* hiddenClasses; //! i18n stuff QHash propDesc; QHash propValDesc; //! internal properties QHash internalProp; /*! flag useful to decide whether to hide some properties. It's value is inherited from WidgetLibrary. */ bool advancedPropertiesVisible; }; WidgetFactory::Private::Private() : hiddenClasses(0), advancedPropertiesVisible(true) { } WidgetFactory::Private::~Private() { qDeleteAll(classesByName); delete hiddenClasses; } WidgetFactory::WidgetFactory(QObject *parent) : QObject(parent), d(new Private()) { } WidgetFactory::~WidgetFactory() { delete d; } void WidgetFactory::addClass(WidgetInfo *w) { WidgetInfo *oldw = d->classesByName.value(w->className()); if (oldw == w) return; if (oldw) { qWarning() << "class with name '" << w->className() << "' already exists for factory '" << objectName() << "'"; return; } d->classesByName.insert(w->className(), w); } void WidgetFactory::hideClass(const char *classname) { if (!d->hiddenClasses) d->hiddenClasses = new QSet; d->hiddenClasses->insert(QByteArray(classname).toLower()); } QHash WidgetFactory::classes() const { return d->classesByName; } void WidgetFactory::disableFilter(QWidget *w, Container *container) { container->form()->disableFilter(w, container); } bool WidgetFactory::editList(QWidget *w, QStringList &list) const { //! @todo KEXI3 port to QDialog #if 1 Q_UNUSED(w); Q_UNUSED(list); #else QDialog dialog(w->topLevelWidget()); dialog.setObjectName("stringlist_dialog"); dialog.setModal(true); dialog.setWindowTitle(xi18nc("@title:window", "Edit Contents of %1", w->objectName())); dialog.setButtons(QDialog::Ok | QDialog::Cancel); QVBoxLayout *mainLayout = new QVBoxLayout; dialog.setLayout(mainLayout); KEditListWidget *edit = new KEditListWidget(&dialog); edit->setObjectName("editlist"); edit->insertStringList(list); mainLayout->addWidget(edit); // buttons QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); mainLayout->addWidget(buttonBox); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); if (dialog.exec() == QDialog::Accepted) { list = edit->items(); return true; } #endif return false; } bool WidgetFactory::editRichText(QWidget *w, QString &text) const { RichTextDialog dlg(w, text); if (dlg.exec() == QDialog::Accepted) { text = dlg.text(); return true; } return false; } -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT void WidgetFactory::editListWidget(QListWidget *listwidget) const { EditListViewDialog dlg(((QWidget*)listwidget)->topLevelWidget()); //! @todo //dlg.exec(listview); } #endif void WidgetFactory::changeProperty(Form *form, QWidget *widget, const char *name, const QVariant &value) { if (form->selectedWidget()) { // single selection form->propertySet()->changePropertyIfExists(name, value); widget->setProperty(name, value); } else { // If eg multiple labels are selected, // we only want to change the text of one of them (the one the user cliked on) if (widget) { widget->setProperty(name, value); } else { form->selectedWidgets()->first()->setProperty(name, value); } } } bool WidgetFactory::isPropertyVisible(const QByteArray &classname, QWidget *w, const QByteArray &property, bool multiple, bool isTopLevel) { if (multiple) { return property == "font" || property == "paletteBackgroundColor" || property == "enabled" || property == "paletteForegroundColor" || property == "cursor" || property == "paletteBackgroundPixmap"; } return isPropertyVisibleInternal(classname, w, property, isTopLevel); } bool WidgetFactory::isPropertyVisibleInternal(const QByteArray &, QWidget *w, const QByteArray &property, bool isTopLevel) { Q_UNUSED(w); -#ifdef KEXI_NO_CURSOR_PROPERTY +#ifndef KEXI_FORM_CURSOR_PROPERTY_SUPPORT //! @todo temporary unless cursor works properly in the Designer if (property == "cursor") return false; #endif if (property == "acceptDrops" || property == "inputMethodHints") return false; if (!isTopLevel && (property == "windowTitle" || property == "windowIcon" || property == "sizeIncrement" || property == "windowIconText")) { // don't show these properties for a non-toplevel widget return false; } return true; } bool WidgetFactory::propertySetShouldBeReloadedAfterPropertyChange( const QByteArray& classname, QWidget *w, const QByteArray& property) { Q_UNUSED(classname) Q_UNUSED(w) Q_UNUSED(property) return false; } void WidgetFactory::resizeEditor(QWidget *, QWidget *, const QByteArray&) { } bool WidgetFactory::clearWidgetContent(const QByteArray &, QWidget *) { return false; } bool WidgetFactory::changeInlineText(Form *form, QWidget *widget, const QString& text, QString &oldText) { oldText = widget->property("text").toString(); changeProperty(form, widget, "text", text); return true; } bool WidgetFactory::readSpecialProperty(const QByteArray &, QDomElement &, QWidget *, ObjectTreeItem *) { return false; } bool WidgetFactory::saveSpecialProperty(const QByteArray &, const QString &, const QVariant&, QWidget *, QDomElement &, QDomDocument &) { return false; } bool WidgetFactory::inheritsFactories() { foreach (WidgetInfo *winfo, d->classesByName) { if (!winfo->parentFactoryName().isEmpty()) return true; } return false; } void WidgetFactory::setPropertyOptions(KPropertySet& set, const WidgetInfo& info, QWidget *w) { Q_UNUSED(set) Q_UNUSED(info) Q_UNUSED(w) //nothing } ObjectTreeItem* WidgetFactory::selectableItem(ObjectTreeItem* item) { return item; } void WidgetFactory::setInternalProperty(const QByteArray &classname, const QByteArray &property, const QVariant &value) { d->internalProp.insert(classname + ":" + property, value); } QVariant WidgetFactory::internalProperty(const QByteArray &classname, const QByteArray &property) const { return d->internalProp.value(classname + ":" + property); } QString WidgetFactory::propertyDescription(const char* name) const { return d->propDesc.value(name); } QString WidgetFactory::valueDescription(const char* name) const { return d->propValDesc.value(name); } WidgetInfo* WidgetFactory::widgetInfoForClassName(const char* classname) { return d->classesByName.value(classname); } const QSet *WidgetFactory::hiddenClasses() const { return d->hiddenClasses; } WidgetLibrary* WidgetFactory::library() { return d->library; } bool WidgetFactory::advancedPropertiesVisible() const { return d->advancedPropertiesVisible; } void WidgetFactory::setLibrary(WidgetLibrary* library) { d->library = library; } void WidgetFactory::setAdvancedPropertiesVisible(bool set) { d->advancedPropertiesVisible = set; } void WidgetFactory::setPropertyDescription(const char* property, const QString &description) { d->propDesc.insert(property, description); } void WidgetFactory::setValueDescription(const char *valueName, const QString &description) { d->propValDesc.insert(valueName, description); } diff --git a/kexi/formeditor/widgetfactory.h b/kexi/formeditor/widgetfactory.h index b92479e437f..e31fdab4a2f 100644 --- a/kexi/formeditor/widgetfactory.h +++ b/kexi/formeditor/widgetfactory.h @@ -1,382 +1,383 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-2009 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 KFORMDESIGNERWIDGETFACTORY_H #define KFORMDESIGNERWIDGETFACTORY_H #include #include #include +#include #include "kformdesigner_export.h" class QWidget; class QListWidget; class QMenu; class QDomElement; class QDomDocument; class QVariant; class KActionCollection; class KPropertySet; namespace KFormDesigner { class Container; class ObjectTreeItem; class Form; class WidgetLibrary; class WidgetInfo; //! Used by WidgetFactory class KFORMDESIGNER_EXPORT InternalPropertyHandlerInterface { protected: InternalPropertyHandlerInterface(); virtual ~InternalPropertyHandlerInterface(); /*! Assigns \a value for internal property \a property for a class \a classname. Internal properties are not stored within objects, but can be provided to describe class' details. */ virtual void setInternalProperty(const QByteArray& classname, const QByteArray& property, const QVariant& value) = 0; friend class WidgetInfo; }; //! The base class for all widget Factories /*! This is the class you need to inherit to create a new Factory. There are few virtuals you need to implement, and some other functions to implement if you want more features.\n \n Widget Creation\n To be able to create widgets, you need to implement the create() function, an classes(), which should return all the widgets supported by this factory.\n \n GUI Integration\n The following functions allow you to customize even more the look-n-feel of your widgets inside KFormDesigner. You can use createMenuActions() to add custom items in widget's context menu. The previewWidget() is called when the Form gets in Preview mode, and you have a last opportunity to remove all editing-related stuff (see eg \ref Spring class).\n You can also choose which properties to show in the Property Editor. By default, most all properties are shown (see implementation for details), but you can hide some reimplementing isPropertyVisibleInternal() (don't forget to call superclass' method) To add new properties, just define new Q_PROPERTY in widget class definition.\n \n Inline editing\n KFormDesigner allow you to edit the widget's contents inside Form, without using a dialog. You can of course customize the behaviour of your widgets, using startInlineEditing(). There are some editing modes already implemented in WidgetFactroy, but you can create your own if you want: \li Editing using a line edit (createInlineEditor()): a line edit is created on top of widget, where the user inputs text. As the text changes, changeInlineText() is called (where you should set your widget's text and resize widget to fit the text if needed) and resizeEditor() to update editor's position when widget is moved/resized.\n \li Editing by disabling event filter: if you call disableFilter(), the event filter on the object is temporarily disabled, so the widget behaves as usual. This can be used for more complex widgets, such as spinbox, date/time edit, etc. \li Other modes: there are 3 other modes, to edit a string list: editList() (for combo box, listbox), to edit rich text: editRichText() (for labels, etc.)\n \n Widget saving/loading\n You can also control how your widget are saved/loaded. You can choose which properties to save (see autoSaveProperties()), and save/load custom properties, ie properties that are not Q_PROPERTY but you want to save in the UI file. This is used eg to save combo box or list widget contents (see saveSpecialProperty() and readSpecialProperty()). \n \n Special internal properties\n Use void WidgetInfo::setInternalProperty(const QByteArray& property, const QVariant& value) to set values of special internal properties. Currently these properties are used for customizing popup menu items used for orientation selection. Customization for class ClassName should look like: WidgetInfo *wi = ... wi->setInternalProperty("orientationSelectionPopup", true); wi->setInternalProperty("orientationSelectionPopup:horizontalIcon", "myicon"); Available internal properties: * "orientationSelectionPopup" - set it to true if you want a given class to offer orientation selection, so orientation selection popup will be displayed when needed. * "orientationSelectionPopup:horizontalIcon" - sets a name of icon for "Horizontal" item for objects of class 'ClassName'. Set this property only for classes supporting orientations. * "orientationSelectionPopup:verticalIcon" - the same for "Vertical" item. Set this property only for classes supporting orientations. * "orientationSelectionPopup:horizontalText" - sets a i18n'd text for "Horizontal" item for objects of class 'ClassName', e.g. xi18n("Insert Horizontal Line"). Set this property only for classes supporting orientations. * "orientationSelectionPopup:verticalText" - the same for "Vertical" item, e.g. xi18n("Insert Vertical Line"). Set this property only for classes supporting orientations. * "dontStartEditingOnInserting" - if true, WidgetFactory::startInlineEditing() will not be executed upon widget inseting by a user. * "forceShowAdvancedProperty:{propertyname}" - set it to true for "{propertyname}" advanced property if you want to force it to be visible even if WidgetLibrary::setAdvancedPropertiesVisible(false) has been called. For example, setting "forceShowAdvancedProperty:pixmap" to true unhides "pixmap" property for a given class. See KexiStandardFormWidgetsFactory::KexiStandardFormWidgetsFactory() for properties like "Line:orientationSelectionPopup:horizontalIcon". \n\n See the standard factories in formeditor/factories for an example of factories, and how to deal with complex widgets (eg tabwidget). */ class KFORMDESIGNER_EXPORT WidgetFactory : public QObject, public InternalPropertyHandlerInterface { Q_OBJECT public: //! Options used in createWidget() enum CreateWidgetOption { NoCreateWidgetOptions = 0, AnyOrientation = 1, //!< any orientation hint HorizontalOrientation = 2, //!< horizontal orientation hint VerticalOrientation = 4, //!< vertical orientation hint DesignViewMode = 8, //!< create widget in design view mode, otherwise preview mode DefaultOptions = AnyOrientation | DesignViewMode }; Q_DECLARE_FLAGS(CreateWidgetOptions, CreateWidgetOption) explicit WidgetFactory(QObject *parent); virtual ~WidgetFactory(); /*! Adds a new class described by \a w. */ void addClass(WidgetInfo *w); /*! This method allows to force a class \a classname to hidden. It is useful if you do not want a class to be available (e.g. because it is not implemented well yet for our purposes). All widget libraries are affected by this setting. */ void hideClass(const char *classname); /** * \return all classes which are provided by this factory */ QHash classes() const; /** * Creates a widget (and if needed a KFormDesigner::Container) * \return the created widget * \param classname the classname of the widget, which should get created * \param parent the parent for the created widget * \param name the name of the created widget * \param container the toplevel Container (if a container should get created) * \param options options for the created widget: orientation and view mode (see CreateWidgetOptions) */ virtual QWidget* createWidget(const QByteArray &classname, QWidget *parent, const char *name, KFormDesigner::Container *container, CreateWidgetOptions options = DefaultOptions) = 0; /*! Creates custom actions. Reimplement this if you need to add some actions coming from the factory. */ virtual void createCustomActions(KActionCollection *col) { Q_UNUSED(col); } /*! This function can be used to add custom items in widget \a w context menu \a menu. */ virtual bool createMenuActions(const QByteArray &classname, QWidget *w, QMenu *menu, KFormDesigner::Container *container) = 0; //! Arguments used by Form::createInlineEditor() and startInlineEditing() /*! @a text is the text to display by default in the line edit. @a widget is the edited widget, @a geometry is the geometry the new line edit should have, and @a alignment is Qt::Alignment of the new line edit. If @a useFrame is false (the default), the line edit has no frame. if @a multiLine is false (the default), the line edit has single line. @a background describes line edit's background. If @a execute is true (the default), createInlineEditor() will be executed. */ class KFORMDESIGNER_EXPORT InlineEditorCreationArguments { public: InlineEditorCreationArguments( const QByteArray& _classname, QWidget *_widget, Container *_container); QByteArray classname; QString text; QWidget *widget; Container *container; QRect geometry; Qt::Alignment alignment; bool useFrame; bool multiLine; bool execute; //! true if the inline editor's bakground should be transparent (false by default) bool transparentBackground; }; /*! Sets up (if necessary) aguments for the inline editor used to edit the contents of the widget directly within the Form, e.g. creates a line edit to change the text of a label. @a args is used to pass the arguments back to the caller. */ virtual bool startInlineEditing(InlineEditorCreationArguments& args) = 0; /*! This function is called just before the Form is previewed. It allows widgets to make changes before switching (ie for a Spring, hiding the cross) */ virtual bool previewWidget(const QByteArray &classname, QWidget *widget, Container *container) = 0; virtual bool clearWidgetContent(const QByteArray &classname, QWidget *w); /*! This function is called when FormIO finds a property, at save time, that it cannot handle (ie not a normal property). This way you can save special properties, for example the contents of a listbox. \sa readSpecialProperty() */ virtual bool saveSpecialProperty(const QByteArray &classname, const QString &name, const QVariant &value, QWidget *w, QDomElement &parentNode, QDomDocument &parent); /*! This function is called when FormIO finds a property or an unknown element in a .ui file. You can this way load a special property, for example the contents of a listbox. \sa saveSpecialProperty() */ virtual bool readSpecialProperty(const QByteArray &classname, QDomElement &node, QWidget *w, ObjectTreeItem *item); /*! This function is used to know whether the \a property for the widget \a w should be shown or not in the PropertyEditor. If \a multiple is true, then multiple widgets of the same class are selected, and you should only show properties shared by widgets (eg font, color). By default, all properties are shown if multiple == true, and none if multiple == false. */ bool isPropertyVisible(const QByteArray &classname, QWidget *w, const QByteArray &property, bool multiple, bool isTopLevel); /*! \return The i18n'ed name of the property whose name is \a name, that will be displayed in PropertyEditor. */ QString propertyDescription(const char* name) const; /*! \return The i18n'ed name of the property's value whose name is \a name. */ QString valueDescription(const char* name) const; /*! This method is called after form's property set was filled with properties of a widget \a w, of class defined by \a info. Default implementation does nothing. Implement this if you need to set options for properties within the set \a set. */ virtual void setPropertyOptions(KPropertySet& set, const WidgetInfo& info, QWidget *w); /*! \return internal property \a property for a class \a classname. Internal properties are not stored within objects, but can be just provided to describe class' details. */ QVariant internalProperty(const QByteArray& classname, const QByteArray& property) const; /*! This function is called when the widget is resized, and the @a editor size needs to be updated. */ virtual void resizeEditor(QWidget *editor, QWidget *widget, const QByteArray &classname); /*! @return selectable item for @a item item. By default it is equal to @a item but e.g. for pages of QTabWidget, item for the widget itself is returned. Used when user clicks on the Widget Tree item or when parent of the current widget should to be selected. Defaults can be overridden by reimplementing this method. */ virtual ObjectTreeItem* selectableItem(ObjectTreeItem* item); /*! Sets the i18n'ed description of a property, which will be shown in PropertyEditor. */ void setPropertyDescription(const char *property, const QString &description); /*! Sets the i18n'ed description of a property value, which will be shown in PropertyEditor. */ void setValueDescription(const char *valueName, const QString &description); void setAdvancedPropertiesVisible(bool set); protected: /*! This function is called when we want to know whether the property should be visible. Implement it in the factory; don't forget to call implementation in the superclass. Default implementation hides "windowTitle", "windowIcon", "sizeIncrement" and "windowIconText" properties. */ virtual bool isPropertyVisibleInternal(const QByteArray &classname, QWidget *w, const QByteArray &property, bool isTopLevel); /*! Sometimes property sets should be reloaded when a given property value changed. Implement it in the factory. Default implementation always returns false. */ virtual bool propertySetShouldBeReloadedAfterPropertyChange(const QByteArray& classname, QWidget *w, const QByteArray& property); /*! This function provides a simple editing mode: it just disables event filtering for the widget, and it install it again when the widget loose focus or Enter is pressed. */ void disableFilter(QWidget *w, Container *container); /*! This function creates a little dialog (a KEditListBox) to modify the contents of a list (of strings). It can be used to modify the contents of a combo box for instance. The modified list is copied into \a list if the user presses "Ok" and true is returned. When user presses "Cancel" false is returned. */ bool editList(QWidget *w, QStringList &list) const; /*! This function creates a little editor to modify rich text. It supports alignment, subscript and superscript and all basic formatting properties. If the user presses "Ok", the edited text is put into @a text and true is returned. If the user presses "Cancel" false is returned. */ bool editRichText(QWidget *w, QString &text) const; -#ifndef KEXI_FORMS_NO_LIST_WIDGET +#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT /*! This function creates a dialog to modify the contents of a list widget. You can modify both columns and list items. The list widget is automatically updated if the user presses "Ok".*/ void editListWidget(QListWidget *listwidget) const; #endif /*! This function is used to modify a property of a widget (eg after editing it). Please use it instead of w->setProperty() to allow sync inside PropertyEditor. */ void changeProperty(Form *form, QWidget *widget, const char *name, const QVariant &value); /*! \return true if at least one class defined by this factory inherits a class from other factory. Used in WidgetLibrary::loadFactories() to load factories in proper order. */ bool inheritsFactories(); /*! Assigns \a value for internal property \a property for a class \a classname. Internal properties are not stored within objects, but can be provided to describe class' details. */ void setInternalProperty(const QByteArray& classname, const QByteArray& property, const QVariant& value); WidgetInfo* widgetInfoForClassName(const char* classname); const QSet* hiddenClasses() const; WidgetLibrary* library(); bool advancedPropertiesVisible() const; void setLibrary(WidgetLibrary* library); public Q_SLOTS: /*! @internal. This slot is called when the editor has lost focus or the user pressed Enter. It destroys the editor or installs again the event filter on the widget. */ //! Changes inline text for widget @a widget to @a text /*! Default implementation changes "text" property of the widget. You have to reimplement this function for inline editing inside the form @a form if your widget's property you want to change is not named "text". This slot is called when the line edit text changes, and you have to make it really change property of the widget using changeProperty() (text, title, etc.). */ virtual bool changeInlineText(Form *form, QWidget *widget, const QString& text, QString &oldText); private: class Private; Private* const d; friend class WidgetLibrary; }; Q_DECLARE_OPERATORS_FOR_FLAGS(WidgetFactory::CreateWidgetOptions) } #endif diff --git a/kexi/main/KexiMainWindow.cpp b/kexi/main/KexiMainWindow.cpp index 768584fbdb0..ccffdfc447e 100644 --- a/kexi/main/KexiMainWindow.cpp +++ b/kexi/main/KexiMainWindow.cpp @@ -1,4307 +1,4306 @@ /* 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.h" #include "KexiMainWindow_p.h" -#include #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 "kexistatusbar.h" #include "kexiinternalpart.h" #include "kexiactioncategories.h" #include "kexifinddialog.h" #include "kexisearchandreplaceiface.h" #include "KexiBugReportDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //! @todo KEXI3 #include #include #include "startup/KexiStartup.h" #include "startup/KexiNewProjectAssistant.h" #include "startup/KexiOpenProjectAssistant.h" #include "startup/KexiWelcomeAssistant.h" #include "startup/KexiImportExportAssistant.h" #include "startup/KexiStartupDialog.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 #if !defined(KexiVDebug) # define KexiVDebug if (0) qDebug() #endif #undef HAVE_KNEWSTUFF #ifdef HAVE_KNEWSTUFF #include #include #include "kexinewstuff.h" #endif class KexiDockWidget::Private { public: Private() {} QSize hint; KexiCloseButton *closeButton; }; KexiDockWidget::KexiDockWidget(const QString & title, QWidget *parent) : QDockWidget(title, parent), 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); QStyleOptionDockWidgetV2 dockOpt; dockOpt.initFrom(this); const int addSpacing = style()->pixelMetric(QStyle::PM_DockWidgetTitleBarButtonMargin, &dockOpt, this); QWidget *titleBar = new QWidget; titleBar->setFocusPolicy(Qt::NoFocus); QHBoxLayout *titleLyr = new QHBoxLayout(titleBar); titleLyr->setContentsMargins(addSpacing, addSpacing, addSpacing, addSpacing); titleLyr->setSpacing(0); titleLyr->addStretch(1); d->closeButton = new KexiCloseButton; d->closeButton->setMarginEnabled(false); connect(d->closeButton, SIGNAL(clicked()), this, SLOT(slotCloseClicked())); titleLyr->addWidget(d->closeButton); setTitleBarWidget(titleBar); } 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) QStyleOptionDockWidgetV2 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(); } void KexiDockWidget::slotCloseClicked() { if (isVisible()) { close(); } else { show(); } } QToolButton* KexiDockWidget::closeButton() const { return d->closeButton; } //------------------------------------------------- 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(true); } 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() { dynamic_cast(KexiMainWindowIface::global())->closeWindowForTab(m_tabIndex); } tristate KexiMainWindowTabWidget::closeAllTabs() { tristate alternateResult = true; QList windowList; for (int i = 0; i < count(); i++) { KexiWindow *window = dynamic_cast(KexiMainWindowIface::global())->windowForTab(i); if (window) { windowList.append(window); } } foreach (KexiWindow *window, windowList) { tristate result = dynamic_cast(KexiMainWindowIface::global())->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 int KexiMainWindow::create(int &argc, char *argv[], const QString &componentName) { const bool appExisted = qApp; //! @todo use non-GUI app when needed QApplication *app = qApp ? qApp : new QApplication(argc, argv); QApplication::setWindowIcon(koIcon("calligrakexi")); KLocalizedString::setApplicationDomain("kexi"); app->setQuitOnLastWindowClosed(false); //! @todo KEXI3 app->setAttribute(Qt::AA_UseHighDpiPixmaps, true); KexiAboutData aboutData; if (!componentName.isEmpty()) { aboutData.setComponentName(componentName); } KAboutData::setApplicationData(aboutData); tristate res = Kexi::startupHandler().init(); if (!res || ~res) { if (!appExisted) { delete app; } return (~res) ? 0 : 1; } //qDebug() << "startupActions OK"; /* Exit requested, e.g. after database removing. */ if (Kexi::startupHandler().action() == KexiStartupData::Exit) { if (!appExisted) { delete app; } return 0; } KexiMainWindow *win = new KexiMainWindow(); #ifdef KEXI_DEBUG_GUI QWidget* debugWindow = 0; if (GUIenabled) { KConfigGroup generalGroup = KSharedConfig::openConfig()->group("General"); if (generalGroup.readEntry("ShowInternalDebugger", false)) { debugWindow = KexiUtils::createDebugWindow(win); debugWindow->show(); } } #endif if (true != win->startup()) { delete win; if (!appExisted) { delete app; } 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. KIconLoader *globalIconLoader = KIconLoader::global(); globalIconLoader->addAppDir(QLatin1String("kexi")); globalIconLoader->addAppDir(QLatin1String("calligra")); //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(); (void)KexiUtils::smallFont(this/*init*/); if (!d->userMode) { setupContextHelp(); setupPropertyEditor(); } invalidateActions(); d->timer.singleShot(0, this, SLOT(slotLastActions())); if (Kexi::startupHandler().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); #ifdef HAVE_KNEWSTUFF action = addAction("project_download_examples", koIcon("go-down"), futureI18n("&Download Example Databases...")); action->setToolTip(futureI18n("Download example databases from the Internet")); action->setWhatsThis(futureI18n("Downloads example databases from the Internet.")); connect(action, SIGNAL(triggered()), this, SLOT(slotGetNewStuff())); #endif { 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.")); setupMainMenuActionShortcut(action); #ifdef KEXI_SHOW_UNIMPLEMENTED d->action_project_relations = addAction("project_relations", koIcon("relation"), 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(koIconName("database-import")), xi18n("&Import Database...")); 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.")); 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(koIconName("kexi-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", koIcon("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"); -#ifndef KEXI_NO_QUICK_PRINTING +#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("document-page-setup"), futureI18n("Print Set&up...")); 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", koIcon("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"), koIconName("delete_table_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"), koIconName("clear_table_contents"), 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"), koIconName("insert_table_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( koIcon("state_data"), 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( koIcon("state_edit"), 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( koIcon("state_sql"), 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_view_nav = addAction("view_navigator", xi18n("Switch to Project Navigator"), "Alt+1"); d->action_view_nav->setToolTip(xi18n("Switch to Project Navigator panel")); d->action_view_nav->setWhatsThis(xi18n("Switches to Project Navigator panel.")); connect(d->action_view_nav, SIGNAL(triggered()), this, SLOT(slotViewNavigator())); } else d->action_view_nav = 0; d->action_view_mainarea = addAction("view_mainarea", xi18n("Switch to Main Area"), "Alt+2"); d->action_view_mainarea->setToolTip(xi18n("Switch to main area")); d->action_view_mainarea->setWhatsThis(xi18n("Switches to main area.")); connect(d->action_view_mainarea, SIGNAL(triggered()), this, SLOT(slotViewMainArea())); if (!d->userMode) { d->action_view_propeditor = addAction("view_propeditor", xi18n("Switch to Property Editor"), "Alt+3"); d->action_view_propeditor->setToolTip(xi18n("Switch to Property Editor panel")); d->action_view_propeditor->setWhatsThis(xi18n("Switches to Property Editor panel.")); connect(d->action_view_propeditor, SIGNAL(triggered()), this, SLOT(slotViewPropertyEditor())); } else d->action_view_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..."), koIconNameWanted("change font of selected object","fonts"), 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.")); 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("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); -#ifndef KEXI_NO_QUICK_PRINTING +#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("view_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); -#ifndef KEXI_NO_QUICK_PRINTING +#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_view_nav) d->action_view_nav->setEnabled(d->prj); d->action_view_mainarea->setEnabled(d->prj); if (d->action_view_propeditor) d->action_view_propeditor->setEnabled(d->prj); -#ifndef KEXI_NO_CTXT_HELP +#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 (Kexi::startupHandler().action()) { case KexiStartupHandler::CreateBlankProject: d->updatePropEditorVisibility(Kexi::NoViewMode); break; #ifdef KEXI_PROJECT_TEMPLATES case KexiStartupHandler::CreateFromTemplate: result = createProjectFromTemplate(*Kexi::startupHandler().projectData()); break; #endif case KexiStartupHandler::OpenProject: result = openProject(*Kexi::startupHandler().projectData()); break; case KexiStartupHandler::ImportProject: result = showProjectMigrationWizard( Kexi::startupHandler().importActionData().mimeType, Kexi::startupHandler().importActionData().fileName ); break; case KexiStartupHandler::ShowWelcomeScreen: //! @todo show welcome screen as soon as is available QTimer::singleShot(1, 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()), QString(), KGuiItem(xi18nc("@action:button Import Database", "&Import..."), koIconName("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 (KexiFileWidget::askForOverwriting(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(); d->statusBar->setReadOnlyFlag(readOnly); 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) { foreach(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"); -#ifndef KEXI_NO_QUICK_PRINTING +#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; } -#ifndef KEXI_NO_QUICK_PRINTING +#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() { -#ifndef KEXI_NO_CTXT_HELP +#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::KDEV3ICON); mainWidgetContainerLyr->addWidget(mtbar, 0); 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::KDEV3ICON); mainWidgetContainerLyr->addWidget(mtbar, 0); d->multiTabBars.insert(mtbar->position(), mtbar); d->statusBar = new KexiStatusBar(this); vlyr->addWidget(d->statusBar); } 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->navDockWidget->closeButton()->setToolTip(xi18n("Hide project navigator")); 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*))); -#ifndef KEXI_NO_QUICK_PRINTING +#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) { slotViewNavigator(); 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->propEditorDockWidget->closeButton()->setToolTip(xi18n("Hide property editor")); 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")); int size = propertyEditorGroup.readEntry("FontSize", -1); QFont f(KexiUtils::smallFont()); if (size > 0) f.setPixelSize(size); 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); } 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() <= 1024 || desk.height() < 768) setWindowState(windowState() | Qt::WindowMaximized); else resize(1024, 768); } // 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) { qDebug(); #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; KexiStartupHandler &h = Kexi::startupHandler(); 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 = Kexi::startupHandler().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() { -#ifndef KEXI_NO_QUICK_PRINTING +#ifdef KEXI_QUICK_PRINTING_SUPPORT if (currentWindow() && currentWindow()->partItem()) printItem(currentWindow()->partItem()); #endif } void KexiMainWindow::slotProjectPrintPreview() { -#ifndef KEXI_NO_QUICK_PRINTING +#ifdef KEXI_QUICK_PRINTING_SUPPORT if (currentWindow() && currentWindow()->partItem()) printPreviewForItem(currentWindow()->partItem()); #endif } void KexiMainWindow::slotProjectPageSetup() { -#ifndef KEXI_NO_QUICK_PRINTING +#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::slotViewNavigator() { if (!d->navigator) { return; } d->navigator->setFocus(); } void KexiMainWindow::slotViewMainArea() { if (currentWindow()) currentWindow()->setFocus(); } void KexiMainWindow::slotViewPropertyEditor() { if (!d->propEditor) { return; } if (d->propEditorTabWidget->currentWidget()) d->propEditorTabWidget->currentWidget()->setFocus(); } 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(xi18n("Selected view is not supported for \"%1\" object.", currentWindow()->partItem()->name()), xi18n("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( xi18n("Saves all recent changes made in \"%1\" object.", window->partItem()->name())); KGuiItem discardChanges(KStandardGuiItem::discard()); discardChanges.setWhatsThis( xi18n("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 const QString window_pluginId = window->partItem()->pluginId(); 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)); -#ifndef KEXI_NO_QUICK_PRINTING +#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 = xi18n("Tab for \"%1\" (%2).", item->captionOrName(), part->info()->name()); } else { whatsThisText = xi18n("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 Remove ?", "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()), KGuiItem(xi18nc("@action:button Delete object", "Delete"), koIconName("edit-delete")), KStandardGuiItem::no(), QString(), KMessageBox::Notify | KMessageBox::Dangerous)) { return cancelled; } } tristate res = true; -#ifndef KEXI_NO_QUICK_PRINTING +#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; window->partItem()->neverSaved(); d->forceWindowClosing = true; res = closeWindow(window); d->forceWindowClosing = tmp; //restore if (!res || ~res) { return res; } } -#ifndef KEXI_NO_QUICK_PRINTING +#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 remove 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()); int r = KMessageBox::questionYesNo(this, msg, QString(), KGuiItem(xi18nc("@action:button", "Close Window"), koIconName("window-close")), KStandardGuiItem::cancel()); if (r != KMessageBox::Yes) { *success = false; return; } } setMessagesEnabled(false); //to avoid double messages const bool res = d->prj->renameObject(item, newName); setMessagesEnabled(true); if (!res) { showErrorMessage(xi18n("Renaming object \"%1\" failed.", newName), d->prj); *success = false; return; } } 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(xi18n("Setting caption for object \"%1\" failed.", newCaption), d->prj); *success = false; return; } } 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 = KPropertyEditorView::ExpandChildItems; if (preservePrevSelection) { options |= KPropertyEditorView::PreservePreviousSelection; } if (sortedProperties) { options |= KPropertyEditorView::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) { KexiStartupDialog dlg( KexiStartupDialog::OpenExisting, 0, Kexi::connset(), this); if (dlg.exec() != QDialog::Accepted) return; if (dlg.selectedFileName().isEmpty()) { //! @todo add support for server based if needed? return; } KDbConnectionData cdata; cdata.setDatabaseName(dlg.selectedFileName()); //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); } 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); } /// TMP (until there's true template support) void KexiMainWindow::slotGetNewStuff() { #ifdef HAVE_KNEWSTUFF if (!d->newStuff) d->newStuff = new KexiNewStuff(this); d->newStuff->download(); //KNS::DownloadDialog::open(newstuff->customEngine(), "kexi/template"); #endif } void KexiMainWindow::highlightObject(const QString& pluginId, const QString& name) { slotViewNavigator(); if (!d->prj) return; KexiPart::Item *item = d->prj->itemForPluginId(pluginId, name); if (!item) return; if (d->navigator) { 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; } //! @todo KEXI3 remove when Migation is ported KexiMigrateManagerTemp::~KexiMigrateManagerTemp() {} QStringList KexiMigrateManagerTemp::supportedFileMimeTypes() { return QStringList(); } KexiMigrateManagerInterface* KexiMainWindow::migrateManager() { if (d->migrateManager.isNull()) { //! @todo KEXI3 #if 0 d->migrateManager.reset(new KexiMigration::MigrateManager()); #else // tmp d->migrateManager.reset(new KexiMigrateManagerTemp()); #endif } return d->migrateManager.data(); } 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(); } } } KToggleFullScreenAction::setFullScreen(this, isFullScreen); } diff --git a/kexi/main/KexiMainWindow_p.h b/kexi/main/KexiMainWindow_p.h index 9de6b4eb087..b3da433ab98 100644 --- a/kexi/main/KexiMainWindow_p.h +++ b/kexi/main/KexiMainWindow_p.h @@ -1,702 +1,702 @@ /* 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. */ #ifndef KEXIMAINWINDOW_P_H #define KEXIMAINWINDOW_P_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KexiMainWindow.h" #include "KexiSearchLineEdit.h" #include "KexiUserFeedbackAgent.h" #include "KexiMenuWidget.h" #include "kexifinddialog.h" #include "kexistatusbar.h" #include "KexiStartup.h" #include #include #include #include #include #include #include #define KEXI_NO_PROCESS_EVENTS #ifdef KEXI_NO_PROCESS_EVENTS # define KEXI_NO_PENDING_DIALOGS #endif #define PROJECT_NAVIGATOR_TABBAR_ID 0 #define PROPERTY_EDITOR_TABBAR_ID 1 #define KEXITABBEDTOOLBAR_SPACER_TAB_INDEX 1 class QPainter; class KexiProjectNavigator; //! @short Main application's tabbed toolbar class KexiTabbedToolBar : public QTabWidget { Q_OBJECT public: explicit KexiTabbedToolBar(QWidget *parent); virtual ~KexiTabbedToolBar(); KToolBar *createWidgetToolBar() const; KToolBar *toolBar(const QString& name) const; void appendWidgetToToolbar(const QString& name, QWidget* widget); void setWidgetVisibleInToolbar(QWidget* widget, bool visible); //! @todo replace with the final Actions API void addAction(const QString& toolBarName, QAction *action); bool mainMenuVisible() const; QRect tabRect(int index) const; KHelpMenu *helpMenu() const; void addSearchableModel(KexiSearchableModel *model); KToolBar *createToolBar(const char *name, const QString& caption); void setCurrentTab(const QString& name); //! Sets current tab to @a index, counting from first visible (non-Kexi) tab. //! In non-user mode, the first visible tab is "create" tab. void setCurrentTab(int index); void hideTab(const QString& name); void showTab(const QString& name); bool isTabVisible(const QString& name) const; bool isRolledUp(); public Q_SLOTS: void setMainMenuContent(QWidget *w); void selectMainMenuItem(const char *actionName); void showMainMenu(const char* actionName = 0); void hideMainMenu(); void toggleMainMenu(); void activateSearchLineEdit(); void toggleRollDown(); protected: virtual void mouseMoveEvent(QMouseEvent* event); virtual void leaveEvent(QEvent* event); virtual bool eventFilter(QObject* watched, QEvent* event); protected Q_SLOTS: void slotCurrentChanged(int index); void slotDelayedTabRaise(); void slotSettingsChanged(int category); //! Used for delayed loading of the "create" toolbar. Called only once. void setupCreateWidgetToolbar(); void slotTabDoubleClicked(int index); void tabBarAnimationFinished(); private: void addAction(KToolBar *tbar, const char* actionName); void addSeparatorAndAction(KToolBar *tbar, const char* actionName); class Private; Private * const d; }; //! @internal window container created to speedup opening new tabs class KexiWindowContainer : public QWidget { public: explicit KexiWindowContainer(QWidget* parent); virtual ~KexiWindowContainer(); void setWindow(KexiWindow* w); QPointer window; private: QVBoxLayout *lyr; }; class EmptyMenuContentWidget : public QWidget { public: explicit EmptyMenuContentWidget(QWidget* parent = 0); void alterBackground(); virtual void changeEvent(QEvent *e); }; //! @todo KEXI3 is KexiMenuWidgetStyle needed? #if 0 //! A style proxy for KexiMenuWidget class KexiMenuWidgetStyle : public KexiUtils::StyleProxy { public: explicit KexiMenuWidgetStyle(QStyle *style, QObject *parent = 0); virtual ~KexiMenuWidgetStyle(); virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; }; #endif //! Main menu class KexiMainMenu : public QWidget { Q_OBJECT public: explicit KexiMainMenu(KexiTabbedToolBar *toolBar, QWidget* parent = 0); ~KexiMainMenu(); virtual bool eventFilter(QObject * watched, QEvent* event); void setContent(QWidget *contentWidget); const QWidget *contentWidget() const; void setPersistentlySelectedAction(KexiMenuWidgetAction* action, bool set); /* void setActiveAction(QAction* action = 0);*/ void selectFirstItem(); tristate showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata); Q_SIGNALS: void contentAreaPressed(); void hideContentsRequested(); protected Q_SLOTS: //void contentWidgetDestroyed(); protected: virtual void showEvent(QShowEvent * event); private: QPointer m_menuWidget; KexiTabbedToolBar* m_toolBar; bool m_initialized; EmptyMenuContentWidget *m_content; QStackedLayout *m_contentLayout; QPointer m_contentWidget; QVBoxLayout* m_mainContentLayout; QPointer m_persistentlySelectedAction; bool m_selectFirstItem; }; class KexiTabbedToolBarTabBar; //! @internal class KexiTabbedToolBar::Private : public QObject { Q_OBJECT public: explicit Private(KexiTabbedToolBar *t); KToolBar *createToolBar(const char *name, const QString& caption); int tabIndex; public Q_SLOTS: void showMainMenu(const char* actionName = 0); void hideMainMenu(); void hideContentsOrMainMenu(); void toggleMainMenu(); void updateMainMenuGeometry(); public: KexiTabbedToolBarTabBar *customTabBar; QPointer mainMenu; KexiTabbedToolBar *q; KActionCollection *ac; int createId; KToolBar *createWidgetToolBar; #ifdef KEXI_AUTORISE_TABBED_TOOLBAR //! Used for delayed tab raising int tabToRaise; //! Used for delayed tab raising QTimer tabRaiseTimer; #endif //! Toolbars for name QHash toolbarsForName; QHash toolbarsIndexForName; QHash toolbarsCaptionForName; QVector toolbarsVisibleForIndex; QHash extraActions; bool rolledUp; QPropertyAnimation tabBarAnimation; QGraphicsOpacityEffect tabBarOpacityEffect; int rolledUpIndex; KHelpMenu *helpMenu; KexiSearchLineEdit *searchLineEdit; void setCurrentTab(const QString& name); void hideTab(const QString& name); void showTab(const QString& name); bool isTabVisible(const QString& name) const; #ifndef NDEBUG void debugToolbars() const; #endif int lowestIndex; }; class KexiTabbedToolBarStyle; //! Tab bar reimplementation for KexiTabbedToolBar. /*! The main its purpose is to alter the width of "Kexi" tab. */ class KexiTabbedToolBarTabBar : public QTabBar { Q_OBJECT public: explicit KexiTabbedToolBarTabBar(QWidget *parent = 0); virtual QSize originalTabSizeHint(int index) const; virtual QSize tabSizeHint(int index) const; KexiTabbedToolBarStyle* customStyle; }; //! Style proxy for KexiTabbedToolBar, to get the "Kexi" tab style right. class KexiTabbedToolBarStyle : public QProxyStyle { public: explicit KexiTabbedToolBarStyle(const QString &baseStyleName); virtual ~KexiTabbedToolBarStyle(); virtual void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; virtual void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; virtual int pixelMetric(PixelMetric metric, const QStyleOption* option = 0, const QWidget* widget = 0) const; }; class KexiMainWidget; //! @internal tab widget acting as central widget for KexiMainWindow class KexiMainWindowTabWidget : public QTabWidget { Q_OBJECT public: KexiMainWindowTabWidget(QWidget *parent, KexiMainWidget *mainWidget); virtual ~KexiMainWindowTabWidget(); public Q_SLOTS: void closeTab(); tristate closeAllTabs(); protected: //! Shows context menu for tab at @a index at point @a point. //! If @a index is -1, context menu for empty area is requested. void showContextMenuForTab(int index, const QPoint& point); //! Reimplemented to hide frame when no tabs are displayed virtual void paintEvent(QPaintEvent * event); virtual void mousePressEvent(QMouseEvent *event); KexiMainWidget *m_mainWidget; QAction *m_closeAction; QAction *m_closeAllTabsAction; private: int m_tabIndex; void setTabIndexFromContextMenu(int clickedIndex); }; //! @short A widget being main part of KexiMainWindow class KexiMainWidget : public KMainWindow { Q_OBJECT public: KexiMainWidget(); virtual ~KexiMainWidget(); void setParent(KexiMainWindow* mainWindow); KexiMainWindowTabWidget* tabWidget() const; protected: virtual bool queryClose(); protected Q_SLOTS: void slotCurrentTabIndexChanged(int index); Q_SIGNALS: void currentTabIndexChanged(int index); private: void setupCentralWidget(); KexiMainWindowTabWidget* m_tabWidget; KexiMainWindow *m_mainWindow; QPointer m_previouslyActiveWindow; friend class KexiMainWindow; friend class KexiMainWindowTabWidget; }; //------------------------------------------ //! @internal Dock widget with floating disabled but still collapsible class KexiDockWidget : public QDockWidget { Q_OBJECT public: KexiDockWidget(const QString &title, QWidget *parent); virtual ~KexiDockWidget(); virtual void setSizeHint(const QSize& hint); virtual QSize sizeHint() const; QToolButton* closeButton() const; protected: virtual void paintEvent(QPaintEvent *pe); protected Q_SLOTS: void slotCloseClicked(); private: class Private; Private * const d; }; //------------------------------------------ //! @internal safer dictionary typedef QMap< int, KexiWindow* > KexiWindowDict; //! @todo KEXI3 remove when Migation is ported class KexiMigrateManagerTemp : public QObject, public KexiMigrateManagerInterface { public: virtual ~KexiMigrateManagerTemp(); //! Implement to return the list offile MIME types that are supported by migration drivers virtual QStringList supportedFileMimeTypes(); }; //! @internal class KexiMainWindow::Private { public: explicit Private(KexiMainWindow* w); ~Private(); #ifndef KEXI_NO_PENDING_DIALOGS //! Job type. Currently used for marking items as being opened or closed. enum PendingJobType { NoJob = 0, WindowOpeningJob, WindowClosingJob }; KexiWindow *openedWindowFor(const KexiPart::Item* item, PendingJobType &pendingType); KexiWindow *openedWindowFor(int identifier, PendingJobType &pendingType); void addItemToPendingWindows(const KexiPart::Item* item, PendingJobType jobType); bool pendingWindowsExist(); void removePendingWindow(int identifier); #else KexiWindow *openedWindowFor(int identifier); #endif void insertWindow(KexiWindow *window); bool windowContainerExistsFor(int identifier) const; void setWindowContainerExistsFor(int identifier, bool set); void updateWindowId(KexiWindow *window, int oldItemID); void removeWindow(int identifier); int openedWindowsCount(); //! Used in KexiMainWindowe::closeProject() void clearWindows(); void showStartProcessMsg(const QStringList& args); //! Updates Property Editor Pane's visibility for the current window and the @a viewMode view mode. /*! @a info can be provided to hadle cases when current window is not yet defined (in openObject()). */ void updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info = 0); void setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id, KexiDockWidget *dockWidget, bool visible); void setPropertyEditorTabBarVisible(bool visible); QObject *openedCustomObjectsForItem(KexiPart::Item* item, const char* name); void addOpenedCustomObjectForItem(KexiPart::Item* item, QObject* object, const char* name); KexiFindDialog *findDialog(); /*! Updates the find/replace dialog depending on the active view. Nothing is performed if the dialog is not instantiated yet or is invisible. */ void updateFindDialogContents(bool createIfDoesNotExist = false); //! \return the current view if it supports \a actionName, otherwise returns 0. KexiView *currentViewSupportingAction(const char* actionName) const; //! \return the current view if it supports KexiSearchAndReplaceViewInterface. KexiSearchAndReplaceViewInterface* currentViewSupportingSearchAndReplaceInterface() const; tristate showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata); KexiMainWindow *wnd; KexiMainWidget *mainWidget; KActionCollection *actionCollection; KexiStatusBar *statusBar; KHelpMenu *helpMenu; KexiProject *prj; KSharedConfig::Ptr config; -#ifndef KEXI_NO_CTXT_HELP +#ifdef KEXI_SHOW_CONTEXT_HELP KexiContextHelp *ctxHelp; #endif KexiProjectNavigator *navigator; KexiTabbedToolBar *tabbedToolBar; QMap tabsToActivateOnShow; KexiDockWidget *navDockWidget; QTabWidget *propEditorTabWidget; KexiDockWidget *propEditorDockWidget; QPointer propEditorDockableWidget; //! poits to kexi part which has been previously used to setup proppanel's tabs using //! KexiPart::setupCustomPropertyPanelTabs(), in updateCustomPropertyPanelTabs(). QPointer partForPreviouslySetupPropertyPanelTabs; QMap recentlySelectedPropertyPanelPages; QPointer propEditor; QPointer propertySet; KexiNameDialog *nameDialog; QTimer timer; //!< helper timer QString appCaptionPrefix; // focus_before_popup; //! Set to true only in destructor, used by closeWindow() to know if //! user can cancel window closing. If true user even doesn't see any messages //! before closing a window. This is for extremely sanity... and shouldn't be even needed. bool forceWindowClosing; //! Indicates that we're inside closeWindow() method - to avoid inf. recursion //! on window removing bool insideCloseWindow; #ifndef KEXI_NO_PENDING_DIALOGS //! Used in executeActionWhenPendingJobsAreFinished(). enum ActionToExecuteWhenPendingJobsAreFinished { NoAction, QuitAction, CloseProjectAction }; ActionToExecuteWhenPendingJobsAreFinished actionToExecuteWhenPendingJobsAreFinished; void executeActionWhenPendingJobsAreFinished(); #endif //! Used for delayed windows closing for 'close all' QList windowsToClose; -#ifndef KEXI_NO_QUICK_PRINTING +#ifndef KEXI_QUICK_PRINTING_SUPPORT //! Opened page setup dialogs, used by printOrPrintPreviewForItem(). QHash pageSetupWindows; /*! A map from Kexi dialog to "print setup" part item's ID of the data item used by closeWindow() to find an ID of the data item, so the entry can be removed from pageSetupWindows dictionary. */ QMap pageSetupWindowItemID2dataItemID_map; #endif //! Indicates if project is started in User Mode bool userMode; //! Indicates if project navigator should be visible bool isProjectNavigatorVisible; //! Indicates if the main menu should be visible bool isMainMenuVisible; //! Set in restoreSettings() and used in initNavigator() //! to customize navigator visibility on startup bool forceShowProjectNavigatorOnCreation; bool forceHideProjectNavigatorOnCreation; bool navWasVisibleBeforeProjectClosing; bool saveSettingsForShowProjectNavigator; #ifdef HAVE_KNEWSTUFF KexiNewStuff *newStuff; #endif //! Used by openedCustomObjectsForItem() and addOpenedCustomObjectForItem() QHash m_openedCustomObjectsForItem; int propEditorDockSeparatorPos, navDockSeparatorPos; bool wasAutoOpen; bool windowExistedBeforeCloseProject; QMap multiTabBars; bool propertyEditorCollapsed; bool enable_slotPropertyEditorVisibilityChanged; KexiUserFeedbackAgent userFeedback; //! @todo KEXI3 #if 0 QScopedPointer migrateManager; #else QScopedPointer migrateManager; #endif private: //! @todo move to KexiProject KexiWindowDict windows; //! A set of item identifiers for whose there are KexiWindowContainer instances already. //! This lets to verify that KexiWindow is about to be constructed and opened so multiple //! opening can be avoided. QSet windowContainers; #ifndef KEXI_NO_PROCESS_EVENTS QHash pendingWindows; //!< part item identifiers for windows whoose opening has been started //! @todo QMutex dialogsMutex; //!< used for locking windows and pendingWindows dicts #endif KexiFindDialog *m_findDialog; }; //------------------------------------------ //! Action shortcut used by KexiMainWindow::setupMainMenuActionShortcut(QAction *) //! Activates action only if enabled. class KexiMainMenuActionShortcut : public QShortcut { Q_OBJECT public: KexiMainMenuActionShortcut(const QKeySequence& key, QAction *action, QWidget *parent); virtual ~KexiMainMenuActionShortcut(); protected Q_SLOTS: //! Triggers associated action only when this action is enabled void slotActivated(); private: QPointer m_action; }; #endif diff --git a/kexi/pics/16-actions-subform.png b/kexi/pics/16-actions-subform.png deleted file mode 100644 index a5d39ac2b5f..00000000000 Binary files a/kexi/pics/16-actions-subform.png and /dev/null differ diff --git a/kexi/pics/22-actions-subform.png b/kexi/pics/22-actions-subform.png deleted file mode 100644 index 6deb050dfa3..00000000000 Binary files a/kexi/pics/22-actions-subform.png and /dev/null differ diff --git a/kexi/pics/CMakeLists.txt b/kexi/pics/CMakeLists.txt index 9ce8e27823b..febda5ad5a0 100644 --- a/kexi/pics/CMakeLists.txt +++ b/kexi/pics/CMakeLists.txt @@ -1,167 +1,165 @@ ecm_install_icons(ICONS 128-actions-form_action.png 16-actions-add_field.png 16-actions-aofit.png 16-actions-aogrid.png 16-actions-aopos2grid.png 16-actions-autofield.png 16-actions-autonumber.png 16-actions-business_user.png 16-actions-button.png 16-actions-button_no.png 16-actions-check.png 16-actions-clear_table_contents.png 16-actions-close.png 16-actions-combo.png 16-actions-database-import.png 16-actions-delete_table_row.png 16-actions-form.png 16-actions-form_action.png 16-actions-form_newobj.png 16-actions-frame.png 16-actions-grid.png 16-actions-groupbox.png 16-actions-insert_table_row.png 16-actions-key.png 16-actions-line.png 16-actions-line_horizontal.png 16-actions-line_vertical.png 16-actions-lineedit.png 16-actions-macro.png 16-actions-macro_newobj.png 16-actions-mouse_pointer.png 16-actions-multiple_obj.png 16-actions-new_sign.png 16-actions-pixmaplabel.png 16-actions-query.png 16-actions-query_newobj.png 16-actions-radio.png 16-actions-relation.png 16-actions-report.png 16-actions-report_newobj.png 16-actions-script.png 16-actions-script_newobj.png 16-actions-state_data.png 16-actions-state_edit.png 16-actions-state_sql.png - 16-actions-subform.png 16-actions-table.png 16-actions-table_newobj.png 16-actions-tabwidget.png 16-actions-tabwidget_tab.png 16-actions-test_it.png 16-actions-textedit.png 16-actions-unknown_widget.png 16-actions-widgets.png 22-actions-alignobjs.png 22-actions-aobottom.png 22-actions-aofit.png 22-actions-aogrid.png 22-actions-aoleft.png 22-actions-aonarrowest.png 22-actions-aopos2grid.png 22-actions-aoright.png 22-actions-aoshortest.png 22-actions-aotallest.png 22-actions-aotop.png 22-actions-aowidest.png 22-actions-autofield.png 22-actions-business_user.png 22-actions-button.png 22-actions-check.png 22-actions-clear_table_contents.png 22-actions-close.png 22-actions-combo.png 22-actions-database-import.png 22-actions-dateedit.png 22-actions-datetimeedit.png 22-actions-delete_table_row.png 22-actions-form.png 22-actions-form_action.png 22-actions-form_edit.png 22-actions-form_newobj.png 22-actions-frame.png 22-actions-grid.png 22-actions-groupbox.png 22-actions-insert_table_row.png 22-actions-key.png 22-actions-label.png 22-actions-line.png 22-actions-line_horizontal.png 22-actions-line_vertical.png 22-actions-lineedit.png 22-actions-listbox.png 22-actions-listwidget.png 22-actions-lower.png 22-actions-macro.png 22-actions-macro_newobj.png 22-actions-mouse_pointer.png 22-actions-multiple_obj.png 22-actions-new_sign.png 22-actions-pixmaplabel.png 22-actions-progress.png 22-actions-query.png 22-actions-query_newobj.png 22-actions-radio.png 22-actions-raise.png 22-actions-relation.png 22-actions-report.png 22-actions-report_newobj.png 22-actions-signalslot.png 22-actions-slider.png 22-actions-spin.png 22-actions-state_data.png 22-actions-state_edit.png 22-actions-state_sql.png - 22-actions-subform.png 22-actions-table.png 22-actions-table_newobj.png 22-actions-tabwidget.png 22-actions-tabwidget_tab.png 22-actions-test_it.png 22-actions-textedit.png 22-actions-timeedit.png 22-actions-unknown_widget.png 22-actions-urlrequest.png 22-actions-widgets.png 22-actions-widgetstack.png 32-actions-business_user.png 32-actions-clear_table_contents.png 32-actions-close.png 32-actions-database-import.png 32-actions-delete_table_row.png 32-actions-form.png 32-actions-form_action.png 32-actions-form_newobj.png 32-actions-grid.png 32-actions-insert_table_row.png 32-actions-key.png 32-actions-macro.png 32-actions-macro_newobj.png 32-actions-new_sign.png 32-actions-pixmaplabel.png 32-actions-query.png 32-actions-query_newobj.png 32-actions-report.png 32-actions-report_newobj.png 32-actions-state_data.png 32-actions-state_sql.png 32-actions-table.png 32-actions-table_newobj.png 48-actions-database-import.png 48-actions-form_action.png 48-actions-key.png 64-actions-business_user.png 64-actions-form_action.png DESTINATION ${DATA_INSTALL_DIR}/kexi/icons THEME hicolor ) install(FILES calligra-logo-white-glow.png calligra-logo-black-glow.png external-link.png DESTINATION ${DATA_INSTALL_DIR}/kexi/pics) add_subdirectory(oxygen) add_subdirectory(app) diff --git a/kexi/plugins/forms/CMakeLists.txt b/kexi/plugins/forms/CMakeLists.txt index 1ed5db923eb..dff66707c81 100644 --- a/kexi/plugins/forms/CMakeLists.txt +++ b/kexi/plugins/forms/CMakeLists.txt @@ -1,112 +1,111 @@ include_directories( ${CMAKE_SOURCE_DIR}/kexi/core ${CMAKE_SOURCE_DIR}/kexi/widget/utils ${CMAKE_SOURCE_DIR}/kexi/widget ${CMAKE_SOURCE_DIR}/kexi/formeditor) if(MARBLE_FOUND) add_subdirectory(widgets/mapbrowser) endif() if(Qt5WebKitWidgets_FOUND) add_subdirectory(widgets/webbrowser) endif() # the main plugin set(kexi_formplugin_SRCS kexiforms.cpp) add_library(kexi_formplugin MODULE ${kexi_formplugin_SRCS}) kcoreaddons_desktop_to_json(kexi_formplugin kexi_formplugin.desktop) target_link_libraries(kexi_formplugin kexicore kexiguiutils kexidatatable kexiextendedwidgets kformdesigner kexiformutils KProperty ) install(TARGETS kexi_formplugin DESTINATION ${KEXI_PLUGIN_INSTALL_DIR}) # the form widgets plugin set(kexiforms_dbwidgetsplugin_SRCS kexidbfactory.cpp) add_library(kexiforms_dbwidgetsplugin MODULE ${kexiforms_dbwidgetsplugin_SRCS}) kcoreaddons_desktop_to_json(kexiforms_dbwidgetsplugin kexiforms_dbwidgetsplugin.desktop) target_link_libraries(kexiforms_dbwidgetsplugin PRIVATE kformdesigner kexiformutils kexicore kexiguiutils kexidataviewcommon kexidatatable kexiextendedwidgets KDb Qt5::Gui ) install(TARGETS kexiforms_dbwidgetsplugin DESTINATION ${KEXI_FORM_WIDGETS_PLUGIN_INSTALL_DIR}) # the form utils lib set(kexiformutils_LIB_SRCS # kexiformdataiteminterface.cpp kexidataawarewidgetinfo.cpp KexiFormScrollAreaWidget.cpp kexiformscrollview.cpp kexidbtextwidgetinterface.cpp kexiformmanager.cpp kexidatasourcepage.cpp kexiformpart.cpp kexiformview.cpp kexidbfactorybase.cpp widgets/kexidbutils.cpp widgets/kexidbautofield.cpp widgets/kexidbform.cpp - #todo widgets/kexidbsubform.cpp widgets/kexidblabel.cpp widgets/kexidbimagebox.cpp widgets/KexiDBPushButton.cpp widgets/kexiframe.cpp widgets/kexidblineedit.cpp widgets/kexidbcheckbox.cpp widgets/kexidbtextedit.cpp widgets/kexidbcombobox.cpp widgets/kexidbcommandlinkbutton.cpp widgets/kexidbslider.cpp widgets/kexidbprogressbar.cpp widgets/kexidbdatepicker.cpp ) #obsolete widgets/kexidbdoublespinbox.cpp #obsolete widgets/kexidbintspinbox.cpp add_library(kexiformutils SHARED ${kexiformutils_LIB_SRCS}) generate_export_header(kexiformutils) target_link_libraries(kexiformutils PRIVATE kexicore kexiextendedwidgets kformdesigner kexiutils kexidataviewcommon kexidatatable kexiguiutils KDb KProperty Qt5::Gui Qt5::Xml ) set_target_properties(kexiformutils PROPERTIES VERSION ${GENERIC_CALLIGRA_LIB_VERSION} SOVERSION ${GENERIC_CALLIGRA_LIB_SOVERSION}) install(TARGETS kexiformutils ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/kexi/plugins/forms/kexidatasourcepage.cpp b/kexi/plugins/forms/kexidatasourcepage.cpp index 5a377d4be7a..acd602e4387 100644 --- a/kexi/plugins/forms/kexidatasourcepage.cpp +++ b/kexi/plugins/forms/kexidatasourcepage.cpp @@ -1,454 +1,455 @@ /* This file is part of the KDE project Copyright (C) 2005-2009 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 "kexidatasourcepage.h" #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KexiDataSourcePage::KexiDataSourcePage(QWidget *parent) : KexiPropertyPaneViewBase(parent) , m_noDataSourceAvailableSingleText( xi18n("No data source could be assigned for this widget.") ) , m_noDataSourceAvailableMultiText( xi18n("No data source could be assigned for multiple widgets.") ) , m_insideClearFormDataSourceSelection(false) -#ifdef KEXI_NO_AUTOFIELD_WIDGET +#ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT , m_tableOrQuerySchema(0) #endif { infoLabel()->setContentsMargins(0, 0, 0, spacing()); m_noDataSourceAvailableLabel = new QLabel(m_noDataSourceAvailableSingleText, this); m_noDataSourceAvailableLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); m_noDataSourceAvailableLabel->setContentsMargins(0, 0, 0, spacing()); m_noDataSourceAvailableLabel->setAlignment(Qt::AlignBottom | Qt::AlignLeft); m_noDataSourceAvailableLabel->setWordWrap(true); mainLayout()->addWidget(m_noDataSourceAvailableLabel); //-Widget's Data Source QHBoxLayout *hlyr = new QHBoxLayout(); mainLayout()->addLayout(hlyr); #if 0 //! @todo unhide this when expression work // m_widgetDSLabel = new QLabel(futureI18nc("Table Field, Query Field or Expression", "Source field or expression"), this); #else m_widgetDSLabel = new QLabel( xi18nc("Table Field or Query Field", "Widget's data source"), this); #endif m_widgetDSLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); m_widgetDSLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom); hlyr->addWidget(m_widgetDSLabel); #if 0 m_clearWidgetDSButton = new KexiSmallToolButton( koIcon("edit-clear-locationbar-rtl"), QString(), this); m_clearWidgetDSButton->setObjectName("clearWidgetDSButton"); m_clearWidgetDSButton->setMinimumHeight(m_widgetDSLabel->minimumHeight()); m_clearWidgetDSButton->setToolTip(futureI18n("Clear widget's data source")); hlyr->addWidget(m_clearWidgetDSButton); connect(m_clearWidgetDSButton, SIGNAL(clicked()), this, SLOT(clearWidgetDataSourceSelection())); #endif m_widgetDataSourceCombo = new KexiFieldComboBox(this); m_widgetDataSourceCombo->setObjectName("sourceFieldCombo"); m_widgetDataSourceCombo->setContentsMargins(0, 0, 0, 0); m_widgetDSLabel->setBuddy(m_widgetDataSourceCombo); connect(m_widgetDataSourceCombo, SIGNAL(editTextChanged(QString)), this, SLOT(slotWidgetDataSourceTextChanged(QString))); mainLayout()->addWidget(m_widgetDataSourceCombo); m_widgetDataSourceComboSpacer = addWidgetSpacer(); //- Form's Data Source hlyr = new QHBoxLayout(); hlyr->setContentsMargins(0, 0, 0, 0); mainLayout()->addLayout(hlyr); m_dataSourceLabel = new QLabel(xi18n("Form's data source"), this); m_dataSourceLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); m_dataSourceLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom); hlyr->addWidget(m_dataSourceLabel); m_gotoButton = new KexiSmallToolButton( koIcon("go-jump"), QString(), this); m_gotoButton->setObjectName("gotoButton"); m_gotoButton->setToolTip(xi18n("Go to selected form's data source")); m_gotoButton->setWhatsThis(xi18n("Goes to selected form's data source")); hlyr->addWidget(m_gotoButton); connect(m_gotoButton, SIGNAL(clicked()), this, SLOT(slotGotoSelected())); #if 0 m_clearDSButton = new KexiSmallToolButton( koIcon("edit-clear-locationbar-rtl"), QString(), this); m_clearDSButton->setObjectName("clearDSButton"); m_clearDSButton->setMinimumHeight(m_dataSourceLabel->minimumHeight()); m_clearDSButton->setToolTip(futureI18n("Clear form's data source")); hlyr->addWidget(m_clearDSButton); connect(m_clearDSButton, SIGNAL(clicked()), this, SLOT(clearFormDataSourceSelection())); #endif m_formDataSourceCombo = new KexiDataSourceComboBox(this); m_formDataSourceCombo->setObjectName("dataSourceCombo"); m_formDataSourceCombo->setContentsMargins(0, 0, 0, 0); m_dataSourceLabel->setBuddy(m_formDataSourceCombo); mainLayout()->addWidget(m_formDataSourceCombo); m_formDataSourceComboSpacer = addWidgetSpacer(); -#ifdef KEXI_NO_AUTOFIELD_WIDGET +#ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT m_availableFieldsLabel = 0; m_addField = 0; mainLayout()->addStretch(); #else //2. Inserting fields //helper info //! @todo allow to hide such helpers by adding global option hlyr = new QHBoxLayout(); hlyr->setContentsMargins(0, 0, 0, 0); mainLayout()->addLayout(hlyr); m_mousePointerLabel = new QLabel(this); hlyr->addWidget(m_mousePointerLabel); m_mousePointerLabel->setPixmap(koIcon("mouse_pointer")); m_mousePointerLabel->setFixedWidth(m_mousePointerLabel->pixmap() ? m_mousePointerLabel->pixmap()->width() : 0); m_availableFieldsDescriptionLabel = new QLabel( futureI18n("Select fields from the list below and drag them onto" " a form or click the Insert button"), this); m_availableFieldsDescriptionLabel->setAlignment(Qt::AlignLeft); m_availableFieldsDescriptionLabel->setWordWrap(true); hlyr->addWidget(m_availableFieldsDescriptionLabel); //Available Fields hlyr = new QHBoxLayout(); hlyr->setContentsMargins(0, 0, 0, 0); mainLayout()->addLayout(hlyr); m_availableFieldsLabel = new QLabel(futureI18n("Available fields"), this); m_availableFieldsLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); hlyr->addWidget(m_availableFieldsLabel); m_addField = new KexiSmallToolButton( koIcon("add_field"), futureI18nc("Insert selected field into form", "Insert"), this); m_addField->setObjectName("addFieldButton"); m_addField->setFocusPolicy(Qt::StrongFocus); m_addField->setToolTip(futureI18n("Insert selected fields into form")); m_addField->setWhatsThis(futureI18n("Inserts selected fields into form")); hlyr->addWidget(m_addField); connect(m_addField, SIGNAL(clicked()), this, SLOT(slotInsertSelectedFields())); m_fieldListView = new KexiFieldListView(this, KexiFieldListView::ShowDataTypes | KexiFieldListView::AllowMultiSelection); m_fieldListView->setObjectName("fieldListView"); m_fieldListView->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding)); m_availableFieldsLabel->setBuddy(m_fieldListView); mainLayout()->addWidget(m_fieldListView, 1); connect(m_fieldListView, SIGNAL(selectionChanged()), this, SLOT(slotFieldListViewSelectionChanged())); connect(m_fieldListView, SIGNAL(fieldDoubleClicked(QString,QString,QString)), this, SLOT(slotFieldDoubleClicked(QString,QString,QString))); #endif mainLayout()->addStretch(1); connect(m_formDataSourceCombo, SIGNAL(editTextChanged(QString)), this, SLOT(slotFormDataSourceTextChanged(QString))); connect(m_formDataSourceCombo, SIGNAL(dataSourceChanged()), this, SLOT(slotFormDataSourceChanged())); connect(m_widgetDataSourceCombo, SIGNAL(selected()), this, SLOT(slotFieldSelected())); clearFormDataSourceSelection(); slotFieldListViewSelectionChanged(); } KexiDataSourcePage::~KexiDataSourcePage() { -#ifdef KEXI_NO_AUTOFIELD_WIDGET +#ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT delete m_tableOrQuerySchema; #endif } void KexiDataSourcePage::setProject(KexiProject *prj) { m_widgetDataSourceCombo->setProject(prj); m_formDataSourceCombo->setProject(prj); } void KexiDataSourcePage::clearFormDataSourceSelection(bool alsoClearComboBox) { if (m_insideClearFormDataSourceSelection) return; m_insideClearFormDataSourceSelection = true; if (alsoClearComboBox && !m_formDataSourceCombo->selectedName().isEmpty()) m_formDataSourceCombo->setDataSource(QString(), QString()); m_gotoButton->setEnabled(false); m_widgetDataSourceCombo->setFieldOrExpression(QString()); -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT m_addField->setEnabled(false); m_fieldListView->clear(); #endif m_insideClearFormDataSourceSelection = false; } void KexiDataSourcePage::slotWidgetDataSourceTextChanged(const QString &text) { if (text.isEmpty()) { clearWidgetDataSourceSelection(); } } void KexiDataSourcePage::clearWidgetDataSourceSelection() { m_widgetDataSourceCombo->setFieldOrExpression(QString()); slotFieldSelected(); } void KexiDataSourcePage::slotGotoSelected() { const QString pluginId(m_formDataSourceCombo->selectedPluginId()); if (pluginId == "org.kexi-project.table" || pluginId == "org.kexi-project.query") { if (m_formDataSourceCombo->isSelectionValid()) emit jumpToObjectRequested(pluginId, m_formDataSourceCombo->selectedName()); } } void KexiDataSourcePage::slotInsertSelectedFields() { -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT QStringList selectedFieldNames(m_fieldListView->selectedFieldNames()); if (selectedFieldNames.isEmpty()) return; emit insertAutoFields(m_fieldListView->schema()->table() ? "org.kexi-project.table" : "org.kexi-project.query", m_fieldListView->schema()->name(), selectedFieldNames); #endif } void KexiDataSourcePage::slotFieldDoubleClicked(const QString& sourcePluginId, const QString& sourceName, const QString& fieldName) { -#ifdef KEXI_NO_AUTOFIELD_WIDGET - Q_UNUSED(sourcePluginId); - Q_UNUSED(sourceName); - Q_UNUSED(fieldName); -#else +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT QStringList selectedFields; selectedFields.append(fieldName); emit insertAutoFields(sourcePluginId, sourceName, selectedFields); +#else + Q_UNUSED(sourcePluginId); + Q_UNUSED(sourceName); + Q_UNUSED(fieldName); #endif } void KexiDataSourcePage::slotFormDataSourceTextChanged(const QString &text) { const bool enable = m_formDataSourceCombo->isSelectionValid(); if (text.isEmpty()) { clearFormDataSourceSelection(); } else if (!enable) { clearFormDataSourceSelection(m_formDataSourceCombo->selectedName().isEmpty()/*alsoClearComboBox*/); } updateSourceFieldWidgetsAvailability(); } void KexiDataSourcePage::slotFormDataSourceChanged() { if (!m_formDataSourceCombo->project()) return; const QString pluginId(m_formDataSourceCombo->selectedPluginId()); bool dataSourceFound = false; QString name(m_formDataSourceCombo->selectedName()); const bool isIdAcceptable = pluginId == QLatin1String("org.kexi-project.table") || pluginId == QLatin1String("org.kexi-project.query"); if (isIdAcceptable && m_formDataSourceCombo->isSelectionValid()) { KDbTableOrQuerySchema *tableOrQuery = new KDbTableOrQuerySchema( m_formDataSourceCombo->project()->dbConnection(), name.toLatin1(), pluginId == "org.kexi-project.table"); if (tableOrQuery->table() || tableOrQuery->query()) { -#ifdef KEXI_NO_AUTOFIELD_WIDGET - m_tableOrQuerySchema = tableOrQuery; -#else +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT m_fieldListView->setSchema(tableOrQuery); +#else + m_tableOrQuerySchema = tableOrQuery; #endif dataSourceFound = true; m_widgetDataSourceCombo->setTableOrQuery(name, pluginId == "org.kexi-project.table"); } else { delete tableOrQuery; } } if (!dataSourceFound) { m_widgetDataSourceCombo->setTableOrQuery(QString(), true); } m_gotoButton->setEnabled(dataSourceFound); if (dataSourceFound) { slotFieldListViewSelectionChanged(); } else { -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT m_addField->setEnabled(false); #endif } updateSourceFieldWidgetsAvailability(); emit formDataSourceChanged(pluginId, name); } void KexiDataSourcePage::slotFieldSelected() { KDbField::Type dataType = KDbField::InvalidType; -#ifdef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT + //! @todo this should also work for expressions + KDbField *field = m_fieldListView->schema()->field( + m_widgetDataSourceCombo->fieldOrExpression()); +#else KDbField *field = m_tableOrQuerySchema->field( m_widgetDataSourceCombo->fieldOrExpression()); //temp -#else -//! @todo this should also work for expressions - KDbField *field = m_fieldListView->schema()->field( - m_widgetDataSourceCombo->fieldOrExpression()); #endif if (field) dataType = field->type(); emit dataSourceFieldOrExpressionChanged( m_widgetDataSourceCombo->fieldOrExpression(), m_widgetDataSourceCombo->fieldOrExpressionCaption(), dataType ); } void KexiDataSourcePage::setFormDataSource(const QString& pluginId, const QString& name) { m_formDataSourceCombo->setDataSource(pluginId, name); } #define KexiDataSourcePage_FADE 1 void KexiDataSourcePage::assignPropertySet(KPropertySet* propertySet) { QString objectName; if (propertySet) objectName = propertySet->propertyValue("objectName").toString(); if (!objectName.isEmpty() && objectName == m_currentObjectName) return; //the same object m_currentObjectName = objectName; //! @todo #if KexiDataSourcePage_FADE KexiFadeWidgetEffect *animation = 0; if (isVisible()) animation = new KexiFadeWidgetEffect(this); #endif QString objectClassName; if (propertySet) { objectClassName = propertySet->propertyValue("this:className").toString(); } updateInfoLabelForPropertySet(propertySet); const bool isForm = objectClassName == "KexiDBForm"; const bool multipleSelection = objectClassName == "special:multiple"; const bool hasDataSourceProperty = propertySet && propertySet->contains("dataSource") && !multipleSelection; if (!isForm) { //this is a widget QString dataSource; if (hasDataSourceProperty) { if (propertySet) { dataSource = (*propertySet)["dataSource"].value().toString(); } m_noDataSourceAvailableLabel->hide(); m_widgetDataSourceCombo->setFieldOrExpression(dataSource); m_widgetDataSourceCombo->setEnabled(true); m_widgetDSLabel->show(); m_widgetDataSourceCombo->show(); m_widgetDataSourceComboSpacer->show(); updateSourceFieldWidgetsAvailability(); } } if (isForm) { m_noDataSourceAvailableLabel->hide(); } else if (!hasDataSourceProperty) { if (multipleSelection) { m_noDataSourceAvailableLabel->setText(m_noDataSourceAvailableMultiText); } else { m_noDataSourceAvailableLabel->setText(m_noDataSourceAvailableSingleText); } m_noDataSourceAvailableLabel->show(); m_widgetDataSourceCombo->setEditText(QString()); } if (isForm || !hasDataSourceProperty) { //no source field can be set m_widgetDSLabel->hide(); m_widgetDataSourceCombo->hide(); m_widgetDataSourceComboSpacer->hide(); } //! @todo #if KexiDataSourcePage_FADE if (animation) animation->start(100); #endif } void KexiDataSourcePage::slotFieldListViewSelectionChanged() { -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT //update "add field" button's state for (Q3ListViewItemIterator it(m_fieldListView); it.current(); ++it) { if (it.current()->isSelected()) { m_addField->setEnabled(true); return; } } m_addField->setEnabled(false); #endif } void KexiDataSourcePage::updateSourceFieldWidgetsAvailability() { const bool hasDataSource = m_formDataSourceCombo->isSelectionValid(); m_widgetDataSourceCombo->setEnabled(hasDataSource); m_widgetDSLabel->setEnabled(hasDataSource); -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT m_fieldListView->setEnabled(hasDataSource); m_availableFieldsLabel->setEnabled(hasDataSource); m_mousePointerLabel->setEnabled(hasDataSource); m_availableFieldsDescriptionLabel->setEnabled(hasDataSource); #endif } diff --git a/kexi/plugins/forms/kexidatasourcepage.h b/kexi/plugins/forms/kexidatasourcepage.h index a01488a33b7..4cedf6bf7ac 100644 --- a/kexi/plugins/forms/kexidatasourcepage.h +++ b/kexi/plugins/forms/kexidatasourcepage.h @@ -1,111 +1,112 @@ /* This file is part of the KDE project Copyright (C) 2005-2009 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 KEXIDATASOURCEPAGE_H #define KEXIDATASOURCEPAGE_H #include "kexiformutils_export.h" +#include #include #include #include #include #include class KexiDataSourceComboBox; class KexiFieldComboBox; class KexiFieldListView; class KexiProject; class QToolButton; class QLabel; //! A page within form designer's property tabbed pane, providing data source editor class KEXIFORMUTILS_EXPORT KexiDataSourcePage : public KexiPropertyPaneViewBase { Q_OBJECT public: explicit KexiDataSourcePage(QWidget *parent); virtual ~KexiDataSourcePage(); public Q_SLOTS: void setProject(KexiProject *prj); void clearFormDataSourceSelection(bool alsoClearComboBox = true); void clearWidgetDataSourceSelection(); //! Sets data source of a currently selected form. //! This is performed on form initialization and on activating. void setFormDataSource(const QString& pluginId, const QString& name); //! Receives a pointer to a new property \a set (from KexiFormView::managerPropertyChanged()) void assignPropertySet(KPropertySet* propertySet); Q_SIGNALS: //! Signal emitted when helper button 'go to selected data source' is clicked. void jumpToObjectRequested(const QString& mime, const QString& name); //! Signal emitted when form's data source has been changed. It's connected to the Form Manager. void formDataSourceChanged(const QString& mime, const QString& name); /*! Signal emitted when current widget's data source (field/expression) has been changed. It's connected to the Form Manager. \a caption for this field is also provided (e.g. AutoField form widget use it) */ void dataSourceFieldOrExpressionChanged(const QString& string, const QString& caption, KDbField::Type type); /*! Signal emitted when 'insert fields' button has been clicked */ void insertAutoFields(const QString& sourcePartClass, const QString& sourceName, const QStringList& fields); protected Q_SLOTS: void slotWidgetDataSourceTextChanged(const QString &text); void slotFormDataSourceTextChanged(const QString &text); void slotFormDataSourceChanged(); void slotFieldSelected(); void slotGotoSelected(); void slotInsertSelectedFields(); void slotFieldListViewSelectionChanged(); void slotFieldDoubleClicked(const QString& sourcePluginId, const QString& sourceName, const QString& fieldName); protected: void updateSourceFieldWidgetsAvailability(); KexiFieldComboBox *m_widgetDataSourceCombo; QWidget *m_widgetDataSourceComboSpacer; KexiDataSourceComboBox* m_formDataSourceCombo; QWidget *m_formDataSourceComboSpacer; QLabel *m_dataSourceLabel, *m_noDataSourceAvailableLabel, *m_widgetDSLabel, *m_availableFieldsLabel, *m_mousePointerLabel, *m_availableFieldsDescriptionLabel; QToolButton *m_gotoButton, *m_addField; QString m_noDataSourceAvailableSingleText; QString m_noDataSourceAvailableMultiText; bool m_insideClearFormDataSourceSelection; -#ifdef KEXI_NO_AUTOFIELD_WIDGET - KDbTableOrQuerySchema *m_tableOrQuerySchema; //!< temp. -#else +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT KexiFieldListView* m_fieldListView; +#else + KDbTableOrQuerySchema *m_tableOrQuerySchema; //!< temp. #endif //! Used only in assignPropertySet() to check whether we already have the set assigned QString m_currentObjectName; }; #endif diff --git a/kexi/plugins/forms/kexidbfactory.cpp b/kexi/plugins/forms/kexidbfactory.cpp index b5adf2768e4..65320fb62f3 100644 --- a/kexi/plugins/forms/kexidbfactory.cpp +++ b/kexi/plugins/forms/kexidbfactory.cpp @@ -1,892 +1,846 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-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 "kexidbfactory.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kexiformview.h" #include "widgets/kexidbautofield.h" #include "widgets/kexidbcheckbox.h" #include "widgets/kexidbimagebox.h" #include "widgets/kexiframe.h" #include "widgets/kexidblabel.h" #include "widgets/kexidblineedit.h" #include "widgets/kexidbtextedit.h" #include "widgets/kexidbcombobox.h" #include "widgets/KexiDBPushButton.h" #include "widgets/kexidbform.h" #include "widgets/kexidbcommandlinkbutton.h" #include "widgets/kexidbslider.h" #include "widgets/kexidbprogressbar.h" #include "widgets/kexidbdatepicker.h" -#ifndef KEXI_NO_SUBFORM -# include "widgets/kexidbsubform.h" -#endif #include "kexidataawarewidgetinfo.h" #include #include #include #include #include #include #include ////////////////////////////////////////// KEXI_PLUGIN_FACTORY(KexiDBFactory, "kexiforms_dbwidgetsplugin.json") KexiDBFactory::KexiDBFactory(QObject *parent, const QVariantList &) : KexiDBFactoryBase(parent) , m_assignAction(0) { QByteArray parentFactory = "org.kexi-project.form.widgets.standard"; { KexiDataAwareWidgetInfo *wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("form")); wi->setClassName("KexiDBForm"); wi->setName(xi18nc("Form widget", "Form")); wi->setNamePrefix( xi18nc("A prefix for identifiers of forms. Based on that, identifiers such as " "form1, form2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "form")); wi->setDescription(xi18n("A form widget")); addClass(wi); } -#ifndef KEXI_NO_SUBFORM - { -// Unused, commented-out in Kexi 2.9 to avoid unnecessary translations: -// KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); -// wi->setIconName(koIconName("subform")); -// wi->setClassName("KexiDBSubForm"); -// wi->addAlternateClassName("KexiSubForm", true/*override*/); //older -// wi->setName(xi18nc("Sub Form widget", "Sub Form")); -// wi->setNamePrefix( -// i18nc("Widget name. This string will be used to name widgets of this class. " -// "It must _not_ contain white spaces and non latin1 characters.", "subForm")); -// wi->setDescription(xi18n("A form widget included in another Form")); -// wi->setAutoSyncForProperty("formName", false); -// addClass(wi); - } -#endif - { // inherited KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("lineedit")); wi->setClassName("KexiDBLineEdit"); wi->setParentFactoryName(parentFactory); wi->setInheritedClassName("QLineEdit"); wi->addAlternateClassName("KLineEdit", true/*override*/); wi->setIncludeFileName("qlineedit.h"); wi->setName(xi18nc("Text Box widget", "Text Box")); wi->setNamePrefix( xi18nc("A prefix for identifiers of text box widgets. Based on that, identifiers such as " "textBox1, textBox2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "textBox")); wi->setDescription(xi18n("A widget for entering and displaying line of text text")); wi->setInternalProperty("dontStartEditingOnInserting", true); // because we are most probably assign data source to this widget wi->setInlineEditingEnabledWhenDataSourceSet(false); addClass(wi); } { // inherited KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("textedit")); wi->setClassName("KexiDBTextEdit"); wi->setParentFactoryName(parentFactory); wi->setInheritedClassName("KTextEdit"); wi->addAlternateClassName("QTextEdit", true/*override*/); wi->addAlternateClassName("KTextEdit", true/*override*/); wi->setIncludeFileName("KTextEdit"); wi->setName(xi18nc("Text Editor widget", "Text Editor")); wi->setNamePrefix( xi18nc("A prefix for identifiers of text editor widgets. Based on that, identifiers such as " "textEditor1, textEditor2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "textEditor")); wi->setDescription(xi18n("A multiline text editor")); wi->setInternalProperty("dontStartEditingOnInserting", true); // because we are most probably assign data source to this widget wi->setInlineEditingEnabledWhenDataSourceSet(false); addClass(wi); } { KFormDesigner::WidgetInfo* wi = new KFormDesigner::WidgetInfo(this); wi->setIconName(koIconName("frame")); wi->setClassName("KexiFrame"); wi->setParentFactoryName(parentFactory); wi->setInheritedClassName("QFrame"); /* we are inheriting to get i18n'd strings already translated there */ wi->addAlternateClassName("QFrame", true/*override*/); wi->addAlternateClassName("Q3Frame", true/*override*/); wi->setName(xi18nc("Frame widget", "Frame")); wi->setNamePrefix( xi18nc("A prefix for identifiers of frame widgets. Based on that, identifiers such as " "frame1, frame2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "frame")); wi->setDescription(xi18n("A frame widget")); addClass(wi); } { KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("label")); wi->setClassName("KexiDBLabel"); wi->setParentFactoryName(parentFactory); wi->setInheritedClassName("QLabel"); /* we are inheriting to get i18n'd strings already translated there */ wi->addAlternateClassName("QLabel", true/*override*/); wi->addAlternateClassName("KexiLabel", true/*override*/); //older wi->setName(xi18nc("Text Label widget", "Label")); wi->setNamePrefix( xi18nc("A prefix for identifiers of label widgets. Based on that, identifiers such as " "label1, label2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "label")); wi->setDescription(xi18n("A widget for displaying text")); wi->setInlineEditingEnabledWhenDataSourceSet(false); addClass(wi); } { KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("pixmaplabel")); wi->setClassName("KexiDBImageBox"); wi->setParentFactoryName(parentFactory); wi->setInheritedClassName("KexiPictureLabel"); /* we are inheriting to get i18n'd strings already translated there */ wi->addAlternateClassName("KexiPictureLabel", true/*override*/); wi->addAlternateClassName("KexiImageBox", true/*override*/); //older wi->setName(xi18nc("Image Box widget", "Image Box")); wi->setNamePrefix( xi18nc("A prefix for identifiers of image box widgets. Based on that, identifiers such as " "image1, image2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "image")); wi->setDescription(xi18n("A widget for displaying images")); // wi->setCustomTypeForProperty("pixmapData", KexiCustomPropertyFactory::PixmapData); wi->setCustomTypeForProperty("pixmapId", KexiCustomPropertyFactory::PixmapId); wi->setInternalProperty("dontStartEditingOnInserting", true); addClass(wi); } { KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("combo")); wi->setClassName("KexiDBComboBox"); wi->setParentFactoryName(parentFactory); wi->setInheritedClassName("KComboBox"); /* we are inheriting to get i18n'd strings already translated there */ wi->addAlternateClassName("KComboBox", true/*override*/); wi->setName(xi18nc("Combo Box widget", "Combo Box")); wi->setNamePrefix( xi18nc("A prefix for identifiers of combo box widgets. Based on that, identifiers such as " "comboBox1, comboBox2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "comboBox")); wi->setDescription(xi18n("A combo box widget")); addClass(wi); } { KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("check")); wi->setClassName("KexiDBCheckBox"); wi->setParentFactoryName(parentFactory); wi->setInheritedClassName("QCheckBox"); /* we are inheriting to get i18n'd strings already translated there */ wi->addAlternateClassName("QCheckBox", true/*override*/); wi->setName(xi18nc("Check Box widget", "Check Box")); wi->setNamePrefix( xi18nc("A prefix for identifiers of combo box widgets. Based on that, identifiers such as " "checkBox1, checkBox2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "checkBox")); wi->setDescription(xi18n("A check box with text label")); addClass(wi); } -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT { // Unused, commented-out in Kexi 2.9 to avoid unnecessary translations: // KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); // wi->setIconName(koIconName("autofield")); // wi->setClassName("KexiDBAutoField"); // wi->addAlternateClassName("KexiDBFieldEdit", true/*override*/); //older // wi->setName(xi18n("Auto Field")); // wi->setNamePrefix( // i18nc("Widget name. This string will be used to name widgets of this class. " // "It must _not_ contain white spaces and non latin1 characters", "autoField")); // wi->setDescription(xi18n("A widget containing an automatically selected editor " // "and a label to edit the value of a database field of any type.")); // addClass(wi); } #endif { // inherited KFormDesigner::WidgetInfo* wi = new KFormDesigner::WidgetInfo(this); wi->addAlternateClassName("KexiDBPushButton"); wi->addAlternateClassName("KexiPushButton"); wi->setName(xi18nc("Button widget", "Button")); wi->setNamePrefix( xi18nc("A prefix for identifiers of button widgets. Based on that, identifiers such as " "button1, button2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "button")); wi->setDescription(xi18n("A button for executing actions")); wi->setParentFactoryName(parentFactory); wi->setInheritedClassName("QPushButton"); addClass(wi); } { KFormDesigner::WidgetInfo* wi = new KFormDesigner::WidgetInfo(this); wi->setClassName("KexiDBCommandLinkButton"); wi->setIconName(koIconName("button")); wi->setName(xi18nc("Link Button widget", "Link Button")); wi->setNamePrefix( xi18nc("A prefix for identifiers of link button widgets. Based on that, identifiers such as " "linkButton1, linkButton2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "linkButton")); wi->setDescription(xi18n("A Link button for executing actions")); addClass(wi); } { KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("slider")); wi->setClassName("KexiDBSlider"); wi->setName(xi18nc("Slider widget", "Slider")); wi->setNamePrefix( xi18nc("A prefix for identifiers of slider widgets. Based on that, identifiers such as " "slider1, slider2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "slider")); wi->setDescription(xi18n("A Slider widget")); addClass(wi); } { KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("progress")); wi->setClassName("KexiDBProgressBar"); wi->setName(xi18nc("Progress Bar widget", "Progress Bar")); wi->setNamePrefix( xi18nc("A prefix for identifiers of progress bar widgets. Based on that, identifiers such as " "progressBar1, progressBar2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "progressBar")); wi->setDescription(xi18n("A Progress Bar widget")); addClass(wi); } { KexiDataAwareWidgetInfo* wi = new KexiDataAwareWidgetInfo(this); wi->setIconName(koIconName("dateedit")); wi->setClassName("KexiDBDatePicker"); wi->setName(xi18nc("Date Picker widget", "Date Picker")); wi->setNamePrefix( xi18nc("A prefix for identifiers of date picker widgets. Based on that, identifiers such as " "datePicker1, datePicker2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "datePicker")); wi->setDescription(xi18n("A Date Picker widget")); addClass(wi); } setPropertyDescription("invertedAppearance", xi18n("Inverted")); setPropertyDescription("minimum", xi18n("Minimum")); setPropertyDescription("maximum", xi18n("Maximum")); setPropertyDescription("format", xi18n("Format")); setPropertyDescription("orientation", xi18n("Orientation")); setPropertyDescription("textDirection", xi18n("Text Direction")); setPropertyDescription("textVisible", xi18n("Text Visible")); setPropertyDescription("value", xi18n("Value")); setPropertyDescription("date", xi18n("Date")); setPropertyDescription("arrowVisible", xi18n("Arrow Visible")); setPropertyDescription("description", xi18n("Description")); setPropertyDescription("pageStep", xi18nc("Property of slider widgets", "Page Step")); setPropertyDescription("singleStep", xi18nc("Property of slider widgets", "Single Step")); setPropertyDescription("tickInterval", xi18nc("Property of slider widgets", "Tick Interval")); setPropertyDescription("tickPosition", xi18nc("Property of slider widgets", "Tick Position")); setPropertyDescription("showEditor", xi18n("Show Editor")); setPropertyDescription("formName", xi18n("Form Name")); setPropertyDescription("onClickAction", xi18n("On Click")); setPropertyDescription("onClickActionOption", xi18n("On Click Option")); setPropertyDescription("autoTabStops", xi18n("Auto Tab Order")); setPropertyDescription("checkSpellingEnabled", xi18n("Spell Checking")); setPropertyDescription("html", xi18nc("Widget Property", "HTML")); setPropertyDescription("lineWrapColumnOrWidth", xi18n("Line Wrap At")); setPropertyDescription("lineWrapMode", xi18n("Line Wrap Mode")); setPropertyDescription("spellCheckingLanguage", xi18n("Spell Checking Language")); setPropertyDescription("widgetType", xi18n("Editor Type")); -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT //for autofield's type: inherit i18n from KexiDB setValueDescription("Auto", futureI18nc("AutoField editor's type", "Auto")); setValueDescription("Text", KDbField::typeName(KDbField::Text)); setValueDescription("Integer", KDbField::typeName(KDbField::Integer)); setValueDescription("Double", KDbField::typeName(KDbField::Double)); setValueDescription("Boolean", KDbField::typeName(KDbField::Boolean)); setValueDescription("Date", KDbField::typeName(KDbField::Date)); setValueDescription("Time", KDbField::typeName(KDbField::Time)); setValueDescription("DateTime", KDbField::typeName(KDbField::DateTime)); setValueDescription("MultiLineText", xi18nc("AutoField editor's type", "Multiline Text")); setValueDescription("ComboBox", xi18nc("AutoField editor's type", "Drop-Down List")); setValueDescription("Image", xi18nc("AutoField editor's type", "Image")); #endif setValueDescription("NoTicks", xi18nc("Possible value of slider widget's \"Tick position\" property", "No Ticks")); setValueDescription("TicksAbove", xi18nc("Possible value of slider widget's \"Tick position\" property", "Above")); setValueDescription("TicksLeft", xi18nc("Possible value of slider widget's \"Tick position\" property", "Left")); setValueDescription("TicksBelow", xi18nc("Possible value of slider widget's \"Tick position\" property", "Below")); setValueDescription("TicksRight", xi18nc("Possible value of slider widget's \"Tick position\" property", "Right")); setValueDescription("TicksBothSides", xi18nc("Possible value of slider widget's \"Tick position\" property", "Both Sides")); // auto field: // setPropertyDescription("autoCaption", futureI18n("Auto Label")); // setPropertyDescription("foregroundLabelColor", futureI18n("Label Text Color")); // setPropertyDescription("backgroundLabelColor", futureI18nc("(a property name, keep the text narrow!)", // "Label Background\nColor")); // setPropertyDescription("labelPosition", futureI18n("Label Position")); // setValueDescription("Left", futureI18nc("Label Position", "Left")); // setValueDescription("Top", futureI18nc("Label Position", "Top")); // setValueDescription("NoLabel", futureI18nc("Label Position", "No Label")); setPropertyDescription("sizeInternal", xi18n("Size")); setPropertyDescription("pixmapId", xi18n("Image")); setPropertyDescription("scaledContents", xi18n("Scaled Contents")); setPropertyDescription("smoothTransformation", xi18nc("Property: Smoothing when contents are scaled", "Smoothing")); setPropertyDescription("keepAspectRatio", xi18nc("Property: Keep Aspect Ratio (keep short)", "Keep Ratio")); //hide classes that are replaced by db-aware versions hideClass("KexiPictureLabel"); hideClass("KComboBox"); //used in labels, frames... setPropertyDescription("dropDownButtonVisible", xi18nc("Drop-Down Button for Image Box Visible (a property name, keep the text narrow!)", "Drop-Down\nButton Visible")); //for checkbox setValueDescription("TristateDefault", xi18nc("Value of \"Tristate\" property in checkbox: default", "Default")); setValueDescription("TristateOn", xi18nc("Value of \"Tristate\" property in checkbox: yes", "Yes")); setValueDescription("TristateOff", xi18nc("Value of \"Tristate\" property in checkbox: no", "No")); //for combobox setPropertyDescription("editable", xi18nc("Editable combobox", "Editable")); //for kexipushbutton setPropertyDescription("hyperlink" , xi18nc("Hyperlink address", "Hyperlink")); setPropertyDescription("hyperlinkType", xi18nc("Type of hyperlink", "Hyperlink Type")); setPropertyDescription("hyperlinkTool", xi18nc("Tool used for opening a hyperlink", "Hyperlink Tool")); setPropertyDescription("remoteHyperlink", xi18nc("Allow to open remote hyperlinks", "Remote Hyperlink")); setPropertyDescription("hyperlinkExecutable", xi18nc("Allow to open executables", "Executable Hyperlink")); setValueDescription("NoHyperlink", xi18nc("Hyperlink type, NoHyperlink", "No Hyperlink")); setValueDescription("StaticHyperlink", xi18nc("Hyperlink type, StaticHyperlink", "Static")); setValueDescription("DynamicHyperlink", xi18nc("Hyperlink type, DynamicHyperlink", "Dynamic")); setValueDescription("DefaultHyperlinkTool", xi18nc("Hyperlink tool, DefaultTool", "Default")); setValueDescription("BrowserHyperlinkTool", xi18nc("Hyperlink tool, BrowserTool", "Browser")); setValueDescription("MailerHyperlinkTool", xi18nc("Hyperlink tool, MailerTool", "Mailer")); } KexiDBFactory::~KexiDBFactory() { } QWidget* KexiDBFactory::createWidget(const QByteArray &c, QWidget *p, const char *n, KFormDesigner::Container *container, CreateWidgetOptions options) { QWidget *w = 0; QString text(container->form()->library()->textForWidgetName(n, c)); const bool designMode = options & KFormDesigner::WidgetFactory::DesignViewMode; bool createContainer = false; if (c == "KexiDBLineEdit") { w = new KexiDBLineEdit(p); } -#ifndef KEXI_NO_SUBFORM - if (c == "KexiDBSubForm") { - w = new KexiDBSubForm(container->form(), p); - } -#endif else if (c == "KexiDBTextEdit") { w = new KexiDBTextEdit(p); } else if (c == "Q3Frame" || c == "QFrame" || c == "KexiFrame") { w = new KexiFrame(p); createContainer = true; } else if (c == "KexiDBLabel") { w = new KexiDBLabel(text, p); } else if (c == "KexiDBImageBox") { w = new KexiDBImageBox(designMode, p); connect(w, SIGNAL(idChanged(long)), this, SLOT(slotImageBoxIdChanged(long))); } -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT else if (c == "KexiDBAutoField") { w = new KexiDBAutoField(p); } #endif else if (c == "KexiDBCheckBox") { w = new KexiDBCheckBox(text, p); } else if (c == "KexiDBSlider") { w = new KexiDBSlider(p); } else if (c == "KexiDBProgressBar") { w = new KexiDBProgressBar(p); } else if (c == "KexiDBDatePicker") { w = new KexiDBDatePicker(p); } else if (c == "KexiDBComboBox") { w = new KexiDBComboBox(p); } else if (c == "QPushButton" || c == "KPushButton" || c == "KexiDBPushButton" || c == "KexiPushButton") { w = new KexiDBPushButton(text, p); } else if (c == "KexiDBCommandLinkButton" || c == "KexiCommandLinkButton") { w = new KexiDBCommandLinkButton(text, QString(), p); } if (w) w->setObjectName(n); if (createContainer) (void)new KFormDesigner::Container(container, w, container); return w; } bool KexiDBFactory::createMenuActions(const QByteArray &classname, QWidget *w, QMenu *menu, KFormDesigner::Container *) { if (m_assignAction->isEnabled()) { /*! @todo also call createMenuActions() for inherited factory! */ menu->addAction(m_assignAction); return true; } else if (classname == "KexiDBImageBox") { KexiDBImageBox *imageBox = static_cast(w); imageBox->contextMenu()->updateActionsAvailability(); KActionCollection *ac = imageBox->contextMenu()->actionCollection(); QMenu *subMenu = menu->addMenu(xi18n("&Image")); //! @todo make these actions undoable/redoable subMenu->addAction(ac->action("insert")); subMenu->addAction(ac->action("file_save_as")); subMenu->addSeparator(); subMenu->addAction(ac->action("edit_cut")); subMenu->addAction(ac->action("edit_copy")); subMenu->addAction(ac->action("edit_paste")); subMenu->addAction(ac->action("delete")); if (ac->action("properties")) { subMenu->addSeparator(); subMenu->addAction(ac->action("properties")); } } return false; } void KexiDBFactory::createCustomActions(KActionCollection* col) { //this will create shared instance action for design mode (special collection is provided) col->addAction("widget_assign_action", m_assignAction = new QAction(koIcon("form_action"), xi18n("&Assign Action..."), this)); } bool KexiDBFactory::startInlineEditing(InlineEditorCreationArguments& args) { const KFormDesigner::WidgetInfo* wclass = args.container->form()->library()->widgetInfoForClassName(args.classname); const KexiDataAwareWidgetInfo* wDataAwareClass = dynamic_cast(wclass); if (wDataAwareClass && !wDataAwareClass->inlineEditingEnabledWhenDataSourceSet()) { KexiFormDataItemInterface* iface = dynamic_cast(args.widget); if (iface && !iface->dataSource().isEmpty()) { //! @todo reimplement inline editing for KexiDBLineEdit using combobox with data sources return false; } } if (args.classname == "KexiDBLineEdit") { //! @todo this code should not be copied here but //! just inherited KexiStandardFormWidgetsFactory::startInlineEditing() should be called QLineEdit *lineedit = static_cast(args.widget); args.text = lineedit->text(); args.alignment = lineedit->alignment(); args.useFrame = true; return true; } else if (args.classname == "KexiDBTextEdit") { //! @todo this code should not be copied here but //! just inherited KexiStandardFormWidgetsFactory::startInlineEditing() should be called KTextEdit *textedit = static_cast(args.widget); //! @todo rich text? args.text = textedit->toPlainText(); args.alignment = textedit->alignment(); args.useFrame = true; args.multiLine = true; //! @todo #if 0 //copy a few properties KTextEdit *ed = dynamic_cast(editor(w)); ed->setLineWrapMode(textedit->lineWrapMode()); ed->setLineWrapColumnOrWidth(textedit->lineWrapColumnOrWidth()); ed->setWordWrapMode(textedit->wordWrapMode()); ed->setTabStopWidth(textedit->tabStopWidth()); ed->setTextFormat(textedit->textFormat()); ed->setHorizontalScrollBarPolicy(textedit->horizontalScrollBarPolicy()); ed->setVerticalScrollBarPolicy(textedit->verticalScrollBarPolicy()); #endif return true; } // KexiDBCommandLinkButton else if (args.classname == "KexiDBCommandLinkButton" ){ KexiDBCommandLinkButton *linkButton=static_cast(args.widget); QStyleOption option; option.initFrom(linkButton); args.text = linkButton->text(); const QRect r(linkButton->style()->subElementRect( QStyle::SE_PushButtonContents, &option, linkButton)); QFontMetrics fm(linkButton->font()); args.geometry = QRect(linkButton->x() + linkButton->iconSize().width() + 6, linkButton->y() + r.y(), r.width() - 6, fm.height()+14); return true; } else if (args.classname == "KexiDBLabel") { KexiDBLabel *label = static_cast(args.widget); if (label->textFormat() == Qt::RichText) { args.execute = false; if (wclass && wclass->inheritedClass()) { const QByteArray thisClassname = args.classname; //save args.classname = wclass->inheritedClass()->className(); //! @todo OK? const bool result = wclass->inheritedClass()->factory()->startInlineEditing(args); args.classname = thisClassname; return result; } else { return false; } } else { args.text = label->text(); args.alignment = label->alignment(); args.multiLine = label->wordWrap(); } return true; } -#ifndef KEXI_NO_SUBFORM - else if (args.classname == "KexiDBSubForm") { -//! @todo - // open the form in design mode - KexiDBSubForm *subform = static_cast(args.widget); - args.execute = false; - if (KexiMainWindowIface::global()) { - bool openingCancelled; - KexiMainWindowIface::global()->openObject( - "org.kexi-project.form", subform->formName(), Kexi::DesignViewMode, - &openingCancelled); - } - return true; - } -#endif #if 0 else if ( args.classname == "KexiDBDateEdit" || args.classname == "KexiDBDateTimeEdit" || args.classname == "KexiDBTimeEdit" /*|| classname == "KexiDBIntSpinBox" || classname == "KexiDBDoubleSpinBox"*/) { disableFilter(w, container); return true; } #endif else if (args.classname == "KexiDBAutoField") { if (static_cast(args.widget)->hasAutoCaption()) return false; // caption is auto, abort editing QLabel *label = static_cast(args.widget)->label(); args.text = label->text(); args.widget = label; args.geometry = label->geometry(); args.alignment = label->alignment(); return true; } else if (args.classname == "KexiDBCheckBox") { KexiDBCheckBox *cb = static_cast(args.widget); QStyleOption option; option.initFrom(cb); QRect r(cb->geometry()); r.setLeft( r.left() + 2 + cb->style()->subElementRect(QStyle::SE_CheckBoxIndicator, &option, cb).width()); args.text = cb->text(); args.geometry = r; return true; } else if (args.classname == "KexiDBImageBox") { KexiDBImageBox *image = static_cast(args.widget); image->insertFromFile(); args.execute = false; return true; } return false; } bool KexiDBFactory::previewWidget(const QByteArray &, QWidget *, KFormDesigner::Container *) { return false; } bool KexiDBFactory::clearWidgetContent(const QByteArray & /*classname*/, QWidget *w) { //! @todo this code should not be copied here but //! just inherited KexiStandardFormWidgetsFactory::clearWidgetContent() should be called KexiFormDataItemInterface *iface = dynamic_cast(w); if (iface) iface->clear(); return true; } bool KexiDBFactory::isPropertyVisibleInternal(const QByteArray& classname, QWidget *w, const QByteArray& property, bool isTopLevel) { //general bool ok = true; if (classname == "KexiDBPushButton" || classname == "KexiPushButton") { ok = property != "isDragEnabled" #ifndef KEXI_SHOW_UNFINISHED && property != "onClickAction" /*! @todo reenable */ && property != "onClickActionOption" /*! @todo reenable */ && property != "iconSet" /*! @todo reenable */ && property != "iconSize" /*! @todo reenable */ && property != "stdItem" /*! @todo reenable stdItem */ #endif ; } else if (classname == "KexiDBCommandLinkButton") { ok = property != "isDragEnabled" && property != "default" && property != "checkable" && property != "autoDefault" && property != "autoRepeat" && property != "autoRepeatDelay" && property != "autoRepeatInterval" #ifndef KEXI_SHOW_UNFINISHED && property != "onClickAction" /*! @todo reenable */ && property != "onClickActionOption" /*! @todo reenable */ && property != "iconSet" /*! @todo reenable */ && property != "iconSize" /*! @todo reenable */ && property != "stdItem" /*! @todo reenable stdItem */ #endif ; } else if (classname == "KexiDBSlider") { ok = property != "sliderPosition" && property != "tracking"; } else if (classname == "KexiDBProgressBar") { ok = property != "focusPolicy" && property != "value"; } else if (classname == "KexiDBLineEdit") ok = property != "urlDropsEnabled" && property != "vAlign" && property != "echoMode" && property != "clickMessage" // Replaced by placeholderText in 2.9, // kept for backward compatibility Kexi projects created with Qt < 4.7. && property != "showClearButton" // Replaced by clearButtonEnabled in 3.0, // kept for backward compatibility Kexi projects created with Qt 4. #ifndef KEXI_SHOW_UNFINISHED && property != "inputMask" && property != "maxLength" //!< we may want to integrate this with db schema #endif ; else if (classname == "KexiDBComboBox") ok = property != "autoCaption" && property != "labelPosition" && property != "widgetType" && property != "fieldTypeInternal" && property != "fieldCaptionInternal" //hide properties that come with KexiDBAutoField -#ifdef KEXI_NO_AUTOFIELD_WIDGET +#ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT && property != "foregroundLabelColor" && property != "backgroundLabelColor" #endif ; else if (classname == "KexiDBTextEdit") ok = property != "undoDepth" && property != "undoRedoEnabled" //always true! && property != "dragAutoScroll" //always true! && property != "overwriteMode" //always false! && property != "resizePolicy" && property != "autoFormatting" //too complex && property != "documentTitle" && property != "cursorWidth" #ifndef KEXI_SHOW_UNFINISHED && property != "paper" #endif && property != "textInteractionFlags" //! @todo support textInteractionFlags property of QLabel and QTextEdit ; -#ifndef KEXI_NO_SUBFORM - else if (classname == "KexiDBSubForm") - ok = property != "dragAutoScroll" - && property != "resizePolicy" - && property != "focusPolicy"; -#endif else if (classname == "KexiDBForm") ok = property != "iconText" && property != "geometry" /*nonsense for toplevel widget; for size, "size" property is used*/; else if (classname == "KexiDBLabel") ok = property != "focusPolicy" && property != "textInteractionFlags"; //! @todo support textInteractionFlags property of QLabel else if (classname == "KexiDBAutoField") { if (!isTopLevel && property == "caption") return true; //force if (property == "fieldTypeInternal" || property == "fieldCaptionInternal" //! @todo unhide in 2.0 || property == "widgetType") return false; ok = property != "text"; /* "text" is not needed as "caption" is used instead */ } else if (classname == "KexiDBImageBox") { ok = property != "font" && property != "wordbreak" && property != "pixmapId"; } else if (classname == "KexiDBCheckBox") { //hide text property if the widget is a child of an autofield beause there's already "caption" for this purpose if (property == "text" && w && dynamic_cast(w->parentWidget())) return false; ok = property != "autoRepeat"; } else if (classname == "KexiDBDatePicker") { ok = property != "closeButton" && property != "fontSize"; } return ok && KexiDBFactoryBase::isPropertyVisibleInternal(classname, w, property, isTopLevel); } bool KexiDBFactory::propertySetShouldBeReloadedAfterPropertyChange(const QByteArray& classname, QWidget *w, const QByteArray& property) { Q_UNUSED(classname); Q_UNUSED(w); return property == "fieldTypeInternal" || property == "widgetType" || property == "paletteBackgroundColor" || property == "autoFillBackground"; } bool KexiDBFactory::changeInlineText(KFormDesigner::Form *form, QWidget *widget, const QString &text, QString &oldText) { const QByteArray n(widget->metaObject()->className()); if (n == "KexiDBAutoField") { oldText = widget->property("caption").toString(); changeProperty(form, widget, "caption", text); return true; } else if (n == "KexiDBCommandLinkButton") { oldText = widget->property("text").toString(); changeProperty(form, widget, "text", text); return true; } //! @todo check field's geometry return false; } void KexiDBFactory::resizeEditor(QWidget *editor, QWidget *w, const QByteArray &classname) { if (classname == "KexiDBAutoField") editor->setGeometry(static_cast(w)->label()->geometry()); } void KexiDBFactory::slotImageBoxIdChanged(KexiBLOBBuffer::Id_t id) { KexiFormView *formView = KDbUtils::findParent((QWidget*)sender()); if (formView) { changeProperty(formView->form(), formView, "pixmapId", int(/*! @todo unsafe */id)); formView->setUnsavedLocalBLOB(formView->form()->selectedWidget(), id); } } #include "kexidbfactory.moc" diff --git a/kexi/plugins/forms/kexidbfactory.h b/kexi/plugins/forms/kexidbfactory.h index 9dd761be48c..05c3d620c90 100644 --- a/kexi/plugins/forms/kexidbfactory.h +++ b/kexi/plugins/forms/kexidbfactory.h @@ -1,68 +1,68 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-2006 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 KEXIDBFACTORY_H #define KEXIDBFACTORY_H #include "kexidbfactorybase.h" class QAction; -//! Kexi Factory (DB widgets + subform) +//! Kexi Factory for data-aware widgets //! @todo merge with KexiStandardFormWidgetsFactory class KexiDBFactory : public KexiDBFactoryBase { Q_OBJECT public: KexiDBFactory(QObject *parent, const QVariantList &); virtual ~KexiDBFactory(); virtual QWidget *createWidget(const QByteArray &classname, QWidget *parent, const char *name, KFormDesigner::Container *container, CreateWidgetOptions options = DefaultOptions); virtual void createCustomActions(KActionCollection* col); virtual bool createMenuActions(const QByteArray &classname, QWidget *w, QMenu *menu, KFormDesigner::Container *container); virtual bool startInlineEditing(InlineEditorCreationArguments& args); virtual bool previewWidget(const QByteArray &, QWidget *, KFormDesigner::Container *); virtual bool clearWidgetContent(const QByteArray &classname, QWidget *w); protected Q_SLOTS: void slotImageBoxIdChanged(long id); /*KexiBLOBBuffer::Id_t*/ protected: virtual bool changeInlineText(KFormDesigner::Form *form, QWidget *widget, const QString &text, QString &oldText); virtual void resizeEditor(QWidget *editor, QWidget *widget, const QByteArray &classname); virtual bool isPropertyVisibleInternal(const QByteArray& classname, QWidget *w, const QByteArray& property, bool isTopLevel); //! Sometimes property sets should be reloaded when a given property value changed. //! @todo this does not seem to work in Kexi 2.x virtual bool propertySetShouldBeReloadedAfterPropertyChange(const QByteArray& classname, QWidget *w, const QByteArray& property); QAction * m_assignAction; }; #endif diff --git a/kexi/plugins/forms/kexiformmanager.cpp b/kexi/plugins/forms/kexiformmanager.cpp index 10876c40d31..e0961525022 100644 --- a/kexi/plugins/forms/kexiformmanager.cpp +++ b/kexi/plugins/forms/kexiformmanager.cpp @@ -1,557 +1,557 @@ /* This file is part of the KDE project Copyright (C) 2005-2011 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 "kexiformmanager.h" #include "widgets/kexidbform.h" #include "widgets/kexidbautofield.h" #include "kexiformscrollview.h" #include "kexiformview.h" #include "kexidatasourcepage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KexiFormManagerPrivate { public: explicit KexiFormManagerPrivate(KexiFormManager *qq) : part(0) , q(qq) { features = KFormDesigner::Form::NoFeatures; widgetActionGroup = new KFormDesigner::ActionGroup(q); #ifdef KFD_SIGSLOTS dragConnectionAction = 0; #endif widgetTree = 0; collection = 0; } ~KexiFormManagerPrivate() { } KexiFormPart* part; KFormDesigner::WidgetLibrary* lib; KFormDesigner::ActionGroup* widgetActionGroup; KFormDesigner::WidgetTreeWidget *widgetTree; KActionCollection *collection; KFormDesigner::Form::Features features; KToggleAction *pointerAction; #ifdef KFD_SIGSLOTS KToggleAction *dragConnectionAction; #endif KToggleAction *snapToGridAction; KexiFormManager *q; }; Q_GLOBAL_STATIC(KexiFormManager, g_manager) KexiFormManager* KexiFormManager::self() { return g_manager; } KexiFormManager::KexiFormManager() : QObject() , d(new KexiFormManagerPrivate(this)) { KexiCustomPropertyFactory::init(); } KexiFormManager::~KexiFormManager() { delete d; } void KexiFormManager::init(KexiFormPart *part, KFormDesigner::WidgetTreeWidget *widgetTree) { /*! @todo add configuration for supported factory groups */ QStringList supportedFactoryGroups; supportedFactoryGroups += "kexi"; d->lib = new KFormDesigner::WidgetLibrary(this, supportedFactoryGroups); d->lib->setAdvancedPropertiesVisible(false); connect(d->lib, SIGNAL(widgetCreated(QWidget*)), this, SLOT(slotWidgetCreatedByFormsLibrary(QWidget*))); connect(d->lib, SIGNAL(widgetActionToggled(QByteArray)), this, SLOT(slotWidgetActionToggled(QByteArray))); d->part = part; KActionCollection *col = /*tmp*/ new KActionCollection(this); if (col) { createActions( col ); //connect actions provided by widget factories connect(col->action("widget_assign_action"), SIGNAL(triggered()), this, SLOT(slotAssignAction())); } d->widgetTree = widgetTree; if (d->widgetTree) { //! @todo KEXI3 Port this: connect() //! @todo KEXI3 Port code related to KFormDesigner::FormManager::m_treeview here //! @todo connect(m_propSet, SIGNAL(widgetNameChanged(QByteArray,QByteArray)), //! @todo m_treeview, SLOT(renameItem(QByteArray,QByteArray))); } } KFormDesigner::ActionGroup* KexiFormManager::widgetActionGroup() const { return d->widgetActionGroup; } void KexiFormManager::createActions(KActionCollection* collection) { d->collection = collection; d->lib->createWidgetActions(d->widgetActionGroup); //! @todo insertWidget() slot? #ifdef KFD_SIGSLOTS if (d->features & KFormDesigner::Form::EnableConnections) { // nothing } else { d->dragConnectionAction = new KToggleAction( koIcon("signalslot"), futureI18n("Connect Signals/Slots"), d->collection); d->dragConnectionAction->setObjectName("drag_connection"); connect(d->dragConnectionAction, SIGNAL(triggered()), this, SLOT(startCreatingConnection())); d->dragConnectionAction->setChecked(false); } #endif d->pointerAction = new KToggleAction( koIcon("mouse_pointer"), xi18n("Pointer"), d->collection); d->pointerAction->setObjectName("edit_pointer"); d->widgetActionGroup->addAction(d->pointerAction); connect(d->pointerAction, SIGNAL(triggered()), this, SLOT(slotPointerClicked())); d->pointerAction->setChecked(true); d->snapToGridAction = new KToggleAction( xi18n("Snap to Grid"), d->collection); d->snapToGridAction->setObjectName("snap_to_grid"); //! @todo #if 0 // Create the Style selection action (with a combo box in toolbar and submenu items) KSelectAction *styleAction = new KSelectAction( xi18n("Style"), d->collection); styleAction->setObjectName("change_style"); connect(styleAction, SIGNAL(triggered()), this, SLOT(slotStyle())); styleAction->setEditable(false); QString currentStyle(kapp->style()->objectName().toLower()); const QStringList styles = QStyleFactory::keys(); styleAction->setItems(styles); styleAction->setCurrentItem(0); QStringList::ConstIterator endIt = styles.constEnd(); int idx = 0; for (QStringList::ConstIterator it = styles.constBegin(); it != endIt; ++it, ++idx) { if ((*it).toLower() == currentStyle) { styleAction->setCurrentItem(idx); break; } } styleAction->setToolTip(xi18n("Set the current view style.")); styleAction->setMenuAccelsEnabled(true); #endif d->lib->addCustomWidgetActions(d->collection); #ifdef KEXI_DEBUG_GUI KConfigGroup generalGroup(KSharedConfig::openConfig()->group("General")); if (generalGroup.readEntry("ShowInternalDebugger", false)) { QAction *a = new QAction(koIcon("run-build-file"), xi18n("Show Form UI Code"), this); d->collection->addAction("show_form_ui", a); a->setShortcut(Qt::CTRL + Qt::Key_U); connect(a, SIGNAL(triggered()), this, SLOT(showFormUICode())); } #endif //! @todo move elsewhere { // (from obsolete kexiformpartinstui.rc) QStringList formActions; formActions << "edit_pointer" << QString() //sep -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT << "library_widget_KexiDBAutoField" #endif << "library_widget_KexiDBLabel" << "library_widget_KexiDBLineEdit" << "library_widget_KexiDBTextEdit" << "library_widget_KexiDBComboBox" << "library_widget_KexiDBCheckBox" << "library_widget_KexiDBImageBox" << QString() //sep << "library_widget_KexiDBPushButton" << QString() //sep << "library_widget_KexiFrame" << "library_widget_QGroupBox" << "library_widget_KFDTabWidget" << "library_widget_Line" << QString() //sep #ifdef CAN_USE_QTWEBKIT << "library_widget_WebBrowserWidget" #endif #ifdef CAN_USE_MARBLE << "library_widget_MapBrowserWidget" #endif << "library_widget_KexiDBSlider" << "library_widget_KexiDBProgressBar" << "library_widget_KexiDBCommandLinkButton" << "library_widget_KexiDBDatePicker" << QString() //sep ; KexiMainWindowIface *win = KexiMainWindowIface::global(); foreach( const QString& actionName_, formActions ) { QAction *a; const QString actionName(actionName_.startsWith(':') ? actionName_.mid(1) : actionName_); if (actionName.isEmpty()) { a = new QAction(this); a->setSeparator(true); } else { a = d->widgetActionGroup->action(actionName); } if (actionName_.startsWith(':')) { // icon only KexiSmallToolButton *btn = new KexiSmallToolButton(a, win->toolBar("form")); btn->setToolButtonStyle(Qt::ToolButtonIconOnly); win->appendWidgetToToolbar("form", btn); } else { win->addToolBarAction("form", a); } } QSet iconOnlyActions; const QList actions( d->collection->actions() ); foreach( QAction *a, actions ) { if (iconOnlyActions.contains(a->objectName())) { // icon only KexiSmallToolButton *btn = new KexiSmallToolButton(a, win->toolBar("form")); btn->setToolButtonStyle(Qt::ToolButtonIconOnly); win->appendWidgetToToolbar("form", btn); win->setWidgetVisibleInToolbar(btn, true); } else { win->addToolBarAction("form", a); } } } } void KexiFormManager::slotWidgetCreatedByFormsLibrary(QWidget* widget) { QList _signals(KexiUtils::methodsForMetaObject( widget->metaObject(), QMetaMethod::Signal)); if (!_signals.isEmpty()) { QByteArray handleDragMoveEventSignal = "handleDragMoveEvent(QDragMoveEvent*)"; QByteArray handleDropEventSignal = "handleDropEvent(QDropEvent*)"; KexiFormView *formView = KDbUtils::findParent(widget); foreach(const QMetaMethod& method, _signals) { if (0 == qstrcmp(method.methodSignature(), handleDragMoveEventSignal)) { qDebug() << method.methodSignature(); if (formView) { connect(widget, SIGNAL(handleDragMoveEvent(QDragMoveEvent*)), formView, SLOT(slotHandleDragMoveEvent(QDragMoveEvent*))); } } else if (0 == qstrcmp(method.methodSignature(), handleDropEventSignal)) { qDebug() << method.methodSignature(); if (formView) { connect(widget, SIGNAL(handleDropEvent(QDropEvent*)), formView, SLOT(slotHandleDropEvent(QDropEvent*))); } } } } } void KexiFormManager::slotWidgetActionToggled(const QByteArray& action) { KexiFormView* fv = activeFormViewWidget(); if (fv) { fv->form()->enterWidgetInsertingState(action); } } KFormDesigner::WidgetLibrary* KexiFormManager::library() const { return d->lib; } QAction* KexiFormManager::action(const char* name) { KActionCollection *col = d->part->actionCollectionForMode(Kexi::DesignViewMode); if (!col) return 0; QString n(translateName(name)); QAction *a = col->action(n); if (a) return a; if (activeFormViewWidget()) { a = KexiMainWindowIface::global()->actionCollection()->action(n); if (a) return a; } return d->collection->action(name); } KexiFormView* KexiFormManager::activeFormViewWidget() const { KexiWindow *currentWindow = KexiMainWindowIface::global()->currentWindow(); if (!currentWindow) return 0; KexiView *currentView = currentWindow->selectedView(); KFormDesigner::Form *form; if (!currentView || currentView->viewMode()!=Kexi::DesignViewMode || !dynamic_cast(currentView) || !(form = dynamic_cast(currentView)->form()) ) { return 0; } KexiDBForm *dbform = dynamic_cast(form->formWidget()); KexiFormScrollView *scrollViewWidget = dynamic_cast(dbform->dataAwareObject()); if (!scrollViewWidget) return 0; return dynamic_cast(scrollViewWidget->parent()); } void KexiFormManager::enableAction(const char* name, bool enable) { KexiFormView* formViewWidget = activeFormViewWidget(); if (!formViewWidget) return; formViewWidget->setAvailable(translateName(name).toLatin1(), enable); } void KexiFormManager::setFormDataSource(const QString& pluginId, const QString& name) { KexiFormView* formViewWidget = activeFormViewWidget(); if (!formViewWidget) return; KexiDBForm* formWidget = dynamic_cast(formViewWidget->form()->widget()); if (!formWidget) return; QString oldDataSourcePartClass(formWidget->dataSourcePluginId()); QString oldDataSource(formWidget->dataSource()); if (pluginId != oldDataSourcePartClass || name != oldDataSource) { QHash propValues; propValues.insert("dataSource", name); propValues.insert("dataSourcePartClass", pluginId); KFormDesigner::PropertyCommandGroup *group = new KFormDesigner::PropertyCommandGroup( xi18n("Set Form's Data Source to \"%1\"", name)); formViewWidget->form()->createPropertyCommandsInDesignMode( formWidget, propValues, group, true /*addToActiveForm*/); } } void KexiFormManager::setDataSourceFieldOrExpression( const QString& string, const QString& caption, KDbField::Type type) { KexiFormView* formViewWidget = activeFormViewWidget(); if (!formViewWidget) return; KPropertySet* set = formViewWidget->form()->propertySet(); if (!set->contains("dataSource")) return; set->property("dataSource").setValue(string); if (set->propertyValue("autoCaption", false).toBool()) { set->changePropertyIfExists("fieldCaptionInternal", caption); } if (set->propertyValue("widgetType").toString() == "Auto") { set->changePropertyIfExists("fieldTypeInternal", type); } } void KexiFormManager::insertAutoFields(const QString& sourcePartClass, const QString& sourceName, const QStringList& fields) { -#ifdef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT Q_UNUSED(sourcePartClass); Q_UNUSED(sourceName); Q_UNUSED(fields); #else KexiFormView* formViewWidget = activeFormViewWidget(); if (!formViewWidget || !formViewWidget->form() || !formViewWidget->form()->activeContainer()) return; formViewWidget->insertAutoFields(sourcePartClass, sourceName, fields, formViewWidget->form()->activeContainer()); #endif } void KexiFormManager::slotHistoryCommandExecuted(KFormDesigner::Command *command) { if (command->childCount() == 2) { KexiFormView* formViewWidget = activeFormViewWidget(); if (!formViewWidget) return; KexiDBForm* formWidget = dynamic_cast(formViewWidget->form()->widget()); if (!formWidget) return; const KFormDesigner::PropertyCommand* pc1 = dynamic_cast(command->child(0)); const KFormDesigner::PropertyCommand* pc2 = dynamic_cast(command->child(1)); if (pc1 && pc2 && pc1->propertyName() == "dataSource" && pc2->propertyName() == "dataSourcePartClass") { const QHash::const_iterator it1(pc1->oldValues().constBegin()); const QHash::const_iterator it2(pc2->oldValues().constBegin()); if (it1.key() == formWidget->objectName() && it2.key() == formWidget->objectName()) d->part->dataSourcePage()->setFormDataSource( formWidget->dataSourcePluginId(), formWidget->dataSource()); } } } void KexiFormManager::showFormUICode() { #ifdef KEXI_DEBUG_GUI KexiFormView* formView = activeFormViewWidget(); if (!formView) return; formView->form()->resetInlineEditor(); QString uiCode; const int indent = 2; if (!KFormDesigner::FormIO::saveFormToString(formView->form(), uiCode, indent)) { //! @todo show err? return; } KPageDialog uiCodeDialog; uiCodeDialog.setFaceType(KPageDialog::Tabbed); uiCodeDialog.setModal(true); uiCodeDialog.setWindowTitle(xi18nc("@title:window", "Form's UI Code")); uiCodeDialog.setButtons(QDialog::Close); uiCodeDialog.resize(700, 600); KTextEdit *currentUICodeDialogEditor = new KTextEdit(&uiCodeDialog); uiCodeDialog.addPage(currentUICodeDialogEditor, xi18n("Current")); currentUICodeDialogEditor->setReadOnly(true); QFont f(currentUICodeDialogEditor->font()); f.setFamily("courier"); currentUICodeDialogEditor->setFont(f); KTextEdit *originalUICodeDialogEditor = new KTextEdit(&uiCodeDialog); uiCodeDialog.addPage(originalUICodeDialogEditor, xi18n("Original")); originalUICodeDialogEditor->setReadOnly(true); originalUICodeDialogEditor->setFont(f); currentUICodeDialogEditor->setPlainText(uiCode); //indent and set our original doc as well: QDomDocument doc; doc.setContent(formView->form()->m_recentlyLoadedUICode); originalUICodeDialogEditor->setPlainText(doc.toString(indent)); uiCodeDialog.exec(); #endif } void KexiFormManager::slotAssignAction() { KexiFormView* formView = activeFormViewWidget(); if (!formView) return; KFormDesigner::Form *form = formView->form(); KexiDBForm *dbform = 0; if (form->mode() != KFormDesigner::Form::DesignMode || !(dbform = dynamic_cast(form->formWidget()))) { return; } KPropertySet* set = form->propertySet(); KexiFormEventAction::ActionData data; const KProperty &onClickActionProp = set->property("onClickAction"); if (!onClickActionProp.isNull()) data.string = onClickActionProp.value().toString(); const KProperty &onClickActionOptionProp = set->property("onClickActionOption"); if (!onClickActionOptionProp.isNull()) data.option = onClickActionOptionProp.value().toString(); KexiFormScrollView *scrollViewWidget = dynamic_cast(dbform->dataAwareObject()); if (!scrollViewWidget) return; KexiFormView* formViewWidget = dynamic_cast(scrollViewWidget->parent()); if (!formViewWidget) return; KexiActionSelectionDialog dlg(dbform, data, set->property("objectName").value().toString()); if (dlg.exec() == QDialog::Accepted) { data = dlg.currentAction(); //update property value set->changeProperty("onClickAction", data.string); set->changeProperty("onClickActionOption", data.option); } } void KexiFormManager::slotPointerClicked() { KexiFormView* formView = activeFormViewWidget(); if (!formView) return; formView->form()->enterWidgetSelectingState(); } QString KexiFormManager::translateName(const char* name) const { QString n(QString::fromLatin1(name)); // translate to our name space: if (n.startsWith("align_") || n.startsWith("adjust_") || n == "format_raise" || n == "format_lower" || n == "taborder") { n.prepend("formpart_"); } return n; } diff --git a/kexi/plugins/forms/kexiformpart.cpp b/kexi/plugins/forms/kexiformpart.cpp index de5d86f70fd..b8afeb24dc9 100644 --- a/kexi/plugins/forms/kexiformpart.cpp +++ b/kexi/plugins/forms/kexiformpart.cpp @@ -1,395 +1,395 @@ /* This file is part of the KDE project Copyright (C) 2004 Lucijan Busch Copyright (C) 2004 Cedric Pasteur Copyright (C) 2005 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 "kexiformpart.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/kexidbform.h" #include "kexiformscrollview.h" #include "kexiformmanager.h" #include "kexidatasourcepage.h" #include #include #include #include #include #include #include #include #include #include //! @todo #define KEXI_SHOW_SPLITTER_WIDGET //! @internal class KexiFormPart::Private { public: Private() { } ~Private() { delete static_cast(widgetTreeWidget); delete static_cast(dataSourcePage); } QPointer dataSourcePage; QPointer widgetTree; QPointer widgetTreeWidget; KexiDataSourceComboBox *dataSourceCombo; }; KexiFormPart::KexiFormPart(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.", "form"), xi18nc("tooltip", "Create new form"), xi18nc("what's this", "Creates new form."), l) , d(new Private) { setInternalPropertyValue("newObjectsAreDirty", true); // Only create form manager if it's not yet created. // KexiReportPart could have created it already. KexiFormManager::self()->init(this, d->widgetTree); // this should create KexiFormManager singleton } KexiFormPart::~KexiFormPart() { delete d; } void KexiFormPart::initPartActions() { } void KexiFormPart::initInstanceActions() { //connect actions provided by widget factories createSharedAction(Kexi::DesignViewMode, xi18n("Clear Widget Contents"), koIconName("edit-clear"), QKeySequence(), "formpart_clear_contents"); createSharedAction(Kexi::DesignViewMode, xi18n("Edit Tab Order..."), koIconName("tab_order"), QKeySequence(), "formpart_taborder"); //! @todo createSharedAction(Kexi::DesignViewMode, xi18n("Edit Pixmap Collection"), koIconName("icons"), 0, "formpart_pixmap_collection"); //! @todo createSharedAction(Kexi::DesignViewMode, xi18n("Edit Form Connections"), koIconName("connections"), 0, "formpart_connections"); createSharedAction(Kexi::DesignViewMode, xi18n("Bring Widget to Front"), koIconName("raise"), QKeySequence(), "formpart_format_raise"); createSharedAction(Kexi::DesignViewMode, xi18n("Send Widget to Back"), koIconName("lower"), QKeySequence(), "formpart_format_lower"); #ifdef KEXI_SHOW_UNFINISHED action = createSharedAction(Kexi::DesignViewMode, futureI18n("Other Widgets"), QString(), QKeySequence(), "other_widgets_menu", "KActionMenu"); #endif QAction *action = createSharedAction(Kexi::DesignViewMode, xi18n("Align Widgets Position"), koIconName("aoleft"), QKeySequence(), "formpart_align_menu", "KActionMenu"); KActionMenu *menu = static_cast(action); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Left"), koIconName("aoleft"), QKeySequence(), "formpart_align_to_left")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Right"), koIconName("aoright"), QKeySequence(), "formpart_align_to_right")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Top"), koIconName("aotop"), QKeySequence(), "formpart_align_to_top")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Bottom"), koIconName("aobottom"), QKeySequence(), "formpart_align_to_bottom")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Grid"), koIconName("aopos2grid"), QKeySequence(), "formpart_align_to_grid")); action = createSharedAction(Kexi::DesignViewMode, xi18n("Adjust Widgets Size"), koIconName("aogrid"), QKeySequence(), "formpart_adjust_size_menu", "KActionMenu"); menu = static_cast(action); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Fit"), koIconName("aofit"), QKeySequence(), "formpart_adjust_to_fit")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Grid"), koIconName("aogrid"), QKeySequence(), "formpart_adjust_size_grid")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Shortest"), koIconName("aoshortest"), QKeySequence(), "formpart_adjust_height_small")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Tallest"), koIconName("aotallest"), QKeySequence(), "formpart_adjust_height_big")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Narrowest"), koIconName("aonarrowest"), QKeySequence(), "formpart_adjust_width_small")); menu->addAction(createSharedAction(Kexi::DesignViewMode, xi18n("To Widest"), koIconName("aowidest"), QKeySequence(), "formpart_adjust_width_big")); } KexiWindowData* KexiFormPart::createWindowData(KexiWindow* window) { return new KexiFormPartTempData(window); } KexiView* KexiFormPart::createView(QWidget *parent, KexiWindow* window, KexiPart::Item *item, Kexi::ViewMode viewMode, QMap*) { Q_ASSERT(item); Q_UNUSED(window); Q_UNUSED(viewMode); qDebug(); KexiMainWindowIface *win = KexiMainWindowIface::global(); if (!win || !win->project() || !win->project()->dbConnection()) return 0; KexiFormView *view = new KexiFormView(parent, win->project()->dbConnection()); view->setObjectName(item->name().toLatin1()); return view; } #ifndef KEXI_NO_FORM_DATASOURCE_WIZARD void KexiFormPart::generateForm(KDbFieldList *list, QDomDocument &domDoc) { //this form generates a .ui from KDbFieldList list //basically that is a Label and a LineEdit for each field domDoc = QDomDocument("UI"); QDomElement uiElement = domDoc.createElement("UI"); domDoc.appendChild(uiElement); uiElement.setAttribute("version", "3.1"); uiElement.setAttribute("stdsetdef", 1); QDomElement baseClass = domDoc.createElement("class"); uiElement.appendChild(baseClass); QDomText baseClassV = domDoc.createTextNode("QWidget"); baseClass.appendChild(baseClassV); QDomElement baseWidget = domDoc.createElement("widget"); baseWidget.setAttribute("class", "QWidget"); int y = 0; for (unsigned int i = 0; i < list->fieldCount(); i++) { QDomElement lclass = domDoc.createElement("widget"); baseWidget.appendChild(lclass); lclass.setAttribute("class", "QLabel"); QDomElement lNameProperty = domDoc.createElement("property"); lNameProperty.setAttribute("name", "name"); QDomElement lType = domDoc.createElement("cstring"); QDomText lClassN = domDoc.createTextNode(QString("l%1").arg(list->field(i)->name())); lType.appendChild(lClassN); lNameProperty.appendChild(lType); lclass.appendChild(lNameProperty); QDomElement gNameProperty = domDoc.createElement("property"); gNameProperty.setAttribute("name", "geometry"); QDomElement lGType = domDoc.createElement("rect"); QDomElement lx = domDoc.createElement("x"); QDomText lxV = domDoc.createTextNode("10"); lx.appendChild(lxV); QDomElement ly = domDoc.createElement("y"); QDomText lyV = domDoc.createTextNode(QString::number(y + 10)); ly.appendChild(lyV); QDomElement lWidth = domDoc.createElement("width"); QDomText lWidthV = domDoc.createTextNode("100"); lWidth.appendChild(lWidthV); QDomElement lHeight = domDoc.createElement("height"); QDomText lHeightV = domDoc.createTextNode("20"); lHeight.appendChild(lHeightV); lGType.appendChild(lx); lGType.appendChild(ly); lGType.appendChild(lWidth); lGType.appendChild(lHeight); gNameProperty.appendChild(lGType); lclass.appendChild(gNameProperty); QDomElement tNameProperty = domDoc.createElement("property"); tNameProperty.setAttribute("name", "text"); QDomElement lTType = domDoc.createElement("string"); QDomText lTextV = domDoc.createTextNode(list->field(i)->name()); lTType.appendChild(lTextV); tNameProperty.appendChild(lTType); lclass.appendChild(tNameProperty); ///line edit! QDomElement vclass = domDoc.createElement("widget"); baseWidget.appendChild(vclass); vclass.setAttribute("class", "QLineEdit"); QDomElement vNameProperty = domDoc.createElement("property"); vNameProperty.setAttribute("name", "name"); QDomElement vType = domDoc.createElement("cstring"); QDomText vClassN = domDoc.createTextNode(list->field(i)->name()); vType.appendChild(vClassN); vNameProperty.appendChild(vType); vclass.appendChild(vNameProperty); QDomElement vgNameProperty = domDoc.createElement("property"); vgNameProperty.setAttribute("name", "geometry"); QDomElement vGType = domDoc.createElement("rect"); QDomElement vx = domDoc.createElement("x"); QDomText vxV = domDoc.createTextNode("110"); vx.appendChild(vxV); QDomElement vy = domDoc.createElement("y"); QDomText vyV = domDoc.createTextNode(QString::number(y + 10)); vy.appendChild(vyV); QDomElement vWidth = domDoc.createElement("width"); QDomText vWidthV = domDoc.createTextNode("200"); vWidth.appendChild(vWidthV); QDomElement vHeight = domDoc.createElement("height"); QDomText vHeightV = domDoc.createTextNode("20"); vHeight.appendChild(vHeightV); vGType.appendChild(vx); vGType.appendChild(vy); vGType.appendChild(vWidth); vGType.appendChild(vHeight); vgNameProperty.appendChild(vGType); vclass.appendChild(vgNameProperty); y += 20; } QDomElement lNameProperty = domDoc.createElement("property"); lNameProperty.setAttribute("name", "name"); QDomElement lType = domDoc.createElement("cstring"); QDomText lClassN = domDoc.createTextNode("DBForm"); lType.appendChild(lClassN); lNameProperty.appendChild(lType); baseWidget.appendChild(lNameProperty); QDomElement wNameProperty = domDoc.createElement("property"); wNameProperty.setAttribute("name", "geometry"); QDomElement wGType = domDoc.createElement("rect"); QDomElement wx = domDoc.createElement("x"); QDomText wxV = domDoc.createTextNode("0"); wx.appendChild(wxV); QDomElement wy = domDoc.createElement("y"); QDomText wyV = domDoc.createTextNode("0"); wy.appendChild(wyV); QDomElement wWidth = domDoc.createElement("width"); QDomText wWidthV = domDoc.createTextNode("340"); wWidth.appendChild(wWidthV); QDomElement wHeight = domDoc.createElement("height"); QDomText wHeightV = domDoc.createTextNode(QString::number(y + 30)); wHeight.appendChild(wHeightV); wGType.appendChild(wx); wGType.appendChild(wy); wGType.appendChild(wWidth); wGType.appendChild(wHeight); wNameProperty.appendChild(wGType); baseWidget.appendChild(wNameProperty); uiElement.appendChild(baseWidget); } #endif KLocalizedString KexiFormPart::i18nMessage( const QString& englishMessage, KexiWindow* window) const { Q_UNUSED(window); if (englishMessage == "Design of object %1 has been modified.") return kxi18nc(I18NC_NOOP("@info", "Design of form %1 has been modified.")); if (englishMessage == "Object %1 already exists.") return kxi18nc(I18NC_NOOP("@info", "Form %1 already exists.")); return Part::i18nMessage(englishMessage, window); } KexiDataSourcePage* KexiFormPart::dataSourcePage() const { return d->dataSourcePage; } KFormDesigner::WidgetTreeWidget* KexiFormPart::widgetTreePage() const { return d->widgetTree; } void KexiFormPart::setupCustomPropertyPanelTabs(QTabWidget *tab) { if (!d->dataSourcePage) { d->dataSourcePage = new KexiDataSourcePage(0); d->dataSourcePage->setObjectName("dataSourcePage"); connect(d->dataSourcePage, SIGNAL(jumpToObjectRequested(QString,QString)), KexiMainWindowIface::global()->thisWidget(), SLOT(highlightObject(QString,QString))); connect(d->dataSourcePage, SIGNAL(formDataSourceChanged(QString,QString)), KexiFormManager::self(), SLOT(setFormDataSource(QString,QString))); connect(d->dataSourcePage, SIGNAL(dataSourceFieldOrExpressionChanged(QString,QString,KDbField::Type)), KexiFormManager::self(), SLOT(setDataSourceFieldOrExpression(QString,QString,KDbField::Type))); -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT connect(d->dataSourcePage, SIGNAL(insertAutoFields(QString,QString,QStringList)), KexiFormManager::self(), SLOT(insertAutoFields(QString,QString,QStringList))); #endif } KexiProject *prj = KexiMainWindowIface::global()->project(); d->dataSourcePage->setProject(prj); tab->addTab(d->dataSourcePage, koIcon("server-database"), QString()); tab->setTabToolTip(tab->indexOf(d->dataSourcePage), xi18n("Data Source")); if (!d->widgetTreeWidget) { d->widgetTreeWidget = new QWidget; QVBoxLayout *lyr = new QVBoxLayout(d->widgetTreeWidget); lyr->setContentsMargins(2, 2, 2, 2); d->widgetTree = new KFormDesigner::WidgetTreeWidget; d->widgetTree->setObjectName("KexiFormPart:WidgetTreeWidget"); lyr->addWidget(d->widgetTree); } tab->addTab(d->widgetTreeWidget, koIcon("widgets"), QString()); tab->setTabToolTip(tab->indexOf(d->widgetTreeWidget), xi18n("Widgets")); } //---------------- KexiFormPartTempData::KexiFormPartTempData(QObject* parent) : KexiWindowData(parent) { } KexiFormPartTempData::~KexiFormPartTempData() { } diff --git a/kexi/plugins/forms/kexiformview.cpp b/kexi/plugins/forms/kexiformview.cpp index 1a4ee40e9ca..1999b57ff8a 100644 --- a/kexi/plugins/forms/kexiformview.cpp +++ b/kexi/plugins/forms/kexiformview.cpp @@ -1,1277 +1,1277 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-2011 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 "kexiformview.h" #include #include #include #include #include #include #include #include #include //! @todo KEXI3 Port #include #include #include #include #include "widgets/kexidbform.h" #include "kexiformscrollview.h" #include "kexidatasourcepage.h" #include "kexiformmanager.h" #include "widgets/kexidbautofield.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //! @todo #define KEXI_SHOW_SPLITTER_WIDGET class KexiFormView::Private { public: Private() : resizeMode(KexiFormView::ResizeDefault) , query(0) , queryIsOwned(false) , cursor(0) { } KexiDBForm *dbform; KexiFormScrollView *scrollView; /*! Database cursor used for data retrieving. It is shared between subsequent Data view sessions (just reopened on switch), but deleted and recreated from scratch when form's "dataSource" property changed since last form viewing (d->previousDataSourceString is used for that). */ QString previousDataSourceString; int resizeMode; KDbQuerySchema* query; /*! True, if d->query is created as temporary object within this form. If user selected an existing, predefined (stored) query, d->queryIsOwned will be false, so the query object will not be destroyed. */ bool queryIsOwned; KDbCursor *cursor; /*! For new (empty) forms only: Our form's area will be resized more than once. We will resize form widget itself later (in resizeEvent()). */ int delayedFormContentsResizeOnShow; //! Used in setFocusInternal() QPointer setFocusInternalOnce; -#ifndef KEXI_NO_AUTOFIELD_WIDGET +#ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT /*! Stores geometry of widget recently inserted using insertAutoFields() method. having this information, we'r eable to compute position for a newly inserted widget in insertAutoFields() is such position has not been specified. (the position is specified when a widget is inserted with mouse drag & dropping but not with clicking of 'Insert fields' button from Data Source pane) */ QRect widgetGeometryForRecentInsertAutoFields; #endif //! Cached form pointer QPointer form; }; KexiFormView::KexiFormView(QWidget *parent, bool dbAware) : KexiDataAwareView(parent) , d(new Private) { Q_UNUSED(dbAware); d->delayedFormContentsResizeOnShow = 0; //! @todo remove? setSortedProperties(true); d->scrollView = new KexiFormScrollView( // will be added to layout this, viewMode() == Kexi::DataViewMode); // in KexiDataAwareView::init() initForm(); if (viewMode() == Kexi::DesignViewMode) { connect(form(), SIGNAL(propertySetSwitched()), this, SLOT(slotPropertySetSwitched())); connect(form(), SIGNAL(modified(bool)), this, SLOT(setDirty(bool))); connect(d->scrollView, SIGNAL(resized()), this, SLOT(setFormModified())); connect(d->dbform, SIGNAL(handleDragMoveEvent(QDragMoveEvent*)), this, SLOT(slotHandleDragMoveEvent(QDragMoveEvent*))); connect(d->dbform, SIGNAL(handleDropEvent(QDropEvent*)), this, SLOT(slotHandleDropEvent(QDropEvent*))); // action stuff plugSharedAction("formpart_taborder", form(), SLOT(editTabOrder())); plugSharedAction("formpart_adjust_size", form(), SLOT(adjustWidgetSize())); //! @todo add formpart_pixmap_collection action //! @todo add formpart_connections action plugSharedAction("edit_copy", form(), SLOT(copyWidget())); plugSharedAction("edit_cut", form(), SLOT(cutWidget())); plugSharedAction("edit_paste", form(), SLOT(pasteWidget())); plugSharedAction("edit_delete", form(), SLOT(deleteWidget())); plugSharedAction("edit_select_all", form(), SLOT(selectAll())); plugSharedAction("formpart_clear_contents", form(), SLOT(clearWidgetContent())); plugSharedAction("edit_undo", form(), SLOT(undo())); plugSharedAction("edit_redo", form(), SLOT(redo())); plugSharedAction("formpart_format_raise", form(), SLOT(bringWidgetToFront())); plugSharedAction("formpart_format_lower", form(), SLOT(sendWidgetToBack())); plugSharedAction("other_widgets_menu", form(), 0); setAvailable("other_widgets_menu", true); plugSharedAction("formpart_align_menu", form(), 0); plugSharedAction("formpart_align_to_left", form(), SLOT(alignWidgetsToLeft())); plugSharedAction("formpart_align_to_right", form(), SLOT(alignWidgetsToRight())); plugSharedAction("formpart_align_to_top", form(), SLOT(alignWidgetsToTop())); plugSharedAction("formpart_align_to_bottom", form(), SLOT(alignWidgetsToBottom())); plugSharedAction("formpart_align_to_grid", form(), SLOT(alignWidgetsToGrid())); plugSharedAction("formpart_adjust_size_menu", form(), 0); plugSharedAction("formpart_adjust_to_fit", form(), SLOT(adjustWidgetSize())); plugSharedAction("formpart_adjust_size_grid", form(), SLOT(adjustSizeToGrid())); plugSharedAction("formpart_adjust_height_small", form(), SLOT(adjustHeightToSmall())); plugSharedAction("formpart_adjust_height_big", form(), SLOT(adjustHeightToBig())); plugSharedAction("formpart_adjust_width_small", form(), SLOT(adjustWidthToSmall())); plugSharedAction("formpart_adjust_width_big", form(), SLOT(adjustWidthToBig())); plugSharedAction("format_font", form(), SLOT(changeFont())); // - setup local actions QList viewActions; QAction* a; a = form()->action("edit_undo"); a->setProperty("iconOnly", true); viewActions << a; a = form()->action("edit_redo"); a->setProperty("iconOnly", true); viewActions << a; setViewActions(viewActions); } KexiDataAwareView::init(d->scrollView, d->scrollView, d->scrollView, /* skip data-awarness if design mode */ viewMode() == Kexi::DesignViewMode); connect(this, SIGNAL(focus(bool)), this, SLOT(slotFocus(bool))); } KexiFormView::~KexiFormView() { if (d->cursor) { KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); conn->deleteCursor(d->cursor); d->cursor = 0; } deleteQuery(); propertySetSwitched(); delete d; } void KexiFormView::deleteQuery() { if (d->cursor) { KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); conn->deleteCursor(d->cursor); d->cursor = 0; } if (d->queryIsOwned) { delete d->query; } else { //! @todo remove this shared query from listened queries list } d->query = 0; } void KexiFormView::setForm(KFormDesigner::Form *f) { if (viewMode() == Kexi::DataViewMode) tempData()->previewForm = f; else tempData()->form = f; d->form = f; } void KexiFormView::initForm() { d->dbform = new KexiDBForm(d->scrollView->widget(), d->scrollView); if (viewMode() == Kexi::DataViewMode) { d->scrollView->setWidget(d->dbform); } else { d->scrollView->setMainAreaWidget(d->dbform); } d->dbform->setObjectName( xi18nc("A prefix for identifiers of forms. Based on that, identifiers such as " "form1, form2 are generated. " "This string can be used to refer the widget object as variables in programming " "languages or macros so it must _not_ contain white spaces and non latin1 characters, " "should start with lower case letter and if there are subsequent words, these should " "start with upper case letter. Example: smallCamelCase. " "Moreover, try to make this prefix as short as possible.", "form")); QPalette pal(d->dbform->palette()); pal.setBrush(QPalette::Window, palette().brush(QPalette::Window)); d->dbform->setPalette(pal); // avoid inheriting QPalette::Window role d->scrollView->setResizingEnabled(true); if (viewMode() == Kexi::DataViewMode) { d->scrollView->recordNavigator()->setRecordHandler(d->scrollView); QPalette pal(d->scrollView->viewport()->palette()); pal.setBrush(d->scrollView->viewport()->backgroundRole(), d->dbform->palette().brush(d->dbform->backgroundRole())); d->scrollView->viewport()->setPalette(pal); } setForm( new KFormDesigner::Form( KexiFormManager::self()->library(), viewMode() == Kexi::DataViewMode ? KFormDesigner::Form::DataMode : KFormDesigner::Form::DesignMode, *KexiMainWindowIface::global()->actionCollection(), *KexiFormManager::self()->widgetActionGroup()) ); form()->createToplevel(d->dbform, d->dbform); const bool newForm = window()->id() < 0; KDbFieldList *fields = 0; #ifndef KEXI_NO_FORM_DATASOURCE_WIZARD if (newForm) { // Show the form wizard if this is a new Form KexiDataSourceWizard *w = new KexiDataSourceWizard( KexiMainWindowIface::global()->thisWidget()); if (!w->exec()) fields = 0; else fields = w->fields(); delete w; } #endif if (fields) { #ifndef KEXI_NO_FORM_DATASOURCE_WIZARD QDomDocument dom; formPart()->generateForm(fields, dom); KFormDesigner::FormIO::loadFormFromDom(form(), d->dbform, dom); //! @todo handle errors #endif } else { loadForm(); } if (form()->autoTabStops()) form()->autoAssignTabStops(); //collect tab order information d->dbform->updateTabStopsOrder(form()); if (viewMode() == Kexi::DesignViewMode) { connect(form(), SIGNAL(widgetNameChanged(QByteArray,QByteArray)), this, SLOT(slotWidgetNameChanged(QByteArray,QByteArray))); connect(form(), SIGNAL(selectionChanged(QWidget*,KFormDesigner::Form::WidgetSelectionFlags)), this, SLOT(slotWidgetSelectionChanged(QWidget*,KFormDesigner::Form::WidgetSelectionFlags))); form()->selectWidget(form()->widget()); } else { form()->setMode(KFormDesigner::Form::DataMode); d->dbform->setMinimumSize(d->dbform->size()); // make vscrollbar appear when viewport is too small } d->scrollView->setForm(form()); d->scrollView->refreshContentsSize(); if (newForm && !fields) { /* Our form's area will be resized more than once. Let's resize form widget itself later. */ d->delayedFormContentsResizeOnShow = 3; } slotPropertySetSwitched(); // this prepares the data source page updateDataSourcePage(); if (!newForm && viewMode() == Kexi::DesignViewMode) { form()->clearUndoStack(); } } void KexiFormView::updateAutoFieldsDataSource() { //! @todo call this when form's data source is changed //update autofields: //-inherit captions //-inherit data types //(this data has not been stored in the form) QString dataSourceString(d->dbform->dataSource()); QString dataSourcePartClassString(d->dbform->dataSourcePluginId()); KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); KDbTableOrQuerySchema tableOrQuery( conn, dataSourceString.toLatin1(), dataSourcePartClassString == "org.kexi-project.table"); if (!tableOrQuery.table() && !tableOrQuery.query()) return; foreach (KFormDesigner::ObjectTreeItem *item, *form()->objectTree()->hash()) { KexiDBAutoField *afWidget = dynamic_cast(item->widget()); if (afWidget) { KDbQueryColumnInfo *colInfo = tableOrQuery.columnInfo(afWidget->dataSource()); if (colInfo) { afWidget->setColumnInfo(colInfo); } } } } void KexiFormView::updateValuesForSubproperties() { //! @todo call this when form's data source is changed //update autofields: //-inherit captions //-inherit data types //(this data has not been stored in the form) QString dataSourceString(d->dbform->dataSource()); QString dataSourcePartClassString(d->dbform->dataSourcePluginId()); KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); KDbTableOrQuerySchema tableOrQuery( conn, dataSourceString.toLatin1(), dataSourcePartClassString == "org.kexi-project.table"); if (!tableOrQuery.table() && !tableOrQuery.query()) return; foreach (KFormDesigner::ObjectTreeItem *item, *form()->objectTree()->hash()) { // (delayed) set values for subproperties //! @todo this could be at the KFD level, but KFD is going to be merged anyway with kexiforms, right? KFormDesigner::WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(item->widget()); if (subpropIface && subpropIface->subwidget() && item->subproperties()) { QWidget *subwidget = subpropIface->subwidget(); QHash* subprops = item->subproperties(); for (QHash::const_iterator subpropIt = subprops->constBegin(); subpropIt != subprops->constEnd(); ++subpropIt) { //qDebug() << "delayed setting of the subproperty: widget=" // << item->widget()->objectName() << " prop=" << subpropIt.key() << " val=" // << subpropIt.value(); QMetaProperty meta = KexiUtils::findPropertyWithSuperclasses( subwidget, qPrintable(subpropIt.key())); if (meta.isValid()) { // Special case: the property value of type enum (set) but is saved as a string list, // not as int, so we need to translate it to int. It's been created as such // by FormIO::readPropertyValue(). Example: "alignment" property. if (meta.isEnumType() && subpropIt.value().type() == QVariant::StringList) { const QByteArray keysCombined(subpropIt.value().toStringList().join("|").toLatin1()); subwidget->setProperty(subpropIt.key().toLatin1(), meta.enumerator().keysToValue(keysCombined.constData())); } else { subwidget->setProperty(subpropIt.key().toLatin1(), subpropIt.value()); } } }//for } } } //! Used in KexiFormView::loadForm() static void setUnsavedBLOBIdsForDataViewMode( QWidget* widget, const QHash& unsavedLocalBLOBsByName) { if (widget) { if (-1 != widget->metaObject()->indexOfProperty("pixmapId")) { const KexiBLOBBuffer::Id_t blobID = unsavedLocalBLOBsByName.value(widget->objectName().toLatin1()); if (blobID > 0) //! @todo KexiBLOBBuffer::Id_t is unsafe and unsupported by QVariant - fix it widget->setProperty( "pixmapId", int(blobID)); } const QList list(widget->findChildren()); if (list.isEmpty()) return; foreach(QWidget *w, list) { setUnsavedBLOBIdsForDataViewMode(w, unsavedLocalBLOBsByName); } } } void KexiFormView::loadForm() { //! @todo also load d->resizeMode //qDebug() << "Loading the form with id" << window()->id(); // If we are previewing the Form, use the tempData instead of the form stored in the db if (viewMode() == Kexi::DataViewMode && !tempData()->tempForm.isNull()) { KFormDesigner::FormIO::loadFormFromString(form(), d->dbform, &tempData()->tempForm); setUnsavedBLOBIdsForDataViewMode(d->dbform, tempData()->unsavedLocalBLOBsByName); updateAutoFieldsDataSource(); updateValuesForSubproperties(); return; } // normal load QString data; loadDataBlock(&data); KFormDesigner::FormIO::loadFormFromString(form(), d->dbform, &data); //"autoTabStops" property is loaded -set it within the form tree as well form()->setAutoTabStops(d->dbform->autoTabStops()); updateAutoFieldsDataSource(); updateValuesForSubproperties(); } void KexiFormView::slotPropertySetSwitched() { propertySetReloaded(); if (viewMode() == Kexi::DesignViewMode) { formPart()->dataSourcePage()->assignPropertySet(form()->propertySet()); } } tristate KexiFormView::beforeSwitchTo(Kexi::ViewMode mode, bool *dontStore) { Q_ASSERT(dontStore); if (mode != viewMode()) { if (viewMode() == Kexi::DataViewMode) { if (!d->scrollView->acceptRecordEditing()) return cancelled; d->scrollView->beforeSwitchView(); } else { //remember our pos tempData()->scrollViewContentsPos = QPoint(d->scrollView->horizontalScrollBar()->value(), d->scrollView->verticalScrollBar()->value()); } } // we don't store on db, but in our TempData *dontStore = true; if (isDirty() && (mode == Kexi::DataViewMode) && form()->objectTree()) { KexiFormPartTempData* temp = tempData(); if (!KFormDesigner::FormIO::saveFormToString(form(), temp->tempForm)) return false; //collect blobs from design mode by name for use in data view mode temp->unsavedLocalBLOBsByName.clear(); for (QHash::const_iterator it = temp->unsavedLocalBLOBs.constBegin(); it != temp->unsavedLocalBLOBs.constEnd(); ++it) { if (!it.key()) continue; temp->unsavedLocalBLOBsByName.insert(it.key()->objectName().toLatin1(), it.value()); } } return true; } tristate KexiFormView::afterSwitchFrom(Kexi::ViewMode mode) { if (mode == 0 || mode == Kexi::DesignViewMode) { if (window()->neverSaved()) { d->scrollView->refreshContentsSizeLater(); } } if (mode != 0 && mode != Kexi::DesignViewMode) { //preserve contents pos after switching to other view d->scrollView->horizontalScrollBar()->setValue(tempData()->scrollViewContentsPos.x()); d->scrollView->verticalScrollBar()->setValue(tempData()->scrollViewContentsPos.y()); } if ((mode == Kexi::DesignViewMode) && viewMode() == Kexi::DataViewMode) { // The form may have been modified, so we must recreate the preview delete d->dbform; // also deletes form() initForm(); //reset position d->scrollView->horizontalScrollBar()->setValue(0); d->scrollView->verticalScrollBar()->setValue(0); d->dbform->move(0, 0); } //update tab stops if needed if (viewMode() == Kexi::DataViewMode) { } else { //set "autoTabStops" property d->dbform->setAutoTabStops(form()->autoTabStops()); } if (viewMode() == Kexi::DataViewMode) { //TMP!! initDataSource(); //handle events for this form d->scrollView->setMainWidgetForEventHandling(d->dbform); //set focus on 1st focusable widget which has valid dataSource property set QList *orderedFocusWidgets = d->dbform->orderedFocusWidgets(); if (!orderedFocusWidgets->isEmpty()) { KexiUtils::unsetFocusWithReason(QApplication::focusWidget(), Qt::TabFocusReason); QWidget *widget = 0; foreach(widget, *orderedFocusWidgets) { KexiFormDataItemInterface *iface = dynamic_cast(widget); if (iface) { //qDebug() << iface->dataSource(); } if (iface && iface->columnInfo() && !iface->isReadOnly() /*! @todo add option for skipping autoincremented fields */ /* also skip autoincremented fields:*/ && !iface->columnInfo()->field->isAutoIncrement()) { break; } } if (!widget) //eventually, focus first available widget if nothing other is available widget = orderedFocusWidgets->first(); widget->setFocus(); KexiUtils::setFocusWithReason(widget, Qt::TabFocusReason); d->setFocusInternalOnce = widget; } if (d->query) d->scrollView->selectFirstRecord(); } //dirty only if it's a new object if (mode == Kexi::NoViewMode) setDirty(window()->partItem()->neverSaved()); updateActionsInternal(); return true; } KPropertySet* KexiFormView::propertySet() { return d->form->propertySet(); } KexiFormPartTempData* KexiFormView::tempData() const { return dynamic_cast(window()->data()); } KexiFormPart* KexiFormView::formPart() const { return dynamic_cast(part()); } void KexiFormView::initDataSource() { deleteQuery(); //! @todo also handle anonymous (not stored) queries provided as statements here KDbTableSchema *tableSchema = 0; KDbConnection *conn = 0; QStringList sources; bool forceReadOnlyDataSource = false; QString dataSourceString(d->dbform->dataSource()); bool ok = !dataSourceString.isEmpty(); if (ok) { //collect all data-aware widgets and create query schema d->scrollView->setMainDataSourceWidget(d->dbform); sources = d->scrollView->usedDataSources(); conn = KexiMainWindowIface::global()->project()->dbConnection(); QString dataSourcePartClassString(d->dbform->dataSourcePluginId()); if (dataSourcePartClassString.isEmpty() /*table type is the default*/ || dataSourcePartClassString == "org.kexi-project.table") { tableSchema = conn->tableSchema(dataSourceString); if (tableSchema) { /* We will build a _minimud-> query schema from selected table fields. */ d->query = new KDbQuerySchema(); d->queryIsOwned = true; if (dataSourcePartClassString.isEmpty()) d->dbform->setDataSourcePluginId("org.kexi-project.table"); //update for compatibility } } if (!tableSchema) { if (dataSourcePartClassString.isEmpty() /*also try to find a query (for compatibility with Kexi<=0.9)*/ || dataSourcePartClassString == "org.kexi-project.query") { //try to find predefined query schema. //Note: In general, we could not skip unused fields within this query because // it can have GROUP BY clause. //! @todo check if the query could have skipped unused fields (no GROUP BY, no joins, etc.) d->query = conn->querySchema(dataSourceString); d->queryIsOwned = false; ok = d->query != 0; if (ok && dataSourcePartClassString.isEmpty()) d->dbform->setDataSourcePluginId("org.kexi-project.query"); //update for compatibility // query results are read-only //! @todo There can be read-write queries, e.g. simple "SELECT * FROM...". Add a checking function to KexiDB. forceReadOnlyDataSource = true; } else { //no other classes are supported ok = false; } } } QSet invalidSources; if (ok) { KDbIndexSchema *pkey = tableSchema ? tableSchema->primaryKey() : 0; if (pkey) { //always add all fields from table's primary key // (don't worry about duplicates, unique list will be computed later) sources += pkey->names(); //qDebug() << "pkey added to data sources:" << pkey->names(); } //qDebug() << "sources=" << sources; int index = 0; for (QStringList::ConstIterator it = sources.constBegin(); it != sources.constEnd(); ++it, index++) { /*! @todo add expression support */ QString fieldName((*it).toLower()); //remove "tablename." if it was prepended if (tableSchema && fieldName.startsWith(tableSchema->name() + QLatin1Char('.'), Qt::CaseInsensitive)) fieldName.remove(0, tableSchema->name().length() + 1); //remove "queryname." if it was prepended if (!tableSchema && fieldName.startsWith(d->query->name() + QLatin1Char('.'), Qt::CaseInsensitive)) fieldName.remove(0, d->query->name().length() + 1); KDbField *f = tableSchema ? tableSchema->field(fieldName) : d->query->field(fieldName); if (!f) { /*! @todo show error */ //remove this widget from the set of data widgets in the provider /*! @todo fieldName is ok, but what about expressions? */ invalidSources.insert(fieldName); //qDebug() << "invalidSources+=" << index << " (" << (*it) << ")"; continue; } if (tableSchema) { if (!d->query->hasField(*f)) { //we're building a new query: add this field d->query->addField(f); } } } if (invalidSources.count() == sources.count()) { //all data sources are invalid! don't execute the query deleteQuery(); } else { qDebug() << d->query->parameters(); // like in KexiQueryView::executeQuery() QList params; { KexiUtils::WaitCursorRemover remover; params = KexiQueryParameters::getParameters(this, *conn->driver(), d->query, &ok); } if (ok) //input cancelled d->cursor = conn->executeQuery(d->query, params); } d->scrollView->invalidateDataSources(invalidSources, d->query); ok = d->cursor != 0; } if (!invalidSources.isEmpty()) d->dbform->updateTabStopsOrder(); if (ok) { //! @todo PRIMITIVE!! data setting: //! @todo KDbTableViewData is not a great name for data class here... rename/move? KDbTableViewData* data = new KDbTableViewData(d->cursor); if (forceReadOnlyDataSource) data->setReadOnly(true); data->preloadAllRecords(); ///*! @todo few backends return result count for free! - no need to reopen() */ // int resultCount = -1; // if (ok) { // resultCount = d->conn->resultCount(d->conn->selectStatement(*d->query)); // ok = d->cursor->reopen(); // } // if (ok) // ok = ! (!d->cursor->moveFirst() && d->cursor->error()); d->scrollView->setData(data, true /*owner*/); } else { d->scrollView->setData(0, false); } } void KexiFormView::setFormModified() { form()->setModified(true); } KDbObject* KexiFormView::storeNewData(const KDbObject& object, KexiView::StoreNewDataOptions options, bool *cancel) { Q_ASSERT(cancel); KDbObject *s = KexiView::storeNewData(object, options, cancel); //qDebug() << "new id:" << s->id(); if (!s || *cancel) { delete s; return 0; } 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 KexiFormView::storeData(bool dontAsk) { Q_UNUSED(dontAsk); //qDebug() << window()->partItem()->name() << "[" << window()->id() << "]"; //-- first, store local BLOBs, so identifiers can be updated //! @todo remove unused data stored previously KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); KDbTableSchema *blobsTable = conn->tableSchema("kexi__blobs"); if (!blobsTable) { //compatibility check for older Kexi project versions //! @todo show message about missing kexi__blobs? return false; } // Not all engines accept passing NULL to PKEY o_id, so we're omitting it. QStringList blobsFieldNamesWithoutID(blobsTable->names()); blobsFieldNamesWithoutID.pop_front(); KDbFieldList *blobsFieldsWithoutID = blobsTable->subList(blobsFieldNamesWithoutID); KDbPreparedStatement st = conn->prepareStatement( KDbPreparedStatement::InsertStatement, blobsFieldsWithoutID); if (!st.isValid()) { delete blobsFieldsWithoutID; //! @todo show message return false; } KexiBLOBBuffer *blobBuf = KexiBLOBBuffer::self(); KexiFormView *designFormView = dynamic_cast( window()->viewForMode(Kexi::DesignViewMode)); if (designFormView) { for (QHash::const_iterator it = tempData()->unsavedLocalBLOBs.constBegin(); it != tempData()->unsavedLocalBLOBs.constEnd(); ++it) { if (!it.key()) { qWarning() << "it.key()==0 !"; continue; } //qDebug() << "name=" << it.key()->objectName() << " dataID=" << it.value(); KexiBLOBBuffer::Handle h(blobBuf->objectForId(it.value(), /*!stored*/false)); if (!h) continue; //no BLOB assigned QString originalFileName(h.originalFileName()); QFileInfo fi(originalFileName); QString caption(fi.baseName().replace('_', ' ').simplified()); KDbPreparedStatementParameters parameters; parameters << h.data() << originalFileName << caption << h.mimeType() << int(/*! @todo unsafe */h.folderId()); if (!st.execute(parameters)) { delete blobsFieldsWithoutID; qWarning() << "execute error"; return false; } delete blobsFieldsWithoutID; blobsFieldsWithoutID = 0; const quint64 storedBLOBID = conn->lastInsertedAutoIncValue("o_id", "kexi__blobs"); if ((quint64) - 1 == storedBLOBID) { //! @todo show message? return false; } //qDebug() << "storedDataID=" << storedBLOBID; //! @todo unsafe - fix! h.setStoredWidthID((KexiBLOBBuffer::Id_t)storedBLOBID); //set widget's internal property so it can be saved... const QVariant oldStoredPixmapId(it.key()->property("storedPixmapId")); //! @todo KexiBLOBBuffer::Id_t is unsafe and unsupported by QVariant - fix! it.key()->setProperty("storedPixmapId", QVariant(int(storedBLOBID))); KFormDesigner::ObjectTreeItem *widgetItem = designFormView->form()->objectTree()->lookup(it.key()->objectName()); if (widgetItem) widgetItem->addModifiedProperty("storedPixmapId", oldStoredPixmapId); else qWarning() << "no" << widgetItem->name() << "widget found within a form"; } } //-- now, save form's XML QString data; if (!KFormDesigner::FormIO::saveFormToString(tempData()->form, data)) return false; if (!storeDataBlock(data)) return false; //all blobs are now saved tempData()->unsavedLocalBLOBs.clear(); tempData()->tempForm.clear(); return true; } //! @todo reuse the action stuff code #if 0 /// Action stuff ///////////////// void KexiFormView::slotWidgetSelected(KFormDesigner::Form *f, bool multiple) { if (f != form()) return; enableFormActions(); // Enable edit actions setAvailable("edit_copy", true); setAvailable("edit_cut", true); setAvailable("edit_clear", true); // 'Align Widgets' menu setAvailable("formpart_align_menu", multiple); setAvailable("formpart_align_to_left", multiple); setAvailable("formpart_align_to_right", multiple); setAvailable("formpart_align_to_top", multiple); setAvailable("formpart_align_to_bottom", multiple); setAvailable("formpart_adjust_size_menu", true); setAvailable("formpart_adjust_width_small", multiple); setAvailable("formpart_adjust_width_big", multiple); setAvailable("formpart_adjust_height_small", multiple); setAvailable("formpart_adjust_height_big", multiple); setAvailable("formpart_format_raise", true); setAvailable("formpart_format_lower", true); // If the widgets selected is a container, we enable layout actions if (!multiple) { KFormDesigner::ObjectTreeItem *item = f->objectTree()->lookup(f->selectedWidgets()->first()->name()); if (item && item->container()) multiple = true; } } void KexiFormView::slotFormWidgetSelected(KFormDesigner::Form *f) { if (f != form()) return; disableWidgetActions(); enableFormActions(); } void KexiFormView::slotNoFormSelected() // == form in preview mode { disableWidgetActions(); // Disable paste action setAvailable("edit_paste", false); setAvailable("edit_undo", false); setAvailable("edit_redo", false); // Disable 'Tools' actions setAvailable("formpart_pixmap_collection", false); setAvailable("formpart_connections", false); setAvailable("formpart_taborder", false); setAvailable("formpart_change_style", false); } void KexiFormView::enableFormActions() { // Enable 'Tools' actions setAvailable("formpart_pixmap_collection", true); setAvailable("formpart_connections", true); setAvailable("formpart_taborder", true); //! @todo KEXI3 Port this.. //! @todo setAvailable("edit_paste", KFormDesigner::FormManager::self()->isPasteEnabled()); } void KexiFormView::disableWidgetActions() { // Disable edit actions setAvailable("edit_copy", false); setAvailable("edit_cut", false); setAvailable("edit_clear", false); // Disable format functions setAvailable("formpart_align_menu", false); setAvailable("formpart_align_to_left", false); setAvailable("formpart_align_to_right", false); setAvailable("formpart_align_to_top", false); setAvailable("formpart_align_to_bottom", false); setAvailable("formpart_adjust_size_menu", false); setAvailable("formpart_adjust_width_small", false); setAvailable("formpart_adjust_width_big", false); setAvailable("formpart_adjust_height_small", false); setAvailable("formpart_adjust_height_big", false); setAvailable("formpart_format_raise", false); setAvailable("formpart_format_lower", false); } void KexiFormView::setUndoEnabled(bool enabled) { setAvailable("edit_undo", enabled); } void KexiFormView::setRedoEnabled(bool enabled) { setAvailable("edit_redo", enabled); } #endif //0 int KexiFormView::resizeMode() const { return d->resizeMode; } KFormDesigner::Form* KexiFormView::form() const { return d->form; } QSize KexiFormView::preferredSizeHint(const QSize& otherSize) { return (d->dbform->size() + QSize(d->scrollView->verticalScrollBar()->isVisible() ? d->scrollView->verticalScrollBar()->width()*3 / 2 : 10, d->scrollView->horizontalScrollBar()->isVisible() ? d->scrollView->horizontalScrollBar()->height()*3 / 2 : 10)) .expandedTo(KexiView::preferredSizeHint(otherSize)); } void KexiFormView::resizeEvent(QResizeEvent *e) { if (viewMode() == Kexi::DataViewMode) { d->scrollView->refreshContentsSizeLater(); } KexiView::resizeEvent(e); if (d->delayedFormContentsResizeOnShow > 0) { d->delayedFormContentsResizeOnShow--; d->dbform->resize(e->size() - QSize(30, 30)); } } void KexiFormView::contextMenuEvent(QContextMenuEvent *e) { // qDebug() << form()->selectedWidget() << form()->widget() << e->reason(); if (form()->selectedWidget() && form()->selectedWidget() == form()->widget() && e->reason() == QContextMenuEvent::Keyboard) { // Outer form area received context key. // Redirect the event to top-level form widget. // It will be received in Container::eventFilter(). e->accept(); QContextMenuEvent me(QContextMenuEvent::Keyboard, QPoint(-1, -1)); QApplication::sendEvent(form()->widget(), &me); return; } KexiView::contextMenuEvent(e); } void KexiFormView::setFocusInternal() { if (viewMode() == Kexi::DataViewMode) { if (d->dbform->focusWidget()) { //better-looking focus if (d->setFocusInternalOnce) { KexiUtils::setFocusWithReason(d->setFocusInternalOnce, Qt::OtherFocusReason); d->setFocusInternalOnce = 0; } else { //ok? SET_FOCUS_USING_REASON(d->dbform->focusWidget(), QFocusEvent::Other); } return; } } QWidget::setFocus(); } void KexiFormView::slotFocus(bool in) { Q_UNUSED(in); } void KexiFormView::updateDataSourcePage() { if (viewMode() == Kexi::DesignViewMode) { KPropertySet *set = form()->propertySet(); const QString dataSourcePartClass = set->propertyValue("dataSourcePartClass").toString(); const QString dataSource = set->propertyValue("dataSource").toString(); formPart()->dataSourcePage()->setFormDataSource(dataSourcePartClass, dataSource); } } void KexiFormView::slotHandleDragMoveEvent(QDragMoveEvent* e) { Q_UNUSED(e); /*! @todo KEXI3 Port kexidragobjects.cpp if (KexiFieldDrag::canDecode(e)) { e->setAccepted(true); }*/ } void KexiFormView::slotHandleDropEvent(QDropEvent* e) { -#ifdef KEXI_NO_AUTOFIELD_WIDGET - Q_UNUSED(e); -#else +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT const QWidget *targetContainerWidget = dynamic_cast(sender()); KFormDesigner::ObjectTreeItem *targetContainerWidgetItem = targetContainerWidget ? form()->objectTree()->lookup(targetContainerWidget->objectName()) : 0; if (targetContainerWidgetItem && targetContainerWidgetItem->container() && KexiFieldDrag::canDecode(e)) { QString sourcePartClass, sourceName; QStringList fields; if (!KexiFieldDrag::decode(e, &sourcePartClass, &sourceName, &fields)) return; insertAutoFields(sourcePartClass, sourceName, fields, targetContainerWidgetItem->container(), e->pos()); } +#else + Q_UNUSED(e); #endif } void KexiFormView::insertAutoFields(const QString& sourcePartClass, const QString& sourceName, const QStringList& fields, KFormDesigner::Container* targetContainer, const QPoint& _pos) { -#ifdef KEXI_NO_AUTOFIELD_WIDGET - Q_UNUSED(sourcePartClass); - Q_UNUSED(sourceName); - Q_UNUSED(fields); - Q_UNUSED(targetContainer); - Q_UNUSED(_pos); -#else +#ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT if (fields.isEmpty()) return; KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); KDbTableOrQuerySchema tableOrQuery(conn, sourceName.toLatin1(), sourcePartClass == "org.kexi-project.table"); if (!tableOrQuery.table() && !tableOrQuery.query()) { qWarning() << "no such table/query" << sourceName; return; } QPoint pos(_pos); //if pos is not specified, compute a new position: if (pos == QPoint(-1, -1)) { if (d->widgetGeometryForRecentInsertAutoFields.isValid()) { pos = d->widgetGeometryForRecentInsertAutoFields.bottomLeft() + QPoint(0, form()->gridSize()); } else { pos = QPoint(40, 40); //start here } } // there will be many actions performed, do not update property pane until all that's finished //! todo unnamed query columns are not supported QWidgetList widgetsToSelect; KFormDesigner::PropertyCommandGroup *group = new KFormDesigner::PropertyCommandGroup( fields.count() == 1 ? futureI18n("Insert AutoField widget") : futureI18n2("Insert %1 AutoField widgets", fields.count()) ); foreach(const QString& field, fields) { KDbQueryColumnInfo* column = tableOrQuery.columnInfo(field); if (!column) { qWarning() << "no such field" << field << "in table/query" << sourceName; continue; } //! todo add autolabel using field's caption or name KFormDesigner::InsertWidgetCommand *insertCmd = new KFormDesigner::InsertWidgetCommand( *targetContainer, //! @todo this is hardcoded! "KexiDBAutoField", //! @todo this name can be invalid for expressions: if so, fall back to a default class' prefix! pos, column->aliasOrName(), group ); insertCmd->redo(); KFormDesigner::ObjectTreeItem *newWidgetItem = form()->objectTree()->hash()->value(insertCmd->widgetName()); KexiDBAutoField* newWidget = newWidgetItem ? dynamic_cast(newWidgetItem->widget()) : 0; widgetsToSelect.append(newWidget); KFormDesigner::PropertyCommandGroup *subGroup = new KFormDesigner::PropertyCommandGroup( QString(), group); QHash propValues; propValues.insert("dataSource", column->aliasOrName()); propValues.insert("fieldTypeInternal", (int)column->field->type()); propValues.insert("fieldCaptionInternal", column->captionOrAliasOrName()); form()->createPropertyCommandsInDesignMode( newWidget, propValues, subGroup, false/*!addToActiveForm*/); subGroup->redo(); //set data source and caption //-we don't need to use PropertyCommand here beacause we don't need UNDO // for these single commands //resize again because autofield's type changed what can lead to changed sizeHint() QWidgetList list; list.append(newWidget); KFormDesigner::AdjustSizeCommand *adjustCommand = new KFormDesigner::AdjustSizeCommand( *form(), KFormDesigner::AdjustSizeCommand::SizeToFit, list, group); adjustCommand->redo(); if (newWidget) {//move position down for next widget pos.setY(pos.y() + newWidget->height() + form()->gridSize()); } } if (widgetsToSelect.last()) { //resize form if needed QRect oldFormRect(d->dbform->geometry()); QRect newFormRect(oldFormRect); newFormRect.setWidth(qMax(d->dbform->width(), widgetsToSelect.last()->geometry().right() + 1)); newFormRect.setHeight(qMax(d->dbform->height(), widgetsToSelect.last()->geometry().bottom() + 1)); if (newFormRect != oldFormRect) { //1. resize by hand d->dbform->setGeometry(newFormRect); //2. store information about resize (void)new KFormDesigner::PropertyCommand( *form(), d->dbform->objectName().toLatin1(), oldFormRect, newFormRect, "geometry", group); } //remember geometry of the last inserted widget d->widgetGeometryForRecentInsertAutoFields = widgetsToSelect.last()->geometry(); } //eventually, add entire command group to active form form()->addCommand(group); //qDebug() << *group; d->scrollView->widget()->update(); d->scrollView->refreshContentsSize(); //select all inserted widgets, if multiple if (widgetsToSelect.count() > 1) { form()->selectWidget(0); foreach (QWidget *w, widgetsToSelect) { form()->selectWidget(w, KFormDesigner::Form::AddToPreviousSelection | KFormDesigner::Form::DontRaise); } } //! @todo eventually, update property pane +#else + Q_UNUSED(sourcePartClass); + Q_UNUSED(sourceName); + Q_UNUSED(fields); + Q_UNUSED(targetContainer); + Q_UNUSED(_pos); #endif } void KexiFormView::setUnsavedLocalBLOB(QWidget *widget, KexiBLOBBuffer::Id_t id) { //! @todo if there already was data assigned, remember it should be dereferenced if (id == 0) tempData()->unsavedLocalBLOBs.remove(widget); else tempData()->unsavedLocalBLOBs.insert(widget, id); } void KexiFormView::updateActions(bool activated) { if (viewMode()==Kexi::DesignViewMode) { if (activated) { form()->emitActionSignals(); formPart()->widgetTreePage()->setForm(form()); } } KexiDataAwareView::updateActions(activated); updateActionsInternal(); } void KexiFormView::slotWidgetNameChanged(const QByteArray& oldname, const QByteArray& newname) { Q_UNUSED(oldname); Q_UNUSED(newname); //qDebug() << oldname << newname << form()->propertySet().propertyValue("objectName").toString(); KexiMainWindowIface::global()->updatePropertyEditorInfoLabel(); formPart()->dataSourcePage()->updateInfoLabelForPropertySet(form()->propertySet()); } void KexiFormView::slotWidgetSelectionChanged(QWidget *w, KFormDesigner::Form::WidgetSelectionFlags flags) { Q_UNUSED(w) Q_UNUSED(flags) updateActionsInternal(); } void KexiFormView::updateActionsInternal() { const QWidget* selectedWidget = form()->selectedWidget(); //qDebug() << selectedWidget << (viewMode()==Kexi::DesignViewMode) << widget_assign_action; QByteArray wClass; if (selectedWidget) { wClass = selectedWidget->metaObject()->className(); //qDebug() << wClass; } QAction *widget_assign_action = KexiFormManager::self()->action("widget_assign_action"); if (widget_assign_action) { widget_assign_action->setEnabled( viewMode()==Kexi::DesignViewMode && selectedWidget && (wClass == "QPushButton" || wClass == "KPushButton" || wClass == "KexiDBPushButton" || wClass == "KexiPushButton" || wClass == "KexiDBCommandLinkButton") ); } #ifdef KEXI_DEBUG_GUI QAction *show_form_ui_action = KexiFormManager::self()->action("show_form_ui"); if (show_form_ui_action) { show_form_ui_action->setEnabled(viewMode()==Kexi::DesignViewMode); } #endif } diff --git a/kexi/plugins/forms/widgets/kexidbsubform.cpp b/kexi/plugins/forms/widgets/kexidbsubform.cpp deleted file mode 100644 index 0536da96ed3..00000000000 --- a/kexi/plugins/forms/widgets/kexidbsubform.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2004 Cedric Pasteur - Copyright (C) 2004-2005 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 "kexidbsubform.h" -#include "kexidbform.h" -#include "kexiformmanager.h" -#include "kexiformview.h" -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -KexiDBSubForm::KexiDBSubForm(KFormDesigner::Form *parentForm, QWidget *parent) - : QScrollArea(parent), m_parentForm(parentForm), m_form(0), m_widget(0) -{ - setFrameStyle(QFrame::WinPanel | QFrame::Sunken); - QPalette pal(viewport()->palette()); - pal.setBrush(viewport()->backgroundRole(), pal.brush(QPalette::Mid)); - viewport()->setPalette(pal); -} - -/* -void -KexiDBSubForm::paintEvent(QPaintEvent *ev) -{ - QScrollView::paintEvent(ev); - QPainter p; - - setWFlags(WPaintUnclipped); - - QString txt("Subform"); - QFont f = font(); - f.setPointSize(f.pointSize() * 3); - QFontMetrics fm(f); - const int txtw = fm.width(txt), txth = fm.height(); - - p.begin(this, true); - p.setPen(black); - p.setFont(f); - p.drawText(width()/2, height()/2, txt, Qt::AlignCenter|Qt::AlignVCenter); - p.end(); - - clearWFlags( WPaintUnclipped ); -} -*/ - -void -KexiDBSubForm::setFormName(const QString &name) -{ - if (m_formName == name) - return; - - m_formName = name; //assign, even if the name points to nowhere - - if (name.isEmpty()) { - delete m_widget; - m_widget = 0; - //updateScrollBars(); - return; - } - - QWidget *pw = parentWidget(); - KexiFormView *view = 0; - QSet names; - while (pw) { - if (KexiUtils::objectIsA(pw, "KexiDBSubForm")) { - if (names.contains(pw->objectName())) { -//! @todo error message - return; // Be sure to don't run into a endless-loop cause of recursive subforms. - } - names.insert(pw->objectName()); - } else if (! view && KexiUtils::objectIsA(pw, "KexiFormView")) { - view = static_cast(pw); // we need a KexiFormView* - } - pw = pw->parentWidget(); - } - - if (!view || !view->window() || !KexiMainWindowIface::global()->project()->dbConnection()) - return; - - KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); - - // we check if there is a form with this name - int id; - if (true != KDb::idForObjectName(*conn, &id, name, KexiPart::FormObjectType)) { - return; - } - if ((id == 0) || (id == view->window()->id())) // == our form - return; // because of recursion when loading - - // we create the container widget - delete m_widget; - m_widget = new QWidget(viewport()); - m_widget->setObjectName("KexiDBSubForm_widget"); - m_widget->show(); - //addChild(m_widget); - m_form = new KFormDesigner::Form(m_parentForm); - m_form->setObjectName(QString("KFormDesigner::Form_") + objectName()); - m_form->createToplevel(m_widget); - - // and load the sub form - QString data; - tristate res = conn->loadDataBlock(id, &data, QString()); - if (res == true) - res = KFormDesigner::FormIO::loadFormFromString(m_form, m_widget, &data); - if (res != true) { - delete m_widget; - m_widget = 0; - //updateScrollBars(); - m_formName.clear(); - return; - } - m_form->setMode(KFormDesigner::Form::DataMode); - - // Install event filters on the whole newly created form - KFormDesigner::ObjectTreeItem *tree = m_parentForm->objectTree()->lookup(QObject::objectName()); - //KFormDesigner::installRecursiveEventFilter(this, tree->eventEater()); -} - diff --git a/kexi/plugins/forms/widgets/kexidbsubform.h b/kexi/plugins/forms/widgets/kexidbsubform.h deleted file mode 100644 index a81e3932192..00000000000 --- a/kexi/plugins/forms/widgets/kexidbsubform.h +++ /dev/null @@ -1,55 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2004 Cedric Pasteur - Copyright (C) 2004-2005 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 KEXIDBSUBFORM_H -#define KEXIDBSUBFORM_H - -#include "kexiformutils_export.h" -#include -#include - -//! @short A form embedded as a widget inside other form -class KEXIFORMUTILS_EXPORT KexiDBSubForm : public QScrollArea -{ - Q_OBJECT - Q_PROPERTY(QString formName READ formName WRITE setFormName) - -public: - KexiDBSubForm(KFormDesigner::Form *parentForm, QWidget *parent); - ~KexiDBSubForm() {} - - //! \return the name of the subform to display inside this widget - QString formName() const { - return m_formName; - } - - //! Sets the name of the subform to display inside this widget - void setFormName(const QString &name); - - //void paintEvent(QPaintEvent *ev); - -private: - KFormDesigner::Form *m_parentForm; - KFormDesigner::Form *m_form; - QWidget *m_widget; - QString m_formName; -}; - -#endif diff --git a/kexi/widget/dataviewcommon/kexidataprovider.cpp b/kexi/widget/dataviewcommon/kexidataprovider.cpp index 56385677d17..6d1d3c9a00b 100644 --- a/kexi/widget/dataviewcommon/kexidataprovider.cpp +++ b/kexi/widget/dataviewcommon/kexidataprovider.cpp @@ -1,266 +1,255 @@ /* This file is part of the KDE project Copyright (C) 2005-2006 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 "kexidataprovider.h" #include #include #include #include #include #include #include KexiFormDataProvider::KexiFormDataProvider() : KexiDataItemChangesListener() , m_mainWidget(0) , m_duplicatedItems(0) , m_disableFillDuplicatedDataItems(false) { } KexiFormDataProvider::~KexiFormDataProvider() { delete m_duplicatedItems; } void KexiFormDataProvider::setMainDataSourceWidget(QWidget* mainWidget) { m_mainWidget = mainWidget; m_dataItems.clear(); m_usedDataSources.clear(); m_fieldNumbersForDataItems.clear(); if (!m_mainWidget) return; //find widgets whose will work as data items const QList widgets(m_mainWidget->findChildren()); QSet tmpSources; foreach(QWidget *widget, widgets) { KexiFormDataItemInterface* const formDataItem = dynamic_cast(widget); if (!formDataItem) continue; if (formDataItem->parentDataItemInterface()) //item with parent interface: collect parent instead... continue; -#if 0 //! @todo reenable when subform is moved to KexiDBForm - KexiDBForm *dbForm = KDbUtils::findParent(widget, "KexiDBForm"); //form's surface... - if (dbForm != m_mainWidget) //only set data for this form's data items - continue; -#else - //tmp: reject widgets within subforms - //if (KDbUtils::findParent(widget, "KexiDBSubForm")) - // continue; - if (KexiUtils::parentIs(widget, "KexiDBSubForm")) - continue; -#endif QString dataSource(formDataItem->dataSource().toLower()); if (dataSource.isEmpty()) continue; qDebug() << widget->objectName(); m_dataItems.append(formDataItem); formDataItem->installListener(this); tmpSources.insert(dataSource); } //now we've got a set (unique list) of field names in tmpSources //remember it in m_usedDataSources foreach(const QString& source, tmpSources) { m_usedDataSources += source; } } void KexiFormDataProvider::fillDataItems(KDbRecordData *data, bool cursorAtNewRecord) { Q_ASSERT(data); qDebug() << "record.count=" << data->count() << "\nRECORD=" << *data; for (KexiFormDataItemInterfaceToIntMap::ConstIterator it = m_fieldNumbersForDataItems.constBegin(); it != m_fieldNumbersForDataItems.constEnd(); ++it) { KexiFormDataItemInterface *itemIface = it.key(); if (!itemIface->columnInfo()) { qDebug() << "itemIface->columnInfo() == 0"; continue; } //1. Is this a value with a combo box (lookup)? int indexForVisibleLookupValue = itemIface->columnInfo()->indexForVisibleLookupValue(); if (indexForVisibleLookupValue<0 && indexForVisibleLookupValue >= data->count()) //sanity indexForVisibleLookupValue = -1; //no const QVariant value(data->at(it.value())); QVariant visibleLookupValue; if (indexForVisibleLookupValue != -1 && (int)data->count() > indexForVisibleLookupValue) visibleLookupValue = data->at(indexForVisibleLookupValue); qDebug() << "fill data of '" << itemIface->dataSource() << "' at idx=" << it.value() << " data=" << value << (indexForVisibleLookupValue != -1 ? QString(" SPECIAL: indexForVisibleLookupValue=%1 visibleValue=%2") .arg(indexForVisibleLookupValue).arg(visibleLookupValue.toString()) : QString()); const bool displayDefaultValue = cursorAtNewRecord && (value.isNull() && visibleLookupValue.isNull()) && !itemIface->columnInfo()->field->defaultValue().isNull() && !itemIface->columnInfo()->field->isAutoIncrement(); //no value to set but there is default value defined itemIface->setValue( displayDefaultValue ? itemIface->columnInfo()->field->defaultValue() : value, QVariant(), /*add*/ /*!remove old*/false, indexForVisibleLookupValue == -1 ? 0 : &visibleLookupValue //pass visible value if available ); // now disable/enable "display default value" if needed (do it after setValue(), before setValue() turns it off) if (itemIface->hasDisplayedDefaultValue() != displayDefaultValue) itemIface->setDisplayDefaultValue(dynamic_cast(itemIface), displayDefaultValue); } } void KexiFormDataProvider::fillDuplicatedDataItems( KexiFormDataItemInterface* item, const QVariant& value) { if (m_disableFillDuplicatedDataItems) return; if (!m_duplicatedItems) { //build (once) a set of duplicated data items (having the same fields assigned) //so we can later check if an item is duplicated with a cost of o(1) QHash tmpDuplicatedItems; QHash::const_iterator it_dup; foreach(KexiFormDataItemInterface *dataItemIface, m_dataItems) { if (!dataItemIface->columnInfo() || !dataItemIface->columnInfo()->field) continue; qDebug() << " ** " << dataItemIface->columnInfo()->field->name(); it_dup = tmpDuplicatedItems.constFind(dataItemIface->columnInfo()->field); int count; if (it_dup == tmpDuplicatedItems.constEnd()) count = 0; else count = it_dup.value(); tmpDuplicatedItems.insert(dataItemIface->columnInfo()->field, ++count); } m_duplicatedItems = new QSet(); for (it_dup = tmpDuplicatedItems.constBegin(); it_dup != tmpDuplicatedItems.constEnd(); ++it_dup) { if (it_dup.value() > 1) { m_duplicatedItems->insert(it_dup.key()); qDebug() << "duplicated item: " << static_cast(it_dup.key())->name() << " (" << it_dup.value() << " times)"; } } } if (item->columnInfo() && m_duplicatedItems->contains(item->columnInfo()->field)) { foreach(KexiFormDataItemInterface *dataItemIface, m_dataItems) { if (dataItemIface != item && item->columnInfo()->field == dataItemIface->columnInfo()->field) { qDebug() << "- setting a copy of value for item '" << dynamic_cast(dataItemIface)->objectName() << "' == " << value; dataItemIface->setValue(value); } } } } void KexiFormDataProvider::valueChanged(KexiDataItemInterface* item) { Q_UNUSED(item); } bool KexiFormDataProvider::cursorAtNewRecord() const { return false; } void KexiFormDataProvider::invalidateDataSources(const QSet& invalidSources, KDbQuerySchema* query) { //fill m_fieldNumbersForDataItems mapping from data item to field number //(needed for fillDataItems) KDbQueryColumnInfo::Vector fieldsExpanded; // int dataFieldsCount; // == fieldsExpanded.count() if query is available or else == m_dataItems.count() if (query) { fieldsExpanded = query->fieldsExpanded(KDbQuerySchema::WithInternalFields); // dataFieldsCount = fieldsExpanded.count(); QHash columnsOrder(query->columnsOrder()); for (QHash::const_iterator it = columnsOrder.constBegin(); it != columnsOrder.constEnd(); ++it) { qDebug() << "query->columnsOrder()[ " << it.key()->field->name() << " ] = " << it.value(); } foreach(KexiFormDataItemInterface *item, m_dataItems) { KDbQueryColumnInfo* ci = query->columnInfo(item->dataSource()); int index = ci ? columnsOrder[ ci ] : -1; qDebug() << "query->columnsOrder()[ " << (ci ? ci->field->name() : QString()) << " ] = " << index << " (dataSource: " << item->dataSource() << ", name=" << dynamic_cast(item)->objectName() << ")"; if (index != -1 && !m_fieldNumbersForDataItems[ item ]) m_fieldNumbersForDataItems.insert(item, index); //! @todo //WRONG: not only used data sources can be fetched! // m_fieldNumbersForDataItems.insert( item, // m_usedDataSources.findIndex(item->dataSource().toLower()) ); } } //update data sources set (some of them may be removed) QSet tmpUsedDataSources; if (query) { qDebug() << *query; } m_disableFillDuplicatedDataItems = true; // temporary disable fillDuplicatedDataItems() // because setColumnInfo() can activate it for (QList::iterator it(m_dataItems.begin()); it != m_dataItems.end();) { KexiFormDataItemInterface *item = *it; Q_ASSERT(item); if (invalidSources.contains(item->dataSource().toLower())) { item->setInvalidState(QString::fromLatin1("#%1?").arg(xi18n("NAME"))); it = m_dataItems.erase(it); continue; } int fieldNumber = m_fieldNumbersForDataItems[ item ]; if (query) { KDbQueryColumnInfo *ci = fieldsExpanded[fieldNumber]; item->setColumnInfo(ci); qDebug() << "- item=" << dynamic_cast(item)->objectName() << " dataSource=" << item->dataSource() << " field=" << ci->field->name(); const int indexForVisibleLookupValue = ci->indexForVisibleLookupValue(); if (-1 != indexForVisibleLookupValue && indexForVisibleLookupValue < (int)fieldsExpanded.count()) { //there's lookup column defined: set visible column as well KDbQueryColumnInfo *visibleColumnInfo = fieldsExpanded[ indexForVisibleLookupValue ]; if (visibleColumnInfo) { item->setVisibleColumnInfo(visibleColumnInfo); if (item->isComboBox() && m_mainWidget && item->internalEditor()) { // m_mainWidget (dbform) should filter the (just created using setVisibleColumnInfo()) // combo box' internal editor (actually, only if the combo is in 'editable' mode) item->internalEditor()->installEventFilter(m_mainWidget); } qDebug() << "ALSO SET visibleColumn=" << *visibleColumnInfo << "\n at position " << indexForVisibleLookupValue; } } } tmpUsedDataSources.insert(item->dataSource().toLower()); ++it; } m_disableFillDuplicatedDataItems = false; m_usedDataSources.clear(); foreach(const QString& source, tmpUsedDataSources) { m_usedDataSources += source; } } diff --git a/kexi/widget/dataviewcommon/kexiformdataiteminterface.h b/kexi/widget/dataviewcommon/kexiformdataiteminterface.h index a9da4f8c3e3..8e3da130f21 100644 --- a/kexi/widget/dataviewcommon/kexiformdataiteminterface.h +++ b/kexi/widget/dataviewcommon/kexiformdataiteminterface.h @@ -1,170 +1,170 @@ /* This file is part of the KDE project Copyright (C) 2005-2009 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 KEXIFORMDATAITEMINTERFACE_H #define KEXIFORMDATAITEMINTERFACE_H #include "kexidataviewcommon_export.h" #include #include #include class KDbField; //! An interface for declaring form widgets to be data-aware. class KEXIDATAVIEWCOMMON_EXPORT KexiFormDataItemInterface : public KexiDataItemInterface { public: KexiFormDataItemInterface(); virtual ~KexiFormDataItemInterface(); //! \return the name of the data source for this widget. //! Data source usually means here a table or query, a field name or an expression. inline QString dataSource() const { return m_dataSource; } //! Sets the name of the data source for this widget. //! Data source usually means here a table or query or field name name. inline void setDataSource(const QString &ds) { m_dataSource = ds; } /*! \return the plugin ID of the part for the widget's data source. It means IDs like "org.kexi-project.table" or "org.kexi-project.query" if the data - source is set to object (as within form or subform) + source is set to object (as within form) or is empty if the data source is set to table field or query column. */ inline QString dataSourcePluginId() const { return m_dataSourcePartClass; } /*! Sets the plugin ID of the part for the data widget's data source. It usually means here a "org.kexi-project.table" or "org.kexi-project.query". @see dataSourcePluginId() */ inline void setDataSourcePluginId(const QString &pluginId) { m_dataSourcePartClass = pluginId; } /*! 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'. You can reimplement this in the widget. Always call the superclass' implementation. setDisplayDefaultValue(.., false) is called in KexiFormScrollView::valueChanged() as a response on data change performed by user. */ virtual void setDisplayDefaultValue(QWidget* widget, bool displayDefaultValue); /*! \return true if default value is displayed for this item. */ virtual bool hasDisplayedDefaultValue() const { return m_displayDefaultValue; } /*! Convenience function: casts this item to a QWidget. Can return 0 if the item is not a QWidget-derived object. */ virtual QWidget* widget() { return dynamic_cast(this); } /*! Sets 'invalid' state, e.g. a text editor widget should display text \a displayText and become read only to prevent entering data, because updating at the database backend is not available. \a displayText is usually set to something i18n'd like "#NAME?". Note: that even widgets that usually do not display texts (e.g. pixmaps) should display \a displayText too. */ virtual void setInvalidState(const QString& displayText) = 0; /*! Changes 'read only' flag, for this widget. Typically this flag can be passed to a widget itself, e.g. QLineEdit::setReadOnly(bool). */ virtual void setReadOnly(bool readOnly) = 0; //! \return database column information for this item virtual KDbField* field() const; //! \return database column information for this item virtual KDbQueryColumnInfo* columnInfo() const { return m_columnInfo; } /*! Used internally to set database column information. Reimplement if you need to do additional actions, e.g. set data validator based on field type. Don't forget about calling superclass implementation. */ virtual void setColumnInfo(KDbQueryColumnInfo* cinfo) { m_columnInfo = cinfo; } /*! Used internally to set visible database column information. Reimplemented in KexiDBComboBox: except for combo box, this does nothing. */ virtual void setVisibleColumnInfo(KDbQueryColumnInfo* cinfo) { Q_UNUSED(cinfo); } /*! \return visible database column information for this item. Except for combo box, this is exactly the same as columnInfo(). */ virtual KDbQueryColumnInfo* visibleColumnInfo() const { return columnInfo(); } /*! Does nothing, because within forms, widgets are always visible. */ virtual void hideWidget() { } /*! Does nothing, because within forms, widgets are always visible. */ virtual void showWidget() { } /*! Undoes changes made to this item - just resets the widget to original value. Note: This is internal method called by KexiFormScrollView::cancelEditor(). To cancel editing of the widget's data from the widget's code, use KexiFormDataItemInterface::cancelEditor(). Reimplemented in KexiDBComboBox to also revert the visible value (i.e. text) to the original state. */ virtual void undoChanges(); /* Cancels editing of the widget's data. This method just looks for the (grand)parent KexiFormScrollView object and calls KexiFormScrollView::cancelEditor(). */ void cancelEditor(); /*! @internal Called by top-level form on key press event. Default implementation does nothing. Implement this if you want to handle key presses from within the editor widget item. \return true if \a ke should be accepted by the widget item. This method is used e.g. in KexiDBImageBox for Key_Escape to if the popup is visible, so the key press won't be consumed to perform "cancel editing". */ virtual bool keyPressed(QKeyEvent *ke) { Q_UNUSED(ke); return false; } //! Selects contents of the widget if there is such behaviour set (it is by default). //! @todo add option for not selecting the field virtual void selectAllOnFocusIfNeeded(); protected: QString m_dataSource; QString m_dataSourcePartClass; KDbQueryColumnInfo* m_columnInfo; KexiDisplayUtils::DisplayParameters *m_displayParametersForEnteredValue; //!< used in setDisplayDefaultValue() KexiDisplayUtils::DisplayParameters *m_displayParametersForDefaultValue; //!< used in setDisplayDefaultValue() bool m_displayDefaultValue; //!< used by setDisplayDefaultValue() friend class KexiDBAutoField; }; #endif diff --git a/kexi/widget/navigator/KexiProjectNavigator.cpp b/kexi/widget/navigator/KexiProjectNavigator.cpp index 5bf9e6a017b..b4d0c418e11 100644 --- a/kexi/widget/navigator/KexiProjectNavigator.cpp +++ b/kexi/widget/navigator/KexiProjectNavigator.cpp @@ -1,761 +1,762 @@ /* This file is part of the KDE project Copyright (C) 2002, 2003 Lucijan Busch Copyright (C) 2003-2014 Jarosław Staniek Copyright (C) 2010 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 "KexiProjectNavigator.h" #include "KexiProjectTreeView.h" #include "KexiProjectModel.h" #include "KexiProjectModelItem.h" #include "KexiProjectItemDelegate.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 class KexiProjectNavigator::Private { public: Private(Features features_, KexiProjectNavigator *qq) : features(features_) , q(qq) , emptyStateLabel(0) , prevSelectedPartInfo(0) , singleClick(false) , readOnly(false) { } ~Private() { delete model; } Features features; KexiProjectNavigator *q; QVBoxLayout *lyr; KexiProjectTreeView *list; QLabel *emptyStateLabel; KActionCollection *actions; KexiItemMenu *itemMenu; KexiGroupMenu *partMenu; QAction *deleteAction, *renameAction, *newObjectAction, *openAction, *designAction, *editTextAction, *executeAction, *dataExportToClipboardAction, *dataExportToFileAction; -#ifndef KEXI_NO_QUICK_PRINTING +#ifndef KEXI_QUICK_PRINTING_SUPPORT QAction *printAction, *pageSetupAction; #endif KActionMenu* exportActionMenu; QAction *itemMenuTitle, *partMenuTitle, *exportActionMenu_sep, *pageSetupAction_sep; KexiPart::Info *prevSelectedPartInfo; bool singleClick; bool readOnly; KexiProjectModel *model; QString itemsPluginId; }; KexiProjectNavigator::KexiProjectNavigator(QWidget* parent, Features features) : QWidget(parent) , d(new Private(features, this)) { d->actions = new KActionCollection(this); setObjectName("KexiProjectNavigator"); setWindowTitle(xi18nc("@title:window", "Project Navigator")); setWindowIcon(KexiMainWindowIface::global()->thisWidget()->windowIcon()); d->lyr = new QVBoxLayout(this); d->lyr->setContentsMargins(2, 0, 0, 0); d->list = new KexiProjectTreeView(this); if (d->features & Borders) { d->list->setAlternatingRowColors(true); } else { d->list->setFrameStyle(QFrame::NoFrame); QPalette pal(d->list->palette()); pal.setColor(QPalette::Base, Qt::transparent); d->list->setPalette(pal); d->list->setIndentation(0); } d->model = new KexiProjectModel(); connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(slotUpdateEmptyStateLabel())); connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(slotUpdateEmptyStateLabel())); d->list->setModel(d->model); KexiProjectItemDelegate *delegate = new KexiProjectItemDelegate(d->list); d->list->setItemDelegate(delegate); d->lyr->addWidget(d->list); //! @todo KEXI3 port from KGlobalSettings::Private::_k_slotNotifyChange: //! connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), SLOT(slotSettingsChanged(int))); slotSettingsChanged(0); connect(d->list, SIGNAL(pressed(QModelIndex)), this,SLOT(slotSelectionChanged(QModelIndex))); KConfigGroup mainWindowGroup = KSharedConfig::openConfig()->group("MainWindow"); if (mainWindowGroup.readEntry("SingleClickOpensItem", true)) { connect(d->list, SIGNAL(activated(QModelIndex)), this, SLOT(slotExecuteItem(QModelIndex))); } else { connect(d->list, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotExecuteItem(QModelIndex))); } // actions d->openAction = addAction("open_object", koIcon("document-open"), xi18n("&Open"), xi18n("Open object"), xi18n("Opens object selected in the list."), SLOT(slotOpenObject())); if (KexiMainWindowIface::global() && KexiMainWindowIface::global()->userMode()) { //! @todo some of these actions can be supported once we deliver ACLs... d->deleteAction = 0; d->renameAction = 0; d->designAction = 0; d->editTextAction = 0; d->newObjectAction = 0; } else { d->deleteAction = addAction("edit_delete", koIcon("edit-delete"), xi18n("&Delete..."), xi18n("Delete object"), xi18n("Deletes the object selected in the list."), SLOT(slotRemove())); d->renameAction = addAction("edit_rename", koIcon("edit-rename"), xi18n("&Rename..."), xi18n("Rename object"), xi18n("Renames the object selected in the list."), SLOT(slotRename())); //! @todo enable, doesn't work now: d->renameAction->setShortcut(QKeySequence(Qt::Key_F2)); #ifdef KEXI_SHOW_UNIMPLEMENTED //! @todo plugSharedAction("edit_cut",SLOT(slotCut())); //! @todo plugSharedAction("edit_copy",SLOT(slotCopy())); //! @todo plugSharedAction("edit_paste",SLOT(slotPaste())); #endif d->designAction = addAction("design_object", koIcon("document-properties"), xi18n("&Design"), xi18n("Design object"), xi18n("Starts designing of the object selected in the list."), SLOT(slotDesignObject())); d->editTextAction = addAction("editText_object", QIcon(), xi18n("Design in &Text View"), xi18n("Design object in text view"), xi18n("Starts designing of the object in the list in text view."), SLOT(slotEditTextObject())); d->newObjectAction = addAction("new_object", koIcon("document-new"), QString(),QString(), QString(), SLOT(slotNewObject())); } d->executeAction = addAction("data_execute", koIcon("system-run"), xi18n("Execute"), //! @todo tooltip, what's this QString(), QString(), SLOT(slotExecuteObject())); d->actions->addAction("export_object", d->exportActionMenu = new KActionMenu(xi18n("Export"), this)); d->dataExportToClipboardAction = addAction("exportToClipboardAsDataTable", koIcon("edit-copy"), xi18nc("Export->To Clipboard as Data... ", "To &Clipboard..."), xi18n("Export data to clipboard"), xi18n("Exports data from the currently selected table or query to clipboard."), SLOT(slotExportToClipboardAsDataTable())); d->exportActionMenu->addAction(d->dataExportToClipboardAction); d->dataExportToFileAction = addAction("exportToFileAsDataTable", koIcon("table"), xi18nc("Export->To File As Data &Table... ", "To &File As Data Table..."), xi18n("Export data to a file"), xi18n("Exports data from the currently selected table or query to a file."), SLOT(slotExportToFileAsDataTable())); d->exportActionMenu->addAction(d->dataExportToFileAction); -#ifndef KEXI_NO_QUICK_PRINTING +#ifndef KEXI_QUICK_PRINTING_SUPPORT d->printAction = addAction("print_object", koIcon("document-print"), futureI18n("&Print..."), futureI18n("Print data"), futureI18n("Prints data from the currently selected table or query."), SLOT(slotPrintObject())); d->pageSetupAction = addAction("pageSetupForObject", koIconWanted("not yet in Oxygen 4.3", "document-page-setup"), futureI18n("Page Setup..."), futureI18n("Page setup for data"), futureI18n("Shows page setup for printing the active table or query."), SLOT(slotPageSetupForObject())); #endif if (KexiMainWindowIface::global() && KexiMainWindowIface::global()->userMode()) { //! @todo some of these actions can be supported once we deliver ACLs... d->partMenu = 0; } else { d->partMenu = new KexiGroupMenu(this, d->actions); } if (d->features & ContextMenus) { d->itemMenu = new KexiItemMenu(this, d->actions); } else { d->itemMenu = 0; } if (!(d->features & Writable)) { setReadOnly(true); } slotSelectionChanged(QModelIndex()); } void KexiProjectNavigator::setProject(KexiProject* prj, const QString& itemsPartClass, QString* partManagerErrorMessages, bool addAsSearchableModel) { d->itemsPluginId = itemsPartClass; d->model->setProject(prj, itemsPartClass, partManagerErrorMessages); if (addAsSearchableModel) { KexiMainWindowIface::global()->addSearchableModel(d->model); } d->list->expandAll(); d->list->setRootIsDecorated(false); slotUpdateEmptyStateLabel(); } QString KexiProjectNavigator::itemsPluginId() const { return d->itemsPluginId; } KexiProjectNavigator::~KexiProjectNavigator() { delete d; } QAction * KexiProjectNavigator::addAction(const QString& name, const QIcon& icon, const QString& text, const QString& toolTip, const QString& whatsThis, const char* slot) { QAction *action = new QAction(icon, text, this); d->actions->addAction(name, action); action->setToolTip(toolTip); action->setWhatsThis(whatsThis); connect(action, SIGNAL(triggered()), this, slot); return action; } void KexiProjectNavigator::contextMenuEvent(QContextMenuEvent* event) { if (!d->list->currentIndex().isValid() || !(d->features & ContextMenus)) return; QModelIndex pointedIndex = d->list->indexAt(d->list->mapFromGlobal(event->globalPos())); KexiProjectModelItem *bit = static_cast(pointedIndex.internalPointer()); if (!bit || !bit->partItem() /*no menu for group*/) { return; } QMenu *pm = 0; if (bit->partItem()) { pm = d->itemMenu; KexiProjectModelItem *par_it = static_cast(bit->parent()); d->itemMenu->update(par_it->partInfo(), bit->partItem()); } if (pm) { pm->exec(event->globalPos()); } event->setAccepted(true); } void KexiProjectNavigator::slotExecuteItem(const QModelIndex& vitem) { KexiProjectModelItem *it = static_cast(vitem.internalPointer()); if (!it) { qWarning() << "No internal pointer"; return; } //! @todo is this needed? // if (!it->partItem() && !d->singleClick /*annoying when in single click mode*/) { // vitem. // d->list->setOpen(vitem, !vitem->isOpen()); // return; // } if (it->partInfo()->isExecuteSupported()) emit executeItem(it->partItem()); else emit openOrActivateItem(it->partItem(), Kexi::DataViewMode); } void KexiProjectNavigator::slotSelectionChanged(const QModelIndex& i) { KexiProjectModelItem *it = static_cast(i.internalPointer()); if (!it) { if (KexiMainWindowIface::global() && !KexiMainWindowIface::global()->userMode()) { d->openAction->setEnabled(false); d->designAction->setEnabled(false); d->deleteAction->setEnabled(false); } return; } const bool gotitem = it && it->partItem(); //! @todo also check if the item is not read only if (d->deleteAction) { d->deleteAction->setEnabled(gotitem && !d->readOnly); } #ifdef KEXI_SHOW_UNIMPLEMENTED //! @todo setAvailable("edit_cut",gotitem); //! @todo setAvailable("edit_copy",gotitem); //! @todo setAvailable("edit_edititem",gotitem); #endif if ( KexiMainWindowIface::global() && !KexiMainWindowIface::global()->userMode() ) { d->openAction->setEnabled(gotitem && (it->partInfo()->supportedViewModes() & Kexi::DataViewMode)); if (d->designAction) { d->designAction->setEnabled(gotitem && (it->partInfo()->supportedViewModes() & Kexi::DesignViewMode)); } if (d->editTextAction) d->editTextAction->setEnabled(gotitem && (it->partInfo()->supportedViewModes() & Kexi::TextViewMode)); if (d->prevSelectedPartInfo != it->partInfo()) { d->prevSelectedPartInfo = it->partInfo(); if (d->newObjectAction) { d->newObjectAction->setText( xi18n("&Create Object: %1...", it->partInfo()->name() )); d->newObjectAction->setIcon(QIcon::fromTheme(it->partInfo()->createIconName())); } #if 0 } else { if (d->newObjectAction) { d->newObjectAction->setText(xi18n("&Create Object...")); } #endif } } emit selectionChanged(it ? it->partItem() : 0); } void KexiProjectNavigator::slotRemove() { if (!d->deleteAction || !d->deleteAction->isEnabled() || !(d->features & Writable)) return; KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partItem()) return; emit removeItem(it->partItem()); } void KexiProjectNavigator::slotNewObject() { if (!d->newObjectAction || !(d->features & Writable)) return; KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partInfo()) return; emit newItem(it->partInfo()); } void KexiProjectNavigator::slotOpenObject() { KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partItem()) return; emit openItem(it->partItem(), Kexi::DataViewMode); } void KexiProjectNavigator::slotDesignObject() { if (!d->designAction) return; KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partItem()) return; emit openItem(it->partItem(), Kexi::DesignViewMode); } void KexiProjectNavigator::slotEditTextObject() { if (!d->editTextAction) return; KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); if (!it || !it->partItem()) return; emit openItem(it->partItem(), Kexi::TextViewMode); } void KexiProjectNavigator::slotCut() { if (!(d->features & Writable)) return; //! @todo } void KexiProjectNavigator::slotCopy() { //! @todo } void KexiProjectNavigator::slotPaste() { if (!(d->features & Writable)) return; //! @todo } void KexiProjectNavigator::slotRename() { if (!d->renameAction || !(d->features & Writable)) return; KexiPart::Item* partItem = selectedPartItem(); if (!partItem) { return; } KexiProjectModelItem *partModelItem = d->model->modelItemFromItem(*partItem); if (!partModelItem) { return; } KexiPart::Info *info = partModelItem->partInfo(); KexiPart::Part *part = Kexi::partManager().partForPluginId(partItem->pluginId()); if (!info || !part) { return; } KexiNameDialog dialog( xi18nc("@info Rename object %1:", "Rename %1:", partItem->name()), this); dialog.buttonBox()->button(QDialogButtonBox::Ok)->setText(xi18nc("@action:button Rename object", "Rename")); if (!d->model->project()) { qWarning() << "No KexiProject assigned!"; return; } dialog.widget()->addNameSubvalidator( //check if new name is allowed new KDbObjectNameValidator(d->model->project()->dbConnection()->driver())); dialog.widget()->setCaptionText(partItem->caption()); dialog.widget()->setNameText(partItem->name()); dialog.setWindowTitle( xi18nc("@title:window Rename Object %1.", "Rename %1", partItem->name())); dialog.setDialogIcon(info->iconName()); dialog.setAllowOverwriting(true); bool overwriteNeeded; if (dialog.execAndCheckIfObjectExists(*d->model->project(), *part, &overwriteNeeded) != QDialog::Accepted) { return; } if (dialog.widget()->nameText() != dialog.widget()->originalNameText() && !d->model->renameItem(partItem, dialog.widget()->nameText())) { return; } d->model->setItemCaption(partItem, dialog.widget()->captionText()); } void KexiProjectNavigator::setFocus() { if (!d->list->currentIndex().isValid()) { // select first QModelIndex first = d->model->firstPartItem(); d->list->setCurrentIndex(first); } d->list->setFocus(); } void KexiProjectNavigator::updateItemName(KexiPart::Item& item, bool dirty) { if (!(d->features & Writable)) return; d->model->updateItemName(item, dirty); } void KexiProjectNavigator::slotSettingsChanged(int) { d->singleClick = KexiUtils::activateItemsOnSingleClick(this); } void KexiProjectNavigator::selectItem(KexiPart::Item& item) { KexiProjectModelItem *bitem = d->model->modelItemFromItem(item); if (!bitem) return; QModelIndex idx = d->model->indexFromItem(bitem); d->list->setCurrentIndex(idx); d->list->scrollTo(idx); } void KexiProjectNavigator::clearSelection() { d->list->clearSelection(); d->list->scrollToTop(); } void KexiProjectNavigator::slotExecuteObject() { if (!d->executeAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit executeItem(item); } void KexiProjectNavigator::slotExportToClipboardAsDataTable() { if (!d->dataExportToClipboardAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit exportItemToClipboardAsDataTable(item); } void KexiProjectNavigator::slotExportToFileAsDataTable() { if (!d->dataExportToFileAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit exportItemToFileAsDataTable(item); } KexiPart::Item* KexiProjectNavigator::selectedPartItem() const { KexiProjectModelItem *it = static_cast(d->list->currentIndex().internalPointer()); return it ? it->partItem() : 0; } bool KexiProjectNavigator::actionEnabled(const QString& actionName) const { if (actionName == "project_export_data_table" && (d->features & ContextMenus)) return d->exportActionMenu->isVisible(); qWarning() << "no such action: " << actionName; return false; } void KexiProjectNavigator::slotPrintObject() { -#ifndef KEXI_NO_QUICK_PRINTING +#ifndef KEXI_QUICK_PRINTING_SUPPORT if (!d->printAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit printItem(item); #endif } void KexiProjectNavigator::slotPageSetupForObject() { -#ifndef KEXI_NO_QUICK_PRINTING +#ifndef KEXI_QUICK_PRINTING_SUPPORT if (!d->pageSetupAction) return; KexiPart::Item* item = selectedPartItem(); if (item) emit pageSetupForItem(item); #endif } void KexiProjectNavigator::setReadOnly(bool set) { d->readOnly = set; if (d->deleteAction) d->deleteAction->setEnabled(!d->readOnly); if (d->renameAction) d->renameAction->setEnabled(!d->readOnly); if (d->newObjectAction) { d->newObjectAction->setEnabled(!d->readOnly); } } bool KexiProjectNavigator::isReadOnly() const { return d->readOnly; } void KexiProjectNavigator::clear() { d->model->clear(); } KexiProjectModel* KexiProjectNavigator::model() const { return d->model; } void KexiProjectNavigator::slotUpdateEmptyStateLabel() { if (d->model->objectsCount() == 0) { // handle the empty state with care... http://www.pinterest.com/romanyakimovich/ui-empty-states/ if (!d->emptyStateLabel) { QString imgPath = KIconLoader::global()->iconPath(KexiIconName(koIconName("kexi-document-empty")), - KIconLoader::SizeMedium); qDebug() << imgPath; d->emptyStateLabel = new QLabel( xi18nc("@info Message for empty state in project navigator", "" "" "" "Your project is empty..." "" "Why not create something?", imgPath), this); d->emptyStateLabel->setPalette( KexiUtils::paletteWithDimmedColor(d->emptyStateLabel->palette(), QPalette::WindowText)); d->emptyStateLabel->setAlignment(Qt::AlignCenter); d->emptyStateLabel->setTextFormat(Qt::RichText); d->emptyStateLabel->setWordWrap(true); QFont f(d->emptyStateLabel->font()); f.setItalic(true); f.setFamily("Times"); f.setPointSize(f.pointSize() * 4 / 3); //d->emptyStateLabel->setFont(f); d->lyr->insertWidget(0, d->emptyStateLabel); } d->emptyStateLabel->show(); } else { delete d->emptyStateLabel; d->emptyStateLabel = 0; } } //-------------------------------------------- KexiMenuBase::KexiMenuBase(QWidget* parent, KActionCollection *col) : QMenu(parent) , m_actionCollection(col) { } KexiMenuBase::~KexiMenuBase() { } QAction* KexiMenuBase::addAction(const QString& actionName) { QAction* action = m_actionCollection->action(actionName); if (action) QMenu::addAction(action); return action; } //-------------------------------------------- KexiItemMenu::KexiItemMenu(QWidget* parent, KActionCollection *col) : KexiMenuBase(parent, col) { } KexiItemMenu::~KexiItemMenu() { } void KexiItemMenu::update(KexiPart::Info* partInfo, KexiPart::Item* partItem) { clear(); addSection(QString()); KexiContextMenuUtils::updateTitle(this, partItem->name(), partInfo->name(), partInfo->iconName()); if (m_actionCollection->action("open_object") && m_actionCollection->action("open_object")->isEnabled() && partItem && (partInfo->supportedViewModes() & Kexi::DataViewMode)) { addAction("open_object"); } if (m_actionCollection->action("design_object") && m_actionCollection->action("design_object")->isEnabled() && partItem && (partInfo->supportedViewModes() & Kexi::DesignViewMode)) { addAction("design_object"); } if (m_actionCollection->action("editText_object") && m_actionCollection->action("editText_object")->isEnabled() && partItem && (partInfo->supportedViewModes() & Kexi::TextViewMode)) { addAction("editText_object"); } addSeparator(); #ifdef KEXI_SHOW_UNIMPLEMENTED //! @todo plugSharedAction("edit_cut", m_itemMenu); //! @todo plugSharedAction("edit_copy", m_itemMenu); //! @todo addSeparator(); #endif bool addSep = false; if (partItem && partInfo->isExecuteSupported()) { addAction("data_execute"); addSep = true; } if (partItem && partInfo->isDataExportSupported()) { addAction("export_object"); addSep = true; } if (addSep) addSeparator(); -#ifndef KEXI_NO_QUICK_PRINTING +#ifndef KEXI_QUICK_PRINTING_SUPPORT if (partItem && partInfo->isPrintingSupported()) addAction("print_object"); if (partItem && partInfo->isPrintingSupported()) addAction("pageSetupForObject"); if (m_actionCollection->action("edit_rename") || m_actionCollection->action("edit_delete")) addSeparator(); #endif addAction("edit_rename"); addAction("edit_delete"); } //-------------------------------------------- KexiGroupMenu::KexiGroupMenu(QWidget* parent, KActionCollection *col) : KexiMenuBase(parent, col) { } KexiGroupMenu::~KexiGroupMenu() { } void KexiGroupMenu::update(KexiPart::Info* partInfo) { Q_UNUSED(partInfo); clear(); addAction("new_object"); }