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

« back to all changes in this revision

Viewing changes to src/widget/tableview/kexicomboboxbase.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-2016 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
 
 
22
#include "kexicomboboxbase.h"
 
23
#include <kexi_global.h>
 
24
#include <widget/utils/kexicomboboxdropdownbutton.h>
 
25
#include "kexicomboboxpopup.h"
 
26
#include "KexiTableScrollArea.h"
 
27
#include "kexi.h"
 
28
#include "KexiTableScrollAreaWidget.h"
 
29
 
 
30
#include <KDbTableSchema>
 
31
#include <KDbTableViewColumn>
 
32
 
 
33
#include <QApplication>
 
34
#include <QDesktopWidget>
 
35
#include <QScopedValueRollback>
 
36
#include <QDebug>
 
37
#include <QScrollBar>
 
38
 
 
39
KexiComboBoxBase::KexiComboBoxBase()
 
40
{
 
41
    m_internalEditorValueChanged = false; //user has text or other value inside editor
 
42
    m_slotInternalEditorValueChanged_enabled = true;
 
43
    m_mouseBtnPressedWhenPopupVisible = false;
 
44
    m_insideCreatePopup = false;
 
45
    m_setValueOrTextInInternalEditor_enabled = true;
 
46
    m_updatePopupSelectionOnShow = true;
 
47
    m_moveCursorToEndInInternalEditor_enabled = true;
 
48
    m_selectAllInInternalEditor_enabled = true;
 
49
    m_setValueInInternalEditor_enabled = true;
 
50
    m_setVisibleValueOnSetValueInternal = false;
 
51
    m_reinstantiatePopupOnShow = false;
 
52
    m_focusPopupBeforeShow = false;
 
53
}
 
54
 
 
55
KexiComboBoxBase::~KexiComboBoxBase()
 
56
{
 
57
}
 
58
 
 
59
KDbLookupFieldSchema *KexiComboBoxBase::lookupFieldSchema() const
 
60
{
 
61
    if (field() && field()->table()) {
 
62
        KDbLookupFieldSchema *lookupFieldSchema = field()->table()->lookupFieldSchema(*field());
 
63
        if (lookupFieldSchema && !lookupFieldSchema->recordSource().name().isEmpty())
 
64
            return lookupFieldSchema;
 
65
    }
 
66
    return 0;
 
67
}
 
68
 
 
69
int KexiComboBoxBase::recordToHighlightForLookupTable() const
 
70
{
 
71
    if (!popup())
 
72
        return -1;//err
 
73
    KDbLookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
 
74
    if (!lookupFieldSchema)
 
75
        return -1;
 
76
    if (lookupFieldSchema->boundColumn() == -1)
 
77
        return -1; //err
 
78
    bool ok;
 
79
    const int recordUid = origValue().toInt();
 
80
//! @todo for now we're assuming the id is INTEGER
 
81
    KDbTableViewData *tvData = popup()->tableView()->data();
 
82
    const int boundColumn = boundColumnIndex();
 
83
    if (boundColumn < 0) {
 
84
        return -1;
 
85
    }
 
86
    int record = -1;
 
87
    for (KDbTableViewDataIterator it(tvData->begin()); it != tvData->end(); ++it) {
 
88
        record++;
 
89
        KDbRecordData* data = *it;
 
90
        if (data->at(boundColumn).toInt(&ok) == recordUid && ok)
 
91
            return record;
 
92
        if (!ok)
 
93
            break;
 
94
    }
 
95
    //item not found: highlight 1st record, if available
 
96
    return -1;
 
97
}
 
98
 
 
99
void KexiComboBoxBase::setValueInternal(const QVariant& add_, bool removeOld)
 
