File indexing completed on 2024-05-12 16:39:45
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at> 0003 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr> 0004 Copyright (C) 2008-2011 Jarosław Staniek <staniek@kde.org> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License as published by the Free Software Foundation; either 0009 version 2 of the License, or (at your option) any later version. 0010 0011 This library is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 Library General Public License for more details. 0015 0016 You should have received a copy of the GNU Library General Public License 0017 along with this library; see the file COPYING.LIB. If not, write to 0018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 */ 0021 0022 #include <QPainter> 0023 #include <QRect> 0024 #include <QEvent> 0025 #include <QLayout> 0026 #include <QCursor> 0027 #include <QGridLayout> 0028 #include <QKeyEvent> 0029 #include <QHBoxLayout> 0030 #include <QVBoxLayout> 0031 #include <QMouseEvent> 0032 #include <QDebug> 0033 0034 #include "utils.h" 0035 #include "container.h" 0036 #include "widgetlibrary.h" 0037 #include "objecttree.h" 0038 #include "form.h" 0039 #include "commands.h" 0040 #include "events.h" 0041 #include "FormWidget.h" 0042 #include <kexiutils/utils.h> 0043 0044 using namespace KFormDesigner; 0045 0046 EventEater::EventEater(QWidget *widget, QObject *container) 0047 : QObject(container) 0048 { 0049 m_widget = widget; 0050 m_container = container; 0051 0052 KexiUtils::installRecursiveEventFilter(m_widget, this); 0053 } 0054 0055 bool 0056 EventEater::eventFilter(QObject *o, QEvent *ev) 0057 { 0058 if (!m_container) 0059 return false; 0060 if (ev->type() == QEvent::MouseButtonPress && o->inherits("QTabBar")) { 0061 QMouseEvent *mev = static_cast<QMouseEvent*>(ev); 0062 if (mev->button() == Qt::RightButton) { 0063 // (because of tab widget specifics) block right-click for tab widget's tab bar, 0064 // otherwise form will be selected! 0065 return true; 0066 } 0067 } 0068 0069 return m_container->eventFilter(m_widget, ev); 0070 } 0071 0072 EventEater::~EventEater() 0073 { 0074 if (m_widget) 0075 KexiUtils::removeRecursiveEventFilter(m_widget, this); 0076 } 0077 0078 void EventEater::setContainer(QObject *container) 0079 { 0080 m_container = container; 0081 } 0082 0083 // Container itself 0084 0085 class Q_DECL_HIDDEN Container::Private 0086 { 0087 public: 0088 Private(Container* toplevel_, QWidget *container) 0089 : state(DoingNothing) 0090 , idOfPropertyCommand(0) 0091 , toplevel(toplevel_) 0092 , widget(container) 0093 , layout(0) 0094 , layType(Form::NoLayout) 0095 , moving(0) 0096 , tree(0) 0097 , mousePressEventReceived(false) 0098 , mouseReleaseEvent(QEvent::None, QPoint(), Qt::NoButton, Qt::NoButton, Qt::NoModifier) 0099 , insertBegin(-1, -1) 0100 { 0101 if (toplevel) 0102 form = toplevel->form(); 0103 } 0104 0105 ~Private() 0106 { 0107 } 0108 0109 //! for inserting/selection 0110 void startSelectionOrInsertingRectangle(const QPoint& begin) 0111 { 0112 insertBegin = begin; 0113 } 0114 void stopSelectionRectangleOrInserting() 0115 { 0116 insertBegin = QPoint(-1, -1); 0117 insertRect = QRect(); 0118 } 0119 void updateSelectionOrInsertingRectangle(const QPoint& end) 0120 { 0121 if (!selectionOrInsertingStarted()) { 0122 stopSelectionRectangleOrInserting(); 0123 return; 0124 } 0125 QRect oldInsertRect( insertRect ); 0126 insertRect.setTopLeft( QPoint( 0127 qMin(insertBegin.x(), end.x()), 0128 qMin(insertBegin.y(), end.y()) ) ); 0129 insertRect.setBottomRight( QPoint( 0130 qMax(insertBegin.x(), end.x()) - 1, 0131 qMax(insertBegin.y(), end.y()) - 1) ); // minus 1 to make the size correct 0132 QRect toUpdate( oldInsertRect.united(insertRect) ); 0133 toUpdate.setWidth(toUpdate.width()+1); 0134 toUpdate.setHeight(toUpdate.height()+1); 0135 widget->update(toUpdate); 0136 } 0137 bool selectionOrInsertingStarted() const 0138 { 0139 return insertBegin != QPoint(-1, -1); 0140 } 0141 QRect selectionOrInsertingRectangle() const { 0142 return insertRect; 0143 } 0144 QPoint selectionOrInsertingBegin() const { 0145 return insertBegin; 0146 } 0147 0148 void widgetDeleted() { 0149 widget = 0; 0150 } 0151 0152 QPointer<Form> form; 0153 0154 enum State { 0155 DoingNothing, 0156 DrawingSelectionRect, 0157 CopyingWidget, 0158 MovingWidget, 0159 InlineEditing 0160 }; 0161 State state; 0162 0163 int idOfPropertyCommand; 0164 0165 //! the watched container and it's toplevel one... 0166 QPointer<Container> toplevel; 0167 QPointer<QWidget> widget; 0168 0169 // Layout 0170 QLayout *layout; 0171 Form::LayoutType layType; 0172 int margin, spacing; 0173 0174 QPoint grab; 0175 QPointer<QWidget> moving; 0176 0177 //inserting 0178 ObjectTreeItem *tree; 0179 0180 bool mousePressEventReceived; 0181 QMouseEvent mouseReleaseEvent; 0182 QPointer<QObject> objectForMouseReleaseEvent; 0183 0184 QPoint insertBegin; 0185 QRect insertRect; 0186 }; 0187 0188 //--------------------------------------------------------------------------------------------------------------------- 0189 0190 Container::Container(Container *toplevel, QWidget *container, QObject *parent) 0191 : QObject(parent) 0192 , d(new Private(toplevel, container)) 0193 { 0194 QByteArray classname = container->metaObject()->className(); 0195 if ((classname == "HBox") || (classname == "Grid") || (classname == "VBox") || 0196 (classname == "HFlow") || (classname == "VFlow")) 0197 d->margin = 4; // those containers don't have frames, so little margin 0198 else 0199 d->margin = d->form ? d->form->defaultMargin() : 0; 0200 d->spacing = d->form ? d->form->defaultSpacing() : 0; 0201 0202 if (toplevel) { 0203 //qDebug() << "Creating ObjectTreeItem:"; 0204 ObjectTreeItem *it = new ObjectTreeItem(d->form->library()->displayName(classname), 0205 widget()->objectName(), widget(), this, this); 0206 setObjectTree(it); 0207 0208 if (parent->isWidgetType()) { 0209 QString n = parent->objectName(); 0210 ObjectTreeItem *parent = d->form->objectTree()->lookup(n); 0211 d->form->objectTree()->addItem(parent, it); 0212 } 0213 else { 0214 d->form->objectTree()->addItem(toplevel->objectTree(), it); 0215 } 0216 0217 connect(toplevel, SIGNAL(destroyed()), this, SLOT(widgetDeleted())); 0218 } 0219 0220 connect(container, SIGNAL(destroyed()), this, SLOT(widgetDeleted())); 0221 } 0222 0223 Container::~Container() 0224 { 0225 delete d; 0226 } 0227 0228 Form* Container::form() const 0229 { 0230 return d->form; 0231 } 0232 0233 QWidget* Container::widget() const 0234 { 0235 return d->widget; 0236 } 0237 0238 void 0239 Container::setForm(Form *form) 0240 { 0241 d->form = form; 0242 d->margin = d->form ? d->form->defaultMargin() : 0; 0243 d->spacing = d->form ? d->form->defaultSpacing() : 0; 0244 } 0245 0246 bool 0247 Container::eventFilter(QObject *s, QEvent *e) 0248 { 0249 #ifdef KFD_SIGSLOTS 0250 const bool connecting = d->form->state() == Form::Connecting; 0251 #else 0252 const bool connecting = false; 0253 #endif 0254 switch (e->type()) { 0255 case QEvent::MouseButtonPress: { 0256 d->stopSelectionRectangleOrInserting(); 0257 d->mousePressEventReceived = true; 0258 0259 //qDebug() << "sender object =" << s->objectName() << "of type =" << s->metaObject()->className() 0260 // << "this =" << this->objectName() << metaObject()->className(); 0261 0262 d->moving = static_cast<QWidget*>(s); 0263 d->idOfPropertyCommand++; // this will create another PropertyCommand 0264 if (d->moving->parentWidget() && KexiUtils::objectIsA(d->moving->parentWidget(), "QStackedWidget")) { 0265 //qDebug() << "widget is a stacked widget's page"; 0266 d->moving = d->moving->parentWidget(); // widget is a stacked widget's page 0267 } 0268 if (d->moving->parentWidget() && d->moving->parentWidget()->inherits("QTabWidget")) { 0269 //qDebug() << "widget is a tab widget page"; 0270 d->moving = d->moving->parentWidget(); // widget is a tab widget page 0271 } 0272 QMouseEvent *mev = static_cast<QMouseEvent*>(e); 0273 d->grab = QPoint(mev->x(), mev->y()); 0274 0275 #ifdef KFD_SIGSLOTS 0276 // we are drawing a connection 0277 if (d->form->state() == Form::Connecting) { 0278 drawConnection(mev); 0279 return true; 0280 } 0281 #endif 0282 0283 if ((mev->modifiers() == Qt::ControlModifier || mev->modifiers() == Qt::ShiftModifier) 0284 && d->form->state() != Form::WidgetInserting) { // multiple selection mode 0285 if (d->form->selectedWidgets()->contains(d->moving)) { // widget is already selected 0286 if (d->form->selectedWidgets()->count() > 1) // we remove it from selection 0287 deselectWidget(d->moving); 0288 else { // the widget is the only selected, so it means we want to copy it 0289 d->state = Private::CopyingWidget; 0290 } 0291 } 0292 else { 0293 // the widget is not yet selected, we add it 0294 Form::WidgetSelectionFlags flags = Form::AddToPreviousSelection 0295 | Form::LastSelection; 0296 if (mev->button() == Qt::RightButton) { 0297 flags |= Form::DontRaise; 0298 } 0299 selectWidget(d->moving, flags); 0300 } 0301 } 0302 else if ((d->form->selectedWidgets()->count() > 1)) { // more than one widget selected 0303 if (!d->form->selectedWidgets()->contains(d->moving)) { 0304 // widget is not selected, it becomes the only selected widget 0305 Form::WidgetSelectionFlags flags 0306 = Form::ReplacePreviousSelection | Form::LastSelection; 0307 if (mev->button() == Qt::RightButton) { 0308 flags |= Form::DontRaise; 0309 } 0310 selectWidget(d->moving, flags); 0311 } 0312 // If the widget is already selected, we do nothing (to ease widget moving, etc.) 0313 } 0314 else {// if(!d->form->manager()->isInserting()) 0315 Form::WidgetSelectionFlags flags 0316 = Form::ReplacePreviousSelection | Form::LastSelection; 0317 if (mev->button() == Qt::RightButton) { 0318 flags |= Form::DontRaise; 0319 } 0320 selectWidget(d->moving, flags); 0321 } 0322 0323 // we are inserting a widget or drawing a selection rect in the form 0324 if ((d->form->state() == Form::WidgetInserting) || ((s == widget()) && !d->toplevel)) { 0325 int tmpx, tmpy; 0326 if ( !d->form->isSnapToGridEnabled() 0327 || d->form->state() != Form::WidgetInserting 0328 || (mev->buttons() == Qt::LeftButton && mev->modifiers() == (Qt::ControlModifier | Qt::AltModifier)) 0329 ) 0330 { 0331 tmpx = mev->x(); 0332 tmpy = mev->y(); 0333 } 0334 else { 0335 int grid = d->form->gridSize(); 0336 tmpx = alignValueToGrid(mev->x(), grid); 0337 tmpy = alignValueToGrid(mev->y(), grid); 0338 } 0339 d->startSelectionOrInsertingRectangle( (static_cast<QWidget*>(s))->mapTo(widget(), QPoint(tmpx, tmpy)) ); 0340 if (d->form->state() != Form::WidgetInserting) { 0341 d->state = Private::DrawingSelectionRect; 0342 } 0343 } 0344 else { 0345 if (s->inherits("QTabWidget")) // to allow changing page by clicking tab 0346 return false; 0347 } 0348 0349 if (d->objectForMouseReleaseEvent) { 0350 const bool res = handleMouseReleaseEvent(d->objectForMouseReleaseEvent, &d->mouseReleaseEvent); 0351 d->objectForMouseReleaseEvent = 0; 0352 return res; 0353 } 0354 return true; 0355 } 0356 0357 case QEvent::MouseButtonRelease: { 0358 QMouseEvent *mev = static_cast<QMouseEvent*>(e); 0359 if (!d->mousePressEventReceived) { 0360 d->mouseReleaseEvent = *mev; 0361 d->objectForMouseReleaseEvent = s; 0362 return true; 0363 } 0364 d->mousePressEventReceived = false; 0365 d->objectForMouseReleaseEvent = 0; 0366 return handleMouseReleaseEvent(s, mev); 0367 } 0368 0369 case QEvent::MouseMove: { 0370 QMouseEvent *mev = static_cast<QMouseEvent*>(e); 0371 if (d->selectionOrInsertingStarted() && d->form->state() == Form::WidgetInserting 0372 && ( (mev->buttons() == Qt::LeftButton) 0373 || (mev->buttons() == Qt::LeftButton && mev->modifiers() == Qt::ControlModifier) 0374 || (mev->buttons() == Qt::LeftButton && mev->modifiers() == (Qt::ControlModifier | Qt::AltModifier)) 0375 || (mev->buttons() == Qt::LeftButton && mev->modifiers() == Qt::ShiftModifier) 0376 ) 0377 ) 0378 { 0379 QPoint realPos; 0380 if (d->form->isSnapToGridEnabled()) { 0381 const int gridX = d->form->gridSize(); 0382 const int gridY = d->form->gridSize(); 0383 realPos = QPoint( 0384 alignValueToGrid(mev->pos().x(), gridX), 0385 alignValueToGrid(mev->pos().y(), gridY)); 0386 } 0387 else { 0388 realPos = mev->pos(); 0389 } 0390 d->updateSelectionOrInsertingRectangle(realPos); 0391 return true; 0392 } 0393 #ifdef KFD_SIGSLOTS 0394 // Creating a connection, we highlight sender and receiver, and we draw a link between them 0395 else if (connecting && !FormManager::self()->createdConnection()->sender().isNull()) { 0396 ObjectTreeItem *tree = d->form->objectTree()->lookup( 0397 FormManager::self()->createdConnection()->sender()); 0398 if (!tree || !tree->widget()) 0399 return true; 0400 0401 if (d->form->formWidget() && (tree->widget() != s)) 0402 d->form->formWidget()->highlightWidgets(tree->widget(), static_cast<QWidget*>(s)); 0403 } 0404 #endif 0405 else if (d->selectionOrInsertingStarted() 0406 && s == widget() 0407 && !d->toplevel 0408 && (mev->modifiers() != Qt::ControlModifier) 0409 && !connecting 0410 ) 0411 { // draw the selection rect 0412 if ((mev->buttons() != Qt::LeftButton) || d->state == Private::InlineEditing) 0413 return true; 0414 d->updateSelectionOrInsertingRectangle(mev->pos()); 0415 0416 //! @todo? if (d->form->formWidget()) 0417 //! @todo? d->form->formWidget()->drawRect(r, 1); 0418 0419 d->state = Private::DoingNothing; 0420 return true; 0421 } 0422 else if (mev->buttons() == Qt::LeftButton && mev->modifiers() == Qt::ControlModifier) { 0423 //! @todo draw the insert rect for the copied widget 0424 // if (s == widget()) { 0425 // return true; 0426 // } 0427 return true; 0428 } 0429 else if ( ( (mev->buttons() == Qt::LeftButton && mev->modifiers() == Qt::NoModifier) 0430 || (mev->buttons() == Qt::LeftButton && mev->modifiers() == (Qt::ControlModifier | Qt::AltModifier)) 0431 ) 0432 && d->form->state() != Form::WidgetInserting 0433 && d->state != Private::CopyingWidget 0434 ) 0435 { 0436 // we are dragging the widget(s) to move it 0437 if (!d->toplevel && d->moving == widget()) // no effect for form 0438 return false; 0439 if (!d->moving || !d->moving->parentWidget()) 0440 return true; 0441 0442 moveSelectedWidgetsBy(mev->x() - d->grab.x(), mev->y() - d->grab.y()); 0443 d->state = Private::MovingWidget; 0444 } 0445 0446 return true; // eat 0447 } 0448 0449 case QEvent::Paint: { // Draw the dotted background 0450 if (s != widget()) 0451 return false; 0452 if (widget()->inherits("ContainerWidget")) { 0453 QWidget *parentContainer = widget()->parentWidget()->parentWidget()->parentWidget(); 0454 if (parentContainer->inherits("KexiDBForm") || parentContainer->inherits("ContainerWidget")) { 0455 // do not display grid on ContainerWidget (e.g. inside of tab widget) becasue it's already done at higher level 0456 return false; 0457 } 0458 } 0459 QPaintEvent* pe = static_cast<QPaintEvent*>(e); 0460 QPainter p(widget()); 0461 p.setRenderHint(QPainter::Antialiasing, false); 0462 #if 1 // grid 0463 //#define DEBUG_PAINTER 0464 #ifdef DEBUG_PAINTER 0465 qDebug() << "would draw grid" << pe->rect(); 0466 QTime t; 0467 t.start(); 0468 long points= 0; 0469 #endif 0470 int gridX = d->form->gridSize(); 0471 int gridY = d->form->gridSize(); 0472 0473 QColor c1(Qt::white); 0474 c1.setAlpha(100); 0475 QColor c2(Qt::black); 0476 c2.setAlpha(100); 0477 int cols = widget()->width() / gridX; 0478 int rows = widget()->height() / gridY; 0479 const QRect r( pe->rect() ); 0480 // for optimization, compute the start/end row and column to paint 0481 int startRow = (r.top()-1) / gridY; 0482 startRow = qMax(startRow, 1); 0483 int endRow = (r.bottom()+1) / gridY; 0484 endRow = qMin(endRow, rows); 0485 int startCol = (r.left()-1) / gridX; 0486 startCol = qMax(startCol, 1); 0487 int endCol = (r.right()+1) / gridX; 0488 endCol = qMin(endCol, cols); 0489 QVector<QPoint> gridpoints; 0490 for (int rowcursor = startRow; rowcursor <= endRow; ++rowcursor) { 0491 for (int colcursor = startCol; colcursor <= endCol; ++colcursor) { 0492 gridpoints << QPoint(colcursor * gridX - 1,rowcursor * gridY - 1); 0493 #ifdef DEBUG_PAINTER 0494 points++; 0495 #endif 0496 } 0497 } 0498 0499 //! @todo when container's background is not solid color, find better grid color, 0500 //! e.g. buffer the background for pixmaps or gradients 0501 p.setPen(KexiUtils::contrastColor(widget()->palette().background().color())); 0502 p.drawPoints(gridpoints); 0503 #ifdef DEBUG_PAINTER 0504 qDebug() << "millisecs:" << t.elapsed() << "points:" << points; 0505 #endif 0506 #endif 0507 if (d->selectionOrInsertingRectangle().isValid()) { 0508 QColor sc1(Qt::white); 0509 sc1.setAlpha(220); 0510 QColor sc2(Qt::black); 0511 sc2.setAlpha(200); 0512 QPen selPen1(sc2, 1.0); 0513 QPen selPen2(sc1, 1.0, Qt::CustomDashLine); 0514 QVector<qreal> dashes; 0515 dashes << 2 << 2; 0516 selPen2.setDashPattern(dashes); 0517 QRect selectionOrInsertingRectangle(d->selectionOrInsertingRectangle()); 0518 selectionOrInsertingRectangle.setSize( 0519 selectionOrInsertingRectangle.size() - QSize(1,1)); // -(1,1) because the rect is painted 0520 // up to the next pixel in Qt 0521 p.setPen(selPen1); 0522 p.drawRect(selectionOrInsertingRectangle); 0523 p.setPen(selPen2); 0524 p.drawRect(selectionOrInsertingRectangle); 0525 } 0526 return false; 0527 } 0528 0529 case QEvent::Resize: { // we are resizing a widget, so we enter MovingWidget state 0530 // -> the layout will be reloaded when releasing mouse 0531 if (d->form->interactiveMode()) 0532 d->state = Private::MovingWidget; 0533 break; 0534 } 0535 0536 //case QEvent::AccelOverride: 0537 case QEvent::KeyPress: { 0538 QKeyEvent *kev = static_cast<QKeyEvent*>(e); 0539 0540 if (kev->key() == Qt::Key_F2) { // pressing F2 == double-clicking 0541 QWidget *w; 0542 0543 // try to find the widget which was clicked last and should be edited 0544 if (d->form->selectedWidgets()->count() == 1) 0545 w = d->form->selectedWidgets()->first(); 0546 else if (d->form->selectedWidgets()->contains(d->moving)) 0547 w = d->moving; 0548 else 0549 w = d->form->selectedWidgets()->last(); 0550 if (d->form->library()->startInlineEditing(w->metaObject()->className(), w, this)) { 0551 d->state = Private::InlineEditing; 0552 } 0553 } 0554 else if (kev->key() == Qt::Key_Escape) { 0555 if (false) { 0556 } 0557 #ifdef KFD_SIGSLOTS 0558 else if (connecting) { 0559 d->form->abortCreatingConnection(); 0560 } 0561 #endif 0562 else if (d->form->state() == Form::WidgetInserting) { 0563 d->form->abortWidgetInserting(); 0564 } 0565 return true; 0566 } 0567 else if ((kev->key() == Qt::Key_Control) && (d->state == Private::MovingWidget)) { 0568 if (!d->moving) 0569 return true; 0570 // we simulate a mouse move event to update screen 0571 QMouseEvent *mev = new QMouseEvent(QEvent::MouseMove, 0572 d->moving->mapFromGlobal(QCursor::pos()), 0573 Qt::NoButton, 0574 Qt::LeftButton, 0575 Qt::ControlModifier); 0576 eventFilter(d->moving, mev); 0577 delete mev; 0578 } 0579 else if (kev->key() == Qt::Key_Delete) { 0580 d->form->deleteWidget(); 0581 return true; 0582 } 0583 // directional buttons move the widget 0584 else if (kev->key() == Qt::Key_Left) { // move the widget of gridX to the left 0585 moveSelectedWidgetsBy(-form()->gridSize(), 0); 0586 return true; 0587 } 0588 else if (kev->key() == Qt::Key_Right) { // move the widget of gridX to the right 0589 moveSelectedWidgetsBy(form()->gridSize(), 0); 0590 return true; 0591 } 0592 else if (kev->key() == Qt::Key_Up) { // move the widget of gridY to the top 0593 moveSelectedWidgetsBy(0, - form()->gridSize()); 0594 return true; 0595 } 0596 else if (kev->key() == Qt::Key_Down) { // move the widget of gridX to the bottom 0597 moveSelectedWidgetsBy(0, form()->gridSize()); 0598 return true; 0599 } 0600 else if ((kev->key() == Qt::Key_Tab) || (kev->key() == Qt::Key_Backtab)) { 0601 ObjectTreeItem *item = form()->objectTree()->lookup( 0602 form()->selectedWidgets()->first()->objectName() 0603 ); 0604 if (!item || !item->parent()) 0605 return true; 0606 ObjectTreeList *list = item->parent()->children(); 0607 if (list->count() == 1) 0608 return true; 0609 int index = list->indexOf(item); 0610 0611 if (kev->key() == Qt::Key_Backtab) { 0612 if (index == 0) // go back to the last item 0613 index = list->count() - 1; 0614 else 0615 index = index - 1; 0616 } 0617 else { 0618 if (index == int(list->count() - 1)) // go back to the first item 0619 index = 0; 0620 else 0621 index = index + 1; 0622 } 0623 0624 ObjectTreeItem *nextItem = list->at(index); 0625 if (nextItem && nextItem->widget()) { 0626 form()->selectWidget(nextItem->widget()); 0627 } 0628 } 0629 return true; 0630 } 0631 0632 case QEvent::KeyRelease: { 0633 QKeyEvent *kev = static_cast<QKeyEvent*>(e); 0634 if ((kev->key() == Qt::Key_Control) && (d->state == Private::CopyingWidget)) { 0635 // cancel copying 0636 } 0637 return true; 0638 } 0639 0640 case QEvent::MouseButtonDblClick: { // editing 0641 //qDebug() << "Mouse dbl click for widget" << s->objectName(); 0642 QWidget *w = static_cast<QWidget*>(s); 0643 if (!w) 0644 return false; 0645 0646 if (d->form->library()->startInlineEditing(w->metaObject()->className(), w, this)) { 0647 d->state = Private::InlineEditing; 0648 } 0649 return true; 0650 } 0651 0652 case QEvent::ContextMenu: { 0653 QContextMenuEvent* cme = static_cast<QContextMenuEvent*>(e); 0654 d->moving = 0; // clear this otherwise mouse dragging outside 0655 // of the popup menu would drag the selected widget(s) randomly 0656 // target widget is the same as selected widget if this is context key event 0657 QWidget *widgetTarget = cme->reason() == QContextMenuEvent::Mouse 0658 ? static_cast<QWidget*>(s) : d->form->selectedWidget(); 0659 if (widgetTarget) { 0660 // target widget is the same as selected widget if this is context key event 0661 QPoint pos; 0662 if (cme->reason() == QContextMenuEvent::Mouse) { 0663 pos = cme->pos(); 0664 } 0665 else { 0666 if (widgetTarget == topLevelWidget()) { 0667 pos = QPoint(20, 20); 0668 } 0669 else { 0670 pos = QPoint(widgetTarget->width() / 2, widgetTarget->height() / 2); 0671 } 0672 } 0673 d->form->createContextMenu(widgetTarget, this, pos, Form::FormContextMenuTarget); 0674 return true; 0675 } 0676 break; 0677 } 0678 case QEvent::Enter: 0679 case QEvent::Leave: 0680 case QEvent::FocusIn: 0681 case QEvent::FocusOut: 0682 return true; // eat them 0683 0684 default: 0685 break; 0686 } 0687 return false; // let the widget do the rest ... 0688 } 0689 0690 bool 0691 Container::handleMouseReleaseEvent(QObject *s, QMouseEvent *mev) 0692 { 0693 if (d->form->state() == Form::WidgetInserting) { 0694 if (mev->button() == Qt::LeftButton) { // insert the widget at cursor pos 0695 Command *com = new InsertWidgetCommand(*this); 0696 d->form->addCommand(com); 0697 d->stopSelectionRectangleOrInserting(); 0698 } 0699 else { // right button, etc. 0700 d->form->abortWidgetInserting(); 0701 } 0702 return true; 0703 } 0704 else if ( s == widget() 0705 && !d->toplevel 0706 && (mev->button() != Qt::RightButton) 0707 && d->selectionOrInsertingRectangle().isValid() ) 0708 { 0709 // we are still drawing a rect to select widgets 0710 selectionWidgetsForRectangle(mev->pos()); 0711 return true; 0712 } 0713 0714 if (mev->button() == Qt::RightButton) { 0715 // Right-click -> context menu 0716 } 0717 else if (mev->button() == Qt::LeftButton && mev->modifiers() == Qt::ControlModifier) { 0718 // copying a widget by Ctrl+dragging 0719 if (s == widget()) // should have no effect on form 0720 return true; 0721 0722 // prevent accidental copying of widget (when moving mouse a little while selecting) 0723 if ( ((mev->pos().x() - d->grab.x()) < form()->gridSize() && (d->grab.x() - mev->pos().x()) < form()->gridSize()) 0724 && ((mev->pos().y() - d->grab.y()) < form()->gridSize() && (d->grab.y() - mev->pos().y()) < form()->gridSize()) ) 0725 { 0726 //qDebug() << "The widget has not been moved. No copying."; 0727 return true; 0728 } 0729 QPoint copyToPoint; 0730 if (d->form->selectedWidgets()->count() > 1) { 0731 copyToPoint = mev->pos(); 0732 } 0733 else { 0734 copyToPoint = static_cast<QWidget*>(s)->mapTo(widget(), mev->pos() - d->grab); 0735 } 0736 0737 Command *com = new DuplicateWidgetCommand(*d->form->activeContainer(), *d->form->selectedWidgets(), copyToPoint); 0738 d->form->addCommand(com); 0739 } 0740 else if (mev->button() == Qt::LeftButton && !(mev->buttons() & Qt::LeftButton) && d->state == Private::MovingWidget) { 0741 // one widget has been moved, so we need to update the layout 0742 reloadLayout(); 0743 } 0744 0745 // cancel copying as user released Ctrl before releasing mouse button 0746 d->stopSelectionRectangleOrInserting(); 0747 d->state = Private::DoingNothing; 0748 d->moving.clear(); 0749 return true; // eat 0750 } 0751 0752 void Container::selectWidget(QWidget *w, Form::WidgetSelectionFlags flags) 0753 { 0754 if (!w) { 0755 d->form->selectWidget(widget()); 0756 return; 0757 } 0758 0759 d->form->selectWidget(w, flags); 0760 } 0761 0762 void 0763 Container::deselectWidget(QWidget *w) 0764 { 0765 if (!w) 0766 return; 0767 0768 d->form->deselectWidget(w); 0769 } 0770 0771 Container* Container::toplevel() 0772 { 0773 if (d->toplevel) 0774 return d->toplevel; 0775 0776 return this; 0777 } 0778 0779 QWidget* Container::topLevelWidget() const 0780 { 0781 if (d->toplevel) 0782 return d->toplevel->widget(); 0783 0784 return widget(); 0785 } 0786 0787 void 0788 Container::deleteWidget(QWidget *w) 0789 { 0790 if (!w) 0791 return; 0792 ObjectTreeItem *itemToRemove = d->form->objectTree()->lookup(w->objectName()); 0793 if (!itemToRemove) 0794 return; 0795 QWidget *widgetoRemove = itemToRemove->widget(); 0796 const ObjectTreeItem *parentItemToSelect = itemToRemove->parent() 0797 ? d->form->library()->selectableItem(itemToRemove->parent()) : 0; 0798 QWidget *parentWidgetToSelect = parentItemToSelect ? parentItemToSelect->widget() : 0; 0799 d->form->objectTree()->removeItem(itemToRemove); 0800 d->form->selectWidget(parentWidgetToSelect); 0801 delete widgetoRemove; 0802 } 0803 0804 void 0805 Container::widgetDeleted() 0806 { 0807 d->widgetDeleted(); 0808 deleteLater(); 0809 } 0810 0811 /// Layout functions 0812 0813 QLayout* Container::layout() const 0814 { 0815 return d->layout; 0816 } 0817 0818 Form::LayoutType Container::layoutType() const 0819 { 0820 return d->layType; 0821 } 0822 0823 int Container::layoutMargin() const 0824 { 0825 return d->margin; 0826 } 0827 0828 int Container::layoutSpacing() const 0829 { 0830 return d->spacing; 0831 } 0832 0833 void Container::setLayoutType(Form::LayoutType type) 0834 { 0835 if (d->layType == type) 0836 return; 0837 0838 delete d->layout; 0839 d->layout = 0; 0840 d->layType = type; 0841 0842 switch (type) { 0843 case Form::HBox: { 0844 d->layout = static_cast<QLayout*>( new QHBoxLayout(widget()) ); 0845 d->layout->setContentsMargins(d->margin, d->margin, d->margin, d->margin); 0846 d->layout->setSpacing(d->spacing); 0847 createBoxLayout(new HorizontalWidgetList(d->form->toplevelContainer()->widget())); 0848 break; 0849 } 0850 case Form::VBox: { 0851 d->layout = static_cast<QLayout*>( new QVBoxLayout(widget()) ); 0852 d->layout->setContentsMargins(d->margin, d->margin, d->margin, d->margin); 0853 d->layout->setSpacing(d->spacing); 0854 createBoxLayout(new VerticalWidgetList(d->form->toplevelContainer()->widget())); 0855 break; 0856 } 0857 case Form::Grid: { 0858 createGridLayout(); 0859 break; 0860 } 0861 default: { 0862 d->layType = Form::NoLayout; 0863 return; 0864 } 0865 } 0866 widget()->setGeometry(widget()->geometry()); // just update layout 0867 d->layout->activate(); 0868 } 0869 0870 void Container::setLayout(QLayout* layout) 0871 { 0872 d->layout = layout; 0873 } 0874 0875 void Container::setLayoutSpacing(int spacing) 0876 { 0877 d->spacing = spacing; 0878 } 0879 0880 void Container::setLayoutMargin(int margin) 0881 { 0882 d->margin = margin; 0883 } 0884 0885 void 0886 Container::reloadLayout() 0887 { 0888 Form::LayoutType type = d->layType; 0889 setLayoutType(Form::NoLayout); 0890 setLayoutType(type); 0891 } 0892 0893 void 0894 Container::createBoxLayout(CustomSortableWidgetList* list) 0895 { 0896 QBoxLayout *layout = static_cast<QBoxLayout*>(d->layout); 0897 0898 foreach (ObjectTreeItem *titem, *d->tree->children()) { 0899 list->append(titem->widget()); 0900 } 0901 list->sort(); 0902 0903 foreach (QWidget *w, *list) { 0904 layout->addWidget(w); 0905 } 0906 delete list; 0907 } 0908 0909 void 0910 Container::createGridLayout(bool testOnly) 0911 { 0912 //Those lists sort widgets by y and x 0913 VerticalWidgetList *vlist = new VerticalWidgetList(d->form->toplevelContainer()->widget()); 0914 HorizontalWidgetList *hlist = new HorizontalWidgetList(d->form->toplevelContainer()->widget()); 0915 // The vector are used to store the x (or y) beginning of each column (or row) 0916 QVector<int> cols; 0917 QVector<int> rows; 0918 int end = -1000; 0919 bool same = false; 0920 0921 foreach (ObjectTreeItem *titem, *d->tree->children()) { 0922 vlist->append(titem->widget()); 0923 } 0924 vlist->sort(); 0925 0926 foreach (ObjectTreeItem *titem, *d->tree->children()) { 0927 hlist->append(titem->widget()); 0928 } 0929 hlist->sort(); 0930 0931 // First we need to make sure that two widgets won't be in the same row, 0932 // ie that no widget overlap another one 0933 if (!testOnly) { 0934 for (QWidgetList::ConstIterator it(vlist->constBegin()); it!=vlist->constEnd(); ++it) { 0935 QWidget *w = *it; 0936 for (QWidgetList::ConstIterator it2(it); it2!=vlist->constEnd(); ++it2) { 0937 QWidget *nextw = *it2; 0938 if ((w->y() >= nextw->y()) || (nextw->y() >= w->geometry().bottom())) 0939 break; 0940 0941 if (!w->geometry().intersects(nextw->geometry())) 0942 break; 0943 // If the geometries of the two widgets intersect each other, 0944 // we move one of the widget to the rght or bottom of the other 0945 if ((nextw->y() - w->y()) > qAbs(nextw->x() - w->x())) 0946 nextw->move(nextw->x(), w->geometry().bottom() + 1); 0947 else if (nextw->x() >= w->x()) 0948 nextw->move(w->geometry().right() + 1, nextw->y()); 0949 else 0950 w->move(nextw->geometry().right() + 1, nextw->y()); 0951 } 0952 } 0953 } 0954 0955 // Then we count the number of rows in the layout, and set their beginnings 0956 for (QWidgetList::ConstIterator it(vlist->constBegin()); it!=vlist->constEnd(); ++it) { 0957 QWidget *w = *it; 0958 if (!same) { // this widget will make a new row 0959 end = w->geometry().bottom(); 0960 rows.append(w->y()); 0961 } 0962 QWidgetList::ConstIterator it2(it); 0963 0964 // If same == true, it means we are in the same row as prev widget 0965 // (so no need to create a new column) 0966 ++it2; 0967 if (it2==vlist->constEnd()) 0968 break; 0969 0970 QWidget *nextw = *it2; 0971 if (nextw->y() >= end) 0972 same = false; 0973 else { 0974 same = !(same && (nextw->y() >= w->geometry().bottom())); 0975 if (!same) 0976 end = w->geometry().bottom(); 0977 } 0978 } 0979 //qDebug() << "the new grid will have n rows: n == " << rows.size(); 0980 0981 end = -10000; 0982 same = false; 0983 // We do the same thing for the columns 0984 for (QWidgetList::ConstIterator it(hlist->constBegin()); it!=hlist->constEnd(); ++it) { 0985 QWidget *w = *it; 0986 if (!same) { 0987 end = w->geometry().right(); 0988 cols.append(w->x()); 0989 } 0990 0991 QWidgetList::ConstIterator it2(it); 0992 ++it2; 0993 if (it2==hlist->constEnd()) 0994 break; 0995 0996 QWidget *nextw = *it2; 0997 if (nextw->x() >= end) 0998 same = false; 0999 else { 1000 same = !(same && (nextw->x() >= w->geometry().right())); 1001 if (!same) 1002 end = w->geometry().right(); 1003 } 1004 } 1005 //qDebug() << "the new grid will have n columns: n == " << cols.size(); 1006 1007 // We create the layout .. 1008 QGridLayout *layout = 0; 1009 if (!testOnly) { 1010 layout = new QGridLayout(widget()); 1011 layout->setObjectName("grid"); 1012 //! @todo allow for individual margins and spacing 1013 layout->setContentsMargins(d->margin, d->margin, d->margin, d->margin); 1014 layout->setSpacing(d->spacing); 1015 d->layout = static_cast<QLayout*>(layout); 1016 } 1017 1018 // .. and we fill it with widgets 1019 for (QWidgetList::ConstIterator it(vlist->constBegin()); it!=vlist->constEnd(); ++it) { 1020 QWidget *w = *it; 1021 QRect r( w->geometry() ); 1022 int wcol = 0, wrow = 0, endrow = 0, endcol = 0; 1023 int i = 0; 1024 1025 // We look for widget row(s) .. 1026 while (r.y() >= rows[i]) { 1027 if (rows.size() <= (i + 1)) { // we are the last row 1028 wrow = i; 1029 break; 1030 } 1031 if (r.y() < rows[i+1]) { 1032 wrow = i; // the widget will be in this row 1033 int j = i + 1; 1034 // Then we check if the widget needs to span multiple rows 1035 while (rows.size() >= (j + 1) && r.bottom() > rows[j]) { 1036 endrow = j; 1037 j++; 1038 } 1039 1040 break; 1041 } 1042 i++; 1043 } 1044 //qDebug() << "the widget " << w->objectName() << " will be in the row " << wrow << 1045 //" and will go to the row " << endrow; 1046 1047 // .. and column(s) 1048 i = 0; 1049 while (r.x() >= cols[i]) { 1050 if (cols.size() <= (i + 1)) { // last column 1051 wcol = i; 1052 break; 1053 } 1054 if (r.x() < cols[i+1]) { 1055 wcol = i; 1056 int j = i + 1; 1057 // Then we check if the widget needs to span multiple columns 1058 while (cols.size() >= (j + 1) && r.right() > cols[j]) { 1059 endcol = j; 1060 j++; 1061 } 1062 1063 break; 1064 } 1065 i++; 1066 } 1067 //qDebug() << "the widget " << w->objectName() << " will be in the col " << wcol << 1068 // " and will go to the col " << endcol; 1069 1070 ObjectTreeItem *item = d->form->objectTree()->lookup(w->objectName()); 1071 if (item) { 1072 if (!endrow && !endcol) { 1073 if (!testOnly) 1074 layout->addWidget(w, wrow, wcol); 1075 item->setGridPos(wrow, wcol, 0, 0); 1076 } 1077 else { 1078 if (!endcol) 1079 endcol = wcol; 1080 if (!endrow) 1081 endrow = wrow; 1082 if (!testOnly) 1083 layout->addWidget(w, wrow, wcol, endrow - wrow + 1, endcol - wcol + 1); 1084 item->setGridPos(wrow, wcol, endrow - wrow + 1, endcol - wcol + 1); 1085 } 1086 } 1087 } //for 1088 } 1089 1090 QString 1091 Container::layoutTypeToString(Form::LayoutType type) 1092 { 1093 switch (type) { 1094 case Form::HBox: return "HBox"; 1095 case Form::VBox: return "VBox"; 1096 case Form::Grid: return "Grid"; 1097 case Form::HFlow: return "HFlow"; 1098 case Form::VFlow: return "VFlow"; 1099 default: return "NoLayout"; 1100 } 1101 } 1102 1103 Form::LayoutType 1104 Container::stringToLayoutType(const QString &name) 1105 { 1106 if (name == "HBox") return Form::HBox; 1107 if (name == "VBox") return Form::VBox; 1108 if (name == "Grid") return Form::Grid; 1109 if (name == "HFlow") return Form::HFlow; 1110 if (name == "VFlow") return Form::VFlow; 1111 return Form::NoLayout; 1112 } 1113 1114 #ifdef KFD_SIGSLOTS 1115 void Container::drawConnection(QMouseEvent *mev) 1116 { 1117 if (mev->button() != Qt::LeftButton) { 1118 FormManager::self()->resetCreatedConnection(); 1119 return; 1120 } 1121 // First click, we select the sender and display menu to choose signal 1122 if (FormManager::self()->createdConnection()->sender().isNull()) { 1123 FormManager::self()->createdConnection()->setSender(d->moving->objectName()); 1124 if (d->form->formWidget()) { 1125 d->form->formWidget()->initBuffer(); 1126 d->form->formWidget()->highlightWidgets(d->moving, 0); 1127 } 1128 FormManager::self()->createSignalMenu(d->moving); 1129 return; 1130 } 1131 // the user clicked outside the menu, we cancel the connection 1132 if (FormManager::self()->createdConnection()->signal().isNull()) { 1133 FormManager::self()->stopCreatingConnection(); 1134 return; 1135 } 1136 // second click to choose the receiver 1137 if (FormManager::self()->createdConnection()->receiver().isNull()) { 1138 FormManager::self()->createdConnection()->setReceiver(d->moving->objectName()); 1139 FormManager::self()->createSlotMenu(d->moving); 1140 widget()->repaint(); 1141 return; 1142 } 1143 // the user clicked outside the menu, we cancel the connection 1144 if (FormManager::self()->createdConnection()->slot().isNull()) { 1145 FormManager::self()->stopCreatingConnection(); 1146 return; 1147 } 1148 } 1149 #endif 1150 1151 void Container::selectionWidgetsForRectangle(const QPoint& secondPoint) 1152 { 1153 //finish drawing unclipped selection rectangle: clear the surface 1154 d->updateSelectionOrInsertingRectangle(secondPoint); 1155 1156 selectWidget(0); 1157 QWidget *widgetToSelect = 0; 1158 // We check which widgets are in the rect and select them 1159 foreach (ObjectTreeItem *titem, *d->tree->children()) { 1160 QWidget *w = titem->widget(); 1161 if (!w) 1162 continue; 1163 if (w->geometry().intersects( d->selectionOrInsertingRectangle() ) && w != widget()) { 1164 if (widgetToSelect) { 1165 selectWidget(widgetToSelect, 1166 Form::AddToPreviousSelection | Form::Raise | Form::MoreWillBeSelected); 1167 } 1168 widgetToSelect = w; //select later 1169 } 1170 } 1171 if (widgetToSelect) { 1172 //the last one left 1173 selectWidget(widgetToSelect, 1174 Form::AddToPreviousSelection | Form::Raise | Form::LastSelection); 1175 } 1176 1177 d->state = Private::DoingNothing; 1178 d->stopSelectionRectangleOrInserting(); 1179 } 1180 1181 // Other functions used by eventFilter 1182 void Container::moveSelectedWidgetsBy(int realdx, int realdy, QMouseEvent *mev) 1183 { 1184 if (d->form->selectedWidget() == d->form->widget()) 1185 return; //do not move top-level widget 1186 1187 const int gridX = d->form->gridSize(); 1188 const int gridY = d->form->gridSize(); 1189 int dx = realdx, dy = realdy; 1190 1191 foreach (QWidget *w, *d->form->selectedWidgets()) { 1192 if (!w->parent() || w->parent()->inherits("QTabWidget") || w->parent()->inherits("QStackedWidget")) 1193 continue; 1194 1195 if (w->parentWidget() && KexiUtils::objectIsA(w->parentWidget(), "QStackedWidget")) { 1196 w = w->parentWidget(); // widget is a stacked widget's page 1197 } 1198 if (w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) { 1199 w = w->parentWidget(); // widget is a tab widget page 1200 } 1201 1202 int tmpx = w->x() + realdx; 1203 int tmpy = w->y() + realdy; 1204 if (tmpx < 0) 1205 dx = qMax(0 - w->x(), dx); // because dx is <0 1206 else if (tmpx > w->parentWidget()->width() - gridX) 1207 dx = qMin(w->parentWidget()->width() - gridX - w->x(), dx); 1208 1209 if (tmpy < 0) 1210 dy = qMax(0 - w->y(), dy); // because dy is <0 1211 else if (tmpy > w->parentWidget()->height() - gridY) 1212 dy = qMin(w->parentWidget()->height() - gridY - w->y(), dy); 1213 } 1214 1215 foreach (QWidget *w, *d->form->selectedWidgets()) { 1216 // Don't move tab widget pages (or widget stack pages) 1217 if (!w->parent() || w->parent()->inherits("QTabWidget") || w->parent()->inherits("QStackedWidget")) 1218 continue; 1219 1220 if (w->parentWidget() && KexiUtils::objectIsA(w->parentWidget(), "QStackedWidget")) { 1221 w = w->parentWidget(); // widget is WidgetStack page 1222 if (w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) // widget is a tab widget page 1223 w = w->parentWidget(); 1224 } 1225 1226 int tmpx, tmpy; 1227 if ( !d->form->isSnapToGridEnabled() 1228 || (mev && mev->buttons() == Qt::LeftButton && mev->modifiers() == (Qt::ControlModifier | Qt::AltModifier)) 1229 ) 1230 { 1231 tmpx = w->x() + dx; 1232 tmpy = w->y() + dy; 1233 } 1234 else { 1235 tmpx = alignValueToGrid(w->x() + dx, gridX); 1236 tmpy = alignValueToGrid(w->y() + dy, gridY); 1237 } 1238 1239 if (tmpx != w->x() || tmpy != w->y()) { 1240 QRect g(w->geometry()); 1241 g.moveTo(tmpx, tmpy); 1242 if (d->form->selectedWidget()) { 1243 // single widget 1244 d->form->addPropertyCommand(w->objectName().toLatin1(), w->geometry(), 1245 g, "geometry", Form::ExecuteCommand, 1246 d->idOfPropertyCommand); 1247 w->move(tmpx, tmpy); 1248 } 1249 else { 1250 // multiple widgets: group them 1251 w->move(tmpx, tmpy); 1252 } 1253 } 1254 } 1255 } 1256 1257 void Container::startChangingGeometryPropertyForSelectedWidget() 1258 { 1259 ++d->idOfPropertyCommand; 1260 } 1261 1262 void Container::setGeometryPropertyForSelectedWidget(const QRect &newGeometry) 1263 { 1264 QWidget *w = d->form->selectedWidget(); 1265 if (!w) { 1266 return; 1267 } 1268 d->form->addPropertyCommand(w->objectName().toLatin1(), w->geometry(), 1269 newGeometry, "geometry", Form::ExecuteCommand, 1270 d->idOfPropertyCommand); 1271 } 1272 1273 void Container::stopInlineEditing() 1274 { 1275 d->state = Private::DoingNothing; 1276 } 1277 1278 QRect Container::selectionOrInsertingRectangle() const 1279 { 1280 return d->selectionOrInsertingRectangle(); 1281 } 1282 1283 QPoint Container::selectionOrInsertingBegin() const 1284 { 1285 return d->selectionOrInsertingBegin(); 1286 } 1287 1288 ObjectTreeItem* Container::objectTree() const 1289 { 1290 return d->tree; 1291 } 1292 1293 void Container::setObjectTree(ObjectTreeItem *t) 1294 { 1295 d->tree = t; 1296 } 1297 1298 //////////// 1299 1300 class Q_DECL_HIDDEN DesignTimeDynamicChildWidgetHandler::Private 1301 { 1302 public: 1303 Private() : item(0) {} 1304 1305 ObjectTreeItem* item; 1306 }; 1307 1308 DesignTimeDynamicChildWidgetHandler::DesignTimeDynamicChildWidgetHandler() 1309 : d(new Private) 1310 { 1311 } 1312 1313 DesignTimeDynamicChildWidgetHandler::~DesignTimeDynamicChildWidgetHandler() 1314 { 1315 delete d; 1316 } 1317 1318 void 1319 DesignTimeDynamicChildWidgetHandler::childWidgetAdded(QWidget* w) 1320 { 1321 if (d->item) { 1322 KexiUtils::installRecursiveEventFilter(w, d->item->eventEater()); 1323 } 1324 } 1325 1326 void DesignTimeDynamicChildWidgetHandler::assignItem(ObjectTreeItem* item) 1327 { 1328 d->item = item; 1329 } 1330