00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <qobjectlist.h>
00023 #include <qpainter.h>
00024 #include <qcursor.h>
00025 #include <qapplication.h>
00026 #include <qfocusdata.h>
00027
00028 #include <kdebug.h>
00029
00030 #include "kexidbform.h"
00031 #include "kexiformscrollview.h"
00032
00033 #include <formeditor/objecttree.h>
00034 #include <formeditor/formmanager.h>
00035 #include <widget/tableview/kexidataawareobjectiface.h>
00036 #include <widget/kexiscrollview.h>
00037
00039 class KexiDBForm::Private
00040 {
00041 public:
00042 Private()
00043 : dataAwareObject(0)
00044 , orderedFocusWidgetsIterator(orderedFocusWidgets)
00045 , autoTabStops(false)
00046 , popupFocused(false)
00047 {
00048 }
00049
00050 ~Private()
00051 {
00052 }
00053
00055 int indexOfDataAwareWidget(QWidget *widget) const
00056 {
00057 if (!dynamic_cast<KexiDataItemInterface*>(widget))
00058 return -1;
00059 return indexOfDataItem( dynamic_cast<KexiDataItemInterface*>(widget) );
00060 }
00061
00063 int indexOfDataItem( KexiDataItemInterface* item ) const
00064 {
00065 QMapConstIterator<KexiDataItemInterface*, uint> indicesForDataAwareWidgetsIt(
00066 indicesForDataAwareWidgets.find(item));
00067 if (indicesForDataAwareWidgetsIt == indicesForDataAwareWidgets.constEnd())
00068 return -1;
00069 kexipluginsdbg << "KexiDBForm: column # for item: "
00070 << indicesForDataAwareWidgetsIt.data() << endl;
00071 return indicesForDataAwareWidgetsIt.data();
00072 }
00073
00075 void setOrderedFocusWidgetsIteratorTo( QWidget *widget )
00076 {
00077 if (orderedFocusWidgetsIterator.current() == widget)
00078 return;
00079 orderedFocusWidgetsIterator.toFirst();
00080 while (orderedFocusWidgetsIterator.current() && orderedFocusWidgetsIterator.current()!=widget)
00081 ++orderedFocusWidgetsIterator;
00082 }
00083
00084 KexiDataAwareObjectInterface* dataAwareObject;
00086 QPtrList<QWidget> orderedFocusWidgets;
00088 QPtrList<QWidget> orderedDataAwareWidgets;
00089 QMap<KexiDataItemInterface*, uint> indicesForDataAwareWidgets;
00090 QPtrListIterator<QWidget> orderedFocusWidgetsIterator;
00091 QPixmap buffer;
00092 QRect prev_rect;
00093
00094 bool autoTabStops : 1;
00095 bool popupFocused : 1;
00096 };
00097
00098
00099
00100 KexiDBForm::KexiDBForm(QWidget *parent, KexiDataAwareObjectInterface* dataAwareObject,
00101 const char *name)
00102 : KexiDBFormBase(parent, name)
00103 , KexiFormDataItemInterface()
00104 , d(new Private())
00105 {
00106 installEventFilter(this);
00107
00108 editedItem = 0;
00109 d->dataAwareObject = dataAwareObject;
00110 m_hasFocusableWidget = false;
00111
00112 kexipluginsdbg << "KexiDBForm::KexiDBForm(): " << endl;
00113 setCursor(QCursor(Qt::ArrowCursor));
00114 setAcceptDrops( true );
00115 }
00116
00117 KexiDBForm::~KexiDBForm()
00118 {
00119 kexipluginsdbg << "KexiDBForm::~KexiDBForm(): close" << endl;
00120 delete d;
00121 }
00122
00123 KexiDataAwareObjectInterface* KexiDBForm::dataAwareObject() const { return d->dataAwareObject; }
00124
00125
00126 static void repaintAll(QWidget *w)
00127 {
00128 QObjectList *list = w->queryList("QWidget");
00129 QObjectListIt it(*list);
00130 for (QObject *obj; (obj=it.current()); ++it ) {
00131 static_cast<QWidget*>(obj)->repaint();
00132 }
00133 delete list;
00134 }
00135
00136 void
00137 KexiDBForm::drawRect(const QRect& r, int type)
00138 {
00139 QValueList<QRect> l;
00140 l.append(r);
00141 drawRects(l, type);
00142 }
00143
00144 void
00145 KexiDBForm::drawRects(const QValueList<QRect> &list, int type)
00146 {
00147 QPainter p;
00148 p.begin(this, true);
00149 bool unclipped = testWFlags( WPaintUnclipped );
00150 setWFlags( WPaintUnclipped );
00151
00152 if (d->prev_rect.isValid()) {
00153
00154 p.drawPixmap( QPoint(d->prev_rect.x()-2, d->prev_rect.y()-2), d->buffer,
00155 QRect(d->prev_rect.x()-2, d->prev_rect.y()-2, d->prev_rect.width()+4, d->prev_rect.height()+4));
00156 }
00157 p.setBrush(QBrush::NoBrush);
00158 if(type == 1)
00159 p.setPen(QPen(white, 1, Qt::DotLine));
00160 else if(type == 2)
00161 p.setPen(QPen(white, 2));
00162 p.setRasterOp(XorROP);
00163
00164 d->prev_rect = QRect();
00165 QValueList<QRect>::ConstIterator endIt = list.constEnd();
00166 for(QValueList<QRect>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
00167 p.drawRect(*it);
00168 if (d->prev_rect.isValid())
00169 d->prev_rect = d->prev_rect.unite(*it);
00170 else
00171 d->prev_rect = *it;
00172 }
00173
00174 if (!unclipped)
00175 clearWFlags( WPaintUnclipped );
00176 p.end();
00177 }
00178
00179 void
00180 KexiDBForm::initBuffer()
00181 {
00182 repaintAll(this);
00183 d->buffer.resize( width(), height() );
00184 d->buffer = QPixmap::grabWindow( winId() );
00185 d->prev_rect = QRect();
00186 }
00187
00188 void
00189 KexiDBForm::clearForm()
00190 {
00191 QPainter p;
00192 p.begin(this, true);
00193 bool unclipped = testWFlags( WPaintUnclipped );
00194 setWFlags( WPaintUnclipped );
00195
00196
00197 p.drawPixmap( QPoint(0,0), d->buffer, QRect(0,0,d->buffer.width(), d->buffer.height()) );
00198
00199 if (!unclipped)
00200 clearWFlags( WPaintUnclipped );
00201 p.end();
00202
00203 repaintAll(this);
00204 }
00205
00206 void
00207 KexiDBForm::highlightWidgets(QWidget *from, QWidget *to)
00208 {
00209 QPoint fromPoint, toPoint;
00210 if(from && from->parentWidget() && (from != this))
00211 fromPoint = from->parentWidget()->mapTo(this, from->pos());
00212 if(to && to->parentWidget() && (to != this))
00213 toPoint = to->parentWidget()->mapTo(this, to->pos());
00214
00215 QPainter p;
00216 p.begin(this, true);
00217 bool unclipped = testWFlags( WPaintUnclipped );
00218 setWFlags( WPaintUnclipped );
00219
00220 if (d->prev_rect.isValid()) {
00221
00222 p.drawPixmap( QPoint(d->prev_rect.x(), d->prev_rect.y()), d->buffer,
00223 QRect(d->prev_rect.x(), d->prev_rect.y(), d->prev_rect.width(), d->prev_rect.height()));
00224 }
00225
00226 p.setPen( QPen(Qt::red, 2) );
00227
00228 if(to)
00229 {
00230 QPixmap pix1 = QPixmap::grabWidget(from);
00231 QPixmap pix2 = QPixmap::grabWidget(to);
00232
00233 if((from != this) && (to != this))
00234 p.drawLine( from->parentWidget()->mapTo(this, from->geometry().center()), to->parentWidget()->mapTo(this, to->geometry().center()) );
00235
00236 p.drawPixmap(fromPoint.x(), fromPoint.y(), pix1);
00237 p.drawPixmap(toPoint.x(), toPoint.y(), pix2);
00238
00239 if(to == this)
00240 p.drawRoundRect(2, 2, width()-4, height()-4, 4, 4);
00241 else
00242 p.drawRoundRect(toPoint.x(), toPoint.y(), to->width(), to->height(), 5, 5);
00243 }
00244
00245 if(from == this)
00246 p.drawRoundRect(2, 2, width()-4, height()-4, 4, 4);
00247 else
00248 p.drawRoundRect(fromPoint.x(), fromPoint.y(), from->width(), from->height(), 5, 5);
00249
00250 if((to == this) || (from == this))
00251 d->prev_rect = QRect(0, 0, d->buffer.width(), d->buffer.height());
00252 else if(to)
00253 {
00254 d->prev_rect.setX( (fromPoint.x() < toPoint.x()) ? (fromPoint.x() - 5) : (toPoint.x() - 5) );
00255 d->prev_rect.setY( (fromPoint.y() < toPoint.y()) ? (fromPoint.y() - 5) : (toPoint.y() - 5) );
00256 d->prev_rect.setRight( (fromPoint.x() < toPoint.x()) ? (toPoint.x() + to->width() + 10) : (fromPoint.x() + from->width() + 10) );
00257 d->prev_rect.setBottom( (fromPoint.y() < toPoint.y()) ? (toPoint.y() + to->height() + 10) : (fromPoint.y() + from->height() + 10) ) ;
00258 }
00259 else
00260 d->prev_rect = QRect(fromPoint.x()- 5, fromPoint.y() -5, from->width() + 10, from->height() + 10);
00261
00262 if (!unclipped)
00263 clearWFlags( WPaintUnclipped );
00264 p.end();
00265 }
00266
00267 QSize
00268 KexiDBForm::sizeHint() const
00269 {
00270
00271 return QSize(400,300);
00272 }
00273
00274 void KexiDBForm::setInvalidState( const QString& displayText )
00275 {
00276 Q_UNUSED( displayText );
00277
00279 }
00280
00281 bool KexiDBForm::autoTabStops() const
00282 {
00283 return d->autoTabStops;
00284 }
00285
00286 void KexiDBForm::setAutoTabStops(bool set)
00287 {
00288 d->autoTabStops = set;
00289 }
00290
00291 QPtrList<QWidget>* KexiDBForm::orderedFocusWidgets() const
00292 {
00293 return &d->orderedFocusWidgets;
00294 }
00295
00296 QPtrList<QWidget>* KexiDBForm::orderedDataAwareWidgets() const
00297 {
00298 return &d->orderedDataAwareWidgets;
00299 }
00300
00301 void KexiDBForm::updateTabStopsOrder(KFormDesigner::Form* form)
00302 {
00303 QWidget *fromWidget = 0;
00304
00305
00306 uint numberOfDataAwareWidgets = 0;
00307
00308
00309 for (KFormDesigner::ObjectTreeListIterator it(form->tabStopsIterator()); it.current(); ++it) {
00310 if (it.current()->widget()->focusPolicy() & QWidget::TabFocus) {
00311
00312 it.current()->widget()->installEventFilter(this);
00313
00314 QObjectList *children = it.current()->widget()->queryList("QWidget");
00315 for (QObjectListIt childrenIt(*children); childrenIt.current(); ++childrenIt) {
00316
00317 kexipluginsdbg << "KexiDBForm::updateTabStopsOrder(): also adding '"
00318 << childrenIt.current()->className() << " " << childrenIt.current()->name()
00319 << "' child to filtered widgets" << endl;
00320
00321 childrenIt.current()->installEventFilter(this);
00322
00323 }
00324 delete children;
00325 if (fromWidget) {
00326 kexipluginsdbg << "KexiDBForm::updateTabStopsOrder() tab order: " << fromWidget->name()
00327 << " -> " << it.current()->widget()->name() << endl;
00328
00329 }
00330 fromWidget = it.current()->widget();
00331 d->orderedFocusWidgets.append( it.current()->widget() );
00332 }
00333
00334 KexiFormDataItemInterface* dataItem = dynamic_cast<KexiFormDataItemInterface*>( it.current()->widget() );
00335 if (dataItem && !dataItem->dataSource().isEmpty()) {
00336 kexipluginsdbg << "#" << numberOfDataAwareWidgets << ": "
00337 << dataItem->dataSource() << " (" << it.current()->widget()->name() << ")" << endl;
00338
00339
00340
00341
00342 d->indicesForDataAwareWidgets.replace(
00343 dataItem,
00344 numberOfDataAwareWidgets );
00345 numberOfDataAwareWidgets++;
00346
00347 d->orderedDataAwareWidgets.append( it.current()->widget() );
00348 }
00349 }
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 }
00364
00365 void KexiDBForm::updateTabStopsOrder()
00366 {
00367 for (QPtrListIterator<QWidget> it( d->orderedFocusWidgets ); it.current();) {
00368 if (! (it.current()->focusPolicy() & QWidget::TabFocus))
00369 d->orderedFocusWidgets.remove( it.current() );
00370 else
00371 ++it;
00372 }
00373 }
00374
00375 void KexiDBForm::updateReadOnlyFlags()
00376 {
00377 for (QPtrListIterator<QWidget> it(d->orderedDataAwareWidgets); it.current(); ++it) {
00378 KexiFormDataItemInterface* dataItem = dynamic_cast<KexiFormDataItemInterface*>( it.current() );
00379 if (dataItem && !dataItem->dataSource().isEmpty()) {
00380 if (dataAwareObject()->isReadOnly()) {
00381 dataItem->setReadOnly( true );
00382 }
00383 }
00384 }
00385 }
00386
00387 bool KexiDBForm::eventFilter( QObject * watched, QEvent * e )
00388 {
00389
00390 if (e->type()==QEvent::Resize && watched == this)
00391 kexipluginsdbg << "RESIZE" << endl;
00392 if (e->type()==QEvent::KeyPress) {
00393 if (preview()) {
00394 QKeyEvent *ke = static_cast<QKeyEvent*>(e);
00395 const int key = ke->key();
00396 const bool tab = ke->state() == Qt::NoButton && key == Qt::Key_Tab;
00397 const bool backtab = ((ke->state() == Qt::NoButton || ke->state() == Qt::ShiftButton) && key == Qt::Key_Backtab)
00398 || (ke->state() == Qt::ShiftButton && key == Qt::Key_Tab);
00399 QObject *o = watched;
00400 QWidget* realWidget = dynamic_cast<QWidget*>(o);
00401 if (!tab && !backtab) {
00402
00403
00404 int curRow = d->dataAwareObject->currentRow();
00405 int curCol = d->dataAwareObject->currentColumn();
00406 bool moveToFirstField;
00407 bool moveToLastField;
00408 if (! (ke->state() == Qt::NoButton && (key == Qt::Key_Home
00409 || key == Qt::Key_End || key == Qt::Key_Down || key == Qt::Key_Up))
00410
00411 && d->dataAwareObject->handleKeyPress(
00412 ke, curRow, curCol, false, &moveToFirstField, &moveToLastField))
00413 {
00414 if (ke->isAccepted())
00415 return true;
00416 QWidget* widgetToFocus;
00417 if (moveToFirstField) {
00418 widgetToFocus = d->orderedFocusWidgets.first();
00419 curCol = d->indexOfDataAwareWidget( widgetToFocus );
00420 }
00421 else if (moveToLastField) {
00422 widgetToFocus = d->orderedFocusWidgets.last();
00423 curCol = d->indexOfDataAwareWidget( widgetToFocus );
00424 }
00425 else
00426 widgetToFocus = d->orderedDataAwareWidgets.at( curCol );
00427
00428 d->dataAwareObject->setCursorPosition( curRow, curCol );
00429
00430 if (widgetToFocus)
00431 widgetToFocus->setFocus();
00432 else
00433 kexipluginswarn << "KexiDBForm::eventFilter(): widgetToFocus not found!" << endl;
00434
00435 ke->accept();
00436 return true;
00437 }
00438 if (key == Qt::Key_Delete && ke->state()==Qt::ControlButton) {
00440 d->dataAwareObject->deleteCurrentRow();
00441 return true;
00442 }
00443
00444 while (true) {
00445 if (!o || o == dynamic_cast<QObject*>(d->dataAwareObject))
00446 break;
00447 if (dynamic_cast<KexiFormDataItemInterface*>(o)) {
00448 realWidget = dynamic_cast<QWidget*>(o);
00449 if (realWidget == this)
00450 return false;
00451 if (dynamic_cast<KexiFormDataItemInterface*>(o)->keyPressed(ke))
00452 return false;
00453 break;
00454 }
00455 o = o->parent();
00456 }
00457 }
00458
00459 if (ke->state() == Qt::NoButton && key == Qt::Key_Escape) {
00460
00461 if (d->dataAwareObject->cancelEditor())
00462 return true;
00463 else if (d->dataAwareObject->cancelRowEdit())
00464 return true;
00465 return false;
00466 }
00467
00468
00469
00470 if (ke->isAccepted() && (ke->state() & Qt::AltButton) && ke->text()>="0" && ke->text()<="9")
00471 return true;
00472
00473 if (tab || backtab) {
00474
00475
00476 while (dynamic_cast<KexiDataItemInterface*>(realWidget) && dynamic_cast<KexiDataItemInterface*>(realWidget)->parentInterface())
00477 realWidget = dynamic_cast<QWidget*>( dynamic_cast<KexiDataItemInterface*>(realWidget)->parentInterface() );
00478
00479 d->setOrderedFocusWidgetsIteratorTo( realWidget );
00480 kexipluginsdbg << realWidget->name() << endl;
00481 if (tab) {
00482 if (d->orderedFocusWidgets.first() && realWidget == d->orderedFocusWidgets.last()) {
00483 d->orderedFocusWidgetsIterator.toFirst();
00484 }
00485 else if (realWidget == d->orderedFocusWidgetsIterator.current()) {
00486
00487
00488
00489
00490 ++d->orderedFocusWidgetsIterator;
00491 }
00492 else
00493 return true;
00494
00495
00496
00497 QWidget *widgetToFocus = d->orderedFocusWidgetsIterator.current();
00498 if (widgetToFocus->focusProxy())
00499 widgetToFocus = widgetToFocus->focusProxy();
00500 if (widgetToFocus && d->dataAwareObject->acceptEditor()) {
00501
00502 UNSET_FOCUS_USING_REASON(realWidget, QFocusEvent::Tab);
00503 SET_FOCUS_USING_REASON(widgetToFocus, QFocusEvent::Tab);
00504 kexipluginsdbg << "focusing " << widgetToFocus->name() << endl;
00505 }
00506 return true;
00507 } else if (backtab) {
00508 if (d->orderedFocusWidgets.last() && realWidget == d->orderedFocusWidgets.first()) {
00509 d->orderedFocusWidgetsIterator.toLast();
00510 }
00511 else if (realWidget == d->orderedFocusWidgetsIterator.current()) {
00512 --d->orderedFocusWidgetsIterator;
00513 }
00514 else
00515 return true;
00516 if (d->dataAwareObject->acceptEditor()) {
00517
00518 UNSET_FOCUS_USING_REASON(realWidget, QFocusEvent::Backtab);
00519
00520 SET_FOCUS_USING_REASON(d->orderedFocusWidgetsIterator.current(), QFocusEvent::Backtab);
00521 kexipluginsdbg << "focusing " << d->orderedFocusWidgetsIterator.current()->name() << endl;
00522 }
00523 return true;
00524 }
00525 }
00526 }
00527 }
00528 else if (e->type()==QEvent::FocusIn) {
00529 bool focusDataWidget = preview();
00530 if (static_cast<QFocusEvent*>(e)->reason()==QFocusEvent::Popup) {
00531 kdDebug() << "->>> focus IN, popup" <<endl;
00532 focusDataWidget = !d->popupFocused;
00533 d->popupFocused = false;
00534
00535
00536
00537
00538 }
00539
00540 if (focusDataWidget) {
00541 kexipluginsdbg << "KexiDBForm: FocusIn: " << watched->className() << " " << watched->name() << endl;
00542 if (d->dataAwareObject) {
00543 QWidget *dataItem = dynamic_cast<QWidget*>(watched);
00544 while (dataItem) {
00545 while (dataItem && !dynamic_cast<KexiDataItemInterface*>(dataItem))
00546 dataItem = dataItem->parentWidget();
00547 if (!dataItem)
00548 break;
00549 kexipluginsdbg << "KexiDBForm: FocusIn: FOUND " << dataItem->className() << " " << dataItem->name() << endl;
00550
00551 const int index = d->indexOfDataAwareWidget(dataItem);
00552 if (index>=0) {
00553 kexipluginsdbg << "KexiDBForm: moving cursor to column #" << index << endl;
00554 editedItem = 0;
00555 if ((int)index!=d->dataAwareObject->currentColumn()) {
00556 d->dataAwareObject->setCursorPosition( d->dataAwareObject->currentRow(), index );
00557 }
00558 break;
00559 }
00560 else
00561 dataItem = dataItem->parentWidget();
00562
00563 dataItem->update();
00564 }
00565 }
00566 }
00567 }
00568 else if (e->type()==QEvent::FocusOut) {
00569 if (static_cast<QFocusEvent*>(e)->reason()==QFocusEvent::Popup) {
00570
00571 d->popupFocused = true;
00572 }
00573 else
00574 d->popupFocused = false;
00575
00576
00577
00578 }
00579 return KexiDBFormBase::eventFilter(watched, e);
00580 }
00581
00582 bool KexiDBForm::valueIsNull()
00583 {
00584 return true;
00585 }
00586
00587 bool KexiDBForm::valueIsEmpty()
00588 {
00589 return true;
00590 }
00591
00592 bool KexiDBForm::isReadOnly() const
00593 {
00594 if (d->dataAwareObject)
00595 return d->dataAwareObject->isReadOnly();
00597 return false;
00598 }
00599
00600 void KexiDBForm::setReadOnly( bool readOnly )
00601 {
00602 if (d->dataAwareObject)
00603 d->dataAwareObject->setReadOnly( readOnly );
00604 }
00605
00606 QWidget* KexiDBForm::widget()
00607 {
00608 return this;
00609 }
00610
00611 bool KexiDBForm::cursorAtStart()
00612 {
00613 return false;
00614 }
00615
00616 bool KexiDBForm::cursorAtEnd()
00617 {
00618 return false;
00619 }
00620
00621 void KexiDBForm::clear()
00622 {
00624 }
00625
00626 bool KexiDBForm::preview() const {
00627 return dynamic_cast<KexiScrollView*>(d->dataAwareObject)
00628 ? dynamic_cast<KexiScrollView*>(d->dataAwareObject)->preview() : false;
00629 }
00630
00631 void KexiDBForm::dragMoveEvent( QDragMoveEvent *e )
00632 {
00633 emit handleDragMoveEvent(e);
00634 }
00635
00636 void KexiDBForm::dropEvent( QDropEvent *e )
00637 {
00638 emit handleDropEvent(e);
00639 }
00640
00641 void KexiDBForm::setCursor( const QCursor & cursor )
00642 {
00643
00645
00646 if (KFormDesigner::FormManager::self()->isInserting())
00647 KexiDBFormBase::setCursor(cursor);
00648 }
00649
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670 #include "kexidbform.moc"