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