3 # GTK oriented packages
10 import gtksourceview2
as sourceview
13 import SourceViewDummy
as sourceview
19 # Process oriented packages
20 from subprocess
import Popen
, PIPE
22 from Queue
import Queue
27 import xml
.etree
.ElementTree
as ET
# Python 2.5
29 import elementtree
.ElementTree
as ET
34 # Custom widget with horizontal pane allowing for the easy
35 # vertical resizing of boxes
36 from VSizerPane
import VSizerPane
43 stages
= None # Linked list of stages
44 pipeline_executor
= None
45 source_lang_manager
= None
46 source_style_manager
= None
49 def text_window(title
, text_buffer
):
50 wTree
= gtk
.glade
.XML("TextWindow.glade")
52 wnd
= wTree
.get_widget("text_window")
55 def close(widget
, data
= None):
59 wnd
.connect("destroy", close
)
61 text_view
= wTree
.get_widget("text_view")
62 text_view
.set_buffer(text_buffer
)
64 wTree
.signal_autoconnect({'on_btn_close_clicked': close
})
71 class Expander(gtk
.Expander
):
73 A GTK expander containing a scrollable text window and a
74 VSizerPane at the bottom
76 window
= None # if the text box is detached into a window
78 def __init__(self
, label
, text_buffer
):
79 gtk
.Expander
.__init
__(self
, label
)
81 text_view
= sourceview
.View(text_buffer
)
82 text_view
.set_editable(True)
83 text_view
.set_wrap_mode(gtk
.WRAP_WORD
)
86 scrolled_window
= gtk
.ScrolledWindow()
87 scrolled_window
.show()
88 scrolled_window
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
89 scrolled_window
.add_with_viewport(text_view
)
90 scrolled_window
.set_size_request(-1, 100)
92 sizer_pane
= VSizerPane('handle.xpm', scrolled_window
)
95 vbox
= gtk
.VBox(homogeneous
= False)
97 vbox
.pack_start(scrolled_window
, expand
= True, fill
= True)
98 vbox
.pack_start(sizer_pane
, expand
= False, fill
= True)
101 self
.set_expanded(True)
103 def __init__(self
, label
, text_buffer
):
104 gtk
.HBox
.__init
__(self
)
106 self
.expander
= View
.Expander(label
, text_buffer
)
109 popout_button
= gtk
.Button("p")
110 popout_button
.connect("clicked", self
.open_text_window
, label
, text_buffer
)
113 vbox
= gtk
.VBox(homogeneous
= False)
116 vbox
.pack_start(popout_button
, expand
= False, fill
= True)
118 self
.pack_start(self
.expander
, expand
= True, fill
= True)
119 self
.pack_start(vbox
, expand
= False, fill
= True)
121 def open_text_window(self
, widget
, label
, text_buffer
):
122 self
.set_expanded(False)
123 text_window(label
, text_buffer
)
125 def set_expanded(self
, val
):
126 return self
.expander
.set_expanded(val
)
129 class PipelineExecutor(threading
.Thread
):
131 threading
.Thread
.__init
__(self
)
137 stage
= self
.queue
.get()
139 while self
.queue
.qsize() > 0:
140 stage
= self
.queue
.get()
144 def add(self
, stage
):
145 self
.queue
.put(stage
)
149 def __init__(self
, command_line
= None):
150 logging
.debug('creating stage with command_line %s' % str(command_line
))
151 self
.command_line
= command_line
153 self
.preproc_cmdline
= None
154 self
.postproc_cmdline
= None
156 self
.text_buffer
= sourceview
.Buffer()
158 #self.text_buffer.set_language(Globals.source_lang_manager.get_lang)
159 self
.text_buffer
.set_language(Globals
.source_lang_manager
.get_language('apertium'))
160 self
.text_buffer
.set_style_scheme(Globals
.source_style_manager
.get_scheme('tango'))
161 self
.text_buffer
.set_highlight_syntax(True)
162 self
.text_buffer
.set_highlight_matching_brackets(False)
164 self
.update_handler
= self
.text_buffer
.connect("changed", self
.update
)
167 if self
.next
== None:
170 # set the marking (on or off)
171 if len(self
.next
.command_line
) > 1 and self
.next
.command_line
[1] == '$1' and Globals
.marcar
== 1:
172 cmdline
= self
.next
.command_line
;
173 cmdline
= (cmdline
[0], '-g', cmdline
[2]);
174 elif len(self
.next
.command_line
) > 1 and self
.next
.command_line
[1] == '$1' and Globals
.marcar
== 0:
175 cmdline
= self
.next
.command_line
;
176 cmdline
= (cmdline
[0], '-n', cmdline
[2]);
178 cmdline
= self
.next
.command_line
;
181 def call(cmdline
, buffer):
182 proc
= Popen(cmdline
, stdin
= PIPE
, stdout
= PIPE
)
183 return proc
.communicate(buffer)
185 buffer_text
= self
.text_buffer
.get_text(self
.text_buffer
.get_start_iter(),
186 self
.text_buffer
.get_end_iter())
188 for _cmd
in [self
.preproc_cmdline
, cmdline
, self
.postproc_cmdline
]:
190 buffer_text
, err
= call(_cmd
, buffer_text
)
192 gtk
.gdk
.threads_enter()
193 self
.next
.text_buffer
.handler_block(self
.next
.update_handler
)
194 self
.next
.text_buffer
.set_text(buffer_text
.strip())
195 self
.next
.text_buffer
.handler_unblock(self
.next
.update_handler
)
196 gtk
.gdk
.threads_leave()
201 logging
.error("Cripes! %s" % str(e
))
203 def update(self
, widget
, *args
):
204 Globals
.pipeline_executor
.add(self
)
215 def menu_item(label
, item
= None):
216 menu_item
= gtk
.MenuItem(label
)
219 if type(item
) == type(lambda: 2):
220 menu_item
.connect("activate", item
)
222 elif type(item
) == gtk
.Menu
:
223 menu_item
.set_submenu(item
)
236 bar_items
= (menu_item("File", menu(menu_item("Open", menu_file_open
),
237 menu_item("Exit", quit
))),
238 menu_item("Compile"))
240 menu_bar
= gtk
.MenuBar()
241 for item
in bar_items
:
242 menu_bar
.append(item
)
249 def load_mode_file(filename
):
252 def menu_file_open(widget
, data
= None):
253 if "open_dialog" not in self
.__dict
__:
254 self
.open_dialog
= gtk
.FileSelection("Select the modes file")
255 self
.open_dialog
.ok_button
.connect("clicked",
256 load_mode_file(self
.open_dialog
.get_filename()))
257 self
.open_dialog
.ok_button
.connect("clicked",
258 lambda w
: self
.open_dialog
.hide())
259 self
.open_dialog
.cancel_button
.connect("clicked",
260 lambda w
: self
.open_dialog
.hide())
262 self
.open_dialog
.show()
266 def quit(widget
, data
= None):
269 def delete_event(widget
, event
, data
= None):
273 # There is probably a much nicer way of doing this.
275 def checkbox_event(widget
, *args
):
276 if Globals
.marcar
== 1:
281 Globals
.stages
.update(widget
);
284 def make_stage_name(command_line
):
285 if command_line
!= None:
286 s
= " ".join(command_line
)
291 return s
[0:64] + "..."
295 def make_handle_box(stages
):
296 view_box
= gtk
.VBox(homogeneous
= False)
301 view
= View(make_stage_name(stage
.command_line
), stage
.text_buffer
)
302 view_list
.append(view
)
304 view_box
.pack_start(view
, expand
= False, fill
= True)
306 for view
in view_list
[1:-1]:
307 view
.set_expanded(False)
311 view_box
= make_handle_box(Globals
.stages
)
314 vbox
= gtk
.VBox(homogeneous
= False, spacing
= 5)
315 vbox_options
= gtk
.VBox(homogeneous
= False, spacing
= 5)
318 vbox
.pack_start(menubar(), expand
= False)
319 # There is probably a much nicer way of doing this.
320 vbox
.pack_start(vbox_options
, expand
= False)
322 marcar_box
= gtk
.CheckButton('Mark unknown words')
325 marcar_box
.connect("clicked", checkbox_event
);
326 vbox_options
.pack_end(marcar_box
, expand
= False, fill
= True)
328 vbox
.pack_start(view_box
, expand
= True)
331 scrolled_window
= gtk
.ScrolledWindow()
332 scrolled_window
.set_policy(gtk
.POLICY_NEVER
, gtk
.POLICY_AUTOMATIC
)
333 scrolled_window
.show()
334 scrolled_window
.add_with_viewport(vbox
)
336 window
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
337 window
.add(scrolled_window
)
339 window
.connect("delete_event", delete_event
)
340 window
.connect("destroy", quit
)
342 window
.resize(400, 500)
348 def apertium_program(program
):
349 # TODO: Make this search for the Apertium path
350 return "%s/%s" % (config
.apertium_bin_path
, program
)
352 def apertium_dictionary(dictionary
):
353 # TODO: Make this search for the Apertium path
354 return "%s/apertium-%s/%s" % (config
.apertium_dict_path
, Globals
.lang_code
, dictionary
)
356 def setup_mode(mode
):
360 for program
in mode
.findall('.//program'):
361 command
= apertium_program(program
.attrib
['name']).split(' ')
363 for param
in program
.findall('.//file'):
364 command
.append(apertium_dictionary(param
.attrib
['name']))
366 stages
.next
= Stage(tuple(command
))
372 last_stage
= [stage
for stage
in stages
if stage
.next
!= None and stage
.next
.next
== None][0]
374 start_stage
.preproc_cmdline
= (apertium_program('apertium-destxt'),)
375 last_stage
.postproc_cmdline
= (apertium_program('apertium-retxt'),)
382 logging
.basicConfig(level
=logging
.DEBUG
,
383 format
='%(asctime)s %(levelname)-8s %(message)s',
384 datefmt
='%a, %d %b %Y %H:%M:%S',
385 filename
='apertium.log',
391 print "usage: apertium-view [<modes file>] [<language code>]"
393 def process_command_line():
396 logging
.debug('Command line is %s' % sys
.argv
)
397 Globals
.lang_code
= sys
.argv
[1]
399 def process_modes(mode_file
, mode_code
= None):
400 logging
.debug("Using mode file %s" % mode_file
)
401 tree
= ET
.parse(mode_file
)
404 if mode_code
!= None:
405 logging
.debug('Looking for mode code %s' % mode_code
)
406 for mode
in tree
.findall('mode'):
407 if mode
.attrib
['name'] == mode_code
:
413 logging
.debug('No mode code specified, using first one in file')
414 return tree
.find('mode')
418 Globals
.mode
= process_modes(*sys
.argv
[2:4])
419 logging
.debug('Parsed command line')
425 process_command_line()
426 Globals
.stages
= setup_mode(Globals
.mode
)
427 Globals
.pipeline_executor
= PipelineExecutor()
428 Globals
.pipeline_executor
.start()
431 if __name__
== "__main__":
432 if len(sys
.argv
) < 3: #{
433 print 'Usage: apertium-view.py <pair name> <modes file> [direction]';
437 Globals
.source_lang_manager
= sourceview
.language_manager_get_default()
438 Globals
.source_style_manager
= sourceview
.style_scheme_manager_get_default()
440 gtk
.gdk
.threads_init()
442 logging
.debug('Completed init phase')
444 logging
.debug('Graceful shutdown')