123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278(*********************************************************************************)(* Lablgtk-extras *)(* *)(* Copyright (C) 2011-2021 Institut National de Recherche en Informatique *)(* et en Automatique. All rights reserved. *)(* *)(* This program is free software; you can redistribute it and/or modify *)(* it under the terms of the GNU Library General Public License as *)(* published by the Free Software Foundation; either version 3 of the *)(* License. *)(* *)(* This program is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Library General Public License for more details. *)(* *)(* You should have received a copy of the GNU Library General Public *)(* License along with this program; if not, write to the Free Software *)(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA *)(* 02111-1307 USA *)(* *)(* Contact: Maxence.Guesdon@inria.fr *)(* *)(* *)(*********************************************************************************)typecol_desc=[`Stringofstring|`Pixmapofstringoption]typecol_row_contents=[`Stringofstring|`PixmapofGdkPixbuf.pixbufoption]class['a]tree_edit?(f_expand=fun(_:'a)->false)~(f_roots:unit->'alist)~(f_children:'a->'alist)?(f_edit:('a->'a)option)?(f_add:('aoption->'aoption)option)?(f_remove:('a->bool)option)?(f_close:(unit->unit)option)~(f_contents:'a->col_row_contentslist)cols=letbox1=GPack.hbox()inletwscroll=GBin.scrolled_window~vpolicy:`AUTOMATIC~hpolicy:`AUTOMATIC~packing:(box1#pack~expand:true)()inletbox2=GPack.vbox~packing:(box1#pack~expand:false)()inlettcols=newGTree.column_listinletdisp_cols=List.map(function|`String_->`String(tcols#addGobject.Data.string)|`Pixmap_->`Pixbuf(tcols#add(Gobject.Data.gobject:GdkPixbuf.pixbufGobject.data_conv)))colsinlet(datacol:'aGTree.column)=tcols#addGobject.Data.camlinletstore=GTree.tree_storetcolsinletview=GTree.view~headers_visible:false~model:store~packing:wscroll#add_with_viewport()inletrenderer=GTree.cell_renderer_text[]inletpix_renderer=GTree.cell_renderer_pixbuf[]inlet_=List.iter(func->letcol=matchcwith|`Stringc->GTree.view_column()~renderer:(renderer,["text",c])|`Pixbufc->GTree.view_column()~renderer:(pix_renderer,["pixbuf",c])inignore(view#append_columncol))disp_colsinobject(self)valmutableselection=(None:'aoption)methodselected_row=matchview#selection#get_selected_rowswith[]->None|p::_->Some(store#get_iterp)methodview=viewmethodbox=box1#coercemethodbuttons_box=box2methodon_selectv=()methodon_unselectv=()methodon_double_clickv=()methodselectv=selection<-Somev;self#on_selectvmethodunselectv=selection<-None;self#on_unselectvmethodinsert?(append=false)?parent(t:'a)=letrow=(ifappendthenstore#appendelsestore#prepend)?parent()inself#set_rowrowt;matchList.rev(f_childrent)with|[]->()|l->letrr=store#get_row_reference(store#get_pathrow)inList.iter(self#insert~append~parent:row)l;iff_expandtthenview#expand_rowrr#pathmethodupdate=(matchselectionwith|None->()|Somev->selection<-None;self#unselectv);store#clear();letroots=f_roots()inList.iter(self#insert?parent:None)(List.revroots)methodprivateset_row_colrowcolcontents=matchcol,contentswith|`Stringcol,`Strings->store#setrowcols|`Pixbufcol,`Pixmap(Somepix)->store#setrowcolpix|_->()methodset_rowrowt=letcontents=f_contentstinList.iter2(self#set_row_colrow)disp_colscontents;store#setrowdatacoltmethodedit()=matchf_edit,view#selection#get_selected_rowswith|None,_|_,[]->()|Somef,path::_->letrow=store#get_iterpathinlett=store#get~row~column:datacolinlet(t2:'a)=ftinself#set_rowrowt2methodadd()=matchf_addwith|None->()|Somef->matchview#selection#get_selected_rowswith|[]->(matchfNonewithNone->()|Somet->self#insertt)|path::_->letrr=store#get_row_referencepathinletparent=store#get~row:rr#iter~column:datacolin(matchf(Someparent)withNone->()|Somet->self#insert~parent:rr#itert)methodremove()=matchf_removewith|None->()|Somef->matchview#selection#get_selected_rowswith[]->()|path::_->letrow=store#get_iterpathiniff(store#get~row~column:datacol)thenignore(store#removerow)else()methodremove_rowrow=store#removerowmethodadd_button:string->('aoption->(unit->unit)->unit)->unit=funlabelf->letw=GButton.button~label~packing:self#buttons_box#pack()inletg()=matchview#selection#get_selected_rowswith|[]->fNone(fun()->self#update)|path::_->letrow=store#get_iterpathinf(Some(store#get~row~column:datacol))(fun()->self#update)inignore(w#connect#clickedg)methodmenu=([]:GToolbox.menu_entrylist)methodfather_datarow=matchstore#iter_parentrowwith|None->None|Someit->Some(store#get~row:it~column:datacol)initializerview#selection#set_mode`SINGLE;List.iterself#insert(List.rev(f_roots()));letl=(iff_edit=Nonethen[]else[`EDIT,self#edit])@(iff_add=Nonethen[]else[`ADD,self#add])@(iff_remove=Nonethen[]else[`REMOVE,self#remove])@(matchf_closewithNone->[]|Somef->[`CLOSE,f])inList.iter(fun(stock,cb)->letwb=GButton.button~stock~packing:self#buttons_box#pack()inignore(wb#connect#clickedcb))l;ignore(view#selection#connect#changed(fun()->letsel=view#selectioninmatchsel#get_selected_rowswith|[]->(matchselectionwith|None->()|Somev->self#unselectv)|path::_->letit=store#get_iterpathinletv=store#get~row:it~column:datacolin(matchselectionwith|None->()|Somev->self#unselectv);self#selectv));(* connect the press on button 3 for contextual menu
and two_button for double click *)ignore(view#event#connect#button_press~callback:(funev->matchGdkEvent.get_typeevwith|`BUTTON_PRESSwhenGdkEvent.Button.buttonev=3->(GToolbox.popup_menu~button:3~time:(Int32.zero)~entries:self#menu;true)|`TWO_BUTTON_PRESS->(letx=int_of_float(GdkEvent.Button.xev)inlety=int_of_float(GdkEvent.Button.yev)inmatchview#get_path_at_pos~x~ywith|None->true|Some(path,_,_,_)->letd=letit=store#get_iterpathinstore#get~row:it~column:datacolinself#on_double_clickd;true)|`BUTTON_PRESS|`BUTTON_RELEASE|`THREE_BUTTON_PRESS->false));end