1/*
2 * Copyright (C) 2008 Jan Michael C. Alonzo
3 * Copyright (C) 2009 Igalia S.L.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB.  If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22
23#include "webkitwebbackforwardlist.h"
24#include "webkitprivate.h"
25#include "webkitwebhistoryitem.h"
26#include "webkitwebview.h"
27
28#include <glib.h>
29
30#include "BackForwardList.h"
31#include "HistoryItem.h"
32
33/**
34 * SECTION:webkitwebbackforwardlist
35 * @short_description: The history of a #WebKitWebView
36 * @see_also: #WebKitWebView, #WebKitWebHistoryItem
37 *
38 * <informalexample><programlisting>
39 * /<!-- -->* Get the WebKitWebBackForwardList from the WebKitWebView *<!-- -->/
40 * WebKitWebBackForwardList *back_forward_list = webkit_web_view_get_back_forward_list (my_web_view);
41 * WebKitWebHistoryItem *item = webkit_web_back_forward_list_get_current_item (back_forward_list);
42 *
43 * /<!-- -->* Do something with a WebKitWebHistoryItem *<!-- -->/
44 * g_print("%p", item);
45 *
46 * /<!-- -->* Control some parameters *<!-- -->/
47 * WebKitWebBackForwardList *back_forward_list = webkit_web_view_get_back_forward_list (my_web_view);
48 * webkit_web_back_forward_list_set_limit (back_forward_list, 30);
49 * </programlisting></informalexample>
50 *
51 */
52
53using namespace WebKit;
54
55struct _WebKitWebBackForwardListPrivate {
56    WebCore::BackForwardList* backForwardList;
57    gboolean disposed;
58};
59
60#define WEBKIT_WEB_BACK_FORWARD_LIST_GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_WEB_BACK_FORWARD_LIST, WebKitWebBackForwardListPrivate))
61
62G_DEFINE_TYPE(WebKitWebBackForwardList, webkit_web_back_forward_list, G_TYPE_OBJECT);
63
64static void webkit_web_back_forward_list_dispose(GObject* object)
65{
66    WebKitWebBackForwardList* list = WEBKIT_WEB_BACK_FORWARD_LIST(object);
67    WebCore::BackForwardList* backForwardList = core(list);
68    WebKitWebBackForwardListPrivate* priv = list->priv;
69
70    if (!priv->disposed) {
71        priv->disposed = true;
72
73        WebCore::HistoryItemVector items = backForwardList->entries();
74        GHashTable* table = webkit_history_items();
75        for (unsigned i = 0; i < items.size(); i++)
76            g_hash_table_remove(table, items[i].get());
77    }
78
79    G_OBJECT_CLASS(webkit_web_back_forward_list_parent_class)->dispose(object);
80}
81
82static void webkit_web_back_forward_list_class_init(WebKitWebBackForwardListClass* klass)
83{
84    GObjectClass* object_class = G_OBJECT_CLASS(klass);
85
86    object_class->dispose = webkit_web_back_forward_list_dispose;
87
88    webkit_init();
89
90    g_type_class_add_private(klass, sizeof(WebKitWebBackForwardListPrivate));
91}
92
93static void webkit_web_back_forward_list_init(WebKitWebBackForwardList* webBackForwardList)
94{
95    webBackForwardList->priv = WEBKIT_WEB_BACK_FORWARD_LIST_GET_PRIVATE(webBackForwardList);
96}
97
98/**
99 * webkit_web_back_forward_list_new_with_web_view:
100 * @web_view: the back forward list's #WebKitWebView
101 *
102 * Creates an instance of the back forward list with a controlling #WebKitWebView
103 *
104 * Return value: a #WebKitWebBackForwardList
105 */
106WebKitWebBackForwardList* webkit_web_back_forward_list_new_with_web_view(WebKitWebView* webView)
107{
108    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
109
110    WebKitWebBackForwardList* webBackForwardList;
111
112    webBackForwardList = WEBKIT_WEB_BACK_FORWARD_LIST(g_object_new(WEBKIT_TYPE_WEB_BACK_FORWARD_LIST, NULL));
113    WebKitWebBackForwardListPrivate* priv = webBackForwardList->priv;
114
115    priv->backForwardList = core(webView)->backForwardList();
116    priv->backForwardList->setEnabled(TRUE);
117
118    return webBackForwardList;
119}
120
121/**
122 * webkit_web_back_forward_list_go_forward:
123 * @web_back_forward_list: a #WebKitWebBackForwardList
124 *
125 * Steps forward in the back forward list
126 */
127void webkit_web_back_forward_list_go_forward(WebKitWebBackForwardList* webBackForwardList)
128{
129    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
130
131    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
132    if (backForwardList->enabled())
133        backForwardList->goForward();
134}
135
136/**
137 * webkit_web_back_forward_list_go_back:
138 * @web_back_forward_list: a #WebKitWebBackForwardList
139 *
140 * Steps backward in the back forward list
141 */
142void webkit_web_back_forward_list_go_back(WebKitWebBackForwardList* webBackForwardList)
143{
144    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
145
146    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
147    if (backForwardList->enabled())
148        backForwardList->goBack();
149}
150
151/**
152 * webkit_web_back_forward_list_contains_item:
153 * @web_back_forward_list: a #WebKitWebBackForwardList
154 * @history_item: the #WebKitWebHistoryItem to check
155 *
156 * Checks if @web_history_item is in the back forward list
157 *
158 * Return: %TRUE if @web_history_item is in the back forward list, %FALSE if it doesn't
159 */
160gboolean webkit_web_back_forward_list_contains_item(WebKitWebBackForwardList* webBackForwardList, WebKitWebHistoryItem* webHistoryItem)
161{
162    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), FALSE);
163    g_return_val_if_fail(WEBKIT_IS_WEB_HISTORY_ITEM(webHistoryItem), FALSE);
164
165    WebCore::HistoryItem* historyItem = core(webHistoryItem);
166
167    g_return_val_if_fail(historyItem != NULL, FALSE);
168
169    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
170
171    return (backForwardList->enabled() ? backForwardList->containsItem(historyItem) : FALSE);
172}
173
174/**
175 * webkit_web_back_forward_list_go_to_item:
176 * @web_back_forward_list: a #WebKitWebBackForwardList
177 * @history_item: the #WebKitWebHistoryItem to go to
178 *
179 * Go to the specified @web_history_item in the back forward list
180 */
181void webkit_web_back_forward_list_go_to_item(WebKitWebBackForwardList* webBackForwardList, WebKitWebHistoryItem* webHistoryItem)
182{
183    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
184    g_return_if_fail(WEBKIT_IS_WEB_HISTORY_ITEM(webHistoryItem));
185
186    WebCore::HistoryItem* historyItem = core(webHistoryItem);
187    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
188
189    if (backForwardList->enabled() && historyItem)
190        backForwardList->goToItem(historyItem);
191}
192
193/**
194 * webkit_web_back_forward_list_get_forward_list_with_limit:
195 * @web_back_forward_list: a #WebKitWebBackForwardList
196 * @limit: the number of items to retrieve
197 *
198 * Returns a list of items that succeed the current item, limited by @limit
199 *
200 * Return value: a #GList of items succeeding the current item, limited by @limit
201 */
202GList* webkit_web_back_forward_list_get_forward_list_with_limit(WebKitWebBackForwardList* webBackForwardList, gint limit)
203{
204    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
205
206    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
207    if (!backForwardList || !backForwardList->enabled())
208        return NULL;
209
210    WebCore::HistoryItemVector items;
211    GList* forwardItems = { 0 };
212
213    backForwardList->forwardListWithLimit(limit, items);
214
215    for (unsigned i = 0; i < items.size(); i++) {
216        WebKitWebHistoryItem* webHistoryItem = kit(items[i]);
217        forwardItems = g_list_prepend(forwardItems, webHistoryItem);
218    }
219
220    return forwardItems;
221}
222
223/**
224 * webkit_web_back_forward_list_get_back_list_with_limit:
225 * @web_back_forward_list: a #WebKitWebBackForwardList
226 * @limit: the number of items to retrieve
227 *
228 * Returns a list of items that precede the current item, limited by @limit
229 *
230 * Return value: a #GList of items preceding the current item, limited by @limit
231 */
232GList* webkit_web_back_forward_list_get_back_list_with_limit(WebKitWebBackForwardList* webBackForwardList, gint limit)
233{
234    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
235
236    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
237    if (!backForwardList || !backForwardList->enabled())
238        return NULL;
239
240    WebCore::HistoryItemVector items;
241    GList* backItems = { 0 };
242
243    backForwardList->backListWithLimit(limit, items);
244
245    for (unsigned i = 0; i < items.size(); i++) {
246        WebKitWebHistoryItem* webHistoryItem = kit(items[i]);
247        backItems = g_list_prepend(backItems, webHistoryItem);
248    }
249
250    return backItems;
251}
252
253/**
254 * webkit_web_back_forward_list_get_back_item:
255 * @web_back_forward_list: a #WebBackForwardList
256 *
257 * Returns the item that precedes the current item
258 *
259 * Return value: the #WebKitWebHistoryItem preceding the current item
260 */
261WebKitWebHistoryItem* webkit_web_back_forward_list_get_back_item(WebKitWebBackForwardList* webBackForwardList)
262{
263    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
264
265    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
266    if (!backForwardList || !backForwardList->enabled())
267        return NULL;
268
269    WebCore::HistoryItem* historyItem = backForwardList->backItem();
270
271    return (historyItem ? kit(historyItem) : NULL);
272}
273
274/**
275 * webkit_web_back_forward_list_get_current_item:
276 * @web_back_forward_list: a #WebKitWebBackForwardList
277 *
278 * Returns the current item.
279 *
280 * Returns a NULL value if the back forward list is empty
281 *
282 * Return value: a #WebKitWebHistoryItem
283 */
284WebKitWebHistoryItem* webkit_web_back_forward_list_get_current_item(WebKitWebBackForwardList* webBackForwardList)
285{
286    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
287
288    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
289    if (!backForwardList || !backForwardList->enabled())
290        return NULL;
291
292    WebCore::HistoryItem* historyItem = backForwardList->currentItem();
293
294    return (historyItem ? kit(historyItem) : NULL);
295}
296
297/**
298 * webkit_web_back_forward_list_get_forward_item:
299 * @web_back_forward_list: a #WebKitWebBackForwardList
300 *
301 * Returns the item that succeeds the current item.
302 *
303 * Returns a NULL value if there nothing that succeeds the current item
304 *
305 * Return value: a #WebKitWebHistoryItem
306 */
307WebKitWebHistoryItem* webkit_web_back_forward_list_get_forward_item(WebKitWebBackForwardList* webBackForwardList)
308{
309    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
310
311    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
312    if (!backForwardList || !backForwardList->enabled())
313        return NULL;
314
315    WebCore::HistoryItem* historyItem = backForwardList->forwardItem();
316
317    return (historyItem ? kit(historyItem) : NULL);
318}
319
320/**
321 * webkit_web_back_forward_list_get_nth_item:
322 * @web_back_forward_list: a #WebKitWebBackForwardList
323 * @index: the index of the item
324 *
325 * Returns the item at a given index relative to the current item.
326 *
327 * Return value: the #WebKitWebHistoryItem located at the specified index relative to the current item
328 */
329WebKitWebHistoryItem* webkit_web_back_forward_list_get_nth_item(WebKitWebBackForwardList* webBackForwardList, gint index)
330{
331    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
332
333    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
334    if (!backForwardList)
335        return NULL;
336
337    WebCore::HistoryItem* historyItem = backForwardList->itemAtIndex(index);
338
339    return (historyItem ? kit(historyItem) : NULL);
340}
341
342/**
343 * webkit_web_back_forward_list_get_back_length:
344 * @web_back_forward_list: a #WebKitWebBackForwardList
345 *
346 * Returns the number of items that preced the current item.
347 *
348 * Return value: a #gint corresponding to the number of items preceding the current item
349 */
350gint webkit_web_back_forward_list_get_back_length(WebKitWebBackForwardList* webBackForwardList)
351{
352    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), 0);
353
354    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
355    if (!backForwardList || !backForwardList->enabled())
356        return 0;
357
358    return backForwardList->backListCount();
359}
360
361/**
362 * webkit_web_back_forward_list_get_forward_length:
363 * @web_back_forward_list: a #WebKitWebBackForwardList
364 *
365 * Returns the number of items that succeed the current item.
366 *
367 * Return value: a #gint corresponding to the nuber of items succeeding the current item
368 */
369gint webkit_web_back_forward_list_get_forward_length(WebKitWebBackForwardList* webBackForwardList)
370{
371    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), 0);
372
373    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
374    if (!backForwardList || !backForwardList->enabled())
375        return 0;
376
377    return backForwardList->forwardListCount();
378}
379
380/**
381 * webkit_web_back_forward_list_get_limit:
382 * @web_back_forward_list: a #WebKitWebBackForwardList
383 *
384 * Returns the maximum limit of the back forward list.
385 *
386 * Return value: a #gint indicating the number of #WebHistoryItem the back forward list can hold
387 */
388gint webkit_web_back_forward_list_get_limit(WebKitWebBackForwardList* webBackForwardList)
389{
390    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), 0);
391
392    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
393    if (!backForwardList || !backForwardList->enabled())
394        return 0;
395
396    return backForwardList->capacity();
397}
398
399/**
400 * webkit_web_back_forward_list_set_limit:
401 * @web_back_forward_list: a #WebKitWebBackForwardList
402 * @limit: the limit to set the back forward list to
403 *
404 * Sets the maximum limit of the back forward list. If the back forward list
405 * exceeds its capacity, items will be removed everytime a new item has been
406 * added.
407 */
408void webkit_web_back_forward_list_set_limit(WebKitWebBackForwardList* webBackForwardList, gint limit)
409{
410    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
411
412    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
413    if (backForwardList)
414        backForwardList->setCapacity(limit);
415}
416
417/**
418 * webkit_web_back_forward_list_add_item:
419 * @web_back_forward_list: a #WebKitWebBackForwardList
420 * @history_item: the #WebKitWebHistoryItem to add
421 *
422 * Adds the item to the #WebKitWebBackForwardList.
423 *
424 * The @webBackForwardList will add a reference to the @webHistoryItem, so you
425 * don't need to keep a reference once you've added it to the list.
426 *
427 * Since: 1.1.1
428 */
429void webkit_web_back_forward_list_add_item(WebKitWebBackForwardList *webBackForwardList, WebKitWebHistoryItem *webHistoryItem)
430{
431    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
432
433    g_object_ref(webHistoryItem);
434
435    WebCore::BackForwardList* backForwardList = core(webBackForwardList);
436    WebCore::HistoryItem* historyItem = core(webHistoryItem);
437
438    backForwardList->addItem(historyItem);
439}
440
441WebCore::BackForwardList* WebKit::core(WebKitWebBackForwardList* webBackForwardList)
442{
443    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
444
445    return webBackForwardList->priv ? webBackForwardList->priv->backForwardList : 0;
446}
447