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

« back to all changes in this revision

Viewing changes to src/gui/widgets/qdockwidgetlayout.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 "qdockwidgetlayout_p.h"
 
30
#include "qdockwidget.h"
 
31
 
 
32
#include <qapplication.h>
 
33
#include <qdebug.h>
 
34
#include <qevent.h>
 
35
#include <qstyle.h>
 
36
#include <qvector.h>
 
37
 
 
38
#include <private/qlayoutengine_p.h>
 
39
 
 
40
#include "qdockwidget_p.h"
 
41
#include "qdockwidgetseparator_p.h"
 
42
#include "qmainwindowlayout_p.h"
 
43
 
 
44
// #define LAYOUT_DEBUG
 
45
#if defined(LAYOUT_DEBUG)
 
46
#  define DEBUG qDebug
 
47
#else
 
48
#  define DEBUG if(false)qDebug
 
49
#endif
 
50
 
 
51
// #define LAYOUT_DEBUG_VERBOSE
 
52
#if defined(LAYOUT_DEBUG_VERBOSE)
 
53
#  define VDEBUG qDebug
 
54
#else
 
55
#  define VDEBUG if(false)qDebug
 
56
#endif
 
57
 
 
58
 
 
59
static inline bool canGrow(Qt::Orientation o, const QSizePolicy &sp)
 
60
{ return (o == Qt::Horizontal ? sp.horizontalPolicy() : sp.verticalPolicy()) & QSizePolicy::GrowFlag; }
 
61
 
 
62
enum { StateFlagVisible = 1, StateFlagFloating = 2 };
 
63
 
 
64
QDockWidgetLayout::QDockWidgetLayout(Qt::DockWidgetArea a, Qt::Orientation o)
 
65
    : QLayout(static_cast<QWidget*>(0)), area(a), orientation(o), save_layout_info(0),
 
66
      relayout_type(QInternal::RelayoutNormal)
 
67
{ connect(this, SIGNAL(emptied()), SLOT(maybeDelete()), Qt::QueuedConnection); }
 
68
 
 
69
QDockWidgetLayout::~QDockWidgetLayout()
 
70
{
 
71
    for (int i = 0; i < layout_info.count(); ++i) {
 
72
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
73
        if (info.is_sep)
 
74
            info.item->widget()->deleteLater();
 
75
        if (!info.item->layout())
 
76
            delete info.item;
 
77
    }
 
78
}
 
79
 
 
80
void QDockWidgetLayout::saveState(QDataStream &stream) const
 
81
{
 
82
    stream << (uchar) Marker;
 
83
    stream << (uchar) orientation;
 
84
    stream << (layout_info.count() + 1) / 2;
 
85
    for (int i = 0; i < layout_info.count(); ++i) {
 
86
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
87
        if (info.is_sep)
 
88
            continue;
 
89
        if (info.item->widget()) {
 
90
            const QDockWidget * const widget =
 
91
                qobject_cast<QDockWidget *>(info.item->widget());
 
92
            stream << (uchar) WidgetMarker;
 
93
            if (widget->objectName().isEmpty()) {
 
94
                qWarning("QMainWindow::saveState(): 'objectName' not set for QDockWidget "
 
95
                         "%p '%s', using 'windowTitle' instead.",
 
96
                         widget, widget->windowTitle().toLocal8Bit().constData());
 
97
                stream << widget->windowTitle();
 
98
            } else {
 
99
                stream << widget->objectName();
 
100
            }
 
101
            uchar flags = 0;
 
102
            if (!widget->isHidden())
 
103
                flags |= StateFlagVisible;
 
104
            if (widget->isFloating())
 
105
                flags |= StateFlagFloating;
 
106
            stream << flags;
 
107
            if (widget->isFloating()) {
 
108
                stream << widget->x();
 
109
                stream << widget->y();
 
110
                stream << widget->width();
 
111
                stream << widget->height();
 
112
            } else {
 
113
                stream << info.cur_pos;
 
114
                stream << info.cur_size;
 
115
                stream << info.min_size;
 
116
                stream << info.max_size;
 
117
            }
 
118
        } else if (info.item->layout()) {
 
119
            stream << (uchar) Marker;
 
120
            stream << info.cur_pos;
 
121
            stream << info.cur_size;
 
122
            stream << info.min_size;
 
123
            stream << info.max_size;
 
124
            const QDockWidgetLayout * const layout =
 
125
                qobject_cast<const QDockWidgetLayout *>(info.item->layout());
 
126
            layout->saveState(stream);
 
127
        }
 
128
    }
 
129
}
 
130
 
 
131
bool QDockWidgetLayout::restoreState(QDataStream &stream)
 
132
{
 
133
    uchar marker;
 
134
    int size;
 
135
    stream >> marker;
 
136
    if (marker != Marker)
 
137
        return false;
 
138
 
 
139
    relayout_type = QInternal::RelayoutDropped;
 
140
 
 
141
    uchar o;
 
142
    stream >> o;
 
143
    orientation = static_cast<Qt::Orientation>(o);
 
144
    stream >> size;
 
145
    QList<QDockWidget *> widgets = qFindChildren<QDockWidget *>(parentWidget());
 
146
    for (int i = 0; i < size; ++i) {
 
147
        uchar nextMarker;
 
148
        stream >> nextMarker;
 
149
        switch (nextMarker) {
 
150
        case WidgetMarker:
 
151
            {
 
152
                QString objectName;
 
153
                stream >> objectName;
 
154
                uchar flags;
 
155
                stream >> flags;
 
156
 
 
157
                // find widget
 
158
                QDockWidget *widget = 0;
 
159
                for (int t = 0; t < widgets.size(); ++t) {
 
160
                    if (widgets.at(t)->objectName() == objectName) {
 
161
                        widget = widgets.at(t);
 
162
                        break;
 
163
                    }
 
164
                }
 
165
                if (!widget) {
 
166
                    qWarning("QMainWindow::restoreState(): cannot find a QDockWidget named "
 
167
                             "'%s', trying to match using 'windowTitle' instead.",
 
168
                             objectName.toLocal8Bit().constData());
 
169
                    // try matching the window title
 
170
                    for (int t = 0; t < widgets.size(); ++t) {
 
171
                        if (widgets.at(t)->windowTitle() == objectName) {
 
172
                            widget = widgets.at(t);
 
173
                            break;
 
174
                        }
 
175
                    }
 
176
                    if (!widget) {
 
177
                        qWarning("QMainWindow::restoreState(): cannot find a QDockWidget with "
 
178
                                 "matching 'windowTitle' (looking for '%s').",
 
179
                                 objectName.toLocal8Bit().constData());
 
180
                        // discard size/position data for unknown widget
 
181
                        QDockWidgetLayoutInfo info(0);
 
182
                        stream >> info.cur_pos;
 
183
                        stream >> info.cur_size;
 
184
                        stream >> info.min_size;
 
185
                        stream >> info.max_size;
 
186
                        continue;
 
187
                    }
 
188
                }
 
189
 
 
190
                QDockWidgetLayoutInfo &info = insert(-1, new QWidgetItem(widget));
 
191
                if (flags & StateFlagFloating) {
 
192
                    widget->hide();
 
193
                    widget->setFloating(true);
 
194
                    int x, y, w, h;
 
195
                    stream >> x;
 
196
                    stream >> y;
 
197
                    stream >> w;
 
198
                    stream >> h;
 
199
                    widget->move(x, y);
 
200
                    widget->resize(w, h);
 
201
                    widget->setVisible(flags & StateFlagVisible);
 
202
                } else {
 
203
                    stream >> info.cur_pos;
 
204
                    stream >> info.cur_size;
 
205
                    stream >> info.min_size;
 
206
                    stream >> info.max_size;
 
207
                    widget->setFloating(false);
 
208
                    widget->setVisible(flags & StateFlagVisible);
 
209
                }
 
210
                break;
 
211
            }
 
212
 
 
213
        case Marker:
 
214
            {
 
215
                QDockWidgetLayout *layout = new QDockWidgetLayout(area, orientation);
 
216
                layout->setParent(this);
 
217
                QDockWidgetLayoutInfo &info = insert(-1, layout);
 
218
                stream >> info.cur_pos;
 
219
                stream >> info.cur_size;
 
220
                stream >> info.min_size;
 
221
                stream >> info.max_size;
 
222
                if (!layout->restoreState(stream)) {
 
223
                    relayout_type = QInternal::RelayoutNormal;
 
224
                    return false;
 
225
                }
 
226
                break;
 
227
            }
 
228
 
 
229
        default:
 
230
            // corrupt data
 
231
            relayout_type = QInternal::RelayoutNormal;
 
232
            return false;
 
233
        }
 
234
    }
 
235
 
 
236
    relayout_type = QInternal::RelayoutNormal;
 
237
    return true;
 
238
}
 
