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

« back to all changes in this revision

Viewing changes to plasma/desktop/applets/tasks/abstracttaskitem.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) 2007 by Robert Knight <robertknight@gmail.com>          *
 
3
 *   Copyright (C) 2008 by Alexis Ménard <darktears31@gmail.com>           *
 
4
 *   Copyright (C) 2008 by Marco Martin <notmart@gmail.com>                *
 
5
 *                                                                         *
 
6
 *   This program is free software; you can redistribute it and/or modify  *
 
7
 *   it under the terms of the GNU General Public License as published by  *
 
8
 *   the Free Software Foundation; either version 2 of the License, or     *
 
9
 *   (at your option) any later version.                                   *
 
10
 *                                                                         *
 
11
 *   This program is distributed in the hope that it will be useful,       *
 
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
14
 *   GNU General Public License for more details.                          *
 
15
 *                                                                         *
 
16
 *   You should have received a copy of the GNU General Public License     *
 
17
 *   along with this program; if not, write to the                         *
 
18
 *   Free Software Foundation, Inc.,                                       *
 
19
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
 
20
 ***************************************************************************/
 
21
 
 
22
// Own
 
23
#include "abstracttaskitem.h"
 
24
 
 
25
// Qt
 
26
#include <QApplication>
 
27
#include <QFileInfo>
 
28
#include <QGraphicsLinearLayout>
 
29
#include <QGraphicsSceneContextMenuEvent>
 
30
#include <QGraphicsView>
 
31
#include <QStyleOptionGraphicsItem>
 
32
#include <QTextLayout>
 
33
#include <QTimer>
 
34
#include <QVarLengthArray>
 
35
#include <QPropertyAnimation>
 
36
#ifdef Q_WS_X11
 
37
#include <QX11Info>
 
38
#endif
 
39
 
 
40
// KDE
 
41
#include <KAuthorized>
 
42
#include <KColorUtils>
 
43
#include <KDebug>
 
44
#include <KGlobalSettings>
 
45
#include <KIcon>
 
46
#include <KIconEffect>
 
47
#include <KIconLoader>
 
48
 
 
49
#include <NETWinInfo>
 
50
 
 
51
#include <Plasma/Containment>
 
52
#include <Plasma/Corona>
 
53
#include <Plasma/FrameSvg>
 
54
#include <Plasma/PaintUtils>
 
55
#include <Plasma/Theme>
 
56
#include <Plasma/ToolTipManager>
 
57
#include <Plasma/WindowEffects>
 
58
 
 
59
#include <taskmanager/task.h>
 
60
#include <taskmanager/taskmanager.h>
 
61
#include <taskmanager/taskgroup.h>
 
62
 
 
63
#include "tasks.h"
 
64
#include "taskgroupitem.h"
 
65
 
 
66
static const int HOVER_EFFECT_TIMEOUT = 900;
 
67
 
 
68
AbstractTaskItem::AbstractTaskItem(QGraphicsWidget *parent, Tasks *applet)
 
69
    : QGraphicsWidget(parent),
 
70
      m_abstractItem(0),
 
71
      m_applet(applet),
 
72
      m_flags(0),
 
73
      m_backgroundFadeAnim(0),
 
74
      m_alpha(1),
 
75
      m_backgroundPrefix("normal"),
 
76
      m_activateTimerId(0),
 
77
      m_updateGeometryTimerId(0),
 
78
      m_updateTimerId(0),
 
79
      m_hoverEffectTimerId(0),
 
80
      m_attentionTimerId(0),
 
81
      m_attentionTicks(0),
 
82
      m_lastViewId(0),
 
83
      m_showText(true),
 
84
      m_layoutAnimationLock(false),
 
85
      m_firstGeometryUpdate(false)
 
86
{
 
87
    m_layoutAnimation = new QPropertyAnimation(this, "animationPos", this);
 
88
    m_layoutAnimation->setEasingCurve(QEasingCurve::InOutQuad);
 
89
    m_layoutAnimation->setDuration(250);
 
90
 
 
91
    setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
 
92
    setAcceptsHoverEvents(true);
 
93
    setAcceptDrops(true);
 
94
    setFocusPolicy(Qt::StrongFocus);
 
95
    setFlag(QGraphicsItem::ItemIsFocusable);
 
96
 
 
97
    checkSettings();
 
98
    connect(applet->itemBackground(), SIGNAL(repaintNeeded()), this, SLOT(syncActiveRect()));
 
99
    connect(applet, SIGNAL(settingsChanged()), this, SLOT(checkSettings()));
 
100
}
 
101
 
 
102
QSize AbstractTaskItem::basicPreferredSize() const
 
103
{
 
104
    QFontMetrics fm(KGlobalSettings::taskbarFont());
 
105
    QSize mSize = fm.size(0, "M");
 
106
    const int iconsize = KIconLoader::SizeSmall;
 
107
 
 
108
    //the 4 should be the default spacing between layout items, is there a way to fetch it without hardcoding?
 
109
    // in small panels, we'll reduce the spacing a bit so it's easier to cramp the text in and still get two rows
 
110
    int topMargin = m_applet->itemTopMargin();
 
111
    int bottomMargin = m_applet->itemBottomMargin();
 
112
 
 
113
    //if this item is out of the applet rect must be in a popup
 
114
    //const bool inPopup = (m_applet->mapToScene(m_applet->rect()).boundingRect().contains(mapToScene(rect()).boundingRect()))
 
115
 
 
116
    if (m_applet->size().height() < 44) {
 
117
        topMargin = 1;
 
118
        bottomMargin = 1;
 
119
    } else if (m_applet->size().height() < 64) {
 
120
        topMargin = qMax(1, topMargin/2); 
 
121
        bottomMargin = qMax(1, bottomMargin/2); 
 
122
    }
 
123
 
 
124
    //kDebug() << (QObject*)this;
 
125
    return QSize(mSize.width()*12 + m_applet->itemLeftMargin() + m_applet->itemRightMargin() + KIconLoader::SizeSmall,
 
126
            qMax(mSize.height(), iconsize) + topMargin + bottomMargin);
 
127
}
 
128
 
 
129
void AbstractTaskItem::setPreferredOffscreenSize()
 
130
{
 
131
    QFontMetrics fm(KGlobalSettings::taskbarFont());
 
132
    QSize mSize = fm.size(0, "M");
 
133
    int iconsize = KIconLoader::SizeSmall;
 
134
    int topMargin = m_applet->offscreenTopMargin();
 
135
    int bottomMargin = m_applet->offscreenBottomMargin();
 
136
    int rightMargin = m_applet->offscreenRightMargin();
 
137
    int leftMargin = m_applet->offscreenLeftMargin();
 
138
 
 
139
    //kDebug() << (QObject*)this;
 
140
    QSizeF s(mSize.width() * 12 + leftMargin + rightMargin + KIconLoader::SizeSmall,
 
141
             qMax(mSize.height(), iconsize) + topMargin + bottomMargin);
 
142
    setPreferredSize(s);
 
143
}
 
