~doctormo/gnome-wallchanger/trunk

« back to all changes in this revision

Viewing changes to gwc/gtkviews.py

  • Committer: Martin Owens (DoctorMO)
  • Date: 2009-10-11 19:32:33 UTC
  • Revision ID: doctormo@gmail.com-20091011193233-15p70kim7zsjyhqx
Add new modules for ver 3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# Copyright 2009 Martin Owens
 
3
#
 
4
# This program is free software: you can redistribute it and/or modify
 
5
#  it under the terms of the GNU General Public License as published by
 
6
#  the Free Software Foundation, either version 3 of the License, or
 
7
#  (at your option) any later version.
 
8
#
 
9
#  This program is distributed in the hope that it will be useful,
 
10
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
#  GNU General Public License for more details.
 
13
#
 
14
#  You should have received a copy of the GNU General Public License
 
15
#  along with this program.  If not, see <http://www.gnu.org/licenses/>
 
16
#
 
17
"""
 
18
Wraps the gtk treeview in something a little nicer.
 
19
"""
 
20
 
 
21
# Import standard python libs
 
22
GLADE_DIR = './'
 
23
PIXMAP_DIR = './pixmaps/'
 
24
 
 
25
import os
 
26
import sys
 
27
import gtk
 
28
import gobject
 
29
import logging
 
30
 
 
31
MISSING = None
 
32
 
 
33
class IconManager(object):
 
34
    """Manage a set of cached icons"""
 
35
    def __init__(self, location):
 
36
        self.location = os.path.join(PIXMAP_DIR, location)
 
37
        self.cache    = {}
 
38
        self.get_icon('default')
 
39
 
 
40
    def get_icon(self, name):
 
41
        """Simple method for getting a set of pix icons and caching them."""
 
42
        if not self.cache.has_key(name):
 
43
            icon_path = self.icon_path(name)
 
44
            if os.path.exists(icon_path):
 
45
                self.cache[name] = gtk.gdk.pixbuf_new_from_file(icon_path)
 
46
            else:
 
47
                self.cache[name] = None
 
48
                logging.warning("Can't find icon for %s in %s" % (
 
49
                    name, self.location))
 
50
        if not self.cache.has_key(name) or not self.cache[name]:
 
51
            name = 'default'
 
52
        return self.cache.get(name, MISSING)
 
53
 
 
54
    def icon_path(self, name):
 
55
        """Returns the icon path based on stored location"""
 
56
        return os.path.join(self.location, '%s.png' % name)
 
57
 
 
58
 
 
59
class Window(object):
 
60
    """This wraps main windows for gtk"""
 
61
    signals = {}
 
62
    glade = None
 
63
    name = None
 
64
    w_tree = None
 
65
    window = None
 
66
    widget = None
 
67
    
 
68
    def __init__(self):
 
69
        self.init_gui()
 
70
        self.finish_gui()
 
71
 
 
72
    def glade_xml(self, glade_file, inital):
 
73
        """Load any given glade file from a standard location"""
 
74
        return gtk.glade.XML(os.path.join(GLADE_DIR, glade_file), inital)
 
75
 
 
76
    def init_gui(self):
 
77
        """Sets up a graphical window interface"""
 
78
        self.signals['destroyWindow'] = gtk.main_quit
 
79
        self.w_tree  = self.glade_xml(self.glade, self.name)
 
80
        self.widget = self.w_tree.get_widget
 
81
        self.window = self.widget(self.name)
 
82
        if not self.window:
 
83
            raise NameError, "Glade file '%s' missing window '%s'" % (
 
84
                self.glade, self.name)
 
85
        self.window.show()
 
86
 
 
87
    def finish_gui(self):
 
88
        """Finish the GUI by autoconnecting signals"""
 
89
        self.w_tree.signal_autoconnect(self.signals)
 
90
 
 
91
 
 
92
class ChildWindow(Window):
 
93
    """Is a basic setup of child windows"""
 
94
    done = False
 
95
 
 
96
    def __init__(self, parent, callback=None):
 
97
        self.glade = parent.glade
 
98
        super(ChildWindow, self).__init__()
 
99
        self.parent = parent.window
 
100
        self.parent.set_sensitive(False)
 
101
        self.callback = callback
 
102
        self.finish_gui()
 
103
 
 
104
    def init_gui(self):
 
105
        """Sets up a graphical child window interface"""
 
106
        super(ChildWindow, self).init_gui()
 
107
        self.signals['destroyWindow'] = self.finish
 
108
        self.signals['genericApply']  = self.apply_changes,
 
109
        self.signals['genericCancel'] = self.close_window,
 
110
 
 
111
    def close_window(self, button=None):
 
112
        """Tell the window to close."""
 
113
        self.window.destroy()
 
114
 
 
115
    def apply_changes(self, button=None):
 
116
        """Apply any changes as required by callbacks"""
 
117
        if self.is_valid():
 
118
            self.done = True
 
119
            self.close_window(self)
 
120
        else:
 
121
            self.is_valid_failed()
 
122
 
 
123
    def finish(self, button=None):
 
124
        """Finish off this child window process and callback with data."""
 
125
        if self.parent:
 
126
            self.parent.set_sensitive(True)
 
127
        if self.callback and self.done:
 
128
            self.callback(self.get_args())
 
129
            self.done = False
 
130
 
 
131
    def get_args(self):
 
132
        """Nothing to return"""
 
133
        return None
 
134
 
 
135
    def is_valid(self):
 
136
        """Return true is all args are valid."""
 
137
        return True
 
138
 
 
139
    def is_valid_failed(self):
 
140
        """This is what happens when we're not valid"""
 
