File: gtk_crud.rb

package info (click to toggle)
mikutter 5.0.4%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 9,700 kB
  • sloc: ruby: 21,307; sh: 181; makefile: 19
file content (170 lines) | stat: -rw-r--r-- 5,300 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
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
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
# -*- coding: utf-8 -*-

# CRUDなリストビューを簡単に実現するためのクラス
class Gtk::CRUD < Gtk::CompatListView
  attr_accessor :creatable, :updatable, :deletable
  type_register

  def initialize
    super()
    @creatable = @updatable = @deletable = true
    handle_release_event
    handle_row_activated
  end

  def buttons(orientation)
    box = Gtk::ButtonBox.new(orientation)
    box.spacing = 6
    box << create_button << update_button << delete_button
  end

  def create_button
    if not defined? @create_button
      @create_button = Gtk::Button.new stock_id: Gtk::Stock::ADD
      @create_button.ssc(:clicked) {
        record_create(nil, nil) } end
    @create_button end

  def update_button
    if not defined? @update_button
      @update_button = Gtk::Button.new stock_id: Gtk::Stock::EDIT
      @update_button.ssc(:clicked) {
        record_update(nil, nil) } end
    @update_button end

  def delete_button
    if not defined? @delete_button
      @delete_button = Gtk::Button.new stock_id: Gtk::Stock::DELETE
      @delete_button.ssc(:clicked) {
        record_delete(nil, nil) } end
    @delete_button end

  protected

  def handle_row_activated
    self.ssc(:row_activated){|view, path, column|
      if @updatable and iter = view.model.get_iter(path)
        if record = popup_input_window((0...model.n_columns).map{|i| iter[i] })
          force_record_update(iter, record) end end }
  end

  def handle_release_event
    self.ssc(:button_release_event){ |widget, event|
      if (event.button == 3)
        menu_pop(self, event)
        true end }
  end

  def on_created(iter)
  end

  def on_updated(iter)
  end

  def on_deleted(iter)
  end

  private

  def get_render_by(scheme, index)
    result = super
    if result
      result
    elsif scheme[:kind] == :active
      toggled = Gtk::CellRendererToggle.new
      toggled.ssc(:toggled) do |toggled, path|
        iter = model.get_iter(path)
        iter[index] = !iter[index]
        on_updated(iter)
        false
      end
      toggled
    end
  end

  def force_record_create(record)
    iter = model.model.append
    record.each_with_index{ |item, index|
      iter[index] = item }
    on_created(iter) end

  def force_record_update(iter, record)
    if defined? model.convert_iter_to_child_iter(iter)
      iter = model.convert_iter_to_child_iter iter end
    record.each_with_index{ |item, index|
      iter[index] = item }
    on_updated(iter) end

  def force_record_delete(iter)
    if defined? model.convert_iter_to_child_iter(iter)
      iter = model.convert_iter_to_child_iter iter end
    on_deleted(iter)
    model.model.remove(iter)
  end

  def record_create(optional, widget)
    if @creatable
      record = popup_input_window()
      if record
        force_record_create(record) end end end

  def record_update(optional, widget)
    if @updatable
      self.selection.selected_each {|model, path, iter|
        record = popup_input_window((0...model.n_columns).map{|i| iter[i] })
        if record and not model.destroyed?
          force_record_update(iter, record) end } end end

  def record_delete(optional, widget)
    if @deletable
      self.selection.each {|model, path, iter|
        if Gtk::Dialog.confirm("本当に削除しますか?\n" +
                               "一度削除するともうもどってこないよ。")
          force_record_delete(iter) end } end end

  def menu_pop(widget, event)
    if(@creatable or @updatable or @deletable)
      contextmenu = Gtk::ContextMenu.new
      contextmenu.register("新規作成", &method(:record_create)) if @creatable
      contextmenu.register("編集", &method(:record_update)) if @updatable
      contextmenu.register("削除", &method(:record_delete)) if @deletable
      contextmenu.popup(widget, widget) end end

  # 入力ウィンドウを表示する
  def popup_input_window(defaults = [])
    input = gen_popup_window_widget(defaults)
    Mtk.scrolled_dialog(dialog_title || "", input[:widget], self.toplevel || self, &input[:result]) end

  def gen_popup_window_widget(results = [])
    widget = Gtk::Box.new(:vertical, 0)
    column_schemer.flatten.each_with_index{ |scheme, index|
      case scheme[:widget]
      when :message_picker
        widget.pack_start(Mtk.message_picker(lambda{ |new|
                                            if(new.nil?)
                                              results[index].freeze_ifn
                                            else
                                              results[index] = new.freeze_ifn
                                            end
                                          }), expand: false)
      when nil
        ;
      else
        widget.pack_start(widget, Mtk.__send__((scheme[:widget] or :input), lambda{ |new|
                                   if(new.nil?)
                                     results[index].freeze_ifn
                                   else
                                     results[index] = new.freeze_ifn
                                   end
                                 },
                                 scheme[:label], *(scheme[:args].to_a or [])), expand: false)
      end
    }
    { :widget => widget,
      :result => lambda{
        results
      }
    }
  end

end