/* * Copyright (C) 2010 Stephan Aßmus * * All rights reserved. Distributed under the terms of the MIT License. */ #include "BrowsingHistory.h" #include #include #include #include #include #include #include #include #include "BrowserApp.h" BrowsingHistoryItem::BrowsingHistoryItem(const BString& url) : fURL(url), fDateTime(BDateTime::CurrentDateTime(B_LOCAL_TIME)), fInvokationCount(0) { } BrowsingHistoryItem::BrowsingHistoryItem(const BrowsingHistoryItem& other) { *this = other; } BrowsingHistoryItem::BrowsingHistoryItem(const BMessage* archive) { if (!archive) return; BMessage dateTimeArchive; if (archive->FindMessage("date time", &dateTimeArchive) == B_OK) fDateTime = BDateTime(&dateTimeArchive); archive->FindString("url", &fURL); archive->FindUInt32("invokations", &fInvokationCount); } BrowsingHistoryItem::~BrowsingHistoryItem() { } status_t BrowsingHistoryItem::Archive(BMessage* archive) const { if (!archive) return B_BAD_VALUE; BMessage dateTimeArchive; status_t status = fDateTime.Archive(&dateTimeArchive); if (status == B_OK) status = archive->AddMessage("date time", &dateTimeArchive); if (status == B_OK) status = archive->AddString("url", fURL.String()); if (status == B_OK) status = archive->AddUInt32("invokations", fInvokationCount); return status; } BrowsingHistoryItem& BrowsingHistoryItem::operator=(const BrowsingHistoryItem& other) { if (this == &other) return *this; fURL = other.fURL; fDateTime = other.fDateTime; fInvokationCount = other.fInvokationCount; return *this; } bool BrowsingHistoryItem::operator==(const BrowsingHistoryItem& other) const { if (this == &other) return true; return fURL == other.fURL && fDateTime == other.fDateTime && fInvokationCount == other.fInvokationCount; } bool BrowsingHistoryItem::operator!=(const BrowsingHistoryItem& other) const { return !(*this == other); } bool BrowsingHistoryItem::operator<(const BrowsingHistoryItem& other) const { if (this == &other) return false; return fDateTime < other.fDateTime || fURL < other.fURL; } bool BrowsingHistoryItem::operator<=(const BrowsingHistoryItem& other) const { return (*this == other) || (*this < other); } bool BrowsingHistoryItem::operator>(const BrowsingHistoryItem& other) const { if (this == &other) return false; return fDateTime > other.fDateTime || fURL > other.fURL; } bool BrowsingHistoryItem::operator>=(const BrowsingHistoryItem& other) const { return (*this == other) || (*this > other); } void BrowsingHistoryItem::Invoked() { // Eventually, we may overflow... uint32 count = fInvokationCount + 1; if (count > fInvokationCount) fInvokationCount = count; fDateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME); } // #pragma mark - BrowsingHistory BrowsingHistory BrowsingHistory::sDefaultInstance; BrowsingHistory::BrowsingHistory() : BLocker("browsing history"), fHistoryItems(64), fMaxHistoryItemAge(7), fSettingsLoaded(false) { } BrowsingHistory::~BrowsingHistory() { _SaveSettings(); _Clear(); } /*static*/ BrowsingHistory* BrowsingHistory::DefaultInstance() { if (sDefaultInstance.Lock()) { sDefaultInstance._LoadSettings(); sDefaultInstance.Unlock(); } return &sDefaultInstance; } bool BrowsingHistory::AddItem(const BrowsingHistoryItem& item) { BAutolock _(this); return _AddItem(item, false); } int32 BrowsingHistory::BrowsingHistory::CountItems() const { BAutolock _(const_cast(this)); return fHistoryItems.CountItems(); } BrowsingHistoryItem BrowsingHistory::HistoryItemAt(int32 index) const { BAutolock _(const_cast(this)); BrowsingHistoryItem* existingItem = reinterpret_cast( fHistoryItems.ItemAt(index)); if (!existingItem) return BrowsingHistoryItem(BString()); return BrowsingHistoryItem(*existingItem); } void BrowsingHistory::Clear() { BAutolock _(this); _Clear(); _SaveSettings(); } void BrowsingHistory::SetMaxHistoryItemAge(int32 days) { BAutolock _(this); if (fMaxHistoryItemAge != days) { fMaxHistoryItemAge = days; _SaveSettings(); } } int32 BrowsingHistory::MaxHistoryItemAge() const { return fMaxHistoryItemAge; } // #pragma mark - private void BrowsingHistory::_Clear() { int32 count = CountItems(); for (int32 i = 0; i < count; i++) { BrowsingHistoryItem* item = reinterpret_cast( fHistoryItems.ItemAtFast(i)); delete item; } fHistoryItems.MakeEmpty(); } bool BrowsingHistory::_AddItem(const BrowsingHistoryItem& item, bool internal) { int32 count = CountItems(); int32 insertionIndex = count; for (int32 i = 0; i < count; i++) { BrowsingHistoryItem* existingItem = reinterpret_cast( fHistoryItems.ItemAtFast(i)); if (item.URL() == existingItem->URL()) { if (!internal) { existingItem->Invoked(); _SaveSettings(); } return true; } if (item < *existingItem) insertionIndex = i; } BrowsingHistoryItem* newItem = new(std::nothrow) BrowsingHistoryItem(item); if (!newItem || !fHistoryItems.AddItem(newItem, insertionIndex)) { delete newItem; return false; } if (!internal) { newItem->Invoked(); _SaveSettings(); } return true; } void BrowsingHistory::_LoadSettings() { if (fSettingsLoaded) return; fSettingsLoaded = true; BFile settingsFile; if (_OpenSettingsFile(settingsFile, B_READ_ONLY)) { BMessage settingsArchive; settingsArchive.Unflatten(&settingsFile); if (settingsArchive.FindInt32("max history item age", &fMaxHistoryItemAge) != B_OK) { fMaxHistoryItemAge = 7; } BDateTime oldestAllowedDateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME); oldestAllowedDateTime.Date().AddDays(-fMaxHistoryItemAge); BMessage historyItemArchive; for (int32 i = 0; settingsArchive.FindMessage("history item", i, &historyItemArchive) == B_OK; i++) { BrowsingHistoryItem item(&historyItemArchive); if (oldestAllowedDateTime < item.DateTime()) _AddItem(item, true); historyItemArchive.MakeEmpty(); } } } void BrowsingHistory::_SaveSettings() { BFile settingsFile; if (_OpenSettingsFile(settingsFile, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY)) { BMessage settingsArchive; settingsArchive.AddInt32("max history item age", fMaxHistoryItemAge); BMessage historyItemArchive; int32 count = CountItems(); for (int32 i = 0; i < count; i++) { BrowsingHistoryItem item = HistoryItemAt(i); if (item.Archive(&historyItemArchive) != B_OK) break; if (settingsArchive.AddMessage("history item", &historyItemArchive) != B_OK) { break; } historyItemArchive.MakeEmpty(); } settingsArchive.Flatten(&settingsFile); } } bool BrowsingHistory::_OpenSettingsFile(BFile& file, uint32 mode) { BPath path; if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK || path.Append(kApplicationName) != B_OK || path.Append("BrowsingHistory") != B_OK) { return false; } return file.SetTo(path.Path(), mode) == B_OK; }