File indexing completed on 2025-02-16 14:20:18
0001 /* 0002 * Copyright 2019 Michail Vourlakos <mvourlakos@gmail.com> 0003 * 0004 * This file is part of Latte-Dock 0005 * 0006 * Latte-Dock is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU General Public License as 0008 * published by the Free Software Foundation; either version 2 of 0009 * the License, or (at your option) any later version. 0010 * 0011 * Latte-Dock is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "genericlayout.h" 0021 0022 // local 0023 #include "abstractlayout.h" 0024 #include "storage.h" 0025 #include "../lattecorona.h" 0026 #include "../screenpool.h" 0027 #include "../layouts/importer.h" 0028 #include "../layouts/manager.h" 0029 #include "../layouts/synchronizer.h" 0030 #include "../shortcuts/shortcutstracker.h" 0031 #include "../view/view.h" 0032 #include "../view/positioner.h" 0033 0034 // Qt 0035 #include <QDebug> 0036 #include <QScreen> 0037 0038 // Plasma 0039 #include <Plasma> 0040 #include <Plasma/Applet> 0041 #include <Plasma/Containment> 0042 0043 // KDE 0044 #include <KConfigGroup> 0045 0046 namespace Latte { 0047 namespace Layout { 0048 0049 GenericLayout::GenericLayout(QObject *parent, QString layoutFile, QString assignedName) 0050 : AbstractLayout (parent, layoutFile, assignedName), 0051 m_storage(new Storage(this)) 0052 { 0053 } 0054 0055 GenericLayout::~GenericLayout() 0056 { 0057 } 0058 0059 Type GenericLayout::type() const 0060 { 0061 return Type::Generic; 0062 } 0063 0064 void GenericLayout::unloadContainments() 0065 { 0066 if (!m_corona) { 0067 return; 0068 } 0069 0070 qDebug() << "Layout - " + name() + " : [unloadContainments]" 0071 << "containments ::: " << m_containments.size() 0072 << " ,latteViews in memory ::: " << m_latteViews.size() 0073 << " ,hidden latteViews in memory ::: " << m_waitingLatteViews.size(); 0074 0075 for (const auto view : m_latteViews) { 0076 view->disconnectSensitiveSignals(); 0077 } 0078 0079 for (const auto view : m_waitingLatteViews) { 0080 view->disconnectSensitiveSignals(); 0081 } 0082 0083 m_unloadedContainmentsIds.clear(); 0084 0085 QList<Plasma::Containment *> systrays; 0086 0087 //!identify systrays and unload them first 0088 for (const auto containment : m_containments) { 0089 if (Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent())) { 0090 systrays.append(containment); 0091 } 0092 } 0093 0094 while (!systrays.isEmpty()) { 0095 Plasma::Containment *systray = systrays.at(0); 0096 m_unloadedContainmentsIds << QString::number(systray->id()); 0097 systrays.removeFirst(); 0098 m_containments.removeAll(systray); 0099 delete systray; 0100 } 0101 0102 while (!m_containments.isEmpty()) { 0103 Plasma::Containment *containment = m_containments.at(0); 0104 m_unloadedContainmentsIds << QString::number(containment->id()); 0105 m_containments.removeFirst(); 0106 delete containment; 0107 } 0108 } 0109 0110 void GenericLayout::unloadLatteViews() 0111 { 0112 if (!m_corona) { 0113 return; 0114 } 0115 0116 qDebug() << "Layout - " + name() + " : [unloadLatteViews]" 0117 << "containments ::: " << m_containments.size() 0118 << " ,latteViews in memory ::: " << m_latteViews.size() 0119 << " ,hidden latteViews in memory ::: " << m_waitingLatteViews.size(); 0120 0121 //!disconnect signals in order to avoid crashes when the layout is unloading 0122 disconnect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRectChanged); 0123 disconnect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRegionChanged); 0124 disconnect(m_corona->activityConsumer(), &KActivities::Consumer::currentActivityChanged, this, &GenericLayout::updateLastUsedActivity); 0125 0126 for (const auto view : m_latteViews) { 0127 view->disconnectSensitiveSignals(); 0128 } 0129 0130 for (const auto view : m_waitingLatteViews) { 0131 view->disconnectSensitiveSignals(); 0132 } 0133 0134 qDeleteAll(m_latteViews); 0135 qDeleteAll(m_waitingLatteViews); 0136 m_latteViews.clear(); 0137 m_waitingLatteViews.clear(); 0138 } 0139 0140 bool GenericLayout::blockAutomaticLatteViewCreation() const 0141 { 0142 return m_blockAutomaticLatteViewCreation; 0143 } 0144 0145 void GenericLayout::setBlockAutomaticLatteViewCreation(bool block) 0146 { 0147 if (m_blockAutomaticLatteViewCreation == block) { 0148 return; 0149 } 0150 0151 m_blockAutomaticLatteViewCreation = block; 0152 } 0153 0154 bool GenericLayout::configViewIsShown() const 0155 { 0156 for (const auto view : m_latteViews) { 0157 if (view && view->settingsWindowIsShown()) { 0158 return true; 0159 } 0160 } 0161 0162 return false; 0163 } 0164 0165 bool GenericLayout::isActive() const 0166 { 0167 if (!m_corona) { 0168 return false; 0169 } 0170 0171 GenericLayout *generic = m_corona->layoutsManager()->synchronizer()->layout(m_layoutName); 0172 0173 if (generic) { 0174 return true; 0175 } else { 0176 return false; 0177 } 0178 } 0179 0180 bool GenericLayout::isCurrent() const 0181 { 0182 if (!m_corona) { 0183 return false; 0184 } 0185 0186 return name() == m_corona->layoutsManager()->currentLayoutName(); 0187 } 0188 0189 bool GenericLayout::isInternalContainment(Plasma::Applet *applet) const 0190 { 0191 if (!applet) { 0192 return false; 0193 } 0194 0195 for (const auto containment : m_containments) { 0196 Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent()); 0197 if (parentApplet && parentApplet == applet) { 0198 return true; 0199 } 0200 } 0201 0202 return false; 0203 } 0204 0205 Plasma::Containment *GenericLayout::internalContainmentOf(Plasma::Applet *applet) const 0206 { 0207 if (!applet) { 0208 return nullptr; 0209 } 0210 0211 if (isInternalContainment(applet)) { 0212 for (const auto containment : m_containments) { 0213 Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent()); 0214 if (parentApplet && parentApplet == applet) { 0215 return containment; 0216 } 0217 } 0218 } 0219 0220 return nullptr; 0221 } 0222 0223 int GenericLayout::viewsCount(int screen) const 0224 { 0225 if (!m_corona) { 0226 return 0; 0227 } 0228 0229 QScreen *scr = m_corona->screenPool()->screenForId(screen); 0230 0231 int views{0}; 0232 0233 for (const auto view : m_latteViews) { 0234 if (view && view->screen() == scr && !view->containment()->destroyed()) { 0235 ++views; 0236 } 0237 } 0238 0239 return views; 0240 } 0241 0242 int GenericLayout::viewsCount(QScreen *screen) const 0243 { 0244 if (!m_corona) { 0245 return 0; 0246 } 0247 0248 int views{0}; 0249 0250 for (const auto view : m_latteViews) { 0251 if (view && view->screen() == screen && !view->containment()->destroyed()) { 0252 ++views; 0253 } 0254 } 0255 0256 return views; 0257 } 0258 0259 int GenericLayout::viewsCount() const 0260 { 0261 if (!m_corona) { 0262 return 0; 0263 } 0264 0265 int views{0}; 0266 0267 for (const auto view : m_latteViews) { 0268 if (view && view->containment() && !view->containment()->destroyed()) { 0269 ++views; 0270 } 0271 } 0272 0273 return views; 0274 } 0275 0276 QList<int> GenericLayout::qmlFreeEdges(int screen) const 0277 { 0278 if (!m_corona) { 0279 const QList<int> emptyEdges; 0280 return emptyEdges; 0281 } 0282 0283 const auto edges = freeEdges(screen); 0284 QList<int> edgesInt; 0285 0286 for (const Plasma::Types::Location &edge : edges) { 0287 edgesInt.append(static_cast<int>(edge)); 0288 } 0289 0290 return edgesInt; 0291 } 0292 0293 QList<Plasma::Types::Location> GenericLayout::freeEdges(QScreen *scr) const 0294 { 0295 using Plasma::Types; 0296 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge, 0297 Types::TopEdge, Types::RightEdge}; 0298 0299 if (!m_corona) { 0300 return edges; 0301 } 0302 0303 for (const auto view : m_latteViews) { 0304 if (view && view->positioner()->currentScreenName() == scr->name()) { 0305 edges.removeOne(view->location()); 0306 } 0307 } 0308 0309 return edges; 0310 } 0311 0312 QList<Plasma::Types::Location> GenericLayout::freeEdges(int screen) const 0313 { 0314 using Plasma::Types; 0315 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge, 0316 Types::TopEdge, Types::RightEdge}; 0317 0318 if (!m_corona) { 0319 return edges; 0320 } 0321 0322 QScreen *scr = m_corona->screenPool()->screenForId(screen); 0323 0324 for (const auto view : m_latteViews) { 0325 if (view && scr && view->positioner()->currentScreenName() == scr->name()) { 0326 edges.removeOne(view->location()); 0327 } 0328 } 0329 0330 return edges; 0331 } 0332 0333 int GenericLayout::viewsWithTasks() const 0334 { 0335 if (!m_corona) { 0336 return 0; 0337 } 0338 0339 int result = 0; 0340 0341 for (const auto view : m_latteViews) { 0342 if (view->tasksPresent()) { 0343 result++; 0344 } 0345 } 0346 0347 return result; 0348 } 0349 0350 QStringList GenericLayout::unloadedContainmentsIds() 0351 { 0352 return m_unloadedContainmentsIds; 0353 } 0354 0355 Latte::Corona *GenericLayout::corona() 0356 { 0357 return m_corona; 0358 } 0359 0360 Types::ViewType GenericLayout::latteViewType(int containmentId) const 0361 { 0362 for (const auto view : m_latteViews) { 0363 if (view->containment() && view->containment()->id() == containmentId) { 0364 return view->type(); 0365 } 0366 } 0367 0368 return Types::DockView; 0369 } 0370 0371 Latte::View *GenericLayout::highestPriorityView() 0372 { 0373 QList<Latte::View *> views = sortedLatteViews(); 0374 0375 return (views.count() > 0 ? views[0] : nullptr); 0376 } 0377 0378 Latte::View *GenericLayout::lastConfigViewFor() 0379 { 0380 if (!latteViews().contains(m_lastConfigViewFor)) { 0381 m_lastConfigViewFor = nullptr; 0382 return nullptr; 0383 } 0384 0385 return m_lastConfigViewFor; 0386 } 0387 0388 void GenericLayout::setLastConfigViewFor(Latte::View *view) 0389 { 0390 if (m_lastConfigViewFor == view) { 0391 return; 0392 } 0393 0394 m_lastConfigViewFor = view; 0395 emit lastConfigViewForChanged(view); 0396 } 0397 0398 Latte::View *GenericLayout::viewForContainment(Plasma::Containment *containment) 0399 { 0400 if (m_containments.contains(containment) && m_latteViews.contains(containment)) { 0401 return m_latteViews[containment]; 0402 } 0403 0404 return nullptr; 0405 } 0406 0407 QList<Latte::View *> GenericLayout::latteViews() 0408 { 0409 return m_latteViews.values(); 0410 } 0411 0412 QList<Latte::View *> GenericLayout::sortedLatteViews(QList<Latte::View *> views) 0413 { 0414 QList<Latte::View *> sortedViews = views.isEmpty() ? latteViews() : views; 0415 0416 qDebug() << " -------- "; 0417 0418 for (int i = 0; i < sortedViews.count(); ++i) { 0419 qDebug() << i << ". " << sortedViews[i]->screen()->name() << " - " << sortedViews[i]->location(); 0420 } 0421 0422 //! sort the views based on screens and edges priorities 0423 //! views on primary screen have higher priority and 0424 //! for views in the same screen the priority goes to 0425 //! Bottom,Left,Top,Right 0426 for (int i = 0; i < sortedViews.size(); ++i) { 0427 for (int j = 0; j < sortedViews.size() - i - 1; ++j) { 0428 if (viewAtLowerScreenPriority(sortedViews[j], sortedViews[j + 1]) 0429 || (sortedViews[j]->screen() == sortedViews[j + 1]->screen() 0430 && viewAtLowerEdgePriority(sortedViews[j], sortedViews[j + 1]))) { 0431 Latte::View *temp = sortedViews[j + 1]; 0432 sortedViews[j + 1] = sortedViews[j]; 0433 sortedViews[j] = temp; 0434 } 0435 } 0436 } 0437 0438 Latte::View *highestPriorityView{nullptr}; 0439 0440 for (int i = 0; i < sortedViews.size(); ++i) { 0441 if (sortedViews[i]->isPreferredForShortcuts()) { 0442 highestPriorityView = sortedViews[i]; 0443 sortedViews.removeAt(i); 0444 break; 0445 } 0446 } 0447 0448 if (highestPriorityView) { 0449 sortedViews.prepend(highestPriorityView); 0450 } 0451 0452 qDebug() << " -------- sorted -----"; 0453 0454 for (int i = 0; i < sortedViews.count(); ++i) { 0455 qDebug() << i << ". " << sortedViews[i]->isPreferredForShortcuts() << " - " << sortedViews[i]->screen()->name() << " - " << sortedViews[i]->location(); 0456 } 0457 0458 return sortedViews; 0459 } 0460 0461 bool GenericLayout::viewAtLowerScreenPriority(Latte::View *test, Latte::View *base) 0462 { 0463 if (!base || ! test) { 0464 return true; 0465 } 0466 0467 if (base->screen() == test->screen()) { 0468 return false; 0469 } else if (base->screen() != qGuiApp->primaryScreen() && test->screen() == qGuiApp->primaryScreen()) { 0470 return false; 0471 } else if (base->screen() == qGuiApp->primaryScreen() && test->screen() != qGuiApp->primaryScreen()) { 0472 return true; 0473 } else { 0474 int basePriority = -1; 0475 int testPriority = -1; 0476 0477 for (int i = 0; i < qGuiApp->screens().count(); ++i) { 0478 if (base->screen() == qGuiApp->screens()[i]) { 0479 basePriority = i; 0480 } 0481 0482 if (test->screen() == qGuiApp->screens()[i]) { 0483 testPriority = i; 0484 } 0485 } 0486 0487 if (testPriority <= basePriority) { 0488 return true; 0489 } else { 0490 return false; 0491 } 0492 0493 } 0494 0495 qDebug() << "viewAtLowerScreenPriority : shouldn't had reached here..."; 0496 return false; 0497 } 0498 0499 bool GenericLayout::viewAtLowerEdgePriority(Latte::View *test, Latte::View *base) 0500 { 0501 if (!base || ! test) { 0502 return true; 0503 } 0504 0505 QList<Plasma::Types::Location> edges{Plasma::Types::RightEdge, Plasma::Types::TopEdge, 0506 Plasma::Types::LeftEdge, Plasma::Types::BottomEdge}; 0507 0508 int testPriority = -1; 0509 int basePriority = -1; 0510 0511 for (int i = 0; i < edges.count(); ++i) { 0512 if (edges[i] == base->location()) { 0513 basePriority = i; 0514 } 0515 0516 if (edges[i] == test->location()) { 0517 testPriority = i; 0518 } 0519 } 0520 0521 if (testPriority < basePriority) { 0522 return true; 0523 } else { 0524 return false; 0525 } 0526 } 0527 0528 bool GenericLayout::viewDataAtLowerScreenPriority(const ViewData &test, const ViewData &base) const 0529 { 0530 if (test.onPrimary && base.onPrimary) { 0531 return false; 0532 } else if (!base.onPrimary && test.onPrimary) { 0533 return false; 0534 } else if (base.onPrimary && !test.onPrimary) { 0535 return true; 0536 } else { 0537 return test.screenId <= base.screenId; 0538 } 0539 } 0540 0541 bool GenericLayout::viewDataAtLowerStatePriority(const ViewData &test, const ViewData &base) const 0542 { 0543 if (test.active == base.active) { 0544 return false; 0545 } else if (!base.active && test.active) { 0546 return false; 0547 } else if (base.active && !test.active) { 0548 return true; 0549 } 0550 0551 return false; 0552 } 0553 0554 bool GenericLayout::viewDataAtLowerEdgePriority(const ViewData &test, const ViewData &base) const 0555 { 0556 QList<Plasma::Types::Location> edges{Plasma::Types::RightEdge, Plasma::Types::TopEdge, 0557 Plasma::Types::LeftEdge, Plasma::Types::BottomEdge}; 0558 0559 int testPriority = -1; 0560 int basePriority = -1; 0561 0562 for (int i = 0; i < edges.count(); ++i) { 0563 if (edges[i] == base.location) { 0564 basePriority = i; 0565 } 0566 0567 if (edges[i] == test.location) { 0568 testPriority = i; 0569 } 0570 } 0571 0572 if (testPriority < basePriority) { 0573 return true; 0574 } else { 0575 return false; 0576 } 0577 } 0578 0579 QList<ViewData> GenericLayout::sortedViewsData(const QList<ViewData> &viewsData) 0580 { 0581 QList<ViewData> sortedData = viewsData; 0582 0583 //! sort the views based on screens and edges priorities 0584 //! views on primary screen have higher priority and 0585 //! for views in the same screen the priority goes to 0586 //! Bottom,Left,Top,Right 0587 for (int i = 0; i < sortedData.size(); ++i) { 0588 for (int j = 0; j < sortedData.size() - i - 1; ++j) { 0589 if (viewDataAtLowerStatePriority(sortedData[j], sortedData[j + 1]) 0590 || viewDataAtLowerScreenPriority(sortedData[j], sortedData[j + 1]) 0591 || (!viewDataAtLowerScreenPriority(sortedData[j], sortedData[j + 1]) 0592 && viewDataAtLowerEdgePriority(sortedData[j], sortedData[j + 1])) ) { 0593 ViewData temp = sortedData[j + 1]; 0594 sortedData[j + 1] = sortedData[j]; 0595 sortedData[j] = temp; 0596 } 0597 } 0598 } 0599 0600 return sortedData; 0601 } 0602 0603 0604 const QList<Plasma::Containment *> *GenericLayout::containments() 0605 { 0606 return &m_containments; 0607 } 0608 0609 QList<Latte::View *> GenericLayout::viewsWithPlasmaShortcuts() 0610 { 0611 QList<Latte::View *> views; 0612 0613 if (!m_corona) { 0614 return views; 0615 } 0616 0617 QList<int> appletsWithShortcuts = m_corona->globalShortcuts()->shortcutsTracker()->appletsWithPlasmaShortcuts(); 0618 0619 for (const auto &appletId : appletsWithShortcuts) { 0620 for (const auto view : m_latteViews) { 0621 bool found{false}; 0622 for (const auto applet : view->containment()->applets()) { 0623 if (appletId == applet->id()) { 0624 if (!views.contains(view)) { 0625 views.append(view); 0626 found = true; 0627 break; 0628 } 0629 } 0630 } 0631 0632 if (found) { 0633 break; 0634 } 0635 } 0636 } 0637 0638 return views; 0639 } 0640 0641 0642 //! Containments Actions 0643 void GenericLayout::addContainment(Plasma::Containment *containment) 0644 { 0645 if (!containment || m_containments.contains(containment)) { 0646 return; 0647 } 0648 0649 bool containmentInLayout{false}; 0650 0651 if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) { 0652 m_containments.append(containment); 0653 containmentInLayout = true; 0654 } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 0655 QString layoutId = containment->config().readEntry("layoutId", QString()); 0656 0657 if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { 0658 m_containments.append(containment); 0659 containmentInLayout = true; 0660 } 0661 } 0662 0663 if (containmentInLayout) { 0664 if (!blockAutomaticLatteViewCreation()) { 0665 addView(containment); 0666 } else { 0667 qDebug() << "delaying LatteView creation for containment :: " << containment->id(); 0668 } 0669 0670 connect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed); 0671 } 0672 } 0673 0674 void GenericLayout::appletCreated(Plasma::Applet *applet) 0675 { 0676 //! In Multiple Layout the orphaned systrays must be assigned to layouts 0677 //! when the user adds them 0678 KConfigGroup appletSettings = applet->containment()->config().group("Applets").group(QString::number(applet->id())).group("Configuration"); 0679 0680 int systrayId = appletSettings.readEntry("SystrayContainmentId", -1); 0681 0682 if (systrayId != -1) { 0683 uint sId = (uint)systrayId; 0684 0685 for (const auto containment : m_corona->containments()) { 0686 if (containment->id() == sId) { 0687 containment->config().writeEntry("layoutId", m_layoutName); 0688 } 0689 0690 addContainment(containment); 0691 } 0692 } 0693 } 0694 0695 void GenericLayout::containmentDestroyed(QObject *cont) 0696 { 0697 if (!m_corona) { 0698 return; 0699 } 0700 0701 Plasma::Containment *containment = static_cast<Plasma::Containment *>(cont); 0702 0703 if (containment) { 0704 int containmentIndex = m_containments.indexOf(containment); 0705 0706 if (containmentIndex >= 0) { 0707 m_containments.removeAt(containmentIndex); 0708 } 0709 0710 qDebug() << "Layout " << name() << " :: containment destroyed!!!!"; 0711 auto view = m_latteViews.take(containment); 0712 0713 if (!view) { 0714 view = m_waitingLatteViews.take(containment); 0715 } 0716 0717 if (view) { 0718 view->disconnectSensitiveSignals(); 0719 0720 view->deleteLater(); 0721 0722 emit viewEdgeChanged(); 0723 emit viewsCountChanged(); 0724 } 0725 } 0726 } 0727 0728 void GenericLayout::destroyedChanged(bool destroyed) 0729 { 0730 if (!m_corona) { 0731 return; 0732 } 0733 0734 qDebug() << "dock containment destroyed changed!!!!"; 0735 Plasma::Containment *sender = qobject_cast<Plasma::Containment *>(QObject::sender()); 0736 0737 if (!sender) { 0738 return; 0739 } 0740 0741 if (destroyed) { 0742 m_waitingLatteViews[sender] = m_latteViews.take(static_cast<Plasma::Containment *>(sender)); 0743 } else { 0744 m_latteViews[sender] = m_waitingLatteViews.take(static_cast<Plasma::Containment *>(sender)); 0745 } 0746 0747 emit viewEdgeChanged(); 0748 emit viewsCountChanged(); 0749 } 0750 0751 void GenericLayout::renameLayout(QString newName) 0752 { 0753 if (!m_corona || m_corona->layoutsManager()->memoryUsage() != Types::MultipleLayouts) { 0754 return; 0755 } 0756 0757 if (m_layoutFile != Layouts::Importer::layoutFilePath(newName)) { 0758 setFile(Layouts::Importer::layoutFilePath(newName)); 0759 } 0760 0761 setName(newName); 0762 0763 for (const auto containment : m_containments) { 0764 qDebug() << "Cont ID :: " << containment->id(); 0765 containment->config().writeEntry("layoutId", m_layoutName); 0766 } 0767 } 0768 0769 void GenericLayout::addNewView() 0770 { 0771 if (!m_corona) { 0772 return; 0773 } 0774 0775 m_corona->addViewForLayout(name()); 0776 emit viewEdgeChanged(); 0777 } 0778 0779 void GenericLayout::addView(Plasma::Containment *containment, bool forceOnPrimary, int explicitScreen, Layout::ViewsMap *occupied) 0780 { 0781 qDebug() << "Layout :::: " << m_layoutName << " ::: addView was called... m_containments :: " << m_containments.size(); 0782 0783 if (!containment || !m_corona || !containment->kPackage().isValid()) { 0784 qWarning() << "the requested containment plugin can not be located or loaded"; 0785 return; 0786 } 0787 0788 qDebug() << "step 1..."; 0789 0790 if (!m_storage->isLatteContainment(containment)) 0791 return; 0792 0793 qDebug() << "step 2..."; 0794 0795 for (auto *dock : m_latteViews) { 0796 if (dock->containment() == containment) 0797 return; 0798 } 0799 0800 qDebug() << "step 3..."; 0801 0802 QScreen *nextScreen{qGuiApp->primaryScreen()}; 0803 0804 bool onPrimary = containment->config().readEntry("onPrimary", true); 0805 int id = containment->screen(); 0806 0807 if (id == -1 && explicitScreen == -1) { 0808 id = containment->lastScreen(); 0809 } 0810 0811 if (onPrimary) { 0812 id = m_corona->screenPool()->primaryScreenId(); 0813 } else if (explicitScreen > -1) { 0814 id = explicitScreen; 0815 } 0816 0817 Plasma::Types::Location edge = containment->location(); 0818 0819 QString connector = m_corona->screenPool()->hasId(id) ? m_corona->screenPool()->connector(id) : ""; 0820 0821 qDebug() << "Adding view - containment id:" << containment->id() << " ,screen :" << id << " - " << connector 0822 << " ,onprimary:" << onPrimary << " - " << " edge:" << edge << " ,screenName:" << qGuiApp->primaryScreen()->name() << " ,forceOnPrimary:" << forceOnPrimary; 0823 0824 if (occupied && m_corona->screenPool()->hasId(id) && (*occupied).contains(connector) && (*occupied)[connector].contains(edge)) { 0825 qDebug() << "Rejected : adding view because the edge is already occupied by a higher priority view ! : " << (*occupied)[connector][edge]; 0826 return; 0827 } 0828 0829 if (id >= 0 && !onPrimary && !forceOnPrimary) { 0830 qDebug() << "Add view - connector : " << connector; 0831 bool found{false}; 0832 0833 if (m_corona->screenPool()->hasId(id)) { 0834 for (const auto scr : qGuiApp->screens()) { 0835 if (scr && scr->name() == connector) { 0836 found = true; 0837 nextScreen = scr; 0838 break; 0839 } 0840 } 0841 } 0842 0843 if (!found) { 0844 qDebug() << "Rejected : adding explicit view, screen not available ! : " << connector; 0845 return; 0846 } 0847 0848 //! explicit dock can not be added at explicit screen when that screen is the same with 0849 //! primary screen and that edge is already occupied by a primary dock 0850 if (nextScreen == qGuiApp->primaryScreen() && primaryDockOccupyEdge(containment->location())) { 0851 qDebug() << "Rejected : adding explicit view, primary dock occupies edge at screen ! : " << connector; 0852 return; 0853 } 0854 } 0855 0856 if (id >= 0 && onPrimary) { 0857 qDebug() << "add dock - connector : " << connector; 0858 0859 for (const auto view : m_latteViews) { 0860 auto testContainment = view->containment(); 0861 0862 int testScreenId = testContainment->screen(); 0863 0864 if (testScreenId == -1) { 0865 testScreenId = testContainment->lastScreen(); 0866 } 0867 0868 bool testOnPrimary = testContainment->config().readEntry("onPrimary", true); 0869 Plasma::Types::Location testLocation = static_cast<Plasma::Types::Location>((int)testContainment->config().readEntry("location", (int)Plasma::Types::BottomEdge)); 0870 0871 if (!testOnPrimary && m_corona->screenPool()->primaryScreenId() == testScreenId && testLocation == containment->location()) { 0872 qDebug() << "Rejected explicit latteView and removing it in order add an onPrimary with higher priority at screen: " << connector; 0873 auto viewToDelete = m_latteViews.take(testContainment); 0874 viewToDelete->disconnectSensitiveSignals(); 0875 viewToDelete->deleteLater(); 0876 } 0877 } 0878 } 0879 0880 qDebug() << "Adding view passed ALL checks" << " ,onPrimary:" << onPrimary << " ,screen:" << nextScreen->name() << " !!!"; 0881 0882 //! it is used to set the correct flag during the creation 0883 //! of the window... This of course is also used during 0884 //! recreations of the window between different visibility modes 0885 auto mode = static_cast<Types::Visibility>(containment->config().readEntry("visibility", static_cast<int>(Types::DodgeActive))); 0886 bool byPassWM{false}; 0887 0888 if (mode == Types::AlwaysVisible || mode == Types::WindowsGoBelow) { 0889 byPassWM = false; 0890 } else { 0891 byPassWM = containment->config().readEntry("byPassWM", false); 0892 } 0893 0894 auto latteView = new Latte::View(m_corona, nextScreen, byPassWM); 0895 0896 latteView->init(); 0897 latteView->setContainment(containment); 0898 0899 //! force this special dock case to become primary 0900 //! even though it isnt 0901 if (forceOnPrimary) { 0902 qDebug() << "Enforcing onPrimary:true as requested for LatteView..."; 0903 latteView->setOnPrimary(true); 0904 } 0905 0906 latteView->setLayout(this); 0907 0908 //! Qt 5.9 creates a crash for this in wayland, that is why the check is used 0909 //! but on the other hand we need this for copy to work correctly and show 0910 //! the copied dock under X11 0911 //if (!KWindowSystem::isPlatformWayland()) { 0912 latteView->show(); 0913 //} 0914 0915 m_latteViews[containment] = latteView; 0916 0917 emit viewsCountChanged(); 0918 } 0919 0920 0921 bool GenericLayout::initToCorona(Latte::Corona *corona) 0922 { 0923 if (m_corona) { 0924 return false; 0925 } 0926 0927 m_corona = corona; 0928 0929 for (const auto containment : m_corona->containments()) { 0930 if (m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout) { 0931 addContainment(containment); 0932 } else if (m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 0933 QString layoutId = containment->config().readEntry("layoutId", QString()); 0934 0935 if (!layoutId.isEmpty() && (layoutId == m_layoutName)) { 0936 addContainment(containment); 0937 } 0938 } 0939 } 0940 0941 qDebug() << "Layout ::::: " << name() << " added containments ::: " << m_containments.size(); 0942 0943 updateLastUsedActivity(); 0944 0945 //! signals 0946 connect(m_corona->activityConsumer(), &KActivities::Consumer::currentActivityChanged, 0947 this, &GenericLayout::updateLastUsedActivity); 0948 0949 connect(m_corona, &Plasma::Corona::containmentAdded, this, &GenericLayout::addContainment); 0950 0951 //!connect signals after adding the containment 0952 connect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRectChanged); 0953 connect(this, &GenericLayout::viewsCountChanged, m_corona, &Plasma::Corona::availableScreenRegionChanged); 0954 0955 emit viewsCountChanged(); 0956 0957 return true; 0958 } 0959 0960 void GenericLayout::updateLastUsedActivity() 0961 { 0962 if (!m_corona) { 0963 return; 0964 } 0965 0966 if (!m_lastUsedActivity.isEmpty() && !m_corona->layoutsManager()->synchronizer()->activities().contains(m_lastUsedActivity)) { 0967 clearLastUsedActivity(); 0968 } 0969 0970 QString currentId = m_corona->activitiesConsumer()->currentActivity(); 0971 0972 QStringList appliedActivitiesIds = appliedActivities(); 0973 0974 if (m_lastUsedActivity != currentId 0975 && (appliedActivitiesIds.contains(currentId) 0976 || m_corona->layoutsManager()->memoryUsage() == Types::SingleLayout)) { 0977 m_lastUsedActivity = currentId; 0978 0979 emit lastUsedActivityChanged(); 0980 } 0981 } 0982 0983 void GenericLayout::assignToLayout(Latte::View *latteView, QList<Plasma::Containment *> containments) 0984 { 0985 if (!m_corona) { 0986 return; 0987 } 0988 0989 if (latteView) { 0990 m_latteViews[latteView->containment()] = latteView; 0991 m_containments << containments; 0992 0993 for (const auto containment : containments) { 0994 containment->config().writeEntry("layoutId", name()); 0995 0996 if (latteView->containment() != containment) { 0997 //! assign signals only to systrays 0998 //! the View::setLayout() is responsible for the View::Containment signals 0999 connect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed); 1000 connect(containment, &Plasma::Applet::destroyedChanged, this, &GenericLayout::destroyedChanged); 1001 connect(containment, &Plasma::Containment::appletCreated, this, &GenericLayout::appletCreated); 1002 } 1003 } 1004 1005 latteView->setLayout(this); 1006 1007 emit viewsCountChanged(); 1008 } 1009 1010 //! sync the original layout file for integrity 1011 if (m_corona && m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 1012 m_storage->syncToLayoutFile(false); 1013 } 1014 } 1015 1016 QList<Plasma::Containment *> GenericLayout::unassignFromLayout(Latte::View *latteView) 1017 { 1018 QList<Plasma::Containment *> containments; 1019 1020 if (!m_corona) { 1021 return containments; 1022 } 1023 1024 containments << latteView->containment(); 1025 1026 for (const auto containment : m_containments) { 1027 Plasma::Applet *parentApplet = qobject_cast<Plasma::Applet *>(containment->parent()); 1028 1029 //! add systrays from that latteView 1030 if (parentApplet && parentApplet->containment() && parentApplet->containment() == latteView->containment()) { 1031 containments << containment; 1032 //! unassign signals only to systrays 1033 //! the View::setLayout() is responsible for the View::Containment signals 1034 disconnect(containment, &QObject::destroyed, this, &GenericLayout::containmentDestroyed); 1035 disconnect(containment, &Plasma::Applet::destroyedChanged, this, &GenericLayout::destroyedChanged); 1036 disconnect(containment, &Plasma::Containment::appletCreated, this, &GenericLayout::appletCreated); 1037 } 1038 } 1039 1040 for (const auto containment : containments) { 1041 m_containments.removeAll(containment); 1042 } 1043 1044 if (containments.size() > 0) { 1045 m_latteViews.remove(latteView->containment()); 1046 } 1047 1048 //! sync the original layout file for integrity 1049 if (m_corona && m_corona->layoutsManager()->memoryUsage() == Types::MultipleLayouts) { 1050 m_storage->syncToLayoutFile(false); 1051 } 1052 1053 return containments; 1054 } 1055 1056 void GenericLayout::recreateView(Plasma::Containment *containment, bool delayed) 1057 { 1058 if (!m_corona || m_viewsToRecreate.contains(containment) || !containment || !m_latteViews.contains(containment)) { 1059 return; 1060 } 1061 1062 int delay = delayed ? 350 : 0; 1063 m_viewsToRecreate << containment; 1064 1065 //! give the time to config window to close itself first and then recreate the dock 1066 //! step:1 remove the latteview 1067 QTimer::singleShot(delay, [this, containment]() { 1068 auto view = m_latteViews[containment]; 1069 view->disconnectSensitiveSignals(); 1070 1071 //! step:2 add the new latteview 1072 connect(view, &QObject::destroyed, this, [this, containment]() { 1073 auto view = m_latteViews.take(containment); 1074 QTimer::singleShot(250, this, [this, containment]() { 1075 if (!m_latteViews.contains(containment)) { 1076 qDebug() << "recreate - step 2: adding dock for containment:" << containment->id(); 1077 addView(containment); 1078 m_viewsToRecreate.removeAll(containment); 1079 } 1080 }); 1081 }); 1082 1083 view->deleteLater(); 1084 }); 1085 } 1086 1087 1088 bool GenericLayout::latteViewExists(Plasma::Containment *containment) 1089 { 1090 if (!m_corona) { 1091 return false; 1092 } 1093 1094 return m_latteViews.keys().contains(containment); 1095 } 1096 1097 QList<Plasma::Types::Location> GenericLayout::availableEdgesForView(QScreen *scr, Latte::View *forView) const 1098 { 1099 using Plasma::Types; 1100 QList<Types::Location> edges{Types::BottomEdge, Types::LeftEdge, 1101 Types::TopEdge, Types::RightEdge}; 1102 1103 if (!m_corona) { 1104 return edges; 1105 } 1106 1107 for (const auto view : m_latteViews) { 1108 //! make sure that availabe edges takes into account only views that should be excluded, 1109 //! this is why the forView should not be excluded 1110 if (view && view != forView && view->positioner()->currentScreenName() == scr->name()) { 1111 edges.removeOne(view->location()); 1112 } 1113 } 1114 1115 return edges; 1116 } 1117 1118 bool GenericLayout::explicitDockOccupyEdge(int screen, Plasma::Types::Location location) const 1119 { 1120 if (!m_corona) { 1121 return false; 1122 } 1123 1124 for (const auto containment : m_containments) { 1125 if (m_storage->isLatteContainment(containment)) { 1126 bool onPrimary = containment->config().readEntry("onPrimary", true); 1127 int id = containment->lastScreen(); 1128 Plasma::Types::Location contLocation = containment->location(); 1129 1130 if (!onPrimary && id == screen && contLocation == location) { 1131 return true; 1132 } 1133 } 1134 } 1135 1136 return false; 1137 } 1138 1139 bool GenericLayout::primaryDockOccupyEdge(Plasma::Types::Location location) const 1140 { 1141 if (!m_corona) { 1142 return false; 1143 } 1144 1145 for (const auto containment : m_containments) { 1146 if (m_storage->isLatteContainment(containment)) { 1147 bool onPrimary = containment->config().readEntry("onPrimary", true); 1148 Plasma::Types::Location contLocation = containment->location(); 1149 1150 if (onPrimary && contLocation == location) { 1151 return true; 1152 } 1153 } 1154 } 1155 1156 return false; 1157 } 1158 1159 bool GenericLayout::mapContainsId(const Layout::ViewsMap *map, uint viewId) const 1160 { 1161 for(const auto &scr : map->keys()) { 1162 for(const auto &edge : (*map)[scr].keys()) { 1163 if ((*map)[scr][edge] == viewId) { 1164 return true; 1165 } 1166 } 1167 } 1168 1169 return false; 1170 } 1171 1172 //! screen name, location, containmentId 1173 Layout::ViewsMap GenericLayout::validViewsMap(Layout::ViewsMap *occupiedMap) 1174 { 1175 Layout::ViewsMap map; 1176 1177 if (!m_corona) { 1178 return map; 1179 } 1180 1181 if (occupiedMap != nullptr) { 1182 map = (*occupiedMap); 1183 } 1184 1185 QString prmScreenName = qGuiApp->primaryScreen()->name(); 1186 1187 //! first step: primary docks must be placed in primary screen free edges 1188 for (const auto containment : m_containments) { 1189 if (m_storage->isLatteContainment(containment)) { 1190 int screenId = 0; 1191 1192 //! valid screen id 1193 if (latteViewExists(containment)) { 1194 screenId = m_latteViews[containment]->positioner()->currentScreenId(); 1195 } else { 1196 screenId = containment->screen(); 1197 1198 if (screenId == -1) { 1199 screenId = containment->lastScreen(); 1200 } 1201 } 1202 1203 bool onPrimary{true}; 1204 1205 //! valid onPrimary flag 1206 if (latteViewExists(containment)) { 1207 onPrimary = m_latteViews[containment]->onPrimary(); 1208 } else { 1209 onPrimary = containment->config().readEntry("onPrimary", true); 1210 } 1211 1212 //! valid location 1213 Plasma::Types::Location location = containment->location(); 1214 1215 if (onPrimary && !map[prmScreenName].contains(location)) { 1216 map[prmScreenName][location] = containment->id(); 1217 } 1218 } 1219 } 1220 1221 //! second step: explicit docks must be placed in their screens if the screen edge is free 1222 for (const auto containment : m_containments) { 1223 if (m_storage->isLatteContainment(containment)) { 1224 int screenId = 0; 1225 1226 //! valid screen id 1227 if (latteViewExists(containment)) { 1228 screenId = m_latteViews[containment]->positioner()->currentScreenId(); 1229 } else { 1230 screenId = containment->screen(); 1231 1232 if (screenId == -1) { 1233 screenId = containment->lastScreen(); 1234 } 1235 } 1236 1237 bool onPrimary{true}; 1238 1239 //! valid onPrimary flag 1240 if (latteViewExists(containment)) { 1241 onPrimary = m_latteViews[containment]->onPrimary(); 1242 } else { 1243 onPrimary = containment->config().readEntry("onPrimary", true); 1244 } 1245 1246 //! valid location 1247 Plasma::Types::Location location = containment->location(); 1248 1249 if (!onPrimary) { 1250 QString expScreenName = m_corona->screenPool()->connector(screenId); 1251 1252 if (m_corona->screenPool()->screenExists(screenId) && !map[expScreenName].contains(location)) { 1253 map[expScreenName][location] = containment->id(); 1254 } 1255 } 1256 } 1257 } 1258 1259 return map; 1260 } 1261 1262 1263 //! the central functions that updates loading/unloading latteviews 1264 //! concerning screen changed (for multi-screen setups mainly) 1265 void GenericLayout::syncLatteViewsToScreens(Layout::ViewsMap *occupiedMap) 1266 { 1267 if (!m_corona) { 1268 return; 1269 } 1270 1271 qDebug() << "START of SyncLatteViewsToScreens ...."; 1272 qDebug() << "LAYOUT ::: " << name(); 1273 qDebug() << "screen count changed -+-+ " << qGuiApp->screens().size(); 1274 1275 Layout::ViewsMap viewsMap = validViewsMap(occupiedMap); 1276 1277 if (occupiedMap != nullptr) { 1278 qDebug() << "Occupied map used :: " << *occupiedMap; 1279 } 1280 1281 QString prmScreenName = qGuiApp->primaryScreen()->name(); 1282 1283 qDebug() << "PRIMARY SCREEN :: " << prmScreenName; 1284 qDebug() << "LATTEVIEWS MAP :: " << viewsMap; 1285 1286 //! add views 1287 for (const auto containment : m_containments) { 1288 int screenId = containment->screen(); 1289 1290 if (screenId == -1) { 1291 screenId = containment->lastScreen(); 1292 } 1293 1294 if (!latteViewExists(containment) && mapContainsId(&viewsMap, containment->id())) { 1295 qDebug() << "syncLatteViewsToScreens: view must be added... for containment:" << containment->id() << " at screen:" << m_corona->screenPool()->connector(screenId); 1296 addView(containment); 1297 } 1298 } 1299 1300 //! remove views 1301 QList<Plasma::Containment *> viewsToDelete; 1302 1303 for (auto view : m_latteViews) { 1304 auto containment = view->containment(); 1305 if (containment && !mapContainsId(&viewsMap, containment->id())) { 1306 viewsToDelete << containment; 1307 } 1308 } 1309 1310 while(!viewsToDelete.isEmpty()) { 1311 auto containment = viewsToDelete.takeFirst(); 1312 auto view = m_latteViews.take(containment); 1313 qDebug() << "syncLatteViewsToScreens: view must be deleted... for containment:" << containment->id() << " at screen:" << view->positioner()->currentScreenName(); 1314 view->disconnectSensitiveSignals(); 1315 view->deleteLater(); 1316 } 1317 1318 //! reconsider views 1319 for (const auto view : m_latteViews) { 1320 if (view->containment() && mapContainsId(&viewsMap, view->containment()->id())) { 1321 //! if the dock will not be deleted its a very good point to reconsider 1322 //! if the screen in which is running is the correct one 1323 qDebug() << "syncLatteViewsToScreens: view must consider its screen... for containment:" << view->containment()->id() << " at screen:" << view->positioner()->currentScreenName(); 1324 view->reconsiderScreen(); 1325 } 1326 } 1327 1328 qDebug() << "end of, syncLatteViewsToScreens ...."; 1329 } 1330 1331 QList<int> GenericLayout::containmentSystrays(Plasma::Containment *containment) const 1332 { 1333 QList<int> trays; 1334 1335 if (m_storage->isLatteContainment(containment)) { 1336 auto applets = containment->config().group("Applets"); 1337 1338 for (const auto &applet : applets.groupList()) { 1339 KConfigGroup appletSettings = applets.group(applet).group("Configuration"); 1340 int tSysId = appletSettings.readEntry("SystrayContainmentId", -1); 1341 1342 if (tSysId != -1) { 1343 trays << tSysId; 1344 } 1345 } 1346 } 1347 1348 return trays; 1349 } 1350 1351 1352 QString GenericLayout::reportHtml(const ScreenPool *screenPool) 1353 { 1354 //qDebug() << "DBUS CALL ::: " << identifier << " - " << value; 1355 auto locationText = [this](const int &location) { 1356 switch (location) { 1357 case Plasma::Types::BottomEdge: return i18nc("bottom edge", "Bottom"); 1358 case Plasma::Types::LeftEdge: return i18nc("left edge", "Left"); 1359 case Plasma::Types::TopEdge: return i18nc("top edge", "Top"); 1360 case Plasma::Types::RightEdge: return i18nc("right edge", "Right"); 1361 } 1362 1363 return QString(); 1364 }; 1365 1366 auto idsLineStr = [this](const QList<int> list) { 1367 QString line; 1368 1369 for(int i=0; i<list.count(); ++i) { 1370 if(i!=0) { 1371 line += ", "; 1372 } 1373 line += "["+QString::number(list[i]) + "]"; 1374 } 1375 1376 return line; 1377 }; 1378 1379 ///////! main report layout code 1380 1381 QString report; 1382 1383 int activeViews = m_latteViews.count(); 1384 1385 report += "<table cellspacing='8'>"; 1386 report += "<tr>"; 1387 report += "<td><b>" + i18nc("active docks panels","Active Views:") +"</b></td>"; 1388 if (activeViews == 0) { 1389 report += "<td><b> -- </b></td>"; 1390 } else { 1391 report += "<td><b><font color='blue'>" + QString::number(activeViews) +"</font></b></td>"; 1392 } 1393 report += "</tr>"; 1394 1395 //! latte containment ids, systrays 1396 QHash<int, QList<int>> systrays; 1397 QList<int> assignedSystrays; 1398 QList<int> orphanSystrays; 1399 1400 if (isActive()) { 1401 //! organize systrays 1402 for (const auto containment : m_containments) { 1403 QList<int> trays = containmentSystrays(containment); 1404 if (trays.count() > 0) { 1405 systrays[containment->id()] = trays; 1406 assignedSystrays << trays; 1407 } 1408 } 1409 1410 //! orphan systrays 1411 for (const auto containment : m_containments) { 1412 if (!m_storage->isLatteContainment(containment) && !assignedSystrays.contains(containment->id())) { 1413 orphanSystrays << containment->id(); 1414 } 1415 } 1416 } else { 1417 m_storage->systraysInformation(systrays, assignedSystrays, orphanSystrays); 1418 } 1419 1420 report += "<tr>"; 1421 report += "<td><b>" + i18n("Orphan Systrays:") +"</b></td>"; 1422 if (orphanSystrays.count() == 0) { 1423 report += "<td><b> -- </b></td>"; 1424 } else { 1425 report += "<td><b><font color='red'>" + idsLineStr(orphanSystrays) +"</font></b></td>"; 1426 } 1427 report += "</tr>"; 1428 report += "</table>"; 1429 1430 report += "<table cellspacing='14'>"; 1431 report += "<tr><td align='center'><b>" + i18nc("view id","ID") + "</b></td>" + 1432 "<td align='center'><b>" + i18n("Screen") + "</b></td>" + 1433 "<td align='center'><b>" + i18nc("screen edge","Edge") + "</b></td>" + 1434 "<td align='center'><b>" + i18nc("active dock/panel","Active") + "</b></td>" + 1435 "<td align='center'><b>" + i18n("Systrays") + "</b></td>"; 1436 1437 report += "<tr><td colspan='5'><hr></td></tr>"; 1438 1439 QList<ViewData> viewsData; 1440 1441 if (isActive()) { 1442 //! collect viewData results 1443 for (const auto containment : m_containments) { 1444 if (m_storage->isLatteContainment(containment)) { 1445 ViewData vData; 1446 vData.id = containment->id(); 1447 vData.active = latteViewExists(containment); 1448 vData.location = containment->location(); 1449 1450 //! onPrimary / Screen Id 1451 int screenId = -1; 1452 bool onPrimary = true; 1453 1454 if (latteViewExists(containment)) { 1455 screenId = m_latteViews[containment]->positioner()->currentScreenId(); 1456 onPrimary = m_latteViews[containment]->onPrimary(); 1457 } else { 1458 screenId = containment->screen(); 1459 onPrimary = containment->config().readEntry("onPrimary", true); 1460 1461 if (screenId == -1) { 1462 screenId = containment->lastScreen(); 1463 } 1464 } 1465 1466 vData.onPrimary = onPrimary; 1467 vData.screenId = screenId; 1468 vData.systrays = containmentSystrays(containment); 1469 1470 viewsData << vData; 1471 } 1472 } 1473 } else { 1474 viewsData = m_storage->viewsData(systrays); 1475 } 1476 1477 //! sort views data 1478 viewsData = sortedViewsData(viewsData); 1479 1480 QStringList unknownScreens; 1481 1482 //! print viewData results 1483 for (int i=0; i<viewsData.count(); ++i) { 1484 report += "<tr>"; 1485 1486 //! view id 1487 QString idStr = "[" + QString::number(viewsData[i].id) + "]"; 1488 if(viewsData[i].active) { 1489 idStr = "<b>" + idStr + "</b>"; 1490 } 1491 report += "<td align='center'>" + idStr + "</td>"; 1492 1493 //! screen 1494 QString screenStr = "[" + i18nc("primary screen","Primary") + "]"; 1495 if (viewsData[i].active && viewsData[i].onPrimary) { 1496 screenStr = "<font color='green'>" + screenStr + "</font>"; 1497 } 1498 if (!viewsData[i].onPrimary) { 1499 if (!screenPool->hasId(viewsData[i].screenId)) { 1500 screenStr = "<font color='red'><i>[" + QString::number(viewsData[i].screenId) + "]</i></font>"; 1501 1502 unknownScreens << QString("[" + QString::number(viewsData[i].screenId) + "]"); 1503 } else { 1504 screenStr = screenPool->connector(viewsData[i].screenId); 1505 } 1506 } 1507 if(viewsData[i].active) { 1508 screenStr = "<b>" + screenStr + "</b>"; 1509 } 1510 report += "<td align='center'>" + screenStr + "</td>"; 1511 1512 //! edge 1513 QString edgeStr = locationText(viewsData[i].location); 1514 if(viewsData[i].active) { 1515 edgeStr = "<b>" + edgeStr + "</b>"; 1516 } 1517 report += "<td align='center'>" + edgeStr + "</td>" ; 1518 1519 //! active 1520 QString activeStr = " -- "; 1521 if(viewsData[i].active) { 1522 activeStr = "<b>" + i18n("Yes") + "</b>"; 1523 } 1524 report += "<td align='center'>" + activeStr + "</td>" ; 1525 1526 //! systrays 1527 QString systraysStr = " -- "; 1528 if (viewsData[i].systrays.count() > 0) { 1529 systraysStr = idsLineStr(viewsData[i].systrays); 1530 } 1531 if(viewsData[i].active) { 1532 systraysStr = "<b>" + systraysStr + "</b>"; 1533 } 1534 report += "<td align='center'>" + systraysStr + "</td>"; 1535 1536 report += "</tr>"; 1537 } 1538 1539 report += "</table>"; 1540 1541 report += "<br/><hr>"; 1542 1543 QStringList errorsList; 1544 bool broken = m_storage->layoutIsBroken(errorsList); 1545 1546 if (!broken && unknownScreens.count() == 0) { 1547 report += "<font color='green'>" + i18n("No errors were identified for this layout...") + "</font><br/>"; 1548 } else { 1549 report += "<font color='red'><b>" + i18n("Errors:") + "</b></font><br/>"; 1550 } 1551 1552 if (broken){ 1553 for(int i=0; i<errorsList.count(); ++i) { 1554 report += "<font color='red'><b>[" + QString::number(i) + "] - " + errorsList[i] + "</b></font><br/>"; 1555 } 1556 } 1557 1558 if (unknownScreens.count() > 0) { 1559 report += "<font color='red'><b>" + i18n("Unknown screens: ") + unknownScreens.join(", ") + "</b></font><br/>"; 1560 } 1561 1562 return report; 1563 } 1564 1565 QList<int> GenericLayout::viewsScreens() 1566 { 1567 QList<int> screens; 1568 1569 if (isActive()) { 1570 for (const auto containment : m_containments) { 1571 if (m_storage->isLatteContainment(containment)) { 1572 int screenId = -1; 1573 1574 //! valid screen id 1575 if (latteViewExists(containment)) { 1576 screenId = m_latteViews[containment]->positioner()->currentScreenId(); 1577 } else { 1578 screenId = containment->screen(); 1579 1580 if (screenId == -1) { 1581 screenId = containment->lastScreen(); 1582 } 1583 } 1584 1585 if (screenId!=-1 &&!screens.contains(screenId)) { 1586 screens << screenId; 1587 } 1588 } 1589 } 1590 1591 return screens; 1592 } else { 1593 return m_storage->viewsScreens(); 1594 } 1595 } 1596 1597 1598 //! STORAGE 1599 1600 bool GenericLayout::isWritable() const 1601 { 1602 return m_storage->isWritable(); 1603 } 1604 1605 void GenericLayout::lock() 1606 { 1607 m_storage->lock(); 1608 } 1609 1610 void GenericLayout::unlock() 1611 { 1612 m_storage->unlock(); 1613 } 1614 1615 void GenericLayout::syncToLayoutFile(bool removeLayoutId) 1616 { 1617 m_storage->syncToLayoutFile(removeLayoutId); 1618 } 1619 1620 void GenericLayout::copyView(Plasma::Containment *containment) 1621 { 1622 m_storage->copyView(containment); 1623 emit viewEdgeChanged(); 1624 } 1625 1626 void GenericLayout::importToCorona() 1627 { 1628 m_storage->importToCorona(); 1629 } 1630 1631 bool GenericLayout::layoutIsBroken() const 1632 { 1633 QStringList errors; 1634 return m_storage->layoutIsBroken(errors); 1635 } 1636 1637 } 1638 }