~ubuntu-branches/debian/sid/kexi/sid

« back to all changes in this revision

Viewing changes to src/widget/tableview/kexicomboboxtableedit.cpp

  • Committer: Package Import Robot
  • Author(s): Pino Toscano
  • Date: 2017-06-24 20:10:10 UTC
  • Revision ID: package-import@ubuntu.com-20170624201010-5lrzd5r2vwthwifp
Tags: upstream-3.0.1.1
ImportĀ upstreamĀ versionĀ 3.0.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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>
 
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 "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"
 
27
#include "kexi.h"
 
28
 
 
29
#include <KDbQueryColumnInfo>
 
30
#include <KDbQuerySchema>
 
31
 
 
32
#include <QApplication>
 
33
#include <QClipboard>
 
34
#include <QDebug>
 
35
#include <QLineEdit>
 
36
#include <QPainter>
 
37
#include <QScrollBar>
 
38
 
 
39
// the right margin is too large when the editor is show, reduce it
 
40
const int RIGHT_MARGIN_DELTA = 6;
 
41
 
 
42
//! @internal
 
43
class KexiComboBoxTableEdit::Private
 
44
{
 
45
public:
 
46
    Private()
 
47
            : popup(0)
 
48
            , currentEditorWidth(0)
 
49
            , visibleTableViewColumn(0)
 
50
            , internalEditor(0) {
 
51
    }
 
52
    ~Private() {
 
53
        delete internalEditor;
 
54
        delete visibleTableViewColumn;
 
55
    }
 
56
 
 
57
    KexiComboBoxDropDownButton *button;
 
58
    KexiComboBoxPopup *popup;
 
59
    int currentEditorWidth;
 
60
    QSize totalSize;
 
61
    KDbTableViewColumn* visibleTableViewColumn;
 
62
    KexiTableEdit* internalEditor;
 
63
    int arrowWidth;
 
64
};
 
65
 
 
66
//======================================================
 
67
 
 
68
KexiComboBoxTableEdit::KexiComboBoxTableEdit(KDbTableViewColumn &column, QWidget *parent)
 
69
        : KexiComboBoxBase()
 
70
        , KexiInputTableEdit(column, parent)
 
71
        , d(new Private())
 
72
{
 
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*/);
 
76
    d->button->hide();
 
77
    d->button->setFocusPolicy(Qt::NoFocus);
 
78
    connect(d->button, SIGNAL(clicked()), this, SLOT(slotButtonClicked()));
 
79
 
 
80
    connect(m_lineedit, SIGNAL(textChanged(QString)), this, SLOT(slotLineEditTextChanged(QString)));
 
81
 
 
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();
 
88
}
 
89
 
 
90
KexiComboBoxTableEdit::~KexiComboBoxTableEdit()
 
91
{
 
92
    delete d;
 
93
}
 
94
 
 
95
void KexiComboBoxTableEdit::createInternalEditor(KDbQuerySchema& schema)
 
96
{
 
97
    if (!m_column->visibleLookupColumnInfo() || d->visibleTableViewColumn/*sanity*/)
 
98
        return;
 
99
    const KDbField::Type t = m_column->visibleLookupColumnInfo()->field->type();
 
100
//! @todo subtype?
 
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
 
105
//! @todo
 
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());
 
112
    }
 
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);
 
116
    m_lineedit->hide();
 
117
}
 
118
 
 
119
KexiComboBoxPopup *KexiComboBoxTableEdit::popup() const
 
120
{
 
121
    return d->popup;
 
122
}
 
123
 
 
124
void KexiComboBoxTableEdit::setPopup(KexiComboBoxPopup *popup)
 
125
{
 
126
    d->popup = popup;
 
127
}
 
128
 
 
129
void KexiComboBoxTableEdit::showFocus(const QRect& r, bool readOnly)
 
130
{
 
131
    updateFocus(r);
 
132
    d->button->setEnabled(!readOnly);
 
133
    d->button->setVisible(!readOnly);
 
134
}
 
135
 
 
136
void KexiComboBoxTableEdit::resize(int w, int h)
 
137
{
 
138
    d->totalSize = QSize(w, h);
 
139
    if (!column()->isReadOnly()) {
 
140
        d->button->resize(h, h);
 
141
        QWidget::resize(w, h);
 
142
    }
 
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())) {
 
149
        r.translate(
 
150
            qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())->scrollArea->horizontalScrollBar()->value(),
 
151
            qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())->scrollArea->verticalScrollBar()->value());
 
152
    }
 
153
    updateFocus(r);
 
154
    if (popup()) {
 
155
        popup()->updateSize();
 
156
    }
 
157
}
 
158
 
 
159
// internal
 
160
void KexiComboBoxTableEdit::updateFocus(const QRect& r)
 
161
{
 
162
    if (!column()->isReadOnly()) {
 
163
        if (d->button->width() > r.width())
 
164
            moveChild(d->button, r.right() + 1, r.top());
 
165
        else
 
166
            moveChild(d->button, r.right() - d->button->width(), r.top());
 
167
    }
 
168
}
 
169
 
 
170
void KexiComboBoxTableEdit::hideFocus()
 
171
{
 
172
    d->button->hide();
 
173
}
 
174
 
 
175
QVariant KexiComboBoxTableEdit::visibleValue()
 
176
{
 
177
    return KexiComboBoxBase::visibleValue();
 
178
}
 
179
 
 
180
void KexiComboBoxTableEdit::clear()
 
181
{
 
182
    m_lineedit->clear();
 
183
    KexiComboBoxBase::clear();
 
184
}
 
185
 
 
186
bool KexiComboBoxTableEdit::valueChanged()
 
187
{
 
188
    const tristate res = valueChangedInternal();
 
189
    if (~res) //no result: just compare values
 
190
        return KexiInputTableEdit::valueChanged();
 
191
    return res == true;
 
192
}
 
193
 
 
194
void KexiComboBoxTableEdit::paintFocusBorders(QPainter *p, QVariant &, int x, int y, int w, int h)
 
195
{
 
196
    p->drawRect(x, y, w, h);
 
197
}
 
198
 
 
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)
 
201
{
 
202
    if (d->internalEditor) {
 
203
        d->internalEditor->setupContents(p, focused, val, txt, align, x, y_offset, w, h);
 
204
    } else {
 
205
        KexiInputTableEdit::setupContents(p, focused, val, txt, align, x, y_offset, w, h);
 
206
    }
 
207
    if (!val.isNull()) {
 
208
        KDbTableViewData *relData = column()->relatedData();
 
209
        if (relData) {
 
210
            int recordToHighlight;
 
211
            txt = valueForString(val.toString(), &recordToHighlight, 0, 1);
 
212
        }
 
213
        else if (lookupFieldSchema()) {
 
214
        }
 
215
        else {
 
216
            //use 'enum hints' model
 
217
            txt = field()->enumHint(val.toInt());
 
218
        }
 
219
    }
 
220
}
 
221
 
 
222
void KexiComboBoxTableEdit::slotButtonClicked()
 
223
{
 
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())
 
227
        return;
 
228
 
 
229
    if (m_mouseBtnPressedWhenPopupVisible) {
 
230
        m_mouseBtnPressedWhenPopupVisible = false;
 
231
        return;
 
232
    }
 
233
    qDebug();
 
234
    if (!popup() || !popup()->isVisible()) {
 
235
        qDebug() << "SHOW POPUP";
 
236
        showPopup();
 
237
    }
 
238
}
 
239
 
 
240
void KexiComboBoxTableEdit::slotPopupHidden()
 
241
{
 
242
}
 
243
 
 
244
void KexiComboBoxTableEdit::updateButton()
 
245
{
 
246
}
 
247
 
 
248
void KexiComboBoxTableEdit::hide()
 
249
{
 
250
    KexiInputTableEdit::hide();
 
251
    KexiComboBoxBase::hide();
 
252
}
 
253
 
 
254
void KexiComboBoxTableEdit::show()
 
255
{
 
256
    KexiInputTableEdit::show();
 
257
    if (!column()->isReadOnly()) {
 
258
        d->button->show();
 
259
    }
 
260
}
 
261
 
 
262
bool KexiComboBoxTableEdit::handleKeyPress(QKeyEvent *ke, bool editorActive)
 
263
{
 
264
    //qDebug() << ke;
 
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)) {
 
268
        //show popup
 
269
        slotButtonClicked();
 
270
        return true;
 
271
    } else if (editorActive) {
 
272
        const bool enterPressed = k == Qt::Key_Enter || k == Qt::Key_Return;
 
273
        if (enterPressed && m_internalEditorValueChanged) {
 
274
            createPopup(false);
 
275
            selectRecordForEnteredValueInLookupTable(m_userEnteredValue);
 
276
            return true;
 
277
        }
 
278
 
 
279
        return handleKeyPressForPopup(ke);
 
280
    }
 
281
 
 
282
    return false;
 
283
}
 
284
 
 
285
void KexiComboBoxTableEdit::slotLineEditTextChanged(const QString& s)
 
286
{
 
287
    slotInternalEditorValueChanged(s);
 
288
}
 
289
 
 
290
int KexiComboBoxTableEdit::widthForValue(const QVariant &val, const QFontMetrics &fm)
 
291
{
 
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
 
296
//! @todo ok?
 
297
        return qMax(KEXITV_MINIMUM_COLUMN_WIDTH, fm.width(val.toString()) + d->arrowWidth);
 
298
    }
 
299
    //use 'enum hints' model
 
