Class: TreeViewer

Inherits:
Object
  • Object
show all
Includes:
SvnColours
Defined in:
lib/hilfer/tree_viewer.rb

Overview

This is the tree viewer object. It contains a GtkTreeView and references an editor object. It also contains a HilferItem which is the root node of the tree, but it’s never displayed

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SvnColours

#compute_colours, #context, #status_colours

Constructor Details

#initialize(path, editor, parent_window, location) ⇒ TreeViewer

Can pass in $options => some_terminal to use different terminal types. See GnomeTerminal for an example



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/hilfer/tree_viewer.rb', line 62

def initialize( path, editor, parent_window, location )
  @terminal = $options[:terminal]
  @parent_window = parent_window
  @location = location
  @location.activates_default = false

  # these need to be window-local
  @expecting_synchronize_path = false
  @auto_synchronize_path = $options[:auto_sync]

  path = Pathname.new( path )
  path = path.parent while !path.directory?

  @root_item = HilferItem.new( '', path.to_s )
  # TODO this shuold be in set_root or something like that
  @location.text = @root_item.path
  @location.select_region(0,0)
  @location.position = -1
  @hilfer_items = {}

  # locators are things that provide a set of shortcut keys
  # to jump to specific directories, files, or related locations
  @locators = []
  @locators << StandardLocator.new( self )
  @locators << RailsLocator.new( self ) if HAS_RAILS_LOCATOR

  # pre-populate model from filesystem, only 1 level deep
  #model = Gtk::TreeStore.new( HilferItem )
  model = HilferModel.new( HilferItem )
  populate( model, @root_item, nil )

  # Create view
  @view = Gtk::TreeView.new( model )
  @view.headers_visible = false
  @view.selection.mode = Gtk::SELECTION_MULTIPLE

  # register with the editor, and remember it
  editor.register_view( self )
  @editor = editor

  # handle key presses
  init_keys

  # handle enter for location bar
  @location.signal_connect( 'activate' ) do |widget|
    new_path = File.expand_path( widget.text )
    if File.exists? new_path
      go_into( new_path )
    else
      dialog = Gtk::MessageDialog.new(
        @window,
        Gtk::Dialog::Flags::MODAL,
        Gtk::MessageDialog::Type::INFO,
        Gtk::MessageDialog::BUTTONS_OK,
        "Directory #{widget.text} does not exist"
      )
      dialog.run
      dialog.destroy
    end
  end

  @location.signal_connect( 'focus-out-event' ) do |widget,event|
    #make sure everything is unselected, and put the cursor at the end
    widget.select_region(0,0)
    widget.position = -1
  end

  # handle double-clicks so they don't activate the
  # cell editing
  @view.signal_connect( 'button-press-event' ) do
    |view, event|
    if event.button == 1 && event.event_type == Gdk::Event::BUTTON2_PRESS
      path, column, cell_x, cell_y = view.get_path( *event.coords )
      if iter = view.model.get_iter( path )
        open_action( [ iter[0] ] )
        true
      end
    end
  end

  # handle collapse and expand are cached in HilferItems
  @view.signal_connect( 'row-collapsed' ) do
    |view, iter, path|
    iter[0].status = :collapsed
    true
  end

  @view.signal_connect( 'row-expanded' ) do
    |view, iter, path|
    puts "expanding row: #{iter[0].path}, #{iter[0].populated?}" if $options[:debug]
    iter[0].status = :expanded
    child = iter.first_child
    loop do
      puts "expanded child: #{child[0].path}, #{child[0].populated?}" if $options[:debug]
      populate( @view.model, child[0], child ) unless child[0].populated?
      break if !child.next!
    end

    # remember expanded status
    setstatus
    true
  end

  # add widgets for the columns and cells
  init_renderers

  # all columns must be fixed for this to work
  @view.fixed_height_mode = true

  init_searchable

  # Allow drag and drop reordering of rows
  # would need to be hooked into fs move, and maybe
  # the refresh so that items aren't put back in their original
  # places. That's hard.
  #@view.set_reorderable( true)

  # set up refresh thread
  #~ Thread.new( self ) do |arg|
    #~ loop do
      #~ sleep 2
      #~ arg.refresh
      #~ print "refreshed\n"
    #~ end
  #~ end
end

Instance Attribute Details

#editorObject (readonly)

Returns the value of attribute editor.



57
58
59
# File 'lib/hilfer/tree_viewer.rb', line 57

def editor
  @editor
end

#root_itemObject (readonly)

Returns the value of attribute root_item.



57
58
59
# File 'lib/hilfer/tree_viewer.rb', line 57

def root_item
  @root_item
end

#viewObject (readonly)

Returns the value of attribute view.



57
58
59
# File 'lib/hilfer/tree_viewer.rb', line 57

def view
  @view
end

Instance Method Details

#confirm_delete_files(iters) ⇒ Object

display a dialog and delete the files if the response was yes. Unless the don’t ask for file deletion flag is switched off



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/hilfer/tree_viewer.rb', line 287

def confirm_delete_files( iters )
  msg = "Are you sure you want to delete\n"
  iters.each { |it| msg += it[0].path + "\n" }

  confirm = Gtk::MessageDialog.new(
    @window,
    Gtk::Dialog::Flags::MODAL,
    Gtk::MessageDialog::Type::QUESTION,
    Gtk::MessageDialog::BUTTONS_YES_NO,
    msg
  )
  confirm.default_response = Gtk::Dialog::RESPONSE_YES
  confirm.signal_connect( 'key-press-event' ) do
    |widget,event|
    case event.hardware_keycode
      when 57 # n pressed
        confirm.response( Gtk::Dialog::RESPONSE_NO )
        true
      when 29 # y pressed
        confirm.response( Gtk::Dialog::RESPONSE_YES )
        true
    end
  end

  # actually delete the files
  confirm.run do |response|
    delete_files( iters ) if response == Gtk::Dialog::RESPONSE_YES
    confirm.destroy
  end
end

#delete_files(iters) ⇒ Object



318
319
320
321
322
323
324
325
326
327
# File 'lib/hilfer/tree_viewer.rb', line 318

def delete_files( iters )
  iters.each do |it|
    begin
      File.delete it[0].path
      @view.model.remove(it)
    rescue
      print "Can't delete #{it[0].path}"
    end
  end
end

#do_compute_colours(item) ⇒ Object



781
782
783
784
785
786
787
# File 'lib/hilfer/tree_viewer.rb', line 781

def do_compute_colours( item )
  if respond_to? :compute_colours
    compute_colours( item.path )
  else
    {}
  end
end

#expand_dir(widget, path, iter) ⇒ Object



606
607
608
609
610
611
612
# File 'lib/hilfer/tree_viewer.rb', line 606

def expand_dir( widget, path, iter )
  # make sure all directories in subtree are populated
  populate( @view.model, iter[0], iter, 100 )

  # expand row, with children
  widget.expand_row( path, true )
end

#expand_parents_of(path) ⇒ Object



614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
# File 'lib/hilfer/tree_viewer.rb', line 614

def expand_parents_of( path )
  cur = path.clone
  cur.up!
  paths = []
  while !@view.row_expanded?( cur ) && cur.depth > 0
    paths << cur.clone
    cur.up!
  end

  # now open the necessary paths from the top down
  # false is don't open all children
  paths.reverse.each do |x|
    @view.expand_row( x, false )
    @view.selection.unselect_path( x )
  end
end

#fetch_hilfer_item(item_name, item_path) ⇒ Object

fetch or create the HilferItem. Attemps a lookup from the item_path first if not found creates it from the item_name and item_path



770
771
772
773
774
775
776
777
778
779
# File 'lib/hilfer/tree_viewer.rb', line 770

def fetch_hilfer_item( item_name, item_path )
  if @hilfer_items.has_key?( item_path )
    @hilfer_items[item_path]
  else
    # create new item, add to column 0
    tmp = HilferItem.new( item_name, item_path )
    @hilfer_items[item_path] = tmp
    tmp
  end
end

#go_into(fs_path) ⇒ Object

Move the displayed tree to the given directory



748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
# File 'lib/hilfer/tree_viewer.rb', line 748

def go_into( fs_path )
  last_select = []
  @view.selection.selected_each do |model, path, iter|
    last_select << path
  end

  last_select = [ Gtk::TreePath.new( '0' ) ] if last_select.empty?

  @view.model.clear
  @hilfer_items.values.each { |x| x.populated = false }
  # this waits forever when called by the refresh thread
  @root_item.path = fs_path
  @root_item.populated = false
  # show location as relative to home
  @location.text = @root_item.path.sub( ENV['HOME'], '~' )
  populate( @view.model, @root_item, nil )
  setstatus
  last_select.each { |x| select_path( x ) }
end

#init_keysObject

handle keypresses TODO use HandlerDefn



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
# File 'lib/hilfer/tree_viewer.rb', line 331

