clicompanion-devs team mailing list archive
-
clicompanion-devs team
-
Mailing list archive
-
Message #00273
[Merge] lp:~dcaro/clicompanion/fix-910355 into lp:clicompanion
David Caro has proposed merging lp:~dcaro/clicompanion/fix-910355 into lp:clicompanion.
Requested reviews:
CLI Companion Development Team (clicompanion-devs)
Related bugs:
Bug #611141 in CLI Companion: "It is not obvious that "q" must be pressed to exit help (man pages)"
https://bugs.launchpad.net/clicompanion/+bug/611141
Bug #801906 in CLI Companion: "clicompanion crashes on start with ValueError in _get()"
https://bugs.launchpad.net/clicompanion/+bug/801906
Bug #909894 in CLI Companion: "Double click execution with user input drags command"
https://bugs.launchpad.net/clicompanion/+bug/909894
Bug #910249 in CLI Companion: "Warning window (when wrong params issued) not working properly"
https://bugs.launchpad.net/clicompanion/+bug/910249
Bug #910355 in CLI Companion: "Properties are not applied to the current terminal"
https://bugs.launchpad.net/clicompanion/+bug/910355
Bug #910360 in CLI Companion: "Incorrect .clicompanion2 file causes the program to crash"
https://bugs.launchpad.net/clicompanion/+bug/910360
Bug #910370 in CLI Companion: "Drag and drop when searching breaks the drag and drop"
https://bugs.launchpad.net/clicompanion/+bug/910370
Bug #910531 in CLI Companion: "Allowed empty user input"
https://bugs.launchpad.net/clicompanion/+bug/910531
Bug #910533 in CLI Companion: "In a fresh start, when executting the first command, the second gets executed instead"
https://bugs.launchpad.net/clicompanion/+bug/910533
For more details, see:
https://code.launchpad.net/~dcaro/clicompanion/fix-910355/+merge/87218
Done a lot of improvements and code refactoring.
Also solved a lot of bugs.
The problem was that the bugs that I resolved one by one, where easily resolved together (also I resolved some other bugs that seemed easy).
Please do a full testing of the program, because a lot of things changed, and is possible that new bug may have been created. I tested myself and I will be testing it from now on, but two (or more than one) heads are better for doing so.
Also, taken back all the conflicting merge proposals, to avoid double merging of fixes.
Thanks,
David
--
https://code.launchpad.net/~dcaro/clicompanion/fix-910355/+merge/87218
Your team CLI Companion Development Team is requested to review the proposed merge of lp:~dcaro/clicompanion/fix-910355 into lp:clicompanion.
=== modified file 'clicompanion'
--- clicompanion 2011-12-31 12:33:51 +0000
+++ clicompanion 2012-01-02 01:28:26 +0000
@@ -6,7 +6,6 @@
import sys
from optparse import OptionParser
-from clicompanionlib.view import run
share_dirs = os.environ.get('XDG_BASE_PDATA',
'/usr/local/share:/usr/share').split(os.pathsep)
@@ -27,10 +26,12 @@
parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.1")
parser.add_option("-f", "--file", dest="filename",
- help="write report to FILE", metavar="FILE")
+ help="Write report to FILE", metavar="FILE")
+parser.add_option("-c", "--cheatsheet", dest="cheatsheet",
+ help="Read cheatsheet from FILE", metavar="FILE")
parser.add_option("-q", "--quiet",
action="store_false", dest="verbose", default=True,
- help="don't print status messages to stdout")
+ help="Don't print status messages to stdout")
(options, args) = parser.parse_args()
@@ -62,4 +63,5 @@
if __name__ == "__main__":
- run()
+ from clicompanionlib.view import run
+ run( options )
=== modified file 'clicompanionlib/config.py'
--- clicompanionlib/config.py 2011-03-12 16:08:24 +0000
+++ clicompanionlib/config.py 2012-01-02 01:28:26 +0000
@@ -20,33 +20,244 @@
#
import os
import ConfigParser
+import clicompanionlib.utils as utils
+from clicompanionlib.utils import dbg
+import collections
+CHEATSHEET = os.path.expanduser("~/.clicompanion2")
CONFIGDIR = os.path.expanduser("~/.config/clicompanion/")
CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config")
-
-class Config(object):
-
- '''
- create configuration file
- '''
-
- def create_config(self):
-
- if not os.path.exists(CONFIGFILE):
- os.makedirs(CONFIGDIR)
- config = ConfigParser.ConfigParser()
- # set a number of parameters
+CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
+DEFAULTS = { "scrollb": '500',
+ "colorf": '#FFFFFF',
+ "colorb": '#000000',
+ "encoding": 'UTF-8',
+ "debug": 'False'}
+
+## To avoid parsing the config file each time, we store the loaded config here
+CONFIG = None
+
+def create_config(conffile=CONFIGFILE):
+ global CONFIG
+ config = CONFIG
+ configdir = conffile.rsplit(os.sep,1)[0]
+ if not os.path.exists(configdir):
+ try:
+ os.makedirs(configdir)
+ except Exception, e:
+ print _('Unable to create config at dir %s (%s)')%(configdir,e)
+ return False
+ # reuse the config if able
+ if not config:
+ config = ConfigParser.SafeConfigParser(DEFAULTS)
+ # set a number of parameters
+ if os.path.isfile(conffile):
+ config.read([conffile])
+ else:
config.add_section("terminal")
- config.set("terminal", "scrollb", 500)
- config.set("terminal", "colorf", '#FFFFFF')
- config.set("terminal", "colorb", '#000000')
- config.set("terminal", "encoding", 'utf-8')
- # Writing our configuration file
- with open(CONFIGFILE, 'wb') as f:
- config.write(f)
-
- else:
- pass
-
-
-
+ for option, value in DEFAULTS.items():
+ config.set("terminal", option, value)
+ CONFIG = config
+ # Writing our configuration file
+ save_config(config, conffile)
+ print _("INFO: Created config file at %s.")%conffile
+ return config
+
+
+def get_config_copy(config=None):
+ global CONFIG
+ if not config:
+ config = CONFIG
+ new_cfg = ConfigParser.SafeConfigParser(DEFAULTS)
+ for section in config.sections():
+ new_cfg.add_section(section)
+ for option in config.options(section):
+ new_cfg.set(section, option, config.get(section, option))
+ return new_cfg
+
+
+def get_config(conffile=CONFIGFILE, confdir=CONFIGDIR):
+ global CONFIG
+ config = CONFIG
+ if not config:
+ dbg('Loading new config')
+ if not os.path.isfile(conffile):
+ config = create_config(conffile)
+ config = ConfigParser.SafeConfigParser(DEFAULTS)
+ config.add_section("terminal")
+ config.read([conffile])
+ CONFIG = config
+ else:
+ dbg('Reusing already loaded config')
+ return config
+
+
+def save_config(config, conffile=CONFIGFILE):
+ global CONFIG
+ dbg('Saving conffile at %s'%conffile)
+ with open(CONFIGFILE, 'wb') as f:
+ config.write(f)
+ CONFIG = config
+
+class Cheatsheet:
+ '''
+ comtainer class for the cheatsheet
+
+ Example of usage:
+ >>> c = config.Cheatsheet()
+ >>> c.load('/home/cascara/.clicompanion2')
+ >>> c[3]
+ ['uname -a', '', 'What kernel am I running\n']
+ >>> c.file
+ '/home/cascara/.clicompanion2'
+ >>> c[2]=[ 'mycmd', 'userui', 'desc' ]
+ >>> c[2]
+ ['mycmd', 'userui', 'desc']
+ >>> del c[2]
+ >>> c[2]
+ ['ps aux | grep ?', 'search string', 'Search active processes for search string\n']
+ >>> c.insert('cmd2','ui2','desc2',2)
+ >>> c[2]
+ ['cmd2', 'ui2', 'desc2']
+
+ '''
+ def __init__(self):
+ self.file = CHEATSHEET
+ self.commands = []
+
+ def __repr__(self):
+ return 'Config: %s - %s'%(self.file, self.commands)
+
+ def load(self, cheatfile=None):
+ if not cheatfile:
+ self.file = CHEATSHEET
+ if not os.path.exists(CHEATSHEET):
+ if os.path.exists(CONFIG_ORIG):
+ os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
+ else:
+ # Oops! Looks like there's no default cheatsheet.
+ # Then, create an empty cheatsheet.
+ open(CHEATSHEET, 'w').close()
+ else:
+ self.file = cheatfile
+ try:
+ dbg('Reading cheatsheet from file %s'%self.file)
+ with open(self.file, 'r') as ch_fd:
+ ## try to detect if the line is a old fashines config line
+ ## (separated by ':'), when saved will rewrite it
+ no_tabs = True
+ some_colon = False
+ for line in ch_fd:
+ line = line.strip()
+ if not line:
+ continue
+ cmd, ui, desc = [ l.strip() for l in line.split('\t',2)] \
+ + ['',]*(3-len(line.split('\t',2)))
+ if ':' in cmd:
+ some_colon = True
+ if ui or desc:
+ no_tabs = False
+ if cmd and [ cmd, ui, desc ] not in self.commands:
+ self.commands.append([cmd, ui, desc])
+ dbg('Adding command %s'%[cmd, ui, desc])
+ if no_tabs and some_colon:
+ ## None of the commands had tabs, and all had ':' in the
+ ## cmd... most probably old config style
+ print _("Detected old cheatsheet style at")\
+ +" %s"%self.file+_(", parsing to new one.")
+ for i in range(len(self.commands)):
+ cmd, ui, desc = self.commands[i]
+ cmd, ui, desc = [ l.strip() for l in cmd.split(':',2)] \
+ + ['',]*(3-len(cmd.split(':',2)))
+ self.commands[i] = [cmd, ui, desc]
+ self.save()
+ except IOError, e:
+ print _("Error while loading cheatfile")+" %s: %s"%(self.file, e)
+
+ def save(self, cheatfile=None):
+ '''
+ Saves the current config to the file cheatfile, or the file that was
+ loaded.
+ NOTE: It does not overwrite the value self.file, that points to the file
+ that was loaded
+ '''
+ if not cheatfile and self.file:
+ cheatfile = self.file
+ elif not cheatfile:
+ return False
+ try:
+ with open(cheatfile, 'wb') as ch_fd:
+ for command in self.commands:
+ ch_fd.write('\t'.join(command)+'\n')
+ except IOError, e:
+ print _("Error writing cheatfile")+" %s: %s"%(cheatfile, e)
+ return False
+ return True
+
+ def __len__(self):
+ return len(self.commands)
+
+ def __getitem__(self, key):
+ return self.commands[key]
+
+ def __setitem__(self, key, value):
+ if not isinstance(value, collections.Iterable) or len(value) < 3:
+ raise ValueError('Value must be a container with three items, but got %s'%value)
+ if key < len(self.commands):
+ self.commands[key]=list(value)
+ else:
+ try:
+ self.insert(*value, pos=key)
+ except ValueError, e:
+ raise ValueError('Value must be a container with three items, but got %s'%value)
+
+ def __iter__(self):
+ for command in self.commands:
+ yield command
+
+ def insert(self, cmd, ui, desc, pos=None):
+ if not [cmd, ui, desc] in self.commands:
+ if not pos:
+ self.commands.append([cmd, ui, desc])
+ else:
+ self.commands.insert(pos, [cmd, ui, desc])
+
+ def append(self, cmd, ui, desc):
+ self.insert(cmd, ui, desc)
+
+ def index(self, cmd, ui, value):
+ return self.commands.index([cmd, ui, desc])
+
+ def __delitem__(self, key):
+ del self.commands[key]
+
+ def pop(self, key):
+ return self.commands.pop(key)
+
+ def del_by_value(self, cmd, ui, desc):
+ if [cmd, ui, desc] in self.commands:
+ return self.commands.pop(self.commands.index([cmd, ui, desc]))
+
+ def drag_n_drop(self, cmd1, cmd2, before=True):
+ if cmd1 in self.commands:
+ dbg('Dropping command from inside %s'%'_\t_'.join(cmd1))
+ i1 = self.commands.index(cmd1)
+ del self.commands[i1]
+ if cmd2:
+ i2 = self.commands.index(cmd2)
+ if before:
+ self.commands.insert(i2, cmd1)
+ else:
+ self.commands.insert(i2+1, cmd1)
+ else:
+ self.commands.append(cmd1)
+ else:
+ dbg('Dropping command from outside %s'%'_\t_'.join(cmd1))
+ if cmd2:
+ i2 = self.commands.index(cmd2)
+ if before:
+ self.commands.insert(i2, cmd1)
+ else:
+ self.commands.insert(i2+1, cmd1)
+ else:
+ self.commands.append(cmd1)
=== modified file 'clicompanionlib/controller.py'
--- clicompanionlib/controller.py 2011-12-31 14:49:46 +0000
+++ clicompanionlib/controller.py 2012-01-02 01:28:26 +0000
@@ -19,17 +19,21 @@
#
#
-from clicompanionlib.utils import get_user_shell
-
-import clicompanionlib.tabs
-import view
-
+import os
import pygtk
pygtk.require('2.0')
import re
import webbrowser
-import ConfigParser
-import os
+import view
+import copy
+import clicompanionlib.tabs
+import clicompanionlib.config as cc_config
+import clicompanionlib.utils as utils
+from clicompanionlib.utils import get_user_shell, dbg
+
+#if cc_config.get_config().get('terminal','debug') == 'True':
+# utils.DEBUG = True
+
# import vte and gtk or print error
try:
import gtk
@@ -49,27 +53,17 @@
-CHEATSHEET = os.path.expanduser("~/.clicompanion2")
-CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
-CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config")
-
class Actions(object):
- #make instances of the Classes we are going to use
- #main_window = view.MainWindow
## Info Dialog Box
## if a command needs more info EX: a package name, a path
- def get_info(self, widget, liststore):
-
- if not view.ROW:
- return
- row_int = int(view.ROW[0][0])
-
+ def get_info(self, cmd, ui, desc):
+ dbg('Got command with user input')
## Create Dialog object
dialog = gtk.MessageDialog(
None,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_QUESTION,
- gtk.BUTTONS_OK,
+ gtk.BUTTONS_OK_CANCEL,
None)
# Primary text
@@ -82,16 +76,16 @@
## create a horizontal box to pack the entry and a label
hbox = gtk.HBox()
- hbox.pack_start(gtk.Label(liststore[row_int][1]+":"), False, 5, 5)
+ hbox.pack_start(gtk.Label(ui+":"), False, 5, 5)
hbox.pack_end(entry)
## some secondary text
- dialog.format_secondary_markup(_("Please provide a "+liststore[row_int][1]))
+ dialog.format_secondary_markup(_("Please provide a "+ui))
## add it and show it
dialog.vbox.pack_end(hbox, True, True, 0)
dialog.show_all()
## Show the dialog
- dialog.run()
+ response = dialog.run()
## user text assigned to a variable
text = entry.get_text()
@@ -100,13 +94,15 @@
## The destroy method must be called otherwise the 'Close' button will
## not work.
dialog.destroy()
+ if response != gtk.RESPONSE_OK:
+ user_input = None
return user_input
def responseToDialog(self, text, dialog, response):
dialog.response(response)
## Add command dialog box
- def add_command(self, widget, liststore):
+ def add_command(self, mw):
## Create Dialog object
dialog = gtk.MessageDialog(
@@ -141,15 +137,16 @@
hbox2.pack_start(entry3, True, 5, 5)
## cancel button
- dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
+ dialog.add_button(_('Cancel'), gtk.RESPONSE_DELETE_EVENT)
## some secondary text
- dialog.format_secondary_markup(_('When entering a command use question '
- 'marks(?) as placeholders if user input is required when the '
- 'command runs. Example: ls /any/directory would be entered as, '
- 'ls ? .For each question mark(?) in your command, if any, use '
- 'the User Input field to provide a hint for each variable. '
- 'Using our example ls ? you could put directory as the User '
- 'Input. Lastly provide a brief Description.'))
+ dialog.format_secondary_markup(
+ _("When entering a command use question marks(?) as placeholders if"
+ " user input is required when the command runs. Example: ls "
+ "/any/directory would be entered as, ls ? .For each question "
+ "mark(?) in your command, if any, use the User Input field to "
+ "provide a hint for each variable. Using our example ls ? you "
+ "could put directory as the User Input. Lastly provide a brief "
+ "Description."))
## add it and show it
dialog.vbox.pack_end(hbox2, True, True, 0)
@@ -163,24 +160,10 @@
text1 = entry1.get_text()
text2 = entry2.get_text()
text3 = entry3.get_text()
- '''open flat file, add the new command, update CMNDS variable
- ## update commands in liststore (on screen) '''
- if text1 != "":
- with open(CHEATSHEET, "r") as cheatfile:
- cheatlines = cheatfile.readlines()
- cheatlines.append(text1+"\t"+text2+"\t"+text3+'\n')
- cheatfile.close()
- with open(CHEATSHEET, "w") as cheatfile2:
- cheatfile2.writelines(cheatlines)
- cheatfile2.close()
- l = str(text1+"\t"+text2+"\t"+text3)
- #ls = l.split(':',2)
- ## update view.CMNDS variable
- filteredcommandplus = text1, text2, text3
- view.CMNDS.append(filteredcommandplus)
- ## update the command list on screen
- liststore.append([text1,text2,text3])
-
+ ## update commandsand sync with screen '''
+ view.CMNDS.append(text1, text2, text3)
+ mw.sync_cmnds()
+ view.CMNDS.save()
## The destroy method must be called otherwise the 'Close' button will
## not work.
@@ -188,32 +171,14 @@
#return text
## This the edit function
- def edit_command(self, widget , liststore):
-
+ def edit_command(self, mw):
if not view.ROW:
return
- row_int_x = int(view.ROW[0][0])
- row_int = 0
- ## TODO: Not implemented with filted yet
- if view.FILTER == 1:
- with open(CHEATSHEET, "r") as cheatfile:
- cheatlines = cheatfile.readlines()
- for i in range(len(cheatlines)):
- if view.CMNDS[row_int_x][0] in cheatlines[i] and view.CMNDS[row_int_x][1] in cheatlines[i] :
- row_int = i
- cheatfile.close()
- else:
- row_int = row_int_x
-
-
- row_obj1 = view.MainWindow.liststore[row_int][0]
- text1 = "".join(row_obj1)
-
- row_obj2 = view.MainWindow.liststore[row_int][1]
- text2 = "".join(row_obj2)
-
- row_obj3 = view.MainWindow.liststore[row_int][2]
- text3 = "".join(row_obj3)
+ lst_index = int(view.ROW[0][0])
+ model = mw.treeview.get_model()
+ cmd = ''.join(model[lst_index][0])
+ ui = ''.join(model[lst_index][1])
+ desc = ''.join(model[lst_index][2])
## Create Dialog object
dialog = gtk.MessageDialog(
@@ -228,11 +193,11 @@
## create the text input fields
entry1 = gtk.Entry()
- entry1.set_text(text1)
+ entry1.set_text(cmd)
entry2 = gtk.Entry()
- entry2.set_text(text2)
+ entry2.set_text(ui)
entry3 = gtk.Entry()
- entry3.set_text(text3)
+ entry3.set_text(desc)
## allow the user to press enter to do ok
entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
@@ -249,7 +214,7 @@
hbox2.pack_start(entry3, True, 5, 5)
## cancel button
- dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
+ dialog.add_button(_('Cancel'), gtk.RESPONSE_DELETE_EVENT)
## some secondary text
dialog.format_secondary_markup(_("Please provide a command, description, and what type of user variable, if any, is required."))
@@ -262,64 +227,35 @@
if result == gtk.RESPONSE_OK:
## user text assigned to a variable
- text1 = entry1.get_text()
- text2 = entry2.get_text()
- text3 = entry3.get_text()
+ cmd = entry1.get_text()
+ ui = entry2.get_text()
+ desc = entry3.get_text()
- if text1 != "":
- self.remove_command(widget, liststore)
- '''open flat file, add the new command, update CMNDS variable
- ## update commands in liststore (on screen) '''
-
- with open(CHEATSHEET, "r") as cheatfile:
- cheatlines = cheatfile.readlines()
- cheatlines.append(text1+":"+text2+":"+text3+'\n')
- cheatfile.close()
- with open(CHEATSHEET, "w") as cheatfile2:
- cheatfile2.writelines(cheatlines)
- cheatfile2.close()
- l = str(text1+":"+text2+":"+text3)
- #ls = l.split(':',2)
- ## update view.CMNDS variable
- filteredcommandplus = text1, text2, text3
- view.CMNDS.append(filteredcommandplus)
- ## update the command list on screen
- liststore.append([text1,text2,text3])
-
+ if cmd != "":
+ cmd_index = model[lst_index][3]
+ dbg('Got index %d for command at pos %d'%(cmd_index, lst_index))
+ view.CMNDS[cmd_index] = [cmd, ui, desc]
+ mw.sync_cmnds()
+ view.CMNDS.save()
## The destroy method must be called otherwise the 'Close' button will
## not work.
dialog.destroy()
## Remove command from command file and GUI
- def remove_command(self, widget, liststore):
-
+ def remove_command(self, mw):
if not view.ROW:
return
- row_int_x = int(view.ROW[0][0])
- row_int = 0
- ## TODO: Not implemented with filted yet
- if view.FILTER == 1:
- with open(CHEATSHEET, "r") as cheatfile:
- cheatlines = cheatfile.readlines()
- for i in range(len(cheatlines)):
- if view.CMNDS[row_int_x][0] in cheatlines[i] and view.CMNDS[row_int_x][1] in cheatlines[i]:
- row_int = i
- cheatfile.close()
- else:
- row_int = row_int_x
-
- del view.CMNDS[row_int_x]
- del liststore[row_int]
-
- ## open command file and delete line so the change is persistent
- with open(CHEATSHEET, "r") as cheatfile:
- cheatlines = cheatfile.readlines()
- del cheatlines[row_int]
- cheatfile.close()
- with open(CHEATSHEET, "w") as cheatfile2:
- cheatfile2.writelines(cheatlines)
- cheatfile2.close()
+ ## get selected row
+ lst_index = int(view.ROW[0][0])
+ ## get selected element index, even from search filter
+ model = mw.treeview.get_model()
+ cmd_index = model[lst_index][3]
+ ## delete element from liststore and CMNDS
+ del view.CMNDS[cmd_index]
+ mw.sync_cmnds()
+ ## save changes
+ view.CMNDS.save()
def _filter_commands(self, widget, liststore, treeview):
@@ -330,11 +266,13 @@
Pretty straight-forward.
"""
search_term = widget.get_text().lower()
+ ## If the search term is empty, restore the liststore
if search_term == "":
- view.FILTER = 0
- else:
- view.FILTER = 1
-
+ view.FILTER = 0
+ treeview.set_model(liststore)
+ return
+
+ view.FILTER = 1
## Create a TreeModelFilter object which provides auxiliary functions for
## filtering data.
## http://www.pygtk.org/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html
@@ -356,39 +294,31 @@
## Python raises a AttributeError if row data was modified . Catch
## that and fail silently.
pass
-
-
modelfilter.set_visible_func(search, search_term)
+ ## save the old liststore and cmnds
treeview.set_model(modelfilter)
-
-
- #clear CMNDS list then populate it with the filteredlist of commands
- view.CMNDS = []
- for line in modelfilter:
- filteredcommandplus = tuple(modelfilter.get(line.iter, 0, 1, 2))
- view.CMNDS.append(filteredcommandplus)
-
-
## send the command to the terminal
- def run_command(self, widget, notebook, liststore):
+ def run_command(self, mw):
## if called without selecting a command from the list return
if not view.ROW:
return
text = ""
- row_int = int(view.ROW[0][0]) ## removes everything but number from [5,]
+ lst_index = int(view.ROW[0][0]) ## removes everything but number from [5,]
## get the current notebook page so the function knows which terminal to run the command in.
- pagenum = notebook.get_current_page()
- widget = notebook.get_nth_page(pagenum)
+ pagenum = mw.notebook.get_current_page()
+ widget = mw.notebook.get_nth_page(pagenum)
page_widget = widget.get_child()
- ## view.CMNDS is where commands are stored
- cmnd = view.CMNDS[row_int][0]
+ model = mw.treeview.get_model()
+ cmd = ''.join(model[lst_index][0])
+ ui = ''.join(model[lst_index][1])
+ desc = ''.join(model[lst_index][2])
## find how many ?(user arguments) are in command
- match = re.findall('\?', cmnd)
+ match = re.findall('\?', cmd)
'''
Make sure user arguments were found. Replace ? with something
.format can read. This is done so the user can just enter ?, when
@@ -400,23 +330,33 @@
else:
num = len(match)
ran = 0
- new_cmnd = self.replace(cmnd, num, ran)
-
-
- if not view.CMNDS[row_int][1] == "": # command with user input
- c = ""
- try:
- text = self.get_info(self, liststore)
- c = new_cmnd.format(text)
- except:
- error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
- _("You need to enter full input. Click on [x] to continue."))
- error.run()
- page_widget.feed_child(c+"\n") #send command w/ input
+ new_cmnd = self.replace(cmd, num, ran)
+
+ if len(match) > 0: # command with user input
+ dbg('command with ui')
+ f_cmd = ""
+ while True:
+ try:
+ ui_text = self.get_info(cmd, ui, desc)
+ if ui_text == None:
+ return
+ dbg('Got ui "%s"'%' '.join(ui_text))
+ if ''.join(ui_text) == '':
+ raise IndexError
+ f_cmd = new_cmnd.format(ui_text)
+ except IndexError, e:
+ error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, \
+ gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
+ _("You need to enter full input. Space separated."))
+ error.connect('response', lambda err, *x: err.destroy())
+ error.run()
+ continue
+ break
+ page_widget.feed_child(f_cmd+"\n") #send command w/ input
page_widget.show()
page_widget.grab_focus()
else: ## command that has no user input
- page_widget.feed_child(cmnd+"\n") #send command
+ page_widget.feed_child(cmd+"\n") #send command
page_widget.show()
page_widget.grab_focus()
@@ -432,7 +372,9 @@
return cmnd
## open the man page for selected command
- def man_page(self, widget, notebook):
+ def man_page(self, notebook):
+ import subprocess as sp
+ import shlex
try:
row_int = int(view.ROW[0][0]) # removes everything but number from EX: [5,]
except IndexError:
@@ -443,21 +385,67 @@
gtk.MESSAGE_QUESTION,
gtk.BUTTONS_OK,
None)
- dialog.set_markup('You must choose row to view help')
+ dialog.set_markup(_('You must choose a row to view the help'))
dialog.show_all()
dialog.run()
dialog.destroy()
return
+ ## get the manpage for the command
cmnd = view.CMNDS[row_int][0] #CMNDS is where commands are store
- splitcommand = self._filter_sudo_from(cmnd.split(" "))
- ## get current notebook tab to use in function
- pagenum = notebook.get_current_page()
- widget = notebook.get_nth_page(pagenum)
- page_widget = widget.get_child()
- #send command to Terminal
- page_widget.feed_child("man "+splitcommand[0]+"| most \n")
- page_widget.grab_focus()
- page_widget.show()
+ ## get each command for each pipe, It's not 100 accurate, but good
+ ## enough (by now)
+ commands = []
+ next_part = True
+ found_sudo = False
+ for part in shlex.split(cmnd):
+ if next_part:
+ if part == 'sudo' and not found_sudo:
+ found_sudo = True
+ commands.append('sudo')
+ else:
+ if part not in commands:
+ commands.append(part)
+ next_part = False
+ else:
+ if part in [ '||', '&&', '&', '|']:
+ next_part = True
+
+ notebook = gtk.Notebook()
+ notebook.set_scrollable(True)
+ notebook.popup_enable()
+ notebook.set_properties(group_id=0, tab_vborder=0, tab_hborder=1, tab_pos=gtk.POS_TOP)
+ ## create a tab for each command
+ for command in commands:
+ scrolled_page = gtk.ScrolledWindow()
+ scrolled_page.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ tab = gtk.HBox()
+ tab_label = gtk.Label(command)
+ tab_label.show()
+ tab.pack_start(tab_label)
+ page = gtk.TextView()
+ page.set_wrap_mode(gtk.WRAP_WORD)
+ page.set_editable(False)
+ page.set_cursor_visible(False)
+ try:
+ manpage = sp.check_output(["man",command])
+ except sp.CalledProcessError, e:
+ manpage = _('Failed to get manpage for command "%s"\nReason:\n%s')%(
+ command, e)
+ textbuffer = page.get_buffer()
+ textbuffer.set_text(manpage)
+ scrolled_page.add(page)
+ notebook.append_page(scrolled_page, tab)
+
+ help_win = gtk.Dialog()
+ help_win.set_title(_("Man page for %s")%cmnd)
+ help_win.vbox.pack_start(notebook, True, True, 0)
+ button = gtk.Button("close")
+ button.connect_object("clicked", lambda self: self.destroy(), help_win)
+ button.set_flags(gtk.CAN_DEFAULT)
+ help_win.action_area.pack_start( button, True, True, 0)
+ button.grab_default()
+ help_win.set_default_size(500,600)
+ help_win.show_all()
@staticmethod
@@ -471,7 +459,6 @@
return command
-
#TODO: Move to menus_buttons
def copy_paste(self, vte, event, data=None):
if event.button == 3:
@@ -517,11 +504,11 @@
# Add a short comment about the application, this appears below the application
# name in the dialog
- dialog.set_comments('This is a CLI Companion program.')
+ dialog.set_comments(_('This is a CLI Companion program.'))
# Add license information, this is connected to the 'License' button
# and is displayed in a new window.
- dialog.set_license('Distributed under the GNU license. You can see it at <http://www.gnu.org/licenses/>.')
+ dialog.set_license(_('Distributed under the GNU license. You can see it at <http://www.gnu.org/licenses/>.'))
# Show the dialog
dialog.run()
@@ -529,11 +516,13 @@
# The destroy method must be called otherwise the 'Close' button will
# not work.
dialog.destroy()
+
+
def help_event(self, widget, data=None):
- webbrowser.open("http://okiebuntu.homelinux.com/okwiki/clicompanion")
+ webbrowser.open("http://launchpad.net/clicompanion")
+
def usage_event(self, widget, data=None):
- mw = view.MainWindow
dialog = gtk.Dialog("Usage",
None,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
@@ -573,139 +562,104 @@
## File --> Preferences
def changed_cb(self, combobox, config):
- config.read(CONFIGFILE)
+ dbg('Changed encoding')
model = combobox.get_model()
index = combobox.get_active()
- if index:
+ if index>=0:
text_e = model[index][0]
- config.set("terminal", "encoding", text_e)
- # Writing our configuration file
- with open(CONFIGFILE, 'wb') as f:
- config.write(f)
+ encoding = text_e.split(':',1)[0].strip()
+ dbg('Setting encoding to "%s"'%encoding)
+ config.set("terminal", "encoding", encoding)
- def color_set_fg_cb(self, colorbutton_fg, config):
- config.read(CONFIGFILE)
- #colorf16 = colorbutton_fg.get_color()
+ def color_set_fg_cb(self, colorbutton_fg, config, tabs):
+ dbg('Changing fg color')
colorf = self.color2hex(colorbutton_fg)
config.set("terminal", "colorf", str(colorf))
- # Writing our configuration file
- with open(CONFIGFILE, 'wb') as f:
- config.write(f)
-
-
-
- def color_set_bg_cb(self, colorbutton_bg, config):
- config.read(CONFIGFILE)
- #colorb16 = colorbutton_bg.get_color()
+ tabs.update_all_term_config(config)
+
+
+ def color_set_bg_cb(self, colorbutton_bg, config, tabs):
+ dbg('Changing bg color')
colorb = self.color2hex(colorbutton_bg)
config.set("terminal", "colorb", str(colorb))
- # Writing our configuration file
- with open(CONFIGFILE, 'wb') as f:
- config.write(f)
-
+ tabs.update_all_term_config(config)
def color2hex(self, widget):
"""Pull the colour values out of a Gtk ColorPicker widget and return them
as 8bit hex values, sinces its default behaviour is to give 16bit values"""
widcol = widget.get_color()
- print widcol
return('#%02x%02x%02x' % (widcol.red>>8, widcol.green>>8, widcol.blue>>8))
- def preferences(self, widget, data=None):
+ def preferences(self, tabs, data=None):
'''
Preferences window
'''
- mw = view.MainWindow
- dialog = gtk.Dialog("User Preferences",
+ dialog = gtk.Dialog(_("User Preferences"),
None,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CLOSE,
gtk.STOCK_OK, gtk.RESPONSE_OK))
- config = ConfigParser.RawConfigParser()
- config.read(CONFIGFILE)
-
+ config = cc_config.get_config_copy()
+
##create the text input fields
entry1 = gtk.Entry()
entry1.set_text(config.get('terminal', 'scrollb'))
-
##combobox for selecting encoding
combobox = gtk.combo_box_new_text()
- combobox.append_text('Select encoding:')
- combobox.append_text('UTF-8')
- combobox.append_text('ISO-8859-1')
- combobox.append_text('ISO-8859-15')
-
+ i=0
+ for encoding, desc in utils.encodings:
+ combobox.append_text(encoding + ': '+desc)
+ if encoding.strip().upper() == config.get('terminal','encoding').upper():
+ active = i
+ i=i+1
+ combobox.set_active(active)
combobox.connect('changed', self.changed_cb, config)
- combobox.set_active(0)
##colorbox for selecting text and background color
- colorbutton_fg = gtk.ColorButton(gtk.gdk.color_parse('white'))
- colorbutton_bg = gtk.ColorButton(gtk.gdk.color_parse('black'))
-
- colorbutton_fg.connect('color-set', self.color_set_fg_cb, config)
- colorbutton_bg.connect('color-set', self.color_set_bg_cb, config)
-
- #dialog.show_all()
+ colorbutton_fg = gtk.ColorButton(
+ gtk.gdk.color_parse(config.get('terminal','colorf')))
+ colorbutton_bg = gtk.ColorButton(
+ gtk.gdk.color_parse(config.get('terminal','colorb')))
+
+ colorbutton_fg.connect('color-set', self.color_set_fg_cb, config, tabs)
+ colorbutton_bg.connect('color-set', self.color_set_bg_cb, config, tabs)
## allow the user to press enter to do ok
entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
-
-
- ## create three labels
+ ## create the labels
hbox1 = gtk.HBox()
hbox1.pack_start(gtk.Label(_("Scrollback")), False, 5, 5)
hbox1.pack_start(entry1, False, 5, 5)
- hbox1.pack_start(gtk.Label(_("encoding")), False, 5, 5)
+ hbox1.pack_start(gtk.Label(_("Encoding")), False, 5, 5)
hbox1.pack_start(combobox, False, 5, 5)
-
hbox2 = gtk.HBox()
- hbox2.pack_start(gtk.Label(_("font color")), False, 5, 5)
+ hbox2.pack_start(gtk.Label(_("Font color")), False, 5, 5)
hbox2.pack_start(colorbutton_fg, True, 5, 5)
- hbox2.pack_start(gtk.Label(_("background color")), False, 5, 5)
+ hbox2.pack_start(gtk.Label(_("Background color")), False, 5, 5)
hbox2.pack_start(colorbutton_bg, True, 5, 5)
-
## add it and show it
dialog.vbox.pack_end(hbox2, True, True, 0)
dialog.vbox.pack_end(hbox1, True, True, 0)
dialog.show_all()
-
+
result = dialog.run()
-
if result == gtk.RESPONSE_OK:
-
## user text assigned to a variable
text_sb = entry1.get_text()
-
- config.read(CONFIGFILE)
config.set("terminal", "scrollb", text_sb)
-
-
-
- # Writing our configuration file
- with open(CONFIGFILE, 'wb') as f:
- config.write(f)
-
-
- ## instantiate tabs
- tabs = clicompanionlib.tabs.Tabs()
- tabs.update_term_config
+ cc_config.save_config(config)
+ tabs.update_all_term_config()
## The destroy method must be called otherwise the 'Close' button will
## not work.
dialog.destroy()
- def save_cmnds(self):
- with open(CHEATSHEET, "w") as cheatfile:
- for command in view.CMNDS:
- cheatfile.write('\t'.join(command)+'\n')
-
-
=== modified file 'clicompanionlib/menus_buttons.py'
--- clicompanionlib/menus_buttons.py 2011-11-16 10:48:50 +0000
+++ clicompanionlib/menus_buttons.py 2012-01-02 01:28:26 +0000
@@ -26,7 +26,11 @@
class FileMenu(object):
- def the_menu(self, actions, notebook, liststore):
+ def the_menu(self, mw):
+ actions = mw.actions
+ liststore = mw.liststore
+ tabs = mw.tabs
+ notebook = mw.notebook
menu = gtk.Menu()
#color = gtk.gdk.Color(65555, 62000, 65555)
#menu.modify_bg(gtk.STATE_NORMAL, color)
@@ -43,33 +47,31 @@
## Make 'Run' menu entry
menu_item1 = gtk.MenuItem(_("Run Command [F4]"))
menu.append(menu_item1)
- menu_item1.connect("activate", actions.run_command, notebook, liststore)
+ menu_item1.connect("activate", lambda *x: actions.run_command(mw))
menu_item1.show()
## Make 'Add' file menu entry
menu_item2 = gtk.MenuItem(_("Add Command [F5]"))
menu.append(menu_item2)
- menu_item2.connect("activate", actions.add_command, liststore)
+ menu_item2.connect("activate", lambda *x: actions.add_command(mw))
menu_item2.show()
## Make 'Remove' file menu entry
menu_item3 = gtk.MenuItem(_("Remove Command [F6]"))
menu.append(menu_item3)
- menu_item3.connect("activate", actions.remove_command, liststore)
+ menu_item3.connect("activate", lambda *x: actions.remove_command(mw))
menu_item3.show()
## Make 'Add Tab' file menu entry
- tab = tabs.Tabs()
menu_item4 = gtk.MenuItem(_("Add Tab [F7]"))
menu.append(menu_item4)
- menu_item4.connect("activate", tab.add_tab, notebook)
+ menu_item4.connect("activate", lambda *x: tabs.add_tab(notebook))
menu_item4.show()
## Make 'User Preferences' file menu entry
- #tab = tabs.Tabs()
menu_item5 = gtk.MenuItem(_("Preferences"))
menu.append(menu_item5)
- menu_item5.connect("activate", actions.preferences)
+ menu_item5.connect("activate", lambda *x: actions.preferences(tabs))
menu_item5.show()
## Make 'Quit' file menu entry
@@ -113,7 +115,7 @@
- def buttons(self, actions, spacing, layout, notebook, liststore):
+ def buttons(self, mw, spacing, layout):
#button box at bottom of main window
frame = gtk.Frame()
bbox = gtk.HButtonBox()
@@ -125,9 +127,9 @@
bbox.set_layout(layout)
bbox.set_spacing(spacing)
# Run button
- buttonRun = gtk.Button(_("Run"))
+ buttonRun = gtk.Button('_'+_("Run"))
bbox.add(buttonRun)
- buttonRun.connect("clicked", actions.run_command, notebook, liststore)
+ buttonRun.connect("clicked", lambda *x: mw.actions.run_command(mw))
buttonRun.set_tooltip_text(_("Click to run a highlighted command"))
#buttonRun.modify_bg(gtk.STATE_NORMAL, color)
#buttonRun.modify_bg(gtk.STATE_PRELIGHT, color)
@@ -135,15 +137,15 @@
# Add button
buttonAdd = gtk.Button(stock=gtk.STOCK_ADD)
bbox.add(buttonAdd)
- buttonAdd.connect("clicked", actions.add_command, liststore)
+ buttonAdd.connect("clicked", lambda *x: mw.actions.add_command(mw))
buttonAdd.set_tooltip_text(_("Click to add a command to your command list"))
#buttonAdd.modify_bg(gtk.STATE_NORMAL, color)
#buttonAdd.modify_bg(gtk.STATE_PRELIGHT, color)
#buttonAdd.modify_bg(gtk.STATE_INSENSITIVE, color)
# Edit button
- buttonEdit = gtk.Button(_("Edit"))
+ buttonEdit = gtk.Button('_'+_("Edit"))
bbox.add(buttonEdit)
- buttonEdit.connect("clicked", actions.edit_command, liststore)
+ buttonEdit.connect("clicked", lambda *x: mw.actions.edit_command(mw))
buttonEdit.set_tooltip_text(_("Click to edit a command in your command list"))
#buttonEdit.modify_bg(gtk.STATE_NORMAL, color)
#buttonEdit.modify_bg(gtk.STATE_PRELIGHT, color)
@@ -151,7 +153,7 @@
# Delete button
buttonDelete = gtk.Button(stock=gtk.STOCK_DELETE)
bbox.add(buttonDelete)
- buttonDelete.connect("clicked", actions.remove_command, liststore)
+ buttonDelete.connect("clicked", lambda *x: mw.actions.remove_command(mw))
buttonDelete.set_tooltip_text(_("Click to delete a command in your command list"))
#buttonDelete.modify_bg(gtk.STATE_NORMAL, color)
#buttonDelete.modify_bg(gtk.STATE_PRELIGHT, color)
@@ -159,7 +161,7 @@
#Help Button
buttonHelp = gtk.Button(stock=gtk.STOCK_HELP)
bbox.add(buttonHelp)
- buttonHelp.connect("clicked", actions.man_page, notebook)
+ buttonHelp.connect("clicked", lambda *x: mw.actions.man_page(mw.notebook))
buttonHelp.set_tooltip_text(_("Click to get help with a command in your command list"))
#buttonHelp.modify_bg(gtk.STATE_NORMAL, color)
#buttonHelp.modify_bg(gtk.STATE_PRELIGHT, color)
@@ -167,7 +169,7 @@
# Cancel button
buttonCancel = gtk.Button(stock=gtk.STOCK_QUIT)
bbox.add(buttonCancel)
- buttonCancel.connect("clicked", actions.delete_event)
+ buttonCancel.connect("clicked", mw.actions.delete_event)
buttonCancel.set_tooltip_text(_("Click to quit CLI Companion"))
#buttonCancel.modify_bg(gtk.STATE_NORMAL, color)
#buttonCancel.modify_bg(gtk.STATE_PRELIGHT, color)
@@ -176,34 +178,34 @@
#right-click popup menu for the Liststore(command list)
- def right_click(self, widget, event, actions, treeview, notebook, liststore):
+ def right_click(self, widget, event, mw):
if event.button == 3:
x = int(event.x)
y = int(event.y)
time = event.time
- pthinfo = treeview.get_path_at_pos(x, y)
+ pthinfo = mw.treeview.get_path_at_pos(x, y)
if pthinfo is not None:
path, col, cellx, celly = pthinfo
- treeview.grab_focus()
- treeview.set_cursor( path, col, 0)
+ mw.treeview.grab_focus()
+ mw.treeview.set_cursor( path, col, 0)
# right-click popup menu Apply(run)
popupMenu = gtk.Menu()
menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_APPLY)
popupMenu.add(menuPopup1)
- menuPopup1.connect("activate", actions.run_command, notebook, liststore)
+ menuPopup1.connect("activate", lambda self, *x: mw.actions.run_command(mw))
# right-click popup menu Edit
menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_EDIT)
popupMenu.add(menuPopup2)
- menuPopup2.connect("activate", actions.edit_command, liststore)
+ menuPopup2.connect("activate", lambda self, *x: mw.actions.edit_command(mw))
# right-click popup menu Delete
menuPopup3 = gtk.ImageMenuItem (gtk.STOCK_DELETE)
popupMenu.add(menuPopup3)
- menuPopup3.connect("activate", actions.remove_command, liststore)
+ menuPopup3.connect("activate", lambda self, *x: mw.actions.remove_command(mw))
# right-click popup menu Help
menuPopup4 = gtk.ImageMenuItem (gtk.STOCK_HELP)
popupMenu.add(menuPopup4)
- menuPopup4.connect("activate", actions.man_page, notebook)
+ menuPopup4.connect("activate", lambda self, *x: mw.actions.man_page(mw.notebook))
# Show popup menu
popupMenu.show_all()
popupMenu.popup( None, None, None, event.button, time)
=== modified file 'clicompanionlib/tabs.py'
--- clicompanionlib/tabs.py 2011-03-29 17:31:11 +0000
+++ clicompanionlib/tabs.py 2012-01-02 01:28:26 +0000
@@ -22,33 +22,33 @@
pygtk.require('2.0')
import gtk
import vte
-import ConfigParser
+import clicompanionlib.config as cc_config
-from clicompanionlib.utils import get_user_shell
+from clicompanionlib.utils import get_user_shell, dbg
import clicompanionlib.controller
+import clicompanionlib.utils as utils
import view
-CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config")
-
-
-#definition gcp - how many pages is visible
-gcp=0;
-
-#definition nop - (no of pages) reflects no of terminal tabs left (some may be closed by the user)
-nop=0;
class Tabs(object):
'''
add a new terminal in a tab above the current terminal
'''
- def add_tab(self,widget, notebook):
+ def __init__(self):
+ #definition nop - (no of pages) reflects no of terminal tabs left (some may be closed by the user)
+ self.nop = 0
+ #definition gcp - how many pages is visible
+ self.gcp = 0
+
+ def add_tab(self, notebook):
+ dbg('Adding a new tab')
_vte = vte.Terminal()
if view.NETBOOKMODE == 1:
_vte.set_size_request(700, 120)
else:
_vte.set_size_request(700, 220)
- _vte.connect ("child-exited", lambda term: gtk.main_quit())
+ _vte.connect("child-exited", lambda term: gtk.main_quit())
_vte.fork_command(get_user_shell()) # Get the user's default shell
self.update_term_config(_vte)
@@ -58,19 +58,16 @@
#notebook.set_show_tabs(True)
#notebook.set_show_border(True)
- global gcp
- global nop
- nop += 1
- gcp += 1
- pagenum = ('Tab %d') % gcp
- if nop > 1:
+ self.nop += 1
+ self.gcp += 1
+ pagenum = ('Tab %d') % self.gcp
+ if self.nop > 1:
+ dbg('More than one tab, showing them.')
view.MainWindow.notebook.set_show_tabs(True)
box = gtk.HBox()
label = gtk.Label(pagenum)
box.pack_start(label, True, True)
-
-
## x image for tab close button
close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
@@ -87,10 +84,10 @@
view.MainWindow.notebook.prepend_page(vte_tab, box) # add tab
view.MainWindow.notebook.set_scrollable(True)
actions = clicompanionlib.controller.Actions()
- _vte.connect ("button_press_event", actions.copy_paste, None)
+ _vte.connect("button_press_event", actions.copy_paste, None)
vte_tab.grab_focus()
# signal handler for tab
- closebtn.connect("clicked", self.close_tab, vte_tab, notebook)
+ closebtn.connect("clicked", lambda *x: self.close_tab(vte_tab, notebook))
vte_tab.show_all()
@@ -98,29 +95,42 @@
## Remove a page from the notebook
- def close_tab(self, sender, widget, notebook):
+ def close_tab(self, vte_tab, notebook):
## get the page number of the tab we wanted to close
- pagenum = view.MainWindow.notebook.page_num(widget)
+ pagenum = view.MainWindow.notebook.page_num(vte_tab)
## and close it
view.MainWindow.notebook.remove_page(pagenum)
- global nop
- nop -= 1
- if nop <= 1:
+ self.nop -= 1
+ if self.nop <= 1:
view.MainWindow.notebook.set_show_tabs(False)
# check if the focus does not go to the last page (ie with only a + sign)
- if view.MainWindow.notebook.get_current_page() == nop:
+ if view.MainWindow.notebook.get_current_page() == self.nop:
view.MainWindow.notebook.prev_page()
-
-
- def update_term_config(self, _vte):
- ##read config file
- config = ConfigParser.RawConfigParser()
- config.read(CONFIGFILE)
-
+ def update_all_term_config(self, config=None):
+ for pagenum in range(view.MainWindow.notebook.get_n_pages()):
+ page = view.MainWindow.notebook.get_nth_page(pagenum)
+ dbg(page)
+ if isinstance(page, gtk.ScrolledWindow):
+ for grandson in page.get_children():
+ dbg(grandson)
+ if isinstance(grandson,vte.Terminal):
+ self.update_term_config(grandson, config)
+
+ def update_term_config(self, _vte, config=None):
##set terminal preferences from conig file data
- config_scrollback = config.getint('terminal', 'scrollb')
+ if not config:
+ config = cc_config.get_config()
+ try:
+ config_scrollback = config.getint('terminal', 'scrollb')
+ except ValueError:
+ print _("WARNING: Invalid value for property 'terminal', int expected:"
+ " got '%s', using default '%s'")%(
+ config.get('terminal', 'scrollb'),
+ config.get('DEFAULT', 'scrollb'))
+ config.set('terminal','scrollb',config.get('DEFAULT', 'scrollb'))
+ config_scrollback = config.getint('DEFAULT', 'scrollb')
_vte.set_scrollback_lines(config_scrollback)
color = '#2e3436:#cc0000:#4e9a06:#c4a000:#3465a4:#75507b:#06989a:#d3d7cf:#555753:#ef2929:#8ae234:#fce94f:#729fcf:#ad7fa8:#34e2e2:#eeeeec'
@@ -130,14 +140,39 @@
if color:
palette.append(gtk.gdk.color_parse(color))
- config_color_fore = gtk.gdk.color_parse(config.get('terminal', 'colorf'))
- #_vte.set_color_foreground(config_color_fore)
-
- config_color_back = gtk.gdk.color_parse(config.get('terminal', 'colorb'))
- #_vte.set_color_background( config_color_back)
-
+ try:
+ config_color_fore = gtk.gdk.color_parse(config.get('terminal', 'colorf'))
+ except ValueError, e:
+ print _("WARNING: Invalid value for property '%s':"
+ " got '%s', using default '%s'.")%(
+ 'colorf',
+ config.get('terminal', 'colorf'),
+ config.get('DEFAULT', 'colorf'))
+ config.set('terminal','colorf',config.get('DEFAULT', 'colorf'))
+ config_color_fore = gtk.gdk.color_parse(config.get('DEFAULT', 'colorf'))
+
+ try:
+ config_color_back = gtk.gdk.color_parse(config.get('terminal', 'colorb'))
+ except ValueError, e:
+ print _("WARNING: Invalid value for property '%s':"
+ " got '%s', using default '%s'.")%(
+ 'colorb',
+ config.get('terminal', 'colorb'),
+ config.get('DEFAULT', 'colorb'))
+ config.set('terminal','colorb',config.get('DEFAULT', 'colorb'))
+ config_color_back = gtk.gdk.color_parse(config.get('DEFAULT', 'colorb'))
_vte.set_colors(config_color_fore, config_color_back, palette)
config_encoding = config.get('terminal', 'encoding')
+ if config_encoding.upper() not in [ enc.upper() for enc, desc in utils.encodings]:
+ print _("WARNING: Invalid value for property '%s':"
+ " got '%s', using default '%s'")%(
+ 'encoding',
+ config_encoding,
+ config.get('DEFAULT', 'encoding'))
+ config.set('terminal','encoding',config.get('DEFAULT', 'encoding'))
+ config_encoding = config.get('DEFAULT', 'encoding')
_vte.set_encoding(config_encoding)
+
+
=== modified file 'clicompanionlib/utils.py'
--- clicompanionlib/utils.py 2011-03-29 17:31:11 +0000
+++ clicompanionlib/utils.py 2012-01-02 01:28:26 +0000
@@ -25,9 +25,148 @@
import getpass
import os
-
-CHEATSHEET = os.path.expanduser("~/.clicompanion2")
-#CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
+import sys
+import gtk
+import pwd
+import inspect
+
+
+## set to True if you want to see more logs
+DEBUG = False
+DEBUGFILES = False
+DEBUGCLASSES = []
+DEBUGMETHODS = []
+
+## list gotten from terminator (https://launchpad.net/terminator)
+encodings = [
+ ["ISO-8859-1", _("Western")],
+ ["ISO-8859-2", _("Central European")],
+ ["ISO-8859-3", _("South European") ],
+ ["ISO-8859-4", _("Baltic") ],
+ ["ISO-8859-5", _("Cyrillic") ],
+ ["ISO-8859-6", _("Arabic") ],
+ ["ISO-8859-7", _("Greek") ],
+ ["ISO-8859-8", _("Hebrew Visual") ],
+ ["ISO-8859-8-I", _("Hebrew") ],
+ ["ISO-8859-9", _("Turkish") ],
+ ["ISO-8859-10", _("Nordic") ],
+ ["ISO-8859-13", _("Baltic") ],
+ ["ISO-8859-14", _("Celtic") ],
+ ["ISO-8859-15", _("Western") ],
+ ["ISO-8859-16", _("Romanian") ],
+ # ["UTF-7", _("Unicode") ],
+ ["UTF-8", _("Unicode") ],
+ # ["UTF-16", _("Unicode") ],
+ # ["UCS-2", _("Unicode") ],
+ # ["UCS-4", _("Unicode") ],
+ ["ARMSCII-8", _("Armenian") ],
+ ["BIG5", _("Chinese Traditional") ],
+ ["BIG5-HKSCS", _("Chinese Traditional") ],
+ ["CP866", _("Cyrillic/Russian") ],
+ ["EUC-JP", _("Japanese") ],
+ ["EUC-KR", _("Korean") ],
+ ["EUC-TW", _("Chinese Traditional") ],
+ ["GB18030", _("Chinese Simplified") ],
+ ["GB2312", _("Chinese Simplified") ],
+ ["GBK", _("Chinese Simplified") ],
+ ["GEORGIAN-PS", _("Georgian") ],
+ ["HZ", _("Chinese Simplified") ],
+ ["IBM850", _("Western") ],
+ ["IBM852", _("Central European") ],
+ ["IBM855", _("Cyrillic") ],
+ ["IBM857", _("Turkish") ],
+ ["IBM862", _("Hebrew") ],
+ ["IBM864", _("Arabic") ],
+ ["ISO-2022-JP", _("Japanese") ],
+ ["ISO-2022-KR", _("Korean") ],
+ ["EUC-TW", _("Chinese Traditional") ],
+ ["GB18030", _("Chinese Simplified") ],
+ ["GB2312", _("Chinese Simplified") ],
+ ["GBK", _("Chinese Simplified") ],
+ ["GEORGIAN-PS", _("Georgian") ],
+ ["HZ", _("Chinese Simplified") ],
+ ["IBM850", _("Western") ],
+ ["IBM852", _("Central European") ],
+ ["IBM855", _("Cyrillic") ],
+ ["IBM857", _("Turkish") ],
+ ["IBM862", _("Hebrew") ],
+ ["IBM864", _("Arabic") ],
+ ["ISO-2022-JP", _("Japanese") ],
+ ["ISO-2022-KR", _("Korean") ],
+ ["ISO-IR-111", _("Cyrillic") ],
+ # ["JOHAB", _("Korean") ],
+ ["KOI8-R", _("Cyrillic") ],
+ ["KOI8-U", _("Cyrillic/Ukrainian") ],
+ ["MAC_ARABIC", _("Arabic") ],
+ ["MAC_CE", _("Central European") ],
+ ["MAC_CROATIAN", _("Croatian") ],
+ ["MAC-CYRILLIC", _("Cyrillic") ],
+ ["MAC_DEVANAGARI", _("Hindi") ],
+ ["MAC_FARSI", _("Persian") ],
+ ["MAC_GREEK", _("Greek") ],
+ ["MAC_GUJARATI", _("Gujarati") ],
+ ["MAC_GURMUKHI", _("Gurmukhi") ],
+ ["MAC_HEBREW", _("Hebrew") ],
+ ["MAC_ICELANDIC", _("Icelandic") ],
+ ["MAC_ROMAN", _("Western") ],
+ ["MAC_ROMANIAN", _("Romanian") ],
+ ["MAC_TURKISH", _("Turkish") ],
+ ["MAC_UKRAINIAN", _("Cyrillic/Ukrainian") ],
+ ["SHIFT-JIS", _("Japanese") ],
+ ["TCVN", _("Vietnamese") ],
+ ["TIS-620", _("Thai") ],
+ ["UHC", _("Korean") ],
+ ["VISCII", _("Vietnamese") ],
+ ["WINDOWS-1250", _("Central European") ],
+ ["WINDOWS-1251", _("Cyrillic") ],
+ ["WINDOWS-1252", _("Western") ],
+ ["WINDOWS-1253", _("Greek") ],
+ ["WINDOWS-1254", _("Turkish") ],
+ ["WINDOWS-1255", _("Hebrew") ],
+ ["WINDOWS-1256", _("Arabic") ],
+ ["WINDOWS-1257", _("Baltic") ],
+ ["WINDOWS-1258", _("Vietnamese") ]
+ ]
+
+
+def dbg(log):
+ if DEBUG:
+ stack = inspect.stack()
+ method = None
+ for stackitem in stack:
+ parent_frame = stackitem[0]
+ names, varargs, keywords, local_vars = inspect.getargvalues(parent_frame)
+ ## little trick to get the second stackline method, in case we do
+ ## not find self
+ if not method and method != None:
+ method = stackitem[3]
+ elif not method:
+ method = ''
+ try:
+ self_name = names[0]
+ if self_name != 'self':
+ continue
+ classname = local_vars[self_name].__class__.__name__
+ except IndexError:
+ classname = "noclass"
+ ## in case self is found, get the method
+ method = stackitem[3]
+ break
+ if DEBUGFILES:
+ line = stackitem[2]
+ filename = parent_frame.f_code.co_filename
+ extra = " (%s:%s)" % (filename, line)
+ else:
+ extra = ""
+ if DEBUGCLASSES != [] and classname not in DEBUGCLASSES:
+ return
+ if DEBUGMETHODS != [] and method not in DEBUGMETHODS:
+ return
+ try:
+ print >> sys.stderr, "%s::%s: %s%s" % (classname, method, log, extra)
+ except IOError:
+ pass
+
#TODO: Move this to controller.py
def get_user_shell():
=== modified file 'clicompanionlib/view.py'
--- clicompanionlib/view.py 2011-12-30 12:22:17 +0000
+++ clicompanionlib/view.py 2012-01-02 01:28:26 +0000
@@ -22,7 +22,6 @@
import pygtk
pygtk.require('2.0')
import os
-import ConfigParser
# import vte and gtk or print error
try:
@@ -43,18 +42,20 @@
import clicompanionlib.menus_buttons
import clicompanionlib.controller
-from clicompanionlib.utils import get_user_shell , Borg
+from clicompanionlib.utils import get_user_shell , Borg, dbg
import clicompanionlib.tabs
-from clicompanionlib.config import Config
-
-
-CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config")
-CHEATSHEET = os.path.expanduser("~/.clicompanion2")
-CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
+import clicompanionlib.utils as utils
+import clicompanionlib.config as cc_config
+
## Changed two->three columns
-CMNDS = [] ## will hold the commands. Actually the first three columns
-ROW = '1' ## holds the currently selected row
+CMNDS = cc_config.Cheatsheet()
+## will hold the commands. Actually the first three columns
+## note that this commands list will not change with searchers and filters,
+## instead, when adding a command to the liststore, we will add also the index
+## of the command in the CMND list
+
+ROW = '0' ## holds the currently selected row
TARGETS = [
('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0),
('text/plain', 0, 1),
@@ -67,7 +68,6 @@
HIDEUI = 0
FULLSCREEN = 0
-
menu_search_hbox = ''
button_box = ''
@@ -76,90 +76,32 @@
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
#color = gtk.gdk.Color(60000, 65533, 60000)
#window.modify_bg(gtk.STATE_NORMAL, color)
- liststore = gtk.ListStore(str, str, str)
+ liststore = gtk.ListStore(str, str, str, int)
treeview = gtk.TreeView()
expander = gtk.Expander()
scrolledwindow = gtk.ScrolledWindow()
notebook = gtk.Notebook()
-
screen = gtk.gdk.display_get_default().get_default_screen()
screen_size = screen.get_monitor_geometry(0)
height = screen.get_height() ## screen height ##
global NETBOOKMODE
if height < 750:
NETBOOKMODE = 1
- ## open file containing command list and put it in a variable
- def update(self, liststore):
- try:
- with open(CHEATSHEET, "r") as cheatfile:
- bugdata=cheatfile.read()
- cheatfile.close()
- except IOError:
- ## CHEATSHEET is not there. Oh, no!
- ## So, run self.setup() again.
- self.setup()
- ## Then, run me again.
- self.update(self.liststore)
-
- ## add bug data from .clicompanion --> bugdata --> to the liststore
- for line in bugdata.splitlines():
- l = line.split('\t',2)
- if len(l) < 2:
- """
- If for any reason we have a old file, we must
- replace it by new one
- """
- print "PLEASE RESTART APPLICATION TO FINISH UPDATE"
- self.setup()
- return
- commandplus = l[0], l[1], l[2]
- CMNDS.append(commandplus)
- self.liststore.append([l[0],l[1],l[2]])
-
-
- #copy config file to user $HOME if does not exist
- def setup(self):
- """
- Check if ~/.clicompanion2 exists. If not check for original
- installed in /etc/clicompanion.d/. If origianl exists copy to $HOME.
- if not create a new, blank ~/.clicompanion2 so program will not crash
- """
-
- if not os.path.exists(CHEATSHEET):
- if os.path.exists(CONFIG_ORIG):
- os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
- else:
- # Oops! Looks like there's no cheatsheet in CHEATSHEET.
- # Then, create an empty cheatsheet.
- open(CHEATSHEET, 'w').close()
- """
- If we have old file, we must replace it by fresh list
- """
- cheatlines = []
- try:
- with open(CHEATSHEET, "r") as cheatfile:
- bugdata=cheatfile.read()
- cheatfile.close()
- for line in bugdata.splitlines():
- l = line.split('\t', 2)
- if len(l) < 2:
- l = line.split(':', 2)
- p = str(l[0] + "\t"+ l[1] +"\t"+ l[2] + "\n")
- cheatlines.append(p)
- else:
- cheatlines.append(str(l[0] + "\t"+ l[1] +"\t"+ l[2] + "\n"))
-
- with open(CHEATSHEET, "w") as cheatfile2:
- cheatfile2.writelines(cheatlines)
- cheatfile2.close()
-
- except IOError:
- ## CHEATSHEET is not there. Oh, no!
- ## So, run self.setup() again.
- self.setup()
- ## Then, run me again.
- self.update(self.liststore)
+
+
+ def sync_cmnds(self, rld=False):
+ global CMNDS
+ dbg('syncing commands')
+ if rld:
+ ## reload the commands list from the file
+ CMNDS.load()
+ self.liststore.clear()
+ ## Store also the index of the command in the CMNDS list
+ i = 0
+ for cmd, ui, desc in CMNDS:
+ self.liststore.append((cmd, ui, desc, i))
+ i = i +1
#liststore in a scrolled window in an expander
@@ -185,13 +127,11 @@
def key_clicked(self, widget, event):
actions = clicompanionlib.controller.Actions()
- tabs = clicompanionlib.tabs.Tabs()
global HIDEUI
global FULLSCREEN
global menu_search_hbox
global button_box
keyname = gtk.gdk.keyval_name(event.keyval).upper()
- #print keyname ##debug
if keyname == "F12":
HIDEUI = 1 - HIDEUI
if HIDEUI == 1:
@@ -215,13 +155,13 @@
pwin = button_box.get_window()
pwin.unfullscreen()
if keyname == "F4":
- actions.run_command(self, self.notebook, self.liststore)
+ actions.run_command(self)
if keyname == "F5":
- actions.add_command(self, self.liststore)
+ actions.add_command(self)
if keyname == "F6":
- actions.remove_command(self, self.liststore)
+ actions.remove_command(self)
if keyname == "F7":
- tabs.add_tab(self, self.notebook)
+ self.tabs.add_tab(self)
def __init__(self):
#import pdb ##debug
@@ -231,14 +171,7 @@
##in libvte in Ubuntu Maverick
os.putenv('TERM', 'xterm')
- ## copy command list to user $HOME if does not exist
- self.setup()
- ##create the config file
- conf_mod = Config()
- conf_mod.create_config()
-
-
## style to reduce padding around tabs
## TODO: Find a better place for this?
gtk.rc_parse_string ("style \"tab-close-button-style\"\n"
@@ -257,7 +190,6 @@
##attach the style to the widget
self.notebook.set_name ("tab-close-button")
-
## set sizes and borders
global NETBOOKMODE
if NETBOOKMODE == 1:
@@ -272,19 +204,15 @@
## Allow user to resize window
self.window.set_resizable(True)
-
## set Window title and icon
self.window.set_title("CLI Companion")
icon = gtk.gdk.pixbuf_new_from_file("/usr/share/pixmaps/clicompanion.16.png")
self.window.set_icon(icon)
-
-
- # get commands and put in liststore
- self.update(self.liststore)
+ # sync liststore with commands
+ self.sync_cmnds()
## set renderer and colors
-
#color2 = gtk.gdk.Color(5000,5000,65000)
renderer = gtk.CellRendererText()
#renderer.set_property("cell-background-gdk", color)
@@ -308,7 +236,7 @@
True)
## set the cell attributes to the appropriate liststore column
self.treeview.columns[n].set_attributes(
- self.treeview.columns[n].cell, text=n)
+ self.treeview.columns[n].cell, text=n)
self.treeview.columns[n].set_resizable(True)
''' set treeview model and put treeview in the scrolled window
@@ -321,12 +249,12 @@
#self.window.show_all()
## instantiate tabs
- tabs = clicompanionlib.tabs.Tabs()
+ self.tabs = clicompanionlib.tabs.Tabs()
## instantiate controller.Actions, where all the button actions are
self.actions = clicompanionlib.controller.Actions()
## instantiate 'File' and 'Help' Drop Down Menu [menus_buttons.py]
bar = clicompanionlib.menus_buttons.FileMenu()
- menu_bar = bar.the_menu(self.actions, self.notebook, self.liststore)
+ menu_bar = bar.the_menu(self)
## get row of a selection
@@ -337,17 +265,17 @@
## double click to run a command
- def treeview_clicked(widget, event):
- if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
- self.actions.run_command(self, self.notebook, self.liststore)
+ def treeview_clicked(widget, path, column):
+ self.actions.run_command(self)
+
## press enter to run a command
def treeview_button(widget, event):
keyname = gtk.gdk.keyval_name(event.keyval).upper()
- #print keyname ##debug
+ dbg('Key %s pressed'%keyname)
if event.type == gtk.gdk.KEY_PRESS:
if keyname == 'RETURN':
- self.actions.run_command(self, self.notebook, self.liststore)
+ self.actions.run_command(self)
@@ -357,7 +285,7 @@
selection.select_path(0)
selection.connect("changed", mark_selected, selection)
## double-click
- self.treeview.connect("button-press-event", treeview_clicked)
+ self.treeview.connect("row-activated", treeview_clicked)
#press enter to run command
self.treeview.connect("key-press-event", treeview_button)
@@ -393,7 +321,7 @@
self.expander.set_label_widget(expander_hbox)
## Add the first tab with the Terminal
- tabs.add_tab(self, self.notebook)
+ self.tabs.add_tab(self.notebook)
self.notebook.set_tab_pos(2)
## The "Add Tab" tab
@@ -405,7 +333,7 @@
global button_box
## buttons at bottom of main window [menus_buttons.py]
- button_box = bar.buttons(self.actions, 10, gtk.BUTTONBOX_END, self.notebook, self.liststore)
+ button_box = bar.buttons(self, 10, gtk.BUTTONBOX_END)
## vbox for search, notebook, buttonbar
vbox = gtk.VBox()
@@ -421,9 +349,9 @@
self.expander.connect('notify::expanded', self.expanded_cb, self.window, self.search_box)
self.window.connect("delete_event", self.delete_event)
self.window.connect("key-press-event", self.key_clicked)
- add_tab_button.connect("clicked", tabs.add_tab, self.notebook)
+ add_tab_button.connect("clicked", lambda *x: self.tabs.add_tab(self.notebook))
## right click menu event capture
- self.treeview.connect ("button_press_event", bar.right_click, self.actions, self.treeview, self.notebook, self.liststore)
+ self.treeview.connect("button_press_event", bar.right_click, self)
# Allow enable drag and drop of rows including row move
self.treeview.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
@@ -435,12 +363,20 @@
self.treeview.connect ("drag_data_get", self.drag_data_get_event)
self.treeview.connect ("drag_data_received", self.drag_data_received_event)
+ self.treeview.connect("drag_drop", self.on_drag_drop )
#self.vte.grab_focus()
self.window.show_all()
return
+ def on_drag_drop(self, treeview, *x):
+ '''
+ Stop the signal when in search mode
+ '''
+ if FILTER:
+ treeview.stop_emission('drag_drop')
+
def drag_data_get_event(self, treeview, context, selection, target_id,
etime):
"""
@@ -457,90 +393,57 @@
Executed when dropping.
"""
global CMNDS
+ global FILTER
+ ## if we are in a search, do nothing
+ if FILTER == 1:
+ return
model = treeview.get_model()
+ ## get the destination
+ drop_info = treeview.get_dest_row_at_pos(x, y)
+ if drop_info:
+ path, position = drop_info
+ iter = model.get_iter(path)
+ dest = list(model.get(iter, 0, 1, 2))
+
+ ## parse all the incoming commands
for data in selection.data.split('\n'):
# if we got an empty line skip it
if not data.replace('\r',''): continue
# format the incoming string
orig = data.replace('\r','').split('\t',2)
- orig = tuple([ fld.strip() for fld in orig ])
+ orig = [ fld.strip() for fld in orig ]
# fill the empty fields
if len(orig) < 3: orig = orig + ('',)*(3-len(orig))
- # if the element already exists delete it (dragged from clicompanion)
- olditer = self.find_iter_by_tuple(orig, model)
- if olditer: del model[olditer]
+ dbg('Got drop of command %s'%'_\t_'.join(orig))
- drop_info = treeview.get_dest_row_at_pos(x, y)
if drop_info:
- path, position = drop_info
- iter = model.get_iter(path)
- dest = tuple(model.get(iter, 0, 1, 2))
if (position == gtk.TREE_VIEW_DROP_BEFORE
or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
- model.insert_before(iter, orig)
- self.drag_cmnd(orig, dest, before=True)
+ dbg('\t to before dest %s'%'_\t_'.join(dest))
+ CMNDS.drag_n_drop(orig, dest, before=True)
else:
- model.insert_after(iter, orig)
- self.drag_cmnd(orig, dest, before=False)
+ dbg('\t to after dest %s'%'_\t_'.join(dest))
+ CMNDS.drag_n_drop(orig, dest, before=False)
else:
- if len(model) > 0:
- iter = model[-1].iter
- model.insert_after(iter, orig)
- else:
- model.insert(0, orig)
- return
- dest = tuple(model.get(iter, 0, 1, 2))
- self.drag_cmnd(orig, dest, before=False)
- if context.action == gtk.gdk.ACTION_MOVE:
- context.finish(True, True, etime)
- self.actions.save_cmnds()
+ dbg('\t to the end')
+ CMNDS[len(CMNDS)] = orig
+ if context.action == gtk.gdk.ACTION_MOVE:
+ context.finish(True, True, etime)
+ self.sync_cmnds()
+ CMNDS.save()
- def find_iter_by_tuple(self, data, model):
- for row in model:
- if tuple(model.get(row.iter, 0, 1, 2)) == data:
- return row.iter
- return None
-
- def drag_cmnd(self, orig, dest, before=True):
- """
- Sync the CMNDS array with the drag and drop of the treeview.
- """
- global CMNDS
- i = j = None
- pos = 0
- for cmnd in CMNDS:
- if cmnd == orig:
- i = pos
- elif cmnd == dest:
- j = pos
- pos += 1
- ## both from clicompanion
- if i != None and j != None:
- cmnd = CMNDS.pop(i)
- if before and i<=j:
- CMNDS.insert(j-1, cmnd)
- elif before and i>j:
- CMNDS.insert(j, cmnd)
- elif i<=j:
- CMNDS.insert(j, cmnd)
- else:
- CMNDS.insert(j+1, cmnd)
- ## origin unknown
- elif j != None:
- cmnd = orig
- if before:
- CMNDS.insert(j, cmnd)
- else:
- CMNDS.insert(j+1, cmnd)
-
-
def main(self):
try:
gtk.main()
except KeyboardInterrupt:
pass
-def run():
-
+def run( options=None ):
+ ##create the config file
+ config = cc_config.create_config()
+ if config.get('terminal','debug') == 'True':
+ utils.DEBUG = True
+ CMNDS.load(options and options.cheatsheet or None)
+ dbg('Loaded commands %s'%CMNDS)
main_window = MainWindow()
main_window.main()