Re: Question about how to start editing GTree.cell_renderer_text's in some easy and safe way...

"Stalkern 2 (Fastweb)" <[email protected]> Mon, 07 Jun 2010 18:41:30 +0200
Newsgroups gmane.comp.lang.ocaml.lib.gtk
Message-ID <[email protected]>
Stalkern 2 (Fastweb) wrote:
> Stalkern 2 (Fastweb) wrote:
>> Jacques Garrigue wrote:
>>> From: "Stalkern 2 (Fastweb)" <[email protected]>
>>>> I was looking at the tree.ml example provided with lablgtk2 and I was
>>>> modifying it so to get cell editing just as soon as cursor is moved to
>>>> an editable cell, without needing to activate the row or press the
>>>> [Space] key or the [Return] key.
>>> [...]
> 
> I just found a complete discussion about this very same problem at
> 
> http://www.ruby-forum.com/topic/130202
> 
> It seems that it is the grabbing of focus that "steals" the start of
> editing. I'm starting to work on it now.
> 
> Very interesting indeed...
> 
> :-)))
> 
> Ernesto
> 

I do not know how to connect to a "editing_started" signal in lablgtk2,
so I started trying to go another way, i.e. with timeouts. If I just write

-------------------------------
tree_testForCellEditing3.ml
-------------------------------
open StdLabels
open Gobject.Data

let cols = new GTree.column_list
let titleCol = cols#add string
let authorCol = cols#add string
let checkedCol = cols#add boolean

