Logo Search packages:      
Sourcecode: debian-bts-applet version File versions  Download package

view.py

# -*- coding: utf-8 -*-

"""
  debian-bts-applet - GNOME applet for monitoring Debian bugs
  Copyright (C) 2008  Chris Lamb <chris@chris-lamb.co.uk>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import gtk
import gtk.glade
import gobject
import gnomeapplet
import pango
import os
import sys
import cPickle as pickle

import BtsApplet

class View(object):
    DEFAULT_TEXT = _("Enter bug number or URL here..")

    def __init__(self, controller, applet, data_dir):
        self.controller = controller
        self.applet = applet
        self.xml = gtk.glade.XML(os.path.join(data_dir, 'debian-bts-applet.glade'))

        self.icon_filename = os.path.join(data_dir, 'debian-bts-applet.svg')
        self.icon = gtk.gdk.pixbuf_new_from_file_at_size(self.icon_filename, 32, 32)
        self.about_icon = gtk.gdk.pixbuf_new_from_file(self.icon_filename)
        self.applet_icon = None
        self.first_time = True

        self.reset_bug_entry()

        if self.applet:
            self['window_main'].set_decorated(False)
            self.applet.set_flags(gnomeapplet.EXPAND_MINOR)

            self.evbox = gtk.EventBox()
            self.evbox.connect("button-press-event", controller.on_applet_click)

            def update_icon_size(applet, size):
                # Remove existing icon
                if self.applet_icon is not None:
                    self.evbox.remove(self.applet_icon)

                # Transform size hint
                i = 1
                sizes = (24, 36, 48, 64, 80, 128)
                while i < len(sizes):
                    if size <= sizes[i]:
                        size = sizes[i - 1];
                        break
                    i += 1

                # Create new icon
                pb = gtk.gdk.pixbuf_new_from_file_at_size(self.icon_filename, size, size)
                self.applet_icon = gtk.image_new_from_pixbuf(pb)
                self.evbox.add(self.applet_icon)
                self.evbox.show_all()

            update_icon_size(applet, self.applet.get_size())
            applet.connect("change_size", update_icon_size)

            self.applet.add(self.evbox)
            self.applet.show_all()

            propxml = """
            <popup name="button3">
                <menuitem name="Show bugs" verb="show_bugs" pixtype="stock"
                    pixname="gtk-dialog-info" label="%(show_bugs)s"/>
                <menuitem name="Report bug" verb="report_bug" label="%(report_bug)s" pixtype="stock" pixname="gtk-network"/>
                <menuitem name="About" verb="show_about" _label="_About" pixtype="stock" pixname="gtk-about" />
            </popup>
            """ % {
                'show_bugs' : _("_Show Bugs"),
                'report_bug' : _("Re_port Bug..."),
            }

            self.applet.setup_menu(propxml, (
                ("show_bugs", self.controller.on_menuitem_show_bugs_activate),
                ("report_bug", self.controller.on_menuitem_report_bug_activate),
                ("show_about", self.controller.on_menuitem_about_activate),
            ))

    def __getitem__(self, key):
        return self.xml.get_widget(key)

    def do_notify(self, old, new, delta):
        old, new = [self._format_bug_data(data, prefer_empty=False) for data in (old, new)]

        cmd = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'notify')
        stdin, stdout = os.popen2(cmd, 'w', 0)
        for obj in old, new, delta, self.icon_filename:
            pickle.dump(obj, stdin)
        stdin.close()
        stdout.close()

    def do_open_webbrowser(self, bug_number=None):
        if bug_number is None:
            url = 'http://www.debian.org/Bugs/Reporting'
        else:
            url = 'http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%d' % bug_number

        BtsApplet.open_url(url)

    def _format_bug_data(self, data, prefer_empty=True):
        # Clean data
        for search, replace in (('<', '&lt;'), ('<', '&gt;')):
            for key in data.keys():
                try:
                    data[key] = data[key].replace(search, replace)
                except AttributeError:
                    pass

        # Rewrite 'pending' status due to confusion with 'pending' tag.
        if data['status'] == 'pending':
            data['status'] = 'open'

        # Strikethrough 'done' status
        if data['status'] == 'done':
            data['status'] = '<s>done</s>'

        # Highlight severities greater than 'normal'
        if data['severity'] in ('critical', 'grave', 'serious'):
            data['severity'] = '<b>%s</b>' % data['severity']

        # Display nicer message if empty summary
        if len(data['summary']) == 0:
            data['summary'] = '<i>(%s)</i>' % _("No summary")

        if not prefer_empty and len(data['tags']) == 0:
            data['tags'] = '<i>(%s)</i>' % _("empty")

        return data

    def setup_treeview(self, model):
        self['treeview_bugs'].set_model(model)

        def my_render(column, cell_renderer, tree_model, iter, format_func):
            data = {}
            for num, col in enumerate(BtsApplet.FIELDS):
                data[col] = tree_model.get_value(iter, num)
            cell_renderer.set_property('markup', format_func(data))

        def format_summary(data):
            # Special case error and updating messages
            if data['state'] == BtsApplet.ST_ERROR_DOWNLOADING:
                text = _("Error loading bug #%d.") % data['bug_number']
                return '<small><i><b>%s</b></i></small>' % text
            elif data['state'] < BtsApplet.ST_UPDATING:
                text = _("Loading bug #%d...") % data['bug_number']
                return '<small><i>%s</i></small>' % text

            data = self._format_bug_data(data)

            lines = range(3)
            lines[0] = '<big><b>%s</b></big> #%d' % (data['package'], data['bug_number'])

            # Strikethrough first line if bug is fixed
            if data['status'].find('done') >= 0:
                lines[0] = '<s>%s</s>' % lines[0]

            status_txt = {
                BtsApplet.ST_UPDATING: _("Updating..."),
                BtsApplet.ST_ERROR_UPDATING: _("Error when updating"),
            }.get(data['state'], None)
            if status_txt:
                lines[0] += ' <small>(%s)</small>' % status_txt

            lines[1] = '<span stretch="condensed">%s' % data['summary']
            lines[2] = ''
            for key, value in (
                (_("Status"), data['status']),
                (_("Tags"), data['tags']),
                (_("Severity"), data['severity']),
                ):
                if len(value) > 0:
                    lines[2] += '<i>%s:</i> %s   ' % (key, value)
            lines[2] += '</span>'

            return '\n'.join(lines)

        def render_icon(column, cell_renderer, tree_model, iter):
            cell_renderer.set_property('pixbuf', self.icon)
            cell_renderer.set_property('visible', True)

        # Setup column and renderer
        column = gtk.TreeViewColumn("Summary")
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
        column.set_expand(True)

        cell_renderer = gtk.CellRendererPixbuf()
        column.pack_start(cell_renderer, False)
        column.set_cell_data_func(cell_renderer, render_icon)

        cell_renderer = gtk.CellRendererText()
        cell_renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
        column.pack_start(cell_renderer, True)
        column.set_cell_data_func(cell_renderer, my_render, format_summary)

        self['treeview_bugs'].append_column(column)

    def do_about_show(self):
        about = gtk.AboutDialog()
        about.set_name("Debian BTS Applet")
        about.set_comments(_("GNOME applet for monitoring Debian bugs"))
        about.set_copyright("Copyright (C) 2008 Chris Lamb <chris@chris-lamb.co.uk>")
        about.set_license(file('/usr/share/common-licenses/GPL-3').read())
        about.set_logo(self.about_icon)

        about.run()
        about.destroy()

    def do_applet_toggle(self):
        if self['window_main'].flags() & gtk.VISIBLE:
            self.do_applet_hide()
        else:
            self.do_applet_show()

    def do_applet_hide(self):
        self['window_main'].hide()

    def do_applet_show(self):
        if self.first_time:
            self['window_main'].show()

        if self.applet:
            x, y = self.applet.window.get_origin()
            orient = self.applet.get_orient()

            if orient == gnomeapplet.ORIENT_DOWN:
                x += self.applet.allocation.x
                y += self.applet.allocation.y + self.applet.allocation.height
            elif orient == gnomeapplet.ORIENT_UP:
                x += self.applet.allocation.x
                y -= self.applet.allocation.y + self['window_main'].allocation.height
            elif orient == gnomeapplet.ORIENT_RIGHT:
                x += self.applet.allocation.x + self.applet.allocation.width
                y += self.applet.allocation.y
            elif orient == gnomeapplet.ORIENT_LEFT:
                x -= self.applet.allocation.x + self['window_main'].allocation.width
                y += self.applet.allocation.y

            if self.first_time:
                self.first_time = False
            else:
                self['window_main'].show()

            self['window_main'].move(x, y)

    def get_bug_string(self):
        return self['entry_bug_number'].get_text()

    def do_popup_menu_bugs(self, treeview, event):
        try:
            path, col, _, _ = treeview.get_path_at_pos(int(event.x), int(event.y))
            treeview.grab_focus()
            treeview.set_cursor(path, col, 0)
            self['menu_bugs'].popup(None, None, None, event.button, event.time)
        except TypeError:
            pass

    def get_selected_bug_iter(self):
        selection = self['treeview_bugs'].get_selection()
        _, iter = selection.get_selected()
        return iter

    def bug_number_focus_in(self):
        if self.get_bug_string() != self.DEFAULT_TEXT:
            return

        self['entry_bug_number'].set_text('')
        self['entry_bug_number'].set_alignment(0)
        self['entry_bug_number'].set_editable(True)
        self['entry_bug_number'].modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse('black'))

    def bug_number_focus_out(self):
        if self.get_bug_string() == '':
            self.reset_bug_entry()

    def reset_bug_entry(self, empty=False):
        if empty:
            self['entry_bug_number'].set_text('')
        else:
            self['entry_bug_number'].set_text(self.DEFAULT_TEXT)
            self['entry_bug_number'].set_alignment(0.5)
            self['entry_bug_number'].set_editable(False)
            self['entry_bug_number'].modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse('grey65'))

Generated by  Doxygen 1.6.0   Back to index