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

« back to all changes in this revision

Viewing changes to src/gui/widgets/qmainwindowlayout.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 widgets module 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 "qmainwindowlayout_p.h"
 
30
#include "qdockseparator_p.h"
 
31
#include "qdockwidgetlayout_p.h"
 
32
 
 
33
#include "qdockwidget.h"
 
34
#include "qmainwindow.h"
 
35
#include "qtoolbar.h"
 
36
 
 
37
#include <qapplication.h>
 
38
#include <qdebug.h>
 
39
#include <qstatusbar.h>
 
40
#include <qstyle.h>
 
41
#include <qvarlengtharray.h>
 
42
#include <qstack.h>
 
43
#include <qmap.h>
 
44
 
 
45
#include <private/qlayoutengine_p.h>
 
46
 
 
47
// #define LAYOUT_DEBUG
 
48
#if defined(LAYOUT_DEBUG)
 
49
#  define DEBUG qDebug
 
50
#else
 
51
#  define DEBUG if(false)qDebug
 
52
#endif
 
53
 
 
54
// #define LAYOUT_DEBUG_VERBOSE
 
55
#if defined(LAYOUT_DEBUG_VERBOSE)
 
56
#  define VDEBUG qDebug
 
57
#else
 
58
#  define VDEBUG if(false)qDebug
 
59
#endif
 
60
 
 
61
// #define TOOLBAR_DEBUG
 
62
#if defined(TOOLBAR_DEBUG)
 
63
#  define TBDEBUG qDebug
 
64
#else
 
65
#  define TBDEBUG if(false)qDebug
 
66
#endif
 
67
 
 
68
 
 
69
 
 
70
enum POSITION {
 
71
    LEFT,
 
72
    RIGHT,
 
73
    TOP,
 
74
    BOTTOM,
 
75
    CENTER,
 
76
    NPOSITIONS
 
77
};
 
78
 
 
79
static inline uint areaForPosition(int pos)
 
80
{ return ((1u << pos) & 0xf); }
 
81
 
 
82
static inline POSITION positionForArea(uint area)
 
83
{
 
84
    switch (area) {
 
85
    case Qt::LeftDockWidgetArea:   return LEFT;
 
86
    case Qt::RightDockWidgetArea:  return RIGHT;
 
87
    case Qt::TopDockWidgetArea:    return TOP;
 
88
    case Qt::BottomDockWidgetArea: return BOTTOM;
 
89
    default: break;
 
90
    }
 
91
    return CENTER;
 
92
}
 
93
 
 
94
static inline POSITION positionForArea(Qt::ToolBarArea area)
 
95
{
 
96
    switch (area) {
 
97
    case Qt::LeftToolBarArea:   return LEFT;
 
98
    case Qt::RightToolBarArea:  return RIGHT;
 
99
    case Qt::TopToolBarArea:    return TOP;
 
100
    case Qt::BottomToolBarArea: return BOTTOM;
 
101
    default: break;
 
102
    }
 
103
    return CENTER;
 
104
}
 
105
 
 
106
static inline int pick(POSITION p, const QSize &s)
 
107
{ return p == TOP || p == BOTTOM ? s.height() : s.width(); }
 
108
 
 
109
static inline int pick(POSITION p, const QPoint &pt)
 
110
{ return p == TOP || p == BOTTOM ? pt.y() : pt.x(); }
 
111
 
 
112
static inline void set(POSITION p, QSize &s, int x)
 
113
{ if (p == LEFT || p == RIGHT) s.setWidth(x); else s.setHeight(x); }
 
114
 
 
115
static inline int pick_perp(POSITION p, const QSize &s)
 
116
{ return p == TOP || p == BOTTOM ? s.width() : s.height(); }
 
117
 
 
118
static inline int pick_perp(POSITION p, const QPoint &pt)
 
119
{ return p == TOP || p == BOTTOM ? pt.x() : pt.y(); }
 
120
 
 
121
static inline void set_perp(POSITION p, QSize &s, int x)
 
122
{ if (p == TOP || p == BOTTOM) s.setWidth(x); else s.setHeight(x); }
 
123
 
 
124
static inline void set_perp(POSITION p, QPoint &pt, int x)
 
125
{ if (p == TOP || p == BOTTOM) pt.setX(x); else pt.setY(x); }
 
126
 
 
127
class QMainWindowLayoutItem : public QWidgetItem
 
128
{
 
129
public:
 
130
    inline QMainWindowLayoutItem(QWidget *w, const QRect &r)
 
131
        : QWidgetItem(w), rect(r)
 
132
    { }
 
133
 
 
134
    inline QSize sizeHint() const
 
135
    { return rect.size(); }
 
136
    inline void setGeometry( const QRect &r)
 
137
    { rect = r; }
 
138
    inline QRect geometry() const
 
139
    { return rect; }
 
140
    inline bool isEmpty() const
 
141
    { return false; }
 
142
 
 
143
    QWidget *widget;
 
144
    QRect rect;
 
145
};
 
146
 
 
147
 
 
148
QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow)
 
149
    : QLayout(mainwindow), statusbar(0), relayout_type(QInternal::RelayoutNormal), save_layout_info(0),
 
150
      save_tb_layout_info(0)
 
151
{
 
152
    setObjectName(mainwindow->objectName() + "_layout");
 
153
 
 
154
    corners[Qt::TopLeftCorner]     = Qt::TopDockWidgetArea;
 
155
    corners[Qt::TopRightCorner]    = Qt::TopDockWidgetArea;
 
156
    corners[Qt::BottomLeftCorner]  = Qt::BottomDockWidgetArea;
 
157
    corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea;
 
158
 
 
159
    for (int i = 0; i < Qt::NDockWidgetAreas + 1; ++i) {
 
160
        QMainWindowLayoutInfo info;
 
161
        info.item = 0;
 
162
        info.sep = 0;
 
163
        info.is_dummy = false;
 
164
        layout_info.append(info);
 
165
    }
 
166
}
 
167
 
 
168
QMainWindowLayout::~QMainWindowLayout()
 
169
{
 
170
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
171
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
172
        for (int i = 0; i < lineInfo.list.size(); ++i)
 
173
            delete lineInfo.list.at(i).item;
 
174
    }
 
175
    tb_layout_info.clear();
 
176
    for (int i = 0; i < NPOSITIONS; ++i) {
 
177
        delete layout_info[i].item;
 
178
        if (layout_info[i].sep)
 
179
            delete layout_info[i].sep->widget();
 
180
        delete layout_info[i].sep;
 
181
        layout_info[i].item = 0;
 
182
        layout_info[i].sep = 0;
 
183
    }
 
184
    delete statusbar;
 
185
}
 
186
 
 
187
QStatusBar *QMainWindowLayout::statusBar() const
 
188
{ return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
 
189
 
 
190
void QMainWindowLayout::setStatusBar(QStatusBar *sb)
 
191
{
 
192
    if (sb)
 
193
        addChildWidget(sb);
 
194
    delete statusbar;
 
195
    statusbar = sb ? new QWidgetItem(sb) : 0;
 
196
}
 
197
 
 
198
QWidget *QMainWindowLayout::centralWidget() const
 
199
{ return layout_info[CENTER].item ? layout_info[CENTER].item->widget() : 0; }
 
200
 
 
201
void QMainWindowLayout::setCentralWidget(QWidget *cw)
 
202
{
 
203
    delete layout_info[CENTER].item;
 
204
    if (cw) {
 
205
        addChildWidget(cw);
 
206
        layout_info[CENTER].item = new QWidgetItem(cw);
 
207
    } else {
 
208
        layout_info[CENTER].item = 0;
 
209
    }
 
210
    layout_info[CENTER].size = QSize();
 
211
    invalidate();
 
212
}
 
213
 
 
214
void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
 
215
{
 
216
    ToolBarLineInfo newLine;
 
217
    newLine.pos = positionForArea(area);
 
218
    switch (newLine.pos) {
 
219
    case TOP:
 
220
    case BOTTOM:
 
221
        {
 
222
            for (int line = 0; line < tb_layout_info.size(); ++line) {
 
223
                ToolBarLineInfo &lineInfo = tb_layout_info[line];
 
224
                if (lineInfo.pos == LEFT || lineInfo.pos == RIGHT) {
 
225
                    tb_layout_info.insert(line, newLine);
 
226
                    return;
 
227
                }
 
228
            }
 
229
        }
 
230
        // fall through intended
 
231
    default:
 
232
        tb_layout_info.append(newLine);
 
233
        TBDEBUG() << "appended new line";
 
234
        break;
 
235
    }
 
236
}
 
237
 
 
238
void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
 
239
{
 
240
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
241
        ToolBarLineInfo &lineInfo = tb_layout_info[line];
 
242
        for (int i = 0; i < lineInfo.list.size(); ++i) {
 
243
            const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
244
            if (info.item->widget() == before) {
 
245
                ToolBarLineInfo newLine;
 
246
                newLine.pos = lineInfo.pos;
 
247
                for (; i < lineInfo.list.size(); ++i)
 
248
                    newLine.list += lineInfo.list.takeAt(i);
 
249
                tb_layout_info.insert(line + 1, newLine);
 
250
                return;
 
251
            }
 
252
        }
 
253
    }
 
254
}
 
255
 
 
256
/*!
 
257
    Adds \a toolbar to \a area, continuing the current line.
 
258
*/
 
259
void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
 
260
                                   QToolBar *toolbar,
 
261
                                   bool needAddChildWidget)
 
262
{
 
263
    if (needAddChildWidget)
 
264
        addChildWidget(toolbar);
 
265
    else
 
266
        removeToolBarInfo(toolbar);
 
267
 
 
268
    POSITION pos = positionForArea(area);
 
269
    // see if we have an existing line in the tb - append it in the last in line
 
270
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
271
        if (tb_layout_info.at(line).pos == pos) {
 
272
            while (line < tb_layout_info.size() - 1 && tb_layout_info.at(line + 1).pos == pos)
 
273
                ++line;
 
274
 
 
275
            switch (pos) {
 
276
            case TOP:
 
277
            case BOTTOM:
 
278
                toolbar->setOrientation(Qt::Horizontal);
 
279
                break;
 
280
            case LEFT:
 
281
            case RIGHT:
 
282
                toolbar->setOrientation(Qt::Vertical);
 
283
                break;
 
284
            default:
 
285
                break;
 
286
            }
 
287
 
 
288
            ToolBarLineInfo &lineInfo = tb_layout_info[line];
 
289
            ToolBarLayoutInfo newinfo;
 
290
            newinfo.item = new QWidgetItem(toolbar);
 
291
            lineInfo.list.append(newinfo);
 
292
            return;
 
293
        }
 
294
    }
 
295
 
 
296
    // no line to continue, add one and recurse
 
297
    addToolBarBreak(area);
 
298
    addToolBar(area, toolbar, false);
 
299
}
 
300
 
 
301
/*!
 
302
    Adds \a toolbar before \a before
 
303
*/
 
304
void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
 
305
{
 
306
    addChildWidget(toolbar);
 
307
 
 
308
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
309
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
310
        for (int i = 0; i < lineInfo.list.size(); ++i) {
 
311
            const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
312
            if (info.item->widget() == before) {
 
313
 
 
314
                ToolBarLayoutInfo newInfo;
 
315
                newInfo.item = new QWidgetItem(toolbar);
 
316
                tb_layout_info[line].list.insert(i, newInfo);
 
317
                return;
 
318
            }
 
319
        }
 
320
    }
 
321
}
 
322
 
 
323
Qt::ToolBarArea QMainWindowLayout::toolBarArea(QToolBar *toolbar) const
 
324
{
 
325
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
326
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
327
        for (int i = 0; i < lineInfo.list.size(); ++i) {
 
328
            const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
329
            if (info.item->widget() == toolbar)
 
330
                return static_cast<Qt::ToolBarArea>(areaForPosition(lineInfo.pos));
 
331
        }
 
332
    }
 
333
    Q_ASSERT_X(false, "QMainWindow::toolBarArea", "'toolbar' is not managed by this main window.");
 
334
    return Qt::TopToolBarArea;
 
335
}
 
336
 
 
337
QDockWidgetLayout *QMainWindowLayout::layoutForArea(Qt::DockWidgetArea area)
 
