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