rbhex-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/CHANGELOG +2000 -0
- data/LICENSE +56 -0
- data/README.md +44 -0
- data/examples/abasiclist.rb +179 -0
- data/examples/alpmenu.rb +50 -0
- data/examples/app.sample +19 -0
- data/examples/atree.rb +100 -0
- data/examples/bline.rb +136 -0
- data/examples/common/file.rb +45 -0
- data/examples/data/README.markdown +9 -0
- data/examples/data/brew.txt +38 -0
- data/examples/data/color.2 +37 -0
- data/examples/data/gemlist.txt +60 -0
- data/examples/data/lotr.txt +12 -0
- data/examples/data/ports.txt +136 -0
- data/examples/data/table.txt +37 -0
- data/examples/data/tasks.csv +88 -0
- data/examples/data/tasks.txt +27 -0
- data/examples/data/todo.txt +10 -0
- data/examples/data/todo.txt.bak +10 -0
- data/examples/data/todocsv.csv +28 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/data/unix2.txt +11 -0
- data/examples/dbdemo.rb +502 -0
- data/examples/dirtree.rb +94 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +146 -0
- data/examples/tasks.rb +178 -0
- data/examples/term2.rb +84 -0
- data/examples/testbuttons.rb +296 -0
- data/examples/testcombo.rb +102 -0
- data/examples/testfields.rb +195 -0
- data/examples/testkeypress.rb +72 -0
- data/examples/testlistbox.rb +170 -0
- data/examples/testmessagebox.rb +140 -0
- data/examples/testprogress.rb +116 -0
- data/examples/testree.rb +106 -0
- data/examples/testwsshortcuts.rb +66 -0
- data/examples/testwsshortcuts2.rb +128 -0
- data/lib/rbhex.rb +6 -0
- data/lib/rbhex/core/docs/index.txt +73 -0
- data/lib/rbhex/core/include/action.rb +80 -0
- data/lib/rbhex/core/include/actionmanager.rb +49 -0
- data/lib/rbhex/core/include/appmethods.rb +214 -0
- data/lib/rbhex/core/include/bordertitle.rb +48 -0
- data/lib/rbhex/core/include/chunk.rb +203 -0
- data/lib/rbhex/core/include/io.rb +553 -0
- data/lib/rbhex/core/include/listbindings.rb +74 -0
- data/lib/rbhex/core/include/listcellrenderer.rb +140 -0
- data/lib/rbhex/core/include/listeditable.rb +317 -0
- data/lib/rbhex/core/include/listscrollable.rb +663 -0
- data/lib/rbhex/core/include/listselectable.rb +271 -0
- data/lib/rbhex/core/include/multibuffer.rb +83 -0
- data/lib/rbhex/core/include/orderedhash.rb +77 -0
- data/lib/rbhex/core/include/ractionevent.rb +73 -0
- data/lib/rbhex/core/include/rchangeevent.rb +27 -0
- data/lib/rbhex/core/include/rhistory.rb +95 -0
- data/lib/rbhex/core/include/rinputdataevent.rb +47 -0
- data/lib/rbhex/core/include/vieditable.rb +172 -0
- data/lib/rbhex/core/include/widgetmenu.rb +66 -0
- data/lib/rbhex/core/system/colormap.rb +165 -0
- data/lib/rbhex/core/system/keyboard.rb +150 -0
- data/lib/rbhex/core/system/keydefs.rb +30 -0
- data/lib/rbhex/core/system/ncurses.rb +236 -0
- data/lib/rbhex/core/system/panel.rb +162 -0
- data/lib/rbhex/core/system/window.rb +913 -0
- data/lib/rbhex/core/util/ansiparser.rb +119 -0
- data/lib/rbhex/core/util/app.rb +1228 -0
- data/lib/rbhex/core/util/basestack.rb +410 -0
- data/lib/rbhex/core/util/bottomline.rb +1859 -0
- data/lib/rbhex/core/util/colorparser.rb +77 -0
- data/lib/rbhex/core/util/focusmanager.rb +31 -0
- data/lib/rbhex/core/util/padreader.rb +192 -0
- data/lib/rbhex/core/util/rcommandwindow.rb +604 -0
- data/lib/rbhex/core/util/rdialogs.rb +574 -0
- data/lib/rbhex/core/util/viewer.rb +149 -0
- data/lib/rbhex/core/util/widgetshortcuts.rb +506 -0
- data/lib/rbhex/core/version.rb +5 -0
- data/lib/rbhex/core/widgets/applicationheader.rb +103 -0
- data/lib/rbhex/core/widgets/box.rb +58 -0
- data/lib/rbhex/core/widgets/divider.rb +310 -0
- data/lib/rbhex/core/widgets/keylabelprinter.rb +194 -0
- data/lib/rbhex/core/widgets/rcombo.rb +253 -0
- data/lib/rbhex/core/widgets/rcontainer.rb +415 -0
- data/lib/rbhex/core/widgets/rlink.rb +30 -0
- data/lib/rbhex/core/widgets/rlist.rb +696 -0
- data/lib/rbhex/core/widgets/rmenu.rb +958 -0
- data/lib/rbhex/core/widgets/rmenulink.rb +22 -0
- data/lib/rbhex/core/widgets/rmessagebox.rb +387 -0
- data/lib/rbhex/core/widgets/rprogress.rb +118 -0
- data/lib/rbhex/core/widgets/rtabbedpane.rb +634 -0
- data/lib/rbhex/core/widgets/rtabbedwindow.rb +70 -0
- data/lib/rbhex/core/widgets/rtextarea.rb +960 -0
- data/lib/rbhex/core/widgets/rtextview.rb +739 -0
- data/lib/rbhex/core/widgets/rtree.rb +768 -0
- data/lib/rbhex/core/widgets/rwidget.rb +3277 -0
- data/lib/rbhex/core/widgets/scrollbar.rb +143 -0
- data/lib/rbhex/core/widgets/statusline.rb +113 -0
- data/lib/rbhex/core/widgets/tabular.rb +264 -0
- data/lib/rbhex/core/widgets/tabularwidget.rb +1142 -0
- data/lib/rbhex/core/widgets/textpad.rb +995 -0
- data/lib/rbhex/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/rbhex/core/widgets/tree/treemodel.rb +428 -0
- data/rbhex-core.gemspec +32 -0
- metadata +172 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# 2010-09-18 15:35
|
|
2
|
+
require 'rbhex'
|
|
3
|
+
require 'rbhex/core/widgets/rwidget'
|
|
4
|
+
module RubyCurses
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# This is a basic list cell renderer that will render the to_s value of anything.
|
|
8
|
+
#
|
|
9
|
+
# TODO upgrade as per new listcellrenderer
|
|
10
|
+
class TreeCellRenderer
|
|
11
|
+
PLUS_PLUS = "++"
|
|
12
|
+
PLUS_MINUS = "+-"
|
|
13
|
+
PLUS_Q = "+?"
|
|
14
|
+
include RubyCurses::ConfigSetup
|
|
15
|
+
include RubyCurses::Utils
|
|
16
|
+
dsl_accessor :justify # :right, :left, :center # added 2008-12-22 19:02
|
|
17
|
+
dsl_accessor :display_length # please give this to ensure the we only print this much
|
|
18
|
+
dsl_accessor :height # if you want a multiline label.
|
|
19
|
+
dsl_accessor :text # text of label
|
|
20
|
+
dsl_accessor :color, :bgcolor
|
|
21
|
+
dsl_accessor :row, :col
|
|
22
|
+
dsl_accessor :parent #usuall the table to get colors and other default info
|
|
23
|
+
attr_reader :actual_length
|
|
24
|
+
attr_accessor :pcol
|
|
25
|
+
|
|
26
|
+
def initialize text="", config={}, &block
|
|
27
|
+
@text = text
|
|
28
|
+
@editable = false
|
|
29
|
+
@focusable = false
|
|
30
|
+
@actual_length = 0
|
|
31
|
+
config_setup config # @config.each_pair { |k,v| variable_set(k,v) }
|
|
32
|
+
instance_eval &block if block_given?
|
|
33
|
+
init_vars
|
|
34
|
+
end
|
|
35
|
+
def init_vars
|
|
36
|
+
@justify ||= :left
|
|
37
|
+
@display_length ||= 10
|
|
38
|
+
end
|
|
39
|
+
def getvalue
|
|
40
|
+
@text
|
|
41
|
+
end
|
|
42
|
+
##
|
|
43
|
+
# sets @color_pair and @attr
|
|
44
|
+
def prepare_default_colors focussed, selected
|
|
45
|
+
@color_pair = get_color $datacolor
|
|
46
|
+
@attr = @row_attr || Ncurses::A_NORMAL
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## determine bg and fg and attr
|
|
50
|
+
if selected
|
|
51
|
+
#@attr = Ncurses::A_BOLD if selected
|
|
52
|
+
## 2010-09-18 18:32 making selected row reverse
|
|
53
|
+
@attr |= Ncurses::A_REVERSE
|
|
54
|
+
|
|
55
|
+
# 2010-09-18 18:33 maybe not required, just confuses the whole thing and uglifies it
|
|
56
|
+
#@color_pair =get_color $selectedcolor, @parent.selected_color, @parent.selected_bgcolor unless @parent.nil?
|
|
57
|
+
end
|
|
58
|
+
case focussed
|
|
59
|
+
when :SOFT_FOCUS
|
|
60
|
+
@attr |= Ncurses::A_BOLD
|
|
61
|
+
when true
|
|
62
|
+
# earlier focussed row showed up in reverse, which was confusing since it looked selected
|
|
63
|
+
# now focussed row has cursor on side, and can be bold. that's enough.
|
|
64
|
+
@attr |= Ncurses::A_BOLD
|
|
65
|
+
#@attr |= Ncurses::A_REVERSE
|
|
66
|
+
when false
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
##
|
|
71
|
+
# paint a list box cell
|
|
72
|
+
# 2010-09-02 15:38 changed focussed to take true, false and :SOFT_FOCUS
|
|
73
|
+
# SOFT_FOCUS means the form focus is no longer on this field, but this row
|
|
74
|
+
# was focussed when use was last on this field. This row will take focus
|
|
75
|
+
# when field is focussed again
|
|
76
|
+
#
|
|
77
|
+
# @param [Buffer] window or buffer object used for printing
|
|
78
|
+
# @param [Fixnum] row
|
|
79
|
+
# @param [Fixnum] column
|
|
80
|
+
# @param [Fixnum] actual index into data, some lists may have actual data elsewhere and
|
|
81
|
+
# display data separate. e.g. rfe_renderer (directory listing)
|
|
82
|
+
# @param [String] text to print in cell
|
|
83
|
+
# @param [Boolean, :SOFT_FOCUS] cell focussed, not focussed, cell focussed but field is not focussed
|
|
84
|
+
# @param [Boolean] cell selected or not
|
|
85
|
+
#renderer.repaint @graphic, r+hh, c+@left_margin, crow, object, content, focus_type, selected, expanded, leaf
|
|
86
|
+
def repaint graphic, r=@row,c=@col, row_index=-1, treearraynode=nil, value=@text, leaf=nil, focussed=false, selected=false, expanded=false
|
|
87
|
+
#$log.debug "label :#{@text}, #{value}, #{r}, #{c} col= #{@color}, #{@bgcolor} acolor= #{acolor} j:#{@justify} dlL: #{@display_length} "
|
|
88
|
+
|
|
89
|
+
prepare_default_colors focussed, selected
|
|
90
|
+
|
|
91
|
+
value=value.to_s # ??
|
|
92
|
+
#icon = object.is_leaf? ? "-" : "+"
|
|
93
|
+
#icon = leaf ? "-" : "+"
|
|
94
|
+
|
|
95
|
+
#level = treearraynode.level
|
|
96
|
+
#node = treearraynode.node
|
|
97
|
+
level = treearraynode.level
|
|
98
|
+
node = treearraynode
|
|
99
|
+
if parent.node_expanded? node
|
|
100
|
+
icon = PLUS_MINUS # can collapse
|
|
101
|
+
else
|
|
102
|
+
icon = PLUS_PLUS # can expand
|
|
103
|
+
end
|
|
104
|
+
if node.children.size == 0
|
|
105
|
+
icon = PLUS_Q # either no children or not visited yet
|
|
106
|
+
if parent.has_been_expanded node
|
|
107
|
+
icon = PLUS_MINUS # definitely no children, we've visited
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
# adding 2 to level, that's the size of icon
|
|
111
|
+
# XXX FIXME if we put the icon here, then when we scroll right, the icon will show, it shoud not
|
|
112
|
+
# FIXME we ignore truncation etc on previous level and take the object as is !!!
|
|
113
|
+
_value = "%*s %s" % [ level+2, icon, node.user_object ]
|
|
114
|
+
@actual_length = _value.length
|
|
115
|
+
pcol = @pcol
|
|
116
|
+
if pcol > 0
|
|
117
|
+
_len = @display_length || @parent.width-2
|
|
118
|
+
_value = _value[@pcol..@pcol+_len-1]
|
|
119
|
+
end
|
|
120
|
+
_value ||= ""
|
|
121
|
+
if @height && @height > 1
|
|
122
|
+
else
|
|
123
|
+
# ensure we do not exceed
|
|
124
|
+
if !@display_length.nil?
|
|
125
|
+
if _value.length > @display_length
|
|
126
|
+
@actual_length = _value.length
|
|
127
|
+
_value = _value[0..@display_length-1]
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
#lablist << value
|
|
131
|
+
end
|
|
132
|
+
len = @display_length || _value.length
|
|
133
|
+
graphic.printstring r, c, "%-*s" % [len, _value], @color_pair,@attr
|
|
134
|
+
#_height = @height || 1
|
|
135
|
+
#0.upto(_height-1) { |i|
|
|
136
|
+
#graphic.printstring r+i, c, ( " " * len) , @color_pair,@attr
|
|
137
|
+
#}
|
|
138
|
+
#lablist.each_with_index do |_value, ix|
|
|
139
|
+
#break if ix >= _height
|
|
140
|
+
#if @justify.to_sym == :center
|
|
141
|
+
#padding = (@display_length - _value.length)/2
|
|
142
|
+
#_value = " "*padding + _value + " "*padding # so its cleared if we change it midway
|
|
143
|
+
#end
|
|
144
|
+
#graphic.printstring r, c, str % [len, _value], @color_pair,@attr
|
|
145
|
+
#r += 1
|
|
146
|
+
#end
|
|
147
|
+
end
|
|
148
|
+
# ADD HERE
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
# File TreeModel
|
|
2
|
+
# (c) rkumar arunachalesha
|
|
3
|
+
# Created on: Fri Sep 17 20:03:10 IST 2010
|
|
4
|
+
require 'rbhex'
|
|
5
|
+
|
|
6
|
+
module RubyCurses
|
|
7
|
+
class IllegalStateException < Exception
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class DefaultTreeModel #< TreeModel
|
|
11
|
+
include RubyCurses::EventHandler
|
|
12
|
+
attr_reader :asks_allow_children
|
|
13
|
+
attr_accessor :root_visible
|
|
14
|
+
def initialize node=nil, asks_allow_children=false, &block
|
|
15
|
+
@root_visible = true
|
|
16
|
+
root(node, asks_allow_children) if node
|
|
17
|
+
instance_eval &block if block_given?
|
|
18
|
+
end
|
|
19
|
+
# insert a node the old sucky java pain in the butt way
|
|
20
|
+
# private
|
|
21
|
+
# sets node as root
|
|
22
|
+
#def root node, asks_allow_children=false, &block
|
|
23
|
+
def root *args, &block
|
|
24
|
+
return @root if args.empty?
|
|
25
|
+
node = args[0]
|
|
26
|
+
@asks_allow_children = args[1]
|
|
27
|
+
if !node.is_a? TreeNode
|
|
28
|
+
n = TreeNode.new node
|
|
29
|
+
node = n
|
|
30
|
+
end
|
|
31
|
+
@root = node
|
|
32
|
+
$log.debug " XXX def root created root with #{node} "
|
|
33
|
+
#add node, true, &block
|
|
34
|
+
instance_eval &block if block_given?
|
|
35
|
+
end
|
|
36
|
+
def insert_node_into nodechild, nodeparent, index
|
|
37
|
+
$log.debug " TODO remove from existing parent to avoid bugs XXX"
|
|
38
|
+
nodeparent.insert nodechild, index
|
|
39
|
+
if @handler # only if someone is listening, won't fire when being prepared
|
|
40
|
+
tme = TreeModelEvent.new(row, row,:ALL_COLUMNS, self, :INSERT)
|
|
41
|
+
fire_handler :TREE_MODEL_EVENT, tme
|
|
42
|
+
end
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
# add a node to root passing a block optionally
|
|
46
|
+
# @param [String, TreeNode, Array, Hash] node/s to add
|
|
47
|
+
# @param [Boolean] allow children to be added
|
|
48
|
+
# @see TreeNode.add
|
|
49
|
+
# @return [TreeNode] node just added to root (NOT self)
|
|
50
|
+
def add nodechild, allows_children=true, &block
|
|
51
|
+
# calling TreeNode.add
|
|
52
|
+
$log.debug " XXX def add of DTM #{nodechild} to root "
|
|
53
|
+
node = @root.add nodechild, allows_children, &block
|
|
54
|
+
if @handler # only if someone is listening, won't fire when being prepared
|
|
55
|
+
tme = TreeModelEvent.new(row, row,:ALL_COLUMNS, self, :INSERT)
|
|
56
|
+
fire_handler :TREE_MODEL_EVENT, tme
|
|
57
|
+
end
|
|
58
|
+
#return @root
|
|
59
|
+
return node
|
|
60
|
+
end
|
|
61
|
+
def leaf node, &block
|
|
62
|
+
add node, false, &block
|
|
63
|
+
end
|
|
64
|
+
def branch node, &block
|
|
65
|
+
add node, true, &block
|
|
66
|
+
end
|
|
67
|
+
alias :<< :add
|
|
68
|
+
def insert row, obj
|
|
69
|
+
@data.insert row, obj
|
|
70
|
+
if @handler # only if someone is listening, won't fire when being prepared
|
|
71
|
+
tme = TreeModelEvent.new(row, row,:ALL_COLUMNS, self, :INSERT)
|
|
72
|
+
fire_handler :TREE_MODEL_EVENT, tme
|
|
73
|
+
end
|
|
74
|
+
def child_at parent, index
|
|
75
|
+
end
|
|
76
|
+
def index_of_child parent, child
|
|
77
|
+
end
|
|
78
|
+
def child_count node
|
|
79
|
+
node.children.size
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def row_count
|
|
83
|
+
@data.length
|
|
84
|
+
end
|
|
85
|
+
#
|
|
86
|
+
def set_value_at row, col, val
|
|
87
|
+
# if editing allowed
|
|
88
|
+
raise "not yet used"
|
|
89
|
+
@data[row][col] = val
|
|
90
|
+
tme = TreeModelEvent.new(row, row, col, self, :UPDATE)
|
|
91
|
+
fire_handler :TREE_MODEL_EVENT, tme
|
|
92
|
+
end
|
|
93
|
+
##
|
|
94
|
+
# please avoid directly hitting this. Suggested to use get_value_at of jtable
|
|
95
|
+
# since columns could have been switched.
|
|
96
|
+
def get_value_at row, col
|
|
97
|
+
raise "not yet used"
|
|
98
|
+
#$log.debug " def get_value_at #{row}, #{col} "
|
|
99
|
+
|
|
100
|
+
raise "IndexError get_value_at #{row}, #{col}" if @data.nil? or row >= @data.size
|
|
101
|
+
return @data[row][ col]
|
|
102
|
+
end
|
|
103
|
+
#def << obj
|
|
104
|
+
#@data << obj
|
|
105
|
+
#tme = TreeModelEvent.new(@data.length-1,@data.length-1, :ALL_COLUMNS, self, :INSERT)
|
|
106
|
+
#fire_handler :TREE_MODEL_EVENT, tme
|
|
107
|
+
#end
|
|
108
|
+
# create tablemodelevent and fire_table_changed for all listeners
|
|
109
|
+
end
|
|
110
|
+
def delete obj
|
|
111
|
+
raise "not yet used"
|
|
112
|
+
row = @data.index obj
|
|
113
|
+
return if row.nil?
|
|
114
|
+
ret = @data.delete obj
|
|
115
|
+
tme = TreeModelEvent.new(row, row,:ALL_COLUMNS, self, :DELETE)
|
|
116
|
+
fire_handler :TREE_MODEL_EVENT, tme
|
|
117
|
+
# create tablemodelevent and fire_table_changed for all listeners
|
|
118
|
+
return ret
|
|
119
|
+
end
|
|
120
|
+
def delete_at row
|
|
121
|
+
raise "not yet used"
|
|
122
|
+
if !$multiplier or $multiplier == 0
|
|
123
|
+
@delete_buffer = @data.delete_at row
|
|
124
|
+
else
|
|
125
|
+
@delete_buffer = @data.slice!(row, $multiplier)
|
|
126
|
+
end
|
|
127
|
+
$multiplier = 0
|
|
128
|
+
#ret = @data.delete_at row
|
|
129
|
+
# create tablemodelevent and fire_table_changed for all listeners
|
|
130
|
+
# we don;t pass buffer to event as in listeditable. how to undo later?
|
|
131
|
+
tme = TreeModelEvent.new(row, row+@delete_buffer.length,:ALL_COLUMNS, self, :DELETE)
|
|
132
|
+
fire_handler :TREE_MODEL_EVENT, tme
|
|
133
|
+
return @delete_buffer
|
|
134
|
+
end
|
|
135
|
+
# a quick method to undo deletes onto given row. More like paste
|
|
136
|
+
def undo where
|
|
137
|
+
raise "not yet used"
|
|
138
|
+
return unless @delete_buffer
|
|
139
|
+
case @delete_buffer[0]
|
|
140
|
+
when Array
|
|
141
|
+
@delete_buffer.each do |r|
|
|
142
|
+
insert where, r
|
|
143
|
+
end
|
|
144
|
+
else
|
|
145
|
+
insert where, @delete_buffer
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
##
|
|
149
|
+
# added 2009-01-17 21:36
|
|
150
|
+
# Use with caution, does not call events per row
|
|
151
|
+
def delete_all
|
|
152
|
+
raise "not yet used"
|
|
153
|
+
len = @data.length-1
|
|
154
|
+
@data=[]
|
|
155
|
+
tme = TreeModelEvent.new(0, len,:ALL_COLUMNS, self, :DELETE)
|
|
156
|
+
fire_handler :TREE_MODEL_EVENT, tme
|
|
157
|
+
end
|
|
158
|
+
##
|
|
159
|
+
# for those quick cases when you wish to replace all the data
|
|
160
|
+
# and not have an event per row being generated
|
|
161
|
+
def data=(data)
|
|
162
|
+
raise "not yet used"
|
|
163
|
+
raise "Data nil or invalid" if data.nil? or data.size == 0
|
|
164
|
+
delete_all
|
|
165
|
+
@data = data
|
|
166
|
+
tme = TreeModelEvent.new(0, @data.length-1,:ALL_COLUMNS, self, :INSERT)
|
|
167
|
+
fire_handler :TREE_MODEL_EVENT, tme
|
|
168
|
+
end
|
|
169
|
+
#def ask_search_forward
|
|
170
|
+
#regex = get_string "Enter regex to search for:"
|
|
171
|
+
#ix = get_list_data_model.find_match regex
|
|
172
|
+
#if ix.nil?
|
|
173
|
+
#alert("No matching data for: #{regex}")
|
|
174
|
+
#else
|
|
175
|
+
#set_focus_on(ix)
|
|
176
|
+
#end
|
|
177
|
+
#end
|
|
178
|
+
## continues previous search
|
|
179
|
+
###
|
|
180
|
+
#def find_match regex, ix0=0, ix1=row_count()
|
|
181
|
+
#$log.debug " find_match got #{regex} #{ix0} #{ix1}"
|
|
182
|
+
#@last_regex = regex
|
|
183
|
+
#@search_start_ix = ix0
|
|
184
|
+
#@search_end_ix = ix1
|
|
185
|
+
#@data.each_with_index do |row, ix|
|
|
186
|
+
#next if ix < ix0
|
|
187
|
+
#break if ix > ix1
|
|
188
|
+
#if row.grep(/#{regex}/) != []
|
|
189
|
+
##if !row.match(regex).nil?
|
|
190
|
+
#@search_found_ix = ix
|
|
191
|
+
#return ix
|
|
192
|
+
#end
|
|
193
|
+
#end
|
|
194
|
+
#return nil
|
|
195
|
+
#end
|
|
196
|
+
#def find_prev regex=@last_regex, start = @search_found_ix
|
|
197
|
+
#raise "No previous search" if @last_regex.nil?
|
|
198
|
+
#$log.debug " find_prev #{@search_found_ix} : #{@current_index}"
|
|
199
|
+
#start -= 1 unless start == 0
|
|
200
|
+
#@last_regex = regex
|
|
201
|
+
#@search_start_ix = start
|
|
202
|
+
#start.downto(0) do |ix|
|
|
203
|
+
#row = @data[ix]
|
|
204
|
+
#if row.grep(/#{regex}/) != []
|
|
205
|
+
#@search_found_ix = ix
|
|
206
|
+
#return ix
|
|
207
|
+
#end
|
|
208
|
+
#end
|
|
209
|
+
#return nil
|
|
210
|
+
##return find_match @last_regex, start, @search_end_ix
|
|
211
|
+
#end
|
|
212
|
+
### dtm findnext
|
|
213
|
+
#def find_next
|
|
214
|
+
#raise "No more search" if @last_regex.nil?
|
|
215
|
+
#start = @search_found_ix && @search_found_ix+1 || 0
|
|
216
|
+
#return find_match @last_regex, start, @search_end_ix
|
|
217
|
+
#end
|
|
218
|
+
# just a test program
|
|
219
|
+
def traverse node=@root, level=0
|
|
220
|
+
icon = node.is_leaf? ? "-" : "+"
|
|
221
|
+
puts "%*s %s" % [ level+1, icon, node.user_object ]
|
|
222
|
+
node.children.each do |e|
|
|
223
|
+
traverse e, level+1
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end # class DTM
|
|
227
|
+
# When an event is fired by TableModel, contents are changed, then this object will be passed
|
|
228
|
+
# to trigger
|
|
229
|
+
# type is :INSERT :UPDATE :DELETE :HEADER_ROW
|
|
230
|
+
# columns: number or :ALL_COLUMNS
|
|
231
|
+
class TreeModelEvent
|
|
232
|
+
attr_accessor :firstrow, :lastrow, :source, :type
|
|
233
|
+
def initialize firstrow, lastrow, source, type
|
|
234
|
+
@firstrow = firstrow
|
|
235
|
+
@lastrow = lastrow
|
|
236
|
+
@source = source
|
|
237
|
+
@type = type
|
|
238
|
+
end
|
|
239
|
+
def to_s
|
|
240
|
+
"#{@type.to_s}, firstrow: #{@firstrow}, lastrow: #{@lastrow}, source: #{@source}"
|
|
241
|
+
end
|
|
242
|
+
def inspect
|
|
243
|
+
to_s
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
class TreeNode
|
|
247
|
+
#extend Forwardable
|
|
248
|
+
|
|
249
|
+
attr_accessor :parent
|
|
250
|
+
attr_reader :children
|
|
251
|
+
attr_reader :user_object
|
|
252
|
+
attr_reader :allows_children
|
|
253
|
+
def initialize user_object=nil, allows_children=true, &block #form, config={}, &block
|
|
254
|
+
@allows_children = allows_children
|
|
255
|
+
@user_object = user_object
|
|
256
|
+
@children = []
|
|
257
|
+
#super
|
|
258
|
+
instance_eval &block if block_given?
|
|
259
|
+
init_vars
|
|
260
|
+
end
|
|
261
|
+
# private
|
|
262
|
+
#@return [TreeNode] just creates node
|
|
263
|
+
def _add node, allows_children=true, &block
|
|
264
|
+
#raise ArgumentError, "Argument should be a node" if !node.is_a? TreeNode
|
|
265
|
+
$log.debug " TODO remove from existing parent to avoid bugs XXX"
|
|
266
|
+
if !node.is_a? TreeNode
|
|
267
|
+
n = TreeNode.new node, allows_children, &block
|
|
268
|
+
node = n
|
|
269
|
+
end
|
|
270
|
+
node.parent = self
|
|
271
|
+
@children << node
|
|
272
|
+
node
|
|
273
|
+
end
|
|
274
|
+
# add a node to this node, optionally passing a block for further adding
|
|
275
|
+
# add a node as child to existing node
|
|
276
|
+
# If node is not a TreeNode it will be converted to one.
|
|
277
|
+
# @param [TreeNode, Array, Hash] node/s to add
|
|
278
|
+
# @param [boolean] should children be allowed
|
|
279
|
+
# @return [TreeNode] node last added (*NOT* self)
|
|
280
|
+
def add node, allows_children=true, &block
|
|
281
|
+
raise IllegalStateException, "Cannot add a child to this node" unless @allows_children
|
|
282
|
+
$log.debug " XXX def add of TreeNode #{node} parent #{self} "
|
|
283
|
+
case node
|
|
284
|
+
when Array
|
|
285
|
+
node.each do |e|
|
|
286
|
+
add e, allows_children, &block
|
|
287
|
+
end
|
|
288
|
+
when Hash
|
|
289
|
+
node.each_pair { |name, val|
|
|
290
|
+
n = _add name, allows_children, &block
|
|
291
|
+
n.add val, allows_children, &block
|
|
292
|
+
}
|
|
293
|
+
else
|
|
294
|
+
return _add node, allows_children, &block
|
|
295
|
+
end
|
|
296
|
+
self
|
|
297
|
+
end
|
|
298
|
+
def leaf node, &block
|
|
299
|
+
add node, false, &block
|
|
300
|
+
end
|
|
301
|
+
def branch node, &block
|
|
302
|
+
add node, true, &block
|
|
303
|
+
end
|
|
304
|
+
alias :<< :add
|
|
305
|
+
def insert node, index
|
|
306
|
+
raise ArgumentError, "Argument should be a node. it is #{node.class} " if !node.is_a? TreeNode
|
|
307
|
+
@children.insert index, node
|
|
308
|
+
self
|
|
309
|
+
end
|
|
310
|
+
def child_after node
|
|
311
|
+
end
|
|
312
|
+
def child_before node
|
|
313
|
+
end
|
|
314
|
+
def child_at node
|
|
315
|
+
end
|
|
316
|
+
def next_node node
|
|
317
|
+
end
|
|
318
|
+
def remove
|
|
319
|
+
end
|
|
320
|
+
def remove_all_children
|
|
321
|
+
end
|
|
322
|
+
def remove_from_parent
|
|
323
|
+
end
|
|
324
|
+
def is_leaf?
|
|
325
|
+
@children.size == 0
|
|
326
|
+
end
|
|
327
|
+
def leaf_count
|
|
328
|
+
end
|
|
329
|
+
def level
|
|
330
|
+
level = 0
|
|
331
|
+
nodeparent = parent()
|
|
332
|
+
while( nodeparent != nil )
|
|
333
|
+
level += 1
|
|
334
|
+
nodeparent = nodeparent.parent()
|
|
335
|
+
end
|
|
336
|
+
return level
|
|
337
|
+
end
|
|
338
|
+
def leaf_count
|
|
339
|
+
end
|
|
340
|
+
def traverse_up &block
|
|
341
|
+
nodeparent = parent()
|
|
342
|
+
while ( nodeparent != nil )
|
|
343
|
+
yield nodeparent
|
|
344
|
+
nodeparent = nodeparent.parent()
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
# returns an array of user_objects for the current node
|
|
348
|
+
# starting from root, ending in the current one. The last node
|
|
349
|
+
# represents this node.
|
|
350
|
+
# @return [Array] Strings[]
|
|
351
|
+
def user_object_path
|
|
352
|
+
arr = []
|
|
353
|
+
arr << self.user_object.to_s
|
|
354
|
+
traverse_up do |e|
|
|
355
|
+
arr << e.user_object.to_s
|
|
356
|
+
end
|
|
357
|
+
arr.reverse!
|
|
358
|
+
end
|
|
359
|
+
# returns an array of nodes for the current node
|
|
360
|
+
# starting from root, ending in the current one. The last node
|
|
361
|
+
# represents this node.
|
|
362
|
+
# @return [Array] TreeNode[]
|
|
363
|
+
def tree_path
|
|
364
|
+
arr = []
|
|
365
|
+
arr << self
|
|
366
|
+
traverse_up do |e|
|
|
367
|
+
arr << e
|
|
368
|
+
end
|
|
369
|
+
arr.reverse!
|
|
370
|
+
end
|
|
371
|
+
# http://github.com/evolve75/RubyTree/blob/master/lib/tree.rb
|
|
372
|
+
def breadth_each(max_depth=999,&block)
|
|
373
|
+
node_queue = [self] # Create a queue with self as the initial entry
|
|
374
|
+
|
|
375
|
+
# Use a queue to do breadth traversal
|
|
376
|
+
until node_queue.empty?
|
|
377
|
+
node_to_traverse = node_queue.shift
|
|
378
|
+
yield node_to_traverse
|
|
379
|
+
# Enqueue the children from left to right.
|
|
380
|
+
node_to_traverse.children { |child| node_queue.push child }
|
|
381
|
+
max_depth -= 1
|
|
382
|
+
break if max_depth == 0
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
def to_s
|
|
386
|
+
@user_object.to_s
|
|
387
|
+
end
|
|
388
|
+
def init_vars
|
|
389
|
+
@repaint_required = true
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
end # module
|
|
393
|
+
|
|
394
|
+
if $0 == __FILE__
|
|
395
|
+
$log = Logger.new("rbc13.log")
|
|
396
|
+
$log.level = Logger::DEBUG
|
|
397
|
+
|
|
398
|
+
include RubyCurses
|
|
399
|
+
root = TreeNode.new "ROOT"
|
|
400
|
+
subroot = TreeNode.new "subroot"
|
|
401
|
+
leaf1 = TreeNode.new "leaf 1"
|
|
402
|
+
leaf2 = TreeNode.new "leaf 2"
|
|
403
|
+
|
|
404
|
+
model = DefaultTreeModel.new root
|
|
405
|
+
#model.insert_node_into(subroot, root, 0)
|
|
406
|
+
#model.insert_node_into(leaf1, subroot, 0)
|
|
407
|
+
#model.insert_node_into(leaf2, subroot, 1)
|
|
408
|
+
root << subroot
|
|
409
|
+
# this will allow us to do a recursive add
|
|
410
|
+
#subroot << leaf1 << leaf2
|
|
411
|
+
subroot << leaf1
|
|
412
|
+
subroot << leaf2
|
|
413
|
+
leaf1 << "leaf11" << "leaf111"
|
|
414
|
+
leaf1 << "leaf12" << "leaf121"
|
|
415
|
+
|
|
416
|
+
root.add "blocky", true do
|
|
417
|
+
add "block2"
|
|
418
|
+
add "block3" do
|
|
419
|
+
add "block31"
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
model.traverse root
|
|
424
|
+
puts "tree path: ..."
|
|
425
|
+
puts leaf2.tree_path
|
|
426
|
+
puts "object path: ..."
|
|
427
|
+
puts leaf2.user_object_path
|
|
428
|
+
end
|