100
{
 
101
    Q_UNUSED(removeOld);
 
102
    m_mouseBtnPressedWhenPopupVisible = false;
 
103
    m_updatePopupSelectionOnShow = true;
 
104
    QString add(add_.toString());
 
105
    if (add.isEmpty()) {
 
106
        KDbTableViewData *relData = column() ? column()->relatedData() : 0;
 
107
        QVariant valueToSet;
 
108
        bool hasValueToSet = true;
 
109
        int recordToHighlight = -1;
 
110
        KDbLookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
 
111
        if (lookupFieldSchema) {
 
112
            //use 'lookup field' model
 
113
//! @todo support more RowSourceType's, not only table
 
114
            if (lookupFieldSchema->boundColumn() == -1)
 
115
//! @todo errmsg
 
116
                return;
 
117
            if (m_setVisibleValueOnSetValueInternal) {
 
118
                //only for table views
 
119
                if (!popup())
 
120
                    createPopup(false/*!show*/);
 
121
            }
 
122
            if (popup()) {
 
123
                const int recordToHighlight = recordToHighlightForLookupTable();
 
124
                popup()->tableView()->setHighlightedRecordNumber(recordToHighlight);
 
125
 
 
126
                const int visibleColumn = visibleColumnIndex();
 
127
                if (m_setVisibleValueOnSetValueInternal && -1 != visibleColumn) {
 
128
                    //only for table views
 
129
                    KDbRecordData *data = popup()->tableView()->highlightedRecord();
 
130
                    if (data)
 
131
                        valueToSet = data->at(visibleColumn);
 
132
                } else {
 
133
                    hasValueToSet = false;
 
134
                }
 
135
            }
 
136
        } else if (relData) {
 
137
            //use 'related table data' model
 
138
            valueToSet = valueForString(origValue().toString(), &recordToHighlight, 0, 1);
 
139
        } else {
 
140
            //use 'enum hints' model
 
141
            const int record = origValue().toInt();
 
142
            valueToSet = field()->enumHint(record).trimmed();
 
143
        }
 
144
        if (hasValueToSet)
 
145
            setValueOrTextInInternalEditor(valueToSet);
 
146
        /*impl.*/moveCursorToEndInInternalEditor();
 
147
        /*impl.*/selectAllInInternalEditor();
 
148
 
 
149
        if (popup()) {
 
150
            if (origValue().isNull()) {
 
151
                popup()->tableView()->clearSelection();
 
152
                popup()->tableView()->setHighlightedRecordNumber(0);
 
153
            } else {
 
154
                if (relData) {
 
155
                    if (recordToHighlight != -1)
 
156
                        popup()->tableView()->setHighlightedRecordNumber(recordToHighlight);
 
157
                } else if (!lookupFieldSchema) {
 
158
                    //popup()->tableView()->selectRecord(origValue().toInt());
 
159
                    popup()->tableView()->setHighlightedRecordNumber(origValue().toInt());
 
160
                }
 
161
            }
 
162
        }
 
163
    } else {
 
164
        //! @todo autocompl.?
 
165
        if (popup())
 
166
            popup()->tableView()->clearSelection();
 
167
        /*impl.*/setValueInInternalEditor(add); //not setLineEditText(), because 'add' is entered by user!
 
168
        //setLineEditText( add );
 
169
        /*impl.*/moveCursorToEndInInternalEditor();
 
170
    }
 
171
}
 
172
 
 
173
KDbRecordData* KexiComboBoxBase::selectRecordForEnteredValueInLookupTable(const QVariant& v)
 
