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