From 0c035f106ac2dfcec3b4169aa6c064d1a4c317b4 Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Wed, 12 Apr 2017 17:44:29 +0100 Subject: [PATCH 01/13] Various changes to make SSH Menu work under Terminator 1.9+ --- ssh_menu.py | 159 ++++++++++++++++++++++++++-------------------------- 1 file changed, 80 insertions(+), 79 deletions(-) diff --git a/ssh_menu.py b/ssh_menu.py index a5d3a7e..568f59b 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -9,7 +9,7 @@ if __name__ == '__main__': sys.path.append( os.path.join(os.path.dirname(__file__), "../..")) -import gtk +from gi.repository import Gtk import terminatorlib.plugin as plugin from terminatorlib.config import Config from terminatorlib.translation import _ @@ -45,15 +45,15 @@ def __init__( self): ) def callback(self, menuitems, menu, terminal): """Add our menu items to the menu""" - item = gtk.MenuItem(_('SSH Menu')) + item = Gtk.MenuItem(_('SSH Menu')) item.connect("activate", self.menu, terminal) menuitems.append(item) - # submenu = gtk.Menu() + # submenu = Gtk.Menu() # item.set_submenu(submenu) - # menuitem = gtk.ImageMenuItem(gtk.STOCK_PREFERENCES) + # menuitem = Gtk.ImageMenuItem(Gtk.STOCK_PREFERENCES) # menuitem.connect("activate", self.configure) # submenu.append(menuitem) @@ -84,15 +84,16 @@ def _execute(self, treeview, path, view_column, data): command = model.get_value(iter,1) if command[len(command)-1] != '\n': command = command + '\n' - data['terminal'].vte.feed_child(command) + length=len(command) + data['terminal'].vte.feed_child(command, length) def menu(self, widget, terminal, data = None): ui = {} - window = gtk.Window() - scroll = gtk.ScrolledWindow(None, None) - scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) + window = Gtk.Window() + scroll = Gtk.ScrolledWindow(None, None) + scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS) #scroll.set_border_width(1) @@ -102,13 +103,13 @@ def menu(self, widget, terminal, data = None): window.set_resizable(True) #window. set_decorated(False) # Create a new button - buttonsbox = gtk.HBox(False, 0) - box1 = gtk.VBox(False, 0) + buttonsbox = Gtk.HBox(False, 0) + box1 = Gtk.VBox(False, 0) - button = gtk.Button("Close", gtk.STOCK_CLOSE) - button.connect_object("clicked", gtk.Widget.destroy, window) + button = Gtk.Button("Close", Gtk.STOCK_CLOSE) + button.connect_object("clicked", Gtk.Widget.destroy, window) - buttonPreferences = gtk.Button("Close", gtk.STOCK_PREFERENCES) + buttonPreferences = Gtk.Button("Configure", Gtk.STOCK_PREFERENCES) buttonPreferences.connect("clicked", self.configure) @@ -118,21 +119,21 @@ def menu(self, widget, terminal, data = None): - store = gtk.TreeStore(str,str) + store = Gtk.TreeStore(str,str) rabbit = store.append(None, ["Main","men"]) for command in self.cmd_list: store.append(rabbit,[command['name'], command['command']]) - treeview = gtk.TreeView(store) + treeview = Gtk.TreeView(store) selection = treeview.get_selection() - selection.set_mode(gtk.SELECTION_SINGLE) + selection.set_mode(Gtk.SelectionMode.SINGLE) selection.connect("changed", self._save_order, {'terminal' : terminal, 'selection' : selection }) treeview.connect("row-activated", self._execute, {'terminal' : terminal, 'selection' : selection }) ui['treeview'] = treeview - renderer = gtk.CellRendererText() - column = gtk.TreeViewColumn("Hosts", renderer, text=CC_COL_NAME) + renderer = Gtk.CellRendererText() + column = Gtk.TreeViewColumn("Hosts", renderer, text=CC_COL_NAME) treeview.append_column(column) @@ -143,21 +144,21 @@ def menu(self, widget, terminal, data = None): treeview.set_enable_search(True) - hbox = gtk.HBox() - hbox.pack_start(treeview) + hbox = Gtk.HBox() + hbox.pack_start(treeview, True, True, 0) - outbox = gtk.VBox(False, 0) + outbox = Gtk.VBox(False, 0) - inbox = gtk.VBox(False, 0) + inbox = Gtk.VBox(False, 0) inbox.pack_start(scroll, True, True, 5) inbox.pack_start(box1,False, False, 8) scroll.add_with_viewport(hbox) scroll.show() - outbox.pack_start(inbox) + outbox.pack_start(inbox, True, True, 0) window.add(outbox) window.show_all() @@ -165,88 +166,88 @@ def menu(self, widget, terminal, data = None): def configure(self, widget, data = None): ui = {} - window = gtk.Dialog( + window = Gtk.Dialog( _("SSH Menu Configuration"), None, - gtk.DIALOG_MODAL, + Gtk.DialogFlags.MODAL, ( - gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, - gtk.STOCK_OK, gtk.RESPONSE_ACCEPT + Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, + Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT ) ) - store = gtk.ListStore(str, str) + store = Gtk.ListStore(str, str) for command in self.cmd_list: store.append([command['name'], command['command']]) - treeview = gtk.TreeView(store) + treeview = Gtk.TreeView(store) #treeview.connect("cursor-changed", self.on_cursor_changed, ui) selection = treeview.get_selection() - selection.set_mode(gtk.SELECTION_SINGLE) + selection.set_mode(Gtk.SelectionMode.SINGLE) selection.connect("changed", self.on_selection_changed, ui) ui['treeview'] = treeview - renderer = gtk.CellRendererText() - column = gtk.TreeViewColumn("Name", renderer, text=CC_COL_NAME) + renderer = Gtk.CellRendererText() + column = Gtk.TreeViewColumn("Name", renderer, text=CC_COL_NAME) treeview.append_column(column) - renderer = gtk.CellRendererText() - column = gtk.TreeViewColumn("Command", renderer, text=CC_COL_COMMAND) + renderer = Gtk.CellRendererText() + column = Gtk.TreeViewColumn("Command", renderer, text=CC_COL_COMMAND) treeview.append_column(column) - hbox = gtk.HBox() - hbox.pack_start(treeview) - window.vbox.pack_start(hbox) + hbox = Gtk.HBox() + hbox.pack_start(treeview, True, True, 0) + window.vbox.pack_start(hbox, True, True, 0) - button_box = gtk.VBox() + button_box = Gtk.VBox() - button = gtk.Button(stock=gtk.STOCK_GOTO_TOP) - button_box.pack_start(button, False, True) + button = Gtk.Button(stock=Gtk.STOCK_GOTO_TOP) + button_box.pack_start(button, False, True, 0) button.connect("clicked", self.on_goto_top, ui) button.set_sensitive(False) ui['button_top'] = button - button = gtk.Button(stock=gtk.STOCK_GO_UP) - button_box.pack_start(button, False, True) + button = Gtk.Button(stock=Gtk.STOCK_GO_UP) + button_box.pack_start(button, False, True, 0) button.connect("clicked", self.on_go_up, ui) button.set_sensitive(False) ui['button_up'] = button - button = gtk.Button(stock=gtk.STOCK_GO_DOWN) - button_box.pack_start(button, False, True) + button = Gtk.Button(stock=Gtk.STOCK_GO_DOWN) + button_box.pack_start(button, False, True, 0) button.connect("clicked", self.on_go_down, ui) button.set_sensitive(False) ui['button_down'] = button - button = gtk.Button(stock=gtk.STOCK_GOTO_LAST) - button_box.pack_start(button, False, True) + button = Gtk.Button(stock=Gtk.STOCK_GOTO_LAST) + button_box.pack_start(button, False, True, 0) button.connect("clicked", self.on_goto_last, ui) button.set_sensitive(False) ui['button_last'] = button - button = gtk.Button(stock=gtk.STOCK_NEW) - button_box.pack_start(button, False, True) + button = Gtk.Button(stock=Gtk.STOCK_NEW) + button_box.pack_start(button, False, True, 0) button.connect("clicked", self.on_new, ui) ui['button_new'] = button - button = gtk.Button(stock=gtk.STOCK_EDIT) - button_box.pack_start(button, False, True) + button = Gtk.Button(stock=Gtk.STOCK_EDIT) + button_box.pack_start(button, False, True, 0) button.set_sensitive(False) button.connect("clicked", self.on_edit, ui) ui['button_edit'] = button - button = gtk.Button(stock=gtk.STOCK_DELETE) - button_box.pack_start(button, False, True) + button = Gtk.Button(stock=Gtk.STOCK_DELETE) + button_box.pack_start(button, False, True, 0) button.connect("clicked", self.on_delete, ui) button.set_sensitive(False) ui['button_delete'] = button - hbox.pack_start(button_box) + hbox.pack_start(button_box, True, True, 0) window.show_all() res = window.run() - if res == gtk.RESPONSE_ACCEPT: + if res == Gtk.ResponseType.ACCEPT: #we save the config iter = store.get_iter_first() self.cmd_list = [] @@ -282,38 +283,38 @@ def on_selection_changed(self,selection, data=None): data['button_delete'].set_sensitive(iter is not None) def _create_command_dialog(self, name_var = "", command_var = ""): - dialog = gtk.Dialog( + dialog = Gtk.Dialog( _("New Command"), None, - gtk.DIALOG_MODAL, + Gtk.DialogFlags.MODAL, ( - gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, - gtk.STOCK_OK, gtk.RESPONSE_ACCEPT + Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT, + Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT ) ) - table = gtk.Table(3, 2) + table = Gtk.Table(3, 2) - label = gtk.Label(_("Name:")) + label = Gtk.Label(label=_("Name:")) table.attach(label, 0, 1, 1, 2) - name = gtk.Entry() + name = Gtk.Entry() name.set_text(name_var) table.attach(name, 1, 2, 1, 2) - label = gtk.Label(_("Command:")) + label = Gtk.Label(label=_("Command:")) table.attach(label, 0, 1, 2, 3) - command = gtk.Entry() + command = Gtk.Entry() command.set_text(command_var) table.attach(command, 1, 2, 2, 3) - dialog.vbox.pack_start(table) + dialog.vbox.pack_start(table, True, True, 0) dialog.show_all() return (dialog,name,command) def _error(self, msg): - err = gtk.MessageDialog(dialog, - gtk.DIALOG_MODAL, - gtk.MESSAGE_ERROR, - gtk.BUTTONS_CLOSE, + err = Gtk.MessageDialog(dialog, + Gtk.DialogFlags.MODAL, + Gtk.MessageType.ERROR, + Gtk.ButtonsType.CLOSE, msg ) err.run() @@ -326,14 +327,14 @@ def on_new(self, button, data): (dialog,name,command) = self._create_command_dialog() res = dialog.run() item = {} - if res == gtk.RESPONSE_ACCEPT: + if res == Gtk.ResponseType.ACCEPT: item['name'] = name.get_text() item['command'] = command.get_text() if item['name'] == '' or item['command'] == '': - err = gtk.MessageDialog(dialog, - gtk.DIALOG_MODAL, - gtk.MESSAGE_ERROR, - gtk.BUTTONS_CLOSE, + err = Gtk.MessageDialog(dialog, + Gtk.DialogFlags.MODAL, + Gtk.MessageType.ERROR, + Gtk.ButtonsType.CLOSE, _("You need to define a name and command") ) err.run() @@ -434,14 +435,14 @@ def on_edit(self, button, data): ) res = dialog.run() item = {} - if res == gtk.RESPONSE_ACCEPT: + if res == Gtk.ResponseType.ACCEPT: item['name'] = name.get_text() item['command'] = command.get_text() if item['name'] == '' or item['command'] == '': - err = gtk.MessageDialog(dialog, - gtk.DIALOG_MODAL, - gtk.MESSAGE_ERROR, - gtk.BUTTONS_CLOSE, + err = Gtk.MessageDialog(dialog, + Gtk.DialogFlags.MODAL, + Gtk.MessageType.ERROR, + Gtk.ButtonsType.CLOSE, _("You need to define a name and command") ) err.run() @@ -468,5 +469,5 @@ def on_edit(self, button, data): if __name__ == '__main__': c = SSHMenu() c.configure(None, None) - gtk.main() + Gtk.main() From 842a5359e55582880aad3c5e409e81c486cb30be Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Wed, 12 Apr 2017 18:01:47 +0100 Subject: [PATCH 02/13] Add some basic instructions to the README --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9dc1c02..8a030f7 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,14 @@ SSH Menu -=================== +======== -Install --------- +SSH Menu is a SSH menu plugin for Terminator v1.9 (ie GTK3 based versions) or later. +Install +------- +Installing SSH Menu is as simple as copying ssh_menu.py to ~/.config/terminator/plugins/ . How to use it ------------- +After copying ssh_menu to your terminator plugins dir and restarting Terminator, you should have a new 'SSH menu' option within the Terminator context menu. Selecting this menu option will open the SSH Menu window. From here you can use the 'Configure' button to add new SSH connection commands to the menu or launch an SSH session in your current tab by double-clicking on an existing SSH command. From 84d38894ffd6573d14ec4256991f5e68d5dc53ea Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Wed, 12 Apr 2017 20:46:39 +0100 Subject: [PATCH 03/13] Add some current limitations of the plugin to the README --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a030f7..07802c8 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,13 @@ SSH Menu is a SSH menu plugin for Terminator v1.9 (ie GTK3 based versions) or la Install ------- -Installing SSH Menu is as simple as copying ssh_menu.py to ~/.config/terminator/plugins/ . +Installing SSH Menu is as simple as copying ssh_menu.py to ~/.config/terminator/plugins/ and reloading Terminator. How to use it ------------- -After copying ssh_menu to your terminator plugins dir and restarting Terminator, you should have a new 'SSH menu' option within the Terminator context menu. Selecting this menu option will open the SSH Menu window. From here you can use the 'Configure' button to add new SSH connection commands to the menu or launch an SSH session in your current tab by double-clicking on an existing SSH command. +After copying ssh_menu to your terminator plugins dir, you should have a new 'SSH menu' option within the Terminator context menu. Selecting this menu option will open the SSH Menu window. From here you can use the 'Configure' button to add new commands to SSH menu. + +Whilst it is expected most people will use this plugin to store and launch ssh sessions via ssh commands, it can be used to store and run any shell command. Due to the lack of encryption, 2FA etc it would be recommended you do not use this plugin to store passwords or other sensitive data. + +Note that you currently need to close and re-open the SSH Menu window before newly added commands are displayed and deleted commands get removed. From 53db5b02c10a6f691d23eeaaaf66dd23f34890cf Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Fri, 21 Apr 2017 13:36:01 +0100 Subject: [PATCH 04/13] Add group dialog to New Command window --- ssh_menu.py | 67 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/ssh_menu.py b/ssh_menu.py index 568f59b..d2a18f3 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -1,7 +1,8 @@ -#!/usr/bin/python -# Terminator by Chris Jones -# GPL v2 only -"""ssh_menu.py - Terminator Plugin to add an SSH Menu""" +# ssh_menu.py - Terminator plugin to add an SSH / command menu +# +# Original version by Mario Lameiras, 2014 +# GTK3 port by Dan MacDonald, 2017 + import sys import os @@ -15,7 +16,7 @@ from terminatorlib.translation import _ from terminatorlib.util import get_config_dir -(CC_COL_NAME, CC_COL_COMMAND) = range(0,2) +(CC_COL_NAME, CC_COL_COMMAND, CC_COL_GROUP) = range(0,3) # Every plugin you want Terminator to load *must* be listed in 'AVAILABLE' AVAILABLE = ['SSHMenu'] @@ -38,9 +39,11 @@ def __init__( self): continue name = s["name"] command = s["command"] + group = s["group"] self.cmd_list.append( { 'name' : name, - 'command' : command + 'command' : command, + 'group' : group } ) def callback(self, menuitems, menu, terminal): @@ -65,10 +68,12 @@ def _save_config(self): while i < length: name = self.cmd_list[i]['name'] command = self.cmd_list[i]['command'] + group = self.cmd_list[i]['group'] item = {} item['name'] = name item['command'] = command + item['group'] = group config.plugin_set(self.__class__.__name__, name, item) config.save() @@ -119,10 +124,10 @@ def menu(self, widget, terminal, data = None): - store = Gtk.TreeStore(str,str) - rabbit = store.append(None, ["Main","men"]) + store = Gtk.TreeStore(str,str,str) + rabbit = store.append(None, ["Main","blah","blah"]) for command in self.cmd_list: - store.append(rabbit,[command['name'], command['command']]) + store.append(rabbit,[command['name'], command['command'], command['group']]) treeview = Gtk.TreeView(store) selection = treeview.get_selection() @@ -175,10 +180,10 @@ def configure(self, widget, data = None): Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT ) ) - store = Gtk.ListStore(str, str) + store = Gtk.ListStore(str, str, str) for command in self.cmd_list: - store.append([command['name'], command['command']]) + store.append([command['name'], command['command'], command['group']]) treeview = Gtk.TreeView(store) #treeview.connect("cursor-changed", self.on_cursor_changed, ui) @@ -194,6 +199,10 @@ def configure(self, widget, data = None): renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn("Command", renderer, text=CC_COL_COMMAND) treeview.append_column(column) + + renderer = Gtk.CellRendererText() + column = Gtk.TreeViewColumn("Group", renderer, text=CC_COL_GROUP) + treeview.append_column(column) hbox = Gtk.HBox() hbox.pack_start(treeview, True, True, 0) @@ -252,12 +261,14 @@ def configure(self, widget, data = None): iter = store.get_iter_first() self.cmd_list = [] while iter: - (name, command) = store.get(iter, + (name, command, group) = store.get(iter, CC_COL_NAME, - CC_COL_COMMAND) + CC_COL_COMMAND, + CC_COL_GROUP) self.cmd_list.append( {'name': name, - 'command' : command} + 'command' : command, + 'group' : group} ) iter = store.iter_next(iter) self._save_config() @@ -282,7 +293,7 @@ def on_selection_changed(self,selection, data=None): data['button_edit'].set_sensitive(iter is not None) data['button_delete'].set_sensitive(iter is not None) - def _create_command_dialog(self, name_var = "", command_var = ""): + def _create_command_dialog(self, name_var = "", command_var = "", group_var = ""): dialog = Gtk.Dialog( _("New Command"), None, @@ -305,10 +316,16 @@ def _create_command_dialog(self, name_var = "", command_var = ""): command = Gtk.Entry() command.set_text(command_var) table.attach(command, 1, 2, 2, 3) + + label = Gtk.Label(label=_("Group:")) + table.attach(label, 0, 1, 3, 4) + group = Gtk.Entry() + command.set_text(group_var) + table.attach(group, 1, 2, 3, 4) dialog.vbox.pack_start(table, True, True, 0) dialog.show_all() - return (dialog,name,command) + return (dialog,name,command,group) def _error(self, msg): err = Gtk.MessageDialog(dialog, @@ -324,12 +341,13 @@ def _error(self, msg): def on_new(self, button, data): - (dialog,name,command) = self._create_command_dialog() + (dialog,name,command,group) = self._create_command_dialog() res = dialog.run() item = {} if res == Gtk.ResponseType.ACCEPT: item['name'] = name.get_text() item['command'] = command.get_text() + item['group'] = group.get_text() if item['name'] == '' or item['command'] == '': err = Gtk.MessageDialog(dialog, Gtk.DialogFlags.MODAL, @@ -350,7 +368,7 @@ def on_new(self, button, data): break iter = store.iter_next(iter) if not name_exist: - store.append((item['name'], item['command'])) + store.append((item['name'], item['command'], item['group'])) else: self._err(_("Name *%s* already exist") % item['name']) dialog.destroy() @@ -429,21 +447,23 @@ def on_edit(self, button, data): if not iter: return - (dialog,name,command) = self._create_command_dialog( + (dialog,name,command,group) = self._create_command_dialog( name_var = store.get_value(iter, CC_COL_NAME), - command_var = store.get_value(iter, CC_COL_COMMAND) + command_var = store.get_value(iter, CC_COL_COMMAND), + group_var = store.get_value(iter, CC_COL_GROUP) ) res = dialog.run() item = {} if res == Gtk.ResponseType.ACCEPT: item['name'] = name.get_text() item['command'] = command.get_text() - if item['name'] == '' or item['command'] == '': + item['group'] = group.get_text() + if item['name'] == '' or item['command'] == '' or item['group'] == '': err = Gtk.MessageDialog(dialog, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, - _("You need to define a name and command") + _("You need to define a name, command and group") ) err.run() err.destroy() @@ -458,7 +478,8 @@ def on_edit(self, button, data): if not name_exist: store.set(iter, CC_COL_NAME, item['name'], - CC_COL_COMMAND, item['command'] + CC_COL_COMMAND, item['command'], + CC_COL_GROUP, item['group'] ) else: self._err(_("Name *%s* already exist") % item['name']) From 67e22ffa17c8de02cfe621a839c285ce7507cabb Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Fri, 21 Apr 2017 22:08:43 +0000 Subject: [PATCH 05/13] Update README with dev instructions --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 07802c8..ec64877 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,22 @@ SSH Menu is a SSH menu plugin for Terminator v1.9 (ie GTK3 based versions) or la Install ------- -Installing SSH Menu is as simple as copying ssh_menu.py to ~/.config/terminator/plugins/ and reloading Terminator. +Installing SSH Menu is as simple as copying ssh_menu.py to ~/.config/terminator/plugins/ and then enabling it under Terminator's Plugins tab, under Preferences. How to use it ------------- -After copying ssh_menu to your terminator plugins dir, you should have a new 'SSH menu' option within the Terminator context menu. Selecting this menu option will open the SSH Menu window. From here you can use the 'Configure' button to add new commands to SSH menu. +Following installation, you should have a new 'SSH menu' option within the Terminator context (right click) menu. Selecting this menu option will open the SSH Menu window. From here you can use the 'Configure' button to add new commands to SSH menu. -Whilst it is expected most people will use this plugin to store and launch ssh sessions via ssh commands, it can be used to store and run any shell command. Due to the lack of encryption, 2FA etc it would be recommended you do not use this plugin to store passwords or other sensitive data. +Whilst it is expected most people will use this plugin to store and launch ssh sessions via ssh commands, it can be used to store and run any shell command. Due to the lack of encryption, it is recommended you do not use this plugin to store passwords or other sensitive data. Note that you currently need to close and re-open the SSH Menu window before newly added commands are displayed and deleted commands get removed. + +Development +----------- + +If you want to debug or help develop this plugin, start Terminator from any non-Terminator terminal emulator with the command: + + terminator -dd --debug-classes SSHMenu + +Like terminator, this plugin was created with Python 2 and GTK 3. From b42a8dd25cbced55f38d261609dadccbfe5d9678 Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Fri, 21 Apr 2017 22:13:10 +0000 Subject: [PATCH 06/13] README formatting --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ec64877..ba7079c 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ SSH Menu SSH Menu is a SSH menu plugin for Terminator v1.9 (ie GTK3 based versions) or later. -Install -------- +Installation +------------ Installing SSH Menu is as simple as copying ssh_menu.py to ~/.config/terminator/plugins/ and then enabling it under Terminator's Plugins tab, under Preferences. @@ -22,6 +22,8 @@ Development If you want to debug or help develop this plugin, start Terminator from any non-Terminator terminal emulator with the command: - terminator -dd --debug-classes SSHMenu +``` +terminator -dd --debug-classes SSHMenu +``` Like terminator, this plugin was created with Python 2 and GTK 3. From 04befeda80d852416d8f7123f7a389b26dfd11ec Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Sat, 22 Apr 2017 08:48:22 +0000 Subject: [PATCH 07/13] Show command groups in separate tree views --- ssh_menu.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ssh_menu.py b/ssh_menu.py index d2a18f3..f5a5366 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -122,12 +122,19 @@ def menu(self, widget, terminal, data = None): buttonsbox.pack_end(buttonPreferences, True, False, 0) box1.pack_start(buttonsbox, False, False, 0) - + allgroups = [] + groupnum = len(self.cmd_list) + for elem in range(groupnum): + allgroups.append(self.cmd_list[elem]['group']) + groups = list(set(allgroups)) store = Gtk.TreeStore(str,str,str) - rabbit = store.append(None, ["Main","blah","blah"]) - for command in self.cmd_list: - store.append(rabbit,[command['name'], command['command'], command['group']]) + + for group in groups: + rabbit = store.append(None, [group,"blah","blah"]) + subgroup = [d for d in self.cmd_list if d['group'] == group] + for command in subgroup: + store.append(rabbit,[command['name'], command['command'], command['group']]) treeview = Gtk.TreeView(store) selection = treeview.get_selection() From 2beeed31cc37a5fbc674fe26df84afe61a42b491 Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Mon, 24 Apr 2017 11:51:46 +0100 Subject: [PATCH 08/13] Change main window column label to Groups --- ssh_menu.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ssh_menu.py b/ssh_menu.py index f5a5366..575a12a 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -80,8 +80,8 @@ def _save_config(self): i = i + 1 - def _save_order(self,selection, data): - print "todo!" + #def _save_order(self,selection, data): + # print "todo!" def _execute(self, treeview, path, view_column, data): @@ -140,12 +140,12 @@ def menu(self, widget, terminal, data = None): selection = treeview.get_selection() selection.set_mode(Gtk.SelectionMode.SINGLE) - selection.connect("changed", self._save_order, {'terminal' : terminal, 'selection' : selection }) + #selection.connect("changed", self._save_order, {'terminal' : terminal, 'selection' : selection }) treeview.connect("row-activated", self._execute, {'terminal' : terminal, 'selection' : selection }) ui['treeview'] = treeview renderer = Gtk.CellRendererText() - column = Gtk.TreeViewColumn("Hosts", renderer, text=CC_COL_NAME) + column = Gtk.TreeViewColumn("Groups", renderer, text=CC_COL_NAME) treeview.append_column(column) From ecb9e3f696fa066aef18701269276c19b1107da5 Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Mon, 24 Apr 2017 12:26:21 +0100 Subject: [PATCH 09/13] New command window errors on empty group dialog --- ssh_menu.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssh_menu.py b/ssh_menu.py index 575a12a..43d6b2e 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -355,12 +355,12 @@ def on_new(self, button, data): item['name'] = name.get_text() item['command'] = command.get_text() item['group'] = group.get_text() - if item['name'] == '' or item['command'] == '': + if item['name'] == '' or item['command'] == '' or item['group'] == '': err = Gtk.MessageDialog(dialog, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, - _("You need to define a name and command") + _("You need to define a name, command and group") ) err.run() err.destroy() From 08cf2ecefc8e5734a65711dca8a02aee6b5f8715 Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Mon, 24 Apr 2017 13:33:40 +0100 Subject: [PATCH 10/13] Fix command editing --- ssh_menu.py | 85 ++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/ssh_menu.py b/ssh_menu.py index 43d6b2e..fa6777d 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -327,7 +327,7 @@ def _create_command_dialog(self, name_var = "", command_var = "", group_var = "" label = Gtk.Label(label=_("Group:")) table.attach(label, 0, 1, 3, 4) group = Gtk.Entry() - command.set_text(group_var) + group.set_text(group_var) table.attach(group, 1, 2, 3, 4) dialog.vbox.pack_start(table, True, True, 0) @@ -447,51 +447,50 @@ def on_delete(self, button, data): return def on_edit(self, button, data): - treeview = data['treeview'] - selection = treeview.get_selection() - (store, iter) = selection.get_selected() - - if not iter: - return - - (dialog,name,command,group) = self._create_command_dialog( + treeview = data['treeview'] + selection = treeview.get_selection() + (store, iter) = selection.get_selected() + + if not iter: + return + + (dialog,name,command,group) = self._create_command_dialog( name_var = store.get_value(iter, CC_COL_NAME), command_var = store.get_value(iter, CC_COL_COMMAND), group_var = store.get_value(iter, CC_COL_GROUP) - ) - res = dialog.run() - item = {} - if res == Gtk.ResponseType.ACCEPT: - item['name'] = name.get_text() - item['command'] = command.get_text() - item['group'] = group.get_text() - if item['name'] == '' or item['command'] == '' or item['group'] == '': - err = Gtk.MessageDialog(dialog, - Gtk.DialogFlags.MODAL, - Gtk.MessageType.ERROR, - Gtk.ButtonsType.CLOSE, - _("You need to define a name, command and group") - ) - err.run() - err.destroy() - else: - tmpiter = store.get_iter_first() - name_exist = False - while tmpiter != None: - if store.get_path(tmpiter) != store.get_path(iter) and store.get_value(tmpiter,CC_COL_NAME) == item['name']: - name_exist = True - break - tmpiter = store.iter_next(tmpiter) - if not name_exist: - store.set(iter, - CC_COL_NAME, item['name'], - CC_COL_COMMAND, item['command'], - CC_COL_GROUP, item['group'] - ) - else: - self._err(_("Name *%s* already exist") % item['name']) - - dialog.destroy() + ) + res = dialog.run() + item = {} + if res == Gtk.ResponseType.ACCEPT: + item['name'] = name.get_text() + item['command'] = command.get_text() + item['group'] = group.get_text() + if item['name'] == '' or item['command'] == '' or item['group'] == '': + err = Gtk.MessageDialog(dialog, + Gtk.DialogFlags.MODAL, + Gtk.MessageType.ERROR, + Gtk.ButtonsType.CLOSE, + _("You need to define a name, command and group") + ) + err.run() + err.destroy() + else: + tmpiter = store.get_iter_first() + name_exist = False + while tmpiter != None: + if store.get_path(tmpiter) != store.get_path(iter) and store.get_value(tmpiter,CC_COL_NAME) == item['name']: + name_exist = True + break + tmpiter = store.iter_next(tmpiter) + if not name_exist: + store.set(iter, + CC_COL_NAME, item['name'], + CC_COL_COMMAND, item['command'], + CC_COL_GROUP, item['group'] + ) + else: + self._err(_("Name *%s* already exist") % item['name']) + dialog.destroy() if __name__ == '__main__': From e43175ba4e88d4890c10ae714b3fe83f09cab285 Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Tue, 25 Apr 2017 10:42:45 +0100 Subject: [PATCH 11/13] Fix deleting of commands --- ssh_menu.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ssh_menu.py b/ssh_menu.py index fa6777d..7bbd051 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -63,6 +63,8 @@ def callback(self, menuitems, menu, terminal): def _save_config(self): config = Config() + config.plugin_del_config(self.__class__.__name__) + config.save() i = 0 length = len(self.cmd_list) while i < length: From f670333d21bf609f015058b536de1c14de200acd Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Wed, 26 Apr 2017 11:17:31 +0100 Subject: [PATCH 12/13] Remove tabs and reinstate GPLv2 license notification --- ssh_menu.py | 97 +++++++++++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 48 deletions(-) diff --git a/ssh_menu.py b/ssh_menu.py index 7bbd051..3ed288a 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -1,3 +1,6 @@ +#!/usr/bin/python +# Terminator by Chris Jones, Stephen Boddy et al +# GPL v2 only # ssh_menu.py - Terminator plugin to add an SSH / command menu # # Original version by Mario Lameiras, 2014 @@ -127,16 +130,16 @@ def menu(self, widget, terminal, data = None): allgroups = [] groupnum = len(self.cmd_list) for elem in range(groupnum): - allgroups.append(self.cmd_list[elem]['group']) + allgroups.append(self.cmd_list[elem]['group']) groups = list(set(allgroups)) store = Gtk.TreeStore(str,str,str) for group in groups: - rabbit = store.append(None, [group,"blah","blah"]) - subgroup = [d for d in self.cmd_list if d['group'] == group] - for command in subgroup: - store.append(rabbit,[command['name'], command['command'], command['group']]) + rabbit = store.append(None, [group,"blah","blah"]) + subgroup = [d for d in self.cmd_list if d['group'] == group] + for command in subgroup: + store.append(rabbit,[command['name'], command['command'], command['group']]) treeview = Gtk.TreeView(store) selection = treeview.get_selection() @@ -449,50 +452,48 @@ def on_delete(self, button, data): return def on_edit(self, button, data): - treeview = data['treeview'] - selection = treeview.get_selection() - (store, iter) = selection.get_selected() - - if not iter: - return - - (dialog,name,command,group) = self._create_command_dialog( + treeview = data['treeview'] + selection = treeview.get_selection() + (store, iter) = selection.get_selected() + + if not iter: + return + + (dialog,name,command) = self._create_command_dialog( name_var = store.get_value(iter, CC_COL_NAME), - command_var = store.get_value(iter, CC_COL_COMMAND), - group_var = store.get_value(iter, CC_COL_GROUP) - ) - res = dialog.run() - item = {} - if res == Gtk.ResponseType.ACCEPT: - item['name'] = name.get_text() - item['command'] = command.get_text() - item['group'] = group.get_text() - if item['name'] == '' or item['command'] == '' or item['group'] == '': - err = Gtk.MessageDialog(dialog, - Gtk.DialogFlags.MODAL, - Gtk.MessageType.ERROR, - Gtk.ButtonsType.CLOSE, - _("You need to define a name, command and group") - ) - err.run() - err.destroy() - else: - tmpiter = store.get_iter_first() - name_exist = False - while tmpiter != None: - if store.get_path(tmpiter) != store.get_path(iter) and store.get_value(tmpiter,CC_COL_NAME) == item['name']: - name_exist = True - break - tmpiter = store.iter_next(tmpiter) - if not name_exist: - store.set(iter, - CC_COL_NAME, item['name'], - CC_COL_COMMAND, item['command'], - CC_COL_GROUP, item['group'] - ) - else: - self._err(_("Name *%s* already exist") % item['name']) - dialog.destroy() + command_var = store.get_value(iter, CC_COL_COMMAND) + ) + res = dialog.run() + item = {} + if res == Gtk.ResponseType.ACCEPT: + item['name'] = name.get_text() + item['command'] = command.get_text() + if item['name'] == '' or item['command'] == '': + err = Gtk.MessageDialog(dialog, + Gtk.DialogFlags.MODAL, + Gtk.MessageType.ERROR, + Gtk.ButtonsType.CLOSE, + _("You need to define a name and command") + ) + err.run() + err.destroy() + else: + tmpiter = store.get_iter_first() + name_exist = False + while tmpiter != None: + if store.get_path(tmpiter) != store.get_path(iter) and store.get_value(tmpiter,CC_COL_NAME) == item['name']: + name_exist = True + break + tmpiter = store.iter_next(tmpiter) + if not name_exist: + store.set(iter, + CC_COL_NAME, item['name'], + CC_COL_COMMAND, item['command'] + ) + else: + self._err(_("Name *%s* already exist") % item['name']) + + dialog.destroy() if __name__ == '__main__': From 69c5012e30203c816c708f0593fc6b9cf39942af Mon Sep 17 00:00:00 2001 From: Dan MacDonald Date: Wed, 26 Apr 2017 11:42:57 +0100 Subject: [PATCH 13/13] Reinstate command editing --- ssh_menu.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ssh_menu.py b/ssh_menu.py index 3ed288a..a9aedcf 100644 --- a/ssh_menu.py +++ b/ssh_menu.py @@ -459,21 +459,23 @@ def on_edit(self, button, data): if not iter: return - (dialog,name,command) = self._create_command_dialog( + (dialog,name,command,group) = self._create_command_dialog( name_var = store.get_value(iter, CC_COL_NAME), - command_var = store.get_value(iter, CC_COL_COMMAND) + command_var = store.get_value(iter, CC_COL_COMMAND), + group_var = store.get_value(iter, CC_COL_GROUP) ) res = dialog.run() item = {} if res == Gtk.ResponseType.ACCEPT: item['name'] = name.get_text() item['command'] = command.get_text() - if item['name'] == '' or item['command'] == '': + item['group'] = group.get_text() + if item['name'] == '' or item['command'] == '' or item['group'] == '': err = Gtk.MessageDialog(dialog, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, - _("You need to define a name and command") + _("You need to define a name, command and group") ) err.run() err.destroy() @@ -488,7 +490,8 @@ def on_edit(self, button, data): if not name_exist: store.set(iter, CC_COL_NAME, item['name'], - CC_COL_COMMAND, item['command'] + CC_COL_COMMAND, item['command'], + CC_COL_GROUP, item['group'] ) else: self._err(_("Name *%s* already exist") % item['name'])