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