~cosmin.lupu/+junk/penguintv

« back to all changes in this revision

Viewing changes to penguintv/TagEditorNG.py

  • Committer: cosmin.lupu at gmail
  • Date: 2010-04-27 16:47:43 UTC
  • Revision ID: cosmin.lupu@gmail.com-20100427164743-ds8xrqonipp5ovdf
initial packaging

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# (C) 2007 Owen Williams
 
2
#
 
3
# A new, more intuitive tag editor
 
4
 
 
5
import penguintv
 
6
import gtk
 
7
import utils
 
8
 
 
9
class TagEditorNG:
 
10
        
 
11
        FEEDID = 0
 
12
        TITLE = 1
 
13
        TAGGED = 2
 
14
        SEPARATOR = 3
 
15
        NEWLY_TOGGLED = 4
 
16
 
 
17
        def __init__(self, xml, app):
 
18
                self._xml = xml
 
19
                self._app = app
 
20
                self._current_tag = None
 
21
                
 
22
                self._app.connect("feed-added", self.__feed_added_cb)
 
23
                self._app.connect("feed-removed", self.__feed_removed_cb)
 
24
                self._app.connect("tags-changed", self.__tags_changed_cb)
 
25
                
 
26
        def show(self):
 
27
                self._window = self._xml.get_widget("dialog_tag_editor_ng")
 
28
                self._window.set_transient_for(self._app.main_window.get_parent())
 
29
                for key in dir(self.__class__):
 
30
                        if key[:3] == '_on':
 
31
                                self._xml.signal_connect(key, getattr(self,key))
 
32
                                
 
33
                self._feeds_widget = self._xml.get_widget("treeview_feeds")
 
34
                self._feeds_model = gtk.ListStore(int, str, bool, bool, bool) #feed_id, title, tagged, separator, newly toggled
 
35
                self._feeds_widget.set_row_separator_func(lambda m,i:m[i][self.SEPARATOR] == True)
 
36
                self._sorted_model = gtk.TreeModelSort(self._feeds_model)
 
37
                
 
38
                def feed_sort_func(model, i1, i2):
 
39
                        #use lists to not affect actual values
 
40
                        r1 = list(model[i1])
 
41
                        r2 = list(model[i2])
 
42
                        
 
43
                        #if either is newly selected, treat as unchecked for sorting
 
44
                        if r1[self.NEWLY_TOGGLED] == True: r1[self.TAGGED] = not r1[self.TAGGED]
 
45
                        if r2[self.NEWLY_TOGGLED] == True: r2[self.TAGGED] = not r2[self.TAGGED]
 
46
                        
 
47
                        #test separator
 
48
                        if r1[self.SEPARATOR] == True:
 
49
                                if r2[self.TAGGED]: return -1
 
50
                                else: return 1
 
51
                        if r2[self.SEPARATOR] == True:
 
52
                                if r1[self.TAGGED]: return 1
 
53
                                else: return -1
 
54
 
 
55
                        #test checkboxes
 
56
                        if r1[self.TAGGED] != r2[self.TAGGED]:
 
57
                                return r1[self.TAGGED] - r2[self.TAGGED]
 
58
                        
 
59
                        #correct for weird bug
 
60
                        if r1[self.TITLE] is None: r1[self.TITLE] = ""
 
61
                        if r2[self.TITLE] is None: r2[self.TITLE] = ""
 
62
                                
 
63
                        #sort by name
 
64
                        if r1[self.TITLE].upper() < r2[self.TITLE].upper():
 
65
                                return 1
 
66
                        elif r1[self.TITLE].upper() == r2[self.TITLE].upper():
 
67
                                return 0
 
68
                        return -1
 
69
                                
 
70
                self._sorted_model.set_sort_func(0, feed_sort_func) 
 
71
                self._sorted_model.set_sort_column_id(0, gtk.SORT_DESCENDING)
 
72
 
 
73
                self._feeds_widget.set_model(self._sorted_model)                
 
74
                
 
75
                renderer = gtk.CellRendererToggle()
 
76
                feed_column = gtk.TreeViewColumn('')
 
77
                feed_column.pack_start(renderer, True)
 
78
                self._feeds_widget.append_column(feed_column)
 
79
                feed_column.set_attributes(renderer, active=2)
 
80
                renderer.connect('toggled', self._feed_toggled)
 
81
                
 
82
                renderer = gtk.CellRendererText()
 
83
                feed_column = gtk.TreeViewColumn('Feeds')
 
84
                feed_column.pack_start(renderer, True)
 
85
                feed_column.set_attributes(renderer, markup=1)
 
86
                self._feeds_widget.append_column(feed_column)
 
87
                
 
88
                self._tags_widget = self._xml.get_widget("treeview_tags")
 
89
                tags_model = gtk.ListStore(str) #tag
 
90
                self._tags_widget.set_model(tags_model)         
 
91
                
 
92
                renderer = gtk.CellRendererText()
 
93
                renderer.set_property('editable', True)
 
94
                renderer.connect('edited', self._tag_name_edited)
 
