1/* 2 Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 4 This library is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Library General Public 6 License as published by the Free Software Foundation; either 7 version 2 of the License, or (at your option) any later version. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Library General Public License for more details. 13 14 You should have received a copy of the GNU Library General Public License 15 along with this library; see the file COPYING.LIB. If not, write to 16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 Boston, MA 02110-1301, USA. 18*/ 19 20#include "config.h" 21#include "qwebhistory.h" 22#include "qwebhistory_p.h" 23 24#include "BackForwardListImpl.h" 25#include "Frame.h" 26#include "IconDatabaseBase.h" 27#include "Image.h" 28#include "IntSize.h" 29#include "KURL.h" 30#include "Page.h" 31#include "PageGroup.h" 32#include <QWebPageAdapter.h> 33#include <wtf/text/WTFString.h> 34 35#include <QSharedData> 36#include <QDebug> 37 38static const int HistoryStreamVersion = 2; 39 40/*! 41 \class QWebHistoryItem 42 \since 4.4 43 \brief The QWebHistoryItem class represents one item in the history of a QWebPage 44 45 \inmodule QtWebKit 46 47 Each QWebHistoryItem instance represents an entry in the history stack of a Web page, 48 containing information about the page, its location, and when it was last visited. 49 50 The following table shows the properties of the page held by the history item, and 51 the functions used to access them. 52 53 \table 54 \header \li Function \li Description 55 \row \li title() \li The page title. 56 \row \li url() \li The location of the page. 57 \row \li originalUrl() \li The URL used to access the page. 58 \row \li lastVisited() \li The date and time of the user's last visit to the page. 59 \row \li icon() \li The icon associated with the page that was provided by the server. 60 \row \li userData() \li The user specific data that was stored with the history item. 61 \endtable 62 63 \note QWebHistoryItem objects are value based, but \e{explicitly shared}. Changing 64 a QWebHistoryItem instance by calling setUserData() will change all copies of that 65 instance. 66 67 \sa QWebHistory, QWebPage::history(), QWebHistoryInterface 68*/ 69 70/*! 71 Constructs a history item from \a other. The new item and \a other 72 will share their data, and modifying either this item or \a other will 73 modify both instances. 74*/ 75QWebHistoryItem::QWebHistoryItem(const QWebHistoryItem &other) 76 : d(other.d) 77{ 78} 79 80/*! 81 Assigns the \a other history item to this. This item and \a other 82 will share their data, and modifying either this item or \a other will 83 modify both instances. 84*/ 85QWebHistoryItem &QWebHistoryItem::operator=(const QWebHistoryItem &other) 86{ 87 d = other.d; 88 return *this; 89} 90 91/*! 92 Destroys the history item. 93*/ 94QWebHistoryItem::~QWebHistoryItem() 95{ 96} 97 98/*! 99 Returns the original URL associated with the history item. 100 101 \sa url() 102*/ 103QUrl QWebHistoryItem::originalUrl() const 104{ 105 if (d->item) 106 return d->item->originalURL(); 107 return QUrl(); 108} 109 110 111/*! 112 Returns the URL associated with the history item. 113 114 \sa originalUrl(), title(), lastVisited() 115*/ 116QUrl QWebHistoryItem::url() const 117{ 118 if (d->item) 119 return d->item->url(); 120 return QUrl(); 121} 122 123 124/*! 125 Returns the title of the page associated with the history item. 126 127 \sa icon(), url(), lastVisited() 128*/ 129QString QWebHistoryItem::title() const 130{ 131 if (d->item) 132 return d->item->title(); 133 return QString(); 134} 135 136 137/*! 138 Returns the date and time that the page associated with the item was last visited. 139 140 \sa title(), icon(), url() 141*/ 142QDateTime QWebHistoryItem::lastVisited() const 143{ 144 //FIXME : this will be wrong unless we correctly set lastVisitedTime ourselves 145 if (d->item) 146 return QDateTime::fromTime_t((uint)d->item->lastVisitedTime()); 147 return QDateTime(); 148} 149 150 151/*! 152 Returns the icon associated with the history item. 153 154 \sa title(), url(), lastVisited() 155*/ 156QIcon QWebHistoryItem::icon() const 157{ 158 if (d->item) 159 return *WebCore::iconDatabase().synchronousNativeIconForPageURL(d->item->url(), WebCore::IntSize(16, 16)); 160 161 return QIcon(); 162} 163 164/*! 165 \since 4.5 166 Returns the user specific data that was stored with the history item. 167 168 \sa setUserData() 169*/ 170QVariant QWebHistoryItem::userData() const 171{ 172 if (d->item) 173 return d->item->userData(); 174 return QVariant(); 175} 176 177/*! 178 \since 4.5 179 180 Stores user specific data \a userData with the history item. 181 182 \note All copies of this item will be modified. 183 184 \sa userData() 185*/ 186void QWebHistoryItem::setUserData(const QVariant& userData) 187{ 188 if (d->item) 189 d->item->setUserData(userData); 190} 191 192/*!* 193 \internal 194*/ 195QWebHistoryItem::QWebHistoryItem(QWebHistoryItemPrivate *priv) 196{ 197 d = priv; 198} 199 200/*! 201 \since 4.5 202 Returns whether this is a valid history item. 203*/ 204bool QWebHistoryItem::isValid() const 205{ 206 return d->item; 207} 208 209/*! 210 \class QWebHistory 211 \since 4.4 212 \brief The QWebHistory class represents the history of a QWebPage 213 214 \inmodule QtWebKit 215 216 Each QWebPage instance contains a history of visited pages that can be accessed 217 by QWebPage::history(). QWebHistory represents this history and makes it possible 218 to navigate it. 219 220 The history uses the concept of a \e{current item}, dividing the pages visited 221 into those that can be visited by navigating \e back and \e forward using the 222 back() and forward() functions. The current item can be obtained by calling 223 currentItem(), and an arbitrary item in the history can be made the current 224 item by passing it to goToItem(). 225 226 A list of items describing the pages that can be visited by going back can be 227 obtained by calling the backItems() function; similarly, items describing the 228 pages ahead of the current page can be obtained with the forwardItems() function. 229 The total list of items is obtained with the items() function. 230 231 Just as with containers, functions are available to examine the history in terms 232 of a list. Arbitrary items in the history can be obtained with itemAt(), the total 233 number of items is given by count(), and the history can be cleared with the 234 clear() function. 235 236 QWebHistory's state can be saved to a QDataStream using the >> operator and loaded 237 by using the << operator. 238 239 \sa QWebHistoryItem, QWebHistoryInterface, QWebPage 240*/ 241 242 243QWebHistory::QWebHistory() 244 : d(0) 245{ 246} 247 248QWebHistory::~QWebHistory() 249{ 250 delete d; 251} 252 253/*! 254 Clears the history. 255 256 \sa count(), items() 257*/ 258void QWebHistory::clear() 259{ 260 //shortcut to private BackForwardListImpl 261 WebCore::BackForwardListImpl* lst = d->lst; 262 263 //clear visited links 264 WebCore::Page* page = static_cast<WebCore::BackForwardListImpl*>(lst)->page(); 265 if (page && page->groupPtr()) 266 page->groupPtr()->removeVisitedLinks(); 267 268 //if count() == 0 then just return 269 if (!lst->entries().size()) 270 return; 271 272 RefPtr<WebCore::HistoryItem> current = lst->currentItem(); 273 int capacity = lst->capacity(); 274 lst->setCapacity(0); 275 276 lst->setCapacity(capacity); //revert capacity 277 lst->addItem(current.get()); //insert old current item 278 lst->goToItem(current.get()); //and set it as current again 279 280 d->page()->updateNavigationActions(); 281} 282 283/*! 284 Returns a list of all items currently in the history. 285 286 \sa count(), clear() 287*/ 288QList<QWebHistoryItem> QWebHistory::items() const 289{ 290 const WebCore::HistoryItemVector &items = d->lst->entries(); 291 292 QList<QWebHistoryItem> ret; 293 for (unsigned i = 0; i < items.size(); ++i) { 294 QWebHistoryItemPrivate *priv = new QWebHistoryItemPrivate(items[i].get()); 295 ret.append(QWebHistoryItem(priv)); 296 } 297 return ret; 298} 299 300/*! 301 Returns the list of items in the backwards history list. 302 At most \a maxItems entries are returned. 303 304 \sa forwardItems() 305*/ 306QList<QWebHistoryItem> QWebHistory::backItems(int maxItems) const 307{ 308 WebCore::HistoryItemVector items(maxItems); 309 d->lst->backListWithLimit(maxItems, items); 310 311 QList<QWebHistoryItem> ret; 312 for (unsigned i = 0; i < items.size(); ++i) { 313 QWebHistoryItemPrivate *priv = new QWebHistoryItemPrivate(items[i].get()); 314 ret.append(QWebHistoryItem(priv)); 315 } 316 return ret; 317} 318 319/*! 320 Returns the list of items in the forward history list. 321 At most \a maxItems entries are returned. 322 323 \sa backItems() 324*/ 325QList<QWebHistoryItem> QWebHistory::forwardItems(int maxItems) const 326{ 327 WebCore::HistoryItemVector items(maxItems); 328 d->lst->forwardListWithLimit(maxItems, items); 329 330 QList<QWebHistoryItem> ret; 331 for (unsigned i = 0; i < items.size(); ++i) { 332 QWebHistoryItemPrivate *priv = new QWebHistoryItemPrivate(items[i].get()); 333 ret.append(QWebHistoryItem(priv)); 334 } 335 return ret; 336} 337 338/*! 339 Returns true if there is an item preceding the current item in the history; 340 otherwise returns false. 341 342 \sa canGoForward() 343*/ 344bool QWebHistory::canGoBack() const 345{ 346 return d->lst->backListCount() > 0; 347} 348 349/*! 350 Returns true if we have an item to go forward to; otherwise returns false. 351 352 \sa canGoBack() 353*/ 354bool QWebHistory::canGoForward() const 355{ 356 return d->lst->forwardListCount() > 0; 357} 358 359/*! 360 Set the current item to be the previous item in the history and goes to the 361 corresponding page; i.e., goes back one history item. 362 363 \sa forward(), goToItem() 364*/ 365void QWebHistory::back() 366{ 367 if (canGoBack()) { 368 WebCore::Page* page = static_cast<WebCore::BackForwardListImpl*>(d->lst)->page(); 369 page->goToItem(d->lst->backItem(), WebCore::FrameLoadTypeIndexedBackForward); 370 } 371} 372 373/*! 374 Sets the current item to be the next item in the history and goes to the 375 corresponding page; i.e., goes forward one history item. 376 377 \sa back(), goToItem() 378*/ 379void QWebHistory::forward() 380{ 381 if (canGoForward()) { 382 WebCore::Page* page = static_cast<WebCore::BackForwardListImpl*>(d->lst)->page(); 383 page->goToItem(d->lst->forwardItem(), WebCore::FrameLoadTypeIndexedBackForward); 384 } 385} 386 387/*! 388 Sets the current item to be the specified \a item in the history and goes to the page. 389 390 \sa back(), forward() 391*/ 392void QWebHistory::goToItem(const QWebHistoryItem &item) 393{ 394 WebCore::Page* page = static_cast<WebCore::BackForwardListImpl*>(d->lst)->page(); 395 page->goToItem(item.d->item, WebCore::FrameLoadTypeIndexedBackForward); 396} 397 398/*! 399 Returns the item before the current item in the history. 400*/ 401QWebHistoryItem QWebHistory::backItem() const 402{ 403 WebCore::HistoryItem *i = d->lst->backItem(); 404 QWebHistoryItemPrivate *priv = new QWebHistoryItemPrivate(i); 405 return QWebHistoryItem(priv); 406} 407 408/*! 409 Returns the current item in the history. 410*/ 411QWebHistoryItem QWebHistory::currentItem() const 412{ 413 WebCore::HistoryItem *i = d->lst->currentItem(); 414 QWebHistoryItemPrivate *priv = new QWebHistoryItemPrivate(i); 415 return QWebHistoryItem(priv); 416} 417 418/*! 419 Returns the item after the current item in the history. 420*/ 421QWebHistoryItem QWebHistory::forwardItem() const 422{ 423 WebCore::HistoryItem *i = d->lst->forwardItem(); 424 QWebHistoryItemPrivate *priv = new QWebHistoryItemPrivate(i); 425 return QWebHistoryItem(priv); 426} 427 428/*! 429 \since 4.5 430 Returns the index of the current item in history. 431*/ 432int QWebHistory::currentItemIndex() const 433{ 434 return d->lst->backListCount(); 435} 436 437/*! 438 Returns the item at index \a i in the history. 439*/ 440QWebHistoryItem QWebHistory::itemAt(int i) const 441{ 442 QWebHistoryItemPrivate *priv; 443 if (i < 0 || i >= count()) 444 priv = new QWebHistoryItemPrivate(0); 445 else { 446 WebCore::HistoryItem *item = d->lst->entries()[i].get(); 447 priv = new QWebHistoryItemPrivate(item); 448 } 449 return QWebHistoryItem(priv); 450} 451 452/*! 453 Returns the total number of items in the history. 454*/ 455int QWebHistory::count() const 456{ 457 return d->lst->entries().size(); 458} 459 460/*! 461 \since 4.5 462 Returns the maximum number of items in the history. 463 464 \sa setMaximumItemCount() 465*/ 466int QWebHistory::maximumItemCount() const 467{ 468 return d->lst->capacity(); 469} 470 471/*! 472 \since 4.5 473 Sets the maximum number of items in the history to \a count. 474 475 \sa maximumItemCount() 476*/ 477void QWebHistory::setMaximumItemCount(int count) 478{ 479 d->lst->setCapacity(count); 480} 481 482/*! 483 \since 4.6 484 \fn QDataStream& operator<<(QDataStream& stream, const QWebHistory& history) 485 \relates QWebHistory 486 487 \brief The operator<< function streams a history into a data stream. 488 489 It saves the \a history into the specified \a stream. 490*/ 491 492QDataStream& operator<<(QDataStream& target, const QWebHistory& history) 493{ 494 QWebHistoryPrivate* d = history.d; 495 496 int version = HistoryStreamVersion; 497 498 target << version; 499 target << history.count() << history.currentItemIndex(); 500 501 const WebCore::HistoryItemVector &items = d->lst->entries(); 502 for (unsigned i = 0; i < items.size(); i++) 503 items[i].get()->saveState(target, version); 504 505 return target; 506} 507 508/*! 509 \fn QDataStream& operator>>(QDataStream& stream, QWebHistory& history) 510 \relates QWebHistory 511 \since 4.6 512 513 \brief The operator>> function loads a history from a data stream. 514 515 Loads a QWebHistory from the specified \a stream into the given \a history. 516*/ 517 518QDataStream& operator>>(QDataStream& source, QWebHistory& history) 519{ 520 QWebHistoryPrivate* d = history.d; 521 // Clear first, to have the same behavior if our version doesn't match and if the HistoryItem's version doesn't. 522 history.clear(); 523 524 // This version covers every field we serialize in qwebhistory.cpp and HistoryItemQt.cpp (like the HistoryItem::userData()). 525 // HistoryItem has its own version in the stream covering the work done in encodeBackForwardTree. 526 // If any of those two stream version changes, the effect should be the same and the QWebHistory should fail to restore. 527 int version; 528 source >> version; 529 if (version != HistoryStreamVersion) { 530 // We do not try to decode previous history stream versions. 531 // Make sure that our history is cleared and mark the rest of the stream as invalid. 532 ASSERT(history.count() == 1); 533 source.setStatus(QDataStream::ReadCorruptData); 534 return source; 535 } 536 537 int count; 538 int currentIndex; 539 source >> count >> currentIndex; 540 541 // only if there are elements 542 if (count) { 543 // after clear() is new clear HistoryItem (at the end we had to remove it) 544 WebCore::HistoryItem* nullItem = d->lst->currentItem(); 545 for (int i = 0; i < count; i++) { 546 WTF::RefPtr<WebCore::HistoryItem> item = WebCore::HistoryItem::restoreState(source, version); 547 if (!item) { 548 // The HistoryItem internal version might have changed, do the same as when our own version change. 549 history.clear(); 550 source.setStatus(QDataStream::ReadCorruptData); 551 return source; 552 } 553 d->lst->addItem(item); 554 } 555 d->lst->removeItem(nullItem); 556 history.goToItem(history.itemAt(currentIndex)); 557 } 558 559 d->page()->updateNavigationActions(); 560 561 return source; 562} 563 564QWebPageAdapter* QWebHistoryPrivate::page() 565{ 566 return QWebPageAdapter::kit(static_cast<WebCore::BackForwardListImpl*>(lst)->page()); 567} 568 569WebCore::HistoryItem* QWebHistoryItemPrivate::core(const QWebHistoryItem* q) 570{ 571 return q->d->item; 572} 573