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 KexiTableViewData::Iterator it(lookupData->iterator());
00176 int row;
00177 for (row = 0;it.current();++it, row++) {
00178 if (valueIsText) {
00179 if (it.current()->at(visibleColumn).toString().stripWhiteSpace().lower() == txt)
00180 break;
00181 }
00182 else {
00183 if (it.current()->at(visibleColumn) == v)
00184 break;
00185 }
00186 }
00187
00188 m_setValueOrTextInInternalEditor_enabled = false;
00189
00190 if (it.current())
00191 popup()->tableView()->selectRow(row);
00192 else
00193 popup()->tableView()->clearSelection();
00194
00195 m_setValueOrTextInInternalEditor_enabled = true;
00196
00197 return it.current();
00198 }
00199
00200 QString KexiComboBoxBase::valueForString(const QString& str, int* row,
00201 uint lookInColumn, uint returnFromColumn, bool allowNulls)
00202 {
00203 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00204 if (!relData)
00205 return QString::null;
00206
00207
00208
00209
00210 const QString txt = str.stripWhiteSpace().lower();
00211 KexiTableViewData::Iterator it( relData->iterator() );
00212 for (*row = 0;it.current();++it, (*row)++) {
00213 if (it.current()->at(lookInColumn).toString().stripWhiteSpace().lower()==txt)
00214 break;
00215 }
00216 if (it.current())
00217 return it.current()->at(returnFromColumn).toString();
00218
00219 *row = -1;
00220
00221 if (column() && column()->relatedDataEditable())
00222 return str;
00223
00224 kexiwarn << "KexiComboBoxBase::valueForString(): no related row found, ID will be painted!" << endl;
00225 if (allowNulls)
00226 return QString::null;
00227 return str;
00228 }
00229
00230 QVariant KexiComboBoxBase::value()
00231 {
00232 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00233 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00234 if (relData) {
00235 if (m_internalEditorValueChanged) {
00236
00237
00238 int rowToHighlight;
00239 return valueForString(m_userEnteredValue.toString(), &rowToHighlight, 1, 0, true);
00240 }
00241 else {
00242
00243 KexiTableItem *it = popup() ? popup()->tableView()->selectedItem() : 0;
00244 return it ? it->at(0) : origValue();
00245 }
00246 }
00247 else if (lookupFieldSchema)
00248 {
00249 if (lookupFieldSchema->boundColumn()==-1)
00250 return origValue();
00251 KexiTableItem *it = popup() ? popup()->tableView()->selectedItem() : 0;
00252 if ( m_internalEditorValueChanged && !m_userEnteredValue.toString().isEmpty()) {
00253
00254 if (!popup())
00255 createPopup(false);
00256 it = selectItemForEnteredValueInLookupTable( m_userEnteredValue );
00257 }
00258 return it ? it->at( lookupFieldSchema->boundColumn() ) : QVariant();
00259 }
00260 else if (popup()) {
00261
00262 const int row = popup()->tableView()->currentRow();
00263 if (row>=0)
00264 return QVariant( row );
00265 }
00266
00267 if (valueFromInternalEditor().toString().isEmpty())
00268 return QVariant();
00271 return origValue();
00272 }
00273
00274 QVariant KexiComboBoxBase::visibleValueForLookupField()
00275 {
00276 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00277 if (!popup() || !lookupFieldSchema)
00278 return QVariant();
00279 KexiTableItem *it = popup()->tableView()->selectedItem();
00280 return it ? it->at( lookupFieldSchema->visibleColumn() ) : QVariant();
00281 }
00282
00283 QVariant KexiComboBoxBase::visibleValue()
00284 {
00285 return m_visibleValue;
00286 }
00287
00288 void KexiComboBoxBase::clear()
00289 {
00290 if (popup())
00291 popup()->hide();
00292 slotInternalEditorValueChanged(QVariant());
00293 }
00294
00295 tristate KexiComboBoxBase::valueChangedInternal()
00296 {
00297
00298 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00299 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00300 if (relData || lookupFieldSchema) {
00301 if (m_internalEditorValueChanged)
00302 return true;
00303
00304
00305 KexiTableItem *it = popup() ? popup()->tableView()->selectedItem() : 0;
00306 if (!it)
00307 return false;
00308 }
00309 else {
00310
00311 const int row = popup() ? popup()->tableView()->currentRow() : -1;
00312 if (row<0 && !m_internalEditorValueChanged)
00313 return false;
00314 }
00315
00316 return cancelled;
00317 }
00318
00319 bool KexiComboBoxBase::valueIsNull()
00320 {
00321
00322 QVariant v( value() );
00323 return v.isNull();
00324
00325 }
00326
00327 bool KexiComboBoxBase::valueIsEmpty()
00328 {
00329 return valueIsNull();
00330 }
00331
00332 void KexiComboBoxBase::showPopup()
00333 {
00334 createPopup(true);
00335 }
00336
00337 void KexiComboBoxBase::createPopup(bool show)
00338 {
00339 if (!field())
00340 return;
00341 m_insideCreatePopup = true;
00342 QWidget* thisWidget = dynamic_cast<QWidget*>(this);
00343 QWidget *widgetToFocus = internalEditor() ? internalEditor() : thisWidget;
00344 if (!popup()) {
00345 setPopup( column() ? new KexiComboBoxPopup(thisWidget, *column())
00346 : new KexiComboBoxPopup(thisWidget, *field()) );
00347 QObject::connect(popup(), SIGNAL(rowAccepted(KexiTableItem*,int)),
00348 thisWidget, SLOT(slotRowAccepted(KexiTableItem*,int)));
00349 QObject::connect(popup()->tableView(), SIGNAL(itemSelected(KexiTableItem*)),
00350 thisWidget, SLOT(slotItemSelected(KexiTableItem*)));
00351
00352 popup()->setFocusProxy( widgetToFocus );
00353 popup()->tableView()->setFocusProxy( widgetToFocus );
00354 popup()->installEventFilter(thisWidget);
00355
00356 if (origValue().isNull())
00357 popup()->tableView()->clearSelection();
00358 else {
00359 popup()->tableView()->selectRow( 0 );
00360 popup()->tableView()->setHighlightedRow( 0 );
00361 }
00362 }
00363 if (show && internalEditor() && !internalEditor()->isVisible())
00364 editRequested();
00365
00366 QPoint posMappedToGlobal = mapFromParentToGlobal(thisWidget->pos());
00367 if (posMappedToGlobal != QPoint(-1,-1)) {
00369 popup()->move( posMappedToGlobal + QPoint(0, thisWidget->height()) );
00370
00371 const int w = popupWidthHint();
00372 popup()->resize(w, 0);
00373 if (show)
00374 popup()->show();
00375 popup()->updateSize(w);
00376 if (m_updatePopupSelectionOnShow) {
00377 int rowToHighlight = -1;
00378 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00379 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00380 if (lookupFieldSchema) {
00381 rowToHighlight = rowToHighlightForLookupTable();
00382 }
00383 else if (relData) {
00384 (void)valueForString(origValue().toString(), &rowToHighlight, 0, 1);
00385 }
00386 else
00387 rowToHighlight = origValue().toInt();
00388
00389 m_moveCursorToEndInInternalEditor_enabled = show;
00390 m_selectAllInInternalEditor_enabled = show;
00391 m_setValueInInternalEditor_enabled = show;
00392 if (rowToHighlight==-1) {
00393 rowToHighlight = QMAX( popup()->tableView()->highlightedRow(), 0);
00394 setValueInInternalEditor(QVariant());
00395 }
00396 popup()->tableView()->selectRow( rowToHighlight );
00397 popup()->tableView()->setHighlightedRow( rowToHighlight );
00398 if (rowToHighlight < popup()->tableView()->rowsPerPage())
00399 popup()->tableView()->ensureCellVisible( 0, -1 );
00400
00401 m_moveCursorToEndInInternalEditor_enabled = true;
00402 m_selectAllInInternalEditor_enabled = true;
00403 m_setValueInInternalEditor_enabled = true;
00404 }
00405 }
00406
00407 if (show) {
00408 moveCursorToEndInInternalEditor();
00409 selectAllInInternalEditor();
00410 widgetToFocus->setFocus();
00411 }
00412 m_insideCreatePopup = false;
00413 }
00414
00415 void KexiComboBoxBase::hide()
00416 {
00417 if (popup())
00418 popup()->hide();
00419 }
00420
00421 void KexiComboBoxBase::slotRowAccepted(KexiTableItem * item, int row)
00422 {
00423 Q_UNUSED(row);
00424
00425
00426 updateButton();
00427 slotItemSelected(item);
00428 acceptRequested();
00429 }
00430
00431 void KexiComboBoxBase::acceptPopupSelection()
00432 {
00433 if (!popup())
00434 return;
00435 KexiTableItem *item = popup()->tableView()->highlightedItem();
00436 if (item) {
00437 popup()->tableView()->selectRow( popup()->tableView()->highlightedRow() );
00438 slotRowAccepted(item, -1);
00439 }
00440 popup()->hide();
00441 }
00442
00443 void KexiComboBoxBase::slotItemSelected(KexiTableItem*)
00444 {
00445 kexidbg << "KexiComboBoxBase::slotItemSelected(): m_visibleValue = " << m_visibleValue << endl;
00446
00447 QVariant valueToSet;
00448 KexiTableViewData *relData = column() ? column()->relatedData() : 0;
00449 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00450
00451 m_visibleValue = lookupFieldSchema ? visibleValueForLookupField() : QVariant();
00452
00453 if (relData) {
00454
00455 KexiTableItem *item = popup()->tableView()->selectedItem();
00456 if (item)
00457 valueToSet = item->at(1);
00458 }
00459 else if (lookupFieldSchema) {
00460 KexiTableItem *item = popup()->tableView()->selectedItem();
00461 if (item && lookupFieldSchema->visibleColumn()!=-1 && (int)item->size() >= lookupFieldSchema->visibleColumn()) {
00462 valueToSet = item->at( lookupFieldSchema->visibleColumn() );
00463 }
00464 }
00465 else {
00466
00467 valueToSet = field()->enumHint( popup()->tableView()->currentRow() );
00468 if (valueToSet.toString().isEmpty() && !m_insideCreatePopup) {
00469 clear();
00470 QWidget* thisWidget = dynamic_cast<QWidget*>(this);
00471 thisWidget->parentWidget()->setFocus();
00472 return;
00473 }
00474 }
00475 setValueOrTextInInternalEditor( valueToSet );
00476 if (m_setValueOrTextInInternalEditor_enabled) {
00477 moveCursorToEndInInternalEditor();
00478 selectAllInInternalEditor();
00479 }
00480
00481 m_updatePopupSelectionOnShow = false;
00482 }
00483
00484 void KexiComboBoxBase::slotInternalEditorValueChanged(const QVariant& v)
00485 {
00486 if (!m_slotInternalEditorValueChanged_enabled)
00487 return;
00488 m_userEnteredValue = v;
00489 m_internalEditorValueChanged = true;
00490 if (v.toString().isEmpty()) {
00491 if (popup()) {
00492 popup()->tableView()->clearSelection();
00493 }
00494 return;
00495 }
00496 }
00497
00498 void KexiComboBoxBase::setValueOrTextInInternalEditor(const QVariant& value)
00499 {
00500 if (!m_setValueOrTextInInternalEditor_enabled)
00501 return;
00502 setValueInInternalEditor( value );
00503
00504 m_userEnteredValue = QVariant();
00505 m_internalEditorValueChanged = false;
00506 }
00507
00508 bool KexiComboBoxBase::handleKeyPressForPopup( QKeyEvent *ke )
00509 {
00510 const int k = ke->key();
00511 int highlightedOrSelectedRow = popup() ? popup()->tableView()->highlightedRow() : -1;
00512 if (popup() && highlightedOrSelectedRow < 0)
00513 highlightedOrSelectedRow = popup()->tableView()->currentRow();
00514
00515 const bool enterPressed = k==Qt::Key_Enter || k==Qt::Key_Return;
00516
00517
00518
00519
00520 if (!popup() || (!enterPressed && !popup()->isVisible())) {
00521 return false;
00522 }
00523
00524 switch (k) {
00525 case Qt::Key_Up:
00526 popup()->tableView()->setHighlightedRow(
00527 QMAX(highlightedOrSelectedRow-1, 0) );
00528 updateTextForHighlightedRow();
00529 return true;
00530 case Qt::Key_Down:
00531 popup()->tableView()->setHighlightedRow(
00532 QMIN(highlightedOrSelectedRow+1, popup()->tableView()->rows()-1) );
00533 updateTextForHighlightedRow();
00534 return true;
00535 case Qt::Key_PageUp:
00536 popup()->tableView()->setHighlightedRow(
00537 QMAX(highlightedOrSelectedRow-popup()->tableView()->rowsPerPage(), 0) );
00538 updateTextForHighlightedRow();
00539 return true;
00540 case Qt::Key_PageDown:
00541 popup()->tableView()->setHighlightedRow(
00542 QMIN(highlightedOrSelectedRow+popup()->tableView()->rowsPerPage(),
00543 popup()->tableView()->rows()-1) );
00544 updateTextForHighlightedRow();
00545 return true;
00546 case Qt::Key_Home:
00547 popup()->tableView()->setHighlightedRow( 0 );
00548 updateTextForHighlightedRow();
00549 return true;
00550 case Qt::Key_End:
00551 popup()->tableView()->setHighlightedRow( popup()->tableView()->rows()-1 );
00552 updateTextForHighlightedRow();
00553 return true;
00554 case Qt::Key_Enter:
00555 case Qt::Key_Return:
00556
00557 if (popup()->tableView()->highlightedRow()>=0)
00558 popup()->tableView()->selectRow( popup()->tableView()->highlightedRow() );
00559
00560 default: ;
00561 }
00562 return false;
00563 }
00564
00565 void KexiComboBoxBase::updateTextForHighlightedRow()
00566 {
00567 KexiTableItem *item = popup() ? popup()->tableView()->highlightedItem() : 0;
00568 if (item)
00569 slotItemSelected(item);
00570 }
00571
00572 void KexiComboBoxBase::undoChanges()
00573 {
00574 KexiDB::LookupFieldSchema *lookupFieldSchema = this->lookupFieldSchema();
00575 if (lookupFieldSchema) {
00576
00577 if (popup())
00578 popup()->tableView()->selectRow( popup()->tableView()->highlightedRow() );
00579 m_visibleValue = visibleValueForLookupField();
00580
00581 setValueOrTextInInternalEditor( m_visibleValue );
00582 }
00583 }