~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to plasma/generic/applets/quicklaunch/icongridlayout.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2010 - 2011 by Ingomar Wesp <ingomar@wesp.name>         *
 
3
 *                                                                         *
 
4
 *   This program is free software; you can redistribute it and/or modify  *
 
5
 *   it under the terms of the GNU General Public License as published by  *
 
6
 *   the Free Software Foundation; either version 2 of the License, or     *
 
7
 *   (at your option) any later version.                                   *
 
8
 *                                                                         *
 
9
 *   This program is distributed in the hope that it will be useful,       *
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
12
 *   GNU General Public License for more details.                          *
 
13
 *                                                                         *
 
14
 *   You should have received a copy of the GNU General Public License     *
 
15
 *   along with this program; if not, write to the                         *
 
16
 *   Free Software Foundation, Inc.,                                       *
 
17
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
 
18
 ***************************************************************************/
 
19
#include "icongridlayout.h"
 
20
 
 
21
// Qt
 
22
#include <Qt>
 
23
#include <QtGlobal>
 
24
#include <QtCore/QList>
 
25
#include <QtCore/QSizeF>
 
26
#include <QtCore/QRectF>
 
27
#include <QtGui/QGraphicsLayout>
 
28
#include <QtGui/QGraphicsLayoutItem>
 
29
#include <QtGui/QSizePolicy>
 
30
 
 
31
// KDE
 
32
#include <KDebug>
 
33
#include <KIconLoader>
 
34
 
 
35
// stdlib
 
36
#include <math.h>
 
