Merge lp:~dcaro/clicompanion/fix-910355 into lp:clicompanion
- fix-910355
- Merge into trunk
Proposed by
David Caro
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Marek Bardoński | Approve | ||
Review via email: mp+87218@code.launchpad.net |
Commit message
Description of the change
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
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'clicompanion' | |||
2 | --- clicompanion 2011-12-31 12:33:51 +0000 | |||
3 | +++ clicompanion 2012-01-02 01:28:26 +0000 | |||
4 | @@ -6,7 +6,6 @@ | |||
5 | 6 | import sys | 6 | import sys |
6 | 7 | from optparse import OptionParser | 7 | from optparse import OptionParser |
7 | 8 | 8 | ||
8 | 9 | from clicompanionlib.view import run | ||
9 | 10 | 9 | ||
10 | 11 | share_dirs = os.environ.get('XDG_BASE_PDATA', | 10 | share_dirs = os.environ.get('XDG_BASE_PDATA', |
11 | 12 | '/usr/local/share:/usr/share').split(os.pathsep) | 11 | '/usr/local/share:/usr/share').split(os.pathsep) |
12 | @@ -27,10 +26,12 @@ | |||
13 | 27 | 26 | ||
14 | 28 | parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.1") | 27 | parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.1") |
15 | 29 | parser.add_option("-f", "--file", dest="filename", | 28 | parser.add_option("-f", "--file", dest="filename", |
17 | 30 | help="write report to FILE", metavar="FILE") | 29 | help="Write report to FILE", metavar="FILE") |
18 | 30 | parser.add_option("-c", "--cheatsheet", dest="cheatsheet", | ||
19 | 31 | help="Read cheatsheet from FILE", metavar="FILE") | ||
20 | 31 | parser.add_option("-q", "--quiet", | 32 | parser.add_option("-q", "--quiet", |
21 | 32 | action="store_false", dest="verbose", default=True, | 33 | action="store_false", dest="verbose", default=True, |
23 | 33 | help="don't print status messages to stdout") | 34 | help="Don't print status messages to stdout") |
24 | 34 | 35 | ||
25 | 35 | (options, args) = parser.parse_args() | 36 | (options, args) = parser.parse_args() |
26 | 36 | 37 | ||
27 | @@ -62,4 +63,5 @@ | |||
28 | 62 | 63 | ||
29 | 63 | 64 | ||
30 | 64 | if __name__ == "__main__": | 65 | if __name__ == "__main__": |
32 | 65 | run() | 66 | from clicompanionlib.view import run |
33 | 67 | run( options ) | ||
34 | 66 | 68 | ||
35 | === modified file 'clicompanionlib/config.py' | |||
36 | --- clicompanionlib/config.py 2011-03-12 16:08:24 +0000 | |||
37 | +++ clicompanionlib/config.py 2012-01-02 01:28:26 +0000 | |||
38 | @@ -20,33 +20,244 @@ | |||
39 | 20 | # | 20 | # |
40 | 21 | import os | 21 | import os |
41 | 22 | import ConfigParser | 22 | import ConfigParser |
42 | 23 | import clicompanionlib.utils as utils | ||
43 | 24 | from clicompanionlib.utils import dbg | ||
44 | 25 | import collections | ||
45 | 23 | 26 | ||
46 | 27 | CHEATSHEET = os.path.expanduser("~/.clicompanion2") | ||
47 | 24 | CONFIGDIR = os.path.expanduser("~/.config/clicompanion/") | 28 | CONFIGDIR = os.path.expanduser("~/.config/clicompanion/") |
48 | 25 | CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config") | 29 | CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config") |
62 | 26 | 30 | CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config" | |
63 | 27 | class Config(object): | 31 | DEFAULTS = { "scrollb": '500', |
64 | 28 | 32 | "colorf": '#FFFFFF', | |
65 | 29 | ''' | 33 | "colorb": '#000000', |
66 | 30 | create configuration file | 34 | "encoding": 'UTF-8', |
67 | 31 | ''' | 35 | "debug": 'False'} |
68 | 32 | 36 | ||
69 | 33 | def create_config(self): | 37 | ## To avoid parsing the config file each time, we store the loaded config here |
70 | 34 | 38 | CONFIG = None | |
71 | 35 | if not os.path.exists(CONFIGFILE): | 39 | |
72 | 36 | os.makedirs(CONFIGDIR) | 40 | def create_config(conffile=CONFIGFILE): |
73 | 37 | config = ConfigParser.ConfigParser() | 41 | global CONFIG |
74 | 38 | # set a number of parameters | 42 | config = CONFIG |
75 | 43 | configdir = conffile.rsplit(os.sep,1)[0] | ||
76 | 44 | if not os.path.exists(configdir): | ||
77 | 45 | try: | ||
78 | 46 | os.makedirs(configdir) | ||
79 | 47 | except Exception, e: | ||
80 | 48 | print _('Unable to create config at dir %s (%s)')%(configdir,e) | ||
81 | 49 | return False | ||
82 | 50 | # reuse the config if able | ||
83 | 51 | if not config: | ||
84 | 52 | config = ConfigParser.SafeConfigParser(DEFAULTS) | ||
85 | 53 | # set a number of parameters | ||
86 | 54 | if os.path.isfile(conffile): | ||
87 | 55 | config.read([conffile]) | ||
88 | 56 | else: | ||
89 | 39 | config.add_section("terminal") | 57 | config.add_section("terminal") |
103 | 40 | config.set("terminal", "scrollb", 500) | 58 | for option, value in DEFAULTS.items(): |
104 | 41 | config.set("terminal", "colorf", '#FFFFFF') | 59 | config.set("terminal", option, value) |
105 | 42 | config.set("terminal", "colorb", '#000000') | 60 | CONFIG = config |
106 | 43 | config.set("terminal", "encoding", 'utf-8') | 61 | # Writing our configuration file |
107 | 44 | # Writing our configuration file | 62 | save_config(config, conffile) |
108 | 45 | with open(CONFIGFILE, 'wb') as f: | 63 | print _("INFO: Created config file at %s.")%conffile |
109 | 46 | config.write(f) | 64 | return config |
110 | 47 | 65 | ||
111 | 48 | else: | 66 | |
112 | 49 | pass | 67 | def get_config_copy(config=None): |
113 | 50 | 68 | global CONFIG | |
114 | 51 | 69 | if not config: | |
115 | 52 | 70 | config = CONFIG | |
116 | 71 | new_cfg = ConfigParser.SafeConfigParser(DEFAULTS) | ||
117 | 72 | for section in config.sections(): | ||
118 | 73 | new_cfg.add_section(section) | ||
119 | 74 | for option in config.options(section): | ||
120 | 75 | new_cfg.set(section, option, config.get(section, option)) | ||
121 | 76 | return new_cfg | ||
122 | 77 | |||
123 | 78 | |||
124 | 79 | def get_config(conffile=CONFIGFILE, confdir=CONFIGDIR): | ||
125 | 80 | global CONFIG | ||
126 | 81 | config = CONFIG | ||
127 | 82 | if not config: | ||
128 | 83 | dbg('Loading new config') | ||
129 | 84 | if not os.path.isfile(conffile): | ||
130 | 85 | config = create_config(conffile) | ||
131 | 86 | config = ConfigParser.SafeConfigParser(DEFAULTS) | ||
132 | 87 | config.add_section("terminal") | ||
133 | 88 | config.read([conffile]) | ||
134 | 89 | CONFIG = config | ||
135 | 90 | else: | ||
136 | 91 | dbg('Reusing already loaded config') | ||
137 | 92 | return config | ||
138 | 93 | |||
139 | 94 | |||
140 | 95 | def save_config(config, conffile=CONFIGFILE): | ||
141 | 96 | global CONFIG | ||
142 | 97 | dbg('Saving conffile at %s'%conffile) | ||
143 | 98 | with open(CONFIGFILE, 'wb') as f: | ||
144 | 99 | config.write(f) | ||
145 | 100 | CONFIG = config | ||
146 | 101 | |||
147 | 102 | class Cheatsheet: | ||
148 | 103 | ''' | ||
149 | 104 | comtainer class for the cheatsheet | ||
150 | 105 | |||
151 | 106 | Example of usage: | ||
152 | 107 | >>> c = config.Cheatsheet() | ||
153 | 108 | >>> c.load('/home/cascara/.clicompanion2') | ||
154 | 109 | >>> c[3] | ||
155 | 110 | ['uname -a', '', 'What kernel am I running\n'] | ||
156 | 111 | >>> c.file | ||
157 | 112 | '/home/cascara/.clicompanion2' | ||
158 | 113 | >>> c[2]=[ 'mycmd', 'userui', 'desc' ] | ||
159 | 114 | >>> c[2] | ||
160 | 115 | ['mycmd', 'userui', 'desc'] | ||
161 | 116 | >>> del c[2] | ||
162 | 117 | >>> c[2] | ||
163 | 118 | ['ps aux | grep ?', 'search string', 'Search active processes for search string\n'] | ||
164 | 119 | >>> c.insert('cmd2','ui2','desc2',2) | ||
165 | 120 | >>> c[2] | ||
166 | 121 | ['cmd2', 'ui2', 'desc2'] | ||
167 | 122 | |||
168 | 123 | ''' | ||
169 | 124 | def __init__(self): | ||
170 | 125 | self.file = CHEATSHEET | ||
171 | 126 | self.commands = [] | ||
172 | 127 | |||
173 | 128 | def __repr__(self): | ||
174 | 129 | return 'Config: %s - %s'%(self.file, self.commands) | ||
175 | 130 | |||
176 | 131 | def load(self, cheatfile=None): | ||
177 | 132 | if not cheatfile: | ||
178 | 133 | self.file = CHEATSHEET | ||
179 | 134 | if not os.path.exists(CHEATSHEET): | ||
180 | 135 | if os.path.exists(CONFIG_ORIG): | ||
181 | 136 | os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET)) | ||
182 | 137 | else: | ||
183 | 138 | # Oops! Looks like there's no default cheatsheet. | ||
184 | 139 | # Then, create an empty cheatsheet. | ||
185 | 140 | open(CHEATSHEET, 'w').close() | ||
186 | 141 | else: | ||
187 | 142 | self.file = cheatfile | ||
188 | 143 | try: | ||
189 | 144 | dbg('Reading cheatsheet from file %s'%self.file) | ||
190 | 145 | with open(self.file, 'r') as ch_fd: | ||
191 | 146 | ## try to detect if the line is a old fashines config line | ||
192 | 147 | ## (separated by ':'), when saved will rewrite it | ||
193 | 148 | no_tabs = True | ||
194 | 149 | some_colon = False | ||
195 | 150 | for line in ch_fd: | ||
196 | 151 | line = line.strip() | ||
197 | 152 | if not line: | ||
198 | 153 | continue | ||
199 | 154 | cmd, ui, desc = [ l.strip() for l in line.split('\t',2)] \ | ||
200 | 155 | + ['',]*(3-len(line.split('\t',2))) | ||
201 | 156 | if ':' in cmd: | ||
202 | 157 | some_colon = True | ||
203 | 158 | if ui or desc: | ||
204 | 159 | no_tabs = False | ||
205 | 160 | if cmd and [ cmd, ui, desc ] not in self.commands: | ||
206 | 161 | self.commands.append([cmd, ui, desc]) | ||
207 | 162 | dbg('Adding command %s'%[cmd, ui, desc]) | ||
208 | 163 | if no_tabs and some_colon: | ||
209 | 164 | ## None of the commands had tabs, and all had ':' in the | ||
210 | 165 | ## cmd... most probably old config style | ||
211 | 166 | print _("Detected old cheatsheet style at")\ | ||
212 | 167 | +" %s"%self.file+_(", parsing to new one.") | ||
213 | 168 | for i in range(len(self.commands)): | ||
214 | 169 | cmd, ui, desc = self.commands[i] | ||
215 | 170 | cmd, ui, desc = [ l.strip() for l in cmd.split(':',2)] \ | ||
216 | 171 | + ['',]*(3-len(cmd.split(':',2))) | ||
217 | 172 | self.commands[i] = [cmd, ui, desc] | ||
218 | 173 | self.save() | ||
219 | 174 | except IOError, e: | ||
220 | 175 | print _("Error while loading cheatfile")+" %s: %s"%(self.file, e) | ||
221 | 176 | |||
222 | 177 | def save(self, cheatfile=None): | ||
223 | 178 | ''' | ||
224 | 179 | Saves the current config to the file cheatfile, or the file that was | ||
225 | 180 | loaded. | ||
226 | 181 | NOTE: It does not overwrite the value self.file, that points to the file | ||
227 | 182 | that was loaded | ||
228 | 183 | ''' | ||
229 | 184 | if not cheatfile and self.file: | ||
230 | 185 | cheatfile = self.file | ||
231 | 186 | elif not cheatfile: | ||
232 | 187 | return False | ||
233 | 188 | try: | ||
234 | 189 | with open(cheatfile, 'wb') as ch_fd: | ||
235 | 190 | for command in self.commands: | ||
236 | 191 | ch_fd.write('\t'.join(command)+'\n') | ||
237 | 192 | except IOError, e: | ||
238 | 193 | print _("Error writing cheatfile")+" %s: %s"%(cheatfile, e) | ||
239 | 194 | return False | ||
240 | 195 | return True | ||
241 | 196 | |||
242 | 197 | def __len__(self): | ||
243 | 198 | return len(self.commands) | ||
244 | 199 | |||
245 | 200 | def __getitem__(self, key): | ||
246 | 201 | return self.commands[key] | ||
247 | 202 | |||
248 | 203 | def __setitem__(self, key, value): | ||
249 | 204 | if not isinstance(value, collections.Iterable) or len(value) < 3: | ||
250 | 205 | raise ValueError('Value must be a container with three items, but got %s'%value) | ||
251 | 206 | if key < len(self.commands): | ||
252 | 207 | self.commands[key]=list(value) | ||
253 | 208 | else: | ||
254 | 209 | try: | ||
255 | 210 | self.insert(*value, pos=key) | ||
256 | 211 | except ValueError, e: | ||
257 | 212 | raise ValueError('Value must be a container with three items, but got %s'%value) | ||
258 | 213 | |||
259 | 214 | def __iter__(self): | ||
260 | 215 | for command in self.commands: | ||
261 | 216 | yield command | ||
262 | 217 | |||
263 | 218 | def insert(self, cmd, ui, desc, pos=None): | ||
264 | 219 | if not [cmd, ui, desc] in self.commands: | ||
265 | 220 | if not pos: | ||
266 | 221 | self.commands.append([cmd, ui, desc]) | ||
267 | 222 | else: | ||
268 | 223 | self.commands.insert(pos, [cmd, ui, desc]) | ||
269 | 224 | |||
270 | 225 | def append(self, cmd, ui, desc): | ||
271 | 226 | self.insert(cmd, ui, desc) | ||
272 | 227 | |||
273 | 228 | def index(self, cmd, ui, value): | ||
274 | 229 | return self.commands.index([cmd, ui, desc]) | ||
275 | 230 | |||
276 | 231 | def __delitem__(self, key): | ||
277 | 232 | del self.commands[key] | ||
278 | 233 | |||
279 | 234 | def pop(self, key): | ||
280 | 235 | return self.commands.pop(key) | ||
281 | 236 | |||
282 | 237 | def del_by_value(self, cmd, ui, desc): | ||
283 | 238 | if [cmd, ui, desc] in self.commands: | ||
284 | 239 | return self.commands.pop(self.commands.index([cmd, ui, desc])) | ||
285 | 240 | |||
286 | 241 | def drag_n_drop(self, cmd1, cmd2, before=True): | ||
287 | 242 | if cmd1 in self.commands: | ||
288 | 243 | dbg('Dropping command from inside %s'%'_\t_'.join(cmd1)) | ||
289 | 244 | i1 = self.commands.index(cmd1) | ||
290 | 245 | del self.commands[i1] | ||
291 | 246 | if cmd2: | ||
292 | 247 | i2 = self.commands.index(cmd2) | ||
293 | 248 | if before: | ||
294 | 249 | self.commands.insert(i2, cmd1) | ||
295 | 250 | else: | ||
296 | 251 | self.commands.insert(i2+1, cmd1) | ||
297 | 252 | else: | ||
298 | 253 | self.commands.append(cmd1) | ||
299 | 254 | else: | ||
300 | 255 | dbg('Dropping command from outside %s'%'_\t_'.join(cmd1)) | ||
301 | 256 | if cmd2: | ||
302 | 257 | i2 = self.commands.index(cmd2) | ||
303 | 258 | if before: | ||
304 | 259 | self.commands.insert(i2, cmd1) | ||
305 | 260 | else: | ||
306 | 261 | self.commands.insert(i2+1, cmd1) | ||
307 | 262 | else: | ||
308 | 263 | self.commands.append(cmd1) | ||
309 | 53 | 264 | ||
310 | === modified file 'clicompanionlib/controller.py' | |||
311 | --- clicompanionlib/controller.py 2011-12-31 14:49:46 +0000 | |||
312 | +++ clicompanionlib/controller.py 2012-01-02 01:28:26 +0000 | |||
313 | @@ -19,17 +19,21 @@ | |||
314 | 19 | # | 19 | # |
315 | 20 | # | 20 | # |
316 | 21 | 21 | ||
322 | 22 | from clicompanionlib.utils import get_user_shell | 22 | import os |
318 | 23 | |||
319 | 24 | import clicompanionlib.tabs | ||
320 | 25 | import view | ||
321 | 26 | |||
323 | 27 | import pygtk | 23 | import pygtk |
324 | 28 | pygtk.require('2.0') | 24 | pygtk.require('2.0') |
325 | 29 | import re | 25 | import re |
326 | 30 | import webbrowser | 26 | import webbrowser |
329 | 31 | import ConfigParser | 27 | import view |
330 | 32 | import os | 28 | import copy |
331 | 29 | import clicompanionlib.tabs | ||
332 | 30 | import clicompanionlib.config as cc_config | ||
333 | 31 | import clicompanionlib.utils as utils | ||
334 | 32 | from clicompanionlib.utils import get_user_shell, dbg | ||
335 | 33 | |||
336 | 34 | #if cc_config.get_config().get('terminal','debug') == 'True': | ||
337 | 35 | # utils.DEBUG = True | ||
338 | 36 | |||
339 | 33 | # import vte and gtk or print error | 37 | # import vte and gtk or print error |
340 | 34 | try: | 38 | try: |
341 | 35 | import gtk | 39 | import gtk |
342 | @@ -49,27 +53,17 @@ | |||
343 | 49 | 53 | ||
344 | 50 | 54 | ||
345 | 51 | 55 | ||
346 | 52 | CHEATSHEET = os.path.expanduser("~/.clicompanion2") | ||
347 | 53 | CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config" | ||
348 | 54 | CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config") | ||
349 | 55 | |||
350 | 56 | class Actions(object): | 56 | class Actions(object): |
351 | 57 | #make instances of the Classes we are going to use | ||
352 | 58 | #main_window = view.MainWindow | ||
353 | 59 | ## Info Dialog Box | 57 | ## Info Dialog Box |
354 | 60 | ## if a command needs more info EX: a package name, a path | 58 | ## if a command needs more info EX: a package name, a path |
361 | 61 | def get_info(self, widget, liststore): | 59 | def get_info(self, cmd, ui, desc): |
362 | 62 | 60 | dbg('Got command with user input') | |
357 | 63 | if not view.ROW: | ||
358 | 64 | return | ||
359 | 65 | row_int = int(view.ROW[0][0]) | ||
360 | 66 | |||
363 | 67 | ## Create Dialog object | 61 | ## Create Dialog object |
364 | 68 | dialog = gtk.MessageDialog( | 62 | dialog = gtk.MessageDialog( |
365 | 69 | None, | 63 | None, |
366 | 70 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, | 64 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, |
367 | 71 | gtk.MESSAGE_QUESTION, | 65 | gtk.MESSAGE_QUESTION, |
369 | 72 | gtk.BUTTONS_OK, | 66 | gtk.BUTTONS_OK_CANCEL, |
370 | 73 | None) | 67 | None) |
371 | 74 | 68 | ||
372 | 75 | # Primary text | 69 | # Primary text |
373 | @@ -82,16 +76,16 @@ | |||
374 | 82 | 76 | ||
375 | 83 | ## create a horizontal box to pack the entry and a label | 77 | ## create a horizontal box to pack the entry and a label |
376 | 84 | hbox = gtk.HBox() | 78 | hbox = gtk.HBox() |
378 | 85 | hbox.pack_start(gtk.Label(liststore[row_int][1]+":"), False, 5, 5) | 79 | hbox.pack_start(gtk.Label(ui+":"), False, 5, 5) |
379 | 86 | hbox.pack_end(entry) | 80 | hbox.pack_end(entry) |
380 | 87 | ## some secondary text | 81 | ## some secondary text |
382 | 88 | dialog.format_secondary_markup(_("Please provide a "+liststore[row_int][1])) | 82 | dialog.format_secondary_markup(_("Please provide a "+ui)) |
383 | 89 | ## add it and show it | 83 | ## add it and show it |
384 | 90 | dialog.vbox.pack_end(hbox, True, True, 0) | 84 | dialog.vbox.pack_end(hbox, True, True, 0) |
385 | 91 | dialog.show_all() | 85 | dialog.show_all() |
386 | 92 | 86 | ||
387 | 93 | ## Show the dialog | 87 | ## Show the dialog |
389 | 94 | dialog.run() | 88 | response = dialog.run() |
390 | 95 | 89 | ||
391 | 96 | ## user text assigned to a variable | 90 | ## user text assigned to a variable |
392 | 97 | text = entry.get_text() | 91 | text = entry.get_text() |
393 | @@ -100,13 +94,15 @@ | |||
394 | 100 | ## The destroy method must be called otherwise the 'Close' button will | 94 | ## The destroy method must be called otherwise the 'Close' button will |
395 | 101 | ## not work. | 95 | ## not work. |
396 | 102 | dialog.destroy() | 96 | dialog.destroy() |
397 | 97 | if response != gtk.RESPONSE_OK: | ||
398 | 98 | user_input = None | ||
399 | 103 | return user_input | 99 | return user_input |
400 | 104 | 100 | ||
401 | 105 | def responseToDialog(self, text, dialog, response): | 101 | def responseToDialog(self, text, dialog, response): |
402 | 106 | dialog.response(response) | 102 | dialog.response(response) |
403 | 107 | 103 | ||
404 | 108 | ## Add command dialog box | 104 | ## Add command dialog box |
406 | 109 | def add_command(self, widget, liststore): | 105 | def add_command(self, mw): |
407 | 110 | 106 | ||
408 | 111 | ## Create Dialog object | 107 | ## Create Dialog object |
409 | 112 | dialog = gtk.MessageDialog( | 108 | dialog = gtk.MessageDialog( |
410 | @@ -141,15 +137,16 @@ | |||
411 | 141 | hbox2.pack_start(entry3, True, 5, 5) | 137 | hbox2.pack_start(entry3, True, 5, 5) |
412 | 142 | 138 | ||
413 | 143 | ## cancel button | 139 | ## cancel button |
415 | 144 | dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT) | 140 | dialog.add_button(_('Cancel'), gtk.RESPONSE_DELETE_EVENT) |
416 | 145 | ## some secondary text | 141 | ## some secondary text |
424 | 146 | dialog.format_secondary_markup(_('When entering a command use question ' | 142 | dialog.format_secondary_markup( |
425 | 147 | 'marks(?) as placeholders if user input is required when the ' | 143 | _("When entering a command use question marks(?) as placeholders if" |
426 | 148 | 'command runs. Example: ls /any/directory would be entered as, ' | 144 | " user input is required when the command runs. Example: ls " |
427 | 149 | 'ls ? .For each question mark(?) in your command, if any, use ' | 145 | "/any/directory would be entered as, ls ? .For each question " |
428 | 150 | 'the User Input field to provide a hint for each variable. ' | 146 | "mark(?) in your command, if any, use the User Input field to " |
429 | 151 | 'Using our example ls ? you could put directory as the User ' | 147 | "provide a hint for each variable. Using our example ls ? you " |
430 | 152 | 'Input. Lastly provide a brief Description.')) | 148 | "could put directory as the User Input. Lastly provide a brief " |
431 | 149 | "Description.")) | ||
432 | 153 | 150 | ||
433 | 154 | ## add it and show it | 151 | ## add it and show it |
434 | 155 | dialog.vbox.pack_end(hbox2, True, True, 0) | 152 | dialog.vbox.pack_end(hbox2, True, True, 0) |
435 | @@ -163,24 +160,10 @@ | |||
436 | 163 | text1 = entry1.get_text() | 160 | text1 = entry1.get_text() |
437 | 164 | text2 = entry2.get_text() | 161 | text2 = entry2.get_text() |
438 | 165 | text3 = entry3.get_text() | 162 | text3 = entry3.get_text() |
457 | 166 | '''open flat file, add the new command, update CMNDS variable | 163 | ## update commandsand sync with screen ''' |
458 | 167 | ## update commands in liststore (on screen) ''' | 164 | view.CMNDS.append(text1, text2, text3) |
459 | 168 | if text1 != "": | 165 | mw.sync_cmnds() |
460 | 169 | with open(CHEATSHEET, "r") as cheatfile: | 166 | view.CMNDS.save() |
443 | 170 | cheatlines = cheatfile.readlines() | ||
444 | 171 | cheatlines.append(text1+"\t"+text2+"\t"+text3+'\n') | ||
445 | 172 | cheatfile.close() | ||
446 | 173 | with open(CHEATSHEET, "w") as cheatfile2: | ||
447 | 174 | cheatfile2.writelines(cheatlines) | ||
448 | 175 | cheatfile2.close() | ||
449 | 176 | l = str(text1+"\t"+text2+"\t"+text3) | ||
450 | 177 | #ls = l.split(':',2) | ||
451 | 178 | ## update view.CMNDS variable | ||
452 | 179 | filteredcommandplus = text1, text2, text3 | ||
453 | 180 | view.CMNDS.append(filteredcommandplus) | ||
454 | 181 | ## update the command list on screen | ||
455 | 182 | liststore.append([text1,text2,text3]) | ||
456 | 183 | |||
461 | 184 | 167 | ||
462 | 185 | ## The destroy method must be called otherwise the 'Close' button will | 168 | ## The destroy method must be called otherwise the 'Close' button will |
463 | 186 | ## not work. | 169 | ## not work. |
464 | @@ -188,32 +171,14 @@ | |||
465 | 188 | #return text | 171 | #return text |
466 | 189 | 172 | ||
467 | 190 | ## This the edit function | 173 | ## This the edit function |
470 | 191 | def edit_command(self, widget , liststore): | 174 | def edit_command(self, mw): |
469 | 192 | |||
471 | 193 | if not view.ROW: | 175 | if not view.ROW: |
472 | 194 | return | 176 | return |
495 | 195 | row_int_x = int(view.ROW[0][0]) | 177 | lst_index = int(view.ROW[0][0]) |
496 | 196 | row_int = 0 | 178 | model = mw.treeview.get_model() |
497 | 197 | ## TODO: Not implemented with filted yet | 179 | cmd = ''.join(model[lst_index][0]) |
498 | 198 | if view.FILTER == 1: | 180 | ui = ''.join(model[lst_index][1]) |
499 | 199 | with open(CHEATSHEET, "r") as cheatfile: | 181 | desc = ''.join(model[lst_index][2]) |
478 | 200 | cheatlines = cheatfile.readlines() | ||
479 | 201 | for i in range(len(cheatlines)): | ||
480 | 202 | if view.CMNDS[row_int_x][0] in cheatlines[i] and view.CMNDS[row_int_x][1] in cheatlines[i] : | ||
481 | 203 | row_int = i | ||
482 | 204 | cheatfile.close() | ||
483 | 205 | else: | ||
484 | 206 | row_int = row_int_x | ||
485 | 207 | |||
486 | 208 | |||
487 | 209 | row_obj1 = view.MainWindow.liststore[row_int][0] | ||
488 | 210 | text1 = "".join(row_obj1) | ||
489 | 211 | |||
490 | 212 | row_obj2 = view.MainWindow.liststore[row_int][1] | ||
491 | 213 | text2 = "".join(row_obj2) | ||
492 | 214 | |||
493 | 215 | row_obj3 = view.MainWindow.liststore[row_int][2] | ||
494 | 216 | text3 = "".join(row_obj3) | ||
500 | 217 | 182 | ||
501 | 218 | ## Create Dialog object | 183 | ## Create Dialog object |
502 | 219 | dialog = gtk.MessageDialog( | 184 | dialog = gtk.MessageDialog( |
503 | @@ -228,11 +193,11 @@ | |||
504 | 228 | 193 | ||
505 | 229 | ## create the text input fields | 194 | ## create the text input fields |
506 | 230 | entry1 = gtk.Entry() | 195 | entry1 = gtk.Entry() |
508 | 231 | entry1.set_text(text1) | 196 | entry1.set_text(cmd) |
509 | 232 | entry2 = gtk.Entry() | 197 | entry2 = gtk.Entry() |
511 | 233 | entry2.set_text(text2) | 198 | entry2.set_text(ui) |
512 | 234 | entry3 = gtk.Entry() | 199 | entry3 = gtk.Entry() |
514 | 235 | entry3.set_text(text3) | 200 | entry3.set_text(desc) |
515 | 236 | ## allow the user to press enter to do ok | 201 | ## allow the user to press enter to do ok |
516 | 237 | entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK) | 202 | entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK) |
517 | 238 | 203 | ||
518 | @@ -249,7 +214,7 @@ | |||
519 | 249 | hbox2.pack_start(entry3, True, 5, 5) | 214 | hbox2.pack_start(entry3, True, 5, 5) |
520 | 250 | 215 | ||
521 | 251 | ## cancel button | 216 | ## cancel button |
523 | 252 | dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT) | 217 | dialog.add_button(_('Cancel'), gtk.RESPONSE_DELETE_EVENT) |
524 | 253 | ## some secondary text | 218 | ## some secondary text |
525 | 254 | dialog.format_secondary_markup(_("Please provide a command, description, and what type of user variable, if any, is required.")) | 219 | dialog.format_secondary_markup(_("Please provide a command, description, and what type of user variable, if any, is required.")) |
526 | 255 | 220 | ||
527 | @@ -262,64 +227,35 @@ | |||
528 | 262 | 227 | ||
529 | 263 | if result == gtk.RESPONSE_OK: | 228 | if result == gtk.RESPONSE_OK: |
530 | 264 | ## user text assigned to a variable | 229 | ## user text assigned to a variable |
534 | 265 | text1 = entry1.get_text() | 230 | cmd = entry1.get_text() |
535 | 266 | text2 = entry2.get_text() | 231 | ui = entry2.get_text() |
536 | 267 | text3 = entry3.get_text() | 232 | desc = entry3.get_text() |
537 | 268 | 233 | ||
558 | 269 | if text1 != "": | 234 | if cmd != "": |
559 | 270 | self.remove_command(widget, liststore) | 235 | cmd_index = model[lst_index][3] |
560 | 271 | '''open flat file, add the new command, update CMNDS variable | 236 | dbg('Got index %d for command at pos %d'%(cmd_index, lst_index)) |
561 | 272 | ## update commands in liststore (on screen) ''' | 237 | view.CMNDS[cmd_index] = [cmd, ui, desc] |
562 | 273 | 238 | mw.sync_cmnds() | |
563 | 274 | with open(CHEATSHEET, "r") as cheatfile: | 239 | view.CMNDS.save() |
544 | 275 | cheatlines = cheatfile.readlines() | ||
545 | 276 | cheatlines.append(text1+":"+text2+":"+text3+'\n') | ||
546 | 277 | cheatfile.close() | ||
547 | 278 | with open(CHEATSHEET, "w") as cheatfile2: | ||
548 | 279 | cheatfile2.writelines(cheatlines) | ||
549 | 280 | cheatfile2.close() | ||
550 | 281 | l = str(text1+":"+text2+":"+text3) | ||
551 | 282 | #ls = l.split(':',2) | ||
552 | 283 | ## update view.CMNDS variable | ||
553 | 284 | filteredcommandplus = text1, text2, text3 | ||
554 | 285 | view.CMNDS.append(filteredcommandplus) | ||
555 | 286 | ## update the command list on screen | ||
556 | 287 | liststore.append([text1,text2,text3]) | ||
557 | 288 | |||
564 | 289 | ## The destroy method must be called otherwise the 'Close' button will | 240 | ## The destroy method must be called otherwise the 'Close' button will |
565 | 290 | ## not work. | 241 | ## not work. |
566 | 291 | dialog.destroy() | 242 | dialog.destroy() |
567 | 292 | 243 | ||
568 | 293 | 244 | ||
569 | 294 | ## Remove command from command file and GUI | 245 | ## Remove command from command file and GUI |
572 | 295 | def remove_command(self, widget, liststore): | 246 | def remove_command(self, mw): |
571 | 296 | |||
573 | 297 | if not view.ROW: | 247 | if not view.ROW: |
574 | 298 | return | 248 | return |
599 | 299 | row_int_x = int(view.ROW[0][0]) | 249 | ## get selected row |
600 | 300 | row_int = 0 | 250 | lst_index = int(view.ROW[0][0]) |
601 | 301 | ## TODO: Not implemented with filted yet | 251 | ## get selected element index, even from search filter |
602 | 302 | if view.FILTER == 1: | 252 | model = mw.treeview.get_model() |
603 | 303 | with open(CHEATSHEET, "r") as cheatfile: | 253 | cmd_index = model[lst_index][3] |
604 | 304 | cheatlines = cheatfile.readlines() | 254 | ## delete element from liststore and CMNDS |
605 | 305 | for i in range(len(cheatlines)): | 255 | del view.CMNDS[cmd_index] |
606 | 306 | if view.CMNDS[row_int_x][0] in cheatlines[i] and view.CMNDS[row_int_x][1] in cheatlines[i]: | 256 | mw.sync_cmnds() |
607 | 307 | row_int = i | 257 | ## save changes |
608 | 308 | cheatfile.close() | 258 | view.CMNDS.save() |
585 | 309 | else: | ||
586 | 310 | row_int = row_int_x | ||
587 | 311 | |||
588 | 312 | del view.CMNDS[row_int_x] | ||
589 | 313 | del liststore[row_int] | ||
590 | 314 | |||
591 | 315 | ## open command file and delete line so the change is persistent | ||
592 | 316 | with open(CHEATSHEET, "r") as cheatfile: | ||
593 | 317 | cheatlines = cheatfile.readlines() | ||
594 | 318 | del cheatlines[row_int] | ||
595 | 319 | cheatfile.close() | ||
596 | 320 | with open(CHEATSHEET, "w") as cheatfile2: | ||
597 | 321 | cheatfile2.writelines(cheatlines) | ||
598 | 322 | cheatfile2.close() | ||
609 | 323 | 259 | ||
610 | 324 | 260 | ||
611 | 325 | def _filter_commands(self, widget, liststore, treeview): | 261 | def _filter_commands(self, widget, liststore, treeview): |
612 | @@ -330,11 +266,13 @@ | |||
613 | 330 | Pretty straight-forward. | 266 | Pretty straight-forward. |
614 | 331 | """ | 267 | """ |
615 | 332 | search_term = widget.get_text().lower() | 268 | search_term = widget.get_text().lower() |
616 | 269 | ## If the search term is empty, restore the liststore | ||
617 | 333 | if search_term == "": | 270 | if search_term == "": |
622 | 334 | view.FILTER = 0 | 271 | view.FILTER = 0 |
623 | 335 | else: | 272 | treeview.set_model(liststore) |
624 | 336 | view.FILTER = 1 | 273 | return |
625 | 337 | 274 | ||
626 | 275 | view.FILTER = 1 | ||
627 | 338 | ## Create a TreeModelFilter object which provides auxiliary functions for | 276 | ## Create a TreeModelFilter object which provides auxiliary functions for |
628 | 339 | ## filtering data. | 277 | ## filtering data. |
629 | 340 | ## http://www.pygtk.org/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html | 278 | ## http://www.pygtk.org/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html |
630 | @@ -356,39 +294,31 @@ | |||
631 | 356 | ## Python raises a AttributeError if row data was modified . Catch | 294 | ## Python raises a AttributeError if row data was modified . Catch |
632 | 357 | ## that and fail silently. | 295 | ## that and fail silently. |
633 | 358 | pass | 296 | pass |
634 | 359 | |||
635 | 360 | |||
636 | 361 | modelfilter.set_visible_func(search, search_term) | 297 | modelfilter.set_visible_func(search, search_term) |
637 | 298 | ## save the old liststore and cmnds | ||
638 | 362 | treeview.set_model(modelfilter) | 299 | treeview.set_model(modelfilter) |
639 | 363 | |||
640 | 364 | |||
641 | 365 | #clear CMNDS list then populate it with the filteredlist of commands | ||
642 | 366 | view.CMNDS = [] | ||
643 | 367 | for line in modelfilter: | ||
644 | 368 | filteredcommandplus = tuple(modelfilter.get(line.iter, 0, 1, 2)) | ||
645 | 369 | view.CMNDS.append(filteredcommandplus) | ||
646 | 370 | |||
647 | 371 | |||
648 | 372 | 300 | ||
649 | 373 | ## send the command to the terminal | 301 | ## send the command to the terminal |
651 | 374 | def run_command(self, widget, notebook, liststore): | 302 | def run_command(self, mw): |
652 | 375 | 303 | ||
653 | 376 | ## if called without selecting a command from the list return | 304 | ## if called without selecting a command from the list return |
654 | 377 | if not view.ROW: | 305 | if not view.ROW: |
655 | 378 | return | 306 | return |
656 | 379 | text = "" | 307 | text = "" |
658 | 380 | row_int = int(view.ROW[0][0]) ## removes everything but number from [5,] | 308 | lst_index = int(view.ROW[0][0]) ## removes everything but number from [5,] |
659 | 381 | 309 | ||
660 | 382 | ## get the current notebook page so the function knows which terminal to run the command in. | 310 | ## get the current notebook page so the function knows which terminal to run the command in. |
663 | 383 | pagenum = notebook.get_current_page() | 311 | pagenum = mw.notebook.get_current_page() |
664 | 384 | widget = notebook.get_nth_page(pagenum) | 312 | widget = mw.notebook.get_nth_page(pagenum) |
665 | 385 | page_widget = widget.get_child() | 313 | page_widget = widget.get_child() |
666 | 386 | 314 | ||
669 | 387 | ## view.CMNDS is where commands are stored | 315 | model = mw.treeview.get_model() |
670 | 388 | cmnd = view.CMNDS[row_int][0] | 316 | cmd = ''.join(model[lst_index][0]) |
671 | 317 | ui = ''.join(model[lst_index][1]) | ||
672 | 318 | desc = ''.join(model[lst_index][2]) | ||
673 | 389 | 319 | ||
674 | 390 | ## find how many ?(user arguments) are in command | 320 | ## find how many ?(user arguments) are in command |
676 | 391 | match = re.findall('\?', cmnd) | 321 | match = re.findall('\?', cmd) |
677 | 392 | ''' | 322 | ''' |
678 | 393 | Make sure user arguments were found. Replace ? with something | 323 | Make sure user arguments were found. Replace ? with something |
679 | 394 | .format can read. This is done so the user can just enter ?, when | 324 | .format can read. This is done so the user can just enter ?, when |
680 | @@ -400,23 +330,33 @@ | |||
681 | 400 | else: | 330 | else: |
682 | 401 | num = len(match) | 331 | num = len(match) |
683 | 402 | ran = 0 | 332 | ran = 0 |
697 | 403 | new_cmnd = self.replace(cmnd, num, ran) | 333 | new_cmnd = self.replace(cmd, num, ran) |
698 | 404 | 334 | ||
699 | 405 | 335 | if len(match) > 0: # command with user input | |
700 | 406 | if not view.CMNDS[row_int][1] == "": # command with user input | 336 | dbg('command with ui') |
701 | 407 | c = "" | 337 | f_cmd = "" |
702 | 408 | try: | 338 | while True: |
703 | 409 | text = self.get_info(self, liststore) | 339 | try: |
704 | 410 | c = new_cmnd.format(text) | 340 | ui_text = self.get_info(cmd, ui, desc) |
705 | 411 | except: | 341 | if ui_text == None: |
706 | 412 | error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, | 342 | return |
707 | 413 | _("You need to enter full input. Click on [x] to continue.")) | 343 | dbg('Got ui "%s"'%' '.join(ui_text)) |
708 | 414 | error.run() | 344 | if ''.join(ui_text) == '': |
709 | 415 | page_widget.feed_child(c+"\n") #send command w/ input | 345 | raise IndexError |
710 | 346 | f_cmd = new_cmnd.format(ui_text) | ||
711 | 347 | except IndexError, e: | ||
712 | 348 | error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, \ | ||
713 | 349 | gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, | ||
714 | 350 | _("You need to enter full input. Space separated.")) | ||
715 | 351 | error.connect('response', lambda err, *x: err.destroy()) | ||
716 | 352 | error.run() | ||
717 | 353 | continue | ||
718 | 354 | break | ||
719 | 355 | page_widget.feed_child(f_cmd+"\n") #send command w/ input | ||
720 | 416 | page_widget.show() | 356 | page_widget.show() |
721 | 417 | page_widget.grab_focus() | 357 | page_widget.grab_focus() |
722 | 418 | else: ## command that has no user input | 358 | else: ## command that has no user input |
724 | 419 | page_widget.feed_child(cmnd+"\n") #send command | 359 | page_widget.feed_child(cmd+"\n") #send command |
725 | 420 | page_widget.show() | 360 | page_widget.show() |
726 | 421 | page_widget.grab_focus() | 361 | page_widget.grab_focus() |
727 | 422 | 362 | ||
728 | @@ -432,7 +372,9 @@ | |||
729 | 432 | return cmnd | 372 | return cmnd |
730 | 433 | 373 | ||
731 | 434 | ## open the man page for selected command | 374 | ## open the man page for selected command |
733 | 435 | def man_page(self, widget, notebook): | 375 | def man_page(self, notebook): |
734 | 376 | import subprocess as sp | ||
735 | 377 | import shlex | ||
736 | 436 | try: | 378 | try: |
737 | 437 | row_int = int(view.ROW[0][0]) # removes everything but number from EX: [5,] | 379 | row_int = int(view.ROW[0][0]) # removes everything but number from EX: [5,] |
738 | 438 | except IndexError: | 380 | except IndexError: |
739 | @@ -443,21 +385,67 @@ | |||
740 | 443 | gtk.MESSAGE_QUESTION, | 385 | gtk.MESSAGE_QUESTION, |
741 | 444 | gtk.BUTTONS_OK, | 386 | gtk.BUTTONS_OK, |
742 | 445 | None) | 387 | None) |
744 | 446 | dialog.set_markup('You must choose row to view help') | 388 | dialog.set_markup(_('You must choose a row to view the help')) |
745 | 447 | dialog.show_all() | 389 | dialog.show_all() |
746 | 448 | dialog.run() | 390 | dialog.run() |
747 | 449 | dialog.destroy() | 391 | dialog.destroy() |
748 | 450 | return | 392 | return |
749 | 393 | ## get the manpage for the command | ||
750 | 451 | cmnd = view.CMNDS[row_int][0] #CMNDS is where commands are store | 394 | cmnd = view.CMNDS[row_int][0] #CMNDS is where commands are store |
760 | 452 | splitcommand = self._filter_sudo_from(cmnd.split(" ")) | 395 | ## get each command for each pipe, It's not 100 accurate, but good |
761 | 453 | ## get current notebook tab to use in function | 396 | ## enough (by now) |
762 | 454 | pagenum = notebook.get_current_page() | 397 | commands = [] |
763 | 455 | widget = notebook.get_nth_page(pagenum) | 398 | next_part = True |
764 | 456 | page_widget = widget.get_child() | 399 | found_sudo = False |
765 | 457 | #send command to Terminal | 400 | for part in shlex.split(cmnd): |
766 | 458 | page_widget.feed_child("man "+splitcommand[0]+"| most \n") | 401 | if next_part: |
767 | 459 | page_widget.grab_focus() | 402 | if part == 'sudo' and not found_sudo: |
768 | 460 | page_widget.show() | 403 | found_sudo = True |
769 | 404 | commands.append('sudo') | ||
770 | 405 | else: | ||
771 | 406 | if part not in commands: | ||
772 | 407 | commands.append(part) | ||
773 | 408 | next_part = False | ||
774 | 409 | else: | ||
775 | 410 | if part in [ '||', '&&', '&', '|']: | ||
776 | 411 | next_part = True | ||
777 | 412 | |||
778 | 413 | notebook = gtk.Notebook() | ||
779 | 414 | notebook.set_scrollable(True) | ||
780 | 415 | notebook.popup_enable() | ||
781 | 416 | notebook.set_properties(group_id=0, tab_vborder=0, tab_hborder=1, tab_pos=gtk.POS_TOP) | ||
782 | 417 | ## create a tab for each command | ||
783 | 418 | for command in commands: | ||
784 | 419 | scrolled_page = gtk.ScrolledWindow() | ||
785 | 420 | scrolled_page.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | ||
786 | 421 | tab = gtk.HBox() | ||
787 | 422 | tab_label = gtk.Label(command) | ||
788 | 423 | tab_label.show() | ||
789 | 424 | tab.pack_start(tab_label) | ||
790 | 425 | page = gtk.TextView() | ||
791 | 426 | page.set_wrap_mode(gtk.WRAP_WORD) | ||
792 | 427 | page.set_editable(False) | ||
793 | 428 | page.set_cursor_visible(False) | ||
794 | 429 | try: | ||
795 | 430 | manpage = sp.check_output(["man",command]) | ||
796 | 431 | except sp.CalledProcessError, e: | ||
797 | 432 | manpage = _('Failed to get manpage for command "%s"\nReason:\n%s')%( | ||
798 | 433 | command, e) | ||
799 | 434 | textbuffer = page.get_buffer() | ||
800 | 435 | textbuffer.set_text(manpage) | ||
801 | 436 | scrolled_page.add(page) | ||
802 | 437 | notebook.append_page(scrolled_page, tab) | ||
803 | 438 | |||
804 | 439 | help_win = gtk.Dialog() | ||
805 | 440 | help_win.set_title(_("Man page for %s")%cmnd) | ||
806 | 441 | help_win.vbox.pack_start(notebook, True, True, 0) | ||
807 | 442 | button = gtk.Button("close") | ||
808 | 443 | button.connect_object("clicked", lambda self: self.destroy(), help_win) | ||
809 | 444 | button.set_flags(gtk.CAN_DEFAULT) | ||
810 | 445 | help_win.action_area.pack_start( button, True, True, 0) | ||
811 | 446 | button.grab_default() | ||
812 | 447 | help_win.set_default_size(500,600) | ||
813 | 448 | help_win.show_all() | ||
814 | 461 | 449 | ||
815 | 462 | 450 | ||
816 | 463 | @staticmethod | 451 | @staticmethod |
817 | @@ -471,7 +459,6 @@ | |||
818 | 471 | return command | 459 | return command |
819 | 472 | 460 | ||
820 | 473 | 461 | ||
821 | 474 | |||
822 | 475 | #TODO: Move to menus_buttons | 462 | #TODO: Move to menus_buttons |
823 | 476 | def copy_paste(self, vte, event, data=None): | 463 | def copy_paste(self, vte, event, data=None): |
824 | 477 | if event.button == 3: | 464 | if event.button == 3: |
825 | @@ -517,11 +504,11 @@ | |||
826 | 517 | 504 | ||
827 | 518 | # Add a short comment about the application, this appears below the application | 505 | # Add a short comment about the application, this appears below the application |
828 | 519 | # name in the dialog | 506 | # name in the dialog |
830 | 520 | dialog.set_comments('This is a CLI Companion program.') | 507 | dialog.set_comments(_('This is a CLI Companion program.')) |
831 | 521 | 508 | ||
832 | 522 | # Add license information, this is connected to the 'License' button | 509 | # Add license information, this is connected to the 'License' button |
833 | 523 | # and is displayed in a new window. | 510 | # and is displayed in a new window. |
835 | 524 | dialog.set_license('Distributed under the GNU license. You can see it at <http://www.gnu.org/licenses/>.') | 511 | dialog.set_license(_('Distributed under the GNU license. You can see it at <http://www.gnu.org/licenses/>.')) |
836 | 525 | 512 | ||
837 | 526 | # Show the dialog | 513 | # Show the dialog |
838 | 527 | dialog.run() | 514 | dialog.run() |
839 | @@ -529,11 +516,13 @@ | |||
840 | 529 | # The destroy method must be called otherwise the 'Close' button will | 516 | # The destroy method must be called otherwise the 'Close' button will |
841 | 530 | # not work. | 517 | # not work. |
842 | 531 | dialog.destroy() | 518 | dialog.destroy() |
843 | 519 | |||
844 | 520 | |||
845 | 532 | def help_event(self, widget, data=None): | 521 | def help_event(self, widget, data=None): |
847 | 533 | webbrowser.open("http://okiebuntu.homelinux.com/okwiki/clicompanion") | 522 | webbrowser.open("http://launchpad.net/clicompanion") |
848 | 534 | 523 | ||
849 | 524 | |||
850 | 535 | def usage_event(self, widget, data=None): | 525 | def usage_event(self, widget, data=None): |
851 | 536 | mw = view.MainWindow | ||
852 | 537 | dialog = gtk.Dialog("Usage", | 526 | dialog = gtk.Dialog("Usage", |
853 | 538 | None, | 527 | None, |
854 | 539 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, | 528 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, |
855 | @@ -573,139 +562,104 @@ | |||
856 | 573 | 562 | ||
857 | 574 | ## File --> Preferences | 563 | ## File --> Preferences |
858 | 575 | def changed_cb(self, combobox, config): | 564 | def changed_cb(self, combobox, config): |
860 | 576 | config.read(CONFIGFILE) | 565 | dbg('Changed encoding') |
861 | 577 | model = combobox.get_model() | 566 | model = combobox.get_model() |
862 | 578 | index = combobox.get_active() | 567 | index = combobox.get_active() |
864 | 579 | if index: | 568 | if index>=0: |
865 | 580 | text_e = model[index][0] | 569 | text_e = model[index][0] |
870 | 581 | config.set("terminal", "encoding", text_e) | 570 | encoding = text_e.split(':',1)[0].strip() |
871 | 582 | # Writing our configuration file | 571 | dbg('Setting encoding to "%s"'%encoding) |
872 | 583 | with open(CONFIGFILE, 'wb') as f: | 572 | config.set("terminal", "encoding", encoding) |
869 | 584 | config.write(f) | ||
873 | 585 | 573 | ||
874 | 586 | 574 | ||
878 | 587 | def color_set_fg_cb(self, colorbutton_fg, config): | 575 | def color_set_fg_cb(self, colorbutton_fg, config, tabs): |
879 | 588 | config.read(CONFIGFILE) | 576 | dbg('Changing fg color') |
877 | 589 | #colorf16 = colorbutton_fg.get_color() | ||
880 | 590 | colorf = self.color2hex(colorbutton_fg) | 577 | colorf = self.color2hex(colorbutton_fg) |
881 | 591 | config.set("terminal", "colorf", str(colorf)) | 578 | config.set("terminal", "colorf", str(colorf)) |
891 | 592 | # Writing our configuration file | 579 | tabs.update_all_term_config(config) |
892 | 593 | with open(CONFIGFILE, 'wb') as f: | 580 | |
893 | 594 | config.write(f) | 581 | |
894 | 595 | 582 | def color_set_bg_cb(self, colorbutton_bg, config, tabs): | |
895 | 596 | 583 | dbg('Changing bg color') | |
887 | 597 | |||
888 | 598 | def color_set_bg_cb(self, colorbutton_bg, config): | ||
889 | 599 | config.read(CONFIGFILE) | ||
890 | 600 | #colorb16 = colorbutton_bg.get_color() | ||
896 | 601 | colorb = self.color2hex(colorbutton_bg) | 584 | colorb = self.color2hex(colorbutton_bg) |
897 | 602 | config.set("terminal", "colorb", str(colorb)) | 585 | config.set("terminal", "colorb", str(colorb)) |
902 | 603 | # Writing our configuration file | 586 | tabs.update_all_term_config(config) |
899 | 604 | with open(CONFIGFILE, 'wb') as f: | ||
900 | 605 | config.write(f) | ||
901 | 606 | |||
903 | 607 | 587 | ||
904 | 608 | 588 | ||
905 | 609 | def color2hex(self, widget): | 589 | def color2hex(self, widget): |
906 | 610 | """Pull the colour values out of a Gtk ColorPicker widget and return them | 590 | """Pull the colour values out of a Gtk ColorPicker widget and return them |
907 | 611 | as 8bit hex values, sinces its default behaviour is to give 16bit values""" | 591 | as 8bit hex values, sinces its default behaviour is to give 16bit values""" |
908 | 612 | widcol = widget.get_color() | 592 | widcol = widget.get_color() |
909 | 613 | print widcol | ||
910 | 614 | return('#%02x%02x%02x' % (widcol.red>>8, widcol.green>>8, widcol.blue>>8)) | 593 | return('#%02x%02x%02x' % (widcol.red>>8, widcol.green>>8, widcol.blue>>8)) |
911 | 615 | 594 | ||
913 | 616 | def preferences(self, widget, data=None): | 595 | def preferences(self, tabs, data=None): |
914 | 617 | ''' | 596 | ''' |
915 | 618 | Preferences window | 597 | Preferences window |
916 | 619 | ''' | 598 | ''' |
919 | 620 | mw = view.MainWindow | 599 | dialog = gtk.Dialog(_("User Preferences"), |
918 | 621 | dialog = gtk.Dialog("User Preferences", | ||
920 | 622 | None, | 600 | None, |
921 | 623 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, | 601 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, |
922 | 624 | (gtk.STOCK_CANCEL, gtk.RESPONSE_CLOSE, | 602 | (gtk.STOCK_CANCEL, gtk.RESPONSE_CLOSE, |
923 | 625 | gtk.STOCK_OK, gtk.RESPONSE_OK)) | 603 | gtk.STOCK_OK, gtk.RESPONSE_OK)) |
924 | 626 | 604 | ||
928 | 627 | config = ConfigParser.RawConfigParser() | 605 | config = cc_config.get_config_copy() |
929 | 628 | config.read(CONFIGFILE) | 606 | |
927 | 629 | |||
930 | 630 | ##create the text input fields | 607 | ##create the text input fields |
931 | 631 | entry1 = gtk.Entry() | 608 | entry1 = gtk.Entry() |
932 | 632 | entry1.set_text(config.get('terminal', 'scrollb')) | 609 | entry1.set_text(config.get('terminal', 'scrollb')) |
933 | 633 | |||
934 | 634 | 610 | ||
935 | 635 | ##combobox for selecting encoding | 611 | ##combobox for selecting encoding |
936 | 636 | combobox = gtk.combo_box_new_text() | 612 | combobox = gtk.combo_box_new_text() |
942 | 637 | combobox.append_text('Select encoding:') | 613 | i=0 |
943 | 638 | combobox.append_text('UTF-8') | 614 | for encoding, desc in utils.encodings: |
944 | 639 | combobox.append_text('ISO-8859-1') | 615 | combobox.append_text(encoding + ': '+desc) |
945 | 640 | combobox.append_text('ISO-8859-15') | 616 | if encoding.strip().upper() == config.get('terminal','encoding').upper(): |
946 | 641 | 617 | active = i | |
947 | 618 | i=i+1 | ||
948 | 619 | combobox.set_active(active) | ||
949 | 642 | combobox.connect('changed', self.changed_cb, config) | 620 | combobox.connect('changed', self.changed_cb, config) |
950 | 643 | combobox.set_active(0) | ||
951 | 644 | 621 | ||
952 | 645 | ##colorbox for selecting text and background color | 622 | ##colorbox for selecting text and background color |
960 | 646 | colorbutton_fg = gtk.ColorButton(gtk.gdk.color_parse('white')) | 623 | colorbutton_fg = gtk.ColorButton( |
961 | 647 | colorbutton_bg = gtk.ColorButton(gtk.gdk.color_parse('black')) | 624 | gtk.gdk.color_parse(config.get('terminal','colorf'))) |
962 | 648 | 625 | colorbutton_bg = gtk.ColorButton( | |
963 | 649 | colorbutton_fg.connect('color-set', self.color_set_fg_cb, config) | 626 | gtk.gdk.color_parse(config.get('terminal','colorb'))) |
964 | 650 | colorbutton_bg.connect('color-set', self.color_set_bg_cb, config) | 627 | |
965 | 651 | 628 | colorbutton_fg.connect('color-set', self.color_set_fg_cb, config, tabs) | |
966 | 652 | #dialog.show_all() | 629 | colorbutton_bg.connect('color-set', self.color_set_bg_cb, config, tabs) |
967 | 653 | 630 | ||
968 | 654 | ## allow the user to press enter to do ok | 631 | ## allow the user to press enter to do ok |
969 | 655 | entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK) | 632 | entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK) |
970 | 656 | 633 | ||
974 | 657 | 634 | ## create the labels | |
972 | 658 | |||
973 | 659 | ## create three labels | ||
975 | 660 | hbox1 = gtk.HBox() | 635 | hbox1 = gtk.HBox() |
976 | 661 | hbox1.pack_start(gtk.Label(_("Scrollback")), False, 5, 5) | 636 | hbox1.pack_start(gtk.Label(_("Scrollback")), False, 5, 5) |
977 | 662 | hbox1.pack_start(entry1, False, 5, 5) | 637 | hbox1.pack_start(entry1, False, 5, 5) |
978 | 663 | 638 | ||
980 | 664 | hbox1.pack_start(gtk.Label(_("encoding")), False, 5, 5) | 639 | hbox1.pack_start(gtk.Label(_("Encoding")), False, 5, 5) |
981 | 665 | hbox1.pack_start(combobox, False, 5, 5) | 640 | hbox1.pack_start(combobox, False, 5, 5) |
982 | 666 | 641 | ||
983 | 667 | |||
984 | 668 | hbox2 = gtk.HBox() | 642 | hbox2 = gtk.HBox() |
986 | 669 | hbox2.pack_start(gtk.Label(_("font color")), False, 5, 5) | 643 | hbox2.pack_start(gtk.Label(_("Font color")), False, 5, 5) |
987 | 670 | hbox2.pack_start(colorbutton_fg, True, 5, 5) | 644 | hbox2.pack_start(colorbutton_fg, True, 5, 5) |
988 | 671 | 645 | ||
990 | 672 | hbox2.pack_start(gtk.Label(_("background color")), False, 5, 5) | 646 | hbox2.pack_start(gtk.Label(_("Background color")), False, 5, 5) |
991 | 673 | hbox2.pack_start(colorbutton_bg, True, 5, 5) | 647 | hbox2.pack_start(colorbutton_bg, True, 5, 5) |
992 | 674 | 648 | ||
993 | 675 | |||
994 | 676 | ## add it and show it | 649 | ## add it and show it |
995 | 677 | dialog.vbox.pack_end(hbox2, True, True, 0) | 650 | dialog.vbox.pack_end(hbox2, True, True, 0) |
996 | 678 | dialog.vbox.pack_end(hbox1, True, True, 0) | 651 | dialog.vbox.pack_end(hbox1, True, True, 0) |
997 | 679 | dialog.show_all() | 652 | dialog.show_all() |
999 | 680 | 653 | ||
1000 | 681 | result = dialog.run() | 654 | result = dialog.run() |
1001 | 682 | |||
1002 | 683 | if result == gtk.RESPONSE_OK: | 655 | if result == gtk.RESPONSE_OK: |
1003 | 684 | |||
1004 | 685 | ## user text assigned to a variable | 656 | ## user text assigned to a variable |
1005 | 686 | text_sb = entry1.get_text() | 657 | text_sb = entry1.get_text() |
1006 | 687 | |||
1007 | 688 | config.read(CONFIGFILE) | ||
1008 | 689 | config.set("terminal", "scrollb", text_sb) | 658 | config.set("terminal", "scrollb", text_sb) |
1020 | 690 | 659 | cc_config.save_config(config) | |
1021 | 691 | 660 | tabs.update_all_term_config() | |
1011 | 692 | |||
1012 | 693 | # Writing our configuration file | ||
1013 | 694 | with open(CONFIGFILE, 'wb') as f: | ||
1014 | 695 | config.write(f) | ||
1015 | 696 | |||
1016 | 697 | |||
1017 | 698 | ## instantiate tabs | ||
1018 | 699 | tabs = clicompanionlib.tabs.Tabs() | ||
1019 | 700 | tabs.update_term_config | ||
1022 | 701 | 661 | ||
1023 | 702 | ## The destroy method must be called otherwise the 'Close' button will | 662 | ## The destroy method must be called otherwise the 'Close' button will |
1024 | 703 | ## not work. | 663 | ## not work. |
1025 | 704 | dialog.destroy() | 664 | dialog.destroy() |
1026 | 705 | 665 | ||
1027 | 706 | def save_cmnds(self): | ||
1028 | 707 | with open(CHEATSHEET, "w") as cheatfile: | ||
1029 | 708 | for command in view.CMNDS: | ||
1030 | 709 | cheatfile.write('\t'.join(command)+'\n') | ||
1031 | 710 | |||
1032 | 711 | |||
1033 | 712 | 666 | ||
1034 | === modified file 'clicompanionlib/menus_buttons.py' | |||
1035 | --- clicompanionlib/menus_buttons.py 2011-11-16 10:48:50 +0000 | |||
1036 | +++ clicompanionlib/menus_buttons.py 2012-01-02 01:28:26 +0000 | |||
1037 | @@ -26,7 +26,11 @@ | |||
1038 | 26 | 26 | ||
1039 | 27 | class FileMenu(object): | 27 | class FileMenu(object): |
1040 | 28 | 28 | ||
1042 | 29 | def the_menu(self, actions, notebook, liststore): | 29 | def the_menu(self, mw): |
1043 | 30 | actions = mw.actions | ||
1044 | 31 | liststore = mw.liststore | ||
1045 | 32 | tabs = mw.tabs | ||
1046 | 33 | notebook = mw.notebook | ||
1047 | 30 | menu = gtk.Menu() | 34 | menu = gtk.Menu() |
1048 | 31 | #color = gtk.gdk.Color(65555, 62000, 65555) | 35 | #color = gtk.gdk.Color(65555, 62000, 65555) |
1049 | 32 | #menu.modify_bg(gtk.STATE_NORMAL, color) | 36 | #menu.modify_bg(gtk.STATE_NORMAL, color) |
1050 | @@ -43,33 +47,31 @@ | |||
1051 | 43 | ## Make 'Run' menu entry | 47 | ## Make 'Run' menu entry |
1052 | 44 | menu_item1 = gtk.MenuItem(_("Run Command [F4]")) | 48 | menu_item1 = gtk.MenuItem(_("Run Command [F4]")) |
1053 | 45 | menu.append(menu_item1) | 49 | menu.append(menu_item1) |
1055 | 46 | menu_item1.connect("activate", actions.run_command, notebook, liststore) | 50 | menu_item1.connect("activate", lambda *x: actions.run_command(mw)) |
1056 | 47 | menu_item1.show() | 51 | menu_item1.show() |
1057 | 48 | 52 | ||
1058 | 49 | ## Make 'Add' file menu entry | 53 | ## Make 'Add' file menu entry |
1059 | 50 | menu_item2 = gtk.MenuItem(_("Add Command [F5]")) | 54 | menu_item2 = gtk.MenuItem(_("Add Command [F5]")) |
1060 | 51 | menu.append(menu_item2) | 55 | menu.append(menu_item2) |
1062 | 52 | menu_item2.connect("activate", actions.add_command, liststore) | 56 | menu_item2.connect("activate", lambda *x: actions.add_command(mw)) |
1063 | 53 | menu_item2.show() | 57 | menu_item2.show() |
1064 | 54 | 58 | ||
1065 | 55 | ## Make 'Remove' file menu entry | 59 | ## Make 'Remove' file menu entry |
1066 | 56 | menu_item3 = gtk.MenuItem(_("Remove Command [F6]")) | 60 | menu_item3 = gtk.MenuItem(_("Remove Command [F6]")) |
1067 | 57 | menu.append(menu_item3) | 61 | menu.append(menu_item3) |
1069 | 58 | menu_item3.connect("activate", actions.remove_command, liststore) | 62 | menu_item3.connect("activate", lambda *x: actions.remove_command(mw)) |
1070 | 59 | menu_item3.show() | 63 | menu_item3.show() |
1071 | 60 | 64 | ||
1072 | 61 | ## Make 'Add Tab' file menu entry | 65 | ## Make 'Add Tab' file menu entry |
1073 | 62 | tab = tabs.Tabs() | ||
1074 | 63 | menu_item4 = gtk.MenuItem(_("Add Tab [F7]")) | 66 | menu_item4 = gtk.MenuItem(_("Add Tab [F7]")) |
1075 | 64 | menu.append(menu_item4) | 67 | menu.append(menu_item4) |
1077 | 65 | menu_item4.connect("activate", tab.add_tab, notebook) | 68 | menu_item4.connect("activate", lambda *x: tabs.add_tab(notebook)) |
1078 | 66 | menu_item4.show() | 69 | menu_item4.show() |
1079 | 67 | 70 | ||
1080 | 68 | ## Make 'User Preferences' file menu entry | 71 | ## Make 'User Preferences' file menu entry |
1081 | 69 | #tab = tabs.Tabs() | ||
1082 | 70 | menu_item5 = gtk.MenuItem(_("Preferences")) | 72 | menu_item5 = gtk.MenuItem(_("Preferences")) |
1083 | 71 | menu.append(menu_item5) | 73 | menu.append(menu_item5) |
1085 | 72 | menu_item5.connect("activate", actions.preferences) | 74 | menu_item5.connect("activate", lambda *x: actions.preferences(tabs)) |
1086 | 73 | menu_item5.show() | 75 | menu_item5.show() |
1087 | 74 | 76 | ||
1088 | 75 | ## Make 'Quit' file menu entry | 77 | ## Make 'Quit' file menu entry |
1089 | @@ -113,7 +115,7 @@ | |||
1090 | 113 | 115 | ||
1091 | 114 | 116 | ||
1092 | 115 | 117 | ||
1094 | 116 | def buttons(self, actions, spacing, layout, notebook, liststore): | 118 | def buttons(self, mw, spacing, layout): |
1095 | 117 | #button box at bottom of main window | 119 | #button box at bottom of main window |
1096 | 118 | frame = gtk.Frame() | 120 | frame = gtk.Frame() |
1097 | 119 | bbox = gtk.HButtonBox() | 121 | bbox = gtk.HButtonBox() |
1098 | @@ -125,9 +127,9 @@ | |||
1099 | 125 | bbox.set_layout(layout) | 127 | bbox.set_layout(layout) |
1100 | 126 | bbox.set_spacing(spacing) | 128 | bbox.set_spacing(spacing) |
1101 | 127 | # Run button | 129 | # Run button |
1103 | 128 | buttonRun = gtk.Button(_("Run")) | 130 | buttonRun = gtk.Button('_'+_("Run")) |
1104 | 129 | bbox.add(buttonRun) | 131 | bbox.add(buttonRun) |
1106 | 130 | buttonRun.connect("clicked", actions.run_command, notebook, liststore) | 132 | buttonRun.connect("clicked", lambda *x: mw.actions.run_command(mw)) |
1107 | 131 | buttonRun.set_tooltip_text(_("Click to run a highlighted command")) | 133 | buttonRun.set_tooltip_text(_("Click to run a highlighted command")) |
1108 | 132 | #buttonRun.modify_bg(gtk.STATE_NORMAL, color) | 134 | #buttonRun.modify_bg(gtk.STATE_NORMAL, color) |
1109 | 133 | #buttonRun.modify_bg(gtk.STATE_PRELIGHT, color) | 135 | #buttonRun.modify_bg(gtk.STATE_PRELIGHT, color) |
1110 | @@ -135,15 +137,15 @@ | |||
1111 | 135 | # Add button | 137 | # Add button |
1112 | 136 | buttonAdd = gtk.Button(stock=gtk.STOCK_ADD) | 138 | buttonAdd = gtk.Button(stock=gtk.STOCK_ADD) |
1113 | 137 | bbox.add(buttonAdd) | 139 | bbox.add(buttonAdd) |
1115 | 138 | buttonAdd.connect("clicked", actions.add_command, liststore) | 140 | buttonAdd.connect("clicked", lambda *x: mw.actions.add_command(mw)) |
1116 | 139 | buttonAdd.set_tooltip_text(_("Click to add a command to your command list")) | 141 | buttonAdd.set_tooltip_text(_("Click to add a command to your command list")) |
1117 | 140 | #buttonAdd.modify_bg(gtk.STATE_NORMAL, color) | 142 | #buttonAdd.modify_bg(gtk.STATE_NORMAL, color) |
1118 | 141 | #buttonAdd.modify_bg(gtk.STATE_PRELIGHT, color) | 143 | #buttonAdd.modify_bg(gtk.STATE_PRELIGHT, color) |
1119 | 142 | #buttonAdd.modify_bg(gtk.STATE_INSENSITIVE, color) | 144 | #buttonAdd.modify_bg(gtk.STATE_INSENSITIVE, color) |
1120 | 143 | # Edit button | 145 | # Edit button |
1122 | 144 | buttonEdit = gtk.Button(_("Edit")) | 146 | buttonEdit = gtk.Button('_'+_("Edit")) |
1123 | 145 | bbox.add(buttonEdit) | 147 | bbox.add(buttonEdit) |
1125 | 146 | buttonEdit.connect("clicked", actions.edit_command, liststore) | 148 | buttonEdit.connect("clicked", lambda *x: mw.actions.edit_command(mw)) |
1126 | 147 | buttonEdit.set_tooltip_text(_("Click to edit a command in your command list")) | 149 | buttonEdit.set_tooltip_text(_("Click to edit a command in your command list")) |
1127 | 148 | #buttonEdit.modify_bg(gtk.STATE_NORMAL, color) | 150 | #buttonEdit.modify_bg(gtk.STATE_NORMAL, color) |
1128 | 149 | #buttonEdit.modify_bg(gtk.STATE_PRELIGHT, color) | 151 | #buttonEdit.modify_bg(gtk.STATE_PRELIGHT, color) |
1129 | @@ -151,7 +153,7 @@ | |||
1130 | 151 | # Delete button | 153 | # Delete button |
1131 | 152 | buttonDelete = gtk.Button(stock=gtk.STOCK_DELETE) | 154 | buttonDelete = gtk.Button(stock=gtk.STOCK_DELETE) |
1132 | 153 | bbox.add(buttonDelete) | 155 | bbox.add(buttonDelete) |
1134 | 154 | buttonDelete.connect("clicked", actions.remove_command, liststore) | 156 | buttonDelete.connect("clicked", lambda *x: mw.actions.remove_command(mw)) |
1135 | 155 | buttonDelete.set_tooltip_text(_("Click to delete a command in your command list")) | 157 | buttonDelete.set_tooltip_text(_("Click to delete a command in your command list")) |
1136 | 156 | #buttonDelete.modify_bg(gtk.STATE_NORMAL, color) | 158 | #buttonDelete.modify_bg(gtk.STATE_NORMAL, color) |
1137 | 157 | #buttonDelete.modify_bg(gtk.STATE_PRELIGHT, color) | 159 | #buttonDelete.modify_bg(gtk.STATE_PRELIGHT, color) |
1138 | @@ -159,7 +161,7 @@ | |||
1139 | 159 | #Help Button | 161 | #Help Button |
1140 | 160 | buttonHelp = gtk.Button(stock=gtk.STOCK_HELP) | 162 | buttonHelp = gtk.Button(stock=gtk.STOCK_HELP) |
1141 | 161 | bbox.add(buttonHelp) | 163 | bbox.add(buttonHelp) |
1143 | 162 | buttonHelp.connect("clicked", actions.man_page, notebook) | 164 | buttonHelp.connect("clicked", lambda *x: mw.actions.man_page(mw.notebook)) |
1144 | 163 | buttonHelp.set_tooltip_text(_("Click to get help with a command in your command list")) | 165 | buttonHelp.set_tooltip_text(_("Click to get help with a command in your command list")) |
1145 | 164 | #buttonHelp.modify_bg(gtk.STATE_NORMAL, color) | 166 | #buttonHelp.modify_bg(gtk.STATE_NORMAL, color) |
1146 | 165 | #buttonHelp.modify_bg(gtk.STATE_PRELIGHT, color) | 167 | #buttonHelp.modify_bg(gtk.STATE_PRELIGHT, color) |
1147 | @@ -167,7 +169,7 @@ | |||
1148 | 167 | # Cancel button | 169 | # Cancel button |
1149 | 168 | buttonCancel = gtk.Button(stock=gtk.STOCK_QUIT) | 170 | buttonCancel = gtk.Button(stock=gtk.STOCK_QUIT) |
1150 | 169 | bbox.add(buttonCancel) | 171 | bbox.add(buttonCancel) |
1152 | 170 | buttonCancel.connect("clicked", actions.delete_event) | 172 | buttonCancel.connect("clicked", mw.actions.delete_event) |
1153 | 171 | buttonCancel.set_tooltip_text(_("Click to quit CLI Companion")) | 173 | buttonCancel.set_tooltip_text(_("Click to quit CLI Companion")) |
1154 | 172 | #buttonCancel.modify_bg(gtk.STATE_NORMAL, color) | 174 | #buttonCancel.modify_bg(gtk.STATE_NORMAL, color) |
1155 | 173 | #buttonCancel.modify_bg(gtk.STATE_PRELIGHT, color) | 175 | #buttonCancel.modify_bg(gtk.STATE_PRELIGHT, color) |
1156 | @@ -176,34 +178,34 @@ | |||
1157 | 176 | 178 | ||
1158 | 177 | 179 | ||
1159 | 178 | #right-click popup menu for the Liststore(command list) | 180 | #right-click popup menu for the Liststore(command list) |
1161 | 179 | def right_click(self, widget, event, actions, treeview, notebook, liststore): | 181 | def right_click(self, widget, event, mw): |
1162 | 180 | if event.button == 3: | 182 | if event.button == 3: |
1163 | 181 | x = int(event.x) | 183 | x = int(event.x) |
1164 | 182 | y = int(event.y) | 184 | y = int(event.y) |
1165 | 183 | time = event.time | 185 | time = event.time |
1167 | 184 | pthinfo = treeview.get_path_at_pos(x, y) | 186 | pthinfo = mw.treeview.get_path_at_pos(x, y) |
1168 | 185 | if pthinfo is not None: | 187 | if pthinfo is not None: |
1169 | 186 | path, col, cellx, celly = pthinfo | 188 | path, col, cellx, celly = pthinfo |
1172 | 187 | treeview.grab_focus() | 189 | mw.treeview.grab_focus() |
1173 | 188 | treeview.set_cursor( path, col, 0) | 190 | mw.treeview.set_cursor( path, col, 0) |
1174 | 189 | 191 | ||
1175 | 190 | # right-click popup menu Apply(run) | 192 | # right-click popup menu Apply(run) |
1176 | 191 | popupMenu = gtk.Menu() | 193 | popupMenu = gtk.Menu() |
1177 | 192 | menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_APPLY) | 194 | menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_APPLY) |
1178 | 193 | popupMenu.add(menuPopup1) | 195 | popupMenu.add(menuPopup1) |
1180 | 194 | menuPopup1.connect("activate", actions.run_command, notebook, liststore) | 196 | menuPopup1.connect("activate", lambda self, *x: mw.actions.run_command(mw)) |
1181 | 195 | # right-click popup menu Edit | 197 | # right-click popup menu Edit |
1182 | 196 | menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_EDIT) | 198 | menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_EDIT) |
1183 | 197 | popupMenu.add(menuPopup2) | 199 | popupMenu.add(menuPopup2) |
1185 | 198 | menuPopup2.connect("activate", actions.edit_command, liststore) | 200 | menuPopup2.connect("activate", lambda self, *x: mw.actions.edit_command(mw)) |
1186 | 199 | # right-click popup menu Delete | 201 | # right-click popup menu Delete |
1187 | 200 | menuPopup3 = gtk.ImageMenuItem (gtk.STOCK_DELETE) | 202 | menuPopup3 = gtk.ImageMenuItem (gtk.STOCK_DELETE) |
1188 | 201 | popupMenu.add(menuPopup3) | 203 | popupMenu.add(menuPopup3) |
1190 | 202 | menuPopup3.connect("activate", actions.remove_command, liststore) | 204 | menuPopup3.connect("activate", lambda self, *x: mw.actions.remove_command(mw)) |
1191 | 203 | # right-click popup menu Help | 205 | # right-click popup menu Help |
1192 | 204 | menuPopup4 = gtk.ImageMenuItem (gtk.STOCK_HELP) | 206 | menuPopup4 = gtk.ImageMenuItem (gtk.STOCK_HELP) |
1193 | 205 | popupMenu.add(menuPopup4) | 207 | popupMenu.add(menuPopup4) |
1195 | 206 | menuPopup4.connect("activate", actions.man_page, notebook) | 208 | menuPopup4.connect("activate", lambda self, *x: mw.actions.man_page(mw.notebook)) |
1196 | 207 | # Show popup menu | 209 | # Show popup menu |
1197 | 208 | popupMenu.show_all() | 210 | popupMenu.show_all() |
1198 | 209 | popupMenu.popup( None, None, None, event.button, time) | 211 | popupMenu.popup( None, None, None, event.button, time) |
1199 | 210 | 212 | ||
1200 | === modified file 'clicompanionlib/tabs.py' | |||
1201 | --- clicompanionlib/tabs.py 2011-03-29 17:31:11 +0000 | |||
1202 | +++ clicompanionlib/tabs.py 2012-01-02 01:28:26 +0000 | |||
1203 | @@ -22,33 +22,33 @@ | |||
1204 | 22 | pygtk.require('2.0') | 22 | pygtk.require('2.0') |
1205 | 23 | import gtk | 23 | import gtk |
1206 | 24 | import vte | 24 | import vte |
1208 | 25 | import ConfigParser | 25 | import clicompanionlib.config as cc_config |
1209 | 26 | 26 | ||
1211 | 27 | from clicompanionlib.utils import get_user_shell | 27 | from clicompanionlib.utils import get_user_shell, dbg |
1212 | 28 | import clicompanionlib.controller | 28 | import clicompanionlib.controller |
1213 | 29 | import clicompanionlib.utils as utils | ||
1214 | 29 | import view | 30 | import view |
1215 | 30 | 31 | ||
1216 | 31 | CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config") | ||
1217 | 32 | |||
1218 | 33 | |||
1219 | 34 | #definition gcp - how many pages is visible | ||
1220 | 35 | gcp=0; | ||
1221 | 36 | |||
1222 | 37 | #definition nop - (no of pages) reflects no of terminal tabs left (some may be closed by the user) | ||
1223 | 38 | nop=0; | ||
1224 | 39 | 32 | ||
1225 | 40 | class Tabs(object): | 33 | class Tabs(object): |
1226 | 41 | ''' | 34 | ''' |
1227 | 42 | add a new terminal in a tab above the current terminal | 35 | add a new terminal in a tab above the current terminal |
1228 | 43 | ''' | 36 | ''' |
1230 | 44 | def add_tab(self,widget, notebook): | 37 | def __init__(self): |
1231 | 38 | #definition nop - (no of pages) reflects no of terminal tabs left (some may be closed by the user) | ||
1232 | 39 | self.nop = 0 | ||
1233 | 40 | #definition gcp - how many pages is visible | ||
1234 | 41 | self.gcp = 0 | ||
1235 | 42 | |||
1236 | 43 | def add_tab(self, notebook): | ||
1237 | 44 | dbg('Adding a new tab') | ||
1238 | 45 | _vte = vte.Terminal() | 45 | _vte = vte.Terminal() |
1239 | 46 | if view.NETBOOKMODE == 1: | 46 | if view.NETBOOKMODE == 1: |
1240 | 47 | _vte.set_size_request(700, 120) | 47 | _vte.set_size_request(700, 120) |
1241 | 48 | else: | 48 | else: |
1242 | 49 | _vte.set_size_request(700, 220) | 49 | _vte.set_size_request(700, 220) |
1243 | 50 | 50 | ||
1245 | 51 | _vte.connect ("child-exited", lambda term: gtk.main_quit()) | 51 | _vte.connect("child-exited", lambda term: gtk.main_quit()) |
1246 | 52 | _vte.fork_command(get_user_shell()) # Get the user's default shell | 52 | _vte.fork_command(get_user_shell()) # Get the user's default shell |
1247 | 53 | 53 | ||
1248 | 54 | self.update_term_config(_vte) | 54 | self.update_term_config(_vte) |
1249 | @@ -58,19 +58,16 @@ | |||
1250 | 58 | #notebook.set_show_tabs(True) | 58 | #notebook.set_show_tabs(True) |
1251 | 59 | #notebook.set_show_border(True) | 59 | #notebook.set_show_border(True) |
1252 | 60 | 60 | ||
1259 | 61 | global gcp | 61 | self.nop += 1 |
1260 | 62 | global nop | 62 | self.gcp += 1 |
1261 | 63 | nop += 1 | 63 | pagenum = ('Tab %d') % self.gcp |
1262 | 64 | gcp += 1 | 64 | if self.nop > 1: |
1263 | 65 | pagenum = ('Tab %d') % gcp | 65 | dbg('More than one tab, showing them.') |
1258 | 66 | if nop > 1: | ||
1264 | 67 | view.MainWindow.notebook.set_show_tabs(True) | 66 | view.MainWindow.notebook.set_show_tabs(True) |
1265 | 68 | box = gtk.HBox() | 67 | box = gtk.HBox() |
1266 | 69 | label = gtk.Label(pagenum) | 68 | label = gtk.Label(pagenum) |
1267 | 70 | box.pack_start(label, True, True) | 69 | box.pack_start(label, True, True) |
1268 | 71 | 70 | ||
1269 | 72 | |||
1270 | 73 | |||
1271 | 74 | 71 | ||
1272 | 75 | ## x image for tab close button | 72 | ## x image for tab close button |
1273 | 76 | close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) | 73 | close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) |
1274 | @@ -87,10 +84,10 @@ | |||
1275 | 87 | view.MainWindow.notebook.prepend_page(vte_tab, box) # add tab | 84 | view.MainWindow.notebook.prepend_page(vte_tab, box) # add tab |
1276 | 88 | view.MainWindow.notebook.set_scrollable(True) | 85 | view.MainWindow.notebook.set_scrollable(True) |
1277 | 89 | actions = clicompanionlib.controller.Actions() | 86 | actions = clicompanionlib.controller.Actions() |
1279 | 90 | _vte.connect ("button_press_event", actions.copy_paste, None) | 87 | _vte.connect("button_press_event", actions.copy_paste, None) |
1280 | 91 | vte_tab.grab_focus() | 88 | vte_tab.grab_focus() |
1281 | 92 | # signal handler for tab | 89 | # signal handler for tab |
1283 | 93 | closebtn.connect("clicked", self.close_tab, vte_tab, notebook) | 90 | closebtn.connect("clicked", lambda *x: self.close_tab(vte_tab, notebook)) |
1284 | 94 | 91 | ||
1285 | 95 | vte_tab.show_all() | 92 | vte_tab.show_all() |
1286 | 96 | 93 | ||
1287 | @@ -98,29 +95,42 @@ | |||
1288 | 98 | 95 | ||
1289 | 99 | 96 | ||
1290 | 100 | ## Remove a page from the notebook | 97 | ## Remove a page from the notebook |
1292 | 101 | def close_tab(self, sender, widget, notebook): | 98 | def close_tab(self, vte_tab, notebook): |
1293 | 102 | ## get the page number of the tab we wanted to close | 99 | ## get the page number of the tab we wanted to close |
1295 | 103 | pagenum = view.MainWindow.notebook.page_num(widget) | 100 | pagenum = view.MainWindow.notebook.page_num(vte_tab) |
1296 | 104 | ## and close it | 101 | ## and close it |
1297 | 105 | view.MainWindow.notebook.remove_page(pagenum) | 102 | view.MainWindow.notebook.remove_page(pagenum) |
1301 | 106 | global nop | 103 | self.nop -= 1 |
1302 | 107 | nop -= 1 | 104 | if self.nop <= 1: |
1300 | 108 | if nop <= 1: | ||
1303 | 109 | view.MainWindow.notebook.set_show_tabs(False) | 105 | view.MainWindow.notebook.set_show_tabs(False) |
1304 | 110 | 106 | ||
1305 | 111 | # check if the focus does not go to the last page (ie with only a + sign) | 107 | # check if the focus does not go to the last page (ie with only a + sign) |
1307 | 112 | if view.MainWindow.notebook.get_current_page() == nop: | 108 | if view.MainWindow.notebook.get_current_page() == self.nop: |
1308 | 113 | view.MainWindow.notebook.prev_page() | 109 | view.MainWindow.notebook.prev_page() |
1309 | 114 | 110 | ||
1317 | 115 | 111 | def update_all_term_config(self, config=None): | |
1318 | 116 | 112 | for pagenum in range(view.MainWindow.notebook.get_n_pages()): | |
1319 | 117 | def update_term_config(self, _vte): | 113 | page = view.MainWindow.notebook.get_nth_page(pagenum) |
1320 | 118 | ##read config file | 114 | dbg(page) |
1321 | 119 | config = ConfigParser.RawConfigParser() | 115 | if isinstance(page, gtk.ScrolledWindow): |
1322 | 120 | config.read(CONFIGFILE) | 116 | for grandson in page.get_children(): |
1323 | 121 | 117 | dbg(grandson) | |
1324 | 118 | if isinstance(grandson,vte.Terminal): | ||
1325 | 119 | self.update_term_config(grandson, config) | ||
1326 | 120 | |||
1327 | 121 | def update_term_config(self, _vte, config=None): | ||
1328 | 122 | ##set terminal preferences from conig file data | 122 | ##set terminal preferences from conig file data |
1330 | 123 | config_scrollback = config.getint('terminal', 'scrollb') | 123 | if not config: |
1331 | 124 | config = cc_config.get_config() | ||
1332 | 125 | try: | ||
1333 | 126 | config_scrollback = config.getint('terminal', 'scrollb') | ||
1334 | 127 | except ValueError: | ||
1335 | 128 | print _("WARNING: Invalid value for property 'terminal', int expected:" | ||
1336 | 129 | " got '%s', using default '%s'")%( | ||
1337 | 130 | config.get('terminal', 'scrollb'), | ||
1338 | 131 | config.get('DEFAULT', 'scrollb')) | ||
1339 | 132 | config.set('terminal','scrollb',config.get('DEFAULT', 'scrollb')) | ||
1340 | 133 | config_scrollback = config.getint('DEFAULT', 'scrollb') | ||
1341 | 124 | _vte.set_scrollback_lines(config_scrollback) | 134 | _vte.set_scrollback_lines(config_scrollback) |
1342 | 125 | 135 | ||
1343 | 126 | color = '#2e3436:#cc0000:#4e9a06:#c4a000:#3465a4:#75507b:#06989a:#d3d7cf:#555753:#ef2929:#8ae234:#fce94f:#729fcf:#ad7fa8:#34e2e2:#eeeeec' | 136 | color = '#2e3436:#cc0000:#4e9a06:#c4a000:#3465a4:#75507b:#06989a:#d3d7cf:#555753:#ef2929:#8ae234:#fce94f:#729fcf:#ad7fa8:#34e2e2:#eeeeec' |
1344 | @@ -130,14 +140,39 @@ | |||
1345 | 130 | if color: | 140 | if color: |
1346 | 131 | palette.append(gtk.gdk.color_parse(color)) | 141 | palette.append(gtk.gdk.color_parse(color)) |
1347 | 132 | 142 | ||
1354 | 133 | config_color_fore = gtk.gdk.color_parse(config.get('terminal', 'colorf')) | 143 | try: |
1355 | 134 | #_vte.set_color_foreground(config_color_fore) | 144 | config_color_fore = gtk.gdk.color_parse(config.get('terminal', 'colorf')) |
1356 | 135 | 145 | except ValueError, e: | |
1357 | 136 | config_color_back = gtk.gdk.color_parse(config.get('terminal', 'colorb')) | 146 | print _("WARNING: Invalid value for property '%s':" |
1358 | 137 | #_vte.set_color_background( config_color_back) | 147 | " got '%s', using default '%s'.")%( |
1359 | 138 | 148 | 'colorf', | |
1360 | 149 | config.get('terminal', 'colorf'), | ||
1361 | 150 | config.get('DEFAULT', 'colorf')) | ||
1362 | 151 | config.set('terminal','colorf',config.get('DEFAULT', 'colorf')) | ||
1363 | 152 | config_color_fore = gtk.gdk.color_parse(config.get('DEFAULT', 'colorf')) | ||
1364 | 153 | |||
1365 | 154 | try: | ||
1366 | 155 | config_color_back = gtk.gdk.color_parse(config.get('terminal', 'colorb')) | ||
1367 | 156 | except ValueError, e: | ||
1368 | 157 | print _("WARNING: Invalid value for property '%s':" | ||
1369 | 158 | " got '%s', using default '%s'.")%( | ||
1370 | 159 | 'colorb', | ||
1371 | 160 | config.get('terminal', 'colorb'), | ||
1372 | 161 | config.get('DEFAULT', 'colorb')) | ||
1373 | 162 | config.set('terminal','colorb',config.get('DEFAULT', 'colorb')) | ||
1374 | 163 | config_color_back = gtk.gdk.color_parse(config.get('DEFAULT', 'colorb')) | ||
1375 | 139 | _vte.set_colors(config_color_fore, config_color_back, palette) | 164 | _vte.set_colors(config_color_fore, config_color_back, palette) |
1376 | 140 | 165 | ||
1377 | 141 | config_encoding = config.get('terminal', 'encoding') | 166 | config_encoding = config.get('terminal', 'encoding') |
1378 | 167 | if config_encoding.upper() not in [ enc.upper() for enc, desc in utils.encodings]: | ||
1379 | 168 | print _("WARNING: Invalid value for property '%s':" | ||
1380 | 169 | " got '%s', using default '%s'")%( | ||
1381 | 170 | 'encoding', | ||
1382 | 171 | config_encoding, | ||
1383 | 172 | config.get('DEFAULT', 'encoding')) | ||
1384 | 173 | config.set('terminal','encoding',config.get('DEFAULT', 'encoding')) | ||
1385 | 174 | config_encoding = config.get('DEFAULT', 'encoding') | ||
1386 | 142 | _vte.set_encoding(config_encoding) | 175 | _vte.set_encoding(config_encoding) |
1387 | 176 | |||
1388 | 177 | |||
1389 | 143 | 178 | ||
1390 | 144 | 179 | ||
1391 | === modified file 'clicompanionlib/utils.py' | |||
1392 | --- clicompanionlib/utils.py 2011-03-29 17:31:11 +0000 | |||
1393 | +++ clicompanionlib/utils.py 2012-01-02 01:28:26 +0000 | |||
1394 | @@ -25,9 +25,148 @@ | |||
1395 | 25 | 25 | ||
1396 | 26 | import getpass | 26 | import getpass |
1397 | 27 | import os | 27 | import os |
1401 | 28 | 28 | import sys | |
1402 | 29 | CHEATSHEET = os.path.expanduser("~/.clicompanion2") | 29 | import gtk |
1403 | 30 | #CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config" | 30 | import pwd |
1404 | 31 | import inspect | ||
1405 | 32 | |||
1406 | 33 | |||
1407 | 34 | ## set to True if you want to see more logs | ||
1408 | 35 | DEBUG = False | ||
1409 | 36 | DEBUGFILES = False | ||
1410 | 37 | DEBUGCLASSES = [] | ||
1411 | 38 | DEBUGMETHODS = [] | ||
1412 | 39 | |||
1413 | 40 | ## list gotten from terminator (https://launchpad.net/terminator) | ||
1414 | 41 | encodings = [ | ||
1415 | 42 | ["ISO-8859-1", _("Western")], | ||
1416 | 43 | ["ISO-8859-2", _("Central European")], | ||
1417 | 44 | ["ISO-8859-3", _("South European") ], | ||
1418 | 45 | ["ISO-8859-4", _("Baltic") ], | ||
1419 | 46 | ["ISO-8859-5", _("Cyrillic") ], | ||
1420 | 47 | ["ISO-8859-6", _("Arabic") ], | ||
1421 | 48 | ["ISO-8859-7", _("Greek") ], | ||
1422 | 49 | ["ISO-8859-8", _("Hebrew Visual") ], | ||
1423 | 50 | ["ISO-8859-8-I", _("Hebrew") ], | ||
1424 | 51 | ["ISO-8859-9", _("Turkish") ], | ||
1425 | 52 | ["ISO-8859-10", _("Nordic") ], | ||
1426 | 53 | ["ISO-8859-13", _("Baltic") ], | ||
1427 | 54 | ["ISO-8859-14", _("Celtic") ], | ||
1428 | 55 | ["ISO-8859-15", _("Western") ], | ||
1429 | 56 | ["ISO-8859-16", _("Romanian") ], | ||
1430 | 57 | # ["UTF-7", _("Unicode") ], | ||
1431 | 58 | ["UTF-8", _("Unicode") ], | ||
1432 | 59 | # ["UTF-16", _("Unicode") ], | ||
1433 | 60 | # ["UCS-2", _("Unicode") ], | ||
1434 | 61 | # ["UCS-4", _("Unicode") ], | ||
1435 | 62 | ["ARMSCII-8", _("Armenian") ], | ||
1436 | 63 | ["BIG5", _("Chinese Traditional") ], | ||
1437 | 64 | ["BIG5-HKSCS", _("Chinese Traditional") ], | ||
1438 | 65 | ["CP866", _("Cyrillic/Russian") ], | ||
1439 | 66 | ["EUC-JP", _("Japanese") ], | ||
1440 | 67 | ["EUC-KR", _("Korean") ], | ||
1441 | 68 | ["EUC-TW", _("Chinese Traditional") ], | ||
1442 | 69 | ["GB18030", _("Chinese Simplified") ], | ||
1443 | 70 | ["GB2312", _("Chinese Simplified") ], | ||
1444 | 71 | ["GBK", _("Chinese Simplified") ], | ||
1445 | 72 | ["GEORGIAN-PS", _("Georgian") ], | ||
1446 | 73 | ["HZ", _("Chinese Simplified") ], | ||
1447 | 74 | ["IBM850", _("Western") ], | ||
1448 | 75 | ["IBM852", _("Central European") ], | ||
1449 | 76 | ["IBM855", _("Cyrillic") ], | ||
1450 | 77 | ["IBM857", _("Turkish") ], | ||
1451 | 78 | ["IBM862", _("Hebrew") ], | ||
1452 | 79 | ["IBM864", _("Arabic") ], | ||
1453 | 80 | ["ISO-2022-JP", _("Japanese") ], | ||
1454 | 81 | ["ISO-2022-KR", _("Korean") ], | ||
1455 | 82 | ["EUC-TW", _("Chinese Traditional") ], | ||
1456 | 83 | ["GB18030", _("Chinese Simplified") ], | ||
1457 | 84 | ["GB2312", _("Chinese Simplified") ], | ||
1458 | 85 | ["GBK", _("Chinese Simplified") ], | ||
1459 | 86 | ["GEORGIAN-PS", _("Georgian") ], | ||
1460 | 87 | ["HZ", _("Chinese Simplified") ], | ||
1461 | 88 | ["IBM850", _("Western") ], | ||
1462 | 89 | ["IBM852", _("Central European") ], | ||
1463 | 90 | ["IBM855", _("Cyrillic") ], | ||
1464 | 91 | ["IBM857", _("Turkish") ], | ||
1465 | 92 | ["IBM862", _("Hebrew") ], | ||
1466 | 93 | ["IBM864", _("Arabic") ], | ||
1467 | 94 | ["ISO-2022-JP", _("Japanese") ], | ||
1468 | 95 | ["ISO-2022-KR", _("Korean") ], | ||
1469 | 96 | ["ISO-IR-111", _("Cyrillic") ], | ||
1470 | 97 | # ["JOHAB", _("Korean") ], | ||
1471 | 98 | ["KOI8-R", _("Cyrillic") ], | ||
1472 | 99 | ["KOI8-U", _("Cyrillic/Ukrainian") ], | ||
1473 | 100 | ["MAC_ARABIC", _("Arabic") ], | ||
1474 | 101 | ["MAC_CE", _("Central European") ], | ||
1475 | 102 | ["MAC_CROATIAN", _("Croatian") ], | ||
1476 | 103 | ["MAC-CYRILLIC", _("Cyrillic") ], | ||
1477 | 104 | ["MAC_DEVANAGARI", _("Hindi") ], | ||
1478 | 105 | ["MAC_FARSI", _("Persian") ], | ||
1479 | 106 | ["MAC_GREEK", _("Greek") ], | ||
1480 | 107 | ["MAC_GUJARATI", _("Gujarati") ], | ||
1481 | 108 | ["MAC_GURMUKHI", _("Gurmukhi") ], | ||
1482 | 109 | ["MAC_HEBREW", _("Hebrew") ], | ||
1483 | 110 | ["MAC_ICELANDIC", _("Icelandic") ], | ||
1484 | 111 | ["MAC_ROMAN", _("Western") ], | ||
1485 | 112 | ["MAC_ROMANIAN", _("Romanian") ], | ||
1486 | 113 | ["MAC_TURKISH", _("Turkish") ], | ||
1487 | 114 | ["MAC_UKRAINIAN", _("Cyrillic/Ukrainian") ], | ||
1488 | 115 | ["SHIFT-JIS", _("Japanese") ], | ||
1489 | 116 | ["TCVN", _("Vietnamese") ], | ||
1490 | 117 | ["TIS-620", _("Thai") ], | ||
1491 | 118 | ["UHC", _("Korean") ], | ||
1492 | 119 | ["VISCII", _("Vietnamese") ], | ||
1493 | 120 | ["WINDOWS-1250", _("Central European") ], | ||
1494 | 121 | ["WINDOWS-1251", _("Cyrillic") ], | ||
1495 | 122 | ["WINDOWS-1252", _("Western") ], | ||
1496 | 123 | ["WINDOWS-1253", _("Greek") ], | ||
1497 | 124 | ["WINDOWS-1254", _("Turkish") ], | ||
1498 | 125 | ["WINDOWS-1255", _("Hebrew") ], | ||
1499 | 126 | ["WINDOWS-1256", _("Arabic") ], | ||
1500 | 127 | ["WINDOWS-1257", _("Baltic") ], | ||
1501 | 128 | ["WINDOWS-1258", _("Vietnamese") ] | ||
1502 | 129 | ] | ||
1503 | 130 | |||
1504 | 131 | |||
1505 | 132 | def dbg(log): | ||
1506 | 133 | if DEBUG: | ||
1507 | 134 | stack = inspect.stack() | ||
1508 | 135 | method = None | ||
1509 | 136 | for stackitem in stack: | ||
1510 | 137 | parent_frame = stackitem[0] | ||
1511 | 138 | names, varargs, keywords, local_vars = inspect.getargvalues(parent_frame) | ||
1512 | 139 | ## little trick to get the second stackline method, in case we do | ||
1513 | 140 | ## not find self | ||
1514 | 141 | if not method and method != None: | ||
1515 | 142 | method = stackitem[3] | ||
1516 | 143 | elif not method: | ||
1517 | 144 | method = '' | ||
1518 | 145 | try: | ||
1519 | 146 | self_name = names[0] | ||
1520 | 147 | if self_name != 'self': | ||
1521 | 148 | continue | ||
1522 | 149 | classname = local_vars[self_name].__class__.__name__ | ||
1523 | 150 | except IndexError: | ||
1524 | 151 | classname = "noclass" | ||
1525 | 152 | ## in case self is found, get the method | ||
1526 | 153 | method = stackitem[3] | ||
1527 | 154 | break | ||
1528 | 155 | if DEBUGFILES: | ||
1529 | 156 | line = stackitem[2] | ||
1530 | 157 | filename = parent_frame.f_code.co_filename | ||
1531 | 158 | extra = " (%s:%s)" % (filename, line) | ||
1532 | 159 | else: | ||
1533 | 160 | extra = "" | ||
1534 | 161 | if DEBUGCLASSES != [] and classname not in DEBUGCLASSES: | ||
1535 | 162 | return | ||
1536 | 163 | if DEBUGMETHODS != [] and method not in DEBUGMETHODS: | ||
1537 | 164 | return | ||
1538 | 165 | try: | ||
1539 | 166 | print >> sys.stderr, "%s::%s: %s%s" % (classname, method, log, extra) | ||
1540 | 167 | except IOError: | ||
1541 | 168 | pass | ||
1542 | 169 | |||
1543 | 31 | 170 | ||
1544 | 32 | #TODO: Move this to controller.py | 171 | #TODO: Move this to controller.py |
1545 | 33 | def get_user_shell(): | 172 | def get_user_shell(): |
1546 | 34 | 173 | ||
1547 | === modified file 'clicompanionlib/view.py' | |||
1548 | --- clicompanionlib/view.py 2011-12-30 12:22:17 +0000 | |||
1549 | +++ clicompanionlib/view.py 2012-01-02 01:28:26 +0000 | |||
1550 | @@ -22,7 +22,6 @@ | |||
1551 | 22 | import pygtk | 22 | import pygtk |
1552 | 23 | pygtk.require('2.0') | 23 | pygtk.require('2.0') |
1553 | 24 | import os | 24 | import os |
1554 | 25 | import ConfigParser | ||
1555 | 26 | 25 | ||
1556 | 27 | # import vte and gtk or print error | 26 | # import vte and gtk or print error |
1557 | 28 | try: | 27 | try: |
1558 | @@ -43,18 +42,20 @@ | |||
1559 | 43 | 42 | ||
1560 | 44 | import clicompanionlib.menus_buttons | 43 | import clicompanionlib.menus_buttons |
1561 | 45 | import clicompanionlib.controller | 44 | import clicompanionlib.controller |
1563 | 46 | from clicompanionlib.utils import get_user_shell , Borg | 45 | from clicompanionlib.utils import get_user_shell , Borg, dbg |
1564 | 47 | import clicompanionlib.tabs | 46 | import clicompanionlib.tabs |
1571 | 48 | from clicompanionlib.config import Config | 47 | import clicompanionlib.utils as utils |
1572 | 49 | 48 | import clicompanionlib.config as cc_config | |
1573 | 50 | 49 | ||
1568 | 51 | CONFIGFILE = os.path.expanduser("~/.config/clicompanion/config") | ||
1569 | 52 | CHEATSHEET = os.path.expanduser("~/.clicompanion2") | ||
1570 | 53 | CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config" | ||
1574 | 54 | 50 | ||
1575 | 55 | ## Changed two->three columns | 51 | ## Changed two->three columns |
1578 | 56 | CMNDS = [] ## will hold the commands. Actually the first three columns | 52 | CMNDS = cc_config.Cheatsheet() |
1579 | 57 | ROW = '1' ## holds the currently selected row | 53 | ## will hold the commands. Actually the first three columns |
1580 | 54 | ## note that this commands list will not change with searchers and filters, | ||
1581 | 55 | ## instead, when adding a command to the liststore, we will add also the index | ||
1582 | 56 | ## of the command in the CMND list | ||
1583 | 57 | |||
1584 | 58 | ROW = '0' ## holds the currently selected row | ||
1585 | 58 | TARGETS = [ | 59 | TARGETS = [ |
1586 | 59 | ('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0), | 60 | ('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0), |
1587 | 60 | ('text/plain', 0, 1), | 61 | ('text/plain', 0, 1), |
1588 | @@ -67,7 +68,6 @@ | |||
1589 | 67 | HIDEUI = 0 | 68 | HIDEUI = 0 |
1590 | 68 | FULLSCREEN = 0 | 69 | FULLSCREEN = 0 |
1591 | 69 | 70 | ||
1592 | 70 | |||
1593 | 71 | menu_search_hbox = '' | 71 | menu_search_hbox = '' |
1594 | 72 | button_box = '' | 72 | button_box = '' |
1595 | 73 | 73 | ||
1596 | @@ -76,90 +76,32 @@ | |||
1597 | 76 | window = gtk.Window(gtk.WINDOW_TOPLEVEL) | 76 | window = gtk.Window(gtk.WINDOW_TOPLEVEL) |
1598 | 77 | #color = gtk.gdk.Color(60000, 65533, 60000) | 77 | #color = gtk.gdk.Color(60000, 65533, 60000) |
1599 | 78 | #window.modify_bg(gtk.STATE_NORMAL, color) | 78 | #window.modify_bg(gtk.STATE_NORMAL, color) |
1601 | 79 | liststore = gtk.ListStore(str, str, str) | 79 | liststore = gtk.ListStore(str, str, str, int) |
1602 | 80 | treeview = gtk.TreeView() | 80 | treeview = gtk.TreeView() |
1603 | 81 | expander = gtk.Expander() | 81 | expander = gtk.Expander() |
1604 | 82 | scrolledwindow = gtk.ScrolledWindow() | 82 | scrolledwindow = gtk.ScrolledWindow() |
1605 | 83 | notebook = gtk.Notebook() | 83 | notebook = gtk.Notebook() |
1606 | 84 | 84 | ||
1607 | 85 | |||
1608 | 86 | screen = gtk.gdk.display_get_default().get_default_screen() | 85 | screen = gtk.gdk.display_get_default().get_default_screen() |
1609 | 87 | screen_size = screen.get_monitor_geometry(0) | 86 | screen_size = screen.get_monitor_geometry(0) |
1610 | 88 | height = screen.get_height() ## screen height ## | 87 | height = screen.get_height() ## screen height ## |
1611 | 89 | global NETBOOKMODE | 88 | global NETBOOKMODE |
1612 | 90 | if height < 750: | 89 | if height < 750: |
1613 | 91 | NETBOOKMODE = 1 | 90 | NETBOOKMODE = 1 |
1685 | 92 | ## open file containing command list and put it in a variable | 91 | |
1686 | 93 | def update(self, liststore): | 92 | |
1687 | 94 | try: | 93 | def sync_cmnds(self, rld=False): |
1688 | 95 | with open(CHEATSHEET, "r") as cheatfile: | 94 | global CMNDS |
1689 | 96 | bugdata=cheatfile.read() | 95 | dbg('syncing commands') |
1690 | 97 | cheatfile.close() | 96 | if rld: |
1691 | 98 | except IOError: | 97 | ## reload the commands list from the file |
1692 | 99 | ## CHEATSHEET is not there. Oh, no! | 98 | CMNDS.load() |
1693 | 100 | ## So, run self.setup() again. | 99 | self.liststore.clear() |
1694 | 101 | self.setup() | 100 | ## Store also the index of the command in the CMNDS list |
1695 | 102 | ## Then, run me again. | 101 | i = 0 |
1696 | 103 | self.update(self.liststore) | 102 | for cmd, ui, desc in CMNDS: |
1697 | 104 | 103 | self.liststore.append((cmd, ui, desc, i)) | |
1698 | 105 | ## add bug data from .clicompanion --> bugdata --> to the liststore | 104 | i = i +1 |
1628 | 106 | for line in bugdata.splitlines(): | ||
1629 | 107 | l = line.split('\t',2) | ||
1630 | 108 | if len(l) < 2: | ||
1631 | 109 | """ | ||
1632 | 110 | If for any reason we have a old file, we must | ||
1633 | 111 | replace it by new one | ||
1634 | 112 | """ | ||
1635 | 113 | print "PLEASE RESTART APPLICATION TO FINISH UPDATE" | ||
1636 | 114 | self.setup() | ||
1637 | 115 | return | ||
1638 | 116 | commandplus = l[0], l[1], l[2] | ||
1639 | 117 | CMNDS.append(commandplus) | ||
1640 | 118 | self.liststore.append([l[0],l[1],l[2]]) | ||
1641 | 119 | |||
1642 | 120 | |||
1643 | 121 | #copy config file to user $HOME if does not exist | ||
1644 | 122 | def setup(self): | ||
1645 | 123 | """ | ||
1646 | 124 | Check if ~/.clicompanion2 exists. If not check for original | ||
1647 | 125 | installed in /etc/clicompanion.d/. If origianl exists copy to $HOME. | ||
1648 | 126 | if not create a new, blank ~/.clicompanion2 so program will not crash | ||
1649 | 127 | """ | ||
1650 | 128 | |||
1651 | 129 | if not os.path.exists(CHEATSHEET): | ||
1652 | 130 | if os.path.exists(CONFIG_ORIG): | ||
1653 | 131 | os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET)) | ||
1654 | 132 | else: | ||
1655 | 133 | # Oops! Looks like there's no cheatsheet in CHEATSHEET. | ||
1656 | 134 | # Then, create an empty cheatsheet. | ||
1657 | 135 | open(CHEATSHEET, 'w').close() | ||
1658 | 136 | """ | ||
1659 | 137 | If we have old file, we must replace it by fresh list | ||
1660 | 138 | """ | ||
1661 | 139 | cheatlines = [] | ||
1662 | 140 | try: | ||
1663 | 141 | with open(CHEATSHEET, "r") as cheatfile: | ||
1664 | 142 | bugdata=cheatfile.read() | ||
1665 | 143 | cheatfile.close() | ||
1666 | 144 | for line in bugdata.splitlines(): | ||
1667 | 145 | l = line.split('\t', 2) | ||
1668 | 146 | if len(l) < 2: | ||
1669 | 147 | l = line.split(':', 2) | ||
1670 | 148 | p = str(l[0] + "\t"+ l[1] +"\t"+ l[2] + "\n") | ||
1671 | 149 | cheatlines.append(p) | ||
1672 | 150 | else: | ||
1673 | 151 | cheatlines.append(str(l[0] + "\t"+ l[1] +"\t"+ l[2] + "\n")) | ||
1674 | 152 | |||
1675 | 153 | with open(CHEATSHEET, "w") as cheatfile2: | ||
1676 | 154 | cheatfile2.writelines(cheatlines) | ||
1677 | 155 | cheatfile2.close() | ||
1678 | 156 | |||
1679 | 157 | except IOError: | ||
1680 | 158 | ## CHEATSHEET is not there. Oh, no! | ||
1681 | 159 | ## So, run self.setup() again. | ||
1682 | 160 | self.setup() | ||
1683 | 161 | ## Then, run me again. | ||
1684 | 162 | self.update(self.liststore) | ||
1699 | 163 | 105 | ||
1700 | 164 | 106 | ||
1701 | 165 | #liststore in a scrolled window in an expander | 107 | #liststore in a scrolled window in an expander |
1702 | @@ -185,13 +127,11 @@ | |||
1703 | 185 | 127 | ||
1704 | 186 | def key_clicked(self, widget, event): | 128 | def key_clicked(self, widget, event): |
1705 | 187 | actions = clicompanionlib.controller.Actions() | 129 | actions = clicompanionlib.controller.Actions() |
1706 | 188 | tabs = clicompanionlib.tabs.Tabs() | ||
1707 | 189 | global HIDEUI | 130 | global HIDEUI |
1708 | 190 | global FULLSCREEN | 131 | global FULLSCREEN |
1709 | 191 | global menu_search_hbox | 132 | global menu_search_hbox |
1710 | 192 | global button_box | 133 | global button_box |
1711 | 193 | keyname = gtk.gdk.keyval_name(event.keyval).upper() | 134 | keyname = gtk.gdk.keyval_name(event.keyval).upper() |
1712 | 194 | #print keyname ##debug | ||
1713 | 195 | if keyname == "F12": | 135 | if keyname == "F12": |
1714 | 196 | HIDEUI = 1 - HIDEUI | 136 | HIDEUI = 1 - HIDEUI |
1715 | 197 | if HIDEUI == 1: | 137 | if HIDEUI == 1: |
1716 | @@ -215,13 +155,13 @@ | |||
1717 | 215 | pwin = button_box.get_window() | 155 | pwin = button_box.get_window() |
1718 | 216 | pwin.unfullscreen() | 156 | pwin.unfullscreen() |
1719 | 217 | if keyname == "F4": | 157 | if keyname == "F4": |
1721 | 218 | actions.run_command(self, self.notebook, self.liststore) | 158 | actions.run_command(self) |
1722 | 219 | if keyname == "F5": | 159 | if keyname == "F5": |
1724 | 220 | actions.add_command(self, self.liststore) | 160 | actions.add_command(self) |
1725 | 221 | if keyname == "F6": | 161 | if keyname == "F6": |
1727 | 222 | actions.remove_command(self, self.liststore) | 162 | actions.remove_command(self) |
1728 | 223 | if keyname == "F7": | 163 | if keyname == "F7": |
1730 | 224 | tabs.add_tab(self, self.notebook) | 164 | self.tabs.add_tab(self) |
1731 | 225 | 165 | ||
1732 | 226 | def __init__(self): | 166 | def __init__(self): |
1733 | 227 | #import pdb ##debug | 167 | #import pdb ##debug |
1734 | @@ -231,14 +171,7 @@ | |||
1735 | 231 | ##in libvte in Ubuntu Maverick | 171 | ##in libvte in Ubuntu Maverick |
1736 | 232 | os.putenv('TERM', 'xterm') | 172 | os.putenv('TERM', 'xterm') |
1737 | 233 | 173 | ||
1738 | 234 | ## copy command list to user $HOME if does not exist | ||
1739 | 235 | self.setup() | ||
1740 | 236 | 174 | ||
1741 | 237 | ##create the config file | ||
1742 | 238 | conf_mod = Config() | ||
1743 | 239 | conf_mod.create_config() | ||
1744 | 240 | |||
1745 | 241 | |||
1746 | 242 | ## style to reduce padding around tabs | 175 | ## style to reduce padding around tabs |
1747 | 243 | ## TODO: Find a better place for this? | 176 | ## TODO: Find a better place for this? |
1748 | 244 | gtk.rc_parse_string ("style \"tab-close-button-style\"\n" | 177 | gtk.rc_parse_string ("style \"tab-close-button-style\"\n" |
1749 | @@ -257,7 +190,6 @@ | |||
1750 | 257 | ##attach the style to the widget | 190 | ##attach the style to the widget |
1751 | 258 | self.notebook.set_name ("tab-close-button") | 191 | self.notebook.set_name ("tab-close-button") |
1752 | 259 | 192 | ||
1753 | 260 | |||
1754 | 261 | ## set sizes and borders | 193 | ## set sizes and borders |
1755 | 262 | global NETBOOKMODE | 194 | global NETBOOKMODE |
1756 | 263 | if NETBOOKMODE == 1: | 195 | if NETBOOKMODE == 1: |
1757 | @@ -272,19 +204,15 @@ | |||
1758 | 272 | ## Allow user to resize window | 204 | ## Allow user to resize window |
1759 | 273 | self.window.set_resizable(True) | 205 | self.window.set_resizable(True) |
1760 | 274 | 206 | ||
1761 | 275 | |||
1762 | 276 | ## set Window title and icon | 207 | ## set Window title and icon |
1763 | 277 | self.window.set_title("CLI Companion") | 208 | self.window.set_title("CLI Companion") |
1764 | 278 | icon = gtk.gdk.pixbuf_new_from_file("/usr/share/pixmaps/clicompanion.16.png") | 209 | icon = gtk.gdk.pixbuf_new_from_file("/usr/share/pixmaps/clicompanion.16.png") |
1765 | 279 | self.window.set_icon(icon) | 210 | self.window.set_icon(icon) |
1766 | 280 | |||
1767 | 281 | |||
1768 | 282 | 211 | ||
1771 | 283 | # get commands and put in liststore | 212 | # sync liststore with commands |
1772 | 284 | self.update(self.liststore) | 213 | self.sync_cmnds() |
1773 | 285 | 214 | ||
1774 | 286 | ## set renderer and colors | 215 | ## set renderer and colors |
1775 | 287 | |||
1776 | 288 | #color2 = gtk.gdk.Color(5000,5000,65000) | 216 | #color2 = gtk.gdk.Color(5000,5000,65000) |
1777 | 289 | renderer = gtk.CellRendererText() | 217 | renderer = gtk.CellRendererText() |
1778 | 290 | #renderer.set_property("cell-background-gdk", color) | 218 | #renderer.set_property("cell-background-gdk", color) |
1779 | @@ -308,7 +236,7 @@ | |||
1780 | 308 | True) | 236 | True) |
1781 | 309 | ## set the cell attributes to the appropriate liststore column | 237 | ## set the cell attributes to the appropriate liststore column |
1782 | 310 | self.treeview.columns[n].set_attributes( | 238 | self.treeview.columns[n].set_attributes( |
1784 | 311 | self.treeview.columns[n].cell, text=n) | 239 | self.treeview.columns[n].cell, text=n) |
1785 | 312 | self.treeview.columns[n].set_resizable(True) | 240 | self.treeview.columns[n].set_resizable(True) |
1786 | 313 | 241 | ||
1787 | 314 | ''' set treeview model and put treeview in the scrolled window | 242 | ''' set treeview model and put treeview in the scrolled window |
1788 | @@ -321,12 +249,12 @@ | |||
1789 | 321 | #self.window.show_all() | 249 | #self.window.show_all() |
1790 | 322 | 250 | ||
1791 | 323 | ## instantiate tabs | 251 | ## instantiate tabs |
1793 | 324 | tabs = clicompanionlib.tabs.Tabs() | 252 | self.tabs = clicompanionlib.tabs.Tabs() |
1794 | 325 | ## instantiate controller.Actions, where all the button actions are | 253 | ## instantiate controller.Actions, where all the button actions are |
1795 | 326 | self.actions = clicompanionlib.controller.Actions() | 254 | self.actions = clicompanionlib.controller.Actions() |
1796 | 327 | ## instantiate 'File' and 'Help' Drop Down Menu [menus_buttons.py] | 255 | ## instantiate 'File' and 'Help' Drop Down Menu [menus_buttons.py] |
1797 | 328 | bar = clicompanionlib.menus_buttons.FileMenu() | 256 | bar = clicompanionlib.menus_buttons.FileMenu() |
1799 | 329 | menu_bar = bar.the_menu(self.actions, self.notebook, self.liststore) | 257 | menu_bar = bar.the_menu(self) |
1800 | 330 | 258 | ||
1801 | 331 | 259 | ||
1802 | 332 | ## get row of a selection | 260 | ## get row of a selection |
1803 | @@ -337,17 +265,17 @@ | |||
1804 | 337 | 265 | ||
1805 | 338 | 266 | ||
1806 | 339 | ## double click to run a command | 267 | ## double click to run a command |
1810 | 340 | def treeview_clicked(widget, event): | 268 | def treeview_clicked(widget, path, column): |
1811 | 341 | if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: | 269 | self.actions.run_command(self) |
1812 | 342 | self.actions.run_command(self, self.notebook, self.liststore) | 270 | |
1813 | 343 | 271 | ||
1814 | 344 | ## press enter to run a command | 272 | ## press enter to run a command |
1815 | 345 | def treeview_button(widget, event): | 273 | def treeview_button(widget, event): |
1816 | 346 | keyname = gtk.gdk.keyval_name(event.keyval).upper() | 274 | keyname = gtk.gdk.keyval_name(event.keyval).upper() |
1818 | 347 | #print keyname ##debug | 275 | dbg('Key %s pressed'%keyname) |
1819 | 348 | if event.type == gtk.gdk.KEY_PRESS: | 276 | if event.type == gtk.gdk.KEY_PRESS: |
1820 | 349 | if keyname == 'RETURN': | 277 | if keyname == 'RETURN': |
1822 | 350 | self.actions.run_command(self, self.notebook, self.liststore) | 278 | self.actions.run_command(self) |
1823 | 351 | 279 | ||
1824 | 352 | 280 | ||
1825 | 353 | 281 | ||
1826 | @@ -357,7 +285,7 @@ | |||
1827 | 357 | selection.select_path(0) | 285 | selection.select_path(0) |
1828 | 358 | selection.connect("changed", mark_selected, selection) | 286 | selection.connect("changed", mark_selected, selection) |
1829 | 359 | ## double-click | 287 | ## double-click |
1831 | 360 | self.treeview.connect("button-press-event", treeview_clicked) | 288 | self.treeview.connect("row-activated", treeview_clicked) |
1832 | 361 | #press enter to run command | 289 | #press enter to run command |
1833 | 362 | self.treeview.connect("key-press-event", treeview_button) | 290 | self.treeview.connect("key-press-event", treeview_button) |
1834 | 363 | 291 | ||
1835 | @@ -393,7 +321,7 @@ | |||
1836 | 393 | self.expander.set_label_widget(expander_hbox) | 321 | self.expander.set_label_widget(expander_hbox) |
1837 | 394 | 322 | ||
1838 | 395 | ## Add the first tab with the Terminal | 323 | ## Add the first tab with the Terminal |
1840 | 396 | tabs.add_tab(self, self.notebook) | 324 | self.tabs.add_tab(self.notebook) |
1841 | 397 | self.notebook.set_tab_pos(2) | 325 | self.notebook.set_tab_pos(2) |
1842 | 398 | 326 | ||
1843 | 399 | ## The "Add Tab" tab | 327 | ## The "Add Tab" tab |
1844 | @@ -405,7 +333,7 @@ | |||
1845 | 405 | 333 | ||
1846 | 406 | global button_box | 334 | global button_box |
1847 | 407 | ## buttons at bottom of main window [menus_buttons.py] | 335 | ## buttons at bottom of main window [menus_buttons.py] |
1849 | 408 | button_box = bar.buttons(self.actions, 10, gtk.BUTTONBOX_END, self.notebook, self.liststore) | 336 | button_box = bar.buttons(self, 10, gtk.BUTTONBOX_END) |
1850 | 409 | 337 | ||
1851 | 410 | ## vbox for search, notebook, buttonbar | 338 | ## vbox for search, notebook, buttonbar |
1852 | 411 | vbox = gtk.VBox() | 339 | vbox = gtk.VBox() |
1853 | @@ -421,9 +349,9 @@ | |||
1854 | 421 | self.expander.connect('notify::expanded', self.expanded_cb, self.window, self.search_box) | 349 | self.expander.connect('notify::expanded', self.expanded_cb, self.window, self.search_box) |
1855 | 422 | self.window.connect("delete_event", self.delete_event) | 350 | self.window.connect("delete_event", self.delete_event) |
1856 | 423 | self.window.connect("key-press-event", self.key_clicked) | 351 | self.window.connect("key-press-event", self.key_clicked) |
1858 | 424 | add_tab_button.connect("clicked", tabs.add_tab, self.notebook) | 352 | add_tab_button.connect("clicked", lambda *x: self.tabs.add_tab(self.notebook)) |
1859 | 425 | ## right click menu event capture | 353 | ## right click menu event capture |
1861 | 426 | self.treeview.connect ("button_press_event", bar.right_click, self.actions, self.treeview, self.notebook, self.liststore) | 354 | self.treeview.connect("button_press_event", bar.right_click, self) |
1862 | 427 | 355 | ||
1863 | 428 | # Allow enable drag and drop of rows including row move | 356 | # Allow enable drag and drop of rows including row move |
1864 | 429 | self.treeview.enable_model_drag_source( gtk.gdk.BUTTON1_MASK, | 357 | self.treeview.enable_model_drag_source( gtk.gdk.BUTTON1_MASK, |
1865 | @@ -435,12 +363,20 @@ | |||
1866 | 435 | 363 | ||
1867 | 436 | self.treeview.connect ("drag_data_get", self.drag_data_get_event) | 364 | self.treeview.connect ("drag_data_get", self.drag_data_get_event) |
1868 | 437 | self.treeview.connect ("drag_data_received", self.drag_data_received_event) | 365 | self.treeview.connect ("drag_data_received", self.drag_data_received_event) |
1869 | 366 | self.treeview.connect("drag_drop", self.on_drag_drop ) | ||
1870 | 438 | 367 | ||
1871 | 439 | 368 | ||
1872 | 440 | #self.vte.grab_focus() | 369 | #self.vte.grab_focus() |
1873 | 441 | self.window.show_all() | 370 | self.window.show_all() |
1874 | 442 | return | 371 | return |
1875 | 443 | 372 | ||
1876 | 373 | def on_drag_drop(self, treeview, *x): | ||
1877 | 374 | ''' | ||
1878 | 375 | Stop the signal when in search mode | ||
1879 | 376 | ''' | ||
1880 | 377 | if FILTER: | ||
1881 | 378 | treeview.stop_emission('drag_drop') | ||
1882 | 379 | |||
1883 | 444 | def drag_data_get_event(self, treeview, context, selection, target_id, | 380 | def drag_data_get_event(self, treeview, context, selection, target_id, |
1884 | 445 | etime): | 381 | etime): |
1885 | 446 | """ | 382 | """ |
1886 | @@ -457,90 +393,57 @@ | |||
1887 | 457 | Executed when dropping. | 393 | Executed when dropping. |
1888 | 458 | """ | 394 | """ |
1889 | 459 | global CMNDS | 395 | global CMNDS |
1890 | 396 | global FILTER | ||
1891 | 397 | ## if we are in a search, do nothing | ||
1892 | 398 | if FILTER == 1: | ||
1893 | 399 | return | ||
1894 | 460 | model = treeview.get_model() | 400 | model = treeview.get_model() |
1895 | 401 | ## get the destination | ||
1896 | 402 | drop_info = treeview.get_dest_row_at_pos(x, y) | ||
1897 | 403 | if drop_info: | ||
1898 | 404 | path, position = drop_info | ||
1899 | 405 | iter = model.get_iter(path) | ||
1900 | 406 | dest = list(model.get(iter, 0, 1, 2)) | ||
1901 | 407 | |||
1902 | 408 | ## parse all the incoming commands | ||
1903 | 461 | for data in selection.data.split('\n'): | 409 | for data in selection.data.split('\n'): |
1904 | 462 | # if we got an empty line skip it | 410 | # if we got an empty line skip it |
1905 | 463 | if not data.replace('\r',''): continue | 411 | if not data.replace('\r',''): continue |
1906 | 464 | # format the incoming string | 412 | # format the incoming string |
1907 | 465 | orig = data.replace('\r','').split('\t',2) | 413 | orig = data.replace('\r','').split('\t',2) |
1909 | 466 | orig = tuple([ fld.strip() for fld in orig ]) | 414 | orig = [ fld.strip() for fld in orig ] |
1910 | 467 | # fill the empty fields | 415 | # fill the empty fields |
1911 | 468 | if len(orig) < 3: orig = orig + ('',)*(3-len(orig)) | 416 | if len(orig) < 3: orig = orig + ('',)*(3-len(orig)) |
1915 | 469 | # if the element already exists delete it (dragged from clicompanion) | 417 | dbg('Got drop of command %s'%'_\t_'.join(orig)) |
1913 | 470 | olditer = self.find_iter_by_tuple(orig, model) | ||
1914 | 471 | if olditer: del model[olditer] | ||
1916 | 472 | 418 | ||
1917 | 473 | drop_info = treeview.get_dest_row_at_pos(x, y) | ||
1918 | 474 | if drop_info: | 419 | if drop_info: |
1919 | 475 | path, position = drop_info | ||
1920 | 476 | iter = model.get_iter(path) | ||
1921 | 477 | dest = tuple(model.get(iter, 0, 1, 2)) | ||
1922 | 478 | if (position == gtk.TREE_VIEW_DROP_BEFORE | 420 | if (position == gtk.TREE_VIEW_DROP_BEFORE |
1923 | 479 | or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): | 421 | or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): |
1926 | 480 | model.insert_before(iter, orig) | 422 | dbg('\t to before dest %s'%'_\t_'.join(dest)) |
1927 | 481 | self.drag_cmnd(orig, dest, before=True) | 423 | CMNDS.drag_n_drop(orig, dest, before=True) |
1928 | 482 | else: | 424 | else: |
1931 | 483 | model.insert_after(iter, orig) | 425 | dbg('\t to after dest %s'%'_\t_'.join(dest)) |
1932 | 484 | self.drag_cmnd(orig, dest, before=False) | 426 | CMNDS.drag_n_drop(orig, dest, before=False) |
1933 | 485 | else: | 427 | else: |
1945 | 486 | if len(model) > 0: | 428 | dbg('\t to the end') |
1946 | 487 | iter = model[-1].iter | 429 | CMNDS[len(CMNDS)] = orig |
1947 | 488 | model.insert_after(iter, orig) | 430 | if context.action == gtk.gdk.ACTION_MOVE: |
1948 | 489 | else: | 431 | context.finish(True, True, etime) |
1949 | 490 | model.insert(0, orig) | 432 | self.sync_cmnds() |
1950 | 491 | return | 433 | CMNDS.save() |
1940 | 492 | dest = tuple(model.get(iter, 0, 1, 2)) | ||
1941 | 493 | self.drag_cmnd(orig, dest, before=False) | ||
1942 | 494 | if context.action == gtk.gdk.ACTION_MOVE: | ||
1943 | 495 | context.finish(True, True, etime) | ||
1944 | 496 | self.actions.save_cmnds() | ||
1951 | 497 | 434 | ||
1952 | 498 | def find_iter_by_tuple(self, data, model): | ||
1953 | 499 | for row in model: | ||
1954 | 500 | if tuple(model.get(row.iter, 0, 1, 2)) == data: | ||
1955 | 501 | return row.iter | ||
1956 | 502 | return None | ||
1957 | 503 | |||
1958 | 504 | def drag_cmnd(self, orig, dest, before=True): | ||
1959 | 505 | """ | ||
1960 | 506 | Sync the CMNDS array with the drag and drop of the treeview. | ||
1961 | 507 | """ | ||
1962 | 508 | global CMNDS | ||
1963 | 509 | i = j = None | ||
1964 | 510 | pos = 0 | ||
1965 | 511 | for cmnd in CMNDS: | ||
1966 | 512 | if cmnd == orig: | ||
1967 | 513 | i = pos | ||
1968 | 514 | elif cmnd == dest: | ||
1969 | 515 | j = pos | ||
1970 | 516 | pos += 1 | ||
1971 | 517 | ## both from clicompanion | ||
1972 | 518 | if i != None and j != None: | ||
1973 | 519 | cmnd = CMNDS.pop(i) | ||
1974 | 520 | if before and i<=j: | ||
1975 | 521 | CMNDS.insert(j-1, cmnd) | ||
1976 | 522 | elif before and i>j: | ||
1977 | 523 | CMNDS.insert(j, cmnd) | ||
1978 | 524 | elif i<=j: | ||
1979 | 525 | CMNDS.insert(j, cmnd) | ||
1980 | 526 | else: | ||
1981 | 527 | CMNDS.insert(j+1, cmnd) | ||
1982 | 528 | ## origin unknown | ||
1983 | 529 | elif j != None: | ||
1984 | 530 | cmnd = orig | ||
1985 | 531 | if before: | ||
1986 | 532 | CMNDS.insert(j, cmnd) | ||
1987 | 533 | else: | ||
1988 | 534 | CMNDS.insert(j+1, cmnd) | ||
1989 | 535 | |||
1990 | 536 | |||
1991 | 537 | def main(self): | 435 | def main(self): |
1992 | 538 | try: | 436 | try: |
1993 | 539 | gtk.main() | 437 | gtk.main() |
1994 | 540 | except KeyboardInterrupt: | 438 | except KeyboardInterrupt: |
1995 | 541 | pass | 439 | pass |
1996 | 542 | 440 | ||
1999 | 543 | def run(): | 441 | def run( options=None ): |
2000 | 544 | 442 | ##create the config file | |
2001 | 443 | config = cc_config.create_config() | ||
2002 | 444 | if config.get('terminal','debug') == 'True': | ||
2003 | 445 | utils.DEBUG = True | ||
2004 | 446 | CMNDS.load(options and options.cheatsheet or None) | ||
2005 | 447 | dbg('Loaded commands %s'%CMNDS) | ||
2006 | 545 | main_window = MainWindow() | 448 | main_window = MainWindow() |
2007 | 546 | main_window.main() | 449 | main_window.main() |
I checked Clicompanion both statically and dynamically. No errors in code observed.
Bug #611141: It is not obvious that "q" must be pressed to exit help (man pages) [OK]
Bug #801906: clicompanion crashes on start with ValueError in _get() [Look good]
Bug #909894: Double click execution with user input drags command [OK]
Bug #910249: Warning window (when wrong params issued) not working properly [OK]
Bug #910355: Properties are not applied to the current terminal [OK]
Bug #910360: Incorrect .clicompanion2 file causes the program to crash [OK]
Bug #910370: Drag and drop when searching breaks the drag and drop [OK]
Bug #910531: Allowed empty user input [OK]
Bug #910533: In a fresh start, when executting the first command, the second gets executed instead [OK]
Regression bugs: .config/ clicompanion/ config" , but that isn't true - my configuration is stored correctly and no new file was created.
1. Low importance. Everytime, when I open new instance of Clicompanion, I got a message "INFO: Created config file at /home/user/
Thank You for your work.