239
 
 
240
int QDockWidgetLayout::count() const
 
241
{
 
242
    qWarning("QDockWidgetLayout::count() is wrong");
 
243
    return layout_info.count();
 
244
}
 
245
 
 
246
QLayoutItem *QDockWidgetLayout::itemAt(int index) const
 
247
{
 
248
    VDEBUG("QDockWidgetLayout::itemAt: index %d (%d)", index, layout_info.count());
 
249
 
 
250
    int x = 0;
 
251
    for (int i = 0; i < layout_info.count(); ++i) {
 
252
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
253
        if (info.is_sep)
 
254
            continue;
 
255
        if (x++ == index) {
 
256
            VDEBUG("END, widget:    pos %3d index %3d", i, x);
 
257
            return info.item;
 
258
        }
 
259
    }
 
260
 
 
261
    VDEBUG("END, not found");
 
262
 
 
263
    return 0;
 
264
}
 
265
 
 
266
QLayoutItem *QDockWidgetLayout::takeAt(int index)
 
267
{
 
268
    DEBUG("QDockWidgetLayout::takeAt: index %d", index);
 
269
 
 
270
    int x = 0;
 
271
    for (int i = 0; i < layout_info.count(); ++i) {
 
272
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
273
        if (info.is_sep)
 
274
            continue;
 
275
        if (x++ == index) {
 
276
            QLayoutItem *layoutitem = info.item;
 
277
            QWidget *widget = info.item->widget();
 
278
 
 
279
            VDEBUG("QDockWidgetLayout::takeAt: layoutitem '%s'\n"
 
280
                   "  index %3d pos %4d size %4d %s",
 
281
                   (layoutitem->widget()
 
282
                    ? layoutitem->widget()->objectName().toLatin1().constData()
 
283
                    : "dummy"),
 
284
                   i, info.cur_pos, info.cur_size,
 
285
                   (widget
 
286
                    ? widget->objectName().toLatin1().constData()
 
287
                    : "dummy"));
 
288
 
 
289
            // remove the item
 
290
            layout_info.removeAt(i);
 
291
 
 
292
            // remove the separator
 
293
            if (i == layout_info.count()) {
 
294
                // we removed the last dockwidget, so we need to remove
 
295
                // the separator that was above it
 
296
                --i;
 
297
            }
 
298
 
 
299
            if (i != -1) {
 
300
                QDockWidgetLayoutInfo &sep_info = layout_info[i];
 
301
                Q_ASSERT(sep_info.is_sep);
 
302
 
 
303
                if (!save_layout_info) {
 
304
                    delete sep_info.item->widget();
 
305
                    delete sep_info.item;
 
306
                }
 
307
 
 
308
                VDEBUG("    removing separator at %d", i);
 
309
                layout_info.removeAt(i);
 
310
            }
 
311
 
 
312
#ifdef LAYOUT_DEBUG_VERBOSE
 
313
            dump();
 
314
#endif
 
315
 
 
316
            if (layout_info.isEmpty()) {
 
317
                if (relayout_type == QInternal::RelayoutDropped) {
 
318
                    // probably splitting...
 
319
                } else if (!save_layout_info) {
 
320
                    emit emptied();
 
321
                } else {
 
322
                    QLayout *parentLayout = qobject_cast<QLayout *>(parent());
 
323
                    if (parentLayout)
 
324
                        parentLayout->removeItem(this);
 
325
                }
 
326
            }
 
327
 
 
328
            VDEBUG("END of remove");
 
329
 
 
330
            return layoutitem;
 
331
        }
 
332
    }
 
333
    return 0;
 
334
}
 
335
 
 
336
/*! \reimp */
 
337
void QDockWidgetLayout::addItem(QLayoutItem *layoutitem)
 
338
{
 
339
    if (relayout_type == QInternal::RelayoutDropped && layoutitem->layout()) {
 
340
        // dropping a nested layout!
 
341
        return;
 
342
    }
 
343
 
 
344
    (void) insert(-1, layoutitem);
 
345
    invalidate();
 
346
}
 
347
 
 
348
/*! \reimp */
 
349
void QDockWidgetLayout::setGeometry(const QRect &rect)
 
