kentaroi-okayu 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +6 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/bin/okayu +6 -0
- data/lib/app.rb +25 -0
- data/lib/app_dir.rb +29 -0
- data/lib/client.rb +210 -0
- data/lib/controllers/listeners_controller.rb +18 -0
- data/lib/controllers/live_controller.rb +82 -0
- data/lib/controllers/visitors_controller.rb +19 -0
- data/lib/controllers.rb +3 -0
- data/lib/cookie_thief.rb +172 -0
- data/lib/db/migrate/000_create_lives.rb +14 -0
- data/lib/db/migrate/001_create_comments.rb +22 -0
- data/lib/db/migrate/002_create_visitors.rb +15 -0
- data/lib/db/migrate/003_create_listeners.rb +15 -0
- data/lib/db/migrate/004_create_communities.rb +13 -0
- data/lib/db/migrate/005_create_listeners_lives.rb +12 -0
- data/lib/db/migrate/006_create_lives_visitors.rb +13 -0
- data/lib/factory.rb +16 -0
- data/lib/models/comment.rb +22 -0
- data/lib/models/community.rb +3 -0
- data/lib/models/listener.rb +5 -0
- data/lib/models/live.rb +6 -0
- data/lib/models/visitor.rb +5 -0
- data/lib/models.rb +23 -0
- data/lib/okayu.rb +10 -0
- data/lib/player_status.rb +16 -0
- data/lib/sample_msg +2 -0
- data/lib/thread_info.rb +32 -0
- data/lib/user_info.rb +49 -0
- data/lib/views/app_frame.rb +89 -0
- data/lib/views/color_dialog.rb +56 -0
- data/lib/views/colors.rb +168 -0
- data/lib/views/live_panel.rb +335 -0
- data/lib/views/login_dialog.rb +80 -0
- data/lib/views/main_panel.rb +50 -0
- data/lib/views.rb +11 -0
- data/logged_in_page +893 -0
- data/login_error_page +83 -0
- data/okayu.gemspec +126 -0
- data/tcp_log +0 -0
- data/test/client_test.rb +61 -0
- data/test/cookie_thief_test.rb +36 -0
- data/test/ie_cookie.txt +63 -0
- data/test/okayu_test.rb +8 -0
- data/test/player_status_test.rb +61 -0
- data/test/raw_player_status +2 -0
- data/test/raw_player_status_community_only +3 -0
- data/test/raw_player_status_notlogged_in +2 -0
- data/test/test_helper.rb +11 -0
- data/test/thread_info_test.rb +11 -0
- metadata +193 -0
@@ -0,0 +1,335 @@
|
|
1
|
+
module Okayu
|
2
|
+
COLORIZE = 300
|
3
|
+
NAME = 301
|
4
|
+
|
5
|
+
class LiveListCtrl < Wx::ListCtrl
|
6
|
+
COLUMNS = { :no => 0,
|
7
|
+
:message => 1,
|
8
|
+
:mail => 2,
|
9
|
+
:time => 3,
|
10
|
+
:name => 4,
|
11
|
+
:id => 5,
|
12
|
+
:premium => 6,
|
13
|
+
:ngword => 7 }
|
14
|
+
attr_accessor :base_time
|
15
|
+
|
16
|
+
def initialize(parent)
|
17
|
+
super(parent, :id => Wx::ID_ANY, :style => Wx::LC_REPORT)
|
18
|
+
insert_column COLUMNS[:no], "No", Wx::LIST_FORMAT_LEFT, -1
|
19
|
+
insert_column COLUMNS[:message], "Message", Wx::LIST_FORMAT_LEFT, -1
|
20
|
+
insert_column COLUMNS[:mail], "Command", Wx::LIST_FORMAT_LEFT, -1
|
21
|
+
insert_column COLUMNS[:time], "Time", Wx::LIST_FORMAT_LEFT, -1
|
22
|
+
insert_column COLUMNS[:name], "Name", Wx::LIST_FORMAT_LEFT, -1
|
23
|
+
insert_column COLUMNS[:id], "Id", Wx::LIST_FORMAT_LEFT, -1
|
24
|
+
insert_column COLUMNS[:premium], "Premium", Wx::LIST_FORMAT_LEFT, -1
|
25
|
+
insert_column COLUMNS[:ngword], "NG word", Wx::LIST_FORMAT_LEFT, -1
|
26
|
+
load_column_width
|
27
|
+
|
28
|
+
evt_list_col_end_drag(Wx::ID_ANY){|event| on_column_resized(event)}
|
29
|
+
|
30
|
+
evt_list_item_right_click(get_id) {|event| on_list_item_right_click(event)}
|
31
|
+
evt_list_item_activated(Wx::ID_ANY) {|event| on_activated(event)}
|
32
|
+
evt_key_down(){|event| get_parent.on_key_down(event)}
|
33
|
+
|
34
|
+
evt_menu(COLORIZE){show_color_dialog}
|
35
|
+
evt_menu(NAME){show_name_dialog}
|
36
|
+
end
|
37
|
+
|
38
|
+
def load_column_width
|
39
|
+
return unless UserInfo.column_width
|
40
|
+
set_column_width COLUMNS[:no], UserInfo.column_width[:no]
|
41
|
+
set_column_width COLUMNS[:message], UserInfo.column_width[:message]
|
42
|
+
set_column_width COLUMNS[:mail], UserInfo.column_width[:mail]
|
43
|
+
set_column_width COLUMNS[:time], UserInfo.column_width[:time]
|
44
|
+
set_column_width COLUMNS[:name], UserInfo.column_width[:name]
|
45
|
+
set_column_width COLUMNS[:id], UserInfo.column_width[:id]
|
46
|
+
set_column_width COLUMNS[:premium], UserInfo.column_width[:premium]
|
47
|
+
set_column_width COLUMNS[:ngword], UserInfo.column_width[:ngword]
|
48
|
+
end
|
49
|
+
|
50
|
+
def insert_comment comment
|
51
|
+
item = Wx::ListItem.new
|
52
|
+
item.set_data({:id => comment.id,
|
53
|
+
:visitor_id => comment.visitor_id,
|
54
|
+
:listener_id => comment.listener_id})
|
55
|
+
item.set_id 0
|
56
|
+
item.set_column COLUMNS[:no]
|
57
|
+
item.set_text comment.number.to_s
|
58
|
+
# item.set_text_colour Wx::GREEN
|
59
|
+
insert_item(item)
|
60
|
+
|
61
|
+
item.set_column COLUMNS[:message]
|
62
|
+
item.set_text comment.message
|
63
|
+
set_item(item)
|
64
|
+
|
65
|
+
item.set_column COLUMNS[:mail]
|
66
|
+
item.set_text comment.mail
|
67
|
+
set_item(item)
|
68
|
+
|
69
|
+
item.set_column COLUMNS[:time]
|
70
|
+
item.set_text Time.at(comment.commented_at - @base_time).strftime("%M:%S")
|
71
|
+
set_item(item)
|
72
|
+
|
73
|
+
if comment.listener
|
74
|
+
item.set_column COLUMNS[:name]
|
75
|
+
item.set_text comment.listener.name
|
76
|
+
set_item(item)
|
77
|
+
end
|
78
|
+
|
79
|
+
item.set_column COLUMNS[:id]
|
80
|
+
item.set_text comment.user_id || comment.visitor.user_id
|
81
|
+
set_item(item)
|
82
|
+
|
83
|
+
item.set_column COLUMNS[:premium]
|
84
|
+
if comment.owner
|
85
|
+
item.set_text '主'
|
86
|
+
elsif comment.premium
|
87
|
+
item.set_text 'P'
|
88
|
+
elsif comment.command
|
89
|
+
item.set_text 'System'
|
90
|
+
else
|
91
|
+
item.set_text ''
|
92
|
+
end
|
93
|
+
set_item(item)
|
94
|
+
|
95
|
+
if comment.listener
|
96
|
+
if color_index = comment.listener.color_index
|
97
|
+
set_color_to_an_item(0, COLORS[color_index])
|
98
|
+
end
|
99
|
+
elsif comment.visitor
|
100
|
+
if color_index = comment.visitor.color_index
|
101
|
+
set_color_to_an_item(0, COLORS[color_index])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
def on_column_resized event
|
108
|
+
column = event.get_column
|
109
|
+
if UserInfo[:column_width]
|
110
|
+
UserInfo[:column_width][COLUMNS.index(column)] = get_column_width(column)
|
111
|
+
else
|
112
|
+
UserInfo[:column_width] = {
|
113
|
+
:no => get_column_width(COLUMNS[:no]),
|
114
|
+
:message => get_column_width(COLUMNS[:message]),
|
115
|
+
:mail => get_column_width(COLUMNS[:mail]),
|
116
|
+
:time => get_column_width(COLUMNS[:time]),
|
117
|
+
:name => get_column_width(COLUMNS[:name]),
|
118
|
+
:id => get_column_width(COLUMNS[:id]),
|
119
|
+
:premium => get_column_width(COLUMNS[:premium]),
|
120
|
+
:ngword => get_column_width(COLUMNS[:ngword])
|
121
|
+
}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def on_list_item_right_click event
|
126
|
+
menu = Wx::Menu.new
|
127
|
+
menu.append(COLORIZE, "色をつける(&C)", "")
|
128
|
+
menu.append(NAME, "名前をつける(&M)", "")
|
129
|
+
popup_menu(menu, event.get_point)
|
130
|
+
end
|
131
|
+
|
132
|
+
def show_color_dialog
|
133
|
+
dialog = ColorDialog.new(self)
|
134
|
+
color_index = dialog.show_modal
|
135
|
+
item_index = get_selections.first
|
136
|
+
if color_index >= 0 && color_index < COLORS.length
|
137
|
+
on_color_set item_index, color_index
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def show_name_dialog
|
142
|
+
dialog = Wx::TextEntryDialog.new(self, "名前を入力してください")
|
143
|
+
dialog.show_modal
|
144
|
+
item_index = get_selections.first
|
145
|
+
|
146
|
+
item = get_item(item_index)
|
147
|
+
item.set_text_colour(COLORS[WHITE][:color])
|
148
|
+
item.set_column COLUMNS[:name]
|
149
|
+
item.set_text(dialog.get_value)
|
150
|
+
set_item(item)
|
151
|
+
end
|
152
|
+
|
153
|
+
def is_colored? index
|
154
|
+
get_item_background_colour(index) != Wx::NULL_COLOUR &&
|
155
|
+
get_item_background_colour(index) != COLORS[WHITE][:color]
|
156
|
+
end
|
157
|
+
|
158
|
+
def on_activated event
|
159
|
+
item_index = event.get_index
|
160
|
+
if is_colored?(item_index)
|
161
|
+
on_color_unset item_index
|
162
|
+
else
|
163
|
+
on_color_set item_index
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def on_color_set index, color_index=nil
|
168
|
+
color_index = rand(COLORS.length) unless color_index
|
169
|
+
data = get_item_data(index)
|
170
|
+
return unless data
|
171
|
+
|
172
|
+
if data[:listener_id]
|
173
|
+
set_color({:listener_id => data[:listener_id]}, COLORS[color_index])
|
174
|
+
unless ListenersController.set_color_index :id => data[:listener_id],
|
175
|
+
:color_index => color_index
|
176
|
+
Wx::message_box('色設定の保存に失敗しました')
|
177
|
+
end
|
178
|
+
else
|
179
|
+
set_color({:visitor_id => data[:visitor_id]}, COLORS[color_index])
|
180
|
+
unless VisitorsController.set_color_index :id => data[:visitor_id],
|
181
|
+
:color_index => color_index
|
182
|
+
Wx::message_box('色設定の保存に失敗しました')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def on_color_unset index
|
188
|
+
data = get_item_data(index)
|
189
|
+
return unless data
|
190
|
+
|
191
|
+
if data[:listener_id]
|
192
|
+
set_color({:listener_id => data[:listener_id]}, COLORS[WHITE])
|
193
|
+
unless ListenersController.unset_color_index :id => data[:listener_id]
|
194
|
+
Wx::message_box('色設定の消去に失敗しました')
|
195
|
+
end
|
196
|
+
else
|
197
|
+
set_color({:visitor_id => data[:visitor_id]}, COLORS[WHITE])
|
198
|
+
unless VisitorsController.unset_color_index :id => data[:visitor_id]
|
199
|
+
Wx::message_box('色設定の消去に失敗しました')
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def set_color target, color
|
205
|
+
if target[:listener_id]
|
206
|
+
self.each do |index|
|
207
|
+
if get_item_data(index)[:listener_id] == target[:listener_id]
|
208
|
+
set_color_to_an_item(index, color)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
elsif target[:visitor_id]
|
212
|
+
self.each do |index|
|
213
|
+
if get_item_data(index)[:visitor_id] == target[:visitor_id]
|
214
|
+
set_color_to_an_item(index, color)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def set_color_to_an_item index, color
|
221
|
+
set_item_background_colour(index, color[:color])
|
222
|
+
if color[:white_text]
|
223
|
+
get_item(index).set_text_colour(COLORS[WHITE][:color])
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def on_name_set index, name
|
228
|
+
end
|
229
|
+
def on_name_unset index, name
|
230
|
+
end
|
231
|
+
def set_name target, name
|
232
|
+
end
|
233
|
+
def set_name_to_an_item index, name
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
class LivePanel < Wx::Panel
|
238
|
+
attr_reader :title
|
239
|
+
def initialize parent
|
240
|
+
super
|
241
|
+
@title = 'live'
|
242
|
+
@ready = false
|
243
|
+
|
244
|
+
@live_url = Wx::TextCtrl.new(self,
|
245
|
+
:id => Wx::ID_ANY,
|
246
|
+
:style => Wx::TE_PROCESS_ENTER)
|
247
|
+
@list = LiveListCtrl.new(self)
|
248
|
+
|
249
|
+
sizer = Wx::BoxSizer.new(Wx::VERTICAL)
|
250
|
+
sizer.add(@live_url, 0, Wx::ALL|Wx::EXPAND, 10)
|
251
|
+
sizer.add(@list, 1, Wx::ALL|Wx::EXPAND, 10)
|
252
|
+
set_sizer(sizer)
|
253
|
+
sizer.set_size_hints(self)
|
254
|
+
|
255
|
+
@live_url.set_focus
|
256
|
+
|
257
|
+
#@live_url.evt_key_down(){|event| on_key_down(event)}
|
258
|
+
evt_key_down(){|event| on_key_down(event)}
|
259
|
+
|
260
|
+
|
261
|
+
@live_url.evt_text_enter(@live_url.get_id) {|event| on_live_url_enter(event)}
|
262
|
+
end
|
263
|
+
|
264
|
+
def set_index index
|
265
|
+
@index = index
|
266
|
+
end
|
267
|
+
|
268
|
+
def on_new_url
|
269
|
+
@live_url.set_focus
|
270
|
+
@live_url.set_selection(-1, -1)
|
271
|
+
end
|
272
|
+
|
273
|
+
def on_live_url_enter event
|
274
|
+
close
|
275
|
+
|
276
|
+
if live_id = live_id_from_url(@live_url.get_value)
|
277
|
+
@ready = false
|
278
|
+
@live_controller = LiveController.new(live_id)
|
279
|
+
if @live_controller.valid?
|
280
|
+
@list.base_time = @live_controller.base_time
|
281
|
+
get_parent.set_page_text(@index, live_id)
|
282
|
+
|
283
|
+
@list.delete_all_items
|
284
|
+
@live_controller.comments.each do |comment|
|
285
|
+
@list.insert_comment(comment)
|
286
|
+
end
|
287
|
+
|
288
|
+
@ready = true
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def live_id_from_url url
|
294
|
+
if /^\d+$/ =~ url
|
295
|
+
"lv#{url}"
|
296
|
+
elsif /lv\d+/ =~ url
|
297
|
+
$&
|
298
|
+
else
|
299
|
+
nil
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def on_key_down event
|
304
|
+
case event.get_key_code
|
305
|
+
when 0x16E # Ctrl+PageUp
|
306
|
+
if event.control_down
|
307
|
+
get_parent.advance_selection false
|
308
|
+
end
|
309
|
+
when 0x16F # Ctrl+PageDown
|
310
|
+
if event.control_down
|
311
|
+
get_parent.advance_selection true
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def close
|
317
|
+
if @live_controller
|
318
|
+
@live_controller.close
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
def on_update
|
324
|
+
if @ready && @live_controller.live_now?
|
325
|
+
comments = @live_controller.new_comments
|
326
|
+
comments.each do |comment|
|
327
|
+
@list.insert_comment(comment)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Okayu
|
2
|
+
IE_BTN = 250
|
3
|
+
FIREFOX_BTN = 251
|
4
|
+
CHROME_BTN = 252
|
5
|
+
|
6
|
+
ID_PASS_BTN = 255
|
7
|
+
class LoginDialog < Wx::Dialog
|
8
|
+
def initialize parent
|
9
|
+
super(parent, Wx::ID_ANY, "ログイン")
|
10
|
+
@ie_btn = Wx::RadioButton.new(self, :id => IE_BTN, :label => 'Internet Explorer')
|
11
|
+
@firefox_btn = Wx::RadioButton.new(self, :id => FIREFOX_BTN, :label => 'Firefox / Iceweasel')
|
12
|
+
@chrome_btn = Wx::RadioButton.new(self, :id => CHROME_BTN, :label => 'Google Chrome')
|
13
|
+
@id_pass_btn = Wx::RadioButton.new(self, :id => ID_PASS_BTN, :label => 'Id && Password')
|
14
|
+
@mail = Wx::TextCtrl.new self,
|
15
|
+
:id => Wx::ID_ANY,
|
16
|
+
:value => UserInfo.mail || '',
|
17
|
+
:style => Wx::TE_PROCESS_ENTER
|
18
|
+
@password = Wx::TextCtrl.new self,
|
19
|
+
:id => Wx::ID_ANY,
|
20
|
+
:value => UserInfo.password || '',
|
21
|
+
:style => Wx::TE_PROCESS_ENTER | Wx::TE_PASSWORD
|
22
|
+
@ok_btn = Wx::Button.new(self, :id => Wx::ID_OK, :label => 'OK')
|
23
|
+
sizer = Wx::BoxSizer.new Wx::VERTICAL
|
24
|
+
sizer.add(@ie_btn, 0, Wx::ALL | Wx::EXPAND, 10)
|
25
|
+
sizer.add(@firefox_btn, 0, Wx::ALL | Wx::EXPAND, 10)
|
26
|
+
sizer.add(@chrome_btn, 0, Wx::ALL | Wx::EXPAND, 10)
|
27
|
+
sizer.add(@id_pass_btn, 0, Wx::ALL | Wx::EXPAND, 10)
|
28
|
+
sizer.add(@mail, 0, Wx::ALL | Wx::EXPAND, 10)
|
29
|
+
sizer.add(@password, 0, Wx::ALL | Wx::EXPAND, 10)
|
30
|
+
sizer.add(@ok_btn, 0, Wx::ALL | Wx::EXPAND, 10)
|
31
|
+
set_sizer(sizer)
|
32
|
+
sizer.set_size_hints(self)
|
33
|
+
sizer.fit(self)
|
34
|
+
|
35
|
+
case UserInfo.login
|
36
|
+
when :ie
|
37
|
+
@ie_btn.set_value true
|
38
|
+
when :firefox
|
39
|
+
@firefox_btn.set_value true
|
40
|
+
when :chrome
|
41
|
+
@chrome_btn.set_value true
|
42
|
+
when :id_pass
|
43
|
+
@id_pass_btn.set_value true
|
44
|
+
end
|
45
|
+
@ok_btn.set_focus
|
46
|
+
|
47
|
+
@mail.evt_text_enter(@mail.get_id){ on_enter }
|
48
|
+
@password.evt_text_enter(@password.get_id){ on_enter}
|
49
|
+
|
50
|
+
@ok_btn.evt_button(Wx::ID_OK){|event| on_ok(event)}
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_enter
|
54
|
+
UserInfo.login = :id_pass
|
55
|
+
UserInfo.mail = @mail.get_value
|
56
|
+
UserInfo.password = @password.get_value
|
57
|
+
Client.connect :mail => @mail.get_value, :password => @password.get_value
|
58
|
+
end_modal 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def on_ok event
|
62
|
+
if @ie_btn.get_value
|
63
|
+
UserInfo.login = :ie
|
64
|
+
Client.connect :cookie => IECookieThief.get(:host => '.nicovideo.jp', :name => 'user_session')
|
65
|
+
end_modal 1
|
66
|
+
elsif @firefox_btn.get_value
|
67
|
+
UserInfo.login = :firefox
|
68
|
+
Client.connect :cookie => FirefoxCookieThief.get(:host => '.nicovideo.jp', :name => 'user_session')
|
69
|
+
end_modal 1
|
70
|
+
elsif @firefox_btn.get_value
|
71
|
+
UserInfo.login = :chrome
|
72
|
+
Client.connect :cookie => ChromeCookieThief.get(:host => '.nicovideo.jp', :name => 'user_session')
|
73
|
+
end_modal 1
|
74
|
+
else
|
75
|
+
on_enter
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Okayu
|
2
|
+
class MainPanel < Wx::Panel
|
3
|
+
attr_reader :timer
|
4
|
+
def initialize(frame, x, y, w, h)
|
5
|
+
super(frame, -1, Wx::Point.new(x, y), Wx::Size.new(w, h))
|
6
|
+
@notebook = Wx::Notebook.new self,
|
7
|
+
:id =>ID_NOTEBOOK,
|
8
|
+
:pos => Wx::Point.new(x, y),
|
9
|
+
:size => Wx::Size.new(w, h)
|
10
|
+
# panel = LivePanel.new(@notebook)
|
11
|
+
# @notebook.add_page(panel, panel.title, TRUE)
|
12
|
+
create_tab
|
13
|
+
|
14
|
+
@timer = Wx::Timer.new(self, Wx::ID_ANY)
|
15
|
+
@timer.start
|
16
|
+
evt_timer(@timer.get_id) {|event| on_update}
|
17
|
+
|
18
|
+
evt_size{|event| on_size(event)}
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_update
|
22
|
+
@notebook.each_page do |page|
|
23
|
+
page.on_update
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_size event
|
28
|
+
if @notebook
|
29
|
+
size = get_client_size
|
30
|
+
@notebook.set_dimensions(2, 2, (size.get_width - 4), (size.get_height - 4))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_tab
|
35
|
+
panel = LivePanel.new(@notebook)
|
36
|
+
@notebook.add_page(panel, panel.title, TRUE)
|
37
|
+
@notebook.get_current_page.set_index(@notebook.get_selection)
|
38
|
+
end
|
39
|
+
|
40
|
+
def close_tab
|
41
|
+
@notebook.get_current_page.close
|
42
|
+
@notebook.delete_page(@notebook.get_selection)
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_current_page
|
46
|
+
@notebook.get_current_page
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|