Class | SSHMenu::PrefsDialog |
In: |
lib/sshmenu.rb
(Git)
|
Parent: | Object |
The SSHMenu::PrefsDialog class implements the main preferences dialog. Current config is read in from the ‘app.model’ object and written back if the user chooses to save a new config.
The dialog user interface comprises a treeview for the menu items and buttons for adding, removing, editing and reordering items.
Two additional tabs provide access to global option settings and the ‘About’ box.
ItemColumn | = | 0 |
Constructor. Takes an application object for global constants and a config object for reading/writing the configuration.
# File lib/sshmenu.rb, line 1818 def initialize(app, config) @app = app @config = config @button = { } @prev_path = nil @next_path = nil end
Called from make_hosts_pane to add each of the dialog buttons and hook up a signal handler for the ‘clicked’ event.
# File lib/sshmenu.rb, line 2071 def add_button(box, key, label, stock_id, sensitive) button = if stock_id @button[key] = Gtk::Button.new(stock_id) else @button[key] = Gtk::Button.new(label) end button.signal_connect('clicked') { send("btn_#{key}_pressed") } button.focus_on_click = false button.sensitive = sensitive box.pack_start(button, false, true, 0) end
Called from button handler routines to add items to the treeview. The new ‘item’ is inserted after an existing item identified by the iter ‘prev’.
# File lib/sshmenu.rb, line 2089 def add_item(prev, item) parent = nil iter = if prev.nil? @model.append(nil) elsif prev[ItemColumn].menu? parent = prev @model.append(prev) else parent = prev.parent @model.insert_after(parent, prev) end iter[ItemColumn] = item @view.expand_row(parent.path, false) if parent return iter end
Handler method for the ‘Add Host’ button. Pops up the Edit Host dialog with all fields blank.
# File lib/sshmenu.rb, line 2293 def btn_add_pressed item = mapper.get_class('app.model.hostitem').new result = edit_host(item) or return iter = add_item(selected_iter, item) @view.selection.select_iter(iter) end
Handler method for the ‘Copy’ button. Pops up the Edit Host dialog with fields populated from the currently selected item.
# File lib/sshmenu.rb, line 2282 def btn_copy_pressed iter = selected_iter or return item = get_item(iter).dup result = edit_host(item) or return iter = add_item(iter, result) @view.selection.select_iter(iter) end
Handler method for the ‘Delete’ button. Removes the currently selected item from the treeview.
# File lib/sshmenu.rb, line 2322 def btn_del_pressed iter = selected_iter path = iter.path @model.remove(iter) @button['up'].sensitive = false @button['down'].sensitive = false @button['edit'].sensitive = false @button['copy'].sensitive = false @button['del'].sensitive = false if @model.get_iter(path).nil? if !path.prev! if !path.up! return end end end @view.selection.select_path(path) end
Handler method for the ‘Down’ button. Exchanges the current and next items in the treeview.
# File lib/sshmenu.rb, line 2212 def btn_down_pressed cur = selected_iter or return new_path = nil nxt_item = nil nxt = @model.get_iter(@next_path) if nxt nxt_item = nxt[ItemColumn] or return end path_after = cur.path path_after.next! if nxt_item and nxt_item.menu? # Move down into submenu parent = nxt nxt = nxt.first_child if nxt nxt = @model.insert_before(parent, nxt) else nxt = @model.append(parent) end @view.expand_row(parent.path, false) new_path = cur.path move_branch(cur, nxt) @model.remove(cur) new_path.down! elsif @next_path.to_str != path_after.to_str # Move down out of submenu sibling = cur.parent parent = sibling.parent nxt = @model.insert_after(parent, sibling) new_path = nxt.path move_branch(cur, nxt) @model.remove(cur) else # Swap with preceding peer nxt = @model.get_iter(@next_path) new_path = @next_path @model.swap(cur, nxt) end sel = @view.selection sel.unselect_all sel.select_path(new_path) @view.scroll_to_cell(new_path, nil, false, 0, 0) end
Handler method for the ‘Edit’ button. Pops up the Edit Host dialog for the currently selected host item.
# File lib/sshmenu.rb, line 2269 def btn_edit_pressed iter = selected_iter or return item = get_item(iter) if item.host? edit_host(item) elsif item.menu? edit_menu(item) end end
Handler method for the ‘Add Submenu’ button. Pops up the Edit Menu Dialog with blank inputs.
# File lib/sshmenu.rb, line 2312 def btn_menu_pressed item = mapper.get_class('app.model.menuitem').new result = edit_menu(item) or return iter = add_item(selected_iter, item) @view.selection.select_iter(iter) end
Handler method for the ‘Add Separator’ button.
# File lib/sshmenu.rb, line 2302 def btn_sep_pressed item_class = mapper.get_class('app.model.item') item = item_class.new_from_hash( { 'type' => 'separator' } ) iter = add_item(selected_iter, item) @view.selection.select_iter(iter) end
Handler method for the ‘Up’ button. Exchanges the current and previous items in the treeview.
# File lib/sshmenu.rb, line 2169 def btn_up_pressed return unless @prev_path cur = selected_iter or return new_path = nil path_before = cur.path path_before.prev! if cur.path.to_str =~ /:0$/ # First child in submenu parent = @model.get_iter(@prev_path).parent sibling = @model.get_iter(@prev_path) new_iter = @model.insert_before(parent, sibling) move_branch(cur, new_iter) @model.remove(cur) new_path = new_iter.path elsif @prev_path.to_str != path_before.to_str # Move up into submenu parent = @model.get_iter(@prev_path).parent @view.expand_row(parent.path, false) sibling = @model.get_iter(@prev_path) new_iter = @model.insert_after(parent, sibling) move_branch(cur, new_iter) @model.remove(cur) new_path = new_iter.path elsif @model.get_iter(@prev_path)[ItemColumn].menu? # Move up into empty menu parent = @model.get_iter(@prev_path) new_iter = @model.append(parent) @view.expand_row(parent.path, false) move_branch(cur, new_iter) @model.remove(cur) new_path = new_iter.path else # Swap with following peer new_path = cur.path new_path.prev! or return prv = @model.get_iter(new_path) @model.swap(prv, cur) end sel = @view.selection sel.unselect_all sel.select_path(new_path) @view.scroll_to_cell(new_path, nil, false, 0, 0) end
Called from the invoke method to assemble the widgets in the dialog.
# File lib/sshmenu.rb, line 1890 def build_dialog dialog = Gtk::Dialog.new( "Preferences", nil, Gtk::Dialog::MODAL | Gtk::Dialog::DESTROY_WITH_PARENT | Gtk::Dialog::NO_SEPARATOR, [Gtk::Stock::OK, Gtk::Dialog::RESPONSE_ACCEPT], [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_REJECT] ) dialog.window_position = Gtk::Window::POS_MOUSE w = @config.get('width') || 370 h = @config.get('height') || 360 dialog.resize(w, h) dialog.screen = @app.display notebook = Gtk::Notebook.new dialog.vbox.pack_start(notebook, true, true, 0) notebook.append_page( make_hosts_pane, Gtk::Label.new("_Hosts", true) ) notebook.append_page( make_options_pane(), Gtk::Label.new("O_ptions", true) ) if not @app.context_menu_active? notebook.append_page( @app.make_about_pane(), Gtk::Label.new("Abou_t", true) ) end dialog.show_all return dialog end
Pops up the Edit Host dialog (‘app.dialog.host’ mapped to SSHMenu::HostDialog by default).
# File lib/sshmenu.rb, line 2371 def edit_host(item) dialog_class = mapper.get_class('app.dialog.host') return dialog_class.new(@app, item, @config).invoke end
Pops up the Edit Menu dialog (‘app.dialog.menu’ mapped to SSHMenu::MenuDialog by default).
# File lib/sshmenu.rb, line 2379 def edit_menu(item) dialog_class = mapper.get_class('app.dialog.menu') return dialog_class.new(@app, item).invoke end
Helper routine for SSHMenu::PrefsDialog#on_selection_changed. Locates item before and item following selected item and stores these values for calculating button sensitivity.
# File lib/sshmenu.rb, line 2129 def find_prev_next(target) @prev_path = nil @next_path = nil targ_path = target.path found = false @model.each do |model, path, iter| if found if @next_path.nil? and !path.descendant?(targ_path) @next_path = path end elsif iter == target found = true else @prev_path = path end end if @next_path.nil? and !target.parent.nil? # Target was last item if targ_path.up! @next_path = targ_path.next! end end end
Handler method for drag-and-drop reordering of items in the treeview. Tries to clean up after bad things that happen when items are dropped in unexpected places.
# File lib/sshmenu.rb, line 2345 def fix_dropped_items bad_path = nil @model.each do |model, path, iter| item = iter[ItemColumn] if !item.menu? and iter.has_child? bad_path = iter.path end end return unless bad_path iter = @model.get_iter(bad_path) item = iter[ItemColumn] child = iter.first_child or return target = child[ItemColumn] @model.remove(child) nxt = @model.insert_after(iter.parent, iter) nxt[ItemColumn] = target sel = @view.selection sel.unselect_all sel.select_iter(nxt) @view.scroll_to_cell(nxt.path, nil, false, 0, 0) return false end
Returns the menu item (separator, host or sub menu) identified by the specified iter.
# File lib/sshmenu.rb, line 2156 def get_item(iter) return iter[ItemColumn] end
Creates the main dialog, waits for it to be dismissed and saves the contents if ‘OK’ was clicked.
# File lib/sshmenu.rb, line 1835 def invoke dialog = build_dialog if dialog.run != Gtk::Dialog::RESPONSE_ACCEPT dialog.destroy return end (w, h) = dialog.size @config.set('width', w) @config.set('height', h) save_menu_items save_options dialog.destroy @config.save end
Called from make_hosts_pane to construct the treeview widget and populate it with host and sub-menu items
# File lib/sshmenu.rb, line 2022 def make_hosts_list @model = Gtk::TreeStore.new(SSHMenu::Item) @view = Gtk::TreeView.new(@model) @view.rules_hint = false @view.search_column = 0 if GLib.check_binding_version?(0, 19, 0) @view.reorderable = true end renderer = Gtk::CellRendererText.new column = Gtk::TreeViewColumn.new("Host", renderer) @view.append_column(column) column.set_cell_data_func(renderer) do |tvc, renderer, model, iter| i = iter[ItemColumn] if i.separator? renderer.text = "_____________________________" else renderer.text = i.title end end @view.selection.signal_connect('changed') { on_selection_changed(@view.selection.selected) } path = {} @config.each_item() do |parents, i| key = i.object_id parent = nil parent = @model.get_iter(path[parents[-1].object_id]) if parents.length > 0 row = @model.append(parent) row[ItemColumn] = i.dup path[key] = row.path end @view.signal_connect('drag-drop') do Gtk.timeout_add(50) { fix_dropped_items } false end return @view.collapse_all end
Called from build_dialog to construct the contents of the main tab.
# File lib/sshmenu.rb, line 1932 def make_hosts_pane pane = Gtk::HBox.new(false, 12) pane.set_border_width(8) list_box = Gtk::VBox.new(false, 8) pane.pack_start(list_box, true, true, 0) sw = Gtk::ScrolledWindow.new sw.set_shadow_type(Gtk::SHADOW_ETCHED_IN) sw.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC) list_box.pack_start(sw, true, true, 0) hlist = make_hosts_list() sw.add(hlist) hlist.signal_connect('row_activated') { btn_edit_pressed } arrows = Gtk::HBox.new(true, 10) list_box.pack_start(arrows, false, true, 0) buttons = Gtk::VBox.new(false, 10) pane.pack_start(buttons, false, true, 0) add_button(arrows, 'up', '', Gtk::Stock::GO_UP, false) add_button(arrows, 'down', '', Gtk::Stock::GO_DOWN, false) add_button(buttons, 'add', '_Add Host', nil, true) add_button(buttons, 'sep', 'Add _Separator', nil, true) add_button(buttons, 'menu', 'Add Sub_menu', nil, true) add_button(buttons, 'edit', '_Edit', nil, false) add_button(buttons, 'copy', 'Cop_y Host', nil, false) add_button(buttons, 'del', '_Remove', nil, false) return pane end
Called from build_dialog to construct the contents of the global options tab.
# File lib/sshmenu.rb, line 1969 def make_options_pane table = Gtk::Table.new(1, 1, false) table.set_border_width(10) r = 0 if @app.can_show_entry? @chk_show_entry = Gtk::CheckButton.new( 'show text _entry next to menu button', true ) @chk_show_entry.active = @config.show_entry? table.attach( @chk_show_entry, 0, 1, r, r+1, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0 ) r += 1 end @chk_back_up_config = Gtk::CheckButton.new( '_back up config file on save', true ) @chk_back_up_config.active = @config.back_up_config? table.attach( @chk_back_up_config, 0, 1, r, r+1, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0 ) r += 1 @chk_tearoff = Gtk::CheckButton.new('enable tear-off _menus', true) @chk_tearoff.active = @config.menus_tearoff? table.attach( @chk_tearoff, 0, 1, r, r+1, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0 ) r += 1 @chk_hide_border = Gtk::CheckButton.new('hide button _border', true) @chk_hide_border.active = @config.hide_border? table.attach( @chk_hide_border, 0, 1, r, r+1, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0 ) r += 1 @chk_open_all = Gtk::CheckButton.new( 'include "Open all _windows" selection', true ) @chk_open_all.active = @config.menus_open_all? table.attach( @chk_open_all, 0, 1, r, r+1, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0 ) return table end
Accessor for the SSHMenu::ClassMapper singleton object
# File lib/sshmenu.rb, line 1828 def mapper ClassMapper.instance end
Helper method for moving a TreeStore row along with all its children.
# File lib/sshmenu.rb, line 2255 def move_branch(src, dst) dst[ItemColumn] = src[ItemColumn] child_src = src.first_child while child_src child_dst = @model.append(dst) move_branch(child_src, child_dst) child_src.next! or break end @view.expand_row(dst.path, false) if @view.row_expanded?(src.path) end
Handler for the ‘Changed’ signal from the host list treeview. Enables/disables buttons as appropriate.
# File lib/sshmenu.rb, line 2109 def on_selection_changed(iter) return unless iter @selected = iter.path item = get_item(iter) @button['edit'].sensitive = (item.host? or item.menu?) @button['copy'].sensitive = (item.host?) if iter[ItemColumn].menu? and iter.has_child? @button['del'].sensitive = false else @button['del'].sensitive = true end find_prev_next(iter) @button['up'].sensitive = !@prev_path.nil? @button['down'].sensitive = !@next_path.nil? end
Helper routine which transfers the host items from the treeview widget back to the config object.
# File lib/sshmenu.rb, line 1858 def save_menu_items items = [] @model.each do |model, path, iter| i = iter[ItemColumn] i.clear_items if i.menu? if path.depth > 1 parent = iter.parent[ItemColumn] parent.append_item(i) else items.push i end end @config.set_items_from_array(items.collect { |i| i.to_h }) end
Helper routine which transfers global option settings back to the config object.
# File lib/sshmenu.rb, line 1878 def save_options if @app.can_show_entry? @config.show_entry = @chk_show_entry.active? end @config.hide_border = @chk_hide_border.active? @config.menus_tearoff = @chk_tearoff.active? @config.menus_open_all = @chk_open_all.active? @config.back_up_config = @chk_back_up_config.active? end