174
{
 
175
    KDbLookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
 
176
    if (!popup() || !lookupFieldSchema)
 
177
        return 0; //safety
 
178
//-not effective for large sets: please cache it!
 
179
//.trimmed() is not generic!
 
180
 
 
181
    const bool valueIsText = v.type() == QVariant::String || v.type() == QVariant::ByteArray; //most common case
 
182
    const QString txt(valueIsText ? v.toString().trimmed() : QString());
 
183
    KDbTableViewData *lookupData = popup()->tableView()->data();
 
184
    const int visibleColumn = visibleColumnIndex();
 
185
    if (-1 == visibleColumn)
 
186
        return 0;
 
187
    KDbTableViewDataConstIterator it(lookupData->constBegin());
 
188
    int record;
 
189
    for (record = 0;it != lookupData->constEnd();++it, record++) {
 
190
        if (valueIsText) {
 
191
            if ((*it)->at(visibleColumn).toString().trimmed().compare(txt, Qt::CaseInsensitive) == 0)
 
192
                break;
 
193
        } else {
 
194
            if ((*it)->at(visibleColumn) == v)
 
195
                break;
 
196
        }
 
197
    }
 
198
 
 
199
    m_setValueOrTextInInternalEditor_enabled = false; // <-- this is the entered value,
 
200
    //     so do not change the internal editor's contents
 
201
    if (it != lookupData->constEnd())
 
202
        popup()->tableView()->selectRecord(record);
 
203
    else
 
204
        popup()->tableView()->clearSelection();
 
205
 
 
206
    m_setValueOrTextInInternalEditor_enabled = true;
 
207
 
 
208
    return it != lookupData->constEnd() ? *it : 0;
 
209
}
 
210
 
 
211
QString KexiComboBoxBase::valueForString(const QString& str, int* record,
 
212
        int lookInColumn, int returnFromColumn, bool allowNulls)
 
213
{
 
214
    Q_UNUSED(returnFromColumn);
 
215
    KDbTableViewData *relData = column() ? column()->relatedData() : 0;
 
216
    if (!relData)
 
217
        return QString(); //safety
 
218
    //use 'related table data' model
 
219
    //-not effective for large sets: please cache it!
 
220
    //.trimmed() is not generic!
 
221
 
 
222
    const QString txt(str.trimmed());
 
223
    KDbTableViewDataIterator it(relData->begin());
 
224
    for (*record = 0;it != relData->end();++it, (*record)++) {
 
225
        const QString s((*it)->at(lookInColumn).toString());
 
226
        if (s.trimmed().compare(txt, Qt::CaseInsensitive) == 0)
 
227
            return s;
 
228
    }
 
229
 
 
230
    *record = -1;
 
231
 
 
232
    if (column() && column()->isRelatedDataEditable())
 
233
        return str; //new value entered and that's allowed
 
234
 
 
235
    qWarning() << "no related record found, ID will be painted!";
 
236
    if (allowNulls)
 
237
        return QString();
 
238
    return str; //for sanity but it's weird to show id to the user
 
239
}
 
240
 
 
241
int KexiComboBoxBase::boundColumnIndex() const
 
242
{
 
243
    if (!lookupFieldSchema()) {
 
244
        return -1;
 
245
    }
 
246
    switch (lookupFieldSchema()->recordSource().type()) {
 
247
    case KDbLookupFieldSchema::RecordSource::Table:
 
248
        // When the record source is Table we have hardcoded columns: <visible>, <bound>
 
249
        return lookupFieldSchema()->visibleColumns().count();
 
250
    default:;
 
251
    }
 
252
    // When the record source is Query we use the lookup field's bound column index
 
253
    //! @todo Implement for other types
 
254
    return lookupFieldSchema()->boundColumn();
 
255
}
 
256
 
 
257
int KexiComboBoxBase::visibleColumnIndex() const
 
258
{
 
259
    if (!lookupFieldSchema() || lookupFieldSchema()->visibleColumns().isEmpty()) {
 
260
        return -1;
 
261
    }
 
262
    switch (lookupFieldSchema()->recordSource().type()) {
 
263
    case KDbLookupFieldSchema::RecordSource::Table:
 
264
        // When the record source is Table we have hardcoded columns: <visible>, <bound>
 
265
        return lookupFieldSchema()->visibleColumn(0);
 
266
    default:;
 
267
    }
 
268
    // When the record source is Query we use the lookup field's visible column index
 
269
    //! @todo Implement for multiple visible columns
 
270
    //! @todo Implement for other types
 
271
    return lookupFieldSchema()->visibleColumns().first();
 
272
}
 
273
 
 
274
QVariant KexiComboBoxBase::value()
 
