2015-01-15 17:07:43 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2007, 2008, 2009, 2010 Ivan Cukic <ivan.cukic(at)kde.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser/Library General Public License version 2,
|
|
|
|
* or (at your option) any later version, as published by the Free
|
|
|
|
* Software Foundation
|
|
|
|
*
|
|
|
|
* 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 Lesser/Library General Public License for more details
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser/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 "CustomListView.h"
|
|
|
|
|
|
|
|
#include <KIcon>
|
|
|
|
#include <KDebug>
|
|
|
|
|
|
|
|
namespace Lancelot {
|
|
|
|
|
|
|
|
//> CustomListItem interface
|
|
|
|
CustomListItem::CustomListItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomListItem::~CustomListItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
//<
|
|
|
|
|
|
|
|
//> CustomListItemFactory
|
|
|
|
CustomListItemFactory::CustomListItemFactory()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomListItemFactory::~CustomListItemFactory()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
//<
|
|
|
|
|
|
|
|
//> CustomList
|
|
|
|
class CustomList::Private {
|
|
|
|
public:
|
|
|
|
Private(CustomList * parent = NULL, CustomListItemFactory * f = NULL) //>
|
|
|
|
: q(parent), factory(f), scale(-1), sizeUpdate(false)
|
|
|
|
{
|
|
|
|
margins[Plasma::TopMargin] = 0;
|
|
|
|
margins[Plasma::LeftMargin] = 0;
|
|
|
|
margins[Plasma::RightMargin] = 0;
|
|
|
|
margins[Plasma::BottomMargin] = 0;
|
|
|
|
} //<
|
|
|
|
|
|
|
|
#define returnIfFactoryNotSet if (!factory) return
|
|
|
|
|
|
|
|
QGraphicsWidget * itemForIndex(int position) //>
|
|
|
|
{
|
|
|
|
QGraphicsWidget * item = dynamic_cast < QGraphicsWidget * >
|
|
|
|
(factory->itemForIndex(position));
|
|
|
|
|
|
|
|
if (item) {
|
|
|
|
item->setParentItem(q);
|
|
|
|
}
|
|
|
|
return item;
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void positionItems(int startPosition = 0) //>
|
|
|
|
{
|
|
|
|
returnIfFactoryNotSet;
|
|
|
|
|
|
|
|
if (startPosition < 0 || startPosition > factory->itemCount()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal top(margins[Plasma::TopMargin]);
|
|
|
|
|
|
|
|
if (startPosition != 0) {
|
|
|
|
top = itemForIndex(startPosition - 1)->geometry().bottom();
|
|
|
|
}
|
|
|
|
|
|
|
|
QGraphicsWidget * item;
|
|
|
|
for (int i = startPosition; i < factory->itemCount(); i++) {
|
|
|
|
item = itemForIndex(i);
|
|
|
|
|
|
|
|
int height = (int) (
|
|
|
|
(scale > 0) ?
|
|
|
|
(item->maximumHeight() * scale) :
|
|
|
|
(item->preferredHeight())
|
|
|
|
);
|
|
|
|
|
|
|
|
item->setGeometry(
|
|
|
|
margins[Plasma::LeftMargin], top,
|
|
|
|
viewport.width() - margins[Plasma::LeftMargin]
|
|
|
|
- margins[Plasma::RightMargin],
|
|
|
|
height
|
|
|
|
);
|
|
|
|
top += height;
|
|
|
|
}
|
|
|
|
|
|
|
|
viewportOriginUpdated();
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void updateSizeInfo() //>
|
|
|
|
{
|
|
|
|
QMap < Qt::SizeHint, int > osizes = sizes;
|
|
|
|
|
|
|
|
sizes[Qt::MinimumSize] = 0;
|
|
|
|
sizes[Qt::PreferredSize] = 0;
|
|
|
|
sizes[Qt::MaximumSize] = 0;
|
|
|
|
|
|
|
|
returnIfFactoryNotSet;
|
|
|
|
|
|
|
|
for (int i = 0; i < factory->itemCount(); i++) {
|
|
|
|
sizes[Qt::MinimumSize] +=
|
|
|
|
factory->itemHeight(i, Qt::MinimumSize);
|
|
|
|
sizes[Qt::PreferredSize] +=
|
|
|
|
factory->itemHeight(i, Qt::PreferredSize);
|
|
|
|
sizes[Qt::MaximumSize] +=
|
|
|
|
factory->itemHeight(i, Qt::MaximumSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (q && q->scrollPane() && osizes != sizes) {
|
|
|
|
sizeUpdate = true;
|
|
|
|
q->scrollPane()->scrollableWidgetSizeUpdateNeeded();
|
|
|
|
sizeUpdate = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
q->setPreferredHeight(sizes[Qt::PreferredSize]);
|
|
|
|
q->setMinimumHeight(sizes[Qt::MinimumSize]);
|
|
|
|
q->setMaximumHeight(sizes[Qt::MaximumSize]);
|
|
|
|
q->updateGeometry();
|
|
|
|
|
|
|
|
kDebug() << "Sizes" << sizes[Qt::PreferredSize] << sizes[Qt::MinimumSize] << sizes[Qt::MaximumSize];
|
|
|
|
|
|
|
|
emit q->sizeChanged();
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void viewportOriginUpdated() //>
|
|
|
|
{
|
|
|
|
returnIfFactoryNotSet;
|
|
|
|
|
|
|
|
QTransform transform;
|
|
|
|
for (int i = 0; i < factory->itemCount(); i++) {
|
|
|
|
QGraphicsWidget * item = itemForIndex(i);
|
|
|
|
QRectF itemGeometry = item->geometry();
|
|
|
|
if (viewport.intersects(itemGeometry)) {
|
|
|
|
item->show();
|
|
|
|
transform.reset();
|
|
|
|
if (!viewport.contains(itemGeometry)) {
|
2016-06-01 15:32:43 +00:00
|
|
|
QRectF clip = viewport.intersected(itemGeometry);
|
2015-01-15 17:07:43 +00:00
|
|
|
transform.translate(0, clip.top() -
|
|
|
|
itemGeometry.top());
|
|
|
|
transform.scale(1, clip.height() /
|
|
|
|
itemGeometry.height());
|
|
|
|
item->setOpacity(clip.height() /
|
|
|
|
itemGeometry.height());
|
|
|
|
} else {
|
|
|
|
item->setOpacity(1);
|
|
|
|
}
|
|
|
|
item->setTransform(transform);
|
|
|
|
} else {
|
|
|
|
item->hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} //<
|
|
|
|
|
|
|
|
//> Variable Declarations
|
|
|
|
CustomList * q;
|
|
|
|
CustomListItemFactory * factory;
|
|
|
|
QMap < Qt::SizeHint, int > sizes;
|
|
|
|
QRectF viewport;
|
|
|
|
qreal scale;
|
|
|
|
QMap < Plasma::MarginEdge, qreal > margins;
|
|
|
|
bool sizeUpdate : 1;
|
|
|
|
//<
|
|
|
|
};
|
|
|
|
|
|
|
|
CustomList::CustomList(QGraphicsItem * parent) //>
|
|
|
|
: QGraphicsWidget(parent), d(new Private(this))
|
|
|
|
{
|
|
|
|
} //<
|
|
|
|
|
|
|
|
CustomList::CustomList(CustomListItemFactory * factory, QGraphicsItem * parent) //>
|
|
|
|
: QGraphicsWidget(parent), d(new Private(this))
|
|
|
|
{
|
|
|
|
setItemFactory(factory);
|
|
|
|
} //<
|
|
|
|
|
|
|
|
CustomList::~CustomList() //>
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void CustomList::setItemFactory(CustomListItemFactory * f) //>
|
|
|
|
{
|
|
|
|
// Releasing the old factory
|
|
|
|
if (d->factory) {
|
|
|
|
disconnect(d->factory, NULL, this, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!f) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->factory = f;
|
|
|
|
|
|
|
|
connect(f, SIGNAL(itemInserted(int)),
|
|
|
|
this, SLOT(factoryItemInserted(int)));
|
|
|
|
connect(f, SIGNAL(itemDeleted(int)),
|
|
|
|
this, SLOT(factoryItemDeleted(int)));
|
|
|
|
connect(f, SIGNAL(itemAltered(int)),
|
|
|
|
this, SLOT(factoryItemAltered(int)));
|
|
|
|
connect(f, SIGNAL(updated()),
|
|
|
|
this, SLOT(factoryUpdated()));
|
|
|
|
|
|
|
|
d->updateSizeInfo();
|
|
|
|
} //<
|
|
|
|
|
|
|
|
int CustomList::itemAtPosition(int y) const
|
|
|
|
{
|
|
|
|
QGraphicsWidget * item;
|
|
|
|
for (int i = 0; i < d->factory->itemCount(); i++) {
|
|
|
|
item = d->itemForIndex(i);
|
|
|
|
if (item->geometry().bottom() > y) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomListItemFactory * CustomList::itemFactory() const //>
|
|
|
|
{
|
|
|
|
return d->factory;
|
|
|
|
} //<
|
|
|
|
|
|
|
|
QSizeF CustomList::sizeFor(QSizeF viewportSize) const //>
|
|
|
|
{
|
|
|
|
QSizeF result = viewportSize;
|
|
|
|
if (result.height() < d->sizes[Qt::MinimumSize]) {
|
|
|
|
result.setHeight(d->sizes[Qt::PreferredSize]);
|
|
|
|
} else if (result.height() > d->sizes[Qt::MaximumSize]) {
|
|
|
|
result.setHeight(d->sizes[Qt::MaximumSize]);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void CustomList::viewportChanged(QRectF viewport) //>
|
|
|
|
{
|
|
|
|
if (d->sizeUpdate || d->viewport.size() != viewport.size()) {
|
|
|
|
if (d->sizes[Qt::MinimumSize] > viewport.height()) {
|
|
|
|
d->scale = -1;
|
|
|
|
} else {
|
|
|
|
if (d->sizes[Qt::MaximumSize] < viewport.height()) {
|
|
|
|
d->scale = 1;
|
|
|
|
} else {
|
|
|
|
d->scale = viewport.height() /
|
|
|
|
(qreal) d->sizes[Qt::MaximumSize];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->viewport.setSize(viewport.size());
|
|
|
|
resize(d->viewport.width(), sizeFor(viewport.size()).height());
|
|
|
|
d->positionItems();
|
|
|
|
d->viewportOriginUpdated();
|
|
|
|
}
|
|
|
|
|
|
|
|
d->viewport = viewport;
|
|
|
|
d->viewportOriginUpdated();
|
|
|
|
setPos(- d->viewport.topLeft());
|
|
|
|
|
|
|
|
d->viewport = viewport;
|
|
|
|
} //<
|
|
|
|
|
|
|
|
qreal CustomList::scrollUnit(Qt::Orientation direction) const //>
|
|
|
|
{
|
|
|
|
Q_UNUSED(direction);
|
|
|
|
return 20;
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void CustomList::factoryItemInserted(int position) //>
|
|
|
|
{
|
|
|
|
Q_UNUSED(position);
|
|
|
|
d->updateSizeInfo();
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void CustomList::factoryItemDeleted(int position) //>
|
|
|
|
{
|
|
|
|
Q_UNUSED(position);
|
|
|
|
d->updateSizeInfo();
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void CustomList::factoryItemAltered(int position) //>
|
|
|
|
{
|
|
|
|
Q_UNUSED(position);
|
|
|
|
d->updateSizeInfo();
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void CustomList::factoryUpdated() //>
|
|
|
|
{
|
|
|
|
d->updateSizeInfo();
|
|
|
|
} //<
|
|
|
|
|
|
|
|
void CustomList::setMargin(Plasma::MarginEdge margin, qreal value) //>
|
|
|
|
{
|
|
|
|
d->margins[margin] = value;
|
|
|
|
d->updateSizeInfo();
|
|
|
|
} //<
|
|
|
|
|
|
|
|
qreal CustomList::margin(Plasma::MarginEdge margin) //>
|
|
|
|
{
|
|
|
|
return d->margins[margin];
|
|
|
|
} //<
|
|
|
|
|
|
|
|
//<
|
|
|
|
|
|
|
|
//> CustomListView
|
|
|
|
class CustomListView::Private {
|
|
|
|
public:
|
|
|
|
Private(CustomList * l, CustomListView * parent)
|
|
|
|
: list(l)
|
|
|
|
{
|
|
|
|
parent->setScrollableWidget(list);
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomList * list;
|
|
|
|
};
|
|
|
|
|
|
|
|
CustomListView::CustomListView(QGraphicsItem * parent)
|
|
|
|
: ScrollPane(parent), d(new Private(new CustomList(this), this))
|
|
|
|
{
|
|
|
|
clearFlag(ClipScrollable);
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomListView::CustomListView(CustomListItemFactory * factory,
|
|
|
|
QGraphicsItem * parent)
|
|
|
|
: ScrollPane(parent),
|
|
|
|
d(new Private(new CustomList(factory, this), this))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomListView::~CustomListView()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
CustomList * CustomListView::list() const
|
|
|
|
{
|
|
|
|
return d->list;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSizeF CustomListView::sizeHint(Qt::SizeHint which,
|
|
|
|
const QSizeF & constraint) const
|
|
|
|
{
|
|
|
|
return d->list->sizeHint(which, constraint);
|
|
|
|
}
|
|
|
|
|
|
|
|
//<
|
|
|
|
|
|
|
|
} // namespace Lancelot
|
|
|
|
|
|
|
|
|