ubuntu-sdk-team team mailing list archive
-
ubuntu-sdk-team team
-
Mailing list archive
-
Message #00060
[Merge] lp:~nick-dedekind/ubuntu-ui-toolkit/actionItem-mnemonics into lp:ubuntu-ui-toolkit
Nick Dedekind has proposed merging lp:~nick-dedekind/ubuntu-ui-toolkit/actionItem-mnemonics into lp:ubuntu-ui-toolkit.
Commit message:
Moved Action mnemonic logic to the ActionItem.
Requested reviews:
Ubuntu SDK team (ubuntu-sdk-team)
For more details, see:
https://code.launchpad.net/~nick-dedekind/ubuntu-ui-toolkit/actionItem-mnemonics/+merge/313114
Moved Action mnemonic logic to the ActionItem.
Added ActionItem.mnemonic for altering properties of the mnemonic logic.
--
Your team Ubuntu SDK team is requested to review the proposed merge of lp:~nick-dedekind/ubuntu-ui-toolkit/actionItem-mnemonics into lp:ubuntu-ui-toolkit.
=== modified file '.bazaar/plugins/makecheck_ubuntu_ui_toolkit.py'
--- .bazaar/plugins/makecheck_ubuntu_ui_toolkit.py 2014-07-14 17:34:44 +0000
+++ .bazaar/plugins/makecheck_ubuntu_ui_toolkit.py 2016-12-13 10:43:19 +0000
@@ -35,6 +35,7 @@
if (subprocess.call("make check", shell=True) != 0):
raise errors.BzrError("Tests failed, fix them before commit!")
+
branch.Branch.hooks.install_named_hook('pre_commit',
execute_makecheck,
'make check pre-commit')
=== modified file '.bazaar/plugins/packaging_sorting.py'
--- .bazaar/plugins/packaging_sorting.py 2016-05-16 06:37:48 +0000
+++ .bazaar/plugins/packaging_sorting.py 2016-12-13 10:43:19 +0000
@@ -52,6 +52,7 @@
subprocess.call(["rm", "-rf", "debian-packaging-wraptest-temporary"])
+
branch.Branch.hooks.install_named_hook("pre_commit",
pre_commit_hook,
"Check packaging sorting")
=== modified file 'components.api'
--- components.api 2016-09-17 05:48:25 +0000
+++ components.api 2016-12-13 10:43:19 +0000
@@ -45,13 +45,14 @@
property bool active
function addAction(Action action)
function removeAction(Action action)
-Ubuntu.Components.ActionItem 1.0 0.1 UCActionItem: StyledItem
+Ubuntu.Components.ActionItem 1.3 1.0 0.1 UCActionItem: StyledItem
property Action action
property string iconName
property url iconSource
signal triggered(var value)
function trigger(var value)
function trigger()
+ readonly property ActionMnemonic mnemonic 1.3
property string text
Ubuntu.Components.Styles.ActionItemProperties 1.3: QtObject
property color backgroundColor
@@ -79,6 +80,10 @@
function removeAction(Action action)
function addLocalContext(ActionContext context)
function removeLocalContext(ActionContext context)
+Ubuntu.Components.ActionMnemonic 1.3: QtObject
+ property int modifier
+ readonly property StandardKey sequence
+ property bool visible
Ubuntu.Components.Popups.ActionSelectionPopover 1.0 0.1: Popover
property var actions
property Component delegate
@@ -1597,6 +1602,7 @@
signal triggered(var value)
function trigger(var value)
function trigger()
+ readonly property ActionMnemonic mnemonic
property string text
Ubuntu.Components.ToolbarButton 1.3: StyledItem
property Action action
@@ -1605,6 +1611,7 @@
signal triggered(var value)
function trigger(var value)
function trigger()
+ readonly property ActionMnemonic mnemonic
property string text
Ubuntu.Components.ToolbarItems 1.0 0.1: Item
property Item back
=== modified file 'debian/control'
--- debian/control 2016-08-29 19:49:33 +0000
+++ debian/control 2016-12-13 10:43:19 +0000
@@ -10,6 +10,7 @@
gdb,
language-pack-en-base,
libdbus-1-dev,
+ libevdev-dev,
libfontconfig1-dev,
libfreetype6-dev,
libgl1-mesa-dri,
@@ -21,6 +22,7 @@
libnih-dbus-dev,
libqt5sql5-sqlite,
libqt5svg5-dev,
+ libqt5systeminfo5,
libudev-dev,
libx11-dev[!armhf],
libxcb1-dev[!armhf],
@@ -53,6 +55,7 @@
qtpim5-dev,
qtscript5-doc-html,
qtsvg5-doc-html,
+ qtsystems5-dev,
qttools5-dev-tools,
qtwebkit5-doc-html,
suru-icon-theme (>= 14.04+16.10.20160720),
=== modified file 'debian/control.gles'
--- debian/control.gles 2016-08-18 05:40:55 +0000
+++ debian/control.gles 2016-12-13 10:43:19 +0000
@@ -10,6 +10,7 @@
gdb,
language-pack-en-base,
libdbus-1-dev,
+ libevdev-dev,
libfontconfig1-dev,
libfreetype6-dev,
libgles2-mesa-dev,
@@ -25,6 +26,7 @@
libqt5quickwidgets5-gles,
libqt5sql5-sqlite,
libqt5svg5-dev,
+ libqt5systeminfo5,
libudev-dev,
libx11-dev[!armhf],
libxcb1-dev[!armhf],
@@ -58,6 +60,7 @@
qtpim5-dev,
qtscript5-doc-html,
qtsvg5-doc-html,
+ qtsystems5-dev,
qtwebkit5-doc-html,
suru-icon-theme,
unity-action-doc,
=== modified file 'src/UbuntuToolkit/UbuntuToolkit.pro'
--- src/UbuntuToolkit/UbuntuToolkit.pro 2016-09-12 14:56:56 +0000
+++ src/UbuntuToolkit/UbuntuToolkit.pro 2016-12-13 10:43:19 +0000
@@ -2,6 +2,9 @@
QT = core-private gui-private qml-private quick-private testlib dbus svg organizer \
UbuntuGestures-private UbuntuMetrics
+#Qt SystemInfo
+QT *= systeminfo systeminfo-private
+
unix {
CONFIG += link_pkgconfig
PKGCONFIG += gio-2.0 dbus-1 libnih libnih-dbus
=== modified file 'src/UbuntuToolkit/quickutils.cpp'
--- src/UbuntuToolkit/quickutils.cpp 2016-09-21 08:47:38 +0000
+++ src/UbuntuToolkit/quickutils.cpp 2016-12-13 10:43:19 +0000
@@ -27,6 +27,7 @@
#include <QtQuick/QQuickItem>
#include <QtQuick/private/qquicktextinput_p.h>
#include <QtQuick/private/qquicktextedit_p.h>
+#include <QtSystemInfo/QInputInfoManager>
UT_NAMESPACE_BEGIN
@@ -37,10 +38,100 @@
m_rootWindow(0),
m_rootView(0),
m_mouseAttached(false),
- m_keyboardAttached(false)
+ m_keyboardAttached(false),
+ m_explicitMouseAttached(false),
+ m_explicitKeyboardAttached(false)
{
QGuiApplication::instance()->installEventFilter(this);
m_omitIM << QStringLiteral("ibus") << QStringLiteral("none") << QStringLiteral("compose");
+
+ m_inputInfo = new QInputInfoManager(this);
+ connect(m_inputInfo, &QInputInfoManager::ready,
+ this, &QuickUtils::onInputInfoReady);
+ // the default values of mouse and keyboard attachment depend on the input info
+ connect(m_inputInfo, &QInputInfoManager::deviceAdded,
+ this, &QuickUtils::onDeviceAdded);
+ connect(m_inputInfo, &QInputInfoManager::deviceRemoved,
+ this, &QuickUtils::onDeviceRemoved);
+}
+
+void QuickUtils::onInputInfoReady()
+{
+ QMapIterator<QString, QInputDevice*> i(m_inputInfo->deviceMap());
+ while (i.hasNext()) {
+ i.next();
+ registerDevice(i.value(), i.key());
+ }
+
+ m_inputInfo->setFilter(QInputDevice::Mouse | QInputDevice::TouchPad | QInputDevice::Keyboard);
+}
+
+void QuickUtils::onDeviceAdded(QInputDevice *device)
+{
+ QMapIterator<QString, QInputDevice*> i(m_inputInfo->deviceMap());
+ while (i.hasNext()) {
+ i.next();
+ if (i.value() == device) {
+ registerDevice(device, i.key());
+ break;
+ }
+ }
+}
+
+void QuickUtils::onDeviceRemoved(const QString deviceId)
+{
+ // the device info is removed by now, so we must look at the internal cache
+ if (m_keyboards.remove(deviceId)) {
+ if (!m_explicitKeyboardAttached && !m_keyboards.size()) {
+ m_keyboardAttached = false;
+ Q_EMIT keyboardAttachedChanged();
+ }
+ }
+ if (m_mice.remove(deviceId)) {
+ if (!m_explicitMouseAttached && !m_mice.size()) {
+ m_mouseAttached = false;
+ Q_EMIT mouseAttachedChanged();
+ }
+ }
+}
+
+void QuickUtils::registerDevice(QInputDevice *device, const QString &deviceId)
+{
+ if (device->types().testFlag(QInputDevice::Keyboard)) {
+ m_keyboards.insert(deviceId);
+ if (!m_explicitKeyboardAttached && !m_keyboardAttached) {
+ m_keyboardAttached = true;
+ Q_EMIT keyboardAttachedChanged();
+ }
+ }
+ if (device->types().testFlag(QInputDevice::Mouse)
+ || device->types().testFlag(QInputDevice::TouchPad)) {
+ m_mice.insert(deviceId);
+ if (!m_explicitMouseAttached && !m_mouseAttached) {
+ m_mouseAttached = true;
+ Q_EMIT mouseAttachedChanged();
+ }
+ }
+}
+
+void QuickUtils::setMouseAttached(bool set)
+{
+ m_explicitMouseAttached = true;
+ if (set == m_mouseAttached) {
+ return;
+ }
+ m_mouseAttached = set;
+ Q_EMIT mouseAttachedChanged();
+}
+
+void QuickUtils::setKeyboardAttached(bool set)
+{
+ m_explicitKeyboardAttached = true;
+ if (set == m_keyboardAttached) {
+ return;
+ }
+ m_keyboardAttached = true;
+ Q_EMIT keyboardAttachedChanged();
}
/*!
=== modified file 'src/UbuntuToolkit/quickutils_p.h'
--- src/UbuntuToolkit/quickutils_p.h 2016-09-19 20:40:13 +0000
+++ src/UbuntuToolkit/quickutils_p.h 2016-12-13 10:43:19 +0000
@@ -26,6 +26,8 @@
class QQuickItem;
class QQmlEngine;
class QQmlComponent;
+class QInputInfoManager;
+class QInputDevice;
UT_NAMESPACE_BEGIN
@@ -35,8 +37,8 @@
Q_PROPERTY(QQuickItem *rootObject READ rootObject NOTIFY rootObjectChanged)
Q_PROPERTY(QString inputMethodProvider READ inputMethodProvider)
Q_PROPERTY(bool touchScreenAvailable READ touchScreenAvailable NOTIFY touchScreenAvailableChanged)
- Q_PROPERTY(bool mouseAttached MEMBER m_mouseAttached NOTIFY mouseAttachedChanged)
- Q_PROPERTY(bool keyboardAttached MEMBER m_keyboardAttached NOTIFY keyboardAttachedChanged)
+ Q_PROPERTY(bool mouseAttached MEMBER m_mouseAttached WRITE setMouseAttached NOTIFY mouseAttachedChanged)
+ Q_PROPERTY(bool keyboardAttached MEMBER m_keyboardAttached WRITE setKeyboardAttached NOTIFY keyboardAttachedChanged)
public:
static QuickUtils *instance(QObject *parent = Q_NULLPTR)
{
@@ -87,13 +89,25 @@
explicit QuickUtils(QObject *parent = 0);
QPointer<QQuickWindow> m_rootWindow;
QPointer<QQuickView> m_rootView;
+ QInputInfoManager *m_inputInfo;
QStringList m_omitIM;
- bool m_mouseAttached;
- bool m_keyboardAttached;
+ QSet<QString> m_mice;
+ QSet<QString> m_keyboards;
+ bool m_mouseAttached:1;
+ bool m_keyboardAttached:1;
+ bool m_explicitMouseAttached:1;
+ bool m_explicitKeyboardAttached:1;
static QuickUtils *m_instance;
void lookupQuickView();
+ void registerDevice(QInputDevice *device, const QString &deviceId);
+ void setMouseAttached(bool set);
+ void setKeyboardAttached(bool set);
+private Q_SLOTS:
+ void onInputInfoReady();
+ void onDeviceAdded(QInputDevice *device);
+ void onDeviceRemoved(const QString deviceId);
};
#define UC_QML_DEPRECATION_WARNING(msg) \
=== modified file 'src/UbuntuToolkit/ubuntutoolkitmodule.cpp'
--- src/UbuntuToolkit/ubuntutoolkitmodule.cpp 2016-09-29 10:19:06 +0000
+++ src/UbuntuToolkit/ubuntutoolkitmodule.cpp 2016-12-13 10:43:19 +0000
@@ -398,6 +398,7 @@
qmlRegisterType<UCMainViewBase>(uri, 1, 3, "MainViewBase");
qmlRegisterType<ActionList>(uri, 1, 3, "ActionList");
qmlRegisterType<ExclusiveGroup>(uri, 1, 3, "ExclusiveGroup");
+ qmlRegisterType<UCActionItem, 1>(uri, 1, 3, "ActionItem");
}
void UbuntuToolkitModule::undefineModule()
=== modified file 'src/UbuntuToolkit/ubuntutoolkitmodule.h'
--- src/UbuntuToolkit/ubuntutoolkitmodule.h 2016-09-09 17:49:07 +0000
+++ src/UbuntuToolkit/ubuntutoolkitmodule.h 2016-12-13 10:43:19 +0000
@@ -61,7 +61,7 @@
// use this API only in tests!
static void initializeContextProperties(QQmlEngine*);
private:
- explicit UbuntuToolkitModule(QObject *parent = 0);
+ explicit UbuntuToolkitModule(QObject *parent = Q_NULLPTR);
static UbuntuToolkitModule* create(QQmlEngine *engine, const QUrl &baseUrl);
void registerWindowContextProperty();
Q_SLOT void setWindowContextProperty(QWindow* focusWindow);
=== modified file 'src/UbuntuToolkit/ucaction.cpp'
--- src/UbuntuToolkit/ucaction.cpp 2016-09-20 08:23:40 +0000
+++ src/UbuntuToolkit/ucaction.cpp 2016-12-13 10:43:19 +0000
@@ -138,20 +138,6 @@
*
* Examples: See \l Page
*
- * \section2 Mnemonics
- * Since Ubuntu.Components 1.3 Action supports mnemonics. Mnemonics are shortcuts
- * defined in the \l text property, prefixed the shortcut letter with \&. For instance
- * \c "\&Call" will bint the \c "Alt-C" shortcut to the action. When a mnemonic
- * is detected on the Action and a keyboard is attached to the device, the \l text
- * property will provide a formatted text having the mnemonic letter underscored.
- * \qml
- * Action {
- * id: call
- * iconName: "call"
- * text: "&Call"
- * }
- * \endqml
- *
* \section2 Checkable property
* Since Ubuntu.Components 1.3 Action supports the checkable/checked properties.
* \qml
@@ -191,40 +177,10 @@
/*!
* \qmlproperty string Action::text
* The user visible primary label of the action.
- *
- * Mnemonics are shortcuts prefixed in the text with \&. If the text has multiple
- * occurences of the \& character, the first one will be considered for the shortcut.
- * However \&\& can be used for a single \& in the text, not as a mnemonic.
- * The \& character cannot be used as shortcut.
*/
QString UCAction::text()
{
- QString displayText(m_text);
- // if we have a mnemonic, underscore it
- if (!m_mnemonic.isEmpty()) {
-
- QString mnemonic = "&" + m_mnemonic.toString().remove(QStringLiteral("Alt+"));
- // patch special cases
- mnemonic.replace(QStringLiteral("Space"), QStringLiteral(" "));
- int mnemonicIndex = m_text.indexOf(mnemonic);
- if (mnemonicIndex < 0) {
- // try lower case
- mnemonic = mnemonic.toLower();
- mnemonicIndex = m_text.indexOf(mnemonic);
- }
- ACT_TRACE("MNEM" << mnemonic);
- // FIXME: we need QInputDeviceInfo to detect the keyboard attechment
- // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808
- if (QuickUtils::instance()->keyboardAttached()) {
- // underscore the character
- displayText.replace(mnemonicIndex, mnemonic.length(), "<u>" + mnemonic[1] + "</u>");
- } else {
- displayText.remove(mnemonicIndex, 1);
- }
- }
- // Escape ampersands
- displayText.replace(QStringLiteral("&&"), QStringLiteral("&"));
- return displayText;
+ return m_text;
}
void UCAction::setText(const QString &text)
{
@@ -232,7 +188,6 @@
return;
}
m_text = text;
- setMnemonicFromText(m_text);
Q_EMIT textChanged();
}
void UCAction::resetText()
@@ -240,25 +195,6 @@
setText(QString());
}
-void UCAction::setMnemonicFromText(const QString &text)
-{
- QKeySequence sequence = QKeySequence::mnemonic(text);
- if (sequence == m_mnemonic) {
- return;
- }
- if (!m_mnemonic.isEmpty()) {
- QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(0, this, m_mnemonic);
- }
-
- m_mnemonic = sequence;
-
- if (!m_mnemonic.isEmpty()) {
- ACT_TRACE("MNEMONIC SET" << m_mnemonic.toString());
- Qt::ShortcutContext context = Qt::WindowShortcut;
- QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(this, m_mnemonic, context, shortcutContextMatcher);
- }
-}
-
/*!
* \qmlproperty string Action::keywords
* Additional user visible keywords for the action.
@@ -287,10 +223,6 @@
, m_checked(false)
{
generateName();
- // FIXME: we need QInputDeviceInfo to detect the keyboard attechment
- // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808
- connect(QuickUtils::instance(), &QuickUtils::keyboardAttachedChanged,
- this, &UCAction::onKeyboardAttached);
}
UCAction::~UCAction()
@@ -609,14 +541,6 @@
return true;
}
-// trigger text changes whenever HW keyboad is attached/detached
-void UCAction::onKeyboardAttached()
-{
- if (!m_mnemonic.isEmpty()) {
- Q_EMIT textChanged();
- }
-}
-
/*!
* \qmlmethod Action::trigger(var value)
* Checks the \c value against the action \l parameterType and triggers the action.
=== modified file 'src/UbuntuToolkit/ucaction_p.h'
--- src/UbuntuToolkit/ucaction_p.h 2016-09-09 17:49:07 +0000
+++ src/UbuntuToolkit/ucaction_p.h 2016-12-13 10:43:19 +0000
@@ -32,6 +32,8 @@
UT_NAMESPACE_BEGIN
+Q_DECLARE_LOGGING_CATEGORY(ucAction)
+
// the function detects whether QML has an overridden trigger() slot available
// and invokes the one with the appropriate signature
template<class T>
@@ -185,7 +187,6 @@
void generateName();
void setMnemonicFromText(const QString &text);
bool event(QEvent *event) override;
- void onKeyboardAttached();
};
UT_NAMESPACE_END
=== modified file 'src/UbuntuToolkit/ucactionitem.cpp'
--- src/UbuntuToolkit/ucactionitem.cpp 2016-09-12 09:03:50 +0000
+++ src/UbuntuToolkit/ucactionitem.cpp 2016-12-13 10:43:19 +0000
@@ -15,16 +15,65 @@
*/
#include "ucactionitem_p_p.h"
-
-#define foreach Q_FOREACH
-#include <QtQml/private/qqmlbinding_p.h>
-#undef foreach
-
#include "ucaction_p.h"
+#include "ucactioncontext_p.h"
#include "ucstyleditembase_p_p.h"
+#include "quickutils_p.h"
+
+#include <QtQuick/qquickwindow.h>
+#include <private/qguiapplication_p.h>
UT_NAMESPACE_BEGIN
+#define ACT_TRACE(params) qCDebug(ucAction) << params
+
+bool itemShortcutContextMatcher(QObject* object, Qt::ShortcutContext context)
+{
+ UCActionItem* actionItem = static_cast<UCActionItem*>(object);
+ UCAction* action = actionItem->action();
+ if (!action || !action->isEnabled()) {
+ return false;
+ }
+
+ switch (context) {
+ case Qt::ApplicationShortcut:
+ return true;
+ case Qt::WindowShortcut: {
+ QObject* window = actionItem->window();
+ bool activatable = window && window == QGuiApplication::focusWindow();
+
+ if (activatable) {
+ QQuickItem *pl = actionItem;
+ activatable = false;
+ while (pl) {
+ UCActionContextAttached *attached = static_cast<UCActionContextAttached*>(
+ qmlAttachedPropertiesObject<UCActionContext>(pl, false));
+ if (attached) {
+ activatable = attached->context()->active();
+ if (!activatable) {
+ ACT_TRACE(action << "Inactive context found" << attached->context());
+ break;
+ }
+ }
+ pl = pl->parentItem();
+ }
+ if (!activatable) {
+ // check if the action is in an active context
+ UCActionContext *context = qobject_cast<UCActionContext*>(action->parent());
+ activatable = context && context->active();
+ }
+ }
+ if (activatable) {
+ ACT_TRACE("SELECTED ACTION" << action);
+ }
+
+ return activatable;
+ }
+ default: break;
+ }
+ return false;
+}
+
UCActionItemPrivate::UCActionItemPrivate()
: action(Q_NULLPTR)
, flags(0)
@@ -36,6 +85,9 @@
Q_Q(UCActionItem);
QObject::connect(q, &UCActionItem::enabledChanged, q, &UCActionItem::enabledChanged2);
QObject::connect(q, &UCActionItem::visibleChanged, q, &UCActionItem::visibleChanged2);
+
+ QObject::connect(&mnemonic, SIGNAL(visibleChanged()), q, SLOT(_q_textBinding()));
+ QObject::connect(&mnemonic, SIGNAL(modifierChanged()), q, SLOT(_q_updateMnemonic()));
}
/*!
@@ -50,6 +102,20 @@
* If \l action is set, the values of the other properties will by default
* be identical to the \l Action's property values. Setting the other properties
* will override the properties copied from the \l Action.
+ *
+ * \section2 Mnemonics
+ * Since Ubuntu.Components 1.3 ActionItem supports mnemonics. Mnemonics are shortcuts
+ * defined in the \l text property, prefixed the shortcut letter with \&. For instance
+ * \c "\&Call" will bint the \c "Alt-C" shortcut to the action. When a mnemonic
+ * is detected on the ActionItem and a keyboard is attached to the device, the \l text
+ * property will provide a formatted text having the mnemonic letter underscored.
+ * \qml
+ * ActionItem {
+ * id: call
+ * iconName: "call"
+ * text: "&Call"
+ * }
+ * \endqml
*/
/*!
@@ -60,6 +126,11 @@
: UCStyledItemBase(*(new UCActionItemPrivate), parent)
{
d_func()->init();
+
+ // FIXME: we need QInputDeviceInfo to detect the keyboard attechment
+ // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808
+ connect(QuickUtils::instance(), SIGNAL(keyboardAttachedChanged()),
+ this, SLOT(_q_onKeyboardAttached()), Qt::DirectConnection);
}
UCActionItem::UCActionItem(UCActionItemPrivate &dd, QQuickItem *parent)
@@ -68,6 +139,29 @@
d_func()->init();
}
+bool UCActionItem::event(QEvent *e)
+{
+ Q_D(UCActionItem);
+ if (e->type() == QEvent::Shortcut) {
+ if (!d->action) {
+ return false;
+ }
+
+ // when we reach this point, we can be sure the Action is used
+ // by a component belonging to an active ActionContext.
+ QShortcutEvent *shortcut_event(static_cast<QShortcutEvent*>(e));
+ if (shortcut_event->isAmbiguous()) {
+ qmlInfo(this) << "Ambiguous shortcut: " << shortcut_event->key().toString();
+ return false;
+ }
+
+ // do not call trigger() directly but invoke, as it may get overridden in QML
+ invokeTrigger<UCAction>(d->action, QVariant());
+ return true;
+ }
+ return UCStyledItemBase::event(e);
+}
+
bool UCActionItemPrivate::hasBindingOnProperty(const QString &name)
{
Q_Q(UCActionItem);
@@ -109,6 +203,52 @@
invokeTrigger<UCAction>(action, value);
}
+// update the text property
+void UCActionItemPrivate::_q_textBinding()
+{
+ if (flags & CustomText) {
+ return;
+ }
+ _q_updateMnemonic();
+ Q_EMIT q_func()->textChanged();
+}
+
+// trigger text changes whenever HW keyboad is attached/detached
+void UCActionItemPrivate::_q_onKeyboardAttached()
+{
+ if (!mnemonic.sequence().isEmpty()) {
+ Q_EMIT q_func()->textChanged();
+ }
+}
+
+void UCActionItemPrivate::_q_updateMnemonic()
+{
+ Q_Q(UCActionItem);
+ if (!action) return;
+
+ const QString displayText = action ? action->text() : QString();
+
+ QKeySequence sequence = QKeySequence::mnemonic(displayText);
+ if (!sequence.isEmpty()) {
+ sequence = sequence[0] & ~Qt::ALT;
+ sequence = sequence[0] | mnemonic.modifier();
+ }
+
+ if (sequence == mnemonic.sequence()) {
+ return;
+ }
+ if (!mnemonic.sequence().isEmpty()) {
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(0, q, mnemonic.sequence());
+ }
+
+ mnemonic.setSequence(sequence);
+
+ if (!sequence.isEmpty()) {
+ Qt::ShortcutContext context = Qt::WindowShortcut;
+ QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(q, sequence, context, itemShortcutContextMatcher);
+ }
+}
+
// setter called when bindings from QML set the value. Internal functions will
// all use the setVisible setter, so initialization and (re)parenting related
// visible alteration won't set the custom flag
@@ -124,12 +264,15 @@
setEnabled(enabled);
}
+UCActionMnemonic *UCActionItem::mnemonic()
+{
+ Q_D(UCActionItem);
+ return &d->mnemonic;
+}
+
void UCActionItemPrivate::updateProperties()
{
Q_Q(UCActionItem);
- if (!(flags & CustomText)) {
- Q_EMIT q->textChanged();
- }
if (!(flags & CustomIconSource)) {
Q_EMIT q->iconSourceChanged();
}
@@ -154,8 +297,8 @@
q, SLOT(_q_enabledBinding()), Qt::DirectConnection);
}
if (!(flags & CustomText)) {
- QObject::connect(action, &UCAction::textChanged,
- q, &UCActionItem::textChanged, Qt::DirectConnection);
+ QObject::connect(action, SIGNAL(textChanged()),
+ q, SLOT(_q_textBinding()), Qt::DirectConnection);
}
if (!(flags & CustomIconSource)) {
QObject::connect(action, &UCAction::iconSourceChanged,
@@ -178,8 +321,8 @@
q, SLOT(_q_enabledBinding()));
}
if (!(flags & CustomText)) {
- QObject::disconnect(action, &UCAction::textChanged,
- q, &UCActionItem::textChanged);
+ QObject::disconnect(action, SIGNAL(textChanged()),
+ q, SLOT(_q_textBinding()));
}
if (!(flags & CustomIconSource)) {
QObject::disconnect(action, &UCAction::iconSourceChanged,
@@ -189,6 +332,11 @@
QObject::disconnect(action, &UCAction::iconNameChanged,
q, &UCActionItem::iconNameChanged);
}
+
+ if (!mnemonic.sequence().isEmpty()) {
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(0, q, mnemonic.sequence());
+ mnemonic.setSequence(QKeySequence());
+ }
}
}
@@ -220,20 +368,59 @@
}
d->_q_visibleBinding();
d->_q_enabledBinding();
+ d->_q_textBinding();
d->updateProperties();
}
/*!
* \qmlproperty string ActionItem::text
* The title of the actionItem. Defaults to the \c action.text.
- */
+ *
+ * Mnemonics are shortcuts prefixed in the text with \&. If the text has multiple
+ * occurences of the \& character, the first one will be considered for the shortcut.
+ * However \&\& can be used for a single \& in the text, not as a mnemonic.
+ * The \& character cannot be used as shortcut.
+ */ */
QString UCActionItem::text()
{
Q_D(UCActionItem);
if (d->flags & UCActionItemPrivate::CustomText) {
return d->text;
}
- return d->action ? d->action->text() : QString();
+
+ if (!d->action) {
+ return QString();
+ }
+
+ QString displayText(d->action->text());
+
+ // if we have a mnemonic, underscore it
+ if (!d->mnemonic.sequence().isEmpty()) {
+ const QString modifier = QKeySequence(d->mnemonic.modifier()).toString();
+
+ QString mnemonic = "&" + d->mnemonic.sequence().toString().remove(modifier);
+ // patch special cases
+ mnemonic.replace(QStringLiteral("Space"), QStringLiteral(" "));
+ int mnemonicIndex = displayText.indexOf(mnemonic);
+ if (mnemonicIndex < 0) {
+ // try lower case
+ mnemonic = mnemonic.toLower();
+ mnemonicIndex = displayText.indexOf(mnemonic);
+ }
+
+ // FIXME: we need QInputDeviceInfo to detect the keyboard attechment
+ // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1276808
+ if (d->mnemonic.visible() && QuickUtils::instance()->keyboardAttached()) {
+ // underscore the character
+ displayText.replace(mnemonicIndex, mnemonic.length(), "<u>" + mnemonic[1] + "</u>");
+ } else {
+ displayText.remove(mnemonicIndex, 1);
+ }
+ }
+
+ // Escape ampersands
+ displayText.replace(QStringLiteral("&&"), QStringLiteral("&"));
+ return displayText;
}
void UCActionItem::setText(const QString &text)
{
@@ -241,8 +428,8 @@
if (d->action && !(d->flags & UCActionItemPrivate::CustomText)) {
// disconnect change signal from Action
- disconnect(d->action, &UCAction::textChanged,
- this, &UCActionItem::textChanged);
+ disconnect(d->action, SIGNAL(textChanged()),
+ this, SLOT(_q_textBinding()));
}
d->flags |= UCActionItemPrivate::CustomText;
@@ -259,8 +446,8 @@
d->flags &= ~UCActionItemPrivate::CustomText;
if (d->action) {
// re-connect change signal from Action
- connect(d->action, &UCAction::textChanged,
- this, &UCActionItem::textChanged, Qt::DirectConnection);
+ connect(d->action, SIGNAL(textChanged()),
+ this, SLOT(_q_textBinding()), Qt::DirectConnection);
}
Q_EMIT textChanged();
}
@@ -382,6 +569,52 @@
}
}
+UCActionMnemonic::UCActionMnemonic(QObject *parent)
+ : QObject(parent)
+ , m_visible(true)
+ , m_modifier(Qt::ALT)
+{
+}
+
+bool UCActionMnemonic::visible() const
+{
+ return m_visible;
+}
+
+void UCActionMnemonic::setVisible(bool visible)
+{
+ if (visible != m_visible) {
+ m_visible = visible;
+ Q_EMIT visibleChanged();
+ }
+}
+
+int UCActionMnemonic::modifier() const
+{
+ return m_modifier;
+}
+
+void UCActionMnemonic::setModifier(int modifier)
+{
+ if (modifier != m_modifier) {
+ m_modifier = modifier;
+ Q_EMIT modifierChanged();
+ }
+}
+
+const QKeySequence& UCActionMnemonic::sequence() const
+{
+ return m_sequence;
+}
+
+void UCActionMnemonic::setSequence(const QKeySequence &sequence)
+{
+ if (m_sequence != sequence) {
+ m_sequence = sequence;
+ Q_EMIT sequenceChanged();
+ }
+}
+
UT_NAMESPACE_END
#include "moc_ucactionitem_p.cpp"
=== modified file 'src/UbuntuToolkit/ucactionitem_p.h'
--- src/UbuntuToolkit/ucactionitem_p.h 2016-09-09 17:49:07 +0000
+++ src/UbuntuToolkit/ucactionitem_p.h 2016-12-13 10:43:19 +0000
@@ -23,6 +23,7 @@
class UCAction;
class UCActionItemPrivate;
+class UCActionMnemonic;
class UBUNTUTOOLKIT_EXPORT UCActionItem : public UCStyledItemBase
{
Q_OBJECT
@@ -35,6 +36,13 @@
Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource RESET resetIconSource NOTIFY iconSourceChanged)
Q_PROPERTY(QString iconName READ iconName WRITE setIconName RESET resetIconName NOTIFY iconNameChanged)
+ // 1.3
+#ifndef Q_QDOC
+ Q_PROPERTY(UT_PREPEND_NAMESPACE(UCActionMnemonic) *mnemonic READ mnemonic CONSTANT FINAL REVISION 1)
+#else
+ Q_PROPERTY(UCActionMnemonic *mnemonic READ mnemonic CONSTANT FINAL REVISION 1)
+#endif
+
// overrides
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled2 NOTIFY enabledChanged2)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible2 NOTIFY visibleChanged2 FINAL)
@@ -56,6 +64,8 @@
void setVisible2(bool visible);
void setEnabled2(bool enabled);
+ UCActionMnemonic* mnemonic();
+
Q_SIGNALS:
void actionChanged();
void textChanged();
@@ -72,10 +82,44 @@
protected:
UCActionItem(UCActionItemPrivate &, QQuickItem *parent);
+ bool event(QEvent *event) override;
+
Q_DECLARE_PRIVATE(UCActionItem)
Q_PRIVATE_SLOT(d_func(), void _q_visibleBinding())
Q_PRIVATE_SLOT(d_func(), void _q_enabledBinding())
Q_PRIVATE_SLOT(d_func(), void _q_invokeActionTrigger(const QVariant &value))
+ Q_PRIVATE_SLOT(d_func(), void _q_textBinding())
+ Q_PRIVATE_SLOT(d_func(), void _q_onKeyboardAttached())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateMnemonic())
+};
+
+class UBUNTUTOOLKIT_EXPORT UCActionMnemonic : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(int modifier READ modifier WRITE setModifier NOTIFY modifierChanged)
+ Q_PROPERTY(QKeySequence sequence READ sequence NOTIFY sequenceChanged)
+public:
+ UCActionMnemonic(QObject* parent = 0);
+
+ bool visible() const;
+ void setVisible(bool visible);
+
+ int modifier() const;
+ void setModifier(int modifier);
+
+ const QKeySequence& sequence() const;
+ void setSequence(const QKeySequence& sequence);
+
+Q_SIGNALS:
+ void visibleChanged();
+ void modifierChanged();
+ void sequenceChanged();
+
+private:
+ bool m_visible;
+ int m_modifier;
+ QKeySequence m_sequence;
};
UT_NAMESPACE_END
=== modified file 'src/UbuntuToolkit/ucactionitem_p_p.h'
--- src/UbuntuToolkit/ucactionitem_p_p.h 2016-09-09 17:49:07 +0000
+++ src/UbuntuToolkit/ucactionitem_p_p.h 2016-12-13 10:43:19 +0000
@@ -45,6 +45,9 @@
void _q_visibleBinding();
void _q_enabledBinding();
void _q_invokeActionTrigger(const QVariant &value);
+ void _q_textBinding();
+ void _q_onKeyboardAttached();
+ void _q_updateMnemonic();
enum {
CustomText = 0x01,
@@ -58,6 +61,7 @@
QUrl iconSource;
UCAction *action;
quint8 flags;
+ UCActionMnemonic mnemonic;
};
UT_NAMESPACE_END
=== modified file 'src/UbuntuToolkit/ucthemingextension.cpp'
--- src/UbuntuToolkit/ucthemingextension.cpp 2016-09-12 14:07:38 +0000
+++ src/UbuntuToolkit/ucthemingextension.cpp 2016-12-13 10:43:19 +0000
@@ -95,7 +95,25 @@
UCItemAttached::~UCItemAttached()
{
- QQuickItemPrivate::get(m_item)->removeItemChangeListener(this, QQuickItemPrivate::Parent);
+ /*
+ * Apparent problem: the UCItemAttached for a given item may be
+ * destructed along with the user data for that item, which
+ * occurs after the QQuickItemPrivate destructor has run, in the
+ * destructor for the base class QObjectPrivate of
+ * QQuickItemPrivate. At that point, the destructors of the
+ * members of QQuickItemPrivate have already been called, so
+ * accessing those members via a member function is invalid.
+ * In particular, the changeListeners list of the
+ * QQuickItemPrivate has already been destructed, so it does
+ * not have much of a chance of removing a listener. We
+ * must detect this and avoid the call to it. Fortunately
+ * the base class QObjectPrivate has a flag wasDeleted that
+ * should still be valid at this point.
+ */
+ QQuickItemPrivate* itemPriv = QQuickItemPrivate::get(m_item);
+ if (!(itemPriv->wasDeleted)) {
+ itemPriv->removeItemChangeListener(this, QQuickItemPrivate::Parent);
+ }
}
bool UCThemingExtension::isThemed(QQuickItem *item)
=== modified file 'src/imports/Components/1.3/TextArea.qml'
--- src/imports/Components/1.3/TextArea.qml 2016-09-19 07:24:45 +0000
+++ src/imports/Components/1.3/TextArea.qml 2016-12-13 10:43:19 +0000
@@ -767,7 +767,12 @@
QtObject {
id: internal
// public property locals enabling aliasing
- property string displayText: editor.getText(0, editor.length)
+ property string displayText: {
+ var plainText = editor.getText(0, editor.length);
+ if (editor.hasOwnProperty('preeditText'))
+ plainText += editor.preeditText;
+ return plainText;
+ }
property real frameSpacing: control.__styleInstance.frameSpacing
property real minimumSize: units.gu(4)
property real scrollbarSpacing: rightScrollbar.__interactive ? units.gu(2) : 0
=== modified file 'src/imports/Components/Themes/Ambiance/1.2/SliderStyle.qml'
--- src/imports/Components/Themes/Ambiance/1.2/SliderStyle.qml 2015-04-24 14:43:08 +0000
+++ src/imports/Components/Themes/Ambiance/1.2/SliderStyle.qml 2016-12-13 10:43:19 +0000
@@ -48,7 +48,7 @@
overlayColor: sliderStyle.foregroundColor
overlayRect: Qt.application.layoutDirection == Qt.LeftToRight ?
Qt.rect(0.0, 0.0, thumb.x / thumb.barMinusThumbWidth, 1.0) :
- Qt.rect(1.0 - (thumb.x / thumb.barMinusThumbWidth), 0.0, 1.0, 1.0)
+ Qt.rect(thumb.x / thumb.barMinusThumbWidth, 0.0, 1 - (thumb.x / thumb.barMinusThumbWidth), 1.0)
}
UbuntuShape {
=== modified file 'src/imports/Components/Themes/Ambiance/1.3/AmbianceNormal.qml'
--- src/imports/Components/Themes/Ambiance/1.3/AmbianceNormal.qml 2016-05-17 13:00:51 +0000
+++ src/imports/Components/Themes/Ambiance/1.3/AmbianceNormal.qml 2016-12-13 10:43:19 +0000
@@ -21,10 +21,10 @@
PaletteValues {
background: "#FFFFFF"
backgroundText: UbuntuColors.jet
- backgroundSecondaryText: UbuntuColors.slate
- backgroundTertiaryText: UbuntuColors.ash
+ backgroundSecondaryText: UbuntuColors.inkstone
+ backgroundTertiaryText: UbuntuColors.graphite
base: UbuntuColors.silk
- baseText: UbuntuColors.graphite
+ baseText: UbuntuColors.inkstone
foreground: UbuntuColors.porcelain
foregroundText: UbuntuColors.jet
raised: "#FFFFFF"
@@ -35,7 +35,7 @@
overlaySecondaryText: UbuntuColors.silk
field: "#FFFFFF"
fieldText: UbuntuColors.jet
- focus: UbuntuColors.orange
+ focus: UbuntuColors.blue
focusText: "#FFFFFF"
selection: Qt.rgba(UbuntuColors.blue.r, UbuntuColors.blue.g, UbuntuColors.blue.b, 0.2)
selectionText: UbuntuColors.jet
=== modified file 'src/imports/Components/Themes/Ambiance/1.3/AmbianceSelected.qml'
--- src/imports/Components/Themes/Ambiance/1.3/AmbianceSelected.qml 2016-04-29 12:22:02 +0000
+++ src/imports/Components/Themes/Ambiance/1.3/AmbianceSelected.qml 2016-12-13 10:43:19 +0000
@@ -20,7 +20,7 @@
AmbianceNormal {
background: UbuntuColors.porcelain
base: UbuntuColors.ash
- baseText: UbuntuColors.inkstone
+ baseText: UbuntuColors.jet
foreground: UbuntuColors.ash
overlay: UbuntuColors.porcelain
}
=== modified file 'src/imports/Components/Themes/Ambiance/1.3/Palette.qml'
--- src/imports/Components/Themes/Ambiance/1.3/Palette.qml 2016-05-17 13:00:51 +0000
+++ src/imports/Components/Themes/Ambiance/1.3/Palette.qml 2016-12-13 10:43:19 +0000
@@ -25,19 +25,19 @@
Component.onCompleted: {
// specific disabled colors
var diff = {
- field: UbuntuColors.porcelain,
selection: Qt.rgba(UbuntuColors.blue.r, UbuntuColors.blue.g, UbuntuColors.blue.b, 0.1),
positiveText: "#FFFFFF",
negativeText: "#FFFFFF",
activityText: "#FFFFFF",
- focusText: "#FFFFFF"
+ focusText: "#FFFFFF",
+ position: "#00000000"
};
for (var p in normal) {
// skip objectName and all change signals
if (p === "objectName" || p.indexOf("Changed") > 0) continue;
disabled[p] = diff[p] || (
- // if not specific, colors are 30% opaque normal
- Qt.rgba(normal[p].r, normal[p].g, normal[p].b, normal[p].a * 0.5)
+ // if not specific, colors are 40% opaque normal
+ Qt.rgba(normal[p].r, normal[p].g, normal[p].b, normal[p].a * 0.4)
);
}
}
@@ -51,21 +51,22 @@
Component.onCompleted: {
// specific selected-disabled colors
var diff = {
- background: UbuntuColors.porcelain,
- base: UbuntuColors.porcelain,
foreground: UbuntuColors.porcelain,
selection: Qt.rgba(UbuntuColors.blue.r, UbuntuColors.blue.g, UbuntuColors.blue.b, 0.1),
positiveText: "#FFFFFF",
negativeText: "#FFFFFF",
activityText: "#FFFFFF",
- focusText: "#FFFFFF"
+ focus: UbuntuColors.blue,
+ focusText: "#FFFFFF",
+ field: "#FFFFFF",
+ position: "#00000000"
};
for (var p in selected) {
// skip objectName and all change signals
if (p === "objectName" || p.indexOf("Changed") > 0) continue;
selectedDisabled[p] = diff[p] || (
- // if not specific, colors are 30% opaque normal
- Qt.rgba(selected[p].r, selected[p].g, selected[p].b, normal[p].a * 0.5)
+ // if not specific, colors are 40% opaque normal
+ Qt.rgba(selected[p].r, selected[p].g, selected[p].b, normal[p].a * 0.4)
);
}
}
@@ -74,7 +75,7 @@
highlighted: AmbianceNormal {
background: UbuntuColors.silk
base: UbuntuColors.ash
- baseText: UbuntuColors.inkstone
+ baseText: UbuntuColors.jet
foreground: UbuntuColors.silk
raised: UbuntuColors.silk
raisedText: UbuntuColors.inkstone
=== modified file 'src/imports/Components/Themes/Ambiance/1.3/SliderStyle.qml'
--- src/imports/Components/Themes/Ambiance/1.3/SliderStyle.qml 2016-02-10 17:46:21 +0000
+++ src/imports/Components/Themes/Ambiance/1.3/SliderStyle.qml 2016-12-13 10:43:19 +0000
@@ -49,7 +49,7 @@
overlayColor: sliderStyle.foregroundColor
overlayRect: Qt.application.layoutDirection == Qt.LeftToRight ?
Qt.rect(0.0, 0.0, thumb.x / thumb.barMinusThumbWidth, 1.0) :
- Qt.rect(1.0 - (thumb.x / thumb.barMinusThumbWidth), 0.0, 1.0, 1.0)
+ Qt.rect(thumb.x / thumb.barMinusThumbWidth, 0.0, 1 - (thumb.x / thumb.barMinusThumbWidth), 1.0)
}
UbuntuShape {
=== modified file 'src/imports/Components/Themes/SuruDark/1.3/Palette.qml'
--- src/imports/Components/Themes/SuruDark/1.3/Palette.qml 2016-05-17 13:00:51 +0000
+++ src/imports/Components/Themes/SuruDark/1.3/Palette.qml 2016-12-13 10:43:19 +0000
@@ -25,19 +25,19 @@
Component.onCompleted: {
// specific disabled colors
var diff = {
- foreground: UbuntuColors.inkstone,
- field: UbuntuColors.inkstone,
+ raised: "#FFFFFF",
positiveText: UbuntuColors.porcelain,
negativeText: UbuntuColors.porcelain,
activityText: UbuntuColors.porcelain,
- focusText: UbuntuColors.porcelain
+ focusText: "#FFFFFF",
+ selectionText: "#FFFFFF"
};
for (var p in normal) {
// skip objectName and all change signals
if (p == "objectName"|| p.indexOf("Changed") > 0) continue;
disabled[p] = diff[p] || (
- // if not specific, colors are 30% opaque normal
- Qt.rgba(normal[p].r, normal[p].g, normal[p].b, normal[p].a * 0.5)
+ // if not specific, colors are 40% opaque normal
+ Qt.rgba(normal[p].r, normal[p].g, normal[p].b, normal[p].a * 0.4)
);
}
}
@@ -51,12 +51,17 @@
Component.onCompleted: {
var diff = {
background: UbuntuColors.inkstone,
- base: UbuntuColors.inkstone,
- foreground: UbuntuColors.inkstone,
+ backgroundText: "#FFFFFF",
+ raised: "#FFFFFF",
+ foregroundText: "#FFFFFF",
+ overlayText: "#FFFFFF",
+ fieldText: "#FFFFFF",
+ selectionText: "#FFFFFF",
positiveText: UbuntuColors.porcelain,
negativeText: UbuntuColors.porcelain,
- activityText: UbuntuColors.porcelain,
- focusText: UbuntuColors.porcelain
+ activityText: UbuntuColors.porcelain,
+ focusText: UbuntuColors.porcelain,
+ position: "#00000000"
};
for (var p in selected) {
// skip objectName and all change signals
=== modified file 'src/imports/Components/Themes/SuruDark/1.3/SuruDarkNormal.qml'
--- src/imports/Components/Themes/SuruDark/1.3/SuruDarkNormal.qml 2016-05-17 13:00:51 +0000
+++ src/imports/Components/Themes/SuruDark/1.3/SuruDarkNormal.qml 2016-12-13 10:43:19 +0000
@@ -24,7 +24,7 @@
backgroundSecondaryText: UbuntuColors.silk
backgroundTertiaryText: UbuntuColors.ash
base: UbuntuColors.graphite
- baseText: UbuntuColors.silk
+ baseText: UbuntuColors.porcelain
foreground: UbuntuColors.inkstone
foregroundText: "#FFFFFF"
raised: "#FFFFFF"
@@ -35,7 +35,7 @@
overlaySecondaryText: UbuntuColors.slate
field: UbuntuColors.jet
fieldText: "#FFFFFF"
- focus: UbuntuColors.orange
+ focus: UbuntuColors.blue
focusText: "#FFFFFF"
selection: Qt.rgba(UbuntuColors.blue.r, UbuntuColors.blue.g, UbuntuColors.blue.b, 0.4)
selectionText: "#FFFFFF"
=== modified file 'src/imports/Components/Themes/SuruDark/1.3/SuruDarkSelected.qml'
--- src/imports/Components/Themes/SuruDark/1.3/SuruDarkSelected.qml 2016-04-29 12:22:02 +0000
+++ src/imports/Components/Themes/SuruDark/1.3/SuruDarkSelected.qml 2016-12-13 10:43:19 +0000
@@ -20,8 +20,8 @@
SuruDarkNormal {
background: UbuntuColors.inkstone
- base: UbuntuColors.inkstone
- baseText: UbuntuColors.ash
+ base: UbuntuColors.slate
+ baseText: UbuntuColors.silk
foreground: UbuntuColors.slate
overlay: UbuntuColors.slate
}
=== modified file 'tests/unit/test-include-x11.pri'
--- tests/unit/test-include-x11.pri 2016-07-07 15:33:34 +0000
+++ tests/unit/test-include-x11.pri 2016-12-13 10:43:19 +0000
@@ -3,5 +3,5 @@
include( add_makecheck_x11.pri )
TEMPLATE = app
-QT += testlib qml quick UbuntuToolkit UbuntuToolkit-private
+QT += testlib qml quick systeminfo UbuntuToolkit UbuntuToolkit-private
CONFIG += no_keywords c++11
=== modified file 'tests/unit/test-include.pri'
--- tests/unit/test-include.pri 2016-09-09 17:49:07 +0000
+++ tests/unit/test-include.pri 2016-12-13 10:43:19 +0000
@@ -2,5 +2,5 @@
include( add_makecheck.pri )
TEMPLATE = app
-QT += testlib qml quick UbuntuToolkit-private
+QT += testlib qml quick systeminfo UbuntuToolkit-private
CONFIG += no_keywords c++11
=== modified file 'tests/unit/visual/tst_actionitem.11.qml'
--- tests/unit/visual/tst_actionitem.11.qml 2016-06-15 13:46:51 +0000
+++ tests/unit/visual/tst_actionitem.11.qml 2016-12-13 10:43:19 +0000
@@ -16,7 +16,7 @@
import QtQuick 2.0
import QtTest 1.0
-import Ubuntu.Components 1.1
+import Ubuntu.Components 1.3
Item {
id: main
@@ -58,6 +58,7 @@
Action {
id: action2
objectName: "action2"
+ text: "&mnemonicActionText"
}
Loader {
@@ -86,6 +87,7 @@
function cleanup() {
loader.sourceComponent = null;
item1.action = null;
+ item1.text = undefined;
action1.visible = true;
action1.enabled = true;
action2.visible = true;
@@ -116,6 +118,12 @@
compare(item1.text, "", "text can be unset")
}
+ function test_action_mnemonic() {
+ QuickUtils.keyboardAttached = true;
+ item1.action = action2;
+ compare(item1.text, "<u>m</u>nemonicActionText", "Text uses action text mnemonics");
+ }
+
// NOTE: This test must be run AFTER test_action(), otherwise setting the action will
// will not update the iconSource
function test_iconSource() {
=== removed file 'tests/unit/visual/tst_pickerpanel.11.qml'
--- tests/unit/visual/tst_pickerpanel.11.qml 2016-06-15 13:46:51 +0000
+++ tests/unit/visual/tst_pickerpanel.11.qml 1970-01-01 00:00:00 +0000
@@ -1,249 +0,0 @@
-/*
- * Copyright 2013 Canonical Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-import QtQuick 2.0
-import QtTest 1.0
-import Ubuntu.Test 1.0
-import Ubuntu.Components 1.1
-import Ubuntu.Components.Pickers 1.0
-
-Item {
- id: testSuite
- width: units.gu(40)
- height: units.gu(71)
-
- Flow {
- anchors {
- fill: parent
- // give a margin so we can dismiss panels
- topMargin: units.gu(4)
- }
-
- Button {
- id: defaultMode
- text: "defaultMode"
- property date buttonDate: new Date()
- property Item panel
- onClicked: panel = PickerPanel.openDatePicker(defaultMode, "buttonDate")
- }
- Button {
- id: modeSet
- text: "modeSet"
- property string mode
- property date buttonDate: new Date()
- property Item panel
- onClicked: panel = PickerPanel.openDatePicker(modeSet, "buttonDate", mode)
- }
- }
-
- SignalSpy {
- id: closeSpy
- signalName: "closed"
- }
-
- UbuntuTestCase {
- name: "PickerPanelAPI"
- when: windowShown
-
- function initTestCase() {
- waitForRendering(testSuite);
- }
-
- function test_0_clickOndefaultMode() {
- mouseClick(defaultMode, units.gu(1), units.gu(1));
- verify(defaultMode.panel !== null, "the picker is not opened");
- verify(defaultMode.panel.picker !== null, "the DatePicker is not defined");
- compare(defaultMode.panel.pickerMode, "Years|Months|Days", "the mode from the picker is not the default");
- compare(defaultMode.panel.date, defaultMode.buttonDate, "the date from the picker differs from the button's");
- compare(defaultMode.panel.caller, defaultMode, "wrong caller");
- compare(defaultMode.panel.callerProperty, "buttonDate", "wrong callerProperty");
- verify(defaultMode.panel.hasOwnProperty("closed"), "the object has no closed signal");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = defaultMode.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- function test_1_modeSet_YM() {
- modeSet.mode = "Years|Months" ;
- mouseClick(modeSet, units.gu(1), units.gu(1));
- verify(modeSet.panel !== null, "the picker is opened");
- compare(modeSet.panel.date, modeSet.buttonDate, "the date from the picker differs from the button's");
- compare(modeSet.panel.pickerMode, modeSet.mode, "the mode from the picker differs from the button's");
- // check the number of pickers
- var picker = findChild(modeSet.panel.picker, "PickerRow_Positioner");
- compare(picker.children.length, 3, "there is not enough pickers in the panel");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = modeSet.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- function test_1_modeSet_YD() {
- ignoreWarning("Invalid DatePicker mode: Years|Days")
- modeSet.mode = "Years|Days" ;
- mouseClick(modeSet, units.gu(1), units.gu(1));
- verify(modeSet.panel !== null, "the picker is opened");
- compare(modeSet.panel.date, modeSet.buttonDate, "the date from the picker differs from the button's");
- compare(modeSet.panel.pickerMode, modeSet.mode, "the mode from the picker differs from the button's");
- // check the number of pickers
- var picker = findChild(modeSet.panel.picker, "PickerRow_Positioner");
- expectFailContinue("", "this mode is invalid");
- compare(picker.children.length, 2, "there is not enough pickers in the panel");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = modeSet.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- function test_1_modeSet_HMS() {
- modeSet.mode = "Hours|Minutes|Seconds" ;
- mouseClick(modeSet, units.gu(1), units.gu(1));
- verify(modeSet.panel !== null, "the picker is opened");
- compare(modeSet.panel.date, modeSet.buttonDate, "the date from the picker differs from the button's");
- compare(modeSet.panel.pickerMode, modeSet.mode, "the mode from the picker differs from the button's");
- // check the number of pickers
- var picker = findChild(modeSet.panel.picker, "PickerRow_Positioner");
- compare(picker.children.length, 4, "there is not enough pickers in the panel");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = modeSet.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- function test_1_modeSet_HS() {
- ignoreWarning("Invalid DatePicker mode: Hours|Seconds")
- modeSet.mode = "Hours|Seconds" ;
- mouseClick(modeSet, units.gu(1), units.gu(1));
- verify(modeSet.panel !== null, "the picker is opened");
- compare(modeSet.panel.date, modeSet.buttonDate, "the date from the picker differs from the button's");
- compare(modeSet.panel.pickerMode, modeSet.mode, "the mode from the picker differs from the button's");
- // check the number of pickers
- var picker = findChild(modeSet.panel.picker, "PickerRow_Positioner");
- expectFailContinue("", "this mode is invalid");
- compare(picker.children.length, 2, "there is not enough pickers in the panel");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = modeSet.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- // forced panel tests
- // these should be executed as last ones
- function test_2_clickOndefaultMode() {
- // force panel - this is private specific!!!
- var privates = findChild(PickerPanel, "PickerPanel_Internals");
- privates.isPhone = true;
-
- mouseClick(defaultMode, units.gu(1), units.gu(1));
- verify(defaultMode.panel !== null, "the picker is not opened");
- verify(defaultMode.panel.picker !== null, "the DatePicker is not defined");
- compare(defaultMode.panel.pickerMode, "Years|Months|Days", "the mode from the picker is not the default");
- compare(defaultMode.panel.date, defaultMode.buttonDate, "the date from the picker differs from the button's");
- compare(defaultMode.panel.caller, defaultMode, "wrong caller");
- compare(defaultMode.panel.callerProperty, "buttonDate", "wrong callerProperty");
- verify(defaultMode.panel.hasOwnProperty("closed"), "the object has no closed signal");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = defaultMode.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- function test_3_modeSet_YM() {
- modeSet.mode = "Years|Months" ;
- mouseClick(modeSet, units.gu(1), units.gu(1));
- verify(modeSet.panel !== null, "the picker is opened");
- compare(modeSet.panel.date, modeSet.buttonDate, "the date from the picker differs from the button's");
- compare(modeSet.panel.pickerMode, modeSet.mode, "the mode from the picker differs from the button's");
- // check the number of pickers
- var picker = findChild(modeSet.panel.picker, "PickerRow_Positioner");
- compare(picker.children.length, 3, "there is not enough pickers in the panel");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = modeSet.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- function test_3_modeSet_YD() {
- ignoreWarning("Invalid DatePicker mode: Years|Days")
- modeSet.mode = "Years|Days" ;
- mouseClick(modeSet, units.gu(1), units.gu(1));
- verify(modeSet.panel !== null, "the picker is opened");
- compare(modeSet.panel.date, modeSet.buttonDate, "the date from the picker differs from the button's");
- compare(modeSet.panel.pickerMode, modeSet.mode, "the mode from the picker differs from the button's");
- // check the number of pickers
- var picker = findChild(modeSet.panel.picker, "PickerRow_Positioner");
- expectFailContinue("", "this mode is invalid");
- compare(picker.children.length, 2, "there is not enough pickers in the panel");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = modeSet.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- function test_3_modeSet_HMS() {
- modeSet.mode = "Hours|Minutes|Seconds" ;
- mouseClick(modeSet, units.gu(1), units.gu(1));
- verify(modeSet.panel !== null, "the picker is opened");
- compare(modeSet.panel.date, modeSet.buttonDate, "the date from the picker differs from the button's");
- compare(modeSet.panel.pickerMode, modeSet.mode, "the mode from the picker differs from the button's");
- // check the number of pickers
- var picker = findChild(modeSet.panel.picker, "PickerRow_Positioner");
- compare(picker.children.length, 4, "there is not enough pickers in the panel");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = modeSet.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
-
- function test_3_modeSet_HS() {
- ignoreWarning("Invalid DatePicker mode: Hours|Seconds")
- modeSet.mode = "Hours|Seconds" ;
- mouseClick(modeSet, units.gu(1), units.gu(1));
- verify(modeSet.panel !== null, "the picker is opened");
- compare(modeSet.panel.date, modeSet.buttonDate, "the date from the picker differs from the button's");
- compare(modeSet.panel.pickerMode, modeSet.mode, "the mode from the picker differs from the button's");
- // check the number of pickers
- var picker = findChild(modeSet.panel.picker, "PickerRow_Positioner");
- expectFailContinue("", "this mode is invalid");
- compare(picker.children.length, 2, "there is not enough pickers in the panel");
-
- // dismiss
- closeSpy.clear();
- closeSpy.target = modeSet.panel;
- mouseClick(testSuite, units.gu(1), units.gu(1));
- closeSpy.wait();
- }
- }
-}
=== modified file 'tests/unit/visual/tst_slider.13.qml'
--- tests/unit/visual/tst_slider.13.qml 2016-06-15 13:46:51 +0000
+++ tests/unit/visual/tst_slider.13.qml 2016-12-13 10:43:19 +0000
@@ -89,6 +89,14 @@
}
}
}
+ Slider {
+ property bool enableRTL: false
+ LayoutMirroring.enabled: enableRTL
+ LayoutMirroring.childrenInherit: enableRTL
+
+ id: slider
+ readonly property rect bar: slider.__styleInstance && slider.__styleInstance.bar ? slider.__styleInstance.bar.overlayRect : null
+ }
}
UbuntuTestCase {
@@ -107,6 +115,7 @@
function cleanup() {
flickSpy.target = null;
flickSpy.clear();
+ slider.enableRTL = false;
}
function test_slider_blocks_flickable_data() {
@@ -160,5 +169,21 @@
valueSpy.wait();
compare(slider.value, to, "Slider has the wrong value!");
}
+
+ function test_bar_rtl() {
+ verify(slider.bar);
+ slider.minimumValue = 0.0;
+ slider.maximumValue = 1.0;
+ slider.value = 0.3;
+
+ // check for LTR
+ print("Slider width:", slider.bar.width)
+ verify(slider.value >= slider.bar.width)
+
+ // check for RTL
+ slider.enableRTL = true;
+ print("Slider RTL width:", slider.bar.width)
+ verify(slider.value >= slider.bar.width)
+ }
}
}
=== renamed file 'tests/unit/visual/FIXME-QT56_textarea.11.qml' => 'tests/unit/visual/tst_textarea.11.qml'
--- tests/unit/visual/FIXME-QT56_textarea.11.qml 2016-09-16 11:20:57 +0000
+++ tests/unit/visual/tst_textarea.11.qml 2016-12-13 10:43:19 +0000
@@ -137,11 +137,6 @@
compare(textArea.canUndo,textEdit.canUndo,"TextArea.canUndo is same as TextEdit.canUndo")
}
- // FIXME: Fails with Qt 5.6. See bug #1624342.
- function test_0_color() {
- compare(textArea.color,textEdit.color,"TextArea.color is same as TextEdit.canUndo")
- }
-
function test_0_cursorDelegate() {
verify(textArea.cursorDelegate === null, "TextArea.cursorDelegate is not null")
}
@@ -220,14 +215,6 @@
compare(textArea.selectedText,textEdit.selectedText,"TextArea.selectedText is same as TextEdit.selectedText")
}
- function test_0_selectedTextColor() {
- compare(textArea.selectedTextColor,textEdit.selectedTextColor,"TextArea.selectedTextColor is same as TextEdit.selectedTextColor")
- }
-
- function test_0_selectionColor() {
- compare(textArea.selectionColor,textEdit.selectionColor,"TextArea.selectionColor is same as TextEdit.selectionColor")
- }
-
function test_0_selectionEnd() {
compare(textArea.selectionEnd,textEdit.selectionEnd,"TextArea.selectionEnd is same as TextEdit.selectionEnd")
}