144
 
 
145
void AbstractTaskItem::setPreferredOnscreenSize()
 
146
{
 
147
    setPreferredSize(basicPreferredSize());
 
148
}
 
149
 
 
150
AbstractTaskItem::~AbstractTaskItem()
 
151
{
 
152
    stopWindowHoverEffect();
 
153
    emit destroyed(this);
 
154
    Plasma::ToolTipManager::self()->unregisterWidget(this);
 
155
}
 
156
 
 
157
void AbstractTaskItem::checkSettings()
 
158
{
 
159
    TaskGroupItem *group = qobject_cast<TaskGroupItem *>(this);
 
160
 
 
161
    if (m_applet->showToolTip() && (!group || group->collapsed())) {
 
162
        clearToolTip();
 
163
    } else {
 
164
        Plasma::ToolTipManager::self()->unregisterWidget(this);
 
165
    }
 
166
}
 
167
 
 
168
void AbstractTaskItem::clearToolTip()
 
169
{
 
170
    Plasma::ToolTipContent data;
 
171
    data.setInstantPopup(true);
 
172
 
 
173
    Plasma::ToolTipManager::self()->setContent(this, data);
 
174
}
 
175
 
 
176
void AbstractTaskItem::clearAbstractItem()
 
177
{
 
178
    m_abstractItem = 0;
 
179
}
 
180
 
 
181
void AbstractTaskItem::textChanged()
 
182
{
 
183
    m_cachedShadow = QPixmap();
 
184
}
 
185
 
 
186
QString AbstractTaskItem::text() const
 
187
{
 
188
    if (m_abstractItem) {
 
189
        return m_abstractItem->name();
 
190
    } else {
 
191
        kDebug() << "no abstract item?";
 
192
    }
 
193
 
 
194
    return QString();
 
195
}
 
196
 
 
197
QIcon AbstractTaskItem::icon() const
 
198
{
 
199
    if (m_abstractItem) {
 
200
        return m_abstractItem->icon();
 
201
    }
 
202
 
 
203
    return QIcon();
 
204
}
 
205
 
 
206
void AbstractTaskItem::setTaskFlags(const TaskFlags flags)
 
207
{
 
208
    if (((m_flags & TaskWantsAttention) != 0) != ((flags & TaskWantsAttention) != 0)) {
 
209
        //kDebug() << "task attention state changed" << m_attentionTimerId;
 
210
        m_flags = flags;
 
211
        if (flags & TaskWantsAttention) {
 
212
            m_applet->needsVisualFocus(true);
 
213
            // start attention getting
 
214
            if (!m_attentionTimerId) {
 
215
                m_attentionTimerId = startTimer(500);
 
216
            }
 
217
        } else {
 
218
            m_applet->needsVisualFocus(false);
 
219
            if (m_attentionTimerId) {
 
220
                killTimer(m_attentionTimerId);
 
221
                m_attentionTimerId = 0;
 
222
            }
 
223
        }
 
224
    }
 
225
 
 
226
    m_flags = flags;
 
227
 
 
228
    QString newBackground;
 
229
    if (m_flags & TaskIsMinimized) {
 
230
        newBackground = "minimized";
 
231
    } else if (m_flags & TaskHasFocus) {
 
232
        newBackground = "focus";
 
233
    } else {
 
234
        newBackground = "normal";
 
235
    }
 
236
 
 
237
    if (newBackground != m_backgroundPrefix) {
 
238
        fadeBackground(newBackground, 250);
 
239
    }
 
240
}
 
241
 
 
242
void AbstractTaskItem::fadeBackground(const QString &newBackground, int duration)
 
243
{
 
244
    TaskGroupItem *group = qobject_cast<TaskGroupItem*>(this);
 
245
    if (group && !group->collapsed()) {
 
246
        return;
 
247
    }
 
248
 
 
249
    m_oldBackgroundPrefix = m_backgroundPrefix;
 
250
    m_backgroundPrefix = newBackground;
 
251
 
 
252
    if (m_oldBackgroundPrefix.isEmpty()) {
 
253
        update();
 
254
    } else {
 
255
        if (!m_backgroundFadeAnim) {
 
256
            m_backgroundFadeAnim = new QPropertyAnimation(this);
 
257
            m_backgroundFadeAnim->setDuration(duration);
 
258
            m_backgroundFadeAnim->setEasingCurve(QEasingCurve::InQuad);
 
259
            m_backgroundFadeAnim->setPropertyName("backgroundFadeAlpha");
 
260
            m_backgroundFadeAnim->setTargetObject(this);
 
261
            m_backgroundFadeAnim->setStartValue(0);
 
262
            m_backgroundFadeAnim->setEndValue(1);
 
263
        }
 
264
 
 
265
        m_backgroundFadeAnim->start();
 
266
    }
 
267
}
 
268
 
 
269
AbstractTaskItem::TaskFlags AbstractTaskItem::taskFlags() const
 
270
{
 
271
    return m_flags;
 
272
}
 
273
 
 
274
void AbstractTaskItem::toolTipAboutToShow()
 
275
{
 
276
    if (m_applet->showToolTip()) {
 
277
        updateToolTip();
 
278
        connect(Plasma::ToolTipManager::self(),
 
279
                SIGNAL(windowPreviewActivated(WId,Qt::MouseButtons,Qt::KeyboardModifiers,QPoint)),
 
280
                this, SLOT(activateWindow(WId,Qt::MouseButtons)));
 
281
    } else {
 
282
        clearToolTip();
 
283
    }
 
284
}
 
285
 
 
286
void AbstractTaskItem::toolTipHidden()
 
287
{
 
288
    clearToolTip();
 
289
    disconnect(Plasma::ToolTipManager::self(),
 
290
               SIGNAL(windowPreviewActivated(WId,Qt::MouseButtons,Qt::KeyboardModifiers,QPoint)),
 
291
               this, SLOT(activateWindow(WId,Qt::MouseButtons)));
 
292
}
 
293
 
 
294
void AbstractTaskItem::activateWindow(WId id, Qt::MouseButtons buttons)
 
295
{
 
296
    if (buttons & Qt::LeftButton) {
 
297
        if (parentGroup()) {
 
298
            AbstractTaskItem *item = parentGroup()->taskItemForWId(id);
 
299
            if (item) {
 
300
                item->activate();
 
301
            }
 
302
        }
 
303
    }
 
304
}
 
305
 
 
306
void AbstractTaskItem::queueUpdate()
 
307
{
 
308
    if (m_updateTimerId || m_attentionTimerId) {
 
309
        return;
 
310
    }
 
311
 
 
312
    if (m_lastUpdate.elapsed() < 100) {
 
313
        m_updateTimerId = startTimer(100);
 
314
        return;
 
315
    }
 
316
 
 
317
    update();
 
318
    m_lastUpdate.restart();
 
319
}
 
320
 
 
321
void AbstractTaskItem::focusInEvent(QFocusEvent *event)
 
322
{
 
323
    Q_UNUSED(event)
 
324
 
 
325
    setTaskFlags(m_flags | TaskHasFocus);
 
326
    update();
 
327
}
 
328
 
 
329
void AbstractTaskItem::focusOutEvent(QFocusEvent *event)
 
330
{
 
331
    Q_UNUSED(event)
 
332
 
 
333
    setTaskFlags(m_flags & ~TaskHasFocus);
 
334
    update();
 
335
}
 
336
 
 
337
void AbstractTaskItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
 
338
{
 
339
    Q_UNUSED(event)
 
340
    fadeBackground("hover", 250);
 
341
    QGraphicsWidget *w = parentWidget();
 
342
    if (w && this != m_applet->rootGroupItem()) {
 
343
        if (m_hoverEffectTimerId) {
 
344
            killTimer(m_hoverEffectTimerId);
 
345
            m_hoverEffectTimerId = 0;
 
346
        }
 
347
 
 
348
        m_hoverEffectTimerId = startTimer(HOVER_EFFECT_TIMEOUT);
 
349
    }
 
350
}
 
351
 
 
352
void AbstractTaskItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
 
353
{
 
354
    Q_UNUSED(event)
 
355
 
 
356
    stopWindowHoverEffect();
 
357
 
 
358
    QString backgroundPrefix;
 
359
    if (m_flags & TaskWantsAttention) {
 
360
        backgroundPrefix = "attention";
 
361
    } else if (m_flags & TaskIsMinimized) {
 
362
        backgroundPrefix = "minimized";
 
363
    } else if (m_flags & TaskHasFocus) {
 
364
        backgroundPrefix = "focus";
 
365
    } else {
 
366
        backgroundPrefix = "normal";
 
367
    }
 
368
 
 
369
    fadeBackground(backgroundPrefix, 150);
 
370
}
 
371
 
 
372
void AbstractTaskItem::stopWindowHoverEffect()
 
373
{
 
374
    if (m_hoverEffectTimerId) {
 
375
        killTimer(m_hoverEffectTimerId);
 
376
        m_hoverEffectTimerId = 0;
 
377
    }
 
378
 
 
379
    if (m_lastViewId && m_applet->highlightWindows()) {
 
380
        Plasma::WindowEffects::highlightWindows(m_lastViewId, QList<WId>());
 
381
    }
 
382
}
 
383
 
 
384
void AbstractTaskItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
 
385
{
 
386
    if (event->button() == Qt::LeftButton && boundingRect().contains(event->pos())) {
 
387
        activate();
 
388
    }
 
389
}
 
390
 
 
391
void AbstractTaskItem::mousePressEvent(QGraphicsSceneMouseEvent *)
 
392
{
 
393
    update();
 
394
}
 
395
 
 
396
void AbstractTaskItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
 
