~submarine/unity-scope-virtualbox/previews

3 by David Callé
* New API
1
#! /usr/bin/python3
1 by David Callé
* Init VirtualBox scope
2
# -*- coding: utf-8 -*-
3
3 by David Callé
* New API
4
# Copyright (C) 2013 David Callé <davidc@framli.eu>
5
# Copyright (C) 2012 Christopher Wayne <cwayne@ubuntu.com>
1 by David Callé
* Init VirtualBox scope
6
# This program is free software: you can redistribute it and/or modify it 
7
# under the terms of the GNU General Public License version 3, as published 
8
# by the Free Software Foundation.
9
# 
10
# This program is distributed in the hope that it will be useful, but 
11
# WITHOUT ANY WARRANTY; without even the implied warranties of 
12
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
13
# PURPOSE.  See the GNU General Public License for more details.
14
# 
15
# You should have received a copy of the GNU General Public License along 
16
# with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
from gi.repository import Unity, UnityExtras
3 by David Callé
* New API
19
from gi.repository import Gio, GLib
1 by David Callé
* Init VirtualBox scope
20
import subprocess
21
import re
22
import shlex
23
import gettext
21 by David Callé
Initial VirtualBox previews
24
import datetime
1 by David Callé
* Init VirtualBox scope
25
3 by David Callé
* New API
26
APP_NAME = 'unity-scope-virtualbox'
27
LOCAL_PATH = '/usr/share/locale/'
1 by David Callé
* Init VirtualBox scope
28
gettext.bindtextdomain(APP_NAME, LOCAL_PATH)
29
gettext.textdomain(APP_NAME)
30
_ = gettext.gettext
31
3 by David Callé
* New API
32
GROUP_NAME = 'com.canonical.Unity.Scope.Boxes.Virtualbox'
33
UNIQUE_PATH = '/com/canonical/unity/scope/boxes/virtualbox'
34
SEARCH_URI = ''
35
SEARCH_HINT = _('Search Virtualbox')
36
NO_RESULTS_HINT = _('Sorry, there is no VirtualBox machine that matches your search.')
37
PROVIDER_CREDITS = _('Powered by VirtualBox')
38
SVG_DIR = '/usr/share/icons/unity-icon-theme/places/svg/'
39
PROVIDER_ICON = SVG_DIR+'service-virtualbox.svg'
40
DEFAULT_RESULT_ICON = 'virtualbox'
41
DEFAULT_RESULT_MIMETYPE = 'application/x-virtualbox-vbox'
42
DEFAULT_RESULT_TYPE = Unity.ResultType.DEFAULT
43
EXTRA_DATA = None
44
15.1.1 by David Callé
Update category id to match master
45
c1 = {'id'      :'boxes',
3 by David Callé
* New API
46
      'name'    :_('Virtual Machines'),
47
      'icon'    :SVG_DIR+'group-boxes.svg',
48
      'renderer':Unity.CategoryRenderer.VERTICAL_TILE}
49
CATEGORIES = [c1]
50
51
FILTERS = []
52
53
EXTRA_METADATA = []
54
55
def search(search, filters):
56
    '''
57
    Any search method returning results as a list of tuples.
58
    Available tuple fields:
59
    uri (string)
60
    icon (string)
61
    title (string)
62
    comment (string)
63
    dnd_uri (string)
64
    mimetype (string)
65
    category (int)
66
    result_type (Unity ResultType)
67
    extras metadata fields (variant)
68
    '''
69
    results = []
70
    try:
71
        if not EXTRA_DATA:
72
            vboxlist = subprocess.check_output(['vboxmanage', 'list', 'vms'])
73
        else:
74
            vboxlist = EXTRA_DATA
75
        for vbox in vboxlist.splitlines():
21 by David Callé
Initial VirtualBox previews
76
            vbox_name = re.sub('\{.*\}', '', vbox.decode('utf-8'))
77
            uuid = re.match(r'.*\{(.*)\}', vbox.decode('utf-8'))
78
            if uuid:
79
                uuid = uuid.group(1)
80
            else:
81
                uuid = shlex.split(vbox_name)[0]
82
            if search.lower() in vbox_name.lower():
83
                results.append({'uri':uuid,
84
                                'title':shlex.split(vbox_name)[0]})
3 by David Callé
* New API
85
    except Exception as error:
86
        print (error)
21 by David Callé
Initial VirtualBox previews
87
    print (results)
3 by David Callé
* New API
88
    return results
89
90
91
# Classes below this point establish communication
92
# with Unity, you probably shouldn't modify them.
93
94
95
class MySearch (Unity.ScopeSearchBase):
96
    def __init__(self, search_context):
97
        super (MySearch, self).__init__()
98
        self.set_search_context (search_context)
99
100
    def do_run (self):
101
        '''
102
        Adds results to the model
103
        '''
1 by David Callé
* Init VirtualBox scope
104
        try:
3 by David Callé
* New API
105
            result_set = self.search_context.result_set
106
            for i in search(self.search_context.search_query,
107
                            self.search_context.filter_state):
108
                if not 'uri' in i or not i['uri'] or i['uri'] == '':
109
                    continue
110
                if not 'icon' in i or not i['icon'] or i['icon'] == '':
111
                    i['icon'] = DEFAULT_RESULT_ICON
112
                if not 'mimetype' in i or not i['mimetype'] or i['mimetype'] == '':
113
                    i['mimetype'] = DEFAULT_RESULT_MIMETYPE
114
                if not 'result_type' in i or not i['result_type'] or i['result_type'] == '':
115
                    i['result_type'] = DEFAULT_RESULT_TYPE
116
                if not 'category' in i or not i['category'] or i['category'] == '':
117
                    i['category'] = 0
118
                if not 'title' in i or not i['title']:
119
                    i['title'] = ''
120
                if not 'comment' in i or not i['comment']:
121
                    i['comment'] = ''
122
                if not 'dnd_uri' in i or not i['dnd_uri'] or i['dnd_uri'] == '':
123
                    i['dnd_uri'] = i['uri']
21 by David Callé
Initial VirtualBox previews
124
                i['provider_credits'] = GLib.Variant('s', PROVIDER_CREDITS)
125
                result_set.add_result(**i)
1 by David Callé
* Init VirtualBox scope
126
        except Exception as error:
3 by David Callé
* New API
127
            print (error)
128
21 by David Callé
Initial VirtualBox previews
129
class Preview (Unity.ResultPreviewer):
130
131
    def do_run(self):
132
        preview = Unity.GenericPreview.new(self.result.title, self.result.comment, None)
133
        preview.props.image_source_uri = self.result.icon_hint
134
        vboxinfo = subprocess.check_output(['vboxmanage', 'showvminfo', self.result.uri])
135
        for line in vboxinfo.splitlines():
136
            line = line.decode('utf-8')
137
            if line.startswith('Guest OS:'):
138
                os = re.match(r'.*:\s+([^\s].*)',line)
139
                if os:
140
                    os_text = os.group(1)
22 by David Callé
OS -> Operating System
141
                    preview.add_info(Unity.InfoHint.new("os", _("Operating System"), None, os_text))
21 by David Callé
Initial VirtualBox previews
142
            if line.startswith('Memory size:'):
143
                memsize = re.match(r'.*:\s+([^\s].*)',line)
144
                if memsize:
145
                    memsize_text = memsize.group(1)
146
                    preview.add_info(Unity.InfoHint.new("memsize", _("Base Memory"), None, memsize_text))
147
            if line.startswith('VRAM size:'):
148
                vramsize = re.match(r'.*:\s+([^\s].*)',line)
149
                if vramsize:
150
                    vramsize_text = vramsize.group(1)
151
                    preview.add_info(Unity.InfoHint.new("vramsize", _("Video Memory"), None, vramsize_text))
152
            if line.startswith('Number of CPUs:'):
153
                numcpu = re.match(r'.*:\s+([^\s].*)',line)
154
                if numcpu:
155
                    numcpu_text = numcpu.group(1)
156
                    preview.add_info(Unity.InfoHint.new("numcpu", _("Number of CPUs"), None, numcpu_text))
157
            if line.startswith('State:'):
158
                state = re.match(r'.*:\s+([^\s].*)\(since\s(.*)\)',line)
159
                if state:
160
                    state_text = state.group(1)
161
                    date = state.group(2)
162
163
                    translated_date = datetime.datetime.strptime(date[:-3], '%Y-%m-%dT%H:%M:%S.%f')
164
                    preview.props.subtitle = state_text.title() + "(%s)" % translated_date.strftime('%c')
165
        icon = Gio.FileIcon.new (Gio.file_new_for_path(PROVIDER_ICON))
166
        view_action = Unity.PreviewAction.new("launch", _("Launch"), icon)
167
        preview.add_action(view_action)
168
        return preview
169
3 by David Callé
* New API
170
class Scope (Unity.AbstractScope):
171
    def __init__(self):
172
        Unity.AbstractScope.__init__(self)
173
174
    def do_get_search_hint (self):
175
        return SEARCH_HINT
176
177
    def do_get_schema (self):
178
        '''
179
        Adds specific metadata fields
180
        '''
181
        schema = Unity.Schema.new ()
182
        if EXTRA_METADATA:
183
            for m in EXTRA_METADATA:
184
                schema.add_field(m['id'], m['type'], m['field'])
185
        #FIXME should be REQUIRED for credits
186
        schema.add_field('provider_credits', 's', Unity.SchemaFieldType.OPTIONAL)
187
        return schema
188
189
    def do_get_categories (self):
190
        '''
191
        Adds categories
192
        '''
193
        cs = Unity.CategorySet.new ()
194
        if CATEGORIES:
195
            for c in CATEGORIES:
196
                cat = Unity.Category.new (c['id'], c['name'],
197
                                          Gio.ThemedIcon.new(c['icon']),
198
                                          c['renderer'])
199
                cs.add (cat)
200
        return cs
201
202
    def do_get_filters (self):
203
        '''
204
        Adds filters
205
        '''
206
        fs = Unity.FilterSet.new ()
207
#        if FILTERS:
208
#            
209
        return fs
210
211
    def do_get_group_name (self):
212
        return GROUP_NAME
213
214
    def do_get_unique_name (self):
215
        return UNIQUE_PATH
216
217
    def do_create_search_for_query (self, search_context):
218
        se = MySearch (search_context)
219
        return se
220
21 by David Callé
Initial VirtualBox previews
221
    def do_create_previewer(self, result, metadata):
222
        rp = Preview()
223
        rp.set_scope_result(result)
224
        rp.set_search_metadata(metadata)
225
        return rp
226
227
    def do_activate(self, result, metadata, id):
228
        GLib.spawn_async(["/usr/bin/vboxmanage", "startvm", result.uri])
229
        return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri=None)
230
3 by David Callé
* New API
231
def load_scope():
232
    return Scope()