kexirelationviewtable.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002, 2003 Lucijan Busch <lucijan@gmx.at>
3 Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <stdlib.h>
22
23#include <tqheader.h>
24#include <tqlayout.h>
25#include <tqlabel.h>
26#include <tqpushbutton.h>
27#include <tqcursor.h>
28#include <tqpoint.h>
29#include <tqapplication.h>
30#include <tqbitmap.h>
31#include <tqstyle.h>
32
33#include <kdebug.h>
34#include <kiconloader.h>
35#include <tdeversion.h>
36#include <tdeconfig.h>
37#include <tdeglobalsettings.h>
38
39#include <kexidb/tableschema.h>
40#include <kexidb/utils.h>
41#include <kexidragobjects.h>
42#include "kexirelationviewtable.h"
43#include "kexirelationview.h"
44
45KexiRelationViewTableContainer::KexiRelationViewTableContainer(
47 : TQFrame(parent,"KexiRelationViewTableContainer" )
48// , m_table(t)
49 , m_parent(parent)
50// , m_mousePressed(false)
51{
52
53// setFixedSize(100, 150);
54//js: resize(100, 150);
55 //setMouseTracking(true);
56
57 setFrameStyle( TQFrame::WinPanel | TQFrame::Raised );
58
59 TQVBoxLayout *lyr = new TQVBoxLayout(this,4,1); //js: using Q*BoxLayout is a good idea
60
61 m_tableHeader = new KexiRelationViewTableContainerHeader(schema->name(), this);
62
63 m_tableHeader->unsetFocus();
64 m_tableHeader->setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Fixed));
65 lyr->addWidget(m_tableHeader);
66 connect(m_tableHeader,TQ_SIGNAL(moved()),this,TQ_SLOT(moved()));
67 connect(m_tableHeader, TQ_SIGNAL(endDrag()), this, TQ_SIGNAL(endDrag()));
68
69 m_tableView = new KexiRelationViewTable(schema, parent, this, "KexiRelationViewTable");
70 //m_tableHeader->setFocusProxy( m_tableView );
71 m_tableView->setSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum));
72
73 m_tableView->setMaximumSize( m_tableView->sizeHint() );
74
75// m_tableView->resize( m_tableView->sizeHint() );
76 lyr->addWidget(m_tableView, 0);
77 connect(m_tableView, TQ_SIGNAL(tableScrolling()), this, TQ_SLOT(moved()));
78 connect(m_tableView, TQ_SIGNAL(contextMenu(TDEListView*, TQListViewItem*, const TQPoint&)),
79 this, TQ_SLOT(slotContextMenu(TDEListView*, TQListViewItem*, const TQPoint&)));
80}
81
82KexiRelationViewTableContainer::~KexiRelationViewTableContainer()
83{
84}
85
86KexiDB::TableOrQuerySchema* KexiRelationViewTableContainer::schema() const
87{
88 return m_tableView->schema();
89}
90
91void KexiRelationViewTableContainer::slotContextMenu(TDEListView *, TQListViewItem *, const TQPoint &p)
92{
93// m_parent->executePopup(p);
94 emit contextMenuRequest( p );
95}
96
97void KexiRelationViewTableContainer::moved() {
98// kdDebug()<<"finally emitting moved"<<endl;
99 emit moved(this);
100}
101
102int KexiRelationViewTableContainer::globalY(const TQString &field)
103{
104// kdDebug() << "KexiRelationViewTableContainer::globalY()" << endl;
105// TQPoint o = mapFromGlobal(TQPoint(0, (m_tableView->globalY(field))/*+m_parent->contentsY()*/));
106
107 TQPoint o(0, (m_tableView->globalY(field)) + m_parent->contentsY());
108// kdDebug() << "KexiRelationViewTableContainer::globalY() db2" << endl;
109 return m_parent->viewport()->mapFromGlobal(o).y();
110}
111
112#if 0//js
113TQSize KexiRelationViewTableContainer::sizeHint()
114{
115#ifdef TQ_WS_WIN
116 TQSize s = m_tableView->sizeHint()
117 + TQSize( 2 * 5 , m_tableHeader->height() + 2 * 5 );
118#else
119 TQSize s = m_tableView->sizeHint();
120 s.setWidth(s.width() + 4);
121 s.setHeight(m_tableHeader->height() + s.height());
122#endif
123 return s;
124}
125#endif
126
127void KexiRelationViewTableContainer::setFocus()
128{
129 kdDebug() << "SET FOCUS" << endl;
130 //select 1st:
131 if (m_tableView->firstChild()) {
132 if (!m_tableView->selectedItems().first())
133 m_tableView->setSelected( m_tableView->firstChild(), true );
134 }
135 m_tableHeader->setFocus();
136 m_tableView->setFocus();
137/* TQPalette p = tqApp->palette();
138 p.setColor( TQPalette::Active, TQColorGroup::Highlight, TDEGlobalSettings::highlightColor() );
139 p.setColor( TQPalette::Active, TQColorGroup::HighlightedText, TDEGlobalSettings::highlightedTextColor() );
140 m_tableView->setPalette(p);*/
141
142 raise();
143 repaint();
144 emit gotFocus();
145}
146
147void KexiRelationViewTableContainer::unsetFocus()
148{
149 kdDebug() << "UNSET FOCUS" << endl;
150// if (m_tableView->selectedItem()) //unselect item if was selected
151// m_tableView->setSelected(m_tableView->selectedItem(), false);
152// m_tableView->clearSelection();
153 m_tableHeader->unsetFocus();
154
155 m_tableView->clearSelection();
156
157// m_tableView->unsetPalette();
158/* TQPalette p = m_tableView->palette();
159// p.setColor( TQPalette::Active, TQColorGroup::Highlight, TDEGlobalSettings::highlightColor() );
160// p.setColor( TQPalette::Active, TQColorGroup::HighlightedText, TDEGlobalSettings::highlightedTextColor() );
161 p.setColor( TQPalette::Active, TQColorGroup::Highlight, p.color(TQPalette::Active, TQColorGroup::Background ) );
162// p.setColor( TQPalette::Active, TQColorGroup::Highlight, gray );
163 p.setColor( TQPalette::Active, TQColorGroup::HighlightedText, p.color(TQPalette::Active, TQColorGroup::Foreground ) );
164// p.setColor( TQPalette::Active, TQColorGroup::Highlight, green );
165// p.setColor( TQPalette::Active, TQColorGroup::HighlightedText, blue );
166 m_tableView->setPalette(p);*/
167
168 clearFocus();
169 repaint();
170}
171
172
173//END KexiRelationViewTableContainer
174
175//============================================================================
176//BEGIN KexiRelatoinViewTableContainerHeader
177
178KexiRelationViewTableContainerHeader::KexiRelationViewTableContainerHeader(
179 const TQString& text,TQWidget *parent)
180 :TQLabel(text,parent),m_dragging(false)
181{
182 setMargin(1);
183 m_activeBG = TDEGlobalSettings::activeTitleColor();
184 m_activeFG = TDEGlobalSettings::activeTextColor();
185 m_inactiveBG = TDEGlobalSettings::inactiveTitleColor();
186 m_inactiveFG = TDEGlobalSettings::inactiveTextColor();
187
188 installEventFilter(this);
189}
190
191KexiRelationViewTableContainerHeader::~KexiRelationViewTableContainerHeader()
192{
193}
194
195void KexiRelationViewTableContainerHeader::setFocus()
196{
197 setPaletteBackgroundColor(m_activeBG);
198 setPaletteForegroundColor(m_activeFG);
199}
200
201void KexiRelationViewTableContainerHeader::unsetFocus()
202{
203 setPaletteBackgroundColor(m_inactiveBG);
204 setPaletteForegroundColor(m_inactiveFG);
205}
206
207bool KexiRelationViewTableContainerHeader::eventFilter(TQObject *, TQEvent *ev)
208{
209 if (ev->type()==TQEvent::MouseMove)
210 {
211 if (m_dragging && static_cast<TQMouseEvent*>(ev)->state()==TQt::LeftButton) {
212 int diffX,diffY;
213 diffX=static_cast<TQMouseEvent*>(ev)->globalPos().x()-m_grabX;
214 diffY=static_cast<TQMouseEvent*>(ev)->globalPos().y()-m_grabY;
215 if ((abs(diffX)>2) || (abs(diffY)>2))
216 {
217 TQPoint newPos=parentWidget()->pos()+TQPoint(diffX,diffY);
218//correct the x position
219 if (newPos.x()<0) {
220 m_offsetX+=newPos.x();
221 newPos.setX(0);
222 }
223 else if (m_offsetX<0) {
224 m_offsetX+=newPos.x();
225 if (m_offsetX>0) {
226 newPos.setX(m_offsetX);
227 m_offsetX=0;
228 }
229 else newPos.setX(0);
230 }
231//correct the y position
232 if (newPos.y()<0) {
233 m_offsetY+=newPos.y();
234 newPos.setY(0);
235 }
236 else
237 if (m_offsetY<0) {
238 m_offsetY+=newPos.y();
239 if (m_offsetY>0) {
240 newPos.setY(m_offsetY);
241 m_offsetY=0;
242 }
243 else newPos.setY(0);
244 }
245//move and update helpers
246
247 parentWidget()->move(newPos);
248 m_grabX=static_cast<TQMouseEvent*>(ev)->globalPos().x();
249 m_grabY=static_cast<TQMouseEvent*>(ev)->globalPos().y();
250// kdDebug()<<"HEADER:emitting moved"<<endl;
251 emit moved();
252 }
253 return true;
254 }
255 }
256 return false;
257}
258
259void KexiRelationViewTableContainerHeader::mousePressEvent(TQMouseEvent *ev) {
260 kdDebug()<<"KexiRelationViewTableContainerHeader::Mouse Press Event"<<endl;
261 parentWidget()->setFocus();
262 ev->accept();
263 if (ev->button()==TQt::LeftButton) {
264 m_dragging=true;
265 m_grabX=ev->globalPos().x();
266 m_grabY=ev->globalPos().y();
267 m_offsetX=0;
268 m_offsetY=0;
269 setCursor(TQt::SizeAllCursor);
270 return;
271 }
272 if (ev->button()==TQt::RightButton) {
273 emit static_cast<KexiRelationViewTableContainer*>(parentWidget())
274 ->contextMenuRequest(ev->globalPos());
275 }
276// TQLabel::mousePressEvent(ev);
277}
278
279void KexiRelationViewTableContainerHeader::mouseReleaseEvent(TQMouseEvent *ev) {
280 kdDebug()<<"KexiRelationViewTableContainerHeader::Mouse Release Event"<<endl;
281 if (m_dragging && ev->button() & TQt::LeftButton) {
282 setCursor(TQt::ArrowCursor);
283 m_dragging=false;
284 emit endDrag();
285 }
286 ev->accept();
287}
288
289//END KexiRelatoinViewTableContainerHeader
290
291
292//=====================================================================================
293
294KexiRelationViewTable::KexiRelationViewTable(KexiDB::TableOrQuerySchema* tableOrQuerySchema,
295 KexiRelationView *view, TQWidget *parent, const char *name)
296 : KexiFieldListView(parent, name, KexiFieldListView::ShowAsterisk)
297 , m_view(view)
298{
299 setSchema(tableOrQuerySchema);
300 header()->hide();
301
302 connect(this, TQ_SIGNAL(dropped(TQDropEvent *, TQListViewItem *)), this, TQ_SLOT(slotDropped(TQDropEvent *)));
303 connect(this, TQ_SIGNAL(contentsMoving(int, int)), this, TQ_SLOT(slotContentsMoving(int,int)));
304}
305
306KexiRelationViewTable::~KexiRelationViewTable()
307{
308}
309
310TQSize KexiRelationViewTable::sizeHint() const
311{
312 TQFontMetrics fm(fontMetrics());
313
314// kdDebug() << schema()->name() << " cw=" << columnWidth(0) + fm.width("i")
315// << ", " << fm.width(schema()->name()+" ") << endl;
316
317 int maxWidth = -1;
318 const int iconWidth = IconSize(TDEIcon::Small) + fm.width("i")+20;
319 for (TQListViewItem *item = firstChild(); item; item = item->nextSibling())
320 maxWidth = TQMAX(maxWidth, iconWidth + fm.width(item->text(0)));
321
322 const uint rowCount = TQMIN( 8, childCount() );
323
324 TQSize s(
325 TQMAX( maxWidth, fm.width(schema()->name()+" ")),
326 rowCount*firstChild()->totalHeight() + 4 );
327 return s;
328}
329
330#if 0
331void KexiRelationViewTable::setReadOnly(bool b)
332{
333 setAcceptDrops(!b);
334 viewport()->setAcceptDrops(!b);
335}
336#endif
337
338int
339KexiRelationViewTable::globalY(const TQString &item)
340{
341 TQListViewItem *i = findItem(item, 0);
342 if (!i)
343 return -1;
344 int y = itemRect(i).y() + (itemRect(i).height() / 2);
345 if (contentsY() > itemPos(i))
346 y = 0;
347 else if (y == 0)
348 y = height();
349 return mapToGlobal(TQPoint(0, y)).y();
350}
351
352bool
353KexiRelationViewTable::acceptDrag(TQDropEvent *ev) const
354{
355// kdDebug() << "KexiRelationViewTable::acceptDrag()" << endl;
356 TQListViewItem *receiver = itemAt(ev->pos() - TQPoint(0,contentsY()));
357 if (!receiver || !KexiFieldDrag::canDecodeSingle(ev))
358 return false;
359 TQString sourceMimeType;
360 TQString srcTable;
361 TQString srcField;
362 if (!KexiFieldDrag::decodeSingle(ev,sourceMimeType,srcTable,srcField))
363 return false;
364 if (sourceMimeType!="kexi/table" && sourceMimeType=="kexi/query")
365 return false;
366 TQString f = receiver->text(0).stripWhiteSpace();
367 if (!srcField.stripWhiteSpace().startsWith("*") && !f.startsWith("*") && ev->source() != (TQWidget*)this)
368 return true;
369
370 return false;
371}
372
373void
374KexiRelationViewTable::slotDropped(TQDropEvent *ev)
375{
376 TQListViewItem *recever = itemAt(ev->pos() - TQPoint(0,contentsY()));
377 if (!recever || !KexiFieldDrag::canDecodeSingle(ev)) {
378 ev->ignore();
379 return;
380 }
381 TQString sourceMimeType;
382 TQString srcTable;
383 TQString srcField;
384 if (!KexiFieldDrag::decodeSingle(ev,sourceMimeType,srcTable,srcField))
385 return;
386 if (sourceMimeType!="kexi/table" && sourceMimeType=="kexi/query")
387 return;
388// kdDebug() << "KexiRelationViewTable::slotDropped() srcfield: " << srcField << endl;
389
390 TQString rcvField = recever->text(0);
391
392 SourceConnection s;
393 s.masterTable = srcTable;
394 s.detailsTable = schema()->name();
395 s.masterField = srcField;
396 s.detailsField = rcvField;
397
398 m_view->addConnection(s);
399
400 kdDebug() << "KexiRelationViewTable::slotDropped() " << srcTable << ":" << srcField << " "
401 << schema()->name() << ":" << rcvField << endl;
402 ev->accept();
403}
404
405void
406KexiRelationViewTable::slotContentsMoving(int,int)
407{
408 emit tableScrolling();
409}
410
411void KexiRelationViewTable::contentsMousePressEvent(TQMouseEvent *ev)
412{
413 parentWidget()->setFocus();
414 setFocus();
415 TDEListView::contentsMousePressEvent(ev);
416// if (ev->button()==TQt::RightButton)
417// static_cast<KexiRelationView*>(parentWidget())->executePopup(ev->pos());
418}
419
420TQRect KexiRelationViewTable::drawItemHighlighter(TQPainter *painter, TQListViewItem *item)
421{
422 if (painter) {
423 style().drawPrimitive(TQStyle::PE_FocusRect, painter, itemRect(item), colorGroup(),
424 TQStyle::Style_FocusAtBorder);
425 }
426 return itemRect(item);
427}
428
429#include "kexirelationviewtable.moc"
static bool canDecodeSingle(TQMimeSource *e)
static bool decodeSingle(TQDropEvent *e, TQString &sourceMimeType, TQString &sourceName, TQString &field)
provides a view for displaying relations between database tables.
int rowCount(Connection &conn, const TQString &sql)