diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/widget/relations | |
download | koffice-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.am | 38 | ||||
-rw-r--r-- | kexi/widget/relations/kexirelationview.cpp | 639 | ||||
-rw-r--r-- | kexi/widget/relations/kexirelationview.h | 167 | ||||
-rw-r--r-- | kexi/widget/relations/kexirelationviewconnection.cpp | 298 | ||||
-rw-r--r-- | kexi/widget/relations/kexirelationviewconnection.h | 75 | ||||
-rw-r--r-- | kexi/widget/relations/kexirelationviewtable.cpp | 429 | ||||
-rw-r--r-- | kexi/widget/relations/kexirelationviewtable.h | 157 | ||||
-rw-r--r-- | kexi/widget/relations/kexirelationwidget.cpp | 425 | ||||
-rw-r--r-- | kexi/widget/relations/kexirelationwidget.h | 137 | ||||
-rw-r--r-- | kexi/widget/relations/r1.xpm | 10 | ||||
-rw-r--r-- | kexi/widget/relations/rn.xpm | 9 |
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", +" .. .. ", +". . .", +". . .", +" .. .. "}; |