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

« back to all changes in this revision

Viewing changes to plasma/netbook/containments/netpanel/panel.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 2007 by Alex Merry <alex.merry@kdemail.net>
 
3
*   Copyright 2008 by Alexis Ménard <darktears31@gmail.com>
 
4
*   Copyright 2008 by Aaron Seigo <aseigo@kde.org>
 
5
*
 
6
*   This program is free software; you can redistribute it and/or modify
 
7
*   it under the terms of the GNU Library General Public License version 2,
 
8
*   or (at your option) any later version.
 
9
*
 
10
*   This program is distributed in the hope that it will be useful,
 
11
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
*   GNU General Public License for more details
 
14
*
 
15
*   You should have received a copy of the GNU Library General Public
 
16
*   License along with this program; if not, write to the
 
17
*   Free Software Foundation, Inc.,
 
18
*   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
19
*/
 
20
 
 
21
#include "panel.h"
 
22
#include "dummytoolbox.h"
 
23
#include "../common/linearappletoverlay.h"
 
24
 
 
25
#include <limits>
 
26
 
 
27
#include <QApplication>
 
28
#include <QGraphicsLinearLayout>
 
29
#include <QPainter>
 
30
#include <QDesktopWidget>
 
31
#include <QAction>
 
32
#include <QGraphicsLayout>
 
33
 
 
34
 
 
35
#include <KAction>
 
36
#include <KDebug>
 
37
#include <KIcon>
 
38
 
 
39
#include <Plasma/Corona>
 
40
#include <Plasma/FrameSvg>
 
41
#include <Plasma/Theme>
 
42
#include <Plasma/View>
 
43
 
 
44
using namespace Plasma;
 
45
 
 
46
Panel::Panel(QObject *parent, const QVariantList &args)
 
47
    : Containment(parent, args),
 
48
      m_layout(0),
 
49
      m_appletOverlay(0)
 
50
{
 
51
    m_background = new Plasma::FrameSvg(this);
 
52
    m_background->setImagePath("widgets/panel-background");
 
53
    m_background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
 
54
    connect(m_background, SIGNAL(repaintNeeded()), this, SLOT(backgroundChanged()));
 
55
    setZValue(150);
 
56
    setContainmentType(Containment::PanelContainment);
 
57
 
 
58
    QSize size = QSize(args.count() ? args[0].toInt() : 1024, 22);
 
59
    kDebug() << "**********" << size;
 
60
    resize(size);
 
61
    setMinimumSize(size);
 
62
    setMaximumSize(size);
 
63
    setDrawWallpaper(false);
 
64
 
 
65
    DummyToolBox *toolBox = new DummyToolBox(this);
 
66
    setToolBox(toolBox);
 
67
 
 
68
    connect(this, SIGNAL(appletRemoved(Plasma::Applet*)),
 
69
            this, SLOT(appletRemoved(Plasma::Applet*)));
 
70
    connect(this, SIGNAL(toolBoxVisibilityChanged(bool)),
 
71
            this, SLOT(updateConfigurationMode(bool)));
 
72
}
 
73
 
 
74
Panel::~Panel()
 
75
{
 
76
}
 
77
 
 
78
void Panel::init()
 
79
{
 
80
    Containment::init();
 
81
 
 
82
    Plasma::Corona *c = corona();
 
83
    connect(c, SIGNAL(containmentAdded(Plasma::Containment *)),
 
84
            this, SLOT(containmentAdded(Plasma::Containment *)));
 
85
 
 
86
    KAction *lockAction = new KAction(this);
 
87
    addAction("lock panel", lockAction);
 
88
    lockAction->setText(i18n("Lock Panel"));
 
89
    lockAction->setIcon(KIcon("object-locked"));
 
90
    QObject::connect(lockAction, SIGNAL(triggered(bool)), this, SLOT(toggleImmutability()));
 
91
    lockAction->setShortcut(KShortcut("alt+d, l"));
 
92
    lockAction->setShortcutContext(Qt::ApplicationShortcut);
 
93
}
 
94
 
 
95
void Panel::toggleImmutability()
 
96
{
 
97
    if (immutability() == Plasma::UserImmutable) {
 
98
        setImmutability(Plasma::Mutable);
 
99
    } else if (immutability() == Plasma::Mutable) {
 
100
        setImmutability(Plasma::UserImmutable);
 
101
    }
 
102
}
 