300
    QVector<QString> hints = field()->enumHints();
 
301
    bool ok;
 
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);
 
306
    if (txt.isEmpty())
 
307
        return KEXITV_MINIMUM_COLUMN_WIDTH;
 
308
    return fm.width(txt) + d->arrowWidth;
 
309
}
 
310
 
 
311
bool KexiComboBoxTableEdit::eventFilter(QObject *o, QEvent *e)
 
312
{
 
313
#if 0
 
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)
 
320
    {
 
321
        qDebug() << e << o;
 
322
        qDebug() << "FOCUS WIDGET:" << focusWidget();
 
323
    }
 
324
#endif
 
325
    KexiTableScrollArea *tv = qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())->scrollArea;
 
326
    if (tv && e->type() == QEvent::KeyPress) {
 
327
        if (tv->eventFilter(o, e)) {
 
328
            return true;
 
329
        }
 
330
    }
 
331
    if (!column()->isReadOnly() && e->type() == QEvent::MouseButtonPress
 
332
        && qobject_cast<KexiTableScrollAreaWidget*>(parentWidget()))
 
333
    {
 
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;
 
339
        }
 
340
    }
 
341
    return false;
 
342
}
 
343
 
 
344
QSize KexiComboBoxTableEdit::totalSize() const
 
345
{
 
346
    return d->totalSize;
 
347
}
 
348
 
 
349
QWidget *KexiComboBoxTableEdit::internalEditor() const
 
350
{
 
351
    return m_lineedit;
 
352
}
 
353
 
 
354
void KexiComboBoxTableEdit::moveCursorToEndInInternalEditor()
 
355
{
 
356
    moveCursorToEnd();
 
357
}
 
358
 
 
359
void KexiComboBoxTableEdit::selectAllInInternalEditor()
 
360
{
 
361
    selectAll();
 
362
}
 
363
 
 
364
void KexiComboBoxTableEdit::moveCursorToEnd()
 
365
{
 
366
    m_lineedit->end(false/*!mark*/);
 
367
}
 
368
 
 
369
void KexiComboBoxTableEdit::moveCursorToStart()
 
370
{
 
371
    m_lineedit->home(false/*!mark*/);
 
372
}
 
373
 
 
374
void KexiComboBoxTableEdit::selectAll()
 
375
{
 
376
    m_lineedit->selectAll();
 
377
}
 
378
 
 
379
void KexiComboBoxTableEdit::setValueInInternalEditor(const QVariant& value)
 
380
{
 
381
    KexiUtils::BoolBlocker guard(&m_slotInternalEditorValueChanged_enabled, false);
 
382
    m_lineedit->setText(value.toString());
 
383
}
 
384
 
 
385
QVariant KexiComboBoxTableEdit::valueFromInternalEditor()
 
386
{
 
387
    return m_lineedit->text();
 
388
}
 
389
 
 
390
QPoint KexiComboBoxTableEdit::mapFromParentToGlobal(const QPoint& pos) const
 
391
{
 
392
    KexiTableScrollArea *tv = qobject_cast<KexiTableScrollAreaWidget*>(parentWidget())->scrollArea;
 
393
    if (!tv)
 
394
        return QPoint(-1, -1);
 
395
    return tv->viewport()->mapToGlobal(pos);
 
396
}
 
397
 
 
398
int KexiComboBoxTableEdit::popupWidthHint() const
 
399
{
 
400
    return m_lineedit->width();
 
401
}
 
402
 
 
403
void KexiComboBoxTableEdit::handleCopyAction(const QVariant& value, const QVariant& visibleValue)
 
404
{
 
405
    Q_UNUSED(value);
 
406
//! @todo does not work with BLOBs!
 
407
    qApp->clipboard()->setText(visibleValue.toString());
 
408
}
 
409
 
 
410
void KexiComboBoxTableEdit::handleAction(const QString& actionName)
 
411
{
 
412
    const bool alreadyVisible = m_lineedit->isVisible();
 
413
 
 
414
    if (actionName == "edit_paste") {
 
415
        if (!alreadyVisible) { //paste as the entire text if the cell was not in edit mode
 
416
            emit editRequested();
 
417
            m_lineedit->clear();
 
418
        }
 
419
//! @todo does not work with BLOBs!
 
420
        setValueInInternalEditor(qApp->clipboard()->text());
 
421
    } else
 
422
        KexiInputTableEdit::handleAction(actionName);
 
423
}
 
424
 
 
425
QVariant KexiComboBoxTableEdit::origValue() const
 
426
{
 
427
    return KexiDataItemInterface::originalValue();
 
428
}
 
429
 
 
430
KEXI_CELLEDITOR_FACTORY_ITEM_IMPL(KexiComboBoxEditorFactoryItem, KexiComboBoxTableEdit)
 
431