2 * Copyright 2007 by Aaron Seigo <aseigo@kde.org>
3 * Copyright 2008 by Ménard Alexis <darktears31@gmail.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library General Public License as
7 * published by the Free Software Foundation; either version 2, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details
15 * You should have received a copy of the GNU Library General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "containment.h"
22 #include "private/containment_p.h"
25 #include <QGraphicsSceneContextMenuEvent>
26 #include <QGraphicsView>
29 #include <QStyleOptionGraphicsItem>
30 #include <QGraphicsLayout>
31 #include <QGraphicsLinearLayout>
34 #include <kapplication.h>
35 #include <kauthorized.h>
38 #include <kmessagebox.h>
39 #include <kmimetype.h>
41 #include <kservicetypetrader.h>
42 #include <kstandarddirs.h>
43 #include <ktemporaryfile.h>
44 #include <kwindowsystem.h>
49 #include "extenderitem.h"
51 #include "wallpaper.h"
53 #include "private/applet_p.h"
54 #include "private/applethandle_p.h"
55 #include "private/desktoptoolbox_p.h"
56 #include "private/extenderitemmimedata_p.h"
57 #include "private/paneltoolbox_p.h"
62 bool ContainmentPrivate::s_positioning
= false;
63 static const char defaultWallpaper
[] = "image";
64 static const char defaultWallpaperMode
[] = "SingleImage";
66 Containment::StyleOption::StyleOption()
67 : QStyleOptionGraphicsItem(),
74 Containment::StyleOption::StyleOption(const Containment::StyleOption
& other
)
75 : QStyleOptionGraphicsItem(other
),
82 Containment::StyleOption::StyleOption(const QStyleOptionGraphicsItem
&other
)
83 : QStyleOptionGraphicsItem(other
),
90 Containment::Containment(QGraphicsItem
*parent
,
91 const QString
&serviceId
,
93 : Applet(parent
, serviceId
, containmentId
),
94 d(new ContainmentPrivate(this))
96 // WARNING: do not access config() OR globalConfig() in this method!
97 // that requires a scene, which is not available at this point
99 setBackgroundHints(NoBackground
);
100 setContainmentType(CustomContainment
);
101 setHasConfigurationInterface(false);
104 Containment::Containment(QObject
*parent
, const QVariantList
&args
)
105 : Applet(parent
, args
),
106 d(new ContainmentPrivate(this))
108 // WARNING: do not access config() OR globalConfig() in this method!
109 // that requires a scene, which is not available at this point
111 setBackgroundHints(NoBackground
);
112 setHasConfigurationInterface(false);
115 Containment::~Containment()
120 void Containment::init()
122 if (!isContainment()) {
126 setCacheMode(NoCache
);
127 setFlag(QGraphicsItem::ItemIsMovable
, false);
128 setFlag(QGraphicsItem::ItemClipsChildrenToShape
, false);
129 setAcceptDrops(true);
130 setAcceptsHoverEvents(true);
132 //TODO: would be nice to not do this on init, as it causes Animator to init
133 connect(Animator::self(), SIGNAL(animationFinished(QGraphicsItem
*,Plasma::Animator::Animation
)),
134 this, SLOT(containmentAppletAnimationComplete(QGraphicsItem
*,Plasma::Animator::Animation
)));
136 if (d
->type
== NoContainmentType
) {
137 setContainmentType(DesktopContainment
);
141 bool unlocked
= immutability() == Mutable
;
143 KAction
*appletBrowserAction
= new KAction(i18n("Add Widgets..."), this);
144 appletBrowserAction
->setIcon(KIcon("list-add"));
145 appletBrowserAction
->setVisible(unlocked
);
146 appletBrowserAction
->setEnabled(unlocked
);
147 connect(appletBrowserAction
, SIGNAL(triggered()), this, SLOT(triggerShowAddWidgets()));
148 appletBrowserAction
->setShortcut(QKeySequence("alt+d,a"));
149 d
->actions().addAction("add widgets", appletBrowserAction
);
151 KAction
*action
= new KAction(i18n("Next Widget"), this);
153 connect(action
, SIGNAL(triggered()), this, SLOT(focusNextApplet()));
154 action
->setShortcut(QKeySequence("alt+d,n"));
155 d
->actions().addAction("next applet", action
);
157 action
= new KAction(i18n("Previous Widget"), this);
159 connect(action
, SIGNAL(triggered()), this, SLOT(focusPreviousApplet()));
160 action
->setShortcut(QKeySequence("alt+d,p"));
161 d
->actions().addAction("previous applet", action
);
163 if (immutability() != SystemImmutable
&& corona()) {
164 QAction
*lockDesktopAction
= corona()->action("lock widgets");
165 //keep a pointer so nobody notices it moved to corona
166 if (lockDesktopAction
) {
167 d
->actions().addAction("lock widgets", lockDesktopAction
);
171 if (d
->type
!= PanelContainment
&&
172 d
->type
!= CustomPanelContainment
) {
173 KAction
*zoomAction
= new KAction(i18n("Zoom In"), this);
174 zoomAction
->setIcon(KIcon("zoom-in"));
175 connect(zoomAction
, SIGNAL(triggered(bool)), this, SLOT(zoomIn()));
176 //two shortcuts because I hate ctrl-+ but others expect it
177 QList
<QKeySequence
> keys
;
178 keys
<< QKeySequence("alt+d,+");
179 keys
<< QKeySequence("alt+d,=");
180 zoomAction
->setShortcuts(keys
);
181 d
->actions().addAction("zoom in", zoomAction
);
183 zoomAction
= new KAction(i18n("Zoom Out"), this);
184 zoomAction
->setIcon(KIcon("zoom-out"));
185 connect(zoomAction
, SIGNAL(triggered(bool)), this, SLOT(zoomOut()));
186 zoomAction
->setShortcut(QKeySequence("alt+d,-"));
187 d
->actions().addAction("zoom out", zoomAction
);
190 QAction
*action
= corona()->action("add sibling containment");
192 d
->actions().addAction("add sibling containment", action
);
196 if (d
->type
== DesktopContainment
&& d
->toolBox
) {
197 d
->toolBox
->addTool(this->action("add widgets"));
198 d
->toolBox
->addTool(this->action("zoom in"));
199 d
->toolBox
->addTool(this->action("zoom out"));
201 //TODO: do we need some way to allow this be overridden?
202 // it's always available because shells rely on this
203 // to offer their own custom configuration as well
204 QAction
*configureContainment
= this->action("configure");
205 if (configureContainment
) {
206 d
->toolBox
->addTool(configureContainment
);
210 //Set a default wallpaper the first time the containment is created,
211 //for instance from the toolbox by the user
212 if (d
->drawWallpaper
) {
213 setDrawWallpaper(true);
218 // helper function for sorting the list of applets
219 bool appletConfigLessThan(const KConfigGroup
&c1
, const KConfigGroup
&c2
)
221 QPointF p1
= c1
.readEntry("geometry", QRectF()).topLeft();
222 QPointF p2
= c2
.readEntry("geometry", QRectF()).topLeft();
224 if (!qFuzzyCompare(p1
.x(), p2
.x())) {
225 return p1
.x() < p2
.x();
228 return qFuzzyCompare(p1
.y(), p2
.y()) || p1
.y() < p2
.y();
231 void Containment::restore(KConfigGroup
&group
)
233 /*kDebug() << "!!!!!!!!!!!!initConstraints" << group.name() << d->type;
234 kDebug() << " location:" << group.readEntry("location", (int)d->location);
235 kDebug() << " geom:" << group.readEntry("geometry", geometry());
236 kDebug() << " formfactor:" << group.readEntry("formfactor", (int)d->formFactor);
237 kDebug() << " screen:" << group.readEntry("screen", d->screen);*/
238 if (!isContainment()) {
239 Applet::restore(group
);
243 QRectF geo
= group
.readEntry("geometry", geometry());
245 //this ensures panels are set to their saved size even when they have max & min set to prevent
247 if (geo
.size() != geo
.size().boundedTo(maximumSize())) {
248 setMaximumSize(maximumSize().expandedTo(geo
.size()));
250 if (geo
.size() != geo
.size().expandedTo(minimumSize())) {
251 setMinimumSize(minimumSize().boundedTo(geo
.size()));
255 setLocation((Plasma::Location
)group
.readEntry("location", (int)d
->location
));
256 setFormFactor((Plasma::FormFactor
)group
.readEntry("formfactor", (int)d
->formFactor
));
257 setScreen(group
.readEntry("screen", d
->screen
), group
.readEntry("desktop", d
->desktop
));
258 setActivity(group
.readEntry("activity", QString()));
260 flushPendingConstraintsEvents();
261 restoreContents(group
);
262 setImmutability((ImmutabilityType
)group
.readEntry("immutability", (int)Mutable
));
264 setWallpaper(group
.readEntry("wallpaperplugin", defaultWallpaper
),
265 group
.readEntry("wallpaperpluginmode", defaultWallpaperMode
));
267 kDebug() << "Containment" << id() <<
268 "screen" << screen() <<
269 "geometry is" << geometry() <<
270 "wallpaper" << ((d->wallpaper) ? d->wallpaper->pluginName() : QString()) <<
271 "wallpaper mode" << wallpaperMode() <<
272 "config entries" << group.entryMap();
276 void Containment::save(KConfigGroup
&g
) const
278 if (Applet::d
->transient
) {
282 KConfigGroup group
= g
;
283 if (!group
.isValid()) {
287 // locking is saved in Applet::save
289 group
.writeEntry("screen", d
->screen
);
290 group
.writeEntry("desktop", d
->desktop
);
291 group
.writeEntry("formfactor", (int)d
->formFactor
);
292 group
.writeEntry("location", (int)d
->location
);
293 group
.writeEntry("activity", d
->context()->currentActivity());
296 d
->toolBox
->save(group
);
300 group
.writeEntry("wallpaperplugin", d
->wallpaper
->pluginName());
301 group
.writeEntry("wallpaperpluginmode", d
->wallpaper
->renderingMode().name());
303 if (d
->wallpaper
->isInitialized()) {
304 KConfigGroup
wallpaperConfig(&group
, "Wallpaper");
305 wallpaperConfig
= KConfigGroup(&wallpaperConfig
, d
->wallpaper
->pluginName());
306 d
->wallpaper
->save(wallpaperConfig
);
313 void Containment::saveContents(KConfigGroup
&group
) const
315 KConfigGroup
applets(&group
, "Applets");
316 foreach (const Applet
*applet
, d
->applets
) {
317 KConfigGroup
appletConfig(&applets
, QString::number(applet
->id()));
318 applet
->save(appletConfig
);
322 void Containment::restoreContents(KConfigGroup
&group
)
324 KConfigGroup
applets(&group
, "Applets");
326 // Sort the applet configs in order of geometry to ensure that applets
327 // are added from left to right or top to bottom for a panel containment
328 QList
<KConfigGroup
> appletConfigs
;
329 foreach (const QString
&appletGroup
, applets
.groupList()) {
330 //kDebug() << "reading from applet group" << appletGroup;
331 KConfigGroup
appletConfig(&applets
, appletGroup
);
332 appletConfigs
.append(appletConfig
);
334 qStableSort(appletConfigs
.begin(), appletConfigs
.end(), appletConfigLessThan
);
336 QMutableListIterator
<KConfigGroup
> it(appletConfigs
);
337 while (it
.hasNext()) {
338 KConfigGroup
&appletConfig
= it
.next();
339 int appId
= appletConfig
.name().toUInt();
340 QString plugin
= appletConfig
.readEntry("plugin", QString());
342 if (plugin
.isEmpty()) {
346 Applet
*applet
= d
->addApplet(plugin
, QVariantList(),
347 appletConfig
.readEntry("geometry", QRectF()),
349 applet
->restore(appletConfig
);
353 Containment::Type
Containment::containmentType() const
358 void Containment::setContainmentType(Containment::Type type
)
360 if (d
->type
== type
) {
368 if (!isContainment()) {
372 if ((type
== DesktopContainment
|| type
== PanelContainment
)) {
376 d
->checkRemoveAction();
379 Corona
*Containment::corona() const
381 return dynamic_cast<Corona
*>(scene());
384 void Containment::mouseMoveEvent(QGraphicsSceneMouseEvent
*event
)
387 if (d
->wallpaper
&& d
->wallpaper
->isInitialized()) {
388 QGraphicsItem
*item
= scene()->itemAt(event
->scenePos());
390 d
->wallpaper
->mouseMoveEvent(event
);
394 if (!event
->isAccepted()) {
396 Applet::mouseMoveEvent(event
);
400 void Containment::mousePressEvent(QGraphicsSceneMouseEvent
*event
)
403 if (d
->wallpaper
&& d
->wallpaper
->isInitialized()) {
404 QGraphicsItem
*item
= scene()->itemAt(event
->scenePos());
406 d
->wallpaper
->mousePressEvent(event
);
410 if (event
->isAccepted()) {
411 setFocus(Qt::MouseFocusReason
);
414 Applet::mousePressEvent(event
);
418 void Containment::mouseReleaseEvent(QGraphicsSceneMouseEvent
*event
)
421 if (d
->wallpaper
&& d
->wallpaper
->isInitialized()) {
422 QGraphicsItem
*item
= scene()->itemAt(event
->scenePos());
424 d
->wallpaper
->mouseReleaseEvent(event
);
428 if (!event
->isAccepted()) {
430 Applet::mouseReleaseEvent(event
);
434 void Containment::showDropZone(const QPoint pos
)
437 //Base implementation does nothing, don't put code here
440 void Containment::showContextMenu(const QPointF
&containmentPos
, const QPoint
&screenPos
)
442 d
->showContextMenu(mapToScene(containmentPos
), screenPos
, false);
445 void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent
*event
)
447 //kDebug() << "let's see if we manage to get a context menu here, huh";
448 if (!isContainment() || !scene() || !KAuthorized::authorizeKAction("desktop_contextmenu")) {
449 Applet::contextMenuEvent(event
);
453 if (!d
->showContextMenu(event
->scenePos(), event
->screenPos(), true)) {
454 Applet::contextMenuEvent(event
);
460 void ContainmentPrivate::containmentActions(KMenu
&desktopMenu
)
462 if (static_cast<Corona
*>(q
->scene())->immutability() != Mutable
&&
463 !KAuthorized::authorizeKAction("unlock_desktop")) {
464 //kDebug() << "immutability";
468 //get base context actions
469 QList
<QAction
*> actions
= q
->contextualActions();
471 //find the separator to insert the activity settings before it
472 QAction
*separatorAction
= 0;
474 //TODO: should a submenu be created if there are too many containment specific
475 // actions? see folderview containment
476 foreach (QAction
*action
, actions
) {
478 desktopMenu
.addAction(action
);
479 if (action
->isSeparator()) {
480 separatorAction
= action
;
485 desktopMenu
.addSeparator();
487 if (type
== Containment::DesktopContainment
) {
488 desktopMenu
.addAction(q
->action("configure"));
492 void ContainmentPrivate::appletActions(KMenu
&desktopMenu
, Applet
*applet
, bool includeApplet
)
494 QList
<QAction
*> actions
;
497 actions
= applet
->contextualActions();
498 if (!actions
.isEmpty()) {
499 foreach (QAction
*action
, actions
) {
501 desktopMenu
.addAction(action
);
507 if (applet
->hasConfigurationInterface()) {
508 QAction
*configureApplet
= applet
->d
->actions
.action("configure");
509 if (configureApplet
) {
510 desktopMenu
.addAction(configureApplet
);
514 KMenu
*containmentMenu
= new KMenu(i18nc("%1 is the name of the containment", "%1 Options", q
->name()), &desktopMenu
);
515 containmentActions(*containmentMenu
);
516 if (!containmentMenu
->isEmpty()) {
518 //count number of real actions
519 foreach(QAction
*action
, containmentMenu
->actions()) {
520 if(action
->isEnabled() && !action
->isSeparator()) {
526 desktopMenu
.addSeparator();
529 //if there is only one, don't create a submenu
531 foreach(QAction
*action
, containmentMenu
->actions()) {
532 desktopMenu
.addAction(action
);
535 desktopMenu
.addMenu(containmentMenu
);
539 if (static_cast<Corona
*>(q
->scene())->immutability() == Mutable
) {
540 if (!desktopMenu
.isEmpty()) {
541 desktopMenu
.addSeparator();
544 QAction
*closeApplet
= applet
->d
->actions
.action("remove");
545 if (!closeApplet
) { //unlikely but not impossible
546 closeApplet
= new QAction(i18nc("%1 is the name of the applet", "Remove this %1", applet
->name()), &desktopMenu
);
547 closeApplet
->setIcon(KIcon("edit-delete"));
548 QObject::connect(closeApplet
, SIGNAL(triggered(bool)), applet
, SLOT(destroy()));
550 desktopMenu
.addAction(closeApplet
);
554 bool ContainmentPrivate::showContextMenu(const QPointF
&point
,
555 const QPoint
&screenPos
, bool includeApplet
)
559 QGraphicsItem
*item
= q
->scene()->itemAt(point
);
565 applet
= qgraphicsitem_cast
<Applet
*>(item
);
566 if (applet
&& !applet
->isContainment()) {
570 // applet may have a value due to finding a containment!
572 item
= item
->parentItem();
576 //kDebug() << "context menu event " << (QObject*)applet;
578 appletActions(desktopMenu
, applet
, includeApplet
);
580 containmentActions(desktopMenu
);
583 if (!desktopMenu
.isEmpty()) {
584 //kDebug() << "executing at" << screenPos;
585 desktopMenu
.exec(screenPos
);
592 void Containment::setFormFactor(FormFactor formFactor
)
594 if (d
->formFactor
== formFactor
) {
598 //kDebug() << "switching FF to " << formFactor;
599 d
->formFactor
= formFactor
;
601 if (isContainment() &&
602 (d
->type
== PanelContainment
|| d
->type
== CustomPanelContainment
)) {
603 // we are a panel and we have chaged our orientation
604 d
->positionPanel(true);
608 if (d
->formFactor
== Vertical
) {
609 d
->toolBox
->setCorner(ToolBox::Bottom
);
610 //defaults to horizontal
611 } else if (QApplication::layoutDirection() == Qt::RightToLeft
) {
612 d
->toolBox
->setCorner(ToolBox::Left
);
614 d
->toolBox
->setCorner(ToolBox::Right
);
618 updateConstraints(Plasma::FormFactorConstraint
);
620 KConfigGroup c
= config();
621 c
.writeEntry("formfactor", (int)formFactor
);
622 emit
configNeedsSaving();
625 void Containment::setLocation(Location location
)
627 if (d
->location
== location
) {
631 bool emitGeomChange
= false;
633 if ((location
== TopEdge
|| location
== BottomEdge
) &&
634 (d
->location
== TopEdge
|| d
->location
== BottomEdge
)) {
635 emitGeomChange
= true;
638 if ((location
== RightEdge
|| location
== LeftEdge
) &&
639 (d
->location
== RightEdge
|| d
->location
== LeftEdge
)) {
640 emitGeomChange
= true;
643 d
->location
= location
;
645 foreach (Applet
*applet
, d
->applets
) {
646 applet
->updateConstraints(Plasma::LocationConstraint
);
649 if (emitGeomChange
) {
650 // our geometry on the scene will not actually change,
651 // but for the purposes of views it has
652 emit
geometryChanged();
655 updateConstraints(Plasma::LocationConstraint
);
657 KConfigGroup c
= config();
658 c
.writeEntry("location", (int)location
);
659 emit
configNeedsSaving();
662 void Containment::addSiblingContainment()
664 emit
addSiblingContainment(this);
667 void Containment::clearApplets()
669 foreach (Applet
*applet
, d
->applets
) {
670 applet
->d
->cleanUpAndDelete();
676 Applet
*Containment::addApplet(const QString
&name
, const QVariantList
&args
,
677 const QRectF
&appletGeometry
)
679 return d
->addApplet(name
, args
, appletGeometry
);
682 void Containment::addApplet(Applet
*applet
, const QPointF
&pos
, bool delayInit
)
684 if (!isContainment() || (!delayInit
&& immutability() != Mutable
)) {
689 kDebug() << "adding null applet!?!";
693 if (d
->applets
.contains(applet
)) {
694 kDebug() << "already have this applet!";
697 Containment
*currentContainment
= applet
->containment();
699 if (d
->type
== PanelContainment
) {
700 //panels don't want backgrounds, which is important when setting geometry
701 setBackgroundHints(NoBackground
);
704 if (currentContainment
&& currentContainment
!= this) {
705 emit currentContainment
->appletRemoved(applet
);
706 disconnect(applet
, 0, currentContainment
, 0);
707 applet
->removeSceneEventFilter(currentContainment
);
708 KConfigGroup oldConfig
= applet
->config();
709 currentContainment
->d
->applets
.removeAll(applet
);
710 if (currentContainment
->d
->handles
.contains(applet
)) {
711 currentContainment
->d
->handles
.remove(applet
);
713 applet
->setParentItem(this);
715 // now move the old config to the new location
716 //FIXME: this doesn't seem to get the actual main config group containing plugin=, etc
717 KConfigGroup c
= config().group("Applets").group(QString::number(applet
->id()));
718 oldConfig
.reparent(&c
);
719 applet
->d
->resetConfigurationObject();
721 disconnect(applet
, SIGNAL(activate()), currentContainment
, SIGNAL(activate()));
723 applet
->setParentItem(this);
726 d
->applets
<< applet
;
728 connect(applet
, SIGNAL(configNeedsSaving()), this, SIGNAL(configNeedsSaving()));
729 connect(applet
, SIGNAL(releaseVisualFocus()), this, SIGNAL(releaseVisualFocus()));
730 connect(applet
, SIGNAL(appletDestroyed(Plasma::Applet
*)), this, SLOT(appletDestroyed(Plasma::Applet
*)));
731 connect(applet
, SIGNAL(activate()), this, SIGNAL(activate()));
733 if (pos
!= QPointF(-1, -1)) {
737 if (delayInit
|| currentContainment
) {
738 if (d
->type
== DesktopContainment
) {
739 applet
->installSceneEventFilter(this);
740 //applet->setWindowFlags(Qt::Window);
744 Animator::self()->animateItem(applet
, Animator::AppearAnimation
);
747 applet
->updateConstraints(Plasma::AllConstraints
);
750 applet
->flushPendingConstraintsEvents();
753 emit
appletAdded(applet
, pos
);
755 if (!currentContainment
) {
756 applet
->updateConstraints(Plasma::StartupCompletedConstraint
);
758 applet
->flushPendingConstraintsEvents();
763 applet
->d
->scheduleModificationNotification();
767 Applet::List
Containment::applets() const
772 void Containment::setScreen(int newScreen
, int newDesktop
)
774 // What we want to do in here is:
775 // * claim the screen as our own
776 // * signal whatever may be watching this containment about the switch
777 // * if we are a full screen containment, then:
778 // * resize to match the screen if we're that kind of containment
779 // * kick other full-screen containments off this screen
780 // * if we had a screen, then give our screen to the containment
783 // a screen of -1 means no associated screen.
785 int numScreens
= corona()->numScreens();
786 if (newScreen
< -1) {
790 // -1 == All desktops
791 if (newDesktop
< -1 || newDesktop
> KWindowSystem::numberOfDesktops() - 1) {
795 kDebug() << "setting screen to " << newScreen
<< newDesktop
<< "and type is" << d
->type
;
797 Containment
*swapScreensWith(0);
798 if (d
->type
== DesktopContainment
|| d
->type
>= CustomContainment
) {
799 // we want to listen to changes in work area if our screen changes
800 if (d
->screen
< 0 && newScreen
> -1) {
801 connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(positionToolBox()));
802 } else if (newScreen
< 0) {
803 disconnect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(positionToolBox()));
806 if (newScreen
> -1 && corona()) {
807 // sanity check to make sure someone else doesn't have this screen already!
808 Containment
*currently
= corona()->containmentForScreen(newScreen
, newDesktop
);
809 if (currently
&& currently
!= this) {
810 kDebug() << "currently is on screen" << currently
->screen()
811 << "and is" << currently
->name()
812 << (QObject
*)currently
<< (QObject
*)this;
813 currently
->setScreen(-1, newDesktop
);
814 swapScreensWith
= currently
;
819 if (newScreen
< numScreens
&& newScreen
> -1) {
820 if (d
->type
== DesktopContainment
||
821 d
->type
>= CustomContainment
) {
822 resize(corona()->screenGeometry(newScreen
).size());
826 int oldDesktop
= d
->desktop
;
827 d
->desktop
= newDesktop
;
829 int oldScreen
= d
->screen
;
830 d
->screen
= newScreen
;
832 updateConstraints(Plasma::ScreenConstraint
);
834 if (oldScreen
!= newScreen
) {
835 emit
screenChanged(oldScreen
, newScreen
, this);
837 KConfigGroup c
= config();
838 c
.writeEntry("screen", d
->screen
);
839 emit
configNeedsSaving();
842 if (swapScreensWith
) {
843 swapScreensWith
->setScreen(oldScreen
, oldDesktop
);
846 d
->checkRemoveAction();
849 int Containment::screen() const
854 int Containment::desktop() const
859 KPluginInfo::List
Containment::listContainments(const QString
&category
,
860 const QString
&parentApp
)
864 if (parentApp
.isEmpty()) {
865 constraint
.append("not exist [X-KDE-ParentApp]");
867 constraint
.append("[X-KDE-ParentApp] == '").append(parentApp
).append("'");
870 if (!category
.isEmpty()) {
871 if (!constraint
.isEmpty()) {
872 constraint
.append(" and ");
875 constraint
.append("[X-KDE-PluginInfo-Category] == '").append(category
).append("'");
876 if (category
== "Miscellaneous") {
877 constraint
.append(" or (not exist [X-KDE-PluginInfo-Category] or [X-KDE-PluginInfo-Category] == '')");
881 KService::List offers
= KServiceTypeTrader::self()->query("Plasma/Containment", constraint
);
882 //kDebug() << "constraint was" << constraint << "which got us" << offers.count() << "matches";
883 return KPluginInfo::fromServices(offers
);
886 KPluginInfo::List
Containment::listContainmentsForMimetype(const QString
&mimetype
)
888 QString constraint
= QString("'%1' in [X-Plasma-DropMimeTypes]").arg(mimetype
);
889 //kDebug() << mimetype << constraint;
890 KService::List offers
= KServiceTypeTrader::self()->query("Plasma/Containment", constraint
);
891 return KPluginInfo::fromServices(offers
);
894 void Containment::dragEnterEvent(QGraphicsSceneDragDropEvent
*event
)
896 //kDebug() << immutability() << Mutable << (immutability() == Mutable);
897 event
->setAccepted(immutability() == Mutable
&&
898 (event
->mimeData()->hasFormat(static_cast<Corona
*>(scene())->appletMimeType()) ||
899 KUrl::List::canDecode(event
->mimeData()) ||
900 event
->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())));
902 if (!event
->isAccepted()) {
903 // check to see if we have an applet that accepts the format.
904 QStringList formats
= event
->mimeData()->formats();
906 foreach (const QString
&format
, formats
) {
907 KPluginInfo::List appletList
= Applet::listAppletInfoForMimetype(format
);
908 if (!appletList
.isEmpty()) {
909 event
->setAccepted(true);
915 if (event
->isAccepted() && view()) {
916 showDropZone(view()->mapFromScene(event
->scenePos()));
920 void Containment::dragMoveEvent(QGraphicsSceneDragDropEvent
*event
)
922 QGraphicsItem
*item
= scene()->itemAt(event
->scenePos());
923 event
->setAccepted(item
== this || !item
);
924 Plasma::Containment
*c
= containment();
925 if (c
&& c
->immutability() == Plasma::Mutable
&&
926 (event
->mimeData()->hasFormat(static_cast<Plasma::Corona
*>(scene())->appletMimeType()) ||
927 KUrl::List::canDecode(event
->mimeData())) && view()) {
928 showDropZone(view()->mapFromScene(event
->scenePos()));
932 void Containment::dropEvent(QGraphicsSceneDragDropEvent
*event
)
934 //kDebug() << event->mimeData()->text();
935 if (!isContainment()) {
936 Applet::dropEvent(event
);
940 QString
mimetype(static_cast<Corona
*>(scene())->appletMimeType());
942 if (event
->mimeData()->hasFormat(mimetype
) && scene()) {
943 QString data
= event
->mimeData()->data(mimetype
);
944 QStringList appletNames
= data
.split('\n', QString::SkipEmptyParts
);
946 foreach (const QString
&appletName
, appletNames
) {
947 //kDebug() << "doing" << appletName;
948 QRectF
geom(mapFromScene(event
->scenePos()), QSize(0, 0));
949 addApplet(appletName
, QVariantList(), geom
);
951 event
->acceptProposedAction();
952 } else if (event
->mimeData()->hasFormat(ExtenderItemMimeData::mimeType())) {
953 kDebug() << "mimetype plasma/extenderitem is dropped, creating internal:extender";
954 //Handle dropping extenderitems.
955 const ExtenderItemMimeData
*mimeData
= qobject_cast
<const ExtenderItemMimeData
*>(event
->mimeData());
957 ExtenderItem
*item
= mimeData
->extenderItem();
958 QRectF
geometry(event
->pos(), item
->size());
959 kDebug() << "desired geometry: " << geometry
;
960 Applet
*applet
= addApplet("internal:extender", QVariantList(), geometry
);
961 item
->setExtender(applet
->extender());
963 } else if (KUrl::List::canDecode(event
->mimeData())) {
964 //TODO: collect the mimetypes of available script engines and offer
965 // to create widgets out of the matching URLs, if any
966 KUrl::List urls
= KUrl::List::fromMimeData(event
->mimeData());
967 foreach (const KUrl
&url
, urls
) {
968 KMimeType::Ptr mime
= KMimeType::findByUrl(url
);
969 QString mimeName
= mime
->name();
970 QRectF
geom(event
->pos(), QSize());
973 // kDebug() << mimeName;
974 KPluginInfo::List appletList
= Applet::listAppletInfoForMimetype(mimeName
);
976 if (!appletList
.isEmpty()) {
977 //TODO: should we show a dialog here to choose which plasmoid load if
978 //!appletList.isEmpty()
980 QHash
<QAction
*, QString
> actionsToPlugins
;
981 foreach (const KPluginInfo
&info
, appletList
) {
983 if (!info
.icon().isEmpty()) {
984 action
= choices
.addAction(KIcon(info
.icon()), info
.name());
986 action
= choices
.addAction(info
.name());
989 actionsToPlugins
.insert(action
, info
.pluginName());
992 actionsToPlugins
.insert(choices
.addAction(i18n("Icon")), "icon");
993 QAction
*choice
= choices
.exec(event
->screenPos());
995 addApplet(actionsToPlugins
[choice
], args
, geom
);
997 } else if (url
.protocol() != "data") {
998 // We don't try to do anything with data: URIs
999 // no special applet associated with this mimetype, let's
1000 addApplet("icon", args
, geom
);
1003 event
->acceptProposedAction();
1005 QStringList formats
= event
->mimeData()->formats();
1006 QHash
<QString
, KPluginInfo
> seenPlugins
;
1007 QHash
<QString
, QString
> pluginFormats
;
1009 foreach (const QString
&format
, formats
) {
1010 KPluginInfo::List plugins
= Applet::listAppletInfoForMimetype(format
);
1012 foreach (const KPluginInfo
&plugin
, plugins
) {
1013 if (seenPlugins
.contains(plugin
.pluginName())) {
1017 seenPlugins
.insert(plugin
.pluginName(), plugin
);
1018 pluginFormats
.insert(plugin
.pluginName(), format
);
1022 QString selectedPlugin
;
1024 if (seenPlugins
.isEmpty()) {
1025 // do nothing, we have no matches =/
1028 if (seenPlugins
.count() == 1) {
1029 selectedPlugin
= seenPlugins
.constBegin().key();
1032 QHash
<QAction
*, QString
> actionsToPlugins
;
1033 foreach (const KPluginInfo
&info
, seenPlugins
) {
1035 if (!info
.icon().isEmpty()) {
1036 action
= choices
.addAction(KIcon(info
.icon()), info
.name());
1038 action
= choices
.addAction(info
.name());
1041 actionsToPlugins
.insert(action
, info
.pluginName());
1044 QAction
*choice
= choices
.exec(event
->screenPos());
1046 selectedPlugin
= actionsToPlugins
[choice
];
1050 if (!selectedPlugin
.isEmpty()) {
1051 KTemporaryFile tempFile
;
1052 if (tempFile
.open()) {
1053 //TODO: what should we do with files after the applet is done with them??
1054 tempFile
.setAutoRemove(false);
1057 QDataStream
stream(&tempFile
);
1058 QByteArray data
= event
->mimeData()->data(pluginFormats
[selectedPlugin
]);
1059 stream
.writeRawData(data
, data
.size());
1062 QRectF
geom(event
->pos(), QSize());
1064 args
<< tempFile
.fileName();
1068 addApplet(selectedPlugin
, args
, geom
);
1074 const QGraphicsItem
*Containment::toolBoxItem() const
1079 void Containment::resizeEvent(QGraphicsSceneResizeEvent
*event
)
1081 Applet::resizeEvent(event
);
1083 if (!ContainmentPrivate::s_positioning
) {
1085 case Containment::PanelContainment
:
1086 case Containment::CustomPanelContainment
:
1090 d
->positionContainments();
1096 d
->wallpaper
->setBoundingRect(boundingRect());
1100 void Containment::keyPressEvent(QKeyEvent
*event
)
1102 //kDebug() << "keyPressEvent with" << event->key()
1103 // << "and hoping and wishing for a" << Qt::Key_Tab;
1104 if (event
->key() == Qt::Key_Tab
) { // && event->modifiers() == 0) {
1105 if (!d
->applets
.isEmpty()) {
1106 kDebug() << "let's give focus to...." << (QObject
*)d
->applets
.first();
1107 d
->applets
.first()->setFocus(Qt::TabFocusReason
);
1112 void Containment::wheelEvent(QGraphicsSceneWheelEvent
*event
)
1114 if (d
->wallpaper
&& d
->wallpaper
->isInitialized()) {
1115 QGraphicsItem
*item
= scene()->itemAt(event
->scenePos());
1118 d
->wallpaper
->wheelEvent(event
);
1120 if (event
->isAccepted()) {
1128 if (d
->type
== DesktopContainment
) {
1129 QGraphicsItem
*item
= scene()->itemAt(event
->scenePos());
1131 int numDesktops
= KWindowSystem::numberOfDesktops();
1132 int currentDesktop
= KWindowSystem::currentDesktop();
1134 if (event
->delta() < 0) {
1135 KWindowSystem::setCurrentDesktop(currentDesktop
% numDesktops
+ 1);
1137 KWindowSystem::setCurrentDesktop((numDesktops
+ currentDesktop
- 2) % numDesktops
+ 1);
1146 Applet::wheelEvent(event
);
1149 bool Containment::sceneEventFilter(QGraphicsItem
*watched
, QEvent
*event
)
1151 Applet
*applet
= qgraphicsitem_cast
<Applet
*>(watched
);
1153 // Otherwise we're watching something we shouldn't be...
1154 Q_ASSERT(applet
!= 0);
1155 if (!d
->applets
.contains(applet
)) {
1159 //kDebug() << "got sceneEvent";
1160 switch (event
->type()) {
1161 case QEvent::GraphicsSceneHoverEnter
:
1162 //kDebug() << "got hoverenterEvent" << immutability() << " " << applet->immutability();
1163 if (immutability() == Mutable
&& applet
->immutability() == Mutable
) {
1164 QGraphicsSceneHoverEvent
*he
= static_cast<QGraphicsSceneHoverEvent
*>(event
);
1165 if (d
->handles
.contains(applet
)) {
1166 AppletHandle
*handle
= d
->handles
.value(applet
);
1168 handle
->setHoverPos(he
->pos());
1171 //kDebug() << "generated applet handle";
1172 AppletHandle
*handle
= new AppletHandle(this, applet
, he
->pos());
1173 d
->handles
[applet
] = handle
;
1174 connect(handle
, SIGNAL(disappearDone(AppletHandle
*)),
1175 this, SLOT(handleDisappeared(AppletHandle
*)));
1176 connect(applet
, SIGNAL(geometryChanged()),
1177 handle
, SLOT(appletResized()));
1181 case QEvent::GraphicsSceneHoverMove
:
1182 if (immutability() == Mutable
&& applet
->immutability() == Mutable
) {
1183 QGraphicsSceneHoverEvent
*he
= static_cast<QGraphicsSceneHoverEvent
*>(event
);
1184 if (d
->handles
.contains(applet
)) {
1185 AppletHandle
*handle
= d
->handles
.value(applet
);
1187 handle
->setHoverPos(he
->pos());
1199 QVariant
Containment::itemChange(GraphicsItemChange change
, const QVariant
&value
)
1201 //FIXME if the applet is moved to another containment we need to unfocus it
1203 if (isContainment() && !ContainmentPrivate::s_positioning
&&
1204 (change
== QGraphicsItem::ItemSceneHasChanged
|| change
== QGraphicsItem::ItemPositionHasChanged
)) {
1206 case PanelContainment
:
1207 case CustomPanelContainment
:
1211 d
->positionContainments();
1216 return Applet::itemChange(change
, value
);
1219 void Containment::enableAction(const QString
&name
, bool enable
)
1221 QAction
*action
= this->action(name
);
1223 action
->setEnabled(enable
);
1224 action
->setVisible(enable
);
1228 void Containment::addToolBoxAction(QAction
*action
)
1230 if (!d
->toolBox
&& (d
->type
== CustomPanelContainment
|| d
->type
>= CustomContainment
)) {
1235 d
->toolBox
->addTool(action
);
1239 void Containment::removeToolBoxAction(QAction
*action
)
1242 d
->toolBox
->removeTool(action
);
1246 void Containment::setToolBoxOpen(bool open
)
1255 void Containment::openToolBox()
1258 d
->toolBox
->showToolBox();
1262 void Containment::closeToolBox()
1265 d
->toolBox
->hideToolBox();
1269 void Containment::addAssociatedWidget(QWidget
*widget
)
1271 Applet::addAssociatedWidget(widget
);
1272 if (d
->focusedApplet
) {
1273 d
->focusedApplet
->addAssociatedWidget(widget
);
1276 foreach (const Applet
*applet
, d
->applets
) {
1277 if (applet
->d
->activationAction
) {
1278 widget
->addAction(applet
->d
->activationAction
);
1283 void Containment::removeAssociatedWidget(QWidget
*widget
)
1285 Applet::removeAssociatedWidget(widget
);
1286 if (d
->focusedApplet
) {
1287 d
->focusedApplet
->removeAssociatedWidget(widget
);
1290 foreach (const Applet
*applet
, d
->applets
) {
1291 if (applet
->d
->activationAction
) {
1292 widget
->removeAction(applet
->d
->activationAction
);
1297 void Containment::setDrawWallpaper(bool drawWallpaper
)
1299 d
->drawWallpaper
= drawWallpaper
;
1300 if (drawWallpaper
) {
1301 KConfigGroup cfg
= config();
1302 QString wallpaper
= cfg
.readEntry("wallpaperplugin", defaultWallpaper
);
1303 QString mode
= cfg
.readEntry("wallpaperpluginmode", defaultWallpaperMode
);
1304 setWallpaper(wallpaper
, mode
);
1306 delete d
->wallpaper
;
1311 bool Containment::drawWallpaper()
1313 return d
->drawWallpaper
;
1316 void Containment::setWallpaper(const QString
&pluginName
, const QString
&mode
)
1318 KConfigGroup cfg
= config();
1319 bool newPlugin
= true;
1320 bool newMode
= true;
1322 if (d
->drawWallpaper
) {
1324 // we have a wallpaper, so let's decide whether we need to swap it out
1325 if (d
->wallpaper
->pluginName() != pluginName
) {
1326 delete d
->wallpaper
;
1329 // it's the same plugin, so let's save its state now so when
1330 // we call restore later on we're safe
1331 newMode
= d
->wallpaper
->renderingMode().name() != mode
;
1336 if (!pluginName
.isEmpty() && !d
->wallpaper
) {
1337 d
->wallpaper
= Plasma::Wallpaper::load(pluginName
);
1341 d
->wallpaper
->setBoundingRect(boundingRect());
1342 d
->wallpaper
->setRenderingMode(mode
);
1345 connect(d
->wallpaper
, SIGNAL(update(const QRectF
&)),
1346 this, SLOT(updateRect(const QRectF
&)));
1347 cfg
.writeEntry("wallpaperplugin", pluginName
);
1350 if (d
->wallpaper
->isInitialized()) {
1351 KConfigGroup wallpaperConfig
= KConfigGroup(&cfg
, "Wallpaper");
1352 wallpaperConfig
= KConfigGroup(&wallpaperConfig
, pluginName
);
1353 d
->wallpaper
->restore(wallpaperConfig
);
1357 cfg
.writeEntry("wallpaperpluginmode", mode
);
1364 if (!d
->wallpaper
) {
1365 cfg
.deleteEntry("wallpaperplugin");
1366 cfg
.deleteEntry("wallpaperpluginmode");
1369 if (newPlugin
|| newMode
) {
1370 emit
configNeedsSaving();
1374 Plasma::Wallpaper
*Containment::wallpaper() const
1376 return d
->wallpaper
;
1379 void Containment::setActivity(const QString
&activity
)
1381 Context
*context
= d
->context();
1382 if (context
->currentActivity() != activity
) {
1383 context
->setCurrentActivity(activity
);
1385 foreach (Applet
*a
, d
->applets
) {
1386 a
->updateConstraints(ContextConstraint
);
1389 KConfigGroup c
= config();
1390 c
.writeEntry("activity", activity
);
1391 emit
configNeedsSaving();
1395 QString
Containment::activity() const
1397 return d
->context()->currentActivity();
1400 Context
*ContainmentPrivate::context()
1403 con
= new Context(q
);
1404 q
->connect(con
, SIGNAL(changed(Plasma::Context
*)),
1405 q
, SIGNAL(contextChanged(Plasma::Context
*)));
1411 KActionCollection
&ContainmentPrivate::actions()
1413 return static_cast<Applet
*>(q
)->d
->actions
;
1416 void ContainmentPrivate::focusApplet(Plasma::Applet
*applet
)
1418 if (focusedApplet
== applet
) {
1422 QList
<QWidget
*> widgets
= actions().associatedWidgets();
1423 if (focusedApplet
) {
1424 foreach (QWidget
*w
, widgets
) {
1425 focusedApplet
->removeAssociatedWidget(w
);
1429 if (applet
&& applets
.contains(applet
)) {
1430 //kDebug() << "switching to" << applet->name();
1431 focusedApplet
= applet
;
1432 foreach (QWidget
*w
, widgets
) {
1433 focusedApplet
->addAssociatedWidget(w
);
1436 if (!focusedApplet
->hasFocus()) {
1437 focusedApplet
->setFocus(Qt::ShortcutFocusReason
);
1444 void Containment::focusNextApplet()
1446 if (d
->applets
.isEmpty()) {
1449 int index
= d
->focusedApplet
? d
->applets
.indexOf(d
->focusedApplet
) + 1 : 0;
1450 if (index
>= d
->applets
.size()) {
1453 kDebug() << "index" << index
;
1454 d
->focusApplet(d
->applets
.at(index
));
1457 void Containment::focusPreviousApplet()
1459 if (d
->applets
.isEmpty()) {
1462 int index
= d
->focusedApplet
? d
->applets
.indexOf(d
->focusedApplet
) - 1 : -1;
1464 index
= d
->applets
.size() - 1;
1466 kDebug() << "index" << index
;
1467 d
->focusApplet(d
->applets
.at(index
));
1470 void Containment::destroy()
1475 void Containment::showConfigurationInterface()
1477 Applet::showConfigurationInterface();
1480 void ContainmentPrivate::requestConfiguration()
1482 emit q
->configureRequested(q
);
1485 void Containment::destroy(bool confirm
)
1487 if (immutability() != Mutable
) {
1491 if (isContainment()) {
1492 //don't remove a desktop that's in use
1493 //FIXME: this should probably be based on whether any views care or not!
1494 // sth like: foreach (view) { view->requires(this); }
1496 if (d
->type
!= PanelContainment
&& d
->type
!= CustomPanelContainment
&&
1497 (d
->screen
!= -1 || d
->screen
>= corona()->numScreens())) {
1498 kDebug() << (QObject
*)this << "containment has a screen number?" << d
->screen
;
1502 //FIXME maybe that %1 should be the containment type not the name
1504 KMessageBox::warningContinueCancel(
1506 i18nc("%1 is the name of the containment", "Do you really want to remove this %1?", name()),
1507 i18nc("@title:window %1 is the name of the containment", "Remove %1", name()), KStandardGuiItem::remove()) == KMessageBox::Continue
) {
1516 void ContainmentPrivate::zoomIn()
1518 emit q
->zoomRequested(q
, Plasma::ZoomIn
);
1522 void ContainmentPrivate::zoomOut()
1524 emit q
->zoomRequested(q
, Plasma::ZoomOut
);
1528 ToolBox
*ContainmentPrivate::createToolBox()
1532 case Containment::PanelContainment
:
1533 case Containment::CustomPanelContainment
:
1534 toolBox
= new PanelToolBox(q
);
1535 toolBox
->setSize(KIconLoader::SizeSmallMedium
);
1536 toolBox
->setIconSize(QSize(KIconLoader::SizeSmall
, KIconLoader::SizeSmall
));
1537 if (q
->immutability() != Mutable
) {
1542 toolBox
= new DesktopToolBox(q
);
1543 toolBox
->setSize(KIconLoader::SizeSmallMedium
);
1544 toolBox
->setIconSize(QSize(KIconLoader::SizeSmall
, KIconLoader::SizeSmall
));
1549 QObject::connect(toolBox
, SIGNAL(toggled()), q
, SIGNAL(toolBoxToggled()));
1558 void ContainmentPrivate::positionToolBox()
1561 toolBox
->reposition();
1565 void ContainmentPrivate::triggerShowAddWidgets()
1567 emit q
->showAddWidgetsInterface(QPointF());
1570 void ContainmentPrivate::handleDisappeared(AppletHandle
*handle
)
1572 if (handles
.contains(handle
->applet())) {
1573 handles
.remove(handle
->applet());
1574 handle
->detachApplet();
1575 handle
->deleteLater();
1579 void ContainmentPrivate::checkRemoveAction()
1581 q
->enableAction("remove", (q
->immutability() == Mutable
&&
1583 type
== Plasma::Containment::PanelContainment
||
1584 type
== Plasma::Containment::CustomPanelContainment
)));
1587 void ContainmentPrivate::containmentConstraintsEvent(Plasma::Constraints constraints
)
1589 if (!q
->isContainment()) {
1593 //kDebug() << "got containmentConstraintsEvent" << constraints << (QObject*)toolBox;
1594 if (constraints
& Plasma::ImmutableConstraint
) {
1596 checkRemoveAction();
1597 bool unlocked
= q
->immutability() == Mutable
;
1598 q
->setAcceptDrops(unlocked
);
1599 q
->enableAction("add widgets", unlocked
);
1601 // tell the applets too
1602 foreach (Applet
*a
, applets
) {
1603 a
->updateConstraints(ImmutableConstraint
);
1607 if (type
== Containment::PanelContainment
|| type
== Containment::CustomPanelContainment
) {
1608 toolBox
->setVisible(unlocked
);
1610 toolBox
->setIsMovable(unlocked
);
1614 //clear handles on lock
1616 QMap
<Applet
*, AppletHandle
*> h
= handles
;
1619 foreach (AppletHandle
*handle
, h
) {
1620 handle
->disconnect(q
);
1621 handle
->deleteLater();
1626 if (constraints
& Plasma::FormFactorConstraint
) {
1627 foreach (Applet
*applet
, applets
) {
1628 applet
->updateConstraints(Plasma::FormFactorConstraint
);
1632 if (toolBox
&& (constraints
& Plasma::SizeConstraint
||
1633 constraints
& Plasma::FormFactorConstraint
||
1634 constraints
& Plasma::ScreenConstraint
||
1635 constraints
& Plasma::StartupCompletedConstraint
)) {
1636 //kDebug() << "Positioning toolbox";
1641 constraints
& Plasma::StartupCompletedConstraint
&&
1642 type
< Containment::CustomContainment
) {
1643 toolBox
->addTool(q
->action("remove"));
1644 checkRemoveAction();
1648 Applet
*ContainmentPrivate::addApplet(const QString
&name
, const QVariantList
&args
,
1649 const QRectF
&appletGeometry
, uint id
, bool delayInit
)
1651 if (!q
->isContainment()) {
1655 if (!delayInit
&& q
->immutability() != Mutable
) {
1656 kDebug() << "addApplet for" << name
<< "requested, but we're currently immutable!";
1660 QGraphicsView
*v
= q
->view();
1662 v
->setCursor(Qt::BusyCursor
);
1665 Applet
*applet
= Applet::load(name
, id
, args
);
1671 kDebug() << "Applet" << name
<< "could not be loaded.";
1672 applet
= new Applet(0, QString(), id
);
1673 applet
->setFailedToLaunch(true, i18n("Could not find requested component: %1", name
));
1676 //kDebug() << applet->name() << "sizehint:" << applet->sizeHint() << "geometry:" << applet->geometry();
1678 q
->addApplet(applet
, appletGeometry
.topLeft(), delayInit
);
1682 bool ContainmentPrivate::regionIsEmpty(const QRectF
®ion
, Applet
*ignoredApplet
) const
1684 foreach (Applet
*applet
, applets
) {
1685 if (applet
!= ignoredApplet
&& applet
->geometry().intersects(region
)) {
1692 void ContainmentPrivate::appletDestroyed(Plasma::Applet
*applet
)
1694 applets
.removeAll(applet
);
1695 if (focusedApplet
== applet
) {
1699 if (handles
.contains(applet
)) {
1700 AppletHandle
*handle
= handles
.value(applet
);
1701 handles
.remove(applet
);
1702 handle
->deleteLater();
1705 emit q
->appletRemoved(applet
);
1706 emit q
->configNeedsSaving();
1709 void ContainmentPrivate::containmentAppletAnimationComplete(QGraphicsItem
*item
, Plasma::Animator::Animation anim
)
1711 if (anim
== Animator::AppearAnimation
&&
1712 item
->parentItem() == q
) {
1713 Applet
*applet
= qgraphicsitem_cast
<Applet
*>(item
);
1716 if (type
== Containment::DesktopContainment
) {
1717 applet
->installSceneEventFilter(q
);
1720 KConfigGroup
*cg
= applet
->d
->mainConfigGroup();
1722 emit q
->configNeedsSaving();
1723 //applet->setWindowFlags(Qt::Window);
1728 bool containmentSortByPosition(const Containment
*c1
, const Containment
*c2
)
1730 return c1
->id() < c2
->id();
1733 void ContainmentPrivate::positionContainments()
1735 Corona
*c
= q
->corona();
1736 if (!c
|| ContainmentPrivate::s_positioning
) {
1740 ContainmentPrivate::s_positioning
= true;
1742 //TODO: we should avoid running this too often; consider compressing requests
1744 QList
<Containment
*> containments
= c
->containments();
1745 QMutableListIterator
<Containment
*> it(containments
);
1747 while (it
.hasNext()) {
1748 Containment
*containment
= it
.next();
1749 if (containment
->d
->type
== Containment::PanelContainment
||
1750 containment
->d
->type
== Containment::CustomPanelContainment
) {
1751 // weed out all containments we don't care about at all
1752 // e.g. Panels and ourself
1758 if (containments
.isEmpty()) {
1759 ContainmentPrivate::s_positioning
= false;
1763 qSort(containments
.begin(), containments
.end(), containmentSortByPosition
);
1772 //kDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++" << containments.count();
1773 while (it
.hasNext()) {
1774 Containment
*containment
= it
.next();
1775 containment
->setPos(x
, y
);
1776 //kDebug() << ++count << "setting to" << x << y;
1778 int height
= containment
->size().height();
1779 if (height
> rowHeight
) {
1785 if (column
== CONTAINMENT_COLUMNS
) {
1788 y
+= rowHeight
+ INTER_CONTAINMENT_MARGIN
+ TOOLBOX_MARGIN
;
1791 x
+= containment
->size().width() + INTER_CONTAINMENT_MARGIN
;
1793 //kDebug() << "column: " << column << "; x " << x << "; y" << y << "; width was"
1794 // << containment->size().width();
1796 //kDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++";
1798 ContainmentPrivate::s_positioning
= false;
1801 void ContainmentPrivate::positionPanel(bool force
)
1804 kDebug() << "no scene yet";
1808 // we position panels in negative coordinates, and stack all horizontal
1809 // and all vertical panels with each other.
1812 const QPointF p
= q
->pos();
1815 p
.y() + q
->size().height() < -INTER_CONTAINMENT_MARGIN
&&
1816 q
->scene()->collidingItems(q
).isEmpty()) {
1817 // already positioned and not running into any other panels
1821 //TODO: research how non-Horizontal, non-Vertical (e.g. Planar) panels behave here
1822 bool horiz
= formFactor
== Plasma::Horizontal
;
1823 qreal bottom
= horiz
? 0 : VERTICAL_STACKING_OFFSET
;
1824 qreal lastHeight
= 0;
1826 // this should be ok for small numbers of panels, but if we ever end
1827 // up managing hundreds of them, this simplistic alogrithm will
1828 // likely be too slow.
1829 foreach (const Containment
*other
, q
->corona()->containments()) {
1831 (other
->d
->type
!= Containment::PanelContainment
&&
1832 other
->d
->type
!= Containment::CustomPanelContainment
) ||
1833 horiz
!= (other
->formFactor() == Plasma::Horizontal
)) {
1834 // only line up with panels of the same orientation
1839 qreal y
= other
->pos().y();
1841 lastHeight
= other
->size().height();
1845 qreal width
= other
->size().width();
1846 qreal x
= other
->pos().x() + width
;
1849 bottom
= x
+ lastHeight
;
1854 kDebug() << "positioning" << (horiz
? "" : "non-") << "horizontal panel; forced?" << force
;
1855 // give a space equal to the height again of the last item so there is
1859 bottom
-= lastHeight
+ INTER_CONTAINMENT_MARGIN
;
1860 //TODO: fix x position for non-flush-left panels
1861 kDebug() << "moved to" << QPointF(0, bottom
- q
->size().height());
1862 newPos
= QPointF(0, bottom
- q
->size().height());
1864 bottom
+= lastHeight
+ INTER_CONTAINMENT_MARGIN
;
1865 //TODO: fix y position for non-flush-top panels
1866 kDebug() << "moved to" << QPointF(bottom
+ q
->size().width(), -INTER_CONTAINMENT_MARGIN
- q
->size().height());
1867 newPos
= QPointF(bottom
+ q
->size().width(), -INTER_CONTAINMENT_MARGIN
- q
->size().height());
1871 ContainmentPrivate::s_positioning
= true;
1873 ContainmentPrivate::s_positioning
= false;
1877 } // Plasma namespace
1879 #include "containment.moc"