(* A graphical frontend (handles backend notifications, copy_in, copy_out, presentation of "select" result in tables) To build prompt_gtk you need lablgtk 1.2 *) open Printf open GMain open Postgresql let () = if (Array.length Sys.argv <> 2) then ( eprintf "Usage: %s conninfo\n" Sys.argv.(0); exit 1) let conninfo = Sys.argv.(1) let file_dialog title = let name = ref "" in let sel = GWindow.file_selection ~title ~modal:true () in let cancel_callback () = sel#destroy (); Main.quit () in let ok_callback () = name := sel#filename; cancel_callback () in let _ = sel#ok_button#connect#clicked ~callback:ok_callback in let _ = sel#cancel_button#connect#clicked ~callback:cancel_callback in sel#show (); Main.main (); !name let make_window title = let window = GWindow.window ~title ~width:300 ~height:300 () in let vbox = GPack.vbox ~packing:window#add () in let button = GButton.button ~label:"Close" ~packing:(vbox#pack ~from:`END) () in let _ = button#connect#clicked ~callback:window#destroy in let hbox = GPack.hbox ~packing:vbox#add () in let sbv = GRange.scrollbar `VERTICAL ~packing:(hbox#pack ~from:`END) () in let sbh = GRange.scrollbar `HORIZONTAL ~packing:(vbox#pack ~from:`END) () in window, hbox, sbv, sbh let show_tuples res = let window, hbox, sbv, sbh = make_window "Result (tuples)" in let cl = GList.clist ~titles:res#get_fnames_lst ~shadow_type:`OUT ~packing:hbox#add ~vadjustment:sbv#adjustment ~hadjustment:sbh#adjustment () in for tuple = 0 to res#ntuples - 1 do ignore (cl#append (res#get_tuple_lst tuple)) done; cl#columns_autosize (); window#show () let show_copy_out conn = let window, hbox, _sbv, _sbh = make_window "Result (copy_out)" in let txt = GText.view ~packing:hbox#add () in let buf = txt#buffer in conn#copy_out (fun s -> buf#insert (s ^ "\n")); window#show () let main () = let conn = new connection ~conninfo () in let window = GWindow.window ~title:"Queries" ~width:300 ~height:300 () in let _ = window#connect#destroy ~callback:Main.quit in let vbox = GPack.vbox ~border_width:5 ~spacing:10 ~packing:window#add () in let result = GText.view ~editable:false ~packing:vbox#add () in let res_buf = result#buffer in let text = GText.view ~editable:true ~packing:vbox#add ~height:50 () in let print s = ignore (res_buf#insert s) in let rec dump_res () = match conn#get_result with | Some res -> (match res#status with | Tuples_ok -> show_tuples res | Copy_out -> show_copy_out conn | Copy_in -> let name = file_dialog "Choose file to send" in if name = "" then (conn # putline "\\.\n"; conn#endcopy) else ( let ic = open_in name in conn#copy_in_channel ic; close_in ic) | Empty_query -> print "Empty query\n" | Command_ok -> print (sprintf "Command ok [%s]\n" res#cmd_status) | Bad_response -> print (sprintf "Bad response : %s\n" res#error); conn#reset | Nonfatal_error -> print (sprintf "Non fatal error : %s\n" res#error) | Fatal_error -> print (sprintf "Fatal error : %s\n" res#error)); dump_res () | None -> () in let query () = let buf = text#buffer in let s = buf#get_text () in print "-> "; print s; print "\n"; buf#delete ~start:buf#start_iter ~stop:buf#end_iter; conn#send_query s; dump_res (); print "======\n"; flush stdout in let key_press k = if GdkEvent.Key.keyval k = GdkKeysyms._KP_Enter then (query (); true) else false in let _ = text#event#connect#key_press ~callback:key_press in let button = GButton.button ~label:"Exec" ~packing:vbox#add () in let _ = button#connect#clicked ~callback:query in window#show (); let window = GWindow.window ~title:"Backend notifications" ~width:300 ~height:150 () in let _ = window#connect#destroy ~callback:Main.quit in let vbox = GPack.vbox ~border_width:5 ~packing:window#add () in let hbox = GPack.hbox ~packing:vbox#add () in let sb = GRange.scrollbar `VERTICAL ~packing:(hbox#pack ~from:`END) () in let clist = GList.clist ~titles:["Backend PID"; "Notification"] ~shadow_type:`OUT ~packing:hbox#add ~vadjustment:sb#adjustment () in let hbox = GPack.hbox ~packing:vbox#pack () in let button_clear = GButton.button ~label:"Clear" ~packing:hbox#add () in let _ = button_clear#connect#clicked ~callback:clist#clear in let button_clear = GButton.button ~label:"Hide" ~packing:hbox#add () in let _ = button_clear#connect#clicked ~callback:window#misc#hide in let rec dump_notification () = match conn#notifies with | Some (msg, pid) -> let _ = clist#append [string_of_int pid; msg] in window#show (); dump_notification () | None -> () in let _ = Timeout.add ~ms:100 ~callback:(fun () -> conn#consume_input; dump_notification (); true) in Main.main () let _ = try main () with | Error e -> prerr_endline (string_of_error e) | e -> prerr_endline (Printexc.to_string e)