def init_keys
  @view.signal_connect( 'key-press-event' ) do |widget,event|
    puts "event: #{event.inspect}" if $options[:debug]

    retval = true
    case
      # enter - go into directory
      # or open all selected files
      when event.match( /return/i, /enter/i ) && !event.state.control_mask?
        items = []

        # fetch all selected items
        widget.selection.selected_each do |model, path, iter|
          items << model.get_value( iter, 0 )
        end

        # go into if the first item is a directory
        open_action( items )

      # ctrl-enter opens new window with the selected root(s)
      when event.match( /return/i, /enter/i ) && event.state.control_mask?
        widget.selection.selected_each do |model, path, iter|
          new_path =
          if !iter[0].dir?
            # open the directory this file lives in
            # unless we're already in that directory
            iter.parent[0].path unless iter.parent.nil?
          else
            # open this directory
            iter[0].path
          end
          TreeViewerWindow.new( new_path, @editor ) unless new_path.nil?
        end

      # backspace - go up to parent directory
      when event =~ 'BackSpace'
        # go up one directory
        temp = Pathname.new( @root_item.path )
        @root_item.path = temp.parent.realpath.to_s
        go_into( @root_item.path )

      # del on main keyboard or keypad deletes a file
      when event =~ /Delete/
        iters = []
        widget.selection.selected_each do |model, path, iter|
          iters << iter
        end
        confirm_delete_files( iters )

      # ctrl-e and F2 edits the file name
      when ( event.e? && event.state.control_mask? ) || event.f2?
        # make sure all the files are selected
        rows = widget.selection.selected_rows
        rows.each do |path|
          # seems it not necessary to set this
          # @text_renderer.mode = Gtk::CellRendererText::MODE_EDITABLE
          @text_renderer.editable = true
          # true is to start editing
          view.set_cursor( path, view.get_column(0), true )
          # the rest of the work is done in the renderer's handler.
          @text_renderer.editable = false
        end

      # ctrl-d sends some debug/info commands to scite
      when event.d? && event.state.control_mask? && !event.state.shift_mask?
        @editor.dump

      # ctrl-b sends the current selection to the editor
      when event.b? && event.state.control_mask?  && !event.state.shift_mask?
        paths = []
        widget.selection.selected_each do |model, path, iter|
          # note use of single quotes
          paths << model.get_value( iter, 0 ).path
        end
        @editor.insert paths

      # ctrl-c copies current selections as text
      when event.c? && event.state.control_mask? && !event.state.shift_mask?
        paths = []

        # fetch all selected items
        # don't use a join here so we get a trailing newline
        widget.selection.selected_each do |model, path, iter|
          paths << model.get_value( iter, 0 ).path
        end

        Gtk::Clipboard.get( Gdk::Selection::CLIPBOARD ).text = paths.join("\n")

      # ctrl-v selects the files in the clipboard
      when event.v? && event.state.control_mask?  && !event.state.shift_mask?
        text = Gtk::Clipboard.get( Gdk::Selection::CLIPBOARD ).wait_for_text
        paths = text.strip.split( /\s*\n\s*/ )
        location_path = Pathname.new( @root_item.path )
        paths = paths.map do |x|
          # check for path names relative to the current location
          fullpath = location_path + x
          ( fullpath.exist? ? fullpath : x ).to_s
        end
        select_fs_paths( paths )

      # ctrl-n opens new window with same root
      when event.n? && event.state.control_mask?
        TreeViewerWindow.new( @root_item.path, @editor )

      # ctrl-y synchronizes with current editor file
      when event.y? && event.state.control_mask?
        # make sure other windows don't synchronize
        @expecting_synchronize_path = true
        # ask editor for current file and sync
        @editor.synchronize_path

      # alt-y toggles automatic synchronization
      when event.y? && event.state.mod1_mask?
        @auto_synchronize_path = !@auto_synchronize_path

      # ctrl-r refreshes from filesystem
      when event.r? && event.state.control_mask?
        refresh

      # ctrl-t opens a terminal window on the given directories.
      # Uses gnome-terminal and opens directories in tabs
      when event.t? && event.state.control_mask? && !event.state.shift_mask?
        # collect all unique directories
        dirs = []
        widget.selection.selected_each do |model, path, iter|
          dirs << if iter[0].dir?
            iter[0].path
          else
            if iter.parent != nil
              iter.parent[0].path
            else
              @root_item.path
            end
          end
        end
        terminal.launch( dirs )

      # alt-l toggles the location bar
      when event.l? && event.state.mod1_mask?
        @location.no_show_all = true
        @location.visible = !@location.visible?

      # alt-q toggles whether shutdown is automatic or not
      when event.q? && event.state.mod1_mask?
        $options.quit_editor = !$options.quit_editor?

      # ctrl-* on keypad means expand the entire tree
      when event =~ 'KP_Multiply' && event.state.control_mask?
        # 100 levels of directories should be enough...
        populate( @view.model, @root_item, nil, 100 )
        @view.expand_all

      # * on keypad means expand subtree
      when event =~ 'KP_Multiply' && event.state.empty?
        widget.selection.selected_rows.each do |path|
          iter = @view.model.get_iter( path )
          if iter[0].dir?
            expand_dir( widget, path, iter )
          end
        end

      # shift-/ on keypad means collapse the entire tree
      when event =~ 'KP_Divide' && event.state.shift_mask?
        @view.collapse_all

      # ctrl-left means go to parent
      when event =~ /left$/i && event.state.control_mask?
        widget.selection.selected_each do |model, path, iter|
          if iter.parent != nil
            iter.parent[0].last_child_used = path
            select_iter( iter.parent )
          end

          # only do the first one
          break
        end

      # ctrl-right means go to last used path, or first child
      when event.right? && event.state.control_mask?
        widget.selection.selected_each do |model, path, iter|
          if iter[0].dir?
            widget.expand_row( iter.path, false )
            if iter[0].last_child_used != nil
              select_path( iter[0].last_child_used )
            else
              select_iter( iter.first_child )
            end
          end

          # only do the first one
          break
        end

      # ctrl-up means go to previous sibling with children
      when event.up? && event.state.control_mask?
        widget.selection.selected_each do |model, path, iter|
          if iter[0].dir?
            while path.prev!
              if model.get_iter( path ).has_child?
                select_path( path )
                break
              end
            end
          else
            select_iter iter.parent unless iter.parent.nil?
          end
          break
        end

      # ctrl-down means go to next sibling with children
      when event.down? && event.state.control_mask?
        widget.selection.selected_each do |model, path, iter|
          if iter[0].dir?
            while iter.next!
              if iter[0].dir?
                select_iter( iter )
                break
              end
            end
          else
            # go up to parent and then down
            # to parent's following sibling
            temp = iter.parent
            if temp != nil
              temp.next!
              select_iter temp
            end
          end
          # only do the first selection
          break
        end

      # shift-left means select parent
      when event.left? && event.state.shift_mask?
        widget.selection.selected_each do |model, path, iter|
          if iter.parent != nil
            select_children( widget, iter.parent )
          end
        end

      # shift-right means select children
      when event.right? && event.state.shift_mask?
        widget.selection.selected_each do |model, path, iter|
          if iter[0].dir?
            select_children( widget, iter )
          end
        end

      # left means close level(s)
      when event.left?
        widget.selection.selected_each do |model, path, iter|
          widget.collapse_row( path ) if iter[0].dir?
        end

      # right means open level(s)
      when event.right?
        widget.selection.selected_each do
          |model, path, iter|
          # false means don't expand children
          widget.expand_row( path, false )
        end

      else
        # indicate signal not handled
        retval = false
        # pass keypress to all locators
        @locators.each {|x| retval = x.handle_keypress( widget, event ) and retval }
        if $options[:debug] && !retval
          puts "not handled"
        end
    end
    retval
  end
end

#init_renderersObject



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/hilfer/tree_viewer.rb', line 193

def init_renderers
  # The column to display everything in
  column = Gtk::TreeViewColumn.new( "icon and name" )
  column.resizable = false
  column.sizing = Gtk::TreeViewColumn::FIXED

  # display the icon
  pixbuf_renderer = Gtk::CellRendererPixbuf.new
  column.pack_start( pixbuf_renderer, false )
  column.set_cell_data_func( pixbuf_renderer ) do
    |column, renderer, model, iter|
    item = iter[0]

    # figure out which icon to use
    icon =
    if item.dir?
      if renderer.expanded?
        Gtk::Stock::OPEN
      else
        Gtk::Stock::DIRECTORY
      end
    else
      Gtk::Stock::FILE
    end

    # set the icon
    renderer.pixbuf = @view.render_icon( icon, Gtk::IconSize::MENU, 'cell_renderer' )
  end

  # display the file name
  @text_renderer = Gtk::CellRendererText.new
  @text_renderer.ypad = 0
  column.pack_start( @text_renderer, true )
  column.set_cell_data_func( @text_renderer ) do
    |column, renderer, model, iter|
    item = iter[0]
    renderer.text = item.item
    renderer.foreground = item.colour
  end

  # Allow file renames
  @text_renderer.signal_connect("editing-started") do |widget,editable,path|
    editable && editable.signal_connect("editing-done") do |widget|
      # Fetch the HilferItem
      item = @view.model.get_iter(path)[0]

      # make the new file name, in full
      new_path = ( Pathname.new( item.path ).parent + editable.text )

      # rename the file if it's renameable
      if editable.text != item.item && !File.exists?( new_path.to_s )
        # rename the file
        begin
          File.rename( item.path, new_path.to_s )
          item.item = editable.text
          item.path = new_path.to_s
        rescue Exception => e
          print "couldn't rename #{item.path} to #{new_path.to_s}\n"
          print e, "\n"
          e.backtrace.each { | line | print line, "\n" }
        end
      end
      true
    end

    true
  end

  @view.append_column( column )
end

#init_searchableObject

Set the interactive search box



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/hilfer/tree_viewer.rb', line 265

def init_searchable
  # allow tree to be searchable using regular expressions
  @view.search_column = 0
  @view.enable_search = true
  @view.set_search_equal_func do
    # - model: a Gtk::TreeModel
    # - column: a Column number
    # - key: a String
    # - iter: a Gtk::TreeIter
    # - Returns: true to continue, or false to quit(the word is matched).
    |model, column, key, iter|
    begin
      iter[0].item !~ /#{key}/
    rescue
      true
    end
  end
end

#no_synchronize {|@editor| ... } ⇒ Object

called from open_action when we don’t want the auto-centering to do its thing.

Yields:



714
715
716
717
718
719
# File 'lib/hilfer/tree_viewer.rb', line 714

def no_synchronize
  save = @auto_synchronize_path
  @auto_synchronize_path = false
  yield @editor
  @auto_synchronize_path = save
end

#open_action(files) ⇒ Object

called from the keyboard handler on enter and the double-click handler to open files or go into a directory



724
725
726
727
728
729
730
731
732
733
# File 'lib/hilfer/tree_viewer.rb', line 724

def open_action( files )
  if files.size == 1 && files.first.dir?
    go_into( files.first.path )
  else
    nodirs = files.find_all{ |x| !x.dir? }
    no_synchronize do |editor|
      editor.open_action( nodirs )
    end
  end
end

#populate(model, item, parent_iter, levels_to_populate = 1, level = 0) ⇒ Object

populate the model from the filesystem by default populate only 1 level down



791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
# File 'lib/hilfer/tree_viewer.rb', line 791

def populate( model, item, parent_iter, levels_to_populate = 1, level = 0 )
  iter = nil
  path_colours = do_compute_colours( item )

  Dir.new( item.path ).entries.sort.each do |x|
    begin
      # ignore directory entries
      next if x =~ /^\.\.?$/
      # ignore hidden files unless the flag is set
      next if x =~ /^\./ && !$options[:hidden]
      # ignore generated files
      next if x =~ /.os$/ || x =~ /.pot$/

      # the path of the new item to consider
      next_item_path = item.path + '/' + x

      if item.populated?
        # already have iters for this item
        if iter.nil?
          iter = parent_iter ? parent_iter.first_child : model.iter_first
        else
          iter.next!
        end
      else
        # generate new iters
        iter = model.append( parent_iter )
      end

      # insert the HilferItem objects, from cache if
      # that exists.
      iter[0] = current_item = fetch_hilfer_item( x, next_item_path )
      if ( colour = path_colours[next_item_path] )
        current_item.colour = colour
      end

      # recursively populate files, so the TreeView
      # knows to draw the expanders
      if ( ( File.directory?( next_item_path ) && level < levels_to_populate ) || iter[0].expanded? )
        puts "populating level #{level} #{iter[0].path}" if $options[:debug]
        # populate children
        populate( model, iter[0], iter, levels_to_populate, level + 1 )
      end

    rescue Errno::EACCES
      # mostly to protect against permissions errors
    rescue Exception => ex
      puts "caught exception: #{ex} #{ex.class}"
      puts ex.backtrace
    end

  end
  # OK, this dir is now populated
  item.populated = true

  # clean deleted entries. Doesn't seem necessary?
  #model.remove iter while iter != model.iter_first
end

#refreshObject



189
190
191
# File 'lib/hilfer/tree_viewer.rb', line 189

def refresh
  go_into( @root_item.path )
end

#select_children(widget, iter) ⇒ Object



635
636
637
638
639
640
# File 'lib/hilfer/tree_viewer.rb', line 635

def select_children( widget, iter )
  widget.expand_row( iter.path, false )
  (0...iter.n_children).each do |index|
    select_iter( iter.nth_child( index ), false, false )
  end
end

#select_firstObject



696
697
698
699
# File 'lib/hilfer/tree_viewer.rb', line 696

def select_first
  # set first item as selected
  @view.selection.select_path Gtk::TreePath.new( '0' )
end

#select_fs_path(fs_path, open = false) ⇒ Object

Set selection to the given filesystem path. TODO could optimise this to select faster if we use directory names. Possibly also use select_iter if it’s faster



665
666
667
668
669
670
671
672
673
674
# File 'lib/hilfer/tree_viewer.rb', line 665

def select_fs_path( fs_path, open = false )
  @view.model.each do
    |model, path, iter|
    if iter[0].path == fs_path
      select_path( path )
      @view.expand_row( path, false ) if open
      break
    end
  end
end

#select_fs_paths(fs_paths, open = false) ⇒ Object



676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
# File 'lib/hilfer/tree_viewer.rb', line 676

def select_fs_paths( fs_paths, open = false )
  cursor_set = false
  @view.model.each do
    |model, path, iter|
    if fs_paths.include?( iter[0].path )
      @view.expand_row( path, false ) if open
      # set the cursor at the beginning because
      # selection seems to follow it and we want
      # a multiple selection with the cursor on the first
      if !cursor_set
        @view.set_cursor( iter.path, nil, false )
        cursor_set = true
      end

      select_iter( iter, false, false )
    end
  end

end

#select_iter(iter, unselect = true, set_cursor = true) ⇒ Object

set selection and cursor to the given GtkTreeModel iter



653
654
655
656
657
658
659
660
# File 'lib/hilfer/tree_viewer.rb', line 653

def select_iter( iter, unselect = true, set_cursor = true )
  unselect_all if unselect
  expand_parents_of( iter.path )
  @view.selection.select_iter( iter )
  @view.set_cursor( iter.path, nil, false ) if set_cursor
  # path, column, use_align, row_align, col_align
  @view.scroll_to_cell( iter.path, nil, true, 0.5, 0.0 )
end

#select_path(path, unselect = true, set_cursor = true) ⇒ Object

set selection and cursor to the given GtkTreeModel path



643
644
645
646
647
648
649
650
# File 'lib/hilfer/tree_viewer.rb', line 643

def select_path( path, unselect = true, set_cursor = true )
  unselect_all if unselect
  expand_parents_of( path )
  @view.selection.select_path( path )
  @view.set_cursor( path, nil, false ) if set_cursor
  # path, column, use_align, row_align, col_align
  @view.scroll_to_cell( path, nil, true, 0.5, 0.0 )
end

#setstatusObject

go through and expand / collapse based on HilferItem status



850
851
852
853
854
855
856
857
858
859
# File 'lib/hilfer/tree_viewer.rb', line 850

def setstatus
  @view.model.each do |model, path, iter|
    case iter[0].status
      when :collapsed
        @view.collapse_row( iter.path )
      when :expanded
        @view.expand_row( iter.path, false )
    end
  end
end

#synchronise_editor_path(fs_path) ⇒ Object

callback for the editor classes First checks the values of and then calls select_fs_path



705
706
707
708
709
710
# File 'lib/hilfer/tree_viewer.rb', line 705

def synchronise_editor_path( fs_path )
  if ( @expecting_synchronize_path || @auto_synchronize_path )
    select_fs_path fs_path
    @expecting_synchronize_path = false
  end
end

#terminalObject



735
736
737
738
739
740
741
742
743
744
745
# File 'lib/hilfer/tree_viewer.rb', line 735

def terminal
  if HAS_GNOME_TERMINAL
    puts "Using Gnome terminal"
    @terminal ||= GnomeTerminal.new
  elsif HAS_XFCE_TERMINAL
    puts "Using XFCE Terminal"
    @terminal ||= XfceTerminal.new
  else
    @terminal ||= Xterm.new
  end
end

#unselect_allObject



631
632
633
# File 'lib/hilfer/tree_viewer.rb', line 631

def unselect_all
  @view.selection.unselect_all
end