1
/* This file is part of the KDE project
2
Copyright (C) 2004-2007 Jarosław Staniek <staniek@kde.org>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
* Boston, MA 02110-1301, USA.
21
#include "KexiMainWindowIface.h"
23
#include "KexiWindow.h"
24
#include "kexiproject.h"
25
#include <koproperty/Set.h>
27
#include <kexidb/connection.h>
28
#include <kexidb/utils.h>
29
#include <kexiutils/utils.h>
30
#include <kexiutils/SmallToolButton.h>
31
#include <kexiutils/FlowLayout.h>
35
#include <KActionCollection>
37
#include <QCloseEvent>
38
#include <QApplication>
39
#include <QVBoxLayout>
42
/*class KexiToggleViewModeAction::Private
51
KexiToggleViewModeAction::KexiToggleViewModeAction(
52
Kexi::ViewMode mode, QObject* parent)//, QObject* receiver, const char* slot)
54
KIcon(Kexi::iconNameForViewMode(mode)),
55
Kexi::nameForViewMode(mode, true/*withAmpersand*/),
60
// connect(this, SIGNAL(toggled(bool)), this, SLOT(slotToggled(bool)));
61
// if (receiver && slot)
62
// connect(this, SIGNAL(switchedTo(Kexi::ViewMode)), receiver, slot);
64
if (mode == Kexi::DataViewMode) {
65
setObjectName("view_data_mode");
66
setToolTip(i18n("Switch to data view"));
67
setWhatsThis(i18n("Switches to data view."));
68
} else if (mode == Kexi::DesignViewMode) {
69
setObjectName("view_design_mode");
70
setToolTip(i18n("Switch to design view"));
71
setWhatsThis(i18n("Switches to design view."));
72
} else if (mode == Kexi::TextViewMode) {
73
setObjectName("view_text_mode");
74
setToolTip(i18n("Switch to text view"));
75
setWhatsThis(i18n("Switches to text view."));
77
kWarning() << "KexiToggleViewModeAction: invalid mode " << mode;
82
void KexiToggleViewModeAction::slotToggled(bool checked)
86
emit switchedTo(d->mode);
89
//-------------------------
91
class KexiView::Private
99
, viewMode(Kexi::NoViewMode) //unknown!
101
, slotSwitchToViewModeInternalEnabled(true)
102
, sortedProperties(false)
103
, recentResultOfSwitchToViewModeInternal(true) {
107
/* qDeleteAll(viewActions); */
108
/* foreach(KAction* action, viewActions) {
109
//only delete action if it is not shared (otherwise, window itself will delete it)
110
if (!window->sharedViewAction(action->name()))
115
void toggleViewModeButtonBack(Kexi::ViewMode mode) {
116
QAction *a = toggleViewModeActions.value(mode);
118
slotSwitchToViewModeInternalEnabled = false;
119
toggleViewModeActions.value(mode)->blockSignals(true);
120
toggleViewModeButtons.value(mode)->blockSignals(true);
121
toggleViewModeButtons.value(mode)->setChecked(viewMode == mode);
122
toggleViewModeActions.value(mode)->blockSignals(false);
123
toggleViewModeButtons.value(mode)->blockSignals(false);
124
//a->setChecked(viewMode == mode);
125
slotSwitchToViewModeInternalEnabled = true;
129
QVBoxLayout* mainLyr;
130
QWidget *topBarHWidget;
131
KexiFlowLayout *topBarLyr;
132
//QActionGroup* viewModeGroup;
133
QHash<Kexi::ViewMode, QAction*> toggleViewModeActions;
134
QHash<Kexi::ViewMode, KexiSmallToolButton*> toggleViewModeButtons;
136
KexiSmallToolButton* saveDesignButton;
137
// KexiToolBarSeparator* saveDesignButtonSeparator;
139
QString defaultIconName;
142
KexiView *parentView;
144
QPointer<QWidget> lastFocusedChildBeforeFocusOut;
146
/*! Member set to newly assigned object's ID in storeNewData()
147
and used in storeDataBlock(). This is needed because usually,
148
storeDataBlock() can be called from storeNewData() and in this case
149
window has not yet assigned valid identifier (it has just negative temp. number).
154
/*! Mode for this view. Initialized by KexiWindow::switchToViewMode().
155
Can be useful when single class is used for more than one view (e.g. KexiDBForm). */
156
Kexi::ViewMode viewMode;
158
QList<KexiView*> children;
160
/*! View-level actions (not shared), owned by the view. */
161
QList<QAction*> viewActions;
162
QHash<QByteArray, QAction*> viewActionsHash;
166
//! Used in slotSwitchToViewModeInternal() to disabling it
167
bool slotSwitchToViewModeInternalEnabled;
169
bool sortedProperties;
171
//! Used in slotSwitchToViewModeInternal() to disabling d->window->switchToViewModeInternal(mode) call.
172
//! Needed because there is another slotSwitchToViewModeInternal() calls if d->window->switchToViewModeInternal(mode)
173
//! did not succeed, so for the second time we block this call.
174
tristate recentResultOfSwitchToViewModeInternal;
177
//----------------------------------------------------------
179
KexiView::KexiView(QWidget *parent)
181
, KexiActionProxy(this)
185
while ((wi = wi->parentWidget()) && !wi->inherits("KexiWindow"))
187
d->window = (wi && wi->inherits("KexiWindow")) ? static_cast<KexiWindow*>(wi) : 0;
189
//init view mode number for this view (obtained from window where this view is created)
190
if (d->window->supportsViewMode(d->window->creatingViewsMode()))
191
d->viewMode = d->window->creatingViewsMode();
194
QString("%1_for_%2_object")
195
.arg(Kexi::nameForViewMode(d->viewMode).replace(" ", "_"))
196
.arg(d->window ? d->window->partItem()->name() : QString("??")));
198
installEventFilter(this);
200
// QLayout *l = layout(); -- FIXME: Not used?
201
d->mainLyr = new QVBoxLayout(this);
202
d->mainLyr->setContentsMargins(0, KDialog::marginHint() / 3, 0, 0);
204
if (parentWidget()->inherits("KexiWindow")) {
205
d->topBarHWidget = new QWidget(this);
206
d->topBarHWidget->setFont(KexiUtils::smallFont());
207
d->mainLyr->addWidget(d->topBarHWidget);
208
QHBoxLayout *topBarHLyr = new QHBoxLayout(d->topBarHWidget); //needed unless KexiFlowLayout properly handles contents margins
209
topBarHLyr->setContentsMargins(0, 0, 0, 0);
210
topBarHLyr->addSpacing(KDialog::marginHint() / 2);
211
d->topBarLyr = new KexiFlowLayout(topBarHLyr, KDialog::marginHint() / 2, 2);
213
const bool userMode = KexiMainWindowIface::global()->userMode();
216
|| d->window->supportedViewModes() == Kexi::DataViewMode
217
|| d->window->supportedViewModes() == Kexi::DesignViewMode
218
|| d->window->supportedViewModes() == Kexi::TextViewMode) {
219
// nothing to do: only single view mode supported
221
if (parentWidget()->inherits("KexiWindow")) {
222
createViewModeToggleButtons();
227
if (d->viewMode == Kexi::DesignViewMode || d->viewMode == Kexi::TextViewMode) {
228
d->topBarLyr->addWidget(new KexiToolBarSeparator(d->topBarHWidget));
230
a = sharedAction("project_save");
231
d->saveDesignButton = new KexiSmallToolButton(a, d->topBarHWidget);
232
d->saveDesignButton->setText(i18n("Save"));
233
d->saveDesignButton->setToolTip(i18n("Save current design"));
234
d->saveDesignButton->setWhatsThis(i18n("Saves changes made to the current design."));
235
d->topBarLyr->addWidget(d->saveDesignButton);
236
// d->topBarLyr->addWidget( d->saveDesignButtonSeparator = new KexiToolBarSeparator(d->topBarHWidget));
238
d->saveDesignButton = 0;
242
d->saveDesignButton = 0;
243
d->topBarHWidget = 0;
248
KexiView::~KexiView()
253
KexiWindow* KexiView::window() const
258
bool KexiView::isDirty() const
263
Kexi::ViewMode KexiView::viewMode() const
268
KexiPart::Part* KexiView::part() const
270
return d->window ? d->window->part() : 0;
273
tristate KexiView::beforeSwitchTo(Kexi::ViewMode mode, bool & dontStore)
280
tristate KexiView::afterSwitchFrom(Kexi::ViewMode mode)
286
QSize KexiView::preferredSizeHint(const QSize& otherSize)
289
#warning KexiView::preferredSizeHint()
291
#pragma WARNING( KexiView::preferredSizeHint() )
294
KexiWindow* w = d->window;
295
if (dlg && dlg->mdiParent()) {
296
QRect r = dlg->mdiParent()->mdiAreaContentsRect();
297
return otherSize.boundedTo(QSize(
299
r.height() - dlg->mdiParent()->captionHeight() - dlg->pos().y() - 10
306
void KexiView::closeEvent(QCloseEvent * e)
309
emit closing(cancel);
314
QWidget::closeEvent(e);
317
KoProperty::Set *KexiView::propertySet()
322
void KexiView::propertySetSwitched()
325
KexiMainWindowIface::global()->propertySetSwitched(window(), false/*force*/,
326
true/*preservePrevSelection*/, d->sortedProperties);
330
void KexiView::propertySetReloaded(bool preservePrevSelection,
331
const QByteArray& propertyToSelect)
334
KexiMainWindowIface::global()->propertySetSwitched(
335
window(), true, preservePrevSelection, d->sortedProperties, propertyToSelect);
338
void KexiView::setDirty(bool set)
340
const bool changed = (d->isDirty != set);
342
d->isDirty = isDirty();
343
if (d->saveDesignButton)
344
d->saveDesignButton->setEnabled(d->isDirty);
346
d->parentView->setDirty(d->isDirty);
348
if (changed && d->window)
349
d->window->dirtyChanged(this);
353
/*bool KexiView::saveData()
362
KexiDB::SchemaData* KexiView::storeNewData(const KexiDB::SchemaData& sdata, bool & /*cancel*/)
364
KexiDB::SchemaData *new_schema = new KexiDB::SchemaData();
367
if (!KexiMainWindowIface::global()->project()->dbConnection()
368
->storeObjectSchemaData(*new_schema, true)) {
372
d->newlyAssignedID = new_schema->id();
376
tristate KexiView::storeData(bool dontAsk)
379
if (!d->window || !d->window->schemaData())
381
if (!KexiMainWindowIface::global()->project()->dbConnection()
382
->storeObjectSchemaData(*d->window->schemaData(), false /*existing object*/)) {
389
bool KexiView::loadDataBlock(QString &dataString, const QString& dataID, bool canBeEmpty)
393
const tristate res = KexiMainWindowIface::global()->project()->dbConnection()
394
->loadDataBlock(d->window->id(), dataString, dataID);
395
if (canBeEmpty && ~res) {
402
bool KexiView::storeDataBlock(const QString &dataString, const QString &dataID)
407
if (d->newlyAssignedID > 0) {//ID not yet stored within window, but we've got ID here
408
effectiveID = d->newlyAssignedID;
409
d->newlyAssignedID = -1;
411
effectiveID = d->window->id();
413
return effectiveID > 0
414
&& KexiMainWindowIface::global()->project()->dbConnection()->storeDataBlock(
415
effectiveID, dataString, dataID);
418
bool KexiView::removeDataBlock(const QString& dataID)
422
return KexiMainWindowIface::global()->project()->dbConnection()
423
->removeDataBlock(d->window->id(), dataID);
426
bool KexiView::eventFilter(QObject *o, QEvent *e)
428
if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) {// && o->inherits("QWidget")) {
429
// //hp==true if currently focused widget is a child of this table view
430
// const bool hp = Kexi::hasParent( static_cast<QWidget*>(o), focusWidget());
431
kDebug() << "this=[" << o->metaObject()->className()
432
<< objectName() << "] o=[" << o->metaObject()->className() << o->objectName()
433
<< "] focusWidget=[" << (qApp->focusWidget() ? qApp->focusWidget()->metaObject()->className() : QString())
434
<< (qApp->focusWidget() ? qApp->focusWidget()->objectName() : QString()) << "] ev.type=" << e->type();
435
if (KexiUtils::hasParent(this, o)) {
436
if (e->type() == QEvent::FocusOut && qApp->focusWidget()
437
&& !KexiUtils::hasParent(this, qApp->focusWidget())) {
438
//focus out: when currently focused widget is not a parent of this view
440
} else if (e->type() == QEvent::FocusIn) {
443
if (e->type() == QEvent::FocusOut) {
444
// kDebug() << focusWidget()->className() << " " << focusWidget()->name();
445
// kDebug() << o->className() << " " << o->name();
446
KexiView *v = KexiUtils::findParent<KexiView*>(o);
448
while (v->d->parentView)
449
v = v->d->parentView;
450
if (KexiUtils::hasParent(this, static_cast<QWidget*>(v->focusWidget())))
451
v->d->lastFocusedChildBeforeFocusOut = static_cast<QWidget*>(v->focusWidget());
455
if (e->type() == QEvent::FocusIn && m_actionProxyParent) {
456
m_actionProxyParent->m_focusedChild = this;
463
void KexiView::setViewWidget(QWidget* w, bool focusProxy)
465
if (d->viewWidget == w)
468
d->viewWidget->removeEventFilter(this);
469
d->mainLyr->removeWidget(d->viewWidget);
473
//if (!d->children.contains(dynamic_cast<KexiView*>(d->viewWidget))) {
474
d->viewWidget->setParent(this);
475
d->mainLyr->addWidget(d->viewWidget);
476
d->viewWidget->installEventFilter(this);
479
setFocusProxy(d->viewWidget); //js: ok?
483
void KexiView::addChildView(KexiView* childView)
485
d->children.append(childView);
486
addActionProxyChild(childView);
487
childView->d->parentView = this;
489
//childView->setParent(this);
490
//d->mainLyr->addWidget(childView);
492
// if (d->parentView)
493
// childView->installEventFilter(d->parentView);
494
childView->installEventFilter(this);
497
void KexiView::setFocus()
499
if (!d->lastFocusedChildBeforeFocusOut.isNull()) {
500
// kDebug() << "FOCUS: " << d->lastFocusedChildBeforeFocusOut->className() << " " << d->lastFocusedChildBeforeFocusOut->name();
501
QWidget *w = d->lastFocusedChildBeforeFocusOut;
502
d->lastFocusedChildBeforeFocusOut = 0;
510
KexiMainWindowIface::global()->invalidateSharedActions(this);
513
QAction* KexiView::sharedAction(const QString& action_name)
516
KActionCollection *ac;
517
if ((ac = part()->actionCollectionForMode(viewMode()))) {
518
QAction* a = ac->action(action_name);
523
return KexiActionProxy::sharedAction(action_name);
526
void KexiView::setAvailable(const QString& action_name, bool set)
529
KActionCollection *ac;
531
if ((ac = part()->actionCollectionForMode(viewMode())) && (a = ac->action(action_name))) {
535
KexiActionProxy::setAvailable(action_name, set);
538
void KexiView::updateActions(bool activated)
541
//do the same for children :)
542
foreach(KexiView* view, d->children) {
543
view->updateActions(activated);
547
void KexiView::setViewActions(const QList<QAction*>& actions)
549
d->viewActions = actions;
550
d->viewActionsHash.clear();
551
foreach(QAction* action, d->viewActions) {
552
d->viewActionsHash.insert(action->objectName().toLatin1(), action);
556
QAction* KexiView::viewAction(const char* name) const
558
return d->viewActionsHash.value(name);
561
QList<QAction*> KexiView::viewActions() const
563
return d->viewActions;
566
void KexiView::toggleViewModeButtonBack()
568
// d->switchToViewModeInternalEnabled = false;
569
d->toggleViewModeButtonBack(Kexi::DataViewMode);
570
d->toggleViewModeButtonBack(Kexi::DesignViewMode);
571
d->toggleViewModeButtonBack(Kexi::TextViewMode);
572
// d->switchToViewModeInternalEnabled = true;
575
void KexiView::createViewModeToggleButtons()
578
KexiSmallToolButton *btn;
579
// d->viewModeGroup = new QActionGroup(this);
580
QLabel *showLabel = new QLabel(i18n("Show:"), d->topBarHWidget);
581
d->topBarLyr->addWidget(showLabel);
582
d->topBarLyr->setAlignment(showLabel, Qt::AlignVCenter | Qt::AlignLeft);
583
if (d->window->supportsViewMode(Kexi::DataViewMode)) {
584
a = new KexiToggleViewModeAction(Kexi::DataViewMode, this);
585
// this, SLOT(slotSwitchToViewModeInternal(Kexi::ViewMode)));
586
d->toggleViewModeActions.insert(Kexi::DataViewMode, a);
587
// d->viewModeGroup->addAction(a);
588
btn = new KexiSmallToolButton(a, d->topBarHWidget);
589
connect(btn, SIGNAL(toggled(bool)), this, SLOT(slotSwitchToDataViewModeInternal(bool)));
590
d->toggleViewModeButtons.insert(Kexi::DataViewMode, btn);
591
btn->setText(i18n("Data"));
592
d->topBarLyr->addWidget(btn);
594
if (d->window->supportsViewMode(Kexi::DesignViewMode)) {
595
a = new KexiToggleViewModeAction(Kexi::DesignViewMode, this);
596
// this, SLOT(slotSwitchToViewModeInternal(Kexi::ViewMode)));
597
d->toggleViewModeActions.insert(Kexi::DesignViewMode, a);
598
// d->viewModeGroup->addAction(a);
599
btn = new KexiSmallToolButton(a, d->topBarHWidget);
600
connect(btn, SIGNAL(toggled(bool)), this, SLOT(slotSwitchToDesignViewModeInternal(bool)));
601
d->toggleViewModeButtons.insert(Kexi::DesignViewMode, btn);
602
btn->setText(i18n("Design"));
603
d->topBarLyr->addWidget(btn);
605
if (d->window->supportsViewMode(Kexi::TextViewMode)) {
606
a = new KexiToggleViewModeAction(Kexi::TextViewMode, this);
607
// this, SLOT(slotSwitchToViewModeInternal(Kexi::ViewMode)));
608
QString customTextViewModeCaption(d->window->internalPropertyValue("textViewModeCaption").toString());
609
if (!customTextViewModeCaption.isEmpty())
610
a->setText(customTextViewModeCaption);
611
d->toggleViewModeActions.insert(Kexi::TextViewMode, a);
612
// d->viewModeGroup->addAction(a);
613
btn = new KexiSmallToolButton(a, d->topBarHWidget);
614
connect(btn, SIGNAL(toggled(bool)), this, SLOT(slotSwitchToTextViewModeInternal(bool)));
615
d->toggleViewModeButtons.insert(Kexi::TextViewMode, btn);
616
d->topBarLyr->addWidget(btn);
618
toggleViewModeButtonBack();
621
void KexiView::slotSwitchToDataViewModeInternal(bool)
623
slotSwitchToViewModeInternal(Kexi::DataViewMode);
626
void KexiView::slotSwitchToDesignViewModeInternal(bool)
628
slotSwitchToViewModeInternal(Kexi::DesignViewMode);
631
void KexiView::slotSwitchToTextViewModeInternal(bool)
633
slotSwitchToViewModeInternal(Kexi::TextViewMode);
636
void KexiView::slotSwitchToViewModeInternal(Kexi::ViewMode mode)
638
if (!d->slotSwitchToViewModeInternalEnabled)
640
if (d->recentResultOfSwitchToViewModeInternal != true)
641
d->recentResultOfSwitchToViewModeInternal = true;
643
d->recentResultOfSwitchToViewModeInternal = d->window->switchToViewModeInternal(mode);
645
if (d->viewMode != mode) {
646
//switch back visually
647
KexiSmallToolButton *b = d->toggleViewModeButtons.value(mode);
648
d->slotSwitchToViewModeInternalEnabled = false;
649
b->setChecked(false);
650
d->slotSwitchToViewModeInternalEnabled = true;
654
void KexiView::initViewActions()
658
if (!d->viewActions.isEmpty())
659
d->topBarLyr->addWidget(new KexiToolBarSeparator(d->topBarHWidget));
660
foreach(QAction* action, d->viewActions) {
661
if (action->isSeparator()) {
662
d->topBarLyr->addWidget(new KexiToolBarSeparator(d->topBarHWidget));
664
KexiSmallToolButton *btn = new KexiSmallToolButton(action, d->topBarHWidget);
665
btn->setText(action->text());
666
btn->setToolTip(action->toolTip());
667
btn->setWhatsThis(action->whatsThis());
668
if (action->dynamicPropertyNames().contains("iconOnly") && action->property("iconOnly").toBool() ) {
669
btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
671
d->topBarLyr->addWidget(btn);
676
void KexiView::setSortedProperties(bool set)
678
d->sortedProperties = set;
681
#include "KexiView.moc"