103
 
 
104
void Panel::containmentAdded(Plasma::Containment *containment)
 
105
{
 
106
    connect(containment, SIGNAL(toolBoxVisibilityChanged(bool)),
 
107
            this, SLOT(updateConfigurationMode(bool)));
 
108
}
 
109
 
 
110
void Panel::backgroundChanged()
 
111
{
 
112
    constraintsEvent(Plasma::LocationConstraint);
 
113
}
 
114
 
 
115
void Panel::layoutApplet(Plasma::Applet* applet, const QPointF &pos)
 
116
{
 
117
    // this gets called whenever an applet is added, and we add it to our m_layoutout
 
118
 
 
119
    if (!m_layout) {
 
120
        return;
 
121
    }
 
122
 
 
123
    Plasma::FormFactor f = formFactor();
 
124
    int insertIndex = -1;
 
125
 
 
126
    //if pos is (-1,-1) insert at the end of the panel
 
127
    if (pos != QPoint(-1, -1)) {
 
128
        for (int i = 0; i < m_layout->count(); ++i) {
 
129
            QRectF siblingGeometry = m_layout->itemAt(i)->geometry();
 
130
            if (f == Plasma::Horizontal) {
 
131
                qreal middle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0;
 
132
                if (pos.x() < middle) {
 
133
                    insertIndex = i;
 
134
                    break;
 
135
                } else if (pos.x() <= siblingGeometry.right()) {
 
136
                    insertIndex = i + 1;
 
137
                    break;
 
138
                }
 
139
            } else { // Plasma::Vertical
 
140
                qreal middle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
 
141
                if (pos.y() < middle) {
 
142
                    insertIndex = i;
 
143
                    break;
 
144
                } else if (pos.y() <= siblingGeometry.bottom()) {
 
145
                    insertIndex = i + 1;
 
146
                    break;
 
147
                }
 
148
            }
 
149
        }
 
150
    }
 
151
 
 
152
    if (insertIndex == -1) {
 
153
        m_layout->addItem(applet);
 
154
    } else {
 
155
        m_layout->insertItem(insertIndex, applet);
 
156
    }
 
157
 
 
158
    connect(applet, SIGNAL(sizeHintChanged(Qt::SizeHint)), this, SLOT(updateSize()));
 
159
}
 
160
 
 
161
void Panel::appletRemoved(Plasma::Applet* applet)
 
162
{
 
163
    //shrink the panel if possible
 
164
    if (formFactor() == Plasma::Horizontal) {
 
165
        resize(size().width() - applet->size().width(), size().height());
 
166
    } else {
 
167
        resize(size().width(), size().height() - applet->size().height());
 
168
    }
 
169
    layout()->setMaximumSize(size());
 
170
}
 
171
 
 
172
void Panel::updateSize()
 
173
{
 
174
    Plasma::Applet *applet = qobject_cast<Plasma::Applet *>(sender());
 
175
 
 
176
    if (applet) {
 
177
        if (formFactor() == Plasma::Horizontal) {
 
178
            const int delta = applet->preferredWidth() - applet->size().width();
 
179
            //setting the preferred width when delta = 0 and preferredWidth() < minimumWidth()
 
180
            // leads to the same thing as setPreferredWidth(minimumWidth())
 
181
            if (delta != 0) {
 
182
                setPreferredWidth(preferredWidth() + delta);
 
183
            }
 
184
        } else if (formFactor() == Plasma::Vertical) {
 
185
            const int delta = applet->preferredHeight() - applet->size().height();
 
186
            if (delta != 0) {
 
187
                setPreferredHeight(preferredHeight() + delta);
 
188
            }
 
189
        }
 
190
 
 
191
        resize(preferredSize());
 
192
    }
 
193
}
 
194
 
 
195
void Panel::updateBorders()
 
