Module: Knj::Gtk2::Tv

Defined in:
lib/knj/gtk2_tv.rb

Overview

This module contains various helper-methods for handeling stuff regarding treeviews.

Constant Summary collapse

ALLOWED_ARGS =
[:cols, :reorderable, :sortable, :type]
@@editable_text_callbacks =
{
  :datetime => {
    :value => proc{ |data|
      begin
        Datet.in(data[:value]).dbstr
      rescue ArgumentError
        raise "Invalid timestamp entered."
      end
    },
    :value_set => proc{ |data|
      Datet.in(data[:value]).out
    }
  },
  :time_as_sec => {
    :value => proc{ |data| Knj::Strings.human_time_str_to_secs(data[:value]) },
    :value_set => proc{ |data| Knj::Strings.secs_to_human_time_str(data[:value]) }
  },
  :int => {
    :value => proc{ |data| data[:value].to_i.to_s }
  },
  :human_number => {
    :value => proc{ |data| Knj::Locales.number_in(data[:value]) },
    :value_set => proc{ |data| Knj::Locales.number_out(data[:value], data[:col_data][:decimals]) }
  },
  :toggle_rev => {
    :value_set => lambda{|data|
      if data[:value]
        return false
      else
        return true
      end
    }
  }
}

Class Method Summary collapse

Class Method Details

.append(tv, data) ⇒ Object

Appends data to the treeview.

Examples

Knj::Gtk2::Tv.append(treeview, [1, “Kasper”])



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/knj/gtk2_tv.rb', line 129

def self.append(tv, data)
  iter = tv.model.append
  
  count = 0
  data.each do |value|
    col = tv.columns[count]
    renderer = col.cell_renderers.first
    
    if renderer.is_a?(Gtk::CellRendererText)
      iter[count] = value.to_s
    elsif renderer.is_a?(Gtk::CellRendererToggle)
      iter[count] = Knj::Strings.yn_str(value, 1, 0)
    elsif renderer.is_a?(Gtk::CellRendererCombo)
      iter[count] = value.to_s
    else
      raise "Unknown renderer: '#{renderer.class.name}'."
    end
    
    count += 1
  end
  
  return {:iter => iter}
end

.editable_text_renderers_to_model(args) ⇒ Object



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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
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
# File 'lib/knj/gtk2_tv.rb', line 208

