1/* 2 * Copyright (C) 2010 Stephan A��mus <superstippi@gmx.de> 3 * 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7#include "BrowsingHistory.h" 8 9#include <new> 10#include <stdio.h> 11 12#include <Autolock.h> 13#include <Entry.h> 14#include <File.h> 15#include <FindDirectory.h> 16#include <Message.h> 17#include <Path.h> 18 19#include "BrowserApp.h" 20 21 22BrowsingHistoryItem::BrowsingHistoryItem(const BString& url) 23 : 24 fURL(url), 25 fDateTime(BDateTime::CurrentDateTime(B_LOCAL_TIME)), 26 fInvokationCount(0) 27{ 28} 29 30 31BrowsingHistoryItem::BrowsingHistoryItem(const BrowsingHistoryItem& other) 32{ 33 *this = other; 34} 35 36 37BrowsingHistoryItem::BrowsingHistoryItem(const BMessage* archive) 38{ 39 if (!archive) 40 return; 41 BMessage dateTimeArchive; 42 if (archive->FindMessage("date time", &dateTimeArchive) == B_OK) 43 fDateTime = BDateTime(&dateTimeArchive); 44 archive->FindString("url", &fURL); 45 archive->FindUInt32("invokations", &fInvokationCount); 46} 47 48 49BrowsingHistoryItem::~BrowsingHistoryItem() 50{ 51} 52 53 54status_t 55BrowsingHistoryItem::Archive(BMessage* archive) const 56{ 57 if (!archive) 58 return B_BAD_VALUE; 59 BMessage dateTimeArchive; 60 status_t status = fDateTime.Archive(&dateTimeArchive); 61 if (status == B_OK) 62 status = archive->AddMessage("date time", &dateTimeArchive); 63 if (status == B_OK) 64 status = archive->AddString("url", fURL.String()); 65 if (status == B_OK) 66 status = archive->AddUInt32("invokations", fInvokationCount); 67 return status; 68} 69 70 71BrowsingHistoryItem& 72BrowsingHistoryItem::operator=(const BrowsingHistoryItem& other) 73{ 74 if (this == &other) 75 return *this; 76 77 fURL = other.fURL; 78 fDateTime = other.fDateTime; 79 fInvokationCount = other.fInvokationCount; 80 81 return *this; 82} 83 84 85bool 86BrowsingHistoryItem::operator==(const BrowsingHistoryItem& other) const 87{ 88 if (this == &other) 89 return true; 90 91 return fURL == other.fURL && fDateTime == other.fDateTime 92 && fInvokationCount == other.fInvokationCount; 93} 94 95 96bool 97BrowsingHistoryItem::operator!=(const BrowsingHistoryItem& other) const 98{ 99 return !(*this == other); 100} 101 102 103bool 104BrowsingHistoryItem::operator<(const BrowsingHistoryItem& other) const 105{ 106 if (this == &other) 107 return false; 108 109 return fDateTime < other.fDateTime || fURL < other.fURL; 110} 111 112 113bool 114BrowsingHistoryItem::operator<=(const BrowsingHistoryItem& other) const 115{ 116 return (*this == other) || (*this < other); 117} 118 119 120bool 121BrowsingHistoryItem::operator>(const BrowsingHistoryItem& other) const 122{ 123 if (this == &other) 124 return false; 125 126 return fDateTime > other.fDateTime || fURL > other.fURL; 127} 128 129 130bool 131BrowsingHistoryItem::operator>=(const BrowsingHistoryItem& other) const 132{ 133 return (*this == other) || (*this > other); 134} 135 136 137void 138BrowsingHistoryItem::Invoked() 139{ 140 // Eventually, we may overflow... 141 uint32 count = fInvokationCount + 1; 142 if (count > fInvokationCount) 143 fInvokationCount = count; 144 fDateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME); 145} 146 147 148// #pragma mark - BrowsingHistory 149 150 151BrowsingHistory 152BrowsingHistory::sDefaultInstance; 153 154 155BrowsingHistory::BrowsingHistory() 156 : 157 BLocker("browsing history"), 158 fHistoryItems(64), 159 fMaxHistoryItemAge(7), 160 fSettingsLoaded(false) 161{ 162} 163 164 165BrowsingHistory::~BrowsingHistory() 166{ 167 _SaveSettings(); 168 _Clear(); 169} 170 171 172/*static*/ BrowsingHistory* 173BrowsingHistory::DefaultInstance() 174{ 175 if (sDefaultInstance.Lock()) { 176 sDefaultInstance._LoadSettings(); 177 sDefaultInstance.Unlock(); 178 } 179 return &sDefaultInstance; 180} 181 182 183bool 184BrowsingHistory::AddItem(const BrowsingHistoryItem& item) 185{ 186 BAutolock _(this); 187 188 return _AddItem(item, false); 189} 190 191 192int32 193BrowsingHistory::BrowsingHistory::CountItems() const 194{ 195 BAutolock _(const_cast<BrowsingHistory*>(this)); 196 197 return fHistoryItems.CountItems(); 198} 199 200 201BrowsingHistoryItem 202BrowsingHistory::HistoryItemAt(int32 index) const 203{ 204 BAutolock _(const_cast<BrowsingHistory*>(this)); 205 206 BrowsingHistoryItem* existingItem = reinterpret_cast<BrowsingHistoryItem*>( 207 fHistoryItems.ItemAt(index)); 208 if (!existingItem) 209 return BrowsingHistoryItem(BString()); 210 211 return BrowsingHistoryItem(*existingItem); 212} 213 214 215void 216BrowsingHistory::Clear() 217{ 218 BAutolock _(this); 219 _Clear(); 220 _SaveSettings(); 221} 222 223 224void 225BrowsingHistory::SetMaxHistoryItemAge(int32 days) 226{ 227 BAutolock _(this); 228 if (fMaxHistoryItemAge != days) { 229 fMaxHistoryItemAge = days; 230 _SaveSettings(); 231 } 232} 233 234 235int32 236BrowsingHistory::MaxHistoryItemAge() const 237{ 238 return fMaxHistoryItemAge; 239} 240 241 242// #pragma mark - private 243 244 245void 246BrowsingHistory::_Clear() 247{ 248 int32 count = CountItems(); 249 for (int32 i = 0; i < count; i++) { 250 BrowsingHistoryItem* item = reinterpret_cast<BrowsingHistoryItem*>( 251 fHistoryItems.ItemAtFast(i)); 252 delete item; 253 } 254 fHistoryItems.MakeEmpty(); 255} 256 257 258bool 259BrowsingHistory::_AddItem(const BrowsingHistoryItem& item, bool internal) 260{ 261 int32 count = CountItems(); 262 int32 insertionIndex = count; 263 for (int32 i = 0; i < count; i++) { 264 BrowsingHistoryItem* existingItem 265 = reinterpret_cast<BrowsingHistoryItem*>( 266 fHistoryItems.ItemAtFast(i)); 267 if (item.URL() == existingItem->URL()) { 268 if (!internal) { 269 existingItem->Invoked(); 270 _SaveSettings(); 271 } 272 return true; 273 } 274 if (item < *existingItem) 275 insertionIndex = i; 276 } 277 BrowsingHistoryItem* newItem = new(std::nothrow) BrowsingHistoryItem(item); 278 if (!newItem || !fHistoryItems.AddItem(newItem, insertionIndex)) { 279 delete newItem; 280 return false; 281 } 282 283 if (!internal) { 284 newItem->Invoked(); 285 _SaveSettings(); 286 } 287 288 return true; 289} 290 291 292void 293BrowsingHistory::_LoadSettings() 294{ 295 if (fSettingsLoaded) 296 return; 297 298 fSettingsLoaded = true; 299 300 BFile settingsFile; 301 if (_OpenSettingsFile(settingsFile, B_READ_ONLY)) { 302 BMessage settingsArchive; 303 settingsArchive.Unflatten(&settingsFile); 304 if (settingsArchive.FindInt32("max history item age", 305 &fMaxHistoryItemAge) != B_OK) { 306 fMaxHistoryItemAge = 7; 307 } 308 BDateTime oldestAllowedDateTime 309 = BDateTime::CurrentDateTime(B_LOCAL_TIME); 310 oldestAllowedDateTime.Date().AddDays(-fMaxHistoryItemAge); 311 312 BMessage historyItemArchive; 313 for (int32 i = 0; settingsArchive.FindMessage("history item", i, 314 &historyItemArchive) == B_OK; i++) { 315 BrowsingHistoryItem item(&historyItemArchive); 316 if (oldestAllowedDateTime < item.DateTime()) 317 _AddItem(item, true); 318 historyItemArchive.MakeEmpty(); 319 } 320 } 321} 322 323 324void 325BrowsingHistory::_SaveSettings() 326{ 327 BFile settingsFile; 328 if (_OpenSettingsFile(settingsFile, 329 B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY)) { 330 BMessage settingsArchive; 331 settingsArchive.AddInt32("max history item age", fMaxHistoryItemAge); 332 BMessage historyItemArchive; 333 int32 count = CountItems(); 334 for (int32 i = 0; i < count; i++) { 335 BrowsingHistoryItem item = HistoryItemAt(i); 336 if (item.Archive(&historyItemArchive) != B_OK) 337 break; 338 if (settingsArchive.AddMessage("history item", 339 &historyItemArchive) != B_OK) { 340 break; 341 } 342 historyItemArchive.MakeEmpty(); 343 } 344 settingsArchive.Flatten(&settingsFile); 345 } 346} 347 348 349bool 350BrowsingHistory::_OpenSettingsFile(BFile& file, uint32 mode) 351{ 352 BPath path; 353 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK 354 || path.Append(kApplicationName) != B_OK 355 || path.Append("BrowsingHistory") != B_OK) { 356 return false; 357 } 358 return file.SetTo(path.Path(), mode) == B_OK; 359} 360 361