-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Fri, 29 Aug 2008 21:52:17 +0200 Luca Bruno <[EMAIL PROTECTED]> wrote:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Hello, > in reply to the discussion: > http://lists.alioth.debian.org/pipermail/reportbug-maint/2008-August/000338.html > I've been working this day on a GTK+ UI for reportbug. > A first work is attached. I've completely rewritten the code of the previous > gnome-reportbug to use GtkAssistant and using a more OO approach. > To let gnome2 be imported correctly by reportbug you should apply this patch: > http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=497024 > Any hints? Can I continue with the work? > > Best regards, > Continued the work, as usual I've attached the .py file. It's almost complete for basic bug reporting. Please let me know what you think about. - -- http://syx.googlecode.com - Smalltalk YX http://lethalman.blogspot.com - Thoughts about computer technologies http://www.ammazzatecitutti.org - Ammazzateci tutti -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAki4iwYACgkQw9Qj+8Kak3H6/ACglHW9upxm4XcCha5yJwaNlqyV r2AAnj3P/qm64geCq886STjrfrBdo2NN =vCiy -----END PGP SIGNATURE-----
import gtk import sys from gtk import gdk import gobject import re gdk.threads_init () from Queue import Queue import threading from reportbug_ui_text import ewrite from reportbug_exceptions import NoPackage, NoBugs, NoNetwork, NoReport ISATTY = True # Utilities def highlight (s): return '<b>%s</b>' % s re_markup_free = re.compile ("<.*?>") def markup_free (s): return re_markup_free.sub ("", s) def create_scrollable (widget): scrolled = gtk.ScrolledWindow () scrolled.set_shadow_type (gtk.SHADOW_ETCHED_IN) scrolled.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled.add (widget) return scrolled # Application class ReportbugApplication (threading.Thread): def __init__ (self): threading.Thread.__init__ (self) self.queue = Queue () def run (self): gtk.main () def get_last_value (self): return self.queue.get () def put_next_value (self): self.queue.put (self.next_value) self.next_value = None def set_next_value (self, value): self.next_value = value @staticmethod def create_idle_callback (func, *args, **kwargs): def callback (): func (*args, **kwargs) return False return callback def run_once_in_main_thread (self, func, *args, **kwargs): gobject.idle_add (self.create_idle_callback (func, *args, **kwargs)) application = ReportbugApplication () # Syncronize "pipe" with reportbug class SyncError (RuntimeError): def __init__ (self, result): RuntimeError.__init__ () self.result = result # Pipe class ReportbugConnector (object): def execute_operation (self, *args, **kwargs): pass def sync_pre_operation (cls, *args, **kwargs): return args, kwargs # Assistant class Page (ReportbugConnector): next_page_num = 0 page_type = gtk.ASSISTANT_PAGE_CONTENT default_complete = False side_image = "/usr/share/pixmaps/debian-logo.png" def __init__ (self, assistant): self.assistant = assistant self.application = assistant.application self.widget = self.create_widget () self.widget.page = self self.widget.set_border_width (6) self.widget.show_all () self.page_num = Page.next_page_num Page.next_page_num += 1 def execute_operation (self, *args, **kwargs): self.switch () self.connect_signals () self.execute (*args, **kwargs) def connect_signals (self): pass def set_page_complete (self, complete): self.assistant.set_page_complete (self.widget, complete) def set_page_type (self, type): self.assistant.set_page_type (self.widget, type) def set_page_title (self, title): if title: self.assistant.set_page_title (self.widget, title) def switch (self): self.assistant.insert_page (self.widget, self.page_num) self.set_page_complete (self.default_complete) self.set_page_type (self.page_type) self.assistant.set_page_side_image (self.widget, gdk.pixbuf_new_from_file (self.side_image)) self.assistant.set_next_page (self) def is_valid (self, value): return bool (value) def validate (self, *args, **kwargs): value = self.get_value () if self.is_valid (value): self.assistant.application.set_next_value (value) self.set_page_complete (True) else: self.set_page_complete (False) class IntroPage (Page): page_type = gtk.ASSISTANT_PAGE_INTRO default_complete = True def create_widget (self): vbox = gtk.VBox () vbox.pack_start (gtk.Label ("ReportBUG")) return vbox class GetStringPage (Page): def create_widget (self): vbox = gtk.VBox (spacing=12) self.label = gtk.Label () self.label.set_line_wrap (True) self.entry = gtk.Entry () vbox.pack_start (self.label, expand=False) vbox.pack_start (self.entry) return vbox def connect_signals (self): self.entry.connect ('changed', self.validate) def get_value (self): return self.entry.get_text () def execute (self, prompt, options=None, title=None, force_prompt=False, default='', ui=None): self.label.set_text (prompt) self.set_page_title (title) class TreePage (Page): value_column = None def __init__ (self, *args, **kwargs): Page.__init__ (self, *args, **kwargs) self.selection = self.view.get_selection() def connect_signals (self): self.selection.connect ('changed', self.validate) def get_value (self): model, paths = self.selection.get_selected_rows () multiple = self.selection.get_mode () == gtk.SELECTION_MULTIPLE result = [] for path in paths: result.append (markup_free (model.get_value (model.get_iter (path), self.value_column))) if not result: return if not multiple: return result[0] return result class MenuPage (TreePage): value_column = 0 def create_widget (self): vbox = gtk.VBox (spacing=12) self.label = gtk.Label () vbox.pack_start (self.label) self.view = gtk.TreeView () scrolled = create_scrollable (self.view) vbox.pack_start (scrolled) vbox.show_all () return vbox def execute (self, par, options, prompt, default=None, title=None, any_ok=False, order=None, extras=None, multiple=False, empty_ok=False): self.label.set_text (par) self.model = gtk.ListStore (str, str) self.view.set_model (self.model) if multiple: self.selection.set_mode (gtk.SELECTION_MULTIPLE) self.view.append_column (gtk.TreeViewColumn ('Option', gtk.CellRendererText (), markup=0)) self.view.append_column (gtk.TreeViewColumn ('Description', gtk.CellRendererText (), text=1)) default_iter = None if isinstance (options, dict): for option, desc in options.iteritems (): iter = self.model.append ((highlight (option), desc)) if option == default: default_iter = iter else: for row in options: iter = self.model.append ((highlight (row[0]), row[1])) if row[0] == default: default_iter = iter if default_iter: self.selection.select_iter (default_iter) self.set_page_title (title) class HandleBTSQueryPage (TreePage): default_complete = True value_column = 0 def sync_pre_operation (self, package, bts, mirrors=None, http_proxy="", queryonly=False, screen=None, title="", archived='no', source=False, version=None): import debianbts sysinfo = debianbts.SYSTEMS[bts] root = sysinfo.get('btsroot') if not root: ewrite("%s bug tracking system has no web URL; bypassing query.\n", sysinfo['name']) return if isinstance(package, basestring): pkgname = package if source: pkgname += ' (source)' progress_label = 'Querying %s bug tracking system for reports on %s' % (debianbts.SYSTEMS[bts]['name'], pkgname) else: progress_label = 'Querying %s bug tracking system for reports %s' % (debianbts.SYSTEMS[bts]['name'], ' '.join([str(x) for x in package])) self.application.run_once_in_main_thread (self.assistant.set_progress_label, progress_label) self.application.run_once_in_main_thread (self.set_page_title, title) result = None try: (count, sectitle, hierarchy) = debianbts.get_reports( package, bts, mirrors=mirrors, version=version, http_proxy=http_proxy, archived=archived, source=source) if not count: ui.run_wrapper(nullfunc) if hierarchy == None: raise NoPackage else: raise NoBugs else: if count > 1: sectitle = '%d bug reports found' % (count,) else: sectitle = 'One bug report found' report = [] for category, bugs in hierarchy: buglist = [] for bug in bugs: # Skip the '#' bug = bug[1:] bits = re.split(r'[: ]', bug, 2) if len(bits) > 2: id, tag, info = bits info = info.strip() if not info: info = '(no subject)' else: id = '(no id)' tag = '(no tag)' info = bug buglist.append((id, tag, info, None)) report.append ((category, buglist)) return (report,), {'title': sectitle} except (IOError, NoNetwork): ui.run_wrapper(nullfunc) long_message('Unable to connect to %s BTS.', sysinfo['name'], title=title) except NoPackage: ui.run_wrapper(nullfunc) long_message('No record of this package found.', title=title) raise NoPackage if result and result < 0: raise NoReport raise SyncReturn (result) def create_widget (self): vbox = gtk.VBox (spacing=12) self.label = gtk.Label ("List of bugs. Select a bug to retrieve and submit more informations.") vbox.pack_start (self.label, expand=False) self.view = gtk.TreeView () scrolled = create_scrollable (self.view) vbox.pack_start (scrolled) return vbox def is_valid (self, value): return True def execute (self, buglist, title=None): self.model = gtk.TreeStore (str, str, str, str) self.view.set_model (self.model) self.view.append_column (gtk.TreeViewColumn ('#ID', gtk.CellRendererText (), text=0)) self.view.append_column (gtk.TreeViewColumn ('Tag', gtk.CellRendererText (), text=1)) self.view.append_column (gtk.TreeViewColumn ('Subject', gtk.CellRendererText (), text=2)) self.view.append_column (gtk.TreeViewColumn ('Date', gtk.CellRendererText (), text=3)) for category in buglist: iter = self.model.append (None, (None, None, category[0], None)) for bug in category[1]: self.model.append (iter, bug) self.set_page_title (title) class DisplayReportPage (Page): default_complete = True def create_widget (self): self.view = gtk.TextView () self.view.set_editable (False) scrolled = create_scrollable (self.view) return scrolled def execute (self, message, title=None): self.view.get_buffer().set_text (message) self.set_page_title (title) class ProgressPage (Page): page_type = gtk.ASSISTANT_PAGE_PROGRESS def pulse (self): self.progress.pulse () return True def create_widget (self): vbox = gtk.VBox (spacing=6) self.label = gtk.Label () self.progress = gtk.ProgressBar () self.progress.set_pulse_step (0.01) vbox.pack_start (self.label, expand=False) vbox.pack_start (self.progress, expand=False) gobject.timeout_add (10, self.pulse) return vbox def set_label (self, text): self.label.set_text (text) def reset_label (self): self.set_label ("This operation may take a while") class ReportbugAssistant (gtk.Assistant): def __init__ (self, application): gtk.Assistant.__init__ (self) self.set_title ('Reportbug') self.application = application self.showing_page = None self.requested_page = None self.progress_page = None self.set_forward_page_func (self.forward) self.connect_signals () self.setup_pages () def connect_signals (self): self.connect ('cancel', self.close) self.connect ('prepare', self.on_prepare) self.connect ('delete-event', self.close) def on_prepare (self, assistant, widget): # If the user goes back then forward, we must ensure the feedback value to reportbug must be sent # when the user clicks on "Forward" to the requested page by reportbug if self.showing_page and self.showing_page == self.requested_page and self.get_current_page () > self.showing_page.page_num: self.application.put_next_value () # Reportbug doesn't support going back, so make widgets insensitive self.showing_page.widget.set_sensitive (False) self.showing_page = widget.page # Some pages might have changed the label in the while if self.showing_page == self.progress_page: self.progress_page.reset_label () def close (self, *args): sys.exit (0) def forward (self, page_num): return page_num + 1 def set_next_page (self, page): self.requested_page = page if self.get_current_page () == Page.next_page_num: self.set_current_page (page.page_num) def set_progress_label (self, text, *args, **kwargs): self.progress_page.set_label (text % args) def setup_pages (self): # We insert pages between the intro and the progress, so that we give the user the feedback # that the applications is still running when he presses the "Forward" button self.showing_page = IntroPage (self) self.progress_page = ProgressPage (self) Page.next_page_num = 1 self.showing_page.switch () self.progress_page.switch () self.set_current_page (0) assistant = ReportbugAssistant (application) assistant.show_all () # Dialogs class YesNoDialog (ReportbugConnector, gtk.MessageDialog): def __init__ (self, application): self.application = application gtk.MessageDialog.__init__ (self, assistant, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO) self.connect ('response', self.on_response) def on_response (self, dialog, res): self.application.set_next_value (res == gtk.RESPONSE_YES) self.application.put_next_value () self.destroy () def execute_operation (self, msg, yeshelp, nohelp, default=True, nowrap=False, ui=None): self.set_markup (msg+"?") self.show_all () log_message = assistant.set_progress_label display_failure = ewrite pages = { 'get_string': GetStringPage, 'menu': MenuPage, 'handle_bts_query': HandleBTSQueryPage, 'display_report': DisplayReportPage } dialogs = {'yes_no': YesNoDialog} # Begin the circle application.start () def create_forwarder (parent, klass): def func (*args, **kwargs): op = klass (parent) try: args, kwargs = op.sync_pre_operation (*args, **kwargs) except SyncError, e: return e.result application.run_once_in_main_thread (op.execute_operation, *args, **kwargs) return application.get_last_value () return func def forward_operations (parent, operations): for operation, klass in operations.iteritems (): globals()[operation] = create_forwarder (parent, klass) forward_operations (assistant, pages) forward_operations (application, dialogs)
_______________________________________________ Reportbug-maint mailing list Reportbug-maint@lists.alioth.debian.org http://lists.alioth.debian.org/mailman/listinfo/reportbug-maint