* move containmentConstraintsUpdated to the pimpl

* move Containment::Private to it's own header (eventually subclass Applet::private?)
* have applet use Containment::Private methods to hide gory internal details ;)
* Toolbox -> ToolBox

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=801127
This commit is contained in:
Aaron J. Seigo 2008-04-25 18:44:09 +00:00
parent 10a6ab9c00
commit a915bf7e6b
4 changed files with 497 additions and 462 deletions

View File

@ -57,6 +57,7 @@
#include "plasma/configxml.h" #include "plasma/configxml.h"
#include "plasma/containment.h" #include "plasma/containment.h"
#include "plasma/containment_p.h"
#include "plasma/corona.h" #include "plasma/corona.h"
#include "plasma/dataenginemanager.h" #include "plasma/dataenginemanager.h"
#include "plasma/package.h" #include "plasma/package.h"
@ -933,7 +934,7 @@ void Applet::flushUpdatedConstraints()
Containment* containment = qobject_cast<Plasma::Containment*>(this); Containment* containment = qobject_cast<Plasma::Containment*>(this);
if (isContainment() && containment) { if (isContainment() && containment) {
containment->containmentConstraintsUpdated(c); containment->d->containmentConstraintsUpdated(c);
} }
constraintsUpdated(c); constraintsUpdated(c);

View File

