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