37
 
 
38
namespace Quicklaunch {
 
39
 
 
40
const int IconGridLayout::DEFAULT_CELL_SPACING = 4;
 
41
 
 
42
IconGridLayout::IconGridLayout(QGraphicsLayoutItem *parent)
 
43
    : QGraphicsLayout(parent),
 
44
      m_items(),
 
45
      m_mode(PreferRows),
 
46
      m_cellSpacing(DEFAULT_CELL_SPACING),
 
47
      m_maxSectionCount(0),
 
48
      m_maxSectionCountForced(false),
 
49
      m_rowCount(0),
 
50
      m_columnCount(0),
 
51
      m_rowHeights(),
 
52
      m_columnWidths()
 
53
{
 
54
    setContentsMargins(0, 0, 0, 0);
 
55
 
 
56
    QSizePolicy sizePolicy(
 
57
        QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
 
58
    sizePolicy.setHeightForWidth(true);
 
59
    sizePolicy.setHorizontalStretch(1);
 
60
    sizePolicy.setVerticalStretch(1);
 
61
    setSizePolicy(sizePolicy);
 
62
}
 
63
 
 
64
IconGridLayout::~IconGridLayout()
 
65
{
 
66
    Q_FOREACH(QGraphicsLayoutItem *item, m_items) {
 
67
        if (item->ownedByLayout()) {
 
68
            delete item;
 
69
        }
 
70
    }
 
71
    m_items.clear();
 
72
}
 
73
 
 
74
IconGridLayout::Mode IconGridLayout::mode() const
 
75
{
 
76
    return m_mode;
 
77
}
 
78
 
 
79
void IconGridLayout::setMode(Mode mode)
 
80
{
 
81
    if (mode == m_mode) {
 
82
        return;
 
83
    }
 
84
 
 
85
    m_mode = mode;
 
86
    updateGridParameters();
 
87
    invalidate();
 
88
}
 
89
 
 
90
int IconGridLayout::cellSpacing() const
 
91
{
 
92
    return m_cellSpacing;
 
93
}
 
94
 
 
95
void IconGridLayout::setCellSpacing(int cellSpacing)
 
96
{
 
97
    cellSpacing = qMax(0, cellSpacing);
 
98
 
 
99
    if (cellSpacing == m_cellSpacing) {
 
100
        return;
 
101
    }
 
102
 
 
103
    m_cellSpacing = cellSpacing;
 
104
    updateGridParameters();
 
105
    invalidate();
 
106
}
 
107
 
 
108
int IconGridLayout::maxSectionCount() const
 
109
{
 
110
    return m_maxSectionCount;
 
111
}
 
112
 
 
113
void IconGridLayout::setMaxSectionCount(int maxSectionCount)
 
114
{
 
115
    if (m_maxSectionCount == maxSectionCount) {
 
116
        return;
 
117
    }
 
118
 
 
119
    m_maxSectionCount = maxSectionCount;
 
120
    updateGridParameters();
 
121
    invalidate();
 
122
}
 
123
 
 
124
bool IconGridLayout::maxSectionCountForced() const
 
125
{
 
126
    return m_maxSectionCountForced;
 
127
}
 
128
 
 
129
void IconGridLayout::setMaxSectionCountForced(bool enable)
 
130
{
 
131
    if (m_maxSectionCountForced == enable) {
 
132
        return;
 
133
    }
 
134
 
 
135
    m_maxSectionCountForced = enable;
 
136
    updateGridParameters();
 
137
    invalidate();
 
138
}
 
139
 
 
140
void IconGridLayout::addItem(QGraphicsLayoutItem *item)
 
141
{
 
142
    m_items.append(item);
 
143
    addChildLayoutItem(item);
 
144
    item->setParentLayoutItem(this);
 
145
    updateGridParameters();
 
146
    invalidate();
 
147
}
 
148
 
 
149
void IconGridLayout::insertItem(int index, QGraphicsLayoutItem *item)
 
150
{
 
151
    m_items.insert(index, item);
 
152
    addChildLayoutItem(item);
 
153
    item->setParentLayoutItem(this);
 
154
    updateGridParameters();
 
155
    invalidate();
 
156
}
 
157
 
 
158
void IconGridLayout::moveItem(int from, int to)
 
159
{
 
160
    m_items.move(from, to);
 
161
    invalidate();
 
162
}
 
163
 
 
164
int IconGridLayout::rowCount() const
 
165
{
 
166
    return m_rowCount;
 
167
}
 
168
 
 
169
int IconGridLayout::columnCount() const
 
170
{
 
171
    return m_columnCount;
 
172
}
 
173
 
 
174
int IconGridLayout::count() const
 
175
{
 
176
    return m_items.size();
 
177
}
 
178
 
 
179
QGraphicsLayoutItem *IconGridLayout::itemAt(int index) const
 
180
{
 
181
    return m_items[index];
 
182
}
 
183
 
 
184
QGraphicsLayoutItem *IconGridLayout::itemAt(int row, int column) const
 
185
{
 
186
    return m_items[row * m_columnCount + column];
 
187
}
 
188
 
 
189
void IconGridLayout::removeAt(int index)
 
190
{
 
191
    QGraphicsLayoutItem *item = m_items.takeAt(index);
 
192
    item->setParentLayoutItem(0);
 
193
 
 
194
    if (item->ownedByLayout()) {
 
195
        delete item;
 
196
    }
 
197
 
 
198
    updateGridParameters();
 
199
    invalidate();
 
200
}
 
201
 
 
202
void IconGridLayout::setGeometry(const QRectF &rect)
 
203
{
 
204
    QGraphicsLayout::setGeometry(rect);
 
205
    updateGridParameters();
 
206
 
 
207
    qreal offsetLeft =
 
208
        qMax<qreal>(
 
209
            contentsRect().left(),
 
210
            (contentsRect().width() - preferredWidth()) / 2);
 
211
 
 
212
    qreal offsetTop =
 
213
        qMax<qreal>(
 
214
            contentsRect().top(),
 
215
            (contentsRect().height() - preferredHeight()) / 2);
 
216
 
 
217
    QPointF pos(offsetLeft, offsetTop);
 
218
    QSizeF size;
 
219
 
 
220
    int itemCount = m_items.size();
 
221
    for (int i = 0; i < itemCount; i++) {
 
222
        int row = i / m_columnCount;
 
223
        int column = i % m_columnCount;
 
224
 
 
225
        if (column == 0) {
 
226
            size.setHeight(m_rowHeights.at(row));
 
227
            if (row > 0) {
 
228
                pos.rx() = offsetLeft;
 
229
                pos.ry() += m_rowHeights.at(row-1) + m_cellSpacing;
 
230
            }
 
231
        } else {
 
232
            pos.rx() += m_columnWidths.at(column-1) + m_cellSpacing;
 
233
        }
 
234
 
 
235
        size.setWidth(m_columnWidths.at(column));
 
236
        m_items[i]->setGeometry(QRectF(pos, size));
 
237
    }
 
238
}
 
239
 
 
240
QSizeF IconGridLayout::sizeHint(
 
241
    Qt::SizeHint which, const QSizeF &constraint) const
 
242
{
 
243
    Q_UNUSED(constraint);
 
244
 
 
245
    switch(which) {
 
246
        case Qt::PreferredSize: return m_preferredSizeHint;
 
247
        case Qt::MinimumSize:
 
248
            if (m_mode == PreferRows) {
 
249
                return QSizeF(m_preferredSizeHint.width(), KIconLoader::SizeSmall);
 
250
            }
 
251
            else {
 
252
                return QSizeF(KIconLoader::SizeSmall, m_preferredSizeHint.height());
 
253
            }
 
254
 
 
255
        default:
 
256
            return QSizeF();
 
257
    }
 
258
}
 
259
 
 
260
void IconGridLayout::computeGridParameters(
 
261
    QList<int> &rowHeights, QList<int> &columnWidths,
 
262
    QSizeF &preferredSize) const
 
263
{
 
264
    columnWidths.clear();
 
265
    rowHeights.clear();
 
266
 
 
267
    const int itemCount = m_items.size();
 
268
    if (itemCount == 0) {
 
269
        preferredSize.setWidth(.0);
 
270
        preferredSize.setHeight(.0);
 
271
        return;
 
272
    }
 
273
 
 
274
    int rowCount;
 
275
    int columnCount;
 
276
 
 
277
    if (m_mode == PreferRows) {
 
278
        const int height = int(contentsRect().height());
 
279
        int minRowHeight = 0;
 
280
        Q_FOREACH(QGraphicsLayoutItem *item, m_items) {
 
281
            minRowHeight = qMax(minRowHeight, (int)item->minimumHeight());
 
282
        }
 
283
 
 
284
        if (m_maxSectionCount > 0 && m_maxSectionCountForced) {
 
285
            rowCount = qMin(itemCount, m_maxSectionCount);
 
286
        }
 
287
        else {
 
288
            rowCount = height / (minRowHeight + m_cellSpacing);
 
289
            rowCount = qBound(1, rowCount, itemCount);
 
290
 
 
291
            if (m_maxSectionCount > 0) {
 
292
                rowCount = qMin(rowCount, m_maxSectionCount);
 
293
            }
 
294
        }
 
295
        columnCount = ceil(double(itemCount) / rowCount);
 
296
 
 
297
        // Determine row heights.
 
298
        int maxRowHeight =
 
299
            qMax(minRowHeight,
 
300
                 (height - (rowCount - 1) * m_cellSpacing) / rowCount);
 
301
 
 
302
        for (int row = 0; row < rowCount; row++) {
 
303
            int desiredRowHeight = 0;
 
304
            for (int column = 0; column < columnCount; column++) {
 
305
                int itemIndex = row * columnCount + column;
 
306
 
 
307
                if (itemIndex >= itemCount) {
 
308
                    break;
 
309
                }
 
310
                desiredRowHeight =
 
311
                    qMax(desiredRowHeight, int(m_items.at(itemIndex)->preferredHeight()));
 
312
            }
 
313
            rowHeights.append(desiredRowHeight < maxRowHeight ? desiredRowHeight : maxRowHeight);
 
314
        }
 
315
 
 
316
        // Determine column widths.
 
317
        for (int column = 0; column < columnCount; column++) {
 
318
            int columnWidth = 0;
 
319
            for (int row = 0; row < rowCount; row++) {
 
320
                int itemIndex = row * columnCount + column;
 
321
 
 
322
                if (itemIndex >= itemCount) {
 
323
                    break;
 
324
                }
 
325
 
 
326
                int preferredItemWidth =
 
327
                    int(m_items.at(itemIndex)->effectiveSizeHint(Qt::PreferredSize, QSizeF(-1, rowHeights.at(row))).width());
 
328
 
 
329
                columnWidth = qMax(columnWidth, preferredItemWidth);
 
330
 
 
331
            }
 
332
            columnWidths.append(columnWidth);
 
333
        }
 
334
    } else { // m_mode == PreferColumns
 
335
        const int width = int(contentsRect().width());
 
336
        int minColumnWidth = 0;
 
337
        Q_FOREACH(QGraphicsLayoutItem *item, m_items) {
 
338
            minColumnWidth = qMax(minColumnWidth, (int)item->minimumWidth());
 
339
        }
 
340
 
 
341
        if (m_maxSectionCount > 0 && m_maxSectionCountForced) {
 
342
            columnCount = qMin(itemCount, m_maxSectionCount);
 
343
        }
 
344
        else {
 
345
            columnCount = width / (minColumnWidth + m_cellSpacing);
 
346
            columnCount = qBound(1, columnCount, itemCount);
 
347
 
 
348
            if (m_maxSectionCount > 0) {
 
349
                columnCount = qMin(columnCount, m_maxSectionCount);
 
350
            }
 
351
        }
 
352
        rowCount = ceil(double(itemCount) / columnCount);
 
353
 
 
354
        // Determine column widths.
 
355
        int maxColumnWidth =
 
356
            qMax(minColumnWidth,
 
357
                 (width - (columnCount - 1) * m_cellSpacing) / columnCount);
 
358
 
 
359
        for (int column = 0; column < columnCount; column++) {
 
360
 
 
361
            int desiredColumnWidth = 0;
 
362
            for (int row = 0; row < rowCount; row++) {
 
363
                int itemIndex = row * columnCount + column;
 
364
 
 
365
                if (itemIndex >= itemCount) {
 
366
                    break;
 
367
                }
 
368
                desiredColumnWidth =
 
369
                    qMax(desiredColumnWidth, int(m_items.at(itemIndex)->preferredWidth()));
 
370
            }
 
371
            columnWidths.append(desiredColumnWidth < maxColumnWidth ? desiredColumnWidth : maxColumnWidth);
 
372
        }
 
373
 
 
374
        // Determine row heights.
 
375
        for (int row = 0; row < rowCount; row++) {
 
376
            int rowHeight = 0;
 
377
            for (int column = 0; column < columnCount; column++) {
 
378
                int itemIndex = row * columnCount + column;
 
379
                if (itemIndex >= itemCount) {
 
380
                    break;
 
381
                }
 
382
 
 
383
                int preferredItemHeight =
 
384
                    int(m_items.at(itemIndex)->effectiveSizeHint(Qt::PreferredSize, QSizeF(columnWidths.at(column), -1)).height());
 
385
 
 
386
                rowHeight = qMax(rowHeight, preferredItemHeight);
 
387
            }
 
388
            rowHeights.append(rowHeight);
 
389
        }
 
390
    }
 
391
 
 
392
    Q_ASSERT(rowCount > 0 && columnCount > 0);
 
393
    Q_ASSERT(rowHeights.length() == rowCount && columnWidths.length() == columnCount);
 
394
 
 
395
    preferredSize.setWidth((columnCount - 1) * m_cellSpacing);
 
396
    preferredSize.setHeight((rowCount - 1) * m_cellSpacing);
 
397
 
 
398
    for (int i = 0; i < columnCount; i++) {
 
399
        preferredSize.rwidth() += columnWidths.at(i);
 
400
    }
 
401
    for (int i = 0; i < rowCount; i++) {
 
402
            preferredSize.rheight() += rowHeights.at(i);
 
403
    }
 
404
}
 
405
 
 
406
void IconGridLayout::updateGridParameters()
 
407
{
 
408
    QSizeF newPreferredSize;
 
409
 
 
410
    computeGridParameters(
 
411
        m_rowHeights, m_columnWidths,
 
412
        newPreferredSize);
 
413
 
 
414
    m_rowCount = m_rowHeights.size();
 
415
    m_columnCount = m_columnWidths.size();
 
416
 
 
417
    if (newPreferredSize != m_preferredSizeHint) {
 
418
        m_preferredSizeHint = newPreferredSize;
 
419
        updateGeometry();
 
420
    }
 
421
}
 
422
}