~mmcg069/software-center/bug855666

« back to all changes in this revision

Viewing changes to softwarecenter/view/viewswitcher.py

merged (and fixed conflicts) from  lp:~gary-lasker/software-center/sourcesview  

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 
32
32
from gettext import gettext as _
33
33
 
 
34
 
34
35
from softwarecenter.backend import get_install_backend
 
36
from softwarecenter.db.database import StoreDatabase
 
37
from softwarecenter.enums import *
 
38
 
35
39
from widgets.animatedimage import CellRendererAnimatedImage, AnimatedImage
36
40
 
37
41
class ViewSwitcher(gtk.TreeView):
39
43
    __gsignals__ = {
40
44
        "view-changed" : (gobject.SIGNAL_RUN_LAST,
41
45
                          gobject.TYPE_NONE, 
42
 
                          (int, ),
 
46
                          (int, str),
43
47
                         ),
44
48
    }
45
49
 
46
50
 
47
 
    def __init__(self, datadir, icons, store=None):
 
51
    def __init__(self, datadir, db, icons, store=None):
48
52
        super(ViewSwitcher, self).__init__()
49
53
        self.datadir = datadir
50
54
        self.icons = icons
51
55
        if not store:
52
 
            store = ViewSwitcherList(datadir, icons)
 
56
            store = ViewSwitcherList(datadir, db, icons)
53
57
            # FIXME: this is just set here for app.py, make the
54
58
            #        transactions-changed signal part of the view api
55
59
            #        instead of the model
96
100
        (path, column) = self.get_cursor()
97
101
        model = self.get_model()
98
102
        action = model[path][ViewSwitcherList.COL_ACTION]
99
 
        self.emit("view-changed", action) 
 
103
        channel_name = model[path][ViewSwitcherList.COL_CHANNEL_NAME]
 
104
        self.emit("view-changed", action, channel_name)
100
105
        
101
106
    def get_view(self):
102
107
        """return the current activated view number or None if no
104
109
           disappeared). Views are:
105
110
           
106
111
           ViewSwitcherList.ACTION_ITEM_AVAILABLE
 
112
           ViewSwitcherList.ACTION_ITEM_CHANNEL
107
113
           ViewSwitcherList.ACTION_ITEM_INSTALLED
108
114
           ViewSwitcherList.ACTION_ITEM_PENDING
109
115
        """
113
119
        return path[0]
114
120
    def set_view(self, action):
115
121
        self.set_cursor((action,))
116
 
        self.emit("view-changed", action)
 
122
        self.emit("view-changed", action, None)
117
123
    def on_motion_notify_event(self, widget, event):
118
124
        #print "on_motion_notify_event: ", event
119
125
        path = self.get_path_at_pos(int(event.x), int(event.y))
127
133
    # columns
128
134
    (COL_ICON,
129
135
     COL_NAME,
130
 
     COL_ACTION) = range(3)
 
136
     COL_ACTION,
 
137
     COL_CHANNEL_NAME) = range(4)
131
138
 
132
139
    # items in the treeview
133
140
    (ACTION_ITEM_AVAILABLE,
134
141
     ACTION_ITEM_INSTALLED,
135
142
     ACTION_ITEM_SEPARATOR_1,
136
 
     ACTION_ITEM_PENDING) = range(4)
 
143
     ACTION_ITEM_PENDING,
 
144
     ACTION_ITEM_CHANNEL) = range(5)
137
145
 
138
146
    ICON_SIZE = 24
139
147
 
140
148
    ANIMATION_PATH = "/usr/share/icons/hicolor/24x24/status/softwarecenter-progress.png"
141
149
 
142
 
    def __init__(self, datadir, icons):
143
 
        gtk.TreeStore.__init__(self, AnimatedImage, str, int)
 
150
    def __init__(self, datadir, db, icons):
 
151
        gtk.TreeStore.__init__(self, AnimatedImage, str, int, str)
144
152
        self.icons = icons
145
153
        self.datadir = datadir
146
154
        self.backend = get_install_backend()
147
155
        self.backend.connect("transactions-changed", self.on_transactions_changed)
 
156
        self.db = db
 
157
        # pending transactions
 
158
        self._pending = 0
148
159
        # setup the normal stuff
