~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to tools/designer/src/lib/shared/layout.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the designer application of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "layout_p.h"
 
30
#include "qdesigner_widget_p.h"
 
31
#include "qlayout_widget_p.h"
 
32
#include "spacer_widget_p.h"
 
33
#include "layoutdecoration.h"
 
34
 
 
35
#include <QtDesigner/QtDesigner>
 
36
 
 
37
#include <QtCore/qdebug.h>
 
38
#include <QtCore/QVector>
 
39
 
 
40
#include <QtGui/qevent.h>
 
41
#include <QtGui/QGridLayout>
 
42
#include <QtGui/QPainter>
 
43
#include <QtGui/QBitmap>
 
44
#include <QtGui/QSplitter>
 
45
#include <QtGui/QMainWindow>
 
46
 
 
47
class FriendlyBoxLayout: public QBoxLayout
 
48
{
 
49
public:
 
50
    inline FriendlyBoxLayout(Direction d) : QBoxLayout(d) { Q_ASSERT(0); }
 
51
 
 
52
    friend void insert_into_box_layout(QBoxLayout *box, int index, QWidget *widget);
 
53
};
 
54
 
 
55
static bool operator<(const QPointer<QWidget> &p1, const QPointer<QWidget> &p2)
 
56
{
 
57
    return p1.operator->() < p2.operator->();
 
58
}
 
59
 
 
60
void add_to_box_layout(QBoxLayout *box, QWidget *widget)
 
61
{
 
62
    if (QLayoutWidget *layoutWidget = qobject_cast<QLayoutWidget*>(widget)) {
 
63
        QLayoutWidgetItem *item = new QLayoutWidgetItem(layoutWidget);
 
64
        item->addTo(box);
 
65
        box->addItem(item);
 
66
    } else {
 
67
        box->addWidget(widget);
 
68
    }
 
69
}
 
70
 
 
71
void insert_into_box_layout(QBoxLayout *box, int index, QWidget *widget)
 
72
{
 
73
    if (QLayoutWidget *layoutWidget = qobject_cast<QLayoutWidget*>(widget)) {
 
74
        QLayoutWidgetItem *item = new QLayoutWidgetItem(layoutWidget);
 
75
        item->addTo(box);
 
76
        static_cast<FriendlyBoxLayout*>(box)->insertItem(index, item);
 
77
    } else {
 
78
        box->insertWidget(index, widget);
 
79
    }
 
80
}
 
81
 
 
82
void add_to_grid_layout(QGridLayout *grid, QWidget *widget, int r, int c, int rs, int cs, Qt::Alignment align)
 
83
{
 
84
    if (QLayoutWidget *layoutWidget = qobject_cast<QLayoutWidget*>(widget)) {
 
85
        QLayoutWidgetItem *item = new QLayoutWidgetItem(layoutWidget);
 
86
        item->addTo(grid);
 
87
        grid->addItem(item, r, c, rs, cs, align);
 
88
    } else {
 
89
        grid->addWidget(widget, r, c, rs, cs, align);
 
90
    }
 
91
}
 
92
 
 
93
/*!
 
94
  \class Layout layout.h
 
95
  \brief Baseclass for layouting widgets in the Designer
 
96
 
 
97
  Classes derived from this abstract base class are used for layouting
 
98
  operations in the Designer.
 
99
 
 
100
*/
 
101
 
 
102
/*!  \a p specifies the parent of the layoutBase \a lb. The parent
 
103
  might be changed in setup(). If the layoutBase is a
 
104
  container, the parent and the layoutBase are the same. Also they
 
105
  always have to be a widget known to the designer (e.g. in the case
 
106
  of the tabwidget parent and layoutBase are the tabwidget and not the
 
107
  page which actually gets laid out. For actual usage the correct
 
108
  widget is found later by Layout.)
 
109
 */
 
110
 
 
111
Layout::Layout(const QList<QWidget*> &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, bool splitter)
 
112
    : m_widgets(wl), m_parentWidget(p), formWindow(fw), isBreak(false), useSplitter(splitter)
 
113
{
 
114
    layoutBase = lb;
 
115
    if (layoutBase)
 
116
        oldGeometry = layoutBase->geometry();
 
117
}
 
118
 
 
119
Layout::~Layout()
 
120
{
 
121
}
 
122
 
 
123
int Layout::margin() const
 
124
{
 
125
    if (layoutBase && layoutBase->layout())
 
126
        return layoutBase->layout()->margin();
 
127
 
 
128
    qWarning("unknown margin");
 
129
    return 0;
 
130
}
 
131
 
 
132
int Layout::spacing() const
 
133
{
 
134
    if (layoutBase && layoutBase->layout())
 
135
        return layoutBase->layout()->spacing();
 
136
 
 
137
    qWarning("unknown spacing");
 
138
    return 0;
 
139
}
 
140
 
 
141
/*!  The widget list we got in the constructor might contain too much
 
142
  widgets (like widgets with different parents, already laid out
 
143
  widgets, etc.). Here we set up the list and so the only the "best"
 
144
  widgets get laid out.
 
145
*/
 
146
 
 
147
void Layout::setup()
 
148
{
 
149
    startPoint = QPoint(32767, 32767);
 
150
 
 
151
    // Go through all widgets of the list we got. As we can only
 
152
    // layout widgets which have the same parent, we first do some
 
153
    // sorting which means create a list for each parent containing
 
154
    // its child here. After that we keep working on the list of
 
155
    // childs which has the most entries.
 
156
    // Widgets which are already laid out are thrown away here too
 
157
 
 
158
    QMultiMap<QWidget*, QWidget*> lists;
 
159
    foreach (QWidget *w, m_widgets) {
 
160
        QWidget *p = w->parentWidget();
 
161
 
 
162
        if (p && LayoutInfo::layoutType(formWindow->core(), p) != LayoutInfo::NoLayout
 
163
                && formWindow->core()->metaDataBase()->item(p->layout()) != 0)
 
164
            continue;
 
165
 
 
166
        lists.insert(p, w);
 
167
    }
 
168
 
 
169
    QList<QWidget*> lastList;
 
170
    QList<QWidget*> parents = lists.keys();
 
171
    foreach (QWidget *p, parents) {
 
172
        QList<QWidget*> children = lists.values(p);
 
173
 
 
174
        if (children.count() > lastList.count())
 
175
            lastList = children;
 
176
    }
 
177
 
 
178
 
 
179
    // If we found no list (because no widget did fit at all) or the
 
180
    // best list has only one entry and we do not layout a container,
 
181
    // we leave here.
 
182
    QDesignerWidgetDataBaseInterface *widgetDataBase = formWindow->core()->widgetDataBase();
 
183
    if (lastList.count() < 2 &&
 
184
                        (!layoutBase ||
 
185
                          (!widgetDataBase->isContainer(layoutBase, false) &&
 
186
                            layoutBase != formWindow->mainContainer()))
 
187
                       ) {
 
188
        m_widgets.clear();
 
189
        startPoint = QPoint(0, 0);
 
190
        return;
 
191
    }
 
192
 
 
193
    // Now we have a new and clean widget list, which makes sense
 
194
    // to layout
 
195
    m_widgets = lastList;
 
196
    // Also use the only correct parent later, so store it
 
197
 
 
198
    Q_ASSERT(m_widgets.isEmpty() == false);
 
199
 
 
200
    m_parentWidget = formWindow->core()->widgetFactory()->widgetOfContainer(m_widgets.first()->parentWidget());
 
201
    // Now calculate the position where the layout-meta-widget should
 
202
    // be placed and connect to widgetDestroyed() signals of the
 
203
    // widgets to get informed if one gets deleted to be able to
 
204
    // handle that and do not crash in this case
 
205
    foreach (QWidget *w, m_widgets) {
 
206
        connect(w, SIGNAL(destroyed()), this, SLOT(widgetDestroyed()));
 
207
        startPoint = QPoint(qMin(startPoint.x(), w->x()), qMin(startPoint.y(), w->y()));
 
208
        QRect rc(w->geometry());
 
209
        geometries.insert(w, rc);
 
210
        // Change the Z-order, as saving/loading uses the Z-order for
 
211
        // writing/creating widgets and this has to be the same as in
 
212
        // the layout. Else saving + loading will give different results
 
213
        w->raise();
 
214
    }
 
215
 
 
216
    sort();
 
217
}
 
218
 
 
219
void Layout::widgetDestroyed()
 
220
{
 
221
     if (sender() && sender()->isWidgetType()) {
 
222
         const QWidget *w = static_cast<const QWidget*>(sender());
 
223
         m_widgets.removeAt(m_widgets.indexOf(const_cast<QWidget*>(w)));
 
224
     }
 
225
}
 
226
 
 
227
bool Layout::prepareLayout(bool &needMove, bool &needReparent)
 
