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
1=== removed file 'CLIcompanion.16.png'
2Binary files CLIcompanion.16.png 2010-10-06 06:54:47 +0000 and CLIcompanion.16.png 1970-01-01 00:00:00 +0000 differ
3=== added file 'MANIFEST'
4--- MANIFEST 1970-01-01 00:00:00 +0000
5+++ MANIFEST 2010-11-30 16:11:27 +0000
6@@ -0,0 +1,12 @@
7+setup.py
8+clicompanion
9+clicompanionlib/__init__.py
10+clicompanionlib/controller.py
11+clicompanionlib/menus_buttons.py
12+clicompanionlib/tabs.py
13+clicompanionlib/utils.py
14+clicompanionlib/view.py
15+data/ubuntuone-indicator.desktop
16+data/clicompanion.config
17+data/clicompanion.16.png
18+data/clicompanion.64.png
19
20=== added file 'clicompanion'
21--- clicompanion 1970-01-01 00:00:00 +0000
22+++ clicompanion 2010-11-30 16:11:27 +0000
23@@ -0,0 +1,37 @@
24+#! /usr/bin/env python
25+
26+import locale
27+import gettext
28+import os
29+
30+from clicompanionlib.view import run
31+
32+
33+BASEDIR = '/usr/share/clicompanion/'
34+
35+def get_language():
36+ """Return the language to be used by the system.
37+
38+ If it finds the system language in the translated files, it
39+ returns it, otherwise it just returns None.
40+ """
41+ loc = locale.setlocale(locale.LC_ALL, "")
42+ loc = loc[:2]
43+ traducidos = os.listdir(locale_dir)
44+ if loc in traducidos:
45+ return loc
46+ return
47+
48+locale_dir = os.path.join(BASEDIR, "locale")
49+gettext.install('clicompanion', locale_dir, unicode=True)
50+idioma = get_language()
51+if idioma is not None:
52+ mo = os.path.join(locale_dir, '%s/LC_MESSAGES/clicompanion.mo' % idioma)
53+ if not os.access(mo, os.F_OK):
54+ raise IOError("The l10n directory (for language %r) exists but "
55+ "not the clicompanion.mo file" % idioma)
56+ trans = gettext.translation('clicompanion', locale_dir, languages=[idioma])
57+ trans.install(unicode=True)
58+
59+if __name__ == "__main__":
60+ run()
61
62=== removed directory 'clicompanion'
63=== removed file 'clicompanion.py'
64--- clicompanion.py 2010-10-06 06:47:50 +0000
65+++ clicompanion.py 1970-01-01 00:00:00 +0000
66@@ -1,723 +0,0 @@
67-#!/usr/bin/env python
68-# -*- coding: utf-8 -*-
69-#
70-# clicompanion.py - commandline tool.
71-#
72-# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
73-#
74-# This program is free software: you can redistribute it and/or modify it
75-# under the terms of the GNU General Public License version 3, as published
76-# by the Free Software Foundation.
77-#
78-# This program is distributed in the hope that it will be useful, but
79-# WITHOUT ANY WARRANTY; without even the implied warranties of
80-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
81-# PURPOSE. See the GNU General Public License for more details.
82-#
83-# You should have received a copy of the GNU General Public License along
84-# with this program. If not, see <http://www.gnu.org/licenses/>.
85-#
86-#pdb debugger
87-#import pdb; pdb.set_trace()
88-#
89-
90-
91-import re
92-import sys
93-import pygtk
94-pygtk.require('2.0')
95-
96-import os
97-import os.path
98-
99-## Starting with the i18n ###
100-import locale
101-import gettext
102-
103-BASEDIR = '/usr/share/clicompanion/'
104-
105-def get_language():
106- """Return the language to be used by the system.
107-
108- If it finds the system language in the translated files, it
109- returns it, otherwise it just returns None.
110- """
111- loc = locale.setlocale(locale.LC_ALL, "")
112- loc = loc[:2]
113- traducidos = os.listdir(locale_dir)
114- if loc in traducidos:
115- return loc
116- return
117-
118-locale_dir = os.path.join(BASEDIR, "locale")
119-gettext.install('clicompanion', locale_dir, unicode=True)
120-idioma = get_language()
121-if idioma is not None:
122- mo = os.path.join(locale_dir, '%s/LC_MESSAGES/clicompanion.mo' % idioma)
123- if not os.access(mo, os.F_OK):
124- raise IOError("The l10n directory (for language %r) exists but "
125- "not the clicompanion.mo file" % idioma)
126- trans = gettext.translation('clicompanion', locale_dir, languages=[idioma])
127- trans.install(unicode=True)
128-## End with i18n ###
129-
130-## import gtk or print error
131-try:
132- import gtk
133-except:
134- error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
135- _("You need to install the python gtk bindings"))
136- error.run()
137- sys.exit (1)
138-
139-## import vte or display message dialog
140-try:
141- import vte
142-except:
143- error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
144- _('You need to install python bindings for libvte'))
145- error.run()
146- sys.exit (1)
147-
148-import clicompanion.menus_buttons
149-from clicompanion.utils import get_user_shell, sumfile
150-
151-
152-#TODO: Get rid of global commands CMNDS and ROW
153-CMNDS = []
154-ROW = ''
155-CHEATSHEET = os.path.expanduser("~/.clicompanion")
156-CHEATSHEETBAK = os.path.expanduser("~/.clicompanion.bak")
157-CONFIG_ORIG = "/etc/clicompanion.d/clicompanion.config"
158-
159-
160-class Companion(object):
161- '''
162- All the actions the program can do.
163- '''
164- ## copy config file to user $HOME if does not exist
165- def setup(self):
166- """Create an initial cheatsheet."""
167- if not os.path.exists(CHEATSHEET):
168- if os.path.exists(CONFIG_ORIG):
169- os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
170- else:
171- ## Oops! Looks like there's no cheatsheet in CHEATSHEET.
172- ## Then, create an empty cheatsheet.
173- open(CHEATSHEET, 'w').close()
174-
175- elif os.path.exists(CHEATSHEET):
176- if os.path.exists(CONFIG_ORIG):
177- md5 = sumfile()
178- print md5
179- if md5 == '824868f40cd02f0039d5a1fbdbe642d7' or 'a244f1b197f5cfc6b2f35b65911d3930' or '08e7f4de1838b79ab476fcbfb8074da0' or 'd68d6e9da0a3753c8142b63f0ea74511' or '8ab6d4bf6168c1b775221f466c2fcbbd' or ' 6f4f152766441670a55d3bf00567c92e' or ' f4e73fe22505091d6d75767fafc2848c' or ' 7d2f69943cfe5dbd33a45c63008fca17' or '7fc757ca67121b14e574280a6dbe24ef' or '0e345d5934032aa7fecb23cff56d5407':
180- os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
181- print '.clicompanion not modified by user'
182- #TODO what to do if user has modified command dictionary?
183- else:
184- os.system ("cp %s %s" % (CHEATSHEET, CHEATSHEETBAK))
185- os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
186- print '.clicompanion modified by user'
187-
188- ## close the window and quit
189- def delete_event(self, widget, data=None):
190- gtk.main_quit()
191- return False
192-
193- ## Info Dialog Box
194- ## if a command needs more info EX: a package name, a path
195- def get_info(self, widget, data=None):
196- global ROW
197- row_int = int(ROW[0][0])
198-
199- ## Create Dialog object
200- dialog = gtk.MessageDialog(
201- None,
202- gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
203- gtk.MESSAGE_QUESTION,
204- gtk.BUTTONS_OK,
205- None)
206-
207- # Primary text
208- dialog.set_markup(_("This command requires more information"))
209-
210- ## create the text input field
211- entry = gtk.Entry()
212- ## allow the user to press enter to do ok
213- entry.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
214-
215- ## create a horizontal box to pack the entry and a label
216- hbox = gtk.HBox()
217- hbox.pack_start(gtk.Label(self.liststore[row_int][1]+":"), False, 5, 5)
218- hbox.pack_end(entry)
219- ## some secondary text
220- dialog.format_secondary_markup(_("Please provide a "+self.liststore[row_int][1]))
221- ## add it and show it
222- dialog.vbox.pack_end(hbox, True, True, 0)
223- dialog.show_all()
224-
225- ## Show the dialog
226- dialog.run()
227-
228- ## user text assigned to a variable
229- text = entry.get_text()
230- user_input = text.split(' ')
231-
232- ## The destroy method must be called otherwise the 'Close' button will
233- ## not work.
234- dialog.destroy()
235- return user_input
236-
237- def responseToDialog(self, text, dialog, response):
238- dialog.response(response)
239-
240- ## Add command dialog box
241- def add_command(self, widget):
242-
243- ## Create Dialog object
244- dialog = gtk.MessageDialog(
245- None,
246- gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
247- gtk.MESSAGE_QUESTION,
248- gtk.BUTTONS_OK,
249- None)
250-
251- ## primaary text
252- dialog.set_markup(_("Add a command to your clicompanion dictionary"))
253-
254- #create the text input field
255- entry1 = gtk.Entry()
256- entry2 = gtk.Entry()
257- entry3 = gtk.Entry()
258- ## allow the user to press enter to do ok
259- entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
260- entry2.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
261- entry3.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
262-
263- ## create three labels
264- hbox1 = gtk.HBox()
265- hbox1.pack_start(gtk.Label(_("Command")), False, 5, 5)
266- hbox1.pack_start(entry1, False, 5, 5)
267-
268- hbox1.pack_start(gtk.Label(_("User Input")), False, 5, 5)
269- hbox1.pack_start(entry2, False, 5, 5)
270-
271- hbox2 = gtk.HBox()
272- hbox2.pack_start(gtk.Label(_("Description")), False, 5, 5)
273- hbox2.pack_start(entry3, True, 5, 5)
274-
275- ## cancel button
276- dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
277- ## some secondary text
278- 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."))
279-
280- ## add it and show it
281- dialog.vbox.pack_end(hbox2, True, True, 0)
282- dialog.vbox.pack_end(hbox1, True, True, 0)
283- dialog.show_all()
284- ## Show the dialog
285- result = dialog.run()
286-
287- if result == gtk.RESPONSE_OK:
288- ## user text assigned to a variable
289- text1 = entry1.get_text()
290- text2 = entry2.get_text()
291- text3 = entry3.get_text()
292- ## open flat file that contains the commands and add the new command
293- with open(CHEATSHEET, "a") as cheatfile:
294- if text1 != "":
295- cheatfile.write(text1+" :"+text2+" : "+text3+'\n')
296- cheatfile.close()
297- l = str(text1+" :"+text2+" : "+text3)
298- ls = l.split(':',2)
299- CMNDS.append(ls[0])
300- self.liststore.append([ls[0],ls[1],ls[2]])
301-
302- ## The destroy method must be called otherwise the 'Close' button will
303- ## not work.
304- dialog.destroy()
305- #return text
306-
307- ## This the edit function
308- def edit_command(self, widget , data=None):
309-
310- global ROW
311- row_int = int(ROW[0][0])
312-
313-
314- row_obj1 = self.liststore[row_int][0]
315- text1 = "".join(row_obj1)
316-
317- row_obj2 = self.liststore[row_int][1]
318- text2 = "".join(row_obj2)
319-
320- row_obj3 = self.liststore[row_int][2]
321- text3 = "".join(row_obj3)
322-
323- ## Create Dialog object
324- dialog = gtk.MessageDialog(
325- None,
326- gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
327- gtk.MESSAGE_QUESTION,
328- gtk.BUTTONS_OK,
329- None)
330-
331- # primary text
332- dialog.set_markup(_("Edit the command in your clicompanion dictionary"))
333-
334- ## create the text input fields
335- entry1 = gtk.Entry()
336- entry1.set_text(text1)
337- entry2 = gtk.Entry()
338- entry2.set_text(text2)
339- entry3 = gtk.Entry()
340- entry3.set_text(text3)
341- ## allow the user to press enter to do ok
342- entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
343-
344- ## create three labels
345- hbox1 = gtk.HBox()
346- hbox1.pack_start(gtk.Label(_("Command")), False, 5, 5)
347- hbox1.pack_start(entry1, False, 5, 5)
348-
349- hbox1.pack_start(gtk.Label(_("User Input")), False, 5, 5)
350- hbox1.pack_start(entry2, False, 5, 5)
351-
352- hbox2 = gtk.HBox()
353- hbox2.pack_start(gtk.Label(_("Description")), False, 5, 5)
354- hbox2.pack_start(entry3, True, 5, 5)
355-
356- ## cancel button
357- dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
358- ## some secondary text
359- dialog.format_secondary_markup(_("Please provide a command, description, and what type of user variable, if any, is required."))
360-
361- ## add it and show it
362- dialog.vbox.pack_end(hbox2, True, True, 0)
363- dialog.vbox.pack_end(hbox1, True, True, 0)
364- dialog.show_all()
365- ## Show the dialog
366- result = dialog.run()
367-
368- if result == gtk.RESPONSE_OK:
369- ## user text assigned to a variable
370- text1 = entry1.get_text()
371- text2 = entry2.get_text()
372- text3 = entry3.get_text()
373-
374- if text1 != "":
375- self.remove_command(widget)
376- ## open flat file, add the new command
377- with open(CHEATSHEET, "a") as cheatfile:
378- cheatfile.write(text1+":"+text2+":"+text3+'\n')
379- cheatfile.close()
380- l = str(text1+":"+text2+":"+text3)
381- ls = l.split(':',2)
382- CMNDS.append(ls[0])
383- self.liststore.append([ls[0],ls[1],ls[2]])
384-
385- ## The destroy method must be called otherwise the 'Close' button will
386- ## not work.
387- dialog.destroy()
388-
389-
390- ## Remove command from command file and GUI
391- def remove_command(self, widget, data=None):
392- global ROW
393- row_int = int(ROW[0][0]) #convert pathlist into something usable
394-
395- del CMNDS[row_int]
396- del self.liststore[row_int]
397-
398-
399- ## open command file and delete line so the change is persistent
400- with open(CHEATSHEET, "r") as cheatfile:
401- cheatlines = cheatfile.readlines()
402- del cheatlines[row_int]
403- cheatfile.close()
404- with open(CHEATSHEET, "w") as cheatfile2:
405- cheatfile2.writelines(cheatlines)
406- cheatfile2.close()
407-
408-
409- def _filter_commands(self, widget, data=None):
410- """
411- Show commands matching a given search term.
412- The user should enter a term in the search box and the treeview should
413- only display the rows which contain the search term.
414- Pretty straight-forward.
415- """
416- search_term = self.search_box.get_text()
417-
418- ## Create a TreeModelFilter object which provides auxiliary functions for
419- ## filtering data.
420- ## http://www.pygtk.org/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html
421- modelfilter = self.liststore.filter_new()
422- def search(modelfilter, iter, search_term):
423- try:
424- ## Iterate through every column and row and check if the search
425- ## term is there:
426- if search_term in modelfilter.get_value(iter, 0) or \
427- search_term in modelfilter.get_value(iter, 1) or \
428- search_term in modelfilter.get_value(iter, 2):
429- return True
430- except TypeError:
431- ## Python raises a TypeError if row data doesn't exist. Catch
432- ## that and fail silently.
433- pass
434-
435- modelfilter.set_visible_func(search, search_term)
436- self.treeview.set_model(modelfilter)
437-
438- ## send the command to the terminal
439- def run_command(self, widget, data=None):
440- global ROW
441- text = ""
442- row_int = int(ROW[0][0]) ## removes everything but number from [5,]
443-
444- ## get the current notebook page so the function knows which terminal to run the command in.
445- pagenum = self.notebook.get_current_page()
446- widget = self.notebook.get_nth_page(pagenum)
447- page_widget = widget.get_child()
448-
449- ## CMNDS is where commands are stored
450- cmnd = CMNDS[row_int]
451- ## find how many @(user arguments) are in command
452- match = re.findall('@', cmnd)
453- '''
454- Make sure user arguments were found. Replace @ with something
455- .format can read. This is done so the user can just enter @, when
456- adding a command where arguments are needed, instead
457- of {0[1]}, {0[1]}, {0[2]}
458- '''
459- if match == False:
460- pass
461- else:
462- num = len(match)
463- ran = 0
464- new_cmnd = self.replace(cmnd, num, ran)
465-
466- if not self.liststore[row_int][1] == " ": # command with user input
467- text = Companion.get_info(self, text)
468- c = new_cmnd.format(text)
469- page_widget.feed_child(c+"\n") #send command w/ input
470- page_widget.show()
471- else: ## command that has no user input
472- page_widget.feed_child(cmnd+"\n") #send command
473- page_widget.show()
474- page_widget.grab_focus()
475-
476- ## replace @ with {0[n]}
477- def replace(self, cmnd, num, ran):
478- replace_cmnd=re.sub('@', '{0['+str(ran)+']}', cmnd, count=1)
479- cmnd = replace_cmnd
480- ran += 1
481- if ran < num:
482- return self.replace(cmnd, num, ran)
483- else:
484- pass
485- return cmnd
486-
487- ## open the man page for selected command
488- def man_page(self, widget, data=None):
489- row_int = int(ROW[0][0]) # removes everything but number from EX: [5,]
490- cmnd = CMNDS[row_int] #CMNDS is where commands are store
491- splitcommand = self._filter_sudo_from(cmnd.split(" "))
492- ## get current notebook tab to use in function
493- pagenum = self.notebook.get_current_page()
494- widget = self.notebook.get_nth_page(pagenum)
495- page_widget = widget.get_child()
496- #send command to Terminal
497- page_widget.feed_child("man "+splitcommand[0]+"| most \n")
498- page_widget.grab_focus()
499- page_widget.show()
500-
501-
502- @staticmethod
503- def _filter_sudo_from(command):
504- """Filter the sudo from `command`, where `command` is a list.
505- Return the command list with the "sudo" filtered out.
506- """
507- if command[0].startswith("sudo"):
508- del command[0]
509- return command
510- return command
511-
512-
513- ## open file containing command dictionary and put it in a variable
514- def update(self):
515- try:
516- with open(CHEATSHEET, "r") as cheatfile:
517- bugdata=cheatfile.read()
518- cheatfile.close()
519- except IOError:
520- ## CHEATSHEET is not there. Oh, no!
521- ## So, run self.setup() again.
522- self.setup()
523- ## Then, run me again.
524- self.update()
525-
526- global CMNDS
527- ## add bug data from .clicompanion to the liststore
528- CMNDS = []
529- for line in bugdata.splitlines():
530- l = line.split(':',2)
531- CMNDS.append(l[0])
532- self.liststore.append([l[0],l[1],l[2]])
533-
534-
535-
536- ## add a new terminal in a tab above the current terminal
537- def add_tab(self, data=None):
538-
539- _vte = vte.Terminal()
540- _vte.set_size_request(700, 220)
541- _vte.connect ("child-exited", lambda term: gtk.main_quit())
542- _vte.fork_command(get_user_shell()) # Get the user's default shell
543-
544- vte_tab = gtk.ScrolledWindow()
545- vte_tab.add(_vte)
546- #self.notebook.set_show_tabs(True)
547- #self.notebook.set_show_border(True)
548-
549- gcp = self.notebook.get_current_page() +1
550- pagenum = ('Tab %d') % gcp
551-
552- box = gtk.HBox()
553- label = gtk.Label(pagenum)
554- box.pack_start(label, True, True)
555-
556- ## x image for tab close button
557- close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
558- ## close button
559- closebtn = gtk.Button()
560- closebtn.set_relief(gtk.RELIEF_NONE)
561- closebtn.set_focus_on_click(True)
562-
563- closebtn.add(close_image)
564- ## put button in a box and show box
565- box.pack_end(closebtn, False, False)
566- box.show_all()
567-
568- self.notebook.prepend_page(vte_tab, box) # add tab
569- self.notebook.set_scrollable(True)
570- _vte.connect ("button_press_event", self.copy_paste, None)
571- vte_tab.grab_focus()
572- # signal handler for tab
573- closebtn.connect("clicked", self.close_tab, vte_tab)
574- self.window.show_all()
575-
576- return vte_tab
577-
578-
579- ## Remove a page from the notebook
580- def close_tab(self, sender, widget):
581- ## get the page number of the tab we wanted to close
582- pagenum = self.notebook.page_num(widget)
583- ## and close it
584- self.notebook.remove_page(pagenum)
585-
586- #TODO: Move to menus_buttons
587- def copy_paste(self, vte, event, data=None):
588- if event.button == 3:
589-
590- time = event.time
591- ## right-click popup menu Copy
592- popupMenu = gtk.Menu()
593- menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_COPY)
594- popupMenu.add(menuPopup1)
595- menuPopup1.connect('activate', lambda x: vte.copy_clipboard())
596- ## right-click popup menu Paste
597- menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_PASTE)
598- popupMenu.add(menuPopup2)
599- menuPopup2.connect('activate', lambda x: vte.paste_clipboard())
600-
601- ## Show popup menu
602- popupMenu.show_all()
603- popupMenu.popup( None, None, None, event.button, time)
604- return True
605- else:
606- pass
607-
608- def about_event(self):
609- pass
610- def help_event(self):
611- pass
612-
613- #liststore in a scrolled window in an expander
614- def expanded_cb(self, expander, params):
615- if expander.get_expanded():
616-
617- self.update()
618- ## create the TreeView
619- self.treeview = gtk.TreeView()
620- ## create window with scrollbar
621- self.scrolledwindow = gtk.ScrolledWindow()
622- self.scrolledwindow.set_size_request(700, 220)
623-
624- ## create the TreeViewColumns to display the data
625- self.treeview.columns = [None]*3
626- self.treeview.columns[0] = gtk.TreeViewColumn(_('Command'))
627- self.treeview.columns[1] = gtk.TreeViewColumn(_('User Argument'))
628- self.treeview.columns[2] = gtk.TreeViewColumn(_('Description'))
629-
630- ## right click menu event capture
631- bar = clicompanion.menus_buttons.FileMenu()
632- self.treeview.connect ("button_press_event", bar.right_click, self)
633-
634- for n in range(3):
635- ## add columns to treeview
636- self.treeview.append_column(self.treeview.columns[n])
637- ## create a CellRenderers to render the data
638- self.treeview.columns[n].cell = gtk.CellRendererText()
639- ## add the cells to the columns
640- self.treeview.columns[n].pack_start(self.treeview.columns[n].cell,
641- True)
642- ## set the cell attributes to the appropriate liststore column
643- self.treeview.columns[n].set_attributes(
644- self.treeview.columns[n].cell, text=n)
645- self.treeview.columns[n].set_resizable(True)
646-
647- ## 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
648- self.treeview.set_model(self.liststore)
649- self.scrolledwindow.add(self.treeview)
650- expander.add(self.scrolledwindow)
651-
652- self.window.show_all()
653-
654- self.treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
655- self.treeview.get_selection().connect('changed',lambda s: mark_selected(s))
656-
657- def mark_selected(treeselection):
658- (model,pathlist)=treeselection.get_selected_rows()
659- global ROW
660- ROW = pathlist
661-
662- # Activate the search box when not expanded
663- self.search_box.set_sensitive(True)
664- else:
665- # De-activate the search box when not expanded
666- self.search_box.set_sensitive(False)
667-
668- expander.remove(expander.child)
669- ##reset the size of the window to its original one
670- self.window.resize(1, 1)
671- return
672-
673-
674- def __init__(self):
675- ##For now TERM is hardcoded to xterm because of a change
676- ##in libvte in Ubuntu Maverick
677- os.putenv('TERM', 'xterm')
678- ## copy config file to user $HOME if does not exist
679- self.setup()
680- #TODO: do we want to do this? Or just keep the height under 600.
681- ##Get user screen size##
682- #screen = gtk.gdk.display_get_default().get_default_screen()
683- #screen_size = screen.get_monitor_geometry(0)
684- #height = screen.get_height() ## screen height ##
685- ## Create a new window
686- self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
687- ## create a liststore with three string columns
688- self.liststore = gtk.ListStore(str, str, str)
689- ## Create an expander
690- expander = gtk.Expander()
691- ## Create Notebook
692- self.notebook = gtk.Notebook()
693- ## set Window title
694- self.window.set_title("CLI Companion")
695- ## Adding icon
696- icon = gtk.gdk.pixbuf_new_from_file("/usr/share/pixmaps/clicompanion.16.png")
697- self.window.set_icon(icon)
698- ## Sets the border width of the window.
699- self.window.set_border_width(10)
700- ## set the size of the window
701- self.window.set_default_size(700, 400)
702- ## Sets the position of the window relative to the screen
703- self.window.set_position(gtk.WIN_POS_CENTER)
704- ## Allow user to resize window
705- self.window.set_resizable(True)
706-
707- self.window.connect("delete_event", self.delete_event)
708-
709- ## 'File' and 'Help' Drop Down Menu [menus_buttons.py]
710- bar = clicompanion.menus_buttons.FileMenu()
711- menu_bar = bar.the_menu(self)
712- ## The search section
713- self.search_label = gtk.Label(_("Search:"))
714- self.search_label.set_alignment(xalign=-1, yalign=0)
715- self.search_box = gtk.Entry()
716- self.search_box.connect("changed", self._filter_commands)
717- ## search box tooltip
718- self.search_box.set_tooltip_text("Search your list of commands")
719- # Set the search box sensitive at program start, because expander is not
720- # unfolded by default
721- self.search_box.set_sensitive(False)
722- ## hbox for menu and search Entry
723- menu_search_hbox = gtk.HBox(False)
724- menu_search_hbox.pack_end(self.search_box, True)
725- menu_search_hbox.pack_end(self.search_label, False, False, 10)
726- menu_search_hbox.pack_start(menu_bar, True)
727-
728- ## TODO Do we want to start with the command list open or closed?
729- ## This code opens the app with it open
730- ## We would also need to change the search field disable code
731- ## start program with expander open
732- #expander.set_expanded(True)
733- #self.expanded_cb(expander, None)
734-
735- ## expander signal
736- expander.connect('notify::expanded', self.expanded_cb)
737-
738- ## expander title
739- expander_hbox = gtk.HBox()
740- image = gtk.Image()
741- image.set_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
742- label = gtk.Label(' Command List')
743- ## tooltip for the label of the expander
744- expander_hbox.set_tooltip_text("Click to show/hide command list")
745-
746- ## add expander widget to hbox
747- expander_hbox.pack_start(image, False, False)
748- expander_hbox.pack_start(label, True, False)
749- expander.set_label_widget(expander_hbox)
750-
751- ## Add the first tab with the Terminal
752- self.add_tab()
753- self.notebook.set_tab_pos(1)
754-
755- ## The "Add Tab" tab
756- add_tab_button = gtk.Button("+")
757- ## tooltip for "Add Tab" tab
758- add_tab_button.set_tooltip_text("Click to add another Tab")
759- add_tab_button.connect("clicked", self.add_tab)
760- self.notebook.append_page(gtk.Label(""), add_tab_button)
761-
762- ## buttons at bottom of main window [menus_buttons.py]
763- button_box = bar.buttons(self, 10, gtk.BUTTONBOX_END)
764-
765- ## vbox for search, notebook, buttonbar
766- self.vbox = gtk.VBox()
767- self.window.add(self.vbox)
768- ## pack everytyhing in the vbox
769- #self.vbox.pack_start(menu_bar, False, False, 0) ##menuBar
770- self.vbox.pack_start(menu_search_hbox, False, False, 5)
771- self.vbox.pack_start(expander, False, False, 5)
772- self.vbox.pack_start(self.notebook, True, True, 10)
773- self.vbox.pack_start(button_box, False, False, 5)
774-
775-
776- #self.vte.grab_focus()
777- self.window.show_all()
778- return
779-
780-def main():
781- try:
782- gtk.main()
783- except KeyboardInterrupt:
784- pass
785-
786-if __name__ == "__main__":
787- companion = Companion()
788- main()
789-
790
791=== removed file 'clicompanion/__init__.py'
792--- clicompanion/__init__.py 2010-10-06 06:54:47 +0000
793+++ clicompanion/__init__.py 1970-01-01 00:00:00 +0000
794@@ -1,23 +0,0 @@
795-#!/usr/bin/env python
796-# -*- coding: utf-8 -*-
797-#
798-# clicompanion.py - commandline tool.
799-#
800-# Copyright 2010 Duane Hinnen, Kenny Meyer
801-#
802-# This program is free software: you can redistribute it and/or modify it
803-# under the terms of the GNU General Public License version 3, as published
804-# by the Free Software Foundation.
805-#
806-# This program is distributed in the hope that it will be useful, but
807-# WITHOUT ANY WARRANTY; without even the implied warranties of
808-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
809-# PURPOSE. See the GNU General Public License for more details.
810-#
811-# You should have received a copy of the GNU General Public License along
812-# with this program. If not, see <http://www.gnu.org/licenses/>.
813-#
814-#
815-'''
816-blah, blah, blah
817-'''
818
819=== removed file 'clicompanion/menus_buttons.py'
820--- clicompanion/menus_buttons.py 2010-10-06 06:54:47 +0000
821+++ clicompanion/menus_buttons.py 1970-01-01 00:00:00 +0000
822@@ -1,157 +0,0 @@
823-#!/usr/bin/env python
824-# -*- coding: utf-8 -*-
825-#
826-# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
827-#
828-# This file contains the menus, buttons, and right clicks
829-#
830-#import clicompanion
831-import gtk
832-
833-class FileMenu(object):
834- def the_menu(self, cli):
835- menu = gtk.Menu()
836- root_menu = gtk.MenuItem(_("File"))
837- root_menu.set_submenu(menu)
838-
839- menu2 = gtk.Menu()
840- root_menu2 = gtk.MenuItem(_("Help"))
841- root_menu2.set_submenu(menu2)
842-
843- ##FILE MENU ##
844- ## Make 'Run' menu entry
845- menu_item1 = gtk.MenuItem(_("Run Command"))
846- menu.append(menu_item1)
847- menu_item1.connect("activate", cli.run_command)
848- menu_item1.show()
849-
850- ## Make 'Add' file menu entry
851- menu_item2 = gtk.MenuItem(_("Add Command"))
852- menu.append(menu_item2)
853- menu_item2.connect("activate", cli.add_command)
854- menu_item2.show()
855-
856- ## Make 'Remove' file menu entry
857- menu_item2 = gtk.MenuItem(_("Remove Command"))
858- menu.append(menu_item2)
859- menu_item2.connect("activate", cli.remove_command)
860- menu_item2.show()
861-
862- ## Make 'Quit' file menu entry
863- menu_item3 = gtk.MenuItem(_("Quit"))
864- menu.append(menu_item3)
865- menu_item3.connect("activate", cli.delete_event)
866- menu_item3.show()
867-
868-
869- ## Make 'Add Tab' file menu entry
870- menu_item4 = gtk.MenuItem(_("Add Tab"))
871- menu.append(menu_item4)
872- menu_item4.connect("activate", cli.add_tab)
873- menu_item4.show()
874-
875-
876- ## HELP MENU ##
877- ## Make 'About' file menu entry
878- menu_item11 = gtk.MenuItem(_("About"))
879- menu2.append(menu_item11)
880- menu_item11.connect("activate", cli.about_event)
881- menu_item11.show()
882-
883-
884- ## Make 'Help' file menu entry
885- menu_item22 = gtk.MenuItem(_("Help"))
886- menu2.append(menu_item22)
887- menu_item22.connect("activate", cli.help_event)
888- menu_item22.show()
889-
890-
891- menu_bar = gtk.MenuBar()
892-
893- menu_bar.append (root_menu) ##Menu bar(file)
894- menu_bar.append (root_menu2) ##Menu bar(help)
895- #menu_bar.show() ##show File Menu # Menu Bar
896- ##Show 'File' Menu
897- #root_menu.show()
898- return menu_bar
899-
900-
901-
902- def buttons(self, cli, spacing, layout):
903- #button box at bottom of main window
904- frame = gtk.Frame()
905- bbox = gtk.HButtonBox()
906- bbox.set_border_width(5)
907- frame.add(bbox)
908-
909- # Set the appearance of the Button Box
910- bbox.set_layout(layout)
911- bbox.set_spacing(spacing)
912- # Run button
913- buttonRun = gtk.Button(_("Run"))
914- bbox.add(buttonRun)
915- buttonRun.connect("clicked", cli.run_command)
916- buttonRun.set_tooltip_text("Click to run a highlighted command")
917- # Add button
918- buttonAdd = gtk.Button(stock=gtk.STOCK_ADD)
919- bbox.add(buttonAdd)
920- buttonAdd.connect("clicked", cli.add_command)
921- buttonAdd.set_tooltip_text("Click to add a command to your command list")
922- # Edit button
923- buttonEdit = gtk.Button("Edit")
924- bbox.add(buttonEdit)
925- buttonEdit.connect("clicked", cli.edit_command)
926- buttonEdit.set_tooltip_text("Click to edit a command in your command list")
927- # Delete button
928- buttonDelete = gtk.Button(stock=gtk.STOCK_DELETE)
929- bbox.add(buttonDelete)
930- buttonDelete.connect("clicked", cli.remove_command)
931- buttonDelete.set_tooltip_text("Click to delete a command in your command list")
932- #Help Button
933- buttonHelp = gtk.Button(stock=gtk.STOCK_HELP)
934- bbox.add(buttonHelp)
935- buttonHelp.connect("clicked", cli.man_page)
936- buttonHelp.set_tooltip_text("Click to get help with a command in your command list")
937- # Cancel button
938- buttonCancel = gtk.Button(stock=gtk.STOCK_QUIT)
939- bbox.add(buttonCancel)
940- buttonCancel.connect("clicked", cli.delete_event)
941- buttonCancel.set_tooltip_text("Click to quit CLI Companion")
942-
943- return frame
944-
945-
946- #right-click popup menu for the Liststore(command list)
947- def right_click(self, treeview, event, cli):
948- if event.button == 3:
949- x = int(event.x)
950- y = int(event.y)
951- time = event.time
952- pthinfo = treeview.get_path_at_pos(x, y)
953- if pthinfo is not None:
954- path, col, cellx, celly = pthinfo
955- treeview.grab_focus()
956- treeview.set_cursor( path, col, 0)
957-
958- # right-click popup menu Apply(run)
959- popupMenu = gtk.Menu()
960- menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_APPLY)
961- popupMenu.add(menuPopup1)
962- menuPopup1.connect("activate", cli.run_command)
963- # right-click popup menu Edit
964- menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_EDIT)
965- popupMenu.add(menuPopup2)
966- menuPopup2.connect("activate", cli.edit_command)
967- # right-click popup menu Delete
968- menuPopup3 = gtk.ImageMenuItem (gtk.STOCK_DELETE)
969- popupMenu.add(menuPopup3)
970- menuPopup3.connect("activate", cli.remove_command)
971- # right-click popup menu Help
972- menuPopup4 = gtk.ImageMenuItem (gtk.STOCK_HELP)
973- popupMenu.add(menuPopup4)
974- menuPopup4.connect("activate", cli.man_page)
975- # Show popup menu
976- popupMenu.show_all()
977- popupMenu.popup( None, None, None, event.button, time)
978- return True
979-
980
981=== removed file 'clicompanion/utils.py'
982--- clicompanion/utils.py 2010-10-06 06:54:47 +0000
983+++ clicompanion/utils.py 1970-01-01 00:00:00 +0000
984@@ -1,66 +0,0 @@
985-# -*- mode: python; coding: utf-8; -*-
986-#
987-# clicompanion.py - commandline tool.
988-#
989-# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
990-#
991-# This program is free software: you can redistribute it and/or modify it
992-# under the terms of the GNU General Public License version 3, as published
993-# by the Free Software Foundation.
994-#
995-# This program is distributed in the hope that it will be useful, but
996-# WITHOUT ANY WARRANTY; without even the implied warranties of
997-# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
998-# PURPOSE. See the GNU General Public License for more details.
999-#
1000-# You should have received a copy of the GNU General Public License along
1001-# with this program. If not, see <http://www.gnu.org/licenses/>.
1002-#
1003-#
1004-
1005-"""
1006-A collection of useful functions.
1007-"""
1008-
1009-import getpass
1010-import hashlib
1011-import os
1012-
1013-CHEATSHEET = os.path.expanduser("~/.clicompanion")
1014-CONFIG_ORIG = "/etc/clicompanion.d/clicompanion.config"
1015-
1016-def get_user_shell():
1017- """Get the user's shell defined in /etc/passwd ."""
1018- data = None
1019- try:
1020- # Read out the data in /etc/passwd
1021- with open('/etc/passwd') as f:
1022- data = f.readlines()
1023- except e:
1024- print "Something unexpected happened!"
1025- raise e
1026-
1027- for i in data:
1028- tmp = i.split(":")
1029- # Check for the entry of the currently logged in user
1030- if tmp[0] == getpass.getuser():
1031- # Columns are separated by colons, so split each column.
1032- # Sample /etc/passwd entry for a user:
1033- #
1034- # jorge:x:1001:1002:,,,:/home/jorge:/bin/bash
1035- #
1036- # The last column is relevant for us.
1037- # Don't forget to strip the newline at the end of the string!
1038- return i.split(":")[-1:][0].strip('\n')
1039-
1040-
1041-def sumfile():
1042- '''Returns an md5 hash for an object with read() method.'''
1043- m = hashlib.md5()
1044- with open(CHEATSHEET, 'rb') as cheatsheet:
1045- d = cheatsheet.read()
1046- m.update(d)
1047- pp = m.hexdigest()
1048- print pp
1049- return m.hexdigest()
1050-
1051
1052=== added directory 'clicompanionlib'
1053=== added file 'clicompanionlib/__init__.py'
1054--- clicompanionlib/__init__.py 1970-01-01 00:00:00 +0000
1055+++ clicompanionlib/__init__.py 2010-11-30 16:11:27 +0000
1056@@ -0,0 +1,23 @@
1057+#!/usr/bin/env python
1058+# -*- coding: utf-8 -*-
1059+#
1060+# clicompanion.py - commandline tool.
1061+#
1062+# Copyright 2010 Duane Hinnen, Kenny Meyer
1063+#
1064+# This program is free software: you can redistribute it and/or modify it
1065+# under the terms of the GNU General Public License version 3, as published
1066+# by the Free Software Foundation.
1067+#
1068+# This program is distributed in the hope that it will be useful, but
1069+# WITHOUT ANY WARRANTY; without even the implied warranties of
1070+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1071+# PURPOSE. See the GNU General Public License for more details.
1072+#
1073+# You should have received a copy of the GNU General Public License along
1074+# with this program. If not, see <http://www.gnu.org/licenses/>.
1075+#
1076+#
1077+'''
1078+blah, blah, blah
1079+'''
1080
1081=== added file 'clicompanionlib/controller.py'
1082--- clicompanionlib/controller.py 1970-01-01 00:00:00 +0000
1083+++ clicompanionlib/controller.py 2010-11-30 16:11:27 +0000
1084@@ -0,0 +1,428 @@
1085+#!/usr/bin/env python
1086+# -*- coding: utf-8 -*-
1087+#
1088+# clicompanion.py - commandline tool.
1089+#
1090+# Copyright 2010 Duane Hinnen, Kenny Meyer
1091+#
1092+# This program is free software: you can redistribute it and/or modify it
1093+# under the terms of the GNU General Public License version 3, as published
1094+# by the Free Software Foundation.
1095+#
1096+# This program is distributed in the hope that it will be useful, but
1097+# WITHOUT ANY WARRANTY; without even the implied warranties of
1098+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1099+# PURPOSE. See the GNU General Public License for more details.
1100+#
1101+# You should have received a copy of the GNU General Public License along
1102+# with this program. If not, see <http://www.gnu.org/licenses/>.
1103+#
1104+# IMPORTANT: you need to move the .cheatsheet file to your $HOME
1105+#
1106+
1107+
1108+import pygtk
1109+pygtk.require('2.0')
1110+import re
1111+import webbrowser
1112+
1113+import os
1114+# import gtk or print error
1115+try:
1116+ import gtk
1117+except:
1118+ print >> sys.stderr, "You need to install the python gtk bindings"
1119+ sys.exit(1)
1120+
1121+# TODO: these handle the exception different. Which do we like?
1122+# import vte or display dialog
1123+try:
1124+ import vte
1125+except:
1126+ error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
1127+ 'You need to install python bindings for libvte')
1128+ error.run()
1129+ sys.exit (1)
1130+
1131+from clicompanionlib.utils import get_user_shell
1132+import view
1133+
1134+
1135+CHEATSHEET = os.path.expanduser("~/.clicompanion2")
1136+CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
1137+
1138+
1139+class Actions(object):
1140+ ## Info Dialog Box
1141+ ## if a command needs more info EX: a package name, a path
1142+ def get_info(self, widget, liststore):
1143+
1144+ row_int = int(view.ROW[0][0])
1145+
1146+ ## Create Dialog object
1147+ dialog = gtk.MessageDialog(
1148+ None,
1149+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
1150+ gtk.MESSAGE_QUESTION,
1151+ gtk.BUTTONS_OK,
1152+ None)
1153+
1154+ # Primary text
1155+ dialog.set_markup(_("This command requires more information"))
1156+
1157+ ## create the text input field
1158+ entry = gtk.Entry()
1159+ ## allow the user to press enter to do ok
1160+ entry.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
1161+
1162+ ## create a horizontal box to pack the entry and a label
1163+ hbox = gtk.HBox()
1164+ hbox.pack_start(gtk.Label(liststore[row_int][1]+":"), False, 5, 5)
1165+ hbox.pack_end(entry)
1166+ ## some secondary text
1167+ dialog.format_secondary_markup(_("Please provide a "+liststore[row_int][1]))
1168+ ## add it and show it
1169+ dialog.vbox.pack_end(hbox, True, True, 0)
1170+ dialog.show_all()
1171+
1172+ ## Show the dialog
1173+ dialog.run()
1174+
1175+ ## user text assigned to a variable
1176+ text = entry.get_text()
1177+ user_input = text.split(' ')
1178+
1179+ ## The destroy method must be called otherwise the 'Close' button will
1180+ ## not work.
1181+ dialog.destroy()
1182+ return user_input
1183+
1184+ def responseToDialog(self, text, dialog, response):
1185+ dialog.response(response)
1186+
1187+ ## Add command dialog box
1188+ def add_command(self, widget, liststore):
1189+
1190+ ## Create Dialog object
1191+ dialog = gtk.MessageDialog(
1192+ None,
1193+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
1194+ gtk.MESSAGE_QUESTION,
1195+ gtk.BUTTONS_OK,
1196+ None)
1197+
1198+ ## primaary text
1199+ dialog.set_markup(_("Add a command to your CLI Companion dictionary"))
1200+
1201+ #create the text input field
1202+ entry1 = gtk.Entry()
1203+ entry2 = gtk.Entry()
1204+ entry3 = gtk.Entry()
1205+ ## allow the user to press enter to do ok
1206+ entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
1207+ entry2.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
1208+ entry3.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
1209+
1210+ ## create three labels
1211+ hbox1 = gtk.HBox()
1212+ hbox1.pack_start(gtk.Label(_("Command")), False, 5, 5)
1213+ hbox1.pack_start(entry1, False, 5, 5)
1214+
1215+ hbox1.pack_start(gtk.Label(_("User Input")), False, 5, 5)
1216+ hbox1.pack_start(entry2, False, 5, 5)
1217+
1218+ hbox2 = gtk.HBox()
1219+ hbox2.pack_start(gtk.Label(_("Description")), False, 5, 5)
1220+ hbox2.pack_start(entry3, True, 5, 5)
1221+
1222+ ## cancel button
1223+ dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
1224+ ## some secondary text
1225+ 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."))
1226+
1227+ ## add it and show it
1228+ dialog.vbox.pack_end(hbox2, True, True, 0)
1229+ dialog.vbox.pack_end(hbox1, True, True, 0)
1230+ dialog.show_all()
1231+ ## Show the dialog
1232+ result = dialog.run()
1233+
1234+ if result == gtk.RESPONSE_OK:
1235+ ## user text assigned to a variable
1236+ text1 = entry1.get_text()
1237+ text2 = entry2.get_text()
1238+ text3 = entry3.get_text()
1239+ '''open flat file, add the new command, update CMNDS variable
1240+ ## update commands in liststore (on screen) '''
1241+ with open(CHEATSHEET, "a") as cheatfile:
1242+ if text1 != "":
1243+ ## write new commands to .clicompanion2 file
1244+ cheatfile.write(text1+":"+text2+":"+text3+'\n')
1245+ cheatfile.close()
1246+ l = str(text1+":"+text2+":"+text3)
1247+ ls = l.split(':',2)
1248+ ## update view.CMNDS variable
1249+ filteredcommandplus = ls[0], ls[1]
1250+ view.CMNDS.append(filteredcommandplus)
1251+ ## update the command list on screen
1252+ liststore.append([ls[0],ls[1],ls[2]])
1253+
1254+
1255+ ## The destroy method must be called otherwise the 'Close' button will
1256+ ## not work.
1257+ dialog.destroy()
1258+ #return text
1259+
1260+ ## This the edit function
1261+ def edit_command(self, widget , liststore):
1262+
1263+ row_int = int(view.ROW[0][0])
1264+
1265+ row_obj1 = liststore[row_int][0]
1266+ text1 = "".join(row_obj1)
1267+
1268+ row_obj2 = liststore[row_int][1]
1269+ text2 = "".join(row_obj2)
1270+
1271+ row_obj3 = liststore[row_int][2]
1272+ text3 = "".join(row_obj3)
1273+
1274+ ## Create Dialog object
1275+ dialog = gtk.MessageDialog(
1276+ None,
1277+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
1278+ gtk.MESSAGE_QUESTION,
1279+ gtk.BUTTONS_OK,
1280+ None)
1281+
1282+ # primary text
1283+ dialog.set_markup(_("Edit the command in your clicompanion dictionary"))
1284+
1285+ ## create the text input fields
1286+ entry1 = gtk.Entry()
1287+ entry1.set_text(text1)
1288+ entry2 = gtk.Entry()
1289+ entry2.set_text(text2)
1290+ entry3 = gtk.Entry()
1291+ entry3.set_text(text3)
1292+ ## allow the user to press enter to do ok
1293+ entry1.connect("activate", self.responseToDialog, dialog, gtk.RESPONSE_OK)
1294+
1295+ ## create three labels
1296+ hbox1 = gtk.HBox()
1297+ hbox1.pack_start(gtk.Label(_("Command")), False, 5, 5)
1298+ hbox1.pack_start(entry1, False, 5, 5)
1299+
1300+ hbox1.pack_start(gtk.Label(_("User Input")), False, 5, 5)
1301+ hbox1.pack_start(entry2, False, 5, 5)
1302+
1303+ hbox2 = gtk.HBox()
1304+ hbox2.pack_start(gtk.Label(_("Description")), False, 5, 5)
1305+ hbox2.pack_start(entry3, True, 5, 5)
1306+
1307+ ## cancel button
1308+ dialog.add_button('Cancel', gtk.RESPONSE_DELETE_EVENT)
1309+ ## some secondary text
1310+ dialog.format_secondary_markup(_("Please provide a command, description, and what type of user variable, if any, is required."))
1311+
1312+ ## add it and show it
1313+ dialog.vbox.pack_end(hbox2, True, True, 0)
1314+ dialog.vbox.pack_end(hbox1, True, True, 0)
1315+ dialog.show_all()
1316+ ## Show the dialog
1317+ result = dialog.run()
1318+
1319+ if result == gtk.RESPONSE_OK:
1320+ ## user text assigned to a variable
1321+ text1 = entry1.get_text()
1322+ text2 = entry2.get_text()
1323+ text3 = entry3.get_text()
1324+
1325+ if text1 != "":
1326+ self.remove_command(widget, liststore)
1327+ '''open flat file, add the new command, update CMNDS variable
1328+ ## update commands in liststore (on screen) '''
1329+ with open(CHEATSHEET, "a") as cheatfile:
1330+ ## write new commands to .clicompanion2 file
1331+ cheatfile.write(text1+":"+text2+":"+text3+'\n')
1332+ cheatfile.close()
1333+ l = str(text1+":"+text2+":"+text3)
1334+ ls = l.split(':',2)
1335+ ## update view.CMNDS variable
1336+ filteredcommandplus = ls[0], ls[1]
1337+ view.CMNDS.append(filteredcommandplus)
1338+ ## update the command list on screen
1339+ liststore.append([ls[0],ls[1],ls[2]])
1340+
1341+ ## The destroy method must be called otherwise the 'Close' button will
1342+ ## not work.
1343+ dialog.destroy()
1344+
1345+
1346+ ## Remove command from command file and GUI
1347+ def remove_command(self, widget, liststore):
1348+
1349+ row_int = int(view.ROW[0][0]) #convert pathlist into something usable
1350+ del view.CMNDS[row_int]
1351+ del liststore[row_int]
1352+
1353+ ## open command file and delete line so the change is persistent
1354+ with open(CHEATSHEET, "r") as cheatfile:
1355+ cheatlines = cheatfile.readlines()
1356+ del cheatlines[row_int]
1357+ cheatfile.close()
1358+ with open(CHEATSHEET, "w") as cheatfile2:
1359+ cheatfile2.writelines(cheatlines)
1360+ cheatfile2.close()
1361+
1362+
1363+ def _filter_commands(self, widget, liststore, treeview):
1364+ """
1365+ Show commands matching a given search term.
1366+ The user should enter a term in the search box and the treeview should
1367+ only display the rows which contain the search term.
1368+ Pretty straight-forward.
1369+ """
1370+ search_term = widget.get_text()
1371+
1372+ ## Create a TreeModelFilter object which provides auxiliary functions for
1373+ ## filtering data.
1374+ ## http://www.pygtk.org/pygtk2tutorial/sec-TreeModelSortAndTreeModelFilter.html
1375+ modelfilter = liststore.filter_new()
1376+ def search(modelfilter, iter, search_term):
1377+ try:
1378+ ## Iterate through every column and row and check if the search
1379+ ## term is there:
1380+ if search_term in modelfilter.get_value(iter, 0) or \
1381+ search_term in modelfilter.get_value(iter, 1) or \
1382+ search_term in modelfilter.get_value(iter, 2):
1383+ return True
1384+
1385+ except TypeError:
1386+ ## Python raises a TypeError if row data doesn't exist. Catch
1387+ ## that and fail silently.
1388+ pass
1389+
1390+ modelfilter.set_visible_func(search, search_term)
1391+ treeview.set_model(modelfilter)
1392+
1393+
1394+ #clear CMNDS list then populate it with the filteredlist of commands
1395+ view.CMNDS = []
1396+ for line in modelfilter:
1397+ linelist = line
1398+ filteredcommandplus = linelist[0], linelist[1]
1399+ view.CMNDS.append(filteredcommandplus)
1400+
1401+
1402+
1403+ ## send the command to the terminal
1404+ def run_command(self, widget, notebook, liststore):
1405+ text = ""
1406+ row_int = int(view.ROW[0][0]) ## removes everything but number from [5,]
1407+
1408+ ## get the current notebook page so the function knows which terminal to run the command in.
1409+ pagenum = notebook.get_current_page()
1410+ widget = notebook.get_nth_page(pagenum)
1411+ page_widget = widget.get_child()
1412+ ## view.CMNDS is where commands are stored
1413+ cmnd = view.CMNDS[row_int][0]
1414+
1415+ ## find how many ?(user arguments) are in command
1416+ match = re.findall('\?', cmnd)
1417+ '''
1418+ Make sure user arguments were found. Replace ? with something
1419+ .format can read. This is done so the user can just enter ?, when
1420+ adding a command where arguments are needed, instead
1421+ of {0[1]}, {0[1]}, {0[2]}
1422+ '''
1423+ if match == False:
1424+ pass
1425+ else:
1426+ num = len(match)
1427+ ran = 0
1428+ new_cmnd = self.replace(cmnd, num, ran)
1429+
1430+
1431+ if not view.CMNDS[row_int][1] == "": # command with user input
1432+ text = self.get_info(self, liststore)
1433+ c = new_cmnd.format(text)
1434+ page_widget.feed_child(c+"\n") #send command w/ input
1435+ page_widget.show()
1436+ page_widget.grab_focus()
1437+ else: ## command that has no user input
1438+ page_widget.feed_child(cmnd+"\n") #send command
1439+ page_widget.show()
1440+ page_widget.grab_focus()
1441+
1442+ ## replace ? with {0[n]}
1443+ def replace(self, cmnd, num, ran):
1444+ replace_cmnd=re.sub('\?', '{0['+str(ran)+']}', cmnd, count=1)
1445+ cmnd = replace_cmnd
1446+ ran += 1
1447+ if ran < num:
1448+ return self.replace(cmnd, num, ran)
1449+ else:
1450+ pass
1451+ return cmnd
1452+
1453+ ## open the man page for selected command
1454+ def man_page(self, widget, notebook):
1455+ row_int = int(view.ROW[0][0]) # removes everything but number from EX: [5,]
1456+ cmnd = view.CMNDS[row_int][0] #CMNDS is where commands are store
1457+ splitcommand = self._filter_sudo_from(cmnd.split(" "))
1458+ ## get current notebook tab to use in function
1459+ pagenum = notebook.get_current_page()
1460+ widget = notebook.get_nth_page(pagenum)
1461+ page_widget = widget.get_child()
1462+ #send command to Terminal
1463+ page_widget.feed_child("man "+splitcommand[0]+"| most \n")
1464+ page_widget.grab_focus()
1465+ page_widget.show()
1466+
1467+
1468+ @staticmethod
1469+ def _filter_sudo_from(command):
1470+ """Filter the sudo from `command`, where `command` is a list.
1471+ Return the command list with the "sudo" filtered out.
1472+ """
1473+ if command[0].startswith("sudo"):
1474+ del command[0]
1475+ return command
1476+ return command
1477+
1478+
1479+
1480+ #TODO: Move to menus_buttons
1481+ def copy_paste(self, vte, event, data=None):
1482+ if event.button == 3:
1483+
1484+ time = event.time
1485+ ## right-click popup menu Copy
1486+ popupMenu = gtk.Menu()
1487+ menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_COPY)
1488+ popupMenu.add(menuPopup1)
1489+ menuPopup1.connect('activate', lambda x: vte.copy_clipboard())
1490+ ## right-click popup menu Paste
1491+ menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_PASTE)
1492+ popupMenu.add(menuPopup2)
1493+ menuPopup2.connect('activate', lambda x: vte.paste_clipboard())
1494+
1495+ ## Show popup menu
1496+ popupMenu.show_all()
1497+ popupMenu.popup( None, None, None, event.button, time)
1498+ return True
1499+ else:
1500+ pass
1501+
1502+ ## close the window and quit
1503+ def delete_event(self, widget, data=None):
1504+ gtk.main_quit()
1505+ return False
1506+
1507+ def about_event(self, widget, data=None):
1508+ pass
1509+ def help_event(self, widget, data=None):
1510+ webbrowser.open("http://okiebuntu.homelinux.com/okwiki/clicompanion")
1511+
1512+
1513
1514=== added file 'clicompanionlib/menus_buttons.py'
1515--- clicompanionlib/menus_buttons.py 1970-01-01 00:00:00 +0000
1516+++ clicompanionlib/menus_buttons.py 2010-11-30 16:11:27 +0000
1517@@ -0,0 +1,175 @@
1518+#!/usr/bin/env python
1519+# -*- coding: utf-8 -*-
1520+#
1521+# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
1522+#
1523+# This program is free software: you can redistribute it and/or modify it
1524+# under the terms of the GNU General Public License version 3, as published
1525+# by the Free Software Foundation.
1526+#
1527+# This program is distributed in the hope that it will be useful, but
1528+# WITHOUT ANY WARRANTY; without even the implied warranties of
1529+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1530+# PURPOSE. See the GNU General Public License for more details.
1531+#
1532+# You should have received a copy of the GNU General Public License along
1533+# with this program. If not, see <http://www.gnu.org/licenses/>.
1534+#
1535+#
1536+#
1537+# This file contains the menus, buttons, and right clicks
1538+#
1539+
1540+import gtk
1541+import clicompanionlib.tabs
1542+
1543+
1544+class FileMenu(object):
1545+
1546+ def the_menu(self, actions, notebook, liststore):
1547+ menu = gtk.Menu()
1548+ root_menu = gtk.MenuItem(_("File"))
1549+ root_menu.set_submenu(menu)
1550+
1551+ menu2 = gtk.Menu()
1552+ root_menu2 = gtk.MenuItem(_("Help"))
1553+ root_menu2.set_submenu(menu2)
1554+
1555+ ##FILE MENU ##
1556+ ## Make 'Run' menu entry
1557+ menu_item1 = gtk.MenuItem(_("Run Command"))
1558+ menu.append(menu_item1)
1559+ menu_item1.connect("activate", actions.run_command, notebook, liststore)
1560+ menu_item1.show()
1561+
1562+ ## Make 'Add' file menu entry
1563+ menu_item2 = gtk.MenuItem(_("Add Command"))
1564+ menu.append(menu_item2)
1565+ menu_item2.connect("activate", actions.add_command, liststore)
1566+ menu_item2.show()
1567+
1568+ ## Make 'Remove' file menu entry
1569+ menu_item2 = gtk.MenuItem(_("Remove Command"))
1570+ menu.append(menu_item2)
1571+ menu_item2.connect("activate", actions.remove_command, liststore)
1572+ menu_item2.show()
1573+
1574+ ## Make 'Add Tab' file menu entry
1575+ tabs = clicompanionlib.tabs.Tabs()
1576+ menu_item4 = gtk.MenuItem(_("Add Tab"))
1577+ menu.append(menu_item4)
1578+ menu_item4.connect("activate", tabs.add_tab, notebook)
1579+ menu_item4.show()
1580+
1581+ ## Make 'Quit' file menu entry
1582+ menu_item3 = gtk.MenuItem(_("Quit"))
1583+ menu.append(menu_item3)
1584+ menu_item3.connect("activate", actions.delete_event)
1585+ menu_item3.show()
1586+
1587+
1588+ ## HELP MENU ##
1589+ ## Make 'About' file menu entry
1590+ menu_item11 = gtk.MenuItem(_("About"))
1591+ menu2.append(menu_item11)
1592+ menu_item11.connect("activate", actions.about_event)
1593+ menu_item11.show()
1594+
1595+
1596+ ## Make 'Help' file menu entry
1597+ menu_item22 = gtk.MenuItem(_("Help"))
1598+ menu2.append(menu_item22)
1599+ menu_item22.connect("activate", actions.help_event)
1600+ menu_item22.show()
1601+
1602+
1603+ menu_bar = gtk.MenuBar()
1604+
1605+ menu_bar.append (root_menu) ##Menu bar(file)
1606+ menu_bar.append (root_menu2) ##Menu bar(help)
1607+ #menu_bar.show() ##show File Menu # Menu Bar
1608+ ##Show 'File' Menu
1609+ #root_menu.show()
1610+ return menu_bar
1611+
1612+
1613+
1614+ def buttons(self, actions, spacing, layout, notebook, liststore):
1615+ #button box at bottom of main window
1616+ frame = gtk.Frame()
1617+ bbox = gtk.HButtonBox()
1618+ bbox.set_border_width(5)
1619+ frame.add(bbox)
1620+
1621+ # Set the appearance of the Button Box
1622+ bbox.set_layout(layout)
1623+ bbox.set_spacing(spacing)
1624+ # Run button
1625+ buttonRun = gtk.Button(_("Run"))
1626+ bbox.add(buttonRun)
1627+ buttonRun.connect("clicked", actions.run_command, notebook, liststore)
1628+ buttonRun.set_tooltip_text(_("Click to run a highlighted command"))
1629+ # Add button
1630+ buttonAdd = gtk.Button(stock=gtk.STOCK_ADD)
1631+ bbox.add(buttonAdd)
1632+ buttonAdd.connect("clicked", actions.add_command, liststore)
1633+ buttonAdd.set_tooltip_text(_("Click to add a command to your command list"))
1634+ # Edit button
1635+ buttonEdit = gtk.Button("Edit")
1636+ bbox.add(buttonEdit)
1637+ buttonEdit.connect("clicked", actions.edit_command, liststore)
1638+ buttonEdit.set_tooltip_text(_("Click to edit a command in your command list"))
1639+ # Delete button
1640+ buttonDelete = gtk.Button(stock=gtk.STOCK_DELETE)
1641+ bbox.add(buttonDelete)
1642+ buttonDelete.connect("clicked", actions.remove_command, liststore)
1643+ buttonDelete.set_tooltip_text(_("Click to delete a command in your command list"))
1644+ #Help Button
1645+ buttonHelp = gtk.Button(stock=gtk.STOCK_HELP)
1646+ bbox.add(buttonHelp)
1647+ buttonHelp.connect("clicked", actions.man_page, notebook)
1648+ buttonHelp.set_tooltip_text(_("Click to get help with a command in your command list"))
1649+ # Cancel button
1650+ buttonCancel = gtk.Button(stock=gtk.STOCK_QUIT)
1651+ bbox.add(buttonCancel)
1652+ buttonCancel.connect("clicked", actions.delete_event)
1653+ buttonCancel.set_tooltip_text(_("Click to quit CLI Companion"))
1654+
1655+ return frame
1656+
1657+
1658+ #right-click popup menu for the Liststore(command list)
1659+ def right_click(self, widget, event, actions, treeview, notebook, liststore):
1660+ if event.button == 3:
1661+ x = int(event.x)
1662+ y = int(event.y)
1663+ time = event.time
1664+ pthinfo = treeview.get_path_at_pos(x, y)
1665+ if pthinfo is not None:
1666+ path, col, cellx, celly = pthinfo
1667+ treeview.grab_focus()
1668+ treeview.set_cursor( path, col, 0)
1669+
1670+ # right-click popup menu Apply(run)
1671+ popupMenu = gtk.Menu()
1672+ menuPopup1 = gtk.ImageMenuItem (gtk.STOCK_APPLY)
1673+ popupMenu.add(menuPopup1)
1674+ menuPopup1.connect("activate", actions.run_command, notebook, liststore)
1675+ # right-click popup menu Edit
1676+ menuPopup2 = gtk.ImageMenuItem (gtk.STOCK_EDIT)
1677+ popupMenu.add(menuPopup2)
1678+ menuPopup2.connect("activate", actions.edit_command, liststore)
1679+ # right-click popup menu Delete
1680+ menuPopup3 = gtk.ImageMenuItem (gtk.STOCK_DELETE)
1681+ popupMenu.add(menuPopup3)
1682+ menuPopup3.connect("activate", actions.remove_command, liststore)
1683+ # right-click popup menu Help
1684+ menuPopup4 = gtk.ImageMenuItem (gtk.STOCK_HELP)
1685+ popupMenu.add(menuPopup4)
1686+ menuPopup4.connect("activate", actions.man_page, notebook)
1687+ # Show popup menu
1688+ popupMenu.show_all()
1689+ popupMenu.popup( None, None, None, event.button, time)
1690+ return True
1691+
1692+
1693
1694=== added file 'clicompanionlib/tabs.py'
1695--- clicompanionlib/tabs.py 1970-01-01 00:00:00 +0000
1696+++ clicompanionlib/tabs.py 2010-11-30 16:11:27 +0000
1697@@ -0,0 +1,81 @@
1698+#!/usr/bin/env python
1699+#
1700+# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
1701+#
1702+# This program is free software: you can redistribute it and/or modify it
1703+# under the terms of the GNU General Public License version 3, as published
1704+# by the Free Software Foundation.
1705+#
1706+# This program is distributed in the hope that it will be useful, but
1707+# WITHOUT ANY WARRANTY; without even the implied warranties of
1708+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1709+# PURPOSE. See the GNU General Public License for more details.
1710+#
1711+# You should have received a copy of the GNU General Public License along
1712+# with this program. If not, see <http://www.gnu.org/licenses/>.
1713+#
1714+#
1715+#
1716+
1717+import pygtk
1718+pygtk.require('2.0')
1719+import gtk
1720+import vte
1721+
1722+from clicompanionlib.utils import get_user_shell
1723+import clicompanionlib.controller
1724+
1725+class Tabs(object):
1726+
1727+
1728+
1729+ ## add a new terminal in a tab above the current terminal
1730+ def add_tab(self,widget, notebook):
1731+
1732+ _vte = vte.Terminal()
1733+ _vte.set_size_request(700, 220)
1734+ _vte.connect ("child-exited", lambda term: gtk.main_quit())
1735+ _vte.fork_command(get_user_shell()) # Get the user's default shell
1736+
1737+ vte_tab = gtk.ScrolledWindow()
1738+ vte_tab.add(_vte)
1739+ #notebook.set_show_tabs(True)
1740+ #notebook.set_show_border(True)
1741+
1742+ gcp = notebook.get_current_page() +1
1743+ pagenum = ('Tab %d') % gcp
1744+
1745+ box = gtk.HBox()
1746+ label = gtk.Label(pagenum)
1747+ box.pack_start(label, True, True)
1748+
1749+ ## x image for tab close button
1750+ close_image = gtk.image_new_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU)
1751+ ## close button
1752+ closebtn = gtk.Button()
1753+ closebtn.set_relief(gtk.RELIEF_NONE)
1754+ closebtn.set_focus_on_click(True)
1755+
1756+ closebtn.add(close_image)
1757+ ## put button in a box and show box
1758+ box.pack_end(closebtn, False, False)
1759+ box.show_all()
1760+
1761+ notebook.prepend_page(vte_tab, box) # add tab
1762+ notebook.set_scrollable(True)
1763+ actions = clicompanionlib.controller.Actions()
1764+ _vte.connect ("button_press_event", actions.copy_paste, None)
1765+ vte_tab.grab_focus()
1766+ # signal handler for tab
1767+ closebtn.connect("clicked", self.close_tab, vte_tab, notebook)
1768+ vte_tab.show_all()
1769+
1770+ return vte_tab
1771+
1772+
1773+ ## Remove a page from the notebook
1774+ def close_tab(self, sender, widget, notebook):
1775+ ## get the page number of the tab we wanted to close
1776+ pagenum = notebook.page_num(widget)
1777+ ## and close it
1778+ notebook.remove_page(pagenum)
1779
1780=== added file 'clicompanionlib/utils.py'
1781--- clicompanionlib/utils.py 1970-01-01 00:00:00 +0000
1782+++ clicompanionlib/utils.py 2010-11-30 16:11:27 +0000
1783@@ -0,0 +1,56 @@
1784+#!/usr/bin/env python
1785+# -*- coding: utf-8 -*-
1786+#
1787+# clicompanion.py - commandline tool.
1788+#
1789+# Copyright 2010 Duane Hinnen, Kenny Meyer, Marcos Vanetta
1790+#
1791+# This program is free software: you can redistribute it and/or modify it
1792+# under the terms of the GNU General Public License version 3, as published
1793+# by the Free Software Foundation.
1794+#
1795+# This program is distributed in the hope that it will be useful, but
1796+# WITHOUT ANY WARRANTY; without even the implied warranties of
1797+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1798+# PURPOSE. See the GNU General Public License for more details.
1799+#
1800+# You should have received a copy of the GNU General Public License along
1801+# with this program. If not, see <http://www.gnu.org/licenses/>.
1802+#
1803+#
1804+
1805+"""
1806+A collection of useful functions.
1807+"""
1808+
1809+import getpass
1810+import os
1811+
1812+CHEATSHEET = os.path.expanduser("~/.clicompanion2")
1813+#CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
1814+
1815+#TODO: Move this to controller.py
1816+def get_user_shell():
1817+ """Get the user's shell defined in /etc/passwd ."""
1818+ data = None
1819+ try:
1820+ # Read out the data in /etc/passwd
1821+ with open('/etc/passwd') as f:
1822+ data = f.readlines()
1823+ except e:
1824+ print "Something unexpected happened!"
1825+ raise e
1826+
1827+ for i in data:
1828+ tmp = i.split(":")
1829+ # Check for the entry of the currently logged in user
1830+ if tmp[0] == getpass.getuser():
1831+ # Columns are separated by colons, so split each column.
1832+ # Sample /etc/passwd entry for a user:
1833+ #
1834+ # jorge:x:1001:1002:,,,:/home/jorge:/bin/bash
1835+ #
1836+ # The last column is relevant for us.
1837+ # Don't forget to strip the newline at the end of the string!
1838+ return i.split(":")[-1:][0].strip('\n')
1839+
1840
1841=== added file 'clicompanionlib/view.py'
1842--- clicompanionlib/view.py 1970-01-01 00:00:00 +0000
1843+++ clicompanionlib/view.py 2010-11-30 16:11:27 +0000
1844@@ -0,0 +1,279 @@
1845+#!/usr/bin/env python
1846+# -*- coding: utf-8 -*-
1847+#
1848+# clicompanion.py - commandline tool.
1849+#
1850+# Copyright 2010 Duane Hinnen, Kenny Meyer
1851+#
1852+# This program is free software: you can redistribute it and/or modify it
1853+# under the terms of the GNU General Public License version 3, as published
1854+# by the Free Software Foundation.
1855+#
1856+# This program is distributed in the hope that it will be useful, but
1857+# WITHOUT ANY WARRANTY; without even the implied warranties of
1858+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1859+# PURPOSE. See the GNU General Public License for more details.
1860+#
1861+# You should have received a copy of the GNU General Public License along
1862+# with this program. If not, see <http://www.gnu.org/licenses/>.
1863+#
1864+#
1865+#
1866+
1867+import pygtk
1868+pygtk.require('2.0')
1869+import os
1870+
1871+# import gtk or print error
1872+try:
1873+ import gtk
1874+except:
1875+ print >> sys.stderr, "You need to install the python gtk bindings"
1876+ sys.exit(1)
1877+
1878+# TODO: these handle the exception different. Which do we like?
1879+# import vte or display dialog
1880+try:
1881+ import vte
1882+except:
1883+ error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
1884+ 'You need to install python bindings for libvte')
1885+ error.run()
1886+ sys.exit (1)
1887+
1888+import clicompanionlib.menus_buttons
1889+import clicompanionlib.controller
1890+from clicompanionlib.utils import get_user_shell
1891+import clicompanionlib.tabs
1892+
1893+
1894+CHEATSHEET = os.path.expanduser("~/.clicompanion2")
1895+CONFIG_ORIG = "/etc/clicompanion.d/clicompanion2.config"
1896+CMNDS = [] ## will hold the commands. Actually the first two columns
1897+ROW = '1' ## holds the currently selected row
1898+
1899+
1900+
1901+class MainWindow():
1902+
1903+ ## open file containing command dictionary and put it in a variable
1904+ def update(self, liststore):
1905+ try:
1906+ with open(CHEATSHEET, "r") as cheatfile:
1907+ bugdata=cheatfile.read()
1908+ cheatfile.close()
1909+ except IOError:
1910+ ## CHEATSHEET is not there. Oh, no!
1911+ ## So, run self.setup() again.
1912+ self.setup()
1913+ ## Then, run me again.
1914+ self.update(liststore)
1915+
1916+ ## add bug data from .clicompanion --> bugdata --> to the liststore
1917+ for line in bugdata.splitlines():
1918+ l = line.split(':',2)
1919+ commandplus = l[0], l[1]
1920+ CMNDS.append(commandplus)
1921+ liststore.append([l[0],l[1],l[2]])
1922+
1923+
1924+ #copy config file to user $HOME if does not exist
1925+ def setup(self):
1926+ """
1927+ Check if ~/.clicompanion2 exists. If not check for original
1928+ installed in /etc/clicompanion.d/. If origianl exists copy to $HOME.
1929+ if not create a new, blank ~/.clicompanion2 so program will not crash
1930+ """
1931+
1932+ if not os.path.exists(CHEATSHEET):
1933+ if os.path.exists(CONFIG_ORIG):
1934+ os.system ("cp %s %s" % (CONFIG_ORIG, CHEATSHEET))
1935+ else:
1936+ # Oops! Looks like there's no cheatsheet in CHEATSHEET.
1937+ # Then, create an empty cheatsheet.
1938+ open(CHEATSHEET, 'w').close()
1939+
1940+
1941+ #liststore in a scrolled window in an expander
1942+ def expanded_cb(self, expander, params, notebook, treeview, liststore):
1943+ if expander.get_expanded():
1944+
1945+
1946+ # Activate the search box when expanded
1947+ self.search_box.set_sensitive(True)
1948+ else:
1949+ # De-activate the search box when not expanded
1950+ self.search_box.set_sensitive(False)
1951+ expander.set_expanded(False)
1952+ #expander.remove(expander.child)
1953+ ##reset the size of the window to its original one
1954+ self.window.resize(1, 1)
1955+ return
1956+
1957+
1958+ # close the window and quit
1959+ def delete_event(self, widget, data=None):
1960+ gtk.main_quit()
1961+ return False
1962+
1963+ def __init__(self):
1964+
1965+ ##For now TERM is hardcoded to xterm because of a change
1966+ ##in libvte in Ubuntu Maverick
1967+ os.putenv('TERM', 'xterm')
1968+ ## copy config file to user $HOME if does not exist
1969+ self.setup()
1970+
1971+ #TODO: do we want to do this? Or just keep the height under 600.
1972+ ##Get user screen size##
1973+ #screen = gtk.gdk.display_get_default().get_default_screen()
1974+ #screen_size = screen.get_monitor_geometry(0)
1975+ #height = screen.get_height() ## screen height ##
1976+
1977+ ## Create UI widgets
1978+ self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
1979+ liststore = gtk.ListStore(str, str, str)
1980+ treeview = gtk.TreeView()
1981+ expander = gtk.Expander()
1982+ self.scrolledwindow = gtk.ScrolledWindow()
1983+ notebook = gtk.Notebook()
1984+
1985+ ## set sizes and borders
1986+ self.scrolledwindow.set_size_request(700, 220)
1987+ self.window.set_default_size(700, 625)
1988+ self.window.set_border_width(10)
1989+ ## Sets the position of the window relative to the screen
1990+ self.window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
1991+ ## Allow user to resize window
1992+ self.window.set_resizable(True)
1993+
1994+ ## set Window title and icon
1995+ self.window.set_title("CLI Companion")
1996+ icon = gtk.gdk.pixbuf_new_from_file("/usr/share/pixmaps/clicompanion.16.png")
1997+ self.window.set_icon(icon)
1998+
1999+ # get commands and put in liststore
2000+ self.update(liststore)
2001+ ## create the TreeViewColumns to display the data
2002+ treeview.columns = [None]*3
2003+ treeview.columns[0] = gtk.TreeViewColumn(_('Command'))
2004+ treeview.columns[1] = gtk.TreeViewColumn(_('User Input'))
2005+ treeview.columns[2] = gtk.TreeViewColumn(_('Description'))
2006+
2007+ for n in range(3):
2008+ ## add columns to treeview
2009+ treeview.append_column(treeview.columns[n])
2010+ ## create a CellRenderers to render the data
2011+ treeview.columns[n].cell = gtk.CellRendererText()
2012+ ## add the cells to the columns
2013+ treeview.columns[n].pack_start(treeview.columns[n].cell,
2014+ True)
2015+ ## set the cell attributes to the appropriate liststore column
2016+ treeview.columns[n].set_attributes(
2017+ treeview.columns[n].cell, text=n)
2018+ treeview.columns[n].set_resizable(True)
2019+
2020+ #set treeview model and put treeview in the scrolled window and the scrolled window in the expander.
2021+ treeview.set_model(liststore)
2022+ self.scrolledwindow.add(treeview)
2023+ expander.add(self.scrolledwindow)
2024+ #self.window.show_all()
2025+
2026+ ## instantiate tabs
2027+ tabs = clicompanionlib.tabs.Tabs()
2028+ ## instantiate controller.Actions, where all the button actions are
2029+ actions = clicompanionlib.controller.Actions()
2030+ ## instantiate 'File' and 'Help' Drop Down Menu [menus_buttons.py]
2031+ bar = clicompanionlib.menus_buttons.FileMenu()
2032+ menu_bar = bar.the_menu(actions, notebook, liststore)
2033+
2034+
2035+ #get row of selection
2036+ def mark_selected(self, treeselection):
2037+ global ROW
2038+ (model, pathlist)=treeselection.get_selected_rows()
2039+ ROW = pathlist
2040+
2041+
2042+ selection = treeview.get_selection()
2043+ selection.set_mode(gtk.SELECTION_SINGLE)
2044+ selection.select_path(0)
2045+ selection.connect("changed", mark_selected, selection)
2046+
2047+
2048+ ## The search section
2049+ self.search_label = gtk.Label(_("Search:"))
2050+ self.search_label.set_alignment(xalign=-1, yalign=0)
2051+ self.search_box = gtk.Entry()
2052+ self.search_box.connect("changed", actions._filter_commands, liststore, treeview)
2053+ ## search box tooltip
2054+ self.search_box.set_tooltip_text(_("Search your list of commands"))
2055+ # Set the search box sensitive at program start, because expander is not
2056+ # unfolded by default
2057+ self.search_box.set_sensitive(False)
2058+ ## hbox for menu and search Entry
2059+ menu_search_hbox = gtk.HBox(False)
2060+ menu_search_hbox.pack_end(self.search_box, True)
2061+ menu_search_hbox.pack_end(self.search_label, False, False, 10)
2062+ menu_search_hbox.pack_start(menu_bar, True)
2063+
2064+
2065+ ## expander title
2066+ expander_hbox = gtk.HBox()
2067+ image = gtk.Image()
2068+ image.set_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
2069+ label = gtk.Label(_('Command List'))
2070+ ## tooltip for the label of the expander
2071+ expander_hbox.set_tooltip_text(_("Click to show/hide command list"))
2072+
2073+ ## add expander widget to hbox
2074+ expander_hbox.pack_start(image, False, False)
2075+ expander_hbox.pack_start(label, True, False)
2076+ expander.set_label_widget(expander_hbox)
2077+
2078+ ## Add the first tab with the Terminal
2079+ tabs.add_tab(self, notebook)
2080+ notebook.set_tab_pos(1)
2081+
2082+ ## The "Add Tab" tab
2083+ add_tab_button = gtk.Button("+")
2084+ ## tooltip for "Add Tab" tab
2085+ add_tab_button.set_tooltip_text(_("Click to add another Tab"))
2086+ ## create first tab
2087+ notebook.append_page(gtk.Label(""), add_tab_button)
2088+
2089+ ## buttons at bottom of main window [menus_buttons.py]
2090+ button_box = bar.buttons(actions, 10, gtk.BUTTONBOX_END, notebook, liststore)
2091+
2092+ ## vbox for search, notebook, buttonbar
2093+ self.vbox = gtk.VBox()
2094+ self.window.add(self.vbox)
2095+ ## pack everytyhing in the vbox
2096+ #self.vbox.pack_start(menu_bar, False, False, 0) ##menuBar
2097+ self.vbox.pack_start(menu_search_hbox, False, False, 5)
2098+ self.vbox.pack_start(expander, False, False, 5)
2099+ self.vbox.pack_start(notebook, True, True, 10)
2100+ self.vbox.pack_start(button_box, False, False, 5)
2101+
2102+ ## signals
2103+ expander.connect('notify::expanded', self.expanded_cb, notebook, treeview, liststore)
2104+ self.window.connect("delete_event", self.delete_event)
2105+ add_tab_button.connect("clicked", tabs.add_tab, notebook)
2106+ ## right click menu event capture
2107+ treeview.connect ("button_press_event", bar.right_click, actions, treeview, notebook, liststore)
2108+
2109+
2110+ #self.vte.grab_focus()
2111+ self.window.show_all()
2112+ return
2113+
2114+ def main(self):
2115+ try:
2116+ gtk.main()
2117+ except KeyboardInterrupt:
2118+ pass
2119+
2120+def run():
2121+
2122+ main_window = MainWindow()
2123+ main_window.main()
2124
2125=== added directory 'data'
2126=== added file 'data/clicompanion.16.png'
2127Binary 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
2128=== added file 'data/clicompanion.64.png'
2129Binary 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
2130=== added file 'data/clicompanion.desktop'
2131--- data/clicompanion.desktop 1970-01-01 00:00:00 +0000
2132+++ data/clicompanion.desktop 2010-11-30 16:11:27 +0000
2133@@ -0,0 +1,7 @@
2134+[Desktop Entry]
2135+Name=CLI Companion
2136+Comment=Run and store terminal commands from a GUI
2137+Categories=Utility;GTK;
2138+Exec=clicompanion
2139+Icon=clicompanion
2140+Type=Application
2141
2142=== added file 'data/clicompanion2.config'
2143--- data/clicompanion2.config 1970-01-01 00:00:00 +0000
2144+++ data/clicompanion2.config 2010-11-30 16:11:27 +0000
2145@@ -0,0 +1,48 @@
2146+dpkg -l ?:package:Find version of a package
2147+df -h::file system disk space usage
2148+free -m::show RAM usage
2149+ps auxww | grep ?:process:displays information about the active process
2150+iwconfig::Display wireless network information
2151+ifconfig -a::displays the status of the currently active interfaces
2152+sudo iwlist::scan Scan Wireless networks
2153+sudo /etc/init.d/networking restart::Reset the Network
2154+lsb_release -a::What version of Ubuntu do I have?
2155+uname -a::What kernel am I running
2156+sudo apt-get update && sudo apt-get upgrade::Refresh update info and update all packages
2157+sudo apt-get clean::clear out all packages in /var/cache/apt/archives
2158+sudo apt-get autoclean::clear out obsolete packages(packages with a newer release)
2159+apt-cache search ?:package:Find information on a package (not installed)
2160+sudo lshw::List hardware
2161+lspci::list all PCI devices
2162+aplay -l::List all soundcards and digital audio devices
2163+cat ?:path:Read File & Print to Standard Output
2164+ls ? :path:List Folders Contents
2165+ls -lSr ?:path:Show files by size, biggest last
2166+mv ?:path:Move (Rename) Files
2167+cp ?:path:Copy Files
2168+sudo lspci::attached PCI devices
2169+chmod ? ?:permissions, file:Change access permissions, change mode
2170+chown ? ?:owner,group, file:Change the owner and/or group of each given file
2171+dmesg::Print kernel & driver messages
2172+history::Command History
2173+locate ?:file:Find files (updatedb to update DB)
2174+sudo updatedb::update the database for locate
2175+which ?:command:Show full path name of command
2176+find -maxdepth 1 -type f | xargs grep -F ?:string:Search all regular files for 'string' in this dir
2177+gpg -c ?:file:Encypt a file
2178+gpg ?:file.gpg:Decrypt a file
2179+tar -xjf ?:archive.tar:Extract all files from archive.tar
2180+tar -czf ?:Destination.tar.gz Source:Create Destination from Source
2181+iostat::cpu and I/O statistics
2182+netstat::Print network connections and interface statistics
2183+sudo fdisk -l ?:disk:List partition tables for specified devices
2184+sudo ufw enable::Enable netfilter firewall
2185+sudo ufw allow ?:port:Open a port in netfilter firewall
2186+sudo ufw deny ?:port:Close a port in netfilter firewall
2187+sudo ufw disable::Disable netfilter firewall
2188+cat ? ? | sort | uniq > ? :file1, file2, file3:combine, sort and remove duplicates from 2 files
2189+mkisofs -V LABEL -r dir | gzip > ?:isoname.iso.gz:Create cdrom image(iso) from contents of directory(pwd)
2190+cdrecord -v dev=/dev/cdrom -audio -pad *.wav::Make audio CD from all wavs in current dir(pwd)
2191+dpkg-query -W -f='${Installed-Size;10}\t${Package}\n' | sort -k1,1n::List all installed packages by size
2192+tail -f /var/log/messages::Monitor messages log file
2193+apropos ?:command or package:search the manual page names and descriptions
2194
2195=== added file 'setup.py'
2196--- setup.py 1970-01-01 00:00:00 +0000
2197+++ setup.py 2010-11-30 16:11:27 +0000
2198@@ -0,0 +1,42 @@
2199+#!/usr/bin/env python
2200+#
2201+# Copyright 2010 Duane Hinnen
2202+#
2203+#
2204+# This program is free software: you can redistribute it and/or modify it
2205+# under the terms of the GNU General Public License version 3, as published
2206+# by the Free Software Foundation.
2207+#
2208+# This program is distributed in the hope that it will be useful, but
2209+# WITHOUT ANY WARRANTY; without even the implied warranties of
2210+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2211+# PURPOSE. See the GNU General Public License for more details.
2212+#
2213+# You should have received a copy of the GNU General Public License along
2214+# with this program. If not, see <http://www.gnu.org/licenses/>.
2215+#
2216+#
2217+
2218+import glob
2219+from distutils.core import setup
2220+from DistUtilsExtra.command import *
2221+
2222+
2223+
2224+setup( name='clicompanion',
2225+ version='0.1.0',
2226+ description='Run Terminal commands from a GUI. Store commands for later use.',
2227+ author='Duane Hinnen',
2228+ author_email='duanedesign@gmail.com',
2229+ scripts=['clicompanion'],
2230+ packages=['clicompanionlib'],
2231+ data_files=[('/etc/clicompanion.d/', ['data/clicompanion2.config']),
2232+ ('/usr/share/pixmaps', ['data/clicompanion.16.png']),
2233+ ('/usr/share/applications', ['data/clicompanion.desktop']),
2234+ ('share/clicompanion/locale/', glob.glob('locale/*/LC_MESSAGES/*.mo')),
2235+ ],
2236+
2237+ cmdclass = { 'build' : build_extra.build_extra,
2238+ 'build_i18n' : build_i18n.build_i18n,
2239+ },
2240+ )

Subscribers

People subscribed via source and target branches