338
{
 
339
    POSITION pos = positionForArea(area);
 
340
    QMainWindowLayoutInfo &info = layout_info[pos];
 
341
    QDockWidgetLayout *l = 0;
 
342
 
 
343
    if (!info.item) {
 
344
        // create new dock window layout
 
345
        static const Qt::Orientation orientations[] = {
 
346
            Qt::Vertical,   // LEFT
 
347
            Qt::Vertical,   // RIGHT
 
348
            Qt::Horizontal, // TOP
 
349
            Qt::Horizontal, // BOTTOM
 
350
        };
 
351
 
 
352
        l = new QDockWidgetLayout(area, orientations[pos]);
 
353
        l->setParent(this);
 
354
        l->setObjectName(objectName() + "_dockwidgetLayout" + QString::number(area, 16));
 
355
 
 
356
        info.item = l;
 
357
 
 
358
        // create separator
 
359
        Q_ASSERT(!info.sep);
 
360
        info.sep = new QWidgetItem(new QDockSeparator(l, parentWidget()));
 
361
    } else {
 
362
        l = qobject_cast<QDockWidgetLayout *>(info.item->layout());
 
363
        Q_ASSERT(l != 0);
 
364
    }
 
365
    return l;
 
366
}
 
367
 
 
368
void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget,
 
369
                                      Qt::Orientation orientation)
 
370
{
 
371
    removeRecursive(dockwidget);
 
372
 
 
373
    QDockWidgetLayout * const layout = layoutForArea(area);
 
374
    layout->extend(dockwidget, orientation);
 
375
}
 
376
 
 
377
void QMainWindowLayout::splitDockWidget(QDockWidget *after, QDockWidget *dockwidget,
 
378
                                        Qt::Orientation orientation)
 
379
{
 
380
    removeRecursive(dockwidget);
 
381
 
 
382
    const Qt::DockWidgetArea area = dockWidgetArea(after);
 
383
    QDockWidgetLayout * const layout = layoutForArea(area);
 
384
    layout->split(after, dockwidget, (orientation == Qt::Horizontal
 
385
                                      ? Qt::RightDockWidgetArea
 
386
                                      : Qt::BottomDockWidgetArea));
 
387
}
 
388
 
 
389
static bool findWidgetRecursively(QLayoutItem *li, QWidget *w)
 
390
{
 
391
    QLayout *lay = li->layout();
 
392
    if (!lay)
 
393
        return false;
 
394
    int i = 0;
 
395
    QLayoutItem *child;
 
396
    while ((child = lay->itemAt(i))) {
 
397
        if (child->widget() == w) {
 
398
            return true;
 
399
        } else if (findWidgetRecursively(child, w)) {
 
400
            return true;
 
401
        } else {
 
402
            ++i;
 
403
        }
 
404
    }
 
405
    return false;
 
406
}
 
407
 
 
408
Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(QDockWidget *dockwidget) const
 
409
{
 
410
    for (int pos = 0; pos < NPOSITIONS - 1; ++pos) {
 
411
        if (!layout_info[pos].item)
 
412
            continue;
 
413
        if (findWidgetRecursively(layout_info[pos].item, dockwidget))
 
414
            return static_cast<Qt::DockWidgetArea>(areaForPosition(pos));
 
415
    }
 
416
    Q_ASSERT_X(false, "QMainWindow::dockWidgetArea",
 
417
               "'dockwidget' is not managed by this main window.");
 
418
    return Qt::TopDockWidgetArea;
 
419
 
 
420
}
 
421
 
 
422
void QMainWindowLayout::saveState(QDataStream &stream) const
 
423
{
 
424
    // save toolbar state
 
425
    stream << (uchar) ToolBarStateMarker;
 
426
    stream << tb_layout_info.size(); // number of toolbar lines
 
427
    if (!tb_layout_info.isEmpty()) {
 
428
        for (int line = 0; line < tb_layout_info.size(); ++line) {
 
429
            const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
430
            stream << lineInfo.pos;
 
431
            stream << lineInfo.list.size();
 
432
            for (int i = 0; i < lineInfo.list.size(); ++i) {
 
433
                const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
434
                QWidget *widget = info.item->widget();
 
435
                if (widget->objectName().isEmpty()) {
 
436
                    qWarning("QMainWindow::saveState(): 'objectName' not set for QToolBar "
 
437
                             "%p '%s', using 'windowTitle' instead",
 
438
                             widget, widget->windowTitle().toLocal8Bit().constData());
 
439
                    stream << widget->windowTitle();
 
440
                } else {
 
441
                    stream << widget->objectName();
 
442
                }
 
443
                stream << (uchar) !widget->isHidden();
 
444
                stream << info.pos;
 
445
                stream << info.size;
 
446
                stream << info.offset;
 
447
            }
 
448
        }
 
449
    }
 
450
 
 
451
    // save dockwidget state
 
452
    stream << (uchar) DockWidgetStateMarker;
 
453
    int x = 0;
 
454
    for (int i = 0; i < NPOSITIONS - 1; ++i) {
 
455
        if (!layout_info[i].item)
 
456
            continue;
 
457
        ++x;
 
458
    }
 
459
    stream << x;
 
460
    for (int i = 0; i < NPOSITIONS - 1; ++i) {
 
461
        if (!layout_info[i].item) {
 
462
            continue;
 
463
        }
 
464
        stream << i;
 
465
        stream << layout_info[i].size;
 
466
        const QDockWidgetLayout * const layout =
 
467
            qobject_cast<const QDockWidgetLayout *>(layout_info[i].item->layout());
 
468
        Q_ASSERT(layout != 0);
 
469
        layout->saveState(stream);
 
470
    }
 
471
 
 
472
    // save center widget state
 
473
    stream << layout_info[CENTER].size;
 
474
}
 
475
 
 
476
bool QMainWindowLayout::restoreState(QDataStream &stream)
 
477
{
 
478
    // restore toolbar layout
 
479
    uchar tmarker;
 
480
    stream >> tmarker;
 
481
    if (tmarker != ToolBarStateMarker)
 
482
        return false;
 
483
 
 
484
    int lines;
 
485
    stream >> lines;
 
486
    QList<ToolBarLineInfo> toolBarState;
 
487
    QList<QToolBar *> toolbars = qFindChildren<QToolBar *>(parentWidget());
 
488
    for (int line = 0; line < lines; ++line) {
 
489
        ToolBarLineInfo lineInfo;
 
490
        stream >> lineInfo.pos;
 
491
        int size;
 
492
        stream >> size;
 
493
        for (int i = 0; i < size; ++i) {
 
494
            ToolBarLayoutInfo info;
 
495
            QString objectName;
 
496
            stream >> objectName;
 
497
            uchar shown;
 
498
            stream >> shown;
 
499
            stream >> info.pos;
 
500
            stream >> info.size;
 
501
            stream >> info.offset;
 
502
 
 
503
            // find toolbar
 
504
            QToolBar *toolbar = 0;
 
505
            for (int t = 0; t < toolbars.size(); ++t) {
 
506
                QToolBar *tb = toolbars.at(t);
 
507
                if (tb && tb->objectName() == objectName) {
 
508
                    toolbar = tb;
 
509
                    toolbars[t] = 0;
 
510
                    break;
 
511
                }
 
512
            }
 
513
            if (!toolbar) {
 
514
                qWarning("QMainWindow::restoreState(): cannot find a QToolBar named "
 
515
                         "'%s', trying to match using 'windowTitle' instead.",
 
516
                         objectName.toLocal8Bit().constData());
 
517
                // try matching the window title
 
518
                for (int t = 0; t < toolbars.size(); ++t) {
 
519
                    QToolBar *tb = toolbars.at(t);
 
520
                    if (tb && tb->windowTitle() == objectName) {
 
521
                        toolbar = tb;
 
522
                        break;
 
523
                    }
 
524
                }
 
525
                if (!toolbar) {
 
526
                    qWarning("QMainWindow::restoreState(): cannot find a QToolBar with "
 
527
                             "matching 'windowTitle' (looking for '%s').",
 
528
                             objectName.toLocal8Bit().constData());
 
529
                    continue;
 
530
                }
 
531
            }
 
532
 
 
533
            info.item = new QWidgetItem(toolbar);
 
534
            toolbar->setVisible(shown);
 
535
            toolbar->setOrientation((lineInfo.pos == LEFT  || lineInfo.pos == RIGHT)
 
536
                                    ? Qt::Vertical
 
537
                                    : Qt::Horizontal);
 
538
            lineInfo.list << info;
 
539
        }
 
540
        toolBarState << lineInfo;
 
541
    }
 
542
 
 
543
    if (stream.status() != QDataStream::Ok)
 
544
        return false;
 
545
 
 
546
    // replace existing toolbar layout
 
547
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
548
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
549
        for (int i = 0; i < lineInfo.list.size(); ++i)
 
550
            delete lineInfo.list.at(i).item;
 
551
    }
 
552
    tb_layout_info = toolBarState;
 
553
 
 
554
    // restore dockwidget layout
 
555
    uchar dmarker;
 
556
    stream >> dmarker;
 
557
    if (dmarker != DockWidgetStateMarker)
 
558
        return false;
 
559
 
 
560
    save_layout_info = new QVector<QMainWindowLayoutInfo>(layout_info);
 
561
 
 
562
    // clear out our working copy
 
563
    for (int i = 0; i < NPOSITIONS - 1; ++i) {
 
564
        layout_info[i].item = 0;
 
565
        layout_info[i].sep = 0;
 
566
        layout_info[i].size = QSize();
 
567
        layout_info[i].is_dummy = false;
 
568
    }
 
569
 
 
570
    int areas;
 
571
    stream >> areas;
 
572
    for (int area = 0; area < areas; ++area) {
 
573
        int pos;
 
574
        stream >> pos;
 
575
        stream >> layout_info[pos].size;
 
576
        QDockWidgetLayout * const layout =
 
577
            layoutForArea(static_cast<Qt::DockWidgetArea>(areaForPosition(pos)));
 
578
        if (!layout->restoreState(stream)) {
 
579
            stream.setStatus(QDataStream::ReadCorruptData);
 
580
            break;
 
581
        }
 
582
    }
 
583
 
 
584
    // restore center widget size
 
585
    stream >> layout_info[CENTER].size;
 
586
 
 
587
    if (stream.status() != QDataStream::Ok) {
 
588
        // restore failed, get rid of the evidence
 
589
        for (int i = 0; i < NPOSITIONS - 1; ++i) {
 
590
            if (layout_info[i].sep)
 
591
                delete layout_info[i].sep->widget();
 
592
            delete layout_info[i].sep;
 
593
            delete layout_info[i].item;
 
594
        }
 
595
        layout_info = *save_layout_info;
 
596
 
 
597
        delete save_layout_info;
 
598
        save_layout_info = 0;
 
599
        relayout_type = QInternal::RelayoutNormal;
 
600
 
 
601
        return false;
 
602
    }
 
603
 
 
604
    // replace existing dockwidget layout
 
605
    for (int i = 0; i < NPOSITIONS - 1; ++i) {
 
606
        if ((*save_layout_info)[i].sep)
 
607
            delete (*save_layout_info)[i].sep->widget();
 
608
        delete (*save_layout_info)[i].sep;
 
609
        delete (*save_layout_info)[i].item;
 
610
    }
 
611
 
 
612
    delete save_layout_info;
 
613
    save_layout_info = 0;
 
614
    relayout_type = QInternal::RelayoutNormal;
 
615
 
 
616
    return true;
 
617
}
 
618
 
 
619
 
 
620
int QMainWindowLayout::count() const
 
621
{
 
622
    qWarning("QMainWindowLayout::count()");
 
623
    return 10; //#################################################
 
624
}
 
625
 
 
626
QLayoutItem *QMainWindowLayout::itemAt(int index) const
 
627
{
 
628
    int x = 0;
 
629
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
630
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
631
        for (int i = 0; i < lineInfo.list.size(); ++i) {
 
632
            if (x++ == index) {
 
633
                const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
634
                return info.item;
 
635
            }
 
636
        }
 
637
    }
 
638
    for (int i = 0; i < NPOSITIONS; ++i) {
 
639
        if (!layout_info[i].item)
 
640
            continue;
 
641
        if (x++ == index)
 
642
            return layout_info[i].item;
 
643
    }
 
644
    return 0;
 
645
}
 
646
 
 
647
QLayoutItem *QMainWindowLayout::takeAt(int index)
 
648
{
 
649
    DEBUG("QMainWindowLayout::takeAt: index %d", index);
 
650
 
 
651
    int x = 0;
 
652
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
653
        ToolBarLineInfo &lineInfo = tb_layout_info[line];
 
654
        for (int i = 0; i < lineInfo.list.size(); ++i) {
 
655
            if (x++ == index) {
 
656
                QLayoutItem *ret = lineInfo.list.at(i).item;
 
657
                lineInfo.list.removeAt(i);
 
658
                if (lineInfo.list.size() == 0)
 
659
                    tb_layout_info.removeAt(line);
 
660
                return ret;
 
661
            }
 
662
        }
 
663
    }
 
664
 
 
665
    for (int i = 0; i < NPOSITIONS; ++i) {
 
666
        if (!layout_info[i].item) continue;
 
667
        if (x++ == index) {
 
668
            VDEBUG() << "  where" << i;
 
669
            QLayoutItem *ret = layout_info[i].item;
 
670
 
 
671
            if (!save_layout_info) {
 
672
                layout_info[i].size = QSize();
 
673
 
 
674
                if (layout_info[i].sep) {
 
675
                    delete layout_info[i].sep->widget();
 
676
                    delete layout_info[i].sep;
 
677
                }
 
678
            }
 
679
 
 
680
            layout_info[i].item = 0;
 
681
            layout_info[i].sep = 0;
 
682
 
 
683
            VDEBUG() << "END of QMainWindowLayout::takeAt (removed" << i << ")";
 
684
            return ret;
 
685
        }
 
686
    }
 
687
 
 
688
    VDEBUG() << "END of QMainWindowLayout::takeAt (not found)";
 
689
    return 0;
 
690
}
 
691
 
 
692
/*
 
693
  Fixes the mininum and maximum sizes depending on the current corner
 
694
  configuration.
 
695
*/
 
696
void fix_minmax(QVector<QLayoutStruct> &ls,
 
697
                const QMainWindowLayout * const layout,
 
698
                POSITION pos)
 
699
{
 
700
    const Qt::DockWidgetArea area = static_cast<Qt::DockWidgetArea>(areaForPosition(pos));
 
701
 
 
702
    const struct
 
703
    {
 
704
        Qt::Corner corner1, corner2;
 
705
        POSITION perp1, perp2;
 
706
    } order[] = {
 
707
        // LEFT
 
708
        {
 
709
            Qt::TopLeftCorner,
 
710
            Qt::BottomLeftCorner,
 
711
            TOP,
 
712
            BOTTOM
 
713
        },
 
714
        // RIGHT
 
715
        {
 
716
            Qt::TopRightCorner,
 
717
            Qt::BottomRightCorner,
 
718
            TOP,
 
719
            BOTTOM
 
720
        },
 
721
        // TOP
 
722
        {
 
723
            Qt::TopLeftCorner,
 
724
            Qt::TopRightCorner,
 
725
            LEFT,
 
726
            RIGHT
 
727
        },
 
728
        // BOTTOM
 
729
        {
 
730
            Qt::BottomLeftCorner,
 
731
            Qt::BottomRightCorner,
 
732
            LEFT,
 
733
            RIGHT
 
734
        }
 
735
    };
 
736
 
 
737
    if (!layout->layout_info[pos].item)
 
738
        return;
 
739
 
 
740
    if ((layout->corners[order[pos].corner1] != area
 
741
         || !layout->layout_info[order[pos].perp1].item)
 
742
        && (layout->corners[order[pos].corner2] != area
 
743
            || !layout->layout_info[order[pos].perp2].item)) {
 
744
        // if the area does not occupy any corner, we constrain the
 
745
        // minimum size of the center to the minimum size of the area
 
746
        ls[1].minimumSize = qMax(pick_perp(pos, layout->layout_info[pos].item->minimumSize()),
 
747
                                 ls[1].minimumSize);
 
748
        ls[1].maximumSize = qMin(pick_perp(pos, layout->layout_info[pos].item->maximumSize()),
 
749
                                 ls[1].maximumSize);
 
750
    } else {
 
751
        // if the area occupies only a single corner, then we
 
752
        // distribute the minimum size of the area across the center
 
753
        // and opposite side equally
 
754
        const int min = pick_perp(pos, layout->layout_info[pos].item->minimumSize());
 
755
        if (layout->layout_info[order[pos].perp1].item
 
756
            && layout->corners[order[pos].corner1] == area
 
757
            && layout->corners[order[pos].corner2] != area) {
 
758
            ls[1].minimumSize = qMax(ls[1].minimumSize, min - ls[0].minimumSize);
 
759
        } else if (layout->layout_info[order[pos].perp2].item
 
760
                   && layout->corners[order[pos].corner2] == area
 
761
                   && layout->corners[order[pos].corner1] != area) {
 
762
            ls[1].minimumSize = qMax(ls[1].minimumSize, min - ls[2].minimumSize);
 
763
        }
 
764
    }
 
765
}
 
766
 
 
767
/*
 
768
  Initializes the layout struct with information from the specified
 
769
  dock window area.
 
770
*/
 
771
static void init_layout_struct(const QMainWindowLayout * const layout,
 
772
                               QLayoutStruct &ls,
 
773
                               const POSITION pos,
 
774
                               const int ext)
 
775
{
 
776
    const QMainWindowLayout::QMainWindowLayoutInfo &info = layout->layout_info[pos];
 
777
    ls.empty = info.item->isEmpty();
 
778
    if (!ls.empty) {
 
779
        ls.minimumSize = pick(pos, info.item->minimumSize()) + ext;
 
780
        ls.maximumSize = pick(pos, info.item->maximumSize()) + ext;
 
781
        ls.sizeHint  = !info.size.isEmpty()
 
782
                       ? pick(pos, info.size)
 
783
                       : pick(pos, info.item->sizeHint()) + ext;
 
784
        // constrain sizeHint
 
785
        ls.sizeHint = qMin(ls.maximumSize, ls.sizeHint);
 
786
        ls.sizeHint = qMax(ls.minimumSize, ls.sizeHint);
 
787
    }
 
788
}
 
789
 
 
790
/*
 
791
  Returns the size hint for the first user item in a tb layout. This
 
792
  is used to contrain the minimum size a tb can have.
 
793
*/
 
794
static QSize get_item_sh(QLayout *layout)
 
795
{
 
796
    QLayoutItem *item = layout->itemAt(1);
 
797
    if (item && item->widget())
 
798
        return item->widget()->sizeHint();
 
799
    else
 
800
        return QSize(0, 0);
 
801
}
 
802
 
 
803
/*
 
804
  Returns the real size hint for items in a layout - including sizes
 
805
  for hidden items.
 
806
*/
 
807
static QSize get_real_sh(QLayout *layout)
 
808
{
 
809
    QSize real_sh(0, 0);
 
810
    int i = 0;
 
811
    while (layout && layout->itemAt(i))
 
812
        real_sh += layout->itemAt(i++)->widget()->sizeHint();
 
813
    --i;
 
814
    int spacing = layout->spacing();
 
815
    int margin = layout->margin();
 
816
    real_sh += QSize(spacing*i + margin*2, spacing*i + margin*2);
 
817
    return real_sh;
 
818
}
 
819
 
 
820
void QMainWindowLayout::setGeometry(const QRect &_r)
 
821
{
 
822
    QLayout::setGeometry(_r);
 
823
    QRect r = _r;
 
824
 
 
825
    if (statusbar) {
 
826
        QRect sbr(QPoint(0, 0),
 
827
                  QSize(r.width(), statusbar->heightForWidth(r.width()))
 
828
                  .expandedTo(statusbar->minimumSize()));
 
829
        sbr.moveBottom(r.bottom());
 
830
        statusbar->setGeometry(sbr);
 
831
        r.setBottom(sbr.top() - 1);
 
832
    }
 
833
 
 
834
    // layout toolbars
 
835
 
 
836
    // calculate the respective tool bar rectangles and store the
 
837
    // width/height of the largest tb on each line
 
838
    QVarLengthArray<QRect> tb_rect(tb_layout_info.size());
 
839
 
 
840
    QMap<int, QSize> rest_sz;
 
841
    QStack<QSize> bottom_sz;
 
842
    QStack<QSize> right_sz;
 
843
 
 
844
    QStack<QRect> bottom_rect;
 
845
    QStack<QRect> right_rect;
 
846
 
 
847
    // calculate the width/height of the different tool bar lines -
 
848
    // the order of the bottom and right tool bars needs to reversed
 
849
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
850
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
851
        QSize tb_sz;
 
852
        for (int i = 0; i < lineInfo.list.size(); ++i) {
 
853
            const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
854
            if (info.item->isEmpty())
 
855
                continue;
 
856
            QSize sh = info.item->sizeHint();
 
857
            if (tb_sz.width() < sh.width())
 
858
                tb_sz.setWidth(sh.width());
 
859
            if (tb_sz.height() < sh.height())
 
860
                tb_sz.setHeight(sh.height());
 
861
        }
 
862
        switch(lineInfo.pos) {
 
863
        case TOP:
 
864
        case LEFT:
 
865
            rest_sz[line] = tb_sz;
 
866
            break;
 
867
        case BOTTOM:
 
868
            bottom_sz.push(tb_sz);
 
869
            break;
 
870
        case RIGHT:
 
871
            right_sz.push(tb_sz);
 
872
            break;
 
873
        default:
 
874
            Q_ASSERT_X(false, "QMainWindowLayout", "internal error");
 
875
        }
 
876
    }
 
877
 
 
878
    // calculate the rect for each tool bar line
 
879
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
880
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
881
        QSize tb_sz;
 
882
        tb_rect[line] = r;
 
883
 
 
884
        switch (lineInfo.pos) {
 
885
        case TOP:
 
886
            tb_sz = rest_sz[line];
 
887
            tb_rect[line].setBottom(tb_rect[line].top() + tb_sz.height() - 1);
 
888
            r.setTop(tb_rect[line].bottom() + 1);
 
889
            break;
 
890
        case LEFT:
 
891
            tb_sz = rest_sz[line];
 
892
            tb_rect[line].setRight(tb_rect[line].x() + tb_sz.width() - 1);
 
893
            r.setLeft(tb_rect[line].right() + 1);
 
894
            break;
 
895
        case BOTTOM:
 
896
            tb_sz = bottom_sz.pop();
 
897
            tb_rect[line].setTop(tb_rect[line].bottom() - tb_sz.height() + 1);
 
898
            bottom_rect.push(tb_rect[line]);
 
899
            r.setBottom(tb_rect[line].top() - 1);
 
900
            break;
 
901
        case RIGHT:
 
902
            tb_sz = right_sz.pop();
 
903
            tb_rect[line].setLeft(tb_rect[line].right() - tb_sz.width() + 1);
 
904
            right_rect.push(tb_rect[line]);
 
905
            r.setRight(tb_rect[line].left() - 1);
 
906
            break;
 
907
        default:
 
908
            Q_ASSERT_X(false, "QMainWindowLayout", "internal error");
 
909
        }
 
910
    }
 
911
 
 
912
    // put the right and bottom rects back in correct order
 
913
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
914
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
915
        if (lineInfo.pos == BOTTOM)
 
916
            tb_rect[line] = bottom_rect.pop();
 
917
        else if (lineInfo.pos == RIGHT)
 
918
            tb_rect[line] = right_rect.pop();
 
919
    }
 
920
 
 
921
    // at this point the space for the tool bars have been shaved off
 
922
    // the main rect, continue laying out each tool bar line
 
923
    int tb_fill = 0;
 
924
    if (tb_layout_info.size() != 0) {
 
925
        tb_fill = tb_layout_info.at(0).list.at(0).item->widget()->layout()->margin() * 2
 
926
                  + QApplication::style()->pixelMetric(QStyle::PM_ToolBarHandleExtent)
 
927
                  + QApplication::style()->pixelMetric(QStyle::PM_ToolBarItemSpacing) * 2
 
928
                  + QApplication::style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent);
 
929
    }
 
930
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
931
        ToolBarLineInfo &lineInfo = tb_layout_info[line];
 
932
        int num_tbs = lineInfo.list.size();
 
933
        POSITION where = static_cast<POSITION>(lineInfo.pos);
 
934
 
 
935
        bool first = true;
 
936
        for (int i = 0; i < num_tbs; ++i) {
 
937
            ToolBarLayoutInfo &info = lineInfo.list[i];
 
938
            if (info.item->isEmpty())
 
939
                continue;
 
940
 
 
941
            set(where, info.size, pick(where, tb_rect[line].size()));
 
942
 
 
943
            // position
 
944
            if (first) { // first tool bar can't have an offset
 
945
                first = false;
 
946
                int nextIndex = nextVisible(i, lineInfo);
 
947
                if (nextIndex != -1 && !info.size.isEmpty()
 
948
                    && pick_perp(where, info.offset) > pick_perp(where, info.size)) {
 
949
                    // swap if dragging it past the next one
 
950
                    ToolBarLayoutInfo &next = lineInfo.list[nextIndex];
 
951
                    next.pos = tb_rect[line].topLeft();
 
952
                    next.size.setHeight(pick_perp(where, get_item_sh(next.item->widget()->layout())) + tb_fill);
 
953
                    next.offset = QPoint();
 
954
                    if (where == LEFT || where == RIGHT)
 
955
                        info.pos = QPoint(tb_rect[line].left(), next.pos.y() + next.size.height());
 
956
                    else
 
957
                        info.pos = QPoint(next.pos.x() + next.size.width(), tb_rect[line].top());
 
958
                    info.offset = QPoint(); // has to be done before swapping
 
959
                    lineInfo.list.swap(i, nextIndex);
 
960
                } else {
 
961
                    info.pos = tb_rect[line].topLeft();
 
962
                    info.offset = QPoint();
 
963
                }
 
964
            } else {
 
965
                int prevIndex = prevVisible(i, lineInfo);
 
966
                Q_ASSERT_X(prevIndex != -1, "QMainWindowLayout", "internal error");
 
967
 
 
968
                ToolBarLayoutInfo &prev = lineInfo.list[prevIndex];
 
969
                QSize min_size = get_item_sh(info.item->widget()->layout());
 
970
                set_perp(where, min_size, pick_perp(where, min_size) + tb_fill);
 
971
                const int cur_pt = info.size.isEmpty()
 
972
                                   ? (pick_perp(where, prev.pos) + pick_perp(where, get_real_sh(prev.item->widget()->layout())))
 
973
                                   : pick_perp(where, prev.pos) + pick_perp(where, prev.size);
 
974
                const int prev_min = pick_perp(where, get_item_sh(prev.item->widget()->layout())) + tb_fill;
 
975
                const int snap_dist = 12;
 
976
 
 
977
                info.pos = tb_rect[line].topLeft();
 
978
                set_perp(where, info.pos, cur_pt + pick_perp(where, info.offset));
 
979
 
 
980
                if (pick_perp(where, info.offset) < 0) { // left/up motion
 
981
                    if (pick_perp(where, prev.size) + pick_perp(where, info.offset) >= prev_min) {
 
982
                        // shrink the previous one and increase size of current with same
 
983
                        QSize real_sh = get_real_sh(prev.item->widget()->layout());
 
984
                        QSize sz(0, 0);
 
985
                        set_perp(where, sz, pick_perp(where, info.offset));
 
986
                        if ((pick_perp(where, prev.size) + pick_perp(where, sz)
 
987
                             < pick_perp(where, real_sh) - snap_dist)
 
988
                            || (pick_perp(where, prev.size) + pick_perp(where, sz)
 
989
                                > pick_perp(where, real_sh) + snap_dist))
 
990
                        {
 
991
                            prev.size += sz;
 
992
                            info.size -= sz;
 
993
                        } else {
 
994
                            info.pos = tb_rect[line].topLeft();
 
995
                            set_perp(where, prev.size, pick_perp(where, real_sh));
 
996
                            int pt = pick_perp(where, prev.pos) + pick_perp(where, prev.size);
 
997
                            set_perp(where, info.pos, pt);
 
998
                        }
 
999
                    } else {
 
1000
                        // can't shrink - push the previous one if possible
 
1001
                        bool can_push = false;
 
1002
                        for (int l = i-2; l >= 0; --l) {
 
1003
                            ToolBarLayoutInfo &t = lineInfo.list[l];
 
1004
                            if (pick_perp(where, t.size) + pick_perp(where, info.offset) >
 
1005
                                pick_perp(where, get_item_sh(t.item->widget()->layout())) + tb_fill) {
 
1006
                                QSize sz(0, 0);
 
1007
                                set_perp(where, sz, pick_perp(where, info.offset) + pick_perp(where, prev.size) - prev_min);
 
1008
                                t.size += sz;
 
1009
                                can_push = true;
 
1010
                                break;
 
1011
                            }
 
1012
                        }
 
1013
                        if (can_push) {
 
1014
                            set_perp(where, prev.pos, pick_perp(where, prev.pos) + pick_perp(where, info.offset));
 
1015
                            set_perp(where, prev.size, prev_min);
 
1016
                            set_perp(where, info.pos, pick_perp(where, info.pos) + pick_perp(where, info.offset));
 
1017
                            QSize sz(0,0);
 
1018
                            set_perp(where, sz, pick_perp(where, info.offset));
 
1019
                            info.size -= sz;
 
1020
                        } else {
 
1021
                            QSize sz(0,0);
 
1022
                            set_perp(where, sz, pick_perp(where, prev.size) - prev_min);
 
1023
                            info.size += sz;
 
1024
                            set_perp(where, prev.size, prev_min);
 
1025
                            if (pick_perp(where, info.pos) < pick_perp(where, prev.pos))
 
1026
                                lineInfo.list.swap(i, i-1);
 
1027
                            else
 
1028
                                set_perp(where, info.pos, pick_perp(where, prev.pos) + prev_min);
 
1029
                        }
 
1030
                    }
 
1031
 
 
1032
                } else if (pick_perp(where, info.offset) > 0) { // right/down motion
 
1033
                    if (pick_perp(where, info.size) - pick_perp(where, info.offset) > pick_perp(where, min_size)) {
 
1034
                        QSize real_sh = get_real_sh(prev.item->widget()->layout());
 
1035
                        QSize sz(0, 0);
 
1036
                        set_perp(where, sz, pick_perp(where, info.offset));
 
1037
                        if ((pick_perp(where, prev.size) + pick_perp(where, sz)
 
1038
                             > pick_perp(where, real_sh) + snap_dist)
 
1039
                            || (pick_perp(where, prev.size) < pick_perp(where, real_sh) - snap_dist))
 
1040
                        {
 
1041
                            info.size -= sz;
 
1042
                        } else {
 
1043
                            info.pos = tb_rect[line].topLeft();
 
1044
                            set_perp(where, prev.size, pick_perp(where, real_sh));
 
1045
                            int pt = pick_perp(where, prev.pos) + pick_perp(where, prev.size);
 
1046
                            set_perp(where, info.pos, pt);
 
1047
                        }
 
1048
                    } else {
 
1049
                        bool can_push = false;
 
1050
                        for (int l = i+1; l < num_tbs; ++l) {
 
1051
                            ToolBarLayoutInfo &t = lineInfo.list[l];
 
1052
                            if (pick_perp(where, t.size) - pick_perp(where, info.offset)
 
1053
                                > pick_perp(where, get_item_sh(t.item->widget()->layout())) + tb_fill) {
 
1054
                                QPoint pt;
 
1055
                                set_perp(where, pt, pick_perp(where, info.offset));
 
1056
                                t.pos += pt;
 
1057
                                t.size -= QSize(pt.x(), pt.y());
 
1058
                                can_push = true;
 
1059
                                break;
 
1060
                            }
 
1061
                        }
 
1062
                        if (!can_push) {
 
1063
                            int can_remove = pick_perp(where, info.size) - pick_perp(where, min_size);
 
1064
                            set_perp(where, info.pos, cur_pt + can_remove);
 
1065
                            QSize sz(0, 0);
 
1066
                            set_perp(where, sz, can_remove);
 
1067
                            info.size -= sz;
 
1068
 
 
1069
                            int nextIndex = nextVisible(i, lineInfo);
 
1070
                            if (nextIndex != -1) {
 
1071
                                ToolBarLayoutInfo &t = lineInfo.list[nextIndex];
 
1072
                                if (pick_perp(where, info.pos) + pick_perp(where, info.offset) > pick_perp(where, t.pos))
 
1073
                                    lineInfo.list.swap(i, nextIndex);
 
1074
                            }
 
1075
                        }
 
1076
                    }
 
1077
                }
 
1078
 
 
1079
                // Figure out a suitable default pos/size
 
1080
                if (pick_perp(where, info.pos) < pick_perp(where, prev.pos) + prev_min) {
 
1081
                    int sz = pick_perp(where, prev.item->widget()->sizeHint());
 
1082
                    // use min size hint if size hint is smaller
 
1083
                    if (sz < prev_min)
 
1084
                        sz = prev_min;
 
1085
                    set_perp(where, info.pos, pick_perp(where, prev.pos) + sz);
 
1086
                }
 
1087
                info.offset = QPoint();
 
1088
            }
 
1089
 
 
1090
            // size
 
1091
            if (num_tbs == 1) {
 
1092
                set_perp(where, info.size, pick_perp(where, tb_rect[line].size()));
 
1093
            } else {
 
1094
                int nextIndex = nextVisible(i, lineInfo);
 
1095
                if (nextIndex == -1) {
 
1096
                    // do a sanity check on the pos
 
1097
                    if (pick_perp(where, info.pos) >= pick_perp(where, tb_rect[line].size())) {
 
1098
                        int min = pick_perp(where, get_item_sh(info.item->widget()->layout())) + tb_fill;
 
1099
                        set_perp(where, info.pos, pick_perp(where, tb_rect[line].size()) - min);
 
1100
                    }
 
1101
                    set_perp(where, info.size, pick_perp(where, tb_rect[line].size()));
 
1102
                    if (where == LEFT || where == RIGHT)
 
1103
                        info.size.setHeight(tb_rect[line].bottom() - info.pos.y() + 1);
 
1104
                    else
 
1105
                        info.size.setWidth(tb_rect[line].right() - info.pos.x() + 1);
 
1106
                    if (pick_perp(where, info.size) < 1)
 
1107
                        set_perp(where, info.size, pick_perp(where, get_item_sh(info.item->widget()->layout())) + tb_fill);
 
1108
                }
 
1109
            }
 
1110
 
 
1111
            if (i > 0) {
 
1112
                // assumes that all tbs are positioned at the correct
 
1113
                // pos - fill in the gaps btw them
 
1114
                int prevIndex = prevVisible(i, lineInfo);
 
1115
                if (prevIndex != -1) {
 
1116
                    ToolBarLayoutInfo &prev = lineInfo.list[prevIndex];
 
1117
                    set_perp(where, prev.size, pick_perp(where, info.pos) - pick_perp(where, prev.pos));
 
1118
                }
 
1119
            }
 
1120
        }
 
1121
 
 
1122
        for (int i = 0; i < num_tbs; ++i) {
 
1123
            ToolBarLayoutInfo &info = lineInfo.list[i];
 
1124
            if (info.item->isEmpty()) {
 
1125
                info.size = QSize();
 
1126
                continue;
 
1127
            }
 
1128
 
 
1129
            QRect tb(info.pos, info.size);
 
1130
            tb = QStyle::visualRect(QApplication::layoutDirection(), tb_rect[line], tb);
 
1131
            if (!tb.isEmpty() && relayout_type == QInternal::RelayoutNormal)
 
1132
                info.item->setGeometry(tb);
 
1133
        }
 
1134
    }
 
1135
 
 
1136
    // layout dockwidgets and center widget
 
1137
    const int ext = QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
1138
 
 
1139
    if (relayout_type == QInternal::RelayoutNormal) {
 
1140
        // hide separators for empty layouts
 
1141
        for (int i = 0; i < 4; ++i) {
 
1142
            if (!layout_info[i].item) continue;
 
1143
            layout_info[i].sep->widget()->setHidden(layout_info[i].item->isEmpty());
 
1144
        }
 
1145
    }
 
1146
 
 
1147
    {
 
1148
        QVector<QLayoutStruct> lsH(3);
 
1149
        for (int i = 0; i < 3; ++i)
 
1150
            lsH[i].init();
 
1151
 
 
1152
        if (layout_info[LEFT].item)
 
1153
            init_layout_struct(this, lsH[0], LEFT, ext);
 
1154
        if (layout_info[RIGHT].item)
 
1155
            init_layout_struct(this, lsH[2], RIGHT, ext);
 
1156
 
 
1157
        lsH[1].empty = false;
 
1158
        lsH[1].minimumSize =
 
1159
            layout_info[CENTER].item ? layout_info[CENTER].item->minimumSize().width() : 0;
 
1160
        lsH[1].maximumSize =
 
1161
            layout_info[CENTER].item ? layout_info[CENTER].item->maximumSize().width() : INT_MAX;
 
1162
        lsH[1].sizeHint =
 
1163
            !layout_info[CENTER].size.isEmpty()
 
1164
            ? layout_info[CENTER].size.width()
 
1165
            : (layout_info[CENTER].item ? layout_info[CENTER].item->sizeHint().width() : 0);
 
1166
        // fix min/max sizes
 
1167
        fix_minmax(lsH, this, TOP);
 
1168
        fix_minmax(lsH, this, BOTTOM);
 
1169
        // constrain sizeHint
 
1170
        lsH[1].sizeHint = qMin(lsH[1].maximumSize, lsH[1].sizeHint);
 
1171
        lsH[1].sizeHint = qMax(lsH[1].minimumSize, lsH[1].sizeHint);
 
1172
        // the center widget always gets stretch
 
1173
        lsH[1].stretch = lsH[1].sizeHint;
 
1174
 
 
1175
        qGeomCalc(lsH, 0, lsH.count(), 0, r.width(), 0);
 
1176
 
 
1177
        if (!lsH[0].empty)
 
1178
            layout_info[LEFT].size.setWidth(lsH[0].size);
 
1179
        layout_info[CENTER].size.setWidth(lsH[1].size);
 
1180
        if (!lsH[2].empty)
 
1181
            layout_info[RIGHT].size.setWidth(lsH[2].size);
 
1182
    }
 
1183
 
 
1184
    {
 
1185
        QVector<QLayoutStruct> lsV(3);
 
1186
        for (int i = 0; i < 3; ++i)
 
1187
            lsV[i].init();
 
1188
 
 
1189
        if (layout_info[TOP].item)
 
1190
            init_layout_struct(this, lsV[0], TOP, ext);
 
1191
        if (layout_info[BOTTOM].item)
 
1192
            init_layout_struct(this, lsV[2], BOTTOM, ext);
 
1193
 
 
1194
        lsV[1].empty = false;
 
1195
        lsV[1].minimumSize =
 
1196
            layout_info[CENTER].item ? layout_info[CENTER].item->minimumSize().height() : 0;
 
1197
        lsV[1].maximumSize =
 
1198
            layout_info[CENTER].item ? layout_info[CENTER].item->maximumSize().height() : INT_MAX;
 
1199
        lsV[1].sizeHint =
 
1200
            !layout_info[CENTER].size.isEmpty()
 
1201
            ? layout_info[CENTER].size.height()
 
1202
            : (layout_info[CENTER].item ? layout_info[CENTER].item->sizeHint().height() : 0);
 
1203
        // fix min/max sizes
 
1204
        fix_minmax(lsV, this, LEFT);
 
1205
        fix_minmax(lsV, this, RIGHT);
 
1206
        // constrain sizeHint
 
1207
        lsV[1].sizeHint = qMin(lsV[1].maximumSize, lsV[1].sizeHint);
 
1208
        lsV[1].sizeHint = qMax(lsV[1].minimumSize, lsV[1].sizeHint);
 
1209
        // the center widget always gets stretch
 
1210
        lsV[1].stretch = lsV[1].sizeHint;
 
1211
 
 
1212
        qGeomCalc(lsV, 0, lsV.count(), 0, r.height(), 0);
 
1213
 
 
1214
        if (!lsV[0].empty)
 
1215
            layout_info[TOP].size.setHeight(lsV[0].size);
 
1216
        layout_info[CENTER].size.setHeight(lsV[1].size);
 
1217
        if (!lsV[2].empty)
 
1218
            layout_info[BOTTOM].size.setHeight(lsV[2].size);
 
1219
    }
 
1220
 
 
1221
    QRect rect[4],
 
1222
        &left   = rect[LEFT],
 
1223
        &right  = rect[RIGHT],
 
1224
        &top    = rect[TOP],
 
1225
        &bottom = rect[BOTTOM];
 
1226
 
 
1227
    for (int i = 0; i < 4; ++i) {
 
1228
        if (!layout_info[i].item || layout_info[i].item->isEmpty())
 
1229
            rect[i].setSize(QSize(0, 0));
 
1230
        else
 
1231
            rect[i].setSize(layout_info[i].size);
 
1232
    }
 
1233
 
 
1234
    left.moveLeft(r.left());
 
1235
    right.moveRight(r.right());
 
1236
    top.moveTop(r.top());
 
1237
    bottom.moveBottom(r.bottom());
 
1238
 
 
1239
    switch (corners[Qt::TopLeftCorner]) {
 
1240
    case Qt::TopDockWidgetArea:
 
1241
        top.setLeft(r.left());
 
1242
        left.setTop(top.bottom() + 1);
 
1243
        break;
 
1244
    case Qt::LeftDockWidgetArea:
 
1245
        left.setTop(r.top());
 
1246
        top.setLeft(left.right() + 1);
 
1247
        break;
 
1248
    default:
 
1249
        Q_ASSERT(false);
 
1250
    }
 
1251
 
 
1252
    switch (corners[Qt::BottomLeftCorner]) {
 
1253
    case Qt::BottomDockWidgetArea:
 
1254
        bottom.setLeft(r.left());
 
1255
        left.setBottom(bottom.top() - 1);
 
1256
        break;
 
1257
    case Qt::LeftDockWidgetArea:
 
1258
        left.setBottom(r.bottom());
 
1259
        bottom.setLeft(left.right() + 1);
 
1260
        break;
 
1261
    default:
 
1262
        Q_ASSERT(false);
 
1263
    }
 
1264
 
 
1265
    switch (corners[Qt::TopRightCorner]) {
 
1266
    case Qt::TopDockWidgetArea:
 
1267
        top.setRight(r.right());
 
1268
        right.setTop(top.bottom() + 1);
 
1269
        break;
 
1270
    case Qt::RightDockWidgetArea:
 
1271
        right.setTop(r.top());
 
1272
        top.setRight(right.left() - 1);
 
1273
        break;
 
1274
    default:
 
1275
        Q_ASSERT(false);
 
1276
    }
 
1277
 
 
1278
    switch (corners[Qt::BottomRightCorner]) {
 
1279
    case Qt::BottomDockWidgetArea:
 
1280
        bottom.setRight(r.right());
 
1281
        right.setBottom(bottom.top() - 1);
 
1282
        break;
 
1283
    case Qt::RightDockWidgetArea:
 
1284
        right.setBottom(r.bottom());
 
1285
        bottom.setRight(right.left() - 1);
 
1286
        break;
 
1287
    default:
 
1288
        Q_ASSERT(false);
 
1289
    }
 
1290
 
 
1291
    for (int i = 0; i < 4; ++i) {
 
1292
        if (!layout_info[i].item) continue;
 
1293
        layout_info[i].size = rect[i].size();
 
1294
        QRect x, s;
 
1295
 
 
1296
        switch (i) {
 
1297
        case LEFT:
 
1298
            x.setCoords(rect[i].left(),
 
1299
                        rect[i].top(),
 
1300
                        rect[i].right() - ext,
 
1301
                        rect[i].bottom());
 
1302
            s.setCoords(x.right() + 1,
 
1303
                        rect[i].top(),
 
1304
                        rect[i].right(),
 
1305
                        rect[i].bottom());
 
1306
            break;
 
1307
        case RIGHT:
 
1308
            x.setCoords(rect[i].left() + ext,
 
1309
                        rect[i].top(),
 
1310
                        rect[i].right(),
 
1311
                        rect[i].bottom());
 
1312
            s.setCoords(rect[i].left(),
 
1313
                        rect[i].top(),
 
1314
                        x.left() - 1,
 
1315
                        rect[i].bottom());
 
1316
            break;
 
1317
        case TOP:
 
1318
            x.setCoords(rect[i].left(),
 
1319
                        rect[i].top(),
 
1320
                        rect[i].right(),
 
1321
                        rect[i].bottom() - ext);
 
1322
            s.setCoords(rect[i].left(),
 
1323
                        x.bottom() + 1,
 
1324
                        rect[i].right(),
 
1325
                        rect[i].bottom());
 
1326
            break;
 
1327
        case BOTTOM:
 
1328
            x.setCoords(rect[i].left(),
 
1329
                        rect[i].top() + ext,
 
1330
                        rect[i].right(),
 
1331
                        rect[i].bottom());
 
1332
            s.setCoords(rect[i].left(),
 
1333
                        rect[i].top(),
 
1334
                        rect[i].right(),
 
1335
                        x.top() - 1);
 
1336
            break;
 
1337
        default:
 
1338
            Q_ASSERT(false);
 
1339
        }
 
1340
 
 
1341
        if (relayout_type == QInternal::RelayoutNormal || layout_info[i].is_dummy)
 
1342
            layout_info[i].item->setGeometry(x);
 
1343
        if (relayout_type == QInternal::RelayoutNormal)
 
1344
            layout_info[i].sep->setGeometry(s);
 
1345
    }
 
1346
 
 
1347
    if (layout_info[CENTER].item) {
 
1348
        QRect c;
 
1349
        c.setCoords(left.right() + 1,
 
1350
                    top.bottom() + 1,
 
1351
                    right.left() - 1,
 
1352
                    bottom.top() - 1);
 
1353
        layout_info[CENTER].size = c.size();
 
1354
        if (relayout_type == QInternal::RelayoutNormal)
 
1355
            layout_info[CENTER].item->setGeometry(c);
 
1356
    }
 
1357
}
 
1358
 
 
1359
void QMainWindowLayout::addItem(QLayoutItem *)
 
1360
{ qWarning("QMainWindowLayout: please use the public QMainWindow API instead."); }
 
1361
 
 
1362
QSize QMainWindowLayout::sizeHint() const
 