228
{
 
229
    if (!m_widgets.count())
 
230
        return false;
 
231
 
 
232
    foreach (QWidget *widget, m_widgets) {
 
233
        widget->raise();
 
234
    }
 
235
 
 
236
    needMove = !layoutBase;
 
237
    needReparent = needMove || qobject_cast<QLayoutWidget*>(layoutBase) || qobject_cast<QSplitter*>(layoutBase);
 
238
 
 
239
    QDesignerWidgetFactoryInterface *widgetFactory = formWindow->core()->widgetFactory();
 
240
    QDesignerMetaDataBaseInterface *metaDataBase = formWindow->core()->metaDataBase();
 
241
 
 
242
    if (layoutBase == 0) {
 
243
        QString baseWidgetClassName = QLatin1String("QLayoutWidget");
 
244
 
 
245
        if (useSplitter)
 
246
            baseWidgetClassName = QLatin1String("QSplitter");
 
247
 
 
248
        layoutBase = widgetFactory->createWidget(baseWidgetClassName, widgetFactory->containerOfWidget(m_parentWidget));
 
249
    } else {
 
250
        LayoutInfo::deleteLayout(formWindow->core(), layoutBase);
 
251
    }
 
252
 
 
253
    metaDataBase->add(layoutBase);
 
254
 
 
255
    Q_ASSERT(layoutBase->layout() == 0 || metaDataBase->item(layoutBase->layout()) == 0);
 
256
 
 
257
    return true;
 
258
}
 
259
 
 
260
void Layout::finishLayout(bool needMove, QLayout *layout)
 
261
{
 
262
    if (m_parentWidget == layoutBase)
 
263
        return;
 
264
 
 
265
    if (needMove)
 
266
        layoutBase->move(startPoint);
 
267
 
 
268
    QRect g(layoutBase->pos(), layoutBase->size());
 
269
 
 
270
    if (LayoutInfo::layoutType(formWindow->core(), layoutBase->parentWidget()) == LayoutInfo::NoLayout && !isBreak)
 
271
        layoutBase->adjustSize();
 
272
    else if (isBreak)
 
273
        layoutBase->setGeometry(oldGeometry);
 
274
 
 
275
    oldGeometry = g;
 
276
    layout->invalidate();
 
277
    layoutBase->show();
 
278
 
 
279
    if (qobject_cast<QLayoutWidget*>(layoutBase) || qobject_cast<QSplitter*>(layoutBase)) {
 
280
        formWindow->manageWidget(layoutBase);
 
281
        formWindow->selectWidget(layoutBase);
 
282
    }
 
283
}
 
284
 
 
285
void Layout::undoLayout()
 
286
{
 
287
    if (!m_widgets.count())
 
288
        return;
 
289
 
 
290
    formWindow->selectWidget(layoutBase, false);
 
291
 
 
292
    QDesignerWidgetFactoryInterface *widgetFactory = formWindow->core()->widgetFactory();
 
293
    QMapIterator<QPointer<QWidget>, QRect> it(geometries);
 
294
    while (it.hasNext()) {
 
295
        it.next();
 
296
 
 
297
        if (!it.key())
 
298
            continue;
 
299
 
 
300
        QWidget* w = it.key();
 
301
        QRect rc = it.value();
 
302
 
 
303
        bool showIt = w->isVisibleTo(formWindow);
 
304
        QWidget *container = widgetFactory->containerOfWidget(m_parentWidget);
 
305
 
 
306
        // ### remove widget here
 
307
        QWidget *parentWidget = w->parentWidget();
 
308
        QDesignerFormEditorInterface *core = formWindow->core();
 
309
        QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), parentWidget);
 
310
 
 
311
        if (deco)
 
312
            deco->removeWidget(w);
 
313
 
 
314
        w->setParent(container);
 
315
        w->setGeometry(rc);
 
316
 
 
317
        if (showIt)
 
318
            w->show();
 
319
    }
 
320
 
 
321
    LayoutInfo::deleteLayout(formWindow->core(), layoutBase);
 
322
 
 
323
    if (m_parentWidget != layoutBase && !qobject_cast<QMainWindow*>(layoutBase)) {
 
324
        formWindow->unmanageWidget(layoutBase);
 
325
        layoutBase->hide();
 
326
    } else {
 
327
        layoutBase->setGeometry(oldGeometry);
 
328
    }
 
329
 
 
330
    QWidget *ww = m_widgets.size() ? m_widgets.front() : formWindow;
 
331
    formWindow->selectWidget(ww);
 
332
}
 
333
 
 
334
void Layout::breakLayout()
 
