Merge lp:~artmello/webbrowser-app/webbrowser-app-bookmarks_view into lp:webbrowser-app

Proposed by Arthur Mello
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 1242
Merged at revision: 1237
Proposed branch: lp:~artmello/webbrowser-app/webbrowser-app-bookmarks_view
Merge into: lp:webbrowser-app
Diff against target: 2039 lines (+1145/-440)
19 files modified
src/app/webbrowser/BookmarksFoldersView.qml (+42/-10)
src/app/webbrowser/BookmarksFoldersViewWide.qml (+226/-0)
src/app/webbrowser/BookmarksModelUtils.js (+27/-0)
src/app/webbrowser/BookmarksView.qml (+132/-0)
src/app/webbrowser/BookmarksViewWide.qml (+130/-0)
src/app/webbrowser/Browser.qml (+82/-3)
src/app/webbrowser/HistoryView.qml (+70/-83)
src/app/webbrowser/HistoryViewWide.qml (+1/-0)
src/app/webbrowser/NewTabView.qml (+4/-1)
src/app/webbrowser/NewTabViewWide.qml (+35/-180)
src/app/webbrowser/UrlDelegate.qml (+6/-1)
src/app/webbrowser/UrlDelegateWide.qml (+3/-3)
tests/autopilot/webbrowser_app/emulators/browser.py (+13/-2)
tests/autopilot/webbrowser_app/tests/__init__.py (+9/-0)
tests/autopilot/webbrowser_app/tests/test_bookmark_options.py (+16/-12)
tests/autopilot/webbrowser_app/tests/test_keyboard.py (+45/-0)
tests/autopilot/webbrowser_app/tests/test_new_tab_view.py (+47/-15)
tests/unittests/qml/tst_BookmarksFoldersViewWide.qml (+257/-0)
tests/unittests/qml/tst_NewTabViewWide.qml (+0/-130)
To merge this branch: bzr merge lp:~artmello/webbrowser-app/webbrowser-app-bookmarks_view
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Olivier Tilloy Approve
Ugo Riboni (community) Approve
Review via email: mp+270613@code.launchpad.net

Commit message

Add bookmarks view to top level menu

Description of the change

Add bookmarks view to top level menu

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ugo Riboni (uriboni) wrote :

- I can not get any favicon to load, even for sites that I just visited and have a favicon. The "globe" icon is always shown instead

- Open two browsers windows side by side and in one open the bookmarks view and in the other the history view:
  The styles of the two are not consistent with each other. If necessary speak with design about this, but I would change the following things:
  - In widescreen mode:
    - Use the same font as the history items for bookmark items
    - Use the same font as the dates in the history view for folders
    - The bookmarks view header should have a separator
    - The folder list items should have a separator
  - In non-widescreen mode:
    - The bookmarks view has an header, the history doesn't. I would add one to the history.
    - The folders in the bookmarks view should probably start all collapsed instead of all open, unless no folders exist.

review: Needs Fixing
Revision history for this message
Arthur Mello (artmello) wrote :

Thanks a lot for reviewing this. Comments bellow:

> - I can not get any favicon to load, even for sites that I just visited and
> have a favicon. The "globe" icon is always shown instead

I am not able to reproduce it, it seems to be working with old bookmarks and with new ones. How are you reproducing it? Some specific url domain?

> - Open two browsers windows side by side and in one open the bookmarks view
> and in the other the history view:
> The styles of the two are not consistent with each other. If necessary speak
> with design about this, but I would change the following things:
> - In widescreen mode:
> - Use the same font as the history items for bookmark items
> - Use the same font as the dates in the history view for folders

Fonts were the same, I set it to use the same fontSize. Let me know if it is better?

> - The bookmarks view header should have a separator
> - The folder list items should have a separator

Done

> - In non-widescreen mode:
> - The bookmarks view has an header, the history doesn't. I would add one
> to the history.

Since that would be a change on history view, what do you think of me doing this on a different MR?

> - The folders in the bookmarks view should probably start all collapsed
> instead of all open, unless no folders exist.

Done

Today we have URlDelegate and UrlDelegateWide with a lot of duplicate code, specially the one related with the url/title font. I didnt look further but would make sense to mix both those components on the same one? What do you think?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ugo Riboni (uriboni) wrote :

> Thanks a lot for reviewing this. Comments bellow:
>
> > - I can not get any favicon to load, even for sites that I just visited and
> > have a favicon. The "globe" icon is always shown instead
>
> I am not able to reproduce it, it seems to be working with old bookmarks and
> with new ones. How are you reproducing it? Some specific url domain?

It must have been my fault. It seems to be working OK now

The style of fonts and other visuals in the bookmarks window is now matching the style of fonts in the new tab view. Thanks for fixing this.

> > - In non-widescreen mode:
> > - The bookmarks view has an header, the history doesn't. I would add one
> > to the history.
>
> Since that would be a change on history view, what do you think of me doing
> this on a different MR?

It is OK to do it here, since it is a change with very little impact other than visuals. But I am happy to have it done in another MR if you prefer (though I won't be around to review it next week).

> > - The folders in the bookmarks view should probably start all collapsed
> > instead of all open, unless no folders exist.
>
> Done

Please add unit tests to ensure this works properly, and make sure this change did not break any AP or unit test.

> Today we have URlDelegate and UrlDelegateWide with a lot of duplicate code,
> specially the one related with the url/title font. I didnt look further but
> would make sense to mix both those components on the same one? What do you
> think?

I am happy to wait and do this in a separate MR. There is enough in this one already.

Other than this, there are lots of AP tests failing, and they seem to be related to bookmarks, so I suspect they are caused by your changes. Please check and make sure everything is passing (the infrastructure is OK at the moment, because most other branches pass all AP tests, so all AP errors are most likely caused by your changes).

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ugo Riboni (uriboni) wrote :

Thanks for the fixes, but there is still a couple of issues that should be addressed:

1) Please make sure the header of the history and bookmarks pages is the same size. Check this screenshot to see the difference: http://i.imgur.com/2a5oeuu.png

2) The divider line in narrow screen mode for the bookmarks and history is in the wrong place (there is white space below the line), as you can see here: http://i.imgur.com/i38zcKK.png

3) Can you please make sure that you added unit tests for this feature: "The folders in the [narrow screen mode] bookmarks view should start all collapsed, instead of all open, unless no folders exist." ?

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ugo Riboni (uriboni) wrote :

All good now. Thanks for the fixes!

review: Approve
Revision history for this message
Olivier Tilloy (osomon) wrote :

A remark on the visuals: in wide mode, I’m seeing a slightly darker gray band on the right of the view.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

In BookmarksFoldersView.qml, is the onActiveFocusChanged handler really needed? Given that the top-level item is a focus scope, simply setting 'focus: true' on bookmarksFolderListView should achieve the same result I think.

The same applies to BookmarksView.qml and BookmarksViewWide.qml, which should be made FocusScopes.

In BookmarksFoldersViewWide.qml, in restoreLastFocusedColumn() there is one extraneous blank line, please remove it.

The bookmarkEntryRemoved signal, in both versions of the bookmarks view, doesn’t seem to be useful, as the view already has a reference to the bookmarks model, so it could do the removal itself, and then call done().

The headers in bookmarks and history views shouldn’t be plain white. See the visual spec at https://docs.google.com/presentation/d/1P6A7ZsI03sPfuI9vzPeC0VcUfIgugxnU4QyObH6UNTs/edit#slide=id.gde1819d92_0_109.

In wide mode, the "all bookmarks" section always contains the homepage, as a hardcoded entry. In narrow mode, it doesn’t. Can we make the two views consistent, by displaying the homepage entry on both?

review: Needs Fixing
1184. By Arthur Mello

Merge with trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1185. By Arthur Mello

Remove darker gray band on the right of the view in wide mode.

1186. By Arthur Mello

Remove unnecessary onActiveFocusChanged handler

1187. By Arthur Mello

Make BookmarksView.qml and BookmarksViewWide.qml FocusScopes

1188. By Arthur Mello

Remove extraneous blank line

1189. By Arthur Mello

Simplify code when a Bookmark entry is removed in narrow mode

1190. By Arthur Mello

Simplify code when a Bookmark entry is removed in wide mode

1191. By Arthur Mello

Fix headers colors in bookmarks views

1192. By Arthur Mello

Fix headers colors in history views

1193. By Arthur Mello

Make the default homepage bookmark visible in all bookmarks views

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1194. By Arthur Mello

Fix AP tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1195. By Arthur Mello

Fix AP tests

1196. By Arthur Mello

Fix AP tests

Revision history for this message
Olivier Tilloy (osomon) wrote :

The changes to UrlsList.qml are meaningless when we’re not prepending a hardcoded entry to the list. And the names of the added properties ('defaultUrl' and 'defaultUrlTitle') are poorly chosen: this is not a default entry, it’s an additional one.

Anyway, you could achieve the same result by building a new model based on the bookmarks model + that additional entry (with a special flag to ensure it can’t be deleted).

Revision history for this message
Olivier Tilloy (osomon) wrote :

And what I’m suggesting above is actually what is already being done in BookmarksFoldersViewWide.qml (line 144).

1197. By Arthur Mello

Undo changes for Homepage default bookmark

1198. By Arthur Mello

Make the default homepage bookmark visible in all bookmarks views

1199. By Arthur Mello

Fix AP tests for new tab view

1200. By Arthur Mello

Fix AP tests for new tab view

1201. By Arthur Mello

Fix AP tests for bookmark options

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

If I press Ctrl+F while in the bookmarks view and then exit the view, the find-in-page mode has been activated in the current tab. This shortcut should be deactivated while in the bookmarks view. Hint: update the 'enabled' property of the corresponding KeyboardShortcut element.

Similarly, if I press Ctrl+L while in the bookmarks view, it looses focus and I can’t regain it. In general, please make sure that all the app’s keyboard shortcuts don’t have unintended effects while in the view.

A keyboard shortcut to open the view would be useful. Both chromium and firefox on desktop use Ctrl+Shift+O, so we could use that one too.

In UrlDelegate.qml, listActions doesn’t need to be a property of an internal QtObject, it can simply be defined as a child of the top-level item with an id, which you would refer to in the assignment of leadingActions.

In BookmarksView.qml, I don’t think we need to expose the entire settings object as a top-level property. Given that only the homepage setting is used (and in a read-only manner), can you expose just that one?

   property bool isHomeBookmark: folder === "" && index === 0
should reuse isAllBookmarksFolder instead of checking whether folder is empty again.

In general, please try and mark properties that won’t ever be written to with the 'readonly' keyword (such as isAllBookmarksFolder or isHomeBookmark.

And while we’re at it, in BookmarksFoldersView.qml the isHomeBookmark property is referenced only once, so its usefulness as a standalone property is questionable, you could simply transfer the condition to the assignment of 'removable'.

In test_set_bookmark_title, the need for an 'index' variable disappeared, you can simply hardcode the index in the assignment of the 'bookmark' variable.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1202. By Arthur Mello

Disable Ctrl+F when Bookmarks are visible

1203. By Arthur Mello

Disable reloading current tab when Bookmarks view is visible

1204. By Arthur Mello

Disable history navigation while Bookmarks view is visible

1205. By Arthur Mello

Disable toggle bookmarked state when bookmarks view is visible

1206. By Arthur Mello

Disable selecting the content in the address bar when Bookmarks is visible

1207. By Arthur Mello

Disable creating/closing tabs when bookmarks view is visible

1208. By Arthur Mello

Disable cycling through open tabs when bookmarks view is visible

1209. By Arthur Mello

Add Ctrl+Shift+O as a shortcut for Bookmarks

1210. By Arthur Mello

Simplify the way that listItemActions are defined on UrlDelegate

1211. By Arthur Mello

Do not expose the entire settings object to the bookmarks view

1212. By Arthur Mello

Reuse isAllBookmarksFolder to define isHomeBookmark property

1213. By Arthur Mello

Set properties as readonly

1214. By Arthur Mello

Simplify use of isHomeBookmark in BookmarksFoldersView

1215. By Arthur Mello

Remove unused variable in AP test

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

Instead of setting 'enabled' to 'chrome.visible && !bookmarksViewLoader.active' on most of the keyboard shortcuts, the visible property of the top-level FocusScope that contains tabContainer should be updated to be false when bookmarksViewLoader.active.
That way you wouldn’t have to update the enabled property of every single keyboard shortcut, and that would make for much easier maintenance.

Once done, please test all the keyboard shortcuts and ensure that they function only where intended. Please also add/update tests in tests/autopilot/webbrowser_app/tests/test_keyboard.py where relevant.

The Ctrl+T shortcut should be enabled while in the bookmarks view, to be consistent with the fact that the view has a "new tab" toolbar button. Of course opening a new tab should close the view.

review: Needs Fixing
1216. By Arthur Mello

Change the check to enable/disable keyboard shortcuts

1217. By Arthur Mello

Enable Ctrl+T to create a new tab when in bookmarks view

1218. By Arthur Mello

Fix wrong test to check if it is a removable bookmark

1219. By Arthur Mello

Add AP tests for bookmarks keyboard shortcuts

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

We’re getting there. Some additional comments:

In BookmarksFoldersView.qml and BookmarksFoldersViewWide.qml there is a very similar piece of code that builds a synthetic bookmarks model with a special entry prepended for the homepage. Can this please be factored out in a shared helper function?

In BookmarksView.qml and BookmarksViewWide.qml, it seems the import of webbrowserapp.private is unnecessary.

In Browser.qml, the signal handlers for the BookmarksView and the BookmarksViewWide instances are duplicated. Can you maybe use a Connections item to factor them out? I haven’t verified, would something like that work?
    Connections {
        target: bookmarksViewLoader.active ? bookmarksViewLoader.item : null
        onBookmarkEntryClicked: …
        onDone: …
    }

In the Ctrl+T KeyboardShortcut’s onTriggered, no need to check whether bookmarksViewLoader.active is true before setting it to false: if it was false already, this is a no-op.

While we’re at it, can you add support for the Ctrl+T shortcut in the history view, similarly to what you did for the bookmarks view?

In tests/autopilot/webbrowser_app/emulators/browser.py, there is no need for custom CPOs for BookmarksView and BookmarksViewWide if they don’t expose any custom methods/getters. In that case you can simply select by name with a string: in get_bookmarks_view, self.select_single("BookmarksView").

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1220. By Arthur Mello

Remove unused imports

1221. By Arthur Mello

Converge signal handlers for the BookmarksView to the same place

1222. By Arthur Mello

Change check for bookmarks view active on Ctrl+T shortcut
Make Ctrl+T shortcut work for History view and add an AP test

1223. By Arthur Mello

Remove custom CPOs for BookmarksView and BookmarksViewWide

1224. By Arthur Mello

Move code to add homepage to bookmarks model to a shared helper function

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

Comments on revision 1224:
 - In BookmarksModelUtils.js:
   * Is there really a use case for model==null? It looks like that check was in BookmarksFoldersViewWide.qml before, but it was not in BookmarksFoldersView.qml, so it doesn’t make sense to factor that bit out.
   * The docstring for the function isn’t correct, it’s not a temporary model (it would be temporary if it was instantiated, used and then deleted within the same scope). And there shouldn’t be a check for homeEntry==undefined. Calling that function with no home entry is useless and needlessly expensive, as it does a deep-copy of the already existing model.
   * Can we find a more expressive name for createUrlsListModel()? Maybe prependHomepageToBookmarks()?
 - As pointed out above, in BookmarksFoldersView.qml and BookmarksFoldersViewWide.qml, calling createUrlsListModel() without a homepage entry is useless, you should simply return the existing model.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

I’m seeing multiple autopilot failures when run locally on my desktop (at least 4 in test_bookmark_options, I haven’t run the entire test suite, please do).

review: Needs Fixing
1225. By Arthur Mello

Merge with trunk

1226. By Arthur Mello

Remove null model checkrom BookmarksModelUtils

1227. By Arthur Mello

Change docstring and function name for BookmarksModelUtils

1228. By Arthur Mello

Do not call utils function when not adding a homepage bookmark entry

1229. By Arthur Mello

Fix wrong remove

1230. By Arthur Mello

Fix AP tests

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

In BookmarksView.qml and BookmarksViewWide.qml, there are references to 'browser' (calls to browser.openUrlInNewTab). This breaks encapsulation. Please replace this with a signal emission that will be connected to in Browser.qml.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

In the Connections instance inside bookmarksViewLoader, the definition of 'target' doesn’t need to be conditional: if the loader is inactive, its item is null anyway.

Revision history for this message
Olivier Tilloy (osomon) wrote :

In the bookmarks view and in the new tab view in wide mode, pressing the right arrow key to move the focus to the right panel works when the first folder is currently highlighted, but not with other folders.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

(please add a test for the fix to the issue above)

1231. By Arthur Mello

Merge with trunk

1232. By Arthur Mello

Remove references to browser component from BookmarksView/BookmarksViewWide

1233. By Arthur Mello

Remove unnecesary check

1234. By Arthur Mello

Fix keyboard navigation

1235. By Arthur Mello

Expand unittest to BookmarksFoldersViewWide keyboa navigation

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1236. By Arthur Mello

Fix AP test issue

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

There are now conflicts when merging this branch into the latest trunk, can you please resolve them?

review: Needs Fixing
1237. By Arthur Mello

Merge with trunk

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

Please revert the changes to po/webbrowser-app.pot.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

Keyboard navigation appears to be broken in the bookmarks section of the wide new tab view.

review: Needs Fixing
1238. By Arthur Mello

Undo changes on po

1239. By Arthur Mello

Merge with trunk

1240. By Arthur Mello

Keep webbrowser-app.po from trunk

1241. By Arthur Mello

Fix NewTabViewWide keyboard navigation

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

In NewTabView.qml, there’s a modified line that has an extraneous trailing whitespace, can you please remove it?

1242. By Arthur Mello

Remove extraneous trailing whitespace

Revision history for this message
Olivier Tilloy (osomon) wrote :

Thanks, LGTM now.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'src/app/webbrowser/BookmarksFolderListView.qml' => 'src/app/webbrowser/BookmarksFoldersView.qml'
2--- src/app/webbrowser/BookmarksFolderListView.qml 2015-08-10 15:22:00 +0000
3+++ src/app/webbrowser/BookmarksFoldersView.qml 2015-10-16 15:16:36 +0000
4@@ -20,11 +20,14 @@
5 import Ubuntu.Components 1.3
6 import Ubuntu.Components.ListItems 1.3 as ListItem
7 import webbrowserapp.private 0.1
8+import "BookmarksModelUtils.js" as BookmarksModelUtils
9
10-Item {
11- id: bookmarksFolderListViewItem
12+FocusScope {
13+ id: bookmarksFoldersViewItem
14
15 property alias model: bookmarksFolderListModel.sourceModel
16+ property alias interactive: bookmarksFolderListView.interactive
17+ property url homeBookmarkUrl
18
19 signal bookmarkClicked(url url)
20 signal bookmarkRemoved(url url)
21@@ -39,6 +42,7 @@
22 id: bookmarksFolderListView
23 anchors.fill: parent
24 interactive: false
25+ focus: true
26
27 model: bookmarksFolderListModel
28 delegate: Loader {
29@@ -65,7 +69,7 @@
30 Column {
31 id: delegateColumn
32
33- property bool expanded: true
34+ property bool expanded: folderName ? false : true
35
36 anchors {
37 left: parent.left
38@@ -138,16 +142,44 @@
39 right: parent.right
40 }
41
42+ height: item ? item.contentHeight : 0
43+
44 visible: status == Loader.Ready
45
46 active: delegateColumn.expanded
47- sourceComponent: UrlsList {
48- spacing: 0
49-
50- model: entries
51-
52- onUrlClicked: bookmarksFolderListViewItem.bookmarkClicked(url)
53- onUrlRemoved: bookmarksFolderListViewItem.bookmarkRemoved(url)
54+ sourceComponent: ListView {
55+ readonly property bool isAllBookmarksFolder: folder === ""
56+
57+ interactive: false
58+
59+ model: {
60+ if (isAllBookmarksFolder) {
61+ return BookmarksModelUtils.prependHomepageToBookmarks(entries, {
62+ title: i18n.tr("Homepage"),
63+ url: bookmarksFoldersViewItem.homeBookmarkUrl
64+ })
65+ }
66+
67+ return entries
68+ }
69+
70+ delegate: UrlDelegate{
71+ id: urlDelegate
72+
73+ property var entry: isAllBookmarksFolder ? modelData : model
74+
75+ width: parent.width
76+ height: units.gu(5)
77+
78+ removable: !isAllBookmarksFolder || index !== 0
79+
80+ icon: entry.icon ? entry.icon : ""
81+ title: entry.title ? entry.title : entry.url
82+ url: entry.url
83+
84+ onClicked: bookmarksFoldersViewItem.bookmarkClicked(url)
85+ onRemoved: bookmarksFoldersViewItem.bookmarkRemoved(url)
86+ }
87 }
88 }
89 }
90
91=== added file 'src/app/webbrowser/BookmarksFoldersViewWide.qml'
92--- src/app/webbrowser/BookmarksFoldersViewWide.qml 1970-01-01 00:00:00 +0000
93+++ src/app/webbrowser/BookmarksFoldersViewWide.qml 2015-10-16 15:16:36 +0000
94@@ -0,0 +1,226 @@
95+/*
96+ * Copyright 2015 Canonical Ltd.
97+ *
98+ * This file is part of webbrowser-app.
99+ *
100+ * webbrowser-app is free software; you can redistribute it and/or modify
101+ * it under the terms of the GNU General Public License as published by
102+ * the Free Software Foundation; version 3.
103+ *
104+ * webbrowser-app is distributed in the hope that it will be useful,
105+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
106+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
107+ * GNU General Public License for more details.
108+ *
109+ * You should have received a copy of the GNU General Public License
110+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
111+ */
112+
113+import QtQuick 2.4
114+import Ubuntu.Components 1.3
115+import webbrowserapp.private 0.1
116+import "BookmarksModelUtils.js" as BookmarksModelUtils
117+
118+FocusScope {
119+ id: bookmarksFoldersViewWideItem
120+
121+ property alias model: bookmarksFolderListModel.sourceModel
122+ property url homeBookmarkUrl
123+
124+ signal bookmarkClicked(url url)
125+ signal bookmarkRemoved(url url)
126+ signal dragStarted()
127+
128+ function restoreLastFocusedColumn() {
129+ if (internal.lastFocusedColumn &&
130+ internal.lastFocusedColumn == bookmarksList &&
131+ model.count > 0) {
132+ bookmarksList.forceActiveFocus()
133+ } else {
134+ folders.forceActiveFocus()
135+ }
136+ }
137+
138+ onActiveFocusChanged: {
139+ if (activeFocus) {
140+ restoreLastFocusedColumn()
141+ }
142+ }
143+
144+ Rectangle {
145+ anchors.fill: parent
146+ color: "#fbfbfb"
147+ }
148+
149+ ListView {
150+ id: folders
151+ objectName: "foldersList"
152+
153+ anchors {
154+ top: parent.top
155+ bottom: parent.bottom
156+ left: parent.left
157+ }
158+
159+ width: units.gu(25)
160+
161+ onActiveFocusChanged: {
162+ if (activeFocus) {
163+ internal.lastFocusedColumn = folders
164+ }
165+ }
166+
167+ model: BookmarksFolderListModel {
168+ id: bookmarksFolderListModel
169+ }
170+ currentIndex: 0
171+
172+ Keys.onRightPressed: {
173+ if (!folders.currentItem) {
174+ return
175+ }
176+
177+ if ((folders.currentItem.isAllBookmarksFolder && bookmarksList.model.length > 0) || bookmarksList.model.count > 0) {
178+ bookmarksList.focus = true
179+ }
180+ }
181+
182+ delegate: ListItem {
183+ id: folderItem
184+ objectName: "folderItem"
185+
186+ property alias name: dropArea.folderName
187+ property var model: entries
188+ readonly property bool isActiveFolder: ListView.isCurrentItem
189+ readonly property bool isAllBookmarksFolder: folder.length === 0
190+ readonly property bool isCurrentDropTarget: dropArea.containsDrag && dropArea.drag.source.folder !== folder
191+
192+ color: isCurrentDropTarget ? "green" :
193+ ((folders.activeFocus && isActiveFolder) ? Qt.rgba(0, 0, 0, 0.05) : "transparent")
194+
195+ Label {
196+ anchors {
197+ verticalCenter: parent.verticalCenter
198+ left: parent.left
199+ right: parent.right
200+ leftMargin: units.gu(2)
201+ rightMargin: units.gu(2)
202+ }
203+
204+ fontSize: "small"
205+ text: isAllBookmarksFolder ? i18n.tr("All Bookmarks") : folderItem.name
206+ color: isActiveFolder ? UbuntuColors.orange : UbuntuColors.darkGrey
207+ }
208+
209+ onClicked: folders.currentIndex = index
210+
211+ DropArea {
212+ id: dropArea
213+
214+ property string folderName: folder
215+ anchors.fill: parent
216+ }
217+ }
218+ }
219+
220+ Scrollbar {
221+ flickableItem: folders
222+ }
223+
224+ ListView {
225+ id: bookmarksList
226+ objectName: "bookmarksList"
227+
228+ anchors {
229+ top: parent.top
230+ bottom: parent.bottom
231+ left: folders.right
232+ right: parent.right
233+ }
234+
235+ onActiveFocusChanged: {
236+ if (activeFocus) {
237+ internal.lastFocusedColumn = bookmarksList
238+ }
239+ }
240+
241+ model: {
242+ if (!folders.currentItem || !folders.currentItem.model) {
243+ return null
244+ }
245+
246+ if (folders.currentItem.isAllBookmarksFolder) {
247+ return BookmarksModelUtils.prependHomepageToBookmarks(folders.currentItem.model, {
248+ title: i18n.tr("Homepage"),
249+ url: bookmarksFoldersViewWideItem.homeBookmarkUrl,
250+ folder: ""
251+ })
252+ }
253+
254+ return folders.currentItem.model
255+ }
256+
257+ currentIndex: 0
258+
259+ delegate: DraggableUrlDelegateWide {
260+ objectName: "bookmarkItem"
261+
262+ property var entry: folders.currentItem.isAllBookmarksFolder ? modelData : model
263+ property string folder: entry.folder
264+ readonly property bool isHomeBookmark: folder === "" && index === 0
265+
266+ clip: true
267+ title: entry.title
268+ icon: entry.icon ? entry.icon : ""
269+ url: entry.url
270+
271+ removable: !isHomeBookmark
272+ draggable: !isHomeBookmark && contentItem.x === 0
273+ highlighted: bookmarksList.activeFocus && ListView.isCurrentItem
274+
275+ onClicked: bookmarksFoldersViewWideItem.bookmarkClicked(url)
276+ onRemoved: bookmarksFoldersViewWideItem.bookmarkRemoved(url)
277+
278+ // Larger margin to prevent interference from Scrollbar hovering area
279+ gripMargin: units.gu(4)
280+ onDragStarted: {
281+ // Remove interactivity to prevent the list from scrolling
282+ // while dragging near its margins. This ensures we can correctly
283+ // return the item to its original position on a failed drop.
284+ bookmarksList.interactive = false
285+
286+ bookmarksFoldersViewWideItem.dragStarted()
287+ }
288+ onDragEnded: {
289+ bookmarksList.interactive = true
290+
291+ if (dragAndDrop.target && dragAndDrop.target.folderName !== folder) {
292+ bookmarksFoldersViewWideItem.model.update(entry.url, entry.title,
293+ dragAndDrop.target.folderName)
294+ dragAndDrop.success = true
295+ }
296+ }
297+ }
298+
299+ Keys.onReturnPressed: bookmarksFoldersViewWideItem.bookmarkClicked(currentItem.url)
300+ Keys.onDeletePressed: {
301+ if (currentItem.removable) {
302+ bookmarksFoldersViewWideItem.bookmarkRemoved(currentItem.url)
303+ if (bookmarksList.model.length === 0) {
304+ folders.focus = true
305+ }
306+ }
307+ }
308+ Keys.onLeftPressed: folders.focus = true
309+ }
310+
311+ Scrollbar {
312+ flickableItem: bookmarksList
313+ }
314+
315+ QtObject {
316+ id: internal
317+
318+ property var lastFocusedColumn: folders
319+ }
320+}
321
322=== added file 'src/app/webbrowser/BookmarksModelUtils.js'
323--- src/app/webbrowser/BookmarksModelUtils.js 1970-01-01 00:00:00 +0000
324+++ src/app/webbrowser/BookmarksModelUtils.js 2015-10-16 15:16:36 +0000
325@@ -0,0 +1,27 @@
326+/*
327+ * Copyright 2015 Canonical Ltd.
328+ *
329+ * This file is part of webbrowser-app.
330+ *
331+ * webbrowser-app is free software; you can redistribute it and/or modify
332+ * it under the terms of the GNU General Public License as published by
333+ * the Free Software Foundation; version 3.
334+ *
335+ * webbrowser-app is distributed in the hope that it will be useful,
336+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
337+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
338+ * GNU General Public License for more details.
339+ *
340+ * You should have received a copy of the GNU General Public License
341+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
342+ */
343+
344+/* Prepend the homepage bookmark item to bookmarks model */
345+function prependHomepageToBookmarks(model, homeEntry) {
346+ var items = []
347+ items.push(homeEntry)
348+ for (var i = 0; i < model.count; i++) {
349+ items.push(model.get(i))
350+ }
351+ return items
352+}
353
354=== added file 'src/app/webbrowser/BookmarksView.qml'
355--- src/app/webbrowser/BookmarksView.qml 1970-01-01 00:00:00 +0000
356+++ src/app/webbrowser/BookmarksView.qml 2015-10-16 15:16:36 +0000
357@@ -0,0 +1,132 @@
358+/*
359+ * Copyright 2015 Canonical Ltd.
360+ *
361+ * This file is part of webbrowser-app.
362+ *
363+ * webbrowser-app is free software; you can redistribute it and/or modify
364+ * it under the terms of the GNU General Public License as published by
365+ * the Free Software Foundation; version 3.
366+ *
367+ * webbrowser-app is distributed in the hope that it will be useful,
368+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
369+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
370+ * GNU General Public License for more details.
371+ *
372+ * You should have received a copy of the GNU General Public License
373+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
374+ */
375+
376+import QtQuick 2.4
377+import Ubuntu.Components 1.3
378+import Ubuntu.Components.ListItems 1.3 as ListItems
379+
380+FocusScope {
381+ id: bookmarksView
382+
383+ property alias bookmarksModel: bookmarksFoldersView.model
384+ property alias homepageUrl: bookmarksFoldersView.homeBookmarkUrl
385+
386+ signal bookmarkEntryClicked(url url)
387+ signal done()
388+ signal newTabClicked()
389+
390+ Rectangle {
391+ anchors.fill: parent
392+ color: "#f6f6f6"
393+ }
394+
395+ BookmarksFoldersView {
396+ id: bookmarksFoldersView
397+
398+ anchors {
399+ top: topBar.bottom
400+ left: parent.left
401+ right: parent.right
402+ bottom: toolbar.top
403+ rightMargin: units.gu(2)
404+ }
405+
406+ interactive: true
407+ focus: true
408+
409+ onBookmarkClicked: bookmarksView.bookmarkEntryClicked(url)
410+ onBookmarkRemoved: {
411+ if (bookmarksModel.count == 1) {
412+ done()
413+ }
414+ bookmarksModel.remove(url)
415+ }
416+ }
417+
418+ Toolbar {
419+ id: topBar
420+
421+ height: units.gu(7)
422+ color: "#f7f7f7"
423+
424+ anchors {
425+ left: parent.left
426+ right: parent.right
427+ top: parent.top
428+ }
429+
430+ Label {
431+ anchors {
432+ top: parent.top
433+ left: parent.left
434+ topMargin: units.gu(2)
435+ leftMargin: units.gu(2)
436+ }
437+
438+ text: i18n.tr("Bookmarks")
439+ }
440+
441+ ListItems.ThinDivider {
442+ anchors {
443+ left: parent.left
444+ right: parent.right
445+ bottom: parent.bottom
446+ }
447+ }
448+ }
449+
450+ Toolbar {
451+ id: toolbar
452+ height: units.gu(7)
453+
454+ anchors {
455+ left: parent.left
456+ right: parent.right
457+ bottom: parent.bottom
458+ }
459+
460+ Button {
461+ objectName: "doneButton"
462+ anchors {
463+ left: parent.left
464+ leftMargin: units.gu(2)
465+ verticalCenter: parent.verticalCenter
466+ }
467+
468+ strokeColor: UbuntuColors.darkGrey
469+
470+ text: i18n.tr("Done")
471+
472+ onClicked: bookmarksView.done()
473+ }
474+
475+ ToolbarAction {
476+ anchors {
477+ right: parent.right
478+ rightMargin: units.gu(2)
479+ verticalCenter: parent.verticalCenter
480+ }
481+ height: parent.height - units.gu(2)
482+
483+ text: i18n.tr("New tab")
484+ iconName: "tab-new"
485+
486+ onClicked: bookmarksView.newTabClicked()
487+ }
488+ }
489+}
490
491=== added file 'src/app/webbrowser/BookmarksViewWide.qml'
492--- src/app/webbrowser/BookmarksViewWide.qml 1970-01-01 00:00:00 +0000
493+++ src/app/webbrowser/BookmarksViewWide.qml 2015-10-16 15:16:36 +0000
494@@ -0,0 +1,130 @@
495+/*
496+ * Copyright 2015 Canonical Ltd.
497+ *
498+ * This file is part of webbrowser-app.
499+ *
500+ * webbrowser-app is free software; you can redistribute it and/or modify
501+ * it under the terms of the GNU General Public License as published by
502+ * the Free Software Foundation; version 3.
503+ *
504+ * webbrowser-app is distributed in the hope that it will be useful,
505+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
506+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
507+ * GNU General Public License for more details.
508+ *
509+ * You should have received a copy of the GNU General Public License
510+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
511+ */
512+
513+import QtQuick 2.4
514+import Ubuntu.Components 1.3
515+import Ubuntu.Components.ListItems 1.3 as ListItems
516+
517+FocusScope {
518+ id: bookmarksViewWide
519+
520+ property alias bookmarksModel: bookmarksFoldersViewWide.model
521+ property alias homepageUrl: bookmarksFoldersViewWide.homeBookmarkUrl
522+
523+ signal bookmarkEntryClicked(url url)
524+ signal done()
525+ signal newTabClicked()
526+
527+ Rectangle {
528+ anchors.fill: parent
529+ color: "#f6f6f6"
530+ }
531+
532+ BookmarksFoldersViewWide {
533+ id: bookmarksFoldersViewWide
534+
535+ anchors {
536+ top: topBar.bottom
537+ left: parent.left
538+ right: parent.right
539+ bottom: toolbar.top
540+ }
541+
542+ focus: true
543+
544+ onBookmarkClicked: bookmarksViewWide.bookmarkEntryClicked(url)
545+ onBookmarkRemoved: {
546+ if (bookmarksModel.count == 1) {
547+ done()
548+ }
549+ bookmarksModel.remove(url)
550+ }
551+ }
552+
553+ Toolbar {
554+ id: topBar
555+
556+ height: units.gu(7)
557+ color: "#f7f7f7"
558+
559+ anchors {
560+ left: parent.left
561+ right: parent.right
562+ top: parent.top
563+ }
564+
565+ Label {
566+ anchors {
567+ top: parent.top
568+ left: parent.left
569+ topMargin: units.gu(2)
570+ leftMargin: units.gu(2)
571+ }
572+
573+ text: i18n.tr("Bookmarks")
574+ }
575+
576+ ListItems.ThinDivider {
577+ anchors {
578+ left: parent.left
579+ right: parent.right
580+ bottom: parent.bottom
581+ }
582+ }
583+ }
584+
585+ Toolbar {
586+ id: toolbar
587+ height: units.gu(7)
588+
589+ anchors {
590+ left: parent.left
591+ right: parent.right
592+ bottom: parent.bottom
593+ }
594+
595+ Button {
596+ objectName: "doneButton"
597+ anchors {
598+ left: parent.left
599+ leftMargin: units.gu(2)
600+ verticalCenter: parent.verticalCenter
601+ }
602+
603+ strokeColor: UbuntuColors.darkGrey
604+
605+ text: i18n.tr("Done")
606+
607+ onClicked: bookmarksViewWide.done()
608+ }
609+
610+ ToolbarAction {
611+ anchors {
612+ right: parent.right
613+ rightMargin: units.gu(2)
614+ verticalCenter: parent.verticalCenter
615+ }
616+ height: parent.height - units.gu(2)
617+
618+ text: i18n.tr("New tab")
619+ iconName: "tab-new"
620+
621+ onClicked: bookmarksViewWide.newTabClicked()
622+ }
623+ }
624+}
625
626=== modified file 'src/app/webbrowser/Browser.qml'
627--- src/app/webbrowser/Browser.qml 2015-10-13 12:57:33 +0000
628+++ src/app/webbrowser/Browser.qml 2015-10-16 15:16:36 +0000
629@@ -140,7 +140,7 @@
630
631 FocusScope {
632 anchors.fill: parent
633- visible: !settingsContainer.visible && !historyViewLoader.active
634+ visible: !settingsContainer.visible && !historyViewLoader.active && !bookmarksViewLoader.active
635
636 TabChrome {
637 id: invisibleTabChrome
638@@ -368,6 +368,13 @@
639 onTriggered: internal.shareLink(browser.currentWebview.url, browser.currentWebview.title)
640 },
641 Action {
642+ objectName: "bookmarks"
643+ text: i18n.tr("Bookmarks")
644+ iconName: "bookmark"
645+ enabled: browser.bookmarksModel
646+ onTriggered: bookmarksViewLoader.active = true
647+ },
648+ Action {
649 objectName: "history"
650 text: i18n.tr("History")
651 iconName: "history"
652@@ -759,6 +766,67 @@
653 }
654
655 Loader {
656+ id: bookmarksViewLoader
657+
658+ anchors.fill: parent
659+ active: false
660+ sourceComponent: browser.wide ? bookmarksViewWideComponent : bookmarksViewComponent
661+
662+ onStatusChanged: {
663+ if (status == Loader.Ready) {
664+ bookmarksViewTimer.restart()
665+ bookmarksViewLoader.item.forceActiveFocus()
666+ } else {
667+ internal.resetFocus()
668+ }
669+ }
670+
671+ Keys.onEscapePressed: bookmarksViewLoader.active = false
672+
673+ Connections {
674+ target: bookmarksViewLoader.item
675+
676+ onBookmarkEntryClicked: {
677+ browser.openUrlInNewTab(url, true)
678+ bookmarksViewLoader.active = false
679+ }
680+ onDone: bookmarksViewLoader.active = false
681+ onNewTabClicked: {
682+ browser.openUrlInNewTab("", true)
683+ bookmarksViewLoader.active = false
684+ }
685+ }
686+
687+ Timer {
688+ id: bookmarksViewTimer
689+ // Set the model asynchronously to ensure
690+ // the view is displayed as early as possible.
691+ interval: 1
692+ onTriggered: bookmarksViewLoader.item.bookmarksModel = browser.bookmarksModel
693+ }
694+
695+ Component {
696+ id: bookmarksViewComponent
697+
698+ BookmarksView {
699+ anchors.fill: parent
700+
701+ homepageUrl: settings.homepage
702+ }
703+ }
704+
705+ Component {
706+ id: bookmarksViewWideComponent
707+
708+ BookmarksViewWide {
709+ anchors.fill: parent
710+
711+ homepageUrl: settings.homepage
712+ }
713+ }
714+ }
715+
716+ Loader {
717 id: historyViewLoader
718
719 anchors.fill: parent
720@@ -1653,10 +1721,13 @@
721 KeyboardShortcut {
722 modifiers: Qt.ControlModifier
723 key: Qt.Key_T
724- enabled: chrome.visible || recentView.visible
725+ enabled: chrome.visible || recentView.visible || bookmarksViewLoader.active || historyViewLoader.active
726 onTriggered: {
727 openUrlInNewTab("", true)
728 if (recentView.visible) recentView.reset()
729+
730+ bookmarksViewLoader.active = false
731+ historyViewLoader.active = false
732 }
733 }
734
735@@ -1703,6 +1774,14 @@
736 onTriggered: historyViewLoader.active = true
737 }
738
739+ // Ctrl+Shift+O: Show Bookmarks
740+ KeyboardShortcut {
741+ modifiers: Qt.ControlModifier | Qt.ShiftModifier
742+ key: Qt.Key_O
743+ enabled: chrome.visible
744+ onTriggered: bookmarksViewLoader.active = true
745+ }
746+
747 // Alt+← or Backspace: Goes to the previous page in history
748 KeyboardShortcut {
749 modifiers: Qt.AltModifier
750@@ -1747,7 +1826,7 @@
751 KeyboardShortcut {
752 modifiers: Qt.ControlModifier
753 key: Qt.Key_F
754- enabled: !newTabViewLoader.active
755+ enabled: !newTabViewLoader.active && !bookmarksViewLoader.active
756 onTriggered: {
757 chrome.findInPageMode = true
758 chrome.focus = true
759
760=== modified file 'src/app/webbrowser/HistoryView.qml'
761--- src/app/webbrowser/HistoryView.qml 2015-08-31 12:50:16 +0000
762+++ src/app/webbrowser/HistoryView.qml 2015-10-16 15:16:36 +0000
763@@ -18,6 +18,7 @@
764
765 import QtQuick 2.4
766 import Ubuntu.Components 1.3
767+import Ubuntu.Components.ListItems 1.3 as ListItems
768 import webbrowserapp.private 0.1
769
770 Item {
771@@ -136,11 +137,12 @@
772 }
773 }
774
775- Item {
776+ Toolbar {
777 id: topBar
778
779 visible: domainsListView.ViewItems.selectMode
780- height: visible ? units.gu(5) : 0
781+ height: visible ? units.gu(7) : 0
782+ color: "#f7f7f7"
783
784 Behavior on height {
785 UbuntuNumberAnimation {}
786@@ -152,91 +154,76 @@
787 top: parent.top
788 }
789
790- Rectangle {
791- width: parent.width
792- height: parent.height + units.gu(1.5)
793- color: "white"
794- }
795-
796- Item {
797+ ToolbarAction {
798+ iconName: "close"
799+ text: i18n.tr("Cancel")
800+
801+ onClicked: domainsListView.ViewItems.selectMode = false
802+
803 anchors {
804- top: parent.top
805 left: parent.left
806 leftMargin: units.gu(2)
807+ }
808+
809+ height: parent.height - units.gu(2)
810+ }
811+
812+ ToolbarAction {
813+ iconName: "select"
814+ text: i18n.tr("Select all")
815+
816+ onClicked: {
817+ if (domainsListView.ViewItems.selectedIndices.length === domainsListView.count) {
818+ domainsListView.ViewItems.selectedIndices = []
819+ } else {
820+ var indices = []
821+ for (var i = 0; i < domainsListView.count; ++i) {
822+ indices.push(i)
823+ }
824+ domainsListView.ViewItems.selectedIndices = indices
825+ }
826+ }
827+
828+ anchors {
829+ right: deleteButton.left
830+ rightMargin: units.gu(2)
831+ }
832+
833+ height: parent.height - units.gu(2)
834+ }
835+
836+ ToolbarAction {
837+ id: deleteButton
838+
839+ iconName: "delete"
840+ text: i18n.tr("Delete")
841+ enabled: domainsListView.ViewItems.selectedIndices.length > 0
842+
843+ onClicked: {
844+ var indices = domainsListView.ViewItems.selectedIndices
845+ var domains = []
846+ for (var i in indices) {
847+ domains.push(domainsListView.model.get(indices[i]))
848+ }
849+ domainsListView.ViewItems.selectMode = false
850+ for (var j in domains) {
851+ HistoryModel.removeEntriesByDomain(domains[j])
852+ }
853+ }
854+
855+ anchors {
856+ right: parent.right
857+ rightMargin: units.gu(2)
858+ }
859+
860+ height: parent.height - units.gu(2)
861+ }
862+
863+ ListItems.ThinDivider {
864+ anchors {
865+ left: parent.left
866+ right: parent.right
867 bottom: parent.bottom
868- right: parent.right
869- rightMargin: units.gu(2)
870- }
871-
872- ToolbarAction {
873- iconName: "close"
874- text: i18n.tr("Cancel")
875-
876- MouseArea {
877- anchors.fill: parent
878- onClicked: domainsListView.ViewItems.selectMode = false
879- }
880-
881- anchors.left: parent.left
882-
883- height: parent.height
884- width: height
885- }
886-
887- ToolbarAction {
888- iconName: "select"
889- text: i18n.tr("Select all")
890-
891- MouseArea {
892- anchors.fill: parent
893- onClicked: {
894- if (domainsListView.ViewItems.selectedIndices.length === domainsListView.count) {
895- domainsListView.ViewItems.selectedIndices = []
896- } else {
897- var indices = []
898- for (var i = 0; i < domainsListView.count; ++i) {
899- indices.push(i)
900- }
901- domainsListView.ViewItems.selectedIndices = indices
902- }
903- }
904- }
905-
906- anchors {
907- right: deleteButton.left
908- rightMargin: units.gu(2)
909- }
910-
911- height: parent.height
912- width: height
913- }
914-
915- ToolbarAction {
916- id: deleteButton
917-
918- iconName: "delete"
919- text: i18n.tr("Delete")
920- enabled: domainsListView.ViewItems.selectedIndices.length > 0
921-
922- MouseArea {
923- anchors.fill: parent
924- onClicked: {
925- var indices = domainsListView.ViewItems.selectedIndices
926- var domains = []
927- for (var i in indices) {
928- domains.push(domainsListView.model.get(indices[i]))
929- }
930- domainsListView.ViewItems.selectMode = false
931- for (var j in domains) {
932- HistoryModel.removeEntriesByDomain(domains[j])
933- }
934- }
935- }
936-
937- anchors.right: parent.right
938-
939- height: parent.height
940- width: height
941 }
942 }
943 }
944
945=== modified file 'src/app/webbrowser/HistoryViewWide.qml'
946--- src/app/webbrowser/HistoryViewWide.qml 2015-10-08 08:50:59 +0000
947+++ src/app/webbrowser/HistoryViewWide.qml 2015-10-16 15:16:36 +0000
948@@ -346,6 +346,7 @@
949 id: topBar
950
951 height: units.gu(7)
952+ color: "#f7f7f7"
953
954 anchors {
955 left: parent.left
956
957=== modified file 'src/app/webbrowser/NewTabView.qml'
958--- src/app/webbrowser/NewTabView.qml 2015-10-12 12:00:35 +0000
959+++ src/app/webbrowser/NewTabView.qml 2015-10-16 15:16:36 +0000
960@@ -148,9 +148,12 @@
961 height: status == Loader.Ready ? item.height : 0
962
963 active: internal.seeMoreBookmarksView
964- sourceComponent: BookmarksFolderListView {
965+
966+ sourceComponent: BookmarksFoldersView {
967 model: newTabView.bookmarksModel
968
969+ homeBookmarkUrl: newTabView.settingsObject.homepage
970+
971 onBookmarkClicked: newTabView.bookmarkClicked(url)
972 onBookmarkRemoved: newTabView.bookmarkRemoved(url)
973 }
974
975=== modified file 'src/app/webbrowser/NewTabViewWide.qml'
976--- src/app/webbrowser/NewTabViewWide.qml 2015-10-05 10:10:29 +0000
977+++ src/app/webbrowser/NewTabViewWide.qml 2015-10-16 15:16:36 +0000
978@@ -26,7 +26,7 @@
979 FocusScope {
980 id: newTabViewWide
981
982- property QtObject bookmarksModel
983+ property alias bookmarksModel: bookmarksFoldersViewWide.model
984 property QtObject settingsObject
985 property alias selectedIndex: sections.selectedIndex
986 readonly property bool inBookmarksView: newTabViewWide.selectedIndex === 1
987@@ -41,13 +41,10 @@
988 onActiveFocusChanged: {
989 if (activeFocus) {
990 if (inBookmarksView) {
991- if (sections.lastFocusedBookmarksColumn === bookmarksList &&
992- bookmarksList.model.length === 0) {
993- sections.lastFocusedBookmarksColumn = folders
994- }
995- sections.lastFocusedBookmarksColumn.focus = true
996+ bookmarksFoldersViewWide.restoreLastFocusedColumn()
997+ } else {
998+ topSitesList.focus = true
999 }
1000- else topSitesList.focus = true
1001 }
1002 }
1003
1004@@ -62,178 +59,38 @@
1005 }
1006 }
1007
1008+ BookmarksFoldersViewWide {
1009+ id: bookmarksFoldersViewWide
1010+
1011+ Keys.onUpPressed: newTabViewWide.releasingKeyboardFocus()
1012+ onBookmarkClicked: newTabViewWide.bookmarkClicked(url)
1013+ onBookmarkRemoved: newTabViewWide.bookmarkRemoved(url)
1014+
1015+ // Relinquish focus as the presses and releases that compose the
1016+ // drag will move the keyboard focus in a location unexpected
1017+ // for the user. This way it will go back to the address bar and
1018+ // the user can predictably resume keyboard interaction from there.
1019+ onDragStarted: newTabViewWide.releasingKeyboardFocus()
1020+
1021+ anchors {
1022+ top: sectionsGroup.bottom
1023+ left: parent.left
1024+ right: parent.right
1025+ bottom: parent.bottom
1026+ topMargin: units.gu(2)
1027+ rightMargin: units.gu(2)
1028+ }
1029+
1030+ visible: inBookmarksView
1031+ homeBookmarkUrl: newTabViewWide.settingsObject.homepage
1032+ }
1033+
1034 Rectangle {
1035 anchors.fill: parent
1036+ visible: !inBookmarksView
1037 color: "#fbfbfb"
1038 }
1039
1040- ListView {
1041- id: folders
1042- objectName: "foldersList"
1043- visible: inBookmarksView
1044-
1045- Keys.onRightPressed: if (bookmarksList.model.length > 0) bookmarksList.focus = true
1046- Keys.onDownPressed: currentIndex = Math.min(currentIndex + 1, folders.model.count - 1)
1047- Keys.onUpPressed: {
1048- if (currentIndex > 0) currentIndex = Math.max(currentIndex - 1, 0)
1049- else newTabViewWide.releasingKeyboardFocus()
1050- }
1051- onActiveFocusChanged: {
1052- if (activeFocus) {
1053- sections.lastFocusedBookmarksColumn = folders
1054- if (currentIndex < 0) currentIndex = 0
1055- }
1056- }
1057-
1058- anchors {
1059- top: sectionsGroup.bottom
1060- bottom: parent.bottom
1061- left: parent.left
1062- topMargin: units.gu(2)
1063- }
1064- width: units.gu(25)
1065-
1066- currentIndex: 0
1067- model: BookmarksFolderListModel {
1068- sourceModel: newTabViewWide.bookmarksModel
1069- }
1070-
1071- delegate: ListItem {
1072- id: folderItem
1073- objectName: "folderItem"
1074- property var model: entries
1075- property bool isActiveFolder: ListView.isCurrentItem
1076- property bool isCurrentItem: ListView.isCurrentItem
1077- property bool isAllBookmarksFolder: folder.length === 0
1078- property alias name: dropArea.folderName
1079- divider.visible: false
1080-
1081- property bool isCurrentDropTarget: dropArea.containsDrag && dropArea.drag.source.folder !== folder
1082- color: isCurrentDropTarget ? "green" :
1083- ((folders.activeFocus && isActiveFolder) ? Qt.rgba(0, 0, 0, 0.05) : "transparent")
1084-
1085- Label {
1086- anchors.verticalCenter: parent.verticalCenter
1087- anchors.left: parent.left
1088- anchors.right: parent.right
1089- anchors.leftMargin: units.gu(2)
1090- anchors.rightMargin: units.gu(2)
1091-
1092- fontSize: isAllBookmarksFolder ? "medium" : "small"
1093- text: isAllBookmarksFolder ? i18n.tr("All Bookmarks") : folderItem.name
1094- color: isActiveFolder ? UbuntuColors.orange : UbuntuColors.darkGrey
1095- }
1096-
1097- onClicked: folders.currentIndex = index
1098-
1099- DropArea {
1100- id: dropArea
1101- anchors.fill: parent
1102- property string folderName: folder
1103- }
1104- }
1105- }
1106-
1107- Scrollbar {
1108- flickableItem: folders
1109- }
1110-
1111- ListView {
1112- id: bookmarksList
1113- objectName: "bookmarksList"
1114- anchors {
1115- top: sectionsGroup.bottom
1116- bottom: parent.bottom
1117- left: folders.right
1118- right: parent.right
1119- topMargin: units.gu(2)
1120- }
1121- visible: inBookmarksView
1122- onActiveFocusChanged: if (activeFocus) sections.lastFocusedBookmarksColumn = bookmarksList
1123-
1124- // Build a temporary model for the bookmarks list that includes, when
1125- // necessary, the homepage bookmark as a fixed first item in the list
1126- model: {
1127- if (!folders.currentItem) return null
1128-
1129- var items = []
1130- if (folders.currentItem.isAllBookmarksFolder) items.push({
1131- title: i18n.tr("Homepage"),
1132- url: newTabViewWide.settingsObject.homepage,
1133- folder: ""
1134- })
1135-
1136- if (!folders.currentItem.model) return null
1137- for (var i = 0; i < folders.currentItem.model.count; i++) {
1138- items.push(folders.currentItem.model.get(i))
1139- }
1140- return items
1141- }
1142-
1143- currentIndex: 0
1144-
1145- delegate: DraggableUrlDelegateWide {
1146- objectName: "bookmarkItem"
1147- clip: true
1148-
1149- title: modelData.title
1150- icon: modelData.icon ? modelData.icon : ""
1151- url: modelData.url
1152-
1153- property string folder: modelData.folder
1154- property bool isHomeBookmark: folder === "" && index === 0
1155-
1156- removable: !isHomeBookmark
1157- draggable: !isHomeBookmark && contentItem.x === 0
1158- highlighted: bookmarksList.activeFocus && ListView.isCurrentItem
1159-
1160- onClicked: newTabViewWide.bookmarkClicked(url)
1161- onRemoved: newTabViewWide.bookmarkRemoved(url)
1162-
1163- // Larger margin to prevent interference from Scrollbar hovering area
1164- gripMargin: units.gu(4)
1165- onDragStarted: {
1166- // Remove interactivity to prevent the list from scrolling
1167- // while dragging near its margins. This ensures we can correctly
1168- // return the item to its original position on a failed drop.
1169- bookmarksList.interactive = false
1170-
1171- // Relinquish focus as the presses and releases that compose the
1172- // drag will move the keyboard focus in a location unexpected
1173- // for the user. This way it will go back to the address bar and
1174- // the user can predictably resume keyboard interaction from there.
1175- newTabViewWide.releasingKeyboardFocus()
1176- }
1177- onDragEnded: {
1178- bookmarksList.interactive = true
1179-
1180- if (dragAndDrop.target && dragAndDrop.target.folderName !== folder) {
1181- bookmarksModel.update(modelData.url, modelData.title,
1182- dragAndDrop.target.folderName)
1183- dragAndDrop.success = true
1184- }
1185- }
1186- }
1187-
1188- Keys.onReturnPressed: newTabViewWide.bookmarkClicked(currentItem.url)
1189- Keys.onDeletePressed: {
1190- if (currentItem.removable) {
1191- newTabViewWide.bookmarkRemoved(currentItem.url)
1192- if (bookmarksList.model.length === 0) folders.focus = true
1193- }
1194- }
1195- Keys.onLeftPressed: folders.focus = true
1196- Keys.onDownPressed: currentIndex = Math.min(currentIndex + 1, model.length - 1)
1197- Keys.onUpPressed: {
1198- if (currentIndex > 0) currentIndex = Math.max(currentIndex - 1, 0)
1199- else newTabViewWide.releasingKeyboardFocus()
1200- }
1201- }
1202-
1203- Scrollbar {
1204- flickableItem: bookmarksList
1205- }
1206-
1207 UrlPreviewGrid {
1208 id: topSitesList
1209 objectName: "topSitesList"
1210@@ -286,14 +143,12 @@
1211 selectedIndex: settingsObject.newTabDefaultSection
1212 onSelectedIndexChanged: {
1213 settingsObject.newTabDefaultSection = selectedIndex
1214- if (selectedIndex === 0) topSitesList.focus = true
1215- else {
1216- if (lastFocusedBookmarksColumn) lastFocusedBookmarksColumn.focus = true
1217- else folders.focus = true
1218+ if (selectedIndex === 0) {
1219+ topSitesList.focus = true
1220+ } else {
1221+ bookmarksFoldersViewWide.restoreLastFocusedColumn()
1222 }
1223-
1224 }
1225- property var lastFocusedBookmarksColumn: folders
1226
1227 actions: [
1228 Action { text: i18n.tr("Top sites") },
1229
1230=== modified file 'src/app/webbrowser/UrlDelegate.qml'
1231--- src/app/webbrowser/UrlDelegate.qml 2015-08-11 21:35:55 +0000
1232+++ src/app/webbrowser/UrlDelegate.qml 2015-10-16 15:16:36 +0000
1233@@ -29,6 +29,8 @@
1234
1235 property alias headerComponent: headerComponentLoader.sourceComponent
1236
1237+ property bool removable: true
1238+
1239 divider.visible: false
1240
1241 signal removed()
1242@@ -83,7 +85,8 @@
1243 }
1244 }
1245
1246- leadingActions: ListItemActions {
1247+ ListItemActions {
1248+ id: listItemActions
1249 actions: [
1250 Action {
1251 objectName: "leadingAction.delete"
1252@@ -92,4 +95,6 @@
1253 }
1254 ]
1255 }
1256+
1257+ leadingActions: removable ? listItemActions : null
1258 }
1259
1260=== modified file 'src/app/webbrowser/UrlDelegateWide.qml'
1261--- src/app/webbrowser/UrlDelegateWide.qml 2015-08-05 16:10:09 +0000
1262+++ src/app/webbrowser/UrlDelegateWide.qml 2015-10-16 15:16:36 +0000
1263@@ -32,7 +32,7 @@
1264 color: highlighted ? Qt.rgba(0, 0, 0, 0.05) : "transparent"
1265
1266 divider.visible: false
1267- height: units.gu(7)
1268+ height: units.gu(5)
1269
1270 signal removed()
1271
1272@@ -56,7 +56,7 @@
1273 Label {
1274 id: title
1275
1276- fontSize: "small"
1277+ fontSize: "x-small"
1278 color: highlighted ? UbuntuColors.orange : UbuntuColors.darkGrey
1279 wrapMode: Text.Wrap
1280 elide: Text.ElideRight
1281@@ -66,7 +66,7 @@
1282 Label {
1283 id: url
1284
1285- fontSize: "small"
1286+ fontSize: "xx-small"
1287 color: highlighted ? UbuntuColors.orange : UbuntuColors.darkGrey
1288 wrapMode: Text.Wrap
1289 elide: Text.ElideRight
1290
1291=== modified file 'tests/autopilot/webbrowser_app/emulators/browser.py'
1292--- tests/autopilot/webbrowser_app/emulators/browser.py 2015-10-08 15:26:18 +0000
1293+++ tests/autopilot/webbrowser_app/emulators/browser.py 2015-10-16 15:16:36 +0000
1294@@ -162,6 +162,17 @@
1295 return self.wait_select_single("Dialog",
1296 objectName="newFolderDialog")
1297
1298+ # The bookmarks view is dynamically created, so it might or might not be
1299+ # available
1300+ def get_bookmarks_view(self):
1301+ try:
1302+ if self.wide:
1303+ return self.select_single("BookmarksViewWide")
1304+ else:
1305+ return self.select_single("BookmarksView")
1306+ except exceptions.StateNotFoundError:
1307+ return None
1308+
1309 # The history view is dynamically created, so it might or might not be
1310 # available
1311 def get_history_view(self):
1312@@ -540,7 +551,7 @@
1313 return self.get_top_sites_list().get_delegates()
1314
1315 def get_bookmarks_folder_list_view(self):
1316- return self.select_single(BookmarksFolderListView)
1317+ return self.wait_select_single(BookmarksFoldersView)
1318
1319 def get_bookmarks(self, folder_name):
1320 # assumes that the "more" button has been clicked
1321@@ -667,7 +678,7 @@
1322 self.pointing_device.click_object(button)
1323
1324
1325-class BookmarksFolderListView(uitk.UbuntuUIToolkitCustomProxyObjectBase):
1326+class BookmarksFoldersView(uitk.UbuntuUIToolkitCustomProxyObjectBase):
1327
1328 def get_delegates(self):
1329 return sorted(self.select_many("QQuickItem",
1330
1331=== modified file 'tests/autopilot/webbrowser_app/tests/__init__.py'
1332--- tests/autopilot/webbrowser_app/tests/__init__.py 2015-10-08 09:34:48 +0000
1333+++ tests/autopilot/webbrowser_app/tests/__init__.py 2015-10-16 15:16:36 +0000
1334@@ -195,6 +195,15 @@
1335 self.pointing_device.click_object(settings_action)
1336 return self.main_window.get_settings_page()
1337
1338+ def open_bookmarks(self):
1339+ chrome = self.main_window.chrome
1340+ drawer_button = chrome.get_drawer_button()
1341+ self.pointing_device.click_object(drawer_button)
1342+ chrome.get_drawer()
1343+ bookmarks_action = chrome.get_drawer_action("bookmarks")
1344+ self.pointing_device.click_object(bookmarks_action)
1345+ return self.main_window.get_bookmarks_view()
1346+
1347 def open_history(self):
1348 chrome = self.main_window.chrome
1349 drawer_button = chrome.get_drawer_button()
1350
1351=== modified file 'tests/autopilot/webbrowser_app/tests/test_bookmark_options.py'
1352--- tests/autopilot/webbrowser_app/tests/test_bookmark_options.py 2015-09-06 08:16:40 +0000
1353+++ tests/autopilot/webbrowser_app/tests/test_bookmark_options.py 2015-10-16 15:16:36 +0000
1354@@ -92,17 +92,18 @@
1355 return self.main_window.get_bookmark_options()
1356
1357 def _assert_bookmark_count_in_folder(self, tab, folder_name, count):
1358- # in wide mode the list of urls in the default folder has the homepage
1359- # bookmark in it, but it does not in narrow mode
1360- if self.main_window.wide and folder_name == "":
1361- count += 1
1362-
1363 urls = tab.get_bookmarks(folder_name)
1364 self.assertThat(lambda: len(urls), Eventually(Equals(count)))
1365
1366+ def _toggle_bookmark_folder(self, tab, folder_name):
1367+ folders = tab.get_bookmarks_folder_list_view()
1368+ folder_delegate = folders.get_folder_delegate(folder_name)
1369+ self.pointing_device.click_object(
1370+ folders.get_header_from_folder(folder_delegate))
1371+
1372 def test_save_bookmarked_url_in_default_folder(self):
1373 new_tab = self.open_new_tab(open_tabs_view=True, expand_view=True)
1374- self._assert_bookmark_count_in_folder(new_tab, "", 4)
1375+ self._assert_bookmark_count_in_folder(new_tab, "", 5)
1376
1377 url = self.base_url + "/test2"
1378 self.main_window.go_to_url(url)
1379@@ -118,12 +119,14 @@
1380 self.assertThat(chrome.bookmarked, Eventually(Equals(True)))
1381
1382 new_tab = self.open_new_tab(open_tabs_view=True, expand_view=True)
1383- self._assert_bookmark_count_in_folder(new_tab, "", 5)
1384+ self._assert_bookmark_count_in_folder(new_tab, "", 6)
1385
1386 def test_save_bookmarked_url_in_existing_folder(self):
1387 new_tab = self.open_new_tab(open_tabs_view=True, expand_view=True)
1388 self.assertThat(lambda: len(new_tab.get_folder_names()),
1389 Eventually(Equals(3)))
1390+ if not self.main_window.wide:
1391+ self._toggle_bookmark_folder(new_tab, "Actinide")
1392 self._assert_bookmark_count_in_folder(new_tab, "Actinide", 1)
1393
1394 url = self.base_url + "/test2"
1395@@ -154,6 +157,8 @@
1396 new_tab = self.open_new_tab(open_tabs_view=True, expand_view=True)
1397 self.assertThat(lambda: len(new_tab.get_folder_names()),
1398 Eventually(Equals(3)))
1399+ if not self.main_window.wide:
1400+ self._toggle_bookmark_folder(new_tab, "Actinide")
1401 self._assert_bookmark_count_in_folder(new_tab, "Actinide", 2)
1402
1403 def test_save_bookmarked_url_in_new_folder(self):
1404@@ -198,6 +203,8 @@
1405 new_tab = self.open_new_tab(open_tabs_view=True, expand_view=True)
1406 self.assertThat(lambda: len(new_tab.get_folder_names()),
1407 Eventually(Equals(4)))
1408+ if not self.main_window.wide:
1409+ self._toggle_bookmark_folder(new_tab, "NewFolder")
1410 self._assert_bookmark_count_in_folder(new_tab, "NewFolder", 1)
1411
1412 def test_set_bookmark_title(self):
1413@@ -223,12 +230,9 @@
1414 self.assertThat(chrome.bookmarked, Eventually(Equals(True)))
1415
1416 new_tab = self.open_new_tab(open_tabs_view=True, expand_view=True)
1417- self._assert_bookmark_count_in_folder(new_tab, "", 5)
1418+ self._assert_bookmark_count_in_folder(new_tab, "", 6)
1419
1420- index = 0
1421- if self.main_window.wide:
1422- index += 1
1423- bookmark = new_tab.get_bookmarks("")[index]
1424+ bookmark = new_tab.get_bookmarks("")[1]
1425 self.assertThat(bookmark.title, Equals("NewTitle"))
1426
1427 def test_bookmark_options_from_contextual_menu(self):
1428
1429=== modified file 'tests/autopilot/webbrowser_app/tests/test_keyboard.py'
1430--- tests/autopilot/webbrowser_app/tests/test_keyboard.py 2015-09-29 13:15:01 +0000
1431+++ tests/autopilot/webbrowser_app/tests/test_keyboard.py 2015-10-16 15:16:36 +0000
1432@@ -273,6 +273,39 @@
1433 self.assertThat(lambda: self.main_window.get_current_webview().url,
1434 Eventually(Equals(url)))
1435
1436+ def test_toggle_bookmarks(self):
1437+ self.assertThat(self.main_window.get_bookmarks_view(), Equals(None))
1438+ self.main_window.press_key('Ctrl+Shift+O')
1439+ self.assertThat(lambda: self.main_window.get_bookmarks_view(),
1440+ Eventually(NotEquals(None)))
1441+ bookmarks_view = self.main_window.get_bookmarks_view()
1442+
1443+ self.main_window.press_key('Escape')
1444+ bookmarks_view.wait_until_destroyed()
1445+ webview = self.main_window.get_current_webview()
1446+ self.assertThat(webview.activeFocus, Eventually(Equals(True)))
1447+
1448+ def test_toggle_bookmarks_from_menu(self):
1449+ self.assertThat(self.main_window.get_bookmarks_view(), Equals(None))
1450+ self.open_bookmarks()
1451+ bookmarks_view = self.main_window.get_bookmarks_view()
1452+ self.assertThat(bookmarks_view.activeFocus, Eventually(Equals(True)))
1453+
1454+ self.main_window.press_key('Escape')
1455+ bookmarks_view.wait_until_destroyed()
1456+
1457+ def test_new_tab_from_bookmarks_view(self):
1458+ self.assertThat(self.main_window.get_bookmarks_view(), Equals(None))
1459+ self.open_bookmarks()
1460+ bookmarks_view = self.main_window.get_bookmarks_view()
1461+ self.assertThat(bookmarks_view.activeFocus, Eventually(Equals(True)))
1462+
1463+ self.main_window.press_key('Ctrl+T')
1464+ bookmarks_view.wait_until_destroyed()
1465+
1466+ new_tab_view = self.main_window.get_new_tab_view()
1467+ self.assertThat(new_tab_view.visible, Eventually(Equals(True)))
1468+
1469 def test_toggle_history(self):
1470 self.assertThat(self.main_window.get_history_view(), Equals(None))
1471 self.main_window.press_key('Ctrl+H')
1472@@ -294,6 +327,18 @@
1473 self.main_window.press_key('Escape')
1474 history_view.wait_until_destroyed()
1475
1476+ def test_new_tab_from_history_view(self):
1477+ self.assertThat(self.main_window.get_history_view(), Equals(None))
1478+ self.open_history()
1479+ history_view = self.main_window.get_history_view()
1480+ self.assertThat(history_view.activeFocus, Eventually(Equals(True)))
1481+
1482+ self.main_window.press_key('Ctrl+T')
1483+ history_view.wait_until_destroyed()
1484+
1485+ new_tab_view = self.main_window.get_new_tab_view()
1486+ self.assertThat(new_tab_view.visible, Eventually(Equals(True)))
1487+
1488 def test_escape_settings(self):
1489 settings = self.open_settings()
1490 self.main_window.press_key('Escape')
1491
1492=== modified file 'tests/autopilot/webbrowser_app/tests/test_new_tab_view.py'
1493--- tests/autopilot/webbrowser_app/tests/test_new_tab_view.py 2015-10-13 11:21:01 +0000
1494+++ tests/autopilot/webbrowser_app/tests/test_new_tab_view.py 2015-10-16 15:16:36 +0000
1495@@ -255,7 +255,7 @@
1496 folder_delegate = folders.get_folder_delegate("")
1497 self.assertThat(lambda: len(folders.get_urls_from_folder(
1498 folder_delegate)),
1499- Eventually(Equals(4)))
1500+ Eventually(Equals(5)))
1501 bookmark = folders.get_urls_from_folder(folder_delegate)[0]
1502 url = bookmark.url
1503 self.pointing_device.click_object(bookmark)
1504@@ -277,7 +277,7 @@
1505 folder_delegate = folders.get_folder_delegate("")
1506 self.assertThat(lambda: len(folders.get_urls_from_folder(
1507 folder_delegate)),
1508- Eventually(Equals(4)))
1509+ Eventually(Equals(5)))
1510 self.assertThat(top_sites.visible, Eventually(Equals(False)))
1511 # Collapse again
1512 self.assertThat(more_button.visible, Equals(True))
1513@@ -308,6 +308,12 @@
1514 lambda: folders.get_urls_from_folder(folder_delegate)[0],
1515 Eventually(NotEquals(url)))
1516
1517+ def _toggle_bookmark_folder(self, folder):
1518+ folders = self.new_tab_view.get_bookmarks_folder_list_view()
1519+ folder_delegate = folders.get_folder_delegate(folder)
1520+ self.pointing_device.click_object(
1521+ folders.get_header_from_folder(folder_delegate))
1522+
1523 def test_remove_bookmarks_when_collapsed(self):
1524 bookmarks = self.new_tab_view.get_bookmarks_list()
1525 self.assertThat(lambda: len(bookmarks.get_delegates()),
1526@@ -327,10 +333,12 @@
1527 folder_delegate = folders.get_folder_delegate("")
1528 self.assertThat(lambda: len(folders.get_urls_from_folder(
1529 folder_delegate)),
1530- Eventually(Equals(4)))
1531+ Eventually(Equals(5)))
1532 more_button = self.new_tab_view.get_bookmarks_more_button()
1533 top_sites = self.new_tab_view.get_top_sites_list()
1534+ self._toggle_bookmark_folder("Actinide")
1535 self._remove_first_bookmark_from_folder("Actinide")
1536+ self._toggle_bookmark_folder("NobleGas")
1537 self._remove_first_bookmark_from_folder("NobleGas")
1538 self.assertThat(more_button.visible, Eventually(Equals(False)))
1539 self.assertThat(top_sites.visible, Eventually(Equals(True)))
1540@@ -345,15 +353,37 @@
1541 folder_delegate = folders.get_folder_delegate("")
1542 self.assertThat(lambda: len(folders.get_urls_from_folder(
1543 folder_delegate)),
1544- Eventually(Equals(4)))
1545- folder_delegate = folders.get_folder_delegate("Actinide")
1546- self.assertThat(lambda: len(folders.get_urls_from_folder(
1547- folder_delegate)),
1548- Eventually(Equals(1)))
1549- folder_delegate = folders.get_folder_delegate("NobleGas")
1550- self.assertThat(lambda: len(folders.get_urls_from_folder(
1551- folder_delegate)),
1552- Eventually(Equals(1)))
1553+ Eventually(Equals(5)))
1554+ self._toggle_bookmark_folder("Actinide")
1555+ folder_delegate = folders.get_folder_delegate("Actinide")
1556+ self.assertThat(lambda: len(folders.get_urls_from_folder(
1557+ folder_delegate)),
1558+ Eventually(Equals(1)))
1559+ self._toggle_bookmark_folder("NobleGas")
1560+ folder_delegate = folders.get_folder_delegate("NobleGas")
1561+ self.assertThat(lambda: len(folders.get_urls_from_folder(
1562+ folder_delegate)),
1563+ Eventually(Equals(1)))
1564+
1565+ def test_collapsed_bookmarks_folders_when_expanded(self):
1566+ more_button = self.new_tab_view.get_bookmarks_more_button()
1567+ self.assertThat(more_button.visible, Equals(True))
1568+ self.pointing_device.click_object(more_button)
1569+ folders = self.new_tab_view.get_bookmarks_folder_list_view()
1570+ self.assertThat(lambda: len(folders.get_delegates()),
1571+ Eventually(Equals(3)))
1572+ folder_delegate = folders.get_folder_delegate("")
1573+ self.assertThat(lambda: len(folders.get_urls_from_folder(
1574+ folder_delegate)),
1575+ Eventually(Equals(5)))
1576+ folder_delegate = folders.get_folder_delegate("Actinide")
1577+ self.assertThat(lambda: len(folders.get_urls_from_folder(
1578+ folder_delegate)),
1579+ Eventually(Equals(0)))
1580+ folder_delegate = folders.get_folder_delegate("NobleGas")
1581+ self.assertThat(lambda: len(folders.get_urls_from_folder(
1582+ folder_delegate)),
1583+ Eventually(Equals(0)))
1584
1585 def test_hide_empty_bookmarks_folders_when_expanded(self):
1586 more_button = self.new_tab_view.get_bookmarks_more_button()
1587@@ -362,6 +392,7 @@
1588 folders = self.new_tab_view.get_bookmarks_folder_list_view()
1589 self.assertThat(lambda: len(folders.get_delegates()),
1590 Eventually(Equals(3)))
1591+ self._toggle_bookmark_folder("Actinide")
1592 folder_delegate = folders.get_folder_delegate("Actinide")
1593 self.assertThat(lambda: len(folders.get_urls_from_folder(
1594 folder_delegate)),
1595@@ -372,7 +403,8 @@
1596 folder_delegate = folders.get_folder_delegate("")
1597 self.assertThat(lambda: len(folders.get_urls_from_folder(
1598 folder_delegate)),
1599- Eventually(Equals(4)))
1600+ Eventually(Equals(5)))
1601+ self._toggle_bookmark_folder("NobleGas")
1602 folder_delegate = folders.get_folder_delegate("NobleGas")
1603 self.assertThat(lambda: len(folders.get_urls_from_folder(
1604 folder_delegate)),
1605@@ -388,7 +420,7 @@
1606 folder_delegate = folders.get_folder_delegate("")
1607 self.assertThat(lambda: len(folders.get_urls_from_folder(
1608 folder_delegate)),
1609- Eventually(Equals(4)))
1610+ Eventually(Equals(5)))
1611 self.pointing_device.click_object(
1612 folders.get_header_from_folder(folder_delegate))
1613 self.assertThat(lambda: len(folders.get_urls_from_folder(
1614@@ -398,7 +430,7 @@
1615 folders.get_header_from_folder(folder_delegate))
1616 self.assertThat(lambda: len(folders.get_urls_from_folder(
1617 folder_delegate)),
1618- Eventually(Equals(4)))
1619+ Eventually(Equals(5)))
1620
1621 def test_remove_top_sites(self):
1622 top_sites = self.new_tab_view.get_top_sites_list()
1623
1624=== added file 'tests/unittests/qml/tst_BookmarksFoldersViewWide.qml'
1625--- tests/unittests/qml/tst_BookmarksFoldersViewWide.qml 1970-01-01 00:00:00 +0000
1626+++ tests/unittests/qml/tst_BookmarksFoldersViewWide.qml 2015-10-16 15:16:36 +0000
1627@@ -0,0 +1,257 @@
1628+/*
1629+ * Copyright 2015 Canonical Ltd.
1630+ *
1631+ * This file is part of webbrowser-app.
1632+ *
1633+ * webbrowser-app is free software; you can redistribute it and/or modify
1634+ * it under the terms of the GNU General Public License as published by
1635+ * the Free Software Foundation; version 3.
1636+ *
1637+ * webbrowser-app is distributed in the hope that it will be useful,
1638+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1639+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1640+ * GNU General Public License for more details.
1641+ *
1642+ * You should have received a copy of the GNU General Public License
1643+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1644+ */
1645+
1646+import QtQuick 2.4
1647+import QtTest 1.0
1648+import Ubuntu.Test 1.0
1649+import "../../../src/app/webbrowser"
1650+import webbrowserapp.private 0.1
1651+
1652+Item {
1653+ id: root
1654+
1655+ width: 800
1656+ height: 600
1657+
1658+ Component {
1659+ id: bookmarksModel
1660+ BookmarksModel {
1661+ databasePath: ":memory:"
1662+ }
1663+ }
1664+
1665+ property BookmarksFoldersViewWide view
1666+ property var bookmarks
1667+ property string homepage: "http://example.com/homepage"
1668+
1669+ Component {
1670+ id: viewComponent
1671+ BookmarksFoldersViewWide {
1672+ anchors.fill: parent
1673+ homeBookmarkUrl: homepage
1674+ model: bookmarks
1675+ }
1676+ }
1677+
1678+ SignalSpy {
1679+ id: bookmarkClickedSpy
1680+ signalName: "bookmarkClicked"
1681+ }
1682+
1683+ SignalSpy {
1684+ id: bookmarkRemovedSpy
1685+ signalName: "bookmarkRemoved"
1686+ }
1687+
1688+ UbuntuTestCase {
1689+ name: "BookmarksFoldersViewWide"
1690+ when: windowShown
1691+
1692+ function init() {
1693+ bookmarks = bookmarksModel.createObject()
1694+ view = viewComponent.createObject(root)
1695+ populate()
1696+
1697+ view.focus = true
1698+
1699+ bookmarkClickedSpy.target = view
1700+ bookmarkClickedSpy.clear()
1701+ bookmarkRemovedSpy.target = view
1702+ bookmarkRemovedSpy.clear()
1703+ }
1704+
1705+ function populate() {
1706+ bookmarks.add("http://example.com", "Example Com", "", "")
1707+ bookmarks.add("http://example.org/bar", "Example Org Bar", "", "Folder B")
1708+ bookmarks.add("http://example.org/foo", "Example Org Foo", "", "Folder B")
1709+ bookmarks.add("http://example.net/a", "Example Net A", "", "Folder A")
1710+ bookmarks.add("http://example.net/b", "Example Net B", "", "Folder A")
1711+ }
1712+
1713+ function cleanup() {
1714+ bookmarks.destroy()
1715+ bookmarks = null
1716+
1717+ view.destroy()
1718+ view = null
1719+ }
1720+
1721+ function clickItem(item) {
1722+ var center = centerOf(item)
1723+ mouseClick(item, center.x, center.y)
1724+ }
1725+
1726+ function getListItems(name, itemName) {
1727+ var list = findChild(view, name)
1728+ var items = []
1729+ if (list) {
1730+ // ensure all the delegates are created
1731+ list.cacheBuffer = list.count * 1000
1732+
1733+ // In some cases the ListView might add other children to the
1734+ // contentItem, so we filter the list of children to include
1735+ // only actual delegates
1736+ var children = list.contentItem.children
1737+ for (var i = 0; i < children.length; i++) {
1738+ if (children[i].objectName === itemName) {
1739+ items.push(children[i])
1740+ }
1741+ }
1742+ }
1743+ return items
1744+ }
1745+
1746+ function test_folder_list() {
1747+ var items = getListItems("foldersList", "folderItem")
1748+ compare(items.length, 3)
1749+ verify(items[0].isAllBookmarksFolder)
1750+ compare(items[0].model.folder, "")
1751+ // named folder items should appear alphabetically sorted
1752+ compare(items[1].model.folder, "Folder A")
1753+ compare(items[2].model.folder, "Folder B")
1754+ }
1755+
1756+ function test_all_bookmarks_list() {
1757+ var items = getListItems("bookmarksList", "bookmarkItem")
1758+ compare(items.length, 2)
1759+ compare(items[0].url, homepage)
1760+ compare(items[1].title, "Example Com")
1761+ }
1762+
1763+ function test_navigate_folders_by_keyboard() {
1764+ var foldersList = getListItems(view, "foldersList")
1765+ var folders = getListItems("foldersList", "folderItem")
1766+ verify(folders[0].isActiveFolder)
1767+
1768+ keyClick(Qt.Key_Down)
1769+ verify(!folders[0].isActiveFolder)
1770+ verify(folders[1].isActiveFolder)
1771+
1772+ // bookmarks within a folder are sorted with the first bookmarked appearing last
1773+ var items = getListItems("bookmarksList", "bookmarkItem")
1774+ compare(items[0].title, "Example Net B")
1775+ compare(items[1].title, "Example Net A")
1776+ compare(items.length, 2)
1777+
1778+ keyClick(Qt.Key_Down)
1779+ verify(folders[2].isActiveFolder)
1780+ items = getListItems("bookmarksList", "bookmarkItem")
1781+ compare(items[0].title, "Example Org Foo")
1782+ compare(items[1].title, "Example Org Bar")
1783+ compare(items.length, 2)
1784+
1785+ // verify scrolling beyond bottom of list is not allowed
1786+ keyClick(Qt.Key_Down)
1787+ verify(folders[2].isActiveFolder)
1788+
1789+ keyClick(Qt.Key_Up)
1790+ verify(folders[1].isActiveFolder)
1791+ keyClick(Qt.Key_Up)
1792+ verify(folders[0].isActiveFolder)
1793+
1794+ keyClick(Qt.Key_Up)
1795+ }
1796+
1797+ function test_switch_between_folder_and_bookmarks_by_keyboard() {
1798+ var foldersList = findChild(view, "foldersList")
1799+ var bookmarks = findChild(view, "bookmarksList")
1800+ var folders = getListItems("foldersList", "folderItem")
1801+
1802+ verify(folders[0].isActiveFolder)
1803+
1804+ keyClick(Qt.Key_Right)
1805+ verify(bookmarks.activeFocus)
1806+ keyClick(Qt.Key_Right)
1807+ verify(bookmarks.activeFocus) // verify no circular scrolling
1808+
1809+ keyClick(Qt.Key_Left)
1810+ verify(foldersList.activeFocus)
1811+ keyClick(Qt.Key_Left)
1812+ verify(foldersList.activeFocus) // verify no circular scrolling
1813+
1814+ keyClick(Qt.Key_Down)
1815+ verify(!folders[0].isActiveFolder)
1816+ verify(folders[1].isActiveFolder)
1817+
1818+ keyClick(Qt.Key_Right)
1819+ verify(bookmarks.activeFocus)
1820+ keyClick(Qt.Key_Right)
1821+ verify(bookmarks.activeFocus) // verify no circular scrolling
1822+
1823+ keyClick(Qt.Key_Left)
1824+ verify(foldersList.activeFocus)
1825+ keyClick(Qt.Key_Left)
1826+ verify(foldersList.activeFocus) // verify no circular scrolling
1827+ }
1828+
1829+ function test_activate_bookmarks_by_keyboard() {
1830+ keyClick(Qt.Key_Right)
1831+
1832+ var items = getListItems("bookmarksList", "bookmarkItem")
1833+ keyClick(Qt.Key_Return)
1834+ compare(bookmarkClickedSpy.count, 1)
1835+ compare(bookmarkClickedSpy.signalArguments[0][0], homepage)
1836+
1837+ keyClick(Qt.Key_Down)
1838+ keyClick(Qt.Key_Return)
1839+ compare(bookmarkClickedSpy.count, 2)
1840+ compare(bookmarkClickedSpy.signalArguments[1][0], "http://example.com")
1841+ }
1842+
1843+ function test_activate_bookmarks_by_mouse() {
1844+ var items = getListItems("bookmarksList", "bookmarkItem")
1845+ clickItem(items[0])
1846+ compare(bookmarkClickedSpy.count, 1)
1847+ compare(bookmarkClickedSpy.signalArguments[0][0], homepage)
1848+
1849+ clickItem(items[1])
1850+ compare(bookmarkClickedSpy.count, 2)
1851+ compare(bookmarkClickedSpy.signalArguments[1][0], "http://example.com")
1852+ }
1853+
1854+ function test_switch_folders_by_mouse() {
1855+ var folders = getListItems("foldersList", "folderItem")
1856+
1857+ clickItem(folders[1])
1858+ var items = getListItems("bookmarksList", "bookmarkItem")
1859+ compare(items[0].title, "Example Net B")
1860+ compare(items[1].title, "Example Net A")
1861+ compare(items.length, 2)
1862+
1863+ clickItem(folders[0])
1864+ items = getListItems("bookmarksList", "bookmarkItem")
1865+ compare(items[0].url, homepage)
1866+ compare(items[1].title, "Example Com")
1867+ compare(items.length, 2)
1868+ }
1869+
1870+ function test_remove_bookmarks_by_keyboard() {
1871+ keyClick(Qt.Key_Right)
1872+ var items = getListItems("bookmarksList", "bookmarkItem")
1873+
1874+ // verify that trying to delete the homepage bookmark does not work
1875+ keyClick(Qt.Key_Delete)
1876+ compare(bookmarkRemovedSpy.count, 0)
1877+
1878+ keyClick(Qt.Key_Down)
1879+ keyClick(Qt.Key_Delete)
1880+ compare(bookmarkRemovedSpy.count, 1)
1881+ compare(bookmarkRemovedSpy.signalArguments[0][0], items[1].url)
1882+ }
1883+ }
1884+}
1885
1886=== modified file 'tests/unittests/qml/tst_NewTabViewWide.qml'
1887--- tests/unittests/qml/tst_NewTabViewWide.qml 2015-09-10 11:29:53 +0000
1888+++ tests/unittests/qml/tst_NewTabViewWide.qml 2015-10-16 15:16:36 +0000
1889@@ -161,23 +161,6 @@
1890 }
1891 }
1892
1893- function test_folder_list() {
1894- var items = getListItems("foldersList", "folderItem")
1895- compare(items.length, 3)
1896- verify(items[0].isAllBookmarksFolder)
1897- compare(items[0].model.folder, "")
1898- // named folder items should appear alphabetically sorted
1899- compare(items[1].model.folder, "Folder A")
1900- compare(items[2].model.folder, "Folder B")
1901- }
1902-
1903- function test_all_bookmarks_list() {
1904- var items = getListItems("bookmarksList", "bookmarkItem")
1905- compare(items.length, 2)
1906- compare(items[0].url, homepage)
1907- compare(items[1].title, "Example Com")
1908- }
1909-
1910 function test_switch_sections_by_keyboard() {
1911 skip("Would fail due to UITK bug: http://pad.lv/1481233")
1912 var sections = findChild(view, "sections")
1913@@ -232,75 +215,6 @@
1914 compare(historyEntryClickedSpy.signalArguments[1][0], "http://example.org")
1915 }
1916
1917- function test_navigate_folders_by_keyboard() {
1918- goToBookmarks()
1919-
1920- var foldersList = getListItems(view, "foldersList")
1921- var folders = getListItems("foldersList", "folderItem")
1922- verify(folders[0].isActiveFolder)
1923-
1924- keyClick(Qt.Key_Down)
1925- verify(!folders[0].isActiveFolder)
1926- verify(folders[1].isActiveFolder)
1927-
1928- // bookmarks within a folder are sorted with the first bookmarked appearing last
1929- var items = getListItems("bookmarksList", "bookmarkItem")
1930- compare(items[0].title, "Example Net B")
1931- compare(items[1].title, "Example Net A")
1932- compare(items.length, 2)
1933-
1934- keyClick(Qt.Key_Down)
1935- verify(folders[2].isActiveFolder)
1936- items = getListItems("bookmarksList", "bookmarkItem")
1937- compare(items[0].title, "Example Org Foo")
1938- compare(items[1].title, "Example Org Bar")
1939- compare(items.length, 2)
1940-
1941- // verify scrolling beyond bottom of list is not allowed
1942- keyClick(Qt.Key_Down)
1943- verify(folders[2].isActiveFolder)
1944-
1945- keyClick(Qt.Key_Up)
1946- verify(folders[1].isActiveFolder)
1947- keyClick(Qt.Key_Up)
1948- verify(folders[0].isActiveFolder)
1949-
1950- keyClick(Qt.Key_Up)
1951- compare(releasingKeyboardFocusSpy.count, 1)
1952- }
1953-
1954- function test_switch_between_folder_and_bookmarks_by_keyboard() {
1955- goToBookmarks()
1956-
1957- var folders = findChild(view, "foldersList")
1958- var bookmarks = findChild(view, "bookmarksList")
1959-
1960- keyClick(Qt.Key_Right)
1961- verify(bookmarks.activeFocus)
1962- keyClick(Qt.Key_Right)
1963- verify(bookmarks.activeFocus) // verify no circular scrolling
1964-
1965- keyClick(Qt.Key_Left)
1966- verify(folders.activeFocus)
1967- keyClick(Qt.Key_Left)
1968- verify(folders.activeFocus) // verify no circular scrolling
1969- }
1970-
1971- function test_activate_bookmarks_by_keyboard() {
1972- goToBookmarks()
1973- keyClick(Qt.Key_Right)
1974-
1975- var items = getListItems("bookmarksList", "bookmarkItem")
1976- keyClick(Qt.Key_Return)
1977- compare(bookmarkClickedSpy.count, 1)
1978- compare(bookmarkClickedSpy.signalArguments[0][0], homepage)
1979-
1980- keyClick(Qt.Key_Down)
1981- keyClick(Qt.Key_Return)
1982- compare(bookmarkClickedSpy.count, 2)
1983- compare(bookmarkClickedSpy.signalArguments[1][0], "http://example.com")
1984- }
1985-
1986 function test_activate_topsites_by_mouse() {
1987 var items = getListItems("topSitesList", "topSiteItem")
1988 clickItem(items[0])
1989@@ -313,50 +227,6 @@
1990
1991 }
1992
1993- function test_activate_bookmarks_by_mouse() {
1994- goToBookmarks()
1995- var items = getListItems("bookmarksList", "bookmarkItem")
1996- clickItem(items[0])
1997- compare(bookmarkClickedSpy.count, 1)
1998- compare(bookmarkClickedSpy.signalArguments[0][0], homepage)
1999-
2000- clickItem(items[1])
2001- compare(bookmarkClickedSpy.count, 2)
2002- compare(bookmarkClickedSpy.signalArguments[1][0], "http://example.com")
2003- }
2004-
2005- function test_switch_folders_by_mouse() {
2006- goToBookmarks()
2007- var folders = getListItems("foldersList", "folderItem")
2008-
2009- clickItem(folders[1])
2010- var items = getListItems("bookmarksList", "bookmarkItem")
2011- compare(items[0].title, "Example Net B")
2012- compare(items[1].title, "Example Net A")
2013- compare(items.length, 2)
2014-
2015- clickItem(folders[0])
2016- items = getListItems("bookmarksList", "bookmarkItem")
2017- compare(items[0].url, homepage)
2018- compare(items[1].title, "Example Com")
2019- compare(items.length, 2)
2020- }
2021-
2022- function test_remove_bookmarks_by_keyboard() {
2023- goToBookmarks()
2024- keyClick(Qt.Key_Right)
2025- var items = getListItems("bookmarksList", "bookmarkItem")
2026-
2027- // verify that trying to delete the homepage bookmark does not work
2028- keyClick(Qt.Key_Delete)
2029- compare(bookmarkRemovedSpy.count, 0)
2030-
2031- keyClick(Qt.Key_Down)
2032- keyClick(Qt.Key_Delete)
2033- compare(bookmarkRemovedSpy.count, 1)
2034- compare(bookmarkRemovedSpy.signalArguments[0][0], items[1].url)
2035- }
2036-
2037 function test_remove_top_sites_by_keyboard() {
2038 var previous = getListItems("topSitesList", "topSiteItem")
2039 keyClick(Qt.Key_Delete)

Subscribers

People subscribed via source and target branches

to status/vote changes: