Class: Sirens::TreeView

Inherits:
WidgetView show all
Defined in:
lib/views/tree_view.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from WidgetView

#add_view, #apply_prop, #apply_props, #initialize, #main_handle

Methods inherited from AbstractView

accepted_styles, #accepted_styles, #add_view, #attribute_at, #background_color=, #foreground_color=, #height, #height=, #initialize, #main_handle, #populate_popup_menu_block=, #remove_view, #set_attribute, #show, #show_popup_menu, #state_colors_from, #width, #width=

Constructor Details

This class inherits a constructor from Sirens::WidgetView

Class Method Details

.view_accepted_stylesObject

Answer the styles accepted by this view.



10
11
12
# File 'lib/views/tree_view.rb', line 10

def view_accepted_styles()
    super() + [:show_headers, :clickable_headers, :on_selection_action ].freeze
end

Instance Method Details

#add_column_with_props(props) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/views/tree_view.rb', line 74

def add_column_with_props(props)
    column_index = tree_view.columns.size

    col = nil

    column_label = props[:label]

    if props.has_image_block?
        renderer = Gtk::CellRendererPixbuf.new

        col = Gtk::TreeViewColumn.new(column_label, renderer, pixbuf: column_index)
    else
        renderer = Gtk::CellRendererText.new

        col = Gtk::TreeViewColumn.new(column_label, renderer, text: column_index)
    end

    tree_view.append_column(col)
end

#add_item(item:, parent_iter:, index:) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/views/tree_view.rb', line 235

def add_item(item:, parent_iter:, index:)
    iter = tree_store.insert(parent_iter, index)

    set_item_column_values(item: item, iter: iter)

    if parent_iter.nil?
        indices_path = [index]
    else
        indices_path = parent_iter.path.indices + [index]
    end

    children_count = get_children_at(path: indices_path).size

    if children_count > 0
        tree_store.insert(iter, 0)
    end
end

#add_items(items:, parent_iter:, index:) ⇒ Object

Adding



229
230
231
232
233
# File 'lib/views/tree_view.rb', line 229

def add_items(items:, parent_iter:, index:)
    items.each_with_index do |each_item, i|
        add_item(item: each_item, parent_iter: parent_iter, index: index + i)
    end
end

#clear_itemsObject

Actions



217
218
219
# File 'lib/views/tree_view.rb', line 217

def clear_items()
    tree_store.clear
end

#clickable_headers=(boolean) ⇒ Object



152
153
154
# File 'lib/views/tree_view.rb', line 152

def clickable_headers=(boolean)
    tree_view.headers_clickable = boolean
end

#clickable_headers?Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/views/tree_view.rb', line 156

def clickable_headers?()
    tree_view.headers_clickable?
end

#define_columns(columns_props_array) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/views/tree_view.rb', line 62

def define_columns(columns_props_array)
    @columns_props = columns_props_array

    list_store_types = @columns_props.collect { |type| tree_store_type_for(type) }

    tree_view.set_model(Gtk::TreeStore.new(*list_store_types))

    @columns_props.each do |each_column_props|
        add_column_with_props(each_column_props)
    end
end

#display_data_of(item, column, column_index) ⇒ Object



289
290
291
292
293
294
295
296
297
# File 'lib/views/tree_view.rb', line 289

def display_data_of(item, column, column_index)
    if column.has_image_block?
        image_file = column.display_image_of(item).to_s

        return GdkPixbuf::Pixbuf.new(file: image_file, width: 16, height: 16)
    end

    column.display_text_of(item)
end

#expand(path:) ⇒ Object



328
329
330
331
332
333
334
# File 'lib/views/tree_view.rb', line 328

def expand(path:)
    tree_path = Gtk::TreePath.new(
            path.join(':')
        )

    tree_view.expand_row(tree_path, false)
end

#get_children_at(path:) ⇒ Object



138
139
140
# File 'lib/views/tree_view.rb', line 138

def get_children_at(path:)
    @get_children_block.call(path: path)
end

#get_children_block(&block) ⇒ Object



48
49
50
51
52
# File 'lib/views/tree_view.rb', line 48

def get_children_block(&block)
    @get_children_block = block

    self
end

#get_item_at(path:) ⇒ Object



134
135
136
# File 'lib/views/tree_view.rb', line 134

def get_item_at(path:)
    @get_item_block.call(path: path)
end

#get_item_block(&block) ⇒ Object



42
43
44
45
46
# File 'lib/views/tree_view.rb', line 42

def get_item_block(&block)
    @get_item_block = block

    self
end

#initialize_handlesObject

Initializing



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/views/tree_view.rb', line 17

def initialize_handles()
    @tree_view = Gtk::TreeView.new
    @tree_view.set_model(Gtk::TreeStore.new(String))

    @main_handle = Gtk::ScrolledWindow.new
    @main_handle.add(tree_view)
    @main_handle.set_policy(:automatic, :automatic)

    @current_selection_indices = []

    @columns_props = []

    @on_selection_changed_block = nil
    @get_item_block = nil
    @get_children_block = nil
end

#on_row_expanded(iter:, tree_path:) ⇒ Object

To emulate a virtual tree elements are added with a child placeholder, the class placeholder constant. The first time a node is expanded if it has the child placeholder it is replaced by the actual node children. The actual children are get using the get_children_block.



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/views/tree_view.rb', line 199

def on_row_expanded(iter:, tree_path:)
    child_iter = iter.first_child

    return if ! tree_store.get_value(child_iter, 0).nil?

    indices_path = tree_path.indices

    children = get_children_at(path: indices_path)

    tree_store.remove(child_iter)

    add_items(items: children, parent_iter: iter, index: 0)

    tree_view.expand_row(tree_path, false)