1363
{
 
1364
    if (!szHint.isValid()) {
 
1365
        int left = 0, right = 0, top = 0, bottom = 0;
 
1366
 
 
1367
        // layout toolbars
 
1368
        for (int line = 0; line < tb_layout_info.size(); ++line) {
 
1369
            const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
1370
            QSize sz;
 
1371
            // need to get the biggest size hint for all tool bars on each line
 
1372
            for (int i = 0; i < lineInfo.list.size(); ++i) {
 
1373
                const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
1374
                QSize ms = info.item->sizeHint();
 
1375
 
 
1376
                if (((lineInfo.pos == LEFT || lineInfo.pos == RIGHT) && (ms.width() > sz.width()))
 
1377
                    || (ms.height() > sz.height()))
 
1378
                    sz = ms;
 
1379
            }
 
1380
            switch (lineInfo.pos) {
 
1381
            case LEFT:
 
1382
                left += sz.width();
 
1383
                break;
 
1384
 
 
1385
            case RIGHT:
 
1386
                right += sz.width();
 
1387
                break;
 
1388
 
 
1389
            case TOP:
 
1390
                top += sz.height();
 
1391
                break;
 
1392
 
 
1393
            case BOTTOM:
 
1394
                bottom += sz.height();
 
1395
                break;
 
1396
 
 
1397
            default:
 
1398
                Q_ASSERT_X(false, "QMainWindowLayout", "internal error");
 
1399
            }
 
1400
        }
 
1401
 
 
1402
        const QSize szC = layout_info[CENTER].item
 
1403
                          ? layout_info[CENTER].item->sizeHint()
 
1404
                          : QSize(0, 0),
 
1405
                    szL = layout_info[LEFT].item
 
1406
                          ? layout_info[LEFT].item->sizeHint()
 
1407
                          : QSize(0, 0),
 
1408
                    szT = layout_info[TOP].item
 
1409
                          ? layout_info[TOP].item->sizeHint()
 
1410
                          : QSize(0, 0),
 
1411
                    szR = layout_info[RIGHT].item
 
1412
                          ? layout_info[RIGHT].item->sizeHint()
 
1413
                          : QSize(0, 0),
 
1414
                    szB = layout_info[BOTTOM].item
 
1415
                          ? layout_info[BOTTOM].item->sizeHint()
 
1416
                          : QSize(0, 0);
 
1417
        int h1, h2, h3, w1, w2, w3;
 
1418
 
 
1419
        w1 = (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea ? szL.width() : 0)
 
1420
             + szT.width()
 
1421
             + (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea ? szR.width() : 0);
 
1422
        w2 = szL.width() + szR.width() + szC.width();
 
1423
        w3 = (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea ? szL.width() : 0)
 
1424
             + szB.width()
 
1425
             + (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea ? szR.width(): 0);
 
1426
 
 
1427
        h1 = (corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea ? szT.height() : 0)
 
1428
             + szL.height()
 
1429
             + (corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea ? szB.height(): 0);
 
1430
        h2 = szT.height() + szB.height() + szC.height();
 
1431
        h3 = (corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea ? szT.height() : 0)
 
1432
             + szR.height()
 
1433
             + (corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea ? szB.height() : 0);
 
1434
 
 
1435
        const int ext = QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
1436
        if (layout_info[LEFT].item && !szL.isEmpty())
 
1437
            left += ext;
 
1438
        if (layout_info[RIGHT].item && !szR.isEmpty())
 
1439
            right += ext;
 
1440
        if (layout_info[TOP].item && !szT.isEmpty())
 
1441
            top += ext;
 
1442
        if (layout_info[BOTTOM].item && !szB.isEmpty())
 
1443
            bottom += ext;
 
1444
 
 
1445
        VDEBUG("QMainWindowLayout::sizeHint:\n"
 
1446
               "    %4dx%4d (l %4d r %4d t %4d b %4d w1 %4d w2 %4d w3 %4d, h1 %4d h2 %4d h3 %4d)",
 
1447
               qMax(qMax(w1,w2),w3), qMax(qMax(h1,h2),h3),
 
1448
               left, right, top, bottom, w1, w2, w3, h1, h2, h3);
 
1449
 
 
1450
        QSize szSB = statusbar ? statusbar->sizeHint() : QSize(0, 0);
 
1451
        szHint = QSize(qMax(szSB.width(), qMax(qMax(w1,w2),w3) + left + right),
 
1452
                       szSB.height() + qMax(qMax(h1,h2),h3) + top + bottom);
 
1453
    }
 
1454
    return szHint;
 
1455
}
 
1456
 
 
1457
QSize QMainWindowLayout::minimumSize() const
 
1458
{
 
1459
    if (!minSize.isValid()) {
 
1460
        int left = 0, right = 0, top = 0, bottom = 0;
 
1461
 
 
1462
        // layout toolbars
 
1463
        for (int line = 0; line < tb_layout_info.size(); ++line) {
 
1464
            const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
1465
            QSize sz;
 
1466
            // need to get the biggest min size for all tool bars on each line
 
1467
            for (int i = 0; i < lineInfo.list.size(); ++i) {
 
1468
                const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
1469
                QSize ms = info.item->minimumSize();
 
1470
 
 
1471
                if (((lineInfo.pos == LEFT || lineInfo.pos == RIGHT) && (ms.width() > sz.width()))
 
1472
                    || (ms.height() > sz.height()))
 
1473
                    sz = ms;
 
1474
            }
 
1475
            switch (lineInfo.pos) {
 
1476
            case LEFT:
 
1477
                left += sz.width();
 
1478
                break;
 
1479
 
 
1480
            case RIGHT:
 
1481
                right += sz.width();
 
1482
                break;
 
1483
 
 
1484
            case TOP:
 
1485
                top += sz.height();
 
1486
                break;
 
1487
 
 
1488
            case BOTTOM:
 
1489
                bottom += sz.height();
 
1490
                break;
 
1491
 
 
1492
            default:
 
1493
                Q_ASSERT_X(false, "QMainWindowLayout", "internal error");
 
1494
            }
 
1495
        }
 
1496
 
 
1497
        const QSize szC = layout_info[CENTER].item
 
1498
                          ? layout_info[CENTER].item->minimumSize()
 
1499
                          : QSize(0, 0),
 
1500
                    szL = layout_info[LEFT].item
 
1501
                          ? layout_info[LEFT].item->minimumSize()
 
1502
                          : QSize(0, 0),
 
1503
                    szT = layout_info[TOP].item
 
1504
                          ? layout_info[TOP].item->minimumSize()
 
1505
                          : QSize(0, 0),
 
1506
                    szR = layout_info[RIGHT].item
 
1507
                          ? layout_info[RIGHT].item->minimumSize()
 
1508
                          : QSize(0, 0),
 
1509
                    szB = layout_info[BOTTOM].item
 
1510
                          ? layout_info[BOTTOM].item->minimumSize()
 
1511
                          : QSize(0, 0);
 
1512
        int h1, h2, h3, w1, w2, w3;
 
1513
 
 
1514
        w1 = (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea ? szL.width() : 0)
 
1515
             + szT.width()
 
1516
             + (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea ? szR.width() : 0);
 
1517
        w2 = szL.width() + szR.width() + szC.width();
 
1518
        w3 = (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea ? szL.width() : 0)
 
1519
             + szB.width()
 
1520
             + (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea ? szR.width() : 0);
 
1521
 
 
1522
        h1 = (corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea ? szT.height() : 0)
 
1523
             + szL.height()
 
1524
             + (corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea ? szB.height() : 0);
 
1525
        h2 = szT.height() + szB.height() + szC.height();
 
1526
        h3 = (corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea ? szT.height() : 0)
 
1527
             + szR.height()
 
1528
             + (corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea ? szB.height() : 0);
 
1529
 
 
1530
        const int ext = QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
1531
        if (layout_info[LEFT].item && !szL.isEmpty())
 
1532
            left += ext;
 
1533
        if (layout_info[RIGHT].item && !szR.isEmpty())
 
1534
            right += ext;
 
1535
        if (layout_info[TOP].item && !szT.isEmpty())
 
1536
            top += ext;
 
1537
        if (layout_info[BOTTOM].item && !szB.isEmpty())
 
1538
            bottom += ext;
 
1539
 
 
1540
        VDEBUG("QMainWindowLayout::minimumSize:\n"
 
1541
               "    %4dx%4d (l %4d r %4d t %4d b %4d w1 %4d w2 %4d w3 %4d, h1 %4d h2 %4d h3 %4d)",
 
1542
               qMax(qMax(w1,w2),w3), qMax(qMax(h1,h2),h3),
 
1543
               left, right, top, bottom, w1, w2, w3, h1, h2, h3);
 
1544
 
 
1545
        QSize szSB = statusbar ? statusbar->minimumSize() : QSize(0, 0);
 
1546
        minSize =  QSize(qMax(szSB.width(), qMax(qMax(w1,w2),w3) + left + right),
 
1547
                         szSB.height() + qMax(qMax(h1,h2),h3) + top + bottom);
 
1548
    }
 
1549
    return minSize;
 
1550
}
 
1551
 
 
1552
void QMainWindowLayout::relayout(QInternal::RelayoutType type)
 
1553
{
 
1554
    QRect g = geometry();
 
1555
    if (g.isValid()) {
 
1556
        QInternal::RelayoutType save_type = relayout_type;
 
1557
        relayout_type = type;
 
1558
        setGeometry(g);
 
1559
        relayout_type = save_type;
 
1560
    } else {
 
1561
        update();
 
1562
    }
 
1563
}
 
1564
 
 
1565
void QMainWindowLayout::invalidate()
 
1566
{
 
1567
    if (relayout_type != QInternal::RelayoutDragging) {
 
1568
        QLayout::invalidate();
 
1569
        minSize = szHint = QSize();
 
1570
    }
 
1571
}
 
1572
 
 
1573
void QMainWindowLayout::saveLayoutInfo()
 
1574
{
 
1575
    Q_ASSERT(save_layout_info == 0);
 
1576
    save_layout_info = new QVector<QMainWindowLayoutInfo>(layout_info);
 
1577
    relayout_type = QInternal::RelayoutDragging;
 
1578
 
 
1579
    for (int i = 0; i < 4; ++i) {
 
1580
        if (!layout_info[i].item) continue;
 
1581
 
 
1582
        QDockWidgetLayout *layout =
 
1583
            qobject_cast<QDockWidgetLayout *>(layout_info[i].item->layout());
 
1584
        Q_ASSERT(layout != 0);
 
1585
        layout->saveLayoutInfo();
 
1586
    }
 
1587
}
 
1588
 
 
1589
void QMainWindowLayout::resetLayoutInfo()
 
1590
{
 
1591
    Q_ASSERT(save_layout_info != 0);
 
1592
    layout_info = *save_layout_info;
 
1593
 
 
1594
    for (int i = 0; i < 4; ++i) {
 
1595
        if (!layout_info[i].item) continue;
 
1596
 
 
1597
        QDockWidgetLayout *layout =
 
1598
            qobject_cast<QDockWidgetLayout *>(layout_info[i].item->layout());
 
1599
        Q_ASSERT(layout != 0);
 
1600
        layout->resetLayoutInfo();
 
1601
    }
 
1602
}
 
1603
 
 
1604
void QMainWindowLayout::discardLayoutInfo()
 
1605
{
 
1606
    Q_ASSERT(save_layout_info != 0);
 
1607
    delete save_layout_info;
 
1608
    save_layout_info = 0;
 
1609
 
 
1610
    relayout_type = QInternal::RelayoutNormal;
 
1611
 
 
1612
    for (int i = 0; i < 4; ++i) {
 
1613
        if (!layout_info[i].item) continue;
 
1614
 
 
1615
        QDockWidgetLayout *layout =
 
1616
            qobject_cast<QDockWidgetLayout *>(layout_info[i].item->layout());
 
1617
        Q_ASSERT(layout != 0);
 
1618
        layout->discardLayoutInfo();
 
1619
    }
 
1620
}
 
1621
 
 
1622
void QMainWindowLayout::beginConstrain()
 
1623
{
 
1624
    save_tb_layout_info = new QList<ToolBarLineInfo>(tb_layout_info);
 
1625
}
 
1626
 
 
1627
void QMainWindowLayout:: endConstrain()
 
1628
{
 
1629
    delete save_tb_layout_info;
 
1630
    save_tb_layout_info = 0;
 
1631
}
 
1632
 
 
1633
int QMainWindowLayout::constrain(QDockWidgetLayout *dock, int delta)
 