335
{
 
336
    QMap<QWidget*, QRect> rects;
 
337
    foreach (QWidget *w, m_widgets) {
 
338
        rects.insert(w, w->geometry());
 
339
    }
 
340
 
 
341
    QPoint layoutBasePos = layoutBase->pos();
 
342
    QDesignerWidgetDataBaseInterface *widgetDataBase = formWindow->core()->widgetDataBase();
 
343
 
 
344
    LayoutInfo::deleteLayout(formWindow->core(), layoutBase);
 
345
 
 
346
    bool needReparent = qobject_cast<QLayoutWidget*>(layoutBase) ||
 
347
                        qobject_cast<QSplitter*>(layoutBase)     ||
 
348
                        (!widgetDataBase->isContainer(layoutBase, false) &&
 
349
                          layoutBase != formWindow->mainContainer());
 
350
    bool needResize = qobject_cast<QSplitter*>(layoutBase);
 
351
    bool add = geometries.isEmpty();
 
352
 
 
353
    QMapIterator<QWidget*, QRect> it(rects);
 
354
    while (it.hasNext()) {
 
355
        it.next();
 
356
 
 
357
        QWidget *w = it.key();
 
358
        if (needReparent) {
 
359
            w->setParent(layoutBase->parentWidget(), 0);
 
360
            w->move(layoutBasePos + it.value().topLeft());
 
361
            w->show();
 
362
        }
 
363
 
 
364
        if (needResize)
 
365
            w->resize(it.value().size());
 
366
 
 
367
        if (add)
 
368
            geometries.insert(w, QRect(w->pos(), w->size()));
 
369
    }
 
370
 
 
371
    if (needReparent) {
 
372
        layoutBase->hide();
 
373
        m_parentWidget = layoutBase->parentWidget();
 
374
        formWindow->unmanageWidget(layoutBase);
 
375
    } else {
 
376
        m_parentWidget = layoutBase;
 
377
    }
 
378
 
 
379
    if (m_widgets.first() && m_widgets.first()->isVisibleTo(formWindow))
 
380
        formWindow->selectWidget(m_widgets.first());
 
381
    else
 
382
        formWindow->selectWidget(formWindow);
 
383
}
 
384
 
 
385
HorizontalLayout::HorizontalLayout(const QList<QWidget*> &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, bool splitter)
 
386
    : Layout(wl, p, fw, lb, splitter)
 
387
{
 
388
}
 
389
 
 
390
void HorizontalLayout::sort()
 
391
{
 
392
    HorizontalLayoutList l(m_widgets);
 
393
    l.sort();
 
394
    m_widgets = l;
 
395
}
 
396
 
 
397
void HorizontalLayout::doLayout()
 
398
{
 
399
    bool needMove, needReparent;
 
400
    if (!prepareLayout(needMove, needReparent))
 
401
        return;
 
402
 
 
403
    QDesignerWidgetFactoryInterface *widgetFactory = formWindow->core()->widgetFactory();
 
404
    QHBoxLayout *layout = (QHBoxLayout*) widgetFactory->createLayout(layoutBase, 0, LayoutInfo::HBox);
 
405
 
 
406
    foreach (QWidget *w, m_widgets) {
 
407
        if (needReparent && w->parent() != layoutBase) {
 
408
            w->setParent(layoutBase, 0);
 
409
            w->move(QPoint(0,0));
 
410
        }
 
411
 
 
412
        if (useSplitter) {
 
413
            QSplitter *splitter = qobject_cast<QSplitter*>(layoutBase);
 
414
            Q_ASSERT(splitter != 0);
 
415
            splitter->addWidget(w);
 
416
        } else {
 
417
            if (Spacer *spacer = qobject_cast<Spacer*>(w))
 
418
                layout->addWidget(w, 0, spacer->alignment());
 
419
            else
 
420
                add_to_box_layout(layout, w);
 
421
        }
 
422
        w->show();
 
423
    }
 
424
 
 
425
    if (QSplitter *splitter = qobject_cast<QSplitter*>(layoutBase))
 
426
        splitter->setOrientation(Qt::Horizontal);
 
427
 
 
428
    finishLayout(needMove, layout);
 
429
}
 
430
 
 
431
VerticalLayout::VerticalLayout(const QList<QWidget*> &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, bool splitter)
 
432
    : Layout(wl, p, fw, lb, splitter)
 
433
{
 
434
}
 
435
 
 
436
void VerticalLayout::sort()
 
437
{
 
438
    VerticalLayoutList l(m_widgets);
 
439
    l.sort();
 
440
    m_widgets = l;
 
441
}
 
442
 
 
443
void VerticalLayout::doLayout()
 
444
{
 
445
    bool needMove, needReparent;
 
446
    if (!prepareLayout(needMove, needReparent))
 
447
        return;
 
448
 
 
449
    QDesignerWidgetFactoryInterface *widgetFactory = formWindow->core()->widgetFactory();
 
450
 
 
451
    QVBoxLayout *layout = (QVBoxLayout*) widgetFactory->createLayout(layoutBase, 0, LayoutInfo::VBox);
 
452
    Q_ASSERT(layout != 0);
 
453
 
 
454
    foreach (QWidget *w, m_widgets) {
 
455
        if (needReparent && w->parent() != layoutBase) {
 
456
            w->setParent(layoutBase, 0);
 
457
            w->move(QPoint(0,0));
 
458
        }
 
459
 
 
460
        if (useSplitter) {
 
461
            QSplitter *splitter = qobject_cast<QSplitter*>(layoutBase);
 
462
            Q_ASSERT(splitter != 0);
 
463
            splitter->addWidget(w);
 
464
        } else {
 
465
            if (Spacer *spacer = qobject_cast<Spacer*>(w))
 
466
                layout->addWidget(w, 0, spacer->alignment());
 
467
            else
 
468
                add_to_box_layout(layout, w);
 
469
        }
 
470
        w->show();
 
471
    }
 
472
 
 
473
    if (QSplitter *splitter = qobject_cast<QSplitter*>(layoutBase)) { // ### useSplitter??
 
474
        splitter->setOrientation(Qt::Vertical);
 
475
    }
 
476
 
 
477
    finishLayout(needMove, layout);
 
478
}
 
