/*************************************************************************** * Copyright (C) 2007 by Robert Knight * * Copyright (C) 2008 by Alexis Ménard * * Copyright (C) 2012-2013 by Eike Hein * * * * 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 . * ***************************************************************************/ #include "tasks.h" #include "support/draghelper.h" #include "support/textlabel.h" #include "support/tooltip.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class GroupManager : public TaskManager::GroupManager { public: GroupManager(Plasma::Applet *applet) : TaskManager::GroupManager(applet), m_applet(applet) { } protected: KConfigGroup config() const { return m_applet->config(); } private: Plasma::Applet *m_applet; }; Tasks::Tasks(QObject *parent, const QVariantList &args) : Plasma::Applet(parent, args), m_groupManager(0), m_declarativeWidget(0), m_highlightWindows(false), m_lastViewId(0) { setAspectRatioMode(Plasma::IgnoreAspectRatio); setHasConfigurationInterface(true); } Tasks::~Tasks() { } void Tasks::init() { m_groupManager = new GroupManager(this); connect(m_groupManager, SIGNAL(configChanged()), this, SIGNAL(configNeedsSaving())); Plasma::Containment *c = containment(); if (c) { m_groupManager->setScreen(c->screen()); } m_tasksModel = new TaskManager::TasksModel(m_groupManager, this); m_declarativeWidget = new Plasma::DeclarativeWidget(this); QDeclarativeContext* rootContext = m_declarativeWidget->engine()->rootContext(); qmlRegisterType( "Tasks", 0, 1, "TextLabel" ); qmlRegisterType( "Tasks", 0, 1, "ToolTip" ); rootContext->setContextProperty("tasksModel", QVariant::fromValue(static_cast(m_tasksModel))); rootContext->setContextProperty("dragHelper", QVariant::fromValue(static_cast(new DragHelper(this)))); // NOTE: This can go away once Plasma::Location becomes available (i.e. once this is // a pure-QML applet.) rootContext->setContextProperty("LeftEdge", Plasma::LeftEdge); rootContext->setContextProperty("TopEdge", Plasma::TopEdge); rootContext->setContextProperty("RightEdge", Plasma::RightEdge); rootContext->setContextProperty("BottomEdge", Plasma::BottomEdge); Plasma::PackageStructure::Ptr structure = Plasma::PackageStructure::load("Plasma/Generic"); Plasma::Package *package = new Plasma::Package(QString(), "org.kde.plasma.tasks", structure); m_declarativeWidget->setQmlPath(package->filePath("mainscript")); delete package; QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); layout->addItem(m_declarativeWidget); setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); setMaximumSize(INT_MAX, INT_MAX); QDeclarativeProperty preferredWidth(m_declarativeWidget->rootObject(), "preferredWidth"); preferredWidth.connectNotifySignal(this, SLOT(changeSizeHint())); QDeclarativeProperty preferredHeight(m_declarativeWidget->rootObject(), "preferredHeight"); preferredHeight.connectNotifySignal(this, SLOT(changeSizeHint())); QDeclarativeProperty optimumCapacity(m_declarativeWidget->rootObject(), "optimumCapacity"); optimumCapacity.connectNotifySignal(this, SLOT(optimumCapacityChanged())); connect(m_declarativeWidget->rootObject(), SIGNAL(activateItem(int,bool)), this, SLOT(activateItem(int,bool))); connect(m_declarativeWidget->rootObject(), SIGNAL(itemContextMenu(int)), this, SLOT(itemContextMenu(int)), Qt::QueuedConnection); connect(m_declarativeWidget->rootObject(), SIGNAL(itemMove(int,int)), this, SLOT(itemMove(int,int))); connect(m_declarativeWidget->rootObject(), SIGNAL(itemGeometryChanged(int,int,int,int,int)), this, SLOT(itemGeometryChanged(int,int,int,int,int))); connect(m_declarativeWidget->rootObject(), SIGNAL(itemNeedsAttention(bool)), this, SLOT(itemNeedsAttention(bool))); connect(m_declarativeWidget->rootObject(), SIGNAL(presentWindows(int)), this, SLOT(presentWindows(int))); connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)), this, SLOT(handleActiveWindowChanged(WId))); configChanged(); } void Tasks::changeSizeHint() { emit sizeHintChanged(Qt::PreferredSize); } QSizeF Tasks::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const { if (which == Qt::PreferredSize && m_declarativeWidget && m_declarativeWidget->rootObject()) { return QSizeF(m_declarativeWidget->rootObject()->property("preferredWidth").toReal(), m_declarativeWidget->rootObject()->property("preferredHeight").toReal()); } else { return Plasma::Applet::sizeHint(which, constraint); } } void Tasks::constraintsEvent(Plasma::Constraints constraints) { if (m_groupManager && (constraints & Plasma::ScreenConstraint)) { Plasma::Containment *c = containment(); if (c) { m_groupManager->setScreen(c->screen()); } } if (constraints & Plasma::FormFactorConstraint) { m_declarativeWidget->rootObject()->setProperty("horizontal", formFactor() == Plasma::Horizontal); m_declarativeWidget->rootObject()->setProperty("vertical", formFactor() == Plasma::Vertical); } if (constraints & Plasma::LocationConstraint) { m_declarativeWidget->rootObject()->setProperty("location", location()); } setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); } void Tasks::optimumCapacityChanged() { m_groupManager->setFullLimit(m_declarativeWidget->rootObject()->property("optimumCapacity").toInt() + 1); } void Tasks::activateItem(int id, bool toggle) { TaskManager::AbstractGroupableItem* item = m_groupManager->rootGroup()->getMemberById(id); if (!item) { return; } if (item->itemType() == TaskManager::TaskItemType && !item->isStartupItem()) { TaskManager::TaskItem* taskItem = static_cast(item); if (toggle) { taskItem->task()->activateRaiseOrIconify(); } else { taskItem->task()->activate(); } } else if (item->itemType() == TaskManager::LauncherItemType) { static_cast(item)->launch(); } } void Tasks::itemContextMenu(int id) { TaskManager::AbstractGroupableItem* item = m_groupManager->rootGroup()->getMemberById(id); QDeclarativeItem* declItem = 0; QList declItems = m_declarativeWidget->rootObject()->findChildren(); foreach(QDeclarativeItem* obj, declItems) { if (obj->property("itemId").toInt() == id) { declItem = obj; break; } } if (!item || !declItem) { return; } QList actionList; QAction *configAction = action("configure"); if (configAction && configAction->isEnabled()) { actionList.append(configAction); } TaskManager::BasicMenu* menu = 0; Q_ASSERT(containment()); Q_ASSERT(containment()->corona()); if (item->itemType() == TaskManager::TaskItemType && !item->isStartupItem()) { TaskManager::TaskItem* taskItem = static_cast(item); /* FIXME (Un)collapse support is pending merge. QAction *a(0); if (taskItem->isGrouped()) { a = new QAction(i18n("Collapse Parent Group"), 0); connect(a, SIGNAL(triggered()), taskItem->parentGroup(), SLOT(collapse())); actionList.prepend(a); } */ menu = new TaskManager::BasicMenu(0, taskItem, m_groupManager, actionList); } else if (item->itemType() == TaskManager::GroupItemType) { TaskManager::TaskGroup* taskGroup = static_cast(item); /* FIXME (Un)collapse support is pending merge. QAction *a; if (true) { a = new QAction(i18n("Collapse Group"), this); connect(a, SIGNAL(triggered()), taskGroup, SLOT(collapse())); } else { a = new QAction(i18n("Expand Group"), this); connect(a, SIGNAL(triggered()), taskGroup, SLOT(expand())); } actionList.prepend(a); */ const int maxWidth = 0.8 * containment()->corona()->screenGeometry(containment()->screen()).width(); menu = new TaskManager::BasicMenu(0, taskGroup, m_groupManager, actionList, QList (), maxWidth); } else if (item->itemType() == TaskManager::LauncherItemType) { menu = new TaskManager::BasicMenu(0, static_cast(item), m_groupManager, actionList); } if (!menu) { return; } menu->adjustSize(); if (formFactor() != Plasma::Vertical) { menu->setMinimumWidth(declItem->implicitWidth()); } menu->exec(containment()->corona()->popupPosition(declItem, menu->size())); menu->deleteLater(); } void Tasks::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { QVariant ret; QMetaObject::invokeMethod(m_declarativeWidget->rootObject(), "isTaskAt", Q_RETURN_ARG(QVariant, ret), Q_ARG(QVariant, event->pos())); if (!ret.toBool()) { Plasma::Applet::contextMenuEvent(event); } } void Tasks::itemHovered(int id, bool hovered) { TaskManager::AbstractGroupableItem* item = m_groupManager->rootGroup()->getMemberById(id); if (!item) { return; } if (hovered && m_highlightWindows && view()) { m_lastViewId = view()->winId(); Plasma::WindowEffects::highlightWindows(m_lastViewId, QList::fromSet(item->winIds())); } else if (m_highlightWindows && m_lastViewId) { Plasma::WindowEffects::highlightWindows(m_lastViewId, QList()); } } void Tasks::itemMove(int id, int newIndex) { m_groupManager->manualSortingRequest(m_groupManager->rootGroup()->getMemberById(id), newIndex); } void Tasks::itemGeometryChanged(int id, int x, int y, int width, int height) { TaskManager:: AbstractGroupableItem *item = m_groupManager->rootGroup()->getMemberById(id); if (!item || item->itemType() != TaskManager::TaskItemType || !scene()) { return; } TaskManager::TaskItem *taskItem = static_cast(item); if (!taskItem->task()) { return; } QGraphicsView *parentView = 0; QGraphicsView *possibleParentView = 0; // 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. foreach (QGraphicsView *view, scene()->views()) { if (view->sceneRect().intersects(sceneBoundingRect()) || view->sceneRect().contains(scenePos())) { if (view->isActiveWindow()) { parentView = view; break; } else { possibleParentView = view; } } } if (!parentView) { parentView = possibleParentView; if (!parentView) { return; } } QRect iconRect(x, y, width, height); iconRect.moveTopLeft(parentView->mapFromScene(m_declarativeWidget->mapToScene(iconRect.topLeft()))); iconRect.moveTopLeft(parentView->mapToGlobal(iconRect.topLeft())); taskItem->task()->publishIconGeometry(iconRect); } void Tasks::itemNeedsAttention(bool needs) { if (needs) { setStatus(Plasma::NeedsAttentionStatus); } else { foreach(TaskManager::AbstractGroupableItem *item, m_groupManager->rootGroup()->members()) { if (item->demandsAttention()) { // not time to go passive yet! :) return; } } setStatus(Plasma::PassiveStatus); } } void Tasks::presentWindows(int groupParentId) { TaskManager:: AbstractGroupableItem *item = m_groupManager->rootGroup()->getMemberById(groupParentId); if (item) { Plasma::WindowEffects::presentWindows(view()->winId(), QList::fromSet(item->winIds())); } } void Tasks::handleActiveWindowChanged(WId activeWindow) { m_declarativeWidget->rootObject()->setProperty("activeWindowId", qulonglong(activeWindow)); } void Tasks::configChanged() { KConfigGroup cg = config(); bool changed = false; // only update these if they have actually changed, because they make the // group manager reload its tasks list const bool showOnlyCurrentDesktop = cg.readEntry("showOnlyCurrentDesktop", true); if (showOnlyCurrentDesktop != m_groupManager->showOnlyCurrentDesktop()) { m_groupManager->setShowOnlyCurrentDesktop(showOnlyCurrentDesktop); m_declarativeWidget->rootObject()->setProperty("showOnlyCurrentDesktop", showOnlyCurrentDesktop); changed = true; } const bool showOnlyCurrentScreen = cg.readEntry("showOnlyCurrentScreen", false); if (showOnlyCurrentScreen != m_groupManager->showOnlyCurrentScreen()) { m_groupManager->setShowOnlyCurrentScreen(showOnlyCurrentScreen); changed = true; } const bool showOnlyMinimized = cg.readEntry("showOnlyMinimized", false); if (showOnlyMinimized != m_groupManager->showOnlyMinimized()) { m_groupManager->setShowOnlyMinimized(showOnlyMinimized); m_declarativeWidget->rootObject()->setProperty("showOnlyMinimized", showOnlyMinimized); changed = true; } TaskManager::GroupManager::TaskGroupingStrategy groupingStrategy = static_cast( cg.readEntry("groupingStrategy", static_cast(TaskManager::GroupManager::ProgramGrouping)) ); if (groupingStrategy != m_groupManager->groupingStrategy()) { // FIXME: Add back support for manual grouping. if (groupingStrategy == TaskManager::GroupManager::ManualGrouping) { groupingStrategy = TaskManager::GroupManager::ProgramGrouping; } m_groupManager->setGroupingStrategy(groupingStrategy); changed = true; } const bool onlyGroupWhenFull = cg.readEntry("groupWhenFull", true); if (onlyGroupWhenFull != m_groupManager->onlyGroupWhenFull()) { m_groupManager->setOnlyGroupWhenFull(onlyGroupWhenFull); changed = true; } TaskManager::GroupManager::TaskSortingStrategy sortingStrategy = static_cast( cg.readEntry("sortingStrategy", static_cast(TaskManager::GroupManager::AlphaSorting)) ); if (sortingStrategy != m_groupManager->sortingStrategy()) { m_groupManager->setSortingStrategy(sortingStrategy); m_declarativeWidget->rootObject()->setProperty("manualSorting", (sortingStrategy == TaskManager::GroupManager::ManualSorting)); changed = true; } const int maxRows = cg.readEntry("maxRows", 2); if (maxRows != m_declarativeWidget->rootObject()->property("maxStripes").toInt()) { m_declarativeWidget->rootObject()->setProperty("maxStripes", maxRows); changed = true; } const bool forceRows = cg.readEntry("forceRows", false); if (forceRows != m_declarativeWidget->rootObject()->property("forceStripes").toBool()) { m_declarativeWidget->rootObject()->setProperty("forceStripes", forceRows); changed = true; } const bool showTooltip = cg.readEntry("showToolTip", true); if (showTooltip != m_declarativeWidget->rootObject()->property("showToolTip").toBool()) { m_declarativeWidget->rootObject()->setProperty("showToolTip", showTooltip); changed = true; } const bool highlightWindows = cg.readEntry("highlightWindows", false); if (highlightWindows != m_highlightWindows) { m_highlightWindows = highlightWindows; m_declarativeWidget->rootObject()->setProperty("highlightWindows", m_highlightWindows); if (m_highlightWindows) { connect(m_declarativeWidget->rootObject(), SIGNAL(itemHovered(int,bool)), this, SLOT(itemHovered(int,bool))); } else { disconnect(m_declarativeWidget->rootObject(), SIGNAL(itemHovered(int,bool)), this, SLOT(itemHovered(int,bool))); } changed = true; } m_groupManager->readLauncherConfig(); if (changed) { emit settingsChanged(); } } void Tasks::createConfigurationInterface(KConfigDialog *parent) { QWidget *widget = new QWidget; m_ui.setupUi(widget); connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted())); connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); parent->addPage(widget, i18n("General"), icon()); m_ui.showTooltip->setChecked(m_declarativeWidget->rootObject()->property("showToolTip").toBool()); m_ui.highlightWindows->setChecked(m_highlightWindows); m_ui.showOnlyCurrentDesktop->setChecked(m_groupManager->showOnlyCurrentDesktop()); m_ui.showOnlyCurrentScreen->setChecked(m_groupManager->showOnlyCurrentScreen()); m_ui.showOnlyMinimized->setChecked(m_groupManager->showOnlyMinimized()); m_ui.fillRows->setChecked(m_declarativeWidget->rootObject()->property("forceStripes").toBool()); m_ui.groupingStrategy->addItem(i18n("Do Not Group"),QVariant(TaskManager::GroupManager::NoGrouping)); // FIXME: Add back support for manual grouping. // m_ui.groupingStrategy->addItem(i18n("Manually"),QVariant(TaskManager::GroupManager::ManualGrouping)); m_ui.groupingStrategy->addItem(i18n("By Program Name"),QVariant(TaskManager::GroupManager::ProgramGrouping)); connect(m_ui.groupingStrategy, SIGNAL(currentIndexChanged(int)), this, SLOT(dialogGroupingChanged(int))); switch (m_groupManager->groupingStrategy()) { case TaskManager::GroupManager::NoGrouping: m_ui.groupingStrategy->setCurrentIndex(0); break; /* FIXME: Add back support for manual grouping. case TaskManager::GroupManager::ManualGrouping: m_ui.groupingStrategy->setCurrentIndex(1); break; */ case TaskManager::GroupManager::ProgramGrouping: m_ui.groupingStrategy->setCurrentIndex(1); break; default: m_ui.groupingStrategy->setCurrentIndex(-1); } m_ui.groupWhenFull->setChecked(m_groupManager->onlyGroupWhenFull()); m_ui.sortingStrategy->addItem(i18n("Do Not Sort"),QVariant(TaskManager::GroupManager::NoSorting)); m_ui.sortingStrategy->addItem(i18n("Manually"),QVariant(TaskManager::GroupManager::ManualSorting)); m_ui.sortingStrategy->addItem(i18n("Alphabetically"),QVariant(TaskManager::GroupManager::AlphaSorting)); m_ui.sortingStrategy->addItem(i18n("By Desktop"),QVariant(TaskManager::GroupManager::DesktopSorting)); switch (m_groupManager->sortingStrategy()) { case TaskManager::GroupManager::NoSorting: m_ui.sortingStrategy->setCurrentIndex(0); break; case TaskManager::GroupManager::ManualSorting: m_ui.sortingStrategy->setCurrentIndex(1); break; case TaskManager::GroupManager::AlphaSorting: m_ui.sortingStrategy->setCurrentIndex(2); break; case TaskManager::GroupManager::DesktopSorting: m_ui.sortingStrategy->setCurrentIndex(3); break; case TaskManager::GroupManager::ActivitySorting: m_ui.sortingStrategy->setCurrentIndex(4); break; default: m_ui.sortingStrategy->setCurrentIndex(-1); } m_ui.maxRows->setValue(m_declarativeWidget->rootObject()->property("maxStripes").toInt()); connect(m_ui.fillRows, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(m_ui.showTooltip, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(m_ui.highlightWindows, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(m_ui.maxRows, SIGNAL(valueChanged(int)), parent, SLOT(settingsModified())); connect(m_ui.groupingStrategy, SIGNAL(currentIndexChanged(int)), parent, SLOT(settingsModified())); connect(m_ui.groupWhenFull, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(m_ui.sortingStrategy, SIGNAL(currentIndexChanged(int)), parent, SLOT(settingsModified())); connect(m_ui.showOnlyCurrentScreen, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(m_ui.showOnlyCurrentDesktop, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); connect(m_ui.showOnlyMinimized, SIGNAL(toggled(bool)), parent, SLOT(settingsModified())); } void Tasks::dialogGroupingChanged(int index) { m_ui.groupWhenFull->setEnabled(static_cast(m_ui.groupingStrategy->itemData(index).toInt()) == TaskManager::GroupManager::ProgramGrouping); } void Tasks::configAccepted() { KConfigGroup cg = config(); cg.writeEntry("showOnlyCurrentDesktop", m_ui.showOnlyCurrentDesktop->isChecked()); cg.writeEntry("showOnlyCurrentScreen", m_ui.showOnlyCurrentScreen->isChecked()); cg.writeEntry("showOnlyMinimized", m_ui.showOnlyMinimized->isChecked()); cg.writeEntry("groupingStrategy", m_ui.groupingStrategy->itemData(m_ui.groupingStrategy->currentIndex()).toInt()); cg.writeEntry("groupWhenFull", m_ui.groupWhenFull->isChecked()); cg.writeEntry("sortingStrategy", m_ui.sortingStrategy->itemData(m_ui.sortingStrategy->currentIndex()).toInt()); cg.writeEntry("maxRows", m_ui.maxRows->value()); cg.writeEntry("forceRows", m_ui.fillRows->isChecked()); cg.writeEntry("showToolTip", m_ui.showTooltip->isChecked()); cg.writeEntry("highlightWindows", m_ui.highlightWindows->isChecked()); emit configNeedsSaving(); } #include "moc_tasks.cpp"