ratchet 0.3.0

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.
Files changed (49) hide show
  1. data/gem_bin/ratchet +23 -0
  2. data/lib/ratchet.rb +613 -0
  3. data/lib/ratchet/aliases.rb +106 -0
  4. data/lib/ratchet/bufferparser.rb +409 -0
  5. data/lib/ratchet/commandbuffer.rb +66 -0
  6. data/lib/ratchet/commandparser.rb +668 -0
  7. data/lib/ratchet/configuration.rb +278 -0
  8. data/lib/ratchet/connections.rb +403 -0
  9. data/lib/ratchet/constants.rb +111 -0
  10. data/lib/ratchet/contrib/instance_exec.rb +21 -0
  11. data/lib/ratchet/eventparser.rb +486 -0
  12. data/lib/ratchet/gtk/bufferlistview.rb +514 -0
  13. data/lib/ratchet/gtk/bufferview.rb +167 -0
  14. data/lib/ratchet/gtk/configwindow.rb +229 -0
  15. data/lib/ratchet/gtk/connectionwindow.rb +218 -0
  16. data/lib/ratchet/gtk/keybinding.rb +356 -0
  17. data/lib/ratchet/gtk/linkwindow.rb +137 -0
  18. data/lib/ratchet/gtk/mainwindow.rb +504 -0
  19. data/lib/ratchet/gtk/networkpresenceconf.rb +567 -0
  20. data/lib/ratchet/gtk/pluginconfig.rb +94 -0
  21. data/lib/ratchet/gtk/pluginwindow.rb +146 -0
  22. data/lib/ratchet/gtk/userlistview.rb +161 -0
  23. data/lib/ratchet/help.rb +64 -0
  24. data/lib/ratchet/items.rb +271 -0
  25. data/lib/ratchet/lines.rb +63 -0
  26. data/lib/ratchet/networks.rb +652 -0
  27. data/lib/ratchet/plugins.rb +616 -0
  28. data/lib/ratchet/queue.rb +47 -0
  29. data/lib/ratchet/ratchet-version.rb +21 -0
  30. data/lib/ratchet/replies.rb +134 -0
  31. data/lib/ratchet/replyparser.rb +441 -0
  32. data/lib/ratchet/tabcomplete.rb +98 -0
  33. data/lib/ratchet/users.rb +237 -0
  34. data/lib/ratchet/utils.rb +178 -0
  35. data/share/defaults.yaml +169 -0
  36. data/share/glade/config.glade +2634 -0
  37. data/share/glade/connect.glade +950 -0
  38. data/share/glade/keybindings.glade +109 -0
  39. data/share/glade/linkwindow.glade +188 -0
  40. data/share/glade/mainwindow.glade +335 -0
  41. data/share/glade/network-presences.glade +1373 -0
  42. data/share/glade/pluginconf.glade +97 -0
  43. data/share/glade/plugins.glade +360 -0
  44. data/share/plugins/colorewrite.rb +193 -0
  45. data/share/plugins/highlighter.rb +115 -0
  46. data/share/plugins/mpdplay.rb +123 -0
  47. data/share/plugins/numberswitcher.rb +30 -0
  48. data/share/plugins/sysinfo.rb +82 -0
  49. metadata +96 -0