350
{
 
351
    VDEBUG("QDockWidgetLayout::setGeometry: width %4d height %4d", rect.width(), rect.height());
 
352
 
 
353
    QLayout::setGeometry(rect);
 
354
 
 
355
    if (relayout_type != QInternal::RelayoutDragging) {
 
356
        bool first = true;
 
357
        for (int i = 0; i < layout_info.count(); ++i) {
 
358
            const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
359
            if (info.is_sep)
 
360
                continue;
 
361
 
 
362
            const bool empty = info.item->isEmpty();
 
363
            if (i > 0)
 
364
                layout_info.at(i - 1).item->widget()->setHidden(first || empty);
 
365
            if (!empty)
 
366
                first = false;
 
367
        }
 
368
    }
 
369
 
 
370
    QVector<QLayoutStruct> a(layout_info.count());
 
371
    int x;
 
372
    const int separator_extent =
 
373
        qApp->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
374
 
 
375
    for (x = 0; x < layout_info.count(); ++x) {
 
376
        const QDockWidgetLayoutInfo &info = layout_info.at(x);
 
377
 
 
378
        QLayoutStruct &ls = a[x];
 
379
        ls.init();
 
380
        ls.empty = info.item->isEmpty();
 
381
        if (ls.empty && !info.is_dropped)
 
382
            continue;
 
383
 
 
384
        if (info.is_sep) {
 
385
            VDEBUG("    separator");
 
386
            ls.sizeHint = ls.minimumSize = ls.maximumSize = separator_extent;
 
387
        } else {
 
388
            const QSizePolicy &sp =
 
389
                info.item->widget()
 
390
                ? info.item->widget()->sizePolicy()
 
391
                : QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
 
392
 
 
393
            if (info.is_dropped) {
 
394
                Q_ASSERT(relayout_type != QInternal::RelayoutNormal);
 
395
                Q_ASSERT(info.cur_size > 0);
 
396
 
 
397
                // item was just dropped into the layout
 
398
                ls.minimumSize = info.cur_size;
 
399
                ls.sizeHint = info.cur_size;
 
400
                ls.maximumSize = info.cur_size;
 
401
                // do not use stretch for dropped items... we want them in the
 
402
                // exact size we specify
 
403
                ls.stretch = 0;
 
404
            } else {
 
405
                ls.minimumSize = pick(orientation, info.item->minimumSize());
 
406
                ls.maximumSize = pick(orientation, info.item->maximumSize());
 
407
 
 
408
                if (canGrow(orientation, sp)) {
 
409
                    ls.sizeHint = ls.minimumSize;
 
410
                    ls.stretch = info.cur_size == -1
 
411
                                 ? pick(orientation, info.item->sizeHint())
 
412
                                 : info.cur_size;
 
413
                    ls.expansive = true;
 
414
                } else {
 
415
                    ls.sizeHint = info.cur_size == -1
 
416
                                 ? pick(orientation, info.item->sizeHint())
 
417
                                 : info.cur_size;
 
418
                }
 
419
            }
 
420
 
 
421
            // sanity checks
 
422
            ls.sizeHint = qMax(ls.sizeHint, ls.minimumSize);
 
423
            ls.minimumSize = qMin(ls.minimumSize, ls.maximumSize);
 
424
 
 
425
            VDEBUG("    dockwidget cur %4d min %4d max %4d, hint %4d stretch %4d "
 
426
                   "expansive %d empty %d",
 
427
                   info.cur_size, ls.minimumSize, ls.maximumSize, ls.sizeHint, ls.stretch, ls.expansive, ls.empty);
 
428
        }
 
429
    }
 
430
 
 
431
    qGeomCalc(a, 0, a.count(), 0, pick(orientation, rect.size()), 0);
 
432
 
 
433
    // DO IT
 
434
    VDEBUG("  final placement:");
 
435
    for (int i = 0; i < a.count(); ++i) {
 
436
        const QLayoutStruct &ls = a.at(i);
 
437
        if (ls.empty)
 
438
            continue;
 
439
 
 
440
        QDockWidgetLayoutInfo &info = layout_info[i];
 
441
 
 
442
        if (info.is_sep) {
 
443
            VDEBUG("    separator  cur %4d", ls.size);
 
444
        } else {
 
445
            VDEBUG("    dockwidget cur %4d min %4d max %4d pos %4d",
 
446
                   ls.size, ls.minimumSize, ls.maximumSize, ls.pos);
 
447
        }
 
448
 
 
449
 
 
450
        if (relayout_type == QInternal::RelayoutDragging) {
 
451
            // we are testing a layout, so don't actually change
 
452
            // anything... but make sure that we update all the dummy
 
453
            // items with the correct geometry
 
454
            continue;
 
455
        }
 
456
 
 
457
        info.cur_pos = ls.pos;
 
458
        info.cur_size = ls.size;
 
459
        info.min_size = ls.minimumSize;
 
460
        info.max_size = ls.maximumSize;
 
461
 
 
462
        info.item->setGeometry(((orientation == Qt::Horizontal) ?
 
463
                                QRect(rect.x() + ls.pos, rect.y(), ls.size, rect.height()) :
 
464
                                QRect(rect.x(), rect.y() + ls.pos, rect.width(), ls.size)));
 
465
    }
 
466
 
 
467
    VDEBUG("END");
 
468
}
 
469
 
 
470
/*! \reimp */
 
471
QSize QDockWidgetLayout::minimumSize() const
 
472
{
 
473
    if (!minSize.isValid()) {
 
474
        VDEBUG("QDockWidget::minimumSize");
 
475
 
 
476
        int size = 0, perp = 0;
 
477
        const int sep_extent =
 
478
            QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
479
 
 
480
        for (int it = 0; it < layout_info.count(); ++it) {
 
481
            const QDockWidgetLayoutInfo &info = layout_info.at(it);
 
482
            int s, p;
 
483
            if (info.is_sep) {
 
484
                s = p = (info.item->widget()->isHidden()) ? 0 : sep_extent;
 
485
            } else {
 
486
                QSize sz = info.item->minimumSize();
 
487
                s = pick(orientation, sz);
 
488
                p = pick_perp(orientation, sz);
 
489
            }
 
490
 
 
491
            VDEBUG("  size %d perp %d", s, p);
 
492
            size += s;
 
493
            perp = qMax(perp, p);
 
494
        }
 
495
 
 
496
        VDEBUG("END: size %4d perp %4d", size, perp);
 
497
 
 
498
        minSize = (orientation == Qt::Horizontal) ? QSize(size, perp) : QSize(perp, size);
 
499
    }
 
500
    return minSize;
 
501
}
 
502
 
 
503
/*! \reimp */
 
504
QSize QDockWidgetLayout::sizeHint() const
 
505
{
 
506
    if (!szHint.isValid()) {
 
507
        VDEBUG("QDockWidget::sizeHint");
 
508
 
 
509
        int size = 0, perp = 0;
 
510
        const int sep_extent =
 
511
            QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
512
 
 
513
        for (int it = 0; it < layout_info.count(); ++it) {
 
514
            const QDockWidgetLayoutInfo &info = layout_info.at(it);
 
515
            int s, p;
 
516
            if (info.is_sep) {
 
517
                s = p = (info.item->widget()->isHidden()) ? 0 : sep_extent;
 
518
            } else {
 
519
                QSize sz = info.item->sizeHint();
 
520
                s = pick(orientation, sz);
 
521
                p = pick_perp(orientation, sz);
 
522
            }
 
523
 
 
524
            VDEBUG("  size %d perp %d", s, p);
 
525
            size += s;
 
526
            perp = qMax(perp, p);
 
527
        }
 
528
 
 
529
        VDEBUG("END: size %4d perp %4d", size, perp);
 
530
 
 
531
        szHint = (orientation == Qt::Horizontal) ? QSize(size, perp) : QSize(perp, size);
 
532
    }
 
533
    return szHint;
 
534
}
 
535
 
 
536
void QDockWidgetLayout::invalidate()
 
537
{
 
538
    if (relayout_type != QInternal::RelayoutDragging) {
 
539
        QLayout::invalidate();
 
540
        minSize = szHint = QSize();
 
541
    }
 
542
}
 
543
 
 
544
bool QDockWidgetLayout::isEmpty() const
 
545
{
 
546
    for (int i = 0; i < layout_info.count(); ++i) {
 
547
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
548
        if (info.is_sep)
 
549
            continue;
 
550
        if (!info.item->isEmpty())
 
551
            return false;
 
552
    }
 
553
    return true;
 
554
}
 