141
        logging.error("Child arguments aren't valid!")
 
142
 
 
143
 
 
144
class BaseView(object):
 
145
    """Controls for tree and icon views, a base class"""
 
146
    _data = None
 
147
    _model = None
 
148
    selected = None
 
149
 
 
150
    def __init__(self, dbobj, selected=None, unselected=None, name=None):
 
151
        self.selected_signal = selected
 
152
        self.unselected_signal = unselected
 
153
        self._list = dbobj
 
154
        self._name = name
 
155
        self.connect_signals()
 
156
        self.setup()
 
157
        super(BaseView, self).__init__()
 
158
 
 
159
    def connect_signals(self):
 
160
        """Try and connect signals to and from the view control"""
 
161
        raise NotImplementedError, "Signal connection should be else where."
 
162
 
 
163
    def setup(self):
 
164
        """Setup any required aspects of the view"""
 
165
        return self._list
 
166
 
 
167
    def clear(self):
 
168
        """Clear all items from this treeview"""
 
169
        for iter_index in range(0, len(self._model)):
 
170
            try:
 
171
                del(self._model[0])
 
172
            except IndexError:
 
173
                logging.error("Could not delete item %d" % iter_index)
 
174
                return
 
175
 
 
176
    def add(self, target):
 
177
        """Add all items from the target to the treeview"""
 
178
        for item in target:
 
179
            self.add_item(item)
 
180
 
 
181
    def add_item(self, item, parent=None):
 
182
        """Add a single item image to the control"""
 
183
        result = self._model.append(parent, [item])
 
184
        # item.connect('update', self.updateItem)
 
185
        return result
 
186
 
 
187
    def replace(self, new_item, item_iter=None):
 
188
        """Replace all items, or a single item with object"""
 
189
        if item_iter:
 
190
            self.remove_item(target_iter=item_iter)
 
191
            self.add_item(new_item)
 
192
        else:
 
193
            self.clear()
 
194
            self._data = new_item
 
195
            self.add(new_item)
 
196
 
 
197
    def item_selected(self, item=None):
 
198
        """Base method result, called as an item is selected"""
 
199
        if self.selected != item:
 
200
            self.selected = item
 
201
            if self.selected_signal and item:
 
202
                self.selected_signal(item)
 
203
            elif self.unselected_signal and not item:
 
204
                self.unselected_signal(item)
 
205
 
 
206
    def remove_item(self, item=None, target_iter=None):
 
207
        """Remove an item from this view"""
 
208
        if target_iter and not item:
 
209
            return self._model.remove(target_iter)
 
210
        target_iter = self._model.get_iter_first()
 
211
        for itemc in self._model:
 
212
            if itemc[0] == item:
 
213
                return self._model.remove(target_iter)
 
214
            target_iter = self._model.iter_next(target_iter)
 
215
 
 
216
    def item_double_clicked(self, items):
 
217
        """What happens when you double click an item"""
 
218
        return items # Nothing
 
219
 
 
220
class TreeView(BaseView):
 
221
    """Controls and operates a tree view."""
 
222
    def connect_signals(self):
 
223
        """Attach the change cursor signal to the item selected"""
 
224
        self._list.connect('cursor_changed', self.item_selected_signal)
 
225
 
 
226
    def selected_items(self, treeview):
 
227
        """Return a list of selected item objects"""
 
228
        # This may need more thought, only returns one item
 
229
        item_iter = treeview.get_selection().get_selected()[1]
 
230
        return [ self._model[item_iter][0] ]
 
231
 
 
232
    def item_selected_signal(self, treeview):
 
233
        """Signal for selecting an item"""
 
234
        return self.item_selected( self.selected_items(treeview)[0] )
 
235
 
 
236
    def item_button_clicked(self, treeview, event):
 
237
        """Signal for mouse button click"""
 
238
        if event.type == gtk.gdk.BUTTON_PRESS:
 
239
            self.item_double_clicked( self.selected_items(treeview)[0] )
 
240
 
 
241
    def setup(self):
 
242
        """Set up an icon view for showing gallery images"""
 
243
        self._model = gtk.TreeStore(gobject.TYPE_PYOBJECT)
 
244
        self._list.set_model(self._model)
 
245
        return self._list
 
246
 
 
247
class DropDown(BaseView):
 
248
    """A simple wrapper for comboboxes"""
 
249
    def connect_signals(self):
 
250
        """Connect the combobox change signal"""
 
251
        self._list.connect('changed', self.item_selected_signal)
 
252
 
 
253
    def setup(self):
 
254
        """Set up an icon view for showing gallery images"""
 
255
        self._model = gtk.TreeStore(gobject.TYPE_PYOBJECT)
 
256
        self._list.set_model(self._model)
 
257
        return self._list
 
258
 
 
259
    def item_selected_signal(self, icon_view):
 
260
        """Item has been selected"""
 
261
        self.selected = icon_view.get_selected_items()
 
262
 
 
263
 
 
264
class IconView(BaseView):
 
265
    """Allows a simpler IconView for DBus List Objects"""
 
266
    def connect_signals(self):
 
267
        """Connect the selection changed signal up"""
 
268
        self._list.connect('selection-changed', self.item_selected_signal)
 
269
 
 
270
    def setup(self):
 
271
        """Setup the icon view control view"""
 
272
        self._model = gtk.ListStore(str, gtk.gdk.Pixbuf, gobject.TYPE_PYOBJECT)
 
273
        self._list.set_model(self._model)
 
274
        return self._list
 
275
 
 
276
    def item_selected_signal(self, icon_view):
 
277
        """Item has been selected"""
 
278
        self.selected = icon_view.get_selected_items()
 
279