appletbrowser gets a remove icon and a filter for running applets

svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=746735
This commit is contained in:
Chani Armitage 2007-12-10 01:18:57 +00:00
parent 5db83950c4
commit 950cc1c149
10 changed files with 380 additions and 143 deletions

View File

@ -27,6 +27,7 @@
#include "plasma/corona.h"
#include "plasma/containment.h"
#include "plasma/applet.h"
#include "plasma/appletbrowser/plasmaappletitemmodel_p.h"
#include "plasma/appletbrowser/kcategorizeditemsview_p.h"
@ -48,11 +49,16 @@ public:
}
void initFilters();
//update the itemModel on our running applets
void updateRunningApplets();
QString application;
Plasma::Corona *corona;
Plasma::Containment *containment;
KCategorizedItemsView *appletList;
QMultiHash<QString,Plasma::Applet*> runningApplets;
//extra hash so we can look up the names of deleted applets
QHash<Plasma::Applet*,QString> appletNames;
KConfig config;
KConfigGroup configGroup;
@ -96,6 +102,9 @@ void AppletBrowserWidget::Private::initFilters()
filterModel.addFilter(i18n("Widgets I Have Used Before"),
KCategorizedItemsViewModels::Filter("used", true),
new KIcon("history"));
filterModel.addFilter(i18n("Currently Running Widgets"),
KCategorizedItemsViewModels::Filter("running", true),
new KIcon("history"));
filterModel.addSeparator(i18n("Categories:"));
@ -105,6 +114,16 @@ void AppletBrowserWidget::Private::initFilters()
}
}
void AppletBrowserWidget::Private::updateRunningApplets()
{
QHash<QString,int> appCount;
foreach (QString key, runningApplets.uniqueKeys()) {
appCount[key]=runningApplets.count(key);
}
kDebug() << appCount;
itemModel.setRunningApplets(appCount);
}
AppletBrowserWidget::AppletBrowserWidget(Plasma::Corona * corona, bool showButtons, QWidget * parent, Qt::WindowFlags f)
: QWidget(parent, f),
@ -161,6 +180,38 @@ void AppletBrowserWidget::init()
// Other models
d->appletList->setItemModel(&d->itemModel);
initRunningApplets();
}
void AppletBrowserWidget::initRunningApplets()
{
//get applets from corona, count them, send results to model
kDebug() << d->runningApplets.count();
QHash<QString,int> appCount;
Plasma::Corona *c=d->corona;
if (!c && d->containment) {
c=d->containment->corona();
}
//we've tried our best to get a corona
//we don't want just one containment, we want them all
if (!c) {
kDebug() << "can't happen";
return;
}
QList<Containment*>containments=c->containments();
foreach (Containment * containment,containments) {
connect(containment, SIGNAL(appletAdded(Plasma::Applet*)), this, SLOT(appletAdded(Plasma::Applet*)));
//TODO track containments too?
QList<Applet*>applets=containment->applets();
foreach (Applet *applet,applets) {
d->runningApplets.insert(applet->name(), applet);
d->appletNames.insert(applet, applet->name());
connect(applet, SIGNAL(destroyed(QObject*)), this, SLOT(appletDestroyed(QObject*)));
appCount[applet->name()]++;
}
}
kDebug() << appCount;
d->itemModel.setRunningApplets(appCount);
}
void AppletBrowserWidget::setApplication(const QString& app)
@ -173,6 +224,8 @@ void AppletBrowserWidget::setApplication(const QString& app)
//FIXME: AFAIK this shouldn't be necessary ... but here it is. need to find out what in that
// maze of models and views is screwing up
d->appletList->setItemModel(&d->itemModel);
d->updateRunningApplets();
}
QString AppletBrowserWidget::application()
@ -199,6 +252,37 @@ void AppletBrowserWidget::addApplet()
}
}
void AppletBrowserWidget::appletAdded(Plasma::Applet* applet)
{
QString name = applet->name();
kDebug() << name;
d->runningApplets.insert(name, applet);
d->appletNames.insert(applet, name);
connect(applet, SIGNAL(destroyed(QObject*)), this, SLOT(appletDestroyed(QObject*)));
d->itemModel.setRunningApplets(name, d->runningApplets.count(name));
}
void AppletBrowserWidget::appletDestroyed(QObject* applet)
{
kDebug() << applet;
Plasma::Applet* a = (Plasma::Applet*)applet; //don't care if it's valid, just need the address
QString name = d->appletNames.take(a);
//if !name, was the applet not found or was the name actually ""?
d->runningApplets.remove(name, a);
d->itemModel.setRunningApplets(name, d->runningApplets.count(name));
}
void AppletBrowserWidget::destroyApplets(QString name)
{
foreach (Plasma::Applet* app, d->runningApplets.values(name)) {
//FIXME I have a hard time believing this is safe without QPointer
app->disconnect(this); //don't need to be told it's being destroyed
app->destroy();
d->appletNames.remove(app);
}
d->runningApplets.remove(name);
}
void AppletBrowserWidget::downloadApplets()
{
//TODO: implement

View File

@ -29,6 +29,7 @@ namespace Plasma
class Corona;
class Containment;
class Applet;
class PLASMA_EXPORT AppletBrowserWidget : public QWidget
{
@ -47,6 +48,21 @@ protected Q_SLOTS:
*/
void addApplet();
/**
* Tracks a new running applet
*/
void appletAdded(Plasma::Applet* applet);
/**
* A running applet is no more
*/
void appletDestroyed(QObject* applet);
/**
* Destroy all applets with this name
*/
void destroyApplets(const QString name);
/**
* Launches a download dialog to retrieve new applets from the Internet
*/
@ -54,6 +70,7 @@ protected Q_SLOTS:
private:
void init();
void initRunningApplets();
class Private;
Private * const d;
bool m_showButtons;

View File

@ -56,7 +56,7 @@ void CustomDragTreeView::startDrag ( Qt::DropActions supportedActions )
QRect rect(0, 0, PIX_SIZE, PIX_SIZE);
foreach (QModelIndex index, indexes) {
if (index.column() == 1) continue;
if (index.column() != 0) continue;
KCategorizedItemsViewModels::AbstractItem * item =
m_view->getItemByProxyIndex(index);

View File

@ -55,6 +55,9 @@ KCategorizedItemsView::KCategorizedItemsView(QWidget * parent, Qt::WindowFlags f
itemsView->setItemDelegate(m_delegate = new KCategorizedItemsViewDelegate(this));
itemsView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
connect (m_delegate, SIGNAL(destroyApplets(const QString)),
parent, SLOT(destroyApplets(const QString)));
comboFilters->setItemDelegate(new KCategorizedItemsViewFilterDelegate(this));
itemsView->viewport()->setAttribute(Qt::WA_Hover);
@ -80,6 +83,7 @@ void KCategorizedItemsView::resizeEvent ( QResizeEvent * event ) {
m_viewWidth = itemsView->viewport()->width();
itemsView->setColumnWidth(0, m_delegate->columnWidth(0, m_viewWidth));
itemsView->setColumnWidth(1, m_delegate->columnWidth(1, m_viewWidth));
itemsView->setColumnWidth(2, m_delegate->columnWidth(2, m_viewWidth));
}
void KCategorizedItemsView::setFilterModel(QStandardItemModel * model)

View File

@ -37,7 +37,7 @@
KCategorizedItemsViewDelegate::KCategorizedItemsViewDelegate(QObject * parent)
: QItemDelegate(parent), m_favoriteIcon("bookmark"),
m_favoriteAddIcon("edit-add"), m_favoriteRemoveIcon("edit-delete"),
m_favoriteAddIcon("edit-add"), m_removeIcon("edit-delete"),
m_onFavoriteIconItem(NULL)
{
m_parent = (KCategorizedItemsView *) parent;
@ -47,13 +47,52 @@ void KCategorizedItemsViewDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
KCategorizedItemsViewModels::AbstractItem * item =
getItemByProxyIndex(index);
if (!item) return;
// Preparing needed data for painting
int left = option.rect.left();
int top = option.rect.top();
int width = option.rect.width();
int height = option.rect.height();
bool leftToRight = (painter->layoutDirection() == Qt::LeftToRight);
QColor backgroundColor = (option.state.testFlag(QStyle::State_Selected))?
option.palette.color(QPalette::Highlight):option.palette.color(QPalette::Base);
// Base Background
painter->fillRect(option.rect, QBrush(backgroundColor));
switch (index.column()) {
case 0:
paintColMain(painter, option, item);
break;
case 1:
paintColFav(painter, option, item);
break;
case 2:
paintColRemove(painter, option, item);
break;
default:
kDebug() << "unexpected column";
}
// Dividing line
backgroundColor = option.palette.color(QPalette::Highlight);
backgroundColor.setAlpha(100);
painter->setPen(backgroundColor);
painter->drawLine(left, top + height - 1, left + width, top + height - 1);
}
void KCategorizedItemsViewDelegate::paintColMain(QPainter *painter,
const QStyleOptionViewItem &option, const KCategorizedItemsViewModels::AbstractItem * item) const
{
int left = option.rect.left();
int top = option.rect.top();
int width = option.rect.width();
bool leftToRight = (painter->layoutDirection() == Qt::LeftToRight);
QIcon::Mode iconMode = QIcon::Normal;
QColor backgroundColor = (option.state.testFlag(QStyle::State_Selected))?
@ -61,14 +100,6 @@ void KCategorizedItemsViewDelegate::paint(QPainter *painter,
QColor foregroundColor = (option.state.testFlag(QStyle::State_Selected))?
option.palette.color(QPalette::HighlightedText):option.palette.color(QPalette::Text);
KCategorizedItemsViewModels::AbstractItem * item =
getItemByProxyIndex(index);
if (!item) return;
// Base Background
painter->fillRect(option.rect, QBrush(backgroundColor));
if (index.column() == 0) {
// Painting main column
QStyleOptionViewItem local_option_title(option);
QStyleOptionViewItem local_option_normal(option);
@ -161,13 +192,17 @@ void KCategorizedItemsViewDelegate::paint(QPainter *painter,
}
}
}
}
void KCategorizedItemsViewDelegate::paintColFav(QPainter *painter,
const QStyleOptionViewItem &option, const KCategorizedItemsViewModels::AbstractItem * item) const
{
int left = option.rect.left();
int top = option.rect.top();
int width = option.rect.width();
} else {
// Painting favorite icon column
KCategorizedItemsViewModels::AbstractItem * item =
getItemByProxyIndex(index);
if (! (option.state & QStyle::State_MouseOver) && m_onFavoriteIconItem == item)
m_onFavoriteIconItem = NULL;
@ -182,21 +217,49 @@ void KCategorizedItemsViewDelegate::paint(QPainter *painter,
left + width - FAV_ICON_SIZE - UNIVERSAL_PADDING, top + UNIVERSAL_PADDING,
FAV_ICON_SIZE, FAV_ICON_SIZE, Qt::AlignCenter, iconMode);
const KIcon * icon = (item->isFavorite())? & m_favoriteRemoveIcon : & m_favoriteAddIcon;
const KIcon * icon = (item->isFavorite())? & m_removeIcon : & m_favoriteAddIcon;
if ((option.state & QStyle::State_MouseOver) && (m_onFavoriteIconItem != item))
icon->paint(painter,
left + width - EMBLEM_ICON_SIZE - UNIVERSAL_PADDING, top + UNIVERSAL_PADDING,
EMBLEM_ICON_SIZE, EMBLEM_ICON_SIZE, Qt::AlignCenter, iconMode);
}
// Dividing line
backgroundColor = option.palette.color(QPalette::Highlight);
backgroundColor.setAlpha(100);
painter->setPen(backgroundColor);
painter->drawLine(left, top + height - 1, left + width, top + height - 1);
void KCategorizedItemsViewDelegate::paintColRemove(QPainter *painter,
const QStyleOptionViewItem &option, const KCategorizedItemsViewModels::AbstractItem * item) const
{
// Painting remove icon column
int running = item->running();
if (!running) {
return;
}
int left = option.rect.left();
int top = option.rect.top();
int width = option.rect.width();
QIcon::Mode iconMode = QIcon::Normal;
if (option.state & QStyle::State_MouseOver) {
iconMode = QIcon::Active;
}
m_removeIcon.paint(painter,
left + width - FAV_ICON_SIZE - UNIVERSAL_PADDING, top + UNIVERSAL_PADDING,
FAV_ICON_SIZE, FAV_ICON_SIZE, Qt::AlignCenter, iconMode);
if (running == 1) {
return;
}
//paint number
QColor foregroundColor = (option.state.testFlag(QStyle::State_Selected))?
option.palette.color(QPalette::HighlightedText):option.palette.color(QPalette::Text);
painter->setPen(foregroundColor);
painter->setFont(option.font);
painter->drawText(
left + UNIVERSAL_PADDING, //FIXME might be wrong
top + UNIVERSAL_PADDING + MAIN_ICON_SIZE / 2,
width - 2 * UNIVERSAL_PADDING, MAIN_ICON_SIZE / 2,
Qt::AlignCenter, QString::number(running));
}
bool KCategorizedItemsViewDelegate::editorEvent(QEvent *event,
@ -204,11 +267,17 @@ bool KCategorizedItemsViewDelegate::editorEvent(QEvent *event,
const QStyleOptionViewItem &option,
const QModelIndex &index)
{
if (index.column() == 1 && event->type() == QEvent::MouseButtonPress) {
(m_onFavoriteIconItem = getItemByProxyIndex(index))
->setFavorite(!getItemByProxyIndex(index)->isFavorite());
if (event->type() == QEvent::MouseButtonPress) {
KCategorizedItemsViewModels::AbstractItem * item = getItemByProxyIndex(index);
if (index.column() == 1) {
(m_onFavoriteIconItem = item)
->setFavorite(!item->isFavorite());
return true;
} else if (index.column() == 2 && item->running()) {
item->setRunning(0);
emit destroyApplets(item->name());
return true;
}
}
return QItemDelegate::editorEvent(event, model, option, index);
@ -220,15 +289,14 @@ QSize KCategorizedItemsViewDelegate::sizeHint(const QStyleOptionViewItem &option
Q_UNUSED(option);
//Q_UNUSED(index);
//option.
int width = (index.column() == 0) ? 0 : FAV_ICON_SIZE;
return QSize(width, MAIN_ICON_SIZE + 2 * UNIVERSAL_PADDING);
}
int KCategorizedItemsViewDelegate::columnWidth (int column, int viewWidth) const {
if (column == 1) {
if (column != 0) {
return FAV_ICON_SIZE + 2 * UNIVERSAL_PADDING;
} else return viewWidth - columnWidth(1, viewWidth);
} else return viewWidth - 2 * columnWidth(1, viewWidth);
}

View File

@ -52,17 +52,25 @@ public:
const QStyleOptionViewItem &option,
const QModelIndex &index);
Q_SIGNALS:
void destroyApplets(const QString name);
private:
KCategorizedItemsView * m_parent;
KIcon m_favoriteIcon;
KIcon m_favoriteAddIcon;
KIcon m_favoriteRemoveIcon;
KIcon m_removeIcon;
mutable KCategorizedItemsViewModels::AbstractItem * m_onFavoriteIconItem;
KCategorizedItemsViewModels::AbstractItem * getItemByProxyIndex(const QModelIndex & index) const;
void paintColMain(QPainter *painter,
const QStyleOptionViewItem &option, const KCategorizedItemsViewModels::AbstractItem * item) const;
void paintColFav(QPainter *painter,
const QStyleOptionViewItem &option, const KCategorizedItemsViewModels::AbstractItem * item) const;
void paintColRemove(QPainter *painter,
const QStyleOptionViewItem &option, const KCategorizedItemsViewModels::AbstractItem * item) const;
};
/**

View File

@ -38,6 +38,11 @@ bool AbstractItem::isFavorite() const
return passesFiltering(Filter("favorite", true));
}
int AbstractItem::running() const
{
return 0;
}
bool AbstractItem::matches(const QString & pattern) const
{
return name().contains(pattern, Qt::CaseInsensitive) || description().contains(pattern, Qt::CaseInsensitive);
@ -101,7 +106,7 @@ QStandardItemModel * DefaultItemFilterProxyModel::sourceModel() const
int DefaultItemFilterProxyModel::columnCount(const QModelIndex& index) const
{
Q_UNUSED(index);
return 2;
return 3;
}
QVariant DefaultItemFilterProxyModel::data(const QModelIndex & index, int role) const
@ -234,7 +239,7 @@ int DefaultItemFilterProxyModel::InnerProxyModel::columnCount(
const QModelIndex& index) const
{
Q_UNUSED(index);
return 2;
return 3; //FIXME: a hardcoded magic number that appears in two places CANNOT be good
}
void DefaultItemFilterProxyModel::InnerProxyModel::setSourceModel(

View File

@ -50,6 +50,12 @@ public:
*/
virtual bool isFavorite() const;
/**
* Returns the item's number of running applets
* Default implementation just returns 0
*/
virtual int running() const;
/**
* Returns if the item contains string specified by pattern.
* Default implementation checks whether name or description contain the
@ -61,6 +67,10 @@ public:
* sets the favorite flag for the item
*/
virtual void setFavorite(bool favorite) = 0;
/**
* sets the number of running applets for the item
*/
virtual void setRunning(int count) = 0;
/**
* Returns if the item passes the filter specified

View File

@ -49,6 +49,11 @@ QString PlasmaAppletItem::description() const
return data().toMap()["description"].toString();
}
int PlasmaAppletItem::running() const
{
return data().toMap()["runningCount"].toInt();
}
void PlasmaAppletItem::setFavorite(bool favorite)
{
QMap<QString, QVariant> attrs = data().toMap();
@ -69,6 +74,14 @@ void PlasmaAppletItem::setFavorite(bool favorite)
}
}
void PlasmaAppletItem::setRunning(int count)
{
QMap<QString, QVariant> attrs = data().toMap();
attrs.insert("running", count > 0); //bool for the filter
attrs.insert("runningCount", count);
setData(QVariant(attrs));
}
bool PlasmaAppletItem::passesFiltering(
const KCategorizedItemsViewModels::Filter & filter) const
{
@ -138,6 +151,29 @@ void PlasmaAppletItemModel::populateModel()
}
}
void PlasmaAppletItemModel::setRunningApplets(const QHash<QString, int> apps)
{
//foreach item, find that string and set the count
for (int r=0; r<rowCount(); ++r) {
QStandardItem *i = item(r);
PlasmaAppletItem *p = (PlasmaAppletItem *)i;
if (p) {
p->setRunning(apps.value(p->name()));
}
}
}
void PlasmaAppletItemModel::setRunningApplets(const QString name, int count)
{
for (int r=0; r<rowCount(); ++r) {
QStandardItem *i = item(r);
PlasmaAppletItem *p = (PlasmaAppletItem *)i;
if (p && p->name() == name) {
p->setRunning(count);
}
}
}
QStringList PlasmaAppletItemModel::mimeTypes() const
{
QStringList types;

View File

@ -47,7 +47,10 @@ public:
virtual QString name() const;
QString pluginName() const;
virtual QString description() const;
virtual int running() const;
virtual void setFavorite(bool favorite);
//set how many instances of this applet are running
virtual void setRunning(int count);
virtual bool passesFiltering(
const KCategorizedItemsViewModels::Filter & filter) const;
virtual QVariantList arguments() const;
@ -68,6 +71,8 @@ public:
void setFavorite(QString plugin, bool favorite);
void setApplication(const QString& app);
void setRunningApplets(const QHash<QString, int> apps);
void setRunningApplets(const QString name, int count);
QString& Application();
private: