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

« back to all changes in this revision

Viewing changes to plasma/generic/applets/quicklaunch/popuplauncherlist.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 "popuplauncherlist.h"
 
20
 
 
21
// Qt
 
22
#include <Qt>
 
23
#include <QtCore/QEvent>
 
24
#include <QtCore/QMimeData>
 
25
#include <QtCore/QPointer>
 
26
#include <QtCore/QPointF>
 
27
#include <QtCore/QRectF>
 
28
#include <QtCore/QUrl>
 
29
#include <QtGui/QApplication>
 
30
#include <QtGui/QBrush>
 
31
#include <QtGui/QDrag>
 
32
#include <QtGui/QGraphicsItem>
 
33
#include <QtGui/QGraphicsLinearLayout>
 
34
#include <QtGui/QGraphicsSceneDragDropEvent>
 
35
#include <QtGui/QGraphicsSceneMouseEvent>
 
36
#include <QtGui/QGraphicsSceneResizeEvent>
 
37
#include <QtGui/QGraphicsWidget>
 
38
#include <QtGui/QIcon>
 
39
#include <QtGui/QPainter>
 
40
#include <QtGui/QSizePolicy>
 
41
#include <QtGui/QStyleOptionGraphicsItem>
 
42
#include <QtGui/QWidget>
 
43
 
 
44
// KDE
 
45
#include <KIcon>
 
46
#include <KIconLoader>
 
47
#include <KUrl>
 
48
 
 
49
// Plasma
 
50
#include <Plasma/Plasma>
 
51
#include <Plasma/IconWidget>
 
52
#include <Plasma/Theme>
 
53
#include <Plasma/ToolTipContent>
 
54
#include <Plasma/ToolTipManager>
 
55
 
 
56
// stdlib
 
57
#include <math.h>
 
58
 
 
59
// Own
 
60
#include "launcherdata.h"
 
61
#include "launcher.h"
 
62
 
 
63
using Plasma::Theme;
 
