class TagEditor(Gtk.Window): """Window allowing to edit a tag's properties.""" def __init__(self, req, app, tag=None): super().__init__() self.req = req self.app = app self.tag = tag self.config = self.req.get_config('tag_editor') self.custom_colors = None self.tn_entry_watch_id = None self.tn_cb_clicked_hid = None self.tn_entry_clicked_hid = None self.tis_selection_changed_hid = None self.tag_icon_selector = None # Build up the window self.set_type_hint(Gdk.WindowTypeHint.DIALOG) self.set_position(Gtk.WindowPosition.CENTER) self.set_title(_('Editing Tag "%s"') % tag.get_name()) self.set_border_width(10) self.set_resizable(False) self.__build_window() self.__set_callbacks() self.set_tag(tag) # Make it visible self.show_all() def __build_window(self): """Build up the widget""" # toplevel widget self.top_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.add(self.top_vbox) # header line: icon, grid with name and "hide in wv" # FIXME self.hdr_align = Gtk.Alignment() self.top_vbox.pack_start(self.hdr_align, True, True, 0) self.hdr_align.set_padding(0, 25, 0, 0) self.hdr_box = Gtk.Box() self.hdr_align.add(self.hdr_box) self.hdr_box.set_spacing(10) # Button to tag icon selector self.ti_bt = Gtk.Button() self.ti_bt_label = Gtk.Label() self.ti_bt.add(self.ti_bt_label) self.hdr_box.pack_start(self.ti_bt, True, True, 0) self.ti_bt.set_size_request(64, 64) self.ti_bt.set_relief(Gtk.ReliefStyle.HALF) # vbox for tag name and hid in WV self.tp_grid = Gtk.Grid() self.hdr_box.pack_start(self.tp_grid, True, True, 0) self.tp_grid.set_column_spacing(5) self.tn_entry_lbl_align = Gtk.Alignment.new(0, 0.5, 0, 0) self.tp_grid.add(self.tn_entry_lbl_align) self.tn_entry_lbl = Gtk.Label() self.tn_entry_lbl.set_markup("<span weight='bold'>%s</span>" % _("Name : ")) self.tn_entry_lbl_align.add(self.tn_entry_lbl) self.tn_entry = Gtk.Entry() self.tn_entry.set_width_chars(20) self.tp_grid.attach(self.tn_entry, 1, 0, 1, 1) self.tn_cb_lbl_align = Gtk.Alignment.new(0, 0.5, 0, 0) self.tp_grid.attach(self.tn_cb_lbl_align, 0, 1, 1, 1) self.tn_cb_lbl = Gtk.Label(label=_('Show Tag in "Actionable" view:')) self.tn_cb_lbl_align.add(self.tn_cb_lbl) self.tn_cb = Gtk.CheckButton() self.tp_grid.attach(self.tn_cb, 1, 1, 1, 1) # Tag color self.tc_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.top_vbox.pack_start(self.tc_vbox, True, True, 0) self.tc_label_align = Gtk.Alignment() self.tc_vbox.pack_start(self.tc_label_align, True, True, 0) self.tc_label_align.set_padding(0, 0, 0, 0) self.tc_label = Gtk.Label() self.tc_label_align.add(self.tc_label) self.tc_label.set_markup("<span weight='bold'>%s</span>" % _("Select Tag Color:")) self.tc_label.set_alignment(0, 0.5) # Tag color chooser self.tc_cc_align = Gtk.Alignment.new(0.5, 0.5, 0, 0) self.tc_vbox.pack_start(self.tc_cc_align, True, True, 0) self.tc_cc_align.set_padding(15, 15, 10, 10) self.tc_cc_colsel = SimpleColorSelector() # self.tc_cc_colsel = Gtk.ColorChooserWidget() self.tc_cc_align.add(self.tc_cc_colsel) # Icon selector self.tag_icon_selector = TagIconSelector() def __set_callbacks(self): """Define the widget callbacks""" # Set the callbacks self.ti_bt.connect('clicked', self.on_ti_bt_clicked) self.tis_selection_changed_hid = \ self.tag_icon_selector.connect('selection-changed', self.on_tis_selection_changed) self.tn_entry_clicked_hid = \ self.tn_entry.connect('changed', self.on_tn_entry_changed) self.tn_cb_clicked_hid = \ self.tn_cb.connect('clicked', self.on_tn_cb_clicked) # FIXME self.tc_cc_colsel.connect('color-changed', self.on_tc_colsel_changed) self.tc_cc_colsel.connect('color-added', self.on_tc_colsel_added) # self.tc_cc_colsel.connect('color-activated', # self.on_tc_colsel_activated) self.connect('delete-event', self.on_close) # allow fast closing by Escape key agr = Gtk.AccelGroup() self.add_accel_group(agr) key, modifier = Gtk.accelerator_parse('Escape') agr.connect(key, modifier, Gtk.AccelFlags.VISIBLE, self.on_close) def __set_default_values(self): """Configure the widget components with their initial default values""" # Disable some handlers while setting up the widget to avoid # interferences self.tn_cb.handler_block(self.tn_cb_clicked_hid) self.tn_entry.handler_block(self.tn_entry_clicked_hid) self.tag_icon_selector.handler_block(self.tis_selection_changed_hid) # Default icon markup = "<span size='small'>%s</span>" % _("Click to\nSet Icon") self.ti_bt_label.set_justify(Gtk.Justification.CENTER) self.ti_bt_label.set_markup(markup) self.ti_bt_label.show() self.__set_icon(None) # Unselect any previously selected icon self.tag_icon_selector.unselect_icon() # Show in WV self.tn_cb.set_active(True) # Name entry self.tn_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, None) # Color selection # FIXME self.tc_cc_colsel.unselect_color() # self.tc_cc_colsel.set_use_alpha(False) # self.tc_cc_colsel.set_rgba(self.tc_cc_colsel, None) # Custom colors self.custom_colors = self.config.get('custom_colors') if len(self.custom_colors) > 0: self.tc_cc_colsel.set_custom_colors(self.custom_colors) # Focus self.tn_entry.grab_focus() # Re-enable checkbutton handler_block self.tn_cb.handler_unblock(self.tn_cb_clicked_hid) self.tn_entry.handler_unblock(self.tn_entry_clicked_hid) self.tag_icon_selector.handler_unblock(self.tis_selection_changed_hid) def __set_icon(self, icon): """Set the icon in the related button widget. Restore the label when when no icon is selected.""" if icon is not None: for i in self.ti_bt: self.ti_bt.remove(i) ti_bt_img = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.BUTTON) ti_bt_img.show() self.ti_bt.add(ti_bt_img) else: for i in self.ti_bt: self.ti_bt.remove(i) self.ti_bt.add(self.ti_bt_label) # PUBLIC API ##### def set_tag(self, tag): """Update the context menu items using the tag attributes.""" # set_active emit the 'toggle' signal, so we have to disable # the handler when we update programmatically self.__set_default_values() if tag is None: self.tag = None else: # Disable some handlers while setting up the widget to avoid # interferences self.tn_cb.handler_block(self.tn_cb_clicked_hid) self.tn_entry.handler_block(self.tn_entry_clicked_hid) self.tag = tag # Update entry if tag.is_search_tag(): name = tag.get_name() else: name = tag.get_name()[1:] self.tn_entry.set_text(name) # Update visibility in Work View s_hidden_in_wv = (self.tag.get_attribute("nonworkview") == "True") self.tn_cb.set_active(not s_hidden_in_wv) # If available, update icon if (tag.get_attribute('icon') is not None): icon = tag.get_attribute('icon') self.__set_icon(icon) # If available, update color selection if (tag.get_attribute('color') is not None): col = tag.get_attribute('color') if not self.tc_cc_colsel.has_color(col): self.tc_cc_colsel.add_custom_color(col) self.tc_cc_colsel.set_selected_color(col) # Re-enable checkbutton handler_block self.tn_cb.handler_unblock(self.tn_cb_clicked_hid) self.tn_entry.handler_unblock(self.tn_entry_clicked_hid) # CALLBACKS ##### def watch_tn_entry_changes(self): """Monitors the value changes in the tag name entry. If no updates have been noticed after 1 second, request an update.""" cur_value = self.get_tn_text() if self.tn_entry_last_recorded_value != cur_value: # they're different: there's been some updates, wait further return True else: # they're the same. We can unregister the watcher and # update the tag name self.tn_entry_watch_id = None if cur_value != '': if self.tag.is_search_tag(): new_name = cur_value else: new_name = "@" + cur_value self.req.rename_tag(self.tag.get_name(), new_name) self.tag = self.req.get_tag(new_name) # Select on sidebar and update values self.app.browser.select_on_sidebar(new_name) self.app.browser.apply_filter_on_panes(new_name) return False def on_tis_selection_changed(self, widget): """Callback: update tag attributes whenever an icon is (un)selected.""" icon = self.tag_icon_selector.get_selected_icon() if icon is not None: self.tag.set_attribute("icon", icon) self.__set_icon(icon) else: self.tag.del_attribute("icon") self.__set_icon(None) def on_ti_bt_clicked(self, widget): """Callback: displays the icon selector widget next to the button.""" rect = self.ti_bt.get_allocation() result, pos_x, pos_y = self.ti_bt.get_window().get_origin() self.tag_icon_selector.show_at_position( pos_x + rect.x + rect.width + 2, pos_y + rect.y) if self.tag.get_attribute('icon') is not None: self.tag_icon_selector.set_remove_enabled(True) else: self.tag_icon_selector.set_remove_enabled(False) def get_tn_text(self): """Return text from the name input.""" return self.tn_entry.get_text().strip().replace(' ', '') def on_tn_entry_changed(self, widget): """ Callback: checks tag name validity and start value changes monitoring to decide when to update a tag's name.""" self.tn_entry_last_recorded_value = self.get_tn_text() # check validity if self.tn_entry_last_recorded_value == "": self.tn_entry.set_icon_from_icon_name( Gtk.EntryIconPosition.SECONDARY, Gtk.STOCK_DIALOG_ERROR) else: self.tn_entry.set_icon_from_icon_name( Gtk.EntryIconPosition.SECONDARY, None) # filter out change requests to reduce commit overhead if self.tn_entry_watch_id is None: # There is no watchers for the text entry. Register one. # Also, wait 1 second before commiting the change in order to # reduce rename requests tn_entry_changes = self.watch_tn_entry_changes self.tn_entry_watch_id = GObject.timeout_add( 1000, tn_entry_changes) def on_tn_cb_clicked(self, widget): """Callback: toggle the nonworkview property according to the related widget's state.""" if self.tag is not None: show_in_wv = self.tn_cb.get_active() hide_in_wv = not show_in_wv self.tag.set_attribute('nonworkview', str(hide_in_wv)) def on_tc_colsel_changed(self, widget): """Callback: update the tag color depending on the current color selection""" color = self.tc_cc_colsel.get_selected_color() if self.tag is not None: if color is not None: my_color = Gdk.color_parse(color) color = Gdk.Color(my_color.red, my_color.green, my_color.blue).to_string() color_add(color) self.tag.set_attribute('color', color) else: color_remove(self.tag.get_attribute('color')) self.tag.del_attribute('color') def on_tc_colsel_activated(self, widget, color): """Callback: update the tag color depending on the current color selection""" print("activated", widget, color, " <--- ignoring for now") return # color = self.tc_cc_colsel.get_rgba().to_color() color = color.to_color() if self.tag is not None: if color is not None: self.tag.set_attribute('color', color) else: self.tag.del_attribute('color') def on_tc_colsel_added(self, widget): """Callback: if a new color is added, register it in the configuration""" self.custom_colors = self.tc_cc_colsel.get_custom_colors() self.config.set("custom_colors", self.custom_colors) def on_close(self, widget, event, arg1=None, arg2=None, arg3=None): """ Callback: hide the tag editor when the close the window. Arguments arg1-arg3 are needed to satisfy callback when closing by Escape """ self.app.close_tag_editor() return True
class TagEditor(gtk.Window): """Window allowing to edit a tag's properties.""" def __init__(self, req, vmanager, tag=None): gtk.Window.__init__(self) self.__gobject_init__() self.req = req self.vmanager = vmanager self.tag = tag self.config = self.req.get_config('tag_editor') self.custom_colors = None self.tn_entry_watch_id = None self.tn_cb_clicked_hid = None self.tn_entry_clicked_hid = None self.tis_selection_changed_hid = None self.tag_icon_selector = None # Build up the window self.set_position(gtk.WIN_POS_CENTER) self.set_title('Edit tag') self.set_border_width(10) self.set_resizable(False) self.__build_window() self.__set_callbacks() self.set_tag(tag) # Make it visible self.show_all() def __build_window(self): """Build up the widget""" # toplevel widget self.top_vbox = gtk.VBox() self.add(self.top_vbox) # header line: icon, table with name and "hide in wv" self.hdr_align = gtk.Alignment() self.top_vbox.pack_start(self.hdr_align) self.hdr_align.set_padding(0, 25, 0, 0) self.hdr_hbox = gtk.HBox() self.hdr_align.add(self.hdr_hbox) self.hdr_hbox.set_spacing(10) # Button to tag icon selector self.ti_bt = gtk.Button() self.ti_bt_label = gtk.Label() self.ti_bt.add(self.ti_bt_label) self.hdr_hbox.pack_start(self.ti_bt) self.ti_bt.set_size_request(64, 64) self.ti_bt.set_relief(gtk.RELIEF_HALF) # vbox for tag name and hid in WV self.tp_table = gtk.Table(2, 2) self.hdr_hbox.pack_start(self.tp_table) self.tp_table.set_col_spacing(0, 5) self.tn_entry_lbl_align = gtk.Alignment(0, 0.5) self.tp_table.attach(self.tn_entry_lbl_align, 0, 1, 0, 1) self.tn_entry_lbl = gtk.Label() self.tn_entry_lbl.set_markup("<span weight='bold'>%s</span>" % _("Name : ")) self.tn_entry_lbl_align.add(self.tn_entry_lbl) self.tn_entry = gtk.Entry() self.tp_table.attach(self.tn_entry, 1, 2, 0, 1) self.tn_entry.set_width_chars(20) self.tn_cb_lbl_align = gtk.Alignment(0, 0.5) self.tp_table.attach(self.tn_cb_lbl_align, 0, 1, 1, 2) self.tn_cb_lbl = gtk.Label(_("Show Tag in Work View :")) self.tn_cb_lbl_align.add(self.tn_cb_lbl) self.tn_cb = gtk.CheckButton() self.tp_table.attach(self.tn_cb, 1, 2, 1, 2) # Tag color self.tc_vbox = gtk.VBox() self.top_vbox.pack_start(self.tc_vbox) self.tc_label_align = gtk.Alignment() self.tc_vbox.pack_start(self.tc_label_align) self.tc_label_align.set_padding(0, 0, 0, 0) self.tc_label = gtk.Label() self.tc_label_align.add(self.tc_label) self.tc_label.set_markup( "<span weight='bold'>%s</span>" % _("Select Tag Color:")) self.tc_label.set_alignment(0, 0.5) # Tag color chooser self.tc_cc_align = gtk.Alignment(0.5, 0.5, 0, 0) self.tc_vbox.pack_start(self.tc_cc_align) self.tc_cc_align.set_padding(15, 15, 10, 10) self.tc_cc_colsel = SimpleColorSelector() self.tc_cc_align.add(self.tc_cc_colsel) # Icon selector self.tag_icon_selector = TagIconSelector() def __set_callbacks(self): """Define the widget callbacks""" # Set the callbacks self.ti_bt.connect('clicked', self.on_ti_bt_clicked) self.tis_selection_changed_hid = \ self.tag_icon_selector.connect('selection-changed', self.on_tis_selection_changed) self.tn_entry_clicked_hid = \ self.tn_entry.connect('changed', self.on_tn_entry_changed) self.tn_cb_clicked_hid = self.tn_cb.connect('clicked', self.on_tn_cb_clicked) self.tc_cc_colsel.connect('color-changed', self.on_tc_colsel_changed) self.tc_cc_colsel.connect('color-added', self.on_tc_colsel_added) self.connect('delete-event', self.on_close) # allow fast closing by Escape key agr = gtk.AccelGroup() self.add_accel_group(agr) key, modifier = gtk.accelerator_parse('Escape') agr.connect_group(key, modifier, gtk.ACCEL_VISIBLE, self.on_close) def __set_default_values(self): """Configure the widget components with their initial default values""" # Disable some handlers while setting up the widget to avoid # interferences self.tn_cb.handler_block(self.tn_cb_clicked_hid) self.tn_entry.handler_block(self.tn_entry_clicked_hid) self.tag_icon_selector.handler_block(self.tis_selection_changed_hid) # Default icon markup = "<span size='small'>%s</span>" % _("Click To\nSet Icon") self.ti_bt_label.set_justify(gtk.JUSTIFY_CENTER) self.ti_bt_label.set_markup(markup) self.ti_bt_label.show() self.__set_icon(None) # Unselect any previously selected icon self.tag_icon_selector.unselect_icon() # Show in WV self.tn_cb.set_active(True) # Name entry self.tn_entry.set_text(_("Enter tag name here")) self.tn_entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, None) # Color selection self.tc_cc_colsel.unselect_color() # Custom colors self.custom_colors = self.config.get('custom_colors') if len(self.custom_colors) > 0: self.tc_cc_colsel.set_custom_colors(self.custom_colors) # Focus self.tn_entry.grab_focus() # Re-enable checkbutton handler_block self.tn_cb.handler_unblock(self.tn_cb_clicked_hid) self.tn_entry.handler_unblock(self.tn_entry_clicked_hid) self.tag_icon_selector.handler_unblock(self.tis_selection_changed_hid) def __set_icon(self, icon): """Set the icon in the related button widget. Restore the label when when no icon is selected.""" if icon is not None: for i in self.ti_bt: self.ti_bt.remove(i) ti_bt_img = gtk.image_new_from_icon_name(icon, gtk.ICON_SIZE_BUTTON) ti_bt_img.show() self.ti_bt.add(ti_bt_img) else: for i in self.ti_bt: self.ti_bt.remove(i) self.ti_bt.add(self.ti_bt_label) ### PUBLIC API ### def set_tag(self, tag): """Update the context menu items using the tag attributes.""" # set_active emit the 'toggle' signal, so we have to disable # the handler when we update programmatically self.__set_default_values() if tag is None: self.tag = None else: # Disable some handlers while setting up the widget to avoid # interferences self.tn_cb.handler_block(self.tn_cb_clicked_hid) self.tn_entry.handler_block(self.tn_entry_clicked_hid) self.tag = tag # Update entry if tag.is_search_tag(): name = tag.get_name() else: name = tag.get_name()[1:] self.tn_entry.set_text(name) # Update visibility in Work View s_hidden_in_wv = (self.tag.get_attribute("nonworkview") == "True") self.tn_cb.set_active(not s_hidden_in_wv) # If available, update icon if (tag.get_attribute('icon') is not None): icon = tag.get_attribute('icon') self.__set_icon(icon) # If available, update color selection if (tag.get_attribute('color') is not None): col = tag.get_attribute('color') if not self.tc_cc_colsel.has_color(col): self.tc_cc_colsel.add_custom_color(col) self.tc_cc_colsel.set_selected_color(col) # Re-enable checkbutton handler_block self.tn_cb.handler_unblock(self.tn_cb_clicked_hid) self.tn_entry.handler_unblock(self.tn_entry_clicked_hid) ### CALLBACKS ### def watch_tn_entry_changes(self): """Monitors the value changes in the tag name entry. If no updates have been noticed after 1 second, request an update.""" cur_value = self.tn_entry.get_text() if self.tn_entry_last_recorded_value != cur_value: # they're different: there's been some updates, wait further return True else: # they're the same. We can unregister the watcher and # update the tag name self.tn_entry_watch_id = None if cur_value.strip() != '': if self.tag.is_search_tag(): new_name = cur_value else: new_name = "@" + cur_value self.req.rename_tag(self.tag.get_name(), new_name) return False def on_tis_selection_changed(self, widget): """Callback: update tag attributes whenever an icon is (un)selected.""" icon = self.tag_icon_selector.get_selected_icon() if icon is not None: self.tag.set_attribute("icon", icon) self.__set_icon(icon) else: self.tag.del_attribute("icon") self.__set_icon(None) def on_ti_bt_clicked(self, widget): """Callback: displays the tag icon selector widget next to the button.""" rect = self.ti_bt.get_allocation() pos_x, pos_y = \ self.ti_bt.window.get_origin() self.tag_icon_selector.show_at_position( pos_x + rect.x + rect.width + 2, pos_y + rect.y) if self.tag.get_attribute('icon') is not None: self.tag_icon_selector.set_remove_enabled(True) else: self.tag_icon_selector.set_remove_enabled(False) def on_tn_entry_changed(self, widget): """ Callback: checks tag name validity and start value changes monitoring to decide when to update a tag's name.""" self.tn_entry_last_recorded_value = self.tn_entry.get_text() # check validity if self.tn_entry_last_recorded_value.strip() == "": self.tn_entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_DIALOG_ERROR) else: self.tn_entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, None) # filter out change requests to reduce commit overhead if self.tn_entry_watch_id is None: # There is no watchers for the text entry. Register one. # Also, wait 1 second before commiting the change in order to # reduce rename requests tn_entry_changes = self.watch_tn_entry_changes self.tn_entry_watch_id = gobject.timeout_add(1000, tn_entry_changes) def on_tn_cb_clicked(self, widget): """Callback: toggle the nonworkview property according to the related widget's state.""" if self.tag is not None: show_in_wv = self.tn_cb.get_active() hide_in_wv = not show_in_wv self.tag.set_attribute('nonworkview', str(hide_in_wv)) def on_tc_colsel_changed(self, widget): """Callback: update the tag color depending on the current color selection""" color = self.tc_cc_colsel.get_selected_color() if self.tag is not None: if color is not None: self.tag.set_attribute('color', color) else: self.tag.del_attribute('color') def on_tc_colsel_added(self, widget): """Callback: if a new color is added, we register it in the configuration""" self.custom_colors = self.tc_cc_colsel.get_custom_colors() self.config.set("custom_colors", self.custom_colors) def on_close(self, widget, event, arg1=None, arg2=None, arg3=None): """ Callback: hide the tag editor when the close the window. Arguments arg1-arg3 are needed to satisfy callback when closing by Escape """ self.vmanager.close_tag_editor() return True
class TagEditor(gtk.Window): """Window allowing to edit a tag's properties.""" def __init__(self, req, vmanager, tag=None): gtk.Window.__init__(self) self.__gobject_init__() self.req = req self.vmanager = vmanager self.tag = tag self.config = self.req.get_config('tag_editor') self.custom_colors = None self.tn_entry_watch_id = None self.tn_cb_clicked_hid = None self.tn_entry_clicked_hid = None self.tis_selection_changed_hid = None self.tag_icon_selector = None # Build up the window self.set_position(gtk.WIN_POS_CENTER) self.set_title('Edit tag') self.set_border_width(10) self.set_resizable(False) self.__build_window() self.__set_callbacks() self.set_tag(tag) # Make it visible self.show_all() def __build_window(self): """Build up the widget""" # toplevel widget self.top_vbox = gtk.VBox() self.add(self.top_vbox) # header line: icon, table with name and "hide in wv" self.hdr_align = gtk.Alignment() self.top_vbox.pack_start(self.hdr_align) self.hdr_align.set_padding(0, 25, 0, 0) self.hdr_hbox = gtk.HBox() self.hdr_align.add(self.hdr_hbox) self.hdr_hbox.set_spacing(10) # Button to tag icon selector self.ti_bt = gtk.Button() self.ti_bt_label = gtk.Label() self.ti_bt.add(self.ti_bt_label) self.hdr_hbox.pack_start(self.ti_bt) self.ti_bt.set_size_request(64, 64) self.ti_bt.set_relief(gtk.RELIEF_HALF) # vbox for tag name and hid in WV self.tp_table = gtk.Table(2, 2) self.hdr_hbox.pack_start(self.tp_table) self.tp_table.set_col_spacing(0, 5) self.tn_entry_lbl_align = gtk.Alignment(0, 0.5) self.tp_table.attach(self.tn_entry_lbl_align, 0, 1, 0, 1) self.tn_entry_lbl = gtk.Label() self.tn_entry_lbl.set_markup("<span weight='bold'>%s</span>" % _("Name : ")) self.tn_entry_lbl_align.add(self.tn_entry_lbl) self.tn_entry = gtk.Entry() self.tp_table.attach(self.tn_entry, 1, 2, 0, 1) self.tn_entry.set_width_chars(20) self.tn_cb_lbl_align = gtk.Alignment(0, 0.5) self.tp_table.attach(self.tn_cb_lbl_align, 0, 1, 1, 2) self.tn_cb_lbl = gtk.Label(_("Show Tag in Work View :")) self.tn_cb_lbl_align.add(self.tn_cb_lbl) self.tn_cb = gtk.CheckButton() self.tp_table.attach(self.tn_cb, 1, 2, 1, 2) # Tag color self.tc_vbox = gtk.VBox() self.top_vbox.pack_start(self.tc_vbox) self.tc_label_align = gtk.Alignment() self.tc_vbox.pack_start(self.tc_label_align) self.tc_label_align.set_padding(0, 0, 0, 0) self.tc_label = gtk.Label() self.tc_label_align.add(self.tc_label) self.tc_label.set_markup("<span weight='bold'>%s</span>" % _("Select Tag Color:")) self.tc_label.set_alignment(0, 0.5) # Tag color chooser self.tc_cc_align = gtk.Alignment(0.5, 0.5, 0, 0) self.tc_vbox.pack_start(self.tc_cc_align) self.tc_cc_align.set_padding(15, 15, 10, 10) self.tc_cc_colsel = SimpleColorSelector() self.tc_cc_align.add(self.tc_cc_colsel) # Icon selector self.tag_icon_selector = TagIconSelector() def __set_callbacks(self): """Define the widget callbacks""" # Set the callbacks self.ti_bt.connect('clicked', self.on_ti_bt_clicked) self.tis_selection_changed_hid = \ self.tag_icon_selector.connect('selection-changed', self.on_tis_selection_changed) self.tn_entry_clicked_hid = \ self.tn_entry.connect('changed', self.on_tn_entry_changed) self.tn_cb_clicked_hid = self.tn_cb.connect('clicked', self.on_tn_cb_clicked) self.tc_cc_colsel.connect('color-changed', self.on_tc_colsel_changed) self.tc_cc_colsel.connect('color-added', self.on_tc_colsel_added) self.connect('delete-event', self.on_close) # allow fast closing by Escape key agr = gtk.AccelGroup() self.add_accel_group(agr) key, modifier = gtk.accelerator_parse('Escape') agr.connect_group(key, modifier, gtk.ACCEL_VISIBLE, self.on_close) def __set_default_values(self): """Configure the widget components with their initial default values""" # Disable some handlers while setting up the widget to avoid # interferences self.tn_cb.handler_block(self.tn_cb_clicked_hid) self.tn_entry.handler_block(self.tn_entry_clicked_hid) self.tag_icon_selector.handler_block(self.tis_selection_changed_hid) # Default icon markup = "<span size='small'>%s</span>" % _("Click To\nSet Icon") self.ti_bt_label.set_justify(gtk.JUSTIFY_CENTER) self.ti_bt_label.set_markup(markup) self.ti_bt_label.show() self.__set_icon(None) # Unselect any previously selected icon self.tag_icon_selector.unselect_icon() # Show in WV self.tn_cb.set_active(True) # Name entry self.tn_entry.set_text(_("Enter tag name here")) self.tn_entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, None) # Color selection self.tc_cc_colsel.unselect_color() # Custom colors self.custom_colors = self.config.get('custom_colors') if len(self.custom_colors) > 0: self.tc_cc_colsel.set_custom_colors(self.custom_colors) # Focus self.tn_entry.grab_focus() # Re-enable checkbutton handler_block self.tn_cb.handler_unblock(self.tn_cb_clicked_hid) self.tn_entry.handler_unblock(self.tn_entry_clicked_hid) self.tag_icon_selector.handler_unblock(self.tis_selection_changed_hid) def __set_icon(self, icon): """Set the icon in the related button widget. Restore the label when when no icon is selected.""" if icon is not None: for i in self.ti_bt: self.ti_bt.remove(i) ti_bt_img = gtk.image_new_from_icon_name(icon, gtk.ICON_SIZE_BUTTON) ti_bt_img.show() self.ti_bt.add(ti_bt_img) else: for i in self.ti_bt: self.ti_bt.remove(i) self.ti_bt.add(self.ti_bt_label) ### PUBLIC API ### def set_tag(self, tag): """Update the context menu items using the tag attributes.""" # set_active emit the 'toggle' signal, so we have to disable # the handler when we update programmatically self.__set_default_values() if tag is None: self.tag = None else: # Disable some handlers while setting up the widget to avoid # interferences self.tn_cb.handler_block(self.tn_cb_clicked_hid) self.tn_entry.handler_block(self.tn_entry_clicked_hid) self.tag = tag # Update entry if tag.is_search_tag(): name = tag.get_name() else: name = tag.get_name()[1:] self.tn_entry.set_text(name) # Update visibility in Work View s_hidden_in_wv = (self.tag.get_attribute("nonworkview") == "True") self.tn_cb.set_active(not s_hidden_in_wv) # If available, update icon if (tag.get_attribute('icon') is not None): icon = tag.get_attribute('icon') self.__set_icon(icon) # If available, update color selection if (tag.get_attribute('color') is not None): col = tag.get_attribute('color') if not self.tc_cc_colsel.has_color(col): self.tc_cc_colsel.add_custom_color(col) self.tc_cc_colsel.set_selected_color(col) # Re-enable checkbutton handler_block self.tn_cb.handler_unblock(self.tn_cb_clicked_hid) self.tn_entry.handler_unblock(self.tn_entry_clicked_hid) ### CALLBACKS ### def watch_tn_entry_changes(self): """Monitors the value changes in the tag name entry. If no updates have been noticed after 1 second, request an update.""" cur_value = self.tn_entry.get_text() if self.tn_entry_last_recorded_value != cur_value: # they're different: there's been some updates, wait further return True else: # they're the same. We can unregister the watcher and # update the tag name self.tn_entry_watch_id = None if cur_value.strip() != '': if self.tag.is_search_tag(): new_name = cur_value else: new_name = "@" + cur_value self.req.rename_tag(self.tag.get_name(), new_name) return False def on_tis_selection_changed(self, widget): """Callback: update tag attributes whenever an icon is (un)selected.""" icon = self.tag_icon_selector.get_selected_icon() if icon is not None: self.tag.set_attribute("icon", icon) self.__set_icon(icon) else: self.tag.del_attribute("icon") self.__set_icon(None) def on_ti_bt_clicked(self, widget): """Callback: displays the tag icon selector widget next to the button.""" rect = self.ti_bt.get_allocation() pos_x, pos_y = \ self.ti_bt.window.get_origin() self.tag_icon_selector.show_at_position( pos_x + rect.x + rect.width + 2, pos_y + rect.y) if self.tag.get_attribute('icon') is not None: self.tag_icon_selector.set_remove_enabled(True) else: self.tag_icon_selector.set_remove_enabled(False) def on_tn_entry_changed(self, widget): """ Callback: checks tag name validity and start value changes monitoring to decide when to update a tag's name.""" self.tn_entry_last_recorded_value = self.tn_entry.get_text() # check validity if self.tn_entry_last_recorded_value.strip() == "": self.tn_entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_DIALOG_ERROR) else: self.tn_entry.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, None) # filter out change requests to reduce commit overhead if self.tn_entry_watch_id is None: # There is no watchers for the text entry. Register one. # Also, wait 1 second before commiting the change in order to # reduce rename requests tn_entry_changes = self.watch_tn_entry_changes self.tn_entry_watch_id = gobject.timeout_add( 1000, tn_entry_changes) def on_tn_cb_clicked(self, widget): """Callback: toggle the nonworkview property according to the related widget's state.""" if self.tag is not None: show_in_wv = self.tn_cb.get_active() hide_in_wv = not show_in_wv self.tag.set_attribute('nonworkview', str(hide_in_wv)) def on_tc_colsel_changed(self, widget): """Callback: update the tag color depending on the current color selection""" color = self.tc_cc_colsel.get_selected_color() if self.tag is not None: if color is not None: self.tag.set_attribute('color', color) else: self.tag.del_attribute('color') def on_tc_colsel_added(self, widget): """Callback: if a new color is added, we register it in the configuration""" self.custom_colors = self.tc_cc_colsel.get_custom_colors() self.config.set("custom_colors", self.custom_colors) def on_close(self, widget, event, arg1=None, arg2=None, arg3=None): """ Callback: hide the tag editor when the close the window. Arguments arg1-arg3 are needed to satisfy callback when closing by Escape """ self.vmanager.close_tag_editor() return True