mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 10:52:53 +00:00

makes no sense to support interface ment for other desktop environment when the applet is ment for use with plasma session Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
1597 lines
47 KiB
C++
1597 lines
47 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2007 by Robert Knight <robertknight@gmail.com> *
|
|
* Copyright (C) 2008 by Alexis Ménard <darktears31@gmail.com> *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
|
***************************************************************************/
|
|
|
|
// Own
|
|
#include "taskgroupitem.h"
|
|
#include "jobmanager.h"
|
|
#include "mediabuttons.h"
|
|
|
|
// Qt
|
|
#include <QtGui/qgraphicssceneevent.h>
|
|
#include <QtGui/qstyleoption.h>
|
|
#include <QGraphicsView>
|
|
#include <QApplication>
|
|
#include <QGraphicsLinearLayout>
|
|
#include <QInputDialog>
|
|
|
|
// KDE
|
|
#include <KDebug>
|
|
#include <KDesktopFile>
|
|
|
|
#include "taskmanager/taskactions.h"
|
|
#include "taskmanager/taskmanager.h"
|
|
#include "taskmanager/taskgroup.h"
|
|
#include "taskmanager/abstractgroupingstrategy.h"
|
|
#include "taskmanager/taskitem.h"
|
|
|
|
#include <Plasma/Theme>
|
|
#include <Plasma/FrameSvg>
|
|
#include "tooltips/tooltipmanager.h"
|
|
#include <Plasma/Corona>
|
|
#include <Plasma/Containment>
|
|
#include <Plasma/Dialog>
|
|
#include <Plasma/WindowEffects>
|
|
|
|
#include "tasks.h"
|
|
#include "taskitemlayout.h"
|
|
#include "windowtaskitem.h"
|
|
#include "applauncheritem.h"
|
|
|
|
class DropIndicator : public QGraphicsWidget
|
|
{
|
|
public:
|
|
|
|
DropIndicator(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0)
|
|
: QGraphicsWidget(parent, wFlags)
|
|
, m_size(16)
|
|
, m_orientation(Qt::Horizontal) {
|
|
m_svg = new Plasma::Svg();
|
|
m_svg->setImagePath("icontasks/dropindicators");
|
|
m_svg->setContainsMultipleImages(true);
|
|
m_svg->resize(m_size, m_size);
|
|
setOrientation(Qt::Horizontal);
|
|
|
|
m_animation = new QPropertyAnimation(this, "pos", this);
|
|
m_animation->setEasingCurve(QEasingCurve::InOutQuad);
|
|
m_animation->setDuration(50);
|
|
}
|
|
|
|
~DropIndicator() {
|
|
}
|
|
|
|
void setOrientation(Qt::Orientation orientation) {
|
|
m_orientation = orientation;
|
|
}
|
|
|
|
Qt::Orientation orientation() {
|
|
return m_orientation;
|
|
}
|
|
|
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
|
|
Q_UNUSED(option);
|
|
Q_UNUSED(widget);
|
|
|
|
m_svg->paint(painter, rect().topLeft(), Qt::Horizontal == m_orientation ? "horizontal-dropindicator" : "vertical-dropindicator");
|
|
}
|
|
|
|
void setSize(int size) {
|
|
int sz = size;
|
|
if (sz < 16) {
|
|
sz = 16;
|
|
} else if (sz > 32) {
|
|
sz = 32;
|
|
} else {
|
|
sz = (sz / 4) * 4;
|
|
}
|
|
|
|
if (m_size != sz) {
|
|
m_size = sz;
|
|
m_svg->resize(m_size, m_size);
|
|
}
|
|
}
|
|
|
|
void setPosition(const QRectF &r) {
|
|
QPointF newPos = Qt::Horizontal == m_orientation
|
|
? QPointF(r.x() - (m_size / 2.0), r.y() + (r.height() - m_size) / 2.0)
|
|
: QPointF(r.x() + (r.width() - m_size) / 2.0, r.y() - (m_size / 2.0));
|
|
|
|
if (isVisible()) {
|
|
if (m_animation->state() == QAbstractAnimation::Running) {
|
|
m_animation->stop();
|
|
}
|
|
|
|
m_animation->setEndValue(newPos);
|
|
m_animation->start();
|
|
} else {
|
|
setVisible(true);
|
|
setPos(newPos);
|
|
}
|
|
}
|
|
|
|
private:
|
|
int m_size;
|
|
Plasma::Svg *m_svg;
|
|
Qt::Orientation m_orientation;
|
|
QPropertyAnimation *m_animation;
|
|
};
|
|
|
|
|
|
TaskGroupItem::TaskGroupItem(QGraphicsWidget *parent, Tasks *applet)
|
|
: AbstractTaskItem(parent, applet),
|
|
m_tasksLayout(0),
|
|
m_popupMenuTimer(0),
|
|
m_lastActivated(-1),
|
|
m_activeTaskIndex(0),
|
|
m_maximumRows(1),
|
|
m_offscreenWidget(0),
|
|
m_offscreenLayout(0),
|
|
m_collapsed(true),
|
|
m_mainLayout(0),
|
|
m_popupDialog(0),
|
|
m_updateTimer(0),
|
|
m_changes(TaskManager::TaskUnchanged),
|
|
m_dropIndicator(0)
|
|
{
|
|
setAcceptDrops(true);
|
|
setFlag(ItemClipsChildrenToShape, true);
|
|
}
|
|
|
|
|
|
TaskGroupItem::~TaskGroupItem()
|
|
{
|
|
if (!m_offscreenLayout && !m_mainLayout) {
|
|
// only delete this if we have neither an offscreen layout or a mainlayout
|
|
// if we do, then they will delete the layout for us.
|
|
delete m_tasksLayout;
|
|
}
|
|
close(false);
|
|
}
|
|
|
|
void TaskGroupItem::activate()
|
|
{
|
|
}
|
|
|
|
void TaskGroupItem::activateOrIconify()
|
|
{
|
|
bool includesActive = false;
|
|
TaskManager::ItemList items(m_group.data()->members());
|
|
int iconified = 0;
|
|
foreach (AbstractGroupableItem * item, items) {
|
|
TaskManager::TaskItem *task = qobject_cast<TaskManager::TaskItem *>(item);
|
|
if (task) {
|
|
if (task->task()->isMinimized()) {
|
|
++ iconified;
|
|
}
|
|
|
|
if (task->task()->isActive()) {
|
|
includesActive = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (includesActive && items.size() - iconified > iconified) {
|
|
// iconify
|
|
foreach (TaskManager::AbstractGroupableItem * item, items) {
|
|
TaskManager::TaskItem *task = qobject_cast<TaskManager::TaskItem*>(item);
|
|
if (task) {
|
|
task->task()->setIconified(true);
|
|
}
|
|
}
|
|
} else {
|
|
// activate
|
|
QList<WId> winOrder(KWindowSystem::stackingOrder());
|
|
const int winCount = winOrder.size();
|
|
TaskManager::TaskItem* sortedItems[winCount];
|
|
|
|
memset(sortedItems, 0, sizeof(TaskManager::TaskItem*) * winCount);
|
|
|
|
foreach (TaskManager::AbstractGroupableItem * item, items) {
|
|
TaskManager::TaskItem *task = qobject_cast<TaskManager::TaskItem*>(item);
|
|
if (task) {
|
|
int index = winOrder.indexOf(task->task()->window());
|
|
if (index != -1) {
|
|
sortedItems[index] = task;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int index = 0; index < winCount; ++ index) {
|
|
TaskManager::TaskItem* task = sortedItems[index];
|
|
if (task) {
|
|
task->task()->activate();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::close()
|
|
{
|
|
close(true);
|
|
}
|
|
|
|
void TaskGroupItem::close(bool hide)
|
|
{
|
|
//kDebug();
|
|
//close the popup if the group is removed
|
|
if (m_popupDialog) {
|
|
m_popupDialog->hide();
|
|
disconnect(m_popupDialog, 0, 0, 0);
|
|
m_popupDialog->deleteLater();
|
|
m_popupDialog = 0;
|
|
}
|
|
|
|
if (m_group) {
|
|
disconnect(m_group.data(), 0, this, 0);
|
|
}
|
|
|
|
if (m_updateTimer) {
|
|
m_updateTimer->stop();
|
|
}
|
|
|
|
if (!isRootGroup()) {
|
|
unregisterFromHelpers();
|
|
if (hide) {
|
|
setVisible(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool TaskGroupItem::isRootGroup() const
|
|
{
|
|
return m_applet == parentWidget();
|
|
}
|
|
|
|
void TaskGroupItem::updateTask(::TaskManager::TaskChanges changes)
|
|
{
|
|
if (!m_group || isRootGroup()) {
|
|
return;
|
|
}
|
|
|
|
m_changes |= changes;
|
|
|
|
if (!m_updateTimer) {
|
|
m_updateTimer = new QTimer(this);
|
|
m_updateTimer->setInterval(10);
|
|
m_updateTimer->setSingleShot(true);
|
|
connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(checkUpdates()));
|
|
}
|
|
|
|
m_updateTimer->start();
|
|
}
|
|
|
|
void TaskGroupItem::checkUpdates()
|
|
{
|
|
if (!m_group) {
|
|
return;
|
|
}
|
|
|
|
bool needsUpdate = false;
|
|
TaskFlags flags = m_flags;
|
|
|
|
if (m_changes & TaskManager::StateChanged) {
|
|
if (m_group.data()->isActive()) {
|
|
flags |= TaskHasFocus;
|
|
if (!(m_flags & TaskHasFocus)) {
|
|
emit activated(this);
|
|
}
|
|
} else {
|
|
flags &= ~TaskHasFocus;
|
|
}
|
|
|
|
if (m_group.data()->isMinimized()) {
|
|
flags |= TaskIsMinimized;
|
|
} else {
|
|
flags &= ~TaskIsMinimized;
|
|
}
|
|
}
|
|
|
|
if (m_changes & TaskManager::AttentionChanged) {
|
|
if (m_group.data()->demandsAttention()) {
|
|
flags |= TaskWantsAttention;
|
|
} else {
|
|
flags &= ~TaskWantsAttention;
|
|
}
|
|
}
|
|
|
|
if (flags != m_flags) {
|
|
needsUpdate = true;
|
|
setTaskFlags(flags);
|
|
}
|
|
|
|
// basic title and icon
|
|
if (m_changes & TaskManager::IconChanged) {
|
|
needsUpdate = true;
|
|
}
|
|
|
|
if (m_changes & TaskManager::NameChanged) {
|
|
needsUpdate = true;
|
|
}
|
|
|
|
if (IconTasks::ToolTipManager::self()->isVisible(this) &&
|
|
(m_changes & TaskManager::IconChanged ||
|
|
m_changes & TaskManager::NameChanged ||
|
|
m_changes & TaskManager::DesktopChanged)) {
|
|
updateToolTip();
|
|
}
|
|
|
|
m_changes = TaskManager::TaskUnchanged;
|
|
if (needsUpdate) {
|
|
//redraw
|
|
queueUpdate();
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::updateToolTip()
|
|
{
|
|
if (!m_group) {
|
|
return;
|
|
}
|
|
|
|
QWidget *dialog = m_applet->popupDialog();
|
|
|
|
if (dialog && dialog->isVisible()) {
|
|
clearToolTip();
|
|
return;
|
|
}
|
|
|
|
IconTasks::ToolTipContent data;
|
|
|
|
data.setClickable(true);
|
|
data.setInstantPopup(m_applet->instantToolTip());
|
|
data.setHighlightWindows(m_applet->highlightWindows());
|
|
data.setVertical(Plasma::Vertical == m_applet->formFactor());
|
|
|
|
QMap<int, IconTasks::ToolTipContent::Window> map;
|
|
|
|
if (m_applet->launcherIcons() && m_icon.isNull()) {
|
|
KUrl launcherUrl(m_abstractItem->launcherUrl());
|
|
if (launcherUrl.isLocalFile() && KDesktopFile::isDesktopFile(launcherUrl.toLocalFile())) {
|
|
KDesktopFile f(launcherUrl.toLocalFile());
|
|
if (f.tryExec()) {
|
|
m_icon = KIcon(f.readIcon());
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (AbstractGroupableItem * item, m_group.data()->members()) {
|
|
TaskManager::TaskItem *taskItem = qobject_cast<TaskManager::TaskItem *>(item);
|
|
if (taskItem && taskItem->task()) {
|
|
if (m_icon.isNull()) {
|
|
m_icon = item->icon();
|
|
}
|
|
map.insertMulti(taskItem->id(),
|
|
IconTasks::ToolTipContent::Window(taskItem->task()->window(),
|
|
item->name(),
|
|
m_icon.pixmap(IconTasks::ToolTipContent::iconSize(), IconTasks::ToolTipContent::iconSize()),
|
|
taskItem->task()->demandsAttention(),
|
|
!m_applet->groupManager().showOnlyCurrentDesktop() || !taskItem->isOnCurrentDesktop()
|
|
? taskItem->task()->desktop() : 0));
|
|
}
|
|
}
|
|
|
|
data.setWindowDetailsToPreview(map.values());
|
|
|
|
QString key = mediaButtonKey();
|
|
if (!key.isEmpty()) {
|
|
data.setPlayState(MediaButtons::self()->playbackStatus(key));
|
|
}
|
|
|
|
IconTasks::ToolTipManager::self()->setContent(this, data);
|
|
}
|
|
|
|
void TaskGroupItem::reload()
|
|
{
|
|
if (!group()) {
|
|
return;
|
|
}
|
|
|
|
QHash<AbstractGroupableItem *, AbstractTaskItem*> itemsToRemove = m_groupMembers;
|
|
foreach (AbstractGroupableItem * item, group()->members()) {
|
|
if (!item) {
|
|
kDebug() << "invalid Item";
|
|
continue;
|
|
}
|
|
|
|
if (itemsToRemove.contains(item)) {
|
|
itemsToRemove.insert(item, 0);
|
|
}
|
|
itemAdded(item);
|
|
|
|
if (item->itemType() == TaskManager::GroupItemType) {
|
|
TaskGroupItem *group = qobject_cast<TaskGroupItem *>(abstractTaskItem(item));
|
|
if (group) {
|
|
group->reload();
|
|
}
|
|
}
|
|
}
|
|
|
|
QHashIterator<AbstractGroupableItem *, AbstractTaskItem*> it(itemsToRemove);
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
if (it.key() && it.value()) {
|
|
itemRemoved(it.key());
|
|
}
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::setGroup(TaskManager::GroupPtr group)
|
|
{
|
|
//kDebug();
|
|
if (m_group.data() == group) {
|
|
kDebug() << "already have this group!";
|
|
return;
|
|
}
|
|
|
|
if (m_group) {
|
|
disconnect(m_group.data(), 0, this, 0);
|
|
}
|
|
|
|
m_group = group;
|
|
m_abstractItem = group;
|
|
|
|
if (m_group) {
|
|
connect(m_abstractItem, SIGNAL(destroyed(QObject*)), this, SLOT(clearAbstractItem()));
|
|
connect(group, SIGNAL(destroyed(QObject*)), this, SLOT(clearGroup()));
|
|
connect(group, SIGNAL(itemRemoved(AbstractGroupableItem*)), this, SLOT(itemRemoved(AbstractGroupableItem*)));
|
|
connect(group, SIGNAL(itemAdded(AbstractGroupableItem*)), this, SLOT(itemAdded(AbstractGroupableItem*)));
|
|
|
|
//connect(group, SIGNAL(destroyed()), this, SLOT(close()));
|
|
|
|
connect(group, SIGNAL(changed(::TaskManager::TaskChanges)), this, SLOT(updateTask(::TaskManager::TaskChanges)));
|
|
|
|
connect(group, SIGNAL(itemPositionChanged(AbstractGroupableItem*)), this, SLOT(itemPositionChanged(AbstractGroupableItem*)));
|
|
}
|
|
|
|
//Add already existing items
|
|
reload();
|
|
updateTask(::TaskManager::EverythingChanged);
|
|
if (!isRootGroup()) {
|
|
registerWithHelpers();
|
|
}
|
|
//kDebug() << "Task added, isActive = " << task->isActive();
|
|
}
|
|
|
|
TaskManager::GroupPtr TaskGroupItem::group() const
|
|
{
|
|
return m_group.data();
|
|
}
|
|
|
|
void TaskGroupItem::clearGroup()
|
|
{
|
|
//now it's useless
|
|
}
|
|
|
|
void TaskGroupItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *e)
|
|
{
|
|
//kDebug();
|
|
if (!m_group) {
|
|
QGraphicsWidget::contextMenuEvent(e);
|
|
return;
|
|
}
|
|
|
|
Q_ASSERT(m_applet);
|
|
//we are the master group item
|
|
if (isRootGroup()) {
|
|
e->ignore();
|
|
return;
|
|
}
|
|
|
|
QList <QAction*> actionList;
|
|
|
|
QAction *a = m_applet->action("configure");
|
|
if (a && a->isEnabled()) {
|
|
actionList.append(a);
|
|
}
|
|
|
|
TaskManager::BasicMenu menu(qobject_cast<QWidget*>(this), m_group.data(), &m_applet->groupManager(), actionList, getAppMenu());
|
|
|
|
menu.adjustSize();
|
|
|
|
if (m_applet->formFactor() != Plasma::Vertical) {
|
|
menu.setMinimumWidth(size().width());
|
|
}
|
|
|
|
Q_ASSERT(m_applet->containment());
|
|
Q_ASSERT(m_applet->containment()->corona());
|
|
stopWindowHoverEffect();
|
|
menu.exec(m_applet->containment()->corona()->popupPosition(this, menu.size()));
|
|
}
|
|
|
|
QHash<AbstractGroupableItem *, AbstractTaskItem*> TaskGroupItem::members() const
|
|
{
|
|
return m_groupMembers;
|
|
}
|
|
|
|
int TaskGroupItem::count() const
|
|
{
|
|
return m_groupMembers.count();
|
|
}
|
|
|
|
AbstractTaskItem *TaskGroupItem::createAbstractItem(TaskManager::AbstractGroupableItem *groupableItem)
|
|
{
|
|
//kDebug() << "item to create" << groupableItem;
|
|
AbstractTaskItem *item = 0;
|
|
|
|
if (groupableItem->itemType() == TaskManager::GroupItemType) {
|
|
TaskGroupItem *groupItem = new TaskGroupItem(this, m_applet);
|
|
groupItem->setGroup(static_cast<TaskManager::TaskGroup*>(groupableItem));
|
|
item = groupItem;
|
|
} else if (groupableItem->itemType() == TaskManager::LauncherItemType) {
|
|
AppLauncherItem *launcherItem = new AppLauncherItem(this, m_applet, static_cast<TaskManager::LauncherItem*>(groupableItem));
|
|
item = launcherItem;
|
|
} else {
|
|
TaskManager::TaskItem * taskItem = static_cast<TaskManager::TaskItem*>(groupableItem);
|
|
//if the taskItem is not either a startup o a task, return 0;
|
|
if (!taskItem->startup() && !taskItem->task()) {
|
|
return item;
|
|
}
|
|
|
|
WindowTaskItem *windowItem = new WindowTaskItem(this, m_applet);
|
|
windowItem->setTask(taskItem);
|
|
item = windowItem;
|
|
}
|
|
|
|
if (m_collapsed) {
|
|
item->setPreferredOffscreenSize();
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
void TaskGroupItem::itemAdded(TaskManager::AbstractGroupableItem * groupableItem)
|
|
{
|
|
//kDebug();
|
|
if (!m_applet) {
|
|
kDebug() << "No applet";
|
|
return;
|
|
}
|
|
|
|
//returns the corresponding item or creates a new one
|
|
AbstractTaskItem *item = m_groupMembers.value(groupableItem);
|
|
|
|
if (!item) {
|
|
item = createAbstractItem(groupableItem);
|
|
|
|
if (item) {
|
|
connect(item, SIGNAL(activated(AbstractTaskItem*)),
|
|
this, SLOT(updateActive(AbstractTaskItem*)));
|
|
|
|
TaskGroupItem *group = qobject_cast<TaskGroupItem*>(item);
|
|
if (group) {
|
|
connect(item, SIGNAL(changed()), this, SLOT(relayoutItems()));
|
|
}
|
|
|
|
if (!isRootGroup()) {
|
|
item->setVisible(false);
|
|
}
|
|
} else {
|
|
kDebug() << "invalid Item";
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_groupMembers[groupableItem] = item;
|
|
item->setParentItem(this);
|
|
|
|
if (m_tasksLayout) { //add to layout either for popup or expanded group
|
|
m_tasksLayout->addTaskItem(item);
|
|
} else { //collapsed and no layout so far
|
|
item->hide();
|
|
QRect rect = iconGeometry();
|
|
item->publishIconGeometry(rect);
|
|
}
|
|
|
|
if (item->isActive()) {
|
|
//kDebug() << "item is Active" ;
|
|
m_activeTaskIndex = indexOf(item);
|
|
} else if (!m_group || m_group.data()->members().size() == 1) {
|
|
m_activeTaskIndex = 0;
|
|
}
|
|
|
|
if (collapsed()) {
|
|
update();
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::itemRemoved(TaskManager::AbstractGroupableItem * groupableItem)
|
|
{
|
|
//kDebug();
|
|
if (!m_applet) {
|
|
kDebug() << "No Applet";
|
|
return;
|
|
}
|
|
|
|
AbstractTaskItem *item = m_groupMembers.take(groupableItem);
|
|
|
|
if (!item) {
|
|
kDebug() << "Item not found";
|
|
return;
|
|
}
|
|
//kDebug() << item->text();
|
|
|
|
disconnect(item, 0, 0, 0);
|
|
|
|
if (m_tasksLayout) {
|
|
m_tasksLayout->removeTaskItem(item);
|
|
|
|
if (m_offscreenWidget) {
|
|
m_offscreenWidget->adjustSize();
|
|
}
|
|
|
|
if (m_popupDialog && m_popupDialog->isVisible() &&
|
|
m_applet->containment() && m_applet->containment()->corona()) {
|
|
m_popupDialog->move(m_applet->containment()->corona()->popupPosition(this, m_popupDialog->size(), Qt::AlignCenter));
|
|
}
|
|
}
|
|
|
|
item->close();
|
|
//item->deleteLater();
|
|
QTimer::singleShot(0, item, SLOT(deleteLater()));
|
|
}
|
|
|
|
bool TaskGroupItem::isWindowItem() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool TaskGroupItem::isActive() const
|
|
{
|
|
//kDebug() << "Not Implemented";
|
|
return false;
|
|
}
|
|
|
|
bool TaskGroupItem::windowPreviewOpen() const
|
|
{
|
|
if (KWindowSystem::compositingActive() && isRootGroup()) {
|
|
QHashIterator<AbstractGroupableItem *, AbstractTaskItem*> it(m_groupMembers);
|
|
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
AbstractTaskItem *item = it.value();
|
|
if (!qobject_cast<AppLauncherItem *>(item) && item->isToolTipVisible()) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QString TaskGroupItem::appName() const
|
|
{
|
|
if (isRootGroup()) {
|
|
return text();
|
|
}
|
|
|
|
foreach (AbstractTaskItem * member, m_groupMembers) {
|
|
QString n(member->appName());
|
|
|
|
if (!n.isEmpty()) {
|
|
return n;
|
|
}
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
KUrl TaskGroupItem::launcherUrl() const
|
|
{
|
|
if (isRootGroup()) {
|
|
return KUrl();
|
|
}
|
|
|
|
foreach (AbstractTaskItem * member, m_groupMembers) {
|
|
KUrl u(member->launcherUrl());
|
|
|
|
if (u.isValid()) {
|
|
return u;
|
|
}
|
|
}
|
|
|
|
return KUrl();
|
|
}
|
|
|
|
QString TaskGroupItem::windowClass() const
|
|
{
|
|
if (isRootGroup()) {
|
|
return QString();
|
|
}
|
|
|
|
foreach (AbstractTaskItem * member, m_groupMembers) {
|
|
QString c(member->windowClass());
|
|
|
|
if (!c.isEmpty()) {
|
|
return c;
|
|
}
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
void TaskGroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if (!m_group) {
|
|
return;
|
|
}
|
|
|
|
event->accept();
|
|
}
|
|
|
|
void TaskGroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if (m_applet->rootGroupItem() == this || !m_group) {
|
|
return;
|
|
}
|
|
|
|
if (event->button() == Qt::LeftButton) {
|
|
if (Tasks::GC_MinMax != m_applet->groupClick() || event->modifiers() & Qt::ControlModifier) {
|
|
bool usePresentWindows=(event->modifiers()&Qt::ControlModifier || Tasks::GC_PresentWindows == m_applet->groupClick()) &&
|
|
KWindowSystem::compositingActive() && Plasma::WindowEffects::isEffectAvailable(Plasma::WindowEffects::PresentWindowsGroup);
|
|
|
|
if (usePresentWindows) {
|
|
QList<WId> ids;
|
|
foreach (AbstractGroupableItem * groupable, m_group.data()->members()) {
|
|
if (groupable->itemType() == TaskManager::GroupItemType) {
|
|
//TODO: recurse through sub-groups?
|
|
} else {
|
|
TaskItem * item = qobject_cast<TaskItem*>(groupable);
|
|
if (item && item->task()) {
|
|
ids << item->task()->info().win();
|
|
}
|
|
}
|
|
}
|
|
|
|
Plasma::WindowEffects::presentWindows(m_applet->view()->winId(), ids);
|
|
} else {
|
|
if (m_popupMenuTimer) {
|
|
m_popupMenuTimer->stop();
|
|
}
|
|
popupMenu();
|
|
}
|
|
} else {
|
|
activateOrIconify();
|
|
}
|
|
}
|
|
|
|
AbstractTaskItem::mouseReleaseEvent(event);
|
|
}
|
|
|
|
void TaskGroupItem::handleActiveWindowChanged(WId id)
|
|
{
|
|
if (!m_popupDialog) {
|
|
return;
|
|
}
|
|
|
|
if (id == m_popupDialog->winId()) {
|
|
return;
|
|
}
|
|
|
|
m_popupDialog->hide();
|
|
|
|
QRect rect = iconGeometry();
|
|
publishIconGeometry(rect);
|
|
}
|
|
|
|
void TaskGroupItem::popupMenu()
|
|
{
|
|
//kDebug();
|
|
if (!m_collapsed) {
|
|
return;
|
|
}
|
|
|
|
if (!m_offscreenWidget) {
|
|
foreach (AbstractTaskItem * member, m_groupMembers) {
|
|
member->setPreferredOffscreenSize();
|
|
}
|
|
|
|
tasksLayout()->invalidate();
|
|
m_tasksLayout->setOrientation(Plasma::Vertical);
|
|
m_tasksLayout->setMaximumRows(1);
|
|
m_offscreenWidget = new QGraphicsWidget(this);
|
|
m_offscreenLayout = new QGraphicsLinearLayout(m_offscreenWidget);
|
|
m_offscreenLayout->setContentsMargins(0, 0, 0, 0); //default are 4 on each side
|
|
m_offscreenLayout->addItem(tasksLayout());
|
|
m_offscreenWidget->setLayout(m_offscreenLayout);
|
|
m_offscreenWidget->adjustSize();
|
|
m_applet->containment()->corona()->addOffscreenWidget(m_offscreenWidget);
|
|
m_offscreenLayout->activate();
|
|
}
|
|
|
|
if (!m_popupDialog) {
|
|
// Initialize popup dialog
|
|
m_popupDialog = new Plasma::Dialog(0, Qt::Popup);
|
|
KWindowSystem::setType(m_popupDialog->winId(), NET::PopupMenu);
|
|
connect(m_popupDialog, SIGNAL(dialogVisible(bool)), this, SLOT(popupVisibilityChanged(bool)));
|
|
connect(m_popupDialog, SIGNAL(dialogVisible(bool)), m_applet, SLOT(setPopupDialog(bool)));
|
|
connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(handleActiveWindowChanged(WId)));
|
|
KWindowSystem::setState(m_popupDialog->winId(), NET::SkipTaskbar | NET::SkipPager);
|
|
m_popupDialog->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
|
|
|
int left, top, right, bottom;
|
|
m_popupDialog->getContentsMargins(&left, &top, &right, &bottom);
|
|
m_offscreenWidget->setMinimumWidth(size().width() - left - right);
|
|
m_popupDialog->setGraphicsWidget(m_offscreenWidget);
|
|
}
|
|
|
|
if (m_popupDialog->isVisible()) {
|
|
m_popupDialog->clearFocus();
|
|
if (m_applet->location() != Plasma::Floating) {
|
|
m_popupDialog->animatedHide(Plasma::locationToInverseDirection(m_applet->location()));
|
|
} else {
|
|
m_popupDialog->hide();
|
|
}
|
|
} else {
|
|
m_tasksLayout->setOrientation(Plasma::Vertical);
|
|
m_tasksLayout->setMaximumRows(1);
|
|
m_offscreenWidget->layout()->activate();
|
|
|
|
QSizeF sz(m_offscreenWidget->effectiveSizeHint(Qt::PreferredSize));
|
|
foreach (AbstractTaskItem * member, m_groupMembers) {
|
|
member->setPreferredOffscreenSize();
|
|
QSizeF m = member->preferredSize();
|
|
if (m.width() > sz.width()) {
|
|
sz.setWidth(m.width());
|
|
}
|
|
}
|
|
|
|
m_offscreenWidget->resize(sz);
|
|
m_popupDialog->syncToGraphicsWidget();
|
|
|
|
if (m_applet->containment() && m_applet->containment()->corona()) {
|
|
m_popupDialog->move(m_applet->containment()->corona()->popupPosition(this, m_popupDialog->size(), Qt::AlignCenter));
|
|
}
|
|
KWindowSystem::setState(m_popupDialog->winId(), NET::SkipTaskbar | NET::SkipPager);
|
|
if (m_applet->location() != Plasma::Floating) {
|
|
m_popupDialog->animatedShow(Plasma::locationToDirection(m_applet->location()));
|
|
} else {
|
|
m_popupDialog->show();
|
|
}
|
|
|
|
m_popupDialog->raise();
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::popupVisibilityChanged(bool visible)
|
|
{
|
|
if (!visible) {
|
|
QRect rect = iconGeometry();
|
|
publishIconGeometry(rect);
|
|
update();
|
|
}
|
|
}
|
|
|
|
bool TaskGroupItem::focusNextPrevChild(bool next)
|
|
{
|
|
return focusSubTask(next, false);
|
|
}
|
|
|
|
bool TaskGroupItem::focusSubTask(bool next, bool activate)
|
|
{
|
|
const int subTasks = totalSubTasks();
|
|
|
|
if (subTasks > 0) {
|
|
int index = -1;
|
|
|
|
if (subTasks > 1) {
|
|
for (int i = 0; i < subTasks; ++i) {
|
|
if (selectSubTask(i)->taskFlags() & TaskHasFocus) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (next) {
|
|
++index;
|
|
|
|
if (index >= subTasks) {
|
|
index = 0;
|
|
}
|
|
} else {
|
|
--index;
|
|
|
|
if (index < 0) {
|
|
index = (subTasks - 1);
|
|
}
|
|
}
|
|
|
|
AbstractTaskItem *taskItem = selectSubTask(index);
|
|
|
|
if (taskItem) {
|
|
taskItem->setFocus();
|
|
m_activeTaskIndex = index;
|
|
}
|
|
|
|
if (activate && taskItem) {
|
|
stopWindowHoverEffect();
|
|
taskItem->activate();
|
|
}
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if (isRootGroup()) {
|
|
return;
|
|
}
|
|
|
|
if (QPoint(event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < QApplication::startDragDistance()) {
|
|
return;
|
|
} //Wait a bit before starting drag
|
|
|
|
//kDebug();
|
|
if (m_popupMenuTimer) {
|
|
//kDebug() << "popupTimer stop";
|
|
m_popupMenuTimer->stop();
|
|
} //Wait a bit before starting drag
|
|
AbstractTaskItem::mouseMoveEvent(event);
|
|
}
|
|
|
|
void TaskGroupItem::resizeEvent(QGraphicsSceneResizeEvent *event)
|
|
{
|
|
Q_UNUSED(event)
|
|
|
|
if (m_offscreenWidget && m_popupDialog) {
|
|
int left, top, right, bottom;
|
|
m_popupDialog->getContentsMargins(&left, &top, &right, &bottom);
|
|
m_offscreenWidget->setMinimumWidth(size().width() - left - right);
|
|
}
|
|
|
|
AbstractTaskItem::resizeEvent(event);
|
|
}
|
|
|
|
void TaskGroupItem::expand()
|
|
{
|
|
if (!collapsed()) {
|
|
//kDebug() << "already expanded";
|
|
return;
|
|
}
|
|
|
|
if (m_popupDialog) {
|
|
m_popupDialog->hide();
|
|
}
|
|
|
|
if (m_offscreenLayout) {
|
|
m_offscreenLayout->removeItem(tasksLayout());
|
|
}
|
|
|
|
if (!m_mainLayout) { //this layout is needed since we can't take a layout directly from a widget without destroying it
|
|
m_mainLayout = new QGraphicsLinearLayout(this);
|
|
m_mainLayout->setContentsMargins(0, 0, 0, 0); //default are 4 on each side
|
|
setLayout(m_mainLayout);
|
|
}
|
|
|
|
//set it back from the popup settings (always vertical and 1 row)
|
|
tasksLayout()->setOrientation(m_applet->formFactor());
|
|
tasksLayout()->setMaximumRows(m_maximumRows);
|
|
|
|
m_mainLayout->addItem(tasksLayout());
|
|
|
|
disconnect(m_applet, SIGNAL(constraintsChanged(Plasma::Constraints)), this, SLOT(constraintsChanged(Plasma::Constraints)));
|
|
connect(m_applet, SIGNAL(constraintsChanged(Plasma::Constraints)), this, SLOT(constraintsChanged(Plasma::Constraints)));
|
|
//connect(m_tasksLayout, SIGNAL(sizeHintChanged(Qt::SizeHint)), this, SLOT(updatePreferredSize()));
|
|
m_collapsed = false;
|
|
tasksLayout()->layoutItems();
|
|
//kDebug() << tasksLayout()->preferredSize() << preferredSize() << m_groupMembers.count();
|
|
emit changed();
|
|
checkSettings();
|
|
//kDebug() << "expanded";
|
|
}
|
|
|
|
void TaskGroupItem::constraintsChanged(Plasma::Constraints constraints)
|
|
{
|
|
//kDebug();
|
|
if (constraints & Plasma::SizeConstraint && m_tasksLayout) {
|
|
m_tasksLayout->layoutItems();
|
|
}
|
|
|
|
if (constraints & Plasma::FormFactorConstraint && m_tasksLayout) {
|
|
m_tasksLayout->setOrientation(m_applet->formFactor());
|
|
if (m_dropIndicator) {
|
|
m_dropIndicator->setOrientation(Plasma::Vertical == m_applet->formFactor() ? Qt::Vertical : Qt::Horizontal);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::relayoutItems()
|
|
{
|
|
if (m_tasksLayout) {
|
|
m_tasksLayout->layoutItems();
|
|
}
|
|
}
|
|
|
|
TaskItemLayout *TaskGroupItem::tasksLayout()
|
|
{
|
|
if (!m_tasksLayout) {
|
|
m_tasksLayout = new TaskItemLayout(this, m_applet);
|
|
m_tasksLayout->setMaximumRows(m_maximumRows);
|
|
m_tasksLayout->setForceRows(false); // m_forceRows);
|
|
m_tasksLayout->setOrientation(m_applet->formFactor());
|
|
}
|
|
|
|
return m_tasksLayout;
|
|
}
|
|
|
|
void TaskGroupItem::collapse()
|
|
{
|
|
//kDebug() << (int)this;
|
|
if (collapsed()) {
|
|
//kDebug() << "already collapsed";
|
|
return;
|
|
}
|
|
|
|
m_mainLayout->removeItem(tasksLayout());
|
|
if (m_offscreenLayout) {
|
|
m_offscreenLayout->addItem(tasksLayout());
|
|
} else {
|
|
foreach (AbstractTaskItem * member, m_groupMembers) {
|
|
scene()->removeItem(member);
|
|
}
|
|
}
|
|
|
|
//kDebug();
|
|
//delete m_tasksLayout;
|
|
disconnect(m_applet, SIGNAL(constraintsChanged(Plasma::Constraints)), this, SLOT(constraintsChanged(Plasma::Constraints)));
|
|
m_collapsed = true;
|
|
updatePreferredSize();
|
|
//kDebug();
|
|
emit changed();
|
|
checkSettings();
|
|
}
|
|
|
|
bool TaskGroupItem::collapsed() const
|
|
{
|
|
return m_collapsed;
|
|
}
|
|
|
|
void TaskGroupItem::toCurrentDesktop()
|
|
{
|
|
if (!isRootGroup()) {
|
|
foreach (AbstractTaskItem * member, m_groupMembers) {
|
|
member->toCurrentDesktop();
|
|
}
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::updatePreferredSize()
|
|
{
|
|
if (m_collapsed) {
|
|
foreach (AbstractTaskItem * taskItem, m_groupMembers) {
|
|
taskItem->setPreferredOffscreenSize();
|
|
}
|
|
|
|
//FIXME: copypaste from abstracttaskitem: to be done better with proper sizeHint()
|
|
setPreferredSize(basicPreferredSize());
|
|
} else {
|
|
foreach (AbstractTaskItem * taskItem, m_groupMembers) {
|
|
taskItem->setPreferredOnscreenSize();
|
|
}
|
|
|
|
layout()->invalidate();
|
|
setPreferredSize(layout()->preferredSize());
|
|
//kDebug() << "expanded group" << layout()->preferredSize();
|
|
}
|
|
|
|
//kDebug() << preferredSize();
|
|
emit sizeHintChanged(Qt::PreferredSize);
|
|
}
|
|
|
|
AbstractTaskItem *TaskGroupItem::directMember(AbstractTaskItem *item)
|
|
{
|
|
Q_ASSERT(item);
|
|
Q_ASSERT(m_group);
|
|
TaskManager::AbstractGroupableItem * directMember = m_group.data()->directMember(item->abstractItem());
|
|
if (!directMember) {
|
|
kDebug() << "Error" << item->abstractItem();
|
|
}
|
|
return abstractTaskItem(directMember);
|
|
}
|
|
|
|
void TaskGroupItem::paint(QPainter *painter,
|
|
const QStyleOptionGraphicsItem *option,
|
|
QWidget *widget)
|
|
{
|
|
if (collapsed()) {
|
|
AbstractTaskItem::paint(painter, option, widget);
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::itemPositionChanged(AbstractGroupableItem * item)
|
|
{
|
|
//kDebug();
|
|
if (!m_tasksLayout) {
|
|
return;
|
|
}
|
|
|
|
Q_ASSERT(item);
|
|
|
|
AbstractTaskItem *taskItem = abstractTaskItem(item);
|
|
|
|
m_tasksLayout->removeTaskItem(taskItem);
|
|
|
|
// NOTE: If the grouping strategy is "only when the taskbar is full",
|
|
// removing the task from the layout might cause this group to
|
|
// split, and so the task might be removed from the group.
|
|
// This will cause deleteLater() to be called on taskItem, and
|
|
// we are in danger of inserting a pointer that will soon be
|
|
// invalid into the layout. So check that the task item is
|
|
// still in the group.
|
|
taskItem = abstractTaskItem(item);
|
|
if (m_group && taskItem) {
|
|
m_tasksLayout->insert(m_group.data()->members().indexOf(item), taskItem);
|
|
}
|
|
}
|
|
|
|
|
|
void TaskGroupItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
|
|
{
|
|
bool shouldIgnore = shouldIgnoreDragEvent(event);
|
|
if ((collapsed() && shouldIgnore) || (isRootGroup() && !shouldIgnore)) {
|
|
event->ignore();
|
|
//kDebug()<<"Drag enter accepted";
|
|
} else {
|
|
event->accept();
|
|
if (!m_popupMenuTimer) {
|
|
m_popupMenuTimer = new QTimer(this);
|
|
m_popupMenuTimer->setSingleShot(true);
|
|
m_popupMenuTimer->setInterval(500);
|
|
connect(m_popupMenuTimer, SIGNAL(timeout()), this, SLOT(popupMenu()));
|
|
}
|
|
m_popupMenuTimer->start();
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *)
|
|
{
|
|
if (m_popupMenuTimer) {
|
|
m_popupMenuTimer->stop();
|
|
}
|
|
|
|
if (m_dropIndicator && m_dropIndicator->isVisible()) {
|
|
m_dropIndicator->setVisible(false);
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
|
|
{
|
|
if (isRootGroup()) {
|
|
//#ifndef ICON_TASKS_SHOW_DROP_INDICATOR_FOR_MOVE
|
|
int sourceIndex = event->mimeData()->property("icontasks-item-ptr").isValid()
|
|
? m_applet->rootGroupItem()->indexOf((AbstractTaskItem *)(event->mimeData()->property("icontasks-item-ptr").toULongLong()), false)
|
|
: -1;
|
|
//#else
|
|
//int sourceIndex = event->mimeData()->property("icontasks-item-index").isValid() ? event->mimeData()->property("icontasks-item-index").toInt() : -1;
|
|
//#endif
|
|
bool isDesktopFile = -1 == sourceIndex && event->mimeData()->hasFormat("text/uri-list");
|
|
bool isLauncher = isDesktopFile || (-1 != sourceIndex && sourceIndex < m_applet->groupManager().launcherCount());
|
|
|
|
if (isLauncher && m_applet->groupManager().launchersLocked()) {
|
|
return;
|
|
}
|
|
|
|
if (sourceIndex > -1 || isDesktopFile) {
|
|
TaskItemLayout::Insert destIndex = m_tasksLayout->insertionIndexAt(event->pos());
|
|
bool visible = destIndex.index != sourceIndex && destIndex.index >= 0 && (destIndex.geom.x() > 0 || destIndex.geom.y() > 0 || 0 == destIndex.index);
|
|
bool moveRight = sourceIndex > -1 && destIndex.index > sourceIndex;
|
|
|
|
// qDebug() << event->pos() << sourceIndex << destIndex.index << destIndex.geom;
|
|
if (visible && ((isLauncher && destIndex.index - (moveRight ? 1 : 0) < m_applet->groupManager().launcherCount()) ||
|
|
(!isLauncher && destIndex.index - (moveRight ? 1 : 0) >= m_applet->groupManager().launcherCount()))) {
|
|
//#ifndef ICON_TASKS_SHOW_DROP_INDICATOR_FOR_MOVE
|
|
if (!isDesktopFile) {
|
|
dropEvent(event);
|
|
return;
|
|
}
|
|
//#endif
|
|
|
|
if (!m_dropIndicator) {
|
|
m_dropIndicator = new DropIndicator(parentItem());
|
|
m_dropIndicator->setOrientation(Plasma::Vertical == m_applet->formFactor() ? Qt::Vertical : Qt::Horizontal);
|
|
m_dropIndicator->setVisible(false);
|
|
}
|
|
|
|
if (!m_dropIndicator->isVisible()) {
|
|
m_dropIndicator->setSize((Plasma::Vertical == m_applet->formFactor() ? destIndex.geom.height() : destIndex.geom.width()) / 3.0);
|
|
}
|
|
|
|
m_dropIndicator->setPosition(QRectF(mapToParent(destIndex.geom.topLeft()), destIndex.geom.size()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (m_dropIndicator && m_dropIndicator->isVisible()) {
|
|
m_dropIndicator->setVisible(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
AbstractTaskItem *TaskGroupItem::taskItemForWId(WId id)
|
|
{
|
|
QHashIterator<AbstractGroupableItem *, AbstractTaskItem*> it(m_groupMembers);
|
|
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
AbstractTaskItem *item = it.value();
|
|
TaskGroupItem *group = qobject_cast<TaskGroupItem*>(item);
|
|
|
|
if (group) {
|
|
item = group->taskItemForWId(id);
|
|
if (item) {
|
|
return item;
|
|
}
|
|
} else {
|
|
TaskManager::TaskItem *task = qobject_cast<TaskManager::TaskItem*>(it.key());
|
|
if (task && task->task() && task->task()->window() == id) {
|
|
return item;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static QString agiName(TaskManager::AbstractGroupableItem *i)
|
|
{
|
|
if (i->itemType() == TaskManager::TaskItemType && !i->isStartupItem()) {
|
|
return static_cast<TaskItem *>(i)->taskName().toLower();
|
|
} else {
|
|
return i->name().toLower();
|
|
}
|
|
}
|
|
|
|
AbstractTaskItem *TaskGroupItem::matchingItem(TaskManager::AbstractGroupableItem *from)
|
|
{
|
|
QHashIterator<AbstractGroupableItem *, AbstractTaskItem*> it(m_groupMembers);
|
|
AbstractTaskItem *itm = 0L;
|
|
QString n = agiName(from);
|
|
KUrl launcherUrl = from->launcherUrl();
|
|
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
AbstractGroupableItem *item = it.key();
|
|
AbstractTaskItem *taskItem = it.value();
|
|
QString name = agiName(item);
|
|
|
|
if ((name == n || (!launcherUrl.isEmpty() && item->launcherUrl() == launcherUrl)) &&
|
|
(qobject_cast<TaskGroupItem*>(taskItem) || !taskItem->busyWidget())) {
|
|
itm = taskItem;
|
|
}
|
|
}
|
|
|
|
return itm;
|
|
}
|
|
|
|
void TaskGroupItem::dropEvent(QGraphicsSceneDragDropEvent *event)
|
|
{
|
|
if (m_dropIndicator && m_dropIndicator->isVisible()) {
|
|
m_dropIndicator->setVisible(false);
|
|
}
|
|
|
|
//kDebug() << "TaskItemLayout dropEvent";
|
|
if (event->mimeData()->hasFormat(TaskManager::Task::mimetype()) ||
|
|
event->mimeData()->hasFormat(TaskManager::Task::groupMimetype())) {
|
|
bool ok;
|
|
QList<WId> ids = TaskManager::Task::idsFromMimeData(event->mimeData(), &ok);
|
|
|
|
if (!ok) {
|
|
//kDebug() << "FAIL!";
|
|
event->ignore();
|
|
return;
|
|
}
|
|
|
|
AbstractTaskItem *targetTask = dynamic_cast<AbstractTaskItem *>(scene()->itemAt(mapToScene(event->pos())));
|
|
// kDebug() << "Pos: " << event->pos() << mapToScene(event->pos()) << "item" << scene()->itemAt(mapToScene(event->pos())) << "target Task " << dynamic_cast<QGraphicsItem *>(targetTask);
|
|
|
|
//kDebug() << "got" << ids.count() << "windows";
|
|
foreach (WId id, ids) {
|
|
handleDroppedId(id, targetTask, event);
|
|
}
|
|
|
|
//kDebug() << "TaskItemLayout dropEvent done";
|
|
event->acceptProposedAction();
|
|
} else if (!m_applet->groupManager().launchersLocked() && event->mimeData()->hasFormat("text/uri-list")) {
|
|
KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
|
|
foreach (const KUrl & url, urls) {
|
|
const bool exists = m_applet->groupManager().launcherExists(url);
|
|
if (exists) {
|
|
// it exists; if we are doing manual sorting, make sure it is in the right location if
|
|
// it is in this group .. otherwise, we can do nothing.
|
|
if (m_applet->groupManager().sortingStrategy() == TaskManager::GroupManager::ManualSorting) {
|
|
QHashIterator<AbstractGroupableItem *, AbstractTaskItem*> it(m_groupMembers);
|
|
while (it.hasNext()) {
|
|
it.next();
|
|
if (it.key()->itemType() == TaskManager::LauncherItemType &&
|
|
it.key()->launcherUrl() == url) {
|
|
layoutTaskItem(it.value(), event->pos());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
m_applet->groupManager().addLauncher(url, QIcon(), QString(), QString(), QString(), m_tasksLayout->insertionIndexAt(event->pos()).index);
|
|
}
|
|
}
|
|
} else {
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::handleDroppedId(WId id, AbstractTaskItem *, QGraphicsSceneDragDropEvent *event)
|
|
{
|
|
AbstractTaskItem *taskItem = m_applet->rootGroupItem()->taskItemForWId(id);
|
|
|
|
if (!taskItem) {
|
|
//kDebug() << "Invalid TaskItem";
|
|
return;
|
|
}
|
|
|
|
if (!taskItem->parentGroup()) {
|
|
//kDebug() << "group invalid";
|
|
return;
|
|
}
|
|
|
|
TaskManager::GroupPtr group = taskItem->parentGroup()->group();
|
|
|
|
//kDebug() << id << taskItem->text() << (QObject*)targetTask;
|
|
|
|
// kDebug() << "first item: " << dynamic_cast<QGraphicsItem*>(m_taskItems.first()) << "layout widget" << dynamic_cast<QGraphicsItem*>(this);
|
|
if (m_applet->groupManager().sortingStrategy() == TaskManager::GroupManager::ManualSorting) {
|
|
//Move action
|
|
if (group == m_group.data()) { //same group
|
|
//kDebug() << "Drag within group";
|
|
layoutTaskItem(taskItem, event->pos());
|
|
} else if (m_group) { //task item was dragged outside of group -> group move
|
|
AbstractTaskItem *directMember = abstractTaskItem(m_group.data()->directMember(group));
|
|
if (directMember) {
|
|
layoutTaskItem(directMember, event->pos()); //we need to get the group right under the receiver group
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::layoutTaskItem(AbstractTaskItem* item, const QPointF &pos)
|
|
{
|
|
if (!m_tasksLayout || !item->abstractItem()) {
|
|
return;
|
|
}
|
|
|
|
int insertIndex = m_tasksLayout->insertionIndexAt(pos).index;
|
|
// kDebug() << "Item inserting at: " << insertIndex << "of: " << numberOfItems();
|
|
m_applet->groupManager().manualSortingRequest(item->abstractItem(), insertIndex);
|
|
}
|
|
|
|
|
|
void TaskGroupItem::updateActive(AbstractTaskItem *task)
|
|
{
|
|
if (!m_tasksLayout) {
|
|
return;
|
|
}
|
|
|
|
m_activeTaskIndex = indexOf(task);
|
|
}
|
|
|
|
int TaskGroupItem::indexOf(AbstractTaskItem *task, bool descendGroups)
|
|
{
|
|
if (!m_group || !task) {
|
|
//kDebug() << "Error";
|
|
return -1;
|
|
}
|
|
|
|
int index = 0;
|
|
|
|
foreach (AbstractGroupableItem * item, m_group.data()->members()) {
|
|
AbstractTaskItem *taskItem = abstractTaskItem(item);
|
|
if (!taskItem) {
|
|
continue;
|
|
}
|
|
|
|
if (task == taskItem) {
|
|
if (descendGroups) {
|
|
TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(taskItem);
|
|
if (groupItem) {
|
|
int subIndex = groupItem->indexOf(groupItem->activeSubTask());
|
|
if (subIndex == -1) {
|
|
index += groupItem->count();
|
|
} else {
|
|
return index + subIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
return index;
|
|
}
|
|
|
|
if (descendGroups) {
|
|
TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(taskItem);
|
|
if (groupItem) {
|
|
int subIndex = groupItem->indexOf(task);
|
|
if (subIndex == -1) {
|
|
index += groupItem->count();
|
|
} else {
|
|
return index + subIndex;
|
|
}
|
|
} else {
|
|
++index;
|
|
}
|
|
} else {
|
|
++index;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
AbstractTaskItem * TaskGroupItem::activeSubTask()
|
|
{
|
|
if (!m_group) {
|
|
return 0;
|
|
}
|
|
|
|
foreach (AbstractGroupableItem * item, m_group.data()->members()) {
|
|
AbstractTaskItem *taskItem = abstractTaskItem(item);
|
|
if (taskItem && taskItem->isActive()) {
|
|
TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(taskItem);
|
|
if (groupItem) {
|
|
return groupItem->activeSubTask();
|
|
}
|
|
return taskItem;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int TaskGroupItem::totalSubTasks()
|
|
{
|
|
int count = 0;
|
|
|
|
foreach (AbstractGroupableItem * item, group()->members()) {
|
|
AbstractTaskItem *taskItem = abstractTaskItem(item);
|
|
if (taskItem) {
|
|
TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(taskItem);
|
|
if (groupItem) {
|
|
count += groupItem->count();
|
|
} else if (!qobject_cast<AppLauncherItem *>(taskItem)) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
AbstractTaskItem * TaskGroupItem::selectSubTask(int index)
|
|
{
|
|
foreach (AbstractGroupableItem * item, group()->members()) {
|
|
AbstractTaskItem *taskItem = abstractTaskItem(item);
|
|
if (taskItem) {
|
|
TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(taskItem);
|
|
if (groupItem) {
|
|
if (index < groupItem->count()) {
|
|
return groupItem->abstractTaskItem(groupItem->group()->members().at(index));
|
|
} else {
|
|
index -= groupItem->count();
|
|
}
|
|
} else if (qobject_cast<AppLauncherItem *>(taskItem)) {
|
|
continue;
|
|
} else if (index == 0) {
|
|
return taskItem;
|
|
} else {
|
|
--index;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void TaskGroupItem::wheelEvent(QGraphicsSceneWheelEvent *event)
|
|
{
|
|
focusSubTask((event->delta() < 0), true);
|
|
}
|
|
|
|
int TaskGroupItem::maxRows()
|
|
{
|
|
return m_maximumRows;
|
|
}
|
|
|
|
void TaskGroupItem::setMaxRows(int rows)
|
|
{
|
|
m_maximumRows = rows;
|
|
if (m_tasksLayout) {
|
|
m_tasksLayout->setMaximumRows(m_maximumRows);
|
|
}
|
|
}
|
|
|
|
int TaskGroupItem::optimumCapacity()
|
|
{
|
|
if (m_tasksLayout) {
|
|
return m_tasksLayout->maximumRows() * m_tasksLayout->preferredColumns();
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
AbstractTaskItem* TaskGroupItem::abstractTaskItem(AbstractGroupableItem * item)
|
|
{
|
|
if (!item) {
|
|
return 0;
|
|
}
|
|
|
|
AbstractTaskItem *abstractTaskItem = m_groupMembers.value(item);
|
|
if (!abstractTaskItem) {
|
|
foreach (AbstractTaskItem * taskItem, m_groupMembers) {
|
|
TaskGroupItem *group = qobject_cast<TaskGroupItem*>(taskItem);
|
|
if (group) {
|
|
abstractTaskItem = group->abstractTaskItem(item);
|
|
if (abstractTaskItem) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//kDebug() << "item not found";
|
|
return abstractTaskItem;
|
|
}
|
|
|
|
void TaskGroupItem::setAdditionalMimeData(QMimeData* mimeData)
|
|
{
|
|
if (m_group) {
|
|
m_group.data()->addMimeData(mimeData);
|
|
}
|
|
}
|
|
|
|
void TaskGroupItem::publishIconGeometry() const
|
|
{
|
|
// only do this if we are a collapsed group, with a GroupPtr and members
|
|
if (!collapsed() || !m_group || m_groupMembers.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QRect rect = iconGeometry();
|
|
publishIconGeometry(rect);
|
|
}
|
|
|
|
void TaskGroupItem::publishIconGeometry(const QRect &rect) const
|
|
{
|
|
foreach (AbstractTaskItem * item, m_groupMembers) {
|
|
WindowTaskItem *windowItem = qobject_cast<WindowTaskItem *>(item);
|
|
if (windowItem) {
|
|
windowItem->publishIconGeometry(rect);
|
|
continue;
|
|
}
|
|
|
|
TaskGroupItem *groupItem = qobject_cast<TaskGroupItem *>(item);
|
|
if (groupItem) {
|
|
groupItem->publishIconGeometry(rect);
|
|
}
|
|
}
|
|
}
|
|
|
|
QWidget *TaskGroupItem::popupDialog() const
|
|
{
|
|
return m_popupDialog;
|
|
}
|
|
|
|
#include "moc_taskgroupitem.cpp"
|
|
|