~submarine/unity-scope-yelp/trunk

« back to all changes in this revision

Viewing changes to src/unity_yelp_daemon.py

  • Committer: Tarmac
  • Author(s): James Henstridge
  • Date: 2013-05-13 09:03:50 UTC
  • mfrom: (27.1.2 unity-scope-yelp)
  • Revision ID: tarmac-20130513090350-8nhqtzgv1jcoq02a
Add a simple preview to the scope, and correctly discover documentation in the fallback "C" directory when there are localised manuals.

Approved by David Callé, PS Jenkins bot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# You should have received a copy of the GNU General Public License along
15
15
# with this program.  If not, see <http://www.gnu.org/licenses/>.
16
16
 
17
 
from gi.repository import GLib, Gio
18
 
from gi.repository import Unity
19
17
import gettext
 
18
import html
20
19
import locale
21
20
import os
22
 
from xml.dom import minidom
 
21
from xml.etree import cElementTree as ET
 
22
 
 
23
from gi.repository import GLib, Gio
 
24
from gi.repository import Unity
23
25
 
24
26
APP_NAME = 'unity-scope-yelp'
25
27
LOCAL_PATH = '/usr/share/locale/'
55
57
EXTRA_METADATA = []
56
58
 
57
59
 
 
60
def _get_manuals_in_dir(dir, manuals):
 
61
    """Yield the manuals found in the given directory, omitting those
 
62
    that have already been discovered."""
 
63
    if not os.path.isdir(dir):
 
64
        return
 
65
    for manual in os.listdir(dir):
 
66
        if manual in manuals:
 
67
            continue
 
68
        manualdir = os.path.join(dir, manual)
 
69
        if os.path.isdir(manualdir):
 
70
            manuals.add(manual)
 
71
            yield manualdir
 
72
 
 
73
 
 
74
def get_manuals(helpdir):
 
75
    """Get the manuals found in the given directory according to the
 
76
    user's locale."""
 
77
    language, encoding = locale.getlocale()
 
78
    manuals = set()
 
79
    if language is not None:
 
80
        languagedir = os.path.join(helpdir, language)
 
81
        yield from _get_manuals_in_dir(languagedir, manuals)
 
82
        # If the locale includes a country, look for manuals 
 
83
        if language[:2] != language:
 
84
            languagedir = os.path.join(helpdir, language[:2])
 
85
            yield from _get_manuals_in_dir(languagedir, manuals)
 
86
    # Now return untranslated versions of remaining manuals.
 
87
    languagedir = os.path.join(helpdir, 'C')
 
88
    yield from _get_manuals_in_dir(languagedir, manuals)
 
89
 
 
90
 
58
91
def get_yelp_documents():
59
92
    '''
60
93
     Parses local help files for <desc> and 1st <title> tags and associates
61
94
    them with the page's uri in self.data as: {uri, page description, page title}
62
95
    If a help file has no <desc> or <title> tag, it is excluded.
63
96
    '''
64
 
    language, encoding = locale.getlocale()
65
 
    if language is None:
66
 
        language = 'C'
67
 
 
68
97
    data = []
69
 
    help_location = '%s%s' % (HELP_DIR, language)
70
 
    if not os.path.exists(help_location):
71
 
        help_location = '%s%s' % (HELP_DIR, language[:2])
72
 
        if not os.path.exists(help_location):
73
 
            help_location = '%s%s' % (HELP_DIR, "C")
74
 
    for dirname in os.listdir(help_location):
75
 
        directory = help_location + "/" + dirname
76
 
        for filename in os.listdir(directory):
77
 
            filename = directory + "/" + filename
78
 
            if not os.path.isdir(filename):
79
 
                if os.path.isfile(filename):
80
 
                    xmldoc = minidom.parse(filename)
81
 
                    try:
82
 
                        pagenode = xmldoc.getElementsByTagName('page')[0]
83
 
                        if pagenode.attributes["type"].value == "topic":
84
 
                            desc = ""
85
 
                            nodes = xmldoc.getElementsByTagName('desc').item(0).childNodes
86
 
                            for node in nodes:
87
 
                                try:
88
 
                                    desc += str(node.wholeText)
89
 
                                except:
90
 
                                    desc += str(node.childNodes[0].wholeText)
91
 
                            desc = desc.strip(' \t\n\r')
92
 
                            title = xmldoc.getElementsByTagName('title').item(0).childNodes[0].data
93
 
                            if desc == "":
94
 
                                desc = title
95
 
                            record = []
96
 
                            record.append(filename)
97
 
                            record.append(desc)
98
 
                            record.append(title)
99
 
                            record.append(dirname)
100
 
                            data.append(record)
101
 
                    except:
102
 
                        pass
 
98
    namespaces = {'m': 'http://projectmallard.org/1.0/'}
 
99
    for manualdir in get_manuals(HELP_DIR):
 
100
        for filename in os.listdir(manualdir):
 
101
            filename = os.path.join(manualdir, filename)
 
102
            if not (filename.endswith('page') and os.path.isfile(filename)):
 
103
                continue
 
104
            try:
 
105
                tree = ET.parse(filename)
 
106
            except ET.ParseError:
 
107
                # Not an XML file
 
108
                continue
 
109
            if (tree.getroot().tag != '{http://projectmallard.org/1.0/}page' or
 
110
                tree.getroot().get('type') != 'topic'):
 
111
                # Not a Mallard documentation file.
 
112
                continue
 
113
            title = desc = ""
 
114
            node = tree.find('m:title', namespaces)
 
115
            if node is not None:
 
116
                title = node.text
 
117
            node = tree.find('m:info/m:desc', namespaces)
 
118
            if node is not None:
 
119
                desc = ''.join(node.itertext())
 
120
            desc = desc.strip(' \t\n\r')
 
121
            if desc == "":
 
122
                desc = title
 
123
 
 
124
            data.append((filename, title, desc, os.path.basename(manualdir)))
103
125
    return data
104
126
 
105
127
 
116
138
        YELP_CACHE = get_yelp_documents()
117
139
    help_data = YELP_CACHE
118
140
 
119
 
    for data in help_data:
 
141
    search = search.lower()
 
142
 
 
143
    for (filename, title, desc, manual) in help_data:
120
144
        if len(results) >= MAX_RESULTS:
121
 
            return results
 
145
            break
122
146
        try:
123
 
            if data[3] == "ubuntu-help":
 
147
            if manual == "ubuntu-help":
124
148
                icon_hint = Gio.ThemedIcon.new("distributor-logo").to_string()
125
149
            else:
126
 
                icon_hint = Gio.ThemedIcon.new(data[3]).to_string()
 
150
                icon_hint = Gio.ThemedIcon.new(manual).to_string()
127
151
        except:
128
152
            icon_hint = Gio.ThemedIcon.new("help").to_string()
129
153
 
130
 
        if search.lower() in data[1].lower():
131
 
            results.append({'uri': data[0],
132
 
                            'icon': icon_hint,
133
 
                            'title': data[1]})
134
 
        elif search.lower() in data[2].lower():
135
 
            results.append({'uri': data[0],
136
 
                            'icon': icon_hint,
137
 
                            'title': data[2]})
138
 
        elif search.lower() in data[3].lower():
139
 
            results.append({'uri': data[0],
140
 
                            'icon': icon_hint,
141
 
                            'title': data[1]})
142
 
        else:
143
 
            continue
 
154
        if (search in title.lower() or
 
155
            search in desc.lower() or
 
156
            search in manual.lower()):
 
157
            results.append({'uri': filename,
 
158
                            'icon': icon_hint,
 
159
                            'title': title,
 
160
                            'comment': desc})
144
161
    return results
145
162
 
146
163
 
 
164
class Previewer(Unity.ResultPreviewer):
 
165
 
 
166
    def do_run(self):
 
167
        image = Gio.ThemedIcon.new(self.result.icon_hint)
 
168
        preview = Unity.GenericPreview.new(
 
169
            self.result.title, html.escape(self.result.comment), image)
 
170
        action = Unity.PreviewAction.new("open", _("Open"), None)
 
171
        preview.add_action(action)
 
172
        return preview
 
173
 
 
174
 
147
175
# Classes below this point establish communication
148
176
# with Unity, you probably shouldn't modify them.
149
177
 
245
273
        se = MySearch(search_context)
246
274
        return se
247
275
 
 
276
    def do_create_previewer(self, result, metadata):
 
277
        rp = Previewer()
 
278
        rp.set_scope_result(result)
 
279
        rp.set_search_metadata(metadata)
 
280
        return rp
 
281
 
248
282
    def do_activate(self, result, metadata, id):
249
283
        parameters = [YELP_EXECUTABLE, result.uri]
250
284
        GLib.spawn_async(parameters)