@ -19,6 +19,7 @@
*/ */
#include "containment.h" #include "containment.h"
#include "containment_p.h"
#include <QAction> #include <QAction>
#include <QDesktopWidget> #include <QDesktopWidget>
@ -51,109 +52,6 @@
namespace Plasma namespace Plasma
{ {
static const int INTER_CONTAINMENT_MARGIN = 6;
static const int VERTICAL_STACKING_OFFSET = 10000;
class Containment::Private
{
public:
Private(Containment* c)
: q(c),
formFactor(Planar),
location(Floating),
screen(-1), // no screen
toolbox(0),
type(Containment::NoContainmentType),
positioning(false)
{
}
~Private()
{
qDeleteAll(applets);
applets.clear();
}
Toolbox* createToolbox()
{
if (!toolbox) {
switch (type) {
case PanelContainment:
toolbox = new PanelToolbox(q);
break;
//defaults to DesktopContainment right now
default:
toolbox = new DesktopToolbox(q);
break;
}
positionToolbox();
}
return toolbox;
}
void positionToolbox()
{
QRectF r;
if (screen < 0) {
r = q->geometry();
} else {
QDesktopWidget *desktop = QApplication::desktop();
r = desktop->availableGeometry(screen);
}
toolbox->setPos(QPointF(r.right(), r.y()));
}
void triggerShowAddWidgets()
{
emit q->showAddWidgetsInterface(QPointF());
}
bool regionIsEmpty(const QRectF &region, Applet *ignoredApplet=0) const;
void positionPanel(bool force = false);
void positionContainment();
void setLockToolText();
void handleDisappeared(AppletHandle *handle);
void destroyApplet();
/**
* Repositions the Plasma toolbox. Useful to ensure its always in the correct place within the view.
*/
void repositionToolbox();
void appletDestroyed(QObject*);
void appletAnimationComplete(QGraphicsItem *item, Plasma::Animator::Animation anim);
Applet* addApplet(const QString& name, const QVariantList& args = QVariantList(),
const QRectF &geometry = QRectF(-1, -1, -1, -1), uint id = 0,
bool delayedInit = false);
Containment *q;
FormFactor formFactor;
Location location;
Applet::List applets;
QMap<Applet*, AppletHandle*> handles;
int screen;
Toolbox *toolbox;
Containment::Type type;
bool positioning;
};
void Containment::Private::setLockToolText()
{
if (toolbox) {
Icon *icon = dynamic_cast<Plasma::Icon*>(toolbox->tool("lockWidgets"));
if (icon) {
// we know it's an icon becase we made it
icon->setText(q->immutability() != NotImmutable ? i18n("Unlock Widgets") :
i18n("Lock Widgets"));
QSizeF iconSize = icon->sizeFromIconSize(22);
icon->setMinimumSize(iconSize);
icon->setMaximumSize(iconSize);
icon->resize(icon->size());
}
}
}
Containment::StyleOption::StyleOption() Containment::StyleOption::StyleOption()
: QStyleOptionGraphicsItem(), : QStyleOptionGraphicsItem(),
view(0) view(0)
@ -289,61 +187,6 @@ void Containment::saveContainment(KConfigGroup* group) const
group->writeEntry("location", (int)d->location); group->writeEntry("location", (int)d->location);
} }
void Containment::containmentConstraintsUpdated(Plasma::Constraints constraints)
{
if (!isContainment()) {
return;
}
//kDebug() << "got containmentConstraintsUpdated" << constraints << (QObject*)d->toolbox;
if (constraints & Plasma::ImmutableConstraint) {
d->setLockToolText();
// tell the applets too
foreach (Applet *a, d->applets) {
a->constraintsUpdated(ImmutableConstraint);
}
}
if ((constraints & Plasma::SizeConstraint || constraints & Plasma::ScreenConstraint) &&
d->toolbox) {
//The placement assumes that the geometry width/height is no more than the screen
if (d->type == PanelContainment) {
if (formFactor() == Vertical) {
d->toolbox->setOrientation(Qt::Vertical);
d->toolbox->setPos(geometry().width()/2 - d->toolbox->boundingRect().width()/2, geometry().height());
//defaulting to Horizontal right now
} else {
d->toolbox->setOrientation(Qt::Horizontal);
d->toolbox->setPos(geometry().width(), geometry().height()/2 - d->toolbox->boundingRect().height()/2);
}
} else {
d->toolbox->setPos(geometry().right() - qAbs(d->toolbox->boundingRect().width()), 0);
}
d->toolbox->enableTool("addwidgets", immutability() == NotImmutable);
}
if (constraints & Plasma::FormFactorConstraint && d->toolbox) {
if (formFactor() == Vertical) {
d->toolbox->setOrientation(Qt::Vertical);
//defaults to horizontal
} else {
d->toolbox->setOrientation(Qt::Horizontal);
}
}
if (constraints & Plasma::SizeConstraint) {
switch (containmentType()) {
case PanelContainment:
d->positionPanel();
break;
default:
d->positionContainment();
break;
}
}
}
Containment::Type Containment::containmentType() const Containment::Type Containment::containmentType() const
{ {
return d->type; return d->type;
@ -354,7 +197,7 @@ void Containment::setContainmentType(Containment::Type type)
d->type = type; d->type = type;
if (isContainment() && type == DesktopContainment) { if (isContainment() && type == DesktopContainment) {
if (!d->toolbox) { if (!d->toolBox) {
QGraphicsWidget *addWidgetTool = addToolBoxTool("addwidgets", "list-add", i18n("Add Widgets")); QGraphicsWidget *addWidgetTool = addToolBoxTool("addwidgets", "list-add", i18n("Add Widgets"));
connect(addWidgetTool, SIGNAL(clicked()), this, SLOT(triggerShowAddWidgets())); connect(addWidgetTool, SIGNAL(clicked()), this, SLOT(triggerShowAddWidgets()));
@ -376,14 +219,14 @@ void Containment::setContainmentType(Containment::Type type)
} }
} else if (isContainment() && type == PanelContainment) { } else if (isContainment() && type == PanelContainment) {
if (!d->toolbox) { if (!d->toolBox) {
d->createToolbox(); d->createToolBox();
d->toolbox->setSize(22); d->toolBox->setSize(22);
d->toolbox->setIconSize(QSize(16, 16)); d->toolBox->setIconSize(QSize(16, 16));
} }
} else { } else {
delete d->toolbox; delete d->toolBox;
d->toolbox = 0; d->toolBox = 0;
} }
} }
@ -504,18 +347,6 @@ void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
desktopMenu.exec(event->screenPos()); desktopMenu.exec(event->screenPos());
} }
void Containment::Private::destroyApplet()
{
QAction *action = qobject_cast<QAction*>(q->sender());
if (!action) {
return;
}
Applet *applet = qobject_cast<Applet*>(action->data().value<QObject*>());
Animator::self()->animateItem(applet, Animator::DisappearAnimation);
}
void Containment::setFormFactor(FormFactor formFactor) void Containment::setFormFactor(FormFactor formFactor)
{ {
if (d->formFactor == formFactor && layout()) { if (d->formFactor == formFactor && layout()) {
@ -688,37 +519,6 @@ Applet* Containment::addApplet(const QString& name, const QVariantList& args, co
return d->addApplet(name, args, appletGeometry); return d->addApplet(name, args, appletGeometry);
} }
Applet* Containment::Private::addApplet(const QString& name, const QVariantList& args,
const QRectF& appletGeometry, uint id, bool delayInit)
{
if (!delayInit && q->immutability() != NotImmutable) {
kDebug() << "addApplet for" << name << "requested, but we're currently immutable!";
return 0;
}
QGraphicsView *v = q->view();
if (v) {
v->setCursor(Qt::BusyCursor);
}
Applet* applet = Applet::load(name, id, args);
if (v) {
v->unsetCursor();
}
if (!applet) {
kDebug() << "Applet" << name << "could not be loaded.";
applet = new Applet;
}
//kDebug() << applet->name() << "sizehint:" << applet->sizeHint() << "geometry:" << applet->geometry();
connect(applet, SIGNAL(configNeedsSaving()), q, SIGNAL(configNeedsSaving()));
connect(applet, SIGNAL(launchActivated()), q, SIGNAL(launchActivated()));
q->addApplet(applet, appletGeometry.topLeft(), delayInit);
return applet;
}
//pos must be relative to the containment already. use mapfromscene. //pos must be relative to the containment already. use mapfromscene.
//what we're trying to do here for panels is make the applet go to the requested position, //what we're trying to do here for panels is make the applet go to the requested position,
//or somewhere close to it, and get integrated properly into the containment as if it were created //or somewhere close to it, and get integrated properly into the containment as if it were created
@ -781,55 +581,6 @@ void Containment::addApplet(Applet *applet, const QPointF &pos, bool delayInit)
emit appletAdded(applet, pos); emit appletAdded(applet, pos);
} }
bool Containment::Private::regionIsEmpty(const QRectF &region, Applet *ignoredApplet) const
{
foreach (Applet *applet, applets) {
if (applet != ignoredApplet && applet->geometry().intersects(region)) {
return false;
}
}
return true;
}
void Containment::Private::appletDestroyed(QObject* object)
{
// we do a static_cast here since it really isn't an Applet by this
// point anymore since we are in the qobject dtor. we don't actually
// try and do anything with it, we just need the value of the pointer
// so this unsafe looking code is actually just fine.
Applet* applet = static_cast<Plasma::Applet*>(object);
applets.removeAll(applet);
emit q->appletRemoved(applet);
emit q->configNeedsSaving();
}
void Containment::Private::appletAnimationComplete(QGraphicsItem *item, Plasma::Animator::Animation anim)
{
if (anim == Animator::DisappearAnimation) {
QGraphicsItem *parent = item->parentItem();
while (parent) {
if (parent == q) {
Applet *applet = qgraphicsitem_cast<Applet*>(item);
if (applet) {
applet->destroy();
}
break;
}
parent = parent->parentItem();
}
} else if (anim == Animator::AppearAnimation) {
if (q->containmentType() == DesktopContainment &&
item->parentItem() == q &&
qgraphicsitem_cast<Applet*>(item)) {
item->installSceneEventFilter(q);
}
}
}
Applet::List Containment::applets() const Applet::List Containment::applets() const
{ {
return d->applets; return d->applets;
@ -842,9 +593,9 @@ void Containment::setScreen(int screen)
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
// we want to listen to changes in work area if our screen changes // we want to listen to changes in work area if our screen changes
if (d->screen < 0 && screen > -1) { if (d->screen < 0 && screen > -1) {
connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(repositionToolbox())); connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(positionToolbox()));
} else if (screen < 0) { } else if (screen < 0) {
disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(repositionToolbox())); disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(positionToolbox()));
} }
#endif #endif
if (screen > -1 && corona()) { if (screen > -1 && corona()) {
@ -880,180 +631,6 @@ void Containment::setScreen(int screen)
} }
} }
void Containment::Private::positionContainment()
{
Corona *c = q->corona();
if (!c) {
return;
}
QList<Containment*> containments = c->containments();
QMutableListIterator<Containment*> it(containments);
while (it.hasNext()) {
Containment *containment = it.next();
if (containment == q ||
containment->containmentType() == PanelContainment) {
// weed out all containments we don't care about at all
// e.g. Panels and ourself
it.remove();
continue;
}
if (q->collidesWithItem(containment)) {
break;
}
}
if (!it.hasNext()) {
// we made it all the way through the list, we have no
// collisions
return;
}
// we need to find how many screens are to our top and left
// to calculate the proper offsets for the margins.
int width = 0;
int height = 0;
QDesktopWidget *desktop = QApplication::desktop();
int numScreens = desktop->numScreens();
for (int i = 0; i < numScreens; ++i) {
QRect otherScreen = desktop->screenGeometry(i);
if (width < otherScreen.width()) {
width = otherScreen.width();
}
if (height < otherScreen.height()) {
height = otherScreen.height();
}
}
//this magic number (4) is the number of columns to try before going to the next row
width = (width + INTER_CONTAINMENT_MARGIN) * 4;
height += INTER_CONTAINMENT_MARGIN;
// a mildly naive "find the first slot" approach
QRectF r = q->boundingRect();
QPointF topLeft(0, 0);
q->setPos(topLeft);
positioning = true;
while (true) {
it.toFront();
while (it.hasNext()) {
Containment *containment = it.next();
if (q->collidesWithItem(containment)) {
break;
}
QPointF pos = containment->pos();
if (pos.x() <= topLeft.x() && pos.y() <= topLeft.y()) {
// we don't colid with this containment, and it's above
// and to the left of us, so let's not bother checking
// it again if we go through this loop again
it.remove();
}
}
if (!it.hasNext()) {
// success! no collisions!
break;
}
if (topLeft.x() + (r.width() * 2) + INTER_CONTAINMENT_MARGIN > width) {
// we ran out of width room, try another row
topLeft = QPoint(0, topLeft.y() + height);
} else {
topLeft.setX(topLeft.x() + r.width() + INTER_CONTAINMENT_MARGIN);
}
kDebug() << "trying at" << topLeft;
q->setPos(topLeft);
//kDebug() << collidingItems().count() << collidingItems()[0] << (QGraphicsItem*)this;
}
positioning = false;
}
void Containment::Private::positionPanel(bool force)
{
if (!q->scene()) {
kDebug() << "no scene yet";
return;
}
// we position panels in negative coordinates, and stack all horizontal
// and all vertical panels with each other.
const QPointF p = q->pos();
if (!force &&
p.y() + q->size().height() < -INTER_CONTAINMENT_MARGIN &&
q->scene()->collidingItems(q).isEmpty()) {
// already positioned and not running into any other panels
return;
}
//TODO: research how non-Horizontal, non-Vertical (e.g. Planar) panels behave here
bool horiz = q->formFactor() == Plasma::Horizontal;
qreal bottom = horiz ? 0 : VERTICAL_STACKING_OFFSET;
qreal lastHeight = 0;
// this should be ok for small numbers of panels, but we ever end
// up managing hundreds of them, this simplistic alogrithm will
// likely be too slow.
foreach (const Containment* other, q->corona()->containments()) {
if (other == q ||
other->containmentType() != PanelContainment ||
horiz != (other->formFactor() == Plasma::Horizontal)) {
// only line up with panels of the same orientation
continue;
}
if (horiz) {
qreal y = other->pos().y();
if (y < bottom) {
lastHeight = other->size().height();
bottom = y;
}
} else {
qreal width = other->size().width();
qreal x = other->pos().x() + width;
if (x > bottom) {
lastHeight = width;
bottom = x + lastHeight;
}
}
}
kDebug() << "positioning" << (horiz ? "" : "non-") << "horizontal panel; forced?" << force;
// give a space equal to the height again of the last item so there is
// room to grow.
QPointF newPos;
if (horiz) {
bottom -= lastHeight + INTER_CONTAINMENT_MARGIN;
//TODO: fix x position for non-flush-left panels
kDebug() << "moved to" << QPointF(0, bottom - q->size().height());
newPos = QPointF(0, bottom - q->size().height());
} else {
bottom += lastHeight + INTER_CONTAINMENT_MARGIN;
//TODO: fix y position for non-flush-top panels
kDebug() << "moved to" << QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
newPos = QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
}
positioning = true;
if (p != newPos) {
q->setPos(newPos);
emit q->geometryChanged();
}
positioning = false;
}
int Containment::screen() const int Containment::screen() const
{ {
return d->screen; return d->screen;
@ -1243,12 +820,6 @@ bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
return false; return false;
} }
void Containment::Private::handleDisappeared(AppletHandle *handle)
{
handles.remove(handle->applet());
handle->deleteLater();
}
QVariant Containment::itemChange(GraphicsItemChange change, const QVariant &value) QVariant Containment::itemChange(GraphicsItemChange change, const QVariant &value)
{ {
Q_UNUSED(value) Q_UNUSED(value)
@ -1282,48 +853,429 @@ QGraphicsWidget * Containment::addToolBoxTool(const QString& toolName, const QSt
tool->setMaximumSize(iconSize); tool->setMaximumSize(iconSize);
tool->resize(tool->size()); tool->resize(tool->size());
d->createToolbox()->addTool(tool, toolName); d->createToolBox()->addTool(tool, toolName);
return tool; return tool;
} }
void Containment::enableToolBoxTool(const QString &toolname, bool enable) void Containment::enableToolBoxTool(const QString &toolname, bool enable)
{ {
if (d->toolbox) { if (d->toolBox) {
d->toolbox->enableTool(toolname, enable); d->toolBox->enableTool(toolname, enable);
} }
} }
bool Containment::isToolboxToolEnabled(const QString &toolname) const bool Containment::isToolboxToolEnabled(const QString &toolname) const
{ {
if (d->toolbox) { if (d->toolBox) {
return d->toolbox->isToolEnabled(toolname); return d->toolBox->isToolEnabled(toolname);
} }
return false; return false;
} }
void Containment::showToolbox() void Containment::showToolbox()
{ {
if (d->toolbox) { if (d->toolBox) {
d->toolbox->showToolbox(); d->toolBox->showToolbox();
} }
} }
void Containment::hideToolbox() void Containment::hideToolbox()
{ {
if (d->toolbox) { if (d->toolBox) {
d->toolbox->hideToolbox(); d->toolBox->hideToolbox();
} }
} }
void Containment::Private::repositionToolbox()
// Private class implementation
Toolbox* Containment::Private::createToolBox()
{ {
//kDebug() << "reposition" << d->screen << (QObject*)d->toolbox; if (!toolBox) {
if (toolbox) { switch (type) {
positionToolbox(); case PanelContainment:
toolBox = new PanelToolbox(q);
break;
//defaults to DesktopContainment right now
default:
toolBox = new DesktopToolbox(q);
break;
}
positionToolBox();
}
return toolBox;
}
void Containment::Private::positionToolBox()
{
if (!toolBox) {
return;
}
QRectF r;
if (screen < 0) {
r = q->geometry();
} else {
QDesktopWidget *desktop = QApplication::desktop();
r = desktop->availableGeometry(screen);
}
toolBox->setPos(QPointF(r.right(), r.y()));
}
void Containment::Private::triggerShowAddWidgets()
{
emit q->showAddWidgetsInterface(QPointF());
}
void Containment::Private::handleDisappeared(AppletHandle *handle)
{
handles.remove(handle->applet());
handle->deleteLater();
}
void Containment::Private::setLockToolText()
{
if (!toolBox) {
return;
}
Icon *icon = dynamic_cast<Plasma::Icon*>(toolBox->tool("lockWidgets"));
if (icon) {
// we know it's an icon becase we made it
icon->setText(q->immutability() != NotImmutable ? i18n("Unlock Widgets") :
i18n("Lock Widgets"));
QSizeF iconSize = icon->sizeFromIconSize(22);
icon->setMinimumSize(iconSize);
icon->setMaximumSize(iconSize);
icon->resize(icon->size());
} }
} }
void Containment::Private::containmentConstraintsUpdated(Plasma::Constraints constraints)
{
if (!q->isContainment()) {
return;
}
//kDebug() << "got containmentConstraintsUpdated" << constraints << (QObject*)toolBox;
if (constraints & Plasma::ImmutableConstraint) {
setLockToolText();
// tell the applets too
foreach (Applet *a, applets) {
a->constraintsUpdated(ImmutableConstraint);
}
}
if ((constraints & Plasma::SizeConstraint || constraints & Plasma::ScreenConstraint) &&
toolBox) {
//The placement assumes that the geometry width/height is no more than the screen
if (type == PanelContainment) {
if (q->formFactor() == Vertical) {
toolBox->setOrientation(Qt::Vertical);
toolBox->setPos(q->geometry().width()/2 - toolBox->boundingRect().width()/2, q->geometry().height());
//defaulting to Horizontal right now
} else {
toolBox->setOrientation(Qt::Horizontal);
toolBox->setPos(q->geometry().width(), q->geometry().height()/2 - toolBox->boundingRect().height()/2);
}
} else {
toolBox->setPos(q->geometry().right() - qAbs(toolBox->boundingRect().width()), 0);
}
toolBox->enableTool("addwidgets", q->immutability() == NotImmutable);
}
if (constraints & Plasma::FormFactorConstraint && toolBox) {
if (q->formFactor() == Vertical) {
toolBox->setOrientation(Qt::Vertical);
//defaults to horizontal
} else {
toolBox->setOrientation(Qt::Horizontal);
}
}
if (constraints & Plasma::SizeConstraint) {
switch (q->containmentType()) {
case PanelContainment:
positionPanel();
break;
default:
positionContainment();
break;
}
}
}
void Containment::Private::destroyApplet()
{
QAction *action = qobject_cast<QAction*>(q->sender());
if (!action) {
return;
}
Applet *applet = qobject_cast<Applet*>(action->data().value<QObject*>());
Animator::self()->animateItem(applet, Animator::DisappearAnimation);
}
Applet* Containment::Private::addApplet(const QString& name, const QVariantList& args,
const QRectF& appletGeometry, uint id, bool delayInit)
{
if (!delayInit && q->immutability() != NotImmutable) {
kDebug() << "addApplet for" << name << "requested, but we're currently immutable!";
return 0;
}
QGraphicsView *v = q->view();
if (v) {
v->setCursor(Qt::BusyCursor);
}
Applet* applet = Applet::load(name, id, args);
if (v) {
v->unsetCursor();
}
if (!applet) {
kDebug() << "Applet" << name << "could not be loaded.";
applet = new Applet;
}
//kDebug() << applet->name() << "sizehint:" << applet->sizeHint() << "geometry:" << applet->geometry();
connect(applet, SIGNAL(configNeedsSaving()), q, SIGNAL(configNeedsSaving()));
connect(applet, SIGNAL(launchActivated()), q, SIGNAL(launchActivated()));
q->addApplet(applet, appletGeometry.topLeft(), delayInit);
return applet;
}
bool Containment::Private::regionIsEmpty(const QRectF &region, Applet *ignoredApplet) const
{
foreach (Applet *applet, applets) {
if (applet != ignoredApplet && applet->geometry().intersects(region)) {
return false;
}
}
return true;
}
void Containment::Private::appletDestroyed(QObject* object)
{
// we do a static_cast here since it really isn't an Applet by this
// point anymore since we are in the qobject dtor. we don't actually
// try and do anything with it, we just need the value of the pointer
// so this unsafe looking code is actually just fine.
Applet* applet = static_cast<Plasma::Applet*>(object);
applets.removeAll(applet);
emit q->appletRemoved(applet);
emit q->configNeedsSaving();
}
void Containment::Private::appletAnimationComplete(QGraphicsItem *item, Plasma::Animator::Animation anim)
{
if (anim == Animator::DisappearAnimation) {
QGraphicsItem *parent = item->parentItem();
while (parent) {
if (parent == q) {
Applet *applet = qgraphicsitem_cast<Applet*>(item);
if (applet) {
applet->destroy();
}
break;
}
parent = parent->parentItem();
}
} else if (anim == Animator::AppearAnimation) {
if (q->containmentType() == DesktopContainment &&
item->parentItem() == q &&
qgraphicsitem_cast<Applet*>(item)) {
item->installSceneEventFilter(q);
}
}
}
void Containment::Private::positionContainment()
{
Corona *c = q->corona();
if (!c) {
return;
}
QList<Containment*> containments = c->containments();
QMutableListIterator<Containment*> it(containments);
while (it.hasNext()) {
Containment *containment = it.next();
if (containment == q ||
containment->containmentType() == PanelContainment) {
// weed out all containments we don't care about at all
// e.g. Panels and ourself
it.remove();
continue;
}
if (q->collidesWithItem(containment)) {
break;
}
}
if (!it.hasNext()) {
// we made it all the way through the list, we have no
// collisions
return;
}
// we need to find how many screens are to our top and left
// to calculate the proper offsets for the margins.
int width = 0;
int height = 0;
QDesktopWidget *desktop = QApplication::desktop();
int numScreens = desktop->numScreens();
for (int i = 0; i < numScreens; ++i) {
QRect otherScreen = desktop->screenGeometry(i);
if (width < otherScreen.width()) {
width = otherScreen.width();
}
if (height < otherScreen.height()) {
height = otherScreen.height();
}
}
//this magic number (4) is the number of columns to try before going to the next row
width = (width + INTER_CONTAINMENT_MARGIN) * 4;
height += INTER_CONTAINMENT_MARGIN;
// a mildly naive "find the first slot" approach
QRectF r = q->boundingRect();
QPointF topLeft(0, 0);
q->setPos(topLeft);
positioning = true;
while (true) {
it.toFront();
while (it.hasNext()) {
Containment *containment = it.next();
if (q->collidesWithItem(containment)) {
break;
}
QPointF pos = containment->pos();
if (pos.x() <= topLeft.x() && pos.y() <= topLeft.y()) {
// we don't colid with this containment, and it's above
// and to the left of us, so let's not bother checking
// it again if we go through this loop again
it.remove();
}
}
if (!it.hasNext()) {
// success! no collisions!
break;
}
if (topLeft.x() + (r.width() * 2) + INTER_CONTAINMENT_MARGIN > width) {
// we ran out of width room, try another row
topLeft = QPoint(0, topLeft.y() + height);
} else {
topLeft.setX(topLeft.x() + r.width() + INTER_CONTAINMENT_MARGIN);
}
kDebug() << "trying at" << topLeft;
q->setPos(topLeft);
//kDebug() << collidingItems().count() << collidingItems()[0] << (QGraphicsItem*)this;
}
positioning = false;
}
void Containment::Private::positionPanel(bool force)
{
if (!q->scene()) {
kDebug() << "no scene yet";
return;
}
// we position panels in negative coordinates, and stack all horizontal
// and all vertical panels with each other.
const QPointF p = q->pos();
if (!force &&
p.y() + q->size().height() < -INTER_CONTAINMENT_MARGIN &&
q->scene()->collidingItems(q).isEmpty()) {
// already positioned and not running into any other panels
return;
}
//TODO: research how non-Horizontal, non-Vertical (e.g. Planar) panels behave here
bool horiz = q->formFactor() == Plasma::Horizontal;
qreal bottom = horiz ? 0 : VERTICAL_STACKING_OFFSET;
qreal lastHeight = 0;
// this should be ok for small numbers of panels, but we ever end
// up managing hundreds of them, this simplistic alogrithm will
// likely be too slow.
foreach (const Containment* other, q->corona()->containments()) {
if (other == q ||
other->containmentType() != PanelContainment ||
horiz != (other->formFactor() == Plasma::Horizontal)) {
// only line up with panels of the same orientation
continue;
}
if (horiz) {
qreal y = other->pos().y();
if (y < bottom) {
lastHeight = other->size().height();
bottom = y;
}
} else {
qreal width = other->size().width();
qreal x = other->pos().x() + width;
if (x > bottom) {
lastHeight = width;
bottom = x + lastHeight;
}
}
}
kDebug() << "positioning" << (horiz ? "" : "non-") << "horizontal panel; forced?" << force;
// give a space equal to the height again of the last item so there is
// room to grow.
QPointF newPos;
if (horiz) {
bottom -= lastHeight + INTER_CONTAINMENT_MARGIN;
//TODO: fix x position for non-flush-left panels
kDebug() << "moved to" << QPointF(0, bottom - q->size().height());
newPos = QPointF(0, bottom - q->size().height());
} else {
bottom += lastHeight + INTER_CONTAINMENT_MARGIN;
//TODO: fix y position for non-flush-top panels
kDebug() << "moved to" << QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
newPos = QPointF(bottom + q->size().width(), -INTER_CONTAINMENT_MARGIN - q->size().height());
}
positioning = true;
if (p != newPos) {
q->setPos(newPos);
emit q->geometryChanged();
}
positioning = false;
}
} // Plasma namespace } // Plasma namespace
#include "containment.moc" #include "containment.moc"