555
 
 
556
void QDockWidgetLayout::setOrientation(Qt::Orientation o)
 
557
{
 
558
    orientation = o;
 
559
    invalidate();
 
560
}
 
561
 
 
562
/*!
 
563
 */
 
564
QDockWidgetLayoutInfo &QDockWidgetLayout::insert(int index, QLayoutItem *layoutitem)
 
565
{
 
566
    DEBUG("QDockWidgetLayout::insert: index %d, layoutitem '%s'",
 
567
          index < 0 ? layout_info.count() : index,
 
568
          ((layoutitem->widget() || layoutitem->layout())
 
569
           ? (layoutitem->layout()
 
570
              ? layoutitem->layout()->objectName().toLatin1().constData()
 
571
              : layoutitem->widget()->objectName().toLatin1().constData())
 
572
           : "dummy"));
 
573
 
 
574
    bool append = index < 0;
 
575
    if (!append) {
 
576
        int it = 0;
 
577
        int idx = 0;
 
578
 
 
579
        // skip to the specified index
 
580
        while (it < layout_info.count()) {
 
581
            if (idx == index) {
 
582
                VDEBUG("found index %d at %d", index, it);
 
583
                break;
 
584
            }
 
585
 
 
586
            if (it + 1 == layout_info.count()) {
 
587
                ++idx;
 
588
                ++it; // ran of the end, force append
 
589
                break;
 
590
            }
 
591
 
 
592
            ++idx;
 
593
            it += 2;
 
594
        }
 
595
 
 
596
        if (it == layout_info.count()) {
 
597
            append = true;
 
598
        } else {
 
599
            VDEBUG("inserting at %d (%d of %d)", it, idx, index);
 
600
 
 
601
            // insert the dockwidget
 
602
            VDEBUG("    inserting dockwidget at %d", it);
 
603
            QDockWidgetLayoutInfo dockwidget_info(layoutitem);
 
604
            int save_it = it;
 
605
            layout_info.insert(it++, dockwidget_info);
 
606
 
 
607
            // insert a separator
 
608
            QLayoutItem *sep_item = 0;
 
609
            Q_ASSERT(!layout_info[it].is_sep);
 
610
            QDockWidgetSeparator *sep = new QDockWidgetSeparator(this, parentWidget());
 
611
            sep_item = new QWidgetItem(sep);
 
612
 
 
613
            QDockWidgetLayoutInfo sep_info(sep_item);
 
614
            sep_info.is_sep = 1;
 
615
            VDEBUG("    inserting separator at %d", it);
 
616
            layout_info.insert(it++, sep_info);
 
617
 
 
618
            return layout_info[save_it];
 
619
        }
 
620
    }
 
621
 
 
622
    Q_ASSERT(append == true);
 
623
 
 
624
    // append the dockwidget
 
625
    if (!layout_info.isEmpty()) {
 
626
        Q_ASSERT(!layout_info.last().is_sep);
 
627
 
 
628
        // insert a separator before the dockwidget
 
629
        QLayoutItem *sep_item = 0;
 
630
        QDockWidgetSeparator *sep = new QDockWidgetSeparator(this, parentWidget());
 
631
        sep_item = new QWidgetItem(sep);
 
632
 
 
633
        QDockWidgetLayoutInfo sep_info(sep_item);
 
634
        sep_info.is_sep = 1;
 
635
        layout_info.append(sep_info);
 
636
    }
 
637
 
 
638
    QDockWidgetLayoutInfo dockwidget_info(layoutitem);
 
639
    layout_info.append(dockwidget_info);
 
640
 
 
641
    return layout_info.last();
 
642
}
 
643
 
 
644
void QDockWidgetLayout::dump()
 
645
{
 
646
    DEBUG("QDockWidgetLayout::dump");
 
647
    for (int i = 0; i < layout_info.count(); ++i) {
 
648
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
649
 
 
650
        if (info.is_sep) {
 
651
            DEBUG("  index %3d pos %4d size %4d SEPARATOR", i, info.cur_pos, info.cur_size);
 
652
        } else if (info.item->layout()) {
 
653
            DEBUG("  index %3d pos %4d size %4d %s", i, info.cur_pos, info.cur_size,
 
654
                  (info.item->layout()
 
655
                   ? info.item->layout()->objectName().toLatin1().constData()
 
656
                   : "dummy"));
 
657
            QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(info.item->layout());
 
658
            Q_ASSERT(l != 0);
 
659
            l->dump();
 
660
        } else {
 
661
            DEBUG("  index %3d pos %4d size %4d %s", i, info.cur_pos, info.cur_size,
 
662
                  (info.item->widget()
 
663
                   ? info.item->widget()->objectName().toLatin1().constData()
 
664
                   : "dummy"));
 
665
        }
 
666
    }
 
667
    DEBUG("END of dump");
 
668
}
 
669
 
 
670
void QDockWidgetLayout::saveLayoutInfo()
 
671
{
 
672
    Q_ASSERT(save_layout_info == 0);
 
673
    save_layout_info = new QList<QDockWidgetLayoutInfo>(layout_info);
 
674
 
 
675
    for (int i = 0; i < layout_info.count(); ++i) {
 
676
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
677
        if (info.is_sep)
 
678
            continue;
 
679
        if (!info.item->layout())
 
680
            continue;
 
681
 
 
682
        QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(info.item->layout());
 
683
        Q_ASSERT(l != 0);
 
684
        l->saveLayoutInfo();
 
685
    }
 
686
}
 
687
 
 
688
void QDockWidgetLayout::resetLayoutInfo()
 
689
{
 
690
    Q_ASSERT(save_layout_info != 0);
 
691
    layout_info = *save_layout_info;
 
692
 
 
693
    for (int i = 0; i < layout_info.count(); ++i) {
 
694
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
695
        if (info.is_sep)
 
696
            continue;
 
697
        if (!info.item->layout())
 
698
            continue;
 
699
 
 
700
        QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(info.item->layout());
 
701
        Q_ASSERT(l != 0);
 
702
        l->resetLayoutInfo();
 
703
    }
 
704
}
 
705
 
 
706
void QDockWidgetLayout::discardLayoutInfo()
 
707
{
 
708
    Q_ASSERT(save_layout_info != 0);
 
709
    delete save_layout_info;
 
710
    save_layout_info = 0;
 
711
 
 
712
    for (int i = 0; i < layout_info.count(); ++i) {
 
713
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
714
        if (info.is_sep)
 
715
            continue;
 
716
        if (!info.item->layout())
 
717
            continue;
 
718
 
 
719
        QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(info.item->layout());
 
720
        Q_ASSERT(l != 0);
 
721
        l->discardLayoutInfo();
 
722
    }
 
723
}
 
724
 
 
725
QPoint QDockWidgetLayout::constrain(QDockWidgetSeparator *sep, int delta)
 
726
{
 
727
    VDEBUG("QDockWidgetLayout::constrain: delta %4d", delta);
 
728
    QList<QDockWidgetLayoutInfo> local_list;
 
729
 
 
730
    for (int pass = 0; pass < 2; ++pass) {
 
731
        VDEBUG("  PASS %d", pass);
 
732
        /*
 
733
          During pass 1, we compute the feedback constraint.  During
 
734
          pass 2, we update layout_info using the calculated
 
735
          constraint.
 
736
        */
 
737
 
 
738
        // find 'sep'
 
739
        local_list = save_layout_info ? *save_layout_info : layout_info;
 
740
        QMutableListIterator<QDockWidgetLayoutInfo> f_it(local_list), b_it(local_list);
 
741
        while (f_it.hasNext()) {
 
742
            const QDockWidgetLayoutInfo &info = f_it.peekNext();
 
743
            if (info.is_sep && qobject_cast<QDockWidgetSeparator*>(info.item->widget()) == sep) break;
 
744
            (void)f_it.next();
 
745
            (void)b_it.next();
 
746
        }
 
747
        // at this point, the iterator is just before 'sep'
 
748
 
 
749
        // get info for 'sep->prev' and move to just after sep->prev
 
750
        while (b_it.hasPrevious()) {
 
751
            if (!b_it.peekPrevious().item->isEmpty())
 
752
                break;
 
753
            (void) b_it.previous(); // skip item
 
754
            (void) b_it.previous(); // skip sep
 
755
        }
 
756
        QDockWidgetLayoutInfo &info1 = b_it.previous(); // move to just after previous separator
 
757
 
 
758
        (void)f_it.next(); // move to before sep->next
 
759
 
 
760
        // get info for 'sep->next' and move to just before next separator
 
761
        while (f_it.hasNext()) {
 
762
            if (!f_it.peekNext().item->isEmpty())
 
763
                break;
 
764
            (void) f_it.next(); // skip sep
 
765
            (void) f_it.next(); // skip item
 
766
        }
 
767
        QDockWidgetLayoutInfo &info2 = f_it.next();
 
768
 
 
769
        // subtract delta to the current size of sep->next
 
770
        int x = info2.cur_size;
 
771
        info2.cur_size -= delta;
 
772
 
 
773
        // constrain the new size according to our min/max size
 
774
        info2.cur_size = qMax(info2.cur_size, info2.min_size);
 
775
        info2.cur_size = qMin(info2.cur_size, info2.max_size);
 
776
        int delta2 = x - info2.cur_size;
 
777
 
 
778
        VDEBUG("next: new %4d old %4d", info2.cur_size, x);
 
779
 
 
780
        if (delta2 != delta) {
 
781
            // distribute space to widgets below if possible
 
782
            int remain = delta - delta2;
 
783
 
 
784
            VDEBUG("remaining below: %d", remain);
 
785
 
 
786
            if (f_it.hasNext()) {
 
787
                while (remain != 0) {
 
788
                    (void)f_it.next(); // skip separator
 
789
 
 
790
                    QDockWidgetLayoutInfo &f_info = f_it.next();
 
791
                    if (!f_info.item->isEmpty()) {
 
792
                        // subtract delta to the current size
 
793
                        x = f_info.cur_size;
 
794
                        f_info.cur_size -= remain;
 
795
 
 
796
                        // constrain the new size according to our min/max size
 
797
                        f_info.cur_size = qMax(f_info.cur_size, f_info.min_size);
 
798
                        f_info.cur_size = qMin(f_info.cur_size, f_info.max_size);
 
799
                        remain -= x - f_info.cur_size;
 
800
 
 
801
                        VDEBUG("  done, new %4d old %4d remaining %d", f_info.cur_size, x, remain);
 
802
                    }
 
803
 
 
804
                    if (!f_it.hasNext()) break; // at the end
 
805
                }
 
806
            }
 
807
 
 
808
            // constrain delta to the absolute minimum of all windows below 'sep'
 
809
            delta -= remain;
 
810
        }
 
811
 
 
812
        // add delta from current size of sep->next
 
813
        x = info1.cur_size;
 
814
        info1.cur_size += delta;
 
815
 
 
816
        // constrain the delta according to our min/max size
 
817
        info1.cur_size = qMax(info1.cur_size, info1.min_size);
 
818
        info1.cur_size = qMin(info1.cur_size, info1.max_size);
 
819
        int delta1 = info1.cur_size - x;
 
820
 
 
821
        VDEBUG("prev: new %4d old %4d", info1.cur_size, x);
 
822
 
 
823
        if (delta1 != delta) {
 
824
            // distribute space to widgets above if possible
 
825
            int remain = delta - delta1;
 
826
 
 
827
            VDEBUG("remaining above: %d", remain);
 
828
 
 
829
            if (b_it.hasPrevious()) {
 
830
                while (remain != 0) {
 
831
                    // (void)b_it.prev(); // skip separator
 
832
 
 
833
                    QDockWidgetLayoutInfo &b_info = b_it.previous();
 
834
                    if (!b_info.item->isEmpty()) {
 
835
                        // add delta from current size of sep->next
 
836
                        x = b_info.cur_size;
 
837
                        b_info.cur_size += remain;
 
838
 
 
839
                        // constrain the delta according to our min/max size
 
840
                        b_info.cur_size = qMax(b_info.cur_size, b_info.min_size);
 
841
                        b_info.cur_size = qMin(b_info.cur_size, b_info.max_size);
 
842
                        remain -= b_info.cur_size - x;
 
843
 
 
844
                        VDEBUG("  done, new %4d old %4d remaining %d", b_info.cur_size, x, remain);
 
845
                    }
 
846
 
 
847
                    if (!b_it.hasPrevious()) break; // at the beginning
 
848
                }
 
849
            }
 
850
 
 
851
            // constrain delta to the absolute minimum of all windows above 'sep'
 
852
            delta -= remain;
 
853
        }
 
854
 
 
855
        VDEBUG("  end of pass %d, delta %4d", pass, delta);
 
856
    }
 
857
 
 
858
    // save the calculated
 
859
    layout_info = local_list;
 
860
 
 
861
    VDEBUG("END");
 
862
 
 
863
    return orientation == Qt::Horizontal ? QPoint(delta, 0) : QPoint(0, delta);
 
864
}
 
865
 
 
866
void QDockWidgetLayout::relayout(QInternal::RelayoutType type)
 
867
{
 
868
    QInternal::RelayoutType save_type = relayout_type;
 
869
    relayout_type = type;
 
870
    setGeometry(geometry());
 
871
    relayout_type = save_type;
 
872
}
 
873
 
 
874
/*!
 
875
 */
 
876
QDockWidgetLayout::Location QDockWidgetLayout::locate(const QPoint &p) const
 
