File indexing completed on 2024-05-12 16:39:42
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003 Lucijan Busch <lucijan@kde.org> 0003 Copyright (C) 2003-2015 Jarosław Staniek <staniek@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "KexiWindow.h" 0022 #include "KexiWindowData.h" 0023 #include "KexiView.h" 0024 #include "KexiMainWindowIface.h" 0025 #include "kexipart.h" 0026 //! @todo KEXI3 #include "kexistaticpart.h" 0027 #include "kexipartitem.h" 0028 #include "kexipartinfo.h" 0029 #include "kexiproject.h" 0030 #include <kexiutils/utils.h> 0031 #include <kexiutils/SmallToolButton.h> 0032 #include <kexiutils/FlowLayout.h> 0033 0034 #include <KDbConnection> 0035 #include <KDbTransactionGuard> 0036 0037 #include <KStandardGuiItem> 0038 #include <KMessageBox> 0039 0040 #include <QStackedWidget> 0041 #include <QEvent> 0042 #include <QCloseEvent> 0043 #include <QDebug> 0044 0045 //---------------------------------------------------------- 0046 0047 //! @internal 0048 class Q_DECL_HIDDEN KexiWindow::Private 0049 { 0050 public: 0051 explicit Private(KexiWindow *window) 0052 : win(window) 0053 , schemaObject(0) 0054 , schemaObjectOwned(false) 0055 , isRegistered(false) 0056 , dirtyChangedEnabled(true) 0057 , switchToViewModeEnabled(true) 0058 { 0059 supportedViewModes = Kexi::NoViewMode; //will be set by KexiPart 0060 openedViewModes = Kexi::NoViewMode; 0061 currentViewMode = Kexi::NoViewMode; //no view available yet 0062 creatingViewsMode = Kexi::NoViewMode; 0063 id = -1; 0064 item = 0; 0065 } 0066 0067 ~Private() { 0068 setSchemaObject(0); 0069 } 0070 0071 void setSchemaObject(KDbObject* data) 0072 { 0073 if (schemaObjectOwned) { 0074 delete schemaObject; 0075 } 0076 schemaObject = data; 0077 } 0078 0079 bool setupSchemaObject(KDbObject *object, KexiPart::Item *item, 0080 KexiView::StoreNewDataOptions options) const 0081 { 0082 object->setName(item->name()); 0083 object->setCaption(item->caption()); 0084 object->setDescription(item->description()); 0085 0086 KexiProject *project = KexiMainWindowIface::global()->project(); 0087 KexiPart::Item* existingItem = project->item(part->info(), object->name()); 0088 if (existingItem && !(options & KexiView::OverwriteExistingData)) { 0089 KMessageBox::information(win, 0090 xi18n("Could not create new object.") 0091 + win->part()->i18nMessage("Object <resource>%1</resource> already exists.", win) 0092 .subs(object->name()).toString()); 0093 return false; 0094 } 0095 return true; 0096 } 0097 0098 KexiWindow *win; 0099 QVBoxLayout* mainLyr; 0100 QStackedWidget* stack; 0101 0102 Kexi::ViewModes supportedViewModes; 0103 Kexi::ViewModes openedViewModes; 0104 Kexi::ViewMode currentViewMode; 0105 0106 #ifdef KEXI_SHOW_CONTEXT_HELP 0107 KexiContextHelpInfo *contextHelpInfo; 0108 #endif 0109 int id; 0110 QPointer<KexiPart::Part> part; 0111 KexiPart::Item *item; 0112 KDbObject* schemaObject; 0113 bool schemaObjectOwned; 0114 QPointer<KexiView> newlySelectedView; //!< Used in isDirty(), temporary set in switchToViewMode() 0115 //!< during view setup, when a new view is not yet raised. 0116 //! Used in viewThatRecentlySetDirtyFlag(), modified in dirtyChanged(). 0117 QPointer<KexiView> viewThatRecentlySetDirtyFlag; 0118 QPointer<KexiWindowData> data; //!< temporary data shared between views 0119 0120 /*! Created view's mode - helper for switchToViewMode(), 0121 KexiView ctor uses that info. >0 values are useful. */ 0122 Kexi::ViewMode creatingViewsMode; 0123 0124 bool isRegistered; 0125 bool dirtyChangedEnabled; //!< used in setDirty(), affects dirtyChanged() 0126 bool switchToViewModeEnabled; //!< used internally switchToViewMode() to avoid infinite loop 0127 QMap<Kexi::ViewMode, KexiView*> views; 0128 }; 0129 0130 //---------------------------------------------------------- 0131 0132 KexiWindow::KexiWindow(QWidget *parent, Kexi::ViewModes supportedViewModes, 0133 KexiPart::Part *part, KexiPart::Item *item) 0134 : QWidget(parent) 0135 , KexiActionProxy(this, KexiMainWindowIface::global()) 0136 , d(new Private(this)) 0137 , m_destroying(false) 0138 { 0139 d->part = part; 0140 d->item = item; 0141 d->supportedViewModes = supportedViewModes; 0142 createSubwidgets(); 0143 #ifdef KEXI_SHOW_CONTEXT_HELP 0144 d->contextHelpInfo = new KexiContextHelpInfo(); 0145 #endif 0146 updateCaption(); 0147 } 0148 0149 KexiWindow::KexiWindow() 0150 : QWidget(0) 0151 , KexiActionProxy(this, KexiMainWindowIface::global()) 0152 , d(new Private(this)) 0153 , m_destroying(false) 0154 { 0155 createSubwidgets(); 0156 #ifdef KEXI_SHOW_CONTEXT_HELP 0157 d->contextHelpInfo = new KexiContextHelpInfo(); 0158 #endif 0159 updateCaption(); 0160 } 0161 0162 KexiWindow::~KexiWindow() 0163 { 0164 close(true /*force*/); 0165 m_destroying = true; 0166 delete d; 0167 d = 0; 0168 } 0169 0170 void KexiWindow::createSubwidgets() 0171 { 0172 d->mainLyr = new QVBoxLayout(this); 0173 d->mainLyr->setContentsMargins(0, KexiUtils::marginHint() / 2, 0, 0); 0174 d->stack = new QStackedWidget(this); 0175 d->mainLyr->addWidget(d->stack); 0176 } 0177 0178 KexiView *KexiWindow::selectedView() const 0179 { 0180 if (m_destroying) 0181 return 0; 0182 return static_cast<KexiView*>(d->stack->currentWidget()); 0183 } 0184 0185 KexiView *KexiWindow::viewForMode(Kexi::ViewMode mode) const 0186 { 0187 return d->views.value(mode); 0188 } 0189 0190 void KexiWindow::addView(KexiView *view) 0191 { 0192 addView(view, Kexi::NoViewMode); 0193 } 0194 0195 void KexiWindow::addView(KexiView *view, Kexi::ViewMode mode) 0196 { 0197 d->stack->addWidget(view); 0198 d->views.insert(mode, view); 0199 d->openedViewModes |= mode; 0200 } 0201 0202 void KexiWindow::removeView(Kexi::ViewMode mode) 0203 { 0204 removeView(viewForMode(mode)); 0205 d->openedViewModes |= mode; 0206 d->openedViewModes ^= mode; 0207 } 0208 0209 void KexiWindow::removeView(KexiView *view) 0210 { 0211 if (view) { 0212 d->stack->removeWidget(view); 0213 d->views.remove(view->viewMode()); 0214 d->openedViewModes |= view->viewMode(); 0215 d->openedViewModes ^= view->viewMode(); 0216 } 0217 } 0218 0219 QSize KexiWindow::minimumSizeHint() const 0220 { 0221 KexiView *v = selectedView(); 0222 if (!v) 0223 return QWidget::minimumSizeHint(); 0224 return v->minimumSizeHint(); 0225 } 0226 0227 QSize KexiWindow::sizeHint() const 0228 { 0229 KexiView *v = selectedView(); 0230 if (!v) 0231 return QWidget::sizeHint(); 0232 return v->preferredSizeHint(v->sizeHint()); 0233 } 0234 0235 void KexiWindow::setId(int id) 0236 { 0237 d->id = id; 0238 } 0239 0240 KexiPart::Part* KexiWindow::part() const 0241 { 0242 return d->part; 0243 } 0244 0245 KexiPart::Item *KexiWindow::partItem() const 0246 { 0247 return d->item; 0248 } 0249 0250 bool KexiWindow::supportsViewMode(Kexi::ViewMode mode) const 0251 { 0252 return d->supportedViewModes & mode; 0253 } 0254 0255 Kexi::ViewModes KexiWindow::supportedViewModes() const 0256 { 0257 return d->supportedViewModes; 0258 } 0259 0260 Kexi::ViewMode KexiWindow::currentViewMode() const 0261 { 0262 return d->currentViewMode; 0263 } 0264 0265 KexiView* KexiWindow::viewThatRecentlySetDirtyFlag() const 0266 { 0267 return d->viewThatRecentlySetDirtyFlag; 0268 } 0269 0270 void KexiWindow::registerWindow() 0271 { 0272 if (d->isRegistered) 0273 return; 0274 KexiMainWindowIface::global()->registerChild(this); 0275 d->isRegistered = true; 0276 } 0277 0278 bool KexiWindow::isRegistered() const 0279 { 0280 return d->isRegistered; 0281 } 0282 0283 int KexiWindow::id() const 0284 { 0285 return (partItem() && partItem()->identifier() > 0) 0286 ? partItem()->identifier() : d->id; 0287 } 0288 0289 void KexiWindow::setContextHelp(const QString& caption, 0290 const QString& text, const QString& iconName) 0291 { 0292 #ifdef KEXI_SHOW_CONTEXT_HELP 0293 d->contextHelpInfo->caption = caption; 0294 d->contextHelpInfo->text = text; 0295 d->contextHelpInfo->text = iconName; 0296 updateContextHelp(); 0297 #else 0298 Q_UNUSED(caption); 0299 Q_UNUSED(text); 0300 Q_UNUSED(iconName); 0301 #endif 0302 } 0303 0304 bool KexiWindow::close(bool force) 0305 { 0306 KexiMainWindowIface::global()->acceptPropertySetEditing(); 0307 0308 //let any view send "closing" signal 0309 QList<KexiView *> list(findChildren<KexiView*>()); 0310 QList< QPointer<KexiView> > listPtr; 0311 foreach(KexiView * view, list) { // use QPointers for sanity 0312 listPtr.append(QPointer<KexiView>(view)); 0313 } 0314 foreach(QPointer<KexiView> viewPtr, listPtr) { 0315 if (viewPtr && viewPtr->parent() == d->stack) { 0316 bool cancel = false; 0317 emit viewPtr->closing(&cancel); 0318 if (!force && cancel) { 0319 return false; 0320 } 0321 } 0322 } 0323 emit closing(); 0324 foreach(QPointer<KexiView> viewPtr, listPtr) { 0325 if (viewPtr && viewPtr->parent() == d->stack) { 0326 removeView(viewPtr.data()); 0327 delete viewPtr.data(); 0328 } 0329 } 0330 return true; 0331 } 0332 0333 void KexiWindow::closeEvent(QCloseEvent * e) 0334 { 0335 if (!close(false /* !force*/)) { 0336 e->ignore(); 0337 return; 0338 } 0339 QWidget::closeEvent(e); 0340 } 0341 0342 bool KexiWindow::isDirty() const 0343 { 0344 //look for "dirty" flag 0345 int m = d->openedViewModes; 0346 int mode = 1; 0347 while (m > 0) { 0348 if (m & 1) { 0349 KexiView *view = viewForMode(static_cast<Kexi::ViewMode>(mode)); 0350 if (view && view->isDirty()) { 0351 return true; 0352 } 0353 } 0354 m >>= 1; 0355 mode <<= 1; 0356 } 0357 return false; 0358 } 0359 0360 void KexiWindow::setDirty(bool dirty) 0361 { 0362 d->dirtyChangedEnabled = false; 0363 int m = d->openedViewModes; 0364 int mode = 1; 0365 while (m > 0) { 0366 if (m & 1) { 0367 KexiView *view = viewForMode(static_cast<Kexi::ViewMode>(mode)); 0368 if (view) { 0369 view->setDirty(dirty); 0370 } 0371 } 0372 m >>= 1; 0373 mode <<= 1; 0374 } 0375 d->dirtyChangedEnabled = true; 0376 dirtyChanged(d->viewThatRecentlySetDirtyFlag); //update 0377 } 0378 0379 QString KexiWindow::iconName() 0380 { 0381 if (!d->part || !d->part->info()) { 0382 KexiView *v = selectedView(); 0383 if (v) { 0384 return v->defaultIconName(); 0385 } 0386 return QString(); 0387 } 0388 return d->part->info()->iconName(); 0389 } 0390 0391 KexiPart::GUIClient* KexiWindow::guiClient() const 0392 { 0393 if (!d->part || d->currentViewMode == 0) 0394 return 0; 0395 return d->part->instanceGuiClient(d->currentViewMode); 0396 } 0397 0398 KexiPart::GUIClient* KexiWindow::commonGUIClient() const 0399 { 0400 if (!d->part) 0401 return 0; 0402 return d->part->instanceGuiClient(Kexi::AllViewModes); 0403 } 0404 0405 bool KexiWindow::isDesignModePreloadedForTextModeHackUsed(Kexi::ViewMode newViewMode) const 0406 { 0407 return newViewMode == Kexi::TextViewMode 0408 && !viewForMode(Kexi::DesignViewMode) 0409 && supportsViewMode(Kexi::DesignViewMode); 0410 } 0411 0412 tristate KexiWindow::switchToViewMode( 0413 Kexi::ViewMode newViewMode, 0414 QMap<QString, QVariant>* staticObjectArgs, 0415 bool *proposeOpeningInTextViewModeBecauseOfProblems) 0416 { 0417 Q_ASSERT(proposeOpeningInTextViewModeBecauseOfProblems); 0418 clearStatus(); 0419 KexiMainWindowIface::global()->acceptPropertySetEditing(); 0420 0421 const bool designModePreloadedForTextModeHack = isDesignModePreloadedForTextModeHackUsed(newViewMode); 0422 tristate res = true; 0423 if (designModePreloadedForTextModeHack) { 0424 /* A HACK: open design BEFORE text mode: otherwise Query schema becames crazy */ 0425 bool _proposeOpeningInTextViewModeBecauseOfProblems = false; // used because even if opening the view failed, 0426 // text view can be opened 0427 res = switchToViewMode(Kexi::DesignViewMode, staticObjectArgs, &_proposeOpeningInTextViewModeBecauseOfProblems); 0428 if ((!res && !_proposeOpeningInTextViewModeBecauseOfProblems) || ~res) 0429 return res; 0430 } 0431 0432 bool dontStore = false; 0433 KexiView *view = selectedView(); 0434 0435 if (d->currentViewMode == newViewMode) 0436 return true; 0437 if (!supportsViewMode(newViewMode)) { 0438 qWarning() << "!" << Kexi::nameForViewMode(newViewMode); 0439 return false; 0440 } 0441 0442 if (view) { 0443 res = true; 0444 if (view->isDataEditingInProgress()) { 0445 KGuiItem saveItem(KStandardGuiItem::save()); 0446 saveItem.setText(xi18n("Save Changes")); 0447 KGuiItem dontSaveItem(KStandardGuiItem::dontSave()); 0448 KGuiItem cancelItem(KStandardGuiItem::cancel()); 0449 cancelItem.setText(xi18n("Do Not Switch")); 0450 const int res = KMessageBox::questionYesNoCancel( 0451 selectedView(), 0452 xi18n("<para>There are unsaved changes in object <resource>%1</resource>.</para>" 0453 "<para>Do you want to save these changes before switching to other view?</para>", 0454 partItem()->captionOrName()), 0455 xi18n("Confirm Saving Changes"), 0456 saveItem, dontSaveItem, cancelItem, QString(), 0457 KMessageBox::Notify | KMessageBox::Dangerous 0458 ); 0459 if (res == KMessageBox::Yes) { 0460 if (true != view->saveDataChanges()) 0461 return cancelled; 0462 } 0463 else if (res == KMessageBox::No) { 0464 if (true != view->cancelDataChanges()) 0465 return cancelled; 0466 } 0467 else { // Cancel: 0468 return cancelled; 0469 } 0470 } 0471 if (!designModePreloadedForTextModeHack) { 0472 const bool wasDirty = view->isDirty(); // remember and restore the flag if the view was clean 0473 res = view->beforeSwitchTo(newViewMode, &dontStore); 0474 if (!wasDirty) { 0475 view->setDirty(false); 0476 } 0477 } 0478 if (~res || !res) 0479 return res; 0480 if (!dontStore && view->isDirty()) { 0481 res = KexiMainWindowIface::global()->saveObject(this, xi18n("Design has been changed. " 0482 "You must save it before switching to other view.")); 0483 if (~res || !res) 0484 return res; 0485 // KMessageBox::questionYesNo(0, xi18n("Design has been changed. You must save it before switching to other view.")) 0486 // ==KMessageBox::No 0487 } 0488 } 0489 0490 //get view for viewMode 0491 KexiView *newView = viewForMode(newViewMode); 0492 if (newView && !newView->inherits("KexiView")) { 0493 newView = 0; 0494 } 0495 if (!newView) { 0496 KexiUtils::setWaitCursor(); 0497 //ask the part to create view for the new mode 0498 d->creatingViewsMode = newViewMode; 0499 /*! @todo KEXI3 StaticPart 0500 KexiPart::StaticPart *staticPart = dynamic_cast<KexiPart::StaticPart*>((KexiPart::Part*)d->part); 0501 if (staticPart) 0502 newView = staticPart->createView(this, this, d->item, newViewMode, staticObjectArgs); 0503 else*/ 0504 newView = d->part->createView(this, this, d->item, newViewMode, staticObjectArgs); 0505 KexiUtils::removeWaitCursor(); 0506 if (!newView) { 0507 //js TODO error? 0508 qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " 0509 << d->currentViewMode << " restored."; 0510 return false; 0511 } 0512 d->creatingViewsMode = Kexi::NoViewMode; 0513 newView->initViewActions(); 0514 newView->initMainMenuActions(); 0515 addView(newView, newViewMode); 0516 } 0517 const Kexi::ViewMode prevViewMode = d->currentViewMode; 0518 res = true; 0519 if (designModePreloadedForTextModeHack) { 0520 d->currentViewMode = Kexi::NoViewMode; //SAFE? 0521 } 0522 bool wasDirty = newView->isDirty(); // remember and restore the flag if the view was clean 0523 res = newView->beforeSwitchTo(newViewMode, &dontStore); 0524 if (!wasDirty) { 0525 newView->setDirty(false); 0526 } 0527 *proposeOpeningInTextViewModeBecauseOfProblems 0528 = data()->proposeOpeningInTextViewModeBecauseOfProblems; 0529 if (!res) { 0530 removeView(newViewMode); 0531 delete newView; 0532 qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " 0533 << d->currentViewMode << " restored."; 0534 return false; 0535 } 0536 d->currentViewMode = newViewMode; 0537 d->newlySelectedView = newView; 0538 if (prevViewMode == Kexi::NoViewMode) 0539 d->newlySelectedView->setDirty(false); 0540 0541 if ((prevViewMode == Kexi::DesignViewMode && d->currentViewMode == Kexi::TextViewMode) 0542 || (prevViewMode == Kexi::TextViewMode && d->currentViewMode == Kexi::DesignViewMode)) { 0543 if (view) { 0544 wasDirty = view->isDirty(); // synchronize the dirty flag between Design and Text views 0545 } 0546 } else { 0547 wasDirty = newView->isDirty(); // remember and restore the flag if the view was clean 0548 } 0549 0550 res = newView->afterSwitchFrom( 0551 designModePreloadedForTextModeHack ? Kexi::NoViewMode : prevViewMode); 0552 newView->setDirty(wasDirty); 0553 0554 *proposeOpeningInTextViewModeBecauseOfProblems 0555 = data()->proposeOpeningInTextViewModeBecauseOfProblems; 0556 if (!res) { 0557 removeView(newViewMode); 0558 delete newView; 0559 qWarning() << "Switching to mode " << newViewMode << " failed. Previous mode " 0560 << prevViewMode << " restored."; 0561 const Kexi::ObjectStatus status(*this); 0562 setStatus(KexiMainWindowIface::global()->project()->dbConnection(), 0563 xi18n("Switching to other view failed (%1).", Kexi::nameForViewMode(newViewMode)), ""); 0564 append(status); 0565 d->currentViewMode = prevViewMode; 0566 return false; 0567 } 0568 d->newlySelectedView = 0; 0569 if (~res) { 0570 d->currentViewMode = prevViewMode; 0571 return cancelled; 0572 } 0573 if (view) { 0574 takeActionProxyChild(view); //take current proxy child 0575 // views have distinct local toolbars, and user has switched the mode button so switch it back 0576 //view->toggleViewModeButtonBack(); 0577 } 0578 addActionProxyChild(newView); //new proxy child 0579 d->stack->setCurrentWidget(newView); 0580 newView->propertySetSwitched(); 0581 KexiMainWindowIface::global()->invalidateSharedActions(newView); 0582 newView->setFocus(); 0583 return true; 0584 } 0585 0586 tristate KexiWindow::switchToViewModeInternal(Kexi::ViewMode newViewMode) 0587 { 0588 return KexiMainWindowIface::global()->switchToViewMode(*this, newViewMode); 0589 } 0590 0591 tristate KexiWindow::switchToViewMode(Kexi::ViewMode newViewMode) 0592 { 0593 if (newViewMode == d->currentViewMode) 0594 return true; 0595 if (!d->switchToViewModeEnabled) 0596 return false; 0597 bool dummy; 0598 return switchToViewMode(newViewMode, 0, &dummy); 0599 } 0600 0601 void KexiWindow::setFocus() 0602 { 0603 if (d->stack->currentWidget()) { 0604 if (d->stack->currentWidget()->inherits("KexiView")) 0605 static_cast<KexiView*>(d->stack->currentWidget())->setFocus(); 0606 else 0607 d->stack->currentWidget()->setFocus(); 0608 } else { 0609 QWidget::setFocus(); 0610 } 0611 activate(); 0612 } 0613 0614 KPropertySet* 0615 KexiWindow::propertySet() 0616 { 0617 KexiView *v = selectedView(); 0618 if (!v) 0619 return 0; 0620 return v->propertySet(); 0621 } 0622 0623 void KexiWindow::setSchemaObject(KDbObject* object) 0624 { 0625 d->setSchemaObject(object); 0626 } 0627 0628 KDbObject* KexiWindow::schemaObject() const 0629 { 0630 return d->schemaObject; 0631 } 0632 0633 void KexiWindow::setSchemaObjectOwned(bool set) 0634 { 0635 d->schemaObjectOwned = set; 0636 } 0637 0638 KexiWindowData *KexiWindow::data() const 0639 { 0640 return d->data; 0641 } 0642 0643 void KexiWindow::setData(KexiWindowData* data) 0644 { 0645 if (data != d->data) 0646 delete d->data; 0647 d->data = data; 0648 } 0649 0650 bool KexiWindow::eventFilter(QObject *obj, QEvent *e) 0651 { 0652 if (QWidget::eventFilter(obj, e)) 0653 return true; 0654 /*if (e->type()==QEvent::FocusIn) { 0655 QWidget *w = m_parentWindow->activeWindow(); 0656 w=0; 0657 }*/ 0658 if ((e->type() == QEvent::FocusIn && KexiMainWindowIface::global()->currentWindow() == this) 0659 || e->type() == QEvent::MouseButtonPress) { 0660 if (d->stack->currentWidget() && KDbUtils::hasParent(d->stack->currentWidget(), obj)) { 0661 //pass the activation 0662 activate(); 0663 } 0664 } 0665 return false; 0666 } 0667 0668 void KexiWindow::dirtyChanged(KexiView* view) 0669 { 0670 if (!d->dirtyChangedEnabled) 0671 return; 0672 d->viewThatRecentlySetDirtyFlag = isDirty() ? view : 0; 0673 updateCaption(); 0674 emit dirtyChanged(this); 0675 } 0676 0677 //static 0678 QString KexiWindow::windowTitleForItem(const KexiPart::Item &item) 0679 { 0680 return item.name(); 0681 } 0682 0683 void KexiWindow::updateCaption() 0684 { 0685 if (!d->item || !d->part) 0686 return; 0687 const QString fullCapt(windowTitleForItem(*d->item)); 0688 setWindowTitle(isDirty() ? xi18nc("@title:window with dirty indicator", "%1*", fullCapt) 0689 : fullCapt); 0690 } 0691 0692 bool KexiWindow::neverSaved() const 0693 { 0694 return d->item ? d->item->neverSaved() : true; 0695 } 0696 0697 tristate KexiWindow::storeNewData(KexiView::StoreNewDataOptions options) 0698 { 0699 if (!neverSaved()) { 0700 return false; 0701 } 0702 if (d->schemaObject) { 0703 return false; //schema must not exist 0704 } 0705 KexiView *v = selectedView(); 0706 if (!v) { 0707 return false; 0708 } 0709 //create schema object and assign information 0710 KexiProject *project = KexiMainWindowIface::global()->project(); 0711 KDbObject object(project->typeIdForPluginId(d->part->info()->pluginId())); 0712 if (!d->setupSchemaObject(&object, d->item, options)) { 0713 return false; 0714 } 0715 0716 bool cancel = false; 0717 d->schemaObject = v->storeNewData(object, options, &cancel); 0718 if (cancel) 0719 return cancelled; 0720 if (!d->schemaObject) { 0721 setStatus(project->dbConnection(), xi18n("Saving object's definition failed."), ""); 0722 return false; 0723 } 0724 0725 if (project->typeIdForPluginId(part()->info()->pluginId()) < 0) { 0726 if (!project->createIdForPart(*part()->info())) 0727 return false; 0728 } 0729 /* Sets 'dirty' flag on every dialog's view. */ 0730 setDirty(false); 0731 //new object data has now ID updated to a unique value 0732 //-assign that to item's identifier 0733 d->item->setIdentifier(d->schemaObject->id()); 0734 project->addStoredItem(part()->info(), d->item); 0735 0736 return true; 0737 } 0738 0739 tristate KexiWindow::storeData(bool dontAsk) 0740 { 0741 if (neverSaved()) 0742 return false; 0743 KexiView *v = selectedView(); 0744 if (!v) 0745 return false; 0746 0747 #define storeData_ERR \ 0748 setStatus(KexiMainWindowIface::global()->project()->dbConnection(), \ 0749 xi18n("Saving object's data failed."),""); 0750 0751 //save changes using transaction 0752 KDbTransaction transaction = KexiMainWindowIface::global() 0753 ->project()->dbConnection()->beginTransaction(); 0754 if (transaction.isNull()) { 0755 storeData_ERR; 0756 return false; 0757 } 0758 KDbTransactionGuard tg(transaction); 0759 0760 const tristate res = v->storeData(dontAsk); 0761 if (~res) //trans. will be cancelled 0762 return res; 0763 if (!res) { 0764 storeData_ERR; 0765 return res; 0766 } 0767 if (!tg.commit()) { 0768 storeData_ERR; 0769 return false; 0770 } 0771 /* Sets 'dirty' flag on every dialog's view. */ 0772 setDirty(false); 0773 return true; 0774 } 0775 0776 tristate KexiWindow::storeDataAs(KexiPart::Item *item, KexiView::StoreNewDataOptions options) 0777 { 0778 if (neverSaved()) { 0779 qWarning() << "The data was never saved, so storeNewData() should be called instead, giving up."; 0780 return false; 0781 } 0782 KexiView *v = selectedView(); 0783 if (!v) { 0784 return false; 0785 } 0786 //create schema object and assign information 0787 KexiProject *project = KexiMainWindowIface::global()->project(); 0788 KDbObject object(project->typeIdForPluginId(d->part->info()->pluginId())); 0789 if (!d->setupSchemaObject(&object, item, options)) { 0790 return false; 0791 } 0792 0793 bool cancel = false; 0794 KDbObject *newSchemaObject; 0795 if (isDirty()) { // full save of new data 0796 newSchemaObject = v->storeNewData(object, options, &cancel); 0797 } 0798 else { // there were no changes; full copy of the data is enough 0799 // - gives better performance (e.g. tables are copied on server side) 0800 // - works without bothering the user (no unnecessary questions) 0801 newSchemaObject = v->copyData(object, options, &cancel); 0802 } 0803 0804 if (cancel) { 0805 return cancelled; 0806 } 0807 if (!newSchemaObject) { 0808 setStatus(project->dbConnection(), xi18n("Saving object's definition failed."), ""); 0809 return false; 0810 } 0811 setSchemaObject(newSchemaObject); // deletes previous schema if owned 0812 0813 if (project->typeIdForPluginId(part()->info()->pluginId()) < 0) { 0814 if (!project->createIdForPart(*part()->info())) 0815 return false; 0816 } 0817 // clear 'dirty' for old window 0818 setDirty(false); 0819 // for now this Window has new item assigned 0820 d->item = item; 0821 0822 // new object data has now ID updated to a unique value 0823 // -assign that to item's identifier 0824 item->setIdentifier(d->schemaObject->id()); 0825 0826 project->addStoredItem(part()->info(), d->item); 0827 0828 // set 'dirty' flag on every dialog's view 0829 setDirty(false); 0830 0831 return true; 0832 } 0833 0834 void KexiWindow::activate() 0835 { 0836 KexiView *v = selectedView(); 0837 //qDebug() << "focusWidget(): " << focusWidget()->name(); 0838 if (!KDbUtils::hasParent(v, KexiMainWindowIface::global()->focusWidget())) { 0839 //ah, focused widget is not in this view, move focus: 0840 if (v) 0841 v->setFocus(); 0842 } 0843 if (v) 0844 v->updateActions(true); 0845 } 0846 0847 void KexiWindow::deactivate() 0848 { 0849 KexiView *v = selectedView(); 0850 if (v) 0851 v->updateActions(false); 0852 } 0853 0854 void KexiWindow::sendDetachedStateToCurrentView() 0855 { 0856 KexiView *v = selectedView(); 0857 if (v) 0858 v->windowDetached(); 0859 } 0860 0861 void KexiWindow::sendAttachedStateToCurrentView() 0862 { 0863 KexiView *v = selectedView(); 0864 if (v) 0865 v->windowAttached(); 0866 } 0867 0868 bool KexiWindow::saveSettings() 0869 { 0870 bool result = true; 0871 for (int i = 0; i < d->stack->count(); ++i) { 0872 KexiView *view = qobject_cast<KexiView*>(d->stack->widget(i)); 0873 if (!view->saveSettings()) { 0874 result = false; 0875 } 0876 } 0877 return result; 0878 } 0879 0880 Kexi::ViewMode KexiWindow::creatingViewsMode() const 0881 { 0882 return d->creatingViewsMode; 0883 } 0884 0885 QVariant KexiWindow::internalPropertyValue(const QByteArray& name, 0886 const QVariant& defaultValue) const 0887 { 0888 return d->part->internalPropertyValue(name, defaultValue); 0889 } 0890