Removed sha-bang from non-executable python files + whitespace cleanups.
[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 * #FIXME
14 import libhookecurve as lhc
15
16 import libinput as linp
17 import liboutlet as lout
18
19 from libhooke import WX_GOOD
20 from libhooke import HOOKE_VERSION
21
22 import wxversion
23 wxversion.select(WX_GOOD)
24 import wx
25
26 from wx.lib.newevent import NewEvent
27 from matplotlib.numerix import * #FIXME
28
29 import xml.dom.minidom
30 import sys, os, os.path, glob, shutil
31 import Queue
32 import cmd
33 import time
34
35 global __version__
36 global __codename__
37 global __releasedate__
38 __version__ = HOOKE_VERSION[0]
39 __codename__ = HOOKE_VERSION[1]
40 __releasedate__ = HOOKE_VERSION[2]
41
42 from matplotlib import __version__ as mpl_version
43 from wx import __version__ as wx_version
44 from wxmpl import __version__ as wxmpl_version
45 from scipy import __version__ as scipy_version
46 from numpy import __version__ as numpy_version
47 from sys import version as python_version
48 import platform
49
50
51 class HookeCli(cmd.Cmd):
52
53     def __init__(self,frame,list_of_events,events_from_gui,config,drivers):
54         cmd.Cmd.__init__(self)
55
56         self.prompt = 'hooke: '
57
58
59         self.current_list=[] #the playlist we're using
60
61         self.current=None    #the current curve under analysis.
62         self.plots=None
63         '''
64         The actual hierarchy of the "current curve" is a bit complex:
65
66         self.current = the lhc.HookeCurve container object of the current curve
67         self.current.curve = the current "real" curve object as defined in the filetype driver class
68         self.current.curve.default_plots() = the default plots of the filetype driver.
69
70         The plot objects obtained by mean of self.current.curve.default_plots()
71         then undergoes modifications by the plotmanip
72         modifier functions. The modified plot is saved in self.plots and used if needed by other functions.
73         '''
74
75
76         self.pointer=0       #a pointer to navigate the current list
77
78         #Things that come from outside
79         self.frame=frame                        #the wx frame we refer to
80         self.list_of_events=list_of_events      #a list of wx events we use to interact with the GUI
81         self.events_from_gui=events_from_gui    #the Queue object we use to have messages from the GUI
82         self.config=config                      #the configuration dictionary
83         self.drivers=drivers                    #the file format drivers
84
85         #get plot manipulation functions
86         plotmanip_functions=[]
87         for object_name in dir(self):
88                 if object_name[0:9]=='plotmanip':
89                     plotmanip_functions.append(getattr(self,object_name))
90         #put plotmanips in order
91         self.plotmanip=[None for item in self.config['plotmanips']]
92         for item in plotmanip_functions:
93             namefunction=item.__name__[10:]
94             if namefunction in self.config['plotmanips']:
95                 nameindex=self.config['plotmanips'].index(namefunction) #index of function in plotmanips config
96                 self.plotmanip[nameindex] = item
97             else:
98                 pass
99
100
101         self.playlist_saved=0 #Did we save the playlist?
102         self.playlist_name='' #Name of playlist
103         self.notes_saved=1 #Did we save the notes?
104         self.notes_filename=None #Name of notes
105
106         #create outlet
107         self.outlet=lout.Outlet()
108
109         #Data that must be saved in the playlist, related to the whole playlist (not individual curves)
110         self.playlist_generics={}
111
112         #make sure we execute _plug_init() for every command line plugin we import
113         for plugin_name in self.config['plugins']:
114             try:
115                 plugin=__import__(plugin_name)
116                 try:
117                     eval('plugin.'+plugin_name+'Commands._plug_init(self)')
118                 except AttributeError:
119                     pass
120             except ImportError:
121                 pass
122
123         #load default list, if possible
124         self.do_loadlist(self.config['defaultlist'])
125
126 #HELPER FUNCTIONS
127 #Everything sending an event should be here
128     def _measure_N_points(self, N, whatset=1):
129         '''
130         general helper function for N-points measures
131         '''
132         wx.PostEvent(self.frame,self.list_of_events['measure_points'](num_of_points=N, set=whatset))
133         while 1:
134             try:
135                 points=self.frame.events_from_gui.get()
136                 break
137             except Empty:
138                 pass
139         return points
140
141     def _get_displayed_plot(self,dest=0):
142         '''
143         returns the currently displayed plot.
144         '''
145         wx.PostEvent(self.frame, self.list_of_events['get_displayed_plot'](dest=dest))
146         while 1:
147             try:
148                 displayed_plot=self.events_from_gui.get()
149             except Empty:
150                 pass
151             if displayed_plot:
152                 break
153         return displayed_plot
154
155     def _send_plot(self,plots):
156         '''
157         sends a plot to the GUI
158         '''
159         wx.PostEvent(self.frame, self.list_of_events['plot_graph'](plots=plots))
160         return
161
162     def _find_plotmanip(self, name):
163         '''
164         returns a plot manipulator function from its name
165         '''
166         return self.plotmanip[self.config['plotmanips'].index(name)]
167
168     def _clickize(self, xvector, yvector, index):
169         '''
170         returns a ClickedPoint() object from an index and vectors of x, y coordinates
171         '''
172         point=ClickedPoint()
173         point.index=index
174         point.absolute_coords=xvector[index],yvector[index]
175         point.find_graph_coords(xvector,yvector)
176         return point
177
178 #HERE COMMANDS BEGIN
179
180     def help_set(self):
181         print '''
182 SET
183 Sets a local configuration variable
184 -------------
185 Syntax: set [variable] [value]
186         '''
187     def do_set(self,args):
188         #FIXME: some variables in self.config should be hidden or intelligently configurated...
189         args=args.split()
190         if len(args)==0:
191             print 'You must specify a variable and a value'
192             print 'Available variables:'
193             print self.config.keys()
194             return
195         if args[0] not in self.config.keys():
196             print 'This is not an internal Hooke variable!'
197             return
198         if len(args)==1:
199             #FIXME:we should reload the config file and reset the config value
200             print self.config[args[0]]
201             return
202         key=args[0]
203         try: #try to have a numeric value
204             value=float(args[1])
205         except ValueError: #if it cannot be converted to float, it's None, or a string...
206             value=args[1]
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 if __name__ == '__main__':
986     mycli=HookeCli(0)
987     mycli.cmdloop()