479
 
 
480
class Grid
 
481
{
 
482
public:
 
483
    Grid(int rows, int cols);
 
484
    ~Grid();
 
485
 
 
486
    QWidget* cell(int row, int col) const { return cells[ row * ncols + col]; }
 
487
    void setCell(int row, int col, QWidget* w) { cells[ row*ncols + col] = w; }
 
488
    void setCells(QRect c, QWidget* w) {
 
489
        for (int rows = c.bottom()-c.top(); rows >= 0; rows--)
 
490
            for (int cols = c.right()-c.left(); cols >= 0; cols--) {
 
491
                setCell(c.top()+rows, c.left()+cols, w);
 
492
            }
 
493
    }
 
494
    int numRows() const { return nrows; }
 
495
    int numCols() const { return ncols; }
 
496
 
 
497
    void simplify();
 
498
    bool locateWidget(QWidget* w, int& row, int& col, int& rowspan, int& colspan);
 
499
 
 
500
private:
 
501
    void merge();
 
502
    int countRow(int r, int c) const;
 
503
    int countCol(int r, int c) const;
 
504
    void setRow(int r, int c, QWidget* w, int count);
 
505
    void setCol(int r, int c, QWidget* w, int count);
 
506
    bool isWidgetStartCol(int c) const;
 
507
    bool isWidgetEndCol(int c) const;
 
508
    bool isWidgetStartRow(int r) const;
 
509
    bool isWidgetEndRow(int r) const;
 
510
    bool isWidgetTopLeft(int r, int c) const;
 
511
    void extendLeft();
 
512
    void extendRight();
 
513
    void extendUp();
 
514
    void extendDown();
 
515
    QWidget** cells;
 
516
    bool* cols;
 
517
    bool* rows;
 
518
    int nrows, ncols;
 
519
 
 
520
};
 
521
 
 
522
Grid::Grid(int r, int c)
 
523
    : nrows(r), ncols(c)
 
524
{
 
525
    cells = new QWidget*[ r * c ];
 
526
    memset(cells, 0, sizeof(cells) * r * c);
 
527
    rows = new bool[ r ];
 
528
    cols = new bool[ c ];
 
529
 
 
530
}
 
531
 
 
532
Grid::~Grid()
 
533
{
 
534
    delete [] cells;
 
535
    delete [] cols;
 
536
    delete [] rows;
 
537
}
 
538
 
 
539
int Grid::countRow(int r, int c) const
 
540
{
 
541
    QWidget* w = cell(r, c);
 
542
    int i = c + 1;
 
543
    while (i < ncols && cell(r, i) == w)
 
544
        i++;
 
545
    return i - c;
 
546
}
 
547
 
 
548
int Grid::countCol(int r, int c) const
 
549
{
 
550
    QWidget* w = cell(r, c);
 
551
    int i = r + 1;
 
552
    while (i < nrows && cell(i, c) == w)
 
553
        i++;
 
554
    return i - r;
 
555
}
 
556
 
 
557
void Grid::setCol(int r, int c, QWidget* w, int count)
 
558
{
 
559
    for (int i = 0; i < count; i++)
 
560
        setCell(r + i, c, w);
 
561
}
 
562
 
 
563
void Grid::setRow(int r, int c, QWidget* w, int count)
 
564
{
 
565
    for (int i = 0; i < count; i++)
 
566
        setCell(r, c + i, w);
 
567
}
 
568
 
 
569
bool Grid::isWidgetStartCol(int c) const
 
570
{
 
571
    int r;
 
572
    for (r = 0; r < nrows; r++) {
 
573
        if (cell(r, c) && ((c==0) || (cell(r, c)  != cell(r, c-1)))) {
 
574
            return true;
 
575
        }
 
576
    }
 
577
    return false;
 
578
}
 
579
 
 
580
bool Grid::isWidgetEndCol(int c) const
 
581
{
 
582
    int r;
 
583
    for (r = 0; r < nrows; r++) {
 
584
        if (cell(r, c) && ((c == ncols-1) || (cell(r, c) != cell(r, c+1))))
 
585
            return true;
 
586
    }
 
587
    return false;
 
588
}
 
