Moved QueueMessage and subclasses from hooke.ui to the more central hooke.engine.
[hooke.git] / hooke / plugin / command_stack.py
1 # Copyright (C) 2008-2010 Alberto Gomez-Casado
2 #                         Massimo Sandal <devicerandom@gmail.com>
3 #                         W. Trevor King <wking@drexel.edu>
4 #
5 # This file is part of Hooke.
6 #
7 # Hooke is free software: you can redistribute it and/or modify it
8 # under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
11 #
12 # Hooke is distributed in the hope that it will be useful, but WITHOUT
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
15 # Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with Hooke.  If not, see
19 # <http://www.gnu.org/licenses/>.
20
21 """The ``command_stack`` module provides :class:`CommandStackPlugin`
22 and several associated :class:`~hooke.command.Command`\s for managing
23 stacks of :class:`~hooke.engine.CommandMessage`\s and applying those
24 stacks to :class:`~hooke.curve.Curve`\s.
25 """
26
27 import os.path
28 import string
29
30 from .. import curve as lhc
31 from .. import libinput as linput
32
33 class macroCommands(object):
34
35         currentmacro=[]
36         pause=0
37         auxprompt=[]
38         macrodir=None
39         
40
41         def _plug_init(self):
42                 self.currentmacro=[]
43                 self.auxprompt=self.prompt
44                 self.macrodir=self.config['workdir']
45                 if not os.path.exists(os.path.join(self.macrodir,'macros')):
46                     try:
47                         os.mkdir('macros')
48                     except:
49                         print 'Warning: cannot create macros folder.'
50                         print 'Probably you do not have permissions in your Hooke folder, use macro at your own risk.'
51                 self.macrodir=os.path.join(self.macrodir,'macros')
52
53         def collect(self):
54                                 
55                 print 'Enter STOP / PAUSE to go back to normal mode\nUNDO to remove last command'
56                 line=[]
57                 while not(line=='STOP' or line=='PAUSE'):
58                         line=raw_input('hooke (macroREC): ')
59                         if line=='PAUSE':
60                                 self.pause=1
61                                 self.prompt='hooke (macroPAUSE): '
62                                 break
63                         if line=='STOP':
64                                 self.prompt=self.auxprompt
65                                 self.do_recordmacro('stop')
66                                 break
67                         if line=='UNDO':
68                                 self.currentmacro.pop()
69                                 continue
70                         param=line.split()
71
72                         #FIXME check if accessing param[2] when it doesnt exist breaks something
73                         if param[0] =='export':
74                                 exportline=param[0]+' __curve__ '
75                                 if len(param)==3:
76                                         exportline=exportline+param[2]
77                                 self.currentmacro.append(exportline)
78                                 self.onecmd(line)
79                                 continue
80                         
81                         if param[0] =='txt':
82                                 exportline=param[0]
83                                 if len(param)==3:
84                                         exportline=exportline+' '+param[2]
85                                 exportline=exportline+'__curve__'
86                                 self.currentmacro.append(exportline)
87                                 self.onecmd(line)
88                                 continue
89
90                         self.onecmd(line)
91                         
92                         self.currentmacro.append(line)
93                 
94
95         def do_recordmacro(self, args):
96                 '''RECORDMACRO
97                 Stores input commands to create script files
98                 -------
99                 Syntax: recordmacro [start / stop]
100                 If a macro is currently paused start resumes recording
101                 '''
102                 
103                 
104                 if len(args)==0:
105                         args='start'
106
107                 if args=='stop':
108                         self.pause=0
109                         self.prompt=self.auxprompt
110                         if len(self.currentmacro) != 0:
111                                 answer=linput.safeinput('Do you want to save this macro? ',['y'])
112                                 if answer[0].lower() == 'y':
113                                         self.do_savemacro('')
114                                 else:
115                                         print 'Macro discarded'
116                                         self.currentmacro=[]
117                         else:
118                                 print 'Macro was empty' 
119
120                 if args=='start':       
121
122                         if self.pause==1:
123                                 self.pause=0    
124                                 self.collect()  
125                         else:
126                                 if len(self.currentmacro) != 0:
127                                         answer=linput.safeinput('Another macro is already beign recorded\nDo you want to save it?',['y'])
128                                         if answer[0].lower() == 'y':
129                                                 self.do_savemacro('')
130                                         else:
131                                                 print 'Old macro discarded, you can start recording the new one'
132                         
133                                 self.currentmacro=[]
134                                 self.collect()
135                 
136
137         def do_savemacro(self, macroname):
138
139                 '''SAVEMACRO
140                 Saves previously recorded macro into a script file for future use
141                 -------
142                 Syntax: savemacro [macroname]
143                 If no macroname is supplied one will be interactively asked
144                 '''
145
146                 saved_ok=0
147                 if self.currentmacro==None:
148                         print 'No macro is being recorded!'
149                         return 0
150                 if len(macroname)==0:
151                         macroname=linput.safeinput('Enter new macro name: ')
152                         if len(macroname) == 0:
153                                 print 'Invalid name'
154                                 
155                 macroname=os.path.join(self.macrodir,macroname+'.hkm')
156                 if os.path.exists(macroname):
157                         overwrite=linput.safeinput('That name is in use, overwrite?',['n'])
158                         if overwrite[0].lower()!='y':
159                                 print 'Cancelled save'
160                                 return 0
161                 txtfile=open(macroname,'w+')
162                 self.currentmacro='\n'.join(self.currentmacro)
163                 txtfile.write(self.currentmacro)
164                 txtfile.close()
165                 print 'Saved on '+macroname
166                 self.currentmacro=[]
167
168         def do_execmacro (self, args):
169                 
170                 '''EXECMACRO
171                 Loads a macro and executes it over current curve / playlist
172                 -----
173                 Syntax: execmacro macroname [playlist] [v]
174
175                 macroname.hkm should be present at [hooke]/macros directory
176                 By default the macro will be executed over current curve
177                 passing 'playlist' word as second argument executes macroname
178                 over all curves
179                 By default curve(s) will be processed silently, passing 'v'
180                 as second/third argument will print each command that is
181                 executed
182
183                 Note that macros applied to playlists should end by export
184                 commands so the processed curves are not lost
185                 '''
186                 verbose=0
187                 cycle=0
188                 curve=None              
189
190                 if len(self.currentmacro) != 0:
191                         print 'Warning!: you are calling a macro while recording other'
192                 if len(args) == 0:
193                         print 'You must provide a macro name'
194                         return 0
195                 args=args.split()
196
197                 #print 'args ' + ' '.join(args)
198                 
199                 if len(args)>1:
200                         if args[1] == 'playlist':
201                                 cycle=1
202                                 print 'Remember! macros applied over playlists should include export orders'
203                                 if len(args)>2 and args[2] == 'v':
204                                         verbose=1
205                         else:
206                                 if args[1] == 'v':
207                                         verbose=1       
208                 #print cycle
209                 #print verbose  
210
211                 macropath=os.path.join(self.macrodir,args[0]+'.hkm')
212                 if not os.path.exists(macropath):
213                         print 'Could not find a macro named '+macropath
214                         return 0
215                 txtfile=open(macropath)
216                 if cycle ==1:
217                         #print self.current_list
218                         for item in self.current_list:
219                                 self.current=item
220                                 self.do_plot(0)
221
222                                 for command in txtfile:
223
224                                         if verbose==1:
225                                                 print 'Executing command '+command
226                                         testcmd=command.split()
227                                         w=0
228                                         for word in testcmd:
229                                                 if word=='__curve__':
230                                                         testcmd[w]=os.path.splitext(os.path.basename(item.path))[0]
231                                                 w=w+1
232                                         self.onecmd(' '.join(testcmd))
233                                 self.current.curve.close_all()
234                                 txtfile.seek(0)
235                 else:
236                         for command in txtfile:
237                                         testcmd=command.split()
238                                         w=0
239                                         for word in testcmd:
240                                                 if word=='__curve__':
241                                                         w=w+1
242                                                         testcmd[w]=os.path.splitext(os.path.basename(self.current.path))[0]+'-'+string.lstrip(os.path.splitext(os.path.basename(self.current.path))[1],'.')
243                                         if verbose==1:
244                                                 print 'Executing command '+' '.join(testcmd)
245                                         self.onecmd(' '.join(testcmd))