00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kexidbcombobox.h"
00021 #include "kexidblineedit.h"
00022 #include "../kexiformscrollview.h"
00023
00024 #include <kcombobox.h>
00025 #include <kdebug.h>
00026 #include <kapplication.h>
00027
00028 #include <qmetaobject.h>
00029 #include <qpainter.h>
00030 #include <qstyle.h>
00031 #include <qdrawutil.h>
00032 #include <qptrdict.h>
00033 #include <qcursor.h>
00034
00035 #include <kexidb/queryschema.h>
00036 #include <widget/tableview/kexicomboboxpopup.h>
00037 #include <widget/tableview/kexicelleditorfactory.h>
00038 #include <kexiutils/utils.h>
00039
00041 class KexiDBComboBox::Private
00042 {
00043 public:
00044 Private()
00045 : popup(0)
00046 , visibleColumnInfo(0)
00047 , subWidgetsWithDisabledEvents(0)
00048 , isEditable(false)
00049 , buttonPressed(false)
00050 , mouseOver(false)
00051 , dataEnteredByHand(true)
00052 {
00053 }
00054 ~Private()
00055 {
00056 delete subWidgetsWithDisabledEvents;
00057 subWidgetsWithDisabledEvents = 0;
00058 }
00059
00060 KexiComboBoxPopup *popup;
00061 KComboBox *paintedCombo;
00062 QSize sizeHint;
00063
00064 KexiDB::QueryColumnInfo* visibleColumnInfo;
00065 QPtrDict<char> *subWidgetsWithDisabledEvents;
00066 bool isEditable : 1;
00067 bool buttonPressed : 1;
00068 bool mouseOver : 1;
00069 bool dataEnteredByHand : 1;
00070 };
00071
00072
00073
00074 KexiDBComboBox::KexiDBComboBox(QWidget *parent, const char *name, bool designMode)
00075 : KexiDBAutoField(parent, name, designMode, NoLabel)
00076 , KexiComboBoxBase()
00077 , d(new Private())
00078 {
00079 setMouseTracking(true);
00080 setFocusPolicy(WheelFocus);
00081 installEventFilter(this);
00082 d->paintedCombo = new KComboBox(this);
00083 d->paintedCombo->hide();
00084 d->paintedCombo->move(0,0);
00085 }
00086
00087 KexiDBComboBox::~KexiDBComboBox()
00088 {
00089 delete d;
00090 }
00091
00092 KexiComboBoxPopup *KexiDBComboBox::popup() const
00093 {
00094 return d->popup;
00095 }
00096
00097 void KexiDBComboBox::setPopup(KexiComboBoxPopup *popup)
00098 {
00099 d->popup = popup;
00100 }
00101
00102 void KexiDBComboBox::setEditable(bool set)
00103 {
00104 if (d->isEditable == set)
00105 return;
00106 d->isEditable = set;
00107 d->paintedCombo->setEditable(set);
00108 if (set)
00109 createEditor();
00110 else {
00111 delete m_subwidget;
00112 m_subwidget = 0;
00113 }
00114 update();
00115 }
00116
00117 bool KexiDBComboBox::isEditable() const
00118 {
00119 return d->isEditable;
00120 }
00121
00122 void KexiDBComboBox::paintEvent( QPaintEvent * )
00123 {
00124 QPainter p( this );
00125 QColorGroup cg( palette().active() );
00126
00127
00128
00129 cg.setColor(QColorGroup::Base, paletteBackgroundColor());
00130 p.setPen(cg.text());
00131
00132 QStyle::SFlags flags = QStyle::Style_Default;
00133 if (isEnabled())
00134 flags |= QStyle::Style_Enabled;
00135 if (hasFocus())
00136 flags |= QStyle::Style_HasFocus;
00137 if (d->mouseOver)
00138 flags |= QStyle::Style_MouseOver;
00139
00140 if ( width() < 5 || height() < 5 ) {
00141 qDrawShadePanel( &p, rect(), cg, FALSE, 2, &cg.brush( QColorGroup::Button ) );
00142 return;
00143 }
00144
00146
00147 style().drawComplexControl( QStyle::CC_ComboBox, &p, d->paintedCombo , rect(), cg,
00148 flags, (uint)QStyle::SC_All,
00149 (d->buttonPressed ? QStyle::SC_ComboBoxArrow : QStyle::SC_None )
00150 );
00151
00152 if (d->isEditable) {
00153
00154 }
00155 else {
00156 QRect editorGeometry( this->editorGeometry() );
00157 if ( hasFocus() ) {
00158 if (0==qstrcmp(style().name(), "windows"))
00159 p.fillRect( editorGeometry, cg.brush( QColorGroup::Highlight ) );
00160 QRect r( QStyle::visualRect( style().subRect( QStyle::SR_ComboBoxFocusRect, d->paintedCombo ), this ) );
00161 r = QRect(r.left()-1, r.top()-1, r.width()+2, r.height()+2);
00162 style().drawPrimitive( QStyle::PE_FocusRect, &p,
00163 r, cg, flags | QStyle::Style_FocusAtBorder, QStyleOption(cg.highlight()));
00164 }
00165
00166 }
00167 }
00168
00169 QRect KexiDBComboBox::editorGeometry() const
00170 {
00171 QRect r( QStyle::visualRect(
00172 style().querySubControlMetrics(QStyle::CC_ComboBox, d->paintedCombo,
00173 QStyle::SC_ComboBoxEditField), d->paintedCombo ) );
00174
00175
00176
00177 return r;
00178 }
00179
00180 void KexiDBComboBox::createEditor()
00181 {
00182 KexiDBAutoField::createEditor();
00183 if (m_subwidget) {
00184 m_subwidget->setGeometry( editorGeometry() );
00185 if (!d->isEditable) {
00186 m_subwidget->setCursor(QCursor(Qt::ArrowCursor));
00188 QPalette subwidgetPalette( m_subwidget->palette() );
00189 subwidgetPalette.setColor(QPalette::Active, QColorGroup::Base,
00190 subwidgetPalette.color(QPalette::Active, QColorGroup::Button));
00191 m_subwidget->setPalette( subwidgetPalette );
00192 if (d->subWidgetsWithDisabledEvents)
00193 d->subWidgetsWithDisabledEvents->clear();
00194 else
00195 d->subWidgetsWithDisabledEvents = new QPtrDict<char>();
00196 d->subWidgetsWithDisabledEvents->insert(m_subwidget, (char*)1);
00197 m_subwidget->installEventFilter(this);
00198 QObjectList *l = m_subwidget->queryList( "QWidget" );
00199 for ( QObjectListIt it( *l ); it.current(); ++it ) {
00200 d->subWidgetsWithDisabledEvents->insert(it.current(), (char*)1);
00201 it.current()->installEventFilter(this);
00202 }
00203 delete l;
00204 }
00205 }
00206 updateGeometry();
00207 }
00208
00209 void KexiDBComboBox::setLabelPosition(LabelPosition position)
00210 {
00211 if(m_subwidget) {
00212 if (-1 != m_subwidget->metaObject()->findProperty("frameShape", true))
00213 m_subwidget->setProperty("frameShape", QVariant((int)QFrame::NoFrame));
00214 m_subwidget->setGeometry( editorGeometry() );
00215 }
00216
00217
00218
00219 QSizePolicy sizePolicy( this->sizePolicy() );
00220 if(position == Left)
00221 sizePolicy.setHorData( QSizePolicy::Minimum );
00222 else
00223 sizePolicy.setVerData( QSizePolicy::Minimum );
00224
00225 setSizePolicy(sizePolicy);
00226
00227
00228 }
00229
00230 QRect KexiDBComboBox::buttonGeometry() const
00231 {
00232 QRect arrowRect(
00233 style().querySubControlMetrics( QStyle::CC_ComboBox, d->paintedCombo, QStyle::SC_ComboBoxArrow) );
00234 arrowRect = QStyle::visualRect(arrowRect, d->paintedCombo);
00235 arrowRect.setHeight( QMAX( height() - (2 * arrowRect.y()), arrowRect.height() ) );
00236 return arrowRect;
00237 }
00238
00239 bool KexiDBComboBox::handleMousePressEvent(QMouseEvent *e)
00240 {
00241 if ( e->button() != Qt::LeftButton )
00242 return true;
00243
00244
00245
00246
00247
00248 if ( ( !isEditable() || buttonGeometry().contains( e->pos() ) ) ) {
00249 d->buttonPressed = false;
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263 showPopup();
00264 return true;
00265 }
00266 return false;
00267 }
00268
00269 bool KexiDBComboBox::handleKeyPressEvent(QKeyEvent *ke)
00270 {
00271 const int k = ke->key();
00272 const bool dropDown = (ke->state() == Qt::NoButton && ((k==Qt::Key_F2 && !d->isEditable) || k==Qt::Key_F4))
00273 || (ke->state() == Qt::AltButton && k==Qt::Key_Down);
00274 const bool escPressed = ke->state() == Qt::NoButton && k==Qt::Key_Escape;
00275 const bool popupVisible = popup() && popup()->isVisible();
00276 if ((dropDown || escPressed) && popupVisible) {
00277 popup()->hide();
00278 return true;
00279 }
00280 else if (dropDown && !popupVisible) {
00281 d->buttonPressed = false;
00282 showPopup();
00283 return true;
00284 }
00285 else if (popupVisible) {
00286 const bool enterPressed = k==Qt::Key_Enter || k==Qt::Key_Return;
00287 if (enterPressed) {
00288 acceptPopupSelection();
00289 return true;
00290 }
00291 return handleKeyPressForPopup( ke );
00292 }
00293
00294 return false;
00295 }
00296
00297 bool KexiDBComboBox::keyPressed(QKeyEvent *ke)
00298 {
00299 if (KexiDBAutoField::keyPressed(ke))
00300 return true;
00301
00302 const int k = ke->key();
00303 const bool popupVisible = popup() && popup()->isVisible();
00304 const bool escPressed = ke->state() == Qt::NoButton && k==Qt::Key_Escape;
00305 if (escPressed && popupVisible) {
00306 popup()->hide();
00307 return true;
00308 }
00309 return false;
00310 }
00311
00312 void KexiDBComboBox::mousePressEvent( QMouseEvent *e )
00313 {
00314 if (handleMousePressEvent(e))
00315 return;
00316
00317
00318
00319
00320 KexiDBAutoField::mousePressEvent( e );
00321 }
00322
00323 void KexiDBComboBox::mouseDoubleClickEvent( QMouseEvent *e )
00324 {
00325 mousePressEvent( e );
00326 }
00327
00328 bool KexiDBComboBox::eventFilter( QObject *o, QEvent *e )
00329 {
00330 if (o==this) {
00331 if (e->type()==QEvent::Resize) {
00332 d->paintedCombo->resize(size());
00333 if (m_subwidget)
00334 m_subwidget->setGeometry( editorGeometry() );
00335 }
00336 else if (e->type()==QEvent::Enter) {
00337 if (!d->isEditable
00338 || buttonGeometry().contains( static_cast<QMouseEvent*>(e)->pos() ))
00339 {
00340 d->mouseOver = true;
00341 update();
00342 }
00343 }
00344 else if (e->type()==QEvent::MouseMove) {
00345 if (d->isEditable) {
00346 const bool overButton = buttonGeometry().contains( static_cast<QMouseEvent*>(e)->pos() );
00347 if (overButton != d->mouseOver) {
00348 d->mouseOver = overButton;
00349 update();
00350 }
00351 }
00352 }
00353 else if (e->type()==QEvent::Leave) {
00354 d->mouseOver = false;
00355 update();
00356 }
00357 else if (e->type()==QEvent::KeyPress) {
00358
00359 if (handleKeyPressEvent(static_cast<QKeyEvent*>(e)))
00360 return true;
00361 }
00362 }
00363 else if (!d->isEditable && d->subWidgetsWithDisabledEvents && d->subWidgetsWithDisabledEvents->find(o)) {
00364 if (e->type()==QEvent::MouseButtonPress) {
00365
00366 if (handleMousePressEvent(static_cast<QMouseEvent*>(e)))
00367 return true;
00368 }
00369 else if (e->type()==QEvent::KeyPress) {
00370 if (handleKeyPressEvent(static_cast<QKeyEvent*>(e)))
00371 return true;
00372 }
00373 return e->type()!=QEvent::Paint;
00374 }
00375 return KexiDBAutoField::eventFilter( o, e );
00376 }
00377
00378 bool KexiDBComboBox::subwidgetStretchRequired(KexiDBAutoField* autoField) const
00379 {
00380 Q_UNUSED(autoField);
00381 return true;
00382 }
00383
00384 void KexiDBComboBox::setPaletteBackgroundColor( const QColor & color )
00385 {
00386 KexiDBAutoField::setPaletteBackgroundColor(color);
00387 QPalette pal(palette());
00388 QColorGroup cg(pal.active());
00389 pal.setColor(QColorGroup::Base, red);
00390 pal.setColor(QColorGroup::Background, red);
00391 pal.setActive(cg);
00392 QWidget::setPalette(pal);
00393 update();
00394 }
00395
00396 bool KexiDBComboBox::valueChanged()
00397 {
00398 kdDebug() << "KexiDataItemInterface::valueChanged(): " << m_origValue.toString() << " ? " << value().toString() << endl;
00399 return m_origValue != value();
00400 }
00401
00402 void
00403 KexiDBComboBox::setColumnInfo(KexiDB::QueryColumnInfo* cinfo)
00404 {
00405 KexiFormDataItemInterface::setColumnInfo(cinfo);
00406 }
00407
00408 void KexiDBComboBox::setVisibleColumnInfo(KexiDB::QueryColumnInfo* cinfo)
00409 {
00410 d->visibleColumnInfo = cinfo;
00411
00412 setColumnInfoInternal(columnInfo(), d->visibleColumnInfo);
00413 }
00414
00415 KexiDB::QueryColumnInfo* KexiDBComboBox::visibleColumnInfo() const
00416 {
00417 return d->visibleColumnInfo;
00418 }
00419
00420 void KexiDBComboBox::moveCursorToEndInInternalEditor()
00421 {
00422 if (d->isEditable && m_moveCursorToEndInInternalEditor_enabled)
00423 moveCursorToEnd();
00424 }
00425
00426 void KexiDBComboBox::selectAllInInternalEditor()
00427 {
00428 if (d->isEditable && m_selectAllInInternalEditor_enabled)
00429 selectAll();
00430 }
00431
00432 void KexiDBComboBox::setValueInternal(const QVariant& add, bool removeOld)
00433 {
00436 KexiComboBoxBase::setValueInternal(add, removeOld);
00437 }
00438
00439 void KexiDBComboBox::setVisibleValueInternal(const QVariant& value)
00440 {
00441 KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
00442 if(iface)
00443 iface->setValue(value, QVariant(), false );
00444 }
00445
00446 QVariant KexiDBComboBox::visibleValue()
00447 {
00448 return KexiComboBoxBase::visibleValue();
00449 }
00450
00451 void KexiDBComboBox::setValueInInternalEditor(const QVariant& value)
00452 {
00453 if (!m_setValueInInternalEditor_enabled)
00454 return;
00455 KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
00456 if(iface)
00457 iface->setValue(value, QVariant(), false);
00458 }
00459
00460 QVariant KexiDBComboBox::valueFromInternalEditor()
00461 {
00462 return KexiDBAutoField::value();
00463 }
00464
00465 QPoint KexiDBComboBox::mapFromParentToGlobal(const QPoint& pos) const
00466 {
00467 const KexiFormScrollView* view = KexiUtils::findParentConst<const KexiFormScrollView>(this, "KexiFormScrollView");
00468 if (!view)
00469 return QPoint(-1,-1);
00470 return view->viewport()->mapToGlobal(pos);
00471 }
00472
00473 int KexiDBComboBox::popupWidthHint() const
00474 {
00475 return width();
00476 }
00477
00478 void KexiDBComboBox::fontChange( const QFont & oldFont )
00479 {
00480 d->sizeHint = QSize();
00481 KexiDBAutoField::fontChange(oldFont);
00482 }
00483
00484 void KexiDBComboBox::styleChange( QStyle& oldStyle )
00485 {
00486 KexiDBAutoField::styleChange( oldStyle );
00487 d->sizeHint = QSize();
00488 if (m_subwidget)
00489 m_subwidget->setGeometry( editorGeometry() );
00490 }
00491
00492 QSize KexiDBComboBox::sizeHint() const
00493 {
00494 if ( isVisible() && d->sizeHint.isValid() )
00495 return d->sizeHint;
00496
00497 const int maxWidth = 7 * fontMetrics().width(QChar('x')) + 18;
00498 const int maxHeight = QMAX( fontMetrics().lineSpacing(), 14 ) + 2;
00499 d->sizeHint = (style().sizeFromContents(QStyle::CT_ComboBox, d->paintedCombo,
00500 QSize(maxWidth, maxHeight)).expandedTo(QApplication::globalStrut()));
00501
00502 return d->sizeHint;
00503 }
00504
00505 void KexiDBComboBox::editRequested()
00506 {
00507 }
00508
00509 void KexiDBComboBox::acceptRequested()
00510 {
00511 signalValueChanged();
00512 }
00513
00514 void KexiDBComboBox::slotRowAccepted(KexiTableItem *item, int row)
00515 {
00516 d->dataEnteredByHand = false;
00517 KexiComboBoxBase::slotRowAccepted(item, row);
00518 d->dataEnteredByHand = true;
00519 }
00520
00521 void KexiDBComboBox::beforeSignalValueChanged()
00522 {
00523 if (d->dataEnteredByHand) {
00524 KexiFormDataItemInterface *iface = dynamic_cast<KexiFormDataItemInterface*>((QWidget*)m_subwidget);
00525 if (iface) {
00526 slotInternalEditorValueChanged( iface->value() );
00527 }
00528 }
00529 }
00530
00531 void KexiDBComboBox::undoChanges()
00532 {
00533 KexiDBAutoField::undoChanges();
00534 KexiComboBoxBase::undoChanges();
00535 }
00536
00537 #include "kexidbcombobox.moc"