275
{
 
276
    KDbTableViewData *relData = column() ? column()->relatedData() : 0;
 
277
    KDbLookupFieldSchema *lookupFieldSchema = 0;
 
278
    if (relData) {
 
279
        if (m_internalEditorValueChanged) {
 
280
            //we've user-entered text: look for id
 
281
//! @todo make error if matching text not found?
 
282
            int recordToHighlight;
 
283
            return valueForString(m_userEnteredValue.toString(), &recordToHighlight, 1, 0, true/*allowNulls*/);
 
284
        } else {
 
285
            //use 'related table data' model
 
286
            KDbRecordData *data = popup() ? popup()->tableView()->selectedRecord() : 0;
 
287
            return data ? data->at(0) : origValue();
 
288
        }
 
289
    } else if ((lookupFieldSchema = this->lookupFieldSchema())) {
 
290
        if (lookupFieldSchema->boundColumn() == -1)
 
291
            return origValue();
 
292
        KDbRecordData *data = popup() ? popup()->tableView()->selectedRecord() : 0;
 
293
        if (/*!record &&*/ m_internalEditorValueChanged && !m_userEnteredValue.toString().isEmpty()) { //
 
294
            //try to select a record using the user-entered text
 
295
            if (!popup()) {
 
296
                QVariant prevUserEnteredValue = m_userEnteredValue;
 
297
                createPopup(false);
 
298
                m_userEnteredValue = prevUserEnteredValue;
 
299
            }
 
300
            data = selectRecordForEnteredValueInLookupTable(m_userEnteredValue);
 
301
        }
 
302
        const int boundColumn = boundColumnIndex();
 
303
        return (data && boundColumn >= 0) ? data->at(boundColumn) : QVariant();
 
304
    } else if (popup()) {
 
305
        //use 'enum hints' model
 
306
        const int record = popup()->tableView()->currentRecord();
 
307
        if (record >= 0)
 
308
            return QVariant(record);
 
309
    }
 
310
 
 
311
    if (valueFromInternalEditor().toString().isEmpty())
 
312
        return QVariant();
 
313
    /*! \todo don't return just 1st record, but use autocompletion feature
 
314
          and: show message box if entered text does not match! */
 
315
    return origValue(); //unchanged
 
316
}
 
317
 
 
318
QVariant KexiComboBoxBase::visibleValueForLookupField()
 
319
{
 
320
    KDbLookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
 
321
    if (!popup() || !lookupFieldSchema)
 
322
        return QVariant();
 
323
    const int visibleColumn = visibleColumnIndex();
 
324
    //qDebug() << "visibleColumn" << visibleColumn;
 
325
    if (-1 == visibleColumn)
 
326
        return QVariant();
 
327
    KDbRecordData *data = popup()->tableView()->selectedRecord();
 
328
    return data ? data->at(qMin(visibleColumn, data->count() - 1)/*sanity*/) : QVariant();
 
329
}
 
330
 
 
331
QVariant KexiComboBoxBase::visibleValue()
 
332
{
 
333
    return m_visibleValue;
 
334
}
 
335
 
 
336
void KexiComboBoxBase::clear()
 
337
{
 
338
    if (popup())
 
339
        popup()->hide();
 
340
    slotInternalEditorValueChanged(QVariant());
 
341
}
 
342
 
 
343
tristate KexiComboBoxBase::valueChangedInternal()
 
344
{
 
345
    //avoid comparing values:
 
346
    KDbTableViewData *relData = column() ? column()->relatedData() : 0;
 
347
    KDbLookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
 
348
    if (relData || lookupFieldSchema) {
 
349
        if (m_internalEditorValueChanged)
 
350
            return true;
 
351
 
 
352
        //use 'related table data' model
 
353
        KDbRecordData *data = popup() ? popup()->tableView()->selectedRecord() : 0;
 
354
        if (!data)
 
355
            return false;
 
356
    } else {
 
357
        //use 'enum hints' model
 
358
        const int record = popup() ? popup()->tableView()->currentRecord() : -1;
 
359
        if (record < 0 && !m_internalEditorValueChanged/*true if text box is cleared*/)
 
360
            return false;
 
361
    }
 
362
 
 
363
    return cancelled;
 
364
}
 
