-----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
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/reportbug-maint