diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 441a70d1a..4f3bb305e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,78 +1,75 @@ add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44020) set(kexicore_LIB_SRCS KexiGlobal.cpp kexi.cpp kexiaboutdata.cpp KexiMainWindowIface.cpp KexiStandardAction.cpp kexidbconnectionset.cpp kexiprojectset.cpp kexiactionproxy.cpp kexisharedactionhost.cpp kexiactioncategories.cpp kexiproject.cpp KexiWindow.cpp KexiWindowData.cpp KexiView.cpp kexipartmanager.cpp kexipartinfo.cpp kexipartitem.cpp kexipartbase.cpp kexipart.cpp kexipartguiclient.cpp kexiprojectdata.cpp KexiRecentProjects.cpp kexiinternalpart.cpp kexidragobjects.cpp kexistartupdata.cpp KexiCommandLineOptions.cpp kexiguimsghandler.cpp kexitextmsghandler.cpp kexidataiteminterface.cpp kexidbshortcutfile.cpp kexiblobbuffer.cpp #TODO KEXI3 kexistaticpart.cpp kexitabledesignerinterface.cpp kexisearchandreplaceiface.cpp kexitemplateloader.cpp KexiRecordNavigatorHandler.cpp KexiRecordNavigatorIface.cpp KexiSearchableModel.cpp KexiGroupButton.cpp #TODO belongs to widget/? ) kexi_add_library(kexicore SHARED ${kexicore_LIB_SRCS}) generate_export_header(kexicore) target_link_libraries(kexicore PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets KF5::CoreAddons KF5::XmlGui kexiutils KDb KPropertyWidgets ) if(WIN32) target_include_directories(kexicore PUBLIC "${KDEWIN_INCLUDES}") target_link_libraries(kexicore PUBLIC ${KDEWIN_LIBRARIES}) endif() -<<<<<<< HEAD -======= include_directories(${CMAKE_SOURCE_DIR}/src/kexiutils/style) set_target_properties(kexicore PROPERTIES VERSION ${GENERIC_KEXI_LIB_VERSION} SOVERSION ${GENERIC_KEXI_LIB_SOVERSION} ) ->>>>>>> Move KexiStyle to kexiutils/style/, add KexiStyle::propertyPane(), add KexiPropertyPaneLineEditStyle install(TARGETS kexicore ${INSTALL_TARGETS_DEFAULT_ARGS}) #install(FILES kexihandler.desktop DESTINATION ${SERVICETYPES_INSTALL_DIR}) diff --git a/src/core/KexiMainWindowIface.h b/src/core/KexiMainWindowIface.h index 3477e8f16..e25a699f9 100644 --- a/src/core/KexiMainWindowIface.h +++ b/src/core/KexiMainWindowIface.h @@ -1,334 +1,334 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KEXIMAINWINDOWIFACE_H #define KEXIMAINWINDOWIFACE_H //#define KEXI_IMPL_WARNINGS #include #include #include #include "KexiMigrateManagerInterface.h" #include "kexisharedactionhost.h" #include "kexi.h" class KDbQuerySchema; class KexiWindow; class KexiProject; class KActionCollection; class KexiSearchableModel; class KexiUserFeedbackAgent; class KexiMigrateManagerInterface; namespace KexiPart { class Item; class Info; } class KToolBar; namespace Kexi { //! Describes a global mode for the application /*! The following describes availability of modes. - Welcome mode: always ON - Help mode: always ON -# State: No project - Project mode: OFF - Edit mode: OFF - Design mode: OFF -# State: Project opened, no object opened - Project mode: ON - Edit mode: ON - Design mode: OFF -# State: Project opened, at least one object opened - Project mode: ON - Edit mode: ON - Design mode: ON (if the current object can be designed) */ /*! @todo What about custom modes? */ enum GlobalViewMode { WelcomeGlobalMode, ProjectGlobalMode, EditGlobalMode, DesignGlobalMode, HelpGlobalMode, LastGlobalMode = HelpGlobalMode }; } /** * @short Kexi's main window interface * This interface is implemented by KexiMainWindow class. * KexiMainWindow offers simple features what lowers cross-dependency (and also avoids * circular dependencies between Kexi modules). */ class KEXICORE_EXPORT KexiMainWindowIface : public KexiSharedActionHost { public: //! Used by printActionForItem() enum PrintActionType { PrintItem, PreviewItem, PageSetupForItem }; KexiMainWindowIface(); virtual ~KexiMainWindowIface(); //! \return KexiMainWindowImpl global singleton (if it is instantiated) static KexiMainWindowIface* global(); QWidget* thisWidget(); //! Project data of currently opened project or NULL if no project here yet. virtual KexiProject *project() = 0; //! @todo KEXI3 virtual KActionCollection* actionCollection() const = 0; virtual KActionCollection* actionCollection() const = 0; //! @todo KEXI3 virtual QWidget* focusWidget() const = 0; virtual QWidget* focusWidget() const = 0; /*! Registers window \a window for watching and adds it to the main window's stack. */ virtual void registerChild(KexiWindow *window) = 0; /*! \return a list of all actions defined by application. Not all of them are shared. Don't use plug these actions in your windows by hand but user methods from KexiView! */ virtual QList allActions() const = 0; /*! \return currently active window or 0 if there is no active window. */ virtual KexiWindow* currentWindow() const = 0; /*! Switches \a window to view \a mode. Activates the window if it is not the current window. */ virtual tristate switchToViewMode(KexiWindow& window, Kexi::ViewMode viewMode) = 0; //! @return current global mode virtual Kexi::GlobalViewMode currentMode() const = 0; /*! \return true if this window is in the User Mode. */ virtual bool userMode() const = 0; // Q_SIGNALS: //! Emitted to make sure the project can be close. //! Connect a slot here and set \a cancel to true to cancel the closing. virtual void acceptProjectClosingRequested(bool *cancel) = 0; //! Emitted before closing the project (and destroying all it's data members). //! You can do you cleanup of your structures here. virtual void beforeProjectClosing() = 0; //! Emitted after closing the project. virtual void projectClosed() = 0; // public Q_SLOTS: /*! Creates new object of type defined by \a info part info. \a openingCancelled is set to true if opening has been cancelled. \return true on success. */ virtual bool newObject(KexiPart::Info *info, bool *openingCancelled) = 0; //! Opens object pointed by \a item in a view \a viewMode virtual KexiWindow* openObject(KexiPart::Item *item, Kexi::ViewMode viewMode, bool *openingCancelled, QMap* staticObjectArgs = 0, QString* errorMessage = 0) = 0; //! For convenience virtual KexiWindow* openObject(const QString& mime, const QString& name, Kexi::ViewMode viewMode, bool *openingCancelled, QMap* staticObjectArgs = 0) = 0; /*! Closes the object for \a item. \return true on success (closing can be dealyed though), false on failure and cancelled if the object has "opening" job assigned. */ virtual tristate closeObject(KexiPart::Item* item) = 0; /*! Called to accept property butter editing. */ virtual void acceptPropertySetEditing() = 0; /*! Received information from active view that \a window has switched its property set, so property editor contents should be reloaded. If \a force is true, property editor's data is reloaded even if the currently pointed property set is the same as before. If \a preservePrevSelection is true and there was a property set set before call, previously selected item will be preselected in the editor (if found). */ virtual void propertySetSwitched(KexiWindow *window, bool force = false, bool preservePrevSelection = true, bool sortedProperties = false, const QByteArray& propertyToSelect = QByteArray()) = 0; virtual void beginPropertyPaneUpdate() = 0; virtual void endPropertyPaneUpdate() = 0; //! Options used in saveObject() enum SaveObjectOption { DoNotAsk = 1, //!< Do not ask for confirmation of overwriting SaveObjectAs = 2 //!< Saving object with a new name }; Q_DECLARE_FLAGS(SaveObjectOptions, SaveObjectOption) /*! Saves window's \a window data. If window's data is never saved, user is asked for name and title, before saving (see getNewObjectInfo()). \return true on successul saving or false on error. If saving was cancelled by user, cancelled is returned. \a messageWhenAskingForName is a i18n'ed text that will be visible within name/caption dialog (see KexiNameDialog), which is popped up for never saved objects. Saving object with a new name is also supported here, to do so SaveObjectOption::SaveObjectAs should be added to @a options. */ virtual tristate saveObject(KexiWindow *window, const QString& messageWhenAskingForName = QString(), SaveObjectOptions options = 0) = 0; /*! Closes window \a window. If window's data (see KexiWindow::isDirty()) is unsaved, used will be asked if saving should be perforemed. \return true on successull closing or false on closing error. If closing was cancelled by user, cancelled is returned. If \a window is 0, the current one will be closed. */ virtual tristate closeWindow(KexiWindow *window) = 0; /*! Find window for a given \a identifier. \return 0 if no windows found. */ virtual KexiWindow *openedWindowFor(int identifier) = 0; /*! Find window for a given \a item. \return 0 if no windows found. */ virtual KexiWindow *openedWindowFor(const KexiPart::Item* item) = 0; /*! Parametrs for query with given id. */ virtual QList currentParametersForQuery(int queryId) const = 0; //! \return query schema currently unsaved (edited) in a window corresponding to Kexi object identified by \a identifier. /*! For implementation in plugins, default implementation returns 0. * In implementations 0 should be returned if there is no such Kexi object * in the current project or if the object's window is not opened or if * the window contains no edited query at the moment. * If the query is "unsaved" the window displaying the corresponding Kexi object is marked as "dirty". * Currently supported type of Kexi objects are only queries being in data view. * See KexiQueryPart::unsavedQuery(int) for this implementation. * The query schema returned by this method can be used for example by data * exporting routines so users can export result of running unsaved * query without prior saving its design. * The changes to design can be even discarded without consequences this way. @note Returned pointer leads to a temporary query schema object owned by the corresponding view, * so lifetime of the object is limited to the lifetime of the view and its window. * Do not store the pointer after the window is closed to avoid dangling pointers. \see KexiPart::Part::currentQuery(KexiView*) KexiWindow::isDirty() */ virtual KDbQuerySchema* unsavedQuery(int identifier) = 0; /*! Displays a dialog for entering object's name and title. Used on new object saving. \return true on successul closing or cancelled on cancel returned. It's unlikely to have false returned here. \a messageWhenAskingForName is a i18n'ed text that will be visible within name/caption dialog (see KexiNameDialog). If \a allowOverwriting is true, user will be asked for existing object's overwriting, else it will be impossible to enter a name of existing object. You can check \a overwriteNeeded after calling this method. If it's true, user agreed on overwriting, if it's false, user picked nonexisting name, so no overwrite will be needed. If \a originalName is not empty, the dialog will make sure the entered name is different, what is useful for "Saving As" objects. */ virtual tristate getNewObjectInfo(KexiPart::Item *partItem, const QString &originalName, KexiPart::Part *part, bool allowOverwriting, bool *overwriteNeeded, const QString& messageWhenAskingForName = QString()) = 0; /*! Highlights object of mime \a mime and name \a name. This can be done in the Project Navigator or so. If a window for the object is opened (in any mode), it should be raised. */ virtual void highlightObject(const QString& mime, const QString& name) = 0; //! Shows "print" dialog for \a item. //! \return true on success. virtual tristate printItem(KexiPart::Item* item) = 0; //! Shows "print preview" window. //! \return true on success. virtual tristate printPreviewForItem(KexiPart::Item* item) = 0; //! Shows "page setup" window for \a item. //! \return true on success and cancelled when the action was cancelled. virtual tristate showPageSetupForItem(KexiPart::Item* item) = 0; /*! Executes custom action for the main window, usually provided by a plugin. Also used by KexiFormEventAction. */ virtual tristate executeCustomActionForObject(KexiPart::Item* item, const QString& actionName) = 0; //! @todo temporary solution before the tabbed toolbar framework emerges /*! Appends widget @a widget to tabbed toolbar declared as @a name. @a widget will be reparented but the ownership is not taken. */ virtual void appendWidgetToToolbar(const QString& name, QWidget* widget) = 0; //! @todo temporary solution before the tabbed toolbar framework emerges /*! Shows or hides widget in the tabbed toolbar. */ virtual void setWidgetVisibleInToolbar(QWidget* widget, bool visible) = 0; //! @todo replace with the final Actions API virtual void addToolBarAction(const QString& toolBarName, QAction *action) = 0; //! @todo replace with the final Actions API virtual KToolBar *toolBar(const QString& name) const = 0; /*! Updates info label of the property editor by reusing properties provided by the current property set. - Read documentation of KexiPropertyEditorView class for information about accepted properties. + Read documentation of KexiPropertyPaneWidget class for information about accepted properties. If the current property is 0 and @a textToDisplayForNullSet string is not empty, this string is displayed (without icon or any other additional part). If the current property is 0 and @a textToDisplayForNullSet string is empty, the info label widget becomes hidden. */ virtual void updatePropertyEditorInfoLabel(const QString& textToDisplayForNullSet = QString()) = 0; /*! Add searchable model to the main window. This extends search to a new area. One example is Project Navigator. */ virtual void addSearchableModel(KexiSearchableModel *model) = 0; virtual KexiUserFeedbackAgent* userFeedbackAgent() const = 0; //! Interface to the migrate manager virtual KexiMigrateManagerInterface* migrateManager() = 0; //! Sets reasonable dialog size based on main window size, that is 80% of its size. virtual void setReasonableDialogSize(QDialog *dialog) = 0; protected: //! Sets current global mode virtual void setCurrentMode(Kexi::GlobalViewMode mode) = 0; protected: // Q_SLOTS: virtual void slotObjectRenamed(const KexiPart::Item &item, const QString& oldName) = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KexiMainWindowIface::SaveObjectOptions) #endif diff --git a/src/core/kexipartbase.cpp b/src/core/kexipartbase.cpp index 1d02747e4..ec6d95aef 100644 --- a/src/core/kexipartbase.cpp +++ b/src/core/kexipartbase.cpp @@ -1,75 +1,75 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2014 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kexipartbase.h" #include namespace KexiPart { //! @internal class Q_DECL_HIDDEN PartBase::Private { public: Private() : info(0) { } Info *info; }; } using namespace KexiPart; PartBase::PartBase(QObject *parent, const QVariantList& list) : QObject(parent) , d(new Private) { Q_UNUSED(list); } PartBase::~PartBase() { delete d; } void PartBase::setInfo(Info *info) { d->info = info; } Info* PartBase::info() const { return d->info; } KLocalizedString PartBase::i18nMessage(const QString& englishMessage, KexiWindow* window) const { Q_UNUSED(window); if (QString(englishMessage).startsWith(':')) return KLocalizedString(); return kxi18nc("@info", englishMessage.toLatin1()); } -void PartBase::setupPropertyPane(QToolBox *toolBox) +void PartBase::setupPropertyPane(KexiPropertyPaneWidget *pane) { - Q_UNUSED(toolBox) + Q_UNUSED(pane) } diff --git a/src/core/kexipartbase.h b/src/core/kexipartbase.h index fe175635f..c01ad34d9 100644 --- a/src/core/kexipartbase.h +++ b/src/core/kexipartbase.h @@ -1,109 +1,109 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2003-2014 Jarosław Staniek + Copyright (C) 2003-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KEXIPARTBASE_H #define KEXIPARTBASE_H #include #include "kexi.h" #include #include -class QToolBox; class KexiWindow; +class KexiPropertyPaneWidget; namespace KexiPart { class Info; //! @short The base class for Kexi frontend parts (plugins) //! @see KexiPart::Part KexiInternalPart class KEXICORE_EXPORT PartBase : public QObject, protected KexiUtils::InternalPropertyMap { Q_OBJECT public: virtual ~PartBase(); /*! @return Info structure for this part. */ Info *info() const; /*! \return i18n'd message translated from \a englishMessage. This method is useful for messages like: "

Table \"%1\" has been modified.

", -- such messages can be accurately translated, while this could not: "

%1 \"%2\" has been modified.

". See implementation of this method in KexiTablePart to see what strings are needed for translation. Default implementation returns generic \a englishMessage. In special cases, \a englishMessage can start with ":", to indicate that empty string will be generated if a part does not offer a message for such \a englishMessage. This is used e.g. in KexiMainWindow::closeWindow(). @note As number of %n parameters is unspecified, you should add appropriate number of parameters using .subs(). to result of i18nMessage(). In your implementation, you should use kxi18nc(I18NC_NOOP("@info", "...")) instead of i18n(). Example: @code QString tableName = "Employees"; QString translated = part->i18nMessage("Design of object %1 has been modified.") .subs(tableName).toString(); @endcode */ virtual KLocalizedString i18nMessage(const QString& englishMessage, KexiWindow *window) const; /*! @internal - This method can be reimplemented to setup additional tool box items - in the property pane. Default implementation does nothing. + This method can be reimplemented to setup additional property pane items. + Default implementation does nothing. This method is called whenever current window (KexiWindow) is switched and type (mime type) of its contents differs from the previous one. For example, if a user switched from Table Designer to Form Designer, additional item containing Form Designer's object tree should be added. */ - virtual void setupPropertyPane(QToolBox *toolBox); + virtual void setupPropertyPane(KexiPropertyPaneWidget *pane); protected: /*! Creates new Plugin @param parent parent of this plugin @param list extra arguments passed to the plugin */ PartBase(QObject *parent, const QVariantList& list); /*! Sets Info structure for this part. */ void setInfo(Info *info); Q_DISABLE_COPY(PartBase) class Private; Private * const d; friend class Manager; }; } // namespace KexiPart #endif diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index 6da65aa44..c7abc5110 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -1,82 +1,81 @@ #TODO add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44019) include_directories(${CMAKE_SOURCE_DIR}/src/core ${CMAKE_SOURCE_DIR}/src/kexiutils ${CMAKE_SOURCE_DIR}/src/kexiutils/style ${CMAKE_SOURCE_DIR}/src/main ${CMAKE_SOURCE_DIR}/src/main/startup ${CMAKE_SOURCE_DIR}/src/widget ${CMAKE_BINARY_DIR}/src/widget ${CMAKE_SOURCE_DIR}/src/widget/navigator ${CMAKE_SOURCE_DIR}/src/widget/properties ) set(QT_USE_QTUITOOLS true) set(keximain_LIB_SRCS KexiMainWindow.cpp KexiMainWindow_p.cpp KexiMenuWidget.cpp kexifinddialog.cpp KexiSearchLineEdit.cpp KexiUserFeedbackAgent.cpp KexiBugReportDialog.cpp KexiGlobalViewModeSelector.cpp KexiObjectViewWidget.cpp KexiObjectViewTabWidget.cpp - KexiPropertyPaneWidget.cpp startup/KexiNewProjectAssistant.cpp startup/KexiOpenProjectAssistant.cpp startup/KexiWelcomeAssistant.cpp startup/KexiWelcomeStatusBar.cpp startup/KexiImportExportAssistant.cpp startup/KexiStartupDialog.cpp startup/KexiStartup.cpp startup/KexiTemplatesModel.cpp startup/KexiRecentProjectsModel.cpp startup/KexiAssistantMessageHandler.cpp startup/KexiPasswordPage.cpp #todo printing/kexisimpleprintingengine.cpp #todo printing/kexisimpleprintingpagesetup.cpp #todo printing/kexisimpleprintingpart.cpp #todo printing/kexisimpleprintpreviewwindow.cpp ) ki18n_wrap_ui(keximain_LIB_SRCS kexifinddialog.ui startup/KexiProjectStorageTypeSelectionPage.ui startup/KexiServerDBNamePage.ui startup/KexiMainImportExportPage.ui ) kexi_add_library(keximain SHARED ${keximain_LIB_SRCS}) generate_export_header(keximain) target_link_libraries(keximain PUBLIC kexicore PRIVATE kexiextendedwidgets kexiguiutils KF5::GuiAddons Qt5::UiTools ) if(HAVE_KCRASH) target_link_libraries(keximain PRIVATE KF5::Crash ) endif() target_compile_definitions(keximain PRIVATE CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") install(TARGETS keximain ${INSTALL_TARGETS_DEFAULT_ARGS}) add_subdirectory(status) if (BUILD_TESTING) add_subdirectory(autotests) endif() diff --git a/src/main/KexiMainWindow.cpp b/src/main/KexiMainWindow.cpp index 68dfdb22d..756ff2818 100644 --- a/src/main/KexiMainWindow.cpp +++ b/src/main/KexiMainWindow.cpp @@ -1,4513 +1,4513 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2017 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KexiMainWindow.h" #include "KexiMainWindow_p.h" #include "kexiactionproxy.h" #include "kexipartmanager.h" #include "kexipart.h" #include "kexipartinfo.h" #include "kexipartguiclient.h" #include "kexiproject.h" #include "kexiprojectdata.h" #include "kexi.h" #include "kexiinternalpart.h" #include "kexiactioncategories.h" #include "kexifinddialog.h" #include "kexisearchandreplaceiface.h" #include "KexiBugReportDialog.h" #define KEXI_SKIP_REGISTERICONSRESOURCE #define KEXI_SKIP_SETUPPRIVATEICONSRESOURCE #include "KexiRegisterResource_p.h" #include "KexiObjectViewWidget.h" #include "KexiObjectViewTabWidget.h" -#include "KexiPropertyPaneWidget.h" #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include #include #include "startup/KexiStartup.h" #include "startup/KexiNewProjectAssistant.h" #include "startup/KexiOpenProjectAssistant.h" #include "startup/KexiWelcomeAssistant.h" #include "startup/KexiImportExportAssistant.h" #include "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 #include #include #include #include #if !defined(KexiVDebug) # define KexiVDebug if (0) qDebug() #endif #ifdef HAVE_KCRASH #include //! @todo else, add Breakpad? https://phabricator.kde.org/T1642 #endif KexiDockWidgetStyle::KexiDockWidgetStyle(const QString &baseStyleName) : QProxyStyle(baseStyleName) { } KexiDockWidgetStyle::~KexiDockWidgetStyle() { } void KexiDockWidgetStyle::polish(QWidget* widget) { baseStyle()->polish(widget); widget->setContentsMargins(0, 0, 0, 0); } class Q_DECL_HIDDEN KexiDockWidget::Private { public: Private() {} QSize hint; }; KexiDockWidget::KexiDockWidget(const QString &_tabText, QWidget *parent) : QDockWidget(parent), tabText(_tabText), d(new Private) { // No floatable dockers, Dolphin had problems, we don't want the same... // https://bugs.kde.org/show_bug.cgi?id=288629 // https://bugs.kde.org/show_bug.cgi?id=322299 setFeatures(QDockWidget::NoDockWidgetFeatures);//DockWidgetClosable); setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea); setFocusPolicy(Qt::NoFocus); if (style()->objectName().compare("windowsvista", Qt::CaseInsensitive) == 0) { // windowsvista style has broken accelerator visualization support KAcceleratorManager::setNoAccel(this); } KexiDockWidgetStyle *customStyle = new KexiDockWidgetStyle(style()->objectName()); customStyle->setParent(this); setStyle(customStyle); setTitleBarWidget(new QWidget(this)); // hide the title layout()->setContentsMargins(0, 0, 0, 0); layout()->setSpacing(0); } KexiDockWidget::~KexiDockWidget() { delete d; } void KexiDockWidget::paintEvent(QPaintEvent *pe) { Q_UNUSED(pe); QStylePainter p(this); if (isFloating()) { QStyleOptionFrame framOpt; framOpt.initFrom(this); p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt); } // Title must be painted after the frame, since the areas overlap, and // the title may wish to extend out to all sides (eg. XP style) QStyleOptionDockWidget titleOpt; initStyleOption(&titleOpt); p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt); } void KexiDockWidget::setSizeHint(const QSize& hint) { d->hint = hint; } QSize KexiDockWidget::sizeHint() const { return d->hint.isValid() ? d->hint : QDockWidget::sizeHint(); } //------------------------------------------------- static bool setupIconTheme(KLocalizedString *errorMessage, KLocalizedString *detailsErrorMessage) { // Register kexi resource first to have priority over the standard breeze theme. // For example "table" icon exists in both resources. if (!registerResource("icons/kexi_breeze.rcc", QStandardPaths::AppDataLocation, QString(), QString(), errorMessage, detailsErrorMessage) || !registerGlobalBreezeIconsResource(errorMessage, detailsErrorMessage)) { return false; } setupBreezeIconTheme(); // tell KIconLoader an co. about the theme KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); cg.writeEntry("Theme", "breeze"); cg.sync(); return true; } //! @todo 3.1 replace with KexiStyle bool setupApplication() { #if defined Q_OS_WIN || defined Q_OS_MACOS // Only this style matches current Kexi theme and can be supported/tested const char *name = "breeze"; QScopedPointer style(QStyleFactory::create(name)); if (!style || style->objectName() != name) { qWarning() << qPrintable(QString("Could not find application style %1. " "Kexi will not start. Please check if Kexi is properly installed. ") .arg(name)); return false; } qApp->setStyle(style.take()); #endif return true; } //static int KexiMainWindow::create(const QStringList &arguments, const QString &componentName, const QList &extraOptions) { qApp->setQuitOnLastWindowClosed(false); KLocalizedString::setApplicationDomain("kexi"); //! @todo KEXI3 app->setAttribute(Qt::AA_UseHighDpiPixmaps, true); KexiAboutData aboutData; if (!componentName.isEmpty()) { aboutData.setComponentName(componentName); } KAboutData::setApplicationData(aboutData); if (!setupApplication()) { return 1; } #ifdef HAVE_KCRASH KCrash::initialize(); #endif KLocalizedString errorMessage; KLocalizedString detailsErrorMessage; if (!setupIconTheme(&errorMessage, &detailsErrorMessage)) { if (detailsErrorMessage.isEmpty()) { KMessageBox::error(nullptr, errorMessage.toString()); } else { KMessageBox::detailedError(nullptr, errorMessage.toString(), detailsErrorMessage.toString()); } qWarning() << qPrintable(errorMessage.toString(Kuit::PlainText)); return 1; } QApplication::setWindowIcon(koIcon("kexi")); const tristate res = KexiStartupHandler::global()->init(arguments, extraOptions); if (!res || ~res) { return (~res) ? 0 : 1; } //qDebug() << "startupActions OK"; /* Exit requested, e.g. after database removing. */ if (KexiStartupHandler::global()->action() == KexiStartupData::Exit) { return 0; } KexiMainWindow *win = new KexiMainWindow(); #ifdef KEXI_DEBUG_GUI QWidget* debugWindow = 0; KConfigGroup generalGroup = KSharedConfig::openConfig()->group("General"); if (generalGroup.readEntry("ShowInternalDebugger", false)) { debugWindow = KexiUtils::createDebugWindow(win); debugWindow->show(); } #endif if (true != win->startup()) { delete win; return 1; } win->restoreSettings(); win->show(); #ifdef KEXI_DEBUG_GUI win->raise(); static_cast(win)->activateWindow(); #endif /*foreach (QWidget *widget, QApplication::topLevelWidgets()) { qDebug() << widget; }*/ return 0; } //------------------------------------------------- KexiMainMenuActionShortcut::KexiMainMenuActionShortcut(const QKeySequence& key, QAction *action, QWidget *parent) : QShortcut(key, parent) , m_action(action) { connect(this, SIGNAL(activated()), this, SLOT(slotActivated())); } KexiMainMenuActionShortcut::~KexiMainMenuActionShortcut() { } void KexiMainMenuActionShortcut::slotActivated() { if (!m_action->isEnabled()) { return; } m_action->trigger(); } //------------------------------------------------- KexiMainWindow::KexiMainWindow(QWidget *parent) : QMainWindow(parent) , KexiMainWindowIface() , KexiGUIMessageHandler(this) , d(new KexiMainWindow::Private(this)) { setObjectName("KexiMainWindow"); setAttribute(Qt::WA_DeleteOnClose); kexiTester() << KexiTestObject(this); if (d->userMode) qDebug() << "starting up in the User Mode"; setAsDefaultHost(); //this is default host now. //get informed connect(&Kexi::partManager(), SIGNAL(partLoaded(KexiPart::Part*)), this, SLOT(slotPartLoaded(KexiPart::Part*))); connect(&Kexi::partManager(), SIGNAL(newObjectRequested(KexiPart::Info*)), this, SLOT(newObject(KexiPart::Info*))); setAcceptDrops(true); setupActions(); setupMainWidget(); setupMainMenu(); updateAppCaption(); if (!d->userMode) { setupContextHelp(); //setupPropertyEditor(); } invalidateActions(); d->timer.singleShot(0, this, SLOT(slotLastActions())); if (KexiStartupHandler::global()->forcedFullScreen()) { toggleFullScreen(true); } // --- global config //! @todo move to specialized KexiConfig class KConfigGroup tablesGroup(d->config->group("Tables")); const int defaultMaxLengthForTextFields = tablesGroup.readEntry("DefaultMaxLengthForTextFields", int(-1)); if (defaultMaxLengthForTextFields >= 0) { KDbField::setDefaultMaxLength(defaultMaxLengthForTextFields); } // --- /global config } KexiMainWindow::~KexiMainWindow() { d->forceWindowClosing = true; closeProject(); delete d; Kexi::deleteGlobalObjects(); } KexiProject *KexiMainWindow::project() { return d->prj; } QList KexiMainWindow::allActions() const { return actionCollection()->actions(); } KActionCollection *KexiMainWindow::actionCollection() const { return d->actionCollection; } KexiWindow* KexiMainWindow::currentWindow() const { if (!d->objectViewWidget || !d->objectViewWidget->tabWidget()) { return 0; } return windowForTab(d->objectViewWidget->tabWidget()->currentIndex()); } KexiWindow* KexiMainWindow::windowForTab(int tabIndex) const { if (!d->objectViewWidget || !d->objectViewWidget->tabWidget()) return 0; return d->objectViewWidget->tabWidget()->window(tabIndex); } 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)); action->setShortcutContext(Qt::ApplicationShortcut); //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)); action->setText(xi18n("&New Project...")); 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->setText(xi18n("&Open Project...")); action->setIcon(koIcon("project-open")); action->setToolTip(xi18n("Open an existing project")); action->setWhatsThis( xi18n("Opens an existing project. Currently opened project is not affected.")); connect(action, SIGNAL(triggered()), this, SLOT(slotProjectOpen())); setupMainMenuActionShortcut(action); ac->addAction("project_open_recent", action = KStandardAction::openRecent(this, SLOT(slotProjectOpen()), this)); action->setToolTip(xi18n("Open a project that was recently opened.")); action->setWhatsThis(xi18n("Opens a project that was recently opened.")); { 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("project-development-close"), xi18n("&Close Project"), 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", KexiIcon("database-relations"), futureI18n("&Relationships...")); d->action_project_relations->setToolTip(futureI18n("Project relationships")); d->action_project_relations->setWhatsThis(futureI18n("Shows project relationships.")); connect(d->action_project_relations, SIGNAL(triggered()), this, SLOT(slotProjectRelations())); #else d->action_project_relations = d->dummy_action; #endif d->action_tools_import_project = addAction("tools_import_project", KexiIcon("database-import"), xi18n("&Import Database...")); d->action_tools_import_project->setToolTip(xi18n("Import entire database as a Kexi project")); d->action_tools_import_project->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("document-empty"), /*! @todo: change to "file_import" with a table or so */ xi18nc("Import->Table Data From File...", "Import Data From &File...")); d->action_project_import_data_table->setToolTip(xi18n("Import table data from a file")); d->action_project_import_data_table->setWhatsThis(xi18n("Imports table data from a file.")); connect(d->action_project_import_data_table, SIGNAL(triggered()), this, SLOT(slotProjectImportDataTable())); } d->action_project_export_data_table = addAction("project_export_data_table", KexiIcon("table"), /*! @todo: change to "file_export" with a table or so */ xi18nc("Export->Table or Query Data to File...", "Export Data to &File...")); d->action_project_export_data_table->setToolTip( xi18n("Export data from the active table or query to a file")); d->action_project_export_data_table->setWhatsThis( xi18n("Exports data from the active table or query to a file.")); connect(d->action_project_export_data_table, SIGNAL(triggered()), this, SLOT(slotProjectExportDataTable())); //! @todo new QAction(xi18n("From File..."), "document-open", 0, //! this, SLOT(slotImportFile()), actionCollection(), "project_import_file"); //! @todo new QAction(xi18n("From Server..."), "network-server-database", 0, //! this, SLOT(slotImportServer()), actionCollection(), "project_import_server"); #ifdef KEXI_SHOW_UNIMPLEMENTED ac->addAction("project_print", d->action_project_print = KStandardAction::print(this, SLOT(slotProjectPrint()), this)); d->action_project_print->setToolTip(futureI18n("Print data from the active table or query")); d->action_project_print->setWhatsThis(futureI18n("Prints data from the active table or query.")); ac->addAction("project_print_preview", d->action_project_print_preview = KStandardAction::printPreview( this, SLOT(slotProjectPrintPreview()), this)); d->action_project_print_preview->setToolTip( futureI18n("Show print preview for the active table or query")); d->action_project_print_preview->setWhatsThis( futureI18n("Shows print preview for the active table or query.")); d->action_project_print_setup = addAction("project_print_setup", koIcon("configure"), futureI18n("Print Set&up...")); //!< @todo document-page-setup could be a better icon d->action_project_print_setup->setToolTip( futureI18n("Show print setup for the active table or query")); d->action_project_print_setup->setWhatsThis( futureI18n("Shows print setup for the active table or query.")); connect(d->action_project_print_setup, SIGNAL(triggered()), this, SLOT(slotProjectPageSetup())); #else d->action_project_print = d->dummy_action; d->action_project_print_preview = d->dummy_action; d->action_project_print_setup = d->dummy_action; #endif //EDIT MENU d->action_edit_cut = createSharedAction(KStandardAction::Cut); d->action_edit_copy = createSharedAction(KStandardAction::Copy); d->action_edit_paste = createSharedAction(KStandardAction::Paste); if (d->userMode) d->action_edit_paste_special_data_table = 0; else { d->action_edit_paste_special_data_table = addAction( "edit_paste_special_data_table", d->action_edit_paste->icon(), xi18nc("Paste Special->As Data &Table...", "Paste Special...")); d->action_edit_paste_special_data_table->setToolTip( xi18n("Paste clipboard data as a table")); d->action_edit_paste_special_data_table->setWhatsThis( xi18n("Pastes clipboard data as a table.")); connect(d->action_edit_paste_special_data_table, SIGNAL(triggered()), this, SLOT(slotEditPasteSpecialDataTable())); } d->action_edit_copy_special_data_table = addAction( "edit_copy_special_data_table", KexiIcon("table"), xi18nc("Copy Special->Table or Query Data...", "Copy Special...")); d->action_edit_copy_special_data_table->setToolTip( xi18n("Copy selected table or query data to clipboard")); d->action_edit_copy_special_data_table->setWhatsThis( xi18n("Copies selected table or query data to clipboard.")); connect(d->action_edit_copy_special_data_table, SIGNAL(triggered()), this, SLOT(slotEditCopySpecialDataTable())); d->action_edit_undo = createSharedAction(KStandardAction::Undo); d->action_edit_undo->setWhatsThis(xi18n("Reverts the most recent editing action.")); d->action_edit_redo = createSharedAction(KStandardAction::Redo); d->action_edit_redo->setWhatsThis(xi18n("Reverts the most recent undo action.")); ac->addAction("edit_find", d->action_edit_find = KStandardAction::find( this, SLOT(slotEditFind()), this)); d->action_edit_find->setToolTip(xi18n("Find text")); d->action_edit_find->setWhatsThis(xi18n("Looks up the first occurrence of a piece of text.")); ac->addAction("edit_findnext", d->action_edit_findnext = KStandardAction::findNext( this, SLOT(slotEditFindNext()), this)); ac->addAction("edit_findprevious", d->action_edit_findprev = KStandardAction::findPrev( this, SLOT(slotEditFindPrevious()), this)); ac->addAction("edit_replace", d->action_edit_replace = KStandardAction::replace( this, SLOT(slotEditReplace()), this)); d->action_edit_replace_all = addAction("edit_replace_all", xi18n("Replace All")); d->action_edit_select_all = createSharedAction(KStandardAction::SelectAll); d->action_edit_delete = createSharedAction(xi18n("&Delete"), koIconName("edit-delete"), QKeySequence(), "edit_delete"); d->action_edit_delete->setToolTip(xi18n("Delete selected object")); d->action_edit_delete->setWhatsThis(xi18n("Deletes currently selected object.")); d->action_edit_delete_row = createSharedAction(xi18n("Delete Record"), KexiIconName("edit-table-delete-row"), QKeySequence(Qt::CTRL + Qt::Key_Delete), "edit_delete_row"); d->action_edit_delete_row->setToolTip(xi18n("Delete the current record")); d->action_edit_delete_row->setWhatsThis(xi18n("Deletes the current record.")); d->action_edit_clear_table = createSharedAction(xi18n("Clear Table Contents..."), KexiIconName("edit-table-clear"), QKeySequence(), "edit_clear_table"); d->action_edit_clear_table->setToolTip(xi18n("Clear table contents")); d->action_edit_clear_table->setWhatsThis(xi18n("Clears table contents.")); setActionVolatile(d->action_edit_clear_table, true); d->action_edit_edititem = createSharedAction(xi18n("Edit Item"), QString(), QKeySequence(), /* CONFLICT in TV: Qt::Key_F2, */ "edit_edititem"); d->action_edit_edititem->setToolTip(xi18n("Edit currently selected item")); d->action_edit_edititem->setWhatsThis(xi18n("Edits currently selected item.")); d->action_edit_insert_empty_row = createSharedAction(xi18n("&Insert Empty Row"), KexiIconName("edit-table-insert-row"), QKeySequence(Qt::SHIFT | Qt::CTRL | Qt::Key_Insert), "edit_insert_empty_row"); setActionVolatile(d->action_edit_insert_empty_row, true); d->action_edit_insert_empty_row->setToolTip(xi18n("Insert one empty row above")); d->action_edit_insert_empty_row->setWhatsThis( xi18n("Inserts one empty row above currently selected table row.")); //VIEW MENU /* UNUSED, see KexiToggleViewModeAction if (!d->userMode) { d->action_view_mode = new QActionGroup(this); ac->addAction( "view_data_mode", d->action_view_data_mode = new KToggleAction( KexiIcon("data-view"), xi18n("&Data View"), d->action_view_mode) ); // d->action_view_data_mode->setObjectName("view_data_mode"); d->action_view_data_mode->setShortcut(QKeySequence("F6")); //d->action_view_data_mode->setExclusiveGroup("view_mode"); d->action_view_data_mode->setToolTip(xi18n("Switch to data view")); d->action_view_data_mode->setWhatsThis(xi18n("Switches to data view.")); d->actions_for_view_modes.insert( Kexi::DataViewMode, d->action_view_data_mode ); connect(d->action_view_data_mode, SIGNAL(triggered()), this, SLOT(slotViewDataMode())); } else { d->action_view_mode = 0; d->action_view_data_mode = 0; } if (!d->userMode) { ac->addAction( "view_design_mode", d->action_view_design_mode = new KToggleAction( KexiIcon("design-view"), xi18n("D&esign View"), d->action_view_mode) ); // d->action_view_design_mode->setObjectName("view_design_mode"); d->action_view_design_mode->setShortcut(QKeySequence("F7")); //d->action_view_design_mode->setExclusiveGroup("view_mode"); d->action_view_design_mode->setToolTip(xi18n("Switch to design view")); d->action_view_design_mode->setWhatsThis(xi18n("Switches to design view.")); d->actions_for_view_modes.insert( Kexi::DesignViewMode, d->action_view_design_mode ); connect(d->action_view_design_mode, SIGNAL(triggered()), this, SLOT(slotViewDesignMode())); } else d->action_view_design_mode = 0; if (!d->userMode) { ac->addAction( "view_text_mode", d->action_view_text_mode = new KToggleAction( KexiIcon("sql-view"), xi18n("&Text View"), d->action_view_mode) ); d->action_view_text_mode->setObjectName("view_text_mode"); d->action_view_text_mode->setShortcut(QKeySequence("F8")); //d->action_view_text_mode->setExclusiveGroup("view_mode"); d->action_view_text_mode->setToolTip(xi18n("Switch to text view")); d->action_view_text_mode->setWhatsThis(xi18n("Switches to text view.")); d->actions_for_view_modes.insert( Kexi::TextViewMode, d->action_view_text_mode ); connect(d->action_view_text_mode, SIGNAL(triggered()), this, SLOT(slotViewTextMode())); } else d->action_view_text_mode = 0; */ if (d->isProjectNavigatorVisible) { ac->addAction("view_navigator", d->action_show_nav = new KToggleAction(xi18n("Show Project Navigator"), this)); d->action_show_nav->setChecked(true); d->action_show_nav->setShortcut(QKeySequence("Alt+0")); d->action_show_nav->setToolTip(xi18n("Show the Project Navigator pane")); d->action_show_nav->setWhatsThis(xi18n("Shows the Project Navigator pane.")); connect(d->action_show_nav, SIGNAL(triggered()), this, SLOT(slotToggleProjectNavigator())); } else { d->action_show_nav = 0; } if (d->isProjectNavigatorVisible) { // Shortcut taken from "Activate Projects pane" http://doc.qt.io/qtcreator/creator-keyboard-shortcuts.html d->action_activate_nav = addAction("activate_navigator", xi18n("Activate Project Navigator"), "Alt+X"); d->action_activate_nav->setToolTip(xi18n("Activate the Project Navigator pane")); d->action_activate_nav->setWhatsThis(xi18n("Activates the Project Navigator pane. If it is hidden, shows it first.")); connect(d->action_activate_nav, SIGNAL(triggered()), this, SLOT(slotActivateNavigator())); } else { d->action_activate_nav = 0; } d->action_activate_mainarea = addAction("activate_mainarea", xi18n("Activate main area") // , "Alt+2"? //! @todo activate_mainarea: pressing Esc in project nav or propeditor should move back to the main area ); d->action_activate_mainarea->setToolTip(xi18n("Activate the main area")); d->action_activate_mainarea->setWhatsThis(xi18n("Activates the main area.")); connect(d->action_activate_mainarea, SIGNAL(triggered()), this, SLOT(slotActivateMainArea())); //! @todo windows with "_3" prefix have conflicting auto shortcut set to Alt+3 -> remove that! if (!d->userMode) { ac->addAction("view_propeditor", d->action_show_propeditor = new KToggleAction(xi18n("Show Property Pane"), this)); d->action_show_propeditor->setShortcut(QKeySequence("Alt+3")); d->action_show_propeditor->setToolTip(xi18n("Show the Property pane")); d->action_show_propeditor->setWhatsThis(xi18n("Shows the Property pane.")); connect(d->action_show_propeditor, SIGNAL(triggered()), this, SLOT(slotTogglePropertyEditor())); } else { d->action_show_propeditor = 0; } if (!d->userMode) { d->action_activate_propeditor = addAction("activate_propeditor", xi18n("Activate Property Pane"), "Alt+-"); d->action_activate_propeditor->setToolTip(xi18n("Activate the Property pane")); d->action_activate_propeditor->setWhatsThis(xi18n("Activates the Property pane. If it is hidden, shows it first.")); connect(d->action_activate_propeditor, SIGNAL(triggered()), this, SLOT(slotActivatePropertyPane())); } else { d->action_activate_propeditor = 0; } d->action_tools_locate = addAction("tools_locate", xi18n("Locate..."), "Ctrl+K"); d->action_tools_locate->setToolTip(xi18n("Switch to Global Locate box")); d->action_tools_locate->setWhatsThis(xi18n("Switches to Global Locate 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 #ifdef KEXI_SHOW_UNIMPLEMENTED d->action_format_font = createSharedAction(xi18n("&Font..."), koIconName("fonts-package"), QKeySequence(), "format_font"); d->action_format_font->setToolTip(xi18n("Change font for selected object")); d->action_format_font->setWhatsThis(xi18n("Changes font for selected object.")); #else d->action_format_font = d->dummy_action; #endif //TOOLS MENU //WINDOW MENU d->action_close_tab = addAction("close_tab", koIcon("tab-close"), xi18n("&Close Tab"), "Ctrl+W"); d->action_close_tab->setToolTip(xi18n("Close the current tab")); d->action_close_tab->setWhatsThis(xi18n("Closes the current tab.")); connect(d->action_close_tab, SIGNAL(triggered()), this, SLOT(closeCurrentWindow())); d->action_close_all_tabs = addAction("close_all_tabs", QIcon(), xi18n("Cl&ose All Tabs")); d->action_close_all_tabs->setToolTip(xi18n("Close all tabs")); d->action_close_all_tabs->setWhatsThis(xi18n("Closes all tabs.")); connect(d->action_close_all_tabs, SIGNAL(triggered()), this, SLOT(closeAllWindows())); d->action_next_tab = addAction("next_tab", koIcon("go-next"), KStandardShortcut::label(KStandardShortcut::TabNext)); d->action_next_tab->setWhatsThis(KStandardShortcut::whatsThis(KStandardShortcut::TabNext)); d->action_next_tab->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::TabNext)); connect(d->action_next_tab, SIGNAL(triggered()), this, SLOT(activateNextTab())); d->action_previous_tab = addAction("previous_tab", koIcon("go-previous"), KStandardShortcut::label(KStandardShortcut::TabPrev)); d->action_previous_tab->setWhatsThis(KStandardShortcut::whatsThis(KStandardShortcut::TabPrev)); d->action_previous_tab->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::TabPrev)); connect(d->action_previous_tab, SIGNAL(triggered()), this, SLOT(activatePreviousTab())); d->action_window_fullscreen = KStandardAction::fullScreen(this, SLOT(toggleFullScreen(bool)), this, ac); ac->addAction("full_screen", d->action_window_fullscreen); //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 // ----- declare action categories, so form's "assign action to button" // (and macros in the future) will be able to recognize category // of actions and filter them ----------------------------------- //! @todo shouldn't we move this to core? Kexi::ActionCategories *acat = Kexi::actionCategories(); acat->addAction("data_execute", Kexi::PartItemActionCategory); //! @todo unused for now acat->addWindowAction("data_filter", KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addWindowAction("data_save_row", KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addWindowAction("data_cancel_row_changes", KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addWindowAction("delete_table_row", KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); //! @todo support this in KexiPart::FormObjectType as well acat->addWindowAction("data_sort_az", KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in KexiPart::FormObjectType as well acat->addWindowAction("data_sort_za", KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in KexiPart::FormObjectType as well acat->addWindowAction("edit_clear_table", KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in KexiPart::FormObjectType as well acat->addWindowAction("edit_copy_special_data_table", KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in FormObjectType as well acat->addWindowAction("project_export_data_table", KexiPart::TableObjectType, KexiPart::QueryObjectType); // GlobalActions, etc. acat->addAction("edit_copy", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory); acat->addAction("edit_cut", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory); acat->addAction("edit_paste", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory); acat->addAction("edit_delete", Kexi::GlobalActionCategory | Kexi::PartItemActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_delete_row", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_edititem", Kexi::PartItemActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType); acat->addAction("edit_find", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_findnext", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_findprevious", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_replace", Kexi::GlobalActionCategory | Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType, KexiPart::FormObjectType); acat->addAction("edit_paste_special_data_table", Kexi::GlobalActionCategory); acat->addAction("help_about_app", Kexi::GlobalActionCategory); acat->addAction("help_about_kde", Kexi::GlobalActionCategory); acat->addAction("help_contents", Kexi::GlobalActionCategory); acat->addAction("help_report_bug", Kexi::GlobalActionCategory); acat->addAction("help_whats_this", Kexi::GlobalActionCategory); acat->addAction("help_donate", Kexi::GlobalActionCategory); // disabled for now acat->addAction("switch_application_language", Kexi::GlobalActionCategory); acat->addAction("options_configure_keybinding", Kexi::GlobalActionCategory); acat->addAction("project_close", Kexi::GlobalActionCategory); acat->addAction("project_import_data_table", Kexi::GlobalActionCategory); acat->addAction("project_new", Kexi::GlobalActionCategory); acat->addAction("project_open", Kexi::GlobalActionCategory); #ifdef KEXI_QUICK_PRINTING_SUPPORT //! @todo support this in FormObjectType, ReportObjectType as well as others acat->addAction("project_print", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in FormObjectType, ReportObjectType as well as others acat->addAction("project_print_preview", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType); //! @todo support this in FormObjectType, ReportObjectType as well as others acat->addAction("project_print_setup", Kexi::WindowActionCategory, KexiPart::TableObjectType, KexiPart::QueryObjectType); #endif acat->addAction("quit", Kexi::GlobalActionCategory); acat->addAction("tools_compact_database", Kexi::GlobalActionCategory); acat->addAction("tools_import_project", Kexi::GlobalActionCategory); acat->addAction("tools_import_tables", Kexi::GlobalActionCategory); acat->addAction("view_data_mode", Kexi::GlobalActionCategory); acat->addAction("view_design_mode", Kexi::GlobalActionCategory); acat->addAction("view_text_mode", Kexi::GlobalActionCategory); acat->addAction("view_mainarea", Kexi::GlobalActionCategory); acat->addAction("view_navigator", Kexi::GlobalActionCategory); acat->addAction("activate_navigator", Kexi::GlobalActionCategory); acat->addAction("view_propeditor", Kexi::GlobalActionCategory); acat->addAction("activate_mainarea", Kexi::GlobalActionCategory); acat->addAction("activate_propeditor", Kexi::GlobalActionCategory); acat->addAction("close_tab", Kexi::GlobalActionCategory | Kexi::WindowActionCategory); acat->setAllObjectTypesSupported("close_tab", true); acat->addAction("close_all_tabs", Kexi::GlobalActionCategory | Kexi::WindowActionCategory); acat->setAllObjectTypesSupported("close_all_tabs", true); acat->addAction("next_tab", Kexi::GlobalActionCategory); acat->addAction("previous_tab", 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::setupMainMenu() { KActionCollection *ac = actionCollection(); QMenuBar *menu = menuBar(); { QMenu *fileMenu = menu->addMenu(xi18n("&File")); if (!d->userMode) { d->addAction(fileMenu, "project_new"); fileMenu->addSeparator(); d->addAction(fileMenu, "project_open"); d->addAction(fileMenu, "project_open_recent"); fileMenu->addSeparator(); } fileMenu->addAction(d->action_save); if (!d->userMode) { fileMenu->addAction(d->action_save_as); } fileMenu->addSeparator(); if (!d->userMode) { fileMenu->addAction(d->action_tools_import_project); fileMenu->addSeparator(); } #ifdef KEXI_SHOW_UNIMPLEMENTED fileMenu->addAction(d->action_project_print); fileMenu->addAction(d->action_project_print_preview); fileMenu->addAction(d->action_project_print_setup); fileMenu->addSeparator(); #endif #ifdef KEXI_SHOW_UNIMPLEMENTED fileMenu->addAction(d->action_project_properties); fileMenu->addSeparator(); #endif fileMenu->addAction(d->action_close_tab); fileMenu->addAction(d->action_close_all_tabs); if (!d->userMode) { fileMenu->addAction(d->action_close); } fileMenu->addSeparator(); d->addAction(fileMenu, "quit"); } { QMenu *editMenu = menu->addMenu(xi18n("&Edit")); editMenu->addAction(d->action_edit_undo); editMenu->addAction(d->action_edit_redo); editMenu->addSeparator(); editMenu->addAction(d->action_edit_cut); editMenu->addAction(d->action_edit_copy); editMenu->addAction(d->action_edit_copy_special_data_table); editMenu->addAction(d->action_edit_paste); if (!d->userMode) { editMenu->addAction(d->action_edit_paste_special_data_table); } editMenu->addSeparator(); editMenu->addAction(d->action_edit_select_all); editMenu->addSeparator(); { QMenu *findReplaceMenu = editMenu->addMenu(xi18n("&Find/Replace")); findReplaceMenu->addAction(d->action_edit_find); findReplaceMenu->addAction(d->action_edit_findnext); findReplaceMenu->addAction(d->action_edit_findprev); #ifdef KEXI_SHOW_UNIMPLEMENTED findReplaceMenu->addSeparator(); findReplaceMenu->addAction(d->action_edit_replace); findReplaceMenu->addAction(d->action_edit_replace_all); #endif } editMenu->addSeparator(); editMenu->addAction(d->action_edit_delete); // in local toolbar already: editMenu->addAction(d->action_data_save_row); // in local toolbar already: editMenu->addAction(d->action_data_cancel_row_changes); //TODO move to local menu: editMenu->addAction(d->action_edit_edititem); //TODO move to local menu: editMenu->addAction(d->action_edit_insert_empty_row); //TODO move to local menu: editMenu->addAction(d->action_data_execute); //editMenu->addSeparator(); //TODO move to local menu: editMenu->addAction(d->action_edit_delete); //TODO move to local menu: editMenu->addAction(d->action_edit_delete_row); //in local menu already editMenu->addAction(d->action_edit_clear_table); } #ifdef KEXI_SHOW_UNIMPLEMENTED { QMenu *formatMenu = menu->addMenu(xi18n("F&ormat")); formatMenu->addAction(d->action_format_font); } #endif { QMenu *toolsMenu = menu->addMenu(xi18n("&Tools")); toolsMenu->addAction(d->action_tools_locate); toolsMenu->addSeparator(); #ifdef KEXI_SHOW_UNIMPLEMENTED toolsMenu->addAction(d->action_project_relations); #endif toolsMenu->addAction(d->action_tools_compact_database); } { QMenu *dataMenu = menu->addMenu(xi18n("&Data")); if (!d->userMode) { dataMenu->addAction(d->action_project_import_data_table); dataMenu->addAction(d->action_tools_data_import); dataMenu->addSeparator(); } dataMenu->addAction(d->action_project_export_data_table); } { QMenu *windowMenu = menu->addMenu(xi18n("&Window")); windowMenu->addAction(d->action_next_tab); windowMenu->addAction(d->action_previous_tab); windowMenu->addSeparator(); windowMenu->addAction(d->action_show_nav); windowMenu->addAction(d->action_show_propeditor); } { QMenu *settingsMenu = menu->addMenu(xi18n("&Settings")); settingsMenu->addAction(d->action_window_fullscreen); settingsMenu->addSeparator(); #ifdef KEXI_SHOW_UNIMPLEMENTED settingsMenu->addAction(d->action_settings); #endif } { // add help menu actions... (KexiTabbedToolBar depends on them) KHelpMenu *helpMenu = new KHelpMenu(this, KAboutData::applicationData(), true/*showWhatsThis*/); QAction* help_report_bug_action = helpMenu->action(KHelpMenu::menuReportBug); ac->addAction(help_report_bug_action->objectName(), help_report_bug_action); QObject::disconnect(help_report_bug_action, 0, 0, 0); QObject::connect(help_report_bug_action, &QAction::triggered, this, &KexiMainWindow::slotReportBug); help_report_bug_action->setText(xi18nc("Report a bug or wish for Kexi application", "Report a &Bug or Wish...")); help_report_bug_action->setIcon(koIcon("tools-report-bug")); // good icon for toolbar help_report_bug_action->setWhatsThis(xi18n("Files a bug or wish for Kexi application.")); QAction* help_whats_this_action = helpMenu->action(KHelpMenu::menuWhatsThis); ac->addAction(help_whats_this_action->objectName(), help_whats_this_action); help_whats_this_action->setWhatsThis(xi18n("Activates a \"What's This?\" tool.")); QAction* help_contents_action = helpMenu->action(KHelpMenu::menuHelpContents); ac->addAction(help_contents_action->objectName(), help_contents_action); help_contents_action->setText(xi18n("Help")); help_contents_action->setWhatsThis(xi18n("Shows Kexi Handbook.")); QAction* help_about_app_action = helpMenu->action(KHelpMenu::menuAboutApp); ac->addAction(help_about_app_action->objectName(), help_about_app_action); help_about_app_action->setWhatsThis(xi18n("Shows information about Kexi application.")); QAction* help_about_kde_action = helpMenu->action(KHelpMenu::menuAboutKDE); ac->addAction(help_about_kde_action->objectName(), help_about_kde_action); help_about_kde_action->setWhatsThis(xi18n("Shows information about KDE.")); menu->addMenu(helpMenu->menu()); } } 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); if (d->objectViewWidget) { d->action_close_tab->setEnabled(has_window); d->action_close_all_tabs->setEnabled(has_window); } //DATA MENU if (d->action_project_import_data_table) d->action_project_import_data_table->setEnabled(d->prj && !readOnly); if (d->action_tools_data_import) d->action_tools_data_import->setEnabled(d->prj && !readOnly); d->action_project_export_data_table->setEnabled( currentWindow() && currentWindow()->part()->info()->isDataExportSupported()); if (d->action_edit_paste_special_data_table) d->action_edit_paste_special_data_table->setEnabled(d->prj && !readOnly); #ifdef KEXI_SHOW_UNIMPLEMENTED const bool printingActionsEnabled = currentWindow() && currentWindow()->part()->info()->isPrintingSupported() && !currentWindow()->neverSaved(); d->action_project_print->setEnabled(printingActionsEnabled); d->action_project_print_preview->setEnabled(printingActionsEnabled); d->action_project_print_setup->setEnabled(printingActionsEnabled); #endif //EDIT MENU //! @todo "copy special" is currently enabled only for data view mode; //! what about allowing it to enable in design view for "kexi/table" ? if (currentWindow() && currentWindow()->currentViewMode() == Kexi::DataViewMode) { KexiPart::Info *activePartInfo = currentWindow()->part()->info(); d->action_edit_copy_special_data_table->setEnabled( activePartInfo ? activePartInfo->isDataExportSupported() : false); } else { d->action_edit_copy_special_data_table->setEnabled(false); } d->action_edit_find->setEnabled(d->prj); //VIEW MENU if (d->action_show_nav) d->action_show_nav->setEnabled(d->prj); d->action_activate_mainarea->setEnabled(d->prj); //CREATE MENU if (d->tabbedToolBar && d->tabbedToolBar->createWidgetToolBar()) d->tabbedToolBar->createWidgetToolBar()->setEnabled(d->prj); // DATA MENU // WINDOW MENU if (d->objectViewWidget) { d->action_next_tab->setEnabled(d->objectViewWidget->tabWidget()->count() > 1); d->action_previous_tab->setEnabled(d->objectViewWidget->tabWidget()->count() > 1); } //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->objectViewWidget && d->objectViewWidget->projectNavigator()) { d->objectViewWidget->projectNavigator()->setEnabled(d->prj); } if (d->objectViewWidget && d->objectViewWidget->propertyPane()) { d->objectViewWidget->propertyPane()->setEnabled(d->prj); } } tristate KexiMainWindow::startup() { tristate result = true; switch (KexiStartupHandler::global()->action()) { case KexiStartupHandler::CreateBlankProject: d->updatePropEditorVisibility(Kexi::NoViewMode); break; #ifdef KEXI_PROJECT_TEMPLATES case KexiStartupHandler::CreateFromTemplate: result = createProjectFromTemplate(*KexiStartupHandler::global()->projectData()); break; #endif case KexiStartupHandler::OpenProject: result = openProject(*KexiStartupHandler::global()->projectData()); break; case KexiStartupHandler::ImportProject: result = showProjectMigrationWizard( KexiStartupHandler::global()->importActionData().mimeType, KexiStartupHandler::global()->importActionData().fileName ); break; case KexiStartupHandler::ShowWelcomeScreen: //! @todo show welcome screen as soon as is available QTimer::singleShot(100, this, SLOT(slotProjectWelcome())); break; default: d->updatePropEditorVisibility(Kexi::NoViewMode); } return result; } static QString internalReason(const KDbResult &result) { const QString msg = result.message(); if (msg.isEmpty()) { return QString(); } return xi18n("
(reason: %1)", msg); } tristate KexiMainWindow::openProject(const KexiProjectData& projectData) { //qDebug() << projectData; QScopedPointer prj(createKexiProjectObject(projectData)); if (~KexiDBPasswordDialog::getPasswordIfNeeded(prj->data()->connectionData(), this)) { return cancelled; } bool incompatibleWithKexi; tristate res = prj->open(&incompatibleWithKexi); if (prj->data()->connectionData()->isPasswordNeeded()) { // password was supplied in this session, and shouldn't be stored or reused afterwards, // so let's remove it prj->data()->connectionData()->setPassword(QString()); } if (~res) { return cancelled; } else if (!res) { if (incompatibleWithKexi) { if (KMessageBox::Yes == KMessageBox::questionYesNo(this, xi18nc("@info (don't add tags around %1, it's done already)", "Database project %1 does not appear to have been created using Kexi." "Do you want to import it as a new Kexi project?", projectData.infoString()), QString(), KGuiItem(xi18nc("@action:button Import Database", "&Import..."), KexiIconName("database-import")), KStandardGuiItem::cancel())) { const bool anotherProjectAlreadyOpened = prj; tristate res = showProjectMigrationWizard("application/x-kexi-connectiondata", projectData.databaseName(), *projectData.connectionData()); if (!anotherProjectAlreadyOpened) //the project could have been opened within this instance return res; //always return cancelled because even if migration succeeded, new Kexi instance //will be started if user wanted to open the imported db return cancelled; } return cancelled; } return false; } // success d->prj = prj.take(); d->modeSelector->setCurrentMode(Kexi::EditGlobalMode); 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->hideTab("form");//temporalily until createToolbar is split d->tabbedToolBar->hideTab("report");//temporalily until createToolbar is split // make sure any tab is activated d->tabbedToolBar->setCurrentTab(0); } return true; } tristate KexiMainWindow::openProject(const KexiProjectData& data, const QString& shortcutPath, bool *opened) { if (!shortcutPath.isEmpty() && d->prj) { const tristate result = openProjectInExternalKexiInstance( shortcutPath, QString(), QString()); if (result == true) { *opened = true; } return result; } return openProject(data); } tristate KexiMainWindow::createProjectFromTemplate(const KexiProjectData& projectData) { Q_UNUSED(projectData); #ifdef KEXI_PROJECT_TEMPLATES QStringList mimetypes; mimetypes.append(KDb::defaultFileBasedDriverMimeType()); QString fname; //! @todo KEXI3 add equivalent of kfiledialog:/// const QString startDir("kfiledialog:///OpenExistingOrCreateNewProject"/*as in KexiNewProjectWizard*/); const QString caption(xi18nc("@window:title", "Select New Project's Location")); while (true) { if (fname.isEmpty() && !projectData.connectionData()->databaseName().isEmpty()) { //propose filename from db template name fname = projectData.connectionData()->databaseName(); } const bool specialDir = fname.isEmpty(); qDebug() << fname << "............."; QFileDialog dlg(specialDir ? QUrl(startDir) : QUrl(), QString(), this); dlg.setModal(true); dlg.setMimeFilter(mimetypes); if (!specialDir) dlg.selectUrl(QUrl::fromLocalFile(fname); // may also be a filename dlg.setFileMode(QFileDialog::ExistingFile); dlg.setFileMode(QFileDialog::AcceptOpen); dlg.setWindowTitle(caption); if (QDialog::Accepted != dlg.exec()) { return cancelled; } if (dlg.selectedFiles().isEmpty() { return cancelled; } fname = dlg.selectedFiles().first(); if (fname.isEmpty()) { return cancelled; } if (KexiUtils::askForFileOverwriting(fname, this)) { break; } } QFile sourceFile(projectData.connectionData()->fileName()); if (!sourceFile.copy(fname)) { //! @todo show error from with QFile::FileError return false; } return openProject(fname, 0, QString(), projectData.autoopenObjects/*copy*/); #else return false; #endif } void KexiMainWindow::updateReadOnlyState() { const bool readOnly = d->prj && d->prj->dbConnection() && d->prj->dbConnection()->options()->isReadOnly(); //! @todo KEXI3 show read-only flag in the GUI because we have no statusbar if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { d->objectViewWidget->projectNavigator()->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"); #ifdef KEXI_QUICK_PRINTING_SUPPORT else if (info->value("action") == "print-preview") taskName = futureI18n("making print preview for"); else if (info->value("action") == "print") taskName = futureI18n("printing"); #endif else taskName = xi18n("opening"); not_found_msg += (QString("
  • ") + taskName + " \"" + info->value("name") + "\" - "); if ("table" == info->value("type").toLower()) not_found_msg += xi18n("table not found"); else if ("query" == info->value("type").toLower()) not_found_msg += xi18n("query not found"); else if ("macro" == info->value("type").toLower()) not_found_msg += xi18n("macro not found"); else if ("script" == info->value("type").toLower()) not_found_msg += xi18n("script not found"); else not_found_msg += xi18n("object not found"); not_found_msg += (internalReason(d->prj->result()) + "
  • "); continue; } // * EXECUTE, PRINT, PRINT PREVIEW if (info->value("action") == "execute") { tristate res = executeItem(item); if (false == res) { not_found_msg += (QString("
  • \"") + info->value("name") + "\" - " + xi18n("cannot execute object") + internalReason(d->prj->result()) + "
  • "); } continue; } #ifdef KEXI_QUICK_PRINTING_SUPPORT else if (info->value("action") == "print") { tristate res = printItem(item); if (false == res) { not_found_msg += (QString("
  • \"") + info->value("name") + "\" - " + futureI18n("cannot print object") + internalReason(d->prj->result()) + "
  • "); } continue; } else if (info->value("action") == "print-preview") { tristate res = printPreviewForItem(item); if (false == res) { not_found_msg += (QString("
  • \"") + info->value("name") + "\" - " + futureI18n("cannot make print preview of object") + internalReason(d->prj->result()) + "
  • "); } continue; } #endif Kexi::ViewMode viewMode; if (info->value("action") == "open") viewMode = Kexi::DataViewMode; else if (info->value("action") == "design") viewMode = Kexi::DesignViewMode; else if (info->value("action") == "edittext") viewMode = Kexi::TextViewMode; else continue; //sanity QString openObjectMessage; if (!openObject(item, viewMode, &openingCancelled, 0, &openObjectMessage) && (!openingCancelled || !openObjectMessage.isEmpty())) { not_found_msg += (QString("
  • \"") + info->value("name") + "\" - "); if (openObjectMessage.isEmpty()) not_found_msg += xi18n("cannot open object"); else not_found_msg += openObjectMessage; not_found_msg += internalReason(d->prj->result()) + "
  • "; continue; } else { d->wasAutoOpen = true; } } } setMessagesEnabled(true); if (!not_found_msg.isEmpty()) showErrorMessage(xi18n("You have requested selected objects to be automatically opened " "or processed on startup. Several objects cannot be opened or processed."), QString("
      %1
    ").arg(not_found_msg)); d->updatePropEditorVisibility(currentWindow() ? currentWindow()->currentViewMode() : Kexi::NoViewMode); #if defined(KDOCKWIDGET_P) if (d->propEditor) { KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); if (ds) ds->setSeparatorPosInPercent(d->config->readEntry("RightDockPosition", 80/* % */)); } #endif updateAppCaption(); if (d->tabbedToolBar) { d->tabbedToolBar->hideMainMenu(); } qApp->processEvents(); emit projectOpened(); } tristate KexiMainWindow::closeProject() { if (d->tabbedToolBar) d->tabbedToolBar->hideMainMenu(); #ifndef KEXI_NO_PENDING_DIALOGS if (d->pendingWindowsExist()) { qDebug() << "pendingWindowsExist..."; d->actionToExecuteWhenPendingJobsAreFinished = Private::CloseProjectAction; return cancelled; } #endif //only save nav. visibility setting if there is project opened d->saveSettingsForShowProjectNavigator = d->prj && d->isProjectNavigatorVisible; if (!d->prj) return true; { // make sure the project can be closed bool cancel = false; emit acceptProjectClosingRequested(&cancel); if (cancel) return cancelled; } d->windowExistedBeforeCloseProject = currentWindow(); #if defined(KDOCKWIDGET_P) //remember docks position - will be used on storeSettings() if (d->propEditor) { KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); if (ds) d->propEditorDockSeparatorPos = ds->separatorPosInPercent(); } if (d->nav) { if (d->propEditor) { //! @todo KEXI3 if (d->openedWindowsCount() == 0) //! @todo KEXI3 makeWidgetDockVisible(d->propEditorTabWidget); KDockWidget *dw = (KDockWidget *)d->propEditorTabWidget->parentWidget(); KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); if (ds) ds->setSeparatorPosInPercent(80); } KDockWidget *dw = (KDockWidget *)d->nav->parentWidget(); KDockSplitter *ds = (KDockSplitter *)dw->parentWidget(); int dwWidth = dw->width(); if (ds) { if (d->openedWindowsCount() != 0 && d->propEditorTabWidget && d->propEditorTabWidget->isVisible()) { d->navDockSeparatorPos = ds->separatorPosInPercent(); } else { d->navDockSeparatorPos = (100 * dwWidth) / width(); } } } #endif //close each window, optionally asking if user wants to close (if data changed) while (currentWindow()) { tristate res = closeWindow(currentWindow()); if (!res || ~res) return res; } // now we will close for sure emit beforeProjectClosing(); if (!d->prj->closeConnection()) return false; if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { d->navWasVisibleBeforeProjectClosing = d->objectViewWidget->projectNavigator()->isVisible(); d->setProjectNavigatorVisible(false); d->objectViewWidget->projectNavigator()->setProject(0); //slotProjectNavigatorVisibilityChanged(true); // hide side tab } if (d->objectViewWidget && d->objectViewWidget->propertyPane()) { d->objectViewWidget->propertyPane()->hide(); d->action_show_propeditor->setChecked(false); } d->clearWindows(); //sanity! delete d->prj; d->prj = 0; updateReadOnlyState(); invalidateActions(); updateAppCaption(); if (d->userMode) { d->modeSelector->setCurrentMode(Kexi::WelcomeGlobalMode); } emit projectClosed(); return true; } void KexiMainWindow::setupContextHelp() { #ifdef KEXI_SHOW_CONTEXT_HELP d->ctxHelp = new KexiContextHelp(d->mainWidget, this); //! @todo /* d->ctxHelp->setContextHelp(xi18n("Welcome"),xi18n("The KEXI team wishes you a lot of productive work, " "with this product.


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


    If you would like to join our effort, the development documentation " "at www.kexi-project.org is a good starting point."),0); */ addToolWindow(d->ctxHelp, KDockWidget::DockBottom | KDockWidget::DockLeft, getMainDockWidget(), 20); #endif } void KexiMainWindow::setupMainWidget() { QWidget *centralWidget = new QWidget; setCentralWidget(centralWidget); QVBoxLayout *vlyr = new QVBoxLayout(centralWidget); 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_tools_locate); connect(d->action_tools_locate, 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); d->modeSelector = new KexiGlobalViewModeSelector; connect(d->modeSelector, &KexiGlobalViewModeSelector::currentModeChanged, this, &KexiMainWindow::slotCurrentModeChanged); mainWidgetContainerLyr->addWidget(d->modeSelector); if (d->userMode) { d->modeSelector->hide(); } d->globalViewStack = new QStackedWidget; mainWidgetContainerLyr->addWidget(d->globalViewStack, 1); } //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::setupObjectView() { if (d->objectViewWidget) { return; } KexiObjectViewWidget::Flags flags; if (d->isProjectNavigatorVisible) { flags |= KexiObjectViewWidget::ProjectNavigatorEnabled; } if (!d->userMode) { flags |= KexiObjectViewWidget::PropertyPaneEnabled; } d->objectViewWidget = new KexiObjectViewWidget(flags); connect(d->objectViewWidget, &KexiObjectViewWidget::activeWindowChanged, this, &KexiMainWindow::activeWindowChanged); connect(d->objectViewWidget, &KexiObjectViewWidget::closeWindowRequested, this, &KexiMainWindow::closeWindowForTab); connect(d->objectViewWidget, &KexiObjectViewWidget::closeAllWindowsRequested, this, &KexiMainWindow::closeAllWindows); connect(d->objectViewWidget, &KexiObjectViewWidget::projectNavigatorAnimationFinished, this, &KexiMainWindow::slotProjectNavigatorVisibilityChanged); slotProjectNavigatorVisibilityChanged(d->objectViewWidget->projectNavigator()); // Restore settings //! @todo FIX LAYOUT PROBLEMS KConfigGroup propertyEditorGroup(d->config->group("PropertyEditor")); QFont f(KexiStyle::propertyPane().font()); const qreal pointSizeF = propertyEditorGroup.readEntry("FontPointSize", -1.0f); // points are more accurate if (pointSizeF > 0.0) { f.setPointSizeF(pointSizeF); } else { const int pixelSize = propertyEditorGroup.readEntry("FontSize", -1); // compatibility with Kexi 2.x if (pixelSize > 0) { f.setPixelSize(pixelSize); } } if (d->objectViewWidget->propertyPane()) { d->objectViewWidget->propertyPane()->setFont(f); KConfigGroup mainWindowGroup(d->config->group("MainWindow")); const QSize projectNavigatorSize = mainWindowGroup.readEntry("ProjectNavigatorSize", QSize()); const QSize propertyEditorSize = mainWindowGroup.readEntry("PropertyEditorSize", QSize()); d->objectViewWidget->setSidebarWidths(projectNavigatorSize.isValid() ? projectNavigatorSize.width() : -1, propertyEditorSize.isValid() ? propertyEditorSize.width() : -1); } d->globalViewStack->addWidget(d->objectViewWidget); KexiProjectNavigator* navigator = d->objectViewWidget->projectNavigator(); if (navigator) { //connect(d->navDockWidget, SIGNAL(visibilityChanged(bool)), // this, SLOT(slotProjectNavigatorVisibilityChanged(bool))); //Nav2 Signals connect(navigator, SIGNAL(openItem(KexiPart::Item*,Kexi::ViewMode)), this, SLOT(openObject(KexiPart::Item*,Kexi::ViewMode))); connect(navigator, SIGNAL(openOrActivateItem(KexiPart::Item*,Kexi::ViewMode)), this, SLOT(openObjectFromNavigator(KexiPart::Item*,Kexi::ViewMode))); connect(navigator, SIGNAL(newItem(KexiPart::Info*)), this, SLOT(newObject(KexiPart::Info*))); connect(navigator, SIGNAL(removeItem(KexiPart::Item*)), this, SLOT(removeObject(KexiPart::Item*))); connect(navigator->model(), SIGNAL(renameItem(KexiPart::Item*,QString,bool*)), this, SLOT(renameObject(KexiPart::Item*,QString,bool*))); connect(navigator->model(), SIGNAL(changeItemCaption(KexiPart::Item*,QString,bool*)), this, SLOT(setObjectCaption(KexiPart::Item*,QString,bool*))); connect(navigator, SIGNAL(executeItem(KexiPart::Item*)), this, SLOT(executeItem(KexiPart::Item*))); connect(navigator, SIGNAL(exportItemToClipboardAsDataTable(KexiPart::Item*)), this, SLOT(copyItemToClipboardAsDataTable(KexiPart::Item*))); connect(navigator, SIGNAL(exportItemToFileAsDataTable(KexiPart::Item*)), this, SLOT(exportItemAsDataTable(KexiPart::Item*))); #ifdef KEXI_QUICK_PRINTING_SUPPORT connect(navigator, SIGNAL(printItem(KexiPart::Item*)), this, SLOT(printItem(KexiPart::Item*))); connect(navigator, SIGNAL(pageSetupForItem(KexiPart::Item*)), this, SLOT(showPageSetupForItem(KexiPart::Item*))); #endif connect(navigator, SIGNAL(selectionChanged(KexiPart::Item*)), this, SLOT(slotPartItemSelectedInNavigator(KexiPart::Item*))); } if (navigator) { connect(d->prj, SIGNAL(newItemStored(KexiPart::Item*)), navigator->model(), SLOT(slotAddItem(KexiPart::Item*))); connect(d->prj, SIGNAL(itemRemoved(KexiPart::Item)), navigator->model(), SLOT(slotRemoveItem(KexiPart::Item))); navigator->setFocus(); /*if (d->forceShowProjectNavigatorOnCreation) { slotShowNavigator(); d->forceShowProjectNavigatorOnCreation = false; } else if (d->forceHideProjectNavigatorOnCreation) { d->forceHideProjectNavigatorOnCreation = false; }*/ } invalidateActions(); } void KexiMainWindow::updateObjectView() { setupObjectView(); if (d->prj && d->prj->isConnected()) { KexiProjectNavigator* navigator = d->objectViewWidget->projectNavigator(); if (navigator && !navigator->model()->project()) { QString partManagerErrorMessages; navigator->setProject(d->prj, QString()/*all classes*/, &partManagerErrorMessages); if (partManagerErrorMessages.isEmpty()) { d->setProjectNavigatorVisible(true); } else { showWarningContinueMessage(partManagerErrorMessages, QString(), "ShowWarningsRelatedToPluginsLoading"); } } } } void KexiMainWindow::slotLastActions() { } 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) { if (queryClose()) { ev->accept(); } else { ev->ignore(); } } void KexiMainWindow::resizeEvent(QResizeEvent *e) { QMainWindow::resizeEvent(e); - qDebug() << "===" << e->size() << size() << isVisible(); + //qDebug() << "===" << e->size() << size() << isVisible(); } static const QSize KEXI_MIN_WINDOW_SIZE(1024, 768); void KexiMainWindow::restoreSettings() { KConfigGroup mainWindowGroup(d->config->group("MainWindow")); const bool maximize = mainWindowGroup.readEntry("Maximized", false); const QRect geometry(mainWindowGroup.readEntry("Geometry", QRect())); if (geometry.isValid()) setGeometry(geometry); else if (maximize) setWindowState(windowState() | Qt::WindowMaximized); else { QRect desk = QApplication::desktop()->screenGeometry( QApplication::desktop()->screenNumber(this)); if (desk.width() <= KEXI_MIN_WINDOW_SIZE.width() || desk.height() <= KEXI_MIN_WINDOW_SIZE.height()) { setWindowState(windowState() | Qt::WindowMaximized); } else { resize(KEXI_MIN_WINDOW_SIZE); } } } 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->objectViewWidget) { int projectNavigatorWidth; int propertyEditorWidth; d->objectViewWidget->getSidebarWidths(&projectNavigatorWidth, &propertyEditorWidth); if (projectNavigatorWidth > 0) { mainWindowGroup.writeEntry("ProjectNavigatorSize", QSize(projectNavigatorWidth, 1)); } if (propertyEditorWidth > 0) { mainWindowGroup.writeEntry("PropertyEditorSize", QSize(propertyEditorWidth, 1)); } } 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->objectViewWidget || !d->objectViewWidget->propertyPane()) return; if ( !curWindowPart || (/*prevWindowPart &&*/ curWindowPart && (prevWindowPart != curWindowPart || prevViewMode != curViewMode) ) ) { #warning TODO KexiMainWindow::updateCustomPropertyPanelTabs() #if 0 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->objectViewWidget->propertyPane()->currentIndex()); } } //delete old custom tabs (other than 'property' tab) const int count = d->objectViewWidget->propertyEditorTabWidget()->count(); for (int i = 1; i < count; i++) d->objectViewWidget->propertyEditorTabWidget()->removeTab(1); #endif } //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->setupPropertyPane(d->objectViewWidget->propertyPane()->toolBox()); + d->objectViewWidget->propertyPane()->removeAllSections(); + curWindowPart->setupPropertyPane(d->objectViewWidget->propertyPane()); #warning TODO KexiMainWindow::updateCustomPropertyPanelTabs() #if 0 //restore current page number for this part if (d->recentlySelectedPropertyPanelPages.contains(curWindowPart)) { d->objectViewWidget->propertyEditorTabWidget()->setCurrentIndex( d->recentlySelectedPropertyPanelPages[ curWindowPart ] ); } #endif } //#endif //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->objectViewWidget->tabWidget()->setCurrentWidget(window.parentWidget()/*container*/); window.activate(); return true; } void KexiMainWindow::activateNextTab() { int index = d->objectViewWidget->tabWidget()->currentIndex() + 1; if (index >= d->objectViewWidget->tabWidget()->count()) { index = 0; } d->objectViewWidget->tabWidget()->setCurrentIndex(index); } void KexiMainWindow::activatePreviousTab() { int index = d->objectViewWidget->tabWidget()->currentIndex() - 1; if (index < 0) { index = d->objectViewWidget->tabWidget()->count() - 1; } d->objectViewWidget->tabWidget()->setCurrentIndex(index); } 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->objectViewWidget && d->objectViewWidget->projectNavigator()){ connect(prj, SIGNAL(itemRemoved(KexiPart::Item)), d->objectViewWidget->projectNavigator()->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(); d->prj->data()->setLastOpened(QDateTime::currentDateTime()); Kexi::recentProjects()->addProjectData(*d->prj->data()); d->modeSelector->setCurrentMode(Kexi::EditGlobalMode); invalidateActions(); updateAppCaption(); return true; } void KexiMainWindow::slotProjectOpen() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_open"); KexiOpenProjectAssistant* assistant = new KexiOpenProjectAssistant; connect(assistant, SIGNAL(openProject(KexiProjectData)), this, SLOT(openProject(KexiProjectData))); connect(assistant, SIGNAL(openProject(QString)), this, SLOT(openProject(QString))); d->tabbedToolBar->setMainMenuContent(assistant); } tristate KexiMainWindow::openProject(const QString& aFileName) { return openProject(aFileName, QString(), QString()); } tristate KexiMainWindow::openProject(const QString& aFileName, const QString& fileNameForConnectionData, const QString& dbName) { if (d->prj) return openProjectInExternalKexiInstance(aFileName, fileNameForConnectionData, dbName); KDbConnectionData *cdata = 0; if (!fileNameForConnectionData.isEmpty()) { cdata = Kexi::connset().connectionDataForFileName(fileNameForConnectionData); if (!cdata) { qWarning() << "cdata?"; return false; } } return openProject(aFileName, cdata, dbName); } tristate KexiMainWindow::openProject(const QString& aFileName, KDbConnectionData *cdata, const QString& dbName, const KexiProjectData::AutoOpenObjects& autoopenObjects) { if (d->prj) { return openProjectInExternalKexiInstance(aFileName, cdata, dbName); } KexiProjectData* projectData = 0; const KexiStartupHandler *h = KexiStartupHandler::global(); bool readOnly = h->isSet(h->options().readOnly); bool deleteAfterOpen = false; if (cdata) { //server-based project if (dbName.isEmpty()) {//no database name given, ask user bool cancel; projectData = KexiStartupHandler::global()->selectProject(cdata, &cancel, this); if (cancel) return cancelled; } else { //! @todo caption arg? projectData = new KexiProjectData(*cdata, dbName); deleteAfterOpen = true; } } else { if (aFileName.isEmpty()) { qWarning() << "aFileName.isEmpty()"; return false; } //file-based project qDebug() << "Project File: " << aFileName; KDbConnectionData fileConnData; fileConnData.setDatabaseName(aFileName); QString detectedDriverId; int detectOptions = 0; if (readOnly) { detectOptions |= KexiStartupHandler::OpenReadOnly; } KexiStartupData::Import importActionData; bool forceReadOnly; const tristate res = KexiStartupHandler::detectActionForFile( &importActionData, &detectedDriverId, fileConnData.driverId(), aFileName, this, detectOptions, &forceReadOnly); if (forceReadOnly) { readOnly = true; } if (true != res) return res; if (importActionData) { //importing requested return showProjectMigrationWizard(importActionData.mimeType, importActionData.fileName); } fileConnData.setDriverId(detectedDriverId); if (fileConnData.driverId().isEmpty()) return false; //opening requested projectData = new KexiProjectData(fileConnData); deleteAfterOpen = true; } if (!projectData) return false; projectData->setReadOnly(readOnly); projectData->autoopenObjects = autoopenObjects; const tristate res = openProject(*projectData); if (deleteAfterOpen) //projectData object has been copied delete projectData; return res; } tristate KexiMainWindow::openProjectInExternalKexiInstance(const QString& aFileName, KDbConnectionData *cdata, const QString& dbName) { QString fileNameForConnectionData; if (aFileName.isEmpty()) { //try .kexic file if (cdata) fileNameForConnectionData = Kexi::connset().fileNameForConnectionData(*cdata); } return openProjectInExternalKexiInstance(aFileName, fileNameForConnectionData, dbName); } tristate KexiMainWindow::openProjectInExternalKexiInstance(const QString& aFileName, const QString& fileNameForConnectionData, const QString& dbName) { QString fileName(aFileName); QStringList args; // open a file-based project or a server connection provided as a .kexic file // (we have no other simple way to provide the startup data to a new process) if (fileName.isEmpty()) { //try .kexic file if (!fileNameForConnectionData.isEmpty()) args << "--skip-conn-dialog"; //user does not expect conn. dialog to be shown here if (dbName.isEmpty()) { //use 'kexi --skip-conn-dialog file.kexic' fileName = fileNameForConnectionData; } else { //use 'kexi --skip-conn-dialog --connection file.kexic dbName' if (fileNameForConnectionData.isEmpty()) { qWarning() << "fileNameForConnectionData?"; return false; } args << "--connection" << fileNameForConnectionData; fileName = dbName; } } if (fileName.isEmpty()) { qWarning() << "fileName?"; return false; } //! @todo use KRun //! @todo untested //Can arguments be supplied to KRun like is used here? AP args << fileName; const bool ok = QProcess::startDetached( qApp->applicationFilePath(), args, QFileInfo(fileName).absoluteDir().absolutePath()); if (!ok) { d->showStartProcessMsg(args); } if (d->tabbedToolBar) { d->tabbedToolBar->hideMainMenu(); } return ok; } void KexiMainWindow::slotProjectWelcome() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_welcome"); KexiWelcomeAssistant* assistant = new KexiWelcomeAssistant( Kexi::recentProjects(), this); connect(assistant, SIGNAL(openProject(KexiProjectData,QString,bool*)), this, SLOT(openProject(KexiProjectData,QString,bool*))); d->tabbedToolBar->setMainMenuContent(assistant); } void KexiMainWindow::slotProjectSave() { if (!currentWindow() || currentWindow()->currentViewMode() == Kexi::DataViewMode) { return; } saveObject(currentWindow()); updateAppCaption(); invalidateActions(); } void KexiMainWindow::slotProjectSaveAs() { if (!currentWindow() || currentWindow()->currentViewMode() == Kexi::DataViewMode) { return; } saveObject(currentWindow(), QString(), SaveObjectAs); updateAppCaption(); invalidateActions(); } void KexiMainWindow::slotProjectPrint() { #ifdef KEXI_QUICK_PRINTING_SUPPORT if (currentWindow() && currentWindow()->partItem()) printItem(currentWindow()->partItem()); #endif } void KexiMainWindow::slotProjectPrintPreview() { #ifdef KEXI_QUICK_PRINTING_SUPPORT if (currentWindow() && currentWindow()->partItem()) printPreviewForItem(currentWindow()->partItem()); #endif } void KexiMainWindow::slotProjectPageSetup() { #ifdef KEXI_QUICK_PRINTING_SUPPORT if (currentWindow() && currentWindow()->partItem()) showPageSetupForItem(currentWindow()->partItem()); #endif } void KexiMainWindow::slotProjectExportDataTable() { if (currentWindow() && currentWindow()->partItem()) exportItemAsDataTable(currentWindow()->partItem()); } void KexiMainWindow::slotProjectProperties() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_properties"); // dummy QLabel *dummy = KEXI_UNFINISHED_LABEL(actionCollection()->action("project_properties")->text()); d->tabbedToolBar->setMainMenuContent(dummy); //! @todo load the implementation not the ui :) // ProjectSettingsUI u(this); // u.exec(); } void KexiMainWindow::slotProjectImportExportOrSend() { if (!d->tabbedToolBar) return; d->tabbedToolBar->showMainMenu("project_import_export_send"); KexiImportExportAssistant* assistant = new KexiImportExportAssistant( d->action_project_import_export_send, d->action_tools_import_project); connect(assistant, SIGNAL(importProject()), this, SLOT(slotToolsImportProject())); d->tabbedToolBar->setMainMenuContent(assistant); } void KexiMainWindow::slotProjectClose() { closeProject(); } void KexiMainWindow::slotProjectRelations() { if (!d->prj) return; KexiWindow *w = KexiInternalPart::createKexiWindowInstance("org.kexi-project.relations", this); if (w) { activateWindow(*w); } } void KexiMainWindow::slotImportFile() { KEXI_UNFINISHED("Import: " + xi18n("From File...")); } void KexiMainWindow::slotImportServer() { KEXI_UNFINISHED("Import: " + xi18n("From Server...")); } void KexiMainWindow::slotProjectQuit() { if (~ closeProject()) return; close(); } void KexiMainWindow::slotActivateNavigator() { if (!d->objectViewWidget || !d->objectViewWidget->projectNavigator()) { return; } d->objectViewWidget->projectNavigator()->setFocus(); } void KexiMainWindow::slotActivateMainArea() { if (currentWindow()) currentWindow()->setFocus(); } void KexiMainWindow::slotActivatePropertyPane() { if (!d->objectViewWidget || !d->objectViewWidget->propertyPane()) { return; } d->objectViewWidget->propertyPane()->setFocus(); // if (d->objectViewWidget->propertyPane()->currentWidget()) { // d->objectViewWidget->propertyPane()->currentWidget()->setFocus(); // } } void KexiMainWindow::slotToggleProjectNavigator() { if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { d->setProjectNavigatorVisible(!d->objectViewWidget->projectNavigator()->isVisible(), Private::ShowAnimated); } } void KexiMainWindow::slotTogglePropertyEditor() { if (d->objectViewWidget && d->objectViewWidget->propertyPane()) { d->objectViewWidget->setPropertyPaneVisible(!d->objectViewWidget->propertyPane()->isVisible()); } } tristate KexiMainWindow::switchToViewMode(KexiWindow& window, Kexi::ViewMode viewMode) { const Kexi::ViewMode prevViewMode = currentWindow()->currentViewMode(); if (prevViewMode == viewMode) return true; if (!activateWindow(window)) return false; if (!currentWindow()) { return false; } if (&window != currentWindow()) return false; if (!currentWindow()->supportsViewMode(viewMode)) { showErrorMessage(xi18nc("@info", "Selected view is not supported for %1 object.", currentWindow()->partItem()->name()), xi18nc("@info", "Selected view (%1) is not supported by this object type (%2).", Kexi::nameForViewMode(viewMode), currentWindow()->part()->info()->name())); return false; } updateCustomPropertyPanelTabs(currentWindow()->part(), prevViewMode, currentWindow()->part(), viewMode); tristate res = currentWindow()->switchToViewMode(viewMode); if (!res) { updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert showErrorMessage(xi18n("Switching to other view failed (%1).", Kexi::nameForViewMode(viewMode)), currentWindow()); return false; } if (~res) { updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert return cancelled; } activateWindow(window); invalidateSharedActions(); invalidateProjectWideActions(); d->updateFindDialogContents(); d->updatePropEditorVisibility(viewMode); QString origTabToActivate; if (viewMode == Kexi::DesignViewMode) { // Save the orig tab: we want to back to design tab // when user moved to data view and then immediately to design view. origTabToActivate = d->tabsToActivateOnShow.value(currentWindow()->partItem()->identifier()); } restoreDesignTabIfNeeded(currentWindow()->partItem()->pluginId(), viewMode, currentWindow()->partItem()->identifier()); if (viewMode == Kexi::DesignViewMode) { activateDesignTab(currentWindow()->partItem()->pluginId()); // Restore the saved tab to the orig one. restoreDesignTabIfNeeded() saved tools tab probably. d->tabsToActivateOnShow.insert(currentWindow()->partItem()->identifier(), origTabToActivate); } return true; } void KexiMainWindow::slotViewDataMode() { if (currentWindow()) switchToViewMode(*currentWindow(), Kexi::DataViewMode); } void KexiMainWindow::slotViewDesignMode() { if (currentWindow()) switchToViewMode(*currentWindow(), Kexi::DesignViewMode); } void KexiMainWindow::slotViewTextMode() { if (currentWindow()) switchToViewMode(*currentWindow(), Kexi::TextViewMode); } //! Used to control if we're not Saving-As object under the original name class SaveAsObjectNameValidator : public KexiNameDialogValidator { public: SaveAsObjectNameValidator(const QString &originalObjectName) : m_originalObjectName(originalObjectName) { } virtual bool validate(KexiNameDialog *dialog) const { if (dialog->widget()->nameText() == m_originalObjectName) { KMessageBox::information(dialog, xi18nc("Could not save object under the original name.", "Could not save under the original name.")); return false; } return true; } private: QString m_originalObjectName; }; tristate KexiMainWindow::getNewObjectInfo( KexiPart::Item *partItem, const QString &originalName, KexiPart::Part *part, bool allowOverwriting, bool *overwriteNeeded, const QString& messageWhenAskingForName) { //data was never saved in the past -we need to create a new object at the backend KexiPart::Info *info = part->info(); if (!d->nameDialog) { d->nameDialog = new KexiNameDialog( messageWhenAskingForName, this); //check if that name is allowed d->nameDialog->widget()->addNameSubvalidator( new KDbObjectNameValidator(project()->dbConnection()->driver())); d->nameDialog->buttonBox()->button(QDialogButtonBox::Ok)->setText(xi18nc("@action:button Save object", "Save")); } else { d->nameDialog->widget()->setMessageText(messageWhenAskingForName); } d->nameDialog->widget()->setCaptionText(partItem->caption()); d->nameDialog->widget()->setNameText(partItem->name()); d->nameDialog->setWindowTitle(xi18nc("@title:window", "Save Object As")); d->nameDialog->setDialogIcon(info->iconName()); d->nameDialog->setAllowOverwriting(allowOverwriting); if (!originalName.isEmpty()) { d->nameDialog->setValidator(new SaveAsObjectNameValidator(originalName)); } if (d->nameDialog->execAndCheckIfObjectExists(*project(), *part, overwriteNeeded) != QDialog::Accepted) { return cancelled; } // close window of object that will be overwritten if (*overwriteNeeded) { KexiPart::Item* overwrittenItem = project()->item(info, d->nameDialog->widget()->nameText()); if (overwrittenItem) { KexiWindow * openedWindow = d->openedWindowFor(overwrittenItem->identifier()); if (openedWindow) { const tristate res = closeWindow(openedWindow); if (res != true) { return res; } } } } //update name and caption partItem->setName(d->nameDialog->widget()->nameText()); partItem->setCaption(d->nameDialog->widget()->captionText()); return true; } //! Used to delete part item on exit from block class PartItemDeleter : public QScopedPointer { public: explicit PartItemDeleter(KexiProject *prj) : m_prj(prj) {} ~PartItemDeleter() { if (!isNull()) { m_prj->deleteUnstoredItem(take()); } } private: KexiProject *m_prj; }; static void showSavingObjectFailedErrorMessage(KexiMainWindow *wnd, KexiPart::Item *item) { wnd->showErrorMessage( xi18nc("@info Saving object failed", "Saving %1 object failed.", item->name()), wnd->currentWindow()); } tristate KexiMainWindow::saveObject(KexiWindow *window, const QString& messageWhenAskingForName, SaveObjectOptions options) { tristate res; bool saveAs = options & SaveObjectAs; if (!saveAs && !window->neverSaved()) { //data was saved in the past -just save again res = window->storeData(options & DoNotAsk); if (!res) { showSavingObjectFailedErrorMessage(this, window->partItem()); } return res; } if (saveAs && window->neverSaved()) { //if never saved, saveAs == save saveAs = false; } const int oldItemID = window->partItem()->identifier(); KexiPart::Item *partItem; KexiView::StoreNewDataOptions storeNewDataOptions; PartItemDeleter itemDeleter(d->prj); if (saveAs) { partItem = d->prj->createPartItem(window->part()); if (!partItem) { //! @todo error return false; } itemDeleter.reset(partItem); } else { partItem = window->partItem(); } bool overwriteNeeded; res = getNewObjectInfo(partItem, saveAs ? window->partItem()->name() : QString(), window->part(), true /*allowOverwriting*/, &overwriteNeeded, messageWhenAskingForName); if (res != true) return res; if (overwriteNeeded) { storeNewDataOptions |= KexiView::OverwriteExistingData; } if (saveAs) { res = window->storeDataAs(partItem, storeNewDataOptions); } else { res = window->storeNewData(storeNewDataOptions); } if (~res) return cancelled; if (!res) { showSavingObjectFailedErrorMessage(this, partItem); return false; } d->updateWindowId(window, oldItemID); invalidateProjectWideActions(); itemDeleter.take(); return true; } tristate KexiMainWindow::closeWindow(KexiWindow *window) { return closeWindow(window ? window : currentWindow(), true); } tristate KexiMainWindow::closeCurrentWindow() { return closeWindow(0); } tristate KexiMainWindow::closeWindowForTab(int tabIndex) { KexiWindow* window = windowForTab(tabIndex); if (!window) return false; return closeWindow(window); } tristate KexiMainWindow::closeAllWindows() { if (!d->objectViewWidget || !d->objectViewWidget->tabWidget()) return true; QList windowList; for (int i = 0; i < d->objectViewWidget->tabWidget()->count(); ++i) { KexiWindow *window = windowForTab(i); if (window) { windowList.append(window); } } tristate alternateResult = true; for (KexiWindow *window : windowList) { const tristate result = closeWindow(window); if (~result) { return result; } if (result == false) { alternateResult = false; } } return alternateResult; } 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->propertyEditor()) { // ah, closing detached window - better switch off property buffer right now... d->propertySet = 0; - d->propertyEditor()->editor()->changeSet(0); + d->propertyEditor()->changeSet(0); } } bool remove_on_closing = window->partItem() ? window->partItem()->neverSaved() : false; if (window->isDirty() && !d->forceWindowClosing && !doNotSaveChanges) { //more accurate tool tips and what's this KGuiItem saveChanges(KStandardGuiItem::save()); saveChanges.setToolTip(xi18n("Save changes")); saveChanges.setWhatsThis( xi18nc("@info", "Saves all recent changes made in %1 object.", window->partItem()->name())); KGuiItem discardChanges(KStandardGuiItem::discard()); discardChanges.setWhatsThis( xi18nc("@info", "Discards all recent changes made in %1 object.", window->partItem()->name())); //dialog's data is dirty: //--adidional message, e.g. table designer will return // "Note: This table is already filled with data which will be removed." // if the window is in design view mode. const KLocalizedString additionalMessage( window->part()->i18nMessage(":additional message before saving design", window)); QString additionalMessageString; if (!additionalMessage.isEmpty()) additionalMessageString = additionalMessage.toString(); if (additionalMessageString.startsWith(':')) additionalMessageString.clear(); if (!additionalMessageString.isEmpty()) additionalMessageString = "

    " + additionalMessageString + "

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

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

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

    " + additionalMessageString /*may be empty*/, QString(), saveChanges, discardChanges); if (questionRes == KMessageBox::Cancel) { #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(window->id()); #endif d->insideCloseWindow = false; d->windowsToClose.clear(); //give up with 'close all' return cancelled; } if (questionRes == KMessageBox::Yes) { //save it tristate res = saveObject(window, QString(), DoNotAsk); if (!res || ~res) { //! @todo show error info; (retry/ignore/cancel) #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(window->id()); #endif d->insideCloseWindow = false; d->windowsToClose.clear(); //give up with 'close all' return res; } remove_on_closing = false; } } const int window_id = window->id(); //remember now, because removeObject() can destruct partitem object if (remove_on_closing) { //we won't save this object, and it was never saved -remove it if (!removeObject(window->partItem(), true)) { #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(window->id()); #endif //msg? //! @todo ask if we'd continue and return true/false d->insideCloseWindow = false; d->windowsToClose.clear(); //give up with 'close all' return false; } } else { //not dirty now if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { d->objectViewWidget->projectNavigator()->updateItemName(*window->partItem(), false); } } hideDesignTab(previousItemId, QString()); d->removeWindow(window_id); d->setWindowContainerExistsFor(window->partItem()->identifier(), false); QWidget *windowContainer = window->parentWidget(); d->objectViewWidget->tabWidget()->removeTab( d->objectViewWidget->tabWidget()->indexOf(windowContainer)); #ifdef KEXI_QUICK_PRINTING_SUPPORT //also remove from 'print setup dialogs' cache, if needed int printedObjectID = 0; if (d->pageSetupWindowItemID2dataItemID_map.contains(window_id)) printedObjectID = d->pageSetupWindowItemID2dataItemID_map[ window_id ]; d->pageSetupWindows.remove(printedObjectID); #endif delete windowContainer; //focus navigator if nothing else available if (d->openedWindowsCount() == 0) { if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { d->objectViewWidget->projectNavigator()->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->objectViewWidget->slotCurrentTabIndexChanged(d->objectViewWidget->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->objectViewWidget->propertyPane()) { 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; QWidget *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); const int tabIndex = d->objectViewWidget->tabWidget()->addEmptyContainerTab( part ? part->info()->icon() : koIcon("object"), KexiWindow::windowTitleForItem(*item)); // open new tab earlier d->setWindowContainerExistsFor(item->identifier(), true); d->objectViewWidget->tabWidget()->setTabToolTip(tabIndex, KexiPart::fullCaptionForItem(item, part)); QString whatsThisText; if (part) { whatsThisText = xi18nc("@info", "Tab for %1 (%2).", item->captionOrName(), part->info()->name()); } else { whatsThisText = xi18nc("@info", "Tab for %1.", item->captionOrName()); } d->objectViewWidget->tabWidget()->setTabWhatsThis(tabIndex, whatsThisText); d->objectViewWidget->tabWidget()->setCurrentIndex(tabIndex); #ifndef KEXI_NO_PENDING_DIALOGS d->addItemToPendingWindows(item, Private::WindowOpeningJob); #endif windowContainer = d->objectViewWidget->tabWidget()->widget(tabIndex); window = d->prj->openObject(windowContainer, item, viewMode, staticObjectArgs); if (window) { d->objectViewWidget->tabWidget()->setWindowForTab(tabIndex, window); // update text and icon d->objectViewWidget->tabWidget()->setTabText(tabIndex, window->windowTitle()); d->objectViewWidget->tabWidget()->setTabIcon(tabIndex, window->windowIcon()); } } if (!window || !activateWindow(*window)) { #ifndef KEXI_NO_PENDING_DIALOGS d->removePendingWindow(item->identifier()); #endif d->setWindowContainerExistsFor(item->identifier(), false); d->objectViewWidget->tabWidget()->removeTab( d->objectViewWidget->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->objectViewWidget->projectNavigator()->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()), KStandardGuiItem::del(), KStandardGuiItem::no(), QString(), KMessageBox::Notify | KMessageBox::Dangerous)) { return cancelled; } } tristate res = true; #ifdef KEXI_QUICK_PRINTING_SUPPORT //also close 'print setup' dialog for this item, if any KexiWindow * pageSetupWindow = d->pageSetupWindows[ item->identifier()]; const bool oldInsideCloseWindow = d->insideCloseWindow; { d->insideCloseWindow = false; if (pageSetupWindow) res = closeWindow(pageSetupWindow); } d->insideCloseWindow = oldInsideCloseWindow; if (!res || ~res) { return res; } #endif #ifndef KEXI_NO_PENDING_DIALOGS Private::PendingJobType pendingType; KexiWindow *window = d->openedWindowFor(item, pendingType); if (pendingType != Private::NoJob) { return cancelled; } #else KexiWindow *window = openedWindowFor(item); #endif if (window) {//close existing window const bool tmp = d->forceWindowClosing; d->forceWindowClosing = true; res = closeWindow(window); d->forceWindowClosing = tmp; //restore if (!res || ~res) { return res; } } #ifdef KEXI_QUICK_PRINTING_SUPPORT //in case the dialog is a 'print setup' dialog, also update d->pageSetupWindows int dataItemID = d->pageSetupWindowItemID2dataItemID_map[item->identifier()]; d->pageSetupWindowItemID2dataItemID_map.remove(item->identifier()); d->pageSetupWindows.remove(dataItemID); #endif if (!d->prj->removeObject(item)) { //! @todo better msg showSorryMessage(xi18n("Could not 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(), KStandardGuiItem::closeWindow(), 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(xi18nc("@info", "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(xi18nc("@info", "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->propertyEditor()) { - d->propertyEditor()->editor()->acceptInput(); + d->propertyEditor()->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->propertyEditor()) { KPropertySet *newSet = _currentWindow ? _currentWindow->propertySet() : 0; if (!newSet || (force || static_cast(d->propertySet) != newSet)) { d->propertySet = newSet; if (preservePrevSelection || force) { KPropertyEditorView::SetOptions options; if (preservePrevSelection) { options |= KPropertyEditorView::SetOption::PreservePreviousSelection; } if (sortedProperties) { options |= KPropertyEditorView::SetOption::AlphabeticalOrder; } if (propertyToSelect.isEmpty()) { - d->propertyEditor()->editor()->changeSet(d->propertySet, options); + d->propertyEditor()->changeSet(d->propertySet, options); } else { - d->propertyEditor()->editor()->changeSet(d->propertySet, propertyToSelect, options); + d->propertyEditor()->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->objectViewWidget->projectNavigator()->updateItemName(*item, window->isDirty()); } invalidateActions(); updateAppCaption(); d->objectViewWidget->tabWidget()->setTabText( d->objectViewWidget->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->objectViewWidget->projectNavigator()->selectedPartItem(); if (item) copyItemToClipboardAsDataTable(item); } tristate KexiMainWindow::copyItemToClipboardAsDataTable(KexiPart::Item* item) { if (!item) return false; QMap args; if (!checkForDirtyFlagOnExport(item, &args)) { return false; } args.insert("destinationType", "clipboard"); args.insert("itemId", QString::number(item->identifier())); QDialog *dlg = KexiInternalPart::createModalDialogInstance( "org.kexi-project.importexport.csv", "KexiCSVExportWizard", this, 0, &args); if (!dlg) return false; //error msg has been shown by KexiInternalPart const int result = dlg->exec(); delete dlg; return result == QDialog::Rejected ? tristate(cancelled) : tristate(true); } void KexiMainWindow::slotEditPasteSpecialDataTable() { //! @todo allow data appending (it is not possible now) if (d->userMode) return; QMap args; args.insert("sourceType", "clipboard"); QDialog *dlg = KexiInternalPart::createModalDialogInstance( "org.kexi-project.importexport.csv", "KexiCSVImportDialog", this, 0, &args); if (!dlg) return; //error msg has been shown by KexiInternalPart dlg->exec(); delete dlg; } void KexiMainWindow::slotEditFind() { KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); if (!iface) return; d->updateFindDialogContents(true/*create if does not exist*/); d->findDialog()->setReplaceMode(false); d->findDialog()->show(); d->findDialog()->activateWindow(); d->findDialog()->raise(); } void KexiMainWindow::slotEditFind(bool next) { KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); if (!iface) return; tristate res = iface->find( d->findDialog()->valueToFind(), d->findDialog()->options(), next); if (~res) return; d->findDialog()->updateMessage(true == res); //! @todo result } void KexiMainWindow::slotEditFindNext() { slotEditFind(true); } void KexiMainWindow::slotEditFindPrevious() { slotEditFind(false); } void KexiMainWindow::slotEditReplace() { KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); if (!iface) return; d->updateFindDialogContents(true/*create if does not exist*/); d->findDialog()->setReplaceMode(true); //! @todo slotEditReplace() d->findDialog()->show(); d->findDialog()->activateWindow(); } void KexiMainWindow::slotEditReplaceNext() { slotEditReplace(false); } void KexiMainWindow::slotEditReplace(bool all) { KexiSearchAndReplaceViewInterface* iface = d->currentViewSupportingSearchAndReplaceInterface(); if (!iface) return; //! @todo add question: "Do you want to replace every occurrence of \"%1\" with \"%2\"? //! You won't be able to undo this." + "Do not ask again". tristate res = iface->findNextAndReplace( d->findDialog()->valueToFind(), d->findDialog()->valueToReplaceWith(), d->findDialog()->options(), all); d->findDialog()->updateMessage(true == res); //! @todo result } void KexiMainWindow::slotEditReplaceAll() { slotEditReplace(true); } void KexiMainWindow::highlightObject(const QString& pluginId, const QString& name) { if (!d->prj) return; KexiPart::Item *item = d->prj->itemForPluginId(pluginId, name); if (!item) return; if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { d->setProjectNavigatorVisible(true, Private::ShowAnimated); d->objectViewWidget->projectNavigator()->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->objectViewWidget->propertyPane()->updateInfoLabelForPropertySet( d->propertySet); } void KexiMainWindow::beginPropertyPaneUpdate() { if (d->propertyPaneAnimation) { d->propertyPaneAnimation->hide(); d->propertyPaneAnimation->deleteLater(); } d->propertyPaneAnimation = new KexiFadeWidgetEffect(d->objectViewWidget->propertyPane()); } void KexiMainWindow::endPropertyPaneUpdate() { if (d->propertyPaneAnimation) { d->objectViewWidget->propertyPane()->repaint(); d->propertyPaneAnimation->start(150); } } void KexiMainWindow::addSearchableModel(KexiSearchableModel *model) { if (d->tabbedToolBar) { d->tabbedToolBar->addSearchableModel(model); } } void KexiMainWindow::setReasonableDialogSize(QDialog *dialog) { dialog->setMinimumSize(600, 400); dialog->resize(size() * 0.8); } void KexiMainWindow::restoreDesignTabAndActivateIfNeeded(const QString &tabName) { if (!d->tabbedToolBar) { return; } d->tabbedToolBar->showTab(tabName); if (currentWindow() && currentWindow()->partItem() && currentWindow()->partItem()->identifier() != 0) // for unstored items id can be < 0 { const QString tabToActivate = d->tabsToActivateOnShow.value( currentWindow()->partItem()->identifier()); //qDebug() << "tabToActivate:" << tabToActivate << "tabName:" << tabName; if (tabToActivate == tabName) { d->tabbedToolBar->setCurrentTab(tabToActivate); } } } void KexiMainWindow::restoreDesignTabIfNeeded(const QString &pluginId, Kexi::ViewMode viewMode, int previousItemId) { //qDebug() << pluginId << viewMode << previousItemId; if (viewMode == Kexi::DesignViewMode) { switch (d->prj->typeIdForPluginId(pluginId)) { case KexiPart::FormObjectType: { hideDesignTab(previousItemId, "org.kexi-project.report"); restoreDesignTabAndActivateIfNeeded("form"); break; } case KexiPart::ReportObjectType: { hideDesignTab(previousItemId, "org.kexi-project.form"); restoreDesignTabAndActivateIfNeeded("report"); break; } default: hideDesignTab(previousItemId); } } else { hideDesignTab(previousItemId); } } void KexiMainWindow::activateDesignTab(const QString &pluginId) { if (!d->tabbedToolBar) { return; } switch (d->prj->typeIdForPluginId(pluginId)) { case KexiPart::FormObjectType: d->tabbedToolBar->setCurrentTab("form"); break; case KexiPart::ReportObjectType: d->tabbedToolBar->setCurrentTab("report"); break; default:; } } void KexiMainWindow::activateDesignTabIfNeeded(const QString &pluginId, Kexi::ViewMode viewMode) { if (!d->tabbedToolBar) { return; } const QString tabToActivate = d->tabsToActivateOnShow.value(currentWindow()->partItem()->identifier()); //qDebug() << pluginId << viewMode << tabToActivate; if (viewMode == Kexi::DesignViewMode && tabToActivate.isEmpty()) { activateDesignTab(pluginId); } else { d->tabbedToolBar->setCurrentTab(tabToActivate); } } void KexiMainWindow::hideDesignTab(int itemId, const QString &pluginId) { if (!d->tabbedToolBar) { return; } //qDebug() << itemId << pluginId; if ( itemId > 0 && d->tabbedToolBar->currentWidget()) { const QString currentTab = d->tabbedToolBar->currentWidget()->objectName(); //qDebug() << "d->tabsToActivateOnShow.insert" << itemId << currentTab; d->tabsToActivateOnShow.insert(itemId, currentTab); } switch (d->prj->typeIdForPluginId(pluginId)) { case KexiPart::FormObjectType: d->tabbedToolBar->hideTab("form"); break; case KexiPart::ReportObjectType: d->tabbedToolBar->hideTab("report"); break; default: d->tabbedToolBar->hideTab("form"); d->tabbedToolBar->hideTab("report"); } } void KexiMainWindow::showDesignTabIfNeeded(int previousItemId) { if (d->insideCloseWindow && d->tabbedToolBar) return; if (currentWindow()) { restoreDesignTabIfNeeded(currentWindow()->partItem()->pluginId(), currentWindow()->currentViewMode(), previousItemId); } else { hideDesignTab(previousItemId); } } KexiUserFeedbackAgent* KexiMainWindow::userFeedbackAgent() const { return &d->userFeedback; } KexiMigrateManagerInterface* KexiMainWindow::migrateManager() { if (!d->migrateManager) { d->migrateManager = dynamic_cast( KexiInternalPart::createObjectInstance( "org.kexi-project.migration", "manager", this, this, nullptr)); } return d->migrateManager; } void KexiMainWindow::toggleFullScreen(bool isFullScreen) { static bool isTabbarRolledDown; if (d->tabbedToolBar) { if (isFullScreen) { isTabbarRolledDown = !d->tabbedToolBar->isRolledUp(); if (isTabbarRolledDown) { d->tabbedToolBar->toggleRollDown(); } } else { if (isTabbarRolledDown && d->tabbedToolBar->isRolledUp()) { d->tabbedToolBar->toggleRollDown(); } } } const Qt::WindowStates s = windowState() & Qt::WindowMaximized; if (isFullScreen) { setWindowState(windowState() | Qt::WindowFullScreen | s); } else { setWindowState((windowState() & ~Qt::WindowFullScreen)); showMaximized(); } } Kexi::GlobalViewMode KexiMainWindow::currentMode() const { return d->modeSelector->currentMode(); } void KexiMainWindow::setCurrentMode(Kexi::GlobalViewMode mode) { d->modeSelector->setCurrentMode(mode); } void KexiMainWindow::slotCurrentModeChanged() { switch (d->modeSelector->currentMode()) { case Kexi::WelcomeGlobalMode: break; case Kexi::ProjectGlobalMode: break; case Kexi::EditGlobalMode: updateObjectView(); d->globalViewStack->setCurrentWidget(d->objectViewWidget); break; case Kexi::DesignGlobalMode: break; case Kexi::HelpGlobalMode: break; } } void KexiMainWindow::slotProjectNavigatorVisibilityChanged(bool visible) { if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { d->modeSelector->setArrowColor(visible ? d->objectViewWidget->projectNavigator()->palette().color(QPalette::Window) : d->objectViewWidget->tabWidget()->palette().color(QPalette::Window)); } } diff --git a/src/main/KexiMainWindow_p.cpp b/src/main/KexiMainWindow_p.cpp index c8593b7a5..94d28c4b9 100644 --- a/src/main/KexiMainWindow_p.cpp +++ b/src/main/KexiMainWindow_p.cpp @@ -1,1458 +1,1458 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KexiMainWindow_p.h" #include "KexiObjectViewWidget.h" -#include "KexiPropertyPaneWidget.h" #include #include #include #include #include +#include #include #include #include #include #include #include #include EmptyMenuContentWidget::EmptyMenuContentWidget(QWidget* parent) : QWidget(parent) { setAutoFillBackground(true); alterBackground(); } void EmptyMenuContentWidget::alterBackground() { QPalette pal(palette()); QColor bg(pal.color(QPalette::Window)); bg.setAlpha(200); pal.setColor(QPalette::Window, bg); setPalette(pal); } void EmptyMenuContentWidget::changeEvent(QEvent *e) { if (e->type() == QEvent::PaletteChange) { alterBackground(); } QWidget::changeEvent(e); } //! @todo KEXI3 is KexiMenuWidgetStyle needed? #if 0 KexiMenuWidgetStyle::KexiMenuWidgetStyle(QStyle *style, QObject *parent) : KexiUtils::StyleProxy(style, parent) { } KexiMenuWidgetStyle::~KexiMenuWidgetStyle() { } void KexiMenuWidgetStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const { if (element == QStyle::CE_MenuItem && (option->state & QStyle::State_Selected) && (option->state & QStyle::State_Enabled) && parentStyle()->objectName() == QLatin1String("oxygen")) { // Ugly fix for visual glitch of oxygen; no chance for improvement since // we've forked QMenu and oxygen checks for qobject_cast directly. QColor c(option->palette.color(QPalette::Window)); int h, s, v, a; c.getHsv(&h, &s, &v, &a); // Why 0.91208791? I knew you're curious. There are some algorithms in Oxygen // to make color a bit lighter. They are not in the public API nor they are simple. // So the number was computed by me to find the proper value for the color // (the accuracy is quite OK). // It's also related to the fact that Oxygen's menus have gradient background. // A lot of computation happens under the mask... c.setHsv(h, s, v * 0.91208791, a); painter->fillRect(option->rect.x() + 6, option->rect.y() + 6, option->rect.width() - 12, option->rect.height() - 12, c); } KexiUtils::StyleProxy::drawControl(element, option, painter, widget); } #endif KexiMainMenu::KexiMainMenu(KexiTabbedToolBar *toolBar, QWidget* parent) : QWidget(parent), m_toolBar(toolBar), m_initialized(false) { m_content = 0; m_selectFirstItem = false; } KexiMainMenu::~KexiMainMenu() { delete (QWidget*)m_contentWidget; } bool KexiMainMenu::eventFilter(QObject * watched, QEvent* event) { if (event->type() == QEvent::MouseButtonPress && watched == m_content && !m_contentWidget) { emit contentAreaPressed(); } else if (event->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast(event); if ((ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) { emit hideContentsRequested(); return true; } } return QWidget::eventFilter(watched, event); } void KexiMainMenu::setContent(QWidget *contentWidget) { if (m_menuWidget && m_persistentlySelectedAction) { m_menuWidget->setPersistentlySelectedAction( m_persistentlySelectedAction, m_persistentlySelectedAction->persistentlySelected()); } /*if (m_menuWidget->persistentlySelectedAction()) qDebug() << "****" << m_menuWidget->persistentlySelectedAction()->objectName();*/ KexiFadeWidgetEffect *fadeEffect = 0; if (m_contentWidget && contentWidget) { fadeEffect = new KexiFadeWidgetEffect(m_content); } if (m_contentWidget) m_contentWidget->deleteLater(); m_contentWidget = contentWidget; if (m_contentWidget) { QPalette contentWidgetPalette(m_contentWidget->palette()); contentWidgetPalette.setBrush(QPalette::Active, QPalette::Window, contentWidgetPalette.brush(QPalette::Active, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::Window, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Window, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base)); contentWidgetPalette.setBrush(QPalette::Active, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Active, QPalette::Text)); contentWidgetPalette.setBrush(QPalette::Inactive, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Inactive, QPalette::Text)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::WindowText, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Text)); const QColor highlightDisabled(KexiUtils::blendedColors( contentWidgetPalette.color(QPalette::Active, QPalette::Highlight), contentWidgetPalette.color(QPalette::Disabled, QPalette::Window), 1, 2)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlightDisabled); const QColor highlightedTextDisabled(KexiUtils::blendedColors( contentWidgetPalette.color(QPalette::Active, QPalette::HighlightedText), contentWidgetPalette.color(QPalette::Disabled, QPalette::WindowText), 1, 2)); contentWidgetPalette.setBrush(QPalette::Disabled, QPalette::HighlightedText, highlightedTextDisabled); m_contentWidget->setPalette(contentWidgetPalette); for(QAbstractScrollArea *area : m_contentWidget->findChildren()) { QPalette pal(area->viewport()->palette()); pal.setBrush(QPalette::Disabled, QPalette::Base, contentWidgetPalette.brush(QPalette::Disabled, QPalette::Base)); area->viewport()->setPalette(pal); } m_contentWidget->setAutoFillBackground(true); m_contentWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); m_contentWidget->setContentsMargins(0, 0, 0, 0); m_contentLayout->addWidget(m_contentWidget); m_contentLayout->setCurrentWidget(m_contentWidget); m_contentWidget->setFocus(); m_contentWidget->installEventFilter(this); //connect(m_contentWidget, SIGNAL(destroyed()), this, SLOT(contentWidgetDestroyed())); } if (fadeEffect) { if (m_contentWidget) m_contentLayout->update(); QTimer::singleShot(10, fadeEffect, SLOT(start())); } } const QWidget *KexiMainMenu::contentWidget() const { return m_contentWidget; } void KexiMainMenu::setPersistentlySelectedAction(KexiMenuWidgetAction* action, bool set) { m_persistentlySelectedAction = action; m_persistentlySelectedAction->setPersistentlySelected(set); } /* void KexiMainMenu::setActiveAction(QAction* action = 0) { if (!action && !m_menuWidget->actions().isEmpty()) { action = actions().first(); } if (action) { m_menuWidget->setActiveAction(action); } } */ void KexiMainMenu::selectFirstItem() { m_selectFirstItem = true; } void KexiMainMenu::showEvent(QShowEvent * event) { if (!m_initialized) { m_initialized = true; KActionCollection *ac = KexiMainWindowIface::global()->actionCollection(); QHBoxLayout *hlyr = new QHBoxLayout(this); hlyr->setSpacing(0); hlyr->setMargin(0); m_menuWidget = new KexiMenuWidget; //! @todo KEXI3 is KexiMenuWidgetStyle needed? #if 0 QString styleName(m_menuWidget->style()->objectName()); if (KDE::version() < KDE_MAKE_VERSION(4, 8, 0) // a fix is apparently needed for glitch in KDE < 4.8 && styleName == "oxygen") { KexiMenuWidgetStyle *customStyle = new KexiMenuWidgetStyle(m_menuWidget->style()->objectName(), this); m_menuWidget->setStyle(customStyle); } #endif m_menuWidget->installEventFilter(this); m_menuWidget->setFocusPolicy(Qt::StrongFocus); setFocusProxy(m_menuWidget); m_menuWidget->setFrame(false); m_menuWidget->setAutoFillBackground(true); m_menuWidget->addAction(ac->action("project_welcome")); m_menuWidget->addAction(ac->action("project_open")); m_menuWidget->addAction(ac->action("project_close")); m_menuWidget->addSeparator(); m_menuWidget->addAction(ac->action("project_new")); m_menuWidget->addAction(ac->action("project_import_export_send")); #ifdef KEXI_SHOW_UNIMPLEMENTED m_menuWidget->addAction(ac->action("project_properties")); //! @todo project information m_menuWidget->addAction(ac->action("settings")); #endif m_menuWidget->addSeparator(); m_menuWidget->addAction(ac->action("quit")); hlyr->addWidget(m_menuWidget); m_content = new EmptyMenuContentWidget; m_content->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); m_content->installEventFilter(this); m_mainContentLayout = new QVBoxLayout; hlyr->addLayout(m_mainContentLayout); m_contentLayout = new QStackedLayout(m_content); m_contentLayout->setStackingMode(QStackedLayout::StackAll); m_contentLayout->setContentsMargins(0, 0, 0, 0); m_mainContentLayout->addWidget(m_content); hlyr->setStretchFactor(m_mainContentLayout, 1); } QWidget::showEvent(event); if (m_selectFirstItem && !m_menuWidget->actions().isEmpty()) { QAction* action = m_menuWidget->actions().first(); m_menuWidget->setActiveAction(action); m_selectFirstItem = false; } } // --- KexiTabbedToolBar::Private::Private(KexiTabbedToolBar *t) : q(t), createWidgetToolBar(0) #ifdef KEXI_AUTORISE_TABBED_TOOLBAR , tabToRaise(-1) #endif , rolledUp(false) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR tabRaiseTimer.setSingleShot(true); tabRaiseTimer.setInterval(300); #endif tabBarAnimation.setPropertyName("opacity"); tabBarAnimation.setDuration(500); connect(&tabBarAnimation, SIGNAL(finished()), q, SLOT(tabBarAnimationFinished())); tabIndex = 0; lowestIndex = 2; } //! @return true if @a style name is specific regarding tab styling static bool isSpecificTabStyle(const QString &styleName) { return styleName == "oxygen" || styleName == "qtcurve" || styleName == "gtk+"; } KexiTabbedToolBarStyle::KexiTabbedToolBarStyle(const QString &baseStyleName) : QProxyStyle(baseStyleName) { } KexiTabbedToolBarStyle::~KexiTabbedToolBarStyle() { } void KexiTabbedToolBarStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { const QString styleName(baseStyle()->objectName()); qreal origOpacity = -1.0; if (element == CE_TabBarTab) { const QStyleOptionTab* opt = qstyleoption_cast(option); const QTabBar* tabBar = qobject_cast(widget); KexiTabbedToolBar* tbar = tabBar ? qobject_cast(tabBar->parentWidget()) : 0; if (opt && tbar) { const int index = tabBar->tabAt(opt->rect.center()); if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) return; bool mouseOver = opt->state & QStyle::State_MouseOver; bool unselectedOrMenuVisible = !(opt->state & State_Selected) || tbar->mainMenuVisible(); if (unselectedOrMenuVisible) { if (styleName == "bespin") { unselectedOrMenuVisible = false; } } QStyleOptionTab newOpt(*opt); const bool specificStyle = isSpecificTabStyle(styleName); newOpt.text = (specificStyle ? " " : "") + tabBar->tabText(index) + (specificStyle ? " " : ""); if (!mouseOver && unselectedOrMenuVisible && index > 0) { if (tbar->mainMenuVisible()) newOpt.state &= ~QStyle::State_HasFocus; QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget); return; } else if (index == 0) { QBrush bg; newOpt.state |= State_Selected; if (tbar->mainMenuVisible()) { bg = newOpt.palette.brush(QPalette::Active, QPalette::Highlight); if (!specificStyle) { newOpt.palette.setBrush(QPalette::WindowText, newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText)); newOpt.palette.setBrush(QPalette::ButtonText, newOpt.palette.brush(QPalette::Active, QPalette::HighlightedText)); } } else { bg = Qt::transparent; } QFont origFont(painter->font()); QFont f(origFont); f.setBold(true); painter->setFont(f); newOpt.palette.setBrush(QPalette::Window, bg); newOpt.palette.setBrush(QPalette::Button, // needed e.g. for Plastique style bg); QProxyStyle::drawControl(element, &newOpt, painter, widget); painter->setFont(origFont); if (!mouseOver || tbar->mainMenuVisible() || styleName == "gtk+") { return; } } if (index > 0 || mouseOver) { const QPalette::ColorGroup hbGroup = (styleName == "oxygen") ? QPalette::Active : QPalette::Inactive; const QBrush hb(newOpt.palette.brush(hbGroup, QPalette::Highlight)); newOpt.palette.setBrush(QPalette::Window, hb); newOpt.palette.setBrush(QPalette::Button, hb); // needed e.g. for Plastique style if (mouseOver && (index != tbar->currentIndex() || tbar->mainMenuVisible())) { // use lower opacity for diplaying hovered tabs origOpacity = painter->opacity(); painter->setOpacity(styleName == "qtcurve" ? 0.2 : 0.3); newOpt.state |= State_Selected; } else { if (!specificStyle) { newOpt.palette.setBrush(QPalette::WindowText, newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText)); newOpt.palette.setBrush(QPalette::ButtonText, newOpt.palette.brush(QPalette::Inactive, QPalette::HighlightedText)); } } if (index == tbar->currentIndex() && styleName == "qtcurve") { origOpacity = painter->opacity(); painter->setOpacity(0.5); } (newOpt.state |= State_Active) ^= State_Active; QProxyStyle::drawControl(element, &newOpt, painter, widget); if (origOpacity != -1.0) { // restore opacity and draw labels using full this opacity painter->setOpacity(origOpacity); if (index > 0) { QProxyStyle::drawControl(CE_TabBarTabLabel, &newOpt, painter, widget); } } return; } } } else if (element == CE_ToolBar) { return; } QProxyStyle::drawControl(element, option, painter, widget); } void KexiTabbedToolBarStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { const QString styleName(baseStyle()->objectName()); if (element == PE_FrameTabWidget) { return; } if (element == PE_FrameTabBarBase) { const QTabBar* tabBar = qobject_cast(widget); KexiTabbedToolBar* tbar = tabBar ? qobject_cast(tabBar->parentWidget()) : 0; if (tbar && tbar->mainMenuVisible() && styleName != "bespin") { return; } } if (element == QStyle::PE_PanelToolBar || element == QStyle::PE_FrameMenu) { return; } QProxyStyle::drawPrimitive(element, option, painter, widget); } int KexiTabbedToolBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const { if (metric == QStyle::PM_SmallIconSize) return KIconLoader::SizeMedium; return QProxyStyle::pixelMetric(metric, option, widget); } // --- KexiTabbedToolBarTabBar::KexiTabbedToolBarTabBar(QWidget *parent) : QTabBar(parent) { setObjectName("tabbar"); customStyle = new KexiTabbedToolBarStyle(style()->objectName()); customStyle->setParent(this); setStyle(customStyle); installEventFilter(parent); QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); mainWindow->installEventFilter(parent); setAttribute(Qt::WA_Hover, true); } QSize KexiTabbedToolBarTabBar::originalTabSizeHint(int index) const { return QTabBar::tabSizeHint(index); } QSize KexiTabbedToolBarTabBar::tabSizeHint(int index) const { QSize s = QTabBar::tabSizeHint(index); QStyleOptionTab ot; ot.initFrom(this); QFont f(font()); f.setBold(true); ot.text = (isSpecificTabStyle(style()->objectName()) ? " " : "") + tabText(index); ot.fontMetrics = QFontMetrics(f); int w = customStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, &ot, this); if (w <= 0) { // needed e.g. for oxygen w = fontMetrics().width(" "); } if (index == 0) { s.setWidth(QFontMetrics(f).width(ot.text) + w * 2); return s; } else if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) { // fix width of the spacer tab s.setWidth(w); } return s; } void KexiTabbedToolBar::Private::toggleMainMenu() { if (q->mainMenuVisible()) hideMainMenu(); else showMainMenu(); } void KexiTabbedToolBar::Private::showMainMenu(const char* actionName) { QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); if (!mainMenu) { mainMenu = new KexiMainMenu(q, mainWindow); connect(mainMenu, SIGNAL(contentAreaPressed()), this, SLOT(hideMainMenu())); connect(mainMenu, SIGNAL(hideContentsRequested()), this, SLOT(hideContentsOrMainMenu())); } updateMainMenuGeometry(); if (actionName) { q->selectMainMenuItem(actionName); } else { mainMenu->selectFirstItem(); } mainMenu->show(); mainMenu->setFocus(); q->update(); // tab bar could have a line that should be repainted } void KexiTabbedToolBar::Private::updateMainMenuGeometry() { if (!mainMenu) return; QWidget *mainWindow = KexiMainWindowIface::global()->thisWidget(); KexiTabbedToolBarTabBar *tabBar = static_cast(q->tabBar()); QPoint pos = q->mapToGlobal(QPoint(0, tabBar->originalTabSizeHint(0).height() - 1)); // qDebug() << "1." << pos; pos = mainWindow->mapFromGlobal(pos); // qDebug() << "2." << pos; // qDebug() << "3." << q->pos(); QStyleOptionTab ot; ot.initFrom(tabBar); int overlap = tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &ot, tabBar) - tabBar->style()->pixelMetric(QStyle::PM_TabBarBaseHeight, &ot, tabBar); // qDebug() << "4. overlap=" << overlap; mainMenu->setGeometry(0, pos.y() - overlap /*- q->y()*/, mainWindow->width(), mainWindow->height() - pos.y() + overlap /*+ q->y()*/); } void KexiTabbedToolBar::activateSearchLineEdit() { d->searchLineEdit->selectAll(); d->searchLineEdit->setFocus(); } void KexiTabbedToolBar::Private::hideMainMenu() { if (!mainMenu || !mainMenu->isVisible()) return; mainMenu->hide(); mainMenu->setContent(0); q->update(); // tab bar could have a line that should be repainted } void KexiTabbedToolBar::Private::hideContentsOrMainMenu() { if (!mainMenu || !mainMenu->isVisible()) return; if (mainMenu->contentWidget()) { mainMenu->setContent(0); } else { hideMainMenu(); } } KToolBar *KexiTabbedToolBar::Private::createToolBar(const char *name, const QString& caption) { KToolBar *tbar = new KToolBar(q, true /*main toolbar*/, false /*read config*/); tbar->setIconDimensions(22); //!< @todo make configurable or system-dependent? // needed e.g. for Windows style to remove the toolbar's frame tbar->setStyle(customTabBar->customStyle); toolbarsForName.insert(name, tbar); tbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); tbar->setObjectName(name); toolbarsCaptionForName.insert(name, caption); tabIndex = q->addTab(tbar, caption); toolbarsVisibleForIndex.append(true); toolbarsIndexForName.insert(name, tabIndex); return tbar; } KexiTabbedToolBar::KexiTabbedToolBar(QWidget *parent) : QTabWidget(parent) , d(new Private(this)) { d->customTabBar = new KexiTabbedToolBarTabBar(this); setTabBar(d->customTabBar); setStyle(d->customTabBar->customStyle); // from ktabwidget.cpp //! @todo QTabWidget::setTabBar() should be added with this code //! @todo KEXI3 Are these tabBar() connections useful to port? #if 0 connect(tabBar(), SIGNAL(contextMenu(int,QPoint)), SLOT(contextMenu(int,QPoint&))); connect(tabBar(), SIGNAL(tabDoubleClicked(int)), SLOT(mouseDoubleClick(int))); connect(tabBar(), SIGNAL(newTabRequest()), this, SIGNAL(mouseDoubleClick())); // #185487 connect(tabBar(), SIGNAL(mouseMiddleClick(int)), SLOT(mouseMiddleClick(int))); connect(tabBar(), SIGNAL(initiateDrag( int )), SLOT(initiateDrag( int ))); connect(tabBar(), SIGNAL(testCanDecode(QDragMoveEvent*,bool*)), SIGNAL(testCanDecode(QDragMoveEvent*,bool*))); connect(tabBar(), SIGNAL(receivedDropEvent(int,QDropEvent*)), SLOT(receivedDropEvent(int,QDropEvent*))); connect(tabBar(), SIGNAL(moveTab(int,int)), SLOT(moveTab(int,int))); connect(tabBar(), SIGNAL(tabCloseRequested(int)), SLOT(closeRequest(int))); #endif setMouseTracking(true); // for mouseMoveEvent() setWhatsThis(xi18n("Task-oriented toolbar. Groups commands using tabs.")); #ifdef KEXI_AUTORISE_TABBED_TOOLBAR connect(&d->tabRaiseTimer, SIGNAL(timeout()), this, SLOT(slotDelayedTabRaise())); #endif connect(tabBar(), SIGNAL(tabBarDoubleClicked(int)), this, SLOT(slotTabDoubleClicked(int))); d->ac = KexiMainWindowIface::global()->actionCollection(); const bool userMode = KexiMainWindowIface::global()->userMode(); KToolBar *tbar; slotSettingsChanged(0);//KGlobalSettings::FontChanged //! @todo KEXI3 port from KGlobalSettings::Private::_k_slotNotifyChange: //! connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), this, SLOT(slotSettingsChanged(int))); // help area QWidget *helpWidget = new QWidget(this); helpWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); QHBoxLayout *helpLyr = new QHBoxLayout(helpWidget); helpLyr->setContentsMargins(0, 0, 0, 0); setCornerWidget(helpWidget, Qt::TopRightCorner); d->searchLineEdit = new KexiSearchLineEdit; kexiTester() << KexiTestObject(d->searchLineEdit, "globalSearch.lineEdit"); d->searchLineEdit->installEventFilter(this); helpLyr->addWidget(d->searchLineEdit); // needed e.g. for Windows style to remove the toolbar's frame QWidget *dummyWidgetForMainMenu = new QWidget(this); dummyWidgetForMainMenu->setObjectName("kexi"); addTab(dummyWidgetForMainMenu, KAboutData::applicationData().displayName()); d->toolbarsVisibleForIndex.append(true); addTab(new QWidget(this), QString()); // dummy for spacer d->toolbarsVisibleForIndex.append(true); if (!userMode) { d->createWidgetToolBar = d->createToolBar("create", xi18n("Create")); } //! @todo move to form plugin tbar = d->createToolBar("form", xi18n("Form Design")); //! @todo move to report plugin tbar = d->createToolBar("report", xi18n("Report Design")); Q_UNUSED(tbar) connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int))); setCurrentWidget(widget(KEXITABBEDTOOLBAR_SPACER_TAB_INDEX + 1)); // the default setFocusPolicy(Qt::NoFocus); } void KexiTabbedToolBar::Private::setCurrentTab(const QString& name) { q->setCurrentWidget(q->toolBar(name)); } void KexiTabbedToolBar::Private::hideTab(const QString& name) { q->removeTab(q->indexOf(toolbarsForName.value(name))); toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = false; } bool KexiTabbedToolBar::Private::isTabVisible(const QString& name) const { return q->indexOf(toolbarsForName.value(name)) != -1 && toolbarsVisibleForIndex[toolbarsIndexForName.value(name)]; } #ifndef NDEBUG void KexiTabbedToolBar::Private::debugToolbars() const { qDebug() << "QHash toolbarsForName:"; for (QHash::ConstIterator it(toolbarsForName.constBegin()); it!=toolbarsForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QHash toolbarsIndexForName:"; for (QHash::ConstIterator it(toolbarsIndexForName.constBegin()); it!=toolbarsIndexForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QHash toolbarsCaptionForName:"; for (QHash::ConstIterator it(toolbarsCaptionForName.constBegin()); it!=toolbarsCaptionForName.constEnd(); ++it) { qDebug() << it.key() << "->" << it.value(); } qDebug() << "QVector toolbarsVisibleForIndex:"; for (int i = 0; i < toolbarsVisibleForIndex.size(); i++) { qDebug() << i << "->" << toolbarsVisibleForIndex[i]; } } #endif void KexiTabbedToolBar::Private::showTab(const QString& name) { // qDebug() << "name:" << name; // qDebug() << "toolbarsForName.value(name):" << toolbarsForName.value(name); // qDebug() << "toolbarsIndexForName.value(name):" << toolbarsIndexForName.value(name); // qDebug() << "q->indexOf(toolbarsForName.value(name))" << q->indexOf(toolbarsForName.value(name)); #ifndef NDEBUG //debugToolbars(); #endif if (q->indexOf(toolbarsForName.value(name)) == -1) { int h = 0; // count h = invisible tabs before this for (int i = lowestIndex; i < toolbarsIndexForName.value(name); i++) { if (!toolbarsVisibleForIndex.at(i)) h++; } q->insertTab(toolbarsIndexForName.value(name) - h, toolbarsForName.value(name), toolbarsCaptionForName.value(name)); toolbarsVisibleForIndex[toolbarsIndexForName.value(name)] = true; } } // --- KexiTabbedToolBar::~KexiTabbedToolBar() { delete d; } bool KexiTabbedToolBar::mainMenuVisible() const { return d->mainMenu && d->mainMenu->isVisible(); } QRect KexiTabbedToolBar::tabRect(int index) const { return tabBar()->tabRect(index); } void KexiTabbedToolBar::slotSettingsChanged(int category) { Q_UNUSED(category); //! @todo if (category == KGlobalSettings::FontChanged) { //! @todo KEXI3 KGlobalSettings::menuFont() not available (using QFontDatabase::systemFont(QFontDatabase::GeneralFont) for now) //! https://community.kde.org/Frameworks/Porting_Notes#Global_Settings setFont(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); // the toolbar acts like a menu //} } KToolBar* KexiTabbedToolBar::createWidgetToolBar() const { return d->createWidgetToolBar; } void KexiTabbedToolBar::mouseMoveEvent(QMouseEvent* event) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR QPoint p = event->pos(); int tab = tabBar()->tabAt(p); if (d->tabToRaise != -1 && (tab == -1 || tab == currentIndex())) { d->tabRaiseTimer.stop(); d->tabToRaise = -1; } else if (d->tabToRaise != tab) { d->tabRaiseTimer.start(); d->tabToRaise = tab; } #endif QTabWidget::mouseMoveEvent(event); } void KexiTabbedToolBar::leaveEvent(QEvent* event) { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR d->tabRaiseTimer.stop(); d->tabToRaise = -1; #endif QTabWidget::leaveEvent(event); } bool KexiTabbedToolBar::eventFilter(QObject* watched, QEvent* event) { switch (event->type()) { case QEvent::MouseButtonPress: { QWidget *mainWin = KexiMainWindowIface::global()->thisWidget(); // qDebug() << "MouseButtonPress: watched:" << watched << "window()->focusWidget():" << window()->focusWidget(); if (watched == d->searchLineEdit) { activateSearchLineEdit(); // custom setFocus() for search box, so it's possible to focus // back on Escape key press return false; } else if (watched == tabBar()) { QMouseEvent* me = static_cast(event); QPoint p = me->pos(); KexiTabbedToolBarTabBar *tb = static_cast(tabBar()); int index = tb->tabAt(p); if (index == 0) { d->toggleMainMenu(); return true; } d->hideMainMenu(); if (index == KEXITABBEDTOOLBAR_SPACER_TAB_INDEX) { return true; } } else if (watched == mainWin && d->mainMenu) { QMouseEvent* me = static_cast(event); if (!QRect(d->mainMenu->mapToGlobal(QPoint(0,0)), d->mainMenu->size()) .contains(mainWin->mapToGlobal(me->pos()))) { // hide if clicked outside of the menu d->hideMainMenu(); } } } break; case QEvent::KeyPress: { QKeyEvent* ke = static_cast(event); // qDebug() << "**********" << QString::number(ke->key(), 16) // << QKeySequence::mnemonic(tabText(0))[0]; if (QKeySequence::mnemonic(tabText(0)) == QKeySequence(ke->key())) { // qDebug() << "eat the &File accel"; if (!d->mainMenu || !d->mainMenu->isVisible()) { d->showMainMenu(); } /*this could be unexpected: else if (d->mainMenu && d->mainMenu->isVisible()) { d->hideMainMenu(); }*/ return true; } if (d->mainMenu && d->mainMenu->isVisible() && (ke->key() == Qt::Key_Escape) && ke->modifiers() == Qt::NoModifier) { d->hideContentsOrMainMenu(); return true; } break; } case QEvent::Resize: if (watched == KexiMainWindowIface::global()->thisWidget()) { d->updateMainMenuGeometry(); } break; case QEvent::Shortcut: { QShortcutEvent *se = static_cast(event); if (watched == tabBar() && QKeySequence::mnemonic(tabText(0)) == se->key()) { // qDebug() << "eat the &File accel"; if (!d->mainMenu || !d->mainMenu->isVisible()) { d->showMainMenu(); return true; } } break; } default:; } return QTabWidget::eventFilter(watched, event); } void KexiTabbedToolBar::slotCurrentChanged(int index) { if (index == indexOf(d->createWidgetToolBar) && index != -1) { if (d->createWidgetToolBar->actions().isEmpty()) { QTimer::singleShot(10, this, SLOT(setupCreateWidgetToolbar())); } } if (d->rolledUp) { // switching the tab rolls down slotTabDoubleClicked(index); } if (index == 0) { // main menu d->showMainMenu(); } else { d->hideMainMenu(); } } void KexiTabbedToolBar::slotTabDoubleClicked(int index) { if (index <= 0) { return; // main item does not count here } d->rolledUp = !d->rolledUp; d->tabBarAnimation.stop(); QWidget *w = widget(index); if (!w) { return; } w->setGraphicsEffect(&d->tabBarOpacityEffect); if (d->rolledUp) { d->tabBarOpacityEffect.setOpacity(1.0); d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect); d->tabBarAnimation.setStartValue(1.0); d->tabBarAnimation.setEndValue(0.0); d->tabBarAnimation.start(); } else { // roll down d->tabBarOpacityEffect.setOpacity(0.0); setMaximumHeight(QWIDGETSIZE_MAX); widget(d->rolledUpIndex)->show(); widget(d->rolledUpIndex)->setMaximumHeight(QWIDGETSIZE_MAX); w->setMaximumHeight(QWIDGETSIZE_MAX); w->show(); d->tabBarAnimation.setTargetObject(&d->tabBarOpacityEffect); d->tabBarAnimation.setStartValue(0.0); d->tabBarAnimation.setEndValue(1.0); d->tabBarAnimation.start(); } } void KexiTabbedToolBar::tabBarAnimationFinished() { if (d->rolledUp) { // hide and collapse the area widget(currentIndex())->hide(); KexiTabbedToolBarTabBar *tb = static_cast(tabBar()); setFixedHeight(tb->tabSizeHint(currentIndex()).height()); widget(currentIndex())->setFixedHeight(0); d->rolledUpIndex = currentIndex(); } } void KexiTabbedToolBar::setupCreateWidgetToolbar() { if (!d->createWidgetToolBar->actions().isEmpty()) return; //! @todo separate core object types from custom.... KexiPart::PartInfoList *plist = Kexi::partManager().infoList(); //this list is properly sorted if (plist) { foreach(KexiPart::Info *info, *plist) { QAction* a = info->newObjectAction(); if (a) { d->createWidgetToolBar->addAction(a); } else { //! @todo err } } } } void KexiTabbedToolBar::slotDelayedTabRaise() { #ifdef KEXI_AUTORISE_TABBED_TOOLBAR QPoint p = mapFromGlobal(QCursor::pos()); // make sure cursor is still over the tab int tab = tabBar()->tabAt(p); if (tab != d->tabToRaise) { d->tabToRaise = -1; } else if (d->tabToRaise != -1) { setCurrentIndex(d->tabToRaise); d->tabToRaise = -1; } #endif } KToolBar *KexiTabbedToolBar::toolBar(const QString& name) const { return d->toolbarsForName[name]; } void KexiTabbedToolBar::addAction(KToolBar *tbar, const char* actionName) { QAction *a = d->ac->action(actionName); if (a) tbar->addAction(a); } void KexiTabbedToolBar::addAction(const QString& toolBarName, QAction *action) { if (!action) return; KToolBar *tbar = d->toolbarsForName[toolBarName]; if (!tbar) return; tbar->addAction(action); } void KexiTabbedToolBar::addSeparatorAndAction(KToolBar *tbar, const char* actionName) { QAction *a = d->ac->action(actionName); if (a) { tbar->addSeparator(); tbar->addAction(a); } } void KexiTabbedToolBar::appendWidgetToToolbar(const QString& name, QWidget* widget) { KToolBar *tbar = d->toolbarsForName[name]; if (!tbar) { return; } QAction *action = tbar->addWidget(widget); d->extraActions.insert(widget, action); } void KexiTabbedToolBar::setWidgetVisibleInToolbar(QWidget* widget, bool visible) { QAction *action = d->extraActions[widget]; if (!action) { return; } action->setVisible(visible); } void KexiTabbedToolBar::showMainMenu(const char* actionName) { d->showMainMenu(actionName); } void KexiTabbedToolBar::hideMainMenu() { d->hideMainMenu(); } void KexiTabbedToolBar::toggleMainMenu() { d->toggleMainMenu(); } void KexiTabbedToolBar::setMainMenuContent(QWidget *w) { d->mainMenu->setContent(w); } void KexiTabbedToolBar::selectMainMenuItem(const char *actionName) { if (actionName) { KActionCollection *ac = KexiMainWindowIface::global()->actionCollection(); KexiMenuWidgetAction *a = qobject_cast(ac->action(actionName)); if (a) { d->mainMenu->setPersistentlySelectedAction(a, true); } } } void KexiTabbedToolBar::addSearchableModel(KexiSearchableModel *model) { d->searchLineEdit->addSearchableModel(model); } KToolBar* KexiTabbedToolBar::createToolBar(const char* name, const QString& caption) { return d->createToolBar(name, caption); } void KexiTabbedToolBar::setCurrentTab(const QString& name) { //qDebug() << name; d->setCurrentTab(name); } void KexiTabbedToolBar::setCurrentTab(int index) { setCurrentIndex(d->lowestIndex + index); } void KexiTabbedToolBar::hideTab(const QString& name) { //qDebug() << name; d->hideTab(name); } void KexiTabbedToolBar::showTab(const QString& name) { //qDebug() << name; d->showTab(name); } bool KexiTabbedToolBar::isTabVisible(const QString& name) const { return d->isTabVisible(name); } bool KexiTabbedToolBar::isRolledUp() { return d->rolledUp; } void KexiTabbedToolBar::toggleRollDown() { slotTabDoubleClicked(-1);//use -1 just to rolldown/up the tabbar } //------------------------------------------ KexiMainWindow::Private::Private(KexiMainWindow* w) : wnd(w) { objectViewWidget = 0; actionCollection = new KActionCollection(w); KexiProjectData *pdata = KexiStartupHandler::global()->projectData(); userMode = KexiStartupHandler::global()->forcedUserMode() /* <-- simply forced the user mode */ /* project has 'user mode' set as default and not 'design mode' override is found: */ || (pdata && pdata->userMode() && !KexiStartupHandler::global()->forcedDesignMode()); isProjectNavigatorVisible = KexiStartupHandler::global()->isProjectNavigatorVisible(); isMainMenuVisible = KexiStartupHandler::global()->isMainMenuVisible(); prj = 0; config = KSharedConfig::openConfig(); nameDialog = 0; m_findDialog = 0; focus_before_popup = 0; action_show_nav = 0; action_show_propeditor = 0; action_activate_nav = 0; action_activate_propeditor = 0; forceWindowClosing = false; insideCloseWindow = false; #ifndef KEXI_NO_PENDING_DIALOGS actionToExecuteWhenPendingJobsAreFinished = NoAction; #endif propEditorDockSeparatorPos = -1; navDockSeparatorPos = -1; wasAutoOpen = false; windowExistedBeforeCloseProject = false; #ifndef KEXI_SHOW_UNIMPLEMENTED dummy_action = new KActionMenu(QString(), wnd); #endif forceShowProjectNavigatorOnCreation = false; forceHideProjectNavigatorOnCreation = false; navWasVisibleBeforeProjectClosing = false; saveSettingsForShowProjectNavigator = true; propertyEditorCollapsed = false; enable_slotPropertyEditorVisibilityChanged = true; migrateManager = 0; } KexiMainWindow::Private::~Private() { qDeleteAll(m_openedCustomObjectsForItem); } void KexiMainWindow::Private::insertWindow(KexiWindow *window) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.insert(window->id(), window); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.remove(window->id()); #endif } bool KexiMainWindow::Private::windowContainerExistsFor(int identifier) const { return windowContainers.contains(identifier); } void KexiMainWindow::Private::setWindowContainerExistsFor(int identifier, bool set) { if (set) { windowContainers.insert(identifier); } else { windowContainers.remove(identifier); } } void KexiMainWindow::Private::updateWindowId(KexiWindow *window, int oldItemID) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.remove(oldItemID); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.remove(oldItemID); #endif windows.insert(window->id(), window); } void KexiMainWindow::Private::removeWindow(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.remove(identifier); } int KexiMainWindow::Private::openedWindowsCount() { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return windows.count(); } //! Used in KexiMainWindowe::closeProject() void KexiMainWindow::Private::clearWindows() { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); windows.clear(); #ifndef KEXI_NO_PENDING_DIALOGS pendingWindows.clear(); #endif } void KexiMainWindow::Private::showStartProcessMsg(const QStringList& args) { wnd->showErrorMessage(xi18nc("@info", "Could not start %1 application.", QString::fromLatin1(KEXI_APP_NAME)), xi18nc("@info", "Command %1 failed.", args.join(" "))); } void KexiMainWindow::Private::updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info) { if (!objectViewWidget || !objectViewWidget->propertyPane()) { return; } KexiWindow *currentWindow = wnd->currentWindow(); if (!info && currentWindow) { info = currentWindow->part()->info(); } const bool visible = (viewMode == Kexi::DesignViewMode) && ((currentWindow && currentWindow->propertySet()) || (info && info->isPropertyEditorAlwaysVisibleInDesignMode())); //qDebug() << "visible == " << visible; enable_slotPropertyEditorVisibilityChanged = false; bool set; if (visible && propertyEditorCollapsed) { // used when we're switching back to a window with propeditor available but collapsed set = !visible; } else { set = visible; } objectViewWidget->propertyPane()->setVisible(set); action_show_propeditor->setChecked(set); action_show_propeditor->setEnabled(set); objectViewWidget->updateSidebarWidths(); enable_slotPropertyEditorVisibilityChanged = true; } /* void KexiMainWindow::Private::setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id, KexiDockWidget *dockWidget, bool visible) { KMultiTabBar *mtbar = multiTabBars.value(position); if (!mtbar) { return; } if (!visible) { mtbar->removeTab(id); } else if (!mtbar->tab(id)) { mtbar->appendTab(koIcon("document-properties"), id, dockWidget->tabText); KMultiTabBarTab *tab = mtbar->tab(id); QObject::connect(tab, SIGNAL(clicked(int)), wnd, SLOT(slotMultiTabBarTabClicked(int)), Qt::UniqueConnection); } } void KexiMainWindow::Private::setPropertyEditorTabBarVisible(bool visible) { setTabBarVisible(KMultiTabBar::Right, PROPERTY_EDITOR_TABBAR_ID, objectViewWidget->propertyEditorTabWidget(), visible); }*/ QObject *KexiMainWindow::Private::openedCustomObjectsForItem(KexiPart::Item* item, const char* name) { if (!item || !name) { qWarning() << "!item || !name"; return 0; } QByteArray key(QByteArray::number(item->identifier()) + name); return m_openedCustomObjectsForItem.value(key); } void KexiMainWindow::Private::addOpenedCustomObjectForItem(KexiPart::Item* item, QObject* object, const char* name) { QByteArray key(QByteArray::number(item->identifier()) + name); m_openedCustomObjectsForItem.insert(key, object); } KexiFindDialog *KexiMainWindow::Private::findDialog() { if (!m_findDialog) { m_findDialog = new KexiFindDialog(wnd); m_findDialog->setActions(action_edit_findnext, action_edit_findprev, action_edit_replace, action_edit_replace_all); } return m_findDialog; } void KexiMainWindow::Private::updateFindDialogContents(bool createIfDoesNotExist) { if (!wnd->currentWindow()) return; if (!createIfDoesNotExist && (!m_findDialog || !m_findDialog->isVisible())) return; KexiSearchAndReplaceViewInterface* iface = currentViewSupportingSearchAndReplaceInterface(); if (!iface) { if (m_findDialog) { m_findDialog->setButtonsEnabled(false); m_findDialog->setLookInColumnList(QStringList(), QStringList()); } return; } //! @todo use ->caption() here, depending on global settings related to displaying captions findDialog()->setObjectNameForCaption(wnd->currentWindow()->partItem()->name()); QStringList columnNames; QStringList columnCaptions; QString currentColumnName; // for 'look in' if (!iface->setupFindAndReplace(columnNames, columnCaptions, currentColumnName)) { m_findDialog->setButtonsEnabled(false); m_findDialog->setLookInColumnList(QStringList(), QStringList()); return; } m_findDialog->setButtonsEnabled(true); const QString prevColumnName(m_findDialog->currentLookInColumnName()); m_findDialog->setLookInColumnList(columnNames, columnCaptions); m_findDialog->setCurrentLookInColumnName(prevColumnName); } KexiView *KexiMainWindow::Private::currentViewSupportingAction(const char* actionName) const { if (!wnd->currentWindow()) return 0; KexiView *view = wnd->currentWindow()->selectedView(); if (!view) return 0; QAction *action = view->sharedAction(actionName); if (!action || !action->isEnabled()) return 0; return view; } KexiSearchAndReplaceViewInterface* KexiMainWindow::Private::currentViewSupportingSearchAndReplaceInterface() const { if (!wnd->currentWindow()) return 0; KexiView *view = wnd->currentWindow()->selectedView(); if (!view) return 0; return dynamic_cast(view); } tristate KexiMainWindow::Private::showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata) { //pass arguments QMap args; args.insert("mimeType", mimeType); args.insert("databaseName", databaseName); if (cdata) { //pass KDbConnectionData serialized as a string... QString str; KDbUtils::serializeMap(cdata->toMap(), &str); args.insert("connectionData", str); } QDialog *dlg = KexiInternalPart::createModalDialogInstance("org.kexi-project.migration", "migration", wnd, 0, &args); if (!dlg) return false; //error msg has been shown by KexiInternalPart const int result = dlg->exec(); delete dlg; if (result != QDialog::Accepted) return cancelled; //open imported project in a new Kexi instance QString destinationDatabaseName(args["destinationDatabaseName"]); QString fileName, destinationConnectionShortcut; if (!destinationDatabaseName.isEmpty()) { if (args.contains("destinationConnectionShortcut")) { // server-based destinationConnectionShortcut = args["destinationConnectionShortcut"]; } else { // file-based fileName = destinationDatabaseName; destinationDatabaseName.clear(); } tristate res = wnd->openProject(fileName, destinationConnectionShortcut, destinationDatabaseName); wnd->raise(); return res; } return true; } -KexiPropertyEditorView* KexiMainWindow::Private::propertyEditor() const +KPropertyEditorView* KexiMainWindow::Private::propertyEditor() const { return (objectViewWidget && objectViewWidget->propertyPane() && objectViewWidget->propertyPane()->editor()) ? objectViewWidget->propertyPane()->editor() : 0; } void KexiMainWindow::Private::setProjectNavigatorVisible(bool set, ShowMode mode) { if (objectViewWidget && objectViewWidget->projectNavigator()) { if (mode == ShowAnimated) { objectViewWidget->setProjectNavigatorVisible(set); if (set) { // on showing, arrow should be updated immediately wnd->slotProjectNavigatorVisibilityChanged(set); } } else { objectViewWidget->projectNavigator()->setVisible(set); action_show_nav->setChecked(set); wnd->slotProjectNavigatorVisibilityChanged(set); } } } #ifndef KEXI_NO_PENDING_DIALOGS void KexiMainWindow::Private::executeActionWhenPendingJobsAreFinished() { ActionToExecuteWhenPendingJobsAreFinished a = actionToExecuteWhenPendingJobsAreFinished; actionToExecuteWhenPendingJobsAreFinished = NoAction; switch (a) { case QuitAction: qApp->quit(); break; case CloseProjectAction: wnd->closeProject(); break; default:; } } KexiWindow *KexiMainWindow::Private::openedWindowFor(const KexiPart::Item* item, PendingJobType &pendingType) { return openedWindowFor(item->identifier(), pendingType); } KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier, PendingJobType &pendingType) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); QHash::ConstIterator it = pendingWindows.find(identifier); if (it == pendingWindows.end()) pendingType = NoJob; else pendingType = it.value(); if (pendingType == WindowOpeningJob) { return 0; } return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0; } void KexiMainWindow::Private::addItemToPendingWindows(const KexiPart::Item* item, PendingJobType jobType) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); pendingWindows.insert(item->identifier(), jobType); } bool KexiMainWindow::Private::pendingWindowsExist() { if (pendingWindows.begin() != pendingWindows.end()) qDebug() << pendingWindows.constBegin().key() << " " << (int)pendingWindows.constBegin().value(); //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return !pendingWindows.isEmpty(); } void KexiMainWindow::Private::removePendingWindow(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); pendingWindows.remove(identifier); } #else // KEXI_NO_PENDING_DIALOGS KexiWindow *KexiMainWindow::Private::openedWindowFor(int identifier) { //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return windows.contains(identifier) ? (KexiWindow*)windows.value(identifier) : 0; } #endif diff --git a/src/main/KexiObjectViewWidget.cpp b/src/main/KexiObjectViewWidget.cpp index cefc1d25a..13991f191 100644 --- a/src/main/KexiObjectViewWidget.cpp +++ b/src/main/KexiObjectViewWidget.cpp @@ -1,257 +1,257 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KexiObjectViewWidget.h" #include "KexiObjectViewTabWidget.h" -#include "KexiPropertyPaneWidget.h" -#include +#include #include #include #include #include #include #include +#include #include #include #include #include class KexiObjectViewWidget::Private { public: Private() : navigator(0) , navigatorWidthAnimator(0) , propertyPane(0) , propertyPaneWidthAnimator(0) , projectNavigatorWidthToSet(-1) , propertyPaneWidthToSet(-1) { } KexiProjectNavigator* navigator; KexiWidgetWidthAnimator* navigatorWidthAnimator; KexiObjectViewTabWidget* tabWidget; QPointer previouslyActiveWindow; KexiPropertyPaneWidget *propertyPane; KexiWidgetWidthAnimator* propertyPaneWidthAnimator; //QMap multiTabBars; QSplitter *splitter; int projectNavigatorWidthToSet; int propertyPaneWidthToSet; }; KexiObjectViewWidget::KexiObjectViewWidget(Flags flags) : QWidget() , d(new Private) { QHBoxLayout *mainLyr = new QHBoxLayout; mainLyr->setContentsMargins(0, 0, 0, 0); mainLyr->setSpacing(0); setLayout(mainLyr); d->splitter = new QSplitter(Qt::Horizontal); connect(d->splitter, &QSplitter::splitterMoved, this, &KexiObjectViewWidget::slotSplitterMoved); mainLyr->addWidget(d->splitter); // Left tab bar // KMultiTabBar *mtbar = new KMultiTabBar(KMultiTabBar::Left); // mtbar->setStyle(KMultiTabBar::VSNET); // mainLyr->addWidget(mtbar); // d->multiTabBars.insert(mtbar->position(), mtbar); if (flags & ProjectNavigatorEnabled) { // Project navigator // KexiDockableWidget* navDockableWidget = new KexiDockableWidget; d->navigator = new KexiProjectNavigator(d->splitter); kexiTester() << KexiTestObject(d->navigator, "KexiProjectNavigator"); //navDockableWidget->setWidget(d->navigator); KexiStyle::setSidebarsPalette(d->navigator); d->navigatorWidthAnimator = new KexiWidgetWidthAnimator(d->navigator); connect(d->navigatorWidthAnimator, &KexiWidgetWidthAnimator::animationFinished, this, &KexiObjectViewWidget::projectNavigatorAnimationFinished); } //d->navDockWidget = new KexiDockWidget(d->navigator->windowTitle(), d->objectViewWidget); //d->navDockWidget->setObjectName("ProjectNavigatorDockWidget"); //d->objectViewWidget->addDockWidget( // applyRightToLeftToDockArea(Qt::LeftDockWidgetArea), d->navDockWidget, // Qt::Vertical); //navDockableWidget->setParent(d->navDockWidget); //d->navDockWidget->setWidget(navDockableWidget); // Central tab widget d->tabWidget = new KexiObjectViewTabWidget(d->splitter, this); d->tabWidget->setTabsClosable(true); connect(d->tabWidget, &KexiObjectViewTabWidget::currentChanged, this, &KexiObjectViewWidget::slotCurrentTabIndexChanged); connect(d->tabWidget, &KexiObjectViewTabWidget::tabCloseRequested, this, &KexiObjectViewWidget::closeWindowRequested); if (flags & PropertyPaneEnabled) { // Property editor d->propertyPane = new KexiPropertyPaneWidget(d->splitter); KexiStyle::setSidebarsPalette(d->propertyPane); KexiStyle::setSidebarsPalette(d->propertyPane->editor()); d->propertyPaneWidthAnimator = new KexiWidgetWidthAnimator(d->propertyPane); } // mtbar = new KMultiTabBar(KMultiTabBar::Right); // mtbar->setStyle(KMultiTabBar::VSNET); // mainLyr->addWidget(mtbar); // d->multiTabBars.insert(mtbar->position(), mtbar); } KexiObjectViewWidget::~KexiObjectViewWidget() { } KexiProjectNavigator* KexiObjectViewWidget::projectNavigator() const { return d->navigator; } KexiObjectViewTabWidget* KexiObjectViewWidget::tabWidget() const { return d->tabWidget; } KexiPropertyPaneWidget* KexiObjectViewWidget::propertyPane() const { return d->propertyPane; } void KexiObjectViewWidget::slotCurrentTabIndexChanged(int index) { KexiWindow *window = d->tabWidget->window(index); if (!window || (KexiWindow*)d->previouslyActiveWindow == window) { return; } emit activeWindowChanged(window, d->previouslyActiveWindow); d->previouslyActiveWindow = window; emit currentTabIndexChanged(index); } void KexiObjectViewWidget::setSidebarWidths(int projectNavigatorWidth, int propertyEditorWidth) { d->projectNavigatorWidthToSet = projectNavigatorWidth; d->propertyPaneWidthToSet = propertyEditorWidth; } void KexiObjectViewWidget::resizeEvent(QResizeEvent *e) { QWidget::resizeEvent(e); //qDebug() << "___" << e->size() << size() << isVisible(); if (isVisible()) { updateSidebarWidths(); } } void KexiObjectViewWidget::showEvent(QShowEvent *e) { QWidget::showEvent(e); updateSidebarWidths(); } const int PROJECT_NAVIGATOR_INDEX = 0; const int MAIN_AREA_INDEX = 1; const int PROPERTY_EDITOR_INDEX = 2; void KexiObjectViewWidget::updateSidebarWidths() { QList sizes(d->splitter->sizes()); if (sizes.count() <= 1) { return; } //qDebug() << "updateSidebarWidths" << d->projectNavigatorWidthToSet << d->propertyEditorWidthToSet << sizes << d->splitter->width() << isVisible(); if (d->projectNavigatorWidthToSet <= 0) { if (d->navigator) { sizes[PROJECT_NAVIGATOR_INDEX] = d->navigator->sizeHint().width(); } } else { sizes[PROJECT_NAVIGATOR_INDEX] = d->projectNavigatorWidthToSet; } if (sizes.count() >= (PROPERTY_EDITOR_INDEX+1)) { if (d->propertyPane && d->propertyPane->isVisible()) { if (d->propertyPaneWidthToSet <= 0) { d->propertyPaneWidthToSet = d->propertyPane->sizeHint().width(); } sizes[PROPERTY_EDITOR_INDEX] = d->propertyPaneWidthToSet; sizes[MAIN_AREA_INDEX] = d->splitter->width() - sizes[PROJECT_NAVIGATOR_INDEX] - sizes[PROPERTY_EDITOR_INDEX]; } else { sizes[PROPERTY_EDITOR_INDEX] = 0; sizes[MAIN_AREA_INDEX] = d->splitter->width() - sizes[PROJECT_NAVIGATOR_INDEX]; } } d->splitter->setSizes(sizes); //qDebug() << "updateSidebarWidths" << sizes << d->splitter->sizes(); } void KexiObjectViewWidget::getSidebarWidths(int *projectNavigatorWidth, int *propertyEditorWidth) const { QList sizes(d->splitter->sizes()); if (sizes.count() < (PROPERTY_EDITOR_INDEX+1)) { *projectNavigatorWidth = -1; *propertyEditorWidth = -1; return; } //qDebug() << "getSidebarWidths" << d->propertyEditorTabWidget->width(); *projectNavigatorWidth = (sizes.count() >= (PROJECT_NAVIGATOR_INDEX+1) && sizes[PROJECT_NAVIGATOR_INDEX] > 0) ? sizes[PROJECT_NAVIGATOR_INDEX] : d->projectNavigatorWidthToSet; *propertyEditorWidth = (sizes.count() >= (PROPERTY_EDITOR_INDEX+1) && sizes[PROPERTY_EDITOR_INDEX] > 0) ? sizes[PROPERTY_EDITOR_INDEX] : d->propertyPaneWidthToSet; //qDebug() << "getSidebarWidths" << *projectNavigatorWidth << *propertyEditorWidth; } void KexiObjectViewWidget::slotSplitterMoved(int pos, int index) { Q_UNUSED(pos) //qDebug() << "slotSplitterMoved" << pos << index; QList sizes(d->splitter->sizes()); if (index == PROJECT_NAVIGATOR_INDEX + 1) { if (sizes.count() >= (PROJECT_NAVIGATOR_INDEX+1)) { d->projectNavigatorWidthToSet = sizes[PROJECT_NAVIGATOR_INDEX]; } } else if (index == PROPERTY_EDITOR_INDEX) { if (sizes.count() >= (PROPERTY_EDITOR_INDEX+1)) { d->propertyPaneWidthToSet = sizes[PROPERTY_EDITOR_INDEX]; } } } void KexiObjectViewWidget::setProjectNavigatorVisible(bool set) { QAction *action_show_nav = KexiMainWindowIface::global()->actionCollection()->action("view_navigator"); action_show_nav->setChecked(set); d->navigatorWidthAnimator->setVisible(set); } void KexiObjectViewWidget::setPropertyPaneVisible(bool set) { QAction *action_show_propeditor = KexiMainWindowIface::global()->actionCollection()->action("view_propeditor"); action_show_propeditor->setChecked(set); d->propertyPaneWidthAnimator->setVisible(set); } diff --git a/src/main/KexiPropertyPaneWidget.cpp b/src/main/KexiPropertyPaneWidget.cpp deleted file mode 100644 index efc2019fc..000000000 --- a/src/main/KexiPropertyPaneWidget.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2016 Jarosław Staniek - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. -*/ - -#include "KexiPropertyPaneWidget.h" -#include - -#include - -#include -#include - -class KexiPropertyPaneWidget::Private -{ -public: - Private() {} - QVBoxLayout *mainLyr; - QToolBox *toolBox; - KexiPropertyEditorView *editor; -}; - -KexiPropertyPaneWidget::KexiPropertyPaneWidget(QWidget *parent) - : QWidget(parent), d(new Private) -{ - d->mainLyr = new QVBoxLayout(this); - d->mainLyr->setContentsMargins(0, 0, 0, 0); - d->toolBox = new QToolBox; - d->mainLyr->addWidget(d->toolBox); - - d->editor = new KexiPropertyEditorView(this); - d->toolBox->addItem(d->editor, d->editor->windowTitle()); - setWindowTitle(d->editor->windowTitle()); -} - -KexiPropertyPaneWidget::~KexiPropertyPaneWidget() -{ - delete d; -} - -KexiPropertyEditorView* KexiPropertyPaneWidget::editor() const -{ - return d->editor; -} - -QToolBox* KexiPropertyPaneWidget::toolBox() const -{ - return d->toolBox; -} diff --git a/src/plugins/forms/kexidatasourcepage.cpp b/src/plugins/forms/kexidatasourcepage.cpp index a0a38eca3..57e8b70fb 100644 --- a/src/plugins/forms/kexidatasourcepage.cpp +++ b/src/plugins/forms/kexidatasourcepage.cpp @@ -1,455 +1,454 @@ /* This file is part of the KDE project - Copyright (C) 2005-2009 Jarosław Staniek + Copyright (C) 2005-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kexidatasourcepage.h" #include #include #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) #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); mainLayout()->addSpacing(KexiUtils::spacingHint()); // needed because unlike m_dataSourceLabel we have no button in hlyr #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(); #ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT 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("tool-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( KexiIcon("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() { #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()); #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() { #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_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_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 { #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_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 #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() { #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); #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/src/plugins/forms/kexiformpart.h b/src/plugins/forms/kexiformpart.h index d3269a1e2..858708b9a 100644 --- a/src/plugins/forms/kexiformpart.h +++ b/src/plugins/forms/kexiformpart.h @@ -1,95 +1,95 @@ /* This file is part of the KDE project Copyright (C) 2004 Lucijan Busch 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. */ #ifndef KEXIFORMPART_H #define KEXIFORMPART_H #include #include #include #include #include class QDomDocument; namespace KFormDesigner { class Form; class WidgetTreeWidget; } class KDbFieldList; class KexiDataSourcePage; class KexiFormPartTempData : public KexiWindowData { Q_OBJECT public: explicit KexiFormPartTempData(QObject* parent); ~KexiFormPartTempData(); QPointer form; QPointer previewForm; QString tempForm; QPoint scrollViewContentsPos; //!< to preserve contents pos after switching //! Used in KexiFormView::setUnsavedLocalBLOBs() QHash unsavedLocalBLOBs; //! Used when loading a form from (temporary) XML in Data View //! to get unsaved blobs collected at design mode. QHash unsavedLocalBLOBsByName; }; //! Kexi Form Plugin /*! It just creates a \ref KexiFormView. See there for most of code. */ class KEXIFORMUTILS_EXPORT KexiFormPart : public KexiPart::Part { Q_OBJECT public: KexiFormPart(QObject *parent, const QVariantList &); virtual ~KexiFormPart(); KexiDataSourcePage* dataSourcePage() const; KFormDesigner::WidgetTreeWidget* widgetTreePage() const; #ifndef KEXI_NO_FORM_DATASOURCE_WIZARD void generateForm(KDbFieldList *list, QDomDocument &domDoc); #endif virtual KLocalizedString i18nMessage(const QString& englishMessage, KexiWindow* window) const; protected: virtual KexiWindowData* createWindowData(KexiWindow* window); virtual KexiView* createView(QWidget *parent, KexiWindow* window, KexiPart::Item *item, Kexi::ViewMode viewMode = Kexi::DataViewMode, QMap* staticObjectArgs = 0); virtual void initPartActions(); virtual void initInstanceActions(); - virtual void setupPropertyPane(QToolBox *toolBox); + virtual void setupPropertyPane(KexiPropertyPaneWidget *pane); private: class Private; Private* d; }; #endif diff --git a/src/plugins/forms/kexiformview.cpp b/src/plugins/forms/kexiformview.cpp index 558ef4732..acd07d25b 100644 --- a/src/plugins/forms/kexiformview.cpp +++ b/src/plugins/forms/kexiformview.cpp @@ -1,1294 +1,1293 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur Copyright (C) 2004-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kexiformview.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/kexidbform.h" #include "kexiformscrollview.h" #include "kexidatasourcepage.h" #include "kexiformmanager.h" #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT #include "kexidbautofield.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //! @todo #define KEXI_SHOW_SPLITTER_WIDGET class Q_DECL_HIDDEN 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_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() (void)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() { 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; } bool 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 { if (!loadForm()) { return false; } } 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(); } return true; } void KexiFormView::updateAutoFieldsDataSource() { #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT //! @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); } } } #endif } 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); } } } bool 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()) { if (!KFormDesigner::FormIO::loadFormFromString(form(), d->dbform, tempData()->tempForm)) { return false; } setUnsavedBLOBIdsForDataViewMode(d->dbform, tempData()->unsavedLocalBLOBsByName); updateAutoFieldsDataSource(); updateValuesForSubproperties(); return true; } if (!window()->neverSaved()) { // normal load QString data; if (!loadDataBlock(&data)) { return false; } if (!KFormDesigner::FormIO::loadFormFromString(form(), d->dbform, data)) { return false; } } //"autoTabStops" property is loaded -set it within the form tree as well form()->setAutoTabStops(d->dbform->autoTabStops()); updateAutoFieldsDataSource(); updateValuesForSubproperties(); return true; } 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()); } } if (d->scrollView->data() && viewMode() == Kexi::DataViewMode) { //old data won't be needed nor valid d->scrollView->setData(0, false); } // 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 == Kexi::DataViewMode) { //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() if (!initForm()) { return false; } //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 KDb. 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 = KDb::lastInsertedAutoIncValue( conn, st.lastInsertRecordId(), "o_id", "kexi__blobs"); if (std::numeric_limits::max() == 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" << it.key()->objectName() << "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) { #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT if (KexiFieldDrag::canDecode(e)) { e->setAccepted(true); } #else Q_UNUSED(e); #endif } void KexiFormView::slotHandleDropEvent(QDropEvent* e) { #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_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/src/plugins/reports/kexireportpart.cpp b/src/plugins/reports/kexireportpart.cpp index ad17a30bb..1e695ce2d 100644 --- a/src/plugins/reports/kexireportpart.cpp +++ b/src/plugins/reports/kexireportpart.cpp @@ -1,202 +1,200 @@ /* * Kexi Report Plugin * Copyright (C) 2007-2008 by Adam Pigg * Copyright (C) 2011-2015 Jarosław Staniek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "kexireportpart.h" -#include #include #include #include #include #include "kexireportview.h" #include "kexireportdesignview.h" #include +#include #include "kexisourceselector.h" //! @internal class Q_DECL_HIDDEN KexiReportPart::Private { public: Private() : toolboxActionGroup(0) { sourceSelector = 0; } ~Private() { } KexiSourceSelector *sourceSelector; QActionGroup toolboxActionGroup; QMap toolboxActionsByName; }; KexiReportPart::KexiReportPart(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.", "report"), xi18nc("tooltip", "Create new report"), xi18nc("what's this", "Creates new report."), l) , d(new Private) { setInternalPropertyValue("newObjectsAreDirty", true); } KexiReportPart::~KexiReportPart() { delete d; } KLocalizedString KexiReportPart::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 report %1 has been modified.")); if (englishMessage == "Object %1 already exists.") return kxi18nc(I18NC_NOOP("@info", "Report %1 already exists.")); return Part::i18nMessage(englishMessage, window); } KexiView* KexiReportPart::createView(QWidget *parent, KexiWindow* window, KexiPart::Item *item, Kexi::ViewMode viewMode, QMap*) { Q_ASSERT(item); Q_UNUSED(window); Q_UNUSED(item); KexiView* view = 0; if (viewMode == Kexi::DataViewMode) { view = new KexiReportView(parent); } else if (viewMode == Kexi::DesignViewMode) { view = new KexiReportDesignView(parent, d->sourceSelector); connect(d->sourceSelector, &KexiSourceSelector::sourceDataChanged, qobject_cast(view), &KexiReportDesignView::slotSourceDataChanged); connect(view, SIGNAL(itemInserted(QString)), this, SLOT(slotItemInserted(QString))); } return view; } void KexiReportPart::initPartActions() { KexiMainWindowIface *win = KexiMainWindowIface::global(); QList reportActions = KReportDesigner::itemActions(&d->toolboxActionGroup); foreach(QAction* action, reportActions) { connect(action, SIGNAL(triggered(bool)), this, SLOT(slotToolboxActionTriggered(bool))); win->addToolBarAction("report", action); d->toolboxActionsByName.insert(action->objectName(), action); } } KDbObject* KexiReportPart::loadSchemaObject( KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow) { QString layout; if ( !loadDataBlock(window, &layout, "layout") == true && !loadDataBlock(window, &layout, "pgzreport_layout") == true /* compat */) { return 0; } QDomDocument doc; if (!doc.setContent(layout)) { return 0; } qDebug() << doc.toString(); KexiReportPartTempData * temp = static_cast(window->data()); const QDomElement root = doc.documentElement(); temp->reportDefinition = root.firstChildElement("report:content"); if (temp->reportDefinition.isNull()) { qWarning() << "no report report:content element found in report" << window->partItem()->name(); return 0; } temp->connectionDefinition = root.firstChildElement("connection"); if (temp->connectionDefinition.isNull()) { qWarning() << "no report report:content element found in report" << window->partItem()->name(); return 0; } return KexiPart::Part::loadSchemaObject(window, object, viewMode, ownedByWindow); } KexiWindowData* KexiReportPart::createWindowData(KexiWindow* window) { return new KexiReportPartTempData(window); } KexiReportPartTempData::KexiReportPartTempData(QObject* parent) : KexiWindowData(parent) , reportSchemaChangedInPreviousView(true /*to force reloading on startup*/) { } -void KexiReportPart::setupPropertyPane(QToolBox *toolBox) +void KexiReportPart::setupPropertyPane(KexiPropertyPaneWidget *pane) { if (!d->sourceSelector) { d->sourceSelector = new KexiSourceSelector(KexiMainWindowIface::global()->project()); } - if (toolBox->indexOf(d->sourceSelector) == -1) { - toolBox->addItem(d->sourceSelector, xi18n("Data source")); - } + pane->addSection(d->sourceSelector, xi18n("Data source")); } void KexiReportPart::slotToolboxActionTriggered(bool checked) { if (!checked) return; QObject *theSender = sender(); if (!theSender) return; QString senderName = sender()->objectName(); KexiMainWindowIface *mainwin = KexiMainWindowIface::global(); KexiWindow *win = mainwin->currentWindow(); if (!win) return; KexiView *designView = win->viewForMode(Kexi::DesignViewMode); if (designView) { KexiReportDesignView *dv = dynamic_cast(designView); if (!dv) return; dv->triggerAction(senderName); } } void KexiReportPart::slotItemInserted(const QString& entity) { Q_UNUSED(entity); // uncheck toolbox action after it is used QAction * a = d->toolboxActionGroup.checkedAction(); if (a) { a->setChecked(false); } } diff --git a/src/plugins/reports/kexireportpart.h b/src/plugins/reports/kexireportpart.h index 847e33801..735e366f2 100644 --- a/src/plugins/reports/kexireportpart.h +++ b/src/plugins/reports/kexireportpart.h @@ -1,88 +1,88 @@ /* * Kexi Report Plugin * Copyright (C) 2007-2008 by Adam Pigg * Copyright (C) 2011-2015 Jarosław Staniek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef _KEXIREPORTPART_H_ #define _KEXIREPORTPART_H_ #include #include #include #include class KexiReportPartTempData : public KexiWindowData { Q_OBJECT public: explicit KexiReportPartTempData(QObject* parent); QDomElement reportDefinition; QDomElement connectionDefinition; /*! true, if \a document member has changed in previous view. Used on view switching. Check this flag to see if we should refresh data for DataViewMode. */ bool reportSchemaChangedInPreviousView; }; /** * @short Application Main Window * @author Adam Pigg * @version 0.1 */ class KexiReportPart : public KexiPart::Part { Q_OBJECT public: /** * Default Constructor */ KexiReportPart(QObject *parent, const QVariantList &l); /** * Default Destructor */ virtual ~KexiReportPart(); - virtual void setupPropertyPane(QToolBox *toolBox); + virtual void setupPropertyPane(KexiPropertyPaneWidget *pane); virtual KLocalizedString i18nMessage(const QString& englishMessage, KexiWindow* window) const; protected: virtual KexiView* createView(QWidget *parent, KexiWindow* win, KexiPart::Item *item, Kexi::ViewMode = Kexi::DataViewMode, QMap* staticObjectArgs = 0); virtual KexiWindowData* createWindowData(KexiWindow* window); virtual void initPartActions(); virtual KDbObject* loadSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow); private Q_SLOTS: void slotToolboxActionTriggered(bool checked); //! Unchecks toolbox action for @a entity after it is used. void slotItemInserted(const QString& entity); private: class Private; Private* d; }; #endif // _KEXIREPORTPART_H_ diff --git a/src/plugins/tables/CMakeLists.txt b/src/plugins/tables/CMakeLists.txt index df3d64d42..43adc4566 100644 --- a/src/plugins/tables/CMakeLists.txt +++ b/src/plugins/tables/CMakeLists.txt @@ -1,35 +1,35 @@ include_directories(${CMAKE_SOURCE_DIR}/src/core ${CMAKE_SOURCE_DIR}/src/widget - ${CMAKE_SOURCE_DIR}/src/widget/tableview) + ${CMAKE_SOURCE_DIR}/src/widget/tableview ${CMAKE_SOURCE_DIR}/src/widget/properties) # the main plugin set(kexi_tableplugin_SRCS kexitablepart.cpp kexitabledesignerview.cpp kexitabledesigner_dataview.cpp kexitabledesignercommands.cpp kexitabledesignerview_p.cpp kexilookupcolumnpage.cpp ) add_library(kexi_tableplugin MODULE ${kexi_tableplugin_SRCS}) kcoreaddons_desktop_to_json(kexi_tableplugin kexi_tableplugin.desktop) target_link_libraries(kexi_tableplugin PRIVATE kexicore kexidataviewcommon kexidatatable kexiextendedwidgets kexiutils kexiundo KDb KPropertyWidgets KF5::CoreAddons Qt5::Core Qt5::Gui ) install(TARGETS kexi_tableplugin DESTINATION ${KEXI_PLUGIN_INSTALL_DIR}) diff --git a/src/plugins/tables/kexilookupcolumnpage.cpp b/src/plugins/tables/kexilookupcolumnpage.cpp index 81536a5f3..aa0b1e4f2 100644 --- a/src/plugins/tables/kexilookupcolumnpage.cpp +++ b/src/plugins/tables/kexilookupcolumnpage.cpp @@ -1,376 +1,384 @@ /* This file is part of the KDE project - Copyright (C) 2006-2008 Jarosław Staniek + Copyright (C) 2006-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kexilookupcolumnpage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QString pluginIdToTypeName(const QString& pluginId) { if (pluginId == "org.kexi-project.table") return "table"; else if (pluginId == "org.kexi-project.query") return "query"; //! @todo more types return pluginId; } QString typeToPartClass(const QString& type) { return QString::fromLatin1("org.kexi-project.")+type; //! @todo more types } //---------------------------------------------- //! @internal class Q_DECL_HIDDEN KexiLookupColumnPage::Private { public: explicit Private(KexiLookupColumnPage *that) : q(that) , currentFieldUid(-1) , insideClearRowSourceSelection(false) , propertySetEnabled(true) { } ~Private() { } bool hasPropertySet() const { return propertySet; } void setPropertySet(KPropertySet* aPropertySet) { propertySet = aPropertySet; } QVariant propertyValue(const QByteArray& propertyName) const { return propertySet ? propertySet->property(propertyName).value() : QVariant(); } void changeProperty(const QByteArray& propertyName, const QVariant &value) { if (!propertySetEnabled) return; propertySet->changeProperty(propertyName, value); } - void updateInfoLabelForPropertySet(const QString& textToDisplayForNullSet) { - q->updateInfoLabelForPropertySet( propertySet, textToDisplayForNullSet); - } - KexiLookupColumnPage *q; + QVBoxLayout *mainLyr; KexiDataSourceComboBox *rowSourceCombo; KexiFieldComboBox *boundColumnCombo, *visibleColumnCombo; QLabel *rowSourceLabel, *boundColumnLabel, *visibleColumnLabel; QToolButton *gotoRowSourceButton; //! Used only in assignPropertySet() to check whether we already have the set assigned int currentFieldUid; bool insideClearRowSourceSelection; //! True if changeProperty() works. Used to block updating properties when within assignPropertySet(). bool propertySetEnabled; private: //! A property set that is displayed on the page. //! The set is also updated after any change in this page's data. QPointer propertySet; }; //---------------------------------------------- KexiLookupColumnPage::KexiLookupColumnPage(QWidget *parent) - : KexiPropertyPaneViewBase(parent) + : QWidget(parent) , d(new Private(this)) { setObjectName("KexiLookupColumnPage"); //! @todo d->noDataSourceAvailableSingleText = xi18n("No data source could be assigned for this widget."); //! @todo d->noDataSourceAvailableMultiText = xi18n("No data source could be assigned for multiple widgets."); //-Record Source + d->mainLyr = new QVBoxLayout(this); + d->mainLyr->setContentsMargins(0, 0, 0, 0); QHBoxLayout *hlyr = new QHBoxLayout(); - mainLayout()->addLayout(hlyr); + d->mainLyr->addLayout(hlyr); d->rowSourceLabel = new QLabel(xi18n("Record source:")); d->rowSourceLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); d->rowSourceLabel->setMinimumHeight(IconSize(KIconLoader::Small) + 4); d->rowSourceLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom); hlyr->addWidget(d->rowSourceLabel); hlyr->addStretch(); d->gotoRowSourceButton = new KexiSmallToolButton(koIcon("go-jump"), QString()); d->gotoRowSourceButton->setObjectName("gotoRowSourceButton"); d->gotoRowSourceButton->setMinimumHeight(d->rowSourceLabel->minimumHeight()); d->gotoRowSourceButton->setToolTip(xi18n("Go to selected record source")); hlyr->addWidget(d->gotoRowSourceButton); connect(d->gotoRowSourceButton, SIGNAL(clicked()), this, SLOT(slotGotoSelectedRowSource())); d->rowSourceCombo = new KexiDataSourceComboBox; d->rowSourceCombo->setObjectName("rowSourceCombo"); d->rowSourceLabel->setBuddy(d->rowSourceCombo); - mainLayout()->addWidget(d->rowSourceCombo); + d->mainLyr->addWidget(d->rowSourceCombo); addWidgetSpacer(); //- Bound Column d->boundColumnLabel = new QLabel(xi18n("Bound column:")); d->boundColumnLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); d->boundColumnLabel->setMinimumHeight(IconSize(KIconLoader::Small) + 4); d->boundColumnLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom); - mainLayout()->addWidget(d->boundColumnLabel); + d->mainLyr->addWidget(d->boundColumnLabel); d->boundColumnCombo = new KexiFieldComboBox(); d->boundColumnCombo->setObjectName("boundColumnCombo"); d->boundColumnLabel->setBuddy(d->boundColumnCombo); - mainLayout()->addWidget(d->boundColumnCombo); + d->mainLyr->addWidget(d->boundColumnCombo); addWidgetSpacer(); //- Visible Column d->visibleColumnLabel = new QLabel(xi18n("Visible column:")); d->visibleColumnLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); d->visibleColumnLabel->setMinimumHeight(IconSize(KIconLoader::Small) + 4); d->visibleColumnLabel->setAlignment(Qt::AlignLeft | Qt::AlignBottom); - mainLayout()->addWidget(d->visibleColumnLabel); + d->mainLyr->addWidget(d->visibleColumnLabel); d->visibleColumnCombo = new KexiFieldComboBox; d->visibleColumnCombo->setObjectName("visibleColumnCombo"); d->visibleColumnLabel->setBuddy(d->visibleColumnCombo); - mainLayout()->addWidget(d->visibleColumnCombo); + d->mainLyr->addWidget(d->visibleColumnCombo); - mainLayout()->addStretch(1); + d->mainLyr->addStretch(1); connect(d->rowSourceCombo, SIGNAL(editTextChanged(QString)), this, SLOT(slotRowSourceTextChanged(QString))); connect(d->boundColumnCombo, SIGNAL(editTextChanged(QString)), this, SLOT(slotBoundColumnTextChanged(QString))); connect(d->visibleColumnCombo, SIGNAL(editTextChanged(QString)), this, SLOT(slotVisibleColumnTextChanged(QString))); connect(d->rowSourceCombo, SIGNAL(dataSourceChanged()), this, SLOT(slotRowSourceChanged())); connect(d->boundColumnCombo, SIGNAL(selected()), this, SLOT(slotBoundColumnSelected())); connect(d->visibleColumnCombo, SIGNAL(selected()), this, SLOT(slotVisibleColumnSelected())); clearBoundColumnSelection(); clearVisibleColumnSelection(); } KexiLookupColumnPage::~KexiLookupColumnPage() { delete d; } void KexiLookupColumnPage::setProject(KexiProject *prj) { d->rowSourceCombo->setProject(prj, true/*showTables*/, true/*showQueries*/ ); d->boundColumnCombo->setProject(prj); d->visibleColumnCombo->setProject(prj); } void KexiLookupColumnPage::assignPropertySet(KPropertySet* propertySet) { if (propertySet && d->currentFieldUid == (*propertySet)["uid"].value().toInt()) return; //already assigned d->propertySetEnabled = false; d->setPropertySet(propertySet); - d->updateInfoLabelForPropertySet(xi18n("No field selected")); const bool hasRowSource = d->hasPropertySet() && !d->propertyValue("rowSourceType").isNull() && !d->propertyValue("rowSource").isNull(); QString rowSource, rowSourceType; if (hasRowSource) { rowSourceType = typeToPartClass(d->propertyValue("rowSourceType").toString()); rowSource = d->propertyValue("rowSource").toString(); } d->rowSourceCombo->setDataSource(rowSourceType, rowSource); d->rowSourceLabel->setEnabled(d->hasPropertySet()); d->rowSourceCombo->setEnabled(d->hasPropertySet()); int boundColumn = -1, visibleColumn = -1; if (d->rowSourceCombo->isSelectionValid()) { boundColumn = d->propertyValue("boundColumn").toInt(); visibleColumn = d->propertyValue("visibleColumn").toInt(); } d->boundColumnCombo->setFieldOrExpression(boundColumn); d->visibleColumnCombo->setFieldOrExpression(visibleColumn); updateBoundColumnWidgetsAvailability(); d->propertySetEnabled = true; } void KexiLookupColumnPage::slotBoundColumnTextChanged(const QString &text) { if (text.isEmpty()) { clearBoundColumnSelection(); } } void KexiLookupColumnPage::clearBoundColumnSelection() { d->boundColumnCombo->setEditText(""); d->boundColumnCombo->setFieldOrExpression(QString()); slotBoundColumnSelected(); } void KexiLookupColumnPage::slotBoundColumnSelected() { // KDbField::Type dataType = KDbField::InvalidType; //! @todo this should also work for expressions /*disabled KDbField *field = d->fieldListView->schema()->field( d->boundColumnCombo->fieldOrExpression() ); if (field) dataType = field->type(); */ if (!d->boundColumnCombo->fieldOrExpression().isEmpty()) { qDebug(); } // update property set if (d->hasPropertySet()) { d->changeProperty("boundColumn", d->boundColumnCombo->indexOfField()); } } void KexiLookupColumnPage::slotVisibleColumnTextChanged(const QString &text) { if (text.isEmpty()) { clearVisibleColumnSelection(); } } void KexiLookupColumnPage::clearVisibleColumnSelection() { d->visibleColumnCombo->setEditText(""); d->visibleColumnCombo->setFieldOrExpression(QString()); slotVisibleColumnSelected(); } void KexiLookupColumnPage::slotVisibleColumnSelected() { // KDbField::Type dataType = KDbField::InvalidType; //! @todo this should also work for expressions // update property set if (d->hasPropertySet()) { //! @todo support expression in special "visibleExpression" d->changeProperty("visibleColumn", d->visibleColumnCombo->indexOfField()); } } void KexiLookupColumnPage::slotRowSourceChanged() { if (!d->rowSourceCombo->project()) return; QString pluginId(d->rowSourceCombo->selectedPluginId()); bool rowSourceFound = false; QString name = d->rowSourceCombo->selectedName(); if ((pluginId == "org.kexi-project.table" || pluginId == "org.kexi-project.query") && d->rowSourceCombo->isSelectionValid()) { KDbTableOrQuerySchema *tableOrQuery = new KDbTableOrQuerySchema( d->rowSourceCombo->project()->dbConnection(), name.toLatin1(), pluginId == "org.kexi-project.table"); if (tableOrQuery->table() || tableOrQuery->query()) { //! @todo disabled d->fieldListView->setSchema( tableOrQuery ); /*tmp*/ delete tableOrQuery; rowSourceFound = true; d->boundColumnCombo->setTableOrQuery(name, pluginId == "org.kexi-project.table"); d->visibleColumnCombo->setTableOrQuery(name, pluginId == "org.kexi-project.table"); } else { delete tableOrQuery; } } if (!rowSourceFound) { d->boundColumnCombo->setTableOrQuery("", true); d->visibleColumnCombo->setTableOrQuery("", true); } clearBoundColumnSelection(); clearVisibleColumnSelection(); d->gotoRowSourceButton->setEnabled(rowSourceFound); updateBoundColumnWidgetsAvailability(); //update property set if (d->hasPropertySet()) { d->changeProperty("rowSourceType", pluginIdToTypeName(pluginId)); d->changeProperty("rowSource", name); } //! @todo update d->propertySet ^^ } void KexiLookupColumnPage::slotRowSourceTextChanged(const QString &text) { if (text.isEmpty()) { clearRowSourceSelection(); } const bool enable = d->rowSourceCombo->isSelectionValid(); if (enable) { updateBoundColumnWidgetsAvailability(); } else { clearRowSourceSelection(d->rowSourceCombo->selectedName().isEmpty()/*alsoClearComboBox*/); } } void KexiLookupColumnPage::clearRowSourceSelection(bool alsoClearComboBox) { if (d->insideClearRowSourceSelection) return; d->insideClearRowSourceSelection = true; if (alsoClearComboBox) { d->rowSourceCombo->setDataSource("", ""); } d->gotoRowSourceButton->setEnabled(false); d->insideClearRowSourceSelection = false; } void KexiLookupColumnPage::slotGotoSelectedRowSource() { const QString pluginId(d->rowSourceCombo->selectedPluginId()); if (pluginId == "org.kexi-project.table" || pluginId == "org.kexi-project.query") { if (d->rowSourceCombo->isSelectionValid()) emit jumpToObjectRequested(pluginId, d->rowSourceCombo->selectedName()); } } void KexiLookupColumnPage::updateBoundColumnWidgetsAvailability() { const bool hasRowSource = d->rowSourceCombo->isSelectionValid(); d->boundColumnCombo->setEnabled(hasRowSource); d->boundColumnLabel->setEnabled(hasRowSource); d->visibleColumnCombo->setEnabled(hasRowSource); d->visibleColumnLabel->setEnabled(hasRowSource); } +QWidget* KexiLookupColumnPage::addWidgetSpacer() +{ + //! @todo + QWidget *sp = new QWidget(this); + const int spacing = fontMetrics().height() * 2 / 3; + sp->setFixedHeight(spacing); + sp->setContentsMargins(0, 0, 0, 0); + d->mainLyr->addWidget(sp); + return sp; +} diff --git a/src/plugins/tables/kexilookupcolumnpage.h b/src/plugins/tables/kexilookupcolumnpage.h index 77fc53ff2..b62b83e91 100644 --- a/src/plugins/tables/kexilookupcolumnpage.h +++ b/src/plugins/tables/kexilookupcolumnpage.h @@ -1,79 +1,81 @@ /* This file is part of the KDE project - Copyright (C) 2006-2008 Jarosław Staniek + Copyright (C) 2006-2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KEXILOOKUPCOLUMNPAGE_H #define KEXILOOKUPCOLUMNPAGE_H -#include +#include #include #include #include class KexiProject; //! @short A page within table designer's property pane, providing lookup column editor. /*! It's data model is basically KDbLookupFieldSchema class, but the page does not create it directly but instead updates a property set that defines the field currently selected in the designer. @todo not all features of KDbLookupFieldSchema class are displayed on this page yet */ -class KexiLookupColumnPage : public KexiPropertyPaneViewBase +class KexiLookupColumnPage : public QWidget { Q_OBJECT public: explicit KexiLookupColumnPage(QWidget *parent = 0); virtual ~KexiLookupColumnPage(); public Q_SLOTS: void setProject(KexiProject *prj); void clearRowSourceSelection(bool alsoClearComboBox = true); void clearBoundColumnSelection(); void clearVisibleColumnSelection(); //! 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 record sourcesource' is clicked. void jumpToObjectRequested(const QString& mime, const QString& name); protected Q_SLOTS: void slotRowSourceTextChanged(const QString &text); void slotRowSourceChanged(); void slotGotoSelectedRowSource(); void slotBoundColumnTextChanged(const QString &text); void slotBoundColumnSelected(); void slotVisibleColumnTextChanged(const QString &text); void slotVisibleColumnSelected(); protected: void updateBoundColumnWidgetsAvailability(); //! Used instead of m_propertySet->changeProperty() to honor m_propertySetEnabled void changeProperty(const QByteArray &property, const QVariant &value); + QWidget* addWidgetSpacer(); + private: class Private; Private* const d; }; #endif diff --git a/src/plugins/tables/kexitablepart.cpp b/src/plugins/tables/kexitablepart.cpp index c869f28f5..dc9b6e46d 100644 --- a/src/plugins/tables/kexitablepart.cpp +++ b/src/plugins/tables/kexitablepart.cpp @@ -1,327 +1,325 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2002, 2003 Joseph Wenninger Copyright (C) 2004-2017 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kexitablepart.h" #include #include #include #include +#include #include #include #include "kexitabledesignerview.h" #include "kexitabledesigner_dataview.h" #include "kexilookupcolumnpage.h" #include #include #include #include -#include KEXI_PLUGIN_FACTORY(KexiTablePart, "kexi_tableplugin.json") //! @internal class Q_DECL_HIDDEN KexiTablePart::Private { public: Private() { } ~Private() { delete static_cast(lookupColumnPage); } QPointer lookupColumnPage; }; KexiTablePart::KexiTablePart(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.", "table"), xi18nc("tooltip", "Create new table"), xi18nc("what's this", "Creates new table."), l) , d(new Private) { //! @todo js: also add Kexi::TextViewMode when we'll have SQL ALTER TABLE EDITOR!!! } KexiTablePart::~KexiTablePart() { delete d; } void KexiTablePart::initPartActions() { } void KexiTablePart::initInstanceActions() { } KexiWindowData* KexiTablePart::createWindowData(KexiWindow* window) { KexiMainWindowIface *win = KexiMainWindowIface::global(); return new KexiTablePartTempData(window, win->project()->dbConnection()); } KexiView* KexiTablePart::createView(QWidget *parent, KexiWindow* window, KexiPart::Item *item, Kexi::ViewMode viewMode, QMap*) { Q_ASSERT(item); KexiMainWindowIface *win = KexiMainWindowIface::global(); if (!win || !win->project() || !win->project()->dbConnection()) return 0; KexiTablePartTempData *temp = static_cast(window->data()); if (!temp->table()) { temp->setTable(win->project()->dbConnection()->tableSchema(item->name())); qDebug() << "schema is " << temp->table(); } if (viewMode == Kexi::DesignViewMode) { KexiTableDesignerView *t = new KexiTableDesignerView(parent); return t; } else if (viewMode == Kexi::DataViewMode) { if (!temp->table()) { return 0; //!< @todo message } //we're not setting table schema here -it will be forced to set // in KexiTableDesigner_DataView::afterSwitchFrom() KexiTableDesigner_DataView *t = new KexiTableDesigner_DataView(parent); return t; } return 0; } tristate KexiTablePart::remove(KexiPart::Item *item) { KexiProject *project = KexiMainWindowIface::global()->project(); if (!project || !project->dbConnection()) return false; KDbConnection *conn = project->dbConnection(); KDbTableSchema *sch = conn->tableSchema(item->identifier()); if (sch) { const tristate res = KexiTablePart::askForClosingObjectsUsingTableSchema( KexiMainWindowIface::global()->openedWindowFor(item->identifier()), conn, sch, xi18n("You are about to remove table %1 but following objects using this table are opened:", sch->name())); if (res != true) { return res; } return conn->dropTable(sch); } //last chance: just remove item return conn->removeObject(item->identifier()); } tristate KexiTablePart::rename(KexiPart::Item *item, const QString& newName) { Q_ASSERT(item); KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); KDbTableSchema *schema = conn->tableSchema(item->identifier()); if (!schema) return false; const tristate res = KexiTablePart::askForClosingObjectsUsingTableSchema( KexiMainWindowIface::global()->openedWindowFor(item->identifier()), conn, schema, xi18n("You are about to rename table %1 but following objects using this table are opened:", schema->name())); if (res != true) { return res; } return conn->alterTableName(schema, newName); } KDbObject* KexiTablePart::loadSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow) { Q_UNUSED(window); Q_UNUSED(viewMode); if (ownedByWindow) *ownedByWindow = false; return KexiMainWindowIface::global()->project()->dbConnection()->tableSchema(object.name()); } //static tristate KexiTablePart::askForClosingObjectsUsingTableSchema( KexiWindow *window, KDbConnection *conn, KDbTableSchema *table, const QString& msg) { Q_ASSERT(conn); Q_ASSERT(table); QList listeners = KDbTableSchemaChangeListener::listeners(conn, table); KexiTablePartTempData *temp = static_cast(window->data()); // Special case: listener that is equal to window->data() will be silently closed // without asking for confirmation. It is not counted when looking for objects that // are "blocking" changes of the table. const bool tempListenerExists = listeners.removeAll(temp) > 0; // Immediate success if there's no temp-data's listener to close nor other listeners to close if (!tempListenerExists && listeners.isEmpty()) { return true; } if (!listeners.isEmpty()) { QString openedObjectsStr = ""; for(const KDbTableSchemaChangeListener* listener : listeners) { openedObjectsStr += QString("%1").arg(listener->name()); } openedObjectsStr += ""; const int r = KMessageBox::questionYesNo(window, i18nc("@info", "%1%2", msg, openedObjectsStr) + "" + xi18n("Do you want to close all windows for these objects?") + "", QString(), KGuiItem(xi18nc("@action:button Close All Windows", "Close Windows"), koIconName("window-close")), KStandardGuiItem::cancel()); if (r != KMessageBox::Yes) { return cancelled; } } //try to close every window depending on the table (if present) and also the temp-data's listener (if present) const tristate res = KDbTableSchemaChangeListener::closeListeners(conn, table); if (res != true) { //do not expose closing errors twice; just cancel return cancelled; } return true; } KLocalizedString KexiTablePart::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 table %1 has been modified.")); if (englishMessage == "Object %1 already exists.") return kxi18nc(I18NC_NOOP("@info", "Table %1 already exists.")); if (window->currentViewMode() == Kexi::DesignViewMode && !window->neverSaved() && englishMessage == ":additional message before saving design") return kxi18nc(I18NC_NOOP("@info", "Any data in this table will be removed upon design's saving!")); return Part::i18nMessage(englishMessage, window); } -void KexiTablePart::setupPropertyPane(QToolBox *toolBox) +void KexiTablePart::setupPropertyPane(KexiPropertyPaneWidget *pane) { if (!d->lookupColumnPage) { d->lookupColumnPage = new KexiLookupColumnPage; connect(d->lookupColumnPage, SIGNAL(jumpToObjectRequested(QString,QString)), KexiMainWindowIface::global()->thisWidget(), SLOT(highlightObject(QString,QString))); //! @todo add "Table" tab /* connect(d->dataSourcePage, SIGNAL(formDataSourceChanged(QCString,QCString)), KFormDesigner::FormManager::self(), SLOT(setFormDataSource(QCString,QCString))); connect(d->dataSourcePage, SIGNAL(dataSourceFieldOrExpressionChanged(QString,QString,KDbField::Type)), KFormDesigner::FormManager::self(), SLOT(setDataSourceFieldOrExpression(QString,QString,KDbField::Type))); connect(d->dataSourcePage, SIGNAL(insertAutoFields(QString,QString,QStringList)), KFormDesigner::FormManager::self(), SLOT(insertAutoFields(QString,QString,QStringList)));*/ } KexiProject *prj = KexiMainWindowIface::global()->project(); d->lookupColumnPage->setProject(prj); //! @todo add lookup field icon - if (toolBox->indexOf(d->lookupColumnPage) == -1) { - toolBox->addItem(d->lookupColumnPage, xi18n("Lookup column")); - } + pane->addSection(d->lookupColumnPage, xi18n("Lookup column")); } KexiLookupColumnPage* KexiTablePart::lookupColumnPage() const { return d->lookupColumnPage; } //---------------- class Q_DECL_HIDDEN KexiTablePartTempData::Private { public: Private() : table(nullptr) { } KDbTableSchema *table; KDbConnection *conn; }; KexiTablePartTempData::KexiTablePartTempData(QObject* parent, KDbConnection *conn) : KexiWindowData(parent) , KDbTableSchemaChangeListener() , tableSchemaChangedInPreviousView(true /*to force reloading on startup*/) , d(new Private) { d->conn = conn; } KexiTablePartTempData::~KexiTablePartTempData() { KDbTableSchemaChangeListener::unregisterForChanges(d->conn, this); delete d; } KDbTableSchema* KexiTablePartTempData::table() { return d->table; } KDbConnection* KexiTablePartTempData::connection() { return d->conn; } void KexiTablePartTempData::setTable(KDbTableSchema *table) { if (d->table == table) { return; } if (d->table) { KDbTableSchemaChangeListener::unregisterForChanges(d->conn, this, d->table); } d->table = table; if (d->table) { KDbTableSchemaChangeListener::registerForChanges(d->conn, this, d->table); } } tristate KexiTablePartTempData::closeListener() { KexiWindow* window = static_cast(parent()); if (window->currentViewMode() != Kexi::DataViewMode) { KexiTableDesigner_DataView *dataView = qobject_cast(window->viewForMode(Kexi::DataViewMode)); if (dataView && dataView->tableView()->data()) { dataView->setData(nullptr); } } return true; } #include "kexitablepart.moc" diff --git a/src/plugins/tables/kexitablepart.h b/src/plugins/tables/kexitablepart.h index cca1e2e41..3beed0da9 100644 --- a/src/plugins/tables/kexitablepart.h +++ b/src/plugins/tables/kexitablepart.h @@ -1,127 +1,127 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2002, 2003 Joseph Wenninger Copyright (C) 2004-2017 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KEXITABLEPART_H #define KEXITABLEPART_H #include #include #include #include #include #include #include class KexiLookupColumnPage; //! @short Temporary data kept in memory while switching between Table Window's views class KexiTablePartTempData : public KexiWindowData, public KDbTableSchemaChangeListener { Q_OBJECT public: explicit KexiTablePartTempData(QObject* parent, KDbConnection *conn); ~KexiTablePartTempData(); //! Table used for this data KDbTableSchema* table(); //! Sets table used for this data //! If the previous table differs from @a table and is not @c nullptr, listener for //! it will be unregistered. //! If @a table is not @c nullptr, this temp-data object will be registered as a listener //! for it. void setTable(KDbTableSchema *table); //! Connection used for retrieving definition of the query KDbConnection* connection(); /*! true, if \a table member has changed in previous view. Used on view switching. We're checking this flag to see if we should refresh data for DataViewMode. */ bool tableSchemaChangedInPreviousView; protected: //! Closes listener - this temp-data acts as a listener for tracking changes in table schema //! that is displayed in the window's data view. //! It just calls KexiDataTableView::setData(nullptr) is there's data set for the view //! (i.e. if KexiDataTableView::tableView()->data() is not @c nullptr). tristate closeListener() override; private: Q_DISABLE_COPY(KexiTablePartTempData) class Private; Private * const d; }; //! @short Kexi Table Designer plugin class KexiTablePart : public KexiPart::Part { Q_OBJECT public: KexiTablePart(QObject *parent, const QVariantList &); virtual ~KexiTablePart(); virtual tristate remove(KexiPart::Item *item); virtual tristate rename(KexiPart::Item *item, const QString& newName); //! Close objects that listenen to changes of the table schema @a table. //! Asks the user for approval if there is at least one object that listens for changes //! of the schema. If there is no approval, returns @c cancelled. //! On failure returns @c false. //! Special case: listener that is equal to window->data() will be silently closed //! without asking for confirmation. It is not counted when looking for objects that //! are "blocking" changes of @a table. //! This exception is needed because the listener handles the data view's lifetime //! and the data view should be reset silently without bothering the user. //! See KexiTablePartTempData::closeListener() static tristate askForClosingObjectsUsingTableSchema( KexiWindow *window, KDbConnection *conn, KDbTableSchema *table, const QString& msg); virtual KLocalizedString i18nMessage(const QString& englishMessage, KexiWindow* window) const; KexiLookupColumnPage* lookupColumnPage() const; protected: virtual KexiWindowData* createWindowData(KexiWindow* window); virtual KexiView* createView(QWidget *parent, KexiWindow* window, KexiPart::Item *item, Kexi::ViewMode viewMode = Kexi::DataViewMode, QMap* staticObjectArgs = 0); virtual void initPartActions(); virtual void initInstanceActions(); - virtual void setupPropertyPane(QToolBox *toolBox); + virtual void setupPropertyPane(KexiPropertyPaneWidget *pane); virtual KDbObject* loadSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow); private: class Private; Private* const d; }; #endif diff --git a/src/tests/altertable/altertable.cpp b/src/tests/altertable/altertable.cpp index 5b20e50b5..a4db629e6 100644 --- a/src/tests/altertable/altertable.cpp +++ b/src/tests/altertable/altertable.cpp @@ -1,698 +1,698 @@ /* This file is part of the KDE project Copyright (C) 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 "altertable.h" #include
    #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QString testFilename; QFile testFile; QTextStream testFileStream; QStringList testFileLine; int testLineNumber = 0; QString origDbFilename, dbFilename; int variableI = 1; // simple variable 'i' support int newArgc; char** newArgv; KexiMainWindow* win = 0; KexiProject* prj = 0; void showError(const QString& msg) { QString msg_(msg); msg_.prepend(QString("Error at line %1: ").arg(testLineNumber)); qDebug() << msg_; } /* Reads a single line from testFileStream, fills testFileLine, updates testLineNumber text in quotes is extracted, e.g. \"ab c\" is treat as one item "ab c" Returns flas on failure (e.g. end of file). Empty lines and lines or parts of lines with # (comments) are omitted. */ tristate readLineFromTestFile(const QString& expectedCommandName = QString()) { QString s; bool blockComment = false; while (true) { if (testFileStream.atEnd()) return cancelled; testLineNumber++; s = testFileStream.readLine().stripWhiteSpace(); if (blockComment) { if (s.endsWith("*/")) blockComment = false; continue; } if (!blockComment && s.startsWith("/*")) { blockComment = true; continue; } if (s.startsWith("#")) continue; //skip commented line if (!s.isEmpty()) break; } s.append(" "); //sentinel QString item; testFileLine.clear(); const int len = s.length(); bool skipWhiteSpace = true, quoted = false; for (int i = 0; i < len; i++) { const QChar ch(s.ref(i)); if (skipWhiteSpace) { if (ch == '#') break; //eoln if (ch == ' ' || ch == '\t') continue; skipWhiteSpace = false; if (ch == '\"') { quoted = true; continue; } item.append(ch); } else { if ((quoted && ch == '\"') || (!quoted && (ch == ' ' || ch == '\t'))) { //end of item skipWhiteSpace = true; quoted = false; testFileLine.append(item); item.clear(); continue; } item.append(ch); } } if (!expectedCommandName.isEmpty() && testFileLine[0] != expectedCommandName) { showError(QString("Invalid command '%1', expected '%2'") .arg(testFileLine[0]).arg(expectedCommandName)); return false; } if (quoted) { showError("Invalid contents"); return false; } return true; } bool checkItemsNumber(int expectedNumberOfItems, int optionalNumberOfItems = -1) { bool ok = expectedNumberOfItems == (int)testFileLine.count(); if (optionalNumberOfItems > 0) ok = ok || optionalNumberOfItems == (int)testFileLine.count(); if (!ok) { QString msg = QString("Invalid number of args (%1) for command '%2', expected: %3") .arg(testFileLine.count()).arg(testFileLine[0]).arg(expectedNumberOfItems); if (optionalNumberOfItems > 0) msg.append(QString(" or %1").arg(optionalNumberOfItems)); showError(msg); return false; } return true; } QVariant::Type typeNameToQVariantType(const QCString& name_) { QCString name(name_.toLower()); if (name == "string") return QVariant::String; if (name == "int") return QVariant::Int; if (name == "bool" || name == "boolean") return QVariant::Bool; if (name == "double" || name == "float") return QVariant::Double; if (name == "date") return QVariant::Date; if (name == "datetime") return QVariant::DateTime; if (name == "time") return QVariant::Time; if (name == "bytearray") return QVariant::ByteArray; if (name == "longlong") return QVariant::LongLong; //! @todo more types showError(QString("Invalid type '%1'").arg(name_)); return QVariant::Invalid; } // casts string to QVariant bool castStringToQVariant(const QString& string, const QCString& type, QVariant& result) { if (string.toLower() == "") { result = QVariant(); return true; } if (string == "\"\"") { result = QString(""); return true; } const QVariant::Type vtype = typeNameToQVariantType(type); bool ok; result = KDb::stringToVariant(string, vtype, &ok); return ok; } // returns a number parsed from argument; if argument is i or i++, variableI is used // 'ok' is set to false on failure static int getNumber(const QString& argument, bool *ok) { int result; *ok = true; if (argument == "i" || argument == "i++") { result = variableI; if (argument == "i++") variableI++; } else { result = argument.toInt(ok); if (!*ok) { showError(QString("Invalid value '%1'").arg(argument)); return -1; } } return result; } //--------------------------------------- AlterTableTester::AlterTableTester() : QObject() , m_finishedCopying(false) { //copy the db file to a temp file qInitNetworkProtocols(); QPtrList list = m_copyOperator.copy( "file://" + QDir::current().path() + "/" + origDbFilename, "file://" + QDir::current().path() + "/" + dbFilename, false, false); connect(&m_copyOperator, SIGNAL(finished(QNetworkOperation*)), this, SLOT(slotFinishedCopying(QNetworkOperation*))); } AlterTableTester::~AlterTableTester() { QFile(dbFilename).remove(); } void AlterTableTester::slotFinishedCopying(QNetworkOperation* oper) { if (oper->operation() == QNetworkProtocol::OpPut) m_finishedCopying = true; } bool AlterTableTester::changeFieldProperty(KexiTableDesignerInterface* designerIface) { if (!checkItemsNumber(5)) return false; QVariant newValue; QCString propertyName(testFileLine[2].toLatin1()); QCString propertyType(testFileLine[3].toLatin1()); QString propertyValueString(testFileLine[4]); if (propertyName == "type") newValue = (int)KDbField::typeForString(testFileLine[4]); else { if (!castStringToQVariant(propertyValueString, propertyType, newValue)) { showError(QString("Could not set property '%1' value '%2' of type '%3'") .arg(propertyName).arg(propertyValueString).arg(propertyType)); return false; } } bool ok; int row = getNumber(testFileLine[1], &ok) - 1; if (!ok) return false; designerIface->changeFieldPropertyForRow(row, propertyName, newValue, 0, true); if (propertyName == "type") { //clean subtype name, e.g. from "longText" to "LongText", because dropdown list is case-sensitive QString realSubTypeName; if (KDbField::BLOB == KDbField::typeForString(testFileLine[4])) //! @todo hardcoded! realSubTypeName = "image"; else realSubTypeName = KDbField::typeString(KDbField::typeForString(testFileLine[4])); designerIface->changeFieldPropertyForRow(row, "subType", realSubTypeName, 0, true); } return true; } //helper bool AlterTableTester::getSchemaDump(KexiWindow* window, QString& schemaDebugString) { KexiTableDesignerInterface* designerIface = dynamic_cast(window->selectedView()); if (!designerIface) return false; // Get the result tristate result; schemaDebugString = designerIface->debugStringForCurrentTableSchema(result); if (true != result) { showError(QString("Loading modified schema failed. Result: %1") .arg(~result ? "cancelled" : "false")); return false; } schemaDebugString.remove(QRegularExpression(",$")); //no need to have "," at the end of lines return true; } bool AlterTableTester::showSchema(KexiWindow* window, bool copyToClipboard) { QString schemaDebugString; if (!getSchemaDump(window, schemaDebugString)) return false; if (copyToClipboard) QApplication::clipboard()->setText(schemaDebugString); else qDebug() << QString("Schema for '%1' table:\n").arg(window->partItem()->name()) + schemaDebugString + "\nendSchema"; return true; } bool AlterTableTester::checkInternal(KexiWindow* window, QString& debugString, const QString& endCommand, bool skipColonsAndStripWhiteSpace) { Q_UNUSED(window); QTextStream resultStream(&debugString, IO_ReadOnly); // Load expected result, compare QString expectedLine, resultLine; while (true) { const bool testFileStreamAtEnd = testFileStream.atEnd(); if (!testFileStreamAtEnd) { testLineNumber++; expectedLine = testFileStream.readLine(); if (skipColonsAndStripWhiteSpace) { expectedLine = expectedLine.stripWhiteSpace(); expectedLine.remove(QRegularExpression(",$")); //no need to have "," at the end of lines } } if (testFileStreamAtEnd || endCommand == expectedLine.stripWhiteSpace()) { if (!resultStream.atEnd()) { showError("Test file ends unexpectedly."); return false; } break; } //test line loaded, load result if (resultStream.atEnd()) { showError(QString("Result ends unexpectedly. There is at least one additinal test line: '") + expectedLine + "'"); return false; } resultLine = resultStream.readLine(); if (skipColonsAndStripWhiteSpace) { resultLine = resultLine.stripWhiteSpace(); resultLine.remove(QRegularExpressions(",$")); //no need to have "," at the end of lines } if (resultLine != expectedLine) { showError( QString("Result differs from the expected:\nExpected: ") + expectedLine + "\n????????: " + resultLine + "\n"); return false; } } return true; } bool AlterTableTester::checkSchema(KexiWindow* window) { QString schemaDebugString; if (!getSchemaDump(window, schemaDebugString)) return false; bool result = checkInternal(window, schemaDebugString, "endSchema", true /*skipColonsAndStripWhiteSpace*/); qDebug() << QString("Schema check for table '%1': %2").arg(window->partItem()->name()) .arg(result ? "OK" : "Failed"); return result; } bool AlterTableTester::getActionsDump(KexiWindow* window, QString& actionsDebugString) { KexiTableDesignerInterface* designerIface = dynamic_cast(window->selectedView()); if (!designerIface) return false; tristate result = designerIface->simulateAlterTableExecution(&actionsDebugString); if (true != result) { showError(QString("Computing simplified actions for table '%1' failed.").arg(window->partItem()->name())); return false; } return true; } bool AlterTableTester::showActions(KexiWindow* window, bool copyToClipboard) { QString actionsDebugString; if (!getActionsDump(window, actionsDebugString)) return false; if (copyToClipboard) QApplication::clipboard()->setText(actionsDebugString); else qDebug() << QString("Simplified actions for altering table '%1':\n").arg(window->partItem()->name()) + actionsDebugString + "\n"; return true; } bool AlterTableTester::checkActions(KexiWindow* window) { QString actionsDebugString; if (!getActionsDump(window, actionsDebugString)) return false; bool result = checkInternal(window, actionsDebugString, "endActions", true /*skipColonsAndStripWhiteSpace*/); qDebug() << QString("Actions check for table '%1': %2").arg(window->partItem()->name()) .arg(result ? "OK" : "Failed"); return result; } bool AlterTableTester::saveTableDesign(KexiWindow* window) { KexiTableDesignerInterface* designerIface = dynamic_cast(window->selectedView()); if (!designerIface) return false; tristate result = designerIface->executeRealAlterTable(); if (true != result) { showError(QString("Saving design of table '%1' failed.").arg(window->partItem()->name())); return false; } return true; } bool AlterTableTester::getTableDataDump(KexiWindow* window, QString& dataString) { KexiTableDesignerInterface* designerIface = dynamic_cast(window->selectedView()); if (!designerIface) return false; QMap args; QTextStream ts(&dataString, IO_WriteOnly); args["textStream"] = KexiUtils::ptrToString(&ts); args["destinationType"] = "file"; args["delimiter"] = "\t"; args["textQuote"] = "\""; args["itemId"] = QString::number( prj->dbConnection()->tableSchema(window->partItem()->name())->id()); if (!KexiInternalPart::executeCommand("org.kexi-project.importexport.csv", win, "KexiCSVExport", &args)) { showError("Error exporting table contents."); return false; } return true; } bool AlterTableTester::showTableData(KexiWindow* window, bool copyToClipboard) { QString dataString; if (!getTableDataDump(window, dataString)) return false; if (copyToClipboard) QApplication::clipboard()->setText(dataString); else qDebug() << QString("Contents of table '%1':\n").arg(window->partItem()->name()) + dataString + "\n"; return true; } bool AlterTableTester::checkTableData(KexiWindow* window) { QString dataString; if (!getTableDataDump(window, dataString)) return false; bool result = checkInternal(window, dataString, "endTableData", false /*!skipColonsAndStripWhiteSpace*/); qDebug() << QString("Table '%1' contents: %2").arg(window->partItem()->name()) .arg(result ? "OK" : "Failed"); return result; } bool AlterTableTester::closeWindow(KexiWindow* window) { if (!window) return true; QString name = window->partItem()->name(); tristate result = true == win->closeDialog(window, true/*layoutTaskBar*/, true/*doNotSaveChanges*/); qDebug() << QString("Closing window for table '%1': %2").arg(name) .arg(result == true ? "OK" : (result == false ? "Failed" : "Cancelled")); return result == true; } //! Processes test file tristate AlterTableTester::run(bool *closeAppRequested) { Q_ASSERT(closeAppRequested); *closeAppRequested = false; while (!m_finishedCopying) qApp->processEvents(300); qDebug() << "Database copied to temporary: " << dbFilename; if (!checkItemsNumber(2)) return false; tristate res = win->openProject(dbFilename, 0); if (true != res) return res; prj = win->project(); //open table in design mode res = readLineFromTestFile("designTable"); if (true != res) return ~res; QString tableName(testFileLine[1]); KexiPart::Item *item = prj->itemForMimeType("kexi/table", tableName); if (!item) { showError(QString("No such table '%1'").arg(tableName)); return false; } bool openingCancelled; KexiWindow* window = win->openObject(item, Kexi::DesignViewMode, &openingCancelled); if (!window) { showError(QString("Could not open table '%1'").arg(item->name())); return false; } KexiTableDesignerInterface* designerIface = dynamic_cast(window->selectedView()); if (!designerIface) return false; //dramatic speedup: temporary hide the window and propeditor QWidget * propeditor - = KexiUtils::findFirstChild(qApp->mainWidget(), "KexiPropertyEditorView"); + = KexiUtils::findFirstChild(qApp->mainWidget(), "KPropertyEditorView"); if (propeditor) propeditor->hide(); window->hide(); bool designTable = true; while (!testFileStream.atEnd()) { res = readLineFromTestFile(); if (true != res) return ~res; QString command(testFileLine[0]); if (designTable) { //subcommands available within "designTable" commands if (command == "endDesign") { if (!checkItemsNumber(1)) return false; //end of the design session: unhide the window and propeditor window->show(); if (propeditor) propeditor->show(); designTable = false; continue; } else if (command == "removeField") { if (!checkItemsNumber(2)) return false; bool ok; int row = getNumber(testFileLine[1], &ok) - 1; if (!ok) return false; designerIface->deleteRow(row, true); continue; } else if (command == "insertField") { if (!checkItemsNumber(3)) return false; bool ok; int row = getNumber(testFileLine[1], &ok) - 1; if (!ok) return false; designerIface->insertField(row, testFileLine[2], true); continue; } else if (command == "insertEmptyRecord") { if (!checkItemsNumber(2)) return false; bool ok; int row = getNumber(testFileLine[1], &ok) - 1; if (!ok) return false; designerIface->insertEmptyRecord(row, true); continue; } else if (command == "changeFieldProperty") { if (!checkItemsNumber(5) || !changeFieldProperty(designerIface)) return false; continue; } else if (command.startsWith("i=")) { bool ok; variableI = command.mid(2).toInt(&ok); if (!ok) { showError(QString("Invalid variable initialization '%1'").arg(command)); return false; } continue; } else if (command.startsWith("i++")) { variableI++; continue; } } else { //top-level commands available outside of "designTable" if (command == "showSchema") { if (!checkItemsNumber(1, 2) || !showSchema(window, testFileLine[1] == "clipboard")) return false; continue; } else if (command == "checkSchema") { if (!checkItemsNumber(1) || !checkSchema(window)) return false; continue; } else if (command == "showActions") { if (!checkItemsNumber(1, 2) || !showActions(window, testFileLine[1] == "clipboard")) return false; continue; } else if (command == "checkActions") { if (!checkItemsNumber(1) || !checkActions(window)) return false; continue; } else if (command == "saveTableDesign") { if (!checkItemsNumber(1) || !saveTableDesign(window)) return false; continue; } else if (command == "showTableData") { if (!checkItemsNumber(1, 2) || !showTableData(window, testFileLine[1] == "clipboard")) return false; continue; } else if (command == "checkTableData") { if (!checkItemsNumber(1) || !checkTableData(window)) return false; continue; } } //common commands if (command == "stop") { if (!checkItemsNumber(1)) return false; qDebug() << QString("Test STOPPED at line %1.").arg(testLineNumber); break; } else if (command == "closeWindow") { if (!checkItemsNumber(1) || !closeWindow(window)) return false; else window = 0; continue; } else if (command == "quit") { if (!checkItemsNumber(1) || !closeWindow(window)) return false; *closeAppRequested = true; qDebug() << QString("Quitting the application..."); break; } else { showError(QString("No such command '%1'").arg(command)); return false; } } return true; } //--------------------------------------- int quit(int result) { testFile.close(); if (newArgv) { delete [] newArgv[0]; delete [] newArgv[1]; delete [] newArgv; } return result; } int main(int argc, char *argv[]) { // args: <.altertable test filename> if (argc < 2) { qWarning() << "Please specify test filename.\nOptions: \n" "\t-close - closes the main window when test finishes"; return quit(1); } // options: const bool closeOnFinish = argc > 2 && 0 == qstrcmp(argv[1], "-close"); // open test file testFilename = argv[argc-1]; testFile.setName(testFilename); if (!testFile.open(IO_ReadOnly)) { qWarning() << QString("Opening test file %1 failed.").arg(testFilename); return quit(1); } //load db name testFileStream.setDevice(&testFile); tristate res = readLineFromTestFile("openDatabase"); if (true != res) return quit(~res ? 0 : 1); origDbFilename = testFileLine[1]; dbFilename = origDbFilename + ".tmp"; newArgc = 2; newArgv = new char*[newArgc]; newArgv[0] = qstrdup(argv[0]); newArgv[1] = 0; KAboutData aboutdata; aboutdata.setProgramName("Kexi Alter Table Test"); int result = KexiMainWindow::create(newArgc, newArgv, aboutdata); if (!qApp) return quit(result); win = KexiMainWindow::self(); AlterTableTester tester; //QObject::connect(win, SIGNAL(projectOpened()), &tester, SLOT(run())); bool closeAppRequested; res = tester.run(&closeAppRequested); if (true != res) { if (false == res) qWarning() << QString("Running test for file '%1' failed.").arg(testFilename); return quit(res == false ? 1 : 0); } qDebug() << QString("Tests from file '%1': OK").arg(testFilename); result = (closeOnFinish || closeAppRequested) ? 0 : qApp->exec(); quit(result); return result; } diff --git a/src/widget/CMakeLists.txt b/src/widget/CMakeLists.txt index 83560987b..de7471114 100644 --- a/src/widget/CMakeLists.txt +++ b/src/widget/CMakeLists.txt @@ -1,109 +1,110 @@ add_subdirectory( dataviewcommon ) add_subdirectory( relations ) add_subdirectory( undo ) add_subdirectory( utils ) if(KEXI_MOBILE) else() add_subdirectory( tableview ) endif() add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44023) include_directories( ${CMAKE_SOURCE_DIR}/src/widget/tableview ${CMAKE_SOURCE_DIR}/src/core ${CMAKE_SOURCE_DIR}/src/kexiutils/style ) ########### next target ############### set(kexiextendedwidgets_LIB_SRCS fields/KexiFieldComboBox.cpp fields/KexiFieldListModel.cpp fields/KexiFieldListModelItem.cpp fields/KexiFieldListView.cpp navigator/KexiProjectModel.cpp navigator/KexiProjectModelItem.cpp navigator/KexiProjectItemDelegate.cpp navigator/KexiProjectNavigator.cpp navigator/KexiProjectTreeView.cpp + properties/KexiPropertyPaneWidget.cpp properties/KexiCustomPropertyFactory.cpp properties/KexiCustomPropertyFactory_p.cpp - properties/KexiPropertyEditorView.cpp - properties/KexiPropertyPaneViewBase.cpp + properties/KexiObjectInfoWidget.cpp + properties/KexiPropertyPaneLineEdit.cpp kexiquerydesignersqleditor.cpp kexiqueryparameters.cpp kexisectionheader.cpp kexidbdrivercombobox.cpp kexieditor.cpp KexiDataSourceComboBox.cpp - KexiObjectInfoLabel.cpp kexicharencodingcombobox.cpp KexiDBTitlePage.cpp KexiProjectSelectorWidget.cpp kexislider.cpp KexiServerDriverNotFoundMessage.cpp KexiNameWidget.cpp KexiNameDialog.cpp KexiStartupFileHandler.cpp KexiListView.cpp KexiWidgetWidthAnimator.cpp ) if (KEXI_MOBILE) else () list(APPEND kexiextendedwidgets_LIB_SRCS #navigator/KexiProjectListView.cpp #navigator/KexiProjectListViewItem.cpp kexidbconnectionwidget.cpp # TODO replace use of KexiProjectListView and KexiProjectListViewList (with KexiProjectNavigator) # in kexiactionselectiondialog and remove them kexiprjtypeselector.cpp KexiConnectionSelectorWidget.cpp KexiFileWidget.cpp KexiFileDialog.cpp KexiPasswordWidget.cpp KexiDBPasswordDialog.cpp ) ki18n_wrap_ui(kexiextendedwidgets_LIB_SRCS KexiConnectionSelector.ui kexidbconnectionwidget.ui kexidbconnectionwidgetdetails.ui kexiprjtypeselector.ui KexiPasswordWidget.ui ) endif () ki18n_wrap_ui(kexiextendedwidgets_LIB_SRCS KexiDBTitlePage.ui KexiProjectSelector.ui ) kexi_add_library(kexiextendedwidgets SHARED ${kexiextendedwidgets_LIB_SRCS}) generate_export_header(kexiextendedwidgets BASE_NAME kexiextwidgets) target_link_libraries(kexiextendedwidgets PRIVATE kexidataviewcommon kexiutils kexiguiutils kexicore KDb KPropertyWidgets KF5::TextWidgets # KTextEdit KF5::Codecs # KCharsets PUBLIC KF5::KIOFileWidgets # KFileWidget KF5::TextEditor + KF5::ConfigWidgets ) install(TARGETS kexiextendedwidgets ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/widget/KexiObjectInfoLabel.cpp b/src/widget/KexiObjectInfoLabel.cpp deleted file mode 100644 index 14cfab120..000000000 --- a/src/widget/KexiObjectInfoLabel.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2004-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. -*/ - -#include "KexiObjectInfoLabel.h" - -#include -#include -#include -#include - -#include -#include - -class Q_DECL_HIDDEN KexiObjectInfoLabel::Private -{ -public: - Private() {} - QString className; - QString classIconName; - QString objectName; - QLabel *objectIconLabel; - QLabel *objectNameLabel; -}; - -KexiObjectInfoLabel::KexiObjectInfoLabel(QWidget* parent) - : QWidget(parent) - , d( new Private ) -{ - QWidget::setObjectName("KexiObjectInfoLabel"); - QHBoxLayout *hlyr = new QHBoxLayout(this); - hlyr->setContentsMargins(0, 0, 0, 0); - hlyr->setSpacing(2); - d->objectIconLabel = new QLabel(this); - d->objectIconLabel->setMargin(2); - setMinimumHeight(IconSize(KIconLoader::Small) + 2 + 2); - hlyr->addWidget(d->objectIconLabel); - d->objectNameLabel = new QLabel(this); - d->objectNameLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); - hlyr->addWidget(d->objectNameLabel); -} - -KexiObjectInfoLabel::~KexiObjectInfoLabel() -{ - delete d; -} - -QString KexiObjectInfoLabel::objectClassIconName() const -{ - return d->classIconName; -} - -void KexiObjectInfoLabel::setObjectClassIconName(const QString &iconName) -{ - d->classIconName = iconName; - if (d->classIconName.isEmpty()) { - d->objectIconLabel->setFixedWidth(0); - } - else { - d->objectIconLabel->setFixedWidth(IconSize(KIconLoader::Small) + 2 + 2); - } - d->objectIconLabel->setPixmap(QIcon::fromTheme(iconName).pixmap(IconSize(KIconLoader::Small))); -} - -QString KexiObjectInfoLabel::objectClassName() const -{ - return d->className; -} - -void KexiObjectInfoLabel::setObjectClassName(const QString& name) -{ - d->className = name; - updateName(); -} - -QString KexiObjectInfoLabel::objectName() const -{ - return d->objectName; -} - -void KexiObjectInfoLabel::setObjectName(const QString& name) -{ - d->objectName = name; - updateName(); -} - -void KexiObjectInfoLabel::updateName() -{ - QString txt(d->className); - if (txt.isEmpty()) { - txt = d->objectName; - } - else if (!d->objectName.isEmpty()) { - txt = xi18nc("Object class \"objectName\", e.g. Text editor \"text\"", "%1 %2", - txt, d->objectName); - } - d->objectNameLabel->setText(txt); -} - -void KexiObjectInfoLabel::setBuddy(QWidget * buddy) -{ - d->objectNameLabel->setBuddy(buddy); -} diff --git a/src/widget/properties/KexiObjectInfoWidget.cpp b/src/widget/properties/KexiObjectInfoWidget.cpp new file mode 100644 index 000000000..682363a73 --- /dev/null +++ b/src/widget/properties/KexiObjectInfoWidget.cpp @@ -0,0 +1,118 @@ +/* This file is part of the KDE project + Copyright (C) 2004-2016 Jarosław Staniek + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "KexiObjectInfoWidget.h" +#include "KexiPropertyPaneLineEdit.h" +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +class KexiObjectInfoWidget::Private +{ +public: + Private() {} + QString classIconName; + QLabel *objectIconLabel; + QLabel *objectClassLabel; + KexiPropertyPaneLineEdit *objectNameBox; +}; + +KexiObjectInfoWidget::KexiObjectInfoWidget(QWidget* parent) + : QWidget(parent) + , d( new Private ) +{ + QWidget::setObjectName("KexiObjectInfoWidget"); + QHBoxLayout *hlyr = new QHBoxLayout(this); + hlyr->setContentsMargins(0, 0, 0, 0); + hlyr->setSpacing(0); + + const KexiStyle::PropertyPane &s = KexiStyle::propertyPane(); + + hlyr->addSpacing(s.sectionTitleIndent); + d->objectIconLabel = new QLabel; + d->objectIconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + hlyr->addWidget(d->objectIconLabel, 3); + + d->objectClassLabel = new QLabel; + d->objectClassLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + d->objectClassLabel->setPalette(s.sectionTitlePalette(d->objectClassLabel->palette())); + hlyr->addWidget(d->objectClassLabel, 0); + + hlyr->addSpacing(s.horizontalSpacingAfterLabel); + + d->objectNameBox = new KexiPropertyPaneLineEdit; + hlyr->addWidget(d->objectNameBox, 2); + d->objectNameBox->setClearButtonEnabled(true); + d->objectNameBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + d->objectClassLabel->setBuddy(d->objectNameBox); + + hlyr->addSpacing(s.margins.right()); +} + +KexiObjectInfoWidget::~KexiObjectInfoWidget() +{ + delete d; +} + +QString KexiObjectInfoWidget::objectClassIconName() const +{ + return d->classIconName; +} + +void KexiObjectInfoWidget::setObjectClassIconName(const QString &iconName) +{ + const KexiStyle::PropertyPane &s = KexiStyle::propertyPane(); + d->classIconName = iconName; + if (d->classIconName.isEmpty()) { + d->objectIconLabel->setFixedWidth(0); + } + else { + d->objectIconLabel->setMaximumWidth(IconSize(KIconLoader::Small) + s.horizontalSpacingAfterIcon); + } + d->objectIconLabel->setPixmap(QIcon::fromTheme(iconName).pixmap(IconSize(KIconLoader::Small))); +} + +QString KexiObjectInfoWidget::objectClassName() const +{ + return d->objectClassLabel->text(); +} + +void KexiObjectInfoWidget::setObjectClassName(const QString& name) +{ + d->objectClassLabel->setText(name); +} + +QString KexiObjectInfoWidget::objectName() const +{ + return d->objectNameBox->text(); +} + +void KexiObjectInfoWidget::setObjectName(const QString& name) +{ + d->objectNameBox->setText(name); + d->objectNameBox->setCursorPosition(0); +} diff --git a/src/widget/KexiObjectInfoLabel.h b/src/widget/properties/KexiObjectInfoWidget.h similarity index 64% rename from src/widget/KexiObjectInfoLabel.h rename to src/widget/properties/KexiObjectInfoWidget.h index 77314042c..820abaad1 100644 --- a/src/widget/KexiObjectInfoLabel.h +++ b/src/widget/properties/KexiObjectInfoWidget.h @@ -1,66 +1,63 @@ /* This file is part of the KDE project Copyright (C) 2004-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 KEXIOBJECTINFOLABEL_H -#define KEXIOBJECTINFOLABEL_H +#ifndef KEXIOBJECTINFOWIDGET_H +#define KEXIOBJECTINFOWIDGET_H #include "kexiextwidgets_export.h" #include -//! @short Helper class displaying small icon with class name and object name -/*! The info label is displayed in a form: - [ObjectClassIcon] ClassName "ObjectName" +//! @short A widget displaying small icon with class name and editable object's name +/*! The info widget is displayed in a form: + [ObjectClassIcon] ClassName [ObjectName] - The ObjectClassIcon is optional. If "ClassName" is empty, the information + The ObjectClassIcon is optional. If ClassName is empty, the information is displayed as: - [ObjectClassIcon] ObjectName + [ObjectClassIcon] [ObjectName] Example uses: - - [button_icon] Button "quit" - - [label_icon] Label "welcome" + - [button_icon] Button [quit] + - [label_icon] Label [welcome] */ -class KEXIEXTWIDGETS_EXPORT KexiObjectInfoLabel : public QWidget +class KEXIEXTWIDGETS_EXPORT KexiObjectInfoWidget : public QWidget { Q_OBJECT public: - explicit KexiObjectInfoLabel(QWidget* parent); - virtual ~KexiObjectInfoLabel(); + explicit KexiObjectInfoWidget(QWidget* parent = 0); + virtual ~KexiObjectInfoWidget(); void setObjectClassIconName(const QString &name); QString objectClassIconName() const; - void setObjectClassName(const QString& name); + void setObjectClassName(const QString& name); QString objectClassName() const; void setObjectName(const QString& name); QString objectName() const; - void setBuddy(QWidget * buddy); -protected: - void updateName(); - +private: class Private; Private * const d; }; #endif diff --git a/src/widget/properties/KexiPropertyEditorView.cpp b/src/widget/properties/KexiPropertyEditorView.cpp index 7458bacca..f08bb5424 100644 --- a/src/widget/properties/KexiPropertyEditorView.cpp +++ b/src/widget/properties/KexiPropertyEditorView.cpp @@ -1,90 +1,127 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur - Copyright (C) 2004-2009 Jarosław Staniek + Copyright (C) 2004-2016 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KexiPropertyEditorView.h" -#include "KexiObjectInfoLabel.h" +#include "KexiObjectInfoWidget.h" #include #include #include #include #include #include //! @internal class Q_DECL_HIDDEN KexiPropertyEditorView::Private { public: Private() { } + QVBoxLayout *mainLayout; + KexiObjectInfoWidget *infoLabel; KPropertyEditorView *editor; }; KexiPropertyEditorView::KexiPropertyEditorView(QWidget* parent) - : KexiPropertyPaneViewBase(parent) + : QWidget(parent) , d(new Private()) { setObjectName("KexiPropertyEditorView"); - setWindowTitle(xi18nc("@title:window", "Properties")); - //! @todo set a nice icon -// setWindowIcon(KexiMainWindowIface::global()->thisWidget()->windowIcon()); + + d->mainLayout = new QVBoxLayout(this); + d->mainLayout->setContentsMargins(0, 0, 0, 0); + d->mainLayout->setSpacing(0); + + d->infoLabel = new KexiObjectInfoWidget; + d->mainLayout->addWidget(d->infoLabel); d->editor = new KPropertyEditorView(this); d->editor->setGridLineColor(QColor()); d->editor->setFrameShape(QFrame::NoFrame); - layout()->addWidget(d->editor); + d->mainLayout->addWidget(d->editor); setFocusProxy(d->editor); - infoLabel()->setBuddy(d->editor); setFocusPolicy(Qt::WheelFocus); connect(d->editor, SIGNAL(propertySetChanged(KPropertySet*)), this, SLOT(slotPropertySetChanged(KPropertySet*))); slotPropertySetChanged(0); } KexiPropertyEditorView::~KexiPropertyEditorView() { delete d; } QSize KexiPropertyEditorView::sizeHint() const { return QSize(200, 200); } QSize KexiPropertyEditorView::minimumSizeHint() const { return QSize(200, 200); } KPropertyEditorView *KexiPropertyEditorView::editor() const { return d->editor; } void KexiPropertyEditorView::slotPropertySetChanged(KPropertySet* set) { - //update information about selected object - updateInfoLabelForPropertySet(set); + QString className, iconName, objectName; + if (set) { + className = set->propertyValue("this:classString").toString(); + iconName = set->propertyValue("this:iconName").toString(); + const bool useCaptionAsObjectName + = set->propertyValue("this:useCaptionAsObjectName", false).toBool(); + objectName = set->propertyValue( + useCaptionAsObjectName ? "caption" : "objectName").toString(); + if (objectName.isEmpty() && useCaptionAsObjectName) { + // get name if there is no caption + objectName = set->propertyValue("objectName").toString(); + } + } + if (!set || objectName.isEmpty()) { +//! @todo don't hardcode + QString textToDisplayForNullSet(xi18n("No field selected")); + objectName = textToDisplayForNullSet; + className.clear(); + iconName.clear(); + } + + if (className.isEmpty() && objectName.isEmpty()) + d->infoLabel->hide(); + else + d->infoLabel->show(); + + if (d->infoLabel->objectClassName() == className + && d->infoLabel->objectClassIconName() == iconName + && d->infoLabel->objectName() == objectName) + return; + + d->infoLabel->setObjectClassIconName(iconName); + d->infoLabel->setObjectClassName(className); + d->infoLabel->setObjectName(objectName); + d->editor->setEnabled(set); } - diff --git a/src/widget/properties/KexiPropertyEditorView.h b/src/widget/properties/KexiPropertyEditorView.h index f3dc29831..0e97e7883 100644 --- a/src/widget/properties/KexiPropertyEditorView.h +++ b/src/widget/properties/KexiPropertyEditorView.h @@ -1,63 +1,63 @@ /* This file is part of the KDE project Copyright (C) 2004 Cedric Pasteur - Copyright (C) 2004-2009 Jarosław Staniek + Copyright (C) 2004-2016 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 KEXIPROPERTYEDITORVIEW_H #define KEXIPROPERTYEDITORVIEW_H #include "kexiextwidgets_export.h" -#include "KexiPropertyPaneViewBase.h" #include //! @short The container (acts as a dock window) for KexiPropertyEditor. -/*! The widget displays KexiObjectInfoLabel on its top, to show user what - object the properties belong to. Read KexiObjectInfoLabel documentation for +/*! The widget displays KexiObjectInfoWidget on its top, to show user what + object the properties belong to. Read the KexiObjectInfoWidget documentation for the description what information is displayed. There are properties obtained from KexiMainWindow's current property set that help to customize displaying this information: - "this:classString property" of type string describes object's class name - "this:iconName" property of type string describes class name - "name" or "caption" property of type string describes object's name - "this:useCaptionAsObjectName" property of type boolean forces displaying "caption" property instead of "name" - this can be usable when we know that "caption" properties are available for a given type of objects (this is the case for Table Designer fields) */ -class KEXIEXTWIDGETS_EXPORT KexiPropertyEditorView : public KexiPropertyPaneViewBase +class KEXIEXTWIDGETS_EXPORT KexiPropertyEditorView : public QWidget { Q_OBJECT public: explicit KexiPropertyEditorView(QWidget* parent); virtual ~KexiPropertyEditorView(); - virtual QSize sizeHint() const; - virtual QSize minimumSizeHint() const; + QSize sizeHint() const Q_DECL_OVERRIDE; + QSize minimumSizeHint() const Q_DECL_OVERRIDE; KPropertyEditorView *editor() const; protected Q_SLOTS: - void slotPropertySetChanged(KPropertySet*); + //! Update information about selected object + void slotPropertySetChanged(KPropertySet* set); protected: class Private; Private * const d; }; #endif diff --git a/src/widget/properties/KexiPropertyPaneLineEdit.cpp b/src/widget/properties/KexiPropertyPaneLineEdit.cpp new file mode 100644 index 000000000..8edbf285f --- /dev/null +++ b/src/widget/properties/KexiPropertyPaneLineEdit.cpp @@ -0,0 +1,48 @@ +/* This file is part of the KDE project + Copyright (C) 2016 Jarosław Staniek + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "KexiPropertyPaneLineEdit.h" +#include + +#include +#include + +#include +#include +#include +#include + +class KexiPropertyPaneLineEdit::Private +{ +public: + Private(KexiPropertyPaneLineEdit *qq) : q(qq) {} + KexiPropertyPaneLineEdit * const q; +}; + +KexiPropertyPaneLineEdit::KexiPropertyPaneLineEdit(QWidget* parent) + : QLineEdit(parent) + , d(new Private(this)) +{ + KexiStyle::propertyPane().alterLineEditStyle(this); +} + +KexiPropertyPaneLineEdit::~KexiPropertyPaneLineEdit() +{ + delete d; +} diff --git a/src/main/KexiPropertyPaneWidget.h b/src/widget/properties/KexiPropertyPaneLineEdit.h similarity index 55% copy from src/main/KexiPropertyPaneWidget.h copy to src/widget/properties/KexiPropertyPaneLineEdit.h index 29b2f4e64..6c583d02b 100644 --- a/src/main/KexiPropertyPaneWidget.h +++ b/src/widget/properties/KexiPropertyPaneLineEdit.h @@ -1,46 +1,40 @@ /* This file is part of the KDE project Copyright (C) 2016 Jarosław Staniek - This library is free software; you can redistribute it and/or + 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 library is distributed in the hope that it will be useful, + 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 library; see the file COPYING.LIB. If not, write to + 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 KEXIPROPERTYPANEWIDGET_H -#define KEXIPROPERTYPANEWIDGET_H +#ifndef KEXIPROPERTYPANELINEEDIT_H +#define KEXIPROPERTYPANELINEEDIT_H -#include +#include "kexiextwidgets_export.h" -class QToolBox; -class KexiPropertyEditorView; +#include -//! @short A widget handling entire Property Pane -class KexiPropertyPaneWidget : public QWidget +//! @short A line edit for use in the property pane +/*! The widget has modified look */ +class KEXIEXTWIDGETS_EXPORT KexiPropertyPaneLineEdit : public QLineEdit { - Q_OBJECT public: - explicit KexiPropertyPaneWidget(QWidget *parent); - - virtual ~KexiPropertyPaneWidget(); - - KexiPropertyEditorView *editor() const; - - QToolBox* toolBox() const; + explicit KexiPropertyPaneLineEdit(QWidget* parent = 0); + virtual ~KexiPropertyPaneLineEdit(); private: class Private; Private * const d; }; #endif diff --git a/src/widget/properties/KexiPropertyPaneViewBase.cpp b/src/widget/properties/KexiPropertyPaneViewBase.cpp index 7de4bc27d..539a39707 100644 --- a/src/widget/properties/KexiPropertyPaneViewBase.cpp +++ b/src/widget/properties/KexiPropertyPaneViewBase.cpp @@ -1,125 +1,124 @@ /* This file is part of the KDE project Copyright (C) 2004-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. */ #include "KexiPropertyPaneViewBase.h" -#include "KexiObjectInfoLabel.h" +#include "KexiObjectInfoWidget.h" #include #include #include #include #include //! @internal class Q_DECL_HIDDEN KexiPropertyPaneViewBase::Private { public: Private() { } - KexiObjectInfoLabel *infoLabel; }; KexiPropertyPaneViewBase::KexiPropertyPaneViewBase(QWidget* parent) : QWidget(parent) , d(new Private()) { //! @todo set a nice icon // setWindowIcon(KexiMainWindowIface::global()->thisWidget()->windowIcon()); QVBoxLayout *lyr = new QVBoxLayout(this); lyr->setContentsMargins(0, 0, 0, 0); lyr->setSpacing(0); //add object class info - d->infoLabel = new KexiObjectInfoLabel(this); + d->infoLabel = new KexiObjectInfoWidget(this); lyr->addWidget(d->infoLabel); } KexiPropertyPaneViewBase::~KexiPropertyPaneViewBase() { delete d; } -KexiObjectInfoLabel *KexiPropertyPaneViewBase::infoLabel() const +KexiObjectInfoWidget *KexiPropertyPaneViewBase::infoLabel() const { return d->infoLabel; } void KexiPropertyPaneViewBase::updateInfoLabelForPropertySet( KPropertySet* set, const QString& textToDisplayForNullSet) { QString className, iconName, objectName; if (set) { className = set->propertyValue("this:classString").toString(); iconName = set->propertyValue("this:iconName").toString(); const bool useCaptionAsObjectName = set->propertyValue("this:useCaptionAsObjectName", false).toBool(); objectName = set->propertyValue( useCaptionAsObjectName ? "caption" : "objectName").toString(); if (objectName.isEmpty() && useCaptionAsObjectName) { // get name if there is no caption objectName = set->propertyValue("objectName").toString(); } } if (!set || objectName.isEmpty()) { objectName = textToDisplayForNullSet; className.clear(); iconName.clear(); } if (className.isEmpty() && objectName.isEmpty()) d->infoLabel->hide(); else d->infoLabel->show(); if (d->infoLabel->objectClassName() == className && d->infoLabel->objectClassIconName() == iconName && d->infoLabel->objectName() == objectName) return; d->infoLabel->setObjectClassIconName(iconName); d->infoLabel->setObjectClassName(className); d->infoLabel->setObjectName(objectName); } QVBoxLayout* KexiPropertyPaneViewBase::mainLayout() const { return qobject_cast(layout()); } int KexiPropertyPaneViewBase::spacing() const { return fontMetrics().height() * 2 / 3; } void KexiPropertyPaneViewBase::addSpacing() { return mainLayout()->addSpacing( spacing() ); } QWidget* KexiPropertyPaneViewBase::addWidgetSpacer() { QWidget *sp = new QWidget(this); sp->setFixedHeight(spacing()); sp->setContentsMargins(0, 0, 0, 0); mainLayout()->addWidget(sp); return sp; } diff --git a/src/widget/properties/KexiPropertyPaneViewBase.h b/src/widget/properties/KexiPropertyPaneViewBase.h index 57977afb2..f3c6037d8 100644 --- a/src/widget/properties/KexiPropertyPaneViewBase.h +++ b/src/widget/properties/KexiPropertyPaneViewBase.h @@ -1,72 +1,72 @@ /* This file is part of the KDE project Copyright (C) 2004-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 KEXIPROPERTYEDITORVIEWBASE_H #define KEXIPROPERTYEDITORVIEWBASE_H #include "kexiextwidgets_export.h" #include class QVBoxLayout; class KPropertySet; -class KexiObjectInfoLabel; +class KexiObjectInfoWidget; //! @short A base class for propety pane's tabs. /*! Defines vertical layout and offers info label on the top. Use mainLayout() to access the QVBoxLayout object. */ class KEXIEXTWIDGETS_EXPORT KexiPropertyPaneViewBase : public QWidget { Q_OBJECT public: explicit KexiPropertyPaneViewBase(QWidget* parent = 0); virtual ~KexiPropertyPaneViewBase(); - KexiObjectInfoLabel *infoLabel() const; + KexiObjectInfoWidget *infoLabel() const; /*! Helper function. Updates \a infoLabel widget by reusing properties provided by property set \a set. Read documentation of KexiPropertyEditorView class for information about accepted properties. If \a set is 0 and \a textToDisplayForNullSet string is not empty, this string is displayed (without icon or any other additional part). If \a set is 0 and \a textToDisplayForNullSet string is empty, the \a infoLabel widget becomes hidden. */ void updateInfoLabelForPropertySet( KPropertySet* set, const QString& textToDisplayForNullSet = QString()); protected: //! @return main vertical layout of the pane QVBoxLayout* mainLayout() const; //! @return default spacing for the pane, 2/3 of the font height int spacing() const; //! Adds spacing to the main layout. The size of spacing is taken from spacing(). void addSpacing(); //! Adds widget-based spacing to the main layout. The size of spacing is taken from spacing(). QWidget* addWidgetSpacer(); class Private; Private * const d; }; #endif diff --git a/src/widget/properties/KexiPropertyPaneWidget.cpp b/src/widget/properties/KexiPropertyPaneWidget.cpp new file mode 100644 index 000000000..c0fde521d --- /dev/null +++ b/src/widget/properties/KexiPropertyPaneWidget.cpp @@ -0,0 +1,153 @@ +/* This file is part of the KDE project + Copyright (C) 2016 Jarosław Staniek + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "KexiPropertyPaneWidget.h" +#include "KexiObjectInfoWidget.h" +#include + +#include +#include +#include + +#include + +class KexiPropertyPaneWidget::Private +{ +public: + Private() {} + QVBoxLayout *mainLyr; + KexiObjectInfoWidget *infoLabel; + KPropertyEditorView *editor; + //! Needed by removeAllSections() + int firstSectionIndex; +}; + +KexiPropertyPaneWidget::KexiPropertyPaneWidget(QWidget *parent) + : QWidget(parent), d(new Private) +{ + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + d->mainLyr = new QVBoxLayout(this); + d->mainLyr->setContentsMargins(0, 0, 0, 0); + d->mainLyr->setSpacing(0); + + const KexiStyle::PropertyPane &s = KexiStyle::propertyPane(); + d->mainLyr->addSpacing(s.margins.top()); + + d->infoLabel = new KexiObjectInfoWidget; + d->mainLyr->addWidget(d->infoLabel); + d->infoLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + + d->mainLyr->addSpacing(s.verticalSpacing); + + d->editor = new KPropertyEditorView(this); + s.setupEditor(d->editor); + d->editor->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum); + d->mainLyr->addWidget(d->editor, 1); + + d->mainLyr->addSpacing(s.verticalSpacing); + + d->firstSectionIndex = d->mainLyr->count(); + setFocusProxy(d->editor); + setFocusPolicy(Qt::WheelFocus); + + connect(d->editor, &KPropertyEditorView::propertySetChanged, + this, &KexiPropertyPaneWidget::slotPropertySetChanged); + + slotPropertySetChanged(0); +} + +KexiPropertyPaneWidget::~KexiPropertyPaneWidget() +{ + delete d; +} + +KPropertyEditorView* KexiPropertyPaneWidget::editor() const +{ + return d->editor; +} + +void KexiPropertyPaneWidget::removeAllSections() +{ + while (d->mainLyr->count() > d->firstSectionIndex) { + QLayoutItem *item = d->mainLyr->itemAt(d->firstSectionIndex); + if (item->widget()) { + item->widget()->hide(); + } + d->mainLyr->removeItem(d->mainLyr->itemAt(d->firstSectionIndex)); + } +} + +void KexiPropertyPaneWidget::addSection(QWidget *widget, const QString &title) +{ + if (d->mainLyr->indexOf(widget) != -1) { + return; + } + d->mainLyr->addWidget(widget); + widget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + widget->show(); +} + +void KexiPropertyPaneWidget::slotPropertySetChanged(KPropertySet* set) +{ + updateInfoLabelForPropertySet(set); +} + +void KexiPropertyPaneWidget::updateInfoLabelForPropertySet(KPropertySet* set) +{ + QString className, iconName, objectName; + if (set) { + className = set->propertyValue("this:classString").toString(); + iconName = set->propertyValue("this:iconName").toString(); + const bool useCaptionAsObjectName + = set->propertyValue("this:useCaptionAsObjectName", false).toBool(); + objectName = set->propertyValue( + useCaptionAsObjectName ? "caption" : "objectName").toString(); + if (objectName.isEmpty() && useCaptionAsObjectName) { + // get name if there is no caption + objectName = set->propertyValue("objectName").toString(); + } + } + if (!set || objectName.isEmpty()) { +//! @todo don't hardcode + QString textToDisplayForNullSet(xi18n("No field selected")); + objectName = textToDisplayForNullSet; + className.clear(); + iconName.clear(); + } + + if (className.isEmpty() && objectName.isEmpty()) + d->infoLabel->hide(); + else + d->infoLabel->show(); + + if (d->infoLabel->objectClassName() == className + && d->infoLabel->objectClassIconName() == iconName + && d->infoLabel->objectName() == objectName) + { + return; + } + + d->infoLabel->setObjectClassIconName(iconName); + d->infoLabel->setObjectClassName(className); + d->infoLabel->setObjectName(objectName); + + d->editor->setEnabled(set); + d->infoLabel->layout()->update(); + update(); +} diff --git a/src/main/KexiPropertyPaneWidget.h b/src/widget/properties/KexiPropertyPaneWidget.h similarity index 59% rename from src/main/KexiPropertyPaneWidget.h rename to src/widget/properties/KexiPropertyPaneWidget.h index 29b2f4e64..04327f1ef 100644 --- a/src/main/KexiPropertyPaneWidget.h +++ b/src/widget/properties/KexiPropertyPaneWidget.h @@ -1,46 +1,59 @@ /* This file is part of the KDE project Copyright (C) 2016 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KEXIPROPERTYPANEWIDGET_H #define KEXIPROPERTYPANEWIDGET_H +#include "kexiextwidgets_export.h" + #include -class QToolBox; -class KexiPropertyEditorView; +class KPropertySet; +class KPropertyEditorView; //! @short A widget handling entire Property Pane -class KexiPropertyPaneWidget : public QWidget +class KEXIEXTWIDGETS_EXPORT KexiPropertyPaneWidget : public QWidget { Q_OBJECT public: - explicit KexiPropertyPaneWidget(QWidget *parent); + explicit KexiPropertyPaneWidget(QWidget *parent = 0); virtual ~KexiPropertyPaneWidget(); - KexiPropertyEditorView *editor() const; + KPropertyEditorView *editor() const; + + void addSection(QWidget *widget, const QString &title); + + //! Removes all sections added by addSection() from the pane's layout and hide them. + //! Does not delete the sections; they should be owned by parts and can be reused later. + //! Used by the main window when pane should be reset. + void removeAllSections(); + + void updateInfoLabelForPropertySet(KPropertySet* set); - QToolBox* toolBox() const; +protected Q_SLOTS: + //! Update information about selected object + void slotPropertySetChanged(KPropertySet* set); private: class Private; Private * const d; }; #endif