365
 
 
366
bool KexiComboBoxBase::valueIsNull()
 
367
{
 
368
// bool ok;
 
369
    QVariant v(value());
 
370
    return v.isNull();
 
371
// return !ok || v.isNull();
 
372
}
 
373
 
 
374
bool KexiComboBoxBase::valueIsEmpty()
 
375
{
 
376
    return valueIsNull();
 
377
}
 
378
 
 
379
void KexiComboBoxBase::showPopup()
 
380
{
 
381
    //qDebug();
 
382
    createPopup(true);
 
383
}
 
384
 
 
385
void KexiComboBoxBase::createPopup(bool show)
 
386
{
 
387
    //qDebug() << show << field() << popup() << m_updatePopupSelectionOnShow;
 
388
    if (!field())
 
389
        return;
 
390
    QWidget* thisWidget = dynamic_cast<QWidget*>(this);
 
391
    if (!thisWidget) {
 
392
        return;
 
393
    }
 
394
    QScopedValueRollback<bool> insideCreatePopuRollback(m_insideCreatePopup, true);
 
395
    QWidget *widgetToFocus = internalEditor() ? internalEditor() : thisWidget;
 
396
    //qDebug() << "widgetToFocus:" << widgetToFocus;
 
397
 
 
398
    if (m_reinstantiatePopupOnShow) {
 
399
        QWidget *oldPopup = popup();
 
400
        setPopup(0);
 
401
        delete oldPopup;
 
402
    }
 
403
 
 
404
    if (!popup()) {
 
405
        setPopup(column() ? new KexiComboBoxPopup(thisWidget, *column())
 
406
                 : new KexiComboBoxPopup(thisWidget, *field()));
 
407
        QObject::connect(popup(), SIGNAL(recordAccepted(KDbRecordData*,int)),
 
408
                         thisWidget, SLOT(slotRecordAccepted(KDbRecordData*,int)));
 
409
        QObject::connect(popup()->tableView(), SIGNAL(itemSelected(KDbRecordData*)),
 
410
                         thisWidget, SLOT(slotRecordSelected(KDbRecordData*)));
 
411
 
 
412
        popup()->setFocusProxy(widgetToFocus);
 
413
        popup()->tableView()->setFocusProxy(widgetToFocus);
 
414
        popup()->installEventFilter(thisWidget);
 
415
 
 
416
        if (origValue().isNull())
 
417
            popup()->tableView()->clearSelection();
 
418
        else {
 
419
            popup()->tableView()->selectRecord(0);
 
420
            popup()->tableView()->setHighlightedRecordNumber(0);
 
421
        }
 
422
    }
 
423
    if (show && internalEditor() && !internalEditor()->isVisible())
 
424
        /*emit*/editRequested();
 
425
 
 
426
    QPoint posMappedToGlobal = mapFromParentToGlobal(thisWidget->pos());
 
427
    if (posMappedToGlobal != QPoint(-1, -1)) {
 
428
//! todo alter the position to fit the popup within screen boundaries
 
429
        QPoint pos = posMappedToGlobal + QPoint(0, thisWidget->height());
 
430
        if (qobject_cast<KexiTableScrollAreaWidget*>(thisWidget->parentWidget())) {
 
431
            KexiTableScrollArea* tableScroll
 
432
                = qobject_cast<KexiTableScrollAreaWidget*>(thisWidget->parentWidget())->scrollArea;
 
433
            pos -= QPoint(tableScroll->horizontalScrollBar()->value(),
 
434
                          tableScroll->verticalScrollBar()->value());
 
435
        }
 
436
        popup()->hide();
 
437
        popup()->move(pos);
 
438
        //qDebug() << "pos:" << posMappedToGlobal + QPoint(0, thisWidget->height());
 
439
        //to avoid flickering: first resize to 0-height, then show and resize back to prev. height
 
440
        int w = popupWidthHint();
 
441
        popup()->resize(w, 0);
 
442
        if (show) {
 
443
            popup()->show();
 
444
            //qDebug() << "SHOW!!!";
 
445
        }
 
446
        popup()->updateSize(w);
 
447
 
 
448
        // make sure the popup fits on the screen
 
449
        const QRect screen = QApplication::desktop()->availableGeometry(posMappedToGlobal);
 
450
        pos -= screen.topLeft(); // to simplify computation
 
451
        w = popup()->width();
 
452
        int h = popup()->height();
 
453
        if (screen.width() < w) {
 
454
            w = screen.width();
 
455
            pos.setX(0);
 
456
        } else if (screen.width() < (pos.x() + w - 1)) {
 
457
            pos.setX(screen.width() - w + 1);
 
458
        } else if (pos.x() < 0) {
 
459
            pos.setX(0);
 
460
        }
 
461
        if (screen.height() < h) {
 
462
            h = screen.height();
 
463
            pos.setY(0);
 
464
        } else if (screen.height() < (pos.y() + h - 1)) {
 
465
            const int topY = pos.y() - thisWidget->height() - h;
 
466
            if (topY >= 0 && (topY + h - 1 < screen.height())) {
 
467
                pos.setY(pos.y() - thisWidget->height() - h);
 
468
            } else {
 
469
                pos.setY(screen.height() - h + 1);
 
470
            }
 
471
        } else if (pos.y() < 0) {
 
472
            pos.setY(0);
 
473
        }
 
474
        popup()->move(pos + screen.topLeft());
 
475
        popup()->resize(w, h);
 
476
 
 
477
        if (m_updatePopupSelectionOnShow) {
 
478
            int recordToHighlight = -1;
 
479
            KDbLookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
 
480
            KDbTableViewData *relData = column() ? column()->relatedData() : 0;
 
481
            if (lookupFieldSchema) {
 
482
                recordToHighlight = recordToHighlightForLookupTable();
 
483
            } else if (relData) {
 
484
                (void)valueForString(origValue().toString(), &recordToHighlight, 0, 1);
 
485
            } else //enum hint
 
486
                recordToHighlight = origValue().toInt();
 
487
 
 
488
            /*-->*/ m_moveCursorToEndInInternalEditor_enabled = show;
 
489
            m_selectAllInInternalEditor_enabled = show;
 
490
            m_setValueInInternalEditor_enabled = show;
 
491
            if (recordToHighlight == -1) {
 
492
                recordToHighlight = qMax(popup()->tableView()->highlightedRecordNumber(), 0);
 
493
                setValueInInternalEditor(QVariant());
 
494
            }
 
495
            popup()->tableView()->selectRecord(recordToHighlight);
 
496
            popup()->tableView()->setHighlightedRecordNumber(recordToHighlight);
 
497
            popup()->tableView()->ensureCellVisible(-1, 0); // scroll to left as expected
 
498
 
 
499
            /*-->*/ m_moveCursorToEndInInternalEditor_enabled = true;
 
500
            m_selectAllInInternalEditor_enabled = true;
 
501
            m_setValueInInternalEditor_enabled = true;
 
502
        }
 
503
    }
 
504
 
 
505
    if (show) {
 
506
        moveCursorToEndInInternalEditor();
 
507
        selectAllInInternalEditor();
 
508
        if (m_focusPopupBeforeShow) {
 
509
            widgetToFocus->setFocus();
 
510
        }
 
511
        popup()->show();
 
512
        popup()->raise();
 
513
        popup()->repaint();
 
514
        if (!m_focusPopupBeforeShow) {
 
515
            widgetToFocus->setFocus();
 
516
        }
 
517
    }
 
518
}
 