let titleCellrenderer = (GTree.cell_renderer_text[])
let authorCellrenderer = (GTree.cell_renderer_text[])
(*set 'author' cell as editable*)
let () = (authorCellrenderer#set_properties [ (`EDITABLE true) ])

let create_model () =
  let store = GTree.tree_store cols in
  let row = store#append () in
  store#set ~row ~column:titleCol "The Arch of Computer Programming";
  store#set ~row ~column:authorCol "Donald Knots";
  store#set ~row ~column:checkedCol false;
  let row = store#append () in
  store#set ~row ~column:titleCol "The Chart of Programmers' Computing";
  store#set ~row ~column:authorCol "A. N. Onymous";
  store#set ~row ~column:checkedCol false;
  let row = store#append () in
  store#set ~row ~column:titleCol "The Bar of Histeric Scripting";
  store#set ~row ~column:authorCol "Gerald Fitz";
  store#set ~row ~column:checkedCol false;
  store

let main () =
  let model = create_model () in
  let window = GWindow.window () in
  window#connect#destroy ~callback:GMain.quit;
  let view = GTree.view ~model ~packing:window#add () in
  let col = GTree.view_column ~title:"Title" ()
      ~renderer:(titleCellrenderer, ["text",titleCol]) in
  view#append_column col;
  let col = GTree.view_column ~title:"Author" ()
      ~renderer:(authorCellrenderer, ["text",authorCol]) in
    view#append_column col;
  let col = GTree.view_column ~title:"Checked-out" ()
      ~renderer:(GTree.cell_renderer_text[], ["text",checkedCol]) in
  view#append_column col;

  view#selection#connect#after#changed ~callback:
    begin fun () ->
      prerr_endline "selection changed";
      List.iter view#selection#get_selected_rows ~f:
        (
	  fun p ->
	    (
	      prerr_endline (GtkTree.TreePath.to_string p);
	      ignore
		(
		  Glib.Timeout.add
		   200 (*UGLY HACK!!! UGLY HACK!!!*)
		   (
		     fun () ->
		       (
			 let () =
			   (
			     view#set_cursor
			     ~cell:authorCellrenderer
			      ~edit:true (*start_editing?*)
			      p
			      (view#get_column 1)
			   )
			 in
			   false
		       )
		   )
		)
	    )
	)
    end;

  (*Jacques Garrigue's*)
  authorCellrenderer#connect#edited ~callback:
    begin fun p s ->
      model#set ~row:(model#get_iter p) ~column:authorCol s
    end;

  window#show ();
  GMain.main ()

let () = main ()
-------------------------------

it just works with

	$ lablgtk2 -threads tree_testForCellEditing3.ml

but what will happen in a threaded app???

Digging the list I see that GMain.Timeout is generally used instead of
Glib.Timeout.

So I went for a GMain timeout and protecting the id of the timeout

-------------------------------
tree_testForCellEditing4.ml
-------------------------------
open StdLabels
open Gobject.Data

let cols = new GTree.column_list
let titleCol = cols#add string
let authorCol = cols#add string
let checkedCol = cols#add boolean

let titleCellrenderer = (GTree.cell_renderer_text[])
let authorCellrenderer = (GTree.cell_renderer_text[]) (*set 'author'
cell as editable*)
let () = (authorCellrenderer#set_properties [ (`EDITABLE true) ])

let create_model () =
  let store = GTree.tree_store cols in
  let row = store#append () in
    store#set ~row ~column:titleCol "The Arch of Computer Programming";
    store#set ~row ~column:authorCol "Donald Knots";
    store#set ~row ~column:checkedCol false;
    let row = store#append () in
      store#set ~row ~column:titleCol "The Chart of Programmers' Computing";
      store#set ~row ~column:authorCol "A. N. Onymous";
      store#set ~row ~column:checkedCol false;
      let row = store#append () in
	store#set ~row ~column:titleCol "The Bar of Histeric Scripting";
	store#set ~row ~column:authorCol "Gerald Fitz";
	store#set ~row ~column:checkedCol false;
	store

(*protect cell editing timeout id... DO I REALLY NEED THIS?*)
module UglyHackCellEditingModule =
struct
  let m = Mutex.create ();;
  let cestoid (*Cell Editing Starting Timeout Opt ID*) = ref None;;
  let set_cestoid oid = Mutex.lock m; cestoid := oid; Mutex.unlock m;;
  let remove_cestoid () =
    Mutex.lock m;
    (
      match !cestoid with
	| None -> ()
	| Some id ->
	    (
	      GMain.Timeout.remove id;
	      prerr_endline ("Timeout removed");
	      cestoid := None;
	      prerr_endline ("Timeout unregistered")
	    )
    );
    Mutex.unlock m;;
end


let main () =
  let model = create_model () in
  let window = GWindow.window () in
    window#connect#destroy ~callback:GMain.quit;
    let view = GTree.view ~model ~packing:window#add () in
    let col = GTree.view_column ~title:"Title" ()
		~renderer:(titleCellrenderer, ["text",titleCol]) in
      view#append_column col;
      let col = GTree.view_column ~title:"Author" ()
		  ~renderer:(authorCellrenderer, ["text",authorCol]) in
	view#append_column col;
	let col = GTree.view_column ~title:"Checked-out" ()
		    ~renderer:(GTree.cell_renderer_text[], ["text",checkedCol]) in
	  view#append_column col;

	  view#selection#connect#after#changed ~callback:
	    begin fun () ->
	      prerr_endline "selection changed";
	      List.iter view#selection#get_selected_rows ~f:
		(
		  fun p ->
		    (
		      prerr_endline (GtkTree.TreePath.to_string p);
		      UglyHackCellEditingModule.remove_cestoid ();
		      let id =
			GMain.Timeout.add
			  ~ms:200 (*UGLY HACK!!!!*)(*UGLY HACK!!!!*)
			  ~callback:
			  (
			    fun () ->
			      (
				prerr_endline ("Timeout callback running!");
				let () =
				  (
				    view#set_cursor
				     ~cell:authorCellrenderer
				     ~edit:true (*start_editing!*)
				     p
				     (view#get_column 1)
				  )
				in
				  false (*exec once only!*)
 			      )
			  )
		      in
			prerr_endline ("Timeout added");
			UglyHackCellEditingModule.set_cestoid (Some id);
			prerr_endline ("Timeout registered")
		    )
		)
	    end;

	  (*Jacques Garrigue's*)
	  authorCellrenderer#connect#edited ~callback:
	    begin fun p s ->
	      model#set ~row:(model#get_iter p) ~column:authorCol s
	    end;

	  window#connect#destroy
	    ~callback:
	    (
	      fun () ->
		(
		  UglyHackCellEditingModule.remove_cestoid ();
		  window#coerce#destroy ()
		)
	    )
	  ;

	  window#show ();
	  GMain.main ()

let () = main ()
-------------------------------

and with
	$ lablgtk2 -thread tree_testForCellEditing4.ml
this works.


Can anybody tell me whether do I really need to protect the id?

TIA

:-))

Ernesto