someone got confused as to the difference between "the layout that manages my children" and "the layout that manages me". this fixes that and stops crashes in applets that use vbox/hbox

* don't crash when parent=0 is passed in
* don't divid by 0 when we have no children
* have the (fugly) setManagingLayout and unsetManagingLayout and managingLayout methods
* do some memory management so layouts that are thrown around don't get lost in the heap

some unit tests would be nice. hell, a design document on the layout stuff would be nice. i know we're only keeping this around for 4.0, but  ... yeah. ugh.
CCMAIL:panel-devel@kde.org

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=693361
This commit is contained in:
Aaron J. Seigo 2007-07-27 20:00:07 +00:00
parent 293c4b5693
commit a8b7589479
8 changed files with 103 additions and 81 deletions

View File

@ -37,15 +37,16 @@ BoxLayout::BoxLayout(LayoutItem *parent)
: Layout(parent), : Layout(parent),
d(new Private) d(new Private)
{ {
parent->setLayout(this); if (parent) {
parent->setLayout(this);
}
} }
BoxLayout::~BoxLayout() BoxLayout::~BoxLayout()
{ {
foreach (LayoutItem *l, d->childList) { foreach (LayoutItem* item, children()) {
l->resetLayout(); item->unsetManagingLayout(this);
} }
delete d; delete d;
} }
@ -90,7 +91,7 @@ void BoxLayout::insertItem(int index, LayoutItem *l)
return; return;
} }
l->setLayout(this); //l->setLayout(this);
d->childList.insert(index, l); d->childList.insert(index, l);
setGeometry(geometry()); setGeometry(geometry());
} }
@ -101,14 +102,18 @@ void BoxLayout::addItem(LayoutItem *l)
return; return;
} }
l->setLayout(this); l->setManagingLayout(this);
d->childList.append(l); d->childList.append(l);
qDebug("Added Child LayoutItem : %p", l);
setGeometry(geometry()); setGeometry(geometry());
} }
void BoxLayout::removeItem(LayoutItem *l) void BoxLayout::removeItem(LayoutItem *l)
{ {
if (!l) {
return;
}
l->unsetManagingLayout(this);
d->childList.removeAll(l); d->childList.removeAll(l);
setGeometry(geometry()); setGeometry(geometry());
} }

View File

@ -66,12 +66,10 @@ void HBoxLayout::setGeometry(const QRectF& geometry)
QSizeF available = geometry.size() - QSizeF(2 * margin(), 2 * margin()); QSizeF available = geometry.size() - QSizeF(2 * margin(), 2 * margin());
foreach (LayoutItem *l, children()) { foreach (LayoutItem *l, children()) {
kDebug() << "testing layout item " << l << endl;
if (l->expandingDirections() & Qt::Horizontal) { if (l->expandingDirections() & Qt::Horizontal) {
expandingChildren += l; expandingChildren.append(l);
} else { } else {
fixedChildren.append(l);
fixedChildren += l;
} }
} }
@ -81,10 +79,12 @@ void HBoxLayout::setGeometry(const QRectF& geometry)
available -= QSizeF(hint.width() + spacing(), 0.0f); available -= QSizeF(hint.width() + spacing(), 0.0f);
} }
qreal expandWidth = (available.width() - ((expandingChildren.count() - 1) * spacing())) / expandingChildren.count(); qreal expandWidth = 0;
if (expandingChildren.count() > 0) {
expandWidth = (available.height() - ((expandingChildren.count() - 1) * spacing())) / expandingChildren.count();
}
foreach (LayoutItem *l, expandingChildren) { foreach (LayoutItem *l, expandingChildren) {
sizes.insert(indexOf(l), QSizeF(expandWidth, available.height())); sizes.insert(indexOf(l), QSizeF(expandWidth, available.height()));
} }

View File