519
 
 
520
void KexiComboBoxBase::hide()
 
521
{
 
522
    if (popup())
 
523
        popup()->hide();
 
524
}
 
525
 
 
526
void KexiComboBoxBase::slotRecordAccepted(KDbRecordData* data, int record)
 
527
{
 
528
    Q_UNUSED(record);
 
529
    //update our value
 
530
    //..nothing to do?
 
531
    updateButton();
 
532
    slotRecordSelected(data);
 
533
    /*emit*/acceptRequested();
 
534
}
 
535
 
 
536
void KexiComboBoxBase::acceptPopupSelection()
 
537
{
 
538
    if (!popup())
 
539
        return;
 
540
    KDbRecordData *data = popup()->tableView()->highlightedRecord();
 
541
    if (data) {
 
542
        popup()->tableView()->selectRecord(popup()->tableView()->highlightedRecordNumber());
 
543
        slotRecordAccepted(data, -1);
 
544
    }
 
545
    popup()->hide();
 
546
}
 
547
 
 
548
void KexiComboBoxBase::slotRecordSelected(KDbRecordData*)
 
549
{
 
550
    //qDebug() << "m_visibleValue=" << m_visibleValue;
 
551
 
 
552
    QVariant valueToSet;
 
553
    KDbTableViewData *relData = column() ? column()->relatedData() : 0;
 
554
    KDbLookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
 
555
 
 
556
    m_visibleValue = lookupFieldSchema ? visibleValueForLookupField() : QVariant();
 
557
 
 
558
    if (relData) {
 
559
        //use 'related table data' model
 
560
        KDbRecordData *data = popup()->tableView()->selectedRecord();
 
561
        if (data)
 
562
            valueToSet = data->at(1);
 
563
    } else if (lookupFieldSchema) {
 
564
        KDbRecordData *data = popup()->tableView()->selectedRecord();
 
565
        const int visibleColumn = visibleColumnIndex();
 
566
        if (data && visibleColumn != -1 /* && (int)item->size() >= visibleColumn --already checked*/) {
 
567
            valueToSet = data->at(qMin(visibleColumn, data->count() - 1)/*sanity*/);
 
568
            popup()->tableView()->ensureCellVisible(popup()->tableView()->highlightedRecordNumber(), -1);
 
569
        }
 
570
    } else {
 
571
        //use 'enum hints' model
 
572
        valueToSet = field()->enumHint(popup()->tableView()->currentRecord());
 
573
        if (valueToSet.toString().isEmpty() && !m_insideCreatePopup) {
 
574
            clear();
 
575
            QWidget* thisWidget = dynamic_cast<QWidget*>(this);
 
576
            if (thisWidget) {
 
577
                thisWidget->parentWidget()->setFocus();
 
578
            }
 
579
            return;
 
580
        }
 
581
    }
 
582
    setValueOrTextInInternalEditor(valueToSet);
 
583
    QWidget* thisWidget = dynamic_cast<QWidget*>(this);
 
584
    thisWidget->setFocus();
 
585
    if (m_setValueOrTextInInternalEditor_enabled) {
 
586
        moveCursorToEndInInternalEditor();
 
587
        selectAllInInternalEditor();
 
588
    }
 
589
    // a new (temp) popup table index is selected: do not update selection next time:
 
590
    m_updatePopupSelectionOnShow = false;
 
591
}
 