end

#on_selection_action(tree_path:, tree_column:) ⇒ Object



183
184
185
186
187
188
189
190
191
# File 'lib/views/tree_view.rb', line 183

def on_selection_action(tree_path:, tree_column:)
    return if @on_selection_action_block.nil?

    index_path = tree_path.indices

    item = get_item_at(path: index_path)

    @on_selection_action_block.call(index_path: index_path, item: item)
end

#on_selection_action=(block) ⇒ Object



160
161
162
# File 'lib/views/tree_view.rb', line 160

def on_selection_action=(block)
    @on_selection_action_block = block
end

#on_selection_changed(tree_selection) ⇒ Object

Handlers



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/views/tree_view.rb', line 166

def on_selection_changed(tree_selection)
    indices = []
    items = []

    tree_selection.each do |tree_store, tree_path, iter|
        indices_path = tree_path.indices

        indices << indices_path
        items << get_item_at(path: indices_path)
    end

    @on_selection_changed_block.call(
        selection_items: items,
        selection_paths: indices
    )
end

#on_selection_changed_block(&block) ⇒ Object

Configuring callbacks



36
37
38
39
40
# File 'lib/views/tree_view.rb', line 36

def on_selection_changed_block(&block)
    @on_selection_changed_block = block

    self
end

#remove_item(item:, index:) ⇒ Object



275
276
277
278
279
# File 'lib/views/tree_view.rb', line 275

def remove_item(item:, index:)
    iter = tree_store.get_iter(index.to_s)

    tree_store.remove(iter)
end

#remove_items(items:, indices:) ⇒ Object

Removing



269
270
271
272
273
# File 'lib/views/tree_view.rb', line 269

def remove_items(items:, indices:)
    items.each_with_index do |each_item, i|
        remove_item(item: each_item, index: indices[i])
    end
end

#rowsObject

Returns the rows contents of the tree. For testing and debugging only.



128
129
130
131
132
# File 'lib/views/tree_view.rb', line 128

def rows()
    tree_store.collect { |store, path, iter|
        iter[0]
    }
end

#selection_indicesObject

Querying



301
302
303
304
305
306
307
308
309
# File 'lib/views/tree_view.rb', line 301

def selection_indices()
    indices = []

    tree_view.selection.each { |tree, path, iter|
        indices << path.to_s.to_i
    }

    indices
end

#set_item_column_values(item:, iter:) ⇒ Object



281
282
283
284
285
286
287
# File 'lib/views/tree_view.rb', line 281

def set_item_column_values(item:, iter:)
    @columns_props.each_with_index { |column, column_index|
        colum_value = display_data_of(item, column, column_index)

        iter.set_value(column_index, colum_value)
    }
end

#set_roots(root_items) ⇒ Object



221
222
223
224
225
# File 'lib/views/tree_view.rb', line 221

def set_roots(root_items)
    clear_items

    add_items(parent_iter: nil, items: root_items, index: 0)
end

#set_selection_indices(indices) ⇒ Object



311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/views/tree_view.rb', line 311

def set_selection_indices(indices)
    if indices.empty?
        tree_view.unselect_all
        return
    end

    tree_path = Gtk::TreePath.new(
            indices.join(':')
        )

    expand(path: indices[0..-2]) if indices.size > 1

    tree_view.selection.select_path(tree_path)

    tree_view.scroll_to_cell(tree_path, nil, false, 0.0, 0.0)
end

#show_headers=(boolean) ⇒ Object

Styles



144
145
146
# File 'lib/views/tree_view.rb', line 144

def show_headers=(boolean)
    tree_view.headers_visible = boolean
end

#show_headers?Boolean

Returns:

  • (Boolean)


148
149
150
# File 'lib/views/tree_view.rb', line 148

def show_headers?()
    tree_view.headers_visible?
end

#subscribe_to_ui_eventsObject

Hooking GUI signals



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/views/tree_view.rb', line 96

def subscribe_to_ui_events()
    tree_view.selection.signal_connect('changed') { |tree_selection|
        on_selection_changed(tree_selection)
    }

    tree_view.signal_connect('row-activated') { |tree_view, tree_path, tree_column|
        on_selection_action(tree_path: tree_path, tree_column: tree_column)
    }

    tree_view.signal_connect('row-expanded') { |tree_view, iter, tree_path|
        on_row_expanded(iter: iter, tree_path: tree_path)
    }

    tree_view.signal_connect('button_press_event') do |tree_view, event|
        show_popup_menu(button: event.button, time: event.time) if (event.button == 3)
    end
end

#tree_storeObject

Accessing



116
117
118
# File 'lib/views/tree_view.rb', line 116

def tree_store()
    tree_view.model
end

#tree_store_type_for(column_props) ⇒ Object

Building columns



56
57
58
59
60
# File 'lib/views/tree_view.rb', line 56

def tree_store_type_for(column_props)
    return GdkPixbuf::Pixbuf if column_props.has_image_block?

    String
end

#tree_viewObject



120
121
122
# File 'lib/views/tree_view.rb', line 120

def tree_view()
    @tree_view
end

#update_item(item:, index:) ⇒ Object



261
262
263
264
265
# File 'lib/views/tree_view.rb', line 261

def update_item(item:, index:)
    iter = tree_store.get_iter(index.to_s)

    set_item_column_values(item: item, iter: iter)
end

#update_items(items:, indices:) ⇒ Object

Updating



255
256
257
258
259
# File 'lib/views/tree_view.rb', line 255

def update_items(items:, indices:)
    items.each_with_index do |each_item, i|
        update_item(item: each_item, index: indices[i])
    end
end