~dpm/qreator/snap

« back to all changes in this revision

Viewing changes to qreator/QreatorWindow.py

  • Committer: David Planella
  • Date: 2012-05-30 08:33:06 UTC
  • Revision ID: david.planella@ubuntu.com-20120530083306-2naqmakzg56jh5mx
Decoupled QR code types from the QR window and from a particular GUI toolkit (right now only GTK is supported)

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import cairo
18
18
import math
19
 
from gi.repository import Gtk, Gdk, GdkPixbuf, GLib  # pylint: disable=E0611
20
 
from gi.repository import GtkChamplain, Clutter, Champlain
21
 
from gi.repository import NetworkManager, NMClient
 
19
from gi.repository import Gtk, Gdk, GdkPixbuf  # pylint: disable=E0611
22
20
import logging
23
21
logger = logging.getLogger('qreator')
24
22
 
25
23
from qreator_lib.i18n import _
26
24
from qreator_lib import Window
27
 
from qreator_lib.helpers import get_media_file as get_media_file
28
 
 
29
 
import sys
30
 
sys.path.insert(0, "/usr/share/software-center/")
31
 
import softwarecenter.db.database
32
 
import defer
33
 
 
34
 
from QRCode import QRCode as QRCode
35
 
from QRCode import QRCodeOutput as QRCodeOutput
 
25
from qreator_lib.helpers import get_media_file
 
26
 
 
27
from QRCode import QRCode
 
28
from QRCode import QRCodeOutput
36
29
 
37
30
COL_DESC = 0
38
31
COL_PIXBUF = 1
39
 
COL_CALLBACK = 2
 
32
COL_ID = 2
40
33
 
41
34
PAGE_NEW = 0
42
35
#PAGE_HISTORY = 1
43
 
#PAGE_SETTINGS = 2
44
36
PAGE_ABOUT = 1
45
37
PAGE_QR = 2
46
38
 
68
60
        # Hide the notebook tabs
69
61
        self.ui.notebook1.set_show_tabs(False)
70
62
 
71
 
        # Initialize combo boxes
72
 
        self.ui.comboboxtextSecurity.set_active(0)
73
 
        self.ui.comboboxtextProtocol.set_active(0)
74
 
 
75
 
        # Initialize placeholder text (we need to do that because due to
76
 
        # a Glade bug they are otherwise not marked as translatable)
77
 
        self.ui.entryURL.set_placeholder_text(_('[URL]'))
78
 
        # TRANSLATORS: 'expand' refers to expanding the drop-down menu
79
 
        # that shows autodetected wireless network identifiers
80
 
        self.ui.entrySSID.set_placeholder_text(
81
 
            _('[Network identifier - expand for autodetection]'))
82
 
        self.ui.entryPassword.set_placeholder_text(_('[Network password]'))
83
 
 
84
63
        # Initialize about dialog
85
 
        about = Gtk.AboutDialog()
86
 
        about.set_program_name("Qreator")
87
 
        about.set_copyright(
88
 
            "Copyright (c) 2012 David Planella" +
89
 
            "\nhttp://about.me/david.planella")
90
 
        about.set_website("https://launchpad.net/qreator")
91
 
 
92
 
        about.set_version('12.05.6')
93
 
        about.set_authors([
94
 
            'David Planella <david.planella@ubuntu.com>',
95
 
            'Michael Hall <mhall119@ubuntu.com>',
96
 
            'Andrew Starr-Bochicchio <andrewsomething@ubuntu.com >',
97
 
            ])
98
 
        about.set_license(_('Distributed under the GPL v3 license.') +
99
 
                '\nhttp://www.opensource.org/licenses/gpl-3.0.html')
100
 
 
101
 
        about.set_translator_credits(_("translator-credits"))
102
 
 
103
 
        box = builder.get_object("about_box")
104
 
        about.vbox.reparent(box)
105
 
 
106
 
        # Get rid of the 'Close' button
107
 
        for button in about.action_area.get_children():
108
 
            if button.get_property('label') == 'gtk-close':
109
 
                button.destroy()
110
 
 
111
 
        # Initialize the Software Center apps autocompletion
112
 
        self.softwarecenterapps = None
113
 
 
114
 
        self.usc_apps_complete = Complete()
115
 
 
116
 
        self.usc_apps_complete.set_hexpand(True)
117
 
        self.usc_apps_complete.connect("changed",
118
 
                                    self.on_usc_apps_complete_changed, None)
119
 
        self.usc_apps_complete.connect("icon-press",
120
 
                                    self.on_usc_apps_complete_icon_pressed)
121
 
        self.usc_apps_complete.set_icon_from_icon_name(
122
 
            Gtk.EntryIconPosition.PRIMARY, 'edit-find-symbolic')
123
 
        self.usc_apps_complete.set_icon_from_stock(
124
 
            Gtk.EntryIconPosition.SECONDARY, None)
125
 
 
126
 
        #self.get_softwarecenterapps()
127
 
        #self.on_get_softwarecenterapps()
128
 
        #deferred = defer.defer(self.get_softwarecenterapps)
129
 
        #deferred.add_callback(self.on_get_softwarecenterapps)
130
 
 
131
 
        self.ui.qr_app.attach(self.usc_apps_complete, 1, 0, 1, 1)
132
 
        self.softwarecenter_apps_init = False
133
 
 
134
 
        # Load the background texture
 
64
        self.init_about_dialog()
 
65
 
 
66
        # Initialize the QR types icon view
 
67
        self.init_qr_types()
 
68
 
 
69
        # Load the background texture in the QR code page
135
70
        self.texture = cairo.ImageSurface.create_from_png(
136
71
                                                get_media_file("pattern.png"))
137
72
 
 
73
        # Add an initial text, so that there is an initial QR code
 
74
        self.qr_code_placeholder = 'http://launchpad.net/qreator'
 
75
 
 
76
    def init_qr_types(self):
138
77
        # Set up the QR types shown in the main icon view
139
78
        self.ui.qr_types_view.set_text_column(COL_DESC)
140
79
        self.ui.qr_types_view.set_pixbuf_column(COL_PIXBUF)
141
80
 
 
81
        from qrcodes.QRCodeText import QRCodeText
 
82
        from qrcodes.QRCodeURL import QRCodeURL
 
83
        from qrcodes.QRCodeLocation import QRCodeLocation
 
84
        from qrcodes.QRCodeWifi import QRCodeWifi
 
85
        from qrcodes.QRCodeSoftwareCenterApp import QRCodeSoftwareCenterApp
 
86
 
142
87
        self.qr_types = [
143
 
            {'desc': _('URL'),
144
 
                'icon': GdkPixbuf.Pixbuf.new_from_file(get_media_file(
145
 
                            'url.png')),
146
 
                'callback': 'on_qr_url_clicked'},
147
 
            {'desc': _('Text'),
148
 
                'icon': GdkPixbuf.Pixbuf.new_from_file(get_media_file(
149
 
                            'text.png')),
150
 
                'callback': 'on_qr_text_clicked'},
151
 
            {'desc': _('Geolocation'),
152
 
                'icon': GdkPixbuf.Pixbuf.new_from_file(get_media_file(
153
 
                            'location.png')),
154
 
                'callback': 'on_qr_location_clicked'},
155
 
            {'desc': _('Wifi network'),
156
 
                'icon': GdkPixbuf.Pixbuf.new_from_file(get_media_file(
157
 
                            'wifi.png')),
158
 
                'callback': 'on_qr_wifi_clicked'},
159
 
            {'desc': _('Ubuntu Software Center app'),
160
 
                'icon': GdkPixbuf.Pixbuf.new_from_file(get_media_file(
161
 
                            'softwarecentre.png')),
162
 
                'callback': 'on_qr_softwarecenterapp_clicked'},
 
88
            QRCodeURL(self.update_qr_code, 'url.png', _('URL'), 0),
 
89
            QRCodeText(self.update_qr_code, 'text.png', _('Text'), 1),
 
90
            QRCodeLocation(self.update_qr_code, 'location.png',
 
91
                _('Geolocation'), 2),
 
92
            QRCodeWifi(self.update_qr_code, 'wifi.png', _('Wifi network'), 3),
 
93
            QRCodeSoftwareCenterApp(self.update_qr_code, 'softwarecentre.png',
 
94
                _('Ubuntu Software Center app'), 4),
163
95
        ]
