lib/clevic/table_view_paste.rb in clevic-0.13.0.b9 vs lib/clevic/table_view_paste.rb in clevic-0.13.0.b10
- old
+ new
@@ -10,11 +10,11 @@
# get something from the clipboard and put it at the current selection
# intended to be called by action / keyboard / menu handlers
def paste
busy_cursor do
sanity_check_read_only
-
+
# Try text/html then text/plain as tsv or csv
# LATER maybe use the java-native-application at some point for
# cut'n'paste internally?
case
when clipboard.html?
@@ -26,27 +26,27 @@
end
end
rescue PasteError => e
show_error e.message
end
-
+
# Paste suitable html to the selection
# Check for presence of tr tags, and make sure there are no colspan or rowspan attributes
# on td tags.
def paste_html
emit_status_text "Fetching data."
html = clipboard.html
-
+
# This should really be factored out somewhere and tested thoroughly
emit_status_text "Analysing data."
doc =
if html.is_a? Hpricot::Doc
html
else
Hpricot.parse( html )
end
-
+
# call the plain text paste if we don't have tabular data
if doc.search( "//tr" ).size == 0
paste_text
else
# throw exception if there are [col|row]span > 1
@@ -60,52 +60,52 @@
somewhere. Split them, and try copy and paste again.
Cells contain
#{cell_list}
EOF
end
-
+
# run through the tabular data and convert to simple array
emit_status_text "Pasting data."
ary = ( doc / :tr ).map do |row|
( row / :td ).map do |cell|
# trim leading and trailing \r\n\t
-
+
# check for br
unless cell.search( '//br' ).empty?
# treat br as separate lines
cell.search('//text()').map( &:to_s ).join("\n")
else
# otherwise just join text elements
cell.search( '//text()' ).join('')
end.gsub( /^[\r\n\t]*/, '').gsub( /[\r\n\t]*$/, '')
end
end
-
+
paste_array ary
end
end
-
+
# LATER probably need a PasteParser or something, to figure
# out if a file is tsv or csv
# Try tsv first, because number formats often have embedded ','.
# if tsv doesn't work, try with csv and test for rectangularness
# otherwise assume it's one string.
# TODO could also heuristically check paste selection area
def paste_text
text = clipboard.text
-
+
case text
when /\t/
paste_array( CSV.parse( text, :col_sep => "\t" ) )
# assume multi-line text, or text with commas, is csv
when /[,\n]/
paste_array( CSV.parse( text, :col_sep => ',' ) )
else
paste_value_to_selection( text )
end
end
-
+
# Paste array to either a single selection or a matching multiple selection
# TODO Check for rectangularness, ie csv_arr.map{|row| row.size}.uniq.size == 1
def paste_array( arr )
if selection_model.single_cell?
# only one cell selected, so paste like a spreadsheet
@@ -122,50 +122,50 @@
paste_value_to_selection arr.first.first
else
if selection_model.ranges.size != 1
raise PasteError, "Can't paste tabular data to multiple selection."
end
-
+
if selection_model.ranges.first.height != arr.size
raise PasteError, "Height of paste area (#{selection_model.ranges.first.height}) doesn't match height of data (#{arr.size})."
end
-
+
if selection_model.ranges.first.width != arr.first.size
raise PasteError, "Width of paste area (#{selection_model.ranges.first.width}) doesn't match width of data (#{arr.first.size})."
end
-
+
# size is the same, so do the paste
paste_to_index( selected_index, arr )
end
end
end
-
+
# set all indexes in the selection to the value
def paste_value_to_selection( value )
selection_model.selected_indexes.each do |index|
index.text_value = value
# save records to db via view, so we get error messages
save_row( index )
end
-
+
# notify of changed data
model.data_changed do |change|
sorted = selection_model.selected_indexes.sort
change.top_left = sorted.first
change.bottom_right = sorted.last
end
end
-
+
# Paste an array to the index, replacing whatever is at that index
# and whatever is at other indices matching the size of the pasted
# csv array. Create new rows if there aren't enough.
def paste_to_index( top_left_index, csv_arr )
csv_arr_size = csv_arr.size
csv_arr.each_with_index do |row,row_index|
# append row if we need one
model.add_new_item if top_left_index.row + row_index >= model.row_count
-
+
row.each_with_index do |field, field_index|
unless top_left_index.column + field_index >= model.column_count
# do paste
cell_index = top_left_index.choppy {|i| i.row += row_index; i.column += field_index }
emit_status_text( "pasted #{row_index+1} of #{csv_arr_size}")
@@ -181,19 +181,19 @@
end
end
# save records to db via view, so we get error messages
save_row( top_left_index.choppy {|i| i.row += row_index; i.column = 0 } )
end
-
+
# make the gui refresh
model.data_changed do |change|
change.top_left = top_left_index
change.bottom_right = top_left_index.choppy do |i|
i.row += csv_arr.size - 1
i.column += csv_arr.first.size - 1
end
end
end
-
+
end
end