summaryrefslogtreecommitdiffstats
path: root/kexi/widget/relations
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/widget/relations
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/widget/relations')
-rw-r--r--kexi/widget/relations/Makefile.am38
-rw-r--r--kexi/widget/relations/kexirelationview.cpp639
-rw-r--r--kexi/widget/relations/kexirelationview.h167
-rw-r--r--kexi/widget/relations/kexirelationviewconnection.cpp298
-rw-r--r--kexi/widget/relations/kexirelationviewconnection.h75
-rw-r--r--kexi/widget/relations/kexirelationviewtable.cpp429
-rw-r--r--kexi/widget/relations/kexirelationviewtable.h157
-rw-r--r--kexi/widget/relations/kexirelationwidget.cpp425
-rw-r--r--kexi/widget/relations/kexirelationwidget.h137
-rw-r--r--kexi/widget/relations/r1.xpm10
-rw-r--r--kexi/widget/relations/rn.xpm9
11 files changed, 2384 insertions, 0 deletions
diff --git a/kexi/widget/relations/Makefile.am b/kexi/widget/relations/Makefile.am
new file mode 100644
index 00000000..f09e939a
--- /dev/null
+++ b/kexi/widget/relations/Makefile.am
@@ -0,0 +1,38 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+lib_LTLIBRARIES = libkexirelationsview.la
+
+libkexirelationsview_la_SOURCES = kexirelationview.cpp kexirelationviewconnection.cpp \
+ kexirelationviewtable.cpp kexirelationwidget.cpp
+
+libkexirelationsview_la_LDFLAGS = $(all_libraries) $(VER_INFO) -Wnounresolved
+libkexirelationsview_la_LIBADD = ../../core/libkexicore.la
+
+libkexirelationsview_la_METASOURCES = AUTO
+
+SUBDIRS = .
+
+# kde_appsdir Where your application's menu entry (.desktop) should go to.
+# kde_icondir Where your icon should go to - better use KDE_ICON.
+# kde_sounddir Where your sounds should go to.
+# kde_htmldir Where your docs should go to. (contains lang subdirs)
+# kde_datadir Where you install application data. (Use a subdir)
+# kde_locale Where translation files should go to. (contains lang subdirs)
+# kde_cgidir Where cgi-bin executables should go to.
+# kde_confdir Where config files should go to (system-wide ones with default values).
+# kde_mimedir Where mimetypes .desktop files should go to.
+# kde_servicesdir Where services .desktop files should go to.
+# kde_servicetypesdir Where servicetypes .desktop files should go to.
+# kde_toolbardir Where general toolbar icons should go to (deprecated, use KDE_ICON).
+# kde_wallpaperdir Where general wallpapers should go to.
+# kde_templatesdir Where templates for the "New" menu (Konqueror/KDesktop) should go to.
+# kde_bindir Where executables should go to. Use bin_PROGRAMS or bin_SCRIPTS.
+# kde_libdir Where shared libraries should go to. Use lib_LTLIBRARIES.
+# kde_moduledir Where modules (e.g. parts) should go to. Use kde_module_LTLIBRARIES.
+# kde_styledir Where Qt/KDE widget styles should go to (new in KDE 3).
+# kde_designerdir Where Qt Designer plugins should go to (new in KDE 3).
+
+# set the include path for X, qt and KDE
+INCLUDES= -I$(top_srcdir)/kexi $(LIB_KEXI_KMDI_INCLUDES) \
+ -I$(top_srcdir)/kexi/core $(all_includes)
+
diff --git a/kexi/widget/relations/kexirelationview.cpp b/kexi/widget/relations/kexirelationview.cpp
new file mode 100644
index 00000000..9d68a755
--- /dev/null
+++ b/kexi/widget/relations/kexirelationview.cpp
@@ -0,0 +1,639 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 <kdebug.h>
+
+#include <qstringlist.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qheader.h>
+#include <qevent.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qlineedit.h>
+#include <qpopupmenu.h>
+
+#include <klocale.h>
+#include <kaction.h>
+#include <kpopupmenu.h>
+#include <kglobalsettings.h>
+#include <kmessagebox.h>
+
+#include <kexidb/tableschema.h>
+#include <kexidb/indexschema.h>
+#include <kexidb/utils.h>
+
+#include "kexirelationview.h"
+#include "kexirelationviewtable.h"
+#include "kexirelationviewconnection.h"
+#include <kexi.h>
+
+KexiRelationView::KexiRelationView(QWidget *parent, const char *name)
+ : QScrollView(parent, name, WStaticContents)
+{
+// m_relation=relation;
+// m_relation->incUsageCount();
+ m_selectedConnection = 0;
+ m_readOnly=false;
+ m_focusedTableView = 0;
+ setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
+
+// connect(relation, SIGNAL(relationListUpdated(QObject *)), this, SLOT(slotListUpdate(QObject *)));
+
+ viewport()->setPaletteBackgroundColor(colorGroup().mid());
+ setFocusPolicy(WheelFocus);
+ setResizePolicy(Manual);
+/*MOVED TO KexiRelationDialog
+ //actions
+ m_tableQueryPopup = new KPopupMenu(this, "m_popup");
+ m_tableQueryPopup->insertTitle(i18n("Table"));
+ m_connectionPopup = new KPopupMenu(this, "m_connectionPopup");
+ m_connectionPopup->insertTitle(i18n("Relation"));
+ m_areaPopup = new KPopupMenu(this, "m_areaPopup");
+
+ plugSharedAction("edit_delete", i18n("Hide Table"), m_tableQueryPopup);
+ plugSharedAction("edit_delete",m_connectionPopup);
+ plugSharedAction("edit_delete",this, SLOT(removeSelectedObject()));
+*/
+#if 0
+ m_removeSelectedTableQueryAction = new KAction(i18n("&Hide Selected Table/Query"), "editdelete", "",
+ this, SLOT(removeSelectedTableQuery()), parent->actionCollection(), "relationsview_removeSelectedTableQuery");
+ m_removeSelectedConnectionAction = new KAction(i18n("&Remove Selected Relationship"), "button_cancel", "",
+ this, SLOT(removeSelectedConnection()), parent->actionCollection(), "relationsview_removeSelectedConnection");
+ m_openSelectedTableQueryAction = new KAction(i18n("&Open Selected Table/Query"), "", "",
+ this, SLOT(openSelectedTableQuery()), 0/*parent->actionCollection()*/, "relationsview_openSelectedTableQuery");
+#endif
+
+// invalidateActions();
+
+#if 0
+
+
+ m_popup = new KPopupMenu(this, "m_popup");
+ m_openSelectedTableQueryAction->plug( m_popup );
+ m_removeSelectedTableQueryAction->plug( m_popup );
+ m_removeSelectedConnectionAction->plug( m_popup );
+
+ invalidateActions();
+#endif
+
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, true);
+}
+
+KexiRelationView::~KexiRelationView()
+{
+}
+
+/*KexiRelationViewTableContainer*
+KexiRelationView::containerForTable(KexiDB::TableSchema* tableSchema)
+{
+ if (!tableSchema)
+ return 0;
+ for (TablesDictIterator it(m_tables); it.current(); ++it) {
+ if (it.current()->schema()->table()==tableSchema)
+ return it.current();
+ }
+ return 0;
+}*/
+
+KexiRelationViewTableContainer *
+KexiRelationView::tableContainer(KexiDB::TableSchema *t) const
+{
+ return t ? m_tables.find(t->name()) : 0;
+}
+
+KexiRelationViewTableContainer*
+KexiRelationView::addTableContainer(KexiDB::TableSchema *t, const QRect &rect)
+{
+ if(!t)
+ return 0;
+
+ kdDebug() << "KexiRelationView::addTable(): " << t->name() << ", " << viewport() << endl;
+
+ KexiRelationViewTableContainer* c = tableContainer(t);
+ if (c) {
+ kdWarning() << "KexiRelationView::addTable(): table already added" << endl;
+ return c;
+ }
+
+ c = new KexiRelationViewTableContainer(this,
+/*! @todo what about query? */
+ new KexiDB::TableOrQuerySchema(t)
+ );
+ connect(c, SIGNAL(endDrag()), this, SLOT(slotTableViewEndDrag()));
+ connect(c, SIGNAL(gotFocus()), this, SLOT(slotTableViewGotFocus()));
+// connect(c, SIGNAL(headerContextMenuRequest(const QPoint&)),
+// this, SLOT(tableHeaderContextMenuRequest(const QPoint&)));
+ connect(c, SIGNAL(contextMenuRequest(const QPoint&)),
+ this, SIGNAL(tableContextMenuRequest(const QPoint&)));
+
+ addChild(c, 100,100);
+ if (rect.isValid()) {//predefined size
+ QSize finalSize = c->size().expandedTo( c->sizeHint() );
+ QRect r = rect;
+ r.setSize( finalSize + QSize(0,10) );
+ moveChild( c, rect.left(), rect.top() );
+ //we're doing this instead of setGeometry(rect)
+ //because the geomenty might be saved on other system with bigger fonts :)
+ c->resize(c->sizeHint());
+// c->setGeometry(r);
+//TODO
+
+// moveChild( c, rect.left(), rect.top() ); // setGeometry(rect);
+// c->resize( finalSize );
+// c->updateGeometry();
+ }
+ c->show();
+ updateGeometry();
+ if (!rect.isValid()) {
+ c->updateGeometry();
+ c->resize(c->sizeHint());
+ }
+ int x, y;
+
+ if(m_tables.count() > 0)
+ {
+ int place = -10;
+ QDictIterator<KexiRelationViewTableContainer> it(m_tables);
+ for(; it.current(); ++it)
+ {
+ int right = (*it)->x() + (*it)->width();
+ if(right > place)
+ place = right;
+ }
+
+ x = place + 30;
+ }
+ else
+ {
+ x = 5;
+ }
+
+ y = 5;
+ QPoint p = viewportToContents(QPoint(x, y));
+ recalculateSize(p.x() + c->width(), p.y() + c->height());
+ if (!rect.isValid()) {
+ moveChild(c, x, y);
+ }
+
+ m_tables.insert(t->name(), c);
+
+ connect(c, SIGNAL(moved(KexiRelationViewTableContainer *)), this,
+ SLOT(containerMoved(KexiRelationViewTableContainer *)));
+
+ if (hasFocus()) //ok?
+ c->setFocus();
+
+ return c;
+}
+
+void
+KexiRelationView::addConnection(const SourceConnection& _conn)
+{
+ SourceConnection conn = _conn;
+ kdDebug() << "KexiRelationView::addConnection()" << endl;
+
+ KexiRelationViewTableContainer *master = m_tables[conn.masterTable];
+ KexiRelationViewTableContainer *details = m_tables[conn.detailsTable];
+ if (!master || !details)
+ return;
+
+/*! @todo what about query? */
+ KexiDB::TableSchema *masterTable = master->schema()->table();
+/*! @todo what about query? */
+ KexiDB::TableSchema *detailsTable = details->schema()->table();
+ if (!masterTable || !detailsTable)
+ return;
+
+ // ok, but we need to know where is the 'master' and where is the 'details' side:
+ KexiDB::Field *masterFld = masterTable->field(conn.masterField);
+ KexiDB::Field *detailsFld = detailsTable->field(conn.detailsField);
+ if (!masterFld || !detailsFld)
+ return;
+
+ if (!masterFld->isUniqueKey()) {
+ if (detailsFld->isUniqueKey()) {
+ //SWAP:
+ KexiDB::Field *tmpFld = masterFld;
+ masterFld = detailsFld;
+ detailsFld = tmpFld;
+ KexiDB::TableSchema *tmpTable = masterTable;
+ masterTable = detailsTable;
+ detailsTable = tmpTable;
+ KexiRelationViewTableContainer *tmp = master;
+ master = details;
+ details = tmp;
+ QString tmp_masterTable = conn.masterTable;
+ conn.masterTable = conn.detailsTable;
+ conn.detailsTable = tmp_masterTable;
+ QString tmp_masterField = conn.masterField;
+ conn.masterField = conn.detailsField;
+ conn.detailsField = tmp_masterField;
+ }
+ }
+
+// kdDebug() << "KexiRelationView::addConnection(): finalSRC = " << m_tables[conn.srcTable] << endl;
+
+ KexiRelationViewConnection *connView = new KexiRelationViewConnection(master, details, conn, this);
+ m_connectionViews.append(connView);
+ updateContents(connView->connectionRect());
+
+/*js: will be moved up to relation/query part as this is only visual class
+ KexiDB::TableSchema *mtable = m_conn->tableSchema(conn.srcTable);
+ KexiDB::TableSchema *ftable = m_conn->tableSchema(conn.rcvTable);
+ KexiDB::IndexSchema *forign = new KexiDB::IndexSchema(ftable);
+
+ forign->addField(mtable->field(conn.srcField));
+ new KexiDB::Reference(forign, mtable->primaryKey());
+*/
+#if 0
+ if(!interactive)
+ {
+ kdDebug() << "KexiRelationView::addConnection: adding self" << endl;
+ RelationList l = m_relation->projectRelations();
+ l.append(conn);
+ m_relation->updateRelationList(this, l);
+ }
+#endif
+}
+
+void
+KexiRelationView::drawContents(QPainter *p, int cx, int cy, int cw, int ch)
+{
+ KexiRelationViewConnection *cview;
+// p->translate(0, (double)contentsY());
+
+ QRect clipping(cx, cy, cw, ch);
+ for(cview = m_connectionViews.first(); cview; cview = m_connectionViews.next())
+ {
+ if(clipping.intersects(cview->oldRect() | cview->connectionRect()))
+ cview->drawConnection(p);
+ }
+}
+
+void
+KexiRelationView::slotTableScrolling(const QString& table)
+{
+ KexiRelationViewTableContainer *c = m_tables[table];
+
+ if(c)
+ containerMoved(c);
+}
+
+void
+KexiRelationView::containerMoved(KexiRelationViewTableContainer *c)
+{
+ KexiRelationViewConnection *cview;
+ QRect r;
+ for (ConnectionListIterator it(m_connectionViews); ((cview=it.current())); ++it) {
+//! @todo optimize
+ if(cview->masterTable() == c || cview->detailsTable() == c
+ || cview->connectionRect().intersects(r))
+ {
+ r |= cview->oldRect();
+ kdDebug() << r << endl;
+ r |= cview->connectionRect();
+ kdDebug() << r << endl;
+ }
+// updateContents(cview->oldRect());
+// updateContents(cview->connectionRect());
+// }
+ }
+//! @todo optimize!
+//didn't work well: updateContents(r);
+ updateContents();
+
+// QRect w(c->x() - 5, c->y() - 5, c->width() + 5, c->height() + 5);
+// updateContents(w);
+
+ QPoint p = viewportToContents(QPoint(c->x(), c->y()));
+ recalculateSize(p.x() + c->width(), p.y() + c->height());
+
+ emit tablePositionChanged(c);
+}
+
+void
+KexiRelationView::setReadOnly(bool b)
+{
+ m_readOnly=b;
+//TODO
+// invalidateActions();
+/* TableList::Iterator it, end( m_tables.end() );
+ for ( it=m_tables.begin(); it != end; ++it)
+ {
+// (*it)->setReadOnly(b);
+#ifndef Q_WS_WIN
+ #warning readonly needed
+#endif
+ }*/
+}
+
+void
+KexiRelationView::slotListUpdate(QObject *)
+{
+#if 0
+ if(s != this)
+ {
+ m_connectionViews.clear();
+ RelationList rl = m_relation->projectRelations();
+ if(!rl.isEmpty())
+ {
+ RelationList::ConstIterator it, end( rl.constEnd() );
+ for( it = rl.begin(); it != end; ++it)
+ {
+ addConnection((*it), true);
+ }
+ }
+ }
+
+ updateContents();
+#endif
+}
+
+void
+KexiRelationView::contentsMousePressEvent(QMouseEvent *ev)
+{
+ KexiRelationViewConnection *cview;
+ for(cview = m_connectionViews.first(); cview; cview = m_connectionViews.next())
+ {
+ if(!cview->matchesPoint(ev->pos(), 3))
+ continue;
+ clearSelection();
+ setFocus();
+ cview->setSelected(true);
+ updateContents(cview->connectionRect());
+ m_selectedConnection = cview;
+ emit connectionViewGotFocus();
+// invalidateActions();
+
+ if(ev->button() == RightButton) {//show popup
+ kdDebug() << "KexiRelationView::contentsMousePressEvent(): context" << endl;
+// QPopupMenu m;
+// m_removeSelectedTableQueryAction->plug( &m );
+// m_removeSelectedConnectionAction->plug( &m );
+ emit connectionContextMenuRequest( ev->globalPos() );
+// executePopup( ev->globalPos() );
+ }
+ return;
+ }
+ //connection not found
+ clearSelection();
+// invalidateActions();
+ if(ev->button() == RightButton) {//show popup on view background area
+// QPopupMenu m;
+// m_removeSelectedConnectionAction->plug( &m );
+ emit emptyAreaContextMenuRequest( ev->globalPos() );
+// executePopup(ev->globalPos());
+ }
+ else {
+ emit emptyAreaGotFocus();
+ }
+ setFocus();
+// QScrollView::contentsMousePressEvent(ev);
+}
+
+void KexiRelationView::clearSelection()
+{
+ if (m_focusedTableView) {
+ m_focusedTableView->unsetFocus();
+ m_focusedTableView = 0;
+// setFocus();
+// invalidateActions();
+ }
+ if (m_selectedConnection) {
+ m_selectedConnection->setSelected(false);
+ updateContents(m_selectedConnection->connectionRect());
+ m_selectedConnection = 0;
+// invalidateActions();
+ }
+}
+
+void
+KexiRelationView::keyPressEvent(QKeyEvent *ev)
+{
+ kdDebug() << "KexiRelationView::keyPressEvent()" << endl;
+
+ if (ev->key()==KGlobalSettings::contextMenuKey()) {
+ if (m_selectedConnection) {
+ emit connectionContextMenuRequest(
+ mapToGlobal(m_selectedConnection->connectionRect().center()) );
+ }
+// m_popup->exec( mapToGlobal( m_focusedTableView ? m_focusedTableView->pos() + m_focusedTableView->rect().center() : rect().center() ) );
+// executePopup();
+ }
+ else {
+ if(ev->key() == Key_Delete)
+ removeSelectedObject();
+ }
+}
+
+void
+KexiRelationView::recalculateSize(int width, int height)
+{
+ kdDebug() << "recalculateSize(" << width << ", " << height << ")" << endl;
+ int newW = contentsWidth(), newH = contentsHeight();
+ kdDebug() << "contentsSize(" << newW << ", " << newH << ")" << endl;
+
+ if(newW < width)
+ newW = width;
+
+ if(newH < height)
+ newH = height;
+
+ resizeContents(newW, newH);
+}
+
+/*! Resizes contents to size exactly enough to fit tableViews.
+ Executed on every tableView's drop event.
+*/
+void
+KexiRelationView::stretchExpandSize()
+{
+ int max_x=-1, max_y=-1;
+ QDictIterator<KexiRelationViewTableContainer> it(m_tables);
+ for (;it.current(); ++it) {
+ if (it.current()->right()>max_x)
+ max_x = it.current()->right();
+ if (it.current()->bottom()>max_y)
+ max_y = it.current()->bottom();
+ }
+ QPoint p = viewportToContents(QPoint(max_x, max_y) + QPoint(3,3)); //3 pixels margin
+ resizeContents(p.x(), p.y());
+}
+
+void KexiRelationView::slotTableViewEndDrag()
+{
+ kdDebug() << "END DRAG!" <<endl;
+ stretchExpandSize();
+
+}
+
+void
+KexiRelationView::removeSelectedObject()
+{
+ if (m_selectedConnection) {
+ removeConnection(m_selectedConnection);
+
+#if 0
+ RelationList l = m_relation->projectRelations();
+ RelationList nl;
+ for(RelationList::Iterator it = l.begin(); it != l.end(); ++it)
+ {
+ if((*it).srcTable == m_selectedConnection->connection().srcTable
+ && (*it).rcvTable == m_selectedConnection->connection().rcvTable
+ && (*it).srcField == m_selectedConnection->connection().srcField
+ && (*it).rcvField == m_selectedConnection->connection().rcvField)
+ {
+ kdDebug() << "KexiRelationView::removeSelectedConnection(): matching found!" << endl;
+// l.remove(it);
+ }
+ else
+ {
+ nl.append(*it);
+ }
+ }
+
+ kdDebug() << "KexiRelationView::removeSelectedConnection(): d2" << endl;
+ m_relation->updateRelationList(this, nl);
+ kdDebug() << "KexiRelationView::removeSelectedConnection(): d3" << endl;
+#endif
+ delete m_selectedConnection;
+ m_selectedConnection = 0;
+// invalidateActions();
+ }
+ else if (m_focusedTableView) {
+ KexiRelationViewTableContainer *tmp = m_focusedTableView;
+ m_focusedTableView = 0;
+ hideTable(tmp);
+ }
+}
+
+void
+KexiRelationView::hideTable(KexiRelationViewTableContainer* tableView)
+{
+/*! @todo what about query? */
+ KexiDB::TableSchema *ts = tableView->schema()->table();
+ //for all connections: find and remove all connected with this table
+ QPtrListIterator<KexiRelationViewConnection> it(m_connectionViews);
+ for (;it.current();) {
+ if (it.current()->masterTable() == tableView
+ || it.current()->detailsTable() == tableView)
+ {
+ //remove this
+ removeConnection(it.current());
+ }
+ else {
+ ++it;
+ }
+ }
+ m_tables.take(tableView->schema()->name());
+ delete tableView;
+ emit tableHidden( *ts );
+}
+
+void
+KexiRelationView::hideAllTablesExcept( KexiDB::TableSchema::List* tables )
+{
+//! @todo what about queries?
+ for (TablesDictIterator it(m_tables); it.current();) {
+ KexiDB::TableSchema *table = it.current()->schema()->table();
+ if (!table || tables->findRef( table )!=-1) {
+ ++it;
+ continue;
+ }
+ hideTable(it.current());
+ }
+}
+
+void
+KexiRelationView::removeConnection(KexiRelationViewConnection *conn)
+{
+ emit aboutConnectionRemove(conn);
+ m_connectionViews.remove(conn);
+ updateContents(conn->connectionRect());
+ kdDebug() << "KexiRelationView::removeConnection()" << endl;
+}
+
+void KexiRelationView::slotTableViewGotFocus()
+{
+ if (m_focusedTableView == sender())
+ return;
+ kdDebug() << "GOT FOCUS!" <<endl;
+ clearSelection();
+// if (m_focusedTableView)
+// m_focusedTableView->unsetFocus();
+ m_focusedTableView = (KexiRelationViewTableContainer*)sender();
+// invalidateActions();
+ emit tableViewGotFocus();
+}
+
+QSize KexiRelationView::sizeHint() const
+{
+ return QSize(QScrollView::sizeHint());//.width(), 600);
+}
+
+void KexiRelationView::clear()
+{
+ removeAllConnections();
+ m_tables.setAutoDelete(true);
+ m_tables.clear();
+ m_tables.setAutoDelete(false);
+ updateContents();
+}
+
+void KexiRelationView::removeAllConnections()
+{
+ clearSelection(); //sanity
+ m_connectionViews.setAutoDelete(true);
+ m_connectionViews.clear();
+ m_connectionViews.setAutoDelete(false);
+ updateContents();
+}
+
+/*
+
+void KexiRelationView::tableHeaderContextMenuRequest(const QPoint& pos)
+{
+ if (m_focusedTableView != sender())
+ return;
+ kdDebug() << "HEADER CTXT MENU!" <<endl;
+ invalidateActions();
+ m_tableQueryPopup->exec(pos);
+}
+
+//! Invalidates all actions availability
+void KexiRelationView::invalidateActions()
+{
+ setAvailable("edit_delete", m_selectedConnection || m_focusedTableView);
+}
+
+void KexiRelationView::executePopup( QPoint pos )
+{
+ if (pos==QPoint(-1,-1)) {
+ pos = mapToGlobal( m_focusedTableView ? m_focusedTableView->pos() + m_focusedTableView->rect().center() : rect().center() );
+ }
+ if (m_focusedTableView)
+ m_tableQueryPopup->exec(pos);
+ else if (m_selectedConnection)
+ m_connectionPopup->exec(pos);
+}
+*/
+
+#include "kexirelationview.moc"
diff --git a/kexi/widget/relations/kexirelationview.h b/kexi/widget/relations/kexirelationview.h
new file mode 100644
index 00000000..2de6620d
--- /dev/null
+++ b/kexi/widget/relations/kexirelationview.h
@@ -0,0 +1,167 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003-2004, 2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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.
+*/
+
+#ifndef KEXIRELATIONVIEW_H
+#define KEXIRELATIONVIEW_H
+
+#include <qguardedptr.h>
+#include <qscrollview.h>
+#include <qptrlist.h>
+#include <qdict.h>
+
+#include <kexidb/tableschema.h>
+
+#include "kexirelationviewconnection.h"
+
+class QFrame;
+
+class KexiRelationViewTable;
+class KexiRelationViewTableContainer;
+class KAction;
+class KPopupMenu;
+
+namespace KexiDB
+{
+ class Reference;
+ class Connection;
+}
+
+typedef QDict<KexiRelationViewTableContainer> TablesDict;
+typedef QDictIterator<KexiRelationViewTableContainer> TablesDictIterator;
+typedef QPtrList<KexiRelationViewConnection> ConnectionList;
+typedef QPtrListIterator<KexiRelationViewConnection> ConnectionListIterator;
+
+struct SourceConnection
+{
+ QString masterTable;
+ QString detailsTable;
+ QString masterField;
+ QString detailsField;
+};
+
+/*! @short provides a view for displaying relations between database tables.
+
+ It is currently used for two purposes:
+ - displaying global database relations
+ - displaying relations defined for a database query
+
+ The class is for displaying only - retrieving data and updating data on the backend side is implemented
+ in KexiRelationWidget, and more specifically in: Kexi Relation Part and Kexi Query Part.
+*/
+class KEXIRELATIONSVIEW_EXPORT KexiRelationView : public QScrollView
+{
+ Q_OBJECT
+
+ public:
+ KexiRelationView(QWidget *parent, const char *name=0);
+ virtual ~KexiRelationView();
+
+ //! \return a dictionary of added tables
+ TablesDict* tables() { return &m_tables; }
+
+ /*! Adds a table \a t to the area. This changes only visual representation.
+ If \a rect is valid, table widget geometry will be initialized.
+ \return added table container or 0 on failure.
+ */
+ KexiRelationViewTableContainer* addTableContainer(KexiDB::TableSchema *t,
+ const QRect &rect = QRect());
+
+ /*! \return table container for table \a t. */
+ KexiRelationViewTableContainer * tableContainer(KexiDB::TableSchema *t) const;
+
+ //! Adds a connection \a con to the area. This changes only visual representation.
+ void addConnection(const SourceConnection& _conn /*, bool interactive=true*/);
+
+ void setReadOnly(bool);
+
+ inline KexiRelationViewConnection* selectedConnection() const { return m_selectedConnection; }
+
+ inline KexiRelationViewTableContainer* focusedTableView() const { return m_focusedTableView; }
+
+ virtual QSize sizeHint() const;
+
+ const ConnectionList* connections() const { return &m_connectionViews; }
+
+// KexiRelationViewTableContainer* containerForTable(KexiDB::TableSchema* tableSchema);
+
+ signals:
+ void tableContextMenuRequest( const QPoint& pos );
+ void connectionContextMenuRequest( const QPoint& pos );
+ void emptyAreaContextMenuRequest( const QPoint& pos );
+ void tableViewGotFocus();
+ void connectionViewGotFocus();
+ void emptyAreaGotFocus();
+ void tableHidden(KexiDB::TableSchema& t);
+ void tablePositionChanged(KexiRelationViewTableContainer*);
+ void aboutConnectionRemove(KexiRelationViewConnection*);
+
+ public slots:
+ //! Clears current selection - table/query or connection
+ void clearSelection();
+
+ /*! Removes all tables and connections from the view.
+ Does not emit signals like tableHidden(). */
+ void clear();
+
+ /*! Removes all coonections from the view. */
+ void removeAllConnections();
+
+ /*! Hides all tables except \a tables. */
+ void hideAllTablesExcept( KexiDB::TableSchema::List* tables );
+
+ void slotTableScrolling(const QString&);
+
+ //! removes selected table or connection
+ void removeSelectedObject();
+
+
+ protected slots:
+ void containerMoved(KexiRelationViewTableContainer *c);
+ void slotListUpdate(QObject *s);
+ void slotTableViewEndDrag();
+ void slotTableViewGotFocus();
+
+ protected:
+// /*! executes popup menu at \a pos, or,
+// if \a pos not specified: at center of selected table view (if any selected),
+// or at center point of the relations view. */
+// void executePopup( QPoint pos = QPoint(-1,-1) );
+
+ void drawContents(QPainter *p, int cx, int cy, int cw, int ch);
+ void contentsMousePressEvent(QMouseEvent *ev);
+ virtual void keyPressEvent(QKeyEvent *ev);
+
+ void recalculateSize(int width, int height);
+ void stretchExpandSize();
+// void invalidateActions();
+// void clearTableSelection();
+// void clearConnSelection();
+
+ void hideTable(KexiRelationViewTableContainer* tableView);
+ void removeConnection(KexiRelationViewConnection *conn);
+
+ TablesDict m_tables;
+ bool m_readOnly;
+ ConnectionList m_connectionViews;
+ KexiRelationViewConnection* m_selectedConnection;
+ QGuardedPtr<KexiRelationViewTableContainer> m_focusedTableView;
+};
+
+#endif
diff --git a/kexi/widget/relations/kexirelationviewconnection.cpp b/kexi/widget/relations/kexirelationviewconnection.cpp
new file mode 100644
index 00000000..2c27de87
--- /dev/null
+++ b/kexi/widget/relations/kexirelationviewconnection.cpp
@@ -0,0 +1,298 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004-2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 <qpainter.h>
+#include <qpixmap.h>
+#include <qcolor.h>
+#include <qapplication.h>
+#include <qpointarray.h>
+
+#include <kdebug.h>
+
+#include <math.h>
+
+#include "kexirelationview.h"
+#include "kexirelationviewtable.h"
+#include "kexirelationviewconnection.h"
+#include <kexidb/tableschema.h>
+#include <kexidb/utils.h>
+#include <core/kexi.h>
+
+//#include "r1.xpm"
+//#include "rn.xpm"
+
+KexiRelationViewConnection::KexiRelationViewConnection(
+ KexiRelationViewTableContainer *masterTbl, KexiRelationViewTableContainer *detailsTbl,
+ SourceConnection &c, KexiRelationView *parent)
+{
+ m_parent = parent;
+// kdDebug() << "KexiRelationViewConnection::KexiRelationViewConnection()" << endl;
+
+ m_masterTable = masterTbl;
+ if(!masterTbl || !detailsTbl)
+ {
+ kdDebug() << "KexiRelationViewConnection::KexiRelationViewConnection(): expect sig11" << endl;
+ kdDebug() << "KexiRelationViewConnection::KexiRelationViewConnection()" << masterTbl << endl;
+ kdDebug() << "KexiRelationViewConnection::KexiRelationViewConnection()" << detailsTbl << endl;
+ }
+
+ m_detailsTable = detailsTbl;
+ m_masterField = c.masterField;
+ m_detailsField = c.detailsField;
+
+ m_selected = false;
+}
+
+KexiRelationViewConnection::~KexiRelationViewConnection()
+{
+}
+
+void
+KexiRelationViewConnection::drawConnection(QPainter *p)
+{
+ p->setPen(m_parent->palette().active().foreground());
+ int sx = m_masterTable->x() + m_masterTable->width() + m_parent->contentsX();
+ int sy = m_masterTable->globalY(m_masterField);
+ int rx = m_detailsTable->x() + m_parent->contentsX();
+ int ry = m_detailsTable->globalY(m_detailsField);
+
+ QFont f( Kexi::smallFont( m_parent ) );
+ QFontMetrics fm(f);
+ int side1x=0, side1y=sy - fm.height(),
+ sideNx=0, sideNy=ry - fm.height();
+//! @todo details char can be also just a '1' for some cases
+ QChar sideNChar(0x221E); //infinity char
+ uint sideNCharWidth = 2+2+ fm.width( sideNChar );
+ QChar side1Char('1');
+ uint side1CharWidth = 2+2+ fm.width( side1Char );
+ p->setBrush(p->pen().color());
+
+ if(m_masterTable->x() < m_detailsTable->x())
+ {
+ //det. side
+ p->drawLine(rx - sideNCharWidth, ry, rx, ry);
+ QPointArray pa(3);
+ pa.setPoint(0, rx - 4, ry - 3);
+ pa.setPoint(1, rx - 4, ry + 3);
+ pa.setPoint(2, rx - 1, ry);
+ p->drawPolygon(pa, true);
+
+ //master side
+ p->drawLine(sx, sy - 1, sx + side1CharWidth -1, sy - 1);
+ p->drawLine(sx, sy, sx + side1CharWidth -1, sy);
+ p->drawLine(sx, sy + 1, sx + side1CharWidth -1, sy + 1);
+
+ side1x = sx;
+// side1y = sy - 7;
+
+ sideNx = rx - sideNCharWidth - 1;
+// sideNy = ry - 6;
+
+ QPen pen(p->pen());
+ if(m_selected)
+ {
+ QPen pen(p->pen());
+ pen.setWidth(2);
+ p->setPen(pen);
+ }
+
+ p->drawLine(sx + side1CharWidth, sy, rx - sideNCharWidth, ry);
+
+ if(m_selected)
+ {
+ QPen pen(p->pen());
+ pen.setWidth(1);
+ p->setPen(pen);
+ }
+
+ }
+ else
+ {
+ int lx = rx + m_detailsTable->width();
+ int rx = sx - m_masterTable->width();
+
+ //det. side
+ p->drawLine(lx, ry, lx + sideNCharWidth, ry);
+ QPointArray pa(3);
+ pa.setPoint(0, lx + 3, ry - 3);
+ pa.setPoint(1, lx + 3, ry + 3);
+ pa.setPoint(2, lx, ry);
+ p->drawPolygon(pa, true);
+
+// p->drawLine(lx, ry, lx + 8, ry);
+// p->drawPoint(lx + 1, ry - 1);
+// p->drawPoint(lx + 1, ry + 1);
+// p->drawLine(lx + 2, ry - 2, lx + 2, ry + 2);
+
+ //master side
+ p->drawLine(rx - side1CharWidth +1, sy - 1, rx, sy - 1);
+ p->drawLine(rx - side1CharWidth +1, sy + 1, rx, sy + 1);
+ p->drawLine(rx - side1CharWidth +1, sy, rx, sy);
+
+ side1x = rx - side1CharWidth;
+// side1y = sy - 7;
+
+ sideNx = lx + 1;
+// sideNy = ry - 6;
+
+ if(m_selected)
+ {
+ QPen pen(p->pen());
+ pen.setWidth(2);
+ p->setPen(pen);
+ }
+
+ p->drawLine(lx + sideNCharWidth, ry, rx - side1CharWidth, sy);
+
+ if(m_selected)
+ {
+ QPen pen(p->pen());
+ pen.setWidth(1);
+ p->setPen(pen);
+ }
+ }
+
+ p->drawText(side1x, side1y, side1CharWidth, fm.height(), Qt::AlignCenter, side1Char);
+ p->drawText(sideNx, sideNy, sideNCharWidth, fm.height(), Qt::AlignCenter, sideNChar);
+ //p->drawRect(QRect(connectionRect().topLeft(), QSize(50,50)));
+// p->drawPixmap(side1, QPixmap(r1_xpm));
+// p->drawPixmap(sideN, QPixmap(rn_xpm));
+}
+
+const QRect
+KexiRelationViewConnection::connectionRect()
+{
+ int sx = m_masterTable->x() + m_parent->contentsX();
+ int rx = m_detailsTable->x() + m_parent->contentsX();
+ int ry = m_detailsTable->globalY(m_detailsField);
+ int sy = m_masterTable->globalY(m_masterField);
+
+ int width, leftX, rightX;
+
+ if(sx < rx)
+ {
+ leftX = sx;
+ rightX = rx;
+ width = m_masterTable->width();
+ }
+ else
+ {
+ leftX = rx;
+ rightX = sx;
+ width = m_detailsTable->width();
+ }
+
+
+ int dx = QABS((leftX + width) - rightX);
+ int dy = QABS(sy - ry) + 2;
+
+ int top = QMIN(sy, ry);
+ int left = leftX + width;
+
+
+// return QRect(sx - 1, sy - 1, (rx + m_detailsTable->width()) - sx + 1, ry - sy + 1);
+ QRect rect(left - 150, top - 150, dx + 150, dy + 150);
+// kdDebug() << "KexiRelationViewConnection::connectionRect():" << m_oldRect << "," << rect << endl;
+
+ m_oldRect = rect;
+
+ return rect;
+}
+
+bool
+KexiRelationViewConnection::matchesPoint(const QPoint &p, int tolerance)
+{
+ QRect we = connectionRect();
+
+ if(!we.contains(p))
+ return false;
+
+ /** get our coordinats
+ * you know what i mean the x1, y1 is the top point
+ * and the x2, y2 is the bottom point
+ * (quite tirvial :) although that was the entrace to the magic
+ * gate...
+ */
+
+ int sx = m_masterTable->x() + m_masterTable->width();
+ int sy = m_masterTable->globalY(m_masterField);
+ int rx = m_detailsTable->x();
+ int ry = m_detailsTable->globalY(m_detailsField);
+
+ int x1 = sx + 8;
+ int y1 = sy;
+ int x2 = rx - 8;
+ int y2 = ry;
+
+ if(sx > rx)
+ {
+ x1 = m_detailsTable->x() + m_detailsTable->width();
+ x2 = m_masterTable->x();
+ y2 = sy;
+ y1 = ry;
+ }
+
+ /*
+ here we call pythagoras (the greek math geek :p)
+ see: http://w1.480.telia.com/%7Eu48019406/geekporn.gif if you don't know
+ how these people have got sex :)
+ */
+ float mx = x2-x1;
+ float my = y2-y1;
+ float mag = sqrt(mx * mx + my * my);
+ float u = (((p.x() - x1)*(x2 - x1))+((p.y() - y1)*(y2 - y1)))/(mag * mag);
+ kdDebug() << "KexiRelationViewConnection::matchesPoint(): u: " << u << endl;
+
+ float iX = x1 + u * (x2 - x1);
+ float iY = y1 + u * (y2 - y1);
+ kdDebug() << "KexiRelationViewConnection::matchesPoint(): px: " << p.x() << endl;
+ kdDebug() << "KexiRelationViewConnection::matchesPoint(): py: " << p.y() << endl;
+ kdDebug() << "KexiRelationViewConnection::matchesPoint(): ix: " << iX << endl;
+ kdDebug() << "KexiRelationViewConnection::matchesPoint(): iy: " << iY << endl;
+
+ float dX = iX - p.x();
+ float dY = iY - p.y();
+
+ kdDebug() << "KexiRelationViewConnection::matchesPoint(): dx: " << dX << endl;
+ kdDebug() << "KexiRelationViewConnection::matchesPoint(): dy: " << dY << endl;
+
+ float distance = sqrt(dX * dX + dY * dY);
+ kdDebug() << "KexiRelationViewConnection::matchesPoint(): distance: " << distance << endl;
+
+ if(distance <= tolerance)
+ return true;
+
+ return false;
+}
+
+QString
+KexiRelationViewConnection::toString() const
+{
+ QString str;
+/*! @todo what about query? */
+ if (m_masterTable && m_masterTable->schema()->table()) {
+ str += (QString(m_masterTable->schema()->name()) + "." + m_masterField);
+ }
+ if (m_detailsTable && m_detailsTable->schema()->table()) {
+ str += " - ";
+ str += (QString(m_detailsTable->schema()->name()) + "." + m_detailsField);
+ }
+ return str;
+}
diff --git a/kexi/widget/relations/kexirelationviewconnection.h b/kexi/widget/relations/kexirelationviewconnection.h
new file mode 100644
index 00000000..699fdf4f
--- /dev/null
+++ b/kexi/widget/relations/kexirelationviewconnection.h
@@ -0,0 +1,75 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
+ Copyright (C) 2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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.
+*/
+
+#ifndef KEXIRELATIONVIEWCONNECTION_H
+#define KEXIRELATIONVIEWCONNECTION_H
+
+#include <qstring.h>
+#include <qguardedptr.h>
+
+class QPainter;
+class KexiRelationViewTableContainer;
+class KexiRelationView;
+
+class KEXIRELATIONSVIEW_EXPORT KexiRelationViewConnection
+{
+ public:
+
+ KexiRelationViewConnection(KexiRelationViewTableContainer *masterTbl,
+ KexiRelationViewTableContainer *detailsTbl, struct SourceConnection &s, KexiRelationView *parent);
+ ~KexiRelationViewConnection();
+
+
+ /*
+ C++PROGRAMMIERER bestehen darauf, da�der Elefant eine Klasse sei,
+ und somit schlie�ich seine Fang-Methoden selbst mitzubringen habe.
+
+ http://www.c-plusplus.de ;)
+ */
+ void drawConnection(QPainter *p);
+
+ bool selected() { return m_selected; }
+ void setSelected(bool s) { m_selected = s; }
+
+ const QRect connectionRect();
+ const QRect oldRect() const { return m_oldRect; }
+
+ KexiRelationViewTableContainer *masterTable() { return m_masterTable; }
+ KexiRelationViewTableContainer *detailsTable() { return m_detailsTable; }
+ QString masterField() const { return m_masterField; }
+ QString detailsField() const { return m_detailsField; }
+
+
+ bool matchesPoint(const QPoint &p, int tolerance=3);
+// SourceConnection connection() { return m_conn; }
+
+ QString toString() const;
+
+ private:
+ QGuardedPtr<KexiRelationViewTableContainer> m_masterTable;
+ QGuardedPtr<KexiRelationViewTableContainer> m_detailsTable;
+ QString m_masterField;
+ QString m_detailsField;
+ QRect m_oldRect;
+ bool m_selected;
+ QGuardedPtr<KexiRelationView> m_parent;
+};
+
+#endif
diff --git a/kexi/widget/relations/kexirelationviewtable.cpp b/kexi/widget/relations/kexirelationviewtable.cpp
new file mode 100644
index 00000000..97beaa87
--- /dev/null
+++ b/kexi/widget/relations/kexirelationviewtable.cpp
@@ -0,0 +1,429 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 <stdlib.h>
+
+#include <qheader.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcursor.h>
+#include <qpoint.h>
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qstyle.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kdeversion.h>
+#include <kconfig.h>
+#include <kglobalsettings.h>
+
+#include <kexidb/tableschema.h>
+#include <kexidb/utils.h>
+#include <kexidragobjects.h>
+#include "kexirelationviewtable.h"
+#include "kexirelationview.h"
+
+KexiRelationViewTableContainer::KexiRelationViewTableContainer(
+ KexiRelationView *parent, KexiDB::TableOrQuerySchema *schema)
+ : QFrame(parent,"KexiRelationViewTableContainer" )
+// , m_table(t)
+ , m_parent(parent)
+// , m_mousePressed(false)
+{
+
+// setFixedSize(100, 150);
+//js: resize(100, 150);
+ //setMouseTracking(true);
+
+ setFrameStyle( QFrame::WinPanel | QFrame::Raised );
+
+ QVBoxLayout *lyr = new QVBoxLayout(this,4,1); //js: using Q*BoxLayout is a good idea
+
+ m_tableHeader = new KexiRelationViewTableContainerHeader(schema->name(), this);
+
+ m_tableHeader->unsetFocus();
+ m_tableHeader->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed));
+ lyr->addWidget(m_tableHeader);
+ connect(m_tableHeader,SIGNAL(moved()),this,SLOT(moved()));
+ connect(m_tableHeader, SIGNAL(endDrag()), this, SIGNAL(endDrag()));
+
+ m_tableView = new KexiRelationViewTable(schema, parent, this, "KexiRelationViewTable");
+ //m_tableHeader->setFocusProxy( m_tableView );
+ m_tableView->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
+
+ m_tableView->setMaximumSize( m_tableView->sizeHint() );
+
+// m_tableView->resize( m_tableView->sizeHint() );
+ lyr->addWidget(m_tableView, 0);
+ connect(m_tableView, SIGNAL(tableScrolling()), this, SLOT(moved()));
+ connect(m_tableView, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)),
+ this, SLOT(slotContextMenu(KListView*, QListViewItem*, const QPoint&)));
+}
+
+KexiRelationViewTableContainer::~KexiRelationViewTableContainer()
+{
+}
+
+KexiDB::TableOrQuerySchema* KexiRelationViewTableContainer::schema() const
+{
+ return m_tableView->schema();
+}
+
+void KexiRelationViewTableContainer::slotContextMenu(KListView *, QListViewItem *, const QPoint &p)
+{
+// m_parent->executePopup(p);
+ emit contextMenuRequest( p );
+}
+
+void KexiRelationViewTableContainer::moved() {
+// kdDebug()<<"finally emitting moved"<<endl;
+ emit moved(this);
+}
+
+int KexiRelationViewTableContainer::globalY(const QString &field)
+{
+// kdDebug() << "KexiRelationViewTableContainer::globalY()" << endl;
+// QPoint o = mapFromGlobal(QPoint(0, (m_tableView->globalY(field))/*+m_parent->contentsY()*/));
+
+ QPoint o(0, (m_tableView->globalY(field)) + m_parent->contentsY());
+// kdDebug() << "KexiRelationViewTableContainer::globalY() db2" << endl;
+ return m_parent->viewport()->mapFromGlobal(o).y();
+}
+
+#if 0//js
+QSize KexiRelationViewTableContainer::sizeHint()
+{
+#ifdef Q_WS_WIN
+ QSize s = m_tableView->sizeHint()
+ + QSize( 2 * 5 , m_tableHeader->height() + 2 * 5 );
+#else
+ QSize s = m_tableView->sizeHint();
+ s.setWidth(s.width() + 4);
+ s.setHeight(m_tableHeader->height() + s.height());
+#endif
+ return s;
+}
+#endif
+
+void KexiRelationViewTableContainer::setFocus()
+{
+ kdDebug() << "SET FOCUS" << endl;
+ //select 1st:
+ if (m_tableView->firstChild()) {
+ if (!m_tableView->selectedItems().first())
+ m_tableView->setSelected( m_tableView->firstChild(), true );
+ }
+ m_tableHeader->setFocus();
+ m_tableView->setFocus();
+/* QPalette p = qApp->palette();
+ p.setColor( QPalette::Active, QColorGroup::Highlight, KGlobalSettings::highlightColor() );
+ p.setColor( QPalette::Active, QColorGroup::HighlightedText, KGlobalSettings::highlightedTextColor() );
+ m_tableView->setPalette(p);*/
+
+ raise();
+ repaint();
+ emit gotFocus();
+}
+
+void KexiRelationViewTableContainer::unsetFocus()
+{
+ kdDebug() << "UNSET FOCUS" << endl;
+// if (m_tableView->selectedItem()) //unselect item if was selected
+// m_tableView->setSelected(m_tableView->selectedItem(), false);
+// m_tableView->clearSelection();
+ m_tableHeader->unsetFocus();
+
+ m_tableView->clearSelection();
+
+// m_tableView->unsetPalette();
+/* QPalette p = m_tableView->palette();
+// p.setColor( QPalette::Active, QColorGroup::Highlight, KGlobalSettings::highlightColor() );
+// p.setColor( QPalette::Active, QColorGroup::HighlightedText, KGlobalSettings::highlightedTextColor() );
+ p.setColor( QPalette::Active, QColorGroup::Highlight, p.color(QPalette::Active, QColorGroup::Background ) );
+// p.setColor( QPalette::Active, QColorGroup::Highlight, gray );
+ p.setColor( QPalette::Active, QColorGroup::HighlightedText, p.color(QPalette::Active, QColorGroup::Foreground ) );
+// p.setColor( QPalette::Active, QColorGroup::Highlight, green );
+// p.setColor( QPalette::Active, QColorGroup::HighlightedText, blue );
+ m_tableView->setPalette(p);*/
+
+ clearFocus();
+ repaint();
+}
+
+
+//END KexiRelationViewTableContainer
+
+//============================================================================
+//BEGIN KexiRelatoinViewTableContainerHeader
+
+KexiRelationViewTableContainerHeader::KexiRelationViewTableContainerHeader(
+ const QString& text,QWidget *parent)
+ :QLabel(text,parent),m_dragging(false)
+{
+ setMargin(1);
+ m_activeBG = KGlobalSettings::activeTitleColor();
+ m_activeFG = KGlobalSettings::activeTextColor();
+ m_inactiveBG = KGlobalSettings::inactiveTitleColor();
+ m_inactiveFG = KGlobalSettings::inactiveTextColor();
+
+ installEventFilter(this);
+}
+
+KexiRelationViewTableContainerHeader::~KexiRelationViewTableContainerHeader()
+{
+}
+
+void KexiRelationViewTableContainerHeader::setFocus()
+{
+ setPaletteBackgroundColor(m_activeBG);
+ setPaletteForegroundColor(m_activeFG);
+}
+
+void KexiRelationViewTableContainerHeader::unsetFocus()
+{
+ setPaletteBackgroundColor(m_inactiveBG);
+ setPaletteForegroundColor(m_inactiveFG);
+}
+
+bool KexiRelationViewTableContainerHeader::eventFilter(QObject *, QEvent *ev)
+{
+ if (ev->type()==QEvent::MouseMove)
+ {
+ if (m_dragging && static_cast<QMouseEvent*>(ev)->state()==Qt::LeftButton) {
+ int diffX,diffY;
+ diffX=static_cast<QMouseEvent*>(ev)->globalPos().x()-m_grabX;
+ diffY=static_cast<QMouseEvent*>(ev)->globalPos().y()-m_grabY;
+ if ((abs(diffX)>2) || (abs(diffY)>2))
+ {
+ QPoint newPos=parentWidget()->pos()+QPoint(diffX,diffY);
+//correct the x position
+ if (newPos.x()<0) {
+ m_offsetX+=newPos.x();
+ newPos.setX(0);
+ }
+ else if (m_offsetX<0) {
+ m_offsetX+=newPos.x();
+ if (m_offsetX>0) {
+ newPos.setX(m_offsetX);
+ m_offsetX=0;
+ }
+ else newPos.setX(0);
+ }
+//correct the y position
+ if (newPos.y()<0) {
+ m_offsetY+=newPos.y();
+ newPos.setY(0);
+ }
+ else
+ if (m_offsetY<0) {
+ m_offsetY+=newPos.y();
+ if (m_offsetY>0) {
+ newPos.setY(m_offsetY);
+ m_offsetY=0;
+ }
+ else newPos.setY(0);
+ }
+//move and update helpers
+
+ parentWidget()->move(newPos);
+ m_grabX=static_cast<QMouseEvent*>(ev)->globalPos().x();
+ m_grabY=static_cast<QMouseEvent*>(ev)->globalPos().y();
+// kdDebug()<<"HEADER:emitting moved"<<endl;
+ emit moved();
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void KexiRelationViewTableContainerHeader::mousePressEvent(QMouseEvent *ev) {
+ kdDebug()<<"KexiRelationViewTableContainerHeader::Mouse Press Event"<<endl;
+ parentWidget()->setFocus();
+ ev->accept();
+ if (ev->button()==Qt::LeftButton) {
+ m_dragging=true;
+ m_grabX=ev->globalPos().x();
+ m_grabY=ev->globalPos().y();
+ m_offsetX=0;
+ m_offsetY=0;
+ setCursor(Qt::SizeAllCursor);
+ return;
+ }
+ if (ev->button()==Qt::RightButton) {
+ emit static_cast<KexiRelationViewTableContainer*>(parentWidget())
+ ->contextMenuRequest(ev->globalPos());
+ }
+// QLabel::mousePressEvent(ev);
+}
+
+void KexiRelationViewTableContainerHeader::mouseReleaseEvent(QMouseEvent *ev) {
+ kdDebug()<<"KexiRelationViewTableContainerHeader::Mouse Release Event"<<endl;
+ if (m_dragging && ev->button() & Qt::LeftButton) {
+ setCursor(Qt::ArrowCursor);
+ m_dragging=false;
+ emit endDrag();
+ }
+ ev->accept();
+}
+
+//END KexiRelatoinViewTableContainerHeader
+
+
+//=====================================================================================
+
+KexiRelationViewTable::KexiRelationViewTable(KexiDB::TableOrQuerySchema* tableOrQuerySchema,
+ KexiRelationView *view, QWidget *parent, const char *name)
+ : KexiFieldListView(parent, name, KexiFieldListView::ShowAsterisk)
+ , m_view(view)
+{
+ setSchema(tableOrQuerySchema);
+ header()->hide();
+
+ connect(this, SIGNAL(dropped(QDropEvent *, QListViewItem *)), this, SLOT(slotDropped(QDropEvent *)));
+ connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotContentsMoving(int,int)));
+}
+
+KexiRelationViewTable::~KexiRelationViewTable()
+{
+}
+
+QSize KexiRelationViewTable::sizeHint() const
+{
+ QFontMetrics fm(fontMetrics());
+
+// kdDebug() << schema()->name() << " cw=" << columnWidth(0) + fm.width("i")
+// << ", " << fm.width(schema()->name()+" ") << endl;
+
+ int maxWidth = -1;
+ const int iconWidth = IconSize(KIcon::Small) + fm.width("i")+20;
+ for (QListViewItem *item = firstChild(); item; item = item->nextSibling())
+ maxWidth = QMAX(maxWidth, iconWidth + fm.width(item->text(0)));
+
+ const uint rowCount = QMIN( 8, childCount() );
+
+ QSize s(
+ QMAX( maxWidth, fm.width(schema()->name()+" ")),
+ rowCount*firstChild()->totalHeight() + 4 );
+ return s;
+}
+
+#if 0
+void KexiRelationViewTable::setReadOnly(bool b)
+{
+ setAcceptDrops(!b);
+ viewport()->setAcceptDrops(!b);
+}
+#endif
+
+int
+KexiRelationViewTable::globalY(const QString &item)
+{
+ QListViewItem *i = findItem(item, 0);
+ if (!i)
+ return -1;
+ int y = itemRect(i).y() + (itemRect(i).height() / 2);
+ if (contentsY() > itemPos(i))
+ y = 0;
+ else if (y == 0)
+ y = height();
+ return mapToGlobal(QPoint(0, y)).y();
+}
+
+bool
+KexiRelationViewTable::acceptDrag(QDropEvent *ev) const
+{
+// kdDebug() << "KexiRelationViewTable::acceptDrag()" << endl;
+ QListViewItem *receiver = itemAt(ev->pos() - QPoint(0,contentsY()));
+ if (!receiver || !KexiFieldDrag::canDecodeSingle(ev))
+ return false;
+ QString sourceMimeType;
+ QString srcTable;
+ QString srcField;
+ if (!KexiFieldDrag::decodeSingle(ev,sourceMimeType,srcTable,srcField))
+ return false;
+ if (sourceMimeType!="kexi/table" && sourceMimeType=="kexi/query")
+ return false;
+ QString f = receiver->text(0).stripWhiteSpace();
+ if (!srcField.stripWhiteSpace().startsWith("*") && !f.startsWith("*") && ev->source() != (QWidget*)this)
+ return true;
+
+ return false;
+}
+
+void
+KexiRelationViewTable::slotDropped(QDropEvent *ev)
+{
+ QListViewItem *recever = itemAt(ev->pos() - QPoint(0,contentsY()));
+ if (!recever || !KexiFieldDrag::canDecodeSingle(ev)) {
+ ev->ignore();
+ return;
+ }
+ QString sourceMimeType;
+ QString srcTable;
+ QString srcField;
+ if (!KexiFieldDrag::decodeSingle(ev,sourceMimeType,srcTable,srcField))
+ return;
+ if (sourceMimeType!="kexi/table" && sourceMimeType=="kexi/query")
+ return;
+// kdDebug() << "KexiRelationViewTable::slotDropped() srcfield: " << srcField << endl;
+
+ QString rcvField = recever->text(0);
+
+ SourceConnection s;
+ s.masterTable = srcTable;
+ s.detailsTable = schema()->name();
+ s.masterField = srcField;
+ s.detailsField = rcvField;
+
+ m_view->addConnection(s);
+
+ kdDebug() << "KexiRelationViewTable::slotDropped() " << srcTable << ":" << srcField << " "
+ << schema()->name() << ":" << rcvField << endl;
+ ev->accept();
+}
+
+void
+KexiRelationViewTable::slotContentsMoving(int,int)
+{
+ emit tableScrolling();
+}
+
+void KexiRelationViewTable::contentsMousePressEvent(QMouseEvent *ev)
+{
+ parentWidget()->setFocus();
+ setFocus();
+ KListView::contentsMousePressEvent(ev);
+// if (ev->button()==Qt::RightButton)
+// static_cast<KexiRelationView*>(parentWidget())->executePopup(ev->pos());
+}
+
+QRect KexiRelationViewTable::drawItemHighlighter(QPainter *painter, QListViewItem *item)
+{
+ if (painter) {
+ style().drawPrimitive(QStyle::PE_FocusRect, painter, itemRect(item), colorGroup(),
+ QStyle::Style_FocusAtBorder);
+ }
+ return itemRect(item);
+}
+
+#include "kexirelationviewtable.moc"
diff --git a/kexi/widget/relations/kexirelationviewtable.h b/kexi/widget/relations/kexirelationviewtable.h
new file mode 100644
index 00000000..cc90e16d
--- /dev/null
+++ b/kexi/widget/relations/kexirelationviewtable.h
@@ -0,0 +1,157 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
+
+ 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.
+*/
+
+#ifndef KEXIRELATIONVIEWTABLE_H
+#define KEXIRELATIONVIEWTABLE_H
+
+#include <qframe.h>
+#include <qstringlist.h>
+#include <qlabel.h>
+#include <klistview.h>
+
+#include <widget/kexifieldlistview.h>
+
+class KexiRelationView;
+class KexiRelationViewTable;
+class KexiRelationViewTableContainerHeader;
+
+namespace KexiDB
+{
+ class TableOrQuerySchema;
+}
+
+class KEXIRELATIONSVIEW_EXPORT KexiRelationViewTableContainer : public QFrame
+{
+ Q_OBJECT
+
+ public:
+// KexiRelationViewTableContainer(KexiRelationView *parent, KexiDB::TableSchema *t);
+ KexiRelationViewTableContainer(
+ KexiRelationView *parent, KexiDB::TableOrQuerySchema *schema);
+
+ virtual ~KexiRelationViewTableContainer();
+
+ int globalY(const QString &field);
+// KexiDB::TableSchema *table();
+
+ KexiRelationViewTable* tableView() const { return m_tableView; }
+ KexiDB::TableOrQuerySchema* schema() const;
+
+ int right() { return x() + width() - 1; }
+ int bottom() { return y() + height() - 1; }
+
+ signals:
+ void moved(KexiRelationViewTableContainer *);
+ void endDrag();
+ void gotFocus();
+ void contextMenuRequest(const QPoint& pos);
+
+ public slots:
+ virtual void setFocus();
+ virtual void unsetFocus();
+
+ protected slots:
+ void moved();
+ void slotContextMenu(KListView *lv, QListViewItem *i, const QPoint& p);
+
+ protected:
+// KexiDB::TableSchema *m_table;
+ KexiRelationViewTableContainerHeader *m_tableHeader;
+ KexiRelationViewTable *m_tableView;
+ KexiRelationView *m_parent;
+
+ friend class KexiRelationViewTableContainerHeader;
+};
+
+/*
+class KEXIRELATIONSVIEW_EXPORT KexiRelationViewTableItem : public KListViewItem
+{
+ public:
+ KexiRelationViewTableItem(QListView *parent, QListViewItem *after,
+ QString key, QString field);
+ virtual void paintFocus ( QPainter * p, const QColorGroup & cg, const QRect & r );
+};*/
+
+
+class KEXIRELATIONSVIEW_EXPORT KexiRelationViewTable : public KexiFieldListView
+{
+ Q_OBJECT
+
+ public:
+ KexiRelationViewTable(KexiDB::TableOrQuerySchema* tableOrQuerySchema,
+ KexiRelationView *view, QWidget *parent, const char *name = 0);
+// KexiRelationViewTable(QWidget *parent, KexiRelationView *view, KexiDB::TableSchema *t, const char *name=0);
+ virtual ~KexiRelationViewTable();
+
+// KexiDB::TableSchema *table() const { return m_table; };
+ int globalY(const QString &item);
+// void setReadOnly(bool);
+ virtual QSize sizeHint() const;
+
+ signals:
+ void tableScrolling();
+
+ protected slots:
+ void slotDropped(QDropEvent *e);
+ void slotContentsMoving(int, int);
+// void slotItemDoubleClicked( QListViewItem *i, const QPoint &, int );
+
+ protected:
+ virtual void contentsMousePressEvent( QMouseEvent * e );
+ virtual bool acceptDrag(QDropEvent *e) const;
+//moved virtual QDragObject *dragObject();
+ virtual QRect drawItemHighlighter(QPainter *painter, QListViewItem *item);
+
+ private:
+// QStringList m_fieldList;
+// KexiDB::TableSchema *m_table;
+ KexiRelationView *m_view;
+// QPixmap m_keyIcon, m_noIcon;
+};
+
+class KEXIRELATIONSVIEW_EXPORT KexiRelationViewTableContainerHeader : public QLabel
+{
+ Q_OBJECT
+ public:
+ KexiRelationViewTableContainerHeader(const QString& text,QWidget *parent);
+ virtual ~KexiRelationViewTableContainerHeader();
+
+ virtual void setFocus();
+ virtual void unsetFocus();
+
+ signals:
+ void moved();
+ void endDrag();
+
+ protected:
+ bool eventFilter(QObject *obj, QEvent *ev);
+ void mousePressEvent(QMouseEvent *ev);
+ void mouseReleaseEvent(QMouseEvent *ev);
+
+ bool m_dragging;
+ int m_grabX;
+ int m_grabY;
+ int m_offsetX;
+ int m_offsetY;
+
+ QColor m_activeBG, m_activeFG, m_inactiveBG, m_inactiveFG;
+};
+
+#endif
diff --git a/kexi/widget/relations/kexirelationwidget.cpp b/kexi/widget/relations/kexirelationwidget.cpp
new file mode 100644
index 00000000..14ec4ce0
--- /dev/null
+++ b/kexi/widget/relations/kexirelationwidget.cpp
@@ -0,0 +1,425 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org>
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexirelationwidget.h"
+
+#include <qlayout.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+#include <qtimer.h>
+
+#include <kcombobox.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+
+#include <kexidb/connection.h>
+#include <kexidb/utils.h>
+
+#include <kexiproject.h>
+#include <keximainwindow.h>
+#include "kexirelationview.h"
+#include "kexirelationviewtable.h"
+#include "kexirelationviewconnection.h"
+
+KexiRelationWidget::KexiRelationWidget(KexiMainWindow *win, QWidget *parent,
+ const char *name)
+ : KexiViewBase(win, parent, name)
+ , m_win(win)
+{
+ m_conn = m_win->project()->dbConnection();
+
+ QHBoxLayout *hlyr = new QHBoxLayout(0);
+ QGridLayout *g = new QGridLayout(this);
+ g->addLayout( hlyr, 0, 0 );
+
+ m_tableCombo = new KComboBox(this, "tables_combo");
+ m_tableCombo->setMinimumWidth(QFontMetrics(font()).width("w")*20);
+ QLabel *lbl = new QLabel(m_tableCombo, i18n("Table")+": ", this);
+ lbl->setIndent(3);
+ m_tableCombo->setInsertionPolicy(QComboBox::NoInsertion);
+ hlyr->addWidget(lbl);
+ hlyr->addWidget(m_tableCombo);
+ m_tableCombo->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred));
+ fillTablesCombo();
+
+ m_btnAdd = new KPushButton(i18n("&Add"), this);
+ hlyr->addWidget(m_btnAdd);
+ hlyr->addStretch(1);
+ connect(m_btnAdd, SIGNAL(clicked()), this, SLOT(slotAddTable()));
+
+ m_relationView = new KexiRelationView(this, "relation_view");
+ setViewWidget(m_relationView);
+ g->addWidget(m_relationView, 1, 0);
+ //m_relationView->setFocus();
+
+ //actions
+ m_tableQueryPopup = new KPopupMenu(this, "m_popup");
+ m_tableQueryPopupTitleID = m_tableQueryPopup->insertTitle(SmallIcon("table"), "");
+ connect(m_tableQueryPopup, SIGNAL(aboutToShow()), this, SLOT(aboutToShowPopupMenu()));
+
+ m_connectionPopup = new KPopupMenu(this, "m_connectionPopup");
+ m_connectionPopupTitleID = m_connectionPopup->insertTitle("");
+ connect(m_connectionPopup, SIGNAL(aboutToShow()), this, SLOT(aboutToShowPopupMenu()));
+
+ m_areaPopup = new KPopupMenu(this, "m_areaPopup");
+
+ m_openSelectedTableAction = new KAction(i18n("&Open Table"), SmallIcon("fileopen"), KShortcut(),
+ this, SLOT(openSelectedTable()), this, "relationsview_openTable");
+ m_openSelectedTableAction->plug( m_tableQueryPopup );
+ m_designSelectedTableAction = new KAction(i18n("&Design Table"), SmallIcon("edit"), KShortcut(),
+ this, SLOT(designSelectedTable()), this, "relationsview_designTable");
+ m_designSelectedTableAction->plug( m_tableQueryPopup );
+ m_tableQueryPopup->insertSeparator();
+
+ KAction* hide_action = plugSharedAction("edit_delete", i18n("&Hide Table"), m_tableQueryPopup);
+ hide_action->setIconSet(QIconSet());
+
+ plugSharedAction("edit_delete",m_connectionPopup);
+ plugSharedAction("edit_delete",this, SLOT(removeSelectedObject()));
+
+ connect(m_relationView, SIGNAL(tableViewGotFocus()),
+ this, SLOT(tableViewGotFocus()));
+ connect(m_relationView, SIGNAL(connectionViewGotFocus()),
+ this, SLOT(connectionViewGotFocus()));
+ connect(m_relationView, SIGNAL(emptyAreaGotFocus()),
+ this, SLOT(emptyAreaGotFocus()));
+ connect(m_relationView, SIGNAL(tableContextMenuRequest( const QPoint& )),
+ this, SLOT(tableContextMenuRequest( const QPoint& )));
+ connect(m_relationView, SIGNAL(connectionContextMenuRequest( const QPoint& )),
+ this, SLOT(connectionContextMenuRequest( const QPoint& )));
+ connect(m_relationView, SIGNAL(tableHidden(KexiDB::TableSchema&)),
+ this, SLOT(slotTableHidden(KexiDB::TableSchema&)));
+ connect(m_relationView, SIGNAL(tablePositionChanged(KexiRelationViewTableContainer*)),
+ this, SIGNAL(tablePositionChanged(KexiRelationViewTableContainer*)));
+ connect(m_relationView, SIGNAL(aboutConnectionRemove(KexiRelationViewConnection*)),
+ this, SIGNAL(aboutConnectionRemove(KexiRelationViewConnection*)));
+
+#if 0
+ if(!embedd)
+ {
+/*todo setContextHelp(i18n("Relations"), i18n("To create a relationship simply drag the source field onto the target field. "
+ "An arrowhead is used to show which table is the parent (master) and which table is the child (slave) in the relationship."));*/
+ }
+#endif
+// else
+//js: while embedding means read-only? m_relationView->setReadOnly(true);
+
+#ifdef TESTING_KexiRelationWidget
+ for (int i=0;i<(int)m_db->tableNames().count();i++)
+ QTimer::singleShot(100,this,SLOT(slotAddTable()));
+#endif
+
+ invalidateActions();
+}
+
+KexiRelationWidget::~KexiRelationWidget()
+{
+}
+
+TablesDict* KexiRelationWidget::tables() const
+{
+ return m_relationView->tables();
+}
+
+KexiRelationViewTableContainer* KexiRelationWidget::table(const QString& name) const
+{
+ return m_relationView->tables()->find( name );
+}
+
+const ConnectionList* KexiRelationWidget::connections() const
+{
+ return m_relationView->connections();
+}
+
+void
+KexiRelationWidget::slotAddTable()
+{
+ if (m_tableCombo->currentItem()==-1)
+ return;
+ QString tname = m_tableCombo->text(m_tableCombo->currentItem());
+ KexiDB::TableSchema *t = m_conn->tableSchema(tname);
+ addTable(t);
+}
+
+void
+KexiRelationWidget::addTable(KexiDB::TableSchema *t, const QRect &rect)
+{
+ if (!t)
+ return;
+ if (!m_relationView->tableContainer(t)) {
+ KexiRelationViewTableContainer *c = m_relationView->addTableContainer(t, rect);
+ kdDebug() << "KexiRelationWidget::slotAddTable(): adding table " << t->name() << endl;
+ if (!c)
+ return;
+ connect(c->tableView(), SIGNAL(doubleClicked(QListViewItem*,const QPoint&,int)),
+ this, SLOT(slotTableFieldDoubleClicked(QListViewItem*,const QPoint&,int)));
+ }
+
+ const QString tname = t->name().lower();
+ const int count = m_tableCombo->count();
+ int i = 0;
+ for (; i < count; i++ ) {
+ if (m_tableCombo->text(i).lower() == tname )
+ break;
+ }
+ if (i<count) {
+ int oi = m_tableCombo->currentItem();
+ kdDebug()<<"KexiRelationWidget::slotAddTable(): removing a table from the combo box"<<endl;
+ m_tableCombo->removeItem(i);
+ if (m_tableCombo->count()>0) {
+ if (oi>=m_tableCombo->count()) {
+ oi=m_tableCombo->count()-1;
+ }
+ m_tableCombo->setCurrentItem(oi);
+ }
+ else {
+ m_tableCombo->setEnabled(false);
+ m_btnAdd->setEnabled(false);
+ }
+ }
+ emit tableAdded(*t);
+}
+
+void
+KexiRelationWidget::addConnection(const SourceConnection& conn)
+{
+ m_relationView->addConnection(conn);
+}
+
+void
+KexiRelationWidget::addTable(const QString& t)
+{
+ for(int i=0; i < m_tableCombo->count(); i++)
+ {
+ if(m_tableCombo->text(i) == t)
+ {
+ m_tableCombo->setCurrentItem(i);
+ slotAddTable();
+ }
+ }
+}
+
+void KexiRelationWidget::tableViewGotFocus()
+{
+// if (m_relationView->focusedTableView == sender())
+// return;
+// kdDebug() << "GOT FOCUS!" <<endl;
+// clearSelection();
+// if (m_focusedTableView)
+// m_focusedTableView->unsetFocus();
+// m_focusedTableView = (KexiRelationViewTableContainer*)sender();
+ invalidateActions();
+}
+
+void KexiRelationWidget::connectionViewGotFocus()
+{
+ invalidateActions();
+}
+
+void KexiRelationWidget::emptyAreaGotFocus()
+{
+ invalidateActions();
+}
+
+void KexiRelationWidget::tableContextMenuRequest(const QPoint& pos)
+{
+ invalidateActions();
+ executePopup( pos );
+}
+
+void KexiRelationWidget::connectionContextMenuRequest(const QPoint& pos)
+{
+ invalidateActions();
+ executePopup( pos );
+// m_connectionPopup->exec(pos);
+}
+
+void KexiRelationWidget::emptyAreaContextMenuRequest( const QPoint& /*pos*/ )
+{
+ invalidateActions();
+ //TODO
+}
+
+void KexiRelationWidget::invalidateActions()
+{
+ setAvailable("edit_delete", m_relationView->selectedConnection() || m_relationView->focusedTableView());
+}
+
+void KexiRelationWidget::executePopup( QPoint pos )
+{
+ if (pos==QPoint(-1,-1)) {
+ pos = mapToGlobal(
+ m_relationView->focusedTableView() ? m_relationView->focusedTableView()->pos() + m_relationView->focusedTableView()->rect().center() : rect().center() );
+ }
+ if (m_relationView->focusedTableView())
+ m_tableQueryPopup->exec(pos);
+ else if (m_relationView->selectedConnection())
+ m_connectionPopup->exec(pos);
+}
+
+void KexiRelationWidget::removeSelectedObject()
+{
+ m_relationView->removeSelectedObject();
+}
+
+void KexiRelationWidget::openSelectedTable()
+{
+/*! @todo what about query? */
+ if (!m_relationView->focusedTableView() || !m_relationView->focusedTableView()->schema()->table())
+ return;
+ bool openingCancelled;
+ m_win->openObject("kexi/table", m_relationView->focusedTableView()->schema()->name(),
+ Kexi::DataViewMode, openingCancelled);
+}
+
+void KexiRelationWidget::designSelectedTable()
+{
+/*! @todo what about query? */
+ if (!m_relationView->focusedTableView() || !m_relationView->focusedTableView()->schema()->table())
+ return;
+ bool openingCancelled;
+ m_win->openObject("kexi/table", m_relationView->focusedTableView()->schema()->name(),
+ Kexi::DesignViewMode, openingCancelled);
+}
+
+QSize KexiRelationWidget::sizeHint() const
+{
+ return m_relationView->sizeHint();
+}
+
+void KexiRelationWidget::slotTableHidden(KexiDB::TableSchema &table)
+{
+ const QString &t = table.name().lower();
+ int i;
+ for (i=0; i<m_tableCombo->count() && t > m_tableCombo->text(i).lower(); i++)
+ ;
+ m_tableCombo->insertItem(table.name(), i);
+ if (!m_tableCombo->isEnabled()) {
+ m_tableCombo->setCurrentItem(0);
+ m_tableCombo->setEnabled(true);
+ m_btnAdd->setEnabled(true);
+ }
+
+ emit tableHidden(table);
+}
+
+void KexiRelationWidget::aboutToShowPopupMenu()
+{
+/*! @todo what about query? */
+ if (m_relationView->focusedTableView() && m_relationView->focusedTableView()->schema()->table()) {
+ m_tableQueryPopup->changeTitle(m_tableQueryPopupTitleID, SmallIcon("table"),
+ QString(m_relationView->focusedTableView()->schema()->name()) + " : " + i18n("Table"));
+ }
+ else if (m_relationView->selectedConnection()) {
+ m_connectionPopup->changeTitle( m_connectionPopupTitleID,
+ m_relationView->selectedConnection()->toString() + " : " + i18n("Relationship") );
+ }
+}
+
+void
+KexiRelationWidget::slotTableFieldDoubleClicked(QListViewItem *i,const QPoint&,int)
+{
+ if (!sender()->isA("KexiRelationViewTable"))
+ return;
+ const KexiRelationViewTable* t = static_cast<const KexiRelationViewTable*>(sender());
+ const QStringList selectedFieldNames( t->selectedFieldNames() );
+ if (selectedFieldNames.count()==1)
+ emit tableFieldDoubleClicked( t->schema()->table(), selectedFieldNames.first() );
+}
+
+void
+KexiRelationWidget::clear()
+{
+ m_relationView->clear();
+ fillTablesCombo();
+}
+
+/*! Removes all coonections from the view. */
+void KexiRelationWidget::removeAllConnections()
+{
+ m_relationView->removeAllConnections();
+}
+
+void
+KexiRelationWidget::fillTablesCombo()
+{
+ m_tableCombo->clear();
+ QStringList tmp = m_conn->tableNames();
+ tmp.sort();
+ m_tableCombo->insertStringList(tmp);
+}
+
+void
+KexiRelationWidget::objectCreated(const QCString &mime, const QCString& name)
+{
+ if (mime=="kexi/table" || mime=="kexi/query") {
+//! @todo query?
+ m_tableCombo->insertItem(QString(name));
+ m_tableCombo->listBox()->sort();
+ }
+}
+
+void
+KexiRelationWidget::objectDeleted(const QCString &mime, const QCString& name)
+{
+ if (mime=="kexi/table" || mime=="kexi/query") {
+ QString strName(name);
+ for (int i=0; i<m_tableCombo->count(); i++) {
+//! @todo query?
+ if (m_tableCombo->text(i)==strName) {
+ m_tableCombo->removeItem(i);
+ if (m_tableCombo->currentItem()==i) {
+ if (i==(m_tableCombo->count()-1))
+ m_tableCombo->setCurrentItem(i-1);
+ else
+ m_tableCombo->setCurrentItem(i);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void
+KexiRelationWidget::objectRenamed(const QCString &mime, const QCString& name, const QCString& newName)
+{
+ if (mime=="kexi/table" || mime=="kexi/query") {
+ QString strName(name);
+ for (int i=0; i<m_tableCombo->count(); i++) {
+//! @todo query?
+ if (m_tableCombo->text(i)==strName) {
+ m_tableCombo->changeItem(QString(newName), i);
+ m_tableCombo->listBox()->sort();
+ break;
+ }
+ }
+ }
+}
+
+void
+KexiRelationWidget::hideAllTablesExcept( KexiDB::TableSchema::List* tables )
+{
+ m_relationView->hideAllTablesExcept(tables);
+}
+
+#include "kexirelationwidget.moc"
diff --git a/kexi/widget/relations/kexirelationwidget.h b/kexi/widget/relations/kexirelationwidget.h
new file mode 100644
index 00000000..3beb0b34
--- /dev/null
+++ b/kexi/widget/relations/kexirelationwidget.h
@@ -0,0 +1,137 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
+
+ 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.
+*/
+
+#ifndef KEXIRELATIONWIDGET_H
+#define KEXIRELATIONWIDGET_H
+
+//#include <qwidget.h>
+//#include "kexiactionproxy.h"
+#include "kexiviewbase.h"
+#include "kexirelationview.h"
+
+class KComboBox;
+class KPushButton;
+class KPopupMenu;
+class KAction;
+class QListViewItem;
+
+class KexiMainWindow;
+
+namespace KexiDB
+{
+ class Connection;
+ class TableSchema;
+ class Reference;
+}
+
+class KEXIRELATIONSVIEW_EXPORT KexiRelationWidget : public KexiViewBase
+{
+ Q_OBJECT
+
+ public:
+ KexiRelationWidget(KexiMainWindow *win, QWidget *parent, const char *name=0);
+ virtual ~KexiRelationWidget();
+
+ //! \return a dictionary of added tables
+ TablesDict* tables() const;
+ KexiRelationViewTableContainer* table(const QString& name) const;
+ const ConnectionList* connections() const;
+
+// KexiRelationView *relationView() const { return m_relationView; }
+ void addTable(const QString& t);
+
+// void openTable(KexiDB::TableSchema* table, bool designMode);
+
+ virtual QSize sizeHint() const;
+
+ /*! Used to add newly created object information to the combo box. */
+ void objectCreated(const QCString &mime, const QCString& name);
+ void objectDeleted(const QCString &mime, const QCString& name);
+ void objectRenamed(const QCString &mime, const QCString& name, const QCString& newName);
+
+ signals:
+ void tableAdded(KexiDB::TableSchema& t);
+ void tableHidden(KexiDB::TableSchema& t);
+ void tablePositionChanged(KexiRelationViewTableContainer*);
+ void aboutConnectionRemove(KexiRelationViewConnection*);
+ void tableFieldDoubleClicked( KexiDB::TableSchema* table, const QString& fieldName );
+
+ public slots:
+ /*! Adds a table \a t to the area. This changes only visual representation.
+ If \a rect is valid, table widget rgeometry will be initialized.
+ */
+ void addTable(KexiDB::TableSchema *t, const QRect &rect = QRect());
+
+ //! Adds a connection \a con to the area. This changes only visual representation.
+ void addConnection(const SourceConnection& conn);
+
+ void removeSelectedObject();
+
+ /*! Removes all tables and coonections from the widget. */
+ void clear();
+
+ /*! Removes all coonections from the view. */
+ void removeAllConnections();
+
+ /*! Hides all tables except \a tables. */
+ void hideAllTablesExcept( KexiDB::TableSchema::List* tables );
+
+ protected slots:
+ void slotAddTable();
+ void tableViewGotFocus();
+ void connectionViewGotFocus();
+ void emptyAreaGotFocus();
+ void tableContextMenuRequest(const QPoint& pos);
+ void connectionContextMenuRequest(const QPoint& pos);
+ void emptyAreaContextMenuRequest( const QPoint& pos );
+ void openSelectedTable();
+ void designSelectedTable();
+ void slotTableHidden(KexiDB::TableSchema &table);
+ void aboutToShowPopupMenu();
+ void slotTableFieldDoubleClicked(QListViewItem *i,const QPoint&,int);
+
+ protected:
+ /*! executes popup menu at \a pos, or,
+ if \a pos not specified: at center of selected table view (if any selected),
+ or at center point of the relations view. */
+ void executePopup( QPoint pos = QPoint(-1,-1) );
+
+ //! Invalidates all actions availability.
+ void invalidateActions();
+
+ //! Fills table's combo box with all available table names.
+ void fillTablesCombo();
+
+ private:
+ KexiMainWindow *m_win;
+ KComboBox *m_tableCombo;
+ KPushButton *m_btnAdd;
+ KexiRelationView *m_relationView;
+ KexiDB::Connection *m_conn;
+
+ KPopupMenu *m_tableQueryPopup //over table/query
+ , *m_connectionPopup //over connection
+ , *m_areaPopup; //over outer area
+ KAction *m_openSelectedTableAction, *m_designSelectedTableAction;
+
+ int m_tableQueryPopupTitleID, m_connectionPopupTitleID;
+};
+
+#endif
diff --git a/kexi/widget/relations/r1.xpm b/kexi/widget/relations/r1.xpm
new file mode 100644
index 00000000..11b8dc66
--- /dev/null
+++ b/kexi/widget/relations/r1.xpm
@@ -0,0 +1,10 @@
+/* XPM */
+static const char * r1_xpm[] = {
+"2 5 2 1",
+" c None",
+". c #000000",
+" .",
+"..",
+" .",
+" .",
+" ."};
diff --git a/kexi/widget/relations/rn.xpm b/kexi/widget/relations/rn.xpm
new file mode 100644
index 00000000..d721e5f5
--- /dev/null
+++ b/kexi/widget/relations/rn.xpm
@@ -0,0 +1,9 @@
+/* XPM */
+static const char * rn_xpm[] = {
+"7 4 2 1",
+" c None",
+". c #000000",
+" .. .. ",
+". . .",
+". . .",
+" .. .. "};