592
 
 
593
void KexiComboBoxBase::slotInternalEditorValueChanged(const QVariant& v)
 
594
{
 
595
    if (!m_slotInternalEditorValueChanged_enabled)
 
596
        return;
 
597
    m_userEnteredValue = v;
 
598
    m_internalEditorValueChanged = true;
 
599
    if (v.toString().isEmpty()) {
 
600
        if (popup()) {
 
601
            popup()->tableView()->clearSelection();
 
602
        }
 
603
        return;
 
604
    }
 
605
}
 
606
 
 
607
void KexiComboBoxBase::setValueOrTextInInternalEditor(const QVariant& value)
 
608
{
 
609
    if (!m_setValueOrTextInInternalEditor_enabled)
 
610
        return;
 
611
    setValueInInternalEditor(value);
 
612
    //this text is not entered by hand:
 
613
    m_userEnteredValue = QVariant();
 
614
    m_internalEditorValueChanged = false;
 
615
}
 
616
 
 
617
bool KexiComboBoxBase::handleKeyPressForPopup(QKeyEvent *ke)
 
618
{
 
619
    const int k = ke->key();
 
620
    int highlightedOrSelectedRecord = popup() ? popup()->tableView()->highlightedRecordNumber() : -1;
 
621
    if (popup() && highlightedOrSelectedRecord < 0)
 
622
        highlightedOrSelectedRecord = popup()->tableView()->currentRecord();
 
623
 
 
624
    const bool enterPressed = k == Qt::Key_Enter || k == Qt::Key_Return;
 
625
 
 
626
    // The editor may be active but the pull down menu not existent/visible,
 
627
    // e.g. when the user has pressed a normal button to activate the editor
 
628
    // Don't handle the event here in that case.
 
629
    if (!popup() || (!enterPressed && !popup()->isVisible())) {
 
630
        return false;
 
631
    }
 
632
 
 
633
    switch (k) {
 
634
    case Qt::Key_Up:
 
635
        popup()->tableView()->setHighlightedRecordNumber(
 
636
            qMax(highlightedOrSelectedRecord - 1, 0));
 
637
        updateTextForHighlightedRecord();
 
638
        return true;
 
639
    case Qt::Key_Down:
 
640
        popup()->tableView()->setHighlightedRecordNumber(
 
641
            qMin(highlightedOrSelectedRecord + 1, popup()->tableView()->recordCount() - 1));
 
642
        updateTextForHighlightedRecord();
 
643
        return true;
 
644
    case Qt::Key_PageUp:
 
645
        popup()->tableView()->setHighlightedRecordNumber(
 
646
            qMax(highlightedOrSelectedRecord - popup()->tableView()->recordsPerPage(), 0));
 
647
        updateTextForHighlightedRecord();
 
648
        return true;
 
649
    case Qt::Key_PageDown:
 
650
        popup()->tableView()->setHighlightedRecordNumber(
 
651
            qMin(highlightedOrSelectedRecord + popup()->tableView()->recordsPerPage(),
 
652
                 popup()->tableView()->recordCount() - 1));
 
653
        updateTextForHighlightedRecord();
 
654
        return true;
 
655
    case Qt::Key_Home:
 
656
        popup()->tableView()->setHighlightedRecordNumber(0);
 
657
        updateTextForHighlightedRecord();
 
658
        return true;
 
659
    case Qt::Key_End:
 
660
        popup()->tableView()->setHighlightedRecordNumber(popup()->tableView()->recordCount() - 1);
 
661
        updateTextForHighlightedRecord();
 
662
        return true;
 
663
    case Qt::Key_Enter:
 
664
    case Qt::Key_Return: //accept
 
665
        //select record that is highlighted
 
666
        if (popup()->tableView()->highlightedRecordNumber() >= 0) {
 
667
            popup()->tableView()->selectRecord(popup()->tableView()->highlightedRecordNumber());
 
668
            acceptPopupSelection();
 
669
            return true;
 
670
        }
 
671
    default: ;
 
672
    }
 
673
    return false;
 
674
}
 
675
 
 
676
void KexiComboBoxBase::updateTextForHighlightedRecord()
 
677
{
 
678
    KDbRecordData* data = popup() ? popup()->tableView()->highlightedRecord() : 0;
 
679
    if (data)
 
680
        slotRecordSelected(data);
 
681
}
 
682
 
 
683
void KexiComboBoxBase::undoChanges()
 
684
{
 
685
    KDbLookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
 
686
    if (lookupFieldSchema) {
 
687
//  qDebug() << "m_visibleValue BEFORE=" << m_visibleValue;
 
688
        if (popup())
 
689
            popup()->tableView()->selectRecord(popup()->tableView()->highlightedRecordNumber());
 
690
        m_visibleValue = visibleValueForLookupField();
 
691
//  qDebug() << "m_visibleValue AFTER=" << m_visibleValue;
 
692
        setValueOrTextInInternalEditor(m_visibleValue);
 
693
    }
 
694
}