877
{
 
878
    // figure out where the dockwidget goes in the layout
 
879
    const int pos = pick(orientation, p);
 
880
    const bool horizontal = orientation == Qt::Horizontal;
 
881
 
 
882
    DEBUG() << "  locate: mouse at" << p;
 
883
 
 
884
    Location location;
 
885
    location.index = -1;
 
886
    for (int i = 0; i < layout_info.count(); ++i) {
 
887
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
888
        if (info.is_sep)
 
889
            continue;
 
890
        if (info.item->isEmpty())
 
891
            continue;
 
892
 
 
893
        if (pos < (info.cur_pos + info.cur_size - 1)) {
 
894
            const QRect current =
 
895
                (horizontal
 
896
                 ? QRect(info.cur_pos, 0, info.cur_size, geometry().height())
 
897
                 : QRect(0, info.cur_pos, geometry().width(), info.cur_size));
 
898
            const QPoint p2 =
 
899
                current.topLeft() + QPoint(current.width() / 2, current.height() / 2);
 
900
            const int dx = qAbs(p.x() - p2.x()),
 
901
                      dy = qAbs(p.y() - p2.y());
 
902
            location.index = i;
 
903
            location.area = ((dx > dy)
 
904
                             ? ((p.x() < p2.x())
 
905
                                ? Qt::LeftDockWidgetArea
 
906
                                : Qt::RightDockWidgetArea)
 
907
                             : ((p.y() < p2.y())
 
908
                                ? Qt::TopDockWidgetArea
 
909
                                : Qt::BottomDockWidgetArea));
 
910
            DEBUG() << "  result: index" << location.index << "area" << location.area;
 
911
            return location;
 
912
        }
 
913
    }
 
914
 
 
915
    location.index = layout_info.count() - 1;
 
916
    location.area = (horizontal ? Qt::RightDockWidgetArea : Qt::BottomDockWidgetArea);
 
917
    DEBUG() << "  result: index" << location.index << "area" << location.area << "(off-end)";
 
918
    return location;
 
919
}
 
920
 
 
921
static Qt::DockWidgetAreas getAllowedAreas(const QRect &r,
 
922
                                           const QSize &sz1,
 
923
                                           const QSize &sz2,
 
924
                                           const int separatorExtent)
 
