1# 2# tkextlib/bwidget/tree.rb 3# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) 4# 5 6require 'tk' 7require 'tk/canvas' 8require 'tkextlib/bwidget.rb' 9 10module Tk 11 module BWidget 12 class Tree < TkWindow 13 class Node < TkObject 14 end 15 end 16 end 17end 18 19class Tk::BWidget::Tree 20 include TkItemConfigMethod 21 include Scrollable 22 23 TkCommandNames = ['Tree'.freeze].freeze 24 WidgetClassName = 'Tree'.freeze 25 WidgetClassNames[WidgetClassName] ||= self 26 27 class Event_for_Items < TkEvent::Event 28 def self._get_extra_args_tbl 29 [ 30 TkComm.method(:string) # item idenfier 31 ] 32 end 33 end 34 35 def __strval_optkeys 36 super() << 'crossfill' << 'linesfill' 37 end 38 private :__strval_optkeys 39 40 def __boolval_optkeys 41 super() << 'dragenabled' << 'dropenabled' << 42 'redraw' << 'selectfill' << 'showlines' 43 end 44 private :__boolval_optkeys 45 46 def __tkvariable_optkeys 47 super() << 'helpvar' 48 end 49 private :__tkvariable_optkeys 50 51 def tagid(tag) 52 if tag.kind_of?(Tk::BWidget::Tree::Node) 53 tag.id 54 else 55 # tag 56 _get_eval_string(tag) 57 end 58 end 59 60 def areabind(context, *args) 61 if TkComm._callback_entry?(args[0]) || !block_given? 62 cmd = args.shift 63 else 64 cmd = Proc.new 65 end 66 _bind_for_event_class(Event_for_Items, [path, 'bindArea'], 67 context, cmd, *args) 68 self 69 end 70 71 def areabind_append(context, *args) 72 if TkComm._callback_entry?(args[0]) || !block_given? 73 cmd = args.shift 74 else 75 cmd = Proc.new 76 end 77 _bind_append_for_event_class(Event_for_Items, [path, 'bindArea'], 78 context, cmd, *args) 79 self 80 end 81 82 def areabind_remove(*args) 83 _bind_remove_for_event_class(Event_for_Items, [path, 'bindArea'], *args) 84 self 85 end 86 87 def areabindinfo(*args) 88 _bindinfo_for_event_class(Event_for_Items, [path, 'bindArea'], *args) 89 end 90 91 #def imagebind(*args) 92 # _bind_for_event_class(Event_for_Items, [path, 'bindImage'], *args) 93 # self 94 #end 95 def imagebind(context, *args) 96 #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 97 if TkComm._callback_entry?(args[0]) || !block_given? 98 cmd = args.shift 99 else 100 cmd = Proc.new 101 end 102 _bind_for_event_class(Event_for_Items, [path, 'bindImage'], 103 context, cmd, *args) 104 self 105 end 106 107 #def imagebind_append(*args) 108 # _bind_append_for_event_class(Event_for_Items, [path, 'bindImage'], *args) 109 # self 110 #end 111 def imagebind_append(context, *args) 112 #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 113 if TkComm._callback_entry?(args[0]) || !block_given? 114 cmd = args.shift 115 else 116 cmd = Proc.new 117 end 118 _bind_append_for_event_class(Event_for_Items, [path, 'bindImage'], 119 context, cmd, *args) 120 self 121 end 122 123 def imagebind_remove(*args) 124 _bind_remove_for_event_class(Event_for_Items, [path, 'bindImage'], *args) 125 self 126 end 127 128 def imagebindinfo(*args) 129 _bindinfo_for_event_class(Event_for_Items, [path, 'bindImage'], *args) 130 end 131 132 #def textbind(*args) 133 # _bind_for_event_class(Event_for_Items, [path, 'bindText'], *args) 134 # self 135 #end 136 def textbind(context, *args) 137 #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 138 if TkComm._callback_entry?(args[0]) || !block_given? 139 cmd = args.shift 140 else 141 cmd = Proc.new 142 end 143 _bind_for_event_class(Event_for_Items, [path, 'bindText'], 144 context, cmd, *args) 145 self 146 end 147 148 #def textbind_append(*args) 149 # _bind_append_for_event_class(Event_for_Items, [path, 'bindText'], *args) 150 # self 151 #end 152 def textbind_append(context, *args) 153 #if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 154 if TkComm._callback_entry?(args[0]) || !block_given? 155 cmd = args.shift 156 else 157 cmd = Proc.new 158 end 159 _bind_append_for_event_class(Event_for_Items, [path, 'bindText'], 160 context, cmd, *args) 161 self 162 end 163 164 def textbind_remove(*args) 165 _bind_remove_for_event_class(Event_for_Items, [path, 'bindText'], *args) 166 self 167 end 168 169 def textbindinfo(*args) 170 _bindinfo_for_event_class(Event_for_Items, [path, 'bindText'], *args) 171 end 172 173 def close_tree(node, recurse=None) 174 tk_send('closetree', tagid(node), recurse) 175 self 176 end 177 178 def delete(*args) 179 tk_send('delete', *(args.collect{|node| tagid(node)})) 180 self 181 end 182 183 def edit(node, text, *args) 184 tk_send('edit', tagid(node), text, *args) 185 self 186 end 187 188 def exist?(node) 189 bool(tk_send('exists', tagid(node))) 190 end 191 192 def find(findinfo, confine=None) 193 Tk::BWidget::Tree::Node.id2obj(self, tk_send(findinfo, confine)) 194 end 195 def find_position(x, y, confine=None) 196 self.find(_at(x,y), confine) 197 end 198 def find_line(linenum) 199 self.find(linenum) 200 end 201 202 def index(node) 203 num_or_str(tk_send('index', tagid(node))) 204 end 205 206 def insert(idx, parent, node, keys={}) 207 tk_send('insert', idx, tagid(parent), tagid(node), *hash_kv(keys)) 208 self 209 end 210 211 def line(node) 212 number(tk_send('line', tagid(node))) 213 end 214 215 def move(parent, node, idx) 216 tk_send('move', tagid(parent), tagid(node), idx) 217 self 218 end 219 220 def get_node(node, idx) 221 Tk::BWidget::Tree::Node.id2obj(self, tk_send('nodes', tagid(node), idx)) 222 end 223 224 def nodes(node, first=None, last=None) 225 simplelist(tk_send('nodes', tagid(node), first, last)).collect{|node| 226 Tk::BWidget::Tree::Node.id2obj(self, node) 227 } 228 end 229 230 def open?(node) 231 bool(self.itemcget(tagid(node), 'open')) 232 end 233 234 def open_tree(node, recurse=None) 235 tk_send('opentree', tagid(node), recurse) 236 self 237 end 238 239 def parent(node) 240 Tk::BWidget::Tree::Node.id2obj(self, tk_send('parent', tagid(node))) 241 end 242 243 def reorder(node, neworder) 244 tk_send('reorder', tagid(node), neworder) 245 self 246 end 247 248 def see(node) 249 tk_send('see', tagid(node)) 250 self 251 end 252 253 def selection_add(*args) 254 tk_send_without_enc('selection', 'add', 255 *(args.collect{|node| tagid(node)})) 256 self 257 end 258 259 def selection_clear 260 tk_send_without_enc('selection', 'clear') 261 self 262 end 263 264 def selection_get 265 list(tk_send_without_enc('selection', 'get')) 266 end 267 268 def selection_include?(*args) 269 bool(tk_send_without_enc('selection', 'get', 270 *(args.collect{|node| tagid(node)}))) 271 end 272 273 def selection_range(*args) 274 tk_send_without_enc('selection', 'range', 275 *(args.collect{|node| tagid(node)})) 276 self 277 end 278 279 def selection_remove(*args) 280 tk_send_without_enc('selection', 'remove', 281 *(args.collect{|node| tagid(node)})) 282 self 283 end 284 285 def selection_set(*args) 286 tk_send_without_enc('selection', 'set', 287 *(args.collect{|node| tagid(node)})) 288 self 289 end 290 291 def selection_toggle(*args) 292 tk_send_without_enc('selection', 'toggle', 293 *(args.collect{|node| tagid(node)})) 294 self 295 end 296 297 def toggle(node) 298 tk_send_without_enc('toggle', tagid(node)) 299 self 300 end 301 302 def visible(node) 303 bool(tk_send_without_enc('visible', tagid(node))) 304 end 305end 306 307class Tk::BWidget::Tree::Node 308 include TkTreatTagFont 309 310 TreeNode_TBL = TkCore::INTERP.create_table 311 312 (TreeNode_ID = ['bw:node'.freeze, TkUtil.untrust('00000')]).instance_eval{ 313 @mutex = Mutex.new 314 def mutex; @mutex; end 315 freeze 316 } 317 318 TkCore::INTERP.init_ip_env{ 319 TreeNode_TBL.mutex.synchronize{ TreeNode_TBL.clear } 320 } 321 322 def self.id2obj(tree, id) 323 tpath = tree.path 324 TreeNode_TBL.mutex.synchronize{ 325 if TreeNode_TBL[tpath] 326 TreeNode_TBL[tpath][id]? TreeNode_TBL[tpath][id]: id 327 else 328 id 329 end 330 } 331 end 332 333 def initialize(tree, *args) 334 if tree.kind_of?(Tk::BWidget::Tree) 335 @tree = tree 336 parent = args.shift 337 if parent.kind_of?(Tk::BWidget::Tree::Node) 338 if parent.tree.path != @tree.path 339 fail RuntimeError, 'tree of parent node is not match' 340 end 341 end 342 elsif tree.kind_of?(Tk::BWidget::Tree::Node) 343 @tree = tree.tree 344 parent = tree.parent 345 else 346 fail RuntimeError, 347 "expect Tk::BWidget::Tree or Tk::BWidget::Tree::Node for 1st argument" 348 end 349 350 if args[-1].kind_of?(Hash) 351 keys = _symbolkey2str(args.pop) 352 else 353 keys = {} 354 end 355 356 index = keys.delete('index') 357 unless args.empty? 358 index = args.shift 359 end 360 index = 'end' unless index 361 362 unless args.empty? 363 fail RuntimeError, 'too much arguments' 364 end 365 366 @tpath = @tree.path 367 368 if keys.key?('nodename') 369 @path = @id = keys.delete('nodename') 370 else 371 TreeNode_ID.mutex.synchronize{ 372 @path = @id = TreeNode_ID.join(TkCore::INTERP._ip_id_) 373 TreeNode_ID[1].succ! 374 } 375 end 376 377 TreeNode_TBL.mutex.synchronize{ 378 TreeNode_TBL[@id] = self 379 TreeNode_TBL[@tpath] = {} unless TreeNode_TBL[@tpath] 380 TreeNode_TBL[@tpath][@id] = self 381 } 382 383 @tree.insert(index, parent, @id, keys) 384 end 385 386 def tree 387 @tree 388 end 389 390 def id 391 @id 392 end 393 394 def [](key) 395 cget(key) 396 end 397 398 def []=(key, val) 399 configure(key, val) 400 val 401 end 402 403 def cget_tkstring(key) 404 @tree.itemcget_tkstring(@id, key) 405 end 406 def cget(key) 407 @tree.itemcget(@id, key) 408 end 409 def cget_strict(key) 410 @tree.itemcget_strict(@id, key) 411 end 412 413 def configure(key, val=None) 414 @tree.itemconfigure(@id, key, val) 415 end 416 417 def configinfo(key=nil) 418 @tree.itemconfiginfo(@id, key) 419 end 420 421 def current_configinfo(key=nil) 422 @tree.current_itemconfiginfo(@id, key) 423 end 424 425 def close_tree(recurse=None) 426 @tree.close_tree(@id, recurse) 427 self 428 end 429 430 def delete 431 @tree.delete(@id) 432 self 433 end 434 435 def edit(*args) 436 @tree.edit(@id, *args) 437 self 438 end 439 440 def exist? 441 @tree.exist?(@id) 442 end 443 444 def index 445 @tree.index(@id) 446 end 447 448 def move(index, parent=nil) 449 if parent 450 @tree.move(parent, @id, index) 451 else 452 @tree.move(self.parent, @id, index) 453 end 454 end 455 456 def open_tree(recurse=None) 457 @tree.open_tree(@id, recurse) 458 self 459 end 460 461 def open? 462 bool(@tree.itemcget(@id, 'open')) 463 end 464 465 def parent 466 @tree.parent(@id) 467 end 468 469 def reorder(neworder) 470 @tree.reorder(@id, neworder) 471 end 472 473 def see 474 @tree.see(@id) 475 end 476 477 def selection_add 478 @tree.selection_add(@id) 479 end 480 481 def selection_remove 482 @tree.selection_remove(@id) 483 end 484 485 def selection_set 486 @tree.selection_set(@id) 487 end 488 489 def selection_toggle 490 @tree.selection_toggle(@id) 491 end 492 493 def toggle 494 @tree.toggle(@id) 495 end 496 497 def visible 498 @tree.visible(@id) 499 end 500end 501