1#
2#  tkextlib/blt/tree.rb
3#                               by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
4#
5
6require 'tk'
7require 'tkextlib/blt.rb'
8
9module Tk::BLT
10  class Tree < TkObject
11    TkCommandNames = ['::blt::tree'.freeze].freeze
12
13    ###################################
14
15    class Node < TkObject
16      TreeNodeID_TBL = TkCore::INTERP.create_table
17
18      TkCore::INTERP.init_ip_env{
19        TreeNodeID_TBL.mutex.synchronize{ TreeNodeID_TBL.clear }
20      }
21
22      def self.id2obj(tree, id)
23        tpath = tree.path
24        TreeNodeID_TBL.mutex.synchronize{
25          if TreeNodeID_TBL[tpath]
26            if TreeNodeID_TBL[tpath][id]
27              TreeNodeID_TBL[tpath][id]
28            else
29              begin
30                # self.new(tree, nil, 'node'=>Integer(id))
31                id = Integer(id)
32                if bool(tk_call(@tpath, 'exists', id))
33                  (obj = self.allocate).instance_eval{
34                    @parent = @tree = tree
35                    @tpath = tpath
36                    @path = @id = id
37                    TreeNodeID_TBL[@tpath] = {} unless TreeNodeID_TBL[@tpath]
38                    TreeNodeID_TBL[@tpath][@id] = self
39                  }
40                  obj
41                else
42                  id
43                end
44              rescue
45                id
46              end
47            end
48          else
49            id
50          end
51        }
52      end
53
54      def self.new(tree, parent, keys={})
55        keys = _symbolkey2str(keys)
56        tpath = tree.path
57
58        TreeNodeID_TBL.mutex.synchronize{
59          TreeNodeID_TBL[tpath] ||= {}
60          if (id = keys['node']) && (obj = TreeNodeID_TBL[tpath][id])
61            keys.delete('node')
62            tk_call(tree.path, 'move', id, parent, keys) if parent
63            return obj
64          end
65
66          (obj = self.allocate).instance_eval{
67            initialize(tree, parent, keys)
68            TreeNodeID_TBL[tpath][@id] = self
69          }
70          obj
71        }
72      end
73
74      def initialize(tree, parent, keys={})
75        @parent = @tree = tree
76        @tpath = @parent.path
77
78        if (id = keys['node']) && bool(tk_call(@tpath, 'exists', id))
79          @path = @id = id
80          keys.delete('node')
81          tk_call(@tpath, 'move', @id, parent, keys) if parent
82        else
83          parent = tk_call(@tpath, 'root') unless parent
84          @path = @id = tk_call(@tpath, 'insert', parent, keys)
85        end
86      end
87
88      def id
89        @id
90      end
91
92      def apply(keys={})
93        @tree.apply(@id, keys)
94        self
95      end
96
97      def children()
98        @tree.children(@id)
99      end
100
101      def copy(parent, keys={})
102        @tree.copy(@id, parent, keys)
103      end
104      def copy_to(dest_tree, parent, keys={})
105        @tree.copy_to(@id, dest_tree, parent, keys)
106      end
107
108      def degree()
109        @tree.degree(@id)
110      end
111
112      def delete()
113        @tree.delete(@id)
114        self
115      end
116
117      def depth()
118        @tree.depth(@id)
119      end
120
121      def dump()
122        @tree.dump(@id)
123      end
124
125      def dump_to_file(file)
126        @tree.dump_to_file(@id, file)
127        self
128      end
129
130      def exist?(keys={})
131        @tree.exist?(@id, keys)
132      end
133
134      def find(keys={})
135        @tree.find(@id, keys)
136      end
137
138      def find_child(label)
139        @tree.find_child(@id, label)
140      end
141
142      def first_child()
143        @tree.first_child(@id)
144      end
145
146      def get()
147        @tree.get(@id)
148      end
149      def get_value(key, default_val=None)
150        @tree.get_value(@id, key, default_val)
151      end
152
153      def index()
154        @tree.index(@id)
155      end
156
157      def leaf?()
158        @tree.leaf?(@id)
159      end
160      def link?()
161        @tree.link?(@id)
162      end
163      def root?()
164        @tree.root?(@id)
165      end
166
167      def keys()
168        @tree.keys(@id)
169      end
170
171      def label(text = nil)
172        @tree.label(@id, nil)
173      end
174      def label=(text)
175        @tree.label(@id, text)
176      end
177
178      def last_child()
179        @tree.last_child(@id)
180      end
181
182      def move(dest, keys={})
183        @tree.keys(@id, dest, keys)
184        self
185      end
186
187      def next()
188        @tree.next(@id)
189      end
190
191      def next_sibling()
192        @tree.next_sibling(@id)
193      end
194
195      def parent()
196        @tree.parent(@id)
197      end
198
199      def fullpath()
200        @tree.fullpath(@id)
201      end
202
203      def position()
204        @tree.position(@id)
205      end
206
207      def previous()
208        @tree.previous(@id)
209      end
210
211      def prev_sibling()
212        @tree.prev_sibling(@id)
213      end
214
215      def restore(str, keys={})
216        @tree.restore(@id, str, keys)
217        self
218      end
219      def restore_overwrite(str, keys={})
220        @tree.restore_overwrite(@id, str, keys)
221        self
222      end
223
224      def restore_from_file(file, keys={})
225        @tree.restore_from_file(@id, file, keys)
226        self
227      end
228      def restore_overwrite_from_file(file, keys={})
229        @tree.restore_overwrite_from_file(@id, file, keys)
230        self
231      end
232
233      def root()
234        @tree.root(@id)
235        self
236      end
237
238      def set(data)
239        @tree.set(@id, data)
240        self
241      end
242
243      def size()
244        @tree.size(@id)
245      end
246
247      def sort(keys={})
248        @tree.sort(@id, keys)
249        self
250      end
251
252      def type(key)
253        @tree.type(@id, key)
254      end
255
256      def unset(*keys)
257        @tree.unset(@id, *keys)
258        self
259      end
260
261      def values(key=None)
262        @tree.values(@id, key)
263      end
264    end
265
266    ###################################
267
268    class Tag < TkObject
269      TreeTagID_TBL = TkCore::INTERP.create_table
270
271      TkCore::INTERP.init_ip_env{
272        TreeTagID_TBL.mutex.synchronize{ TreeTagID_TBL.clear }
273      }
274
275      (TreeTag_ID = ['blt_tree_tag'.freeze, TkUtil.untrust('00000')]).instance_eval{
276        @mutex = Mutex.new
277        def mutex; @mutex; end
278        freeze
279      }
280
281      def self.id2obj(tree, id)
282        tpath = tree.path
283        TreeTagID_TBL.mutex.synchronize{
284          if TreeTagID_TBL[tpath]
285            if TreeTagID_TBL[tpath][id]
286              TreeTagID_TBL[tpath][id]
287            else
288              begin
289                # self.new(tree, id)
290                (obj = self.allocate).instance_eval{
291                  @parent = @tree = tree
292                  @tpath = @parent.path
293                  @path = @id = id.dup.freeze if id
294                  TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
295                  TreeTagID_TBL[@tpath][@id] = self
296                }
297                obj
298              rescue
299                id
300              end
301            end
302          else
303            id
304          end
305        }
306      end
307
308      def initialize(tree, tag_str = nil)
309        @parent = @tree = tree
310        @tpath = @parent.path
311
312        if tag_str
313          @path = @id = tag_str.dup.freeze
314        else
315          TreeTag_ID.mutex.synchronize{
316            @path = @id = TreeTag_ID.join(TkCore::INTERP._ip_id_)
317            TreeTag_ID[1].succ!
318          }
319        end
320        TreeTagID_TBL.mutex.synchronize{
321          TreeTagID_TBL[@tpath] = {} unless TreeTagID_TBL[@tpath]
322          TreeTagID_TBL[@tpath][@id] = self
323        }
324      end
325
326      def id
327        @id
328      end
329
330      def add(*nodes)
331        tk_call(@tpath, 'tag', 'add', @id, *nodes)
332        self
333      end
334
335      def delete(*nodes)
336        tk_call(@tpath, 'tag', 'delete', @id, *nodes)
337        self
338      end
339
340      def forget()
341        tk_call(@tpath, 'tag', 'forget', @id)
342        TreeTagID_TBL.mutex.synchronize{
343          TreeTagID_TBL[@tpath].delete(@id)
344        }
345        self
346      end
347
348      def nodes()
349        simplelist(tk_call(@tpath, 'tag', 'nodes', @id)).collect{|node|
350          Tk::BLT::Tree::Node.id2obj(@path, node)
351        }
352      end
353
354      def set(node)
355        tk_call(@tpath, 'tag', 'set', node, @id)
356        self
357      end
358
359      def unset(node)
360        tk_call(@tpath, 'tag', 'unset', node, @id)
361        self
362      end
363    end
364
365    ###################################
366
367    class Notify < TkObject
368      NotifyID_TBL = TkCore::INTERP.create_table
369
370      TkCore::INTERP.init_ip_env{
371        NotifyID_TBL.mutex.synchronize{ NotifyID_TBL.clear }
372      }
373
374      def self.id2obj(tree, id)
375        tpath = tree.path
376        NotifyID_TBL.mutex.synchronize{
377          if NotifyID_TBL[tpath]
378            if NotifyID_TBL[tpath][id]
379              NotifyID_TBL[tpath][id]
380            else
381              (obj = self.allocate).instance_eval{
382                @parent = @tree = tree
383                @tpath = @parent.path
384                @path = @id = id
385                NotifyID_TBL[@tpath] ||= {}
386                NotifyID_TBL[@tpath][@id] = self
387              }
388              obj
389            end
390          else
391            return id
392          end
393        }
394      end
395
396      def self.new(tree, *args, &b)
397        NotifyID_TBL.mutex.synchronize{
398          if tree.kind_of?(Array)
399            # not create
400            tpath = tree[0].path
401            NotifyID_TBL[tpath] ||= {}
402            unless (obj = NotifyID_TBL[tpath][tree[1]])
403              (NotifyID_TBL[tpath][tree[1]] =
404                 obj = self.allocate).instance_eval{
405                @parent = @tree = tree[0]
406                @tpath = @parent.path
407                @path = @id = tree[1]
408              }
409            end
410            return obj
411          end
412
413          (obj = self.allocate).instance_eval{
414            initialize(tree, *args, &b)
415            NotifyID_TBL[@tpath] ||= {}
416            NotifyID_TBL[@tpath][@id] = self
417          }
418          return obj
419        }
420      end
421
422      def initialize(tree, *args, &b)
423        @parent = @tree = tree
424        @tpath = @parent.path
425
426        # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
427        if TkComm._callback_entry?(args[0])
428          cmd = args.shift
429        # elsif args[-1].kind_of?(Proc) || args[-1].kind_of?(Method)
430        elsif TkComm._callback_entry?(args[-1])
431          cmd = args.pop
432        elsif b
433          cmd = Proc.new(&b)
434        else
435          fail ArgumentError, "lack of 'command' argument"
436        end
437
438        args = args.collect{|arg| '-' << arg.to_s}
439
440        args << proc{|id, type|
441          cmd.call(Tk::BLT::Tree::Node.id2obj(@tree, id),
442                   ((type[0] == ?-)? type[1..-1]: type))
443        }
444
445        @path = @id = tk_call(@tpath, 'notify', 'create', *args)
446      end
447
448      def id
449        @id
450      end
451
452      def delete()
453        tk_call(@tpath, 'notify', 'delete', @id)
454        NotifyID_TBL.mutex.synchronize{
455          NotifyID_TBL[@tpath].delete(@id)
456        }
457        self
458      end
459
460      def info()
461        lst = simplelist(tk_call(@tpath, 'notify', 'info', id))
462        lst[0] = Tk::BLT::Tree::Notify.id2obj(@tree, lst[0])
463        lst[1] = simplelist(lst[1]).collect{|flag| flag[1..-1]}
464        lst[2] = tk_tcl2ruby(lst[2])
465        lst
466      end
467    end
468
469    ###################################
470
471    class Trace < TkObject
472      TraceID_TBL = TkCore::INTERP.create_table
473
474      TkCore::INTERP.init_ip_env{
475        TraceID_TBL.mutex.synchronize{ TraceID_TBL.clear }
476      }
477
478      def self.id2obj(tree, id)
479        tpath = tree.path
480        TraceID_TBL.mutex.synchronize{
481          if TraceID_TBL[tpath]
482            if TraceID_TBL[tpath][id]
483              TraceID_TBL[tpath][id]
484            else
485              begin
486                # self.new([tree, id])
487                (obj = self.allocate).instance_eval{
488                  @parent = @tree = tree
489                  @tpath = @parent.path
490                  @path = @id = node  # == traceID
491                  TraceID_TBL[@tpath] ||= {}
492                  TraceID_TBL[@tpath][@id] = self
493                }
494                obj
495              rescue
496                id
497              end
498            end
499          else
500            id
501          end
502        }
503      end
504
505      def self.new(tree, *args, &b)
506        TraceID_TBL.mutex.synchronize{
507          if tree.kind_of?(Array)
508            # not create
509            tpath = tree[0].path
510            TraceID_TBL[tpath] ||= {}
511            unless (obj = TraceID_TBL[tpath][tree[1]])
512              (TraceID_TBL[tpath][tree[1]] =
513                 obj = self.allocate).instance_eval{
514                @parent = @tree = tree
515                @tpath = @parent.path
516                @path = @id = tree[1]  # == traceID
517              }
518            end
519            return obj
520          end
521
522          # super(true, tree, *args, &b)
523          (obj = self.allocate).instance_eval{
524            initialize(tree, *args, &b)
525            TraceID_TBL[@tpath] ||= {}
526            TraceID_TBL[@tpath][@id] = self
527          }
528          return obj
529        }
530      end
531
532      def initialize(tree, node, key, opts, cmd=nil, &b)
533        @parent = @tree = tree
534        @tpath = @parent.path
535
536        if !cmd
537          if b
538            cmd = Proc.new(&b)
539          else
540            fail ArgumentError, "lack of 'command' argument"
541          end
542        end
543
544        @path = @id = tk_call(@tpath, 'trace', 'create', node, key, opts,
545                              proc{|t, id, k, ops|
546                                tobj = Tk::BLT::Tree.id2obj(t)
547                                if tobj.kind_of?(Tk::BLT::Tree)
548                                  nobj = Tk::BLT::Tree::Node.id2obj(tobj, id)
549                                else
550                                  nobj = id
551                                end
552                                cmd.call(tobj, nobj, k, ops)
553                              })
554      end
555
556      def id
557        @id
558      end
559
560      def delete()
561        tk_call(@tpath, 'trace', 'delete', @id)
562        TraceID_TBL.mutex.synchronize{
563          TraceID_TBL[tpath].delete(@id)
564        }
565        self
566      end
567
568      def info()
569        lst = simplelist(tk_call(@tpath, 'trace', 'info', id))
570        lst[0] = Tk::BLT::Tree::Trace.id2obj(@tree, lst[0])
571        lst[2] = simplelist(lst[2])
572        lst[3] = tk_tcl2ruby(lst[3])
573        lst
574      end
575    end
576
577    ###################################
578
579    TreeID_TBL = TkCore::INTERP.create_table
580
581    (Tree_ID = ['blt_tree'.freeze, TkUtil.untrust('00000')]).instance_eval{
582      @mutex = Mutex.new
583      def mutex; @mutex; end
584      freeze
585    }
586
587    def __keyonly_optkeys
588      {
589        # apply / find  command
590        'invert'=>nil, 'leafonly'=>nil, 'nocase'=>nil,
591
592        # apply / find / sort command
593        'path'=>nil,
594
595        # copy / restore / restorefile command
596        'overwrite'=>nil,
597
598        # copy command
599        'recurse'=>nil, 'tags'=>nil,
600
601        # sort command
602        'ascii'=>nil, 'decreasing'=>nil, 'disctionary'=>nil,
603        'integer'=>nil, 'real'=>nil, 'recurse'=>nil, 'reorder'=>nil,
604      }
605    end
606
607    def self.id2obj(id)
608      TreeID_TBL.mutex.synchronize{
609        TreeID_TBL[id]? TreeID_TBL[id]: id
610      }
611    end
612
613    def self.names(pat = None)
614      simplelist(tk_call('::blt::tree', 'names', pat)).collect{|name|
615        id2obj(name)
616      }
617    end
618
619    def self.destroy(*names)
620      tk_call('::blt::tree', 'destroy',
621              *(names.collect{|n| (n.kind_of?(Tk::BLT::Tree))? n.id: n }) )
622    end
623
624    def self.new(name = nil)
625      TreeID_TBL.mutex.synchronize{
626        if name && TreeID_TBL[name]
627          TreeID_TBL[name]
628        else
629          (obj = self.allocate).instance_eval{
630            initialize(name)
631            TreeID_TBL[@id] = self
632          }
633          obj
634        end
635      }
636    end
637
638    def initialzie(name = nil)
639      if name
640        @path = @id = name
641      else
642        Tree_ID.mutex.synchronize{
643          @path = @id = Tree_ID.join(TkCore::INTERP._ip_id_)
644          Tree_ID[1].succ!
645        }
646      end
647
648      tk_call('::blt::tree', 'create', @id)
649    end
650
651    def __destroy_hook__
652      Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{
653        Tk::BLT::Tree::Node::TreeNodeID_TBL.delete(@path)
654      }
655      Tk::BLT::Tree::Tag::TreeTagID_TBL.mutex.synchronize{
656        Tk::BLT::Tree::Tag::TreeTagID_TBL.delete(@path)
657      }
658      Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{
659        Tk::BLT::Tree::Notify::NotifyID_TBL.delete(@path)
660      }
661      Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{
662        Tk::BLT::Tree::Trace::TraceID_TBL.delete(@path)
663      }
664    end
665
666    def tagid(tag)
667      if tag.kind_of?(Tk::BLT::Tree::Node) ||
668          tag.kind_of?(Tk::BLT::Tree::Tag) ||
669          tag.kind_of?(Tk::BLT::Tree::Notify) ||
670          tag.kind_of?(Tk::BLT::Tree::Trace)
671        tag.id
672      else
673        tag  # maybe an Array of configure paramters
674      end
675    end
676
677    def destroy()
678      tk_call('::blt::tree', 'destroy', @id)
679      self
680    end
681
682    def ancestor(node1, node2)
683      Tk::BLT::Tree::Node.id2obj(self, tk_call('::blt::tree', 'ancestor',
684                                               tagid(node1), tagid(node2)))
685    end
686
687    def apply(node, keys={})
688      tk_call('::blt::tree', 'apply', tagid(node), __conv_keyonly_opts(keys))
689      self
690    end
691
692    def attach(tree_obj)
693      tk_call('::blt::tree', 'attach', tree_obj)
694      self
695    end
696
697    def children(node)
698      simplelist(tk_call('::blt::tree', 'children', tagid(node))).collect{|n|
699        Tk::BLT::Tree::Node.id2obj(self, n)
700      }
701    end
702
703    def copy(src, parent, keys={})
704      id = tk_call('::blt::tree', 'copy', tagid(src), tagid(parent),
705                   __conv_keyonly_opts(keys))
706      Tk::BLT::Tree::Node.new(self, nil, 'node'=>id)
707    end
708    def copy_to(src, dest_tree, parent, keys={})
709      return copy(src, parent, keys={}) unless dest_tree
710
711      id = tk_call('::blt::tree', 'copy', tagid(src), dest_tree,
712                   tagid(parent), __conv_keyonly_opts(keys))
713      Tk::BLT::Tree::Node.new(dest_tree, nil, 'node'=>id)
714    end
715
716    def degree(node)
717      number(tk_call('::blt::tree', 'degree', tagid(node)))
718    end
719
720    def delete(*nodes)
721      tk_call('::blt::tree', 'delete', *(nodes.collect{|node| tagid(node)}))
722      Tk::BLT::Tree::Node::TreeNodeID_TBL.mutex.synchronize{
723        nodes.each{|node|
724          if node.kind_of?(Tk::BLT::Tree::Node)
725            Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.id)
726          else
727            Tk::BLT::Tree::Node::TreeNodeID_TBL[@path].delete(node.to_s)
728          end
729        }
730      }
731      self
732    end
733
734    def depth(node)
735      number(tk_call('::blt::tree', 'depth', tagid(node)))
736    end
737
738    def dump(node)
739      simplelist(tk_call('::blt::tree', 'dump', tagid(node))).collect{|n|
740        simplelist(n)
741      }
742    end
743
744    def dump_to_file(node, file)
745      tk_call('::blt::tree', 'dumpfile', tagid(node), file)
746      self
747    end
748
749    def exist?(node, key=None)
750      bool(tk_call('::blt::tree', 'exists', tagid(node), key))
751    end
752
753    def find(node, keys={})
754      simplelist(tk_call('::blt::tree', 'find', tagid(node),
755                         __conv_keyonly_opts(keys))).collect{|n|
756        Tk::BLT::Tree::Node.id2obj(self, n)
757      }
758    end
759
760    def find_child(node, label)
761      ret = tk_call('::blt::tree', 'findchild', tagid(node), label)
762      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
763    end
764
765    def first_child(node)
766      ret = tk_call('::blt::tree', 'firstchild', tagid(node))
767      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
768    end
769
770    def get(node)
771      Hash[*simplelist(tk_call('::blt::tree', 'get', tagid(node)))]
772    end
773    def get_value(node, key, default_val=None)
774      tk_call('::blt::tree', 'get', tagid(node), key, default_val)
775    end
776
777    def index(node)
778      Tk::BLT::Tree::Node.id2obj(self,
779                                 tk_call('::blt::tree', 'index', tagid(node)))
780    end
781
782    def insert(parent, keys={})
783      id = tk_call('::blt::tree', 'insert', tagid(parent), keys)
784      Tk::BLT::Tree::Node.new(self, nil, 'node'=>id)
785    end
786
787    def ancestor?(node1, node2)
788      bool(tk_call('::blt::tree', 'is', 'ancestor',
789                   tagid(node1), tagid(node2)))
790    end
791    def before?(node1, node2)
792      bool(tk_call('::blt::tree', 'is', 'before',
793                   tagid(node1), tagid(node2)))
794    end
795    def leaf?(node)
796      bool(tk_call('::blt::tree', 'is', 'leaf', tagid(node)))
797    end
798    def link?(node)
799      bool(tk_call('::blt::tree', 'is', 'link', tagid(node)))
800    end
801    def root?(node)
802      bool(tk_call('::blt::tree', 'is', 'root', tagid(node)))
803    end
804
805    def keys(node, *nodes)
806      if nodes.empty?
807        simplelist(tk_call('blt::tree', 'keys', tagid(node)))
808      else
809        simplelist(tk_call('blt::tree', 'keys', tagid(node),
810                           *(nodes.collect{|n| tagid(n)}))).collect{|lst|
811          simplelist(lst)
812        }
813      end
814    end
815
816    def label(node, text=nil)
817      if text
818        tk_call('::blt::tree', 'label', tagid(node), text)
819        text
820      else
821        tk_call('::blt::tree', 'label', tagid(node))
822      end
823    end
824
825    def last_child(node)
826      ret = tk_call('::blt::tree', 'lastchild', tagid(node))
827      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
828    end
829
830    def link(parent, node, keys={})
831      ret = tk_call('::blt::tree', 'link', tagid(parent), tagid(node),
832                    __conv_keyonly_opts(keys))
833      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
834    end
835
836    def move(node, dest, keys={})
837      tk_call('::blt::tree', 'move', tagid(node), tagid(dest), keys)
838      self
839    end
840
841    def next(node)
842      ret = tk_call('::blt::tree', 'next', tagid(node))
843      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
844    end
845
846    def next_sibling(node)
847      ret = tk_call('::blt::tree', 'nextsibling', tagid(node))
848      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
849    end
850
851    def notify_create(*args, &b)
852      Tk::BLT::Tree::Notify.new(self, *args, &b)
853    end
854
855    def notify_delete(id)
856      if id.kind_of?(Tk::BLT::Tree::Notify)
857        id.delete
858      else
859        tk_call(@path, 'notify', 'delete', id)
860        Tk::BLT::Tree::Notify::NotifyID_TBL.mutex.synchronize{
861          Tk::BLT::Tree::Notify::NotifyID_TBL[@path].delete(id.to_s)
862        }
863      end
864      self
865    end
866
867    def notify_info(id)
868      lst = simplelist(tk_call(@path, 'notify', 'info', tagid(id)))
869      lst[0] = Tk::BLT::Tree::Notify.id2obj(self, lst[0])
870      lst[1] = simplelist(lst[1]).collect{|flag| flag[1..-1]}
871      lst[2] = tk_tcl2ruby(lst[2])
872      lst
873    end
874
875    def notify_names()
876      tk_call(@path, 'notify', 'names').collect{|id|
877        Tk::BLT::Tree::Notify.id2obj(self, id)
878      }
879    end
880
881    def parent(node)
882      ret = tk_call('::blt::tree', 'parent', tagid(node))
883      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
884    end
885
886    def fullpath(node)
887      tk_call('::blt::tree', 'path', tagid(node))
888    end
889
890    def position(node)
891      number(tk_call('::blt::tree', 'position', tagid(node)))
892    end
893
894    def previous(node)
895      ret = tk_call('::blt::tree', 'previous', tagid(node))
896      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
897    end
898
899    def prev_sibling(node)
900      ret = tk_call('::blt::tree', 'prevsibling', tagid(node))
901      (ret == '-1')? nil: Tk::BLT::Tree::Node.id2obj(self, ret)
902    end
903
904    def restore(node, str, keys={})
905      tk_call('::blt::tree', 'restore', tagid(node), str,
906              __conv_keyonly_opts(keys))
907      self
908    end
909    def restore_overwrite(node, str, keys={})
910      keys = __conv_keyonly_opts(keys)
911      keys.delete('overwrite')
912      keys.delete(:overwrite)
913      tk_call('::blt::tree', 'restore', tagid(node), str, '-overwrite', keys)
914      self
915    end
916
917    def restore_from_file(node, file, keys={})
918      tk_call('::blt::tree', 'restorefile', tagid(node), file,
919              __conv_keyonly_opts(keys))
920      self
921    end
922    def restore_overwrite_from_file(node, file, keys={})
923      keys = __conv_keyonly_opts(keys)
924      keys.delete('overwrite')
925      keys.delete(:overwrite)
926      tk_call('::blt::tree', 'restorefile', tagid(node), file,
927              '-overwrite', keys)
928      self
929    end
930
931    def root(node=None)
932      Tk::BLT::Tree::Node.id2obj(self, tk_call('::blt::tree', 'root',
933                                               tagid(node)))
934    end
935
936    def set(node, data)
937      unless data.kind_of?(Hash)
938        fail ArgumentError, 'Hash is expected for data'
939      end
940      args = []
941      data.each{|k, v|  args << k << v}
942      tk_call('::blt::tree', 'set', tagid(node), *args)
943      self
944    end
945
946    def size(node)
947      number(tk_call('::blt::tree', 'size', tagid(node)))
948    end
949
950    def sort(node, keys={})
951      tk_call('::blt::tree', 'sort', tagid(node), __conv_keyonly_opts(keys))
952      self
953    end
954
955    def tag_add(tag, *nodes)
956      tk_call(@path, 'tag', 'add', tagid(tag), *(nodes.collect{|n| tagid(n)}))
957      self
958    end
959
960    def tag_delete(tag, *nodes)
961      tk_call(@path, 'tag', 'delete', tagid(tag),
962              *(nodes.collect{|n| tagid(n)}))
963      self
964    end
965
966    def tag_forget(tag)
967      tag = tag.id if tag.kind_of?(Tk::BLT::Tree::Tag)
968      tk_call(@path, 'tag', 'forget', tag)
969      TreeTagID_TBL.mutex.synchronize{
970        TreeTagID_TBL[@path].delete(tag)
971      }
972      self
973    end
974
975    def tag_get(node, *patterns)
976      simplelist(tk_call(@tpath, 'tag', 'get', tagid(node),
977                         *(patterns.collect{|pat| tagid(pat)}))).collect{|str|
978        Tk::BLT::Tree::Tag.id2obj(self, str)
979      }
980    end
981
982    def tag_names(node = None)
983      simplelist(tk_call(@tpath, 'tag', 'names', tagid(node))).collect{|str|
984        Tk::BLT::Tree::Tag.id2obj(self, str)
985      }
986    end
987
988    def tag_nodes(tag)
989      simplelist(tk_call(@tpath, 'tag', 'nodes', tagid(tag))).collect{|node|
990        Tk::BLT::Tree::Node.id2obj(self, node)
991      }
992    end
993
994    def tag_set(node, *tags)
995      tk_call(@path, 'tag', 'set', tagid(node), *(tags.collect{|t| tagid(t)}))
996      self
997    end
998
999    def tag_unset(node, *tags)
1000      tk_call(@path, 'tag', 'unset', tagid(node),
1001              *(tags.collect{|t| tagid(t)}))
1002      self
1003    end
1004
1005    def trace_create(*args, &b)
1006      Tk::BLT::Tree::Trace.new(self, *args, &b)
1007    end
1008
1009=begin
1010    def trace_delete(*args)
1011      args.each{|id|
1012        if id.kind_of?(Tk::BLT::Tree::Trace)
1013          id.delete
1014        else
1015          tk_call(@path, 'trace', 'delete', id)
1016          Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)
1017        end
1018        self
1019      }
1020    end
1021=end
1022    def trace_delete(*args)
1023      args = args.collect{|id| tagid(id)}
1024      tk_call(@path, 'trace', 'delete', *args)
1025      Tk::BLT::Tree::Trace::TraceID_TBL.mutex.synchronize{
1026        args.each{|id| Tk::BLT::Tree::Trace::TraceID_TBL[@path].delete(id.to_s)}
1027      }
1028      self
1029    end
1030
1031    def trace_info(id)
1032      lst = simplelist(tk_call(@path, 'trace', 'info', tagid(id)))
1033      lst[0] = Tk::BLT::Tree::Trace.id2obj(self, lst[0])
1034      lst[2] = simplelist(lst[2])
1035      lst[3] = tk_tcl2ruby(lst[3])
1036      lst
1037    end
1038
1039    def trace_names()
1040      tk_call(@path, 'trace', 'names').collect{|id|
1041        Tk::BLT::Tree::Trace.id2obj(self, id)
1042      }
1043    end
1044
1045    def type(node, key)
1046      tk_call('::blt::tree', 'type', tagid(node), key)
1047    end
1048
1049    def unset(node, *keys)
1050      tk_call('::blt::tree', 'unset', tagid(node), *keys)
1051      self
1052    end
1053
1054    def values(node, key=None)
1055      simplelist(tk_call('::blt::tree', 'values', tagid(node), key))
1056    end
1057  end
1058end
1059