1
/* This file is part of the KDE project
2
Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
3
Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org>
4
Copyright (C) 2003-2007 JarosÅaw Staniek <staniek@kde.org>
6
This program is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License as published by the Free Software Foundation; either
9
version 2 of the License, or (at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Library General Public License for more details.
16
You should have received a copy of the GNU Library General Public License
17
along with this program; see the file COPYING. If not, write to
18
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
* Boston, MA 02110-1301, USA.
22
#include "KexiRelationsView.h"
24
#include <kexiutils/utils.h>
25
#include <kexiproject.h>
26
#include <KexiMainWindowIface.h>
27
#include "KexiRelationsScrollArea.h"
28
#include "KexiRelationsConnection.h"
30
#include <KDbConnection>
31
#include <KDbTableOrQuerySchema>
34
#include <KLocalizedString>
37
#include <QHBoxLayout>
39
#include <QGridLayout>
41
#include <QPushButton>
45
class KexiRelationsView::Private
52
KComboBox *tableCombo;
54
KexiRelationsScrollArea *scrollArea;
57
QMenu *tableQueryPopup; //!< over table/query
58
QMenu *connectionPopup; //!< over connection
59
QMenu *areaPopup; //!< over outer area
60
QAction *openSelectedTableAction, *designSelectedTableAction,
61
*appendSelectedFieldAction, *appendSelectedFieldsAction, *hideTableAction;
66
KexiRelationsView::KexiRelationsView(QWidget *parent)
70
QWidget *mainWidget = new QWidget(this);
71
QGridLayout *g = new QGridLayout(mainWidget);
72
g->setContentsMargins(0, 0, 0, 0);
73
g->setSpacing(KexiUtils::spacingHint());
75
QWidget *horWidget = new QWidget(mainWidget);
76
QHBoxLayout *hlyr = new QHBoxLayout(horWidget);
77
hlyr->setContentsMargins(0, 0, 0, 0);
78
g->addWidget(horWidget, 0, 0);
80
d->tableCombo = new KComboBox(horWidget);
81
d->tableCombo->setObjectName("tables_combo");
82
d->tableCombo->setMinimumWidth(QFontMetrics(font()).width("w")*20);
83
d->tableCombo->setInsertPolicy(QComboBox::NoInsert);
84
d->tableCombo->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred));
85
QLabel *lbl = new QLabel(xi18n("Table:"), horWidget);
86
lbl->setBuddy(d->tableCombo);
89
hlyr->addWidget(d->tableCombo);
91
d->btnAdd = new QPushButton(xi18nc("Insert table/query into relations view", "&Insert"), horWidget);
92
hlyr->addWidget(d->btnAdd);
94
connect(d->btnAdd, SIGNAL(clicked()), this, SLOT(slotAddTable()));
96
d->scrollArea = new KexiRelationsScrollArea(mainWidget);
97
d->scrollArea->setObjectName("scroll_area");
98
setViewWidget(mainWidget, false/* no focus proxy */);
99
setFocusProxy(d->scrollArea);
100
g->addWidget(d->scrollArea, 1, 0);
103
d->tableQueryPopup = new QMenu(this);
104
d->tableQueryPopup->setObjectName("tableQueryPopup");
105
connect(d->tableQueryPopup, SIGNAL(aboutToShow()), this, SLOT(aboutToShowPopupMenu()));
107
d->hideTableAction = plugSharedAction("edit_delete", xi18n("&Hide Table"), d->tableQueryPopup);
108
if (d->hideTableAction)
109
d->hideTableAction->setIcon(QIcon());
111
d->connectionPopup = new QMenu(this);
112
d->connectionPopup->setObjectName("connectionPopup");
113
connect(d->connectionPopup, SIGNAL(aboutToShow()), this, SLOT(aboutToShowPopupMenu()));
116
d->areaPopup = new QMenu(this);
117
d->areaPopup->setObjectName("areaPopup");
119
d->appendSelectedFieldAction = new QAction(KexiIcon("add-field"), xi18n("&Append Field"), this);
120
d->appendSelectedFieldAction->setObjectName("relationsview_appendField");
121
connect(d->appendSelectedFieldAction, SIGNAL(triggered()),
122
this, SLOT(appendSelectedFields()));
124
d->appendSelectedFieldsAction = new QAction(KexiIcon("add-field"), xi18n("&Append Fields"), this);
125
d->appendSelectedFieldsAction->setObjectName("relationsview_appendFields");
126
connect(d->appendSelectedFieldsAction, SIGNAL(triggered()),
127
this, SLOT(appendSelectedFields()));
129
d->openSelectedTableAction = new QAction(koIcon("document-open"), xi18n("&Open Table"), this);
130
d->openSelectedTableAction->setObjectName("relationsview_openTable");
131
connect(d->openSelectedTableAction, SIGNAL(triggered()),
132
this, SLOT(openSelectedTable()));
134
d->designSelectedTableAction = new QAction(koIcon("document-properties"), xi18n("&Design Table"), this);
135
connect(d->designSelectedTableAction, SIGNAL(triggered()),
136
this, SLOT(designSelectedTable()));
137
d->designSelectedTableAction->setObjectName("relationsview_designTable");
139
plugSharedAction("edit_delete", this, SLOT(removeSelectedObject()));
141
connect(d->scrollArea, SIGNAL(tableViewGotFocus()),
142
this, SLOT(tableViewGotFocus()));
143
connect(d->scrollArea, SIGNAL(connectionViewGotFocus()),
144
this, SLOT(connectionViewGotFocus()));
145
connect(d->scrollArea, SIGNAL(emptyAreaGotFocus()),
146
this, SLOT(emptyAreaGotFocus()));
147
connect(d->scrollArea, SIGNAL(tableContextMenuRequest(QPoint)),
148
this, SLOT(tableContextMenuRequest(QPoint)));
149
connect(d->scrollArea, SIGNAL(connectionContextMenuRequest(QPoint)),
150
this, SLOT(connectionContextMenuRequest(QPoint)));
151
connect(d->scrollArea, SIGNAL(tableHidden(KDbTableSchema*)),
152
this, SLOT(slotTableHidden(KDbTableSchema*)));
153
connect(d->scrollArea, SIGNAL(tablePositionChanged(KexiRelationsTableContainer*)),
154
this, SIGNAL(tablePositionChanged(KexiRelationsTableContainer*)));
155
connect(d->scrollArea, SIGNAL(aboutConnectionRemove(KexiRelationsConnection*)),
156
this, SIGNAL(aboutConnectionRemove(KexiRelationsConnection*)));
161
/*todo setContextHelp(xi18n("Relations"), xi18n("To create a relationship simply drag the source field onto the target field. "
162
"An arrowhead is used to show which table is the parent (master) and which table is the child (slave) in the relationship."));*/
166
#ifdef TESTING_KexiRelationWidget
167
for (int i = 0;i < (int)d->db->tableNames().count();i++)
168
QTimer::singleShot(100, this, SLOT(slotAddTable()));
174
KexiRelationsView::~KexiRelationsView()
179
TablesHash* KexiRelationsView::tables() const
181
return d->scrollArea->tables();
184
KexiRelationsTableContainer* KexiRelationsView::table(const QString& name) const
186
return d->scrollArea->tables()->value(name);
189
const QSet<KexiRelationsConnection*>* KexiRelationsView::relationsConnections() const
191
return d->scrollArea->relationsConnections();
195
KexiRelationsView::slotAddTable()
197
if (d->tableCombo->currentIndex() == -1)
199
const QString tname = d->tableCombo->itemText(d->tableCombo->currentIndex());
200
KDbTableSchema *t = d->conn->tableSchema(tname);
205
KexiRelationsView::addTable(KDbTableSchema *t, const QRect &rect)
209
if (!d->scrollArea->tableContainer(t)) {
210
KexiRelationsTableContainer *c = d->scrollArea->addTableContainer(t, rect);
211
qDebug() << "adding table" << t->name();
214
connect(c, SIGNAL(fieldsDoubleClicked(KDbTableOrQuerySchema&,QStringList)),
215
this, SIGNAL(appendFields(KDbTableOrQuerySchema&,QStringList)));
218
const QString tname = t->name().toLower();
219
const int count = d->tableCombo->count();
221
for (; i < count; i++) {
222
if (d->tableCombo->itemText(i).toLower() == tname)
226
int oi = d->tableCombo->currentIndex();
227
qDebug() << "removing a table from the combo box";
228
d->tableCombo->removeItem(i);
229
if (d->tableCombo->count() > 0) {
230
if (oi >= d->tableCombo->count()) {
231
oi = d->tableCombo->count() - 1;
233
d->tableCombo->setCurrentIndex(oi);
235
d->tableCombo->setEnabled(false);
236
d->btnAdd->setEnabled(false);
243
KexiRelationsView::addConnection(const SourceConnection& conn)
245
d->scrollArea->addConnection(conn);
249
KexiRelationsView::addTable(const QString& t)
251
for (int i = 0; i < d->tableCombo->count(); i++) {
252
if (d->tableCombo->itemText(i) == t) {
253
d->tableCombo->setCurrentIndex(i);
259
void KexiRelationsView::tableViewGotFocus()
264
void KexiRelationsView::connectionViewGotFocus()
269
void KexiRelationsView::emptyAreaGotFocus()
274
void KexiRelationsView::tableContextMenuRequest(const QPoint& pos)
280
void KexiRelationsView::connectionContextMenuRequest(const QPoint& pos)
286
void KexiRelationsView::emptyAreaContextMenuRequest(const QPoint& /*pos*/)
292
void KexiRelationsView::invalidateActions()
294
setAvailable("edit_delete", d->scrollArea->selectedConnection() || d->scrollArea->focusedTableContainer());
297
void KexiRelationsView::executePopup(QPoint pos)
299
if (pos == QPoint(-1, -1)) {
301
d->scrollArea->focusedTableContainer() ? d->scrollArea->focusedTableContainer()->pos() + d->scrollArea->focusedTableContainer()->rect().center() : rect().center());
303
if (d->scrollArea->focusedTableContainer())
304
d->tableQueryPopup->exec(pos);
305
else if (d->scrollArea->selectedConnection())
306
d->connectionPopup->exec(pos);
309
void KexiRelationsView::removeSelectedObject()
311
d->scrollArea->removeSelectedObject();
314
void KexiRelationsView::appendSelectedFields()
316
KexiRelationsTableContainer* currentTableContainer = d->scrollArea->focusedTableContainer();
317
if (!currentTableContainer)
319
emit appendFields(*currentTableContainer->schema(), currentTableContainer->selectedFieldNames());
322
void KexiRelationsView::openSelectedTable()
324
/*! @todo what about query? */
325
if (!d->scrollArea->focusedTableContainer() || !d->scrollArea->focusedTableContainer()->schema()->table())
327
bool openingCancelled;
328
KexiMainWindowIface::global()->openObject(
329
"kexi/table", d->scrollArea->focusedTableContainer()->schema()->name(),
330
Kexi::DataViewMode, &openingCancelled);
333
void KexiRelationsView::designSelectedTable()
335
/*! @todo what about query? */
336
if (!d->scrollArea->focusedTableContainer() || !d->scrollArea->focusedTableContainer()->schema()->table())
338
bool openingCancelled;
339
KexiMainWindowIface::global()->openObject(
340
"kexi/table", d->scrollArea->focusedTableContainer()->schema()->name(),
341
Kexi::DesignViewMode, &openingCancelled);
344
QSize KexiRelationsView::sizeHint() const
346
return d->scrollArea->sizeHint();
349
void KexiRelationsView::slotTableHidden(KDbTableSchema* table)
351
const QString &t = table->name().toLower();
353
for (i = 0; i < d->tableCombo->count() && t > d->tableCombo->itemText(i).toLower(); i++) {
355
d->tableCombo->insertItem(i, table->name());
356
if (!d->tableCombo->isEnabled()) {
357
d->tableCombo->setCurrentIndex(0);
358
d->tableCombo->setEnabled(true);
359
d->btnAdd->setEnabled(true);
362
emit tableHidden(table);
365
void KexiRelationsView::aboutToShowPopupMenu()
367
KexiRelationsTableContainer* currentTableContainer = d->scrollArea->focusedTableContainer();
368
if (currentTableContainer /*&& currentTableContainer->schema()->table()*/) {
369
/*! @todo what about query? */
370
d->tableQueryPopup->clear();
371
d->tableQueryPopup->addSection(KexiIcon("table"),
372
QString(d->scrollArea->focusedTableContainer()->schema()->name()) + " : " + xi18n("Table"));
373
QStringList selectedFieldNames(currentTableContainer->selectedFieldNames());
374
if (currentTableContainer && !selectedFieldNames.isEmpty()) {
375
if (selectedFieldNames.count() > 1 || selectedFieldNames.first() == "*") //multiple
376
d->tableQueryPopup->addAction(d->appendSelectedFieldsAction);
378
d->tableQueryPopup->addAction(d->appendSelectedFieldAction);
379
d->tableQueryPopup->addSeparator();
381
d->tableQueryPopup->addAction(d->openSelectedTableAction);
382
d->tableQueryPopup->addAction(d->designSelectedTableAction);
383
d->tableQueryPopup->addSeparator();
384
d->tableQueryPopup->addAction(d->hideTableAction);
385
} else if (d->scrollArea->selectedConnection()) {
386
unplugSharedAction("edit_delete", d->connectionPopup);
387
d->connectionPopup->clear();
388
d->connectionPopup->addSection(QIcon(),
389
d->scrollArea->selectedConnection()->toString() + " : " + xi18n("Relationship"));
390
plugSharedAction("edit_delete", d->connectionPopup);
394
bool KexiRelationsView::clear()
396
d->scrollArea->clear();
397
return setConnection(d->conn);
400
/*! Removes all coonections from the view. */
401
void KexiRelationsView::removeAllConnections()
403
d->scrollArea->removeAllConnections();
406
bool KexiRelationsView::setConnection(KDbConnection *conn)
408
d->tableCombo->clear();
412
QStringList result = d->conn->tableNames(false/*no system tables*/, &ok);
417
d->tableCombo->addItems(result);
423
KexiRelationsView::objectCreated(const QString &mime, const QString& name)
425
if (mime == "kexi/table" || mime == "kexi/query") {
427
const int count = d->tableCombo->count();
428
QString strName(name);
430
for (; i < count && d->tableCombo->itemText(i) <= strName; i++) {
432
d->tableCombo->insertItem(i, name);
437
KexiRelationsView::objectDeleted(const QString &mime, const QString& name)
439
if (mime == "kexi/table" || mime == "kexi/query") {
440
for (int i = 0; i < d->tableCombo->count(); i++) {
442
if (d->tableCombo->itemText(i) == name) {
443
d->tableCombo->removeItem(i);
444
if (d->tableCombo->currentIndex() == i) {
445
if (i == (d->tableCombo->count() - 1))
446
d->tableCombo->setCurrentIndex(i - 1);
448
d->tableCombo->setCurrentIndex(i);
457
KexiRelationsView::objectRenamed(const QString &mime, const QString& name,
458
const QString& newName)
460
if (mime == "kexi/table" || mime == "kexi/query") {
461
const int count = d->tableCombo->count();
462
for (int i = 0; i < count; i++) {
464
if (d->tableCombo->itemText(i) == name) {
465
d->tableCombo->removeItem(i);
467
for (; j < count && d->tableCombo->itemText(j) <= newName; j++) {
469
d->tableCombo->insertItem(j, newName);
477
KexiRelationsView::hideAllTablesExcept(QList<KDbTableSchema*>* tables)
479
d->scrollArea->hideAllTablesExcept(tables);