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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
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
|
# -*- coding: utf-8 -*-
miquire :mui, 'timeline', 'tree_view_pretty_scroll', 'dark_matter_prification'
miquire :lib, 'uithreadonly'
require 'gtk2'
class Gtk::TimeLine::InnerTL < Gtk::CRUD
include UiThreadOnly
include Gtk::TreeViewPrettyScroll
include Gtk::InnerTLDarkMatterPurification
attr_writer :force_retrieve_in_reply_to
attr_accessor :postbox, :imaginary
type_register('GtkInnerTL')
# TLの値を返すときに使う
Record = Struct.new(:uri, :message, :order, :miracle_painter)
URI = 0
MESSAGE = 1
ORDER = 2
MIRACLE_PAINTER = 3
def self.current_tl
ctl = @@current_tl and @@current_tl.toplevel.focus.get_ancestor(Gtk::TimeLine::InnerTL) rescue nil
ctl if(ctl.is_a?(Gtk::TimeLine::InnerTL) and not ctl.destroyed?)
end
# ==== Args
# [from] 設定値を引き継ぐ元のInnerTL
def initialize(from = nil)
super()
@force_retrieve_in_reply_to = :auto
@@current_tl ||= self
@iter_dict = {} # String: Gdk::TreeIter
@order = ->(m) { m.modified.to_i }
self.name = 'timeline'
set_headers_visible(false)
set_enable_search(false)
last_geo = nil
selection.mode = Gtk::SELECTION_MULTIPLE
get_column(0).set_sizing(Gtk::TreeViewColumn::AUTOSIZE)
extend(from) if from
set_events end
def cell_renderer_message
@cell_renderer_message ||= Gtk::CellRendererMessage.new
end
def column_schemer
[ {:renderer => lambda{ |x,y|
cell_renderer_message.tree = self
cell_renderer_message
},
:kind => :uri, :widget => :text, :type => String, :label => ''},
{:kind => :text, :widget => :text, :type => Message},
{:kind => :text, :type => Integer},
{:kind => :text, :type => Object}
].freeze
end
def get_order(m)
@order.call(m) end
# レコードの並び順を決めるブロックを登録する。ブロックは一つの Message を受け取り、数値を返す
# ==== Args
# [&block] 並び順を決めるブロック
# ==== Return
# self
def set_order(&block)
@order = block end
def menu_pop(widget, event)
end
def handle_row_activated
end
def reply(options = {})
ctl = Gtk::TimeLine::InnerTL.current_tl
pb = nil
if(ctl)
options = options.dup
options[:before_post_hook] = lambda{ |this|
get_ancestor(Gtk::Window).set_focus(self) unless self.destroyed? }
pb = Gtk::PostBox.new(options).show_all
postbox.closeup(pb)
pb.on_delete(&Proc.new) if block_given?
get_ancestor(Gtk::Window).set_focus(pb.post)
ctl.selection.unselect_all end
pb end
def add_postbox(i_postbox)
reply(i_postbox.options)
end
def set_cursor_to_display_top
iter = model.iter_first
set_cursor(iter.path, get_column(0), false) if iter end
def get_active_messages
get_active_iterators.map{ |iter| iter[1] } end
def get_active_iterators
selected = []
if not destroyed?
selection.selected_each{ |model, path, iter|
selected << iter } end
selected end
def get_active_pathes
selected = []
if not destroyed?
selection.selected_each{ |model, path, iter|
selected << path } end
selected end
# _message_ のレコードの _column_ 番目のカラムの値を _value_ にセットする。
# 成功したら _value_ を返す
def update!(message, column, value)
iter = get_iter_by_message(message)
if iter
iter[column] = value
# 更新の結果、高さが変わる可能性がある
iter[MIRACLE_PAINTER].reset_height
value end end
# タイムラインの内容を全て削除する
# ==== Return
# self
def clear
deleted = @iter_dict
@iter_dict = {}
deleted.values.each{ |iter| iter[MIRACLE_PAINTER].destroy }
model.clear end
# _path_ からレコードを取得する。なければnilを返す。
def get_record(path)
iter = model.get_iter(path)
if iter
Record.new(iter[0], iter[1], iter[2], iter[3]) end end
# _message_ に対応する Gtk::TreePath を返す。なければnilを返す。
def get_path_by_message(message)
get_path_and_iter_by_message(message)[1] end
# _message_ に対応する値の構造体を返す。なければnilを返す。
def get_record_by_message(message)
get_record_by_uri(message.uri.to_s) end
# _message_ に対応する値の構造体を返す。なければnilを返す。
def get_record_by_uri(uri)
path = get_path_and_iter_by_uri(uri)[1]
if path
get_record(path) end end
def force_retrieve_in_reply_to
if(:auto == @force_retrieve_in_reply_to)
UserConfig[:retrieve_force_mumbleparent]
else
@force_retrieve_in_reply_to end end
# _message_ が含まれているかを返す
# ==== Args
# [message] Message タイムラインに含まれているかどうかを確認するMessage
# ==== Return
# 含まれていれば真
def include?(message)
@iter_dict.has_key?(message.uri.to_s) end
# Gtk::TreeIterの対を再利用できるように登録しておく
# ==== Args
# [iter] Gtk::TreeIter
# ==== Return
# self
def set_iter_dict(iter)
uri = iter[URI]
if not @iter_dict.has_key?(uri)
@iter_dict[uri] = iter
iters = @iter_dict
iter[MIRACLE_PAINTER].signal_connect(:destroy) {
iters.delete(uri)
false } end
self end
# 別の InnerTL が自分をextend()した時に呼ばれる
def extended
if @destroy_child_miraclepainters and signal_handler_is_connected?(@destroy_child_miraclepainters)
signal_handler_disconnect(@destroy_child_miraclepainters) end end
private
# self に _from_ の内容をコピーする
# ==== Args
# [from] InnerTL
# ==== Return
# self
def extend(from)
@force_retrieve_in_reply_to = from.instance_eval{ @force_retrieve_in_reply_to }
@imaginary = from.imaginary
from.extended
from.model.each{ |from_model, from_path, from_iter|
iter = model.append
iter[URI] = from_iter[URI]
iter[MESSAGE] = from_iter[MESSAGE]
iter[ORDER] = from_iter[ORDER]
iter[MIRACLE_PAINTER] = from_iter[MIRACLE_PAINTER].set_tree(self)
set_iter_dict(iter) }
self
end
def set_events
@destroy_child_miraclepainters = signal_connect(:destroy) {
model.each{ |m, p, iter|
iter[MIRACLE_PAINTER].destroy }
}
signal_connect(:focus_in_event){
@@current_tl.selection.unselect_all if not(@@current_tl.destroyed?) and @@current_tl and @@current_tl != self
@@current_tl = self
false } end
# _message_ に対応する Gtk::TreeIter を返す。なければnilを返す。
def get_iter_by_message(message)
get_path_and_iter_by_message(message)[2] end
# _message_ に対応する Gtk::TreeIter を返す。なければnilを返す。
def get_iter_by_uri(uri)
get_path_and_iter_by_uri(uri)[2] end
# _message_ から [model, path, iter] の配列を返す。見つからなかった場合は空の配列を返す。
def get_path_and_iter_by_message(message)
get_path_and_iter_by_uri(message.uri.to_s) end
def get_path_and_iter_by_uri(uri)
uri = uri.to_s
iter = @iter_dict[uri]
if iter
if iter[MIRACLE_PAINTER].destroyed?
warn "destroyed miracle painter in cache (##{uri})"
@iter_dict.delete(uri)
[]
else
[model, iter.path, iter] end
else
[] end end
end
|