forked from Qortal/Brooklyn
756 lines
21 KiB
C++
756 lines
21 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
|
|
|
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
|
*/
|
|
|
|
#include "appletslayout.h"
|
|
#include "appletcontainer.h"
|
|
#include "containmentlayoutmanager_debug.h"
|
|
#include "gridlayoutmanager.h"
|
|
|
|
#include <QQmlContext>
|
|
#include <QQmlEngine>
|
|
#include <QStyleHints>
|
|
#include <QTimer>
|
|
|
|
// Plasma
|
|
#include <Containment>
|
|
#include <Corona>
|
|
#include <PlasmaQuick/AppletQuickItem>
|
|
|
|
AppletsLayout::AppletsLayout(QQuickItem *parent)
|
|
: QQuickItem(parent)
|
|
{
|
|
m_layoutManager = new GridLayoutManager(this);
|
|
|
|
setFlags(QQuickItem::ItemIsFocusScope);
|
|
setAcceptedMouseButtons(Qt::LeftButton);
|
|
|
|
m_saveLayoutTimer = new QTimer(this);
|
|
m_saveLayoutTimer->setSingleShot(true);
|
|
m_saveLayoutTimer->setInterval(100);
|
|
connect(m_layoutManager, &AbstractLayoutManager::layoutNeedsSaving, m_saveLayoutTimer, QOverload<>::of(&QTimer::start));
|
|
connect(m_saveLayoutTimer, &QTimer::timeout, this, [this]() {
|
|
// We can't assume m_containment to be valid: if we load in a plasmoid that can run also
|
|
// in "applet" mode, m_containment will never be valid
|
|
if (!m_containment) {
|
|
return;
|
|
}
|
|
// We can't save the layout during bootup, for performance reasons and to avoid race consitions as much as possible, so if we needto save and still
|
|
// starting up, don't actually savenow, but we will when Corona::startupCompleted is emitted
|
|
|
|
if (!m_configKey.isEmpty() && m_containment && m_containment->corona()->isStartupCompleted()) {
|
|
const QString serializedConfig = m_layoutManager->serializeLayout();
|
|
m_containment->config().writeEntry(m_configKey, serializedConfig);
|
|
m_containment->config().writeEntry(m_fallbackConfigKey, serializedConfig);
|
|
// FIXME: something more efficient
|
|
m_layoutManager->parseLayout(serializedConfig);
|
|
m_savedSize = size();
|
|
m_containment->corona()->requireConfigSync();
|
|
}
|
|
});
|
|
|
|
m_layoutChangeTimer = new QTimer(this);
|
|
m_layoutChangeTimer->setSingleShot(true);
|
|
m_layoutChangeTimer->setInterval(100);
|
|
connect(m_layoutChangeTimer, &QTimer::timeout, this, [this]() {
|
|
// We can't assume m_containment to be valid: if we load in a plasmoid that can run also
|
|
// in "applet" mode, m_containment will never be valid
|
|
if (!m_containment) {
|
|
return;
|
|
}
|
|
const QString &serializedConfig = m_containment->config().readEntry(m_configKey, "");
|
|
if ((m_layoutChanges & ConfigKeyChange) && !serializedConfig.isEmpty()) {
|
|
if (!m_configKey.isEmpty() && m_containment) {
|
|
m_layoutManager->parseLayout(serializedConfig);
|
|
|
|
if (width() > 0 && height() > 0) {
|
|
m_layoutManager->resetLayoutFromConfig();
|
|
m_savedSize = size();
|
|
}
|
|
}
|
|
} else if (m_layoutChanges & SizeChange) {
|
|
const QRect newGeom(x(), y(), width(), height());
|
|
// The size has been restored from the last one it has been saved: restore that exact same layout
|
|
if (newGeom.size() == m_savedSize) {
|
|
m_layoutManager->resetLayoutFromConfig();
|
|
|
|
// If the resize is consequence of a screen resolution change, queue a relayout maintaining the distance between screen edges
|
|
} else if (!m_geometryBeforeResolutionChange.isEmpty()) {
|
|
m_layoutManager->layoutGeometryChanged(newGeom, m_geometryBeforeResolutionChange);
|
|
m_geometryBeforeResolutionChange = QRectF();
|
|
|
|
// Heuristically relayout items only when the plasma startup is fully completed
|
|
} else {
|
|
polish();
|
|
}
|
|
}
|
|
m_layoutChanges = NoChange;
|
|
});
|
|
m_pressAndHoldTimer = new QTimer(this);
|
|
m_pressAndHoldTimer->setSingleShot(true);
|
|
connect(m_pressAndHoldTimer, &QTimer::timeout, this, [this]() {
|
|
setEditMode(true);
|
|
});
|
|
}
|
|
|
|
AppletsLayout::~AppletsLayout()
|
|
{
|
|
}
|
|
|
|
PlasmaQuick::AppletQuickItem *AppletsLayout::containment() const
|
|
{
|
|
return m_containmentItem;
|
|
}
|
|
|
|
void AppletsLayout::setContainment(PlasmaQuick::AppletQuickItem *containmentItem)
|
|
{
|
|
// Forbid changing containmentItem at runtime
|
|
if (m_containmentItem || containmentItem == m_containmentItem || !containmentItem->applet() || !containmentItem->applet()->isContainment()) {
|
|
qCWarning(CONTAINMENTLAYOUTMANAGER_DEBUG) << "Error: cannot change the containment to AppletsLayout";
|
|
return;
|
|
}
|
|
|
|
// Can't assign containments that aren't parents
|
|
QQuickItem *candidate = parentItem();
|
|
while (candidate) {
|
|
if (candidate == m_containmentItem) {
|
|
break;
|
|
}
|
|
candidate = candidate->parentItem();
|
|
}
|
|
if (candidate != m_containmentItem) {
|
|
return;
|
|
}
|
|
|
|
m_containmentItem = containmentItem;
|
|
m_containment = static_cast<Plasma::Containment *>(m_containmentItem->applet());
|
|
|
|
connect(m_containmentItem, SIGNAL(appletAdded(QObject *, int, int)), this, SLOT(appletAdded(QObject *, int, int)));
|
|
|
|
connect(m_containmentItem, SIGNAL(appletRemoved(QObject *)), this, SLOT(appletRemoved(QObject *)));
|
|
|
|
Q_EMIT containmentChanged();
|
|
}
|
|
|
|
QString AppletsLayout::configKey() const
|
|
{
|
|
return m_configKey;
|
|
}
|
|
|
|
void AppletsLayout::setConfigKey(const QString &key)
|
|
{
|
|
if (m_configKey == key) {
|
|
return;
|
|
}
|
|
|
|
m_configKey = key;
|
|
|
|
// Reloading everything from the new config is expansive, event compress it
|
|
m_layoutChanges |= ConfigKeyChange;
|
|
m_layoutChangeTimer->start();
|
|
|
|
Q_EMIT configKeyChanged();
|
|
}
|
|
|
|
QString AppletsLayout::fallbackConfigKey() const
|
|
{
|
|
return m_fallbackConfigKey;
|
|
}
|
|
|
|
void AppletsLayout::setFallbackConfigKey(const QString &key)
|
|
{
|
|
if (m_fallbackConfigKey == key) {
|
|
return;
|
|
}
|
|
|
|
m_fallbackConfigKey = key;
|
|
|
|
Q_EMIT fallbackConfigKeyChanged();
|
|
}
|
|
|
|
QJSValue AppletsLayout::acceptsAppletCallback() const
|
|
{
|
|
return m_acceptsAppletCallback;
|
|
}
|
|
|
|
qreal AppletsLayout::minimumItemWidth() const
|
|
{
|
|
return m_minimumItemSize.width();
|
|
}
|
|
|
|
void AppletsLayout::setMinimumItemWidth(qreal width)
|
|
{
|
|
if (qFuzzyCompare(width, m_minimumItemSize.width())) {
|
|
return;
|
|
}
|
|
|
|
m_minimumItemSize.setWidth(width);
|
|
|
|
Q_EMIT minimumItemWidthChanged();
|
|
}
|
|
|
|
qreal AppletsLayout::minimumItemHeight() const
|
|
{
|
|
return m_minimumItemSize.height();
|
|
}
|
|
|
|
void AppletsLayout::setMinimumItemHeight(qreal height)
|
|
{
|
|
if (qFuzzyCompare(height, m_minimumItemSize.height())) {
|
|
return;
|
|
}
|
|
|
|
m_minimumItemSize.setHeight(height);
|
|
|
|
Q_EMIT minimumItemHeightChanged();
|
|
}
|
|
|
|
qreal AppletsLayout::defaultItemWidth() const
|
|
{
|
|
return m_defaultItemSize.width();
|
|
}
|
|
|
|
void AppletsLayout::setDefaultItemWidth(qreal width)
|
|
{
|
|
if (qFuzzyCompare(width, m_defaultItemSize.width())) {
|
|
return;
|
|
}
|
|
|
|
m_defaultItemSize.setWidth(width);
|
|
|
|
Q_EMIT defaultItemWidthChanged();
|
|
}
|
|
|
|
qreal AppletsLayout::defaultItemHeight() const
|
|
{
|
|
return m_defaultItemSize.height();
|
|
}
|
|
|
|
void AppletsLayout::setDefaultItemHeight(qreal height)
|
|
{
|
|
if (qFuzzyCompare(height, m_defaultItemSize.height())) {
|
|
return;
|
|
}
|
|
|
|
m_defaultItemSize.setHeight(height);
|
|
|
|
Q_EMIT defaultItemHeightChanged();
|
|
}
|
|
|
|
qreal AppletsLayout::cellWidth() const
|
|
{
|
|
return m_layoutManager->cellSize().width();
|
|
}
|
|
|
|
void AppletsLayout::setCellWidth(qreal width)
|
|
{
|
|
if (qFuzzyCompare(width, m_layoutManager->cellSize().width())) {
|
|
return;
|
|
}
|
|
|
|
m_layoutManager->setCellSize(QSizeF(width, m_layoutManager->cellSize().height()));
|
|
|
|
Q_EMIT cellWidthChanged();
|
|
}
|
|
|
|
qreal AppletsLayout::cellHeight() const
|
|
{
|
|
return m_layoutManager->cellSize().height();
|
|
}
|
|
|
|
void AppletsLayout::setCellHeight(qreal height)
|
|
{
|
|
if (qFuzzyCompare(height, m_layoutManager->cellSize().height())) {
|
|
return;
|
|
}
|
|
|
|
m_layoutManager->setCellSize(QSizeF(m_layoutManager->cellSize().width(), height));
|
|
|
|
Q_EMIT cellHeightChanged();
|
|
}
|
|
|
|
void AppletsLayout::setAcceptsAppletCallback(const QJSValue &callback)
|
|
{
|
|
if (m_acceptsAppletCallback.strictlyEquals(callback)) {
|
|
return;
|
|
}
|
|
|
|
if (!callback.isNull() && !callback.isCallable()) {
|
|
return;
|
|
}
|
|
|
|
m_acceptsAppletCallback = callback;
|
|
|
|
Q_EMIT acceptsAppletCallbackChanged();
|
|
}
|
|
|
|
QQmlComponent *AppletsLayout::appletContainerComponent() const
|
|
{
|
|
return m_appletContainerComponent;
|
|
}
|
|
|
|
void AppletsLayout::setAppletContainerComponent(QQmlComponent *component)
|
|
{
|
|
if (m_appletContainerComponent == component) {
|
|
return;
|
|
}
|
|
|
|
m_appletContainerComponent = component;
|
|
|
|
Q_EMIT appletContainerComponentChanged();
|
|
}
|
|
|
|
AppletsLayout::EditModeCondition AppletsLayout::editModeCondition() const
|
|
{
|
|
return m_editModeCondition;
|
|
}
|
|
|
|
void AppletsLayout::setEditModeCondition(AppletsLayout::EditModeCondition condition)
|
|
{
|
|
if (m_editModeCondition == condition) {
|
|
return;
|
|
}
|
|
|
|
if (m_editModeCondition == Locked) {
|
|
setEditMode(false);
|
|
}
|
|
|
|
m_editModeCondition = condition;
|
|
|
|
Q_EMIT editModeConditionChanged();
|
|
}
|
|
|
|
bool AppletsLayout::editMode() const
|
|
{
|
|
return m_editMode;
|
|
}
|
|
|
|
void AppletsLayout::setEditMode(bool editMode)
|
|
{
|
|
if (m_editMode == editMode) {
|
|
return;
|
|
}
|
|
|
|
m_editMode = editMode;
|
|
|
|
Q_EMIT editModeChanged();
|
|
}
|
|
|
|
ItemContainer *AppletsLayout::placeHolder() const
|
|
{
|
|
return m_placeHolder;
|
|
}
|
|
|
|
void AppletsLayout::setPlaceHolder(ItemContainer *placeHolder)
|
|
{
|
|
if (m_placeHolder == placeHolder) {
|
|
return;
|
|
}
|
|
|
|
m_placeHolder = placeHolder;
|
|
m_placeHolder->setParentItem(this);
|
|
m_placeHolder->setZ(9999);
|
|
m_placeHolder->setOpacity(false);
|
|
|
|
Q_EMIT placeHolderChanged();
|
|
}
|
|
|
|
QQuickItem *AppletsLayout::eventManagerToFilter() const
|
|
{
|
|
return m_eventManagerToFilter;
|
|
}
|
|
|
|
void AppletsLayout::setEventManagerToFilter(QQuickItem *item)
|
|
{
|
|
if (m_eventManagerToFilter == item) {
|
|
return;
|
|
}
|
|
|
|
m_eventManagerToFilter = item;
|
|
setFiltersChildMouseEvents(m_eventManagerToFilter);
|
|
Q_EMIT eventManagerToFilterChanged();
|
|
}
|
|
|
|
void AppletsLayout::save()
|
|
{
|
|
m_saveLayoutTimer->start();
|
|
}
|
|
|
|
void AppletsLayout::showPlaceHolderAt(const QRectF &geom)
|
|
{
|
|
if (!m_placeHolder) {
|
|
return;
|
|
}
|
|
|
|
m_placeHolder->setPosition(geom.topLeft());
|
|
m_placeHolder->setSize(geom.size());
|
|
|
|
m_layoutManager->positionItem(m_placeHolder);
|
|
|
|
m_placeHolder->setProperty("opacity", 1);
|
|
}
|
|
|
|
void AppletsLayout::showPlaceHolderForItem(ItemContainer *item)
|
|
{
|
|
if (!m_placeHolder) {
|
|
return;
|
|
}
|
|
|
|
m_placeHolder->setPreferredLayoutDirection(item->preferredLayoutDirection());
|
|
m_placeHolder->setPosition(item->position());
|
|
m_placeHolder->setSize(item->size());
|
|
|
|
m_layoutManager->positionItem(m_placeHolder);
|
|
|
|
m_placeHolder->setProperty("opacity", 1);
|
|
}
|
|
|
|
void AppletsLayout::hidePlaceHolder()
|
|
{
|
|
if (!m_placeHolder) {
|
|
return;
|
|
}
|
|
|
|
m_placeHolder->setProperty("opacity", 0);
|
|
}
|
|
|
|
bool AppletsLayout::isRectAvailable(qreal x, qreal y, qreal width, qreal height)
|
|
{
|
|
return m_layoutManager->isRectAvailable(QRectF(x, y, width, height));
|
|
}
|
|
|
|
bool AppletsLayout::itemIsManaged(ItemContainer *item)
|
|
{
|
|
if (!item) {
|
|
return false;
|
|
}
|
|
|
|
return m_layoutManager->itemIsManaged(item);
|
|
}
|
|
|
|
void AppletsLayout::positionItem(ItemContainer *item)
|
|
{
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
item->setParent(this);
|
|
m_layoutManager->positionItemAndAssign(item);
|
|
}
|
|
|
|
void AppletsLayout::restoreItem(ItemContainer *item)
|
|
{
|
|
m_layoutManager->restoreItem(item);
|
|
}
|
|
|
|
void AppletsLayout::releaseSpace(ItemContainer *item)
|
|
{
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
m_layoutManager->releaseSpace(item);
|
|
}
|
|
|
|
void AppletsLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
|
{
|
|
// Ignore completely moves without resize
|
|
if (newGeometry.size() == oldGeometry.size()) {
|
|
QQuickItem::geometryChanged(newGeometry, oldGeometry);
|
|
return;
|
|
}
|
|
|
|
// Don't care for anything happening before startup completion
|
|
if (!m_containment || !m_containment->corona() || !m_containment->corona()->isStartupCompleted()) {
|
|
QQuickItem::geometryChanged(newGeometry, oldGeometry);
|
|
return;
|
|
}
|
|
|
|
// Only do a layouting procedure if we received a valid size
|
|
if (!newGeometry.isEmpty()) {
|
|
m_layoutChanges |= SizeChange;
|
|
m_layoutChangeTimer->start();
|
|
}
|
|
|
|
QQuickItem::geometryChanged(newGeometry, oldGeometry);
|
|
}
|
|
|
|
void AppletsLayout::updatePolish()
|
|
{
|
|
m_layoutManager->resetLayout();
|
|
m_savedSize = size();
|
|
}
|
|
|
|
void AppletsLayout::componentComplete()
|
|
{
|
|
if (!m_containment || !m_containmentItem) {
|
|
QQuickItem::componentComplete();
|
|
return;
|
|
}
|
|
|
|
if (!m_configKey.isEmpty()) {
|
|
const QString &serializedConfig = m_containment->config().readEntry(m_configKey, "");
|
|
if (!serializedConfig.isEmpty()) {
|
|
m_layoutManager->parseLayout(serializedConfig);
|
|
} else {
|
|
m_layoutManager->parseLayout(m_containment->config().readEntry(m_fallbackConfigKey, ""));
|
|
}
|
|
}
|
|
|
|
const QList<QObject *> appletObjects = m_containmentItem->property("applets").value<QList<QObject *>>();
|
|
|
|
for (auto *obj : appletObjects) {
|
|
PlasmaQuick::AppletQuickItem *appletItem = qobject_cast<PlasmaQuick::AppletQuickItem *>(obj);
|
|
|
|
if (!obj) {
|
|
continue;
|
|
}
|
|
|
|
AppletContainer *container = createContainerForApplet(appletItem);
|
|
if (width() > 0 && height() > 0) {
|
|
m_layoutManager->positionItemAndAssign(container);
|
|
}
|
|
}
|
|
|
|
// layout all extra non applet items
|
|
if (width() > 0 && height() > 0) {
|
|
for (auto *child : childItems()) {
|
|
ItemContainer *item = qobject_cast<ItemContainer *>(child);
|
|
if (item && item != m_placeHolder && !m_layoutManager->itemIsManaged(item)) {
|
|
m_layoutManager->positionItemAndAssign(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_containment && m_containment->corona()) {
|
|
// We inhibit save during startup, so actually save now that startup is completed
|
|
connect(m_containment->corona(), &Plasma::Corona::startupCompleted, this, [this]() {
|
|
save();
|
|
});
|
|
// When the screen geometry changes, we need to know the geometry just before it did, so we can apply out heuristic of keeping the distance with borders
|
|
// constant
|
|
connect(m_containment->corona(), &Plasma::Corona::screenGeometryChanged, this, [this](int id) {
|
|
if (m_containment->screen() == id) {
|
|
m_geometryBeforeResolutionChange = QRectF(x(), y(), width(), height());
|
|
}
|
|
});
|
|
}
|
|
QQuickItem::componentComplete();
|
|
}
|
|
|
|
bool AppletsLayout::childMouseEventFilter(QQuickItem *item, QEvent *event)
|
|
{
|
|
if (item != m_eventManagerToFilter) {
|
|
return QQuickItem::childMouseEventFilter(item, event);
|
|
}
|
|
|
|
switch (event->type()) {
|
|
case QEvent::MouseButtonPress: {
|
|
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
|
if (me->buttons() & Qt::LeftButton) {
|
|
mousePressEvent(me);
|
|
}
|
|
break;
|
|
}
|
|
case QEvent::MouseMove: {
|
|
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
|
mouseMoveEvent(me);
|
|
break;
|
|
}
|
|
case QEvent::MouseButtonRelease: {
|
|
QMouseEvent *me = static_cast<QMouseEvent *>(event);
|
|
mouseReleaseEvent(me);
|
|
break;
|
|
}
|
|
case QEvent::UngrabMouse:
|
|
mouseUngrabEvent();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return QQuickItem::childMouseEventFilter(item, event);
|
|
}
|
|
|
|
void AppletsLayout::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
forceActiveFocus(Qt::MouseFocusReason);
|
|
|
|
if (!m_editMode && m_editModeCondition == AppletsLayout::Manual) {
|
|
return;
|
|
}
|
|
|
|
if (!m_editMode && m_editModeCondition == AppletsLayout::AfterPressAndHold) {
|
|
m_pressAndHoldTimer->start(QGuiApplication::styleHints()->mousePressAndHoldInterval());
|
|
}
|
|
|
|
m_mouseDownWasEditMode = m_editMode;
|
|
m_mouseDownPosition = event->windowPos();
|
|
|
|
// event->setAccepted(false);
|
|
}
|
|
|
|
void AppletsLayout::mouseMoveEvent(QMouseEvent *event)
|
|
{
|
|
if (!m_editMode && m_editModeCondition == AppletsLayout::Manual) {
|
|
return;
|
|
}
|
|
|
|
if (!m_editMode && QPointF(event->windowPos() - m_mouseDownPosition).manhattanLength() >= QGuiApplication::styleHints()->startDragDistance()) {
|
|
m_pressAndHoldTimer->stop();
|
|
}
|
|
}
|
|
|
|
void AppletsLayout::mouseReleaseEvent(QMouseEvent *event)
|
|
{
|
|
if (m_editMode
|
|
&& m_mouseDownWasEditMode
|
|
// By only accepting synthetyzed events, this makes the
|
|
// close by tapping in any empty area only work with real
|
|
// touch events, as we want a different behavior between desktop
|
|
// and tablet mode
|
|
&& (event->source() == Qt::MouseEventSynthesizedBySystem || event->source() == Qt::MouseEventSynthesizedByQt)
|
|
&& QPointF(event->windowPos() - m_mouseDownPosition).manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) {
|
|
setEditMode(false);
|
|
}
|
|
|
|
m_pressAndHoldTimer->stop();
|
|
|
|
if (!m_editMode) {
|
|
for (auto *child : childItems()) {
|
|
ItemContainer *item = qobject_cast<ItemContainer *>(child);
|
|
if (item && item != m_placeHolder) {
|
|
item->setEditMode(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AppletsLayout::mouseUngrabEvent()
|
|
{
|
|
m_pressAndHoldTimer->stop();
|
|
}
|
|
|
|
void AppletsLayout::appletAdded(QObject *applet, int x, int y)
|
|
{
|
|
PlasmaQuick::AppletQuickItem *appletItem = qobject_cast<PlasmaQuick::AppletQuickItem *>(applet);
|
|
|
|
// maybe even an assert?
|
|
if (!appletItem) {
|
|
return;
|
|
}
|
|
|
|
if (m_acceptsAppletCallback.isCallable()) {
|
|
QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
|
|
Q_ASSERT(engine);
|
|
QJSValueList args;
|
|
args << engine->newQObject(applet) << QJSValue(x) << QJSValue(y);
|
|
|
|
if (!m_acceptsAppletCallback.call(args).toBool()) {
|
|
Q_EMIT appletRefused(applet, x, y);
|
|
return;
|
|
}
|
|
}
|
|
|
|
AppletContainer *container = createContainerForApplet(appletItem);
|
|
container->setPosition(QPointF(x, y));
|
|
container->setVisible(true);
|
|
|
|
m_layoutManager->positionItemAndAssign(container);
|
|
}
|
|
|
|
void AppletsLayout::appletRemoved(QObject *applet)
|
|
{
|
|
PlasmaQuick::AppletQuickItem *appletItem = qobject_cast<PlasmaQuick::AppletQuickItem *>(applet);
|
|
|
|
// maybe even an assert?
|
|
if (!appletItem) {
|
|
return;
|
|
}
|
|
|
|
AppletContainer *container = m_containerForApplet.value(appletItem);
|
|
if (!container) {
|
|
return;
|
|
}
|
|
|
|
m_layoutManager->releaseSpace(container);
|
|
m_containerForApplet.remove(appletItem);
|
|
appletItem->setParentItem(this);
|
|
container->deleteLater();
|
|
}
|
|
|
|
AppletContainer *AppletsLayout::createContainerForApplet(PlasmaQuick::AppletQuickItem *appletItem)
|
|
{
|
|
AppletContainer *container = m_containerForApplet.value(appletItem);
|
|
|
|
if (container) {
|
|
return container;
|
|
}
|
|
|
|
bool createdFromQml = true;
|
|
|
|
if (m_appletContainerComponent) {
|
|
QQmlContext *context = QQmlEngine::contextForObject(this);
|
|
Q_ASSERT(context);
|
|
QObject *instance = m_appletContainerComponent->beginCreate(context);
|
|
container = qobject_cast<AppletContainer *>(instance);
|
|
if (container) {
|
|
container->setParentItem(this);
|
|
} else {
|
|
qCWarning(CONTAINMENTLAYOUTMANAGER_DEBUG) << "Error: provided component not an AppletContainer instance";
|
|
if (instance) {
|
|
instance->deleteLater();
|
|
}
|
|
createdFromQml = false;
|
|
}
|
|
}
|
|
|
|
if (!container) {
|
|
container = new AppletContainer(this);
|
|
}
|
|
|
|
container->setVisible(false);
|
|
|
|
const QSizeF appletSize = appletItem->size();
|
|
container->setContentItem(appletItem);
|
|
|
|
m_containerForApplet[appletItem] = container;
|
|
container->setLayout(this);
|
|
container->setKey(QLatin1String("Applet-") + QString::number(appletItem->applet()->id()));
|
|
|
|
const bool geometryWasSaved = m_layoutManager->restoreItem(container);
|
|
|
|
if (!geometryWasSaved) {
|
|
container->setPosition(QPointF(appletItem->x() - container->leftPadding(), appletItem->y() - container->topPadding()));
|
|
|
|
if (!appletSize.isEmpty()) {
|
|
container->setSize(QSizeF(qMax(m_minimumItemSize.width(), appletSize.width() + container->leftPadding() + container->rightPadding()),
|
|
qMax(m_minimumItemSize.height(), appletSize.height() + container->topPadding() + container->bottomPadding())));
|
|
}
|
|
}
|
|
|
|
if (m_appletContainerComponent && createdFromQml) {
|
|
m_appletContainerComponent->completeCreate();
|
|
}
|
|
|
|
// NOTE: This has to be done here as we need the component completed to have all the bindings evaluated
|
|
if (!geometryWasSaved && appletSize.isEmpty()) {
|
|
if (container->initialSize().width() > m_minimumItemSize.width() && container->initialSize().height() > m_minimumItemSize.height()) {
|
|
const QSizeF size = m_layoutManager->cellAlignedContainingSize(container->initialSize());
|
|
container->setSize(size);
|
|
} else {
|
|
container->setSize(
|
|
QSizeF(qMax(m_minimumItemSize.width(), m_defaultItemSize.width()), qMax(m_minimumItemSize.height(), m_defaultItemSize.height())));
|
|
}
|
|
}
|
|
|
|
container->setVisible(true);
|
|
appletItem->setVisible(true);
|
|
|
|
return container;
|
|
}
|
|
|
|
#include "moc_appletslayout.cpp"
|