首先分成了两个类,Scope类和Daemon类,Scope封装了用于保存预览结果的回调函数,Daemon类封装了整个翻译过程和将其显示在dash中的方法。
先看Scope类,
<span style="font-size:14px;">def do_preview_result(self, result, callback):
"""Temporarily save the ScopeResult so it is available for
preview-uri signal handlers."""
# Wrap the AsyncReadyCallback to handle dummy user_data argument.
def wrapped_callback(object, async_result, user_data):
return callback(object, async_result)
self.last_result = result
try:
return Unity.DeprecatedScope.do_preview_result(
self, result, wrapped_callback, None)
finally:
self.last_result = None</span>
可以看到注释里所写,用于暂存Scope的结果
下面再看Daemon类:
1.
<span style="font-size:14px;">def __init__(self):
"""Set some initial values for the scope and connect to Unity"""
self._scope = Scope (dbus_path="/com/canonical/unity/scope/web/dictionary", id="dictionary")
self._sources_options = []
self.url = ''
self.items_web = []
self.items_basic = []
self.new_dic = {}
self.result_list = []
# Storage for results waiting to be displayed
self.results_waiting = {1:[], 2:[], 3:[]}
self.init_session_management ()
self._enabled = False
self._scope.connect("search-changed", self.on_search_changed)
self._scope.connect("notify::active", self.on_lens_active_or_preference_changed)
self._scope.connect('preview-uri', self.on_preview_uri)
self.preferences = Unity.PreferencesManager.get_default()
self.preferences.connect("notify::remote-content-search", self.on_lens_active_or_preference_changed)
</span>
这里对变量进行了初始化,其中self.url用于存储有道提供的接口,self.items_web用于存储翻译的网络释义,self.items_basic用于存储翻译的本地释义(对有道而言),self.result_list用于存储结果,然后将scope与unity进行连接
2.
<span style="font-size:14px;">def init_session_management (self):
""" Define a set of variables used for Soup session management """
self._pending = []
self._http = []
for i in range(3):
self._pending.append(None)
self._http.append(self._get_http_session ())
def _get_http_session (self):
session = Soup.SessionAsync()
session.add_feature_by_type(SoupGNOME.ProxyResolverGNOME)
return session</span>
这里初始化了一个session,但是我感觉应该用不到,但是目前还没有确定它的功能,于是就把它放在这,不会影响其他模块。
3.
<span style="font-size:14px;"> def _handle_search_msg(self, msg, cat):
""" Handle response message"""
results = {}
a = ''
if msg.status_code != 200:
self._pending[cat] = None
print ("Error: Unable to get results from the server")
print (" %d: %s" % (msg.status_code, msg.reason_phrase))
else:
self._pending[cat] = None
try:
# a = urllib.parse.unquote(self.url).encode()
results = json.loads(urllib.request.urlopen(self.url).read().decode('utf-8', 'ignore'))
# print(type(results))
except:
pass
return results</span>
这里调用了有道的api,并在获得结果后调用json.loads函数进行解析,返回的是json格式的数据形式是这样的
{
"errorCode":0
"query":"good",
"translation":["好"], // 有道翻译
"basic":{ // 有道词典-基本词典
"phonetic":"gʊd"
"uk-phonetic":"gʊd" //英式发音
"us-phonetic":"ɡʊd" //美式发音
"explains":[
"好处",
"好的"
"好"
]
},
"web":[ // 有道词典-网络释义
{
"key":"good",
"value":["良好","善","美好"]
},
{...}
]
}
其中errcode为错误码,0表示翻译正常,query表示要翻译的单词,basic中的内容表示有道的基本词典翻译,web中的内容表示网络释义,可以看到,我们需要的就是query,basic中的explains,web中的valus
4.
<span style="font-size:14px;"> </span>
<span style="font-size:14px;"></span>
<span style="font-size:14px;"></span>
<span style="font-size:14px;"> def update_results_model(self, search, model, results, cat, recent_done):
"""Update results for category 0, then the others"""
counter = 0
myresults = {}
myresults = results
web_explains = ''
if myresults['web'] != {}:
self.items_web = myresults['web']
for i in self.items_web['value']:
web_explains += ' '
web_explains += i
self.items_basic = myresults['basic']
self.new_dic['title'] = myresults['query']
self.new_dic['page_url'] = ''
self.new_dic['thumbUrl'] = ''
query = myresults['query']
basic_explains = ''
for k in self.items_basic ['explains']:
basic_explains += ' '
basic_explains += k
model.append(uri=self.url,icon_hint=self.new_dic['thumbUrl'],category=0,mimetype="text/html",title=self.new_dic['title'],comment='',dnd_uri=self.new_dic['page_url'],result_type=Unity.ResultType.PERSONAL)
self.result_list.append({'query':query, 'web_explains':web_explains,'basic_explains':basic_explains})</span>
这里的函数对结果进行了解析,我将其中的'query', 'web_explains','basic_explains',以追加的形式添加进了结果列表中,其中变量的含义我们在之前说过,这里在更新结果的同时也对数据模型进行了更新。
5.
<span style="font-size:14px;">def on_preview_uri(self, scope, uri):
"""Preview request handler"""
preview = None
meta = self.getMetadataForTrans (scope.last_result.category)
width, date, image, title, description, height, position, album_size = None, None, None, '', '', None, None, None
if meta[2]:
title = meta[2]
else:
title = scope.last_result.title
#new preview
preview = Unity.GenericPreview.new(title.strip (), None,None)
preview.props.image_source_uri = scope.last_result.icon_hint
if meta[1]:
preview.props.subtitle = meta[1]
if meta[2]:
#Unity.InfoHint.new(id, display_name, icon_hint, data)
preview.add_info(Unity.InfoHint.new("query", _("Query"), None, meta[2]))
if meta[3]:
preview.add_info(Unity.InfoHint.new("web_explains", _("Web Explain"), None, meta[3]))
if meta[4]:
preview.add_info(Unity.InfoHint.new("basic_explains", _("Basic Explain"), None, meta[4]))
gfile_icon = Gio.file_new_for_path("/usr/share/icons/unity-icon-theme/places/svg/service-sogou.svg")
gicon = Gio.FileIcon.new (gfile_icon)
view_action = Unity.PreviewAction.new("view", _("View"), gicon)
view_action.connect('activated', self.view_action)
preview.add_action(view_action)
if preview == None:
print ("Couldn't find model row for requested preview uri: '%s'", uri)
return preview
def getMetadataForTrans(self, cat):
"""Fetch photo metadata from service"""
url = oid
image, subtitle = None, None
query, web_explains, basic_explains = None, None, None
tag_list = []
for i in self.result_list:
query = i['query']
web_explains = i['web_explains']
basic_explains = i['basic_explains']
return [ image, subtitle, query,web_explains, basic_explains]</span>
这两个函数中getMetadataForTrans即为获得翻译结果的元数据,这个函数之前用于搜索图片的时候将结果中的图片的标题,副标题,尺寸,大小等提取出来,这里我们需要的是源单词,基本释义和网络释义。
on_preview_uri函数则对预览的结果进行操作,传入的参数为上一个函数获得的元数据,其中调用了Unity.GenericPreview类的初始化函数,新建了预览结果,然后调用add_info方法,将元数据与预览结果的变量一一对应,最后为结果添加图标,返回预览结果。
6.
<span style="font-size:14px;">if __name__ == '__main__':
daemon = UnityExtras.dbus_own_name(BUS_NAME, Daemon, None)
if daemon:
GLib.unix_signal_add(0, 2, lambda x: daemon.quit(), None)
daemon.run([])
</span>
最后即为main函数,这里讲unity-scope-runner中的函数放到了这里,应该是在调用unity-scope-daemon.py生成scope的同时就使得这个scope生效,这样基本的代码就写完了。
测试的话我选用了在虚拟机中,因为是一个scope应用,所以debug起来并不是很方便,选用虚拟机的原因一个是配置起来比较方便,配置一个进行克隆就可以了,省去了多次配置的过程。
将/usr/share/unity-scopes/sogou/中的unity-sogou-daemon.py中的内容换成我们刚写好的代码,然后重启ubuntu
在dash中选择Photos目录,输入good,发现提示ubuntu出现了错误,提示发现是语法错误,修改之后再次重启,输入之后提示没有匹配的图片,看来代码还是有问题,继续调试中。