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