Changeset View
Changeset View
Standalone View
Standalone View
components/containmentlayoutmanager/appletslayout.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright 2019 by Marco Martin <mart@kde.org> | ||||
3 | * | ||||
4 | * This program is free software; you can redistribute it and/or modify | ||||
5 | * it under the terms of the GNU Library General Public License as | ||||
6 | * published by the Free Software Foundation; either version 2, or | ||||
7 | * (at your option) any later version. | ||||
8 | * | ||||
9 | * This program is distributed in the hope that it will be useful, | ||||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
12 | * GNU Library General Public License for more details | ||||
13 | * | ||||
14 | * You should have received a copy of the GNU Library General Public | ||||
15 | * License along with this program; if not, write to the | ||||
16 | * Free Software Foundation, Inc., | ||||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
18 | * | ||||
19 | */ | ||||
20 | | ||||
21 | #include "appletslayout.h" | ||||
22 | #include "appletcontainer.h" | ||||
23 | #include "gridlayoutmanager.h" | ||||
24 | | ||||
25 | #include <QQmlEngine> | ||||
26 | #include <QQmlContext> | ||||
27 | #include <QTimer> | ||||
28 | #include <QStyleHints> | ||||
29 | | ||||
30 | // Plasma | ||||
31 | #include <Containment> | ||||
32 | #include <Corona> | ||||
33 | #include <PlasmaQuick/AppletQuickItem> | ||||
34 | | ||||
35 | AppletsLayout::AppletsLayout(QQuickItem *parent) | ||||
36 | : QQuickItem(parent) | ||||
37 | { | ||||
38 | m_layoutManager = new GridLayoutManager(this); | ||||
39 | | ||||
40 | setFlags(QQuickItem::ItemIsFocusScope); | ||||
41 | setAcceptedMouseButtons(Qt::LeftButton); | ||||
42 | | ||||
43 | m_saveLayoutTimer = new QTimer(this); | ||||
44 | m_saveLayoutTimer->setSingleShot(true); | ||||
45 | m_saveLayoutTimer->setInterval(100); | ||||
46 | connect(m_layoutManager, &AbstractLayoutManager::layoutNeedsSaving, m_saveLayoutTimer, QOverload<>::of(&QTimer::start)); | ||||
47 | connect(m_saveLayoutTimer, &QTimer::timeout, this, [this] () { | ||||
48 | if (!m_configKey.isEmpty() && m_containment && m_containment->corona()->isStartupCompleted()) { | ||||
49 | const QString serializedConfig = m_layoutManager->serializeLayout(); | ||||
50 | m_containment->config().writeEntry(m_configKey, serializedConfig); | ||||
51 | //FIXME: something more efficient | ||||
52 | m_layoutManager->parseLayout(serializedConfig); | ||||
53 | m_savedSize = size(); | ||||
54 | m_containment->corona()->requireConfigSync(); | ||||
55 | } | ||||
56 | }); | ||||
57 | | ||||
58 | m_configKeyChangeTimer = new QTimer(this); | ||||
59 | m_configKeyChangeTimer->setSingleShot(true); | ||||
60 | m_configKeyChangeTimer->setInterval(100); | ||||
61 | connect(m_configKeyChangeTimer, &QTimer::timeout, this, [this] () { | ||||
62 | if (!m_configKey.isEmpty() && m_containment) { | ||||
63 | m_layoutManager->parseLayout(m_containment->config().readEntry(m_configKey, "")); | ||||
64 | | ||||
65 | if (width() > 0 && height() > 0) { | ||||
66 | m_layoutManager->resetLayoutFromConfig(); | ||||
67 | m_savedSize = size(); | ||||
68 | } | ||||
69 | } | ||||
70 | }); | ||||
71 | m_pressAndHoldTimer = new QTimer(this); | ||||
72 | m_pressAndHoldTimer->setSingleShot(true); | ||||
73 | connect(m_pressAndHoldTimer, &QTimer::timeout, this, [this]() { | ||||
74 | setEditMode(true); | ||||
75 | }); | ||||
76 | | ||||
77 | m_sizeSyncTimer = new QTimer(this); | ||||
78 | m_sizeSyncTimer->setSingleShot(true); | ||||
79 | m_sizeSyncTimer->setInterval(150); | ||||
80 | connect(m_sizeSyncTimer, &QTimer::timeout, this, [this]() { | ||||
81 | const QRect newGeom(x(), y(), width(), height()); | ||||
82 | // The size has been restored from the last one it has been saved: restore that exact same layout | ||||
83 | if (newGeom.size() == m_savedSize) { | ||||
84 | m_layoutManager->resetLayoutFromConfig(); | ||||
85 | | ||||
86 | // If the resize is consequence of a screen resolution change, queue a relayout maintaining the distance between screen edges | ||||
87 | } else if (!m_geometryBeforeResolutionChange.isEmpty()) { | ||||
88 | m_layoutManager->layoutGeometryChanged(newGeom, m_geometryBeforeResolutionChange); | ||||
89 | m_geometryBeforeResolutionChange = QRectF(); | ||||
90 | | ||||
91 | // Heuristically relayout items only when the plasma startup is fully completed | ||||
92 | } else { | ||||
93 | polish(); | ||||
94 | } | ||||
95 | }); | ||||
96 | | ||||
97 | connect(this, &QQuickItem::focusChanged, this, [this]() { | ||||
98 | if (!hasFocus()) { | ||||
99 | setEditMode(false); | ||||
100 | } | ||||
101 | }); | ||||
102 | } | ||||
103 | | ||||
104 | AppletsLayout::~AppletsLayout() | ||||
105 | { | ||||
106 | } | ||||
107 | | ||||
108 | PlasmaQuick::AppletQuickItem *AppletsLayout::containment() const | ||||
109 | { | ||||
110 | return m_containmentItem; | ||||
111 | } | ||||
112 | | ||||
113 | void AppletsLayout::setContainment(PlasmaQuick::AppletQuickItem *containmentItem) | ||||
114 | { | ||||
115 | // Forbid changing containmentItem at runtime | ||||
116 | if (m_containmentItem | ||||
117 | || containmentItem == m_containmentItem | ||||
118 | || !containmentItem->applet() | ||||
119 | || !containmentItem->applet()->isContainment()) { | ||||
120 | qWarning() << "Error: cannot change the containment to AppletsLayout"; | ||||
121 | return; | ||||
122 | } | ||||
123 | | ||||
124 | // Can't assign containments that aren't parents | ||||
125 | QQuickItem *candidate = parentItem(); | ||||
126 | while (candidate) { | ||||
127 | if (candidate == m_containmentItem) { | ||||
128 | break; | ||||
129 | } | ||||
130 | candidate = candidate->parentItem(); | ||||
131 | } | ||||
132 | if (candidate != m_containmentItem) { | ||||
133 | return; | ||||
134 | } | ||||
135 | | ||||
136 | m_containmentItem = containmentItem; | ||||
137 | m_containment = static_cast<Plasma::Containment *>(m_containmentItem->applet()); | ||||
138 | | ||||
139 | connect(m_containmentItem, SIGNAL(appletAdded(QObject *, int, int)), | ||||
140 | this, SLOT(appletAdded(QObject *, int, int))); | ||||
141 | | ||||
142 | connect(m_containmentItem, SIGNAL(appletRemoved(QObject *)), | ||||
143 | this, SLOT(appletRemoved(QObject *))); | ||||
144 | | ||||
145 | emit containmentChanged(); | ||||
146 | } | ||||
147 | | ||||
148 | QString AppletsLayout::configKey() const | ||||
149 | { | ||||
150 | return m_configKey; | ||||
151 | } | ||||
152 | | ||||
153 | void AppletsLayout::setConfigKey(const QString &key) | ||||
154 | { | ||||
155 | if (m_configKey == key) { | ||||
156 | return; | ||||
157 | } | ||||
158 | | ||||
159 | m_configKey = key; | ||||
160 | | ||||
161 | // Reloading everything from the new config is expansive, event compress it | ||||
162 | m_configKeyChangeTimer->start(); | ||||
163 | | ||||
164 | emit configKeyChanged(); | ||||
165 | } | ||||
166 | | ||||
167 | QJSValue AppletsLayout::acceptsAppletCallback() const | ||||
168 | { | ||||
169 | return m_acceptsAppletCallback; | ||||
170 | } | ||||
171 | | ||||
172 | qreal AppletsLayout::minimumItemWidth() const | ||||
173 | { | ||||
174 | return m_minimumItemSize.width(); | ||||
175 | } | ||||
176 | | ||||
177 | void AppletsLayout::setMinimumItemWidth(qreal width) | ||||
178 | { | ||||
179 | if (qFuzzyCompare(width, m_minimumItemSize.width())) { | ||||
180 | return; | ||||
181 | } | ||||
182 | | ||||
183 | m_minimumItemSize.setWidth(width); | ||||
184 | | ||||
185 | emit minimumItemWidthChanged(); | ||||
186 | } | ||||
187 | | ||||
188 | qreal AppletsLayout::minimumItemHeight() const | ||||
189 | { | ||||
190 | return m_minimumItemSize.height(); | ||||
191 | } | ||||
192 | | ||||
193 | void AppletsLayout::setMinimumItemHeight(qreal height) | ||||
194 | { | ||||
195 | if (qFuzzyCompare(height, m_minimumItemSize.height())) { | ||||
196 | return; | ||||
197 | } | ||||
198 | | ||||
199 | m_minimumItemSize.setHeight(height); | ||||
200 | | ||||
201 | emit minimumItemHeightChanged(); | ||||
202 | } | ||||
203 | | ||||
204 | qreal AppletsLayout::defaultItemWidth() const | ||||
205 | { | ||||
206 | return m_defaultItemSize.width(); | ||||
207 | } | ||||
208 | | ||||
209 | void AppletsLayout::setDefaultItemWidth(qreal width) | ||||
210 | { | ||||
211 | if (qFuzzyCompare(width, m_defaultItemSize.width())) { | ||||
212 | return; | ||||
213 | } | ||||
214 | | ||||
215 | m_defaultItemSize.setWidth(width); | ||||
216 | | ||||
217 | emit defaultItemWidthChanged(); | ||||
218 | } | ||||
219 | | ||||
220 | qreal AppletsLayout::defaultItemHeight() const | ||||
221 | { | ||||
222 | return m_defaultItemSize.height(); | ||||
223 | } | ||||
224 | | ||||
225 | void AppletsLayout::setDefaultItemHeight(qreal height) | ||||
226 | { | ||||
227 | if (qFuzzyCompare(height, m_defaultItemSize.height())) { | ||||
228 | return; | ||||
229 | } | ||||
230 | | ||||
231 | m_defaultItemSize.setHeight(height); | ||||
232 | | ||||
233 | emit defaultItemHeightChanged(); | ||||
234 | } | ||||
235 | | ||||
236 | qreal AppletsLayout::cellWidth() const | ||||
237 | { | ||||
238 | return m_layoutManager->cellSize().width(); | ||||
239 | } | ||||
240 | | ||||
241 | void AppletsLayout::setCellWidth(qreal width) | ||||
242 | { | ||||
243 | if (qFuzzyCompare(width, m_layoutManager->cellSize().width())) { | ||||
244 | return; | ||||
245 | } | ||||
246 | | ||||
247 | m_layoutManager->setCellSize(QSizeF(width, m_layoutManager->cellSize().height())); | ||||
248 | | ||||
249 | emit cellWidthChanged(); | ||||
250 | } | ||||
251 | | ||||
252 | qreal AppletsLayout::cellHeight() const | ||||
253 | { | ||||
254 | return m_layoutManager->cellSize().height(); | ||||
255 | } | ||||
256 | | ||||
257 | void AppletsLayout::setCellHeight(qreal height) | ||||
258 | { | ||||
259 | if (qFuzzyCompare(height, m_layoutManager->cellSize().height())) { | ||||
260 | return; | ||||
261 | } | ||||
262 | | ||||
263 | m_layoutManager->setCellSize(QSizeF(m_layoutManager->cellSize().width(), height)); | ||||
264 | | ||||
265 | emit cellHeightChanged(); | ||||
266 | } | ||||
267 | | ||||
268 | void AppletsLayout::setAcceptsAppletCallback(const QJSValue& callback) | ||||
269 | { | ||||
270 | if (m_acceptsAppletCallback.strictlyEquals(callback)) { | ||||
271 | return; | ||||
272 | } | ||||
273 | | ||||
274 | if (!callback.isNull() && !callback.isCallable()) { | ||||
275 | return; | ||||
276 | } | ||||
277 | | ||||
278 | m_acceptsAppletCallback = callback; | ||||
279 | | ||||
280 | Q_EMIT acceptsAppletCallbackChanged(); | ||||
281 | } | ||||
282 | | ||||
283 | QQmlComponent *AppletsLayout::appletContainerComponent() const | ||||
284 | { | ||||
285 | return m_appletContainerComponent; | ||||
286 | } | ||||
287 | | ||||
288 | void AppletsLayout::setAppletContainerComponent(QQmlComponent *component) | ||||
289 | { | ||||
290 | if (m_appletContainerComponent == component) { | ||||
291 | return; | ||||
292 | } | ||||
293 | | ||||
294 | m_appletContainerComponent = component; | ||||
295 | | ||||
296 | emit appletContainerComponentChanged(); | ||||
297 | } | ||||
298 | | ||||
299 | AppletsLayout::EditModeCondition AppletsLayout::editModeCondition() const | ||||
300 | { | ||||
301 | return m_editModeCondition; | ||||
302 | } | ||||
303 | | ||||
304 | void AppletsLayout::setEditModeCondition(AppletsLayout::EditModeCondition condition) | ||||
305 | { | ||||
306 | if (m_editModeCondition == condition) { | ||||
307 | return; | ||||
308 | } | ||||
309 | | ||||
310 | if (m_editModeCondition == Locked) { | ||||
311 | setEditMode(false); | ||||
312 | } | ||||
313 | | ||||
314 | m_editModeCondition = condition; | ||||
315 | | ||||
316 | emit editModeConditionChanged(); | ||||
317 | } | ||||
318 | | ||||
319 | bool AppletsLayout::editMode() const | ||||
320 | { | ||||
321 | return m_editMode; | ||||
322 | } | ||||
323 | | ||||
324 | void AppletsLayout::setEditMode(bool editMode) | ||||
325 | { | ||||
326 | if (m_editMode == editMode) { | ||||
327 | return; | ||||
328 | } | ||||
329 | | ||||
330 | m_editMode = editMode; | ||||
331 | | ||||
332 | emit editModeChanged(); | ||||
333 | } | ||||
334 | | ||||
335 | ItemContainer *AppletsLayout::placeHolder() const | ||||
336 | { | ||||
337 | return m_placeHolder; | ||||
338 | } | ||||
339 | | ||||
340 | void AppletsLayout::setPlaceHolder(ItemContainer *placeHolder) | ||||
341 | { | ||||
342 | if (m_placeHolder == placeHolder) { | ||||
343 | return; | ||||
344 | } | ||||
345 | | ||||
346 | m_placeHolder = placeHolder; | ||||
347 | m_placeHolder->setParentItem(this); | ||||
348 | m_placeHolder->setZ(9999); | ||||
349 | m_placeHolder->setOpacity(false); | ||||
350 | | ||||
351 | emit placeHolderChanged(); | ||||
352 | } | ||||
353 | | ||||
354 | void AppletsLayout::save() | ||||
355 | { | ||||
356 | m_saveLayoutTimer->start(); | ||||
357 | } | ||||
358 | | ||||
359 | void AppletsLayout::showPlaceHolderAt(const QRectF &geom) | ||||
360 | { | ||||
361 | if (!m_placeHolder) { | ||||
362 | return; | ||||
363 | } | ||||
364 | | ||||
365 | m_placeHolder->setPosition(geom.topLeft()); | ||||
366 | m_placeHolder->setSize(geom.size()); | ||||
367 | | ||||
368 | m_layoutManager->positionItem(m_placeHolder); | ||||
369 | | ||||
370 | m_placeHolder->setProperty("opacity", 1); | ||||
371 | } | ||||
372 | | ||||
373 | void AppletsLayout::showPlaceHolderForItem(QQuickItem *item) | ||||
374 | { | ||||
375 | if (!m_placeHolder) { | ||||
376 | return; | ||||
377 | } | ||||
378 | | ||||
379 | m_placeHolder->setPosition(item->position()); | ||||
380 | m_placeHolder->setSize(item->size()); | ||||
381 | | ||||
382 | m_layoutManager->positionItem(m_placeHolder); | ||||
383 | | ||||
384 | m_placeHolder->setProperty("opacity", 1); | ||||
385 | } | ||||
386 | | ||||
387 | void AppletsLayout::hidePlaceHolder() | ||||
388 | { | ||||
389 | if (!m_placeHolder) { | ||||
390 | return; | ||||
391 | } | ||||
392 | | ||||
393 | m_placeHolder->setProperty("opacity", 0); | ||||
394 | } | ||||
395 | | ||||
396 | bool AppletsLayout::isRectAvailable(qreal x, qreal y, qreal width, qreal height) | ||||
397 | { | ||||
398 | return m_layoutManager->isRectAvailable(QRectF(x, y, width, height)); | ||||
399 | } | ||||
400 | | ||||
401 | bool AppletsLayout::itemIsManaged(ItemContainer *item) | ||||
402 | { | ||||
403 | return m_layoutManager->itemIsManaged(item); | ||||
404 | } | ||||
405 | | ||||
406 | void AppletsLayout::positionItem(ItemContainer *item) | ||||
407 | { | ||||
408 | item->setParent(this); | ||||
409 | m_layoutManager->positionItemAndAssign(item); | ||||
410 | } | ||||
411 | | ||||
412 | void AppletsLayout::releaseSpace(ItemContainer *item) | ||||
413 | { | ||||
414 | m_layoutManager->releaseSpace(item); | ||||
415 | } | ||||
416 | | ||||
417 | void AppletsLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) | ||||
418 | { | ||||
419 | // Ignore completely moves without resize | ||||
420 | if (newGeometry.size() == oldGeometry.size()) { | ||||
421 | QQuickItem::geometryChanged(newGeometry, oldGeometry); | ||||
422 | return; | ||||
423 | } | ||||
424 | | ||||
425 | // Don't care for anythin happening before startup completion | ||||
426 | if (!m_containment || !m_containment->corona() || !m_containment->corona()->isStartupCompleted()) { | ||||
427 | return; | ||||
428 | } | ||||
429 | | ||||
430 | // Only do a layouting procedure if we received a valid size | ||||
431 | if (!newGeometry.isEmpty()) { | ||||
432 | m_sizeSyncTimer->start(); | ||||
433 | } | ||||
434 | | ||||
435 | QQuickItem::geometryChanged(newGeometry, oldGeometry); | ||||
436 | } | ||||
437 | | ||||
438 | void AppletsLayout::updatePolish() | ||||
439 | { | ||||
440 | m_layoutManager->resetLayout(); | ||||
441 | m_savedSize = size(); | ||||
442 | } | ||||
443 | | ||||
444 | void AppletsLayout::componentComplete() | ||||
445 | { | ||||
446 | if (!m_containment || !m_containmentItem) { | ||||
447 | return; | ||||
448 | } | ||||
449 | | ||||
450 | if (!m_configKey.isEmpty()) { | ||||
451 | m_layoutManager->parseLayout(m_containment->config().readEntry(m_configKey, "")); | ||||
452 | } | ||||
453 | | ||||
454 | QList <QObject*> appletObjects = m_containmentItem->property("applets").value<QList <QObject*> >(); | ||||
455 | | ||||
456 | for (auto *obj : appletObjects) { | ||||
457 | PlasmaQuick::AppletQuickItem *appletItem = qobject_cast<PlasmaQuick::AppletQuickItem *>(obj); | ||||
458 | | ||||
459 | if (!obj) { | ||||
460 | continue; | ||||
461 | } | ||||
462 | | ||||
463 | AppletContainer *container = createContainerForApplet(appletItem); | ||||
464 | if (width() > 0 && height() > 0) { | ||||
465 | m_layoutManager->positionItemAndAssign(container); | ||||
466 | } | ||||
467 | } | ||||
468 | | ||||
469 | //layout all extra non applet items | ||||
470 | if (width() > 0 && height() > 0) { | ||||
471 | for (auto *child : childItems()) { | ||||
472 | ItemContainer *item = qobject_cast<ItemContainer *>(child); | ||||
473 | if (item && item != m_placeHolder && !m_layoutManager->itemIsManaged(item)) { | ||||
474 | m_layoutManager->positionItemAndAssign(item); | ||||
475 | } | ||||
476 | } | ||||
477 | } | ||||
478 | | ||||
479 | if (m_containment && m_containment->corona()) { | ||||
480 | connect(m_containment->corona(), &Plasma::Corona::startupCompleted, this, [this](){ | ||||
481 | // m_savedSize = size(); | ||||
482 | }); | ||||
483 | // 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 | ||||
484 | connect(m_containment->corona(), &Plasma::Corona::screenGeometryChanged, this, [this](int id){ | ||||
485 | if (m_containment->screen() == id) { | ||||
486 | m_geometryBeforeResolutionChange = QRectF(x(), y(), width(), height()); | ||||
487 | } | ||||
488 | }); | ||||
489 | } | ||||
490 | QQuickItem::componentComplete(); | ||||
491 | } | ||||
492 | | ||||
493 | | ||||
494 | | ||||
495 | void AppletsLayout::mousePressEvent(QMouseEvent *event) | ||||
496 | { | ||||
497 | forceActiveFocus(Qt::MouseFocusReason); | ||||
498 | | ||||
499 | if (!m_editMode && m_editModeCondition == AppletsLayout::Manual) { | ||||
500 | return; | ||||
501 | } | ||||
502 | | ||||
503 | if (!m_editMode && m_editModeCondition == AppletsLayout::AfterPressAndHold) { | ||||
504 | m_pressAndHoldTimer->start(QGuiApplication::styleHints()->mousePressAndHoldInterval()); | ||||
505 | } | ||||
506 | | ||||
507 | m_mouseDownWasEditMode = m_editMode; | ||||
508 | m_mouseDownPosition = event->windowPos(); | ||||
509 | | ||||
510 | //event->setAccepted(false); | ||||
511 | } | ||||
512 | | ||||
513 | void AppletsLayout::mouseMoveEvent(QMouseEvent *event) | ||||
514 | { | ||||
515 | if (!m_editMode && m_editModeCondition == AppletsLayout::Manual) { | ||||
516 | return; | ||||
517 | } | ||||
518 | | ||||
519 | if (!m_editMode | ||||
520 | && QPointF(event->windowPos() - m_mouseDownPosition).manhattanLength() >= QGuiApplication::styleHints()->startDragDistance()) { | ||||
521 | m_pressAndHoldTimer->stop(); | ||||
522 | } | ||||
523 | } | ||||
524 | | ||||
525 | void AppletsLayout::mouseReleaseEvent(QMouseEvent *event) | ||||
526 | { | ||||
527 | if (m_editMode | ||||
528 | && m_mouseDownWasEditMode | ||||
529 | && QPointF(event->windowPos() - m_mouseDownPosition).manhattanLength() < QGuiApplication::styleHints()->startDragDistance()) { | ||||
530 | setEditMode(false); | ||||
531 | } | ||||
532 | | ||||
533 | m_pressAndHoldTimer->stop(); | ||||
534 | | ||||
535 | if (!m_editMode) { | ||||
536 | for (auto *child : childItems()) { | ||||
537 | ItemContainer *item = qobject_cast<ItemContainer *>(child); | ||||
538 | if (item && item != m_placeHolder) { | ||||
539 | item->setEditMode(false); | ||||
540 | } | ||||
541 | } | ||||
542 | } | ||||
543 | } | ||||
544 | | ||||
545 | void AppletsLayout::appletAdded(QObject *applet, int x, int y) | ||||
546 | { | ||||
547 | PlasmaQuick::AppletQuickItem *appletItem = qobject_cast<PlasmaQuick::AppletQuickItem *>(applet); | ||||
548 | | ||||
549 | //maybe even an assert? | ||||
550 | if (!appletItem) { | ||||
551 | return; | ||||
552 | } | ||||
553 | | ||||
554 | if (m_acceptsAppletCallback.isCallable()) { | ||||
555 | QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine(); | ||||
556 | Q_ASSERT(engine); | ||||
557 | QJSValueList args; | ||||
558 | args << engine->newQObject(applet) << QJSValue(x) << QJSValue(y); | ||||
559 | | ||||
560 | if (!m_acceptsAppletCallback.call(args).toBool()) { | ||||
561 | emit appletRefused(applet, x, y); | ||||
562 | return; | ||||
563 | } | ||||
564 | } | ||||
565 | | ||||
566 | AppletContainer *container = createContainerForApplet(appletItem); | ||||
567 | container->setPosition(QPointF(x, y)); | ||||
568 | container->setVisible(true); | ||||
569 | | ||||
570 | m_layoutManager->positionItemAndAssign(container); | ||||
571 | } | ||||
572 | | ||||
573 | void AppletsLayout::appletRemoved(QObject *applet) | ||||
574 | { | ||||
575 | PlasmaQuick::AppletQuickItem *appletItem = qobject_cast<PlasmaQuick::AppletQuickItem *>(applet); | ||||
576 | | ||||
577 | //maybe even an assert? | ||||
578 | if (!appletItem) { | ||||
579 | return; | ||||
580 | } | ||||
581 | | ||||
582 | AppletContainer *container = m_containerForApplet.value(appletItem); | ||||
583 | if (!container) { | ||||
584 | return; | ||||
585 | } | ||||
586 | | ||||
587 | m_layoutManager->releaseSpace(container); | ||||
588 | m_containerForApplet.remove(appletItem); | ||||
589 | appletItem->setParentItem(this); | ||||
590 | container->deleteLater(); | ||||
591 | } | ||||
592 | | ||||
593 | AppletContainer *AppletsLayout::createContainerForApplet(PlasmaQuick::AppletQuickItem *appletItem) | ||||
594 | { | ||||
595 | AppletContainer *container = m_containerForApplet.value(appletItem); | ||||
596 | | ||||
597 | if (container) { | ||||
598 | return container; | ||||
599 | } | ||||
600 | | ||||
601 | bool createdFromQml = true; | ||||
602 | | ||||
603 | if (m_appletContainerComponent) { | ||||
604 | QQmlContext *context = QQmlEngine::contextForObject(this); | ||||
605 | Q_ASSERT(context); | ||||
606 | QObject *instance = m_appletContainerComponent->beginCreate(context); | ||||
607 | container = qobject_cast<AppletContainer *>(instance); | ||||
608 | if (container) { | ||||
609 | container->setParentItem(this); | ||||
610 | } else { | ||||
611 | qWarning() << "Error: provided component not an AppletContainer instance"; | ||||
612 | if (instance) { | ||||
613 | instance->deleteLater(); | ||||
614 | } | ||||
615 | createdFromQml = false; | ||||
616 | } | ||||
617 | } | ||||
618 | | ||||
619 | if (!container) { | ||||
620 | container = new AppletContainer(this); | ||||
621 | } | ||||
622 | | ||||
623 | container->setVisible(false); | ||||
624 | | ||||
625 | const QSizeF appletSize = appletItem->size(); | ||||
626 | container->setContentItem(appletItem); | ||||
627 | | ||||
628 | m_containerForApplet[appletItem] = container; | ||||
629 | container->setLayout(this); | ||||
630 | container->setKey(QLatin1String("Applet-") + QString::number(appletItem->applet()->id())); | ||||
631 | | ||||
632 | const bool geometryWasSaved = m_layoutManager->restoreItem(container); | ||||
633 | | ||||
634 | if (!geometryWasSaved) { | ||||
635 | container->setPosition(QPointF(appletItem->x() - container->leftPadding(), | ||||
636 | appletItem->y() - container->topPadding())); | ||||
637 | | ||||
638 | if (!appletSize.isEmpty()) { | ||||
639 | container->setSize(QSizeF(qMax(m_minimumItemSize.width(), appletSize.width() + container->leftPadding() + container->rightPadding()), | ||||
640 | qMax(m_minimumItemSize.height(), appletSize.height() + container->topPadding() + container->bottomPadding()))); | ||||
641 | } | ||||
642 | } | ||||
643 | | ||||
644 | if (m_appletContainerComponent && createdFromQml) { | ||||
645 | m_appletContainerComponent->completeCreate(); | ||||
646 | } | ||||
647 | | ||||
648 | //NOTE: This has to be done here as we need the component completed to have all the bindings evaluated | ||||
649 | if (!geometryWasSaved && appletSize.isEmpty()) { | ||||
650 | if (container->initialSize().width() > m_minimumItemSize.width() && | ||||
651 | container->initialSize().height() > m_minimumItemSize.height()) { | ||||
652 | const QSizeF size = m_layoutManager->cellAlignedContainingSize( container->initialSize()); | ||||
653 | container->setSize(size); | ||||
654 | } else { | ||||
655 | container->setSize(QSizeF(qMax(m_minimumItemSize.width(), m_defaultItemSize.width()), | ||||
656 | qMax(m_minimumItemSize.height(), m_defaultItemSize.height()))); | ||||
657 | } | ||||
658 | } | ||||
659 | | ||||
660 | container->setVisible(true); | ||||
661 | appletItem->setVisible(true); | ||||
662 | | ||||
663 | | ||||
664 | return container; | ||||
665 | } | ||||
666 | | ||||
667 | #include "moc_appletslayout.cpp" |