diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,7 @@ PURPOSE "Used to provide crash reporting on Linux") set(REQUIRED_QT_VERSION 5.4.0) -find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Gui Widgets Xml Network PrintSupport Test) +find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Gui Widgets Xml Network PrintSupport Svg Test) find_package(Qt5 ${REQUIRED_QT_VERSION} COMPONENTS UiTools WebKit WebKitWidgets) # use sane compile flags diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -69,5 +69,7 @@ ) endif() +target_include_directories(kexicore PUBLIC ${CMAKE_SOURCE_DIR}/src/kexiutils/style) + 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 --- a/src/core/KexiMainWindowIface.h +++ b/src/core/KexiMainWindowIface.h @@ -1,6 +1,6 @@ /* 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 @@ -47,6 +47,43 @@ } 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, + NoGlobalMode //!< special +}; + +//! @return global view mode for window view mode @a viewMode. +//! EditGlobalMode is mapped from data view, DesignGlobalMode and for design and text view. +//! NoGlobalMode is returned for other values. +KEXICORE_EXPORT GlobalViewMode viewModeToGlobal(Kexi::ViewMode viewMode); + +} + /** * @short Kexi's main window interface * This interface is implemented by KexiMainWindow class. @@ -95,6 +132,9 @@ 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; @@ -146,6 +186,10 @@ bool sortedProperties = false, const QByteArray& propertyToSelect = QByteArray()) = 0; + virtual void beginPropertyPaneUpdate() = 0; + + virtual void endPropertyPaneUpdate() = 0; + //! Options used in saveObject() enum SaveObjectOption { @@ -264,12 +308,8 @@ /*! Updates info label of the property editor by reusing properties provided by the current property set. - Read documentation of KexiPropertyEditorView class for information about accepted properties. - If the current property is 0 and @a textToDisplayForNullSet string is not empty, this string is displayed - (without icon or any other additional part). - If the current property is 0 and @a textToDisplayForNullSet string is empty, the info label widget becomes - hidden. */ - virtual void updatePropertyEditorInfoLabel(const QString& textToDisplayForNullSet = QString()) = 0; + Read documentation of KexiPropertyPaneWidget class for information about accepted properties. */ + virtual void updatePropertyEditorInfoLabel() = 0; /*! Add searchable model to the main window. This extends search to a new area. One example is Project Navigator. */ @@ -286,6 +326,10 @@ //! 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; diff --git a/src/core/KexiMainWindowIface.cpp b/src/core/KexiMainWindowIface.cpp --- a/src/core/KexiMainWindowIface.cpp +++ b/src/core/KexiMainWindowIface.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2003-2009 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 @@ -45,3 +45,20 @@ { return dynamic_cast(this); } + +namespace Kexi { + +KEXICORE_EXPORT GlobalViewMode viewModeToGlobal(Kexi::ViewMode viewMode) +{ + switch(viewMode) { + case DataViewMode: + return EditGlobalMode; + case DesignViewMode: + case TextViewMode: + return DesignGlobalMode; + default: + return NoGlobalMode; + } +} + +} // namespace Kexi diff --git a/src/core/KexiView.h b/src/core/KexiView.h --- a/src/core/KexiView.h +++ b/src/core/KexiView.h @@ -1,5 +1,5 @@ /* This file is part of the KDE project - Copyright (C) 2004-2012 Jarosław Staniek + 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 @@ -138,6 +138,10 @@ /*! For KexiQueryView */ virtual QList currentParameters() const; + //! @return i18n'd message text to be displayed in the property pane if the current + //! property set is @c nullptr. + QString textToDisplayForNullSet() const; + public Q_SLOTS: virtual void setFocus(); @@ -338,13 +342,17 @@ //! Sets properties in the Property Editor to be sorted if @a set is true. void setSortedProperties(bool set); + /*! Sets i18n'd message text to be displayed in the property pane if the current property set + is @c nullptr. By default it is empty, what means "No object selected" is displayed. */ + void setTextToDisplayForNullSet(const QString& text); + private Q_SLOTS: void slotSwitchToViewModeInternal(Kexi::ViewMode mode); - void slotSwitchToDataViewModeInternal(bool); void slotSwitchToDesignViewModeInternal(bool); void slotSwitchToTextViewModeInternal(bool); private: + void createTopBar(); void createViewModeToggleButtons(); class Private; diff --git a/src/core/KexiView.cpp b/src/core/KexiView.cpp --- a/src/core/KexiView.cpp +++ b/src/core/KexiView.cpp @@ -1,5 +1,5 @@ /* This file is part of the KDE project - Copyright (C) 2004-2012 Jarosław Staniek + 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 @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include "KexiGroupButton.h" @@ -49,27 +51,23 @@ public: //! Creates action for toggling to view mode @a mode. @a slot should have signature //! matching switchedTo(Kexi::ViewMode mode) signal. - KexiToggleViewModeAction(Kexi::ViewMode mode, QObject* parent) + KexiToggleViewModeAction(const QString& pluginId, Kexi::ViewMode mode, QObject* parent) : QAction( - QIcon::fromTheme(Kexi::iconNameForViewMode(mode)), + QIcon::fromTheme(Kexi::iconNameForViewMode(pluginId, mode)), Kexi::nameForViewMode(mode, true/*withAmpersand*/), parent) { setCheckable(true); - if (mode == Kexi::DataViewMode) { - setObjectName("view_data_mode"); - setToolTip(xi18n("Switch to data view")); - setWhatsThis(xi18n("Switches to data view.")); - } else if (mode == Kexi::DesignViewMode) { + if (mode == Kexi::DesignViewMode) { setObjectName("view_design_mode"); - setToolTip(xi18n("Switch to design view")); - setWhatsThis(xi18n("Switches to design view.")); + setToolTip(xi18n("Switch to visual design view")); + setWhatsThis(xi18n("Switches to visual design view.")); } else if (mode == Kexi::TextViewMode) { setObjectName("view_text_mode"); setToolTip(xi18n("Switch to text view")); setWhatsThis(xi18n("Switches to text view.")); } else { - qWarning() << "KexiToggleViewModeAction: invalid mode " << mode; + qWarning() << "KexiToggleViewModeAction: invalid mode" << mode; } } }; @@ -100,11 +98,7 @@ QAction *a = toggleViewModeActions.value(mode); if (a) { slotSwitchToViewModeInternalEnabled = false; - toggleViewModeActions.value(mode)->blockSignals(true); - toggleViewModeButtons.value(mode)->blockSignals(true); toggleViewModeButtons.value(mode)->setChecked(viewMode == mode); - toggleViewModeActions.value(mode)->blockSignals(false); - toggleViewModeButtons.value(mode)->blockSignals(false); slotSwitchToViewModeInternalEnabled = true; } } @@ -118,11 +112,10 @@ return 0; } KexiSmallToolButton* menuButton = new KexiSmallToolButton( - QIcon(), - window->part()->info()->name() + " ", - topBarHWidget); - menuButton->setToolTip(xi18n("Menu for the current window")); - menuButton->setWhatsThis(xi18n("Shows menu for the current window.")); + koIcon("application-menu"), topBarHWidget); + menuButton->setToolTip(xi18nc("@info:tooltip", "Menu for %1") + .arg(window->partItem()->captionOrName())); + menuButton->setWhatsThis(xi18n("Shows context menu for the current view.")); menuButton->setPopupMode(QToolButton::InstantPopup); topBarLyr->insertWidget(0, menuButton); @@ -138,13 +131,13 @@ if (!window->supportsViewMode(mode)) { return 0; } - QAction *a = new KexiToggleViewModeAction(mode, q); + QAction *a = new KexiToggleViewModeAction(q->part()->info()->id(), mode, q); toggleViewModeActions.insert(mode, a); KexiGroupButton *btn = new KexiGroupButton(pos, parent); toggleViewModeButtons.insert(mode, btn); connect(btn, SIGNAL(toggled(bool)), q, slot); - btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + btn->setToolButtonStyle(Qt::ToolButtonTextOnly); btn->setText(text); btn->setIcon(a->icon()); QFont f(q->font()); @@ -207,6 +200,8 @@ //! Needed because there is another slotSwitchToViewModeInternal() calls if d->window->switchToViewModeInternal(mode) //! did not succeed, so for the second time we block this call. tristate recentResultOfSwitchToViewModeInternal; + + QString textToDisplayForNullSet; private: QMenu* m_mainMenu; }; @@ -238,51 +233,52 @@ d->mainLyr->setContentsMargins(0, 0, 0, 0); if (qobject_cast(parentWidget())) { - d->topBarHWidget = new QWidget(this); - d->topBarHWidget->setFont(KexiUtils::smallestReadableFont()); - d->mainLyr->addWidget(d->topBarHWidget); - QHBoxLayout *topBarHLyr = new QHBoxLayout(d->topBarHWidget); //needed unless KexiFlowLayout properly handles contents margins - topBarHLyr->setContentsMargins(0, 0, 0, 0); - topBarHLyr->addSpacing(KexiUtils::spacingHint() / 2); - d->topBarLyr = new KexiFlowLayout(topBarHLyr, 0, 2); - - const bool userMode = KexiMainWindowIface::global()->userMode(); - - if (userMode - || d->window->supportedViewModes() == Kexi::DataViewMode - || d->window->supportedViewModes() == Kexi::DesignViewMode - || d->window->supportedViewModes() == Kexi::TextViewMode) - { - // nothing to do: only single view mode supported - } - else { - createViewModeToggleButtons(); - } - - (void)d->mainMenu(); - - if (d->viewMode == Kexi::DesignViewMode || d->viewMode == Kexi::TextViewMode) { - QAction *a = sharedAction("project_save"); - d->saveDesignButton = new KexiSmallToolButton(a, d->topBarHWidget); - d->saveDesignButton->setText(xi18n("Save")); - d->saveDesignButton->setToolTip(xi18n("Save current design")); - d->saveDesignButton->setWhatsThis(xi18n("Saves changes made to the current design.")); - d->topBarLyr->addWidget(d->saveDesignButton); - - a = sharedAction("project_saveas"); - d->mainMenu()->addAction(a); - } - else { - d->saveDesignButton = 0; - } + createTopBar(); } else { - // no toolbar d->saveDesignButton = 0; d->topBarHWidget = 0; d->topBarLyr = 0; } } +void KexiView::createTopBar() +{ + d->topBarHWidget = new QWidget(this); + d->topBarHWidget->setFont(KexiUtils::smallestReadableFont()); + d->mainLyr->addWidget(d->topBarHWidget); + QHBoxLayout *topBarHLyr = new QHBoxLayout(d->topBarHWidget); //needed unless KexiFlowLayout properly handles contents margins + topBarHLyr->setContentsMargins(0, 0, 0, 0); + topBarHLyr->addSpacing(KexiUtils::spacingHint() / 2); + d->topBarLyr = new KexiFlowLayout(topBarHLyr, 0, 0); + + bool toggleModePossible = viewMode() != Kexi::DataViewMode && !KexiMainWindowIface::global()->userMode(); + if ( !(d->window->supportedViewModes() & Kexi::DesignViewMode) + || !(d->window->supportedViewModes() & Kexi::TextViewMode)) + { + toggleModePossible = false; + } + if (toggleModePossible) { + createViewModeToggleButtons(); + } + + (void)d->mainMenu(); + + if (d->viewMode == Kexi::DesignViewMode || d->viewMode == Kexi::TextViewMode) { + QAction *a = sharedAction("project_save"); + d->saveDesignButton = new KexiSmallToolButton(a, d->topBarHWidget); + d->saveDesignButton->setToolButtonStyle(Qt::ToolButtonIconOnly); + d->saveDesignButton->setToolTip(xi18n("Save current design")); + d->saveDesignButton->setWhatsThis(xi18n("Saves changes made to the current design.")); + d->topBarLyr->addWidget(d->saveDesignButton); + + a = sharedAction("project_saveas"); + d->mainMenu()->addAction(a); + } + else { + d->saveDesignButton = 0; + } +} + KexiView::~KexiView() { delete d; @@ -504,8 +500,8 @@ emit focus(true); } if (e->type() == QEvent::FocusOut) { -// qDebug() << focusWidget()->className() << " " << focusWidget()->name(); -// qDebug() << o->className() << " " << o->name(); +// qDebug() << focusWidget()->className() << focusWidget()->name(); +// qDebug() << o->className() << o->name(); KexiView *v = KDbUtils::findParent(o); if (v) { while (v->d->parentView) @@ -533,6 +529,8 @@ } d->viewWidget = w; if (d->viewWidget) { + QFrame *frameWidget = qobject_cast(d->viewWidget); + KexiStyle::setupFrame(frameWidget); d->viewWidget->setParent(this); d->mainLyr->addWidget(d->viewWidget, 1); d->viewWidget->installEventFilter(this); @@ -558,7 +556,7 @@ void KexiView::setFocus() { if (!d->lastFocusedChildBeforeFocusOut.isNull()) { -// qDebug() << "FOCUS: " << d->lastFocusedChildBeforeFocusOut->className() << " " << d->lastFocusedChildBeforeFocusOut->name(); +// qDebug() << "FOCUS:" << d->lastFocusedChildBeforeFocusOut->className() << d->lastFocusedChildBeforeFocusOut->name(); QWidget *w = d->lastFocusedChildBeforeFocusOut; d->lastFocusedChildBeforeFocusOut = 0; w->setFocus(); @@ -649,34 +647,23 @@ d->topBarLyr->addWidget(btnCont); d->topBarLyr->addSpacing(KexiUtils::spacingHint()); - d->addViewButton(KexiGroupButton::GroupLeft, Kexi::DataViewMode, btnCont, - SLOT(slotSwitchToDataViewModeInternal(bool)), xi18n("Data"), btnLyr); - d->addViewButton(d->window->supportsViewMode(Kexi::TextViewMode) ? KexiGroupButton::GroupCenter - : KexiGroupButton::GroupRight, - Kexi::DesignViewMode, btnCont, - SLOT(slotSwitchToDesignViewModeInternal(bool)), xi18n("Design"), btnLyr); + d->addViewButton(KexiGroupButton::GroupLeft, Kexi::DesignViewMode, btnCont, + SLOT(slotSwitchToDesignViewModeInternal(bool)), + xi18nc("@action:button Visual Design", "Visual"), btnLyr); KexiGroupButton *btn = d->addViewButton(KexiGroupButton::GroupRight, Kexi::TextViewMode, btnCont, SLOT(slotSwitchToTextViewModeInternal(bool)), QString(), btnLyr); if (btn) { - QString customTextViewModeCaption(d->window->internalPropertyValue("textViewModeCaption").toString()); - if (customTextViewModeCaption.isEmpty()) { - QAction *a = d->toggleViewModeActions.value(Kexi::TextViewMode); - btn->setText(a->text()); - } - else { - btn->setText(customTextViewModeCaption); - } + QAction *a = d->toggleViewModeActions.value(Kexi::TextViewMode); + const QString customTextViewModeCaption(d->window->internalPropertyValue("textViewModeCaption").toString()); + btn->setText(customTextViewModeCaption.isEmpty() ? a->text() : customTextViewModeCaption); + const QString customTextViewModeToolTip(d->window->internalPropertyValue("textViewModeToolTip").toString()); + btn->setToolTip(customTextViewModeToolTip.isEmpty() ? a->toolTip() : customTextViewModeToolTip); } toggleViewModeButtonBack(); } -void KexiView::slotSwitchToDataViewModeInternal(bool) -{ - slotSwitchToViewModeInternal(Kexi::DataViewMode); -} - void KexiView::slotSwitchToDesignViewModeInternal(bool) { slotSwitchToViewModeInternal(Kexi::DesignViewMode); @@ -709,20 +696,20 @@ { if (!d->topBarLyr) return; - if (!d->viewActions.isEmpty() && d->saveDesignButton) { - d->topBarLyr->addWidget(new KexiToolBarSeparator(d->topBarHWidget)); - } foreach(QAction* action, d->viewActions) { if (action->isSeparator()) { d->topBarLyr->addWidget(new KexiToolBarSeparator(d->topBarHWidget)); } else { KexiSmallToolButton *btn = new KexiSmallToolButton(action, d->topBarHWidget); btn->setText(action->text()); btn->setToolTip(action->toolTip()); btn->setWhatsThis(action->whatsThis()); + //! @todo Local toolbar actions are hardcoded as icons-only, maybe add view option? +#if 0 if (action->dynamicPropertyNames().contains("iconOnly") && action->property("iconOnly").toBool() ) { - btn->setToolButtonStyle(Qt::ToolButtonIconOnly); - } +#endif + btn->setToolButtonStyle(Qt::ToolButtonIconOnly); + //} d->topBarLyr->addWidget(btn); } } @@ -766,4 +753,14 @@ return QList(); } +QString KexiView::textToDisplayForNullSet() const +{ + return d->textToDisplayForNullSet; +} + +void KexiView::setTextToDisplayForNullSet(const QString& text) +{ + d->textToDisplayForNullSet = text; +} + #include "KexiView.moc" diff --git a/src/core/KexiWindow.cpp b/src/core/KexiWindow.cpp --- a/src/core/KexiWindow.cpp +++ b/src/core/KexiWindow.cpp @@ -170,7 +170,7 @@ void KexiWindow::createSubwidgets() { d->mainLyr = new QVBoxLayout(this); - d->mainLyr->setContentsMargins(0, KexiUtils::marginHint() / 2, 0, 0); + d->mainLyr->setContentsMargins(0, 0, 0, 0); d->stack = new QStackedWidget(this); d->mainLyr->addWidget(d->stack); } @@ -505,8 +505,8 @@ KexiUtils::removeWaitCursor(); if (!newView) { //js TODO error? - qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " - << d->currentViewMode << " restored."; + qWarning() << "Switching to mode" << newViewMode << "failed. Previous mode " + << d->currentViewMode << "restored."; return false; } d->creatingViewsMode = Kexi::NoViewMode; @@ -529,8 +529,8 @@ if (!res) { removeView(newViewMode); delete newView; - qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " - << d->currentViewMode << " restored."; + qWarning() << "Switching to mode" << newViewMode << "failed. Previous mode" + << d->currentViewMode << "restored."; return false; } d->currentViewMode = newViewMode; @@ -556,8 +556,8 @@ if (!res) { removeView(newViewMode); delete newView; - qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " - << prevViewMode << " restored."; + qWarning() << "Switching to mode" << newViewMode << "failed. Previous mode" + << prevViewMode << "restored."; const Kexi::ObjectStatus status(*this); setStatus(KexiMainWindowIface::global()->project()->dbConnection(), xi18n("Switching to other view failed (%1).", Kexi::nameForViewMode(newViewMode)), ""); @@ -834,7 +834,7 @@ void KexiWindow::activate() { KexiView *v = selectedView(); - //qDebug() << "focusWidget(): " << focusWidget()->name(); + //qDebug() << "focusWidget():" << focusWidget()->name(); if (!KDbUtils::hasParent(v, KexiMainWindowIface::global()->focusWidget())) { //ah, focused widget is not in this view, move focus: if (v) diff --git a/src/core/kexi.h b/src/core/kexi.h --- a/src/core/kexi.h +++ b/src/core/kexi.h @@ -54,7 +54,7 @@ KEXICORE_EXPORT QString nameForViewMode(ViewMode mode, bool withAmpersand = false); /*! @return icon name of view mode @a mode. */ -KEXICORE_EXPORT QString iconNameForViewMode(ViewMode mode); +KEXICORE_EXPORT QString iconNameForViewMode(const QString& pluginId, ViewMode mode); //! A set of known connections KEXICORE_EXPORT KexiDBConnectionSet& connset(); diff --git a/src/core/kexi.cpp b/src/core/kexi.cpp --- a/src/core/kexi.cpp +++ b/src/core/kexi.cpp @@ -20,6 +20,7 @@ #include "kexi.h" #include "KexiRecentProjects.h" #include "KexiMainWindowIface.h" +#include "kexipart.h" #include "kexipartmanager.h" #include @@ -150,15 +151,19 @@ } //-------------------------------------------------------------------------------- -QString Kexi::iconNameForViewMode(ViewMode mode) -{ - const char *const id = - (mode == DataViewMode) ? KexiIconNameCStr("data-view") : - (mode == DesignViewMode) ? KexiIconNameCStr("design-view") : - (mode == TextViewMode) ? KexiIconNameCStr("sql-view"): - 0; - - return QLatin1String(id); +QString Kexi::iconNameForViewMode(const QString& pluginId, ViewMode mode) +{ + switch(mode) { + case DataViewMode: return KexiIconName("mode-selector-edit"); + case DesignViewMode: return KexiIconName("mode-selector-design"); + case TextViewMode: { + QString iconName; + KexiPart::getTextViewAction(pluginId, 0, &iconName); + return iconName; + } + default: break; + } + return QString(); } //-------------------------------------------------------------------------------- diff --git a/src/core/kexiblobbuffer.cpp b/src/core/kexiblobbuffer.cpp --- a/src/core/kexiblobbuffer.cpp +++ b/src/core/kexiblobbuffer.cpp @@ -108,7 +108,7 @@ if (!m_item) return; if (m_item->stored) { - qWarning() << "object for id=" << id << " is aleady stored"; + qWarning() << "object for id=" << id << "is aleady stored"; return; } diff --git a/src/core/kexidataiteminterface.cpp b/src/core/kexidataiteminterface.cpp --- a/src/core/kexidataiteminterface.cpp +++ b/src/core/kexidataiteminterface.cpp @@ -155,7 +155,7 @@ bool KexiDataItemInterface::valueChanged() { - //qDebug() << d->origValue.toString() << " ? " << value().toString(); + //qDebug() << d->origValue.toString() << "?" << value().toString(); return d->origValue != value(); } diff --git a/src/core/kexipart.h b/src/core/kexipart.h --- a/src/core/kexipart.h +++ b/src/core/kexipart.h @@ -71,6 +71,7 @@ so supported internal properties affecting its behaviour are: - newObjectsAreDirty: True if newly created, unsaved objects are dirty. False by default. - textViewModeCaption: custum i18n'd action text replacing standard "Text View" text. + - textViewModeToolTip: custum i18n'd action tool tip replacing standard "Switch to text view" text. Used in for query's "SQL View". In general: a whole set of i18n'd action names, initialised on KexiPart::Part subclass ctor. The names are useful because the same action can have other name for each part, @@ -277,6 +278,11 @@ otherwise it will be in a form of "name", e.g. "Employees". */ KEXICORE_EXPORT QString fullCaptionForItem(KexiPart::Item *item, KexiPart::Part *part); +/*! \return i18n'd actionText and iconName for "Open in text view" action specific for @a pluginId. + Currently it the only special is for "org.kexi-project.query". + The default is "Design in Text View" and no icon. */ +KEXICORE_EXPORT void getTextViewAction(const QString& pluginId, QString *actionText, QString *iconName); + } // namespace KexiPart #endif diff --git a/src/core/kexipart.cpp b/src/core/kexipart.cpp --- a/src/core/kexipart.cpp +++ b/src/core/kexipart.cpp @@ -29,6 +29,7 @@ #include "KexiMainWindowIface.h" #include "kexi.h" #include +#include #include @@ -180,7 +181,7 @@ { GUIClient *instanceGuiClient = d->instanceGuiClients.value((int)mode); if (!instanceGuiClient) { - qWarning() << "no gui client for mode " << mode << "!"; + qWarning() << "no gui client for mode" << mode << "!"; return 0; } return KexiMainWindowIface::global()->createSharedAction(text, pix_name, cut, name, @@ -313,7 +314,7 @@ d->status = window->status(); window->close(); delete window; - qWarning() << "!window, switching to view mode failed, " << + qWarning() << "!window, switching to view mode failed," << Kexi::nameForViewMode(viewMode); return 0; } @@ -439,3 +440,23 @@ return item->name() + " : " + part->info()->name(); return item->name(); } + +KEXICORE_EXPORT void KexiPart::getTextViewAction(const QString& pluginId, QString *actionText, + QString *iconName) +{ + if (pluginId == QLatin1String("org.kexi-project.query")) { + if (actionText) { + *actionText = xi18n("Design in SQL View"); + } + if (iconName) { + *iconName = KexiIconName("mode-selector-sql"); + } + } else { + if (actionText) { + *actionText = xi18n("Design in Text View"); + } + if (iconName) { + iconName->clear(); + } + } +} diff --git a/src/core/kexipartbase.h b/src/core/kexipartbase.h --- a/src/core/kexipartbase.h +++ b/src/core/kexipartbase.h @@ -1,6 +1,6 @@ /* 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 @@ -27,8 +27,8 @@ #include #include -class QTabWidget; class KexiWindow; +class KexiPropertyPaneWidget; namespace KexiPart { @@ -76,13 +76,13 @@ KexiWindow *window) const; /*! @internal - This method can be reimplemented to setup additional tabs - in the property editor panel. 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 previous one. + type (mime type) of its contents differs from the previous one. For example, if a user switched from Table Designer to Form Designer, - additional tab containing Form Designer's object tree should be shown. */ - virtual void setupCustomPropertyPanelTabs(QTabWidget *tab); + additional item containing Form Designer's object tree should be added. */ + virtual void setupPropertyPane(KexiPropertyPaneWidget *pane); protected: /*! diff --git a/src/core/kexipartbase.cpp b/src/core/kexipartbase.cpp --- a/src/core/kexipartbase.cpp +++ b/src/core/kexipartbase.cpp @@ -68,7 +68,8 @@ return kxi18nc("@info", englishMessage.toLatin1()); } -void PartBase::setupCustomPropertyPanelTabs(QTabWidget *) +void PartBase::setupPropertyPane(KexiPropertyPaneWidget *pane) { + Q_UNUSED(pane) } diff --git a/src/core/kexipartinfo.h b/src/core/kexipartinfo.h --- a/src/core/kexipartinfo.h +++ b/src/core/kexipartinfo.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2003-2015 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 @@ -27,6 +27,7 @@ #include "KexiPluginMetaData.h" class QAction; +class QIcon; class KexiProject; class KexiWindow; @@ -57,6 +58,17 @@ */ QString groupName() const; + /** + * @return the icon for this plugin + * Use this method instead of iconName() to get proper support for both light and dark backgrounds. + */ + QIcon icon() const; + + /** + * @return the icon for this plugin ofr dark backgrounds + */ + QIcon darkIcon() const; + /** * @return an untranslated group name e.g. "Tables" or "Queries". * diff --git a/src/core/kexipartinfo.cpp b/src/core/kexipartinfo.cpp --- a/src/core/kexipartinfo.cpp +++ b/src/core/kexipartinfo.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2003-2015 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 @@ -21,6 +21,8 @@ #include "kexipartinfo_p.h" #include "kexipartmanager.h" #include "KexiMainWindowIface.h" +#include +#include #include @@ -100,7 +102,7 @@ //------------------------------ KexiNewObjectAction::KexiNewObjectAction(Info* info, QObject *parent) - : QAction(QIcon::fromTheme(info->iconName()), info->name() + "...", parent) + : QAction(info->icon(), info->name() + "...", parent) , m_info(info) { setObjectName(nameForCreateAction(*m_info)); @@ -151,6 +153,19 @@ return d->groupName; } +QIcon Info::icon() const +{ + return QIcon::fromTheme(iconName()); +} + +QIcon Info::darkIcon() const +{ + if (d->icon.isNull()) { + d->icon = KexiStyle::darkIcon(iconName()); + } + return d->icon; +} + QString Info::untranslatedGroupName() const { return d->untranslatedGroupName; diff --git a/src/core/kexipartinfo_p.h b/src/core/kexipartinfo_p.h --- a/src/core/kexipartinfo_p.h +++ b/src/core/kexipartinfo_p.h @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch - Copyright (C) 2003-2015 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 @@ -39,6 +39,7 @@ QString groupName; QString untranslatedGroupName; QString typeName; + QIcon icon; /*! Supported modes for dialogs created by this part. @see KexiPart::Info::supportedViewModes() */ diff --git a/src/core/kexiproject.cpp b/src/core/kexiproject.cpp --- a/src/core/kexiproject.cpp +++ b/src/core/kexiproject.cpp @@ -330,7 +330,7 @@ return cancelled; } qWarning() << "!d->connection->useDatabase() " - << d->data->databaseName() << " " << d->data->connectionData()->driverId(); + << d->data->databaseName() << d->data->connectionData()->driverId(); if (d->connection->result().code() == ERR_NO_DB_PROPERTY) { // @@ -677,13 +677,13 @@ d->connection = driver->createConnection(*d->data->connectionData(), connectionOptions); if (!d->connection) { m_result = driver->result(); - qWarning() << "error create connection: " << m_result; + qWarning() << "error create connection:" << m_result; return false; } if (!d->connection->connect()) { m_result = d->connection->result(); - qWarning() << "error connecting: " << m_result; + qWarning() << "error connecting:" << m_result; delete d->connection; //this will also clear connection for BLOB buffer d->connection = 0; return false; @@ -946,7 +946,7 @@ KDbMessageTitleSetter et(this); KexiPart::Part *part = Kexi::partManager().partForPluginId(item.pluginId()); if (!part) { - qWarning() << "!part: " << item.pluginId(); + qWarning() << "!part:" << item.pluginId(); m_result = Kexi::partManager().result(); } return part; @@ -1318,14 +1318,14 @@ return false; } QScopedPointer fl(ts->subList("p_id", "p_name", "p_mime", "p_url")); - //qDebug() << "fieldlist: " << (fl ? *fl : QString()); + //qDebug() << "fieldlist:" << (fl ? *fl : QString()); if (!fl) return false; //qDebug() << info.ptr()->untranslatedGenericName(); // QStringList sl = part()->info()->ptr()->propertyNames(); // for (QStringList::ConstIterator it=sl.constBegin();it!=sl.constEnd();++it) - //qDebug() << *it << " " << part()->info()->ptr()->property(*it).toString(); + //qDebug() << *it << part()->info()->ptr()->property(*it).toString(); if (!d->connection->insertRecord( fl.data(), QVariant(typeId), @@ -1339,7 +1339,7 @@ //qDebug() << "insert success!"; d->savePluginId(info.id(), typeId); - //qDebug() << "new id is: " << p_id; + //qDebug() << "new id is:" << p_id; return true; } diff --git a/src/core/kexisharedactionhost.cpp b/src/core/kexisharedactionhost.cpp --- a/src/core/kexisharedactionhost.cpp +++ b/src/core/kexisharedactionhost.cpp @@ -163,7 +163,7 @@ } } a->setEnabled(avail); - //qDebug() << "Action " << a->name() << (avail ? " enabled." : " disabled."); + //qDebug() << "Action" << a->name() << (avail ? "enabled." : "disabled."); } } diff --git a/src/formeditor/CMakeLists.txt b/src/formeditor/CMakeLists.txt --- a/src/formeditor/CMakeLists.txt +++ b/src/formeditor/CMakeLists.txt @@ -1,8 +1,14 @@ -include_directories(${CMAKE_SOURCE_DIR}/src/widget ${CMAKE_SOURCE_DIR}/src/widget/utils -${CMAKE_SOURCE_DIR}/src/widget/tableview ${CMAKE_SOURCE_DIR}/src/core) - add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44010) +include_directories( + ${CMAKE_SOURCE_DIR}/src/widget + ${CMAKE_SOURCE_DIR}/src/widget/utils + ${CMAKE_SOURCE_DIR}/src/widget/tableview + ${CMAKE_SOURCE_DIR}/src/widget/properties + ${CMAKE_SOURCE_DIR}/src/core + ${CMAKE_SOURCE_DIR}/src/kexiutils/style +) + # enable to add signal/slot connections # set(KFD_SIGSLOTS true) diff --git a/src/formeditor/WidgetTreeWidget.cpp b/src/formeditor/WidgetTreeWidget.cpp --- a/src/formeditor/WidgetTreeWidget.cpp +++ b/src/formeditor/WidgetTreeWidget.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "objecttree.h" #include "form.h" @@ -219,6 +220,7 @@ WidgetTreeWidget::WidgetTreeWidget(QWidget *parent, Options options) : QTreeWidget(parent), d(new Private(options)) { + KexiStyle::setupFrame(this); setRootIsDecorated(false); setHeaderLabels(QStringList() << xi18n("Widget name") << xi18nc("Widget's type", "Type")); installEventFilter(this); diff --git a/src/formeditor/commands.cpp b/src/formeditor/commands.cpp --- a/src/formeditor/commands.cpp +++ b/src/formeditor/commands.cpp @@ -113,6 +113,14 @@ { } + bool thisSingleWidgetSelected() const + { + const QWidget *selected = form->selectedWidget(); + return selected + && oldValues.count() == 1 + && oldValues.contains(selected->objectName().toLatin1()); + } + Form *form; QVariant value; QHash oldValues; //!< (widget_name -> value) hash @@ -195,16 +203,8 @@ void PropertyCommand::execute() { - QWidget *selected = d->form->selectedWidget(); - bool reSelectWidgets = true; - if (selected - && d->oldValues.count() == 1 - && d->oldValues.contains(selected->objectName().toLatin1()) ) - { - // do not reselect widget; this e.g. avoids removing resize handles - reSelectWidgets = false; - } - + // do not reselect widget; this e.g. avoids removing resize handles + const bool reSelectWidgets = !d->thisSingleWidgetSelected(); if (reSelectWidgets) { d->form->selectFormWidget(); } @@ -235,22 +235,28 @@ void PropertyCommand::undo() { - d->form->selectFormWidget(); + // do not reselect widget; this e.g. avoids removing resize handles + const bool reSelectWidgets = !d->thisSingleWidgetSelected(); + if (reSelectWidgets) { + d->form->selectFormWidget(); + } d->form->setUndoing(true); QHash::ConstIterator endIt = d->oldValues.constEnd(); for (QHash::ConstIterator it = d->oldValues.constBegin(); it != endIt; ++it) { ObjectTreeItem* item = d->form->objectTree()->lookup(it.key()); if (!item) continue; //better this than a crash QWidget *widget = item->widget(); - d->form->selectWidget(widget, Form::AddToPreviousSelection | Form::LastSelection | Form::Raise); + if (reSelectWidgets) { + d->form->selectWidget(widget, Form::AddToPreviousSelection | Form::LastSelection | Form::Raise); + } WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(widget); QWidget *subWidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : widget; if (subWidget && -1 != subWidget->metaObject()->indexOfProperty(d->propertyName)) { - qDebug() << "OLD" << d->propertyName << subWidget->property(d->propertyName); - qDebug() << "NEW" << d->propertyName << it.value(); + //qDebug() << "OLD" << d->propertyName << subWidget->property(d->propertyName); + //qDebug() << "NEW" << d->propertyName << it.value(); subWidget->setProperty(d->propertyName, it.value()); } } @@ -1035,7 +1041,7 @@ w->metaObject()->className(), w, item->container() ? item->container() : container); } //! @todo update widget's width for entered text's metrics - //qDebug() << "widget added " << this; + //qDebug() << "widget added" << this; } void InsertWidgetCommand::undo() @@ -1151,7 +1157,7 @@ if (!parsed) { qWarning() << errMsg; - qWarning() << "line: " << errLine << "col: " << errCol; + qWarning() << "line:" << errLine << "col:" << errCol; return; } @@ -1315,7 +1321,7 @@ int rw = wi.text().toInt(); int rh = h.text().toInt(); QRect r(rx + p.x(), ry + p.y(), rw, rh); - //qDebug() << "Moving widget by " << p << "from " << rx << ry << "to" << r.topLeft(); + //qDebug() << "Moving widget by" << p << "from" << rx << ry << "to" << r.topLeft(); QWidget *w = d->form->widget()->childAt(r.x() + 6, r.y() + 6); diff --git a/src/formeditor/container.cpp b/src/formeditor/container.cpp --- a/src/formeditor/container.cpp +++ b/src/formeditor/container.cpp @@ -976,7 +976,7 @@ end = w->geometry().bottom(); } } - //qDebug() << "the new grid will have n rows: n == " << rows.size(); + //qDebug() << "the new grid will have n rows: n ==" << rows.size(); end = -10000; same = false; @@ -1002,7 +1002,7 @@ end = w->geometry().right(); } } - //qDebug() << "the new grid will have n columns: n == " << cols.size(); + //qDebug() << "the new grid will have n columns: n ==" << cols.size(); // We create the layout .. QGridLayout *layout = 0; @@ -1041,8 +1041,8 @@ } i++; } - //qDebug() << "the widget " << w->objectName() << " will be in the row " << wrow << - //" and will go to the row " << endrow; + //qDebug() << "the widget" << w->objectName() << "will be in the row" << wrow << + //"and will go to the row" << endrow; // .. and column(s) i = 0; @@ -1064,8 +1064,8 @@ } i++; } - //qDebug() << "the widget " << w->objectName() << " will be in the col " << wcol << - // " and will go to the col " << endcol; + //qDebug() << "the widget" << w->objectName() << "will be in the col" << wcol << + // "and will go to the col" << endcol; ObjectTreeItem *item = d->form->objectTree()->lookup(w->objectName()); if (item) { diff --git a/src/formeditor/factories/KexiStandardFormWidgetsFactory.h b/src/formeditor/factories/KexiStandardFormWidgetsFactory.h deleted file mode 100644 --- a/src/formeditor/factories/KexiStandardFormWidgetsFactory.h +++ /dev/null @@ -1,93 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2003 by Lucijan Busch - Copyright (C) 2004 Cedric Pasteur - Copyright (C) 2009 Jarosław Staniek - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. -*/ - -#ifndef KEXISTANDARDFORMWIDGETSFACTORY_H -#define KEXISTANDARDFORMWIDGETSFACTORY_H - -#include -#include -#include -#include - -#include "widgetfactory.h" -#include "container.h" - -class QTreeWidgetItem; -class QTreeWidget; - -class KPropertySet; - -//! Factory for all basic widgets, including Spring (not containers) -class KexiStandardFormWidgetsFactory : public KFormDesigner::WidgetFactory -{ - Q_OBJECT - -public: - KexiStandardFormWidgetsFactory(QObject *parent, const QVariantList &args); - ~KexiStandardFormWidgetsFactory(); - - virtual QWidget* createWidget(const QByteArray &classname, QWidget *parent, const char *name, - KFormDesigner::Container *container, - CreateWidgetOptions options = DefaultOptions); - - virtual bool createMenuActions(const QByteArray &classname, QWidget *w, - QMenu *menu, KFormDesigner::Container *container); - virtual bool startInlineEditing(InlineEditorCreationArguments& args); - virtual bool previewWidget(const QByteArray &classname, QWidget *widget, - KFormDesigner::Container *container); - virtual bool clearWidgetContent(const QByteArray &classname, QWidget *w); - - virtual bool saveSpecialProperty(const QByteArray &classname, - const QString &name, const QVariant &value, QWidget *w, - QDomElement &parentNode, QDomDocument &parent); - virtual bool readSpecialProperty(const QByteArray &classname, QDomElement &node, - QWidget *w, KFormDesigner::ObjectTreeItem *item); - - virtual void setPropertyOptions(KPropertySet& set, const KFormDesigner::WidgetInfo& info, QWidget *w); - - //! Moved into public for EditRichTextAction - bool editRichText(QWidget *w, QString &text) const { return KFormDesigner::WidgetFactory::editRichText(w, text); } - - //! Moved into public for EditRichTextAction - void changeProperty(KFormDesigner::Form *form, QWidget *widget, const char *name, - const QVariant &value) { KFormDesigner::WidgetFactory::changeProperty(form, widget, name, value); } - -public Q_SLOTS: -#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT - void editListContents(); -#endif -protected Q_SLOTS: - void reorderTabs(int oldpos, int newpos); - -protected: - KFormDesigner::ObjectTreeItem* selectableItem(KFormDesigner::ObjectTreeItem* item); - virtual bool isPropertyVisibleInternal(const QByteArray &classname, QWidget *w, - const QByteArray &property, bool isTopLevel); - virtual bool changeInlineText(KFormDesigner::Form *form, QWidget *widget, - const QString &text, QString &oldText); - virtual void resizeEditor(QWidget *editor, QWidget *widget, const QByteArray &classname); -#ifdef KEXI_LIST_FORM_WIDGET_SUPPORT - void saveTreeItem(QTreeWidgetItem *item, QDomNode &parentNode, QDomDocument &domDoc); - void readTreeItem(QDomElement &node, QTreeWidgetItem *parent, QTreeWidget *treewidget); -#endif -}; - -#endif diff --git a/src/formeditor/form.h b/src/formeditor/form.h --- a/src/formeditor/form.h +++ b/src/formeditor/form.h @@ -589,6 +589,10 @@ void widgetDestroyed(); + //! Called as delayed slot when invalid name is entered. + //! @see checkNameValidity() + void checkNameValidityForSelection(); + Q_SIGNALS: /*! This signal is emitted by selectWidget() when user selects a new widget, to update both the Property Editor and the Object Tree View. @@ -667,9 +671,14 @@ void disableWidgetActions(); + enum CheckValidityMode { + CheckValidityOnly, + CheckValidityShowMessages + }; + /*! Checks if the name entered by user is valid, ie that it is a valid identifier, and that there is no name conflict. */ - bool isNameValid(const QString &name) const; + bool checkNameValidity(const QString &name, CheckValidityMode mode) const; void addWidget(QWidget *w); diff --git a/src/formeditor/form.cpp b/src/formeditor/form.cpp --- a/src/formeditor/form.cpp +++ b/src/formeditor/form.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -55,6 +56,7 @@ #include #include #include +#include using namespace KFormDesigner; @@ -273,8 +275,8 @@ void Form::createToplevel(QWidget *container, FormWidget *formWidget, const QByteArray &) { - //qDebug() << "container= " << (container ? container->objectName() : "") - // << " formWidget=" << formWidget; + //qDebug() << "container=" << (container ? container->objectName() : "") + // << "formWidget=" << formWidget; setFormWidget(formWidget); d->toplevel = new Container(0, container, this); @@ -396,8 +398,15 @@ void Form::selectWidget(QWidget *w, WidgetSelectionFlags flags) { - if (!d->selectWidgetEnabled) + if (!d->selectWidgetEnabled) { return; + } + if (selectedWidget() && !checkNameValidity(d->propertySet.propertyValue("objectName").toString(), CheckValidityOnly)) { + // current selection has invalid objectName: don't allow to switch so user is able to fix it! + //qDebug() << "disallow!"; + return; + } + d->selectWidgetEnabled = false; selectWidgetInternal(w, flags); d->selectWidgetEnabled = true; @@ -863,7 +872,7 @@ return; if (!containers.contains(item->container())) { //qDebug() << item->container()->objectTree()->className() - // << " " << item->container()->objectTree()->name(); + // << item->container()->objectTree()->name(); containers.insert(item->container()); } foreach (ObjectTreeItem *child, *item->children()) { @@ -883,7 +892,7 @@ foreach (ObjectTreeItem *item, d->tabstops) { if (item->widget()) { - //qDebug() << "Widget to sort: " << item->widget(); + //qDebug() << "Widget to sort:" << item->widget(); list.append(item->widget()); } } @@ -931,7 +940,7 @@ foreach (QWidget *w, hlist) { ObjectTreeItem *tree = d->topTree->lookup(w->objectName()); if (tree) { - //qDebug() << "adding " << tree->name(); + //qDebug() << "adding" << tree->name(); d->tabstops.append(tree); } } @@ -1218,8 +1227,11 @@ qWarning() << "changing objectName property only allowed for single selection"; return; } - if (!isNameValid(value.toString())) + if (!checkNameValidity(value.toString(), CheckValidityOnly)) { + // Tricky: revert later so if there's selectWidget() before, we can cancel selectWidget() + QTimer::singleShot(500, this, &Form::checkNameValidityForSelection); return; + } } else if (property == "paletteBackgroundPixmap") { // a widget with a background pixmap should have its own origin @@ -1305,41 +1317,53 @@ } } -bool Form::isNameValid(const QString &name) const +bool Form::checkNameValidity(const QString &name, CheckValidityMode mode) const { if (d->selected.isEmpty()) return false; //! @todo add to the undo buffer QWidget *w = d->selected.first(); - //also update widget's name in QObject member + + if (name.isEmpty()) { + if (mode == CheckValidityShowMessages) { + KMessageBox::sorry(widget(), xi18n("Widget name could not be empty.")); + } + return false; + } if (!KDb::isIdentifier(name)) { - KMessageBox::sorry(widget(), - xi18nc("@info", - "Could not rename widget %1 to " - "%2 because " - "%3 is not a valid name (identifier) for a widget.", - w->objectName(), name, name)); - d->slotPropertyChangedEnabled = false; - d->propertySet["objectName"].resetValue(); - d->slotPropertyChangedEnabled = true; + if (mode == CheckValidityShowMessages) { + KMessageBox::sorry(widget(), + xi18nc("@info", + "Could not rename widget %1 to " + "%2 because " + "%3 is not a valid name (identifier) for a widget.", + w->objectName(), name, name)); + } return false; } - - if (objectTree()->lookup(name)) { - KMessageBox::sorry(widget(), - xi18nc("@info", - "Could not rename widget %1 to %2 " - "because a widget with the name %3 already exists.", - w->objectName(), name, name)); - d->slotPropertyChangedEnabled = false; - d->propertySet["objectName"].resetValue(); - d->slotPropertyChangedEnabled = true; + if (name != w->objectName() && objectTree()->lookup(name)) { + if (mode == CheckValidityShowMessages) { + KMessageBox::sorry(widget(), + xi18nc("@info", + "Could not rename widget %1 to %2 " + "because a widget with the name %3 already exists.", + w->objectName(), name, name)); + } return false; } return true; } +void Form::checkNameValidityForSelection() +{ + if (!checkNameValidity(d->propertySet.propertyValue("objectName").toString(), CheckValidityShowMessages)) { + KexiUtils::BoolBlocker blocker(&d->slotPropertyChangedEnabled, false); + d->propertySet["objectName"].resetValue(); + KexiMainWindowIface::global()->updatePropertyEditorInfoLabel(); + } +} + void Form::undo() { if (!objectTree()) @@ -1483,13 +1507,13 @@ const QSet subproperties(subpropIface->subproperties()); foreach(const QByteArray& propName, subproperties) { propNames.insert(propName); - //qDebug() << "Added subproperty: " << propName; + //qDebug() << "Added subproperty:" << propName; } } // iterate over the property list, and create Property objects foreach(const QByteArray& propName, propNames) { - //qDebug() << ">> " << propName; + //qDebug() << ">>" << propName; const QMetaProperty subMeta = // special case - subproperty subpropIface ? subpropIface->findMetaSubproperty(propName) : QMetaProperty(); const QMetaProperty meta = subMeta.isValid() ? subMeta @@ -1504,7 +1528,7 @@ : w; WidgetInfo *subwinfo = subwidget ? library()->widgetInfoForClassName( subwidget->metaObject()->className()) : 0; -// qDebug() << "$$$ " << subwidget->className(); +// qDebug() << "$$$" << subwidget->className(); if ( subwinfo && meta.isDesignable(subwidget) @@ -1644,6 +1668,7 @@ //! @todo clearSet()? return; } + KexiMainWindowIface::global()->beginPropertyPaneUpdate(); // if our list is empty,don't use add parameter value if (d->selected.isEmpty() == 0) { @@ -1662,7 +1687,8 @@ if (flags & LastSelection) { emit propertySetSwitched(); } - } + KexiMainWindowIface::global()->endPropertyPaneUpdate(); +} KPropertySet* Form::propertySet() { diff --git a/src/formeditor/formIO.cpp b/src/formeditor/formIO.cpp --- a/src/formeditor/formIO.cpp +++ b/src/formeditor/formIO.cpp @@ -275,7 +275,7 @@ if (!parsed) { qWarning() << errMsg; - qWarning() << "line:" << errLine << "col: " << errCol; + qWarning() << "line:" << errLine << "col:" << errCol; return false; } @@ -311,7 +311,7 @@ QFile file(_filename); if (!file.open(QIODevice::ReadOnly)) { //! @todo show err msg to the user - qWarning() << "Cannot open the file " << _filename; + qWarning() << "Cannot open the file" << _filename; return false; } QDomDocument doc; @@ -342,8 +342,8 @@ } } //update format version information - QString ver = form->headerProperties()->value("version"); - qDebug() << "Original format version: " << ver; + const QString ver = form->headerProperties()->value("version"); + //qDebug() << "Original format version:" << ver; form->setOriginalFormatVersion(ver); bool verOk; const double verNum = ver.toDouble(&verOk); @@ -418,7 +418,7 @@ const char *name, const QVariant &value) { // Widget specific properties and attributes -// qDebug() << "Saving the property: " << name; +// qDebug() << "Saving the property:" << name; Form *form = item->container() ? item->container()->form() : item->parent()->container()->form(); WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast(item->widget()); QWidget *subwidget = item->widget(); @@ -431,7 +431,7 @@ addSubwidgetFlag = true; } if (!propertyIsName && propertyId == -1) { - qDebug() << "The object doesn't have this property. Let's try the WidgetLibrary."; + //qDebug() << "The object doesn't have this property. Let's try the WidgetLibrary."; if (form->library()) form->library()->saveSpecialProperty(item->widget()->metaObject()->className(), name, value, item->widget(), parentNode, parent); @@ -1226,8 +1226,8 @@ { ObjectTreeItem *item = form->objectTree()->lookup(it.key()); if (!item || !item->widget()) { - qDebug() << "Cannot assign buddy for widget " - << it.value()->objectName() << " to " << it.key(); + qDebug() << "Cannot assign buddy for widget" + << it.value()->objectName() << "to" << it.key(); continue; } it.value()->setBuddy(item->widget()); diff --git a/src/formeditor/kexiactionselectiondialog.cpp b/src/formeditor/kexiactionselectiondialog.cpp --- a/src/formeditor/kexiactionselectiondialog.cpp +++ b/src/formeditor/kexiactionselectiondialog.cpp @@ -141,7 +141,7 @@ QList sharedActions(KexiMainWindowIface::global()->allActions()); const Kexi::ActionCategories *acat = Kexi::actionCategories(); foreach(QAction *action, sharedActions) { -// qDebug() << (*it)->name() << " " << (*it)->text(); +// qDebug() << (*it)->name() << (*it)->text(); //! @todo group actions //! @todo: store QAction * here? const int actionCategories = acat->actionCategories(action->objectName().toLatin1()); @@ -284,7 +284,7 @@ if (supportedViewModes & Kexi::DataViewMode) { itm = new ActionSelectorDialogTreeItem(xi18n("Open in Data View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "open"); - itm->setIcon(koIcon("document-open")); + itm->setIcon(KexiIcon("mode-selector-edit")); } if (part->info()->isExecuteSupported()) { itm = new ActionSelectorDialogTreeItem(xi18n("Execute"), this); @@ -323,17 +323,20 @@ itm = new ActionSelectorDialogTreeItem(xi18n("Create New Object (%1)", part->info()->name().toLower()), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "new"); - itm->setIcon(koIcon("document-new")); + itm->setIcon(koIcon("list-add")); if (supportedViewModes & Kexi::DesignViewMode) { itm = new ActionSelectorDialogTreeItem(xi18n("Open in Design View"), this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "design"); - itm->setIcon(koIcon("document-properties")); + itm->setIcon(KexiIcon("mode-selector-design")); } if (supportedViewModes & Kexi::TextViewMode) { - itm = new ActionSelectorDialogTreeItem(xi18n("Open in Text View"), this); + QString actionText; + QString iconName; + KexiPart::getTextViewAction(pluginId, &actionText, &iconName); + itm = new ActionSelectorDialogTreeItem(actionText, this); itm->setData(ActionSelectorDialogTreeItem::ActionDataRole , "editText"); - itm->setIcon(noIcon); + itm->setIcon(iconName.isEmpty() ? noIcon : QIcon::fromTheme(iconName)); } itm = new ActionSelectorDialogTreeItem( xi18n("Close View"), this); @@ -459,7 +462,8 @@ - kactionPageWidget contains only a QVBoxLayout and label+kactionListView */ d->glyr = new QGridLayout(mainWidget); // 2x2 - KexiUtils::setStandardMarginsAndSpacing(d->glyr); + d->glyr->setSpacing(0); + KexiUtils::setMargins(d->glyr, KexiUtils::marginHint()); d->glyr->setRowStretch(1, 1); // 1st column: action types @@ -469,13 +473,8 @@ connect(d->actionCategoriesListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotActionCategorySelected(QTreeWidgetItem*))); - QLabel *lbl = new QLabel(xi18n("Action category:"), mainWidget); - lbl->setBuddy(d->actionCategoriesListView); - lbl->setMinimumHeight(lbl->fontMetrics().height()*2); - lbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - lbl->setAlignment(Qt::AlignTop | Qt::AlignLeft); - lbl->setWordWrap(true); - + QLabel *lbl = createSelectActionLabel(mainWidget, d->actionCategoriesListView); + lbl->setText(xi18n("Action category:")); d->glyr->addWidget(lbl, 0, 0, Qt::AlignTop | Qt::AlignLeft); // widget stack for 2nd and 3rd column @@ -486,7 +485,8 @@ d->secondAnd3rdColumnMainWidget = new QWidget(d->secondAnd3rdColumnStack); d->secondAnd3rdColumnMainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); d->secondAnd3rdColumnGrLyr = new QGridLayout(d->secondAnd3rdColumnMainWidget); - //! @todo KEXI3 QDialog::resizeLayout(d->secondAnd3rdColumnGrLyr, 0, KexiUtils::spacingHint()); + d->secondAnd3rdColumnGrLyr->setMargin(0); + d->secondAnd3rdColumnGrLyr->setSpacing(0); d->secondAnd3rdColumnGrLyr->setRowStretch(1, 2); d->secondAnd3rdColumnStack->addWidget(d->secondAnd3rdColumnMainWidget); @@ -634,7 +634,7 @@ d->kactionPageWidget = new QWidget(); d->kactionPageWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); QVBoxLayout *vlyr = new QVBoxLayout(d->kactionPageWidget); - vlyr->setSpacing(KexiUtils::spacingHint()); + vlyr->setSpacing(0); d->kactionListView = new KActionsListView(d->kactionPageWidget); d->kactionListView->init(); d->kactionPageLabel = createSelectActionLabel(d->kactionPageWidget, d->kactionListView); @@ -659,7 +659,7 @@ d->currentFormActionsPageWidget->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum); QVBoxLayout *vlyr = new QVBoxLayout(d->currentFormActionsPageWidget); - vlyr->setSpacing(KexiUtils::spacingHint()); + vlyr->setSpacing(0); d->currentFormActionsListView = new CurrentFormActionsListView( d->currentFormActionsPageWidget); d->currentFormActionsListView->init(); @@ -669,7 +669,7 @@ vlyr->addWidget(d->currentFormActionsListView); d->secondAnd3rdColumnStack->addWidget(d->currentFormActionsPageWidget); KexiUtils::setMargins(vlyr, 0); - connect(d->currentFormActionsListView, SIGNAL(itemActivated(QTreeWidgetItem*,int)), + connect(d->currentFormActionsListView, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotCurrentFormActionItemExecuted(QTreeWidgetItem*))); connect(d->currentFormActionsListView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(slotCurrentFormActionItemSelected(QTreeWidgetItem*))); diff --git a/src/formeditor/objecttree.cpp b/src/formeditor/objecttree.cpp --- a/src/formeditor/objecttree.cpp +++ b/src/formeditor/objecttree.cpp @@ -115,7 +115,7 @@ if (!d->props.contains(property)) { d->props.insert(property, oldValue); - //qDebug() << "Added this property in the list: " << property << " oldValue: " << oldValue; + //qDebug() << "Added this property in the list:" << property << "oldValue:" << oldValue; } } @@ -346,7 +346,7 @@ parent->addChild(c); container()->form()->emitChildAdded(c); - //qDebug() << "adding " << c->name() << " to " << parent->name(); + //qDebug() << "adding" << c->name() << "to" << parent->name(); } void diff --git a/src/formeditor/utils.cpp b/src/formeditor/utils.cpp --- a/src/formeditor/utils.cpp +++ b/src/formeditor/utils.cpp @@ -43,8 +43,8 @@ // If any widget in the list is a child of this widget, we remove it from the list foreach (QWidget *widg, list) { if ((w != widg) && (w->findChild(widg->objectName()))) { - qDebug() << "Removing the widget " << widg->objectName() - << "which is a child of " << w->objectName(); + //qDebug() << "Removing the widget" << widg->objectName() + // << "which is a child of" << w->objectName(); toRemove.insert(widg); } } @@ -159,12 +159,12 @@ else y2 = w2->mapTo(m_topLevelWidget, QPoint(0, 0)).y(); - qDebug() << w1->objectName() << ": " << y1 << " " - << " | " << w2->objectName() << ": " << y2; + //qDebug() << w1->objectName() << y1 << + // << w2->objectName() << y2; - //qDebug() << w1->name() << ": " << w1->mapTo(m_topLevelWidget, QPoint(0,0)) << " " << w1->y() - //<< " | " << w2->name() << ":" /*<< w2->mapFrom(m_topLevelWidget, QPoint(0,w2->y()))*/ << " " << w2->y(); + //qDebug() << w1->name() << w1->mapTo(m_topLevelWidget, QPoint(0,0)) << w1->y() + //<< w2->name() << /*<< w2->mapFrom(m_topLevelWidget, QPoint(0,w2->y()))*/ << w2->y(); return y1 < y2; } QWidget *m_topLevelWidget; diff --git a/src/formeditor/widgetfactory.cpp b/src/formeditor/widgetfactory.cpp --- a/src/formeditor/widgetfactory.cpp +++ b/src/formeditor/widgetfactory.cpp @@ -238,6 +238,9 @@ { Q_UNUSED(w); + if (property == "objectName") { // name is available in the KexiObjectInfoWidget + return false; + } #ifndef KEXI_FORM_CURSOR_PROPERTY_SUPPORT //! @todo temporary unless cursor works properly in the Designer if (property == "cursor") diff --git a/src/formeditor/widgetlibrary.cpp b/src/formeditor/widgetlibrary.cpp --- a/src/formeditor/widgetlibrary.cpp +++ b/src/formeditor/widgetlibrary.cpp @@ -288,7 +288,7 @@ } WidgetInfo* inheritedClass = parentFactory->widgetInfoForClassName(w->inheritedClassName()); if (!inheritedClass) { - qWarning() << "class" << w->inheritedClassName() << " - no such class to inherit in factory" + qWarning() << "class" << w->inheritedClassName() << "- no such class to inherit in factory" << w->parentFactoryName(); continue; } diff --git a/src/formeditor/widgetwithsubpropertiesinterface.cpp b/src/formeditor/widgetwithsubpropertiesinterface.cpp --- a/src/formeditor/widgetwithsubpropertiesinterface.cpp +++ b/src/formeditor/widgetwithsubpropertiesinterface.cpp @@ -69,8 +69,8 @@ { d->subproperties.insert(property.name()); addedSubproperties.insert(property.name()); - qDebug() << "added subwidget's property that is not present in the parent: " - << property.name(); + //qDebug() << "added subwidget's property that is not present in the parent: " + // << property.name(); } } } diff --git a/src/kexiutils/CMakeLists.txt b/src/kexiutils/CMakeLists.txt --- a/src/kexiutils/CMakeLists.txt +++ b/src/kexiutils/CMakeLists.txt @@ -27,6 +27,9 @@ KexiPluginMetaData.cpp completer/KexiCompleter.cpp + + style/KexiStyle.cpp + style/KexiPropertyPaneLineEditStyle.cpp ) if(SHOULD_BUILD_KEXI_MOBILE_APP) @@ -58,9 +61,15 @@ KF5::IconThemes KF5::WidgetsAddons KF5::ConfigWidgets # KStandardAction KColorScheme + KF5::GuiAddons # KColorUtils KF5::I18n KF5::ItemViews # KCategorizedView KCategoryDrawer KDb + KPropertyWidgets + + PRIVATE + Qt5::Svg + KF5::KIOFileWidgets # KFileWidget::getStartUrl(), KRecentDirs ) if(SHOULD_BUILD_KEXI_DESKTOP_APP) target_link_libraries(kexiutils diff --git a/src/kexiutils/FlowLayout.cpp b/src/kexiutils/FlowLayout.cpp --- a/src/kexiutils/FlowLayout.cpp +++ b/src/kexiutils/FlowLayout.cpp @@ -262,7 +262,7 @@ if (o->isEmpty()) // do not consider hidden widgets continue; -// qDebug() << o->widget()->className() << " " << o->widget()->name(); +// qDebug() << o->widget()->className() << o->widget()->name(); QSize oSizeHint = o->sizeHint(); // we cache these ones because it can take // a while to get it (eg for child layouts) if ((x + oSizeHint.width()) > r.right() && h > 0) { diff --git a/src/kexiutils/KexiFadeWidgetEffect.cpp b/src/kexiutils/KexiFadeWidgetEffect.cpp --- a/src/kexiutils/KexiFadeWidgetEffect.cpp +++ b/src/kexiutils/KexiFadeWidgetEffect.cpp @@ -22,7 +22,7 @@ #include "KexiFadeWidgetEffect.h" #include "KexiFadeWidgetEffect_p.h" -#include +#include #include #include #include @@ -94,7 +94,7 @@ } KexiFadeWidgetEffect::KexiFadeWidgetEffect(QWidget *destWidget, int defaultDuration) - : QWidget(destWidget ? destWidget->parentWidget() : 0), + : QWidget(destWidget), d(new KexiFadeWidgetEffectPrivate(destWidget)) { d->defaultDuration = defaultDuration; @@ -105,6 +105,8 @@ hide(); return; } + destWidget->updateGeometry(); + destWidget->repaint(); setGeometry(QRect(destWidget->mapTo(parentWidget(), QPoint(0, 0)), destWidget->size())); d->oldPixmap = destWidget->grab(); d->timeLine.setFrameRange(0, 255); @@ -133,8 +135,14 @@ deleteLater(); return; } + d->destWidget->updateGeometry(); + d->destWidget->update(); + qApp->processEvents(); + hide(); d->newPixmap = d->destWidget->grab(); d->timeLine.setDuration(duration); + show(); + raise(); d->timeLine.start(); } diff --git a/src/kexiutils/KexiIcon.h b/src/kexiutils/KexiIcon.h --- a/src/kexiutils/KexiIcon.h +++ b/src/kexiutils/KexiIcon.h @@ -42,6 +42,7 @@ //! Use these macros for icons without any issues - global icons (breeze) #define koIcon(name) (QIcon::fromTheme(QLatin1String(name))) +#define koDarkIcon(name, ...) (KexiStyle::darkIcon(QLatin1String(name), ##__VA_ARGS__)) #define koIconName(name) (QLatin1String(name)) #define koIconNameCStr(name) (name) #define koSmallIcon(name) (QIcon::fromTheme(QLatin1String(name)).pixmap(IconSize(KIconLoader::Small))) diff --git a/src/kexiutils/debuggui.cpp b/src/kexiutils/debuggui.cpp --- a/src/kexiutils/debuggui.cpp +++ b/src/kexiutils/debuggui.cpp @@ -135,21 +135,21 @@ // compute availableNestingLevels QTreeWidgetItem * lastItem = kexiAlterTableActionDebugPage->invisibleRootItem()->child( kexiAlterTableActionDebugPage->invisibleRootItem()->childCount()-1); - //qDebug() << "lastItem: " << (lastItem ? lastItem->text(0) : QString()); + //qDebug() << "lastItem:" << (lastItem ? lastItem->text(0) : QString()); while (lastItem) { lastItem = lastItem->parent(); availableNestingLevels++; } - //qDebug() << "availableNestingLevels: " << availableNestingLevels; + //qDebug() << "availableNestingLevels:" << availableNestingLevels; //go up (availableNestingLevels-levelsToGoUp) levels lastItem = kexiAlterTableActionDebugPage->invisibleRootItem()->child( kexiAlterTableActionDebugPage->invisibleRootItem()->childCount()-1); int levelsToGoUp = availableNestingLevels - nestingLevel; while (levelsToGoUp > 0 && lastItem) { lastItem = lastItem->parent(); levelsToGoUp--; } - //qDebug() << "lastItem2: " << (lastItem ? lastItem->text(0) : QString()); + //qDebug() << "lastItem2:" << (lastItem ? lastItem->text(0) : QString()); if (lastItem) { if (lastItem->childCount() > 0) { li = new QTreeWidgetItem(lastItem, lastItem->child(lastItem->childCount()-1)); //child, after @@ -163,7 +163,7 @@ while (lastItem && lastItem->parent()) { lastItem = lastItem->parent(); } - //qDebug() << "lastItem2: " << (lastItem ? lastItem->text(0) : QString()); + //qDebug() << "lastItem2:" << (lastItem ? lastItem->text(0) : QString()); if (lastItem && lastItem->parent()) li = new QTreeWidgetItem(lastItem->parent(), lastItem); //after else if (!lastItem) diff --git a/src/kexiutils/style/KexiPropertyPaneLineEditStyle.h b/src/kexiutils/style/KexiPropertyPaneLineEditStyle.h new file mode 100644 --- /dev/null +++ b/src/kexiutils/style/KexiPropertyPaneLineEditStyle.h @@ -0,0 +1,34 @@ +/* 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. +*/ + +#ifndef KEXIPROPERTYPANELINEEDITSTYLE_H +#define KEXIPROPERTYPANELINEEDITSTYLE_H + +#include +#include + +#include +#include +#include +#include + +//! @internal sets style for KexiPropertyPaneLineEdit +void alterPropertyPaneLineEditProxyStyle(QWidget *w); + +#endif diff --git a/src/kexiutils/style/KexiPropertyPaneLineEditStyle.cpp b/src/kexiutils/style/KexiPropertyPaneLineEditStyle.cpp new file mode 100644 --- /dev/null +++ b/src/kexiutils/style/KexiPropertyPaneLineEditStyle.cpp @@ -0,0 +1,214 @@ +/* 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 "KexiPropertyPaneLineEditStyle.h" +#include +#include "KexiStyle.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static int MenuButton_IndicatorWidth = 20; + +//! A style modification for KexiPropertyPaneLineEdit to allow minimal size +class KexiPropertyPaneLineEditProxyStyle : public QProxyStyle +{ +public: + explicit KexiPropertyPaneLineEditProxyStyle(QStyle *s = nullptr) + : QProxyStyle(s) + , m_viewFocusBrush(KColorScheme::View, KColorScheme::FocusColor) + { + } + + int pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const Q_DECL_OVERRIDE { + const QLineEdit* lineEdit = qobject_cast(widget); + if (lineEdit) { + switch( metric ) { + // frame width + case PM_DefaultFrameWidth: + return 0; + case PM_ComboBoxFrameWidth: + return 0; + default: + break; + } + } + return QProxyStyle::pixelMetric(metric, option, widget); + } + + QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const Q_DECL_OVERRIDE { + if (cc == CC_ComboBox) { + if (sc == SC_ComboBoxEditField) { + //qDebug() << opt->rect; + QRect r(opt->rect); + r.adjust(1, 0, -MenuButton_IndicatorWidth, 0); + return visualRect(opt->direction, opt->rect, r); + } + } + return QProxyStyle::subControlRect(cc, opt, sc, widget); + } + + QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const Q_DECL_OVERRIDE { + if (type == CT_ComboBox) { + return size; + } + else if (type == CT_LineEdit) { + return size - QSize(MenuButton_IndicatorWidth, 0); + } + return QProxyStyle::sizeFromContents(type, option, size, widget); + } + + void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, + const QWidget* widget ) const Q_DECL_OVERRIDE + { + switch (element) { + case PE_FrameLineEdit: { + //qDebug() << "**" << option->rect; + return; + } + case PE_PanelLineEdit: { + const bool enabled(option->state & State_Enabled); + const bool hasFocus(enabled && (option->state & State_HasFocus)); + const QComboBox* combo = qobject_cast(widget->parentWidget()); + const bool popupVisible = combo && combo->view()->isVisible(); + if (hasFocus || popupVisible) { + //normal: QColor outline(KColorUtils::mix(option->palette.color(QPalette::Window), + // option->palette.color( QPalette::WindowText ), 0.25)); + const QColor outline = m_viewFocusBrush.brush(option->palette).color(); + const QColor background(option->palette.color(QPalette::Base)); + QRectF frameRect(option->rect); + if (outline.isValid()) { + painter->setPen(outline); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + } else { + painter->setPen(Qt::NoPen); + } + if (combo) { + frameRect.adjust(-MenuButton_IndicatorWidth - 1, 0, MenuButton_IndicatorWidth - 1, 0); + } + painter->setBrush(background.isValid() ? background : Qt::NoBrush); + const qreal radius = 1.5; + painter->setRenderHint(QPainter::Antialiasing); + //painter->setClipRect(option->rect.adjusted(-MenuButton_IndicatorWidth, 0, MenuButton_IndicatorWidth, 0)); + painter->drawRoundedRect(frameRect, radius, radius); + return; + } + } + default: + break; + } + QProxyStyle::drawPrimitive(element, option, painter, widget); + } + + void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *widget) const { + if (element == CE_ComboBoxLabel) { + const QStyleOptionComboBox *cb = qstyleoption_cast(opt); + if (cb) { + QStyleOptionComboBox cbNew(*cb); + cbNew.palette.setBrush(QPalette::Base, QBrush()); + QProxyStyle::drawControl(element, &cbNew, p, widget); + return; + } + //return; + } + QProxyStyle::drawControl(element, opt, p, widget); + } + + void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option, QPainter *painter, + const QWidget *widget = nullptr) const Q_DECL_OVERRIDE + { + QProxyStyle::drawComplexControl(cc, option, painter, widget); + const bool enabled(option->state & State_Enabled); + const bool hasFocus(enabled && (option->state & State_HasFocus)); + const QComboBox* combo = qobject_cast(widget); + const bool popupVisible = combo && combo->view()->isVisible(); + if (cc == CC_ComboBox && (hasFocus || popupVisible)) { + const qreal radius = 1.5; + QRectF frameRect(option->rect); + const QColor outline = m_viewFocusBrush.brush(option->palette).color(); + if (outline.isValid()) { + painter->setPen(outline); + frameRect.adjust(0.5, 0.5, -0.5, -0.5); + } else { + painter->setPen(Qt::NoPen); + } + painter->setBrush(Qt::NoBrush); + //qDebug() << frameRect << "frameRect"; + painter->drawRoundedRect(frameRect, radius, radius); + } + } + + QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr, + const QWidget *widget = nullptr) const Q_DECL_OVERRIDE + { + if (standardIcon == SP_LineEditClearButton) { + return koDarkIcon("edit-clear-small"); + } + return QProxyStyle::standardIcon(standardIcon, option, widget); + } + +private: + KStatefulBrush m_viewFocusBrush; +}; + +class Filter : public QObject +{ +public: + Filter(QObject *parent) : QObject(parent) + { + parent->installEventFilter(this); + } + bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE { + if (event->type() == QEvent::StyleChange) { + return true; + } + return QObject::eventFilter(watched, event); + } +}; + +class KexiPropertyPaneLineEditProxyStyleGlobal +{ +public: + void alterStyle(QWidget *w) { + if (!style) { + KexiPropertyPaneLineEditProxyStyle *s = new KexiPropertyPaneLineEditProxyStyle(w->style()); + style.reset(s); + } + (void)new Filter(w); + w->setStyle(style.data()); + } + QScopedPointer style; +}; + +Q_GLOBAL_STATIC(KexiPropertyPaneLineEditProxyStyleGlobal, s_style); + +void alterPropertyPaneLineEditProxyStyle(QWidget *w) +{ + if (w) { + s_style->alterStyle(w); + } +} diff --git a/src/kexiutils/style/KexiStyle.h b/src/kexiutils/style/KexiStyle.h new file mode 100644 --- /dev/null +++ b/src/kexiutils/style/KexiStyle.h @@ -0,0 +1,155 @@ +/* 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 KEXISTYLE_H +#define KEXISTYLE_H + +#include + +#include + +#include +#include + +class KLocalizedString; +class KPropertyEditorView; +class QComboBox; +class QFont; +class QFrame; +class QGridLayout; +class QIcon; +class QLabel; +class QLineEdit; +class QModelIndex; +class QPainter; +class QPalette; +class QRect; +class QStyleOptionViewItem; +class QVBoxLayout; +class QWidget; + +//! Styled icon parameters +class KEXIUTILS_EXPORT KexiStyledIconParameters { +public: + explicit KexiStyledIconParameters(KIconLoader::Context c = KIconLoader::Action) : context(c) + { + } + //! Icon name + QString name; + //! Icon color, when used for normal mode (QIcon::Normal). + //! If the value is valid, default color will be replaced with it. + QColor color; + //! Icon color, when used for selected mode (QIcon::Selected). + //! If the value is valid, default color will be replaced with it. + QColor selectedColor; + //! Icon color, when used for disabled palette group (QPalette::Disabled). + //! If the value is valid, default color will be replaced with it. + QColor disabledColor; + //! Icon context such as "actions" + KIconLoader::Context context; +}; + +//! Application style. +//! @todo make it configurable? +namespace KexiStyle +{ + //! Setup style for this application. Called once after creating of application. + //! @return false on error, then @a errorMessage is set + KEXIUTILS_EXPORT bool setupApplication(KLocalizedString *errorMessage); + + //! Setup style for @a frame. By default flat style is set (QFrame::NoFrame). + KEXIUTILS_EXPORT void setupFrame(QFrame *frame); + + //! Setup style for the global view mode selector widget (KexiGlobalViewModeSelector). + //! By default setupFrame() is called to set flat style, minimal fonts are set + //! and a bit darker version of alternativePalette(). + KEXIUTILS_EXPORT void setupGlobalViewModeSelector(QFrame *selector); + + //! Overpaints entire global view mode selector. By default it paints a dark shadow an arrow + //! for selected item. If @a selectedRect is not null, provides geometry of selected item. + KEXIUTILS_EXPORT void overpaintGlobalViewModeSelector(QWidget *widget, QPainter *painter, + const QRect &selectedRect, + const QColor &arrowColor); + + //! Overpaints global view mode selector's item. By default does nothing. + KEXIUTILS_EXPORT void overpaintModeSelectorItem(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index); + + //! @return alternative palette based on @a palette. + //! By default it is dark one based on Breeze colors. + KEXIUTILS_EXPORT QPalette alternativePalette(const QPalette &palette); + + //! @return palette dedicated for side bars, based on @a palette. + //! By default it equal to alternativePalette(). + KEXIUTILS_EXPORT QPalette sidebarsPalette(const QPalette &palette); + + //! Sets sidebarsPalette(). If it's nonstandard palette, + //! QWidget::setAutoFillBackground(true) is also called for the widget. + KEXIUTILS_EXPORT void setSidebarsPalette(QWidget *widget); + + //! @return font @a font adjusted to make it a title font. + //! By default capitalization is set for the font. + KEXIUTILS_EXPORT QFont titleFont(const QFont &font); + + //! @return styled dark icon @a iconName of context @a iconContext. Group can be "actions", etc. + //! The same styled icon can be used with light and dark background. Filename for dark + //! variants should have "@dark" suffix. If proper file does not exist, null icon is returned. + //! KIconLoader::Any means KIconLoader::Action. + KEXIUTILS_EXPORT QIcon darkIcon(const QString &iconName, + KIconLoader::Context iconContext = KIconLoader::Action); + + KEXIUTILS_EXPORT QIcon icon(const KexiStyledIconParameters ¶meters); + + //! Style definition for property pane + class KEXIUTILS_EXPORT PropertyPane { + public: + PropertyPane(); + void setupEditor(KPropertyEditorView *view) const; + QPalette sectionTitlePalette(const QPalette &palette) const; + QPalette labelPalette(const QPalette &palette) const; + QPalette warningLabelPalette(const QPalette &palette) const; + QFont font() const; + void alterLineEditStyle(QLineEdit *edit) const; + void alterComboBoxStyle(QComboBox *combo) const; + void alterTitleFont(QWidget *widget) const; + Q_REQUIRED_RESULT QVBoxLayout* createVLayout(QWidget *widget) const; + Q_REQUIRED_RESULT QGridLayout* createFormLayout(QVBoxLayout *parentLayout) const; + Q_REQUIRED_RESULT QLabel* createLabel(const QString &labelText) const; + Q_REQUIRED_RESULT QLabel* createWarningLabel(const QString &labelText) const; + QLabel* createTitleLabel(const QString &title, QVBoxLayout *lyr) const; + void addLabelAndWidget(const QString &labelText, QWidget *widget, QGridLayout *formLayout) const; + void setFormLabelAndWidgetVisible(QWidget *widget, QGridLayout *formLayout, bool set) const; + + //! @return icon suitable for use in the property pane's background + QIcon icon(const QString &iconName) const; + + const QMargins margins; + const int verticalSpacing; + const int sectionTitleIndent; + const int horizontalSpacingAfterIcon; + const int horizontalSpacingAfterLabel; + private: + Q_DISABLE_COPY(PropertyPane) + }; + + KEXIUTILS_EXPORT const PropertyPane& propertyPane(); +} + +#endif // KEXISTYLE_H diff --git a/src/kexiutils/style/KexiStyle.cpp b/src/kexiutils/style/KexiStyle.cpp new file mode 100644 --- /dev/null +++ b/src/kexiutils/style/KexiStyle.cpp @@ -0,0 +1,480 @@ +/* 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 "KexiStyle.h" +#include "KexiPropertyPaneLineEditStyle.h" +#include "utils.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace KexiStyle { + +KEXIUTILS_EXPORT bool setupApplication(KLocalizedString *errorMessage) +{ + // Only this style matches current Kexi theme and can be supported. + // @todo add support for more styles via theme plugins. + const char *name = "breeze"; + QScopedPointer style(QStyleFactory::create(name)); + if (!style || style->objectName() != name) { + *errorMessage = kxi18nc("@info", + "Could not find application style %1." + "Kexi will not start. " + "Please check if Kexi is properly installed.") + .subs(name); + return false; + } + qApp->setStyle(style.take()); + *errorMessage = KLocalizedString(); + return true; +} + +KEXIUTILS_EXPORT void setupFrame(QFrame *frame) +{ + if (frame) { + frame->setFrameStyle(QFrame::NoFrame); + } +} + +KEXIUTILS_EXPORT void setupGlobalViewModeSelector(QFrame *selector) +{ + KexiStyle::setupFrame(selector); + selector->setFont(KexiUtils::smallestReadableFont()); + QPalette p(selector->palette()); + p.setColor(QPalette::Window, KexiUtils::shadeBlack()); + p.setColor(QPalette::Base, KexiUtils::shadeBlack()); + p.setColor(QPalette::Button, KexiUtils::shadeBlack()); + p.setColor(QPalette::AlternateBase, KexiUtils::shadeBlackLighter()); + p.setColor(QPalette::WindowText, KexiUtils::cardboardGrey()); + p.setColor(QPalette::ButtonText, KexiUtils::cardboardGrey()); + p.setColor(QPalette::Text, KexiUtils::cardboardGrey()); + p.setBrush(QPalette::Disabled, QPalette::Text, KexiUtils::iconGrey()); // yes, modes can be disabled + //generic?? KColorScheme(QPalette::Disabled, KColorScheme::View).foreground()); + p.setColor(QPalette::Highlight, KexiUtils::cardboardGrey()); + p.setColor(QPalette::Active, QPalette::Highlight, KexiUtils::plasmaBlue()); // unused anyway because mode selector has no focus + p.setColor(QPalette::HighlightedText, KexiUtils::charcoalGrey()); + selector->setPalette(p); +} + +KEXIUTILS_EXPORT void overpaintGlobalViewModeSelector(QWidget *widget, QPainter *painter, + const QRect &selectedRect, + const QColor &arrowColor) +{ + // draw gradient + painter->save(); + int w = widget->fontMetrics().height() * 3 / 2; + const bool rtl = QGuiApplication::isRightToLeft(); + painter->translate(rtl ? 0 : (widget->width() - w), 0); + QLinearGradient grad(0, 0, w, 0); + QColor c(widget->palette().base().color()); + c.setAlpha(0); + grad.setColorAt(rtl ? 1.0 : 0.0, c); + c.setAlpha(15); + grad.setColorAt(0.5, c); + grad.setColorAt(rtl ? 0.0 : 1.0, QColor(0, 0, 0, 50)); + painter->fillRect(0, 0, w, widget->height(), QBrush(grad)); + painter->restore(); + + // draw arrow: /| (or reversed for RTL) + // \| + if (!selectedRect.isNull()) { + painter->save(); + w = selectedRect.height() / 10; + if (w % 2 == 0) { + ++w; + } + painter->translate( + selectedRect.x() + (rtl ? 0 : (selectedRect.width() - w)), + selectedRect.y() + (selectedRect.height() - w * 2) / 2 - 0.5); + QPolygon polygon; + if (rtl) { + polygon << QPoint(0, 0) << QPoint(w, w) << QPoint(0, w * 2); + } else { + polygon << QPoint(w, 0) << QPoint(w, w * 2) << QPoint(0, w); + } + painter->setPen(QPen(Qt::NoPen)); + painter->setBrush(arrowColor); + painter->drawPolygon(polygon); + painter->restore(); + } +} + +KEXIUTILS_EXPORT void overpaintModeSelectorItem(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) +{ + Q_UNUSED(painter) + Q_UNUSED(option) + Q_UNUSED(index) +} + +KEXIUTILS_EXPORT QPalette alternativePalette(const QPalette &palette) +{ + QPalette p(palette); + p.setColor(QPalette::Window, KexiUtils::charcoalGrey()); + p.setColor(QPalette::Base, KexiUtils::shadeBlack()); + p.setColor(QPalette::Disabled, QPalette::Base, KexiUtils::charcoalGrey()); + p.setColor(QPalette::Button, KexiUtils::shadeBlack()); + p.setColor(QPalette::AlternateBase, KexiUtils::shadeBlackLighter()); + p.setColor(QPalette::WindowText, KexiUtils::paperWhite()); + p.setColor(QPalette::Disabled, QPalette::WindowText, KexiUtils::iconGrey().lighter(125)); + p.setColor(QPalette::ButtonText, KexiUtils::paperWhite()); + p.setColor(QPalette::Disabled, QPalette::ButtonText, KexiUtils::cardboardGreyAlternative()); + p.setColor(QPalette::Text, KexiUtils::paperWhite()); + p.setColor(QPalette::Disabled, QPalette::Text, p.color(QPalette::Disabled, QPalette::WindowText)); + p.setColor(QPalette::Highlight, KexiUtils::cardboardGrey()); + p.setColor(QPalette::Active, QPalette::Highlight, KexiUtils::plasmaBlue()); + p.setColor(QPalette::HighlightedText, KexiUtils::charcoalGrey()); + p.setColor(QPalette::Active, QPalette::HighlightedText, KexiUtils::cardboardGrey()); + return p; +} + +KEXIUTILS_EXPORT QPalette sidebarsPalette(const QPalette &palette) +{ + return alternativePalette(palette); +} + +KEXIUTILS_EXPORT void setSidebarsPalette(QWidget *widget) +{ + widget->setPalette(sidebarsPalette(widget->palette())); + widget->setAutoFillBackground(true); +} + +KEXIUTILS_EXPORT QFont titleFont(const QFont &font) +{ + QFont newFont(font); + newFont.setCapitalization(QFont::AllUppercase); + return newFont; +} + +static const QString g_contexts[] = { + QLatin1String("actions"), // Any + QLatin1String("actions"), + QLatin1String("apps"), + QLatin1String("devices"), + QLatin1String("filesystems"), + QLatin1String("mimetypes"), + QLatin1String("animations"), + QLatin1String("categories"), + QLatin1String("emblems"), + QLatin1String("emotes"), + QLatin1String("intl"), + QLatin1String("places"), + QLatin1String("status") +}; + +KEXIUTILS_EXPORT QIcon darkIcon(const QString &iconName, KIconLoader::Context iconContext) +{ + Q_ASSERT(iconContext < (sizeof(g_contexts) / sizeof(g_contexts[0]))); + static const QIcon::Mode modes[] = { QIcon::Normal }; //can be supported too: , QIcon::Selected }; + const QString prefix(QLatin1String(":/icons/breeze/") + + g_contexts[iconContext] + QLatin1Char('/')); + const QString suffixes[] = { + iconName + QLatin1String("@dark.svg"), + iconName + QLatin1String(".svg") }; + static const QString sizesStr[] = { + QString::fromLatin1("32/"), // important: opposite direction + QString::fromLatin1("22/"), + QString::fromLatin1("16/") }; + static const QSize sizes[] = { QSize(32, 32), QSize(22, 22), QSize(16, 16) }; // important: opposite direction + QIcon icon; + for (int mode = 0; mode < int(sizeof(modes) / sizeof(modes[0])); ++mode) { + for (int size = 0; size < int(sizeof(sizes) / sizeof(sizes[0])); ++size) { + const QString fileName(prefix + sizesStr[size] + suffixes[mode]); + //qDebug() << fileName << sizes[size] << modes[mode]; + if (QFile::exists(fileName)) { + icon.addFile(fileName, sizes[size], modes[mode], QIcon::Off); + icon.addFile(fileName, sizes[size], modes[mode], QIcon::On); + } + } + } + return icon; +} + +class IconEngine : public QIconEngine +{ +public: + IconEngine(const KexiStyledIconParameters ¶meters) + : m_parameters(parameters) + { + } + inline QIconEngine *clone() const Q_DECL_OVERRIDE { + return new IconEngine(*this); + } + + //! @todo add caching? + QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE { + Q_UNUSED(state) + QFile f(QLatin1String(":/icons/breeze/") + g_contexts[m_parameters.context] + QChar('/') + QString::number(size.width()) + + QChar('/') + m_parameters.name + ".svg"); + if (!f.open(QIODevice::ReadOnly)) { + return QPixmap(); + } + QByteArray svg(f.readAll()); + QColor color; + if (mode == QIcon::Selected && m_parameters.selectedColor.isValid()) { + color = m_parameters.selectedColor; + } else if (mode == QIcon::Disabled && m_parameters.disabledColor.isValid()) { + color = m_parameters.disabledColor; + //qDebug() << m_parameters.disabledColor; + } else if (m_parameters.color.isValid()) { + color = m_parameters.color; + } + if (color.isValid()) { + svg.replace(KexiUtils::iconGrey().name().toLatin1(), color.name().toLatin1()); + } + QSvgRenderer renderer(svg); + QPixmap pm(size); + pm.fill(Qt::transparent); + QPainter p(&pm); + renderer.render(&p, pm.rect()); + return pm; + } + + //! Nothing to paint extra here + void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) Q_DECL_OVERRIDE { + Q_UNUSED(painter) + Q_UNUSED(rect) + Q_UNUSED(mode) + Q_UNUSED(state) + } + +private: + //! Needed for clone() + IconEngine(const IconEngine &other) : QIconEngine(other), m_parameters(other.m_parameters) {} + + const KexiStyledIconParameters m_parameters; +}; + +KEXIUTILS_EXPORT QIcon icon(const KexiStyledIconParameters ¶meters) +{ + return QIcon(new IconEngine(parameters)); +} + +const int propertyPaneMargin = 2; + +Q_GLOBAL_STATIC(PropertyPane, s_propertyPane) + +KEXIUTILS_EXPORT const PropertyPane& propertyPane() +{ + return *s_propertyPane; +} + +PropertyPane::PropertyPane() + : margins(propertyPaneMargin, propertyPaneMargin * 2, propertyPaneMargin, propertyPaneMargin) //left top right bottom + , verticalSpacing(5) + , sectionTitleIndent(8) + , horizontalSpacingAfterIcon(2) + , horizontalSpacingAfterLabel(5) +{ +} + +void PropertyPane::setupEditor(KPropertyEditorView *view) const +{ + view->setGridLineColor(QColor()); + view->setFrameShape(QFrame::NoFrame); +} + +QPalette PropertyPane::sectionTitlePalette(const QPalette &palette) const +{ + QPalette pal(palette); + pal.setColor(QPalette::WindowText, KexiUtils::cardboardGreyAlternative()); + return pal; +} + +QPalette PropertyPane::labelPalette(const QPalette &palette) const +{ + QPalette pal(palette); + pal.setColor(QPalette::WindowText, QColor(0x7f8c8d)); + return pal; +} + +QPalette PropertyPane::warningLabelPalette(const QPalette &palette) const +{ + QPalette pal(palette); + QColor c(0xffa92d); // orange + c.setAlpha(120); + pal.setColor(QPalette::WindowText, c); + return pal; +} + +QFont PropertyPane::font() const +{ + return KexiUtils::smallestReadableFont(); +} + +void PropertyPane::alterLineEditStyle(QLineEdit *edit) const +{ + alterPropertyPaneLineEditProxyStyle(edit); +} + +void PropertyPane::alterComboBoxStyle(QComboBox *combo) const +{ + if (combo) { + combo->setContentsMargins(0, 0, 0, 0); + alterPropertyPaneLineEditProxyStyle(combo); + alterPropertyPaneLineEditProxyStyle(combo->lineEdit()); + } +} + +void PropertyPane::alterTitleFont(QWidget *widget) const +{ + QFont f(widget->font()); + f.setCapitalization(QFont::AllUppercase); + widget->setFont(f); +} + +QVBoxLayout* PropertyPane::createVLayout(QWidget *widget) const +{ + QVBoxLayout *lyr = new QVBoxLayout(widget); + lyr->setContentsMargins(0, 0, 0, 0); + lyr->setSpacing(0); + return lyr; +} + +QGridLayout* PropertyPane::createFormLayout(QVBoxLayout *parentLayout) const +{ + const PropertyPane &s = KexiStyle::propertyPane(); + QGridLayout *formLyr = new QGridLayout; + QMargins formMargins(0, 0, s.margins.right(), 0); + KexiUtils::adjustIfRtl(&formMargins); + formLyr->setContentsMargins(formMargins); + + formLyr->setVerticalSpacing(0); + parentLayout->addLayout(formLyr); + return formLyr; +} + +static QLabel* createLabelInternal(const QString &labelText) +{ + QLabel *label = new QLabel(labelText); + label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + label->setWordWrap(true); + label->setContentsMargins(0, 0, 0, 0); + if (QGuiApplication::isRightToLeft()) { + label->setAlignment(Qt::AlignRight); + } + return label; +} + +QLabel* PropertyPane::createLabel(const QString &labelText) const +{ + const PropertyPane &s = KexiStyle::propertyPane(); + QLabel* label = createLabelInternal(labelText); + label->setPalette(s.labelPalette(label->palette())); + return label; +} + +QLabel* PropertyPane::createWarningLabel(const QString &labelText) const +{ + const PropertyPane &s = KexiStyle::propertyPane(); + QLabel* label = createLabelInternal(labelText); + label->setPalette(s.warningLabelPalette(label->palette())); + return label; +} + +QLabel* PropertyPane::createTitleLabel(const QString &title, QVBoxLayout *layout) const +{ + const PropertyPane &s = KexiStyle::propertyPane(); + QLabel *lbl = new QLabel(title); + lbl->setIndent(s.sectionTitleIndent); + if (QGuiApplication::isRightToLeft()) { + lbl->setAlignment(Qt::AlignRight); + } + s.alterTitleFont(lbl); + lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + lbl->setPalette(s.sectionTitlePalette(lbl->palette())); + layout->addWidget(lbl); + layout->addSpacing(verticalSpacing); + return lbl; +} + +void PropertyPane::addLabelAndWidget(const QString &labelText, QWidget *widget, + QGridLayout *formLayout) const +{ + const PropertyPane &s = KexiStyle::propertyPane(); + QLabel * label = new QLabel(labelText); + label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); + QMargins labelMargins(s.sectionTitleIndent * 2, 0, s.horizontalSpacingAfterLabel, 0); + KexiUtils::adjustIfRtl(&labelMargins); + label->setContentsMargins(labelMargins); + if (QGuiApplication::isRightToLeft()) { + label->setAlignment(Qt::AlignRight); + } + label->setPalette(s.labelPalette(label->palette())); + + QComboBox* comboBox = qobject_cast(widget); + if (comboBox) { + s.alterComboBoxStyle(comboBox); + } + widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); + label->setBuddy(widget); + formLayout->addWidget(label, formLayout->rowCount(), 0, Qt::AlignRight | Qt::AlignTop); + formLayout->addWidget(widget, formLayout->rowCount() - 1, 1); + formLayout->addItem(new QSpacerItem(1, verticalSpacing, QSizePolicy::Fixed, QSizePolicy::Fixed), formLayout->rowCount(), 1); +} + +void PropertyPane::setFormLabelAndWidgetVisible(QWidget *widget, QGridLayout *formLayout, bool set) const +{ + if (!widget) { + return; + } + const int index = formLayout->indexOf(widget); + if (index == -1) { + qWarning() << "No widget" << widget << "in form layout" << formLayout; + return; + } + int row, column, rowSpan, columnSpan; + formLayout->getItemPosition(index, &row, &column, &rowSpan, &columnSpan); + QLayoutItem *labelItem = formLayout->itemAtPosition(row, 0); + if (labelItem->widget()) { + labelItem->widget()->setVisible(set); + } + widget->setVisible(set); + QLayoutItem *spacerItem = formLayout->itemAtPosition(row + 1, 1); + if (spacerItem && spacerItem->spacerItem()) { + spacerItem->spacerItem()->changeSize(set ? 1 : 0, set ? verticalSpacing : 0); + } +} + +QIcon PropertyPane::icon(const QString &iconName) const +{ + return KexiStyle::darkIcon(iconName); +} + +} // namespace KexiStyle diff --git a/src/kexiutils/utils.h b/src/kexiutils/utils.h --- a/src/kexiutils/utils.h +++ b/src/kexiutils/utils.h @@ -591,12 +591,33 @@ //! @return Paper White color, see https://techbase.kde.org/Projects/Usability/HIG/Color inline QColor paperWhite() { return QColor(0xfcfcfc); } +//! @return Cardboard Grey color, see https://techbase.kde.org/Projects/Usability/HIG/Color +inline QColor cardboardGrey() { return QColor(0xeff0f1); } + +//! @return Alternative to Normal background (Cardboard Grey), +//! see https://techbase.kde.org/Projects/Usability/HIG/Color +inline QColor cardboardGreyAlternative() { return QColor(0xbdc3c7); } + +//! @return Icon Grey color, see https://techbase.kde.org/Projects/Usability/HIG/Color +inline QColor iconGrey() { return QColor(0x4d4d4d); } + //! @return Charcoal Grey color, see https://techbase.kde.org/Projects/Usability/HIG/Color inline QColor charcoalGrey() { return QColor(0x31363b); } +//! @return Charcoal Grey color made a bit darker, suitable for disabled dark base, +//! see https://techbase.kde.org/Projects/Usability/HIG/Color +//inline QColor charcoalGreyDarker() { return charcoalGrey().darker(125); } + //! @return Shade Black color, see https://techbase.kde.org/Projects/Usability/HIG/Color inline QColor shadeBlack() { return QColor(0x232629); } +//! @return Shade Black color made a bit lighter, suitable for alternate base, +//! see https://techbase.kde.org/Projects/Usability/HIG/Color +inline QColor shadeBlackLighter() { return shadeBlack().lighter(125); } + +//! @return Shade Black color, see https://techbase.kde.org/Projects/Usability/HIG/Color +inline QColor plasmaBlue() { return QColor(0x3daee9); } + /*! @return @c true if whether the app runs in a single click mode (the default). @c false if returned if the app runs in double click mode. The flag is checked in two stages. diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -2,8 +2,12 @@ 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 ${CMAKE_BINARY_DIR}/src/widget +${CMAKE_SOURCE_DIR}/src/widget/navigator +${CMAKE_SOURCE_DIR}/src/widget/properties +) set(QT_USE_QTUITOOLS true) @@ -15,6 +19,9 @@ KexiSearchLineEdit.cpp KexiUserFeedbackAgent.cpp KexiBugReportDialog.cpp + KexiGlobalViewModeSelector.cpp + KexiObjectViewWidget.cpp + KexiObjectViewTabWidget.cpp startup/KexiNewProjectAssistant.cpp startup/KexiOpenProjectAssistant.cpp diff --git a/src/main/KexiGlobalViewModeSelector.h b/src/main/KexiGlobalViewModeSelector.h new file mode 100644 --- /dev/null +++ b/src/main/KexiGlobalViewModeSelector.h @@ -0,0 +1,72 @@ +/* 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 KEXIGLOBALVIEWMODESELECTOR_H +#define KEXIGLOBALVIEWMODESELECTOR_H + +#include +#include + +#include + +//! A global view mode selector widget +class KexiGlobalViewModeSelector : public KexiListView +{ + Q_OBJECT +public: + explicit KexiGlobalViewModeSelector(QWidget *parent = 0); + virtual ~KexiGlobalViewModeSelector(); + + //! @return current mode + Kexi::GlobalViewMode currentMode() const; + + //! Sets current mode + void setCurrentMode(Kexi::GlobalViewMode mode); + + //! Set arrow color, it depends on color of sibling area so needs to be controlled + void setArrowColor(const QColor &color); + + //! @return keyboard modifiers (CTRL, SHIFT, etc.) pressed while item was recently clicked. + //! Use with currentModeChanged(); + //! Useful for handling "Edit text" mode as CTRL+Design. + Qt::KeyboardModifiers keyboardModifiers() const; + +Q_SIGNALS: + void currentModeChanged(Kexi::GlobalViewMode previousMode); + +protected Q_SLOTS: + void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) Q_DECL_OVERRIDE; + +protected: + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; + + //! Reimplemented to handle keyboardModifiers() and disable modifiers for selections + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + + //! Emptied to disable double clicks + void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + + //! Emptied to disable dragging over items that changes selection + void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + + class Private; + const QScopedPointer d; +}; + +#endif // KEXIGLOBALVIEWMODESELECTOR_H diff --git a/src/main/KexiGlobalViewModeSelector.cpp b/src/main/KexiGlobalViewModeSelector.cpp new file mode 100644 --- /dev/null +++ b/src/main/KexiGlobalViewModeSelector.cpp @@ -0,0 +1,240 @@ +/* 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 "KexiGlobalViewModeSelector.h" +#include "KexiGlobalViewModeSelector_p.h" +#include + +#include + +#include +#include +#include +#include + +KexiGlobalViewModeSelectorModel::KexiGlobalViewModeSelectorModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +KexiGlobalViewModeSelectorModel::~KexiGlobalViewModeSelectorModel() +{ + qDeleteAll(modes); +} + +int KexiGlobalViewModeSelectorModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return modes.count(); +} + +QVariant KexiGlobalViewModeSelectorModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= modes.size()) + return QVariant(); + + KexiGlobalViewModeItem *mode = static_cast(index.internalPointer()); + switch (role) { + case Qt::DisplayRole: + return mode->name; + case Qt::DecorationRole: + return mode->icon; + default:; + } + return QVariant(); +} + +Qt::ItemFlags KexiGlobalViewModeSelectorModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = QAbstractListModel::flags(index); + KexiGlobalViewModeItem *mode = static_cast(index.internalPointer()); + if (!mode->enabled) { + flags &= ~(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } + return flags; +} + +QModelIndex KexiGlobalViewModeSelectorModel::index(int row, int column, const QModelIndex& parent) const +{ + Q_UNUSED(parent); + if (row < 0 || row >= modes.count()) { + return QModelIndex(); + } + return createIndex(row, column, modes.at(row)); +} + +// ---- + +KexiGlobalViewModeSelectorDelegate::KexiGlobalViewModeSelectorDelegate(QObject *parent) + : KexiListViewDelegate(parent) +{ +} + +void KexiGlobalViewModeSelectorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + KexiListViewDelegate::paint(painter, option, index); + KexiStyle::overpaintModeSelectorItem(painter, option, index); +} + +// ---- + +class KexiGlobalViewModeSelector::Private +{ +public: + Private() : keyboardModifiers(Qt::NoModifier) {} + KexiGlobalViewModeSelectorModel model; + QColor arrowColor; + Qt::KeyboardModifiers keyboardModifiers; +}; + +KexiGlobalViewModeSelector::KexiGlobalViewModeSelector(QWidget *parent) + : KexiListView(DontUseDelegate, parent), d(new Private) +{ + KexiStyle::setupGlobalViewModeSelector(this); + setSpacing(0); + setContentsMargins(0, 0, 0, 0); + setFocusPolicy(Qt::NoFocus); + setEditTriggers(NoEditTriggers); + setDropIndicatorShown(false); + setSelectionBehavior(SelectRows); + setSelectionMode(SingleSelection); + setSelectionRectVisible(false); + setUniformItemSizes(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + setItemDelegate(new KexiGlobalViewModeSelectorDelegate(this)); + + KexiStyledIconParameters param; + param.color = palette().color(QPalette::Text); + param.selectedColor = palette().color(QPalette::HighlightedText); + param.disabledColor = palette().color(QPalette::Disabled, QPalette::Text); + { + KexiGlobalViewModeItem *welcomeMode = new KexiGlobalViewModeItem; + welcomeMode->name = xi18nc("Welcome global view mode", "Welcome"); + param.context = KIconLoader::Action; + param.name = "mode-selector-welcome"; + welcomeMode->icon = KexiStyle::icon(param); + d->model.modes << welcomeMode; + } + { + KexiGlobalViewModeItem *projectMode = new KexiGlobalViewModeItem; + projectMode->enabled = false; + projectMode->name = xi18nc("Project global view mode (noun)", "Project"); + param.context = KIconLoader::Action; + param.name = "mode-selector-project"; + projectMode->icon = KexiStyle::icon(param); + d->model.modes << projectMode; + } + { + KexiGlobalViewModeItem *dataMode = new KexiGlobalViewModeItem; + dataMode->name = xi18nc("Edit global view mode (verb)", "Edit"); + param.context = KIconLoader::Action; + param.name = "mode-selector-edit"; + dataMode->icon = KexiStyle::icon(param); + d->model.modes << dataMode; + } + { + KexiGlobalViewModeItem *designMode = new KexiGlobalViewModeItem; + designMode->name = xi18nc("Design global view mode (verb)", "Design"); + param.context = KIconLoader::Action; + param.name = "mode-selector-design"; + designMode->icon = KexiStyle::icon(param); + d->model.modes << designMode; + } + { + KexiGlobalViewModeItem *helpMode = new KexiGlobalViewModeItem; + helpMode->name = xi18nc("Help global view mode (noun)", "Help"); + param.context = KIconLoader::Action; + param.name = "mode-selector-help"; + helpMode->icon = KexiStyle::icon(param); + d->model.modes << helpMode; + } + setModel(&d->model); + setCurrentMode(Kexi::WelcomeGlobalMode); +} + +KexiGlobalViewModeSelector::~KexiGlobalViewModeSelector() +{ +} + +void KexiGlobalViewModeSelector::paintEvent(QPaintEvent *event) +{ + KexiListView::paintEvent(event); + + QRect selectedRect; + if (!selectedIndexes().isEmpty()) { + selectedRect = visualRect(selectedIndexes().first()); + } + QPainter painter(viewport()); + KexiStyle::overpaintGlobalViewModeSelector(this, &painter, selectedRect, d->arrowColor); +} + +Kexi::GlobalViewMode KexiGlobalViewModeSelector::currentMode() const +{ + int index = currentIndex().row(); + if (index < 0 || index > Kexi::LastGlobalMode) { + index = 0; + } + return static_cast(index); +} + +void KexiGlobalViewModeSelector::setCurrentMode(Kexi::GlobalViewMode mode) +{ + if (mode <= Kexi::LastGlobalMode) { + setCurrentIndex(model()->index(int(mode), 0)); + } +} + +void KexiGlobalViewModeSelector::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + const Kexi::GlobalViewMode previousMode = currentMode(); + KexiListView::currentChanged(current, previous); + emit currentModeChanged(previousMode); +} + +void KexiGlobalViewModeSelector::mousePressEvent(QMouseEvent *event) +{ + d->keyboardModifiers = event->modifiers(); + QMouseEvent newEvent = *event; + newEvent.setModifiers(Qt::NoModifier); // otherwise affects selection + KexiListView::mousePressEvent(&newEvent); +} + +void KexiGlobalViewModeSelector::mouseDoubleClickEvent(QMouseEvent *event) +{ + Q_UNUSED(event); +} + +void KexiGlobalViewModeSelector::mouseMoveEvent(QMouseEvent *event) +{ + Q_UNUSED(event); +} + +Qt::KeyboardModifiers KexiGlobalViewModeSelector::keyboardModifiers() const +{ + return d->keyboardModifiers; +} + +void KexiGlobalViewModeSelector::setArrowColor(const QColor &color) +{ + d->arrowColor = color; + update(currentIndex()); +} diff --git a/src/main/KexiGlobalViewModeSelector_p.h b/src/main/KexiGlobalViewModeSelector_p.h new file mode 100644 --- /dev/null +++ b/src/main/KexiGlobalViewModeSelector_p.h @@ -0,0 +1,70 @@ +/* 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 KEXIGLOBALVIEWMODESELECTOR_P_H +#define KEXIGLOBALVIEWMODESELECTOR_P_H + +#include + +class QPainter; + +//! @internal A single global mode +class KexiGlobalViewModeItem +{ +public: + KexiGlobalViewModeItem() : enabled(true) {} + QString name; + QIcon icon; + bool enabled; +}; + +//! @internal A model for KexiGlobalViewModeSelector, each item has name and icon +class KexiGlobalViewModeSelectorModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit KexiGlobalViewModeSelectorModel(QObject *parent = 0); + + ~KexiGlobalViewModeSelectorModel(); + + int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + + QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; + + Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + + QModelIndex index(int row, int column, const QModelIndex& parent) const Q_DECL_OVERRIDE; + + QList modes; +}; + +//! @internal A delegate for items of KexiGlobalViewModeSelector +class KexiGlobalViewModeSelectorDelegate : public KexiListViewDelegate +{ + Q_OBJECT + +public: + explicit KexiGlobalViewModeSelectorDelegate(QObject *parent = 0); + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const Q_DECL_OVERRIDE; +}; + +#endif // KEXIGLOBALVIEWMODESELECTOR_P_H diff --git a/src/main/KexiMainWindow.h b/src/main/KexiMainWindow.h --- a/src/main/KexiMainWindow.h +++ b/src/main/KexiMainWindow.h @@ -25,31 +25,29 @@ #include "keximain_export.h" -#include #include #include #include +#include #include class QPaintEvent; class KDbObject; class KDbConnectionData; class KexiProjectData; -class KexiMainWidget; +class KexiObjectViewWidget; namespace KexiPart { class Info; class Part; } -#define KexiMainWindowSuper QWidget //KMainWindow - /** * @short Kexi's main window implementation */ class KEXIMAIN_EXPORT KexiMainWindow - : public QWidget /*KMainWindow*/, public KexiMainWindowIface, public KexiGUIMessageHandler + : public QMainWindow, public KexiMainWindowIface, public KexiGUIMessageHandler { Q_OBJECT @@ -62,7 +60,7 @@ //! @todo virtual QWidget* focusWidget() const; virtual QWidget* focusWidget() const { - return KexiMainWindowSuper::focusWidget(); + return QMainWindow::focusWidget(); } /*! Used by the main Kexi's routine. Creates a new Kexi main window. @@ -97,6 +95,9 @@ /*! \return true if the application window is in the User Mode. */ virtual bool userMode() const; + //! @return current global mode + Kexi::GlobalViewMode currentMode() const Q_DECL_OVERRIDE; + /*! \return true if opening of item \a item in \a viewMode mode is allowed. userMode() is taken into account as well as KexiPart::PartInfo::supportedUserViewModes() for \a item. */ @@ -157,6 +158,9 @@ /*! Closes window inside tab @a tabIndex. */ tristate closeWindowForTab(int tabIndex); + /*! Closes all windows. */ + tristate closeAllWindows(); + /*! Internal implementation. If \a doNotSaveChanges is true, messages asking for saving the will be skipped and the changes will be dropped. This should not be usually used, maybe except for test suites @@ -336,12 +340,18 @@ void projectOpened(); protected: + /*! Setups main menu with sub-menus */ + void setupMainMenu(); + /*! Setups main widget */ void setupMainWidget(); - /*! Creates the Project Navigator (if it's not yet created), - lookups items for current project and fills the nav. with not-opened items */ - void setupProjectNavigator(); + /*! Creates a view widget for object view, used in edit and design global view mode + if it's not yet created. This includes project navigator and property editor. */ + void setupObjectView(); + + //! Setups object view and assigns project to the project navigator. + void updateObjectView(); void setupContextHelp(); @@ -401,6 +411,8 @@ virtual void closeEvent(QCloseEvent *ev); + void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE; + //! Called by KexiMainWidget::queryClose() bool queryClose(); @@ -424,18 +436,22 @@ /*! Updates info label of the property editor by reusing properties provided by the current property set. - Read documentation of KexiPropertyEditorView class for information about accepted properties. - If the current property is 0 and @a textToDisplayForNullSet string is not empty, this string is displayed - (without icon or any other additional part). - If the current property is 0 and @a textToDisplayForNullSet string is empty, the info label widget becomes - hidden. + Read documentation of KexiPropertyPaneWidget class for information about accepted properties. + Implemented for KexiMainWindow. - @see KexiPropertyPaneViewBase::updateInfoLabelForPropertySet() */ - virtual void updatePropertyEditorInfoLabel(const QString& textToDisplayForNullSet); + @see KexiPropertyPaneWidget::updateInfoLabelForPropertySet() */ + void updatePropertyEditorInfoLabel() Q_DECL_OVERRIDE; //! Activates design tab when switching to design view, according to \a pluginId. void activateDesignTab(const QString &pluginId); + //! Sets current global mode + void setCurrentMode(Kexi::GlobalViewMode mode) Q_DECL_OVERRIDE; + + void beginPropertyPaneUpdate() Q_DECL_OVERRIDE; + + void endPropertyPaneUpdate() Q_DECL_OVERRIDE; + protected Q_SLOTS: tristate createNewProject(const KexiProjectData &projectData); @@ -535,9 +551,9 @@ void slotEditReplaceAll(); void slotActivateNavigator(); void slotActivateMainArea(); - void slotActivatePropertyEditor(); - void slotShowNavigator(); - void slotShowPropertyEditor(); + void slotActivatePropertyPane(); + void slotToggleProjectNavigator(); + void slotTogglePropertyEditor(); void slotViewDataMode(); void slotViewDesignMode(); void slotViewTextMode(); //!< sometimes called "SQL View" @@ -623,11 +639,14 @@ \return true on success and cancelled when the action was cancelled. */ //! @todo reenable when ported tristate printActionForItem(KexiPart::Item* item, PrintActionType action); - void slotSetProjectNavigatorVisible(bool set); - void slotSetPropertyEditorVisible(bool set); + //void slotSetProjectNavigatorVisible(bool set); + //void slotSetPropertyEditorVisible(bool set); + //void slotProjectNavigatorVisibilityChanged(bool visible); + //void slotPropertyEditorVisibilityChanged(bool visible); + //void slotMultiTabBarTabClicked(int id); + void slotCurrentModeChanged(Kexi::GlobalViewMode previousMode); + void slotProjectNavigatorVisibilityChanged(bool visible); - void slotPropertyEditorVisibilityChanged(bool visible); - void slotMultiTabBarTabClicked(int id); private: //! Adds action @a name with text @a text and optional shortcut @a shortcut. @@ -647,7 +666,7 @@ Private * const d; friend class KexiWindow; - friend class KexiMainWidget; + friend class KexiObjectViewWidget; }; #endif diff --git a/src/main/KexiMainWindow.cpp b/src/main/KexiMainWindow.cpp --- a/src/main/KexiMainWindow.cpp +++ b/src/main/KexiMainWindow.cpp @@ -36,7 +36,10 @@ #define KEXI_SKIP_REGISTERICONSRESOURCE #define KEXI_SKIP_SETUPPRIVATEICONSRESOURCE #include "KexiRegisterResource_p.h" +#include "KexiObjectViewWidget.h" +#include "KexiObjectViewTabWidget.h" #include +#include #include #include #include @@ -46,7 +49,7 @@ #include #include #include -#include +#include #include #include #include @@ -74,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +102,7 @@ #include #include #include +#include #if !defined(KexiVDebug) # define KexiVDebug if (0) qDebug() @@ -185,124 +190,6 @@ //------------------------------------------------- -KexiMainWindowTabWidget::KexiMainWindowTabWidget(QWidget *parent, KexiMainWidget* mainWidget) - : QTabWidget(parent) - , m_mainWidget(mainWidget) - , m_tabIndex(-1) -{ - m_closeAction = new QAction(koIcon("tab-close"), xi18n("&Close Tab"), this); - m_closeAction->setToolTip(xi18n("Close the current tab")); - m_closeAction->setWhatsThis(xi18n("Closes the current tab.")); - m_closeAllTabsAction = new QAction(xi18n("Cl&ose All Tabs"), this); - m_closeAllTabsAction->setToolTip(xi18n("Close all tabs")); - m_closeAllTabsAction->setWhatsThis(xi18n("Closes all tabs.")); - connect(m_closeAction, SIGNAL(triggered()), this, SLOT(closeTab())); - connect(m_closeAllTabsAction, SIGNAL(triggered()), this, SLOT(closeAllTabs())); -//! @todo insert window list in the corner widget as in firefox -#if 0 - // close-tab button: - QToolButton* rightWidget = new QToolButton(this); - rightWidget->setDefaultAction(m_closeAction); - rightWidget->setText(QString()); - rightWidget->setAutoRaise(true); - rightWidget->adjustSize(); - setCornerWidget(rightWidget, Qt::TopRightCorner); -#endif - setMovable(true); - setDocumentMode(true); - tabBar()->setExpanding(false); -} - -KexiMainWindowTabWidget::~KexiMainWindowTabWidget() -{ -} - -void KexiMainWindowTabWidget::paintEvent(QPaintEvent * event) -{ - if (count() > 0) - QTabWidget::paintEvent(event); - else - QWidget::paintEvent(event); -} - -void KexiMainWindowTabWidget::mousePressEvent(QMouseEvent *event) -{ - //! @todo KEXI3 test KexiMainWindowTabWidget's contextMenu event port from KTabWidget - if (event->button() == Qt::RightButton) { - int tab = tabBar()->tabAt(event->pos()); - const QPoint realPos(tabBar()->mapToGlobal(event->pos())); - if (QRect(tabBar()->mapToGlobal(QPoint(0,0)), - tabBar()->mapToGlobal(QPoint(tabBar()->width()-1, tabBar()->height()-1))).contains(realPos)) - { - showContextMenuForTab(tab, tabBar()->mapToGlobal(event->pos())); - return; - } - } - QTabWidget::mousePressEvent(event); -} - -void KexiMainWindowTabWidget::closeTab() -{ - KexiMainWindow *main = dynamic_cast(KexiMainWindowIface::global()); - if (main) { - main->closeWindowForTab(m_tabIndex); - } -} - -tristate KexiMainWindowTabWidget::closeAllTabs() -{ - tristate alternateResult = true; - QList windowList; - KexiMainWindow *main = dynamic_cast(KexiMainWindowIface::global()); - if (!main) { - return alternateResult; - } - for (int i = 0; i < count(); i++) { - KexiWindow *window = main->windowForTab(i); - if (window) { - windowList.append(window); - } - } - foreach (KexiWindow *window, windowList) { - tristate result = main->closeWindow(window); - if (result != true && result != false) { - return result; - } - if (result == false) { - alternateResult = false; - } - } - return alternateResult; -} - -void KexiMainWindowTabWidget::showContextMenuForTab(int index, const QPoint& point) -{ - QMenu menu; - if (index >= 0) { - menu.addAction(m_closeAction); - } - if (count() > 0) { - menu.addAction(m_closeAllTabsAction); - } - //! @todo add "&Detach Tab" - if (menu.actions().isEmpty()) { - return; - } - setTabIndexFromContextMenu(index); - menu.exec(point); -} - -void KexiMainWindowTabWidget::setTabIndexFromContextMenu(int clickedIndex) -{ - if (currentIndex() == -1) { - m_tabIndex = -1; - return; - } - m_tabIndex = clickedIndex; -} - -//------------------------------------------------- - static bool setupIconTheme(KLocalizedString *errorMessage, KLocalizedString *detailsErrorMessage) { // Register kexi resource first to have priority over the standard breeze theme. @@ -326,13 +213,13 @@ bool setupApplication() { #if defined Q_OS_WIN || defined Q_OS_MACOS - // Only this style matches current Kexi theme and can be supported/tested + // Only this style matches current KEXI theme and can be supported/tested const char *name = "breeze"; QScopedPointer style(QStyleFactory::create(name)); if (!style || style->objectName() != name) { qWarning() << qPrintable(QString("Could not find application style %1. " - "Kexi will not start. Please check if KEXI is properly installed. ") + "KEXI will not start. Please check if KEXI is properly installed. ") .arg(name)); return false; } @@ -366,7 +253,9 @@ KLocalizedString errorMessage; KLocalizedString detailsErrorMessage; - if (!setupIconTheme(&errorMessage, &detailsErrorMessage)) { + if (!setupIconTheme(&errorMessage, &detailsErrorMessage) + || !KexiStyle::setupApplication(&errorMessage)) + { if (detailsErrorMessage.isEmpty()) { KMessageBox::error(nullptr, errorMessage.toString()); } else { @@ -440,18 +329,18 @@ //------------------------------------------------- KexiMainWindow::KexiMainWindow(QWidget *parent) - : KexiMainWindowSuper(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"; - + if (d->userMode) { + //qDebug() << "starting up in the User Mode"; + } setAsDefaultHost(); //this is default host now. //get informed @@ -463,11 +352,12 @@ setAcceptDrops(true); setupActions(); setupMainWidget(); + setupMainMenu(); updateAppCaption(); if (!d->userMode) { setupContextHelp(); - setupPropertyEditor(); + //setupPropertyEditor(); } invalidateActions(); @@ -511,26 +401,25 @@ KexiWindow* KexiMainWindow::currentWindow() const { - return windowForTab(d->mainWidget->tabWidget()->currentIndex()); + if (!d->objectViewWidget || !d->objectViewWidget->tabWidget()) { + return 0; + } + return windowForTab(d->objectViewWidget->tabWidget()->currentIndex()); } KexiWindow* KexiMainWindow::windowForTab(int tabIndex) const { - if (!d->mainWidget->tabWidget()) + if (!d->objectViewWidget || !d->objectViewWidget->tabWidget()) return 0; - KexiWindowContainer *windowContainer - = dynamic_cast(d->mainWidget->tabWidget()->widget(tabIndex)); - if (!windowContainer) - return 0; - return windowContainer->window; + 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); - } + //foreach(const QKeySequence &shortcut, action->shortcuts()) { + //(void)new KexiMainMenuActionShortcut(shortcut, action, this); + //} } } @@ -546,8 +435,9 @@ actionCollection()->addAction(name, action); if (shortcut) { action->setShortcut(QKeySequence(shortcut)); - QShortcut *s = new QShortcut(action->shortcut(), this); - connect(s, SIGNAL(activated()), action, SLOT(trigger())); + action->setShortcutContext(Qt::ApplicationShortcut); + //QShortcut *s = new QShortcut(action->shortcut(), this); + //connect(s, SIGNAL(activated()), action, SLOT(trigger())); } return action; } @@ -566,7 +456,7 @@ ac->addAction("project_new", action = new KexiMenuWidgetAction(KStandardAction::New, this)); - addThreeDotsToActionText(action); + action->setText(xi18n("&New Project...")); action->setShortcuts(KStandardShortcut::openNew()); action->setToolTip(xi18n("Create a new project")); action->setWhatsThis( @@ -576,12 +466,19 @@ 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( @@ -629,7 +526,7 @@ ac->addAction("project_close", action = d->action_close = new KexiMenuWidgetAction( - koIcon("window-close"), xi18nc("Close Project", "&Close"), this)); + 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())); @@ -644,7 +541,7 @@ #ifdef KEXI_SHOW_UNIMPLEMENTED d->action_project_relations = addAction("project_relations", KexiIcon("database-relations"), - futureI18n("&Relationships..."), "Ctrl+R"); + 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()), @@ -706,7 +603,7 @@ //! @todo new QAction(xi18n("From Server..."), "network-server-database", 0, //! this, SLOT(slotImportServer()), actionCollection(), "project_import_server"); -#ifdef KEXI_QUICK_PRINTING_SUPPORT +#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")); @@ -728,6 +625,10 @@ 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 @@ -775,12 +676,10 @@ ac->addAction("edit_findprevious", d->action_edit_findprev = KStandardAction::findPrev( this, SLOT(slotEditFindPrevious()), this)); - d->action_edit_replace = 0; -//! @todo d->action_edit_replace = KStandardAction::replace( -//! this, SLOT(slotEditReplace()), actionCollection(), "project_print_preview" ); - d->action_edit_replace_all = 0; -//! @todo d->action_edit_replace_all = new QAction( xi18n("Replace All"), "", 0, -//! this, SLOT(slotEditReplaceAll()), actionCollection(), "edit_replaceall"); + 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); @@ -868,13 +767,14 @@ d->action_view_text_mode = 0; */ if (d->isProjectNavigatorVisible) { - d->action_show_nav = addAction("view_navigator", - xi18n("Show Project Navigator"), - "Alt+0"); + 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(slotShowNavigator())); + this, SLOT(slotToggleProjectNavigator())); } else { d->action_show_nav = 0; } @@ -904,41 +804,42 @@ //! @todo windows with "_3" prefix have conflicting auto shortcut set to Alt+3 -> remove that! if (!d->userMode) { - d->action_show_propeditor = addAction("view_propeditor", - xi18n("Show Property Editor"), "Alt+3"); - d->action_show_propeditor->setToolTip(xi18n("Show the Property Editor pane")); - d->action_show_propeditor->setWhatsThis(xi18n("Shows the Property Editor pane.")); + 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(slotShowPropertyEditor())); + this, SLOT(slotTogglePropertyEditor())); } else { d->action_show_propeditor = 0; } if (!d->userMode) { d->action_activate_propeditor = addAction("activate_propeditor", - xi18n("Activate Property Editor"), "Alt+-"); - d->action_activate_propeditor->setToolTip(xi18n("Activate the Property Editor pane")); - d->action_activate_propeditor->setWhatsThis(xi18n("Activates the Property Editor pane. If it is hidden, shows it first.")); + 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(slotActivatePropertyEditor())); + this, SLOT(slotActivatePropertyPane())); } else { d->action_activate_propeditor = 0; } - d->action_view_global_search = addAction("view_global_search", - xi18n("Switch to Global Search"), "Ctrl+K"); - d->action_view_global_search->setToolTip(xi18n("Switch to Global Search box")); - d->action_view_global_search->setWhatsThis(xi18n("Switches to Global Search box.")); + 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"), + d->action_data_save_row = createSharedAction(xi18n("&Accept"), 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.")); + d->action_data_save_row->setToolTip(xi18n("Accept changes made to the current record")); + d->action_data_save_row->setWhatsThis(xi18n("Accepts 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"), + d->action_data_cancel_row_changes = createSharedAction(xi18n("&Cancel"), 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")); @@ -966,48 +867,53 @@ 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 + //WINDOW MENU // additional 'Window' menu items d->action_window_next = addAction("window_next", xi18n("&Next Window"), "Alt+Right"); d->action_window_next->setToolTip(xi18n("Next window")); d->action_window_next->setWhatsThis(xi18n("Switches to the next window.")); - connect(d->action_window_next, SIGNAL(triggered()), - this, SLOT(activateNextWindow())); + connect(d->action_window_next, SIGNAL(triggered()), this, SLOT(activateNextWindow())); d->action_window_previous = addAction("window_previous", xi18n("&Previous Window"), "Alt+Left"); d->action_window_previous->setToolTip(xi18n("Previous window")); d->action_window_previous->setWhatsThis(xi18n("Switches to the previous window.")); - connect(d->action_window_previous, SIGNAL(triggered()), - this, SLOT(activatePreviousWindow())); - - d->action_tab_next = addAction("tab_next", xi18n("&Next Tab"), "Ctrl+Tab"); - d->action_tab_next->setToolTip(xi18n("Next tab")); - d->action_tab_next->setWhatsThis(xi18n("Switches to the next tab.")); + connect(d->action_window_previous, SIGNAL(triggered()), this, SLOT(activatePreviousWindow())); + + 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_tab_next = addAction("tab_next", koIcon("go-next"), + KStandardShortcut::label(KStandardShortcut::TabNext)); + d->action_tab_next->setWhatsThis(KStandardShortcut::whatsThis(KStandardShortcut::TabNext)); + d->action_tab_next->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::TabNext)); connect(d->action_tab_next, &QAction::triggered, this, &KexiMainWindow::activateNextTab); - d->action_tab_previous = addAction("tab_previous", xi18n("&Previous Tab"), "Ctrl+Shift+Tab"); - d->action_tab_previous->setToolTip(xi18n("Previous tab")); - d->action_tab_previous->setWhatsThis(xi18n("Switches to the previous tab.")); + d->action_tab_previous = addAction("tab_previous", koIcon("go-previous"), + KStandardShortcut::label(KStandardShortcut::TabPrev)); + d->action_tab_previous->setWhatsThis(KStandardShortcut::whatsThis(KStandardShortcut::TabPrev)); + d->action_tab_previous->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::TabPrev)); connect(d->action_tab_previous, &QAction::triggered, this, &KexiMainWindow::activatePreviousTab); d->action_window_fullscreen = KStandardAction::fullScreen(this, SLOT(toggleFullScreen(bool)), this, ac); ac->addAction("full_screen", d->action_window_fullscreen); - QList shortcuts; - shortcuts << d->action_window_fullscreen->shortcut() << QKeySequence("F11"); - d->action_window_fullscreen->setShortcuts(shortcuts); - QShortcut *s = new QShortcut(d->action_window_fullscreen->shortcut(), this); - connect(s, SIGNAL(activated()), d->action_window_fullscreen, SLOT(trigger())); - if (d->action_window_fullscreen->shortcuts().count() > 1) { - QShortcut *sa = new QShortcut(d->action_window_fullscreen->shortcuts().value(1), this); - connect(sa, SIGNAL(activated()), d->action_window_fullscreen, SLOT(trigger())); - } //SETTINGS MENU //! @todo put 'configure keys' into settings view @@ -1034,7 +940,7 @@ action = d->action_settings = new KexiMenuWidgetAction( KStandardAction::Preferences, this)); action->setObjectName("settings"); - action->setText(futureI18n("Settings...")); + //action->setText(futureI18n("Settings...")); action->setToolTip(futureI18n("Show KEXI settings")); action->setWhatsThis(futureI18n("Shows KEXI settings.")); connect(action, SIGNAL(triggered()), this, SLOT(slotSettings())); @@ -1049,12 +955,6 @@ ->setWhatsThis(xi18n("This shows useful tips on the use of this application.")); #endif - // GLOBAL - d->action_show_help_menu = addAction("help_show_menu", xi18nc("Help Menu", "Help"), "Alt+H"); - d->action_show_help_menu->setToolTip(xi18n("Show Help menu")); - d->action_show_help_menu->setWhatsThis(xi18n("Shows Help menu.")); - // (connection is added elsewhere) - // ----- declare action categories, so form's "assign action to button" // (and macros in the future) will be able to recognize category // of actions and filter them ----------------------------------- @@ -1189,12 +1089,15 @@ acat->addAction("activate_propeditor", Kexi::GlobalActionCategory); - acat->addAction("window_close", Kexi::GlobalActionCategory | Kexi::WindowActionCategory); - acat->setAllObjectTypesSupported("window_close", true); + 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("window_next", Kexi::GlobalActionCategory); + acat->addAction("tab_next", Kexi::GlobalActionCategory); - acat->addAction("window_previous", Kexi::GlobalActionCategory); + acat->addAction("tab_previous", Kexi::GlobalActionCategory); acat->addAction("full_screen", Kexi::GlobalActionCategory); @@ -1230,6 +1133,152 @@ 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 *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 *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 *settingsMenu = menu->addMenu(xi18n("&Settings")); + settingsMenu->addAction(d->action_window_fullscreen); + settingsMenu->addSeparator(); +#ifdef KEXI_SHOW_UNIMPLEMENTED + settingsMenu->addAction(d->action_settings); +#endif + } + { + QMenu *windowMenu = menu->addMenu(xi18n("&Window")); + windowMenu->addAction(d->action_tab_next); + windowMenu->addAction(d->action_tab_previous); + windowMenu->addSeparator(); + windowMenu->addAction(d->action_show_nav); + windowMenu->addAction(d->action_show_propeditor); + } + { + // 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(); @@ -1271,6 +1320,10 @@ 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) @@ -1282,7 +1335,7 @@ if (d->action_edit_paste_special_data_table) d->action_edit_paste_special_data_table->setEnabled(d->prj && !readOnly); -#ifdef KEXI_QUICK_PRINTING_SUPPORT +#ifdef KEXI_SHOW_UNIMPLEMENTED const bool printingActionsEnabled = currentWindow() && currentWindow()->part()->info()->isPrintingSupported() && !currentWindow()->neverSaved(); @@ -1307,18 +1360,19 @@ if (d->action_show_nav) d->action_show_nav->setEnabled(d->prj); d->action_activate_mainarea->setEnabled(d->prj); - if (d->action_show_propeditor) - d->action_show_propeditor->setEnabled(d->prj); -#ifdef KEXI_SHOW_CONTEXT_HELP - d->action_show_helper->setEnabled(d->prj); -#endif //CREATE MENU if (d->tabbedToolBar && d->tabbedToolBar->createWidgetToolBar()) d->tabbedToolBar->createWidgetToolBar()->setEnabled(d->prj); // DATA MENU + // WINDOW MENU + if (d->objectViewWidget) { + d->action_tab_next->setEnabled(d->objectViewWidget->tabWidget()->count() > 1); + d->action_tab_previous->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( @@ -1329,11 +1383,12 @@ ); //DOCKS - if (d->navigator) { - d->navigator->setEnabled(d->prj); + if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { + d->objectViewWidget->projectNavigator()->setEnabled(d->prj); + } + if (d->objectViewWidget && d->objectViewWidget->propertyPane()) { + d->objectViewWidget->propertyPane()->setEnabled(d->prj); } - if (d->propEditor) - d->propEditorTabWidget->setEnabled(d->prj); } tristate KexiMainWindow::startup() @@ -1424,7 +1479,7 @@ // success d->prj = prj.take(); - setupProjectNavigator(); + d->modeSelector->setCurrentMode(Kexi::EditGlobalMode); d->prj->data()->setLastOpened(QDateTime::currentDateTime()); Kexi::recentProjects()->addProjectData(*d->prj->data()); updateReadOnlyState(); @@ -1434,9 +1489,6 @@ QTimer::singleShot(1, this, SLOT(slotAutoOpenObjectsLater())); if (d->tabbedToolBar) { d->tabbedToolBar->showTab("create");// not needed since create toolbar already shows toolbar! move when kexi starts - d->tabbedToolBar->showTab("data"); - d->tabbedToolBar->showTab("external"); - d->tabbedToolBar->showTab("tools"); d->tabbedToolBar->hideTab("form");//temporalily until createToolbar is split d->tabbedToolBar->hideTab("report");//temporalily until createToolbar is split @@ -1519,8 +1571,8 @@ { const bool readOnly = d->prj && d->prj->dbConnection() && d->prj->dbConnection()->options()->isReadOnly(); //! @todo KEXI3 show read-only flag in the GUI because we have no statusbar - if (d->navigator) { - d->navigator->setReadOnly(readOnly); + if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { + d->objectViewWidget->projectNavigator()->setReadOnly(readOnly); } // update "insert ....." actions for every part @@ -1756,23 +1808,27 @@ if (!d->prj->closeConnection()) return false; - if (d->navigator) { - d->navWasVisibleBeforeProjectClosing = d->navDockWidget->isVisible(); - d->navDockWidget->hide(); - d->navigator->setProject(0); - slotProjectNavigatorVisibilityChanged(true); // hide side tab + if (d->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->propEditorDockWidget) - d->propEditorDockWidget->hide(); - + 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; @@ -1796,7 +1852,10 @@ void KexiMainWindow::setupMainWidget() { - QVBoxLayout *vlyr = new QVBoxLayout(this); + QWidget *centralWidget = new QWidget; + setCentralWidget(centralWidget); + + QVBoxLayout *vlyr = new QVBoxLayout(centralWidget); vlyr->setContentsMargins(0, 0, 0, 0); vlyr->setSpacing(0); @@ -1810,8 +1869,8 @@ KexiUtils::marginHint() / 2, KexiUtils::marginHint() / 2); d->tabbedToolBar = new KexiTabbedToolBar(tabbedToolBarContainer); - Q_ASSERT(d->action_view_global_search); - connect(d->action_view_global_search, SIGNAL(triggered()), + 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 @@ -1827,53 +1886,46 @@ 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(); + } - KMultiTabBar *mtbar = new KMultiTabBar(KMultiTabBar::Left); - mtbar->setStyle(KMultiTabBar::VSNET); - mainWidgetContainerLyr->addWidget(mtbar); - d->multiTabBars.insert(mtbar->position(), mtbar); - - d->mainWidget = new KexiMainWidget(); - d->mainWidget->setParent(this); - - d->mainWidget->tabWidget()->setTabsClosable(true); - connect(d->mainWidget->tabWidget(), SIGNAL(tabCloseRequested(int)), - this, SLOT(closeWindowForTab(int))); - mainWidgetContainerLyr->addWidget(d->mainWidget, 1); - - mtbar = new KMultiTabBar(KMultiTabBar::Right); - mtbar->setStyle(KMultiTabBar::VSNET); - mainWidgetContainerLyr->addWidget(mtbar); - d->multiTabBars.insert(mtbar->position(), mtbar); + d->globalViewStack = new QStackedWidget; + mainWidgetContainerLyr->addWidget(d->globalViewStack, 1); } -void KexiMainWindow::slotSetProjectNavigatorVisible(bool set) -{ - if (d->navDockWidget) - d->navDockWidget->setVisible(set); -} +//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::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::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::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) { @@ -1898,150 +1950,130 @@ } } return area; -} +}*/ -void KexiMainWindow::setupProjectNavigator() +void KexiMainWindow::setupObjectView() { - if (!d->isProjectNavigatorVisible) + if (d->objectViewWidget) { return; - - if (d->navigator) { - d->navDockWidget->show(); } - else { - KexiDockableWidget* navDockableWidget = new KexiDockableWidget; - d->navigator = new KexiProjectNavigator(navDockableWidget); - kexiTester() << KexiTestObject(d->navigator, "KexiProjectNavigator"); - - navDockableWidget->setWidget(d->navigator); - - d->navDockWidget = new KexiDockWidget(d->navigator->windowTitle(), d->mainWidget); - d->navDockWidget->setObjectName("ProjectNavigatorDockWidget"); - d->mainWidget->addDockWidget( - applyRightToLeftToDockArea(Qt::LeftDockWidgetArea), d->navDockWidget, - Qt::Vertical); - navDockableWidget->setParent(d->navDockWidget); - d->navDockWidget->setWidget(navDockableWidget); + 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()); - if (!projectNavigatorSize.isNull()) { - navDockableWidget->setSizeHint(projectNavigatorSize); - } + const QSize propertyEditorSize = mainWindowGroup.readEntry("PropertyEditorSize", QSize()); + d->objectViewWidget->setSidebarWidths(projectNavigatorSize.isValid() ? projectNavigatorSize.width() : -1, + propertyEditorSize.isValid() ? propertyEditorSize.width() : -1); + } - connect(d->navDockWidget, SIGNAL(visibilityChanged(bool)), - this, SLOT(slotProjectNavigatorVisibilityChanged(bool))); + 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(d->navigator, SIGNAL(openItem(KexiPart::Item*,Kexi::ViewMode)), + connect(navigator, SIGNAL(openItem(KexiPart::Item*,Kexi::ViewMode)), this, SLOT(openObject(KexiPart::Item*,Kexi::ViewMode))); - connect(d->navigator, SIGNAL(openOrActivateItem(KexiPart::Item*,Kexi::ViewMode)), + connect(navigator, SIGNAL(openOrActivateItem(KexiPart::Item*,Kexi::ViewMode)), this, SLOT(openObjectFromNavigator(KexiPart::Item*,Kexi::ViewMode))); - connect(d->navigator, SIGNAL(newItem(KexiPart::Info*)), + connect(navigator, SIGNAL(newItem(KexiPart::Info*)), this, SLOT(newObject(KexiPart::Info*))); - connect(d->navigator, SIGNAL(removeItem(KexiPart::Item*)), + connect(navigator, SIGNAL(removeItem(KexiPart::Item*)), this, SLOT(removeObject(KexiPart::Item*))); - connect(d->navigator->model(), SIGNAL(renameItem(KexiPart::Item*,QString,bool*)), + connect(navigator->model(), SIGNAL(renameItem(KexiPart::Item*,QString,bool*)), this, SLOT(renameObject(KexiPart::Item*,QString,bool*))); - connect(d->navigator->model(), SIGNAL(changeItemCaption(KexiPart::Item*,QString,bool*)), + connect(navigator->model(), SIGNAL(changeItemCaption(KexiPart::Item*,QString,bool*)), this, SLOT(setObjectCaption(KexiPart::Item*,QString,bool*))); - connect(d->navigator, SIGNAL(executeItem(KexiPart::Item*)), + connect(navigator, SIGNAL(executeItem(KexiPart::Item*)), this, SLOT(executeItem(KexiPart::Item*))); - connect(d->navigator, SIGNAL(exportItemToClipboardAsDataTable(KexiPart::Item*)), + connect(navigator, SIGNAL(exportItemToClipboardAsDataTable(KexiPart::Item*)), this, SLOT(copyItemToClipboardAsDataTable(KexiPart::Item*))); - connect(d->navigator, SIGNAL(exportItemToFileAsDataTable(KexiPart::Item*)), + connect(navigator, SIGNAL(exportItemToFileAsDataTable(KexiPart::Item*)), this, SLOT(exportItemAsDataTable(KexiPart::Item*))); #ifdef KEXI_QUICK_PRINTING_SUPPORT - connect(d->navigator, SIGNAL(printItem(KexiPart::Item*)), + connect(navigator, SIGNAL(printItem(KexiPart::Item*)), this, SLOT(printItem(KexiPart::Item*))); - connect(d->navigator, SIGNAL(pageSetupForItem(KexiPart::Item*)), + connect(navigator, SIGNAL(pageSetupForItem(KexiPart::Item*)), this, SLOT(showPageSetupForItem(KexiPart::Item*))); #endif - connect(d->navigator, SIGNAL(selectionChanged(KexiPart::Item*)), + connect(navigator, SIGNAL(selectionChanged(KexiPart::Item*)), this, SLOT(slotPartItemSelectedInNavigator(KexiPart::Item*))); } - if (d->prj->isConnected()) { - QString partManagerErrorMessages; - - if (!partManagerErrorMessages.isEmpty()) { - showWarningContinueMessage(partManagerErrorMessages, QString(), - "ShowWarningsRelatedToPluginsLoading"); - } - d->navigator->setProject(d->prj, QString()/*all classes*/, &partManagerErrorMessages); - - } - connect(d->prj, SIGNAL(newItemStored(KexiPart::Item*)), d->navigator->model(), SLOT(slotAddItem(KexiPart::Item*))); - connect(d->prj, SIGNAL(itemRemoved(KexiPart::Item)), d->navigator->model(), SLOT(slotRemoveItem(KexiPart::Item))); - d->navigator->setFocus(); + if (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; + /*if (d->forceShowProjectNavigatorOnCreation) { + slotShowNavigator(); + d->forceShowProjectNavigatorOnCreation = false; + } else if (d->forceHideProjectNavigatorOnCreation) { + d->forceHideProjectNavigatorOnCreation = false; + }*/ } invalidateActions(); } -void KexiMainWindow::slotLastActions() -{ -} - -void KexiMainWindow::setupPropertyEditor() +void KexiMainWindow::updateObjectView() { - if (!d->propEditor) { - KConfigGroup mainWindowGroup(d->config->group("MainWindow")); -//! @todo FIX LAYOUT PROBLEMS - d->propEditorDockWidget = new KexiDockWidget(xi18n("Property Editor"), d->mainWidget); - d->propEditorDockWidget->setObjectName("PropertyEditorDockWidget"); - d->mainWidget->addDockWidget( - applyRightToLeftToDockArea(Qt::RightDockWidgetArea), d->propEditorDockWidget, - Qt::Vertical - ); - connect(d->propEditorDockWidget, SIGNAL(visibilityChanged(bool)), - this, SLOT(slotPropertyEditorVisibilityChanged(bool))); + setupObjectView(); - d->propEditorDockableWidget = new KexiDockableWidget(d->propEditorDockWidget); - d->propEditorDockWidget->setWidget(d->propEditorDockableWidget); - const QSize propertyEditorSize = mainWindowGroup.readEntry("PropertyEditorSize", QSize()); - if (!propertyEditorSize.isNull()) { - d->propEditorDockableWidget->setSizeHint(propertyEditorSize); - } - - QWidget *propEditorDockWidgetContents = new QWidget(d->propEditorDockableWidget); - d->propEditorDockableWidget->setWidget(propEditorDockWidgetContents); - QVBoxLayout *propEditorDockWidgetContentsLyr = new QVBoxLayout(propEditorDockWidgetContents); - propEditorDockWidgetContentsLyr->setContentsMargins(0, 0, 0, 0); - - d->propEditorTabWidget = new QTabWidget(propEditorDockWidgetContents); - d->propEditorTabWidget->setDocumentMode(true); - propEditorDockWidgetContentsLyr->addWidget(d->propEditorTabWidget); - d->propEditor = new KexiPropertyEditorView(d->propEditorTabWidget); - d->propEditorTabWidget->setWindowTitle(d->propEditor->windowTitle()); - d->propEditorTabWidget->addTab(d->propEditor, xi18n("Properties")); -//! @todo REMOVE? d->propEditor->installEventFilter(this); - - KConfigGroup propertyEditorGroup(d->config->group("PropertyEditor")); - QFont f(KexiUtils::smallestReadableFont()); - const qreal pointSizeF = propertyEditorGroup.readEntry("FontPointSize", -1.0f); // points are more accurate - if (pointSizeF > 0.0) { - f.setPointSizeF(pointSizeF); - } else { - const int pixelSize = propertyEditorGroup.readEntry("FontSize", -1); // compatibility with KEXI 2.x - if (pixelSize > 0) { - f.setPixelSize(pixelSize); + 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"); } } - d->propEditorTabWidget->setFont(f); - - d->enable_slotPropertyEditorVisibilityChanged = false; - d->propEditorDockWidget->setVisible(false); - d->enable_slotPropertyEditorVisibilityChanged = true; } } +void KexiMainWindow::slotLastActions() +{ +} + void KexiMainWindow::slotPartLoaded(KexiPart::Part* p) { if (!p) @@ -2092,7 +2124,17 @@ void KexiMainWindow::closeEvent(QCloseEvent *ev) { - d->mainWidget->closeEvent(ev); + if (queryClose()) { + ev->accept(); + } else { + ev->ignore(); + } +} + +void KexiMainWindow::resizeEvent(QResizeEvent *e) +{ + QMainWindow::resizeEvent(e); + //qDebug() << "===" << e->size() << size() << isVisible(); } static const QSize KEXI_MIN_WINDOW_SIZE(1024, 768); @@ -2118,7 +2160,6 @@ resize(KEXI_MIN_WINDOW_SIZE); } } - // Saved settings } void @@ -2135,12 +2176,17 @@ mainWindowGroup.writeEntry("Geometry", geometry()); } - if (d->navigator) - mainWindowGroup.writeEntry("ProjectNavigatorSize", d->navigator->parentWidget()->size()); - - if (d->propEditorDockableWidget) - mainWindowGroup.writeEntry("PropertyEditorSize", d->propEditorDockableWidget->size()); - + 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(); } @@ -2171,31 +2217,34 @@ KexiPart::Part *prevWindowPart, Kexi::ViewMode prevViewMode, KexiPart::Part *curWindowPart, Kexi::ViewMode curViewMode) { - if (!d->propEditorTabWidget) + 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->propEditorTabWidget->currentIndex()); + d->objectViewWidget->propertyPane()->currentIndex()); } } //delete old custom tabs (other than 'property' tab) - const int count = d->propEditorTabWidget->count(); + const int count = d->objectViewWidget->propertyEditorTabWidget()->count(); for (int i = 1; i < count; i++) - d->propEditorTabWidget->removeTab(1); + d->objectViewWidget->propertyEditorTabWidget()->removeTab(1); +#endif } //don't change anything if part is not switched nor view mode changed @@ -2210,16 +2259,20 @@ if (curWindowPart) { //recreate custom tabs - curWindowPart->setupCustomPropertyPanelTabs(d->propEditorTabWidget); + 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->propEditorTabWidget->setCurrentIndex( + d->objectViewWidget->propertyEditorTabWidget()->setCurrentIndex( d->recentlySelectedPropertyPanelPages[ curWindowPart ] ); } +#endif } - +//#endif //new part for 'previously setup tabs' d->partForPreviouslySetupPropertyPanelTabs = curWindowPart; } @@ -2245,6 +2298,8 @@ if (windowChanged) { if (currentWindow() && currentWindow()->currentViewMode() != 0 && window) { + setCurrentMode(viewModeToGlobal(currentWindow()->currentViewMode())); + //on opening new dialog it can be 0; we don't want this d->updatePropEditorVisibility(currentWindow()->currentViewMode()); @@ -2278,7 +2333,7 @@ //qDebug(); d->focus_before_popup = &window; - d->mainWidget->tabWidget()->setCurrentWidget(window.parentWidget()/*container*/); + d->objectViewWidget->tabWidget()->setCurrentWidget(window.parentWidget()/*container*/); window.activate(); return true; } @@ -2309,12 +2364,20 @@ void KexiMainWindow::activateNextTab() { - //! @todo + int index = d->objectViewWidget->tabWidget()->currentIndex() + 1; + if (index >= d->objectViewWidget->tabWidget()->count()) { + index = 0; + } + d->objectViewWidget->tabWidget()->setCurrentIndex(index); } void KexiMainWindow::activatePreviousTab() { - //! @todo + int index = d->objectViewWidget->tabWidget()->currentIndex() - 1; + if (index < 0) { + index = d->objectViewWidget->tabWidget()->count() - 1; + } + d->objectViewWidget->tabWidget()->setCurrentIndex(index); } void @@ -2352,8 +2415,10 @@ KexiProject *prj = new KexiProject(data, this); connect(prj, SIGNAL(itemRenamed(KexiPart::Item,QString)), this, SLOT(slotObjectRenamed(KexiPart::Item,QString))); - if (d->navigator){ - connect(prj, SIGNAL(itemRemoved(KexiPart::Item)), d->navigator->model(), SLOT(slotRemoveItem(KexiPart::Item))); + if (d->objectViewWidget && d->objectViewWidget->projectNavigator()){ + connect(prj, SIGNAL(itemRemoved(KexiPart::Item)), + d->objectViewWidget->projectNavigator()->model(), + SLOT(slotRemoveItem(KexiPart::Item))); } return prj; } @@ -2393,9 +2458,9 @@ d->tabbedToolBar->hideMainMenu(); } d->prj = prj.take(); - setupProjectNavigator(); d->prj->data()->setLastOpened(QDateTime::currentDateTime()); Kexi::recentProjects()->addProjectData(*d->prj->data()); + d->modeSelector->setCurrentMode(Kexi::EditGlobalMode); invalidateActions(); updateAppCaption(); @@ -2467,7 +2532,7 @@ return false; } //file-based project - qDebug() << "Project File: " << aFileName; + //qDebug() << "Project File:" << aFileName; KDbConnectionData fileConnData; fileConnData.setDatabaseName(aFileName); QString detectedDriverId; @@ -2665,7 +2730,9 @@ if (!d->prj) return; KexiWindow *w = KexiInternalPart::createKexiWindowInstance("org.kexi-project.relations", this); - activateWindow(*w); + if (w) { + activateWindow(*w); + } } void KexiMainWindow::slotImportFile() @@ -2688,38 +2755,42 @@ void KexiMainWindow::slotActivateNavigator() { - if (!d->navigator) { + if (!d->objectViewWidget || !d->objectViewWidget->projectNavigator()) { return; } - d->navigator->setFocus(); + d->objectViewWidget->projectNavigator()->setFocus(); } void KexiMainWindow::slotActivateMainArea() { if (currentWindow()) currentWindow()->setFocus(); } -void KexiMainWindow::slotActivatePropertyEditor() +void KexiMainWindow::slotActivatePropertyPane() { - if (!d->propEditor) { + if (!d->objectViewWidget || !d->objectViewWidget->propertyPane()) { return; } - if (d->propEditorTabWidget->currentWidget()) - d->propEditorTabWidget->currentWidget()->setFocus(); + d->objectViewWidget->propertyPane()->setFocus(); +// if (d->objectViewWidget->propertyPane()->currentWidget()) { +// d->objectViewWidget->propertyPane()->currentWidget()->setFocus(); +// } } -void KexiMainWindow::slotShowNavigator() +void KexiMainWindow::slotToggleProjectNavigator() { - if (d->navDockWidget) - d->navDockWidget->setVisible(!d->navDockWidget->isVisible()); + if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { + d->setProjectNavigatorVisible(!d->objectViewWidget->projectNavigator()->isVisible(), Private::ShowAnimated); + } } -void KexiMainWindow::slotShowPropertyEditor() +void KexiMainWindow::slotTogglePropertyEditor() { - if (d->propEditorDockWidget) - d->propEditorDockWidget->setVisible(!d->propEditorDockWidget->isVisible()); + if (d->objectViewWidget && d->objectViewWidget->propertyPane()) { + d->objectViewWidget->setPropertyPaneVisible(!d->objectViewWidget->propertyPane()->isVisible()); + } } tristate KexiMainWindow::switchToViewMode(KexiWindow& window, Kexi::ViewMode viewMode) @@ -2744,6 +2815,8 @@ currentWindow()->part()->info()->name())); return false; } + setCurrentMode(viewModeToGlobal(viewMode)); + updateCustomPropertyPanelTabs(currentWindow()->part(), prevViewMode, currentWindow()->part(), viewMode); tristate res = currentWindow()->switchToViewMode(viewMode); @@ -2975,6 +3048,30 @@ 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() @@ -2995,10 +3092,10 @@ d->insideCloseWindow = true; if (window == currentWindow() && !window->isAttached()) { - if (d->propEditor) { + if (d->propertyEditor()) { // ah, closing detached window - better switch off property buffer right now... d->propertySet = 0; - d->propEditor->editor()->changeSet(0); + d->propertyEditor()->changeSet(0); } } @@ -3078,18 +3175,18 @@ } } else { //not dirty now - if (d->navigator) { - d->navigator->updateItemName(*window->partItem(), false); + 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->mainWidget->tabWidget()->removeTab( - d->mainWidget->tabWidget()->indexOf(windowContainer)); + d->objectViewWidget->tabWidget()->removeTab( + d->objectViewWidget->tabWidget()->indexOf(windowContainer)); #ifdef KEXI_QUICK_PRINTING_SUPPORT //also remove from 'print setup dialogs' cache, if needed @@ -3103,8 +3200,8 @@ //focus navigator if nothing else available if (d->openedWindowsCount() == 0) { - if (d->navigator) { - d->navigator->setFocus(); + if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { + d->objectViewWidget->projectNavigator()->setFocus(); } d->updatePropEditorVisibility(Kexi::NoViewMode); } @@ -3124,7 +3221,7 @@ d->executeActionWhenPendingJobsAreFinished(); } #endif - d->mainWidget->slotCurrentTabIndexChanged(d->mainWidget->tabWidget()->currentIndex()); + //d->objectViewWidget->slotCurrentTabIndexChanged(d->objectViewWidget->tabWidget()->currentIndex()); showDesignTabIfNeeded(0); if (currentWindow()) { @@ -3139,8 +3236,9 @@ QWidget* KexiMainWindow::findWindow(QWidget *w) { while (w && !acceptsSharedActions(w)) { - if (w == d->propEditorDockWidget) + if (w == d->objectViewWidget->propertyPane()) { return currentWindow(); + } w = w->parentWidget(); } return w; @@ -3250,7 +3348,7 @@ *openingCancelled = false; bool alreadyOpened = false; - KexiWindowContainer *windowContainer = 0; + QWidget *windowContainer = 0; if (window) { if (viewMode != window->currentViewMode()) { @@ -3271,14 +3369,12 @@ 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 - windowContainer = new KexiWindowContainer(d->mainWidget->tabWidget()); d->setWindowContainerExistsFor(item->identifier(), true); - const int tabIndex = d->mainWidget->tabWidget()->addTab( - windowContainer, - QIcon::fromTheme(part ? part->info()->iconName() : QString()), - KexiWindow::windowTitleForItem(*item)); - d->mainWidget->tabWidget()->setTabToolTip(tabIndex, KexiPart::fullCaptionForItem(item, part)); + d->objectViewWidget->tabWidget()->setTabToolTip(tabIndex, KexiPart::fullCaptionForItem(item, part)); QString whatsThisText; if (part) { whatsThisText = xi18nc("@info", @@ -3289,32 +3385,29 @@ whatsThisText = xi18nc("@info", "Tab for %1.", item->captionOrName()); } - d->mainWidget->tabWidget()->setTabWhatsThis(tabIndex, whatsThisText); - d->mainWidget->tabWidget()->setCurrentWidget(windowContainer); + 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) { - windowContainer->setWindow(window); + d->objectViewWidget->tabWidget()->setWindowForTab(tabIndex, window); // update text and icon - d->mainWidget->tabWidget()->setTabText( - d->mainWidget->tabWidget()->indexOf(windowContainer), - window->windowTitle()); - d->mainWidget->tabWidget()->setTabIcon( - d->mainWidget->tabWidget()->indexOf(windowContainer), - window->windowIcon()); + 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->mainWidget->tabWidget()->removeTab( - d->mainWidget->tabWidget()->indexOf(windowContainer)); + d->objectViewWidget->tabWidget()->removeTab( + d->objectViewWidget->tabWidget()->indexOf(windowContainer)); delete windowContainer; updateCustomPropertyPanelTabs(0, Kexi::NoViewMode); //revert //! @todo add error msg... @@ -3440,7 +3533,7 @@ } if (!it->neverSaved()) { //only add stored objects to the browser - d->navigator->model()->slotAddItem(it); + d->objectViewWidget->projectNavigator()->model()->slotAddItem(it); } return openObject(it, Kexi::DesignViewMode, openingCancelled); } @@ -3613,22 +3706,23 @@ void KexiMainWindow::acceptPropertySetEditing() { - if (d->propEditor) - d->propEditor->editor()->acceptInput(); + if (d->propertyEditor()) { + 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")); + // << "window:" << (window ? window->windowTitle() : QString("NULL")); if (_currentWindow && _currentWindow != window) { d->propertySet = 0; //we'll need to move to another prop. set return; } - if (d->propEditor) { + if (d->propertyEditor()) { KPropertySet *newSet = _currentWindow ? _currentWindow->propertySet() : 0; if (!newSet || (force || static_cast(d->propertySet) != newSet)) { d->propertySet = newSet; @@ -3641,12 +3735,11 @@ options |= KPropertyEditorView::SetOption::AlphabeticalOrder; } - if (propertyToSelect.isEmpty()) { - d->propEditor->editor()->changeSet(d->propertySet, options); - } - else { - d->propEditor->editor()->changeSet(d->propertySet, propertyToSelect, options); - } + d->objectViewWidget->propertyPane()->changePropertySet( + d->propertySet, propertyToSelect, options, + (_currentWindow && _currentWindow->selectedView()) + ? _currentWindow->selectedView()->textToDisplayForNullSet() + : QString()); } } } @@ -3657,13 +3750,13 @@ KexiPart::Item *item = window->partItem(); //update text in navigator and app. caption if (!d->userMode) { - d->navigator->updateItemName(*item, window->isDirty()); + d->objectViewWidget->projectNavigator()->updateItemName(*item, window->isDirty()); } invalidateActions(); updateAppCaption(); - d->mainWidget->tabWidget()->setTabText( - d->mainWidget->tabWidget()->indexOf(window->parentWidget()), + d->objectViewWidget->tabWidget()->setTabText( + d->objectViewWidget->tabWidget()->indexOf(window->parentWidget()), window->windowTitle()); } @@ -4101,7 +4194,7 @@ void KexiMainWindow::slotEditCopySpecialDataTable() { - KexiPart::Item* item = d->navigator->selectedPartItem(); + KexiPart::Item* item = d->objectViewWidget->projectNavigator()->selectedPartItem(); if (item) copyItemToClipboardAsDataTable(item); } @@ -4222,9 +4315,9 @@ KexiPart::Item *item = d->prj->itemForPluginId(pluginId, name); if (!item) return; - if (d->navigator) { - slotSetProjectNavigatorVisible(true); - d->navigator->selectItem(*item); + if (d->objectViewWidget && d->objectViewWidget->projectNavigator()) { + d->setProjectNavigatorVisible(true, Private::ShowAnimated); + d->objectViewWidget->projectNavigator()->selectItem(*item); } } @@ -4256,9 +4349,31 @@ d->tabbedToolBar->addAction(toolBarName, action); } -void KexiMainWindow::updatePropertyEditorInfoLabel(const QString& textToDisplayForNullSet) +void KexiMainWindow::updatePropertyEditorInfoLabel() +{ + if (d->objectViewWidget && d->objectViewWidget->propertyPane()) { + d->objectViewWidget->propertyPane()->updateInfoLabelForPropertySet( + (currentWindow() && currentWindow()->selectedView()) + ? currentWindow()->selectedView()->textToDisplayForNullSet() + : QString()); + } +} + +void KexiMainWindow::beginPropertyPaneUpdate() { - d->propEditor->updateInfoLabelForPropertySet(d->propertySet, textToDisplayForNullSet); + 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) @@ -4433,3 +4548,64 @@ showMaximized(); } } + +Kexi::GlobalViewMode KexiMainWindow::currentMode() const +{ + return d->modeSelector->currentMode(); +} + +void KexiMainWindow::setCurrentMode(Kexi::GlobalViewMode mode) +{ + d->modeSelector->setCurrentMode(mode); +} + +void KexiMainWindow::slotCurrentModeChanged(Kexi::GlobalViewMode previousMode) +{ + const Kexi::ViewMode viewMode = currentWindow() + ? currentWindow()->currentViewMode() : Kexi::NoViewMode; + switch (d->modeSelector->currentMode()) { + case Kexi::WelcomeGlobalMode: + break; + case Kexi::ProjectGlobalMode: + break; + case Kexi::EditGlobalMode: + updateObjectView(); + d->globalViewStack->setCurrentWidget(d->objectViewWidget); + if (viewMode == Kexi::DesignViewMode || viewMode == Kexi::TextViewMode) { + if (true != switchToViewMode(*currentWindow(), Kexi::DataViewMode)) { + setCurrentMode(previousMode); + } + } + break; + case Kexi::DesignGlobalMode: + updateObjectView(); + d->globalViewStack->setCurrentWidget(d->objectViewWidget); + if (viewMode == Kexi::DataViewMode) { + Kexi::ViewMode newViewMode; + if (currentWindow()->supportsViewMode(Kexi::TextViewMode) + && d->modeSelector->keyboardModifiers() == Qt::CTRL) + { + newViewMode = Kexi::TextViewMode; + } else { + newViewMode = Kexi::DesignViewMode; + } + if (true != switchToViewMode(*currentWindow(), newViewMode)) { + setCurrentMode(previousMode); + } + } + break; + case Kexi::HelpGlobalMode: + break; + case Kexi::NoGlobalMode: + 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.h b/src/main/KexiMainWindow_p.h --- a/src/main/KexiMainWindow_p.h +++ b/src/main/KexiMainWindow_p.h @@ -32,29 +32,31 @@ #include #include #include +#include +#include #include #include #include #include #include #include -#include #include #include "KexiMainWindow.h" #include "KexiSearchLineEdit.h" #include "KexiUserFeedbackAgent.h" #include "KexiMenuWidget.h" #include "kexifinddialog.h" #include "KexiStartup.h" +#include "KexiGlobalViewModeSelector.h" #include #include -#include #include #include #include #include +#include #define KEXI_NO_PROCESS_EVENTS @@ -69,6 +71,7 @@ class QPainter; class KexiAssistantPage; class KexiProjectNavigator; +class KPropertyEditorView; //! @short Main application's tabbed toolbar class KexiTabbedToolBar : public QTabWidget @@ -93,8 +96,6 @@ QRect tabRect(int index) const; - KHelpMenu *helpMenu() const; - void addSearchableModel(KexiSearchableModel *model); void removeSearchableModel(KexiSearchableModel *model); @@ -148,23 +149,6 @@ Private * const d; }; -//! @internal window container created to speedup opening new tabs -class KexiWindowContainer : public QWidget -{ - Q_OBJECT -public: - explicit KexiWindowContainer(QWidget* parent); - - virtual ~KexiWindowContainer(); - - void setWindow(KexiWindow* w); - - QPointer window; - -private: - QVBoxLayout *lyr; -}; - class EmptyMenuContentWidget : public QWidget { Q_OBJECT @@ -285,7 +269,6 @@ QPropertyAnimation tabBarAnimation; QGraphicsOpacityEffect tabBarOpacityEffect; int rolledUpIndex; - KHelpMenu *helpMenu; KexiSearchLineEdit *searchLineEdit = nullptr; void setCurrentTab(const QString& name); void hideTab(const QString& name); @@ -345,70 +328,6 @@ void polish(QWidget* widget) Q_DECL_OVERRIDE; }; -class KexiMainWidget; - -//! @internal tab widget acting as central widget for KexiMainWindow -class KexiMainWindowTabWidget : public QTabWidget -{ - Q_OBJECT -public: - KexiMainWindowTabWidget(QWidget *parent, KexiMainWidget *mainWidget); - virtual ~KexiMainWindowTabWidget(); -public Q_SLOTS: - void closeTab(); - tristate closeAllTabs(); - -protected: - //! Shows context menu for tab at @a index at point @a point. - //! If @a index is -1, context menu for empty area is requested. - void showContextMenuForTab(int index, const QPoint& point); - - //! Reimplemented to hide frame when no tabs are displayed - virtual void paintEvent(QPaintEvent * event); - - virtual void mousePressEvent(QMouseEvent *event); - - KexiMainWidget *m_mainWidget; - QAction *m_closeAction; - QAction *m_closeAllTabsAction; - -private: - int m_tabIndex; - - void setTabIndexFromContextMenu(int clickedIndex); -}; - -//! @short A widget being main part of KexiMainWindow -class KexiMainWidget : public KMainWindow -{ - Q_OBJECT -public: - KexiMainWidget(); - - virtual ~KexiMainWidget(); - - void setParent(KexiMainWindow* mainWindow); - - KexiMainWindowTabWidget* tabWidget() const; - -protected: - virtual bool queryClose(); -protected Q_SLOTS: - void slotCurrentTabIndexChanged(int index); -Q_SIGNALS: - void currentTabIndexChanged(int index); - -private: - void setupCentralWidget(); - - KexiMainWindowTabWidget* m_tabWidget; - KexiMainWindow *m_mainWindow; - QPointer m_previouslyActiveWindow; - - friend class KexiMainWindow; - friend class KexiMainWindowTabWidget; -}; - //------------------------------------------ //! @internal Dock widget with floating disabled but still collapsible @@ -489,10 +408,10 @@ /*! @a info can be provided to hadle cases when current window is not yet defined (in openObject()). */ void updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info = 0); - void setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id, - KexiDockWidget *dockWidget, bool visible); + //void setTabBarVisible(KMultiTabBar::KMultiTabBarPosition position, int id, + // KexiDockWidget *dockWidget, bool visible); - void setPropertyEditorTabBarVisible(bool visible); + //void setPropertyEditorTabBarVisible(bool visible); QObject *openedCustomObjectsForItem(KexiPart::Item* item, const char* name); @@ -513,33 +432,46 @@ tristate showProjectMigrationWizard( const QString& mimeType, const QString& databaseName, const KDbConnectionData *cdata); + KPropertyEditorView *propertyEditor() const; + + //! Show mode for panes + enum ShowMode { + ShowImmediately, + ShowAnimated + }; + + //! Sets visibility of the project navigator without or without animating it. + //! Related action is checked/unchecked accordingly. + void setProjectNavigatorVisible(bool set, ShowMode mode = ShowImmediately); + + inline void addAction(QMenu *menu, const char* actionName) { + menu->addAction(actionCollection->action(QLatin1String(actionName))); + } + /** * Returns current page of active visible main menu widget or @c nullptr if there is no visible * menu widget or menu widget contains no page. */ KexiAssistantPage *visibleMainMenuWidgetPage(); KexiMainWindow *wnd; - KexiMainWidget *mainWidget; + QStackedWidget *globalViewStack; + KexiObjectViewWidget *objectViewWidget; + QPointer propertyPaneAnimation; KActionCollection *actionCollection; + KexiGlobalViewModeSelector *modeSelector; KHelpMenu *helpMenu; KexiProject *prj; KSharedConfig::Ptr config; #ifdef KEXI_SHOW_CONTEXT_HELP KexiContextHelp *ctxHelp; #endif - KexiProjectNavigator *navigator; KexiTabbedToolBar *tabbedToolBar; QMap tabsToActivateOnShow; - KexiDockWidget *navDockWidget; - QTabWidget *propEditorTabWidget; - KexiDockWidget *propEditorDockWidget; - QPointer propEditorDockableWidget; //! poits to kexi part which has been previously used to setup proppanel's tabs using //! KexiPart::setupCustomPropertyPanelTabs(), in updateCustomPropertyPanelTabs(). QPointer partForPreviouslySetupPropertyPanelTabs; QMap recentlySelectedPropertyPanelPages; - QPointer propEditor; QPointer propertySet; KexiNameDialog *nameDialog; @@ -556,14 +488,9 @@ *action_project_properties, *action_project_relations, *action_project_import_data_table, *action_project_export_data_table; -#ifdef KEXI_QUICK_PRINTING_SUPPORT QAction *action_project_print, *action_project_print_preview, *action_project_print_setup; -#endif QAction *action_project_welcome; - QAction *action_show_other; - int action_welcome_projects_title_id, - action_welcome_connections_title_id; QAction *action_settings; //! edit menu @@ -578,14 +505,6 @@ *action_edit_paste_special_data_table, *action_edit_copy_special_data_table; - //! view menu - QAction *action_show_nav, *action_show_propeditor; - QAction *action_activate_nav; - QAction *action_activate_mainarea; - QAction *action_activate_propeditor; -#ifdef KEXI_SHOW_CONTEXT_HELP - KToggleAction *action_show_helper; -#endif //! data menu QAction *action_data_save_row; QAction *action_data_cancel_row_changes; @@ -596,15 +515,18 @@ //! tools menu QAction *action_tools_import_project, *action_tools_compact_database, *action_tools_data_import; - KActionMenu *action_tools_scripts; + QAction *action_tools_locate; //! window menu + KToggleAction *action_show_nav; + KToggleAction *action_show_propeditor; + QAction *action_activate_nav; + QAction *action_activate_mainarea; + QAction *action_activate_propeditor; QAction *action_window_next, *action_window_previous, *action_window_fullscreen; + QAction *action_close_tab, *action_close_all_tabs; QAction *action_tab_next, *action_tab_previous; - //! global - QAction *action_show_help_menu; - QAction *action_view_global_search; //! for dock windows QPointer focus_before_popup; @@ -668,7 +590,6 @@ bool wasAutoOpen; bool windowExistedBeforeCloseProject; - QMap multiTabBars; bool propertyEditorCollapsed; bool enable_slotPropertyEditorVisibilityChanged; diff --git a/src/main/KexiMainWindow_p.cpp b/src/main/KexiMainWindow_p.cpp --- a/src/main/KexiMainWindow_p.cpp +++ b/src/main/KexiMainWindow_p.cpp @@ -19,46 +19,28 @@ */ #include "KexiMainWindow_p.h" +#include "KexiObjectViewWidget.h" + +#include #include #include +#include #include #include +#include #include #include #include #include +#include +#include #include #include -KexiWindowContainer::KexiWindowContainer(QWidget* parent) - : QWidget(parent) - , window(0) - , lyr(new QVBoxLayout(this)) -{ - lyr->setContentsMargins(0, 0, 0, 0); -} -KexiWindowContainer::~KexiWindowContainer() -{ - //! @todo warning if saveSettings() failed? - if (window) { - window->saveSettings(); - delete (KexiWindow*)window; - } -} - -void KexiWindowContainer::setWindow(KexiWindow* w) -{ - window = w; - if (w) - lyr->addWidget(w); -} - -// --- - EmptyMenuContentWidget::EmptyMenuContentWidget(QWidget* parent) : QWidget(parent) { @@ -662,7 +644,6 @@ connect(tabBar(), SIGNAL(tabBarDoubleClicked(int)), this, SLOT(slotTabDoubleClicked(int))); d->ac = KexiMainWindowIface::global()->actionCollection(); - QWidget *mainWin = KexiMainWindowIface::global()->thisWidget(); const bool userMode = KexiMainWindowIface::global()->userMode(); KToolBar *tbar; @@ -675,65 +656,6 @@ helpWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); d->helpLayer = new QHBoxLayout(helpWidget); d->helpLayer->setContentsMargins(0, 0, 0, 0); - - // * HELP MENU - // add help menu actions... (KexiTabbedToolBar depends on them) - d->helpMenu = new KHelpMenu(this, KAboutData::applicationData(), - true/*showWhatsThis*/); - QAction* help_report_bug_action = d->helpMenu->action(KHelpMenu::menuReportBug); - d->ac->addAction(help_report_bug_action->objectName(), help_report_bug_action); - QObject::disconnect(help_report_bug_action, 0, 0, 0); - QObject::connect(help_report_bug_action, SIGNAL(triggered()), mainWin, SLOT(slotReportBug())); - help_report_bug_action->setText(xi18nc("Report a bug or wish for KEXI application", "Report a &Bug or Wish...")); - help_report_bug_action->setIcon(koIcon("tools-report-bug")); // good icon for toolbar - help_report_bug_action->setWhatsThis(xi18nc( - "@info:whatsthis", "Files a bug or wish for %1 application.", - QApplication::applicationDisplayName())); - QAction* help_whats_this_action = d->helpMenu->action(KHelpMenu::menuWhatsThis); - d->ac->addAction(help_whats_this_action->objectName(), help_whats_this_action); - help_whats_this_action->setWhatsThis(xi18n("Activates a \"What's This?\" tool.")); - QAction* help_contents_action = d->helpMenu->action(KHelpMenu::menuHelpContents); - d->ac->addAction(help_contents_action->objectName(), help_contents_action); - help_contents_action->setText(xi18n("Help")); - help_contents_action->setWhatsThis(xi18nc("@info:whatsthis", - "Shows %1 Handbook.", - QApplication::applicationDisplayName())); - QAction* help_about_app_action = d->helpMenu->action(KHelpMenu::menuAboutApp); - d->ac->addAction(help_about_app_action->objectName(), help_about_app_action); - help_about_app_action->setWhatsThis( - xi18nc("@info:whatsthis", "Shows information about %1 application.", - QApplication::applicationDisplayName())); - QAction* help_about_kde_action = d->helpMenu->action(KHelpMenu::menuAboutKDE); - d->ac->addAction(help_about_kde_action->objectName(), help_about_kde_action); - help_about_kde_action->setWhatsThis(xi18n("Shows information about KDE.")); - QAction* help_switch_language_action = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); - if (help_switch_language_action) { - d->ac->addAction(help_switch_language_action->objectName(), help_switch_language_action); - } - // extra action such as help_donate may be confusing for the user or conflicting with existing so hide it - QAction *extraAction = d->helpMenu->action(static_cast(KHelpMenu::menuSwitchLanguage + 1)); - if (extraAction) { - extraAction->setVisible(false); - } - - QAction *action_show_help_menu = d->ac->action("help_show_menu"); - KexiSmallToolButton *btn = new KexiSmallToolButton(koIcon("help-about"), QString(), helpWidget); - btn->setToolButtonStyle(Qt::ToolButtonIconOnly); - btn->setPopupMode(QToolButton::InstantPopup); - btn->setToolTip(action_show_help_menu->toolTip()); - btn->setWhatsThis(action_show_help_menu->whatsThis()); - btn->setFocusPolicy(Qt::NoFocus); - QStyleOptionToolButton opt; - opt.initFrom(btn); - int w = btn->sizeHint().width(); - int wAdd = btn->style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, btn); - if (w <= (2 * (wAdd + 1))) { - w += wAdd + 2; - } - btn->setMinimumWidth(w); - connect(action_show_help_menu, SIGNAL(triggered()), btn, SLOT(showMenu())); - d->helpLayer->addWidget(btn); - btn->setMenu(d->helpMenu->menu()); setCornerWidget(helpWidget, Qt::TopRightCorner); d->initSearchLineEdit(); @@ -749,28 +671,12 @@ d->createWidgetToolBar = d->createToolBar("create", xi18n("Create")); } - tbar = d->createToolBar("data", xi18n("Data")); - addAction(tbar, "edit_cut"); - addAction(tbar, "edit_copy"); - addAction(tbar, "edit_paste"); - if (!userMode) - addAction(tbar, "edit_paste_special_data_table"); -//! @todo move undo/redo to quickbar: - - tbar = d->createToolBar("external", xi18n("External Data")); - if (!userMode) { - addAction(tbar, "project_import_data_table"); - addAction(tbar, "tools_import_tables"); - } - - tbar = d->createToolBar("tools", xi18n("Tools")); - addAction(tbar, "tools_compact_database"); - //! @todo move to form plugin tbar = d->createToolBar("form", xi18n("Form Design")); //! @todo move to report plugin tbar = d->createToolBar("report", xi18n("Report Design")); + Q_UNUSED(tbar) connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int))); setCurrentWidget(widget(KEXITABBEDTOOLBAR_SPACER_TAB_INDEX + 1)); // the default @@ -861,11 +767,6 @@ return tabBar()->tabRect(index); } -KHelpMenu* KexiTabbedToolBar::helpMenu() const -{ - return d->helpMenu; -} - void KexiTabbedToolBar::slotSettingsChanged(int category) { Q_UNUSED(category); @@ -1225,77 +1126,19 @@ slotTabDoubleClicked(-1);//use -1 just to rolldown/up the tabbar } -// --- - -KexiMainWidget::KexiMainWidget() - : KMainWindow(0, Qt::Widget) - , m_mainWindow(0) -{ - setupCentralWidget(); -} - -KexiMainWidget::~KexiMainWidget() -{ -} - -void KexiMainWidget::setParent(KexiMainWindow* mainWindow) -{ - KMainWindow::setParent(mainWindow); - m_mainWindow = mainWindow; -} - -KexiMainWindowTabWidget* KexiMainWidget::tabWidget() const -{ - return m_tabWidget; -} - -void KexiMainWidget::setupCentralWidget() -{ - QWidget *centralWidget = new QWidget(this); - QVBoxLayout *centralWidgetLyr = new QVBoxLayout(centralWidget); - m_tabWidget = new KexiMainWindowTabWidget(centralWidget, this); - connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentTabIndexChanged(int))); - centralWidgetLyr->setContentsMargins(0, 0, 0, 0); - centralWidgetLyr->setSpacing(0); - centralWidgetLyr->addWidget(m_tabWidget); - setCentralWidget(centralWidget); - layout()->setContentsMargins(0, 0, 0, 0); - layout()->setSpacing(0); -} - -bool KexiMainWidget::queryClose() -{ - return m_mainWindow ? m_mainWindow->queryClose() : true; -} - -void KexiMainWidget::slotCurrentTabIndexChanged(int index) -{ - KexiWindowContainer* cont = dynamic_cast(m_tabWidget->widget(index)); - if (! cont || (KexiWindow*)m_previouslyActiveWindow == cont->window) - return; - if (m_mainWindow) - m_mainWindow->activeWindowChanged(cont->window, (KexiWindow*)m_previouslyActiveWindow); - m_previouslyActiveWindow = cont->window; - emit currentTabIndexChanged(index); -} - //------------------------------------------ KexiMainWindow::Private::Private(KexiMainWindow* w) : wnd(w) { + objectViewWidget = 0; actionCollection = new KActionCollection(w); - propEditor = 0; - propEditorDockWidget = 0; - navDockWidget = 0; - propEditorTabWidget = 0; KexiProjectData *pdata = KexiStartupHandler::global()->projectData(); userMode = KexiStartupHandler::global()->forcedUserMode() /* <-- simply forced the user mode */ /* project has 'user mode' set as default and not 'design mode' override is found: */ || (pdata && pdata->userMode() && !KexiStartupHandler::global()->forcedDesignMode()); isProjectNavigatorVisible = KexiStartupHandler::global()->isProjectNavigatorVisible(); isMainMenuVisible = KexiStartupHandler::global()->isMainMenuVisible(); - navigator = 0; prj = 0; config = KSharedConfig::openConfig(); nameDialog = 0; @@ -1305,8 +1148,6 @@ action_show_propeditor = 0; action_activate_nav = 0; action_activate_propeditor = 0; - action_welcome_projects_title_id = -1; - action_welcome_connections_title_id = -1; forceWindowClosing = false; insideCloseWindow = false; #ifndef KEXI_NO_PENDING_DIALOGS @@ -1399,27 +1240,32 @@ void KexiMainWindow::Private::updatePropEditorVisibility(Kexi::ViewMode viewMode, KexiPart::Info *info) { - if (!propEditorDockWidget) + 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; + //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 - propEditorDockWidget->setVisible(!visible); - setPropertyEditorTabBarVisible(true); + set = !visible; } else { - propEditorDockWidget->setVisible(visible); - setPropertyEditorTabBarVisible(false); + 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) { @@ -1442,8 +1288,8 @@ void KexiMainWindow::Private::setPropertyEditorTabBarVisible(bool visible) { setTabBarVisible(KMultiTabBar::Right, PROPERTY_EDITOR_TABBAR_ID, - propEditorDockWidget, visible); -} + objectViewWidget->propertyEditorTabWidget(), visible); +}*/ QObject *KexiMainWindow::Private::openedCustomObjectsForItem(KexiPart::Item* item, const char* name) { @@ -1567,6 +1413,28 @@ return true; } +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); + } + } +} + KexiAssistantPage *KexiMainWindow::Private::visibleMainMenuWidgetPage() { const KexiAssistantWidget *widget = qobject_cast(tabbedToolBar->mainMenuContent()); @@ -1621,7 +1489,7 @@ bool KexiMainWindow::Private::pendingWindowsExist() { if (pendingWindows.begin() != pendingWindows.end()) - qDebug() << pendingWindows.constBegin().key() << " " << (int)pendingWindows.constBegin().value(); + qDebug() << pendingWindows.constBegin().key() << (int)pendingWindows.constBegin().value(); //! @todo (threads) QMutexLocker dialogsLocker( &dialogsMutex ); return !pendingWindows.isEmpty(); } diff --git a/src/main/KexiObjectViewTabWidget.h b/src/main/KexiObjectViewTabWidget.h new file mode 100644 --- /dev/null +++ b/src/main/KexiObjectViewTabWidget.h @@ -0,0 +1,69 @@ +/* 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 KEXIOBJECTVIEWTABWIDGET_H +#define KEXIOBJECTVIEWTABWIDGET_H + +#include +#include + +class KexiObjectViewWidget; +class KexiWindow; + +//! @internal tab widget acting as central widget for KexiMainWindow +class KexiObjectViewTabWidget : public QTabWidget +{ + Q_OBJECT +public: + KexiObjectViewTabWidget(QWidget *parent, KexiObjectViewWidget *mainWidget); + virtual ~KexiObjectViewTabWidget(); + + //! @return window for tab @a index + KexiWindow *window(int index); + +public Q_SLOTS: + void closeCurrentTab(); + void closeAllTabs(); + + //! Adds a new tab with empty container widget. @return index of the new tab. + int addEmptyContainerTab(const QIcon &icon, const QString &label); + + //! Sets window for tab @a index previously created using addEmptyContainerTab() + void setWindowForTab(int index, KexiWindow *window); + +protected: + //! Shows context menu for tab at @a index at point @a point. + //! If @a index is -1, context menu for empty area is requested. + void showContextMenuForTab(int index, const QPoint& point); + + //! Reimplemented to hide frame when no tabs are displayed + virtual void paintEvent(QPaintEvent * event); + + virtual void mousePressEvent(QMouseEvent *event); + + KexiObjectViewWidget *m_mainWidget; + +private: + int m_tabIndex; + + void setTabIndexFromContextMenu(int clickedIndex); +}; + +#endif diff --git a/src/main/KexiObjectViewTabWidget.cpp b/src/main/KexiObjectViewTabWidget.cpp new file mode 100644 --- /dev/null +++ b/src/main/KexiObjectViewTabWidget.cpp @@ -0,0 +1,198 @@ +/* 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 "KexiObjectViewTabWidget.h" +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +//! @internal window container created to speedup opening new tabs +class KexiWindowContainer : public QWidget +{ + Q_OBJECT +public: + explicit KexiWindowContainer(QWidget* parent); + + virtual ~KexiWindowContainer(); + + void setWindow(KexiWindow* w); + + KexiWindow* window() { return m_window; } + +private: + QPointer m_window; + QVBoxLayout *lyr; +}; + +KexiWindowContainer::KexiWindowContainer(QWidget* parent) + : QWidget(parent) + , lyr(new QVBoxLayout(this)) +{ + lyr->setContentsMargins(0, 0, 0, 0); +} + +KexiWindowContainer::~KexiWindowContainer() +{ + //! @todo warning if saveSettings() failed? + if (m_window) { + m_window->saveSettings(); + delete (KexiWindow*)m_window; + } +} + +void KexiWindowContainer::setWindow(KexiWindow* w) +{ + m_window = w; + if (w) { + lyr->addWidget(w); + } +} + +//------------------------------------------------- + +KexiObjectViewTabWidget::KexiObjectViewTabWidget(QWidget *parent, KexiObjectViewWidget* mainWidget) + : QTabWidget(parent) + , m_mainWidget(mainWidget) + , m_tabIndex(-1) +{ +//! @todo insert window list in the corner widget as in firefox +#if 0 + // close-tab button: + QToolButton* rightWidget = new QToolButton(this); + rightWidget->setDefaultAction(m_closeAction); + rightWidget->setText(QString()); + rightWidget->setAutoRaise(true); + rightWidget->adjustSize(); + setCornerWidget(rightWidget, Qt::TopRightCorner); +#endif + setMovable(true); + setDocumentMode(true); + tabBar()->setExpanding(false); +} + +KexiObjectViewTabWidget::~KexiObjectViewTabWidget() +{ +} + +void KexiObjectViewTabWidget::paintEvent(QPaintEvent * event) +{ + if (count() > 0) + QTabWidget::paintEvent(event); + else + QWidget::paintEvent(event); +} + +void KexiObjectViewTabWidget::mousePressEvent(QMouseEvent *event) +{ + //! @todo KEXI3 test KexiMainWindowTabWidget's contextMenu event port from KTabWidget + if (event->button() == Qt::RightButton) { + int tab = tabBar()->tabAt(event->pos()); + const QPoint realPos(tabBar()->mapToGlobal(event->pos())); + if (QRect(tabBar()->mapToGlobal(QPoint(0,0)), + tabBar()->mapToGlobal(QPoint(tabBar()->width()-1, tabBar()->height()-1))).contains(realPos)) + { + showContextMenuForTab(tab, tabBar()->mapToGlobal(event->pos())); + return; + } + } + QTabWidget::mousePressEvent(event); +} + +KexiWindow* KexiObjectViewTabWidget::window(int index) +{ + KexiWindowContainer *windowContainer = qobject_cast(widget(index)); + return windowContainer ? windowContainer->window() : 0; +} + +void KexiObjectViewTabWidget::closeCurrentTab() +{ + emit tabCloseRequested(m_tabIndex); +} + +void KexiObjectViewTabWidget::closeAllTabs() +{ + QAction *action_close_all_tabs = KexiMainWindowIface::global()->actionCollection()->action("close_all_tabs"); + action_close_all_tabs->trigger(); +} + +int KexiObjectViewTabWidget::addEmptyContainerTab(const QIcon &icon, const QString &label) +{ + KexiWindowContainer *windowContainer = new KexiWindowContainer(this); + return addTab(windowContainer, icon, label); +} + +void KexiObjectViewTabWidget::setWindowForTab(int index, KexiWindow *window) +{ + KexiWindowContainer *windowContainer = qobject_cast(widget(index)); + if (windowContainer) { + if (windowContainer->window()) { + qWarning() << "tab" << index << "already has KexiWindow assigned"; + return; + } + windowContainer->setWindow(window); + } +} + +void KexiObjectViewTabWidget::showContextMenuForTab(int index, const QPoint& point) +{ + QMenu menu; + if (index >= 0) { + QAction *action_close_tab = KexiMainWindowIface::global()->actionCollection()->action("close_tab"); + // Copy the action; we can't use the original action because instead of calling closeCurrentTab() + // tabCloseRequested() signal should be called. + QAction *closeAction = new QAction(action_close_tab->icon(), action_close_tab->text(), &menu); + closeAction->setToolTip(action_close_tab->toolTip()); + closeAction->setWhatsThis(action_close_tab->whatsThis()); + closeAction->setShortcut(action_close_tab->shortcut()); + connect(closeAction, &QAction::triggered, this, &KexiObjectViewTabWidget::tabCloseRequested); + menu.addAction(closeAction); + } + if (count() > 0) { + QAction *action_close_all_tabs = KexiMainWindowIface::global()->actionCollection()->action("close_all_tabs"); + menu.addAction(action_close_all_tabs); + } + //! @todo add "&Detach Tab" + if (menu.actions().isEmpty()) { + return; + } + setTabIndexFromContextMenu(index); + menu.exec(point); +} + +void KexiObjectViewTabWidget::setTabIndexFromContextMenu(int clickedIndex) +{ + if (currentIndex() == -1) { + m_tabIndex = -1; + return; + } + m_tabIndex = clickedIndex; +} + +#include "KexiObjectViewTabWidget.moc" diff --git a/src/main/KexiObjectViewWidget.h b/src/main/KexiObjectViewWidget.h new file mode 100644 --- /dev/null +++ b/src/main/KexiObjectViewWidget.h @@ -0,0 +1,94 @@ +/* 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 KEXIOBJECTVIEWWIDGET_H +#define KEXIOBJECTVIEWWIDGET_H + +#include + +class KexiObjectViewTabWidget; +class KexiProjectNavigator; +class KexiPropertyPaneWidget; +class KexiWindow; + +//! @short A widget for object view, used in edit and design global view mode +/*! Contents: + @verbatim + |---|--------------|-------------|---------------|---| + | | | tabs | | | + |tab| |-------------| |tab| + |bar|Prj. navigator|Object's view|Property editor|bar| + | | pane | | pane | | + |---|--------------|-------------|---------------|---| + @endverbatim +*/ +class KexiObjectViewWidget : public QWidget +{ + Q_OBJECT +public: + enum Flag { + NoFlags = 0, + ProjectNavigatorEnabled = 1, + PropertyPaneEnabled = 2, + DefaultFlags = ProjectNavigatorEnabled | PropertyPaneEnabled + }; + Q_DECLARE_FLAGS(Flags, Flag) + Q_FLAG(Flags) + + explicit KexiObjectViewWidget(Flags flags = DefaultFlags); + + virtual ~KexiObjectViewWidget(); + + KexiProjectNavigator* projectNavigator() const; + KexiObjectViewTabWidget* tabWidget() const; + KexiPropertyPaneWidget* propertyPane() const; + + void setProjectNavigatorVisible(bool set); + void setPropertyPaneVisible(bool set); + + void setSidebarWidths(int projectNavigatorWidth, int propertyEditorWidth); + void getSidebarWidths(int *projectNavigatorWidth, int *propertyEditorWidth) const; + void updateSidebarWidths(); + +protected Q_SLOTS: + void slotCurrentTabIndexChanged(int index); + void slotSplitterMoved(int pos, int index); + +Q_SIGNALS: + void currentTabIndexChanged(int index); + void activeWindowChanged(KexiWindow *window, KexiWindow *prevWindow); + void closeWindowRequested(int index); + void closeAllWindowsRequested(); + void projectNavigatorAnimationFinished(bool visible); + +protected: + void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE; + void showEvent(QShowEvent *e) Q_DECL_OVERRIDE; + +private: + void setupCentralWidget(); + + class Private; + const QScopedPointer d; + + friend class KexiObjectViewTabWidget; +}; + +#endif diff --git a/src/main/KexiObjectViewWidget.cpp b/src/main/KexiObjectViewWidget.cpp new file mode 100644 --- /dev/null +++ b/src/main/KexiObjectViewWidget.cpp @@ -0,0 +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 +#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/KexiSearchLineEdit.cpp b/src/main/KexiSearchLineEdit.cpp --- a/src/main/KexiSearchLineEdit.cpp +++ b/src/main/KexiSearchLineEdit.cpp @@ -22,9 +22,11 @@ #include #include +#include #include #include +#include #include #include @@ -35,6 +37,7 @@ #include #include #include +#include class SearchableObject { @@ -433,8 +436,11 @@ // previously focus widget in KexiSearchLineEdit::setFocus(). // We need this information to focus back when pressing Escape key. setClearButtonEnabled(true); - setPlaceholderText(xi18n("Search")); + QAction *action_tools_locate = KexiMainWindowIface::global()->actionCollection()->action("tools_locate"); + setPlaceholderText(xi18nc("Tools->Locate textbox' placeholder text with shortcut", "Locate (%1)") + .arg(action_tools_locate->shortcut().toString(QKeySequence::NativeText))); fixLeftMargin(this); + setMinimumWidth(fontMetrics().width(" " + placeholderText() + " " + " " + " ")); } KexiSearchLineEdit::~KexiSearchLineEdit() diff --git a/src/main/startup/KexiNewProjectAssistant.cpp b/src/main/startup/KexiNewProjectAssistant.cpp --- a/src/main/startup/KexiNewProjectAssistant.cpp +++ b/src/main/startup/KexiNewProjectAssistant.cpp @@ -235,7 +235,7 @@ void KexiProjectTitleSelectionPage::askForOverwriting(const KexiContextMessage& message) { - qDebug() << message.text(); + //qDebug() << message.text(); delete messageWidget; messageWidget = new KexiContextMessageWidget(this, contents->formLayout, diff --git a/src/main/startup/KexiStartupDialog.cpp b/src/main/startup/KexiStartupDialog.cpp new file mode 100644 --- /dev/null +++ b/src/main/startup/KexiStartupDialog.cpp @@ -0,0 +1,494 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2007 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 "KexiStartupDialog.h" +#include "kexi.h" +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//! @internal +class Q_DECL_HIDDEN KexiStartupDialog::Private +{ +public: + Private() + : pageTemplates(0), pageOpenExisting(0) + , templPageWidgetItem_BlankDatabase(0) + , templPageWidgetItem_ImportExisting(0) + , templPageWidgetItem_CreateFromTemplate(0) + { + result = -1; + kexi_sqlite_icon = Kexi::defaultFileBasedDriverIcon(); + chkDoNotShow = 0; + openExistingConnWidget = 0; + templatesWidget = 0; + templatesWidget_IconListView = 0; + } + ~Private() { + } + + int dialogType, dialogOptions; + + KPageWidgetItem *pageTemplates, *pageOpenExisting; + + // subpages within "templates" page + KPageWidgetItem *templPageWidgetItem_BlankDatabase, + *templPageWidgetItem_ImportExisting, *templPageWidgetItem_CreateFromTemplate; + QCheckBox *chkDoNotShow; + + //widgets for template tab: + KPageWidget* templatesWidget; + QListView *templatesWidget_IconListView;//helper + + int result; + + QIcon kexi_sqlite_icon; + + //! used for "open existing" + KexiDBConnectionSet *connSet; + KexiFileWidget *openExistingFileWidget; //! embedded file widget + KexiConnectionSelectorWidget *openExistingConnWidget; + KDbConnectionData* selectedExistingConnection; //! helper for returning selected connection + + //! true if the dialog contain single page, not tabs + bool singlePage; +}; + +static QString captionForDialogType(int type) +{ + if (type == KexiStartupDialog::Templates) + return xi18n("Create Project"); + else if (type == KexiStartupDialog::OpenExisting) + return xi18n("Open Existing Project"); + + return xi18n("Choose Project"); +} + +/*================================================================*/ + +KexiStartupDialog::KexiStartupDialog( + int dialogType, int dialogOptions, + KexiDBConnectionSet& connSet, + QWidget *parent) + : KPageDialog(parent) + , d(new Private()) +{ + d->connSet = &connSet; + d->dialogType = dialogType; + d->dialogOptions = dialogOptions; + d->singlePage = dialogType == KexiStartupDialog::Templates + || dialogType == KexiStartupDialog::OpenExisting; + setFaceType(d->singlePage ? Plain : Tabbed); + setWindowTitle(captionForDialogType(dialogType)); + + // buttons + QPushButton *okButton = buttonBox()->button(QDialogButtonBox::Ok); + okButton->setDefault(true); + okButton->setShortcut(Qt::CTRL | Qt::Key_Return); + + if (dialogType == OpenExisting) {//this dialog has "open" tab only! + setWindowIcon(koIcon("document-open")); + } else { + setWindowIcon(d->kexi_sqlite_icon); + } + + setSizeGripEnabled(true); + KPageWidgetItem *firstPage = 0; + if (d->dialogType & Templates) { + setupPageTemplates(); + //d->pageTemplatesID = id++; + d->templatesWidget->setFocus(); + if (!firstPage) + firstPage = d->pageTemplates; + } + if (d->dialogType & OpenExisting) { + setupPageOpenExisting(); + if (d->singlePage) + d->openExistingConnWidget->setFocus(); + if (!firstPage) + firstPage = d->pageOpenExisting; + } + + if (!d->singlePage) { + connect(this, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), + this, SLOT(slotCurrentPageChanged(KPageWidgetItem*,KPageWidgetItem*))); + d->templatesWidget->setFocus(); + } + connect(okButton, SIGNAL(clicked()), this, SLOT(slotOk())); + setCurrentPage(firstPage); + updateDialogOKButton(firstPage); + adjustSize(); +} + +KexiStartupDialog::~KexiStartupDialog() +{ + delete d; +} + +void KexiStartupDialog::showEvent(QShowEvent *e) +{ + KPageDialog::showEvent(e); + //just some cleanup + d->result = -1; + + //! @todo QDialog::centerOnScreen(this); +} + +int KexiStartupDialog::result() const +{ + return d->result; +} + +void KexiStartupDialog::done(int r) +{ + if (d->result != -1) //already done! + return; + +// qDebug() << r; +// updateSelectedTemplateKeyInfo(); + + if (r == QDialog::Rejected) { + d->result = CancelResult; + } else { + KPageWidgetItem *currentPageWidgetItem = currentPage(); + + if (currentPageWidgetItem == d->pageTemplates) { + KPageWidgetItem *currenTemplatesPageWidgetItem = d->templatesWidget->currentPage(); + if (currenTemplatesPageWidgetItem == d->templPageWidgetItem_BlankDatabase) + d->result = CreateBlankResult; +#ifdef KEXI_PROJECT_TEMPLATES + else if (currenTemplatesPageWidgetItem == d->templPageWidgetItem_CreateFromTemplate) + d->result = CreateFromTemplateResult; +#endif + else if (currenTemplatesPageWidgetItem == d->templPageWidgetItem_ImportExisting) + d->result = ImportResult; + } else if (currentPageWidgetItem == d->pageOpenExisting) { + // return file or connection: + if (d->openExistingConnWidget->selectedConnectionType() + == KexiConnectionSelectorWidget::FileBased) { + if (!d->openExistingFileWidget->checkSelectedFile()) + return; + d->openExistingFileWidget->accept(); + d->selectedExistingConnection = 0; + } else { + d->selectedExistingConnection + = d->openExistingConnWidget->selectedConnectionData(); + } + d->result = OpenExistingResult; + } else + return; + } + + //save settings + KConfigGroup group = KSharedConfig::openConfig()->group("Startup"); + if (d->openExistingConnWidget) + group.writeEntry("OpenExistingType", + (d->openExistingConnWidget->selectedConnectionType() == KexiConnectionSelectorWidget::FileBased) + ? "File" : "Server"); + if (d->chkDoNotShow) + group.writeEntry("ShowStartupDialog", !d->chkDoNotShow->isChecked()); + + group.sync(); + + KPageDialog::done(r); +} + +void KexiStartupDialog::reject() +{ + KPageDialog::reject(); +} + +void KexiStartupDialog::setupPageTemplates() +{ + QFrame *pageTemplatesFrame = new QFrame(this); + d->pageTemplates = addPage(pageTemplatesFrame, xi18n("Create Project")); + QVBoxLayout *lyr = new QVBoxLayout(pageTemplatesFrame); + lyr->setSpacing(KexiUtils::spacingHint()); + lyr->setMargin(0); + + d->templatesWidget = new KPageWidget(pageTemplatesFrame); + d->templatesWidget->setObjectName("templatesWidget"); + d->templatesWidget->setFaceType(KPageWidget::List); + { + d->templatesWidget_IconListView = KexiUtils::findFirstChild(d->templatesWidget, "QListView"); + if (d->templatesWidget_IconListView) + d->templatesWidget_IconListView->installEventFilter(this); + } + lyr->addWidget(d->templatesWidget); + connect(d->templatesWidget, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), + this, SLOT(slotCurrentTemplatesubpageChanged(KPageWidgetItem*,KPageWidgetItem*))); + + if (d->dialogOptions & CheckBoxDoNotShowAgain) { + d->chkDoNotShow = new QCheckBox(xi18n("Do not show me this dialog again"), pageTemplatesFrame); + d->chkDoNotShow->setObjectName("chkDoNotShow"); + lyr->addWidget(d->chkDoNotShow); + } + + //template groups: + QFrame *templPageWidget = 0; + QVBoxLayout *tmplyr; + + //- page "blank db" + QString clickMsg("\n\n" + xi18n("Click OK button to proceed.")); + templPageWidget = new QFrame(d->templatesWidget); + d->templPageWidgetItem_BlankDatabase = d->templatesWidget->addPage(templPageWidget, + xi18n("Blank Database")); + d->templPageWidgetItem_BlankDatabase->setHeader(xi18n("New Blank Database Project")); + d->templPageWidgetItem_BlankDatabase->setIcon(koIcon("x-office-document")); + tmplyr = new QVBoxLayout(templPageWidget); + tmplyr->setSpacing(KexiUtils::spacingHint()); + QLabel *lbl_blank = new QLabel( + xi18n("Kexi will create a new blank database project.") + clickMsg, templPageWidget); + lbl_blank->setAlignment(Qt::AlignLeft | Qt::AlignTop); + lbl_blank->setWordWrap(true); + lbl_blank->setMargin(0); + tmplyr->addWidget(lbl_blank); + tmplyr->addStretch(1); + + //- page "import db" + templPageWidget = new QFrame(d->templatesWidget); + d->templPageWidgetItem_ImportExisting = d->templatesWidget->addPage(templPageWidget, + xi18n("Import Existing Database")); + d->templPageWidgetItem_ImportExisting->setHeader( + xi18n("Import Existing Database as New Database Project")); + d->templPageWidgetItem_ImportExisting->setIcon(KexiIcon("database-import")); + tmplyr = new QVBoxLayout(templPageWidget); + tmplyr->setSpacing(KexiUtils::spacingHint()); + QLabel *lbl_import = new QLabel( + xi18n("Kexi will import the structure and data of an existing database " + "as a new database project.") + clickMsg, templPageWidget); + lbl_import->setAlignment(Qt::AlignLeft | Qt::AlignTop); + lbl_import->setWordWrap(true); + lbl_import->setMargin(0); + tmplyr->addWidget(lbl_import); + tmplyr->addStretch(1); +} + +void KexiStartupDialog::slotCurrentPageChanged(KPageWidgetItem* current, + KPageWidgetItem* before) +{ + Q_UNUSED(before); + updateDialogOKButton(current); +} + +void KexiStartupDialog::slotCurrentTemplatesubpageChanged(KPageWidgetItem* current, + KPageWidgetItem* before) +{ + Q_UNUSED(before); + if (current == d->templPageWidgetItem_BlankDatabase) {//blank + } else if (current == d->templPageWidgetItem_ImportExisting) { + } +#ifdef KEXI_PROJECT_TEMPLATES + else if (current == d->templPageWidgetItem_CreateFromTemplate) { + //! @todo d->viewTemplates->populate(); + } +#endif + updateDialogOKButton(d->pageTemplates); +} + +void KexiStartupDialog::updateDialogOKButton(KPageWidgetItem *pageWidgetItem) +{ + if (!pageWidgetItem) { + pageWidgetItem = currentPage(); + if (!pageWidgetItem) + return; + } + bool enable = true; + if (pageWidgetItem == d->pageTemplates) { + //int t_id = d->templatesWidget->activePageIndex(); + KPageWidgetItem *currenTemplatesPageWidgetItem = d->templatesWidget->currentPage(); +#ifdef KEXI_PROJECT_TEMPLATES + enable = + currenTemplatesPageWidgetItem == d->templPageWidgetItem_BlankDatabase + || currenTemplatesPageWidgetItem == d->templPageWidgetItem_ImportExisting + || (currenTemplatesPageWidgetItem == d->templPageWidgetItem_CreateFromTemplate + /*! @todo && !d->viewTemplates->selectedFileName().isEmpty()*/); +#else + enable = currenTemplatesPageWidgetItem == d->templPageWidgetItem_BlankDatabase + || currenTemplatesPageWidgetItem == d->templPageWidgetItem_ImportExisting; +#endif + } else if (pageWidgetItem == d->pageOpenExisting) { + //qDebug() << "d->openExistingFileWidget->highlightedFile():" << d->openExistingFileWidget->highlightedFile(); + enable = + (d->openExistingConnWidget->selectedConnectionType() == KexiConnectionSelectorWidget::FileBased) + ? !d->openExistingFileWidget->highlightedFile().isEmpty() + : (bool)d->openExistingConnWidget->selectedConnectionData(); +//qDebug() << d->openExistingFileWidget->selectedFile() << "--------------"; + } + QPushButton *okButton = buttonBox()->button(QDialogButtonBox::Ok); + okButton->setEnabled(enable); +} + +void KexiStartupDialog::setupPageOpenExisting() +{ + QWidget *pageOpenExistingWidget = new QFrame(this); + d->pageOpenExisting = addPage(pageOpenExistingWidget, xi18n("Open Existing Project")); + + QVBoxLayout *lyr = new QVBoxLayout(pageOpenExistingWidget); + lyr->setSpacing(KexiUtils::spacingHint()); + lyr->setMargin(0); + + d->openExistingConnWidget = new KexiConnectionSelectorWidget(d->connSet, + "kfiledialog:///OpenExistingOrCreateNewProject", KFileWidget::Opening, + pageOpenExistingWidget); + d->openExistingConnWidget->setObjectName("KexiConnectionSelectorWidget"); + d->openExistingConnWidget->hideConnectonIcon(); + lyr->addWidget(d->openExistingConnWidget); + KConfigGroup group = KSharedConfig::openConfig()->group("Startup"); + if (group.readEntry("OpenExistingType", "File") == "File") + d->openExistingConnWidget->showSimpleConn(); + else { + d->openExistingConnWidget->showSimpleConn(); + d->openExistingConnWidget->showAdvancedConn(); + } + d->openExistingFileWidget = d->openExistingConnWidget->fileWidget; + connect(d->openExistingFileWidget, SIGNAL(accepted()), this, SLOT(accept())); + connect(d->openExistingFileWidget, SIGNAL(selectionChanged()), + this, SLOT(existingFileSelected())); + connect(d->openExistingConnWidget, SIGNAL(connectionItemExecuted(ConnectionDataLVItem*)), + this, SLOT(connectionItemForOpenExistingExecuted(ConnectionDataLVItem*))); + connect(d->openExistingConnWidget, SIGNAL(connectionItemHighlighted(ConnectionDataLVItem*)), + this, SLOT(connectionItemForOpenExistingHighlighted(ConnectionDataLVItem*))); +} + +void KexiStartupDialog::connectionItemForOpenExistingExecuted(ConnectionDataLVItem *item) +{ + if (!item) + return; + accept(); +} + +void KexiStartupDialog::connectionItemForOpenExistingHighlighted(ConnectionDataLVItem *item) +{ + QPushButton *okButton = buttonBox()->button(QDialogButtonBox::Ok); + okButton->setEnabled(item); +} + +void KexiStartupDialog::slotOk() +{ +// qDebug(); +} + +void KexiStartupDialog::showSimpleConnForOpenExisting() +{ +// qDebug() << "simple"; + d->openExistingConnWidget->showSimpleConn(); +} + +void KexiStartupDialog::showAdvancedConnForOpenExisting() +{ +// qDebug() << "adv"; + d->openExistingConnWidget->showAdvancedConn(); +} + +QString KexiStartupDialog::selectedFileName() const +{ + if (d->result == OpenExistingResult) + return d->openExistingFileWidget->highlightedFile(); +#ifdef KEXI_PROJECT_TEMPLATES + /*! @todo + else if (d->result == CreateFromTemplateResult && d->viewTemplates) + return d->viewTemplates->selectedFileName();*/ +#endif + else + return QString(); +} + +KDbConnectionData* KexiStartupDialog::selectedExistingConnection() const +{ + return d->selectedExistingConnection; +} + +void KexiStartupDialog::existingFileSelected() +{ + //qDebug(); + updateDialogOKButton(0); +} + +KexiProjectData* KexiStartupDialog::selectedProjectData() const +{ + return 0; +} + +//! used for accepting templates dialog with just return key press +bool KexiStartupDialog::eventFilter(QObject *o, QEvent *e) +{ + if (o == d->templatesWidget_IconListView && d->templatesWidget_IconListView) { + bool tryAcept = false; + if ( e->type() == QEvent::KeyPress + && ( static_cast(e)->key() == Qt::Key_Enter + || static_cast(e)->key() == Qt::Key_Return) + ) + { + tryAcept = true; + } + else if (e->type() == QEvent::MouseButtonDblClick) { + tryAcept = true; + } + + if (tryAcept) { + KPageWidgetItem *currentTemplatesPageWidgetItem = d->templatesWidget->currentPage(); + if ( currentTemplatesPageWidgetItem == d->templPageWidgetItem_BlankDatabase + || currentTemplatesPageWidgetItem == d->templPageWidgetItem_ImportExisting) + { + accept(); + } + } + } + return KPageDialog::eventFilter(o, e); +} + +void KexiStartupDialog::templateSelected(const QString& fileName) +{ + if (!fileName.isEmpty()) + accept(); +} + +#ifdef KEXI_PROJECT_TEMPLATES +KexiProjectData::AutoOpenObjects KexiStartupDialog::autoopenObjects() const +{ + /*! @todo if (d->result != CreateFromTemplateResult || !d->viewTemplates) + KexiProjectData::AutoOpenObjects(); + + return d->viewTemplates->autoopenObjectsForSelectedTemplate(); + */ + return KexiProjectData::AutoOpenObjects(); +} +#endif + diff --git a/src/main/startup/KexiWelcomeStatusBar.cpp b/src/main/startup/KexiWelcomeStatusBar.cpp --- a/src/main/startup/KexiWelcomeStatusBar.cpp +++ b/src/main/startup/KexiWelcomeStatusBar.cpp @@ -368,8 +368,8 @@ int minutes = lastStatusBarUpdate.secsTo(QDateTime::currentDateTime()) / 60; if (minutes < GUI_UPDATE_INTERVAL) { - qDebug() << "gui updated" << minutes << "min. ago, next auto-update in" - << (GUI_UPDATE_INTERVAL - minutes) << "min."; + //qDebug() << "gui updated" << minutes << "min. ago, next auto-update in" + // << (GUI_UPDATE_INTERVAL - minutes) << "min."; return; } } @@ -716,8 +716,8 @@ int days = lastDonation.secsTo(QDateTime::currentDateTime()) / 60 / 60 / 24; if (days >= DONATION_INTERVAL) { donated = false; - qDebug() << "last donation declared" << days << "days ago, next in" - << (DONATION_INTERVAL - days) << "days."; + //qDebug() << "last donation declared" << days << "days ago, next in" + // << (DONATION_INTERVAL - days) << "days."; } else if (days >= 0) { donated = true; diff --git a/src/migration/AlterSchemaWidget.cpp b/src/migration/AlterSchemaWidget.cpp --- a/src/migration/AlterSchemaWidget.cpp +++ b/src/migration/AlterSchemaWidget.cpp @@ -111,7 +111,7 @@ m_selectedColumn = idx.column(); m_columnNumLabel->setText(xi18n("Column %1", m_selectedColumn + 1)); if (m_schema && m_selectedColumn < int(m_schema->fieldCount()) && m_schema->field(m_selectedColumn)) { - qDebug() << m_schema->field(m_selectedColumn)->typeName() << m_types.indexOf(m_schema->field(m_selectedColumn)->typeName()); + //qDebug() << m_schema->field(m_selectedColumn)->typeName() << m_types.indexOf(m_schema->field(m_selectedColumn)->typeName()); m_columnType->setCurrentIndex(m_types.indexOf(m_schema->field(m_selectedColumn)->typeName())); //Only set the pkey check enabled if the field type is integer diff --git a/src/migration/importtablewizard.cpp b/src/migration/importtablewizard.cpp --- a/src/migration/importtablewizard.cpp +++ b/src/migration/importtablewizard.cpp @@ -364,7 +364,7 @@ delete m_prjSet; m_prjSet = 0; m_srcDBPageWidget->hide(); - qDebug() << "Looks like we need a project selector widget!"; + //qDebug() << "Looks like we need a project selector widget!"; KDbConnectionData* conndata = m_srcConnSel->selectedConnectionData(); if (conndata) { @@ -607,7 +607,7 @@ if (!result->error()) { sourceDriver = m_migrateManager.driver(sourceDriverId); if (!sourceDriver || m_migrateManager.result().isError()) { - qDebug() << "Import migrate driver error..."; + //qDebug() << "Import migrate driver error..."; result->setStatus(m_migrateManager.resultable()); } } diff --git a/src/migration/importwizard.cpp b/src/migration/importwizard.cpp --- a/src/migration/importwizard.cpp +++ b/src/migration/importwizard.cpp @@ -759,20 +759,20 @@ if (!result.error()) { if (d->dstConn->selectedConnectionData()) { //server-based project - qDebug() << "Server destination..."; + //qDebug() << "Server destination..."; cdata = d->dstConn->selectedConnectionData(); dbname = d->dstNewDBNameLineEdit->text(); } else { //file-based project - qDebug() << "File Destination..."; + //qDebug() << "File Destination..."; cdata = new KDbConnectionData(); cdataDeleter.reset(cdata); // ownership won't be transferred cdata->setCaption(d->dstNewDBTitleLineEdit->text()); cdata->setDriverId(KDb::defaultFileBasedDriverId()); dbname = d->dstTitlePageWidget->file_requester->url().toLocalFile(); cdata->setDatabaseName(dbname); - qDebug() << "Current file name:" << dbname; + //qDebug() << "Current file name:" << dbname; } } @@ -788,7 +788,7 @@ if (!result.error()) { sourceDriver = d->migrateManager.driver(d->driverIdForSelectedSource); if (!sourceDriver || d->migrateManager.result().isError()) { - qDebug() << "Import migrate driver error..."; + qWarning() << "Import migrate driver error..."; result.setStatus(d->migrateManager.resultable()); } } @@ -809,13 +809,13 @@ bool keepData; if (d->importTypeStructureAndDataCheckBox->isChecked()) { - qDebug() << "Structure and data selected"; + //qDebug() << "Structure and data selected"; keepData = true; } else if (d->importTypeStructureOnlyCheckBox->isChecked()) { - qDebug() << "structure only selected"; + //qDebug() << "structure only selected"; keepData = false; } else { - qDebug() << "Neither radio button is selected (not possible?) presume keep data"; + //qDebug() << "Neither radio button is selected (not possible?) presume keep data"; keepData = true; } @@ -860,13 +860,13 @@ ); } if (!sourceDriver->checkIfDestinationDatabaseOverwritingNeedsAccepting(&result, &acceptingNeeded)) { - qDebug() << "Abort import cause checkIfDestinationDatabaseOverwritingNeedsAccepting " - "returned false."; + //qDebug() << "Abort import cause checkIfDestinationDatabaseOverwritingNeedsAccepting " + // "returned false."; return false; } - qDebug() << sourceDriver->data()->destinationProjectData()->databaseName(); - qDebug() << "Performing import..."; + //qDebug() << sourceDriver->data()->destinationProjectData()->databaseName(); + //qDebug() << "Performing import..."; } if (sourceDriver && !result.error() && acceptingNeeded) { @@ -914,7 +914,7 @@ KexiTextMessageHandler handler(&msg, &details); handler.showErrorMessage(&result); - qDebug() << msg << "\n" << details; + //qDebug() << msg << "\n" << details; d->finishPageItem->setHeader(xi18n("Failure")); // note: we're using .arg() here because the msg and details arguments are already in rich-text format diff --git a/src/migration/keximigrate.cpp b/src/migration/keximigrate.cpp --- a/src/migration/keximigrate.cpp +++ b/src/migration/keximigrate.cpp @@ -384,7 +384,7 @@ } // Step 2 - get table names - qDebug() << "GETTING TABLENAMES..."; + //qDebug() << "GETTING TABLENAMES..."; QStringList tables; if (!tableNames(&tables)) { qWarning() << "Couldn't get list of tables"; @@ -397,7 +397,7 @@ // Check if there are any tables if (tables.isEmpty()) { - qDebug() << "There were no tables to import"; + qWarning() << "There were no tables to import"; if (result) result->setStatus( xi18n("No tables have been found in database %1.", @@ -435,8 +435,8 @@ tablesIt.remove(); } } - //qDebug() << "KDb-compatible tables: " << kexiDBTables; - //qDebug() << "non-KDb tables: " << tables; + //qDebug() << "KDb-compatible tables:" << kexiDBTables; + //qDebug() << "non-KDb tables:" << tables; } } @@ -521,7 +521,7 @@ foreach(KDbTableSchema* ts, d->tableSchemas) { ok = destConn->createTable(ts); if (!ok) { - qWarning() << "Failed to create a table " << ts->name(); + qWarning() << "Failed to create a table" << ts->name(); qWarning() << destConn->result(); if (result) { result->setStatus(destConn->parentConnection()->result(), nullptr, @@ -587,12 +587,12 @@ && ts->name() != "kexi__userdata" //copy this too ) { - qDebug() << "Won't copy data to system table" << ts->name(); + //qDebug() << "Won't copy data to system table" << ts->name(); //! @todo copy kexi__db contents! continue; } QString tsName = nativeNames.value(ts->name()); - qDebug() << "Copying data for table: " << tsName; + //qDebug() << "Copying data for table: " << tsName; if (tsName.isEmpty()) { tsName = ts->name(); } @@ -662,16 +662,16 @@ foreach(const QString& tableName, tables) { quint64 size; if (drv_getTableSize(tableName, &size)) { - qDebug() << "table:" << tableName << "size: " << (ulong)size; + //qDebug() << "table:" << tableName << "size:" << (ulong)size; sum += size; emit progressPercent(tableNumber * 5 /* 5% */ / tables.count()); tableNumber++; } else { return false; } } - qDebug() << "job size:" << sum; + //qDebug() << "job size:" << sum; d->progressTotal = sum; d->progressTotal += tables.count() * NUM_OF_ROWS_PER_CREATE_TABLE; d->progressTotal = d->progressTotal * 105 / 100; //add 5 percent for above task 1) @@ -687,9 +687,9 @@ if (d->progressTotal > 0 && d->progressDone >= d->progressNextReport) { int percent = (d->progressDone + 1) * 100 / d->progressTotal; d->progressNextReport = ((percent + 1) * d->progressTotal) / 100; - qDebug() << (ulong)d->progressDone << "/" - << (ulong)d->progressTotal << " (" << percent << "%) next report at" - << (ulong)d->progressNextReport; + /*qDebug() << (ulong)d->progressDone << "/" + << (ulong)d->progressTotal << "(" << percent << "%) next report at" + << (ulong)d->progressNextReport;*/ emit progressPercent(percent); } } @@ -823,7 +823,7 @@ bool KexiMigrate::tableNames(QStringList *tn) { //! @todo Cache list of table names - qDebug() << "Reading list of tables..."; + //qDebug() << "Reading list of tables..."; tn->clear(); return drv_tableNames(tn); } diff --git a/src/migration/mdb/src/keximdb/mdbmigrate.cpp b/src/migration/mdb/src/keximdb/mdbmigrate.cpp --- a/src/migration/mdb/src/keximdb/mdbmigrate.cpp +++ b/src/migration/mdb/src/keximdb/mdbmigrate.cpp @@ -154,7 +154,7 @@ return false; } mdb_read_columns(tableDef); - //qDebug() << "#cols = " << tableDef->num_cols; + //qDebug() << "#cols =" << tableDef->num_cols; /*! Convert column data to Kexi KDbTableSchema Nice mix of terminology here, MDBTools has columns, Kexi has fields. */ @@ -286,7 +286,7 @@ bool ok = true; while (mdb_fetch_row(tableDef)) { QList vals; -// qDebug() << kdLoc << "Copying " << tableDef->num_cols << " cols"; +// qDebug() << kdLoc << "Copying" << tableDef->num_cols << "cols"; for (unsigned int i = 0; i < tableDef->num_cols; i++) { MdbColumn *col = (MdbColumn*) g_ptr_array_index(tableDef->columns, i); @@ -408,7 +408,7 @@ //! @todo: MDB index order (asc, desc) - qDebug() << "num_keys" << idx->num_keys; + //qDebug() << "num_keys" << idx->num_keys; //! Create the KdbIndexSchema ... QVector key_col_num(idx->num_keys); @@ -420,8 +420,8 @@ bool ok = true; for (unsigned int i = 0; i < idx->num_keys; i++) { key_col_num[i] = idx->key_col_num[i]; - qDebug() << "key" << i + 1 << " col " << key_col_num[i] - << table->field(idx->key_col_num[i] - 1)->name(); + //qDebug() << "key" << i + 1 << "col" << key_col_num[i] + // << table->field(idx->key_col_num[i] - 1)->name(); if (!p_idx->addField(table->field(idx->key_col_num[i] - 1))) { delete p_idx; ok = false; diff --git a/src/migration/spreadsheet/spreadsheetmigrate.cpp b/src/migration/spreadsheet/spreadsheetmigrate.cpp --- a/src/migration/spreadsheet/spreadsheetmigrate.cpp +++ b/src/migration/spreadsheet/spreadsheetmigrate.cpp @@ -93,7 +93,7 @@ { QList sheets = m_KSDoc->map()->sheetList(); - qDebug() << sheets.size() << "sheets" << m_KSDoc->map()->sheetList().size(); + //qDebug() << sheets.size() << "sheets" << m_KSDoc->map()->sheetList().size(); foreach(Calligra::Sheets::Sheet *sheet, sheets) { tablenames << sheet->sheetName(); @@ -157,7 +157,7 @@ ok = false; break; } - qDebug() << fieldName; + //qDebug() << fieldName; col++; } diff --git a/src/mobile/KexiMobileMainWindow.h b/src/mobile/KexiMobileMainWindow.h --- a/src/mobile/KexiMobileMainWindow.h +++ b/src/mobile/KexiMobileMainWindow.h @@ -75,7 +75,7 @@ virtual void slotObjectRenamed(const KexiPart::Item& item, const QString& oldName); virtual tristate switchToViewMode(KexiWindow& window, Kexi::ViewMode viewMode); virtual KToolBar* toolBar(const QString& name) const; - virtual void updatePropertyEditorInfoLabel(const QString& textToDisplayForNullSet = QString()); + virtual void updatePropertyEditorInfoLabel(); virtual KexiUserFeedbackAgent* userFeedbackAgent() const; virtual bool userMode() const; diff --git a/src/mobile/KexiMobileMainWindow.cpp b/src/mobile/KexiMobileMainWindow.cpp --- a/src/mobile/KexiMobileMainWindow.cpp +++ b/src/mobile/KexiMobileMainWindow.cpp @@ -104,13 +104,13 @@ QString driverName = driverManager.lookupByMime(mime.name()); driver = driverManager.driver(driverName.toLower()); - qDebug() << driverManager.driverNames(); - qDebug() << driverName; + //qDebug() << driverManager.driverNames(); + //qDebug() << driverName; KexiProjectData *project_data = new KexiProjectData; project_data->setDatabaseName(url.path()); - qDebug() << driver; + //qDebug() << driver; if (driver && driver->isFileDriver()) { project_data->connectionData()->setFileName(url.path()); @@ -138,8 +138,6 @@ QMap* staticObjectArgs, QString* errorMessage) { Q_ASSERT(openingCancelled); - qDebug() << "KexiMobileMainWindow::openObject"; - KexiWindow *window = 0; if (!openingAllowed(item, viewMode, errorMessage)) { @@ -151,7 +149,7 @@ *openingCancelled = true; return 0; } - qDebug() << m_project << item; + //qDebug() << m_project << item; if (!m_project || !item) return 0; @@ -191,7 +189,7 @@ bool KexiMobileMainWindow::openingAllowed(KexiPart::Item* item, Kexi::ViewMode viewMode, QString* errorMessage) { - qDebug() << viewMode; + //qDebug() << viewMode; //! @todo this can be more complex once we deliver ACLs... //1 Load the part //2 Return true if the part loads AND the part supports the view mode AND the viewmode is Data @@ -202,7 +200,7 @@ *errorMessage = Kexi::partManager().errorMsg(); } } - qDebug() << part << item->pluginId(); + //qDebug() << part << item->pluginId(); /*if (part) qDebug() << item->pluginId() << part->supportedUserViewModes();*/ return part /*&& (part->supportedUserViewModes() & viewMode)*/ && (viewMode == Kexi::DataViewMode); @@ -354,7 +352,7 @@ return 0; } -void KexiMobileMainWindow::updatePropertyEditorInfoLabel(const QString& textToDisplayForNullSet) +void KexiMobileMainWindow::updatePropertyEditorInfoLabel() { } diff --git a/src/mobile/KexiMobileToolbar.cpp b/src/mobile/KexiMobileToolbar.cpp --- a/src/mobile/KexiMobileToolbar.cpp +++ b/src/mobile/KexiMobileToolbar.cpp @@ -65,13 +65,13 @@ void KexiMobileToolbar::gotoNavigatorClicked() { - qDebug() << "Goto Navigator"; + //qDebug() << "Goto Navigator"; emit(pageNavigator()); } void KexiMobileToolbar::openFileClicked() { - qDebug() << "Open File"; + //qDebug() << "Open File"; emit(pageOpenFile()); } @@ -93,7 +93,7 @@ void KexiMobileToolbar::setRecordHandler(KexiRecordNavigatorHandler* handler) { - qDebug() << handler; + //qDebug() << handler; m_recordHandler = handler; updatePage(); } diff --git a/src/mobile/KexiMobileWidget.cpp b/src/mobile/KexiMobileWidget.cpp --- a/src/mobile/KexiMobileWidget.cpp +++ b/src/mobile/KexiMobileWidget.cpp @@ -55,7 +55,7 @@ m_project = project; if (project && (project->open() == true)) { m_navWidget->setProject(project); - qDebug() << "Project opened"; + //qDebug() << "Project opened"; } else { qWarning() << "Project not opened"; if (project) { diff --git a/src/pics/icons/breeze/actions/16/edit-clear-small.svg b/src/pics/icons/breeze/actions/16/edit-clear-small.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/16/edit-clear-small.svg @@ -0,0 +1,96 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/16/mode-selector-design.svg b/src/pics/icons/breeze/actions/16/mode-selector-design.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/16/mode-selector-design.svg @@ -0,0 +1,187 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/16/mode-selector-edit.svg b/src/pics/icons/breeze/actions/16/mode-selector-edit.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/16/mode-selector-edit.svg @@ -0,0 +1,106 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/16/mode-selector-sql.svg b/src/pics/icons/breeze/actions/16/mode-selector-sql.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/16/mode-selector-sql.svg @@ -0,0 +1,94 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/22/mode-selector-design.svg b/src/pics/icons/breeze/actions/22/mode-selector-design.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/22/mode-selector-design.svg @@ -0,0 +1,78 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/22/mode-selector-edit.svg b/src/pics/icons/breeze/actions/22/mode-selector-edit.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/22/mode-selector-edit.svg @@ -0,0 +1,102 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/22/mode-selector-sql.svg b/src/pics/icons/breeze/actions/22/mode-selector-sql.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/22/mode-selector-sql.svg @@ -0,0 +1,90 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/32/mode-selector-design.svg b/src/pics/icons/breeze/actions/32/mode-selector-design.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/32/mode-selector-design.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/src/pics/icons/breeze/actions/32/mode-selector-edit.svg b/src/pics/icons/breeze/actions/32/mode-selector-edit.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/32/mode-selector-edit.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/32/mode-selector-help.svg b/src/pics/icons/breeze/actions/32/mode-selector-help.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/32/mode-selector-help.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/32/mode-selector-project.svg b/src/pics/icons/breeze/actions/32/mode-selector-project.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/32/mode-selector-project.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/32/mode-selector-sql.svg b/src/pics/icons/breeze/actions/32/mode-selector-sql.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/32/mode-selector-sql.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/pics/icons/breeze/actions/32/mode-selector-welcome.svg b/src/pics/icons/breeze/actions/32/mode-selector-welcome.svg new file mode 100644 --- /dev/null +++ b/src/pics/icons/breeze/actions/32/mode-selector-welcome.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/pics/kexi_breeze_files.cmake b/src/pics/kexi_breeze_files.cmake --- a/src/pics/kexi_breeze_files.cmake +++ b/src/pics/kexi_breeze_files.cmake @@ -73,6 +73,7 @@ icons/breeze/actions/16/combobox.svg icons/breeze/actions/16/database-key.svg icons/breeze/actions/16/data-source-tag.svg +icons/breeze/actions/16/edit-clear-small.svg icons/breeze/actions/16/edit-table-clear.svg icons/breeze/actions/16/edit-table-delete-row.svg icons/breeze/actions/16/edit-table-insert-row.svg @@ -82,6 +83,9 @@ icons/breeze/actions/16/imagebox.svg icons/breeze/actions/16/line-horizontal.svg icons/breeze/actions/16/line-vertical.svg +icons/breeze/actions/16/mode-selector-design.svg +icons/breeze/actions/16/mode-selector-edit.svg +icons/breeze/actions/16/mode-selector-sql.svg icons/breeze/actions/16/network-server-database.svg icons/breeze/actions/16/tabwidget-page.svg icons/breeze/actions/16/tabwidget.svg @@ -102,6 +106,9 @@ icons/breeze/actions/22/imagebox.svg icons/breeze/actions/22/line-horizontal.svg icons/breeze/actions/22/line-vertical.svg +icons/breeze/actions/22/mode-selector-design.svg +icons/breeze/actions/22/mode-selector-edit.svg +icons/breeze/actions/22/mode-selector-sql.svg icons/breeze/actions/22/network-server-database.svg icons/breeze/actions/22/tabwidget-page.svg icons/breeze/actions/22/tabwidget.svg @@ -121,6 +128,12 @@ icons/breeze/actions/32/imagebox.svg icons/breeze/actions/32/line-horizontal.svg icons/breeze/actions/32/line-vertical.svg +icons/breeze/actions/32/mode-selector-design.svg +icons/breeze/actions/32/mode-selector-edit.svg +icons/breeze/actions/32/mode-selector-help.svg +icons/breeze/actions/32/mode-selector-project.svg +icons/breeze/actions/32/mode-selector-sql.svg +icons/breeze/actions/32/mode-selector-welcome.svg icons/breeze/actions/32/network-server-database.svg icons/breeze/actions/32/tabwidget-page.svg icons/breeze/actions/32/tabwidget.svg diff --git a/src/plugins/forms/CMakeLists.txt b/src/plugins/forms/CMakeLists.txt --- a/src/plugins/forms/CMakeLists.txt +++ b/src/plugins/forms/CMakeLists.txt @@ -1,6 +1,11 @@ -include_directories( ${CMAKE_SOURCE_DIR}/src/core - ${CMAKE_SOURCE_DIR}/src/widget/utils ${CMAKE_SOURCE_DIR}/src/widget - ${CMAKE_SOURCE_DIR}/src/formeditor) +include_directories( + ${CMAKE_SOURCE_DIR}/src/core + ${CMAKE_SOURCE_DIR}/src/kexiutils/style + ${CMAKE_SOURCE_DIR}/src/widget/utils + ${CMAKE_SOURCE_DIR}/src/widget + ${CMAKE_SOURCE_DIR}/src/widget/properties + ${CMAKE_SOURCE_DIR}/src/formeditor +) # the form plugin set(kexi_formplugin_SRCS kexiforms.cpp) diff --git a/src/plugins/forms/KexiFormScrollAreaWidget.cpp b/src/plugins/forms/KexiFormScrollAreaWidget.cpp --- a/src/plugins/forms/KexiFormScrollAreaWidget.cpp +++ b/src/plugins/forms/KexiFormScrollAreaWidget.cpp @@ -118,8 +118,8 @@ } // needs update? if (neww != -1 && mainAreaWidget->size() != QSize(neww, newh)) { - qDebug() << "mainAreaWidget->size():" << mainAreaWidget->size() - << "neww, newh:" << neww << newh; + //qDebug() << "mainAreaWidget->size():" << mainAreaWidget->size() + // << "neww, newh:" << neww << newh; mainAreaWidget->resize(neww, newh); scrollArea->refreshContentsSize(); emit resized(); diff --git a/src/plugins/forms/kexidatasourcepage.h b/src/plugins/forms/kexidatasourcepage.h --- a/src/plugins/forms/kexidatasourcepage.h +++ b/src/plugins/forms/kexidatasourcepage.h @@ -21,30 +21,41 @@ #include "kexiformutils_export.h" #include -#include - #include #include #include #include +#include + class KexiDataSourceComboBox; class KexiFieldComboBox; class KexiFieldListView; class KexiProject; class QToolButton; class QLabel; +class QVBoxLayout; +class QGridLayout; +class QSpacerItem; //! A page within form designer's property tabbed pane, providing data source editor -class KEXIFORMUTILS_EXPORT KexiDataSourcePage : public KexiPropertyPaneViewBase +class KEXIFORMUTILS_EXPORT KexiDataSourcePage : public QWidget { Q_OBJECT public: - explicit KexiDataSourcePage(QWidget *parent); + explicit KexiDataSourcePage(QWidget *parent = 0); virtual ~KexiDataSourcePage(); + //QSize sizeHint() const Q_DECL_OVERRIDE { return QSize(); } + + enum AssignFlag { + NoFlags = 0, + ForceAssign = 1 + }; + Q_DECLARE_FLAGS(AssignFlags, AssignFlag) + //! @return name plugin ID of selected item (usually a table or a query). Can return an empty string. QString selectedPluginId() const; @@ -61,7 +72,7 @@ void setFormDataSource(const QString& pluginId, const QString& name); //! Receives a pointer to a new property \a set (from KexiFormView::managerPropertyChanged()) - void assignPropertySet(KPropertySet* propertySet); + void assignPropertySet(KPropertySet* propertySet, AssignFlags flags = NoFlags); Q_SIGNALS: //! Signal emitted when helper button 'go to selected data source' is clicked. @@ -94,15 +105,18 @@ protected: void updateSourceFieldWidgetsAvailability(); + QVBoxLayout *m_mainLyr; + QGridLayout *m_formLyr; KexiFieldComboBox *m_widgetDataSourceCombo; - QWidget *m_widgetDataSourceComboSpacer; + QWidget *m_widgetDataSourceContainer; KexiDataSourceComboBox* m_formDataSourceCombo; QWidget *m_formDataSourceComboSpacer; - QLabel *m_dataSourceLabel, *m_noDataSourceAvailableLabel, *m_widgetDSLabel; + QLabel *m_noDataSourceAvailableLabel; QToolButton *m_gotoButton; QString m_noDataSourceAvailableSingleText; QString m_noDataSourceAvailableMultiText; bool m_insideClearFormDataSourceSelection; + bool m_slotWidgetDataSourceTextChangedEnabled; #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT KexiFieldListView* m_availableFieldsLabel; KexiFieldListView* m_fieldListView; diff --git a/src/plugins/forms/kexidatasourcepage.cpp b/src/plugins/forms/kexidatasourcepage.cpp --- a/src/plugins/forms/kexidatasourcepage.cpp +++ b/src/plugins/forms/kexidatasourcepage.cpp @@ -19,9 +19,9 @@ #include "kexidatasourcepage.h" #include +#include #include -#include -#include +#include #include #include #include @@ -40,108 +40,74 @@ #include #include #include +#include +#include KexiDataSourcePage::KexiDataSourcePage(QWidget *parent) - : KexiPropertyPaneViewBase(parent) + : QWidget(parent) , m_noDataSourceAvailableSingleText( - xi18n("No data source could be assigned for this widget.") ) + xi18n("[Can't assign to this widget]") ) , m_noDataSourceAvailableMultiText( - xi18n("No data source could be assigned for multiple widgets.") ) + xi18n("[Can't assign to multiple widgets]") ) , m_insideClearFormDataSourceSelection(false) + , m_slotWidgetDataSourceTextChangedEnabled(true) #ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT , m_tableOrQuerySchema(0) #endif { - infoLabel()->setContentsMargins(0, 0, 0, spacing()); + const KexiStyle::PropertyPane &s = KexiStyle::propertyPane(); + m_mainLyr = s.createVLayout(this); - 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); + s.createTitleLabel(xi18nc("@label Form data source - title", "Data source"), m_mainLyr); - //-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(); + m_formLyr = s.createFormLayout(m_mainLyr); //- 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); - +//! @todo Port "Go to selected form's data source" +#if 0 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 = new KexiDataSourceComboBox; m_formDataSourceCombo->setObjectName("dataSourceCombo"); - m_formDataSourceCombo->setContentsMargins(0, 0, 0, 0); - m_dataSourceLabel->setBuddy(m_formDataSourceCombo); - mainLayout()->addWidget(m_formDataSourceCombo); + s.addLabelAndWidget(xi18nc("@label Forms's data source (table or query)", "Form"), + m_formDataSourceCombo, m_formLyr); - m_formDataSourceComboSpacer = addWidgetSpacer(); + //-Widget's Data Source + m_widgetDataSourceContainer = new QWidget; + QVBoxLayout *widgetDataSourceContainerLyr = new QVBoxLayout(m_widgetDataSourceContainer); + widgetDataSourceContainerLyr->setContentsMargins(0, 0, 0, 0); + + m_widgetDataSourceCombo = new KexiFieldComboBox; + widgetDataSourceContainerLyr->addWidget(m_widgetDataSourceCombo); + s.alterComboBoxStyle(m_widgetDataSourceCombo); + m_widgetDataSourceCombo->setObjectName("sourceFieldCombo"); + connect(m_widgetDataSourceCombo, &KexiFieldComboBox::editTextChanged, + this, &KexiDataSourcePage::slotWidgetDataSourceTextChanged); + + m_noDataSourceAvailableLabel = s.createWarningLabel(m_noDataSourceAvailableSingleText); + m_noDataSourceAvailableLabel->hide(); + widgetDataSourceContainerLyr->addWidget(m_noDataSourceAvailableLabel); + + s.addLabelAndWidget(xi18nc("@label Widget's data source (table field or query field)", "Widget"), + m_widgetDataSourceContainer, m_formLyr); #ifndef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT - mainLayout()->addStretch(); + m_mainLyr->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_mainLyr->addLayout(hlyr); m_mousePointerLabel = new QLabel(this); hlyr->addWidget(m_mousePointerLabel); m_mousePointerLabel->setPixmap(koIcon("tool-pointer")); @@ -157,7 +123,7 @@ //Available Fields hlyr = new QHBoxLayout(); hlyr->setContentsMargins(0, 0, 0, 0); - mainLayout()->addLayout(hlyr); + m_mainLyr->addLayout(hlyr); m_availableFieldsLabel = new QLabel(futureI18n("Available fields"), this); m_availableFieldsLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); hlyr->addWidget(m_availableFieldsLabel); @@ -176,15 +142,15 @@ m_fieldListView->setObjectName("fieldListView"); m_fieldListView->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding)); m_availableFieldsLabel->setBuddy(m_fieldListView); - mainLayout()->addWidget(m_fieldListView, 1); + m_mainLyr->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); + m_mainLyr->addStretch(1); connect(m_formDataSourceCombo, SIGNAL(editTextChanged(QString)), this, SLOT(slotFormDataSourceTextChanged(QString))); @@ -217,7 +183,7 @@ m_insideClearFormDataSourceSelection = true; if (alsoClearComboBox && !m_formDataSourceCombo->selectedName().isEmpty()) m_formDataSourceCombo->setDataSource(QString(), QString()); - m_gotoButton->setEnabled(false); + //! @todo m_gotoButton->setEnabled(false); m_widgetDataSourceCombo->setFieldOrExpression(QString()); #ifdef KEXI_AUTOFIELD_FORM_WIDGET_SUPPORT m_addField->setEnabled(false); @@ -228,6 +194,9 @@ void KexiDataSourcePage::slotWidgetDataSourceTextChanged(const QString &text) { + if (!m_slotWidgetDataSourceTextChangedEnabled) { + return; + } if (text.isEmpty()) { clearWidgetDataSourceSelection(); } @@ -307,15 +276,17 @@ m_tableOrQuerySchema = tableOrQuery; #endif dataSourceFound = true; + m_slotWidgetDataSourceTextChangedEnabled = false; // block clearing widget's data source property m_widgetDataSourceCombo->setTableOrQuery(name, pluginId == "org.kexi-project.table"); + m_slotWidgetDataSourceTextChangedEnabled = true; } else { delete tableOrQuery; } } if (!dataSourceFound) { m_widgetDataSourceCombo->setTableOrQuery(QString(), true); } - m_gotoButton->setEnabled(dataSourceFound); + //! @todo m_gotoButton->setEnabled(dataSourceFound); if (dataSourceFound) { slotFieldListViewSelectionChanged(); } else { @@ -353,28 +324,20 @@ m_formDataSourceCombo->setDataSource(pluginId, name); } -#define KexiDataSourcePage_FADE 1 - -void KexiDataSourcePage::assignPropertySet(KPropertySet* propertySet) +void KexiDataSourcePage::assignPropertySet(KPropertySet* propertySet, AssignFlags flags) { + const KexiStyle::PropertyPane &s = KexiStyle::propertyPane(); QString objectName; if (propertySet) objectName = propertySet->propertyValue("objectName").toString(); - if (!objectName.isEmpty() && objectName == m_currentObjectName) + if (flags != ForceAssign && !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"; @@ -390,39 +353,31 @@ } m_noDataSourceAvailableLabel->hide(); m_widgetDataSourceCombo->setFieldOrExpression(dataSource); - m_widgetDataSourceCombo->setEnabled(true); - m_widgetDSLabel->show(); m_widgetDataSourceCombo->show(); - m_widgetDataSourceComboSpacer->show(); + s.setFormLabelAndWidgetVisible(m_widgetDataSourceContainer, m_formLyr, true); updateSourceFieldWidgetsAvailability(); } } if (isForm) { - m_noDataSourceAvailableLabel->hide(); + // no source field can be set + s.setFormLabelAndWidgetVisible(m_widgetDataSourceContainer, m_formLyr, false); } else if (!hasDataSourceProperty) { if (multipleSelection) { m_noDataSourceAvailableLabel->setText(m_noDataSourceAvailableMultiText); } else { m_noDataSourceAvailableLabel->setText(m_noDataSourceAvailableSingleText); } + s.setFormLabelAndWidgetVisible(m_widgetDataSourceContainer, m_formLyr, true); + m_widgetDataSourceCombo->hide(); 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 + m_mainLyr->update(); + qApp->processEvents(); } void KexiDataSourcePage::slotFieldListViewSelectionChanged() @@ -443,7 +398,6 @@ { 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); diff --git a/src/plugins/forms/kexiformpart.h b/src/plugins/forms/kexiformpart.h --- a/src/plugins/forms/kexiformpart.h +++ b/src/plugins/forms/kexiformpart.h @@ -102,7 +102,7 @@ virtual void initPartActions(); virtual void initInstanceActions(); - virtual void setupCustomPropertyPanelTabs(QTabWidget *tab); + virtual void setupPropertyPane(KexiPropertyPaneWidget *pane); private: class Private; diff --git a/src/plugins/forms/kexiformpart.cpp b/src/plugins/forms/kexiformpart.cpp --- a/src/plugins/forms/kexiformpart.cpp +++ b/src/plugins/forms/kexiformpart.cpp @@ -26,7 +26,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -45,7 +46,6 @@ #include #include -#include #include #include @@ -334,7 +334,7 @@ return d->widgetTree; } -void KexiFormPart::setupCustomPropertyPanelTabs(QTabWidget *tab) +void KexiFormPart::setupPropertyPane(KexiPropertyPaneWidget *pane) { if (!d->dataSourcePage) { d->dataSourcePage = new KexiDataSourcePage(0); @@ -362,19 +362,17 @@ KexiProject *prj = KexiMainWindowIface::global()->project(); d->dataSourcePage->setProject(prj); - tab->addTab(d->dataSourcePage, koIcon("server-database"), QString()); - tab->setTabToolTip(tab->indexOf(d->dataSourcePage), xi18n("Data Source")); + pane->addSection(d->dataSourcePage, xi18n("Data source")); if (!d->widgetTreeWidget) { d->widgetTreeWidget = new QWidget; QVBoxLayout *lyr = new QVBoxLayout(d->widgetTreeWidget); - lyr->setContentsMargins(2, 2, 2, 2); + lyr->setContentsMargins(0, 0, 0, 0); d->widgetTree = new KFormDesigner::WidgetTreeWidget; d->widgetTree->setObjectName("KexiFormPart:WidgetTreeWidget"); lyr->addWidget(d->widgetTree); } - tab->addTab(d->widgetTreeWidget, KexiIcon("widgets"), QString()); - tab->setTabToolTip(tab->indexOf(d->widgetTreeWidget), xi18n("Widgets")); + //! @todo pane->addSection(d->widgetTreeWidget, xi18n("Widgets")); } //---------------- diff --git a/src/plugins/forms/kexiformscrollview.cpp b/src/plugins/forms/kexiformscrollview.cpp --- a/src/plugins/forms/kexiformscrollview.cpp +++ b/src/plugins/forms/kexiformscrollview.cpp @@ -411,7 +411,7 @@ foreach(KexiFormDataItemInterface *dataItemIface, m_dataItems) { qDebug() << (dynamic_cast(dataItemIface) ? dynamic_cast(dataItemIface)->objectName() : "") - << " " << dataItemIface->dataSource(); + << dataItemIface->dataSource(); } //qDebug() << "-- focus widgets --"; foreach(QWidget* widget, *dbFormWidget()->orderedFocusWidgets()) { diff --git a/src/plugins/forms/kexiformview.h b/src/plugins/forms/kexiformview.h --- a/src/plugins/forms/kexiformview.h +++ b/src/plugins/forms/kexiformview.h @@ -141,6 +141,9 @@ //! Used in loadForm() void updateValuesForSubproperties(); + //! Reimplemented to pass the information + void propertySetSwitched() Q_DECL_OVERRIDE; + virtual void resizeEvent(QResizeEvent *); //! Reimplemented for context key event of top-level form widget. diff --git a/src/plugins/forms/kexiformview.cpp b/src/plugins/forms/kexiformview.cpp --- a/src/plugins/forms/kexiformview.cpp +++ b/src/plugins/forms/kexiformview.cpp @@ -195,7 +195,7 @@ KexiFormView::~KexiFormView() { deleteQuery(); - propertySetSwitched(); + KexiDataAwareView::propertySetSwitched(); delete d; } @@ -360,6 +360,15 @@ #endif } +void KexiFormView::propertySetSwitched() +{ + KexiDataAwareView::propertySetSwitched(); + updateDataSourcePage(); + if (viewMode() == Kexi::DesignViewMode) { + formPart()->dataSourcePage()->assignPropertySet(form()->propertySet(), KexiDataSourcePage::ForceAssign); + } +} + void KexiFormView::updateValuesForSubproperties() { //! @todo call this when form's data source is changed @@ -389,7 +398,7 @@ subpropIt != subprops->constEnd(); ++subpropIt) { //qDebug() << "delayed setting of the subproperty: widget=" - // << item->widget()->objectName() << " prop=" << subpropIt.key() << " val=" + // << item->widget()->objectName() << "prop=" << subpropIt.key() << "val=" // << subpropIt.value(); QMetaProperty meta = KexiUtils::findPropertyWithSuperclasses( @@ -695,7 +704,7 @@ //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) << ")"; + //qDebug() << "invalidSources+=" << index << "(" << (*it) << ")"; continue; } if (tableSchema) { @@ -710,7 +719,7 @@ deleteQuery(); } else { - qDebug() << d->query->parameters(conn); + //qDebug() << d->query->parameters(); // like in KexiQueryView::executeQuery() QList params; { @@ -817,7 +826,7 @@ qWarning() << "it.key()==0 !"; continue; } - //qDebug() << "name=" << it.key()->objectName() << " dataID=" << it.value(); + //qDebug() << "name=" << it.key()->objectName() << "dataID=" << it.value(); KexiBLOBBuffer::Handle h(blobBuf->objectForId(it.value(), /*!stored*/false)); if (!h) continue; //no BLOB assigned @@ -1271,7 +1280,6 @@ 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) diff --git a/src/plugins/forms/widgets/kexidbautofield.cpp b/src/plugins/forms/widgets/kexidbautofield.cpp --- a/src/plugins/forms/widgets/kexidbautofield.cpp +++ b/src/plugins/forms/widgets/kexidbautofield.cpp @@ -208,8 +208,8 @@ { //qDebug() << subwidget(); if (subwidget()) { -// qDebug() << "base col: " << d->baseColor.name() << -// "; text col: " << d->textColor.name(); +// qDebug() << "base col:" << d->baseColor.name() << +// "; text col:" << d->textColor.name(); QPalette p(subwidget()->palette()); p.setBrush(QPalette::Base, d->baseBrush); if (d->widgetType == Boolean) diff --git a/src/plugins/forms/widgets/kexidbcombobox.cpp b/src/plugins/forms/widgets/kexidbcombobox.cpp --- a/src/plugins/forms/widgets/kexidbcombobox.cpp +++ b/src/plugins/forms/widgets/kexidbcombobox.cpp @@ -465,7 +465,7 @@ bool KexiDBComboBox::valueChanged() { - //qDebug() << KexiDataItemInterface::originalValue().toString() << " ? " << value().toString(); + //qDebug() << KexiDataItemInterface::originalValue().toString() << "?" << value().toString(); return KexiDataItemInterface::originalValue() != value(); } diff --git a/src/plugins/forms/widgets/kexidbform.cpp b/src/plugins/forms/widgets/kexidbform.cpp --- a/src/plugins/forms/widgets/kexidbform.cpp +++ b/src/plugins/forms/widgets/kexidbform.cpp @@ -69,7 +69,7 @@ indicesForDataAwareWidgets.find(item)); if (indicesForDataAwareWidgetsIt == indicesForDataAwareWidgets.constEnd()) return -1; - //qDebug() << "column # for item: " << indicesForDataAwareWidgetsIt.value(); + //qDebug() << "column # for item:" << indicesForDataAwareWidgetsIt.value(); return indicesForDataAwareWidgetsIt.value(); } @@ -114,8 +114,6 @@ editedItem = 0; d->dataAwareObject = dataAwareObject; KexiDataItemInterface::setHasFocusableWidget(false); - - qDebug() << ":"; setCursor(QCursor(Qt::ArrowCursor)); //to avoid keeping Size cursor when moving from form's boundaries setAcceptDrops(true); setAutoFillBackground(true); @@ -168,8 +166,8 @@ foreach (KFormDesigner::ObjectTreeItem* titem, *form->tabStops()) { if (titem->widget()->focusPolicy() & Qt::TabFocus) { if (fromWidget) { - qDebug() << "tab order: " - << fromWidget->objectName() << "->" << titem->widget()->objectName(); + //qDebug() << "tab order:" + // << fromWidget->objectName() << "->" << titem->widget()->objectName(); } fromWidget = titem->widget(); d->orderedFocusWidgets.append(titem->widget()); @@ -179,17 +177,17 @@ //also filter events for data-aware children of this widget (i.e. KexiDBAutoField's editors) QList children(titem->widget()->findChildren()); foreach(QWidget* widget, children) { - qDebug() << "also adding '" + /*qDebug() << "also adding '" << widget->metaObject()->className() - << " " << widget->objectName() - << "' child to filtered widgets"; + << widget->objectName() + << "' child to filtered widgets";*/ widget->installEventFilter(this); } KexiFormDataItemInterface* dataItem = dynamic_cast(titem->widget()); if (dataItem && !dataItem->dataSource().isEmpty()) { - qDebug() << "#" << numberOfDataAwareWidgets << ": " - << dataItem->dataSource() << " (" << titem->widget()->objectName() << ")"; + //qDebug() << "#" << numberOfDataAwareWidgets << ": " + // << dataItem->dataSource() << "(" << titem->widget()->objectName() << ")"; //! @todo d->indicesForDataAwareWidgets SHOULD NOT BE UPDATED HERE BECAUSE //! THERE CAN BE ALSO NON-TABSTOP DATA WIDGETS! @@ -203,8 +201,8 @@ //restore ordering for (QPtrListIterator it(d->orderedFocusWidgets); it.current(); ++it) { if (fromWidget) { - qDebug() << "tab order: " << fromWidget->name() - << " -> " << it.current()->name(); + qDebug() << "tab order:" << fromWidget->name() + << "->" << it.current()->name(); setTabOrder( fromWidget, it.current() ); } fromWidget = it.current(); @@ -439,7 +437,7 @@ if (tab) { //qDebug() << e->type() << "focusing " << widgetToFocus->objectName(); widgetToFocus->setFocus(); - //qDebug() << e->type() << "focusing " << (*d->orderedFocusWidgetsIterator)->objectName(); + //qDebug() << "focusing" << (*d->orderedFocusWidgetsIterator)->objectName(); (*d->orderedFocusWidgetsIterator)->setFocus(); } KexiFormDataItemInterface *formItem = dynamic_cast(widgetToSelectAll); @@ -460,7 +458,7 @@ } if (focusDataWidget) { - //qDebug() << "FocusIn: " << watched->metaObject()->className() << " " << watched->objectName(); + //qDebug() << "FocusIn:" << watched->metaObject()->className() << watched->objectName(); if (d->dataAwareObject) { QWidget *dataItem = dynamic_cast(watched); while (dataItem) { @@ -470,7 +468,7 @@ if (!dataItem) { break; } - //qDebug() << "FocusIn: FOUND " << dataItem->metaObject()->className() << " " << dataItem->objectName(); + //qDebug() << "FocusIn: FOUND" << dataItem->metaObject()->className() << dataItem->objectName(); const int index = d->indexOfDataAwareWidget(dataItem); if (index >= 0) { @@ -494,7 +492,7 @@ } else { d->popupFocused = false; } -// qDebug() << "e->type()==QEvent::FocusOut " << watched->className() << " " <name(); +// qDebug() << "e->type()==QEvent::FocusOut" << watched->className() << watched->name(); } return QWidget::eventFilter(watched, e); } diff --git a/src/plugins/forms/widgets/kexidbimagebox.cpp b/src/plugins/forms/widgets/kexidbimagebox.cpp --- a/src/plugins/forms/widgets/kexidbimagebox.cpp +++ b/src/plugins/forms/widgets/kexidbimagebox.cpp @@ -709,17 +709,18 @@ return; if (!KexiDBImageBox_static->pixmap) { - QPixmap pm( KIconLoader::global()->loadMimeTypeIcon( - koIconNameCStr("image-x-generic"), KIconLoader::NoGroup, KIconLoader::SizeLarge, KIconLoader::DisabledState) ); - if (!pm.isNull()) { - KIconEffect::semiTransparent(pm); - KIconEffect::semiTransparent(pm); + const QIcon icon(KexiIcon("imagebox")); + KexiDBImageBox_static->pixmap = new QPixmap( + icon.pixmap(KIconLoader::SizeLarge, KIconLoader::SizeLarge, QIcon::Disabled)); + if (!KexiDBImageBox_static->pixmap->isNull()) { + KIconEffect::semiTransparent(*KexiDBImageBox_static->pixmap); + KIconEffect::semiTransparent(*KexiDBImageBox_static->pixmap); } - KexiDBImageBox_static->pixmap = new QPixmap(pm); KexiDBImageBox_static->small = new QPixmap( - KexiDBImageBox_static->pixmap->scaled( - KexiDBImageBox_static->pixmap->width() / 2, KexiDBImageBox_static->pixmap->height() / 2, - Qt::KeepAspectRatio, Qt::SmoothTransformation) ); + icon.pixmap(KIconLoader::SizeSmall, KIconLoader::SizeSmall, QIcon::Disabled)); + if (!KexiDBImageBox_static->small->isNull()) { + KIconEffect::semiTransparent(*KexiDBImageBox_static->small); // once is enough for small + } } } diff --git a/src/plugins/forms/widgets/kexidbutils.cpp b/src/plugins/forms/widgets/kexidbutils.cpp --- a/src/plugins/forms/widgets/kexidbutils.cpp +++ b/src/plugins/forms/widgets/kexidbutils.cpp @@ -68,7 +68,7 @@ int size = IconSize(KIconLoader::Small); if (size < KIconLoader::SizeSmallMedium && fm.height() >= KIconLoader::SizeSmallMedium) size = KIconLoader::SizeSmallMedium; - m_dataSourceTagIcon = QIcon::fromTheme(KexiIconName("data-source-tag")).pixmap(size); + m_dataSourceTagIcon = KexiIcon("data-source-tag").pixmap(size); KIconEffect::semiTransparent(m_dataSourceTagIcon); m_dataSourceRTLTagIcon = QPixmap::fromImage(m_dataSourceTagIcon.toImage().mirrored(true /*h*/, false /*v*/)); } diff --git a/src/plugins/forms/widgets/mapbrowser/MapBrowserFactory.cpp b/src/plugins/forms/widgets/mapbrowser/MapBrowserFactory.cpp --- a/src/plugins/forms/widgets/mapbrowser/MapBrowserFactory.cpp +++ b/src/plugins/forms/widgets/mapbrowser/MapBrowserFactory.cpp @@ -78,7 +78,7 @@ if (w){ w->setObjectName(name); - qDebug() << w << w->objectName() << "created"; + //qDebug() << w << w->objectName() << "created"; return w; } qWarning() << "w == 0"; diff --git a/src/plugins/forms/widgets/webbrowser/WebBrowserFactory.cpp b/src/plugins/forms/widgets/webbrowser/WebBrowserFactory.cpp --- a/src/plugins/forms/widgets/webbrowser/WebBrowserFactory.cpp +++ b/src/plugins/forms/widgets/webbrowser/WebBrowserFactory.cpp @@ -80,7 +80,7 @@ if (w){ w->setObjectName(name); - qDebug() << w << w->objectName() << "created"; + //qDebug() << w << w->objectName() << "created"; return w; } qWarning() << "w == 0"; diff --git a/src/plugins/importexport/csv/kexicsvexport.cpp b/src/plugins/importexport/csv/kexicsvexport.cpp --- a/src/plugins/importexport/csv/kexicsvexport.cpp +++ b/src/plugins/importexport/csv/kexicsvexport.cpp @@ -124,8 +124,8 @@ int bufSize = qMin((recordCount < 0 ? 10 : recordCount) * fields.count() * 20, 128000); buffer.reserve(bufSize); if (buffer.capacity() < bufSize) { - qWarning() << "Cannot allocate memory for " << bufSize - << " characters"; + qWarning() << "Cannot allocate memory for" << bufSize + << "characters"; return false; } } else { @@ -138,12 +138,12 @@ } kSaveFile.reset(new QSaveFile(options.fileName)); - qDebug() << "QSaveFile Filename:" << kSaveFile->fileName(); + //qDebug() << "QSaveFile Filename:" << kSaveFile->fileName(); if (kSaveFile->open(QIODevice::WriteOnly)) { kSaveFileTextStream.reset(new QTextStream(kSaveFile.data())); stream = kSaveFileTextStream.data(); - qDebug() << "have a stream"; + //qDebug() << "have a stream"; } if (QFileDevice::NoError != kSaveFile->error() || !stream) {//sanity qWarning() << "Status != 0 or stream == 0"; @@ -272,7 +272,7 @@ if (copyToClipboard) QApplication::clipboard()->setText(buffer, QClipboard::Clipboard); - qDebug() << "Done"; + //qDebug() << "Done"; if (kSaveFile) { stream->flush(); diff --git a/src/plugins/importexport/csv/kexicsvimportdialog.cpp b/src/plugins/importexport/csv/kexicsvimportdialog.cpp --- a/src/plugins/importexport/csv/kexicsvimportdialog.cpp +++ b/src/plugins/importexport/csv/kexicsvimportdialog.cpp @@ -1316,7 +1316,7 @@ } if (inGUI && row > (m_maximumRowsForPreview + (m_table->firstRowForFieldNames() ? 1 : 0))) { - qDebug() << "loading stopped at row #" << m_maximumRowsForPreview; + //qDebug() << "loading stopped at row #" << m_maximumRowsForPreview; break; } if (nextRow) { @@ -1732,7 +1732,7 @@ else m_textquote = tq[0]; - qDebug() << m_textquote; + //qDebug() << m_textquote; //delayed, otherwise combobox won't be repainted fillTableLater(); diff --git a/src/plugins/queries/CMakeLists.txt b/src/plugins/queries/CMakeLists.txt --- a/src/plugins/queries/CMakeLists.txt +++ b/src/plugins/queries/CMakeLists.txt @@ -1,5 +1,10 @@ -include_directories(${CMAKE_SOURCE_DIR}/src/core - ${CMAKE_SOURCE_DIR}/src/widget ${CMAKE_SOURCE_DIR}/src/widget/tableview) +include_directories( + ${CMAKE_SOURCE_DIR}/src/core + ${CMAKE_SOURCE_DIR}/src/widget + ${CMAKE_SOURCE_DIR}/src/widget/tableview + ${CMAKE_SOURCE_DIR}/src/widget/properties + ${CMAKE_SOURCE_DIR}/src/kexiutils/style +) # the main plugin set(kexi_queryplugin_SRCS diff --git a/src/plugins/queries/kexiquerydesignerguieditor.cpp b/src/plugins/queries/kexiquerydesignerguieditor.cpp --- a/src/plugins/queries/kexiquerydesignerguieditor.cpp +++ b/src/plugins/queries/kexiquerydesignerguieditor.cpp @@ -20,6 +20,7 @@ #include "kexiquerydesignerguieditor.h" #include +#include #include #include #include @@ -188,6 +189,7 @@ d->dataTable->dataAwareObject()->setSpreadSheetMode(true); d->data = new KDbTableViewData(); //just empty data + setTextToDisplayForNullSet(xi18nc("No query column selected in the Query Designer", "No column selected")); d->sets = new KexiDataAwarePropertySet(this, d->dataTable->dataAwareObject()); connect(d->sets, SIGNAL(propertyChanged(KPropertySet&,KProperty&)), this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&))); @@ -198,6 +200,7 @@ QList c; c << COLUMN_ID_COLUMN << COLUMN_ID_TABLE << COLUMN_ID_CRITERIA; if (d->dataTable->tableView()/*sanity*/) { + KexiStyle::setupFrame(d->dataTable->tableView()); d->dataTable->tableView()->adjustColumnWidthToContents(COLUMN_ID_VISIBLE); d->dataTable->tableView()->setColumnWidth(COLUMN_ID_SORTING, d->sortColumnPreferredWidth); d->dataTable->tableView()->setStretchLastColumn(true); @@ -418,7 +421,7 @@ if (!(**it)[COLUMN_ID_TABLE].isNull() && (**it)[COLUMN_ID_COLUMN].isNull()) { //show message about missing field name, and set focus to that cell - qDebug() << "no field provided!"; + //qDebug() << "no field provided!"; d->dataTable->dataAwareObject()->setCursorPosition(i, 0); if (errMsg) *errMsg = xi18nc("@info", "Select column for table %1", @@ -529,7 +532,7 @@ } if (!fieldVisible && criteriaStr.isEmpty() && set->contains("isExpression") && (*set)["sorting"].value().toString() != "nosorting") { - qDebug() << "invisible field with sorting: do not add it to the fields list"; + //qDebug() << "invisible field with sorting: do not add it to the fields list"; continue; } const int tablePosition = temp->query()->tablePosition(t->name()); @@ -631,7 +634,7 @@ } temp->query()->setOrderByColumnList(orderByColumns); - qDebug() << KDbConnectionAndQuerySchema(conn, *temp->query()); + //qDebug() << KDbConnectionAndQuerySchema(conn, *temp->query()); temp->registerTableSchemaChanges(temp->query()); //! @todo ? return true; @@ -641,12 +644,12 @@ KexiQueryDesignerGuiEditor::beforeSwitchTo(Kexi::ViewMode mode, bool *dontStore) { Q_ASSERT(dontStore); - qDebug() << mode; + //qDebug() << mode; if (!d->dataTable->dataAwareObject()->acceptRecordEditing()) return cancelled; - qDebug() << "queryChangedInView:" << tempData()->queryChangedInView(); + //qDebug() << "queryChangedInView:" << tempData()->queryChangedInView(); if (mode == Kexi::DesignViewMode) { return true; @@ -909,7 +912,7 @@ if (!eItem.isValid()) continue; - qDebug() << eItem; + //qDebug() << eItem; KDbBinaryExpression binary(eItem.toBinary()); if (binary.isValid() && eItem.expressionClass() == KDb::RelationalExpression) { KDbField *leftField = 0, *rightField = 0; @@ -952,10 +955,10 @@ QSet usedCriterias; // <-- used criterias will be saved here // so in step 4. we will be able to add // remaining invisible columns with criterias - qDebug() << KDbConnectionAndQuerySchema(conn, *query); + /*qDebug() << KDbConnectionAndQuerySchema(conn, *query); foreach(KDbField* field, *query->fields()) { qDebug() << *field; - } + }*/ foreach(KDbField* field, *query->fields()) { //append a new row QString tableName, fieldName, columnAlias, criteriaString; @@ -1033,8 +1036,8 @@ const int columnPosition = columnsOrder.value(column); data = d->data->at(columnPosition); rowPropertySet = d->sets->at(columnPosition); - qDebug() << "\tSetting \"" << *orderByColumn << "\" sorting for record #" - << columnPosition; + //qDebug() << "\tSetting \"" << *orderByColumn << "\" sorting for record #" + // << columnPosition; } } } else if (orderByColumn->field()) { @@ -1045,8 +1048,8 @@ d->dataTable->dataAwareObject()->insertItem(data, row_num); rowPropertySet = createPropertySet(row_num, tableName, field->name(), true /*newOne*/); propertySetSwitched(); - qDebug() << "\tSetting \"" << *orderByColumn << "\" sorting for invisible field" - << field->name() << ", table " << tableName << " -row #" << row_num; + //qDebug() << "\tSetting \"" << *orderByColumn << "\" sorting for invisible field" + // << field->name() << ", table" << tableName << "-row #" << row_num; row_num++; } //alter sorting for either existing or new row @@ -1703,7 +1706,7 @@ if (newValue.toInt() == 0 || sortingAllowed(field, table)) { KProperty &property = set->property("sorting"); QString key(property.listData()->keysAsStringList()[ newValue.toInt()]); - qDebug() << "new key=" << key; + //qDebug() << "new key=" << key; property.setValue(key, valueOptions); } else { //show msg: sorting is not available diff --git a/src/plugins/queries/kexiquerypart.h b/src/plugins/queries/kexiquerypart.h --- a/src/plugins/queries/kexiquerypart.h +++ b/src/plugins/queries/kexiquerypart.h @@ -101,6 +101,8 @@ Reimplemented to mark the query obsolete by using KDbConnection::setQuerySchemaObsolete(). */ virtual tristate rename(KexiPart::Item *item, const QString& newName); + void setupPropertyPane(KexiPropertyPaneWidget* pane) Q_DECL_OVERRIDE; + /** * Closes objects that listenen to changes of the query schema @a query, i.e. use it. * @@ -145,6 +147,11 @@ virtual KDbObject* loadSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow); + + Q_DISABLE_COPY(KexiQueryPart) + + class Private; + Private * const d2; }; #endif diff --git a/src/plugins/queries/kexiquerypart.cpp b/src/plugins/queries/kexiquerypart.cpp --- a/src/plugins/queries/kexiquerypart.cpp +++ b/src/plugins/queries/kexiquerypart.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -37,9 +38,17 @@ #include #include +#include KEXI_PLUGIN_FACTORY(KexiQueryPart, "kexi_queryplugin.json") +class KexiQueryPart::Private +{ +public: + Private() : propertyPaneSpacer(0) {} + QWidget *propertyPaneSpacer; //!< needed until we have at least one property pane section +}; + KexiQueryPart::KexiQueryPart(QObject *parent, const QVariantList &l) : KexiPart::Part(parent, xi18nc("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " @@ -49,12 +58,15 @@ xi18nc("tooltip", "Create new query"), xi18nc("what's this", "Creates new query."), l) + , d2(new Private) { - setInternalPropertyValue("textViewModeCaption", xi18n("SQL")); + setInternalPropertyValue("textViewModeCaption", xi18nc("@action:button SQL query design view", "SQL")); + setInternalPropertyValue("textViewModeToolTip", xi18nc("@info:tooltip SQL query design view", "Switch to SQL design view")); } KexiQueryPart::~KexiQueryPart() { + delete d2; } KexiWindowData* KexiQueryPart::createWindowData(KexiWindow* window) @@ -157,15 +169,15 @@ //! @todo return 0; } - qDebug() << KDbConnectionAndQuerySchema( - KexiMainWindowIface::global()->project()->dbConnection(), *query); + //qDebug() << KDbConnectionAndQuerySchema( + // KexiMainWindowIface::global()->project()->dbConnection(), *query); (KDbObject&)*query = object; //copy main attributes temp->registerTableSchemaChanges(query); *ownedByWindow = true; // owned because it is created by the parser - qDebug() << KDbConnectionAndQuerySchema( - KexiMainWindowIface::global()->project()->dbConnection(), *query); + //qDebug() << KDbConnectionAndQuerySchema( + // KexiMainWindowIface::global()->project()->dbConnection(), *query); return query; } @@ -205,6 +217,16 @@ return true; } +void KexiQueryPart::setupPropertyPane(KexiPropertyPaneWidget* pane) +{ + if (!d2->propertyPaneSpacer) { + d2->propertyPaneSpacer = new QWidget; + QVBoxLayout *lyr = new QVBoxLayout(d2->propertyPaneSpacer); + lyr->addStretch(1); + } + pane->addSection(d2->propertyPaneSpacer, QString()); +} + // static tristate KexiQueryPart::askForClosingObjectsUsingQuerySchema(KexiWindow *window, KDbConnection *conn, diff --git a/src/plugins/queries/kexiqueryview.cpp b/src/plugins/queries/kexiqueryview.cpp --- a/src/plugins/queries/kexiqueryview.cpp +++ b/src/plugins/queries/kexiqueryview.cpp @@ -83,7 +83,7 @@ if (query) { KexiUtils::WaitCursor wait; KDbConnection * conn = KexiMainWindowIface::global()->project()->dbConnection(); - qDebug() << query->parameters(conn); + //qDebug() << query->parameters(conn); bool ok; { KexiUtils::WaitCursorRemover remover; diff --git a/src/plugins/reports/CMakeLists.txt b/src/plugins/reports/CMakeLists.txt --- a/src/plugins/reports/CMakeLists.txt +++ b/src/plugins/reports/CMakeLists.txt @@ -1,6 +1,8 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/core + ${CMAKE_SOURCE_DIR}/src/kexiutils/style ${CMAKE_SOURCE_DIR}/src/widget + ${CMAKE_SOURCE_DIR}/src/widget/properties ) # the main plugin diff --git a/src/plugins/reports/KexiDBReportDataSource.cpp b/src/plugins/reports/KexiDBReportDataSource.cpp --- a/src/plugins/reports/KexiDBReportDataSource.cpp +++ b/src/plugins/reports/KexiDBReportDataSource.cpp @@ -99,7 +99,7 @@ } } } else { - qDebug() << "Unable to add expresstion to null schema"; + qWarning() << "Unable to add expresstion to null schema"; } } @@ -119,15 +119,15 @@ } else if ( d->copySchema) { - qDebug() << "Opening cursor.." - << KDbConnectionAndQuerySchema(d->tempData->connection(), *d->copySchema); + //qDebug() << "Opening cursor.." + // << KDbConnectionAndQuerySchema(d->tempData->connection(), *d->copySchema); d->cursor = d->tempData->connection()->executeQuery(d->copySchema, KDbCursor::Option::Buffered); } if ( d->cursor ) { - qDebug() << "Moving to first record.."; + //qDebug() << "Moving to first record.."; return d->cursor->moveFirst(); } else @@ -161,32 +161,32 @@ if ((pluginId.isEmpty() || pluginId == "org.kexi-project.table") && (table = d->tempData->connection()->tableSchema(d->objectName))) { - qDebug() << d->objectName << "is a table.."; + //qDebug() << d->objectName << "is a table.."; d->originalSchema = new KDbQuerySchema(table); } else if ((pluginId.isEmpty() || pluginId == "org.kexi-project.query") && (query = d->tempData->connection()->querySchema(d->objectName))) { - qDebug() << d->objectName << "is a query.."; - qDebug() << KDbConnectionAndQuerySchema(d->tempData->connection(), *query); + //qDebug() << d->objectName << "is a query.."; + //qDebug() << KDbConnectionAndQuerySchema(d->tempData->connection(), *query); d->originalSchema = new KDbQuerySchema(*query, d->tempData->connection()); } if (d->originalSchema) { const KDbNativeStatementBuilder builder(d->tempData->connection(), KDb::DriverEscaping); KDbEscapedString sql; if (builder.generateSelectStatement(&sql, d->originalSchema)) { - qDebug() << "Original:" << sql; + //qDebug() << "Original:" << sql; } else { qDebug() << "Original: ERROR"; return false; } - qDebug() << KDbConnectionAndQuerySchema(d->tempData->connection(), *d->originalSchema); - + //qDebug() << KDbConnectionAndQuerySchema(d->tempData->connection(), *d->originalSchema); d->copySchema = new KDbQuerySchema(*d->originalSchema, d->tempData->connection()); - qDebug() << KDbConnectionAndQuerySchema(d->tempData->connection(), *d->copySchema); + //qDebug() << KDbConnectionAndQuerySchema(d->tempData->connection(), *d->copySchema); + if (builder.generateSelectStatement(&sql, d->copySchema)) { - qDebug() << "Copy:" << sql; + //qDebug() << "Copy:" << sql; } else { qDebug() << "Copy: ERROR"; return false; diff --git a/src/plugins/reports/kexireportdesignview.cpp b/src/plugins/reports/kexireportdesignview.cpp --- a/src/plugins/reports/kexireportdesignview.cpp +++ b/src/plugins/reports/kexireportdesignview.cpp @@ -37,7 +37,7 @@ : KexiView(parent) { m_scrollArea = new QScrollArea(this); - layout()->addWidget(m_scrollArea); + setViewWidget(m_scrollArea); m_sourceSelector = s; m_reportDesigner = 0; @@ -80,8 +80,28 @@ return m_reportDesigner->selectedItemPropertySet(); } +//! Finds or creates property +static KProperty* findOrCreateProperty(KPropertySet *set, const char *name, const QVariant &value) +{ + KProperty *prop; + if (set->contains(name)) { + prop = &set->property(name); + prop->setValue(value); + } else { + prop = new KProperty(name, value); + prop->setVisible(false); + set->addProperty(prop); + } + return prop; +} + void KexiReportDesignView::slotDesignerPropertySetChanged() { + KPropertySet *set = propertySet(); + if (set) { + KProperty *prop = findOrCreateProperty(set, "this:visibleObjectNameProperty", "name"); + Q_UNUSED(prop) + } propertySetReloaded(true); propertySetSwitched(); } @@ -95,7 +115,7 @@ delete s; return 0; } - qDebug() << "new id:" << s->id(); + //qDebug() << "new id:" << s->id(); if (!storeData()) { //failure: remove object's object data to avoid garbage @@ -116,34 +136,35 @@ QDomElement root = doc.createElement("kexireport"); QDomElement conndata = connectionData(); - if (conndata.isNull()) - qDebug() << "Null conn data!"; + if (conndata.isNull()) { + //qDebug() << "Null conn data!"; + } root.appendChild(m_reportDesigner->document()); root.appendChild(conndata); doc.appendChild(root); QString src = doc.toString(); - qDebug() << src; + //qDebug() << src; if (storeDataBlock(src, "layout")) { - qDebug() << "Saved OK"; + //qDebug() << "Saved OK"; setDirty(false); return true; } - qDebug() << "NOT Saved OK"; + //qDebug() << "NOT Saved OK"; return false; } tristate KexiReportDesignView::beforeSwitchTo(Kexi::ViewMode mode, bool *dontStore) { - qDebug() << mode; + //qDebug() << mode; *dontStore = true; if (m_reportDesigner && mode == Kexi::DataViewMode) { - qDebug() << "Saving temp data"; + //qDebug() << "Saving temp data"; tempData()->reportDefinition = m_reportDesigner->document(); - qDebug() << m_reportDesigner->document().toDocument().toString(); + //qDebug() << m_reportDesigner->document().toDocument().toString(); tempData()->reportSchemaChangedInPreviousView = true; } return true; diff --git a/src/plugins/reports/kexireportpart.h b/src/plugins/reports/kexireportpart.h --- a/src/plugins/reports/kexireportpart.h +++ b/src/plugins/reports/kexireportpart.h @@ -73,7 +73,7 @@ */ virtual ~KexiReportPart(); - virtual void setupCustomPropertyPanelTabs(QTabWidget *tab); + virtual void setupPropertyPane(KexiPropertyPaneWidget *pane); virtual KLocalizedString i18nMessage(const QString& englishMessage, KexiWindow* window) const; diff --git a/src/plugins/reports/kexireportpart.cpp b/src/plugins/reports/kexireportpart.cpp --- a/src/plugins/reports/kexireportpart.cpp +++ b/src/plugins/reports/kexireportpart.cpp @@ -20,7 +20,6 @@ #include "kexireportpart.h" -#include #include #include @@ -32,6 +31,7 @@ #include "kexireportview.h" #include "kexireportdesignview.h" #include +#include #include "kexisourceselector.h" #include #include @@ -202,13 +202,12 @@ return KexiMainWindowIface::global()->closeWindow(window); } -void KexiReportPart::setupCustomPropertyPanelTabs(QTabWidget *tab) +void KexiReportPart::setupPropertyPane(KexiPropertyPaneWidget *pane) { if (!d->sourceSelector) { - d->sourceSelector = new KexiSourceSelector(KexiMainWindowIface::global()->project(), tab); + d->sourceSelector = new KexiSourceSelector(KexiMainWindowIface::global()->project()); } - tab->addTab(d->sourceSelector, koIcon("server-database"), QString()); - tab->setTabToolTip(tab->indexOf(d->sourceSelector), xi18n("Data Source")); + pane->addSection(d->sourceSelector, xi18n("Data source")); } void KexiReportPart::slotToolboxActionTriggered(bool checked) diff --git a/src/plugins/reports/kexireportview.cpp b/src/plugins/reports/kexireportview.cpp --- a/src/plugins/reports/kexireportview.cpp +++ b/src/plugins/reports/kexireportview.cpp @@ -26,6 +26,7 @@ #include #include #include +#include //! @todo KEXI3 #include "../scripting/kexiscripting/kexiscriptadaptor.h" @@ -55,7 +56,8 @@ setObjectName("KexiReportDesigner_DataView"); m_reportView = new KReportView(this); - layout()->addWidget(m_reportView); + setViewWidget(m_reportView); + KexiStyle::setupFrame(m_reportView->scrollArea()); #ifndef KEXI_MOBILE m_pageSelector = new KexiRecordNavigator(*m_reportView->scrollArea(), m_reportView); @@ -356,6 +358,7 @@ delete m_preRenderer; //qDebug() << tempData()->reportDefinition.tagName(); + m_preRenderer = new KReportPreRenderer(tempData()->reportDefinition); if (m_preRenderer->isValid()) { KReportDataSource *reportData = 0; diff --git a/src/plugins/reports/kexisourceselector.h b/src/plugins/reports/kexisourceselector.h --- a/src/plugins/reports/kexisourceselector.h +++ b/src/plugins/reports/kexisourceselector.h @@ -33,7 +33,7 @@ class KexiProject; //! @todo rename to KexiReportDataSourcePage -//! @todo use KexiPropertyPaneViewBase +//! @todo use KexiPropertyPaneWidget class KexiSourceSelector : public QWidget { Q_OBJECT diff --git a/src/plugins/reports/krscriptfunctions.cpp b/src/plugins/reports/krscriptfunctions.cpp --- a/src/plugins/reports/krscriptfunctions.cpp +++ b/src/plugins/reports/krscriptfunctions.cpp @@ -100,15 +100,13 @@ QVariant KRScriptFunctions::value(const QString &field) { - QVariant val; if (!m_cursor) { - qDebug() << "No cursor to get value of field " << field; - return val; + qDebug() << "No cursor to get value of field" << field; + return QVariant(); } QStringList fields = m_cursor->fieldNames(); - - val = m_cursor->value(fields.indexOf(field)); + QVariant val = m_cursor->value(fields.indexOf(field)); if (val.type() == QVariant::String) { // UTF-8 values are expected so convert this return val.toString().toUtf8(); diff --git a/src/plugins/scripting/kexidb/kexidbconnection.cpp b/src/plugins/scripting/kexidb/kexidbconnection.cpp --- a/src/plugins/scripting/kexidb/kexidbconnection.cpp +++ b/src/plugins/scripting/kexidb/kexidbconnection.cpp @@ -129,7 +129,7 @@ bool ok = true; QStringList queries = m_connection->objectNames(KDb::QueryObjectType, &ok); if (! ok) { - KexiScriptingWarning() << "Failed to determinate querynames."; + KexiScriptingWarning() << "Failed to determinate query names."; return QStringList(); } return queries; diff --git a/src/plugins/scripting/kexidb/kexidbcursor.cpp b/src/plugins/scripting/kexidb/kexidbcursor.cpp --- a/src/plugins/scripting/kexidb/kexidbcursor.cpp +++ b/src/plugins/scripting/kexidb/kexidbcursor.cpp @@ -113,13 +113,13 @@ { KDbQuerySchema* query = m_cursor->query(); if (! query) { - qWarning() << "Invalid query, index=" << index << " value=" << value; + qWarning() << "Invalid query, index=" << index << "value=" << value; return false; } KDbQueryColumnInfo* column = query->fieldsExpanded(m_cursor->connection()).at(index); if (! column) { - qWarning() << "Invalid column, index=" << index << " value=" << value; + qWarning() << "Invalid column, index=" << index << "value=" << value; return false; } diff --git a/src/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp b/src/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp --- a/src/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp +++ b/src/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp @@ -141,7 +141,7 @@ a->setSeparator(true); viewActions << a; - KActionMenu *menu = new KActionMenu(koIcon("document-properties"), xi18n("Edit"), this); + KActionMenu *menu = new KActionMenu(koIcon("document-edit"), xi18n("Edit"), this); menu->setObjectName("script_edit_menu"); menu->setToolTip(xi18n("Edit actions")); menu->setWhatsThis(xi18n("Provides Edit menu.")); diff --git a/src/plugins/tables/CMakeLists.txt b/src/plugins/tables/CMakeLists.txt --- a/src/plugins/tables/CMakeLists.txt +++ b/src/plugins/tables/CMakeLists.txt @@ -1,5 +1,5 @@ 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 diff --git a/src/plugins/tables/kexilookupcolumnpage.h b/src/plugins/tables/kexilookupcolumnpage.h --- a/src/plugins/tables/kexilookupcolumnpage.h +++ b/src/plugins/tables/kexilookupcolumnpage.h @@ -1,5 +1,5 @@ /* 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 @@ -19,7 +19,7 @@ #ifndef KEXILOOKUPCOLUMNPAGE_H #define KEXILOOKUPCOLUMNPAGE_H -#include +#include #include #include @@ -35,7 +35,7 @@ @todo not all features of KDbLookupFieldSchema class are displayed on this page yet */ -class KexiLookupColumnPage : public KexiPropertyPaneViewBase +class KexiLookupColumnPage : public QWidget { Q_OBJECT @@ -71,6 +71,8 @@ //! 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; diff --git a/src/plugins/tables/kexilookupcolumnpage.cpp b/src/plugins/tables/kexilookupcolumnpage.cpp --- a/src/plugins/tables/kexilookupcolumnpage.cpp +++ b/src/plugins/tables/kexilookupcolumnpage.cpp @@ -1,5 +1,5 @@ /* 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 @@ -20,7 +20,6 @@ #include "kexilookupcolumnpage.h" #include -#include #include #include #include @@ -89,11 +88,8 @@ 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; @@ -114,7 +110,7 @@ //---------------------------------------------- KexiLookupColumnPage::KexiLookupColumnPage(QWidget *parent) - : KexiPropertyPaneViewBase(parent) + : QWidget(parent) , d(new Private(this)) { setObjectName("KexiLookupColumnPage"); @@ -124,8 +120,10 @@ //-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); @@ -142,37 +140,37 @@ 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))); @@ -209,7 +207,6 @@ 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(); @@ -376,3 +373,13 @@ 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/kexitabledesignercommands.cpp b/src/plugins/tables/kexitabledesignercommands.cpp --- a/src/plugins/tables/kexitabledesignercommands.cpp +++ b/src/plugins/tables/kexitabledesignercommands.cpp @@ -97,7 +97,7 @@ m_oldValue.toString(), m_alterTableAction.newValue().toString())); - qDebug() << debugString(); + //qDebug() << debugString(); } ChangeFieldPropertyCommand::~ChangeFieldPropertyCommand() @@ -251,8 +251,7 @@ m_alterTableAction.propertyName(), m_oldVisibility ? "true" : "false", m_alterTableAction.newValue().toBool() ? "true" : "false")); - - qDebug() << debugString(); + //qDebug() << debugString(); } ChangePropertyVisibilityCommand::~ChangePropertyVisibilityCommand() diff --git a/src/plugins/tables/kexitabledesignerview.cpp b/src/plugins/tables/kexitabledesignerview.cpp --- a/src/plugins/tables/kexitabledesignerview.cpp +++ b/src/plugins/tables/kexitabledesignerview.cpp @@ -106,6 +106,7 @@ , d(new KexiTableDesignerViewPrivate(this)) { setObjectName("KexiTableDesignerView"); + setTextToDisplayForNullSet(xi18nc("No table field selected in the Table Designer", "No field selected")); KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); d->view = dynamic_cast(mainWidget()); @@ -290,8 +291,8 @@ KPropertyListData *listData = new KPropertyListData( KDb::fieldTypeStringsForGroup(fieldTypeGroup), KDb::fieldTypeNamesForGroup(fieldTypeGroup)); // } - qDebug() << "subType strings: " << listData->keysAsStringList().join("|") - << "\nnames: " << listData->namesAsStringList().join("|"); + //qDebug() << "subType strings: " << listData->keysAsStringList().join("|") + // << "\nnames: " << listData->namesAsStringList().join("|"); return listData; } @@ -314,8 +315,7 @@ KexiIconName("lineedit") //"table_field" )); prop->setVisible(false); - set->addProperty(prop = new KProperty("this:useCaptionAsObjectName", - QVariant(true), QString())); //we want "caption" to be displayed in the header, not name + set->addProperty(prop = new KProperty("this:visibleObjectNameProperty", "caption", QString())); //we want "caption" to be displayed in the header, not name prop->setVisible(false); //name @@ -620,8 +620,8 @@ { if (!d->slotBeforeCellChanged_enabled) return; - // qDebug() << d->view->selectedRecord() << " " << item - //<< " " << d->sets->at( d->view->currentRecord() ) << " " << propertySet(); + // qDebug() << d->view->selectedRecord() << item + //<< d->sets->at( d->view->currentRecord() ) << propertySet(); if (colnum == COLUMN_ID_CAPTION) {//'caption' //if 'type' is not filled yet if (data->at(COLUMN_ID_TYPE).isNull()) { @@ -714,7 +714,7 @@ subTypeValue = KDbField::typeString(fieldType); //} KProperty *subTypeProperty = &set["subType"]; - qDebug() << subTypeProperty->value(); + //qDebug() << subTypeProperty->value(); // *** this action contains subactions *** Command *changeDataTypeCommand = new Command( @@ -770,7 +770,7 @@ return; //update field desc. QVariant oldValue((*propertySetForRecord)["description"].value()); - qDebug() << oldValue; + //qDebug() << oldValue; propertySetForRecord->changeProperty("description", *newValue); } } @@ -839,7 +839,7 @@ default:; } - qDebug() << field; + //qDebug() << field; //create a new property set: KPropertySet *newSet = createPropertySet(record, field, true); @@ -862,8 +862,8 @@ void KexiTableDesignerView::slotPropertyChanged(KPropertySet& set, KProperty& property) { const QByteArray pname(property.name()); - qDebug() << pname << " = " << property.value() - << " (oldvalue = " << property.oldValue() << ")"; + //qDebug() << pname << "=" << property.value() + // << "(oldvalue =" << property.oldValue() << ")"; // true if PK should be altered bool changePrimaryKey = false; @@ -949,7 +949,7 @@ if (set["primaryKey"].value().toBool() == true && property.value().toString() != KDbField::typeString(KDbField::BigInteger)) { - qDebug() << "INVALID " << property.value().toString(); + qDebug() << "INVALID" << property.value().toString(); // if (KMessageBox::Yes == KMessageBox::questionYesNo(this, msg, // xi18n("This field has primary key assigned. Setting autonumber field"), // KGuiItem(xi18nc("@action:button", "Create &Primary Key"), KexiIconName("database-key")), KStandardGuiItem::cancel() )) @@ -976,7 +976,7 @@ d->setPropertyValueIfNeeded(set, "subType", property.value(), property.oldValue(), changeFieldTypeCommand); - qDebug() << set["type"].value(); + //qDebug() << set["type"].value(); const KDbField::Type newType = KDbField::typeForString(property.value().toString()); set["type"].setValue(newType); @@ -1183,7 +1183,7 @@ //check for pkey; automatically add a pkey if user wanted if (!d->primaryKeyExists) { if (beSilent) { - qDebug() << "no primay key defined..."; + //qDebug() << "no primay key defined..."; } else { const int questionRes = KMessageBox::questionYesNoCancel(this, xi18nc("@info", @@ -1308,7 +1308,7 @@ actions.clear(); qDebug() << d->history->count() - << " top-level command(s) to process..."; + << "top-level command(s) to process..."; for (int i = 0; i < d->history->count(); ++i) { copyAlterTableActions(d->history->command(i), actions); @@ -1462,7 +1462,7 @@ static_cast(*newTable) = static_cast(*tempData()->table()); res = buildSchema(*newTable); - qDebug() << "BUILD SCHEMA:" << *newTable; + //qDebug() << "BUILD SCHEMA:" << *newTable; { KDbTableSchema *oldTable = tempData()->table(); tempData()->setTable(nullptr); // needed, otherwise setTable() will access dangling @@ -1476,10 +1476,10 @@ KDbAlterTableHandler::ExecutionArguments args; newTable = alterTableHandler->execute(tempData()->table()->name(), &args); res = args.result; - qDebug() << "ALTER TABLE EXECUTE: " - << res.toString(); + //qDebug() << "ALTER TABLE EXECUTE:" + // << res.toString(); if (true != res) { - qDebug() << alterTableHandler->result(); + //qDebug() << alterTableHandler->result(); window()->setStatus(alterTableHandler, ""); } } @@ -1835,7 +1835,7 @@ //find a property by UID const int record = d->sets->findRecordForPropertyValue("uid", fieldUID); if (record < 0) { - qWarning() << "field with uid=" << fieldUID << " not found!"; + qWarning() << "field with uid=" << fieldUID << "not found!"; return; } changeFieldPropertyForRecord(record, propertyName, newValue, listData, addCommand); diff --git a/src/plugins/tables/kexitabledesignerview_p.cpp b/src/plugins/tables/kexitabledesignerview_p.cpp --- a/src/plugins/tables/kexitabledesignerview_p.cpp +++ b/src/plugins/tables/kexitabledesignerview_p.cpp @@ -152,8 +152,8 @@ bool visible; prop = &set["subType"]; - qDebug() << "subType=" << prop->value().toInt() - << " type=" << set["type"].value().toInt(); + //qDebug() << "subType=" << prop->value().toInt() + // << "type=" << set["type"].value().toInt(); //if there is no more than 1 subType name or it's a PK: hide the property visible = diff --git a/src/plugins/tables/kexitablepart.h b/src/plugins/tables/kexitablepart.h --- a/src/plugins/tables/kexitablepart.h +++ b/src/plugins/tables/kexitablepart.h @@ -134,7 +134,7 @@ virtual void initPartActions(); virtual void initInstanceActions(); - virtual void setupCustomPropertyPanelTabs(QTabWidget *tab); + virtual void setupPropertyPane(KexiPropertyPaneWidget *pane); virtual KDbObject* loadSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow); diff --git a/src/plugins/tables/kexitablepart.cpp b/src/plugins/tables/kexitablepart.cpp --- a/src/plugins/tables/kexitablepart.cpp +++ b/src/plugins/tables/kexitablepart.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,6 @@ #include #include -#include KEXI_PLUGIN_FACTORY(KexiTablePart, "kexi_tableplugin.json") @@ -104,7 +104,7 @@ = static_cast(window->data()); if (!temp->table()) { temp->setTable(win->project()->dbConnection()->tableSchema(item->name())); - qDebug() << "schema is " << temp->table(); + //qDebug() << "schema is " << temp->table(); } if (viewMode == Kexi::DesignViewMode) { @@ -250,10 +250,10 @@ return Part::i18nMessage(englishMessage, window); } -void KexiTablePart::setupCustomPropertyPanelTabs(QTabWidget *tab) +void KexiTablePart::setupPropertyPane(KexiPropertyPaneWidget *pane) { if (!d->lookupColumnPage) { - d->lookupColumnPage = new KexiLookupColumnPage(0); + d->lookupColumnPage = new KexiLookupColumnPage; connect(d->lookupColumnPage, SIGNAL(jumpToObjectRequested(QString,QString)), KexiMainWindowIface::global()->thisWidget(), @@ -273,8 +273,7 @@ d->lookupColumnPage->setProject(prj); //! @todo add lookup field icon - tab->addTab(d->lookupColumnPage, KexiIcon("combobox"), QString()); - tab->setTabToolTip(tab->indexOf(d->lookupColumnPage), xi18n("Lookup column")); + pane->addSection(d->lookupColumnPage, xi18n("Lookup column")); } KexiLookupColumnPage* KexiTablePart::lookupColumnPage() const diff --git a/src/tests/altertable/altertable.cpp b/src/tests/altertable/altertable.cpp --- a/src/tests/altertable/altertable.cpp +++ b/src/tests/altertable/altertable.cpp @@ -289,13 +289,15 @@ bool AlterTableTester::showSchema(KexiWindow* window, bool copyToClipboard) { QString schemaDebugString; - if (!getSchemaDump(window, schemaDebugString)) + if (!getSchemaDump(window, schemaDebugString)) { return false; - if (copyToClipboard) + } + if (copyToClipboard) { QApplication::clipboard()->setText(schemaDebugString); - else - qDebug() << QString("Schema for '%1' table:\n").arg(window->partItem()->name()) - + schemaDebugString + "\nendSchema"; + } else { + //qDebug() << QString("Schema for '%1' table:\n").arg(window->partItem()->name()) + //+ schemaDebugString + "\nendSchema"; + } return true; } @@ -350,8 +352,8 @@ 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"); + //qDebug() << QString("Schema check for table '%1': %2").arg(window->partItem()->name()) + // .arg(result ? "OK" : "Failed"); return result; } @@ -372,13 +374,15 @@ bool AlterTableTester::showActions(KexiWindow* window, bool copyToClipboard) { QString actionsDebugString; - if (!getActionsDump(window, actionsDebugString)) + if (!getActionsDump(window, actionsDebugString)) { return false; - if (copyToClipboard) + } + if (copyToClipboard) { QApplication::clipboard()->setText(actionsDebugString); - else - qDebug() << QString("Simplified actions for altering table '%1':\n").arg(window->partItem()->name()) - + actionsDebugString + "\n"; + } else { + //qDebug() << QString("Simplified actions for altering table '%1':\n").arg(window->partItem()->name()) + //+ actionsDebugString + "\n"; + } return true; } @@ -388,8 +392,8 @@ 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"); + //qDebug() << QString("Actions check for table '%1': %2").arg(window->partItem()->name()) + //.arg(result ? "OK" : "Failed"); return result; } @@ -432,12 +436,14 @@ bool AlterTableTester::showTableData(KexiWindow* window, bool copyToClipboard) { QString dataString; - if (!getTableDataDump(window, dataString)) + if (!getTableDataDump(window, dataString)) { return false; - if (copyToClipboard) + } + if (copyToClipboard) { QApplication::clipboard()->setText(dataString); - else - qDebug() << QString("Contents of table '%1':\n").arg(window->partItem()->name()) + dataString + "\n"; + } else { + //qDebug() << QString("Contents of table '%1':\n").arg(window->partItem()->name()) + dataString + "\n"; + } return true; } @@ -447,8 +453,8 @@ 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"); + //qDebug() << QString("Table '%1' contents: %2").arg(window->partItem()->name()) + //.arg(result ? "OK" : "Failed"); return result; } @@ -458,8 +464,8 @@ 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")); + //qDebug() << QString("Closing window for table '%1': %2").arg(name) + //.arg(result == true ? "OK" : (result == false ? "Failed" : "Cancelled")); return result == true; } @@ -471,7 +477,7 @@ while (!m_finishedCopying) qApp->processEvents(300); - qDebug() << "Database copied to temporary: " << dbFilename; + //qDebug() << "Database copied to temporary:" << dbFilename; if (!checkItemsNumber(2)) return false; @@ -505,7 +511,7 @@ //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(); @@ -606,7 +612,7 @@ if (command == "stop") { if (!checkItemsNumber(1)) return false; - qDebug() << QString("Test STOPPED at line %1.").arg(testLineNumber); + //qDebug() << QString("Test STOPPED at line %1.").arg(testLineNumber); break; } else if (command == "closeWindow") { if (!checkItemsNumber(1) || !closeWindow(window)) @@ -618,7 +624,7 @@ if (!checkItemsNumber(1) || !closeWindow(window)) return false; *closeAppRequested = true; - qDebug() << QString("Quitting the application..."); + //qDebug() << QString("Quitting the application..."); break; } else { showError(QString("No such command '%1'").arg(command)); @@ -690,7 +696,7 @@ 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); + //qDebug() << QString("Tests from file '%1': OK").arg(testFilename); result = (closeOnFinish || closeAppRequested) ? 0 : qApp->exec(); quit(result); return result; diff --git a/src/tests/newapi/cursors_test.h b/src/tests/newapi/cursors_test.h --- a/src/tests/newapi/cursors_test.h +++ b/src/tests/newapi/cursors_test.h @@ -36,15 +36,15 @@ } KDbCursor *cursor = conn->executeQuery("select * from persons", cursor_options); - qDebug() << "executeQuery() = " << !!cursor; + qDebug() << "executeQuery() =" << !!cursor; if (!cursor) return 1; qDebug() << "Cursor::moveLast() ---------------------"; - qDebug() << "-- Cursor::moveLast() == " << cursor->moveLast(); + qDebug() << "-- Cursor::moveLast() ==" << cursor->moveLast(); cursor->moveLast(); qDebug() << "Cursor::moveFirst() ---------------------"; - qDebug() << "-- Cursor::moveFirst() == " << cursor->moveFirst(); + qDebug() << "-- Cursor::moveFirst() ==" << cursor->moveFirst(); /* qDebug()<<"Cursor::moveNext() == "<moveNext(); qDebug()<<"Cursor::moveNext() == "<moveNext(); diff --git a/src/tests/newapi/dbcreation_test.h b/src/tests/newapi/dbcreation_test.h --- a/src/tests/newapi/dbcreation_test.h +++ b/src/tests/newapi/dbcreation_test.h @@ -43,10 +43,10 @@ qDebug()<<"executeQuery() = "<moveLast(); + qDebug()<<"-- Cursor::moveLast() ==" << cursor->moveLast(); cursor->moveLast(); qDebug()<<"Cursor::moveFirst() ---------------------"; - qDebug()<<"-- Cursor::moveFirst() == " << cursor->moveFirst(); + qDebug()<<"-- Cursor::moveFirst() ==" << cursor->moveFirst(); */ /* qDebug()<<"Cursor::moveNext() == "<moveNext(); qDebug()<<"Cursor::moveNext() == "<moveNext(); diff --git a/src/tests/newapi/dr_prop_test.h b/src/tests/newapi/dr_prop_test.h --- a/src/tests/newapi/dr_prop_test.h +++ b/src/tests/newapi/dr_prop_test.h @@ -25,10 +25,10 @@ QList names = driver->propertyNames(); qDebug() << QString("%1 properties found:").arg(names.count()); foreach(const QByteArray& propertyName, names) { - qDebug() << " - " << propertyName << ":" - << " caption=\"" << driver->propertyCaption(propertyName) << "\"" - << " type=" << driver->propertyValue(propertyName).typeName() - << " value=\"" << driver->propertyValue(propertyName).toString() << "\""; + qDebug() << "-" << propertyName << ":" + << "caption=\"" << driver->propertyCaption(propertyName) << "\"" + << "type=" << driver->propertyValue(propertyName).typeName() + << "value=\"" << driver->propertyValue(propertyName).toString() << "\""; } // QVariant propertyValue( const QCString& propName ) const; diff --git a/src/tests/newapi/main.cpp b/src/tests/newapi/main.cpp --- a/src/tests/newapi/main.cpp +++ b/src/tests/newapi/main.cpp @@ -74,7 +74,7 @@ #define RETURN(code) \ exitRoutine(); \ - qDebug()<< test_name << " TEST: " << (code==0?"PASSED":"ERROR"); \ + qDebug()<< test_name << "TEST:" << (code==0?"PASSED":"ERROR"); \ return code int main(int argc, char** argv) @@ -187,7 +187,7 @@ manager.debugError(); RETURN(1); } - qDebug() << "MIME type for '" << drv_info.name << "': " << drv_info.fileDBMimeType; + qDebug() << "MIME type for '" << drv_info.name << "':" << drv_info.fileDBMimeType; //open connection if (args->count() >= 2) @@ -255,7 +255,7 @@ } else if (test_name == "dr_prop") r = drPropTest(); else { - qWarning() << "No such test: " << test_name; + qWarning() << "No such test:" << test_name; // usage(); RETURN(1); } @@ -274,8 +274,8 @@ // if (conn && !conn->disconnect()) // r = 1; -// qDebug() << "!!! KDbTransaction::globalcount == " << KDbTransaction::globalCount(); -// qDebug() << "!!! KDbTransactionData::globalcount == " << KDbTransactionData::globalCount(); +// qDebug() << "!!! KDbTransaction::globalcount ==" << KDbTransaction::globalCount(); +// qDebug() << "!!! KDbTransactionData::globalcount ==" << KDbTransactionData::globalCount(); delete app; diff --git a/src/tests/parser/main.cpp b/src/tests/parser/main.cpp --- a/src/tests/parser/main.cpp +++ b/src/tests/parser/main.cpp @@ -50,15 +50,15 @@ KDbConnection *conn = driver->createConnection(conn_data); if (!conn || driver->result().isError()) { - qDebug() << "error: " << driver->result(); + qDebug() << "error:" << driver->result(); return 1; } if (!conn->connect()) { - qDebug() << "error: " << conn->errorMsg(); + qDebug() << "error:" << conn->errorMsg(); return 1; } if (!conn->useDatabase(db_name)) { - qDebug() << "error: " << conn->errorMsg(); + qDebug() << "error:" << conn->errorMsg(); return 1; } @@ -77,13 +77,13 @@ break; case KDbParser::OP_CreateTable: { if (parser->table()) { - qDebug() << "Schema of table: " << parser->table()->name(); + qDebug() << "Schema of table:" << parser->table()->name(); qDebug() << *parser->table(); } break; } case KDbParser::OP_Select: { - qDebug() << "Select statement: "; + qDebug() << "Select statement:"; KDbQuerySchema *q = parser->query(); if (q) { qDebug() << *q; diff --git a/src/tests/startup/main.cpp b/src/tests/startup/main.cpp --- a/src/tests/startup/main.cpp +++ b/src/tests/startup/main.cpp @@ -77,36 +77,36 @@ if (e == QDialog::Accepted) { int r = startup.result(); if (r == KexiStartupDialog::TemplateResult) { - qDebug() << "Template key == " << startup.selectedTemplateKey(); + qDebug() << "Template key ==" << startup.selectedTemplateKey(); if (startup.selectedTemplateKey() == "blank") { #if 0 KexiConnSelectorDialog sel(connset, 0, "sel"); e = sel.exec(); qDebug() << (e == QDialog::Accepted ? "Accepted" : "Rejected"); if (e == QDialog::Accepted) { - qDebug() << "Selected conn. type: " << (sel.selectedConnectionType() == KexiConnSelectorWidget::FileBased ? "File based" : "Server based"); + qDebug() << "Selected conn. type:" << (sel.selectedConnectionType() == KexiConnSelectorWidget::FileBased ? "File based" : "Server based"); if (sel.selectedConnectionType() == KexiConnSelectorWidget::ServerBased) { - qDebug() << "SERVER: " << sel.selectedConnectionData()->toUserVisibleString(); + qDebug() << "SERVER:" << sel.selectedConnectionData()->toUserVisibleString(); } } #endif } } else if (r == KexiStartupDialog::OpenExistingResult) { qDebug() << "Existing project --------"; QString selFile = startup.selectedExistingFile(); if (!selFile.isEmpty()) - qDebug() << "Project File: " << selFile; + qDebug() << "Project File:" << selFile; else if (startup.selectedExistingConnection()) { - qDebug() << "Existing connection: " << startup.selectedExistingConnection()->toUserVisibleString(); - //ok, now we are trying to show daabases for this connection to this user + qDebug() << "Existing connection:" << startup.selectedExistingConnection()->toUserVisibleString(); + //ok, now we are trying to show databases for this connection to this user //! @todo } } else if (r == KexiStartupDialog::OpenRecentResult) { qDebug() << "Recent project --------"; const KexiProjectData *data = startup.selectedProjectData(); if (data) { qDebug() << "Selected project: database=" << data->databaseName() - << " connection=" << data->connectionData()->toUserVisibleString(); + << "connection=" << data->connectionData()->toUserVisibleString(); } } } diff --git a/src/widget/CMakeLists.txt b/src/widget/CMakeLists.txt --- a/src/widget/CMakeLists.txt +++ b/src/widget/CMakeLists.txt @@ -9,8 +9,11 @@ add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44023) -include_directories(${CMAKE_SOURCE_DIR}/src/widget/tableview ${CMAKE_SOURCE_DIR}/src/core) - +include_directories( + ${CMAKE_SOURCE_DIR}/src/widget/tableview + ${CMAKE_SOURCE_DIR}/src/core + ${CMAKE_SOURCE_DIR}/src/kexiutils/style +) ########### next target ############### @@ -26,18 +29,18 @@ 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 @@ -49,6 +52,7 @@ KexiFileRequester.cpp KexiStartupFileHandler.cpp KexiListView.cpp + KexiWidgetWidthAnimator.cpp ) if(SHOULD_BUILD_KEXI_DESKTOP_APP) @@ -98,6 +102,7 @@ KPropertyWidgets KF5::TextEditor + KF5::ConfigWidgets ) if(KEXI_USE_KFILEWIDGET) diff --git a/src/widget/KexiDataSourceComboBox.cpp b/src/widget/KexiDataSourceComboBox.cpp --- a/src/widget/KexiDataSourceComboBox.cpp +++ b/src/widget/KexiDataSourceComboBox.cpp @@ -162,10 +162,12 @@ void KexiDataSourceComboBox::setDataSource(const QString& pluginId, const QString& name) { if (name.isEmpty()) { - clearEditText(); - setCurrentIndex(0); - d->prevIndex = -1; - emit dataSourceChanged(); + if (currentIndex() != 0) { + clearEditText(); + setCurrentIndex(0); + d->prevIndex = -1; + emit dataSourceChanged(); + } return; } @@ -177,12 +179,16 @@ if (pluginId.isEmpty()) i = findItem("org.kexi-project.query", name); if (i == -1) { - setCurrentIndex(0); + if (currentIndex() != 0) { + setCurrentIndex(0); + } return; } } - setCurrentIndex(i); - slotActivated(i); + if (currentIndex() != i) { + setCurrentIndex(i); + slotActivated(i); + } } void KexiDataSourceComboBox::slotNewItemStored(KexiPart::Item* item) diff --git a/src/widget/KexiFileWidget.cpp b/src/widget/KexiFileWidget.cpp --- a/src/widget/KexiFileWidget.cpp +++ b/src/widget/KexiFileWidget.cpp @@ -90,8 +90,8 @@ QString dirStr = fi.isDir() ? fi.absoluteFilePath() : fi.dir().absolutePath(); dir = QUrl::fromLocalFile(dirStr); } - qDebug() << dir; - qDebug() << highlightedFile(); + //qDebug() << dir; + //qDebug() << highlightedFile(); if (!dir.isEmpty()) KRecentDirs::add(d->recentDirClass, dir.path()); } @@ -101,14 +101,15 @@ void KexiFileWidget::slotFileHighlighted(const QUrl& url) { - qDebug() << url; + //qDebug() << url; d->selectedUrl = url; emit fileSelected(selectedFile()); } void KexiFileWidget::slotFileSelected(const QUrl& url) { - qDebug() << url; + Q_UNUSED(url) + //qDebug() << url; emit fileSelected(selectedFile()); } @@ -148,29 +149,29 @@ #ifdef Q_OS_WIN // QString path = selectedFile(); //js @todo -// qDebug() << "selectedFile() == " << path << " '" << url().fileName() << "' " << m_lineEdit->text(); +// qDebug() << "selectedFile() ==" << path << "'" << url().fileName() << "'" << m_lineEdit->text(); QString path = dir()->absolutePath(); if (!path.endsWith('/') && !path.endsWith("\\")) path.append("/"); path += m_lineEdit->text(); // QString path = QFileInfo(selectedFile()).dirPath(true) + "/" + m_lineEdit->text(); #else // QString path = locationEdit->currentText().trimmed(); //url.path().trimmed(); that does not work, if the full path is not in the location edit !!!!! QString path( KFileWidget::selectedFile() ); - qDebug() << "prev selectedFile() == " << path; - qDebug() << "locationEdit == " << locationEdit()->currentText().trimmed(); + qDebug() << "prev selectedFile() ==" << path; + qDebug() << "locationEdit ==" << locationEdit()->currentText().trimmed(); //make sure user-entered path is acceped: //! @todo KEXI3 setSelection( locationEdit()->currentText().trimmed() ); // path = KFileWidget::selectedFile(); path = locationEdit()->currentText().trimmed(); - qDebug() << "selectedFile() == " << path; + qDebug() << "selectedFile() ==" << path; #endif if (!currentFilter().isEmpty()) { if (d->mode & SavingFileBasedDB) { const QStringList filters( currentFilter().split(' ') ); - qDebug()<< " filter == " << filters; + qDebug()<< "filter ==" << filters; QString ext( QFileInfo(path).suffix() ); bool hasExtension = false; foreach (const QString& filter, filters) { @@ -185,11 +186,11 @@ if (defaultExtension.isEmpty()) defaultExtension = filters.first().trimmed().mid(2); //first one path += (QString(".")+defaultExtension); - qDebug() << "KexiFileWidget::checkURL(): append extension, " << path; + qDebug() << "KexiFileWidget::checkURL(): append extension," << path; } } } - qDebug() << "KexiFileWidget::currentFileName() == " << path; + qDebug() << "KexiFileWidget::currentFileName() ==" << path; return path; } */ @@ -220,9 +221,9 @@ if (enteredFileName.isEmpty()) { return; } - qDebug() << enteredFileName; - qDebug() << locationEdit()->urls(); - qDebug() << currentDir(); + //qDebug() << enteredFileName; + //qDebug() << locationEdit()->urls(); + //qDebug() << currentDir(); setSelectedFile(currentDir()); // FIXME: find first... @@ -240,17 +241,16 @@ void KexiFileWidget::accept() { - qDebug(); - + //qDebug(); KFileWidget::accept(); // qDebug() << selectedFile(); // locationEdit->setFocus(); // QKeyEvent ev(QEvent::KeyPress, Qt::Key_Enter, '\n', 0); // QApplication::sendEvent(locationEdit, &ev); // QApplication::postEvent(locationEdit, &ev); -// qDebug() << "KexiFileWidget::accept() m_lastUrl == " << m_lastUrl.path(); +// qDebug() << "KexiFileWidget::accept() m_lastUrl ==" << m_lastUrl.path(); // if (m_lastUrl.path()==currentURL().path()) {//(js) to prevent more multiple kjob signals (I do not know why this is) /* if (d->lastFileName==selectedFile()) {//(js) to prevent more multiple kjob signals (I do not know why this is) @@ -261,7 +261,7 @@ return; #endif } - qDebug() << "KexiFileWidget::accept(): path = " << selectedFile(); + qDebug() << "KexiFileWidget::accept(): path =" << selectedFile(); if ( checkSelectedFile() ) { emit accepted(); } @@ -274,7 +274,7 @@ void KexiFileWidget::reject() { - qDebug(); + //qDebug(); emit rejected(); } diff --git a/src/widget/KexiListView.h b/src/widget/KexiListView.h --- a/src/widget/KexiListView.h +++ b/src/widget/KexiListView.h @@ -28,6 +28,25 @@ #include "kexiextwidgets_export.h" +//! Default delegate for KexiListView +class KEXIEXTWIDGETS_EXPORT KexiListViewDelegate : public QAbstractItemDelegate +{ + Q_OBJECT + +public: + explicit KexiListViewDelegate(QObject *parent = 0); + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const Q_DECL_OVERRIDE; + QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const Q_DECL_OVERRIDE; + +private: + void drawFocus(QPainter *, const QStyleOptionViewItem &, const QRect &) const; + void paint(QPainter *painter, const QStyle &style, QStyleOptionViewItem *option, + const QModelIndex &index) const; +}; + class KEXIEXTWIDGETS_EXPORT KexiListView : public QListView { Q_OBJECT @@ -39,6 +58,18 @@ void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE; +protected: + //! Used in KexiListView(UseDelegate, QWidget*) + enum UseDelegate + { + UseDefaultDelegate, + DontUseDelegate + }; + + //! Alternative constructor, the same as the default but if @a useDelegate is DontUseDelegate, + //! delegate is not set. This allows to replace delegate. + KexiListView(UseDelegate useDelegate = UseDefaultDelegate, QWidget *parent = 0); + private Q_SLOTS: void updateWidth(); }; diff --git a/src/widget/KexiListView.cpp b/src/widget/KexiListView.cpp --- a/src/widget/KexiListView.cpp +++ b/src/widget/KexiListView.cpp @@ -25,19 +25,27 @@ #include "KexiListView_p.h" #include +#include #include #include const int KEXILISTVIEW_VERTICAL_MARGIN = 10; const int KEXILISTVIEW_HORIZONTAL_MARGIN = 12; KexiListView::KexiListView(QWidget *parent) - : QListView(parent) + : KexiListView(UseDefaultDelegate, parent) +{ +} + +KexiListView::KexiListView(UseDelegate useDelegate, QWidget *parent) + : QListView(parent) { setViewMode(QListView::ListMode); setMovement(QListView::Static); setVerticalScrollMode(QListView::ScrollPerPixel); - setItemDelegate(new KexiListViewDelegate(this)); + if (useDelegate == UseDefaultDelegate) { + setItemDelegate(new KexiListViewDelegate(this)); + } } KexiListView::~KexiListView() @@ -115,50 +123,62 @@ QStyleOptionViewItem opt(option); opt.showDecorationSelected = true; - QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + const QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); + paint(painter, *style, &opt, index); +} - int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize); +void KexiListViewDelegate::paint(QPainter *painter, const QStyle &style, + QStyleOptionViewItem *option, + const QModelIndex &index) const +{ + int iconSize = style.pixelMetric(QStyle::PM_IconViewIconSize); const QString text = index.model()->data(index, Qt::DisplayRole).toString(); const QIcon icon = index.model()->data(index, Qt::DecorationRole).value(); - const QPixmap pixmap = icon.pixmap(iconSize, iconSize, - (option.state & QStyle::State_Selected) ? QIcon::Selected : QIcon::Normal); - + QIcon::Mode iconMode; + if (option->state & QStyle::State_Enabled && option->state & QStyle::State_Selected) { + iconMode = QIcon::Selected; + } else { + iconMode = (option->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled; + } + const QPixmap pixmap = icon.pixmap(iconSize, iconSize, iconMode); QFontMetrics fm = painter->fontMetrics(); int wp = pixmap.width() / pixmap.devicePixelRatio(); int hp = pixmap.height() / pixmap.devicePixelRatio(); - QTextLayout iconTextLayout(text, option.font); + QTextLayout iconTextLayout(text, option->font); QTextOption textOption(Qt::AlignHCenter); iconTextLayout.setTextOption(textOption); int maxWidth = qMax(3 * wp, 8 * fm.height()); layoutText(&iconTextLayout, maxWidth); QPen pen = painter->pen(); - QPalette::ColorGroup cg = option.state & QStyle::State_Enabled - ? QPalette::Normal : QPalette::Disabled; - if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) { - cg = QPalette::Inactive; + QPalette::ColorGroup cg; + if (option->state & QStyle::State_Enabled) { + cg = (option->state & QStyle::State_Active) ? QPalette::Normal : QPalette::Inactive; + } else { + cg = QPalette::Disabled; + option->state &= ~QStyle::State_MouseOver; } + //qDebug() << hex << int(option->state) << text << int(iconMode) << cg; - style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); - if (option.state & QStyle::State_Selected) { - painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); + style.drawPrimitive(QStyle::PE_PanelItemViewItem, option, painter, option->widget); + if (option->state & QStyle::State_Selected) { + painter->setPen(option->palette.color(cg, QPalette::HighlightedText)); } else { - painter->setPen(option.palette.color(cg, QPalette::Text)); + painter->setPen(option->palette.color(cg, QPalette::Text)); } - painter->drawPixmap(option.rect.x() + (option.rect.width() / 2) - - (wp / 2), option.rect.y() + KEXILISTVIEW_VERTICAL_MARGIN, + painter->drawPixmap(option->rect.x() + (option->rect.width() / 2) + - (wp / 2), option->rect.y() + KEXILISTVIEW_VERTICAL_MARGIN, pixmap); if (!text.isEmpty()) { iconTextLayout.draw(painter, - QPoint(option.rect.x() + (option.rect.width() / 2) - - (maxWidth / 2), option.rect.y() + hp + KEXILISTVIEW_VERTICAL_MARGIN + 2)); + QPoint(option->rect.x() + (option->rect.width() / 2) + - (maxWidth / 2), option->rect.y() + hp + KEXILISTVIEW_VERTICAL_MARGIN + 2)); } painter->setPen(pen); - - drawFocus(painter, option, option.rect); + drawFocus(painter, *option, option->rect); } QSize KexiListViewDelegate::sizeHint(const QStyleOptionViewItem &option, @@ -238,7 +258,7 @@ QItemSelectionModel::SelectionFlags command) { // Don't allow the current selection to be cleared - if (!index.isValid() && (command & QItemSelectionModel::Clear)) { + if (!index.isValid() && (command & Clear || command & Deselect)) { return; } QItemSelectionModel::select(index, command); diff --git a/src/widget/KexiListView_p.h b/src/widget/KexiListView_p.h --- a/src/widget/KexiListView_p.h +++ b/src/widget/KexiListView_p.h @@ -27,22 +27,6 @@ #include #include -class KexiListViewDelegate : public QAbstractItemDelegate -{ - Q_OBJECT - -public: - explicit KexiListViewDelegate(QObject *parent = 0); - - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; - QSize sizeHint(const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; - -private: - void drawFocus(QPainter *, const QStyleOptionViewItem &, const QRect &) const; -}; - class KexiListViewSelectionModel : public QItemSelectionModel { Q_OBJECT diff --git a/src/widget/KexiObjectInfoLabel.h b/src/widget/KexiObjectInfoLabel.h deleted file mode 100644 --- a/src/widget/KexiObjectInfoLabel.h +++ /dev/null @@ -1,66 +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. -*/ - -#ifndef KEXIOBJECTINFOLABEL_H -#define KEXIOBJECTINFOLABEL_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" - - The ObjectClassIcon is optional. If "ClassName" is empty, the information - is displayed as: - [ObjectClassIcon] ObjectName - - Example uses: - - [button_icon] Button "quit" - - [label_icon] Label "welcome" -*/ -class KEXIEXTWIDGETS_EXPORT KexiObjectInfoLabel : public QWidget -{ - Q_OBJECT -public: - explicit KexiObjectInfoLabel(QWidget* parent); - virtual ~KexiObjectInfoLabel(); - - void setObjectClassIconName(const QString &name); - - QString objectClassIconName() const; - - void setObjectClassName(const QString& name); - - QString objectClassName() const; - - void setObjectName(const QString& name); - - QString objectName() const; - - void setBuddy(QWidget * buddy); -protected: - void updateName(); - - class Private; - Private * const d; -}; - -#endif diff --git a/src/widget/KexiProjectSelectorWidget.cpp b/src/widget/KexiProjectSelectorWidget.cpp --- a/src/widget/KexiProjectSelectorWidget.cpp +++ b/src/widget/KexiProjectSelectorWidget.cpp @@ -212,7 +212,7 @@ return; //! @todo what with project set's ownership? if (d->prj_set->result().isError()) { - qDebug() << "d->prj_set->error()" << d->prj_set->result(); + //qDebug() << "d->prj_set->error()" << d->prj_set->result(); return; } KDbDriverManager manager; diff --git a/src/widget/KexiStartupFileHandler.cpp b/src/widget/KexiStartupFileHandler.cpp --- a/src/widget/KexiStartupFileHandler.cpp +++ b/src/widget/KexiStartupFileHandler.cpp @@ -138,18 +138,18 @@ void KexiStartupFileHandler::saveRecentDir() { if (!d->recentDirClass.isEmpty()) { - qDebug() << d->recentDirClass; + //qDebug() << d->recentDirClass; QUrl dirUrl; if (d->requester) dirUrl = d->requester->url(); //removed in KEXI3 else if (d->dialog) //removed in KEXI3 dirUrl = d->dialog->selectedUrl(); - qDebug() << dirUrl; + //qDebug() << dirUrl; if (dirUrl.isValid() && dirUrl.isLocalFile()) { dirUrl = dirUrl.adjusted(QUrl::RemoveFilename); dirUrl.setPath(dirUrl.path() + QString()); - qDebug() << "Added" << dirUrl.path() << "to recent dirs class" << d->recentDirClass; + //qDebug() << "Added" << dirUrl.path() << "to recent dirs class" << d->recentDirClass; KexiUtils::addRecentDir(d->recentDirClass, dirUrl.path()); } } @@ -300,29 +300,29 @@ #ifdef Q_OS_WIN // QString path = selectedFile(); //js @todo -// qDebug() << "selectedFile() == " << path << " '" << url().fileName() << "' " << m_lineEdit->text(); +// qDebug() << "selectedFile() ==" << path << "'" << url().fileName() << "'" << m_lineEdit->text(); QString path = dir()->absolutePath(); if (!path.endsWith('/') && !path.endsWith("\\")) path.append("/"); path += m_lineEdit->text(); // QString path = QFileInfo(selectedFile()).dirPath(true) + "/" + m_lineEdit->text(); #else // QString path = locationEdit->currentText().trimmed(); //url.path().trimmed(); that does not work, if the full path is not in the location edit !!!!! QString path( KFileWidget::selectedFile() ); - qDebug() << "prev selectedFile() == " << path; - qDebug() << "locationEdit == " << locationEdit()->currentText().trimmed(); + qDebug() << "prev selectedFile() ==" << path; + qDebug() << "locationEdit ==" << locationEdit()->currentText().trimmed(); //make sure user-entered path is acceped: //! @todo KEXI3 setSelection( locationEdit()->currentText().trimmed() ); // path = KFileWidget::selectedFile(); path = locationEdit()->currentText().trimmed(); - qDebug() << "selectedFile() == " << path; + qDebug() << "selectedFile() ==" << path; #endif if (!currentFilter().isEmpty()) { if (d->mode & SavingFileBasedDB) { const QStringList filters( currentFilter().split(' ') ); - qDebug()<< " filter == " << filters; + qDebug()<< "filter ==" << filters; QString ext( QFileInfo(path).suffix() ); bool hasExtension = false; foreach (const QString& filter, filters) { @@ -337,25 +337,25 @@ if (defaultExtension.isEmpty()) defaultExtension = filters.first().trimmed().mid(2); //first one path += (QString(".")+defaultExtension); - qDebug() << "KexiStartupFileDialog::checkURL(): append extension, " << path; + qDebug() << "KexiStartupFileDialog::checkURL(): append extension," << path; } } } - qDebug() << "KexiStartupFileDialog::currentFileName() == " << path; + qDebug() << "KexiStartupFileDialog::currentFileName() ==" << path; return path; } */ bool KexiStartupFileHandler::checkSelectedUrl() { - //qDebug() << "d->highlightedUrl: " << d->highlightedUrl; + //qDebug() << "d->highlightedUrl:" << d->highlightedUrl; QUrl url; if (d->requester) url = d->requester->url(); //removed in KEXI3 else //removed in KEXI3 url = d->dialog->selectedUrl(); - qDebug() << url; + //qDebug() << url; #if 0 if (/*d->highlightedUrl.isEmpty() &&*/ !locationEdit()->lineEdit()->text().isEmpty()) { qDebug() << locationEdit()->lineEdit()->text(); @@ -370,7 +370,7 @@ d->highlightedUrl.addPath(firstUrl); } #endif - //qDebug() << "d->highlightedUrl: " << d->highlightedUrl; + //qDebug() << "d->highlightedUrl:" << d->highlightedUrl; if (!url.isValid() || QFileInfo(url.path()).isDir()) { KMessageBox::error(d->requester->parentWidget(), xi18n("Enter a filename.")); return false; @@ -403,15 +403,15 @@ defaultExtension = filters.first().trimmed().mid(2); //first one } path += (QLatin1String(".") + defaultExtension); - qDebug() << "appended extension, result:" << path; + //qDebug() << "appended extension, result:" << path; url = QUrl(path); d->setUrl(url); } } } -// qDebug() << "KexiStartupFileDialog::checkURL() path: " << d->highlightedUrl; -// qDebug() << "KexiStartupFileDialog::checkURL() fname: " << url.fileName(); +// qDebug() << "KexiStartupFileDialog::checkURL() path:" << d->highlightedUrl; +// qDebug() << "KexiStartupFileDialog::checkURL() fname:" << url.fileName(); //! @todo if ( url.isLocalFile() ) { QFileInfo fi(url.toLocalFile()); if (d->mode & KFile::ExistingOnly) { @@ -457,7 +457,7 @@ if (!fn.isEmpty() && !fn.endsWith(".kexi")) fn += ".kexi"; url = url.adjusted(QUrl::RemoveFilename); - qDebug() << url.toLocalFile(); + //qDebug() << url.toLocalFile(); url.setPath(url.toLocalFile() + fn); d->requester->setUrl(url); } diff --git a/src/widget/KexiListView.h b/src/widget/KexiWidgetWidthAnimator.h copy from src/widget/KexiListView.h copy to src/widget/KexiWidgetWidthAnimator.h --- a/src/widget/KexiListView.h +++ b/src/widget/KexiWidgetWidthAnimator.h @@ -1,10 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2016 Jarosław Staniek - Forked from kwidgetsaddons/src/kpageview_p.h: - Copyright (C) 2006 Tobias Koenig (tokoe@kde.org) - Copyright (C) 2007 Rafael Fernández López (ereslibre@kde.org) - 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 @@ -21,26 +17,38 @@ * Boston, MA 02110-1301, USA. */ -#ifndef KEXILISTVIEW_H -#define KEXILISTVIEW_H - -#include +#ifndef KEXIWIDGETWIDTHANIMATOR_H +#define KEXIWIDGETWIDTHANIMATOR_H #include "kexiextwidgets_export.h" +#include -class KEXIEXTWIDGETS_EXPORT KexiListView : public QListView +//! A tool that animates showing and hiding a given widget by changing its width. +class KEXIEXTWIDGETS_EXPORT KexiWidgetWidthAnimator : public QObject { Q_OBJECT - + Q_PROPERTY(int width READ width WRITE setWidth) public: - explicit KexiListView(QWidget *parent = 0); - - virtual ~KexiListView(); - - void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE; - -private Q_SLOTS: - void updateWidth(); + //! Sets up width animator object for @a targetWidget widget. + //! It is expected that the widget is a child of a QSplitter. + explicit KexiWidgetWidthAnimator(QWidget *targetWidget); + ~KexiWidgetWidthAnimator(); + void setVisible(bool set); + +Q_SIGNALS: + void animationFinished(bool visible); + +protected: + int width() const; + void setWidth(int width); + bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; + +protected Q_SLOTS: + void slotWidthAnimationFinished(); + +private: + class Private; + Private* const d; }; #endif diff --git a/src/widget/KexiWidgetWidthAnimator.cpp b/src/widget/KexiWidgetWidthAnimator.cpp new file mode 100644 --- /dev/null +++ b/src/widget/KexiWidgetWidthAnimator.cpp @@ -0,0 +1,214 @@ +/* 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 "KexiWidgetWidthAnimator.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +const int PROJECT_NAVIGATOR_INDEX = 0; +const int MAIN_AREA_INDEX = 1; +const int PROPERTY_EDITOR_INDEX = 2; + +class KexiWidgetWidthAnimator::Private +{ +public: + explicit Private(KexiWidgetWidthAnimator *qq) + : q(qq) + , widthAnimation(0) + , originalWidth(0) + , frozen(false) + { + } + + void setSubWidgetsVisible(bool set) + { + QWidget *targetWidget = qobject_cast(q->parent()); + QLayout *lyr = targetWidget->layout(); + if (!lyr) { + return; + } + for (int i = 0; i < lyr->count(); ++i) { + QWidget *subWidget = lyr->itemAt(i)->widget(); + if (subWidget) { + subWidget->setVisible(set); + } + } + } + + void setSubWidgetsScrollbarsVisible(bool set) + { + QWidget *targetWidget = qobject_cast(q->parent()); + QLayout *lyr = targetWidget->layout(); + if (!lyr) { + return; + } + for (int i = 0; i < lyr->count(); ++i) { + QAbstractScrollArea* area = qobject_cast(lyr->itemAt(i)->widget()); + if (area) { + //! @todo remember and restore these settings instead of hardcoding! + area->setHorizontalScrollBarPolicy(set ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); + area->setVerticalScrollBarPolicy(set ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff); + } + } + } + + KexiWidgetWidthAnimator * const q; + QPropertyAnimation *widthAnimation; + int originalWidth; + bool frozen; + QPixmap snapshot; +}; + +KexiWidgetWidthAnimator::KexiWidgetWidthAnimator(QWidget *targetWidget) + : QObject(targetWidget), d(new Private(this)) +{ + targetWidget->installEventFilter(this); +} + +KexiWidgetWidthAnimator::~KexiWidgetWidthAnimator() +{ + delete d; +} + +void KexiWidgetWidthAnimator::setVisible(bool set) +{ + const bool stoppedBeforeFinishing = d->widthAnimation && d->widthAnimation->state() == QAbstractAnimation::Running; + QWidget *targetWidget = qobject_cast(parent()); + if (set == targetWidget->isVisible()) { + return; + } + if (!stoppedBeforeFinishing && !set) { + d->originalWidth = width(); + } + if (!d->widthAnimation) { + d->widthAnimation = new QPropertyAnimation(this, "width"); + const int duration = (KexiUtils::graphicEffectsLevel() & KexiUtils::SimpleAnimationEffects) ? 300 : 0; + d->widthAnimation->setDuration(duration); + d->widthAnimation->setEasingCurve(QEasingCurve::InOutQuad); + connect(d->widthAnimation, &QPropertyAnimation::finished, + this, &KexiWidgetWidthAnimator::slotWidthAnimationFinished); + } + if (stoppedBeforeFinishing) { + d->widthAnimation->pause(); + const QVariant end = d->widthAnimation->endValue(); + d->widthAnimation->setEndValue(d->widthAnimation->startValue()); + d->widthAnimation->setStartValue(end); + d->widthAnimation->setCurrentTime( + d->widthAnimation->duration() - d->widthAnimation->currentTime()); + d->widthAnimation->resume(); + } else { + d->widthAnimation->setStartValue(set ? 0 : d->originalWidth); + d->widthAnimation->setEndValue(set ? d->originalWidth : 0); + //qDebug() << "targetWidget->isVisible():" << set << targetWidget->isVisible() << d->originalWidth << width(); + const int w = d->originalWidth; + if (set) { + targetWidget->setVisible(true); + d->originalWidth = w; // restore because setVisible() causes resize event and changes d->originalWidth + } + if (d->widthAnimation->duration() > 0) { + d->setSubWidgetsVisible(true); + d->frozen = false; + const QSize currentSize = targetWidget->size(); + //qDebug() << "currentSize:" << currentSize << d->originalWidth; + targetWidget->resize(d->originalWidth, targetWidget->height()); + d->setSubWidgetsScrollbarsVisible(false); + targetWidget->updateGeometry(); + d->snapshot = targetWidget->grab(); + targetWidget->resize(currentSize); + d->originalWidth = w; // restore because targetWidget->resize() causes resize event and changes d->originalWidth + d->setSubWidgetsScrollbarsVisible(true); + d->setSubWidgetsVisible(false); + d->frozen = true; + } + d->widthAnimation->start(); + } +} + +int KexiWidgetWidthAnimator::width() const +{ + return qobject_cast(parent())->width(); +} + +void KexiWidgetWidthAnimator::setWidth(int width) +{ + QWidget *targetWidget = qobject_cast(parent()); + QSplitter* splitter = qobject_cast(targetWidget->parentWidget()); + const int index = splitter->indexOf(targetWidget); + if (index < 0) { + return; + } + QList sizes(splitter->sizes()); + //qDebug() << "setWidth-" << sizes; + int oldWidth = sizes[index]; + if (sizes.count() >= (MAIN_AREA_INDEX+1)) { // make total size unchanged + sizes[MAIN_AREA_INDEX] += (oldWidth - width); + } + sizes[index] = width; + targetWidget->resize(width, targetWidget->height()); + splitter->setSizes(sizes); + //qDebug() << "setWidth" << index << width << sizes << splitter->sizes(); +} + +void KexiWidgetWidthAnimator::slotWidthAnimationFinished() +{ + QWidget *targetWidget = qobject_cast(parent()); + if (width() == 0) { + targetWidget->setVisible(false); + } + d->frozen = false; + d->snapshot = QPixmap(); // no longer needed + d->setSubWidgetsVisible(true); + emit animationFinished(targetWidget->isVisible()); +} + +bool KexiWidgetWidthAnimator::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == parent()) { + switch (event->type()) { + case QEvent::Paint: + if (d->frozen) { + //qDebug() << "d->snapshot.size():" << d->snapshot.size(); + QPaintEvent *paintEvent = static_cast(event); + QWidget *targetWidget = qobject_cast(parent()); + QPainter p(targetWidget); + p.drawPixmap(paintEvent->rect(), d->snapshot, + QRect(d->originalWidth - targetWidget->width(), 0, + targetWidget->width(), targetWidget->height())); + } + break; + case QEvent::Resize: + if (!d->widthAnimation || d->widthAnimation->state() != QAbstractAnimation::Running) { + QResizeEvent *resizeEvent = static_cast(event); + d->originalWidth = resizeEvent->size().width(); + //qDebug() << "new size:" << resizeEvent->size(); + } + break; + default:; + } + } + return QObject::eventFilter(obj, event); +} diff --git a/src/widget/dataviewcommon/kexidataawareobjectiface.h b/src/widget/dataviewcommon/kexidataawareobjectiface.h --- a/src/widget/dataviewcommon/kexidataawareobjectiface.h +++ b/src/widget/dataviewcommon/kexidataawareobjectiface.h @@ -1005,7 +1005,7 @@ /* qDebug() << "record:" << record; int i=1; for (KexiTableItem::Iterator it = item->begin();it!=item->end();++it,i++) - qDebug() << i<<": " << (*it).toString();*/ + qDebug() << i<<":" << (*it).toString();*/ } return data; } diff --git a/src/widget/dataviewcommon/kexidataawareobjectiface.cpp b/src/widget/dataviewcommon/kexidataawareobjectiface.cpp --- a/src/widget/dataviewcommon/kexidataawareobjectiface.cpp +++ b/src/widget/dataviewcommon/kexidataawareobjectiface.cpp @@ -107,7 +107,7 @@ { const bool theSameData = m_data && m_data == data; if (m_owner && m_data && m_data != data/*don't destroy if it's the same*/) { - qDebug() << "destroying old data (owned)"; + //qDebug() << "destroying old data (owned)"; delete m_data; //destroy old data m_data = 0; m_itemIterator = KDbTableViewDataIterator(); @@ -499,7 +499,7 @@ newRecord = qMax(0, record); newRecord = qMin(recordCount() - 1 + (isInsertingEnabled() ? 1 : 0), newRecord); -// qDebug() << "setCursorPosition(): d->curRow=" << d->curRow << " oldRow=" << oldRow << " d->curCol=" << d->curCol << " oldCol=" << oldCol; +// qDebug() << "setCursorPosition(): d->curRow=" << d->curRow << "oldRow=" << oldRow << "d->curCol=" << d->curCol << "oldCol=" << oldCol; const bool forceSet = flags & ForceSetCursorPosition; if (forceSet || m_curRecord != newRecord || m_curColumn != newCol) { #ifdef setCursorPosition_DEBUG @@ -694,16 +694,16 @@ //qDebug() << "-- NOTHING TO ACCEPT!!!"; } else {//not empty edit buffer or new row to insert: if (m_newRecordEditing) { - qDebug() << "-- INSERTING:" << *m_data->recordEditBuffer(); + //qDebug() << "-- INSERTING:" << *m_data->recordEditBuffer(); success = m_data->saveNewRecord(m_currentRecord); } else { if (success) { //accept changes for this row: - qDebug() << "-- UPDATING:" << *m_data->recordEditBuffer(); - qDebug() << "-- BEFORE:" << *m_currentRecord; + //qDebug() << "-- UPDATING:" << *m_data->recordEditBuffer(); + //qDebug() << "-- BEFORE:" << *m_currentRecord; success = m_data->saveRecordChanges(m_currentRecord); - qDebug() << "-- AFTER:" << *m_currentRecord; + //qDebug() << "-- AFTER:" << *m_currentRecord; } } } @@ -717,7 +717,7 @@ m_recordEditing = -1; m_newRecordEditing = false; updateAfterAcceptRecordEditing(); - qDebug() << "EDIT RECORD ACCEPTED:"; + //qDebug() << "EDIT RECORD ACCEPTED:"; if (inserting) { //update navigator's data @@ -789,7 +789,7 @@ } //! \todo (js): cancel changes for this row! - qDebug() << "EDIT RECORD CANCELLED."; + //qDebug() << "EDIT RECORD CANCELLED."; /*emit*/ recordEditingTerminated(m_curRecord); return true; @@ -858,36 +858,36 @@ } else if (m_editor->valueIsNull()) {//null value entered if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) { - qDebug() << "NULL NOT ALLOWED!"; + //qDebug() << "NULL NOT ALLOWED!"; res = KDbValidator::Error; msg = KDbValidator::messageColumnNotEmpty().arg(m_editor->field()->captionOrName()) + "\n\n" + KDbTableViewData::messageYouCanImproveData(); desc = xi18n("The column's constraint is declared as NOT NULL (required)."); } else { - qDebug() << "NULL VALUE WILL BE SET"; + //qDebug() << "NULL VALUE WILL BE SET"; //ok, just leave newval as NULL setNull = true; } } else if (m_editor->valueIsEmpty()) {//empty value entered if (m_editor->field()->hasEmptyProperty()) { if (m_editor->field()->isNotEmpty() && !autoIncColumnCanBeOmitted) { - qDebug() << "EMPTY NOT ALLOWED!"; + //qDebug() << "EMPTY NOT ALLOWED!"; res = KDbValidator::Error; msg = KDbValidator::messageColumnNotEmpty().arg(m_editor->field()->captionOrName()) + "\n\n" + KDbTableViewData::messageYouCanImproveData(); desc = xi18n("The column's constraint is declared as NOT EMPTY (text should be filled)."); } else { - qDebug() << "EMPTY VALUE WILL BE SET"; + //qDebug() << "EMPTY VALUE WILL BE SET"; } } else { if (m_editor->field()->isNotNull() && !autoIncColumnCanBeOmitted) { - qDebug() << "NEITHER NULL NOR EMPTY VALUE CAN BE SET!"; + //qDebug() << "NEITHER NULL NOR EMPTY VALUE CAN BE SET!"; res = KDbValidator::Error; msg = KDbValidator::messageColumnNotEmpty().arg(m_editor->field()->captionOrName()) + "\n\n" + KDbTableViewData::messageYouCanImproveData(); desc = xi18n("The column's constraint is declared as NOT EMPTY and NOT NULL."); } else { - qDebug() << "NULL VALUE WILL BE SET BECAUSE EMPTY IS NOT ALLOWED"; + //qDebug() << "NULL VALUE WILL BE SET BECAUSE EMPTY IS NOT ALLOWED"; //ok, just leave newval as NULL setNull = true; } @@ -921,7 +921,7 @@ if ( (!setNull && !valueChanged) || (m_editor->field()->type() != KDbField::Boolean && setNull && m_currentRecord->at(realFieldNumber).isNull())) { - qDebug() << "VALUE NOT CHANGED."; + //qDebug() << "VALUE NOT CHANGED."; removeEditor(); if (m_acceptsRecordEditAfterCellAccepting || m_internal_acceptsRecordEditingAfterCellAccepting) acceptRecordEditing(); @@ -968,9 +968,9 @@ &newval, /*allowSignals*/true, currentTVColumn->visibleLookupColumnInfo() ? &visibleValue : 0)) { - qDebug() << "------ EDIT BUFFER CHANGED TO:" << *m_data->recordEditBuffer(); + //qDebug() << "------ EDIT BUFFER CHANGED TO:" << *m_data->recordEditBuffer(); } else { - qDebug() << "------ CHANGE FAILED"; + //qDebug() << "------ CHANGE FAILED"; res = KDbValidator::Error; //now: there might be called cancelEditor() in updateRecordEditBuffer() handler, diff --git a/src/widget/dataviewcommon/kexidataawarepropertyset.cpp b/src/widget/dataviewcommon/kexidataawarepropertyset.cpp --- a/src/widget/dataviewcommon/kexidataawarepropertyset.cpp +++ b/src/widget/dataviewcommon/kexidataawarepropertyset.cpp @@ -219,11 +219,11 @@ { cur_r = *r_it; if (prev_r >= 0) { -// qDebug() << "move " << prev_r+nud->removed-1 << ".." << cur_r-1 << " to " << prev_r+nud->removed-1 << ".." << cur_r-2; +// qDebug() << "move" << prev_r+nud->removed-1 << ".." << cur_r-1 << "to" << prev_r+nud->removed-1 << ".." << cur_r-2; int i = prev_r; KPropertySet *set = d->sets.at(i + num_removed); d->sets.remove(i + num_removed); - qDebug() << "property set " << i + num_removed << " deleted"; + //qDebug() << "property set" << i + num_removed << "deleted"; delete set; num_removed++; } diff --git a/src/widget/dataviewcommon/kexidataprovider.cpp b/src/widget/dataviewcommon/kexidataprovider.cpp --- a/src/widget/dataviewcommon/kexidataprovider.cpp +++ b/src/widget/dataviewcommon/kexidataprovider.cpp @@ -63,7 +63,7 @@ QString dataSource(formDataItem->dataSource().toLower()); if (dataSource.isEmpty()) continue; - qDebug() << widget->objectName(); + //qDebug() << widget->objectName(); m_dataItems.append(formDataItem); formDataItem->installListener(this); tmpSources.insert(dataSource); @@ -78,14 +78,14 @@ void KexiFormDataProvider::fillDataItems(KDbRecordData *data, bool cursorAtNewRecord) { Q_ASSERT(data); - qDebug() << "record.count=" << data->count() - << "\nRECORD=" << *data; + //qDebug() << "record.count=" << data->count() + // << "\nRECORD=" << *data; for (KexiFormDataItemInterfaceToIntMap::ConstIterator it = m_fieldNumbersForDataItems.constBegin(); it != m_fieldNumbersForDataItems.constEnd(); ++it) { KexiFormDataItemInterface *itemIface = it.key(); if (!itemIface->columnInfo()) { - qDebug() << "itemIface->columnInfo() == 0"; + //qDebug() << "itemIface->columnInfo() == 0"; continue; } //1. Is this a value with a combo box (lookup)? @@ -97,9 +97,9 @@ if (indexForVisibleLookupValue != -1 && (int)data->count() > indexForVisibleLookupValue) { visibleLookupValue = data->at(indexForVisibleLookupValue); } - qDebug() << "fill data of" << itemIface->dataSource() << "at idx" << it.value() + /*qDebug() << "fill data of" << itemIface->dataSource() << "at idx" << it.value() << "data=" << KDbUtils::squeezedValue(value) - << "indexForVisibleLookupValue=" << indexForVisibleLookupValue << "visibleLookupValue=" << KDbUtils::squeezedValue(visibleLookupValue); + << "indexForVisibleLookupValue=" << indexForVisibleLookupValue << "visibleLookupValue=" << KDbUtils::squeezedValue(visibleLookupValue);*/ const bool displayDefaultValue = cursorAtNewRecord && (value.isNull() && visibleLookupValue.isNull()) && !itemIface->columnInfo()->field()->defaultValue().isNull() && !itemIface->columnInfo()->field()->isAutoIncrement(); //no value to set but there is default value defined @@ -128,7 +128,7 @@ foreach(KexiFormDataItemInterface *dataItemIface, m_dataItems) { if (!dataItemIface->columnInfo() || !dataItemIface->columnInfo()->field()) continue; - qDebug() << " ** " << dataItemIface->columnInfo()->field()->name(); + //qDebug() << " ** " << dataItemIface->columnInfo()->field()->name(); it_dup = tmpDuplicatedItems.constFind(dataItemIface->columnInfo()->field()); int count; if (it_dup == tmpDuplicatedItems.constEnd()) @@ -141,16 +141,16 @@ for (it_dup = tmpDuplicatedItems.constBegin(); it_dup != tmpDuplicatedItems.constEnd(); ++it_dup) { if (it_dup.value() > 1) { m_duplicatedItems->insert(it_dup.key()); - qDebug() << "duplicated item: " << static_cast(it_dup.key())->name() - << " (" << it_dup.value() << " times)"; + //qDebug() << "duplicated item:" << static_cast(it_dup.key())->name() + // << "(" << it_dup.value() << "times)"; } } } if (item->columnInfo() && m_duplicatedItems->contains(item->columnInfo()->field())) { foreach(KexiFormDataItemInterface *dataItemIface, m_dataItems) { if (dataItemIface != item && item->columnInfo()->field() == dataItemIface->columnInfo()->field()) { - qDebug() << "- setting a copy of value for item '" - << dynamic_cast(dataItemIface)->objectName() << "' == " << value; + //qDebug() << "- setting a copy of value for item '" + // << dynamic_cast(dataItemIface)->objectName() << "'==" << value; dataItemIface->setValue(value); } } @@ -181,15 +181,15 @@ QHash columnsOrder(query->columnsOrder(conn)); for (QHash::const_iterator it = columnsOrder.constBegin(); it != columnsOrder.constEnd(); ++it) { - qDebug() << "query->columnsOrder()[ " << it.key()->field()->name() << " ] = " - << it.value(); + //qDebug() << "query->columnsOrder()[ " << it.key()->field()->name() << " ] = " + // << it.value(); } foreach(KexiFormDataItemInterface *item, m_dataItems) { KDbQueryColumnInfo* ci = query->columnInfo(conn, item->dataSource()); int index = ci ? columnsOrder[ ci ] : -1; - qDebug() << "query->columnsOrder()[ " << (ci ? ci->field()->name() : QString()) << " ] = " << index + /*qDebug() << "query->columnsOrder()[ " << (ci ? ci->field()->name() : QString()) << " ] = " << index << " (dataSource: " << item->dataSource() << ", name=" - << dynamic_cast(item)->objectName() << ")"; + << dynamic_cast(item)->objectName() << ")";*/ if (index != -1 && !m_fieldNumbersForDataItems[ item ]) m_fieldNumbersForDataItems.insert(item, index); //! @todo @@ -203,7 +203,7 @@ QSet tmpUsedDataSources; if (query) { - qDebug() << KDbConnectionAndQuerySchema(conn, *query); + //qDebug() << KDbConnectionAndQuerySchema(conn, *query); } m_disableFillDuplicatedDataItems = true; // temporary disable fillDuplicatedDataItems() // because setColumnInfo() can activate it @@ -221,9 +221,9 @@ if (query) { KDbQueryColumnInfo *ci = fieldsExpanded[fieldNumber]; item->setColumnInfo(conn, ci); - qDebug() << "- item=" << dynamic_cast(item)->objectName() + /*qDebug() << "- item=" << dynamic_cast(item)->objectName() << " dataSource=" << item->dataSource() - << " field=" << ci->field()->name(); + << " field=" << ci->field()->name();*/ const int indexForVisibleLookupValue = ci->indexForVisibleLookupValue(); if (-1 != indexForVisibleLookupValue && indexForVisibleLookupValue < (int)fieldsExpanded.count()) { //there's lookup column defined: set visible column as well @@ -237,8 +237,8 @@ item->internalEditor()->installEventFilter(m_mainWidget); } - qDebug() << "ALSO SET visibleColumn=" << *visibleColumnInfo - << "\n at position " << indexForVisibleLookupValue; + //qDebug() << "ALSO SET visibleColumn=" << *visibleColumnInfo + // << "\n at position" << indexForVisibleLookupValue; } } } diff --git a/src/widget/kexiqueryparameters.cpp b/src/widget/kexiqueryparameters.cpp --- a/src/widget/kexiqueryparameters.cpp +++ b/src/widget/kexiqueryparameters.cpp @@ -138,8 +138,8 @@ break; } default: - qWarning() << "unsupported type " << KDbField::typeName(parameter.type()) - << "for parameter \"" << parameter.message() << "\" - aborting query execution!"; + qWarning() << "unsupported type" << KDbField::typeName(parameter.type()) + << "for parameter \"" << parameter.message() << "\" - aborting query execution!"; return QList(); } } diff --git a/src/widget/kexisectionheader.cpp b/src/widget/kexisectionheader.cpp --- a/src/widget/kexisectionheader.cpp +++ b/src/widget/kexisectionheader.cpp @@ -116,7 +116,7 @@ void KexiSectionHeader::slotFocus(bool in) { - qDebug() << in; + //qDebug() << in; in = in || qApp->focusWidget() == this; QPalette pal(d->lbl->palette()); pal.setBrush(QPalette::Window, diff --git a/src/widget/navigator/KexiProjectItemDelegate.cpp b/src/widget/navigator/KexiProjectItemDelegate.cpp --- a/src/widget/navigator/KexiProjectItemDelegate.cpp +++ b/src/widget/navigator/KexiProjectItemDelegate.cpp @@ -1,5 +1,5 @@ /* This file is part of the KDE project - Copyright (C) 2011-2014 Jarosław Staniek + Copyright (C) 2011-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 @@ -21,6 +21,7 @@ #include "KexiProjectModel.h" #include "KexiProjectModelItem.h" #include +#include #include #include @@ -58,7 +59,18 @@ newOption.state |= QStyle::State_MouseOver; } KexiProjectModelItem *item = static_cast(index.internalPointer()); - if (!item->partItem()) { // this is a group item + const bool isGroupItem = !item->partItem(); + if (!isGroupItem) { + QStyledItemDelegate::paint(painter, newOption, QModelIndex()); + if (!(newOption.state & QStyle::State_Selected)) { + newOption.state + &= (0xffffffff ^ QStyle::State_MouseOver); // don't paint mouse highlight + // twice because it's translucent + } + } + newOption.rect.setLeft(newOption.rect.left() + + newOption.decorationSize.width() / (isGroupItem ? 2 : 1)); + if (isGroupItem) { if (item->childCount() == 0) { return; } @@ -69,6 +81,7 @@ newOption.displayAlignment = Qt::AlignLeft | Qt::AlignBottom; newOption.state &= (0xffffffff ^ QStyle::State_MouseOver); newOption.rect.setBottom(newOption.rect.bottom() - 3); + newOption.font = KexiStyle::titleFont(newOption.font); } QStyledItemDelegate::paint(painter, newOption, index); } diff --git a/src/widget/navigator/KexiProjectModelItem.cpp b/src/widget/navigator/KexiProjectModelItem.cpp --- a/src/widget/navigator/KexiProjectModelItem.cpp +++ b/src/widget/navigator/KexiProjectModelItem.cpp @@ -1,6 +1,6 @@ /* This file is part of the KDE project Copyright (C) 2002-2003 Lucijan Busch - Copyright (C) 2003-2004 Jarosław Staniek + Copyright (C) 2003-2016 Jarosław Staniek Copyright (C) 2010 Adam Pigg This library is free software; you can redistribute it and/or @@ -44,7 +44,6 @@ /* private: */ QList childItems; KexiProjectModelItem *parentItem; - QIcon icon; bool dirty; /* protected: */ KexiPart::Info *info; @@ -69,7 +68,6 @@ { Q_ASSERT(i); Q_ASSERT(item); - d->icon = QIcon::fromTheme(i->iconName()); } KexiProjectModelItem::~KexiProjectModelItem() @@ -159,13 +157,13 @@ //qDebug() << d->parentItem->d->childItems << this << data(0); return d->parentItem->d->childItems.indexOf(this); } - qDebug() << "No parent item!"; + //qDebug() << "No parent item!"; return 0; } QIcon KexiProjectModelItem::icon() const { - return d->icon; + return d->item ? d->info->darkIcon() : QIcon(); } Qt::ItemFlags KexiProjectModelItem::flags() const diff --git a/src/widget/navigator/KexiProjectNavigator.cpp b/src/widget/navigator/KexiProjectNavigator.cpp --- a/src/widget/navigator/KexiProjectNavigator.cpp +++ b/src/widget/navigator/KexiProjectNavigator.cpp @@ -185,12 +185,12 @@ //! @todo plugSharedAction("edit_paste",SLOT(slotPaste())); #endif - d->designAction = addAction("design_object", koIcon("document-properties"), xi18n("&Design"), + d->designAction = addAction("design_object", KexiIcon("mode-selector-design"), xi18n("&Design"), xi18n("Design object"), xi18n("Starts designing of the object selected in the list."), SLOT(slotDesignObject())); - d->editTextAction = addAction("editText_object", QIcon(), xi18n("Design in &Text View"), + d->editTextAction = addAction("editText_object", QIcon(), "Design in Text View", // <- no icon, no i18n, will be updated before use xi18n("Design object in text view"), xi18n("Starts designing of the object in the list in text view."), SLOT(slotEditTextObject())); @@ -573,7 +573,7 @@ { if (actionName == "project_export_data_table" && (d->features & ContextMenus)) return d->exportActionMenu->isVisible(); - qWarning() << "no such action: " << actionName; + qWarning() << "no such action:" << actionName; return false; } @@ -633,7 +633,7 @@ // handle the empty state with care... http://www.pinterest.com/romanyakimovich/ui-empty-states/ if (!d->emptyStateLabel) { QString imgPath = KIconLoader::global()->iconPath(KexiIconName("document-empty"), - KIconLoader::SizeLarge); - qDebug() << imgPath; + //qDebug() << imgPath; d->emptyStateLabel = new QLabel( xi18nc("@info Message for empty state in project navigator", "" @@ -709,10 +709,16 @@ && (partInfo.supportedViewModes() & Kexi::DesignViewMode)) { addAction("design_object"); } - if (m_actionCollection->action("editText_object") - && m_actionCollection->action("editText_object")->isEnabled() - && (partInfo.supportedViewModes() & Kexi::TextViewMode)) { - addAction("editText_object"); + QAction *a = m_actionCollection->action("editText_object"); + if (a && a->isEnabled() + && (partInfo.supportedViewModes() & Kexi::TextViewMode)) + { + QString actionText; + QString iconName; + KexiPart::getTextViewAction(partInfo.id(), &actionText, &iconName); + a->setText(actionText); + a->setIcon(QIcon::fromTheme(iconName)); + QMenu::addAction(a); } addSeparator(); diff --git a/src/widget/properties/KexiCustomPropertyFactory_p.cpp b/src/widget/properties/KexiCustomPropertyFactory_p.cpp --- a/src/widget/properties/KexiCustomPropertyFactory_p.cpp +++ b/src/widget/properties/KexiCustomPropertyFactory_p.cpp @@ -100,8 +100,9 @@ return; } const QString identifier(KDb::stringToIdentifier(value)); - if (identifier != value) - qDebug() << QString("String \"%1\" converted to identifier \"%2\".").arg(value).arg(identifier); + if (identifier != value) { + //qDebug() << QString("String \"%1\" converted to identifier \"%2\".").arg(value).arg(identifier); + } KPropertyStringEditor::setValue(identifier); } diff --git a/src/widget/properties/KexiObjectInfoWidget.h b/src/widget/properties/KexiObjectInfoWidget.h new file mode 100644 --- /dev/null +++ b/src/widget/properties/KexiObjectInfoWidget.h @@ -0,0 +1,87 @@ +/* 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. +*/ + +#ifndef KEXIOBJECTINFOWIDGET_H +#define KEXIOBJECTINFOWIDGET_H + +#include "kexiextwidgets_export.h" + +#include + +//! @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 + is displayed as: + [ObjectClassIcon] [ObjectName] + + Example uses: + - [button_icon] Button [quit] + - [label_icon] Label [welcome] +*/ +class KEXIEXTWIDGETS_EXPORT KexiObjectInfoWidget : public QWidget +{ + Q_OBJECT +public: + explicit KexiObjectInfoWidget(QWidget* parent = 0); + virtual ~KexiObjectInfoWidget(); + + void setObjectClassIconName(const QString &name); + + QString objectClassIconName() const; + + void setObjectClassName(const QString& name); + + QString objectClassName() const; + + void setObjectName(const QString& name); + + QString objectName() const; + + //! Sets the object name box read-only flag to @a set. + //! In addition it clears its focus policy. + void setObjectNameReadOnly(bool set); + + void setObjectNameVisible(bool set); + + void focusObjectNameBox(); + + bool checkObjectName(); + + //! If @a set is @c true, object name is assumed to be identifier (as in programming). + //! Otherwise it can be any text. + void setObjectNameIsIdentifier(bool set); + + //! @return true if object name is assumed to be identifier (as in programming). + bool isObjectNameIdentifier() const; + +Q_SIGNALS: + //! Possible name change accepted by the user with Enter or Return key or after Focus Out + void objectNameChangeAccepted(); + +protected Q_SLOTS: + void slotObjectNameEnterPressed(); + +private: + class Private; + Private * const d; +}; + +#endif diff --git a/src/widget/properties/KexiObjectInfoWidget.cpp b/src/widget/properties/KexiObjectInfoWidget.cpp new file mode 100644 --- /dev/null +++ b/src/widget/properties/KexiObjectInfoWidget.cpp @@ -0,0 +1,181 @@ +/* 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 + +#include +#include +#include + +class KexiObjectInfoWidget::Private +{ +public: + Private() : isObjectNameIdentifier(false), objectNameValidator(nullptr) + , slotObjectNameEnterPressedEnabled(true) {} + QString classIconName; + QLabel *objectIconLabel; + QLabel *objectClassLabel; + KexiPropertyPaneLineEdit *objectNameBox; + bool isObjectNameIdentifier; + KDbIdentifierValidator *objectNameValidator; + bool slotObjectNameEnterPressedEnabled; +}; + +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); + d->objectIconLabel->setFocusPolicy(Qt::NoFocus); + hlyr->addWidget(d->objectIconLabel, 3); + + d->objectClassLabel = new QLabel; + d->objectClassLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + d->objectClassLabel->setPalette(s.sectionTitlePalette(d->objectClassLabel->palette())); + d->objectClassLabel->setFocusPolicy(Qt::NoFocus); + hlyr->addWidget(d->objectClassLabel, 0); + + hlyr->addSpacing(s.horizontalSpacingAfterLabel); + + d->objectNameBox = new KexiPropertyPaneLineEdit; + connect(d->objectNameBox, &KexiPropertyPaneLineEdit::enterPressed, this, &KexiObjectInfoWidget::slotObjectNameEnterPressed); + connect(d->objectNameBox, &KexiPropertyPaneLineEdit::focusOut, this, &KexiObjectInfoWidget::slotObjectNameEnterPressed); + hlyr->addWidget(d->objectNameBox, 2); + d->objectNameBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + setObjectNameReadOnly(false); + + 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; + QIcon icon(d->classIconName.isEmpty() ? QIcon() : s.icon(iconName)); + if (icon.isNull()) { + d->objectIconLabel->setFixedWidth(0); + d->objectIconLabel->setPixmap(QPixmap()); + } + else { + d->objectIconLabel->setMaximumWidth(IconSize(KIconLoader::Small) + s.horizontalSpacingAfterIcon); + d->objectIconLabel->setPixmap(icon.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::setObjectNameReadOnly(bool set) +{ + d->objectNameBox->setReadOnly(set); + d->objectNameBox->setClearButtonEnabled(!set); + d->objectNameBox->setFocusPolicy(set ? Qt::NoFocus : Qt::ClickFocus); +} + +void KexiObjectInfoWidget::setObjectNameVisible(bool set) +{ + d->objectNameBox->setVisible(set); +} + +void KexiObjectInfoWidget::setObjectName(const QString& name) +{ + d->objectNameBox->setText(name); + d->objectNameBox->end(false); +} + +void KexiObjectInfoWidget::focusObjectNameBox() +{ + d->objectNameBox->setFocus(); +} + +void KexiObjectInfoWidget::setObjectNameIsIdentifier(bool set) +{ + if (d->isObjectNameIdentifier == set) { + return; + } + if (set) { + d->objectNameValidator = new KDbIdentifierValidator(this); + d->objectNameBox->setValidator(d->objectNameValidator); + } else { + d->objectNameBox->setValidator(0); + delete d->objectNameValidator; + d->objectNameValidator = 0; + } + d->isObjectNameIdentifier = set; +} + +bool KexiObjectInfoWidget::isObjectNameIdentifier() const +{ + return d->isObjectNameIdentifier; +} + +void KexiObjectInfoWidget::slotObjectNameEnterPressed() +{ + emit objectNameChangeAccepted(); +} + +bool KexiObjectInfoWidget::checkObjectName() +{ + const KDbValidator::Result result = d->objectNameValidator->check( + QString(), d->objectNameBox->text(), nullptr, nullptr); + return result == KDbValidator::Ok; +} diff --git a/src/widget/properties/KexiPropertyEditorView.h b/src/widget/properties/KexiPropertyEditorView.h --- a/src/widget/properties/KexiPropertyEditorView.h +++ b/src/widget/properties/KexiPropertyEditorView.h @@ -1,6 +1,6 @@ /* 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 @@ -22,13 +22,12 @@ #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 @@ -40,20 +39,21 @@ 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; diff --git a/src/widget/properties/KexiPropertyEditorView.cpp b/src/widget/properties/KexiPropertyEditorView.cpp --- a/src/widget/properties/KexiPropertyEditorView.cpp +++ b/src/widget/properties/KexiPropertyEditorView.cpp @@ -1,6 +1,6 @@ /* 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 @@ -19,7 +19,7 @@ */ #include "KexiPropertyEditorView.h" -#include "KexiObjectInfoLabel.h" +#include "KexiObjectInfoWidget.h" #include #include #include @@ -35,24 +35,29 @@ 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*)), @@ -83,8 +88,40 @@ 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/KexiPropertyPaneLineEdit.h b/src/widget/properties/KexiPropertyPaneLineEdit.h new file mode 100644 --- /dev/null +++ b/src/widget/properties/KexiPropertyPaneLineEdit.h @@ -0,0 +1,51 @@ +/* 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. +*/ + +#ifndef KEXIPROPERTYPANELINEEDIT_H +#define KEXIPROPERTYPANELINEEDIT_H + +#include "kexiextwidgets_export.h" + +#include + +//! @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 KexiPropertyPaneLineEdit(QWidget* parent = 0); + virtual ~KexiPropertyPaneLineEdit(); + + void setReadOnly(bool set); + +Q_SIGNALS: + void enterPressed(); + void focusOut(); + +protected: + void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; + void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE; + +private: + class Private; + Private * const d; +}; + +#endif diff --git a/src/widget/properties/KexiPropertyPaneLineEdit.cpp b/src/widget/properties/KexiPropertyPaneLineEdit.cpp new file mode 100644 --- /dev/null +++ b/src/widget/properties/KexiPropertyPaneLineEdit.cpp @@ -0,0 +1,67 @@ +/* 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 + +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; +} + +void KexiPropertyPaneLineEdit::keyPressEvent(QKeyEvent *event) +{ + QLineEdit::keyPressEvent(event); + if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { + emit enterPressed(); + } +} + +void KexiPropertyPaneLineEdit::focusOutEvent(QFocusEvent *event) +{ + emit focusOut(); + QLineEdit::focusOutEvent(event); +} + +void KexiPropertyPaneLineEdit::setReadOnly(bool set) +{ + QLineEdit::setReadOnly(set); + setCursor(QCursor(Qt::IBeamCursor)); +} diff --git a/src/widget/properties/KexiPropertyPaneViewBase.h b/src/widget/properties/KexiPropertyPaneViewBase.h deleted file mode 100644 --- a/src/widget/properties/KexiPropertyPaneViewBase.h +++ /dev/null @@ -1,72 +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. -*/ - -#ifndef KEXIPROPERTYEDITORVIEWBASE_H -#define KEXIPROPERTYEDITORVIEWBASE_H - -#include "kexiextwidgets_export.h" - -#include - -class QVBoxLayout; - -class KPropertySet; - -class KexiObjectInfoLabel; - -//! @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; - - /*! 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/KexiPropertyPaneViewBase.cpp b/src/widget/properties/KexiPropertyPaneViewBase.cpp deleted file mode 100644 --- a/src/widget/properties/KexiPropertyPaneViewBase.cpp +++ /dev/null @@ -1,125 +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 "KexiPropertyPaneViewBase.h" -#include "KexiObjectInfoLabel.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); - lyr->addWidget(d->infoLabel); -} - -KexiPropertyPaneViewBase::~KexiPropertyPaneViewBase() -{ - delete d; -} - -KexiObjectInfoLabel *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/KexiPropertyPaneWidget.h b/src/widget/properties/KexiPropertyPaneWidget.h new file mode 100644 --- /dev/null +++ b/src/widget/properties/KexiPropertyPaneWidget.h @@ -0,0 +1,88 @@ +/* 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 + +#include + +class KPropertyEditorView; + +//! @short A widget handling entire Property Pane +class KEXIEXTWIDGETS_EXPORT KexiPropertyPaneWidget : public QWidget +{ + Q_OBJECT +public: + explicit KexiPropertyPaneWidget(QWidget *parent = 0); + + virtual ~KexiPropertyPaneWidget(); + + 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(); + + /*! Changes property set to @a set. + If @a set is @c nullptr and @a textToDisplayForNullSet string is not empty, this + string is displayed (without icon or any other additional part). + If not specified, "No object selected" message is used. */ + void changePropertySet(KPropertySet* set, + const QByteArray& propertyToSelect = QByteArray(), + KPropertyEditorView::SetOptions options = KPropertyEditorView::SetOption::None, + const QString& textToDisplayForNullSet = QString()); + + /*! Updates info label of the property editor by reusing properties provided + by the current property set. + + Following internal properties in @a set can customize displaying this information: + - "this:classString" property of type string describes object's class name + - "this:iconName" property of type string describes class' icon, if missing, the icon + will be hidden + - "objectName" or "caption" property of type string describes object's name + - "this:visibleObjectNameProperty" property of type string specified name of property + that contains "object name" to display; this can be usable when we know that e.g. + "caption" property is available for a given type of objects and is better to use + (this is the case for Table Designer fields); if missing, "objectName" property is used + - "this:objectNameReadOnly" property of type boolean makes the object name box + read-only for the user; false by default + + If object's class and name is empty, the entire info label widget becomes hidden. + If @a set is @c nullptr, the property editor (editor()) becomes hidden. + + @see KexiMainWindow::updatePropertyEditorInfoLabel() */ + void updateInfoLabelForPropertySet(const QString& textToDisplayForNullSet); + +protected Q_SLOTS: + //! Possible name change accepted by the user + void slotObjectNameChangeAccepted(); + +private: + class Private; + Private * const d; +}; + +#endif diff --git a/src/widget/properties/KexiPropertyPaneWidget.cpp b/src/widget/properties/KexiPropertyPaneWidget.cpp new file mode 100644 --- /dev/null +++ b/src/widget/properties/KexiPropertyPaneWidget.cpp @@ -0,0 +1,189 @@ +/* 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 + +#include +#include +#include + +class KexiPropertyPaneWidget::Private +{ +public: + Private() : focusObjectNameBoxOnChange(false) {} + QVBoxLayout *mainLyr; + KexiObjectInfoWidget *infoLabel; + KPropertyEditorView *editor; + //! Needed by removeAllSections() + int firstSectionIndex; + bool focusObjectNameBoxOnChange; + + QByteArray objectNamePropertyName() const + { + if (!editor->propertySet()) { + return "objectName"; + } + return editor->propertySet()->propertyValue("this:visibleObjectNameProperty", "objectName") + .toByteArray(); + } +}; + +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); + connect(d->infoLabel, &KexiObjectInfoWidget::objectNameChangeAccepted, + this, &KexiPropertyPaneWidget::slotObjectNameChangeAccepted); + d->mainLyr->addSpacing(s.margins.top()); + + d->editor = new KPropertyEditorView(this); + s.setupEditor(d->editor); + d->editor->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + // Note: QWidgetItem is used instead of addWidget() so the editor's sizeHint() is used. + // This displays as many property items as possible. + d->mainLyr->addItem(new QWidgetItem(d->editor)); + d->mainLyr->addSpacing(s.verticalSpacing); // extra spacing after the editor + + d->mainLyr->addSpacing(s.verticalSpacing); + + d->firstSectionIndex = d->mainLyr->count(); + setFocusProxy(d->editor); + setFocusPolicy(Qt::WheelFocus); + + changePropertySet(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) +{ + Q_UNUSED(title); + if (d->mainLyr->indexOf(widget) != -1) { + return; + } + d->mainLyr->addWidget(widget); + widget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); + widget->show(); +} + +void KexiPropertyPaneWidget::changePropertySet(KPropertySet* set, + const QByteArray& propertyToSelect, + KPropertyEditorView::SetOptions options, + const QString& textToDisplayForNullSet) +{ + if (set != d->editor->propertySet()) { + slotObjectNameChangeAccepted(); // last chance to update + d->editor->changeSet(set, propertyToSelect, options); + } + updateInfoLabelForPropertySet(textToDisplayForNullSet); +} + +void KexiPropertyPaneWidget::updateInfoLabelForPropertySet(const QString& textToDisplayForNullSet) +{ + const KPropertySet* set = d->editor->propertySet(); + QString className, iconName, objectName; + if (set) { + className = set->propertyValue("this:classString").toString(); + iconName = set->propertyValue("this:iconName").toString(); + const bool useNameAsObjectName = d->objectNamePropertyName() == "objectName"; + d->infoLabel->setObjectNameIsIdentifier(useNameAsObjectName); + objectName = set->propertyValue(d->objectNamePropertyName()).toString(); + if (objectName.isEmpty() && !useNameAsObjectName) { + // get name if there is no caption/etc. + objectName = set->propertyValue("objectName").toString(); + } + d->infoLabel->setObjectNameReadOnly( + set->propertyValue("this:objectNameReadOnly", false).toBool()); + } else { + className = KDb::iifNotEmpty(textToDisplayForNullSet, xi18n("No object selected")); + iconName.clear(); + } + d->editor->setVisible(set); + + if (className.isEmpty() && objectName.isEmpty()) { + d->infoLabel->hide(); + } else { + d->infoLabel->setObjectNameVisible(set); + 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); + if (d->focusObjectNameBoxOnChange) { + d->focusObjectNameBoxOnChange = false; + if (set && set->propertyValue(d->objectNamePropertyName()).toString() != d->infoLabel->objectName()) { + d->infoLabel->focusObjectNameBox(); + } + } + d->infoLabel->setObjectName(objectName); + + d->infoLabel->layout()->update(); + update(); +} + +void KexiPropertyPaneWidget::slotObjectNameChangeAccepted() +{ + if (d->editor->propertySet()) { + d->editor->propertySet()->changeProperty(d->objectNamePropertyName(), d->infoLabel->objectName()); + d->focusObjectNameBoxOnChange = true; + } +} diff --git a/src/widget/relations/CMakeLists.txt b/src/widget/relations/CMakeLists.txt --- a/src/widget/relations/CMakeLists.txt +++ b/src/widget/relations/CMakeLists.txt @@ -1,4 +1,7 @@ -include_directories(${CMAKE_SOURCE_DIR}/src/core) +include_directories( + ${CMAKE_SOURCE_DIR}/src/core + ${CMAKE_SOURCE_DIR}/src/kexiutils/style +) ########### next target ############### diff --git a/src/widget/relations/KexiRelationsConnection.cpp b/src/widget/relations/KexiRelationsConnection.cpp --- a/src/widget/relations/KexiRelationsConnection.cpp +++ b/src/widget/relations/KexiRelationsConnection.cpp @@ -63,9 +63,9 @@ d->masterTable = masterTbl; if (!masterTbl || !detailsTbl) { - qDebug() << "expect sig11"; + /*qDebug() << "expect sig11"; qDebug() << masterTbl; - qDebug() << detailsTbl; + qDebug() << detailsTbl;*/ } d->detailsTable = detailsTbl; @@ -262,23 +262,23 @@ float my = y2 - y1; float mag = sqrt(mx * mx + my * my); float u = (((p.x() - x1) * (x2 - x1)) + ((p.y() - y1) * (y2 - y1))) / (mag * mag); - qDebug() << "u: " << u; + //qDebug() << "u:" << u; float iX = x1 + u * (x2 - x1); float iY = y1 + u * (y2 - y1); - qDebug() << "px: " << p.x(); - qDebug() << "py: " << p.y(); - qDebug() << "ix: " << iX; - qDebug() << "iy: " << iY; + //qDebug() << "px:" << p.x(); + //qDebug() << "py:" << p.y(); + //qDebug() << "ix:" << iX; + //qDebug() << "iy:" << iY; float dX = iX - p.x(); float dY = iY - p.y(); - qDebug() << "dx: " << dX; - qDebug() << "dy: " << dY; + //qDebug() << "dx:" << dX; + //qDebug() << "dy:" << dY; float distance = sqrt(dX * dX + dY * dY); - qDebug() << "distance: " << distance; + //qDebug() << "distance:" << distance; if (distance <= tolerance) return true; diff --git a/src/widget/relations/KexiRelationsScrollArea.cpp b/src/widget/relations/KexiRelationsScrollArea.cpp --- a/src/widget/relations/KexiRelationsScrollArea.cpp +++ b/src/widget/relations/KexiRelationsScrollArea.cpp @@ -158,7 +158,7 @@ if (!t || !d->connection) return 0; - qDebug() << t->name(); + //qDebug() << t->name(); KexiRelationsTableContainer* c = tableContainer(t); if (c) { @@ -270,7 +270,7 @@ KexiRelationsConnection *connView = new KexiRelationsConnection(master, details, conn, this); d->relationsConnections.insert(connView); - qDebug() << "connView->connectionRect() " << connView->connectionRect(); + //qDebug() << "connView->connectionRect()" << connView->connectionRect(); d->areaWidget->update(); /*! @todo will be moved up to relation/query part as this is only visual class @@ -343,7 +343,7 @@ if (delay < 0) delay = 0; delay = delay * delay / 100; - qDebug() << delay; + //qDebug() << delay; int add = 16; if (horizontalScrollBar()->maximum() > (d->movedTableContainer->geometry().right() + add)) { horizontalScrollBar()->setValue(horizontalScrollBar()->value() + add); @@ -397,7 +397,7 @@ emit connectionViewGotFocus(); if (ev->button() == Qt::RightButton) {//show popup - qDebug() << "context"; + //qDebug() << "context"; emit connectionContextMenuRequest(ev->globalPos()); } return; @@ -462,7 +462,7 @@ void KexiRelationsScrollArea::slotTableViewEndDrag() { - qDebug() << "END DRAG!"; + //qDebug() << "END DRAG!"; d->autoScrollTimer.stop(); } @@ -571,7 +571,7 @@ { if (d->focusedTableContainer == sender()) return; - qDebug() << "GOT FOCUS!"; + //qDebug() << "GOT FOCUS!"; clearSelection(); d->focusedTableContainer = (KexiRelationsTableContainer*)sender(); emit tableViewGotFocus(); diff --git a/src/widget/relations/KexiRelationsTableContainer_p.cpp b/src/widget/relations/KexiRelationsTableContainer_p.cpp --- a/src/widget/relations/KexiRelationsTableContainer_p.cpp +++ b/src/widget/relations/KexiRelationsTableContainer_p.cpp @@ -171,8 +171,8 @@ { //QFontMetrics fm(fontMetrics()); -// qDebug() << schema()->name() << " cw=" << columnWidth(0) + fm.width("i") -// << ", " << fm.width(schema()->name()+" "); +// qDebug() << schema()->name() << "cw=" << columnWidth(0) + fm.width("i") +// << "," << fm.width(schema()->name()+" "); //! @todo return KexiFieldListView::sizeHint(); } diff --git a/src/widget/relations/KexiRelationsView.cpp b/src/widget/relations/KexiRelationsView.cpp --- a/src/widget/relations/KexiRelationsView.cpp +++ b/src/widget/relations/KexiRelationsView.cpp @@ -22,6 +22,7 @@ #include "KexiRelationsView.h" #include #include +#include #include #include #include "KexiRelationsScrollArea.h" @@ -95,6 +96,7 @@ d->scrollArea = new KexiRelationsScrollArea(mainWidget); d->scrollArea->setObjectName("scroll_area"); + KexiStyle::setupFrame(d->scrollArea); setViewWidget(mainWidget, false/* no focus proxy */); setFocusProxy(d->scrollArea); g->addWidget(d->scrollArea, 1, 0); @@ -131,7 +133,7 @@ connect(d->openSelectedTableAction, SIGNAL(triggered()), this, SLOT(openSelectedTable())); - d->designSelectedTableAction = new QAction(koIcon("document-properties"), xi18n("&Design Table"), this); + d->designSelectedTableAction = new QAction(KexiIcon("mode-selector-design"), xi18n("&Design Table"), this); connect(d->designSelectedTableAction, SIGNAL(triggered()), this, SLOT(designSelectedTable())); d->designSelectedTableAction->setObjectName("relationsview_designTable"); @@ -208,7 +210,7 @@ return; if (!d->scrollArea->tableContainer(t)) { KexiRelationsTableContainer *c = d->scrollArea->addTableContainer(t, rect); - qDebug() << "adding table" << t->name(); + //qDebug() << "adding table" << t->name(); if (!c) return; connect(c, SIGNAL(fieldsDoubleClicked(KDbTableOrQuerySchema&,QStringList)), @@ -224,7 +226,7 @@ } if (i < count) { int oi = d->tableCombo->currentIndex(); - qDebug() << "removing a table from the combo box"; + //qDebug() << "removing a table from the combo box"; d->tableCombo->removeItem(i); if (d->tableCombo->count() > 0) { if (oi >= d->tableCombo->count()) { diff --git a/src/widget/tableview/KexiDataTableScrollArea.cpp b/src/widget/tableview/KexiDataTableScrollArea.cpp --- a/src/widget/tableview/KexiDataTableScrollArea.cpp +++ b/src/widget/tableview/KexiDataTableScrollArea.cpp @@ -67,7 +67,7 @@ if (!m_cursor->query()) { qWarning() << "Cursor should have query schema defined!\n--aborting setData().\n"; - qDebug() << *m_cursor; + //qDebug() << *m_cursor; clearColumns(); return false; } diff --git a/src/widget/tableview/KexiTableScrollArea.cpp b/src/widget/tableview/KexiTableScrollArea.cpp --- a/src/widget/tableview/KexiTableScrollArea.cpp +++ b/src/widget/tableview/KexiTableScrollArea.cpp @@ -865,7 +865,7 @@ // coordinates, as a region can't handle bigger coordinates contentsToViewport2(cx, cy, cx, cy); QRegion reg(QRect(cx, cy, cw, ch)); - //qDebug() << "---cy-- " << verticalScrollBar()->value(); + //qDebug() << "---cy--" << verticalScrollBar()->value(); // Subtract the table from it reg = reg.subtracted(QRect(QPoint(0, 0), ts - QSize(0, + verticalScrollBar()->value()))); @@ -934,8 +934,8 @@ s, s); //qDebug() << r; if (r.contains(e->pos())) { -// qDebug() << "e->x:" << e->x() << " e->y:" << e->y() << " " << recordPos(m_curRecord) << -// " " << columnPos(m_curColumn); +// qDebug() << "e->x:" << e->x() << "e->y:" << e->y() << recordPos(m_curRecord) << +// << columnPos(m_curColumn); boolToggled(); } } @@ -968,7 +968,7 @@ bool KexiTableScrollArea::handleContentsMousePressOrRelease(QMouseEvent* e, bool release) { Q_UNUSED(release); - //qDebug() << "oldRow=" << m_curRecord << " oldCol=" << m_curColumn; + //qDebug() << "oldRow=" << m_curRecord << "oldCol=" << m_curColumn; int newrow, newcol; //compute clicked row nr @@ -980,7 +980,7 @@ return false; } newrow++; - qDebug() << "Clicked just on 'insert' record."; + //qDebug() << "Clicked just on 'insert' record."; } else { // get new focus cell newrow = recordNumberAt(e->pos().y()); @@ -1024,7 +1024,7 @@ if (row > (recordCount() - 1 + (isInsertingEnabled() ? 1 : 0))) row = -1; //no row to paint } -// qDebug() << " row="<text().isEmpty() || !e->text()[0].isPrint()) { - qDebug() << "NOT PRINTABLE: 0x0" << QString("%1").arg(k, 0, 16); + //qDebug() << "NOT PRINTABLE: 0x0" << QString("%1").arg(k, 0, 16); // e->ignore(); QScrollArea::keyPressEvent(e); return; @@ -1249,12 +1249,12 @@ if (printable && !ro) { KDbTableViewColumn *tvcol = m_data->column(curCol); if (tvcol->acceptsFirstChar(e->text()[0])) { - qDebug() << "ev pressed: acceptsFirstChar()==true"; + //qDebug() << "ev pressed: acceptsFirstChar()==true"; const CreateEditorFlags flags = DefaultCreateEditorFlags | ReplaceOldValue; createEditor(curRow, curCol, e->text(), flags); } else { //! @todo show message "key not allowed eg. on a statusbar" - qDebug() << "ev pressed: acceptsFirstChar()==false"; + //qDebug() << "ev pressed: acceptsFirstChar()==false"; } } @@ -1561,7 +1561,7 @@ // qDebug()<value() << recordPos(row) << viewport()->width() << recordHeight(); if (record < 0 || record >= (recordCount() + 2/* sometimes we want to refresh the row after last*/)) return; - //qDebug() << horizontalScrollBar()->value() << " " << verticalScrollBar()->value(); + //qDebug() << horizontalScrollBar()->value() << verticalScrollBar()->value(); //qDebug() << QRect( columnPos( leftcol ), recordPos(row), viewport()->width(), recordHeight() ); d->scrollAreaWidget->update(horizontalScrollBar()->value(), recordPos(record), viewport()->width(), recordHeight()); @@ -1704,7 +1704,7 @@ #endif if ((recordCount() + (isInsertingEnabled() ? 1 : 0)) > 0 && columnCount() > 0) { /* qDebug() << columnPos( columnCount() - 1 ) + columnWidth( columnCount() - 1 ) - << ", " << recordPos( rowCount()-1+(isInsertingEnabled()?1:0)) + d->recordHeight */ + << "," << recordPos(rowCount()-1+(isInsertingEnabled()?1:0)) + d->recordHeight */ // qDebug() << m_navPanel->isVisible() <<" "<height()<<" " // << horizontalScrollBar()->sizeHint().height()<<" "<spontaneous() << " type=" << e->type(); +// qDebug() << "spontaneous" << e->spontaneous() << "type=" << e->type(); #ifdef KEXITABLEVIEW_DEBUG if (e->type() != QEvent::Paint && e->type() != QEvent::Leave diff --git a/src/widget/tableview/KexiTableScrollArea_p.cpp b/src/widget/tableview/KexiTableScrollArea_p.cpp --- a/src/widget/tableview/KexiTableScrollArea_p.cpp +++ b/src/widget/tableview/KexiTableScrollArea_p.cpp @@ -75,13 +75,7 @@ int KexiTableScrollArea::Private::columnOffset() const { - const QByteArray s(tv->style()->objectName().toLatin1().toLower()); - // hardcode, no choice - if (s == "breeze" || s == "windows") { - return 1; - } - if (s == "oxygen" || s == "qtcurve" ) { - return 2; - } - return 0; + //const QByteArray s(tv->style()->objectName().toLatin1().toLower()); + // Now in Qt 5 it's enough to just return this. Let's see if this will last forever. + return -1; } diff --git a/src/widget/tableview/kexiblobtableedit.cpp b/src/widget/tableview/kexiblobtableedit.cpp --- a/src/widget/tableview/kexiblobtableedit.cpp +++ b/src/widget/tableview/kexiblobtableedit.cpp @@ -136,17 +136,17 @@ //! @todo #if 0 //todo? QByteArray val = m_origValue.toByteArray(); - qDebug() << "Size of BLOB: " << val.size(); + qDebug() << "Size of BLOB:" << val.size(); m_tempFile = new QTemporaryFile(); m_tempFile->open(); - qDebug() << "Creating temporary file: " << m_tempFile->fileName(); + qDebug() << "Creating temporary file:" << m_tempFile->fileName(); QDataStream stream(m_tempFile); stream->writeRawBytes(val.data(), val.size()); delete m_tempFile; m_tempFile = 0; KMimeMagicResult* mmr = KMimeMagic::self()->findFileType(m_tempFile->fileName()); - qDebug() << "Mimetype = " << mmr->mimeType(); + qDebug() << "Mimetype=" << mmr->mimeType(); setViewWidget(new QWidget(this)); #endif @@ -182,7 +182,7 @@ stream.readRawBytes(data, f.size()); value.duplicate(data, f.size()); free(data); - qDebug() << "Size of BLOB: " << value.size(); + qDebug() << "Size of BLOB:" << value.size(); return QVariant(value); #endif } @@ -583,8 +583,7 @@ pm = *cached; if (pm.isNull()) { //cache pixmap - pm = KIconLoader::global()->loadIcon(key, KIconLoader::Small, - 0, KIconLoader::DefaultState , QStringList() , 0L, true/*canReturnNull*/); + pm = QIcon::fromTheme(key).pixmap(IconSize(KIconLoader::Small)); if (!pm.isNull()) d->pixmapCache.insert(key, new QPixmap(pm)); } diff --git a/src/widget/tableview/kexibooltableedit.cpp b/src/widget/tableview/kexibooltableedit.cpp --- a/src/widget/tableview/kexibooltableedit.cpp +++ b/src/widget/tableview/kexibooltableedit.cpp @@ -29,8 +29,8 @@ KexiBoolTableEdit::KexiBoolTableEdit(KDbTableViewColumn *column, QWidget *parent) : KexiTableEdit(column, parent) { - qDebug() << "KexiDataItemInterface::d->origValue.typeName()==" << KexiDataItemInterface::originalValue().typeName(); - qDebug() << "type== " << field()->typeName(); + //qDebug() << "KexiDataItemInterface::d->origValue.typeName()==" << KexiDataItemInterface::originalValue().typeName(); + //qDebug() << "type==" << field()->typeName(); KexiDataItemInterface::setHasFocusableWidget(false); KexiDataItemInterface::setAcceptEditorAfterDeleteContents(true); m_usesSelectedTextColor = false; @@ -122,7 +122,7 @@ else m_currentValue = m_currentValue.toBool() ? QVariant(false) : QVariant(); } - qDebug() << KexiDataItemInterface::originalValue() << m_currentValue; + //qDebug() << KexiDataItemInterface::originalValue() << m_currentValue; if (oldValue != m_currentValue) { signalValueChanged(); } diff --git a/src/widget/tableview/kexicomboboxpopup.cpp b/src/widget/tableview/kexicomboboxpopup.cpp --- a/src/widget/tableview/kexicomboboxpopup.cpp +++ b/src/widget/tableview/kexicomboboxpopup.cpp @@ -218,7 +218,7 @@ bool columnsFound = true; QList visibleAndBoundColumns = visibleColumns; visibleAndBoundColumns.append(lookupFieldSchema->boundColumn()); - qDebug() << visibleAndBoundColumns; + //qDebug() << visibleAndBoundColumns; foreach (int index, visibleAndBoundColumns) { KDbQueryColumnInfo *columnInfo = fieldsExpanded.value(index); if (!columnInfo || !columnInfo->field() || !d->privateQuery->addField(columnInfo->field())) { @@ -286,7 +286,7 @@ expr = fieldExpr; } } - qDebug() << expr; + //qDebug() << expr; KDbField *f = new KDbField(); f->setExpression(expr); @@ -312,7 +312,7 @@ // #endif //! @todo ... - qDebug() << "--- Private query:" << KDbConnectionAndQuerySchema(conn, *d->privateQuery); + //qDebug() << "--- Private query:" << KDbConnectionAndQuerySchema(conn, *d->privateQuery); cursor = conn->prepareQuery(d->privateQuery); } if (!cursor) @@ -341,7 +341,7 @@ for (int i = 0; i < hints.size(); i++) { KDbRecordData *newData = data->createItem(); (*newData)[0] = QVariant(hints[i]); - qDebug() << "added: '" << hints[i] << "'"; + //qDebug() << "added: '" << hints[i] << "'"; data->append(newData); } setDataInternal(data, true); @@ -452,12 +452,12 @@ } #endif if (o == this && (e->type() == QEvent::Hide || e->type() == QEvent::FocusOut)) { - qDebug() << "HIDE!!!"; + //qDebug() << "HIDE!!!"; emit hidden(); } else if (e->type() == QEvent::MouseButtonPress) { - qDebug() << "QEvent::MousePress"; + //qDebug() << "QEvent::MousePress"; } else if (o == d->tv) { - qDebug() << "QEvent::KeyPress TV"; + //qDebug() << "QEvent::KeyPress TV"; if (e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); const int k = ke->key(); diff --git a/src/widget/tableview/kexicomboboxtableedit.cpp b/src/widget/tableview/kexicomboboxtableedit.cpp --- a/src/widget/tableview/kexicomboboxtableedit.cpp +++ b/src/widget/tableview/kexicomboboxtableedit.cpp @@ -241,7 +241,7 @@ return; } if (!popup() || !popup()->isVisible()) { - qDebug() << "SHOW POPUP"; + //qDebug() << "SHOW POPUP"; showPopup(); } } diff --git a/src/widget/tableview/kexidatetableedit.cpp b/src/widget/tableview/kexidatetableedit.cpp --- a/src/widget/tableview/kexidatetableedit.cpp +++ b/src/widget/tableview/kexidatetableedit.cpp @@ -37,7 +37,7 @@ //! @todo add QValidator so date like "2006-59-67" cannot be even entered - qDebug() << m_formatter.inputMask(); + //qDebug() << m_formatter.inputMask(); m_lineedit->setInputMask(m_formatter.inputMask()); } @@ -116,7 +116,7 @@ bool KexiDateTableEdit::valueChanged() { - //qDebug() << m_origValue.toString() << " ? " << m_lineedit->text(); + //qDebug() << m_origValue.toString() << "?" << m_lineedit->text(); return KexiDataItemInterface::originalValue() != m_lineedit->text(); } diff --git a/src/widget/tableview/kexidatetimetableedit.cpp b/src/widget/tableview/kexidatetimetableedit.cpp --- a/src/widget/tableview/kexidatetimetableedit.cpp +++ b/src/widget/tableview/kexidatetimetableedit.cpp @@ -37,7 +37,7 @@ //! @todo add QValidator so time like "99:88:77" cannot be even entered - qDebug() << KexiDateTimeFormatter::inputMask(m_dateFormatter, m_timeFormatter); + //qDebug() << KexiDateTimeFormatter::inputMask(m_dateFormatter, m_timeFormatter); m_lineedit->setInputMask( KexiDateTimeFormatter::inputMask(m_dateFormatter, m_timeFormatter)); } @@ -111,7 +111,7 @@ bool KexiDateTimeTableEdit::valueChanged() { - //qDebug() << m_origValue.toString() << " ? " << m_lineedit->text(); + //qDebug() << m_origValue.toString() << "?" << m_lineedit->text(); return KexiDataItemInterface::originalValue() != m_lineedit->text(); } diff --git a/src/widget/tableview/kexiinputtableedit.cpp b/src/widget/tableview/kexiinputtableedit.cpp --- a/src/widget/tableview/kexiinputtableedit.cpp +++ b/src/widget/tableview/kexiinputtableedit.cpp @@ -69,8 +69,8 @@ void KexiInputTableEdit::init() { // qDebug() << "m_origValue.typeName()==" << m_origValue.typeName(); -// qDebug() << "type== " << field()->typeName(); -// qDebug() << "displayed type== " << displayedField()->typeName(); +// qDebug() << "type==" << field()->typeName(); +// qDebug() << "displayed type==" << displayedField()->typeName(); m_textFormatter.setField( field() ); KexiTextFormatter::OverrideDecimalPlaces overrideDecimalPlaces; @@ -252,7 +252,7 @@ QRect internalRect(rect); internalRect.setLeft(rect.x() + leftMargin()); internalRect.setWidth(internalRect.width() - rightMargin(focused) - 2*3); - qDebug() << rect << internalRect << fm.width(text); + //qDebug() << rect << internalRect << fm.width(text); return fm.width(text) > internalRect.width(); } diff --git a/src/widget/tableview/kexitimetableedit.cpp b/src/widget/tableview/kexitimetableedit.cpp --- a/src/widget/tableview/kexitimetableedit.cpp +++ b/src/widget/tableview/kexitimetableedit.cpp @@ -37,7 +37,7 @@ //! @todo add QValidator so time like "99:88:77" cannot be even entered - qDebug() << m_formatter.inputMask(); + //qDebug() << m_formatter.inputMask(); m_lineedit->setInputMask(m_formatter.inputMask()); } @@ -116,7 +116,7 @@ bool KexiTimeTableEdit::valueChanged() { - qDebug() << KexiDataItemInterface::originalValue().toString() << " ? " << m_lineedit->text(); + //qDebug() << KexiDataItemInterface::originalValue().toString() << "?" << m_lineedit->text(); return KexiDataItemInterface::originalValue() != m_lineedit->text(); } diff --git a/src/widget/utils/kexicontextmenuutils.cpp b/src/widget/utils/kexicontextmenuutils.cpp --- a/src/widget/utils/kexicontextmenuutils.cpp +++ b/src/widget/utils/kexicontextmenuutils.cpp @@ -153,7 +153,7 @@ if (QFileInfo(url.toLocalFile()).completeSuffix().isEmpty()) { url.setPath(url.toLocalFile() + QLatin1Char('.') + fileExtension); } - qDebug() << url; + //qDebug() << url; QFile f(url.toLocalFile()); if (f.exists() && KMessageBox::Yes