• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

Plasma

  • plasma
corona.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2007 Matt Broadstone <mbroadst@gmail.com>
3  * Copyright 2007-2011 Aaron Seigo <aseigo@kde.org>
4  * Copyright 2007 Riccardo Iaconelli <riccardo@kde.org>
5  * Copyright (c) 2009 Chani Armitage <chani@kde.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Library General Public License as
9  * published by the Free Software Foundation; either version 2, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 #include "corona.h"
24 #include "private/corona_p.h"
25 
26 #include <QApplication>
27 #include <QDesktopWidget>
28 #include <QGraphicsView>
29 #include <QGraphicsSceneDragDropEvent>
30 #include <QGraphicsGridLayout>
31 #include <QMimeData>
32 #include <QPainter>
33 #include <QTimer>
34 
35 #include <cmath>
36 
37 #include <kaction.h>
38 #include <kdebug.h>
39 #include <kglobal.h>
40 #include <klocale.h>
41 #include <kmimetype.h>
42 #include <kshortcutsdialog.h>
43 #include <kwindowsystem.h>
44 
45 #include "animator.h"
46 #include "abstracttoolbox.h"
47 #include "containment.h"
48 #include "containmentactionspluginsconfig.h"
49 #include "view.h"
50 #include "private/animator_p.h"
51 #include "private/applet_p.h"
52 #include "private/containment_p.h"
53 #include "tooltipmanager.h"
54 #include "abstractdialogmanager.h"
55 
56 using namespace Plasma;
57 
58 namespace Plasma
59 {
60 
61 bool CoronaPrivate::s_positioningContainments = false;
62 
63 Corona::Corona(QObject *parent)
64  : QGraphicsScene(parent),
65  d(new CoronaPrivate(this))
66 {
67  kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Corona ctor start";
68  d->init();
69  ToolTipManager::self()->m_corona = this;
70  //setViewport(new QGLWidget(QGLFormat(QGL::StencilBuffer | QGL::AlphaChannel)));
71 }
72 
73 Corona::~Corona()
74 {
75  KConfigGroup trans(KGlobal::config(), "PlasmaTransientsConfig");
76  trans.deleteGroup();
77 
78  // FIXME: Same fix as in Plasma::View - make sure that when the focused widget is
79  // destroyed we don't try to transfer it to something that's already been
80  // deleted.
81  clearFocus();
82  delete d;
83 }
84 
85 void Corona::setAppletMimeType(const QString &type)
86 {
87  d->mimetype = type;
88 }
89 
90 QString Corona::appletMimeType()
91 {
92  return d->mimetype;
93 }
94 
95 void Corona::setDefaultContainmentPlugin(const QString &name)
96 {
97  // we could check if it is in:
98  // Containment::listContainments().contains(name) ||
99  // Containment::listContainments(QString(), KGlobal::mainComponent().componentName()).contains(name)
100  // but that seems like overkill
101  d->defaultContainmentPlugin = name;
102 }
103 
104 QString Corona::defaultContainmentPlugin() const
105 {
106  return d->defaultContainmentPlugin;
107 }
108 
109 void Corona::saveLayout(const QString &configName) const
110 {
111  KSharedConfigPtr c;
112 
113  if (configName.isEmpty() || configName == d->configName) {
114  c = config();
115  } else {
116  c = KSharedConfig::openConfig(configName, KConfig::SimpleConfig);
117  }
118 
119  d->saveLayout(c);
120 }
121 
122 void Corona::exportLayout(KConfigGroup &config, QList<Containment*> containments)
123 {
124  foreach (const QString &group, config.groupList()) {
125  KConfigGroup cg(&config, group);
126  cg.deleteGroup();
127  }
128 
129  //temporarily unlock so that removal works
130  ImmutabilityType oldImm = immutability();
131  d->immutability = Mutable;
132 
133  KConfigGroup dest(&config, "Containments");
134  KConfigGroup dummy;
135  foreach (Plasma::Containment *c, containments) {
136  c->save(dummy);
137  c->config().reparent(&dest);
138 
139  //ensure the containment is unlocked
140  //this is done directly because we have to bypass any SystemImmutable checks
141  c->Applet::d->immutability = Mutable;
142  foreach (Applet *a, c->applets()) {
143  a->d->immutability = Mutable;
144  }
145 
146  c->destroy(false);
147  }
148 
149  //restore immutability
150  d->immutability = oldImm;
151 
152  config.sync();
153 }
154 
155 void Corona::requestConfigSync()
156 {
157  // constant controlling how long between requesting a configuration sync
158  // and one happening should occur. currently 10 seconds
159  static const int CONFIG_SYNC_TIMEOUT = 10000;
160 
161  // TODO: should we check into our immutability before doing this?
162 
163  //NOTE: this is a pretty simplistic model: we simply save no more than CONFIG_SYNC_TIMEOUT
164  // after the first time this is called. not much of a heuristic for save points, but
165  // it should at least compress these activities a bit and provide a way for applet
166  // authors to ween themselves from the sync() disease. A more interesting/dynamic
167  // algorithm for determining when to actually sync() to disk might be better, though.
168  if (!d->configSyncTimer.isActive()) {
169  d->configSyncTimer.start(CONFIG_SYNC_TIMEOUT);
170  }
171 }
172 
173 void Corona::requireConfigSync()
174 {
175  d->syncConfig();
176 }
177 
178 void Corona::initializeLayout(const QString &configName)
179 {
180  clearContainments();
181  loadLayout(configName);
182 
183  if (d->containments.isEmpty()) {
184  loadDefaultLayout();
185  if (!d->containments.isEmpty()) {
186  requestConfigSync();
187  }
188  }
189 
190  if (config()->isImmutable()) {
191  setImmutability(SystemImmutable);
192  } else {
193  KConfigGroup coronaConfig(config(), "General");
194  setImmutability((ImmutabilityType)coronaConfig.readEntry("immutability", (int)Mutable));
195  }
196 }
197 
198 bool containmentSortByPosition(const Containment *c1, const Containment *c2)
199 {
200  return c1->id() < c2->id();
201 }
202 
203 void Corona::layoutContainments()
204 {
205  if (CoronaPrivate::s_positioningContainments) {
206  return;
207  }
208 
209  CoronaPrivate::s_positioningContainments = true;
210 
211  //TODO: we should avoid running this too often; consider compressing requests
212  // with a timer.
213  QList<Containment*> c = containments();
214  QMutableListIterator<Containment*> it(c);
215 
216  while (it.hasNext()) {
217  Containment *containment = it.next();
218  if (containment->containmentType() == Containment::PanelContainment ||
219  containment->containmentType() == Containment::CustomPanelContainment ||
220  offscreenWidgets().contains(containment)) {
221  // weed out all containments we don't care about at all
222  // e.g. Panels and ourself
223  it.remove();
224  continue;
225  }
226  }
227 
228  qSort(c.begin(), c.end(), containmentSortByPosition);
229 
230  if (c.isEmpty()) {
231  CoronaPrivate::s_positioningContainments = false;
232  return;
233  }
234 
235  int column = 0;
236  int x = 0;
237  int y = 0;
238  int rowHeight = 0;
239 
240  it.toFront();
241  while (it.hasNext()) {
242  Containment *containment = it.next();
243  containment->setPos(x, y);
244  //kDebug() << ++count << "setting to" << x << y;
245 
246  int height = containment->size().height();
247  if (height > rowHeight) {
248  rowHeight = height;
249  }
250 
251  ++column;
252 
253  if (column == CONTAINMENT_COLUMNS) {
254  column = 0;
255  x = 0;
256  y += rowHeight + INTER_CONTAINMENT_MARGIN + TOOLBOX_MARGIN;
257  rowHeight = 0;
258  } else {
259  x += containment->size().width() + INTER_CONTAINMENT_MARGIN;
260  }
261  //kDebug() << "column: " << column << "; x " << x << "; y" << y << "; width was"
262  // << containment->size().width();
263  }
264 
265  CoronaPrivate::s_positioningContainments = false;
266 }
267 
268 
269 void Corona::loadLayout(const QString &configName)
270 {
271  if (!configName.isEmpty() && configName != d->configName) {
272  // if we have a new config name passed in, then use that as the config file for this Corona
273  d->config = 0;
274  d->configName = configName;
275  }
276 
277  KSharedConfigPtr conf = config();
278  d->importLayout(*conf, false);
279 }
280 
281 QList<Plasma::Containment *> Corona::importLayout(const KConfigGroup &conf)
282 {
283  return d->importLayout(conf, true);
284 }
285 
286 #ifndef KDE_NO_DEPRECATED
287 QList<Plasma::Containment *> Corona::importLayout(const KConfigBase &conf)
288 {
289  return d->importLayout(conf, true);
290 }
291 #endif
292 
293 Containment *Corona::containmentForScreen(int screen, int desktop) const
294 {
295  foreach (Containment *containment, d->containments) {
296  if (containment->screen() == screen &&
297  (desktop < 0 || containment->desktop() == desktop) &&
298  (containment->containmentType() == Containment::DesktopContainment ||
299  containment->containmentType() == Containment::CustomContainment)) {
300  return containment;
301  }
302  }
303 
304  return 0;
305 }
306 
307 Containment *Corona::containmentForScreen(int screen, int desktop,
308  const QString &defaultPluginIfNonExistent, const QVariantList &defaultArgs)
309 {
310  Containment *containment = containmentForScreen(screen, desktop);
311  if (!containment && !defaultPluginIfNonExistent.isEmpty()) {
312  // screen requests are allowed to bypass immutability
313  if (screen >= 0 && screen < numScreens() &&
314  desktop >= -1 && desktop < KWindowSystem::numberOfDesktops()) {
315  containment = d->addContainment(defaultPluginIfNonExistent, defaultArgs, 0, false);
316  if (containment) {
317  containment->setScreen(screen, desktop);
318  }
319  }
320  }
321 
322  return containment;
323 }
324 
325 QList<Containment*> Corona::containments() const
326 {
327  return d->containments;
328 }
329 
330 void Corona::clearContainments()
331 {
332  foreach (Containment *containment, d->containments) {
333  containment->clearApplets();
334  }
335 }
336 
337 KSharedConfigPtr Corona::config() const
338 {
339  if (!d->config) {
340  d->config = KSharedConfig::openConfig(d->configName, KConfig::SimpleConfig);
341  }
342 
343  return d->config;
344 }
345 
346 Containment *Corona::addContainment(const QString &name, const QVariantList &args)
347 {
348  if (d->immutability == Mutable) {
349  return d->addContainment(name, args, 0, false);
350  }
351 
352  return 0;
353 }
354 
355 Containment *Corona::addContainmentDelayed(const QString &name, const QVariantList &args)
356 {
357  if (d->immutability == Mutable) {
358  return d->addContainment(name, args, 0, true);
359  }
360 
361  return 0;
362 }
363 
364 void Corona::mapAnimation(Animator::Animation from, Animator::Animation to)
365 {
366  AnimatorPrivate::mapAnimation(from, to);
367 }
368 
369 void Corona::mapAnimation(Animator::Animation from, const QString &to)
370 {
371  AnimatorPrivate::mapAnimation(from, to);
372 }
373 
374 void Corona::addOffscreenWidget(QGraphicsWidget *widget)
375 {
376  foreach (QGraphicsWidget *w, d->offscreenWidgets) {
377  if (w == widget) {
378  kDebug() << "widget is already an offscreen widget!";
379  return;
380  }
381  }
382 
383  //search for an empty spot in the topleft quadrant of the scene. each 'slot' is QWIDGETSIZE_MAX
384  //x QWIDGETSIZE_MAX, so we're guaranteed to never have to move widgets once they're placed here.
385  int i = 0;
386  while (d->offscreenWidgets.contains(i)) {
387  i++;
388  }
389 
390  d->offscreenWidgets[i] = widget;
391  widget->setPos((-i - 1) * QWIDGETSIZE_MAX, -QWIDGETSIZE_MAX);
392 
393  QGraphicsWidget *pw = widget->parentWidget();
394  widget->setParentItem(0);
395  if (pw) {
396  widget->setParent(pw);
397  }
398 
399  //kDebug() << "adding offscreen widget at slot " << i;
400  if (!widget->scene()) {
401  addItem(widget);
402  }
403 
404  connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(offscreenWidgetDestroyed(QObject*)));
405 }
406 
407 void Corona::removeOffscreenWidget(QGraphicsWidget *widget)
408 {
409  QMutableHashIterator<uint, QGraphicsWidget *> it(d->offscreenWidgets);
410 
411  while (it.hasNext()) {
412  if (it.next().value() == widget) {
413  it.remove();
414  return;
415  }
416  }
417 }
418 
419 QList <QGraphicsWidget *> Corona::offscreenWidgets() const
420 {
421  return d->offscreenWidgets.values();
422 }
423 
424 void CoronaPrivate::offscreenWidgetDestroyed(QObject *o)
425 {
426  // at this point, it's just a QObject, not a QGraphicsWidget, but we still need
427  // a pointer of the appropriate type.
428  // WARNING: DO NOT USE THE WIDGET POINTER FOR ANYTHING OTHER THAN POINTER COMPARISONS
429  QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(o);
430  q->removeOffscreenWidget(widget);
431 }
432 
433 int Corona::numScreens() const
434 {
435  return 1;
436 }
437 
438 QRect Corona::screenGeometry(int id) const
439 {
440  Q_UNUSED(id);
441  QGraphicsView *v = views().value(0);
442  if (v) {
443  QRect r = sceneRect().toRect();
444  r.moveTo(v->mapToGlobal(QPoint(0, 0)));
445  return r;
446  }
447 
448  return sceneRect().toRect();
449 }
450 
451 QRegion Corona::availableScreenRegion(int id) const
452 {
453  return QRegion(screenGeometry(id));
454 }
455 
456 QPoint Corona::popupPosition(const QGraphicsItem *item, const QSize &s)
457 {
458  return popupPosition(item, s, Qt::AlignLeft);
459 }
460 
461 QPoint Corona::popupPosition(const QGraphicsItem *item, const QSize &s, Qt::AlignmentFlag alignment)
462 {
463  // TODO: merge both methods (also these in Applet) into one (with optional alignment) when we can break compatibility
464  // TODO: add support for more flags in the future?
465 
466  const QGraphicsItem *actualItem = item;
467 
468  const QGraphicsView *v = viewFor(item);
469 
470  if (!v) {
471  return QPoint(0, 0);
472  }
473 
474  //its own view could be hidden, for instance if item is in an hidden Dialog
475  //try to position it using the parent applet as the item
476  if (!v->isVisible()) {
477  actualItem = item->parentItem();
478  if (!actualItem) {
479  const QGraphicsWidget *widget = qgraphicsitem_cast<const QGraphicsWidget*>(item);
480  if (widget) {
481  actualItem = qobject_cast<QGraphicsItem*>(widget->parent());
482  }
483  }
484 
485  //kDebug() << actualItem;
486 
487  if (actualItem) {
488  v = viewFor(actualItem);
489  if (!v) {
490  return QPoint(0, 0);
491  }
492  }
493  }
494 
495  if (!actualItem) {
496  actualItem = item;
497  }
498 
499  QPoint pos;
500  QTransform sceneTransform = actualItem->sceneTransform();
501 
502  //swap direction if necessary
503  if (QApplication::isRightToLeft() && alignment != Qt::AlignCenter) {
504  if (alignment == Qt::AlignRight) {
505  alignment = Qt::AlignLeft;
506  } else {
507  alignment = Qt::AlignRight;
508  }
509  }
510 
511  //if the applet is rotated the popup position has to be un-transformed
512  if (sceneTransform.isRotating()) {
513  qreal angle = acos(sceneTransform.m11());
514  QTransform newTransform;
515  QPointF center = actualItem->sceneBoundingRect().center();
516 
517  newTransform.translate(center.x(), center.y());
518  newTransform.rotateRadians(-angle);
519  newTransform.translate(-center.x(), -center.y());
520  pos = v->mapFromScene(newTransform.inverted().map(actualItem->scenePos()));
521  } else {
522  pos = v->mapFromScene(actualItem->scenePos());
523  }
524 
525  pos = v->mapToGlobal(pos);
526  //kDebug() << "==> position is" << actualItem->scenePos() << v->mapFromScene(actualItem->scenePos()) << pos;
527  const Plasma::View *pv = qobject_cast<const Plasma::View *>(v);
528 
529  Plasma::Location loc = Floating;
530  if (pv && pv->containment()) {
531  loc = pv->containment()->location();
532  }
533 
534  switch (loc) {
535  case BottomEdge:
536  case TopEdge: {
537  if (alignment == Qt::AlignCenter) {
538  pos.setX(pos.x() + actualItem->boundingRect().width()/2 - s.width()/2);
539  } else if (alignment == Qt::AlignRight) {
540  pos.setX(pos.x() + actualItem->boundingRect().width() - s.width());
541  }
542 
543  if (pos.x() + s.width() > v->geometry().x() + v->geometry().width()) {
544  pos.setX((v->geometry().x() + v->geometry().width()) - s.width());
545  } else {
546  pos.setX(qMax(pos.x(), v->geometry().left()));
547  }
548  break;
549  }
550  case LeftEdge:
551  case RightEdge: {
552  if (alignment == Qt::AlignCenter) {
553  pos.setY(pos.y() + actualItem->boundingRect().height()/2 - s.height()/2);
554  } else if (alignment == Qt::AlignRight) {
555  pos.setY(pos.y() + actualItem->boundingRect().height() - s.height());
556  }
557 
558  if (pos.y() + s.height() > v->geometry().y() + v->geometry().height()) {
559  pos.setY((v->geometry().y() + v->geometry().height()) - s.height());
560  } else {
561  pos.setY(qMax(pos.y(), v->geometry().top()));
562  }
563  break;
564  }
565  default:
566  if (alignment == Qt::AlignCenter) {
567  pos.setX(pos.x() + actualItem->boundingRect().width()/2 - s.width()/2);
568  } else if (alignment == Qt::AlignRight) {
569  pos.setX(pos.x() + actualItem->boundingRect().width() - s.width());
570  }
571  break;
572  }
573 
574 
575  //are we out of screen?
576  int screen = ((pv && pv->containment()) ? pv->containment()->screen() : -1);
577  if (screen == -1) {
578  if (pv) {
579  screen = pv->screen();
580  } else {
581  // fall back to asking the actual system what screen the view is on
582  // in the case we are dealing with a non-PlasmaView QGraphicsView
583  screen = QApplication::desktop()->screenNumber(v);
584  }
585  }
586 
587  QRect screenRect = screenGeometry(screen);
588 
589  switch (loc) {
590  case BottomEdge:
591  pos.setY(v->geometry().y() - s.height());
592  break;
593  case TopEdge:
594  pos.setY(v->geometry().y() + v->geometry().height());
595  break;
596  case LeftEdge:
597  pos.setX(v->geometry().x() + v->geometry().width());
598  break;
599  case RightEdge:
600  pos.setX(v->geometry().x() - s.width());
601  break;
602  default:
603  if (pos.y() - s.height() > screenRect.top()) {
604  pos.ry() = pos.y() - s.height();
605  } else {
606  pos.ry() = pos.y() + (int)actualItem->boundingRect().size().height() + 1;
607  }
608  }
609 
610  //kDebug() << "==> rect for" << screen << "is" << screenRect;
611 
612  if (loc != LeftEdge && pos.x() + s.width() > screenRect.x() + screenRect.width()) {
613  pos.rx() -= ((pos.x() + s.width()) - (screenRect.x() + screenRect.width()));
614  }
615 
616  if (loc != TopEdge && pos.y() + s.height() > screenRect.y() + screenRect.height()) {
617  pos.ry() -= ((pos.y() + s.height()) - (screenRect.y() + screenRect.height()));
618  }
619 
620  pos.rx() = qMax(0, pos.x());
621  pos.ry() = qMax(0, pos.y());
622  return pos;
623 }
624 
625 void Corona::loadDefaultLayout()
626 {
627 }
628 
629 void Corona::setPreferredToolBoxPlugin(const Containment::Type type, const QString &plugin)
630 {
631  d->toolBoxPlugins[type] = plugin;
632  //TODO: react to plugin changes on the fly? still don't see the use case (maybe for laptops that become tablets?)
633 }
634 
635 QString Corona::preferredToolBoxPlugin(const Containment::Type type) const
636 {
637  return d->toolBoxPlugins.value(type);
638 }
639 
640 void Corona::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
641 {
642  QGraphicsScene::dragEnterEvent(event);
643 }
644 
645 void Corona::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
646 {
647  QGraphicsScene::dragLeaveEvent(event);
648 }
649 
650 void Corona::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
651 {
652  QGraphicsScene::dragMoveEvent(event);
653 }
654 
655 ImmutabilityType Corona::immutability() const
656 {
657  return d->immutability;
658 }
659 
660 void Corona::setImmutability(const ImmutabilityType immutable)
661 {
662  if (d->immutability == immutable || d->immutability == SystemImmutable) {
663  return;
664  }
665 
666  kDebug() << "setting immutability to" << immutable;
667  d->immutability = immutable;
668  d->updateContainmentImmutability();
669  //tell non-containments that might care (like plasmaapp or a custom corona)
670  emit immutabilityChanged(immutable);
671 
672  //update our actions
673  QAction *action = d->actions.action("lock widgets");
674  if (action) {
675  if (d->immutability == SystemImmutable) {
676  action->setEnabled(false);
677  action->setVisible(false);
678  } else {
679  bool unlocked = d->immutability == Mutable;
680  action->setText(unlocked ? i18n("Lock Widgets") : i18n("Unlock Widgets"));
681  action->setIcon(KIcon(unlocked ? "object-locked" : "object-unlocked"));
682  action->setEnabled(true);
683  action->setVisible(true);
684  }
685  }
686 
687  if (d->immutability != SystemImmutable) {
688  KConfigGroup cg(config(), "General");
689 
690  // we call the dptr member directly for locked since isImmutable()
691  // also checks kiosk and parent containers
692  cg.writeEntry("immutability", (int)d->immutability);
693  requestConfigSync();
694  }
695 }
696 
697 QList<Plasma::Location> Corona::freeEdges(int screen) const
698 {
699  QList<Plasma::Location> freeEdges;
700  freeEdges << Plasma::TopEdge << Plasma::BottomEdge
701  << Plasma::LeftEdge << Plasma::RightEdge;
702 
703  foreach (Containment *containment, containments()) {
704  if (containment->screen() == screen &&
705  freeEdges.contains(containment->location())) {
706  freeEdges.removeAll(containment->location());
707  }
708  }
709 
710  return freeEdges;
711 }
712 
713 QAction *Corona::action(QString name) const
714 {
715  return d->actions.action(name);
716 }
717 
718 void Corona::addAction(QString name, QAction *action)
719 {
720  d->actions.addAction(name, action);
721 }
722 
723 KAction* Corona::addAction(QString name)
724 {
725  return d->actions.addAction(name);
726 }
727 
728 QList<QAction*> Corona::actions() const
729 {
730  return d->actions.actions();
731 }
732 
733 void Corona::enableAction(const QString &name, bool enable)
734 {
735  QAction *action = d->actions.action(name);
736  if (action) {
737  action->setEnabled(enable);
738  action->setVisible(enable);
739  }
740 }
741 
742 void Corona::updateShortcuts()
743 {
744  QMutableListIterator<QWeakPointer<KActionCollection> > it(d->actionCollections);
745  while (it.hasNext()) {
746  it.next();
747  KActionCollection *collection = it.value().data();
748  if (!collection) {
749  // get rid of KActionCollections that have been deleted behind our backs
750  it.remove();
751  continue;
752  }
753 
754  collection->readSettings();
755  if (d->shortcutsDlg) {
756  d->shortcutsDlg.data()->addCollection(collection);
757  }
758  }
759 }
760 
761 void Corona::addShortcuts(KActionCollection *newShortcuts)
762 {
763  d->actionCollections << newShortcuts;
764  if (d->shortcutsDlg) {
765  d->shortcutsDlg.data()->addCollection(newShortcuts);
766  }
767 }
768 
769 void Corona::setContainmentActionsDefaults(Containment::Type containmentType, const ContainmentActionsPluginsConfig &config)
770 {
771  d->containmentActionsDefaults.insert(containmentType, config);
772 }
773 
774 ContainmentActionsPluginsConfig Corona::containmentActionsDefaults(Containment::Type containmentType)
775 {
776  return d->containmentActionsDefaults.value(containmentType);
777 }
778 
779 void Corona::setDialogManager(AbstractDialogManager *dialogManager)
780 {
781  d->dialogManager = dialogManager;
782 }
783 
784 AbstractDialogManager *Corona::dialogManager()
785 {
786  return d->dialogManager.data();
787 }
788 
789 CoronaPrivate::CoronaPrivate(Corona *corona)
790  : q(corona),
791  immutability(Mutable),
792  mimetype("text/x-plasmoidservicename"),
793  defaultContainmentPlugin("desktop"),
794  config(0),
795  actions(corona)
796 {
797  if (KGlobal::hasMainComponent()) {
798  configName = KGlobal::mainComponent().componentName() + "-appletsrc";
799  } else {
800  configName = "plasma-appletsrc";
801  }
802 }
803 
804 CoronaPrivate::~CoronaPrivate()
805 {
806  qDeleteAll(containments);
807 }
808 
809 void CoronaPrivate::init()
810 {
811  q->setStickyFocus(true);
812  configSyncTimer.setSingleShot(true);
813  QObject::connect(&configSyncTimer, SIGNAL(timeout()), q, SLOT(syncConfig()));
814 
815  //some common actions
816  actions.setConfigGroup("Shortcuts");
817 
818  KAction *lockAction = actions.addAction("lock widgets");
819  QObject::connect(lockAction, SIGNAL(triggered(bool)), q, SLOT(toggleImmutability()));
820  lockAction->setText(i18n("Lock Widgets"));
821  lockAction->setAutoRepeat(true);
822  lockAction->setIcon(KIcon("object-locked"));
823  lockAction->setData(AbstractToolBox::ControlTool);
824  lockAction->setShortcut(KShortcut("alt+d, l"));
825  lockAction->setShortcutContext(Qt::ApplicationShortcut);
826 
827  //FIXME this doesn't really belong here. desktop KCM maybe?
828  //but should the shortcuts be per-app or really-global?
829  //I don't know how to make kactioncollections use plasmarc
830  KAction *action = actions.addAction("configure shortcuts");
831  QObject::connect(action, SIGNAL(triggered()), q, SLOT(showShortcutConfig()));
832  action->setText(i18n("Shortcut Settings"));
833  action->setIcon(KIcon("configure-shortcuts"));
834  action->setAutoRepeat(false);
835  action->setData(AbstractToolBox::ConfigureTool);
836  //action->setShortcut(KShortcut("ctrl+h"));
837  action->setShortcutContext(Qt::ApplicationShortcut);
838 
839  //fake containment/applet actions
840  KActionCollection *containmentActions = AppletPrivate::defaultActions(q); //containment has to start with applet stuff
841  ContainmentPrivate::addDefaultActions(containmentActions); //now it's really containment
842  actionCollections << &actions << AppletPrivate::defaultActions(q) << containmentActions;
843  q->updateShortcuts();
844 }
845 
846 void CoronaPrivate::showShortcutConfig()
847 {
848  //show a kshortcutsdialog with the actions
849  KShortcutsDialog *dlg = shortcutsDlg.data();
850  if (!dlg) {
851  dlg = new KShortcutsDialog();
852  dlg->setModal(false);
853  dlg->setAttribute(Qt::WA_DeleteOnClose, true);
854  QObject::connect(dlg, SIGNAL(saved()), q, SIGNAL(shortcutsChanged()));
855 
856  dlg->addCollection(&actions);
857  QMutableListIterator<QWeakPointer<KActionCollection> > it(actionCollections);
858  while (it.hasNext()) {
859  it.next();
860  KActionCollection *collection = it.value().data();
861  if (!collection) {
862  // get rid of KActionCollections that have been deleted behind our backs
863  it.remove();
864  continue;
865  }
866 
867  dlg->addCollection(collection);
868  }
869  }
870 
871  KWindowSystem::setOnDesktop(dlg->winId(), KWindowSystem::currentDesktop());
872  dlg->configure();
873  dlg->raise();
874 }
875 
876 void CoronaPrivate::toggleImmutability()
877 {
878  if (immutability == Mutable) {
879  q->setImmutability(UserImmutable);
880  } else {
881  q->setImmutability(Mutable);
882  }
883 }
884 
885 void CoronaPrivate::saveLayout(KSharedConfigPtr cg) const
886 {
887  KConfigGroup containmentsGroup(cg, "Containments");
888  foreach (const Containment *containment, containments) {
889  QString cid = QString::number(containment->id());
890  KConfigGroup containmentConfig(&containmentsGroup, cid);
891  containment->save(containmentConfig);
892  }
893 }
894 
895 void CoronaPrivate::updateContainmentImmutability()
896 {
897  foreach (Containment *c, containments) {
898  // we need to tell each containment that immutability has been altered
899  c->updateConstraints(ImmutableConstraint);
900  }
901 }
902 
903 void CoronaPrivate::containmentDestroyed(QObject *obj)
904 {
905  // we do a static_cast here since it really isn't an Containment by this
906  // point anymore since we are in the qobject dtor. we don't actually
907  // try and do anything with it, we just need the value of the pointer
908  // so this unsafe looking code is actually just fine.
909  Containment* containment = static_cast<Plasma::Containment*>(obj);
910  int index = containments.indexOf(containment);
911 
912  if (index > -1) {
913  containments.removeAt(index);
914  q->requestConfigSync();
915  }
916  }
917 
918 void CoronaPrivate::syncConfig()
919 {
920  q->config()->sync();
921  emit q->configSynced();
922 }
923 
924 Containment *CoronaPrivate::addContainment(const QString &name, const QVariantList &args, uint id, bool delayedInit)
925 {
926  QString pluginName = name;
927  Containment *containment = 0;
928  Applet *applet = 0;
929 
930  //kDebug() << "Loading" << name << args << id;
931 
932  if (pluginName.isEmpty() || pluginName == "default") {
933  // default to the desktop containment
934  pluginName = defaultContainmentPlugin;
935  }
936 
937  bool loadingNull = pluginName == "null";
938  if (!loadingNull) {
939  applet = Applet::load(pluginName, id, args);
940  containment = dynamic_cast<Containment*>(applet);
941  }
942 
943  if (!containment) {
944  if (!loadingNull) {
945  kDebug() << "loading of containment" << name << "failed.";
946  }
947 
948  // in case we got a non-Containment from Applet::loadApplet or
949  // a null containment was requested
950  if (applet) {
951  // the applet probably doesn't know what's hit it, so let's pretend it can be
952  // initialized to make assumptions in the applet's dtor safer
953  q->addItem(applet);
954  applet->init();
955  q->removeItem(applet);
956  delete applet;
957  }
958  applet = containment = new Containment(0, 0, id);
959 
960  if (loadingNull) {
961  containment->setDrawWallpaper(false);
962  } else {
963  containment->setFailedToLaunch(false);
964  }
965 
966  // we want to provide something and don't care about the failure to launch
967  containment->setFormFactor(Plasma::Planar);
968  }
969 
970  // if this is a new containment, we need to ensure that there are no stale
971  // configuration data around
972  if (id == 0) {
973  KConfigGroup conf(q->config(), "Containments");
974  conf = KConfigGroup(&conf, QString::number(containment->id()));
975  conf.deleteGroup();
976  }
977 
978  applet->d->isContainment = true;
979  containment->setPos(containment->d->preferredPos(q));
980  q->addItem(containment);
981  applet->d->setIsContainment(true, true);
982  containments.append(containment);
983 
984  if (!delayedInit) {
985  containment->init();
986  KConfigGroup cg = containment->config();
987  containment->restore(cg);
988  containment->updateConstraints(Plasma::StartupCompletedConstraint);
989  containment->save(cg);
990  q->requestConfigSync();
991  containment->flushPendingConstraintsEvents();
992  }
993 
994  QObject::connect(containment, SIGNAL(destroyed(QObject*)),
995  q, SLOT(containmentDestroyed(QObject*)));
996  QObject::connect(containment, SIGNAL(configNeedsSaving()),
997  q, SLOT(requestConfigSync()));
998  QObject::connect(containment, SIGNAL(releaseVisualFocus()),
999  q, SIGNAL(releaseVisualFocus()));
1000  QObject::connect(containment, SIGNAL(screenChanged(int,int,Plasma::Containment*)),
1001  q, SIGNAL(screenOwnerChanged(int,int,Plasma::Containment*)));
1002 
1003  if (!delayedInit) {
1004  emit q->containmentAdded(containment);
1005  }
1006 
1007  return containment;
1008 }
1009 
1010 QList<Plasma::Containment *> CoronaPrivate::importLayout(const KConfigBase &conf, bool mergeConfig)
1011 {
1012  if (const KConfigGroup *group = dynamic_cast<const KConfigGroup *>(&conf)) {
1013  if (!group->isValid()) {
1014  return QList<Containment *>();
1015  }
1016  }
1017 
1018  QList<Plasma::Containment *> newContainments;
1019  QSet<uint> containmentsIds;
1020 
1021  foreach (Containment *containment, containments) {
1022  containmentsIds.insert(containment->id());
1023  }
1024 
1025  KConfigGroup containmentsGroup(&conf, "Containments");
1026 
1027  foreach (const QString &group, containmentsGroup.groupList()) {
1028  KConfigGroup containmentConfig(&containmentsGroup, group);
1029 
1030  if (containmentConfig.entryMap().isEmpty()) {
1031  continue;
1032  }
1033 
1034  uint cid = group.toUInt();
1035  if (containmentsIds.contains(cid)) {
1036  cid = ++AppletPrivate::s_maxAppletId;
1037  } else if (cid > AppletPrivate::s_maxAppletId) {
1038  AppletPrivate::s_maxAppletId = cid;
1039  }
1040 
1041  if (mergeConfig) {
1042  KConfigGroup realConf(q->config(), "Containments");
1043  realConf = KConfigGroup(&realConf, QString::number(cid));
1044  // in case something was there before us
1045  realConf.deleteGroup();
1046  containmentConfig.copyTo(&realConf);
1047  }
1048 
1049  //kDebug() << "got a containment in the config, trying to make a" << containmentConfig.readEntry("plugin", QString()) << "from" << group;
1050  kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Adding Containment" << containmentConfig.readEntry("plugin", QString());
1051  Containment *c = addContainment(containmentConfig.readEntry("plugin", QString()), QVariantList(), cid, true);
1052  if (!c) {
1053  continue;
1054  }
1055 
1056  newContainments.append(c);
1057  containmentsIds.insert(c->id());
1058 
1059  c->init();
1060  kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Init Containment" << c->pluginName();
1061  c->restore(containmentConfig);
1062  kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Restored Containment" << c->pluginName();
1063  }
1064 
1065  foreach (Containment *containment, newContainments) {
1066  containment->updateConstraints(Plasma::StartupCompletedConstraint);
1067  containment->d->initApplets();
1068  emit q->containmentAdded(containment);
1069  kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "Containment" << containment->name();
1070  }
1071 
1072  return newContainments;
1073 }
1074 
1075 } // namespace Plasma
1076 
1077 #include "corona.moc"
1078 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Mon Jul 15 2013 13:03:23 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.10.5 API Reference

Skip menu "kdelibs-4.10.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal