kexicomboboxpopup.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004-2007 Jaroslaw Staniek <js@iidea.pl>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "kexicomboboxpopup.h"
21
22#include "kexidatatableview.h"
23#include "kexitableview_p.h"
24#include "kexitableitem.h"
25#include "kexitableedit.h"
26
27#include <kexidb/lookupfieldschema.h>
28#include <kexidb/expression.h>
29#include <kexidb/parser/sqlparser.h>
30
31#include <kdebug.h>
32
33#include <tqlayout.h>
34#include <tqevent.h>
35
38class KexiComboBoxPopup_KexiTableView : public KexiDataTableView
39{
40 public:
41 KexiComboBoxPopup_KexiTableView(TQWidget* parent=0)
42 : KexiDataTableView(parent, "KexiComboBoxPopup_tv")
43 {
44 init();
45 }
46 void init()
47 {
48 setReadOnly( true );
49 setLineWidth( 0 );
50 d->moveCursorOnMouseRelease = true;
52 a.navigatorEnabled = false;
54 a.backgroundAltering = false;
55 a.fullRowSelection = true;
56 a.rowHighlightingEnabled = true;
57 a.rowMouseOverHighlightingEnabled = true;
58 a.persistentSelections = false;
59 a.rowMouseOverHighlightingColor = colorGroup().highlight();
60 a.rowMouseOverHighlightingTextColor = colorGroup().highlightedText();
61 a.rowHighlightingTextColor = a.rowMouseOverHighlightingTextColor;
62 a.gridEnabled = false;
64 setInsertingEnabled( false );
65 setSortingEnabled( false );
68 setContextMenuEnabled( false );
70 installEventFilter(this);
71 setBottomMarginInternal( - horizontalScrollBar()->sizeHint().height() );
72 }
73 virtual void setData( KexiTableViewData *data, bool owner = true )
74 { KexiTableView::setData( data, owner ); }
77};
78
79//========================================
80
82class KexiComboBoxPopupPrivate
83{
84 public:
85 KexiComboBoxPopupPrivate()
86 : int_f(0)
87 , privateQuery(0)
88 {
90 }
91 ~KexiComboBoxPopupPrivate() {
92 delete int_f;
93 delete privateQuery;
94 }
95
96 KexiComboBoxPopup_KexiTableView *tv;
97 KexiDB::Field *int_f; //TODO: remove this -temporary
98 KexiDB::QuerySchema* privateQuery;
99 int max_rows;
100};
101
102//========================================
103
105
107 : TQFrame( parent, "KexiComboBoxPopup", WType_Popup )
108{
109 init();
110 //setup tv data
111 setData(&column, 0);
112}
113
115 : TQFrame( parent, "KexiComboBoxPopup", WType_Popup )
116{
117 init();
118 //setup tv data
119 setData(0, &field);
120}
121
122KexiComboBoxPopup::~KexiComboBoxPopup()
123{
124 delete d;
125}
126
127void KexiComboBoxPopup::init()
128{
129 d = new KexiComboBoxPopupPrivate();
130 setPaletteBackgroundColor(palette().color(TQPalette::Active,TQColorGroup::Base));
131 setLineWidth( 1 );
132 setFrameStyle( Box | Plain );
133
134 d->tv = new KexiComboBoxPopup_KexiTableView(this);
135 installEventFilter(this);
136
137 connect(d->tv, TQ_SIGNAL(itemReturnPressed(KexiTableItem*,int,int)),
138 this, TQ_SLOT(slotTVItemAccepted(KexiTableItem*,int,int)));
139
140 connect(d->tv, TQ_SIGNAL(itemMouseReleased(KexiTableItem*,int,int)),
141 this, TQ_SLOT(slotTVItemAccepted(KexiTableItem*,int,int)));
142
143 connect(d->tv, TQ_SIGNAL(itemDblClicked(KexiTableItem*,int,int)),
144 this, TQ_SLOT(slotTVItemAccepted(KexiTableItem*,int,int)));
145}
146
148{
149 if (column && !field)
150 field = column->field();
151 if (!field) {
152 kexiwarn << "KexiComboBoxPopup::setData(): !field" << endl;
153 return;
154 }
155
156 // case 1: simple related data
157 if (column && column->relatedData()) {
158 d->tv->setColumnStretchEnabled( true, -1 ); //only needed when using single column
159 setDataInternal( column->relatedData(), false );
160 return;
161 }
162 // case 2: lookup field
163 KexiDB::LookupFieldSchema *lookupFieldSchema = 0;
164 if (field->table())
165 lookupFieldSchema = field->table()->lookupFieldSchema( *field );
166 delete d->privateQuery;
167 d->privateQuery = 0;
168 if (lookupFieldSchema) {
169 const TQValueList<uint> visibleColumns( lookupFieldSchema->visibleColumns() );
170 const bool multipleLookupColumnJoined = visibleColumns.count() > 1;
172 KexiDB::Cursor *cursor = 0;
173 switch (lookupFieldSchema->rowSource().type()) {
175 KexiDB::TableSchema *lookupTable
176 = field->table()->connection()->tableSchema( lookupFieldSchema->rowSource().name() );
177 if (!lookupTable)
179 return;
180 if (multipleLookupColumnJoined) {
181 kdDebug() << "--- Orig query: " << endl;
182 lookupTable->query()->debug();
183 d->privateQuery = new KexiDB::QuerySchema(*lookupTable->query());
184 }
185 else {
186 cursor = field->table()->connection()->prepareQuery( *lookupTable );
187 }
188 break;
189 }
191 KexiDB::QuerySchema *lookupQuery
192 = field->table()->connection()->querySchema( lookupFieldSchema->rowSource().name() );
193 if (!lookupQuery)
195 return;
196 if (multipleLookupColumnJoined) {
197 kdDebug() << "--- Orig query: " << endl;
198 lookupQuery->debug();
199 d->privateQuery = new KexiDB::QuerySchema(*lookupQuery);
200 }
201 else {
202 cursor = field->table()->connection()->prepareQuery( *lookupQuery );
203 }
204 break;
205 }
206 default:;
207 }
208 if (d->privateQuery) {
209 // append column computed using multiple columns
210 const KexiDB::QueryColumnInfo::Vector fieldsExpanded( d->privateQuery->fieldsExpanded() );
211 uint fieldsExpandedSize( fieldsExpanded.size() );
212 KexiDB::BaseExpr *expr = 0;
213 int count = visibleColumns.count();
214 for (TQValueList<uint>::ConstIterator it( visibleColumns.at(count-1) ); count>0; count--, --it) {
215 KexiDB::QueryColumnInfo *ci = ((*it) < fieldsExpandedSize) ? fieldsExpanded.at( *it ) : 0;
216 if (!ci) {
217 kdWarning() << "KexiComboBoxPopup::setData(): " << *it << " >= fieldsExpandedSize" << endl;
218 continue;
219 }
220 KexiDB::VariableExpr *fieldExpr
221 = new KexiDB::VariableExpr( ci->field->table()->name()+"."+ci->field->name() );
222 fieldExpr->field = ci->field;
223 fieldExpr->tablePositionForField = d->privateQuery->tableBoundToColumn( *it );
224 if (expr) {
227 KexiDB::ConstExpr *constExpr = new KexiDB::ConstExpr(CHARACTER_STRING_LITERAL, " ");
228 expr = new KexiDB::BinaryExpr(KexiDBExpr_Arithm, constExpr, CONCATENATION, expr);
229 expr = new KexiDB::BinaryExpr(KexiDBExpr_Arithm, fieldExpr, CONCATENATION, expr);
230 }
231 else
232 expr = fieldExpr;
233 }
234 expr->debug();
235 kdDebug() << expr->toString() << endl;
236
237 KexiDB::Field *f = new KexiDB::Field();
238 f->setExpression( expr );
239 d->privateQuery->addField( f );
240#if 0 //does not work yet
241// <remove later>
243 const int numColumntoHide = d->privateQuery->fieldsExpanded().count() - 1;
244 for (int i=0; i < numColumntoHide; i++)
245 d->privateQuery->setColumnVisible(i, false);
246// </remove later>
247#endif
248//todo...
249 kdDebug() << "--- Private query: " << endl;
250 d->privateQuery->debug();
251 cursor = field->table()->connection()->prepareQuery( *d->privateQuery );
252 }
253 if (!cursor)
255 return;
256
257 if (d->tv->KexiDataAwareObjectInterface::data())
258 d->tv->KexiDataAwareObjectInterface::data()->disconnect( this );
259 d->tv->setData( cursor );
260
261 connect( d->tv, TQ_SIGNAL(dataRefreshed()), this, TQ_SLOT(slotDataReloadRequested()));
262 updateSize();
263 return;
264 }
265
266 kdWarning() << "KexiComboBoxPopup::setData(KexiTableViewColumn &): no column relatedData \n - moving to setData(KexiDB::Field &)" << endl;
267
268 // case 3: enum hints
269 d->tv->setColumnStretchEnabled( true, -1 ); //only needed when using single column
270
272 d->int_f = new KexiDB::Field(field->name(), KexiDB::Field::Text);
274 data->addColumn( new KexiTableViewColumn( *d->int_f ) );
275 TQValueVector<TQString> hints = field->enumHints();
276 for(uint i=0; i < hints.size(); i++) {
277 KexiTableItem *item = data->createItem();//new KexiTableItem(1);
278 (*item)[0]=TQVariant(hints[i]);
279 kdDebug() << "added: '" << hints[i] <<"'"<<endl;
280 data->append( item );
281 }
282 setDataInternal( data, true );
283}
284
286{
287 if (d->tv->KexiDataAwareObjectInterface::data())
288 d->tv->KexiDataAwareObjectInterface::data()->disconnect( this );
289 d->tv->setData( data, owner );
290 connect( d->tv, TQ_SIGNAL(dataRefreshed()), this, TQ_SLOT(slotDataReloadRequested()));
291
292 updateSize();
293}
294
295void KexiComboBoxPopup::updateSize(int minWidth)
296{
297 const int rows = TQMIN( d->max_rows, d->tv->rows() );
298
299 d->tv->adjustColumnWidthToContents(-1);
300
301 KexiTableEdit *te = dynamic_cast<KexiTableEdit*>(parentWidget());
302 const int width = TQMAX( d->tv->tableSize().width(),
303 (te ? te->totalSize().width() : (parentWidget()?parentWidget()->width():0/*sanity*/)) );
304 kexidbg << "KexiComboBoxPopup::updateSize(): size=" << size() << endl;
305 resize( TQMAX(minWidth, width)/*+(d->tv->columns()>1?2:0)*/ /*(d->updateSizeCalled?0:1)*/, d->tv->rowHeight() * rows +2 );
306 kexidbg << "KexiComboBoxPopup::updateSize(): size after=" << size() << endl;
307
308 //stretch the last column
309 d->tv->setColumnStretchEnabled(true, d->tv->columns()-1);
310}
311
312KexiTableView* KexiComboBoxPopup::tableView()
313{
314 return d->tv;
315}
316
317void KexiComboBoxPopup::resize( int w, int h )
318{
319 d->tv->horizontalScrollBar()->hide();
320 d->tv->verticalScrollBar()->hide();
321 d->tv->move(1,1);
322 d->tv->resize( w-2, h-2 );
323 TQFrame::resize(w,h);
324 update();
325 updateGeometry();
326}
327
329{
330 d->max_rows = r;
331}
332
334{
335 return d->max_rows;
336}
337
338void KexiComboBoxPopup::slotTVItemAccepted(KexiTableItem *item, int row, int)
339{
340 hide();
341 emit rowAccepted(item, row);
342}
343
344bool KexiComboBoxPopup::eventFilter( TQObject *o, TQEvent *e )
345{
346 if (o==this && e->type()==TQEvent::Hide) {
347 emit hidden();
348 }
349 else if (e->type()==TQEvent::MouseButtonPress) {
350 kdDebug() << "TQEvent::MousePress" << endl;
351 }
352 else if (o==d->tv) {
353 if (e->type()==TQEvent::KeyPress) {
354 TQKeyEvent *ke = static_cast<TQKeyEvent*>(e);
355 const int k = ke->key();
356 if ((ke->state()==TQt::NoButton && (k==Key_Escape || k==Key_F4))
357 || (ke->state()==AltButton && k==Key_Up))
358 {
359 hide();
360 emit cancelled();
361 return true;
362 }
363 }
364 }
365 return TQFrame::eventFilter( o, e );
366}
367
368void KexiComboBoxPopup::slotDataReloadRequested()
369{
370 updateSize();
371}
372
373#include "kexicomboboxpopup.moc"
void setDataInternal(KexiTableViewData *data, bool owner=true)
used by setData()
void setData(KexiTableViewColumn *column, KexiDB::Field *field)
The main function for setting data; data can be set either by passing column or field.
KexiComboBoxPopup(TQWidget *parent, KexiTableViewColumn &column)
static const int defaultMaxRows
A base class for all expressions.
Definition expression.h:67
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)=0
Provides database cursor functionality.
Definition cursor.h:67
Meta-data for a field.
Definition field.h:73
void setExpression(KexiDB::BaseExpr *expr)
Definition field.cpp:633
virtual TableSchema * table() const
Definition field.cpp:300
@ Table
table as lookup row source
@ Query
named query as lookup row source
Provides information about lookup field's setup.
TQValueList< uint > visibleColumns() const
Helper class that assigns additional information for the column in a query.
Definition queryschema.h:49
KexiDB::QuerySchema provides information about database query.
QuerySchema * query()
Variables like fieldname or tablename.fieldname
Definition expression.h:245
KexiTableViewData * data() const
Database aware table widget.
KexiDB::Cursor * cursor()
bool setData(KexiDB::Cursor *cursor)
Abstract class for a cell editor. Handles cell painting and displaying the editor widget.
virtual TQSize totalSize()
KexiDB::Field * field() const
KexiTableViewData * relatedData() const
void addColumn(KexiTableViewColumn *col)
KexiTableView class provides a widget for displaying data in a tabular view.
void setAppearance(const Appearance &a)
const Appearance & appearance() const
void setVerticalHeaderVisible(bool set)
Sets vertical header's visibility.
void setHorizontalHeaderVisible(bool set)
Sets horizontal header's visibility.