95
                tag_column = gtk.TreeViewColumn('Tags')
 
96
                tag_column.pack_start(renderer, True)
 
97
                tag_column.set_attributes(renderer, markup=0)
 
98
                
 
99
                
 
100
                self._tags_widget.append_column(tag_column)
 
101
                
 
102
                self._tags_widget.get_selection().connect('changed', self._tags_widget_changed)
 
103
                
 
104
                pane = self._xml.get_widget("hpaned1")
 
105
                pane.set_position(200)
 
106
                
 
107
                if utils.RUNNING_HILDON:
 
108
                        self._window.resize(650,300)
 
109
                else:
 
110
                        self._window.resize(500,600)
 
111
                self._window.show()
 
112
                
 
113
                self._populate_lists()
 
114
                
 
115
        def __feed_added_cb(self, app, a, b):
 
116
                self._populate_lists()
 
117
                
 
118
        def __feed_removed_cb(self, app, a):
 
119
                self._populate_lists()
 
120
                
 
121
        def __tags_changed_cb(self, app, val):
 
122
                # if we initiated the change we set val=1
 
123
                # the app sets val=0
 
124
                if val != 1:
 
125
                        self._populate_lists()
 
126
 
 
127
        def _populate_lists(self):
 
128
                self._feeds_model.clear()
 
129
                for feed_id, title, url in self._app.db.get_feedlist():
 
130
                        self._feeds_model.append([feed_id, title, False, False, False])
 
131
                self._feeds_model.append([-1, "None", False, True, False])
 
132
 
 
133
                model = self._tags_widget.get_model()
 
134
                model.clear()
 
135
                for tag, favorite in self._app.db.get_all_tags():
 
136
                        model.append([tag])
 
137
                        
 
138
        def _tags_widget_changed(self, event):
 
139
                tags_model = self._tags_widget.get_model()
 
140
                selected = self._tags_widget.get_selection().get_selected()
 
141
                try:
 
142
                        self._current_tag = tags_model[selected[1]][0]
 
143
                        tagged_feeds = self._app.db.get_feeds_for_tag(self._current_tag)
 
144
                except:
 
145
                        self._current_tag = None
 
146
                        tagged_feeds = []
 
147
                
 
148
                for row in self._feeds_model:
 
149
                        #reset "newly selected" feeds
 
150
                        row[self.NEWLY_TOGGLED] = False
 
151
                        row[self.TAGGED] = row[self.FEEDID] in tagged_feeds                     
 
152
                        
 
153
        def _feed_toggled(self, obj, path):
 
154
                if self._current_tag is None:
 
155
                        return
 
156
        
 
157
                path = self._sorted_model.convert_path_to_child_path(path)
 
158
                row = self._feeds_model[path]
 
159
 
 
160
                row[self.TAGGED] = not row[self.TAGGED]
 
161
                row[self.NEWLY_TOGGLED] = not row[self.NEWLY_TOGGLED]
 
162
                
 
163
                if row[self.TAGGED]:
 
164
                        self._app.db.add_tag_for_feed(row[self.FEEDID], self._current_tag)
 
165
                        self._app.emit('tags-changed', 1)
 
166
                else:
 
167
                        self._app.db.remove_tag_from_feed(row[self.FEEDID], self._current_tag)
 
168
                        self._app.emit('tags-changed', 1)
 
169
                        
 
170
        def _on_button_rename_clicked(self, event):
 
171
                if self._current_tag is None:
 
172
                        return
 
173
        
 
174
                # pop up a dialog to rename the current tag
 
175
                dialog = gtk.Dialog(title=_("Rename Tag"), parent=None, flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
 
176
 
 
177
                label = gtk.Label(_("Please enter a new name for this tag"))
 
178
                dialog.vbox.pack_start(label, True, True, 0)
 
179
                
 
180
                entry = gtk.Entry()
 
181
                dialog.vbox.pack_start(entry)
 
182
                
 
183
                dialog.show_all()
 
184
                response = dialog.run()
 
185
                dialog.hide()
 
186
                del dialog
 
187
                if response == gtk.RESPONSE_ACCEPT:     
 
188
                        # rename this item
 
189
                        new_name = entry.get_text()
 
190
                        self._rename_tag(self._current_tag, new_name)
 
191
                        
 
192
        def _tag_name_edited(self, renderer, path, new_text):
 
193
                #FIXME: do we need to check if the new_name already exists?
 
194
                model = self._tags_widget.get_model()
 
195
                self._rename_tag(model[path][0], new_text)
 
196
                        
 
197
        def _rename_tag(self, old_name, new_name):
 
198
                #FIXME: do we need to check if the new_name already exists?
 
199
                self._app.db.rename_tag(old_name, new_name)
 
200
                self._app.emit('tags-changed', 1)
 
201
                
 
202
                # resort
 
203
                selection = self._tags_widget.get_selection()
 
204
                model, old_iter = selection.get_selected()      
 
205
                model.remove(old_iter)
 
206
                
 
207
                self._current_tag = new_name
 
208
                
 
209
                new_index = -1
 
210
                i = -1
 
211
                for row in model:
 
212
                        i += 1
 
213
                        if new_name.upper() < row[0].upper():
 
214
                                new_index = i
 
215
                                break
 
216
                if new_index == -1:
 
217
                        new_index = len(model) - 1
 
218
                model.insert(new_index,[new_name])
 
219
                
 
220
                new_iter = model.get_iter((new_index,))
 
221
                self._tags_widget.scroll_to_cell((new_index,))
 
222
                selection.select_path((new_index,))
 
223
 
 
224
        def _on_button_add_clicked(self, event):
 
225
                # pop up a dialog to ask for a name, and add it... how to deal with
 
226
                # a tag with no associated feed????  ... I don't think it even matters
 
227
                # because the tag will be "created" as soon as we check a box
 
228
                
 
229
                # pop up a dialog to rename the current tag
 
230
                dialog = gtk.Dialog(title=_("Rename Tag"), parent=None, flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
 
231
 
 
232
                label = gtk.Label(_("Please enter a name for this new tag:"))
 
233
                dialog.vbox.pack_start(label, True, True, 0)
 
234
                
 
235
                entry = gtk.Entry()
 
236
                dialog.vbox.pack_start(entry)
 
237
                
 
238
                dialog.show_all()
 
239
                response = dialog.run()
 
240
                dialog.hide()
 
241
                del dialog
 
242
                if response == gtk.RESPONSE_ACCEPT:
 
243
                        # rename this item
 
244
                        tag_name = entry.get_text()
 
245
                        
 
246
                        # add tag to our list
 
247
                        model = self._tags_widget.get_model()
 
248
                        selection = self._tags_widget.get_selection()
 
249
                        
 
250
                        self._current_tag = tag_name
 
251
                        
 
252
                        new_index = -1
 
253
                        i = -1
 
254
                        for row in model:
 
255
                                i += 1
 
256
                                if tag_name.upper() < row[0].upper():
 
257
                                        new_index = i
 
258
                                        break
 
259
                        if new_index == -1:
 
260
                                new_index = len(model) - 1
 
261
                        model.insert(new_index,[tag_name])
 
262
                        
 
263
                        # select it
 
264
                        new_iter = model.get_iter((new_index,))
 
265
                        self._tags_widget.scroll_to_cell((new_index,))
 
266
                        selection.select_iter(new_iter)
 
267
                
 
268
        def _on_button_remove_clicked(self, event):
 
269
                if self._current_tag is None:
 
270
                        return 
 
271
        
 
272
                dialog = gtk.Dialog(title=_("Really Delete Tag?"), parent=None, flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
 
273
                label = gtk.Label(_("Are you sure you want to remove this tag from all feeds?"))
 
274
                dialog.vbox.pack_start(label, True, True, 0)
 
275
                label.show()
 
276
                response = dialog.run()
 
277
                dialog.hide()
 
278
                del dialog
 
279
                if response == gtk.RESPONSE_ACCEPT:     
 
280
                        #remove from db 
 
281
                        self._app.db.remove_tag(self._current_tag)
 
282
                        self._app.emit('tags-changed', 1)
 
283
                        
 
284
                        #remove tag from our list
 
285
                        selection = self._tags_widget.get_selection()
 
286
                        model, old_iter = selection.get_selected()      
 
287
                        model.remove(old_iter)
 
288
                        
 
289
                        self._current_tag = None
 
290
                        
 
291
                        #select nothing
 
292
                        self._tags_widget.scroll_to_cell((0,))
 
293
                        selection.unselect_all()
 
294
                
 
295
        def _on_button_close_clicked(self, event):
 
296
                self.hide()
 
297
 
 
298
        def _on_editor_help_button_activate(self, event):
 
299
                dialog = gtk.Dialog(title=_("Tag Editor Help"), parent=None, flags=gtk.DIALOG_MODAL, buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
 
300
                hbox = gtk.HBox()
 
301
                hbox.set_spacing(12)
 
302
                image = gtk.image_new_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_DIALOG)
 
303
                hbox.pack_start(image, False, False, 12)
 
304
                label = gtk.Label(_("""Select a tag in the list on the left, and all the feeds with that tag will be marked on the right.  You may mark and unmark feeds to add or remove that tag from them.
 
305
 
 
306
Tagged feeds will appear at the top of the list."""))
 
307
                label.set_line_wrap(True)
 
308
                hbox.pack_start(label, True, True, 0)
 
309
                dialog.vbox.pack_start(hbox, True, True, 0)
 
310
                dialog.show_all()
 
311
                dialog.resize(400,-1)
 
312
                response = dialog.run()
 
313
                dialog.hide()
 
314
                del dialog
 
315
                
 
316
        def on_dialog_tag_editor_ng_destroy_event(self, data1, data2):
 
317
                self.hide()
 
318
                
 
319
        def on_dialog_tag_editor_ng_delete_event(self, data1, data2):
 
320
                return self._window.hide_on_delete()
 
321
                
 
322
        def hide(self):
 
323
                self._window.hide()