1634
{
 
1635
    QVector<QMainWindowLayoutInfo> info = save_layout_info ? *save_layout_info : layout_info;
 
1636
 
 
1637
    const POSITION order[] = {
 
1638
        // LEFT
 
1639
        RIGHT,
 
1640
        // RIGHT
 
1641
        LEFT,
 
1642
        // TOP
 
1643
        BOTTOM,
 
1644
        // BOTTOM
 
1645
        TOP
 
1646
    };
 
1647
 
 
1648
    // which dock are we constraining?
 
1649
    POSITION pos;
 
1650
    if (info[LEFT].item && info[LEFT].item->layout() == dock) {
 
1651
        pos = LEFT;
 
1652
    } else if (info[TOP].item && info[TOP].item->layout() == dock) {
 
1653
        pos = TOP;
 
1654
    } else if (info[RIGHT].item && info[RIGHT].item->layout() == dock) {
 
1655
        pos = RIGHT;
 
1656
        delta = -delta;
 
1657
    } else {
 
1658
        Q_ASSERT(info[BOTTOM].item && info[BOTTOM].item->layout() == dock);
 
1659
        pos = BOTTOM;
 
1660
        delta = -delta;
 
1661
    }
 
1662
 
 
1663
    // remove delta from 'dock'
 
1664
    int current = pick(pos, info[pos].size)
 
1665
                  + pick(pos, info[CENTER].size)
 
1666
                  + pick(pos, info[order[pos]].size);
 
1667
 
 
1668
    const int _ext = QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
1669
    const QSize ext(_ext, _ext);
 
1670
    const QSize dmin = info[pos].item->minimumSize() + ext,
 
1671
                dmax = info[pos].item->maximumSize() + ext;
 
1672
    if (pick(pos, info[pos].size) + delta < pick(pos, dmin))
 
1673
        delta = pick(pos, dmin) - pick(pos, info[pos].size);
 
1674
    if (pick(pos, info[pos].size) + delta > pick(pos, dmax))
 
1675
        delta = pick(pos, dmax) - pick(pos, info[pos].size);
 
1676
 
 
1677
    // remove delta from the center widget
 
1678
    int from_center = delta;
 
1679
    if (from_center) {
 
1680
        const QSize cmin = info[CENTER].item->minimumSize(),
 
1681
                    cmax = info[CENTER].item->maximumSize();
 
1682
        if (pick(pos, info[CENTER].size) - from_center < pick(pos, cmin))
 
1683
            from_center = pick(pos, info[CENTER].size) - pick(pos, cmin);
 
1684
        if (pick(pos, info[CENTER].size) - from_center > pick(pos, cmax))
 
1685
            from_center = pick(pos, cmax) - pick(pos, info[CENTER].size);
 
1686
        set(pos, info[CENTER].size, pick(pos, info[CENTER].size) - from_center);
 
1687
    }
 
1688
 
 
1689
    // remove remaining delta from the other dock (i.e. the one opposite us)
 
1690
    int from_other = 0;
 
1691
    if (info[order[pos]].item) {
 
1692
        from_other = delta - from_center;
 
1693
        if (from_other) {
 
1694
            const QSize omin = info[order[pos]].item->minimumSize() + ext,
 
1695
                        omax = info[order[pos]].item->maximumSize() + ext;
 
1696
            if (pick(pos, info[order[pos]].size) - from_other < pick(pos, omin))
 
1697
                from_other = pick(pos, info[order[pos]].size) - pick(pos, omin);
 
1698
            if (pick(pos, info[order[pos]].size) - from_other > pick(pos, omax))
 
1699
                from_other = pick(pos, omax) - pick(pos, info[order[pos]].size);
 
1700
            set(pos, info[order[pos]].size, pick(pos, info[order[pos]].size) - from_other);
 
1701
        }
 
1702
    }
 
1703
 
 
1704
    // the real delta is how much we stole from the center and right widgets
 
1705
    delta = from_center + from_other;
 
1706
    set(pos, info[pos].size, pick(pos, info[pos].size) + delta);
 
1707
 
 
1708
    int new_current = (pick(pos, info[pos].size)
 
1709
                       + pick(pos, info[CENTER].size)
 
1710
                       + pick(pos, info[order[pos]].size));
 
1711
    Q_UNUSED(current);
 
1712
    Q_UNUSED(new_current);
 
1713
    Q_ASSERT(current == new_current);
 
1714
 
 
1715
    delta = info[pos].size == layout_info[pos].size ? 0 : 1;
 
1716
 
 
1717
    layout_info = info;
 
1718
 
 
1719
    return delta;
 
1720
}
 
1721
 
 
1722
static
 
1723
Qt::DockWidgetAreas areasForMousePosition(const QRect &r, const QPoint &p, bool floatable = false)
 
1724
{
 
1725
    const int dl = qAbs(r.left()   - p.x()),
 
1726
              dr = qAbs(r.right()  - p.x()),
 
1727
              dt = qAbs(r.top()    - p.y()),
 
1728
              db = qAbs(r.bottom() - p.y()),
 
1729
           delta = qMin(dl, qMin(dr, qMin(dt, db))),
 
1730
       threshold = 50,
 
1731
              dx = qAbs(r.center().x() - p.x()),
 
1732
              dy = qAbs(r.center().y() - p.y());
 
1733
 
 
1734
    Qt::DockWidgetAreas areas = 0;
 
1735
    if (delta < threshold) {
 
1736
        VDEBUG() << "    below threshold";
 
1737
        if (delta == dl || delta == dr) {
 
1738
            if (delta == dl)
 
1739
                areas = Qt::LeftDockWidgetArea;
 
1740
            else
 
1741
                areas = Qt::RightDockWidgetArea;
 
1742
 
 
1743
            if (dt < threshold)
 
1744
                areas |= Qt::TopDockWidgetArea;
 
1745
            else if (db < threshold)
 
1746
                areas |= Qt::BottomDockWidgetArea;
 
1747
        } else if (delta == dt || delta == db) {
 
1748
            if (delta == dt)
 
1749
                areas = Qt::TopDockWidgetArea;
 
1750
            else
 
1751
                areas = Qt::BottomDockWidgetArea;
 
1752
 
 
1753
            if (dl < threshold)
 
1754
                areas |= Qt::LeftDockWidgetArea;
 
1755
            else if (dr < threshold)
 
1756
                areas |= Qt::RightDockWidgetArea;
 
1757
        }
 
1758
    } else if (!floatable) {
 
1759
        VDEBUG() << "    not floatable";
 
1760
        areas = ((dx > dy)
 
1761
                 ? ((p.x() < r.center().x())
 
1762
                    ? Qt::LeftDockWidgetArea
 
1763
                    : Qt::RightDockWidgetArea)
 
1764
                 : ((p.y() < r.center().y())
 
1765
                    ? Qt::TopDockWidgetArea
 
1766
                    : Qt::BottomDockWidgetArea));
 
1767
    } else {
 
1768
        VDEBUG() << "    floatable";
 
1769
    }
 
1770
 
 
1771
    return areas;
 
1772
}
 
1773
 
 
1774
Qt::DockWidgetArea QMainWindowLayout::locateDockWidget(QDockWidget *dockwidget,
 
1775
                                                       const QPoint &mouse) const
 
1776
{
 
1777
    VDEBUG() << "  locate: mouse" << mouse;
 
1778
 
 
1779
    const QPoint p = parentWidget()->mapFromGlobal(mouse);
 
1780
 
 
1781
    /*
 
1782
      if there is a window dock layout under the mouse, forward the
 
1783
      place request
 
1784
    */
 
1785
    for (int i = 0; i < 4; ++i) {
 
1786
        if (!layout_info[i].item)
 
1787
            continue;
 
1788
        const Qt::DockWidgetArea area = static_cast<Qt::DockWidgetArea>(areaForPosition(i));
 
1789
        if (!dockwidget->isAreaAllowed(area))
 
1790
            continue;
 
1791
        if (layout_info[i].item->isEmpty() ||
 
1792
            (!layout_info[i].item->geometry().contains(p)
 
1793
             && !layout_info[i].sep->geometry().contains(p)))
 
1794
            continue;
 
1795
        VDEBUG() << "  result: mouse over item" << i;
 
1796
        return area;
 
1797
    }
 
1798
 
 
1799
    Qt::DockWidgetAreas areas =
 
1800
        areasForMousePosition(layout_info[4].item->geometry(), p,
 
1801
                              (dockwidget->features() & QDockWidget::DockWidgetFloatable));
 
1802
    Qt::DockWidgetArea area;
 
1803
 
 
1804
    if (areas == (Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea))
 
1805
        area = corners[Qt::TopLeftCorner];
 
1806
    else if (areas == (Qt::LeftDockWidgetArea | Qt::BottomDockWidgetArea))
 
1807
        area = corners[Qt::BottomLeftCorner];
 
1808
    else if (areas == (Qt::RightDockWidgetArea | Qt::TopDockWidgetArea))
 
1809
        area = corners[Qt::TopRightCorner];
 
1810
    else if (areas == (Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea))
 
1811
        area = corners[Qt::BottomRightCorner];
 
1812
    else
 
1813
        area = (Qt::DockWidgetArea)(uint)areas;
 
1814
 
 
1815
    VDEBUG() << "  result:" << area;
 
1816
    return area;
 
1817
}
 
1818
 
 
1819
QRect QMainWindowLayout::placeDockWidget(QDockWidget *dockwidget,
 
1820
                                         const QRect &r,
 
1821
                                         const QPoint &mouse)
 
1822
{
 
1823
    DEBUG("QMainWindowLayout::placeDockWidget");
 
1824
 
 
1825
    Qt::DockWidgetArea area = locateDockWidget(dockwidget, mouse);
 
1826
    QRect target;
 
1827
 
 
1828
    if (!area || !dockwidget->isAreaAllowed(area)) {
 
1829
        DEBUG() << "END of QMainWindowLayout::placeDockWidget (failed to place)";
 
1830
        return target;
 
1831
    }
 
1832
 
 
1833
    // if there is a window dock layout already here, forward the place
 
1834
    const int pos = positionForArea(area);
 
1835
    if (layout_info[pos].item && !layout_info[pos].item->isEmpty()) {
 
1836
        DEBUG("  forwarding...");
 
1837
        QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(layout_info[pos].item->layout());
 
1838
        Q_ASSERT(l != 0);
 
1839
        target = l->place(dockwidget, r, mouse);
 
1840
        DEBUG("END of QMainWindowLayout::placeDockWidget (forwarded)");
 
1841
        return target;
 
1842
    }
 
1843
 
 
1844
    // remove dockwidget from current position in the layout
 
1845
    removeRecursive(dockwidget);
 
1846
 
 
1847
    // see if the tool window will fix in the main window
 
1848
    const QSize cur = parentWidget()->size();
 
1849
 
 
1850
    QMainWindowLayoutItem layoutitem(dockwidget, r);
 
1851
    layout_info[pos].item = &layoutitem;
 
1852
    layout_info[pos].size = r.size();
 
1853
    DEBUG() << "  pos" << pos << " size" << layout_info[pos].size;
 
1854
    layout_info[pos].is_dummy = true;
 
1855
 
 
1856
    relayout(QInternal::RelayoutDragging);
 
1857
 
 
1858
    const QSize new_min = minimumSize();
 
1859
    const bool forbid = cur.width() < new_min.width() || cur.height() < new_min.height();
 
1860
 
 
1861
    if (!forbid) {
 
1862
        DEBUG() << "  placed at " << layoutitem.geometry();
 
1863
        target = layoutitem.geometry();
 
1864
        target.moveTopLeft(parentWidget()->mapToGlobal(target.topLeft()));
 
1865
    } else {
 
1866
        DEBUG() << "  forbidden, minimum size" << new_min << " larger than current size" << cur;
 
1867
    }
 
1868
 
 
1869
    DEBUG() << "END of QMainWindowLayout::placeDockWidget, target" << target;
 
1870
 
 
1871
    return target;
 
1872
}
 
1873
 
 
1874
void QMainWindowLayout::dropDockWidget(QDockWidget *dockwidget,
 
1875
                                        const QRect &r,
 
1876
                                        const QPoint &mouse)
 
1877
{
 
1878
    DEBUG("QMainWindowLayout::dropDockWidget");
 
1879
 
 
1880
    Qt::DockWidgetArea area = locateDockWidget(dockwidget, mouse);
 
1881
 
 
1882
    if (!area || !dockwidget->isAreaAllowed(area)) {
 
1883
        DEBUG() << "END of QMainWindowLayout::dropDockWidget (failed to place)";
 
1884
        return;
 
1885
    }
 
1886
 
 
1887
    // if there is a window dock layout already here, forward the drop
 
1888
    const int pos = positionForArea(area);
 
1889
    if (layout_info[pos].item) {
 
1890
        DEBUG() << "  forwarding...";
 
1891
        QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(layout_info[pos].item->layout());
 
1892
        Q_ASSERT(l);
 
1893
        l->drop(dockwidget, r, mouse);
 
1894
        relayout();
 
1895
        DEBUG() << "END of QMainWindowLayout::dropDockWidget (forwarded)";
 
1896
        return;
 
1897
    }
 
1898
 
 
1899
    // remove dockwidget from current position in the layout
 
1900
    removeRecursive(dockwidget);
 
1901
 
 
1902
    QWidget *parent = qobject_cast<QMainWindow *>(parentWidget());
 
1903
    dockwidget->setParent(parent);
 
1904
    QDockWidgetLayout *dwl = layoutForArea(static_cast<Qt::DockWidgetArea>(areaForPosition(pos)));
 
1905
    dwl->addWidget(dockwidget);
 
1906
 
 
1907
    layout_info[pos].size = r.size();
 
1908
 
 
1909
    relayout();
 
1910
 
 
1911
    dockwidget->show();
 
1912
    layout_info[pos].sep->widget()->show();
 
1913
 
 
1914
    DEBUG() << "END of QMainWindowLayout::dropDockWidget";
 
1915
}
 
1916
 
 
1917
static bool removeWidgetRecursively(QLayoutItem *li, QWidget *w, bool dummy)
 
1918
{
 
1919
    QLayout *lay = li->layout();
 
1920
    if (!lay)
 
1921
        return false;
 
1922
    int i = 0;
 
1923
    QLayoutItem *child;
 
1924
    while ((child = lay->itemAt(i))) {
 
1925
        if (child->widget() == w) {
 
1926
            QLayoutItem *item = lay->takeAt(i);
 
1927
            if (!dummy)
 
1928
                delete item;
 
1929
            return true;
 
1930
        } else if (removeWidgetRecursively(child, w, dummy)) {
 
1931
            return true;
 
1932
        } else {
 
1933
            ++i;
 
1934
        }
 
1935
    }
 
1936
    return false;
 
1937
}
 
1938
 
 
1939
void QMainWindowLayout::removeRecursive(QDockWidget *dockwidget)
 
1940
{
 
1941
    removeWidgetRecursively(this, dockwidget, save_layout_info != 0);
 
1942
}
 
1943
 
 
1944
int QMainWindowLayout::locateToolBar(QToolBar *toolbar, const QPoint &mouse) const
 
1945
{
 
1946
    const int width = parentWidget()->width(),
 
1947
             height = parentWidget()->height();
 
1948
    const QPoint p = parentWidget()->mapFromGlobal(mouse),
 
1949
                p2 = QPoint(width / 2, height / 2);
 
1950
    const int dx = qAbs(p.x() - p2.x()),
 
1951
              dy = qAbs(p.y() - p2.y());
 
1952
 
 
1953
    POSITION pos = CENTER;
 
1954
    if (dx > dy) {
 
1955
        if (p.x() < p2.x() && toolbar->isAreaAllowed(Qt::LeftToolBarArea)) {
 
1956
            pos = LEFT;
 
1957
        } else if (p.x() >= p2.x() && toolbar->isAreaAllowed(Qt::RightToolBarArea)) {
 
1958
            pos = RIGHT;
 
1959
        } else {
 
1960
            if (p.y() < p2.y() && toolbar->isAreaAllowed(Qt::TopToolBarArea))
 
1961
                pos = TOP;
 
1962
            else if (p.y() >= p2.y() && toolbar->isAreaAllowed(Qt::BottomToolBarArea))
 
1963
                pos = BOTTOM;
 
1964
        }
 
1965
    } else {
 
1966
        if (p.y() < p2.y() && toolbar->isAreaAllowed(Qt::TopToolBarArea)) {
 
1967
                pos = TOP;
 
1968
        } else if (p.y() >= p2.y() && toolbar->isAreaAllowed(Qt::BottomToolBarArea)) {
 
1969
                pos = BOTTOM;
 
1970
        } else {
 
1971
            if (p.x() < p2.x() && toolbar->isAreaAllowed(Qt::LeftToolBarArea))
 
1972
                pos = LEFT;
 
1973
            else if (p.x() >= p2.x() && toolbar->isAreaAllowed(Qt::RightToolBarArea))
 
1974
                pos = RIGHT;
 
1975
        }
 
1976
    }
 
1977
    Q_ASSERT(pos != CENTER);
 
1978
 
 
1979
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
1980
        const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
 
1981
        bool break_it = false;
 
1982
        for (int i = 0; i < lineInfo.list.size(); ++i) {
 
1983
            const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
1984
            if (!info.item)
 
1985
                continue;
 
1986
            if (info.item->isEmpty())
 
1987
                continue;
 
1988
            if (!info.item->geometry().contains(p))
 
1989
                continue;
 
1990
            pos = static_cast<POSITION>(lineInfo.pos);
 
1991
            break_it = true;
 
1992
            break;
 
1993
        }
 
1994
        if (break_it)
 
1995
            break;
 
1996
    }
 
1997
    return pos;
 
1998
}
 
1999
 
 
2000
void QMainWindowLayout::dropToolBar(QToolBar *toolbar, const QPoint &mouse, const QPoint &offset)
 
2001
{
 
2002
    POSITION where = static_cast<POSITION>(locateToolBar(toolbar, mouse));
 
2003
 
 
2004
    if (positionForArea(toolBarArea(toolbar)) == where) {
 
2005
#ifdef TOOLBAR_DEBUG
 
2006
        TBDEBUG() << "###";
 
2007
        for (int l = 0; l < tb_layout_info.size(); ++l) {
 
2008
            const ToolBarLineInfo &lineInfo = tb_layout_info.at(l);
 
2009
            for (int i = 0; i < lineInfo.list.size(); ++i) {
 
2010
                const ToolBarLayoutInfo &tmp = lineInfo.list.at(i);
 
2011
                qDebug() << "bar: " << lineInfo.pos << l << i << tmp.item->widget() << tmp.item->widget()->geometry();
 
2012
            }
 
2013
        }
 
2014
#endif
 
2015
        // move the tool bars more than magic_offset pixels past a boundary
 
2016
        // in either dir in order to move it to a different tb line
 
2017
        const int magic_offset = 5;
 
2018
        int l = 0, i = 0;
 
2019
        ToolBarLayoutInfo info;
 
2020
 
 
2021
        for (l = 0; l < tb_layout_info.size(); ++l) {
 
2022
            ToolBarLineInfo &lineInfo = tb_layout_info[l];
 
2023
            bool break_it = false;
 
2024
            for (i = 0; i < lineInfo.list.size(); ++i) {
 
2025
                ToolBarLayoutInfo &tmp = lineInfo.list[i];
 
2026
                if (tmp.item->widget() == toolbar) {
 
2027
                    info = tmp;
 
2028
                    tmp.offset += offset;
 
2029
                    break_it = true;
 
2030
                    break;
 
2031
                }
 
2032
            }
 
2033
            if (break_it)
 
2034
                break;
 
2035
        }
 
2036
 
 
2037
        if (pick(where, offset) < -magic_offset) { // move left/up
 
2038
            TBDEBUG() << "left/up" << offset << "line: " << l << where;
 
2039
            if (l > 0 && tb_layout_info.at(l-1).pos == where) { // is this the first line in this tb area?
 
2040
                tb_layout_info[l].list.removeAt(i);
 
2041
                if (tb_layout_info[l].list.size() == 0)
 
2042
                    tb_layout_info.removeAt(l);
 
2043
                if (tb_layout_info.at(l-1).pos == where) {
 
2044
                    TBDEBUG() << "1. appending to existing" << info.item->widget() << info.item->widget()->geometry();
 
2045
                    if (tb_layout_info[l-1].list.size() > 0) {
 
2046
                        const ToolBarLayoutInfo &tmp = tb_layout_info.at(l-1).list.last();
 
2047
                        if (pick_perp(where, tmp.pos) == pick_perp(where, info.pos))
 
2048
                            info.offset = info.pos - (tmp.pos + QPoint(tmp.size.width(), tmp.size.height()) - offset);
 
2049
                        else if (pick_perp(where, tmp.pos) < pick_perp(where, info.pos))
 
2050
                            info.offset = -(tmp.pos + QPoint(tmp.size.width(), tmp.size.height()) - info.pos + offset);
 
2051
                    }
 
2052
                    tb_layout_info[l-1].list.append(info);
 
2053
 
 
2054
                } else {
 
2055
                    ToolBarLineInfo line;
 
2056
                    line.pos = where;
 
2057
                    line.list.append(info);
 
2058
                    tb_layout_info.insert(l, line);
 
2059
                    TBDEBUG() << "2. inserting new";
 
2060
                }
 
2061
            } else if ((tb_layout_info.at(l).list.size() > 1)
 
2062
                       && ((l > 0 && tb_layout_info.at(l-1).pos == where)
 
2063
                           || where == BOTTOM || where == RIGHT))
 
2064
            {
 
2065
                tb_layout_info[l].list.removeAt(i);
 
2066
                ToolBarLineInfo line;
 
2067
                line.pos = where;
 
2068
                line.list.append(info);
 
2069
                tb_layout_info.insert(l, line);
 
2070
                TBDEBUG() << "3. inserting new" << l << toolbar;
 
2071
            }
 
2072
        } else if (pick(where, offset) > pick(where, info.size) + magic_offset) { // move right/down
 
2073
            TBDEBUG() << "right/down" << offset << "line: " << l;
 
2074
            if (l < tb_layout_info.size()-1 && tb_layout_info.at(l+1).pos == where) {
 
2075
                tb_layout_info[l].list.removeAt(i);
 
2076
                if (tb_layout_info.at(l).list.size() == 0)
 
2077
                    tb_layout_info.removeAt(l--);
 
2078
                if (tb_layout_info.at(l+1).pos == where) {
 
2079
                    if (tb_layout_info[l+1].list.size() > 0) {
 
2080
                        const ToolBarLayoutInfo &tmp = tb_layout_info.at(l+1).list.last();
 
2081
                        if (pick_perp(where, tmp.pos) == pick_perp(where, info.pos))
 
2082
                            info.offset = info.pos -(tmp.pos + QPoint(tmp.size.width(), tmp.size.height()) - offset);
 
2083
                        else if (pick_perp(where, tmp.pos) < pick_perp(where, info.pos))
 
2084
                            info.offset = -(tmp.pos + QPoint(tmp.size.width(), tmp.size.height()) - info.pos + offset);
 
2085
                    }
 
2086
                    tb_layout_info[l+1].list.append(info);
 
2087
                    TBDEBUG() << "1. appending to exisitng";
 
2088
                } else {
 
2089
                    ToolBarLineInfo line;
 
2090
                    line.pos = where;
 
2091
                    line.list.append(info);
 
2092
                    tb_layout_info.insert(l, line);
 
2093
                    TBDEBUG() << "2. inserting new line";
 
2094
                }
 
2095
            } else if ((tb_layout_info.at(l).list.size() > 1)
 
2096
                       && ((l < tb_layout_info.size()-1 && tb_layout_info.at(l+1).pos == where)
 
2097
                           || where == TOP || where == LEFT))
 
2098
            {
 
2099
                tb_layout_info[l].list.removeAt(i);
 
2100
                ToolBarLineInfo line;
 
2101
                line.pos = where;
 
2102
                line.list.append(info);
 
2103
                tb_layout_info.insert(l+1, line);
 
2104
                TBDEBUG() << "3. inserting new line";
 
2105
            }
 
2106
        }
 
2107
    } else {
 
2108
        TBDEBUG() << "changed area";
 
2109
        addToolBar(static_cast<Qt::ToolBarArea>(areaForPosition(where)), toolbar, false);
 
2110
        dropToolBar(toolbar, mouse, offset);
 
2111
        return;
 
2112
    }
 
2113
    relayout();
 
2114
}
 
2115
 
 
2116
void QMainWindowLayout::removeToolBarInfo(QToolBar *toolbar)
 
2117
{
 
2118
    for (int line = 0; line < tb_layout_info.size(); ++line) {
 
2119
        ToolBarLineInfo &lineInfo = tb_layout_info[line];
 
2120
        for (int i = 0; i < lineInfo.list.size(); ++i) {
 
2121
            const ToolBarLayoutInfo &info = lineInfo.list.at(i);
 
2122
            if (info.item->widget() == toolbar) {
 
2123
                delete info.item;
 
2124
                lineInfo.list.removeAt(i);
 
2125
                if (lineInfo.list.size() == 0)
 
2126
                    tb_layout_info.removeAt(line);
 
2127
                break;
 
2128
            }
 
2129
        }
 
2130
    }
 
2131
}
 
2132
 
 
2133
int QMainWindowLayout::nextVisible(int index, const ToolBarLineInfo &lineInfo)
 
2134
{
 
2135
    for (++index; index < lineInfo.list.size(); ++index) {
 
2136
        if (!lineInfo.list.at(index).item->isEmpty())
 
2137
            break;
 
2138
    }
 
2139
    return (index >= 0 && index < lineInfo.list.size()) ? index : -1;
 
2140
}
 
2141
 
 
2142
int QMainWindowLayout::prevVisible(int index, const ToolBarLineInfo &lineInfo)
 
2143
{
 
2144
    for (--index; index >= 0; --index) {
 
2145
        if (!lineInfo.list.at(index).item->isEmpty())
 
2146
            break;
 
2147
    }
 
2148
    return (index >= 0 && index < lineInfo.list.size()) ? index : -1;
 
2149
}