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 22 BrowsingHistoryItem::BrowsingHistoryItem(const BString& url) 23 : 24 fURL(url), 25 fDateTime(BDateTime::CurrentDateTime(B_LOCAL_TIME)), 26 fInvokationCount(0) 27 { 28 } 29 30 31 BrowsingHistoryItem::BrowsingHistoryItem(const BrowsingHistoryItem& other) 32 { 33 *this = other; 34 } 35 36 37 BrowsingHistoryItem::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 49 BrowsingHistoryItem::~BrowsingHistoryItem() 50 { 51 } 52 53 54 status_t 55 BrowsingHistoryItem::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 71 BrowsingHistoryItem& 72 BrowsingHistoryItem::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 85 bool 86 BrowsingHistoryItem::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 96 bool 97 BrowsingHistoryItem::operator!=(const BrowsingHistoryItem& other) const 98 { 99 return !(*this == other); 100 } 101 102 103 bool 104 BrowsingHistoryItem::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 113 bool 114 BrowsingHistoryItem::operator<=(const BrowsingHistoryItem& other) const 115 { 116 return (*this == other) || (*this < other); 117 } 118 119 120 bool 121 BrowsingHistoryItem::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 130 bool 131 BrowsingHistoryItem::operator>=(const BrowsingHistoryItem& other) const 132 { 133 return (*this == other) || (*this > other); 134 } 135 136 137 void 138 BrowsingHistoryItem::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 151 BrowsingHistory 152 BrowsingHistory::sDefaultInstance; 153 154 155 BrowsingHistory::BrowsingHistory() 156 : 157 BLocker("browsing history"), 158 fHistoryItems(64), 159 fMaxHistoryItemAge(7), 160 fSettingsLoaded(false) 161 { 162 } 163 164 165 BrowsingHistory::~BrowsingHistory() 166 { 167 _SaveSettings(); 168 _Clear(); 169 } 170 171 172 /*static*/ BrowsingHistory* 173 BrowsingHistory::DefaultInstance() 174 { 175 if (sDefaultInstance.Lock()) { 176 sDefaultInstance._LoadSettings(); 177 sDefaultInstance.Unlock(); 178 } 179 return &sDefaultInstance; 180 } 181 182 183 bool 184 BrowsingHistory::AddItem(const BrowsingHistoryItem& item) 185 { 186 BAutolock _(this); 187 188 return _AddItem(item, false); 189 } 190 191 192 int32 193 BrowsingHistory::BrowsingHistory::CountItems() const 194 { 195 BAutolock _(const_cast<BrowsingHistory*>(this)); 196 197 return fHistoryItems.CountItems(); 198 } 199 200 201 BrowsingHistoryItem 202 BrowsingHistory::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 215 void 216 BrowsingHistory::Clear() 217 { 218 BAutolock _(this); 219 _Clear(); 220 _SaveSettings(); 221 } 222 223 224 void 225 BrowsingHistory::SetMaxHistoryItemAge(int32 days) 226 { 227 BAutolock _(this); 228 if (fMaxHistoryItemAge != days) { 229 fMaxHistoryItemAge = days; 230 _SaveSettings(); 231 } 232 } 233 234 235 int32 236 BrowsingHistory::MaxHistoryItemAge() const 237 { 238 return fMaxHistoryItemAge; 239 } 240 241 242 // #pragma mark - private 243 244 245 void 246 BrowsingHistory::_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 258 bool 259 BrowsingHistory::_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 292 void 293 BrowsingHistory::_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 324 void 325 BrowsingHistory::_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 349 bool 350 BrowsingHistory::_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