File indexing completed on 2024-05-12 05:37:13

0001 /*
0002     SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "itemcontainer.h"
0008 #include "configoverlay.h"
0009 #include "containmentlayoutmanager_debug.h"
0010 
0011 #include <QGuiApplication>
0012 #include <QQmlContext>
0013 #include <QQmlEngine>
0014 #include <QQuickWindow>
0015 #include <QStyleHints>
0016 #include <QTimer>
0017 #include <cmath>
0018 
0019 #include <PlasmaQuick/AppletQuickItem>
0020 #include <chrono>
0021 
0022 using namespace std::chrono_literals;
0023 
0024 ItemContainer::ItemContainer(QQuickItem *parent)
0025     : QQuickItem(parent)
0026 {
0027     setFiltersChildMouseEvents(true);
0028     setFlags(QQuickItem::ItemIsFocusScope);
0029     setActiveFocusOnTab(true);
0030     setAcceptedMouseButtons(Qt::LeftButton);
0031 
0032     setLayout(qobject_cast<AppletsLayout *>(parent));
0033 
0034     m_editModeTimer = new QTimer(this);
0035     m_editModeTimer->setSingleShot(true);
0036 
0037     connect(this, &QQuickItem::parentChanged, this, [this]() {
0038         setLayout(qobject_cast<AppletsLayout *>(parentItem()));
0039     });
0040 
0041     connect(m_editModeTimer, &QTimer::timeout, this, [this]() {
0042         setEditMode(true);
0043     });
0044 
0045     setKeepMouseGrab(true);
0046     m_sizeHintAdjustTimer = new QTimer(this);
0047     m_sizeHintAdjustTimer->setSingleShot(true);
0048     m_sizeHintAdjustTimer->setInterval(0);
0049 
0050     connect(m_sizeHintAdjustTimer, &QTimer::timeout, this, &ItemContainer::sizeHintsChanged);
0051 }
0052 
0053 ItemContainer::~ItemContainer()
0054 {
0055     disconnect(this, &QQuickItem::parentChanged, this, nullptr);
0056 
0057     if (m_contentItem) {
0058         m_contentItem->setEnabled(true);
0059     }
0060 }
0061 
0062 QString ItemContainer::key() const
0063 {
0064     return m_key;
0065 }
0066 
0067 void ItemContainer::setKey(const QString &key)
0068 {
0069     if (m_key == key) {
0070         return;
0071     }
0072 
0073     m_key = key;
0074 
0075     Q_EMIT keyChanged();
0076 }
0077 
0078 bool ItemContainer::editMode() const
0079 {
0080     return m_editMode;
0081 }
0082 
0083 bool ItemContainer::dragActive() const
0084 {
0085     return m_dragActive;
0086 }
0087 
0088 void ItemContainer::cancelEdit()
0089 {
0090     m_editModeTimer->stop();
0091     m_mouseDown = false;
0092     setEditMode(false);
0093 }
0094 
0095 void ItemContainer::setEditMode(bool editMode)
0096 {
0097     if (m_editMode == editMode) {
0098         return;
0099     }
0100 
0101     if (editMode && editModeCondition() == Locked) {
0102         return;
0103     }
0104 
0105     m_editMode = editMode;
0106 
0107     if (m_contentItem && (m_editModeCondition != AfterMouseOver || (m_layout && m_layout->editMode()))) {
0108         m_contentItem->setEnabled(!editMode);
0109     }
0110 
0111     if (editMode) {
0112         setZ(1);
0113     } else {
0114         setZ(0);
0115     }
0116 
0117     if (m_mouseDown) {
0118         sendUngrabRecursive(m_contentItem);
0119         QMouseEvent ev(QEvent::MouseButtonPress, mapFromScene(m_mouseDownPosition), m_mouseDownPosition, QPointF(), Qt::LeftButton, {}, {});
0120         ev.setExclusiveGrabber(ev.point(0), this);
0121         QCoreApplication::sendEvent(this, &ev);
0122     }
0123 
0124     if (m_dragActive != editMode && m_mouseDown) {
0125         m_dragActive = editMode && m_mouseDown;
0126         Q_EMIT dragActiveChanged();
0127     }
0128 
0129     setConfigOverlayVisible(editMode);
0130 
0131     Q_EMIT editModeChanged(editMode);
0132 }
0133 
0134 ItemContainer::EditModeCondition ItemContainer::editModeCondition() const
0135 {
0136     if (m_layout && m_layout->editModeCondition() == AppletsLayout::Locked) {
0137         return Locked;
0138     }
0139 
0140     return m_editModeCondition;
0141 }
0142 
0143 void ItemContainer::setEditModeCondition(EditModeCondition condition)
0144 {
0145     if (condition == m_editModeCondition) {
0146         return;
0147     }
0148 
0149     if (condition == Locked) {
0150         setEditMode(false);
0151     }
0152 
0153     m_editModeCondition = condition;
0154 
0155     setAcceptHoverEvents(condition == AfterMouseOver || (m_layout && m_layout->editMode()));
0156 
0157     Q_EMIT editModeConditionChanged();
0158 }
0159 
0160 AppletsLayout::PreferredLayoutDirection ItemContainer::preferredLayoutDirection() const
0161 {
0162     return m_preferredLayoutDirection;
0163 }
0164 
0165 void ItemContainer::setPreferredLayoutDirection(AppletsLayout::PreferredLayoutDirection direction)
0166 {
0167     if (direction == m_preferredLayoutDirection) {
0168         return;
0169     }
0170 
0171     m_preferredLayoutDirection = direction;
0172 
0173     Q_EMIT preferredLayoutDirectionChanged();
0174 }
0175 
0176 void ItemContainer::setLayout(AppletsLayout *layout)
0177 {
0178     if (m_layout == layout) {
0179         return;
0180     }
0181 
0182     if (m_layout) {
0183         disconnect(m_layout, &AppletsLayout::editModeConditionChanged, this, nullptr);
0184         disconnect(m_layout, &AppletsLayout::editModeChanged, this, nullptr);
0185 
0186         if (m_editMode) {
0187             m_layout->hidePlaceHolder();
0188         }
0189     }
0190 
0191     m_layout = layout;
0192 
0193     if (!layout) {
0194         Q_EMIT layoutChanged();
0195         return;
0196     }
0197 
0198     if (parentItem() != layout) {
0199         setParentItem(layout);
0200     }
0201 
0202     connect(m_layout, &AppletsLayout::editModeConditionChanged, this, [this]() {
0203         if (m_layout->editModeCondition() == AppletsLayout::Locked) {
0204             setEditMode(false);
0205         }
0206         if ((m_layout->editModeCondition() == AppletsLayout::Locked) != (m_editModeCondition == ItemContainer::Locked)) {
0207             Q_EMIT editModeConditionChanged();
0208         }
0209     });
0210     connect(m_layout, &AppletsLayout::editModeChanged, this, [this]() {
0211         setAcceptHoverEvents(m_editModeCondition == AfterMouseOver || m_layout->editMode());
0212     });
0213     Q_EMIT layoutChanged();
0214 }
0215 
0216 AppletsLayout *ItemContainer::layout() const
0217 {
0218     return m_layout;
0219 }
0220 
0221 void ItemContainer::onConfigOverlayComponentStatusChanged(QQmlComponent::Status status, QQmlComponent *component)
0222 {
0223     if (status == QQmlComponent::Loading) {
0224         return;
0225     }
0226     if (!component) {
0227         component = static_cast<QQmlComponent *>(sender());
0228     }
0229     if (status != QQmlComponent::Ready) {
0230         delete component;
0231         return;
0232     }
0233 
0234     Q_ASSERT(!m_configOverlay);
0235     m_configOverlay = static_cast<ConfigOverlay *>(component->beginCreate(QQmlEngine::contextForObject(this)));
0236 
0237     m_configOverlay->setVisible(false);
0238     m_configOverlay->setItemContainer(this);
0239     m_configOverlay->setParentItem(this);
0240     m_configOverlay->setTouchInteraction(m_mouseSynthetizedFromTouch);
0241     m_configOverlay->setZ(999);
0242     m_configOverlay->setPosition(QPointF(0, 0));
0243     m_configOverlay->setSize(size());
0244 
0245     component->completeCreate();
0246     component->deleteLater();
0247 
0248     connect(m_configOverlay, &ConfigOverlay::openChanged, this, &ItemContainer::configOverlayVisibleChanged);
0249 
0250     Q_EMIT configOverlayItemChanged();
0251 
0252     m_configOverlay->setOpen(m_configOverlayVisible);
0253 }
0254 
0255 void ItemContainer::syncChildItemsGeometry(const QSizeF &size)
0256 {
0257     if (m_contentItem) {
0258         m_contentItem->setPosition(QPointF(m_leftPadding, m_topPadding));
0259 
0260         m_contentItem->setSize(QSizeF(size.width() - m_leftPadding - m_rightPadding, size.height() - m_topPadding - m_bottomPadding));
0261     }
0262 
0263     if (m_backgroundItem) {
0264         m_backgroundItem->setPosition(QPointF(0, 0));
0265         m_backgroundItem->setSize(size);
0266     }
0267 
0268     if (m_configOverlay) {
0269         m_configOverlay->setPosition(QPointF(0, 0));
0270         m_configOverlay->setSize(size);
0271     }
0272 }
0273 
0274 QUrl ItemContainer::configOverlaySource() const
0275 {
0276     return m_configOverlaySource;
0277 }
0278 
0279 void ItemContainer::setConfigOverlaySource(const QUrl &url)
0280 {
0281     if (url == m_configOverlaySource || !url.isValid()) {
0282         return;
0283     }
0284 
0285     m_configOverlaySource = url;
0286     if (m_configOverlay) {
0287         m_configOverlay->deleteLater();
0288         m_configOverlay = nullptr;
0289     }
0290     Q_EMIT configOverlaySourceChanged();
0291 
0292     if (m_configOverlayVisible) {
0293         loadConfigOverlayItem();
0294     }
0295 }
0296 
0297 ConfigOverlay *ItemContainer::configOverlayItem() const
0298 {
0299     return m_configOverlay;
0300 }
0301 
0302 QSizeF ItemContainer::initialSize() const
0303 {
0304     return m_initialSize;
0305 }
0306 
0307 void ItemContainer::setInitialSize(const QSizeF &size)
0308 {
0309     if (m_initialSize == size) {
0310         return;
0311     }
0312 
0313     m_initialSize = size;
0314 
0315     Q_EMIT initialSizeChanged();
0316 }
0317 
0318 bool ItemContainer::configOverlayVisible() const
0319 {
0320     return m_configOverlay && m_configOverlay->open();
0321 }
0322 
0323 void ItemContainer::setConfigOverlayVisible(bool visible)
0324 {
0325     if (!m_configOverlaySource.isValid() || visible == m_configOverlayVisible) {
0326         return;
0327     }
0328 
0329     m_configOverlayVisible = visible;
0330 
0331     if (visible && !m_configOverlay) {
0332         loadConfigOverlayItem();
0333     } else if (m_configOverlay) {
0334         m_configOverlay->setVisible(visible);
0335     }
0336 }
0337 
0338 void ItemContainer::contentData_append(QQmlListProperty<QObject> *prop, QObject *object)
0339 {
0340     ItemContainer *container = static_cast<ItemContainer *>(prop->object);
0341     if (!container) {
0342         return;
0343     }
0344 
0345     //    QQuickItem *item = qobject_cast<QQuickItem *>(object);
0346     container->m_contentData.append(object);
0347 }
0348 
0349 qsizetype ItemContainer::contentData_count(QQmlListProperty<QObject> *prop)
0350 {
0351     ItemContainer *container = static_cast<ItemContainer *>(prop->object);
0352     if (!container) {
0353         return 0;
0354     }
0355 
0356     return container->m_contentData.count();
0357 }
0358 
0359 QObject *ItemContainer::contentData_at(QQmlListProperty<QObject> *prop, qsizetype index)
0360 {
0361     ItemContainer *container = static_cast<ItemContainer *>(prop->object);
0362     if (!container) {
0363         return nullptr;
0364     }
0365 
0366     if (index < 0 || index >= container->m_contentData.count()) {
0367         return nullptr;
0368     }
0369     return container->m_contentData.value(index);
0370 }
0371 
0372 void ItemContainer::contentData_clear(QQmlListProperty<QObject> *prop)
0373 {
0374     ItemContainer *container = static_cast<ItemContainer *>(prop->object);
0375     if (!container) {
0376         return;
0377     }
0378 
0379     return container->m_contentData.clear();
0380 }
0381 
0382 QQmlListProperty<QObject> ItemContainer::contentData()
0383 {
0384     return QQmlListProperty<QObject>(this, nullptr, contentData_append, contentData_count, contentData_at, contentData_clear);
0385 }
0386 
0387 void ItemContainer::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
0388 {
0389     syncChildItemsGeometry(newGeometry.size());
0390     QQuickItem::geometryChange(newGeometry, oldGeometry);
0391     Q_EMIT contentWidthChanged();
0392     Q_EMIT contentHeightChanged();
0393 }
0394 
0395 void ItemContainer::componentComplete()
0396 {
0397     if (!m_contentItem) {
0398         // qWarning()<<"Creating default contentItem";
0399         m_contentItem = new QQuickItem(this);
0400         syncChildItemsGeometry(size());
0401     }
0402 
0403     for (auto *o : std::as_const(m_contentData)) {
0404         QQuickItem *item = qobject_cast<QQuickItem *>(o);
0405         if (item) {
0406             item->setParentItem(m_contentItem);
0407         }
0408     }
0409 
0410     // Search for the Layout attached property
0411     // Qt6: this should become public api
0412     // https://bugreports.qt.io/browse/QTBUG-77103
0413     for (auto *o : children()) {
0414         if (o->inherits("QQuickLayoutAttached")) {
0415             m_layoutAttached = o;
0416         }
0417     }
0418 
0419     if (m_layoutAttached) {
0420         // NOTE: new syntax cannot be used because we don't have access to the QQuickLayoutAttached class
0421         connect(m_layoutAttached, SIGNAL(minimumHeightChanged()), m_sizeHintAdjustTimer, SLOT(start()));
0422         connect(m_layoutAttached, SIGNAL(minimumWidthChanged()), m_sizeHintAdjustTimer, SLOT(start()));
0423 
0424         connect(m_layoutAttached, SIGNAL(preferredHeightChanged()), m_sizeHintAdjustTimer, SLOT(start()));
0425         connect(m_layoutAttached, SIGNAL(preferredWidthChanged()), m_sizeHintAdjustTimer, SLOT(start()));
0426 
0427         connect(m_layoutAttached, SIGNAL(maximumHeightChanged()), m_sizeHintAdjustTimer, SLOT(start()));
0428         connect(m_layoutAttached, SIGNAL(maximumWidthChanged()), m_sizeHintAdjustTimer, SLOT(start()));
0429     }
0430     QQuickItem::componentComplete();
0431 }
0432 
0433 void ItemContainer::sendUngrabRecursive(QQuickItem *item)
0434 {
0435     if (!item || !item->window()) {
0436         return;
0437     }
0438 
0439     for (auto *child : item->childItems()) {
0440         sendUngrabRecursive(child);
0441     }
0442 
0443     QEvent ev(QEvent::UngrabMouse);
0444 
0445     QCoreApplication::sendEvent(item, &ev);
0446 }
0447 
0448 void ItemContainer::loadConfigOverlayItem()
0449 {
0450     Q_ASSERT(!m_configOverlay);
0451     constexpr QQmlComponent::CompilationMode mode = QQmlComponent::Asynchronous;
0452     QQmlContext *context = QQmlEngine::contextForObject(this);
0453     auto component = new QQmlComponent(context->engine(), context->resolvedUrl(m_configOverlaySource), mode, this);
0454     if (!component->isLoading()) {
0455         onConfigOverlayComponentStatusChanged(component->status(), component);
0456     } else {
0457         connect(component,
0458                 &QQmlComponent::statusChanged,
0459                 this,
0460                 std::bind(&ItemContainer::onConfigOverlayComponentStatusChanged, this, std::placeholders::_1, nullptr));
0461     }
0462 }
0463 
0464 bool ItemContainer::childMouseEventFilter(QQuickItem *item, QEvent *event)
0465 {
0466     // Don't filter the configoverlay
0467     if (item == m_configOverlay || (m_configOverlay && m_configOverlay->isAncestorOf(item)) || (!m_editMode && m_editModeCondition == Manual)) {
0468         if (m_closeEditModeTimer && m_closeEditModeTimer->isActive()) {
0469             m_closeEditModeTimer->setInterval(2s);
0470             m_closeEditModeTimer->start();
0471         }
0472         return QQuickItem::childMouseEventFilter(item, event);
0473     }
0474 
0475     // give more time before closing
0476     if (m_closeEditModeTimer && m_closeEditModeTimer->isActive()) {
0477         m_closeEditModeTimer->setInterval(500ms);
0478         m_closeEditModeTimer->start();
0479     }
0480     if (event->type() == QEvent::MouseButtonPress) {
0481         QMouseEvent *me = static_cast<QMouseEvent *>(event);
0482         if (me->button() != Qt::LeftButton && !(me->buttons() & Qt::LeftButton)) {
0483             return QQuickItem::childMouseEventFilter(item, event);
0484         }
0485         forceActiveFocus(Qt::MouseFocusReason);
0486         m_mouseDown = true;
0487         m_mouseSynthetizedFromTouch = me->source() == Qt::MouseEventSynthesizedBySystem || me->source() == Qt::MouseEventSynthesizedByQt;
0488         if (m_configOverlay) {
0489             m_configOverlay->setTouchInteraction(m_mouseSynthetizedFromTouch);
0490         }
0491 
0492         const bool wasEditMode = m_editMode;
0493         if (m_layout && m_layout->editMode()) {
0494             setEditMode(true);
0495         } else if (m_editModeCondition == AfterPressAndHold) {
0496             m_editModeTimer->start(QGuiApplication::styleHints()->mousePressAndHoldInterval());
0497         }
0498         m_lastMousePosition = me->scenePosition();
0499         m_mouseDownPosition = me->scenePosition();
0500 
0501         if (m_editMode && !wasEditMode) {
0502             event->accept();
0503             return true;
0504         }
0505 
0506     } else if (event->type() == QEvent::MouseMove) {
0507         QMouseEvent *me = static_cast<QMouseEvent *>(event);
0508 
0509         if (!m_editMode && QPointF(me->scenePosition() - m_mouseDownPosition).manhattanLength() >= QGuiApplication::styleHints()->startDragDistance()) {
0510             m_editModeTimer->stop();
0511         } else if (m_editMode) {
0512             event->accept();
0513         }
0514 
0515     } else if (event->type() == QEvent::MouseButtonRelease) {
0516         m_editModeTimer->stop();
0517         m_mouseDown = false;
0518         m_mouseSynthetizedFromTouch = false;
0519         if (auto mouseEvent = static_cast<QMouseEvent *>(event); mouseEvent->exclusiveGrabber(mouseEvent->point(0)) == this) {
0520             mouseEvent->setExclusiveGrabber(mouseEvent->point(0), nullptr);
0521         }
0522         event->accept();
0523         m_dragActive = false;
0524         if (m_editMode) {
0525             Q_EMIT dragActiveChanged();
0526         }
0527     }
0528 
0529     return QQuickItem::childMouseEventFilter(item, event);
0530 }
0531 
0532 void ItemContainer::mousePressEvent(QMouseEvent *event)
0533 {
0534     forceActiveFocus(Qt::MouseFocusReason);
0535 
0536     if (!m_editMode && m_editModeCondition == Manual) {
0537         return;
0538     }
0539 
0540     m_mouseDown = true;
0541     m_mouseSynthetizedFromTouch = event->source() == Qt::MouseEventSynthesizedBySystem || event->source() == Qt::MouseEventSynthesizedByQt;
0542     if (m_configOverlay) {
0543         m_configOverlay->setTouchInteraction(m_mouseSynthetizedFromTouch);
0544     }
0545 
0546     if (m_layout && m_layout->editMode()) {
0547         setEditMode(true);
0548     }
0549 
0550     if (m_editMode) {
0551         event->setExclusiveGrabber(event->point(0), this);
0552         setCursor(Qt::ClosedHandCursor);
0553         m_dragActive = true;
0554         Q_EMIT dragActiveChanged();
0555     } else if (m_editModeCondition == AfterPressAndHold) {
0556         m_editModeTimer->start(QGuiApplication::styleHints()->mousePressAndHoldInterval());
0557     }
0558 
0559     m_lastMousePosition = event->scenePosition();
0560     m_mouseDownPosition = event->scenePosition();
0561     event->accept();
0562 }
0563 
0564 void ItemContainer::mouseReleaseEvent(QMouseEvent *event)
0565 {
0566     Q_UNUSED(event);
0567 
0568     if (!m_layout || (!m_editMode && m_editModeCondition == Manual)) {
0569         return;
0570     }
0571 
0572     m_mouseDown = false;
0573     m_mouseSynthetizedFromTouch = false;
0574     m_editModeTimer->stop();
0575     if (event->exclusiveGrabber(event->point(0)) == this) {
0576         event->setExclusiveGrabber(event->point(0), nullptr);
0577     }
0578 
0579     if (m_editMode && !m_layout->itemIsManaged(this)) {
0580         m_layout->hidePlaceHolder();
0581         m_layout->positionItem(this);
0582     }
0583 
0584     m_dragActive = false;
0585     if (m_editMode) {
0586         Q_EMIT dragActiveChanged();
0587         setCursor(Qt::OpenHandCursor);
0588     }
0589     event->accept();
0590 }
0591 
0592 void ItemContainer::mouseMoveEvent(QMouseEvent *event)
0593 {
0594     if ((event->button() == Qt::NoButton && event->buttons() == Qt::NoButton) || (!m_editMode && m_editModeCondition == Manual)) {
0595         return;
0596     }
0597 
0598     if (!m_editMode && QPointF(event->scenePosition() - m_mouseDownPosition).manhattanLength() >= QGuiApplication::styleHints()->startDragDistance()) {
0599         if (m_editModeCondition == AfterPress) {
0600             setEditMode(true);
0601         } else {
0602             m_editModeTimer->stop();
0603         }
0604     }
0605 
0606     if (!m_editMode) {
0607         return;
0608     }
0609 
0610     if (m_layout && m_layout->itemIsManaged(this)) {
0611         m_layout->releaseSpace(this);
0612         event->setExclusiveGrabber(event->point(0), this);
0613         m_dragActive = true;
0614         Q_EMIT dragActiveChanged();
0615 
0616     } else {
0617         setPosition(QPointF(x() + event->scenePosition().x() - m_lastMousePosition.x(), y() + event->scenePosition().y() - m_lastMousePosition.y()));
0618 
0619         if (m_layout) {
0620             m_layout->showPlaceHolderForItem(this);
0621         }
0622 
0623         Q_EMIT userDrag(QPointF(x(), y()), event->pos());
0624     }
0625     m_lastMousePosition = event->scenePosition();
0626     event->accept();
0627 }
0628 
0629 void ItemContainer::mouseUngrabEvent()
0630 {
0631     m_mouseDown = false;
0632     m_mouseSynthetizedFromTouch = false;
0633     m_editModeTimer->stop();
0634 
0635     if (m_layout && m_editMode && !m_layout->itemIsManaged(this)) {
0636         m_layout->hidePlaceHolder();
0637         m_layout->positionItem(this);
0638     }
0639 
0640     m_dragActive = false;
0641     if (m_editMode) {
0642         Q_EMIT dragActiveChanged();
0643     }
0644 }
0645 
0646 void ItemContainer::hoverEnterEvent(QHoverEvent *event)
0647 {
0648     Q_UNUSED(event);
0649 
0650     if (m_editModeCondition != AfterMouseOver && !m_layout->editMode()) {
0651         return;
0652     }
0653 
0654     if (m_closeEditModeTimer) {
0655         m_closeEditModeTimer->stop();
0656     }
0657 
0658     if (m_layout->editMode()) {
0659         setCursor(Qt::OpenHandCursor);
0660         setEditMode(true);
0661     } else {
0662         m_editModeTimer->start(QGuiApplication::styleHints()->mousePressAndHoldInterval());
0663     }
0664 }
0665 
0666 void ItemContainer::hoverLeaveEvent(QHoverEvent *event)
0667 {
0668     Q_UNUSED(event);
0669 
0670     if (m_editModeCondition != AfterMouseOver && !m_layout->editMode()) {
0671         return;
0672     }
0673 
0674     m_editModeTimer->stop();
0675     if (!m_closeEditModeTimer) {
0676         m_closeEditModeTimer = new QTimer(this);
0677         m_closeEditModeTimer->setSingleShot(true);
0678         connect(m_closeEditModeTimer, &QTimer::timeout, this, [this]() {
0679             setEditMode(false);
0680         });
0681     }
0682     m_closeEditModeTimer->setInterval(500ms);
0683     m_closeEditModeTimer->start();
0684 }
0685 
0686 QQuickItem *ItemContainer::contentItem() const
0687 {
0688     return m_contentItem;
0689 }
0690 
0691 void ItemContainer::setContentItem(QQuickItem *item)
0692 {
0693     if (m_contentItem == item) {
0694         return;
0695     }
0696 
0697     m_contentItem = item;
0698     item->setParentItem(this);
0699 
0700     item->setVisible(true);
0701     m_contentItem->setPosition(QPointF(m_leftPadding, m_topPadding));
0702     m_contentItem->setSize(QSizeF(width() - m_leftPadding - m_rightPadding, height() - m_topPadding - m_bottomPadding));
0703 
0704     Q_EMIT contentItemChanged();
0705 }
0706 
0707 QQuickItem *ItemContainer::background() const
0708 {
0709     return m_backgroundItem;
0710 }
0711 
0712 void ItemContainer::setBackground(QQuickItem *item)
0713 {
0714     if (m_backgroundItem == item) {
0715         return;
0716     }
0717 
0718     m_backgroundItem = item;
0719     m_backgroundItem->setParentItem(this);
0720     m_backgroundItem->setPosition(QPointF(0, 0));
0721     m_backgroundItem->setSize(size());
0722 
0723     Q_EMIT backgroundChanged();
0724 }
0725 
0726 int ItemContainer::leftPadding() const
0727 {
0728     return m_leftPadding;
0729 }
0730 
0731 void ItemContainer::setLeftPadding(int padding)
0732 {
0733     if (m_leftPadding == padding) {
0734         return;
0735     }
0736 
0737     m_leftPadding = padding;
0738     syncChildItemsGeometry(size());
0739     Q_EMIT leftPaddingChanged();
0740     Q_EMIT contentWidthChanged();
0741 }
0742 
0743 int ItemContainer::topPadding() const
0744 {
0745     return m_topPadding;
0746 }
0747 
0748 void ItemContainer::setTopPadding(int padding)
0749 {
0750     if (m_topPadding == padding) {
0751         return;
0752     }
0753 
0754     m_topPadding = padding;
0755     syncChildItemsGeometry(size());
0756     Q_EMIT topPaddingChanged();
0757     Q_EMIT contentHeightChanged();
0758 }
0759 
0760 int ItemContainer::rightPadding() const
0761 {
0762     return m_rightPadding;
0763 }
0764 
0765 void ItemContainer::setRightPadding(int padding)
0766 {
0767     if (m_rightPadding == padding) {
0768         return;
0769     }
0770 
0771     m_rightPadding = padding;
0772     syncChildItemsGeometry(size());
0773     Q_EMIT rightPaddingChanged();
0774     Q_EMIT contentWidthChanged();
0775 }
0776 
0777 int ItemContainer::bottomPadding() const
0778 {
0779     return m_bottomPadding;
0780 }
0781 
0782 void ItemContainer::setBottomPadding(int padding)
0783 {
0784     if (m_bottomPadding == padding) {
0785         return;
0786     }
0787 
0788     m_bottomPadding = padding;
0789     syncChildItemsGeometry(size());
0790     Q_EMIT bottomPaddingChanged();
0791     Q_EMIT contentHeightChanged();
0792 }
0793 
0794 int ItemContainer::contentWidth() const
0795 {
0796     return width() - m_leftPadding - m_rightPadding;
0797 }
0798 
0799 int ItemContainer::contentHeight() const
0800 {
0801     return height() - m_topPadding - m_bottomPadding;
0802 }
0803 
0804 #include "moc_itemcontainer.cpp"