src/eric7/WebBrowser/History/HistoryManager.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 import os 10 import os
11 import pathlib 11 import pathlib
12 12
13 from PyQt6.QtCore import ( 13 from PyQt6.QtCore import (
14 pyqtSignal, pyqtSlot, QDateTime, QDate, QTime, QUrl, QTimer, QFile, 14 pyqtSignal,
15 QIODevice, QByteArray, QDataStream, QTemporaryFile, QObject 15 pyqtSlot,
16 QDateTime,
17 QDate,
18 QTime,
19 QUrl,
20 QTimer,
21 QFile,
22 QIODevice,
23 QByteArray,
24 QDataStream,
25 QTemporaryFile,
26 QObject,
16 ) 27 )
17 28
18 from EricWidgets import EricMessageBox 29 from EricWidgets import EricMessageBox
19 30
20 from Utilities.AutoSaver import AutoSaver 31 from Utilities.AutoSaver import AutoSaver
28 39
29 class HistoryEntry: 40 class HistoryEntry:
30 """ 41 """
31 Class implementing a history entry. 42 Class implementing a history entry.
32 """ 43 """
44
33 def __init__(self, url=None, dateTime=None, title=None, visitCount=None): 45 def __init__(self, url=None, dateTime=None, title=None, visitCount=None):
34 """ 46 """
35 Constructor 47 Constructor
36 48
37 @param url URL of the history entry (string) 49 @param url URL of the history entry (string)
38 @param dateTime date and time this entry was created (QDateTime) 50 @param dateTime date and time this entry was created (QDateTime)
39 @param title title string for the history entry (string) 51 @param title title string for the history entry (string)
40 @param visitCount number of visits of this URL (int) 52 @param visitCount number of visits of this URL (int)
41 """ 53 """
42 self.url = url and url or "" 54 self.url = url and url or ""
43 self.dateTime = dateTime and dateTime or QDateTime() 55 self.dateTime = dateTime and dateTime or QDateTime()
44 self.title = title and title or "" 56 self.title = title and title or ""
45 self.visitCount = visitCount and visitCount or 0 57 self.visitCount = visitCount and visitCount or 0
46 58
47 def __eq__(self, other): 59 def __eq__(self, other):
48 """ 60 """
49 Special method determining equality. 61 Special method determining equality.
50 62
51 @param other reference to the history entry to compare against 63 @param other reference to the history entry to compare against
52 (HistoryEntry) 64 (HistoryEntry)
53 @return flag indicating equality (boolean) 65 @return flag indicating equality (boolean)
54 """ 66 """
55 return ( 67 return (
56 other.title == self.title and 68 other.title == self.title
57 other.url == self.url and 69 and other.url == self.url
58 other.dateTime == self.dateTime 70 and other.dateTime == self.dateTime
59 ) 71 )
60 72
61 def __lt__(self, other): 73 def __lt__(self, other):
62 """ 74 """
63 Special method determining less relation. 75 Special method determining less relation.
64 76
65 Note: History is sorted in reverse order by date and time 77 Note: History is sorted in reverse order by date and time
66 78
67 @param other reference to the history entry to compare against 79 @param other reference to the history entry to compare against
68 (HistoryEntry) 80 (HistoryEntry)
69 @return flag indicating less (boolean) 81 @return flag indicating less (boolean)
70 """ 82 """
71 return self.dateTime > other.dateTime 83 return self.dateTime > other.dateTime
72 84
73 def userTitle(self): 85 def userTitle(self):
74 """ 86 """
75 Public method to get the title of the history entry. 87 Public method to get the title of the history entry.
76 88
77 @return title of the entry (string) 89 @return title of the entry (string)
78 """ 90 """
79 if not self.title: 91 if not self.title:
80 page = pathlib.Path(QUrl(self.url).path()).name 92 page = pathlib.Path(QUrl(self.url).path()).name
81 if page: 93 if page:
82 return page 94 return page
83 return self.url 95 return self.url
84 return self.title 96 return self.title
85 97
86 def isValid(self): 98 def isValid(self):
87 """ 99 """
88 Public method to determine validity. 100 Public method to determine validity.
89 101
90 @return flag indicating validity 102 @return flag indicating validity
91 @rtype bool 103 @rtype bool
92 """ 104 """
93 return bool(self.url) and self.dateTime.isValid() 105 return bool(self.url) and self.dateTime.isValid()
94 106
95 107
96 class HistoryManager(QObject): 108 class HistoryManager(QObject):
97 """ 109 """
98 Class implementing the history manager. 110 Class implementing the history manager.
99 111
100 @signal historyCleared() emitted after the history has been cleared 112 @signal historyCleared() emitted after the history has been cleared
101 @signal historyReset() emitted after the history has been reset 113 @signal historyReset() emitted after the history has been reset
102 @signal entryAdded(HistoryEntry) emitted after a history entry has been 114 @signal entryAdded(HistoryEntry) emitted after a history entry has been
103 added 115 added
104 @signal entryRemoved(HistoryEntry) emitted after a history entry has been 116 @signal entryRemoved(HistoryEntry) emitted after a history entry has been
105 removed 117 removed
106 @signal entryUpdated(int) emitted after a history entry has been updated 118 @signal entryUpdated(int) emitted after a history entry has been updated
107 @signal historySaved() emitted after the history was saved 119 @signal historySaved() emitted after the history was saved
108 """ 120 """
121
109 historyCleared = pyqtSignal() 122 historyCleared = pyqtSignal()
110 historyReset = pyqtSignal() 123 historyReset = pyqtSignal()
111 entryAdded = pyqtSignal(HistoryEntry) 124 entryAdded = pyqtSignal(HistoryEntry)
112 entryRemoved = pyqtSignal(HistoryEntry) 125 entryRemoved = pyqtSignal(HistoryEntry)
113 entryUpdated = pyqtSignal(int) 126 entryUpdated = pyqtSignal(int)
114 historySaved = pyqtSignal() 127 historySaved = pyqtSignal()
115 128
116 def __init__(self, parent=None): 129 def __init__(self, parent=None):
117 """ 130 """
118 Constructor 131 Constructor
119 132
120 @param parent reference to the parent object (QObject) 133 @param parent reference to the parent object (QObject)
121 """ 134 """
122 super().__init__(parent) 135 super().__init__(parent)
123 136
124 self.__saveTimer = AutoSaver(self, self.save) 137 self.__saveTimer = AutoSaver(self, self.save)
125 self.__daysToExpire = Preferences.getWebBrowser("HistoryLimit") 138 self.__daysToExpire = Preferences.getWebBrowser("HistoryLimit")
126 self.__history = [] 139 self.__history = []
127 self.__lastSavedUrl = "" 140 self.__lastSavedUrl = ""
128 141
129 self.__expiredTimer = QTimer(self) 142 self.__expiredTimer = QTimer(self)
130 self.__expiredTimer.setSingleShot(True) 143 self.__expiredTimer.setSingleShot(True)
131 self.__expiredTimer.timeout.connect(self.__checkForExpired) 144 self.__expiredTimer.timeout.connect(self.__checkForExpired)
132 145
133 self.__frequencyTimer = QTimer(self) 146 self.__frequencyTimer = QTimer(self)
134 self.__frequencyTimer.setSingleShot(True) 147 self.__frequencyTimer.setSingleShot(True)
135 self.__frequencyTimer.timeout.connect(self.__refreshFrequencies) 148 self.__frequencyTimer.timeout.connect(self.__refreshFrequencies)
136 149
137 self.entryAdded.connect(self.__saveTimer.changeOccurred) 150 self.entryAdded.connect(self.__saveTimer.changeOccurred)
138 self.entryRemoved.connect(self.__saveTimer.changeOccurred) 151 self.entryRemoved.connect(self.__saveTimer.changeOccurred)
139 152
140 self.__load() 153 self.__load()
141 154
142 from .HistoryModel import HistoryModel 155 from .HistoryModel import HistoryModel
143 from .HistoryFilterModel import HistoryFilterModel 156 from .HistoryFilterModel import HistoryFilterModel
144 from .HistoryTreeModel import HistoryTreeModel 157 from .HistoryTreeModel import HistoryTreeModel
145 158
146 self.__historyModel = HistoryModel(self, self) 159 self.__historyModel = HistoryModel(self, self)
147 self.__historyFilterModel = HistoryFilterModel( 160 self.__historyFilterModel = HistoryFilterModel(self.__historyModel, self)
148 self.__historyModel, self) 161 self.__historyTreeModel = HistoryTreeModel(self.__historyFilterModel, self)
149 self.__historyTreeModel = HistoryTreeModel( 162
150 self.__historyFilterModel, self)
151
152 self.__startFrequencyTimer() 163 self.__startFrequencyTimer()
153 164
154 def close(self): 165 def close(self):
155 """ 166 """
156 Public method to close the history manager. 167 Public method to close the history manager.
157 """ 168 """
158 # remove history items on application exit 169 # remove history items on application exit
159 if self.__daysToExpire == -2: 170 if self.__daysToExpire == -2:
160 self.clear() 171 self.clear()
161 self.__saveTimer.saveIfNeccessary() 172 self.__saveTimer.saveIfNeccessary()
162 173
163 def history(self): 174 def history(self):
164 """ 175 """
165 Public method to return the history. 176 Public method to return the history.
166 177
167 @return reference to the list of history entries (list of HistoryEntry) 178 @return reference to the list of history entries (list of HistoryEntry)
168 """ 179 """
169 return self.__history[:] 180 return self.__history[:]
170 181
171 def setHistory(self, history, loadedAndSorted=False): 182 def setHistory(self, history, loadedAndSorted=False):
172 """ 183 """
173 Public method to set a new history. 184 Public method to set a new history.
174 185
175 @param history reference to the list of history entries to be set 186 @param history reference to the list of history entries to be set
176 (list of HistoryEntry) 187 (list of HistoryEntry)
177 @param loadedAndSorted flag indicating that the list is sorted 188 @param loadedAndSorted flag indicating that the list is sorted
178 (boolean) 189 (boolean)
179 """ 190 """
180 self.__history = history[:] 191 self.__history = history[:]
181 if not loadedAndSorted: 192 if not loadedAndSorted:
182 self.__history.sort() 193 self.__history.sort()
183 194
184 self.__checkForExpired() 195 self.__checkForExpired()
185 196
186 if loadedAndSorted: 197 if loadedAndSorted:
187 try: 198 try:
188 self.__lastSavedUrl = self.__history[0].url 199 self.__lastSavedUrl = self.__history[0].url
189 except IndexError: 200 except IndexError:
190 self.__lastSavedUrl = "" 201 self.__lastSavedUrl = ""
191 else: 202 else:
192 self.__lastSavedUrl = "" 203 self.__lastSavedUrl = ""
193 self.__saveTimer.changeOccurred() 204 self.__saveTimer.changeOccurred()
194 self.historyReset.emit() 205 self.historyReset.emit()
195 206
196 def __findFirstHistoryEntry(self, url): 207 def __findFirstHistoryEntry(self, url):
197 """ 208 """
198 Private method to find the first entry for the given URL. 209 Private method to find the first entry for the given URL.
199 210
200 @param url URL to search for 211 @param url URL to search for
201 @type str 212 @type str
202 @return first entry for the given URL 213 @return first entry for the given URL
203 @rtype HistoryEntry 214 @rtype HistoryEntry
204 """ 215 """
205 for index in range(len(self.__history)): 216 for index in range(len(self.__history)):
206 if url == self.__history[index].url: 217 if url == self.__history[index].url:
207 return self.__history[index] 218 return self.__history[index]
208 219
209 # not found, return an empty entry 220 # not found, return an empty entry
210 return HistoryEntry() 221 return HistoryEntry()
211 222
212 def __updateVisitCount(self, url, count): 223 def __updateVisitCount(self, url, count):
213 """ 224 """
214 Private method to update the visit count for all entries of the 225 Private method to update the visit count for all entries of the
215 given URL. 226 given URL.
216 227
217 @param url URL to be updated 228 @param url URL to be updated
218 @type str 229 @type str
219 @param count new visit count 230 @param count new visit count
220 @type int 231 @type int
221 """ 232 """
222 for index in range(len(self.__history)): 233 for index in range(len(self.__history)):
223 if url == self.__history[index].url: 234 if url == self.__history[index].url:
224 self.__history[index].visitCount = count 235 self.__history[index].visitCount = count
225 236
226 def addHistoryEntry(self, view): 237 def addHistoryEntry(self, view):
227 """ 238 """
228 Public method to add a history entry. 239 Public method to add a history entry.
229 240
230 @param view reference to the view to add an entry for 241 @param view reference to the view to add an entry for
231 @type WebBrowserView 242 @type WebBrowserView
232 """ 243 """
233 import WebBrowser.WebBrowserWindow 244 import WebBrowser.WebBrowserWindow
245
234 if WebBrowser.WebBrowserWindow.WebBrowserWindow.isPrivate(): 246 if WebBrowser.WebBrowserWindow.WebBrowserWindow.isPrivate():
235 return 247 return
236 248
237 url = view.url() 249 url = view.url()
238 title = view.title() 250 title = view.title()
239 251
240 if url.scheme() not in ["eric", "about", "data", "chrome"]: 252 if url.scheme() not in ["eric", "about", "data", "chrome"]:
241 cleanUrlStr = self.__cleanUrlStr(url) 253 cleanUrlStr = self.__cleanUrlStr(url)
242 firstEntry = self.__findFirstHistoryEntry(cleanUrlStr) 254 firstEntry = self.__findFirstHistoryEntry(cleanUrlStr)
243 if firstEntry.isValid(): 255 if firstEntry.isValid():
244 visitCount = firstEntry.visitCount + 1 256 visitCount = firstEntry.visitCount + 1
245 self.__updateVisitCount(cleanUrlStr, visitCount) 257 self.__updateVisitCount(cleanUrlStr, visitCount)
246 else: 258 else:
247 visitCount = 1 259 visitCount = 1
248 itm = HistoryEntry(cleanUrlStr, 260 itm = HistoryEntry(
249 QDateTime.currentDateTime(), 261 cleanUrlStr, QDateTime.currentDateTime(), title, visitCount
250 title, 262 )
251 visitCount)
252 self.__history.insert(0, itm) 263 self.__history.insert(0, itm)
253 self.entryAdded.emit(itm) 264 self.entryAdded.emit(itm)
254 if len(self.__history) == 1: 265 if len(self.__history) == 1:
255 self.__checkForExpired() 266 self.__checkForExpired()
256 267
257 def updateHistoryEntry(self, url, title): 268 def updateHistoryEntry(self, url, title):
258 """ 269 """
259 Public method to update a history entry. 270 Public method to update a history entry.
260 271
261 @param url URL of the entry to update (string) 272 @param url URL of the entry to update (string)
262 @param title title of the entry to update (string) 273 @param title title of the entry to update (string)
263 """ 274 """
264 if QUrl(url).scheme() not in ["eric", "about", "data", "chrome"]: 275 if QUrl(url).scheme() not in ["eric", "about", "data", "chrome"]:
265 cleanUrlStr = self.__cleanUrlStr(QUrl(url)) 276 cleanUrlStr = self.__cleanUrlStr(QUrl(url))
269 self.__saveTimer.changeOccurred() 280 self.__saveTimer.changeOccurred()
270 if not self.__lastSavedUrl: 281 if not self.__lastSavedUrl:
271 self.__lastSavedUrl = self.__history[index].url 282 self.__lastSavedUrl = self.__history[index].url
272 self.entryUpdated.emit(index) 283 self.entryUpdated.emit(index)
273 break 284 break
274 285
275 def removeHistoryEntry(self, url, title=""): 286 def removeHistoryEntry(self, url, title=""):
276 """ 287 """
277 Public method to remove a history entry. 288 Public method to remove a history entry.
278 289
279 @param url URL of the entry to remove (QUrl) 290 @param url URL of the entry to remove (QUrl)
280 @param title title of the entry to remove (string) 291 @param title title of the entry to remove (string)
281 """ 292 """
282 if url.scheme() not in ["eric", "about", "data", "chrome"]: 293 if url.scheme() not in ["eric", "about", "data", "chrome"]:
283 cleanUrlStr = self.__cleanUrlStr(url) 294 cleanUrlStr = self.__cleanUrlStr(url)
284 for index in range(len(self.__history)): 295 for index in range(len(self.__history)):
285 if ( 296 if cleanUrlStr == self.__history[index].url and (
286 cleanUrlStr == self.__history[index].url and 297 not title or title == self.__history[index].title
287 (not title or title == self.__history[index].title)
288 ): 298 ):
289 itm = self.__history[index] 299 itm = self.__history[index]
290 self.__lastSavedUrl = "" 300 self.__lastSavedUrl = ""
291 self.__history.remove(itm) 301 self.__history.remove(itm)
292 self.entryRemoved.emit(itm) 302 self.entryRemoved.emit(itm)
293 break 303 break
294 304
295 def __cleanUrl(self, url): 305 def __cleanUrl(self, url):
296 """ 306 """
297 Private method to generate a clean URL usable for the history entry. 307 Private method to generate a clean URL usable for the history entry.
298 308
299 @param url original URL 309 @param url original URL
300 @type QUrl 310 @type QUrl
301 @return cleaned URL 311 @return cleaned URL
302 @rtype QUrl 312 @rtype QUrl
303 """ 313 """
306 # don't save the password in the history 316 # don't save the password in the history
307 cleanurl.setPassword("") 317 cleanurl.setPassword("")
308 if cleanurl.host(): 318 if cleanurl.host():
309 # convert host to lower case 319 # convert host to lower case
310 cleanurl.setHost(url.host().lower()) 320 cleanurl.setHost(url.host().lower())
311 321
312 return cleanurl 322 return cleanurl
313 323
314 def __cleanUrlStr(self, url): 324 def __cleanUrlStr(self, url):
315 """ 325 """
316 Private method to generate a clean URL usable for the history entry. 326 Private method to generate a clean URL usable for the history entry.
317 327
318 @param url original URL 328 @param url original URL
319 @type QUrl 329 @type QUrl
320 @return cleaned URL 330 @return cleaned URL
321 @rtype str 331 @rtype str
322 """ 332 """
323 cleanurl = self.__cleanUrl(url) 333 cleanurl = self.__cleanUrl(url)
324 return cleanurl.toString() 334 return cleanurl.toString()
325 335
326 def historyModel(self): 336 def historyModel(self):
327 """ 337 """
328 Public method to get a reference to the history model. 338 Public method to get a reference to the history model.
329 339
330 @return reference to the history model (HistoryModel) 340 @return reference to the history model (HistoryModel)
331 """ 341 """
332 return self.__historyModel 342 return self.__historyModel
333 343
334 def historyFilterModel(self): 344 def historyFilterModel(self):
335 """ 345 """
336 Public method to get a reference to the history filter model. 346 Public method to get a reference to the history filter model.
337 347
338 @return reference to the history filter model (HistoryFilterModel) 348 @return reference to the history filter model (HistoryFilterModel)
339 """ 349 """
340 return self.__historyFilterModel 350 return self.__historyFilterModel
341 351
342 def historyTreeModel(self): 352 def historyTreeModel(self):
343 """ 353 """
344 Public method to get a reference to the history tree model. 354 Public method to get a reference to the history tree model.
345 355
346 @return reference to the history tree model (HistoryTreeModel) 356 @return reference to the history tree model (HistoryTreeModel)
347 """ 357 """
348 return self.__historyTreeModel 358 return self.__historyTreeModel
349 359
350 def __checkForExpired(self): 360 def __checkForExpired(self):
351 """ 361 """
352 Private slot to check entries for expiration. 362 Private slot to check entries for expiration.
353 """ 363 """
354 if self.__daysToExpire < 0 or len(self.__history) == 0: 364 if self.__daysToExpire < 0 or len(self.__history) == 0:
355 return 365 return
356 366
357 now = QDateTime.currentDateTime() 367 now = QDateTime.currentDateTime()
358 nextTimeout = 0 368 nextTimeout = 0
359 369
360 while self.__history: 370 while self.__history:
361 checkForExpired = QDateTime(self.__history[-1].dateTime) 371 checkForExpired = QDateTime(self.__history[-1].dateTime)
362 checkForExpired.setDate( 372 checkForExpired.setDate(checkForExpired.date().addDays(self.__daysToExpire))
363 checkForExpired.date().addDays(self.__daysToExpire))
364 nextTimeout = ( 373 nextTimeout = (
365 7 * 86400 374 7 * 86400
366 if now.daysTo(checkForExpired) > 7 else 375 if now.daysTo(checkForExpired) > 7
367 now.secsTo(checkForExpired) 376 else now.secsTo(checkForExpired)
368 ) 377 )
369 if nextTimeout > 0: 378 if nextTimeout > 0:
370 break 379 break
371 380
372 itm = self.__history.pop(-1) 381 itm = self.__history.pop(-1)
373 self.__lastSavedUrl = "" 382 self.__lastSavedUrl = ""
374 self.entryRemoved.emit(itm) 383 self.entryRemoved.emit(itm)
375 self.__saveTimer.saveIfNeccessary() 384 self.__saveTimer.saveIfNeccessary()
376 385
377 if nextTimeout > 0: 386 if nextTimeout > 0:
378 self.__expiredTimer.start(nextTimeout * 1000) 387 self.__expiredTimer.start(nextTimeout * 1000)
379 388
380 def daysToExpire(self): 389 def daysToExpire(self):
381 """ 390 """
382 Public method to get the days for entry expiration. 391 Public method to get the days for entry expiration.
383 392
384 @return days for entry expiration (integer) 393 @return days for entry expiration (integer)
385 """ 394 """
386 return self.__daysToExpire 395 return self.__daysToExpire
387 396
388 def setDaysToExpire(self, limit): 397 def setDaysToExpire(self, limit):
389 """ 398 """
390 Public method to set the days for entry expiration. 399 Public method to set the days for entry expiration.
391 400
392 @param limit days for entry expiration (integer) 401 @param limit days for entry expiration (integer)
393 """ 402 """
394 if self.__daysToExpire == limit: 403 if self.__daysToExpire == limit:
395 return 404 return
396 405
397 self.__daysToExpire = limit 406 self.__daysToExpire = limit
398 self.__checkForExpired() 407 self.__checkForExpired()
399 self.__saveTimer.changeOccurred() 408 self.__saveTimer.changeOccurred()
400 409
401 def preferencesChanged(self): 410 def preferencesChanged(self):
402 """ 411 """
403 Public method to indicate a change of preferences. 412 Public method to indicate a change of preferences.
404 """ 413 """
405 self.setDaysToExpire(Preferences.getWebBrowser("HistoryLimit")) 414 self.setDaysToExpire(Preferences.getWebBrowser("HistoryLimit"))
406 415
407 @pyqtSlot() 416 @pyqtSlot()
408 def clear(self, period=0): 417 def clear(self, period=0):
409 """ 418 """
410 Public slot to clear the complete history. 419 Public slot to clear the complete history.
411 420
412 @param period history period in milliseconds to be cleared (integer) 421 @param period history period in milliseconds to be cleared (integer)
413 """ 422 """
414 if period == 0: 423 if period == 0:
415 self.__history = [] 424 self.__history = []
416 self.historyReset.emit() 425 self.historyReset.emit()
417 else: 426 else:
418 breakMS = QDateTime.currentMSecsSinceEpoch() - period 427 breakMS = QDateTime.currentMSecsSinceEpoch() - period
419 while ( 428 while self.__history and (
420 self.__history and 429 QDateTime(self.__history[0].dateTime).toMSecsSinceEpoch() > breakMS
421 (QDateTime(self.__history[0].dateTime).toMSecsSinceEpoch() >
422 breakMS)
423 ): 430 ):
424 itm = self.__history.pop(0) 431 itm = self.__history.pop(0)
425 self.entryRemoved.emit(itm) 432 self.entryRemoved.emit(itm)
426 self.__lastSavedUrl = "" 433 self.__lastSavedUrl = ""
427 self.__saveTimer.changeOccurred() 434 self.__saveTimer.changeOccurred()
428 self.__saveTimer.saveIfNeccessary() 435 self.__saveTimer.saveIfNeccessary()
429 self.historyCleared.emit() 436 self.historyCleared.emit()
430 437
431 def getFileName(self): 438 def getFileName(self):
432 """ 439 """
433 Public method to get the file name of the history file. 440 Public method to get the file name of the history file.
434 441
435 @return name of the history file (string) 442 @return name of the history file (string)
436 """ 443 """
437 return os.path.join(Utilities.getConfigDir(), "web_browser", "history") 444 return os.path.join(Utilities.getConfigDir(), "web_browser", "history")
438 445
439 def reload(self): 446 def reload(self):
440 """ 447 """
441 Public method to reload the history. 448 Public method to reload the history.
442 """ 449 """
443 self.__load() 450 self.__load()
444 451
445 def __load(self): 452 def __load(self):
446 """ 453 """
447 Private method to load the saved history entries from disk. 454 Private method to load the saved history entries from disk.
448 """ 455 """
449 historyFile = QFile(self.getFileName()) 456 historyFile = QFile(self.getFileName())
453 EricMessageBox.warning( 460 EricMessageBox.warning(
454 None, 461 None,
455 self.tr("Loading History"), 462 self.tr("Loading History"),
456 self.tr( 463 self.tr(
457 """<p>Unable to open history file <b>{0}</b>.<br/>""" 464 """<p>Unable to open history file <b>{0}</b>.<br/>"""
458 """Reason: {1}</p>""") 465 """Reason: {1}</p>"""
459 .format(historyFile.fileName, historyFile.errorString())) 466 ).format(historyFile.fileName, historyFile.errorString()),
467 )
460 return 468 return
461 469
462 history = [] 470 history = []
463 471
464 # double check, that the history file is sorted as it is read 472 # double check, that the history file is sorted as it is read
465 needToSort = False 473 needToSort = False
466 lastInsertedItem = HistoryEntry() 474 lastInsertedItem = HistoryEntry()
467 data = QByteArray(historyFile.readAll()) 475 data = QByteArray(historyFile.readAll())
468 stream = QDataStream(data, QIODevice.OpenModeFlag.ReadOnly) 476 stream = QDataStream(data, QIODevice.OpenModeFlag.ReadOnly)
475 itm.url = Utilities.readStringFromStream(stream) 483 itm.url = Utilities.readStringFromStream(stream)
476 stream >> itm.dateTime 484 stream >> itm.dateTime
477 itm.title = Utilities.readStringFromStream(stream) 485 itm.title = Utilities.readStringFromStream(stream)
478 if ver == HISTORY_VERSION_60: 486 if ver == HISTORY_VERSION_60:
479 itm.visitCount = stream.readUInt32() 487 itm.visitCount = stream.readUInt32()
480 488
481 if not itm.dateTime.isValid(): 489 if not itm.dateTime.isValid():
482 continue 490 continue
483 491
484 if itm == lastInsertedItem: 492 if itm == lastInsertedItem:
485 if not lastInsertedItem.title and len(history) > 0: 493 if not lastInsertedItem.title and len(history) > 0:
486 history[0].title = itm.title 494 history[0].title = itm.title
487 continue 495 continue
488 496
489 if ver == HISTORY_VERSION_42: 497 if ver == HISTORY_VERSION_42:
490 firstEntry = self.__findFirstHistoryEntry(itm.url) 498 firstEntry = self.__findFirstHistoryEntry(itm.url)
491 if firstEntry.isValid(): 499 if firstEntry.isValid():
492 visitCount = firstEntry.visitCount + 1 500 visitCount = firstEntry.visitCount + 1
493 self.__updateVisitCount(itm.url, visitCount) 501 self.__updateVisitCount(itm.url, visitCount)
494 else: 502 else:
495 visitCount = 1 503 visitCount = 1
496 itm.visitCount = visitCount 504 itm.visitCount = visitCount
497 505
498 if not needToSort and history and lastInsertedItem < itm: 506 if not needToSort and history and lastInsertedItem < itm:
499 needToSort = True 507 needToSort = True
500 508
501 history.insert(0, itm) 509 history.insert(0, itm)
502 lastInsertedItem = itm 510 lastInsertedItem = itm
503 historyFile.close() 511 historyFile.close()
504 512
505 if needToSort: 513 if needToSort:
506 history.sort() 514 history.sort()
507 515
508 self.setHistory(history, True) 516 self.setHistory(history, True)
509 517
510 # if the history had to be sorted, rewrite the history sorted 518 # if the history had to be sorted, rewrite the history sorted
511 if needToSort: 519 if needToSort:
512 self.__lastSavedUrl = "" 520 self.__lastSavedUrl = ""
513 self.__saveTimer.changeOccurred() 521 self.__saveTimer.changeOccurred()
514 522
515 def save(self): 523 def save(self):
516 """ 524 """
517 Public slot to save the history entries to disk. 525 Public slot to save the history entries to disk.
518 """ 526 """
519 historyFile = QFile(self.getFileName()) 527 historyFile = QFile(self.getFileName())
520 if not historyFile.exists(): 528 if not historyFile.exists():
521 self.__lastSavedUrl = "" 529 self.__lastSavedUrl = ""
522 530
523 saveAll = self.__lastSavedUrl == "" 531 saveAll = self.__lastSavedUrl == ""
524 first = len(self.__history) - 1 532 first = len(self.__history) - 1
525 if not saveAll: 533 if not saveAll:
526 # find the first one to save 534 # find the first one to save
527 for index in range(len(self.__history)): 535 for index in range(len(self.__history)):
528 if self.__history[index].url == self.__lastSavedUrl: 536 if self.__history[index].url == self.__lastSavedUrl:
529 first = index - 1 537 first = index - 1
530 break 538 break
531 if first == len(self.__history) - 1: 539 if first == len(self.__history) - 1:
532 saveAll = True 540 saveAll = True
533 541
534 if saveAll: 542 if saveAll:
535 # use a temporary file when saving everything 543 # use a temporary file when saving everything
536 f = QTemporaryFile() 544 f = QTemporaryFile()
537 f.setAutoRemove(False) 545 f.setAutoRemove(False)
538 opened = f.open() 546 opened = f.open()
539 else: 547 else:
540 f = historyFile 548 f = historyFile
541 opened = f.open(QIODevice.OpenModeFlag.Append) 549 opened = f.open(QIODevice.OpenModeFlag.Append)
542 550
543 if not opened: 551 if not opened:
544 EricMessageBox.warning( 552 EricMessageBox.warning(
545 None, 553 None,
546 self.tr("Saving History"), 554 self.tr("Saving History"),
547 self.tr( 555 self.tr(
548 """<p>Unable to open history file <b>{0}</b>.<br/>""" 556 """<p>Unable to open history file <b>{0}</b>.<br/>"""
549 """Reason: {1}</p>""") 557 """Reason: {1}</p>"""
550 .format(f.fileName(), f.errorString())) 558 ).format(f.fileName(), f.errorString()),
559 )
551 return 560 return
552 561
553 for index in range(first, -1, -1): 562 for index in range(first, -1, -1):
554 data = QByteArray() 563 data = QByteArray()
555 stream = QDataStream(data, QIODevice.OpenModeFlag.WriteOnly) 564 stream = QDataStream(data, QIODevice.OpenModeFlag.WriteOnly)
556 stream.setVersion(QDataStream.Version.Qt_4_6) 565 stream.setVersion(QDataStream.Version.Qt_4_6)
557 itm = self.__history[index] 566 itm = self.__history[index]
558 stream.writeUInt32(HISTORY_VERSION_60) 567 stream.writeUInt32(HISTORY_VERSION_60)
559 stream.writeString(itm.url.encode("utf-8")) 568 stream.writeString(itm.url.encode("utf-8"))
560 stream << itm.dateTime 569 stream << itm.dateTime
561 stream.writeString(itm.title.encode('utf-8')) 570 stream.writeString(itm.title.encode("utf-8"))
562 stream.writeUInt32(itm.visitCount) 571 stream.writeUInt32(itm.visitCount)
563 f.write(data) 572 f.write(data)
564 573
565 f.close() 574 f.close()
566 if saveAll: 575 if saveAll:
567 if historyFile.exists() and not historyFile.remove(): 576 if historyFile.exists() and not historyFile.remove():
568 EricMessageBox.warning( 577 EricMessageBox.warning(
569 None, 578 None,
570 self.tr("Saving History"), 579 self.tr("Saving History"),
571 self.tr( 580 self.tr(
572 """<p>Error removing old history file <b>{0}</b>.""" 581 """<p>Error removing old history file <b>{0}</b>."""
573 """<br/>Reason: {1}</p>""") 582 """<br/>Reason: {1}</p>"""
574 .format(historyFile.fileName(), 583 ).format(historyFile.fileName(), historyFile.errorString()),
575 historyFile.errorString())) 584 )
576 if not f.copy(historyFile.fileName()): 585 if not f.copy(historyFile.fileName()):
577 EricMessageBox.warning( 586 EricMessageBox.warning(
578 None, 587 None,
579 self.tr("Saving History"), 588 self.tr("Saving History"),
580 self.tr( 589 self.tr(
581 """<p>Error moving new history file over old one """ 590 """<p>Error moving new history file over old one """
582 """(<b>{0}</b>).<br/>Reason: {1}</p>""") 591 """(<b>{0}</b>).<br/>Reason: {1}</p>"""
583 .format(historyFile.fileName(), f.errorString())) 592 ).format(historyFile.fileName(), f.errorString()),
593 )
584 f.remove() # get rid of the temporary file 594 f.remove() # get rid of the temporary file
585 self.historySaved.emit() 595 self.historySaved.emit()
586 try: 596 try:
587 self.__lastSavedUrl = self.__history[0].url 597 self.__lastSavedUrl = self.__history[0].url
588 except IndexError: 598 except IndexError:
589 self.__lastSavedUrl = "" 599 self.__lastSavedUrl = ""
590 600
591 def __refreshFrequencies(self): 601 def __refreshFrequencies(self):
592 """ 602 """
593 Private slot to recalculate the refresh frequencies. 603 Private slot to recalculate the refresh frequencies.
594 """ 604 """
595 self.__historyFilterModel.recalculateFrequencies() 605 self.__historyFilterModel.recalculateFrequencies()
596 self.__startFrequencyTimer() 606 self.__startFrequencyTimer()
597 607
598 def __startFrequencyTimer(self): 608 def __startFrequencyTimer(self):
599 """ 609 """
600 Private method to start the timer to recalculate the frequencies. 610 Private method to start the timer to recalculate the frequencies.
601 """ 611 """
602 tomorrow = QDateTime(QDate.currentDate().addDays(1), QTime(3, 0)) 612 tomorrow = QDateTime(QDate.currentDate().addDays(1), QTime(3, 0))
603 self.__frequencyTimer.start( 613 self.__frequencyTimer.start(QDateTime.currentDateTime().secsTo(tomorrow) * 1000)
604 QDateTime.currentDateTime().secsTo(tomorrow) * 1000) 614
605
606 def siteVisitsCount(self, scheme, host): 615 def siteVisitsCount(self, scheme, host):
607 """ 616 """
608 Public method to get the visit count for a web site using the given 617 Public method to get the visit count for a web site using the given
609 scheme. 618 scheme.
610 619
611 @param scheme scheme to look for 620 @param scheme scheme to look for
612 @type str 621 @type str
613 @param host host to look for 622 @param host host to look for
614 @type str 623 @type str
615 @return number of visits to this site 624 @return number of visits to this site
616 @rtype int 625 @rtype int
617 """ 626 """
618 count = 0 627 count = 0
619 url = "{0}://{1}".format(scheme.lower(), host.lower()) 628 url = "{0}://{1}".format(scheme.lower(), host.lower())
620 629
621 seenUrls = [] 630 seenUrls = []
622 631
623 for index in range(len(self.__history)): 632 for index in range(len(self.__history)):
624 historyUrl = self.__history[index].url 633 historyUrl = self.__history[index].url
625 if historyUrl.startswith(url) and historyUrl not in seenUrls: 634 if historyUrl.startswith(url) and historyUrl not in seenUrls:
626 count += self.__history[index].visitCount 635 count += self.__history[index].visitCount
627 seenUrls.append(historyUrl) 636 seenUrls.append(historyUrl)
628 637
629 return count 638 return count

eric ide

mercurial