196
{
 
197
    FrameSvg::EnabledBorders enabledBorders = FrameSvg::AllBorders;
 
198
 
 
199
    kDebug() << "!!!!!!!!!!!!!!!! location be:" << location();
 
200
    switch (location()) {
 
201
        case BottomEdge:
 
202
            enabledBorders = FrameSvg::TopBorder;
 
203
            break;
 
204
        case TopEdge:
 
205
            enabledBorders = FrameSvg::BottomBorder;
 
206
            break;
 
207
        case LeftEdge:
 
208
            enabledBorders = FrameSvg::RightBorder;
 
209
            break;
 
210
        case RightEdge:
 
211
            enabledBorders = FrameSvg::LeftBorder;
 
212
            break;
 
213
        default:
 
214
            break;
 
215
    }
 
216
 
 
217
    qreal topHeight = 0;
 
218
    qreal bottomHeight = 0;
 
219
    qreal leftWidth = 0;
 
220
    qreal rightWidth = 0;
 
221
 
 
222
    //activate borders and fetch sizes again
 
223
    m_background->setEnabledBorders(enabledBorders);
 
224
    m_background->getMargins(leftWidth, topHeight, rightWidth, bottomHeight);
 
225
 
 
226
    //FIXME: this will be probably just killed not kept in this zombie state :)
 
227
#if 0
 
228
    //calculation of extra margins has to be done after getMargins
 
229
    if (formFactor() == Vertical) {
 
230
        //hardcoded extra margin for the toolbox right now
 
231
        if (immutability() == Mutable) {
 
232
            bottomHeight += 20;
 
233
        }
 
234
    //Default to horizontal for now
 
235
    } else {
 
236
        //hardcoded extra margin for the toolbox for now
 
237
        if (immutability() == Mutable) {
 
238
            if (QApplication::layoutDirection() == Qt::RightToLeft) {
 
239
                leftWidth += 20;
 
240
            } else {
 
241
                rightWidth += 20;
 
242
            }
 
243
        }
 
244
    }
 
245
#endif
 
246
 
 
247
    switch (location()) {
 
248
    case LeftEdge:
 
249
        rightWidth = qMin(rightWidth, qMax(qreal(1), size().width() - KIconLoader::SizeMedium));
 
250
        break;
 
251
    case RightEdge:
 
252
        leftWidth = qMin(leftWidth, qMax(qreal(1), size().width() - KIconLoader::SizeMedium));
 
253
        break;
 
254
    case TopEdge:
 
255
        bottomHeight = qMin(bottomHeight, qMax(qreal(1), size().height() - KIconLoader::SizeMedium));
 
256
        break;
 
257
    case BottomEdge:
 
258
        topHeight = qMin(topHeight, qMax(qreal(1), size().height() - KIconLoader::SizeMedium));
 
259
        break;
 
260
    default:
 
261
        break;
 
262
    }
 
263
 
 
264
    //invalidate the layout and set again
 
265
    if (layout()) {
 
266
        layout()->setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
 
267
        layout()->invalidate();
 
268
    }
 
269
 
 
270
    update();
 
271
}
 
272
 
 
273
void Panel::constraintsEvent(Plasma::Constraints constraints)
 
