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 "kexicomboboxtableedit.h"
00027 #include "kexicomboboxpopup.h"
00028 #include "kexitableview.h"
00029 #include "kexitableitem.h"
00030 #include "kexi.h"
00031
00032 #include <kpushbutton.h>
00033 #include <klineedit.h>
00034
00036 class KDownArrowPushButton : public KPushButton
00037 {
00038 public:
00039 KDownArrowPushButton( QWidget *parent )
00040 : KPushButton(parent)
00041 {
00042 setToggleButton(true);
00043 styleChange(style());
00044 }
00045 protected:
00048 virtual void drawButton(QPainter *p) {
00049
00050 int flags = QStyle::Style_Enabled | QStyle::Style_HasFocus;
00051 if (isDown())
00052 flags |= QStyle::Style_Down;
00053
00054 KPushButton::drawButton(p);
00055
00056 QRect r = rect();
00057 r.setHeight(r.height()+m_fixForHeight);
00058 if (m_drawComplexControl) {
00059
00060 style().drawComplexControl( QStyle::CC_ComboBox, p, this, r, colorGroup(),
00061 flags, (uint)(QStyle::SC_ComboBoxArrow ),
00062 QStyle::SC_None );
00063 }
00064 else {
00065 r.setWidth(r.width()+2);
00066 style().drawPrimitive( QStyle::PE_ArrowDown, p, r, colorGroup(), flags);
00067 }
00068 }
00069 virtual void styleChange( QStyle & oldStyle ) {
00070
00071 if (qstricmp(style().name(),"thinkeramik")==0) {
00072 m_fixForHeight = 3;
00073 }
00074 else
00075 m_fixForHeight = 0;
00076
00077 m_drawComplexControl = style().inherits("KStyle") || qstricmp(style().name(),"platinum")==0;
00078 setFixedWidth( style().querySubControlMetrics( QStyle::CC_ComboBox,
00079 this, QStyle::SC_ComboBoxArrow ).width() +1 );
00080 KPushButton::styleChange(oldStyle);
00081 }
00082
00083 int m_fixForHeight;
00084 bool m_drawComplexControl : 1;
00085 };
00086
00087
00088
00090 class KexiComboBoxTableEdit::Private
00091 {
00092 public:
00093 Private()
00094 : popup(0)
00095 {
00096 mouseBtnPressedWhenPopupVisible = false;
00097 currentEditorWidth = 0;
00098 slotLineEditTextChanged_enabled = true;
00099 userEnteredTextChanged = false;
00100 }
00101 KPushButton *button;
00102 KexiComboBoxPopup *popup;
00103 int parentRightMargin;
00104 int currentEditorWidth;
00105 QSize totalSize;
00106 QString userEnteredText;
00107 bool mouseBtnPressedWhenPopupVisible : 1;
00108 bool slotLineEditTextChanged_enabled : 1;
00109 bool userEnteredTextChanged : 1;
00110 };
00111
00112
00113
00114 KexiComboBoxTableEdit::KexiComboBoxTableEdit(KexiTableViewColumn &column, QScrollView *parent)
00115 : KexiInputTableEdit(column, parent)
00116 , d(new Private())
00117 {
00118 setName("KexiComboBoxTableEdit");
00119
00120 d->button = new KDownArrowPushButton( parent->viewport() );
00121 d->button->hide();
00122 d->button->setFocusPolicy( NoFocus );
00123 connect(d->button, SIGNAL(clicked()), this, SLOT(slotButtonClicked()));
00124
00125 connect(m_lineedit, SIGNAL(textChanged(const QString&)), this, SLOT(slotLineEditTextChanged(const QString&)));
00126
00127 d->parentRightMargin = m_rightMargin;
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 }
00150
00151 KexiComboBoxTableEdit::~KexiComboBoxTableEdit()
00152 {
00153 delete d;
00154 }
00155
00156 void KexiComboBoxTableEdit::setValueInternal(const QVariant& add_, bool removeOld)
00157 {
00158 Q_UNUSED(removeOld);
00159 d->mouseBtnPressedWhenPopupVisible = false;
00160
00161 QString add(add_.toString());
00162 if (add.isEmpty()) {
00163 KexiTableViewData *relData = column()->relatedData();
00164 QString stringValue;
00165 if (relData) {
00166
00167
00168
00169 stringValue = valueForString(m_origValue.toString(), 0, 1);
00171
00172 }
00173 else {
00174
00175 const int row = m_origValue.toInt();
00176 stringValue = field()->enumHint(row);
00177 }
00178 setLineEditText( stringValue );
00179
00180 if (d->popup) {
00181 if (m_origValue.isNull()) {
00182 d->popup->tableView()->clearSelection();
00183 d->popup->tableView()->setHighlightedRow(0);
00184 } else {
00185 if (relData) {
00186 int row = 0;
00187 KexiTableViewData::Iterator it(relData->iterator());
00188 for (;it.current();++it, row++)
00189 {
00190 kexidbg << "- '" <<it.current()->at(0).toString() << "' '"<<it.current()->at(1).toString()<<"'"<<endl;
00191 if (it.current()->at(0).toString()==stringValue)
00192 break;
00193 }
00194 if (it.current()) {
00195 d->popup->tableView()->setHighlightedRow(row);
00196 }
00197 else {
00198
00199 if (!relData->isEmpty())
00200 d->popup->tableView()->setHighlightedRow(0);
00201 }
00202
00203 }
00204 else {
00205
00206 d->popup->tableView()->setHighlightedRow(m_origValue.toInt());
00207 }
00208 }
00209 }
00210 }
00211 else {
00212
00213 if (d->popup)
00214 d->popup->tableView()->clearSelection();
00215 m_lineedit->setText(add);
00216
00217 }
00218 m_lineedit->end(false);
00219 }
00220
00221 QString KexiComboBoxTableEdit::valueForString(const QString& str,
00222 uint lookInColumn, uint returnFromColumn, bool allowNulls)
00223 {
00224 KexiTableViewData *relData = column()->relatedData();
00225 if (!relData)
00226 return QString::null;
00227
00228
00229
00230
00231 const QString txt = str.stripWhiteSpace();
00232 KexiTableViewData::Iterator it(relData->iterator());
00233 for (;it.current();++it) {
00234 if (it.current()->at(lookInColumn).toString().stripWhiteSpace()==txt)
00235 break;
00236 }
00237 if (it.current())
00238 return it.current()->at(returnFromColumn).toString().stripWhiteSpace();
00239
00240 if (column()->relatedDataEditable())
00241 return str;
00242
00243 kexiwarn << "KexiComboBoxTableEdit::valueForString(): no related row found, ID will be painted!" << endl;
00244 if (allowNulls)
00245 return QString::null;
00246 return str;
00247 }
00248
00249 void KexiComboBoxTableEdit::showFocus( const QRect& r, bool readOnly )
00250 {
00251
00252 updateFocus( r );
00253 d->button->setEnabled(!readOnly);
00254 d->button->show();
00255 }
00256
00257 void KexiComboBoxTableEdit::resize(int w, int h)
00258 {
00259 d->totalSize = QSize(w,h);
00260 QWidget::resize(w - d->button->width(), h);
00261 d->button->resize( h, h );
00262 m_rightMargin = d->parentRightMargin + d->button->width();
00263
00264 QRect r( pos().x(), pos().y(), w+1, h+1 );
00265
00266 r.moveBy(m_scrollView->contentsX(),m_scrollView->contentsY());
00267 updateFocus( r );
00268 if (d->popup) {
00269
00270
00271
00272 d->popup->updateSize();
00273 }
00274 }
00275
00276
00277 void KexiComboBoxTableEdit::updateFocus( const QRect& r )
00278 {
00279 if (d->button->width() > r.width())
00280 moveChild(d->button, r.right() + 1, r.top());
00281 else
00282 moveChild(d->button, r.right() - d->button->width(), r.top() );
00283
00284
00285
00286
00287
00288 }
00289
00290 void KexiComboBoxTableEdit::hideFocus()
00291 {
00292 d->button->hide();
00293 }
00294
00295 QVariant KexiComboBoxTableEdit::value()
00296 {
00297
00298 KexiTableViewData *relData = column()->relatedData();
00299 if (relData) {
00300 if (d->userEnteredTextChanged) {
00301
00302
00303 return valueForString(d->userEnteredText, 1, 0, true);
00304 }
00305 else {
00306
00307 KexiTableItem *it = d->popup->tableView()->selectedItem();
00308 return it ? it->at(0) : m_origValue;
00309 }
00310 }
00311 else if (d->popup) {
00312
00313 const int row = d->popup->tableView()->currentRow();
00314 if (row>=0)
00315 return QVariant( row );
00316
00317
00318 }
00319
00320 if (m_lineedit->text().isEmpty())
00321 return QVariant();
00322
00323
00324
00325 return m_origValue;
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 void KexiComboBoxTableEdit::clear()
00341 {
00342 m_lineedit->clear();
00343 if (d->popup)
00344 d->popup->hide();
00345 }
00346
00347 bool KexiComboBoxTableEdit::valueChanged()
00348 {
00349
00350 KexiTableViewData *relData = column()->relatedData();
00351 if (relData) {
00352 if (d->userEnteredTextChanged)
00353 return true;
00354
00355
00356 KexiTableItem *it = d->popup ? d->popup->tableView()->selectedItem() : 0;
00357 if (!it)
00358 return false;
00359 }
00360 else {
00361
00362 const int row = d->popup ? d->popup->tableView()->currentRow() : -1;
00363 if (row<0 && !d->userEnteredTextChanged)
00364 return false;
00365 }
00366
00367
00368 return KexiTableEdit::valueChanged();
00369 }
00370
00371 bool KexiComboBoxTableEdit::valueIsNull()
00372 {
00373
00374 QVariant v( value() );
00375 return v.isNull();
00376
00377 }
00378
00379 bool KexiComboBoxTableEdit::valueIsEmpty()
00380 {
00381 return valueIsNull();
00382 }
00383
00384 void KexiComboBoxTableEdit::paintFocusBorders( QPainter *p, QVariant &, int x, int y, int w, int h )
00385 {
00386 d->currentEditorWidth = w;
00387 if (w > d->button->width())
00388 w -= d->button->width();
00389 p->drawRect(x, y, w, h);
00390 }
00391
00392 void KexiComboBoxTableEdit::setupContents( QPainter *p, bool focused, QVariant val,
00393 QString &txt, int &align, int &x, int &y_offset, int &w, int &h )
00394 {
00395
00396 KexiTableEdit::setupContents( p, focused, val, txt, align, x, y_offset, w, h );
00397 if (focused && (w > d->button->width()))
00398 w -= (d->button->width() - x);
00399 if (!val.isNull()) {
00400 KexiTableViewData *relData = column()->relatedData();
00401 if (relData) {
00402 txt = valueForString(val.toString(), 0, 1);
00403 }
00404 else {
00405
00406 txt = field()->enumHint( val.toInt() );
00407 }
00408 }
00409 }
00410
00411 void KexiComboBoxTableEdit::slotButtonClicked()
00412 {
00413
00414
00415 if (!d->button->isEnabled())
00416 return;
00417
00418 if (d->mouseBtnPressedWhenPopupVisible) {
00419 d->mouseBtnPressedWhenPopupVisible = false;
00420 d->button->setOn(false);
00421 return;
00422 }
00423 kdDebug() << "KexiComboBoxTableEdit::slotButtonClicked()" << endl;
00424
00425 if (!d->popup || !d->popup->isVisible()) {
00426 kdDebug() << "SHOW POPUP" << endl;
00427 showPopup();
00428 d->button->setOn(true);
00429 }
00430
00431
00432
00433
00434
00435 }
00436
00437 void KexiComboBoxTableEdit::showPopup()
00438 {
00439 if (!d->popup) {
00440
00441
00442 d->popup = new KexiComboBoxPopup(this, *m_column);
00443 connect(d->popup, SIGNAL(rowAccepted(KexiTableItem*,int)),
00444 this, SLOT(slotRowAccepted(KexiTableItem*,int)));
00445 connect(d->popup, SIGNAL(cancelled()), this, SIGNAL(cancelRequested()));
00446 connect(d->popup, SIGNAL(hidden()), this, SLOT(slotPopupHidden()));
00447 connect(d->popup->tableView(), SIGNAL(itemSelected(KexiTableItem*)),
00448 this, SLOT(slotItemSelected(KexiTableItem*)));
00449
00450 d->popup->setFocusProxy( m_lineedit );
00451 d->popup->tableView()->setFocusProxy( m_lineedit );
00452 d->popup->installEventFilter(this);
00453
00454
00455 if (m_origValue.isNull())
00456 d->popup->tableView()->clearSelection();
00457 else
00458 d->popup->tableView()->setHighlightedRow( 0 );
00459
00460 }
00461 if (!m_lineedit->isVisible())
00462 emit editRequested();
00463
00464 KexiTableView *tv = dynamic_cast<KexiTableView*>(m_scrollView);
00465 if (tv) {
00466 d->popup->move( tv->viewport()->mapToGlobal(pos()) + QPoint(0,height()) );
00467
00468
00469 const int w = QMAX(d->popup->width(), d->currentEditorWidth);
00470 d->popup->resize(w, 0);
00471 d->popup->show();
00472 d->popup->updateSize(w);
00473
00474 int rowToHighlight;
00475 if (!m_origValue.isNull() && m_origValue.toInt()>=0) {
00476 d->popup->tableView()->selectRow( m_origValue.toInt() );
00477 rowToHighlight = -1;
00478 }
00479 else {
00480 rowToHighlight = QMAX( d->popup->tableView()->highlightedRow(), 0);
00481 }
00482 d->popup->tableView()->setHighlightedRow( rowToHighlight );
00483 if (rowToHighlight < d->popup->tableView()->rowsPerPage())
00484 d->popup->tableView()->ensureCellVisible( 0, -1 );
00485 }
00486
00487 m_lineedit->setFocus();
00488 }
00489
00490 void KexiComboBoxTableEdit::slotPopupHidden()
00491 {
00492 d->button->setOn(false);
00493 }
00494
00495
00496
00497
00498
00499
00500 void KexiComboBoxTableEdit::hide()
00501 {
00502 KexiInputTableEdit::hide();
00503 if (d->popup)
00504 d->popup->hide();
00505 d->button->setOn(false);
00506
00507 }
00508
00509 void KexiComboBoxTableEdit::show()
00510 {
00511 KexiInputTableEdit::show();
00512 d->button->show();
00513 d->button->setOn(false);
00514 }
00515
00516 void KexiComboBoxTableEdit::slotRowAccepted(KexiTableItem * item, int )
00517 {
00518
00519
00520
00521 slotItemSelected(item);
00522 emit acceptRequested();
00523 }
00524
00525 bool KexiComboBoxTableEdit::handleKeyPress( QKeyEvent *ke, bool editorActive )
00526 {
00527 const int k = ke->key();
00528 if ((ke->state()==NoButton && k==Key_F4)
00529 || (ke->state()==AltButton && k==Key_Down))
00530 {
00531
00532 slotButtonClicked();
00533 return true;
00534 }
00535 else if (editorActive) {
00536
00537
00538
00539
00540 if (!d->popup || !d->popup->isVisible()) {
00541 return false;
00542 }
00543
00544 int highlightedOrSelectedRow = d->popup->tableView()->highlightedRow();
00545 if (highlightedOrSelectedRow < 0)
00546 highlightedOrSelectedRow = d->popup->tableView()->currentRow();
00547
00548 switch (k) {
00549 case Key_Up:
00550
00551 d->popup->tableView()->setHighlightedRow(
00552 QMAX(highlightedOrSelectedRow-1, 0) );
00553 updateTextForHighlightedRow();
00554 return true;
00555 case Key_Down:
00556
00557 d->popup->tableView()->setHighlightedRow(
00558 QMIN(highlightedOrSelectedRow+1, d->popup->tableView()->rows()-1) );
00559 updateTextForHighlightedRow();
00560 return true;
00561 case Key_PageUp:
00562
00563 d->popup->tableView()->setHighlightedRow(
00564 QMAX(highlightedOrSelectedRow-d->popup->tableView()->rowsPerPage(), 0) );
00565 updateTextForHighlightedRow();
00566 return true;
00567 case Key_PageDown:
00568
00569 d->popup->tableView()->setHighlightedRow(
00570 QMIN(highlightedOrSelectedRow+d->popup->tableView()->rowsPerPage(),
00571 d->popup->tableView()->rows()-1) );
00572 updateTextForHighlightedRow();
00573 return true;
00574 case Key_Home:
00575 d->popup->tableView()->setHighlightedRow( 0 );
00576 updateTextForHighlightedRow();
00577 return true;
00578 case Key_End:
00579 d->popup->tableView()->setHighlightedRow( d->popup->tableView()->rows()-1 );
00580 updateTextForHighlightedRow();
00581 return true;
00582 case Key_Enter:
00583 case Key_Return:
00584
00585 if (d->popup->tableView()->highlightedRow()>=0)
00586 d->popup->tableView()->selectRow( d->popup->tableView()->highlightedRow() );
00587
00588 default: ;
00589 }
00590 }
00591 return false;
00592 }
00593
00594 void KexiComboBoxTableEdit::slotItemSelected(KexiTableItem*)
00595 {
00596 QString stringValue;
00597 KexiTableViewData *relData = column()->relatedData();
00598 if (relData) {
00599
00600
00601 KexiTableItem *item = d->popup->tableView()->selectedItem();
00602 if (item)
00603 stringValue = item->at(1).toString();
00604 }
00605 else {
00606
00607 stringValue = field()->enumHint( d->popup->tableView()->currentRow() );
00608 }
00609 setLineEditText( stringValue );
00610 m_lineedit->end(false);
00611 m_lineedit->selectAll();
00612 }
00613
00614 void KexiComboBoxTableEdit::slotLineEditTextChanged(const QString &newtext)
00615 {
00616 if (!d->slotLineEditTextChanged_enabled)
00617 return;
00618 d->userEnteredText = newtext;
00619 d->userEnteredTextChanged = true;
00620 if (newtext.isEmpty()) {
00621 if (d->popup) {
00622 d->popup->tableView()->clearSelection();
00623 }
00624 return;
00625 }
00626
00627 }
00628
00629 void KexiComboBoxTableEdit::updateTextForHighlightedRow()
00630 {
00631 KexiTableViewData *relData = column()->relatedData();
00632 if (relData) {
00633
00634 const KexiTableItem *item = d->popup ? d->popup->tableView()->highlightedItem() : 0;
00635 if (item) {
00636 d->slotLineEditTextChanged_enabled = false;
00637 setLineEditText( item->at(1).toString() );
00638 d->slotLineEditTextChanged_enabled = true;
00639 m_lineedit->setCursorPosition(m_lineedit->text().length());
00640 m_lineedit->selectAll();
00641 }
00642 }
00643 }
00644
00645 int KexiComboBoxTableEdit::widthForValue( QVariant &val, QFontMetrics &fm )
00646 {
00647 QValueVector<QString> hints = field()->enumHints();
00648 bool ok;
00649 int idx = val.toInt(&ok);
00650 if (!ok || idx < 0 || idx > int(hints.size()-1))
00651 return KEXITV_MINIMUM_COLUMN_WIDTH;
00652 QString txt = hints.at( idx, &ok );
00653 if (!ok)
00654 return KEXITV_MINIMUM_COLUMN_WIDTH;
00655 return fm.width( txt );
00656 }
00657
00658 bool KexiComboBoxTableEdit::eventFilter( QObject *o, QEvent *e )
00659 {
00660 if (e->type()==QEvent::MouseButtonPress) {
00661 QPoint gp = static_cast<QMouseEvent*>(e)->globalPos() + QPoint(m_scrollView->childX(d->button), m_scrollView->childY(d->button));
00662 QRect r(d->button->mapToGlobal(d->button->geometry().topLeft()), d->button->mapToGlobal(d->button->geometry().bottomRight()));
00663 if (o==d->popup && d->popup->isVisible() && r.contains( gp )) {
00664 d->mouseBtnPressedWhenPopupVisible = true;
00665 }
00666 }
00667 return false;
00668 }
00669
00670 QSize KexiComboBoxTableEdit::totalSize() const
00671 {
00672 return d->totalSize;
00673 }
00674
00675 void KexiComboBoxTableEdit::setLineEditText(const QString& text)
00676 {
00677 m_lineedit->setText( text );
00678
00679 d->userEnteredText = QString::null;
00680 d->userEnteredTextChanged = false;
00681 }
00682
00683
00684
00685 KexiComboBoxEditorFactoryItem::KexiComboBoxEditorFactoryItem()
00686 {
00687 }
00688
00689 KexiComboBoxEditorFactoryItem::~KexiComboBoxEditorFactoryItem()
00690 {
00691 }
00692
00693 KexiTableEdit* KexiComboBoxEditorFactoryItem::createEditor(
00694 KexiTableViewColumn &column, QScrollView* parent)
00695 {
00696 return new KexiComboBoxTableEdit(column, parent);
00697 }
00698
00699
00700 #include "kexicomboboxtableedit.moc"