589
 
 
590
bool Grid::isWidgetStartRow(int r) const
 
591
{
 
592
    int c;
 
593
    for (c = 0; c < ncols; c++) {
 
594
        if (cell(r, c) && ((r==0) || (cell(r, c) != cell(r-1, c))))
 
595
            return true;
 
596
    }
 
597
    return false;
 
598
}
 
599
 
 
600
bool Grid::isWidgetEndRow(int r) const
 
601
{
 
602
    int c;
 
603
    for (c = 0; c < ncols; c++) {
 
604
        if (cell(r, c) && ((r == nrows-1) || (cell(r, c) != cell(r+1, c))))
 
605
            return true;
 
606
    }
 
607
    return false;
 
608
}
 
609
 
 
610
 
 
611
bool Grid::isWidgetTopLeft(int r, int c) const
 
612
{
 
613
    QWidget* w = cell(r, c);
 
614
    if (!w)
 
615
        return false;
 
616
    return (!r || cell(r-1, c) != w) && (!c || cell(r, c-1) != w);
 
617
}
 
618
 
 
619
void Grid::extendLeft()
 
620
{
 
621
    int r,c,i;
 
622
    for (c = 1; c < ncols; c++) {
 
623
        for (r = 0; r < nrows; r++) {
 
624
            QWidget* w = cell(r, c);
 
625
            if (!w)
 
626
                continue;
 
627
 
 
628
            int cc = countCol(r, c);
 
629
            int stretch = 0;
 
630
            for (i = c-1; i >= 0; i--) {
 
631
                if (cell(r, i))
 
632
                    break;
 
633
                if (countCol(r, i) < cc)
 
634
                    break;
 
635
                if (isWidgetEndCol(i))
 
636
                    break;
 
637
                if (isWidgetStartCol(i)) {
 
638
                    stretch = c - i;
 
639
                    break;
 
640
                }
 
641
            }
 
642
            if (stretch) {
 
643
                for (i = 0; i < stretch; i++)
 
644
                    setCol(r, c-i-1, w, cc);
 
645
            }
 
646
        }
 
647
    }
 
648
}
 
649
 
 
650
 
 
651
void Grid::extendRight()
 
652
{
 
653
    int r,c,i;
 
654
    for (c = ncols - 2; c >= 0; c--) {
 
655
        for (r = 0; r < nrows; r++) {
 
656
            QWidget* w = cell(r, c);
 
657
            if (!w)
 
658
                continue;
 
659
            int cc = countCol(r, c);
 
660
            int stretch = 0;
 
661
            for (i = c+1; i < ncols; i++) {
 
662
                if (cell(r, i))
 
663
                    break;
 
664
                if (countCol(r, i) < cc)
 
665
                    break;
 
666
                if (isWidgetStartCol(i))
 
667
                    break;
 
668
                if (isWidgetEndCol(i)) {
 
669
                    stretch = i - c;
 
670
                    break;
 
671
                }
 
672
            }
 
673
            if (stretch) {
 
674
                for (i = 0; i < stretch; i++)
 
675
                    setCol(r, c+i+1, w, cc);
 
676
            }
 
677
        }
 
678
    }
 
679
 
 
680
}
 
681
 
 
682
void Grid::extendUp()
 
683
{
 
684
    int r,c,i;
 
685
    for (r = 1; r < nrows; r++) {
 
686
        for (c = 0; c < ncols; c++) {
 
687
            QWidget* w = cell(r, c);
 
688
            if (!w)
 
689
                continue;
 
690
            int cr = countRow(r, c);
 
691
            int stretch = 0;
 
692
            for (i = r-1; i >= 0; i--) {
 
693
                if (cell(i, c))
 
694
                    break;
 
695
                if (countRow(i, c) < cr)
 
696
                    break;
 
697
                if (isWidgetEndRow(i))
 
698
                    break;
 
699
                if (isWidgetStartRow(i)) {
 
700
                    stretch = r - i;
 
701
                    break;
 
702
                }
 
703
            }
 
704
            if (stretch) {
 
705
                for (i = 0; i < stretch; i++)
 
706
                    setRow(r-i-1, c, w, cr);
 
707
            }
 
708
        }
 
709
    }
 
710
}
 
711
 
 
712
void Grid::extendDown()
 
713
{
 
714
    int r,c,i;
 
715
    for (r = nrows - 2; r >= 0; r--) {
 
716
        for (c = 0; c < ncols; c++) {
 
717
            QWidget* w = cell(r, c);
 
718
            if (!w)
 
719
                continue;
 
720
            int cr = countRow(r, c);
 
721
            int stretch = 0;
 
722
            for (i = r+1; i < nrows; i++) {
 
723
                if (cell(i, c))
 
724
                    break;
 
725
                if (countRow(i, c) < cr)
 
726
                    break;
 
727
                if (isWidgetStartRow(i))
 
728
                    break;
 
729
                if (isWidgetEndRow(i)) {
 
730
                    stretch = i - r;
 
731
                    break;
 
732
                }
 
733
            }
 
734
            if (stretch) {
 
735
                for (i = 0; i < stretch; i++)
 
736
                    setRow(r+i+1, c, w, cr);
 
737
            }
 
738
        }
 
739
    }
 
740
 
 
741
}
 