def self.editable_text_renderers_to_model(args)
  args[:id_col] = 0 if !args.key?(:id_col)
  
  args[:cols].each do |col_no, col_data|
    col_data = {:col => col_data} if col_data.is_a?(Symbol)
    
    if col_data.key?(:type)
      if callbacks = @@editable_text_callbacks[col_data[:type]]
        col_data[:value_callback] = callbacks[:value] if callbacks.key?(:value)
        col_data[:value_set_callback] = callbacks[:value_set] if callbacks.key?(:value_set)
      else
        raise "Invalid type: '#{col_data[:type]}'."
      end
    end
    
    renderer = args[:renderers][col_no]
    raise "Could not find a renderer for column no. '#{col_no}'." if !renderer
    
    if args[:on_edit]
      renderer.signal_connect("editing-started") do |renderer, row_no, path|
        iter = args[:tv].model.get_iter(path)
        id = args[:tv].model.get_value(iter, args[:id_col])
        
        if id.to_i > 0
          model_obj = args[:ob].get(args[:model_class], id)
          args[:on_edit].call(:renderer => renderer, :row_no => row_no, :path => path, :args => args, :model => model_obj, :col_no => col_no, :col_data => col_data)
        end
      end
    end
    
    if args[:on_edit_done]
      renderer.signal_connect("editing-canceled") do |renderer|
        args[:on_edit_done].call(:renderer => renderer, :done_mode => :canceled, :args => args, :col_no => col_no, :col_data => col_data)
      end
    end
    
    if col_data[:on_edit]
      renderer.signal_connect("editing-started") do |renderer, row_no, path|
        iter = args[:tv].model.get_iter(path)
        id = args[:tv].model.get_value(iter, args[:id_col])
        model_obj = args[:ob].get(args[:model_class], id)
        
        col_data[:on_edit].call(:renderer => renderer, :row_no => row_no, :path => path, :iter => iter, :args => args, :model => model_obj, :col_no => col_no, :col_data => col_data)
      end
    end
    
    if renderer.is_a?(Gtk::CellRendererText)
      renderer.editable = true
      renderer.signal_connect("edited") do |renderer, row_no, value|
        iter = args[:tv].model.get_iter(row_no)
        id = args[:tv].model.get_value(iter, args[:id_col])
        
        if id.to_i > 0
          model_obj = args[:ob].get(args[:model_class], id)
          cancel = false
          callback_hash = {:args => args, :value => value, :model => model_obj, :col_no => col_no, :col_data => col_data}
          
          if args[:on_edit_done]
            args[:on_edit_done].call(:renderer => renderer, :row_no => row_no, :done_mode => :canceled, :args => args, :model => model_obj, :col_no => col_no, :col_data => col_data)
          end
          
          if col_data[:value_callback]
            begin
              value = col_data[:value_callback].call(callback_hash)
              callback_hash[:value] = value
            rescue => e
              Knj::Gtk2.msgbox(e.message, "warning")
              cancel = true
            end
          end
          
          if !cancel
            begin
              args[:change_before].call(callback_hash) if args[:change_before]
            rescue => e
              cancel = true
              Knj::Gtk2.msgbox(e.message, "warning")
            end
            
            if !cancel
              begin
                model_obj[col_data[:col]] = value
                value = col_data[:value_set_callback].call(callback_hash) if col_data.key?(:value_set_callback)
                iter[col_no] = value
              rescue => e
                Knj::Gtk2.msgbox(e.message, "warning")
              ensure
                args[:change_after].call(callback_hash) if args[:change_after]
              end
            end
          end
        end
      end
    elsif renderer.is_a?(Gtk::CellRendererToggle)
      renderer.activatable = true
      renderer.signal_connect("toggled") do |renderer, path|
        iter = args[:tv].model.get_iter(path)
        id = args[:tv].model.get_value(iter, 0)
        model_obj = args[:ob].get(args[:model_class], id) if id.to_i > 0
        
        if model_obj and col_data[:col]
          if model_obj[col_data[:col]].to_i == 1
            value = false
            value_i = 0
          else
            value = true
            value_i = 1
          end
        else
          if iter[col_no] == 0
            value = true
            value_i = 1
          else
            value = false
            value_i = 0
          end
        end
        
        callback_hash = {:args => args, :value => value, :model => model_obj, :col_no => col_no, :col_data => col_data}
        
        if col_data[:value_callback]
          begin
            value = col_data[:value_callback].call(callback_hash)
            callback_hash[:value] = value
          rescue => e
            Knj::Gtk2.msgbox(e.message, "warning")
            cancel = true
          end
        end
        
        if value
          value_i = 1
        else
          value_i = 0
        end
        
        callback_hash[:value] = value
        
        if !cancel
          args[:change_before].call(callback_hash) if args[:change_before]
          begin
            model_obj[col_data[:col]] = value_i if model_obj and col_data[:col]
            
            if col_data.key?(:value_set_callback)
              value = col_data[:value_set_callback].call(callback_hash)
              
              if value
                value_i = 1
              else
                value_i = 0
              end
            end
            
            iter[col_no] = value_i
          ensure
            args[:change_after].call(:args => args) if args[:change_after]
          end
        end
      end
    else
      raise "Invalid cellrenderer: '#{renderer.class.name}'."
    end
  end
end

.init(tv, rargs) ⇒ Object

Initializes a treeview with a model and a number of columns. Returns a hash containing various data like the renderers.

Examples

Knj::Gtk2::Tv.init(treeview, [“ID”, “Name”])



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
# File 'lib/knj/gtk2_tv.rb', line 8

def self.init(tv, rargs)
  ret = {
    :renderers => []
  }
  
  if rargs.is_a?(Array)
    columns = rargs
    rargs = {}
  else
    columns = rargs[:cols]
  end
  
  
  #Default arguments.
  rargs = {
    :reorderable => true,
    :sortable => true
  }.merge!(rargs)
  
  rargs.each do |key, val|
    raise "Invalid argument: '#{key}'." if !ALLOWED_ARGS.include?(key)
  end
  
  
  #Spawn store.
  model_args = []
  columns.each do |args|
    if args.is_a?(String)
      args = {:type => :string, :title => args}
    end
    
    if args[:type] == :string
      model_args << String
    elsif args[:type] == :toggle
      model_args << Integer
    elsif args[:type] == :combo
      model_args << String
    else
      raise "Invalid type: '#{args[:type]}'."
    end
  end
  
  if rargs[:type] == :treestore
    list_store = Gtk::TreeStore.new(*model_args)
  else
    list_store = Gtk::ListStore.new(*model_args)
  end
  
  tv.model = list_store
  
  count = 0
  columns.each do |args|
    if args.is_a?(String)
      args = {:type => :string, :title => args}
    end
    
    if args[:type] == :string
      if args[:markup]
        col_args = {:markup => count}
      else
        col_args = {:text => count}
      end
      
      renderer = Gtk::CellRendererText.new
      col = Gtk::TreeViewColumn.new(args[:title], renderer, col_args)
      col.resizable = true
    elsif args[:type] == :toggle
      renderer = Gtk::CellRendererToggle.new
      col = Gtk::TreeViewColumn.new(args[:title], renderer, :active => count)
    elsif args[:type] == :combo
      renderer = Gtk::CellRendererCombo.new
      renderer.text_column = 0
      renderer.model = args[:model] if args.key?(:model)
      renderer.has_entry = args[:has_entry] if args.key?(:has_entry)
      
      if args[:markup]
        col_args = {:markup => count}
      else
        col_args = {:text => count}
      end
      
      col = Gtk::TreeViewColumn.new(args[:title], renderer, col_args)
      col.resizable = true
    else
      raise "Invalid type: '#{args[:type]}'."
    end
    
    col.spacing = 0
    col.reorderable = rargs[:reorderable] if !args.key?(:reorderable) or args[:reorderable]
    
    if !rargs[:sortable]
      col.sort_column_id = -1
    else
      col.sort_column_id = count
    end
    
    if args.key?(:fixed_width)
      col.sizing = Gtk::TreeViewColumn::FIXED
    else
      col.sizing = Gtk::TreeViewColumn::AUTOSIZE
    end
    
    [:min_width, :max_width, :fixed_width, :expand, :spacing, :reorderable].each do |arg|
      col.__send__("#{arg}=", args[arg]) if args.key?(arg)
    end
    
    [:width_chars, :wrap_mode, :wrap_width].each do |arg|
      renderer.__send__("#{arg}=", args[arg]) if args.key?(arg)
    end
    
    tv.append_column(col)
    ret[:renderers] << renderer
    count += 1
  end
  
  return ret
end

.sel(tv) ⇒ Object

Gets the selected data from the treeview.

Examples

Knj::Gtk2::Tv.sel(treeview) #=> [1, “Kasper”]



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/knj/gtk2_tv.rb', line 156

def self.sel(tv)
  selected = tv.selection.selected_rows
  return nil if !tv.model or selected.size <= 0
  
  iter = tv.model.get_iter(selected[0])
  returnval = []
  columns = tv.columns
  
  count = 0
  columns.each do |column|
    returnval[count] = iter[count]
    count += 1
  end
  
  return returnval
end