274
{
 
275
    kDebug() << "constraints updated with" << constraints << "!!!!!!";
 
276
 
 
277
    if (constraints & Plasma::FormFactorConstraint) {
 
278
        Plasma::FormFactor form = formFactor();
 
279
        Qt::Orientation layoutDirection = form == Plasma::Vertical ? Qt::Vertical : Qt::Horizontal;
 
280
 
 
281
        // create our layout!
 
282
        if (layout()) {
 
283
            QGraphicsLayout *lay = layout();
 
284
            QGraphicsLinearLayout * linearLay = dynamic_cast<QGraphicsLinearLayout *>(lay);
 
285
            if (linearLay) {
 
286
                linearLay->setOrientation(layoutDirection);
 
287
            }
 
288
        } else {
 
289
            m_layout = new QGraphicsLinearLayout(this);
 
290
            m_layout->setOrientation(layoutDirection);
 
291
            m_layout->setContentsMargins(0, 0, 0, 0);
 
292
            m_layout->setSpacing(4);
 
293
            m_layout->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
 
294
            setLayout(m_layout);
 
295
            updateBorders();
 
296
 
 
297
            foreach (Applet *applet, applets()) {
 
298
                m_layout->addItem(applet);
 
299
            }
 
300
        }
 
301
    }
 
302
 
 
303
    //we need to know if the width or height is 100%
 
304
    if (constraints & Plasma::LocationConstraint || constraints & Plasma::SizeConstraint) {
 
305
        QSize size = geometry().size().toSize();
 
306
        QRectF screenRect = screen() >= 0 ? QApplication::desktop()->screenGeometry(screen()) : geometry();
 
307
 
 
308
        if (formFactor() == Horizontal ||
 
309
            formFactor() == Vertical) {
 
310
            m_background->setElementPrefix(location());
 
311
        } else {
 
312
            m_background->setElementPrefix(QString());
 
313
        }
 
314
 
 
315
        m_background->resizeFrame(size);
 
316
        updateBorders();
 
317
    }
 
318
 
 
319
    if (constraints & Plasma::SizeConstraint && m_appletOverlay) {
 
320
        m_appletOverlay->resize(size());
 
321
    }
 
322
 
 
323
    //FIXME: this seems the only way to correctly resize the layout the first time when the
 
324
    // saved panel size is less than the default is to setting a maximum size.
 
325
    // this shouldn't happen. maybe even a qgraphicslayout bug?
 
326
    if (layout() && (constraints & Plasma::SizeConstraint)) {
 
327
        layout()->setMaximumSize(size());
 
328
    }
 
329
 
 
330
    if (constraints & Plasma::LocationConstraint) {
 
331
        setFormFactorFromLocation(location());
 
332
    }
 
333
 
 
334
    if (constraints & Plasma::ImmutableConstraint) {
 
335
        updateBorders();
 
336
 
 
337
        QAction *a = action("lock panel");
 
338
        if (a) {
 
339
            switch (immutability()) {
 
340
                case Plasma::SystemImmutable:
 
341
                    a->setEnabled(false);
 
342
                    a->setVisible(false);
 
343
                    break;
 
344
 
 
345
                case Plasma::UserImmutable:
 
346
                    a->setText(i18n("Unlock Panel"));
 
347
                    a->setIcon(KIcon("object-unlocked"));
 
348
                    a->setEnabled(true);
 
349
                    a->setVisible(true);
 
350
                    break;
 
351
 
 
352
                case Plasma::Mutable:
 
353
                    a->setText(i18n("Lock Panel"));
 
354
                    a->setIcon(KIcon("object-locked"));
 
355
                    a->setEnabled(true);
 
356
                    a->setVisible(true);
 
357
                    break;
 
358
            }
 
359
        }
 
360
    }
 
361
 
 
362
    if (constraints & Plasma::StartupCompletedConstraint) {
 
363
        connect(this, SIGNAL(appletAdded(Plasma::Applet*,QPointF)),
 
364
                this, SLOT(layoutApplet(Plasma::Applet*,QPointF)));
 
365
        delete action("remove");
 
366
    }
 
367
}
 
368
 
 
369
QList<QAction *> Panel::contextualActions()
 
370
{
 
371
    QList<QAction *> actions;
 
372
 
 
373
    QAction *a = action("lock panel");
 
374
    if (a) {
 
375
        actions << a;
 
376
    }
 
377
 
 
378
    return actions;
 
379
}
 
380
 
 
381
void Panel::updateConfigurationMode(bool config)
 
382
{
 
383
    if (config && !m_appletOverlay && immutability() == Plasma::Mutable) {
 
384
        m_appletOverlay = new LinearAppletOverlay(this, m_layout);
 
385
        m_appletOverlay->resize(size());
 
386
        connect (m_appletOverlay, SIGNAL(dropRequested(QGraphicsSceneDragDropEvent *)),
 
387
                 this, SLOT(overlayRequestedDrop(QGraphicsSceneDragDropEvent *)));
 
388
    } else if (!config) {
 
389
        delete m_appletOverlay;
 
390
        m_appletOverlay = 0;
 
391
    }
 
392
}
 
393
 
 
394
void Panel::overlayRequestedDrop(QGraphicsSceneDragDropEvent *event)
 
395
{
 
396
    dropEvent(event);
 
397
}
 
398
 
 
399
//TODO: fold it into saveContents even if it's not strictly contents related?
 
400
void Panel::saveState(KConfigGroup &config) const
 
401
{
 
402
    config.writeEntry("minimumSize", minimumSize());
 
403
    config.writeEntry("maximumSize", maximumSize());
 
404
}
 
405
 
 
406
void Panel::paintInterface(QPainter *painter,
 
407
                           const QStyleOptionGraphicsItem *option,
 
408
                           const QRect& contentsRect)
 