149
 
        if self.icons.lookup_icon("softwarecenter", self.ICON_SIZE, 0):
150
 
            icon = AnimatedImage(self.icons.load_icon("softwarecenter", self.ICON_SIZE, 0))
151
 
        else:
152
 
            icon = AnimatedImage(self.icons.load_icon("gtk-missing-image", 
153
 
                                                      self.ICON_SIZE, 0))
154
 
        piter = self.append(None, [icon, _("Get Software"), self.ACTION_ITEM_AVAILABLE])
155
 
        
156
 
        if self.icons.lookup_icon("distributor-logo", self.ICON_SIZE, 0):
157
 
            icon = AnimatedImage(self.icons.load_icon("distributor-logo", self.ICON_SIZE, 0))
158
 
        else:
159
 
            # icon not present in theme, probably because running uninstalled
160
 
            icon = AnimatedImage(self.icons.load_icon("gtk-missing-image", 
161
 
                                                      self.ICON_SIZE, 0))
162
 
        self.append(piter, [icon, _("Free Software"), self.ACTION_ITEM_AVAILABLE])
 
160
        available_icon = self._get_icon("softwarecenter")
 
161
        available_iter = self.append(None, [available_icon, _("Get Software"), self.ACTION_ITEM_AVAILABLE, None])
 
162
        
 
163
        # gather icons for use with channel sources
 
164
        self.dist_icon = self._get_icon("distributor-logo")
 
165
        self.partner_icon = self._get_icon("partner")
 
166
        self.ppa_icon = self._get_icon("ppa")
 
167
        self.unknown_channel_icon = self._get_icon("unknown-channel")
 
168
        
 
169
        # get list of channel sources of form:
 
170
        #     [icon, label, action, channel_name]
 
171
        channel_sources = self._get_channel_sources()
 
172
        
 
173
        # iterate the channel sources list and add as subnodes of the available node
 
174
        for channel in channel_sources:
 
175
            self.append(available_iter, channel)
163
176
        
164
177
        icon = AnimatedImage(self.icons.load_icon("computer", self.ICON_SIZE, 0))
165
 
        self.append(None, [icon, _("Installed Software"), self.ACTION_ITEM_INSTALLED])
 
178
        installed_iter = self.append(None, [icon, _("Installed Software"), self.ACTION_ITEM_INSTALLED, ""])
166
179
        icon = AnimatedImage(None)
167
 
        self.append(None, [icon, "<span size='1'> </span>", self.ACTION_ITEM_SEPARATOR_1])
 
180
        self.append(None, [icon, "<span size='1'> </span>", self.ACTION_ITEM_SEPARATOR_1, ""])
 
181
        
 
182
        # iterate the channel sources list and add as subnodes of the installed node
 
183
        # TODO:  These lists must be filtered on installed only!
 
184
        for channel in channel_sources:
 
185
            self.append(installed_iter, channel)
168
186
 
169
187
    def on_transactions_changed(self, backend, total_transactions):
170
188
        logging.debug("on_transactions_changed '%s'" % total_transactions)
184
202
                if row[self.COL_ACTION] == self.ACTION_ITEM_PENDING:
185
203
                    del self[(i,)]
186
204
 
 
205
    def _get_icon(self, icon_name):
 
206
        if self.icons.lookup_icon(icon_name, self.ICON_SIZE, 0):
 
207
            icon = AnimatedImage(self.icons.load_icon(icon_name, self.ICON_SIZE, 0))
 
208
        else:
 
209
            # icon not present in theme, probably because running uninstalled
 
210
            icon = AnimatedImage(self.icons.load_icon("gtk-missing-image", 
 
211
                                                      self.ICON_SIZE, 0))
 
212
        return icon
 
213
        
 
214
    def _get_channel_sources(self):
 
215
        """
 
216
        return a list of channel sources, with each entry in the list
 
217
        in the form:
 
218
               [icon, label, action, channel_name]
 
219
        """        
 
220
        channels = []
 
221
        for channel_iter in self.db.xapiandb.allterms("XOL"):
 
222
            channel_name = channel_iter.term[3:]            
 
223
            print "channel_name: %s" % channel_name
 
224
            
 
225
            # get origin information for this channel
 
226
            m = self.db.xapiandb.postlist_begin(channel_iter.term)
 
227
            doc = self.db.xapiandb.get_document(m.get_docid())
 
228
            for term_iter in doc.termlist():
 
229
                if term_iter.term.startswith("XOO"): 
 
230
                    channel_origin = term_iter.term[3:]
 
231
                    print "channel_origin: %s" % channel_origin
 
232
                    break
 
233
            channels.append((channel_name, channel_origin))
 
234
            
 
235
        channel_sources = []
 
236
        for (channel_name, channel_origin) in self._order_channels(channels):
 
237
            channel_sources.append([self._get_icon_for_channel(channel_name, channel_origin), 
 
238
                                    self._get_display_name_for_channel(channel_name),
 
239
                                    self.ACTION_ITEM_CHANNEL,
 
240
                                    channel_name])     
 
241
                
 
242
        return channel_sources
 
243
        
 
244
    def _order_channels(self, channels):
 
245
        """
 
246
        given a list of channels, order them according to:
 
247
            Distribution, Partners, PPAs alphabetically, Other channels alphabetically,
 
248
            Unknown channel last
 
249
        """
 
250
        dist_channel = []
 
251
        partner_channel = []
 
252
        ppa_channels = []
 
253
        other_channels = []
 
254
        unknown_channel = []
 
255
        ordered_channels = []
 
256
        
 
257
        for (channel_name, channel_origin) in channels:
 
258
            if not channel_name:
 
259
                unknown_channel.append((channel_name, channel_origin))
 
260
            elif channel_name == "Ubuntu":
 
261
                dist_channel.append((channel_name, channel_origin))
 
262
            elif channel_origin and channel_origin.startswith("LP-PPA"):
 
263
                ppa_channels.append((channel_name, channel_origin))
 
264
            # TODO: detect partner channel
 
265
            else:
 
266
                other_channels.append((channel_name, channel_origin))
 
267
        
 
268
        # set them in order
 
269
        ordered_channels.extend(dist_channel)
 
270
        ordered_channels.extend(partner_channel)
 
271
        ordered_channels.extend(ppa_channels)
 
272
        ordered_channels.extend(other_channels)
 
273
        ordered_channels.extend(unknown_channel)
 
274
        
 
275
        return ordered_channels
 
276
        
 
277
    def _get_icon_for_channel(self, channel_name, channel_origin):
 
278
        """
 
279
        return the icon that corresponds to each channel node based
 
280
        on the channel name and its origin string
 
281
        """
 
282
        # TODO: detect PPA using the origin string (see above)
 
283
        if channel_name == "Ubuntu":
 
284
            channel_icon = self.dist_icon
 
285
        elif channel_origin.startswith("LP-PPA"):
 
286
            channel_icon = self.ppa_icon
 
287
        # TODO:  Add check for partner_icon
 
288
        elif channel_name == "Unknown":
 
289
            channel_icon = self.unknown_channel_icon
 
290
        else:
 
291
            channel_icon = self.unknown_channel_icon
 
292
        return channel_icon
 
293
        
 
294
    def _get_display_name_for_channel(self, channel_name):
 
295
        """
 
296
        return the display name for the corresponding channel node
 
297
        """
 
298
        if not channel_name:
 
299
            channel_display_name = "Unknown"
 
300
        elif channel_name == "Ubuntu":
 
301
            channel_display_name = _("Provided by Ubuntu")
 
302
        else:
 
303
            channel_display_name = channel_name
 
304
        return channel_display_name
 
305
 
187
306
if __name__ == "__main__":
188
307
    logging.basicConfig(level=logging.DEBUG)
189
308
    import sys
197
316
 
198
317
    scroll = gtk.ScrolledWindow()
199
318
    icons = gtk.icon_theme_get_default()
200
 
    view = ViewSwitcher(datadir, icons)
 
319
 
 
320
    xapian_base_path = XAPIAN_BASE_PATH
 
321
    pathname = os.path.join(xapian_base_path, "xapian")
 
322
    cache = apt.Cache(apt.progress.OpTextProgress())
 
323
    db = StoreDatabase(pathname, cache)
 
324
    db.open()
 
325
 
 
326
    view = ViewSwitcher(datadir, db, icons)
201
327
 
202
328
    box = gtk.VBox()
203
329
    box.pack_start(scroll)