@ -25,27 +25,35 @@ namespace Plasma
class Layout::Private class Layout::Private
{ {
public: public:
Private() : margin(10.0), spacing(10.0), parent(0) {} Private(LayoutItem* parent)
~Private() {} : margin(12.0),
spacing(6.0),
parent(parent)
{
}
qreal margin; ~Private() {}
qreal spacing;
LayoutItem *parent; qreal margin;
qreal spacing;
LayoutItem *parent;
}; };
Layout::Layout(LayoutItem *parent) Layout::Layout(LayoutItem *parent)
: LayoutItem(), : LayoutItem(),
d(new Private) d(new Private(parent))
{ {
d->parent = parent;
} }
Layout::~Layout() Layout::~Layout()
{ {
delete d; if (parent()) {
parent()->setLayout(0);
}
delete d;
} }
qreal Layout::margin() const qreal Layout::margin() const

View File

@ -17,6 +17,9 @@
*/ */
#include "layoutitem.h" #include "layoutitem.h"
#include <KDebug>
#include "layout.h" #include "layout.h"
namespace Plasma namespace Plasma
@ -26,27 +29,30 @@ class LayoutItem::Private
{ {
public: public:
Private() Private()
: layout(0) : layout(0),
managingLayout(0)
{ {
} }
~Private() {} ~Private() {}
Layout* layout; Layout* layout;
Layout* managingLayout;
}; };
LayoutItem::LayoutItem() LayoutItem::LayoutItem()
: d(new Private) : d(new Private())
{ {
} }
LayoutItem::~LayoutItem() LayoutItem::~LayoutItem()
{ {
if (d->layout) { if (d->managingLayout) {
d->layout->removeItem(this); d->managingLayout->removeItem(this);
} }
delete d->layout;
delete d; delete d;
} }
@ -70,15 +76,11 @@ qreal LayoutItem::widthForHeight(qreal h) const
return 0.0; return 0.0;
} }
void LayoutItem::resetLayout()
{
d->layout = 0;
}
void LayoutItem::setLayout(Layout* layout) void LayoutItem::setLayout(Layout* layout)
{ {
if (d->layout) { if (d->layout && layout) {
d->layout->removeItem(this); kDebug() << k_funcinfo << " already have a layout." << endl;
return;
} }
d->layout = layout; d->layout = layout;
@ -89,4 +91,25 @@ Layout* LayoutItem::layout()
return d->layout; return d->layout;
} }
void LayoutItem::setManagingLayout(Layout* layout)
{
if (d->managingLayout) {
d->managingLayout->removeItem(this);
}
d->managingLayout = layout;
}
void LayoutItem::unsetManagingLayout(Layout* layout)
{
if (d->managingLayout == layout) {
d->managingLayout = 0;
}
}
Layout* LayoutItem::managingLayout()
{
return d->managingLayout;
}
} }

View File

@ -44,7 +44,7 @@ class PLASMA_EXPORT LayoutItem
/** /**
* Constructor. * Constructor.
*/ */
LayoutItem(); explicit LayoutItem();
/** /**
* Virtual Destructor. * Virtual Destructor.
@ -106,28 +106,37 @@ class PLASMA_EXPORT LayoutItem
virtual QSizeF sizeHint() const = 0; virtual QSizeF sizeHint() const = 0;
/** /**
* Resets the layout to 0 and doesn't notify the previous layout. * Sets the layout that will manage children items
* Should only be used by the current layout when relinquishing the item,
* e.g. during layout destruction.
*/
void resetLayout();
/**
* Sets the layout so that the LayoutItem may inform the layout of its
* deletion. Should only be used by the layout it is added to.
*
* If the layout item is currently associated with another layout, it will
* first remove itself from that layout.
* *
* @param layout The Layout that this LayoutItem will be managed by. * @param layout The Layout that this LayoutItem will be managed by.
*/ */
void setLayout(Layout* layout); void setLayout(Layout* layout);
/** /**
* Returns the layout this item is currently associated with. * @return the layout this item is currently associated with.
*/ */
Layout* layout(); Layout* layout();
/**
* Sets the layout that manages this item's geometry
*
* @param layout the layout that manage this item's geometry
**/
void setManagingLayout(Layout* layout);
/**
* Resets the layout that manges this item's geometry if it is the
* currently associated layout
*
* @param layout to unset
**/
void unsetManagingLayout(Layout* layout);
/**
* @return the layout that manages this item's geometry, or 0 if none
**/
Layout* managingLayout();
private: private:
class Private; class Private;
Private *const d; Private *const d;

