kde-extraapps/kdeplasma-addons/containments/groupingdesktop/lib/abstractgroup.cpp
Ivailo Monev c6ca1775e6 generic: misc cleanups
Signed-off-by: Ivailo Monev <xakepa10@laimg.moc>
2016-11-02 03:20:34 +00:00

866 lines
22 KiB
C++

/*
* Copyright 2009-2010 by Giulio Camuffo <giuliocamuffo@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, 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 Library 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 "abstractgroup.h"
#include "abstractgroup_p.h"
#include <QtCore/QTimer>
#include <QtGui/QGraphicsView>
#include <QtGui/QGraphicsScene>
#include <QtGui/qgraphicssceneevent.h>
#include <KConfigDialog>
#include <KWindowSystem>
#include <kservice.h>
#include <kservicetypetrader.h>
#include <Plasma/Containment>
#include <Plasma/FrameSvg>
#include <Plasma/Animator>
#include <Plasma/Animation>
#include "groupingcontainment.h"
#include "freehandle.h"
#include <cmath>
#include <math.h>
AbstractGroupPrivate::AbstractGroupPrivate(AbstractGroup *group)
: q(group),
parentGroup(0),
destroying(false),
background(0),
immutability(Plasma::Mutable),
groupType(AbstractGroup::FreeGroup),
interestingGroup(0),
isMainGroup(false),
backgroundHints(AbstractGroup::NoBackground),
isLoading(true),
hasInterface(false),
simplerBackgroundChildren(false),
m_mainConfig(0)
{
}
AbstractGroupPrivate::~AbstractGroupPrivate()
{
delete m_mainConfig;
}
KConfigGroup *AbstractGroupPrivate::mainConfigGroup()
{
if (m_mainConfig) {
return m_mainConfig;
}
KConfigGroup containmentGroup = q->containment()->config();
KConfigGroup groupsConfig = KConfigGroup(&containmentGroup, "Groups");
m_mainConfig = new KConfigGroup(&groupsConfig, QString::number(id));
return m_mainConfig;
}
void AbstractGroupPrivate::destroyGroup()
{
mainConfigGroup()->deleteGroup();
emit q->configNeedsSaving();
q->scene()->removeItem(q);
delete q;
}
void AbstractGroupPrivate::startDestroyAnimation()
{
Plasma::Animation *zoomAnim = Plasma::Animator::create(Plasma::Animator::ZoomAnimation);
q->connect(zoomAnim, SIGNAL(finished()), q, SLOT(destroyGroup()));
zoomAnim->setTargetWidget(q);
zoomAnim->start();
}
void AbstractGroupPrivate::appletDestroyed(Plasma::Applet *applet)
{
if (applets.contains(applet)) {
kDebug()<<"removed applet"<<applet->id()<<"from group"<<id<<"of type"<<q->pluginName();
applets.removeAll(applet);
emit q->appletRemovedFromGroup(applet, q);
q->saveChildren();
emit q->configNeedsSaving();
if (destroying && (q->children().count() == 0)) {
startDestroyAnimation();
destroying = false;
}
}
}
void AbstractGroupPrivate::subGroupDestroyed(AbstractGroup *subGroup)
{
if (subGroups.contains(subGroup)) {
kDebug()<<"removed sub group"<<subGroup->id()<<"from group"<<id<<"of type"<<q->pluginName();
subGroups.removeAll(subGroup);
KConfigGroup subGroupConfig = subGroup->config().parent();
KConfigGroup groupConfig(&subGroupConfig, QString("GroupInformation"));
groupConfig.deleteGroup();
emit q->subGroupRemovedFromGroup(subGroup, q);
q->saveChildren();
emit q->configNeedsSaving();
if (destroying && (q->children().count() == 0)) {
startDestroyAnimation();
destroying = false;
}
}
}
void AbstractGroupPrivate::addChild(QGraphicsWidget *child)
{
QPointF newPos = q->mapFromItem(child->parentItem(), child->pos());
if (groupType == AbstractGroup::ConstrainedGroup) {
child->setTransform(QTransform());
} else {
QTransform t(child->itemTransform(q));
if (t.m11() != 0) {
qreal angle = (t.m12() > 0 ? acos(t.m11()) : -acos(t.m11()));
QTransform at;
QSizeF size(child->size());
at.translate(size.width() / 2, size.height() / 2);
at.rotateRadians(angle);
at.translate(-size.width() / 2, -size.height() / 2);
child->setTransform(at);
newPos -= QPointF(at.dx(), at.dy());
}
}
child->setParentItem(q);
child->setProperty("group", QVariant::fromValue(q));
child->setPos(newPos);
if (groupType == AbstractGroup::FreeGroup) {
q->connect(child, SIGNAL(geometryChanged()), q, SLOT(onChildGeometryChanged()));
}
}
void AbstractGroupPrivate::removeChild(QGraphicsWidget *child)
{
QPointF newPos = child->scenePos();
QGraphicsItem *parent = q->parentItem();
QTransform t(child->itemTransform(parent));
if (t.m11() != 0) {
qreal angle = (t.m12() > 0 ? acos(t.m11()) : -acos(t.m11()));
QTransform at;
QSizeF size(child->size());
at.translate(size.width() / 2, size.height() / 2);
at.rotateRadians(angle);
at.translate(-size.width() / 2, -size.height() / 2);
child->setTransform(at);
}
child->setParentItem(parent);
child->setPos(parent->mapFromScene(newPos));
child->disconnect(q);
}
void AbstractGroupPrivate::restoreChildren()
{
q->restoreChildren();
isLoading = false;
setBackground();
q->update();
}
void AbstractGroupPrivate::onChildGeometryChanged()
{
q->saveChildren();
emit q->configNeedsSaving();
}
QString AbstractGroupPrivate::configDialogId()
{
return QString("%1settings").arg(id);
}
void AbstractGroupPrivate::setChildBorders(Plasma::Applet *a, bool added)
{
if (added) {
savedAppletsHints.insert(a, a->backgroundHints());
a->setBackgroundHints(Plasma::Applet::NoBackground);
} else {
if (savedAppletsHints.contains(a)) {
a->setBackgroundHints(savedAppletsHints.value(a));
}
}
}
void AbstractGroupPrivate::setChildBorders(AbstractGroup *g, bool added)
{
if (added) {
savedGroupsHints.insert(g, g->backgroundHints());
g->setBackgroundHints(AbstractGroup::PlainBackground);
} else {
if (savedGroupsHints.contains(g)) {
g->setBackgroundHints(savedGroupsHints.value(g));
}
}
}
void AbstractGroupPrivate::setBackground()
{
if ((backgroundHints & AbstractGroup::StandardBackground) ||
(backgroundHints & AbstractGroup::PlainBackground)) {
if (!background) {
background = new Plasma::FrameSvg(q);
background->setEnabledBorders(Plasma::FrameSvg::AllBorders);
}
if (backgroundHints & AbstractGroup::StandardBackground) {
background->setImagePath("widgets/translucentbackground");
background->setElementPrefix(QString());
} else {
background->setImagePath("widgets/frame");
background->setElementPrefix("sunken");
}
qreal left, top, right, bottom;
background->getMargins(left, top, right, bottom);
q->setContentsMargins(left, right, top, bottom);
background->resizeFrame(q->boundingRect().size());
} else if (background) {
delete background;
background = 0;
q->setContentsMargins(0, 0, 0, 0);
}
}
//-----------------------------AbstractGroup------------------------------
AbstractGroup::AbstractGroup(QGraphicsItem *parent, Qt::WindowFlags wFlags)
: QGraphicsWidget(parent, wFlags),
d(new AbstractGroupPrivate(this))
{
setAcceptDrops(true);
setAcceptHoverEvents(true);
setContentsMargins(10, 10, 10, 10);
setBackgroundHints(StandardBackground);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setMinimumSize(20, 20);
}
AbstractGroup::~AbstractGroup()
{
emit groupDestroyed(this);
delete KConfigDialog::exists(d->configDialogId());
delete d;
}
void AbstractGroup::init()
{
}
void AbstractGroup::setImmutability(Plasma::ImmutabilityType immutability)
{
if (!isMainGroup()) {
setFlag(QGraphicsItem::ItemIsMovable, immutability == Plasma::Mutable);
}
d->immutability = immutability;
foreach (Plasma::Applet *applet, applets()) {
applet->setImmutability(immutability);
}
foreach (AbstractGroup *group, subGroups()) {
group->setImmutability(immutability);
}
emit immutabilityChanged(immutability);
}
Plasma::ImmutabilityType AbstractGroup::immutability() const
{
return d->immutability;
}
uint AbstractGroup::id() const
{
return d->id;
}
AbstractGroup *AbstractGroup::parentGroup() const
{
return d->parentGroup;
}
void AbstractGroup::addApplet(Plasma::Applet *applet, bool layoutApplet)
{
if (!applet) {
return;
}
if (applets().contains(applet)) {
if (applet->parentItem() != this) {
applet->setParentItem(this);
}
return;
}
QVariant pGroup = applet->property("group");
if (pGroup.isValid()) {
pGroup.value<AbstractGroup *>()->removeApplet(applet);
}
kDebug()<<"adding applet"<<applet->id()<<"in group"<<id()<<"of type"<<pluginName();
if (d->simplerBackgroundChildren) {
d->setChildBorders(applet, true);
}
d->applets << applet;
d->addChild(applet);
emit appletAddedInGroup(applet, this);
if (layoutApplet) {
layoutChild(applet, applet->pos());
save(*(d->mainConfigGroup()));
saveChildren();
emit configNeedsSaving();
}
connect(applet, SIGNAL(appletDestroyed(Plasma::Applet*)),
this, SLOT(appletDestroyed(Plasma::Applet*)));
}
void AbstractGroup::addSubGroup(AbstractGroup *group, bool layoutGroup)
{
if (!group) {
return;
}
if (subGroups().contains(group)) {
if (group->parentItem() != this) {
group->setParentItem(this);
}
return;
}
AbstractGroup *parent = group->parentGroup();
if (parent) {
parent->removeSubGroup(group);
}
kDebug()<<"adding sub group"<<group->id()<<"in group"<<id()<<"of type"<<pluginName();
if (d->simplerBackgroundChildren) {
d->setChildBorders(group, true);
}
group->d->parentGroup = this;
d->subGroups << group;
d->addChild(group);
emit subGroupAddedInGroup(group, this);
if (layoutGroup) {
layoutChild(group, group->pos());
save(*(d->mainConfigGroup()));
saveChildren();
emit configNeedsSaving();
}
connect(group, SIGNAL(groupDestroyed(AbstractGroup*)),
this, SLOT(subGroupDestroyed(AbstractGroup*)));
}
Plasma::Applet::List AbstractGroup::applets() const
{
return d->applets;
}
QList<AbstractGroup *> AbstractGroup::subGroups() const
{
return d->subGroups;
}
QList<QGraphicsWidget *> AbstractGroup::children() const
{
QList<QGraphicsWidget *> list;
foreach (Plasma::Applet *applet, d->applets) {
list << applet;
}
foreach (AbstractGroup *group, d->subGroups) {
list << group;
}
return list;
}
void AbstractGroup::removeApplet(Plasma::Applet *applet, AbstractGroup *newGroup)
{
kDebug()<<"removing applet"<<applet->id()<<"from group"<<id()<<"of type"<<pluginName();
if (d->simplerBackgroundChildren) {
d->setChildBorders(applet, false);
}
d->applets.removeAll(applet);
KConfigGroup appletConfig = applet->config().parent();
KConfigGroup groupConfig(&appletConfig, QString("GroupInformation"));
groupConfig.deleteGroup();
if (newGroup) {
newGroup->addApplet(applet);
} else {
d->removeChild(applet);
}
emit appletRemovedFromGroup(applet, this);
saveChildren();
emit configNeedsSaving();
}
void AbstractGroup::removeSubGroup(AbstractGroup *subGroup, AbstractGroup *newGroup)
{
kDebug()<<"removing sub group"<<subGroup->id()<<"from group"<<id()<<"of type"<<pluginName();
if (d->simplerBackgroundChildren) {
d->setChildBorders(subGroup, false);
}
d->subGroups.removeAll(subGroup);
KConfigGroup subGroupConfig = subGroup->config().parent();
KConfigGroup groupConfig(&subGroupConfig, QString("GroupInformation"));
groupConfig.deleteGroup();
if (newGroup) {
newGroup->addSubGroup(subGroup);
} else {
d->removeChild(subGroup);
subGroup->d->parentGroup = 0;
}
emit subGroupRemovedFromGroup(subGroup, this);
saveChildren();
emit configNeedsSaving();
}
void AbstractGroup::destroy()
{
kDebug()<<"destroying group"<<id()<<"of type"<<pluginName();
d->destroying = true;
if (children().count() == 0) {
d->startDestroyAnimation();
return;
}
foreach (AbstractGroup *group, subGroups()) {
group->destroy();
}
foreach (Plasma::Applet *applet, applets()) {
applet->destroy();
}
}
QGraphicsView *AbstractGroup::view() const
{
// It's assumed that we won't be visible on more than one view here.
// Anything that actually needs view() should only really care about
// one of them anyway though.
if (!scene()) {
return 0;
}
QGraphicsView *found = 0;
QGraphicsView *possibleFind = 0;
//kDebug() << "looking through" << scene()->views().count() << "views";
foreach (QGraphicsView *view, scene()->views()) {
//kDebug() << " checking" << view << view->sceneRect()
// << "against" << sceneBoundingRect() << scenePos();
if (view->sceneRect().intersects(sceneBoundingRect()) ||
view->sceneRect().contains(scenePos())) {
//kDebug() << " found something!" << view->isActiveWindow();
if (view->isActiveWindow()) {
found = view;
} else {
possibleFind = view;
}
}
}
return found ? found : possibleFind;
}
GroupingContainment *AbstractGroup::containment() const
{
QGraphicsItem *parent = parentItem();
GroupingContainment *c = 0;
while (parent) {
GroupingContainment *possibleC = dynamic_cast<GroupingContainment *>(parent);
if (possibleC) {
c = possibleC;
break;
}
parent = parent->parentItem();
}
return c;
}
KConfigGroup AbstractGroup::config() const
{
KConfigGroup config = KConfigGroup(d->mainConfigGroup(), "Configuration");
return config;
}
void AbstractGroup::save(KConfigGroup &group) const
{
if (d->isLoading) {
return;
}
if (!group.isValid()) {
group = *d->mainConfigGroup();
}
group.writeEntry("zvalue", zValue());
group.writeEntry("plugin", pluginName());
group.writeEntry("geometry", geometry());
if (transform() == QTransform()) {
group.deleteEntry("transform");
} else {
QList<qreal> m;
QTransform t = transform();
m << t.m11() << t.m12() << t.m13() << t.m21() << t.m22() << t.m23() << t.m31() << t.m32() << t.m33();
group.writeEntry("transform", m);
}
}
void AbstractGroup::saveChildren() const
{
foreach (Plasma::Applet *applet, d->applets) {
KConfigGroup appletConfig = applet->config().parent();
KConfigGroup groupConfig(&appletConfig, QString("GroupInformation"));
groupConfig.writeEntry("Group", id());
saveChildGroupInfo(applet, groupConfig);
}
foreach (AbstractGroup *subGroup, d->subGroups) {
KConfigGroup subGroupConfig = subGroup->config().parent();
KConfigGroup groupConfig(&subGroupConfig, QString("GroupInformation"));
groupConfig.writeEntry("Group", id());
saveChildGroupInfo(subGroup, groupConfig);
}
}
void AbstractGroup::restore(KConfigGroup &group)
{
QList<qreal> m = group.readEntry("transform", QList<qreal>());
if (m.count() == 9) {
QTransform t(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
setTransform(t);
}
qreal z = group.readEntry("zvalue", 0);
QRectF geom = group.readEntry("geometry", QRectF());
setGeometry(geom);
if (z > 0) {
setZValue(z);
}
}
void AbstractGroup::restoreChildren()
{
foreach (Plasma::Applet *applet, d->applets) {
KConfigGroup appletConfig = applet->config().parent();
KConfigGroup groupConfig(&appletConfig, QString("GroupInformation"));
restoreChildGroupInfo(applet, groupConfig);
}
foreach (AbstractGroup *subGroup, d->subGroups) {
KConfigGroup subGroupConfig = subGroup->config().parent();
KConfigGroup groupConfig(&subGroupConfig, QString("GroupInformation"));
restoreChildGroupInfo(subGroup, groupConfig);
}
}
bool AbstractGroup::showDropZone(const QPointF &pos)
{
Q_UNUSED(pos)
//base implementation does nothing
return true;
}
void AbstractGroup::raise()
{
containment()->raise(this);
}
Handle *AbstractGroup::createHandleForChild(QGraphicsWidget *child)
{
if (!children().contains(child)) {
return 0;
}
Plasma::Applet *a = qobject_cast<Plasma::Applet *>(child);
if (a) {
return new FreeHandle(containment(), a);
}
return new FreeHandle(containment(), static_cast<AbstractGroup *>(child));
}
void AbstractGroup::setGroupType(AbstractGroup::GroupType type)
{
d->groupType = type;
}
AbstractGroup::GroupType AbstractGroup::groupType() const
{
return d->groupType;
}
void AbstractGroup::setIsMainGroup()
{
d->isMainGroup = true;
setBackgroundHints(AbstractGroup::NoBackground);
setFlag(QGraphicsItem::ItemIsMovable, false);
setZValue(0);
setContentsMargins(0, 0, 0, 0);
}
bool AbstractGroup::isMainGroup() const
{
return d->isMainGroup;
}
void AbstractGroup::setBackgroundHints(BackgroundHints hints)
{
if (d->backgroundHints == hints) {
return;
}
d->backgroundHints = hints;
if (!d->isLoading) {
d->setBackground();
update();
}
}
AbstractGroup::BackgroundHints AbstractGroup::backgroundHints() const
{
return d->backgroundHints;
}
void AbstractGroup::setUseSimplerBackgroundForChildren(bool use)
{
if (d->simplerBackgroundChildren != use) {
foreach (Plasma::Applet *applet, d->applets) {
d->setChildBorders(applet, use);
}
foreach (AbstractGroup *group, d->subGroups) {
d->setChildBorders(group, use);
}
d->simplerBackgroundChildren = use;
}
}
bool AbstractGroup::useSimplerBackgroundForChildren() const
{
return d->simplerBackgroundChildren;
}
void AbstractGroup::dragLeaveEvent(QGraphicsSceneDragDropEvent *)
{
showDropZone(QPointF());
}
void AbstractGroup::resizeEvent(QGraphicsSceneResizeEvent *event)
{
if (d->background) {
d->background->resizeFrame(event->newSize());
}
if (!d->isLoading && !d->destroying) {
emit geometryChanged();
save(*(d->mainConfigGroup()));
emit configNeedsSaving();
}
}
void AbstractGroup::constraintsEvent(Plasma::Constraints)
{
}
int AbstractGroup::type() const
{
return Type;
}
QVariant AbstractGroup::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch (change) {
case ItemPositionHasChanged:
emit geometryChanged();
case ItemTransformHasChanged: {
// invalid group, will result in save using the default group
KConfigGroup cg;
save(cg);
emit configNeedsSaving();
}
break;
default:
break;
}
return QGraphicsWidget::itemChange(change, value);
}
void AbstractGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
if (d->backgroundHints == NoBackground || !d->background) {
return;
}
if (sceneTransform().isRotating()) {
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->setRenderHint(QPainter::Antialiasing);
}
d->background->paintFrame(painter);
}
void AbstractGroup::showConfigurationInterface()
{
KConfigDialog *dlg = KConfigDialog::exists(d->configDialogId());
if (dlg) {
KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
dlg->show();
KWindowSystem::activateWindow(dlg->winId());
return;
}
KConfigSkeleton *nullManager = new KConfigSkeleton();
KConfigDialog *dialog = new KConfigDialog(0, d->configDialogId(), nullManager);
dialog->setFaceType(KPageDialog::Auto);
dialog->setWindowTitle(i18n("Group Configuration"));
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
createConfigurationInterface(dialog);
//TODO: Apply button does not correctly work for now, so do not show it
dialog->showButton(KDialog::Apply, false);
dialog->showButton(KDialog::Default, false);
QObject::connect(dialog, SIGNAL(finished()), nullManager, SLOT(deleteLater()));
dialog->show();
}
void AbstractGroup::createConfigurationInterface(KConfigDialog *)
{
}
bool AbstractGroup::hasConfigurationInterface() const
{
return d->hasInterface;
}
void AbstractGroup::setHasConfigurationInterface(bool hasInterface)
{
d->hasInterface = hasInterface;
}
void AbstractGroup::updateConstraints(Plasma::Constraints constraints)
{
if (constraints & Plasma::FormFactorConstraint) {
Plasma::FormFactor f = containment()->formFactor();
if (d->background && (f == Plasma::Vertical || f == Plasma::Horizontal)) {
if (backgroundHints() == AbstractGroup::StandardBackground) {
setBackgroundHints(AbstractGroup::PlainBackground);
}
}
}
constraintsEvent(constraints);
}
void AbstractGroup::releaseChild(QGraphicsWidget *)
{
}
QString AbstractGroup::mimeType()
{
return QString("plasma/group");
}
AbstractGroup *AbstractGroup::load(const QString &name, QGraphicsItem *parent)
{
return GroupFactory::instance()->load(name, parent);
}
QStringList AbstractGroup::availableGroups()
{
QStringList groups;
foreach (const GroupInfo &gi, GroupFactory::instance()->groupInfos()) {
groups << gi.name();
}
return groups;
}
GroupInfo AbstractGroup::groupInfo(const QString &name)
{
foreach (const GroupInfo &gi, GroupFactory::instance()->groupInfos()) {
if (gi.name() == name) {
return gi;
}
}
return GroupInfo("");
}
#include "moc_abstractgroup.cpp"