Mercurial > forge
changeset 10406:1600469c640f octave-forge
Support for odfdom-0.8.8-incubator; tabs replaced by double space
author | prnienhuis |
---|---|
date | Fri, 08 Jun 2012 15:28:27 +0000 |
parents | 8467fcf135a3 |
children | 7a142d50999f |
files | main/io/inst/getusedrange.m main/io/inst/oct2ods.m main/io/inst/ods2oct.m main/io/inst/odsclose.m main/io/inst/odsfinfo.m main/io/inst/odsopen.m main/io/inst/odsread.m main/io/inst/odswrite.m |
diffstat | 8 files changed, 1547 insertions(+), 1539 deletions(-) [+] |
line wrap: on
line diff
--- a/main/io/inst/getusedrange.m Fri Jun 08 14:11:42 2012 +0000 +++ b/main/io/inst/getusedrange.m Fri Jun 08 15:28:27 2012 +0000 @@ -66,8 +66,10 @@ ## 2011-06-13 OpenXLS support added ## 2011-09-08 Style & layout updates ## 2012-01-26 Fixed "seealso" help string +## 2012-06-08 Replaced tabs by double space +## '' Added COM and OXS to message about supported interfaces ## -## Last subfunc update: 2012-04-18 (JOD) +## Last subfunc update: 2012-06-08 (OTK) function [ trow, lrow, lcol, rcol ] = getusedrange (spptr, ii) @@ -89,7 +91,7 @@ elseif (strcmp (spptr.xtype, 'OXS')) [ trow, lrow, lcol, rcol ] = getusedrange_oxs (spptr, ii); else - error ('Only OTK, JOD, POI and JXL interface implemented'); + error ("Only OTK, JOD, COM, POI, JXL and OXS interface implemented"); endif endfunction @@ -124,10 +126,11 @@ ## Currently this fix is just commented. ## 2011-06-06 Fixed wrong if clause for finding last filler cells (L.160 & L.176) ## 2011-09-12 Support for odfdom-0.8.7 added (API change for XPATH) +## 2012-06-08 Support for odsfdom-0.8.8-incubator function [ trow, lrow, lcol, rcol ] = getusedrange_otk (ods, ii) - odfcont = ods.workbook; # Local copy just in case + odfcont = ods.workbook; # Local copy just in case if (isfield (ods, 'odfvsn')) if (strcmp (ods.odfvsn, '0.8.6') || strcmp (ods.odfvsn, '0.7.5')) @@ -166,11 +169,11 @@ reprows = 0; endif - # Get leftmost cell column number + # Get leftmost cell column number lcell = row.getFirstChild (); cl_char = char (lcell); - # Swap the following lines into comment to catch a jOpenDocument bug which foobars OTK - # (JOD doesn't set <office:value-type='string'> attribute when writing strings + # Swap the following lines into comment to catch a jOpenDocument bug which foobars OTK + # (JOD doesn't set <office:value-type='string'> attribute when writing strings #if (isempty (findstr ('office:value-type', cl_char)) || isempty (findstr ('<text:', cl_char))) if (isempty (findstr ('office:value-type', cl_char))) lcol = min (lcol, lcell.getTableNumberColumnsRepeatedAttribute () + 1); @@ -232,7 +235,7 @@ ## Created: 2010-05-25 ## Last updates: ## 2010-05-31 Fixed ignoring table-covered-cells; fixed count of sheets comprising just A1:A1 -## '' Added option for wsh being a string argument +## Added option for wsh being a string argument ## 2010-08-12 Little textual adaptations ## 2010-11-13 Catched jOpenDocument bug (1.2bx) where string cells have no office:value-type ## '' attrb set (by JOD). Somehow OTK is more robust as it catches these cells @@ -241,15 +244,15 @@ function [ trow, brow, lcol, rcol ] = getusedrange_jod (ods, wsh) - # This function works by virtue of sheets in JOD actually being a Java string. - # It works outside of the Java memory/heap space which is an added benefit... - # (Read: this is one big dirty hack...... prone to crash Java on BIG spreadsheets) + # This function works by virtue of sheets in JOD actually being a Java string. + # It works outside of the Java memory/heap space which is an added benefit... + # (Read: this is one big dirty hack...... prone to crash Java on BIG spreadsheets) - if (isnumeric (wsh)) - sh = ods.workbook.getSheet (wsh - 1); - else - sh = ods.workbook.getSheet (wsh); - endif + if (isnumeric (wsh)) + sh = char (ods.workbook.getSheet (wsh - 1)); + else + sh = char (ods.workbook.getSheet (wsh)); + endif try # Let's see if we have JOD v. 1.3x. If not, next call fails & we'll fall back to the old hack @@ -266,16 +269,12 @@ brow = trow + nr - 1; rcol = lcol + nc - 1; endif - return catch - # This function works by virtue of sheets in JOD actually being a Java string. - # It works outside of the Java memory/heap space which is an added benefit... - # (Read: this is one big dirty hack...... prone to crash Java on BIG spreadsheets) - + # Fall back to the old hack :-( sh = char (sh); - # Get table-row pointers + # 1. Get table-row pointers id_trow = strfind (sh, '<table:table-row'); id = strfind (sh, '</table:table>') - 1; id_trow = [id_trow id]; @@ -283,96 +282,96 @@ trow = rcol = 0; lcol = 1024; brow = 0; if (~isempty (id)) - # Loop over all table-rows - rowrepcnt = 0; - for irow = 1:length (id_trow)-1 - # Isolate single table-row - tablerow = sh(id_trow(irow):id_trow(irow+1)-1); - # Search table-cells. table-c covers both table-cell & table-covered-cell - id_tcell = strfind (tablerow, '<table:table-c'); - id_tcell = [id_tcell id]; - rowl = length (tablerow); - if (isempty (id_tcell(1:end-1))) - rowend = rowl; - else - rowend = id_tcell(1); - endif - # Add in table-number-rows-repeated attribute values - rowrept = strfind (tablerow(1:rowend), 'number-rows-repeated'); - if (~isempty (rowrept)) - [st, en] = regexp (tablerow(rowrept:min (rowend, rowrept+30)), '\d+'); - rowrepcnt += str2num (tablerow(rowrept+st-1:min (rowend, rowrept+en-1))) - 1; - endif + # 2. Loop over all table-rows + rowrepcnt = 0; + for irow = 1:length (id_trow)-1 + # Isolate single table-row + tablerow = sh(id_trow(irow):id_trow(irow+1)-1); + # Search table-cells. table-c covers both table-cell & table-covered-cell + id_tcell = strfind (tablerow, '<table:table-c'); + id_tcell = [id_tcell id]; + rowl = length (tablerow); + if (isempty (id_tcell(1:end-1))) + rowend = rowl; + else + rowend = id_tcell(1); + endif + # Add in table-number-rows-repeated attribute values + rowrept = strfind (tablerow(1:rowend), 'number-rows-repeated'); + if (~isempty (rowrept)) + [st, en] = regexp (tablerow(rowrept:min (rowend, rowrept+30)), '\d+'); + rowrepcnt += str2num (tablerow(rowrept+st-1:min (rowend, rowrept+en-1))) - 1; + endif - # Search table-cells. table-c is a table-covered-cell that is considered empty - id_tcell = strfind (tablerow, '<table:table-c'); - if (~isempty (id_tcell)) - # OK, this row has a value cell. Now table-covered-cells must be included. - id_tcell2 = strfind (tablerow, '<table:covered-t'); - if (~isempty (id_tcell2)) id_tcell = sort ([id_tcell id_tcell2]); endif - id_tcell = [id_tcell rowl]; - # Search for non-empty cells (i.e., with an office:value-type attribute). But: - # jOpenDocument 1.2b3 has a bug: it often doesn't set this attr for string cells - id_valtcell = strfind (tablerow, 'office:value-type='); - id_textonlycell = strfind (tablerow, '<text:'); - id_valtcell = sort ([id_valtcell id_textonlycell]); - id_valtcell = [id_valtcell rowl]; - if (~isempty (id_valtcell(1:end-1))) - brow = irow + rowrepcnt; - # First set trow if it hadn't already been found - if (~trow) trow = irow; endif - # Search for repeated table-cells - id_reptcell = strfind (tablerow, 'number-columns-repeated'); - id_reptcell = [id_reptcell rowl]; - # Search for leftmost non-empty table-cell. llcol = counter for this table-row - llcol = 1; - while (id_tcell (llcol) < id_valtcell(1) && llcol <= length (id_tcell) - 1) - ++llcol; - endwhile - --llcol; - # Compensate for repeated cells. First count all repeats left of llcol - ii = 1; - repcnt = 0; - if (~isempty (id_reptcell(1:end-1))) - # First try lcol - while (ii <= length (id_reptcell) - 1 && id_reptcell(ii) < id_valtcell(1)) - # Add all repeat counts left of leftmost data tcell minus 1 for each - [st, en] = regexp (tablerow(id_reptcell(ii):id_reptcell(ii)+30), '\d+'); - repcnt += str2num (tablerow(id_reptcell(ii)+st-1:id_reptcell(ii)+en-1)) - 1; - ++ii; - endwhile - # Next, add current repcnt value to llcol and update lcol - lcol = min (lcol, llcol + repcnt); - # Get last value table-cell in table-cell idx - jj = 1; - while (id_tcell (jj) < id_valtcell(length (id_valtcell)-1)) - ++jj; - endwhile + # 3. Search table-cells. table-c is a table-covered-cell that is considered empty + id_tcell = strfind (tablerow, '<table:table-c'); + if (~isempty (id_tcell)) + # OK, this row has a value cell. Now table-covered-cells must be included. + id_tcell2 = strfind (tablerow, '<table:covered-t'); + if (~isempty (id_tcell2)) id_tcell = sort ([id_tcell id_tcell2]); endif + id_tcell = [id_tcell rowl]; + # Search for non-empty cells (i.e., with an office:value-type attribute). But: + # jOpenDocument 1.2b3 has a bug: it often doesn't set this attr for string cells + id_valtcell = strfind (tablerow, 'office:value-type='); + id_textonlycell = strfind (tablerow, '<text:'); + id_valtcell = sort ([id_valtcell id_textonlycell]); + id_valtcell = [id_valtcell rowl]; + if (~isempty (id_valtcell(1:end-1))) + brow = irow + rowrepcnt; + # First set trow if it hadn't already been found + if (~trow) trow = irow; endif + # Search for repeated table-cells + id_reptcell = strfind (tablerow, 'number-columns-repeated'); + id_reptcell = [id_reptcell rowl]; + # Search for leftmost non-empty table-cell. llcol = counter for this table-row + llcol = 1; + while (id_tcell (llcol) < id_valtcell(1) && llcol <= length (id_tcell) - 1) + ++llcol; + endwhile + --llcol; + # Compensate for repeated cells. First count all repeats left of llcol + ii = 1; + repcnt = 0; + if (~isempty (id_reptcell(1:end-1))) + # First try lcol + while (ii <= length (id_reptcell) - 1 && id_reptcell(ii) < id_valtcell(1)) + # Add all repeat counts left of leftmost data tcell minus 1 for each + [st, en] = regexp (tablerow(id_reptcell(ii):id_reptcell(ii)+30), '\d+'); + repcnt += str2num (tablerow(id_reptcell(ii)+st-1:id_reptcell(ii)+en-1)) - 1; + ++ii; + endwhile + # Next, add current repcnt value to llcol and update lcol + lcol = min (lcol, llcol + repcnt); + # Get last value table-cell in table-cell idx + jj = 1; + while (id_tcell (jj) < id_valtcell(length (id_valtcell)-1)) + ++jj; + endwhile - # Get rest of column repeat counts in value table-cell range - while (ii < length (id_reptcell) && id_reptcell(ii) < id_tcell(jj)) - # Add all repeat counts minus 1 for each tcell in value tcell range - [st, en] = regexp (tablerow(id_reptcell(ii):id_reptcell(ii)+30), '\d+'); - repcnt += str2num (tablerow(id_reptcell(ii)+st-1:id_reptcell(ii)+en-1)) - 1; - ++ii; - endwhile - else - # In case left column = A - lcol = min (lcol, llcol); - endif - # Count all table-cells in value table-cell-range - ii = 1; # Indexes cannot be negative - while (ii < length (id_tcell) && id_tcell(ii) < id_valtcell(length (id_valtcell) - 1)) - ++ii; - endwhile - --ii; - rcol = max (rcol, ii + repcnt); - endif - endif - endfor + # Get rest of column repeat counts in value table-cell range + while (ii < length (id_reptcell) && id_reptcell(ii) < id_tcell(jj)) + # Add all repeat counts minus 1 for each tcell in value tcell range + [st, en] = regexp (tablerow(id_reptcell(ii):id_reptcell(ii)+30), '\d+'); + repcnt += str2num (tablerow(id_reptcell(ii)+st-1:id_reptcell(ii)+en-1)) - 1; + ++ii; + endwhile + else + # In case left column = A + lcol = min (lcol, llcol); + endif + # Count all table-cells in value table-cell-range + ii = 1; # Indexes cannot be negative + while (ii < length (id_tcell) && id_tcell(ii) < id_valtcell(length (id_valtcell) - 1)) + ++ii; + endwhile + --ii; + rcol = max (rcol, ii + repcnt); + endif + endif + endfor else - # No data found, empty sheet - lcol = rcol = brow = trow = 0; + # No data found, empty sheet + lcol = rcol = brow = trow = 0; endif end_try_catch @@ -482,30 +481,30 @@ function [ trow, brow, lcol, rcol ] = getusedrange_com (xls, ii) - sh = xls.workbook.Worksheets (ii); - - # Decipher used range. Beware, UsedRange() returns *cached* rectangle of - # all spreadsheet cells containing *anything*, including just formatting - # (i.e., empty cells are included too). ==> This is an approximation only - allcells = sh.UsedRange; - - # Get top left cell as a Range object - toplftcl = allcells.Columns(1).Rows(1); - - # Count number of rows & cols in virtual range from A1 to top left cell - lcol = sh.Range ("A1", toplftcl).columns.Count; - trow = sh.Range ("A1", toplftcl).rows.Count; - - # Add real occupied rows & cols to obtain end row & col - brow = trow + allcells.rows.Count() - 1; - rcol = lcol + allcells.columns.Count() - 1; - - # Check if there are real data - if ((lcol == rcol) && (trow = brow)) - if (isempty (toplftcl.Value)) - trow = brow = lcol = rcol = 0; - endif + sh = xls.workbook.Worksheets (ii); + + # Decipher used range. Beware, UsedRange() returns *cached* rectangle of + # all spreadsheet cells containing *anything*, including just formatting + # (i.e., empty cells are included too). ==> This is an approximation only + allcells = sh.UsedRange; + + # Get top left cell as a Range object + toplftcl = allcells.Columns(1).Rows(1); + + # Count number of rows & cols in virtual range from A1 to top left cell + lcol = sh.Range ("A1", toplftcl).columns.Count; + trow = sh.Range ("A1", toplftcl).rows.Count; + + # Add real occupied rows & cols to obtain end row & col + brow = trow + allcells.rows.Count() - 1; + rcol = lcol + allcells.columns.Count() - 1; + + # Check if there are real data + if ((lcol == rcol) && (trow = brow)) + if (isempty (toplftcl.Value)) + trow = brow = lcol = rcol = 0; endif + endif endfunction @@ -532,35 +531,35 @@ function [ trow, brow, lcol, rcol ] = getusedrange_poi (xls, ii) - persistent cblnk; cblnk = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); + persistent cblnk; cblnk = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); - sh = xls.workbook.getSheetAt (ii-1); # Java POI starts counting at 0 + sh = xls.workbook.getSheetAt (ii-1); # Java POI starts counting at 0 - trow = sh.getFirstRowNum (); # 0-based - brow = sh.getLastRowNum (); # 0-based - # Get column range - lcol = 1048577; # OOXML (xlsx) max. + 1 - rcol = 0; - botrow = brow; - for jj=trow:brow - irow = sh.getRow (jj); - if (~isempty (irow)) - scol = (irow.getFirstCellNum).intValue (); - lcol = min (lcol, scol); - ecol = (irow.getLastCellNum).intValue () - 1; - rcol = max (rcol, ecol); - # Keep track of lowermost non-empty row as getLastRowNum() is unreliable - if ~(irow.getCell(scol).getCellType () == cblnk && irow.getCell(ecol).getCellType () == cblnk) - botrow = jj; - endif - endif - endfor - if (lcol > 1048576) - # Empty sheet - trow = 0; brow = 0; lcol = 0; rcol = 0; - else - brow = min (brow, botrow) + 1; ++trow; ++lcol; ++rcol; # 1-based return values + trow = sh.getFirstRowNum (); # 0-based + brow = sh.getLastRowNum (); # 0-based + # Get column range + lcol = 1048577; # OOXML (xlsx) max. + 1 + rcol = 0; + botrow = brow; + for jj=trow:brow + irow = sh.getRow (jj); + if (~isempty (irow)) + scol = (irow.getFirstCellNum).intValue (); + lcol = min (lcol, scol); + ecol = (irow.getLastCellNum).intValue () - 1; + rcol = max (rcol, ecol); + # Keep track of lowermost non-empty row as getLastRowNum() is unreliable + if ~(irow.getCell(scol).getCellType () == cblnk && irow.getCell(ecol).getCellType () == cblnk) + botrow = jj; + endif endif + endfor + if (lcol > 1048576) + # Empty sheet + trow = 0; brow = 0; lcol = 0; rcol = 0; + else + brow = min (brow, botrow) + 1; ++trow; ++lcol; ++rcol; # 1-based return values + endif endfunction @@ -588,33 +587,33 @@ function [ trow, brow, lcol, rcol ] = getusedrange_jxl (xls, wsh) - persistent emptycell = (java_get ('jxl.CellType', 'EMPTY')).toString (); + persistent emptycell = (java_get ('jxl.CellType', 'EMPTY')).toString (); - sh = xls.workbook.getSheet (wsh - 1); # JXL sheet count 0-based + sh = xls.workbook.getSheet (wsh - 1); # JXL sheet count 0-based - brow = sh.getRows (); - rcol = sh.getColumns (); - - if (brow == 0 || rcol == 0) - # Empty sheet - trow = 0; lcol = 0; brow = 0; rcol = 0; - else - trow = brow + 1; - lcol = rcol + 1; - for ii=0:brow-1 # For loop coz we must check ALL rows for leftmost column - emptyrow = 1; - jj = 0; - while (jj < rcol && emptyrow) # While loop => only til first non-empty cell - cell = sh.getCell (jj, ii); - if ~(strcmp (char (cell.getType ()), emptycell)) - lcol = min (lcol, jj + 1); - emptyrow = 0; - endif - ++jj; - endwhile - if ~(emptyrow) trow = min (trow, ii + 1); endif - endfor - endif + brow = sh.getRows (); + rcol = sh.getColumns (); + + if (brow == 0 || rcol == 0) + # Empty sheet + trow = 0; lcol = 0; brow = 0; rcol = 0; + else + trow = brow + 1; + lcol = rcol + 1; + for ii=0:brow-1 # For loop coz we must check ALL rows for leftmost column + emptyrow = 1; + jj = 0; + while (jj < rcol && emptyrow) # While loop => only til first non-empty cell + cell = sh.getCell (jj, ii); + if ~(strcmp (char (cell.getType ()), emptycell)) + lcol = min (lcol, jj + 1); + emptyrow = 0; + endif + ++jj; + endwhile + if ~(emptyrow) trow = min (trow, ii + 1); endif + endfor + endif endfunction @@ -643,18 +642,18 @@ function [ trow, brow, lcol, rcol ] = getusedrange_oxs (xls, wsh) - sh = xls.workbook.getWorkSheet (wsh - 1); - try - # Intriguing: sh.getFirst<> is off by one, sh.getLast<> = OK.... 8-Z - trow = sh.getFirstRow () + 1; - brow = sh.getLastRow (); - lcol = sh.getFirstCol () + 1; - rcol = sh.getLastCol (); - catch - # Might be an empty sheet - trow = brow = lcol = rcol = 0; - end_try_catch - # Check for empty sheet - if ((trow > brow) || (lcol > rcol)), trow = brow = lcol = rcol = 0; endif + sh = xls.workbook.getWorkSheet (wsh - 1); + try + # Intriguing: sh.getFirst<> is off by one, sh.getLast<> = OK.... 8-Z + trow = sh.getFirstRow () + 1; + brow = sh.getLastRow (); + lcol = sh.getFirstCol () + 1; + rcol = sh.getLastCol (); + catch + # Might be an empty sheet + trow = brow = lcol = rcol = 0; + end_try_catch + # Check for empty sheet + if ((trow > brow) || (lcol > rcol)), trow = brow = lcol = rcol = 0; endif endfunction
--- a/main/io/inst/oct2ods.m Fri Jun 08 14:11:42 2012 +0000 +++ b/main/io/inst/oct2ods.m Fri Jun 08 15:28:27 2012 +0000 @@ -115,98 +115,96 @@ ## 2012-02-20 Fixed range parameter to be default empty string rather than empty numeral ## 2012-02-27 More range arg fixes ## 2012-03-07 Updated texinfo help text -## 2012-05-22 Cast all numeric data in input array to double +## 2012-06-08 Support for odfdom-incubator-0.8.8 +## '' Tabs replaced by double space ## -## Last update of subfunctions below: 2012-02-26 +## Last update of subfunctions below: 2012-06-08 function [ ods, rstatus ] = oct2ods (c_arr, ods, wsh=1, crange='', spsh_opts=[]) - if (nargin < 2) error ("oct2xls needs a minimum of 2 arguments."); endif + if (nargin < 2) error ("oct2xls needs a minimum of 2 arguments."); endif - # Check if input array is cell - if (isempty (c_arr)) - warning ("Request to write empty matrix - ignored."); - rstatus = 1; - return; - elseif (isnumeric (c_arr)) - c_arr = num2cell (c_arr); - elseif (ischar(c_arr)) - c_arr = {c_arr}; - printf ("(oct2ods: input character array converted to 1x1 cell)\n"); - elseif (~iscell (c_arr)) - error ("oct2ods: input array neither cell nor numeric array"); - endif - if (ndims (c_arr) > 2), error ("Only 2-dimensional arrays can be written to spreadsheet"); endif - # Cast all numerical values to double as spreadsheets only have double/boolean/text type - idx = cellfun (@isnumeric, obj, "UniformOutput", true); - obj(idx) = cellfun (@double, obj(idx), "UniformOutput", false); + # Check if input array is cell + if (isempty (c_arr)) + warning ("Request to write empty matrix - ignored."); + rstatus = 1; + return; + elseif (isnumeric (c_arr)) + c_arr = num2cell (c_arr); + elseif (ischar(c_arr)) + c_arr = {c_arr}; + printf ("(oct2ods: input character array converted to 1x1 cell)\n"); + elseif (~iscell (c_arr)) + error ("oct2ods: input array neither cell nor numeric array"); + endif + if (ndims (c_arr) > 2), error ("Only 2-dimensional arrays can be written to spreadsheet"); endif # Check ods file pointer struct - test1 = ~isfield (ods, "xtype"); - test1 = test1 || ~isfield (ods, "workbook"); - test1 = test1 || isempty (ods.workbook); - test1 = test1 || isempty (ods.app); - if test1 - error ("Arg #2: Invalid ods file pointer struct"); - endif + test1 = ~isfield (ods, "xtype"); + test1 = test1 || ~isfield (ods, "workbook"); + test1 = test1 || isempty (ods.workbook); + test1 = test1 || isempty (ods.app); + if test1 + error ("Arg #2: Invalid ods file pointer struct"); + endif - # Check worksheet ptr - if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 3"); endif + # Check worksheet ptr + if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 3"); endif - # Check range - if (~isempty (crange) && ~ischar (crange)) + # Check range + if (~isempty (crange) && ~ischar (crange)) error ("Character string (range) expected for arg # 4"); elseif (isempty (crange)) crange = ''; endif - # Various options - if (isempty (spsh_opts)) - spsh_opts.formulas_as_text = 0; - # other options to be implemented here - elseif (isstruct (spsh_opts)) - if (~isfield (spsh_opts, 'formulas_as_text')), spsh_opts.formulas_as_text = 0; endif - # other options to be implemented here - else - error ("Structure expected for arg # 5"); - endif - - if (nargout < 1) printf ("Warning: no output spreadsheet file pointer specified.\n"); endif + # Various options + if (isempty (spsh_opts)) + spsh_opts.formulas_as_text = 0; + # other options to be implemented here + elseif (isstruct (spsh_opts)) + if (~isfield (spsh_opts, 'formulas_as_text')), spsh_opts.formulas_as_text = 0; endif + # other options to be implemented here + else + error ("Structure expected for arg # 5"); + endif + + if (nargout < 1) printf ("Warning: no output spreadsheet file pointer specified.\n"); endif - if (strcmp (ods.xtype, 'OTK')) - # Write ods file tru Java & ODF toolkit. - switch ods.odfvsn - case "0.7.5" - [ ods, rstatus ] = oct2jotk2ods (c_arr, ods, wsh, crange, spsh_opts); - case {"0.8.6", "0.8.7"} - [ ods, rstatus ] = oct3jotk2ods (c_arr, ods, wsh, crange, spsh_opts); - otherwise - error ("Unsupported odfdom version"); - endswitch + if (strcmp (ods.xtype, 'OTK')) + # Write ods file tru Java & ODF toolkit. + switch ods.odfvsn + case "0.7.5" + [ ods, rstatus ] = oct2jotk2ods (c_arr, ods, wsh, crange, spsh_opts); + case {"0.8.6", "0.8.7", "0.8.8"} + [ ods, rstatus ] = oct3jotk2ods (c_arr, ods, wsh, crange, spsh_opts); + otherwise + error ("Unsupported odfdom version"); + endswitch - elseif (strcmp (ods.xtype, 'JOD')) - # Write ods file tru Java & jOpenDocument. API still leaves lots to be wished... - [ ods, rstatus ] = oct2jod2ods (c_arr, ods, wsh, crange); + elseif (strcmp (ods.xtype, 'JOD')) + # Write ods file tru Java & jOpenDocument. API still leaves lots to be wished... + [ ods, rstatus ] = oct2jod2ods (c_arr, ods, wsh, crange); - elseif (strcmp (ods.xtype, 'UNO')) - # Write ods file tru Java & UNO bridge (OpenOffice.org & clones) - [ ods, rstatus ] = oct2uno2ods (c_arr, ods, wsh, crange, spsh_opts); + elseif (strcmp (ods.xtype, 'UNO')) + # Write ods file tru Java & UNO bridge (OpenOffice.org & clones) + [ ods, rstatus ] = oct2uno2ods (c_arr, ods, wsh, crange, spsh_opts); -# elseif - # ---- < Other interfaces here > +# elseif + # ---- < Other interfaces here > - else - error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); - endif + else + error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); + endif - if (rstatus), ods.limits = []; endif + if (rstatus), ods.limits = []; endif endfunction #============================================================================= -## Copyright (C) 2010,2011 Philip Nienhuis <prnienhuis@users.sf.net> +## Copyright (C) 2010,2011,2012 Philip Nienhuis <prnienhuis@users.sf.net> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software @@ -253,401 +251,401 @@ function [ ods, rstatus ] = oct2jotk2ods (c_arr, ods, wsh, crange, spsh_opts) - persistent ctype; - if (isempty (ctype)) - # Number, Boolean, String, Formula, Empty, Date, Time (last 2 are ignored) - ctype = [1, 2, 3, 4, 5, 6, 7]; - endif + persistent ctype; + if (isempty (ctype)) + # Number, Boolean, String, Formula, Empty, Date, Time (last 2 are ignored) + ctype = [1, 2, 3, 4, 5, 6, 7]; + endif - rstatus = 0; f_errs = 0; + rstatus = 0; f_errs = 0; - # Get some basic spreadsheet data from the pointer using ODFtoolkit - odfcont = ods.workbook; - xpath = ods.app.getXPath (); - offsprdsh = ods.app.getContentRoot(); - autostyles = odfcont.getOrCreateAutomaticStyles(); - officestyles = ods.app.getOrCreateDocumentStyles(); + # Get some basic spreadsheet data from the pointer using ODFtoolkit + odfcont = ods.workbook; + xpath = ods.app.getXPath (); + offsprdsh = ods.app.getContentRoot(); + autostyles = odfcont.getOrCreateAutomaticStyles(); + officestyles = ods.app.getOrCreateDocumentStyles(); - # Create an instance of type NODESET for use in subsequent statements - NODESET = java_get ('javax.xml.xpath.XPathConstants', 'NODESET'); + # Create an instance of type NODESET for use in subsequent statements + NODESET = java_get ('javax.xml.xpath.XPathConstants', 'NODESET'); - # Parse sheets ("tables") from ODS file - sheets = xpath.evaluate ("//table:table", odfcont, NODESET); - nr_of_sheets = sheets.getLength (); - newsh = 0; # Assume existing sheet - if isempty (wsh) wsh = 1; endif - if (~isnumeric (wsh)) # Sheet name specified - # Search in sheet names, match sheet name to sheet number. - # Beware, 0-based index, 1-based count! - ii = 0; - while (++ii <= nr_of_sheets && ischar (wsh)) - # Look in first part of the sheet nodeset - sh_name = sheets.item(ii-1).getTableNameAttribute (); - if (strcmp (sh_name, wsh)) - # Convert local copy of wsh into a number (pointer) - wsh = ii - 1; - endif - endwhile - if (ischar (wsh) && nr_of_sheets < 256) newsh = 1; endif - else # Sheet index specified - if ((ods.changed > 2) || (wsh > nr_of_sheets && wsh < 256)) # Max nr of sheets = 256 - # Create a new sheet - newsh = 1; - elseif (wsh <=nr_of_sheets && wsh > 0) - # Existing sheet. Count = 1-based, index = 0-based - --wsh; sh = sheets.item(wsh); - printf ("Writing to sheet %s\n", sh.getTableNameAttribute()); - else - error ("oct2ods: illegal sheet number."); - endif - endif + # Parse sheets ("tables") from ODS file + sheets = xpath.evaluate ("//table:table", odfcont, NODESET); + nr_of_sheets = sheets.getLength (); + newsh = 0; # Assume existing sheet + if isempty (wsh) wsh = 1; endif + if (~isnumeric (wsh)) # Sheet name specified + # Search in sheet names, match sheet name to sheet number. + # Beware, 0-based index, 1-based count! + ii = 0; + while (++ii <= nr_of_sheets && ischar (wsh)) + # Look in first part of the sheet nodeset + sh_name = sheets.item(ii-1).getTableNameAttribute (); + if (strcmp (sh_name, wsh)) + # Convert local copy of wsh into a number (pointer) + wsh = ii - 1; + endif + endwhile + if (ischar (wsh) && nr_of_sheets < 256) newsh = 1; endif + else # Sheet index specified + if ((ods.changed > 2) || (wsh > nr_of_sheets && wsh < 256)) # Max nr of sheets = 256 + # Create a new sheet + newsh = 1; + elseif (wsh <=nr_of_sheets && wsh > 0) + # Existing sheet. Count = 1-based, index = 0-based + --wsh; sh = sheets.item(wsh); + printf ("Writing to sheet %s\n", sh.getTableNameAttribute()); + else + error ("oct2ods: illegal sheet number."); + endif + endif # Check size of data array & range / capacity of worksheet & prepare vars - [nr, nc] = size (c_arr); - [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, ods.xtype, ods.filename); - --trow; --lcol; # Zero-based row # & col # - if (nrows < nr || ncols < nc) - warning ("Array truncated to fit in range"); - c_arr = c_arr(1:nrows, 1:ncols); - endif - + [nr, nc] = size (c_arr); + [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, ods.xtype, ods.filename); + --trow; --lcol; # Zero-based row # & col # + if (nrows < nr || ncols < nc) + warning ("Array truncated to fit in range"); + c_arr = c_arr(1:nrows, 1:ncols); + endif + # Parse data array, setup typarr and throw out NaNs to speed up writing; - typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts, 0); - if ~(spsh_opts.formulas_as_text) - # Find formulas (designated by a string starting with "=" and ending in ")") - fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) && strncmp (x(end:end), ")", 1), c_arr); - typearr(fptr) = ctype(4); # FORMULA - endif + typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts, 0); + if ~(spsh_opts.formulas_as_text) + # Find formulas (designated by a string starting with "=" and ending in ")") + fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) && strncmp (x(end:end), ")", 1), c_arr); + typearr(fptr) = ctype(4); # FORMULA + endif # Prepare worksheet for writing. If needed create new sheet - if (newsh) - if (ods.changed > 2) - # New spreadsheet. Prepare to use the default 1x1 first sheet. - sh = sheets.item(0); - else - # Other sheets exist, create a new sheet. First the basics - sh = java_new ('org.odftoolkit.odfdom.doc.table.OdfTable', odfcont); - # Append sheet to spreadsheet ( contentRoot) - offsprdsh.appendChild (sh); - # Rebuild sheets nodes - sheets = xpath.evaluate ("//table:table", odfcont, NODESET); - endif + if (newsh) + if (ods.changed > 2) + # New spreadsheet. Prepare to use the default 1x1 first sheet. + sh = sheets.item(0); + else + # Other sheets exist, create a new sheet. First the basics + sh = java_new ('org.odftoolkit.odfdom.doc.table.OdfTable', odfcont); + # Append sheet to spreadsheet ( contentRoot) + offsprdsh.appendChild (sh); + # Rebuild sheets nodes + sheets = xpath.evaluate ("//table:table", odfcont, NODESET); + endif - # Sheet name - if (isnumeric (wsh)) - # Give sheet a name - str = sprintf ("Sheet%d", wsh); - sh.setTableNameAttribute (str); - else - # Assign name to sheet and change wsh into numeric pointer - sh.setTableNameAttribute (wsh); - wsh = sheets.getLength () - 1; - endif - # Fixup wsh pointer in case of new spreadsheet - if (ods.changed > 2) wsh = 0; endif + # Sheet name + if (isnumeric (wsh)) + # Give sheet a name + str = sprintf ("Sheet%d", wsh); + sh.setTableNameAttribute (str); + else + # Assign name to sheet and change wsh into numeric pointer + sh.setTableNameAttribute (wsh); + wsh = sheets.getLength () - 1; + endif + # Fixup wsh pointer in case of new spreadsheet + if (ods.changed > 2) wsh = 0; endif - # Add table-column entry for style etc - col = sh.addTableColumn (); - col.setTableDefaultCellStyleNameAttribute ("Default"); - col.setTableNumberColumnsRepeatedAttribute (lcol + ncols + 1); - col.setTableStyleNameAttribute ("co1"); + # Add table-column entry for style etc + col = sh.addTableColumn (); + col.setTableDefaultCellStyleNameAttribute ("Default"); + col.setTableNumberColumnsRepeatedAttribute (lcol + ncols + 1); + col.setTableStyleNameAttribute ("co1"); - # Build up the complete row & cell structure to cover the data array. - # This will speed up processing later + # Build up the complete row & cell structure to cover the data array. + # This will speed up processing later - # 1. Build empty table row template - row = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableRow', odfcont); - # Create an empty tablecell & append it to the row - scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); - scell = row.appendCell (scell); - scell.setTableNumberColumnsRepeatedAttribute (1024); - # 2. If needed add empty filler row above the data rows & if needed add repeat count - if (trow > 0) - sh.appendRow (row); - if (trow > 1) row.setTableNumberRowsRepeatedAttribute (trow); endif - endif - # 3. Add data rows; first one serves as a template - drow = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableRow', odfcont); - if (lcol > 0) - scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); - drow.appendCell (scell); - if (lcol > 1) scell.setTableNumberColumnsRepeatedAttribute (lcol); endif - endif - # 4. Add data cell placeholders - scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); - drow.appendCell (scell); - for jj=2:ncols - dcell = scell.cloneNode (1); # Deep copy - drow.appendCell (dcell); - endfor - # 5. Last cell is remaining column counter - rest = max (1024 - lcol - ncols); - if (rest) - dcell = scell.cloneNode (1); # Deep copy - drow.appendCell (dcell); - if (rest > 1) dcell.setTableNumberColumnsRepeatedAttribute (rest); endif - endif - # Only now add drow as otherwise for each cell an empty table-column is - # inserted above the rows (odftoolkit bug?) - sh.appendRow (drow); - if (ods.changed > 2) - # In case of a completely new spreadsheet, delete the first initial 1-cell row - # But check if it *is* a row... - try - sh.removeChild (drow.getPreviousRow ()); - catch - # Nothing. Apparently there was only the just appended row. - end_try_catch - endif - # 6. Row template ready. Copy row template down to cover future array - for ii=2:nrows - nrow = drow.cloneNode (1); # Deep copy - sh.appendRow (nrow); - endfor - ods.changed = min (ods.changed, 2); # Keep 2 for new spshsht, 1 for existing + changed + # 1. Build empty table row template + row = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableRow', odfcont); + # Create an empty tablecell & append it to the row + scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); + scell = row.appendCell (scell); + scell.setTableNumberColumnsRepeatedAttribute (1024); + # 2. If needed add empty filler row above the data rows & if needed add repeat count + if (trow > 0) + sh.appendRow (row); + if (trow > 1) row.setTableNumberRowsRepeatedAttribute (trow); endif + endif + # 3. Add data rows; first one serves as a template + drow = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableRow', odfcont); + if (lcol > 0) + scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); + drow.appendCell (scell); + if (lcol > 1) scell.setTableNumberColumnsRepeatedAttribute (lcol); endif + endif + # 4. Add data cell placeholders + scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); + drow.appendCell (scell); + for jj=2:ncols + dcell = scell.cloneNode (1); # Deep copy + drow.appendCell (dcell); + endfor + # 5. Last cell is remaining column counter + rest = max (1024 - lcol - ncols); + if (rest) + dcell = scell.cloneNode (1); # Deep copy + drow.appendCell (dcell); + if (rest > 1) dcell.setTableNumberColumnsRepeatedAttribute (rest); endif + endif + # Only now add drow as otherwise for each cell an empty table-column is + # inserted above the rows (odftoolkit bug?) + sh.appendRow (drow); + if (ods.changed > 2) + # In case of a completely new spreadsheet, delete the first initial 1-cell row + # But check if it *is* a row... + try + sh.removeChild (drow.getPreviousRow ()); + catch + # Nothing. Apparently there was only the just appended row. + end_try_catch + endif + # 6. Row template ready. Copy row template down to cover future array + for ii=2:nrows + nrow = drow.cloneNode (1); # Deep copy + sh.appendRow (nrow); + endfor + ods.changed = min (ods.changed, 2); # Keep 2 for new spshsht, 1 for existing + changed - else - # Existing sheet. We must be prepared for all situations, incomplete rows, - # number-rows/columns-repeated, merged (spanning) cells, you name it. - # First explore row buildup of existing sheet using an XPath - sh = sheets.item(wsh); # 0 - based - str = sprintf ("//table:table[%d]/table:table-row", wsh + 1); # 1 - based - trows = xpath.evaluate (str, odfcont, NODESET); - nr_of_trows = trows.getLength(); # Nr. of existing table-rows, not data rows! + else + # Existing sheet. We must be prepared for all situations, incomplete rows, + # number-rows/columns-repeated, merged (spanning) cells, you name it. + # First explore row buildup of existing sheet using an XPath + sh = sheets.item(wsh); # 0 - based + str = sprintf ("//table:table[%d]/table:table-row", wsh + 1); # 1 - based + trows = xpath.evaluate (str, odfcont, NODESET); + nr_of_trows = trows.getLength(); # Nr. of existing table-rows, not data rows! - # For the first rows we do some preprocessing here. Similar stuff for cells - # i.e. table-cells (columns) is done in the loops below. - # Make sure the upper data array row doesn't end up in a nr-rows-repeated row + # For the first rows we do some preprocessing here. Similar stuff for cells + # i.e. table-cells (columns) is done in the loops below. + # Make sure the upper data array row doesn't end up in a nr-rows-repeated row - # Provisionally! set start table-row in case "while" & "if" (split) are skipped - drow = trows.item(0); - rowcnt = 0; trowcnt = 0; # Spreadsheet/ table-rows, resp; - while (rowcnt < trow && trowcnt < nr_of_trows) - # Count rows & table-rows UNTIL we reach trow - ++trowcnt; # Nr of table-rows - row = drow; - drow = row.getNextSibling (); - repcnt = row.getTableNumberRowsRepeatedAttribute(); - rowcnt = rowcnt + repcnt; # Nr of spreadsheet rows - endwhile - rsplit = rowcnt - trow; - if (rsplit > 0) - # Apparently a nr-rows-repeated top table-row must be split, as the - # first data row seems to be projected in it (1st while condition above!) - row.removeAttribute ('table:number-rows-repeated'); - row.getCellAt (0).removeAttribute ('table:number-columns-repeated'); - nrow = row.cloneNode (1); - drow = nrow; # Future upper data array row - if (repcnt > 1) - row.setTableNumberRowsRepeatedAttribute (repcnt - rsplit); - else - row.removeAttribute ('table:number-rows-repeated'); - endif - rrow = row.getNextSibling (); - sh.insertBefore (nrow, rrow); - for jj=2:rsplit - nrow = nrow.cloneNode (1); - sh.insertBefore (nrow, rrow); - endfor - elseif (rsplit < 0) - # New data rows to be added below existing data & table(!) rows, i.e. - # beyond lower end of the current sheet. Add filler row and 1st data row - row = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableRow', odfcont); - drow = row.cloneNode (1); # First data row - row.setTableNumberRowsRepeatedAttribute (-rsplit); # Filler row - scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); - dcell = scell.cloneNode (1); - scell.setTableNumberColumnsRepeatedAttribute (COL_CAP); # Filler cell - row.appendCell (scell); - sh.appendRow (row); - drow.appendCell (dcell); - sh.appendRow (drow); - endif - endif + # Provisionally! set start table-row in case "while" & "if" (split) are skipped + drow = trows.item(0); + rowcnt = 0; trowcnt = 0; # Spreadsheet/ table-rows, resp; + while (rowcnt < trow && trowcnt < nr_of_trows) + # Count rows & table-rows UNTIL we reach trow + ++trowcnt; # Nr of table-rows + row = drow; + drow = row.getNextSibling (); + repcnt = row.getTableNumberRowsRepeatedAttribute(); + rowcnt = rowcnt + repcnt; # Nr of spreadsheet rows + endwhile + rsplit = rowcnt - trow; + if (rsplit > 0) + # Apparently a nr-rows-repeated top table-row must be split, as the + # first data row seems to be projected in it (1st while condition above!) + row.removeAttribute ('table:number-rows-repeated'); + row.getCellAt (0).removeAttribute ('table:number-columns-repeated'); + nrow = row.cloneNode (1); + drow = nrow; # Future upper data array row + if (repcnt > 1) + row.setTableNumberRowsRepeatedAttribute (repcnt - rsplit); + else + row.removeAttribute ('table:number-rows-repeated'); + endif + rrow = row.getNextSibling (); + sh.insertBefore (nrow, rrow); + for jj=2:rsplit + nrow = nrow.cloneNode (1); + sh.insertBefore (nrow, rrow); + endfor + elseif (rsplit < 0) + # New data rows to be added below existing data & table(!) rows, i.e. + # beyond lower end of the current sheet. Add filler row and 1st data row + row = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableRow', odfcont); + drow = row.cloneNode (1); # First data row + row.setTableNumberRowsRepeatedAttribute (-rsplit); # Filler row + scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); + dcell = scell.cloneNode (1); + scell.setTableNumberColumnsRepeatedAttribute (COL_CAP); # Filler cell + row.appendCell (scell); + sh.appendRow (row); + drow.appendCell (dcell); + sh.appendRow (drow); + endif + endif # For each row, for each cell, add the data. Expand row/column-repeated nodes - row = drow; # Start row; pointer still exists from above stanzas - for ii=1:nrows - if (~newsh) # Only for existing sheets the next checks should be made - # While processing next data rows, fix table-rows if needed - if (isempty (row) || (row.getLength () < 1)) - # Append an empty row with just one empty cell - row = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableRow', odfcont); - scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); - scell.setTableNumberColumnsRepeatedAttribute (lcol + 1); - row.appendCell (scell); - sh.appendRow (row); - else - # If needed expand nr-rows-repeated - repcnt = row.getTableNumberRowsRepeatedAttribute (); - if (repcnt > 1) - row.removeAttribute ('table:number-rows-repeated'); - # Insert new table-rows above row until our new data space is complete. - # Keep handle of upper new table-row as that's where data are added 1st - drow = row.cloneNode (1); - sh.insertBefore (drow, row); - for kk=1:min (repcnt, nrows-ii) - nrow = row.cloneNode (1); - sh.insertBefore (nrow, row); - endfor - if (repcnt > nrows-ii+1) - row.setTableNumberRowsRepeatedAttribute (repcnt - nrows +ii - 1); - endif - row = drow; - endif - endif + row = drow; # Start row; pointer still exists from above stanzas + for ii=1:nrows + if (~newsh) # Only for existing sheets the next checks should be made + # While processing next data rows, fix table-rows if needed + if (isempty (row) || (row.getLength () < 1)) + # Append an empty row with just one empty cell + row = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableRow', odfcont); + scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); + scell.setTableNumberColumnsRepeatedAttribute (lcol + 1); + row.appendCell (scell); + sh.appendRow (row); + else + # If needed expand nr-rows-repeated + repcnt = row.getTableNumberRowsRepeatedAttribute (); + if (repcnt > 1) + row.removeAttribute ('table:number-rows-repeated'); + # Insert new table-rows above row until our new data space is complete. + # Keep handle of upper new table-row as that's where data are added 1st + drow = row.cloneNode (1); + sh.insertBefore (drow, row); + for kk=1:min (repcnt, nrows-ii) + nrow = row.cloneNode (1); + sh.insertBefore (nrow, row); + endfor + if (repcnt > nrows-ii+1) + row.setTableNumberRowsRepeatedAttribute (repcnt - nrows +ii - 1); + endif + row = drow; + endif + endif - # Check if leftmost cell ends up in nr-cols-repeated cell - colcnt = 0; tcellcnt = 0; rcellcnt = row.getLength(); - dcell = row.getCellAt (0); - while (colcnt < lcol && tcellcnt < rcellcnt) - # Count columns UNTIL we hit lcol - ++tcellcnt; # Nr of table-cells counted - scell = dcell; - dcell = scell.getNextSibling (); - repcnt = scell.getTableNumberColumnsRepeatedAttribute (); - colcnt = colcnt + repcnt; # Nr of spreadsheet cell counted - endwhile - csplit = colcnt - lcol; - if (csplit > 0) - # Apparently a nr-columns-repeated cell must be split - scell.removeAttribute ('table:number-columns-repeated'); - ncell = scell.cloneNode (1); - if (repcnt > 1) - scell.setTableNumberColumnsRepeatedAttribute (repcnt - csplit); - else - scell.removeAttribute ('table:number-columns-repeated'); - endif - rcell = scell.getNextSibling (); - row.insertBefore (ncell, rcell); - for jj=2:csplit - ncell = ncell.cloneNode (1); - row.insertBefore (ncell, rcell); - endfor - elseif (csplit < 0) - # New cells to be added beyond current last cell & table-cell in row - dcell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); - scell = dcell.cloneNode (1); - dcell.setTableNumberColumnsRepeatedAttribute (-csplit); - row.appendCell (dcell); - row.appendCell (scell); - endif - endif + # Check if leftmost cell ends up in nr-cols-repeated cell + colcnt = 0; tcellcnt = 0; rcellcnt = row.getLength(); + dcell = row.getCellAt (0); + while (colcnt < lcol && tcellcnt < rcellcnt) + # Count columns UNTIL we hit lcol + ++tcellcnt; # Nr of table-cells counted + scell = dcell; + dcell = scell.getNextSibling (); + repcnt = scell.getTableNumberColumnsRepeatedAttribute (); + colcnt = colcnt + repcnt; # Nr of spreadsheet cell counted + endwhile + csplit = colcnt - lcol; + if (csplit > 0) + # Apparently a nr-columns-repeated cell must be split + scell.removeAttribute ('table:number-columns-repeated'); + ncell = scell.cloneNode (1); + if (repcnt > 1) + scell.setTableNumberColumnsRepeatedAttribute (repcnt - csplit); + else + scell.removeAttribute ('table:number-columns-repeated'); + endif + rcell = scell.getNextSibling (); + row.insertBefore (ncell, rcell); + for jj=2:csplit + ncell = ncell.cloneNode (1); + row.insertBefore (ncell, rcell); + endfor + elseif (csplit < 0) + # New cells to be added beyond current last cell & table-cell in row + dcell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); + scell = dcell.cloneNode (1); + dcell.setTableNumberColumnsRepeatedAttribute (-csplit); + row.appendCell (dcell); + row.appendCell (scell); + endif + endif - # Write a row of data from data array, column by column - - for jj=1:ncols - scell = row.getCellAt (lcol + jj - 1); - if (~newsh) - if (isempty (scell)) - # Apparently end of row encountered. Add cell - scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); - scell = row.appendCell (scell); - else - # If needed expand nr-cols-repeated - repcnt = scell.getTableNumberColumnsRepeatedAttribute (); - if (repcnt > 1) - scell.removeAttribute ('table:number-columns-repeated'); - for kk=2:repcnt - ncell = scell.cloneNode (1); - row.insertBefore (ncell, scell.getNextSibling ()); - endfor - endif - endif - # Clear text contents - while (scell.hasChildNodes ()) - tmp = scell.getFirstChild (); - scell.removeChild (tmp); - endwhile - scell.removeAttribute ('table:formula'); - endif + # Write a row of data from data array, column by column + + for jj=1:ncols + scell = row.getCellAt (lcol + jj - 1); + if (~newsh) + if (isempty (scell)) + # Apparently end of row encountered. Add cell + scell = java_new ('org.odftoolkit.odfdom.doc.table.OdfTableCell', odfcont); + scell = row.appendCell (scell); + else + # If needed expand nr-cols-repeated + repcnt = scell.getTableNumberColumnsRepeatedAttribute (); + if (repcnt > 1) + scell.removeAttribute ('table:number-columns-repeated'); + for kk=2:repcnt + ncell = scell.cloneNode (1); + row.insertBefore (ncell, scell.getNextSibling ()); + endfor + endif + endif + # Clear text contents + while (scell.hasChildNodes ()) + tmp = scell.getFirstChild (); + scell.removeChild (tmp); + endwhile + scell.removeAttribute ('table:formula'); + endif - # Empty cell count stuff done. At last we can add the data - switch (typearr (ii, jj)) - case 1 # float - scell.setOfficeValueTypeAttribute ('float'); - scell.setOfficeValueAttribute (c_arr{ii, jj}); - case 2 # boolean - # Beware, for unpatched-for-booleans java-1.2.7- we must resort to floats - try - # First try the preferred java-boolean way - scell.setOfficeValueTypeAttribute ('boolean'); - scell.removeAttribute ('office:value'); - if (c_arr{ii, jj}) - scell.setOfficeBooleanValueAttribute (1); - else - scell.setOfficeBooleanValueAttribute (0); - endif - catch - # Unpatched java package. Fall back to transferring a float - scell.setOfficeValueTypeAttribute ('float'); - if (c_arr{ii, jj}) - scell.setOfficeValueAttribute (1); - else - scell.setOfficeValueAttribute (0); - endif - end_try_catch - case 3 # string - scell.setOfficeValueTypeAttribute ('string'); - pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', c_arr{ii, jj}); - scell.appendChild (pe); - case 4 # Formula. - # As we don't know the result type, simply remove previous type info. - # Once OOo Calc reads it, it'll add the missing attributes - scell.removeAttribute ('office:value'); - scell.removeAttribute ('office:value-type'); - # Try-catch not strictly needed, there's no formula validator yet - try - scell.setTableFormulaAttribute (c_arr{ii, jj}); - scell.setOfficeValueTypeAttribute ('string'); - pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', '#Recalc Formula#'); - scell.appendChild (pe); - catch - ++f_errs; - scell.setOfficeValueTypeAttribute ('string'); - pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', c_arr{ii, jj}); - scell.appendChild (pe); - end_try_catch - case {0 5} # Empty. Clear value attributes - if (~newsh) - scell.removeAttribute ('office:value-type'); - scell.removeAttribute ('office:value'); - endif - case 6 # Date (implemented but Octave has no "date" data type - yet?) - scell.setOfficeValueTypeAttribute ('date'); - [hh mo dd hh mi ss] = datevec (c_arr{ii,jj}); - str = sprintf ("%4d-%2d-%2dT%2d:%2d:%2d", yy, mo, dd, hh, mi, ss); - scell.setOfficeDateValueAttribute (str); - case 7 # Time (implemented but Octave has no "time" data type) - scell.setOfficeValueTypeAttribute ('time'); - [hh mo dd hh mi ss] = datevec (c_arr{ii,jj}); - str = sprintf ("PT%2d:%2d:%2d", hh, mi, ss); - scell.setOfficeTimeValuettribute (str); - otherwise - # Nothing - endswitch + # Empty cell count stuff done. At last we can add the data + switch (typearr (ii, jj)) + case 1 # float + scell.setOfficeValueTypeAttribute ('float'); + scell.setOfficeValueAttribute (c_arr{ii, jj}); + case 2 # boolean + # Beware, for unpatched-for-booleans java-1.2.7- we must resort to floats + try + # First try the preferred java-boolean way + scell.setOfficeValueTypeAttribute ('boolean'); + scell.removeAttribute ('office:value'); + if (c_arr{ii, jj}) + scell.setOfficeBooleanValueAttribute (1); + else + scell.setOfficeBooleanValueAttribute (0); + endif + catch + # Unpatched java package. Fall back to transferring a float + scell.setOfficeValueTypeAttribute ('float'); + if (c_arr{ii, jj}) + scell.setOfficeValueAttribute (1); + else + scell.setOfficeValueAttribute (0); + endif + end_try_catch + case 3 # string + scell.setOfficeValueTypeAttribute ('string'); + pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', c_arr{ii, jj}); + scell.appendChild (pe); + case 4 # Formula. + # As we don't know the result type, simply remove previous type info. + # Once OOo Calc reads it, it'll add the missing attributes + scell.removeAttribute ('office:value'); + scell.removeAttribute ('office:value-type'); + # Try-catch not strictly needed, there's no formula validator yet + try + scell.setTableFormulaAttribute (c_arr{ii, jj}); + scell.setOfficeValueTypeAttribute ('string'); + pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', '#Recalc Formula#'); + scell.appendChild (pe); + catch + ++f_errs; + scell.setOfficeValueTypeAttribute ('string'); + pe = java_new ('org.odftoolkit.odfdom.doc.text.OdfTextParagraph', odfcont,'', c_arr{ii, jj}); + scell.appendChild (pe); + end_try_catch + case {0 5} # Empty. Clear value attributes + if (~newsh) + scell.removeAttribute ('office:value-type'); + scell.removeAttribute ('office:value'); + endif + case 6 # Date (implemented but Octave has no "date" data type - yet?) + scell.setOfficeValueTypeAttribute ('date'); + [hh mo dd hh mi ss] = datevec (c_arr{ii,jj}); + str = sprintf ("%4d-%2d-%2dT%2d:%2d:%2d", yy, mo, dd, hh, mi, ss); + scell.setOfficeDateValueAttribute (str); + case 7 # Time (implemented but Octave has no "time" data type) + scell.setOfficeValueTypeAttribute ('time'); + [hh mo dd hh mi ss] = datevec (c_arr{ii,jj}); + str = sprintf ("PT%2d:%2d:%2d", hh, mi, ss); + scell.setOfficeTimeValuettribute (str); + otherwise + # Nothing + endswitch - scell = scell.getNextSibling (); + scell = scell.getNextSibling (); - endfor + endfor - row = row.getNextSibling (); + row = row.getNextSibling (); - endfor + endfor - if (f_errs) - printf ("%d formula errors encountered - please check input array\n", f_errs); - endif - ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) - rstatus = 1; - + if (f_errs) + printf ("%d formula errors encountered - please check input array\n", f_errs); + endif + ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) + rstatus = 1; + endfunction #============================================================================= -## Copyright (C) 2010,2011 Philip Nienhuis <prnienhuis _at- users.sf.net> +## Copyright (C) 2010,2011,2012 Philip Nienhuis <prnienhuis _at- users.sf.net> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software @@ -662,9 +660,9 @@ ## You should have received a copy of the GNU General Public License along with ## this program; if not, see <http://www.gnu.org/licenses/>. -## odf3jotk2oct - read ODS spreadsheet data using Java & odftoolkit v 0.8.6. -## You need proper java-for-octave & odfdom.jar 0.8.6 + xercesImpl.jar -## in your javaclasspath. For reliable writing odfdom-0.8.6 is still +## odf3jotk2oct - read ODS spreadsheet data using Java & odftoolkit v 0.8.6+. +## You need proper java-for-octave & odfdom.jar 0.8.6+ & xercesImpl.jar 2.9.1 +## in your javaclasspath. For reliable writing odfdom-0.8.6+ is still ## experimental :-( v. 0.7.5 has been tested much more ## ## Author: Philip Nenhuis <pr.nienhuis at users.sf.net> @@ -684,167 +682,168 @@ ## 2010-11-12 Improved file change tracking tru ods.changed ## 2010-12-08 Bugfixes (obj -> arg L.715; removed stray arg in call to spsh_prstype L.719) ## 2011-03-23 First try of odfdom 0.8.7 +## 2012-06-08 Support for odfdom-incubator-0.8.8 function [ ods, rstatus ] = oct3jotk2ods (c_arr, ods, wsh, crange, spsh_opts) - persistent ctype; - if (isempty (ctype)) - # Number, Boolean, String, Formula, Empty; Date, Time - last two aren't used - ctype = [1, 2, 3, 4, 5, 6, 7]; - endif + persistent ctype; + if (isempty (ctype)) + # Number, Boolean, String, Formula, Empty; Date, Time - last two aren't used + ctype = [1, 2, 3, 4, 5, 6, 7]; + endif - rstatus = 0; changed = 0; newsh = 0; + rstatus = 0; changed = 0; newsh = 0; - # Get contents and table stuff from the workbook - odfcont = ods.workbook; # Use a local copy just to be sure. octave - # makes physical copies only when needed (?) - odfroot = odfcont.getRootElement (); - offsprdsh = ods.app.getContentRoot(); - if (strcmp (ods.odfvsn, '0.8.7')) - spsh = odfcont.getDocument (); - else - spsh = odfcont.getOdfDocument (); - endif + # Get contents and table stuff from the workbook + odfcont = ods.workbook; # Use a local copy just to be sure. octave + # makes physical copies only when needed (?) + odfroot = odfcont.getRootElement (); + offsprdsh = ods.app.getContentRoot(); + if (strcmp (ods.odfvsn, '0.8.7') || strfind (ods.odfvsn, "0.8.8")) + spsh = odfcont.getDocument (); + else + spsh = odfcont.getOdfDocument (); + endif - # Get some basic spreadsheet data from the pointer using ODFtoolkit - autostyles = odfcont.getOrCreateAutomaticStyles(); - officestyles = ods.app.getOrCreateDocumentStyles(); + # Get some basic spreadsheet data from the pointer using ODFtoolkit + autostyles = odfcont.getOrCreateAutomaticStyles(); + officestyles = ods.app.getOrCreateDocumentStyles(); - # Parse sheets ("tables") from ODS file - sheets = ods.app.getTableList(); - nr_of_sheets = sheets.size (); - # Check user input & find sheet pointer - if (~isnumeric (wsh)) - try - sh = ods.app.getTableByName (wsh); - # We do need a sheet index number... - ii = 0; - while (ischar (wsh) && ii < nr_of_sheets) - sh_nm = sh.getTableName (); - if (strcmp (sh_nm, wsh)) wsh = ii + 1; else ++ii; endif - endwhile - catch - newsh = 1; - end_try_catch - if isempty (sh) newsh = 1; endif - elseif (wsh < 1) - # Negative sheet number: - error (sprintf ("Illegal worksheet nr. %d\n", wsh)); - elseif (wsh > nr_of_sheets) - newsh = 1; - else - sh = sheets.get (wsh - 1); - endif + # Parse sheets ("tables") from ODS file + sheets = ods.app.getTableList(); + nr_of_sheets = sheets.size (); + # Check user input & find sheet pointer + if (~isnumeric (wsh)) + try + sh = ods.app.getTableByName (wsh); + # We do need a sheet index number... + ii = 0; + while (ischar (wsh) && ii < nr_of_sheets) + sh_nm = sh.getTableName (); + if (strcmp (sh_nm, wsh)) wsh = ii + 1; else ++ii; endif + endwhile + catch + newsh = 1; + end_try_catch + if isempty (sh) newsh = 1; endif + elseif (wsh < 1) + # Negative sheet number: + error (sprintf ("Illegal worksheet nr. %d\n", wsh)); + elseif (wsh > nr_of_sheets) + newsh = 1; + else + sh = sheets.get (wsh - 1); + endif - # Check size of data array & range / capacity of worksheet & prepare vars - [nr, nc] = size (c_arr); - [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, ods.xtype, ods.filename); - --trow; --lcol; # Zero-based row # & col # - if (nrows < nr || ncols < nc) - warning ("Array truncated to fit in range"); - c_arr = c_arr(1:nrows, 1:ncols); - endif - + # Check size of data array & range / capacity of worksheet & prepare vars + [nr, nc] = size (c_arr); + [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, ods.xtype, ods.filename); + --trow; --lcol; # Zero-based row # & col # + if (nrows < nr || ncols < nc) + warning ("Array truncated to fit in range"); + c_arr = c_arr(1:nrows, 1:ncols); + endif + # Parse data array, setup typarr and throw out NaNs to speed up writing; - typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts); - if ~(spsh_opts.formulas_as_text) - # Find formulas (designated by a string starting with "=" and ending in ")") - fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) && strncmp (x(end:end), ")", 1), c_arr); - typearr(fptr) = ctype(4); # FORMULA - endif + typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts); + if ~(spsh_opts.formulas_as_text) + # Find formulas (designated by a string starting with "=" and ending in ")") + fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) && strncmp (x(end:end), ")", 1), c_arr); + typearr(fptr) = ctype(4); # FORMULA + endif # Prepare spreadsheet for writing (size, etc.). If needed create new sheet - if (newsh) - if (ods.changed > 2) - # New spreadsheet, use default first sheet - sh = sheets.get (0); - else - # Create a new sheet using DOM API. This part works OK. - sh = sheets.get (nr_of_sheets - 1).newTable (spsh, nrows, ncols); - endif - changed = 1; - if (isnumeric (wsh)) - # Give sheet a name - str = sprintf ("Sheet%d", wsh); - sh.setTableName (str); - wsh = str; - else - # Assign name to sheet and change wsh into numeric pointer - sh.setTableName (wsh); - endif - printf ("Sheet %s added to spreadsheet.\n", wsh); - - else - # Add "physical" rows & columns. Spreadsheet max. capacity checks have been done above - # Add spreadsheet data columns if needed. Compute nr of extra columns & rows. - curr_ncols = sh.getColumnCount (); - ii = max (0, lcol + ncols - curr_ncols); - if (ii == 1) - nwcols = sh.appendColumn (); - else - nwcols = sh.appendColumns (ii); - endif + if (newsh) + if (ods.changed > 2) + # New spreadsheet, use default first sheet + sh = sheets.get (0); + else + # Create a new sheet using DOM API. This part works OK. + sh = sheets.get (nr_of_sheets - 1).newTable (spsh, nrows, ncols); + endif + changed = 1; + if (isnumeric (wsh)) + # Give sheet a name + str = sprintf ("Sheet%d", wsh); + sh.setTableName (str); + wsh = str; + else + # Assign name to sheet and change wsh into numeric pointer + sh.setTableName (wsh); + endif + printf ("Sheet %s added to spreadsheet.\n", wsh); + + else + # Add "physical" rows & columns. Spreadsheet max. capacity checks have been done above + # Add spreadsheet data columns if needed. Compute nr of extra columns & rows. + curr_ncols = sh.getColumnCount (); + ii = max (0, lcol + ncols - curr_ncols); + if (ii == 1) + nwcols = sh.appendColumn (); + else + nwcols = sh.appendColumns (ii); + endif - # Add spreadsheet rows if needed - curr_nrows = sh.getRowCount (); - ii = max (0, trow + nrows - curr_nrows); - if (ii == 1) - nwrows = sh.appendRow (); - else - nwrows = sh.appendRows (ii); - endif - endif + # Add spreadsheet rows if needed + curr_nrows = sh.getRowCount (); + ii = max (0, trow + nrows - curr_nrows); + if (ii == 1) + nwrows = sh.appendRow (); + else + nwrows = sh.appendRows (ii); + endif + endif - # Transfer array data to sheet - for ii=1:nrows - for jj=1:ncols - ocell = sh.getCellByPosition (jj+lcol-1, ii+trow-1); - if ~(isempty (ocell )) # Might be spanned (merged), hidden, .... - # Number, String, Boolean, Date, Time - try - switch typearr (ii, jj) - case {1, 6, 7} # Numeric, Date, Time - ocell.setDoubleValue (c_arr{ii, jj}); - case 2 # Logical / Boolean - # ocell.setBooleanValue (c_arr{ii, jj}); # Doesn't work, bug in odfdom 0.8.6 - # Bug workaround: 1. Remove all cell contents - ocell.removeContent (); - # 2. Switch to TableTableElement API - tocell = ocell.getOdfElement (); - tocell.setAttributeNS ('office', 'office:value-type', 'boolean'); - # 3. Add boolean-value attribute. - # This is only accepted in TTE API with a NS tag (actual bug, IMO) - if (c_arr {ii,jj}) - tocell.setAttributeNS ('office', 'office:boolean-value', 'true'); - else - tocell.setAttributeNS ('office', 'office:boolean-value', 'false'); - endif - case 3 # String - ocell.setStringValue (c_arr{ii, jj}); - case 4 # Formula - ocell.setFormula (c_arr{ii, jj}); - otherwise # 5, empty and catch-all - # The above is all octave has to offer & java can accept... - endswitch - changed = 1; - catch - printf ("\n"); - end_try_catch - endif - endfor - endfor + # Transfer array data to sheet + for ii=1:nrows + for jj=1:ncols + ocell = sh.getCellByPosition (jj+lcol-1, ii+trow-1); + if ~(isempty (ocell )) # Might be spanned (merged), hidden, .... + # Number, String, Boolean, Date, Time + try + switch typearr (ii, jj) + case {1, 6, 7} # Numeric, Date, Time + ocell.setDoubleValue (c_arr{ii, jj}); + case 2 # Logical / Boolean + # ocell.setBooleanValue (c_arr{ii, jj}); # Doesn't work, bug in odfdom 0.8.6 + # Bug workaround: 1. Remove all cell contents + ocell.removeContent (); + # 2. Switch to TableTableElement API + tocell = ocell.getOdfElement (); + tocell.setAttributeNS ('office', 'office:value-type', 'boolean'); + # 3. Add boolean-value attribute. + # This is only accepted in TTE API with a NS tag (actual bug, IMO) + if (c_arr {ii,jj}) + tocell.setAttributeNS ('office', 'office:boolean-value', 'true'); + else + tocell.setAttributeNS ('office', 'office:boolean-value', 'false'); + endif + case 3 # String + ocell.setStringValue (c_arr{ii, jj}); + case 4 # Formula + ocell.setFormula (c_arr{ii, jj}); + otherwise # 5, empty and catch-all + # The above is all octave has to offer & java can accept... + endswitch + changed = 1; + catch + printf ("\n"); + end_try_catch + endif + endfor + endfor - if (changed) - ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) - rstatus = 1; - endif + if (changed) + ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) + rstatus = 1; + endif endfunction #============================================================================= -## Copyright (C) 2009,2010,2011 Philip Nienhuis <pr.nienhuis at users.sf.net> +## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <pr.nienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software @@ -887,124 +886,124 @@ function [ ods, rstatus ] = oct2jod2ods (c_arr, ods, wsh, crange) - rstatus = 0; sh = []; changed = 0; + rstatus = 0; sh = []; changed = 0; - # Get worksheet. Use first one if none given - if (isempty (wsh)) wsh = 1; endif - sh_cnt = ods.workbook.getSheetCount (); - if (isnumeric (wsh)) - if (wsh > 1024) - error ("Sheet number out of range of ODS specification (>1024)"); - elseif (wsh > sh_cnt) - error ("Sheet number (%d) larger than number of sheets in file (%d)\n", wsh, sh_cnt); - else - wsh = wsh - 1; - sh = ods.workbook.getSheet (wsh); - if (isempty (sh)) - # Sheet number wsh didn't exist yet - wsh = sprintf ("Sheet%d", wsh+1); - elseif (ods.changed > 2) - sh.setName ('Sheet1'); - changed = 1; - endif - endif - endif - # wsh is now either a 0-based sheet no. or a string. In latter case: - if (isempty (sh) && ischar (wsh)) - sh = ods.workbook.getSheet (wsh); - if (isempty (sh)) - # Still doesn't exist. Create sheet - if (ods.odfvsn == 3) - if (ods.changed > 2) - # 1st "new" -unnamed- sheet has already been made when creating the spreadsheet - sh = ods.workbook.getSheet (0); - sh.setName (wsh); - changed = 1; - else - # For existing spreadsheets - printf ("Adding sheet '%s'\n", wsh); - sh = ods.workbook.addSheet (sh_cnt, wsh); - changed = 1; - endif - else - error ("jOpenDocument v. 1.2b2 does not support adding sheets - upgrade to v. 1.2b3\n"); - endif - endif - endif + # Get worksheet. Use first one if none given + if (isempty (wsh)) wsh = 1; endif + sh_cnt = ods.workbook.getSheetCount (); + if (isnumeric (wsh)) + if (wsh > 1024) + error ("Sheet number out of range of ODS specification (>1024)"); + elseif (wsh > sh_cnt) + error ("Sheet number (%d) larger than number of sheets in file (%d)\n", wsh, sh_cnt); + else + wsh = wsh - 1; + sh = ods.workbook.getSheet (wsh); + if (isempty (sh)) + # Sheet number wsh didn't exist yet + wsh = sprintf ("Sheet%d", wsh+1); + elseif (ods.changed > 2) + sh.setName ('Sheet1'); + changed = 1; + endif + endif + endif + # wsh is now either a 0-based sheet no. or a string. In latter case: + if (isempty (sh) && ischar (wsh)) + sh = ods.workbook.getSheet (wsh); + if (isempty (sh)) + # Still doesn't exist. Create sheet + if (ods.odfvsn == 3) + if (ods.changed > 2) + # 1st "new" -unnamed- sheet has already been made when creating the spreadsheet + sh = ods.workbook.getSheet (0); + sh.setName (wsh); + changed = 1; + else + # For existing spreadsheets + printf ("Adding sheet '%s'\n", wsh); + sh = ods.workbook.addSheet (sh_cnt, wsh); + changed = 1; + endif + else + error ("jOpenDocument v. 1.2b2 does not support adding sheets - upgrade to v. 1.2b3\n"); + endif + endif + endif - [nr, nc] = size (c_arr); - if (isempty (crange)) - trow = 0; - lcol = 0; - nrows = nr; - ncols = nc; - elseif (isempty (strfind (deblank (crange), ':'))) - [dummy1, dummy2, dummy3, trow, lcol] = parse_sp_range (crange); - nrows = nr; - ncols = nc; - # Row/col = 0 based in jOpenDocument - trow = trow - 1; lcol = lcol - 1; - else - [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); - # Row/col = 0 based in jOpenDocument - trow = trow - 1; lcol = lcol - 1; - endif + [nr, nc] = size (c_arr); + if (isempty (crange)) + trow = 0; + lcol = 0; + nrows = nr; + ncols = nc; + elseif (isempty (strfind (deblank (crange), ':'))) + [dummy1, dummy2, dummy3, trow, lcol] = parse_sp_range (crange); + nrows = nr; + ncols = nc; + # Row/col = 0 based in jOpenDocument + trow = trow - 1; lcol = lcol - 1; + else + [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); + # Row/col = 0 based in jOpenDocument + trow = trow - 1; lcol = lcol - 1; + endif - if (trow > 65535 || lcol > 1023) - error ("Topleft cell beyond spreadsheet limits (AMJ65536)."); - endif - # Check spreadsheet capacity beyond requested topleft cell - nrows = min (nrows, 65536 - trow); # Remember, lcol & trow are zero-based - ncols = min (ncols, 1024 - lcol); - # Check array size and requested range - nrows = min (nrows, nr); - ncols = min (ncols, nc); - if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); endif + if (trow > 65535 || lcol > 1023) + error ("Topleft cell beyond spreadsheet limits (AMJ65536)."); + endif + # Check spreadsheet capacity beyond requested topleft cell + nrows = min (nrows, 65536 - trow); # Remember, lcol & trow are zero-based + ncols = min (ncols, 1024 - lcol); + # Check array size and requested range + nrows = min (nrows, nr); + ncols = min (ncols, nc); + if (nrows < nr || ncols < nc) warning ("Array truncated to fit in range"); endif - if (isnumeric (c_arr)) c_arr = num2cell (c_arr); endif + if (isnumeric (c_arr)) c_arr = num2cell (c_arr); endif - # Ensure sheet capacity is large enough to contain new data - try # try-catch needed to work around bug in jOpenDocument v 1.2b3 and earlier - sh.ensureColumnCount (lcol + ncols); # Remember, lcol & trow are zero-based - catch # catch is needed for new empty sheets (first ensureColCnt() hits null ptr) - sh.ensureColumnCount (lcol + ncols); - # Kludge needed because upper row is defective (NPE jOpenDocument bug). ?Fixed in 1.2b4? - if (trow == 0) - # Shift rows one down to avoid defective upper row - ++trow; - printf ("Info: empy upper row above data added to avoid JOD bug.\n"); - endif - end_try_catch - sh.ensureRowCount (trow + nrows); + # Ensure sheet capacity is large enough to contain new data + try # try-catch needed to work around bug in jOpenDocument v 1.2b3 and earlier + sh.ensureColumnCount (lcol + ncols); # Remember, lcol & trow are zero-based + catch # catch is needed for new empty sheets (first ensureColCnt() hits null ptr) + sh.ensureColumnCount (lcol + ncols); + # Kludge needed because upper row is defective (NPE jOpenDocument bug). ?Fixed in 1.2b4? + if (trow == 0) + # Shift rows one down to avoid defective upper row + ++trow; + printf ("Info: empy upper row above data added to avoid JOD bug.\n"); + endif + end_try_catch + sh.ensureRowCount (trow + nrows); - # Write data to worksheet - for ii = 1 : nrows - for jj = 1 : ncols - val = c_arr {ii, jj}; - if ((isnumeric (val) && ~isnan (val)) || ischar (val) || islogical (val)) + # Write data to worksheet + for ii = 1 : nrows + for jj = 1 : ncols + val = c_arr {ii, jj}; + if ((isnumeric (val) && ~isnan (val)) || ischar (val) || islogical (val)) # FIXME: jOpenDocument doesn't really support writing booleans (doesn't set OffValAttr) if (islogical (val)); val = double (val); endif - try - sh.getCellAt (jj + lcol - 1, ii + trow - 1).clearValue(); - jcell = sh.getCellAt (jj + lcol - 1, ii + trow - 1).setValue (val); - changed = 1; - catch - # No panic, probably a merged cell - # printf (sprintf ("Cell skipped at (%d, %d)\n", ii+lcol-1, jj+trow-1)); - end_try_catch - endif - endfor - endfor + try + sh.getCellAt (jj + lcol - 1, ii + trow - 1).clearValue(); + jcell = sh.getCellAt (jj + lcol - 1, ii + trow - 1).setValue (val); + changed = 1; + catch + # No panic, probably a merged cell + # printf (sprintf ("Cell skipped at (%d, %d)\n", ii+lcol-1, jj+trow-1)); + end_try_catch + endif + endfor + endfor - if (changed) - ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) - rstatus = 1; - endif + if (changed) + ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) + rstatus = 1; + endif endfunction -## Copyright (C) 2011 Philip Nienhuis <prnienhuis@users.sf.net> +## Copyright (C) 2011,2012 Philip Nienhuis <prnienhuis@users.sf.net> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software @@ -1101,7 +1100,7 @@ # wsh is a sheet name. See if it exists already if (isempty (strmatch (wsh, sh_names))) # Not found. New sheet to be added - newsh = 1; + newsh = 1; endif endif if (newsh) @@ -1122,7 +1121,7 @@ warning ("Array truncated to fit in range"); c_arr = c_arr(1:nrows, 1:ncols); endif - + # Parse data array, setup typarr and throw out NaNs to speed up writing; typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts, 0); if ~(spsh_opts.formulas_as_text) @@ -1137,14 +1136,14 @@ try XCell = sh.getCellByPosition (lcol+jj-1, trow+ii-1); switch typearr(ii, jj) - case 1 # Float + case 1 # Float XCell.setValue (c_arr{ii, jj}); - case 2 # Logical. Convert to float + case 2 # Logical. Convert to float XCell.setValue (double (c_arr{ii, jj})); - case 3 # String + case 3 # String unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.text.XText'); XCell.queryInterface (unotmp).setString (c_arr{ii, jj}); - case 4 # Formula + case 4 # Formula if (spsh_opts.formulas_as_text) unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.text.XText'); XCell.queryInterface (unotmp).setString (c_arr{ii, jj}); @@ -1154,15 +1153,15 @@ otherwise # Empty cell endswitch - changed = 1; + changed = 1; catch printf ("Error writing cell %s (typearr() = %d)\n", calccelladdress(trow+ii, lcol+jj), typearr(ii, jj)); - end_try_catch + end_try_catch endfor endfor - if (changed) - ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) + if (changed) + ods.changed = max (min (ods.changed, 2), changed); # Preserve 2 (new file), 1 (existing) rstatus = 1; endif
--- a/main/io/inst/ods2oct.m Fri Jun 08 14:11:42 2012 +0000 +++ b/main/io/inst/ods2oct.m Fri Jun 08 15:28:27 2012 +0000 @@ -121,91 +121,93 @@ ## 2012-01-26 Fixed "seealso" help string ## 2012-02-25 Added 0.8.7 to supported odfdom versions in L.155 ## 2012-02-26 Updated texinfo header help text +## 2012-06-08 Support for odfdom-incubator 0.8.8 +## '' Replaced tabs by double space ## -## (Latest update of subfunctions below: 2012-02-25) +## (Latest update of subfunctions below: 2012-06-08) function [ rawarr, ods, rstatus ] = ods2oct (ods, wsh=1, datrange=[], spsh_opts=[]) - # Check if ods struct pointer seems valid - if (~isstruct (ods)), error ("File ptr struct expected for arg @ 1"); endif - test1 = ~isfield (ods, "xtype"); - test1 = test1 || ~isfield (ods, "workbook"); - test1 = test1 || isempty (ods.workbook); - test1 = test1 || isempty (ods.app); - if (test1) - error ("Arg #1 is an invalid ods file struct"); - endif - # Check worksheet ptr - if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 2"); endif - # Check range - if (~(isempty (datrange) || ischar (datrange))), error ("Character string (range) expected for arg # 3"); endif - # Check & setup options struct - if (nargin < 4 || isempty (spsh_opts)) - spsh_opts.formulas_as_text = 0; - spsh_opts.strip_array = 1; - # Other options here - elseif (~isstruct (spsh_opts)) - error ("struct expected for OPTIONS argument (# 4)"); - else - if (~isfield (spsh_opts, 'formulas_as_text')), spsh_opts.formulas_as_text = 0; endif - if (~isfield (spsh_opts, 'strip_array')), spsh_opts.strip_array = 1; endif - % Future options: - endif + # Check if ods struct pointer seems valid + if (~isstruct (ods)), error ("File ptr struct expected for arg @ 1"); endif + test1 = ~isfield (ods, "xtype"); + test1 = test1 || ~isfield (ods, "workbook"); + test1 = test1 || isempty (ods.workbook); + test1 = test1 || isempty (ods.app); + if (test1) + error ("Arg #1 is an invalid ods file struct"); + endif + # Check worksheet ptr + if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 2"); endif + # Check range + if (~(isempty (datrange) || ischar (datrange))), error ("Character string (range) expected for arg # 3"); endif + # Check & setup options struct + if (nargin < 4 || isempty (spsh_opts)) + spsh_opts.formulas_as_text = 0; + spsh_opts.strip_array = 1; + # Other options here + elseif (~isstruct (spsh_opts)) + error ("struct expected for OPTIONS argument (# 4)"); + else + if (~isfield (spsh_opts, 'formulas_as_text')), spsh_opts.formulas_as_text = 0; endif + if (~isfield (spsh_opts, 'strip_array')), spsh_opts.strip_array = 1; endif + % Future options: + endif - # Select the proper interfaces - if (strcmp (ods.xtype, 'OTK')) - # Read ods file tru Java & ODF toolkit - switch ods.odfvsn - case '0.7.5' - [rawarr, ods] = ods2jotk2oct (ods, wsh, datrange, spsh_opts); - case {'0.8.6', '0.8.7'} - [rawarr, ods] = ods3jotk2oct (ods, wsh, datrange, spsh_opts); - otherwise - error ("Unsupported odfdom version or invalid ods file pointer."); - endswitch - elseif (strcmp (ods.xtype, 'JOD')) - # Read ods file tru Java & jOpenDocument. JOD doesn't know about formulas :-( - [rawarr, ods] = ods2jod2oct (ods, wsh, datrange); - elseif (strcmp (ods.xtype, 'UNO')) - # Read ods file tru Java & UNO - [rawarr, ods] = ods2uno2oct (ods, wsh, datrange, spsh_opts); -# elseif - # ---- < Other interfaces here > - else - error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); - endif + # Select the proper interfaces + if (strcmp (ods.xtype, 'OTK')) + # Read ods file tru Java & ODF toolkit + switch ods.odfvsn + case '0.7.5' + [rawarr, ods] = ods2jotk2oct (ods, wsh, datrange, spsh_opts); + case {'0.8.6', '0.8.7', '0.8.8'} + [rawarr, ods] = ods3jotk2oct (ods, wsh, datrange, spsh_opts); + otherwise + error ("Unsupported odfdom version or invalid ods file pointer."); + endswitch + elseif (strcmp (ods.xtype, 'JOD')) + # Read ods file tru Java & jOpenDocument. JOD doesn't know about formulas :-( + [rawarr, ods] = ods2jod2oct (ods, wsh, datrange); + elseif (strcmp (ods.xtype, 'UNO')) + # Read ods file tru Java & UNO + [rawarr, ods] = ods2uno2oct (ods, wsh, datrange, spsh_opts); +# elseif + # ---- < Other interfaces here > + else + error (sprintf ("ods2oct: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); + endif rstatus = ~isempty (rawarr); - # Optionally strip empty outer rows and columns & keep track of original data location - if (spsh_opts.strip_array && rstatus) - emptr = cellfun ('isempty', rawarr); - if (all (all (emptr))) - rawarr = {}; - ods.limits= []; - else - nrows = size (rawarr, 1); ncols = size (rawarr, 2); - irowt = 1; - while (all (emptr(irowt, :))), irowt++; endwhile - irowb = nrows; - while (all (emptr(irowb, :))), irowb--; endwhile - icoll = 1; - while (all (emptr(:, icoll))), icoll++; endwhile - icolr = ncols; - while (all (emptr(:, icolr))), icolr--; endwhile + # Optionally strip empty outer rows and columns & keep track of original data location + if (spsh_opts.strip_array && rstatus) + emptr = cellfun ('isempty', rawarr); + if (all (all (emptr))) + rawarr = {}; + ods.limits= []; + else + nrows = size (rawarr, 1); ncols = size (rawarr, 2); + irowt = 1; + while (all (emptr(irowt, :))), irowt++; endwhile + irowb = nrows; + while (all (emptr(irowb, :))), irowb--; endwhile + icoll = 1; + while (all (emptr(:, icoll))), icoll++; endwhile + icolr = ncols; + while (all (emptr(:, icolr))), icolr--; endwhile - # Crop outer rows and columns and update limits - rawarr = rawarr(irowt:irowb, icoll:icolr); - ods.limits = ods.limits + [icoll-1, icolr-ncols; irowt-1, irowb-nrows]; - endif - endif + # Crop outer rows and columns and update limits + rawarr = rawarr(irowt:irowb, icoll:icolr); + ods.limits = ods.limits + [icoll-1, icolr-ncols; irowt-1, irowb-nrows]; + endif + endif endfunction #===================================================================== -## Copyright (C) 2009,2010,2011 Philip Nienhuis <prnienhuis _at- users.sf.net> +## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis _at- users.sf.net> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software @@ -239,187 +241,187 @@ function [ rawarr, ods ] = ods2jotk2oct (ods, wsh, crange, spsh_opts) - # Parts after user gfterry in - # http://www.oooforum.org/forum/viewtopic.phtml?t=69060 - - # Get contents and table stuff from the workbook - odfcont = ods.workbook; # Use a local copy just to be sure. octave - # makes physical copies only when needed (?) - xpath = ods.app.getXPath; - - # AFAICS ODS spreadsheets have the following hierarchy (after Xpath processing): - # <table:table> - table nodes, the actual worksheets; - # <table:table-row> - row nodes, the rows in a worksheet; - # <table:table-cell> - cell nodes, the cells in a row; - # Styles (formatting) are defined in a section "settings" outside the - # contents proper but are referenced in the nodes. - - # Create an instance of type NODESET for use in subsequent statement - NODESET = java_get ('javax.xml.xpath.XPathConstants', 'NODESET'); - # Parse sheets ("tables") from ODS file - sheets = xpath.evaluate ("//table:table", odfcont, NODESET); - nr_of_sheets = sheets.getLength (); + # Parts after user gfterry in + # http://www.oooforum.org/forum/viewtopic.phtml?t=69060 + + # Get contents and table stuff from the workbook + odfcont = ods.workbook; # Use a local copy just to be sure. octave + # makes physical copies only when needed (?) + xpath = ods.app.getXPath; + + # AFAICS ODS spreadsheets have the following hierarchy (after Xpath processing): + # <table:table> - table nodes, the actual worksheets; + # <table:table-row> - row nodes, the rows in a worksheet; + # <table:table-cell> - cell nodes, the cells in a row; + # Styles (formatting) are defined in a section "settings" outside the + # contents proper but are referenced in the nodes. + + # Create an instance of type NODESET for use in subsequent statement + NODESET = java_get ('javax.xml.xpath.XPathConstants', 'NODESET'); + # Parse sheets ("tables") from ODS file + sheets = xpath.evaluate ("//table:table", odfcont, NODESET); + nr_of_sheets = sheets.getLength (); - # Check user input & find sheet pointer (1-based), using ugly hacks - if (~isnumeric (wsh)) - # Search in sheet names, match sheet name to sheet number - ii = 0; - while (++ii <= nr_of_sheets && ischar (wsh)) - # Look in first part of the sheet nodeset - sh_name = sheets.item(ii-1).getTableNameAttribute (); - if (strcmp (sh_name, wsh)) - # Convert local copy of wsh into a number (pointer) - wsh = ii; - endif - endwhile - if (ischar (wsh)) - error (sprintf ("No worksheet '%s' found in file %s", wsh, ods.filename)); - endif - elseif (wsh > nr_of_sheets || wsh < 1) - # We already have a numeric sheet pointer. If it's not in range: - error (sprintf ("Worksheet no. %d out of range (1 - %d)", wsh, nr_of_sheets)); - endif + # Check user input & find sheet pointer (1-based), using ugly hacks + if (~isnumeric (wsh)) + # Search in sheet names, match sheet name to sheet number + ii = 0; + while (++ii <= nr_of_sheets && ischar (wsh)) + # Look in first part of the sheet nodeset + sh_name = sheets.item(ii-1).getTableNameAttribute (); + if (strcmp (sh_name, wsh)) + # Convert local copy of wsh into a number (pointer) + wsh = ii; + endif + endwhile + if (ischar (wsh)) + error (sprintf ("No worksheet '%s' found in file %s", wsh, ods.filename)); + endif + elseif (wsh > nr_of_sheets || wsh < 1) + # We already have a numeric sheet pointer. If it's not in range: + error (sprintf ("Worksheet no. %d out of range (1 - %d)", wsh, nr_of_sheets)); + endif - # Get table-rows in sheet no. wsh. Sheet count = 1-based (!) - str = sprintf ("//table:table[%d]/table:table-row", wsh); - sh = xpath.evaluate (str, odfcont, NODESET); - nr_of_rows = sh.getLength (); + # Get table-rows in sheet no. wsh. Sheet count = 1-based (!) + str = sprintf ("//table:table[%d]/table:table-row", wsh); + sh = xpath.evaluate (str, odfcont, NODESET); + nr_of_rows = sh.getLength (); - # Either parse (given cell range) or prepare (unknown range) help variables - if (isempty (crange)) - [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); - nrows = brow - trow + 1; # Number of rows to be read - ncols = rcol - lcol + 1; # Number of columns to be read - else - [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); - brow = min (trow + nrows - 1, nr_of_rows); - # Check ODS column limits - if (lcol > 1024 || trow > 65536) - error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); - endif - # Truncate range silently if needed - rcol = min (lcol + ncols - 1, 1024); - ncols = min (ncols, 1024 - lcol + 1); - nrows = min (nrows, 65536 - trow + 1); - endif - # Create storage for data content - rawarr = cell (nrows, ncols); + # Either parse (given cell range) or prepare (unknown range) help variables + if (isempty (crange)) + [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); + nrows = brow - trow + 1; # Number of rows to be read + ncols = rcol - lcol + 1; # Number of columns to be read + else + [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); + brow = min (trow + nrows - 1, nr_of_rows); + # Check ODS column limits + if (lcol > 1024 || trow > 65536) + error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); + endif + # Truncate range silently if needed + rcol = min (lcol + ncols - 1, 1024); + ncols = min (ncols, 1024 - lcol + 1); + nrows = min (nrows, 65536 - trow + 1); + endif + # Create storage for data content + rawarr = cell (nrows, ncols); - # Prepare reading sheet row by row - rightmcol = 0; # Used to find actual rightmost column - ii = trow - 1; # Spreadsheet row counter - rowcnt = 0; - # Find uppermost requested *tablerow*. It may be influenced by nr-rows-repeated - if (ii >= 1) - tfillrows = 0; - while (tfillrows < ii) - row = sh.item(tfillrows); - extrarows = row.getTableNumberRowsRepeatedAttribute (); - tfillrows = tfillrows + extrarows; - ++rowcnt; - endwhile - # Desired top row may be in a nr-rows-repeated tablerow.... - if (tfillrows > ii) ii = tfillrows; endif - endif + # Prepare reading sheet row by row + rightmcol = 0; # Used to find actual rightmost column + ii = trow - 1; # Spreadsheet row counter + rowcnt = 0; + # Find uppermost requested *tablerow*. It may be influenced by nr-rows-repeated + if (ii >= 1) + tfillrows = 0; + while (tfillrows < ii) + row = sh.item(tfillrows); + extrarows = row.getTableNumberRowsRepeatedAttribute (); + tfillrows = tfillrows + extrarows; + ++rowcnt; + endwhile + # Desired top row may be in a nr-rows-repeated tablerow.... + if (tfillrows > ii); ii = tfillrows; endif + endif - # Read from worksheet row by row. Row numbers are 0-based - while (ii < brow) - row = sh.item(rowcnt++); - nr_of_cells = min (row.getLength (), rcol); - rightmcol = max (rightmcol, nr_of_cells); # Keep track of max row length - # Read column (cell, "table-cell" in ODS speak) by column - jj = lcol; - while (jj <= rcol) - tcell = row.getCellAt(jj-1); - form = 0; - if (~isempty (tcell)) # If empty it's possibly in columns-repeated/spanned - if (spsh_opts.formulas_as_text) # Get spreadsheet formula rather than value - # Check for formula attribute - tmp = tcell.getTableFormulaAttribute (); - if isempty (tmp) - form = 0; - else - if (strcmp (tolower (tmp(1:3)), 'of:')) - tmp (1:end-3) = tmp(4:end); - endif - rawarr(ii-trow+2, jj-lcol+1) = tmp; - form = 1; - endif - endif - if ~(form || index (char(tcell), 'text:p>Err:') || index (char(tcell), 'text:p>#DIV')) - # Get data from cell - ctype = tcell.getOfficeValueTypeAttribute (); - cvalue = tcell.getOfficeValueAttribute (); - switch deblank (ctype) - case {'float', 'currency', 'percentage'} - rawarr(ii-trow+2, jj-lcol+1) = cvalue; - case 'date' - cvalue = tcell.getOfficeDateValueAttribute (); - # Dates are returned as octave datenums, i.e. 0-0-0000 based - yr = str2num (cvalue(1:4)); - mo = str2num (cvalue(6:7)); - dy = str2num (cvalue(9:10)); - if (index (cvalue, 'T')) - hh = str2num (cvalue(12:13)); - mm = str2num (cvalue(15:16)); - ss = str2num (cvalue(18:19)); - rawarr(ii-trow+2, jj-lcol+1) = datenum (yr, mo, dy, hh, mm, ss); - else - rawarr(ii-trow+2, jj-lcol+1) = datenum (yr, mo, dy); - endif - case 'time' - cvalue = tcell.getOfficeTimeValueAttribute (); - if (index (cvalue, 'PT')) - hh = str2num (cvalue(3:4)); - mm = str2num (cvalue(6:7)); - ss = str2num (cvalue(9:10)); - rawarr(ii-trow+2, jj-lcol+1) = datenum (0, 0, 0, hh, mm, ss); - endif - case 'boolean' - cvalue = tcell.getOfficeBooleanValueAttribute (); - rawarr(ii-trow+2, jj-lcol+1) = cvalue; - case 'string' - cvalue = tcell.getOfficeStringValueAttribute (); - if (isempty (cvalue)) # Happens with e.g., hyperlinks - tmp = char (tcell); - # Hack string value from between <text:p|r> </text:p|r> tags - ist = findstr (tmp, '<text:'); - if (ist) - ist = ist (length (ist)); - ist = ist + 8; - ien = index (tmp(ist:end), '</text') + ist - 2; - tmp (ist:ien); - cvalue = tmp(ist:ien); - endif - endif - rawarr(ii-trow+2, jj-lcol+1)= cvalue; - otherwise - # Nothing - endswitch - endif - endif - ++jj; # Next cell - endwhile + # Read from worksheet row by row. Row numbers are 0-based + while (ii < brow) + row = sh.item(rowcnt++); + nr_of_cells = min (row.getLength (), rcol); + rightmcol = max (rightmcol, nr_of_cells); # Keep track of max row length + # Read column (cell, "table-cell" in ODS speak) by column + jj = lcol; + while (jj <= rcol) + tcell = row.getCellAt(jj-1); + form = 0; + if (~isempty (tcell)) # If empty it's possibly in columns-repeated/spanned + if (spsh_opts.formulas_as_text) # Get spreadsheet formula rather than value + # Check for formula attribute + tmp = tcell.getTableFormulaAttribute (); + if isempty (tmp) + form = 0; + else + if (strcmp (tolower (tmp(1:3)), 'of:')) + tmp (1:end-3) = tmp(4:end); + endif + rawarr(ii-trow+2, jj-lcol+1) = tmp; + form = 1; + endif + endif + if ~(form || index (char(tcell), 'text:p>Err:') || index (char(tcell), 'text:p>#DIV')) + # Get data from cell + ctype = tcell.getOfficeValueTypeAttribute (); + cvalue = tcell.getOfficeValueAttribute (); + switch deblank (ctype) + case {'float', 'currency', 'percentage'} + rawarr(ii-trow+2, jj-lcol+1) = cvalue; + case 'date' + cvalue = tcell.getOfficeDateValueAttribute (); + # Dates are returned as octave datenums, i.e. 0-0-0000 based + yr = str2num (cvalue(1:4)); + mo = str2num (cvalue(6:7)); + dy = str2num (cvalue(9:10)); + if (index (cvalue, 'T')) + hh = str2num (cvalue(12:13)); + mm = str2num (cvalue(15:16)); + ss = str2num (cvalue(18:19)); + rawarr(ii-trow+2, jj-lcol+1) = datenum (yr, mo, dy, hh, mm, ss); + else + rawarr(ii-trow+2, jj-lcol+1) = datenum (yr, mo, dy); + endif + case 'time' + cvalue = tcell.getOfficeTimeValueAttribute (); + if (index (cvalue, 'PT')) + hh = str2num (cvalue(3:4)); + mm = str2num (cvalue(6:7)); + ss = str2num (cvalue(9:10)); + rawarr(ii-trow+2, jj-lcol+1) = datenum (0, 0, 0, hh, mm, ss); + endif + case 'boolean' + cvalue = tcell.getOfficeBooleanValueAttribute (); + rawarr(ii-trow+2, jj-lcol+1) = cvalue; + case 'string' + cvalue = tcell.getOfficeStringValueAttribute (); + if (isempty (cvalue)) # Happens with e.g., hyperlinks + tmp = char (tcell); + # Hack string value from between <text:p|r> </text:p|r> tags + ist = findstr (tmp, '<text:'); + if (ist) + ist = ist (length (ist)); + ist = ist + 8; + ien = index (tmp(ist:end), '</text') + ist - 2; + tmp (ist:ien); + cvalue = tmp(ist:ien); + endif + endif + rawarr(ii-trow+2, jj-lcol+1)= cvalue; + otherwise + # Nothing + endswitch + endif + endif + ++jj; # Next cell + endwhile - # Check for repeated rows (i.e. condensed in one table-row) - extrarows = row.getTableNumberRowsRepeatedAttribute () - 1; - if (extrarows > 0 && (ii + extrarows) < 65535) - # Expand rawarr cf. table-row - nr_of_rows = nr_of_rows + extrarows; - ii = ii + extrarows; - endif - ++ii; - endwhile + # Check for repeated rows (i.e. condensed in one table-row) + extrarows = row.getTableNumberRowsRepeatedAttribute () - 1; + if (extrarows > 0 && (ii + extrarows) < 65535) + # Expand rawarr cf. table-row + nr_of_rows = nr_of_rows + extrarows; + ii = ii + extrarows; + endif + ++ii; + endwhile - # Keep track of data rectangle limits - ods.limits = [lcol, rcol; trow, brow]; + # Keep track of data rectangle limits + ods.limits = [lcol, rcol; trow, brow]; endfunction #=========================================================================== -## Copyright (C) 2010,2011 Philip Nienhuis <prnienhuis@users.sf.net> +## Copyright (C) 2010,2011,2012 Philip Nienhuis <prnienhuis@users.sf.net> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software @@ -447,146 +449,146 @@ function [ rawarr, ods ] = ods3jotk2oct (ods, wsh, crange, spsh_opts) - # Get contents and table stuff from the workbook - odfcont = ods.workbook; # Use a local copy just to be sure. octave - # makes physical copies only when needed (?) - - # Parse sheets ("tables") from ODS file - sheets = ods.app.getTableList(); - nr_of_sheets = sheets.size (); + # Get contents and table stuff from the workbook + odfcont = ods.workbook; # Use a local copy just to be sure. octave + # makes physical copies only when needed (?) + + # Parse sheets ("tables") from ODS file + sheets = ods.app.getTableList(); + nr_of_sheets = sheets.size (); - # Check user input & find sheet pointer (1-based) - if (~isnumeric (wsh)) - try - sh = ods.app.getTableByName (wsh); - sh_err = isempty (sh); - catch - sh_err = 1; - end_try_catch - if (sh_err) - error (sprintf ("Sheet %s not found in file %s\n", wsh, ods.filename)); - endif - elseif (wsh > nr_of_sheets || wsh < 1) - # We already have a numeric sheet pointer. If it's not in range: - error (sprintf ("Worksheet no. %d out of range (1 - %d)", wsh, nr_of_sheets)); - else - sh = sheets.get (wsh - 1); - endif + # Check user input & find sheet pointer (1-based) + if (~isnumeric (wsh)) + try + sh = ods.app.getTableByName (wsh); + sh_err = isempty (sh); + catch + sh_err = 1; + end_try_catch + if (sh_err) + error (sprintf ("Sheet %s not found in file %s\n", wsh, ods.filename)); + endif + elseif (wsh > nr_of_sheets || wsh < 1) + # We already have a numeric sheet pointer. If it's not in range: + error (sprintf ("Worksheet no. %d out of range (1 - %d)", wsh, nr_of_sheets)); + else + sh = sheets.get (wsh - 1); + endif - # Either parse (given cell range) or prepare (unknown range) help variables - if (isempty (crange)) - if ~isnumeric (wsh) - # Get sheet index - jj = nr_of_sheets; - while jj-- >= 0 - if (strcmp (wsh, sheets.get(jj).getTableName()) == 1) - wsh = jj +1; - jj = -1; - endif - endwhile - endif - [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); - nrows = brow - trow + 1; # Number of rows to be read - ncols = rcol - lcol + 1; # Number of columns to be read - else - [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); - # Check ODS row/column limits - if (lcol > 1024 || trow > 65536) - error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); - endif - # Truncate range silently if needed - rcol = min (lcol + ncols - 1, 1024); - ncols = min (ncols, 1024 - lcol + 1); - nrows = min (nrows, 65536 - trow + 1); - brow = trow + nrows - 1; - endif + # Either parse (given cell range) or prepare (unknown range) help variables + if (isempty (crange)) + if ~isnumeric (wsh) + # Get sheet index + jj = nr_of_sheets; + while jj-- >= 0 + if (strcmp (wsh, sheets.get(jj).getTableName()) == 1) + wsh = jj +1; + jj = -1; + endif + endwhile + endif + [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); + nrows = brow - trow + 1; # Number of rows to be read + ncols = rcol - lcol + 1; # Number of columns to be read + else + [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); + # Check ODS row/column limits + if (lcol > 1024 || trow > 65536) + error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); + endif + # Truncate range silently if needed + rcol = min (lcol + ncols - 1, 1024); + ncols = min (ncols, 1024 - lcol + 1); + nrows = min (nrows, 65536 - trow + 1); + brow = trow + nrows - 1; + endif - # Create storage for data content - rawarr = cell (nrows, ncols); + # Create storage for data content + rawarr = cell (nrows, ncols); - # Read from worksheet row by row. Row numbers are 0-based - for ii=trow:nrows+trow-1 - row = sh.getRowByIndex (ii-1); - for jj=lcol:ncols+lcol-1; - ocell = row.getCellByIndex (jj-1); - if ~isempty (ocell) - otype = deblank (tolower (ocell.getValueType ())); - if (spsh_opts.formulas_as_text) - if ~isempty (ocell.getFormula ()) - otype = 'formula'; - endif - endif -# # Provisions for catching jOpenDocument 1.2b bug where text cells -# # haven't been assigned an <office:value-type='string'> attribute -# if (~isempty (ocell)) -# if (findstr ('<text:', char (ocell.getOdfElement ()))), otype = 'string'; endif -# endif - # At last, read the data - switch otype - case {'float', 'currency', 'percentage'} - rawarr(ii-trow+1, jj-lcol+1) = ocell.getDoubleValue (); - case 'date' - # Dive into TableTable API - tvalue = ocell.getOdfElement ().getOfficeDateValueAttribute (); - # Dates are returned as octave datenums, i.e. 0-0-0000 based - yr = str2num (tvalue(1:4)); - mo = str2num (tvalue(6:7)); - dy = str2num (tvalue(9:10)); - if (index (tvalue, 'T')) - hh = str2num (tvalue(12:13)); - mm = str2num (tvalue(15:16)); - ss = str2num (tvalue(18:19)); - rawarr(ii-trow+1, jj-lcol+1) = datenum (yr, mo, dy, hh, mm, ss); - else - rawarr(ii-trow+1, jj-lcol+1) = datenum (yr, mo, dy); - endif - case 'time' - # Dive into TableTable API - tvalue = ocell.getOdfElement ().getOfficeTimeValueAttribute (); - if (index (tvalue, 'PT')) - hh = str2num (tvalue(3:4)); - mm = str2num (tvalue(6:7)); - ss = str2num (tvalue(9:10)); - rawarr(ii-trow+1, jj-lcol+1) = datenum (0, 0, 0, hh, mm, ss); - endif - case 'boolean' - rawarr(ii-trow+1, jj-lcol+1) = ocell.getBooleanValue (); - case 'string' - rawarr(ii-trow+1, jj-lcol+1) = ocell.getStringValue (); -# # Code left in for in case odfdom 0.8.6+ has similar bug -# # as 0.7.5 -# cvalue = tcell.getOfficeStringValueAttribute (); -# if (isempty (cvalue)) # Happens with e.g., hyperlinks -# tmp = char (tcell); -# # Hack string value from between <text:p|r> </text:p|r> tags -# ist = findstr (tmp, '<text:'); -# if (ist) -# ist = ist (length (ist)); -# ist = ist + 8; -# ien = index (tmp(ist:end), '</text') + ist - 2; -# tmp (ist:ien); -# cvalue = tmp(ist:ien); -# endif -# endif -# rawarr(ii-trow+1, jj-lcol+1)= cvalue; - case 'formula' - rawarr(ii-trow+1, jj-lcol+1) = ocell.getFormula (); - otherwise - # Nothing. - endswitch - endif - endfor - endfor + # Read from worksheet row by row. Row numbers are 0-based + for ii=trow:nrows+trow-1 + row = sh.getRowByIndex (ii-1); + for jj=lcol:ncols+lcol-1; + ocell = row.getCellByIndex (jj-1); + if ~isempty (ocell) + otype = deblank (tolower (ocell.getValueType ())); + if (spsh_opts.formulas_as_text) + if ~isempty (ocell.getFormula ()) + otype = 'formula'; + endif + endif +# # Provisions for catching jOpenDocument 1.2b bug where text cells +# # haven't been assigned an <office:value-type='string'> attribute +# if (~isempty (ocell)) +# if (findstr ('<text:', char (ocell.getOdfElement ()))), otype = 'string'; endif +# endif + # At last, read the data + switch otype + case {'float', 'currency', 'percentage'} + rawarr(ii-trow+1, jj-lcol+1) = ocell.getDoubleValue (); + case 'date' + # Dive into TableTable API + tvalue = ocell.getOdfElement ().getOfficeDateValueAttribute (); + # Dates are returned as octave datenums, i.e. 0-0-0000 based + yr = str2num (tvalue(1:4)); + mo = str2num (tvalue(6:7)); + dy = str2num (tvalue(9:10)); + if (index (tvalue, 'T')) + hh = str2num (tvalue(12:13)); + mm = str2num (tvalue(15:16)); + ss = str2num (tvalue(18:19)); + rawarr(ii-trow+1, jj-lcol+1) = datenum (yr, mo, dy, hh, mm, ss); + else + rawarr(ii-trow+1, jj-lcol+1) = datenum (yr, mo, dy); + endif + case 'time' + # Dive into TableTable API + tvalue = ocell.getOdfElement ().getOfficeTimeValueAttribute (); + if (index (tvalue, 'PT')) + hh = str2num (tvalue(3:4)); + mm = str2num (tvalue(6:7)); + ss = str2num (tvalue(9:10)); + rawarr(ii-trow+1, jj-lcol+1) = datenum (0, 0, 0, hh, mm, ss); + endif + case 'boolean' + rawarr(ii-trow+1, jj-lcol+1) = ocell.getBooleanValue (); + case 'string' + rawarr(ii-trow+1, jj-lcol+1) = ocell.getStringValue (); +# # Code left in for in case odfdom 0.8.6+ has similar bug +# # as 0.7.5 +# cvalue = tcell.getOfficeStringValueAttribute (); +# if (isempty (cvalue)) # Happens with e.g., hyperlinks +# tmp = char (tcell); +# # Hack string value from between <text:p|r> </text:p|r> tags +# ist = findstr (tmp, '<text:'); +# if (ist) +# ist = ist (length (ist)); +# ist = ist + 8; +# ien = index (tmp(ist:end), '</text') + ist - 2; +# tmp (ist:ien); +# cvalue = tmp(ist:ien); +# endif +# endif +# rawarr(ii-trow+1, jj-lcol+1)= cvalue; + case 'formula' + rawarr(ii-trow+1, jj-lcol+1) = ocell.getFormula (); + otherwise + # Nothing. + endswitch + endif + endfor + endfor - # Keep track of data rectangle limits - ods.limits = [lcol, rcol; trow, brow]; + # Keep track of data rectangle limits + ods.limits = [lcol, rcol; trow, brow]; endfunction #=========================================================================== -## Copyright (C) 2009,2010,2011 Philip Nienhuis <pr.nienhuis at users.sf.net> +## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <pr.nienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software @@ -622,156 +624,156 @@ function [ rawarr, ods] = ods2jod2oct (ods, wsh, crange) - persistent months; - months = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; + persistent months; + months = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; - # Check jOpenDocument version - sh = ods.workbook.getSheet (0); - cl = sh.getCellAt (0, 0); - if (ods.odfvsn == 3) - # 1.2b3+ has public getValueType () - persistent ctype; - if (isempty (ctype)) - BOOLEAN = char (java_get ('org.jopendocument.dom.ODValueType', 'BOOLEAN')); - CURRENCY = char (java_get ('org.jopendocument.dom.ODValueType', 'CURRENCY')); - DATE = char (java_get ('org.jopendocument.dom.ODValueType', 'DATE')); - FLOAT = char (java_get ('org.jopendocument.dom.ODValueType', 'FLOAT')); - PERCENTAGE = char (java_get ('org.jopendocument.dom.ODValueType', 'PERCENTAGE')); - STRING = char (java_get ('org.jopendocument.dom.ODValueType', 'STRING')); - TIME = char (java_get ('org.jopendocument.dom.ODValueType', 'TIME')); - endif -# else -# # 1.2b2 has not -# ver = 2; - endif + # Check jOpenDocument version + sh = ods.workbook.getSheet (0); + cl = sh.getCellAt (0, 0); + if (ods.odfvsn == 3) + # 1.2b3+ has public getValueType () + persistent ctype; + if (isempty (ctype)) + BOOLEAN = char (java_get ('org.jopendocument.dom.ODValueType', 'BOOLEAN')); + CURRENCY = char (java_get ('org.jopendocument.dom.ODValueType', 'CURRENCY')); + DATE = char (java_get ('org.jopendocument.dom.ODValueType', 'DATE')); + FLOAT = char (java_get ('org.jopendocument.dom.ODValueType', 'FLOAT')); + PERCENTAGE = char (java_get ('org.jopendocument.dom.ODValueType', 'PERCENTAGE')); + STRING = char (java_get ('org.jopendocument.dom.ODValueType', 'STRING')); + TIME = char (java_get ('org.jopendocument.dom.ODValueType', 'TIME')); + endif +# else +# # 1.2b2 has not +# ver = 2; + endif - if (isnumeric (wsh)) wsh = wsh - 1; endif # Sheet INDEX starts at 0 - # Check if sheet exists. If wsh = numeric, nonexistent sheets throw errors. - try - sh = ods.workbook.getSheet (wsh); - catch - error ("Illegal sheet number (%d) requested for file %s\n", wsh+1, ods.filename); - end_try_catch - # If wsh = string, nonexistent sheets yield empty results - if (isempty (sh)) - error ("No sheet called '%s' present in file %s\n", wsh, ods.filename); - endif + if (isnumeric (wsh)) wsh = wsh - 1; endif # Sheet INDEX starts at 0 + # Check if sheet exists. If wsh = numeric, nonexistent sheets throw errors. + try + sh = ods.workbook.getSheet (wsh); + catch + error ("Illegal sheet number (%d) requested for file %s\n", wsh+1, ods.filename); + end_try_catch + # If wsh = string, nonexistent sheets yield empty results + if (isempty (sh)) + error ("No sheet called '%s' present in file %s\n", wsh, ods.filename); + endif - # Either parse (given cell range) or prepare (unknown range) help variables - if (isempty (crange)) - if (ods.odfvsn < 3) - error ("No empty read range allowed in jOpenDocument version 1.2b2") - else - if (isnumeric (wsh)) wsh = wsh + 1; endif - [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); - nrows = brow - trow + 1; # Number of rows to be read - ncols = rcol - lcol + 1; # Number of columns to be read - endif - else - [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); - # Check ODS column limits - if (lcol > 1024 || trow > 65536) - error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); - endif - # Truncate range silently if needed - rcol = min (lcol + ncols - 1, 1024); - ncols = min (ncols, 1024 - lcol + 1); - nrows = min (nrows, 65536 - trow + 1); - brow= trow + nrows - 1; - endif - # Create storage for data content - rawarr = cell (nrows, ncols); + # Either parse (given cell range) or prepare (unknown range) help variables + if (isempty (crange)) + if (ods.odfvsn < 3) + error ("No empty read range allowed in jOpenDocument version 1.2b2") + else + if (isnumeric (wsh)) wsh = wsh + 1; endif + [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); + nrows = brow - trow + 1; # Number of rows to be read + ncols = rcol - lcol + 1; # Number of columns to be read + endif + else + [dummy, nrows, ncols, trow, lcol] = parse_sp_range (crange); + # Check ODS column limits + if (lcol > 1024 || trow > 65536) + error ("ods2oct: invalid range; max 1024 columns & 65536 rows."); + endif + # Truncate range silently if needed + rcol = min (lcol + ncols - 1, 1024); + ncols = min (ncols, 1024 - lcol + 1); + nrows = min (nrows, 65536 - trow + 1); + brow= trow + nrows - 1; + endif + # Create storage for data content + rawarr = cell (nrows, ncols); - if (ods.odfvsn >= 3) - # Version 1.2b3+ - for ii=1:nrows - for jj = 1:ncols - try - scell = sh.getCellAt (lcol+jj-2, trow+ii-2); - sctype = char (scell.getValueType ()); - switch sctype - case { FLOAT, CURRENCY, PERCENTAGE } - rawarr{ii, jj} = scell.getValue ().doubleValue (); - case BOOLEAN - rawarr {ii, jj} = scell.getValue () == 1; - case STRING - rawarr{ii, jj} = scell.getValue(); - case DATE - tmp = strsplit (char (scell.getValue ()), ' '); - yy = str2num (tmp{6}); - mo = find (ismember (months, toupper (tmp{2})) == 1); - dd = str2num (tmp{3}); - hh = str2num (tmp{4}(1:2)); - mi = str2num (tmp{4}(4:5)); - ss = str2num (tmp{4}(7:8)); - rawarr{ii, jj} = datenum (yy, mo, dd, hh, mi, ss); - case TIME - tmp = strsplit (char (scell.getValue ().getTime ()), ' '); - hh = str2num (tmp{4}(1:2)) / 24.0; - mi = str2num (tmp{4}(4:5)) / 1440.0; - ss = str2num (tmp{4}(7:8)) / 86600.0; - rawarr {ii, jj} = hh + mi + ss; - otherwise + if (ods.odfvsn >= 3) + # Version 1.2b3+ + for ii=1:nrows + for jj = 1:ncols + try + scell = sh.getCellAt (lcol+jj-2, trow+ii-2); + sctype = char (scell.getValueType ()); + switch sctype + case { FLOAT, CURRENCY, PERCENTAGE } + rawarr{ii, jj} = scell.getValue ().doubleValue (); + case BOOLEAN + rawarr {ii, jj} = scell.getValue () == 1; + case STRING + rawarr{ii, jj} = scell.getValue(); + case DATE + tmp = strsplit (char (scell.getValue ()), ' '); + yy = str2num (tmp{6}); + mo = find (ismember (months, toupper (tmp{2})) == 1); + dd = str2num (tmp{3}); + hh = str2num (tmp{4}(1:2)); + mi = str2num (tmp{4}(4:5)); + ss = str2num (tmp{4}(7:8)); + rawarr{ii, jj} = datenum (yy, mo, dd, hh, mi, ss); + case TIME + tmp = strsplit (char (scell.getValue ().getTime ()), ' '); + hh = str2num (tmp{4}(1:2)) / 24.0; + mi = str2num (tmp{4}(4:5)) / 1440.0; + ss = str2num (tmp{4}(7:8)) / 86600.0; + rawarr {ii, jj} = hh + mi + ss; + otherwise # Workaround for sheets written by jOpenDocument (no value-type attrb): if (~isempty (scell.getValue) ) # FIXME Assume cell contains string if there's a text attr. But it could be BOOLEAN too... if (findstr ('<text:', char (scell))), sctype = STRING; endif rawarr{ii, jj} = scell.getValue(); endif - # Nothing - endswitch - catch - # Probably a merged cell, just skip - # printf ("Error in row %d, col %d (addr. %s)\n", ii, jj, calccelladdress (lcol+jj-2, trow+ii-2)); - end_try_catch - endfor - endfor - else # ods,odfvsn == 3 - # 1.2b2 - for ii=1:nrows - for jj = 1:ncols - celladdress = calccelladdress (trow+ii-1, lcol+jj-1); - try - val = sh.getCellAt (celladdress).getValue (); - catch - # No panic, probably a merged cell - val = {}; - end_try_catch - if (~isempty (val)) - if (ischar (val)) - # Text string - rawarr(ii, jj) = val; - elseif (isnumeric (val)) - # Boolean - if (val) rawarr(ii, jj) = true; else; rawarr(ii, jj) = false; endif - else - try - val = sh.getCellAt (celladdress).getValue ().doubleValue (); - rawarr(ii, jj) = val; - catch - val = char (val); - if (isempty (val)) - # Probably empty Cell - else - # Maybe date / time value. Dirty hack to get values: - mo = strmatch (toupper (val(5:7)), months); - dd = str2num (val(9:10)); - yy = str2num (val(25:end)); - hh = str2num (val(12:13)); - mm = str2num (val(15:16)); - ss = str2num (val(18:19)); - rawarr(ii, jj) = datenum (yy, mo, dd, hh, mm,ss); - endif - end_try_catch - endif - endif - endfor - endfor + # Nothing + endswitch + catch + # Probably a merged cell, just skip + # printf ("Error in row %d, col %d (addr. %s)\n", ii, jj, calccelladdress (lcol+jj-2, trow+ii-2)); + end_try_catch + endfor + endfor + else # ods.odfvsn == 3 + # 1.2b2 + for ii=1:nrows + for jj = 1:ncols + celladdress = calccelladdress (trow+ii-1, lcol+jj-1); + try + val = sh.getCellAt (celladdress).getValue (); + catch + # No panic, probably a merged cell + val = {}; + end_try_catch + if (~isempty (val)) + if (ischar (val)) + # Text string + rawarr(ii, jj) = val; + elseif (isnumeric (val)) + # Boolean + if (val) rawarr(ii, jj) = true; else; rawarr(ii, jj) = false; endif + else + try + val = sh.getCellAt (celladdress).getValue ().doubleValue (); + rawarr(ii, jj) = val; + catch + val = char (val); + if (isempty (val)) + # Probably empty Cell + else + # Maybe date / time value. Dirty hack to get values: + mo = strmatch (toupper (val(5:7)), months); + dd = str2num (val(9:10)); + yy = str2num (val(25:end)); + hh = str2num (val(12:13)); + mm = str2num (val(15:16)); + ss = str2num (val(18:19)); + rawarr(ii, jj) = datenum (yy, mo, dd, hh, mm,ss); + endif + end_try_catch + endif + endif + endfor + endfor - endif + endif - # Keep track of data rectangle limits - ods.limits = [lcol, rcol; trow, brow]; + # Keep track of data rectangle limits + ods.limits = [lcol, rcol; trow, brow]; endfunction @@ -813,7 +815,7 @@ # Check sheet pointer if (isnumeric (wsh)) - if (wsh < 1 || wsh > numel (sh_names)) + if (wsh < 1 || wsh > numel (sh_names)) error ("Sheet index %d out of range 1-%d", wsh, numel (sh_names)); endif else @@ -822,7 +824,7 @@ wsh = ii; endif unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.sheet.XSpreadsheet'); - sh = sheets.getByName(sh_names{wsh}).getObject.queryInterface (unotmp); + sh = sheets.getByName (sh_names{wsh}).getObject.queryInterface (unotmp); unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.sheet.XCellRangesQuery'); xRQ = sh.queryInterface (unotmp); @@ -848,8 +850,8 @@ # out-of-range errors [ trow, brow, lcol, rcol ] = getusedrange (ods, wsh); if (isempty (datrange)) - nrows = brow - trow + 1; # Number of rows to be read - ncols = rcol - lcol + 1; # Number of columns to be read + nrows = brow - trow + 1; # Number of rows to be read + ncols = rcol - lcol + 1; # Number of columns to be read else [dummy, nrows, ncols, srow, scol] = parse_sp_range (datrange); # Truncate range silently if needed @@ -857,8 +859,8 @@ rcol = min (scol + ncols - 1, rcol); trow = max (trow, srow); lcol = max (lcol, scol); - nrows = min (brow - trow + 1, nrows); # Number of rows to be read - ncols = min (rcol - lcol + 1, ncols); # Number of columns to be read + nrows = min (brow - trow + 1, nrows); # Number of rows to be read + ncols = min (rcol - lcol + 1, ncols); # Number of columns to be read endif # Create storage for data at Octave side rawarr = cell (nrows, ncols); @@ -869,12 +871,12 @@ XCell = sh.getCellByPosition (jj, ii); cType = XCell.getType().getValue (); switch cType - case 1 # Value + case 1 # Value rawarr{ii-trow+2, jj-lcol+2} = XCell.getValue (); - case 2 # String + case 2 # String unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.text.XText'); rawarr{ii-trow+2, jj-lcol+2} = XCell.queryInterface (unotmp).getString (); - case 3 # Formula + case 3 # Formula if (spsh_opts.formulas_as_text) rawarr{ii-trow+2, jj-lcol+2} = XCell.getFormula (); else
--- a/main/io/inst/odsclose.m Fri Jun 08 14:11:42 2012 +0000 +++ b/main/io/inst/odsclose.m Fri Jun 08 15:28:27 2012 +0000 @@ -58,128 +58,129 @@ ## 2010-10-17 Fixed typo in error message about unknown interface ## 2010-10-27 Improved file change tracking tru ods.changed ## 2010-11-12 Keep ods file pointer when write errors occur. -## " Added optional filename arg to change filename to be written to +## '' Added optional filename arg to change filename to be written to ## 2011-05-06 Experimental UNO support ## 2011-05-07 In case of UNO, soffice now properly closed using xDesk ## 2011-05-18 Saving newly created files using UNO supported now ## 2011-09-08 FIXME - closing OOo kills all other OOo invocations (known Java-UNO issue) ## 2012-01-26 Fixed "seealso" help string +## 2012-06-08 tabs replaced by double space function [ ods ] = odsclose (ods, varargs) - # If needed warn that dangling spreadsheet pointers may be left - if (nargout < 1) warning ("return argument missing - ods invocation not reset."); endif + # If needed warn that dangling spreadsheet pointers may be left + if (nargout < 1) warning ("return argument missing - ods invocation not reset."); endif - force = 0; + force = 0; - if (nargin > 1) - for ii=2:nargin - if (strcmp (lower (varargin{ii}), "force")) - # Close .ods anyway even if write errors occur - force = 1; - elseif (~isempty (strfind (tolower (varargin{ii}), '.ods')) || ... - ~isempty (strfind (tolower (varargin{ii}), '.sxc'))) - # Apparently a file name - if (ods.changed == 0 || ods.changed > 2) - warning ("File %s wasn't changed, new filename ignored.", ods.filename); - else - if (strfind (tolower (filename), '.sxc') || strfind (tolower (filename), '.ods')) - ods.filename = filename; - else - error ('No .sxc or .ods filename extension specified'); - endif - endif - endif - endfor - endif + if (nargin > 1) + for ii=2:nargin + if (strcmp (lower (varargin{ii}), "force")) + # Close .ods anyway even if write errors occur + force = 1; + elseif (~isempty (strfind (tolower (varargin{ii}), '.ods')) || ... + ~isempty (strfind (tolower (varargin{ii}), '.sxc'))) + # Apparently a file name + if (ods.changed == 0 || ods.changed > 2) + warning ("File %s wasn't changed, new filename ignored.", ods.filename); + else + if (strfind (tolower (filename), '.sxc') || strfind (tolower (filename), '.ods')) + ods.filename = filename; + else + error ('No .sxc or .ods filename extension specified'); + endif + endif + endif + endfor + endif - if (strcmp (ods.xtype, 'OTK')) - # Java & ODF toolkit - try - if (ods.changed && ods.changed < 3) - ods.app.save (ods.filename); - ods.changed = 0; - endif - ods.app.close (); - catch - if (force) - ods.app.close (); - endif - end_try_catch + if (strcmp (ods.xtype, 'OTK')) + # Java & ODF toolkit + try + if (ods.changed && ods.changed < 3) + ods.app.save (ods.filename); + ods.changed = 0; + endif + ods.app.close (); + catch + if (force) + ods.app.close (); + endif + end_try_catch - elseif (strcmp (ods.xtype, 'JOD')) - # Java & jOpenDocument - try - if (ods.changed && ods.changed < 3) - ofile = java_new ('java.io.File', ods.filename); - ods.workbook.saveAs (ofile); - ods.changed = 0; - endif - catch - end_try_catch + elseif (strcmp (ods.xtype, 'JOD')) + # Java & jOpenDocument + try + if (ods.changed && ods.changed < 3) + ofile = java_new ('java.io.File', ods.filename); + ods.workbook.saveAs (ofile); + ods.changed = 0; + endif + catch + end_try_catch - elseif (strcmp (ods.xtype, 'UNO')) - # Java & UNO bridge - try - if (ods.changed && ods.changed < 3) - # Workaround: - unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XModel'); - xModel = ods.workbook.queryInterface (unotmp); - unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.util.XModifiable'); - xModified = xModel.queryInterface (unotmp); - if (xModified.isModified ()) - unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XStorable'); # isReadonly() ? - xStore = ods.app.xComp.queryInterface (unotmp); - if (ods.changed == 2) - # Some trickery as Octave Java cannot create non-numeric arrays - lProps = javaArray ('com.sun.star.beans.PropertyValue', 1); - lProp = java_new ('com.sun.star.beans.PropertyValue', "Overwrite", 0, true, []); - lProps(1) = lProp; - # OK, save file to disk - xStore.storeAsURL (ods.filename, lProps); - else - xStore.store (); - endif - endif - endif - ods.changed = -1; # Needed for check op properly shutting down OOo - # Workaround: - unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XModel'); - xModel = ods.app.xComp.queryInterface (unotmp); - unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.util.XCloseable'); - xClosbl = xModel.queryInterface (unotmp); - xClosbl.close (true); - unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XDesktop'); - xDesk = ods.app.aLoader.queryInterface (unotmp); - xDesk.terminate(); - ods.changed = 0; - catch - if (force) - # Force closing OOo - unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XDesktop'); - xDesk = ods.app.aLoader.queryInterface (unotmp); - xDesk.terminate(); - else - warning ("Error dbclosing ods pointer (UNO)"); - endif - return - end_try_catch + elseif (strcmp (ods.xtype, 'UNO')) + # Java & UNO bridge + try + if (ods.changed && ods.changed < 3) + # Workaround: + unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XModel'); + xModel = ods.workbook.queryInterface (unotmp); + unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.util.XModifiable'); + xModified = xModel.queryInterface (unotmp); + if (xModified.isModified ()) + unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XStorable'); # isReadonly() ? + xStore = ods.app.xComp.queryInterface (unotmp); + if (ods.changed == 2) + # Some trickery as Octave Java cannot create non-numeric arrays + lProps = javaArray ('com.sun.star.beans.PropertyValue', 1); + lProp = java_new ('com.sun.star.beans.PropertyValue', "Overwrite", 0, true, []); + lProps(1) = lProp; + # OK, save file to disk + xStore.storeAsURL (ods.filename, lProps); + else + xStore.store (); + endif + endif + endif + ods.changed = -1; # Needed for check op properly shutting down OOo + # Workaround: + unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XModel'); + xModel = ods.app.xComp.queryInterface (unotmp); + unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.util.XCloseable'); + xClosbl = xModel.queryInterface (unotmp); + xClosbl.close (true); + unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XDesktop'); + xDesk = ods.app.aLoader.queryInterface (unotmp); + xDesk.terminate(); + ods.changed = 0; + catch + if (force) + # Force closing OOo + unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XDesktop'); + xDesk = ods.app.aLoader.queryInterface (unotmp); + xDesk.terminate(); + else + warning ("Error dbclosing ods pointer (UNO)"); + endif + return + end_try_catch -# elseif ---- < Other interfaces here > +# elseif ---- < Other interfaces here > - else - error (sprintf ("ods2close: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); + else + error (sprintf ("ods2close: unknown OpenOffice.org .ods interface - %s.", ods.xtype)); - endif + endif - if (ods.changed && ods.changed < 3) - error ( sprintf ("Could not save file %s - read-only or in use elsewhere?\nFile pointer preserved", ods.filename)); - if (force) - ods = []; - endif - else - # Reset file pointer - ods = []; - endif + if (ods.changed && ods.changed < 3) + error ( sprintf ("Could not save file %s - read-only or in use elsewhere?\nFile pointer preserved", ods.filename)); + if (force) + ods = []; + endif + else + # Reset file pointer + ods = []; + endif endfunction
--- a/main/io/inst/odsfinfo.m Fri Jun 08 14:11:42 2012 +0000 +++ b/main/io/inst/odsfinfo.m Fri Jun 08 15:28:27 2012 +0000 @@ -76,6 +76,7 @@ ## 2012-02-25 Return occupied sheet ranges in output args ## '' Improve echo of sheet names & ranges if interactive ## 2012-03-01 Fix wrong cell refs in UNO section ("(..)" rather than "{..}" +## 2012-06-08 Support for odfdom-0.8.8-incubator function [ filetype, sheetnames ] = odsfinfo (filename, reqintf=[]) @@ -95,7 +96,7 @@ if (strcmp (ods.xtype, 'OTK')) # Get contents and table (= sheet) stuff from the workbook odfcont = ods.workbook; # Local copy just in case - if (strcmp (ods.odfvsn, '0.8.7')) + if (strcmp (ods.odfvsn, '0.8.7') || strfind (ods.odfvsn, "0.8.8")) xpath = ods.workbook.getXPath; else xpath = ods.app.getXPath;
--- a/main/io/inst/odsopen.m Fri Jun 08 14:11:42 2012 +0000 +++ b/main/io/inst/odsopen.m Fri Jun 08 15:28:27 2012 +0000 @@ -94,7 +94,7 @@ ## 2012-06-06 Made interface checking routine less verbose when same requested interface ## was used consecutively ## -## Latest change on subfunctions below: 2012-06-06 +## Latest change on subfunctions below: 2012-06-08 function [ ods ] = odsopen (filename, rw=0, reqinterface=[]) @@ -335,7 +335,7 @@ endfunction -## Copyright (C) 2009,2010,2011 Philip Nienhuis <prnienhuis at users.sf.net> +## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by @@ -399,6 +399,7 @@ ## 2011-09-18 Added temporary warning about UNO interface ## 2012-03-22 Improved Java checks (analogous to xlsopen) ## 2012-06-06 Again improved & simplified Java-based interface checking support +## 2012-06-08 Support for odfdom-0.8.8 (-incubator) function [odsinterfaces] = getodsinterfaces (odsinterfaces) @@ -472,8 +473,11 @@ catch odfvsn = java_invoke ('org.odftoolkit.odfdom.Version', 'getApplicationVersion'); end_try_catch - if ~(strcmp (odfvsn, '0.7.5') || strcmp (odfvsn, '0.8.6') || strcmp (odfvsn, '0.8.7')) - warning ("\nodfdom version %s is not supported - use v. 0.8.6 or 0.8.7.\n", odfvsn); + # For odfdom-incubator, strip extra info + odfvsn = regexp (odfvsn, '\d\.\d\.\d', "match"){1}; + if ~(strcmp (odfvsn, "0.7.5") || strcmp (odfvsn, "0.8.6") || strcmp (odfvsn, "0.8.7") + || strfind (odfvsn, "0.8.8")) + warning ("\nodfdom version %s is not supported - use v. 0.8.6 or later\n", odfvsn); else if (strcmp (odfvsn, '0.7.5')) warning ("odfdom v. 0.7.5 support won't be maintained - please upgrade to 0.8.6 or higher.");
--- a/main/io/inst/odsread.m Fri Jun 08 14:11:42 2012 +0000 +++ b/main/io/inst/odsread.m Fri Jun 08 15:28:27 2012 +0000 @@ -118,30 +118,31 @@ ## 2011-09-18 Return empty output arg in case of empty rawarr ## 2012-01-26 Fixed "seealso" help string ## 2012-03-07 Updated texinfo help text +## 2012-06-08 Tabs replaced by double space function [ numarr, txtarr, rawarr, lim ] = odsread (filename, wsh=1, datrange=[], reqintf=[]) - if (nargin < 1 || isempty (findstr ('.ods', tolower (filename)))) - usage ("odsread: at least a filename incl. suffix is needed"); - endif - if (nargout < 1) - usage ("odsread: no output argument(s) specified"); - endif + if (nargin < 1 || isempty (findstr ('.ods', tolower (filename)))) + usage ("odsread: at least a filename incl. suffix is needed"); + endif + if (nargout < 1) + usage ("odsread: no output argument(s) specified"); + endif - ods = odsopen (filename, 0, reqintf); + ods = odsopen (filename, 0, reqintf); if (~isempty (ods)) - [rawarr, ods, rstatus] = ods2oct (ods, wsh, datrange); + [rawarr, ods, rstatus] = ods2oct (ods, wsh, datrange); - if (rstatus) - [numarr, txtarr, lim] = parsecell (rawarr, ods.limits); - else - warning (sprintf ("No data read from %s.", filename)); + if (rstatus) + [numarr, txtarr, lim] = parsecell (rawarr, ods.limits); + else + warning (sprintf ("No data read from %s.", filename)); numarr = []; - endif - - ods = odsclose (ods); + endif + + ods = odsclose (ods); endif
--- a/main/io/inst/odswrite.m Fri Jun 08 14:11:42 2012 +0000 +++ b/main/io/inst/odswrite.m Fri Jun 08 15:28:27 2012 +0000 @@ -94,29 +94,30 @@ ## 2012-01-26 Fixed "seealso" help string ## 2012-02-20 Fixed range parameter to be default empty string rather than empty numeral ## 2010-03-07 Updated texinfo help text +## 2012-06-08 Tabs replaced by double space function [ rstatus ] = odswrite (filename, data, wsh=1, crange='', reqintf=[]) - # Input validity checks - if (nargin < 2) - usage ("Insufficient arguments - see 'help odswrite'"); - elseif (~ischar (filename) || isempty (findstr ('.ods', tolower (filename)))) - error ("First argument must be a filename (incl. .ods suffix for OTK & JOD)"); - endif + # Input validity checks + if (nargin < 2) + usage ("Insufficient arguments - see 'help odswrite'"); + elseif (~ischar (filename) || isempty (findstr ('.ods', tolower (filename)))) + error ("First argument must be a filename (incl. .ods suffix for OTK & JOD)"); + endif - ods = odsopen (filename, 1, reqintf); + ods = odsopen (filename, 1, reqintf); - if (~isempty (ods)) - [ods, rstatus] = oct2ods (data, ods, wsh, crange); + if (~isempty (ods)) + [ods, rstatus] = oct2ods (data, ods, wsh, crange); - # If rstatus was not OK, reset change indicator in ods pointer - if (~rstatus) - ods.changed = rstatus; - warning ("odswrite: data transfer errors, file not rewritten"); - endif + # If rstatus was not OK, reset change indicator in ods pointer + if (~rstatus) + ods.changed = rstatus; + warning ("odswrite: data transfer errors, file not rewritten"); + endif - ods = odsclose (ods); + ods = odsclose (ods); - endif + endif endfunction