summaryrefslogtreecommitdiff
path: root/portato/gui/windows/basic.py
blob: ecd34f122d23c296240110fd2ea1fdff7854a962 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# -*- coding: utf-8 -*-
#
# File: portato/gui/windows/basic.py
# This file is part of the Portato-Project, a graphical portage-frontend.
#
# 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>



# gtk stuff
import gtk
import gobject

from functools import wraps
import os.path

from ...constants import TEMPLATE_DIR, APP, LOCALE_DIR
from ...helper import error, debug

# for the GtkBuilder to translate correctly :)
import ctypes
from locale import CODESET
try:
    getlib = ctypes.cdll.LoadLibrary("libgettextlib.so")
except OSError:
    error("'libgettextlib.so' cannot be loaded. Might be, that there are no translations available in the GUI.")
else:
    getlib.textdomain(APP)
    getlib.bindtextdomain(APP, LOCALE_DIR)
    getlib.bind_textdomain_codeset(APP, "UTF-8")

    # some debugging output about the current codeset used
    nll = getlib.nl_langinfo
    nll.restype = ctypes.c_char_p
    debug("Switching from '%s' to 'UTF-8'.", nll(CODESET))

    getlib.bind_textdomain_codeset(APP, "UTF-8")

class WrappedTree (object):
    __slots__ = ("klass", "tree", "get_widget", "get_ui")
    def __init__ (self, klass, tree):
        self.tree = tree
        self.klass = klass

    def __getattribute__ (self, name):
        if name in WrappedTree.__slots__:
            return object.__getattribute__(self, name)
        else:
            return getattr(self.tree, name)

    def get_widget(self, name):
        w = self.tree.get_object(name)
        if w is None:
            error("Widget '%s' could not be found in class '%s'.", name, self.klass)
        return w

    def get_ui (self, name, ui = "uimanager"):
        uiw = self.get_widget(ui)
        if uiw is None:
            return None

        if not name.startswith("ui/"):
            name = "ui/%s" % name

        w = uiw.get_widget(name)
        if w is None:
            error("UIItem '%s' of UIManager '%s' could not be found in class '%s'.", name, ui, self.klass)
        return w

class Window (object):

    def __init__ (self, connector = None):
        if not hasattr(self, "__file__"):
            self.__file__ = self.__class__.__name__

        # general setup
        self._builder = gtk.Builder()
        self._builder.add_from_file(os.path.join(TEMPLATE_DIR, self.__file__+".ui"))
        self._builder.set_translation_domain(APP)
        
        self.tree = WrappedTree(self.__class__.__name__, self._builder)

        if not hasattr(self, "__window__"):
            self.__window__ = self.__class__.__name__

        self.window = self.tree.get_widget(self.__window__)

        # load menu if existing
        menufile = os.path.join(TEMPLATE_DIR, self.__file__+".menu")
        if os.path.exists(menufile):
            debug("There is a menu-file for '%s'. Trying to load it.", self.__file__)
            barbox = self.tree.get_widget("menubar_box")
            if barbox is not None:
                self._add_menu(menufile, barbox)
        
        # signal connections
        if connector is None: connector = self

        unconnected = self._builder.connect_signals(connector)

        if unconnected is not None:
            for uc in set(unconnected):
                error("Signal '%s' not connected in class '%s'.", uc, self.__class__.__name__)

    def _add_menu (self, menufile, barbox):
        # add menubar
        self._builder.add_from_file(menufile)
        bar = self.tree.get_ui("menubar")
        barbox.pack_start(bar, expand = False, fill = False)

        # connect accelerators
        for ui in self._builder.get_objects():
            if isinstance(ui, gtk.UIManager):
                self.window.add_accel_group(ui.get_accel_group())

    @staticmethod
    def watch_cursor (func):
        """This is a decorator for functions being so time consuming, that it is appropriate to show the watch-cursor.
        @attention: this function relies on the gtk.Window-Object being stored as self.window"""
        
        @wraps(func)
        def wrapper (self, *args, **kwargs):
            ret = None
            def cb_idle():
                try:
                    ret = func(self, *args, **kwargs)
                finally:
                    self.window.window.set_cursor(None)
                return False
            
            watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
            self.window.window.set_cursor(watch)
            gobject.idle_add(cb_idle)
            return ret

        return wrapper

class AbstractDialog (Window):
    """A class all our dialogs get derived from. It sets useful default vars and automatically handles the ESC-Button."""

    def __init__ (self, parent):
        """Constructor.

        @param parent: the parent window
        @type parent: gtk.Window"""
        
        Window.__init__(self)

        # set parent
        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)

    def cb_key_pressed (self, widget, event):
        """Closes the window if ESC is pressed."""
        keyname = gtk.gdk.keyval_name(event.keyval)
        if keyname == "Escape":
            self.close()
            return True
        else:
            return False

    def close (self, *args):
        self.window.destroy()