|
a/src/desktop/unity-lens-recoll/recollscope/rclsearch.py |
|
b/src/desktop/unity-lens-recoll/recollscope/rclsearch.py |
1 |
|
1 |
|
2 |
import sys
|
2 |
import sys
|
3 |
import subprocess
|
3 |
import subprocess
|
4 |
import time
|
4 |
import time
|
|
|
5 |
import urllib
|
|
|
6 |
import hashlib
|
|
|
7 |
import os
|
|
|
8 |
import locale
|
5 |
|
9 |
|
6 |
from gi.repository import GLib, GObject, Gio
|
10 |
from gi.repository import GLib, GObject, Gio
|
7 |
from gi.repository import Dee
|
11 |
from gi.repository import Dee
|
8 |
from gi.repository import Unity
|
12 |
from gi.repository import Unity
|
9 |
|
13 |
|
10 |
import recoll
|
14 |
import recoll
|
11 |
|
15 |
|
12 |
BUS_PATH = "/org/recoll/unitylensrecoll/scope/main"
|
16 |
BUS_PATH = "/org/recoll/unitylensrecoll/scope/main"
|
|
|
17 |
|
|
|
18 |
# Thumbnails standard
|
|
|
19 |
# 256x256
|
|
|
20 |
THMBDIRLARGE = "~/.thumbnails/large"
|
|
|
21 |
# 128x128
|
|
|
22 |
THMBDIRNORMAL = "~/.thumbnails/normal"
|
|
|
23 |
|
|
|
24 |
# Icon names for some recoll mime types which don't have standard icon by the
|
|
|
25 |
# normal method
|
|
|
26 |
SPEC_MIME_ICONS = {'application/x-fsdirectory' : 'gnome-fs-directory.svg',
|
|
|
27 |
'message/rfc822' : 'mail-read',
|
|
|
28 |
'application/x-recoll' : 'recoll'}
|
13 |
|
29 |
|
14 |
# These category ids must match the order in which we add them to the lens
|
30 |
# These category ids must match the order in which we add them to the lens
|
15 |
CATEGORY_ALL = 0
|
31 |
CATEGORY_ALL = 0
|
16 |
|
32 |
|
17 |
# typing timeout: we don't want to start a search for every
|
33 |
# typing timeout: we don't want to start a search for every
|
|
... |
|
... |
97 |
search.props.results_model.clear()
|
113 |
search.props.results_model.clear()
|
98 |
|
114 |
|
99 |
def _on_global_search_changed (self, scope, param_spec):
|
115 |
def _on_global_search_changed (self, scope, param_spec):
|
100 |
search = self.get_global_search_string()
|
116 |
search = self.get_global_search_string()
|
101 |
results = scope.props.global_results_model
|
117 |
results = scope.props.global_results_model
|
102 |
|
|
|
103 |
#print "Global search changed to: '%s'" % search
|
118 |
#print "Global search changed to: '%s'" % search
|
104 |
|
|
|
105 |
self._update_results_model (search, results)
|
119 |
self._update_results_model (search, results)
|
106 |
|
120 |
|
107 |
def _update_results_model (self, search_string, model):
|
121 |
def _update_results_model (self, search_string, model):
|
108 |
if search_string:
|
122 |
if search_string:
|
109 |
self._do_search (search_string, model)
|
123 |
self._do_search (search_string, model)
|
110 |
else:
|
124 |
else:
|
111 |
self._do_browse (model)
|
125 |
self._do_browse (model)
|
112 |
|
126 |
|
113 |
def _do_browse (self, model):
|
127 |
def _do_browse (self, model):
|
114 |
if self.timeout_id is not None:
|
128 |
if self.timeout_id is not None:
|
115 |
GObject.source_remove(self.timeout_id)
|
129 |
GObject.source_remove(self.timeout_id)
|
116 |
model.clear ()
|
130 |
model.clear ()
|
117 |
|
131 |
|
|
... |
|
... |
132 |
|
146 |
|
133 |
def _do_search (self, search_string, model):
|
147 |
def _do_search (self, search_string, model):
|
134 |
if TYPING_TIMEOUT == 0:
|
148 |
if TYPING_TIMEOUT == 0:
|
135 |
self._really_do_search(search_string, model)
|
149 |
self._really_do_search(search_string, model)
|
136 |
return True
|
150 |
return True
|
137 |
|
151 |
|
138 |
if self.timeout_id is not None:
|
152 |
if self.timeout_id is not None:
|
139 |
GObject.source_remove(self.timeout_id)
|
153 |
GObject.source_remove(self.timeout_id)
|
140 |
self.timeout_id = \
|
154 |
self.timeout_id = \
|
141 |
GObject.timeout_add(TYPING_TIMEOUT, self._on_timeout,
|
155 |
GObject.timeout_add(TYPING_TIMEOUT, self._on_timeout,
|
142 |
search_string, model)
|
156 |
search_string, model)
|
|
|
157 |
|
|
|
158 |
def _get_thumbnail_path(self, url):
|
|
|
159 |
"""Look for a thumbnail for the input url, according to the
|
|
|
160 |
freedesktop thumbnail storage standard. The input 'url' always
|
|
|
161 |
begins with file:// and is unencoded. We encode it properly
|
|
|
162 |
and compute the path inside the thumbnail storage
|
|
|
163 |
directory. We return the path only if the thumbnail does exist
|
|
|
164 |
(no generation performed)"""
|
|
|
165 |
path = url
|
|
|
166 |
path = path.replace("file://", "", 1)
|
|
|
167 |
try:
|
|
|
168 |
path = "file://" + urllib.quote(path)
|
|
|
169 |
except:
|
|
|
170 |
#print "_get_thumbnail_path: quote failed"
|
|
|
171 |
return None
|
|
|
172 |
#print "_get_thumbnail: encoded path: [%s]" % (path,)
|
|
|
173 |
thumbname = hashlib.md5(path).hexdigest() + ".png"
|
|
|
174 |
#print "_get_thumbnail: thumbname: [%s]" % (thumbname,)
|
|
|
175 |
tpath = os.path.join(os.path.expanduser(THMBDIRNORMAL), thumbname)
|
|
|
176 |
if os.path.exists(tpath):
|
|
|
177 |
return tpath
|
|
|
178 |
tpath = os.path.join(os.path.expanduser(THMBDIRLARGE), thumbname)
|
|
|
179 |
if os.path.exists(tpath):
|
|
|
180 |
return tpath
|
|
|
181 |
return None
|
143 |
|
182 |
|
144 |
def _really_do_search(self, search_string, model):
|
183 |
def _really_do_search(self, search_string, model):
|
145 |
#print "really_do_search:", "[" + search_string + "]"
|
184 |
#print "really_do_search:", "[" + search_string + "]"
|
146 |
|
185 |
|
147 |
model.clear ()
|
186 |
model.clear ()
|
|
... |
|
... |
181 |
except:
|
220 |
except:
|
182 |
break
|
221 |
break
|
183 |
|
222 |
|
184 |
# Results with an ipath get a special mime type so that they
|
223 |
# Results with an ipath get a special mime type so that they
|
185 |
# get opened by starting a recoll instance.
|
224 |
# get opened by starting a recoll instance.
|
|
|
225 |
thumbnail = None
|
186 |
if doc.ipath != "":
|
226 |
if doc.ipath != "":
|
187 |
mimetype = "application/x-recoll"
|
227 |
mimetype = "application/x-recoll"
|
188 |
url = doc.url + "#" + doc.ipath
|
228 |
url = doc.url + "#" + doc.ipath
|
189 |
else:
|
229 |
else:
|
190 |
mimetype = doc.mimetype
|
230 |
mimetype = doc.mimetype
|
191 |
url = doc.url
|
231 |
url = doc.url
|
|
|
232 |
# doc.url is a unicode string which is badly wrong. A
|
|
|
233 |
# future version of the pyrecoll module will have a
|
|
|
234 |
# separate method to retrieve the binary
|
|
|
235 |
# version. Until this happens, try to encode
|
|
|
236 |
# back. This won't work every time (ie: if the
|
|
|
237 |
# original path could not be translated to unicode by
|
|
|
238 |
# pyrecoll, or if the unicode can't be translated back
|
|
|
239 |
# in the current locale)
|
|
|
240 |
encoding = locale.nl_langinfo(locale.CODESET)
|
|
|
241 |
thumbnail = \
|
|
|
242 |
self._get_thumbnail_path(url.encode(encoding,
|
|
|
243 |
errors='replace'))
|
192 |
|
244 |
|
193 |
#print "Recoll Lens: Using MIMETYPE", mimetype, " URL", url
|
245 |
#print "Recoll Lens: Using MIMETYPE", mimetype, " URL", url
|
194 |
|
246 |
|
195 |
titleorfilename = doc.title
|
247 |
titleorfilename = doc.title
|
196 |
if titleorfilename == "":
|
248 |
if titleorfilename == "":
|
197 |
titleorfilename = doc.filename
|
249 |
titleorfilename = doc.filename
|
198 |
|
250 |
|
|
|
251 |
iconname = None
|
|
|
252 |
if thumbnail:
|
|
|
253 |
iconname = thumbnail
|
|
|
254 |
else:
|
|
|
255 |
if SPEC_MIME_ICONS.has_key(doc.mimetype):
|
|
|
256 |
iconname = SPEC_MIME_ICONS[doc.mimetype]
|
|
|
257 |
else:
|
199 |
icon = Gio.content_type_get_icon(doc.mimetype)
|
258 |
icon = Gio.content_type_get_icon(doc.mimetype)
|
200 |
if icon:
|
259 |
if icon:
|
201 |
iconname = icon.get_names()[0]
|
260 |
iconname = icon.get_names()[0]
|
|
|
261 |
|
|
|
262 |
#print "iconname:", iconname
|
|
|
263 |
|
202 |
|
264 |
|
203 |
try:
|
265 |
try:
|
204 |
abstract = self.db.makeDocAbstract(doc, query).encode('utf-8')
|
266 |
abstract = self.db.makeDocAbstract(doc, query).encode('utf-8')
|
205 |
except:
|
267 |
except:
|
206 |
break
|
268 |
break
|