xref: /haiku/src/apps/webpositive/BrowsingHistory.cpp (revision c14bca2958fb7b0c34d5464ccfdd87038f909a0c)
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 
BrowsingHistoryItem(const BString & url)22 BrowsingHistoryItem::BrowsingHistoryItem(const BString& url)
23 	:
24 	fURL(url),
25 	fDateTime(BDateTime::CurrentDateTime(B_LOCAL_TIME)),
26 	fInvokationCount(0)
27 {
28 }
29 
30 
BrowsingHistoryItem(const BrowsingHistoryItem & other)31 BrowsingHistoryItem::BrowsingHistoryItem(const BrowsingHistoryItem& other)
32 {
33 	*this = other;
34 }
35 
36 
BrowsingHistoryItem(const BMessage * archive)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 
~BrowsingHistoryItem()49 BrowsingHistoryItem::~BrowsingHistoryItem()
50 {
51 }
52 
53 
54 status_t
Archive(BMessage * archive) const55 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&
operator =(const BrowsingHistoryItem & other)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
operator ==(const BrowsingHistoryItem & other) const86 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
operator !=(const BrowsingHistoryItem & other) const97 BrowsingHistoryItem::operator!=(const BrowsingHistoryItem& other) const
98 {
99 	return !(*this == other);
100 }
101 
102 
103 bool
operator <(const BrowsingHistoryItem & other) const104 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
operator <=(const BrowsingHistoryItem & other) const114 BrowsingHistoryItem::operator<=(const BrowsingHistoryItem& other) const
115 {
116 	return (*this == other) || (*this < other);
117 }
118 
119 
120 bool
operator >(const BrowsingHistoryItem & other) const121 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
operator >=(const BrowsingHistoryItem & other) const131 BrowsingHistoryItem::operator>=(const BrowsingHistoryItem& other) const
132 {
133 	return (*this == other) || (*this > other);
134 }
135 
136 
137 void
Invoked()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 
BrowsingHistory()155 BrowsingHistory::BrowsingHistory()
156 	:
157 	BLocker("browsing history"),
158 	fHistoryItems(64),
159 	fMaxHistoryItemAge(7),
160 	fSettingsLoaded(false)
161 {
162 }
163 
164 
~BrowsingHistory()165 BrowsingHistory::~BrowsingHistory()
166 {
167 	_SaveSettings();
168 	_Clear();
169 }
170 
171 
172 /*static*/ BrowsingHistory*
DefaultInstance()173 BrowsingHistory::DefaultInstance()
174 {
175 	if (sDefaultInstance.Lock()) {
176 		sDefaultInstance._LoadSettings();
177 		sDefaultInstance.Unlock();
178 	}
179 	return &sDefaultInstance;
180 }
181 
182 
183 bool
AddItem(const BrowsingHistoryItem & item)184 BrowsingHistory::AddItem(const BrowsingHistoryItem& item)
185 {
186 	BAutolock _(this);
187 
188 	return _AddItem(item, false);
189 }
190 
191 
192 int32
CountItems() const193 BrowsingHistory::BrowsingHistory::CountItems() const
194 {
195 	BAutolock _(const_cast<BrowsingHistory*>(this));
196 
197 	return fHistoryItems.CountItems();
198 }
199 
200 
201 BrowsingHistoryItem
HistoryItemAt(int32 index) const202 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
Clear()216 BrowsingHistory::Clear()
217 {
218 	BAutolock _(this);
219 	_Clear();
220 	_SaveSettings();
221 }
222 
223 
224 void
SetMaxHistoryItemAge(int32 days)225 BrowsingHistory::SetMaxHistoryItemAge(int32 days)
226 {
227 	BAutolock _(this);
228 	if (fMaxHistoryItemAge != days) {
229 		fMaxHistoryItemAge = days;
230 		_SaveSettings();
231 	}
232 }
233 
234 
235 int32
MaxHistoryItemAge() const236 BrowsingHistory::MaxHistoryItemAge() const
237 {
238 	return fMaxHistoryItemAge;
239 }
240 
241 
242 // #pragma mark - private
243 
244 
245 void
_Clear()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
_AddItem(const BrowsingHistoryItem & item,bool internal)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
_LoadSettings()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
_SaveSettings()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
_OpenSettingsFile(BFile & file,uint32 mode)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