viewworkbook 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/viewworkbook +31 -0
- data/doc/html/viewworkbook.html +523 -0
- data/doc/license.txt +674 -0
- data/doc/man/viewworkbook.1.gz +0 -0
- data/doc/rst/viewworkbook.rst +126 -0
- data/lib/action.rb +57 -0
- data/lib/busy_indicator/busy_function_test.rb +56 -0
- data/lib/busy_indicator/busy_indicator.rb +95 -0
- data/lib/cell.rb +122 -0
- data/lib/color_output.rb +43 -0
- data/lib/column.rb +97 -0
- data/lib/file_checking.rb +87 -0
- data/lib/log.conf +62 -0
- data/lib/logging.rb +195 -0
- data/lib/menu.rb +107 -0
- data/lib/row.rb +82 -0
- data/lib/scrollable.rb +392 -0
- data/lib/sheetdata.rb +96 -0
- data/lib/sheetinterface.rb +464 -0
- data/lib/translating.rb +89 -0
- data/lib/translations +26 -0
- data/lib/user_input.rb +52 -0
- data/lib/viewworkbook.rb +83 -0
- metadata +128 -0
data/lib/sheetdata.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#encoding: UTF-8
|
2
|
+
|
3
|
+
=begin
|
4
|
+
/*****************************************************************************
|
5
|
+
* Copyright © 2016-2016, Michael Uplawski <michael.uplawski@uplawski.eu> *
|
6
|
+
* *
|
7
|
+
* This program is free software; you can redistribute it and/or modify *
|
8
|
+
* it under the terms of the GNU General Public License as published by *
|
9
|
+
* the Free Software Foundation; either version 3 of the License, or *
|
10
|
+
* (at your option) any later version. *
|
11
|
+
* *
|
12
|
+
* This program is distributed in the hope that it will be useful, *
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
15
|
+
* GNU General Public License for more details. *
|
16
|
+
* *
|
17
|
+
* You should have received a copy of the GNU General Public License *
|
18
|
+
* along with this program; if not, write to the *
|
19
|
+
* Free Software Foundation, Inc., *
|
20
|
+
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
21
|
+
*****************************************************************************/
|
22
|
+
=end
|
23
|
+
|
24
|
+
require 'roo'
|
25
|
+
require 'roo-xls'
|
26
|
+
require 'filemagic'
|
27
|
+
|
28
|
+
require_relative 'logging'
|
29
|
+
|
30
|
+
# Transforms a file into a Roo spreadsheet instance.
|
31
|
+
|
32
|
+
ODS_Magic = "OpenDocument Spreadsheet"
|
33
|
+
XLS_Magic = "Composite Document File V2 Document"
|
34
|
+
XLSX_Magic = "Microsoft OOXML"
|
35
|
+
|
36
|
+
ODS_MIME = "application/vnd.oasis.opendocument.spreadsheet"
|
37
|
+
XLS_MIME = "application/vnd.ms-excel"
|
38
|
+
XLSX_MIME = "application/octet-stream"
|
39
|
+
CSV_MIME = "text/plain"
|
40
|
+
|
41
|
+
class SheetData
|
42
|
+
self::extend(Logging)
|
43
|
+
@@log = init_logger(STDOUT, Logger::INFO)
|
44
|
+
|
45
|
+
@@file = nil
|
46
|
+
@@workbook = nil
|
47
|
+
|
48
|
+
def self::workbook(file)
|
49
|
+
@@file = file
|
50
|
+
if !@@workbook
|
51
|
+
begin
|
52
|
+
magic, mime = file_type
|
53
|
+
@@workbook = case mime
|
54
|
+
when ODS_MIME
|
55
|
+
if magic.match ODS_Magic
|
56
|
+
@@log.debug('ODS')
|
57
|
+
Roo::Spreadsheet::open(@@file, extension: :ods )
|
58
|
+
end
|
59
|
+
when XLS_MIME
|
60
|
+
if magic.match XLS_Magic
|
61
|
+
@@log.debug('XLS')
|
62
|
+
Roo::Spreadsheet::open(@@file, extension: :xls )
|
63
|
+
end
|
64
|
+
when XLSX_MIME
|
65
|
+
if magic.match XLSX_Magic
|
66
|
+
@@log.debug('XLSX')
|
67
|
+
Roo::Spreadsheet::open(@@file, extension: :xlsx )
|
68
|
+
end
|
69
|
+
when CSV_MIME
|
70
|
+
raise IOError.new('CSV is not yet supported, sorry')
|
71
|
+
else
|
72
|
+
raise IOError.new('Mime-Type is ' << mime << ' and Magic sais: ' << magic << ". Is this supposed to be a spreadsheet?")
|
73
|
+
end
|
74
|
+
rescue Exception => ex
|
75
|
+
msg = 'ERROR! File %s is not supported: %s' %[@@file, ex.message]
|
76
|
+
puts msg
|
77
|
+
@log.error yellow(msg)
|
78
|
+
exit false
|
79
|
+
end
|
80
|
+
|
81
|
+
return @@workbook
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
# derive the mime-type from the file
|
87
|
+
def self::file_type
|
88
|
+
fm = FileMagic.fm
|
89
|
+
file_magic = fm.file(@@file)
|
90
|
+
fm.flags = [:mime_type]
|
91
|
+
file_mime = fm.file(@@file)
|
92
|
+
@log.debug('File type is ' << file_magic << ', Mime-type is ' << file_mime)
|
93
|
+
return file_magic, file_mime
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,464 @@
|
|
1
|
+
#encoding: UTF-8
|
2
|
+
|
3
|
+
=begin
|
4
|
+
/***************************************************************************
|
5
|
+
* Copyright © 2014 - 2017, Michael Uplawski <michael.uplawski@uplawski.eu> *
|
6
|
+
* *
|
7
|
+
* This program is free software; you can redistribute it and/or modify *
|
8
|
+
* it under the terms of the GNU General Public License as published by *
|
9
|
+
* the Free Software Foundation; either version 3 of the License, or *
|
10
|
+
* (at your option) any later version. *
|
11
|
+
* *
|
12
|
+
* This program is distributed in the hope that it will be useful, *
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
15
|
+
* GNU General Public License for more details. *
|
16
|
+
* *
|
17
|
+
* You should have received a copy of the GNU General Public License *
|
18
|
+
* along with this program; if not, write to the *
|
19
|
+
* Free Software Foundation, Inc., *
|
20
|
+
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
21
|
+
***************************************************************************/
|
22
|
+
=end
|
23
|
+
|
24
|
+
require 'roo'
|
25
|
+
require 'io/wait'
|
26
|
+
require 'io/console'
|
27
|
+
|
28
|
+
require_relative 'logging'
|
29
|
+
require_relative 'scrollable'
|
30
|
+
require_relative 'row'
|
31
|
+
require_relative 'cell'
|
32
|
+
require_relative 'column'
|
33
|
+
require_relative 'color_output'
|
34
|
+
require_relative 'busy_indicator/busy_indicator'
|
35
|
+
require_relative 'user_input'
|
36
|
+
require_relative 'menu'
|
37
|
+
require_relative 'action'
|
38
|
+
require_relative 'translating'
|
39
|
+
|
40
|
+
# So this draws a table complete with the content of the cells from the
|
41
|
+
# currently selected spreadsheet.
|
42
|
+
# The really ingenuous stuff was provided by a helpful user on a newsgroup.
|
43
|
+
# Really... Usenet! Like in ... 2014!
|
44
|
+
|
45
|
+
#TODO: provide conversion for column designators to int vv, also for AA to ZZ !
|
46
|
+
|
47
|
+
class SheetInterface
|
48
|
+
include Logging
|
49
|
+
include Translating
|
50
|
+
|
51
|
+
class Status
|
52
|
+
def show
|
53
|
+
if(@message)
|
54
|
+
puts @message
|
55
|
+
@message.clear
|
56
|
+
end
|
57
|
+
end
|
58
|
+
attr_writer :message
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize(wb, num)
|
62
|
+
init_logger(STDOUT, Logger::INFO)
|
63
|
+
@workbook = wb.sheet(num)
|
64
|
+
@menu = nil
|
65
|
+
@status = Status.new
|
66
|
+
construct
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
=begin
|
71
|
+
returns [width, height] in columns and lines of the current
|
72
|
+
terminal-window.
|
73
|
+
=end
|
74
|
+
def terminal_size
|
75
|
+
size = `stty size`.split.map { |x| x.to_i }.reverse
|
76
|
+
return size
|
77
|
+
end
|
78
|
+
# Asks the user to enter a number, then verifies ageinst eventual
|
79
|
+
# constraints.
|
80
|
+
def ask_number(question, &constraint)
|
81
|
+
num = nil
|
82
|
+
3.times do
|
83
|
+
print question.dup << " "
|
84
|
+
begin
|
85
|
+
num = STDIN.gets()
|
86
|
+
rescue Interrupt
|
87
|
+
return nil
|
88
|
+
end
|
89
|
+
num = num.to_i
|
90
|
+
if (constraint && !yield(num))
|
91
|
+
num = nil
|
92
|
+
end
|
93
|
+
return num if num
|
94
|
+
end
|
95
|
+
if !num
|
96
|
+
@status.message = "Inacceptable value, doing nothing."
|
97
|
+
return nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Shortcutting from “user inputs bull” to “program interrupts”
|
102
|
+
# without the need for the program to actually run havoc, first.
|
103
|
+
def ask_string(question, &constraint)
|
104
|
+
str = nil
|
105
|
+
until str
|
106
|
+
print question.dup << " "
|
107
|
+
begin
|
108
|
+
str = STDIN.gets().chomp!
|
109
|
+
rescue Interrupt
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
if("" == str || "\e" == str)
|
113
|
+
return nil
|
114
|
+
end
|
115
|
+
if(constraint && !yield(str))
|
116
|
+
str = nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
if !str
|
120
|
+
@status.message = "Inacceptable value, doing nothing."
|
121
|
+
end
|
122
|
+
return str
|
123
|
+
end
|
124
|
+
|
125
|
+
# Write content to a new file
|
126
|
+
def new_file()
|
127
|
+
file = nil
|
128
|
+
until file
|
129
|
+
print 'file path:' << ' '
|
130
|
+
begin
|
131
|
+
file = STDIN.gets().chomp!
|
132
|
+
rescue Interrupt
|
133
|
+
return nil
|
134
|
+
end
|
135
|
+
if(file && File::exist?(file) )
|
136
|
+
if(File::writable?(file) )
|
137
|
+
print "File #{file} exists! Do you want to overwrite its content, now (j/N)? "
|
138
|
+
answer = "%c" %wait_for_user
|
139
|
+
if('j' != answer.downcase)
|
140
|
+
file = nil
|
141
|
+
else
|
142
|
+
puts
|
143
|
+
end
|
144
|
+
else
|
145
|
+
puts "File #{file} is not writable! Please name a different file path"
|
146
|
+
file = nil
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
return file
|
152
|
+
end
|
153
|
+
|
154
|
+
def ask_cell_coord()
|
155
|
+
coord = nil
|
156
|
+
until coord
|
157
|
+
print 'Which cell (col:row)? '
|
158
|
+
begin
|
159
|
+
coord = STDIN.gets().chomp!
|
160
|
+
rescue Interrupt
|
161
|
+
return nil
|
162
|
+
end
|
163
|
+
if('' == coord || !coord.include?(':') || "\e" == coord)
|
164
|
+
return nil
|
165
|
+
else
|
166
|
+
col, row = coord.split(':')
|
167
|
+
row = row.to_i
|
168
|
+
col = col.strip
|
169
|
+
end
|
170
|
+
return [col, row]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def set_sheet(sheet)
|
175
|
+
current_sheet = @workbook.default_sheet
|
176
|
+
@workbook = @workbook.sheet(sheet)
|
177
|
+
columns = @workbook.last_column
|
178
|
+
if columns && columns > 0
|
179
|
+
@rows = nil
|
180
|
+
@columns = nil
|
181
|
+
else
|
182
|
+
@workbook = @workbook.sheet(current_sheet)
|
183
|
+
@status.message = red("Sheet #{sheet} contains no data!")
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def open_sheet(designator = :number)
|
188
|
+
sn = nil
|
189
|
+
if designator == :number
|
190
|
+
sn = ask_number("Sheet number (max #{@workbook.sheets.size() - 1})?") do |num|
|
191
|
+
num < @workbook.sheets.size
|
192
|
+
end
|
193
|
+
else
|
194
|
+
sn = ask_string("Sheet name (#{@workbook.sheets.join(', ')})?") do |name|
|
195
|
+
@workbook.sheets.include?(name)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
if sn && !sn.to_s.empty?
|
200
|
+
@log.debug('calling workbook.sheet with ' << sn.to_s)
|
201
|
+
@log.debug('@workbook is of type ' << @workbook.class.name)
|
202
|
+
set_sheet(sn)
|
203
|
+
end
|
204
|
+
construct
|
205
|
+
end
|
206
|
+
|
207
|
+
# Adds concrete actions to the menu.
|
208
|
+
# Note the calls to ask_number and ask_string with constraints.
|
209
|
+
def define_actions(menu)
|
210
|
+
sm_Menu = Menu.new(:name => 'sheet', :key => 's')
|
211
|
+
sm_Menu.add_action(Action.new(:name => 'sheet number', :key => '#') {open_sheet(:number)})
|
212
|
+
sm_Menu.add_action(Action.new(:name => 'sheet name', :key => 'n') {open_sheet(:name)})
|
213
|
+
|
214
|
+
save_Menu = Menu.new(:name => 'save to file', :key => 'f')
|
215
|
+
save_Menu.add_action(Action.new(:name => 'current sheet', :key => 'c') do
|
216
|
+
file = new_file()
|
217
|
+
if(file)
|
218
|
+
File::open(file, 'w+') {|out| draw(out) }
|
219
|
+
@status.message = green('... done')
|
220
|
+
end
|
221
|
+
construct
|
222
|
+
end)
|
223
|
+
|
224
|
+
save_Menu.add_action(Action.new(:name => 'all sheets', :key => 'a') do
|
225
|
+
current_sheet = @workbook.default_sheet
|
226
|
+
@status.message = "\nATTN! If saving takes a long time, your spreadsheet may contain useless data or many empty cells. Check the visible width and height of your tables.\n"
|
227
|
+
file = new_file()
|
228
|
+
if(file)
|
229
|
+
bi = BusyIndicator.new(true)
|
230
|
+
begin
|
231
|
+
File::open(file, 'w+') do |out|
|
232
|
+
@workbook.sheets.each do |s|
|
233
|
+
@log.debug('writing sheet ' << s)
|
234
|
+
set_sheet(s)
|
235
|
+
construct(false)
|
236
|
+
draw(out)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
rescue Interrupt
|
240
|
+
puts bold(red("Interrupted by user. Bye!"))
|
241
|
+
exit true
|
242
|
+
end
|
243
|
+
bi.stop('... done')
|
244
|
+
end
|
245
|
+
set_sheet(current_sheet)
|
246
|
+
construct
|
247
|
+
end)
|
248
|
+
|
249
|
+
col_Menu = Menu.new(:name=>'column', :key => 'c')
|
250
|
+
col_Menu.add_action(Action.new(:name => 'column width', :key => 'w') do |num|
|
251
|
+
num = ask_number('column width (min. 4) ?'){|w| w > 3}
|
252
|
+
Column::col_width = num if num
|
253
|
+
construct
|
254
|
+
end)
|
255
|
+
|
256
|
+
menu.add_action(Action.new(:name => 'value', :key => 'v') do
|
257
|
+
cell_coord = ask_cell_coord
|
258
|
+
if(cell_coord && cell_coord.length == 2)
|
259
|
+
row = cell_coord[1] - 1
|
260
|
+
col = cell_coord[0].upcase.bytes[0] - 65
|
261
|
+
cell = nil
|
262
|
+
if(@rows[row] && @columns[col])
|
263
|
+
cell = @rows[row].cells.detect {|c| c.col == col}
|
264
|
+
if(cell)
|
265
|
+
@status.message = "#{cell_coord[0].upcase}:#{cell_coord[1]} is \"" << cell.value.to_s << "\" (%d)" %cell.value.to_s.length
|
266
|
+
else
|
267
|
+
@status.message = red('invalid cell')
|
268
|
+
end
|
269
|
+
else
|
270
|
+
@status.message = red(cell_coord.join(':') << ': out of range')
|
271
|
+
end
|
272
|
+
elsif(cell_coord && cell_coord.length > 0)
|
273
|
+
@status.message = red('invalid input')
|
274
|
+
end
|
275
|
+
construct
|
276
|
+
end)
|
277
|
+
|
278
|
+
menu.add_menu(save_Menu)
|
279
|
+
menu.add_menu(sm_Menu)
|
280
|
+
menu.add_menu(col_Menu)
|
281
|
+
menu.add_action(Action.new(:name => "⇧", :key => "i") {@table_view.up; refresh()})
|
282
|
+
menu.add_action(Action.new(:name => "⇩", :key => "k") {@table_view.down; refresh()})
|
283
|
+
menu.add_action(Action.new(:name => "⇦", :key => "j") {@table_view.left; refresh()})
|
284
|
+
menu.add_action(Action.new(:name => "⇨", :key => "l") {@table_view.right; refresh()})
|
285
|
+
menu.add_action(Action.new(:global => true, :hidden => true, :name => '', :key => "\e") {refresh})
|
286
|
+
menu.add_action(Action.new(:global => true, :name => 'quit', :key => 'q') {puts 'Bye ';exit 0})
|
287
|
+
end
|
288
|
+
# This is hard to describe.
|
289
|
+
# The function basically draws a table on screen.
|
290
|
+
def draw(out = STDOUT)
|
291
|
+
if(@rows && !@rows.empty?)
|
292
|
+
# Welcome to hell.
|
293
|
+
on_screen = STDOUT == out
|
294
|
+
col_w = Column::col_width
|
295
|
+
num_c = @rows[0].cells.length()
|
296
|
+
num_r = @rows.length
|
297
|
+
ch = nil
|
298
|
+
hline = nil
|
299
|
+
#-----
|
300
|
+
table_view = ''
|
301
|
+
#-----
|
302
|
+
|
303
|
+
table_view << @workbook.default_sheet << "\n"
|
304
|
+
#out.puts @workbook.default_sheet
|
305
|
+
table_view << ('┌' << '─' * num_r.to_s.length << '┬' << (('─' * col_w) << '┬' ) * (num_c -1) ) << (('─' * col_w) << '┐' ) << "\n"
|
306
|
+
# out.puts ('┌' << '─' * num_r.to_s.length << '┬' << (('─' * col_w) << '┬' ) * (num_c -1) ) << (('─' * col_w) << '┐' )
|
307
|
+
lh = 0
|
308
|
+
@rows.each do |row|
|
309
|
+
|
310
|
+
if(row == @rows.first)
|
311
|
+
ch = 'A'
|
312
|
+
table_view << "│%#{num_r.to_s.length}s" %" "
|
313
|
+
#out.print "│%#{num_r.to_s.length}s" %" "
|
314
|
+
table_view << '│'
|
315
|
+
# out.print '│'
|
316
|
+
row.each do |c|
|
317
|
+
head = "%#{col_w}s" %ch
|
318
|
+
head = bold(head) if(on_screen)
|
319
|
+
# out.print(head << "|")
|
320
|
+
table_view << (head << "│")
|
321
|
+
ch = ch.next
|
322
|
+
end
|
323
|
+
# out.puts
|
324
|
+
table_view << "\n"
|
325
|
+
hline = ('├' << ('─' * (num_r.to_s.length) ) <<'┼' << (('─' * col_w) << '┼' ) * (num_c - 1) ) << (('─' * col_w) << '┤')if !hline
|
326
|
+
table_view << hline << "\n"
|
327
|
+
# out.puts hline
|
328
|
+
end
|
329
|
+
lh += 1
|
330
|
+
table_view << "│"
|
331
|
+
# out.print "│"
|
332
|
+
line_head = "%#{num_r.to_s.length}s" %lh.to_s
|
333
|
+
line_head = bold(line_head) if on_screen
|
334
|
+
table_view << line_head
|
335
|
+
# out.print line_head
|
336
|
+
|
337
|
+
# out.print "│" << bold("%#{num_r.to_s.length}s" %line_head)
|
338
|
+
|
339
|
+
row.height.times do |li|
|
340
|
+
table_view << "│%#{num_r.to_s.length}s" %" " if li > 0
|
341
|
+
# out.print "│%#{num_r.to_s.length}s" %" " if li > 0
|
342
|
+
table_view << '│'
|
343
|
+
# out.print '│'
|
344
|
+
row.each do |cell|
|
345
|
+
line = cell.line(li)
|
346
|
+
content = "%#{col_w}s│" %line
|
347
|
+
if(on_screen && line && line.end_with?('...'))
|
348
|
+
content = red(content)
|
349
|
+
end
|
350
|
+
table_view << content
|
351
|
+
# out.print content
|
352
|
+
end
|
353
|
+
table_view << "\n"
|
354
|
+
# out.puts
|
355
|
+
end
|
356
|
+
hlline = ('│' << (('─' * col_w) << '│' ) * num_c ) if !hline
|
357
|
+
|
358
|
+
table_view << hline << "\n"
|
359
|
+
# out.puts hline
|
360
|
+
|
361
|
+
# Some of the following code may go to a function as it repeats the
|
362
|
+
# procedure from the beginning of the table. I am currently unwilling to
|
363
|
+
# do it, because all the rest must stay so verbose that another
|
364
|
+
# function-call at this position cannot contribute to a better
|
365
|
+
# understanding of this ... table-generating MESS!!
|
366
|
+
if(row == @rows.last)
|
367
|
+
ch = 'A'
|
368
|
+
table_view << "│%#{num_r.to_s.length}s" %" "
|
369
|
+
# out.print "│%#{num_r.to_s.length}s" %" "
|
370
|
+
table_view << '│'
|
371
|
+
# out.print '│'
|
372
|
+
row.each do |c|
|
373
|
+
head = "%#{col_w}s" %ch
|
374
|
+
head = bold(head) if on_screen
|
375
|
+
table_view << ( head << '│')
|
376
|
+
# out.print( head << '│')
|
377
|
+
ch = ch.next
|
378
|
+
end
|
379
|
+
table_view << "\n"
|
380
|
+
# out.puts
|
381
|
+
hline = ('└' << ('─' * (num_r.to_s.length) ) << '┴' << (('─' * col_w) << '┴' ) * (num_c - 1) ) << (('─' * col_w) << '┘' )
|
382
|
+
|
383
|
+
table_view << hline << "\n"
|
384
|
+
# out.puts hline
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
=begin
|
389
|
+
table_width = hline.length
|
390
|
+
tw = terminal_size[0]
|
391
|
+
if(on_screen && table_width > tw)
|
392
|
+
@status.message = red("ATTN! Terminal is to narrow to display the whole table (#{tw} characters for #{table_width}). Diminish column-width!")
|
393
|
+
end
|
394
|
+
=end
|
395
|
+
return table_view
|
396
|
+
else
|
397
|
+
return nil
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
# The function which is called to recreate the view.
|
402
|
+
# It prepares the table-generation by transforming the Roo-instance to
|
403
|
+
# objects of the classes Cell, Row and Column, then calls draw(), above and
|
404
|
+
# adds the status- and menu-lines. The menu waits for user input (blocking)
|
405
|
+
# before construct() returns, no other thread or “event-loop” involved there.
|
406
|
+
def construct(on_screen = true)
|
407
|
+
puts "... reading spreadsheet data (%s), PSE wait" %[@workbook.default_sheet]
|
408
|
+
bi = BusyIndicator.new()
|
409
|
+
if(!@rows || !@columns)
|
410
|
+
|
411
|
+
@rows = Array.new if !@rows
|
412
|
+
@columns = Array.new if !@columns
|
413
|
+
# create for each column
|
414
|
+
num_columns = @workbook.last_column
|
415
|
+
if(num_columns && num_columns > 0)
|
416
|
+
num_columns.times do |column|
|
417
|
+
# ... a column, then
|
418
|
+
@columns[column] = Column.new(column) if !@columns[column]
|
419
|
+
cur_col = @columns[column]
|
420
|
+
|
421
|
+
# ... create for each row in each column
|
422
|
+
(@workbook.last_row).times do |row|
|
423
|
+
# ... a row then
|
424
|
+
@rows[row] = Row.new(row) if !@rows[row]
|
425
|
+
cur_row = @rows[row]
|
426
|
+
# ... create for each cell in each row
|
427
|
+
cur_cell = cur_row.cells.detect {|cell| column == cell.col }
|
428
|
+
if !cur_cell
|
429
|
+
# ... a cell
|
430
|
+
cell = @workbook.cell(row + 1, column + 1)
|
431
|
+
cur_cell = Cell.new(cur_row, cur_col, cell.to_s)
|
432
|
+
cur_row << cur_cell
|
433
|
+
cur_col << cur_cell
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
bi.stop("\n")
|
441
|
+
if(on_screen)
|
442
|
+
@table_view = draw()
|
443
|
+
if @table_view
|
444
|
+
@table_view.extend(Scrollable)
|
445
|
+
@table_view.fixed_rows = 4
|
446
|
+
@table_view.fixed_cols = 4
|
447
|
+
refresh()
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
def refresh()
|
453
|
+
@table_view.width=terminal_size[0] - 1
|
454
|
+
@table_view.height=terminal_size[1]
|
455
|
+
# @table_view.box = true
|
456
|
+
@table_view.show
|
457
|
+
@status.show
|
458
|
+
if !@menu
|
459
|
+
@menu = Menu.new(:name => 'main')
|
460
|
+
define_actions(@menu)
|
461
|
+
end
|
462
|
+
@menu.call
|
463
|
+
end
|
464
|
+
end
|