@@ -0,0 +1,271 @@
1
+ =begin
2
+ This file is part of the Ratchet project, a client for Icecap.
3
+ Copyright (C) 2005-6 Andrew Thompson
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program; if not, write to the Free Software
17
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ =end
19
+
20
+ #### items.rb ####
21
+ # Ugh, this file still exists. Its function is to store the network-gateway-presence relations
22
+ # I really would like to unify this with the actual buffers, but its tricker than I'd hoped
23
+ ####
24
+
25
+ #TODO: get rid this damndable thing, or at least make it a bit nicer, but its not massively important
26
+
27
+ module Ratchet
28
+ class Item
29
+ def <=>(object)
30
+ return 0 unless @name
31
+ return 1 unless object
32
+ return @name<=>object.name
33
+ end
34
+
35
+ #~ def ==(object)
36
+ #~ return nil unless object
37
+ #~ return @name == object.name
38
+ #~ end
39
+ end
40
+
41
+ class Network < Item
42
+ attr_reader :name, :protocol
43
+ attr_accessor :charset
44
+ def initialize(name, protocol)
45
+ @name = name
46
+ @protocol = protocol
47
+ @gateways = ItemList.new(Gateway)
48
+ @presences = ItemList.new(Presence)
49
+ end
50
+
51
+ def add_gateway(host, port=nil)
52
+ return @gateways.add(host, port)
53
+ end
54
+
55
+ def gateways
56
+ return @gateways
57
+ end
58
+
59
+ def add_presence(name)
60
+ return @presences.add(name)
61
+ end
62
+
63
+ def presences
64
+ return @presences
65
+ end
66
+
67
+ def presences=(list)
68
+ @presences = list
69
+ end
70
+
71
+ def gateways=(list)
72
+ @gateways = list
73
+ end
74
+
75
+ def diff(object)
76
+ settings = []
77
+ if object.charset != @charset
78
+ settings.push('charset='+@charset.to_s)
79
+ end
80
+
81
+ if settings.empty?
82
+ return nil
83
+ else
84
+ return settings.join(';')
85
+ end
86
+ end
87
+
88
+ def update(object)
89
+ @charset = object.charset
90
+ end
91
+
92
+ def create
93
+ string = 'network add;network='+@name+';protocol='+@protocol
94
+ if @charset
95
+ string += ';charset='+@charset
96
+ end
97
+ return string
98
+ end
99
+
100
+ end
101
+
102
+ class Protocol < Item
103
+ attr_reader :name, :charsets_in, :charset_out
104
+ def initialize(name, charset_in, charset_out)
105
+ @name = name
106
+ @charsets_in = charset_in.split(' ')
107
+ @charset_out = charset_out
108
+ end
109
+ end
110
+
111
+ class Gateway < Item
112
+ attr_reader :network
113
+ attr_accessor :host, :port, :password, :priority
114
+ def initialize(host, port=nil)
115
+ @host = host
116
+ @port = port
117
+ end
118
+
119
+ def name
120
+ return @host
121
+ end
122
+
123
+ def diff(object)
124
+ settings = []
125
+ settings.push('port='+@port.to_s) if object.port != @port
126
+ settings.push('password='+@password.to_s) if object.password != @password
127
+ #settings.push('port='+port) if object.port != @port
128
+
129
+ if settings.empty?
130
+ return nil
131
+ else
132
+ return settings.join(';')
133
+ end
134
+ end
135
+
136
+ def update(object)
137
+ @port = object.port
138
+ @password = object.password
139
+ @priority = object.priority
140
+ end
141
+
142
+ def create(network)
143
+ string = 'gateway add;host='+@host+';network='+network
144
+ if @port
145
+ string += ';port='+@port
146
+ end
147
+ if @password
148
+ string += ';password='+@password
149
+ end
150
+ return string
151
+ end
152
+
153
+ #~ def ==(object)
154
+ #~ return false unless object
155
+ #~ x = (@host == object.host and @port == object.port)
156
+ #~ return x
157
+ #~ end
158
+ end
159
+
160
+ class Presence < Item
161
+ attr_reader :name
162
+ attr_accessor :autoconnect
163
+ def initialize(name)
164
+ @name = name
165
+ end
166
+
167
+ def diff(object)
168
+ settings = []
169
+ if object.autoconnect != @autoconnect
170
+ if @autoconnect
171
+ settings.push('autoconnect')
172
+ else
173
+ settings.push('autoconnect=')
174
+ end
175
+ end
176
+
177
+ if settings.empty?
178
+ return nil
179
+ else
180
+ return settings.join(';')
181
+ end
182
+ end
183
+
184
+ def update(object)
185
+ @autoconnect = object.autoconnect
186
+ end
187
+
188
+ def create(network)
189
+ string = 'presence add;mypresence='+@name+';network='+network
190
+ return string
191
+ end
192
+ end
193
+
194
+ class ItemList
195
+ attr_reader :list
196
+ def initialize(classtype)
197
+ @classtype = classtype
198
+ @list = []
199
+ end
200
+
201
+ def [](key)
202
+ results = []
203
+ @list.each do |item|
204
+ if item.name == key
205
+ return item
206
+ end
207
+ end
208
+
209
+ return nil
210
+
211
+ #~ if results.length == 1
212
+ #~ return results[0]
213
+ #~ elsif results.length > 1
214
+ #~ return results
215
+ #~ else
216
+ #~ return nil
217
+ #~ end
218
+ end
219
+
220
+ def []=(key, replacement)
221
+ results = []
222
+ @list.each do |item|
223
+ if item.name == key
224
+ return item.update(replacement)
225
+ end
226
+ end
227
+
228
+ return nil
229
+ end
230
+
231
+ #~ def exists?(*args)
232
+ #~ item = @classtype.new(*args)
233
+ #~ return includes?(item)
234
+ #~ end
235
+
236
+ def add(*args)
237
+ item = @classtype.new(*args)
238
+ return nil if self.include?(item)
239
+ @list.push(item)
240
+ return item
241
+ end
242
+
243
+ def insert(item)
244
+ return nil if self.include?(item)
245
+ @list.push(item)
246
+ return item
247
+ end
248
+
249
+ def remove(item)
250
+ @list.delete(item)
251
+ end
252
+
253
+ def include?(item)
254
+ @list.each do |i|
255
+ if i.name == item.name
256
+ return true
257
+ end
258
+ end
259
+ return false
260
+ end
261
+
262
+ def sort!
263
+ @list.sort!
264
+ return @list
265
+ end
266
+
267
+ def sort
268
+ return @list.sort
269
+ end
270
+ end
271
+ end
@@ -0,0 +1,63 @@
1
+ =begin
2
+ This file is part of the Ratchet project, a client for Icecap.
3
+ Copyright (C) 2005-6 Andrew Thompson
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program; if not, write to the Free Software
17
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ =end
19
+
20
+ #### lines.rb ####
21
+ # A simple hash derivative that internally converts to symbols
22
+ ####
23
+
24
+ #TODO: is this *really* needed? Seems like I was just anxious to try some subclassing
25
+
26
+ module Ratchet
27
+ #derive from Hash and simply convert all keys to symbols for internal storage
28
+ #also convert all lookup keys to symbols
29
+ class Line < Hash
30
+ #convert keys to symbols
31
+ def self.[](*args)
32
+
33
+ if args[0].class == Hash
34
+ new = {}
35
+ args[0].each do |k,v|
36
+ new[k.to_sym] = v
37
+ end
38
+
39
+ args[0] = new
40
+ else
41
+ x = true
42
+ args.each_with_index do |k, i|
43
+ if x
44
+ args[i] = k.to_sym
45
+ end
46
+ x = !x
47
+ end
48
+ end
49
+
50
+ super(*args)
51
+ end
52
+
53
+ def[]=(key, value)
54
+ key = key.to_sym
55
+ super(key, value)
56
+ end
57
+
58
+ def [](key)
59
+ key = key.to_sym
60
+ super(key)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,652 @@
1
+ =begin
2
+ This file is part of the Ratchet project, a client for Icecap.
3
+ Copyright (C) 2005-6 Andrew Thompson
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation; either version 2 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program; if not, write to the Free Software
17
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ =end
19
+
20
+ #### networks.rb ####
21
+ # Provides the M and C of the buffers' MVC
22
+ # also contains the channel, network, chat and console objects
23
+ ####
24
+
25
+ module Ratchet
26
+ #hopefully, the program will only need access to the controller, so wrap all the useful stuff here?
27
+ class BufferListController
28
+ #include PluginAPI
29
+ #include BufferParser
30
+ attr_reader :view, :config, :window, :model
31
+ def initialize(window, console=false)
32
+ @window = window
33
+ @config = window.config
34
+ @model = BufferListModel.new(self, console)
35
+ set_sort(BufferListModel::HIERARCHICAL)
36
+ set_comparator(BufferListModel::INSENSITIVE)
37
+ #initialize the view with the references it needs
38
+ # @view = TreeBufferListView.new(self, @model)
39
+ # @model.view = view #give the model a reference to the view
40
+ recreate
41
+ @window.switch_buffer(@model.console) if @model.console
42
+ end
43
+
44
+ def console
45
+ @model.console
46
+ end
47
+
48
+ def recreate
49
+ if @config['tablisttype'] == 'button' and @view.class.superclass != BoxBufferListView
50
+ puts 'new buttonbox'
51
+ @view = HBoxBufferListView.new(self, @model)
52
+ elsif @config['tablisttype'] == 'treeview' and @view.class != TreeBufferListView
53
+ puts 'new treeview'
54
+ @view = TreeBufferListView.new(self, @model)
55
+ end
56
+ @model.view = @view
57
+ end
58
+
59
+ #most of these wrap model functions...
60
+ #~ def add_network(name, presence)
61
+ #~ @model.add_network(name, presence)
62
+ #~ end
63
+
64
+ def next_buffer
65
+ index = @model.structure.index(active)+1
66
+ index %= @model.structure.length
67
+ set_active(@model.structure[index])
68
+ end
69
+
70
+ def prev_buffer
71
+ index = @model.structure.index(active)-1
72
+ set_active(@model.structure[index])
73
+ end
74
+
75
+ def connect(buffer)
76
+ if buffer.respond_to? 'connect'
77
+ #buffer.connect
78
+ @model.sort
79
+ set_active(buffer) if buffer.connected?
80
+ end
81
+ end
82
+
83
+ def join(buffer)
84
+ if buffer.respond_to? 'join'
85
+ #buffer.connect
86
+ @model.sort
87
+ set_active(buffer) if buffer.joined?
88
+ end
89
+ end
90
+
91
+ def add_buffer(buffer)
92
+ return unless buffer
93
+ # puts 'adding to window'
94
+ buffer.controller = self
95
+ case buffer
96
+ when NetworkBuffer
97
+ # puts 'network'
98
+ @model.add_network(buffer)
99
+ when ChannelBuffer
100
+ @model.add_channel(buffer)
101
+ when ChatBuffer
102
+ @model.add_chat(buffer)
103
+ set_active(buffer)
104
+ end
105
+ end
106
+
107
+ #~ def add_chat(name, network)
108
+ #~ @model.add_chat(name, network)
109
+ #~ end
110
+
111
+ #~ def add_channel(name, network)
112
+ #~ @model.add_channel(name, network)
113
+ #~ end
114
+
115
+ def find_network(name, presence)
116
+ @model.find_network(name, presence)
117
+ end
118
+
119
+ #here we provide a unified function for looking up channels/chats
120
+ def find_chat(*args)
121
+ if args.length == 2
122
+ @model.find_chat_in_network(*args)
123
+ elsif args.length == 3
124
+ @model.find_chat(*args)
125
+ else
126
+ raise ArgumentError, 'function takes 2 or 3 arguments'
127
+ end
128
+ end
129
+
130
+ def find_channel(*args)
131
+ if args.length == 2
132
+ @model.find_channel_in_network(*args)
133
+ elsif args.length == 3
134
+ @model.find_channel(*args)
135
+ else
136
+ raise ArgumentError, 'function takes 2 or 3 arguments'
137
+ end
138
+ end
139
+
140
+ def close_buffer(buffer)
141
+ return unless buffer
142
+ case buffer
143
+ when NetworkBuffer
144
+ #puts 'network'
145
+ #@model.add_network(buffer)
146
+ when ChannelBuffer
147
+ #@model.add_channel(buffer)
148
+ when ChatBuffer
149
+ @model.remove_chat(buffer)
150
+ @window.main.remove_buffer(buffer)
151
+ end
152
+ @model.sort
153
+ @window.switch_buffer(@model.active)
154
+ end
155
+
156
+ def include?(object)
157
+ # puts networks.include?(object)
158
+ # puts channels.include?(object)
159
+ # puts chats.include?(object)
160
+ # puts console == object
161
+ networks.include?(object) || channels.include?(object) || chats.include?(object) || console == object
162
+ end
163
+
164
+ def active
165
+ @model.active
166
+ end
167
+
168
+ def channels
169
+ @model.channels
170
+ end
171
+
172
+ def networks
173
+ @model.networks
174
+ end
175
+
176
+ def chats
177
+ @model.chats
178
+ end
179
+
180
+ def remove_network(obj)
181
+ @model.remove_network(obj)
182
+ end
183
+
184
+ def remove_channel(obj)
185
+ @model.remove_channel(obj)
186
+ end
187
+
188
+ def remove_chat(obj)
189
+ @model.remove_chat(obj)
190
+ end
191
+
192
+ #do some prefunctory checking here...
193
+ def set_sort(block)
194
+ return if @model.sort and @model.sort == block
195
+ @model.set_sort(block)
196
+ end
197
+
198
+ def set_comparator(block)
199
+ return if @model.comp and @model.comp == block
200
+ @model.set_comparator(block)
201
+ end
202
+
203
+
204
+ def set_status(object, status)
205
+ @model.set_status(object, status) if @model
206
+ end
207
+
208
+ def set_active(object)
209
+ #if the model includes the object and the model isn't already set this as active
210
+ if @model.structure.include? object and @model.active != object
211
+ @model.set_active(object)
212
+ end
213
+ #switch the window to display this tab
214
+ @window.switch_buffer(object) unless @window.currentbuffer == object
215
+ end
216
+ end
217
+
218
+ #model, so all the data munging here, the controller should protect us from too much invalid nonsense
219
+ class BufferListModel
220
+ attr_reader :structure, :view, :sort, :comp, :active, :console, :networks, :channels, :chats
221
+
222
+ #ooh look, the layout/sort algorithms are pluggable. me++
223
+ HIERARCHICAL = Proc.new do |console, networks, channels, chats, comp|
224
+ res= []
225
+ res << console if console
226
+ networks.sort(&comp).each do |n|
227
+ res << n
228
+ channels.select{|c| c.network == n}.sort(&comp).each{|c| res << c}
229
+ chats.select{|c| c.network == n}.sort(&comp).each{|c| res << c}
230
+ end
231
+ res
232
+ end
233
+
234
+ FLAT = Proc.new do |console, networks, channels, chats, comp|
235
+ res= []
236
+ res << console if console
237
+ channels.sort(&comp).each{|x| res << x}
238
+ chats.sort(&comp).each{|x| res << x}
239
+ res
240
+ end
241
+
242
+ SENSITIVE = Proc.new{|x, y| x.name<=>y.name}
243
+ INSENSITIVE = Proc.new{|x, y| x.name.downcase<=>y.name.downcase}
244
+
245
+ def initialize(controller, console=false)
246
+ @controller = controller
247
+ @networks = []
248
+ @channels = []
249
+ @chats = []
250
+ @structure = []
251
+ if console
252
+ @console = console#ConsoleBuffer.new(@controller)
253
+ console.add_controller(@controller)
254
+ set_active(@console)
255
+ end
256
+ end
257
+
258
+ def view=(view)
259
+ @view = view
260
+ sort
261
+ view.fill unless view.filled?
262
+ end
263
+
264
+ def set_status(object, status)
265
+ # puts object, status, object.status
266
+ object.status = status if status > object.status or status == 0
267
+ @view.update_status(object)
268
+ end
269
+
270
+ #set the block to use to sort the networks/channels/chats
271
+ def set_sort(block)
272
+ @sort = block
273
+ sort
274
+ end
275
+
276
+ #set the block used to compare networks/channels/chats
277
+ def set_comparator(block)
278
+ @comp = block
279
+ sort
280
+ end
281
+
282
+ #updates the view, then stores the new active
283
+ def set_active(obj)
284
+ @active.set_status(0) if @active
285
+ # obj.set_status(0)
286
+ # @view.update_status(obj) if @view
287
+ @view.set_active(obj) if @view
288
+ @active = obj
289
+ end
290
+
291
+ def add_network(network)
292
+ @networks << network
293
+ sort
294
+ #set_active(network)
295
+ end
296
+
297
+ def add_channel(channel)
298
+ @channels << channel
299
+ sort
300
+ #set_active(channel)
301
+ end
302
+
303
+ def add_chat(chat)
304
+ @chats << chat
305
+ sort
306
+ #set_active(chat)
307
+ end
308
+
309
+ #~ #takes a name string
310
+ #~ def add_network(name, presence)
311
+ #~ unless network = @networks.detect{|n| n.name == name and n.presence == presence}
312
+ #~ network = NetworkBuffer.new(@controller, name, presence)
313
+ #~ @networks << network
314
+ #~ end
315
+ #~ sort
316
+ #~ network
317
+ #~ end
318
+
319
+ #~ def add_channel(name, network)
320
+ #~ unless channel = @channels.detect{|c| c.name == name and c.network = network}
321
+ #~ channel = ChannelBuffer.new(@controller, name, network)
322
+ #~ @channels << channel
323
+ #~ end
324
+ #~ sort
325
+ #~ channel
326
+ #~ end
327
+
328
+ #~ def add_chat(name, network)
329
+ #~ unless chat = @chats.detect{|c| c.name == name and c.network = network}
330
+ #~ chat = ChatBuffer.new(@controller, name, network)
331
+ #~ @chats << chat
332
+ #~ end
333
+ #~ sort
334
+ #~ set_active(chat)
335
+ #~ chat
336
+ #~ end
337
+
338
+
339
+
340
+ #takes a Network object
341
+ def remove_network(network)
342
+ # puts network.class
343
+ @networks.delete(network)
344
+ @channels.delete_if{|x| x.network == network}
345
+ @chats.delete_if{|x| x.network == network}
346
+ sort
347
+ end
348
+
349
+ #takes a Channel object
350
+ def remove_channel(channel)
351
+ @channels.delete(channel)
352
+ sort
353
+ end
354
+
355
+ #takes a Chat object
356
+ def remove_chat(chat)
357
+ @chats.delete(chat)
358
+ sort
359
+ end
360
+
361
+ def find_network(name, presence)
362
+ @networks.detect{|n| n.name == name and n.presence == presence}
363
+ end
364
+
365
+ def find_channel(networkname, presence, channelname)
366
+ res = nil
367
+ if network = find_network(networkname, presence)
368
+ res = find_channel_in_network(network, channelname)
369
+ end
370
+ return res
371
+ end
372
+
373
+ def find_chat(networkname, presence, chatname)
374
+ res = nil
375
+ if network = find_network(networkname, presence)
376
+ res = find_chat_in_network(network, chatname)
377
+ end
378
+ return res
379
+ end
380
+
381
+ #needs a network object
382
+ def find_channel_in_network(network, name)
383
+ @channels.detect{|x| x.network == network and x.name == name}
384
+ end
385
+
386
+ def find_chat_in_network(network, name)
387
+ @chats.detect{|x| x.network == network and x.name == name}
388
+ end
389
+
390
+ def sort
391
+ return unless @sort and @comp
392
+ oldstructure = @structure
393
+ @structure = @sort.call(@console, @networks.select{|x| x.buffer}, @channels.select{|x| x.buffer}, @chats.select{|x| x.buffer}, @comp)
394
+ return @structure unless @view
395
+
396
+ #check if its an add or a delete
397
+ #TODO - renames, mainly for chats
398
+ if oldstructure.length < @structure.length
399
+ (@structure - oldstructure).each do |x|
400
+ index = @structure.index(x)
401
+ if index == 0
402
+ obj = nil
403
+ else
404
+ obj = @structure[index-1]
405
+ end
406
+ #insert passes the object to be inserted and the object that comes before it
407
+ #this makes it easier to determine where to insert (I think)
408
+ @view.insert(x, obj)
409
+ end
410
+ elsif oldstructure.length > @structure.length
411
+ (oldstructure - @structure).each do |x|
412
+ @view.remove(x)
413
+ end
414
+ end
415
+
416
+ #switch the active tab if the active one got removed
417
+ unless @structure.include? @active
418
+ if oldstructure.index(@active) == 0
419
+ set_active(@structure[0])
420
+ elsif oldstructure.include? @active
421
+ #try to go to the next channel, but don't try too hard
422
+ if oldstructure[oldstructure.index(@active)+1].kind_of? ChannelBuffer
423
+ set_active(oldstructure[oldstructure.index(@active)+1])
424
+ else
425
+ set_active(oldstructure[oldstructure.index(@active)-1])
426
+ end
427
+ end
428
+ end
429
+ @structure.uniq
430
+ end
431
+ end
432
+
433
+ class Buffer
434
+ include PluginAPI
435
+ include BufferParser
436
+ include TabCompleteModule
437
+ attr_reader :buffer, :name, :commandbuffer, :controller, :main
438
+ attr_accessor :status
439
+ def initialize(*args)
440
+ @controller = nil
441
+ @main = args[-1]
442
+ @config = @main.config
443
+ @status = 0
444
+ end
445
+
446
+ def controller=(controller)
447
+ @controller = controller
448
+ @config = controller.config
449
+ @main = @controller.window.main
450
+ end
451
+
452
+ def set_status(status)
453
+ @controller.set_status(self, status)
454
+ end
455
+
456
+ def close
457
+ @buffer = nil
458
+ @controller.close_buffer(self)
459
+ end
460
+ end
461
+
462
+ class ConsoleBuffer < Buffer
463
+ def initialize(main)
464
+ @main = main
465
+ @config = @main.config
466
+ @controllers = []
467
+ @buffer = BufferView.new(@config)
468
+ @name = 'Console'
469
+ @commandbuffer = CommandBuffer.new(@config)
470
+ @status = 0
471
+ end
472
+
473
+ def add_controller(controller)
474
+ @controllers.push(controller)
475
+ end
476
+
477
+ def set_status(status)
478
+ @controllers.each{|x| x.set_status(self, status)}
479
+ end
480
+ end
481
+
482
+ class NetworkBuffer < Buffer
483
+ attr_reader :presence, :users
484
+ #attr_writer :username
485
+ def initialize(name, presence, main)
486
+ super
487
+ @name = name
488
+ @presence = presence
489
+ @username = presence
490
+ @users = UserList.new
491
+ end
492
+
493
+ def username
494
+ @username
495
+ end
496
+
497
+ def username=(username)
498
+ @username = username
499
+ @controller.window.get_username if @controller.active.respond_to? :network and @controller.active.network == self
500
+ end
501
+
502
+ def network
503
+ self
504
+ end
505
+
506
+ def connect
507
+ @connected = true
508
+ @buffer ||= BufferView.new(@config)
509
+ @commandbuffer ||= CommandBuffer.new(@config)
510
+ @controller.connect(self)
511
+ end
512
+
513
+ def connected?
514
+ @connected
515
+ end
516
+
517
+ def disconnect
518
+ @connected = nil
519
+ # @commandbuffer = nil
520
+ end
521
+
522
+ def close
523
+ disconnect
524
+ @commandbuffer = nil
525
+ super
526
+ end
527
+
528
+ def reconnect
529
+ #TODO
530
+ end
531
+
532
+ def identifier_string
533
+ "network=#{@name};mypresence=#{@presence}"
534
+ end
535
+ end
536
+
537
+ class ChatBuffer < Buffer
538
+ attr_reader :network, :name, :presence, :users
539
+ def initialize(name, network, main)
540
+ super
541
+ @name = name
542
+ @network = network
543
+ @presence = network.presence
544
+ @buffer = BufferView.new(@config)
545
+ @users = UserList.new
546
+ @commandbuffer = CommandBuffer.new(@config)
547
+
548
+ #fill the userlist... there's only 2 people in a chat
549
+ @users.add(network.users[username])
550
+ @users.add(network.users[name])
551
+ end
552
+
553
+ def username
554
+ @network.username
555
+ end
556
+
557
+ def identifier_string
558
+ "network=#{@network.name};mypresence=#{@presence};presence=#{@name}"
559
+ end
560
+ end
561
+
562
+ class ChannelBuffer < Buffer
563
+ attr_reader :network, :name, :presence, :users, :topic, :userlistview
564
+ attr_accessor :eventsync, :usersync
565
+ def initialize(name, network, main)
566
+ super
567
+ @topic = ''
568
+ @name = name
569
+ @network = network
570
+ @presence = network.presence
571
+ @eventsync = @usersync = false
572
+ end
573
+
574
+ def topic=(topic)
575
+ @topic = topic
576
+ @controller.window.update_topic if @controller.active == self
577
+ end
578
+
579
+ def username
580
+ @network.username
581
+ end
582
+
583
+ def join
584
+ @joined = true
585
+ @buffer ||= BufferView.new(@config)
586
+ @users ||= ChannelUserList.new
587
+ @userlistview ||= UserListView.new(self)
588
+ @users.view ||= @userlistview
589
+ @commandbuffer ||= CommandBuffer.new(@config)
590
+ @controller.join(self)
591
+ #@userlist = SomeUnwrittenClass.new
592
+ end
593
+
594
+ def joined?
595
+ @joined
596
+ end
597
+
598
+ def close
599
+ @commandbuffer = nil
600
+ @userlistview = nil
601
+ part
602
+ super
603
+ end
604
+
605
+ def part
606
+ @joined = false
607
+ @users = nil
608
+ @userlistview.clear if @userlistview
609
+ #@users.clear
610
+ end
611
+ def identifier_string
612
+ "network=#{@network.name};mypresence=#{@presence};channel=#{@name}"
613
+ end
614
+ end
615
+ end
616
+
617
+ #******some testing******
618
+
619
+ #~ f = NetworkController.new(nil, true)
620
+ #~ f.set_sort(NetworkModel::HIERARCHICAL)
621
+ #~ f.set_comparator(NetworkModel::INSENSITIVE)
622
+ #~ n = f.add_network('Freenode', 'Vagabond')
623
+ #~ f.add_channel('#icecap', n)
624
+ #~ f.add_channel('#aardvark', n)
625
+ #~ f.add_chat('foo', n)
626
+ #~ f.add_channel('#zztop', n)
627
+ #~ n = f.add_network('EFNet', 'Vagabond')
628
+ #~ f.add_channel('#dragonflybsd', n)
629
+ #~ f.add_channel('#Foo', n)
630
+ #~ n = f.add_network('arpanet', 'Vagabond')
631
+
632
+ #~ puts f.find_network('EFNet', 'Vagabond')
633
+ #~ puts f.find_channel('Freenode', 'Vagabond', '#icecap')
634
+ #~ puts f.find_chat('Freenode', 'Vagabond', 'foo')
635
+
636
+ #~ #f.structure.each{|x| puts x.name}
637
+ #~ Gtk::Window.new.add(f.view.widget).show_all
638
+
639
+ #~ Thread.new do
640
+ #~ sleep 4
641
+ #~ f.remove_network(f.find_network('arpanet', 'Vagabond'))
642
+ #~ f.remove_channel(f.find_channel('Freenode', 'Vagabond', '#icecap'))
643
+ #~ end
644
+
645
+ #~ Gtk::main
646
+
647
+ #~ f.sort.each{|x| puts x.name}
648
+
649
+ #~ f.remove_channel(f.find_channel('Freenode', 'Vagabond', '#icecap'))
650
+ #~ puts
651
+
652
+ #~ f.sort.each{|x| puts x.name}