Merge lp:~osomon/webbrowser-app/qquickshortcuts into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 1391
Merged at revision: 1407
Proposed branch: lp:~osomon/webbrowser-app/qquickshortcuts
Merge into: lp:webbrowser-app
Diff against target: 1198 lines (+666/-337)
12 files modified
src/app/CMakeLists.txt (+3/-1)
src/app/FilteredKeyboardModel.qml (+33/-0)
src/app/browserapplication.cpp (+2/-0)
src/app/qquickshortcut.cpp (+283/-0)
src/app/qquickshortcut_p.h (+109/-0)
src/app/webbrowser/Browser.qml (+200/-258)
src/app/webbrowser/KeyboardShortcut.qml (+0/-25)
src/app/webbrowser/KeyboardShortcuts.qml (+0/-41)
src/app/webbrowser/ListViewHighlight.qml (+2/-3)
src/app/webbrowser/NavigationBar.qml (+10/-7)
tests/autopilot/webbrowser_app/tests/test_keyboard.py (+22/-1)
tests/autopilot/webbrowser_app/tests/test_private.py (+2/-1)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/qquickshortcuts
Reviewer Review Type Date Requested Status
system-apps-ci-bot continuous-integration Needs Fixing
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+290299@code.launchpad.net

Commit message

Import QQuickShortcut from Qt 5.5 to properly handle window-level keyboard shortcuts.
We cannot bump the dependency on Qt to 5.5 as the stable overlay PPA for devices currently has Qt 5.4.1.

To post a comment you must log in.
1389. By Olivier Tilloy

Remove an incorrect condition now that the QInputInfo API is available.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1390. By Olivier Tilloy

Fix failing autopilot test.

1391. By Olivier Tilloy

Filter out autopilot-emulated keyboards.

Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
1392. By Olivier Tilloy

Do not change focus unnecessarily when switching tabs: clear the address bar instead if needed.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/app/CMakeLists.txt'
--- src/app/CMakeLists.txt 2016-02-09 21:19:41 +0000
+++ src/app/CMakeLists.txt 2016-04-08 16:47:47 +0000
@@ -27,13 +27,15 @@
27 session-storage.cpp27 session-storage.cpp
28 single-instance-manager.cpp28 single-instance-manager.cpp
29 webbrowser-window.cpp29 webbrowser-window.cpp
30 qquickshortcut.cpp
30)31)
3132
32add_library(${COMMONLIB} STATIC ${COMMONLIB_SRC})33add_library(${COMMONLIB} STATIC ${COMMONLIB_SRC})
3334
34include_directories(${unity8_SOURCE_DIR}/libs/UbuntuGestures35include_directories(${unity8_SOURCE_DIR}/libs/UbuntuGestures
35 ${unity8_SOURCE_DIR}/plugins36 ${unity8_SOURCE_DIR}/plugins
36 ${LIBAPPARMOR_INCLUDE_DIRS})37 ${LIBAPPARMOR_INCLUDE_DIRS}
38 ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
37target_link_libraries(${COMMONLIB}39target_link_libraries(${COMMONLIB}
38 Qt5::Core40 Qt5::Core
39 Qt5::Gui41 Qt5::Gui
4042
=== added file 'src/app/FilteredKeyboardModel.qml'
--- src/app/FilteredKeyboardModel.qml 1970-01-01 00:00:00 +0000
+++ src/app/FilteredKeyboardModel.qml 2016-04-08 16:47:47 +0000
@@ -0,0 +1,33 @@
1/*
2 * Copyright 2016 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.4
20import Ubuntu.Components 1.3
21import Unity.InputInfo 0.1
22
23SortFilterModel {
24 model: InputDeviceModel {
25 deviceFilter: InputInfo.Keyboard
26 }
27 filter {
28 // Filter out autopilot-emulated keyboards
29 // (see https://launchpad.net/bugs/1542224).
30 property: "name"
31 pattern: /^(?!py-evdev-uinput).*$/
32 }
33}
034
=== modified file 'src/app/browserapplication.cpp'
--- src/app/browserapplication.cpp 2016-02-09 22:03:25 +0000
+++ src/app/browserapplication.cpp 2016-04-08 16:47:47 +0000
@@ -38,6 +38,7 @@
38#include "favicon-fetcher.h"38#include "favicon-fetcher.h"
39#include "meminfo.h"39#include "meminfo.h"
40#include "mime-database.h"40#include "mime-database.h"
41#include "qquickshortcut_p.h"
41#include "session-storage.h"42#include "session-storage.h"
42#include "webbrowser-window.h"43#include "webbrowser-window.h"
4344
@@ -179,6 +180,7 @@
179 qmlRegisterSingletonType<MemInfo>(uri, 0, 1, "MemInfo", MemInfo_singleton_factory);180 qmlRegisterSingletonType<MemInfo>(uri, 0, 1, "MemInfo", MemInfo_singleton_factory);
180 qmlRegisterSingletonType<MimeDatabase>(uri, 0, 1, "MimeDatabase", MimeDatabase_singleton_factory);181 qmlRegisterSingletonType<MimeDatabase>(uri, 0, 1, "MimeDatabase", MimeDatabase_singleton_factory);
181 qmlRegisterType<SessionStorage>(uri, 0, 1, "SessionStorage");182 qmlRegisterType<SessionStorage>(uri, 0, 1, "SessionStorage");
183 qmlRegisterType<QQuickShortcut>(uri, 0, 1, "Shortcut");
182184
183 const char* gesturesUri = "Ubuntu.Gestures";185 const char* gesturesUri = "Ubuntu.Gestures";
184 qmlRegisterSingletonType<Direction>(gesturesUri, 0, 1, "Direction", Direction_singleton_factory);186 qmlRegisterSingletonType<Direction>(gesturesUri, 0, 1, "Direction", Direction_singleton_factory);
185187
=== added file 'src/app/qquickshortcut.cpp'
--- src/app/qquickshortcut.cpp 1970-01-01 00:00:00 +0000
+++ src/app/qquickshortcut.cpp 2016-04-08 16:47:47 +0000
@@ -0,0 +1,283 @@
1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#include "qquickshortcut_p.h"
35
36#include <QtQuick/qquickitem.h>
37#include <QtQuick/qquickwindow.h>
38#include <QtGui/private/qguiapplication_p.h>
39
40QT_BEGIN_NAMESPACE
41
42/*!
43 \qmltype Shortcut
44 \instantiates QQuickShortcut
45 \inqmlmodule QtQuick
46 \since 5.5
47 \ingroup qtquick-input
48 \brief Provides keyboard shortcuts
49
50 The Shortcut type provides a way of handling keyboard shortcuts. The shortcut can
51 be set to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts},
52 or it can be described with a string containing a sequence of up to four key
53 presses that are needed to \l{Shortcut::activated}{activate} the shortcut.
54
55 \qml
56 Item {
57 id: view
58
59 property int currentIndex
60
61 Shortcut {
62 sequence: StandardKey.NextChild
63 onActivated: view.currentIndex++
64 }
65 }
66 \endqml
67
68 \sa Keys
69*/
70
71/*! \qmlsignal QtQuick::Shortcut::activated()
72
73 This signal is emitted when the shortcut is activated.
74
75 The corresponding handler is \c onActivated.
76*/
77
78/*! \qmlsignal QtQuick::Shortcut::activatedAmbiguously()
79
80 This signal is emitted when the shortcut is activated ambigously,
81 meaning that it matches the start of more than one shortcut.
82
83 The corresponding handler is \c onActivatedAmbiguously.
84*/
85
86QQuickShortcut::QQuickShortcut(QObject *parent) : QObject(parent), m_id(0),
87 m_enabled(true), m_completed(false), m_autorepeat(true), m_context(Qt::WindowShortcut)
88{
89}
90
91QQuickShortcut::~QQuickShortcut()
92{
93 ungrabShortcut();
94}
95
96/*!
97 \qmlproperty keysequence QtQuick::Shortcut::sequence
98
99 This property holds the shortcut's key sequence. The key sequence can be set
100 to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, or
101 it can be described with a string containing a sequence of up to four key
102 presses that are needed to \l{Shortcut::activated}{activate} the shortcut.
103
104 The default value is an empty key sequence.
105
106 \qml
107 Shortcut {
108 sequence: "Ctrl+E,Ctrl+W"
109 onActivated: edit.wrapMode = TextEdit.Wrap
110 }
111 \endqml
112*/
113QVariant QQuickShortcut::sequence() const
114{
115 return m_sequence;
116}
117
118void QQuickShortcut::setSequence(const QVariant &sequence)
119{
120 if (sequence == m_sequence)
121 return;
122
123 QKeySequence shortcut;
124 if (sequence.type() == QVariant::Int)
125 shortcut = QKeySequence(static_cast<QKeySequence::StandardKey>(sequence.toInt()));
126 else
127 shortcut = QKeySequence::fromString(sequence.toString());
128
129 grabShortcut(shortcut, m_context);
130
131 m_sequence = sequence;
132 m_shortcut = shortcut;
133 emit sequenceChanged();
134}
135
136/*!
137 \qmlproperty bool QtQuick::Shortcut::enabled
138
139 This property holds whether the shortcut is enabled.
140
141 The default value is \c true.
142*/
143bool QQuickShortcut::isEnabled() const
144{
145 return m_enabled;
146}
147
148void QQuickShortcut::setEnabled(bool enabled)
149{
150 if (enabled == m_enabled)
151 return;
152
153 if (m_id)
154 QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enabled, m_id, this);
155
156 m_enabled = enabled;
157 emit enabledChanged();
158}
159
160/*!
161 \qmlproperty bool QtQuick::Shortcut::autoRepeat
162
163 This property holds whether the shortcut can auto repeat.
164
165 The default value is \c true.
166*/
167bool QQuickShortcut::autoRepeat() const
168{
169 return m_autorepeat;
170}
171
172void QQuickShortcut::setAutoRepeat(bool repeat)
173{
174 if (repeat == m_autorepeat)
175 return;
176
177 if (m_id)
178 QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(repeat, m_id, this);
179
180 m_autorepeat = repeat;
181 emit autoRepeatChanged();
182}
183
184/*!
185 \qmlproperty enumeration QtQuick::Shortcut::context
186
187 This property holds the \l{Qt::ShortcutContext}{shortcut context}.
188
189 Supported values are:
190 \list
191 \li \c Qt.WindowShortcut (default) - The shortcut is active when its parent item is in an active top-level window.
192 \li \c Qt.ApplicationShortcut - The shortcut is active when one of the application's windows are active.
193 \endlist
194
195 \qml
196 Shortcut {
197 sequence: StandardKey.Quit
198 context: Qt.ApplicationShortcut
199 onActivated: Qt.quit()
200 }
201 \endqml
202*/
203Qt::ShortcutContext QQuickShortcut::context() const
204{
205 return m_context;
206}
207
208void QQuickShortcut::setContext(Qt::ShortcutContext context)
209{
210 if (context == m_context)
211 return;
212
213 grabShortcut(m_shortcut, context);
214
215 m_context = context;
216 emit contextChanged();
217}
218
219void QQuickShortcut::classBegin()
220{
221}
222
223void QQuickShortcut::componentComplete()
224{
225 m_completed = true;
226 grabShortcut(m_shortcut, m_context);
227}
228
229bool QQuickShortcut::event(QEvent *event)
230{
231 if (m_enabled && event->type() == QEvent::Shortcut) {
232 QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
233 if (se->shortcutId() == m_id && se->key() == m_shortcut){
234 if (se->isAmbiguous())
235 emit activatedAmbiguously();
236 else
237 emit activated();
238 return true;
239 }
240 }
241 return false;
242}
243
244static bool qQuickShortcutContextMatcher(QObject *obj, Qt::ShortcutContext context)
245{
246 switch (context) {
247 case Qt::ApplicationShortcut:
248 return true;
249 case Qt::WindowShortcut:
250 while (obj && !obj->isWindowType()) {
251 obj = obj->parent();
252 if (QQuickItem *item = qobject_cast<QQuickItem *>(obj))
253 obj = item->window();
254 }
255 return obj && obj == QGuiApplication::focusWindow();
256 default:
257 return false;
258 }
259}
260
261void QQuickShortcut::grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context)
262{
263 ungrabShortcut();
264
265 if (m_completed && !sequence.isEmpty()) {
266 QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
267 m_id = pApp->shortcutMap.addShortcut(this, sequence, context, qQuickShortcutContextMatcher);
268 if (!m_enabled)
269 pApp->shortcutMap.setShortcutEnabled(false, m_id, this);
270 if (!m_autorepeat)
271 pApp->shortcutMap.setShortcutAutoRepeat(false, m_id, this);
272 }
273}
274
275void QQuickShortcut::ungrabShortcut()
276{
277 if (m_id) {
278 QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_id, this);
279 m_id = 0;
280 }
281}
282
283QT_END_NAMESPACE
0284
=== added file 'src/app/qquickshortcut_p.h'
--- src/app/qquickshortcut_p.h 1970-01-01 00:00:00 +0000
+++ src/app/qquickshortcut_p.h 2016-04-08 16:47:47 +0000
@@ -0,0 +1,109 @@
1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34#ifndef QQUICKSHORTCUT_P_H
35#define QQUICKSHORTCUT_P_H
36
37//
38// W A R N I N G
39// -------------
40//
41// This file is not part of the Qt API. It exists purely as an
42// implementation detail. This header file may change from version to
43// version without notice, or even be removed.
44//
45// We mean it.
46//
47
48#include <QtCore/qobject.h>
49#include <QtCore/qvariant.h>
50#include <QtGui/qkeysequence.h>
51#include <QtQml/qqmlparserstatus.h>
52
53QT_BEGIN_NAMESPACE
54
55class QQuickShortcut : public QObject, public QQmlParserStatus
56{
57 Q_OBJECT
58 Q_INTERFACES(QQmlParserStatus)
59 Q_PROPERTY(QVariant sequence READ sequence WRITE setSequence NOTIFY sequenceChanged FINAL)
60 Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
61 Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL)
62 Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext NOTIFY contextChanged FINAL)
63
64public:
65 explicit QQuickShortcut(QObject *parent = Q_NULLPTR);
66 ~QQuickShortcut();
67
68 QVariant sequence() const;
69 void setSequence(const QVariant &sequence);
70
71 bool isEnabled() const;
72 void setEnabled(bool enabled);
73
74 bool autoRepeat() const;
75 void setAutoRepeat(bool repeat);
76
77 Qt::ShortcutContext context() const;
78 void setContext(Qt::ShortcutContext context);
79
80Q_SIGNALS:
81 void sequenceChanged();
82 void enabledChanged();
83 void autoRepeatChanged();
84 void contextChanged();
85
86 void activated();
87 void activatedAmbiguously();
88
89protected:
90 void classBegin() Q_DECL_OVERRIDE;
91 void componentComplete() Q_DECL_OVERRIDE;
92 bool event(QEvent *event) Q_DECL_OVERRIDE;
93
94 void grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context);
95 void ungrabShortcut();
96
97private:
98 int m_id;
99 bool m_enabled;
100 bool m_completed;
101 bool m_autorepeat;
102 QKeySequence m_shortcut;
103 Qt::ShortcutContext m_context;
104 QVariant m_sequence;
105};
106
107QT_END_NAMESPACE
108
109#endif // QQUICKSHORTCUT_P_H
0110
=== modified file 'src/app/webbrowser/Browser.qml'
--- src/app/webbrowser/Browser.qml 2016-03-07 18:44:34 +0000
+++ src/app/webbrowser/Browser.qml 2016-04-08 16:47:47 +0000
@@ -63,21 +63,6 @@
63 }63 }
6464
65 Connections {65 Connections {
66 target: tabsModel
67 onCurrentIndexChanged: {
68 // Remove focus from the address bar when the current tab
69 // changes to ensure that its contents are updated.
70 contentsContainer.forceActiveFocus()
71
72 // In narrow mode, the tabslist is a stack:
73 // the current tab is always at the top.
74 if (!browser.wide) {
75 tabsModel.move(tabsModel.currentIndex, 0)
76 }
77 }
78 }
79
80 Connections {
81 target: currentWebview66 target: currentWebview
8267
83 /* Note that we are connecting the mediaAccessPermissionRequested signal68 /* Note that we are connecting the mediaAccessPermissionRequested signal
@@ -111,6 +96,10 @@
111 deviceFilter: InputInfo.TouchScreen96 deviceFilter: InputInfo.TouchScreen
112 }97 }
11398
99 FilteredKeyboardModel {
100 id: keyboardModel
101 }
102
114 Component {103 Component {
115 id: mediaAccessDialogComponent104 id: mediaAccessDialogComponent
116 MediaAccessDialog { }105 MediaAccessDialog { }
@@ -1425,21 +1414,12 @@
1425 Component {1414 Component {
1426 id: bookmarkOptionsComponent1415 id: bookmarkOptionsComponent
1427 BookmarkOptions {1416 BookmarkOptions {
1428 id: bookmarkOptions
1429 folderModel: BookmarksFolderListModel {1417 folderModel: BookmarksFolderListModel {
1430 sourceModel: BookmarksModel1418 sourceModel: BookmarksModel
1431 }1419 }
14321420
1433 Component.onCompleted: {1421 Component.onCompleted: forceActiveFocus()
1434 forceActiveFocus()
1435 }
14361422
1437 // Fragile workaround for https://launchpad.net/bugs/1546677.
1438 // By destroying the popover, its visibility isn’t changed to
1439 // false, and thus the bookmark is not removed.
1440 function closeAndConfirm() {
1441 destroy()
1442 }
1443 onVisibleChanged: {1423 onVisibleChanged: {
1444 if (!visible) {1424 if (!visible) {
1445 BookmarksModel.remove(bookmarkUrl)1425 BookmarksModel.remove(bookmarkUrl)
@@ -1452,28 +1432,11 @@
1452 }1432 }
1453 }1433 }
14541434
1455 Keys.onPressed: {1435 // Fragile workaround for https://launchpad.net/bugs/1546677.
1456 if (bookmarkOptionsShortcuts.processKey(event.key, event.modifiers)) {1436 // By destroying the popover, its visibility isn’t changed to
1457 event.accepted = true1437 // false, and thus the bookmark is not removed.
1458 }1438 Keys.onEnterPressed: destroy()
1459 }1439 Keys.onReturnPressed: destroy()
1460
1461 KeyboardShortcuts {
1462 id: bookmarkOptionsShortcuts
1463 KeyboardShortcut {
1464 key: Qt.Key_Return
1465 onTriggered: closeAndConfirm()
1466 }
1467
1468 KeyboardShortcut {
1469 modifiers: Qt.ControlModifier
1470 key: Qt.Key_D
1471 onTriggered: {
1472 BookmarksModel.remove(bookmarkUrl)
1473 closeAndConfirm()
1474 }
1475 }
1476 }
1477 }1440 }
1478 }1441 }
14791442
@@ -1627,16 +1590,7 @@
1627 }1590 }
16281591
1629 function maybeFocusAddressBar() {1592 function maybeFocusAddressBar() {
1630 // XXX: this is not the right condition, but it is better than1593 if (keyboardModel.count > 0) {
1631 // inferring a "desktop" form factor from various heuristics.
1632 // The real fix is to detect whether there is a physical keyboard
1633 // connected, for which there is currently no API yet (there will
1634 // be a QInputInfo API in a future version of Qt).
1635 // Wide mode might be in use on a device without a physical
1636 // keyboard (e.g. a 10" tablet), and conversely the browser window
1637 // might be shrinked to a narrow layout on a desktop setup with a
1638 // physical keyboard and no OSK.
1639 if (browser.wide) {
1640 focusAddressBar()1594 focusAddressBar()
1641 } else {1595 } else {
1642 contentsContainer.forceActiveFocus()1596 contentsContainer.forceActiveFocus()
@@ -1682,14 +1636,14 @@
1682 }1636 }
1683 }1637 }
16841638
1639 property var currentBookmarkOptionsDialog: null
1685 function addBookmark(url, title, icon, location) {1640 function addBookmark(url, title, icon, location) {
1686 if (title == "") title = UrlUtils.removeScheme(url)1641 if (title == "") title = UrlUtils.removeScheme(url)
1687 BookmarksModel.add(url, title, icon, "")1642 BookmarksModel.add(url, title, icon, "")
1688 if (location === undefined) location = chrome.bookmarkTogglePlaceHolder1643 if (location === undefined) location = chrome.bookmarkTogglePlaceHolder
1689 PopupUtils.open(bookmarkOptionsComponent,1644 var properties = {"bookmarkUrl": url, "bookmarkTitle": title}
1690 location,1645 currentBookmarkOptionsDialog = PopupUtils.open(bookmarkOptionsComponent,
1691 {"bookmarkUrl": url,1646 location, properties)
1692 "bookmarkTitle": title})
1693 }1647 }
1694 }1648 }
16951649
@@ -1926,6 +1880,13 @@
19261880
1927 Connections {1881 Connections {
1928 target: tabsModel1882 target: tabsModel
1883 onCurrentIndexChanged: {
1884 // In narrow mode, the tabslist is a stack:
1885 // the current tab is always at the top.
1886 if (!browser.wide) {
1887 tabsModel.move(tabsModel.currentIndex, 0)
1888 }
1889 }
1929 onCurrentTabChanged: {1890 onCurrentTabChanged: {
1930 chrome.findInPageMode = false1891 chrome.findInPageMode = false
1931 var tab = tabsModel.currentTab1892 var tab = tabsModel.currentTab
@@ -1972,206 +1933,187 @@
1972 }1933 }
1973 }1934 }
19741935
1975 Keys.onPressed: if (shortcuts.processKey(event.key, event.modifiers)) event.accepted = true1936 // TODO: internationalize non-standard key sequences?
1976 KeyboardShortcuts {1937
1977 id: shortcuts1938 // Ctrl+Tab or Ctrl+PageDown: cycle through open tabs
19781939 Shortcut {
1979 // Ctrl+Tab or Ctrl+PageDown: cycle through open tabs1940 sequence: StandardKey.NextChild
1980 KeyboardShortcut {1941 enabled: tabContainer.visible || recentView.visible
1981 modifiers: Qt.ControlModifier1942 onActivated: internal.switchToNextTab()
1982 key: Qt.Key_Tab1943 }
1983 enabled: tabContainer.visible || recentView.visible1944 Shortcut {
1984 onTriggered: internal.switchToNextTab()1945 sequence: "Ctrl+PgDown"
1985 }1946 enabled: tabContainer.visible || recentView.visible
1986 KeyboardShortcut {1947 onActivated: internal.switchToNextTab()
1987 modifiers: Qt.ControlModifier1948 }
1988 key: Qt.Key_PageDown1949
1989 enabled: tabContainer.visible || recentView.visible1950 // Ctrl+Shift+Tab or Ctrl+PageUp: cycle through open tabs in reverse order
1990 onTriggered: internal.switchToNextTab()1951 Shortcut {
1991 }1952 sequence: StandardKey.PreviousChild
19921953 enabled: tabContainer.visible || recentView.visible
1993 // Ctrl+Shift+Tab or Ctrl+PageUp: cycle through open tabs in reverse order1954 onActivated: internal.switchToPreviousTab()
1994 KeyboardShortcut {1955 }
1995 modifiers: Qt.ControlModifier1956 Shortcut {
1996 key: Qt.Key_Backtab1957 sequence: "Ctrl+Shift+Tab"
1997 enabled: tabContainer.visible || recentView.visible1958 enabled: tabContainer.visible || recentView.visible
1998 onTriggered: internal.switchToPreviousTab()1959 onActivated: internal.switchToPreviousTab()
1999 }1960 }
2000 KeyboardShortcut {1961 Shortcut {
2001 modifiers: Qt.ControlModifier1962 sequence: "Ctrl+PgUp"
2002 key: Qt.Key_PageUp1963 enabled: tabContainer.visible || recentView.visible
2003 enabled: tabContainer.visible || recentView.visible1964 onActivated: internal.switchToPreviousTab()
2004 onTriggered: internal.switchToPreviousTab()1965 }
2005 }1966
20061967 // Ctrl+W or Ctrl+F4: Close the current tab
2007 // Ctrl+Shift+W or Ctrl+Shift+T: Undo close tab1968 Shortcut {
2008 KeyboardShortcut {1969 sequence: StandardKey.Close
2009 modifiers: Qt.ControlModifier | Qt.ShiftModifier1970 enabled: tabContainer.visible || recentView.visible
2010 key: Qt.Key_W1971 onActivated: internal.closeCurrentTab()
2011 enabled: tabContainer.visible || recentView.visible1972 }
2012 onTriggered: internal.undoCloseTab()1973 Shortcut {
2013 }1974 sequence: "Ctrl+F4"
20141975 enabled: tabContainer.visible || recentView.visible
2015 KeyboardShortcut {1976 onActivated: internal.closeCurrentTab()
2016 modifiers: Qt.ControlModifier | Qt.ShiftModifier1977 }
2017 key: Qt.Key_T1978
2018 enabled: tabContainer.visible || recentView.visible1979 // Ctrl+Shift+W or Ctrl+Shift+T: Undo close tab
2019 onTriggered: internal.undoCloseTab()1980 Shortcut {
2020 }1981 sequence: "Ctrl+Shift+W"
20211982 enabled: tabContainer.visible || recentView.visible
2022 // Ctrl+W or Ctrl+F4: Close the current tab1983 onActivated: internal.undoCloseTab()
2023 KeyboardShortcut {1984 }
2024 modifiers: Qt.ControlModifier1985 Shortcut {
2025 key: Qt.Key_W1986 sequence: "Ctrl+Shift+T"
2026 enabled: tabContainer.visible || recentView.visible1987 enabled: tabContainer.visible || recentView.visible
2027 onTriggered: internal.closeCurrentTab()1988 onActivated: internal.undoCloseTab()
2028 }1989 }
2029 KeyboardShortcut {1990
2030 modifiers: Qt.ControlModifier1991 // Ctrl+T: Open a new Tab
2031 key: Qt.Key_F41992 Shortcut {
2032 enabled: tabContainer.visible || recentView.visible1993 sequence: StandardKey.AddTab
2033 onTriggered: internal.closeCurrentTab()1994 enabled: tabContainer.visible || recentView.visible ||
2034 }1995 bookmarksViewLoader.active || historyViewLoader.active
20351996 onActivated: {
2036 // Ctrl+T: Open a new Tab1997 openUrlInNewTab("", true)
2037 KeyboardShortcut {1998 if (recentView.visible) recentView.reset()
2038 modifiers: Qt.ControlModifier1999 bookmarksViewLoader.active = false
2039 key: Qt.Key_T2000 historyViewLoader.active = false
2040 enabled: tabContainer.visible || recentView.visible ||2001 }
2041 bookmarksViewLoader.active || historyViewLoader.active2002 }
2042 onTriggered: {2003
2043 openUrlInNewTab("", true)2004 // F6 or Ctrl+L or Alt+D: Select the content in the address bar
2044 if (recentView.visible) recentView.reset()2005 Shortcut {
2045 bookmarksViewLoader.active = false2006 sequence: "F6"
2046 historyViewLoader.active = false2007 enabled: tabContainer.visible
2047 }2008 onActivated: internal.focusAddressBar(true)
2048 }2009 }
20492010 Shortcut {
2050 // F6 or Ctrl+L or Alt+D: Select the content in the address bar2011 sequence: "Ctrl+L"
2051 KeyboardShortcut {2012 enabled: tabContainer.visible
2052 modifiers: Qt.ControlModifier2013 onActivated: internal.focusAddressBar(true)
2053 key: Qt.Key_L2014 }
2054 enabled: tabContainer.visible2015 Shortcut {
2055 onTriggered: internal.focusAddressBar(true)2016 sequence: "Alt+D"
2056 }2017 enabled: tabContainer.visible
2057 KeyboardShortcut {2018 onActivated: internal.focusAddressBar(true)
2058 modifiers: Qt.AltModifier2019 }
2059 key: Qt.Key_D2020
2060 enabled: tabContainer.visible2021 // Ctrl+D: Toggle bookmarked state on current Tab
2061 onTriggered: internal.focusAddressBar(true)2022 Shortcut {
2062 }2023 sequence: "Ctrl+D"
2063 KeyboardShortcut {2024 enabled: tabContainer.visible
2064 key: Qt.Key_F62025 onActivated: {
2065 enabled: tabContainer.visible2026 if (internal.currentBookmarkOptionsDialog) {
2066 onTriggered: internal.focusAddressBar(true)2027 internal.currentBookmarkOptionsDialog.hide()
2067 }2028 } else if (currentWebview) {
20682029 if (BookmarksModel.contains(currentWebview.url)) {
2069 // Ctrl+D: Toggle bookmarked state on current Tab2030 BookmarksModel.remove(currentWebview.url)
2070 KeyboardShortcut {2031 } else {
2071 modifiers: Qt.ControlModifier2032 internal.addBookmark(currentWebview.url, currentWebview.title, currentWebview.icon)
2072 key: Qt.Key_D
2073 enabled: tabContainer.visible
2074 onTriggered: {
2075 if (currentWebview) {
2076 if (BookmarksModel.contains(currentWebview.url)) {
2077 BookmarksModel.remove(currentWebview.url)
2078 } else {
2079 internal.addBookmark(currentWebview.url, currentWebview.title, currentWebview.icon)
2080 }
2081 }2033 }
2082 }2034 }
2083 }2035 }
20842036 }
2085 // Ctrl+H: Show History2037
2086 KeyboardShortcut {2038 // Ctrl+H: Show History
2087 modifiers: Qt.ControlModifier2039 Shortcut {
2088 key: Qt.Key_H2040 sequence: "Ctrl+H"
2089 enabled: tabContainer.visible2041 enabled: tabContainer.visible
2090 onTriggered: historyViewLoader.active = true2042 onActivated: historyViewLoader.active = true
2091 }2043 }
20922044
2093 // Ctrl+Shift+O: Show Bookmarks2045 // Ctrl+Shift+O: Show Bookmarks
2094 KeyboardShortcut {2046 Shortcut {
2095 modifiers: Qt.ControlModifier | Qt.ShiftModifier2047 sequence: "Ctrl+Shift+O"
2096 key: Qt.Key_O2048 enabled: tabContainer.visible
2097 enabled: tabContainer.visible2049 onActivated: bookmarksViewLoader.active = true
2098 onTriggered: bookmarksViewLoader.active = true2050 }
2099 }2051
21002052 // Alt+← or Backspace: Goes to the previous page in history
2101 // Alt+← or Backspace: Goes to the previous page in history2053 Shortcut {
2102 KeyboardShortcut {2054 sequence: StandardKey.Back
2103 modifiers: Qt.AltModifier2055 enabled: tabContainer.visible
2104 key: Qt.Key_Left2056 onActivated: internal.historyGoBack()
2105 enabled: tabContainer.visible2057 }
2106 onTriggered: internal.historyGoBack()2058 Shortcut {
2107 }2059 sequence: "Backspace"
2108 KeyboardShortcut {2060 enabled: tabContainer.visible
2109 key: Qt.Key_Backspace2061 onActivated: internal.historyGoBack()
2110 enabled: tabContainer.visible2062 }
2111 onTriggered: internal.historyGoBack()2063
2112 }2064 // Alt+→ or Shift+Backspace: Goes to the next page in history
21132065 Shortcut {
2114 // Alt+→ or Shift+Backspace: Goes to the next page in history2066 sequence: StandardKey.Forward
2115 KeyboardShortcut {2067 enabled: tabContainer.visible
2116 modifiers: Qt.AltModifier2068 onActivated: internal.historyGoForward()
2117 key: Qt.Key_Right2069 }
2118 enabled: tabContainer.visible2070 Shortcut {
2119 onTriggered: internal.historyGoForward()2071 sequence: "Shift+Backspace"
2120 }2072 enabled: tabContainer.visible
2121 KeyboardShortcut {2073 onActivated: internal.historyGoForward()
2122 modifiers: Qt.ShiftModifier2074 }
2123 key: Qt.Key_Backspace2075
2124 enabled: tabContainer.visible2076 // F5 or Ctrl+R: Reload current Tab
2125 onTriggered: internal.historyGoForward()2077 Shortcut {
2126 }2078 sequence: StandardKey.Refresh
21272079 enabled: tabContainer.visible
2128 // F5 or Ctrl+R: Reload current Tab2080 onActivated: if (currentWebview) currentWebview.reload()
2129 KeyboardShortcut {2081 }
2130 key: Qt.Key_F52082 Shortcut {
2131 enabled: tabContainer.visible2083 sequence: "F5"
2132 onTriggered: if (currentWebview) currentWebview.reload()2084 enabled: tabContainer.visible
2133 }2085 onActivated: if (currentWebview) currentWebview.reload()
2134 KeyboardShortcut {2086 }
2135 modifiers: Qt.ControlModifier2087
2136 key: Qt.Key_R2088 // Ctrl+F: Find in Page
2137 enabled: tabContainer.visible2089 Shortcut {
2138 onTriggered: if (currentWebview) currentWebview.reload()2090 sequence: StandardKey.Find
2139 }2091 enabled: tabContainer.visible && !newTabViewLoader.active
21402092 onActivated: chrome.findInPageMode = true
2141 // Ctrl+F: Find in Page2093 }
2142 KeyboardShortcut {2094
2143 modifiers: Qt.ControlModifier2095 // Ctrl+J: Show downloads page
2144 key: Qt.Key_F2096 Shortcut {
2145 enabled: tabContainer.visible && !newTabViewLoader.active2097 sequence: "Ctrl+J"
2146 onTriggered: chrome.findInPageMode = true2098 enabled: chrome.visible &&
2147 }2099 downloadHandlerLoader.status == Loader.Ready &&
21482100 contentHandlerLoader.status == Loader.Ready &&
2149 // Ctrl+J: Show downloads page2101 !downloadsViewLoader.active
2150 KeyboardShortcut {2102 onActivated: downloadsViewLoader.active = true
2151 modifiers: Qt.ControlModifier2103 }
2152 key: Qt.Key_J2104
2153 enabled: chrome.visible &&2105 // Ctrl+G: Find next
2154 downloadHandlerLoader.status == Loader.Ready &&2106 Shortcut {
2155 contentHandlerLoader.status == Loader.Ready &&2107 sequence: StandardKey.FindNext
2156 !downloadsViewLoader.active2108 enabled: currentWebview && chrome.findInPageMode
2157 onTriggered: downloadsViewLoader.active = true2109 onActivated: currentWebview.findController.next()
2158 }2110 }
21592111
2160 // Ctrl+Shift+G: Find previous2112 // Ctrl+Shift+G: Find previous
2161 KeyboardShortcut {2113 Shortcut {
2162 modifiers: Qt.ControlModifier | Qt.ShiftModifier2114 sequence: StandardKey.FindPrevious
2163 key: Qt.Key_G2115 enabled: currentWebview && chrome.findInPageMode
2164 enabled: currentWebview && chrome.findInPageMode2116 onActivated: currentWebview.findController.previous()
2165 onTriggered: currentWebview.findController.previous()
2166 }
2167
2168 // Ctrl+G: Find next
2169 KeyboardShortcut {
2170 modifiers: Qt.ControlModifier
2171 key: Qt.Key_G
2172 enabled: currentWebview && chrome.findInPageMode
2173 onTriggered: currentWebview.findController.next()
2174 }
2175 }2117 }
21762118
2177 Loader {2119 Loader {
21782120
=== removed file 'src/app/webbrowser/KeyboardShortcut.qml'
--- src/app/webbrowser/KeyboardShortcut.qml 2015-08-10 15:22:00 +0000
+++ src/app/webbrowser/KeyboardShortcut.qml 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.4
20import Ubuntu.Components 1.3
21
22Action {
23 property int key
24 property int modifiers: Qt.NoModifier
25}
260
=== removed file 'src/app/webbrowser/KeyboardShortcuts.qml'
--- src/app/webbrowser/KeyboardShortcuts.qml 2015-08-10 15:22:00 +0000
+++ src/app/webbrowser/KeyboardShortcuts.qml 1970-01-01 00:00:00 +0000
@@ -1,41 +0,0 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.4
20
21Item {
22 function processKey(key, modifiers) {
23 for (var i = 0; i < data.length; i++) {
24 var shortcut = data[i];
25
26 if (!shortcut.enabled) continue
27 if (key !== shortcut.key) continue
28
29 if (shortcut.modifiers === Qt.NoModifier) {
30 if (modifiers === Qt.NoModifier) {
31 shortcut.trigger()
32 return true
33 }
34 } else if ((modifiers & shortcut.modifiers) === shortcut.modifiers) {
35 shortcut.trigger()
36 return true
37 }
38 }
39 return false
40 }
41}
420
=== modified file 'src/app/webbrowser/ListViewHighlight.qml'
--- src/app/webbrowser/ListViewHighlight.qml 2016-02-10 17:20:47 +0000
+++ src/app/webbrowser/ListViewHighlight.qml 2016-04-08 16:47:47 +0000
@@ -18,7 +18,7 @@
1818
19import QtQuick 2.419import QtQuick 2.4
20import Ubuntu.Components 1.320import Ubuntu.Components 1.3
21import Unity.InputInfo 0.121import ".."
2222
23Rectangle {23Rectangle {
24 color: "transparent"24 color: "transparent"
@@ -33,8 +33,7 @@
3333
34 readonly property bool hasKeyboard: keyboardModel.count > 034 readonly property bool hasKeyboard: keyboardModel.count > 0
3535
36 InputDeviceModel {36 FilteredKeyboardModel {
37 id: keyboardModel37 id: keyboardModel
38 deviceFilter: InputInfo.Keyboard
39 }38 }
40}39}
4140
=== modified file 'src/app/webbrowser/NavigationBar.qml'
--- src/app/webbrowser/NavigationBar.qml 2016-03-01 09:20:32 +0000
+++ src/app/webbrowser/NavigationBar.qml 2016-04-08 16:47:47 +0000
@@ -220,15 +220,18 @@
220 id: internal220 id: internal
221 property var openDrawer: null221 property var openDrawer: null
222 readonly property var webview: tab ? tab.webview : null222 readonly property var webview: tab ? tab.webview : null
223 }
223224
224 onWebviewChanged: {225 onTabChanged: {
225 if (webview) {226 if (tab) {
226 addressbar.actualUrl = webview.url227 addressbar.actualUrl = tab.url
227 addressbar.securityStatus = webview.securityStatus228 addressbar.securityStatus = (tab.webview ? tab.webview.securityStatus : null)
228 } else {229 if (!tab.url.toString() && editing) {
229 addressbar.actualUrl = ""230 addressbar.text = ""
230 addressbar.securityStatus = null
231 }231 }
232 } else {
233 addressbar.actualUrl = ""
234 addressbar.securityStatus = null
232 }235 }
233 }236 }
234237
235238
=== modified file 'tests/autopilot/webbrowser_app/tests/test_keyboard.py'
--- tests/autopilot/webbrowser_app/tests/test_keyboard.py 2016-01-21 10:29:17 +0000
+++ tests/autopilot/webbrowser_app/tests/test_keyboard.py 2016-04-08 16:47:47 +0000
@@ -103,7 +103,7 @@
103 self.check_tab_number(2)103 self.check_tab_number(2)
104 self.main_window.press_key('Ctrl+Page_Down')104 self.main_window.press_key('Ctrl+Page_Down')
105 self.check_tab_number(0)105 self.check_tab_number(0)
106 self.main_window.press_key('Shift+Ctrl+Tab')106 self.main_window.press_key('Ctrl+Shift+Tab')
107 if self.main_window.wide:107 if self.main_window.wide:
108 self.check_tab_number(2)108 self.check_tab_number(2)
109 else:109 else:
@@ -493,3 +493,24 @@
493493
494 self.main_window.press_key('Ctrl+w')494 self.main_window.press_key('Ctrl+w')
495 self.assert_number_webviews_eventually(1)495 self.assert_number_webviews_eventually(1)
496
497 def test_addressbar_cleared_when_opening_new_tab(self):
498 # Verify that when opening a new tab while the address bar was focused,
499 # the address bar is cleared.
500 self.main_window.press_key('Ctrl+l')
501 self.address_bar.activeFocus.wait_for(True)
502 self.assertThat(self.address_bar.text, Eventually(Equals(self.url)))
503 self.main_window.press_key('Ctrl+t')
504 self.address_bar.activeFocus.wait_for(True)
505 self.assertThat(self.address_bar.text, Eventually(Equals("")))
506
507 def test_addressbar_cleared_when_switching_between_new_tabs(self):
508 # Verify that when opening a new tab while a new tab was already open
509 # with text input in the address bar, the address bar is cleared.
510 self.main_window.press_key('Ctrl+t')
511 self.address_bar.activeFocus.wait_for(True)
512 self.assertThat(self.address_bar.text, Eventually(Equals("")))
513 self.address_bar.write("abc")
514 self.main_window.press_key('Ctrl+t')
515 self.address_bar.activeFocus.wait_for(True)
516 self.assertThat(self.address_bar.text, Eventually(Equals("")))
496517
=== modified file 'tests/autopilot/webbrowser_app/tests/test_private.py'
--- tests/autopilot/webbrowser_app/tests/test_private.py 2016-01-21 10:29:17 +0000
+++ tests/autopilot/webbrowser_app/tests/test_private.py 2016-04-08 16:47:47 +0000
@@ -16,6 +16,7 @@
1616
17from testtools.matchers import Equals, NotEquals17from testtools.matchers import Equals, NotEquals
18from autopilot.matchers import Eventually18from autopilot.matchers import Eventually
19from autopilot.platform import model
1920
20from webbrowser_app.tests import StartOpenRemotePageTestCaseBase21from webbrowser_app.tests import StartOpenRemotePageTestCaseBase
2122
@@ -30,7 +31,7 @@
30 self.assert_number_incognito_webviews_eventually(1)31 self.assert_number_incognito_webviews_eventually(1)
31 self.assertTrue(self.main_window.is_new_private_tab_view_visible())32 self.assertTrue(self.main_window.is_new_private_tab_view_visible())
32 self.assertThat(address_bar.activeFocus,33 self.assertThat(address_bar.activeFocus,
33 Eventually(Equals(self.main_window.wide)))34 Eventually(Equals(model() == 'Desktop')))
34 self.assertThat(address_bar.text, Eventually(Equals("")))35 self.assertThat(address_bar.text, Eventually(Equals("")))
3536
36 self.main_window.leave_private_mode()37 self.main_window.leave_private_mode()

Subscribers

People subscribed via source and target branches

to status/vote changes: