1
# (C) 2007 Owen Williams
3
# A new, more intuitive tag editor
17
def __init__(self, xml, app):
20
self._current_tag = None
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)
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__):
31
self._xml.signal_connect(key, getattr(self,key))
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)
38
def feed_sort_func(model, i1, i2):
39
#use lists to not affect actual values
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]
48
if r1[self.SEPARATOR] == True:
49
if r2[self.TAGGED]: return -1
51
if r2[self.SEPARATOR] == True:
52
if r1[self.TAGGED]: return 1
56
if r1[self.TAGGED] != r2[self.TAGGED]:
57
return r1[self.TAGGED] - r2[self.TAGGED]
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] = ""
64
if r1[self.TITLE].upper() < r2[self.TITLE].upper():
66
elif r1[self.TITLE].upper() == r2[self.TITLE].upper():
70
self._sorted_model.set_sort_func(0, feed_sort_func)
71
self._sorted_model.set_sort_column_id(0, gtk.SORT_DESCENDING)
73
self._feeds_widget.set_model(self._sorted_model)
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)
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)
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)
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)
100
self._tags_widget.append_column(tag_column)
102
self._tags_widget.get_selection().connect('changed', self._tags_widget_changed)
104
pane = self._xml.get_widget("hpaned1")
105
pane.set_position(200)
107
if utils.RUNNING_HILDON:
108
self._window.resize(650,300)
110
self._window.resize(500,600)
113
self._populate_lists()
115
def __feed_added_cb(self, app, a, b):
116
self._populate_lists()
118
def __feed_removed_cb(self, app, a):
119
self._populate_lists()
121
def __tags_changed_cb(self, app, val):
122
# if we initiated the change we set val=1
125
self._populate_lists()
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])
133
model = self._tags_widget.get_model()
135
for tag, favorite in self._app.db.get_all_tags():
138
def _tags_widget_changed(self, event):
139
tags_model = self._tags_widget.get_model()
140
selected = self._tags_widget.get_selection().get_selected()
142
self._current_tag = tags_model[selected[1]][0]
143
tagged_feeds = self._app.db.get_feeds_for_tag(self._current_tag)
145
self._current_tag = None
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
153
def _feed_toggled(self, obj, path):
154
if self._current_tag is None:
157
path = self._sorted_model.convert_path_to_child_path(path)
158
row = self._feeds_model[path]
160
row[self.TAGGED] = not row[self.TAGGED]
161
row[self.NEWLY_TOGGLED] = not row[self.NEWLY_TOGGLED]
164
self._app.db.add_tag_for_feed(row[self.FEEDID], self._current_tag)
165
self._app.emit('tags-changed', 1)
167
self._app.db.remove_tag_from_feed(row[self.FEEDID], self._current_tag)
168
self._app.emit('tags-changed', 1)
170
def _on_button_rename_clicked(self, event):
171
if self._current_tag is None:
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))
177
label = gtk.Label(_("Please enter a new name for this tag"))
178
dialog.vbox.pack_start(label, True, True, 0)
181
dialog.vbox.pack_start(entry)
184
response = dialog.run()
187
if response == gtk.RESPONSE_ACCEPT:
189
new_name = entry.get_text()
190
self._rename_tag(self._current_tag, new_name)
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)
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)
203
selection = self._tags_widget.get_selection()
204
model, old_iter = selection.get_selected()
205
model.remove(old_iter)
207
self._current_tag = new_name
213
if new_name.upper() < row[0].upper():
217
new_index = len(model) - 1
218
model.insert(new_index,[new_name])
220
new_iter = model.get_iter((new_index,))
221
self._tags_widget.scroll_to_cell((new_index,))
222
selection.select_path((new_index,))
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
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))
232
label = gtk.Label(_("Please enter a name for this new tag:"))
233
dialog.vbox.pack_start(label, True, True, 0)
236
dialog.vbox.pack_start(entry)
239
response = dialog.run()
242
if response == gtk.RESPONSE_ACCEPT:
244
tag_name = entry.get_text()
246
# add tag to our list
247
model = self._tags_widget.get_model()
248
selection = self._tags_widget.get_selection()
250
self._current_tag = tag_name
256
if tag_name.upper() < row[0].upper():
260
new_index = len(model) - 1
261
model.insert(new_index,[tag_name])
264
new_iter = model.get_iter((new_index,))
265
self._tags_widget.scroll_to_cell((new_index,))
266
selection.select_iter(new_iter)
268
def _on_button_remove_clicked(self, event):
269
if self._current_tag is None:
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)
276
response = dialog.run()
279
if response == gtk.RESPONSE_ACCEPT:
281
self._app.db.remove_tag(self._current_tag)
282
self._app.emit('tags-changed', 1)
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)
289
self._current_tag = None
292
self._tags_widget.scroll_to_cell((0,))
293
selection.unselect_all()
295
def _on_button_close_clicked(self, event):
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))
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.
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)
311
dialog.resize(400,-1)
312
response = dialog.run()
316
def on_dialog_tag_editor_ng_destroy_event(self, data1, data2):
319
def on_dialog_tag_editor_ng_delete_event(self, data1, data2):
320
return self._window.hide_on_delete()