164
96
 
165
 
        self.qr_types_store = Gtk.ListStore(str, GdkPixbuf.Pixbuf, str)
166
 
        # ^ desc, icon, callback ^
 
97
        self.qr_types_store = Gtk.ListStore(str, GdkPixbuf.Pixbuf, int)
 
98
        # ^ desc, icon, id ^
167
99
        self.qr_types_store.set_sort_column_id(COL_DESC,
168
100
                                               Gtk.SortType.ASCENDING)
169
101
        self.ui.qr_types_view.set_model(self.qr_types_store)
172
104
        self.curr_height = 0
173
105
        self.curr_width = 0
174
106
 
175
 
        # Add an initial text, so that there is an initial QR code
176
 
        self.qr_code_placeholder = 'http://launchpad.net/qreator'
177
 
 
178
 
    def on_usc_apps_complete_icon_pressed(self, widget, icon, mouse_button):
179
 
        self._clear_text_entry(widget, icon)
180
 
 
181
 
    def _clear_text_entry(self, widget, icon):
182
 
        if icon == Gtk.EntryIconPosition.SECONDARY:
183
 
            widget.set_text("")
184
 
            self._check_style(widget)
185
 
 
186
 
        elif icon == Gtk.EntryIconPosition.PRIMARY:
187
 
            widget.select_region(0, -1)
188
 
            widget.grab_focus()
189
 
 
190
 
    def _check_style(self, widget):
191
 
        """
192
 
        Show the clear icon whenever the field is not empty
193
 
        """
194
 
        if widget.get_text() != "":
195
 
            widget.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY,
196
 
                Gtk.STOCK_CLEAR)
197
 
            # reverse the icon if we are in an rtl environment
198
 
            if widget.get_direction() == Gtk.TextDirection.RTL:
199
 
                pb = widget.get_icon_pixbuf(
200
 
                    Gtk.EntryIconPosition.SECONDARY).flip(True)
201
 
                widget.set_icon_from_pixbuf(Gtk.EntryIconPosition.SECONDARY,
202
 
                    pb)
203
 
        else:
204
 
            widget.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None)
205
 
 
206
 
    def init_softwarecenter_apps(self):
207
 
        deferred = defer.defer(self.get_softwarecenterapps)
208
 
        deferred.add_callback(self.on_get_softwarecenterapps)
209
 
        self.softwarecenter_apps_init = True
 
107
        for qr_type in self.qr_types:
 
108
            self.ui.qr_input_notebook.append_page(qr_type.widget.grid, None)
210
109
 
211
110
    def fill_qr_types_store(self):
212
111
        self.qr_types_store.clear()
213
112
 
214
113
        for qr_type in self.qr_types:
215
 
            self.qr_types_store.append([qr_type['desc'],
216
 
                                        qr_type['icon'],
217
 
                                        qr_type['callback']])
 
114
            icon = GdkPixbuf.Pixbuf.new_from_file(get_media_file(
 
115
                            qr_type.icon_path))
 
116
            self.qr_types_store.append([qr_type.description,
 
117
                                        icon,
 
118
                                        qr_type.id])
218
119
 
219
120
    def on_qreator_window_check_resize(self, widget):
220
121
        '''We need this function to fix the issue described at
232
133
            # and refill iconviews with icons to adjust columns number
233
134
            self.fill_qr_types_store()
234
135
 
235
 
    def on_entryText_changed(self, widget, data=None):
236
 
        self.update_qr_code(widget.get_text(widget.get_start_iter(),
237
 
                                            widget.get_end_iter(),
238
 
                                            False))
239
 
 
240
 
    def on_map_widget_button_press_event(self, actor, event, view):
241
 
        x, y = event.get_coords()
242
 
        lat, lon = view.x_to_longitude(x), view.y_to_latitude(y)
243
 
 
244
 
        self.ui.lat_entry.set_text(str(lat))
245
 
        self.ui.lon_entry.set_text(str(lon))
246
 
 
247
 
        self.update_qr_code('geo:{0},{1}'.format(str(lon), str(lat)))
248
 
 
249
 
        return True
 
136
    def init_about_dialog(self):
 
137
        # Initialize about dialog
 
138
        about = Gtk.AboutDialog()
 
139
        about.set_program_name("Qreator")
 
140
        about.set_copyright(
 
141
            "Copyright (c) 2012 David Planella" +
 
142
            "\nhttp://about.me/david.planella")
 
143
        about.set_website("https://launchpad.net/qreator")
 
144
 
 
145
        about.set_version('12.05.6')
 
146
        about.set_authors([
 
147
            'David Planella <david.planella@ubuntu.com>',
 
148
            'Michael Hall <mhall119@ubuntu.com>',
 
149
            'Andrew Starr-Bochicchio <andrewsomething@ubuntu.com >',
 
150
            ])
 
151
        about.set_license(_('Distributed under the GPL v3 license.') +
 
152
                '\nhttp://www.opensource.org/licenses/gpl-3.0.html')
 
153
 
 
154
        about.set_translator_credits(_("translator-credits"))
 
155
 
 
156
        box = self.ui.about_box
 
157
        about.vbox.reparent(box)
 
158
 
 
159
        # Get rid of the 'Close' button
 
160
        for button in about.action_area.get_children():
 
161
            if button.get_property('label') == 'gtk-close':
 
162
                button.destroy()
 
163
 
 
164
##########################################
250
165
 
251
166
    def on_toolbuttonNew_clicked(self, widget, data=None):
252
167
        '''Shows the home page'''
256
171
        '''Shows the history page'''
257
172
        pass  # self.ui.notebook1.set_current_page(PAGE_HISTORY)
258
173
 
259
 
    def on_toolbuttonSettings_clicked(self, widget, data=None):
260
 
        '''Shows the settings page'''
261
 
        pass  # self.ui.notebook1.set_current_page(PAGE_SETTINGS)
262
 
 
263
174
    def on_toolbuttonAbout_clicked(self, widget, data=None):
264
175
        '''Shows the about page'''
265
176
        self.ui.notebook1.set_current_page(PAGE_ABOUT)
266
177
 
267
 
    def _hide_children(self, widget):
268
 
        for child in widget.get_children():
269
 
            child.hide()
270
 
 
271
 
    def on_qr_url_clicked(self):
272
 
        self._hide_children(self.ui.qr_input)
273
 
        self.ui.qr_url.show_all()
274
 
 
275
 
    def on_qr_wifi_clicked(self):
276
 
        self._hide_children(self.ui.qr_input)
277
 
        self.ui.qr_wifi.show_all()
278
 
 
279
 
        ssids = get_ssids()
280
 
        for ssid in ssids:
281
 
            self.ui.comboboxtextSSID.append_text(ssid)
282
 
 
283
 
    def on_qr_softwarecenterapp_clicked(self):
284
 
        # We're now loading the UI for the Software Center app QR type
285
 
        self._hide_children(self.ui.qr_input)
286
 
        self.ui.qr_app.show_all()
287
 
        if not self.softwarecenter_apps_init:
288
 
            GLib.idle_add(self.init_softwarecenter_apps)
289
 
 
290
 
    def on_qr_text_clicked(self):
291
 
        # Initialize multi-line text entry
292
 
        textbuffer = self.ui.entryText.get_buffer()
293
 
        textbuffer.connect("changed", self.on_entryText_changed, None)
294
 
 
295
 
        self._hide_children(self.ui.qr_input)
296
 
        self.ui.qr_text.show_all()
297
 
 
298
 
    def on_qr_location_clicked(self):
299
 
        # We're now loading the UI for the location QR type
300
 
        self._hide_children(self.ui.qr_input)
301
 
        self.ui.qr_location.show_all()
302
 
 
303
 
        map_widget = GtkChamplain.Embed()
304
 
        map_widget.set_hexpand(True)
305
 
        map_widget.set_vexpand(True)
306
 
 
307
 
        map_grid = self.ui.qr_location
308
 
 
309
 
        map_grid.set_size_request(-1, 250)
310
 
        map_grid.attach(map_widget, 0, 0, 1, 1)
311
 
 
312
 
        self.map_view = map_widget.get_view()
313
 
        self.map_view.set_reactive(True)
314
 
        map_widget.connect('button-release-event',
315
 
                           self.on_map_widget_button_press_event,
316
 
                           self.map_view)
317
 
 
318
 
        # Get the current location, center the map on it, and initialize
319
 
        # other map features
320
 
        latitude, longitude = get_current_location()
321
 
        self.map_view.center_on(latitude, longitude)
322
 
        if latitude == 0 and longitude == 0:
323
 
            # In case something went wrong in getting the current location
324
 
            self.map_view.set_zoom_level(1)
325
 
        else:
326
 
            self.map_view.set_zoom_level(15)
327
 
        self.map_view.set_kinetic_mode(True)
328
 
 
329
 
        scale = Champlain.Scale()
330
 
        scale.connect_view(self.map_view)
331
 
        self.map_view.bin_layout_add(scale, Clutter.BinAlignment.START,
332
 
                                     Clutter.BinAlignment.END)
333
 
 
334
 
        self.ui.qr_location.show_all()
 
178
##########################################
335
179
 
336
180
    def on_qr_types_view_item_activated(self, widget, item):
337
181
        '''Loads the UI for the appropriate QR type'''
338
182
 
339
183
        model = widget.get_model()
340
 
        qr_callback = getattr(QreatorWindow, model[item][COL_CALLBACK])
341
 
 
342
 
        qr_callback(self)
 
184
        qr_id = model[item][COL_ID]
 
185
        self.qr_types[qr_id].widget.on_activated()
343
186
 
344
187
        self.ui.notebook1.set_current_page(PAGE_QR)
 
188
        self.ui.qr_input_notebook.set_current_page(qr_id)
 
189
 
 
190
##########################################
345
191
 
346
192
    def get_pixbuf_from_drawing_area(self):
347
193
        window = self.ui.qr_drawingarea.get_window()
354
200
        return Gdk.pixbuf_get_from_window(window, src_x, src_y,
355
201
                                          image_width, image_height)
356
202
 
 
203
##########################################
 
204
 
357
205
    def on_toolbuttonSave_clicked(self, widget, data=None):
358
206
        if not self.surface:
359
207
            return
391
239
        pixbuf = self.get_pixbuf_from_drawing_area()
392
240
        self.clipboard.set_image(pixbuf)
393
241
 
 
242
##########################################
 
243
 
394
244
    def update_qr_code(self, text):
395
245
        self.qr_code_placeholder = text
396
246
        self.ui.qr_drawingarea.queue_draw()
397
247
 
398
 
    def on_usc_apps_complete_changed(self, widget, data=None):
399
 
        self._check_style(widget)
400
 
        USC_APPS_BASE_URL = 'https://apps.ubuntu.com/cat/applications/'
401
 
        self.update_qr_code(USC_APPS_BASE_URL + widget.get_text())
402
 
 
403
 
    def on_entryURL_icon_press(self, widget, icon, mouse_button):
404
 
        self._clear_text_entry(widget, icon)
405
 
 
406
 
    def on_entryURL_changed(self, widget, data=None):
407
 
        self._check_style(widget)
408
 
        self.update_url_qr_code(www=widget.get_text())
409
 
 
410
 
    def on_comboboxtextProtocol_changed(self, widget, data=None):
411
 
        self.update_url_qr_code(protocol=widget.get_active_text())
412
 
 
413
 
    def update_url_qr_code(self, protocol=None, www=None):
414
 
        if not protocol:
415
 
            protocol = self.ui.comboboxtextProtocol.get_active_text()
416
 
        if not www:
417
 
            www = self.ui.entryURL.get_text()
418
 
 
419
 
        if not protocol or www == '':
420
 
            return
421
 
 
422
 
        self.update_qr_code(protocol + www)
423
 
 
424
 
    def update_wifi_qr_code(self, security=None, ssid=None, password=None):
425
 
        if not security:
426
 
            security = self.ui.comboboxtextSecurity.get_active_text()
427
 
        if not ssid:
428
 
            ssid = self.ui.entrySSID.get_text()
429
 
        if not password:
430
 
            password = self.ui.entryPassword.get_text()
431
 
 
432
 
        if not security or ssid == '' or password == '':
433
 
            return
434
 
 
435
 
        wifi_qr_code = 'WIFI:T:{0};S:{1};P:{2};;'.format(security, ssid,
436
 
                                                         password)
437
 
        self.update_qr_code(wifi_qr_code)
438
 
 
439
 
    def on_comboboxtextSecurity_changed(self, widget, data=None):
440
 
        self.update_wifi_qr_code(security=widget.get_active_text())
441
 
 
442
 
    def on_entrySSID_icon_press(self, widget, icon, mouse_button):
443
 
        self._clear_text_entry(widget, icon)
444
 
 
445
 
    def on_comboboxtextSSID_changed(self, widget, data=None):
446
 
        self._check_style(self.ui.entrySSID)
447
 
        self.update_wifi_qr_code(ssid=widget.get_active_text())
448
 
 
449
 
    def on_entryPassword_icon_press(self, widget, icon, mouse_button):
450
 
        self._clear_text_entry(widget, icon)
451
 
 
452
 
    def on_entryPassword_changed(self, widget, data=None):
453
 
        self._check_style(widget)
454
 
        self.update_wifi_qr_code(password=widget.get_text())
455
 
 
456
 
    def on_checkbutton1_clicked(self, widget):
457
 
        if widget.get_active():
458
 
            self.ui.entryPassword.set_visibility(True)
459
 
        else:
460
 
            self.ui.entryPassword.set_visibility(False)
461
 
 
462
248
    def get_centered_coordinates(self, drawing_area, surface):
463
249
 
464
250
        drawing_area_height = drawing_area.get_allocated_height()
524
310
 
525
311
            # Render the image
526
312
            ctx.paint()
527
 
 
528
 
    def get_softwarecenterapps(self):
529
 
        print 'Task STARTED!'
530
 
        db = softwarecenter.db.database.StoreDatabase()
531
 
        db._aptcache.open()
532
 
        db.open(use_axi=False, use_agent=False)
533
 
        apps = []
534
 
        for doc in db:
535
 
            app = db.get_application(doc)
536
 
            appdetails = app.get_details(db)
537
 
            appinfo = App(app.appname, app.pkgname, appdetails.icon)
538
 
            apps.append(appinfo)
539
 
        self.softwarecenterapps = apps
540
 
        return apps
541
 
 
542
 
    def on_get_softwarecenterapps(self, result):
543
 
        print 'Task FINISHED!'
544
 
        self.usc_apps_complete.add(self.softwarecenterapps)
545
 
 
546
 
 
547
 
def get_current_location():
548
 
    '''Gets the current location from geolocation via IP (only method
549
 
       currently supported)'''
550
 
    #import Geoclue
551
 
    #POS_PROVIDER = 'Ubuntu GeoIP'
552
 
    #location = Geoclue.DiscoverLocation()
553
 
    #location.init()
554
 
    #location.set_position_provider(POS_PROVIDER)
555
 
    #position = location.get_location_info()
556
 
 
557
 
    import dbus
558
 
    bus = dbus.SessionBus()
559
 
    geoclue = bus.get_object(
560
 
        'org.freedesktop.Geoclue.Providers.UbuntuGeoIP',
561
 
        '/org/freedesktop/Geoclue/Providers/UbuntuGeoIP')
562
 
    position_info = geoclue.GetPosition(
563
 
        dbus_interface='org.freedesktop.Geoclue.Position')
564
 
 
565
 
    position = {}
566
 
    position['timestamp'] = position_info[1]
567
 
    position['latitude'] = position_info[2]
568
 
    position['longitude'] = position_info[3]
569
 
    position['altitude'] = position_info[4]
570
 
 
571
 
    return position['latitude'], position['longitude']
572
 
 
573
 
 
574
 
def get_ssids():
575
 
    nmc = NMClient.Client.new()
576
 
    devs = nmc.get_devices()
577
 
 
578
 
    ssids = []
579
 
    for dev in devs:
580
 
        if dev.get_device_type() == NetworkManager.DeviceType.WIFI:
581
 
            for ap in dev.get_access_points():
582
 
                ssids.append(ap.get_ssid())
583
 
 
584
 
    return ssids
585
 
 
586
 
 
587
 
class App(object):
588
 
    def __init__(self, name, package, icon):
589
 
        self.name = name
590
 
        self.package = package
591
 
        self.icon = icon
592
 
 
593
 
 
594
 
class Complete(Gtk.Entry):
595
 
    '''a class to autocomplete'''
596
 
 
597
 
    def __init__(self, apps=None):
598
 
        Gtk.Entry.__init__(self)
599
 
        self.completion = Gtk.EntryCompletion()
600
 
        self.set_completion(self.completion)
601
 
        self.model = Gtk.ListStore(str, GdkPixbuf.Pixbuf, str)
602
 
        self.completion.set_model(self.model)
603
 
        self.completion_img = Gtk.CellRendererPixbuf()
604
 
        self.completion.pack_start(self.completion_img, True)
605
 
        self.completion.add_attribute(self.completion_img, "pixbuf", 1)
606
 
        self.completion.set_text_column(0)
607
 
        self.completion.set_popup_set_width(False)
608
 
        self.completion.set_inline_completion(True)
609
 
        self.icons = Gtk.IconTheme.get_default()
610
 
        self.icons.append_search_path("/usr/share/app-install/icons/")
611
 
 
612
 
        if apps:
613
 
            self.add(apps)
614
 
        else:
615
 
            # TRANSLATORS: this message appears for a few seconds on the
616
 
            # Software Center apps text entry until the app names to
617
 
            # suggest for autocompletion have been read from the Software
618
 
            # Center database
619
 
            self.set_placeholder_text(
620
 
                _('[Wait a few seconds to enable autocompletion...]'))
621
 
 
622
 
    def add(self, apps):
623
 
        for app in apps:
624
 
            self._remember(app)
625
 
        self.set_placeholder_text(
626
 
                _('[Type the name of an app]'))
627
 
 
628
 
    def _remember(self, app):
629
 
        '''Add a value to the list of strings to suggest'''
630
 
        try:
631
 
            icon = self.icons.load_icon(
632
 
                "{0}".format(app.icon),
633
 
                16, Gtk.IconLookupFlags.USE_BUILTIN)
634
 
        except:
635
 
            icon = self.icons.load_icon(
636
 
                "stock_not",
637
 
                16, Gtk.IconLookupFlags.USE_BUILTIN)
638
 
        self.model.append([app.package, icon, app.name])