1 (* Copyright (C) 2000, HELM Team.
3 * This file is part of HELM, an Hypertextual, Electronic
4 * Library of Mathematics, developed at the Computer Science
5 * Department, University of Bologna, Italy.
7 * HELM is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * HELM is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with HELM; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 * For details, see the HELM World-Wide-Web page,
23 * http://cs.unibo.it/helm/.
26 (******************************************************************************)
30 (* Claudio Sacerdoti Coen <sacerdot@cs.unibo.it> *)
33 (* This is a simple gtk interface to the Coq-like pretty printer cicPp for *)
34 (* cic terms exported in xml. It uses directly the modules cicPp and *)
35 (* cicCcache and indirectly all the other modules (cicParser, cicParser2, *)
36 (* cicParser3, getter). *)
37 (* The syntax is "gtkInterface[.opt] filename1 ... filenamen" where *)
38 (* filenamei is the path-name of an xml file describing a cic term. *)
39 (* The terms are loaded in cache and then pretty-printed one at a time and *)
40 (* only once, when the user wants to look at it: if the user wants to look at *)
41 (* a term again, then the pretty-printed term is showed again, but not *)
44 (******************************************************************************)
46 (* GLOBAL REFERENCES (USED BY CALLBACKS) *)
48 let annotated_obj = ref None;; (* reference to a couple option where *)
49 (* the first component is the current *)
50 (* annotated object and the second is *)
51 (* the map from ids to annotated targets *)
52 let ann = ref (ref None);; (* current annotation *)
53 let radio_some_status = ref false;; (* is the radio_some button selected? *)
54 let current_url = ref "";;
56 (* GLOBAL CONSTANTS *)
58 let helmns = Ominidom.o_mDOMString_of_string "http://www.cs.unibo.it/helm";;
62 let pathname_of_annuri uristring =
63 Configuration.annotations_dir ^
64 Str.replace_first (Str.regexp "^cic:") "" uristring
67 let make_dirs dirpath =
68 ignore (Unix.system ("mkdir -p " ^ dirpath))
71 module UrlManipulator =
73 exception No_param_dot_CICURI_or_param_dot_annotations_found_in of string;;
74 exception No_param_found_in of string * string;;
75 exception Bad_formed_url of string;;
77 let uri_from_url url =
78 let module N = Neturl in
79 let founduri = ref None in
80 let foundann = ref None in
83 [] -> raise (No_param_dot_CICURI_or_param_dot_annotations_found_in url)
85 match Str.split (Str.regexp "=") he with
86 ["param.CICURI";uri] ->
87 if !founduri <> None then
88 raise (Bad_formed_url url)
91 founduri := Some uri ;
92 if !foundann = None then
95 | ["param.annotations";ann] ->
96 if !foundann <> None then
97 raise (Bad_formed_url url)
105 | _ -> raise (Bad_formed_url url)
107 if !founduri = None then
113 (Str.split (Str.regexp "&")
114 (N.url_query ~encoded:true (N.url_of_string N.ip_url_syntax url))) ;
115 match !founduri,!foundann with
116 (Some uri),(Some ann) -> uri ^ ann
118 raise (No_param_dot_CICURI_or_param_dot_annotations_found_in url)
121 let extractParam param url =
122 let module N = Neturl in
125 [] -> raise (No_param_found_in (param,url))
127 match Str.split (Str.regexp "=") he with
128 [name;value] when name = param -> value
132 (Str.split (Str.regexp "&")
133 (N.url_query ~encoded:true (N.url_of_string N.ip_url_syntax url)))
136 let set_annotations_to_yes query url =
137 let found =ref false in
142 else raise (No_param_found_in ("param.annotations",url))
144 match Str.split (Str.regexp "=") he with
145 ["param.annotations" as s ; ann] ->
147 let auxtl = aux tl in
149 (if auxtl = "" then "" else "&" ^ auxtl)
151 let auxtl = aux tl in
153 (if auxtl = "" then "" else "&" ^ auxtl)
155 let auxtl = aux tl in
157 (if auxtl = "" then "" else "&" ^ auxtl)
158 | _ -> raise (Bad_formed_url url)
160 aux (Str.split (Str.regexp "&") query)
163 let annurl_of_url url =
164 let module N = Neturl in
165 let nurl = N.url_of_string N.ip_url_syntax url in
166 let query = N.url_query ~encoded:true nurl in
167 let newquery = set_annotations_to_yes query url in
168 N.string_of_url (N.modify_url ~encoded:true ~query:newquery nurl)
172 let get_current_uri () =
173 UriManager.uri_of_string (UrlManipulator.uri_from_url !current_url)
178 let get_annotated_obj () =
179 match !annotated_obj with
182 (CicCache.get_annobj (get_current_uri ()))
184 annotated_obj := Some annobj ;
186 | Some annobj -> annobj
189 let update_output rendering_window url =
190 rendering_window#label#set_text (UrlManipulator.uri_from_url url) ;
191 rendering_window#output#load url
194 let choose_selection rendering_window (node : Ominidom.o_mDOMNode option) =
195 let module O = Ominidom in
197 match node#get_attribute_ns (O.o_mDOMString_of_string "xref") helmns with
198 Some _ -> rendering_window#output#set_selection (Some node)
199 | None -> aux (node#get_parent)
203 | None -> rendering_window#output#set_selection None
206 let annotateb_pressed rendering_window annotation_window () =
207 let module O = Ominidom in
208 match rendering_window#output#get_selection with
211 match (node#get_attribute_ns (O.o_mDOMString_of_string "xref") helmns) with
213 let annobj = get_annotated_obj ()
214 and annotation = (annotation_window#annotation : GEdit.text) in
215 ann := CicXPath.get_annotation annobj (xpath#get_string) ;
216 CicAnnotationHinter.create_hints annotation_window annobj
218 annotation#delete_text 0 annotation#length ;
222 annotation#misc#set_sensitive false ;
223 annotation_window#radio_none#set_active true ;
224 radio_some_status := false
226 annotation#insert ann' ;
227 annotation#misc#set_sensitive true ;
228 annotation_window#radio_some#set_active true ;
229 radio_some_status := true
231 GMain.Grab.add (annotation_window#window_to_annotate#coerce) ;
232 annotation_window#show () ;
233 | None -> rendering_window#label#set_text ("ERROR: No xref found!!!\n")
235 | None -> rendering_window#label#set_text ("ERROR: No selection!!!\n")
238 (* called when the annotation is confirmed *)
239 let save_annotation annotation =
240 let module S = Str in
241 let module U = UriManager in
242 if !radio_some_status then
243 !ann := Some (annotation#get_chars 0 annotation#length)
246 match !annotated_obj with
249 let uri = get_current_uri () in
250 let annxml = CicAnnotation2Xml.pp_annotation annobj uri in
252 (pathname_of_annuri (U.buri_of_uri uri)) ;
253 Xml.pp ~quiet:true annxml
255 (pathname_of_annuri (U.string_of_uri (U.annuri_of_uri uri)) ^
261 (* STUFF TO BUILD THE GTK INTERFACE *)
263 (* Stuff for the widget settings *)
265 let export_to_postscript (output : GMathView.math_view) () =
266 output#export_to_postscript ~filename:"output.ps" ();
269 let activate_t1 output button_set_anti_aliasing button_set_kerning
270 button_set_transparency button_export_to_postscript button_t1 ()
272 let is_set = button_t1#active in
273 output#set_font_manager_type
274 (if is_set then `font_manager_t1 else `font_manager_gtk) ;
277 button_set_anti_aliasing#misc#set_sensitive true ;
278 button_set_kerning#misc#set_sensitive true ;
279 button_set_transparency#misc#set_sensitive true ;
280 button_export_to_postscript#misc#set_sensitive true ;
284 button_set_anti_aliasing#misc#set_sensitive false ;
285 button_set_kerning#misc#set_sensitive false ;
286 button_set_transparency#misc#set_sensitive false ;
287 button_export_to_postscript#misc#set_sensitive false ;
291 let set_anti_aliasing output button_set_anti_aliasing () =
292 output#set_anti_aliasing button_set_anti_aliasing#active
295 let set_kerning output button_set_kerning () =
296 output#set_kerning button_set_kerning#active
299 let set_transparency output button_set_transparency () =
300 output#set_transparency button_set_transparency#active
303 let changefont output font_size_spinb () =
304 output#set_font_size font_size_spinb#value_as_int
307 let set_log_verbosity output log_verbosity_spinb () =
308 output#set_log_verbosity log_verbosity_spinb#value_as_int
311 class settings_window output sw button_export_to_postscript
312 selection_changed_callback
314 let settings_window = GWindow.window ~title:"GtkMathView settings" () in
316 GPack.vbox ~packing:settings_window#add () in
319 ~rows:1 ~columns:3 ~homogeneous:false ~row_spacings:5 ~col_spacings:5
320 ~border_width:5 ~packing:vbox#add () in
322 GButton.toggle_button ~label:"activate t1 fonts"
323 ~packing:(table#attach ~left:0 ~top:0) () in
324 let button_set_anti_aliasing =
325 GButton.toggle_button ~label:"set_anti_aliasing"
326 ~packing:(table#attach ~left:0 ~top:1) () in
327 let button_set_kerning =
328 GButton.toggle_button ~label:"set_kerning"
329 ~packing:(table#attach ~left:1 ~top:1) () in
330 let button_set_transparency =
331 GButton.toggle_button ~label:"set_transparency"
332 ~packing:(table#attach ~left:2 ~top:1) () in
335 ~rows:2 ~columns:2 ~homogeneous:false ~row_spacings:5 ~col_spacings:5
336 ~border_width:5 ~packing:vbox#add () in
337 let font_size_label =
338 GMisc.label ~text:"font size:"
339 ~packing:(table#attach ~left:0 ~top:0 ~expand:`NONE) () in
340 let font_size_spinb =
342 GData.adjustment ~value:14.0 ~lower:5.0 ~upper:50.0 ~step_incr:1.0 ()
345 ~adjustment:sadj ~packing:(table#attach ~left:1 ~top:0 ~fill:`NONE) () in
346 let log_verbosity_label =
347 GMisc.label ~text:"log verbosity:"
348 ~packing:(table#attach ~left:0 ~top:1) () in
349 let log_verbosity_spinb =
351 GData.adjustment ~value:0.0 ~lower:0.0 ~upper:3.0 ~step_incr:1.0 ()
354 ~adjustment:sadj ~packing:(table#attach ~left:1 ~top:1) () in
356 GPack.hbox ~packing:(vbox#pack ~expand:false ~fill:false ~padding:5) () in
358 GButton.button ~label:"Close"
359 ~packing:(hbox#pack ~expand:false ~fill:false ~padding:5) () in
361 method show = settings_window#show
363 button_set_anti_aliasing#misc#set_sensitive false ;
364 button_set_kerning#misc#set_sensitive false ;
365 button_set_transparency#misc#set_sensitive false ;
366 (* Signals connection *)
367 ignore(button_t1#connect#clicked
368 (activate_t1 output button_set_anti_aliasing button_set_kerning
369 button_set_transparency button_export_to_postscript button_t1)) ;
370 ignore(font_size_spinb#connect#changed (changefont output font_size_spinb)) ;
371 ignore(button_set_anti_aliasing#connect#toggled
372 (set_anti_aliasing output button_set_anti_aliasing));
373 ignore(button_set_kerning#connect#toggled
374 (set_kerning output button_set_kerning)) ;
375 ignore(button_set_transparency#connect#toggled
376 (set_transparency output button_set_transparency)) ;
377 ignore(log_verbosity_spinb#connect#changed
378 (set_log_verbosity output log_verbosity_spinb)) ;
379 ignore(closeb#connect#clicked settings_window#misc#hide)
384 class annotation_window output label =
385 let window_to_annotate =
386 GWindow.window ~title:"Annotating environment" ~border_width:2 () in
388 GPack.hbox ~packing:window_to_annotate#add () in
390 GPack.vbox ~packing:(hbox1#pack ~padding:5) () in
392 GPack.hbox ~packing:(vbox1#pack ~expand:false ~fill:false ~padding:5) () in
393 let radio_some = GButton.radio_button ~label:"Annotation below"
394 ~packing:(hbox2#pack ~expand:false ~fill:false ~padding:5) () in
395 let radio_none = GButton.radio_button ~label:"No annotation"
396 ~group:radio_some#group
397 ~packing:(hbox2#pack ~expand:false ~fill:false ~padding:5)
399 let annotation = GEdit.text ~editable:true ~width:400 ~height:180
400 ~packing:(vbox1#pack ~padding:5) () in
402 GPack.table ~rows:3 ~columns:3 ~packing:(vbox1#pack ~padding:5) () in
403 let annotation_hints =
406 GButton.button ~label:("Hint " ^ string_of_int i)
407 ~packing:(table#attach ~left:(i mod 3) ~top:(i / 3)) ()
410 GPack.vbox ~packing:(hbox1#pack ~expand:false ~fill:false ~padding:5) () in
412 GButton.button ~label:"O.K."
413 ~packing:(vbox2#pack ~expand:false ~fill:false ~padding:5) () in
415 GButton.button ~label:"Abort"
416 ~packing:(vbox2#pack ~expand:false ~fill:false ~padding:5) () in
418 method window_to_annotate = window_to_annotate
419 method annotation = annotation
420 method radio_some = radio_some
421 method radio_none = radio_none
422 method annotation_hints = annotation_hints
423 method output = (output : GMathView.math_view)
424 method show () = window_to_annotate#show ()
426 (* signal handlers here *)
427 ignore (window_to_annotate#event#connect#delete
429 window_to_annotate#misc#hide () ;
430 GMain.Grab.remove (window_to_annotate#coerce) ;
433 ignore (confirmb#connect#clicked
435 window_to_annotate#misc#hide () ;
436 save_annotation annotation ;
437 GMain.Grab.remove (window_to_annotate#coerce) ;
438 let new_current_uri = UriManager.annuri_of_uri (get_current_uri ()) in
439 Getter.register new_current_uri
440 (Configuration.annotations_url ^
441 Str.replace_first (Str.regexp "^cic:") ""
442 (UriManager.string_of_uri new_current_uri) ^ ".xml"
444 let new_current_url = UrlManipulator.annurl_of_url !current_url in
445 current_url := new_current_url ;
446 label#set_text (UriManager.string_of_uri new_current_uri) ;
447 output#load new_current_url
449 ignore (abortb#connect#clicked
451 window_to_annotate#misc#hide () ;
452 GMain.Grab.remove (window_to_annotate#coerce)
454 ignore (radio_some#connect#clicked
455 (fun () -> annotation#misc#set_sensitive true ; radio_some_status := true)) ;
456 ignore (radio_none #connect#clicked
458 annotation#misc#set_sensitive false;
459 radio_some_status := false)
463 class rendering_window annotation_window output (label : GMisc.label) =
465 GWindow.window ~title:"MathML viewer" ~border_width:2 () in
467 GPack.vbox ~packing:window#add () in
468 let _ = vbox#pack ~expand:false ~fill:false ~padding:5 label#coerce in
469 let scrolled_window0 =
470 GBin.scrolled_window ~border_width:10
471 ~packing:(vbox#pack ~expand:true ~padding:5) () in
472 let _ = scrolled_window0#add output#coerce in
474 GPack.hbox ~packing:(vbox#pack ~expand:false ~fill:false ~padding:5) () in
476 GButton.button ~label:"Annotate"
477 ~packing:(hbox#pack ~expand:false ~fill:false ~padding:5) () in
479 GButton.button ~label:"Settings"
480 ~packing:(hbox#pack ~expand:false ~fill:false ~padding:5) () in
481 let button_export_to_postscript =
482 GButton.button ~label:"export_to_postscript"
483 ~packing:(hbox#pack ~expand:false ~fill:false ~padding:5) () in
485 GButton.button ~label:"Close"
486 ~packing:(hbox#pack ~expand:false ~fill:false ~padding:5) () in
489 method output = (output : GMathView.math_view)
490 method show () = window#show ()
492 button_export_to_postscript#misc#set_sensitive false ;
494 (* signal handlers here *)
495 ignore(output#connect#selection_changed (choose_selection self)) ;
496 ignore(closeb#connect#clicked (fun _ -> GMain.Main.quit ())) ;
497 ignore(annotateb#connect#clicked (annotateb_pressed self annotation_window)) ;
498 let settings_window = new settings_window output scrolled_window0
499 button_export_to_postscript (choose_selection self) in
500 ignore(settingsb#connect#clicked settings_window#show) ;
501 ignore(button_export_to_postscript#connect#clicked (export_to_postscript output)) ;
502 ignore(window#event#connect#delete (fun _ -> GMain.Main.quit () ; true ))
507 let initialize_everything tmpfile url =
508 let module U = Unix in
509 let output = GMathView.math_view ~width:400 ~height:380 ()
510 and label = GMisc.label ~text:"???" () in
511 let annotation_window = new annotation_window output label in
512 let rendering_window =
513 new rendering_window annotation_window output label
515 rendering_window#show () ;
516 rendering_window#label#set_text (UrlManipulator.uri_from_url url) ;
517 rendering_window#output#load tmpfile ;
522 let filename = ref "" in
524 "\nusage: annotationHelper[.opt] file url\n\n List of options:"
528 if x = "" then raise (Arg.Bad "Empty filename or URL not allowed") ;
529 if !filename = "" then
531 else if !current_url = "" then
535 prerr_string "More than two arguments provided\n" ;
536 Arg.usage [] usage_msg ;
541 Netencoding.Url.decode
542 (UrlManipulator.extractParam "param.getterURL" !current_url) ;
543 initialize_everything !filename !current_url