64
 
 
65
namespace Quicklaunch {
 
66
 
 
67
class DropMarker : public Launcher {
 
68
 
 
69
public:
 
70
    DropMarker(PopupLauncherList *parent)
 
71
        : Launcher(LauncherData(), parent)
 
72
    {
 
73
        hide();
 
74
    }
 
75
 
 
76
protected:
 
77
    void paint(
 
78
        QPainter *painter,
 
79
        const QStyleOptionGraphicsItem *option,
 
80
        QWidget *widget)
 
81
    {
 
82
        // This mirrors the behavior of the panel spacer committed by mart
 
83
        // workspace/plasma/desktop/containments/panel/panel.cpp R875513)
 
84
        QColor brushColor(Theme::defaultTheme()->color(Theme::TextColor));
 
85
        brushColor.setAlphaF(0.3);
 
86
 
 
87
        painter->setRenderHint(QPainter::Antialiasing);
 
88
        painter->setPen(Qt::NoPen);
 
89
        painter->setBrush(QBrush(brushColor));
 
90
 
 
91
        painter->drawRoundedRect(contentsRect(), 4, 4);
 
92
        Launcher::paint(painter, option, widget);
 
93
    }
 
94
};
 
95
 
 
96
PopupLauncherList::PopupLauncherList(QGraphicsItem *parent)
 
97
:
 
98
    QGraphicsWidget(parent),
 
99
    m_launchers(),
 
100
    m_preferredIconSize(),
 
101
    m_locked(false),
 
102
    m_layout(new QGraphicsLinearLayout()),
 
103
    m_mousePressedPos(),
 
104
    m_dropMarker(new DropMarker(this)),
 
105
    m_dropMarkerIndex(-1),
 
106
    m_placeHolder(0)
 
107
{
 
108
    m_layout->setOrientation(Qt::Vertical);
 
109
 
 
110
    m_dropMarker->setOrientation(Qt::Horizontal);
 
111
    m_dropMarker->setNameVisible(true);
 
112
    m_dropMarker->setMaximumHeight(KIconLoader::SizeSmallMedium);
 
113
 
 
114
    setLayout(m_layout);
 
115
    initPlaceHolder();
 
116
 
 
117
    setLocked(false);
 
118
}
 
119
 
 
120
 
 
121
void PopupLauncherList::setPreferredIconSize(int size)
 
122
{
 
123
    QSizeF newSize(size, size);
 
124
 
 
125
    if (newSize == m_preferredIconSize) {
 
126
        return;
 
127
    }
 
128
 
 
129
    m_preferredIconSize = newSize;
 
130
    m_dropMarker->setPreferredIconSize(newSize);
 
131
 
 
132
    Q_FOREACH (Launcher *launcher, m_launchers) {
 
133
        launcher->setPreferredIconSize(newSize);
 
134
    }
 
135
 
 
136
    if (m_placeHolder) {
 
137
        m_placeHolder->setPreferredIconSize(newSize);
 
138
    }
 
139
}
 
140
 
 
141
bool PopupLauncherList::locked() const
 
142
{
 
143
    return m_locked;
 
144
}
 
145
 
 
146
void PopupLauncherList::setLocked(bool enable)
 
147
{
 
148
    m_locked = enable;
 
149
    setAcceptDrops(!enable);
 
150
}
 
151
 
 
152
QGraphicsLinearLayout * PopupLauncherList::layout() const
 
153
{
 
154
    return m_layout;
 
155
}
 
156
 
 
157
int PopupLauncherList::launcherCount() const
 
158
{
 
159
    return m_launchers.size();
 
160
}
 
161
 
 
162
void PopupLauncherList::clear()
 
163
{
 
164
    while(launcherCount() > 0) {
 
165
        removeAt(0);
 
166
    }
 
167
}
 
168
 
 
169
void PopupLauncherList::insert(int index, const LauncherData &launcherData)
 
170
{
 
171
    QList<LauncherData> launcherDataList;
 
172
    launcherDataList.append(launcherData);
 
173
    insert(index, launcherDataList);
 
174
}
 
175
 
 
176
void PopupLauncherList::insert(int index, const QList<LauncherData> &launcherDataList)
 
177
{
 
178
    if (launcherDataList.size() == 0) {
 
179
        return;
 
180
    }
 
181
 
 
182
    if (m_launchers.size() == 0 && m_placeHolder) {
 
183
        deletePlaceHolder();
 
184
        index = 0;
 
185
    }
 
186
    else if (index < 0 || index > m_launchers.size()) {
 
187
        index = m_launchers.size();
 
188
    }
 
189
 
 
190
    Q_FOREACH(const LauncherData &launcherData, launcherDataList) {
 
191
 
 
192
        Launcher *launcher = new Launcher(launcherData);
 
193
 
 
194
        launcher->setOrientation(Qt::Horizontal);
 
195
        launcher->setNameVisible(true);
 
196
        launcher->setMaximumHeight(KIconLoader::SizeSmallMedium);
 
197
 
 
198
        if (m_preferredIconSize.isValid()) {
 
199
            launcher->setPreferredIconSize(m_preferredIconSize);
 
200
        }
 
201
 
 
202
        launcher->installEventFilter(this);
 
203
        connect(launcher, SIGNAL(clicked()), this, SIGNAL(launcherClicked()));
 
204
 
 
205
        m_launchers.insert(index, launcher);
 
206
 
 
207
        int layoutIndex = index;
 
208
 
 
209
        if (m_dropMarkerIndex != -1) {
 
210
            if (m_dropMarkerIndex <= index) {
 
211
                layoutIndex++;
 
212
            } else {
 
213
                m_dropMarkerIndex++;
 
214
            }
 
215
        }
 
216
 
 
217
        m_layout->insertItem(layoutIndex, launcher);
 
218
 
 
219
        index++;
 
220
    }
 
221
 
 
222
    Q_EMIT launchersChanged();
 
223
}
 
224
 
 
225
void PopupLauncherList::removeAt(int index)
 
226
{
 
227
    int layoutIndex = index;
 
228
 
 
229
    if (m_dropMarkerIndex != -1) {
 
230
        if (m_dropMarkerIndex <= index) {
 
231
            layoutIndex++;
 
232
        } else {
 
233
            m_dropMarkerIndex--;
 
234
        }
 
235
    }
 
236
 
 
237
    m_layout->removeAt(layoutIndex);
 
238
    delete m_launchers.takeAt(index);
 
239
 
 
240
    if (m_launchers.size() == 0 && m_dropMarkerIndex == -1) {
 
241
        initPlaceHolder();
 
242
    }
 
243
 
 
244
    Q_EMIT launchersChanged();
 
245
}
 
246
 
 
247
LauncherData PopupLauncherList::launcherAt(int index) const
 
248
{
 
249
    return m_launchers.at(index)->launcherData();
 
250
}
 
251
 
 
252
int PopupLauncherList::launcherIndexAtPosition(const QPointF& pos) const
 
253
{
 
254
    for (int i = 0; i < m_launchers.size(); i++) {
 
255
        if (m_launchers.at(i)->geometry().contains(pos)) {
 
256
            return i;
 
257
        }
 
258
    }
 
259
    return -1;
 
260
}
 
261
 
 
262
bool PopupLauncherList::eventFilter(QObject *watched, QEvent *event)
 
263
{
 
264
    Launcher *sourceLauncher =
 
265
        qobject_cast<Launcher*>(watched);
 
266
 
 
267
    // Start of Drag & Drop operations
 
268
    if (sourceLauncher && !m_locked) {
 
269
 
 
270
        if (event->type() == QEvent::GraphicsSceneMousePress) {
 
271
            m_mousePressedPos =
 
272
                static_cast<QGraphicsSceneMouseEvent*>(event)->pos();
 
273
 
 
274
            return false;
 
275
        }
 
276
        else if (event->type() == QEvent::GraphicsSceneMouseMove) {
 
277
 
 
278
            QGraphicsSceneMouseEvent *mouseEvent =
 
279
                static_cast<QGraphicsSceneMouseEvent*>(event);
 
280
 
 
281
            if ((m_mousePressedPos - mouseEvent->pos()).manhattanLength() >=
 
282
                    QApplication::startDragDistance()) {
 
283
 
 
284
                LauncherData sourceData = sourceLauncher->launcherData();
 
285
 
 
286
                QMimeData *mimeData = new QMimeData();
 
287
                sourceData.populateMimeData(mimeData);
 
288
 
 
289
                QPointer<QDrag> drag = new QDrag(mouseEvent->widget());
 
290
                drag->setMimeData(mimeData);
 
291
                drag->setPixmap(sourceLauncher->icon().pixmap(16, 16));
 
292
 
 
293
                int launcherIndex = m_launchers.indexOf(sourceLauncher);
 
294
 
 
295
                removeAt(launcherIndex);
 
296
 
 
297
                Qt::DropAction dropAction = drag->exec();
 
298
 
 
299
                if (dropAction != Qt::MoveAction) {
 
300
                    // Restore the icon.
 
301
                    insert(launcherIndex, sourceData);
 
302
                }
 
303
                return true;
 
304
            }
 
305
        }
 
306
    }
 
307
    return false;
 
308
}
 
309
 
 
310
void PopupLauncherList::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
 
311
{
 
312
    Q_ASSERT(!m_locked);
 
313
 
 
314
    Qt::DropAction proposedAction = event->proposedAction();
 
315
 
 
316
    if (proposedAction != Qt::CopyAction && proposedAction != Qt::MoveAction) {
 
317
 
 
318
        Qt::DropActions possibleActions = event->possibleActions();
 
319
 
 
320
        if (possibleActions & Qt::CopyAction) {
 
321
            event->setProposedAction(Qt::CopyAction);
 
322
        }
 
323
        else if (possibleActions & Qt::MoveAction) {
 
324
            event->setProposedAction(Qt::MoveAction);
 
325
        } else {
 
326
            event->setAccepted(false);
 
327
            return;
 
328
        }
 
329
    }
 
330
 
 
331
    // Initialize drop marker
 
332
    const QMimeData *mimeData = event->mimeData();
 
333
 
 
334
    if (LauncherData::canDecode(mimeData)) {
 
335
        QList<LauncherData> data = LauncherData::fromMimeData(mimeData);
 
336
 
 
337
        if (data.size() > 0) {
 
338
 
 
339
            if (data.size() == 1) {
 
340
                m_dropMarker->setLauncherData(data.at(0));
 
341
            } else {
 
342
                m_dropMarker->setLauncherData(LauncherData());
 
343
                m_dropMarker->setIcon("document-multiple");
 
344
 
 
345
                m_dropMarker->setText(i18n("Multiple items"));
 
346
            }
 
347
 
 
348
            if (m_launchers.size() != 0) {
 
349
                m_dropMarkerIndex = determineDropMarkerIndex(
 
350
                    mapFromScene(event->scenePos()));
 
351
 
 
352
            } else {
 
353
                deletePlaceHolder();
 
354
                m_dropMarkerIndex = 0;
 
355
            }
 
356
 
 
357
            m_layout->insertItem(m_dropMarkerIndex, m_dropMarker);
 
358
            m_dropMarker->show();
 
359
 
 
360
            event->accept();
 
361
        } else {
 
362
            event->setAccepted(false);
 
363
            return;
 
364
        }
 
365
    } else {
 
366
        event->setAccepted(false);
 
367
        return;
 
368
    }
 
369
}
 
370
 
 
371
void PopupLauncherList::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
 
372
{
 
373
    // DragMoveEvents are always preceded by DragEnterEvents
 
374
    Q_ASSERT(m_dropMarkerIndex != -1);
 
375
 
 
376
    int newDropMarkerIndex =
 
377
        determineDropMarkerIndex(mapFromScene(event->scenePos()));
 
378
 
 
379
    if (newDropMarkerIndex != m_dropMarkerIndex) {
 
380
 
 
381
        m_layout->removeAt(m_dropMarkerIndex);
 
382
        m_layout->insertItem(newDropMarkerIndex, m_dropMarker);
 
383
 
 
384
        m_dropMarkerIndex = newDropMarkerIndex;
 
385
    }
 
386
}
 
387
 
 
388
void PopupLauncherList::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
 
389
{
 
390
    Q_UNUSED(event);
 
391
 
 
392
    if (m_dropMarkerIndex != -1) {
 
393
 
 
394
        m_dropMarker->hide();
 
395
        m_layout->removeAt(m_dropMarkerIndex);
 
396
        m_dropMarker->setLauncherData(LauncherData());
 
397
        m_dropMarkerIndex = -1;
 
398
 
 
399
        if (m_launchers.size() == 0) {
 
400
            initPlaceHolder();
 
401
        }
 
402
    }
 
403
}
 
404
 
 
405
void PopupLauncherList::dropEvent(QGraphicsSceneDragDropEvent *event)
 
406
{
 
407
    int dropIndex = m_dropMarkerIndex;
 
408
 
 
409
    if (dropIndex != -1) {
 
410
        m_dropMarker->hide();
 
411
        m_layout->removeAt(m_dropMarkerIndex);
 
412
        m_dropMarker->setLauncherData(LauncherData());
 
413
        m_dropMarkerIndex = -1;
 
414
    }
 
415
 
 
416
    const QMimeData *mimeData = event->mimeData();
 
417
 
 
418
    if (LauncherData::canDecode(mimeData)) {
 
419
 
 
420
        QList<LauncherData> data = LauncherData::fromMimeData(mimeData);
 
421
        insert(dropIndex, data);
 
422
    }
 
423
 
 
424
    event->accept();
 
425
}
 
426
 
 
427
void PopupLauncherList::onPlaceHolderActivated()
 
428
{
 
429
    Q_ASSERT(m_placeHolder);
 
430
    Plasma::ToolTipManager::self()->show(m_placeHolder);
 
431
}
 
432
 
 
433
void PopupLauncherList::initPlaceHolder()
 
434
{
 
435
    Q_ASSERT(!m_placeHolder);
 
436
 
 
437
    m_placeHolder = new Plasma::IconWidget(KIcon("fork"), QString(), this);
 
438
    m_placeHolder->setPreferredIconSize(m_dropMarker->preferredIconSize());
 
439
 
 
440
    Plasma::ToolTipContent tcp(
 
441
        i18n("Quicklaunch"),
 
442
        i18n("Add launchers by Drag and Drop or by using the context menu."),
 
443
        m_placeHolder->icon());
 
444
    Plasma::ToolTipManager::self()->setContent(m_placeHolder, tcp);
 
445
 
 
446
    connect(m_placeHolder, SIGNAL(activated()), SLOT(onPlaceHolderActivated()));
 
447
    m_layout->addItem(m_placeHolder);
 
448
}
 
449
 
 
450
void PopupLauncherList::deletePlaceHolder()
 
451
{
 
452
    Q_ASSERT(m_placeHolder);
 
453
 
 
454
    m_layout->removeAt(0);
 
455
 
 
456
    delete m_placeHolder;
 
457
    m_placeHolder = 0;
 
458
}
 
459
 
 
460
int PopupLauncherList::determineDropMarkerIndex(const QPointF &localPos) const
 
461
{
 
462
    if (m_placeHolder) {
 
463
        return 0;
 
464
    }
 
465
 
 
466
    // Determine the new index of the drop marker.
 
467
    const int itemCount = m_layout->count();
 
468
 
 
469
    int index = 0;
 
470
    while (index + 1 < itemCount && localPos.y() > m_layout->itemAt(index + 1)->geometry().top()) {
 
471
        index++;
 
472
    }
 
473
    return index;
 
474
}
 
475
}
 
476
 
 
477
#include "popuplauncherlist.moc"