1#
2#  treeview widget
3#                               by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
4#
5require 'tk'
6require 'tkextlib/tile.rb'
7
8module Tk
9  module Tile
10    class Treeview < TkWindow
11    end
12  end
13end
14
15module Tk::Tile::TreeviewConfig
16  include TkItemConfigMethod
17
18  def __item_configinfo_struct(id)
19    # maybe need to override
20    {:key=>0, :alias=>nil, :db_name=>nil, :db_class=>nil,
21      :default_value=>nil, :current_value=>1}
22  end
23  private :__item_configinfo_struct
24
25  def __itemconfiginfo_core(tagOrId, slot = nil)
26    if TkComm::GET_CONFIGINFO_AS_ARRAY
27      if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
28        fontkey  = $2
29        return [slot.to_s, tagfontobj(tagid(tagOrId), fontkey)]
30      else
31        if slot
32          slot = slot.to_s
33
34          alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot}
35          if real_name
36            slot = real_name.to_s
37          end
38
39          case slot
40          when /^(#{__tile_specific_item_optkeys(tagid(tagOrId)).join('|')})$/
41            begin
42              # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
43              val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << slot))
44            rescue
45              # Maybe, 'state' option has '-' in future.
46              val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
47            end
48            return [slot, val]
49
50          when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
51            method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot]
52            optval = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
53            begin
54              val = method.call(tagOrId, optval)
55            rescue => e
56              warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
57              val = optval
58            end
59            return [slot, val]
60
61          when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/
62            method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot]
63            return [slot, self.__send__(method, tagOrId)]
64
65          when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
66            begin
67              val = number(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
68            rescue
69              val = nil
70            end
71            return [slot, val]
72
73          when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
74            val = num_or_str(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
75            return [slot, val]
76
77          when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
78            begin
79              val = bool(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
80            rescue
81              val = nil
82            end
83            return [slot, val]
84
85          when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
86            val = simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
87            return [slot, val]
88
89          when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
90            val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
91            if val =~ /^[0-9]/
92              return [slot, list(val)]
93            else
94              return [slot, val]
95            end
96
97          when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
98            val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
99            return [slot, val]
100
101          when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
102            val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
103            if val.empty?
104              return [slot, nil]
105            else
106              return [slot, TkVarAccess.new(val)]
107            end
108
109          else
110            val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
111            if val.index('{')
112              return [slot, tk_split_list(val)]
113            else
114              return [slot, tk_tcl2ruby(val)]
115            end
116          end
117
118        else # ! slot
119          ret = Hash[*(tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false))].to_a.collect{|conf|
120            conf[0] = conf[0][1..-1] if conf[0][0] == ?-
121            case conf[0]
122            when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
123              method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[conf[0]]
124              optval = conf[1]
125              begin
126                val = method.call(tagOrId, optval)
127              rescue => e
128                warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
129                val = optval
130              end
131              conf[1] = val
132
133            when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
134              # do nothing
135
136            when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
137              begin
138                conf[1] = number(conf[1])
139              rescue
140                conf[1] = nil
141              end
142
143            when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
144              conf[1] = num_or_str(conf[1])
145
146            when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
147              begin
148                conf[1] = bool(conf[1])
149              rescue
150                conf[1] = nil
151              end
152
153            when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
154              conf[1] = simplelist(conf[1])
155
156            when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
157              if conf[1] =~ /^[0-9]/
158                conf[1] = list(conf[1])
159              end
160
161            when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
162              if conf[1].empty?
163                conf[1] = nil
164              else
165                conf[1] = TkVarAccess.new(conf[1])
166              end
167
168            else
169              if conf[1].index('{')
170                conf[1] = tk_split_list(conf[1])
171              else
172                conf[1] = tk_tcl2ruby(conf[1])
173              end
174            end
175
176            conf
177          }
178
179          __item_font_optkeys(tagid(tagOrId)).each{|optkey|
180            optkey = optkey.to_s
181            fontconf = ret.assoc(optkey)
182            if fontconf
183              ret.delete_if{|inf| inf[0] =~ /^(|latin|ascii|kanji)#{optkey}$/}
184              fontconf[1] = tagfontobj(tagid(tagOrId), optkey)
185              ret.push(fontconf)
186            end
187          }
188
189          __item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method|
190            ret << [optkey.to_s, self.__send__(method, tagOrId)]
191          }
192
193          ret
194        end
195      end
196
197    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
198      if (slot && slot.to_s =~ /^(|latin|ascii|kanji)(#{__item_font_optkeys(tagid(tagOrId)).join('|')})$/)
199        fontkey  = $2
200        return {slot.to_s => tagfontobj(tagid(tagOrId), fontkey)}
201      else
202        if slot
203          slot = slot.to_s
204
205          alias_name, real_name = __item_optkey_aliases(tagid(tagOrId)).find{|k, v| k.to_s == slot}
206          if real_name
207            slot = real_name.to_s
208          end
209
210          case slot
211          when /^(#{__tile_specific_item_optkeys(tagid(tagOrId)).join('|')})$/
212            begin
213              # On tile-0.7.{2-8}, 'state' option has no '-' at its head.
214              val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << slot))
215            rescue
216              # Maybe, 'state' option has '-' in future.
217              val = tk_call(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
218            end
219            return {slot => val}
220
221          when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
222            method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[slot]
223            optval = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
224            begin
225              val = method.call(tagOrId, optval)
226            rescue => e
227              warn("Warning:: #{e.message} (when #{method}lcall(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
228              val = optval
229            end
230            return {slot => val}
231
232          when /^(#{__item_methodcall_optkeys(tagid(tagOrId)).keys.join('|')})$/
233            method = _symbolkey2str(__item_methodcall_optkeys(tagid(tagOrId)))[slot]
234            return {slot => self.__send__(method, tagOrId)}
235
236          when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
237            begin
238              val = number(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
239            rescue
240              val = nil
241            end
242            return {slot => val}
243
244          when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
245            val = num_or_str(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
246            return {slot => val}
247
248          when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
249            begin
250              val = bool(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
251            rescue
252              val = nil
253            end
254            return {slot => val}
255
256          when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
257            val = simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}")))
258            return {slot => val}
259
260          when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
261            val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
262            if val =~ /^[0-9]/
263              return {slot => list(val)}
264            else
265              return {slot => val}
266            end
267
268          when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
269            val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
270            return {slot => val}
271
272          when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
273            val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
274            if val.empty?
275              return {slot => nil}
276            else
277              return {slot => TkVarAccess.new(val)}
278            end
279
280          else
281            val = tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)) << "-#{slot}"))
282            if val.index('{')
283              return {slot => tk_split_list(val)}
284            else
285              return {slot => tk_tcl2ruby(val)}
286            end
287          end
288
289        else # ! slot
290          ret = {}
291          ret = Hash[*(tk_split_simplelist(tk_call_without_enc(*(__item_confinfo_cmd(tagid(tagOrId)))), false, false))].to_a.collect{|conf|
292            conf[0] = conf[0][1..-1] if conf[0][0] == ?-
293
294            optkey = conf[0]
295            case optkey
296            when /^(#{__item_val2ruby_optkeys(tagid(tagOrId)).keys.join('|')})$/
297              method = _symbolkey2str(__item_val2ruby_optkeys(tagid(tagOrId)))[optkey]
298              optval = conf[1]
299              begin
300                val = method.call(tagOrId, optval)
301              rescue => e
302                warn("Warning:: #{e.message} (when #{method}.call(#{tagOrId.inspect}, #{optval.inspect})") if $DEBUG
303                val = optval
304              end
305              conf[1] = val
306
307            when /^(#{__item_strval_optkeys(tagid(tagOrId)).join('|')})$/
308              # do nothing
309
310            when /^(#{__item_numval_optkeys(tagid(tagOrId)).join('|')})$/
311              begin
312                conf[1] = number(conf[1])
313              rescue
314                conf[1] = nil
315              end
316
317            when /^(#{__item_numstrval_optkeys(tagid(tagOrId)).join('|')})$/
318              conf[1] = num_or_str(conf[1])
319
320            when /^(#{__item_boolval_optkeys(tagid(tagOrId)).join('|')})$/
321              begin
322                conf[1] = bool(conf[1])
323              rescue
324                conf[1] = nil
325              end
326
327            when /^(#{__item_listval_optkeys(tagid(tagOrId)).join('|')})$/
328              conf[1] = simplelist(conf[1])
329
330            when /^(#{__item_numlistval_optkeys(tagid(tagOrId)).join('|')})$/
331              if conf[1] =~ /^[0-9]/
332                conf[1] = list(conf[1])
333              end
334
335            when /^(#{__item_tkvariable_optkeys(tagid(tagOrId)).join('|')})$/
336              if conf[1].empty?
337                conf[1] = nil
338              else
339                conf[1] = TkVarAccess.new(conf[1])
340              end
341
342            else
343              if conf[1].index('{')
344                return [slot, tk_split_list(conf[1])]
345              else
346                return [slot, tk_tcl2ruby(conf[1])]
347              end
348            end
349
350            ret[conf[0]] = conf[1]
351          }
352
353          __item_font_optkeys(tagid(tagOrId)).each{|optkey|
354            optkey = optkey.to_s
355            fontconf = ret[optkey]
356            if fontconf.kind_of?(Array)
357              ret.delete(optkey)
358              ret.delete('latin' << optkey)
359              ret.delete('ascii' << optkey)
360              ret.delete('kanji' << optkey)
361              fontconf[1] = tagfontobj(tagid(tagOrId), optkey)
362              ret[optkey] = fontconf
363            end
364          }
365
366          __item_methodcall_optkeys(tagid(tagOrId)).each{|optkey, method|
367            ret[optkey.to_s] = self.__send__(method, tagOrId)
368          }
369
370          ret
371        end
372      end
373    end
374  end
375
376  ###################
377
378  def __item_cget_cmd(id)
379    [self.path, *id]
380  end
381  private :__item_cget_cmd
382
383  def __item_config_cmd(id)
384    [self.path, *id]
385  end
386  private :__item_config_cmd
387
388  def __item_numstrval_optkeys(id)
389    case id[0]
390    when :item, 'item'
391      ['width']
392    when :column, 'column'
393      super(id[1]) + ['minwidth']
394    when :tag, 'tag'
395      super(id[1])
396    when :heading, 'heading'
397      super(id[1])
398    else
399      super(id[1])
400    end
401  end
402  private :__item_numstrval_optkeys
403
404  def __item_strval_optkeys(id)
405    case id[0]
406    when :item, 'item'
407      super(id) + ['id']
408    when :column, 'column'
409      super(id[1])
410    when :tag, 'tag'
411      super(id[1])
412    when :heading, 'heading'
413      super(id[1])
414    else
415      super(id[1])
416    end
417  end
418  private :__item_strval_optkeys
419
420  def __item_boolval_optkeys(id)
421    case id[0]
422    when :item, 'item'
423      ['open']
424    when :column, 'column'
425      super(id[1]) + ['stretch']
426    when :tag, 'tag'
427      super(id[1])
428    when :heading, 'heading'
429      super(id[1])
430    end
431  end
432  private :__item_boolval_optkeys
433
434  def __item_listval_optkeys(id)
435    case id[0]
436    when :item, 'item'
437      ['values']
438    when :column, 'column'
439      []
440    when :heading, 'heading'
441      []
442    else
443      []
444    end
445  end
446  private :__item_listval_optkeys
447
448  def __item_val2ruby_optkeys(id)
449    case id[0]
450    when :item, 'item'
451      {
452        'tags'=>proc{|arg_id, val|
453          simplelist(val).collect{|tag|
454            Tk::Tile::Treeview::Tag.id2obj(self, tag)
455          }
456        }
457      }
458    when :column, 'column'
459      {}
460    when :heading, 'heading'
461      {}
462    else
463      {}
464    end
465  end
466  private :__item_val2ruby_optkeys
467
468  def __tile_specific_item_optkeys(id)
469    case id[0]
470    when :item, 'item'
471      []
472    when :column, 'column'
473      []
474    when :heading, 'heading'
475      ['state']  # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
476    else
477      []
478    end
479  end
480  private :__item_val2ruby_optkeys
481
482  def itemconfiginfo(tagOrId, slot = nil)
483    __itemconfiginfo_core(tagOrId, slot)
484  end
485
486  def current_itemconfiginfo(tagOrId, slot = nil)
487    if TkComm::GET_CONFIGINFO_AS_ARRAY
488      if slot
489        org_slot = slot
490        begin
491          conf = __itemconfiginfo_core(tagOrId, slot)
492          if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
493              || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
494            return {conf[0] => conf[-1]}
495          end
496          slot = conf[__item_configinfo_struct(tagid(tagOrId))[:alias]]
497        end while(org_slot != slot)
498        fail RuntimeError,
499          "there is a configure alias loop about '#{org_slot}'"
500      else
501        ret = {}
502        __itemconfiginfo_core(tagOrId).each{|conf|
503          if ( ! __item_configinfo_struct(tagid(tagOrId))[:alias] \
504              || conf.size > __item_configinfo_struct(tagid(tagOrId))[:alias] + 1 )
505            ret[conf[0]] = conf[-1]
506          end
507        }
508        ret
509      end
510    else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
511      ret = {}
512      __itemconfiginfo_core(tagOrId, slot).each{|key, conf|
513        ret[key] = conf[-1] if conf.kind_of?(Array)
514      }
515      ret
516    end
517  end
518
519  alias __itemcget_tkstring itemcget_tkstring
520  alias __itemcget itemcget
521  alias __itemcget_strict itemcget_strict
522  alias __itemconfigure itemconfigure
523  alias __itemconfiginfo itemconfiginfo
524  alias __current_itemconfiginfo current_itemconfiginfo
525
526  private :__itemcget_tkstring, :__itemcget, :__itemcget_strict
527  private :__itemconfigure, :__itemconfiginfo, :__current_itemconfiginfo
528
529  # Treeview Item
530  def itemcget_tkstring(tagOrId, option)
531    __itemcget_tkstring([:item, tagOrId], option)
532  end
533  def itemcget(tagOrId, option)
534    __itemcget([:item, tagOrId], option)
535  end
536  def itemcget_strict(tagOrId, option)
537    __itemcget_strict([:item, tagOrId], option)
538  end
539  def itemconfigure(tagOrId, slot, value=None)
540    __itemconfigure([:item, tagOrId], slot, value)
541  end
542  def itemconfiginfo(tagOrId, slot=nil)
543    __itemconfiginfo([:item, tagOrId], slot)
544  end
545  def current_itemconfiginfo(tagOrId, slot=nil)
546    __current_itemconfiginfo([:item, tagOrId], slot)
547  end
548
549  # Treeview Column
550  def columncget_tkstring(tagOrId, option)
551    __itemcget_tkstring([:column, tagOrId], option)
552  end
553  def columncget(tagOrId, option)
554    __itemcget([:column, tagOrId], option)
555  end
556  def columncget_strict(tagOrId, option)
557    __itemcget_strict([:column, tagOrId], option)
558  end
559  def columnconfigure(tagOrId, slot, value=None)
560    __itemconfigure([:column, tagOrId], slot, value)
561  end
562  def columnconfiginfo(tagOrId, slot=nil)
563    __itemconfiginfo([:column, tagOrId], slot)
564  end
565  def current_columnconfiginfo(tagOrId, slot=nil)
566    __current_itemconfiginfo([:column, tagOrId], slot)
567  end
568  alias column_cget_tkstring columncget_tkstring
569  alias column_cget columncget
570  alias column_cget_strict columncget_strict
571  alias column_configure columnconfigure
572  alias column_configinfo columnconfiginfo
573  alias current_column_configinfo current_columnconfiginfo
574
575  # Treeview Heading
576  def headingcget_tkstring(tagOrId, option)
577    if __tile_specific_item_optkeys([:heading, tagOrId]).index(option.to_s)
578      begin
579        # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
580        tk_call(*(__item_cget_cmd([:heading, tagOrId]) << option.to_s))
581      rescue
582        # Maybe, 'state' option has '-' in future.
583        tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{option}"))
584      end
585    else
586      __itemcget_tkstring([:heading, tagOrId], option)
587    end
588  end
589  def headingcget_strict(tagOrId, option)
590    if __tile_specific_item_optkeys([:heading, tagOrId]).index(option.to_s)
591      begin
592        # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
593        tk_call(*(__item_cget_cmd([:heading, tagOrId]) << option.to_s))
594      rescue
595        # Maybe, 'state' option has '-' in future.
596        tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{option}"))
597      end
598    else
599      __itemcget_strict([:heading, tagOrId], option)
600    end
601  end
602  def headingcget(tagOrId, option)
603    unless TkItemConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
604      headingcget_strict(tagOrId, option)
605    else
606      begin
607        headingcget_strict(tagOrId, option)
608      rescue => e
609        begin
610          if current_headingconfiginfo(tagOrId).has_key?(option.to_s)
611            # not tag error & option is known -> error on known option
612            fail e
613          else
614            # not tag error & option is unknown
615            nil
616          end
617        rescue
618          fail e  # tag error
619        end
620      end
621    end
622  end
623  def headingconfigure(tagOrId, slot, value=None)
624    if slot.kind_of?(Hash)
625      slot = _symbolkey2str(slot)
626      sp_kv = []
627      __tile_specific_item_optkeys([:heading, tagOrId]).each{|k|
628        sp_kv << k << _get_eval_string(slot.delete(k)) if slot.has_key?(k)
629      }
630      tk_call(*(__item_config_cmd([:heading, tagOrId]).concat(sp_kv)))
631      tk_call(*(__item_config_cmd([:heading, tagOrId]).concat(hash_kv(slot))))
632    elsif __tile_specific_item_optkeys([:heading, tagOrId]).index(slot.to_s)
633      begin
634        # On tile-0.7.{2-8}, 'state' options has no '-' at its head.
635        tk_call(*(__item_cget_cmd([:heading, tagOrId]) << slot.to_s << value))
636      rescue
637        # Maybe, 'state' option has '-' in future.
638        tk_call(*(__item_cget_cmd([:heading, tagOrId]) << "-#{slot}" << value))
639      end
640    else
641      __itemconfigure([:heading, tagOrId], slot, value)
642    end
643    self
644  end
645  def headingconfiginfo(tagOrId, slot=nil)
646    __itemconfiginfo([:heading, tagOrId], slot)
647  end
648  def current_headingconfiginfo(tagOrId, slot=nil)
649    __current_itemconfiginfo([:heading, tagOrId], slot)
650  end
651  alias heading_cget_tkstring headingcget_tkstring
652  alias heading_cget headingcget
653  alias heading_cget_strict headingcget_strict
654  alias heading_configure headingconfigure
655  alias heading_configinfo headingconfiginfo
656  alias current_heading_configinfo current_headingconfiginfo
657
658  # Treeview Tag
659  def tagcget_tkstring(tagOrId, option)
660    __itemcget_tkstring([:tag, :configure, tagOrId], option)
661  end
662  def tagcget(tagOrId, option)
663    __itemcget([:tag, :configure, tagOrId], option)
664  end
665  def tagcget_strict(tagOrId, option)
666    __itemcget_strict([:tag, :configure, tagOrId], option)
667  end
668  def tagconfigure(tagOrId, slot, value=None)
669    __itemconfigure([:tag, :configure, tagOrId], slot, value)
670  end
671  def tagconfiginfo(tagOrId, slot=nil)
672    __itemconfiginfo([:tag, :configure, tagOrId], slot)
673  end
674  def current_tagconfiginfo(tagOrId, slot=nil)
675    __current_itemconfiginfo([:tag, :configure, tagOrId], slot)
676  end
677  alias tag_cget_tkstring tagcget_tkstring
678  alias tag_cget tagcget
679  alias tag_cget_strict tagcget_strict
680  alias tag_configure tagconfigure
681  alias tag_configinfo tagconfiginfo
682  alias current_tag_configinfo current_tagconfiginfo
683end
684
685########################
686
687class Tk::Tile::Treeview::Item < TkObject
688  ItemID_TBL = TkCore::INTERP.create_table
689
690  TkCore::INTERP.init_ip_env{
691    Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
692      Tk::Tile::Treeview::Item::ItemID_TBL.clear
693    }
694  }
695
696  def self.id2obj(tree, id)
697    tpath = tree.path
698    Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
699      if Tk::Tile::Treeview::Item::ItemID_TBL[tpath]
700        (Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id])? \
701             Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]: id
702      else
703        id
704      end
705    }
706  end
707
708  def self.assign(tree, id)
709    tpath = tree.path
710    obj = nil
711    Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
712      if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] &&
713          Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]
714        return Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id]
715      end
716
717      obj = self.allocate
718      obj.instance_eval{
719        @parent = @t = tree
720        @tpath = tpath
721        @path = @id = id
722      }
723      Tk::Tile::Treeview::Item::ItemID_TBL[tpath] ||= {}
724      Tk::Tile::Treeview::Item::ItemID_TBL[tpath][id] = obj
725    }
726    obj
727  end
728
729  def _insert_item(tree, parent_item, idx, keys={})
730    keys = _symbolkey2str(keys)
731    id = keys.delete('id')
732    if id
733      num_or_str(tk_call(tree, 'insert',
734                         parent_item, idx, '-id', id, *hash_kv(keys)))
735    else
736      num_or_str(tk_call(tree, 'insert', parent_item, idx, *hash_kv(keys)))
737    end
738  end
739  private :_insert_item
740
741  def initialize(tree, parent_item = '', idx = 'end', keys = {})
742    if parent_item.kind_of?(Hash)
743      keys = parent_item
744      idx = 'end'
745      parent_item = ''
746    elsif idx.kind_of?(Hash)
747      keys = idx
748      idx = 'end'
749    end
750
751    @parent = @t = tree
752    @tpath = tree.path
753    @path = @id = _insert_item(@t, parent_item, idx, keys)
754    Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
755      ItemID_TBL[@tpath] = {} unless ItemID_TBL[@tpath]
756      ItemID_TBL[@tpath][@id] = self
757    }
758  end
759  def id
760    @id
761  end
762
763  def cget_tkstring(option)
764    @t.itemcget_tkstring(@id, option)
765  end
766  def cget(option)
767    @t.itemcget(@id, option)
768  end
769  def cget_strict(option)
770    @t.itemcget_strict(@id, option)
771  end
772
773  def configure(key, value=None)
774    @t.itemconfigure(@id, key, value)
775    self
776  end
777
778  def configinfo(key=nil)
779    @t.itemconfiginfo(@id, key)
780  end
781
782  def current_configinfo(key=nil)
783    @t.current_itemconfiginfo(@id, key)
784  end
785
786  def open?
787    cget('open')
788  end
789  def open
790    configure('open', true)
791    self
792  end
793  def close
794    configure('open', false)
795    self
796  end
797
798  def tag_has?(tag)
799    @t.tag_has?(tag, @id)
800  end
801  alias has_tag? tag_has?
802
803  def bbox(column=None)
804    @t.bbox(@id, column)
805  end
806
807  def children
808    @t.children(@id)
809  end
810  def set_children(*items)
811    @t.set_children(@id, *items)
812    self
813  end
814
815  def delete
816    @t.delete(@id)
817    self
818  end
819
820  def detach
821    @t.detach(@id)
822    self
823  end
824
825  def exist?
826    @t.exist?(@id)
827  end
828
829  def focus
830    @t.focus_item(@id)
831  end
832
833  def index
834    @t.index(@id)
835  end
836
837  def insert(idx='end', keys={})
838    @t.insert(@id, idx, keys)
839  end
840
841  def move(parent, idx)
842    @t.move(@id, parent, idx)
843    self
844  end
845
846  def next_item
847    @t.next_item(@id)
848  end
849
850  def parent_item
851    @t.parent_item(@id)
852  end
853
854  def prev_item
855    @t.prev_item(@id)
856  end
857
858  def see
859    @t.see(@id)
860    self
861  end
862
863  def selection_add
864    @t.selection_add(@id)
865    self
866  end
867
868  def selection_remove
869    @t.selection_remove(@id)
870    self
871  end
872
873  def selection_set
874    @t.selection_set(@id)
875    self
876  end
877
878  def selection_toggle
879    @t.selection_toggle(@id)
880    self
881  end
882
883  def get_directory
884    @t.get_directory(@id)
885  end
886  alias get_dictionary get_directory
887
888  def get(col)
889    @t.get(@id, col)
890  end
891
892  def set(col, value)
893    @t.set(@id, col, value)
894  end
895end
896
897########################
898
899class Tk::Tile::Treeview::Root < Tk::Tile::Treeview::Item
900  def self.new(tree, keys = {})
901    tpath = tree.path
902    obj = nil
903    Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
904      if Tk::Tile::Treeview::Item::ItemID_TBL[tpath] &&
905          Tk::Tile::Treeview::Item::ItemID_TBL[tpath]['']
906        obj = Tk::Tile::Treeview::Item::ItemID_TBL[tpath]['']
907      else
908        #super(tree, keys)
909        (obj = self.allocate).instance_eval{
910          @parent = @t = tree
911          @tpath = tree.path
912          @path = @id = ''
913          Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {}
914          Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self
915        }
916      end
917    }
918    obj.configure(keys) if keys && ! keys.empty?
919    obj
920  end
921
922  def initialize(tree, keys = {})
923    # dummy:: not called by 'new' method
924    @parent = @t = tree
925    @tpath = tree.path
926    @path = @id = ''
927    Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
928      Tk::Tile::Treeview::Item::ItemID_TBL[@tpath] ||= {}
929      Tk::Tile::Treeview::Item::ItemID_TBL[@tpath][@id] = self
930    }
931  end
932end
933
934########################
935
936class Tk::Tile::Treeview::Tag < TkObject
937  include TkTreatTagFont
938
939  TagID_TBL = TkCore::INTERP.create_table
940
941  (Tag_ID = ['tile_treeview_tag'.freeze, TkUtil.untrust('00000')]).instance_eval{
942    @mutex = Mutex.new
943    def mutex; @mutex; end
944    freeze
945  }
946
947  TkCore::INTERP.init_ip_env{
948    Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{
949      Tk::Tile::Treeview::Tag::TagID_TBL.clear
950    }
951  }
952
953  def self.id2obj(tree, id)
954    tpath = tree.path
955    Tk::Tile::Treeview::Tag::TagID_TBL.mutex.synchronize{
956      if Tk::Tile::Treeview::Tag::TagID_TBL[tpath]
957        (Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id])? \
958               Tk::Tile::Treeview::Tag::TagID_TBL[tpath][id]: id
959      else
960        id
961      end
962    }
963  end
964
965  def initialize(tree, keys=nil)
966    @parent = @t = tree
967    @tpath = tree.path
968    Tag_ID.mutex.synchronize{
969      @path = @id = Tag_ID.join(TkCore::INTERP._ip_id_)
970      Tag_ID[1].succ!
971    }
972    TagID_TBL.mutex.synchronize{
973      TagID_TBL[@tpath] = {} unless TagID_TBL[@tpath]
974      TagID_TBL[@tpath][@id] = self
975    }
976    if keys && keys != None
977      tk_call_without_enc(@tpath, 'tag', 'configure', @id, *hash_kv(keys,true))
978    end
979  end
980  def id
981    @id
982  end
983
984  def tag_has?(item)
985    @t.tag_has?(@id, item)
986  end
987  alias added? tag_has?
988
989  def bind(seq, *args)
990    if TkComm._callback_entry?(args[0]) || !block_given?
991      cmd = args.shift
992    else
993      cmd = Proc.new
994    end
995    @t.tag_bind(@id, seq, cmd, *args)
996    self
997  end
998
999  def bind_append(seq, *args)
1000    if TkComm._callback_entry?(args[0]) || !block_given?
1001      cmd = args.shift
1002    else
1003      cmd = Proc.new
1004    end
1005    @t.tag_bind_append(@id, seq, cmd, *args)
1006    self
1007  end
1008
1009  def bind_remove(seq)
1010    @t.tag_bind_remove(@id, seq)
1011    self
1012  end
1013
1014  def bindinfo(seq=nil)
1015    @t.tag_bindinfo(@id, seq)
1016  end
1017
1018  def cget_tkstring(option)
1019    @t.tagcget_tkstring(@id, option)
1020  end
1021  def cget(option)
1022    @t.tagcget(@id, option)
1023  end
1024  def cget_strict(option)
1025    @t.tagcget_strict(@id, option)
1026  end
1027
1028  def configure(key, value=None)
1029    @t.tagconfigure(@id, key, value)
1030    self
1031  end
1032
1033  def configinfo(key=nil)
1034    @t.tagconfiginfo(@id, key)
1035  end
1036
1037  def current_configinfo(key=nil)
1038    @t.current_tagconfiginfo(@id, key)
1039  end
1040end
1041
1042########################
1043
1044class Tk::Tile::Treeview < TkWindow
1045  include Tk::Tile::TileWidget
1046  include Scrollable
1047
1048  include Tk::Tile::TreeviewConfig
1049
1050  if Tk::Tile::USE_TTK_NAMESPACE
1051    TkCommandNames = ['::ttk::treeview'.freeze].freeze
1052  else
1053    TkCommandNames = ['::treeview'.freeze].freeze
1054  end
1055  WidgetClassName = 'Treeview'.freeze
1056  WidgetClassNames[WidgetClassName] ||= self
1057
1058  def __destroy_hook__
1059    Tk::Tile::Treeview::Item::ItemID_TBL.mutex.synchronize{
1060      Tk::Tile::Treeview::Item::ItemID_TBL.delete(@path)
1061    }
1062    Tk::Tile::Treeview::Tag::ItemID_TBL.mutex.synchronize{
1063      Tk::Tile::Treeview::Tag::ItemID_TBL.delete(@path)
1064    }
1065  end
1066
1067  def self.style(*args)
1068    [self::WidgetClassName, *(args.map!{|a| _get_eval_string(a)})].join('.')
1069  end
1070
1071  def tagid(id)
1072    if id.kind_of?(Tk::Tile::Treeview::Item) ||
1073        id.kind_of?(Tk::Tile::Treeview::Tag)
1074      id.id
1075    elsif id.kind_of?(Array)
1076      # size is 2 or 3
1077      id[0..-2] << _get_eval_string(id[-1])
1078    else
1079      _get_eval_string(id)
1080    end
1081  end
1082
1083  def root
1084    Tk::Tile::Treeview::Root.new(self)
1085  end
1086
1087  def bbox(item, column=None)
1088    list(tk_send('item', 'bbox', item, column))
1089  end
1090
1091  def children(item)
1092    simplelist(tk_send_without_enc('children', item)).collect{|id|
1093      Tk::Tile::Treeview::Item.id2obj(self, id)
1094    }
1095  end
1096  def set_children(item, *items)
1097    tk_send_without_enc('children', item,
1098                        array2tk_list(items.flatten, true))
1099    self
1100  end
1101
1102  def delete(*items)
1103    tk_send_without_enc('delete', array2tk_list(items.flatten, true))
1104    self
1105  end
1106
1107  def detach(*items)
1108    tk_send_without_enc('detach', array2tk_list(items.flatten, true))
1109    self
1110  end
1111
1112  def exist?(item)
1113    bool(tk_send_without_enc('exists', _get_eval_enc_str(item)))
1114  end
1115
1116  def focus_item(item = nil)
1117    if item
1118      tk_send('focus', item)
1119      item
1120    else
1121      id = tk_send('focus')
1122      (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
1123    end
1124  end
1125
1126  def identify(x, y)
1127    # tile-0.7.2 or previous
1128    ret = simplelist(tk_send('identify', x, y))
1129    case ret[0]
1130    when 'heading', 'separator'
1131      ret[-1] = num_or_str(ret[-1])
1132    when 'cell'
1133      ret[1] = Tk::Tile::Treeview::Item.id2obj(self, ret[1])
1134      ret[-1] = num_or_str(ret[-1])
1135    when 'item', 'row'
1136      ret[1] = Tk::Tile::Treeview::Item.id2obj(self, ret[1])
1137    end
1138  end
1139
1140  def identify_region(x, y)
1141    tk_send('identify', 'region', x, y)
1142  end
1143
1144  def identify_item(x, y)
1145    id = tk_send('identify', 'item', x, y)
1146    (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
1147  end
1148
1149  def identify_element(x, y)
1150    tk_send('identify', 'element', x, y)
1151  end
1152
1153  def row_identify(x, y)
1154    id = tk_send('identify', 'row', x, y)
1155    (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
1156  end
1157  alias identify_row row_identify
1158
1159  def column_identify(x, y)
1160    tk_send('identify', 'column', x, y)
1161  end
1162  alias identify_column column_identify
1163
1164  def index(item)
1165    number(tk_send('index', item))
1166  end
1167
1168  # def insert(parent, idx='end', keys={})
1169  #   keys = _symbolkey2str(keys)
1170  #   id = keys.delete('id')
1171  #   if id
1172  #     num_or_str(tk_send('insert', parent, idx, '-id', id, *hash_kv(keys)))
1173  #   else
1174  #     num_or_str(tk_send('insert', parent, idx, *hash_kv(keys)))
1175  #   end
1176  # end
1177  def insert(parent, idx='end', keys={})
1178    Tk::Tile::Treeview::Item.new(self, parent, idx, keys)
1179  end
1180
1181  # def instate(spec, cmd=Proc.new)
1182  #   tk_send('instate', spec, cmd)
1183  # end
1184  # def state(spec=None)
1185  #   tk_send('state', spec)
1186  # end
1187
1188  def move(item, parent, idx)
1189    tk_send('move', item, parent, idx)
1190    self
1191  end
1192
1193  def next_item(item)
1194    id = tk_send('next', item)
1195    (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
1196  end
1197
1198  def parent_item(item)
1199    if (id = tk_send('parent', item)).empty?
1200      Tk::Tile::Treeview::Root.new(self)
1201    else
1202      Tk::Tile::Treeview::Item.id2obj(self, id)
1203    end
1204  end
1205
1206  def prev_item(item)
1207    id = tk_send('prev', item)
1208    (id.empty?)? nil: Tk::Tile::Treeview::Item.id2obj(self, id)
1209  end
1210
1211  def see(item)
1212    tk_send('see', item)
1213    self
1214  end
1215
1216  def selection
1217    simplelist(tk_send('selection')).collect{|id|
1218      Tk::Tile::Treeview::Item.id2obj(self, id)
1219    }
1220  end
1221  alias selection_get selection
1222
1223  def selection_add(*items)
1224    tk_send('selection', 'add', array2tk_list(items.flatten, true))
1225    self
1226  end
1227  def selection_remove(*items)
1228    tk_send('selection', 'remove', array2tk_list(items.flatten, true))
1229    self
1230  end
1231  def selection_set(*items)
1232    tk_send('selection', 'set', array2tk_list(items.flatten, true))
1233    self
1234  end
1235  def selection_toggle(*items)
1236    tk_send('selection', 'toggle', array2tk_list(items.flatten, true))
1237    self
1238  end
1239
1240  def get_directory(item)
1241    # tile-0.7+
1242    ret = []
1243    lst = simplelist(tk_send('set', item))
1244    until lst.empty?
1245      col = lst.shift
1246      val = lst.shift
1247      ret << [col, val]
1248    end
1249    ret
1250  end
1251  alias get_dictionary get_directory
1252
1253  def get(item, col)
1254    tk_send('set', item, col)
1255  end
1256  def set(item, col, value)
1257    tk_send('set', item, col, value)
1258    self
1259  end
1260
1261  def tag_has?(tag, item)
1262    bool(tk_send('tag', 'has', tagid(tag), tagid(item)))
1263  end
1264  def tag_has(tag)
1265    tk_split_simplelist(tk_send('tag', 'has', tagid(tag))).collect{|id|
1266      Tk::Tile::Treeview::Item.id2obj(self, id)
1267    }
1268  end
1269
1270  def tag_bind(tag, seq, *args)
1271    if TkComm._callback_entry?(args[0]) || !block_given?
1272      cmd = args.shift
1273    else
1274      cmd = Proc.new
1275    end
1276    _bind([@path, 'tag', 'bind', tag], seq, cmd, *args)
1277    self
1278  end
1279  alias tagbind tag_bind
1280
1281  def tag_bind_append(tag, seq, *args)
1282    if TkComm._callback_entry?(args[0]) || !block_given?
1283      cmd = args.shift
1284    else
1285      cmd = Proc.new
1286    end
1287    _bind_append([@path, 'tag', 'bind', tag], seq, cmd, *args)
1288    self
1289  end
1290  alias tagbind_append tag_bind_append
1291
1292  def tag_bind_remove(tag, seq)
1293    _bind_remove([@path, 'tag', 'bind', tag], seq)
1294    self
1295  end
1296  alias tagbind_remove tag_bind_remove
1297
1298  def tag_bindinfo(tag, context=nil)
1299    _bindinfo([@path, 'tag', 'bind', tag], context)
1300  end
1301  alias tagbindinfo tag_bindinfo
1302end
1303
1304#Tk.__set_toplevel_aliases__(:Ttk, Tk::Tile::Treeview, :TkTreeview)
1305Tk.__set_loaded_toplevel_aliases__('tkextlib/tile/treeview.rb',
1306                                   :Ttk, Tk::Tile::Treeview, :TkTreeview)
1307