diff --git a/plasma/applet.cpp b/plasma/applet.cpp index 00863e68cd..6ed9b2d5ac 100644 --- a/plasma/applet.cpp +++ b/plasma/applet.cpp @@ -1,1404 +1,1404 @@ /* * Copyright 2005 by Aaron Seigo * Copyright 2007 by Riccardo Iaconelli * * 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 "applet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "plasma/configxml.h" #include "plasma/containment.h" #include "plasma/corona.h" #include "plasma/dataenginemanager.h" #include "plasma/package.h" #include "plasma/packages_p.h" #include "plasma/plasma.h" #include "plasma/scripting/appletscript.h" #include "plasma/shadowitem_p.h" #include "plasma/svg.h" #include "plasma/svgpanel.h" #include "plasma/theme.h" #include "plasma/view.h" #include "plasma/layouts/boxlayout.h" #include "plasma/widgets/widget.h" #include "plasma/widgets/lineedit.h" #include "plasma/widgets/pushbutton.h" //#define DYNAMIC_SHADOWS namespace Plasma { class Applet::Private { public: Private(KService::Ptr service, int uniqueID) : appletId(uniqueID), appletDescription(service), package(0), background(0), failureText(0), script(0), configXml(0), shadow(0), cachedBackground(0), mainConfig(0), pendingConstraints(NoConstraint), aspectRatioMode(Qt::KeepAspectRatio), kioskImmutable(false), immutable(false), hasConfigurationInterface(false), failed(false), needsConfig(false), isContainment(false), square(false) { if (appletId == 0) { appletId = nextId(); } if (appletId > s_maxAppletId) { s_maxAppletId = appletId; } } ~Private() { foreach ( const QString& engine, loadedEngines ) { DataEngineManager::self()->unloadDataEngine( engine ); } delete background; delete package; delete configXml; delete shadow; delete cachedBackground; delete mainConfig; } void init(Applet* applet) { // WARNING: do not access config() OR globalConfig() in this method! // that requires a scene, which is not available at this point applet->setAcceptsHoverEvents(true); applet->setZValue(100); if (!appletDescription.isValid()) { applet->setFailedToLaunch(true); return; } QString language = appletDescription.property("X-Plasma-Language").toString(); // we have a scripted plasmoid if (!language.isEmpty()) { // find where the Package is QString path = KStandardDirs::locate("appdata", "plasmoids/" + appletDescription.pluginName() + '/'); if (path.isEmpty()) { applet->setFailedToLaunch(true, i18n("Could not locate the %1 package required for the %2 widget.", appletDescription.pluginName(), appletDescription.name())); } else { // create the package and see if we have something real //kDebug() << "trying for" << path; package = new Package(path, PlasmoidStructure()); if (package->isValid()) { // now we try and set up the script engine. // it will be parented to this applet and so will get // deleted when the applet does script = Plasma::loadScriptEngine(language, applet); if (!script) { delete package; package = 0; applet->setFailedToLaunch(true, i18n("Could not create a %1 ScriptEngine for the %2 widget.", language, appletDescription.name())); } } else { applet->setFailedToLaunch(true, i18n("Could not open the %1 package required for the %2 widget.", appletDescription.pluginName(), appletDescription.name())); delete package; package = 0; } if (package) { setupScriptSupport(applet); } } } applet->setDrawStandardBackground(true); } // put all setup routines for script here. at this point we can assume that // package exists and that we have a script engin void setupScriptSupport(Applet* applet) { Q_ASSERT(package); QString xmlPath = package->filePath("mainconfigxml"); if (!xmlPath.isEmpty()) { QFile file(xmlPath); // FIXME: KConfigSkeleton doesn't play well with KConfigGroup =/ KConfigGroup config = applet->config(); configXml = new ConfigXml(&config, &file); } if (!package->filePath("mainconfigui").isEmpty()) { applet->setHasConfigurationInterface(true); } } QSizeF contentSize(const Applet* q) { if (failureText) { return failureText->geometry().size(); } return q->contentSize(); } static uint nextId() { ++s_maxAppletId; return s_maxAppletId; } QString instanceName() { if (!appletDescription.isValid()) { return QString(); } return appletDescription.service()->library() + QString::number(appletId); } void getBorderSize(int& left , int& top, int &right, int& bottom) { if (background) { - top = background->marginSize(Plasma::Layout::TopMargin); - left = background->marginSize(Plasma::Layout::LeftMargin); - right = background->marginSize(Plasma::Layout::RightMargin); - bottom = background->marginSize(Plasma::Layout::BottomMargin); + top = background->marginSize(Plasma::TopMargin); + left = background->marginSize(Plasma::LeftMargin); + right = background->marginSize(Plasma::RightMargin); + bottom = background->marginSize(Plasma::BottomMargin); } else { top = left = right = bottom = 0; } } void scheduleConstraintsUpdate(Plasma::Constraints c, Applet* applet) { if (pendingConstraints == NoConstraint) { QTimer::singleShot(0, applet, SLOT(flushUpdatedConstraints())); } pendingConstraints |= c; } KConfigGroup* mainConfigGroup(const Applet* q) { if (mainConfig) { return mainConfig; } if (isContainment) { const Containment *asContainment = qobject_cast(const_cast(q)); Q_ASSERT(asContainment); KConfigGroup containmentConfig; //kDebug() << "got a corona, baby?" << (QObject*)asContainment->corona(); if (asContainment->corona()) { containmentConfig = KConfigGroup(asContainment->corona()->config(), "Containments"); } else { containmentConfig = KConfigGroup(KGlobal::config(), "Containments"); } mainConfig = new KConfigGroup(&containmentConfig, QString::number(appletId)); } else { KConfigGroup appletConfig; if (q->containment()) { appletConfig = q->containment()->config(); appletConfig = KConfigGroup(&appletConfig, "Applets"); } else { kWarning() << "requesting config for" << q->name() << "without a containment!"; appletConfig = KConfigGroup(KGlobal::config(), "Applets"); } mainConfig = new KConfigGroup(&appletConfig, QString::number(appletId)); } return mainConfig; } void copyEntries(KConfigGroup *source, KConfigGroup *destination) { foreach (const QString &group, source->groupList()) { KConfigGroup subSource(source, group); KConfigGroup subDest(destination, group); copyEntries(&subSource, &subDest); } QMap entries = source->entryMap(); QMapIterator it(entries); while (it.hasNext()) { it.next(); destination->writeEntry(it.key(), it.value()); } } //TODO: examine the usage of memory here; there's a pretty large // number of members at this point. uint appletId; KPluginInfo appletDescription; Package* package; QList watchedForFocus; QStringList loadedEngines; static uint s_maxAppletId; Plasma::SvgPanel *background; Plasma::LineEdit *failureText; AppletScript *script; ConfigXml* configXml; ShadowItem* shadow; QPixmap* cachedBackground; KConfigGroup *mainConfig; Plasma::Constraints pendingConstraints; Qt::AspectRatioMode aspectRatioMode; bool kioskImmutable : 1; bool immutable : 1; bool hasConfigurationInterface : 1; bool failed : 1; bool needsConfig : 1; bool isContainment : 1; bool square : 1; }; uint Applet::Private::s_maxAppletId = 0; Applet::Applet(QGraphicsItem *parent, const QString& serviceID, uint appletId) : Widget(parent), d(new Private(KService::serviceByStorageId(serviceID), appletId)) { // WARNING: do not access config() OR globalConfig() in this method! // that requires a scene, which is not available at this point d->init(this); } Applet::Applet(QObject* parentObject, const QVariantList& args) : Widget(0,parentObject), d(new Private(KService::serviceByStorageId(args.count() > 0 ? args[0].toString() : QString()), args.count() > 1 ? args[1].toInt() : 0)) { // WARNING: do not access config() OR globalConfig() in this method! // that requires a scene, which is not available at this point d->init(this); // the brain damage seen in the initialization list is due to the // inflexibility of KService::createInstance } Applet::~Applet() { needsFocus(false); delete d; } void Applet::init() { if (d->script && !d->script->init()) { setFailedToLaunch(true); } } uint Applet::id() const { return d->appletId; } void Applet::save(KConfigGroup* group) const { // we call the dptr member directly for locked since isImmutable() // also checks kiosk and parent containers group->writeEntry("locked", d->immutable); group->writeEntry("plugin", pluginName()); //FIXME: for containments, we need to have some special values here w/regards to // screen affinity (e.g. "bottom of screen 0") //kDebug() << pluginName() << "geometry is" << geometry() << "pos is" << pos() << "bounding rect is" << boundingRect(); group->writeEntry("geometry", geometry()); if (transform() == QTransform()) { group->deleteEntry("transform"); } else { QList 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); //group->writeEntry("transform", transformToString(transform())); } KConfigGroup appletConfigGroup(group, "Configuration"); //FIXME: we need a global save state too saveState(&appletConfigGroup); } void Applet::saveState(KConfigGroup* group) const { if (group->config()->name() != config().config()->name()) { // we're being saved to a different file! // let's just copy the current values in our configuration over KConfigGroup c = config(); d->copyEntries(&c, group); } Q_UNUSED(group) } KConfigGroup Applet::config(const QString &group) const { KConfigGroup cg = config(); return KConfigGroup(&cg, group); } KConfigGroup Applet::config() const { if (d->isContainment) { return *(d->mainConfigGroup(this)); } return KConfigGroup(d->mainConfigGroup(this), "Configuration"); } KConfigGroup Applet::globalConfig() const { KConfigGroup globalAppletConfig; const Containment *c = isContainment() ? dynamic_cast(this) : containment(); QString group = isContainment() ? "ContainmentGlobals" : "AppletGlobals"; if (c && c->corona()) { KSharedConfig::Ptr coronaConfig = c->corona()->config(); globalAppletConfig = KConfigGroup(coronaConfig, group); } else { globalAppletConfig = KConfigGroup(KGlobal::config(), group); } return KConfigGroup(&globalAppletConfig, globalName()); } void Applet::destroy() { //kDebug() << "???????????????? DESTROYING APPLET" << name() << " ???????????????????????????"; if (d->configXml) { d->configXml->setDefaults(); } resetConfigurationObject(); deleteLater(); } void Applet::resetConfigurationObject() { d->mainConfigGroup(this)->deleteGroup(); delete d->mainConfig; d->mainConfig = 0; } ConfigXml* Applet::configXml() const { return d->configXml; } DataEngine* Applet::dataEngine(const QString& name) const { int index = d->loadedEngines.indexOf(name); if (index != -1) { return DataEngineManager::self()->dataEngine(name); } DataEngine* engine = DataEngineManager::self()->loadDataEngine(name); if (engine->isValid()) { d->loadedEngines.append(name); } return engine; } const Package* Applet::package() const { return d->package; } void Applet::updateConstraints(Plasma::Constraints constraints) { d->scheduleConstraintsUpdate(constraints, this); } void Applet::constraintsUpdated(Plasma::Constraints constraints) { //NOTE: do NOT put any code in here that reacts to constraints updates // as it will not get called for any applet that reimplements constraintsUpdated // without calling the Applet:: version as well, which it shouldn't need to. // INSTEAD put such code into flushUpdatedConstraints Q_UNUSED(constraints) //kDebug() << constraints << "constraints are FormFactor: " << formFactor() << ", Location: " << location(); } QString Applet::name() const { if (!d->appletDescription.isValid()) { return i18n("Unknown Applet"); } return d->appletDescription.name(); } QString Applet::icon() const { if (!d->appletDescription.isValid()) { return QString(); } return d->appletDescription.icon(); } QString Applet::pluginName() const { if (!d->appletDescription.isValid()) { return QString(); } return d->appletDescription.pluginName(); } bool Applet::shouldConserveResources() const { return Solid::PowerManagement::appShouldConserveResources(); } QString Applet::category() const { if (!d->appletDescription.isValid()) { return i18n("Miscellaneous"); } return d->appletDescription.category(); } QString Applet::category(const KPluginInfo& applet) { return applet.property("X-KDE-PluginInfo-Category").toString(); } QString Applet::category(const QString& appletName) { if (appletName.isEmpty()) { return QString(); } QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(appletName); KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint); if (offers.isEmpty()) { return QString(); } return offers.first()->property("X-KDE-PluginInfo-Category").toString(); } bool Applet::isImmutable() const { return d->immutable || d->kioskImmutable || (containment() && containment()->isImmutable()) || (dynamic_cast( scene() ) && static_cast(scene())->isImmutable()); } bool Applet::isKioskImmutable() const { return d->kioskImmutable; } void Applet::setImmutable(bool immutable) { if (d->immutable == immutable || (immutable && d->kioskImmutable)) { return; } d->immutable = immutable; // TODO: should we tell the applets too? updateConstraints(ImmutableConstraint); } bool Applet::drawStandardBackground() const { return d->background != 0; } void Applet::setDrawStandardBackground(bool drawBackground) { if (drawBackground) { if (!d->background) { d->background = new Plasma::SvgPanel("widgets/background"); updateGeometry(); } } else if (d->background) { delete d->background; d->background = 0; updateGeometry(); } } bool Applet::failedToLaunch() const { return d->failed; } QString visibleFailureText(const QString& reason) { QString text; if (reason.isEmpty()) { text = i18n("This object could not be created."); } else { text = i18n("This object could not be created for the following reason:

%1

", reason); } return text; } void Applet::setFailedToLaunch(bool failed, const QString& reason) { if (d->failed == failed) { if (d->failureText) { d->failureText->setHtml(visibleFailureText(reason)); setGeometry(QRectF(geometry().topLeft(), d->failureText->sizeHint())); } return; } d->failed = failed; prepareGeometryChange(); d->failureText = 0; qDeleteAll(QGraphicsItem::children()); delete layout(); if (failed) { setDrawStandardBackground(true); Layout* failureLayout = new BoxLayout(BoxLayout::TopToBottom, this); failureLayout->setMargin(0); d->failureText = new LineEdit(this); d->failureText->setTextInteractionFlags( Qt::TextSelectableByMouse ); d->failureText->setStyled(false); d->failureText->document()->setTextWidth(200); d->failureText->setHtml(visibleFailureText(reason)); //FIXME: this needs to get the colour from the theme's colour scheme d->failureText->setDefaultTextColor(KStatefulBrush(KColorScheme::Window, KColorScheme::NormalText, Theme::self()->colors()) .brush(QPalette::Normal).color()); failureLayout->addItem(d->failureText); setGeometry(QRectF(geometry().topLeft(), d->failureText->sizeHint())); } update(); } bool Applet::needsConfiguring() const { return d->needsConfig; } void Applet::setNeedsConfiguring(bool needsConfig) { if (d->needsConfig == needsConfig) { return; } d->needsConfig = needsConfig; prepareGeometryChange(); qDeleteAll(QGraphicsItem::children()); delete layout(); if (needsConfig) { setDrawStandardBackground(true); Layout* layout = new BoxLayout(BoxLayout::TopToBottom,this); PushButton* button = new PushButton(this); button->setText(i18n("Configure...")); connect(button, SIGNAL(clicked()), this, SLOT(performSetupConfig())); layout->addItem(button); } } void Applet::performSetupConfig() { qDeleteAll(QGraphicsItem::children()); delete layout(); showConfigurationInterface(); } void Applet::checkImmutability() { d->kioskImmutable = globalConfig().isImmutable() || config().isImmutable() || (containment() && containment()->isKioskImmutable()) || (dynamic_cast(scene()) && static_cast(scene())->isKioskImmutable()); if (d->kioskImmutable) { updateConstraints(ImmutableConstraint); } } void Applet::flushUpdatedConstraints() { if (d->pendingConstraints == NoConstraint) { return; } //kDebug() << "fushing constraints: " << d->pendingConstraints << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; Plasma::Constraints c = d->pendingConstraints; d->pendingConstraints = NoConstraint; Containment* containment = qobject_cast(this); if (c & Plasma::FormFactorConstraint) { FormFactor f = formFactor(); setShadowShown(f == Planar); setDrawStandardBackground(!containment && f != Vertical && f != Horizontal); /** FIXME: what follows was an attempt to constrain the size of applets. it is, however, broken for the following reasons: * it constrains to the size of an icon, when clearly this is not valid for any non-single-icon applet * it is far too pessimistic for horizontal constraints QSizeF newMax; const QSizeF infSize(std::numeric_limits::infinity(), std::numeric_limits::infinity()); if (f == Plasma::Vertical && !(expandingDirections() & Qt::Vertical)) { newMax = QSizeF(maximumContentSize().width(), IconSize(KIconLoader::Panel)); } else if (f == Plasma::Horizontal && !(expandingDirections() & Qt::Horizontal)) { newMax = QSizeF(IconSize(KIconLoader::Panel), maximumContentSize().height()); } else if (maximumContentSize() != infSize) { newMax = infSize; } if (newMax.isValid()) { setMaximumContentSize(newMax); if (newMax.width() < contentSize().width() || newMax.height() < contentSize().height()) { updateGeometry(); } } */ } if (isContainment() && containment) { containment->containmentConstraintsUpdated(c); } constraintsUpdated(c); if (layout()) { layout()->updateGeometry(); } } void Applet::launchActivated() { if (containment()) { containment()->emitLaunchActivated(); } } int Applet::type() const { return Type; } QRectF Applet::boundingRect() const { QRectF rect = QRectF(QPointF(0,0), d->contentSize(this)); int left; int right; int top; int bottom; d->getBorderSize(left,top,right,bottom); //kDebug() << "Background , Border size" << d->background << left << top << right << bottom; return rect.adjusted(-left,-top,right,bottom); } QPainterPath Applet::shape() const { if (isContainment()) { return Plasma::Widget::shape(); } return Plasma::roundedRectangle(boundingRect().adjusted(-2, -2, 2, 2), 10); } QSizeF Applet::sizeHint() const { int left = 0; int right = 0; int top = 0; int bottom = 0; d->getBorderSize(left, top, right, bottom); QSizeF borderSize = QSizeF(left + right, top + bottom); //kDebug() << "Applet content size hint: " << contentSizeHint() << "plus our borders" << left << right << top << bottom; return contentSizeHint() + QSizeF(left + right, top + bottom); } Qt::Orientations Applet::expandingDirections() const { if (d->square) { return 0; } return Widget::expandingDirections(); } QList Applet::contextActions() { kDebug() << "empty context actions"; return QList(); } QColor Applet::color() const { // TODO: add more colors for more categories and // maybe read from config? QString c = category(); int alpha = 200; // Colors taken from Oxygen color palette if (c == "Date and Time") { return QColor(191, 94, 0, alpha); } else if (c == "Environment & Weather") { return QColor(191, 0, 0, alpha); } else if (c == "Examples") { return QColor(204, 0, 154, alpha); } else if (c == "File System") { return QColor(90, 0, 179, alpha); } else if (c == "Graphics") { return QColor(0, 0, 255, alpha); } else if (c == "Language") { return QColor(0, 191, 0, alpha); } else if (c == "Mapping") { return QColor(191, 245, 0, alpha); } else if (c == "Online Services") { return QColor(255, 213, 0, alpha); } else if (c == "System Information") { return QColor(0, 196, 204, alpha); } else if (c == "Windows and Tasks") { return QColor(255, 126, 0, alpha); } else { return QColor(136, 136, 136, alpha); } } void Applet::paintWidget(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(widget) if (d->shadow && d->shadow->shadowedSize() != boundingRect().size()) { //kDebug() << "sizes are " << d->shadow->shadowedSize() << boundingRect().size(); d->shadow->generate(); } painter->save(); if (transform().isRotating()) { painter->setRenderHint(QPainter::SmoothPixmapTransform); painter->setRenderHint(QPainter::Antialiasing); } if (d->background && formFactor() != Plasma::Vertical && formFactor() != Plasma::Horizontal) { //kDebug() << "option rect is" << option->rect; d->background->paint(painter, option->rect); } if (!d->failed && !d->needsConfig) { if (widget && isContainment()) { // note that the widget we get is actually the viewport of the view, not the view itself View* v = qobject_cast(widget->parent()); if (v && !v->drawWallpaper()) { painter->restore(); return; } } //kDebug() << "paint interface of" << (QObject*) this; paintInterface(painter, option, QRect(QPoint(0,0), d->contentSize(this).toSize())); } painter->restore(); } void Applet::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect & contentsRect) { Q_UNUSED(contentsRect) if (d->script) { d->script->paintInterface(painter, option, contentsRect); } else { //kDebug() << "Applet::paintInterface() default impl"; } } FormFactor Applet::formFactor() const { Containment* c = containment(); return c ? c->formFactor() : Plasma::Planar; } Containment* Applet::containment() const { /* * while this is probably "more correct", much of the code in applet assumes containment * returns zero in the case that this is a containment itself. * if (isContainment()) { return dynamic_cast(const_cast(this)); } */ QGraphicsItem *parent = parentItem(); Containment *c = 0; while (parent) { Containment *possibleC = dynamic_cast(parent); if (possibleC && possibleC->isContainment()) { c = possibleC; break; } parent = parent->parentItem(); } return c; } Location Applet::location() const { Containment* c = containment(); if (!c) { return Plasma::Desktop; } return c->location(); } QRectF Applet::contentRect() const { return QRectF(QPointF(0, 0), contentSize()); } QSizeF Applet::contentSize() const { int top, left, right, bottom; d->getBorderSize(left, top, right, bottom); // kDebug() << "Geometry size: " << geometry().size(); // kDebug() << "Borders: " << left << top << right << bottom; return (geometry().size() - QSizeF(left + right, top + bottom)).expandedTo(QSizeF(0, 0)); } void Applet::setContentSize(const QSizeF &size) { int top, left, right, bottom; d->getBorderSize(left, top, right, bottom); resize(size + QSizeF(left + right, top + bottom)); } void Applet::setContentSize(int width, int height) { setContentSize(QSizeF(width, height)); } QSizeF Applet::contentSizeHint() const { QSizeF size; if (layout()) { size = layout()->sizeHint(); } else { size = contentSize(); } QSizeF max = maximumContentSize(); size = size.boundedTo(max); if (d->square) { //kDebug() << "SizeHintIn: " << (QObject*)this << size; switch (formFactor()) { case Plasma::Vertical: if (size.width() > max.height()) { size.setWidth(max.height()); } size.setHeight(size.width()); case Plasma::Horizontal: case Plasma::Planar: case Plasma::MediaCenter: if (size.height() > max.width()) { size.setHeight(max.width()); } size.setWidth(size.height()); default: break; } //kDebug() << "SizeHintOut: " << size; return size; } return size; } void Applet::setMinimumContentSize(const QSizeF &minSize) { int top, left, right, bottom; d->getBorderSize(left, top, right, bottom); setMinimumSize(minSize + QSizeF(left + right, top + bottom)); } void Applet::setMinimumContentSize(int minWidth, int minHeight) { setMinimumContentSize(QSizeF(minWidth, minHeight)); } QSizeF Applet::minimumContentSize() const { int top, left, right, bottom; d->getBorderSize(left, top, right, bottom); return minimumSize() - QSizeF(left + right, top + bottom); } void Applet::setMaximumContentSize(const QSizeF &maxSize) { int top, left, right, bottom; d->getBorderSize(left, top, right, bottom); setMaximumSize(maxSize + QSizeF(left + right, top + bottom)); } void Applet::setMaximumContentSize(int maxWidth, int maxHeight) { setMaximumContentSize(QSizeF(maxWidth, maxHeight)); } QSizeF Applet::maximumContentSize() const { int top, left, right, bottom; d->getBorderSize(left, top, right, bottom); return maximumSize() - QSizeF(left + right, top + bottom); } Qt::AspectRatioMode Applet::aspectRatioMode() const { return d->aspectRatioMode; } void Applet::setAspectRatioMode(Qt::AspectRatioMode mode) { d->aspectRatioMode = mode; } bool Applet::remainSquare() const { return d->square; } void Applet::setRemainSquare(bool square) { d->square = square; } QString Applet::globalName() const { if (!d->appletDescription.isValid()) { return QString(); } return d->appletDescription.service()->library(); } QString Applet::instanceName() const { return d->instanceName(); } void Applet::watchForFocus(QObject *widget, bool watch) { if ( !widget ) { return; } int index = d->watchedForFocus.indexOf(widget); if ( watch ) { if ( index == -1 ) { d->watchedForFocus.append( widget ); widget->installEventFilter( this ); } } else if ( index != -1 ) { d->watchedForFocus.removeAt( index ); widget->removeEventFilter( this ); } } void Applet::needsFocus(bool focus) { if (focus == QGraphicsItem::hasFocus()) { return; } emit requestFocus(focus); } bool Applet::hasConfigurationInterface() { return d->hasConfigurationInterface; } void Applet::setHasConfigurationInterface(bool hasInterface) { d->hasConfigurationInterface = hasInterface; } bool Applet::eventFilter( QObject *o, QEvent * e ) { if ( !d->watchedForFocus.contains( o ) ) { if ( e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::FocusIn ) { needsFocus( true ); } else if ( e->type() == QEvent::FocusOut ) { needsFocus( false ); } } return QObject::eventFilter(o, e); } void Applet::showConfigurationInterface() { if (d->package && d->configXml) { QString uiFile = d->package->filePath("mainconfigui"); if (uiFile.isEmpty()) { return; } KConfigDialog *dialog = new KConfigDialog(0, "", d->configXml); dialog->setWindowTitle(i18n("%1 Settings", name())); dialog->setAttribute(Qt::WA_DeleteOnClose, true); QUiLoader loader; QFile f(uiFile); if (!f.open(QIODevice::ReadOnly)) { delete dialog; return; } QWidget *w = loader.load(&f); f.close(); dialog->addPage(w, i18n("Settings"), icon(), i18n("%1 Settings", name())); dialog->show(); } } KPluginInfo::List Applet::knownApplets(const QString &category, const QString &parentApp) { QString constraint; if (parentApp.isEmpty()) { constraint.append("not exist [X-KDE-ParentApp]"); } else { constraint.append("[X-KDE-ParentApp] == '").append(parentApp).append("'"); } if (!category.isEmpty()) { if (!constraint.isEmpty()) { constraint.append(" and "); } constraint.append("[X-KDE-PluginInfo-Category] == '").append(category).append("'"); if (category == "Miscellaneous") { constraint.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')"); } } KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint); //kDebug() << "Applet::knownApplets constraint was '" << constraint << "' which got us " << offers.count() << " matches"; return KPluginInfo::fromServices(offers); } KPluginInfo::List Applet::knownAppletsForMimetype(const QString &mimetype) { QString constraint = QString("'%1' in MimeTypes").arg(mimetype); //kDebug() << "knownAppletsForMimetype with" << mimetype << constraint; KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint); return KPluginInfo::fromServices(offers); } QStringList Applet::knownCategories(const QString &parentApp, bool visibleOnly) { QString constraint = "exist [X-KDE-PluginInfo-Category]"; if (parentApp.isEmpty()) { constraint.append(" and not exist [X-KDE-ParentApp]"); } else { constraint.append(" and [X-KDE-ParentApp] == '").append(parentApp).append("'"); } KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint); QStringList categories; foreach (const KService::Ptr applet, offers) { QString appletCategory = applet->property("X-KDE-PluginInfo-Category").toString(); if (visibleOnly && applet->noDisplay()) { // we don't want to show the hidden category continue; } //kDebug() << " and we have " << appletCategory; if (appletCategory.isEmpty()) { if (!categories.contains(i18n("Miscellaneous"))) { categories << i18n("Miscellaneous"); } } else if (!categories.contains(appletCategory)) { categories << appletCategory; } } categories.sort(); return categories; } Applet* Applet::loadApplet(const QString& appletName, uint appletId, const QVariantList& args) { if (appletName.isEmpty()) { return 0; } QString constraint = QString("[X-KDE-PluginInfo-Name] == '%1'").arg(appletName); KService::List offers = KServiceTypeTrader::self()->query("Plasma/Applet", constraint); if (offers.isEmpty()) { //TODO: what would be -really- cool is offer to try and download the applet // from the network at this point kDebug() << "Applet::loadApplet: offers is empty for \"" << appletName << "\""; return 0; } /* else if (offers.count() > 1) { kDebug() << "hey! we got more than one! let's blindly take the first one"; } */ KService::Ptr offer = offers.first(); if (appletId == 0) { appletId = Private::nextId(); } if (!offer->property("X-Plasma-Language").toString().isEmpty()) { kDebug() << "we have a script in the language of" << offer->property("X-Plasma-Language").toString(); Applet *applet = new Applet(0, offer->storageId(), appletId); return applet; } QVariantList allArgs; allArgs << offer->storageId() << appletId << args; QString error; Applet* applet = offer->createInstance(0, allArgs, &error); if (!applet) { kDebug() << "Couldn't load applet \"" << appletName << "\"! reason given: " << error; } return applet; } Applet* Applet::loadApplet(const KPluginInfo& info, uint appletId, const QVariantList& args) { if (!info.isValid()) { return 0; } return loadApplet(info.pluginName(), appletId, args); } void Applet::setShadowShown(bool shown) { //There are various problems with shadows right now: // //1) shadows can be seen through translucent areas, which is probably technically correct ubt //looks odd //2) the shape of the item odesn't conform to the shape of the standard background, e.g. with //rounded corners #ifdef DYNAMIC_SHADOWS if (shown) { if (d->shadow) { d->shadow->setVisible(true); } else { d->shadow = new ShadowItem(this); if (scene()) { scene()->addItem(d->shadow); d->shadow->show(); } } } else { delete d->shadow; d->shadow = 0; } #else Q_UNUSED(shown); #endif } bool Applet::isShadowShown() const { return d->shadow && d->shadow->isVisible(); } QVariant Applet::itemChange(GraphicsItemChange change, const QVariant &value) { switch (change) { case ItemPositionChange: if (d->shadow) { d->shadow->adjustPosition(); } break; case ItemSceneChange: { QGraphicsScene *newScene = qvariant_cast(value); if (newScene) { // checking immutability requires having a working config object // Applet relies on having a Corona scene to be able to get the // correct config. so we have to wait until we have the scene, // otherwise we trigger premature creation of the config objects QTimer::singleShot(0, this, SLOT(checkImmutability())); } if (d->shadow) { if (d->shadow->scene()) { d->shadow->scene()->removeItem(d->shadow); } if (newScene) { newScene->addItem(d->shadow); d->shadow->generate(); d->shadow->adjustPosition(); d->shadow->show(); } } } break; case ItemVisibleChange: if (d->shadow) { d->shadow->setVisible(isVisible()); } break; default: break; }; return Widget::itemChange(change, value); } void Applet::setGeometry(const QRectF& geometry) { Plasma::Constraints updatedConstraints(0); if (geometry.size().width() > 0 && geometry.size().height() > 0 && size() != geometry.size()) { prepareGeometryChange(); qreal width = qBound(minimumSize().width(), geometry.size().width(), maximumSize().width()); qreal height = qBound(minimumSize().height(), geometry.size().height(), maximumSize().height()); setSize(QSizeF(width, height)); if (layout()) { layout()->setGeometry(QRectF(QPoint(0, 0), contentSize())); } if (managingLayout()) { managingLayout()->invalidate(); } if (d->background) { d->background->resize(size()); } updatedConstraints |= Plasma::SizeConstraint; } if (geometry.topLeft() != pos()) { setPos(geometry.topLeft()); updatedConstraints |= Plasma::LocationConstraint; } if (updatedConstraints) { updateConstraints(updatedConstraints); emit geometryChanged(); update(); } } void Applet::setIsContainment(bool isContainment) { d->isContainment = isContainment; } bool Applet::isContainment() const { return d->isContainment; } } // Plasma namespace #include "applet.moc" diff --git a/plasma/layouts/layout.cpp b/plasma/layouts/layout.cpp index 5d27937d39..919b86ab25 100644 --- a/plasma/layouts/layout.cpp +++ b/plasma/layouts/layout.cpp @@ -1,235 +1,235 @@ /* * Copyright 2007 by Matias Valdenegro T. * * 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 "layout.h" #include #include #include #include #include #include "widgets/widget.h" #include "layouts/layoutanimator.h" namespace Plasma { class Layout::Private { public: Private(LayoutItem* p) : leftMargin(12.0), rightMargin(12.0), topMargin(12.0), bottomMargin(12.0), spacing(6.0), parent(p), animator(0), relayouting(false) { } ~Private() {} qreal leftMargin; qreal rightMargin; qreal topMargin; qreal bottomMargin; qreal spacing; LayoutItem *parent; LayoutAnimator *animator; bool relayouting; QRectF geometry; }; Layout::Layout(LayoutItem *parent) : LayoutItem(), d(new Private(parent)) { if (parent) { parent->setLayout(this); } } void Layout::setParent(LayoutItem *parent) { d->parent = parent; } Layout::~Layout() { if (parent()) { parent()->setLayout(0); } delete d; } bool Layout::isEmpty() const { return count() == 0; } void Layout::updateGeometry() { if (d->relayouting) { return; } d->relayouting = true; relayout(); d->relayouting = false; } QRectF Layout::geometry() const { return d->geometry; } void Layout::setGeometry(const QRectF &geometry) { if (!geometry.isValid() || geometry == d->geometry) { return; } d->geometry = geometry; invalidate(); } void Layout::invalidate() { if (d->relayouting) { return; } d->relayouting = true; // find and update the top level layout Layout *layout = this; Layout *parentLayout = 0; do { parentLayout = dynamic_cast(layout->parent()); if (parentLayout) { if (parentLayout->d->relayouting) { break; } layout = parentLayout; } } while (parentLayout); layout->relayout(); d->relayouting = false; } LayoutAnimator* Layout::animator() const { return d->animator; } void Layout::setAnimator(LayoutAnimator *animator) { d->animator = animator; } -qreal Layout::margin(MarginEdge edge) const +qreal Layout::margin(Plasma::MarginEdge edge) const { switch (edge) { case LeftMargin: return d->leftMargin; break; case RightMargin: return d->rightMargin; break; case TopMargin: return d->topMargin; break; case BottomMargin: return d->bottomMargin; break; } return 0; } -void Layout::setMargin(MarginEdge edge, qreal m) +void Layout::setMargin(Plasma::MarginEdge edge, qreal m) { switch (edge) { case LeftMargin: d->leftMargin = m; break; case RightMargin: d->rightMargin = m; break; case TopMargin: d->topMargin = m; break; case BottomMargin: d->bottomMargin = m; break; } } void Layout::setMargin(qreal m) { d->leftMargin = m; d->rightMargin = m; d->topMargin = m; d->bottomMargin = m; } qreal Layout::spacing() const { return d->spacing; } void Layout::setSpacing(qreal s) { d->spacing = s; } LayoutItem *Layout::parent() const { return d->parent; } QSizeF Layout::minimumSize() const { return QSizeF(0,0); } QSizeF Layout::maximumSize() const { return QSizeF(std::numeric_limits::infinity(),std::numeric_limits::infinity()); } void Layout::startAnimation() { if (animator() && animator()->timeLine()) { if (animator()->timeLine()->state() == QTimeLine::NotRunning) { animator()->timeLine()->setCurrentTime(0); animator()->timeLine()->start(); } } } } diff --git a/plasma/layouts/layout.h b/plasma/layouts/layout.h index 4ba44ab50b..9a39083eb1 100644 --- a/plasma/layouts/layout.h +++ b/plasma/layouts/layout.h @@ -1,195 +1,194 @@ /* * Copyright 2007 by Matias Valdenegro T. * * 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 __LAYOUT__ #define __LAYOUT__ #include #include #include #include +#include namespace Plasma { class LayoutAnimator; /** * Base class for Plasma Layout managers * * @author Matias Valdenegro T. * * All layout managers must implement this class. Normal users should use the specific layouts, * like Plasma::VBoxLayout, Plasma::HBoxLayout and Plasma::GridLayout. */ class PLASMA_EXPORT Layout : public LayoutItem { public: - enum MarginEdge { TopMargin, BottomMargin, LeftMargin, RightMargin }; - /** * Constructor. */ explicit Layout(LayoutItem *parent); /** * Virtual Destructor. */ virtual ~Layout(); /** * Returns the margin of this Layout. */ - qreal margin(MarginEdge edge) const; + qreal margin(Plasma::MarginEdge edge) const; /** * Sets the margin of this Layout. */ - void setMargin(MarginEdge edge, qreal m); + void setMargin(Plasma::MarginEdge edge, qreal m); /** * Sets all the margins of this Layout. */ void setMargin(qreal m); /** * Returns the spacing between Layout elements of this Layout. */ qreal spacing() const; /** * Sets the spacing of this Layout. */ void setSpacing(qreal s); /** * Returns the parent of this Layout. */ LayoutItem *parent() const; /** * Sets the parent of this layout. */ void setParent(LayoutItem *parent); /** * Returns the number of elements of this Layout. */ virtual int count() const = 0; /** * Returns true if this Layout contains no elements, false otherwise. */ bool isEmpty() const; /** * Adds a Item to this Layout. * @param l Pointer to the Item to be added. */ virtual void addItem(LayoutItem *l) = 0; /** * Removes a Item from this Layout. * @param l Pointer to the Item to be removed. */ virtual void removeItem(LayoutItem *l) = 0; /** * Returns the index of a Item in this Layout. * @param l Pointer to an Item to be queryed. */ virtual int indexOf(LayoutItem *l) const = 0; /** * Returns a Pointer to an Item in this Layout. * @param i Index of the desired Item. */ virtual LayoutItem *itemAt(int i) const = 0; /** * Takes the Pointer of an Item in this Layout. * @param i Index of the desired Item. */ virtual LayoutItem *takeAt(int i) = 0; /** * Returns the object controlling animation of changes * in this layout or 0 if no animator has been set. */ virtual LayoutAnimator* animator() const; /** * Sets the object controlling animation of changes in this * layout. */ virtual void setAnimator( LayoutAnimator* animator ); /** * Returns the current geometry for this layout */ virtual QRectF geometry() const; /** * Changes the geometry of this layout */ void setGeometry(const QRectF &geometry); /** Triggers an update of the layout. */ void updateGeometry(); /** * Returns the minimum size of this layout. * The default implementation allows unlimited resizing. */ virtual QSizeF minimumSize() const; /** * Returns the maximum size of this layout. The default * implementation allows unlimited resizing. */ virtual QSizeF maximumSize() const; /** TODO Document me */ void invalidate(); protected: /** * Triggers a layout, usually after a change in geometry */ virtual void relayout() = 0; /** * Starts a layout animation. Subclasses may call this * at the end of their relayout() implementation to * start the timeline associated with the layout's animator() * if there is one. If an animation is already in progress then * the timeline is reset to 0ms and the animation continues. */ void startAnimation(); private: class Private; Private *const d; }; } #endif /* __LAYOUT__ */ diff --git a/plasma/plasma.h b/plasma/plasma.h index c90498edbe..8d66fca150 100644 --- a/plasma/plasma.h +++ b/plasma/plasma.h @@ -1,175 +1,181 @@ /* * Copyright 2005 by Aaron Seigo * * 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 PLASMA_DEFS_H #define PLASMA_DEFS_H #include #include #include /** * Namespace for everything in libplasma */ namespace Plasma { /** * The Constraint enumeration lists the various constraints that Plasma * objects have managed for them and which they may wish to react to, * for instance in Applet::constraintsUpdated */ enum Constraint { NoConstraint = 0, FormFactorConstraint = 1 /** The FormFactor for an object */, LocationConstraint = 2 /** The Location of an object */, ScreenConstraint = 4 /** Which screen an object is on */, SizeConstraint = 8 /** the size of the applet was changed */, ImmutableConstraint = 16 /** the immutability (locked) nature of the applet changed */, StartupCompletedConstraint = 32 /** application startup has completed */, AllConstraints = FormFactorConstraint | LocationConstraint | ScreenConstraint | SizeConstraint | ImmutableConstraint }; Q_DECLARE_FLAGS(Constraints, Constraint) /** * The FormFactor enumeration describes how a Plasma::Applet should arrange * itself. The value is derived from the container managing the Applet * (e.g. in Plasma, a Corona on the desktop or on a panel). **/ enum FormFactor { Planar = 0 /**< The applet lives in a plane and has two degrees of freedom to grow. Optimize for desktop, laptop or tablet usage: a high resolution screen 1-3 feet distant from the viewer. */, MediaCenter /**< As with Planar, the applet lives in a plane but the interface should be optimized for medium-to-high resolution screens that are 5-15 feet distant from the viewer. Sometimes referred to as a "ten foot interface".*/, Horizontal /**< The applet is constrained vertically, but can expand horizontally. */, Vertical /**< The applet is constrained horizontally, but can expand vertically. */ }; /** * The Direction enumeration describes in which direction, relative to the * Applet (and its managing container), popup menus, expanders, balloons, * message boxes, arrows and other such visually associated widgets should * appear in. This is usually the oposite of the Location. **/ enum Direction { Down = 0 /**< Display downards */ , Up /**< Display upwards */, Left /**< Display to the left */, Right /**< Display to the right */ }; /** * The Location enumeration describes where on screen an element, such as an * Applet or its managing container, is positioned on the screen. **/ enum Location { Floating = 0 /**< Free floating. Neither geometry or z-ordering is described precisely by this value. */, Desktop /**< On the planar desktop layer, extending across the full screen from edge to edge */, FullScreen /**< Full screen */, TopEdge /**< Along the top of the screen*/, BottomEdge /**< Along the bottom of the screen*/, LeftEdge /**< Along the left side of the screen */, RightEdge /**< Along the right side of the screen */ }; /** * The position enumeration * **/ enum Position { LeftPositioned /**< Positioned left */, RightPositioned /**< Positioned right */, TopPositioned /**< Positioned top */, BottomPositioned /**< Positioned bottom */, CenterPositioned /**< Positioned in the center */ }; /** * Flip enumeration */ enum FlipDirection { NoFlip = 0 /**< Do not flip */, HorizontalFlip = 1 /**< Flip horizontally */, VerticalFlip = 2 /**< Flip vertically */ }; Q_DECLARE_FLAGS(Flip, FlipDirection) /** * Zoom levels that Plasma is aware of... **/ enum ZoomLevel { DesktopZoom = 0 /**< Normal desktop usage, plasmoids are painted normally and have full interaction */, GroupZoom /**< Plasmoids are shown as icons in visual groups; drag and drop and limited context menu interaction only */ , OverviewZoom /**< Groups become icons themselves */ }; /** * Possible timing alignments **/ enum IntervalAlignment { NoAlignment = 0, AlignToMinute, AlignToHour }; enum ItemTypes { AppletType = QGraphicsItem::UserType + 1, LineEditType = QGraphicsItem::UserType + 2 }; /** * The ComonentType enumeration refers to the various types of components, * or plugins, supported by plasma. */ enum ComponentType { AppletComponent = 1 /**< Plasma::Applet based plugins **/, DataEngineComponent = 2 /**< Plasma::DataEngine based plugins **/, RunnerComponent = 4 /**< Plasma::AbstractRunner based plugsin **/, AnimatorComponent = 8 /**< Plasma::Animator based plugins **/, ContainmentComponent = 16 /**< Plasma::Containment based plugins **/ }; Q_DECLARE_FLAGS(ComponentTypes, ComponentType) +enum MarginEdge { TopMargin = 0, + BottomMargin, + LeftMargin, + RightMargin + }; + /** * @return the scaling factor (0..1) for a ZoomLevel **/ PLASMA_EXPORT qreal scalingFactor(ZoomLevel level); /** * Converts a location to a direction. Handy for figuring out which way to send a popup based on * location or to point arrows and other directional items. * * @param location the location of the container the element will appear in * @reutrn the visual direction of the element should be oriented in **/ PLASMA_EXPORT Direction locationToDirection(Location location); /** * Returns a nicely rounded rectanglular path for painting. */ PLASMA_EXPORT QPainterPath roundedRectangle(const QRectF& rect, qreal radius); } // Plasma namespace Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::Constraints) Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::Flip) Q_DECLARE_OPERATORS_FOR_FLAGS(Plasma::ComponentTypes) #endif // multiple inclusion guard diff --git a/plasma/svgpanel.cpp b/plasma/svgpanel.cpp index 09b3e4d869..704bc84491 100644 --- a/plasma/svgpanel.cpp +++ b/plasma/svgpanel.cpp @@ -1,339 +1,339 @@ /* * Copyright 2008 by Aaron Seigo * Copyright 2008 Marco Martin * * 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 "svgpanel.h" #include #include #include namespace Plasma { class SvgPanel::Private { public: Private() : bFlags(DrawTop|DrawBottom|DrawLeft|DrawRight|ContentAtOrigin), cachedBackground(0) { } ~Private() { delete cachedBackground; } BorderFlags bFlags; QPixmap *cachedBackground; Svg *background; QSizeF panelSize; //measures int topHeight; int leftWidth; int rightWidth; int bottomHeight; //size of the svg where the size of the "center" //element is contentWidth x contentHeight bool noBorderPadding : 1; bool stretchBorders : 1; }; SvgPanel::SvgPanel(const QString& imagePath, QObject* parent) : QObject(parent), d(new Private) { d->background = new Svg(imagePath, this); connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(updateSizes())); updateSizes(); d->panelSize = d->background->size(); } SvgPanel::~SvgPanel() { delete d; } void SvgPanel::setFile(const QString& imagePath) { if (imagePath == d->background->file()) { return; } delete d->cachedBackground; d->cachedBackground = 0; d->background->setFile(imagePath); updateSizes(); } QString SvgPanel::file() const { return d->background->file(); } void SvgPanel::setBorderFlags(const BorderFlags flags) { if (flags == d->bFlags) { return; } delete d->cachedBackground; d->cachedBackground = 0; d->bFlags = flags; updateSizes(); } SvgPanel::BorderFlags SvgPanel::borderFlags() const { return d->bFlags; } void SvgPanel::resize(const QSizeF& size) { if (!size.isValid() || size.width() < 1 || size.height() < 1 || size == d->panelSize) { return; } delete d->cachedBackground; d->cachedBackground = 0; d->panelSize = size; updateSizes(); } -qreal SvgPanel::marginSize(const Plasma::Layout::MarginEdge edge) const +qreal SvgPanel::marginSize(const Plasma::MarginEdge edge) const { if (d->noBorderPadding) { return .0; } switch (edge) { - case Plasma::Layout::TopMargin: + case Plasma::TopMargin: return d->topHeight; break; - case Plasma::Layout::LeftMargin: + case Plasma::LeftMargin: return d->leftWidth; break; - case Plasma::Layout::RightMargin: + case Plasma::RightMargin: return d->rightWidth; break; - //Plasma::Layout::BottomMargin + //Plasma::BottomMargin default: return d->bottomHeight; break; } } void SvgPanel::paint(QPainter* painter, const QRectF& rect) { const int topWidth = d->background->elementSize("top").width(); const int leftHeight = d->background->elementSize("left").height(); const int topOffset = d->bFlags & ContentAtOrigin ? 0 - d->topHeight : 0; const int leftOffset = d->bFlags & ContentAtOrigin ? 0 - d->leftWidth : 0; if (!d->cachedBackground) { const int contentTop = 0; const int contentLeft = 0; const int contentWidth = d->panelSize.width() - d->leftWidth - d->rightWidth; const int contentHeight = d->panelSize.height() - d->topHeight - d->bottomHeight; const int rightOffset = contentWidth; const int bottomOffset = contentHeight; QSizeF scaledSize = QSizeF(d->panelSize.width() - (d->leftWidth + d->rightWidth) + d->panelSize.width()*(((qreal)(d->leftWidth + d->rightWidth)) / d->panelSize.width()), d->panelSize.height() - (d->topHeight + d->bottomHeight) + d->panelSize.height()*(((qreal)(d->topHeight + d->bottomHeight)) / d->panelSize.height())); delete d->cachedBackground; d->cachedBackground = new QPixmap(d->leftWidth + contentWidth + d->rightWidth, d->topHeight + contentHeight + d->bottomHeight); d->cachedBackground->fill(Qt::transparent); QPainter p(d->cachedBackground); p.translate(d->leftWidth, d->topHeight); p.setCompositionMode(QPainter::CompositionMode_Source); p.setRenderHint(QPainter::SmoothPixmapTransform); //FIXME: This is a hack to fix a drawing problems with svg files where a thin transparent border is drawn around the svg image. // the transparent border around the svg seems to vary in size depending on the size of the svg and as a result increasing the // svg image by 2 all around didn't resolve the issue. For now it resizes based on the border size. //CENTER if (contentHeight > 0 && contentWidth > 0) { d->background->resize(scaledSize.width(), scaledSize.height()); d->background->paint(&p, QRect(contentLeft - d->leftWidth, contentTop - d->topHeight, contentWidth + d->leftWidth*2, contentHeight + d->topHeight*2), "center"); d->background->resize(); } //EDGES if (d->bFlags & DrawTop) { if (d->bFlags & DrawLeft) { d->background->paint(&p, QRect(leftOffset, topOffset, d->leftWidth, d->topHeight), "topleft"); } if (d->bFlags & DrawRight) { d->background->paint(&p, QRect(rightOffset, topOffset, d->rightWidth, d->topHeight), "topright"); } } if (d->bFlags & DrawBottom) { if (d->bFlags & DrawLeft) { d->background->paint(&p, QRect(leftOffset, bottomOffset, d->leftWidth, d->bottomHeight), "bottomleft"); } if (d->bFlags & DrawRight) { d->background->paint(&p, QRect(rightOffset, bottomOffset, d->rightWidth, d->bottomHeight), "bottomright"); } } //SIDES if (d->stretchBorders) { if (d->bFlags & DrawLeft) { d->background->resize(d->background->size().width(), scaledSize.height()); d->background->paint(&p, QRect(leftOffset, contentTop, d->leftWidth, contentHeight), "left"); d->background->resize(); } if (d->bFlags & DrawRight) { d->background->resize(d->background->size().width(), scaledSize.height()); d->background->paint(&p, QRect(rightOffset, contentTop, d->rightWidth, contentHeight), "right"); d->background->resize(); } if (d->bFlags & DrawTop) { d->background->resize(scaledSize.width(), d->background->size().height()); d->background->paint(&p, QRect(contentLeft, topOffset, contentWidth, d->topHeight), "top"); d->background->resize(); } if (d->bFlags & DrawBottom) { d->background->resize(scaledSize.width(), d->background->size().height()); d->background->paint(&p, QRect(contentLeft, bottomOffset, contentWidth, d->bottomHeight), "bottom"); d->background->resize(); } } else { if (d->bFlags & DrawLeft) { QPixmap left(d->leftWidth, leftHeight); left.fill(Qt::transparent); { QPainter sidePainter(&left); sidePainter.setCompositionMode(QPainter::CompositionMode_Source); d->background->paint(&sidePainter, QPoint(0, 0), "left"); } p.drawTiledPixmap(QRect(leftOffset, contentTop, d->leftWidth, contentHeight), left); } if (d->bFlags & DrawRight) { QPixmap right(d->rightWidth, leftHeight); right.fill(Qt::transparent); { QPainter sidePainter(&right); sidePainter.setCompositionMode(QPainter::CompositionMode_Source); d->background->paint(&sidePainter, QPoint(0, 0), "right"); } p.drawTiledPixmap(QRect(rightOffset, contentTop, d->rightWidth, contentHeight), right); } if (d->bFlags & DrawTop) { QPixmap top(topWidth, d->topHeight); top.fill(Qt::transparent); { QPainter sidePainter(&top); sidePainter.setCompositionMode(QPainter::CompositionMode_Source); d->background->paint(&sidePainter, QPoint(0, 0), "top"); } p.drawTiledPixmap(QRect(contentLeft, topOffset, contentWidth, d->topHeight), top); } if (d->bFlags & DrawBottom) { QPixmap bottom(topWidth, d->bottomHeight); bottom.fill(Qt::transparent); { QPainter sidePainter(&bottom); sidePainter.setCompositionMode(QPainter::CompositionMode_Source); d->background->paint(&sidePainter, QPoint(0, 0), "bottom"); } p.drawTiledPixmap(QRect(contentLeft, bottomOffset, contentWidth, d->bottomHeight), bottom); } } // re-enable this once Qt's svg rendering is un-buggered //resize(contentWidth, contentHeight); //paint(&p, QRect(contentLeft, contentTop, contentWidth, contentHeight), "center"); } //p2->drawPixmap(paintRect, *cachedBackground, paintRect.translated(-leftOffset,-topOffset)); painter->drawPixmap(rect, *d->cachedBackground, rect.translated(-leftOffset, -topOffset)); } void SvgPanel::updateSizes() { d->background->resize(); if (d->bFlags & DrawTop) { d->topHeight = d->background->elementSize("top").height(); } else { d->topHeight = 0; } if (d->bFlags & DrawLeft) { d->leftWidth = d->background->elementSize("left").width(); } else { d->leftWidth = 0; } if (d->bFlags & DrawRight) { d->rightWidth = d->background->elementSize("right").width(); } else { d->rightWidth = 0; } if (d->bFlags & DrawBottom) { d->bottomHeight = d->background->elementSize("bottom").height(); } else { d->bottomHeight = 0; } //since it's rectangular, topWidth and bottomWidth must be the same d->noBorderPadding = d->background->elementExists("hint-no-border-padding"); d->stretchBorders = d->background->elementExists("hint-stretch-borders"); } } // Plasma namespace #include "svgpanel.moc" diff --git a/plasma/svgpanel.h b/plasma/svgpanel.h index 4545ceec4a..18571dc490 100644 --- a/plasma/svgpanel.h +++ b/plasma/svgpanel.h @@ -1,128 +1,128 @@ /* * Copyright 2008 by Aaron Seigo * Copyright 2008 Marco Martin * * 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 PLASMA_SVGPANEL_H #define PLASMA_SVGPANEL_H #include #include #include +#include #include -#include class QPainter; class QPoint; class QPointF; class QRect; class QRectF; class QSize; class QSizeF; class QMatrix; namespace Plasma { class PLASMA_EXPORT SvgPanel : public QObject { Q_OBJECT public: /** * These flags represents what borders should be drawn */ enum BorderFlag { DrawTop = 1, DrawBottom = 2, DrawLeft = 4, DrawRight = 8, ContentAtOrigin = 16 }; Q_DECLARE_FLAGS(BorderFlags, BorderFlag) /** * Constructs a new SvgPanel that paints the proper named subelements * as borders * * The size is initialized to be the SVG's native size. * * @arg imagePath the image to show. If a relative path is passed, then * Plasma::Theme is used to load the SVG. * @arg parent options QObject to parent this to * * @related Plasma::Theme */ explicit SvgPanel(const QString& imagePath = QString(), QObject* parent = 0); ~SvgPanel(); /** * Loads a new Svg * @arg imagePath the new file */ void setFile(const QString& imagePath); /** * Convenience method to get the svg filepath and name of svg. * @return the svg's filepath including name of the svg. */ QString file() const; /** * Sets what borders should be painted * @arg flags borders we want to paint */ void setBorderFlags(const BorderFlags flags); /** * Convenience method to get the border flags * @return what borders are painted */ BorderFlags borderFlags() const; /** * Resize the panel maintaining the same border size * @arg size the new size of the panel */ void resize(const QSizeF& size); /** * Returns the margin size given the margin edge we want * @arg edge the margin edge we want, top, bottom, left or right * @return the margin size */ - qreal marginSize(const Plasma::Layout::MarginEdge edge) const; + qreal marginSize(const Plasma::MarginEdge edge) const; /** * Paints the loaded SVG with the elements that represents the border * @arg painter the QPainter to use * @arg rect the exposed rect to draw into */ Q_INVOKABLE void paint(QPainter* painter, const QRectF& rect); private slots: //update sizes of the svg elements void updateSizes(); private: class Private; Private * const d; }; } // Plasma namespace #endif // multiple inclusion guard