kexicomboboxbase.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qlayout.h>
00022 #include <qstyle.h>
00023 #include <qwindowsstyle.h>
00024 #include <qpainter.h>
00025
00026 #include "kexicomboboxbase.h"
00027 #include <widget/utils/kexicomboboxdropdownbutton.h>
00028 #include "kexicomboboxpopup.h"
00029 #include "kexitableview.h"
00030 #include "kexitableitem.h"
00031 #include "kexi.h"
00032
00033 #include <klineedit.h>
00034
00035 KexiComboBoxBase::KexiComboBoxBase()
00036 {
00037 m_internalEditorValueChanged = false;
00038 m_slotInternalEditorValueChanged_enabled = true;
00039 m_mouseBtnPressedWhenPopupVisible = false;
00040 m_insideCreatePopup = false;
00041 m_setValueOrTextInInternalEditor_enabled = true;
00042 m_updatePopupSelectionOnShow = true;
00043 m_moveCursorToEndInInternalEditor_enabled = true;
00044 m_selectAllInInternalEditor_enabled = true;
00045 m_setValueInInternalEditor_enabled = true;
00046 m_setVisibleValueOnSetValueInternal = false;
00047 }
00048
00049 KexiComboBoxBase::~KexiComboBoxBase()
00050 {
00051 }
00052
00053 KexiDB::LookupFieldSchema *KexiComboBoxBase::lookupFieldSchema() const
00054 {
00055 if (field() && field()->table())
00056 return field()->table()->lookupFieldSchema( *field() );
00057 return 0;
00058 }
00059
00060 int KexiComboBoxBase::rowToHighlightForLookupTable() const
00061 {
00062 if (!popup())
00063 return -1;
00064 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00065 if (!lookupFieldSchema)
00066 return -1;
00067 if (lookupFieldSchema->boundColumn()==-1)
00068 return -1;
00069 bool ok;
00070 const int rowUid = origValue().toInt();
00072 KexiTableViewData *tvData = popup()->tableView()->data();
00073 const int boundColumn = lookupFieldSchema->boundColumn();
00074 KexiTableViewData::Iterator it(tvData->iterator());
00075 int row=0;
00076 for (;it.current();++it, row++)
00077 {
00078 if (it.current()->at(boundColumn).toInt(&ok) == rowUid && ok || !ok)
00079 break;
00080 }
00081 if (!ok || !it.current())
00082 return -1;
00083 return row;
00084 }
00085
00086 void KexiComboBoxBase::setValueInternal(const QVariant& add_, bool removeOld)
00087 {
00088 Q_UNUSED(removeOld);
00089 m_mouseBtnPressedWhenPopupVisible = false;
00090 m_updatePopupSelectionOnShow = true;
00091 QString add(add_.toString());
00092 if (add.isEmpty()) {
00093 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00094 QVariant valueToSet;
00095 bool hasValueToSet = true;
00096 int rowToHighlight = -1;
00097 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00098 if (lookupFieldSchema) {
00099
00101 if (lookupFieldSchema->boundColumn()==-1)
00103 return;
00104 if (m_setVisibleValueOnSetValueInternal) {
00105
00106 if (!popup())
00107 createPopup(false);
00108 }
00109 if (popup()) {
00110 const int rowToHighlight = rowToHighlightForLookupTable();
00111 popup()->tableView()->setHighlightedRow(rowToHighlight);
00112 }
00113 if (m_setVisibleValueOnSetValueInternal && -1!=lookupFieldSchema->visibleColumn()) {
00114
00115 KexiTableItem *it = popup()->tableView()->highlightedItem();
00116 if (it)
00117 valueToSet = it->at( lookupFieldSchema->visibleColumn() );
00118 }
00119 else {
00120 hasValueToSet = false;
00121 }
00122 }
00123 else if (relData) {
00124
00125 valueToSet = valueForString(origValue().toString(), &rowToHighlight, 0, 1);
00126 }
00127 else {
00128
00129 const int row = origValue().toInt();
00130 valueToSet = field()->enumHint(row).stripWhiteSpace();
00131 }
00132 if (hasValueToSet)
00133 setValueOrTextInInternalEditor( valueToSet );
00134 moveCursorToEndInInternalEditor();
00135 selectAllInInternalEditor();
00136
00137 if (popup()) {
00138 if (origValue().isNull()) {
00139 popup()->tableView()->clearSelection();
00140 popup()->tableView()->setHighlightedRow(0);
00141 } else {
00142 if (relData) {
00143 if (rowToHighlight!=-1)
00144 popup()->tableView()->setHighlightedRow(rowToHighlight);
00145 }
00146 else if (!lookupFieldSchema) {
00147
00148 popup()->tableView()->setHighlightedRow(origValue().toInt());
00149 }
00150 }
00151 }
00152 }
00153 else {
00154
00155 if (popup())
00156 popup()->tableView()->clearSelection();
00157 setValueInInternalEditor(add);
00158
00159 moveCursorToEndInInternalEditor();
00160 }
00161 }
00162
00163 KexiTableItem* KexiComboBoxBase::selectItemForEnteredValueInLookupTable(const QVariant& v)
00164 {
00165 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00166 if (!popup() || !lookupFieldSchema)
00167 return 0;
00168
00169
00170
00171 const bool valueIsText = v.type()==QVariant::String || v.type()==QVariant::CString;
00172 const QString txt( valueIsText ? v.toString().stripWhiteSpace().lower() : QString::null );
00173 KexiTableViewData *lookupData = popup()->tableView()->data();
00174 const int visibleColumn = lookupFieldSchema->visibleColumn();
00175 if (-1 == visibleColumn)
00176 return 0;
00177 KexiTableViewData::Iterator it(lookupData->iterator());
00178 int row;
00179 for (row = 0;it.current();++it, row++) {
00180 if (valueIsText) {
00181 if (it.current()->at(visibleColumn).toString().stripWhiteSpace().lower() == txt)
00182 break;
00183 }
00184 else {
00185 if (it.current()->at(visibleColumn) == v)
00186 break;
00187 }
00188 }
00189
00190 m_setValueOrTextInInternalEditor_enabled = false;
00191
00192 if (it.current())
00193 popup()->tableView()->selectRow(row);
00194 else
00195 popup()->tableView()->clearSelection();
00196
00197 m_setValueOrTextInInternalEditor_enabled = true;
00198
00199 return it.current();
00200 }
00201
00202 QString KexiComboBoxBase::valueForString(const QString& str, int* row,
00203 uint lookInColumn, uint returnFromColumn, bool allowNulls)
00204 {
00205 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00206 if (!relData)
00207 return QString::null;
00208
00209
00210
00211
00212 const QString txt = str.stripWhiteSpace().lower();
00213 KexiTableViewData::Iterator it( relData->iterator() );
00214 for (*row = 0;it.current();++it, (*row)++) {
00215 if (it.current()->at(lookInColumn).toString().stripWhiteSpace().lower()==txt)
00216 break;
00217 }
00218 if (it.current())
00219 return it.current()->at(returnFromColumn).toString();
00220
00221 *row = -1;
00222
00223 if (column() && column()->relatedDataEditable())
00224 return str;
00225
00226 kexiwarn << "KexiComboBoxBase::valueForString(): no related row found, ID will be painted!" << endl;
00227 if (allowNulls)
00228 return QString::null;
00229 return str;
00230 }
00231
00232 QVariant KexiComboBoxBase::value()
00233 {
00234 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00235 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00236 if (relData) {
00237 if (m_internalEditorValueChanged) {
00238
00239
00240 int rowToHighlight;
00241 return valueForString(m_userEnteredValue.toString(), &rowToHighlight, 1, 0, true);
00242 }
00243 else {
00244
00245 KexiTableItem *it = popup() ? popup()->tableView()->selectedItem() : 0;
00246 return it ? it->at(0) : origValue();
00247 }
00248 }
00249 else if (lookupFieldSchema)
00250 {
00251 if (lookupFieldSchema->boundColumn()==-1)
00252 return origValue();
00253 KexiTableItem *it = popup() ? popup()->tableView()->selectedItem() : 0;
00254 if ( m_internalEditorValueChanged && !m_userEnteredValue.toString().isEmpty()) {
00255
00256 if (!popup())
00257 createPopup(false);
00258 it = selectItemForEnteredValueInLookupTable( m_userEnteredValue );
00259 }
00260 return it ? it->at( lookupFieldSchema->boundColumn() ) : QVariant();
00261 }
00262 else if (popup()) {
00263
00264 const int row = popup()->tableView()->currentRow();
00265 if (row>=0)
00266 return QVariant( row );
00267 }
00268
00269 if (valueFromInternalEditor().toString().isEmpty())
00270 return QVariant();
00273 return origValue();
00274 }
00275
00276 QVariant KexiComboBoxBase::visibleValueForLookupField()
00277 {
00278 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00279 if (!popup() || !lookupFieldSchema || -1 == lookupFieldSchema->visibleColumn())
00280 return QVariant();
00281 KexiTableItem *it = popup()->tableView()->selectedItem();
00282 return it ? it->at( lookupFieldSchema->visibleColumn() ) : QVariant();
00283 }
00284
00285 QVariant KexiComboBoxBase::visibleValue()
00286 {
00287 return m_visibleValue;
00288 }
00289
00290 void KexiComboBoxBase::clear()
00291 {
00292 if (popup())
00293 popup()->hide();
00294 slotInternalEditorValueChanged(QVariant());
00295 }
00296
00297 tristate KexiComboBoxBase::valueChangedInternal()
00298 {
00299
00300 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00301 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00302 if (relData || lookupFieldSchema) {
00303 if (m_internalEditorValueChanged)
00304 return true;
00305
00306
00307 KexiTableItem *it = popup() ? popup()->tableView()->selectedItem() : 0;
00308 if (!it)
00309 return false;
00310 }
00311 else {
00312
00313 const int row = popup() ? popup()->tableView()->currentRow() : -1;
00314 if (row<0 && !m_internalEditorValueChanged)
00315 return false;
00316 }
00317
00318 return cancelled;
00319 }
00320
00321 bool KexiComboBoxBase::valueIsNull()
00322 {
00323
00324 QVariant v( value() );
00325 return v.isNull();
00326
00327 }
00328
00329 bool KexiComboBoxBase::valueIsEmpty()
00330 {
00331 return valueIsNull();
00332 }
00333
00334 void KexiComboBoxBase::showPopup()
00335 {
00336 createPopup(true);
00337 }
00338
00339 void KexiComboBoxBase::createPopup(bool show)
00340 {
00341 if (!field())
00342 return;
00343 m_insideCreatePopup = true;
00344 QWidget* thisWidget = dynamic_cast<QWidget*>(this);
00345 QWidget *widgetToFocus = internalEditor() ? internalEditor() : thisWidget;
00346 if (!popup()) {
00347 setPopup( column() ? new KexiComboBoxPopup(thisWidget, *column())
00348 : new KexiComboBoxPopup(thisWidget, *field()) );
00349 QObject::connect(popup(), SIGNAL(rowAccepted(KexiTableItem*,int)),
00350 thisWidget, SLOT(slotRowAccepted(KexiTableItem*,int)));
00351 QObject::connect(popup()->tableView(), SIGNAL(itemSelected(KexiTableItem*)),
00352 thisWidget, SLOT(slotItemSelected(KexiTableItem*)));
00353
00354 popup()->setFocusProxy( widgetToFocus );
00355 popup()->tableView()->setFocusProxy( widgetToFocus );
00356 popup()->installEventFilter(thisWidget);
00357
00358 if (origValue().isNull())
00359 popup()->tableView()->clearSelection();
00360 else {
00361 popup()->tableView()->selectRow( 0 );
00362 popup()->tableView()->setHighlightedRow( 0 );
00363 }
00364 }
00365 if (show && internalEditor() && !internalEditor()->isVisible())
00366 editRequested();
00367
00368 QPoint posMappedToGlobal = mapFromParentToGlobal(thisWidget->pos());
00369 if (posMappedToGlobal != QPoint(-1,-1)) {
00371 popup()->move( posMappedToGlobal + QPoint(0, thisWidget->height()) );
00372
00373 const int w = popupWidthHint();
00374 popup()->resize(w, 0);
00375 if (show)
00376 popup()->show();
00377 popup()->updateSize(w);
00378 if (m_updatePopupSelectionOnShow) {
00379 int rowToHighlight = -1;
00380 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00381 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00382 if (lookupFieldSchema) {
00383 rowToHighlight = rowToHighlightForLookupTable();
00384 }
00385 else if (relData) {
00386 (void)valueForString(origValue().toString(), &rowToHighlight, 0, 1);
00387 }
00388 else
00389 rowToHighlight = origValue().toInt();
00390
00391 m_moveCursorToEndInInternalEditor_enabled = show;
00392 m_selectAllInInternalEditor_enabled = show;
00393 m_setValueInInternalEditor_enabled = show;
00394 if (rowToHighlight==-1) {
00395 rowToHighlight = QMAX( popup()->tableView()->highlightedRow(), 0);
00396 setValueInInternalEditor(QVariant());
00397 }
00398 popup()->tableView()->selectRow( rowToHighlight );
00399 popup()->tableView()->setHighlightedRow( rowToHighlight );
00400 if (rowToHighlight < popup()->tableView()->rowsPerPage())
00401 popup()->tableView()->ensureCellVisible( 0, -1 );
00402
00403 m_moveCursorToEndInInternalEditor_enabled = true;
00404 m_selectAllInInternalEditor_enabled = true;
00405 m_setValueInInternalEditor_enabled = true;
00406 }
00407 }
00408
00409 if (show) {
00410 moveCursorToEndInInternalEditor();
00411 selectAllInInternalEditor();
00412 widgetToFocus->setFocus();
00413 }
00414 m_insideCreatePopup = false;
00415 }
00416
00417 void KexiComboBoxBase::hide()
00418 {
00419 if (popup())
00420 popup()->hide();
00421 }
00422
00423 void KexiComboBoxBase::slotRowAccepted(KexiTableItem * item, int row)
00424 {
00425 Q_UNUSED(row);
00426
00427
00428 updateButton();
00429 slotItemSelected(item);
00430 acceptRequested();
00431 }
00432
00433 void KexiComboBoxBase::acceptPopupSelection()
00434 {
00435 if (!popup())
00436 return;
00437 KexiTableItem *item = popup()->tableView()->highlightedItem();
00438 if (item) {
00439 popup()->tableView()->selectRow( popup()->tableView()->highlightedRow() );
00440 slotRowAccepted(item, -1);
00441 }
00442 popup()->hide();
00443 }
00444
00445 void KexiComboBoxBase::slotItemSelected(KexiTableItem*)
00446 {
00447 kexidbg << "KexiComboBoxBase::slotItemSelected(): m_visibleValue = " << m_visibleValue << endl;
00448
00449 QVariant valueToSet;
00450 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00451 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00452
00453 m_visibleValue = lookupFieldSchema ? visibleValueForLookupField() : QVariant();
00454
00455 if (relData) {
00456
00457 KexiTableItem *item = popup()->tableView()->selectedItem();
00458 if (item)
00459 valueToSet = item->at(1);
00460 }
00461 else if (lookupFieldSchema) {
00462 KexiTableItem *item = popup()->tableView()->selectedItem();
00463 if (item && lookupFieldSchema->visibleColumn()!=-1 && (int)item->size() >= lookupFieldSchema->visibleColumn()) {
00464 valueToSet = item->at( lookupFieldSchema->visibleColumn() );
00465 }
00466 }
00467 else {
00468
00469 valueToSet = field()->enumHint( popup()->tableView()->currentRow() );
00470 if (valueToSet.toString().isEmpty() && !m_insideCreatePopup) {
00471 clear();
00472 QWidget* thisWidget = dynamic_cast<QWidget*>(this);
00473 thisWidget->parentWidget()->setFocus();
00474 return;
00475 }
00476 }
00477 setValueOrTextInInternalEditor( valueToSet );
00478 if (m_setValueOrTextInInternalEditor_enabled) {
00479 moveCursorToEndInInternalEditor();
00480 selectAllInInternalEditor();
00481 }
00482
00483 m_updatePopupSelectionOnShow = false;
00484 }
00485
00486 void KexiComboBoxBase::slotInternalEditorValueChanged(const QVariant& v)
00487 {
00488 if (!m_slotInternalEditorValueChanged_enabled)
00489 return;
00490 m_userEnteredValue = v;
00491 m_internalEditorValueChanged = true;
00492 if (v.toString().isEmpty()) {
00493 if (popup()) {
00494 popup()->tableView()->clearSelection();
00495 }
00496 return;
00497 }
00498 }
00499
00500 void KexiComboBoxBase::setValueOrTextInInternalEditor(const QVariant& value)
00501 {
00502 if (!m_setValueOrTextInInternalEditor_enabled)
00503 return;
00504 setValueInInternalEditor( value );
00505
00506 m_userEnteredValue = QVariant();
00507 m_internalEditorValueChanged = false;
00508 }
00509
00510 bool KexiComboBoxBase::handleKeyPressForPopup( QKeyEvent *ke )
00511 {
00512 const int k = ke->key();
00513 int highlightedOrSelectedRow = popup() ? popup()->tableView()->highlightedRow() : -1;
00514 if (popup() && highlightedOrSelectedRow < 0)
00515 highlightedOrSelectedRow = popup()->tableView()->currentRow();
00516
00517 const bool enterPressed = k==Qt::Key_Enter || k==Qt::Key_Return;
00518
00519
00520
00521
00522 if (!popup() || (!enterPressed && !popup()->isVisible())) {
00523 return false;
00524 }
00525
00526 switch (k) {
00527 case Qt::Key_Up:
00528 popup()->tableView()->setHighlightedRow(
00529 QMAX(highlightedOrSelectedRow-1, 0) );
00530 updateTextForHighlightedRow();
00531 return true;
00532 case Qt::Key_Down:
00533 popup()->tableView()->setHighlightedRow(
00534 QMIN(highlightedOrSelectedRow+1, popup()->tableView()->rows()-1) );
00535 updateTextForHighlightedRow();
00536 return true;
00537 case Qt::Key_PageUp:
00538 popup()->tableView()->setHighlightedRow(
00539 QMAX(highlightedOrSelectedRow-popup()->tableView()->rowsPerPage(), 0) );
00540 updateTextForHighlightedRow();
00541 return true;
00542 case Qt::Key_PageDown:
00543 popup()->tableView()->setHighlightedRow(
00544 QMIN(highlightedOrSelectedRow+popup()->tableView()->rowsPerPage(),
00545 popup()->tableView()->rows()-1) );
00546 updateTextForHighlightedRow();
00547 return true;
00548 case Qt::Key_Home:
00549 popup()->tableView()->setHighlightedRow( 0 );
00550 updateTextForHighlightedRow();
00551 return true;
00552 case Qt::Key_End:
00553 popup()->tableView()->setHighlightedRow( popup()->tableView()->rows()-1 );
00554 updateTextForHighlightedRow();
00555 return true;
00556 case Qt::Key_Enter:
00557 case Qt::Key_Return:
00558
00559 if (popup()->tableView()->highlightedRow()>=0)
00560 popup()->tableView()->selectRow( popup()->tableView()->highlightedRow() );
00561
00562 default: ;
00563 }
00564 return false;
00565 }
00566
00567 void KexiComboBoxBase::updateTextForHighlightedRow()
00568 {
00569 KexiTableItem *item = popup() ? popup()->tableView()->highlightedItem() : 0;
00570 if (item)
00571 slotItemSelected(item);
00572 }
00573
00574 void KexiComboBoxBase::undoChanges()
00575 {
00576 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00577 if (lookupFieldSchema) {
00578
00579 if (popup())
00580 popup()->tableView()->selectRow( popup()->tableView()->highlightedRow() );
00581 m_visibleValue = visibleValueForLookupField();
00582
00583 setValueOrTextInInternalEditor( m_visibleValue );
00584 }
00585 }
This file is part of the documentation for Kexi 2.0 alpha.