diff --git a/src/core/KexiWindow.cpp b/src/core/KexiWindow.cpp --- a/src/core/KexiWindow.cpp +++ b/src/core/KexiWindow.cpp @@ -538,12 +538,17 @@ if (prevViewMode == Kexi::NoViewMode) d->newlySelectedView->setDirty(false); - wasDirty = newView->isDirty(); // remember and restore the flag if the view was clean + if ((prevViewMode == Kexi::DesignViewMode && d->currentViewMode == Kexi::TextViewMode) + || (prevViewMode == Kexi::TextViewMode && d->currentViewMode == Kexi::DesignViewMode)) { + wasDirty = view->isDirty(); // synchronize the dirty flag between Design and Text views + } else { + wasDirty = newView->isDirty(); // remember and restore the flag if the view was clean + } + res = newView->afterSwitchFrom( designModePreloadedForTextModeHack ? Kexi::NoViewMode : prevViewMode); - if (!wasDirty) { - newView->setDirty(false); - } + newView->setDirty(wasDirty); + *proposeOpeningInTextViewModeBecauseOfProblems = data()->proposeOpeningInTextViewModeBecauseOfProblems; if (!res) { diff --git a/src/core/kexipart.h b/src/core/kexipart.h --- a/src/core/kexipart.h +++ b/src/core/kexipart.h @@ -217,13 +217,13 @@ 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); + /*! Can be reimplemented if object data is extended beyond 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 returns + owned KDbObject object (value pointed by @a ownedByWindow is set to true). + @a ownedByWindow is required. */ + virtual KDbObject *loadSchemaObject(KexiWindow *window, const KDbObject &object, + Kexi::ViewMode viewMode, bool *ownedByWindow) Q_REQUIRED_RESULT; bool loadDataBlock(KexiWindow *window, QString *dataString, const QString& dataID = QString()); diff --git a/src/core/kexipart.cpp b/src/core/kexipart.cpp --- a/src/core/kexipart.cpp +++ b/src/core/kexipart.cpp @@ -335,10 +335,10 @@ { Q_UNUSED(window); Q_UNUSED(viewMode); + Q_ASSERT(ownedByWindow); KDbObject *newObject = new KDbObject(); *newObject = object; - if (ownedByWindow) - *ownedByWindow = true; + *ownedByWindow = true; return newObject; } diff --git a/src/plugins/queries/kexiquerydesignersql.cpp b/src/plugins/queries/kexiquerydesignersql.cpp --- a/src/plugins/queries/kexiquerydesignersql.cpp +++ b/src/plugins/queries/kexiquerydesignersql.cpp @@ -65,6 +65,9 @@ , justSwitchedFromNoViewMode(false) , slotTextChangedEnabled(true) { } + ~Private() { + delete parsedQuery; + } KexiQueryDesignerSqlEditor *editor; QLabel *pixmapStatus, *lblStatus; QHBoxLayout *statusHLyr; @@ -75,6 +78,7 @@ QSplitter *splitter; //! For internal use, this pointer is usually copied to TempData structure, //! when switching out of this view (then it's cleared). + //! If it's still present at destruction of Private then it's deleted. KDbQuerySchema *parsedQuery; //! For internal use, statement passed in switching to this view KDbEscapedString origStatement; @@ -251,7 +255,9 @@ //replace old query schema with new one temp->setQuery(d->parsedQuery); //this will also delete temp->query() d->parsedQuery = 0; - temp->setQueryChangedInView(true); + if (!compareSql(d->origStatement.toString(), d->editor->text())) { + temp->setQueryChangedInView(true); + } } } d->origStatement = KDbEscapedString(d->editor->text()); 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 @@ -129,6 +129,8 @@ KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow) { + Q_ASSERT(ownedByWindow); + *ownedByWindow = false; KexiQueryPartTempData * temp = static_cast(window->data()); QString sql; if (!loadDataBlock(window, &sql, "sql")) { @@ -159,8 +161,7 @@ (KDbObject&)*query = object; //copy main attributes temp->registerTableSchemaChanges(query); - if (ownedByWindow) - *ownedByWindow = false; + *ownedByWindow = true; // owned because it is created by the parser qDebug() << KDbConnectionAndQuerySchema( KexiMainWindowIface::global()->project()->dbConnection(), *query); @@ -316,10 +317,15 @@ { if (m_query && m_query == query) return; + KexiWindow* window = static_cast(parent()); if (m_query /* query not owned by window */ && (static_cast(parent())->schemaObject() != static_cast(m_query))) { + KexiQueryView* dataView = qobject_cast(window->viewForMode(Kexi::DataViewMode)); + if (dataView && dataView->query() == m_query) { + dataView->setQuery(nullptr); // unassign before deleting + } delete m_query; } m_query = query; diff --git a/src/plugins/queries/kexiqueryview.h b/src/plugins/queries/kexiqueryview.h --- a/src/plugins/queries/kexiqueryview.h +++ b/src/plugins/queries/kexiqueryview.h @@ -45,11 +45,29 @@ virtual tristate storeData(bool dontAsk = false); - /*! Executes query \a query, filling the table view with query results. - \return true on success, false on failure and cancelled when user has - cancelled execution (for example when she pressed the Cancel button - of the "Enter Query Parameter" input dialog. */ - tristate executeQuery(KDbQuerySchema *query); + /** + * Assigns query @a query to this view + * + * - executes it + * - fills the table view with results + * + * @return @c true on success, @c false on failure and @c cancelled when user has cancelled + * execution, for example when she pressed the Cancel button in the "Enter Query Parameter" + * input dialog. + * + * In successful execution of the query of if @a query is @c nullptr previous query (if any) + * is unassigned and data is removed. + */ + tristate setQuery(KDbQuerySchema *query); + + /** + * @brief Query that was assigned to this view + * + * @note It is not owned. + */ + KDbQuerySchema *query(); + + friend class KexiQueryPartTempData; class Private; Private * const d; 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 @@ -44,6 +44,7 @@ currentParams() {} ~Private() {} + KDbQuerySchema* query = nullptr; KDbCursor *cursor; QList currentParams; /*! Used in storeNewData(), storeData() to decide whether @@ -73,59 +74,72 @@ delete d; } -tristate KexiQueryView::executeQuery(KDbQuerySchema *query) +tristate KexiQueryView::setQuery(KDbQuerySchema *query) { - if (!query) - return false; - KexiUtils::WaitCursor wait; - KDbCursor *oldCursor = d->cursor; - KDbConnection * conn = KexiMainWindowIface::global()->project()->dbConnection(); - qDebug() << query->parameters(conn); - bool ok; - { - KexiUtils::WaitCursorRemover remover; - d->currentParams = KexiQueryParameters::getParameters(this, conn, query, &ok); + if (d->query == query) { + return true; } - if (!ok) {//input cancelled - return cancelled; + KDbCursor* newCursor; + if (query) { + KexiUtils::WaitCursor wait; + KDbConnection * conn = KexiMainWindowIface::global()->project()->dbConnection(); + qDebug() << query->parameters(conn); + bool ok; + { + KexiUtils::WaitCursorRemover remover; + d->currentParams = KexiQueryParameters::getParameters(this, conn, query, &ok); + } + if (!ok) {//input cancelled + return cancelled; + } + newCursor = conn->executeQuery(query, d->currentParams); + if (!newCursor) { + window()->setStatus(conn, xi18n("Query executing failed.")); + //! @todo also provide server result and sql statement + return false; + } + } else { + newCursor = nullptr; } - d->cursor = conn->executeQuery(query, d->currentParams); - if (!d->cursor) { - window()->setStatus( - conn, - xi18n("Query executing failed.")); -//! @todo also provide server result and sql statement - return false; + + if (d->cursor) { + d->cursor->connection()->deleteCursor(d->cursor); } + d->cursor = newCursor; + d->query = query; setData(d->cursor); //! @todo remove close() when dynamic cursors arrive - if (!d->cursor->close()) { + if (d->cursor && !d->cursor->close()) { return false; } - if (oldCursor) - oldCursor->connection()->deleteCursor(oldCursor); - //! @todo maybe allow writing and inserting for single-table relations? tableView()->setReadOnly(true); //! @todo maybe allow writing and inserting for single-table relations? //set data model itself read-only too - tableView()->data()->setReadOnly(true); + if (tableView()->data()) { + tableView()->data()->setReadOnly(true); + } tableView()->setInsertingEnabled(false); return true; } +KDbQuerySchema* KexiQueryView::query() +{ + return d->query; +} + tristate KexiQueryView::afterSwitchFrom(Kexi::ViewMode mode) { if (mode == Kexi::NoViewMode) { KDbQuerySchema *querySchema = static_cast(window()->schemaObject()); - const tristate result = executeQuery(querySchema); + const tristate result = setQuery(querySchema); if (true != result) return result; } else if (mode == Kexi::DesignViewMode || mode == Kexi::TextViewMode) { KexiQueryPartTempData * temp = static_cast(window()->data()); - const tristate result = executeQuery(temp->query()); + const tristate result = setQuery(temp->query()); if (true != result) return result; } 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 @@ -129,6 +129,7 @@ KexiWindow *window, const KDbObject& object, Kexi::ViewMode viewMode, bool *ownedByWindow) { + Q_ASSERT(ownedByWindow); QString layout; if ( !loadDataBlock(window, &layout, "layout") == true && !loadDataBlock(window, &layout, "pgzreport_layout") == true /* compat */) 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 @@ -169,8 +169,8 @@ { Q_UNUSED(window); Q_UNUSED(viewMode); - if (ownedByWindow) - *ownedByWindow = false; + Q_ASSERT(ownedByWindow); + *ownedByWindow = false; return KexiMainWindowIface::global()->project()->dbConnection()->tableSchema(object.name()); }