742
 
 
743
void Grid::simplify()
 
744
{
 
745
    extendLeft();
 
746
    extendRight();
 
747
    extendUp();
 
748
    extendDown();
 
749
    merge();
 
750
}
 
751
 
 
752
 
 
753
void Grid::merge()
 
754
{
 
755
    int r,c;
 
756
    for (c = 0; c < ncols; c++)
 
757
        cols[c] = false;
 
758
 
 
759
    for (r = 0; r < nrows; r++)
 
760
        rows[r] = false;
 
761
 
 
762
    for (c = 0; c < ncols; c++) {
 
763
        for (r = 0; r < nrows; r++) {
 
764
            if (isWidgetTopLeft(r, c)) {
 
765
                rows[r] = true;
 
766
                cols[c] = true;
 
767
            }
 
768
        }
 
769
    }
 
770
}
 
771
 
 
772
bool Grid::locateWidget(QWidget *w, int &row, int &col, int &rowspan, int &colspan)
 
773
{
 
774
    int r, c, r2, c2;
 
775
 
 
776
    for (c = 0; c < ncols; c++) {
 
777
        for (r = 0; r < nrows; r++) {
 
778
            if (cell(r, c) == w) {
 
779
                row = 0;
 
780
                for (r2 = 1; r2 <= r; r2++) {
 
781
                    if (rows[r2-1])
 
782
                        row++;
 
783
                }
 
784
                col = 0;
 
785
                for (c2 = 1; c2 <= c; c2++) {
 
786
                    if (cols[c2-1])
 
787
                        col++;
 
788
                }
 
789
                rowspan = 0;
 
790
                for (r2 = r ; r2 < nrows && cell(r2, c) == w; r2++) {
 
791
                    if (rows[r2])
 
792
                        rowspan++;
 
793
                }
 
794
                colspan = 0;
 
795
                for (c2 = c; c2 < ncols && cell(r, c2) == w; c2++) {
 
796
                    if (cols[c2])
 
797
                        colspan++;
 
798
                }
 
799
                return true;
 
800
            }
 
801
        }
 
802
    }
 
803
    return false;
 
804
}
 
805
 
 
806
 
 
807
 
 
808
 
 
809
GridLayout::GridLayout(const QList<QWidget*> &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, const QSize &res)
 
810
    : Layout(wl, p, fw, lb), resolution(res)
 
811
{
 
812
    grid = 0;
 
813
}
 
814
 
 
815
GridLayout::~GridLayout()
 
816
{
 
817
    delete grid;
 
818
}
 
819
 
 
820
QWidget *GridLayout::widgetAt(QGridLayout *layout, int row, int column) const
 
821
{
 
822
    int index = 0;
 
823
    while (QLayoutItem *item = layout->itemAt(index)) {
 
824
        if (item->widget()) {
 
825
            int r, c, rowspan, colspan;
 
826
            layout->getItemPosition(index, &r, &c, &rowspan, &colspan);
 
827
            if (row == r && column == c)
 
828
                return item->widget();
 
829
        }
 
830
        ++index;
 
831
    }
 
832
    return 0;
 
833
}
 
834
 
 
835
void GridLayout::doLayout()
 
836
{
 
837
    bool needMove, needReparent;
 
838
    if (!prepareLayout(needMove, needReparent))
 
839
        return;
 
840
 
 
841
    QDesignerWidgetFactoryInterface *ff = formWindow->core()->widgetFactory();
 
842
    QGridLayout *layout = static_cast<QGridLayout*>(ff->createLayout(layoutBase, 0, LayoutInfo::Grid));
 
843
 
 
844
    if (!grid)
 
845
        buildGrid();
 
846
 
 
847
    foreach (QWidget *w, m_widgets) {
 
848
        int r = 0, c = 0, rs = 0, cs = 0;
 
849
 
 
850
        if (grid->locateWidget(w, r, c, rs, cs)) {
 
851
            if (needReparent && w->parent() != layoutBase) {
 
852
                w->setParent(layoutBase, 0);
 
853
                w->move(QPoint(0,0));
 
854
            }
 
855
 
 
856
            Qt::Alignment alignment = Qt::Alignment(0);
 
857
            if (Spacer *spacer = qobject_cast<Spacer*>(w))
 
858
                alignment = spacer->alignment();
 
859
 
 
860
            if (rs * cs == 1) {
 
861
                add_to_grid_layout(layout, w, r, c, 1, 1, alignment);
 
862
            } else {
 
863
                add_to_grid_layout(layout, w, r, c, rs, cs, alignment);
 
864
            }
 
865
 
 
866
            w->show();
 
867
        } else {
 
868
            qWarning("ooops, widget '%s' does not fit in layout", w->objectName().toUtf8().constData());
 
869
        }
 
870
    }
 
871
 
 
872
    QLayoutSupport::createEmptyCells(layout);
 
873
 
 
874
    finishLayout(needMove, layout);
 
875
}
 