View File

@ -258,14 +258,6 @@ class PLASMA_EXPORT Containment : public Applet
*/ */
bool isToolboxToolEnabled(const QString &toolName) const; bool isToolboxToolEnabled(const QString &toolName) const;
/**
* @internal
* Called when constraints have been updated on this containment to provide
* constraint services common to all containments. Containments should still
* implement their own constraintsUpdated method
*/
void containmentConstraintsUpdated(Plasma::Constraints constraints);
/** /**
* Open the Plasma toolbox * Open the Plasma toolbox
*/ */
@ -394,7 +386,7 @@ class PLASMA_EXPORT Containment : public Applet
Q_PRIVATE_SLOT(d, void triggerShowAddWidgets()) Q_PRIVATE_SLOT(d, void triggerShowAddWidgets())
Q_PRIVATE_SLOT(d, void handleDisappeared(AppletHandle *handle)) Q_PRIVATE_SLOT(d, void handleDisappeared(AppletHandle *handle))
Q_PRIVATE_SLOT(d, void destroyApplet()) Q_PRIVATE_SLOT(d, void destroyApplet())
Q_PRIVATE_SLOT(d, void repositionToolbox()) Q_PRIVATE_SLOT(d, void positionToolBox())
friend class Applet; friend class Applet;
class Private; class Private;

90
containment_p.h Normal file
View File

@ -0,0 +1,90 @@
/*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2008 by Ménard Alexis <darktears31@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.
*/
#ifndef CONTAINMENT_P_H
#define CONTAINMENT_P_H
static const int INTER_CONTAINMENT_MARGIN = 6;
static const int VERTICAL_STACKING_OFFSET = 10000;
namespace Plasma
{
class Containment;
class Toolbox;
class Containment::Private
{
public:
Private(Containment* c)
: q(c),
formFactor(Planar),
location(Floating),
screen(-1), // no screen
toolBox(0),
type(Containment::NoContainmentType),
positioning(false)
{
}
~Private()
{
qDeleteAll(applets);
applets.clear();
}
Toolbox* createToolBox();
void positionToolBox();
void triggerShowAddWidgets();
/**
* Called when constraints have been updated on this containment to provide
* constraint services common to all containments. Containments should still
* implement their own constraintsUpdated method
*/
void containmentConstraintsUpdated(Plasma::Constraints constraints);
bool regionIsEmpty(const QRectF &region, Applet *ignoredApplet=0) const;
void positionPanel(bool force = false);
void positionContainment();
void setLockToolText();
void handleDisappeared(AppletHandle *handle);
void destroyApplet();
void appletDestroyed(QObject*);
void appletAnimationComplete(QGraphicsItem *item, Plasma::Animator::Animation anim);
Applet* addApplet(const QString& name, const QVariantList& args = QVariantList(),
const QRectF &geometry = QRectF(-1, -1, -1, -1), uint id = 0,
bool delayedInit = false);
Containment *q;
FormFactor formFactor;
Location location;
Applet::List applets;
QMap<Applet*, AppletHandle*> handles;
int screen;
Toolbox *toolBox;
Containment::Type type;
bool positioning;
};
} // Plasma namespace
#endif