kexi

kexicomboboxtableedit.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 Peter Simonsson <psn@linux.se>
3 Copyright (C) 2003-2006 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 <tqlayout.h>
22#include <tqstyle.h>
23#include <tqwindowsstyle.h>
24#include <tqpainter.h>
25#include <tqapplication.h>
26#include <tqclipboard.h>
27
28#include "kexicomboboxtableedit.h"
29#include <widget/utils/kexicomboboxdropdownbutton.h>
30#include "kexicomboboxpopup.h"
31#include "kexitableview.h"
32#include "kexitableitem.h"
33#include "kexi.h"
34
35#include <klineedit.h>
36
38class KexiComboBoxTableEdit::Private
39{
40public:
41 Private()
42 : popup(0)
43 , currentEditorWidth(0)
44 , visibleTableViewColumn(0)
45 , internalEditor(0)
46 {
47 }
48 ~Private()
49 {
50 delete internalEditor;
51 delete visibleTableViewColumn;
52 }
53
54 KPushButton *button;
55 KexiComboBoxPopup *popup;
56 int currentEditorWidth;
57 TQSize totalSize;
58 KexiTableViewColumn* visibleTableViewColumn;
59 KexiTableEdit* internalEditor;
60};
61
62//======================================================
63
64KexiComboBoxTableEdit::KexiComboBoxTableEdit(KexiTableViewColumn &column, TQWidget *parent)
65 : KexiInputTableEdit(column, parent)
67 , d(new Private())
68{
69 setName("KexiComboBoxTableEdit");
70 m_setVisibleValueOnSetValueInternal = true;
71 d->button = new KexiComboBoxDropDownButton( parentWidget() /*usually a viewport*/ );
72 d->button->hide();
73 d->button->setFocusPolicy( TQWidget::NoFocus );
74 connect(d->button, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotButtonClicked()));
75
76 connect(m_lineedit, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(slotLineEditTextChanged(const TQString&)));
77
78// m_lineedit = new KLineEdit(this, "lineedit");
79// m_lineedit->setFrame(false);
80// m_lineedit->setFrameStyle( TQFrame::Plain | TQFrame::Box );
81// m_lineedit->setLineWidth( 1 );
82// if (f.isNumericType()) {
83// m_lineedit->setAlignment(AlignRight);
84// }
85// setView( m_lineedit );
86
87// layout->addWidget(m_view);
88// m_combo->setEditable( true );
89// m_combo->clear();
90// m_combo->insertStringList(f.enumHints());
91// TQStringList::ConstIterator it, end( f.enumHints().constEnd() );
92// for ( it = f.enumHints().constBegin(); it != end; ++it) {
93// if(!hints.at(i).isEmpty())
94// m_combo->insertItem(hints.at(i));
95// }
96
97//js: TODO
98//js static_cast<KComboBox*>(m_view)->insertStringList(list);
99//js static_cast<KComboBox*>(m_view)->setCurrentItem(static_cast<int>(t));
100}
101
102KexiComboBoxTableEdit::~KexiComboBoxTableEdit()
103{
104 delete d;
105}
106
108{
109 if (!m_column->visibleLookupColumnInfo || d->visibleTableViewColumn/*sanity*/)
110 return;
111 const KexiDB::Field::Type t = m_column->visibleLookupColumnInfo->field->type();
114 if (!item || item->className()=="KexiInputTableEdit")
115 return; //unsupported type or there is no need to use subeditor for KexiInputTableEdit
116 //special cases: BLOB, Bool datatypes
117//todo
118 //find real type to display
119 KexiDB::QueryColumnInfo *ci = m_column->visibleLookupColumnInfo;
120 KexiDB::QueryColumnInfo *visibleLookupColumnInfo = 0;
121 if (ci->indexForVisibleLookupValue() != -1) {
122 //Lookup field is defined
123 visibleLookupColumnInfo = schema.expandedOrInternalField( ci->indexForVisibleLookupValue() );
124 }
125 d->visibleTableViewColumn = new KexiTableViewColumn(schema, *ci, visibleLookupColumnInfo);
127 d->internalEditor = KexiCellEditorFactory::createEditor(*d->visibleTableViewColumn, 0);
128 m_lineedit->hide();
129}
130
131KexiComboBoxPopup *KexiComboBoxTableEdit::popup() const
132{
133 return d->popup;
134}
135
136void KexiComboBoxTableEdit::setPopup(KexiComboBoxPopup *popup)
137{
138 d->popup = popup;
139}
140
141void KexiComboBoxTableEdit::showFocus( const TQRect& r, bool readOnly )
142{
143// d->button->move( pos().x()+ width(), pos().y() );
144 updateFocus( r );
145 d->button->setEnabled(!readOnly);
146 if (readOnly)
147 d->button->hide();
148 else
149 d->button->show();
150}
151
153{
154 d->totalSize = TQSize(w,h);
155 if (!column()->isReadOnly()) {
156 d->button->resize( h, h );
157 TQWidget::resize(w - d->button->width(), h);
158 }
159 m_rightMarginWhenFocused = m_rightMargin + (column()->isReadOnly() ? 0 : d->button->width());
160 TQRect r( pos().x(), pos().y(), w+1, h+1 );
161 if (m_scrollView)
162 r.moveBy(m_scrollView->contentsX(), m_scrollView->contentsY());
163 updateFocus( r );
164 if (popup()) {
165 popup()->updateSize();
166 }
167}
168
169// internal
171{
172 if (!column()->isReadOnly()) {
173 if (d->button->width() > r.width())
174 moveChild(d->button, r.right() + 1, r.top());
175 else
176 moveChild(d->button, r.right() - d->button->width(), r.top() );
177 }
178}
179
181{
182 d->button->hide();
183}
184
186{
187 return KexiComboBoxBase::visibleValue();
188/* KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
189 if (!popup() || !lookupFieldSchema)
190 return TQVariant();
191 KexiTableItem *it = popup()->tableView()->selectedItem();
192 return it ? it->at( lookupFieldSchema->visibleColumn() ) : TQVariant();*/
193}
194
200
202{
203 const tristate res = valueChangedInternal();
204 if (~res) //no result: just compare values
206 return res == true;
207}
208
209void KexiComboBoxTableEdit::paintFocusBorders( TQPainter *p, TQVariant &, int x, int y, int w, int h )
210{
211// d->currentEditorWidth = w;
212 if (!column()->isReadOnly()) {
213 if (w > d->button->width())
214 w -= d->button->width();
215 }
216 p->drawRect(x, y, w, h);
217}
218
219void KexiComboBoxTableEdit::setupContents( TQPainter *p, bool focused, const TQVariant& val,
220 TQString &txt, int &align, int &x, int &y_offset, int &w, int &h )
221{
222 if (d->internalEditor) {
223 d->internalEditor->setupContents( p, focused, val, txt, align, x, y_offset, w, h );
224 }
225 else {
226 KexiInputTableEdit::setupContents( p, focused, val, txt, align, x, y_offset, w, h );
227 }
228 if (!column()->isReadOnly() && focused && (w > d->button->width()))
229 w -= (d->button->width() - x);
230 if (!val.isNull()) {
231 KexiTableViewData *relData = column()->relatedData();
233 if (relData) {
234 int rowToHighlight;
235 txt = valueForString(val.toString(), &rowToHighlight, 0, 1);
236 }
237 else if ((lookupFieldSchema = this->lookupFieldSchema())) {
238 /* handled at at KexiTableView level
239 if (popup()) {
240 KexiTableItem *it = popup()->tableView()->selectedItem();
241 if (it && lookupFieldSchema->visibleColumn()!=-1 && (int)it->size() >= lookupFieldSchema->visibleColumn())
242 txt = it->at( lookupFieldSchema->visibleColumn() ).toString();
243 }*/
244 }
245 else {
246 //use 'enum hints' model
247 txt = field()->enumHint( val.toInt() );
248 }
249 }
250}
251
252void KexiComboBoxTableEdit::slotButtonClicked()
253{
254 // this method is sometimes called by hand:
255 // do not allow to simulate clicks when the button is disabled
256 if (column()->isReadOnly() || !d->button->isEnabled())
257 return;
258
261 d->button->setOn(false);
262 return;
263 }
264 kdDebug() << "KexiComboBoxTableEdit::slotButtonClicked()" << endl;
265 if (!popup() || !popup()->isVisible()) {
266 kdDebug() << "SHOW POPUP" << endl;
267 showPopup();
268 d->button->setOn(true);
269 }
270}
271
272void KexiComboBoxTableEdit::slotPopupHidden()
273{
274 d->button->setOn(false);
275// d->currentEditorWidth = 0;
276}
277
279{
280 d->button->setOn(popup()->isVisible());
281}
282
283void KexiComboBoxTableEdit::hide()
284{
285 KexiInputTableEdit::hide();
286 KexiComboBoxBase::hide();
287 d->button->setOn(false);
288}
289
290void KexiComboBoxTableEdit::show()
291{
292 KexiInputTableEdit::show();
293 if (!column()->isReadOnly()) {
294 d->button->show();
295 }
296}
297
298bool KexiComboBoxTableEdit::handleKeyPress( TQKeyEvent *ke, bool editorActive )
299{
300 const int k = ke->key();
301 if ((ke->state()==TQt::NoButton && k==TQt::Key_F4)
302 || (ke->state()==AltButton && k==TQt::Key_Down))
303 {
304 //show popup
305 slotButtonClicked();
306 return true;
307 }
308 else if (editorActive) {
309 const bool enterPressed = k==TQt::Key_Enter || k==TQt::Key_Return;
310 if (enterPressed && m_internalEditorValueChanged) {
311 createPopup(false);
313 return false;
314 }
315
316 return handleKeyPressForPopup( ke );
317 }
318
319 return false;
320}
321
322void KexiComboBoxTableEdit::slotLineEditTextChanged(const TQString& s)
323{
324 slotInternalEditorValueChanged(s);
325}
326
327int KexiComboBoxTableEdit::widthForValue( TQVariant &val, const TQFontMetrics &fm )
328{
329 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
330 if (lookupFieldSchema() || relData) {
331 // in 'lookupFieldSchema' or or 'related table data' model
332 // we're assuming val is already the text, not the index
334 return TQMAX(KEXITV_MINIMUM_COLUMN_WIDTH, fm.width(val.toString()));
335 }
336 //use 'enum hints' model
337 TQValueVector<TQString> hints = field()->enumHints();
338 bool ok;
339 int idx = val.toInt(&ok);
340 if (!ok || idx < 0 || idx > int(hints.size()-1))
341 return KEXITV_MINIMUM_COLUMN_WIDTH;
342 TQString txt = hints.at( idx, &ok );
343 if (!ok)
344 return KEXITV_MINIMUM_COLUMN_WIDTH;
345 return fm.width( txt );
346}
347
348bool KexiComboBoxTableEdit::eventFilter( TQObject *o, TQEvent *e )
349{
350 if (!column()->isReadOnly() && e->type()==TQEvent::MouseButtonPress && m_scrollView) {
351 TQPoint gp = static_cast<TQMouseEvent*>(e)->globalPos()
352 + TQPoint(m_scrollView->childX(d->button), m_scrollView->childY(d->button));
353 TQRect r(d->button->mapToGlobal(d->button->geometry().topLeft()),
354 d->button->mapToGlobal(d->button->geometry().bottomRight()));
355 if (o==popup() && popup()->isVisible() && r.contains( gp )) {
357 }
358 }
359 return false;
360}
361
363{
364 return d->totalSize;
365}
366
368{
369 return m_lineedit;
370}
371
376
381
383{
384 m_lineedit->end(false);
385}
386
388{
389 m_lineedit->home(false);
390}
391
393{
394 m_lineedit->selectAll();
395}
396
398{
399 m_lineedit->setText(value.toString());
400}
401
403{
404 return m_lineedit->text();
405}
406
407TQPoint KexiComboBoxTableEdit::mapFromParentToGlobal(const TQPoint& pos) const
408{
409 KexiTableView *tv = dynamic_cast<KexiTableView*>(m_scrollView);
410 if (!tv)
411 return TQPoint(-1,-1);
412 return tv->viewport()->mapToGlobal(pos);
413}
414
416{
417 return m_lineedit->width() + m_leftMargin + m_rightMarginWhenFocused; //TQMAX(popup()->width(), d->currentEditorWidth);
418}
419
420void KexiComboBoxTableEdit::handleCopyAction(const TQVariant& value, const TQVariant& visibleValue)
421{
422 Q_UNUSED(value);
424 tqApp->clipboard()->setText( visibleValue.toString() );
425}
426
427void KexiComboBoxTableEdit::handleAction(const TQString& actionName)
428{
429 const bool alreadyVisible = m_lineedit->isVisible();
430
431 if (actionName=="edit_paste") {
432 if (!alreadyVisible) { //paste as the entire text if the cell was not in edit mode
433 emit editRequested();
434 m_lineedit->clear();
435 }
437 setValueInInternalEditor( tqApp->clipboard()->text() );
438 }
439 else
441}
442
443
444KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiComboBoxEditorFactoryItem, KexiComboBoxTableEdit)
445
446#include "kexicomboboxtableedit.moc"
A base class for implementing cell editor factories.
static KexiTableEdit * createEditor(KexiTableViewColumn &column, TQWidget *parent=0)
static KexiCellEditorFactoryItem * item(uint type, const TQString &subType=TQString())
A base class for handling data-aware combo boxes. This class is used by KexiComboBoxTableEdit and Kex...
bool m_mouseBtnPressedWhenPopupVisible
Used only by KexiComboBoxTableEdit.
TQVariant m_userEnteredValue
value (usually a text) entered by hand (by the user)
KexiTableItem * selectItemForEnteredValueInLookupTable(const TQVariant &v)
void createPopup(bool show)
virtual void clear()
Reimplement this and call this impl.: used to clear internal editor.
KexiDB::LookupFieldSchema * lookupFieldSchema() const
TQString valueForString(const TQString &str, int *row, uint lookInColumn, uint returnFromColumn, bool allowNulls=false)
bool m_internalEditorValueChanged
true if user has text or other value inside editor
A drop-down button for combo box widgets.
Internal class for displaying popup table view.
Drop-down cell editor.
virtual int widthForValue(TQVariant &val, const TQFontMetrics &fm)
virtual void setValueInInternalEditor(const TQVariant &value)
Implemented for KexiComboBoxBase.
virtual void moveCursorToStart()
Implemented for KexiDataItemInterface.
virtual void paintFocusBorders(TQPainter *p, TQVariant &cal, int x, int y, int w, int h)
virtual TQWidget * internalEditor() const
Implemented for KexiComboBoxBase.
virtual TQPoint mapFromParentToGlobal(const TQPoint &pos) const
Implemented for KexiComboBoxBase.
virtual TQVariant visibleValue()
virtual void showFocus(const TQRect &r, bool readOnly)
virtual void createInternalEditor(KexiDB::QuerySchema &schema)
virtual KexiTableViewColumn * column() const
Implemented for KexiComboBoxBase.
virtual TQVariant value()
virtual void clear()
clears item's data, so the data will contain NULL data
virtual KexiDB::Field * field() const
Implemented for KexiComboBoxBase.
virtual bool handleKeyPress(TQKeyEvent *ke, bool editorActive)
virtual void resize(int w, int h)
virtual void handleAction(const TQString &actionName)
virtual void moveCursorToEnd()
Implemented for KexiDataItemInterface.
virtual TQSize totalSize() const
virtual void moveCursorToEndInInternalEditor()
Implemented for KexiComboBoxBase.
virtual void updateButton()
Implemented this to update button state.
virtual void editRequested()
Implemented for KexiComboBoxBase.
virtual void selectAllInInternalEditor()
Implemented for KexiComboBoxBase.
virtual void handleCopyAction(const TQVariant &value, const TQVariant &visibleValue)
virtual void setupContents(TQPainter *p, bool focused, const TQVariant &val, TQString &txt, int &align, int &x, int &y_offset, int &w, int &h)
virtual TQVariant valueFromInternalEditor()
Implemented for KexiComboBoxBase.
void updateFocus(const TQRect &r)
internal
virtual int popupWidthHint() const
Implemented for KexiComboBoxBase.
virtual void selectAll()
Implemented for KexiDataItemInterface.
TQValueVector< TQString > enumHints() const
Definition field.h:541
Provides information about lookup field's setup.
Helper class that assigns additional information for the column in a query.
Definition queryschema.h:49
int indexForVisibleLookupValue() const
Definition queryschema.h:75
KexiDB::QuerySchema provides information about database query.
QueryColumnInfo * expandedOrInternalField(uint index)
virtual bool isReadOnly() const
General purpose cell editor using line edit widget.
KLineEdit * m_lineedit
orig. Line Edit's text after conversion - for easy comparing
virtual void handleAction(const TQString &actionName)
virtual void setupContents(TQPainter *p, bool focused, const TQVariant &val, TQString &txt, int &align, int &x, int &y_offset, int &w, int &h)
void moveChild(TQWidget *child, int x, int y)
TQScrollView * m_scrollView
may be 0 if the parent is not a scrollview
KexiTableViewData * relatedData() const
KexiTableView class provides a widget for displaying data in a tabular view.
3-state logical type with three values: true, false and cancelled and convenient operators.
Definition tristate.h:100