summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/Changelog1
-rw-r--r--plugins/exception.xml13
-rw-r--r--portato/gui/exception_handling.py30
-rw-r--r--portato/gui/templates/MailInfoWindow.glade202
-rw-r--r--portato/gui/utils.py23
-rw-r--r--portato/gui/windows/mailinfo.py86
-rw-r--r--portato/gui/windows/main.py3
-rw-r--r--portato/plugins/exception.py2
-rw-r--r--portato/plugins/new_version.py2
9 files changed, 335 insertions, 27 deletions
diff --git a/doc/Changelog b/doc/Changelog
index 3c95fe8..c477bd0 100644
--- a/doc/Changelog
+++ b/doc/Changelog
@@ -4,6 +4,7 @@ next:
- added shortcut for "Reload Portage"
- increased the maximum scrollback lines
- now only use external "shm" package
+- allow to send bug report directly per mail
- bug fixes
0.10:
diff --git a/plugins/exception.xml b/plugins/exception.xml
new file mode 100644
index 0000000..385e743
--- /dev/null
+++ b/plugins/exception.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<plugin xmlns="http://portato.sourceforge.net/plugin" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://portato.sourceforge.net/plugin http://portato.sourceforge.net/plugin.xsd">
+
+ <author>René 'Necoro' Neumann</author>
+ <name>Exception Thrower</name>
+
+ <import>portato.plugins.exception</import>
+
+ <menu>
+ <item call="throw">Throw exception</item>
+ </menu>
+
+</plugin>
diff --git a/portato/gui/exception_handling.py b/portato/gui/exception_handling.py
index 29cd4e6..eadf124 100644
--- a/portato/gui/exception_handling.py
+++ b/portato/gui/exception_handling.py
@@ -16,32 +16,12 @@ from __future__ import absolute_import, with_statement
import gtk, pango, gobject
import sys, traceback
-from threading import Thread
from StringIO import StringIO
from ..helper import debug, error
from .dialogs import file_chooser_dialog, io_ex_dialog
-
-# for the i18n
-from ..constants import LOCALE_DIR, APP
-import gettext
-
-class GtkThread (Thread):
- def run(self):
- # for some reason, I have to install this for each thread ...
- gettext.install(APP, LOCALE_DIR, unicode = True)
- try:
- Thread.run(self)
- except SystemExit:
- raise # let normal thread handle it
- except:
- type, val, tb = sys.exc_info()
- try:
- sys.excepthook(type, val, tb, thread = self.getName())
- except TypeError:
- raise type, val, tb # let normal thread handle it
- finally:
- del type, val, tb
+from .windows.mailinfo import MailInfoWindow
+from .utils import GtkThread
class UncaughtExceptionDialog(gtk.MessageDialog):
"""Original idea by Gustavo Carneiro - original code: http://www.daa.com.au/pipermail/pygtk/attachments/20030828/2d304204/gtkexcepthook.py."""
@@ -53,6 +33,7 @@ class UncaughtExceptionDialog(gtk.MessageDialog):
self.format_secondary_text(_("It probably isn't fatal, but should be reported to the developers nonetheless."))
self.add_button(_("Show Details"), 1)
+ self.add_button(_("Send..."), 3)
self.add_button(gtk.STOCK_SAVE_AS, 2)
self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
@@ -103,6 +84,11 @@ class UncaughtExceptionDialog(gtk.MessageDialog):
else:
debug("Nothing to save")
+ elif resp == 3:
+ debug("Send bug per mail")
+ self.destroy()
+ MailInfoWindow(None, self.text)
+ return
else:
break
self.destroy()
diff --git a/portato/gui/templates/MailInfoWindow.glade b/portato/gui/templates/MailInfoWindow.glade
new file mode 100644
index 0000000..743c81c
--- /dev/null
+++ b/portato/gui/templates/MailInfoWindow.glade
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.4 on Mon Jun 23 22:23:44 2008 -->
+<glade-interface>
+ <widget class="GtkWindow" id="MailInfoWindow">
+ <property name="title" translatable="yes">Send Bug Mail ...</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <property name="default_width">450</property>
+ <property name="default_height">230</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="skip_pager_hint">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTextView" id="commentEntry">
+ <property name="height_request">50</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Comments /
+what did you do to hit the bug?</property>
+ </widget>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="x_padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Name:</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Email address:</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="mailEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="nameEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;&lt;u&gt;Additional Information&lt;/u&gt;&lt;/b&gt;
+
+(all optional)</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <child>
+ <widget class="GtkButton" id="cancelBtn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="cb_cancel_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="sendBtn">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="cb_send_clicked"/>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="stock">gtk-ok</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Send</property>
+ <property name="use_underline">True</property>
+ <property name="single_line_mode">True</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">5</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/portato/gui/utils.py b/portato/gui/utils.py
index 0a2930b..6e04814 100644
--- a/portato/gui/utils.py
+++ b/portato/gui/utils.py
@@ -14,19 +14,38 @@ from __future__ import absolute_import, with_statement
# some stuff needed
import re
+import sys
import logging
+import gettext
from collections import defaultdict
-from threading import RLock
+from threading import Thread, RLock
from functools import wraps
# some backend things
from ..backend import flags, system, set_system
from ..helper import debug, info, set_log_level
-from ..constants import USE_CATAPULT
+from ..constants import USE_CATAPULT, APP, LOCALE_DIR
# parser
from ..config_parser import ConfigParser
+class GtkThread (Thread):
+ def run(self):
+ # for some reason, I have to install this for each thread ...
+ gettext.install(APP, LOCALE_DIR, unicode = True)
+ try:
+ Thread.run(self)
+ except SystemExit:
+ raise # let normal thread handle it
+ except:
+ type, val, tb = sys.exc_info()
+ try:
+ sys.excepthook(type, val, tb, thread = self.getName())
+ except TypeError:
+ raise type, val, tb # let normal thread handle it
+ finally:
+ del type, val, tb
+
class Config (ConfigParser):
def __init__ (self, cfgFile):
diff --git a/portato/gui/windows/mailinfo.py b/portato/gui/windows/mailinfo.py
new file mode 100644
index 0000000..8e476c6
--- /dev/null
+++ b/portato/gui/windows/mailinfo.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+#
+# File: portato/gui/windows/mailinfo.py
+# This file is part of the Portato-Project, a graphical portage-frontend.
+#
+# Copyright (C) 2008 René 'Necoro' Neumann
+# This is free software. You may redistribute copies of it under the terms of
+# the GNU General Public License version 2.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# Written by René 'Necoro' Neumann <necoro@necoro.net>
+
+from __future__ import absolute_import
+
+import smtplib
+import time
+
+from .basic import AbstractDialog
+from ..utils import GtkThread
+from ...helper import debug, info
+from ...constants import VERSION
+
+class MailInfoWindow (AbstractDialog):
+ TO = "bugs@portato.necoro.net"
+
+ def __init__ (self, parent, tb):
+
+ AbstractDialog.__init__(self, parent)
+
+ self.tb = tb
+ self.window.show_all()
+
+ def set_data (self):
+ name = self.tree.get_widget("nameEntry").get_text()
+ addr = self.tree.get_widget("mailEntry").get_text()
+
+ if not addr:
+ addr = self.TO
+
+ if name:
+ fro = "%s <%s>" % (name, addr)
+ else:
+ fro = addr
+
+ commentBuffer = self.tree.get_widget("commentEntry").get_buffer()
+ text = commentBuffer.get_text(*commentBuffer.get_bounds())
+
+ if text:
+ text += "\n\n===========\n"
+
+ text += self.tb
+
+ message = """From: %s
+To: %s
+Subject: %s
+%s""" % ( fro, self.TO, ("[Bug Report] Bug in Portato %s" % VERSION), text)
+
+ self.addr = addr
+ self.message = message
+
+ def send (self):
+ debug("Connecting to server")
+ server = smtplib.SMTP("mail.necoro.eu")
+ debug("Sending mail")
+ try:
+ try:
+ server.sendmail(self.addr, self.TO, self.message)
+ except smtplib.SMTPRecipientsRefused, e:
+ info(_("An error occurred while sending. I think we where greylisted. The error: %s") % e)
+ info(_("Wait 60 seconds and try again."))
+ time.sleep(60)
+ server.sendmail(self.addr, self.TO, self.message)
+ debug("Sent")
+ finally:
+ server.quit()
+
+ def cb_cancel_clicked (self, *args):
+
+ self.close()
+ return True
+
+ def cb_send_clicked (self, *args):
+ self.set_data()
+ GtkThread(target = self.send, name = "Mail Send Thread").start()
+ self.close()
+ return True
diff --git a/portato/gui/windows/main.py b/portato/gui/windows/main.py
index b675d17..8e5eafb 100644
--- a/portato/gui/windows/main.py
+++ b/portato/gui/windows/main.py
@@ -30,11 +30,10 @@ from ...constants import CONFIG_LOCATION, VERSION, APP_ICON, ICON_DIR
from ...backend.exceptions import PackageNotFoundException, BlockedException
# more GUI stuff
-from ..utils import Database, Config
+from ..utils import Database, Config, GtkThread
from ..queue import EmergeQueue
from ..session import SESSION_VERSION, SessionException, OldSessionException, NewSessionException
from ..wrapper import GtkTree, GtkConsole
-from ..exception_handling import GtkThread
from ..views import LogView, HighlightView, InstalledOnlyView
from ..dialogs import (blocked_dialog, changed_flags_dialog, io_ex_dialog,
nothing_found_dialog, queue_not_empty_dialog, remove_deps_dialog,
diff --git a/portato/plugins/exception.py b/portato/plugins/exception.py
new file mode 100644
index 0000000..64bdb77
--- /dev/null
+++ b/portato/plugins/exception.py
@@ -0,0 +1,2 @@
+def throw (*args, **kwargs):
+ raise Exception, "As requested, Sir!"
diff --git a/portato/plugins/new_version.py b/portato/plugins/new_version.py
index 462d67c..fe69292 100644
--- a/portato/plugins/new_version.py
+++ b/portato/plugins/new_version.py
@@ -7,7 +7,7 @@ import gobject
from portato.helper import debug, warning
from portato import get_listener
from portato.constants import VERSION, APP_ICON, APP
-from portato.gui.exception_handling import GtkThread
+from portato.gui.utils import GtkThread
def find_version (rev):
try: