kexi

container.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
00003    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <qpainter.h>
00022 #include <qpixmap.h>
00023 #include <qrect.h>
00024 #include <qevent.h>
00025 #include <qvaluevector.h>
00026 #include <qlayout.h>
00027 #include <qcursor.h>
00028 
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031 #include <kpopupmenu.h>
00032 
00033 #include <cstdlib> // for abs()
00034 
00035 #include "utils.h"
00036 #include "container.h"
00037 #include "widgetlibrary.h"
00038 #include "objecttree.h"
00039 #include "form.h"
00040 #include "formmanager.h"
00041 #include "commands.h"
00042 #include "events.h"
00043 #include "kexiflowlayout.h"
00044 
00045 using namespace KFormDesigner;
00046 
00047 EventEater::EventEater(QWidget *widget, QObject *container)
00048  : QObject(container)
00049 {
00050     m_widget = widget;
00051     m_container = container;
00052 
00053     installRecursiveEventFilter(m_widget, this);
00054 }
00055 
00056 bool
00057 EventEater::eventFilter(QObject *, QEvent *ev)
00058 {
00059     if(!m_container)
00060         return false;
00061 
00062     // When the user click the empty part of tab bar, only MouseReleaseEvent is sent,
00063     // we need to simulate the Press event
00064     if(ev->type() == QEvent::MouseButtonRelease && m_widget->inherits("QTabWidget"))
00065     {
00066         QMouseEvent *mev = static_cast<QMouseEvent*>(ev);
00067         if(mev->button() == LeftButton)
00068         {
00069             QMouseEvent *myev = new QMouseEvent(QEvent::MouseButtonPress, mev->pos(), mev->button(), mev->state());
00070             m_container->eventFilter(m_widget, myev);
00071             delete myev;
00072             //return true;
00073         }
00074     }
00075 //  else if(ev->type() == QEvent::ChildInserted) {
00076         // widget's children have changed, we need to reinstall filter
00077 //      installRecursiveEventFilter(m_widget, this);
00078 //  }
00079 
00080     return m_container->eventFilter(m_widget, ev);
00081 }
00082 
00083 EventEater::~EventEater()
00084 {
00085     if(m_widget)
00086         removeRecursiveEventFilter(m_widget, this);
00087 }
00088 
00089 // Container itself
00090 
00091 Container::Container(Container *toplevel, QWidget *container, QObject *parent, const char *name)
00092 : QObject(parent, name)
00093 , m_insertBegin(-1,-1)
00094 , m_mousePressEventReceived(false)
00095 , m_mouseReleaseEvent(QEvent::None, QPoint(), 0, 0)
00096 {
00097     m_container = container;
00098     m_toplevel = toplevel;
00099 
00100     m_moving = 0;
00101     m_tree = 0;
00102     m_form = toplevel ? toplevel->form() : 0;
00103     m_layout = 0;
00104     m_layType = NoLayout;
00105     m_state = DoingNothing;
00106 
00107     QCString classname = container->className();
00108     if((classname == "HBox") || (classname == "Grid") || (classname == "VBox") ||
00109         (classname == "HFlow")  || (classname == "VFlow"))
00110         m_margin = 4; // those containers don't have frames, so little margin
00111     else
00112         m_margin = m_form ? m_form->defaultMargin() : 0;
00113     m_spacing = m_form ? m_form->defaultSpacing() : 0;
00114 
00115     if(toplevel)
00116     {
00117         ObjectTreeItem *it = new ObjectTreeItem(m_form->library()->displayName(classname),
00118             widget()->name(), widget(), this, this);
00119         setObjectTree(it);
00120 
00121         if(parent->isWidgetType())
00122         {
00123             QString n = parent->name();
00124             ObjectTreeItem *parent = m_form->objectTree()->lookup(n);
00125             m_form->objectTree()->addItem(parent, it);
00126         }
00127         else
00128             m_form->objectTree()->addItem(toplevel->objectTree(), it);
00129 
00130         connect(toplevel, SIGNAL(destroyed()), this, SLOT(widgetDeleted()));
00131     }
00132 
00133     connect(container, SIGNAL(destroyed()), this, SLOT(widgetDeleted()));
00134 }
00135 
00136 Container::~Container()
00137 {
00138     kdDebug() << " Container being deleted this == " << name() << endl;
00139 }
00140 
00141 void
00142 Container::setForm(Form *form)
00143 {
00144     m_form = form;
00145     m_margin = m_form ? m_form->defaultMargin() : 0;
00146     m_spacing = m_form ? m_form->defaultSpacing() : 0;
00147 }
00148 
00149 bool
00150 Container::eventFilter(QObject *s, QEvent *e)
00151 {
00152 //  kdDebug() << e->type() << endl;
00153     switch(e->type())
00154     {
00155         case QEvent::MouseButtonPress:
00156         {
00157             m_insertBegin = QPoint(-1, -1);
00158             m_mousePressEventReceived = true;
00159 
00160             kdDebug() << "QEvent::MouseButtonPress sender object = " << s->name()
00161                 << "of type " << s->className() << endl;
00162             kdDebug() << "QEvent::MouseButtonPress this          = " << name() << endl;
00163 
00164             m_moving = static_cast<QWidget*>(s);
00165             QMouseEvent *mev = static_cast<QMouseEvent*>(e);
00166             m_grab = QPoint(mev->x(), mev->y());
00167 
00168             // we are drawing a connection
00169             if(FormManager::self()->isCreatingConnection())  {
00170                 drawConnection(mev);
00171                 return true;
00172             }
00173 
00174             if(((mev->state() == ControlButton) || (mev->state() == ShiftButton)) 
00175                 && (!FormManager::self()->isInserting())) // multiple selection mode
00176             {
00177                 if(m_form->selectedWidgets()->findRef(m_moving) != -1) // widget is already selected
00178                 {
00179                     if(m_form->selectedWidgets()->count() > 1) // we remove it from selection
00180                         unSelectWidget(m_moving);
00181                     else // the widget is the only selected, so it means we want to copy it
00182                     {
00183                         //m_copyRect = m_moving->geometry();
00184                         m_state = CopyingWidget;
00185                         if(m_form->formWidget())
00186                             m_form->formWidget()->initBuffer();
00187                     }
00188                 }
00189                 else // the widget is not yet selected, we add it
00190                     setSelectedWidget(m_moving, true, (mev->button() == RightButton));
00191             }
00192             else if((m_form->selectedWidgets()->count() > 1))//&& (!m_form->manager()->isInserting())) // more than one widget selected
00193             {
00194                 if(m_form->selectedWidgets()->findRef(m_moving) == -1) // widget is not selected, it becomes the only selected widget
00195                     setSelectedWidget(m_moving, false, (mev->button() == RightButton));
00196                 // If the widget is already selected, we do nothing (to ease widget moving, etc.)
00197             }
00198             else// if(!m_form->manager()->isInserting())
00199                 setSelectedWidget(m_moving, false, (mev->button() == RightButton));
00200 
00201             // we are inserting a widget or drawing a selection rect in the form
00202             if((/*s == m_container &&*/ FormManager::self()->isInserting()) || ((s == m_container) && !m_toplevel))
00203             {
00204                 int tmpx,tmpy;
00205                 if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (LeftButton|ControlButton|AltButton)))
00206                 {
00207                     tmpx = mev->x();
00208                     tmpy = mev->y();
00209                 }
00210                 else
00211                 {
00212                     int gridX = m_form->gridSize();
00213                     int gridY = m_form->gridSize();
00214                     tmpx = int( (float)mev->x() / ((float)gridX) + 0.5 ); // snap to grid
00215                     tmpx *= gridX;
00216                     tmpy = int( (float)mev->y() / ((float)gridY) + 0.5 );
00217                     tmpy *= gridX;
00218                 }
00219 
00220                 m_insertBegin = (static_cast<QWidget*>(s))->mapTo(m_container, QPoint(tmpx, tmpy));
00221                 if(m_form->formWidget())
00222                     m_form->formWidget()->initBuffer();
00223 
00224                 if(!FormManager::self()->isInserting())
00225                     m_state = DrawingSelectionRect;
00226             }
00227             else {
00228                 if(s->inherits("QTabWidget")) // to allow changing page by clicking tab
00229                     return false;
00230             }
00231 
00232             if (m_objectForMouseReleaseEvent) {
00233                 const bool res = handleMouseReleaseEvent(m_objectForMouseReleaseEvent, &m_mouseReleaseEvent);
00234                 m_objectForMouseReleaseEvent = 0;
00235                 return res;
00236             }
00237             return true;
00238         }
00239 
00240         case QEvent::MouseButtonRelease:
00241         {
00242             QMouseEvent *mev = static_cast<QMouseEvent*>(e);
00243             if (!m_mousePressEventReceived) {
00244                 m_mouseReleaseEvent = *mev;
00245                 m_objectForMouseReleaseEvent = s;
00246                 return true;
00247             }
00248             m_mousePressEventReceived = false;
00249             m_objectForMouseReleaseEvent = 0;
00250             return handleMouseReleaseEvent(s, mev);
00251         }
00252 
00253         case QEvent::MouseMove:
00254         {
00255             QMouseEvent *mev = static_cast<QMouseEvent*>(e);
00256             if(m_insertBegin!=QPoint(-1,-1) && FormManager::self()->isInserting() && ((mev->state() == LeftButton) || (mev->state() == (LeftButton|ControlButton)) ||
00257             (mev->state() == (LeftButton|ControlButton|AltButton)) || (mev->state() == (LeftButton|ShiftButton)) ) )
00258             // draw the insert rect
00259             {
00260                 drawInsertRect(mev, s);
00261                 return true;
00262             }
00263             // Creating a connection, we highlight sender and receiver, and we draw a link between them
00264             else if(FormManager::self()->isCreatingConnection() && !FormManager::self()->createdConnection()->sender().isNull())
00265             {
00266                 ObjectTreeItem *tree = m_form->objectTree()->lookup(FormManager::self()->createdConnection()->sender());
00267                 if(!tree || !tree->widget())
00268                     return true;
00269 
00270                 if(m_form->formWidget() && (tree->widget() != s))
00271                     m_form->formWidget()->highlightWidgets(tree->widget(), static_cast<QWidget*>(s));
00272             }
00273             else if(m_insertBegin!=QPoint(-1,-1) && s == m_container && !m_toplevel && (mev->state() != ControlButton) && !FormManager::self()->isCreatingConnection()) // draw the selection rect
00274             {
00275                 if((mev->state() != LeftButton) || /*m_inlineEditing*/ m_state == InlineEditing)
00276                     return true;
00277                 int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() :  mev->x();
00278                 int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y();
00279                 int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() :  mev->x();
00280                 int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y();
00281                 QRect r = QRect(QPoint(topx, topy), QPoint(botx, boty));
00282                 m_insertRect = r;
00283 
00284                 if(m_form->formWidget())
00285                     m_form->formWidget()->drawRect(r, 1);
00286 
00287                 m_state = DoingNothing;
00288                 return true;
00289             }
00290             else if(mev->state() == (LeftButton|ControlButton)) // draw the insert rect for the copied widget
00291             {
00292                 if(s == m_container)// || (m_form->selectedWidgets()->count() > 1))
00293                     return true;
00294                 drawCopiedWidgetRect(mev);
00295                 return true;
00296             }
00297             else if( ( (mev->state() == Qt::LeftButton) || (mev->state() == (LeftButton|ControlButton|AltButton)) )
00298               && !FormManager::self()->isInserting() && (m_state != CopyingWidget)) // we are dragging the widget(s) to move it
00299             {
00300                 if(!m_toplevel && m_moving == m_container) // no effect for form
00301                     return false;
00302                 if((!m_moving) || (!m_moving->parentWidget()))// || (m_moving->parentWidget()->inherits("QWidgetStack")))
00303                         return true;
00304 
00305                 moveSelectedWidgetsBy(mev->x() - m_grab.x(), mev->y() - m_grab.y());
00306                 m_state = MovingWidget;
00307             }
00308 
00309             return true; // eat
00310         }
00311 
00312         case QEvent::Paint: // Draw the dotted background
00313         {
00314             if(s != m_container)
00315                 return false;
00316             int gridX = m_form->gridSize();
00317             int gridY = m_form->gridSize();
00318 
00319             QPainter p(m_container);
00320             p.setPen(QPen(white, 2));
00321             p.setRasterOp(XorROP);
00322             int cols = m_container->width() / gridX;
00323             int rows = m_container->height() / gridY;
00324 
00325             for(int rowcursor = 1; rowcursor <= rows; ++rowcursor)
00326             {
00327                 for(int colcursor = 1; colcursor <= cols; ++colcursor)
00328                 {
00329                     p.drawPoint(-1 + colcursor *gridX, -1 + rowcursor *gridY);
00330                 }
00331             }
00332 
00333             return false;
00334         }
00335 
00336         case QEvent::Resize: // we are resizing a widget, so we set m_move to true -> the layout will be reloaded when releasing mouse
00337         {
00338             if(m_form->interactiveMode())
00339                 m_state = MovingWidget;
00340             break;
00341         }
00342 
00343         //case QEvent::AccelOverride:
00344         case QEvent::KeyPress:
00345         {
00346             QKeyEvent *kev = static_cast<QKeyEvent*>(e);
00347 
00348             if(kev->key() == Key_F2) // pressing F2 == double-clicking
00349             {
00350                 m_state = InlineEditing;
00351                 QWidget *w;
00352 
00353                 // try to find the widget which was clicked last and should be edited
00354                 if(m_form->selectedWidgets()->count() == 1)
00355                     w = m_form->selectedWidgets()->first();
00356                 else if(m_form->selectedWidgets()->findRef(m_moving) != -1)
00357                     w = m_moving;
00358                 else
00359                     w = m_form->selectedWidgets()->last();
00360                 m_form->library()->startEditing(w->className(), w, this);
00361             }
00362             else if(kev->key() == Key_Escape)
00363             {
00364                 if(FormManager::self()->isCreatingConnection())
00365                     FormManager::self()->stopCreatingConnection();
00366                 else if(FormManager::self()->isInserting())
00367                     FormManager::self()->stopInsert();
00368                 return true;
00369             }
00370             else if((kev->key() == Key_Control) && (m_state == MovingWidget))
00371             {
00372                 if(!m_moving)
00373                     return true;
00374                 // we simulate a mouse move event to update screen
00375                 QMouseEvent *mev = new QMouseEvent(QEvent::MouseMove, m_moving->mapFromGlobal(QCursor::pos()), NoButton,
00376                 LeftButton|ControlButton );
00377                 eventFilter(m_moving, mev);
00378                 delete mev;
00379             }
00380             else if(kev->key() == FormManager::self()->contextMenuKey())
00381             {
00382                     FormManager::self()->createContextMenu(static_cast<QWidget*>(s), this, false);
00383                     return true;
00384             }
00385             else if (kev->key() == Key_Delete)
00386             {
00387                 FormManager::self()->deleteWidget();
00388                 return true;
00389             }
00390             // directional buttons move the widget
00391             else if(kev->key() == Key_Left){ // move the widget of gridX to the left
00392                 moveSelectedWidgetsBy(-form()->gridSize(), 0);
00393                 return true;
00394             }
00395             else if(kev->key() == Key_Right){ // move the widget of gridX to the right
00396                 moveSelectedWidgetsBy(form()->gridSize(), 0);
00397                 return true;
00398             }
00399             else if(kev->key() == Key_Up){ // move the widget of gridY to the top
00400                 moveSelectedWidgetsBy(0, - form()->gridSize());
00401                 return true;
00402             }
00403             else if(kev->key() == Key_Down){ // move the widget of gridX to the bottom
00404                 moveSelectedWidgetsBy(0, form()->gridSize());
00405                 return true;
00406             }
00407             else if((kev->key() == Key_Tab) || (kev->key() == Key_BackTab)){
00408                 ObjectTreeItem *item = form()->objectTree()->lookup(form()->selectedWidgets()->first()->name());
00409                 if(!item || !item->parent())
00410                     return true;
00411                 ObjectTreeList *list = item->parent()->children();
00412                 if(list->count() == 1)
00413                     return true;
00414                 int index = list->findRef(item);
00415 
00416                 if(kev->key() == Key_BackTab){
00417                     if(index == 0) // go back to the last item
00418                         index = list->count() - 1;
00419                     else
00420                         index = index - 1;
00421                 }
00422                 else  {
00423                     if(index == int(list->count() - 1)) // go back to the first item
00424                         index = 0;
00425                     else
00426                         index = index + 1;
00427                 }
00428 
00429                 ObjectTreeItem *nextItem = list->at(index);
00430                 if(nextItem && nextItem->widget())
00431                     form()->setSelectedWidget(nextItem->widget(), false);
00432             }
00433             return true;
00434         }
00435 
00436         case QEvent::KeyRelease:
00437         {
00438             QKeyEvent *kev = static_cast<QKeyEvent*>(e);
00439             if((kev->key() == Key_Control) && (m_state == CopyingWidget)) {
00440                 // cancel copying
00441                 //m_copyRect = QRect();
00442                 if(m_form->formWidget())
00443                     m_form->formWidget()->clearForm();
00444             }
00445             return true;
00446         }
00447 
00448         case QEvent::MouseButtonDblClick: // editing
00449         {
00450             kdDebug() << "Container: Mouse dbl click for widget " << s->name() << endl;
00451             QWidget *w = static_cast<QWidget*>(s);
00452             if(!w)
00453                 return false;
00454 
00455             //m_inlineEditing = true;
00456             m_state = InlineEditing;
00457             m_form->library()->startEditing(w->className(), w, this);
00458             return true;
00459         }
00460 
00461         case QEvent::ContextMenu:
00462         case QEvent::Enter:
00463         case QEvent::Leave:
00464         case QEvent::FocusIn:
00465         case QEvent::FocusOut:
00466 //      case QEvent::DragEnter:
00467 //      case QEvent::DragMove:
00468 //      case QEvent::DragLeave:
00469             return true; // eat them
00470 
00471         default:
00472             return false; // let the widget do the rest ...
00473     }
00474     return false;
00475 }
00476 
00477 bool
00478 Container::handleMouseReleaseEvent(QObject *s, QMouseEvent *mev)
00479 {
00480     if(FormManager::self()->isInserting()) // we insert the widget at cursor pos
00481     {
00482         if(m_form->formWidget())
00483             m_form->formWidget()->clearForm();
00484         KCommand *com = new InsertWidgetCommand(this/*, mev->pos()*/);
00485         m_form->addCommand(com, true);
00486         m_insertBegin = QPoint(-1,-1);
00487         m_insertRect = QRect();
00488         return true;
00489     }
00490     else if(s == m_container && !m_toplevel && (mev->button() != RightButton) && m_insertRect.isValid()) // we are drawing a rect to select widgets
00491     {
00492         drawSelectionRect(mev);
00493         return true;
00494     }
00495     if(mev->button() == RightButton) // Right-click -> context menu
00496     {
00497         FormManager::self()->createContextMenu(static_cast<QWidget*>(s), this);
00498     }
00499     else if(mev->state() == (Qt::LeftButton|Qt::ControlButton))// && (m_copyRect.isValid()))
00500     {
00501         // copying a widget by Ctrl+dragging
00502 
00503         if(m_form->formWidget())
00504             m_form->formWidget()->clearForm();
00505         if(s == m_container) // should have no effect on form
00506             return true;
00507 
00508         // prevent accidental copying of widget (when moving mouse a little while selecting)
00509         if( ( (mev->pos().x() - m_grab.x()) < form()->gridSize() &&  (m_grab.x() - mev->pos().x()) < form()->gridSize() ) &&
00510             ( (mev->pos().y() - m_grab.y()) < form()->gridSize() &&  (m_grab.y() - mev->pos().y()) < form()->gridSize() ) )
00511         {
00512             kdDebug() << "The widget has not been moved. No copying" << endl;
00513             return true;
00514         }
00515 
00516         m_form->setInteractiveMode(false);
00517         // We simulate copy and paste
00518         FormManager::self()->copyWidget();
00519         if(m_form->selectedWidgets()->count() > 1)
00520             FormManager::self()->setInsertPoint( mev->pos() );
00521         else
00522             FormManager::self()->setInsertPoint( static_cast<QWidget*>(s)->mapTo(m_container, mev->pos() - m_grab) );
00523         FormManager::self()->pasteWidget();
00524         m_form->setInteractiveMode(true);
00525 
00526         //m_initialPos = QPoint();
00527     }
00528     else if(m_state == MovingWidget) // one widget has been moved, so we need to update the layout
00529         reloadLayout();
00530 
00531     // cancel copying as user released Ctrl before releasing mouse button
00532     m_insertBegin = QPoint(-1,-1);
00533     m_insertRect = QRect();
00534     m_state = DoingNothing;
00535     return true; // eat
00536 }
00537 
00538 void
00539 Container::setSelectedWidget(QWidget *w, bool add, bool dontRaise, bool moreWillBeSelected)
00540 {
00541     if (w)
00542         kdDebug() << "slotSelectionChanged " << w->name()<< endl;
00543 
00544     if(!w)
00545     {
00546         m_form->setSelectedWidget(m_container);
00547         return;
00548     }
00549 
00550     m_form->setSelectedWidget(w, add, dontRaise, moreWillBeSelected);
00551 }
00552 
00553 void
00554 Container::unSelectWidget(QWidget *w)
00555 {
00556     if(!w)
00557         return;
00558 
00559     m_form->unSelectWidget(w);
00560 }
00561 
00562 Container*
00563 Container::toplevel()
00564 {
00565     if(m_toplevel)
00566         return m_toplevel;
00567     else
00568         return this;
00569 }
00570 
00571 void
00572 Container::deleteWidget(QWidget *w)
00573 {
00574     if(!w)
00575         return;
00576 //  kdDebug() << "Deleting a widget: " << w->name() << endl;
00577     m_form->objectTree()->removeItem(w->name());
00578     FormManager::self()->deleteWidgetLater( w );
00579     m_form->setSelectedWidget(m_container);
00580 }
00581 
00582 void
00583 Container::widgetDeleted()
00584 {
00585     m_container = 0;
00586     deleteLater();
00587 }
00588 
00590 
00591 void
00592 Container::setLayout(LayoutType type)
00593 {
00594     if(m_layType == type)
00595         return;
00596 
00597     delete m_layout;
00598     m_layout = 0;
00599     m_layType = type;
00600 
00601     switch(type)
00602     {
00603         case HBox:
00604         {
00605             m_layout = (QLayout*) new QHBoxLayout(m_container, m_margin, m_spacing);
00606             createBoxLayout(new HorWidgetList(m_form->toplevelContainer()->widget()));
00607             break;
00608         }
00609         case VBox:
00610         {
00611             m_layout = (QLayout*) new QVBoxLayout(m_container, m_margin, m_spacing);
00612             createBoxLayout(new VerWidgetList(m_form->toplevelContainer()->widget()));
00613             break;
00614         }
00615         case Grid:
00616         {
00617             createGridLayout();
00618             break;
00619         }
00620         case  HFlow:
00621         {
00622             KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing);
00623             flow->setOrientation(Horizontal);
00624             m_layout = (QLayout*)flow;
00625             createFlowLayout();
00626             break;
00627         }
00628         case VFlow:
00629         {
00630             KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing);
00631             flow->setOrientation(Vertical);
00632             m_layout = (QLayout*)flow;
00633             createFlowLayout();
00634             break;
00635         }
00636         default:
00637         {
00638             m_layType = NoLayout;
00639             return;
00640         }
00641     }
00642     m_container->setGeometry(m_container->geometry()); // just update layout
00643     m_layout->activate();
00644 }
00645 
00646 void
00647 Container::reloadLayout()
00648 {
00649     LayoutType type = m_layType;
00650     setLayout(NoLayout);
00651     setLayout(type);
00652 }
00653 
00654 void
00655 Container::createBoxLayout(WidgetList *list)
00656 {
00657     QBoxLayout *layout = static_cast<QBoxLayout*>(m_layout);
00658 
00659     for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
00660         list->append( tree->widget());
00661     list->sort();
00662 
00663     for(QWidget *obj = list->first(); obj; obj = list->next())
00664         layout->addWidget(obj);
00665     delete list;
00666 }
00667 
00668 void
00669 Container::createFlowLayout()
00670 {
00671     KexiFlowLayout *flow = dynamic_cast<KexiFlowLayout*>(m_layout);
00672     if(!flow || m_tree->children()->isEmpty())
00673         return;
00674 
00675     const int offset = 15;
00676     WidgetList *list=0, *list2=0;
00677     if(flow->orientation() == Horizontal) {
00678         list = new VerWidgetList(m_form->toplevelContainer()->widget());
00679         list2 = new HorWidgetList(m_form->toplevelContainer()->widget());
00680     }
00681     else {
00682         list = new HorWidgetList(m_form->toplevelContainer()->widget());
00683         list2 = new VerWidgetList(m_form->toplevelContainer()->widget());
00684     }
00685 
00686     // fill the list
00687     for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
00688         list->append( tree->widget());
00689     list->sort();
00690 
00691     if(flow->orientation() == Horizontal) {
00692         int y = list->first()->y();
00693         for(QWidget *w = list->first(); w; w = list->next()) {
00694             if( (w->y() > y +offset)) {
00695                 // start a new line
00696                 list2->sort();
00697                 for(QWidget *obj = list2->first(); obj; obj = list2->next())
00698                     flow->add(obj);
00699                 list2->clear();
00700                 y = w->y();
00701             }
00702             list2->append(w);
00703         }
00704 
00705         list2->sort(); // don't forget the last line
00706         for(QWidget *obj = list2->first(); obj; obj = list2->next())
00707             flow->add(obj);
00708     }
00709     else {
00710         int x = list->first()->x();
00711         for(QWidget *w = list->first(); w; w = list->next()) {
00712             if( (w->x() > x +offset)) {
00713                 // start a new column
00714                 list2->sort();
00715                 for(QWidget *obj = list2->first(); obj; obj = list2->next())
00716                     flow->add(obj);
00717                 list2->clear();
00718                 x = w->x();
00719             }
00720             list2->append(w);
00721         }
00722 
00723         list2->sort(); // don't forget the last column
00724         for(QWidget *obj = list2->first(); obj; obj = list2->next())
00725             flow->add(obj);
00726     }
00727 
00728     delete list;
00729     delete list2;
00730 }
00731 
00732 void
00733 Container::createGridLayout(bool testOnly)
00734 {
00735     //Those lists sort widgets by y and x
00736     VerWidgetList *vlist = new VerWidgetList(m_form->toplevelContainer()->widget());
00737     HorWidgetList *hlist = new HorWidgetList(m_form->toplevelContainer()->widget());
00738     // The vector are used to store the x (or y) beginning of each column (or row)
00739     QValueVector<int> cols;
00740     QValueVector<int> rows;
00741     int end=-1000;
00742     bool same = false;
00743 
00744     for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
00745         vlist->append( tree->widget());
00746     vlist->sort();
00747 
00748     for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
00749         hlist->append( tree->widget());
00750     hlist->sort();
00751 
00752     // First we need to make sure that two widgets won't be in the same row,
00753     // ie that no widget overlap another one
00754     if(!testOnly) {
00755         for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
00756         {
00757             QWidget *w = it.current();
00758             WidgetListIterator it2 = it;
00759 
00760             for(; it2.current() != 0; ++it2) {
00761                 QWidget *nextw = it2.current();
00762                 if((w->y() >= nextw->y()) || (nextw->y() >= w->geometry().bottom()))
00763                     break;
00764 
00765                 if(!w->geometry().intersects(nextw->geometry()))
00766                     break;
00767                 // If the geometries of the two widgets intersect each other,
00768                 // we move one of the widget to the rght or bottom of the other
00769                 if((nextw->y() - w->y()) > abs(nextw->x() - w->x()))
00770                     nextw->move(nextw->x(), w->geometry().bottom()+1);
00771                 else if(nextw->x() >= w->x())
00772                     nextw->move(w->geometry().right()+1, nextw->y());
00773                 else
00774                     w->move(nextw->geometry().right()+1, nextw->y());
00775             }
00776         }
00777     }
00778 
00779     // Then we count the number of rows in the layout, and set their beginnings
00780     for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
00781     {
00782         QWidget *w = it.current();
00783         WidgetListIterator it2 = it;
00784         if(!same) { // this widget will make a new row
00785             end = w->geometry().bottom();
00786             rows.append(w->y());
00787         }
00788 
00789         // If same == true, it means we are in the same row as prev widget
00790         // (so no need to create a new column)
00791         ++it2;
00792         if(!it2.current())
00793             break;
00794 
00795         QWidget *nextw = it2.current();
00796         if(nextw->y() >= end)
00797             same = false;
00798         else {
00799             same = !(same && (nextw->y() >= w->geometry().bottom()));
00800             if(!same)
00801                 end = w->geometry().bottom();
00802         }
00803     }
00804     kdDebug() << "the new grid will have n rows: n == " << rows.size() << endl;
00805 
00806     end = -10000;
00807     same = false;
00808     // We do the same thing for the columns
00809     for(WidgetListIterator it(*hlist); it.current() != 0; ++it)
00810     {
00811         QWidget *w = it.current();
00812         WidgetListIterator it2 = it;
00813         if(!same) {
00814             end = w->geometry().right();
00815             cols.append(w->x());
00816         }
00817 
00818         ++it2;
00819         if(!it2.current())
00820             break;
00821 
00822         QWidget *nextw = it2.current();
00823         if(nextw->x() >= end)
00824             same = false;
00825         else {
00826             same = !(same && (nextw->x() >= w->geometry().right()));
00827             if(!same)
00828                 end = w->geometry().right();
00829         }
00830     }
00831     kdDebug() << "the new grid will have n columns: n == " << cols.size() << endl;
00832 
00833     // We create the layout ..
00834     QGridLayout *layout=0;
00835     if(!testOnly) {
00836         layout = new QGridLayout(m_container, rows.size(), cols.size(), m_margin, m_spacing, "grid");
00837         m_layout = (QLayout*)layout;
00838     }
00839 
00840     // .. and we fill it with widgets
00841     for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
00842     {
00843         QWidget *w = it.current();
00844         QRect r = w->geometry();
00845         uint wcol=0, wrow=0, endrow=0, endcol=0;
00846         uint i = 0;
00847 
00848         // We look for widget row(s) ..
00849         while(r.y() >= rows[i])
00850         {
00851             if(rows.size() <= i+1) // we are the last row
00852             {
00853                 wrow = i;
00854                 break;
00855             }
00856             if(r.y() < rows[i+1])
00857             {
00858                 wrow = i; // the widget will be in this row
00859                 uint j = i + 1;
00860                 // Then we check if the widget needs to span multiple rows
00861                 while(rows.size() >= j+1 && r.bottom() > rows[j])
00862                 {
00863                     endrow = j;
00864                     j++;
00865                 }
00866 
00867                 break;
00868             }
00869             i++;
00870         }
00871         //kdDebug() << "the widget " << w->name() << " wil be in the row " << wrow <<
00872            //" and will go to the row " << endrow << endl;
00873 
00874         // .. and column(s)
00875         i = 0;
00876         while(r.x() >= cols[i])
00877         {
00878             if(cols.size() <= i+1) // last column
00879             {
00880                 wcol = i;
00881                 break;
00882             }
00883             if(r.x() < cols[i+1])
00884             {
00885                 wcol = i;
00886                 uint j = i + 1;
00887                 // Then we check if the widget needs to span multiple columns
00888                 while(cols.size() >= j+1 && r.right() > cols[j])
00889                 {
00890                     endcol = j;
00891                     j++;
00892                 }
00893 
00894                 break;
00895             }
00896             i++;
00897         }
00898         //kdDebug() << "the widget " << w->name() << " wil be in the col " << wcol <<
00899          // " and will go to the col " << endcol << endl;
00900 
00901         ObjectTreeItem *item = m_form->objectTree()->lookup(w->name());
00902         if(!endrow && !endcol) {
00903             if(!testOnly)
00904                 layout->addWidget(w, wrow, wcol);
00905             item->setGridPos(wrow, wcol, 0, 0);
00906         }
00907         else {
00908             if(!endcol)  endcol = wcol;
00909             if(!endrow)  endrow = wrow;
00910             if(!testOnly)
00911                 layout->addMultiCellWidget(w, wrow, endrow, wcol, endcol);
00912             item->setGridPos(wrow, wcol, endrow-wrow+1, endcol-wcol+1);
00913         }
00914     }
00915 }
00916 
00917 QString
00918 Container::layoutTypeToString(int type)
00919 {
00920     switch(type)
00921     {
00922         case HBox: return "HBox";
00923         case VBox: return "VBox";
00924         case Grid: return "Grid";
00925         case HFlow: return "HFlow";
00926         case VFlow: return "VFlow";
00927         default:   return "NoLayout";
00928     }
00929 }
00930 
00931 Container::LayoutType
00932 Container::stringToLayoutType(const QString &name)
00933 {
00934     if(name == "HBox") return HBox;
00935     if(name == "VBox") return VBox;
00936     if(name == "Grid") return Grid;
00937     if(name == "HFlow")  return HFlow;
00938     if(name == "VFlow")  return VFlow;
00939     return NoLayout;
00940 }
00941 
00943 void
00944 Container::drawConnection(QMouseEvent *mev)
00945 {
00946     if(mev->button() != LeftButton)
00947     {
00948         FormManager::self()->resetCreatedConnection();
00949         return;
00950     }
00951     // First click, we select the sender and display menu to choose signal
00952     if(FormManager::self()->createdConnection()->sender().isNull())
00953     {
00954         FormManager::self()->createdConnection()->setSender(m_moving->name());
00955         if(m_form->formWidget())
00956         {
00957             m_form->formWidget()->initBuffer();
00958             m_form->formWidget()->highlightWidgets(m_moving, 0/*, QPoint()*/);
00959         }
00960         FormManager::self()->createSignalMenu(m_moving);
00961         return;
00962     }
00963     // the user clicked outside the menu, we cancel the connection
00964     if(FormManager::self()->createdConnection()->signal().isNull())
00965     {
00966         FormManager::self()->stopCreatingConnection();
00967         return;
00968     }
00969     // second click to choose the receiver
00970     if(FormManager::self()->createdConnection()->receiver().isNull())
00971     {
00972         FormManager::self()->createdConnection()->setReceiver(m_moving->name());
00973         FormManager::self()->createSlotMenu(m_moving);
00974         m_container->repaint();
00975         return;
00976     }
00977     // the user clicked outside the menu, we cancel the connection
00978     if(FormManager::self()->createdConnection()->slot().isNull())
00979     {
00980         FormManager::self()->stopCreatingConnection();
00981         return;
00982     }
00983 }
00984 
00985 void
00986 Container::drawSelectionRect(QMouseEvent *mev)
00987 {
00988     //finish drawing unclipped selection rectangle: clear the surface
00989     if(m_form->formWidget())
00990         m_form->formWidget()->clearForm();
00991     int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() :  mev->x();
00992     int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y();
00993     int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() :  mev->x();
00994     int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y();
00995     QRect r = QRect(QPoint(topx, topy), QPoint(botx, boty));
00996 
00997     setSelectedWidget(m_container, false);
00998     QWidget *widgetToSelect = 0;
00999     // We check which widgets are in the rect and select them
01000     for(ObjectTreeItem *item = m_tree->children()->first(); item; item = m_tree->children()->next())
01001     {
01002         QWidget *w = item->widget();
01003         if(!w)
01004             continue;
01005         if(w->geometry().intersects(r) && w != m_container) {
01006             if (widgetToSelect)
01007                 setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, true/*moreWillBeSelected*/);
01008             widgetToSelect = w; //select later
01009         }
01010     }
01011     if (widgetToSelect) //the last one left
01012         setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, false);
01013 
01014     m_insertRect = QRect();
01015     m_state = DoingNothing;
01016     m_container->repaint();
01017 }
01018 
01019 void
01020 Container::drawInsertRect(QMouseEvent *mev, QObject *s)
01021 {
01022     int tmpx, tmpy;
01023     QPoint pos = static_cast<QWidget*>(s)->mapTo(m_container, mev->pos());
01024     int gridX = m_form->gridSize();
01025     int gridY = m_form->gridSize();
01026     if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (LeftButton|ControlButton|AltButton)) )
01027     {
01028         tmpx = pos.x();
01029         tmpy = pos.y();
01030     }
01031     else
01032     {
01033         tmpx = int( (float) pos.x() / ((float)gridX) + 0.5);
01034         tmpx *= gridX;
01035         tmpy = int( (float)pos.y() / ((float)gridY) + 0.5);
01036         tmpy *= gridX;
01037     }
01038 
01039     int topx = (m_insertBegin.x() < tmpx) ? m_insertBegin.x() : tmpx;
01040     int topy = (m_insertBegin.y() < tmpy) ? m_insertBegin.y() : tmpy;
01041     int botx = (m_insertBegin.x() > tmpx) ? m_insertBegin.x() : tmpx;
01042     int boty = (m_insertBegin.y() > tmpy) ? m_insertBegin.y() : tmpy;
01043     m_insertRect = QRect(QPoint(topx, topy), QPoint(botx, boty));
01044 
01045     if(m_insertRect.x() < 0)
01046         m_insertRect.setLeft(0);
01047     if(m_insertRect.y() < 0)
01048         m_insertRect.setTop(0);
01049     if(m_insertRect.right() > m_container->width())
01050         m_insertRect.setRight(m_container->width());
01051     if(m_insertRect.bottom() > m_container->height())
01052         m_insertRect.setBottom(m_container->height());
01053 
01054     if(FormManager::self()->isInserting() && m_insertRect.isValid())
01055     {
01056         if(m_form->formWidget())
01057         {
01058             QRect drawRect = QRect(m_container->mapTo(m_form->widget(), m_insertRect.topLeft())
01059                 , m_insertRect.size());
01060             m_form->formWidget()->drawRect(drawRect, 2);
01061         }
01062     }
01063 }
01064 
01065 void
01066 Container::drawCopiedWidgetRect(QMouseEvent *mev)
01067 {
01068     // We've been dragging a widget, but Ctrl was hold, so we start copy
01069     if(m_state == MovingWidget)  {
01070         //FormManager::self()->undo(); // undo last moving
01071         //m_moving->move(m_initialPos);
01072         if(m_form->formWidget())  {
01073             m_container->repaint();
01074             m_form->formWidget()->initBuffer();
01075         }
01076         m_state = CopyingWidget;
01077     }
01078 
01079     //m_copyRect.moveTopLeft(m_container->mapFromGlobal( mev->globalPos()) - m_grab);
01080 
01081     if(m_form->formWidget())  {
01082         QValueList<QRect> rectList;
01083         for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next()) {
01084             QRect drawRect = w->geometry();
01085             QPoint p = mev->pos() - m_grab;
01086             drawRect.moveBy(p.x(), p.y());
01087             p = m_container->mapTo(m_form->widget(), QPoint(0, 0));
01088             //drawRect = QRect( ((QWidget*)s)->mapTo(m_form->widget(), drawRect.topLeft()), drawRect.size());
01089             drawRect.moveBy(p.x(), p.y());
01090             rectList.append(drawRect);
01091         }
01092 
01093         m_form->formWidget()->drawRects(rectList, 2);
01094     }
01095 }
01096 
01098 void
01099 Container::moveSelectedWidgetsBy(int realdx, int realdy, QMouseEvent *mev)
01100 {
01101     if (m_form->selectedWidget() == m_form->widget())
01102         return; //do not move top-level widget
01103 
01104     const int gridX = m_form->gridSize();
01105     const int gridY = m_form->gridSize();
01106     int dx=realdx, dy=realdy;
01107 
01108     for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next())
01109     {
01110         if(!w || !w->parent() || w->parent()->inherits("QTabWidget") || w->parent()->inherits("QWidgetStack"))
01111             continue;
01112 
01113         if(w->parentWidget() && w->parentWidget()->isA("QWidgetStack"))
01114         {
01115             w = w->parentWidget(); // widget is WidgetStack page
01116             if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) // widget is tabwidget page
01117                 w = w->parentWidget();
01118         }
01119 
01120         int tmpx = w->x() + realdx;
01121         int tmpy = w->y() + realdy;
01122         if(tmpx < 0)
01123             dx = QMAX(0 - w->x(), dx); // because dx is <0
01124         else if(tmpx > w->parentWidget()->width() - gridX)
01125             dx = QMIN(w->parentWidget()->width() - gridX - w->x(), dx);
01126 
01127         if(tmpy < 0)
01128             dy = QMAX(0 - w->y(), dy); // because dy is <0
01129         else if(tmpy > w->parentWidget()->height() - gridY)
01130             dy = QMIN(w->parentWidget()->height() - gridY - w->y(), dy);
01131     }
01132 
01133     for(QWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next())
01134     {
01135         // Don't move tab widget pages (or widget stack pages)
01136         if(!w || !w->parent() || w->parent()->inherits("QTabWidget") || w->parent()->inherits("QWidgetStack"))
01137             continue;
01138 
01139         if(w->parentWidget() && w->parentWidget()->isA("QWidgetStack"))
01140         {
01141             w = w->parentWidget(); // widget is WidgetStack page
01142             if(w->parentWidget() && w->parentWidget()->inherits("QTabWidget")) // widget is tabwidget page
01143                 w = w->parentWidget();
01144         }
01145 
01146         int tmpx, tmpy;
01147         if(!FormManager::self()->snapWidgetsToGrid() || (mev && mev->state() == (LeftButton|ControlButton|AltButton)) )
01148         {
01149             tmpx = w->x() + dx;
01150             tmpy = w->y() + dy;
01151         }
01152         else
01153         {
01154             tmpx = int( float( w->x() + dx) / float(gridX) + 0.5) * gridX;
01155             tmpy = int( float( w->y() + dy) / float(gridY) + 0.5) * gridY;
01156         }
01157 
01158         if((tmpx != w->x()) || (tmpy != w->y()))
01159             w->move(tmpx,tmpy);
01160     }
01161 }
01162 
01164 
01165 DesignTimeDynamicChildWidgetHandler::DesignTimeDynamicChildWidgetHandler()
01166  : m_item(0)
01167 {
01168 }
01169 
01170 DesignTimeDynamicChildWidgetHandler::~DesignTimeDynamicChildWidgetHandler()
01171 {
01172 }
01173 
01174 void
01175 DesignTimeDynamicChildWidgetHandler::childWidgetAdded(QWidget* w)
01176 {
01177     if (m_item) {
01178         installRecursiveEventFilter(w, m_item->eventEater());
01179     }
01180 }
01181 
01182 #include "container.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys