eric6/WebBrowser/History/HistoryCompleter.py

changeset 7775
4a1db75550bd
parent 7360
9190402e4505
child 7923
91e843545d9a
equal deleted inserted replaced
7774:9eed155411f0 7775:4a1db75550bd
5 5
6 """ 6 """
7 Module implementing a special completer for the history. 7 Module implementing a special completer for the history.
8 """ 8 """
9 9
10 10 import re
11 from PyQt5.QtCore import Qt, QRegExp, QTimer, QSortFilterProxyModel 11
12 from PyQt5.QtCore import Qt, QTimer, QSortFilterProxyModel
12 from PyQt5.QtWidgets import QTableView, QAbstractItemView, QCompleter 13 from PyQt5.QtWidgets import QTableView, QAbstractItemView, QCompleter
13 14
14 from .HistoryModel import HistoryModel 15 from .HistoryModel import HistoryModel
15 from .HistoryFilterModel import HistoryFilterModel 16 from .HistoryFilterModel import HistoryFilterModel
16 17
74 @param parent reference to the parent object (QObject) 75 @param parent reference to the parent object (QObject)
75 """ 76 """
76 super(HistoryCompletionModel, self).__init__(parent) 77 super(HistoryCompletionModel, self).__init__(parent)
77 78
78 self.__searchString = "" 79 self.__searchString = ""
79 self.__searchMatcher = QRegExp( 80 self.__searchMatcher = None
80 "", Qt.CaseInsensitive, QRegExp.FixedString) 81 self.__wordMatcher = None
81 self.__wordMatcher = QRegExp("", Qt.CaseInsensitive)
82 self.__isValid = False 82 self.__isValid = False
83 83
84 self.setDynamicSortFilter(True) 84 self.setDynamicSortFilter(True)
85 85
86 def data(self, index, role=Qt.DisplayRole): 86 def data(self, index, role=Qt.DisplayRole):
113 113
114 @return current search string (string) 114 @return current search string (string)
115 """ 115 """
116 return self.__searchString 116 return self.__searchString
117 117
118 def setSearchString(self, string): 118 def setSearchString(self, sstring):
119 """ 119 """
120 Public method to set the current search string. 120 Public method to set the current search string.
121 121
122 @param string new search string (string) 122 @param sstring new search string (string)
123 """ 123 """
124 if string == self.__searchString: 124 if sstring != self.__searchString:
125 return 125 self.__searchString = sstring
126 126 self.__searchMatcher = re.compile(
127 self.__searchString = string 127 re.escape(self.__searchString), re.IGNORECASE)
128 self.__searchMatcher.setPattern(self.__searchString) 128 self.__wordMatcher = re.compile(
129 self.__wordMatcher.setPattern( 129 r"\b" + re.escape(self.__searchString), re.IGNORECASE)
130 "\\b" + QRegExp.escape(self.__searchString)) 130 self.invalidateFilter()
131 self.invalidateFilter()
132 131
133 def isValid(self): 132 def isValid(self):
134 """ 133 """
135 Public method to check the model for validity. 134 Public method to check the model for validity.
136 135
159 158
160 @param sourceRow row number in the source model (integer) 159 @param sourceRow row number in the source model (integer)
161 @param sourceParent index of the source item (QModelIndex) 160 @param sourceParent index of the source item (QModelIndex)
162 @return flag indicating acceptance (boolean) 161 @return flag indicating acceptance (boolean)
163 """ 162 """
164 # Do a case-insensitive substring match against both the url and title. 163 if self.__searchMatcher is not None:
165 # It's already ensured, that the user doesn't accidentally use regexp 164 # Do a case-insensitive substring match against both the url and
166 # metacharacters (s. setSearchString()). 165 # title. It's already ensured, that the user doesn't accidentally
167 idx = self.sourceModel().index(sourceRow, 0, sourceParent) 166 # use regexp metacharacters (s. setSearchString()).
168 167 idx = self.sourceModel().index(sourceRow, 0, sourceParent)
169 url = self.sourceModel().data(idx, HistoryModel.UrlStringRole) 168
170 if self.__searchMatcher.indexIn(url) != -1: 169 url = self.sourceModel().data(idx, HistoryModel.UrlStringRole)
171 return True 170 if self.__searchMatcher.search(url) is not None:
172 171 return True
173 title = self.sourceModel().data(idx, HistoryModel.TitleRole) 172
174 if self.__searchMatcher.indexIn(title) != -1: 173 title = self.sourceModel().data(idx, HistoryModel.TitleRole)
175 return True 174 if self.__searchMatcher.search(title) is not None:
175 return True
176 176
177 return False 177 return False
178 178
179 def lessThan(self, left, right): 179 def lessThan(self, left, right):
180 """ 180 """
186 "slashdot.org". However, it only looks for the string in the host name, 186 "slashdot.org". However, it only looks for the string in the host name,
187 not the entire URL, since while it makes sense to e.g. give 187 not the entire URL, since while it makes sense to e.g. give
188 "www.phoronix.com" a bonus for "ph", it does NOT make sense to give 188 "www.phoronix.com" a bonus for "ph", it does NOT make sense to give
189 "www.yadda.com/foo.php" the bonus. 189 "www.yadda.com/foo.php" the bonus.
190 190
191 @param left index of left item (QModelIndex) 191 @param left index of left item
192 @param right index of right item (QModelIndex) 192 @type QModelIndex
193 @return true, if left is less than right (boolean) 193 @param right index of right item
194 @type QModelIndex
195 @return true, if left is less than right
196 @rtype bool
194 """ 197 """
195 frequency_L = self.sourceModel().data( 198 frequency_L = self.sourceModel().data(
196 left, HistoryFilterModel.FrequencyRole) 199 left, HistoryFilterModel.FrequencyRole)
197 url_L = self.sourceModel().data(left, HistoryModel.UrlRole).host() 200 url_L = self.sourceModel().data(left, HistoryModel.UrlRole).host()
198 title_L = self.sourceModel().data(left, HistoryModel.TitleRole) 201 title_L = self.sourceModel().data(left, HistoryModel.TitleRole)
199 202
200 if ( 203 if (
201 self.__wordMatcher.indexIn(url_L) != -1 or 204 self.__wordMatcher is not None and
202 self.__wordMatcher.indexIn(title_L) != -1 205 (bool(self.__wordMatcher.search(url_L)) or
206 bool(self.__wordMatcher.search(title_L)))
203 ): 207 ):
204 frequency_L *= 2 208 frequency_L *= 2
205 209
206 frequency_R = self.sourceModel().data( 210 frequency_R = self.sourceModel().data(
207 right, HistoryFilterModel.FrequencyRole) 211 right, HistoryFilterModel.FrequencyRole)
208 url_R = self.sourceModel().data(right, HistoryModel.UrlRole).host() 212 url_R = self.sourceModel().data(right, HistoryModel.UrlRole).host()
209 title_R = self.sourceModel().data(right, HistoryModel.TitleRole) 213 title_R = self.sourceModel().data(right, HistoryModel.TitleRole)
210 214
211 if ( 215 if (
212 self.__wordMatcher.indexIn(url_R) != -1 or 216 self.__wordMatcher is not None and
213 self.__wordMatcher.indexIn(title_R) != -1 217 (bool(self.__wordMatcher.search(url_R)) or
218 bool(self.__wordMatcher.search(title_R)))
214 ): 219 ):
215 frequency_R *= 2 220 frequency_R *= 2
216 221
217 # Sort results in descending frequency-derived score. 222 # Sort results in descending frequency-derived score.
218 return frequency_R < frequency_L 223 return frequency_R < frequency_L

eric ide

mercurial