00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "corona.h"
00023
00024 #include <QApplication>
00025 #include <QDesktopWidget>
00026 #include <QGraphicsSceneDragDropEvent>
00027 #include <QMimeData>
00028 #include <QUrl>
00029 #include <QGraphicsView>
00030 #include <QStringList>
00031 #include <QTimer>
00032
00033 #include <KDebug>
00034 #include <KLocale>
00035 #include <KMimeType>
00036 #include <KWindowSystem>
00037
00038 #include "containment.h"
00039 #include "dataengine.h"
00040 #include "phase.h"
00041 #include "layouts/layout.h"
00042 #include "widgets/icon.h"
00043
00044 using namespace Plasma;
00045
00046 namespace Plasma
00047 {
00048
00049
00050
00051 const int CONFIG_SYNC_TIMEOUT = 120000;
00052
00053 class Corona::Private
00054 {
00055 public:
00056 Private()
00057 : immutable(false),
00058 kioskImmutable(false),
00059 mimetype("text/x-plasmoidservicename"),
00060 configName("plasma-appletsrc"),
00061 config(0)
00062 {
00063 }
00064
00065 ~Private()
00066 {
00067 qDeleteAll(containments);
00068 }
00069
00070 void init(Corona* q)
00071 {
00072 configSyncTimer.setSingleShot(true);
00073 connect(&configSyncTimer, SIGNAL(timeout()), q, SLOT(syncConfig()));
00074 QObject::connect(QApplication::desktop(), SIGNAL(resized(int)), q, SLOT(screenResized(int)));
00075 }
00076
00077 void saveApplets(KSharedConfigPtr cg) const
00078 {
00079 KConfigGroup containmentsGroup(cg, "Containments");
00080 foreach (const Containment *containment, containments) {
00081 QString cid = QString::number(containment->id());
00082 KConfigGroup containmentConfig(&containmentsGroup, cid);
00083 containment->saveConstraints(&containmentConfig);
00084 containment->save(&containmentConfig);
00085 KConfigGroup applets(&containmentConfig, "Applets");
00086 foreach (const Applet* applet, containment->applets()) {
00087 KConfigGroup appletConfig(&applets, QString::number(applet->id()));
00088 applet->save(&appletConfig);
00089 }
00090 }
00091 }
00092
00093 void updateContainmentImmutability()
00094 {
00095 foreach (Containment *c, containments) {
00096
00097
00098 c->updateConstraints(ImmutableConstraint);
00099 }
00100 }
00101
00102 bool immutable;
00103 bool kioskImmutable;
00104 QString mimetype;
00105 QString configName;
00106 KSharedConfigPtr config;
00107 QTimer configSyncTimer;
00108 QList<Containment*> containments;
00109 };
00110
00111 Corona::Corona(QObject *parent)
00112 : QGraphicsScene(parent),
00113 d(new Private)
00114 {
00115 d->init(this);
00116
00117 }
00118
00119 Corona::Corona(const QRectF & sceneRect, QObject * parent )
00120 : QGraphicsScene(sceneRect, parent),
00121 d(new Private)
00122 {
00123 d->init(this);
00124
00125 }
00126
00127 Corona::Corona(qreal x, qreal y, qreal width, qreal height, QObject * parent)
00128 : QGraphicsScene(x, y, width, height, parent),
00129 d(new Private)
00130 {
00131 d->init(this);
00132
00133 }
00134
00135 Corona::~Corona()
00136 {
00137 KConfigGroup cg(config(), "General");
00138
00139
00140
00141 cg.writeEntry("locked", d->immutable);
00142 delete d;
00143 }
00144
00145 QRectF Corona::maxSizeHint() const
00146 {
00147
00148
00149 return sceneRect();
00150 }
00151
00152 void Corona::setAppletMimeType(const QString& type)
00153 {
00154 d->mimetype = type;
00155 }
00156
00157 QString Corona::appletMimeType()
00158 {
00159 return d->mimetype;
00160 }
00161
00162 void Corona::saveApplets(const QString &config) const
00163 {
00164 KSharedConfigPtr cg = KSharedConfig::openConfig(config);
00165 d->saveApplets(cg);
00166 }
00167
00168 void Corona::saveApplets() const
00169 {
00170 d->saveApplets(config());
00171 scheduleConfigSync();
00172 }
00173
00174 void Corona::scheduleConfigSync() const
00175 {
00176
00177
00178
00179
00180
00181 if (!d->configSyncTimer.isActive()) {
00182 d->configSyncTimer.start(CONFIG_SYNC_TIMEOUT);
00183 }
00184 }
00185
00186 bool appletConfigLessThan(const KConfigGroup &c1, const KConfigGroup &c2)
00187 {
00188 QPointF p1 = c1.readEntry("geometry", QRectF()).topLeft();
00189 QPointF p2 = c2.readEntry("geometry", QRectF()).topLeft();
00190 if (p1.x() != p2.x()) {
00191 return p1.x() < p2.x();
00192 }
00193 return p1.y() < p2.y();
00194 }
00195
00196 void Corona::loadApplets(const QString& configName)
00197 {
00198 clearApplets();
00199 if (configName != d->configName) {
00200 d->configName = configName;
00201 d->config = 0;
00202 }
00203
00204 KConfigGroup containments(config(), "Containments");
00205
00206 foreach (const QString& group, containments.groupList()) {
00207 KConfigGroup containmentConfig(&containments, group);
00208
00209 if (containmentConfig.entryMap().isEmpty()) {
00210 continue;
00211 }
00212
00213 int cid = group.toUInt();
00214
00215 Containment *c = addContainment(containmentConfig.readEntry("plugin", QString()), QVariantList(),
00216 cid, true);
00217 if (!c) {
00218 continue;
00219 }
00220
00221 addItem(c);
00222 c->init();
00223 c->loadConstraints(&containmentConfig);
00224 c->flushUpdatedConstraints();
00225
00226 KConfigGroup applets(&containmentConfig, "Applets");
00227
00228
00229
00230 QList<KConfigGroup> appletConfigs;
00231 foreach (const QString &appletGroup, applets.groupList()) {
00232
00233 KConfigGroup appletConfig(&applets, appletGroup);
00234 appletConfigs.append(appletConfig);
00235 }
00236 qSort(appletConfigs.begin(), appletConfigs.end(), appletConfigLessThan);
00237
00238 foreach (KConfigGroup appletConfig, appletConfigs) {
00239 int appId = appletConfig.name().toUInt();
00240
00241 QString plugin = appletConfig.readEntry("plugin", QString());
00242
00243 if (plugin.isEmpty()) {
00244 continue;
00245 }
00246
00247 Applet *applet = c->addApplet(plugin, QVariantList(), appId, appletConfig.readEntry("geometry", QRectF()), true);
00248
00249 QList<qreal> m = appletConfig.readEntry("transform", QList<qreal>());
00250 if (m.count() == 9) {
00251 QTransform t(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
00252 applet->setTransform(t);
00253 }
00254 }
00255 }
00256
00257 if (d->containments.count() < 1) {
00258 loadDefaultSetup();
00259 } else {
00260 foreach (Containment* containment, d->containments) {
00261 QString cid = QString::number(containment->id());
00262 KConfigGroup containmentConfig(&containments, cid);
00263
00264 foreach(Applet* applet, containment->applets()) {
00265 applet->init();
00266 }
00267
00268 containment->updateConstraints(Plasma::StartupCompletedConstraint);
00269 containment->flushUpdatedConstraints();
00270 }
00271
00272
00273 int numScreens = QApplication::desktop()->numScreens();
00274 for (int i = 0; i < numScreens; ++i) {
00275 if (!containmentForScreen(i)) {
00276
00277 Containment* c = addContainment("desktop");
00278 c->setScreen(i);
00279 c->setFormFactor(Plasma::Planar);
00280 c->flushUpdatedConstraints();
00281 }
00282 }
00283 }
00284
00285 d->kioskImmutable = config()->isImmutable();
00286 if (d->kioskImmutable) {
00287 d->updateContainmentImmutability();
00288 }
00289
00290 KConfigGroup coronaConfig(config(), "General");
00291 setImmutable(coronaConfig.readEntry("locked", false));
00292 }
00293
00294 void Corona::loadApplets()
00295 {
00296 loadApplets(d->configName);
00297 }
00298
00299 void Corona::loadDefaultSetup()
00300 {
00301
00302 QDesktopWidget *desktop = QApplication::desktop();
00303 int numScreens = desktop->numScreens();
00304 kDebug() << "number of screens is" << numScreens;
00305 int topLeftScreen = 0;
00306 QPoint topLeftCorner = desktop->screenGeometry(0).topLeft();
00307
00308
00309 for (int i = 0; i < numScreens; ++i) {
00310 QRect g = desktop->screenGeometry(i);
00311 kDebug() << " screen " << i << "geometry is" << g;
00312 Containment* c = addContainment("desktop");
00313 c->setScreen(i);
00314 c->setFormFactor(Plasma::Planar);
00315 c->flushUpdatedConstraints();
00316
00317 if (g.x() <= topLeftCorner.x() && g.y() >= topLeftCorner.y()) {
00318 topLeftCorner = g.topLeft();
00319 topLeftScreen = i;
00320 }
00321 }
00322
00323
00324 Containment* panel = addContainment("panel");
00325 panel->setScreen(topLeftScreen);
00326 panel->setLocation(Plasma::BottomEdge);
00327
00328
00329 panel->addApplet("launcher");
00330 panel->addApplet("tasks");
00331 panel->addApplet("pager");
00332 panel->addApplet("systemtray");
00333 panel->addApplet("notifier");
00334 panel->addApplet("digital-clock");
00335
00336
00337
00338 panel->flushUpdatedConstraints();
00339 if (panel->layout()) {
00340 panel->layout()->invalidate();
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 scheduleConfigSync();
00354 }
00355
00356 Containment* Corona::containmentForScreen(int screen) const
00357 {
00358 foreach (Containment* containment, d->containments) {
00359 if (containment->screen() == screen &&
00360 containment->containmentType() == Containment::DesktopContainment) {
00361 return containment;
00362 }
00363 }
00364
00365 return 0;
00366 }
00367
00368 QList<Containment*> Corona::containments() const
00369 {
00370 return d->containments;
00371 }
00372
00373 void Corona::clearApplets()
00374 {
00375 foreach (Containment* containment, d->containments) {
00376 containment->clearApplets();
00377 }
00378 }
00379
00380 KSharedConfigPtr Corona::config() const
00381 {
00382 if (!d->config) {
00383 d->config = KSharedConfig::openConfig(d->configName);
00384 }
00385
00386 return d->config;
00387 }
00388
00389 Containment* Corona::addContainment(const QString& name, const QVariantList& args, uint id, bool delayedInit)
00390 {
00391 QString pluginName = name;
00392 Containment* containment = 0;
00393 Applet* applet = 0;
00394
00395
00396
00397 if (pluginName.isEmpty()) {
00398
00399 pluginName = "desktop";
00400 } else if (pluginName != "null") {
00401 applet = Applet::loadApplet(pluginName, id, args);
00402 containment = dynamic_cast<Containment*>(applet);
00403 }
00404
00405 if (!containment) {
00406 kDebug() << "loading of containment" << name << "failed.";
00407
00408
00409 delete applet;
00410 containment = new Containment;
00411
00412
00413 containment->setFailedToLaunch(false);
00414 containment->setFormFactor(Plasma::Planar);
00415 }
00416
00417 containment->setIsContainment(true);
00418
00419 if (!delayedInit) {
00420 addItem(containment);
00421 containment->init();
00422 containment->updateConstraints(Plasma::StartupCompletedConstraint);
00423 }
00424
00425 d->containments.append(containment);
00426 connect(containment, SIGNAL(destroyed(QObject*)),
00427 this, SLOT(containmentDestroyed(QObject*)));
00428 connect(containment, SIGNAL(launchActivated()),
00429 SIGNAL(launchActivated()));
00430 connect(containment, SIGNAL(configNeedsSaving()),
00431 SLOT(scheduleConfigSync()));
00432
00433 return containment;
00434 }
00435
00436 void Corona::destroyContainment(Containment *c)
00437 {
00438 if (!d->containments.contains(c)) {
00439 return;
00440 }
00441
00442 d->containments.removeAll(c);
00443 c->config().deleteGroup();
00444 c->deleteLater();
00445 }
00446
00447 void Corona::dragEnterEvent( QGraphicsSceneDragDropEvent *event)
00448 {
00449
00450 if (event->mimeData()->hasFormat(d->mimetype) ||
00451 KUrl::List::canDecode(event->mimeData())) {
00452 event->acceptProposedAction();
00453
00454
00455
00456
00457 }
00458
00459 event->accept();
00460
00461
00462 }
00463
00464 void Corona::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
00465 {
00466
00467
00468
00469
00470 QGraphicsScene::dragLeaveEvent(event);
00471 }
00472
00473 void Corona::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
00474 {
00475 QGraphicsScene::dragMoveEvent(event);
00476
00477 event->accept();
00478
00479 }
00480
00481 void Corona::containmentDestroyed(QObject* obj)
00482 {
00483
00484
00485
00486
00487 Containment* containment = static_cast<Plasma::Containment*>(obj);
00488 int index = d->containments.indexOf(containment);
00489
00490 if (index > -1) {
00491 d->containments.removeAt(index);
00492 }
00493 }
00494
00495 void Corona::screenResized(int screen)
00496 {
00497 bool desktopFound = false;
00498 foreach (Containment *c, d->containments) {
00499 if (c->screen() == screen) {
00500
00501 c->setScreen(screen);
00502 desktopFound = desktopFound || c->containmentType() == Containment::DesktopContainment;
00503 }
00504 }
00505
00506 if (desktopFound) {
00507 return;
00508 }
00509
00510
00511
00512
00513
00514 Containment* c = addContainment("desktop");
00515 c->setScreen(screen);
00516 c->setFormFactor(Plasma::Planar);
00517 emit newScreen(screen);
00518 }
00519
00520 void Corona::syncConfig()
00521 {
00522 config()->sync();
00523 }
00524
00525 bool Corona::isImmutable() const
00526 {
00527 return d->kioskImmutable || d->immutable;
00528 }
00529
00530 bool Corona::isKioskImmutable() const
00531 {
00532 return d->kioskImmutable;
00533 }
00534
00535 void Corona::setImmutable(bool immutable)
00536 {
00537 if (d->immutable == immutable ||
00538 (!immutable && d->kioskImmutable)) {
00539 return;
00540 }
00541
00542 kDebug() << "setting immutability to" << immutable;
00543 d->immutable = immutable;
00544 d->updateContainmentImmutability();
00545 }
00546
00547 }
00548
00549 #include "corona.moc"
00550