cheri 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -6,7 +6,7 @@ based on the framework, as well as a builder-builder tool for easily creating
6
6
  simple builders. Cheri also comes with a demo application, Cheri::JRuby::Explorer,
7
7
  that is built using two of the supplied builders (Cheri::Swing and Cheri::Html).
8
8
 
9
- This version (0.0.4) is an early beta release. Some features are not yet fully
9
+ This version (0.0.5) is an early beta release. Some features are not yet fully
10
10
  developed, in particular the HTML/XML components. On the other hand, Cheri::Swing,
11
11
  which is the successor to JRBuilder (http://www2.webng.com/bdortch/jrbuilder), is
12
12
  relatively mature, in an adolescent sort of way, though many features could be added.
@@ -40,8 +40,13 @@ Cheri gem):
40
40
 
41
41
  Cheri::JRuby::Explorer.run
42
42
 
43
+ Alternatively, you can load and run it in one step:
44
+
45
+ require 'rubygems'
46
+ require 'cheri/cjx'
47
+
43
48
  This will take several seconds to load and start -- performance will be one area
44
- of improvement for versions 0.0.5 and beyond. Once it loads, it should be fairly
49
+ of improvement for versions 0.0.6 and beyond. Once it loads, it should be fairly
45
50
  clear what to do.
46
51
 
47
52
  Some known issues:
@@ -49,22 +54,13 @@ Some known issues:
49
54
  * Browsing the class hierarchy is very slow right now -- this actually slowed down
50
55
  in the past couple of days when I switched from HTML to straight Swing layout, the
51
56
  opposite of what I expected to happen.
52
-
53
- * ObjectSpace searches that return large numbers of objects sometimes result in a
54
- NullPointerException (JList seems to get overwhelmed), requiring a restart of
55
- CJX. I had a fix in that did a GC on the target instance before each search,
56
- which seemed to help, but also seemed a little extreme. This will be a search
57
- option in 0.0.5.
58
-
57
+
59
58
  * There are lots of layout issues; neither HTML (JEditorPane) nor BoxLayout provide
60
59
  exactly what I'm looking for. Will probably have to bite the bullet and go to
61
60
  GridBagLayout. Ugh.
62
-
63
- * Tab management (and navigation in general) is not yet quite right.
64
- Will have history/back buttons and better tab management in 0.0.5.
65
-
61
+
66
62
  * Global variables are currently shown, um, globally, when many of them should be shown
67
- per thread. This will be fixed in 0.0.5, which will include a Thread section with
63
+ per thread. This will be fixed in 0.0.6, which will include a Thread section with
68
64
  other goodies as well (thread-local vars, status, etc.).
69
65
 
70
66
  To install the CJX DRb server component in an instance (assuming the Cheri gem is
@@ -81,7 +81,7 @@ class TypeConnecter
81
81
  t = @t
82
82
  bld_anc = (class<<builder.object;self;end).ancestors
83
83
  anc ||= (class<<obj;self;end).ancestors
84
- key = [bld_anc,anc,sym]
84
+ key = [sym,bld_anc,anc]
85
85
  if (ctr = @c[key])
86
86
  return ctr.prepare(ctx,builder,obj,sym,props)
87
87
  end
@@ -557,6 +557,11 @@ class Context
557
557
  # alias_method :check, :ck
558
558
  #
559
559
 
560
+ # Overrides the default Object#inspect to prevent mind-boggling circular displays in IRB.
561
+ def inspect
562
+ "#<#{self.class}:instance>"
563
+ end
564
+
560
565
  # We want to prevent built objects passed as parameters from
561
566
  # being dynamically connected, since presumably the method/ctor
562
567
  # being called will do whatever is needed (except for cherify,
@@ -28,6 +28,9 @@ module Swing
28
28
 
29
29
  # note: inherits connection types from AWTConnecter
30
30
  SwingConnecter = Cheri::Builder::TypeConnecter.new(Cheri::AWT::AWTConnecter) do
31
+ jver = ENV_JAVA['java.version']
32
+ Java5 = String === jver && jver >= '1.5'
33
+ Java6 = String === jver && jver >= '1.6'
31
34
  S = java.lang.String.new ''
32
35
  TreePath = javax.swing.tree.TreePath
33
36
 
@@ -81,13 +84,13 @@ SwingConnecter = Cheri::Builder::TypeConnecter.new(Cheri::AWT::AWTConnecter) do
81
84
  # TODO: close button (:default or user JButton)
82
85
  connect java.awt.Component do |pane,cmp,sym,props|
83
86
  if props
84
- if (tc = props[:tab])
87
+ if Java6 && (tc = props[:tab])
85
88
  pane.addTab(S,cmp)
86
89
  i = pane.indexOfComponent(cmp)
87
90
  pane.setTabComponentAt(i,tc)
88
91
  # TODO: tooltip allowed for custom tab?
89
92
  else
90
- title = props[:title] || cmp.name || ''
93
+ title = props[:title] || cmp.name || S
91
94
  icon = props[:icon]
92
95
  tooltip = props[:tooltip]
93
96
  pane.addTab(title,icon,cmp,tooltip)
data/lib/cheri/cheri.rb CHANGED
@@ -29,10 +29,12 @@ module Cheri
29
29
  module VERSION #:nodoc:
30
30
  MAJOR = 0
31
31
  MINOR = 0
32
- TINY = 4
32
+ TINY = 5
33
33
  STRING = [MAJOR, MINOR, TINY].join('.').freeze
34
34
  end
35
- PathExp = Regexp.new "cheri-#{VERSION::STRING}\\/lib$" #:nodoc:
35
+ #:stopdoc:
36
+ PathExp = Regexp.new "cheri-#{VERSION::STRING}\\/lib$"
37
+ #:startdoc:
36
38
  class CheriException < StandardError; end
37
39
  # global threadsafe; set if all Cheri module instances in a system
38
40
  # must be threadsafe
@@ -79,6 +79,9 @@ module Explorer
79
79
  end
80
80
 
81
81
  class ObjectRec
82
+ # TODO: make this configurable (or settable in search dialog)
83
+ MaxDataLength = 100000
84
+
82
85
  def initialize(obj)
83
86
  @z = obj.class.to_s rescue nil
84
87
  @i = obj.__id__ rescue nil
@@ -95,6 +98,8 @@ class ObjectRec
95
98
  end
96
99
  @u = (obj.superclass.to_s rescue nil) if obj.respond_to?(:superclass)
97
100
  @s = obj.inspect rescue nil
101
+ # we're going allow a maximum of ~ 64K for value
102
+ @s = @s[0,MaxDataLength] << '...' if @s && @s.length > MaxDataLength
98
103
  end
99
104
  def clazz
100
105
  @z
@@ -186,7 +191,7 @@ class NameValue
186
191
  raise Cheri.type_error(name,String) unless String === name
187
192
  @n = name
188
193
  @i = value.__id__ rescue '?'
189
- @v = String === value ? value[0,100] : (value.to_s[0,100] rescue '?')
194
+ @v = String === value ? value[0,128] : (value.to_s[0,128] rescue '?')
190
195
  end
191
196
  def name
192
197
  @n
@@ -229,6 +234,7 @@ class NameTypeValue < NameValue
229
234
  end #NameTypeValue
230
235
 
231
236
  class SearchArgs
237
+ attr :gc, true
232
238
  def initialize(clazz,vars=nil,any=nil)
233
239
  raise Cheri.type_error(clazz,String) unless String === clazz
234
240
  raise ArgumentError,"Invalid class "+ clazz unless /^([A-Z])((\w|::[A-Z])*)$/.match clazz
@@ -237,7 +243,7 @@ class SearchArgs
237
243
  raise Cheri.type_error(vars,Array) unless Array === vars
238
244
  vars.each do |v|
239
245
  raise Cheri.type_error(v,SearchNameValue) unless SearchNameValue === v
240
- raise Cheri.type_error(v.name,Symbol) unless Symbol === v.name
246
+ raise Cheri.type_error(v.name,Symbol) if v.name && !(Symbol === v.name)
241
247
  end
242
248
  @v = vars
243
249
  @a = !(any == nil || any == false)
@@ -402,7 +408,9 @@ class RubyExplorer
402
408
  def module_methods(name,id=nil)
403
409
  if id && defined?ObjectSpace
404
410
  raise Cheri.type_error(id,Fixnum) unless Fixnum === id
405
- if Module === (mod = ObjectSpace._id2ref(id) rescue nil)
411
+ # doing this in two steps to work around JRuby bug (JRUBY-1125)
412
+ mod = ObjectSpace._id2ref(id)
413
+ if Module === mod
406
414
  return MethodRec.new(mod)
407
415
  end
408
416
  elsif name
@@ -420,7 +428,9 @@ class RubyExplorer
420
428
  def object(id)
421
429
  return unless id && defined?ObjectSpace
422
430
  raise Cheri.type_error(id,Fixnum) unless Fixnum === id
423
- if (obj = ObjectSpace._id2ref(id) rescue nil) && !(Fixnum === obj)
431
+ # doing this in two steps to work around JRuby bug (JRUBY-1125)
432
+ obj = ObjectSpace._id2ref(id)
433
+ if obj && !(Fixnum === obj)
424
434
  if Module === obj && (name = obj.name rescue nil)
425
435
  if (ix = name.rindex('::'))
426
436
  parent = name[0,ix]
@@ -440,18 +450,22 @@ class RubyExplorer
440
450
  def object_methods(id)
441
451
  return unless id && defined?ObjectSpace
442
452
  raise Cheri.type_error(id,Fixnum) unless Fixnum === id
443
- if (obj = ObjectSpace._id2ref(id) rescue nil) && !(Fixnum === obj)
453
+ # doing this in two steps to work around JRuby bug (JRUBY-1125)
454
+ obj = ObjectSpace._id2ref(id)
455
+ if obj && !(Fixnum === obj)
444
456
  return MethodRec.new(obj)
445
457
  end
446
458
  end
447
459
 
448
- def simple_value(id)
460
+ def simple_value(id,maxlen=80)
449
461
  return unless id && defined?ObjectSpace
450
462
  raise Cheri.type_error(id,Fixnum) unless Fixnum === id
451
- if (obj = ObjectSpace._id2ref(id)) && !(Fixnum === obj)
452
- obj.to_s[0,40] rescue 'Unreadable'
463
+ # doing this in two steps to work around JRuby bug (JRUBY-1125)
464
+ obj = ObjectSpace._id2ref(id)
465
+ if obj && !(Fixnum === obj)
466
+ obj.to_s[0,maxlen] rescue 'Unreadable'
453
467
  else
454
- 'Unavailable'
468
+ nil
455
469
  end
456
470
  end
457
471
 
@@ -463,30 +477,67 @@ class RubyExplorer
463
477
  # make sure we don't have anything executable before we eval it
464
478
  raise ArgumentError,"Invalid class "+ sclazz unless /^([A-Z])((\w|::[A-Z])*)$/.match sclazz
465
479
  if Module === (clazz = (eval("::#{sclazz}") rescue nil))
466
- #GC.start
480
+ GC.start if sargs.gc
467
481
  result = []
468
- vars = sargs.vars
469
- len = vars.length if vars
470
- any = sargs.any
471
- ObjectSpace.each_object(clazz) do |o|
472
- if (id = o.__id__ rescue nil)
473
- if vars
474
- match = 0
475
- vars.each do |v|
476
- if (iv = o.instance_variable_get(v.name) rescue nil) &&
477
- (v.rx? ? (iv.to_s =~ v.value rescue nil) : (iv.to_s.index(v.value) rescue nil))
478
- if any
479
- match = 1
480
- break
481
- else
482
- match += 1
482
+ if (vars = sargs.vars) && !vars.empty?
483
+ # just supporting one var name and/or value for now
484
+ sname = vars[0].name
485
+ raise ArgumentError,"Invalid instance variable" if sname && !(Symbol === sname)
486
+ sval = vars[0].value
487
+ sval = nil if String === sval && sval.empty?
488
+ rx = Regexp === sval
489
+ else
490
+ sname = nil
491
+ sval = nil
492
+ end
493
+ if sname && sval
494
+ ObjectSpace.each_object(clazz) do |o|
495
+ if Fixnum === (id = o.__id__ rescue nil) &&
496
+ #(o.respond_to?(:instance_variable_get) rescue nil) &&
497
+ (iv = o.instance_variable_get(sname) rescue nil) &&
498
+ (String === iv || String === (iv = iv.to_s rescue nil)) &&
499
+ (rx ? (iv =~ sval rescue nil) : (iv.index(sval) rescue nil))
500
+ result << id
501
+ end
502
+ end
503
+ elsif sname
504
+ sname = sname.to_s
505
+ ObjectSpace.each_object(clazz) do |o|
506
+ if Fixnum === (id = o.__id__ rescue nil) &&
507
+ #(o.respond_to?(:instance_variables) rescue nil) &&
508
+ Array === (ivs = o.instance_variables rescue nil) &&
509
+ (ivs.include?(sname) rescue nil)
510
+ result << id
511
+ end
512
+ end
513
+ elsif sval
514
+ # note: _not_ calling inspect here to avoid circular reference trap;
515
+ # examining (potentially) each instance var instead
516
+ ObjectSpace.each_object(clazz) do |o|
517
+ if Fixnum === (id = o.__id__ rescue nil)
518
+ if (String === (os = o) || String === (os = o.to_s rescue nil)) &&
519
+ (rx ? (os =~ sval rescue nil) : (os.index(sval) rescue nil))
520
+ result << id
521
+ elsif Array === (ivs = o.instance_variables rescue nil)
522
+ hit = nil
523
+ ivs.each do |ivn|
524
+ if (iv = o.instance_variable_get(ivn.to_sym) rescue nil) &&
525
+ (String === iv || String === (iv = iv.to_s rescue nil)) &&
526
+ (rx ? (iv =~ sval rescue nil) : (iv.index(sval) rescue nil))
527
+ result << id unless hit
528
+ hit = true
529
+ # this doesn't appear to be breaking?
530
+ break # TODO: check for LocalJumpError
483
531
  end
484
532
  end
485
533
  end
486
- result << id if (any && match == 1) || match == len
487
- else
488
- result << id
489
- end
534
+ end
535
+ end
536
+ else
537
+ ObjectSpace.each_object(clazz) do |o|
538
+ if Fixnum === (id = o.__id__ rescue nil)
539
+ result << id
540
+ end
490
541
  end
491
542
  end
492
543
  result
Binary file
Binary file
@@ -165,8 +165,6 @@ class SearchDialog
165
165
  @object_id = text_field do
166
166
  columns 16
167
167
  fixed_size 100,24
168
- #maximum_size dimension(100,24)
169
- #minimum_size dimension(100,24)
170
168
  end
171
169
  y_glue
172
170
  end
@@ -182,6 +180,7 @@ class SearchDialog
182
180
  'Search Error', JOptionPane::ERROR_MESSAGE)
183
181
  else
184
182
  @dialog.visible = false
183
+ @object_id.text = ''
185
184
  @main.new_find(@instances[@instance_list.selected_index],id)
186
185
  end
187
186
  end
@@ -192,11 +191,12 @@ class SearchDialog
192
191
 
193
192
  y_glue
194
193
 
195
- x_panel do
194
+ y_panel do
196
195
  compound_border(
197
196
  titled_border('Search for instances by type and optional variable/value') { etched_border :LOWERED },
198
197
  empty_border(4,8,4,8)
199
198
  )
199
+ x_panel do
200
200
  y_box do
201
201
  y_glue
202
202
  label 'Class or Module:'
@@ -217,22 +217,16 @@ class SearchDialog
217
217
  @clazz = text_field do
218
218
  columns 20
219
219
  fixed_size 200,24
220
- #maximum_size dimension(200,24)
221
- #minimum_size dimension(200,24)
222
220
  end
223
221
  y_glue
224
222
  @name1 = text_field do
225
223
  columns 20
226
224
  fixed_size 200,24
227
- #maximum_size dimension(200,24)
228
- #minimum_size dimension(200,24)
229
225
  end
230
226
  y_glue
231
227
  @value1 = text_field do
232
228
  columns 20
233
229
  fixed_size 200,24
234
- #maximum_size dimension(200,24)
235
- #minimum_size dimension(200,24)
236
230
  end
237
231
  y_glue
238
232
  end
@@ -253,24 +247,38 @@ class SearchDialog
253
247
  elsif name && name !~ /^([A-Za-z_])(\w*)$/
254
248
  JOptionPane.show_message_dialog(@dialog,"Invalid variable name, please re-enter",
255
249
  'Search Error', JOptionPane::ERROR_MESSAGE)
256
- elsif value && !name && !value.empty?
257
- JOptionPane.show_message_dialog(@dialog,"Please enter a variable name (or omit value)",
258
- 'Search Error', JOptionPane::ERROR_MESSAGE)
259
250
  else
260
- @dialog.visible = false
261
- @main.new_search(@instances[@instance_list.selected_index],clazz,name,value)
251
+ if value && value.strip.length != value.length
252
+ rsp = JOptionPane.show_confirm_dialog(@main_frame,
253
+ "Value contains leading/trailing whitespace -- continue?")
254
+ else
255
+ rsp = nil
256
+ end
257
+ unless rsp && rsp != JOptionPane::YES_OPTION
258
+ @dialog.visible = false
259
+ gc = @gc.selected
260
+ reset_fields
261
+ @main.new_search(@instances[@instance_list.selected_index],clazz,name,value,gc)
262
+ end
262
263
  end
263
264
  end
264
265
  end
265
266
  end
267
+ end
268
+ x_panel do
269
+ @gc = check_box 'GC target instance before search'
270
+ end
266
271
  end
267
272
  y_glue
273
+ x_box do
274
+ x_glue
268
275
  button 'Cancel' do
269
276
  on_click do
270
277
  @dialog.visible = false
271
278
  end
272
279
  end
273
-
280
+ x_glue
281
+ end
274
282
  y_glue
275
283
  end
276
284
 
@@ -285,6 +293,14 @@ class SearchDialog
285
293
  val
286
294
  end
287
295
 
296
+ def reset_fields
297
+ @clazz.text = ''
298
+ @name1.text = ''
299
+ @value1.text = ''
300
+ @gc.selected = false
301
+ end
302
+ private :reset_fields
303
+
288
304
  def value
289
305
  @dialog
290
306
  end
@@ -345,7 +361,7 @@ class AboutDialog
345
361
  table(:width=>'97%') {
346
362
  tr{td(:align=>:left) {
347
363
  p 'Cheri::JRuby::Explorer (CJX) demonstrates some of the features ',
348
- 'of the Cheri builder framework, and with any luck may prove useful ',
364
+ 'of the Cheri builder framework, and may even prove useful ',
349
365
  'in its own right. CJX is built using the Cheri::Swing and Cheri::Html ',
350
366
  'components of the framework.'
351
367
  p
@@ -72,6 +72,9 @@ class Main
72
72
  SearchIcon = CJava.get_icon('Search24.gif')
73
73
  RefreshIcon = CJava.get_icon('Refresh24.gif')
74
74
  CloseIcon = CJava.get_icon('Delete24.gif')
75
+ # TODO: I *hate* these next two -- find replacements!
76
+ NextIcon = CJava.get_icon('Forward24.gif')
77
+ PrevIcon = CJava.get_icon('Back24.gif')
75
78
  ClassIcon = CJava.get_icon('class_16x16.png')
76
79
  ModuleIcon = CJava.get_icon('mod_tree.png')
77
80
  Viewers = Cheri::JRuby::Explorer
@@ -106,9 +109,10 @@ class Main
106
109
  @instances = {}
107
110
  @instance_listeners = []
108
111
  @main_tabs = {}
109
- @search_tabs = {}
112
+ @result_tabs = {}
113
+ @main_tab_history = []
110
114
  @main_tabs[:global] = {}
111
- @search_tabs[:global] = {}
115
+ @result_tabs[:global] = {}
112
116
  @local_instance = JRubyInstance.new(RubyExplorer.new,'Local','local')
113
117
  add_instance(@local_instance)
114
118
  end
@@ -122,14 +126,14 @@ class Main
122
126
  @main_frame.set_location(Math.max(0,(bounds.width - 800)/2), Math.max(0,(bounds.height - 760)/2))
123
127
  @main_frame.show
124
128
  @main_frame.to_front
125
- sleep 2
129
+ sleep 1.5
126
130
  @main_tree.selection_row = 0
127
131
  @main_frame.content_pane.remove(splash_screen)
128
132
  @main_menu.visible = true
129
133
  @main_tool_bar.visible = true
130
134
  @main_panel.visible = true
131
135
  @footer_panel.visible = true
132
- @search_tab_pane.visible = false
136
+ @result_tab_pane.visible = false
133
137
  end
134
138
 
135
139
  def release_resources
@@ -157,7 +161,7 @@ class Main
157
161
  right_pane do
158
162
  right_splitter do
159
163
  main_tab_pane
160
- search_tab_pane
164
+ result_tab_pane
161
165
  end
162
166
  end
163
167
  end
@@ -212,10 +216,10 @@ class Main
212
216
  def view_menu(&block)
213
217
  @view_menu ||= menu 'View' do |mn|
214
218
  mnemonic :VK_V
215
- @search_results_select = check_box_menu_item 'Search Results pane' do
219
+ @results_select = check_box_menu_item 'Search Results pane' do
216
220
  selected true
217
221
  on_click do |e|
218
- if (@search_tab_pane.visible = e.source.selected = !@search_tab_pane.visible)
222
+ if (@result_tab_pane.visible = e.source.selected = !@result_tab_pane.visible)
219
223
  adjust_right_splitter
220
224
  end
221
225
  end
@@ -264,7 +268,12 @@ class Main
264
268
  on_click do
265
269
  show_search_dialog
266
270
  end
267
-
271
+ end
272
+ menu_item 'Repeat last search' do
273
+ mnemonic :VK_R
274
+ on_click do
275
+ repeat_search
276
+ end
268
277
  end
269
278
  end
270
279
  cheri_yield(@search_menu,&block) if block
@@ -304,9 +313,24 @@ class Main
304
313
  show_search_dialog
305
314
  end
306
315
  end
307
- button FindAgainIcon
308
- button SearchIcon
316
+ button FindAgainIcon do
317
+ tool_tip_text 'Repeat last search'
318
+ on_click do
319
+ repeat_search
320
+ end
321
+ end
322
+ button SearchIcon do
323
+ tool_tip_text "We don't know what this does yet"
324
+ end
309
325
  x_glue
326
+ button PrevIcon do
327
+ tool_tip_text 'Previous tab view'
328
+ on_click {prev_view}
329
+ end
330
+ button NextIcon do
331
+ tool_tip_text 'Next tab view'
332
+ on_click {next_view}
333
+ end
310
334
  button CloseActiveIcon do
311
335
  tool_tip_text 'Close active view'
312
336
  on_click do
@@ -372,15 +396,15 @@ class Main
372
396
  @main_tab_pane
373
397
  end
374
398
 
375
- def search_tab_pane(&block)
376
- unless @search_tab_pane
377
- @search_tab_pane = tabbed_pane do
399
+ def result_tab_pane(&block)
400
+ unless @result_tab_pane
401
+ @result_tab_pane = tabbed_pane do
378
402
  align :LEFT
379
403
  end
380
- @search_tab_pane.extend TabbedPaneMethods
404
+ @result_tab_pane.extend TabbedPaneMethods
381
405
  end
382
- cheri_yield(@search_tab_pane,&block) if block
383
- @search_tab_pane
406
+ cheri_yield(@result_tab_pane,&block) if block
407
+ @result_tab_pane
384
408
  end
385
409
 
386
410
  def main_panel(&block)
@@ -469,32 +493,51 @@ class Main
469
493
  tabs = main_tab_pane
470
494
  unless tabs.include?(view)
471
495
  set_view_viewer(view,viewer)
472
- instance = viewer.instance || :global
496
+ if instance = viewer.instance
497
+ tab_group = instance.__id__
498
+ else
499
+ tab_group = :global
500
+ end
473
501
  ntype = viewer.type.type
474
502
  tab_type = TypeTabMap[ntype] || ntype
475
- current_viewer = @main_tabs[instance][tab_type]
476
- if current_viewer && (ix = tabs.index(current_viewer.view))
477
- tabs[ix] = view
478
- if Java6 && (tab = viewer.tab)
479
- tabs[ix,:tab] = tab
480
- else
481
- tabs[ix,:title] = viewer.title_tab
482
- tabs[ix,:icon] = viewer.icon_tab
483
- end
503
+ current_viewer = @main_tabs[tab_group][tab_type]
504
+ if current_viewer && (index = tabs.index(current_viewer.view))
505
+ replace_view_tab(tabs,view,viewer,index)
484
506
  else
485
- cheri_yield tabs do
486
- if Java6 && (tab = viewer.tab)
487
- cherify(view, :tab => tab)
488
- else
489
- cherify(view, :title => viewer.title_tab, :icon => viewer.icon_tab)
490
- end
491
- end
507
+ add_view_tab(tabs,view,viewer)
492
508
  end
493
- @main_tabs[instance][tab_type] = viewer
509
+ @main_tabs[tab_group][tab_type] = viewer
494
510
  end
495
511
  tabs.set_selected_component(view)
496
512
  end
497
513
 
514
+ def add_view_tab(tabs,view,viewer)
515
+ cheri_yield tabs do
516
+ cherify(view, :tab => viewer.tab, :title => viewer.title_tab, :icon => viewer.icon_tab)
517
+ end
518
+ if tabs == @main_tab_pane
519
+ index = tabs.index(view)
520
+ @main_tab_history[index] = TabHistory.new(viewer)
521
+ end
522
+ end
523
+
524
+ def replace_view_tab(tabs,view,viewer,index)
525
+ tabs[index] = view
526
+ if Java6 && (tab = viewer.tab)
527
+ tabs[index,:tab] = tab
528
+ else
529
+ tabs[index,:title] = viewer.title_tab
530
+ tabs[index,:icon] = viewer.icon_tab
531
+ end
532
+ if tabs == @main_tab_pane
533
+ if hist = @main_tab_history[index]
534
+ hist << viewer
535
+ else
536
+ @main_tab_history[index] = TabHistory.new(viewer)
537
+ end
538
+ end
539
+ end
540
+
498
541
  def prepare_for_node_expansion(node)
499
542
  unless node.child_count > 0
500
543
  vwr = node.user_object
@@ -533,6 +576,36 @@ class Main
533
576
  view.get_client_property(:viewer)
534
577
  end
535
578
 
579
+ def next_view
580
+ tabs = main_tab_pane
581
+ if (oldvwr = tabs.active_viewer) &&
582
+ (ix = tabs.index(oldvwr.view)) &&
583
+ (hist = @main_tab_history[ix]) &&
584
+ (newvwr = hist.next!)
585
+ replace_view(tabs,ix,newvwr)
586
+ end
587
+ end
588
+
589
+ def prev_view
590
+ tabs = main_tab_pane
591
+ if (oldvwr = tabs.active_viewer) &&
592
+ (ix = tabs.index(oldvwr.view)) &&
593
+ (hist = @main_tab_history[ix]) &&
594
+ (newvwr = hist.prev!)
595
+ replace_view(tabs,ix,newvwr)
596
+ end
597
+ end
598
+
599
+ def replace_view(tabs,index,viewer)
600
+ tabs[index] = viewer.view
601
+ if Java6 && (tab = viewer.tab)
602
+ tabs[index,:tab] = tab
603
+ else
604
+ tabs[index,:title] = viewer.title_tab
605
+ tabs[index,:icon] = viewer.icon_tab
606
+ end
607
+ end
608
+
536
609
  def refresh_active_view
537
610
  if (viewer = main_tab_pane.active_viewer)
538
611
  viewer.refresh if viewer.respond_to?(:refresh)
@@ -546,29 +619,39 @@ class Main
546
619
  end
547
620
 
548
621
  def close_active_search_view
549
- if (viewer = search_tab_pane.active_viewer)
550
- close_search_view(viewer)
622
+ if (viewer = result_tab_pane.active_viewer)
623
+ close_results_view(viewer)
551
624
  end
552
625
  end
553
626
 
554
627
  def close_view(viewer)
555
628
  view = viewer.view
556
- main_tab_pane.remove(view)
557
- instance = viewer.instance || :global
629
+ index = (tabs = main_tab_pane).index(view)
630
+ tabs.remove(view)
631
+ @main_tab_history.delete_at(index)
632
+ if instance = viewer.instance
633
+ tab_group = instance.__id__
634
+ else
635
+ tab_group = :global
636
+ end
558
637
  ntype = viewer.type.type
559
638
  tab_type = TypeTabMap[ntype] || ntype
560
- @main_tabs[instance].delete(tab_type) if @main_tabs[instance][tab_type] == viewer
561
- @main_tabs[instance].delete(viewer.__id__)
639
+ @main_tabs[tab_group].delete(tab_type) if @main_tabs[tab_group][tab_type] == viewer
640
+ @main_tabs[tab_group].delete(viewer.__id__)
562
641
  end
563
642
 
564
- def close_search_view(viewer)
643
+ def close_results_view(viewer)
565
644
  view = viewer.view
566
- search_tab_pane.remove(view)
567
- instance = viewer.instance || :global
645
+ result_tab_pane.remove(view)
646
+ if instance = viewer.instance
647
+ tab_group = instance.__id__
648
+ else
649
+ tab_group = :global
650
+ end
568
651
  ntype = viewer.type.type
569
652
  tab_type = TypeTabMap[ntype] || ntype
570
- @search_tabs[instance].delete(tab_type) if @search_tabs[instance][tab_type] == viewer
571
- @search_tabs[instance].delete(viewer.__id__)
653
+ @result_tabs[tab_group].delete(tab_type) if @result_tabs[tab_group][tab_type] == viewer
654
+ @result_tabs[tab_group].delete(viewer.__id__)
572
655
  end
573
656
 
574
657
  def close_views_for_instance(inst)
@@ -577,41 +660,39 @@ class Main
577
660
  views.each do |view|
578
661
  close_view(view_viewer(view))
579
662
  end
580
- views = search_tab_pane.select {|view| view_viewer(view).instance == inst}
663
+ views = result_tab_pane.select {|view| view_viewer(view).instance == inst}
581
664
  views.each do |view|
582
- close_search_view(view_viewer(view))
665
+ close_results_view(view_viewer(view))
583
666
  end
584
667
  end
585
668
 
586
- def open_search_view(viewer)
669
+ def open_results_view(viewer)
587
670
  view = viewer.view
588
- tabs = search_tab_pane
671
+ tabs = result_tab_pane
589
672
  set_view_viewer(view,viewer)
590
- instance = viewer.instance || :global
673
+ if instance = viewer.instance
674
+ tab_group = instance.__id__
675
+ else
676
+ tab_group = :global
677
+ end
591
678
  ntype = viewer.type.type
592
679
  tab_type = TypeTabMap[ntype] || ntype
593
- cheri_yield tabs do
594
- if Java6 && (tab = viewer.tab)
595
- cherify(view, :tab => tab)
596
- else
597
- cherify(view, :title => viewer.title_tab, :icon => viewer.icon_tab)
598
- end
599
- end
600
- @search_tabs[instance][tab_type] = viewer
680
+ add_view_tab(tabs,view,viewer)
681
+ @result_tabs[tab_group][tab_type] = viewer
601
682
  tabs.set_selected_component(view)
602
683
  show_search_results
603
684
  end
604
685
 
605
686
  def show_search_results
606
- @search_tab_pane.visible = true
607
- @search_results_select.selected = true
687
+ @result_tab_pane.visible = true
688
+ @results_select.selected = true
608
689
  adjust_right_splitter
609
690
  end
610
691
 
611
692
  def add_instance(instance)
612
693
  @instances[instance.address] = instance
613
- @main_tabs[instance] = {}
614
- @search_tabs[instance] = {}
694
+ @main_tabs[instance.__id__] = {}
695
+ @result_tabs[instance.__id__] = {}
615
696
  @instance_listeners.each do |lst|
616
697
  lst.instance_added(instance)
617
698
  end
@@ -621,8 +702,8 @@ class Main
621
702
  close_views_for_instance(inst)
622
703
  main_tree_model.remove_node_from_parent(inst.tree_node) if inst.tree_node
623
704
  @instances.delete(inst.address)
624
- @main_tabs.delete(inst)
625
- @search_tabs.delete(inst)
705
+ @main_tabs.delete(inst.__id__)
706
+ @result_tabs.delete(inst.__id__)
626
707
  @instance_listeners.each do |lst|
627
708
  lst.instance_removed(inst)
628
709
  end
@@ -684,64 +765,137 @@ class Main
684
765
  @connection_dialog ||= ConnectionDialog.new(self)
685
766
  end
686
767
 
687
- def new_search(instance,clazz,var,value)
768
+ def new_search(instance,clazz,var,value,gc=nil)
688
769
  raise Cheri.type_error(clazz,RubyInstance) unless RubyInstance === instance
689
770
  raise ArgumentError, "invalid class name #{clazz}" unless clazz =~ /^([A-Z])((\w|::[A-Z])*)$/
690
771
  raise ArgumentError, "invalid variable name #{var}" if var && var !~ /^([A-Za-z_])(\w*)$/
691
- if var
692
- var = ('@' + var).to_sym rescue nil
693
- if value
694
- if value =~ /^(\/)(.*)(\/)$/
695
- unless (val = Regexp.new($2) rescue nil)
696
- JOptionPane.show_message_dialog(@main_frame,"Invalid regular expression #{value}")
697
- return
698
- end
699
- else
700
- val = value
772
+ var = ('@' + var).to_sym rescue nil if var
773
+ if value
774
+ if value =~ /^(\/)(.*)(\/)$/
775
+ unless (val = Regexp.new($2) rescue nil)
776
+ JOptionPane.show_message_dialog(@main_frame,"Invalid regular expression #{value}")
777
+ return
701
778
  end
702
779
  else
703
- val = ''
780
+ val = value
704
781
  end
782
+ end
783
+ if var || value
705
784
  nv = Cheri::Explorer::SearchNameValue.new(var,val)
706
785
  args = Cheri::Explorer::SearchArgs.new(clazz,[nv])
707
786
  else
708
787
  args = Cheri::Explorer::SearchArgs.new(clazz)
709
788
  end
710
- res = instance.proxy.find(args)
789
+ args.gc = true if gc
790
+ @last_search = [instance,args]
711
791
  if (res = instance.proxy.find(args))
712
792
  results = Cheri::Explorer::SearchResults.new(args,res)
713
793
  vwr = viewer(:results).new(NodeTypes[:results],self,instance,results)
714
- open_search_view(vwr)
794
+ open_results_view(vwr)
715
795
  end
716
796
  end
717
797
 
718
- def new_find(instance,id)
719
- if rec = instance.proxy.object(id)
720
- ntv = case rec.clazz
721
- when 'Class' : NodeTypeValue.new(Class,rec.value,rec)
722
- when 'Module' : NodeTypeValue.new(Module,rec.value,rec)
723
- else NodeTypeValue.new(:object,rec.clazz,rec)
724
- end
725
- if (clazz = viewer(ntv.type,ntv.subtype))
726
- vwr = clazz.new(ntv,self,instance,ntv.value)
727
- view = vwr.view
728
- set_view_viewer(view,vwr)
729
- tabs = main_tab_pane
730
- cheri_yield tabs do
731
- if Java6 && (tab = vwr.tab)
732
- cherify(view, :tab => tab)
733
- else
734
- cherify(view, :title => vwr.title_tab, :icon => vwr.icon_tab)
735
- end
736
- end
737
- @main_tabs[instance][vwr.__id__] = vwr
738
- tabs.set_selected_component(view)
798
+ def repeat_search
799
+ if (last = @last_search)
800
+ instance = last[0]
801
+ args = last[1]
802
+ if (res = instance.proxy.find(args))
803
+ results = Cheri::Explorer::SearchResults.new(args,res)
804
+ vwr = viewer(:results).new(NodeTypes[:results],self,instance,results)
805
+ open_results_view(vwr)
806
+ end
807
+ end
808
+ end
809
+
810
+ # def new_find(instance,id,new_tab=nil)
811
+ # if rec = instance.proxy.object(id)
812
+ # ntv = case rec.clazz
813
+ # when 'Class' : NodeTypeValue.new(Class,rec.value,rec)
814
+ # when 'Module' : NodeTypeValue.new(Module,rec.value,rec)
815
+ # else NodeTypeValue.new(:object,rec.clazz,rec)
816
+ # end
817
+ # if (clazz = viewer(ntv.type,ntv.subtype))
818
+ # vwr = clazz.new(ntv,self,instance,ntv.value)
819
+ # view = vwr.view
820
+ # set_view_viewer(view,vwr)
821
+ # tabs = main_tab_pane
822
+ # add_view_tab(tabs,view,vwr)
823
+ # @main_tabs[instance.__id__][vwr.__id__] = vwr
824
+ # tabs.set_selected_component(view)
825
+ # else
826
+ # JOptionPane.show_message_dialog(@main_frame,"Unable to display object #{id} (no viewer)")
827
+ # end
828
+ # else
829
+ # JOptionPane.show_message_dialog(@main_frame,"Unable to retrieve object #{id} (garbage-collected?)")
830
+ # end
831
+ # end
832
+ #
833
+ def show_linked_object(curvwr,id,new_tab=nil)
834
+ instance = curvwr.instance
835
+ unless rec = instance.proxy.object(id)
836
+ JOptionPane.show_message_dialog(@main_frame,"Unable to retrieve object #{id} (garbage-collected?)")
837
+ return
838
+ end
839
+ ntv = case rec.clazz
840
+ when 'Class' : NodeTypeValue.new(Class,rec.value,rec)
841
+ when 'Module' : NodeTypeValue.new(Module,rec.value,rec)
842
+ else NodeTypeValue.new(:object,rec.clazz,rec)
843
+ end
844
+ unless clazz = viewer(ntv.type,ntv.subtype)
845
+ JOptionPane.show_message_dialog(@main_frame,"Unable to display object #{id} (no viewer)")
846
+ end
847
+ vwr = clazz.new(ntv,self,instance,ntv.value)
848
+ view = vwr.view
849
+ set_view_viewer(view,vwr)
850
+ tabs = main_tab_pane
851
+ if new_tab
852
+ add_view_tab(tabs,view,vwr)
853
+ @main_tabs[instance.__id__][vwr.__id__] = vwr
854
+ else
855
+ ntype = vwr.type.type
856
+ tab_type = TypeTabMap[ntype] || ntype
857
+ current_viewer = @main_tabs[instance.__id__][tab_type]
858
+ if current_viewer && (index = tabs.index(current_viewer.view))
859
+ replace_view_tab(tabs,view,vwr,index)
739
860
  else
740
- JOptionPane.show_message_dialog(@main_frame,"Unable to display object #{id}")
861
+ add_view_tab(tabs,view,vwr)
741
862
  end
863
+ @main_tabs[instance.__id__][tab_type] = vwr
864
+ end
865
+ tabs.set_selected_component(view)
866
+ end
867
+
868
+ def show_result_object(resvwr,id,new_tab=nil)
869
+ instance = resvwr.instance
870
+ unless rec = instance.proxy.object(id)
871
+ JOptionPane.show_message_dialog(@main_frame,"Unable to retrieve object #{id} (garbage-collected?)")
872
+ return
873
+ end
874
+ ntv = case rec.clazz
875
+ when 'Class' : NodeTypeValue.new(Class,rec.value,rec)
876
+ when 'Module' : NodeTypeValue.new(Module,rec.value,rec)
877
+ else NodeTypeValue.new(:object,rec.clazz,rec)
878
+ end
879
+ unless clazz = viewer(ntv.type,ntv.subtype)
880
+ JOptionPane.show_message_dialog(@main_frame,"Unable to display object #{id} (no viewer)")
881
+ end
882
+ vwr = clazz.new(ntv,self,instance,ntv.value)
883
+ view = vwr.view
884
+ set_view_viewer(view,vwr)
885
+ tabs = main_tab_pane
886
+ if new_tab
887
+ add_view_tab(tabs,view,vwr)
888
+ @main_tabs[instance.__id__][vwr.__id__] = vwr
742
889
  else
743
- JOptionPane.show_message_dialog(@main_frame,"Unable to retrieve object #{id}")
890
+ current_viewer = @main_tabs[instance.__id__][resvwr.__id__]
891
+ if current_viewer && (index = tabs.index(current_viewer.view))
892
+ replace_view_tab(tabs,view,vwr,index)
893
+ else
894
+ add_view_tab(tabs,view,vwr)
895
+ end
896
+ @main_tabs[instance.__id__][resvwr.__id__] = vwr
744
897
  end
898
+ tabs.set_selected_component(view)
745
899
  end
746
900
 
747
901
  def simple_value(instance,id)
@@ -898,6 +1052,45 @@ module TabbedPaneMethods
898
1052
  end
899
1053
  end #TabbedPaneMethods
900
1054
 
1055
+ class TabHistory
1056
+ def initialize(viewer)
1057
+ @h = [viewer]
1058
+ @c = 1
1059
+ end
1060
+ def <<(viewer)
1061
+ if (len = @h.length) > @c
1062
+ @h = @h[0,@c]
1063
+ end
1064
+ @h << viewer
1065
+ @c = @h.length
1066
+ end
1067
+ def curr
1068
+ @h[@c-1]
1069
+ end
1070
+ def next
1071
+ @h[@c]
1072
+ end
1073
+ def prev
1074
+ if @c >= 2
1075
+ @h[@c-2]
1076
+ end
1077
+ end
1078
+ def next!
1079
+ if @c < @h.length
1080
+ v = @h[@c]
1081
+ @c += 1
1082
+ v
1083
+ end
1084
+ end
1085
+ def prev!
1086
+ if @c > 1
1087
+ @c -= 1
1088
+ @h[@c-1]
1089
+ end
1090
+ end
1091
+ end #TabHistory
1092
+
1093
+
901
1094
  # TODO: may want JComponent version that uses get/put client property?
902
1095
  # TODO: had to do this, see note at set_view_viewer
903
1096
  #module ComponentViewMethods
@@ -436,6 +436,11 @@ module NavViewerConstants
436
436
  IFont = Font.new('Monospaced',Font::BOLD,14)
437
437
  CFont = Font.new('Dialog',Font::PLAIN,14)
438
438
  ResFont = Font.new('Monospaced',Font::PLAIN,12)
439
+ MouseEvent = ::Java::JavaAwtEvent::MouseEvent
440
+ BUTTON1 = MouseEvent::BUTTON1
441
+ BUTTON2 = MouseEvent::BUTTON2
442
+ BUTTON3 = MouseEvent::BUTTON3
443
+ SHIFT = MouseEvent::SHIFT_DOWN_MASK
439
444
  HdrName = 'Name'.freeze
440
445
  HdrVarName = 'Variable name'.freeze
441
446
  HdrType = 'Type'.freeze
@@ -566,15 +571,15 @@ module NavViewer
566
571
  set_font col.dfont || VFont
567
572
  foreground col.dfg if col.dfg
568
573
  if (click_val = col.clk)
569
- on_mouse_clicked do
570
- mouse_clicked(click_val)
571
- end
572
574
  on_mouse_entered do |e|
573
575
  e.source.parent.background = HColor
574
576
  end
575
577
  on_mouse_exited do |e|
576
578
  e.source.parent.background = VColor
577
579
  end
580
+ on_mouse_clicked {|e| mouse_clicked(e,click_val) }
581
+ on_mouse_pressed {|e| mouse_action(e,click_val) }
582
+ on_mouse_released {|e| mouse_action(e,click_val) }
578
583
  end
579
584
  end
580
585
  end
@@ -599,7 +604,10 @@ module NavViewer
599
604
  y_glue if glue
600
605
  end
601
606
 
602
- def mouse_clicked(val)
607
+ def mouse_clicked(e,val=nil)
608
+ end
609
+
610
+ def mouse_action(e,val=nil)
603
611
  end
604
612
 
605
613
  end
@@ -550,29 +550,42 @@ end
550
550
  class ResultListViewer < Viewer
551
551
  include ValueViewerInterface
552
552
  include NavViewerConstants
553
-
553
+ #:stopdoc:
554
+ Empty = '(empty)'
555
+ #:startdoc:
556
+
554
557
  class ResultListItem
555
558
  def initialize(id,value)
556
559
  @i = id
557
- @v = value || 'Unavailable'
560
+ @v = value
558
561
  end
559
562
  def id
560
563
  @i
561
564
  end
562
- def value
565
+ def v
563
566
  @v
564
567
  end
568
+ alias_method :value,:v
569
+ def ==(other)
570
+ @v == other.v
571
+ end
572
+ def eql?(other)
573
+ @v.eql?(other.v)
574
+ end
575
+ def <=>(other)
576
+ @v <=> other.v
577
+ end
565
578
  def to_s
566
579
  @v
567
580
  end
568
581
  alias_method :to_str, :to_s
569
- #alias_method :toString, :to_s
570
- end
571
-
572
- def item_value(id)
573
- @main.simple_value(@instance,id)
574
- end
582
+
583
+ end #ResultListItem
575
584
 
585
+ # def item_value(id)
586
+ # @main.simple_value(@instance,id)
587
+ # end
588
+ #
576
589
  def initialize(*r,&k)
577
590
  super
578
591
  create_object_list
@@ -581,19 +594,16 @@ class ResultListViewer < Viewer
581
594
  def create_object_list
582
595
  res = @value.results
583
596
  proxy = @instance.proxy
584
- len = res.length;
585
- list = @obj_list = ::Java::JavaLang::Object[len].new
586
- len.times do |i|
597
+ items = []
598
+ res.length.times do |i|
587
599
  id = res[i]
588
- val = nil
589
- begin
590
- val = proxy.simple_value(id)
591
- rescue
592
- val = 'Unavailable'
600
+ if (val = proxy.simple_value(id) rescue nil)
601
+ val.strip!
602
+ val = Empty if val.empty?
603
+ items << ResultListItem.new(id,val)
593
604
  end
594
- list[i] = ResultListItem.new(id,val)
595
605
  end
596
- list
606
+ @obj_list = items.sort.to_java
597
607
  end
598
608
 
599
609
  def title
@@ -647,8 +657,13 @@ class ResultListViewer < Viewer
647
657
  name_value_row('Class/Module',@value.args.clazz,CFont)
648
658
  if (vars = @value.args.vars) && !vars.empty?
649
659
  vname = vars[0].name.to_s
650
- vval = vars[0].value || ''
651
- vval = vval.inspect if Regexp === vval
660
+ vname = ' ' if vname.empty?
661
+ vval = vars[0].value || ' '
662
+ if Regexp === vval
663
+ vval = vval.inspect
664
+ elsif String === vval
665
+ vval = ' ' if vval.empty?
666
+ end
652
667
  name_value_row('Variable',vname)
653
668
  name_value_row('Value',vval)
654
669
  end
@@ -682,12 +697,64 @@ class ResultListViewer < Viewer
682
697
  super
683
698
  end
684
699
 
685
- def item_selected
700
+ def set_selection
686
701
  if (ix = @list.selected_index) >= 0
687
- @main.new_find(@instance,@value.results[ix])
702
+ @pending = ix
703
+ end
704
+ end
705
+ def send_selection(new_tab=nil)
706
+ if ix = @pending
707
+ @pending = nil
708
+ @main.show_result_object(self,@obj_list[ix].id,new_tab)
709
+ end
710
+ end
711
+ def list_clicked(e)
712
+ list = @list
713
+ point = e.point
714
+ if BUTTON1 == e.button &&
715
+ (ix = list.location_to_index(point)) >= 0 &&
716
+ list.get_cell_bounds(ix,ix).contains(point)
717
+ send_selection((e.modifiers_ex & SHIFT) == SHIFT)
718
+ end
719
+ end
720
+
721
+ def list_keyed(e)
722
+ if @pending && e.action_key?
723
+ send_selection((e.modifiers_ex & SHIFT) == SHIFT)
724
+ end
725
+ end
726
+
727
+ def mouse_action(e)
728
+ if e.popup_trigger?
729
+ list = @list
730
+ point = e.point
731
+ if (ix = list.location_to_index(point)) >= 0 &&
732
+ list.get_cell_bounds(ix,ix).contains(point)
733
+ @menu_pending = ix
734
+ selection_popup.show(e.component,e.x,e.y)
735
+ end
688
736
  end
689
737
  end
690
738
 
739
+ def menu_selection(new_tab)
740
+ if ix = @menu_pending
741
+ @menu_pending = nil
742
+ @list.selected_index = ix
743
+ send_selection(new_tab)
744
+ end
745
+ end
746
+
747
+ def selection_popup
748
+ @popup ||= popup_menu 'Open item in ... ' do
749
+ menu_item 'Open in new tab' do
750
+ on_click {menu_selection true}
751
+ end
752
+ menu_item 'Open in default tab' do
753
+ on_click {menu_selection false}
754
+ end
755
+ end
756
+ end
757
+
691
758
  def result_list
692
759
  @list = list @obj_list do
693
760
  align :LEFT
@@ -696,9 +763,14 @@ class ResultListViewer < Viewer
696
763
  selection_mode :SINGLE_SELECTION
697
764
  on_value_changed do |e|
698
765
  unless e.value_is_adjusting
699
- item_selected
766
+ set_selection
700
767
  end
701
- end
768
+ end
769
+ on_mouse_clicked {|e| list_clicked e}
770
+ on_mouse_pressed {|e| mouse_action e}
771
+ on_mouse_released {|e| mouse_action e}
772
+ on_key_pressed {|e| list_keyed e}
773
+ on_key_released {|e| list_keyed e}
702
774
  end
703
775
  end
704
776
 
@@ -744,7 +816,7 @@ class ResultListViewer < Viewer
744
816
  end
745
817
 
746
818
  def close_view
747
- @main.close_search_view(self)
819
+ @main.close_results_view(self)
748
820
  end
749
821
  end
750
822
 
@@ -818,8 +890,37 @@ class NavObjectViewer
818
890
  end
819
891
  end
820
892
 
821
- def mouse_clicked(val)
822
- @main.new_find(@instance,val)
893
+ def send_selection(id,new_tab=nil)
894
+ @main.show_linked_object(self,id,new_tab)
895
+ end
896
+
897
+ def mouse_clicked(e,id)
898
+ send_selection(id,(e.modifiers_ex & SHIFT) == SHIFT)
899
+ end
900
+
901
+ def mouse_action(e,id)
902
+ if e.popup_trigger?
903
+ @menu_pending = id
904
+ selection_popup.show(e.component,e.x,e.y)
905
+ end
906
+ end
907
+
908
+ def menu_selection(new_tab)
909
+ if id = @menu_pending
910
+ @menu_pending = nil
911
+ send_selection(id,new_tab)
912
+ end
913
+ end
914
+
915
+ def selection_popup
916
+ @popup ||= popup_menu 'Open item in ... ' do
917
+ menu_item 'Open in new tab' do
918
+ on_click {menu_selection true}
919
+ end
920
+ menu_item 'Open in default tab' do
921
+ on_click {menu_selection false}
922
+ end
923
+ end
823
924
  end
824
925
 
825
926
 
@@ -1021,9 +1122,39 @@ class NavModuleViewer
1021
1122
  @children
1022
1123
  end
1023
1124
 
1024
- def mouse_clicked(val)
1025
- @main.new_find(@instance,val)
1125
+ def send_selection(id,new_tab=nil)
1126
+ @main.show_linked_object(self,id,new_tab)
1026
1127
  end
1128
+
1129
+ def mouse_clicked(e,id)
1130
+ send_selection(id,(e.modifiers_ex & SHIFT) == SHIFT)
1131
+ end
1132
+
1133
+ def mouse_action(e,id)
1134
+ if e.popup_trigger?
1135
+ @menu_pending = id
1136
+ selection_popup.show(e.component,e.x,e.y)
1137
+ end
1138
+ end
1139
+
1140
+ def menu_selection(new_tab)
1141
+ if id = @menu_pending
1142
+ @menu_pending = nil
1143
+ send_selection(id,new_tab)
1144
+ end
1145
+ end
1146
+
1147
+ def selection_popup
1148
+ @popup ||= popup_menu 'Open item in ... ' do
1149
+ menu_item 'Open in new tab' do
1150
+ on_click {menu_selection true}
1151
+ end
1152
+ menu_item 'Open in default tab' do
1153
+ on_click {menu_selection false}
1154
+ end
1155
+ end
1156
+ end
1157
+
1027
1158
 
1028
1159
  def view(&block)
1029
1160
  @view ||= scroll_pane do
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: cheri
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.4
7
- date: 2007-06-10 00:00:00 -07:00
6
+ version: 0.0.5
7
+ date: 2007-06-11 00:00:00 -07:00
8
8
  summary: Cheri Builder Platform
9
9
  require_paths:
10
10
  - lib
@@ -75,6 +75,7 @@ files:
75
75
  - lib/cheri/explorer.rb
76
76
  - lib/cheri/html.rb
77
77
  - lib/cheri/image
78
+ - lib/cheri/image/Back24.gif
78
79
  - lib/cheri/image/cheri_icon_16x16.png
79
80
  - lib/cheri/image/cheri_icon_24x24.png
80
81
  - lib/cheri/image/cheri_logo_medium.png
@@ -90,6 +91,7 @@ files:
90
91
  - lib/cheri/image/Delete24.gif
91
92
  - lib/cheri/image/Find24.gif
92
93
  - lib/cheri/image/FindAgain24.gif
94
+ - lib/cheri/image/Forward24.gif
93
95
  - lib/cheri/image/jruby_14x16.png
94
96
  - lib/cheri/image/jruby_logo.png
95
97
  - lib/cheri/image/mod_tree.png