diff --git a/src/core/KexiView.cpp b/src/core/KexiView.cpp index 080690d88..f809db835 100644 --- a/src/core/KexiView.cpp +++ b/src/core/KexiView.cpp @@ -1,772 +1,754 @@ /* 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 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 "KexiView.h" #include "KexiMainWindowIface.h" #include "KexiWindow.h" #include "kexiproject.h" #include "kexipartinfo.h" #include #include #include #include #include #include "KexiGroupButton.h" #include #include #include #include #include #include #include #include #include #include //! @internal Action for toggling view mode class KEXICORE_EXPORT KexiToggleViewModeAction : public QAction { Q_OBJECT 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) : QAction( QIcon::fromTheme(Kexi::iconNameForViewMode(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; } } }; //------------------------- class Q_DECL_HIDDEN KexiView::Private { public: explicit Private(KexiView *qq) : q(qq) , viewWidget(0) , parentView(0) , newlyAssignedID(-1) , viewMode(Kexi::NoViewMode) //unknown! , isDirty(false) , slotSwitchToViewModeInternalEnabled(true) , sortedProperties(false) , recentResultOfSwitchToViewModeInternal(true) , m_mainMenu(0) { } ~Private() { } void toggleViewModeButtonBack(Kexi::ViewMode mode) { 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; } } QMenu* mainMenu() { if (m_mainMenu) { return m_mainMenu; } if (!window) { return 0; } KexiSmallToolButton* menuButton = new KexiSmallToolButton( 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); m_mainMenu = new QMenu(menuButton); menuButton->setMenu(m_mainMenu); return m_mainMenu; } KexiGroupButton *addViewButton(KexiGroupButton::GroupPosition pos, Kexi::ViewMode mode, QWidget *parent, const char *slot, const QString &text, QHBoxLayout *btnLyr) { if (!window->supportsViewMode(mode)) { return 0; } QAction *a = new KexiToggleViewModeAction(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->setText(text); btn->setIcon(a->icon()); QFont f(q->font()); f.setPointSizeF(KexiUtils::smallestReadableFont().pointSizeF()); btn->setFont(f); btn->setToolTip(a->toolTip()); btn->setWhatsThis(a->whatsThis()); btn->setCheckable(true); btn->setAutoRaise(true); btnLyr->addWidget(btn); return btn; } KexiView *q; QVBoxLayout* mainLyr; QWidget *topBarHWidget; KexiFlowLayout *topBarLyr; QHash toggleViewModeActions; QHash toggleViewModeButtons; KexiSmallToolButton* saveDesignButton; QString defaultIconName; KexiWindow *window; QWidget *viewWidget; KexiView *parentView; QPointer lastFocusedChildBeforeFocusOut; /*! Member set to newly assigned object's ID in storeNewData() and used in storeDataBlock(). This is needed because usually, storeDataBlock() can be called from storeNewData() and in this case window has not yet assigned valid identifier (it has just negative temp. number). \sa KexiWindow::id() */ int newlyAssignedID; /*! Mode for this view. Initialized by KexiWindow::switchToViewMode(). Can be useful when single class is used for more than one view (e.g. KexiDBForm). */ Kexi::ViewMode viewMode; QList children; /*! View-level actions (not shared), owned by the view. */ QList viewActions; QHash viewActionsHash; /*! Main-meny-level actions (not shared), owned by the view. */ QList mainMenuActions; QHash mainMenuActionsHash; bool isDirty; //! Used in slotSwitchToViewModeInternal() to disabling it bool slotSwitchToViewModeInternalEnabled; bool sortedProperties; //! Used in slotSwitchToViewModeInternal() to disabling d->window->switchToViewModeInternal(mode) call. //! 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; private: QMenu* m_mainMenu; }; //---------------------------------------------------------- KexiView::KexiView(QWidget *parent) : QWidget(parent) , KexiActionProxy(this) , d(new Private(this)) { QWidget *wi = this; while ((wi = wi->parentWidget()) && !qobject_cast(wi)) { } d->window = (wi && qobject_cast(wi)) ? qobject_cast(wi) : nullptr; if (d->window) { //init view mode number for this view (obtained from window where this view is created) if (d->window->supportsViewMode(d->window->creatingViewsMode())) d->viewMode = d->window->creatingViewsMode(); } setObjectName( QString("%1_for_%2_object") .arg(Kexi::nameForViewMode(d->viewMode).replace(' ', '_')) .arg(d->window ? d->window->partItem()->name() : QString("??"))); installEventFilter(this); d->mainLyr = new QVBoxLayout(this); 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, 2); + + bool toggleModePossible = !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->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; + } +} + KexiView::~KexiView() { delete d; } KexiWindow* KexiView::window() const { return d->window; } bool KexiView::isDirty() const { return d->isDirty; } bool KexiView::isDataEditingInProgress() const { return false; } tristate KexiView::saveDataChanges() { return true; } tristate KexiView::cancelDataChanges() { return true; } Kexi::ViewMode KexiView::viewMode() const { return d->viewMode; } KexiPart::Part* KexiView::part() const { return d->window ? d->window->part() : 0; } tristate KexiView::beforeSwitchTo(Kexi::ViewMode mode, bool *dontStore) { Q_UNUSED(mode); Q_UNUSED(dontStore); return true; } tristate KexiView::afterSwitchFrom(Kexi::ViewMode mode) { Q_UNUSED(mode); return true; } QSize KexiView::preferredSizeHint(const QSize& otherSize) { return otherSize; } void KexiView::closeEvent(QCloseEvent * e) { bool cancel = false; emit closing(&cancel); if (cancel) { e->ignore(); return; } QWidget::closeEvent(e); } KPropertySet *KexiView::propertySet() { return 0; } void KexiView::propertySetSwitched() { if (window()) { KexiMainWindowIface::global()->propertySetSwitched(window(), false/*force*/, true/*preservePrevSelection*/, d->sortedProperties); } } void KexiView::propertySetReloaded(bool preservePrevSelection, const QByteArray& propertyToSelect) { if (window()) KexiMainWindowIface::global()->propertySetSwitched( window(), true, preservePrevSelection, d->sortedProperties, propertyToSelect); } void KexiView::setDirty(bool set) { const bool changed = (d->isDirty != set); d->isDirty = set; d->isDirty = isDirty(); if (d->saveDesignButton) d->saveDesignButton->setEnabled(d->isDirty); if (d->parentView) { d->parentView->setDirty(d->isDirty); } else { if (changed && d->window) d->window->dirtyChanged(this); } } void KexiView::setDirty() { setDirty(true); } KDbObject* KexiView::storeNewData(const KDbObject& object, KexiView::StoreNewDataOptions options, bool *cancel) { Q_ASSERT(cancel); Q_UNUSED(options) Q_UNUSED(cancel) QScopedPointer newObject(new KDbObject); *newObject = object; KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); if (!conn->storeNewObjectData(newObject.data()) || !conn->removeDataBlock(newObject->id()) // for sanity || !KexiMainWindowIface::global()->project()->removeUserDataBlock(newObject->id()) // for sanity ) { return 0; } d->newlyAssignedID = newObject->id(); return newObject.take(); } KDbObject* KexiView::copyData(const KDbObject& object, KexiView::StoreNewDataOptions options, bool *cancel) { Q_ASSERT(cancel); Q_UNUSED(options) Q_UNUSED(cancel) QScopedPointer newObject(new KDbObject); *newObject = object; KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); if (!conn->storeNewObjectData(newObject.data()) || !conn->copyDataBlock(d->window->id(), newObject->id()) || !KexiMainWindowIface::global()->project()->copyUserDataBlock(d->window->id(), newObject->id()) ) { return 0; } d->newlyAssignedID = newObject->id(); return newObject.take(); } tristate KexiView::storeData(bool dontAsk) { Q_UNUSED(dontAsk); if (!d->window || !d->window->schemaObject()) return false; if (!KexiMainWindowIface::global()->project() ->dbConnection()->storeObjectData(d->window->schemaObject())) { return false; } setDirty(false); return true; } bool KexiView::loadDataBlock(QString *dataString, const QString& dataID, bool canBeEmpty) { if (!d->window) return false; const tristate res = KexiMainWindowIface::global()->project()->dbConnection() ->loadDataBlock(d->window->id(), dataString, dataID); if (canBeEmpty && ~res) { dataString->clear(); return true; } return res == true; } bool KexiView::storeDataBlock(const QString &dataString, const QString &dataID) { if (!d->window) return false; int effectiveID; if (d->newlyAssignedID > 0) {//ID not yet stored within window, but we've got ID here effectiveID = d->newlyAssignedID; d->newlyAssignedID = -1; } else effectiveID = d->window->id(); return effectiveID > 0 && KexiMainWindowIface::global()->project()->dbConnection()->storeDataBlock( effectiveID, dataString, dataID); } bool KexiView::removeDataBlock(const QString& dataID) { if (!d->window) return false; return KexiMainWindowIface::global()->project()->dbConnection() ->removeDataBlock(d->window->id(), dataID); } bool KexiView::eventFilter(QObject *o, QEvent *e) { if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) { // qDebug() << "this=[" << o->metaObject()->className() // << objectName() << "] o=[" << o->metaObject()->className() << o->objectName() // << "] focusWidget=[" << (qApp->focusWidget() ? qApp->focusWidget()->metaObject()->className() : QString()) // << (qApp->focusWidget() ? qApp->focusWidget()->objectName() : QString()) << "] ev.type=" << e->type(); if (KDbUtils::hasParent(this, o)) { if (e->type() == QEvent::FocusOut && qApp->focusWidget() && !KDbUtils::hasParent(this, qApp->focusWidget())) { //focus out: when currently focused widget is not a parent of this view emit focus(false); } else if (e->type() == QEvent::FocusIn) { emit focus(true); } if (e->type() == QEvent::FocusOut) { // qDebug() << focusWidget()->className() << focusWidget()->name(); // qDebug() << o->className() << o->name(); KexiView *v = KDbUtils::findParent(o); if (v) { while (v->d->parentView) v = v->d->parentView; if (KDbUtils::hasParent(this, static_cast(v->focusWidget()))) v->d->lastFocusedChildBeforeFocusOut = static_cast(v->focusWidget()); } } if (e->type() == QEvent::FocusIn && m_actionProxyParent) { m_actionProxyParent->m_focusedChild = this; } } } return false; } void KexiView::setViewWidget(QWidget* w, bool focusProxy) { if (d->viewWidget == w) return; if (d->viewWidget) { d->viewWidget->removeEventFilter(this); d->mainLyr->removeWidget(d->viewWidget); } 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); //} if (focusProxy) setFocusProxy(d->viewWidget); //js: ok? } } void KexiView::addChildView(KexiView* childView) { d->children.append(childView); addActionProxyChild(childView); childView->d->parentView = this; childView->installEventFilter(this); } void KexiView::removeView(Kexi::ViewMode mode) { window()->removeView(mode); } void KexiView::setFocus() { if (!d->lastFocusedChildBeforeFocusOut.isNull()) { // qDebug() << "FOCUS:" << d->lastFocusedChildBeforeFocusOut->className() << d->lastFocusedChildBeforeFocusOut->name(); QWidget *w = d->lastFocusedChildBeforeFocusOut; d->lastFocusedChildBeforeFocusOut = 0; w->setFocus(); } else { setFocusInternal(); } KexiMainWindowIface::global()->invalidateSharedActions(this); } QAction* KexiView::sharedAction(const QString& action_name) { if (part()) { KActionCollection *ac; if ((ac = part()->actionCollectionForMode(viewMode()))) { QAction* a = ac->action(action_name); if (a) return a; } } return KexiActionProxy::sharedAction(action_name); } void KexiView::setAvailable(const QString& action_name, bool set) { if (part()) { KActionCollection *ac; QAction* a; if ((ac = part()->actionCollectionForMode(viewMode())) && (a = ac->action(action_name))) { a->setEnabled(set); } } KexiActionProxy::setAvailable(action_name, set); } void KexiView::updateActions(bool activated) { //do nothing here //do the same for children :) foreach(KexiView* view, d->children) { view->updateActions(activated); } } void KexiView::setViewActions(const QList& actions) { d->viewActions = actions; d->viewActionsHash.clear(); foreach(QAction* action, d->viewActions) { d->viewActionsHash.insert(action->objectName().toLatin1(), action); } } void KexiView::setMainMenuActions(const QList& actions) { d->mainMenuActions = actions; d->mainMenuActionsHash.clear(); foreach(QAction* action, d->mainMenuActions) { d->mainMenuActionsHash.insert(action->objectName().toLatin1(), action); } } QAction* KexiView::viewAction(const char* name) const { return d->viewActionsHash.value(name); } QList KexiView::viewActions() const { return d->viewActions; } void KexiView::toggleViewModeButtonBack() { d->toggleViewModeButtonBack(Kexi::DataViewMode); d->toggleViewModeButtonBack(Kexi::DesignViewMode); d->toggleViewModeButtonBack(Kexi::TextViewMode); } void KexiView::createViewModeToggleButtons() { d->topBarLyr->addSpacing(KexiUtils::spacingHint()); QWidget *btnCont = new QWidget(d->topBarHWidget); QHBoxLayout *btnLyr = new QHBoxLayout; btnLyr->setSpacing(0); btnLyr->setContentsMargins(0, 0, 0, 0); btnCont->setLayout(btnLyr); 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); } void KexiView::slotSwitchToTextViewModeInternal(bool) { slotSwitchToViewModeInternal(Kexi::TextViewMode); } void KexiView::slotSwitchToViewModeInternal(Kexi::ViewMode mode) { if (!d->slotSwitchToViewModeInternalEnabled) return; if (d->recentResultOfSwitchToViewModeInternal != true) d->recentResultOfSwitchToViewModeInternal = true; else d->recentResultOfSwitchToViewModeInternal = d->window->switchToViewModeInternal(mode); if (d->viewMode != mode) { //switch back visually KexiGroupButton *b = d->toggleViewModeButtons.value(mode); d->slotSwitchToViewModeInternalEnabled = false; b->setChecked(false); d->slotSwitchToViewModeInternalEnabled = true; } } void KexiView::initViewActions() { 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()); if (action->dynamicPropertyNames().contains("iconOnly") && action->property("iconOnly").toBool() ) { btn->setToolButtonStyle(Qt::ToolButtonIconOnly); } d->topBarLyr->addWidget(btn); } } } void KexiView::initMainMenuActions() { if (!d->topBarLyr) return; if (d->mainMenuActions.isEmpty()) { return; } d->mainMenu()->clear(); foreach(QAction* action, d->mainMenuActions) { d->mainMenu()->addAction(action); } } void KexiView::setSortedProperties(bool set) { d->sortedProperties = set; } bool KexiView::saveSettings() { return true; } QString KexiView::defaultIconName() const { return d->defaultIconName; } void KexiView::setDefaultIconName(const QString& iconName) { d->defaultIconName = iconName; } QList KexiView::currentParameters() const { return QList(); } #include "KexiView.moc" diff --git a/src/core/KexiView.h b/src/core/KexiView.h index 2669ed830..d3a9e2618 100644 --- a/src/core/KexiView.h +++ b/src/core/KexiView.h @@ -1,357 +1,357 @@ /* 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 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 KEXIVIEW_H #define KEXIVIEW_H #include #include #include #include "kexiactionproxy.h" class KexiWindow; class KPropertySet; class KDbObject; //! Base class for single view embeddable in KexiWindow. /*! This class automatically works as a proxy for shared (application-wide) actions. KexiView has 'dirty' flag to indicate that view's data has changed. This flag's state is reused by KexiWindow object that contain the view. KexiView objects can be also nested, using addChildView(): any actions and 'dirty' flag are transmited to parent view in this case. KexiView objects are usually allocated within KexiWindow objects by implementing KexiPart::createView() method. See query or table part code for examples. KexiView object can be also allocated without attaching it KexiWindow, especially within dock window. see KexiMainWindow::initNavigator() to see example how KexiBrowser does this. @todo add some protected access methods */ class KEXICORE_EXPORT KexiView : public QWidget, public KexiActionProxy { Q_OBJECT public: explicit KexiView(QWidget *parent); virtual ~KexiView(); //! \return parent KexiWindow that containing this view, //! or 0 if no window contain this view KexiWindow* window() const; /*! Added for convenience. \return KexiPart object that was used to create this view (with a window) or 0 if this view is not created using KexiPart. \sa window() */ KexiPart::Part* part() const; /*! \return preferred size hint, that can be used to resize the view. It is computed using maximum of (a) \a otherSize and (b) current dock area's size, so the view won't exceed this maximum size. The method is used e.g. in KexiWindow::sizeHint(). If you reimplement this method, do not forget to return value of yoursize.boundedTo( KexiView::preferredSizeHint(otherSize) ). */ virtual QSize preferredSizeHint(const QSize& otherSize); void addChildView(KexiView* childView); void removeView(Kexi::ViewMode mode); /*! True if contents (data) of the view is dirty and need to be saved This may or not be used, depending if changes in the window are saved immediately (e.g. like in datatableview) or saved by hand (by user) (e.g. like in alter-table window). "Dirty" flag is reused by KexiWindow::dirty(). Default implementation just uses internal dirty flag, that is false by default. Reimplement this if you e.g. want reuse other "dirty" flag from internal structures that may be changed. */ virtual bool isDirty() const; /*! @return true if data editing is in progress. This is useful to indicate * to the master window that the view should save the before switching to * other view. This information is used in KexiWindow::switchToViewMode(). * Implement this in view that supports data editing, typically * of mode Kexi::DataViewMode. If you do this, also implement * saveDataChanges() and cancelDataChanges(). * Default implementation just returns false. */ virtual bool isDataEditingInProgress() const; /*! Saves changes that are currently made to the associated data. * Implement this in view that supports data editing, typically * of mode Kexi::DataViewMode. If you do this, also implement * isDataEditingInProgress() and cancelDataChanges(). * This method is used by KexiWindow::switchToViewMode(). * Default implementation just returns true. * @return true on success, false on failure and cancelled if the operation * has been cancelled. */ virtual tristate saveDataChanges(); /*! Cancel changes that are currently made to the associated data. * Implement this in view that supports data editing, typically * of mode Kexi::DataViewMode. If you do this, also implement * isDataEditingInProgress() and saveDataChanges(). * This method is used by KexiWindow::switchToViewMode(). * Default implementation just returns true. * @return true on success, false on failure and cancelled if the operation * has been cancelled. */ virtual tristate cancelDataChanges(); /*! \return the view mode for this view. */ Kexi::ViewMode viewMode() const; /*! Reimplemented from KexiActionProxy. \return shared action with name \a action_name for this view. If there's no such action declared in Kexi Part (part()), global shared action is returned (if exists). */ virtual QAction* sharedAction(const QString& action_name); /*! Enables or disables shared action declared in Kexi Part (part()). If there's no such action, global shared action is enabled or disabled (if exists). */ virtual void setAvailable(const QString& action_name, bool set); enum StoreNewDataOption { OverwriteExistingData = 1 //!< Overwerite existing object in storeNewData() }; Q_DECLARE_FLAGS(StoreNewDataOptions, StoreNewDataOption) QString defaultIconName() const; void setDefaultIconName(const QString& iconName); /*! For KexiQueryView */ virtual QList currentParameters() const; public Q_SLOTS: virtual void setFocus(); /*! Call this in your view's implementation whenever current property set (returned by propertySet()) is switched to other, so property editor contents need to be completely replaced. */ virtual void propertySetSwitched(); /*! Saves settings for the view. Default implementation does nothing and returns true. Implement this if there are settings to save. */ virtual bool saveSettings(); /*! Sets dirty flag on or off. It the flag changes, dirty(bool) signal is emitted by the parent window (KexiWindow), to inform the world about that. If this view has a parent view, setDirty() is called also on parent view. Always use this function to update 'dirty' flag information. */ void setDirty(bool set); /*! Equal to setDirty(true). */ void setDirty(); Q_SIGNALS: //! emitted when the view is about to close void closing(bool *cancel); void focus(bool in); protected: virtual bool eventFilter(QObject *o, QEvent *e); /*! called by KexiWindow::switchToViewMode() right before window is switched to new mode By default does nothing. Reimplement this if you need to do something before switching to this view. \return true if you accept or false if a error occupied and view shouldn't change If there is no error but switching should be just cancelled (probably after showing some info messages), you need to return cancelled. Set \a dontStore to true (it's false by default) if you want to avoid data storing by storeData() or storeNewData(). */ virtual tristate beforeSwitchTo(Kexi::ViewMode mode, bool *dontStore); /*! called by KexiWindow::switchToViewMode() right after window is switched to new mode By default does nothing. Reimplement this if you need to do something after switching to this view. \return true if you accept or false if a error occupied and view shouldn't change If there is no error but switching should be just cancelled (probably after showing some info messages), you need to return cancelled. */ virtual tristate afterSwitchFrom(Kexi::ViewMode mode); virtual void closeEvent(QCloseEvent * e); /*! \return a property set for this view. For reimplementation. By default returns NULL. */ virtual KPropertySet *propertySet(); /*! Call this in your view's implementation whenever current property set is changed that few properties are now visible and/or few other are invisible, so property editor operating on this property set should be completely reloaded. If \a preservePrevSelection is true and there was a property set assigned before call, previously selected item will be preselected in the editor (if found). */ void propertySetReloaded(bool preservePrevSelection = false, const QByteArray& propertyToSelect = QByteArray()); /*! Tells this view to create and store data of the new object pointed by \a object on the backend. Called by KexiWindow::storeNewData() and KexiWindow::storeDataAs(). Default implementation: - makes a deep copy of \a object - stores object data \a object in 'kexi__objects' internal table using KDbConnection::storeNewObjectData(). Reimplement this for your needs. Requirements: - deep copy of \a object should be made - object data should be created at the backend (by calling KexiView::storeNewData(const KDbObject&, KexiView::StoreNewDataOptions,bool*)) or using KDbConnection::storeNewObjectData() or more specialized method. For example KexiTableDesignerView uses KDbConnection::createTable(KDbTableSchema) for this (KDbTableSchema inherits KDbObject) to store more information than just the object data. You should use such subclasses if needed. Should return newly created object data object on success. In this case, do not store schema object yourself (make a deep copy if needed). */ virtual KDbObject* storeNewData(const KDbObject& object, KexiView::StoreNewDataOptions options, bool *cancel); /*! Tells this view to fully copy existing object's data pointed by \a object on the backend. For example, for database tables it whould copy metadata, copy \a object, so the copy will have different name, caption and description, and physically copy the table (possibly on the server side). Called by KexiWindow::storeDataAs(). Default implementation: - makes a deep copy of \a object - stores object data \a object in 'kexi__objects' internal table using KDbConnection::storeNewObjectData() - makes a full copy of data and user data. Reimplement this for your needs. Requirements: - deep copy of \a object should be made - object data should be created at the backend (by calling KexiView::copyData(const KDbObject&, KexiView::StoreNewDataOptions,bool*)) or using KDbConnection::storeNewObjectData() or more specialized method. For example KexiTableDesignerView uses KDbConnection::createTable(KDbTableSchema) for this (KDbTableSchema inherits KDbObject) to store more information than just object data. Then it copies data table on the server side. You should use such subclasses if needed. Should return newly created object data object on success. In this case, do not store schema object yourself (make deep copy if needed). */ virtual KDbObject* copyData(const KDbObject& object, KexiView::StoreNewDataOptions options, bool *cancel); /*! Loads large string data \a dataString block (e.g. xml form's representation), indexed with optional \a dataID, from the database backend. If \a canBeEmpty is true and there is no data block for dataID, true is returned and \a dataString is set to null string. The default is false. \return true on success \sa storeDataBlock(). */ bool loadDataBlock(QString *dataString, const QString& dataID = QString(), bool canBeEmpty = false); /*! Tells this view to store data changes on the backend. Called by KexiWindow::storeData(). Default implementation: - stores object data \a object in 'kexi__objects' internal table using KDbConnection::storeObjectData(). If \a dontAsk is true, no question dialog will be shown to the user. The default is false. Reimplement this for your needs. Should return true on success, false on failure and cancelled when the task should be cancelled. \sa storeNewData() */ virtual tristate storeData(bool dontAsk = false); /*! Stores (potentially large) string data \a dataString, block (e.g. xml form's representation), at the database backend. Block will be stored in "kexi__objectdata" table pointed by this object's id and an optional \a dataID identifier. If window's id is not available (KexiWindow::id()), then ID that was just created in storeNewData() is used (see description of newlyAssignedID()). If there is already such record in the table, it's simply overwritten. \return true on success */ bool storeDataBlock(const QString &dataString, const QString &dataID = QString()); /*! Removes (potentially large) string data (e.g. xml form's representation), pointed by optional \a dataID, from the database backend. \return true on success. Does not fail if the block doe not exists. Note that if \a dataID is not specified, all data blocks for this view will be removed. \sa storeDataBlock(). */ bool removeDataBlock(const QString& dataID = QString()); void setViewWidget(QWidget* w, bool focusProxy = false); /*! Updates actions (e.g. availability). Reimplement it, if needed (you must call superclass impelmentation at the end!). This implementation does nothing for this view but calls updateActions() for every child-view of this view. called by KexiWindow on window's activation (\a activated is true) or deactivation. */ virtual void updateActions(bool activated); virtual void setFocusInternal() { QWidget::setFocus(); } /*! Allows to react on parent window's detaching. @todo it should be called by KexiWindow::youAreDetached(). Default implementation does nothing. Implement it if you want to perform some appropriate actions. */ virtual void windowDetached() {} /*! Allows to react on parent window's attaching. @todo it should be called by KexiWindow::youAreAttached(). Default implementation does nothing. Implement it if you want to perform some appropriate actions. */ virtual void windowAttached() {} /*! Assigns a list of view-level actions. Used by KexiView ctor. */ void setViewActions(const QList& actions); /*! Assigns a list of main-menu-level actions. Used by KexiView ctor. */ void setMainMenuActions(const QList& actions); /*! @return a list of view-level actions. */ QList viewActions() const; /*! @return view-level action for name @a name or 0 if there is no such action. */ QAction* viewAction(const char* name) const; void initViewActions(); void initMainMenuActions(); void toggleViewModeButtonBack(); //! Sets properties in the Property Editor to be sorted if @a set is true. void setSortedProperties(bool set); private Q_SLOTS: void slotSwitchToViewModeInternal(Kexi::ViewMode mode); - void slotSwitchToDataViewModeInternal(bool); void slotSwitchToDesignViewModeInternal(bool); void slotSwitchToTextViewModeInternal(bool); private: + void createTopBar(); void createViewModeToggleButtons(); class Private; Private * const d; friend class KexiWindow; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KexiView::StoreNewDataOptions) #endif diff --git a/src/core/kexipart.h b/src/core/kexipart.h index b125869fb..8c5e88d09 100644 --- a/src/core/kexipart.h +++ b/src/core/kexipart.h @@ -1,283 +1,284 @@ /* This file is part of the KDE project Copyright (C) 2003 Lucijan Busch Copyright (C) 2003-2014 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KEXIPART_H #define KEXIPART_H #include #include #include #include "kexipartbase.h" #include class KActionCollection; class KexiWindow; class KexiWindowData; class KexiView; class KDbQuerySchema; class QAction; class QKeySequence; namespace KexiPart { class Item; class GUIClient; class StaticPartInfo; /*! Official (registered) type IDs for objects like table, query, form... */ enum ObjectType { UnknownObjectType = KDb::UnknownObjectType, //!< -1, helper AnyObjectType = KDb::AnyObjectType, //!< 0, helper TableObjectType = KDb::TableObjectType, //!< 1, like in KDb::ObjectType QueryObjectType = KDb::QueryObjectType, //!< 2, like in KDb::ObjectType FormObjectType = 3, ReportObjectType = 4, ScriptObjectType = 5, WebObjectType = 6, MacroObjectType = 7, LastObjectType = 7, //ALWAYS UPDATE THIS UserObjectType = 100 //!< external types }; //! @return Kexi Part API version: "major.minor" //! @since 3.1 KEXICORE_EXPORT QString version(); //! @short The main class for kexi frontend parts (plugins) like tables, queries, forms and reports /*! Plugins create windows (KexiWindow) for a given type of object. Notes for plugins implementors: This class supports InternalPropertyMap interface, 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, e.g. "New table" vs "New query" can have different forms for some languages. So this is a flexible way for customizing translatable strings. */ class KEXICORE_EXPORT Part : public PartBase { Q_OBJECT public: virtual ~Part(); //! @todo make it protected, outside world should use KexiProject /*! Try to execute the part. Implementations of this \a Part are able to overwrite this method to offer execution. \param item The \a KexiPart::Item that should be executed. \param sender The sender QObject which likes to execute this \a Part or NULL if there is no sender. The KFormDesigner uses this to pass the actual widget (e.g. the button that was pressed). \return true if execution was successfully else false. */ virtual bool execute(KexiPart::Item* item, QObject* sender = 0) { Q_UNUSED(item); Q_UNUSED(sender); return false; } //! @todo make it protected, outside world should use KexiProject /*! "Opens" an instance that the part provides, pointed by \a item in a mode \a viewMode. \a viewMode is one of Kexi::ViewMode enum. \a staticObjectArgs can be passed for static Kexi Parts. The new widget will be a child of \a parent. */ KexiWindow* openInstance(QWidget* parent, KexiPart::Item *item, Kexi::ViewMode viewMode = Kexi::DataViewMode, QMap* staticObjectArgs = 0); //! @todo make it protected, outside world should use KexiProject /*! Removes any stored data pointed by \a item (example: table is dropped for table part). From now this data is inaccesible, and \a item disappear. You do not need to remove \a item, or remove object's schema stored in the database, beacuse this will be done automatically by KexiProject after successful call of this method. All object's data blocks are also automatically removed from database (from "kexi__objectdata" table). For this, a database connection associated with kexi project owned by \a win can be used. Database transaction is started by KexiProject before calling this method, and it will be rolled back if you return false here. You shouldn't use by hand transactions here. Default implementation just removes object from kexi__* system structures at the database backend using KDbConnection::removeObject(). */ virtual tristate remove(KexiPart::Item *item); /*! Renames stored data pointed by \a item to \a newName (example: table name is altered in the database). For this, a database connection associated with kexi project owned by \a win can be used. You do not need to change \a item, and change object's schema stored in the database, beacuse this is automatically handled by KexiProject. Database transaction is started by KexiProject before calling this method, and it will be rolled back if you return false here. You shouldn't use by hand transactions here. Default implementation does nothing and returns true. */ virtual tristate rename(KexiPart::Item *item, const QString& newName); /*! Creates and returns a new temporary data for a window \a window. This method is called on openInstance() once per dialog. Reimplement this to return KexiWindowData subclass instance. Default implemention just returns empty KexiWindowData object. */ virtual KexiWindowData* createWindowData(KexiWindow *window); /*! Creates a new view for mode \a viewMode, \a item and \a parent. The view will be used inside \a dialog. */ virtual KexiView* createView(QWidget *parent, KexiWindow *window, KexiPart::Item *item, Kexi::ViewMode viewMode = Kexi::DataViewMode, QMap* staticObjectArgs = 0) = 0; //virtual void initTabs(); /*! @return i18n'd instance name usable for displaying in gui as object's name, e.g. "table". The name is valid identifier - contains latin-1 lowercase characters only. */ QString instanceName() const; /*! @return i18n'd tooltip that can also act as descriptive name of the action. Example: "Create new table". */ QString toolTip() const; /*! @return i18n'd "what's this" string. Example: "Creates new table." */ QString whatsThis() const; /*! \return part's GUI Client, so you can create part-wide actions using this client. */ GUIClient *guiClient() const; /*! \return part's GUI Client, so you can create instance-wide actions using this client. */ GUIClient *instanceGuiClient(Kexi::ViewMode mode = Kexi::AllViewModes) const; /*! \return action collection for mode \a viewMode. */ KActionCollection* actionCollectionForMode(Kexi::ViewMode viewMode) const; const Kexi::ObjectStatus& lastOperationStatus() const; /*! \return query schema currently edited in the \a view. * It may be the original/saved query if user has no unsaved changes so far * or a temporary unsaved query if there are unsaved modifications. * The query can be used for example by data exporting routines so user can * export result of a running unsaved query without prior saving it. For implementation in plugins. */ virtual KDbQuerySchema *currentQuery(KexiView* view); /*! @internal Creates GUIClients for this part, attached to the main window. This method is called by KexiMainWindow. */ void createGUIClients(); Q_SIGNALS: void newObjectRequest(KexiPart::Info *info); protected: /*! Creates new Plugin @param parent parent of this plugin @param instanceName i18n'd instance name written using only lowercase alphanumeric characters (a..z, 0..9). Use '_' character instead of spaces. First character should be a..z character. If you cannot use latin characters in your language, use english word. Example: "table". @param toolTip i18n'd tooltip that can also act as descriptive name of the action. Example: "Create new table". @param whatsThis i18n'd "what's this" string. Example: "Creates new table." @param list extra arguments passed to the plugin */ Part(QObject *parent, const QString& instanceName, const QString& toolTip, const QString& whatsThis, const QVariantList& list); //! Used by StaticPart Part(QObject* parent, StaticPartInfo *info); virtual void initPartActions(); virtual void initInstanceActions(); /*! Can be reimplemented if object data is extended behind the default set of properties. This is the case for table and query schema objects, where object of KDbObject subclass is returned. In this case value pointed by @a ownedByWindow is set to false. Default implemenatation owned (value pointed by @a ownedByWindow is set to true). */ virtual KDbObject* loadSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow); bool loadDataBlock(KexiWindow *window, QString *dataString, const QString& dataID = QString()); /*! Creates shared action for action collection declared for 'instance actions' of this part. See KexiSharedActionHost::createSharedAction() for details. Pass desired QAction subclass with \a subclassName (e.g. "KToggleAction") to have that subclass allocated instead just QAction (what is the default). */ QAction * createSharedAction(Kexi::ViewMode mode, const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name, const char *subclassName = 0); /*! Convenience version of above method - creates shared toggle action. */ QAction * createSharedToggleAction(Kexi::ViewMode mode, const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name); /*! Creates shared action for action collection declared for 'part actions' of this part. See KexiSharedActionHost::createSharedAction() for details. Pass desired QAction subclass with \a subclassName (e.g. "KToggleAction") to have that subclass allocated instead just QAction (what is the default). */ QAction * createSharedPartAction(const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name, const char *subclassName = 0); /*! Convenience version of above method - creates shared toggle action for 'part actions' of this part. */ QAction * createSharedPartToggleAction(const QString &text, const QString &pix_name, const QKeySequence &cut, const char *name); void setActionAvailable(const char *action_name, bool avail); private: //! Calls loadSchemaObject() (virtual), updates ownership of object data for @a window //! and assigns the created data to @a window. void loadAndSetSchemaObject(KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode); Q_DISABLE_COPY(Part) class Private; Private * const d; friend class Manager; friend class ::KexiWindow; friend class GUIClient; }; /*! \return full caption for item \a item and part \a part. If \a part is provided, the captions will be in a form of "name : inctancetype", e.g. "Employees : Table", otherwise it will be in a form of "name", e.g. "Employees". */ KEXICORE_EXPORT QString fullCaptionForItem(KexiPart::Item *item, KexiPart::Part *part); } // namespace KexiPart #endif diff --git a/src/plugins/queries/kexiquerypart.cpp b/src/plugins/queries/kexiquerypart.cpp index 738969648..93b84f957 100644 --- a/src/plugins/queries/kexiquerypart.cpp +++ b/src/plugins/queries/kexiquerypart.cpp @@ -1,266 +1,267 @@ /* This file is part of the KDE project Copyright (C) 2004 Lucijan Busch 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 "kexiquerypart.h" #include "kexiqueryview.h" #include "kexiquerydesignerguieditor.h" #include "kexiquerydesignersql.h" #include #include #include #include #include #include #include #include KEXI_PLUGIN_FACTORY(KexiQueryPart, "kexi_queryplugin.json") KexiQueryPart::KexiQueryPart(QObject *parent, const QVariantList &l) : KexiPart::Part(parent, xi18nc("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " "Use '_' character instead of spaces. First character should be a..z character. " "If you cannot use latin characters in your language, use english word.", "query"), xi18nc("tooltip", "Create new query"), xi18nc("what's this", "Creates new query."), l) { - 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() { } KexiWindowData* KexiQueryPart::createWindowData(KexiWindow* window) { KexiQueryPartTempData *data = new KexiQueryPartTempData( window, KexiMainWindowIface::global()->project()->dbConnection()); data->setName(xi18nc("@info Object \"objectname\"", "%1 %2", window->part()->info()->name(), window->partItem()->name())); return data; } KexiView* KexiQueryPart::createView(QWidget *parent, KexiWindow* window, KexiPart::Item *item, Kexi::ViewMode viewMode, QMap*) { Q_ASSERT(item); Q_UNUSED(item); Q_UNUSED(window); //qDebug(); KexiView* view = 0; if (viewMode == Kexi::DataViewMode) { view = new KexiQueryView(parent); view->setObjectName("dataview"); } else if (viewMode == Kexi::DesignViewMode) { view = new KexiQueryDesignerGuiEditor(parent); view->setObjectName("guieditor"); //needed for updating tables combo box: KexiProject *prj = KexiMainWindowIface::global()->project(); connect(prj, SIGNAL(newItemStored(KexiPart::Item*)), view, SLOT(slotNewItemStored(KexiPart::Item*))); connect(prj, SIGNAL(itemRemoved(KexiPart::Item)), view, SLOT(slotItemRemoved(KexiPart::Item))); connect(prj, SIGNAL(itemRenamed(KexiPart::Item,QString)), view, SLOT(slotItemRenamed(KexiPart::Item,QString))); } else if (viewMode == Kexi::TextViewMode) { view = new KexiQueryDesignerSQLView(parent); view->setObjectName("sqldesigner"); } return view; } tristate KexiQueryPart::remove(KexiPart::Item *item) { if (!KexiMainWindowIface::global()->project() || !KexiMainWindowIface::global()->project()->dbConnection()) return false; KDbConnection *conn = KexiMainWindowIface::global()->project()->dbConnection(); KDbQuerySchema *sch = conn->querySchema(item->identifier()); if (sch) return conn->dropQuery(sch); //last chance: just remove item return conn->removeObject(item->identifier()); } void KexiQueryPart::initPartActions() { } void KexiQueryPart::initInstanceActions() { } KDbObject* KexiQueryPart::loadSchemaObject( KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow) { KexiQueryPartTempData * temp = static_cast(window->data()); QString sql; if (!loadDataBlock(window, &sql, "sql")) { return 0; } KDbEscapedString sqlText(sql); KDbParser *parser = KexiMainWindowIface::global()->project()->sqlParser(); KDbQuerySchema *query = 0; if (parser->parse(sqlText)) { query = parser->query(); } //error? if (!query) { if (viewMode == Kexi::TextViewMode) { //for SQL view, no parsing is initially needed: //-just make a copy: return KexiPart::Part::loadSchemaObject(window, object, viewMode, ownedByWindow); } /* Set this to true on data loading loadSchemaObject() to indicate that TextView mode could be used instead of DataView or DesignView, because there are problems with opening object. */ temp->proposeOpeningInTextViewModeBecauseOfProblems = true; //! @todo return 0; } //qDebug() << *query; (KDbObject&)*query = object; //copy main attributes temp->registerTableSchemaChanges(query); if (ownedByWindow) *ownedByWindow = false; //qDebug() << *query; return query; } KDbQuerySchema *KexiQueryPart::currentQuery(KexiView* view) { if (!view) return 0; KexiQueryView *qvp = 0; if (!(qvp = qobject_cast(view))) { return 0; } return static_cast(qvp->window()->data())->query(); } KLocalizedString KexiQueryPart::i18nMessage(const QString& englishMessage, KexiWindow* window) const { if (englishMessage == "Design of object %1 has been modified.") return kxi18nc(I18NC_NOOP("@info", "Design of query %1 has been modified.")); if (englishMessage == "Object %1 already exists.") return kxi18nc(I18NC_NOOP("@info", "Query %1 already exists.")); return Part::i18nMessage(englishMessage, window); } tristate KexiQueryPart::rename(KexiPart::Item *item, const QString& newName) { Q_ASSERT(item); Q_UNUSED(newName); if (!KexiMainWindowIface::global()->project()->dbConnection()) return false; KexiMainWindowIface::global()->project()->dbConnection() ->setQuerySchemaObsolete(item->name()); return true; } //---------------- KexiQueryPartTempData::KexiQueryPartTempData(KexiWindow* window, KDbConnection *conn) : KexiWindowData(window) , KDbTableSchemaChangeListener() , m_query(0) , m_queryChangedInView(Kexi::NoViewMode) { this->conn = conn; } KexiQueryPartTempData::~KexiQueryPartTempData() { KDbTableSchemaChangeListener::unregisterForChanges(conn, this); } void KexiQueryPartTempData::clearQuery() { if (!m_query) return; unregisterForTablesSchemaChanges(); m_query->clear(); } void KexiQueryPartTempData::unregisterForTablesSchemaChanges() { KDbTableSchemaChangeListener::unregisterForChanges(conn, this); } void KexiQueryPartTempData::registerTableSchemaChanges(KDbQuerySchema *q) { if (!q) return; foreach(const KDbTableSchema* table, *q->tables()) { KDbTableSchemaChangeListener::registerForChanges(conn, this, table); } } tristate KexiQueryPartTempData::closeListener() { KexiWindow* window = static_cast(parent()); return KexiMainWindowIface::global()->closeWindow(window); } KDbQuerySchema *KexiQueryPartTempData::takeQuery() { KDbQuerySchema *query = m_query; m_query = 0; return query; } void KexiQueryPartTempData::setQuery(KDbQuerySchema *query) { if (m_query && m_query == query) return; if (m_query /* query not owned by window */ && (static_cast(parent())->schemaObject() != static_cast(m_query))) { delete m_query; } m_query = query; } Kexi::ViewMode KexiQueryPartTempData::queryChangedInView() const { return m_queryChangedInView; } void KexiQueryPartTempData::setQueryChangedInView(bool set) { m_queryChangedInView = set ? qobject_cast(parent())->currentViewMode() : Kexi::NoViewMode; } #include "kexiquerypart.moc"