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#include "webkitwebbackforwardlist.h"
23
24#include "BackForwardListImpl.h"
25#include "HistoryItem.h"
26#include "Page.h"
27#include "webkitglobalsprivate.h"
28#include "webkitwebbackforwardlistprivate.h"
29#include "webkitwebhistoryitem.h"
30#include "webkitwebhistoryitemprivate.h"
31#include "webkitwebview.h"
32#include "webkitwebviewprivate.h"
33#include <glib.h>
34
35/**
36 * SECTION:webkitwebbackforwardlist
37 * @short_description: The history of a #WebKitWebView
38 * @see_also: #WebKitWebView, #WebKitWebHistoryItem
39 *
40 * <informalexample><programlisting>
41 * /<!-- -->* Get the WebKitWebBackForwardList from the WebKitWebView *<!-- -->/
42 * WebKitWebBackForwardList *back_forward_list = webkit_web_view_get_back_forward_list (my_web_view);
43 * WebKitWebHistoryItem *item = webkit_web_back_forward_list_get_current_item (back_forward_list);
44 *
45 * /<!-- -->* Do something with a WebKitWebHistoryItem *<!-- -->/
46 * g_print("%p", item);
47 *
48 * /<!-- -->* Control some parameters *<!-- -->/
49 * WebKitWebBackForwardList *back_forward_list = webkit_web_view_get_back_forward_list (my_web_view);
50 * webkit_web_back_forward_list_set_limit (back_forward_list, 30);
51 * </programlisting></informalexample>
52 *
53 */
54
55using namespace WebKit;
56
57struct _WebKitWebBackForwardListPrivate {
58    WebCore::BackForwardListImpl* backForwardList;
59    gboolean disposed;
60};
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::BackForwardListImpl* 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    webkitInit();
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 = G_TYPE_INSTANCE_GET_PRIVATE(webBackForwardList, WEBKIT_TYPE_WEB_BACK_FORWARD_LIST, WebKitWebBackForwardListPrivate);
96}
97
98/**
99 * webkit_web_back_forward_list_new_with_web_view: (skip)
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 *
106 * Deprecated: 1.3.4: Instances of #WebKitWebBackForwardList are
107 * created and owned by #WebKitWebView instances only.
108 */
109WebKitWebBackForwardList* webkit_web_back_forward_list_new_with_web_view(WebKitWebView* webView)
110{
111    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), NULL);
112
113    WebKitWebBackForwardList* webBackForwardList;
114
115    webBackForwardList = WEBKIT_WEB_BACK_FORWARD_LIST(g_object_new(WEBKIT_TYPE_WEB_BACK_FORWARD_LIST, NULL));
116    WebKitWebBackForwardListPrivate* priv = webBackForwardList->priv;
117
118    priv->backForwardList = static_cast<WebCore::BackForwardListImpl*>(core(webView)->backForwardList());
119    priv->backForwardList->setEnabled(TRUE);
120
121    return webBackForwardList;
122}
123
124/**
125 * webkit_web_back_forward_list_go_forward:
126 * @web_back_forward_list: a #WebKitWebBackForwardList
127 *
128 * Steps forward in the back forward list
129 */
130void webkit_web_back_forward_list_go_forward(WebKitWebBackForwardList* webBackForwardList)
131{
132    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
133
134    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
135    if (backForwardList->enabled())
136        backForwardList->goForward();
137}
138
139/**
140 * webkit_web_back_forward_list_go_back:
141 * @web_back_forward_list: a #WebKitWebBackForwardList
142 *
143 * Steps backward in the back forward list
144 */
145void webkit_web_back_forward_list_go_back(WebKitWebBackForwardList* webBackForwardList)
146{
147    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
148
149    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
150    if (backForwardList->enabled())
151        backForwardList->goBack();
152}
153
154/**
155 * webkit_web_back_forward_list_contains_item:
156 * @web_back_forward_list: a #WebKitWebBackForwardList
157 * @history_item: (type WebKit.WebHistoryItem) (transfer none): the #WebKitWebHistoryItem to check
158 *
159 * Checks if @web_history_item is in the back forward list
160 *
161 * Return value: %TRUE if @web_history_item is in the back forward list, %FALSE if it doesn't
162 */
163gboolean webkit_web_back_forward_list_contains_item(WebKitWebBackForwardList* webBackForwardList, WebKitWebHistoryItem* webHistoryItem)
164{
165    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), FALSE);
166    g_return_val_if_fail(WEBKIT_IS_WEB_HISTORY_ITEM(webHistoryItem), FALSE);
167
168    WebCore::HistoryItem* historyItem = core(webHistoryItem);
169
170    g_return_val_if_fail(historyItem != NULL, FALSE);
171
172    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
173
174    return (backForwardList->enabled() ? backForwardList->containsItem(historyItem) : FALSE);
175}
176
177/**
178 * webkit_web_back_forward_list_go_to_item:
179 * @web_back_forward_list: a #WebKitWebBackForwardList
180 * @history_item: (type WebKit.WebHistoryItem) (transfer none): the #WebKitWebHistoryItem to go to
181 *
182 * Go to the specified @web_history_item in the back forward list
183 */
184void webkit_web_back_forward_list_go_to_item(WebKitWebBackForwardList* webBackForwardList, WebKitWebHistoryItem* webHistoryItem)
185{
186    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
187    g_return_if_fail(WEBKIT_IS_WEB_HISTORY_ITEM(webHistoryItem));
188
189    WebCore::HistoryItem* historyItem = core(webHistoryItem);
190    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
191
192    if (backForwardList->enabled() && historyItem)
193        backForwardList->goToItem(historyItem);
194}
195
196/**
197 * webkit_web_back_forward_list_get_forward_list_with_limit:
198 * @web_back_forward_list: a #WebKitWebBackForwardList
199 * @limit: the number of items to retrieve
200 *
201 * Returns a list of items that succeed the current item, limited by @limit
202 *
203 * Return value: (element-type WebKit.WebHistoryItem) (transfer container): a #GList of items succeeding the current item, limited by @limit
204 */
205GList* webkit_web_back_forward_list_get_forward_list_with_limit(WebKitWebBackForwardList* webBackForwardList, gint limit)
206{
207    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
208
209    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
210    if (!backForwardList || !backForwardList->enabled())
211        return NULL;
212
213    WebCore::HistoryItemVector items;
214    GList* forwardItems = { 0 };
215
216    backForwardList->forwardListWithLimit(limit, items);
217
218    for (unsigned i = 0; i < items.size(); i++) {
219        WebKitWebHistoryItem* webHistoryItem = kit(items[i]);
220        forwardItems = g_list_prepend(forwardItems, webHistoryItem);
221    }
222
223    return forwardItems;
224}
225
226/**
227 * webkit_web_back_forward_list_get_back_list_with_limit:
228 * @web_back_forward_list: a #WebKitWebBackForwardList
229 * @limit: the number of items to retrieve
230 *
231 * Returns a list of items that precede the current item, limited by @limit
232 *
233 * Return value: (element-type WebKit.WebHistoryItem) (transfer container): a #GList of items preceding the current item, limited by @limit
234 */
235GList* webkit_web_back_forward_list_get_back_list_with_limit(WebKitWebBackForwardList* webBackForwardList, gint limit)
236{
237    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
238
239    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
240    if (!backForwardList || !backForwardList->enabled())
241        return NULL;
242
243    WebCore::HistoryItemVector items;
244    GList* backItems = { 0 };
245
246    backForwardList->backListWithLimit(limit, items);
247
248    for (unsigned i = 0; i < items.size(); i++) {
249        WebKitWebHistoryItem* webHistoryItem = kit(items[i]);
250        backItems = g_list_prepend(backItems, webHistoryItem);
251    }
252
253    return backItems;
254}
255
256/**
257 * webkit_web_back_forward_list_get_back_item:
258 * @web_back_forward_list: a #WebKitWebBackForwardList
259 *
260 * Returns the item that precedes the current item
261 *
262 * Return value: (type WebKit.WebHistoryItem) (transfer none): the #WebKitWebHistoryItem preceding the current item
263 */
264WebKitWebHistoryItem* webkit_web_back_forward_list_get_back_item(WebKitWebBackForwardList* webBackForwardList)
265{
266    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
267
268    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
269    if (!backForwardList || !backForwardList->enabled())
270        return NULL;
271
272    WebCore::HistoryItem* historyItem = backForwardList->backItem();
273
274    return (historyItem ? kit(historyItem) : NULL);
275}
276
277/**
278 * webkit_web_back_forward_list_get_current_item:
279 * @web_back_forward_list: a #WebKitWebBackForwardList
280 *
281 * Returns the current item.
282 *
283 * Returns a NULL value if the back forward list is empty
284 *
285 * Return value: (type WebKit.WebHistoryItem) (transfer none): a #WebKitWebHistoryItem
286 */
287WebKitWebHistoryItem* webkit_web_back_forward_list_get_current_item(WebKitWebBackForwardList* webBackForwardList)
288{
289    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
290
291    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
292    if (!backForwardList || !backForwardList->enabled())
293        return NULL;
294
295    WebCore::HistoryItem* historyItem = backForwardList->currentItem();
296
297    return (historyItem ? kit(historyItem) : NULL);
298}
299
300/**
301 * webkit_web_back_forward_list_get_forward_item:
302 * @web_back_forward_list: a #WebKitWebBackForwardList
303 *
304 * Returns the item that succeeds the current item.
305 *
306 * Returns a NULL value if there nothing that succeeds the current item
307 *
308 * Return value: (type WebKit.WebHistoryItem) (transfer none): a #WebKitWebHistoryItem
309 */
310WebKitWebHistoryItem* webkit_web_back_forward_list_get_forward_item(WebKitWebBackForwardList* webBackForwardList)
311{
312    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
313
314    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
315    if (!backForwardList || !backForwardList->enabled())
316        return NULL;
317
318    WebCore::HistoryItem* historyItem = backForwardList->forwardItem();
319
320    return (historyItem ? kit(historyItem) : NULL);
321}
322
323/**
324 * webkit_web_back_forward_list_get_nth_item:
325 * @web_back_forward_list: a #WebKitWebBackForwardList
326 * @index: the index of the item
327 *
328 * Returns the item at a given index relative to the current item.
329 *
330 * Return value: (type WebKit.WebHistoryItem) (transfer none): the #WebKitWebHistoryItem located at the specified index relative to the current item
331 */
332WebKitWebHistoryItem* webkit_web_back_forward_list_get_nth_item(WebKitWebBackForwardList* webBackForwardList, gint index)
333{
334    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
335
336    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
337    if (!backForwardList)
338        return NULL;
339
340    WebCore::HistoryItem* historyItem = backForwardList->itemAtIndex(index);
341
342    return (historyItem ? kit(historyItem) : NULL);
343}
344
345/**
346 * webkit_web_back_forward_list_get_back_length:
347 * @web_back_forward_list: a #WebKitWebBackForwardList
348 *
349 * Returns the number of items that preced the current item.
350 *
351 * Return value: a #gint corresponding to the number of items preceding the current item
352 */
353gint webkit_web_back_forward_list_get_back_length(WebKitWebBackForwardList* webBackForwardList)
354{
355    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), 0);
356
357    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
358    if (!backForwardList || !backForwardList->enabled())
359        return 0;
360
361    return backForwardList->backListCount();
362}
363
364/**
365 * webkit_web_back_forward_list_get_forward_length:
366 * @web_back_forward_list: a #WebKitWebBackForwardList
367 *
368 * Returns the number of items that succeed the current item.
369 *
370 * Return value: a #gint corresponding to the nuber of items succeeding the current item
371 */
372gint webkit_web_back_forward_list_get_forward_length(WebKitWebBackForwardList* webBackForwardList)
373{
374    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), 0);
375
376    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
377    if (!backForwardList || !backForwardList->enabled())
378        return 0;
379
380    return backForwardList->forwardListCount();
381}
382
383/**
384 * webkit_web_back_forward_list_get_limit:
385 * @web_back_forward_list: a #WebKitWebBackForwardList
386 *
387 * Returns the maximum limit of the back forward list.
388 *
389 * Return value: a #gint indicating the number of #WebKitWebHistoryItem the back forward list can hold
390 */
391gint webkit_web_back_forward_list_get_limit(WebKitWebBackForwardList* webBackForwardList)
392{
393    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), 0);
394
395    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
396    if (!backForwardList || !backForwardList->enabled())
397        return 0;
398
399    return backForwardList->capacity();
400}
401
402/**
403 * webkit_web_back_forward_list_set_limit:
404 * @web_back_forward_list: a #WebKitWebBackForwardList
405 * @limit: the limit to set the back forward list to
406 *
407 * Sets the maximum limit of the back forward list. If the back forward list
408 * exceeds its capacity, items will be removed everytime a new item has been
409 * added.
410 */
411void webkit_web_back_forward_list_set_limit(WebKitWebBackForwardList* webBackForwardList, gint limit)
412{
413    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
414
415    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
416    if (backForwardList)
417        backForwardList->setCapacity(limit);
418}
419
420/**
421 * webkit_web_back_forward_list_add_item:
422 * @web_back_forward_list: a #WebKitWebBackForwardList
423 * @history_item: (type WebKit.WebHistoryItem) (transfer none): the #WebKitWebHistoryItem to add
424 *
425 * Adds the item to the #WebKitWebBackForwardList.
426 *
427 * The @webBackForwardList will add a reference to the @webHistoryItem, so you
428 * don't need to keep a reference once you've added it to the list.
429 *
430 * Since: 1.1.1
431 */
432void webkit_web_back_forward_list_add_item(WebKitWebBackForwardList *webBackForwardList, WebKitWebHistoryItem *webHistoryItem)
433{
434    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
435
436    g_object_ref(webHistoryItem);
437
438    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
439    WebCore::HistoryItem* historyItem = core(webHistoryItem);
440
441    backForwardList->addItem(historyItem);
442}
443
444/**
445 * webkit_web_back_forward_list_clear:
446 * @web_back_forward_list: the #WebKitWebBackForwardList to be cleared
447 *
448 * Clears the @webBackForwardList by removing all its elements. Note that not even
449 * the current page is kept in list when cleared so you would have to add it later.
450 *
451 * Since: 1.3.1
452 **/
453void webkit_web_back_forward_list_clear(WebKitWebBackForwardList* webBackForwardList)
454{
455    g_return_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList));
456
457    WebCore::BackForwardListImpl* backForwardList = core(webBackForwardList);
458    if (!backForwardList || !backForwardList->enabled() || !backForwardList->entries().size())
459        return;
460
461    // Clear the current list by setting capacity to 0
462    int capacity = backForwardList->capacity();
463    backForwardList->setCapacity(0);
464    backForwardList->setCapacity(capacity);
465}
466
467WebCore::BackForwardListImpl* WebKit::core(WebKitWebBackForwardList* webBackForwardList)
468{
469    g_return_val_if_fail(WEBKIT_IS_WEB_BACK_FORWARD_LIST(webBackForwardList), NULL);
470
471    return webBackForwardList->priv ? webBackForwardList->priv->backForwardList : 0;
472}
473