925
{
 
926
    Qt::DockWidgetAreas allowedAreas = Qt::AllDockWidgetAreas;
 
927
    if (!r.contains(QRect(r.x(),
 
928
                          r.y(),
 
929
                          sz1.width() + sz2.width() + separatorExtent,
 
930
                          qMax(sz1.height(), sz2.height())))) {
 
931
        DEBUG() << "    cannot split horizontally";
 
932
        allowedAreas &= ~(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
 
933
    }
 
934
    if (!r.contains(QRect(r.x(),
 
935
                          r.y(),
 
936
                          qMax(sz1.width(), sz2.width()),
 
937
                          sz1.height() + sz2.height() +separatorExtent))) {
 
938
        DEBUG() << "    cannot split vertically";
 
939
        allowedAreas &= ~(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
 
940
    }
 
941
    return allowedAreas;
 
942
}
 
943
 
 
944
static QRect trySplit(Qt::Orientation orientation,
 
945
                      Qt::DockWidgetArea &area,
 
946
                      Qt::DockWidgetAreas allowedAreas,
 
947
                      const QRect &r,
 
948
                      const QPoint &p,
 
949
                      int separatorExtent)
 
950
{
 
951
    if (allowedAreas == 0) {
 
952
        // cannot split anywhere
 
953
        return QRect();
 
954
    }
 
955
 
 
956
    if ((allowedAreas & area) != area) {
 
957
        // cannot split in the desired location, pick another one
 
958
        switch (orientation) {
 
959
        case Qt::Horizontal:
 
960
            switch (area) {
 
961
            case Qt::TopDockWidgetArea:
 
962
            case Qt::BottomDockWidgetArea:
 
963
                DEBUG() << "    cannot split vertically, trying horizontally";
 
964
                area = ((p.x() < r.center().x())
 
965
                        ? Qt::LeftDockWidgetArea
 
966
                        : Qt::RightDockWidgetArea);
 
967
                break;
 
968
            default:
 
969
                break;
 
970
            }
 
971
            if ((allowedAreas & area) != area) {
 
972
                switch (area) {
 
973
                case Qt::LeftDockWidgetArea:
 
974
                    area = Qt::RightDockWidgetArea;
 
975
                    DEBUG() << "    cannot split left, trying right";
 
976
                    break;
 
977
                case Qt::RightDockWidgetArea:
 
978
                    area = Qt::LeftDockWidgetArea;
 
979
                    DEBUG() << "    cannot split right, trying left";
 
980
                    break;
 
981
                default:
 
982
                    break;
 
983
                }
 
984
            }
 
985
            if ((allowedAreas & area) != area) {
 
986
                DEBUG() << "      cannot split, trying vertically";
 
987
                area = ((p.y() < r.center().y())
 
988
                        ? Qt::TopDockWidgetArea
 
989
                        : Qt::BottomDockWidgetArea);
 
990
            }
 
991
            break;
 
992
        case Qt::Vertical:
 
993
            switch (area) {
 
994
            case Qt::LeftDockWidgetArea:
 
995
            case Qt::RightDockWidgetArea:
 
996
                DEBUG() << "    cannot split horizontally, trying vertically";
 
997
                area = ((p.y() < r.center().y())
 
998
                        ? Qt::TopDockWidgetArea
 
999
                        : Qt::BottomDockWidgetArea);
 
1000
                break;
 
1001
            default:
 
1002
                break;
 
1003
            }
 
1004
            if ((allowedAreas & area) != area) {
 
1005
                switch (area) {
 
1006
                case Qt::TopDockWidgetArea:
 
1007
                    DEBUG() << "    cannot split top, trying bottom";
 
1008
                    area = Qt::BottomDockWidgetArea;
 
1009
                    break;
 
1010
                case Qt::BottomDockWidgetArea:
 
1011
                    DEBUG() << "    cannot split bottom, trying top";
 
1012
                    area = Qt::TopDockWidgetArea;
 
1013
                    break;
 
1014
                default:
 
1015
                    break;
 
1016
                }
 
1017
            }
 
1018
            if ((allowedAreas & area) != area) {
 
1019
                DEBUG() << "      cannot split, trying horizontally";
 
1020
                area = ((p.x() < r.center().x())
 
1021
                        ? Qt::LeftDockWidgetArea
 
1022
                        : Qt::RightDockWidgetArea);
 
1023
            }
 
1024
            break;
 
1025
        default:
 
1026
            Q_ASSERT_X(false, "QDockWidgetLayout", "internal error");
 
1027
        }
 
1028
    }
 
1029
 
 
1030
    if ((allowedAreas & area) != area) {
 
1031
        // still cannot split, give up
 
1032
        DEBUG() << "  cannot split at all, giving up";
 
1033
        return QRect();
 
1034
    }
 
1035
 
 
1036
    QRect rect;
 
1037
    switch (area) {
 
1038
    case Qt::LeftDockWidgetArea:
 
1039
        rect.setRect(r.x(),
 
1040
                     r.y(),
 
1041
                     (r.width() - separatorExtent) / 2,
 
1042
                     r.height());
 
1043
        break;
 
1044
    case Qt::RightDockWidgetArea:
 
1045
        rect.setRect(r.right() - (r.width() - separatorExtent - 1) / 2,
 
1046
                     r.y(),
 
1047
                     (r.width() - separatorExtent + 1) / 2,
 
1048
                     r.height());
 
1049
        break;
 
1050
    case Qt::TopDockWidgetArea:
 
1051
        rect.setRect(r.x(),
 
1052
                     r.y(),
 
1053
                     r.width(),
 
1054
                     (r.height() - separatorExtent) / 2);
 
1055
        break;
 
1056
    case Qt::BottomDockWidgetArea:
 
1057
        rect.setRect(r.x(),
 
1058
                     r.bottom() - (r.height() - separatorExtent - 1) / 2,
 
1059
                     r.width(),
 
1060
                     (r.height() - separatorExtent + 1) / 2);
 
1061
        break;
 
1062
    default:
 
1063
        Q_ASSERT_X(false, "QDockWidgetLayout", "internal error");
 
1064
    }
 
1065
 
 
1066
    return rect;
 
1067
}
 
1068
 
 
1069
/*!
 
1070
 */
 
1071
QRect QDockWidgetLayout::place(QDockWidget *dockwidget, const QRect &r, const QPoint &mouse)
 
1072
{
 
1073
    DEBUG("QDockWidgetLayout::place");
 
1074
 
 
1075
    const QPoint p = parentWidget()->mapFromGlobal(mouse);
 
1076
    Location location = locate(p - geometry().topLeft());
 
1077
    const QDockWidgetLayoutInfo &info = layout_info.at(location.index);
 
1078
    const bool horizontal = orientation == Qt::Horizontal;
 
1079
 
 
1080
    QRect target;
 
1081
 
 
1082
    if (info.item->layout()) {
 
1083
        // forward the place to the nested layout
 
1084
        QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(info.item->layout());
 
1085
        Q_ASSERT(l != 0);
 
1086
        DEBUG("  forwarding...");
 
1087
        target = l->place(dockwidget, r, mouse);
 
1088
        DEBUG("END of QDockWidgetLayout::place (forwarded)");
 
1089
        return target;
 
1090
    }
 
1091
 
 
1092
    const QSize sz1 = dockwidget->minimumSizeHint(),
 
1093
                sz2 = info.item->minimumSize();
 
1094
    const int separatorExtent =
 
1095
        parentWidget()->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
1096
    Qt::DockWidgetAreas allowedAreas =
 
1097
        getAllowedAreas(info.item->geometry(), sz1, sz2, separatorExtent);
 
1098
 
 
1099
    /*
 
1100
      we do in-place reordering if the dock widget is in this layout.
 
1101
 
 
1102
      we allow splitting into adjacent items by delaying the
 
1103
      reordering until the mouse is closer to the center of the
 
1104
      adjacent item then the current one
 
1105
    */
 
1106
    int which = -1;
 
1107
    for (int i = 0; which == -1 && i < layout_info.count(); ++i) {
 
1108
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
1109
        if (info.is_sep)
 
1110
            continue;
 
1111
        if (info.item->isEmpty())
 
1112
            continue;
 
1113
        if (dockwidget == info.item->widget())
 
1114
            which = i;
 
1115
    }
 
1116
    if (which != -1) {
 
1117
        if (which == location.index) {
 
1118
            target = info.item->geometry();
 
1119
            target.moveTopLeft(parentWidget()->mapToGlobal(target.topLeft()));
 
1120
            DEBUG() << "END of place (placed back at original position" << target << ")";
 
1121
            return target;
 
1122
        }
 
1123
 
 
1124
        const int center =
 
1125
            pick(orientation, layout_info.at(location.index).item->geometry().center());
 
1126
        const int pos = pick(orientation, p);
 
1127
 
 
1128
        if ((which > location.index && pos < center)
 
1129
            || (which < location.index && pos > center)) {
 
1130
            DEBUG() << "  swapping" << which << "with" << location.index;
 
1131
            layout_info.swap(which, location.index);
 
1132
            relayout();
 
1133
            target = layout_info.at(location.index).item->geometry();
 
1134
            target.moveTopLeft(parentWidget()->mapToGlobal(target.topLeft()));
 
1135
            // make sure we don't discard the new layout information!
 
1136
            *save_layout_info = layout_info;
 
1137
            DEBUG() << "END of place, in-place reorder, target is" << target;
 
1138
            return target;
 
1139
        } else {
 
1140
            DEBUG() << "  cannot swap" << endl;
 
1141
            if (horizontal)
 
1142
                allowedAreas &= ~(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
 
1143
            else
 
1144
                allowedAreas &= ~(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
 
1145
        }
 
1146
    }
 
1147
 
 
1148
    DEBUG() << "  trySplit:" << orientation << location.area
 
1149
            << info.item->geometry() << p << sz1 << sz2 << separatorExtent;
 
1150
    target = ::trySplit(orientation, location.area, allowedAreas,
 
1151
                        info.item->geometry(), p, separatorExtent);
 
1152
    if (!target.isEmpty()) {
 
1153
        target.setSize(target.size().expandedTo(sz1));
 
1154
        target.moveTopLeft(parentWidget()->mapToGlobal(target.topLeft()));
 
1155
    }
 
1156
    DEBUG() << "END of place, target is" << target;
 
1157
    return target;
 
1158
}
 
1159
 
 
1160
/*!
 
1161
 */
 
1162
void QDockWidgetLayout::drop(QDockWidget *dockwidget, const QRect &r, const QPoint &mouse)
 
1163
{
 
1164
    DEBUG("QDockWidgetLayout::drop");
 
1165
 
 
1166
    const QPoint p = parentWidget()->mapFromGlobal(mouse);
 
1167
    Location location = locate(p - geometry().topLeft());
 
1168
    const QDockWidgetLayoutInfo &info = layout_info.at(location.index);
 
1169
    const bool horizontal = orientation == Qt::Horizontal;
 
1170
 
 
1171
    if (info.item->layout()) {
 
1172
        // forward the drop to the nested layout
 
1173
        QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(info.item->layout());
 
1174
        Q_ASSERT(l != 0);
 
1175
        DEBUG("  forwarding...");
 
1176
        l->drop(dockwidget, r, mouse);
 
1177
        DEBUG("END of QDockWidgetLayout::drop (forwarded)");
 
1178
        return;
 
1179
    }
 
1180
 
 
1181
    if (dockwidget == info.item->widget()) {
 
1182
        // placed back at original position
 
1183
        if (dockwidget->isFloating()) {
 
1184
            dockwidget->setFloating(false);
 
1185
            dockwidget->show();
 
1186
        }
 
1187
        DEBUG("END of drop (shortcut - dropped at original position)");
 
1188
        return;
 
1189
    }
 
1190
 
 
1191
    const QSize sz1 = dockwidget->minimumSizeHint(),
 
1192
                sz2 = info.item->minimumSize();
 
1193
    const int separatorExtent =
 
1194
        parentWidget()->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
 
1195
    Qt::DockWidgetAreas allowedAreas =
 
1196
        getAllowedAreas(info.item->geometry(), sz1, sz2, separatorExtent);
 
1197
 
 
1198
    /*
 
1199
      we do in-place reordering if the dock widget is in this layout.
 
1200
 
 
1201
      we allow splitting into adjacent items by delaying the
 
1202
      reordering until the mouse is closer to the center of the
 
1203
      adjacent item then the current one
 
1204
    */
 
1205
    int found = -1;
 
1206
    int which = -1;
 
1207
    for (int i = 0; which == -1 && i < layout_info.count(); ++i) {
 
1208
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
1209
        if (info.is_sep)
 
1210
            continue;
 
1211
        if (dockwidget == info.item->widget()) {
 
1212
            found = i;
 
1213
            if (!info.item->isEmpty())
 
1214
                which = i;
 
1215
        }
 
1216
    }
 
1217
    if (which != -1) {
 
1218
        DEBUG() << "  drop after in-place reorder, only allowing perpendicular splits";
 
1219
        if (horizontal)
 
1220
            allowedAreas &= ~(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
 
1221
        else
 
1222
            allowedAreas &= ~(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
 
1223
    }
 
1224
 
 
1225
    DEBUG() << "  trySplit:" << orientation << location.area
 
1226
            << info.item->geometry() << p << sz1 << sz2 << separatorExtent;
 
1227
    QRect target = ::trySplit(orientation, location.area, allowedAreas,
 
1228
                              info.item->geometry(), p, separatorExtent);
 
1229
    if (!target.isEmpty()) {
 
1230
        QMainWindowLayout *layout =
 
1231
            qobject_cast<QMainWindowLayout *>(parentWidget()->layout());
 
1232
        Q_ASSERT(layout != 0);
 
1233
        layout->removeRecursive(dockwidget);
 
1234
 
 
1235
        // if we removed a dock widget in this layout, adjust the
 
1236
        // insertion index
 
1237
        if (found != -1 && found < location.index)
 
1238
            location.index -= 2;
 
1239
 
 
1240
        bool nested = false;
 
1241
        switch (orientation) {
 
1242
        case Qt::Horizontal:
 
1243
            switch (location.area) {
 
1244
            case Qt::TopDockWidgetArea:
 
1245
            case Qt::BottomDockWidgetArea:
 
1246
                nested = true;
 
1247
            default:
 
1248
                break;
 
1249
            }
 
1250
            break;
 
1251
        case Qt::Vertical:
 
1252
            switch (location.area) {
 
1253
            case Qt::LeftDockWidgetArea:
 
1254
            case Qt::RightDockWidgetArea:
 
1255
                nested = true;
 
1256
            default:
 
1257
                break;
 
1258
            }
 
1259
            break;
 
1260
        default:
 
1261
            Q_ASSERT_X(false, "QDockWidgetLayout", "internal error");
 
1262
        }
 
1263
 
 
1264
        if (nested) {
 
1265
            split(qobject_cast<QDockWidget *>(info.item->widget()), dockwidget, location.area);
 
1266
        } else {
 
1267
            int at = location.index / 2;
 
1268
            if (location.area == Qt::RightDockWidgetArea
 
1269
                || location.area == Qt::BottomDockWidgetArea)
 
1270
                ++at;
 
1271
            const int sz = pick(orientation, target.size());
 
1272
            const_cast<QDockWidgetLayoutInfo &>(info).cur_size -= sz + separatorExtent;
 
1273
            QDockWidgetLayoutInfo &newInfo = insert(at, new QWidgetItem(dockwidget));
 
1274
            newInfo.cur_size = sz;
 
1275
            newInfo.is_dropped = true;
 
1276
            relayout(QInternal::RelayoutDropped);
 
1277
            newInfo.is_dropped = false;
 
1278
        }
 
1279
 
 
1280
        if (dockwidget->isFloating()) {
 
1281
            // reparent the dock window into the main window
 
1282
            dockwidget->setFloating(false);
 
1283
            dockwidget->show();
 
1284
        }
 
1285
    }
 
1286
 
 
1287
    DEBUG("END of drop");
 
1288
}
 
1289
 
 
1290
void QDockWidgetLayout::extend(QDockWidget *dockwidget, Qt::Orientation direction)
 
1291
{
 
1292
    if (direction == orientation) {
 
1293
        addWidget(dockwidget);
 
1294
    } else {
 
1295
        Q_ASSERT(relayout_type == QInternal::RelayoutNormal);
 
1296
        relayout_type = QInternal::RelayoutDropped;
 
1297
 
 
1298
        QDockWidgetLayout *nestedLayout = new QDockWidgetLayout(area, orientation);
 
1299
        nestedLayout->setParent(this);
 
1300
        nestedLayout->setObjectName(objectName() + QLatin1String("_nestedCopy"));
 
1301
 
 
1302
        for (int i = 0; i < layout_info.count(); ++i) {
 
1303
            const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
1304
            if (info.is_sep) {
 
1305
                delete info.item->widget();
 
1306
                delete info.item;
 
1307
            } else {
 
1308
                nestedLayout->addItem(info.item);
 
1309
            }
 
1310
        }
 
1311
 
 
1312
        relayout_type = QInternal::RelayoutNormal;
 
1313
 
 
1314
        layout_info.clear();
 
1315
        setOrientation(direction);
 
1316
 
 
1317
        addItem(nestedLayout);
 
1318
        addWidget(dockwidget);
 
1319
    }
 
1320
}
 
1321
 
 
1322
void QDockWidgetLayout::split(QDockWidget *existing, QDockWidget *with, Qt::DockWidgetArea area)
 
1323
{
 
1324
    int which = -1;
 
1325
    for (int i = 0; which == -1 && i < layout_info.count(); ++i) {
 
1326
        const QDockWidgetLayoutInfo &info = layout_info.at(i);
 
1327
        if (info.is_sep)
 
1328
            continue;
 
1329
        if (existing == info.item->widget())
 
1330
            which = i;
 
1331
    }
 
1332
    Q_ASSERT(which != -1);
 
1333
    const QDockWidgetLayoutInfo &info = layout_info.at(which);
 
1334
 
 
1335
    Q_ASSERT(relayout_type == QInternal::RelayoutNormal);
 
1336
    relayout_type = QInternal::RelayoutDropped;
 
1337
 
 
1338
    int save_size = info.cur_size;
 
1339
    removeWidget(existing);
 
1340
    // note: info is invalid from now on
 
1341
 
 
1342
    // create a nested window dock in place of the current widget
 
1343
    QDockWidgetLayout *nestedLayout =
 
1344
        new QDockWidgetLayout(area, orientation == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal);
 
1345
    nestedLayout->setParent(this);
 
1346
    nestedLayout->setObjectName(objectName() + "_nestedLayout");
 
1347
    insert(which / 2, nestedLayout).cur_size = save_size;
 
1348
    invalidate();
 
1349
 
 
1350
    switch (area) {
 
1351
    case Qt::LeftDockWidgetArea:
 
1352
    case Qt::TopDockWidgetArea:
 
1353
        nestedLayout->addWidget(with);
 
1354
        nestedLayout->addWidget(existing);
 
1355
        break;
 
1356
 
 
1357
    case Qt::RightDockWidgetArea:
 
1358
    case Qt::BottomDockWidgetArea:
 
1359
        nestedLayout->addWidget(existing);
 
1360
        nestedLayout->addWidget(with);
 
1361
        break;
 
1362
 
 
1363
    default:
 
1364
        Q_ASSERT_X(false, "QDockWidgetLayout", "internal error");
 
1365
        break;
 
1366
    }
 
1367
 
 
1368
    relayout_type = QInternal::RelayoutNormal;
 
1369
}
 
1370
 
 
1371
void QDockWidgetLayout::maybeDelete()
 
1372
{
 
1373
    if (layout_info.isEmpty())
 
1374
        delete this;
 
1375
}