1
/* This file is part of the KDE project
2
Copyright (C) 2002 Peter Simonsson <psn@linux.se>
3
Copyright (C) 2003-2014 JarosÅaw Staniek <staniek@kde.org>
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.
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.
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.
21
#include "kexicomboboxtableedit.h"
22
#include <widget/utils/kexicomboboxdropdownbutton.h>
23
#include <kexiutils/utils.h>
24
#include "kexicomboboxpopup.h"
25
#include "KexiTableScrollArea.h"
26
#include "KexiTableScrollAreaWidget.h"
29
#include <KDbQueryColumnInfo>
30
#include <KDbQuerySchema>
32
#include <QApplication>
39
// the right margin is too large when the editor is show, reduce it
40
const int RIGHT_MARGIN_DELTA = 6;
43
class KexiComboBoxTableEdit::Private
48
, currentEditorWidth(0)
49
, visibleTableViewColumn(0)
53
delete internalEditor;
54
delete visibleTableViewColumn;
57
KexiComboBoxDropDownButton *button;
58
KexiComboBoxPopup *popup;
59
int currentEditorWidth;
61
KDbTableViewColumn* visibleTableViewColumn;
62
KexiTableEdit* internalEditor;
66
//======================================================
68
KexiComboBoxTableEdit::KexiComboBoxTableEdit(KDbTableViewColumn &column, QWidget *parent)
70
, KexiInputTableEdit(column, parent)
73
m_setVisibleValueOnSetValueInternal = true;
74
m_reinstantiatePopupOnShow = true; // needed because re-opening of the popup fails for unknown reason
75
d->button = new KexiComboBoxDropDownButton(parentWidget() /*usually a viewport*/);
77
d->button->setFocusPolicy(Qt::NoFocus);
78
connect(d->button, SIGNAL(clicked()), this, SLOT(slotButtonClicked()));
80
connect(m_lineedit, SIGNAL(textChanged(QString)), this, SLOT(slotLineEditTextChanged(QString)));
82
m_rightMarginWhenFocused = this->column()->isReadOnly() ? 0 : d->button->width();
83
m_rightMarginWhenFocused -= RIGHT_MARGIN_DELTA;
84
updateLineEditStyleSheet();
85
m_rightMarginWhenFocused += RIGHT_MARGIN_DELTA;
86
//! @todo update when style changes
87
d->arrowWidth = KexiUtils::comboBoxArrowSize(style()).width();
90
KexiComboBoxTableEdit::~KexiComboBoxTableEdit()
95
void KexiComboBoxTableEdit::createInternalEditor(KDbQuerySchema& schema)
97
if (!m_column->visibleLookupColumnInfo() || d->visibleTableViewColumn/*sanity*/)
99
const KDbField::Type t = m_column->visibleLookupColumnInfo()->field->type();
101
KexiCellEditorFactoryItem *item = KexiCellEditorFactory::item(t);
102
if (!item || item->className() == "KexiInputTableEdit")
103
return; //unsupported type or there is no need to use subeditor for KexiInputTableEdit
104
//special cases: BLOB, Bool datatypes
106
//find real type to display
107
KDbQueryColumnInfo *ci = m_column->visibleLookupColumnInfo();
108
KDbQueryColumnInfo *visibleLookupColumnInfo = 0;
109
if (ci->indexForVisibleLookupValue() != -1) {
110
//Lookup field is defined
111
visibleLookupColumnInfo = schema.expandedOrInternalField(ci->indexForVisibleLookupValue());
113
d->visibleTableViewColumn = new KDbTableViewColumn(schema, ci, visibleLookupColumnInfo);
114
//! todo set d->internalEditor visible and use it to enable data entering by hand
115
d->internalEditor = KexiCellEditorFactory::createEditor(*d->visibleTableViewColumn, 0);
119
KexiComboBoxPopup *KexiComboBoxTableEdit::popup() const
124
void KexiComboBoxTableEdit::setPopup(KexiComboBoxPopup *popup)
129
void KexiComboBoxTableEdit::showFocus(const QRect& r, bool readOnly)
132
d->button->setEnabled(!readOnly);
133
d->button->setVisible(!readOnly);
136
void KexiComboBoxTableEdit::resize(int w, int h)
138
d->totalSize = QSize(w, h);
139
if (!column()->isReadOnly()) {
140
d->button->resize(h, h);
141
QWidget::resize(w, h);
143
m_rightMarginWhenFocused = column()->isReadOnly() ? 0 : d->button->width();
144
m_rightMarginWhenFocused -= RIGHT_MARGIN_DELTA;
145
updateLineEditStyleSheet();
146
m_rightMarginWhenFocused += RIGHT_MARGIN_DELTA;
147
QRect r(pos().x(), pos().y(), w + 1, h + 1);
148
if (qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())) {
150
qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())->scrollArea->horizontalScrollBar()->value(),
151
qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())->scrollArea->verticalScrollBar()->value());
155
popup()->updateSize();
160
void KexiComboBoxTableEdit::updateFocus(const QRect& r)
162
if (!column()->isReadOnly()) {
163
if (d->button->width() > r.width())
164
moveChild(d->button, r.right() + 1, r.top());
166
moveChild(d->button, r.right() - d->button->width(), r.top());
170
void KexiComboBoxTableEdit::hideFocus()
175
QVariant KexiComboBoxTableEdit::visibleValue()
177
return KexiComboBoxBase::visibleValue();
180
void KexiComboBoxTableEdit::clear()
183
KexiComboBoxBase::clear();
186
bool KexiComboBoxTableEdit::valueChanged()
188
const tristate res = valueChangedInternal();
189
if (~res) //no result: just compare values
190
return KexiInputTableEdit::valueChanged();
194
void KexiComboBoxTableEdit::paintFocusBorders(QPainter *p, QVariant &, int x, int y, int w, int h)
196
p->drawRect(x, y, w, h);
199
void KexiComboBoxTableEdit::setupContents(QPainter *p, bool focused, const QVariant& val,
200
QString &txt, int &align, int &x, int &y_offset, int &w, int &h)
202
if (d->internalEditor) {
203
d->internalEditor->setupContents(p, focused, val, txt, align, x, y_offset, w, h);
205
KexiInputTableEdit::setupContents(p, focused, val, txt, align, x, y_offset, w, h);
208
KDbTableViewData *relData = column()->relatedData();
210
int recordToHighlight;
211
txt = valueForString(val.toString(), &recordToHighlight, 0, 1);
213
else if (lookupFieldSchema()) {
216
//use 'enum hints' model
217
txt = field()->enumHint(val.toInt());
222
void KexiComboBoxTableEdit::slotButtonClicked()
224
// this method is sometimes called by hand:
225
// do not allow to simulate clicks when the button is disabled
226
if (column()->isReadOnly() || !d->button->isEnabled())
229
if (m_mouseBtnPressedWhenPopupVisible) {
230
m_mouseBtnPressedWhenPopupVisible = false;
234
if (!popup() || !popup()->isVisible()) {
235
qDebug() << "SHOW POPUP";
240
void KexiComboBoxTableEdit::slotPopupHidden()
244
void KexiComboBoxTableEdit::updateButton()
248
void KexiComboBoxTableEdit::hide()
250
KexiInputTableEdit::hide();
251
KexiComboBoxBase::hide();
254
void KexiComboBoxTableEdit::show()
256
KexiInputTableEdit::show();
257
if (!column()->isReadOnly()) {
262
bool KexiComboBoxTableEdit::handleKeyPress(QKeyEvent *ke, bool editorActive)
265
const int k = ke->key();
266
if ((ke->modifiers() == Qt::NoModifier && k == Qt::Key_F4)
267
|| (ke->modifiers() == Qt::AltModifier && k == Qt::Key_Down)) {
271
} else if (editorActive) {
272
const bool enterPressed = k == Qt::Key_Enter || k == Qt::Key_Return;
273
if (enterPressed && m_internalEditorValueChanged) {
275
selectRecordForEnteredValueInLookupTable(m_userEnteredValue);
279
return handleKeyPressForPopup(ke);
285
void KexiComboBoxTableEdit::slotLineEditTextChanged(const QString& s)
287
slotInternalEditorValueChanged(s);
290
int KexiComboBoxTableEdit::widthForValue(const QVariant &val, const QFontMetrics &fm)
292
KDbTableViewData *relData = column() ? column()->relatedData() : 0;
293
if (lookupFieldSchema() || relData) {
294
// in 'lookupFieldSchema' or or 'related table data' model
295
// we're assuming val is already the text, not the index
297
return qMax(KEXITV_MINIMUM_COLUMN_WIDTH, fm.width(val.toString()) + d->arrowWidth);
299
//use 'enum hints' model
300
QVector<QString> hints = field()->enumHints();
302
int idx = val.toInt(&ok);
303
if (!ok || idx < 0 || idx > int(hints.size() - 1))
304
return KEXITV_MINIMUM_COLUMN_WIDTH;
305
QString txt = hints.value(idx);
307
return KEXITV_MINIMUM_COLUMN_WIDTH;
308
return fm.width(txt) + d->arrowWidth;
311
bool KexiComboBoxTableEdit::eventFilter(QObject *o, QEvent *e)
314
if (e->type() != QEvent::Paint
315
&& e->type() != QEvent::Leave
316
&& e->type() != QEvent::MouseMove
317
&& e->type() != QEvent::HoverMove
318
&& e->type() != QEvent::HoverEnter
319
&& e->type() != QEvent::HoverLeave)
322
qDebug() << "FOCUS WIDGET:" << focusWidget();
325
KexiTableScrollArea *tv = qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())->scrollArea;
326
if (tv && e->type() == QEvent::KeyPress) {
327
if (tv->eventFilter(o, e)) {
331
if (!column()->isReadOnly() && e->type() == QEvent::MouseButtonPress
332
&& qobject_cast<KexiTableScrollAreaWidget*>(parentWidget()))
334
QPoint gp = static_cast<QMouseEvent*>(e)->globalPos() + d->button->pos();
335
QRect r(d->button->mapToGlobal(d->button->geometry().topLeft()),
336
d->button->mapToGlobal(d->button->geometry().bottomRight()));
337
if (o == popup() && popup()->isVisible() && r.contains(gp)) {
338
m_mouseBtnPressedWhenPopupVisible = true;
344
QSize KexiComboBoxTableEdit::totalSize() const
349
QWidget *KexiComboBoxTableEdit::internalEditor() const
354
void KexiComboBoxTableEdit::moveCursorToEndInInternalEditor()
359
void KexiComboBoxTableEdit::selectAllInInternalEditor()
364
void KexiComboBoxTableEdit::moveCursorToEnd()
366
m_lineedit->end(false/*!mark*/);
369
void KexiComboBoxTableEdit::moveCursorToStart()
371
m_lineedit->home(false/*!mark*/);
374
void KexiComboBoxTableEdit::selectAll()
376
m_lineedit->selectAll();
379
void KexiComboBoxTableEdit::setValueInInternalEditor(const QVariant& value)
381
KexiUtils::BoolBlocker guard(&m_slotInternalEditorValueChanged_enabled, false);
382
m_lineedit->setText(value.toString());
385
QVariant KexiComboBoxTableEdit::valueFromInternalEditor()
387
return m_lineedit->text();
390
QPoint KexiComboBoxTableEdit::mapFromParentToGlobal(const QPoint& pos) const
392
KexiTableScrollArea *tv = qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())->scrollArea;
394
return QPoint(-1, -1);
395
return tv->viewport()->mapToGlobal(pos);
398
int KexiComboBoxTableEdit::popupWidthHint() const
400
return m_lineedit->width();
403
void KexiComboBoxTableEdit::handleCopyAction(const QVariant& value, const QVariant& visibleValue)
406
//! @todo does not work with BLOBs!
407
qApp->clipboard()->setText(visibleValue.toString());
410
void KexiComboBoxTableEdit::handleAction(const QString& actionName)
412
const bool alreadyVisible = m_lineedit->isVisible();
414
if (actionName == "edit_paste") {
415
if (!alreadyVisible) { //paste as the entire text if the cell was not in edit mode
416
emit editRequested();
419
//! @todo does not work with BLOBs!
420
setValueInInternalEditor(qApp->clipboard()->text());
422
KexiInputTableEdit::handleAction(actionName);
425
QVariant KexiComboBoxTableEdit::origValue() const
427
return KexiDataItemInterface::originalValue();
430
KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiComboBoxEditorFactoryItem, KexiComboBoxTableEdit)