View File

@ -55,10 +55,11 @@ void VBoxLayout::setGeometry(const QRectF& geometry)
{ {
if (!geometry.isValid() || geometry.isEmpty()) { if (!geometry.isValid() || geometry.isEmpty()) {
kDebug() << "Invalid Geometry " << geometry << endl; kDebug() << "Invalid Geometry " << geometry << endl;
BoxLayout::setGeometry(geometry);
return; return;
} }
kDebug() << this << " Geometry process " << geometry << " for " << children().count() << " childrens"<< endl; kDebug() << this << " Geometry process " << geometry << " for " << children().count() << " children"<< endl;
QList<LayoutItem *> fixedChildren; QList<LayoutItem *> fixedChildren;
QList<LayoutItem *> expandingChildren; QList<LayoutItem *> expandingChildren;
@ -68,9 +69,9 @@ void VBoxLayout::setGeometry(const QRectF& geometry)
foreach (LayoutItem *l, children()) { foreach (LayoutItem *l, children()) {
kDebug() << "testing layout item " << l << endl; kDebug() << "testing layout item " << l << endl;
if (l->expandingDirections() & Qt::Vertical) { if (l->expandingDirections() & Qt::Vertical) {
expandingChildren += l; expandingChildren.append(l);
} else { } else {
fixedChildren += l; fixedChildren.append(l);
} }
} }
@ -80,7 +81,11 @@ void VBoxLayout::setGeometry(const QRectF& geometry)
available -= QSizeF(0.0, hint.height() + spacing()); available -= QSizeF(0.0, hint.height() + spacing());
} }
qreal expandHeight = (available.height() - ((expandingChildren.count() - 1) * spacing())) / expandingChildren.count(); qreal expandHeight = 0;
if (expandingChildren.count() > 0) {
expandHeight = (available.height() - ((expandingChildren.count() - 1) * spacing())) / expandingChildren.count();
}
foreach (LayoutItem *l, expandingChildren) { foreach (LayoutItem *l, expandingChildren) {
sizes.insert(indexOf(l),QSizeF(available.width(), expandHeight)); sizes.insert(indexOf(l),QSizeF(available.width(), expandHeight));

View File

@ -33,8 +33,7 @@ class Widget::Private
{ {
public: public:
Private() Private()
: parent(0), : parent(0)
layout(0)
{ } { }
~Private() { } ~Private() { }
@ -43,7 +42,6 @@ class Widget::Private
QSizeF maximumSize; QSizeF maximumSize;
Widget *parent; Widget *parent;
Layout *layout;
QList<Widget *> childList; QList<Widget *> childList;
}; };
@ -139,9 +137,7 @@ void Widget::setGeometry(const QRectF& geometry)
void Widget::updateGeometry() void Widget::updateGeometry()
{ {
if (layout()) { if (layout()) {
kDebug() << (void *) this << " updating geometry to " << size() << endl; kDebug() << (void *) this << " updating geometry to " << size() << endl;
layout()->setGeometry(geometry()); layout()->setGeometry(geometry());
} }
} }
@ -180,20 +176,6 @@ void Widget::resize(qreal w, qreal h)
resize(QSizeF(w, h)); resize(QSizeF(w, h));
} }
void Widget::setLayout(Layout *l)
{
if(!d->layout) {
d->layout = l;
} else {
kDebug() << "Widget " << this << "already has a layout!" << endl;
}
}
Layout *Widget::layout() const
{
return d->layout;
}
Widget *Widget::parent() const Widget *Widget::parent() const
{ {
return d->parent; return d->parent;

View File

@ -161,16 +161,6 @@ class PLASMA_EXPORT Widget : public QGraphicsItem,
*/ */
void resize(qreal w, qreal h); void resize(qreal w, qreal h);
/**
* Sets the Layout that will manage this Widget's childrens.
*/
void setLayout(Layout *l);
/**
* Returns the Layout associated with this Widget.
*/
Layout *layout() const;
/** /**
* Returns the parent of this Widget. * Returns the parent of this Widget.
*/ */