jota 0.8.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.
data/lib/clip_array.rb ADDED
@@ -0,0 +1,393 @@
1
+
2
+ # $Id: clip_array.rb 37 2009-02-09 10:06:02Z dz $
3
+
4
+ # if you use vim and don't like folds type zR
5
+
6
+
7
+ require 'app_error'
8
+ require 'clip'
9
+ require 'helper'
10
+ require 'preferences'
11
+
12
+ class ClipArray < Array
13
+
14
+ # Instance Variables
15
+ # self Array [Clip.new] the array of clips
16
+ # current_index Integer 0 the position of current clip
17
+ # pref Preferences Preferences.defaults preferences object
18
+ # file_and_path String ni name and path of current file
19
+ # filename String ni name of current file
20
+ # dirname String ni directory of current file
21
+ # file File ni current File object
22
+ # autosave_thread Thread nil thread for autosaving
23
+
24
+
25
+ attr_reader :current_index, :file, :filename, :dirname, :file_and_path
26
+ attr_accessor :pref
27
+
28
+ # Clear array and reset index
29
+ def clear
30
+ #{{{1
31
+ super
32
+ @current_index = -1
33
+ end #}}}1
34
+
35
+ # Clear array and create one empty clip
36
+ def clear1
37
+ #{{{1
38
+ clear
39
+ self << Clip.new
40
+ end #}}}1
41
+
42
+ def initialize
43
+ #{{{1
44
+ clear
45
+ @file = nil
46
+ @filename = nil
47
+ @pref = Preferences.defaults
48
+ @autosave_thread = nil
49
+ print_verbose "initializing clip array"
50
+ end #}}}1
51
+
52
+ def <<(clip)
53
+ #{{{1
54
+ push(clip)
55
+ @current_index = length-1
56
+ return self
57
+ end #}}}1
58
+
59
+ def set_file(file,file_and_path)
60
+ #{{{1
61
+ @file = file
62
+ @file_and_path = file_and_path
63
+ @filename = File.basename(file_and_path)
64
+ @dirname = File.dirname(file_and_path)
65
+ end #}}}1
66
+
67
+ #
68
+ # Export
69
+ #
70
+
71
+ #def save_as_mbox(filename)
72
+ ##{{{1
73
+ # filename = get_filename(filename,:save)
74
+ #
75
+ # puts "# saving clips to '#{filename}', format mbox" if $VERBOSE
76
+ #
77
+ # f = open(filename,"w")
78
+ # write_mbox(f)
79
+ # self.each do | clip |
80
+ # f.print "From %s@localhost %s\n" %
81
+ # [Version::PROGRAM_NAME, Time.now.ctime]
82
+ # f.print(escape_from(clip.to_mbox.chomp))
83
+ # f.print("\n")
84
+ # end
85
+ # f.close
86
+ #end #}}}1
87
+ #
88
+ #def save_as_yaml(filename)
89
+ ##{{{1
90
+ # filename = get_filename(filename,:save)
91
+ #
92
+ # arr = Array.new
93
+ # self.each_index do | i |
94
+ # arr[i] = self[i].to_hash
95
+ # end
96
+ #
97
+ # puts "# saving clips to '#{filename}', format yaml" if $VERBOSE
98
+ #
99
+ # File.open(filename,"w") do | file |
100
+ # YAML::dump(arr, file)
101
+ # end
102
+ #end #}}}1
103
+
104
+ #def ClipArray.load(filename,format)
105
+ ##{{{1
106
+ # case format
107
+ # when :mbox
108
+ # return ClipArray.load_from_mbox(filename)
109
+ # when :yaml
110
+ # return ClipArray.load_from_yaml(filename)
111
+ # end
112
+ #end #}}}1
113
+
114
+ def current_index=(num)
115
+ #{{{1
116
+ if num < 0 then
117
+ @current_index = 0
118
+ elsif num >= length then
119
+ @current_index = length - 1
120
+ else
121
+ @current_index = num
122
+ end
123
+ print_verbose "going to clip #{@current_index+1}"
124
+ end #}}}1
125
+
126
+ def next
127
+ #{{{1
128
+ if @current_index < length-1 then
129
+ @current_index += 1
130
+ print_verbose "going to next clip #{@current_index+1}"
131
+ end
132
+ return self
133
+ end #}}}1
134
+
135
+ def prev
136
+ #{{{1
137
+ if @current_index > 0 then
138
+ @current_index -= 1
139
+ print_verbose "going to previous clip #{@current_index+1}"
140
+ end
141
+ return self
142
+ end #}}}1
143
+
144
+ def delete
145
+ #{{{1
146
+ if @current_index == length-1 then
147
+ new_current_index = @current_index - 1
148
+ else
149
+ new_current_index = @current_index
150
+ end
151
+
152
+ print_verbose "deleting clip #{@current_index+1}"
153
+ delete_at(@current_index)
154
+
155
+ if length == 0 then
156
+ clear1
157
+ else
158
+ @current_index = new_current_index
159
+ end
160
+
161
+ end #}}}1
162
+
163
+ def new
164
+ #{{{1
165
+ c = Clip.new
166
+ push(c)
167
+ @current_index = length-1
168
+ print_verbose "creating new clip #{@current_index+1}"
169
+ end #}}}1
170
+
171
+ def current
172
+ #{{{1
173
+ return self[@current_index]
174
+ end #}}}1
175
+
176
+ #def ClipArray.load_from_yaml(filename)
177
+ ##{{{1
178
+ # filename = get_filename(filename,:open)
179
+ # ca = self.new
180
+ #
181
+ # puts "# loading clips from '#{filename}', format yaml" if $VERBOSE
182
+ #
183
+ # begin
184
+ # yaml = YAML::load_file(filename)
185
+ # yaml.each_index do | i |
186
+ # clip = Clip.from_hash(yaml[i])
187
+ # puts "# '#{clip.title}' loaded" if $VERBOSE
188
+ # ca[i] = clip
189
+ # end
190
+ # rescue SystemCallError
191
+ # puts "# loading failed, continuing with empty clips" if $VERBOSE
192
+ # end
193
+ #
194
+ # ca.current_index = ca.length - 1
195
+ # return ca
196
+ #end #}}}1
197
+ #
198
+ #def ClipArray.load_from_mbox(filename)
199
+ ##{{{1
200
+ # ca = self.new
201
+ # str = nil
202
+ #
203
+ # puts "# loading clips from '#{filename}', format mbox" if $VERBOSE
204
+ #
205
+ # begin
206
+ # file = open(get_filename(filename,:open),"r")
207
+ # ca = ClipArray.read_mbox(file)
208
+ # ensure
209
+ # file.close
210
+ # end
211
+ #
212
+ # return ca
213
+ #end #}}}1
214
+
215
+ def ClipArray.create(file_and_path)
216
+ #{{{1
217
+ print_verbose "creating file '#{file_and_path}"
218
+
219
+ if File.exists?(file_and_path) then
220
+ raise AppError, "File '#{file_and_path}' already exists"
221
+ end
222
+
223
+ begin
224
+ file = File.open(file_and_path,"w+")
225
+ ca = ClipArray.new.clear1
226
+ ca.set_file(file,file_and_path)
227
+
228
+ # test if writable
229
+ obtain_exclusive_lock(file)
230
+
231
+ obtain_shared_lock(file)
232
+ rescue Exception
233
+ file.close if file
234
+ raise
235
+ end
236
+
237
+ return ca
238
+ end #}}}1
239
+
240
+ def ClipArray.open(file_and_path)
241
+ #{{{1
242
+ print_verbose "opening file '#{file_and_path}'"
243
+
244
+ begin
245
+ file = File.open(file_and_path,"r+")
246
+ ca = ClipArray.read_mbox(file)
247
+ ca.set_file(file,file_and_path)
248
+
249
+ # test if writable
250
+ obtain_exclusive_lock(file)
251
+
252
+ obtain_shared_lock(file)
253
+ rescue Exception
254
+ file.close if file
255
+ raise
256
+ end
257
+
258
+ return ca
259
+ end #}}}1
260
+
261
+ def save
262
+ #{{{1
263
+ if @file.nil? then
264
+ return
265
+ end
266
+
267
+ print_verbose "saving file '#{@filename}'"
268
+
269
+ obtain_exclusive_lock(@file)
270
+ @file.truncate(0)
271
+ @file.rewind
272
+ write_mbox(@file)
273
+ @file.flush
274
+ obtain_shared_lock(@file)
275
+ end #}}}1
276
+
277
+ def close
278
+ #{{{1
279
+ autosave(0)
280
+ save
281
+ print_verbose "closing file '#{@filename}'"
282
+ if @file then
283
+ release_lock(@file)
284
+ @file.close
285
+ end
286
+ @file = nil
287
+ @filename = nil
288
+ clear
289
+ end #}}}1
290
+
291
+ def autosave(seconds)
292
+ #{{{1
293
+ print_debug "autosave(#{seconds}) called"
294
+ if @autosave_thread then
295
+ print_debug " killing old thread"
296
+ @autosave_thread.kill
297
+ @autosave_thread = nil
298
+ end
299
+
300
+ if seconds == 0 then
301
+ print_debug " returning because seconds==0"
302
+ return
303
+ end
304
+
305
+ print_verbose "starting autosave thread"
306
+ @autosave_thread = Thread.new do
307
+ while true
308
+ print_verbose "autosaving at #{Time.now}"
309
+ save
310
+ sleep(seconds)
311
+ end
312
+ end
313
+ end #}}}1
314
+
315
+
316
+ private
317
+
318
+
319
+ def ClipArray.read_mbox(file)
320
+ #{{{1
321
+ ca = self.new
322
+ first_line = true
323
+ str = ""
324
+ i = 1
325
+
326
+ print_debug "reading clips, mbox format"
327
+
328
+ if file.eof? or file.readline =~ /^From / then
329
+ # valid
330
+ else
331
+ raise AppError, "Not an Mbox file"
332
+ end
333
+
334
+ file.each_line do | line |
335
+ line.chomp!
336
+ if line =~ /^From / then
337
+ if not first_line then
338
+ clip = Clip.from_mbox(unescape_from(str))
339
+ if clip.type == :pref then
340
+ ca.pref = Preferences.read(clip.data)
341
+ print_debug " #{i}: Preferences"
342
+ else
343
+ ca << clip
344
+ print_debug " #{i}: '#{clip.title}'"
345
+ end
346
+ i += 1
347
+ end
348
+ str = ""
349
+ else
350
+ str << line << "\n"
351
+ end
352
+ first_line = false
353
+ end
354
+
355
+ if str != "" then
356
+ clip = Clip.from_mbox(unescape_from(str))
357
+ if clip.type == :pref then
358
+ ca.pref = Preferences.read(clip.data)
359
+ print_debug " #{i}: Preferences"
360
+ else
361
+ ca << clip
362
+ print_debug " #{i}: '#{clip.title}'"
363
+ end
364
+ end
365
+
366
+ ca.current_index = ca.length - 1
367
+ return ca
368
+ end #}}}1
369
+
370
+ def write_mbox(file)
371
+ #{{{1
372
+ print_debug "writing clips, mbox format"
373
+ i = 1
374
+
375
+ # Pref clip first
376
+ pc = Clip.new
377
+ pc.type = :pref
378
+ pc.title = "Preferences"
379
+ pc.data = @pref.write
380
+
381
+ ([pc]+self).each do | clip |
382
+ file.print "From %s@localhost %s\n" %
383
+ [Version::PROGRAM_NAME, Time.now.ctime]
384
+ file.print(escape_from(clip.to_mbox.chomp))
385
+ file.print("\n")
386
+ print_debug " #{i}: '#{clip.title}'"
387
+ i += 1
388
+ end
389
+ end #}}}1
390
+
391
+ end # class
392
+
393
+ # vim600: set foldmethod=marker: