File indexing completed on 2024-04-28 13:26:02

0001 /*
0002     SPDX-FileCopyrightText: 2021 Michail Vourlakos <mvourlakos@gmail.com>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "layoutmanager.h"
0007 
0008 // local
0009 #include <plugin/lattetypes.h>
0010 
0011 // Qt
0012 #include <QtMath>
0013 
0014 // KDE
0015 #include <KDeclarative/ConfigPropertyMap>
0016 
0017 // Plasma
0018 #include <Plasma>
0019 #include <Plasma/Applet>
0020 #include <PlasmaQuick/AppletQuickItem>
0021 
0022 #define ISAPPLETLOCKEDOPTION "lockZoom"
0023 #define ISCOLORINGBLOCKEDOPTION "userBlocksColorizing"
0024 
0025 namespace Latte{
0026 namespace Containment{
0027 
0028 const int LayoutManager::JUSTIFYSPLITTERID;
0029 
0030 LayoutManager::LayoutManager(QObject *parent)
0031     : QObject(parent)
0032 {
0033     m_option[ISAPPLETLOCKEDOPTION] = "lockedZoomApplets";
0034     m_option[ISCOLORINGBLOCKEDOPTION] = "userBlocksColorizingApplets";
0035 
0036     connect(this, &LayoutManager::rootItemChanged, this, &LayoutManager::onRootItemChanged);
0037 
0038     m_hasRestoredAppletsTimer.setInterval(2000);
0039     m_hasRestoredAppletsTimer.setSingleShot(true);
0040     connect(&m_hasRestoredAppletsTimer, &QTimer::timeout, this, [&]() {
0041         m_hasRestoredApplets = true;
0042         emit hasRestoredAppletsChanged();
0043     });
0044 }
0045 
0046 bool LayoutManager::hasRestoredApplets() const
0047 {
0048     return m_hasRestoredApplets;
0049 }
0050 
0051 int LayoutManager::splitterPosition() const
0052 {
0053     return m_splitterPosition;
0054 }
0055 
0056 void LayoutManager::setSplitterPosition(const int &position)
0057 {
0058     if (m_splitterPosition == position) {
0059         return;
0060     }
0061 
0062     m_splitterPosition = position;
0063     emit splitterPositionChanged();
0064 }
0065 
0066 int LayoutManager::splitterPosition2() const
0067 {
0068     return m_splitterPosition2;
0069 }
0070 
0071 void LayoutManager::setSplitterPosition2(const int &position)
0072 {
0073     if (m_splitterPosition2 == position) {
0074         return;
0075     }
0076 
0077     m_splitterPosition2 = position;
0078     emit splitterPosition2Changed();
0079 }
0080 
0081 QList<int> LayoutManager::appletOrder() const
0082 {
0083     return m_appletOrder;
0084 }
0085 
0086 void LayoutManager::setAppletOrder(const QList<int> &order)
0087 {
0088     if (m_appletOrder == order) {
0089         return;
0090     }
0091 
0092     m_appletOrder = order;
0093     emit appletOrderChanged();
0094 }
0095 
0096 QList<int> LayoutManager::lockedZoomApplets() const
0097 {
0098     return m_lockedZoomApplets;
0099 }
0100 
0101 void LayoutManager::setLockedZoomApplets(const QList<int> &applets)
0102 {
0103     if (m_lockedZoomApplets == applets) {
0104         return;
0105     }
0106 
0107     m_lockedZoomApplets = applets;
0108     emit lockedZoomAppletsChanged();
0109 }
0110 
0111 QList<int> LayoutManager::order() const
0112 {
0113     return m_order;
0114 }
0115 
0116 void LayoutManager::setOrder(const QList<int> &order)
0117 {
0118     if (m_order == order) {
0119         return;
0120     }
0121 
0122     m_order = order;
0123     emit orderChanged();
0124 }
0125 
0126 QList<int> LayoutManager::userBlocksColorizingApplets() const
0127 {
0128     return m_userBlocksColorizingApplets;
0129 }
0130 
0131 void LayoutManager::setUserBlocksColorizingApplets(const QList<int> &applets)
0132 {
0133     if (m_userBlocksColorizingApplets == applets) {
0134         return;
0135     }
0136 
0137     m_userBlocksColorizingApplets = applets;
0138     emit userBlocksColorizingAppletsChanged();
0139 }
0140 
0141 QList<int> LayoutManager::appletsInScheduledDestruction() const
0142 {
0143     return m_appletsInScheduledDestruction.keys();
0144 }
0145 
0146 void LayoutManager::setAppletInScheduledDestruction(const int &id, const bool &enabled)
0147 {
0148     if (m_appletsInScheduledDestruction.contains(id) && !enabled) {
0149         m_appletsInScheduledDestruction.remove(id);
0150         emit appletsInScheduledDestructionChanged();
0151     } else if (!m_appletsInScheduledDestruction.contains(id) && enabled) {
0152         m_appletsInScheduledDestruction[id] = appletItem(id);
0153         emit appletsInScheduledDestructionChanged();
0154     }
0155 }
0156 
0157 
0158 QObject *LayoutManager::plasmoid() const
0159 {
0160     return m_plasmoid;
0161 }
0162 
0163 void LayoutManager::setPlasmoid(QObject *plasmoid)
0164 {
0165     if (m_plasmoid == plasmoid) {
0166         return;
0167     }
0168 
0169     m_plasmoid = plasmoid;
0170 
0171     if (m_plasmoid) {
0172         m_configuration = qobject_cast<KDeclarative::ConfigPropertyMap *>(m_plasmoid->property("configuration").value<QObject *>());
0173     }
0174 
0175     emit plasmoidChanged();
0176 }
0177 
0178 QQuickItem *LayoutManager::rootItem() const
0179 {
0180     return m_rootItem;
0181 }
0182 
0183 void LayoutManager::setRootItem(QQuickItem *root)
0184 {
0185     if (m_rootItem == root) {
0186         return;
0187     }
0188 
0189     m_rootItem = root;
0190     emit rootItemChanged();
0191 }
0192 
0193 QQuickItem *LayoutManager::dndSpacer() const
0194 {
0195     return m_dndSpacer;
0196 }
0197 
0198 void LayoutManager::setDndSpacer(QQuickItem *dnd)
0199 {
0200     if (m_dndSpacer == dnd) {
0201         return;
0202     }
0203 
0204     m_dndSpacer = dnd;
0205     emit dndSpacerChanged();
0206 }
0207 
0208 QQuickItem *LayoutManager::mainLayout() const
0209 {
0210     return m_mainLayout;
0211 }
0212 
0213 void LayoutManager::setMainLayout(QQuickItem *main)
0214 {
0215     if (main == m_mainLayout) {
0216         return;
0217     }
0218 
0219     m_mainLayout = main;
0220     emit mainLayoutChanged();
0221 }
0222 
0223 QQuickItem *LayoutManager::startLayout() const
0224 {
0225     return m_startLayout;
0226 }
0227 
0228 void LayoutManager::setStartLayout(QQuickItem *start)
0229 {
0230     if (m_startLayout == start) {
0231         return;
0232     }
0233 
0234     m_startLayout = start;
0235     emit startLayoutChanged();
0236 }
0237 
0238 QQuickItem *LayoutManager::endLayout() const
0239 {
0240     return m_endLayout;
0241 }
0242 
0243 void LayoutManager::setEndLayout(QQuickItem *end)
0244 {
0245     if (m_endLayout == end) {
0246         return;
0247     }
0248 
0249     m_endLayout = end;
0250     emit endLayoutChanged();
0251 }
0252 
0253 QQuickItem *LayoutManager::metrics() const
0254 {
0255     return m_metrics;
0256 }
0257 
0258 void LayoutManager::setMetrics(QQuickItem *metrics)
0259 {
0260     if (m_metrics == metrics) {
0261         return;
0262     }
0263 
0264     m_metrics = metrics;
0265     emit metricsChanged();
0266 }
0267 
0268 void LayoutManager::updateOrder()
0269 {
0270     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
0271 
0272     auto nextorder = m_appletOrder;
0273 
0274     if (alignment==Latte::Types::Justify) {
0275         nextorder.insert(m_splitterPosition-1, JUSTIFYSPLITTERID);
0276         nextorder.insert(m_splitterPosition2-1, JUSTIFYSPLITTERID);
0277     }
0278 
0279     setOrder(nextorder);
0280 }
0281 
0282 void LayoutManager::onRootItemChanged()
0283 {
0284     if (!m_rootItem) {
0285         return;
0286     }
0287 
0288     auto rootMetaObject = m_rootItem->metaObject();
0289     int createAppletItemIndex = rootMetaObject->indexOfMethod("createAppletItem(QVariant)");
0290     m_createAppletItemMethod = rootMetaObject->method(createAppletItemIndex);
0291 
0292     int createJustifySplitterIndex = rootMetaObject->indexOfMethod("createJustifySplitter()");
0293     m_createJustifySplitterMethod = rootMetaObject->method(createJustifySplitterIndex);
0294 
0295     int initAppletContainerIndex = rootMetaObject->indexOfMethod("initAppletContainer(QVariant,QVariant)");
0296     m_initAppletContainerMethod = rootMetaObject->method(initAppletContainerIndex);
0297 }
0298 
0299 bool LayoutManager::isValidApplet(const int &id)
0300 {
0301     //! should be loaded after m_plasmoid has been set properly
0302     if (!m_plasmoid) {
0303         return false;
0304     }
0305 
0306     QList<QObject *> applets = m_plasmoid->property("applets").value<QList<QObject *>>();
0307 
0308     for(int i=0; i<applets.count(); ++i) {
0309         uint appletid = applets[i]->property("id").toUInt();
0310         if (id>0 && appletid == (uint)id) {
0311             return true;
0312         }
0313     }
0314 
0315     return false;
0316 }
0317 
0318 //! Actions
0319 void LayoutManager::restore()
0320 {
0321     QList<int> appletIdsOrder = toIntList((*m_configuration)["appletOrder"].toString());
0322     QList<QObject *> applets = m_plasmoid->property("applets").value<QList<QObject *>>();
0323 
0324     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
0325     int splitterPosition = (*m_configuration)["splitterPosition"].toInt();
0326     int splitterPosition2 = (*m_configuration)["splitterPosition2"].toInt();
0327 
0328     if (alignment==Latte::Types::Justify) {
0329         if (splitterPosition!=-1 && splitterPosition2!=-1) {
0330             appletIdsOrder.insert(splitterPosition-1, -1);
0331             appletIdsOrder.insert(splitterPosition2-1, -1);
0332         } else {
0333             appletIdsOrder.insert(0, -1);
0334             appletIdsOrder << -1;
0335         }
0336     }
0337 
0338     QList<int> invalidApplets;
0339 
0340     //! track invalid applets, meaning applets that have not be loaded properly
0341     for (int i=0; i<appletIdsOrder.count(); ++i) {
0342         int aid = appletIdsOrder[i];
0343 
0344         if (aid>0 && !isValidApplet(aid)) {
0345             invalidApplets << aid;
0346         }
0347     }
0348 
0349     //! remove invalid applets from the ids order
0350     for (int i=0; i<invalidApplets.count(); ++i) {
0351         appletIdsOrder.removeAll(invalidApplets[i]);
0352     }
0353 
0354     //! order valid applets based on the cleaned applet ids order
0355     QList<QObject *> orderedApplets;
0356 
0357     for (int i=0; i<appletIdsOrder.count(); ++i) {
0358         if (appletIdsOrder[i] == -1) {
0359             orderedApplets << nullptr;
0360             continue;
0361         }
0362 
0363         for(int j=0; j<applets.count(); ++j) {
0364             if (applets[j]->property("id").toInt() == appletIdsOrder[i]) {
0365                 orderedApplets << applets[j];
0366                 break;
0367             }
0368         }
0369     }
0370 
0371     QList<int> orphanedIds;
0372     for(int i=0; i<applets.count(); ++i) {
0373         uint id = applets[i]->property("id").toUInt();
0374 
0375         if (!appletIdsOrder.contains(id)) {
0376             orphanedIds << id;
0377         }
0378     }
0379 
0380     //Validator
0381     QList<int> validateAppletsOrder;
0382     for (int i=0; i<orderedApplets.count(); ++i) {
0383         if (orderedApplets[i] == nullptr) {
0384             validateAppletsOrder << -1;
0385             continue;
0386         }
0387 
0388         validateAppletsOrder << orderedApplets[i]->property("id").toUInt();
0389     }
0390 
0391     for(int i=0; i<applets.count(); ++i) {
0392         if (!orderedApplets.contains(applets[i])) {
0393             //! after order has been loaded correctly all renaming applets that do not have specified position are added in the end
0394             orderedApplets<<applets[i];
0395         }
0396     }
0397 
0398     qDebug() << "org.kde.latte ::: applets found :: " << applets.count() << " : " << appletIdsOrder << " :: " << splitterPosition << " : " << splitterPosition2 << " | " << alignment;
0399     qDebug() << "org.kde.latte ::: applets orphaned added in the end:: " << orphanedIds;
0400     qDebug() << "org.kde.latte ::: applets recorded order :: " << appletIdsOrder;
0401     qDebug() << "org.kde.latte ::: applets produced order ?? " << validateAppletsOrder;
0402 
0403     if (alignment != Latte::Types::Justify) {
0404         for (int i=0; i<orderedApplets.count(); ++i) {
0405             if (orderedApplets[i] == nullptr) {
0406                 continue;
0407             }
0408 
0409             QVariant appletItemVariant;
0410             QVariant appletVariant; appletVariant.setValue(orderedApplets[i]);
0411             m_createAppletItemMethod.invoke(m_rootItem, Q_RETURN_ARG(QVariant, appletItemVariant), Q_ARG(QVariant, appletVariant));
0412             QQuickItem *appletItem = appletItemVariant.value<QQuickItem *>();
0413             appletItem->setParentItem(m_mainLayout);
0414         }
0415     } else {
0416         QQuickItem *parentlayout = m_startLayout;
0417 
0418         for (int i=0; i<orderedApplets.count(); ++i) {
0419             if (orderedApplets[i] == nullptr) {
0420                 QVariant splitterItemVariant;
0421                 m_createJustifySplitterMethod.invoke(m_rootItem, Q_RETURN_ARG(QVariant, splitterItemVariant));
0422                 QQuickItem *splitterItem = splitterItemVariant.value<QQuickItem *>();
0423 
0424                 if (parentlayout == m_startLayout) {
0425                     //! first splitter as last child in startlayout
0426                     splitterItem->setParentItem(parentlayout);
0427                     parentlayout = m_mainLayout;
0428                 } else if (parentlayout == m_mainLayout) {
0429                     //! second splitter as first child in endlayout
0430                     parentlayout = m_endLayout;
0431                     splitterItem->setParentItem(parentlayout);
0432                 }
0433 
0434                 continue;
0435             }
0436 
0437             QVariant appletItemVariant;
0438             QVariant appletVariant; appletVariant.setValue(orderedApplets[i]);
0439             m_createAppletItemMethod.invoke(m_rootItem, Q_RETURN_ARG(QVariant, appletItemVariant), Q_ARG(QVariant, appletVariant));
0440             QQuickItem *appletItem = appletItemVariant.value<QQuickItem *>();
0441             appletItem->setParentItem(parentlayout);
0442         }
0443     }
0444 
0445     restoreOptions();
0446     save(); //will restore also a valid applets ids order
0447     cleanupOptions();
0448     initSaveConnections();
0449     m_hasRestoredAppletsTimer.start();
0450 }
0451 
0452 void LayoutManager::initSaveConnections()
0453 {
0454     connect(this, &LayoutManager::appletOrderChanged, this, &LayoutManager::cleanupOptions);
0455     connect(this, &LayoutManager::splitterPositionChanged, this, &LayoutManager::saveOptions);
0456     connect(this, &LayoutManager::splitterPosition2Changed, this, &LayoutManager::saveOptions);
0457     connect(this, &LayoutManager::lockedZoomAppletsChanged, this, &LayoutManager::saveOptions);
0458     connect(this, &LayoutManager::userBlocksColorizingAppletsChanged, this, &LayoutManager::saveOptions);
0459 }
0460 
0461 void LayoutManager::restoreOptions()
0462 {
0463     restoreOption(ISAPPLETLOCKEDOPTION);
0464     restoreOption(ISCOLORINGBLOCKEDOPTION);
0465 }
0466 
0467 void LayoutManager::restoreOption(const char *option)
0468 {
0469     QList<int> applets = toIntList((*m_configuration)[m_option[option]].toString());
0470 
0471     if (option == ISAPPLETLOCKEDOPTION) {
0472         setLockedZoomApplets(applets);
0473     } else if (option == ISCOLORINGBLOCKEDOPTION) {
0474         setUserBlocksColorizingApplets(applets);
0475     }
0476 }
0477 
0478 bool LayoutManager::isJustifySplitter(const QQuickItem *item) const
0479 {
0480     return item && (item->property("isInternalViewSplitter").toBool() == true);
0481 }
0482 
0483 bool LayoutManager::isMasqueradedIndex(const int &x, const int &y)
0484 {
0485     return (x==y && x<=MASQUERADEDINDEXTOPOINTBASE && y<=MASQUERADEDINDEXTOPOINTBASE);
0486 }
0487 
0488 int LayoutManager::masquearadedIndex(const int &x, const int &y)
0489 {
0490     return qAbs(x - MASQUERADEDINDEXTOPOINTBASE);
0491 }
0492 
0493 QPoint LayoutManager::indexToMasquearadedPoint(const int &index)
0494 {
0495     return QPoint(MASQUERADEDINDEXTOPOINTBASE-index, MASQUERADEDINDEXTOPOINTBASE-index);
0496 }
0497 
0498 void LayoutManager::reorderParabolicSpacers()
0499 {
0500     QQuickItem *startParabolicSpacer = m_mainLayout->property("startParabolicSpacer").value<QQuickItem *>();
0501     QQuickItem *endParabolicSpacer = m_mainLayout->property("endParabolicSpacer").value<QQuickItem *>();
0502 
0503     if (!startParabolicSpacer || !endParabolicSpacer) {
0504         return;
0505     }
0506 
0507     insertAtLayoutTail(m_mainLayout, startParabolicSpacer);
0508     insertAtLayoutHead(m_mainLayout, endParabolicSpacer);
0509 }
0510 
0511 void LayoutManager::save()
0512 {
0513     QList<int> appletIds;
0514 
0515     reorderParabolicSpacers();
0516 
0517     auto collectLayoutAppletIds = [](QQuickItem *layout, QList<int> &appletIds) {
0518         int childCount = 0;
0519         for (int i=0; i<layout->childItems().count(); ++i) {
0520             QQuickItem *item = layout->childItems()[i];
0521             bool isInternalSplitter = item->property("isInternalViewSplitter").toBool();
0522             bool isParabolicEdgeSpacer = item->property("isParabolicEdgeSpacer").toBool();
0523             if (!isInternalSplitter && !isParabolicEdgeSpacer) {
0524                 QVariant appletVariant = item->property("applet");
0525                 if (!appletVariant.isValid()) {
0526                     continue;
0527                 }
0528 
0529                 QObject *applet = appletVariant.value<QObject *>();
0530 
0531                 if (!applet) {
0532                     continue;
0533                 }
0534 
0535                 uint id = applet->property("id").toUInt();
0536 
0537                 if (id>0) {
0538                     childCount++;
0539                     appletIds << id;
0540                 }
0541             }
0542         }
0543         return childCount;
0544     };
0545 
0546     int startChilds = collectLayoutAppletIds(m_startLayout, appletIds);
0547     int mainChilds  = collectLayoutAppletIds(m_mainLayout,  appletIds);
0548     int endChilds   = collectLayoutAppletIds(m_endLayout,   appletIds);
0549 
0550     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
0551 
0552     if (alignment == Latte::Types::Justify) {
0553         setSplitterPosition(startChilds + 1);
0554         setSplitterPosition2(startChilds + 1 + mainChilds + 1);
0555     } else {
0556         int splitterPosition = (*m_configuration)["splitterPosition"].toInt();
0557         int splitterPosition2 = (*m_configuration)["splitterPosition2"].toInt();
0558 
0559         setSplitterPosition(splitterPosition);
0560         setSplitterPosition2(splitterPosition2);
0561     }
0562 
0563     //! are not writing in config file for some cases mentioned in class header so they are not used
0564     //(*m_configuration)["splitterPosition"] = QVariant(startChilds + 1);
0565     //(*m_configuration)["splitterPosition2"] = QVariant(startChilds + 1 + mainChilds + 1);
0566     //(*m_configuration)["appletOrder"] = appletIds.join(";");
0567 
0568     setAppletOrder(appletIds);
0569 
0570     //! publish updated order
0571     updateOrder();
0572 
0573     //! save applet order
0574     QString appletsserialized = toStr(appletIds);
0575 
0576     if ((*m_configuration)["appletOrder"] != appletsserialized) {
0577         m_configuration->insert("appletOrder", appletsserialized);
0578         emit m_configuration->valueChanged("appletOrder", appletsserialized);
0579     }
0580 }
0581 
0582 void LayoutManager::saveOptions()
0583 {    
0584     QString lockedserialized =  toStr(m_lockedZoomApplets);
0585     if ((*m_configuration)[m_option[ISAPPLETLOCKEDOPTION]] != lockedserialized) {
0586         m_configuration->insert(m_option[ISAPPLETLOCKEDOPTION], lockedserialized);
0587         emit m_configuration->valueChanged(m_option[ISAPPLETLOCKEDOPTION], lockedserialized);
0588     }
0589 
0590     QString colorsserialized = toStr(m_userBlocksColorizingApplets);
0591     if ((*m_configuration)[m_option[ISCOLORINGBLOCKEDOPTION]] != colorsserialized) {
0592         m_configuration->insert(m_option[ISCOLORINGBLOCKEDOPTION], colorsserialized);
0593         emit m_configuration->valueChanged(m_option[ISCOLORINGBLOCKEDOPTION], colorsserialized);
0594     }
0595 
0596     if ((*m_configuration)["splitterPosition"] != m_splitterPosition) {
0597         m_configuration->insert("splitterPosition", m_splitterPosition);
0598         emit m_configuration->valueChanged(m_option["splitterPosition"], m_splitterPosition);
0599     }
0600 
0601     if ((*m_configuration)["splitterPosition2"] != m_splitterPosition2) {
0602         m_configuration->insert("splitterPosition2", m_splitterPosition2);
0603         emit m_configuration->valueChanged(m_option["splitterPosition2"], m_splitterPosition2);
0604     }
0605 }
0606 
0607 void LayoutManager::setOption(const int &appletId, const QString &property, const QVariant &value)
0608 {
0609     if (property == ISAPPLETLOCKEDOPTION) {
0610         bool enabled = value.toBool();
0611 
0612         if (enabled && !m_lockedZoomApplets.contains(appletId)) {
0613             QList<int> applets = m_lockedZoomApplets; applets << appletId;
0614             setLockedZoomApplets(applets);
0615         } else if (!enabled && m_lockedZoomApplets.contains(appletId)) {
0616             QList<int> applets = m_lockedZoomApplets; applets.removeAll(appletId);
0617             setLockedZoomApplets(applets);
0618         }
0619     } else if (property == ISCOLORINGBLOCKEDOPTION) {
0620         bool enabled = value.toBool();
0621 
0622         if (enabled && !m_userBlocksColorizingApplets.contains(appletId)) {
0623             QList<int> applets = m_userBlocksColorizingApplets; applets << appletId;
0624             setUserBlocksColorizingApplets(applets);
0625         } else if (!enabled && m_userBlocksColorizingApplets.contains(appletId)) {
0626             QList<int> applets = m_userBlocksColorizingApplets; applets.removeAll(appletId);
0627             setUserBlocksColorizingApplets(applets);
0628         }
0629     }
0630 }
0631 
0632 void LayoutManager::insertBefore(QQuickItem *hoveredItem, QQuickItem *item)
0633 {
0634     if (!hoveredItem || !item || hoveredItem == item) {
0635         return;
0636     }
0637 
0638     item->setParentItem(hoveredItem->parentItem());
0639     item->stackBefore(hoveredItem);
0640 }
0641 
0642 void LayoutManager::insertAfter(QQuickItem *hoveredItem, QQuickItem *item)
0643 {
0644     if (!hoveredItem || !item || hoveredItem == item) {
0645         return;
0646     }
0647 
0648     item->setParentItem(hoveredItem->parentItem());
0649     item->stackAfter(hoveredItem);
0650 }
0651 
0652 void LayoutManager::insertAtLayoutTail(QQuickItem *layout, QQuickItem *item)
0653 {
0654     if (!layout || !item) {
0655         return;
0656     }
0657 
0658     if (layout->childItems().count() > 0) {
0659         if (layout == m_endLayout && isJustifySplitter(layout->childItems()[0])) {
0660             //! this way we ignore the justify splitter in start layout
0661             insertAfter(layout->childItems()[0], item);
0662         } else {
0663             insertBefore(layout->childItems()[0], item);
0664         }
0665         return;
0666     }
0667 
0668     item->setParentItem(layout);
0669 }
0670 
0671 void LayoutManager::insertAtLayoutHead(QQuickItem *layout, QQuickItem *item)
0672 {
0673     if (!layout || !item) {
0674         return;
0675     }
0676 
0677     int count = layout->childItems().count();
0678 
0679     if (count > 0) {
0680         if (layout == m_startLayout && isJustifySplitter(layout->childItems()[count-1])) {
0681             //! this way we ignore the justify splitter in end layout
0682             insertBefore(layout->childItems()[count-1], item);
0683         } else {
0684             insertAfter(layout->childItems()[count-1], item);
0685         }
0686         return;
0687     }
0688 
0689     item->setParentItem(layout);
0690 }
0691 
0692 void LayoutManager::insertAtLayoutIndex(QQuickItem *layout, QQuickItem *item, const int &index)
0693 {
0694     if (!layout || !item) {
0695         return;
0696     }
0697 
0698     if (index == 0) {
0699         insertAtLayoutTail(layout, item);
0700     } else if (index >= layout->childItems().count()) {
0701         insertAtLayoutHead(layout, item);
0702     } else {
0703         insertBefore(layout->childItems()[index], item);
0704     }
0705 }
0706 
0707 bool LayoutManager::insertAtLayoutCoordinates(QQuickItem *layout, QQuickItem *item, int x, int y)
0708 {
0709     if (!layout || !item || !m_plasmoid || !layout->contains(QPointF(x,y))) {
0710         return false;
0711     }
0712 
0713     bool horizontal = (m_plasmoid->property("formFactor").toInt() != Plasma::Types::Vertical);
0714     bool vertical = !horizontal;
0715     int rowspacing = qMax(0, layout->property("rowSpacing").toInt());
0716     int columnspacing = qMax(0, layout->property("columnSpacing").toInt());
0717 
0718     if (horizontal) {
0719         y = layout->height() / 2;
0720     } else {
0721         x = layout->width() / 2;
0722     }
0723 
0724     //! child renamed at hovered
0725     QQuickItem *hovered = layout->childAt(x, y);
0726 
0727     //if we got a place inside the space between 2 applets, we have to find it manually
0728     if (!hovered) {
0729         int size = layout->childItems().count();
0730         if (horizontal) {
0731             for (int i = 0; i < size; ++i) {
0732                 if (i>=layout->childItems().count()) {
0733                     break;
0734                 }
0735 
0736                 QQuickItem *candidate = layout->childItems()[i];
0737                 int right = candidate->x() + candidate->width() + rowspacing;
0738                 if (x>=candidate->x() && x<right) {
0739                     hovered = candidate;
0740                     break;
0741                 }
0742             }
0743         } else {
0744             for (int i = 0; i < size; ++i) {
0745                 if (i>=layout->childItems().count()) {
0746                     break;
0747                 }
0748 
0749                 QQuickItem *candidate = layout->childItems()[i];
0750                 int bottom = candidate->y() + candidate->height() + columnspacing;
0751                 if (y>=candidate->y() && y<bottom) {
0752                     hovered = candidate;
0753                     break;
0754                 }
0755             }
0756         }
0757     }
0758 
0759     if (hovered == item && item->parentItem() == layout) {
0760         //! already hovered and in correct position
0761         return true;
0762     }
0763 
0764     if (hovered) {
0765         if ((vertical && y < (hovered->y() + hovered->height()/2) && hovered->height() > 1) ||
0766                 (horizontal && x < (hovered->x() + hovered->width()/2) && hovered->width() > 1)) {
0767             insertBefore(hovered, item);
0768         } else {
0769             insertAfter(hovered, item);
0770         }
0771 
0772         return true;
0773     }
0774 
0775     return false;
0776 }
0777 
0778 QQuickItem *LayoutManager::firstSplitter()
0779 {
0780     for(int i=0; i<m_startLayout->childItems().count(); ++i) {
0781         QQuickItem *item = m_startLayout->childItems()[i];
0782         bool isInternalSplitter = item->property("isInternalViewSplitter").toBool();
0783         if (isInternalSplitter) {
0784             return item;
0785         }
0786     }
0787 
0788     for(int i=0; i<m_mainLayout->childItems().count(); ++i) {
0789         QQuickItem *item = m_mainLayout->childItems()[i];
0790         bool isInternalSplitter = item->property("isInternalViewSplitter").toBool();
0791         if (isInternalSplitter) {
0792             return item;
0793         }
0794     }
0795 
0796     for(int i=0; i<m_endLayout->childItems().count(); ++i) {
0797         QQuickItem *item = m_endLayout->childItems()[i];
0798         bool isInternalSplitter = item->property("isInternalViewSplitter").toBool();
0799         if (isInternalSplitter) {
0800             return item;
0801         }
0802     }
0803 
0804     return nullptr;
0805 }
0806 
0807 QQuickItem *LayoutManager::lastSplitter()
0808 {
0809     for(int i=m_endLayout->childItems().count()-1; i>=0; --i) {
0810         QQuickItem *item = m_endLayout->childItems()[i];
0811         bool isInternalSplitter = item->property("isInternalViewSplitter").toBool();
0812         if (isInternalSplitter) {
0813             return item;
0814         }
0815     }
0816 
0817     for(int i=m_mainLayout->childItems().count()-1; i>=0; --i) {
0818         QQuickItem *item = m_mainLayout->childItems()[i];
0819         bool isInternalSplitter = item->property("isInternalViewSplitter").toBool();
0820         if (isInternalSplitter) {
0821             return item;
0822         }
0823     }
0824 
0825     for(int i=m_endLayout->childItems().count()-1; i>=0; --i) {
0826         QQuickItem *item = m_endLayout->childItems()[i];
0827         bool isInternalSplitter = item->property("isInternalViewSplitter").toBool();
0828         if (isInternalSplitter) {
0829             return item;
0830         }
0831     }
0832 
0833     return nullptr;
0834 }
0835 
0836 QQuickItem *LayoutManager::appletItemInLayout(QQuickItem *layout, const int &id)
0837 {
0838     if (!layout) {
0839         return nullptr;
0840     }
0841 
0842     for(int i=0; i<layout->childItems().count(); ++i) {
0843         QQuickItem *item = layout->childItems()[i];
0844         bool isInternalSplitter = item->property("isInternalViewSplitter").toBool();
0845         bool isParabolicEdgeSpacer = item->property("isParabolicEdgeSpacer").toBool();
0846         if (!isInternalSplitter && !isParabolicEdgeSpacer) {
0847             QVariant appletVariant = item->property("applet");
0848             if (!appletVariant.isValid()) {
0849                 continue;
0850             }
0851 
0852             QObject *applet = appletVariant.value<QObject *>();
0853 
0854             if (!applet) {
0855                 continue;
0856             }
0857 
0858             int tempid = applet->property("id").toInt();
0859 
0860             if (id == tempid) {
0861                 return item;
0862             }
0863         }
0864     }
0865 
0866     return nullptr;
0867 }
0868 
0869 QQuickItem *LayoutManager::appletItem(const int &id)
0870 {
0871     QQuickItem *item = appletItemInLayout(m_mainLayout, id);
0872 
0873     if (!item) {
0874         item = appletItemInLayout(m_startLayout, id);
0875     }
0876 
0877     if (!item) {
0878         item = appletItemInLayout(m_endLayout, id);
0879     }
0880 
0881     return item;
0882 }
0883 
0884 int LayoutManager::dndSpacerIndex()
0885 {
0886     if (m_dndSpacer->parentItem() != m_startLayout
0887             && m_dndSpacer->parentItem() != m_mainLayout
0888             && m_dndSpacer->parentItem() != m_endLayout) {
0889         return -1;
0890     }
0891 
0892     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
0893     int index = -1;
0894 
0895     if (alignment == Latte::Types::Justify) {
0896         for(int i=0; i<m_startLayout->childItems().count(); ++i) {
0897             QQuickItem *item = m_startLayout->childItems()[i];
0898             bool isparabolicspacer = item->property("isParabolicEdgeSpacer").toBool();
0899 
0900             if (isparabolicspacer) {
0901                 continue;
0902             }
0903 
0904             index++;
0905             if (item == m_dndSpacer) {
0906                 return index;
0907             }
0908         }
0909     }
0910 
0911     for(int i=0; i<m_mainLayout->childItems().count(); ++i) {
0912         QQuickItem *item = m_mainLayout->childItems()[i];       
0913         bool isparabolicspacer = item->property("isParabolicEdgeSpacer").toBool();
0914 
0915         if (isparabolicspacer) {
0916             continue;
0917         }
0918 
0919         index++;
0920         if (item == m_dndSpacer) {
0921             return index;
0922         }
0923     }
0924 
0925     if (alignment == Latte::Types::Justify) {
0926         for(int i=0; i<m_endLayout->childItems().count(); ++i) {
0927             QQuickItem *item = m_endLayout->childItems()[i];
0928             bool isparabolicspacer = item->property("isParabolicEdgeSpacer").toBool();
0929 
0930             if (isparabolicspacer) {
0931                 continue;
0932             }
0933 
0934             index++;
0935             if (item == m_dndSpacer) {
0936                 return index;
0937             }
0938         }
0939     }
0940 
0941     return -1;
0942 }
0943 
0944 
0945 void LayoutManager::requestAppletsOrder(const QList<int> &order)
0946 {
0947     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
0948     QQuickItem *nextlayout = alignment != Latte::Types::Justify ? m_mainLayout : m_startLayout;
0949     QQuickItem *previousitem = nullptr;
0950 
0951     int addedsplitters{0};
0952 
0953     for (int i=0; i<order.count(); ++i) {
0954         QQuickItem *currentitem;
0955 
0956         if (alignment != Latte::Types::Justify || order[i] != JUSTIFYSPLITTERID) {
0957             currentitem = appletItem(order[i]);
0958         } else if (alignment == Latte::Types::Justify && order[i] == JUSTIFYSPLITTERID) {
0959             currentitem = addedsplitters == 0 ? firstSplitter() : lastSplitter();
0960             addedsplitters++;
0961         }
0962 
0963 
0964         if (previousitem) {
0965             insertAfter(previousitem, currentitem);
0966         } else {
0967             insertAtLayoutTail(nextlayout, currentitem);
0968         }
0969 
0970         previousitem = currentitem;
0971 
0972         if (alignment == Latte::Types::Justify && order[i] == JUSTIFYSPLITTERID) {
0973             nextlayout = addedsplitters == 1 ? m_mainLayout : m_endLayout;
0974         }
0975     }
0976 
0977     if (alignment == Latte::Types::Justify) {
0978         moveAppletsBasedOnJustifyAlignment();
0979         save();
0980     }
0981 }
0982 
0983 void LayoutManager::requestAppletsInLockedZoom(const QList<int> &applets)
0984 {
0985     setLockedZoomApplets(applets);
0986 }
0987 
0988 void LayoutManager::requestAppletsDisabledColoring(const QList<int> &applets)
0989 {
0990     setUserBlocksColorizingApplets(applets);
0991 }
0992 
0993 int LayoutManager::distanceFromTail(QQuickItem *layout, QPointF pos) const
0994 {
0995     return (int)qSqrt(qPow(pos.x() - 0, 2) + qPow(pos.y() - 0, 2));
0996 }
0997 
0998 int LayoutManager::distanceFromHead(QQuickItem *layout, QPointF pos) const
0999 {
1000     float rightX = layout->width() - 1;
1001     float rightY = layout->height() - 1;
1002     return  (int)qSqrt(qPow(pos.x() - rightX, 2) + qPow(pos.y() - rightY, 2));
1003 }
1004 
1005 void LayoutManager::insertAtCoordinates(QQuickItem *item, const int &x, const int &y)
1006 {
1007     if (!m_configuration || !item) {
1008         return;
1009     }
1010 
1011     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
1012 
1013     bool result{false};
1014 
1015     if (alignment == Latte::Types::Justify) {
1016         QPointF startPos = m_startLayout->mapFromItem(m_rootItem, QPointF(x, y));
1017         result = insertAtLayoutCoordinates(m_startLayout, item, startPos.x(), startPos.y());
1018 
1019         if (!result) {
1020             QPointF endPos = m_endLayout->mapFromItem(m_rootItem, QPointF(x, y));
1021             result = insertAtLayoutCoordinates(m_endLayout, item, endPos.x(), endPos.y());
1022         }
1023     }
1024 
1025     if (!result) {
1026         QPointF mainPos = m_mainLayout->mapFromItem(m_rootItem, QPointF(x, y));
1027         //! in javascript direct insertAtCoordinates was usedd ???
1028         result = insertAtLayoutCoordinates(m_mainLayout, item, mainPos.x(), mainPos.y());
1029     }
1030 
1031     if (result) {
1032         return;
1033     }
1034 
1035     //! item was not added because it does not hover any of the layouts and layout items
1036     //! so the place that will be added is specified by the distance of the item from the layouts
1037 
1038     QPointF startrelpos = m_startLayout->mapFromItem(m_rootItem, QPointF(x, y));
1039     QPointF endrelpos = m_endLayout->mapFromItem(m_rootItem, QPointF(x, y));
1040     QPointF mainrelpos = m_mainLayout->mapFromItem(m_rootItem, QPointF(x, y));
1041 
1042     int starttaildistance = distanceFromTail(m_startLayout, startrelpos);
1043     int startheaddistance = distanceFromHead(m_startLayout, startrelpos);
1044     int maintaildistance = distanceFromTail(m_mainLayout, mainrelpos);
1045     int mainheaddistance = distanceFromHead(m_mainLayout, mainrelpos);
1046     int endtaildistance = distanceFromTail(m_endLayout, endrelpos);
1047     int endheaddistance = distanceFromHead(m_endLayout, endrelpos);
1048 
1049     int startdistance = qMin(starttaildistance, startheaddistance);
1050     int maindistance = qMin(maintaildistance, mainheaddistance);
1051     int enddistance = qMin(endtaildistance, endheaddistance);
1052 
1053     if (alignment != Latte::Types::Justify || (maindistance < startdistance && maindistance < enddistance)) {
1054         if (maintaildistance <= mainheaddistance) {
1055             insertAtLayoutTail(m_mainLayout, item);
1056         } else {
1057             insertAtLayoutHead(m_mainLayout, item);
1058         }
1059     } else if (startdistance < maindistance && startdistance < enddistance) {
1060         if (maintaildistance <= mainheaddistance) {
1061             insertAtLayoutTail(m_startLayout, item);
1062         } else {
1063             insertAtLayoutHead(m_startLayout, item);
1064         }
1065     } else {
1066         if (endtaildistance <= endheaddistance) {
1067             insertAtLayoutTail(m_endLayout, item);
1068         } else {
1069             insertAtLayoutHead(m_endLayout, item);
1070         }
1071     }
1072 }
1073 
1074 void LayoutManager::cleanupOptions()
1075 {
1076     auto inlockedzoomcurrent = m_lockedZoomApplets;
1077     QList<int> inlockedzoomnext;
1078     for(int i=0; i<inlockedzoomcurrent.count(); ++i) {
1079         if (m_appletOrder.contains(inlockedzoomcurrent[i])) {
1080             inlockedzoomnext << inlockedzoomcurrent[i];
1081         }
1082     }
1083     setLockedZoomApplets(inlockedzoomnext);
1084 
1085     auto disabledcoloringcurrent = m_userBlocksColorizingApplets;
1086     QList <int> disabledcoloringnext;
1087     for(int i=0; i<disabledcoloringcurrent.count(); ++i) {
1088         if (m_appletOrder.contains(disabledcoloringcurrent[i])) {
1089             disabledcoloringnext << disabledcoloringcurrent[i];
1090         }
1091     }
1092     setUserBlocksColorizingApplets(disabledcoloringnext);
1093 }
1094 
1095 void LayoutManager::addAppletItem(QObject *applet, int index)
1096 {
1097     if (!m_startLayout || !m_mainLayout || !m_endLayout || index < 0) {
1098         return;
1099     }
1100 
1101     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
1102     QVariant appletItemVariant;
1103     QVariant appletVariant; appletVariant.setValue(applet);
1104     m_createAppletItemMethod.invoke(m_rootItem, Q_RETURN_ARG(QVariant, appletItemVariant), Q_ARG(QVariant, appletVariant));
1105     QQuickItem *aitem = appletItemVariant.value<QQuickItem *>();
1106 
1107     if (m_dndSpacer) {
1108         m_dndSpacer->setParentItem(m_rootItem);
1109     }
1110 
1111     QQuickItem *previousItem{nullptr};
1112 
1113     if (index >= m_order.count()) {
1114         // do nothing it should be added at the end
1115     } else {
1116         if (alignment == Latte::Types::Justify && m_order[index] == JUSTIFYSPLITTERID) {
1117             if (index<m_splitterPosition2-1) {
1118                 previousItem = firstSplitter();
1119             } else {
1120                 previousItem = lastSplitter();
1121             }
1122         } else {
1123             previousItem = appletItem(m_order[index]);
1124         }
1125     }
1126 
1127     if (previousItem) {
1128         insertBefore(previousItem, aitem);
1129     } else {
1130         if (alignment == Latte::Types::Justify) {
1131             insertAtLayoutHead(m_endLayout, aitem);
1132         } else {
1133             insertAtLayoutHead(m_mainLayout, aitem);
1134         }
1135     }
1136 
1137     if (alignment == Latte::Types::Justify) {
1138         moveAppletsBasedOnJustifyAlignment();
1139     }
1140 
1141     save();
1142 }
1143 
1144 void LayoutManager::addAppletItem(QObject *applet, int x, int y)
1145 {
1146     if (!m_startLayout || !m_mainLayout || !m_endLayout) {
1147         return;
1148     }    
1149 
1150     PlasmaQuick::AppletQuickItem *aqi = qobject_cast<PlasmaQuick::AppletQuickItem *>(applet);
1151 
1152     if (aqi && aqi->applet() && !aqi->applet()->destroyed() && m_appletsInScheduledDestruction.contains(aqi->applet()->id())) {
1153         int id = aqi->applet()->id();
1154         QVariant appletContainerVariant; appletContainerVariant.setValue(m_appletsInScheduledDestruction[id]);
1155         QVariant appletVariant; appletVariant.setValue(applet);
1156         m_initAppletContainerMethod.invoke(m_rootItem, Q_ARG(QVariant, appletContainerVariant), Q_ARG(QVariant, appletVariant));
1157         setAppletInScheduledDestruction(id, false);
1158         return;
1159     }
1160 
1161     QVariant appletItemVariant;
1162     QVariant appletVariant; appletVariant.setValue(applet);
1163     m_createAppletItemMethod.invoke(m_rootItem, Q_RETURN_ARG(QVariant, appletItemVariant), Q_ARG(QVariant, appletVariant));
1164     QQuickItem *appletItem = appletItemVariant.value<QQuickItem *>();
1165 
1166     if (m_dndSpacer->parentItem() == m_mainLayout
1167             || m_dndSpacer->parentItem() == m_startLayout
1168             || m_dndSpacer->parentItem() == m_endLayout) {
1169         insertBefore(m_dndSpacer, appletItem);
1170 
1171         QQuickItem *currentlayout = m_dndSpacer->parentItem();
1172         m_dndSpacer->setParentItem(m_rootItem);
1173 
1174         if (currentlayout == m_startLayout) {
1175             reorderSplitterInStartLayout();
1176         } else if (currentlayout ==m_endLayout) {
1177             reorderSplitterInEndLayout();
1178         }
1179     } else if (x >= 0 && y >= 0) {
1180         // If the provided position is valid, use it.
1181         insertAtCoordinates(appletItem, x , y);
1182     } else {
1183         // Fall through to adding at the end of main layout.
1184         appletItem->setParentItem(m_mainLayout);
1185     }
1186 
1187     save();
1188 }
1189 
1190 void LayoutManager::removeAppletItem(QObject *applet)
1191 {
1192     if (!m_startLayout || !m_mainLayout || !m_endLayout) {
1193         return;
1194     }
1195 
1196     PlasmaQuick::AppletQuickItem *aqi = qobject_cast<PlasmaQuick::AppletQuickItem *>(applet);
1197 
1198     if (!aqi) {
1199         return;
1200     }
1201 
1202     int id = aqi->applet()->id();
1203 
1204     if (aqi->applet() && aqi->applet()->destroyed() && !m_appletsInScheduledDestruction.contains(id)/*this way we really delete it in the end*/) {
1205         setAppletInScheduledDestruction(id, true);
1206         return;
1207     }
1208 
1209     destroyAppletContainer(aqi->applet());
1210 }
1211 
1212 void LayoutManager::destroyAppletContainer(QObject *applet)
1213 {
1214     if (!applet || !m_startLayout || !m_mainLayout || !m_endLayout) {
1215         return;
1216     }
1217 
1218     Plasma::Applet *ca = qobject_cast<Plasma::Applet *>(applet);
1219 
1220     if (!ca) {
1221         qDebug() << "org.kde.destroy destroying applet could not succeed Plasma/Applet was not identified...";
1222         return;
1223     }
1224 
1225     int id = ca->id();
1226 
1227     bool destroyed{false};
1228 
1229     if (m_appletsInScheduledDestruction.contains(id)) {
1230         //! when deleted from scheduled destruction
1231         m_appletsInScheduledDestruction[id]->setVisible(false);
1232         m_appletsInScheduledDestruction[id]->setParentItem(m_rootItem);
1233         m_appletsInScheduledDestruction[id]->deleteLater();
1234         setAppletInScheduledDestruction(id, false);
1235         destroyed = true;
1236     } else {
1237         //! when deleted directly for Plasma::Applet destruction e.g. synced applets
1238         for (int i=0; i<=2; ++i) {
1239             if (destroyed) {
1240                 break;
1241             }
1242 
1243             QQuickItem *layout = (i==0 ? m_startLayout : (i==1 ? m_mainLayout : m_endLayout));
1244 
1245             if (layout->childItems().count() > 0) {
1246                 int size = layout->childItems().count();
1247                 for (int j=size-1; j>=0; --j) {
1248                     QQuickItem *item = layout->childItems()[j];
1249                     bool issplitter = item->property("isInternalViewSplitter").toBool();
1250                     if (issplitter) {
1251                         continue;
1252                     }
1253 
1254                     QVariant appletVariant = item->property("applet");
1255                     if (!appletVariant.isValid()) {
1256                         continue;
1257                     }
1258                     PlasmaQuick::AppletQuickItem *appletitem = appletVariant.value<PlasmaQuick::AppletQuickItem *>();
1259 
1260                     if (appletitem && appletitem->applet() == applet) {
1261                         item->setVisible(false);
1262                         item->setParentItem(m_rootItem);
1263                         item->deleteLater();
1264                         destroyed = true;
1265                         break;
1266                     }
1267                 }
1268             }
1269         }
1270     }
1271 
1272     if (destroyed) {
1273         save();
1274     }
1275 }
1276 
1277 void LayoutManager::reorderSplitterInStartLayout()
1278 {
1279     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
1280 
1281     if (alignment != Latte::Types::Justify) {
1282         return;
1283     }
1284 
1285     int size = m_startLayout->childItems().count();
1286 
1287     if (size > 0) {
1288         QQuickItem *splitter{nullptr};
1289 
1290         for (int i=0; i<size; ++i) {
1291             QQuickItem *item = m_startLayout->childItems()[i];
1292             bool issplitter = item->property("isInternalViewSplitter").toBool();
1293 
1294             if (issplitter && i<size-1) {
1295                 splitter = item;
1296                 break;
1297             }
1298         }
1299 
1300         if (splitter) {
1301             insertAfter(m_startLayout->childItems()[size-1],splitter);
1302         }
1303     }
1304 }
1305 
1306 void LayoutManager::reorderSplitterInEndLayout()
1307 {
1308     Latte::Types::Alignment alignment = static_cast<Latte::Types::Alignment>((*m_configuration)["alignment"].toInt());
1309 
1310     if (alignment != Latte::Types::Justify) {
1311         return;
1312     }
1313 
1314     int size = m_endLayout->childItems().count();
1315 
1316     if (size > 0) {
1317         QQuickItem *splitter{nullptr};
1318 
1319         for (int i=0; i<size; ++i) {
1320             QQuickItem *item = m_endLayout->childItems()[i];
1321             bool issplitter = item->property("isInternalViewSplitter").toBool();
1322 
1323             if (issplitter && i!=0) {
1324                 splitter = item;
1325                 break;
1326             }
1327         }
1328 
1329         if (splitter) {
1330             insertBefore(m_endLayout->childItems()[0],splitter);
1331         }
1332     }
1333 }
1334 
1335 void LayoutManager::addJustifySplittersInMainLayout()
1336 {
1337     if (!m_configuration || !m_mainLayout) {
1338         return;
1339     }
1340 
1341     destroyJustifySplitters();
1342 
1343     int splitterPosition = (*m_configuration)["splitterPosition"].toInt();
1344     int splitterPosition2 = (*m_configuration)["splitterPosition2"].toInt();
1345 
1346     int splitterIndex = (splitterPosition >= 1 ? splitterPosition - 1 : -1);
1347     int splitterIndex2 = (splitterPosition2 >= 1 ? splitterPosition2 - 1 : -1);
1348 
1349     //! First Splitter
1350     QVariant splitterItemVariant;
1351     m_createJustifySplitterMethod.invoke(m_rootItem, Q_RETURN_ARG(QVariant, splitterItemVariant));
1352     QQuickItem *splitterItem = splitterItemVariant.value<QQuickItem *>();
1353 
1354     int size = m_mainLayout->childItems().count()-2; //we need to remove parabolic spacers
1355 
1356     splitterItem->setParentItem(m_mainLayout);
1357 
1358     if (size>0 && splitterIndex>=0) {
1359         bool atend = (splitterIndex >= size);
1360         int validindex = (atend ? size-1 : splitterIndex) + 1; //we need to take into account first parabolic spacer
1361         QQuickItem *currentitem = m_mainLayout->childItems()[validindex];
1362 
1363         if (atend) {
1364             splitterItem->stackAfter(currentitem);
1365         } else {
1366             splitterItem->stackBefore(currentitem);
1367         }
1368     } else if (size>0) {
1369         //! add in first position
1370         QQuickItem *currentitem = m_mainLayout->childItems()[0];
1371         splitterItem->stackBefore(currentitem);
1372     }
1373 
1374     //! Second Splitter
1375     QVariant splitterItemVariant2;
1376     m_createJustifySplitterMethod.invoke(m_rootItem, Q_RETURN_ARG(QVariant, splitterItemVariant2));
1377     QQuickItem *splitterItem2 = splitterItemVariant2.value<QQuickItem *>();
1378 
1379     int size2 = m_mainLayout->childItems().count()-2; //we need to remove parabolic spacers
1380 
1381     splitterItem2->setParentItem(m_mainLayout);
1382 
1383     if (size2>0 && splitterIndex2>=0) {
1384         bool atend = (splitterIndex2 >= size2);
1385         int validindex2 = (atend ? size2-1 : splitterIndex2) + 1; //we need to take into account first parabolic spacer
1386         QQuickItem *currentitem2 = m_mainLayout->childItems()[validindex2];
1387 
1388         if (atend) {
1389             splitterItem2->stackAfter(currentitem2);
1390         } else {
1391             splitterItem2->stackBefore(currentitem2);
1392         }
1393     } else if (size2>1){
1394         //! add in last position
1395         QQuickItem *currentitem2 = m_mainLayout->childItems()[size2-1+1]; //we need to take into account first parabolic spacer
1396         splitterItem2->stackAfter(currentitem2);
1397     }
1398 }
1399 
1400 void LayoutManager::destroyJustifySplitters()
1401 {
1402     if (!m_startLayout || !m_mainLayout || !m_endLayout) {
1403         return;
1404     }
1405 
1406     for (int i=0; i<=2; ++i) {
1407         QQuickItem *layout = (i==0 ? m_startLayout : (i==1 ? m_mainLayout : m_endLayout));
1408 
1409         if (layout->childItems().count() > 0) {
1410             int size = layout->childItems().count();
1411             for (int j=size-1; j>=0; --j) {
1412                 QQuickItem *item = layout->childItems()[j];
1413                 bool issplitter = item->property("isInternalViewSplitter").toBool();
1414                 if (issplitter) {
1415                     item->deleteLater();
1416                 }
1417             }
1418         }
1419     }
1420 }
1421 
1422 void LayoutManager::joinLayoutsToMainLayout()
1423 {
1424     if (!m_startLayout || !m_mainLayout || !m_endLayout) {
1425         return;
1426     }
1427 
1428     if (m_startLayout->childItems().count() > 0) {
1429         int size = m_startLayout->childItems().count();
1430         for (int i=size-1; i>=0; --i) {
1431             QQuickItem *lastStartLayoutItem = m_startLayout->childItems()[i];
1432             QQuickItem *firstMainLayoutItem = m_mainLayout->childItems().count() > 0 ? m_mainLayout->childItems()[0] : nullptr;
1433 
1434             lastStartLayoutItem->setParentItem(m_mainLayout);
1435 
1436             if (firstMainLayoutItem) {
1437                 lastStartLayoutItem->stackBefore(firstMainLayoutItem);
1438             }
1439         }
1440     }
1441 
1442     if (m_endLayout->childItems().count() > 0) {
1443         int size = m_endLayout->childItems().count();
1444         for (int i=0; i<size; ++i) {
1445             QQuickItem *firstEndLayoutItem = m_endLayout->childItems()[0];
1446             QQuickItem *lastMainLayoutItem = m_mainLayout->childItems().count() > 0 ? m_mainLayout->childItems()[m_mainLayout->childItems().count()-1] : nullptr;
1447 
1448             firstEndLayoutItem->setParentItem(m_mainLayout);
1449 
1450             if (lastMainLayoutItem) {
1451                 firstEndLayoutItem->stackAfter(lastMainLayoutItem);
1452             }
1453         }
1454     }
1455 
1456     destroyJustifySplitters();
1457 }
1458 
1459 void LayoutManager::moveAppletsBasedOnJustifyAlignment()
1460 {
1461     if (!m_startLayout || !m_mainLayout || !m_endLayout) {
1462         return;
1463     }
1464 
1465     reorderParabolicSpacers();
1466 
1467     QList<QQuickItem *> appletlist;
1468 
1469     appletlist << m_startLayout->childItems();
1470     appletlist << m_mainLayout->childItems();
1471     appletlist << m_endLayout->childItems();
1472 
1473     bool firstSplitterFound{false};
1474     bool secondSplitterFound{false};
1475     int splitter1{-1};
1476     int splitter2{-1};
1477 
1478     for(int i=0; i<appletlist.count(); ++i) {
1479         bool issplitter = appletlist[i]->property("isInternalViewSplitter").toBool();
1480         bool isparabolicspacer = appletlist[i]->property("isParabolicEdgeSpacer").toBool();
1481 
1482         if (!firstSplitterFound) {
1483             insertAtLayoutIndex(m_startLayout, appletlist[i], i);
1484             if (issplitter) {
1485                 firstSplitterFound = true;
1486                 splitter1 = i;
1487             }
1488         } else if (firstSplitterFound && !secondSplitterFound) {
1489             if (issplitter) {
1490                 secondSplitterFound = true;
1491                 splitter2 = i;
1492                 insertAtLayoutTail(m_endLayout, appletlist[i]);
1493             } else {
1494                 insertAtLayoutIndex(m_mainLayout, appletlist[i], i-splitter1);
1495             }
1496         } else if (firstSplitterFound && secondSplitterFound) {
1497             insertAtLayoutIndex(m_endLayout, appletlist[i], i-splitter2);
1498         }
1499     }
1500 
1501     reorderParabolicSpacers();
1502 }
1503 
1504 void LayoutManager::printAppletList(QList<QQuickItem *> list)
1505 {
1506     for(int i=0; i<list.count(); ++i) {
1507         bool issplitter = list[i]->property("isInternalViewSplitter").toBool();
1508         bool isparabolicspacer = list[i]->property("isParabolicEdgeSpacer").toBool();
1509 
1510         if (issplitter) {
1511             qDebug() << i << " __ JUSTIFY SPLITTER";
1512             continue;
1513         }
1514 
1515         if (isparabolicspacer) {
1516             qDebug() << i << " __ PARABOLICSPACER";
1517             continue;
1518         }
1519 
1520         QVariant appletVariant = list[i]->property("applet");
1521         if (!appletVariant.isValid()) {
1522             continue;
1523         }
1524         PlasmaQuick::AppletQuickItem *appletitem = appletVariant.value<PlasmaQuick::AppletQuickItem *>();
1525 
1526         if (appletitem) {
1527             qDebug() << i << " __ " << appletitem->applet()->pluginMetaData().pluginId();
1528         }
1529     }
1530 }
1531 
1532 QList<int> LayoutManager::toIntList(const QString &serialized)
1533 {
1534     QList<int> list;
1535     QStringList items = serialized.split(";");
1536     items.removeAll(QString());
1537 
1538     for(const auto &item: items) {
1539         list << item.toInt();
1540     }
1541 
1542     return list;
1543 }
1544 
1545 QString LayoutManager::toStr(const QList<int> &list)
1546 {
1547     QString str;
1548     QStringList strlist;
1549 
1550     for(const auto &num: list) {
1551         strlist << QString::number(num);
1552     }
1553 
1554     return strlist.join(";");
1555 }
1556 
1557 }
1558 }