summaryrefslogtreecommitdiff
path: root/portato/gui/windows
diff options
context:
space:
mode:
Diffstat (limited to 'portato/gui/windows')
-rw-r--r--portato/gui/windows/__init__.py2
-rw-r--r--portato/gui/windows/about.py15
-rw-r--r--portato/gui/windows/basic.py5
-rw-r--r--portato/gui/windows/mailinfo.py139
-rw-r--r--portato/gui/windows/main.py86
-rw-r--r--portato/gui/windows/pkglist.py2
-rw-r--r--portato/gui/windows/plugin.py2
-rw-r--r--portato/gui/windows/preference.py2
-rw-r--r--portato/gui/windows/search.py2
-rw-r--r--portato/gui/windows/splash.py2
10 files changed, 203 insertions, 54 deletions
diff --git a/portato/gui/windows/__init__.py b/portato/gui/windows/__init__.py
index 6a4ac82..5be95ce 100644
--- a/portato/gui/windows/__init__.py
+++ b/portato/gui/windows/__init__.py
@@ -3,7 +3,7 @@
# File: portato/gui/gtk/__init__.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.
diff --git a/portato/gui/windows/about.py b/portato/gui/windows/about.py
index 6c6fec5..0d2ce1a 100644
--- a/portato/gui/windows/about.py
+++ b/portato/gui/windows/about.py
@@ -3,19 +3,20 @@
# File: portato/gui/windows/about.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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
+from __future__ import absolute_import, with_statement
+import os
import gtk
from .basic import AbstractDialog
-from ...constants import VERSION, REVISION, APP_ICON
+from ...constants import VERSION, REVISION, DATA_DIR
class AboutWindow (AbstractDialog):
"""A window showing the "about"-informations."""
@@ -24,11 +25,11 @@ class AboutWindow (AbstractDialog):
AbstractDialog.__init__(self, parent)
- img = gtk.Image()
- img.set_from_file(APP_ICON)
-
self.window.set_version(VERSION)
- self.window.set_logo(img.get_pixbuf())
+ self.window.set_logo(None)
+
+ with open(os.path.join(DATA_DIR, "TRANSLATORS")) as f:
+ self.window.set_translator_credits("".join(f.readlines()))
if REVISION:
gitlabel = self.tree.get_widget("gitLabel")
diff --git a/portato/gui/windows/basic.py b/portato/gui/windows/basic.py
index 20d8009..01d31e5 100644
--- a/portato/gui/windows/basic.py
+++ b/portato/gui/windows/basic.py
@@ -3,7 +3,7 @@
# File: portato/gui/windows/basic.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.
@@ -151,6 +151,9 @@ class AbstractDialog (Window):
self.window.set_transient_for(parent)
self.parent = parent
+ # type hint
+ self.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+
# catch the ESC-key
self.window.connect("key-press-event", self.cb_key_pressed)
diff --git a/portato/gui/windows/mailinfo.py b/portato/gui/windows/mailinfo.py
index 0cc79f2..4367482 100644
--- a/portato/gui/windows/mailinfo.py
+++ b/portato/gui/windows/mailinfo.py
@@ -3,7 +3,7 @@
# File: portato/gui/windows/mailinfo.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.
@@ -14,34 +14,98 @@ from __future__ import absolute_import, with_statement
import smtplib, socket
import time
+import gtk, pango, gobject
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
+from os.path import basename
from .basic import AbstractDialog
from ..utils import GtkThread
-from ..dialogs import mail_failure_dialog
+from .. import dialogs
from ...helper import debug, info
-from ...constants import VERSION
+from ...constants import VERSION, CONFIG_LOCATION
from ...log import LOGFILE
+from ... import session
+
+def mail_failure_dialog(*a):
+ dialogs.mail_failure_dialog(*a)
+ return False
+
+class ShowDialog (gtk.Dialog):
+
+ def __init__(self, parent, f):
+ gtk.Dialog.__init__(self, f, parent, buttons = (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+
+ textview = gtk.TextView()
+ textview.set_editable(False)
+ textview.modify_font(pango.FontDescription("Monospace"))
+ textview.set_size_request(gtk.gdk.screen_width()/2, gtk.gdk.screen_height()/3)
+
+ sw = gtk.ScrolledWindow();
+ sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ sw.add(textview)
+
+ self.vbox.add(sw)
+
+ textbuffer = textview.get_buffer()
+
+ with open(f) as text:
+ textbuffer.set_text(text.read())
+
+ self.vbox.show_all()
class MailInfoWindow (AbstractDialog):
- TO = "bugs@portato.necoro.net"
+ TO = "bugs@necoro.eu"
def __init__ (self, parent, tb):
AbstractDialog.__init__(self, parent)
+
+ self.files = [LOGFILE, CONFIG_LOCATION] + [s._file for s in session.sessionlist]
+ self.fileList = self.tree.get_widget("fileList")
+ self.build_file_list()
+ self.mailEntry = self.tree.get_widget("mailEntry")
self.tb = tb
self.window.show_all()
+ def build_file_list(self):
+ store = gtk.ListStore(bool, str)
+
+ for f in self.files:
+ store.append((True, f))
+
+ self.fileList.set_model(store)
+ cell = gtk.CellRendererText()
+ tCell = gtk.CellRendererToggle()
+ tCell.set_property("activatable", True)
+ tCell.connect("toggled", self.cb_file_toggled)
+
+ self.fileList.append_column(gtk.TreeViewColumn(None, tCell, active = 0))
+ self.fileList.append_column(gtk.TreeViewColumn(None, cell, text = 1))
+
+ def cb_file_toggled(self, cell, path):
+ store = self.fileList.get_model()
+ store[path][0] = not store[path][0]
+ return True
+
+ def cb_file_clicked(self, view, path, *args):
+ store = view.get_model()
+ f = store[path][1]
+
+ dialog = ShowDialog(self.window, f)
+ dialog.run()
+ dialog.destroy()
+
def set_data (self):
self.message = MIMEMultipart()
self.message["Subject"] = "[Bug Report] Bug in Portato %s" % VERSION
self.message["To"] = self.TO
+ self.message["X-Portato-Version"] = VERSION
# TO and FROM
name = self.tree.get_widget("nameEntry").get_text()
- self.addr = self.tree.get_widget("mailEntry").get_text()
+ self.addr = self.mailEntry.get_text()
if not self.addr:
self.addr = self.TO
@@ -63,40 +127,61 @@ class MailInfoWindow (AbstractDialog):
txtmsg = MIMEText(text, "plain", "utf-8")
self.message.attach(txtmsg)
- # log
- if self.tree.get_widget("logCheck").get_active():
- with open(LOGFILE, "r") as f:
- log = MIMEText(f.read(), "plain", "utf-8")
- log.add_header('Content-Disposition', 'attachment', filename='portato.log')
+ # logs
+ for (active, f) in self.fileList.get_model():
+ if active:
+ debug("Attaching '%s'", f)
+ with open(f, "r") as text:
+ log = MIMEText(text.read(), "plain", "utf-8")
+ log.add_header('Content-Disposition', 'attachment', filename=basename(f))
- self.message.attach(log)
+ self.message.attach(log)
def send (self):
try:
- debug("Connecting to server")
- server = smtplib.SMTP("mail.necoro.eu")
- debug("Sending mail")
- try:
+ for i in range(5): # try 5 times at max
+ if i > 0:
+ info(_("Retrying after waiting %d seconds."), 300)
+ time.sleep(300)
try:
+ debug("Connecting to server")
+ server = smtplib.SMTP("mail.necoro.eu")
+ debug("Sending mail")
+
+ if smtplib._have_ssl: server.starttls()
+ else: debug("TLS not supported in Python. Continuing without it.")
+
server.sendmail(self.addr, self.TO, self.message.as_string())
except smtplib.SMTPRecipientsRefused, e:
- info(_("An error occurred while sending. I think we were greylisted. The error: %s") % e)
- info(_("Retrying after waiting 60 seconds."))
- time.sleep(60)
- server.sendmail(self.addr, self.TO, self.message.as_string())
- debug("Sent")
- finally:
- server.quit()
+ if e.recipients[self.TO][0] < 500:
+ info(_("An error occurred while sending. I think we were greylisted. The error: %s") % e)
+ else: raise
+ else:
+ debug("Sent")
+ break
+ finally:
+ try:
+ server.quit()
+ except smtplib.SMTPServerDisconnected:
+ pass # ignore this
except socket.error, e:
- mail_failure_dialog("%s (Code: %s)" % (e.args[1], e.args[0]))
+ gobject.idle_add(mail_failure_dialog, "%s (Code: %s)" % (e.args[1], e.args[0]))
+ except smtplib.SMTPResponseException, e:
+ gobject.idle_add(mail_failure_dialog, "%s (Code: %s)" % (e.smtp_error, e.smtp_code))
+ except smtplib.SMTPException, e:
+ gobject.idle_add(mail_failure_dialog, e.args)
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()
+ if self.mailEntry.get_text() or dialogs.no_email_dialog(self.window) == gtk.RESPONSE_OK:
+ self.set_data()
+ GtkThread(target = self.send, name = "Mail Send Thread").start()
+ self.close()
+ else:
+ self.window.present()
+ self.mailEntry.grab_focus()
+
return True
diff --git a/portato/gui/windows/main.py b/portato/gui/windows/main.py
index ca88b04..3c868e8 100644
--- a/portato/gui/windows/main.py
+++ b/portato/gui/windows/main.py
@@ -3,7 +3,7 @@
# File: portato/gui/windows/main.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.
@@ -29,7 +29,8 @@ from ... import get_listener
from ...helper import debug, warning, error, info
from ...session import Session
from ...db import Database
-from ...constants import CONFIG_LOCATION, VERSION, APP_ICON
+from ...db.database import UnsupportedSearchTypeError
+from ...constants import CONFIG_LOCATION, VERSION, APP_ICON, ICON_DIR
from ...backend.exceptions import PackageNotFoundException, BlockedException, VersionsNotFoundException
# plugin stuff
@@ -434,18 +435,27 @@ class MainWindow (Window):
self.window.set_geometry_hints (self.window, max_height = gtk.gdk.screen_height(), max_width = gtk.gdk.screen_width())
# app icon
- self.window.set_icon_from_file(APP_ICON)
- gtk.window_set_default_icon(self.window.get_icon())
+ gtk.window_set_default_icon_from_file(APP_ICON)
# booleans
self.doUpdate = False
self.showAll = True # show only installed or all packages?
self.__searchChanged = False
+ # our own icon factory
+ fac = gtk.IconFactory()
+ iSet = gtk.IconSet()
+ iSource = gtk.IconSource()
+ iSource.set_filename(os.path.abspath(os.path.join(ICON_DIR, "better-package.svg")))
+ iSet.add_source(iSource)
+ fac.add("portato-better-pkg", iSet)
+ fac.add_default()
+
# icons
self.icons = {}
self.icons["installed"] = self.window.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
self.icons["or"] = self.window.render_icon(gtk.STOCK_MEDIA_PAUSE, gtk.ICON_SIZE_MENU)
+ self.icons["better"] = self.window.render_icon("portato-better-pkg", gtk.ICON_SIZE_MENU)
# get the logging window as soon as possible
self.logView = LogView(self.tree.get_widget("logView"))
@@ -556,6 +566,10 @@ class MainWindow (Window):
splash(_("Finishing startup"))
+ # depends on session
+ self.typeCombo = self.tree.get_widget("typeCombo")
+ self.build_type_combo()
+
self.window.show_all()
def show_package (self, pkg = None, cpv = None, cp = None, version = None, **kwargs):
@@ -782,10 +796,14 @@ class MainWindow (Window):
if not packages:
raise VersionsNotFoundException(cp)
+ best = system.find_best_match(cp)
+
# append versions
for vers, inst, slot in ((x.get_version(), x.is_installed(), get_slot(x)) for x in packages):
if inst:
icon = self.icons["installed"]
+ elif best is not None and vers == best.get_version():
+ icon = self.icons["better"]
else:
icon = None
@@ -871,6 +889,26 @@ class MainWindow (Window):
else: # no selCatName -> so no category selected --> ignore
debug("No category selected --> should be no harm.")
+ def build_type_combo (self):
+ model = gtk.ListStore(int, str)
+ for k,v in self.db.TYPES.iteritems():
+ model.append((k,v))
+
+ self.typeCombo.set_model(model)
+ cell = gtk.CellRendererText()
+ self.typeCombo.pack_start(cell)
+ self.typeCombo.set_attributes(cell, text = 1)
+
+
+ for i, (k, v) in enumerate(model):
+ if k == self.db.type: break
+
+ self.typeCombo.set_active(i)
+
+ types = self.db.search_types()
+ if types == 1 or types % 2 == 0:
+ self.typeCombo.set_sensitive(False)
+
def load_session(self, sessionEx = None, defaults_only = False):
"""
Loads the session data.
@@ -987,6 +1025,14 @@ class MainWindow (Window):
return _save
+ # SEARCH TYPE
+ def load_search_type (t):
+ t = int(t)
+ try:
+ self.db.type = t
+ except UnsupportedSearchTypeError:
+ info("Cannot set search type. '%s' not supported by database '%s'.", t, self.db.__class__.__name__)
+
# SESSION VERSION
def load_session_version (version):
@@ -1015,7 +1061,8 @@ class MainWindow (Window):
(["width", "height"], lambda w,h: self.window.resize(int(w), int(h)), self.window.get_size),
(["vpanedpos", "hpanedpos"], load_paned, save_paned),
(["catsel"], load_cat_selection, save_cat_selection, ["app-portage@0"]),
- (["pkgsel"], load_pkg_selection, save_pkg_selection, ["portato@0"])
+ (["pkgsel"], load_pkg_selection, save_pkg_selection, ["portato@0"]),
+ (["searchtype"], load_search_type, lambda: self.db.type)
#([("merge", "queue"), ("unmerge", "queue"), ("oneshot", "queue")], load_queue, save_queue),
])
@@ -1023,7 +1070,7 @@ class MainWindow (Window):
queue = plugin.get_plugin_queue()
if queue:
for p in queue.get_plugins():
- self.session.add_handler(([(p.name.replace(" ","_"), "plugins")], load_plugin(p), save_plugin(p)))
+ self.session.add_handler(([(p.name.replace(" ","_").replace(":","_"), "plugins")], load_plugin(p), save_plugin(p)))
# the other things
def load_cfg ((name, cat)):
@@ -1387,8 +1434,8 @@ class MainWindow (Window):
"""Execute the current queue."""
if len(flags.newUseFlags) > 0:
- if not self.session.get_boolean("useflags", "dialogs"):
- self.session.set("useflags", dialogs.changed_flags_dialog(_("use flags"))[1], "dialogs")
+ if not self.session.get_bool("useflags", "dialogs"):
+ self.session.set("useflags", str(dialogs.changed_flags_dialog(_("use flags"))[1]), "dialogs")
try:
flags.write_use_flags()
except IOError, e:
@@ -1399,8 +1446,8 @@ class MainWindow (Window):
debug("new masked: %s",flags.new_masked)
debug("new unmasked: %s", flags.new_unmasked)
debug("new testing: %s", flags.newTesting)
- if not self.session.get_boolean("keywords", "dialogs"):
- self.session.set("keywords", dialogs.changed_flags_dialog(_("masking keywords"))[1], "dialogs")
+ if not self.session.get_bool("keywords", "dialogs"):
+ self.session.set("keywords", str(dialogs.changed_flags_dialog(_("masking keywords"))[1]), "dialogs")
try:
flags.write_masked()
flags.write_testing()
@@ -1464,8 +1511,15 @@ class MainWindow (Window):
gobject.idle_add(cb_idle_append, updating)
finally:
self.window.window.set_cursor(None)
-
- GtkThread(name="Update-Thread", target=__update).start()
+
+ # for some reason, I have to create the thread before displaying the dialog
+ # else the GUI hangs
+ t = GtkThread(name="Update-Thread", target=__update)
+
+ if not self.session.get_bool("update_world_warning", "dialogs"):
+ self.session.set("update_world_warning", str(dialogs.update_world_warning_dialog()[1]), "dialogs")
+
+ t.start()
return True
@@ -1562,7 +1616,13 @@ class MainWindow (Window):
return False # not again ;)
- gobject.timeout_add(100, __update)
+ gobject.timeout_add(200, __update)
+
+ def cb_type_combo_changed (self, *args):
+ model = self.typeCombo.get_model()
+ active = self.typeCombo.get_active()
+
+ self.db.type = model[active][0]
def cb_delete_search_clicked (self, *args):
self.searchEntry.set_text("")
diff --git a/portato/gui/windows/pkglist.py b/portato/gui/windows/pkglist.py
index 90915cb..df3ef46 100644
--- a/portato/gui/windows/pkglist.py
+++ b/portato/gui/windows/pkglist.py
@@ -3,7 +3,7 @@
# File: portato/gui/windows/pkglist.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.
diff --git a/portato/gui/windows/plugin.py b/portato/gui/windows/plugin.py
index 755ad58..89d38f5 100644
--- a/portato/gui/windows/plugin.py
+++ b/portato/gui/windows/plugin.py
@@ -3,7 +3,7 @@
# File: portato/gui/windows/plugin.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.
diff --git a/portato/gui/windows/preference.py b/portato/gui/windows/preference.py
index 4bd7551..021788c 100644
--- a/portato/gui/windows/preference.py
+++ b/portato/gui/windows/preference.py
@@ -3,7 +3,7 @@
# File: portato/gui/windows/preference.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.
diff --git a/portato/gui/windows/search.py b/portato/gui/windows/search.py
index c531507..f9191d7 100644
--- a/portato/gui/windows/search.py
+++ b/portato/gui/windows/search.py
@@ -3,7 +3,7 @@
# File: portato/gui/windows/search.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.
diff --git a/portato/gui/windows/splash.py b/portato/gui/windows/splash.py
index c9e1542..2e9d5a8 100644
--- a/portato/gui/windows/splash.py
+++ b/portato/gui/windows/splash.py
@@ -3,7 +3,7 @@
# File: portato/gui/windows/splash.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
-# Copyright (C) 2006-2009 René 'Necoro' Neumann
+# Copyright (C) 2006-2010 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.