fixed: plot does not display on Windows at program launch (troubleshooting issue 1)
[hooke.git] / hooke_cli.py
1 #!/usr/bin/env python
2
3 '''
4 hooke_cli.py
5
6 Command line module of Hooke.
7
8 Copyright (C) 2006 Massimo Sandal (University of Bologna, Italy).
9
10 This program is released under the GNU General Public License version 2.
11 '''
12
13
14 from libhooke import * #FIXME
15 import libhookecurve as lhc
16
17 import libinput as linp
18 import liboutlet as lout
19
20 from libhooke import WX_GOOD
21 from libhooke import HOOKE_VERSION
22
23 import wxversion
24 wxversion.select(WX_GOOD)
25 import wx
26
27 from wx.lib.newevent import NewEvent
28 from matplotlib.numerix import * #FIXME
29
30 import xml.dom.minidom
31 import sys, os, os.path, glob, shutil
32 import Queue
33 import cmd
34 import time
35
36 global __version__
37 global __codename__
38 global __releasedate__
39 __version__ = HOOKE_VERSION[0]
40 __codename__ = HOOKE_VERSION[1]
41 __releasedate__ = HOOKE_VERSION[2]
42
43 from matplotlib import __version__ as mpl_version
44 from wx import __version__ as wx_version
45 from wxmpl import __version__ as wxmpl_version
46 from scipy import __version__ as scipy_version
47 from numpy import __version__ as numpy_version
48 from sys import version as python_version
49 import platform
50
51
52 class HookeCli(cmd.Cmd):
53     
54     def __init__(self,frame,list_of_events,events_from_gui,config,drivers):
55         cmd.Cmd.__init__(self)
56                        
57         self.prompt = 'hooke: '
58         
59         
60         self.current_list=[] #the playlist we're using
61         
62         self.current=None    #the current curve under analysis. 
63         self.plots=None
64         '''
65         The actual hierarchy of the "current curve" is a bit complex:
66         
67         self.current = the lhc.HookeCurve container object of the current curve
68         self.current.curve = the current "real" curve object as defined in the filetype driver class
69         self.current.curve.default_plots() = the default plots of the filetype driver.
70         
71         The plot objects obtained by mean of self.current.curve.default_plots() 
72         then undergoes modifications by the plotmanip
73         modifier functions. The modified plot is saved in self.plots and used if needed by other functions.       
74         '''
75         
76         
77         self.pointer=0       #a pointer to navigate the current list
78                         
79         #Things that come from outside
80         self.frame=frame                        #the wx frame we refer to
81         self.list_of_events=list_of_events      #a list of wx events we use to interact with the GUI
82         self.events_from_gui=events_from_gui    #the Queue object we use to have messages from the GUI
83         self.config=config                      #the configuration dictionary
84         self.drivers=drivers                    #the file format drivers
85         
86         #get plot manipulation functions
87         plotmanip_functions=[]
88         for object_name in dir(self):
89                 if object_name[0:9]=='plotmanip':
90                     plotmanip_functions.append(getattr(self,object_name))
91         #put plotmanips in order
92         self.plotmanip=[None for item in self.config['plotmanips']]
93         for item in plotmanip_functions:
94             namefunction=item.__name__[10:]
95             if namefunction in self.config['plotmanips']:
96                 nameindex=self.config['plotmanips'].index(namefunction) #index of function in plotmanips config
97                 self.plotmanip[nameindex] = item
98             else:
99                 pass
100            
101             
102         self.playlist_saved=0 #Did we save the playlist?
103         self.playlist_name='' #Name of playlist
104         self.notes_saved=1 #Did we save the notes?
105         self.notes_filename=None #Name of notes
106
107         #create outlet
108         self.outlet=lout.Outlet()
109         
110         #Data that must be saved in the playlist, related to the whole playlist (not individual curves)
111         self.playlist_generics={} 
112         
113         #make sure we execute _plug_init() for every command line plugin we import
114         for plugin_name in self.config['plugins']:
115             try:
116                 plugin=__import__(plugin_name)
117                 try:
118                     eval('plugin.'+plugin_name+'Commands._plug_init(self)')
119                 except AttributeError:
120                     pass
121             except ImportError:
122                 pass
123
124         #load default list, if possible
125         self.do_loadlist(self.config['defaultlist'])
126         
127 #HELPER FUNCTIONS
128 #Everything sending an event should be here
129     def _measure_N_points(self, N, whatset=1):
130         '''
131         general helper function for N-points measures
132         '''
133         wx.PostEvent(self.frame,self.list_of_events['measure_points'](num_of_points=N, set=whatset))
134         while 1:
135             try:
136                 points=self.frame.events_from_gui.get()
137                 break
138             except Empty:
139                 pass
140         return points
141         
142     def _get_displayed_plot(self,dest=0):
143         '''
144         returns the currently displayed plot.
145         '''
146         wx.PostEvent(self.frame, self.list_of_events['get_displayed_plot'](dest=dest))
147         while 1:
148             try:
149                 displayed_plot=self.events_from_gui.get()
150             except Empty:
151                 pass
152             if displayed_plot:
153                 break
154         return displayed_plot
155     
156     def _send_plot(self,plots):
157         '''
158         sends a plot to the GUI
159         '''
160         wx.PostEvent(self.frame, self.list_of_events['plot_graph'](plots=plots))
161         return
162         
163     def _find_plotmanip(self, name):
164         '''
165         returns a plot manipulator function from its name
166         '''
167         return self.plotmanip[self.config['plotmanips'].index(name)]
168     
169     def _clickize(self, xvector, yvector, index):
170         '''
171         returns a ClickedPoint() object from an index and vectors of x, y coordinates       
172         '''
173         point=ClickedPoint()
174         point.index=index
175         point.absolute_coords=xvector[index],yvector[index]
176         point.find_graph_coords(xvector,yvector)
177         return point
178     
179 #HERE COMMANDS BEGIN
180     
181     def help_set(self):
182         print '''
183 SET
184 Sets a local configuration variable
185 -------------
186 Syntax: set [variable] [value]
187         '''
188     def do_set(self,args):
189         #FIXME: some variables in self.config should be hidden or intelligently configurated...
190         args=args.split()
191         if len(args)==0:
192             print 'You must specify a variable and a value'
193             print 'Available variables:'
194             print self.config.keys()
195             return
196         if args[0] not in self.config.keys():
197             print 'This is not an internal Hooke variable!'
198             return
199         if len(args)==1:
200             #FIXME:we should reload the config file and reset the config value
201             print self.config[args[0]]
202             return
203         key=args[0]
204         try: #try to have a numeric value
205             value=float(args[1])
206         except ValueError: #if it cannot be converted to float, it's None, or a string...
207             if value.lower()=='none':
208                 value=None
209             else:
210                 value=args[1]
211                 
212         self.config[key]=value
213         self.do_plot(0)
214         
215 #PLAYLIST MANAGEMENT AND NAVIGATION
216 #------------------------------------
217     
218     def help_loadlist(self):
219         print '''
220 LOADLIST
221 Loads a file playlist
222 -----------
223 Syntax: loadlist [playlist file]
224         '''
225     def do_loadlist(self, args):
226         #checking for args: if nothing is given as input, we warn and exit.
227         while len(args)==0:
228             args=linp.safeinput('File to load?')
229         
230         arglist=args.split()
231         play_to_load=arglist[0]
232         
233         #We assume a Hooke playlist has the extension .hkp
234         if play_to_load[-4:] != '.hkp':
235             play_to_load+='.hkp'
236         
237         try:            
238             playxml=PlaylistXML()
239             self.current_list, self.playlist_generics=playxml.load(play_to_load)
240             self.current_playxml=playxml
241         except IOError:
242             print 'File not found.'
243             return
244         
245         print 'Loaded %s curves' %len(self.current_list)
246         
247         if 'pointer' in self.playlist_generics.keys():
248             self.pointer=int(self.playlist_generics['pointer'])
249         else:
250             #if no pointer is found, set the current curve as the first curve of the loaded playlist
251             self.pointer=0
252         print 'Starting at curve ',self.pointer
253             
254         self.current=self.current_list[self.pointer]
255         
256         #resets saved/notes saved state
257         self.playlist_saved=0
258         self.playlist_name=''
259         self.notes_saved=0        
260     
261         self.do_plot(0)
262         
263         
264     def help_genlist(self):
265         print '''
266 GENLIST
267 Generates a file playlist.
268 Note it doesn't *save* it: see savelist for this.
269
270 If [input files] is a directory, it will use all files in the directory for playlist.
271 So:
272 genlist dir
273 genlist dir/
274 genlist dir/*.*
275
276 are all equivalent syntax.
277 ------------
278 Syntax: genlist [input files]
279         
280 '''
281     def do_genlist(self,args):
282         #args list is: input path, output name
283         if len(args)==0:
284             args=linp.safeinput('Input files?')
285                     
286         arglist=args.split()      
287         list_path=arglist[0]
288                   
289         #if it's a directory, is like /directory/*.*
290         #FIXME: probably a bit kludgy.
291         if os.path.isdir(list_path): 
292             if platform.system == 'Windows':
293                 SLASH="\\"
294             else:
295                 SLASH="/"
296             if list_path[-1] == SLASH:
297                 list_path=list_path+'*.*'
298             else:    
299                 list_path=list_path+SLASH+'*.*'
300         
301         #expanding correctly the input list with the glob module :)        
302         list_files=glob.glob(list_path)
303         list_files.sort()
304
305         self.current_list=[]
306         for item in list_files:
307             try:
308                 if os.path.isfile(item):
309                     self.current_list.append(lhc.HookeCurve(os.path.abspath(item))) 
310             except:
311                 pass
312             
313         self.pointer=0    
314         if len(self.current_list)>0:
315             self.current=self.current_list[self.pointer]
316         else:
317             print 'Empty list!'
318             return
319         
320         #resets saved/notes saved state
321         self.playlist_saved=0
322         self.playlist_name=''
323         self.notes_saved=0  
324         
325         self.do_plot(0)
326        
327         
328     def do_savelist(self,args):
329         '''
330         SAVELIST
331         Saves the current file playlist on disk.
332         ------------
333         Syntax: savelist [filename]
334         '''
335         while len(args)==0:
336             args=linp.safeinput('Output file?',['savedlist.txt'])
337     
338         output_filename=args
339         
340         self.playlist_generics['pointer']=self.pointer
341         
342         #autocomplete filename if not specified
343         if output_filename[-4:] != '.hkp':
344             output_filename+='.hkp'
345         
346         playxml=PlaylistXML()
347         playxml.export(self.current_list, self.playlist_generics)
348         playxml.save(output_filename)                  
349         
350         #remembers we have saved playlist
351         self.playlist_saved=1
352         
353     def help_addtolist(self):
354         print '''
355 ADDTOLIST
356 Adds a file to the current playlist
357 --------------
358 Syntax: addtolist [filename]
359 '''
360     def do_addtolist(self,args):
361         #args list is: input path
362         if len(args)==0:
363             print 'You must give the input filename you want to add'
364             self.help_addtolist()
365             return
366           
367         filenames=glob.glob(args)
368         
369         for filename in filenames:
370             self.current_list.append(lhc.HookeCurve(os.path.abspath(filename)))
371         #we need to save playlist
372         self.playlist_saved=0
373     
374     def help_printlist(self):
375         print '''
376 PRINTLIST
377 Prints the list of curves in the current playlist
378 -------------
379 Syntax: printlist
380 '''
381     def do_printlist(self,args):
382         for item in self.current_list:
383             print item.path
384             
385     
386     def help_jump(self):
387         print '''
388 JUMP
389 Jumps to a given curve.
390 ------
391 Syntax: jump {$curve}
392
393 If the curve is not in the current playlist, it politely asks if we want to add it.
394         '''  
395     def do_jump(self,filename):
396         '''
397         jumps to the curve with the given filename.
398         if the filename is not in the playlist, it asks if we must add it or not.
399         '''
400         
401         if filename=='':
402             filename=linp.safeinput('Jump to?')
403             
404         filepath=os.path.abspath(filename)
405         print filepath
406                 
407         c=0
408         item_not_found=1
409         while item_not_found:
410             try:
411                 
412                 if self.current_list[c].path == filepath:
413                     self.pointer=c
414                     self.current=self.current_list[self.pointer]
415                     item_not_found=0
416                     self.do_plot(0)
417                 else:
418                     c+=1  
419             except IndexError:
420                 #We've found the end of the list.
421                 answer=linp.safeinput('Curve not found in playlist. Add it to list?',['y'])
422                 if answer.lower()[0]=='y':
423                     try:
424                         self.do_addtolist(filepath)
425                     except:
426                         print 'Curve file not found.'
427                         return
428                     self.current=self.current_list[-1]
429                     self.pointer=(len(current_list)-1)
430                     self.do_plot(0)
431                     
432                 item_not_found=0
433     
434     
435     def do_index(self,args):
436         '''
437         INDEX
438         Prints the index of the current curve in the list
439         -----
440         Syntax: index
441         '''
442         print self.pointer+1, 'of', len(self.current_list) 
443     
444     
445     def help_next(self):
446         print '''
447 NEXT
448 Go the next curve in the playlist.
449 If we are at the last curve, we come back to the first.
450 -----
451 Syntax: next, n
452         '''
453     def do_next(self,args):
454         try:
455             self.current.curve.close_all()
456         except:
457             print 'No curve file loaded, currently!'
458             print 'This should not happen, report to http://code.google.com/p/hooke'
459             return
460         
461         if self.pointer == (len(self.current_list)-1):
462             self.pointer=0
463             print 'Playlist finished; back to first curve.'
464         else:
465             self.pointer+=1
466         
467         self.current=self.current_list[self.pointer]
468         self.do_plot(0)
469         
470     
471     def help_n(self):
472         self.help_next()
473     def do_n(self,args):
474         self.do_next(args)
475         
476     def help_previous(self,args):
477         print '''
478 PREVIOUS
479 Go to the previous curve in the playlist.
480 If we are at the first curve, we jump to the last.
481 -------
482 Syntax: previous, p
483     '''
484     def do_previous(self,args):
485         try:
486             self.current.curve.close_all()
487         except:
488             print 'No curve file loaded, currently!'
489             print 'This should not happen, report to http://code.google.com/p/hooke'
490             return
491         if self.pointer == 0:
492             self.pointer=(len(self.current_list)-1)
493             print 'Start of playlist; jump to last curve.' 
494         else:
495             self.pointer-=1
496             
497         self.current=self.current_list[self.pointer]
498         self.do_plot(args)
499         
500             
501     def help_p(self):
502         self.help_previous()
503     def do_p(self,args):
504         self.do_previous(args)
505
506         
507 #PLOT INTERACTION COMMANDS
508 #-------------------------------    
509     def help_plot(self):
510         print '''
511 PLOT
512 Plots the current force curve
513 -------
514 Syntax: plot
515         '''
516     def do_plot(self,args):
517         
518         self.current.identify(self.drivers)
519         self.plots=self.current.curve.default_plots()
520         try:
521             self.plots=self.current.curve.default_plots()
522         except Exception, e:
523             print 'Unexpected error occurred in do_plot().'
524             print e
525             return
526             
527         #apply the plotmanip functions eventually present
528         nplots=len(self.plots)
529         c=0
530         while c<nplots:
531             for function in self.plotmanip: #FIXME: something strange happens about self.plotmanip[0]
532                 self.plots[c]=function(self.plots[c], self.current)
533                 
534             self.plots[c].xaxes=self.config['xaxes'] #FIXME: in the future, xaxes and yaxes should be set per-plot
535             self.plots[c].yaxes=self.config['yaxes']
536                 
537             c+=1
538
539         self._send_plot(self.plots)
540         
541     def _delta(self, set=1):
542         '''
543         calculates the difference between two clicked points
544         '''
545         print 'Click two points'
546         points=self._measure_N_points(N=2, whatset=set)
547         dx=abs(points[0].graph_coords[0]-points[1].graph_coords[0])
548         dy=abs(points[0].graph_coords[1]-points[1].graph_coords[1])
549         unitx=self.plots[points[0].dest].units[0]
550         unity=self.plots[points[0].dest].units[1]
551         return dx,unitx,dy,unity
552         
553     def do_delta(self,args):
554         '''
555         DELTA
556         
557         Measures the delta X and delta Y between two points.
558         ----
559         Syntax: delta
560         '''
561         dx,unitx,dy,unity=self._delta()
562         print str(dx)+' '+unitx
563         print str(dy)+' '+unity
564     
565     def _point(self, set=1):
566         '''calculates the coordinates of a single clicked point'''
567
568         print 'Click one point'
569         point=self._measure_N_points(N=1, whatset=set)
570         
571         x=point[0].graph_coords[0]
572         y=point[0].graph_coords[1]
573         unitx=self.plots[point[0].dest].units[0]
574         unity=self.plots[point[0].dest].units[1]
575         return x,unitx,y,unity
576         
577     def do_point(self,args):
578         '''
579         POINT
580         
581         Returns the coordinates of a point on the graph.
582         ----
583         Syntax: point
584         '''
585         x,unitx,y,unity=self._point()
586         print str(x)+' '+unitx
587         print str(y)+' '+unity
588         to_dump='point '+self.current.path+' '+str(x)+' '+unitx+', '+str(y)+' '+unity
589         self.outlet.push(to_dump)    
590    
591         
592     def do_close(self,args=None):
593         '''
594         CLOSE
595         Closes one of the two plots. If no arguments are given, the bottom plot is closed.
596         ------
597         Syntax: close [top,bottom]
598         '''
599         if args=='top':
600             to_close=0
601         elif args=='bottom':
602             to_close=1
603         else:
604             to_close=1
605         
606         close_plot=self.list_of_events['close_plot']
607         wx.PostEvent(self.frame, close_plot(to_close=to_close))
608         
609     def do_show(self,args=None):
610         '''
611         SHOW
612         Shows both plots.
613         ''' 
614         show_plots=self.list_of_events['show_plots']
615         wx.PostEvent(self.frame, show_plots())
616        
617         
618     
619     #PLOT EXPORT AND MANIPULATION COMMANDS
620     def help_export(self):
621         print '''
622 EXPORT
623 Saves the current plot as an image file
624 ---------------
625 Syntax: export [filename] {plot to export}
626
627 The supported formats are PNG and EPS; the file extension of the filename is automatically recognized
628 and correctly exported. Resolution is (for now) fixed at 150 dpi.
629
630 If you have a multiple plot, the optional plot to export argument tells Hooke which plot you want to export. If 0, the top plot is exported. If 1, the bottom plot is exported (Exporting both plots is still to implement)
631         '''
632     def do_export(self,args):
633         #FIXME: the bottom plot doesn't have the title
634         
635         dest=0
636         
637         if len(args)==0:
638             #FIXME: We have to go into the libinput stuff and fix it, for now here's a dummy replacement...
639             #name=linp.safeinput('Filename?',[self.current.path+'.png'])
640             name=raw_input('Filename? ')
641         else:
642             args=args.split()
643             name=args[0]
644             if len(args) > 1:
645                 dest=int(args[1]) 
646                 
647         export_image=self.list_of_events['export_image']
648         wx.PostEvent(self.frame, export_image(name=name, dest=dest))
649         
650         
651     def help_txt(self):
652         print '''
653 TXT
654 Saves the current curve as a text file
655 Columns are, in order:
656 X1 , Y1 , X2 , Y2 , X3 , Y3 ...
657
658 -------------
659 Syntax: txt [filename] {plot to export}
660         '''
661     def do_txt(self,args):
662         
663         def transposed2(lists, defval=0):
664             '''
665             transposes a list of lists, i.e. from [[a,b,c],[x,y,z]] to [[a,x],[b,y],[c,z]] without losing
666             elements
667             (by Zoran Isailovski on the Python Cookbook online)
668             '''
669             if not lists: return []
670             return map(lambda *row: [elem or defval for elem in row], *lists)
671         
672         whichplot=0
673         args=args.split()
674         if len(args)==0:
675             filename=linp.safeinput('Filename?',[self.current.path+'.txt'])
676         else:
677             filename=linp.checkalphainput(args[0],self.current.path+'.txt',[])
678             try:
679                 whichplot=int(args[1])
680             except:
681                 pass
682             
683         columns=[]     
684         for dataset in self.plots[whichplot].vectors:
685             for i in range(0,len(dataset)): 
686                 columns.append([])
687                 for value in dataset[i]:
688                     columns[-1].append(str(value))                   
689         
690         rows=transposed2(columns, 'nan')
691         rows=[' , '.join(item) for item in rows]
692         text='\n'.join(rows)
693         
694         txtfile=open(filename,'w+')
695         #Save units of measure in header
696         txtfile.write('X:'+self.plots[whichplot].units[0]+'\n')
697         txtfile.write('Y:'+self.plots[whichplot].units[1]+'\n')
698         txtfile.write(text)
699         txtfile.close()
700         
701     
702     #LOGGING, REPORTING, NOTETAKING
703     
704
705     def do_note_old(self,args):
706         '''
707         NOTE_OLD
708         **deprecated**: Use note instead. Will be removed in 0.9
709         
710         Writes or displays a note about the current curve.
711         If [anything] is empty, it displays the note, otherwise it adds a note.
712         The note is then saved in the playlist if you issue a savelist command
713         ---------------
714         Syntax: note_old [anything]        
715
716         '''
717         if args=='':
718             print self.current_list[self.pointer].notes
719         else:
720             #bypass UnicodeDecodeError troubles
721             try:
722                 args=args.decode('ascii')
723             except:
724                 args=args.decode('ascii','ignore')
725                 if len(args)==0:
726                     args='?'
727                     
728             self.current_list[self.pointer].notes=args
729         self.notes_saved=0
730             
731             
732     def do_note(self,args):
733         '''
734         NOTE
735         
736         Writes or displays a note about the current curve.
737         If [anything] is empty, it displays the note, otherwise it adds a note.
738         The note is then saved in the playlist if you issue a savelist command.
739         ---------------
740         Syntax: note_old [anything]        
741
742         '''
743         if args=='':
744             print self.current_list[self.pointer].notes
745         else:
746             if self.notes_filename == None:
747                 self.notes_filename=raw_input('Notebook filename? ')
748                 title_line='Notes taken at '+time.asctime()+'\n'
749                 f=open(self.notes_filename,'w')
750                 f.write(title_line)
751                 f.close()
752                 
753             #bypass UnicodeDecodeError troubles    
754             try:
755                args=args.decode('ascii')
756             except:
757                args=args.decode('ascii','ignore')
758                if len(args)==0:
759                    args='?'
760             self.current_list[self.pointer].notes=args
761             
762             f=open(self.notes_filename,'a+')
763             note_string=(self.current.path+'  |  '+self.current.notes+'\n')
764             f.write(note_string)
765             f.close()
766                            
767     def help_notelog(self):
768         print '''
769 NOTELOG
770 Writes a log of the notes taken during the session for the current
771 playlist
772 --------------        
773 Syntax notelog [filename]
774 '''        
775     def do_notelog(self,args):
776         
777         if len(args)==0:
778             args=linp.safeinput('Notelog filename?',['notelog.txt'])
779             
780         note_lines='Notes taken at '+time.asctime()+'\n'
781         for item in self.current_list:
782             if len(item.notes)>0:
783                 #FIXME: log should be justified
784                 #FIXME: file path should be truncated...
785                 note_string=(item.path+'  |  '+item.notes+'\n')
786                 note_lines+=note_string
787                 
788         try:
789             f=open(args,'a+')
790             f.write(note_lines)
791             f.close()
792         except IOError, (ErrorNumber, ErrorMessage):
793             print 'Error: notes cannot be saved. Catched exception:'
794             print ErrorMessage
795         
796         self.notes_saved=1
797
798     def help_copylog(self):
799         print '''
800 COPYLOG
801 Moves the annotated curves to another directory
802 -----------
803 Syntax copylog [directory]
804         '''
805     def do_copylog(self,args):
806         
807         if len(args)==0:
808             args=linp.safeinput('Destination directory?')  #TODO default
809         
810         mydir=os.path.abspath(args)
811         if not os.path.isdir(mydir):
812             print 'Destination is not a directory.'
813             return
814         
815         for item in self.current_list:
816             if len(item.notes)>0:
817                 try:
818                     shutil.copy(item.path, mydir)
819                 except (OSError, IOError):
820                     print 'Cannot copy file. '+item.path+' Perhaps you gave me a wrong directory?'
821
822 #OUTLET management
823 #-----------------
824     def do_outlet_show(self,args):
825         '''OUTLET_SHOW
826         ---------
827         Shows current content of outlet with index for reference
828         '''
829         self.outlet.printbuf()
830
831     def do_outlet_undo(self, args):
832         '''OUTLET_UNDO
833         ---------
834         Eliminates last entry in outlet
835         '''
836         print 'Erasing last entry'
837         self.outlet.pop()
838
839     def do_outlet_delete(self, args):
840         '''OUTLET_DELETE
841         Eliminates a particular entry from outlet
842         Syntax: outlet_delete n
843         '''
844         if len(args)==0:
845             print 'Index needed!, use outlet_show to know it'
846         else:
847             self.outlet.delete(args)
848
849 #OS INTERACTION COMMANDS
850 #-----------------    
851     def help_dir(self):
852         print '''
853 DIR, LS
854 Lists the files in the directory
855 ---------
856 Syntax: dir [path]
857           ls  [path]
858         '''
859     def do_dir(self,args):
860         
861         if len(args)==0:
862             args='*'
863         print glob.glob(args)
864         
865     def help_ls(self):
866         self.help_dir(self)
867     def do_ls(self,args):
868         self.do_dir(args)
869         
870     def help_pwd(self):
871         print '''
872 PWD
873 Gives the current working directory.
874 ------------
875 Syntax: pwd
876         '''
877     def do_pwd(self,args):
878         print os.getcwd()         
879     
880     def help_cd(self):
881         print '''
882 CD
883 Changes the current working directory
884 -----
885 Syntax: cd
886         '''
887     def do_cd(self,args):
888         mypath=os.path.abspath(args)
889         try:
890             os.chdir(mypath)
891         except OSError:
892             print 'I cannot access that directory.'
893     
894     
895     def help_system(self):
896         print '''
897 SYSTEM
898 Executes a system command line and reports the output
899 -----
900 Syntax system [command line]
901         '''
902         pass
903     def do_system(self,args):
904         waste=os.system(args)           
905             
906     def do_debug(self,args):
907         '''
908         this is a dummy command where I put debugging things
909         '''
910         print self.config['plotmanips']
911         pass
912             
913     def help_current(self):
914         print '''
915 CURRENT
916 Prints the current curve path.
917 ------
918 Syntax: current
919         '''
920     def do_current(self,args):
921         print self.current.path
922         
923     def do_info(self,args):
924         '''
925         INFO
926         ----
927         Returns informations about the current curve.
928         '''
929         print 'Path: ',self.current.path
930         print 'Experiment: ',self.current.curve.experiment
931         print 'Filetype: ',self.current.curve.filetype
932         for plot in self.current.curve.default_plots():
933             for set in plot.vectors:
934                 lengths=[len(item) for item in set]
935                 print 'Data set size: ',lengths
936         
937     def do_version(self,args):
938         '''
939         VERSION
940         ------
941         Prints the current version and codename, plus library version. Useful for debugging.
942         '''     
943         print 'Hooke '+__version__+' ('+__codename__+')'
944         print 'Released on: '+__releasedate__
945         print '---'
946         print 'Python version: '+python_version
947         print 'WxPython version: '+wx_version
948         print 'wxMPL version: '+wxmpl_version
949         print 'Matplotlib version: '+mpl_version
950         print 'SciPy version: '+scipy_version
951         print 'NumPy version: '+numpy_version
952         print '---'
953         print 'Platform: '+str(platform.uname())
954         print '---'
955         print 'Loaded plugins:',self.config['loaded_plugins']
956         
957     def help_exit(self):
958         print '''
959 EXIT, QUIT
960 Exits the program cleanly.
961 ------
962 Syntax: exit
963 Syntax: quit
964 '''    
965     def do_exit(self,args):
966         we_exit='N'
967         
968         if (not self.playlist_saved) or (not self.notes_saved):
969             we_exit=linp.safeinput('You did not save your playlist and/or notes. Exit?',['n'])
970         else:
971             we_exit=linp.safeinput('Exit?',['y'])
972         
973         if we_exit[0].upper()=='Y':
974             wx.CallAfter(self.frame.Close)
975             sys.exit(0)
976         else:
977             return
978     
979     def help_quit(self):
980         self.help_exit()
981     def do_quit(self,args):
982         self.do_exit(args)
983
984
985
986
987
988 if __name__ == '__main__':
989     mycli=HookeCli(0)
990     mycli.cmdloop()