Merge lp:~osomon/webbrowser-app/qquickshortcuts into lp:webbrowser-app
- qquickshortcuts
- Merge into trunk
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 | ||||||||||||
Related bugs: |
|
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.
Description of the change
- 1389. By Olivier Tilloy
-
Remove an incorrect condition now that the QInputInfo API is available.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 1390. By Olivier Tilloy
-
Fix failing autopilot test.
- 1391. By Olivier Tilloy
-
Filter out autopilot-emulated keyboards.
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:1391
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 1392. By Olivier Tilloy
-
Do not change focus unnecessarily when switching tabs: clear the address bar instead if needed.
Preview Diff
1 | === modified file 'src/app/CMakeLists.txt' | |||
2 | --- src/app/CMakeLists.txt 2016-02-09 21:19:41 +0000 | |||
3 | +++ src/app/CMakeLists.txt 2016-04-08 16:47:47 +0000 | |||
4 | @@ -27,13 +27,15 @@ | |||
5 | 27 | session-storage.cpp | 27 | session-storage.cpp |
6 | 28 | single-instance-manager.cpp | 28 | single-instance-manager.cpp |
7 | 29 | webbrowser-window.cpp | 29 | webbrowser-window.cpp |
8 | 30 | qquickshortcut.cpp | ||
9 | 30 | ) | 31 | ) |
10 | 31 | 32 | ||
11 | 32 | add_library(${COMMONLIB} STATIC ${COMMONLIB_SRC}) | 33 | add_library(${COMMONLIB} STATIC ${COMMONLIB_SRC}) |
12 | 33 | 34 | ||
13 | 34 | include_directories(${unity8_SOURCE_DIR}/libs/UbuntuGestures | 35 | include_directories(${unity8_SOURCE_DIR}/libs/UbuntuGestures |
14 | 35 | ${unity8_SOURCE_DIR}/plugins | 36 | ${unity8_SOURCE_DIR}/plugins |
16 | 36 | ${LIBAPPARMOR_INCLUDE_DIRS}) | 37 | ${LIBAPPARMOR_INCLUDE_DIRS} |
17 | 38 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) | ||
18 | 37 | target_link_libraries(${COMMONLIB} | 39 | target_link_libraries(${COMMONLIB} |
19 | 38 | Qt5::Core | 40 | Qt5::Core |
20 | 39 | Qt5::Gui | 41 | Qt5::Gui |
21 | 40 | 42 | ||
22 | === added file 'src/app/FilteredKeyboardModel.qml' | |||
23 | --- src/app/FilteredKeyboardModel.qml 1970-01-01 00:00:00 +0000 | |||
24 | +++ src/app/FilteredKeyboardModel.qml 2016-04-08 16:47:47 +0000 | |||
25 | @@ -0,0 +1,33 @@ | |||
26 | 1 | /* | ||
27 | 2 | * Copyright 2016 Canonical Ltd. | ||
28 | 3 | * | ||
29 | 4 | * This file is part of webbrowser-app. | ||
30 | 5 | * | ||
31 | 6 | * webbrowser-app is free software; you can redistribute it and/or modify | ||
32 | 7 | * it under the terms of the GNU General Public License as published by | ||
33 | 8 | * the Free Software Foundation; version 3. | ||
34 | 9 | * | ||
35 | 10 | * webbrowser-app is distributed in the hope that it will be useful, | ||
36 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
37 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
38 | 13 | * GNU General Public License for more details. | ||
39 | 14 | * | ||
40 | 15 | * You should have received a copy of the GNU General Public License | ||
41 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
42 | 17 | */ | ||
43 | 18 | |||
44 | 19 | import QtQuick 2.4 | ||
45 | 20 | import Ubuntu.Components 1.3 | ||
46 | 21 | import Unity.InputInfo 0.1 | ||
47 | 22 | |||
48 | 23 | SortFilterModel { | ||
49 | 24 | model: InputDeviceModel { | ||
50 | 25 | deviceFilter: InputInfo.Keyboard | ||
51 | 26 | } | ||
52 | 27 | filter { | ||
53 | 28 | // Filter out autopilot-emulated keyboards | ||
54 | 29 | // (see https://launchpad.net/bugs/1542224). | ||
55 | 30 | property: "name" | ||
56 | 31 | pattern: /^(?!py-evdev-uinput).*$/ | ||
57 | 32 | } | ||
58 | 33 | } | ||
59 | 0 | 34 | ||
60 | === modified file 'src/app/browserapplication.cpp' | |||
61 | --- src/app/browserapplication.cpp 2016-02-09 22:03:25 +0000 | |||
62 | +++ src/app/browserapplication.cpp 2016-04-08 16:47:47 +0000 | |||
63 | @@ -38,6 +38,7 @@ | |||
64 | 38 | #include "favicon-fetcher.h" | 38 | #include "favicon-fetcher.h" |
65 | 39 | #include "meminfo.h" | 39 | #include "meminfo.h" |
66 | 40 | #include "mime-database.h" | 40 | #include "mime-database.h" |
67 | 41 | #include "qquickshortcut_p.h" | ||
68 | 41 | #include "session-storage.h" | 42 | #include "session-storage.h" |
69 | 42 | #include "webbrowser-window.h" | 43 | #include "webbrowser-window.h" |
70 | 43 | 44 | ||
71 | @@ -179,6 +180,7 @@ | |||
72 | 179 | qmlRegisterSingletonType<MemInfo>(uri, 0, 1, "MemInfo", MemInfo_singleton_factory); | 180 | qmlRegisterSingletonType<MemInfo>(uri, 0, 1, "MemInfo", MemInfo_singleton_factory); |
73 | 180 | qmlRegisterSingletonType<MimeDatabase>(uri, 0, 1, "MimeDatabase", MimeDatabase_singleton_factory); | 181 | qmlRegisterSingletonType<MimeDatabase>(uri, 0, 1, "MimeDatabase", MimeDatabase_singleton_factory); |
74 | 181 | qmlRegisterType<SessionStorage>(uri, 0, 1, "SessionStorage"); | 182 | qmlRegisterType<SessionStorage>(uri, 0, 1, "SessionStorage"); |
75 | 183 | qmlRegisterType<QQuickShortcut>(uri, 0, 1, "Shortcut"); | ||
76 | 182 | 184 | ||
77 | 183 | const char* gesturesUri = "Ubuntu.Gestures"; | 185 | const char* gesturesUri = "Ubuntu.Gestures"; |
78 | 184 | qmlRegisterSingletonType<Direction>(gesturesUri, 0, 1, "Direction", Direction_singleton_factory); | 186 | qmlRegisterSingletonType<Direction>(gesturesUri, 0, 1, "Direction", Direction_singleton_factory); |
79 | 185 | 187 | ||
80 | === added file 'src/app/qquickshortcut.cpp' | |||
81 | --- src/app/qquickshortcut.cpp 1970-01-01 00:00:00 +0000 | |||
82 | +++ src/app/qquickshortcut.cpp 2016-04-08 16:47:47 +0000 | |||
83 | @@ -0,0 +1,283 @@ | |||
84 | 1 | /**************************************************************************** | ||
85 | 2 | ** | ||
86 | 3 | ** Copyright (C) 2015 The Qt Company Ltd. | ||
87 | 4 | ** Contact: http://www.qt.io/licensing/ | ||
88 | 5 | ** | ||
89 | 6 | ** This file is part of the QtQuick module of the Qt Toolkit. | ||
90 | 7 | ** | ||
91 | 8 | ** $QT_BEGIN_LICENSE:LGPL21$ | ||
92 | 9 | ** Commercial License Usage | ||
93 | 10 | ** Licensees holding valid commercial Qt licenses may use this file in | ||
94 | 11 | ** accordance with the commercial license agreement provided with the | ||
95 | 12 | ** Software or, alternatively, in accordance with the terms contained in | ||
96 | 13 | ** a written agreement between you and The Qt Company. For licensing terms | ||
97 | 14 | ** and conditions see http://www.qt.io/terms-conditions. For further | ||
98 | 15 | ** information use the contact form at http://www.qt.io/contact-us. | ||
99 | 16 | ** | ||
100 | 17 | ** GNU Lesser General Public License Usage | ||
101 | 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | ||
102 | 19 | ** General Public License version 2.1 or version 3 as published by the Free | ||
103 | 20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and | ||
104 | 21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the | ||
105 | 22 | ** following information to ensure the GNU Lesser General Public License | ||
106 | 23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and | ||
107 | 24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | ||
108 | 25 | ** | ||
109 | 26 | ** As a special exception, The Qt Company gives you certain additional | ||
110 | 27 | ** rights. These rights are described in The Qt Company LGPL Exception | ||
111 | 28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | ||
112 | 29 | ** | ||
113 | 30 | ** $QT_END_LICENSE$ | ||
114 | 31 | ** | ||
115 | 32 | ****************************************************************************/ | ||
116 | 33 | |||
117 | 34 | #include "qquickshortcut_p.h" | ||
118 | 35 | |||
119 | 36 | #include <QtQuick/qquickitem.h> | ||
120 | 37 | #include <QtQuick/qquickwindow.h> | ||
121 | 38 | #include <QtGui/private/qguiapplication_p.h> | ||
122 | 39 | |||
123 | 40 | QT_BEGIN_NAMESPACE | ||
124 | 41 | |||
125 | 42 | /*! | ||
126 | 43 | \qmltype Shortcut | ||
127 | 44 | \instantiates QQuickShortcut | ||
128 | 45 | \inqmlmodule QtQuick | ||
129 | 46 | \since 5.5 | ||
130 | 47 | \ingroup qtquick-input | ||
131 | 48 | \brief Provides keyboard shortcuts | ||
132 | 49 | |||
133 | 50 | The Shortcut type provides a way of handling keyboard shortcuts. The shortcut can | ||
134 | 51 | be set to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, | ||
135 | 52 | or it can be described with a string containing a sequence of up to four key | ||
136 | 53 | presses that are needed to \l{Shortcut::activated}{activate} the shortcut. | ||
137 | 54 | |||
138 | 55 | \qml | ||
139 | 56 | Item { | ||
140 | 57 | id: view | ||
141 | 58 | |||
142 | 59 | property int currentIndex | ||
143 | 60 | |||
144 | 61 | Shortcut { | ||
145 | 62 | sequence: StandardKey.NextChild | ||
146 | 63 | onActivated: view.currentIndex++ | ||
147 | 64 | } | ||
148 | 65 | } | ||
149 | 66 | \endqml | ||
150 | 67 | |||
151 | 68 | \sa Keys | ||
152 | 69 | */ | ||
153 | 70 | |||
154 | 71 | /*! \qmlsignal QtQuick::Shortcut::activated() | ||
155 | 72 | |||
156 | 73 | This signal is emitted when the shortcut is activated. | ||
157 | 74 | |||
158 | 75 | The corresponding handler is \c onActivated. | ||
159 | 76 | */ | ||
160 | 77 | |||
161 | 78 | /*! \qmlsignal QtQuick::Shortcut::activatedAmbiguously() | ||
162 | 79 | |||
163 | 80 | This signal is emitted when the shortcut is activated ambigously, | ||
164 | 81 | meaning that it matches the start of more than one shortcut. | ||
165 | 82 | |||
166 | 83 | The corresponding handler is \c onActivatedAmbiguously. | ||
167 | 84 | */ | ||
168 | 85 | |||
169 | 86 | QQuickShortcut::QQuickShortcut(QObject *parent) : QObject(parent), m_id(0), | ||
170 | 87 | m_enabled(true), m_completed(false), m_autorepeat(true), m_context(Qt::WindowShortcut) | ||
171 | 88 | { | ||
172 | 89 | } | ||
173 | 90 | |||
174 | 91 | QQuickShortcut::~QQuickShortcut() | ||
175 | 92 | { | ||
176 | 93 | ungrabShortcut(); | ||
177 | 94 | } | ||
178 | 95 | |||
179 | 96 | /*! | ||
180 | 97 | \qmlproperty keysequence QtQuick::Shortcut::sequence | ||
181 | 98 | |||
182 | 99 | This property holds the shortcut's key sequence. The key sequence can be set | ||
183 | 100 | to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, or | ||
184 | 101 | it can be described with a string containing a sequence of up to four key | ||
185 | 102 | presses that are needed to \l{Shortcut::activated}{activate} the shortcut. | ||
186 | 103 | |||
187 | 104 | The default value is an empty key sequence. | ||
188 | 105 | |||
189 | 106 | \qml | ||
190 | 107 | Shortcut { | ||
191 | 108 | sequence: "Ctrl+E,Ctrl+W" | ||
192 | 109 | onActivated: edit.wrapMode = TextEdit.Wrap | ||
193 | 110 | } | ||
194 | 111 | \endqml | ||
195 | 112 | */ | ||
196 | 113 | QVariant QQuickShortcut::sequence() const | ||
197 | 114 | { | ||
198 | 115 | return m_sequence; | ||
199 | 116 | } | ||
200 | 117 | |||
201 | 118 | void QQuickShortcut::setSequence(const QVariant &sequence) | ||
202 | 119 | { | ||
203 | 120 | if (sequence == m_sequence) | ||
204 | 121 | return; | ||
205 | 122 | |||
206 | 123 | QKeySequence shortcut; | ||
207 | 124 | if (sequence.type() == QVariant::Int) | ||
208 | 125 | shortcut = QKeySequence(static_cast<QKeySequence::StandardKey>(sequence.toInt())); | ||
209 | 126 | else | ||
210 | 127 | shortcut = QKeySequence::fromString(sequence.toString()); | ||
211 | 128 | |||
212 | 129 | grabShortcut(shortcut, m_context); | ||
213 | 130 | |||
214 | 131 | m_sequence = sequence; | ||
215 | 132 | m_shortcut = shortcut; | ||
216 | 133 | emit sequenceChanged(); | ||
217 | 134 | } | ||
218 | 135 | |||
219 | 136 | /*! | ||
220 | 137 | \qmlproperty bool QtQuick::Shortcut::enabled | ||
221 | 138 | |||
222 | 139 | This property holds whether the shortcut is enabled. | ||
223 | 140 | |||
224 | 141 | The default value is \c true. | ||
225 | 142 | */ | ||
226 | 143 | bool QQuickShortcut::isEnabled() const | ||
227 | 144 | { | ||
228 | 145 | return m_enabled; | ||
229 | 146 | } | ||
230 | 147 | |||
231 | 148 | void QQuickShortcut::setEnabled(bool enabled) | ||
232 | 149 | { | ||
233 | 150 | if (enabled == m_enabled) | ||
234 | 151 | return; | ||
235 | 152 | |||
236 | 153 | if (m_id) | ||
237 | 154 | QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enabled, m_id, this); | ||
238 | 155 | |||
239 | 156 | m_enabled = enabled; | ||
240 | 157 | emit enabledChanged(); | ||
241 | 158 | } | ||
242 | 159 | |||
243 | 160 | /*! | ||
244 | 161 | \qmlproperty bool QtQuick::Shortcut::autoRepeat | ||
245 | 162 | |||
246 | 163 | This property holds whether the shortcut can auto repeat. | ||
247 | 164 | |||
248 | 165 | The default value is \c true. | ||
249 | 166 | */ | ||
250 | 167 | bool QQuickShortcut::autoRepeat() const | ||
251 | 168 | { | ||
252 | 169 | return m_autorepeat; | ||
253 | 170 | } | ||
254 | 171 | |||
255 | 172 | void QQuickShortcut::setAutoRepeat(bool repeat) | ||
256 | 173 | { | ||
257 | 174 | if (repeat == m_autorepeat) | ||
258 | 175 | return; | ||
259 | 176 | |||
260 | 177 | if (m_id) | ||
261 | 178 | QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(repeat, m_id, this); | ||
262 | 179 | |||
263 | 180 | m_autorepeat = repeat; | ||
264 | 181 | emit autoRepeatChanged(); | ||
265 | 182 | } | ||
266 | 183 | |||
267 | 184 | /*! | ||
268 | 185 | \qmlproperty enumeration QtQuick::Shortcut::context | ||
269 | 186 | |||
270 | 187 | This property holds the \l{Qt::ShortcutContext}{shortcut context}. | ||
271 | 188 | |||
272 | 189 | Supported values are: | ||
273 | 190 | \list | ||
274 | 191 | \li \c Qt.WindowShortcut (default) - The shortcut is active when its parent item is in an active top-level window. | ||
275 | 192 | \li \c Qt.ApplicationShortcut - The shortcut is active when one of the application's windows are active. | ||
276 | 193 | \endlist | ||
277 | 194 | |||
278 | 195 | \qml | ||
279 | 196 | Shortcut { | ||
280 | 197 | sequence: StandardKey.Quit | ||
281 | 198 | context: Qt.ApplicationShortcut | ||
282 | 199 | onActivated: Qt.quit() | ||
283 | 200 | } | ||
284 | 201 | \endqml | ||
285 | 202 | */ | ||
286 | 203 | Qt::ShortcutContext QQuickShortcut::context() const | ||
287 | 204 | { | ||
288 | 205 | return m_context; | ||
289 | 206 | } | ||
290 | 207 | |||
291 | 208 | void QQuickShortcut::setContext(Qt::ShortcutContext context) | ||
292 | 209 | { | ||
293 | 210 | if (context == m_context) | ||
294 | 211 | return; | ||
295 | 212 | |||
296 | 213 | grabShortcut(m_shortcut, context); | ||
297 | 214 | |||
298 | 215 | m_context = context; | ||
299 | 216 | emit contextChanged(); | ||
300 | 217 | } | ||
301 | 218 | |||
302 | 219 | void QQuickShortcut::classBegin() | ||
303 | 220 | { | ||
304 | 221 | } | ||
305 | 222 | |||
306 | 223 | void QQuickShortcut::componentComplete() | ||
307 | 224 | { | ||
308 | 225 | m_completed = true; | ||
309 | 226 | grabShortcut(m_shortcut, m_context); | ||
310 | 227 | } | ||
311 | 228 | |||
312 | 229 | bool QQuickShortcut::event(QEvent *event) | ||
313 | 230 | { | ||
314 | 231 | if (m_enabled && event->type() == QEvent::Shortcut) { | ||
315 | 232 | QShortcutEvent *se = static_cast<QShortcutEvent *>(event); | ||
316 | 233 | if (se->shortcutId() == m_id && se->key() == m_shortcut){ | ||
317 | 234 | if (se->isAmbiguous()) | ||
318 | 235 | emit activatedAmbiguously(); | ||
319 | 236 | else | ||
320 | 237 | emit activated(); | ||
321 | 238 | return true; | ||
322 | 239 | } | ||
323 | 240 | } | ||
324 | 241 | return false; | ||
325 | 242 | } | ||
326 | 243 | |||
327 | 244 | static bool qQuickShortcutContextMatcher(QObject *obj, Qt::ShortcutContext context) | ||
328 | 245 | { | ||
329 | 246 | switch (context) { | ||
330 | 247 | case Qt::ApplicationShortcut: | ||
331 | 248 | return true; | ||
332 | 249 | case Qt::WindowShortcut: | ||
333 | 250 | while (obj && !obj->isWindowType()) { | ||
334 | 251 | obj = obj->parent(); | ||
335 | 252 | if (QQuickItem *item = qobject_cast<QQuickItem *>(obj)) | ||
336 | 253 | obj = item->window(); | ||
337 | 254 | } | ||
338 | 255 | return obj && obj == QGuiApplication::focusWindow(); | ||
339 | 256 | default: | ||
340 | 257 | return false; | ||
341 | 258 | } | ||
342 | 259 | } | ||
343 | 260 | |||
344 | 261 | void QQuickShortcut::grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context) | ||
345 | 262 | { | ||
346 | 263 | ungrabShortcut(); | ||
347 | 264 | |||
348 | 265 | if (m_completed && !sequence.isEmpty()) { | ||
349 | 266 | QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance(); | ||
350 | 267 | m_id = pApp->shortcutMap.addShortcut(this, sequence, context, qQuickShortcutContextMatcher); | ||
351 | 268 | if (!m_enabled) | ||
352 | 269 | pApp->shortcutMap.setShortcutEnabled(false, m_id, this); | ||
353 | 270 | if (!m_autorepeat) | ||
354 | 271 | pApp->shortcutMap.setShortcutAutoRepeat(false, m_id, this); | ||
355 | 272 | } | ||
356 | 273 | } | ||
357 | 274 | |||
358 | 275 | void QQuickShortcut::ungrabShortcut() | ||
359 | 276 | { | ||
360 | 277 | if (m_id) { | ||
361 | 278 | QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_id, this); | ||
362 | 279 | m_id = 0; | ||
363 | 280 | } | ||
364 | 281 | } | ||
365 | 282 | |||
366 | 283 | QT_END_NAMESPACE | ||
367 | 0 | 284 | ||
368 | === added file 'src/app/qquickshortcut_p.h' | |||
369 | --- src/app/qquickshortcut_p.h 1970-01-01 00:00:00 +0000 | |||
370 | +++ src/app/qquickshortcut_p.h 2016-04-08 16:47:47 +0000 | |||
371 | @@ -0,0 +1,109 @@ | |||
372 | 1 | /**************************************************************************** | ||
373 | 2 | ** | ||
374 | 3 | ** Copyright (C) 2015 The Qt Company Ltd. | ||
375 | 4 | ** Contact: http://www.qt.io/licensing/ | ||
376 | 5 | ** | ||
377 | 6 | ** This file is part of the QtQuick module of the Qt Toolkit. | ||
378 | 7 | ** | ||
379 | 8 | ** $QT_BEGIN_LICENSE:LGPL21$ | ||
380 | 9 | ** Commercial License Usage | ||
381 | 10 | ** Licensees holding valid commercial Qt licenses may use this file in | ||
382 | 11 | ** accordance with the commercial license agreement provided with the | ||
383 | 12 | ** Software or, alternatively, in accordance with the terms contained in | ||
384 | 13 | ** a written agreement between you and The Qt Company. For licensing terms | ||
385 | 14 | ** and conditions see http://www.qt.io/terms-conditions. For further | ||
386 | 15 | ** information use the contact form at http://www.qt.io/contact-us. | ||
387 | 16 | ** | ||
388 | 17 | ** GNU Lesser General Public License Usage | ||
389 | 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | ||
390 | 19 | ** General Public License version 2.1 or version 3 as published by the Free | ||
391 | 20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and | ||
392 | 21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the | ||
393 | 22 | ** following information to ensure the GNU Lesser General Public License | ||
394 | 23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and | ||
395 | 24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | ||
396 | 25 | ** | ||
397 | 26 | ** As a special exception, The Qt Company gives you certain additional | ||
398 | 27 | ** rights. These rights are described in The Qt Company LGPL Exception | ||
399 | 28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | ||
400 | 29 | ** | ||
401 | 30 | ** $QT_END_LICENSE$ | ||
402 | 31 | ** | ||
403 | 32 | ****************************************************************************/ | ||
404 | 33 | |||
405 | 34 | #ifndef QQUICKSHORTCUT_P_H | ||
406 | 35 | #define QQUICKSHORTCUT_P_H | ||
407 | 36 | |||
408 | 37 | // | ||
409 | 38 | // W A R N I N G | ||
410 | 39 | // ------------- | ||
411 | 40 | // | ||
412 | 41 | // This file is not part of the Qt API. It exists purely as an | ||
413 | 42 | // implementation detail. This header file may change from version to | ||
414 | 43 | // version without notice, or even be removed. | ||
415 | 44 | // | ||
416 | 45 | // We mean it. | ||
417 | 46 | // | ||
418 | 47 | |||
419 | 48 | #include <QtCore/qobject.h> | ||
420 | 49 | #include <QtCore/qvariant.h> | ||
421 | 50 | #include <QtGui/qkeysequence.h> | ||
422 | 51 | #include <QtQml/qqmlparserstatus.h> | ||
423 | 52 | |||
424 | 53 | QT_BEGIN_NAMESPACE | ||
425 | 54 | |||
426 | 55 | class QQuickShortcut : public QObject, public QQmlParserStatus | ||
427 | 56 | { | ||
428 | 57 | Q_OBJECT | ||
429 | 58 | Q_INTERFACES(QQmlParserStatus) | ||
430 | 59 | Q_PROPERTY(QVariant sequence READ sequence WRITE setSequence NOTIFY sequenceChanged FINAL) | ||
431 | 60 | Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) | ||
432 | 61 | Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL) | ||
433 | 62 | Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext NOTIFY contextChanged FINAL) | ||
434 | 63 | |||
435 | 64 | public: | ||
436 | 65 | explicit QQuickShortcut(QObject *parent = Q_NULLPTR); | ||
437 | 66 | ~QQuickShortcut(); | ||
438 | 67 | |||
439 | 68 | QVariant sequence() const; | ||
440 | 69 | void setSequence(const QVariant &sequence); | ||
441 | 70 | |||
442 | 71 | bool isEnabled() const; | ||
443 | 72 | void setEnabled(bool enabled); | ||
444 | 73 | |||
445 | 74 | bool autoRepeat() const; | ||
446 | 75 | void setAutoRepeat(bool repeat); | ||
447 | 76 | |||
448 | 77 | Qt::ShortcutContext context() const; | ||
449 | 78 | void setContext(Qt::ShortcutContext context); | ||
450 | 79 | |||
451 | 80 | Q_SIGNALS: | ||
452 | 81 | void sequenceChanged(); | ||
453 | 82 | void enabledChanged(); | ||
454 | 83 | void autoRepeatChanged(); | ||
455 | 84 | void contextChanged(); | ||
456 | 85 | |||
457 | 86 | void activated(); | ||
458 | 87 | void activatedAmbiguously(); | ||
459 | 88 | |||
460 | 89 | protected: | ||
461 | 90 | void classBegin() Q_DECL_OVERRIDE; | ||
462 | 91 | void componentComplete() Q_DECL_OVERRIDE; | ||
463 | 92 | bool event(QEvent *event) Q_DECL_OVERRIDE; | ||
464 | 93 | |||
465 | 94 | void grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context); | ||
466 | 95 | void ungrabShortcut(); | ||
467 | 96 | |||
468 | 97 | private: | ||
469 | 98 | int m_id; | ||
470 | 99 | bool m_enabled; | ||
471 | 100 | bool m_completed; | ||
472 | 101 | bool m_autorepeat; | ||
473 | 102 | QKeySequence m_shortcut; | ||
474 | 103 | Qt::ShortcutContext m_context; | ||
475 | 104 | QVariant m_sequence; | ||
476 | 105 | }; | ||
477 | 106 | |||
478 | 107 | QT_END_NAMESPACE | ||
479 | 108 | |||
480 | 109 | #endif // QQUICKSHORTCUT_P_H | ||
481 | 0 | 110 | ||
482 | === modified file 'src/app/webbrowser/Browser.qml' | |||
483 | --- src/app/webbrowser/Browser.qml 2016-03-07 18:44:34 +0000 | |||
484 | +++ src/app/webbrowser/Browser.qml 2016-04-08 16:47:47 +0000 | |||
485 | @@ -63,21 +63,6 @@ | |||
486 | 63 | } | 63 | } |
487 | 64 | 64 | ||
488 | 65 | Connections { | 65 | Connections { |
489 | 66 | target: tabsModel | ||
490 | 67 | onCurrentIndexChanged: { | ||
491 | 68 | // Remove focus from the address bar when the current tab | ||
492 | 69 | // changes to ensure that its contents are updated. | ||
493 | 70 | contentsContainer.forceActiveFocus() | ||
494 | 71 | |||
495 | 72 | // In narrow mode, the tabslist is a stack: | ||
496 | 73 | // the current tab is always at the top. | ||
497 | 74 | if (!browser.wide) { | ||
498 | 75 | tabsModel.move(tabsModel.currentIndex, 0) | ||
499 | 76 | } | ||
500 | 77 | } | ||
501 | 78 | } | ||
502 | 79 | |||
503 | 80 | Connections { | ||
504 | 81 | target: currentWebview | 66 | target: currentWebview |
505 | 82 | 67 | ||
506 | 83 | /* Note that we are connecting the mediaAccessPermissionRequested signal | 68 | /* Note that we are connecting the mediaAccessPermissionRequested signal |
507 | @@ -111,6 +96,10 @@ | |||
508 | 111 | deviceFilter: InputInfo.TouchScreen | 96 | deviceFilter: InputInfo.TouchScreen |
509 | 112 | } | 97 | } |
510 | 113 | 98 | ||
511 | 99 | FilteredKeyboardModel { | ||
512 | 100 | id: keyboardModel | ||
513 | 101 | } | ||
514 | 102 | |||
515 | 114 | Component { | 103 | Component { |
516 | 115 | id: mediaAccessDialogComponent | 104 | id: mediaAccessDialogComponent |
517 | 116 | MediaAccessDialog { } | 105 | MediaAccessDialog { } |
518 | @@ -1425,21 +1414,12 @@ | |||
519 | 1425 | Component { | 1414 | Component { |
520 | 1426 | id: bookmarkOptionsComponent | 1415 | id: bookmarkOptionsComponent |
521 | 1427 | BookmarkOptions { | 1416 | BookmarkOptions { |
522 | 1428 | id: bookmarkOptions | ||
523 | 1429 | folderModel: BookmarksFolderListModel { | 1417 | folderModel: BookmarksFolderListModel { |
524 | 1430 | sourceModel: BookmarksModel | 1418 | sourceModel: BookmarksModel |
525 | 1431 | } | 1419 | } |
526 | 1432 | 1420 | ||
530 | 1433 | Component.onCompleted: { | 1421 | Component.onCompleted: forceActiveFocus() |
528 | 1434 | forceActiveFocus() | ||
529 | 1435 | } | ||
531 | 1436 | 1422 | ||
532 | 1437 | // Fragile workaround for https://launchpad.net/bugs/1546677. | ||
533 | 1438 | // By destroying the popover, its visibility isn’t changed to | ||
534 | 1439 | // false, and thus the bookmark is not removed. | ||
535 | 1440 | function closeAndConfirm() { | ||
536 | 1441 | destroy() | ||
537 | 1442 | } | ||
538 | 1443 | onVisibleChanged: { | 1423 | onVisibleChanged: { |
539 | 1444 | if (!visible) { | 1424 | if (!visible) { |
540 | 1445 | BookmarksModel.remove(bookmarkUrl) | 1425 | BookmarksModel.remove(bookmarkUrl) |
541 | @@ -1452,28 +1432,11 @@ | |||
542 | 1452 | } | 1432 | } |
543 | 1453 | } | 1433 | } |
544 | 1454 | 1434 | ||
567 | 1455 | Keys.onPressed: { | 1435 | // Fragile workaround for https://launchpad.net/bugs/1546677. |
568 | 1456 | if (bookmarkOptionsShortcuts.processKey(event.key, event.modifiers)) { | 1436 | // By destroying the popover, its visibility isn’t changed to |
569 | 1457 | event.accepted = true | 1437 | // false, and thus the bookmark is not removed. |
570 | 1458 | } | 1438 | Keys.onEnterPressed: destroy() |
571 | 1459 | } | 1439 | Keys.onReturnPressed: destroy() |
550 | 1460 | |||
551 | 1461 | KeyboardShortcuts { | ||
552 | 1462 | id: bookmarkOptionsShortcuts | ||
553 | 1463 | KeyboardShortcut { | ||
554 | 1464 | key: Qt.Key_Return | ||
555 | 1465 | onTriggered: closeAndConfirm() | ||
556 | 1466 | } | ||
557 | 1467 | |||
558 | 1468 | KeyboardShortcut { | ||
559 | 1469 | modifiers: Qt.ControlModifier | ||
560 | 1470 | key: Qt.Key_D | ||
561 | 1471 | onTriggered: { | ||
562 | 1472 | BookmarksModel.remove(bookmarkUrl) | ||
563 | 1473 | closeAndConfirm() | ||
564 | 1474 | } | ||
565 | 1475 | } | ||
566 | 1476 | } | ||
572 | 1477 | } | 1440 | } |
573 | 1478 | } | 1441 | } |
574 | 1479 | 1442 | ||
575 | @@ -1627,16 +1590,7 @@ | |||
576 | 1627 | } | 1590 | } |
577 | 1628 | 1591 | ||
578 | 1629 | function maybeFocusAddressBar() { | 1592 | function maybeFocusAddressBar() { |
589 | 1630 | // XXX: this is not the right condition, but it is better than | 1593 | if (keyboardModel.count > 0) { |
580 | 1631 | // inferring a "desktop" form factor from various heuristics. | ||
581 | 1632 | // The real fix is to detect whether there is a physical keyboard | ||
582 | 1633 | // connected, for which there is currently no API yet (there will | ||
583 | 1634 | // be a QInputInfo API in a future version of Qt). | ||
584 | 1635 | // Wide mode might be in use on a device without a physical | ||
585 | 1636 | // keyboard (e.g. a 10" tablet), and conversely the browser window | ||
586 | 1637 | // might be shrinked to a narrow layout on a desktop setup with a | ||
587 | 1638 | // physical keyboard and no OSK. | ||
588 | 1639 | if (browser.wide) { | ||
590 | 1640 | focusAddressBar() | 1594 | focusAddressBar() |
591 | 1641 | } else { | 1595 | } else { |
592 | 1642 | contentsContainer.forceActiveFocus() | 1596 | contentsContainer.forceActiveFocus() |
593 | @@ -1682,14 +1636,14 @@ | |||
594 | 1682 | } | 1636 | } |
595 | 1683 | } | 1637 | } |
596 | 1684 | 1638 | ||
597 | 1639 | property var currentBookmarkOptionsDialog: null | ||
598 | 1685 | function addBookmark(url, title, icon, location) { | 1640 | function addBookmark(url, title, icon, location) { |
599 | 1686 | if (title == "") title = UrlUtils.removeScheme(url) | 1641 | if (title == "") title = UrlUtils.removeScheme(url) |
600 | 1687 | BookmarksModel.add(url, title, icon, "") | 1642 | BookmarksModel.add(url, title, icon, "") |
601 | 1688 | if (location === undefined) location = chrome.bookmarkTogglePlaceHolder | 1643 | if (location === undefined) location = chrome.bookmarkTogglePlaceHolder |
606 | 1689 | PopupUtils.open(bookmarkOptionsComponent, | 1644 | var properties = {"bookmarkUrl": url, "bookmarkTitle": title} |
607 | 1690 | location, | 1645 | currentBookmarkOptionsDialog = PopupUtils.open(bookmarkOptionsComponent, |
608 | 1691 | {"bookmarkUrl": url, | 1646 | location, properties) |
605 | 1692 | "bookmarkTitle": title}) | ||
609 | 1693 | } | 1647 | } |
610 | 1694 | } | 1648 | } |
611 | 1695 | 1649 | ||
612 | @@ -1926,6 +1880,13 @@ | |||
613 | 1926 | 1880 | ||
614 | 1927 | Connections { | 1881 | Connections { |
615 | 1928 | target: tabsModel | 1882 | target: tabsModel |
616 | 1883 | onCurrentIndexChanged: { | ||
617 | 1884 | // In narrow mode, the tabslist is a stack: | ||
618 | 1885 | // the current tab is always at the top. | ||
619 | 1886 | if (!browser.wide) { | ||
620 | 1887 | tabsModel.move(tabsModel.currentIndex, 0) | ||
621 | 1888 | } | ||
622 | 1889 | } | ||
623 | 1929 | onCurrentTabChanged: { | 1890 | onCurrentTabChanged: { |
624 | 1930 | chrome.findInPageMode = false | 1891 | chrome.findInPageMode = false |
625 | 1931 | var tab = tabsModel.currentTab | 1892 | var tab = tabsModel.currentTab |
626 | @@ -1972,206 +1933,187 @@ | |||
627 | 1972 | } | 1933 | } |
628 | 1973 | } | 1934 | } |
629 | 1974 | 1935 | ||
736 | 1975 | Keys.onPressed: if (shortcuts.processKey(event.key, event.modifiers)) event.accepted = true | 1936 | // TODO: internationalize non-standard key sequences? |
737 | 1976 | KeyboardShortcuts { | 1937 | |
738 | 1977 | id: shortcuts | 1938 | // Ctrl+Tab or Ctrl+PageDown: cycle through open tabs |
739 | 1978 | 1939 | Shortcut { | |
740 | 1979 | // Ctrl+Tab or Ctrl+PageDown: cycle through open tabs | 1940 | sequence: StandardKey.NextChild |
741 | 1980 | KeyboardShortcut { | 1941 | enabled: tabContainer.visible || recentView.visible |
742 | 1981 | modifiers: Qt.ControlModifier | 1942 | onActivated: internal.switchToNextTab() |
743 | 1982 | key: Qt.Key_Tab | 1943 | } |
744 | 1983 | enabled: tabContainer.visible || recentView.visible | 1944 | Shortcut { |
745 | 1984 | onTriggered: internal.switchToNextTab() | 1945 | sequence: "Ctrl+PgDown" |
746 | 1985 | } | 1946 | enabled: tabContainer.visible || recentView.visible |
747 | 1986 | KeyboardShortcut { | 1947 | onActivated: internal.switchToNextTab() |
748 | 1987 | modifiers: Qt.ControlModifier | 1948 | } |
749 | 1988 | key: Qt.Key_PageDown | 1949 | |
750 | 1989 | enabled: tabContainer.visible || recentView.visible | 1950 | // Ctrl+Shift+Tab or Ctrl+PageUp: cycle through open tabs in reverse order |
751 | 1990 | onTriggered: internal.switchToNextTab() | 1951 | Shortcut { |
752 | 1991 | } | 1952 | sequence: StandardKey.PreviousChild |
753 | 1992 | 1953 | enabled: tabContainer.visible || recentView.visible | |
754 | 1993 | // Ctrl+Shift+Tab or Ctrl+PageUp: cycle through open tabs in reverse order | 1954 | onActivated: internal.switchToPreviousTab() |
755 | 1994 | KeyboardShortcut { | 1955 | } |
756 | 1995 | modifiers: Qt.ControlModifier | 1956 | Shortcut { |
757 | 1996 | key: Qt.Key_Backtab | 1957 | sequence: "Ctrl+Shift+Tab" |
758 | 1997 | enabled: tabContainer.visible || recentView.visible | 1958 | enabled: tabContainer.visible || recentView.visible |
759 | 1998 | onTriggered: internal.switchToPreviousTab() | 1959 | onActivated: internal.switchToPreviousTab() |
760 | 1999 | } | 1960 | } |
761 | 2000 | KeyboardShortcut { | 1961 | Shortcut { |
762 | 2001 | modifiers: Qt.ControlModifier | 1962 | sequence: "Ctrl+PgUp" |
763 | 2002 | key: Qt.Key_PageUp | 1963 | enabled: tabContainer.visible || recentView.visible |
764 | 2003 | enabled: tabContainer.visible || recentView.visible | 1964 | onActivated: internal.switchToPreviousTab() |
765 | 2004 | onTriggered: internal.switchToPreviousTab() | 1965 | } |
766 | 2005 | } | 1966 | |
767 | 2006 | 1967 | // Ctrl+W or Ctrl+F4: Close the current tab | |
768 | 2007 | // Ctrl+Shift+W or Ctrl+Shift+T: Undo close tab | 1968 | Shortcut { |
769 | 2008 | KeyboardShortcut { | 1969 | sequence: StandardKey.Close |
770 | 2009 | modifiers: Qt.ControlModifier | Qt.ShiftModifier | 1970 | enabled: tabContainer.visible || recentView.visible |
771 | 2010 | key: Qt.Key_W | 1971 | onActivated: internal.closeCurrentTab() |
772 | 2011 | enabled: tabContainer.visible || recentView.visible | 1972 | } |
773 | 2012 | onTriggered: internal.undoCloseTab() | 1973 | Shortcut { |
774 | 2013 | } | 1974 | sequence: "Ctrl+F4" |
775 | 2014 | 1975 | enabled: tabContainer.visible || recentView.visible | |
776 | 2015 | KeyboardShortcut { | 1976 | onActivated: internal.closeCurrentTab() |
777 | 2016 | modifiers: Qt.ControlModifier | Qt.ShiftModifier | 1977 | } |
778 | 2017 | key: Qt.Key_T | 1978 | |
779 | 2018 | enabled: tabContainer.visible || recentView.visible | 1979 | // Ctrl+Shift+W or Ctrl+Shift+T: Undo close tab |
780 | 2019 | onTriggered: internal.undoCloseTab() | 1980 | Shortcut { |
781 | 2020 | } | 1981 | sequence: "Ctrl+Shift+W" |
782 | 2021 | 1982 | enabled: tabContainer.visible || recentView.visible | |
783 | 2022 | // Ctrl+W or Ctrl+F4: Close the current tab | 1983 | onActivated: internal.undoCloseTab() |
784 | 2023 | KeyboardShortcut { | 1984 | } |
785 | 2024 | modifiers: Qt.ControlModifier | 1985 | Shortcut { |
786 | 2025 | key: Qt.Key_W | 1986 | sequence: "Ctrl+Shift+T" |
787 | 2026 | enabled: tabContainer.visible || recentView.visible | 1987 | enabled: tabContainer.visible || recentView.visible |
788 | 2027 | onTriggered: internal.closeCurrentTab() | 1988 | onActivated: internal.undoCloseTab() |
789 | 2028 | } | 1989 | } |
790 | 2029 | KeyboardShortcut { | 1990 | |
791 | 2030 | modifiers: Qt.ControlModifier | 1991 | // Ctrl+T: Open a new Tab |
792 | 2031 | key: Qt.Key_F4 | 1992 | Shortcut { |
793 | 2032 | enabled: tabContainer.visible || recentView.visible | 1993 | sequence: StandardKey.AddTab |
794 | 2033 | onTriggered: internal.closeCurrentTab() | 1994 | enabled: tabContainer.visible || recentView.visible || |
795 | 2034 | } | 1995 | bookmarksViewLoader.active || historyViewLoader.active |
796 | 2035 | 1996 | onActivated: { | |
797 | 2036 | // Ctrl+T: Open a new Tab | 1997 | openUrlInNewTab("", true) |
798 | 2037 | KeyboardShortcut { | 1998 | if (recentView.visible) recentView.reset() |
799 | 2038 | modifiers: Qt.ControlModifier | 1999 | bookmarksViewLoader.active = false |
800 | 2039 | key: Qt.Key_T | 2000 | historyViewLoader.active = false |
801 | 2040 | enabled: tabContainer.visible || recentView.visible || | 2001 | } |
802 | 2041 | bookmarksViewLoader.active || historyViewLoader.active | 2002 | } |
803 | 2042 | onTriggered: { | 2003 | |
804 | 2043 | openUrlInNewTab("", true) | 2004 | // F6 or Ctrl+L or Alt+D: Select the content in the address bar |
805 | 2044 | if (recentView.visible) recentView.reset() | 2005 | Shortcut { |
806 | 2045 | bookmarksViewLoader.active = false | 2006 | sequence: "F6" |
807 | 2046 | historyViewLoader.active = false | 2007 | enabled: tabContainer.visible |
808 | 2047 | } | 2008 | onActivated: internal.focusAddressBar(true) |
809 | 2048 | } | 2009 | } |
810 | 2049 | 2010 | Shortcut { | |
811 | 2050 | // F6 or Ctrl+L or Alt+D: Select the content in the address bar | 2011 | sequence: "Ctrl+L" |
812 | 2051 | KeyboardShortcut { | 2012 | enabled: tabContainer.visible |
813 | 2052 | modifiers: Qt.ControlModifier | 2013 | onActivated: internal.focusAddressBar(true) |
814 | 2053 | key: Qt.Key_L | 2014 | } |
815 | 2054 | enabled: tabContainer.visible | 2015 | Shortcut { |
816 | 2055 | onTriggered: internal.focusAddressBar(true) | 2016 | sequence: "Alt+D" |
817 | 2056 | } | 2017 | enabled: tabContainer.visible |
818 | 2057 | KeyboardShortcut { | 2018 | onActivated: internal.focusAddressBar(true) |
819 | 2058 | modifiers: Qt.AltModifier | 2019 | } |
820 | 2059 | key: Qt.Key_D | 2020 | |
821 | 2060 | enabled: tabContainer.visible | 2021 | // Ctrl+D: Toggle bookmarked state on current Tab |
822 | 2061 | onTriggered: internal.focusAddressBar(true) | 2022 | Shortcut { |
823 | 2062 | } | 2023 | sequence: "Ctrl+D" |
824 | 2063 | KeyboardShortcut { | 2024 | enabled: tabContainer.visible |
825 | 2064 | key: Qt.Key_F6 | 2025 | onActivated: { |
826 | 2065 | enabled: tabContainer.visible | 2026 | if (internal.currentBookmarkOptionsDialog) { |
827 | 2066 | onTriggered: internal.focusAddressBar(true) | 2027 | internal.currentBookmarkOptionsDialog.hide() |
828 | 2067 | } | 2028 | } else if (currentWebview) { |
829 | 2068 | 2029 | if (BookmarksModel.contains(currentWebview.url)) { | |
830 | 2069 | // Ctrl+D: Toggle bookmarked state on current Tab | 2030 | BookmarksModel.remove(currentWebview.url) |
831 | 2070 | KeyboardShortcut { | 2031 | } else { |
832 | 2071 | modifiers: Qt.ControlModifier | 2032 | internal.addBookmark(currentWebview.url, currentWebview.title, currentWebview.icon) |
727 | 2072 | key: Qt.Key_D | ||
728 | 2073 | enabled: tabContainer.visible | ||
729 | 2074 | onTriggered: { | ||
730 | 2075 | if (currentWebview) { | ||
731 | 2076 | if (BookmarksModel.contains(currentWebview.url)) { | ||
732 | 2077 | BookmarksModel.remove(currentWebview.url) | ||
733 | 2078 | } else { | ||
734 | 2079 | internal.addBookmark(currentWebview.url, currentWebview.title, currentWebview.icon) | ||
735 | 2080 | } | ||
833 | 2081 | } | 2033 | } |
834 | 2082 | } | 2034 | } |
835 | 2083 | } | 2035 | } |
927 | 2084 | 2036 | } | |
928 | 2085 | // Ctrl+H: Show History | 2037 | |
929 | 2086 | KeyboardShortcut { | 2038 | // Ctrl+H: Show History |
930 | 2087 | modifiers: Qt.ControlModifier | 2039 | Shortcut { |
931 | 2088 | key: Qt.Key_H | 2040 | sequence: "Ctrl+H" |
932 | 2089 | enabled: tabContainer.visible | 2041 | enabled: tabContainer.visible |
933 | 2090 | onTriggered: historyViewLoader.active = true | 2042 | onActivated: historyViewLoader.active = true |
934 | 2091 | } | 2043 | } |
935 | 2092 | 2044 | ||
936 | 2093 | // Ctrl+Shift+O: Show Bookmarks | 2045 | // Ctrl+Shift+O: Show Bookmarks |
937 | 2094 | KeyboardShortcut { | 2046 | Shortcut { |
938 | 2095 | modifiers: Qt.ControlModifier | Qt.ShiftModifier | 2047 | sequence: "Ctrl+Shift+O" |
939 | 2096 | key: Qt.Key_O | 2048 | enabled: tabContainer.visible |
940 | 2097 | enabled: tabContainer.visible | 2049 | onActivated: bookmarksViewLoader.active = true |
941 | 2098 | onTriggered: bookmarksViewLoader.active = true | 2050 | } |
942 | 2099 | } | 2051 | |
943 | 2100 | 2052 | // Alt+← or Backspace: Goes to the previous page in history | |
944 | 2101 | // Alt+← or Backspace: Goes to the previous page in history | 2053 | Shortcut { |
945 | 2102 | KeyboardShortcut { | 2054 | sequence: StandardKey.Back |
946 | 2103 | modifiers: Qt.AltModifier | 2055 | enabled: tabContainer.visible |
947 | 2104 | key: Qt.Key_Left | 2056 | onActivated: internal.historyGoBack() |
948 | 2105 | enabled: tabContainer.visible | 2057 | } |
949 | 2106 | onTriggered: internal.historyGoBack() | 2058 | Shortcut { |
950 | 2107 | } | 2059 | sequence: "Backspace" |
951 | 2108 | KeyboardShortcut { | 2060 | enabled: tabContainer.visible |
952 | 2109 | key: Qt.Key_Backspace | 2061 | onActivated: internal.historyGoBack() |
953 | 2110 | enabled: tabContainer.visible | 2062 | } |
954 | 2111 | onTriggered: internal.historyGoBack() | 2063 | |
955 | 2112 | } | 2064 | // Alt+→ or Shift+Backspace: Goes to the next page in history |
956 | 2113 | 2065 | Shortcut { | |
957 | 2114 | // Alt+→ or Shift+Backspace: Goes to the next page in history | 2066 | sequence: StandardKey.Forward |
958 | 2115 | KeyboardShortcut { | 2067 | enabled: tabContainer.visible |
959 | 2116 | modifiers: Qt.AltModifier | 2068 | onActivated: internal.historyGoForward() |
960 | 2117 | key: Qt.Key_Right | 2069 | } |
961 | 2118 | enabled: tabContainer.visible | 2070 | Shortcut { |
962 | 2119 | onTriggered: internal.historyGoForward() | 2071 | sequence: "Shift+Backspace" |
963 | 2120 | } | 2072 | enabled: tabContainer.visible |
964 | 2121 | KeyboardShortcut { | 2073 | onActivated: internal.historyGoForward() |
965 | 2122 | modifiers: Qt.ShiftModifier | 2074 | } |
966 | 2123 | key: Qt.Key_Backspace | 2075 | |
967 | 2124 | enabled: tabContainer.visible | 2076 | // F5 or Ctrl+R: Reload current Tab |
968 | 2125 | onTriggered: internal.historyGoForward() | 2077 | Shortcut { |
969 | 2126 | } | 2078 | sequence: StandardKey.Refresh |
970 | 2127 | 2079 | enabled: tabContainer.visible | |
971 | 2128 | // F5 or Ctrl+R: Reload current Tab | 2080 | onActivated: if (currentWebview) currentWebview.reload() |
972 | 2129 | KeyboardShortcut { | 2081 | } |
973 | 2130 | key: Qt.Key_F5 | 2082 | Shortcut { |
974 | 2131 | enabled: tabContainer.visible | 2083 | sequence: "F5" |
975 | 2132 | onTriggered: if (currentWebview) currentWebview.reload() | 2084 | enabled: tabContainer.visible |
976 | 2133 | } | 2085 | onActivated: if (currentWebview) currentWebview.reload() |
977 | 2134 | KeyboardShortcut { | 2086 | } |
978 | 2135 | modifiers: Qt.ControlModifier | 2087 | |
979 | 2136 | key: Qt.Key_R | 2088 | // Ctrl+F: Find in Page |
980 | 2137 | enabled: tabContainer.visible | 2089 | Shortcut { |
981 | 2138 | onTriggered: if (currentWebview) currentWebview.reload() | 2090 | sequence: StandardKey.Find |
982 | 2139 | } | 2091 | enabled: tabContainer.visible && !newTabViewLoader.active |
983 | 2140 | 2092 | onActivated: chrome.findInPageMode = true | |
984 | 2141 | // Ctrl+F: Find in Page | 2093 | } |
985 | 2142 | KeyboardShortcut { | 2094 | |
986 | 2143 | modifiers: Qt.ControlModifier | 2095 | // Ctrl+J: Show downloads page |
987 | 2144 | key: Qt.Key_F | 2096 | Shortcut { |
988 | 2145 | enabled: tabContainer.visible && !newTabViewLoader.active | 2097 | sequence: "Ctrl+J" |
989 | 2146 | onTriggered: chrome.findInPageMode = true | 2098 | enabled: chrome.visible && |
990 | 2147 | } | 2099 | downloadHandlerLoader.status == Loader.Ready && |
991 | 2148 | 2100 | contentHandlerLoader.status == Loader.Ready && | |
992 | 2149 | // Ctrl+J: Show downloads page | 2101 | !downloadsViewLoader.active |
993 | 2150 | KeyboardShortcut { | 2102 | onActivated: downloadsViewLoader.active = true |
994 | 2151 | modifiers: Qt.ControlModifier | 2103 | } |
995 | 2152 | key: Qt.Key_J | 2104 | |
996 | 2153 | enabled: chrome.visible && | 2105 | // Ctrl+G: Find next |
997 | 2154 | downloadHandlerLoader.status == Loader.Ready && | 2106 | Shortcut { |
998 | 2155 | contentHandlerLoader.status == Loader.Ready && | 2107 | sequence: StandardKey.FindNext |
999 | 2156 | !downloadsViewLoader.active | 2108 | enabled: currentWebview && chrome.findInPageMode |
1000 | 2157 | onTriggered: downloadsViewLoader.active = true | 2109 | onActivated: currentWebview.findController.next() |
1001 | 2158 | } | 2110 | } |
1002 | 2159 | 2111 | ||
1003 | 2160 | // Ctrl+Shift+G: Find previous | 2112 | // Ctrl+Shift+G: Find previous |
1004 | 2161 | KeyboardShortcut { | 2113 | Shortcut { |
1005 | 2162 | modifiers: Qt.ControlModifier | Qt.ShiftModifier | 2114 | sequence: StandardKey.FindPrevious |
1006 | 2163 | key: Qt.Key_G | 2115 | enabled: currentWebview && chrome.findInPageMode |
1007 | 2164 | enabled: currentWebview && chrome.findInPageMode | 2116 | onActivated: currentWebview.findController.previous() |
917 | 2165 | onTriggered: currentWebview.findController.previous() | ||
918 | 2166 | } | ||
919 | 2167 | |||
920 | 2168 | // Ctrl+G: Find next | ||
921 | 2169 | KeyboardShortcut { | ||
922 | 2170 | modifiers: Qt.ControlModifier | ||
923 | 2171 | key: Qt.Key_G | ||
924 | 2172 | enabled: currentWebview && chrome.findInPageMode | ||
925 | 2173 | onTriggered: currentWebview.findController.next() | ||
926 | 2174 | } | ||
1008 | 2175 | } | 2117 | } |
1009 | 2176 | 2118 | ||
1010 | 2177 | Loader { | 2119 | Loader { |
1011 | 2178 | 2120 | ||
1012 | === removed file 'src/app/webbrowser/KeyboardShortcut.qml' | |||
1013 | --- src/app/webbrowser/KeyboardShortcut.qml 2015-08-10 15:22:00 +0000 | |||
1014 | +++ src/app/webbrowser/KeyboardShortcut.qml 1970-01-01 00:00:00 +0000 | |||
1015 | @@ -1,25 +0,0 @@ | |||
1016 | 1 | /* | ||
1017 | 2 | * Copyright 2015 Canonical Ltd. | ||
1018 | 3 | * | ||
1019 | 4 | * This file is part of webbrowser-app. | ||
1020 | 5 | * | ||
1021 | 6 | * webbrowser-app is free software; you can redistribute it and/or modify | ||
1022 | 7 | * it under the terms of the GNU General Public License as published by | ||
1023 | 8 | * the Free Software Foundation; version 3. | ||
1024 | 9 | * | ||
1025 | 10 | * webbrowser-app is distributed in the hope that it will be useful, | ||
1026 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1027 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1028 | 13 | * GNU General Public License for more details. | ||
1029 | 14 | * | ||
1030 | 15 | * You should have received a copy of the GNU General Public License | ||
1031 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1032 | 17 | */ | ||
1033 | 18 | |||
1034 | 19 | import QtQuick 2.4 | ||
1035 | 20 | import Ubuntu.Components 1.3 | ||
1036 | 21 | |||
1037 | 22 | Action { | ||
1038 | 23 | property int key | ||
1039 | 24 | property int modifiers: Qt.NoModifier | ||
1040 | 25 | } | ||
1041 | 26 | 0 | ||
1042 | === removed file 'src/app/webbrowser/KeyboardShortcuts.qml' | |||
1043 | --- src/app/webbrowser/KeyboardShortcuts.qml 2015-08-10 15:22:00 +0000 | |||
1044 | +++ src/app/webbrowser/KeyboardShortcuts.qml 1970-01-01 00:00:00 +0000 | |||
1045 | @@ -1,41 +0,0 @@ | |||
1046 | 1 | /* | ||
1047 | 2 | * Copyright 2015 Canonical Ltd. | ||
1048 | 3 | * | ||
1049 | 4 | * This file is part of webbrowser-app. | ||
1050 | 5 | * | ||
1051 | 6 | * webbrowser-app is free software; you can redistribute it and/or modify | ||
1052 | 7 | * it under the terms of the GNU General Public License as published by | ||
1053 | 8 | * the Free Software Foundation; version 3. | ||
1054 | 9 | * | ||
1055 | 10 | * webbrowser-app is distributed in the hope that it will be useful, | ||
1056 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1057 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1058 | 13 | * GNU General Public License for more details. | ||
1059 | 14 | * | ||
1060 | 15 | * You should have received a copy of the GNU General Public License | ||
1061 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1062 | 17 | */ | ||
1063 | 18 | |||
1064 | 19 | import QtQuick 2.4 | ||
1065 | 20 | |||
1066 | 21 | Item { | ||
1067 | 22 | function processKey(key, modifiers) { | ||
1068 | 23 | for (var i = 0; i < data.length; i++) { | ||
1069 | 24 | var shortcut = data[i]; | ||
1070 | 25 | |||
1071 | 26 | if (!shortcut.enabled) continue | ||
1072 | 27 | if (key !== shortcut.key) continue | ||
1073 | 28 | |||
1074 | 29 | if (shortcut.modifiers === Qt.NoModifier) { | ||
1075 | 30 | if (modifiers === Qt.NoModifier) { | ||
1076 | 31 | shortcut.trigger() | ||
1077 | 32 | return true | ||
1078 | 33 | } | ||
1079 | 34 | } else if ((modifiers & shortcut.modifiers) === shortcut.modifiers) { | ||
1080 | 35 | shortcut.trigger() | ||
1081 | 36 | return true | ||
1082 | 37 | } | ||
1083 | 38 | } | ||
1084 | 39 | return false | ||
1085 | 40 | } | ||
1086 | 41 | } | ||
1087 | 42 | 0 | ||
1088 | === modified file 'src/app/webbrowser/ListViewHighlight.qml' | |||
1089 | --- src/app/webbrowser/ListViewHighlight.qml 2016-02-10 17:20:47 +0000 | |||
1090 | +++ src/app/webbrowser/ListViewHighlight.qml 2016-04-08 16:47:47 +0000 | |||
1091 | @@ -18,7 +18,7 @@ | |||
1092 | 18 | 18 | ||
1093 | 19 | import QtQuick 2.4 | 19 | import QtQuick 2.4 |
1094 | 20 | import Ubuntu.Components 1.3 | 20 | import Ubuntu.Components 1.3 |
1096 | 21 | import Unity.InputInfo 0.1 | 21 | import ".." |
1097 | 22 | 22 | ||
1098 | 23 | Rectangle { | 23 | Rectangle { |
1099 | 24 | color: "transparent" | 24 | color: "transparent" |
1100 | @@ -33,8 +33,7 @@ | |||
1101 | 33 | 33 | ||
1102 | 34 | readonly property bool hasKeyboard: keyboardModel.count > 0 | 34 | readonly property bool hasKeyboard: keyboardModel.count > 0 |
1103 | 35 | 35 | ||
1105 | 36 | InputDeviceModel { | 36 | FilteredKeyboardModel { |
1106 | 37 | id: keyboardModel | 37 | id: keyboardModel |
1107 | 38 | deviceFilter: InputInfo.Keyboard | ||
1108 | 39 | } | 38 | } |
1109 | 40 | } | 39 | } |
1110 | 41 | 40 | ||
1111 | === modified file 'src/app/webbrowser/NavigationBar.qml' | |||
1112 | --- src/app/webbrowser/NavigationBar.qml 2016-03-01 09:20:32 +0000 | |||
1113 | +++ src/app/webbrowser/NavigationBar.qml 2016-04-08 16:47:47 +0000 | |||
1114 | @@ -220,15 +220,18 @@ | |||
1115 | 220 | id: internal | 220 | id: internal |
1116 | 221 | property var openDrawer: null | 221 | property var openDrawer: null |
1117 | 222 | readonly property var webview: tab ? tab.webview : null | 222 | readonly property var webview: tab ? tab.webview : null |
1118 | 223 | } | ||
1119 | 223 | 224 | ||
1127 | 224 | onWebviewChanged: { | 225 | onTabChanged: { |
1128 | 225 | if (webview) { | 226 | if (tab) { |
1129 | 226 | addressbar.actualUrl = webview.url | 227 | addressbar.actualUrl = tab.url |
1130 | 227 | addressbar.securityStatus = webview.securityStatus | 228 | addressbar.securityStatus = (tab.webview ? tab.webview.securityStatus : null) |
1131 | 228 | } else { | 229 | if (!tab.url.toString() && editing) { |
1132 | 229 | addressbar.actualUrl = "" | 230 | addressbar.text = "" |
1126 | 230 | addressbar.securityStatus = null | ||
1133 | 231 | } | 231 | } |
1134 | 232 | } else { | ||
1135 | 233 | addressbar.actualUrl = "" | ||
1136 | 234 | addressbar.securityStatus = null | ||
1137 | 232 | } | 235 | } |
1138 | 233 | } | 236 | } |
1139 | 234 | 237 | ||
1140 | 235 | 238 | ||
1141 | === modified file 'tests/autopilot/webbrowser_app/tests/test_keyboard.py' | |||
1142 | --- tests/autopilot/webbrowser_app/tests/test_keyboard.py 2016-01-21 10:29:17 +0000 | |||
1143 | +++ tests/autopilot/webbrowser_app/tests/test_keyboard.py 2016-04-08 16:47:47 +0000 | |||
1144 | @@ -103,7 +103,7 @@ | |||
1145 | 103 | self.check_tab_number(2) | 103 | self.check_tab_number(2) |
1146 | 104 | self.main_window.press_key('Ctrl+Page_Down') | 104 | self.main_window.press_key('Ctrl+Page_Down') |
1147 | 105 | self.check_tab_number(0) | 105 | self.check_tab_number(0) |
1149 | 106 | self.main_window.press_key('Shift+Ctrl+Tab') | 106 | self.main_window.press_key('Ctrl+Shift+Tab') |
1150 | 107 | if self.main_window.wide: | 107 | if self.main_window.wide: |
1151 | 108 | self.check_tab_number(2) | 108 | self.check_tab_number(2) |
1152 | 109 | else: | 109 | else: |
1153 | @@ -493,3 +493,24 @@ | |||
1154 | 493 | 493 | ||
1155 | 494 | self.main_window.press_key('Ctrl+w') | 494 | self.main_window.press_key('Ctrl+w') |
1156 | 495 | self.assert_number_webviews_eventually(1) | 495 | self.assert_number_webviews_eventually(1) |
1157 | 496 | |||
1158 | 497 | def test_addressbar_cleared_when_opening_new_tab(self): | ||
1159 | 498 | # Verify that when opening a new tab while the address bar was focused, | ||
1160 | 499 | # the address bar is cleared. | ||
1161 | 500 | self.main_window.press_key('Ctrl+l') | ||
1162 | 501 | self.address_bar.activeFocus.wait_for(True) | ||
1163 | 502 | self.assertThat(self.address_bar.text, Eventually(Equals(self.url))) | ||
1164 | 503 | self.main_window.press_key('Ctrl+t') | ||
1165 | 504 | self.address_bar.activeFocus.wait_for(True) | ||
1166 | 505 | self.assertThat(self.address_bar.text, Eventually(Equals(""))) | ||
1167 | 506 | |||
1168 | 507 | def test_addressbar_cleared_when_switching_between_new_tabs(self): | ||
1169 | 508 | # Verify that when opening a new tab while a new tab was already open | ||
1170 | 509 | # with text input in the address bar, the address bar is cleared. | ||
1171 | 510 | self.main_window.press_key('Ctrl+t') | ||
1172 | 511 | self.address_bar.activeFocus.wait_for(True) | ||
1173 | 512 | self.assertThat(self.address_bar.text, Eventually(Equals(""))) | ||
1174 | 513 | self.address_bar.write("abc") | ||
1175 | 514 | self.main_window.press_key('Ctrl+t') | ||
1176 | 515 | self.address_bar.activeFocus.wait_for(True) | ||
1177 | 516 | self.assertThat(self.address_bar.text, Eventually(Equals(""))) | ||
1178 | 496 | 517 | ||
1179 | === modified file 'tests/autopilot/webbrowser_app/tests/test_private.py' | |||
1180 | --- tests/autopilot/webbrowser_app/tests/test_private.py 2016-01-21 10:29:17 +0000 | |||
1181 | +++ tests/autopilot/webbrowser_app/tests/test_private.py 2016-04-08 16:47:47 +0000 | |||
1182 | @@ -16,6 +16,7 @@ | |||
1183 | 16 | 16 | ||
1184 | 17 | from testtools.matchers import Equals, NotEquals | 17 | from testtools.matchers import Equals, NotEquals |
1185 | 18 | from autopilot.matchers import Eventually | 18 | from autopilot.matchers import Eventually |
1186 | 19 | from autopilot.platform import model | ||
1187 | 19 | 20 | ||
1188 | 20 | from webbrowser_app.tests import StartOpenRemotePageTestCaseBase | 21 | from webbrowser_app.tests import StartOpenRemotePageTestCaseBase |
1189 | 21 | 22 | ||
1190 | @@ -30,7 +31,7 @@ | |||
1191 | 30 | self.assert_number_incognito_webviews_eventually(1) | 31 | self.assert_number_incognito_webviews_eventually(1) |
1192 | 31 | self.assertTrue(self.main_window.is_new_private_tab_view_visible()) | 32 | self.assertTrue(self.main_window.is_new_private_tab_view_visible()) |
1193 | 32 | self.assertThat(address_bar.activeFocus, | 33 | self.assertThat(address_bar.activeFocus, |
1195 | 33 | Eventually(Equals(self.main_window.wide))) | 34 | Eventually(Equals(model() == 'Desktop'))) |
1196 | 34 | self.assertThat(address_bar.text, Eventually(Equals(""))) | 35 | self.assertThat(address_bar.text, Eventually(Equals(""))) |
1197 | 35 | 36 | ||
1198 | 36 | self.main_window.leave_private_mode() | 37 | self.main_window.leave_private_mode() |
FAILED: Continuous integration, rev:1389 jenkins. qa.ubuntu. com/job/ webbrowser- app-ci/ 2677/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 6789/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- amd64-ci/ 1430/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- armhf-ci/ 1430/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- i386-ci/ 1430/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 6800/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/webbrowser- app-ci/ 2677/rebuild
http://