Merge lp:~duanedesign/clicompanion/clicompanion.seperate.merge into lp:clicompanion

Proposed by Duane Hinnen
Status: Merged
Approved by: Duane Hinnen
Approved revision: 56
Merged at revision: 55
Proposed branch: lp:~duanedesign/clicompanion/clicompanion.seperate.merge
Merge into: lp:clicompanion
Diff against target: 2240 lines (+1188/-969)
15 files modified
MANIFEST (+12/-0)
clicompanion (+37/-0)
clicompanion.py (+0/-723)
clicompanion/__init__.py (+0/-23)
clicompanion/menus_buttons.py (+0/-157)
clicompanion/utils.py (+0/-66)
clicompanionlib/__init__.py (+23/-0)
clicompanionlib/controller.py (+428/-0)
clicompanionlib/menus_buttons.py (+175/-0)
clicompanionlib/tabs.py (+81/-0)
clicompanionlib/utils.py (+56/-0)
clicompanionlib/view.py (+279/-0)
data/clicompanion.desktop (+7/-0)
data/clicompanion2.config (+48/-0)
setup.py (+42/-0)
To merge this branch: bzr merge lp:~duanedesign/clicompanion/clicompanion.seperate.merge
Reviewer Review Type Date Requested Status
Duane Hinnen Approve
Review via email: mp+42261@code.launchpad.net

Description of the change

merge of lp:clicompanion.seperate
Because of the way that branch was created it was necessary to create clicompanion.seperate.merge and then merge it with trunk

To post a comment you must log in.
Revision history for this message
Duane Hinnen (duanedesign) wrote :

This is actually clicompanion.seperate. I had to create another branch of trunk and do the merge correctly. This is what the clicompanion.seperate.merge is.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file 'CLIcompanion.16.png'
0Binary files CLIcompanion.16.png 2010-10-06 06:54:47 +0000 and CLIcompanion.16.png 1970-01-01 00:00:00 +0000 differ0Binary files CLIcompanion.16.png 2010-10-06 06:54:47 +0000 and CLIcompanion.16.png 1970-01-01 00:00:00 +0000 differ
=== added file 'MANIFEST'
--- MANIFEST 1970-01-01 00:00:00 +0000
+++ MANIFEST 2010-11-30 16:11:27 +0000
@@ -0,0 +1,12 @@
1setup.py
2clicompanion
3clicompanionlib/__init__.py
4clicompanionlib/controller.py
5clicompanionlib/menus_buttons.py
6clicompanionlib/tabs.py
7clicompanionlib/utils.py
8clicompanionlib/view.py
9data/ubuntuone-indicator.desktop
10data/clicompanion.config
11data/clicompanion.16.png
12data/clicompanion.64.png
013
=== added file 'clicompanion'
--- clicompanion 1970-01-01 00:00:00 +0000
+++ clicompanion 2010-11-30 16:11:27 +0000
@@ -0,0 +1,37 @@
1#! /usr/bin/env python
2
3import locale
4import gettext
5import os
6
7from clicompanionlib.view import run
8
9
10BASEDIR = '/usr/share/clicompanion/'
11
12def get_language():
13 """Return the language to be used by the system.
14
15 If it finds the system language in the translated files, it
16 returns it, otherwise it just returns None.
17 """
18 loc = locale.setlocale(locale.LC_ALL, "")
19 loc = loc[:2]
20 traducidos = os.listdir(locale_dir)
21 if loc in traducidos:
22 return loc
23 return
24
25locale_dir = os.path.join(BASEDIR, "locale")
26gettext.install('clicompanion', locale_dir, unicode=True)
27idioma = get_language()
28if idioma is not None:
29 mo = os.path.join(locale_dir, '%s/LC_MESSAGES/clicompanion.mo' % idioma)
30 if not os.access(mo, os.F_OK):
31 raise IOError("The l10n directory (for language %r) exists but "
32 "not the clicompanion.mo file" % idioma)
33 trans = gettext.translation('clicompanion', locale_dir, languages=[idioma])
34 trans.install(unicode=True)
35
36if __name__ == "__main__":
37 run()
038
=== removed directory 'clicompanion'
=== removed file 'clicompanion.py'
--- clicompanion.py 2010-10-06 06:47:50 +0000
+++ clicompanion.py 1970-01-01 00:00:00 +0000
@@ -1,723 +0,0 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# clicompanion.py - commandline tool.
5#
6# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
7#
8# This program is free software: you can redistribute it and/or modify it
9# under the terms of the GNU General Public License version 3, as published
10# by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranties of
14# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20#pdb debugger
21#import pdb; pdb.set_trace()
22#
23
24
25import re
26import sys
27import pygtk
28pygtk.require('2.0')
29
30import os
31import os.path
32
33## Starting with the i18n ###
34import locale
35import gettext
36
37BASEDIR = '/usr/share/clicompanion/'
38
39def get_language():
40 """Return the language to be used by the system.
41
42 If it finds the system language in the translated files, it
43 returns it, otherwise it just returns None.
44 """
45 loc = locale.setlocale(locale.LC_ALL, "")
46 loc = loc[:2]
47 traducidos = os.listdir(locale_dir)
48 if loc in traducidos:
49 return loc
50 return
51
52locale_dir = os.path.join(BASEDIR, "locale")
53gettext.install('clicompanion', locale_dir, unicode=True)
54idioma = get_language()
55if idioma is not None:
56 mo = os.path.join(locale_dir, '%s/LC_MESSAGES/clicompanion.mo' % idioma)
57 if not os.access(mo, os.F_OK):
58 raise IOError("The l10n directory (for language %r) exists but "
59 "not the clicompanion.mo file" % idioma)
60 trans = gettext.translation('clicompanion', locale_dir, languages=[idioma])
61 trans.install(unicode=True)
62## End with i18n ###
63
64## import gtk or print error
65try:
66 import gtk
67except:
68 error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
69 _("You need to install the python gtk bindings"))
70 error.run()
71 sys.exit (1)
72
73## import vte or display message dialog
74try:
75 import vte
76except:
77 error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
78 _('You need to install python bindings for libvte'))
79 error.run()
80 sys.exit (1)
81
82import clicompanion.menus_buttons
83from clicompanion.utils import get_user_shell, sumfile
84
85
86#TODO: Get rid of global commands CMNDS and ROW
87CMNDS = []
88ROW = ''
89CHEATSHEET = os.path.expanduser("~/.clicompanion")
90CHEATSHEETBAK = os.path.expanduser("~/.clicompanion.bak")
91CONFIG_ORIG = "/etc/clicompanion.d/clicompanion.config"
92
93
94class Companion(object):
95 '''
96 All the actions the program can do.
97 '''
98 ## copy config file to user $HOME if does not exist
99 def setup(self):
100 """Create an initial cheatsheet."""
101 if not os.path.exists(CHEATSHEET):
102 if os.path.exists(CONFIG_ORIG):
103 os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
104 else:
105 ## Oops! Looks like there's no cheatsheet in CHEATSHEET.
106 ## Then, create an empty cheatsheet.
107 open(CHEATSHEET, 'w').close()
108
109 elif os.path.exists(CHEATSHEET):
110 if os.path.exists(CONFIG_ORIG):
111 md5 = sumfile()
112 print md5
113 if md5 == '824868f40cd02f0039d5a1fbdbe642d7' or 'a244f1b197f5cfc6b2f35b65911d3930' or '08e7f4de1838b79ab476fcbfb8074da0' or 'd68d6e9da0a3753c8142b63f0ea74511' or '8ab6d4bf6168c1b775221f466c2fcbbd' or ' 6f4f152766441670a55d3bf00567c92e' or ' f4e73fe22505091d6d75767fafc2848c' or ' 7d2f69943cfe5dbd33a45c63008fca17' or '7fc757ca67121b14e574280a6dbe24ef' or '0e345d5934032aa7fecb23cff56d5407':
114 os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
115 print '.clicompanion not modified by user'
116 #TODO what to do if user has modified command dictionary?
117 else:
118 os.system ("cp %s %s" % (CHEATSHEET, CHEATSHEETBAK))
119 os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
120 print '.clicompanion modified by user'
121
122 ## close the window and quit
123 def delete_event(self, widget, data=None):
124 gtk.main_quit()
125 return False
126
127 ## Info Dialog Box
128 ## if a command needs more info EX: a package name, a path
129 def get_info(self, widget, data=None):
130 global ROW
131 row_int = int(ROW[0][0])
132
133 ## Create Dialog object
134 dialog = gtk.MessageDialog(
135 None,
136 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
137 gtk.MESSAGE_QUESTION,
138 gtk.BUTTONS_OK,
139 None)
140
141 # Primary text
142 dialog.set_markup(_("This command requires more information"))
143
144 ## create the text input field
145 entry = gtk.Entry()
146 ## allow the user to press enter to do ok
147 entry.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
148
149 ## create a horizontal box to pack the entry and a label
150 hbox = gtk.HBox()
151 hbox.pack_start(gtk.Label(self.liststore[row_int][1]+":"), False, 5, 5)
152 hbox.pack_end(entry)
153 ## some secondary text
154 dialog.format_secondary_markup(_("Please provide a "+self.liststore[row_int][1]))
155 ## add it and show it
156 dialog.vbox.pack_end(hbox, True, True, 0)
157 dialog.show_all()
158
159 ## Show the dialog
160 dialog.run()
161
162 ## user text assigned to a variable
163 text = entry.get_text()
164 user_input = text.split(' ')
165
166 ## The destroy method must be called otherwise the 'Close' button will
167 ## not work.
168 dialog.destroy()
169 return user_input
170
171 def responseToDialog(self, text, dialog, response):
172 dialog.response(response)
173
174 ## Add command dialog box
175 def add_command(self, widget):
176
177 ## Create Dialog object
178 dialog = gtk.MessageDialog(
179 None,
180 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
181 gtk.MESSAGE_QUESTION,
182 gtk.BUTTONS_OK,
183 None)
184
185 ## primaary text
186 dialog.set_markup(_("Add a command to your clicompanion dictionary"))
187
188 #create the text input field
189 entry1 = gtk.Entry()
190 entry2 = gtk.Entry()
191 entry3 = gtk.Entry()
192 ## allow the user to press enter to do ok
193 entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
194 entry2.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
195 entry3.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
196
197 ## create three labels
198 hbox1 = gtk.HBox()
199 hbox1.pack_start(gtk.Label(_("Command")), False, 5, 5)
200 hbox1.pack_start(entry1, False, 5, 5)
201
202 hbox1.pack_start(gtk.Label(_("User Input")), False, 5, 5)
203 hbox1.pack_start(entry2, False, 5, 5)
204
205 hbox2 = gtk.HBox()
206 hbox2.pack_start(gtk.Label(_("Description")), False, 5, 5)
207 hbox2.pack_start(entry3, True, 5, 5)
208
209 ## cancel button
210 dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
211 ## some secondary text
212 dialog.format_secondary_markup(_("Please provide a command. Use a @ symbol where user input is required at runtime. Example: ls /any/direstory would be entered as ls @. Also include a brief description."))
213
214 ## add it and show it
215 dialog.vbox.pack_end(hbox2, True, True, 0)
216 dialog.vbox.pack_end(hbox1, True, True, 0)
217 dialog.show_all()
218 ## Show the dialog
219 result = dialog.run()
220
221 if result == gtk.RESPONSE_OK:
222 ## user text assigned to a variable
223 text1 = entry1.get_text()
224 text2 = entry2.get_text()
225 text3 = entry3.get_text()
226 ## open flat file that contains the commands and add the new command
227 with open(CHEATSHEET, "a") as cheatfile:
228 if text1 != "":
229 cheatfile.write(text1+" :"+text2+" : "+text3+'\n')
230 cheatfile.close()
231 l = str(text1+" :"+text2+" : "+text3)
232 ls = l.split(':',2)
233 CMNDS.append(ls[0])
234 self.liststore.append([ls[0],ls[1],ls[2]])
235
236 ## The destroy method must be called otherwise the 'Close' button will
237 ## not work.
238 dialog.destroy()
239 #return text
240
241 ## This the edit function
242 def edit_command(self, widget , data=None):
243
244 global ROW
245 row_int = int(ROW[0][0])
246
247
248 row_obj1 = self.liststore[row_int][0]
249 text1 = "".join(row_obj1)
250
251 row_obj2 = self.liststore[row_int][1]
252 text2 = "".join(row_obj2)
253
254 row_obj3 = self.liststore[row_int][2]
255 text3 = "".join(row_obj3)
256
257 ## Create Dialog object
258 dialog = gtk.MessageDialog(
259 None,
260 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
261 gtk.MESSAGE_QUESTION,
262 gtk.BUTTONS_OK,
263 None)
264
265 # primary text
266 dialog.set_markup(_("Edit the command in your clicompanion dictionary"))
267
268 ## create the text input fields
269 entry1 = gtk.Entry()
270 entry1.set_text(text1)
271 entry2 = gtk.Entry()
272 entry2.set_text(text2)
273 entry3 = gtk.Entry()
274 entry3.set_text(text3)
275 ## allow the user to press enter to do ok
276 entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
277
278 ## create three labels
279 hbox1 = gtk.HBox()
280 hbox1.pack_start(gtk.Label(_("Command")), False, 5, 5)
281 hbox1.pack_start(entry1, False, 5, 5)
282
283 hbox1.pack_start(gtk.Label(_("User Input")), False, 5, 5)
284 hbox1.pack_start(entry2, False, 5, 5)
285
286 hbox2 = gtk.HBox()
287 hbox2.pack_start(gtk.Label(_("Description")), False, 5, 5)
288 hbox2.pack_start(entry3, True, 5, 5)
289
290 ## cancel button
291 dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
292 ## some secondary text
293 dialog.format_secondary_markup(_("Please provide a command, description, and what type of user variable, if any, is required."))
294
295 ## add it and show it
296 dialog.vbox.pack_end(hbox2, True, True, 0)
297 dialog.vbox.pack_end(hbox1, True, True, 0)
298 dialog.show_all()
299 ## Show the dialog
300 result = dialog.run()
301
302 if result == gtk.RESPONSE_OK:
303 ## user text assigned to a variable
304 text1 = entry1.get_text()
305 text2 = entry2.get_text()
306 text3 = entry3.get_text()
307
308 if text1 != "":
309 self.remove_command(widget)
310 ## open flat file, add the new command
311 with open(CHEATSHEET, "a") as cheatfile:
312 cheatfile.write(text1+":"+text2+":"+text3+'\n')
313 cheatfile.close()
314 l = str(text1+":"+text2+":"+text3)
315 ls = l.split(':',2)
316 CMNDS.append(ls[0])
317 self.liststore.append([ls[0],ls[1],ls[2]])
318
319 ## The destroy method must be called otherwise the 'Close' button will
320 ## not work.
321 dialog.destroy()
322
323
324 ## Remove command from command file and GUI
325 def remove_command(self, widget, data=None):
326 global ROW
327 row_int = int(ROW[0][0]) #convert pathlist into something usable
328
329 del CMNDS[row_int]
330 del self.liststore[row_int]
331
332
333 ## open command file and delete line so the change is persistent
334 with open(CHEATSHEET, "r") as cheatfile:
335 cheatlines = cheatfile.readlines()
336 del cheatlines[row_int]
337 cheatfile.close()
338 with open(CHEATSHEET, "w") as cheatfile2:
339 cheatfile2.writelines(cheatlines)
340 cheatfile2.close()
341
342
343 def _filter_commands(self, widget, data=None):
344 """
345 Show commands matching a given search term.
346 The user should enter a term in the search box and the treeview should
347 only display the rows which contain the search term.
348 Pretty straight-forward.
349 """
350 search_term = self.search_box.get_text()
351
352 ## Create a TreeModelFilter object which provides auxiliary functions for
353 ## filtering data.
354 ## http://www.pygtk.org/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html
355 modelfilter = self.liststore.filter_new()
356 def search(modelfilter, iter, search_term):
357 try:
358 ## Iterate through every column and row and check if the search
359 ## term is there:
360 if search_term in modelfilter.get_value(iter, 0) or \
361 search_term in modelfilter.get_value(iter, 1) or \
362 search_term in modelfilter.get_value(iter, 2):
363 return True
364 except TypeError:
365 ## Python raises a TypeError if row data doesn't exist. Catch
366 ## that and fail silently.
367 pass
368
369 modelfilter.set_visible_func(search, search_term)
370 self.treeview.set_model(modelfilter)
371
372 ## send the command to the terminal
373 def run_command(self, widget, data=None):
374 global ROW
375 text = ""
376 row_int = int(ROW[0][0]) ## removes everything but number from [5,]
377
378 ## get the current notebook page so the function knows which terminal to run the command in.
379 pagenum = self.notebook.get_current_page()
380 widget = self.notebook.get_nth_page(pagenum)
381 page_widget = widget.get_child()
382
383 ## CMNDS is where commands are stored
384 cmnd = CMNDS[row_int]
385 ## find how many @(user arguments) are in command
386 match = re.findall('@', cmnd)
387 '''
388 Make sure user arguments were found. Replace @ with something
389 .format can read. This is done so the user can just enter @, when
390 adding a command where arguments are needed, instead
391 of {0[1]}, {0[1]}, {0[2]}
392 '''
393 if match == False:
394 pass
395 else:
396 num = len(match)
397 ran = 0
398 new_cmnd = self.replace(cmnd, num, ran)
399
400 if not self.liststore[row_int][1] == " ": # command with user input
401 text = Companion.get_info(self, text)
402 c = new_cmnd.format(text)
403 page_widget.feed_child(c+"\n") #send command w/ input
404 page_widget.show()
405 else: ## command that has no user input
406 page_widget.feed_child(cmnd+"\n") #send command
407 page_widget.show()
408 page_widget.grab_focus()
409
410 ## replace @ with {0[n]}
411 def replace(self, cmnd, num, ran):
412 replace_cmnd=re.sub('@', '{0['+str(ran)+']}', cmnd, count=1)
413 cmnd = replace_cmnd
414 ran += 1
415 if ran < num:
416 return self.replace(cmnd, num, ran)
417 else:
418 pass
419 return cmnd
420
421 ## open the man page for selected command
422 def man_page(self, widget, data=None):
423 row_int = int(ROW[0][0]) # removes everything but number from EX: [5,]
424 cmnd = CMNDS[row_int] #CMNDS is where commands are store
425 splitcommand = self._filter_sudo_from(cmnd.split(" "))
426 ## get current notebook tab to use in function
427 pagenum = self.notebook.get_current_page()
428 widget = self.notebook.get_nth_page(pagenum)
429 page_widget = widget.get_child()
430 #send command to Terminal
431 page_widget.feed_child("man "+splitcommand[0]+"| most \n")
432 page_widget.grab_focus()
433 page_widget.show()
434
435
436 @staticmethod
437 def _filter_sudo_from(command):
438 """Filter the sudo from `command`, where `command` is a list.
439 Return the command list with the "sudo" filtered out.
440 """
441 if command[0].startswith("sudo"):
442 del command[0]
443 return command
444 return command
445
446
447 ## open file containing command dictionary and put it in a variable
448 def update(self):
449 try:
450 with open(CHEATSHEET, "r") as cheatfile:
451 bugdata=cheatfile.read()
452 cheatfile.close()
453 except IOError:
454 ## CHEATSHEET is not there. Oh, no!
455 ## So, run self.setup() again.
456 self.setup()
457 ## Then, run me again.
458 self.update()
459
460 global CMNDS
461 ## add bug data from .clicompanion to the liststore
462 CMNDS = []
463 for line in bugdata.splitlines():
464 l = line.split(':',2)
465 CMNDS.append(l[0])
466 self.liststore.append([l[0],l[1],l[2]])
467
468
469
470 ## add a new terminal in a tab above the current terminal
471 def add_tab(self, data=None):
472
473 _vte = vte.Terminal()
474 _vte.set_size_request(700, 220)
475 _vte.connect ("child-exited", lambda term: gtk.main_quit())
476 _vte.fork_command(get_user_shell()) # Get the user's default shell
477
478 vte_tab = gtk.ScrolledWindow()
479 vte_tab.add(_vte)
480 #self.notebook.set_show_tabs(True)
481 #self.notebook.set_show_border(True)
482
483 gcp = self.notebook.get_current_page() +1
484 pagenum = ('Tab %d') % gcp
485
486 box = gtk.HBox()
487 label = gtk.Label(pagenum)
488 box.pack_start(label, True, True)
489
490 ## x image for tab close button
491 close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
492 ## close button
493 closebtn = gtk.Button()
494 closebtn.set_relief(gtk.RELIEF_NONE)
495 closebtn.set_focus_on_click(True)
496
497 closebtn.add(close_image)
498 ## put button in a box and show box
499 box.pack_end(closebtn, False, False)
500 box.show_all()
501
502 self.notebook.prepend_page(vte_tab, box) # add tab
503 self.notebook.set_scrollable(True)
504 _vte.connect ("button_press_event", self.copy_paste, None)
505 vte_tab.grab_focus()
506 # signal handler for tab
507 closebtn.connect("clicked", self.close_tab, vte_tab)
508 self.window.show_all()
509
510 return vte_tab
511
512
513 ## Remove a page from the notebook
514 def close_tab(self, sender, widget):
515 ## get the page number of the tab we wanted to close
516 pagenum = self.notebook.page_num(widget)
517 ## and close it
518 self.notebook.remove_page(pagenum)
519
520 #TODO: Move to menus_buttons
521 def copy_paste(self, vte, event, data=None):
522 if event.button == 3:
523
524 time = event.time
525 ## right-click popup menu Copy
526 popupMenu = gtk.Menu()
527 menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_COPY)
528 popupMenu.add(menuPopup1)
529 menuPopup1.connect('activate', lambda x: vte.copy_clipboard())
530 ## right-click popup menu Paste
531 menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_PASTE)
532 popupMenu.add(menuPopup2)
533 menuPopup2.connect('activate', lambda x: vte.paste_clipboard())
534
535 ## Show popup menu
536 popupMenu.show_all()
537 popupMenu.popup( None, None, None, event.button, time)
538 return True
539 else:
540 pass
541
542 def about_event(self):
543 pass
544 def help_event(self):
545 pass
546
547 #liststore in a scrolled window in an expander
548 def expanded_cb(self, expander, params):
549 if expander.get_expanded():
550
551 self.update()
552 ## create the TreeView
553 self.treeview = gtk.TreeView()
554 ## create window with scrollbar
555 self.scrolledwindow = gtk.ScrolledWindow()
556 self.scrolledwindow.set_size_request(700, 220)
557
558 ## create the TreeViewColumns to display the data
559 self.treeview.columns = [None]*3
560 self.treeview.columns[0] = gtk.TreeViewColumn(_('Command'))
561 self.treeview.columns[1] = gtk.TreeViewColumn(_('User Argument'))
562 self.treeview.columns[2] = gtk.TreeViewColumn(_('Description'))
563
564 ## right click menu event capture
565 bar = clicompanion.menus_buttons.FileMenu()
566 self.treeview.connect ("button_press_event", bar.right_click, self)
567
568 for n in range(3):
569 ## add columns to treeview
570 self.treeview.append_column(self.treeview.columns[n])
571 ## create a CellRenderers to render the data
572 self.treeview.columns[n].cell = gtk.CellRendererText()
573 ## add the cells to the columns
574 self.treeview.columns[n].pack_start(self.treeview.columns[n].cell,
575 True)
576 ## set the cell attributes to the appropriate liststore column
577 self.treeview.columns[n].set_attributes(
578 self.treeview.columns[n].cell, text=n)
579 self.treeview.columns[n].set_resizable(True)
580
581 ## The set_model() method sets the "model" property for the treeview to the value of model. model : the new tree model to use with the treeview
582 self.treeview.set_model(self.liststore)
583 self.scrolledwindow.add(self.treeview)
584 expander.add(self.scrolledwindow)
585
586 self.window.show_all()
587
588 self.treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
589 self.treeview.get_selection().connect('changed',lambda s: mark_selected(s))
590
591 def mark_selected(treeselection):
592 (model,pathlist)=treeselection.get_selected_rows()
593 global ROW
594 ROW = pathlist
595
596 # Activate the search box when not expanded
597 self.search_box.set_sensitive(True)
598 else:
599 # De-activate the search box when not expanded
600 self.search_box.set_sensitive(False)
601
602 expander.remove(expander.child)
603 ##reset the size of the window to its original one
604 self.window.resize(1, 1)
605 return
606
607
608 def __init__(self):
609 ##For now TERM is hardcoded to xterm because of a change
610 ##in libvte in Ubuntu Maverick
611 os.putenv('TERM', 'xterm')
612 ## copy config file to user $HOME if does not exist
613 self.setup()
614 #TODO: do we want to do this? Or just keep the height under 600.
615 ##Get user screen size##
616 #screen = gtk.gdk.display_get_default().get_default_screen()
617 #screen_size = screen.get_monitor_geometry(0)
618 #height = screen.get_height() ## screen height ##
619 ## Create a new window
620 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
621 ## create a liststore with three string columns
622 self.liststore = gtk.ListStore(str, str, str)
623 ## Create an expander
624 expander = gtk.Expander()
625 ## Create Notebook
626 self.notebook = gtk.Notebook()
627 ## set Window title
628 self.window.set_title("CLI Companion")
629 ## Adding icon
630 icon = gtk.gdk.pixbuf_new_from_file("/usr/share/pixmaps/clicompanion.16.png")
631 self.window.set_icon(icon)
632 ## Sets the border width of the window.
633 self.window.set_border_width(10)
634 ## set the size of the window
635 self.window.set_default_size(700, 400)
636 ## Sets the position of the window relative to the screen
637 self.window.set_position(gtk.WIN_POS_CENTER)
638 ## Allow user to resize window
639 self.window.set_resizable(True)
640
641 self.window.connect("delete_event", self.delete_event)
642
643 ## 'File' and 'Help' Drop Down Menu [menus_buttons.py]
644 bar = clicompanion.menus_buttons.FileMenu()
645 menu_bar = bar.the_menu(self)
646 ## The search section
647 self.search_label = gtk.Label(_("Search:"))
648 self.search_label.set_alignment(xalign=-1, yalign=0)
649 self.search_box = gtk.Entry()
650 self.search_box.connect("changed", self._filter_commands)
651 ## search box tooltip
652 self.search_box.set_tooltip_text("Search your list of commands")
653 # Set the search box sensitive at program start, because expander is not
654 # unfolded by default
655 self.search_box.set_sensitive(False)
656 ## hbox for menu and search Entry
657 menu_search_hbox = gtk.HBox(False)
658 menu_search_hbox.pack_end(self.search_box, True)
659 menu_search_hbox.pack_end(self.search_label, False, False, 10)
660 menu_search_hbox.pack_start(menu_bar, True)
661
662 ## TODO Do we want to start with the command list open or closed?
663 ## This code opens the app with it open
664 ## We would also need to change the search field disable code
665 ## start program with expander open
666 #expander.set_expanded(True)
667 #self.expanded_cb(expander, None)
668
669 ## expander signal
670 expander.connect('notify::expanded', self.expanded_cb)
671
672 ## expander title
673 expander_hbox = gtk.HBox()
674 image = gtk.Image()
675 image.set_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
676 label = gtk.Label(' Command List')
677 ## tooltip for the label of the expander
678 expander_hbox.set_tooltip_text("Click to show/hide command list")
679
680 ## add expander widget to hbox
681 expander_hbox.pack_start(image, False, False)
682 expander_hbox.pack_start(label, True, False)
683 expander.set_label_widget(expander_hbox)
684
685 ## Add the first tab with the Terminal
686 self.add_tab()
687 self.notebook.set_tab_pos(1)
688
689 ## The "Add Tab" tab
690 add_tab_button = gtk.Button("+")
691 ## tooltip for "Add Tab" tab
692 add_tab_button.set_tooltip_text("Click to add another Tab")
693 add_tab_button.connect("clicked", self.add_tab)
694 self.notebook.append_page(gtk.Label(""), add_tab_button)
695
696 ## buttons at bottom of main window [menus_buttons.py]
697 button_box = bar.buttons(self, 10, gtk.BUTTONBOX_END)
698
699 ## vbox for search, notebook, buttonbar
700 self.vbox = gtk.VBox()
701 self.window.add(self.vbox)
702 ## pack everytyhing in the vbox
703 #self.vbox.pack_start(menu_bar, False, False, 0) ##menuBar
704 self.vbox.pack_start(menu_search_hbox, False, False, 5)
705 self.vbox.pack_start(expander, False, False, 5)
706 self.vbox.pack_start(self.notebook, True, True, 10)
707 self.vbox.pack_start(button_box, False, False, 5)
708
709
710 #self.vte.grab_focus()
711 self.window.show_all()
712 return
713
714def main():
715 try:
716 gtk.main()
717 except KeyboardInterrupt:
718 pass
719
720if __name__ == "__main__":
721 companion = Companion()
722 main()
723
7240
=== removed file 'clicompanion/__init__.py'
--- clicompanion/__init__.py 2010-10-06 06:54:47 +0000
+++ clicompanion/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,23 +0,0 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# clicompanion.py - commandline tool.
5#
6# Copyright 2010 Duane Hinnen, Kenny Meyer
7#
8# This program is free software: you can redistribute it and/or modify it
9# under the terms of the GNU General Public License version 3, as published
10# by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranties of
14# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20#
21'''
22blah, blah, blah
23'''
240
=== removed file 'clicompanion/menus_buttons.py'
--- clicompanion/menus_buttons.py 2010-10-06 06:54:47 +0000
+++ clicompanion/menus_buttons.py 1970-01-01 00:00:00 +0000
@@ -1,157 +0,0 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
5#
6# This file contains the menus, buttons, and right clicks
7#
8#import clicompanion
9import gtk
10
11class FileMenu(object):
12 def the_menu(self, cli):
13 menu = gtk.Menu()
14 root_menu = gtk.MenuItem(_("File"))
15 root_menu.set_submenu(menu)
16
17 menu2 = gtk.Menu()
18 root_menu2 = gtk.MenuItem(_("Help"))
19 root_menu2.set_submenu(menu2)
20
21 ##FILE MENU ##
22 ## Make 'Run' menu entry
23 menu_item1 = gtk.MenuItem(_("Run Command"))
24 menu.append(menu_item1)
25 menu_item1.connect("activate", cli.run_command)
26 menu_item1.show()
27
28 ## Make 'Add' file menu entry
29 menu_item2 = gtk.MenuItem(_("Add Command"))
30 menu.append(menu_item2)
31 menu_item2.connect("activate", cli.add_command)
32 menu_item2.show()
33
34 ## Make 'Remove' file menu entry
35 menu_item2 = gtk.MenuItem(_("Remove Command"))
36 menu.append(menu_item2)
37 menu_item2.connect("activate", cli.remove_command)
38 menu_item2.show()
39
40 ## Make 'Quit' file menu entry
41 menu_item3 = gtk.MenuItem(_("Quit"))
42 menu.append(menu_item3)
43 menu_item3.connect("activate", cli.delete_event)
44 menu_item3.show()
45
46
47 ## Make 'Add Tab' file menu entry
48 menu_item4 = gtk.MenuItem(_("Add Tab"))
49 menu.append(menu_item4)
50 menu_item4.connect("activate", cli.add_tab)
51 menu_item4.show()
52
53
54 ## HELP MENU ##
55 ## Make 'About' file menu entry
56 menu_item11 = gtk.MenuItem(_("About"))
57 menu2.append(menu_item11)
58 menu_item11.connect("activate", cli.about_event)
59 menu_item11.show()
60
61
62 ## Make 'Help' file menu entry
63 menu_item22 = gtk.MenuItem(_("Help"))
64 menu2.append(menu_item22)
65 menu_item22.connect("activate", cli.help_event)
66 menu_item22.show()
67
68
69 menu_bar = gtk.MenuBar()
70
71 menu_bar.append (root_menu) ##Menu bar(file)
72 menu_bar.append (root_menu2) ##Menu bar(help)
73 #menu_bar.show() ##show File Menu # Menu Bar
74 ##Show 'File' Menu
75 #root_menu.show()
76 return menu_bar
77
78
79
80 def buttons(self, cli, spacing, layout):
81 #button box at bottom of main window
82 frame = gtk.Frame()
83 bbox = gtk.HButtonBox()
84 bbox.set_border_width(5)
85 frame.add(bbox)
86
87 # Set the appearance of the Button Box
88 bbox.set_layout(layout)
89 bbox.set_spacing(spacing)
90 # Run button
91 buttonRun = gtk.Button(_("Run"))
92 bbox.add(buttonRun)
93 buttonRun.connect("clicked", cli.run_command)
94 buttonRun.set_tooltip_text("Click to run a highlighted command")
95 # Add button
96 buttonAdd = gtk.Button(stock=gtk.STOCK_ADD)
97 bbox.add(buttonAdd)
98 buttonAdd.connect("clicked", cli.add_command)
99 buttonAdd.set_tooltip_text("Click to add a command to your command list")
100 # Edit button
101 buttonEdit = gtk.Button("Edit")
102 bbox.add(buttonEdit)
103 buttonEdit.connect("clicked", cli.edit_command)
104 buttonEdit.set_tooltip_text("Click to edit a command in your command list")
105 # Delete button
106 buttonDelete = gtk.Button(stock=gtk.STOCK_DELETE)
107 bbox.add(buttonDelete)
108 buttonDelete.connect("clicked", cli.remove_command)
109 buttonDelete.set_tooltip_text("Click to delete a command in your command list")
110 #Help Button
111 buttonHelp = gtk.Button(stock=gtk.STOCK_HELP)
112 bbox.add(buttonHelp)
113 buttonHelp.connect("clicked", cli.man_page)
114 buttonHelp.set_tooltip_text("Click to get help with a command in your command list")
115 # Cancel button
116 buttonCancel = gtk.Button(stock=gtk.STOCK_QUIT)
117 bbox.add(buttonCancel)
118 buttonCancel.connect("clicked", cli.delete_event)
119 buttonCancel.set_tooltip_text("Click to quit CLI Companion")
120
121 return frame
122
123
124 #right-click popup menu for the Liststore(command list)
125 def right_click(self, treeview, event, cli):
126 if event.button == 3:
127 x = int(event.x)
128 y = int(event.y)
129 time = event.time
130 pthinfo = treeview.get_path_at_pos(x, y)
131 if pthinfo is not None:
132 path, col, cellx, celly = pthinfo
133 treeview.grab_focus()
134 treeview.set_cursor( path, col, 0)
135
136 # right-click popup menu Apply(run)
137 popupMenu = gtk.Menu()
138 menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_APPLY)
139 popupMenu.add(menuPopup1)
140 menuPopup1.connect("activate", cli.run_command)
141 # right-click popup menu Edit
142 menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_EDIT)
143 popupMenu.add(menuPopup2)
144 menuPopup2.connect("activate", cli.edit_command)
145 # right-click popup menu Delete
146 menuPopup3 = gtk.ImageMenuItem (gtk.STOCK_DELETE)
147 popupMenu.add(menuPopup3)
148 menuPopup3.connect("activate", cli.remove_command)
149 # right-click popup menu Help
150 menuPopup4 = gtk.ImageMenuItem (gtk.STOCK_HELP)
151 popupMenu.add(menuPopup4)
152 menuPopup4.connect("activate", cli.man_page)
153 # Show popup menu
154 popupMenu.show_all()
155 popupMenu.popup( None, None, None, event.button, time)
156 return True
157
1580
=== removed file 'clicompanion/utils.py'
--- clicompanion/utils.py 2010-10-06 06:54:47 +0000
+++ clicompanion/utils.py 1970-01-01 00:00:00 +0000
@@ -1,66 +0,0 @@
1# -*- mode: python; coding: utf-8; -*-
2#
3# clicompanion.py - commandline tool.
4#
5# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19#
20
21"""
22A collection of useful functions.
23"""
24
25import getpass
26import hashlib
27import os
28
29CHEATSHEET = os.path.expanduser("~/.clicompanion")
30CONFIG_ORIG = "/etc/clicompanion.d/clicompanion.config"
31
32def get_user_shell():
33 """Get the user's shell defined in /etc/passwd ."""
34 data = None
35 try:
36 # Read out the data in /etc/passwd
37 with open('/etc/passwd') as f:
38 data = f.readlines()
39 except e:
40 print "Something unexpected happened!"
41 raise e
42
43 for i in data:
44 tmp = i.split(":")
45 # Check for the entry of the currently logged in user
46 if tmp[0] == getpass.getuser():
47 # Columns are separated by colons, so split each column.
48 # Sample /etc/passwd entry for a user:
49 #
50 # jorge:x:1001:1002:,,,:/home/jorge:/bin/bash
51 #
52 # The last column is relevant for us.
53 # Don't forget to strip the newline at the end of the string!
54 return i.split(":")[-1:][0].strip('\n')
55
56
57def sumfile():
58 '''Returns an md5 hash for an object with read() method.'''
59 m = hashlib.md5()
60 with open(CHEATSHEET, 'rb') as cheatsheet:
61 d = cheatsheet.read()
62 m.update(d)
63 pp = m.hexdigest()
64 print pp
65 return m.hexdigest()
66
670
=== added directory 'clicompanionlib'
=== added file 'clicompanionlib/__init__.py'
--- clicompanionlib/__init__.py 1970-01-01 00:00:00 +0000
+++ clicompanionlib/__init__.py 2010-11-30 16:11:27 +0000
@@ -0,0 +1,23 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# clicompanion.py - commandline tool.
5#
6# Copyright 2010 Duane Hinnen, Kenny Meyer
7#
8# This program is free software: you can redistribute it and/or modify it
9# under the terms of the GNU General Public License version 3, as published
10# by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranties of
14# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20#
21'''
22blah, blah, blah
23'''
024
=== added file 'clicompanionlib/controller.py'
--- clicompanionlib/controller.py 1970-01-01 00:00:00 +0000
+++ clicompanionlib/controller.py 2010-11-30 16:11:27 +0000
@@ -0,0 +1,428 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# clicompanion.py - commandline tool.
5#
6# Copyright 2010 Duane Hinnen, Kenny Meyer
7#
8# This program is free software: you can redistribute it and/or modify it
9# under the terms of the GNU General Public License version 3, as published
10# by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranties of
14# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20# IMPORTANT: you need to move the .cheatsheet file to your $HOME
21#
22
23
24import pygtk
25pygtk.require('2.0')
26import re
27import webbrowser
28
29import os
30# import gtk or print error
31try:
32 import gtk
33except:
34 print >> sys.stderr, "You need to install the python gtk bindings"
35 sys.exit(1)
36
37# TODO: these handle the exception different. Which do we like?
38# import vte or display dialog
39try:
40 import vte
41except:
42 error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
43 'You need to install python bindings for libvte')
44 error.run()
45 sys.exit (1)
46
47from clicompanionlib.utils import get_user_shell
48import view
49
50
51CHEATSHEET = os.path.expanduser("~/.clicompanion2")
52CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
53
54
55class Actions(object):
56 ## Info Dialog Box
57 ## if a command needs more info EX: a package name, a path
58 def get_info(self, widget, liststore):
59
60 row_int = int(view.ROW[0][0])
61
62 ## Create Dialog object
63 dialog = gtk.MessageDialog(
64 None,
65 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
66 gtk.MESSAGE_QUESTION,
67 gtk.BUTTONS_OK,
68 None)
69
70 # Primary text
71 dialog.set_markup(_("This command requires more information"))
72
73 ## create the text input field
74 entry = gtk.Entry()
75 ## allow the user to press enter to do ok
76 entry.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
77
78 ## create a horizontal box to pack the entry and a label
79 hbox = gtk.HBox()
80 hbox.pack_start(gtk.Label(liststore[row_int][1]+":"), False, 5, 5)
81 hbox.pack_end(entry)
82 ## some secondary text
83 dialog.format_secondary_markup(_("Please provide a "+liststore[row_int][1]))
84 ## add it and show it
85 dialog.vbox.pack_end(hbox, True, True, 0)
86 dialog.show_all()
87
88 ## Show the dialog
89 dialog.run()
90
91 ## user text assigned to a variable
92 text = entry.get_text()
93 user_input = text.split(' ')
94
95 ## The destroy method must be called otherwise the 'Close' button will
96 ## not work.
97 dialog.destroy()
98 return user_input
99
100 def responseToDialog(self, text, dialog, response):
101 dialog.response(response)
102
103 ## Add command dialog box
104 def add_command(self, widget, liststore):
105
106 ## Create Dialog object
107 dialog = gtk.MessageDialog(
108 None,
109 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
110 gtk.MESSAGE_QUESTION,
111 gtk.BUTTONS_OK,
112 None)
113
114 ## primaary text
115 dialog.set_markup(_("Add a command to your CLI Companion dictionary"))
116
117 #create the text input field
118 entry1 = gtk.Entry()
119 entry2 = gtk.Entry()
120 entry3 = gtk.Entry()
121 ## allow the user to press enter to do ok
122 entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
123 entry2.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
124 entry3.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
125
126 ## create three labels
127 hbox1 = gtk.HBox()
128 hbox1.pack_start(gtk.Label(_("Command")), False, 5, 5)
129 hbox1.pack_start(entry1, False, 5, 5)
130
131 hbox1.pack_start(gtk.Label(_("User Input")), False, 5, 5)
132 hbox1.pack_start(entry2, False, 5, 5)
133
134 hbox2 = gtk.HBox()
135 hbox2.pack_start(gtk.Label(_("Description")), False, 5, 5)
136 hbox2.pack_start(entry3, True, 5, 5)
137
138 ## cancel button
139 dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
140 ## some secondary text
141 dialog.format_secondary_markup(_("When entering a command, use a ? symbol if user input is required at runtime. Example: ls /any/direstory would be entered as ls ? .For each ? in your command, if any, use the User Input field to provide a hint for each variable. Using our example ls ? you could put directory as the User Input. Lastly provide a brief Description."))
142
143 ## add it and show it
144 dialog.vbox.pack_end(hbox2, True, True, 0)
145 dialog.vbox.pack_end(hbox1, True, True, 0)
146 dialog.show_all()
147 ## Show the dialog
148 result = dialog.run()
149
150 if result == gtk.RESPONSE_OK:
151 ## user text assigned to a variable
152 text1 = entry1.get_text()
153 text2 = entry2.get_text()
154 text3 = entry3.get_text()
155 '''open flat file, add the new command, update CMNDS variable
156 ## update commands in liststore (on screen) '''
157 with open(CHEATSHEET, "a") as cheatfile:
158 if text1 != "":
159 ## write new commands to .clicompanion2 file
160 cheatfile.write(text1+":"+text2+":"+text3+'\n')
161 cheatfile.close()
162 l = str(text1+":"+text2+":"+text3)
163 ls = l.split(':',2)
164 ## update view.CMNDS variable
165 filteredcommandplus = ls[0], ls[1]
166 view.CMNDS.append(filteredcommandplus)
167 ## update the command list on screen
168 liststore.append([ls[0],ls[1],ls[2]])
169
170
171 ## The destroy method must be called otherwise the 'Close' button will
172 ## not work.
173 dialog.destroy()
174 #return text
175
176 ## This the edit function
177 def edit_command(self, widget , liststore):
178
179 row_int = int(view.ROW[0][0])
180
181 row_obj1 = liststore[row_int][0]
182 text1 = "".join(row_obj1)
183
184 row_obj2 = liststore[row_int][1]
185 text2 = "".join(row_obj2)
186
187 row_obj3 = liststore[row_int][2]
188 text3 = "".join(row_obj3)
189
190 ## Create Dialog object
191 dialog = gtk.MessageDialog(
192 None,
193 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
194 gtk.MESSAGE_QUESTION,
195 gtk.BUTTONS_OK,
196 None)
197
198 # primary text
199 dialog.set_markup(_("Edit the command in your clicompanion dictionary"))
200
201 ## create the text input fields
202 entry1 = gtk.Entry()
203 entry1.set_text(text1)
204 entry2 = gtk.Entry()
205 entry2.set_text(text2)
206 entry3 = gtk.Entry()
207 entry3.set_text(text3)
208 ## allow the user to press enter to do ok
209 entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
210
211 ## create three labels
212 hbox1 = gtk.HBox()
213 hbox1.pack_start(gtk.Label(_("Command")), False, 5, 5)
214 hbox1.pack_start(entry1, False, 5, 5)
215
216 hbox1.pack_start(gtk.Label(_("User Input")), False, 5, 5)
217 hbox1.pack_start(entry2, False, 5, 5)
218
219 hbox2 = gtk.HBox()
220 hbox2.pack_start(gtk.Label(_("Description")), False, 5, 5)
221 hbox2.pack_start(entry3, True, 5, 5)
222
223 ## cancel button
224 dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
225 ## some secondary text
226 dialog.format_secondary_markup(_("Please provide a command, description, and what type of user variable, if any, is required."))
227
228 ## add it and show it
229 dialog.vbox.pack_end(hbox2, True, True, 0)
230 dialog.vbox.pack_end(hbox1, True, True, 0)
231 dialog.show_all()
232 ## Show the dialog
233 result = dialog.run()
234
235 if result == gtk.RESPONSE_OK:
236 ## user text assigned to a variable
237 text1 = entry1.get_text()
238 text2 = entry2.get_text()
239 text3 = entry3.get_text()
240
241 if text1 != "":
242 self.remove_command(widget, liststore)
243 '''open flat file, add the new command, update CMNDS variable
244 ## update commands in liststore (on screen) '''
245 with open(CHEATSHEET, "a") as cheatfile:
246 ## write new commands to .clicompanion2 file
247 cheatfile.write(text1+":"+text2+":"+text3+'\n')
248 cheatfile.close()
249 l = str(text1+":"+text2+":"+text3)
250 ls = l.split(':',2)
251 ## update view.CMNDS variable
252 filteredcommandplus = ls[0], ls[1]
253 view.CMNDS.append(filteredcommandplus)
254 ## update the command list on screen
255 liststore.append([ls[0],ls[1],ls[2]])
256
257 ## The destroy method must be called otherwise the 'Close' button will
258 ## not work.
259 dialog.destroy()
260
261
262 ## Remove command from command file and GUI
263 def remove_command(self, widget, liststore):
264
265 row_int = int(view.ROW[0][0]) #convert pathlist into something usable
266 del view.CMNDS[row_int]
267 del liststore[row_int]
268
269 ## open command file and delete line so the change is persistent
270 with open(CHEATSHEET, "r") as cheatfile:
271 cheatlines = cheatfile.readlines()
272 del cheatlines[row_int]
273 cheatfile.close()
274 with open(CHEATSHEET, "w") as cheatfile2:
275 cheatfile2.writelines(cheatlines)
276 cheatfile2.close()
277
278
279 def _filter_commands(self, widget, liststore, treeview):
280 """
281 Show commands matching a given search term.
282 The user should enter a term in the search box and the treeview should
283 only display the rows which contain the search term.
284 Pretty straight-forward.
285 """
286 search_term = widget.get_text()
287
288 ## Create a TreeModelFilter object which provides auxiliary functions for
289 ## filtering data.
290 ## http://www.pygtk.org/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html
291 modelfilter = liststore.filter_new()
292 def search(modelfilter, iter, search_term):
293 try:
294 ## Iterate through every column and row and check if the search
295 ## term is there:
296 if search_term in modelfilter.get_value(iter, 0) or \
297 search_term in modelfilter.get_value(iter, 1) or \
298 search_term in modelfilter.get_value(iter, 2):
299 return True
300
301 except TypeError:
302 ## Python raises a TypeError if row data doesn't exist. Catch
303 ## that and fail silently.
304 pass
305
306 modelfilter.set_visible_func(search, search_term)
307 treeview.set_model(modelfilter)
308
309
310 #clear CMNDS list then populate it with the filteredlist of commands
311 view.CMNDS = []
312 for line in modelfilter:
313 linelist = line
314 filteredcommandplus = linelist[0], linelist[1]
315 view.CMNDS.append(filteredcommandplus)
316
317
318
319 ## send the command to the terminal
320 def run_command(self, widget, notebook, liststore):
321 text = ""
322 row_int = int(view.ROW[0][0]) ## removes everything but number from [5,]
323
324 ## get the current notebook page so the function knows which terminal to run the command in.
325 pagenum = notebook.get_current_page()
326 widget = notebook.get_nth_page(pagenum)
327 page_widget = widget.get_child()
328 ## view.CMNDS is where commands are stored
329 cmnd = view.CMNDS[row_int][0]
330
331 ## find how many ?(user arguments) are in command
332 match = re.findall('\?', cmnd)
333 '''
334 Make sure user arguments were found. Replace ? with something
335 .format can read. This is done so the user can just enter ?, when
336 adding a command where arguments are needed, instead
337 of {0[1]}, {0[1]}, {0[2]}
338 '''
339 if match == False:
340 pass
341 else:
342 num = len(match)
343 ran = 0
344 new_cmnd = self.replace(cmnd, num, ran)
345
346
347 if not view.CMNDS[row_int][1] == "": # command with user input
348 text = self.get_info(self, liststore)
349 c = new_cmnd.format(text)
350 page_widget.feed_child(c+"\n") #send command w/ input
351 page_widget.show()
352 page_widget.grab_focus()
353 else: ## command that has no user input
354 page_widget.feed_child(cmnd+"\n") #send command
355 page_widget.show()
356 page_widget.grab_focus()
357
358 ## replace ? with {0[n]}
359 def replace(self, cmnd, num, ran):
360 replace_cmnd=re.sub('\?', '{0['+str(ran)+']}', cmnd, count=1)
361 cmnd = replace_cmnd
362 ran += 1
363 if ran < num:
364 return self.replace(cmnd, num, ran)
365 else:
366 pass
367 return cmnd
368
369 ## open the man page for selected command
370 def man_page(self, widget, notebook):
371 row_int = int(view.ROW[0][0]) # removes everything but number from EX: [5,]
372 cmnd = view.CMNDS[row_int][0] #CMNDS is where commands are store
373 splitcommand = self._filter_sudo_from(cmnd.split(" "))
374 ## get current notebook tab to use in function
375 pagenum = notebook.get_current_page()
376 widget = notebook.get_nth_page(pagenum)
377 page_widget = widget.get_child()
378 #send command to Terminal
379 page_widget.feed_child("man "+splitcommand[0]+"| most \n")
380 page_widget.grab_focus()
381 page_widget.show()
382
383
384 @staticmethod
385 def _filter_sudo_from(command):
386 """Filter the sudo from `command`, where `command` is a list.
387 Return the command list with the "sudo" filtered out.
388 """
389 if command[0].startswith("sudo"):
390 del command[0]
391 return command
392 return command
393
394
395
396 #TODO: Move to menus_buttons
397 def copy_paste(self, vte, event, data=None):
398 if event.button == 3:
399
400 time = event.time
401 ## right-click popup menu Copy
402 popupMenu = gtk.Menu()
403 menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_COPY)
404 popupMenu.add(menuPopup1)
405 menuPopup1.connect('activate', lambda x: vte.copy_clipboard())
406 ## right-click popup menu Paste
407 menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_PASTE)
408 popupMenu.add(menuPopup2)
409 menuPopup2.connect('activate', lambda x: vte.paste_clipboard())
410
411 ## Show popup menu
412 popupMenu.show_all()
413 popupMenu.popup( None, None, None, event.button, time)
414 return True
415 else:
416 pass
417
418 ## close the window and quit
419 def delete_event(self, widget, data=None):
420 gtk.main_quit()
421 return False
422
423 def about_event(self, widget, data=None):
424 pass
425 def help_event(self, widget, data=None):
426 webbrowser.open("http://okiebuntu.homelinux.com/okwiki/clicompanion")
427
428
0429
=== added file 'clicompanionlib/menus_buttons.py'
--- clicompanionlib/menus_buttons.py 1970-01-01 00:00:00 +0000
+++ clicompanionlib/menus_buttons.py 2010-11-30 16:11:27 +0000
@@ -0,0 +1,175 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
5#
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17#
18#
19#
20# This file contains the menus, buttons, and right clicks
21#
22
23import gtk
24import clicompanionlib.tabs
25
26
27class FileMenu(object):
28
29 def the_menu(self, actions, notebook, liststore):
30 menu = gtk.Menu()
31 root_menu = gtk.MenuItem(_("File"))
32 root_menu.set_submenu(menu)
33
34 menu2 = gtk.Menu()
35 root_menu2 = gtk.MenuItem(_("Help"))
36 root_menu2.set_submenu(menu2)
37
38 ##FILE MENU ##
39 ## Make 'Run' menu entry
40 menu_item1 = gtk.MenuItem(_("Run Command"))
41 menu.append(menu_item1)
42 menu_item1.connect("activate", actions.run_command, notebook, liststore)
43 menu_item1.show()
44
45 ## Make 'Add' file menu entry
46 menu_item2 = gtk.MenuItem(_("Add Command"))
47 menu.append(menu_item2)
48 menu_item2.connect("activate", actions.add_command, liststore)
49 menu_item2.show()
50
51 ## Make 'Remove' file menu entry
52 menu_item2 = gtk.MenuItem(_("Remove Command"))
53 menu.append(menu_item2)
54 menu_item2.connect("activate", actions.remove_command, liststore)
55 menu_item2.show()
56
57 ## Make 'Add Tab' file menu entry
58 tabs = clicompanionlib.tabs.Tabs()
59 menu_item4 = gtk.MenuItem(_("Add Tab"))
60 menu.append(menu_item4)
61 menu_item4.connect("activate", tabs.add_tab, notebook)
62 menu_item4.show()
63
64 ## Make 'Quit' file menu entry
65 menu_item3 = gtk.MenuItem(_("Quit"))
66 menu.append(menu_item3)
67 menu_item3.connect("activate", actions.delete_event)
68 menu_item3.show()
69
70
71 ## HELP MENU ##
72 ## Make 'About' file menu entry
73 menu_item11 = gtk.MenuItem(_("About"))
74 menu2.append(menu_item11)
75 menu_item11.connect("activate", actions.about_event)
76 menu_item11.show()
77
78
79 ## Make 'Help' file menu entry
80 menu_item22 = gtk.MenuItem(_("Help"))
81 menu2.append(menu_item22)
82 menu_item22.connect("activate", actions.help_event)
83 menu_item22.show()
84
85
86 menu_bar = gtk.MenuBar()
87
88 menu_bar.append (root_menu) ##Menu bar(file)
89 menu_bar.append (root_menu2) ##Menu bar(help)
90 #menu_bar.show() ##show File Menu # Menu Bar
91 ##Show 'File' Menu
92 #root_menu.show()
93 return menu_bar
94
95
96
97 def buttons(self, actions, spacing, layout, notebook, liststore):
98 #button box at bottom of main window
99 frame = gtk.Frame()
100 bbox = gtk.HButtonBox()
101 bbox.set_border_width(5)
102 frame.add(bbox)
103
104 # Set the appearance of the Button Box
105 bbox.set_layout(layout)
106 bbox.set_spacing(spacing)
107 # Run button
108 buttonRun = gtk.Button(_("Run"))
109 bbox.add(buttonRun)
110 buttonRun.connect("clicked", actions.run_command, notebook, liststore)
111 buttonRun.set_tooltip_text(_("Click to run a highlighted command"))
112 # Add button
113 buttonAdd = gtk.Button(stock=gtk.STOCK_ADD)
114 bbox.add(buttonAdd)
115 buttonAdd.connect("clicked", actions.add_command, liststore)
116 buttonAdd.set_tooltip_text(_("Click to add a command to your command list"))
117 # Edit button
118 buttonEdit = gtk.Button("Edit")
119 bbox.add(buttonEdit)
120 buttonEdit.connect("clicked", actions.edit_command, liststore)
121 buttonEdit.set_tooltip_text(_("Click to edit a command in your command list"))
122 # Delete button
123 buttonDelete = gtk.Button(stock=gtk.STOCK_DELETE)
124 bbox.add(buttonDelete)
125 buttonDelete.connect("clicked", actions.remove_command, liststore)
126 buttonDelete.set_tooltip_text(_("Click to delete a command in your command list"))
127 #Help Button
128 buttonHelp = gtk.Button(stock=gtk.STOCK_HELP)
129 bbox.add(buttonHelp)
130 buttonHelp.connect("clicked", actions.man_page, notebook)
131 buttonHelp.set_tooltip_text(_("Click to get help with a command in your command list"))
132 # Cancel button
133 buttonCancel = gtk.Button(stock=gtk.STOCK_QUIT)
134 bbox.add(buttonCancel)
135 buttonCancel.connect("clicked", actions.delete_event)
136 buttonCancel.set_tooltip_text(_("Click to quit CLI Companion"))
137
138 return frame
139
140
141 #right-click popup menu for the Liststore(command list)
142 def right_click(self, widget, event, actions, treeview, notebook, liststore):
143 if event.button == 3:
144 x = int(event.x)
145 y = int(event.y)
146 time = event.time
147 pthinfo = treeview.get_path_at_pos(x, y)
148 if pthinfo is not None:
149 path, col, cellx, celly = pthinfo
150 treeview.grab_focus()
151 treeview.set_cursor( path, col, 0)
152
153 # right-click popup menu Apply(run)
154 popupMenu = gtk.Menu()
155 menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_APPLY)
156 popupMenu.add(menuPopup1)
157 menuPopup1.connect("activate", actions.run_command, notebook, liststore)
158 # right-click popup menu Edit
159 menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_EDIT)
160 popupMenu.add(menuPopup2)
161 menuPopup2.connect("activate", actions.edit_command, liststore)
162 # right-click popup menu Delete
163 menuPopup3 = gtk.ImageMenuItem (gtk.STOCK_DELETE)
164 popupMenu.add(menuPopup3)
165 menuPopup3.connect("activate", actions.remove_command, liststore)
166 # right-click popup menu Help
167 menuPopup4 = gtk.ImageMenuItem (gtk.STOCK_HELP)
168 popupMenu.add(menuPopup4)
169 menuPopup4.connect("activate", actions.man_page, notebook)
170 # Show popup menu
171 popupMenu.show_all()
172 popupMenu.popup( None, None, None, event.button, time)
173 return True
174
175
0176
=== added file 'clicompanionlib/tabs.py'
--- clicompanionlib/tabs.py 1970-01-01 00:00:00 +0000
+++ clicompanionlib/tabs.py 2010-11-30 16:11:27 +0000
@@ -0,0 +1,81 @@
1#!/usr/bin/env python
2#
3# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17#
18#
19
20import pygtk
21pygtk.require('2.0')
22import gtk
23import vte
24
25from clicompanionlib.utils import get_user_shell
26import clicompanionlib.controller
27
28class Tabs(object):
29
30
31
32 ## add a new terminal in a tab above the current terminal
33 def add_tab(self,widget, notebook):
34
35 _vte = vte.Terminal()
36 _vte.set_size_request(700, 220)
37 _vte.connect ("child-exited", lambda term: gtk.main_quit())
38 _vte.fork_command(get_user_shell()) # Get the user's default shell
39
40 vte_tab = gtk.ScrolledWindow()
41 vte_tab.add(_vte)
42 #notebook.set_show_tabs(True)
43 #notebook.set_show_border(True)
44
45 gcp = notebook.get_current_page() +1
46 pagenum = ('Tab %d') % gcp
47
48 box = gtk.HBox()
49 label = gtk.Label(pagenum)
50 box.pack_start(label, True, True)
51
52 ## x image for tab close button
53 close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
54 ## close button
55 closebtn = gtk.Button()
56 closebtn.set_relief(gtk.RELIEF_NONE)
57 closebtn.set_focus_on_click(True)
58
59 closebtn.add(close_image)
60 ## put button in a box and show box
61 box.pack_end(closebtn, False, False)
62 box.show_all()
63
64 notebook.prepend_page(vte_tab, box) # add tab
65 notebook.set_scrollable(True)
66 actions = clicompanionlib.controller.Actions()
67 _vte.connect ("button_press_event", actions.copy_paste, None)
68 vte_tab.grab_focus()
69 # signal handler for tab
70 closebtn.connect("clicked", self.close_tab, vte_tab, notebook)
71 vte_tab.show_all()
72
73 return vte_tab
74
75
76 ## Remove a page from the notebook
77 def close_tab(self, sender, widget, notebook):
78 ## get the page number of the tab we wanted to close
79 pagenum = notebook.page_num(widget)
80 ## and close it
81 notebook.remove_page(pagenum)
082
=== added file 'clicompanionlib/utils.py'
--- clicompanionlib/utils.py 1970-01-01 00:00:00 +0000
+++ clicompanionlib/utils.py 2010-11-30 16:11:27 +0000
@@ -0,0 +1,56 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# clicompanion.py - commandline tool.
5#
6# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
7#
8# This program is free software: you can redistribute it and/or modify it
9# under the terms of the GNU General Public License version 3, as published
10# by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranties of
14# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20#
21
22"""
23A collection of useful functions.
24"""
25
26import getpass
27import os
28
29CHEATSHEET = os.path.expanduser("~/.clicompanion2")
30#CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
31
32#TODO: Move this to controller.py
33def get_user_shell():
34 """Get the user's shell defined in /etc/passwd ."""
35 data = None
36 try:
37 # Read out the data in /etc/passwd
38 with open('/etc/passwd') as f:
39 data = f.readlines()
40 except e:
41 print "Something unexpected happened!"
42 raise e
43
44 for i in data:
45 tmp = i.split(":")
46 # Check for the entry of the currently logged in user
47 if tmp[0] == getpass.getuser():
48 # Columns are separated by colons, so split each column.
49 # Sample /etc/passwd entry for a user:
50 #
51 # jorge:x:1001:1002:,,,:/home/jorge:/bin/bash
52 #
53 # The last column is relevant for us.
54 # Don't forget to strip the newline at the end of the string!
55 return i.split(":")[-1:][0].strip('\n')
56
057
=== added file 'clicompanionlib/view.py'
--- clicompanionlib/view.py 1970-01-01 00:00:00 +0000
+++ clicompanionlib/view.py 2010-11-30 16:11:27 +0000
@@ -0,0 +1,279 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# clicompanion.py - commandline tool.
5#
6# Copyright 2010 Duane Hinnen, Kenny Meyer
7#
8# This program is free software: you can redistribute it and/or modify it
9# under the terms of the GNU General Public License version 3, as published
10# by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful, but
13# WITHOUT ANY WARRANTY; without even the implied warranties of
14# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15# PURPOSE. See the GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20#
21#
22
23import pygtk
24pygtk.require('2.0')
25import os
26
27# import gtk or print error
28try:
29 import gtk
30except:
31 print >> sys.stderr, "You need to install the python gtk bindings"
32 sys.exit(1)
33
34# TODO: these handle the exception different. Which do we like?
35# import vte or display dialog
36try:
37 import vte
38except:
39 error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
40 'You need to install python bindings for libvte')
41 error.run()
42 sys.exit (1)
43
44import clicompanionlib.menus_buttons
45import clicompanionlib.controller
46from clicompanionlib.utils import get_user_shell
47import clicompanionlib.tabs
48
49
50CHEATSHEET = os.path.expanduser("~/.clicompanion2")
51CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
52CMNDS = [] ## will hold the commands. Actually the first two columns
53ROW = '1' ## holds the currently selected row
54
55
56
57class MainWindow():
58
59 ## open file containing command dictionary and put it in a variable
60 def update(self, liststore):
61 try:
62 with open(CHEATSHEET, "r") as cheatfile:
63 bugdata=cheatfile.read()
64 cheatfile.close()
65 except IOError:
66 ## CHEATSHEET is not there. Oh, no!
67 ## So, run self.setup() again.
68 self.setup()
69 ## Then, run me again.
70 self.update(liststore)
71
72 ## add bug data from .clicompanion --> bugdata --> to the liststore
73 for line in bugdata.splitlines():
74 l = line.split(':',2)
75 commandplus = l[0], l[1]
76 CMNDS.append(commandplus)
77 liststore.append([l[0],l[1],l[2]])
78
79
80 #copy config file to user $HOME if does not exist
81 def setup(self):
82 """
83 Check if ~/.clicompanion2 exists. If not check for original
84 installed in /etc/clicompanion.d/. If origianl exists copy to $HOME.
85 if not create a new, blank ~/.clicompanion2 so program will not crash
86 """
87
88 if not os.path.exists(CHEATSHEET):
89 if os.path.exists(CONFIG_ORIG):
90 os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
91 else:
92 # Oops! Looks like there's no cheatsheet in CHEATSHEET.
93 # Then, create an empty cheatsheet.
94 open(CHEATSHEET, 'w').close()
95
96
97 #liststore in a scrolled window in an expander
98 def expanded_cb(self, expander, params, notebook, treeview, liststore):
99 if expander.get_expanded():
100
101
102 # Activate the search box when expanded
103 self.search_box.set_sensitive(True)
104 else:
105 # De-activate the search box when not expanded
106 self.search_box.set_sensitive(False)
107 expander.set_expanded(False)
108 #expander.remove(expander.child)
109 ##reset the size of the window to its original one
110 self.window.resize(1, 1)
111 return
112
113
114 # close the window and quit
115 def delete_event(self, widget, data=None):
116 gtk.main_quit()
117 return False
118
119 def __init__(self):
120
121 ##For now TERM is hardcoded to xterm because of a change
122 ##in libvte in Ubuntu Maverick
123 os.putenv('TERM', 'xterm')
124 ## copy config file to user $HOME if does not exist
125 self.setup()
126
127 #TODO: do we want to do this? Or just keep the height under 600.
128 ##Get user screen size##
129 #screen = gtk.gdk.display_get_default().get_default_screen()
130 #screen_size = screen.get_monitor_geometry(0)
131 #height = screen.get_height() ## screen height ##
132
133 ## Create UI widgets
134 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
135 liststore = gtk.ListStore(str, str, str)
136 treeview = gtk.TreeView()
137 expander = gtk.Expander()
138 self.scrolledwindow = gtk.ScrolledWindow()
139 notebook = gtk.Notebook()
140
141 ## set sizes and borders
142 self.scrolledwindow.set_size_request(700, 220)
143 self.window.set_default_size(700, 625)
144 self.window.set_border_width(10)
145 ## Sets the position of the window relative to the screen
146 self.window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
147 ## Allow user to resize window
148 self.window.set_resizable(True)
149
150 ## set Window title and icon
151 self.window.set_title("CLI Companion")
152 icon = gtk.gdk.pixbuf_new_from_file("/usr/share/pixmaps/clicompanion.16.png")
153 self.window.set_icon(icon)
154
155 # get commands and put in liststore
156 self.update(liststore)
157 ## create the TreeViewColumns to display the data
158 treeview.columns = [None]*3
159 treeview.columns[0] = gtk.TreeViewColumn(_('Command'))
160 treeview.columns[1] = gtk.TreeViewColumn(_('User Input'))
161 treeview.columns[2] = gtk.TreeViewColumn(_('Description'))
162
163 for n in range(3):
164 ## add columns to treeview
165 treeview.append_column(treeview.columns[n])
166 ## create a CellRenderers to render the data
167 treeview.columns[n].cell = gtk.CellRendererText()
168 ## add the cells to the columns
169 treeview.columns[n].pack_start(treeview.columns[n].cell,
170 True)
171 ## set the cell attributes to the appropriate liststore column
172 treeview.columns[n].set_attributes(
173 treeview.columns[n].cell, text=n)
174 treeview.columns[n].set_resizable(True)
175
176 #set treeview model and put treeview in the scrolled window and the scrolled window in the expander.
177 treeview.set_model(liststore)
178 self.scrolledwindow.add(treeview)
179 expander.add(self.scrolledwindow)
180 #self.window.show_all()
181
182 ## instantiate tabs
183 tabs = clicompanionlib.tabs.Tabs()
184 ## instantiate controller.Actions, where all the button actions are
185 actions = clicompanionlib.controller.Actions()
186 ## instantiate 'File' and 'Help' Drop Down Menu [menus_buttons.py]
187 bar = clicompanionlib.menus_buttons.FileMenu()
188 menu_bar = bar.the_menu(actions, notebook, liststore)
189
190
191 #get row of selection
192 def mark_selected(self, treeselection):
193 global ROW
194 (model, pathlist)=treeselection.get_selected_rows()
195 ROW = pathlist
196
197
198 selection = treeview.get_selection()
199 selection.set_mode(gtk.SELECTION_SINGLE)
200 selection.select_path(0)
201 selection.connect("changed", mark_selected, selection)
202
203
204 ## The search section
205 self.search_label = gtk.Label(_("Search:"))
206 self.search_label.set_alignment(xalign=-1, yalign=0)
207 self.search_box = gtk.Entry()
208 self.search_box.connect("changed", actions._filter_commands, liststore, treeview)
209 ## search box tooltip
210 self.search_box.set_tooltip_text(_("Search your list of commands"))
211 # Set the search box sensitive at program start, because expander is not
212 # unfolded by default
213 self.search_box.set_sensitive(False)
214 ## hbox for menu and search Entry
215 menu_search_hbox = gtk.HBox(False)
216 menu_search_hbox.pack_end(self.search_box, True)
217 menu_search_hbox.pack_end(self.search_label, False, False, 10)
218 menu_search_hbox.pack_start(menu_bar, True)
219
220
221 ## expander title
222 expander_hbox = gtk.HBox()
223 image = gtk.Image()
224 image.set_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
225 label = gtk.Label(_('Command List'))
226 ## tooltip for the label of the expander
227 expander_hbox.set_tooltip_text(_("Click to show/hide command list"))
228
229 ## add expander widget to hbox
230 expander_hbox.pack_start(image, False, False)
231 expander_hbox.pack_start(label, True, False)
232 expander.set_label_widget(expander_hbox)
233
234 ## Add the first tab with the Terminal
235 tabs.add_tab(self, notebook)
236 notebook.set_tab_pos(1)
237
238 ## The "Add Tab" tab
239 add_tab_button = gtk.Button("+")
240 ## tooltip for "Add Tab" tab
241 add_tab_button.set_tooltip_text(_("Click to add another Tab"))
242 ## create first tab
243 notebook.append_page(gtk.Label(""), add_tab_button)
244
245 ## buttons at bottom of main window [menus_buttons.py]
246 button_box = bar.buttons(actions, 10, gtk.BUTTONBOX_END, notebook, liststore)
247
248 ## vbox for search, notebook, buttonbar
249 self.vbox = gtk.VBox()
250 self.window.add(self.vbox)
251 ## pack everytyhing in the vbox
252 #self.vbox.pack_start(menu_bar, False, False, 0) ##menuBar
253 self.vbox.pack_start(menu_search_hbox, False, False, 5)
254 self.vbox.pack_start(expander, False, False, 5)
255 self.vbox.pack_start(notebook, True, True, 10)
256 self.vbox.pack_start(button_box, False, False, 5)
257
258 ## signals
259 expander.connect('notify::expanded', self.expanded_cb, notebook, treeview, liststore)
260 self.window.connect("delete_event", self.delete_event)
261 add_tab_button.connect("clicked", tabs.add_tab, notebook)
262 ## right click menu event capture
263 treeview.connect ("button_press_event", bar.right_click, actions, treeview, notebook, liststore)
264
265
266 #self.vte.grab_focus()
267 self.window.show_all()
268 return
269
270 def main(self):
271 try:
272 gtk.main()
273 except KeyboardInterrupt:
274 pass
275
276def run():
277
278 main_window = MainWindow()
279 main_window.main()
0280
=== added directory 'data'
=== added file 'data/clicompanion.16.png'
1Binary files data/clicompanion.16.png 1970-01-01 00:00:00 +0000 and data/clicompanion.16.png 2010-11-30 16:11:27 +0000 differ281Binary files data/clicompanion.16.png 1970-01-01 00:00:00 +0000 and data/clicompanion.16.png 2010-11-30 16:11:27 +0000 differ
=== added file 'data/clicompanion.64.png'
2Binary files data/clicompanion.64.png 1970-01-01 00:00:00 +0000 and data/clicompanion.64.png 2010-11-30 16:11:27 +0000 differ282Binary files data/clicompanion.64.png 1970-01-01 00:00:00 +0000 and data/clicompanion.64.png 2010-11-30 16:11:27 +0000 differ
=== added file 'data/clicompanion.desktop'
--- data/clicompanion.desktop 1970-01-01 00:00:00 +0000
+++ data/clicompanion.desktop 2010-11-30 16:11:27 +0000
@@ -0,0 +1,7 @@
1[Desktop Entry]
2Name=CLI Companion
3Comment=Run and store terminal commands from a GUI
4Categories=Utility;GTK;
5Exec=clicompanion
6Icon=clicompanion
7Type=Application
08
=== added file 'data/clicompanion2.config'
--- data/clicompanion2.config 1970-01-01 00:00:00 +0000
+++ data/clicompanion2.config 2010-11-30 16:11:27 +0000
@@ -0,0 +1,48 @@
1dpkg -l ?:package:Find version of a package
2df -h::file system disk space usage
3free -m::show RAM usage
4ps auxww | grep ?:process:displays information about the active process
5iwconfig::Display wireless network information
6ifconfig -a::displays the status of the currently active interfaces
7sudo iwlist::scan Scan Wireless networks
8sudo /etc/init.d/networking restart::Reset the Network
9lsb_release -a::What version of Ubuntu do I have?
10uname -a::What kernel am I running
11sudo apt-get update && sudo apt-get upgrade::Refresh update info and update all packages
12sudo apt-get clean::clear out all packages in /var/cache/apt/archives
13sudo apt-get autoclean::clear out obsolete packages(packages with a newer release)
14apt-cache search ?:package:Find information on a package (not installed)
15sudo lshw::List hardware
16lspci::list all PCI devices
17aplay -l::List all soundcards and digital audio devices
18cat ?:path:Read File & Print to Standard Output
19ls ? :path:List Folders Contents
20ls -lSr ?:path:Show files by size, biggest last
21mv ?:path:Move (Rename) Files
22cp ?:path:Copy Files
23sudo lspci::attached PCI devices
24chmod ? ?:permissions, file:Change access permissions, change mode
25chown ? ?:owner,group, file:Change the owner and/or group of each given file
26dmesg::Print kernel & driver messages
27history::Command History
28locate ?:file:Find files (updatedb to update DB)
29sudo updatedb::update the database for locate
30which ?:command:Show full path name of command
31find -maxdepth 1 -type f | xargs grep -F ?:string:Search all regular files for 'string' in this dir
32gpg -c ?:file:Encypt a file
33gpg ?:file.gpg:Decrypt a file
34tar -xjf ?:archive.tar:Extract all files from archive.tar
35tar -czf ?:Destination.tar.gz Source:Create Destination from Source
36iostat::cpu and I/O statistics
37netstat::Print network connections and interface statistics
38sudo fdisk -l ?:disk:List partition tables for specified devices
39sudo ufw enable::Enable netfilter firewall
40sudo ufw allow ?:port:Open a port in netfilter firewall
41sudo ufw deny ?:port:Close a port in netfilter firewall
42sudo ufw disable::Disable netfilter firewall
43cat ? ? | sort | uniq > ? :file1, file2, file3:combine, sort and remove duplicates from 2 files
44mkisofs -V LABEL -r dir | gzip > ?:isoname.iso.gz:Create cdrom image(iso) from contents of directory(pwd)
45cdrecord -v dev=/dev/cdrom -audio -pad *.wav::Make audio CD from all wavs in current dir(pwd)
46dpkg-query -W -f='${Installed-Size;10}\t${Package}\n' | sort -k1,1n::List all installed packages by size
47tail -f /var/log/messages::Monitor messages log file
48apropos ?:command or package:search the manual page names and descriptions
049
=== added file 'setup.py'
--- setup.py 1970-01-01 00:00:00 +0000
+++ setup.py 2010-11-30 16:11:27 +0000
@@ -0,0 +1,42 @@
1#!/usr/bin/env python
2#
3# Copyright 2010 Duane Hinnen
4#
5#
6# This program is free software: you can redistribute it and/or modify it
7# under the terms of the GNU General Public License version 3, as published
8# by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful, but
11# WITHOUT ANY WARRANTY; without even the implied warranties of
12# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13# PURPOSE. See the GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License along
16# with this program. If not, see <http://www.gnu.org/licenses/>.
17#
18#
19
20import glob
21from distutils.core import setup
22from DistUtilsExtra.command import *
23
24
25
26setup( name='clicompanion',
27 version='0.1.0',
28 description='Run Terminal commands from a GUI. Store commands for later use.',
29 author='Duane Hinnen',
30 author_email='duanedesign@gmail.com',
31 scripts=['clicompanion'],
32 packages=['clicompanionlib'],
33 data_files=[('/etc/clicompanion.d/', ['data/clicompanion2.config']),
34 ('/usr/share/pixmaps', ['data/clicompanion.16.png']),
35 ('/usr/share/applications', ['data/clicompanion.desktop']),
36 ('share/clicompanion/locale/', glob.glob('locale/*/LC_MESSAGES/*.mo')),
37 ],
38
39 cmdclass = { 'build' : build_extra.build_extra,
40 'build_i18n' : build_i18n.build_i18n,
41 },
42 )

Subscribers

People subscribed via source and target branches