rbcurse-core 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +69 -0
- data/VERSION +1 -0
- data/examples/abasiclist.rb +151 -0
- data/examples/alpmenu.rb +46 -0
- data/examples/app.sample +17 -0
- data/examples/atree.rb +100 -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/todocsv.csv +28 -0
- data/examples/data/unix1.txt +21 -0
- data/examples/data/unix2.txt +11 -0
- data/examples/dbdemo.rb +487 -0
- data/examples/dirtree.rb +90 -0
- data/examples/newtabbedwindow.rb +100 -0
- data/examples/newtesttabp.rb +92 -0
- data/examples/tabular.rb +132 -0
- data/examples/tasks.rb +167 -0
- data/examples/term2.rb +83 -0
- data/examples/testkeypress.rb +72 -0
- data/examples/testlistbox.rb +158 -0
- data/examples/testmessagebox.rb +140 -0
- data/examples/testree.rb +106 -0
- data/examples/testwsshortcuts.rb +66 -0
- data/examples/testwsshortcuts2.rb +127 -0
- data/lib/rbcurse.rb +8 -0
- data/lib/rbcurse/core/docs/index.txt +73 -0
- data/lib/rbcurse/core/include/action.rb +40 -0
- data/lib/rbcurse/core/include/appmethods.rb +112 -0
- data/lib/rbcurse/core/include/bordertitle.rb +41 -0
- data/lib/rbcurse/core/include/chunk.rb +182 -0
- data/lib/rbcurse/core/include/io.rb +953 -0
- data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
- data/lib/rbcurse/core/include/listeditable.rb +317 -0
- data/lib/rbcurse/core/include/listscrollable.rb +590 -0
- data/lib/rbcurse/core/include/listselectable.rb +264 -0
- data/lib/rbcurse/core/include/multibuffer.rb +83 -0
- data/lib/rbcurse/core/include/orderedhash.rb +77 -0
- data/lib/rbcurse/core/include/ractionevent.rb +67 -0
- data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
- data/lib/rbcurse/core/include/rhistory.rb +62 -0
- data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
- data/lib/rbcurse/core/include/vieditable.rb +170 -0
- data/lib/rbcurse/core/system/colormap.rb +163 -0
- data/lib/rbcurse/core/system/keyboard.rb +150 -0
- data/lib/rbcurse/core/system/keydefs.rb +30 -0
- data/lib/rbcurse/core/system/ncurses.rb +218 -0
- data/lib/rbcurse/core/system/panel.rb +162 -0
- data/lib/rbcurse/core/system/window.rb +901 -0
- data/lib/rbcurse/core/util/ansiparser.rb +117 -0
- data/lib/rbcurse/core/util/app.rb +1235 -0
- data/lib/rbcurse/core/util/basestack.rb +407 -0
- data/lib/rbcurse/core/util/bottomline.rb +1850 -0
- data/lib/rbcurse/core/util/colorparser.rb +71 -0
- data/lib/rbcurse/core/util/focusmanager.rb +31 -0
- data/lib/rbcurse/core/util/padreader.rb +189 -0
- data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
- data/lib/rbcurse/core/util/rdialogs.rb +619 -0
- data/lib/rbcurse/core/util/viewer.rb +149 -0
- data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
- data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
- data/lib/rbcurse/core/widgets/box.rb +58 -0
- data/lib/rbcurse/core/widgets/divider.rb +310 -0
- data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
- data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
- data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
- data/lib/rbcurse/core/widgets/rlink.rb +30 -0
- data/lib/rbcurse/core/widgets/rlist.rb +723 -0
- data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
- data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
- data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
- data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
- data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
- data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
- data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
- data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
- data/lib/rbcurse/core/widgets/rtree.rb +787 -0
- data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
- data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
- data/lib/rbcurse/core/widgets/statusline.rb +94 -0
- data/lib/rbcurse/core/widgets/tabular.rb +264 -0
- data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
- data/lib/rbcurse/core/widgets/textpad.rb +516 -0
- data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
- data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
- metadata +156 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
# 2010-09-18 15:35
|
2
|
+
require 'rbcurse'
|
3
|
+
require 'rbcurse/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 'rbcurse'
|
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
|