You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/kexi/widget/relations/kexirelationviewconnection.cpp

299 lines
8.0 KiB

/* 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;
}