kexi

container.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
3 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <tqpainter.h>
22#include <tqpixmap.h>
23#include <tqrect.h>
24#include <tqevent.h>
25#include <tqvaluevector.h>
26#include <tqlayout.h>
27#include <tqcursor.h>
28
29#include <kdebug.h>
30#include <tdelocale.h>
31#include <tdepopupmenu.h>
32
33#include <cstdlib> // for abs()
34
35#include "utils.h"
36#include "container.h"
37#include "widgetlibrary.h"
38#include "objecttree.h"
39#include "form.h"
40#include "formmanager.h"
41#include "commands.h"
42#include "events.h"
43#include "kexiflowlayout.h"
44
45using namespace KFormDesigner;
46
47EventEater::EventEater(TQWidget *widget, TQObject *container)
48 : TQObject(container)
49{
50 m_widget = widget;
51 m_container = container;
52
53 installRecursiveEventFilter(m_widget, this);
54}
55
56bool
57EventEater::eventFilter(TQObject *, TQEvent *ev)
58{
59 if(!m_container)
60 return false;
61
62 // When the user click the empty part of tab bar, only MouseReleaseEvent is sent,
63 // we need to simulate the Press event
64 if(ev->type() == TQEvent::MouseButtonRelease && m_widget->inherits("TQTabWidget"))
65 {
66 TQMouseEvent *mev = static_cast<TQMouseEvent*>(ev);
67 if(mev->button() == TQt::LeftButton)
68 {
69 TQMouseEvent *myev = new TQMouseEvent(TQEvent::MouseButtonPress, mev->pos(), mev->button(), mev->state());
70 m_container->eventFilter(m_widget, myev);
71 delete myev;
72 //return true;
73 }
74 }
75// else if(ev->type() == TQEvent::ChildInserted) {
76 // widget's children have changed, we need to reinstall filter
77// installRecursiveEventFilter(m_widget, this);
78// }
79
80 return m_container->eventFilter(m_widget, ev);
81}
82
83EventEater::~EventEater()
84{
85 if(m_widget)
86 removeRecursiveEventFilter(m_widget, this);
87}
88
89// Container itself
90
91Container::Container(Container *toplevel, TQWidget *container, TQObject *parent, const char *name)
92: TQObject(parent, name)
93, m_insertBegin(-1,-1)
94, m_mousePressEventReceived(false)
95, m_mouseReleaseEvent(TQEvent::None, TQPoint(), 0, 0)
96{
97 m_container = container;
98 m_toplevel = toplevel;
99
100 m_moving = 0;
101 m_tree = 0;
102 m_form = toplevel ? toplevel->form() : 0;
103 m_layout = 0;
104 m_layType = NoLayout;
105 m_state = DoingNothing;
106
107 TQCString classname = container->className();
108 if((classname == "HBox") || (classname == "Grid") || (classname == "VBox") ||
109 (classname == "HFlow") || (classname == "VFlow"))
110 m_margin = 4; // those containers don't have frames, so little margin
111 else
112 m_margin = m_form ? m_form->defaultMargin() : 0;
113 m_spacing = m_form ? m_form->defaultSpacing() : 0;
114
115 if(toplevel)
116 {
117 ObjectTreeItem *it = new ObjectTreeItem(m_form->library()->displayName(classname),
118 widget()->name(), widget(), this, this);
119 setObjectTree(it);
120
121 if(parent->isWidgetType())
122 {
123 TQString n = parent->name();
124 ObjectTreeItem *parent = m_form->objectTree()->lookup(n);
125 m_form->objectTree()->addItem(parent, it);
126 }
127 else
128 m_form->objectTree()->addItem(toplevel->objectTree(), it);
129
130 connect(toplevel, TQ_SIGNAL(destroyed()), this, TQ_SLOT(widgetDeleted()));
131 }
132
133 connect(container, TQ_SIGNAL(destroyed()), this, TQ_SLOT(widgetDeleted()));
134}
135
136Container::~Container()
137{
138 kdDebug() << " Container being deleted this == " << name() << endl;
139}
140
141void
143{
144 m_form = form;
145 m_margin = m_form ? m_form->defaultMargin() : 0;
146 m_spacing = m_form ? m_form->defaultSpacing() : 0;
147}
148
149bool
150Container::eventFilter(TQObject *s, TQEvent *e)
151{
152// kdDebug() << e->type() << endl;
153 switch(e->type())
154 {
155 case TQEvent::MouseButtonPress:
156 {
157 m_insertBegin = TQPoint(-1, -1);
158 m_mousePressEventReceived = true;
159
160 kdDebug() << "TQEvent::MouseButtonPress sender object = " << s->name()
161 << "of type " << s->className() << endl;
162 kdDebug() << "TQEvent::MouseButtonPress this = " << name() << endl;
163
164 m_moving = static_cast<TQWidget*>(s);
165 TQMouseEvent *mev = static_cast<TQMouseEvent*>(e);
166 m_grab = TQPoint(mev->x(), mev->y());
167
168 // we are drawing a connection
169 if(FormManager::self()->isCreatingConnection()) {
170 drawConnection(mev);
171 return true;
172 }
173
174 if(((mev->state() == TQt::ControlButton) || (mev->state() == TQt::ShiftButton))
175 && (!FormManager::self()->isInserting())) // multiple selection mode
176 {
177 if(m_form->selectedWidgets()->findRef(m_moving) != -1) // widget is already selected
178 {
179 if(m_form->selectedWidgets()->count() > 1) // we remove it from selection
180 unSelectWidget(m_moving);
181 else // the widget is the only selected, so it means we want to copy it
182 {
183 //m_copyRect = m_moving->geometry();
184 m_state = CopyingWidget;
185 if(m_form->formWidget())
186 m_form->formWidget()->initBuffer();
187 }
188 }
189 else // the widget is not yet selected, we add it
190 setSelectedWidget(m_moving, true, (mev->button() == TQt::RightButton));
191 }
192 else if((m_form->selectedWidgets()->count() > 1))//&& (!m_form->manager()->isInserting())) // more than one widget selected
193 {
194 if(m_form->selectedWidgets()->findRef(m_moving) == -1) // widget is not selected, it becomes the only selected widget
195 setSelectedWidget(m_moving, false, (mev->button() == TQt::RightButton));
196 // If the widget is already selected, we do nothing (to ease widget moving, etc.)
197 }
198 else// if(!m_form->manager()->isInserting())
199 setSelectedWidget(m_moving, false, (mev->button() == TQt::RightButton));
200
201 // we are inserting a widget or drawing a selection rect in the form
202 if((/*s == m_container &&*/ FormManager::self()->isInserting()) || ((s == m_container) && !m_toplevel))
203 {
204 int tmpx,tmpy;
205 if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (TQt::LeftButton|TQt::ControlButton|TQt::AltButton)))
206 {
207 tmpx = mev->x();
208 tmpy = mev->y();
209 }
210 else
211 {
212 int gridX = m_form->gridSize();
213 int gridY = m_form->gridSize();
214 tmpx = int( (float)mev->x() / ((float)gridX) + 0.5 ); // snap to grid
215 tmpx *= gridX;
216 tmpy = int( (float)mev->y() / ((float)gridY) + 0.5 );
217 tmpy *= gridX;
218 }
219
220 m_insertBegin = (static_cast<TQWidget*>(s))->mapTo(m_container, TQPoint(tmpx, tmpy));
221 if(m_form->formWidget())
222 m_form->formWidget()->initBuffer();
223
224 if(!FormManager::self()->isInserting())
225 m_state = DrawingSelectionRect;
226 }
227 else {
228 if(s->inherits("TQTabWidget")) // to allow changing page by clicking tab
229 return false;
230 }
231
232 if (m_objectForMouseReleaseEvent) {
233 const bool res = handleMouseReleaseEvent(m_objectForMouseReleaseEvent, &m_mouseReleaseEvent);
234 m_objectForMouseReleaseEvent = 0;
235 return res;
236 }
237 return true;
238 }
239
240 case TQEvent::MouseButtonRelease:
241 {
242 TQMouseEvent *mev = static_cast<TQMouseEvent*>(e);
243 if (!m_mousePressEventReceived) {
244 m_mouseReleaseEvent = *mev;
245 m_objectForMouseReleaseEvent = s;
246 return true;
247 }
248 m_mousePressEventReceived = false;
249 m_objectForMouseReleaseEvent = 0;
250 return handleMouseReleaseEvent(s, mev);
251 }
252
253 case TQEvent::MouseMove:
254 {
255 TQMouseEvent *mev = static_cast<TQMouseEvent*>(e);
256 if(m_insertBegin!=TQPoint(-1,-1) && FormManager::self()->isInserting() && ((mev->state() == TQt::LeftButton) || (mev->state() == (TQt::LeftButton|TQt::ControlButton)) ||
257 (mev->state() == (TQt::LeftButton|TQt::ControlButton|TQt::AltButton)) || (mev->state() == (TQt::LeftButton|TQt::ShiftButton)) ) )
258 // draw the insert rect
259 {
260 drawInsertRect(mev, s);
261 return true;
262 }
263 // Creating a connection, we highlight sender and receiver, and we draw a link between them
264 else if(FormManager::self()->isCreatingConnection() && !FormManager::self()->createdConnection()->sender().isNull())
265 {
266 ObjectTreeItem *tree = m_form->objectTree()->lookup(FormManager::self()->createdConnection()->sender());
267 if(!tree || !tree->widget())
268 return true;
269
270 if(m_form->formWidget() && (tree->widget() != s))
271 m_form->formWidget()->highlightWidgets(tree->widget(), static_cast<TQWidget*>(s));
272 }
273 else if(m_insertBegin!=TQPoint(-1,-1) && s == m_container && !m_toplevel && (mev->state() != TQt::ControlButton) && !FormManager::self()->isCreatingConnection()) // draw the selection rect
274 {
275 if((mev->state() != TQt::LeftButton) || /*m_inlineEditing*/ m_state == InlineEditing)
276 return true;
277 int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() : mev->x();
278 int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y();
279 int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() : mev->x();
280 int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y();
281 TQRect r = TQRect(TQPoint(topx, topy), TQPoint(botx, boty));
282 m_insertRect = r;
283
284 if(m_form->formWidget())
285 m_form->formWidget()->drawRect(r, 1);
286
287 m_state = DoingNothing;
288 return true;
289 }
290 else if(mev->state() == (TQt::LeftButton|TQt::ControlButton)) // draw the insert rect for the copied widget
291 {
292 if(s == m_container)// || (m_form->selectedWidgets()->count() > 1))
293 return true;
294 drawCopiedWidgetRect(mev);
295 return true;
296 }
297 else if( ( (mev->state() == TQt::LeftButton) || (mev->state() == (TQt::LeftButton|TQt::ControlButton|TQt::AltButton)) )
298 && !FormManager::self()->isInserting() && (m_state != CopyingWidget)) // we are dragging the widget(s) to move it
299 {
300 if(!m_toplevel && m_moving == m_container) // no effect for form
301 return false;
302 if((!m_moving) || (!m_moving->parentWidget()))// || (m_moving->parentWidget()->inherits("TQWidgetStack")))
303 return true;
304
305 moveSelectedWidgetsBy(mev->x() - m_grab.x(), mev->y() - m_grab.y());
306 m_state = MovingWidget;
307 }
308
309 return true; // eat
310 }
311
312 case TQEvent::Paint: // Draw the dotted background
313 {
314 if(s != m_container)
315 return false;
316 int gridX = m_form->gridSize();
317 int gridY = m_form->gridSize();
318
319 TQPainter p(m_container);
320 p.setPen(TQPen(white, 2));
321 p.setRasterOp(XorROP);
322 int cols = m_container->width() / gridX;
323 int rows = m_container->height() / gridY;
324
325 for(int rowcursor = 1; rowcursor <= rows; ++rowcursor)
326 {
327 for(int colcursor = 1; colcursor <= cols; ++colcursor)
328 {
329 p.drawPoint(-1 + colcursor *gridX, -1 + rowcursor *gridY);
330 }
331 }
332
333 return false;
334 }
335
336 case TQEvent::Resize: // we are resizing a widget, so we set m_move to true -> the layout will be reloaded when releasing mouse
337 {
338 if(m_form->interactiveMode())
339 m_state = MovingWidget;
340 break;
341 }
342
343 //case TQEvent::AccelOverride:
344 case TQEvent::KeyPress:
345 {
346 TQKeyEvent *kev = static_cast<TQKeyEvent*>(e);
347
348 if(kev->key() == Key_F2) // pressing F2 == double-clicking
349 {
350 m_state = InlineEditing;
351 TQWidget *w;
352
353 // try to find the widget which was clicked last and should be edited
354 if(m_form->selectedWidgets()->count() == 1)
355 w = m_form->selectedWidgets()->first();
356 else if(m_form->selectedWidgets()->findRef(m_moving) != -1)
357 w = m_moving;
358 else
359 w = m_form->selectedWidgets()->last();
360 m_form->library()->startEditing(w->className(), w, this);
361 }
362 else if(kev->key() == Key_Escape)
363 {
364 if(FormManager::self()->isCreatingConnection())
366 else if(FormManager::self()->isInserting())
368 return true;
369 }
370 else if((kev->key() == Key_Control) && (m_state == MovingWidget))
371 {
372 if(!m_moving)
373 return true;
374 // we simulate a mouse move event to update screen
375 TQMouseEvent *mev = new TQMouseEvent(TQEvent::MouseMove, m_moving->mapFromGlobal(TQCursor::pos()), TQt::NoButton,
376 TQt::LeftButton|TQt::ControlButton );
377 eventFilter(m_moving, mev);
378 delete mev;
379 }
380 else if(kev->key() == FormManager::self()->contextMenuKey())
381 {
382 FormManager::self()->createContextMenu(static_cast<TQWidget*>(s), this, false);
383 return true;
384 }
385 else if (kev->key() == Key_Delete)
386 {
388 return true;
389 }
390 // directional buttons move the widget
391 else if(kev->key() == Key_Left){ // move the widget of gridX to the left
392 moveSelectedWidgetsBy(-form()->gridSize(), 0);
393 return true;
394 }
395 else if(kev->key() == Key_Right){ // move the widget of gridX to the right
396 moveSelectedWidgetsBy(form()->gridSize(), 0);
397 return true;
398 }
399 else if(kev->key() == Key_Up){ // move the widget of gridY to the top
400 moveSelectedWidgetsBy(0, - form()->gridSize());
401 return true;
402 }
403 else if(kev->key() == Key_Down){ // move the widget of gridX to the bottom
404 moveSelectedWidgetsBy(0, form()->gridSize());
405 return true;
406 }
407 else if((kev->key() == Key_Tab) || (kev->key() == Key_BackTab)){
408 ObjectTreeItem *item = form()->objectTree()->lookup(form()->selectedWidgets()->first()->name());
409 if(!item || !item->parent())
410 return true;
411 ObjectTreeList *list = item->parent()->children();
412 if(list->count() == 1)
413 return true;
414 int index = list->findRef(item);
415
416 if(kev->key() == Key_BackTab){
417 if(index == 0) // go back to the last item
418 index = list->count() - 1;
419 else
420 index = index - 1;
421 }
422 else {
423 if(index == int(list->count() - 1)) // go back to the first item
424 index = 0;
425 else
426 index = index + 1;
427 }
428
429 ObjectTreeItem *nextItem = list->at(index);
430 if(nextItem && nextItem->widget())
431 form()->setSelectedWidget(nextItem->widget(), false);
432 }
433 return true;
434 }
435
436 case TQEvent::KeyRelease:
437 {
438 TQKeyEvent *kev = static_cast<TQKeyEvent*>(e);
439 if((kev->key() == Key_Control) && (m_state == CopyingWidget)) {
440 // cancel copying
441 //m_copyRect = TQRect();
442 if(m_form->formWidget())
443 m_form->formWidget()->clearForm();
444 }
445 return true;
446 }
447
448 case TQEvent::MouseButtonDblClick: // editing
449 {
450 kdDebug() << "Container: Mouse dbl click for widget " << s->name() << endl;
451 TQWidget *w = static_cast<TQWidget*>(s);
452 if(!w)
453 return false;
454
455 //m_inlineEditing = true;
456 m_state = InlineEditing;
457 m_form->library()->startEditing(w->className(), w, this);
458 return true;
459 }
460
461 case TQEvent::ContextMenu:
462 case TQEvent::Enter:
463 case TQEvent::Leave:
464 case TQEvent::FocusIn:
465 case TQEvent::FocusOut:
466// case TQEvent::DragEnter:
467// case TQEvent::DragMove:
468// case TQEvent::DragLeave:
469 return true; // eat them
470
471 default:
472 return false; // let the widget do the rest ...
473 }
474 return false;
475}
476
477bool
478Container::handleMouseReleaseEvent(TQObject *s, TQMouseEvent *mev)
479{
480 if(FormManager::self()->isInserting()) // we insert the widget at cursor pos
481 {
482 if(m_form->formWidget())
483 m_form->formWidget()->clearForm();
484 KCommand *com = new InsertWidgetCommand(this/*, mev->pos()*/);
485 m_form->addCommand(com, true);
486 m_insertBegin = TQPoint(-1,-1);
487 m_insertRect = TQRect();
488 return true;
489 }
490 else if(s == m_container && !m_toplevel && (mev->button() != TQt::RightButton) && m_insertRect.isValid()) // we are drawing a rect to select widgets
491 {
493 return true;
494 }
495 if(mev->button() == TQt::RightButton) // Right-click -> context menu
496 {
497 FormManager::self()->createContextMenu(static_cast<TQWidget*>(s), this);
498 }
499 else if(mev->state() == (TQt::LeftButton|TQt::ControlButton))// && (m_copyRect.isValid()))
500 {
501 // copying a widget by Ctrl+dragging
502
503 if(m_form->formWidget())
504 m_form->formWidget()->clearForm();
505 if(s == m_container) // should have no effect on form
506 return true;
507
508 // prevent accidental copying of widget (when moving mouse a little while selecting)
509 if( ( (mev->pos().x() - m_grab.x()) < form()->gridSize() && (m_grab.x() - mev->pos().x()) < form()->gridSize() ) &&
510 ( (mev->pos().y() - m_grab.y()) < form()->gridSize() && (m_grab.y() - mev->pos().y()) < form()->gridSize() ) )
511 {
512 kdDebug() << "The widget has not been moved. No copying" << endl;
513 return true;
514 }
515
516 m_form->setInteractiveMode(false);
517 // We simulate copy and paste
519 if(m_form->selectedWidgets()->count() > 1)
520 FormManager::self()->setInsertPoint( mev->pos() );
521 else
522 FormManager::self()->setInsertPoint( static_cast<TQWidget*>(s)->mapTo(m_container, mev->pos() - m_grab) );
524 m_form->setInteractiveMode(true);
525
526 //m_initialPos = TQPoint();
527 }
528 else if(m_state == MovingWidget) // one widget has been moved, so we need to update the layout
529 reloadLayout();
530
531 // cancel copying as user released Ctrl before releasing mouse button
532 m_insertBegin = TQPoint(-1,-1);
533 m_insertRect = TQRect();
534 m_state = DoingNothing;
535 return true; // eat
536}
537
538void
539Container::setSelectedWidget(TQWidget *w, bool add, bool dontRaise, bool moreWillBeSelected)
540{
541 if (w)
542 kdDebug() << "slotSelectionChanged " << w->name()<< endl;
543
544 if(!w)
545 {
546 m_form->setSelectedWidget(m_container);
547 return;
548 }
549
550 m_form->setSelectedWidget(w, add, dontRaise, moreWillBeSelected);
551}
552
553void
555{
556 if(!w)
557 return;
558
559 m_form->unSelectWidget(w);
560}
561
564{
565 if(m_toplevel)
566 return m_toplevel;
567 else
568 return this;
569}
570
571void
573{
574 if(!w)
575 return;
576// kdDebug() << "Deleting a widget: " << w->name() << endl;
577 m_form->objectTree()->removeItem(w->name());
579 m_form->setSelectedWidget(m_container);
580}
581
582void
584{
585 m_container = 0;
586 deleteLater();
587}
588
590
591void
592Container::setLayout(LayoutType type)
593{
594 if(m_layType == type)
595 return;
596
597 delete m_layout;
598 m_layout = 0;
599 m_layType = type;
600
601 switch(type)
602 {
603 case HBox:
604 {
605 m_layout = (TQLayout*) new TQHBoxLayout(m_container, m_margin, m_spacing);
606 createBoxLayout(new HorWidgetList(m_form->toplevelContainer()->widget()));
607 break;
608 }
609 case VBox:
610 {
611 m_layout = (TQLayout*) new TQVBoxLayout(m_container, m_margin, m_spacing);
612 createBoxLayout(new VerWidgetList(m_form->toplevelContainer()->widget()));
613 break;
614 }
615 case Grid:
616 {
618 break;
619 }
620 case HFlow:
621 {
622 KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing);
623 flow->setOrientation(TQt::Horizontal);
624 m_layout = (TQLayout*)flow;
626 break;
627 }
628 case VFlow:
629 {
630 KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing);
631 flow->setOrientation(TQt::Vertical);
632 m_layout = (TQLayout*)flow;
634 break;
635 }
636 default:
637 {
638 m_layType = NoLayout;
639 return;
640 }
641 }
642 m_container->setGeometry(m_container->geometry()); // just update layout
643 m_layout->activate();
644}
645
646void
648{
649 LayoutType type = m_layType;
650 setLayout(NoLayout);
651 setLayout(type);
652}
653
654void
656{
657 TQBoxLayout *layout = static_cast<TQBoxLayout*>(m_layout);
658
659 for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
660 list->append( tree->widget());
661 list->sort();
662
663 for(TQWidget *obj = list->first(); obj; obj = list->next())
664 layout->addWidget(obj);
665 delete list;
666}
667
668void
670{
671 KexiFlowLayout *flow = dynamic_cast<KexiFlowLayout*>(m_layout);
672 if(!flow || m_tree->children()->isEmpty())
673 return;
674
675 const int offset = 15;
676 WidgetList *list=0, *list2=0;
677 if(flow->orientation() ==TQt::Horizontal) {
678 list = new VerWidgetList(m_form->toplevelContainer()->widget());
679 list2 = new HorWidgetList(m_form->toplevelContainer()->widget());
680 }
681 else {
682 list = new HorWidgetList(m_form->toplevelContainer()->widget());
683 list2 = new VerWidgetList(m_form->toplevelContainer()->widget());
684 }
685
686 // fill the list
687 for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
688 list->append( tree->widget());
689 list->sort();
690
691 if(flow->orientation() ==TQt::Horizontal) {
692 int y = list->first()->y();
693 for(TQWidget *w = list->first(); w; w = list->next()) {
694 if( (w->y() > y +offset)) {
695 // start a new line
696 list2->sort();
697 for(TQWidget *obj = list2->first(); obj; obj = list2->next())
698 flow->add(obj);
699 list2->clear();
700 y = w->y();
701 }
702 list2->append(w);
703 }
704
705 list2->sort(); // don't forget the last line
706 for(TQWidget *obj = list2->first(); obj; obj = list2->next())
707 flow->add(obj);
708 }
709 else {
710 int x = list->first()->x();
711 for(TQWidget *w = list->first(); w; w = list->next()) {
712 if( (w->x() > x +offset)) {
713 // start a new column
714 list2->sort();
715 for(TQWidget *obj = list2->first(); obj; obj = list2->next())
716 flow->add(obj);
717 list2->clear();
718 x = w->x();
719 }
720 list2->append(w);
721 }
722
723 list2->sort(); // don't forget the last column
724 for(TQWidget *obj = list2->first(); obj; obj = list2->next())
725 flow->add(obj);
726 }
727
728 delete list;
729 delete list2;
730}
731
732void
734{
735 //Those lists sort widgets by y and x
736 VerWidgetList *vlist = new VerWidgetList(m_form->toplevelContainer()->widget());
737 HorWidgetList *hlist = new HorWidgetList(m_form->toplevelContainer()->widget());
738 // The vector are used to store the x (or y) beginning of each column (or row)
739 TQValueVector<int> cols;
740 TQValueVector<int> rows;
741 int end=-1000;
742 bool same = false;
743
744 for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
745 vlist->append( tree->widget());
746 vlist->sort();
747
748 for(ObjectTreeItem *tree = m_tree->children()->first(); tree; tree = m_tree->children()->next())
749 hlist->append( tree->widget());
750 hlist->sort();
751
752 // First we need to make sure that two widgets won't be in the same row,
753 // ie that no widget overlap another one
754 if(!testOnly) {
755 for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
756 {
757 TQWidget *w = it.current();
758 WidgetListIterator it2 = it;
759
760 for(; it2.current() != 0; ++it2) {
761 TQWidget *nextw = it2.current();
762 if((w->y() >= nextw->y()) || (nextw->y() >= w->geometry().bottom()))
763 break;
764
765 if(!w->geometry().intersects(nextw->geometry()))
766 break;
767 // If the geometries of the two widgets intersect each other,
768 // we move one of the widget to the rght or bottom of the other
769 if((nextw->y() - w->y()) > abs(nextw->x() - w->x()))
770 nextw->move(nextw->x(), w->geometry().bottom()+1);
771 else if(nextw->x() >= w->x())
772 nextw->move(w->geometry().right()+1, nextw->y());
773 else
774 w->move(nextw->geometry().right()+1, nextw->y());
775 }
776 }
777 }
778
779 // Then we count the number of rows in the layout, and set their beginnings
780 for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
781 {
782 TQWidget *w = it.current();
783 WidgetListIterator it2 = it;
784 if(!same) { // this widget will make a new row
785 end = w->geometry().bottom();
786 rows.append(w->y());
787 }
788
789 // If same == true, it means we are in the same row as prev widget
790 // (so no need to create a new column)
791 ++it2;
792 if(!it2.current())
793 break;
794
795 TQWidget *nextw = it2.current();
796 if(nextw->y() >= end)
797 same = false;
798 else {
799 same = !(same && (nextw->y() >= w->geometry().bottom()));
800 if(!same)
801 end = w->geometry().bottom();
802 }
803 }
804 kdDebug() << "the new grid will have n rows: n == " << rows.size() << endl;
805
806 end = -10000;
807 same = false;
808 // We do the same thing for the columns
809 for(WidgetListIterator it(*hlist); it.current() != 0; ++it)
810 {
811 TQWidget *w = it.current();
812 WidgetListIterator it2 = it;
813 if(!same) {
814 end = w->geometry().right();
815 cols.append(w->x());
816 }
817
818 ++it2;
819 if(!it2.current())
820 break;
821
822 TQWidget *nextw = it2.current();
823 if(nextw->x() >= end)
824 same = false;
825 else {
826 same = !(same && (nextw->x() >= w->geometry().right()));
827 if(!same)
828 end = w->geometry().right();
829 }
830 }
831 kdDebug() << "the new grid will have n columns: n == " << cols.size() << endl;
832
833 // We create the layout ..
834 TQGridLayout *layout=0;
835 if(!testOnly) {
836 layout = new TQGridLayout(m_container, rows.size(), cols.size(), m_margin, m_spacing, "grid");
837 m_layout = (TQLayout*)layout;
838 }
839
840 // .. and we fill it with widgets
841 for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
842 {
843 TQWidget *w = it.current();
844 TQRect r = w->geometry();
845 uint wcol=0, wrow=0, endrow=0, endcol=0;
846 uint i = 0;
847
848 // We look for widget row(s) ..
849 while(r.y() >= rows[i])
850 {
851 if(rows.size() <= i+1) // we are the last row
852 {
853 wrow = i;
854 break;
855 }
856 if(r.y() < rows[i+1])
857 {
858 wrow = i; // the widget will be in this row
859 uint j = i + 1;
860 // Then we check if the widget needs to span multiple rows
861 while(rows.size() >= j+1 && r.bottom() > rows[j])
862 {
863 endrow = j;
864 j++;
865 }
866
867 break;
868 }
869 i++;
870 }
871 //kdDebug() << "the widget " << w->name() << " wil be in the row " << wrow <<
872 //" and will go to the row " << endrow << endl;
873
874 // .. and column(s)
875 i = 0;
876 while(r.x() >= cols[i])
877 {
878 if(cols.size() <= i+1) // last column
879 {
880 wcol = i;
881 break;
882 }
883 if(r.x() < cols[i+1])
884 {
885 wcol = i;
886 uint j = i + 1;
887 // Then we check if the widget needs to span multiple columns
888 while(cols.size() >= j+1 && r.right() > cols[j])
889 {
890 endcol = j;
891 j++;
892 }
893
894 break;
895 }
896 i++;
897 }
898 //kdDebug() << "the widget " << w->name() << " wil be in the col " << wcol <<
899 // " and will go to the col " << endcol << endl;
900
901 ObjectTreeItem *item = m_form->objectTree()->lookup(w->name());
902 if(!endrow && !endcol) {
903 if(!testOnly)
904 layout->addWidget(w, wrow, wcol);
905 item->setGridPos(wrow, wcol, 0, 0);
906 }
907 else {
908 if(!endcol) endcol = wcol;
909 if(!endrow) endrow = wrow;
910 if(!testOnly)
911 layout->addMultiCellWidget(w, wrow, endrow, wcol, endcol);
912 item->setGridPos(wrow, wcol, endrow-wrow+1, endcol-wcol+1);
913 }
914 }
915}
916
917TQString
919{
920 switch(type)
921 {
922 case HBox: return "HBox";
923 case VBox: return "VBox";
924 case Grid: return "Grid";
925 case HFlow: return "HFlow";
926 case VFlow: return "VFlow";
927 default: return "NoLayout";
928 }
929}
930
931Container::LayoutType
932Container::stringToLayoutType(const TQString &name)
933{
934 if(name == "HBox") return HBox;
935 if(name == "VBox") return VBox;
936 if(name == "Grid") return Grid;
937 if(name == "HFlow") return HFlow;
938 if(name == "VFlow") return VFlow;
939 return NoLayout;
940}
941
943void
945{
946 if(mev->button() != TQt::LeftButton)
947 {
949 return;
950 }
951 // First click, we select the sender and display menu to choose signal
952 if(FormManager::self()->createdConnection()->sender().isNull())
953 {
954 FormManager::self()->createdConnection()->setSender(m_moving->name());
955 if(m_form->formWidget())
956 {
957 m_form->formWidget()->initBuffer();
958 m_form->formWidget()->highlightWidgets(m_moving, 0/*, TQPoint()*/);
959 }
961 return;
962 }
963 // the user clicked outside the menu, we cancel the connection
964 if(FormManager::self()->createdConnection()->signal().isNull())
965 {
967 return;
968 }
969 // second click to choose the receiver
970 if(FormManager::self()->createdConnection()->receiver().isNull())
971 {
972 FormManager::self()->createdConnection()->setReceiver(m_moving->name());
974 m_container->repaint();
975 return;
976 }
977 // the user clicked outside the menu, we cancel the connection
978 if(FormManager::self()->createdConnection()->slot().isNull())
979 {
981 return;
982 }
983}
984
985void
987{
988 //finish drawing unclipped selection rectangle: clear the surface
989 if(m_form->formWidget())
990 m_form->formWidget()->clearForm();
991 int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() : mev->x();
992 int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y();
993 int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() : mev->x();
994 int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y();
995 TQRect r = TQRect(TQPoint(topx, topy), TQPoint(botx, boty));
996
997 setSelectedWidget(m_container, false);
998 TQWidget *widgetToSelect = 0;
999 // We check which widgets are in the rect and select them
1000 for(ObjectTreeItem *item = m_tree->children()->first(); item; item = m_tree->children()->next())
1001 {
1002 TQWidget *w = item->widget();
1003 if(!w)
1004 continue;
1005 if(w->geometry().intersects(r) && w != m_container) {
1006 if (widgetToSelect)
1007 setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, true/*moreWillBeSelected*/);
1008 widgetToSelect = w; //select later
1009 }
1010 }
1011 if (widgetToSelect) //the last one left
1012 setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, false);
1013
1014 m_insertRect = TQRect();
1015 m_state = DoingNothing;
1016 m_container->repaint();
1017}
1018
1019void
1020Container::drawInsertRect(TQMouseEvent *mev, TQObject *s)
1021{
1022 int tmpx, tmpy;
1023 TQPoint pos = static_cast<TQWidget*>(s)->mapTo(m_container, mev->pos());
1024 int gridX = m_form->gridSize();
1025 int gridY = m_form->gridSize();
1026 if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (TQt::LeftButton|TQt::ControlButton|TQt::AltButton)) )
1027 {
1028 tmpx = pos.x();
1029 tmpy = pos.y();
1030 }
1031 else
1032 {
1033 tmpx = int( (float) pos.x() / ((float)gridX) + 0.5);
1034 tmpx *= gridX;
1035 tmpy = int( (float)pos.y() / ((float)gridY) + 0.5);
1036 tmpy *= gridX;
1037 }
1038
1039 int topx = (m_insertBegin.x() < tmpx) ? m_insertBegin.x() : tmpx;
1040 int topy = (m_insertBegin.y() < tmpy) ? m_insertBegin.y() : tmpy;
1041 int botx = (m_insertBegin.x() > tmpx) ? m_insertBegin.x() : tmpx;
1042 int boty = (m_insertBegin.y() > tmpy) ? m_insertBegin.y() : tmpy;
1043 m_insertRect = TQRect(TQPoint(topx, topy), TQPoint(botx, boty));
1044
1045 if(m_insertRect.x() < 0)
1046 m_insertRect.setLeft(0);
1047 if(m_insertRect.y() < 0)
1048 m_insertRect.setTop(0);
1049 if(m_insertRect.right() > m_container->width())
1050 m_insertRect.setRight(m_container->width());
1051 if(m_insertRect.bottom() > m_container->height())
1052 m_insertRect.setBottom(m_container->height());
1053
1054 if(FormManager::self()->isInserting() && m_insertRect.isValid())
1055 {
1056 if(m_form->formWidget())
1057 {
1058 TQRect drawRect = TQRect(m_container->mapTo(m_form->widget(), m_insertRect.topLeft())
1059 , m_insertRect.size());
1060 m_form->formWidget()->drawRect(drawRect, 2);
1061 }
1062 }
1063}
1064
1065void
1066Container::drawCopiedWidgetRect(TQMouseEvent *mev)
1067{
1068 // We've been dragging a widget, but Ctrl was hold, so we start copy
1069 if(m_state == MovingWidget) {
1070 //FormManager::self()->undo(); // undo last moving
1071 //m_moving->move(m_initialPos);
1072 if(m_form->formWidget()) {
1073 m_container->repaint();
1074 m_form->formWidget()->initBuffer();
1075 }
1076 m_state = CopyingWidget;
1077 }
1078
1079 //m_copyRect.moveTopLeft(m_container->mapFromGlobal( mev->globalPos()) - m_grab);
1080
1081 if(m_form->formWidget()) {
1082 TQValueList<TQRect> rectList;
1083 for(TQWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next()) {
1084 TQRect drawRect = w->geometry();
1085 TQPoint p = mev->pos() - m_grab;
1086 drawRect.moveBy(p.x(), p.y());
1087 p = m_container->mapTo(m_form->widget(), TQPoint(0, 0));
1088 //drawRect = TQRect( ((TQWidget*)s)->mapTo(m_form->widget(), drawRect.topLeft()), drawRect.size());
1089 drawRect.moveBy(p.x(), p.y());
1090 rectList.append(drawRect);
1091 }
1092
1093 m_form->formWidget()->drawRects(rectList, 2);
1094 }
1095}
1096
1098void
1099Container::moveSelectedWidgetsBy(int realdx, int realdy, TQMouseEvent *mev)
1100{
1101 if (m_form->selectedWidget() == m_form->widget())
1102 return; //do not move top-level widget
1103
1104 const int gridX = m_form->gridSize();
1105 const int gridY = m_form->gridSize();
1106 int dx=realdx, dy=realdy;
1107
1108 for(TQWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next())
1109 {
1110 if(!w || !w->parent() || w->parent()->inherits("TQTabWidget") || w->parent()->inherits("TQWidgetStack"))
1111 continue;
1112
1113 if(w->parentWidget() && w->parentWidget()->isA("TQWidgetStack"))
1114 {
1115 w = w->parentWidget(); // widget is WidgetStack page
1116 if(w->parentWidget() && w->parentWidget()->inherits("TQTabWidget")) // widget is tabwidget page
1117 w = w->parentWidget();
1118 }
1119
1120 int tmpx = w->x() + realdx;
1121 int tmpy = w->y() + realdy;
1122 if(tmpx < 0)
1123 dx = TQMAX(0 - w->x(), dx); // because dx is <0
1124 else if(tmpx > w->parentWidget()->width() - gridX)
1125 dx = TQMIN(w->parentWidget()->width() - gridX - w->x(), dx);
1126
1127 if(tmpy < 0)
1128 dy = TQMAX(0 - w->y(), dy); // because dy is <0
1129 else if(tmpy > w->parentWidget()->height() - gridY)
1130 dy = TQMIN(w->parentWidget()->height() - gridY - w->y(), dy);
1131 }
1132
1133 for(TQWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next())
1134 {
1135 // Don't move tab widget pages (or widget stack pages)
1136 if(!w || !w->parent() || w->parent()->inherits("TQTabWidget") || w->parent()->inherits("TQWidgetStack"))
1137 continue;
1138
1139 if(w->parentWidget() && w->parentWidget()->isA("TQWidgetStack"))
1140 {
1141 w = w->parentWidget(); // widget is WidgetStack page
1142 if(w->parentWidget() && w->parentWidget()->inherits("TQTabWidget")) // widget is tabwidget page
1143 w = w->parentWidget();
1144 }
1145
1146 int tmpx, tmpy;
1147 if(!FormManager::self()->snapWidgetsToGrid() || (mev && mev->state() == (TQt::LeftButton|TQt::ControlButton|TQt::AltButton)) )
1148 {
1149 tmpx = w->x() + dx;
1150 tmpy = w->y() + dy;
1151 }
1152 else
1153 {
1154 tmpx = int( float( w->x() + dx) / float(gridX) + 0.5) * gridX;
1155 tmpy = int( float( w->y() + dy) / float(gridY) + 0.5) * gridY;
1156 }
1157
1158 if((tmpx != w->x()) || (tmpy != w->y()))
1159 w->move(tmpx,tmpy);
1160 }
1161}
1162
1164
1165DesignTimeDynamicChildWidgetHandler::DesignTimeDynamicChildWidgetHandler()
1166 : m_item(0)
1167{
1168}
1169
1170DesignTimeDynamicChildWidgetHandler::~DesignTimeDynamicChildWidgetHandler()
1171{
1172}
1173
1174void
1175DesignTimeDynamicChildWidgetHandler::childWidgetAdded(TQWidget* w)
1176{
1177 if (m_item) {
1178 installRecursiveEventFilter(w, m_item->eventEater());
1179 }
1180}
1181
1182#include "container.moc"
This class makes a container out of any TQWidget.
Definition container.h:74
void moveSelectedWidgetsBy(int realdx, int realdy, TQMouseEvent *mev=0)
Other functions used by eventFilter.
void setLayout(LayoutType type)
Layout functions.
void deleteWidget(TQWidget *w)
TQWidget * widget() const
Definition container.h:94
void setSelectedWidget(TQWidget *selected, bool add, bool dontRaise=false, bool moreWillBeSelected=false)
void drawSelectionRect(TQMouseEvent *mev)
ObjectTreeItem * objectTree() const
Definition container.h:97
static TQString layoutTypeToString(int type)
void drawConnection(TQMouseEvent *mev)
Drawing functions used by eventFilter.
Container(Container *toplevel, TQWidget *container, TQObject *parent=0, const char *name=0)
Creates a Container from the widget container, which have toplevel as parent Container.
Definition container.cpp:91
void setForm(Form *form)
Sets the Form which this Container belongs to.
void createGridLayout(bool testOnly=false)
TQLayout * layout() const
Definition container.h:107
void createBoxLayout(WidgetList *list)
virtual bool eventFilter(TQObject *o, TQEvent *e)
void unSelectWidget(TQWidget *w)
void setObjectTree(ObjectTreeItem *t)
Definition container.h:104
static LayoutType stringToLayoutType(const TQString &name)
Form * form() const
Definition container.h:91
EventEater(TQWidget *widget, TQObject *container)
Definition container.cpp:47
void setInsertPoint(const TQPoint &p)
static FormManager * self()
Access to FormManager singleton.
void stopCreatingConnection()
Leave the Connection creation mode.
void createSignalMenu(TQWidget *w)
Creates and display a menu with all the signals of widget w.
void createSlotMenu(TQWidget *w)
Creates and display a menu with all the slots of widget w.
void createContextMenu(TQWidget *w, Container *container, bool popupAtCursor=true)
Connection * createdConnection()
void deleteWidgetLater(TQWidget *w)
Used to delayed widgets' deletion (in Container::deleteItem()).
A simple class representing a form.
Definition form.h:136
void setSelectedWidget(TQWidget *selected, bool add=false, bool dontRaise=false, bool moreWillBeSelected=false)
Definition form.cpp:237
ObjectTree * objectTree() const
Definition form.h:167
A helper for sorting widgets horizontally.
An item representing a widget Holds the properties of a widget (classname, name, parent,...
Definition objecttree.h:59
ObjectTreeItem * lookup(const TQString &name)
A helper for sorting widgets vertically.
a special "flow" layout
TQt::Orientation orientation() const
void setOrientation(TQt::Orientation orientation)
TQPtrList< TQWidget > WidgetList
A list of widget pointers.
TQPtrList< ObjectTreeItem > ObjectTreeList
An list of ObjectTreeItem pointers.
Definition objecttree.h:42
TQPtrListIterator< TQWidget > WidgetListIterator
An iterator for WidgetList.
KFORMEDITOR_EXPORT void installRecursiveEventFilter(TQObject *object, TQObject *container)
KFORMEDITOR_EXPORT void removeRecursiveEventFilter(TQObject *object, TQObject *container)