Merge lp:~osomon/oxide/navigation-api into lp:~oxide-developers/oxide/oxide.trunk

Proposed by Olivier Tilloy
Status: Merged
Merged at revision: 294
Proposed branch: lp:~osomon/oxide/navigation-api
Merge into: lp:~oxide-developers/oxide/oxide.trunk
Diff against target: 1014 lines (+672/-3)
19 files modified
qt/core/glue/oxide_qt_web_view_adapter.cc (+28/-0)
qt/core/glue/oxide_qt_web_view_adapter.h (+13/-0)
qt/core/glue/private/oxide_qt_web_view_adapter_p.cc (+12/-0)
qt/core/glue/private/oxide_qt_web_view_adapter_p.h (+4/-0)
qt/quick/api/oxideqquicknavigationhistory.cc (+202/-0)
qt/quick/api/oxideqquicknavigationhistory_p.h (+67/-0)
qt/quick/api/oxideqquicknavigationhistory_p_p.h (+44/-0)
qt/quick/api/oxideqquickwebview.cc (+19/-0)
qt/quick/api/oxideqquickwebview_p.h (+5/-0)
qt/quick/api/oxideqquickwebview_p_p.h (+7/-0)
qt/quick/oxide_qml_plugin.cc (+3/-0)
qt/quick/qmlplugin.pro (+3/-0)
qt/tests/qmltests/data/tst_WebView_navigation1.html (+3/-0)
qt/tests/qmltests/data/tst_WebView_navigation2.html (+3/-0)
qt/tests/qmltests/data/tst_WebView_navigation3.html (+4/-1)
qt/tests/qmltests/data/tst_WebView_navigation4.html (+3/-0)
qt/tests/qmltests/data/tst_WebView_navigationHistory.qml (+116/-0)
shared/browser/oxide_web_view.cc (+110/-2)
shared/browser/oxide_web_view.h (+26/-0)
To merge this branch: bzr merge lp:~osomon/oxide/navigation-api
Reviewer Review Type Date Requested Status
Chris Coulson Approve
Review via email: mp+196704@code.launchpad.net

Commit message

Implement a navigation API for the QML WebView.

To post a comment you must log in.
Revision history for this message
Chris Coulson (chrisccoulson) wrote :
Download full text (5.3 KiB)

Thanks for working on this - it's looking good! I've just got a few initial comments:

- Do we need virtualUrl and titleForDisplay for anything? I'd be tempted to leave those out for now unless we've got a use-case for them.

- Technically, the code in the additional functions added to WebViewAdapterPrivate could all live in WebViewAdapter. The classes in qt/core/glue/private are only there so that we don't leak Chromium API's / types across a public interface, and also to provide a way of constructing objects from other parts of Oxide (see the text in qt/core/api/README, which is applicable here too). However, I've not been that disciplined in making it obvious where code should live, so it's ok as it is for now. I'll probably push some cleanup patches later on for everything in qt/core/glue.

Saying that, as those functions aren't Qt-specific, they could probably just go in oxide::WebView instead...

**************

+
+#include "oxideqquicknavigationhistory_p.h"
+#include "oxideqquicknavigationhistory_p_p.h"
+#include "oxideqquickwebview_p.h"
+
+#include <QDateTime>
+#include <QString>
+#include <QtAlgorithms>
+#include <QUrl>
+
+#include "qt/core/glue/oxide_qt_web_view_adapter.h"
+
+struct NavigationEntry {

Just a nit, but generally I've tried to follow the Google style guide when ordering headers (http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Names_and_Order_of_Includes), with the additional requirements of putting headers from shared/ before those in qt/ and listing headers from the same folder as the current object at the end. So I would order these like this:

#include "oxideqquicknavigationhistory_p.h"
#include "oxideqquicknavigationhistory_p_p.h"

#include <QDateTime>
#include <QString>
#include <QtAlgorithms>
#include <QUrl>

#include "qt/core/glue/oxide_qt_web_view_adapter.h"

#include "oxideqquickwebview_p.h"

I should write this down somewhere :)

**************

+OxideQQuickNavigationHistory::OxideQQuickNavigationHistory(
+ oxide::qt::WebViewAdapter* adapter, OxideQQuickWebView* webview) :
+ QAbstractListModel(webview),
+ d_ptr(new OxideQQuickNavigationHistoryPrivate) {
+ Q_D(OxideQQuickNavigationHistory);
+ d->q_ptr = this;

The "adapter" parameter in the constructor is not needed here, as there is a helper for getting this already from the public webview instance (OxideQQuickWebViewPrivate::get()).

**************

+void OxideQQuickNavigationHistory::onNavigationHistoryChanged() {
+ Q_D(OxideQQuickNavigationHistory);
+ Q_ASSERT(d->webview_adapter_ != NULL);
+
+ int newCount = d->webview_adapter_->getNavigationEntryCount();
+ if (newCount != d->entry_count_) {
+ beginResetModel();
+ d->entry_count_ = newCount;
+ for (int i = 0; i < newCount; ++i) {
+ int id = d->webview_adapter_->getNavigationEntryUniqueID(i);
+ NavigationEntry* entry;
+ if (d->entry_cache_.contains(id)) {
+ entry = d->entry_cache_.value(id);
+ } else {
+ entry = new NavigationEntry;
+ d->entry_cache_.insert(id, entry);
+ }
+ entry->url = d->webview_adapter_->getNavigationEntryUrl(i);
+ entry->virtualUrl = d->webview_adapter_->getNavigationEntryVirtualUrl(i);
+ ...

Read more...

review: Needs Fixing
lp:~osomon/oxide/navigation-api updated
265. By Olivier Tilloy

Leave out virtualUrl and titleForDisplay for now, we don’t need them.

266. By Olivier Tilloy

#include re-ordering to be more consistent with the style of the existing code.

267. By Olivier Tilloy

Remove the unneeded "adapter" parameter.

268. By Olivier Tilloy

Issue a warning when trying to set the current index to an invalid value, and add corresponding tests.

269. By Olivier Tilloy

Add a bounds check for index.

270. By Olivier Tilloy

Remove trailing underscores from public members’ names.

271. By Olivier Tilloy

Move code that is not Qt-specific from qt/core/glue/private to shared/.

272. By Olivier Tilloy

Embed OxideQQuickNavigationHistory in the address space of OxideQQuickWebViewPrivate.

273. By Olivier Tilloy

Clear the entry cache when resetting the model.

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

All remarks/suggestions addressed, but for this one:

> Does this work as expected when NavigationController prunes entries?
> For example, if there is a new navigation entry but
> NavigationController prunes one entry, then won't the model end up
> being out of date?

Not sure whether such a hypothetical case can ever happen, but if it did then as you point out the model would end up outdated.
In fact, onNavigationHistoryChanged is not enough to allow fine-grained updates of the model. To achieve that, I’ll need to implement a NotificationObserver that reacts to NOTIFICATION_NAV_LIST_PRUNED and NOTIFICATION_NAV_ENTRY_CHANGED, as well as implement WebContentsObserver::NavigationEntryCommitted() in oxide::WebView.
Does that make sense?

lp:~osomon/oxide/navigation-api updated
274. By Olivier Tilloy

Emit fine-grained notifications on oxide::WebView when the navigation history changes.

275. By Olivier Tilloy

Actually register to notifications.

276. By Olivier Tilloy

Hook to the navigation notifications on the Qt side.

277. By Olivier Tilloy

Update the navigation history model when notified that it changed.

278. By Olivier Tilloy

Discard notifications coming from other navigation controllers.

279. By Olivier Tilloy

Fix property type.

280. By Olivier Tilloy

Use tryCompare because the title is changed asynchronously.

281. By Olivier Tilloy

Implement WebContentsObserver::TitleWasSet to react to immediate title changes that are not notified otherwise.

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

I just fixed the last remaining issue, this is now ready for review.

lp:~osomon/oxide/navigation-api updated
282. By Olivier Tilloy

Merge the latest changes from trunk.

283. By Olivier Tilloy

Instantiate the NotificationRegistrar only when initializing the WebView.

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

Fixed to work with the latest trunk.

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

This looks mostly ok now, but I don't understand why you made the change in r283 :)

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

> This looks mostly ok now, but I don't understand why you made the change in
> r283 :)

After merging the latest changes from trunk (at revision 282), this code was consistently crashing at startup, because the registrar was instantiated at construction time, before the WebContents was assigned.

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Ok, that's fine. This is a result of http://bazaar.launchpad.net/~oxide-developers/oxide/oxide.trunk/revision/282, which requires that the browser components are started by a WebContext rather than a WebView.

Could you please change it to use a scoped_ptr though? Once that's done, feel free to merge it in. Thanks!

review: Approve
lp:~osomon/oxide/navigation-api updated
284. By Olivier Tilloy

Use a scoped_ptr instead of a plain pointer.

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

> Could you please change it to use a scoped_ptr though?
> Once that's done, feel free to merge it in. Thanks!

Done, and merged. Thanks for the review!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qt/core/glue/oxide_qt_web_view_adapter.cc'
2--- qt/core/glue/oxide_qt_web_view_adapter.cc 2013-12-12 22:54:44 +0000
3+++ qt/core/glue/oxide_qt_web_view_adapter.cc 2014-01-07 14:38:44 +0000
4@@ -126,5 +126,33 @@
5 return priv->web_contents() != NULL;
6 }
7
8+int WebViewAdapter::getNavigationEntryCount() const {
9+ return priv->GetNavigationEntryCount();
10+}
11+
12+int WebViewAdapter::getNavigationCurrentEntryIndex() const {
13+ return priv->GetNavigationCurrentEntryIndex();
14+}
15+
16+void WebViewAdapter::setNavigationCurrentEntryIndex(int index) {
17+ priv->SetNavigationCurrentEntryIndex(index);
18+}
19+
20+int WebViewAdapter::getNavigationEntryUniqueID(int index) const {
21+ return priv->GetNavigationEntryUniqueID(index);
22+}
23+
24+QUrl WebViewAdapter::getNavigationEntryUrl(int index) const {
25+ return QUrl(QString::fromStdString(priv->GetNavigationEntryUrl(index).spec()));
26+}
27+
28+QString WebViewAdapter::getNavigationEntryTitle(int index) const {
29+ return QString::fromStdString(priv->GetNavigationEntryTitle(index));
30+}
31+
32+QDateTime WebViewAdapter::getNavigationEntryTimestamp(int index) const {
33+ return QDateTime::fromMSecsSinceEpoch(priv->GetNavigationEntryTimestamp(index).ToJsTime());
34+}
35+
36 } // namespace qt
37 } // namespace oxide
38
39=== modified file 'qt/core/glue/oxide_qt_web_view_adapter.h'
40--- qt/core/glue/oxide_qt_web_view_adapter.h 2013-12-16 12:18:07 +0000
41+++ qt/core/glue/oxide_qt_web_view_adapter.h 2014-01-07 14:38:44 +0000
42@@ -18,6 +18,7 @@
43 #ifndef _OXIDE_QT_CORE_GLUE_WEB_VIEW_ADAPTER_H_
44 #define _OXIDE_QT_CORE_GLUE_WEB_VIEW_ADAPTER_H_
45
46+#include <QDateTime>
47 #include <QList>
48 #include <QRect>
49 #include <QScopedPointer>
50@@ -95,6 +96,10 @@
51 const QString& error_description) = 0;
52 virtual void LoadSucceeded(const QUrl& url) = 0;
53
54+ virtual void NavigationEntryCommitted() = 0;
55+ virtual void NavigationListPruned(bool from_front, int count) = 0;
56+ virtual void NavigationEntryChanged(int index) = 0;
57+
58 virtual WebFrameAdapter* CreateWebFrame() = 0;
59
60 virtual QRect GetContainerBounds() = 0;
61@@ -103,6 +108,14 @@
62
63 bool isInitialized();
64
65+ int getNavigationEntryCount() const;
66+ int getNavigationCurrentEntryIndex() const;
67+ void setNavigationCurrentEntryIndex(int index);
68+ int getNavigationEntryUniqueID(int index) const;
69+ QUrl getNavigationEntryUrl(int index) const;
70+ QString getNavigationEntryTitle(int index) const;
71+ QDateTime getNavigationEntryTimestamp(int index) const;
72+
73 protected:
74 WebViewAdapter();
75
76
77=== modified file 'qt/core/glue/private/oxide_qt_web_view_adapter_p.cc'
78--- qt/core/glue/private/oxide_qt_web_view_adapter_p.cc 2013-12-16 12:18:07 +0000
79+++ qt/core/glue/private/oxide_qt_web_view_adapter_p.cc 2014-01-07 14:38:44 +0000
80@@ -77,6 +77,18 @@
81 a->LoadSucceeded(QUrl(QString::fromStdString(validated_url.spec())));
82 }
83
84+void WebViewAdapterPrivate::OnNavigationEntryCommitted() {
85+ a->NavigationEntryCommitted();
86+}
87+
88+void WebViewAdapterPrivate::OnNavigationListPruned(bool from_front, int count) {
89+ a->NavigationListPruned(from_front, count);
90+}
91+
92+void WebViewAdapterPrivate::OnNavigationEntryChanged(int index) {
93+ a->NavigationEntryChanged(index);
94+}
95+
96 oxide::WebFrame* WebViewAdapterPrivate::CreateWebFrame() {
97 return new WebFrame(a->CreateWebFrame());
98 }
99
100=== modified file 'qt/core/glue/private/oxide_qt_web_view_adapter_p.h'
101--- qt/core/glue/private/oxide_qt_web_view_adapter_p.h 2013-12-16 12:18:07 +0000
102+++ qt/core/glue/private/oxide_qt_web_view_adapter_p.h 2014-01-07 14:38:44 +0000
103@@ -61,6 +61,10 @@
104 const std::string& error_description) FINAL;
105 void OnLoadSucceeded(const GURL& validated_url) FINAL;
106
107+ void OnNavigationEntryCommitted() FINAL;
108+ void OnNavigationListPruned(bool from_front, int count) FINAL;
109+ void OnNavigationEntryChanged(int index) FINAL;
110+
111 oxide::WebFrame* CreateWebFrame() FINAL;
112
113 WebViewAdapter* a;
114
115=== added file 'qt/quick/api/oxideqquicknavigationhistory.cc'
116--- qt/quick/api/oxideqquicknavigationhistory.cc 1970-01-01 00:00:00 +0000
117+++ qt/quick/api/oxideqquicknavigationhistory.cc 2014-01-07 14:38:44 +0000
118@@ -0,0 +1,202 @@
119+// vim:expandtab:shiftwidth=2:tabstop=2:
120+// Copyright (C) 2013 Canonical Ltd.
121+
122+// This library is free software; you can redistribute it and/or
123+// modify it under the terms of the GNU Lesser General Public
124+// License as published by the Free Software Foundation; either
125+// version 2.1 of the License, or (at your option) any later version.
126+
127+// This library is distributed in the hope that it will be useful,
128+// but WITHOUT ANY WARRANTY; without even the implied warranty of
129+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
130+// Lesser General Public License for more details.
131+
132+// You should have received a copy of the GNU Lesser General Public
133+// License along with this library; if not, write to the Free Software
134+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
135+
136+#include "oxideqquicknavigationhistory_p.h"
137+#include "oxideqquicknavigationhistory_p_p.h"
138+
139+#include <QDateTime>
140+#include <QDebug>
141+#include <QSet>
142+#include <QString>
143+#include <QtAlgorithms>
144+#include <QUrl>
145+
146+#include "oxideqquickwebview_p.h"
147+#include "oxideqquickwebview_p_p.h"
148+
149+struct NavigationEntry {
150+ QUrl url;
151+ QString title;
152+ QDateTime timestamp;
153+};
154+
155+OxideQQuickNavigationHistory::OxideQQuickNavigationHistory(
156+ OxideQQuickWebView* webview) :
157+ QAbstractListModel(webview),
158+ d_ptr(new OxideQQuickNavigationHistoryPrivate) {
159+ Q_D(OxideQQuickNavigationHistory);
160+ d->q_ptr = this;
161+ d->webview = webview;
162+ d->entry_count = 0;
163+ d->current_index = -1;
164+}
165+
166+OxideQQuickNavigationHistory::~OxideQQuickNavigationHistory() {
167+ Q_D(OxideQQuickNavigationHistory);
168+ qDeleteAll(d->entry_cache);
169+ d->entry_cache.clear();
170+}
171+
172+void OxideQQuickNavigationHistory::onNavigationEntryCommitted() {
173+ Q_D(OxideQQuickNavigationHistory);
174+
175+ OxideQQuickWebViewPrivate* adapter = OxideQQuickWebViewPrivate::get(d->webview);
176+ int newCount = adapter->getNavigationEntryCount();
177+ int index = adapter->getNavigationCurrentEntryIndex();
178+ if (newCount > d->entry_count) {
179+ beginInsertRows(QModelIndex(), index, index);
180+ d->entry_count = newCount;
181+ int id = adapter->getNavigationEntryUniqueID(index);
182+ if (!d->entry_cache.contains(id)) {
183+ NavigationEntry* entry = new NavigationEntry;
184+ d->entry_cache.insert(id, entry);
185+ entry->url = adapter->getNavigationEntryUrl(index);
186+ entry->title = adapter->getNavigationEntryTitle(index);
187+ entry->timestamp = adapter->getNavigationEntryTimestamp(index);
188+ }
189+ endInsertRows();
190+ }
191+
192+ if (index != d->current_index) {
193+ d->current_index = index;
194+ Q_EMIT currentIndexChanged();
195+ }
196+}
197+
198+void OxideQQuickNavigationHistory::onNavigationListPruned(bool from_front, int count) {
199+ Q_D(OxideQQuickNavigationHistory);
200+
201+ int first;
202+ if (from_front) {
203+ first = 0;
204+ } else {
205+ first = d->entry_count - count;
206+ }
207+ int last = first + count - 1;
208+ beginRemoveRows(QModelIndex(), first, last);
209+ d->entry_count -= count;
210+ endRemoveRows();
211+
212+ OxideQQuickWebViewPrivate* adapter = OxideQQuickWebViewPrivate::get(d->webview);
213+ QSet<int> ids;
214+ for (int i = 0; i < d->entry_count; ++i) {
215+ ids.insert(adapter->getNavigationEntryUniqueID(i));
216+ }
217+ Q_FOREACH(int id, d->entry_cache.keys()) {
218+ if (!ids.contains(id)) {
219+ delete d->entry_cache.take(id);
220+ }
221+ }
222+}
223+
224+void OxideQQuickNavigationHistory::onNavigationEntryChanged(int index) {
225+ Q_D(OxideQQuickNavigationHistory);
226+
227+ OxideQQuickWebViewPrivate* adapter = OxideQQuickWebViewPrivate::get(d->webview);
228+ int id = adapter->getNavigationEntryUniqueID(index);
229+ NavigationEntry* entry;
230+ if (d->entry_cache.contains(id)) {
231+ entry = d->entry_cache.value(id);
232+ } else {
233+ entry = new NavigationEntry;
234+ d->entry_cache.insert(id, entry);
235+ }
236+ QVector<int> roles;
237+ QUrl url = adapter->getNavigationEntryUrl(index);
238+ if (url != entry->url) {
239+ entry->url = url;
240+ roles.append(OxideQQuickNavigationHistoryPrivate::Url);
241+ }
242+ QString title = adapter->getNavigationEntryTitle(index);
243+ if (title != entry->title) {
244+ entry->title = title;
245+ roles.append(OxideQQuickNavigationHistoryPrivate::Title);
246+ }
247+ QDateTime timestamp = adapter->getNavigationEntryTimestamp(index);
248+ if (timestamp != entry->timestamp) {
249+ entry->timestamp = timestamp;
250+ roles.append(OxideQQuickNavigationHistoryPrivate::Timestamp);
251+ }
252+ if (!roles.isEmpty()) {
253+ QModelIndex modelIndex = this->index(index, 0);
254+ Q_EMIT dataChanged(modelIndex, modelIndex, roles);
255+ }
256+}
257+
258+int OxideQQuickNavigationHistory::currentIndex() const {
259+ Q_D(const OxideQQuickNavigationHistory);
260+ return d->current_index;
261+}
262+
263+void OxideQQuickNavigationHistory::setCurrentIndex(int index) {
264+ Q_D(OxideQQuickNavigationHistory);
265+ if ((index < 0) || (index >= d->entry_count)) {
266+ qWarning() << "Invalid index:" << index;
267+ return;
268+ }
269+ if (index != d->current_index) {
270+ d->current_index = index;
271+ OxideQQuickWebViewPrivate* adapter = OxideQQuickWebViewPrivate::get(d->webview);
272+ adapter->setNavigationCurrentEntryIndex(index);
273+ Q_EMIT currentIndexChanged();
274+ }
275+}
276+
277+QHash<int, QByteArray> OxideQQuickNavigationHistory::roleNames() const {
278+ static QHash<int, QByteArray> roles;
279+ if (roles.isEmpty()) {
280+ roles[OxideQQuickNavigationHistoryPrivate::Url] = "url";
281+ roles[OxideQQuickNavigationHistoryPrivate::Title] = "title";
282+ roles[OxideQQuickNavigationHistoryPrivate::Timestamp] = "timestamp";
283+ }
284+ return roles;
285+}
286+
287+int OxideQQuickNavigationHistory::rowCount(const QModelIndex& parent) const {
288+ Q_UNUSED(parent);
289+ Q_D(const OxideQQuickNavigationHistory);
290+ return d->entry_count;
291+}
292+
293+QVariant OxideQQuickNavigationHistory::data(const QModelIndex& index, int role) const {
294+ Q_D(const OxideQQuickNavigationHistory);
295+ if (!index.isValid()) {
296+ return QVariant();
297+ }
298+ int row = index.row();
299+ if ((row < 0) || (row >= d->entry_count)) {
300+ return QVariant();
301+ }
302+ OxideQQuickWebViewPrivate* adapter = OxideQQuickWebViewPrivate::get(d->webview);
303+ int id = adapter->getNavigationEntryUniqueID(row);
304+ NavigationEntry* entry;
305+ if (d->entry_cache.contains(id)) {
306+ entry = d->entry_cache.value(id);
307+ } else {
308+ return QVariant();
309+ }
310+ switch (role) {
311+ case OxideQQuickNavigationHistoryPrivate::Url:
312+ return entry->url;
313+ case OxideQQuickNavigationHistoryPrivate::Title:
314+ return entry->title;
315+ case OxideQQuickNavigationHistoryPrivate::Timestamp:
316+ return entry->timestamp;
317+ default:
318+ return QVariant();
319+ }
320+}
321
322=== added file 'qt/quick/api/oxideqquicknavigationhistory_p.h'
323--- qt/quick/api/oxideqquicknavigationhistory_p.h 1970-01-01 00:00:00 +0000
324+++ qt/quick/api/oxideqquicknavigationhistory_p.h 2014-01-07 14:38:44 +0000
325@@ -0,0 +1,67 @@
326+// vim:expandtab:shiftwidth=2:tabstop=2:
327+// Copyright (C) 2013 Canonical Ltd.
328+
329+// This library is free software; you can redistribute it and/or
330+// modify it under the terms of the GNU Lesser General Public
331+// License as published by the Free Software Foundation; either
332+// version 2.1 of the License, or (at your option) any later version.
333+
334+// This library is distributed in the hope that it will be useful,
335+// but WITHOUT ANY WARRANTY; without even the implied warranty of
336+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
337+// Lesser General Public License for more details.
338+
339+// You should have received a copy of the GNU Lesser General Public
340+// License along with this library; if not, write to the Free Software
341+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
342+
343+#ifndef _OXIDE_QT_QUICK_API_NAVIGATION_HISTORY_P_H_
344+#define _OXIDE_QT_QUICK_API_NAVIGATION_HISTORY_P_H_
345+
346+#include <QAbstractListModel>
347+#include <QScopedPointer>
348+#include <QtQml>
349+
350+namespace oxide {
351+namespace qt {
352+class WebViewAdapter;
353+}
354+}
355+
356+class OxideQQuickNavigationHistoryPrivate;
357+class OxideQQuickWebView;
358+
359+class OxideQQuickNavigationHistory : public QAbstractListModel {
360+ Q_OBJECT
361+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
362+
363+ public:
364+ OxideQQuickNavigationHistory(OxideQQuickWebView* webview);
365+ ~OxideQQuickNavigationHistory();
366+
367+ // reimplemented from QAbstractListModel
368+ QHash<int, QByteArray> roleNames() const;
369+ int rowCount(const QModelIndex& parent = QModelIndex()) const;
370+ QVariant data(const QModelIndex& index, int role) const;
371+
372+ int currentIndex() const;
373+ void setCurrentIndex(int index);
374+
375+Q_SIGNALS:
376+ void currentIndexChanged();
377+
378+private Q_SLOTS:
379+ friend class OxideQQuickWebViewPrivate;
380+ void onNavigationEntryCommitted();
381+ void onNavigationListPruned(bool from_front, int count);
382+ void onNavigationEntryChanged(int index);
383+
384+private:
385+ Q_DISABLE_COPY(OxideQQuickNavigationHistory)
386+ QScopedPointer<OxideQQuickNavigationHistoryPrivate> d_ptr;
387+ Q_DECLARE_PRIVATE(OxideQQuickNavigationHistory)
388+};
389+
390+QML_DECLARE_TYPE(OxideQQuickNavigationHistory)
391+
392+#endif // _OXIDE_QT_QUICK_API_NAVIGATION_HISTORY_P_H_
393
394=== added file 'qt/quick/api/oxideqquicknavigationhistory_p_p.h'
395--- qt/quick/api/oxideqquicknavigationhistory_p_p.h 1970-01-01 00:00:00 +0000
396+++ qt/quick/api/oxideqquicknavigationhistory_p_p.h 2014-01-07 14:38:44 +0000
397@@ -0,0 +1,44 @@
398+// vim:expandtab:shiftwidth=2:tabstop=2:
399+// Copyright (C) 2013 Canonical Ltd.
400+
401+// This library is free software; you can redistribute it and/or
402+// modify it under the terms of the GNU Lesser General Public
403+// License as published by the Free Software Foundation; either
404+// version 2.1 of the License, or (at your option) any later version.
405+
406+// This library is distributed in the hope that it will be useful,
407+// but WITHOUT ANY WARRANTY; without even the implied warranty of
408+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
409+// Lesser General Public License for more details.
410+
411+// You should have received a copy of the GNU Lesser General Public
412+// License along with this library; if not, write to the Free Software
413+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
414+
415+#ifndef _OXIDE_QT_QUICK_API_NAVIGATION_HISTORY_P_P_H_
416+#define _OXIDE_QT_QUICK_API_NAVIGATION_HISTORY_P_P_H_
417+
418+#include <QMap>
419+
420+class OxideQQuickNavigationHistory;
421+class OxideQQuickWebView;
422+
423+struct NavigationEntry;
424+
425+class OxideQQuickNavigationHistoryPrivate {
426+ Q_DECLARE_PUBLIC(OxideQQuickNavigationHistory)
427+
428+ enum Roles {
429+ Url = Qt::UserRole + 1,
430+ Title,
431+ Timestamp
432+ };
433+
434+ OxideQQuickNavigationHistory* q_ptr;
435+ OxideQQuickWebView* webview;
436+ int entry_count;
437+ int current_index;
438+ QMap<int, NavigationEntry*> entry_cache;
439+};
440+
441+#endif // _OXIDE_QT_QUICK_API_NAVIGATION_HISTORY_P_P_H_
442
443=== modified file 'qt/quick/api/oxideqquickwebview.cc'
444--- qt/quick/api/oxideqquickwebview.cc 2013-12-19 12:37:21 +0000
445+++ qt/quick/api/oxideqquickwebview.cc 2014-01-07 14:38:44 +0000
446@@ -57,6 +57,7 @@
447 OxideQQuickWebViewPrivate::OxideQQuickWebViewPrivate(
448 OxideQQuickWebView* view) :
449 context(NULL),
450+ navigationHistory(view),
451 popup_menu(NULL),
452 init_props_(new InitData()),
453 load_progress_(0),
454@@ -148,6 +149,18 @@
455 emit q->loadingChanged(&event);
456 }
457
458+void OxideQQuickWebViewPrivate::NavigationEntryCommitted() {
459+ navigationHistory.onNavigationEntryCommitted();
460+}
461+
462+void OxideQQuickWebViewPrivate::NavigationListPruned(bool from_front, int count) {
463+ navigationHistory.onNavigationListPruned(from_front, count);
464+}
465+
466+void OxideQQuickWebViewPrivate::NavigationEntryChanged(int index) {
467+ navigationHistory.onNavigationEntryChanged(index);
468+}
469+
470 oxide::qt::WebFrameAdapter* OxideQQuickWebViewPrivate::CreateWebFrame() {
471 return OxideQQuickWebFramePrivate::get(new OxideQQuickWebFrame());
472 }
473@@ -466,6 +479,12 @@
474 d->context = context;
475 }
476
477+OxideQQuickNavigationHistory* OxideQQuickWebView::navigationHistory() {
478+ Q_D(OxideQQuickWebView);
479+
480+ return &d->navigationHistory;
481+}
482+
483 // static
484 OxideQQuickWebViewAttached* OxideQQuickWebView::qmlAttachedProperties(
485 QObject* object) {
486
487=== modified file 'qt/quick/api/oxideqquickwebview_p.h'
488--- qt/quick/api/oxideqquickwebview_p.h 2013-12-16 12:18:07 +0000
489+++ qt/quick/api/oxideqquickwebview_p.h 2014-01-07 14:38:44 +0000
490@@ -33,6 +33,7 @@
491
492 class OxideQLoadEvent;
493 class OxideQQuickMessageHandler;
494+class OxideQQuickNavigationHistory;
495 class OxideQQuickWebContext;
496 class OxideQQuickWebFrame;
497 class OxideQQuickWebView;
498@@ -69,6 +70,8 @@
499
500 Q_PROPERTY(OxideQQuickWebContext* context READ context WRITE setContext)
501
502+ Q_PROPERTY(OxideQQuickNavigationHistory* navigationHistory READ navigationHistory CONSTANT)
503+
504 Q_DECLARE_PRIVATE(OxideQQuickWebView)
505
506 public:
507@@ -104,6 +107,8 @@
508 OxideQQuickWebContext* context() const;
509 void setContext(OxideQQuickWebContext* context);
510
511+ OxideQQuickNavigationHistory* navigationHistory();
512+
513 static OxideQQuickWebViewAttached* qmlAttachedProperties(QObject* object);
514
515 public Q_SLOTS:
516
517=== modified file 'qt/quick/api/oxideqquickwebview_p_p.h'
518--- qt/quick/api/oxideqquickwebview_p_p.h 2013-12-16 12:18:07 +0000
519+++ qt/quick/api/oxideqquickwebview_p_p.h 2014-01-07 14:38:44 +0000
520@@ -25,6 +25,8 @@
521
522 #include "qt/core/glue/oxide_qt_web_view_adapter.h"
523
524+#include "oxideqquicknavigationhistory_p.h"
525+
526 class OxideQQuickMessageHandler;
527 class OxideQQuickWebContext;
528 class OxideQQuickWebView;
529@@ -68,6 +70,10 @@
530 const QString& error_description) Q_DECL_FINAL;
531 void LoadSucceeded(const QUrl& url) Q_DECL_FINAL;
532
533+ void NavigationEntryCommitted() Q_DECL_FINAL;
534+ void NavigationListPruned(bool from_front, int count) Q_DECL_FINAL;
535+ void NavigationEntryChanged(int index) Q_DECL_FINAL;
536+
537 oxide::qt::WebFrameAdapter* CreateWebFrame() Q_DECL_FINAL;
538
539 QRect GetContainerBounds() Q_DECL_FINAL;
540@@ -92,6 +98,7 @@
541 InitData* init_props() { return init_props_.data(); }
542
543 OxideQQuickWebContext* context;
544+ OxideQQuickNavigationHistory navigationHistory;
545 QQmlComponent* popup_menu;
546
547 private:
548
549=== modified file 'qt/quick/oxide_qml_plugin.cc'
550--- qt/quick/oxide_qml_plugin.cc 2013-10-31 03:16:28 +0000
551+++ qt/quick/oxide_qml_plugin.cc 2014-01-07 14:38:44 +0000
552@@ -26,6 +26,7 @@
553 #include "qt/core/api/oxideqincomingmessage.h"
554 #include "qt/core/api/oxideqloadevent.h"
555 #include "qt/quick/api/oxideqquickmessagehandler_p.h"
556+#include "qt/quick/api/oxideqquicknavigationhistory_p.h"
557 #include "qt/quick/api/oxideqquickoutgoingmessagerequest_p.h"
558 #include "qt/quick/api/oxideqquickuserscript_p.h"
559 #include "qt/quick/api/oxideqquickwebcontext_p.h"
560@@ -212,6 +213,8 @@
561 qmlRegisterUncreatableType<OxideQQuickWebFrame>(uri, 0, 1, "WebFrame",
562 "Frames are created automatically by Oxide to represent frames in the renderer");
563 qmlRegisterType<OxideQQuickWebContext>(uri, 0, 1, "WebContext");
564+ qmlRegisterUncreatableType<OxideQQuickNavigationHistory>(uri, 0, 1, "NavigationHistory",
565+ "Each WebView has a NavigationHistory automatically instantiated by Oxide");
566 qmlRegisterType<OxideQQuickWebView>(uri, 0, 1, "WebView");
567 }
568 };
569
570=== modified file 'qt/quick/qmlplugin.pro'
571--- qt/quick/qmlplugin.pro 2013-12-05 18:24:51 +0000
572+++ qt/quick/qmlplugin.pro 2014-01-07 14:38:44 +0000
573@@ -12,6 +12,7 @@
574
575 SOURCES += \
576 api/oxideqquickmessagehandler.cc \
577+ api/oxideqquicknavigationhistory.cc \
578 api/oxideqquickoutgoingmessagerequest.cc \
579 api/oxideqquickuserscript.cc \
580 api/oxideqquickwebcontext.cc \
581@@ -26,6 +27,8 @@
582 HEADERS += \
583 api/oxideqquickmessagehandler_p.h \
584 api/oxideqquickmessagehandler_p_p.h \
585+ api/oxideqquicknavigationhistory_p.h \
586+ api/oxideqquicknavigationhistory_p_p.h \
587 api/oxideqquickoutgoingmessagerequest_p.h \
588 api/oxideqquickoutgoingmessagerequest_p_p.h \
589 api/oxideqquickuserscript_p.h \
590
591=== modified file 'qt/tests/qmltests/data/tst_WebView_navigation1.html'
592--- qt/tests/qmltests/data/tst_WebView_navigation1.html 2013-09-24 21:30:30 +0000
593+++ qt/tests/qmltests/data/tst_WebView_navigation1.html 2014-01-07 14:38:44 +0000
594@@ -1,4 +1,7 @@
595 <html>
596+<head>
597+ <title>Navigation test 1</title>
598+</head>
599 <body>
600 <h1>Navigation test 1</h1>
601 </body>
602
603=== modified file 'qt/tests/qmltests/data/tst_WebView_navigation2.html'
604--- qt/tests/qmltests/data/tst_WebView_navigation2.html 2013-09-24 21:30:30 +0000
605+++ qt/tests/qmltests/data/tst_WebView_navigation2.html 2014-01-07 14:38:44 +0000
606@@ -1,4 +1,7 @@
607 <html>
608+<head>
609+ <title>Navigation test 2</title>
610+</head>
611 <body>
612 <h1>Navigation test 2</h1>
613 </body>
614
615=== modified file 'qt/tests/qmltests/data/tst_WebView_navigation3.html'
616--- qt/tests/qmltests/data/tst_WebView_navigation3.html 2013-09-24 21:30:30 +0000
617+++ qt/tests/qmltests/data/tst_WebView_navigation3.html 2014-01-07 14:38:44 +0000
618@@ -1,5 +1,8 @@
619 <html>
620+<head>
621+ <title>Navigation test 3</title>
622+</head>
623 <body>
624- <h1>Navigation test 2</h1>
625+ <h1>Navigation test 3</h1>
626 </body>
627 </html>
628
629=== modified file 'qt/tests/qmltests/data/tst_WebView_navigation4.html'
630--- qt/tests/qmltests/data/tst_WebView_navigation4.html 2013-09-24 21:30:30 +0000
631+++ qt/tests/qmltests/data/tst_WebView_navigation4.html 2014-01-07 14:38:44 +0000
632@@ -1,4 +1,7 @@
633 <html>
634+<head>
635+ <title>Navigation test 4</title>
636+</head>
637 <body>
638 <h1>Navigation test 4</h1>
639 </body>
640
641=== added file 'qt/tests/qmltests/data/tst_WebView_navigationHistory.qml'
642--- qt/tests/qmltests/data/tst_WebView_navigationHistory.qml 1970-01-01 00:00:00 +0000
643+++ qt/tests/qmltests/data/tst_WebView_navigationHistory.qml 2014-01-07 14:38:44 +0000
644@@ -0,0 +1,116 @@
645+import QtQuick 2.0
646+import QtTest 1.0
647+import com.canonical.Oxide 0.1
648+import com.canonical.Oxide.Testing 0.1
649+
650+TestWebView {
651+ id: webView
652+ focus: true
653+ width: 200
654+ height: 200
655+
656+ ListView {
657+ id: navigationView
658+ model: webView.navigationHistory
659+ currentIndex: model.currentIndex
660+ readonly property url currentUrl: currentItem ? currentItem.url : ""
661+ readonly property string currentTitle: currentItem ? currentItem.title : ""
662+ delegate: Item {
663+ readonly property url url: model.url
664+ readonly property string title: model.title
665+ }
666+ }
667+
668+ TestCase {
669+ id: test
670+ name: "WebView_navigationHistory"
671+ when: windowShown
672+
673+ readonly property alias count: navigationView.count
674+ readonly property alias currentIndex: navigationView.currentIndex
675+ readonly property alias currentUrl: navigationView.currentUrl
676+ readonly property alias currentTitle: navigationView.currentTitle
677+
678+ function verifyLoadSucceeded() {
679+ verify(webView.waitForLoadSucceeded(),
680+ "Timed out waiting for a successful load");
681+ }
682+
683+ function loadUrl(url) {
684+ webView.url = url;
685+ verifyLoadSucceeded();
686+ }
687+
688+ function compareAttributes(rCount, rCurrentIndex, rCurrentUrl,
689+ rCurrentTitle, message) {
690+ compare(count, rCount, message);
691+ compare(currentIndex, rCurrentIndex, message);
692+ compare(currentUrl, rCurrentUrl, message);
693+ tryCompare(test, "currentTitle", rCurrentTitle);
694+ }
695+
696+ function test_WebView_navigationHistory() {
697+ compareAttributes(0, -1, "", "",
698+ "Navigation history should be initially empty");
699+
700+ webView.navigationHistory.currentIndex = 0;
701+ compare(currentIndex, -1,
702+ "Cannot set the current index when the history is empty");
703+
704+ var url1 = "http://localhost:8080/tst_WebView_navigation1.html";
705+ var title1 = "Navigation test 1";
706+ loadUrl(url1);
707+ compareAttributes(1, 0, url1, title1,
708+ "One entry / current is the first one");
709+
710+ webView.navigationHistory.currentIndex = -1;
711+ compare(currentIndex, 0,
712+ "Cannot set the current index to an invalid value");
713+
714+ var url2 = "http://localhost:8080/tst_WebView_navigation2.html";
715+ var title2 = "Navigation test 2";
716+ loadUrl(url2);
717+ compareAttributes(2, 1, url2, title2,
718+ "Two entries / current entry is the last one");
719+
720+ webView.navigationHistory.currentIndex = 3;
721+ compare(currentIndex, 1,
722+ "Cannot set the current index to an invalid value");
723+
724+ webView.goBack();
725+ verifyLoadSucceeded();
726+ compareAttributes(2, 0, url1, title1,
727+ "No new entries / current is the first one");
728+
729+ webView.goForward();
730+ verifyLoadSucceeded();
731+ compareAttributes(2, 1, url2, title2,
732+ "No new entries / current is the last one");
733+
734+ webView.navigationHistory.currentIndex = 0;
735+ verifyLoadSucceeded();
736+ compareAttributes(2, 0, url1, title1,
737+ "No new entries / current is the first one");
738+
739+ var url3 = "http://localhost:8080/tst_WebView_navigation3.html";
740+ var title3 = "Navigation test 3";
741+ loadUrl(url3);
742+ compareAttributes(2, 1, url3, title3, "Two entries / last one updated");
743+
744+ loadUrl(url1);
745+ compareAttributes(3, 2, url1, title1,
746+ "Three entries / current is the last one");
747+
748+ webView.navigationHistory.currentIndex = 0;
749+ verifyLoadSucceeded();
750+ compareAttributes(3, 0, url1, title1,
751+ "No new entries / current is the first one");
752+
753+ var url4 = "http://localhost:8080/tst_WebView_navigation4.html";
754+ var title4 = "Navigation test 4";
755+ loadUrl(url4);
756+ compareAttributes(2, 1, url4, title4,
757+ "Entry count updated / current is the last one");
758+ }
759+ }
760+}
761
762=== modified file 'shared/browser/oxide_web_view.cc'
763--- shared/browser/oxide_web_view.cc 2013-12-16 12:18:07 +0000
764+++ shared/browser/oxide_web_view.cc 2014-01-07 14:38:44 +0000
765@@ -25,6 +25,13 @@
766 #include "content/public/browser/invalidate_type.h"
767 #include "content/public/browser/browser_context.h"
768 #include "content/public/browser/navigation_controller.h"
769+#include "content/public/browser/navigation_details.h"
770+#include "content/public/browser/navigation_entry.h"
771+#include "content/public/browser/notification_details.h"
772+#include "content/public/browser/notification_registrar.h"
773+#include "content/public/browser/notification_service.h"
774+#include "content/public/browser/notification_source.h"
775+#include "content/public/browser/notification_types.h"
776 #include "content/public/browser/web_contents.h"
777 #include "content/public/browser/web_contents_view.h"
778 #include "net/base/net_errors.h"
779@@ -205,6 +212,10 @@
780 const std::string& error_description) {}
781 void WebView::OnLoadSucceeded(const GURL& validated_url) {}
782
783+void WebView::OnNavigationEntryCommitted() {}
784+void WebView::OnNavigationListPruned(bool from_front, int count) {}
785+void WebView::OnNavigationEntryChanged(int index) {}
786+
787 WebView::WebView() :
788 root_frame_(NULL) {}
789
790@@ -240,7 +251,13 @@
791 }
792
793 web_contents_->SetDelegate(this);
794- Observe(web_contents_.get());
795+ WebContentsObserver::Observe(web_contents_.get());
796+
797+ registrar_.reset(new content::NotificationRegistrar);
798+ registrar_->Add(this, content::NOTIFICATION_NAV_LIST_PRUNED,
799+ content::NotificationService::AllBrowserContextsAndSources());
800+ registrar_->Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED,
801+ content::NotificationService::AllBrowserContextsAndSources());
802
803 return true;
804 }
805@@ -251,7 +268,9 @@
806 return;
807 }
808
809- Observe(NULL);
810+ registrar_.reset();
811+
812+ WebContentsObserver::Observe(NULL);
813
814 if (root_frame_) {
815 root_frame_->DestroyFrame();
816@@ -363,6 +382,62 @@
817 return BrowserContext::FromContent(web_contents_->GetBrowserContext());
818 }
819
820+int WebView::GetNavigationEntryCount() const {
821+ if (!web_contents_) {
822+ return 0;
823+ }
824+ return web_contents_->GetController().GetEntryCount();
825+}
826+
827+int WebView::GetNavigationCurrentEntryIndex() const {
828+ if (!web_contents_) {
829+ return -1;
830+ }
831+ return web_contents_->GetController().GetCurrentEntryIndex();
832+}
833+
834+void WebView::SetNavigationCurrentEntryIndex(int index) {
835+ if (web_contents_) {
836+ web_contents_->GetController().GoToIndex(index);
837+ }
838+}
839+
840+int WebView::GetNavigationEntryUniqueID(int index) const {
841+ if (!web_contents_) {
842+ return 0;
843+ }
844+ const content::NavigationController& controller = web_contents_->GetController();
845+ content::NavigationEntry* entry = controller.GetEntryAtIndex(index);
846+ return entry->GetUniqueID();
847+}
848+
849+const GURL& WebView::GetNavigationEntryUrl(int index) const {
850+ if (!web_contents_) {
851+ return GURL::EmptyGURL();
852+ }
853+ const content::NavigationController& controller = web_contents_->GetController();
854+ content::NavigationEntry* entry = controller.GetEntryAtIndex(index);
855+ return entry->GetURL();
856+}
857+
858+std::string WebView::GetNavigationEntryTitle(int index) const {
859+ if (!web_contents_) {
860+ return std::string();
861+ }
862+ const content::NavigationController& controller = web_contents_->GetController();
863+ content::NavigationEntry* entry = controller.GetEntryAtIndex(index);
864+ return base::UTF16ToUTF8(entry->GetTitle());
865+}
866+
867+base::Time WebView::GetNavigationEntryTimestamp(int index) const {
868+ if (!web_contents_) {
869+ return base::Time();
870+ }
871+ const content::NavigationController& controller = web_contents_->GetController();
872+ content::NavigationEntry* entry = controller.GetEntryAtIndex(index);
873+ return entry->GetTimestamp();
874+}
875+
876 WebFrame* WebView::GetRootFrame() const {
877 return root_frame_;
878 }
879@@ -389,6 +464,21 @@
880 return NULL;
881 }
882
883+void WebView::Observe(int type,
884+ const content::NotificationSource& source,
885+ const content::NotificationDetails& details) {
886+ if (content::Source<content::NavigationController>(source).ptr() != &web_contents()->GetController()) {
887+ return;
888+ }
889+ if (type == content::NOTIFICATION_NAV_LIST_PRUNED) {
890+ content::PrunedDetails* pruned_details = content::Details<content::PrunedDetails>(details).ptr();
891+ OnNavigationListPruned(pruned_details->from_front, pruned_details->count);
892+ } else if (type == content::NOTIFICATION_NAV_ENTRY_CHANGED) {
893+ int index = content::Details<content::EntryChangedDetails>(details).ptr()->index;
894+ OnNavigationEntryChanged(index);
895+ }
896+}
897+
898 void WebView::RenderViewHostChanged(content::RenderViewHost* old_host,
899 content::RenderViewHost* new_host) {
900 // Make sure the new RWHV gets the correct size
901@@ -480,6 +570,10 @@
902 DispatchLoadFailed(validated_url, error_code, error_description);
903 }
904
905+void WebView::NavigationEntryCommitted(
906+ const content::LoadCommittedDetails& load_details) {
907+ OnNavigationEntryCommitted();
908+}
909
910 void WebView::FrameDetached(content::RenderViewHost* rvh,
911 int64 frame_id) {
912@@ -491,6 +585,20 @@
913 frame->DestroyFrame();
914 }
915
916+void WebView::TitleWasSet(content::NavigationEntry* entry, bool explicit_set) {
917+ if (!web_contents_) {
918+ return;
919+ }
920+ const content::NavigationController& controller = web_contents_->GetController();
921+ int count = controller.GetEntryCount();
922+ for (int i = 0; i < count; ++i) {
923+ if (controller.GetEntryAtIndex(i) == entry) {
924+ OnNavigationEntryChanged(i);
925+ return;
926+ }
927+ }
928+}
929+
930 bool WebView::OnMessageReceived(const IPC::Message& message) {
931 bool handled = true;
932 IPC_BEGIN_MESSAGE_MAP(WebView, message)
933
934=== modified file 'shared/browser/oxide_web_view.h'
935--- shared/browser/oxide_web_view.h 2013-12-16 12:18:07 +0000
936+++ shared/browser/oxide_web_view.h 2014-01-07 14:38:44 +0000
937@@ -24,6 +24,7 @@
938 #include "base/basictypes.h"
939 #include "base/compiler_specific.h"
940 #include "base/memory/scoped_ptr.h"
941+#include "content/public/browser/notification_observer.h"
942 #include "content/public/browser/web_contents_delegate.h"
943 #include "content/public/browser/web_contents_observer.h"
944 #include "ui/gfx/rect.h"
945@@ -41,6 +42,7 @@
946
947 namespace content {
948
949+class NotificationRegistrar;
950 struct OpenURLParams;
951 class RenderWidgetHost;
952 class RenderWidgetHostView;
953@@ -58,6 +60,7 @@
954 // this. Note that this class will hold the main browser process
955 // components alive
956 class WebView : public MessageTarget,
957+ public content::NotificationObserver,
958 public content::WebContentsDelegate,
959 public content::WebContentsObserver {
960 public:
961@@ -94,9 +97,21 @@
962
963 BrowserContext* GetBrowserContext() const;
964
965+ int GetNavigationEntryCount() const;
966+ int GetNavigationCurrentEntryIndex() const;
967+ void SetNavigationCurrentEntryIndex(int index);
968+ int GetNavigationEntryUniqueID(int index) const;
969+ const GURL& GetNavigationEntryUrl(int index) const;
970+ std::string GetNavigationEntryTitle(int index) const;
971+ base::Time GetNavigationEntryTimestamp(int index) const;
972+
973 WebFrame* GetRootFrame() const;
974 WebFrame* FindFrameWithID(int64 frame_id) const;
975
976+ void Observe(int type,
977+ const content::NotificationSource& source,
978+ const content::NotificationDetails& details) FINAL;
979+
980 void RenderViewHostChanged(content::RenderViewHost* old_host,
981 content::RenderViewHost* new_host) FINAL;
982
983@@ -137,9 +152,14 @@
984 const base::string16& error_description,
985 content::RenderViewHost* render_view_host) FINAL;
986
987+ void NavigationEntryCommitted(
988+ const content::LoadCommittedDetails& load_details) FINAL;
989+
990 void FrameDetached(content::RenderViewHost* rvh,
991 int64 frame_id) FINAL;
992
993+ void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) FINAL;
994+
995 bool OnMessageReceived(const IPC::Message& message) FINAL;
996
997 virtual size_t GetMessageHandlerCount() const OVERRIDE;
998@@ -200,11 +220,17 @@
999 const std::string& error_description);
1000 virtual void OnLoadSucceeded(const GURL& validated_url);
1001
1002+ virtual void OnNavigationEntryCommitted();
1003+ virtual void OnNavigationListPruned(bool from_front, int count);
1004+ virtual void OnNavigationEntryChanged(int index);
1005+
1006 virtual WebFrame* CreateWebFrame() = 0;
1007
1008 scoped_ptr<content::WebContents> web_contents_;
1009 WebFrame* root_frame_;
1010
1011+ scoped_ptr<content::NotificationRegistrar> registrar_;
1012+
1013 DISALLOW_COPY_AND_ASSIGN(WebView);
1014 };
1015

Subscribers

People subscribed via source and target branches