Merge lp:~zsombi/ubuntu-ui-toolkit/theming-attached into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri on 2015-07-29
Status: Rejected
Rejected by: Christian Dywan on 2015-10-08
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/theming-attached
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 777 lines (+379/-209)
9 files modified
components.api (+2/-1)
src/Ubuntu/Components/plugin/plugin.cpp (+2/-1)
src/Ubuntu/Components/plugin/plugin.pri (+4/-2)
src/Ubuntu/Components/plugin/ucstyleditembase.cpp (+21/-184)
src/Ubuntu/Components/plugin/ucstyleditembase.h (+1/-3)
src/Ubuntu/Components/plugin/ucstyleditembase_p.h (+7/-14)
src/Ubuntu/Components/plugin/uctheme.cpp (+4/-4)
src/Ubuntu/Components/plugin/ucthemingattached.cpp (+257/-0)
src/Ubuntu/Components/plugin/ucthemingattached.h (+81/-0)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/theming-attached
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2015-08-06
Christian Dywan 2015-07-29 Approve on 2015-07-30
Review via email: mp+266317@code.launchpad.net

Commit message

Detaching theming management from StyledItem to be reused in other cpp types.

To post a comment you must log in.
Zsombor Egri (zsombi) wrote :

StyledItem was registered twice with the revision 2, so the 1.3 appeared twice in the API file. I fixed that as well.

1584. By Zsombor Egri on 2015-07-30

segfault fixed

Christian Dywan (kalikiana) wrote :

As discussed, there is no effective change in functionality in StyledItemBase so it's already covered by unit tests. We won't really know if it exposes the theming correctly until we have the first real word user of it, which is going to be the Label in C++ which can't currently inherit from StyledItemBase, so this should be the prerequisite branch.

review: Approve
1585. By Zsombor Egri on 2015-08-05

staging sync

1586. By Zsombor Egri on 2015-08-06

simplifying the use of theming

1587. By Zsombor Egri on 2015-08-06

staging sync

Unmerged revisions

1587. By Zsombor Egri on 2015-08-06

staging sync

1586. By Zsombor Egri on 2015-08-06

simplifying the use of theming

1585. By Zsombor Egri on 2015-08-05

staging sync

1584. By Zsombor Egri on 2015-07-30

segfault fixed

1583. By Zsombor Egri on 2015-07-30

renaming styling to theming

1582. By Zsombor Egri on 2015-07-30

API file fixed

1581. By Zsombor Egri on 2015-07-30

staging merge

1580. By Zsombor Egri on 2015-07-29

separation completed

1579. By Zsombor Egri on 2015-07-28

staging sync

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'components.api'
--- components.api 2015-08-04 20:07:41 +0000
+++ components.api 2015-08-06 18:06:52 +0000
@@ -878,7 +878,7 @@
878Ubuntu.Components.StateSaver 1.0 0.1: QtObject878Ubuntu.Components.StateSaver 1.0 0.1: QtObject
879Ubuntu.Components.StyleHints 1.3: QtObject879Ubuntu.Components.StyleHints 1.3: QtObject
880 property bool ignoreUnknownProperties880 property bool ignoreUnknownProperties
881Ubuntu.Components.StyledItem 1.3 1.3 1.1 1.0 0.1: Item881Ubuntu.Components.StyledItem 1.3 1.1 1.0 0.1: Item
882 property bool activeFocusOnPress 1.3882 property bool activeFocusOnPress 1.3
883 function bool requestFocus(Qt.FocusReason reason) 1.3883 function bool requestFocus(Qt.FocusReason reason) 1.3
884 function bool requestFocus() 1.3884 function bool requestFocus() 1.3
@@ -1238,6 +1238,7 @@
1238UCStateSaverAttached: QtObject1238UCStateSaverAttached: QtObject
1239 property bool enabled1239 property bool enabled
1240 property string properties1240 property string properties
1241UCThemingAttached: QtObject
1241Ubuntu.Components.UCUnits 1.0 0.1: QtObject1242Ubuntu.Components.UCUnits 1.0 0.1: QtObject
1242 property float gridUnit1243 property float gridUnit
1243 function float dp(float value)1244 function float dp(float value)
12441245
=== modified file 'src/Ubuntu/Components/plugin/plugin.cpp'
--- src/Ubuntu/Components/plugin/plugin.cpp 2015-07-23 11:49:38 +0000
+++ src/Ubuntu/Components/plugin/plugin.cpp 2015-08-06 18:06:52 +0000
@@ -22,6 +22,7 @@
2222
23#include "plugin.h"23#include "plugin.h"
24#include "uctheme.h"24#include "uctheme.h"
25#include "ucthemingattached.h"
25#include "ucdeprecatedtheme.h"26#include "ucdeprecatedtheme.h"
2627
27#include <QtQml/QQmlContext>28#include <QtQml/QQmlContext>
@@ -208,11 +209,11 @@
208 qmlRegisterType<UCUbuntuShapeOverlay>(uri, 1, 2, "UbuntuShapeOverlay");209 qmlRegisterType<UCUbuntuShapeOverlay>(uri, 1, 2, "UbuntuShapeOverlay");
209210
210 // register 1.3 API211 // register 1.3 API
212 qmlRegisterType<UCThemingAttached>();
211 qmlRegisterType<UCListItem13>(uri, 1, 3, "ListItem");213 qmlRegisterType<UCListItem13>(uri, 1, 3, "ListItem");
212 qmlRegisterType<UCTheme>(uri, 1, 3, "ThemeSettings");214 qmlRegisterType<UCTheme>(uri, 1, 3, "ThemeSettings");
213 qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem");215 qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem");
214 qmlRegisterSingletonType<UCNamespaceV13>(uri, 1, 3, "Ubuntu", registerUbuntuNamespace13);216 qmlRegisterSingletonType<UCNamespaceV13>(uri, 1, 3, "Ubuntu", registerUbuntuNamespace13);
215 qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem");
216 qmlRegisterCustomType<UCStyleHints>(uri, 1, 3, "StyleHints", new UCStyleHintsParser);217 qmlRegisterCustomType<UCStyleHints>(uri, 1, 3, "StyleHints", new UCStyleHintsParser);
217 qmlRegisterType<UCAction, 1>(uri, 1, 3, "Action");218 qmlRegisterType<UCAction, 1>(uri, 1, 3, "Action");
218 qmlRegisterType<UCUbuntuShape, 2>(uri, 1, 3, "UbuntuShape");219 qmlRegisterType<UCUbuntuShape, 2>(uri, 1, 3, "UbuntuShape");
219220
=== modified file 'src/Ubuntu/Components/plugin/plugin.pri'
--- src/Ubuntu/Components/plugin/plugin.pri 2015-07-30 09:57:45 +0000
+++ src/Ubuntu/Components/plugin/plugin.pri 2015-08-06 18:06:52 +0000
@@ -76,7 +76,8 @@
76 $$PWD/ucnamespace.h \76 $$PWD/ucnamespace.h \
77 $$PWD/ucdeprecatedtheme.h \77 $$PWD/ucdeprecatedtheme.h \
78 $$PWD/ucdefaulttheme.h \78 $$PWD/ucdefaulttheme.h \
79 $$PWD/ucstylehints.h79 $$PWD/ucstylehints.h \
80 $$PWD/ucthemingattached.h
8081
81SOURCES += $$PWD/plugin.cpp \82SOURCES += $$PWD/plugin.cpp \
82 $$PWD/uctheme.cpp \83 $$PWD/uctheme.cpp \
@@ -125,7 +126,8 @@
125 $$PWD/ucnamespace.cpp \126 $$PWD/ucnamespace.cpp \
126 $$PWD/ucdeprecatedtheme.cpp \127 $$PWD/ucdeprecatedtheme.cpp \
127 $$PWD/ucdefaulttheme.cpp \128 $$PWD/ucdefaulttheme.cpp \
128 $$PWD/ucstylehints.cpp129 $$PWD/ucstylehints.cpp \
130 $$PWD/ucthemingattached.cpp
129131
130# adapters132# adapters
131SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp133SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp
132134
=== modified file 'src/Ubuntu/Components/plugin/ucstyleditembase.cpp'
--- src/Ubuntu/Components/plugin/ucstyleditembase.cpp 2015-07-29 11:41:16 +0000
+++ src/Ubuntu/Components/plugin/ucstyleditembase.cpp 2015-08-06 18:06:52 +0000
@@ -18,18 +18,16 @@
1818
19#include "ucstyleditembase.h"19#include "ucstyleditembase.h"
20#include "ucstyleditembase_p.h"20#include "ucstyleditembase_p.h"
21#include "ucthemingattached.h"
21#include "uctheme.h"22#include "uctheme.h"
22#include "ucstylehints.h"23#include "ucstylehints.h"
23#include <QtQml/QQmlEngine>24#include <QtQml/QQmlEngine>
24#include <QtQuick/private/qquickanchors_p.h>25#include <QtQuick/private/qquickanchors_p.h>
2526
26UCStyledItemBasePrivate::UCStyledItemBasePrivate()27UCStyledItemBasePrivate::UCStyledItemBasePrivate()
27 : activeFocusOnPress(false)28 : styleComponent(0)
28 , styleComponent(0)
29 , styleItemContext(0)
30 , styleItem(0)29 , styleItem(0)
31 , theme(0)30 , activeFocusOnPress(false)
32 , parentStyledItem(0)
33{31{
34}32}
3533
@@ -41,10 +39,6 @@
41{39{
42 Q_Q(UCStyledItemBase);40 Q_Q(UCStyledItemBase);
43 q->setFlag(QQuickItem::ItemIsFocusScope);41 q->setFlag(QQuickItem::ItemIsFocusScope);
44 QObject::connect(&UCTheme::defaultTheme(), SIGNAL(nameChanged()),
45 q, SLOT(_q_reloadStyle()));
46 QObject::connect(&UCTheme::defaultTheme(), SIGNAL(versionChanged()),
47 q, SLOT(_q_reloadStyle()));
48}42}
4943
5044
@@ -455,75 +449,14 @@
455 */449 */
456UCTheme *UCStyledItemBasePrivate::getTheme() const450UCTheme *UCStyledItemBasePrivate::getTheme() const
457{451{
458 if (theme) {452 return theming ? theming->getTheme() : &UCTheme::defaultTheme();
459 return theme;
460 } else if (!parentStyledItem.isNull()) {
461 return UCStyledItemBasePrivate::get(parentStyledItem)->getTheme();
462 }
463 return &UCTheme::defaultTheme();
464}453}
465void UCStyledItemBasePrivate::setTheme(UCTheme *newTheme)454void UCStyledItemBasePrivate::setTheme(UCTheme *newTheme)
466{455{
467 Q_Q(UCStyledItemBase);456 if (theming && !theming->setTheme(newTheme)) {
468 if (theme == newTheme) {
469 return;457 return;
470 }458 }
471459
472 // preform pre-theme change tasks
473 preThemeChanged();
474
475 // disconnect from the previous set
476 UCTheme *connectedSet = theme ?
477 theme :
478 (!parentStyledItem ? &UCTheme::defaultTheme() : NULL);
479 if (connectedSet) {
480 QObject::disconnect(connectedSet, SIGNAL(nameChanged()),
481 q, SLOT(_q_reloadStyle()));
482 QObject::disconnect(connectedSet, SIGNAL(versionChanged()),
483 q, SLOT(_q_reloadStyle()));
484 }
485
486 UCTheme *prevSet = theme;
487
488 // resolve new theme
489 if (theme && newTheme) {
490 // no need to redo the parentStack, simply set the theme and leave
491 theme = newTheme;
492 } else {
493 theme = newTheme;
494 if (!newTheme) {
495 // redo the parent chanin
496 disconnectTillItem(0);
497 connectParents(0);
498 }
499 }
500
501 // connect to the new set
502 connectedSet = theme ?
503 theme :
504 (!parentStyledItem ? &UCTheme::defaultTheme() : NULL);
505 if (connectedSet) {
506 QObject::connect(connectedSet, SIGNAL(nameChanged()),
507 q, SLOT(_q_reloadStyle()));
508 QObject::connect(connectedSet, SIGNAL(versionChanged()),
509 q, SLOT(_q_reloadStyle()));
510 }
511 // detach previous set and attach the new one
512 if (prevSet) {
513 Q_EMIT prevSet->parentThemeChanged();
514 }
515 if (theme) {
516 // re-parent theme to make sure we have it
517 // for the entire lifetime of the styled item
518 theme->setParent(q);
519 Q_EMIT theme->parentThemeChanged();
520 }
521
522 // perform post-theme changes, update internal styling
523 postThemeChanged();
524
525 Q_EMIT q->themeChanged();
526
527 // perform style reload460 // perform style reload
528 if (!styleComponent) {461 if (!styleComponent) {
529 preStyleChanged();462 preStyleChanged();
@@ -533,102 +466,22 @@
533}466}
534void UCStyledItemBasePrivate::resetTheme()467void UCStyledItemBasePrivate::resetTheme()
535{468{
536 setTheme(NULL);469 theming->setTheme(Q_NULLPTR);
537}470}
538471
539// link/unlink all ascendant items until we reach a StyledItem, returns true if the472
540// theme change signal emission is justified473void UCStyledItemBase::classBegin()
541bool UCStyledItemBasePrivate::connectParents(QQuickItem *fromItem)474{
542{475 QQuickItem::classBegin();
543 Q_Q(UCStyledItemBase);476
544 QQuickItem *item = fromItem ? fromItem : parentItem;477 Q_D(UCStyledItemBase);
545 while (item) {478 // attach theming
546 // push the item onto the stack479 d->theming = UCThemingAttached::attachTheming(this);
547 parentStack.push(QPointer<QQuickItem>(item));480 if (d->theming) {
548 UCStyledItemBase *styledItem = qobject_cast<UCStyledItemBase*>(item);481 d->theming->setListener(d);
549 if (styledItem) {482 connect(d->theming.data(), SIGNAL(themeChanged()),
550 // this is the closest StyledItem, connect its themeChanged() signal483 this, SLOT(_q_reloadStyle()));
551 QObject::connect(styledItem, SIGNAL(themeChanged()),484 }
552 q, SLOT(_q_parentStyleChanged()), Qt::DirectConnection);
553 // set the current style set to the one in the parent's one if differs
554 return setParentStyled(styledItem);
555 } else {
556 // connect to the item's parentChanged() signal so we can detect when the parent changes
557 QObject::connect(item, SIGNAL(parentChanged(QQuickItem*)),
558 q, SLOT(_q_ascendantChanged(QQuickItem*)), Qt::DirectConnection);
559 }
560 item = item->parentItem();
561 }
562 return false;
563}
564
565// set the used parent styled item's style; returns true if the parent styled got changed
566bool UCStyledItemBasePrivate::setParentStyled(UCStyledItemBase *styledItem)
567{
568 if (parentStyledItem == styledItem) {
569 return false;
570 }
571 parentStyledItem = styledItem;
572 if (theme) {
573 Q_EMIT theme->parentThemeChanged();
574 }
575 return (theme == NULL);
576}
577
578// disconnect parent stack till item is reached; all the stack if item == 0
579void UCStyledItemBasePrivate::disconnectTillItem(QQuickItem *item)
580{
581 Q_Q(UCStyledItemBase);
582 while (!parentStack.isEmpty() && item != parentStack.top()) {
583 QPointer<QQuickItem> stackItem = parentStack.pop();
584 // the topmost item can be the only one which is a StyledItem
585 UCStyledItemBase *styledItem = qobject_cast<UCStyledItemBase*>(stackItem.data());
586 if (styledItem) {
587 QObject::disconnect(styledItem, SIGNAL(themeChanged()),
588 q, SLOT(_q_parentStyleChanged()));
589 } else if (!stackItem.isNull()) {
590 QObject::disconnect(stackItem.data(), SIGNAL(parentChanged(QQuickItem*)),
591 q, SLOT(_q_ascendantChanged(QQuickItem*)));
592 }
593 }
594}
595
596// captures ascendant change signal, the sender is the one which counts!
597void UCStyledItemBasePrivate::_q_ascendantChanged(QQuickItem *ascendant)
598{
599 Q_Q(UCStyledItemBase);
600 QQuickItem *sender = static_cast<QQuickItem*>(q->sender());
601 if (!sender) {
602 // cannot detect the sender, leave!
603 return;
604 }
605 if (ascendant) {
606 // disconnect from the previous ones
607 disconnectTillItem(sender);
608 parentStyledItem.clear();
609 // traverse ascendants till we reach a StyledItem or root and push them into the stack
610 if (connectParents(ascendant)) {
611 Q_EMIT q->themeChanged();
612 }
613 }
614}
615
616// syncs the ascendant StyledItem's style
617void UCStyledItemBasePrivate::_q_parentStyleChanged()
618{
619 // do not trigger themeChanged() on this item if we have a
620 // custom one, but resolve its eventual parent change!
621 if (theme) {
622 Q_EMIT theme->parentThemeChanged();
623 return;
624 }
625 Q_Q(UCStyledItemBase);
626 UCStyledItemBase *styledItem = static_cast<UCStyledItemBase*>(q->sender());
627 if (!styledItem) {
628 return;
629 }
630 setParentStyled(styledItem);
631 Q_EMIT q->themeChanged();
632}485}
633486
634void UCStyledItemBase::componentComplete()487void UCStyledItemBase::componentComplete()
@@ -667,20 +520,4 @@
667 return QQuickItem::childMouseEventFilter(child, event);520 return QQuickItem::childMouseEventFilter(child, event);
668}521}
669522
670// catch parent change event so we can lookup for the parent chain theme
671void UCStyledItemBase::itemChange(ItemChange change, const ItemChangeData &data)
672{
673 QQuickItem::itemChange(change, data);
674 if (change == ItemParentHasChanged) {
675 Q_D(UCStyledItemBase);
676 // clean stack
677 d->disconnectTillItem(0);
678 // make sure we reset parent StyledItem
679 d->parentStyledItem.clear();
680 // build the stack - if possible
681 d->connectParents(0);
682 Q_EMIT themeChanged();
683 }
684}
685
686#include "moc_ucstyleditembase.cpp"523#include "moc_ucstyleditembase.cpp"
687524
=== modified file 'src/Ubuntu/Components/plugin/ucstyleditembase.h'
--- src/Ubuntu/Components/plugin/ucstyleditembase.h 2015-06-02 12:37:41 +0000
+++ src/Ubuntu/Components/plugin/ucstyleditembase.h 2015-08-06 18:06:52 +0000
@@ -53,16 +53,14 @@
53protected:53protected:
54 UCStyledItemBase(UCStyledItemBasePrivate &, QQuickItem *parent);54 UCStyledItemBase(UCStyledItemBasePrivate &, QQuickItem *parent);
5555
56 void classBegin();
56 void componentComplete();57 void componentComplete();
57 void mousePressEvent(QMouseEvent *event);58 void mousePressEvent(QMouseEvent *event);
58 bool childMouseEventFilter(QQuickItem *child, QEvent *event);59 bool childMouseEventFilter(QQuickItem *child, QEvent *event);
59 void itemChange(ItemChange, const ItemChangeData &);
6060
61private:61private:
62 Q_DECLARE_PRIVATE(UCStyledItemBase)62 Q_DECLARE_PRIVATE(UCStyledItemBase)
63 Q_PRIVATE_SLOT(d_func(), void _q_styleResized())63 Q_PRIVATE_SLOT(d_func(), void _q_styleResized())
64 Q_PRIVATE_SLOT(d_func(), void _q_ascendantChanged(QQuickItem*))
65 Q_PRIVATE_SLOT(d_func(), void _q_parentStyleChanged())
66 Q_PRIVATE_SLOT(d_func(), void _q_reloadStyle())64 Q_PRIVATE_SLOT(d_func(), void _q_reloadStyle())
67};65};
6866
6967
=== modified file 'src/Ubuntu/Components/plugin/ucstyleditembase_p.h'
--- src/Ubuntu/Components/plugin/ucstyleditembase_p.h 2015-06-02 12:37:41 +0000
+++ src/Ubuntu/Components/plugin/ucstyleditembase_p.h 2015-08-06 18:06:52 +0000
@@ -21,10 +21,11 @@
2121
22#include <QtQuick/private/qquickitem_p.h>22#include <QtQuick/private/qquickitem_p.h>
23#include "ucstyleditembase.h"23#include "ucstyleditembase.h"
24#include "ucthemingattached.h"
2425
25class QQuickMouseArea;26class QQuickMouseArea;
26class UCStyledItemBase;27class UCStyledItemBase;
27class UCStyledItemBasePrivate : public QQuickItemPrivate28class UCStyledItemBasePrivate : public QQuickItemPrivate, public UCThemeChangeListener
28{29{
29 Q_DECLARE_PUBLIC(UCStyledItemBase)30 Q_DECLARE_PUBLIC(UCStyledItemBase)
30public:31public:
@@ -35,8 +36,6 @@
3536
36 void _q_reloadStyle();37 void _q_reloadStyle();
37 void _q_styleResized();38 void _q_styleResized();
38 void _q_ascendantChanged(QQuickItem *ascendant);
39 void _q_parentStyleChanged();
4039
41 UCStyledItemBasePrivate();40 UCStyledItemBasePrivate();
42 virtual ~UCStyledItemBasePrivate();41 virtual ~UCStyledItemBasePrivate();
@@ -61,25 +60,19 @@
61 void setTheme(UCTheme *theme);60 void setTheme(UCTheme *theme);
62 void resetTheme();61 void resetTheme();
6362
64 virtual void preThemeChanged(){}63 void preThemeChanged(){}
65 virtual void postThemeChanged(){}64 void postThemeChanged(){}
6665
67public:66public:
68 bool activeFocusOnPress:1;
69 QString styleDocument;67 QString styleDocument;
68 QPointer<UCThemingAttached> theming;
69 QPointer<QQmlContext> styleItemContext;
70 QQmlComponent *styleComponent;70 QQmlComponent *styleComponent;
71 QPointer<QQmlContext> styleItemContext;
72 QQuickItem *styleItem;71 QQuickItem *styleItem;
73 UCTheme *theme;72 bool activeFocusOnPress:1;
74 QPointer<UCStyledItemBase> parentStyledItem;
7573
76protected:74protected:
77 QStack< QPointer<QQuickItem> > parentStack;
78
79 void connectStyleSizeChanges(bool attach);75 void connectStyleSizeChanges(bool attach);
80 bool connectParents(QQuickItem *fromItem);
81 bool setParentStyled(UCStyledItemBase *styledItem);
82 void disconnectTillItem(QQuickItem *item);
83};76};
8477
85#endif // UCSTYLEDITEMBASE_P_H78#endif // UCSTYLEDITEMBASE_P_H
8679
=== modified file 'src/Ubuntu/Components/plugin/uctheme.cpp'
--- src/Ubuntu/Components/plugin/uctheme.cpp 2015-07-20 12:56:17 +0000
+++ src/Ubuntu/Components/plugin/uctheme.cpp 2015-08-06 18:06:52 +0000
@@ -24,6 +24,7 @@
24#include "i18n.h"24#include "i18n.h"
25#include "ucfontutils.h"25#include "ucfontutils.h"
26#include "ucstyleditembase_p.h"26#include "ucstyleditembase_p.h"
27#include "ucthemingattached.h"
2728
28#include <QtQml/qqml.h>29#include <QtQml/qqml.h>
29#include <QtQml/qqmlinfo.h>30#include <QtQml/qqmlinfo.h>
@@ -422,10 +423,9 @@
422 */423 */
423UCTheme *UCTheme::parentTheme()424UCTheme *UCTheme::parentTheme()
424{425{
425 UCStyledItemBase *owner = qobject_cast<UCStyledItemBase*>(parent());426 UCThemingAttached *theming = itemTheming(static_cast<QQuickItem*>(parent()));
426 UCStyledItemBasePrivate *pOwner = owner ? UCStyledItemBasePrivate::get(owner) : NULL;427 if (theming && theming->m_theme == this && theming->m_parentTheming) {
427 if (pOwner && pOwner->theme == this && pOwner->parentStyledItem) {428 return theming->m_parentTheming->getTheme();
428 return UCStyledItemBasePrivate::get(pOwner->parentStyledItem)->getTheme();
429 }429 }
430 return NULL;430 return NULL;
431}431}
432432
=== added file 'src/Ubuntu/Components/plugin/ucthemingattached.cpp'
--- src/Ubuntu/Components/plugin/ucthemingattached.cpp 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/plugin/ucthemingattached.cpp 2015-08-06 18:06:52 +0000
@@ -0,0 +1,257 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Zsombor Egri <zsombor.egri@canonical.com>
17 */
18
19#include "ucthemingattached.h"
20#include <QtQuick/QQuickItem>
21#include "uctheme.h"
22
23/*
24 * UCThemingAttached is an attached object to all themable components. It is used
25 * internally by those components which need theme access thru the theme property.
26 * Components which want to use this should do the following:
27 * - attach the object in classBegin() function
28 * - expose a theme property
29 * - getter should use the getTheme() attached function
30 * - setter/reset should use the setTheme() attached function
31 * - themeChanged() signal must be connected to the property change signal
32 *
33 * The theme change is notified through listener callbacks. Registering listener
34 * is not mandatory.
35 */
36
37UCThemingAttached *itemTheming(QQuickItem *item)
38{
39 return qobject_cast<UCThemingAttached*>(
40 qmlAttachedPropertiesObject<UCThemingAttached>(item, false));
41}
42
43UCThemingAttached::UCThemingAttached(QObject *parent)
44 : QObject(parent)
45 , m_theme(Q_NULLPTR)
46 , m_listener(Q_NULLPTR)
47 , m_ownerItem(static_cast<QQuickItem*>(parent))
48{
49}
50
51UCThemingAttached *UCThemingAttached::qmlAttachedProperties(QObject *owner)
52{
53 UCThemingAttached *theming = new UCThemingAttached(owner);
54 // the theme is the default one at this stage, so connect all the necessary signals
55 // owner must have theme signal
56 theming->connectThemeSignals(theming->getTheme(), true);
57 // connect parentChanged of owner to know when its parent is changed
58 connect(theming->m_ownerItem, &QQuickItem::parentChanged,
59 theming, &UCThemingAttached::itemParentChanged, Qt::DirectConnection);
60 return theming;
61}
62
63UCThemingAttached *UCThemingAttached::attachTheming(QObject *owner)
64{
65 return qobject_cast<UCThemingAttached*>(
66 qmlAttachedPropertiesObject<UCThemingAttached>(owner, true));
67}
68
69void UCThemingAttached::connectThemeSignals(UCTheme *theme, bool connect)
70{
71 if (connect) {
72 QObject::connect(theme, SIGNAL(nameChanged()), this, SIGNAL(themeChanged()), Qt::DirectConnection);
73 QObject::connect(theme, SIGNAL(versionChanged()), this, SIGNAL(themeChanged()), Qt::DirectConnection);
74 } else {
75 QObject::disconnect(theme, SIGNAL(nameChanged()), this, SIGNAL(themeChanged()));
76 QObject::disconnect(theme, SIGNAL(versionChanged()), this, SIGNAL(themeChanged()));
77 }
78}
79
80// link/unlink all ascendant items until we reach a StyledItem, returns true if the
81// theme change signal emission is justified
82bool UCThemingAttached::connectParents(QQuickItem *fromItem)
83{
84 QQuickItem *item = fromItem ? fromItem : m_ownerItem->parentItem();
85 while (item) {
86 // push the item onto the stack
87 m_parentStack.push(QPointer<QQuickItem>(item));
88 UCThemingAttached *styling = itemTheming(item);
89 if (styling) {
90 // this is the closest StyledItem, connect its themeChanged() signal
91 QObject::connect(styling, SIGNAL(themeChanged()),
92 this, SLOT(parentStyleChanged()), Qt::DirectConnection);
93 // set the current style set to the one in the parent's one if differs
94 return setParentStyled(styling);
95 } else {
96 // connect to the item's parentChanged() signal so we can detect when the parent changes
97 QObject::connect(item, SIGNAL(parentChanged(QQuickItem*)),
98 this, SLOT(ascendantChanged(QQuickItem*)), Qt::DirectConnection);
99 }
100 item = item->parentItem();
101 }
102 return false;
103}
104
105// disconnect parent stack till item is reached; all the stack if item == 0
106void UCThemingAttached::disconnectTillItem(QQuickItem *item)
107{
108 while (!m_parentStack.isEmpty() && item != m_parentStack.top()) {
109 QPointer<QQuickItem> stackItem = m_parentStack.pop();
110 // the topmost item can be the only one which is a StyledItem
111 UCThemingAttached *styling = itemTheming(stackItem.data());
112 if (styling) {
113 QObject::disconnect(styling, SIGNAL(themeChanged()),
114 this, SLOT(parentStyleChanged()));
115 // clear parent styling as well
116 if (styling == m_parentTheming) {
117 m_parentTheming.clear();
118 }
119 } else if (!stackItem.isNull()) {
120 QObject::disconnect(stackItem.data(), SIGNAL(parentChanged(QQuickItem*)),
121 this, SLOT(ascendantChanged(QQuickItem*)));
122 }
123 }
124}
125
126// set the used parent styled item's style; returns true if the parent styled got changed
127bool UCThemingAttached::setParentStyled(UCThemingAttached *newStyling)
128{
129 if (m_parentTheming == newStyling) {
130 return false;
131 }
132 m_parentTheming = newStyling;
133 if (m_theme) {
134 Q_EMIT themeChanged();
135 }
136 return (m_theme == NULL);
137}
138
139UCTheme *UCThemingAttached::getTheme()
140{
141 if (m_theme) {
142 return m_theme;
143 } else if (!m_parentTheming.isNull()) {
144 return m_parentTheming->getTheme();
145 }
146 return &UCTheme::defaultTheme();
147}
148
149bool UCThemingAttached::setTheme(UCTheme *newTheme)
150{
151 if (m_theme == newTheme) {
152 return false;
153 }
154
155 // preform pre-theme change tasks
156 if (m_listener) {
157 m_listener->preThemeChanged();
158 }
159
160 // disconnect from the previous set
161 UCTheme *connectedSet = m_theme ?
162 m_theme :
163 (!m_parentTheming ? &UCTheme::defaultTheme() : NULL);
164 if (connectedSet) {
165 connectThemeSignals(connectedSet, false);
166 }
167
168 UCTheme *prevSet = m_theme;
169
170 // resolve new theme
171 if (m_theme && newTheme) {
172 // no need to redo the parentStack, simply set the theme and leave
173 m_theme = newTheme;
174 } else {
175 m_theme = newTheme;
176 if (!newTheme) {
177 // redo the parent chanin
178 disconnectTillItem(0);
179 connectParents(0);
180 }
181 }
182
183 // connect to the new set
184 connectedSet = m_theme ?
185 m_theme :
186 (!m_parentTheming ? &UCTheme::defaultTheme() : NULL);
187 if (connectedSet) {
188 connectThemeSignals(connectedSet, true);
189 }
190 // detach previous set and attach the new one
191 if (prevSet) {
192 Q_EMIT prevSet->parentThemeChanged();
193 }
194 if (m_theme) {
195 // re-parent theme to make sure we have it
196 // for the entire lifetime of the styled item
197 m_theme->setParent(parent());
198 Q_EMIT m_theme->parentThemeChanged();
199 }
200
201 // perform post-theme changes, update internal styling
202 if (m_listener) {
203 m_listener->postThemeChanged();
204 }
205
206 Q_EMIT themeChanged();
207 return true;
208}
209
210// lookup for the parent chain theme
211void UCThemingAttached::itemParentChanged()
212{
213 // clean stack
214 disconnectTillItem(0);
215 // make sure we reset parent StyledItem
216 m_parentTheming.clear();
217 // build the stack - if possible
218 connectParents(0);
219 Q_EMIT themeChanged();
220}
221
222// captures ascendant change signal, the sender is the one which counts!
223void UCThemingAttached::ascendantChanged(QQuickItem *ascendant)
224{
225 QQuickItem *sender = static_cast<QQuickItem*>(this->sender());
226 if (!sender) {
227 // cannot detect the sender, leave!
228 return;
229 }
230 if (ascendant) {
231 // disconnect from the previous ones
232 disconnectTillItem(sender);
233 m_parentTheming.clear();
234 // traverse ascendants till we reach a StyledItem or root and push them into the stack
235 if (connectParents(ascendant)) {
236 Q_EMIT themeChanged();
237 }
238 }
239}
240
241// syncs the ascendant styled item's styles
242void UCThemingAttached::parentStyleChanged()
243{
244 // do not trigger themeChanged() on this item if we have a
245 // custom one, but resolve its eventual parent change!
246 if (m_theme) {
247 Q_EMIT m_theme->parentThemeChanged();
248 return;
249 }
250
251 UCThemingAttached *styling = static_cast<UCThemingAttached*>(sender());
252 if (!styling) {
253 return;
254 }
255 setParentStyled(styling);
256 Q_EMIT themeChanged();
257}
0258
=== added file 'src/Ubuntu/Components/plugin/ucthemingattached.h'
--- src/Ubuntu/Components/plugin/ucthemingattached.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/plugin/ucthemingattached.h 2015-08-06 18:06:52 +0000
@@ -0,0 +1,81 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Zsombor Egri <zsombor.egri@canonical.com>
17 */
18
19#ifndef UCTHEMINGATTACHED_H
20#define UCTHEMINGATTACHED_H
21
22#include <QtCore/QObject>
23#include <QtCore/QPointer>
24#include <QtQml>
25
26class UCTheme;
27class QQuickItem;
28
29class UCThemeChangeListener {
30public:
31 virtual void preThemeChanged() = 0;
32 virtual void postThemeChanged() = 0;
33};
34
35class UCThemingAttached : public QObject
36{
37 Q_OBJECT
38public:
39 explicit UCThemingAttached(QObject *parent = 0);
40
41 static UCThemingAttached *qmlAttachedProperties(QObject *owner);
42 static UCThemingAttached *attachTheming(QObject *owner);
43
44 void setListener(UCThemeChangeListener *listener)
45 {
46 m_listener = listener;
47 }
48 UCTheme *getTheme();
49 bool setTheme(UCTheme *theme);
50
51Q_SIGNALS:
52 void themeChanged();
53
54public Q_SLOTS:
55
56 void ascendantChanged(QQuickItem *ascendant);
57 void parentStyleChanged();
58 void itemParentChanged();
59
60protected:
61 friend class UCTheme;
62
63 QStack< QPointer<QQuickItem> > m_parentStack;
64 QPointer<UCThemingAttached> m_parentTheming;
65 UCTheme *m_theme;
66 UCThemeChangeListener *m_listener;
67 QQuickItem *m_ownerItem;
68
69 void connectThemeSignals(UCTheme *theme, bool connect);
70
71 bool connectParents(QQuickItem *fromItem);
72 void disconnectTillItem(QQuickItem *item);
73 bool setParentStyled(UCThemingAttached *newStyling);
74
75};
76QML_DECLARE_TYPEINFO(UCThemingAttached, QML_HAS_ATTACHED_PROPERTIES)
77
78UCThemingAttached *itemTheming(QQuickItem *item);
79
80
81#endif // UCTHEMINGATTACHED_H

Subscribers

People subscribed via source and target branches