876
 
 
877
void GridLayout::sort()
 
878
{
 
879
    buildGrid();
 
880
}
 
881
 
 
882
void GridLayout::buildGrid()
 
883
{
 
884
    if (!m_widgets.count())
 
885
        return;
 
886
#if 0
 
887
    QMap<int, int> x_dict;
 
888
    QMap<int, int> y_dict;
 
889
 
 
890
    foreach (QWidget *w, m_widgets) {
 
891
        QRect g = w->geometry();
 
892
 
 
893
        x_dict.insert(g.left(), g.left());
 
894
        x_dict.insert(g.right(), g.right());
 
895
 
 
896
        y_dict.insert(g.top(), g.top());
 
897
        y_dict.insert(g.bottom(), g.bottom());
 
898
    }
 
899
 
 
900
    QList<int> x = x_dict.keys();
 
901
    QList<int> y = y_dict.keys();
 
902
#else
 
903
    // Pixel to cell conversion:
 
904
    // By keeping a list of start'n'stop values (x & y) for each widget,
 
905
    // it is possible to create a very small grid of cells to represent
 
906
    // the widget layout.
 
907
    // -----------------------------------------------------------------
 
908
 
 
909
    // We need a list of both start and stop values for x- & y-axis
 
910
    QVector<int> x( m_widgets.count()*2 );
 
911
    QVector<int> y( m_widgets.count()*2 );
 
912
 
 
913
    // Using push_back would look nicer, but operator[] is much faster
 
914
    int index  = 0;
 
915
    QWidget* w = 0;
 
916
    for (int i = 0; i < m_widgets.size(); ++i) {
 
917
        w = m_widgets.at(i);
 
918
        QRect widgetPos = w->geometry();
 
919
        x[index]   = widgetPos.left();
 
920
        x[index+1] = widgetPos.right();
 
921
        y[index]   = widgetPos.top();
 
922
        y[index+1] = widgetPos.bottom();
 
923
        index += 2;
 
924
    }
 
925
 
 
926
    qSort(x);
 
927
    qSort(y);
 
928
 
 
929
    // Remove duplicate x enteries (Remove next, if equal to current)
 
930
    if ( !x.empty() ) {
 
931
        for (QVector<int>::iterator current = x.begin() ;
 
932
             (current != x.end()) && ((current+1) != x.end()) ; )
 
933
            if ( (*current == *(current+1)) )
 
934
                x.erase(current+1);
 
935
            else
 
936
                current++;
 
937
    }
 
938
 
 
939
    // Remove duplicate y enteries (Remove next, if equal to current)
 
940
    if ( !y.empty() ) {
 
941
        for (QVector<int>::iterator current = y.begin() ;
 
942
             (current != y.end()) && ((current+1) != y.end()) ; )
 
943
            if ( (*current == *(current+1)) )
 
944
                y.erase(current+1);
 
945
            else
 
946
                current++;
 
947
    }
 
948
#endif
 
949
 
 
950
    delete grid;
 
951
    grid = new Grid(y.size() - 1, x.size() - 1);
 
952
 
 
953
    // Mark the cells in the grid that contains a widget
 
954
    foreach (QWidget *w, m_widgets) {
 
955
        QRect widgetPos = w->geometry();
 
956
 
 
957
        QRect c(0, 0, 0, 0);
 
958
 
 
959
        // From left til right (not including)
 
960
        for (int cw=0; cw<x.size(); cw++) {
 
961
            if (x[cw] == widgetPos.left())
 
962
                c.setLeft(cw);
 
963
            if (x[cw] <  widgetPos.right())
 
964
                c.setRight(cw);
 
965
        }
 
966
 
 
967
        // From top til bottom (not including)
 
968
        for (int ch=0; ch<y.size(); ch++) {
 
969
            if (y[ch] == widgetPos.top()   )
 
970
                c.setTop(ch);
 
971
            if (y[ch] <  widgetPos.bottom())
 
972
                c.setBottom(ch);
 
973
        }
 
974
 
 
975
        grid->setCells(c, w); // Mark cellblock
 
976
    }
 
977
 
 
978
    grid->simplify();
 
979
}