397
{
 
398
    //kDebug();
 
399
    if (QPoint(event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < QApplication::startDragDistance()) {
 
400
        return;
 
401
    } //Wait a bit before starting drag
 
402
 
 
403
  /*  if((m_applet->taskSortOrder() != Tasks::NoSorting) && (m_applet->taskSortOrder() != Tasks::GroupSorting)){ //FIXME check somhow if drag is allowed
 
404
        return;
 
405
    }*/
 
406
 
 
407
    QByteArray data;
 
408
    data.resize(sizeof(AbstractTaskItem*));
 
409
    AbstractTaskItem *selfPtr = this;
 
410
    memcpy(data.data(), &selfPtr, sizeof(AbstractTaskItem*));
 
411
 
 
412
    QMimeData* mimeData = new QMimeData();
 
413
    setAdditionalMimeData(mimeData);
 
414
 
 
415
    if (mimeData->formats().isEmpty()) {
 
416
        delete mimeData;
 
417
        return;
 
418
    }
 
419
 
 
420
    QDrag *drag = new QDrag(event->widget());
 
421
    drag->setMimeData(mimeData);
 
422
    drag->setPixmap(icon().pixmap(20));
 
423
   // drag->setDragCursor( set the correct cursor //TODO
 
424
    drag->exec();
 
425
}
 
426
 
 
427
void AbstractTaskItem::timerEvent(QTimerEvent *event)
 
428
{
 
429
    if (event->timerId() == m_activateTimerId) {
 
430
        killTimer(m_activateTimerId);
 
431
        m_activateTimerId = 0;
 
432
        if (!isActive()) {
 
433
            activate();
 
434
        }
 
435
    } else if (event->timerId() == m_updateGeometryTimerId) {
 
436
        killTimer(m_updateGeometryTimerId);
 
437
        m_updateGeometryTimerId = 0;
 
438
        m_firstGeometryUpdate = true;
 
439
        publishIconGeometry();
 
440
    } else if (event->timerId() == m_updateTimerId) {
 
441
        killTimer(m_updateTimerId);
 
442
        m_updateTimerId = 0;
 
443
        update();
 
444
    } else if (event->timerId() == m_attentionTimerId) {
 
445
        ++m_attentionTicks;
 
446
        if (m_attentionTicks > 6) {
 
447
            killTimer(m_attentionTimerId);
 
448
            m_attentionTimerId = 0;
 
449
            m_attentionTicks = 0;
 
450
        }
 
451
 
 
452
        if (m_attentionTicks % 2 == 0) {
 
453
            fadeBackground("attention", 200);
 
454
        } else {
 
455
            fadeBackground("normal", 250);
 
456
        }
 
457
    } else if (event->timerId() == m_hoverEffectTimerId) {
 
458
        killTimer(m_hoverEffectTimerId);
 
459
        m_hoverEffectTimerId = 0;
 
460
        if (!isUnderMouse()) {
 
461
            return;
 
462
        }
 
463
 
 
464
#ifdef Q_WS_X11
 
465
        QList<WId> windows;
 
466
 
 
467
        if (m_abstractItem && m_abstractItem->itemType() == TaskManager::GroupItemType) {
 
468
            TaskManager::TaskGroup *group = qobject_cast<TaskManager::TaskGroup *>(m_abstractItem);
 
469
 
 
470
            if (group) {
 
471
                TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(this);
 
472
                if (groupItem && groupItem->popupDialog()) {
 
473
                    kDebug() << "adding" << groupItem->popupDialog()->winId();
 
474
                    windows.append(groupItem->popupDialog()->winId());
 
475
                }
 
476
 
 
477
                foreach (AbstractGroupableItem *item, group->members()) {
 
478
                    if (item->itemType() == TaskManager::TaskItemType) {
 
479
                        TaskManager::TaskItem *taskItem = qobject_cast<TaskManager::TaskItem *>(item);
 
480
                        if (taskItem && taskItem->task()) {
 
481
                            windows.append(taskItem->task()->window());
 
482
                        }
 
483
                    } //TODO: if taskgroup, recurse through sub-groups?
 
484
                }
 
485
            }
 
486
        } else {
 
487
            WindowTaskItem *windowTaskItem = qobject_cast<WindowTaskItem *>(this);
 
488
            if (windowTaskItem && windowTaskItem->parent()) {
 
489
                TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(windowTaskItem->parent());
 
490
                if (groupItem && groupItem->popupDialog()) {
 
491
                    windows.append(groupItem->popupDialog()->winId());
 
492
                }
 
493
            }
 
494
 
 
495
            TaskManager::TaskItem *taskItem = qobject_cast<TaskManager::TaskItem *>(m_abstractItem);
 
496
            if (taskItem && taskItem->task()) {
 
497
                windows.append(taskItem->task()->window());
 
498
            }
 
499
        }
 
500
 
 
501
        stopWindowHoverEffect();
 
502
        QGraphicsView *view = m_applet->view();
 
503
        if (view && m_applet->highlightWindows()) {
 
504
            m_lastViewId = view->winId();
 
505
            Plasma::WindowEffects::highlightWindows(m_lastViewId, windows);
 
506
        }
 
507
#endif
 
508
    } else {
 
509
        QGraphicsWidget::timerEvent(event);
 
510
    }
 
511
}
 
512
 
 
513
void AbstractTaskItem::paint(QPainter *painter,
 
514
                             const QStyleOptionGraphicsItem *option,
 
515
                             QWidget *widget)
 
516
{
 
517
    if (!m_abstractItem) {
 
518
        return;
 
519
    }
 
520
    //kDebug() << "painting" << (QObject*)this << text();
 
521
    painter->setRenderHint(QPainter::Antialiasing);
 
522
 
 
523
    if (m_abstractItem->itemType() != TaskManager::LauncherItemType) { //Launchers have no frame
 
524
        // draw background
 
525
        drawBackground(painter, option, widget);
 
526
    }
 
527
 
 
528
    // draw icon and text
 
529
    drawTask(painter, option, widget);
 
530
}
 
531
 
 
532
void AbstractTaskItem::syncActiveRect()
 
533
{
 
534
    m_cachedShadow = QPixmap();
 
535
    Plasma::FrameSvg *itemBackground = m_applet->itemBackground();
 
536
    itemBackground->setElementPrefix("normal");
 
537
 
 
538
    qreal left, top, right, bottom;
 
539
    itemBackground->getMargins(left, top, right, bottom);
 
540
 
 
541
    itemBackground->setElementPrefix("focus");
 
542
    qreal activeLeft, activeTop, activeRight, activeBottom;
 
543
    itemBackground->getMargins(activeLeft, activeTop, activeRight, activeBottom);
 
544
 
 
545
    m_activeRect = QRectF(QPointF(0, 0), size());
 
546
    m_activeRect.adjust(left - activeLeft, top - activeTop,
 
547
                        -(right - activeRight), -(bottom - activeBottom));
 
548
 
 
549
    itemBackground->setElementPrefix(m_backgroundPrefix);
 
550
 
 
551
    // check to see if there is enough room!
 
552
    QFontMetrics fm(font());
 
553
    const int minimumWidth = left + 8 + IconTextSpacing + right;
 
554
    m_showText = (size().width() >= fm.width("M") * 6 + minimumWidth);
 
555
    queueUpdate();
 
556
}
 
557
 
 
558
void AbstractTaskItem::resizeEvent(QGraphicsSceneResizeEvent *event)
 
559
{
 
560
    syncActiveRect();
 
561
    resizeBackground(event->newSize().toSize());
 
562
}
 
563
 
 
564
void AbstractTaskItem::resizeBackground(const QSize &size)
 
565
{
 
566
    Plasma::FrameSvg *itemBackground = m_applet->itemBackground();
 
567
 
 
568
    itemBackground->setElementPrefix("focus");
 
569
    m_applet->resizeItemBackground(size);
 
570
    itemBackground->setElementPrefix("normal");
 
571
    m_applet->resizeItemBackground(size);
 
572
    itemBackground->setElementPrefix("minimized");
 
573
    m_applet->resizeItemBackground(size);
 
574
    itemBackground->setElementPrefix("attention");
 
575
    m_applet->resizeItemBackground(size);
 
576
    itemBackground->setElementPrefix("hover");
 
577
    m_applet->resizeItemBackground(size);
 
578
 
 
579
    //restore the prefix
 
580
    itemBackground->setElementPrefix(m_backgroundPrefix);
 
581
}
 
582
 
 
583
void AbstractTaskItem::drawBackground(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
 
584
{
 
585
    // Do not paint with invalid sizes, the happens when the layout is being initialized
 
586
    if (!option->rect.isValid()) {
 
587
        return;
 
588
    }
 
589
 
 
590
    /*FIXME -could be done more elegant with caching in tasks in a qhash <size,svg>.
 
591
    -do not use size() directly because this introduces the blackline syndrome.
 
592
    -This line is only needed when we have different items in the taskbar because of an expanded group for example. otherwise the resizing in the resizeEvent is sufficient
 
593
    */
 
594
    Plasma::FrameSvg *itemBackground = m_applet->itemBackground();
 
595
 
 
596
    if (~option->state & QStyle::State_Sunken && 
 
597
        (!m_backgroundFadeAnim || m_backgroundFadeAnim->state() != QAbstractAnimation::Running)) {
 
598
        itemBackground->setElementPrefix(m_backgroundPrefix);
 
599
        //since a single framesvg is shared between all tasks, we could have to resize it even if there wasn't a resizeevent
 
600
        if (size().toSize() != itemBackground->frameSize()) {
 
601
            resizeBackground(size().toSize());
 
602
        }
 
603
 
 
604
        if (itemBackground->frameSize() == m_activeRect.size().toSize()) {
 
605
            itemBackground->paintFrame(painter, m_activeRect.topLeft());
 
606
        } else {
 
607
            itemBackground->paintFrame(painter);
 
608
        }
 
609
        //itemBackground->paintFrame(painter, backgroundPosition);
 
610
        return;
 
611
    }
 
612
 
 
613
    itemBackground->setElementPrefix(m_oldBackgroundPrefix);
 
614
    //since a single framesvg is shared between all tasks, we could have to resize it even if there wasn't a resizeevent
 
615
    if (size().toSize() != itemBackground->frameSize()) {
 
616
        resizeBackground(size().toSize());
 
617
    }
 
618
 
 
619
    QPixmap oldBackground;
 
620
 
 
621
    if (option->state & QStyle::State_Sunken) {
 
622
        oldBackground = QPixmap(m_activeRect.size().toSize());
 
623
        oldBackground.fill(Qt::transparent);
 
624
        m_alpha = 0.4;
 
625
    } else {
 
626
        oldBackground = itemBackground->framePixmap();
 
627
    }
 
628
 
 
629
    itemBackground->setElementPrefix(m_backgroundPrefix);
 
630
    //since a single framesvg is shared between all tasks, we could have to resize it even if there wasn't a resizeevent
 
631
    if (size().toSize() != itemBackground->frameSize()) {
 
632
        resizeBackground(size().toSize());
 
633
    }
 
634
 
 
635
    QPixmap result = Plasma::PaintUtils::transition(oldBackground, itemBackground->framePixmap(), m_alpha);
 
636
 
 
637
    if (result.size() == m_activeRect.size().toSize()) {
 
638
        painter->drawPixmap(m_activeRect.topLeft(), result);
 
639
    } else {
 
640
        painter->drawPixmap(QPoint(0,0), result);
 
641
    }
 
642
}
 
643
 
 
644
void AbstractTaskItem::drawTask(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
 
645
{
 
646
    Q_UNUSED(option)
 
647
 
 
648
    QRectF bounds = boundingRect();
 
649
 
 
650
    if (m_abstractItem->itemType() != TaskManager::LauncherItemType) {
 
651
        bounds = bounds.adjusted(m_applet->itemLeftMargin(), m_applet->itemTopMargin(), -m_applet->itemRightMargin(), -m_applet->itemBottomMargin());
 
652
    } else {
 
653
        bounds = bounds.adjusted(5,5,-5,-5);
 
654
    }
 
655
 
 
656
    WindowTaskItem *window = qobject_cast<WindowTaskItem *>(this);
 
657
    QGraphicsWidget *busyWidget;
 
658
    busyWidget = window ? window->busyWidget() : 0;
 
659
    const QRectF iconR = iconRect(bounds);
 
660
 
 
661
    if (busyWidget) {
 
662
        busyWidget->setGeometry(iconR);
 
663
        busyWidget->show();
 
664
    } else {
 
665
        /*
 
666
        kDebug() << bool(option->state & QStyle::State_MouseOver) << m_backgroundFadeAnim <<
 
667
            (m_backgroundFadeAnim ? m_backgroundFadeAnim->state() : QAbstractAnimation::Stopped);*/
 
668
        const bool fadingBg = m_backgroundFadeAnim && m_backgroundFadeAnim->state() == QAbstractAnimation::Running;
 
669
        if ((!fadingBg && !(option->state & QStyle::State_MouseOver)) ||
 
670
            (m_oldBackgroundPrefix != "hover" && m_backgroundPrefix != "hover")) {
 
671
            // QIcon::paint does some alignment work and can lead to funny
 
672
            // things when icon().size() != iconR.toRect().size()
 
673
            QPixmap result = icon().pixmap(iconR.toRect().size());
 
674
            painter->drawPixmap(iconR.topLeft(), result);
 
675
        } else {
 
676
            KIconEffect *effect = KIconLoader::global()->iconEffect();
 
677
            QPixmap result = icon().pixmap(iconR.toRect().size());
 
678
 
 
679
            if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
 
680
                if (qFuzzyCompare(qreal(1.0), m_alpha)) {
 
681
                    result = effect->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
 
682
                } else {
 
683
                    result = Plasma::PaintUtils::transition(result,
 
684
                                        effect->apply(result, KIconLoader::Desktop,
 
685
                                        KIconLoader::ActiveState), m_backgroundPrefix != "hover" ? 1 - m_alpha : m_alpha);
 
686
                }
 
687
            }
 
688
 
 
689
            painter->drawPixmap(iconR.topLeft(), result);
 
690
        }
 
691
    }
 
692
 
 
693
    painter->setPen(QPen(textColor(), 1.0));
 
694
 
 
695
    if (m_abstractItem->itemType() != TaskManager::LauncherItemType) {
 
696
        if (m_showText) {
 
697
            QRect rect = textRect(bounds).toRect();
 
698
            if (rect.height() > 20) {
 
699
                rect.adjust(2, 2, -2, -2); // Create a text margin
 
700
            }
 
701
            QTextLayout layout;
 
702
            layout.setFont(KGlobalSettings::taskbarFont());
 
703
            layout.setTextOption(textOption());
 
704
 
 
705
            layoutText(layout, text(), rect.size());
 
706
            drawTextLayout(painter, layout, rect);
 
707
        }
 
708
 
 
709
        TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(this);
 
710
        if (groupItem) {
 
711
            QFont font(KGlobalSettings::smallestReadableFont());
 
712
            QFontMetrics fm(font);
 
713
            QRectF rect(expanderRect(bounds));
 
714
 
 
715
            Plasma::FrameSvg *itemBackground = m_applet->itemBackground();
 
716
 
 
717
            if (itemBackground->hasElement(expanderElement())) {
 
718
                QSizeF arrowSize(itemBackground->elementSize(expanderElement()));
 
719
                QRectF arrowRect(rect.center()-QPointF(arrowSize.width()/2, arrowSize.height()+fm.xHeight()/2), arrowSize);
 
720
                itemBackground->paint(painter, arrowRect, expanderElement());
 
721
 
 
722
                painter->setFont(font);
 
723
                rect.setTop(arrowRect.bottom());
 
724
                painter->drawText(rect, Qt::AlignHCenter|Qt::AlignTop, QString::number(groupItem->count()));
 
725
            } else {
 
726
                painter->setFont(font);
 
727
                painter->drawText(rect, Qt::AlignCenter, QString::number(groupItem->count()));
 
728
            }
 
729
        }
 
730
    }
 
731
}
 
732
 
 
733
QTextOption AbstractTaskItem::textOption() const
 
734
{
 
735
    Qt::LayoutDirection direction = QApplication::layoutDirection();
 
736
    Qt::Alignment alignment = QStyle::visualAlignment(direction, Qt::AlignLeft | Qt::AlignVCenter);
 
737
 
 
738
    QTextOption option;
 
739
    option.setTextDirection(direction);
 
740
    option.setAlignment(alignment);
 
741
 
 
742
    return option;
 
743
}
 
744
 
 
745
QSize AbstractTaskItem::layoutText(QTextLayout &layout, const QString &text,
 
746
                                   const QSize &constraints) const
 
747
{
 
748
    QFontMetrics metrics(layout.font());
 
749
    int leading     = metrics.leading();
 
750
    int height      = 0;
 
751
    int maxWidth    = constraints.width();
 
752
    int widthUsed   = 0;
 
753
    int lineSpacing = metrics.lineSpacing();
 
754
    QTextLine line;
 
755
 
 
756
    layout.setText(text);
 
757
 
 
758
    layout.beginLayout();
 
759
    while ((line = layout.createLine()).isValid()) {
 
760
        height += leading;
 
761
 
 
762
        // Make the last line that will fit infinitely long.
 
763
        // drawTextLayout() will handle this by fading the line out
 
764
        // if it won't fit in the constraints.
 
765
        if (height + 2 * lineSpacing > constraints.height()) {
 
766
            line.setPosition(QPoint(0, height));
 
767
            break;
 
768
        }
 
769
 
 
770
        line.setLineWidth(maxWidth);
 
771
        line.setPosition(QPoint(0, height));
 
772
 
 
773
        height += int(line.height());
 
774
        widthUsed = int(qMax(qreal(widthUsed), line.naturalTextWidth()));
 
775
    }
 
776
    layout.endLayout();
 
777
 
 
778
    return QSize(widthUsed, height);
 
779
}
 
780
 
 
781
void AbstractTaskItem::drawTextLayout(QPainter *painter, const QTextLayout &layout, const QRect &rect)
 
782
{
 
783
    if (rect.width() < 1 || rect.height() < 1) {
 
784
        return;
 
785
    }
 
786
 
 
787
    QPixmap pixmap(rect.size());
 
788
    pixmap.fill(Qt::transparent);
 
789
 
 
790
    QPainter p(&pixmap);
 
791
    p.setPen(painter->pen());
 
792
 
 
793
    // Create the alpha gradient for the fade out effect
 
794
    QLinearGradient alphaGradient(0, 0, 1, 0);
 
795
    alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
 
796
    if (layout.textOption().textDirection() == Qt::LeftToRight)
 
797
    {
 
798
        alphaGradient.setColorAt(0, QColor(0, 0, 0, 255));
 
799
        alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
 
800
    } else
 
801
    {
 
802
        alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
 
803
        alphaGradient.setColorAt(1, QColor(0, 0, 0, 255));
 
804
    }
 
805
 
 
806
    QFontMetrics fm(layout.font());
 
807
    int textHeight = layout.lineCount() * fm.lineSpacing();
 
808
 
 
809
    QPointF position(0, (rect.height() - textHeight) / 2 + (fm.tightBoundingRect("M").height() - fm.xHeight())/2);
 
810
    QList<QRect> fadeRects;
 
811
    int fadeWidth = 30;
 
812
 
 
813
    // Draw each line in the layout
 
814
    for (int i = 0; i < layout.lineCount(); i++)
 
815
    {
 
816
        QTextLine line = layout.lineAt(i);
 
817
        line.draw(&p, position);
 
818
 
 
819
        // Add a fade out rect to the list if the line is too long
 
820
        if (line.naturalTextWidth() > rect.width())
 
821
        {
 
822
            int x = int(qMin(line.naturalTextWidth(), (qreal)pixmap.width())) - fadeWidth;
 
823
            int y = int(line.position().y() + position.y());
 
824
            QRect r = QStyle::visualRect(layout.textOption().textDirection(), pixmap.rect(),
 
825
                                         QRect(x, y, fadeWidth, int(line.height())));
 
826
            fadeRects.append(r);
 
827
        }
 
828
    }
 
829
 
 
830
    // Reduce the alpha in each fade out rect using the alpha gradient
 
831
    if (!fadeRects.isEmpty())
 
832
    {
 
833
        p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
 
834
        foreach (const QRect &rect, fadeRects) {
 
835
            p.fillRect(rect, alphaGradient);
 
836
        }
 
837
    }
 
838
 
 
839
    p.end();
 
840
 
 
841
 
 
842
    QColor shadowColor;
 
843
    if (qGray(textColor().rgb()) > 192) {
 
844
        shadowColor = Qt::black;
 
845
    } else {
 
846
        shadowColor = Qt::white;
 
847
    }
 
848
 
 
849
    if (m_cachedShadow.isNull()) {
 
850
        QImage shadow = pixmap.toImage();
 
851
        Plasma::PaintUtils::shadowBlur(shadow, 2, shadowColor);
 
852
        m_cachedShadow = QPixmap(shadow.size());
 
853
        m_cachedShadow.fill(Qt::transparent);
 
854
        QPainter buffPainter(&m_cachedShadow);
 
855
        buffPainter.drawImage(QPoint(0,0), shadow);
 
856
    }
 
857
 
 
858
    if (shadowColor == Qt::white) {
 
859
        painter->drawPixmap(rect.topLeft(), m_cachedShadow);
 
860
    } else {
 
861
        painter->drawPixmap(rect.topLeft() + QPoint(1,2), m_cachedShadow);
 
862
    }
 
863
    painter->drawPixmap(rect.topLeft(), pixmap);
 
864
}
 
865
 
 
866
 
 
867
qreal AbstractTaskItem::backgroundFadeAlpha() const
 
868
{
 
869
    return m_alpha;
 
870
}
 
871
 
 
872
void AbstractTaskItem::setBackgroundFadeAlpha(qreal progress)
 
873
{
 
874
    m_alpha = progress;
 
875
    update();
 
876
}
 
877
 
 
878
bool AbstractTaskItem::shouldIgnoreDragEvent(QGraphicsSceneDragDropEvent *event)
 
879
{
 
880
   if (event->mimeData()->hasFormat(TaskManager::Task::mimetype()) ||
 
881
       event->mimeData()->hasFormat(TaskManager::Task::groupMimetype())) {
 
882
        return true;
 
883
    }
 
884
 
 
885
    if (event->mimeData()->hasFormat("text/uri-list")) {
 
886
        // we want to check if we have executables; if so, then we treat it as a possible
 
887
        // drop for a launcher
 
888
        const KUrl::List uris = KUrl::List::fromMimeData(event->mimeData());
 
889
        if (!uris.isEmpty()) {
 
890
            foreach (const QUrl &uri, uris) {
 
891
                KUrl url(uri);
 
892
                if (url.isLocalFile()) {
 
893
                    const QString path = url.toLocalFile();
 
894
                    QFileInfo info(path);
 
895
                    if (info.isDir() || !info.isExecutable()) {
 
896
                        return false;
 
897
                        break;
 
898
                    }
 
899
                }
 
900
            }
 
901
 
 
902
            return true;
 
903
        }
 
904
    }
 
905
 
 
906
    return false;
 
907
}
 
908
 
 
909
void AbstractTaskItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
 
910
{
 
911
    if (shouldIgnoreDragEvent(event)) {
 
912
        event->ignore();
 
913
        return;
 
914
    }
 
915
 
 
916
    event->accept();
 
917
 
 
918
    if (!m_activateTimerId) {
 
919
        m_activateTimerId = startTimer(500);
 
920
    }
 
921
}
 
922
 
 
923
void AbstractTaskItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
 
924
{
 
925
    Q_UNUSED(event);
 
926
 
 
927
    // restart the timer so that activate() is only called after the mouse
 
928
    // stops moving
 
929
    if (m_activateTimerId) {
 
930
        killTimer(m_activateTimerId);
 
931
        m_activateTimerId = startTimer(500);
 
932
    }
 
933
}
 
934
 
 
935
void AbstractTaskItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
 
936
{
 
937
    Q_UNUSED(event);
 
938
 
 
939
    if (m_activateTimerId) {
 
940
        killTimer(m_activateTimerId);
 
941
        m_activateTimerId = 0;
 
942
    }
 
943
}
 
944
 
 
945
QRect AbstractTaskItem::iconGeometry() const
 
946
{
 
947
    if (!scene() || !boundingRect().isValid()) {
 
948
        return QRect();
 
949
    }
 
950
 
 
951
    QGraphicsView *parentView = 0;
 
952
    QGraphicsView *possibleParentView = 0;
 
953
    // The following was taken from Plasma::Applet, it doesn't make sense to make the item an applet, and this was the easiest way around it.
 
954
    foreach (QGraphicsView *view, scene()->views()) {
 
955
        if (view->sceneRect().intersects(sceneBoundingRect()) ||
 
956
            view->sceneRect().contains(scenePos())) {
 
957
            if (view->isActiveWindow()) {
 
958
                parentView = view;
 
959
                break;
 
960
            } else {
 
961
                possibleParentView = view;
 
962
            }
 
963
        }
 
964
    }
 
965
 
 
966
    if (!parentView) {
 
967
        parentView = possibleParentView;
 
968
 
 
969
        if (!parentView) {
 
970
            return QRect();
 
971
        }
 
972
    }
 
973
 
 
974
    QRect rect = parentView->mapFromScene(mapToScene(boundingRect())).boundingRect().adjusted(0, 0, 1, 1);
 
975
    rect.moveTopLeft(parentView->mapToGlobal(rect.topLeft()));
 
976
    return rect;
 
977
}
 
978
 
 
979
void AbstractTaskItem::publishIconGeometry() const
 
980
{
 
981
}
 
982
 
 
983
void AbstractTaskItem::publishIconGeometry(const QRect &rect) const
 
984
{
 
985
    Q_UNUSED(rect)
 
986
}
 
987
 
 
988
void AbstractTaskItem::setAnimationPos(const QPointF &pos)
 
989
{
 
990
    m_layoutAnimationLock = true;
 
991
    setPos(pos);
 
992
    m_layoutAnimationLock = false;
 
993
}
 
994
 
 
995
QPointF AbstractTaskItem::animationPos() const
 
996
{
 
997
    return pos();
 
998
}
 
999
 
 
1000
void AbstractTaskItem::setGeometry(const QRectF& geometry)
 
1001
{
 
1002
    if (geometry == QGraphicsWidget::geometry()) {
 
1003
        return;
 
1004
    }
 
1005
 
 
1006
    QPointF oldPos = pos();
 
1007
 
 
1008
    if (m_lastGeometryUpdate.elapsed() < 500) {
 
1009
        if (m_updateGeometryTimerId) {
 
1010
            killTimer(m_updateGeometryTimerId);
 
1011
            m_updateGeometryTimerId = 0;
 
1012
        }
 
1013
 
 
1014
        m_updateGeometryTimerId = startTimer(500 - m_lastGeometryUpdate.elapsed());
 
1015
    } else {
 
1016
        publishIconGeometry();
 
1017
        m_lastGeometryUpdate.restart();
 
1018
    }
 
1019
 
 
1020
    //TODO:remove when we will have proper animated layouts
 
1021
    if (m_firstGeometryUpdate && !m_layoutAnimationLock) {
 
1022
        QRectF animStartGeom(oldPos, geometry.size());
 
1023
        QGraphicsWidget::setGeometry(animStartGeom);
 
1024
 
 
1025
        if (m_layoutAnimation->state() == QAbstractAnimation::Running) {
 
1026
            m_layoutAnimation->stop();
 
1027
        }
 
1028
 
 
1029
        m_layoutAnimation->setEndValue(geometry.topLeft());
 
1030
        m_layoutAnimation->start();
 
1031
    } else {
 
1032
        QGraphicsWidget::setGeometry(geometry);
 
1033
    }
 
1034
}
 
1035
 
 
1036
QRectF AbstractTaskItem::iconRect(const QRectF &b)
 
1037
{
 
1038
    QRectF bounds(b);
 
1039
    const int right = bounds.right();
 
1040
 
 
1041
    if (m_showText) {
 
1042
        //leave enough space for the text. useful in vertical panel
 
1043
        bounds.setWidth(qMax(bounds.width() / 3, qMin(minimumSize().height(), bounds.width())));
 
1044
    }
 
1045
 
 
1046
    //restore right position if the layout is RTL
 
1047
    if (QApplication::layoutDirection() == Qt::RightToLeft) {
 
1048
        bounds.moveRight(right);
 
1049
    }
 
1050
 
 
1051
    QSize iconSize = icon().actualSize(bounds.size().toSize());
 
1052
 
 
1053
    if (iconSize.width() == iconSize.height()) {
 
1054
        if (iconSize.width() > KIconLoader::SizeSmall && iconSize.width() < KIconLoader::SizeSmallMedium) {
 
1055
            iconSize = QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
 
1056
        } else if (iconSize.width() > KIconLoader::SizeSmallMedium && iconSize.width() < KIconLoader::SizeMedium) {
 
1057
            iconSize = QSize(KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium);
 
1058
        } else if (iconSize.width() > KIconLoader::SizeMedium && iconSize.width() < KIconLoader::SizeLarge) {
 
1059
            iconSize = QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium);
 
1060
        }
 
1061
    }
 
1062
 
 
1063
    if (iconSize != m_lastIconSize) {
 
1064
        m_cachedShadow = QPixmap();
 
1065
    }
 
1066
    m_lastIconSize = iconSize;
 
1067
    return QStyle::alignedRect(QApplication::layoutDirection(),
 
1068
                               (m_showText ? Qt::AlignLeft : Qt::AlignCenter) | Qt::AlignVCenter,
 
1069
                               iconSize, bounds.toRect());
 
1070
}
 
1071
 
 
1072
QRectF AbstractTaskItem::expanderRect(const QRectF &bounds)
 
1073
{
 
1074
    const TaskGroupItem *groupItem = qobject_cast<const TaskGroupItem *>(this);
 
1075
    if (!groupItem) {
 
1076
        return QRectF();
 
1077
    }
 
1078
 
 
1079
    QFontMetrics fm(KGlobalSettings::smallestReadableFont());
 
1080
    Plasma::FrameSvg *itemBackground = m_applet->itemBackground();
 
1081
 
 
1082
    QSize expanderSize(qMax(fm.width(QString::number(groupItem->count())),
 
1083
                       itemBackground->elementSize(expanderElement()).width()),
 
1084
                       size().height());
 
1085
 
 
1086
    return QStyle::alignedRect(QApplication::layoutDirection(), Qt::AlignRight | Qt::AlignVCenter,
 
1087
                               expanderSize, bounds.toRect());
 
1088
}
 
1089
 
 
1090
QRectF AbstractTaskItem::textRect(const QRectF &bounds)
 
1091
{
 
1092
    QSize size(bounds.size().toSize());
 
1093
    QRectF effectiveBounds(bounds);
 
1094
 
 
1095
    size.rwidth() -= int(iconRect(bounds).width()) + qMax(0, IconTextSpacing - 2);
 
1096
    if (!isWindowItem()) {
 
1097
        size.rwidth() -= int(expanderRect(bounds).width()) + qMax(0, IconTextSpacing - 2);
 
1098
 
 
1099
        if (QApplication::layoutDirection() == Qt::RightToLeft) {
 
1100
            effectiveBounds.setLeft(expanderRect(bounds).right());
 
1101
        } else {
 
1102
            effectiveBounds.setRight(expanderRect(bounds).left());
 
1103
        }
 
1104
    }
 
1105
 
 
1106
    return QStyle::alignedRect(QApplication::layoutDirection(), Qt::AlignRight | Qt::AlignVCenter,
 
1107
                                     size, effectiveBounds.toRect());
 
1108
}
 
1109
 
 
1110
QColor AbstractTaskItem::textColor() const
 
1111
{
 
1112
    QColor color;
 
1113
    qreal bias;
 
1114
    Plasma::Theme *theme = Plasma::Theme::defaultTheme();
 
1115
 
 
1116
    if ((m_oldBackgroundPrefix == "attention" || m_backgroundPrefix == "attention") &&
 
1117
         m_applet->itemBackground()->hasElement("hint-attention-button-color")) {
 
1118
        bool animatingBg = m_backgroundFadeAnim && m_backgroundFadeAnim->state() == QAbstractAnimation::Running;
 
1119
        if (animatingBg) {
 
1120
            if (m_oldBackgroundPrefix == "attention") {
 
1121
                bias = 1 - m_alpha;
 
1122
            } else {
 
1123
                bias = m_alpha;
 
1124
            }
 
1125
 
 
1126
            color = KColorUtils::mix(theme->color(Plasma::Theme::TextColor),
 
1127
                                     theme->color(Plasma::Theme::ButtonTextColor), bias);
 
1128
        } else if (m_backgroundPrefix != "attention") {
 
1129
                color = theme->color(Plasma::Theme::TextColor);
 
1130
        } else {
 
1131
            color = theme->color(Plasma::Theme::ButtonTextColor);
 
1132
        }
 
1133
    } else {
 
1134
        color = theme->color(Plasma::Theme::TextColor);
 
1135
    }
 
1136
 
 
1137
    if (m_flags & TaskIsMinimized) {
 
1138
        color.setAlphaF(0.85);
 
1139
    }
 
1140
 
 
1141
    return color;
 
1142
}
 
1143
 
 
1144
QString AbstractTaskItem::expanderElement() const
 
1145
{
 
1146
    switch (m_applet->location()) {
 
1147
    case Plasma::TopEdge:
 
1148
        return "group-expander-top";
 
1149
    case Plasma::RightEdge:
 
1150
        return "group-expander-right";
 
1151
    case Plasma::LeftEdge:
 
1152
        return "group-expander-left";
 
1153
    case Plasma::BottomEdge:
 
1154
    default:
 
1155
        return "group-expander-bottom";
 
1156
    }
 
1157
}
 
1158
 
 
1159
 
 
1160
bool AbstractTaskItem::isGroupMember(const TaskGroupItem *group) const
 
1161
{
 
1162
    if (!m_abstractItem || !group) {
 
1163
        kDebug() <<"no task";
 
1164
        return false;
 
1165
    }
 
1166
 
 
1167
    return m_abstractItem->isGroupMember(group->group());
 
1168
 
 
1169
}
 
1170
 
 
1171
bool AbstractTaskItem::isGrouped() const
 
1172
{
 
1173
    if (!m_abstractItem) {
 
1174
        kDebug() <<"no item";
 
1175
        return false;
 
1176
    }
 
1177
 
 
1178
    return m_abstractItem->isGrouped();
 
1179
}
 
1180
 
 
1181
TaskGroupItem * AbstractTaskItem::parentGroup() const
 
1182
{
 
1183
    TaskGroupItem *group = qobject_cast<TaskGroupItem*>(parentWidget());
 
1184
 
 
1185
    //lucky case: directly in a group
 
1186
    if (group) {
 
1187
        return group;
 
1188
    }
 
1189
 
 
1190
    //in a popup or a popup's popup?
 
1191
    QObject *candidate = parentWidget();
 
1192
 
 
1193
    while (candidate) {
 
1194
        group = qobject_cast<TaskGroupItem*>(candidate);
 
1195
        candidate = candidate->parent();
 
1196
        if (group) {
 
1197
            return group;
 
1198
        }
 
1199
    }
 
1200
 
 
1201
    return 0;
 
1202
}
 
1203
 
 
1204
TaskManager::AbstractGroupableItem * AbstractTaskItem::abstractItem()
 
1205
{
 
1206
    return m_abstractItem;
 
1207
}
 
1208
 
 
1209
#include "abstracttaskitem.moc"