409
{
 
410
    Q_UNUSED(contentsRect)
 
411
 
 
412
    //FIXME: this background drawing is bad and ugly =)
 
413
    // draw the background untransformed (saves lots of per-pixel-math)
 
414
    painter->save();
 
415
    painter->resetTransform();
 
416
 
 
417
    const Containment::StyleOption *containmentOpt = qstyleoption_cast<const Containment::StyleOption *>(option);
 
418
 
 
419
    QRect viewGeom;
 
420
    if (containmentOpt) {
 
421
        viewGeom = containmentOpt->view->geometry();
 
422
    }
 
423
 
 
424
    painter->fillRect(option->exposedRect, Qt::transparent);
 
425
    m_background->paintFrame(painter, option->exposedRect, option->exposedRect);
 
426
 
 
427
 
 
428
    // restore transformation and composition mode
 
429
    painter->restore();
 
430
}
 
431
 
 
432
void Panel::setFormFactorFromLocation(Plasma::Location loc) {
 
433
    switch (loc) {
 
434
        case BottomEdge:
 
435
        case TopEdge:
 
436
            //kDebug() << "setting horizontal form factor";
 
437
            setFormFactor(Plasma::Horizontal);
 
438
            break;
 
439
        case RightEdge:
 
440
        case LeftEdge:
 
441
            //kDebug() << "setting vertical form factor";
 
442
            setFormFactor(Plasma::Vertical);
 
443
            break;
 
444
        case Floating:
 
445
            //TODO: implement a form factor for floating panels
 
446
            kDebug() << "Floating is unimplemented.";
 
447
            break;
 
448
        default:
 
449
            kDebug() << "invalid location!!";
 
450
    }
 
451
}
 
452
 
 
453
void Panel::restore(KConfigGroup &group)
 
454
{
 
455
    Containment::restore(group);
 
456
 
 
457
    KConfigGroup appletsConfig(&group, "Applets");
 
458
 
 
459
    QMap<int, Applet *> oderedApplets;
 
460
    QList<Applet *> unoderedApplets;
 
461
 
 
462
    foreach (Applet *applet, applets()) {
 
463
        KConfigGroup appletConfig(&appletsConfig, QString::number(applet->id()));
 
464
        KConfigGroup layoutConfig(&appletConfig, "LayoutInformation");
 
465
 
 
466
        int order = layoutConfig.readEntry("Order", -1);
 
467
 
 
468
        if (order > -1) {
 
469
            oderedApplets[order] = applet;
 
470
        //if LayoutInformation is not available use the usual way, as a bonus makes it retrocompatible with oler configs
 
471
        } else {
 
472
            unoderedApplets.append(applet);
 
473
        }
 
474
 
 
475
        connect(applet, SIGNAL(sizeHintChanged(Qt::SizeHint)), this, SLOT(updateSize()));
 
476
    }
 
477
 
 
478
    foreach (Applet *applet, oderedApplets) {
 
479
        m_layout->addItem(applet);
 
480
    }
 
481
 
 
482
    foreach (Applet *applet, unoderedApplets) {
 
483
        layoutApplet(applet, applet->pos());
 
484
    }
 
485
 
 
486
    updateSize();
 
487
}
 
488
 
 
489
void Panel::saveContents(KConfigGroup &group) const
 
490
{
 
491
    Containment::saveContents(group);
 
492
 
 
493
    if (!m_layout) {
 
494
        return;
 
495
    }
 
496
 
 
497
    KConfigGroup appletsConfig(&group, "Applets");
 
498
    for (int order = 0; order < m_layout->count(); ++order) {
 
499
        const Applet *applet = dynamic_cast<Applet *>(m_layout->itemAt(order));
 
500
        if (applet) {
 
501
            KConfigGroup appletConfig(&appletsConfig, QString::number(applet->id()));
 
502
            KConfigGroup layoutConfig(&appletConfig, "LayoutInformation");
 
503
 
 
504
            layoutConfig.writeEntry("Order", order);
 
505
        }
 
506
    }
 
507
}
 
508
 
 
509
K_EXPORT_PLASMA_APPLET(netpanel, Panel)
 
510
 
 
511
#include "panel.moc"
 
512