/trunk/octave-forge/main/io/inst/oct2xls.m

# · Objective C · 1062 lines · 974 code · 88 blank · 0 comment · 175 complexity · c69becd79b1976f479fc40dd3c896b71 MD5 · raw file

  1. ## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net>
  2. ##
  3. ## This program is free software; you can redistribute it and/or modify it under
  4. ## the terms of the GNU General Public License as published by the Free Software
  5. ## Foundation; either version 3 of the License, or (at your option) any later
  6. ## version.
  7. ##
  8. ## This program is distributed in the hope that it will be useful, but WITHOUT
  9. ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  11. ## details.
  12. ##
  13. ## You should have received a copy of the GNU General Public License along with
  14. ## this program; if not, see <http://www.gnu.org/licenses/>.
  15. ## -*- texinfo -*-
  16. ## @deftypefn {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls})
  17. ## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh})
  18. ## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}, @var{range})
  19. ## @deftypefnx {Function File} [ @var{xls}, @var{rstatus} ] = oct2xls (@var{arr}, @var{xls}, @var{wsh}, @var{range}, @var{options})
  20. ##
  21. ## Add data in 1D/2D CELL array @var{arr} into a cell range specified in
  22. ## @var{range} in worksheet @var{wsh} in an Excel spreadsheet file
  23. ## pointed to in structure @var{xls}.
  24. ## Return argument @var{xls} equals supplied argument @var{xls} and is
  25. ## updated by oct2xls.
  26. ##
  27. ## A subsequent call to xlsclose is needed to write the updated spreadsheet
  28. ## to disk (and -if needed- close the Excel or Java invocation).
  29. ##
  30. ## @var{arr} can be any 1D or 2D array containing numerical or character
  31. ## data (cellstr) except complex. Mixed numeric/text arrays can only be
  32. ## cell arrays.
  33. ##
  34. ## @var{xls} must be a valid pointer struct created earlier by xlsopen.
  35. ##
  36. ## @var{wsh} can be a number or string (max. 31 chars).
  37. ## In case of a yet non-existing Excel file, the first worksheet will be
  38. ## used & named according to @var{wsh} - extra empty worksheets that Excel
  39. ## creates by default are deleted.
  40. ## In case of existing files, some checks are made for existing worksheet
  41. ## names or numbers, or whether @var{wsh} refers to an existing sheet with
  42. ## a type other than worksheet (e.g., chart).
  43. ## When new worksheets are to be added to the Excel file, they are
  44. ## inserted to the right of all existing worksheets. The pointer to the
  45. ## "active" sheet (shown when Excel opens the file) remains untouched.
  46. ##
  47. ## If @var{range} is omitted or just the top left cell of the range is
  48. ## specified, the actual range to be used is determined by the size of
  49. ## @var{arr}. If nothing is specified for @var{range} the top left cell
  50. ## is assumed to be 'A1'.
  51. ##
  52. ## Data are added to the worksheet, ignoring other data already present;
  53. ## existing data in the range to be used will be overwritten.
  54. ##
  55. ## If @var{range} contains merged cells, only the elements of @var{arr}
  56. ## corresponding to the top or left Excel cells of those merged cells
  57. ## will be written, other array cells corresponding to that cell will be
  58. ## ignored.
  59. ##
  60. ## Optional argument @var{options}, a structure, can be used to specify
  61. ## various write modes.
  62. ## Currently the only option field is "formulas_as_text", which -if set
  63. ## to 1 or TRUE- specifies that formula strings (i.e., text strings
  64. ## starting with "=" and ending in a ")" ) should be entered as litteral
  65. ## text strings rather than as spreadsheet formulas (the latter is the
  66. ## default).
  67. ##
  68. ## Beware that -if invoked- Excel invocations may be left running silently
  69. ## in case of COM errors. Invoke xlsclose with proper pointer struct to
  70. ## close them.
  71. ## When using Java, note that large data array sizes elements may exhaust
  72. ## the Java shared memory space for the default java memory settings.
  73. ## For larger arrays, appropriate memory settings are needed in the file
  74. ## java.opts; then the maximum array size for the Java-based spreadsheet
  75. ## options may be in the order of 10^6 elements. In caso of UNO this
  76. ## limit is not applicable and spreadsheets may be much larger.
  77. ##
  78. ## Examples:
  79. ##
  80. ## @example
  81. ## [xlso, status] = xls2oct ('arr', xlsi, 'Third_sheet', 'AA31:AB278');
  82. ## @end example
  83. ##
  84. ## @seealso {xls2oct, xlsopen, xlsclose, xlsread, xlswrite, xlsfinfo}
  85. ##
  86. ## @end deftypefn
  87. ## Author: Philip Nienhuis
  88. ## Created: 2009-12-01
  89. ## Updates:
  90. ## 2010-01-03 (OOXML support)
  91. ## 2010-03-14 Updated help text section on java memory usage
  92. ## 2010-07-27 Added formula writing support (based on patch by Benjamin Lindner)
  93. ## 2010-08-01 Added check on input array size vs. spreadsheet capacity
  94. ## '' Changed argument topleft into range (now compatible with ML); the
  95. ## '' old argument version (just topleft cell) is still recognized, though
  96. ## 2010-08014 Added char array conversion to 1x1 cell for character input arrays
  97. ## 2010-08-16 Added check on presence of output argument. Made wsh = 1 default
  98. ## 2010-08-17 Corrected texinfo ("topleft" => "range")
  99. ## 2010-08-25 Improved help text (section on java memory usage)
  100. ## 2010-11-12 Moved ptr struct check into main func. More input validity checks
  101. ## 2010-11-13 Added check for 2-D input array
  102. ## 2010-12-01 Better check on file pointer struct (ischar (xls.xtype))
  103. ## 2011-03-29 OpenXLS support added. Works but saving to file (xlsclose) doesn't work yet
  104. ## '' Bug fixes (stray variable c_arr, and wrong test for valid xls struct)
  105. ## 2011-05-18 Experimental UNO support
  106. ## 2011-09-08 Bug fix in range arg check; code cleanup
  107. ## 2011-11-18 Fixed another bug in test for range parameter being character string
  108. ## 2012-01-26 Fixed "seealso" help string
  109. ## 2012-02-20 Fixed range parameter to be default empty string rather than empty numeral
  110. ## 2012-02-27 More range param fixes
  111. ## 2012-03-07 Updated texinfo help text
  112. ## Last script file update (incl. subfunctions): 2012-02-26
  113. function [ xls, rstatus ] = oct2xls (obj, xls, wsh=1, crange='', spsh_opts=[])
  114. if (nargin < 2) error ("oct2xls needs a minimum of 2 arguments."); endif
  115. # Make sure input array is a cell array
  116. if (isempty (obj))
  117. warning ("Request to write empty matrix - ignored.");
  118. rstatus = 1;
  119. return;
  120. elseif (isnumeric (obj))
  121. obj = num2cell (obj);
  122. elseif (ischar (obj))
  123. obj = {obj};
  124. printf ("(oct2xls: input character array converted to 1x1 cell)\n");
  125. elseif (~iscell (obj))
  126. error ("oct2xls: input array neither cell nor numeric array");
  127. endif
  128. if (ndims (obj) > 2), error ("Only 2-dimensional arrays can be written to spreadsheet"); endif
  129. # Check xls file pointer struct
  130. test1 = ~isfield (xls, "xtype");
  131. test1 = test1 || ~isfield (xls, "workbook");
  132. test1 = test1 || isempty (xls.workbook);
  133. test1 = test1 || isempty (xls.app);
  134. test1 = test1 || ~ischar (xls.xtype);
  135. if (test1)
  136. error ("Invalid xls file pointer struct");
  137. endif
  138. # Check worksheet ptr
  139. if (~(ischar (wsh) || isnumeric (wsh))), error ("Integer (index) or text (wsh name) expected for arg # 3"); endif
  140. # Check range
  141. if (~isempty (crange) && ~ischar (crange))
  142. error ("Character string (range) expected for arg # 4");
  143. elseif (isempty (crange))
  144. crange = '';
  145. endif
  146. # Various options
  147. if (isempty (spsh_opts))
  148. spsh_opts.formulas_as_text = 0;
  149. # other options to be implemented here
  150. elseif (isstruct (spsh_opts))
  151. if (~isfield (spsh_opts, 'formulas_as_text')), spsh_opts.formulas_as_text = 0; endif
  152. # other options to be implemented here
  153. else
  154. error ("Structure expected for arg # 5");
  155. endif
  156. if (nargout < 1) printf ("Warning: no output spreadsheet file pointer specified.\n"); endif
  157. # Select interface to be used
  158. if (strcmpi (xls.xtype, 'COM'))
  159. # Call oct2com2xls to do the work
  160. [xls, rstatus] = oct2com2xls (obj, xls, wsh, crange, spsh_opts);
  161. elseif (strcmpi (xls.xtype, 'POI'))
  162. # Invoke Java and Apache POI
  163. [xls, rstatus] = oct2jpoi2xls (obj, xls, wsh, crange, spsh_opts);
  164. elseif (strcmpi (xls.xtype, 'JXL'))
  165. # Invoke Java and JExcelAPI
  166. [xls, rstatus] = oct2jxla2xls (obj, xls, wsh, crange, spsh_opts);
  167. elseif (strcmpi (xls.xtype, 'OXS'))
  168. # Invoke Java and OpenXLS ##### Not complete, saving file doesn't work yet!
  169. printf ('Sorry, writing with OpenXLS not reliable => not supported yet\n');
  170. # [xls, rstatus] = oct2oxs2xls (obj, xls, wsh, crange, spsh_opts);
  171. elseif (strcmpi (xls.xtype, 'UNO'))
  172. # Invoke Java and UNO bridge (OpenOffice.org)
  173. [xls, rstatus] = oct2uno2xls (obj, xls, wsh, crange, spsh_opts);
  174. # elseif (strcmpi (xls.xtype, '<whatever>'))
  175. # <Other Excel interfaces>
  176. else
  177. error (sprintf ("oct2xls: unknown Excel .xls interface - %s.", xls.xtype));
  178. endif
  179. endfunction
  180. #===================================================================================
  181. ## Copyright (C) 2009,2010,2011,2012 by Philip Nienhuis <prnienhuis@users.sf.net>
  182. ##
  183. ## This program is free software; you can redistribute it and/or modify it under
  184. ## the terms of the GNU General Public License as published by the Free Software
  185. ## Foundation; either version 3 of the License, or (at your option) any later
  186. ## version.
  187. ##
  188. ## This program is distributed in the hope that it will be useful, but WITHOUT
  189. ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  190. ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  191. ## details.
  192. ##
  193. ## You should have received a copy of the GNU General Public License along with
  194. ## this program; if not, see <http://www.gnu.org/licenses/>.
  195. ## -*- texinfo -*-
  196. ## @deftypefn {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi})
  197. ## @deftypefnx {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi}, @var{wsh})
  198. ## @deftypefnx {Function File} [@var{xlso}, @var{status}] = oct2com2xls (@var{obj}, @var{xlsi}, @var{wsh}, @var{top_left_cell})
  199. ## Save matrix @var{obj} into worksheet @var{wsh} in Excel file pointed
  200. ## to in struct @var{xlsi}. All elements of @var{obj} are converted into
  201. ## Excel cells, starting at cell @var{top_left_cell}. Return argument
  202. ## @var{xlso} is @var{xlsi} with updated fields.
  203. ##
  204. ## oct2com2xls should not be invoked directly but rather through oct2xls.
  205. ##
  206. ## Excel invocations may be left running invisibly in case of COM errors.
  207. ##
  208. ## Example:
  209. ##
  210. ## @example
  211. ## xls = oct2com2xls (rand (10, 15), xls, 'Third_sheet', 'BF24');
  212. ## @end example
  213. ##
  214. ## @seealso {oct2xls, xls2oct, xlsopen, xlsclose, xlswrite, xlsread, xls2com2oct}
  215. ##
  216. ## @end deftypefn
  217. ## Author: Philip Nienhuis (originally based on mat2xls by Michael Goffioul)
  218. ## Rewritten: 2009-09-26
  219. ## Updates:
  220. ## 2009-12-11
  221. ## 2010-01-12 Fixed typearr sorting out (was only 1-dim & braces rather than parens))
  222. ## Set cells corresponding to empty array cells empty (cf. Matlab)
  223. ## 2010-01-13 Removed an extraneous statement used for debugging
  224. ## I plan look at it when octave v.3.4 is about to arrive.
  225. ## 2010-08-01 Added checks for input array size vs check on capacity
  226. ## '' Changed topleft arg into range arg (just topleft still recognized)
  227. ## '' Some code cleanup
  228. ## '' Added option for formula input as text string
  229. ## 2010-08-01 Added range vs. array size vs. capacity checks
  230. ## 2010-08-03 Moved range checks and type array parsing to separate functions
  231. ## 2010-10-20 Bug fix removing new empty sheets in new workbook that haven't been
  232. ## created in the first place due to Excel setting (thanks Ian Journeaux)
  233. ## '' Changed range use in COM transfer call
  234. ## 2010-10-21 Improved file change tracking (var xls.changed)
  235. ## 2010-10-24 Fixed bug introduced in above fix: for loops have no stride param,
  236. ## '' replaced by while loop
  237. ## '' Added check for "live" ActiveX server
  238. ## 2010-11-12 Moved ptr struct check into main func
  239. ## 2012-01-26 Fixed "seealso" help string
  240. ## 2012-02-27 Copyright strings updated
  241. function [ xls, status ] = oct2com2xls (obj, xls, wsh, crange, spsh_opts)
  242. # Preliminary sanity checks
  243. if (~strmatch (lower (xls.filename(end-4:end)), '.xls'))
  244. error ("oct2com2xls can only write to Excel .xls or .xlsx files")
  245. endif
  246. if (isnumeric (wsh))
  247. if (wsh < 1) error ("Illegal worksheet number: %i\n", wsh); endif
  248. elseif (size (wsh, 2) > 31)
  249. error ("Illegal worksheet name - too long")
  250. endif
  251. # Check to see if ActiveX is still alive
  252. try
  253. wb_cnt = xls.workbook.Worksheets.count;
  254. catch
  255. error ("ActiveX invocation in file ptr struct seems non-functional");
  256. end_try_catch
  257. # define some constants not yet in __COM__.cc
  258. xlWorksheet = -4167; # xlChart= 4;
  259. # scratch vars
  260. status = 0;
  261. # Parse date ranges
  262. [nr, nc] = size (obj);
  263. [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename);
  264. lowerright = calccelladdress (trow + nrows - 1, lcol + ncols - 1);
  265. crange = [topleft ':' lowerright];
  266. if (nrows < nr || ncols < nc)
  267. warning ("Array truncated to fit in range");
  268. obj = obj(1:nrows, 1:ncols);
  269. endif
  270. # Cleanup NaNs. Find where they are and mark as empty
  271. ctype = [0 1 2 3 4]; # Numeric Boolean Text Formula Empty
  272. typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts);
  273. # Make cells now indicated to be empty, empty
  274. fptr = ~(4 * (ones (size (typearr))) .- typearr);
  275. obj(fptr) = cellfun (@(x) [], obj(fptr), "Uniformoutput", false);
  276. if (spsh_opts.formulas_as_text)
  277. # find formulas (designated by a string starting with "=" and ending in ")")
  278. fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1) && strncmp (x(end:end), ")", 1), obj);
  279. # ... and add leading "'" character
  280. obj(fptr) = cellfun (@(x) ["'" x], obj(fptr), "Uniformoutput", false);
  281. endif
  282. clear fptr;
  283. if (xls.changed < 3)
  284. # Existing file OR a new file with data added in a previous oct2xls call.
  285. # Some involved investigation is needed to preserve
  286. # existing data that shouldn't be touched.
  287. #
  288. # See if desired *sheet* name exists.
  289. old_sh = 0;
  290. ws_cnt = xls.workbook.Sheets.count;
  291. if (isnumeric (wsh))
  292. if (wsh <= ws_cnt)
  293. # Here we check for sheet *position* in the sheet stack
  294. # rather than a name like "Sheet<Number>"
  295. old_sh = wsh;
  296. else
  297. # wsh > nr of sheets; proposed new sheet name.
  298. # This sheet name can already exist to the left in the sheet stack!
  299. shnm = sprintf ("Sheet%d", wsh); shnm1 = shnm;
  300. endif
  301. endif
  302. if (~old_sh)
  303. # Check if the requested (or proposed) sheet already exists
  304. # COM objects are not OO (yet?), so we need a WHILE loop
  305. ii = 1; jj = 1;
  306. while ((ii <= ws_cnt) && ~old_sh)
  307. # Get existing sheet names one by one
  308. sh_name = xls.workbook.Sheets(ii).name;
  309. if (~isnumeric (wsh) && strcmp (sh_name, wsh))
  310. # ...and check with requested sheet *name*...
  311. old_sh = ii;
  312. elseif (isnumeric (wsh) && strcmp (sh_name, shnm))
  313. # ... or proposed new sheet name (corresp. to requested sheet *number*)
  314. shnm = [shnm "_"];
  315. ii = 0; # Also check if this new augmented sheet name exists...
  316. if (strmatch (shnm1, sh_name)), jj++; endif
  317. if (jj > 5) # ... but not unlimited times...
  318. error (sprintf (" > 5 sheets named [_]Sheet%d already present!", wsh));
  319. endif
  320. endif
  321. ++ii;
  322. endwhile
  323. endif
  324. if (old_sh)
  325. # Requested sheet exists. Check if it is a *work*sheet
  326. if ~(xls.workbook.Sheets(old_sh).Type == xlWorksheet)
  327. # Error as you can't write data to Chart sheet
  328. error (sprintf ("Existing sheet '%s' is not type worksheet.", wsh));
  329. else
  330. # Simply point to the relevant sheet
  331. sh = xls.workbook.Worksheets (old_sh);
  332. endif
  333. else
  334. # Add a new worksheet. Earlier it was checked whether this is safe
  335. try
  336. sh = xls.workbook.Worksheets.Add ();
  337. catch
  338. error (sprintf ("Cannot add new worksheet to file %s\n", xls.filename));
  339. end_try_catch
  340. if (~isnumeric (wsh))
  341. sh.Name = wsh;
  342. else
  343. sh.Name = shnm;
  344. printf ("Writing to worksheet %s\n", shnm);
  345. endif
  346. # Prepare to move new sheet to right of the worksheet stack anyway
  347. ws_cnt = xls.workbook.Worksheets.count; # New count needed
  348. # Find where Excel has left it. We have to, depends on Excel version :-(
  349. ii = 1;
  350. while ((ii < ws_cnt+1) && ~strcmp (sh.Name, xls.workbook.Worksheets(ii).Name) == 1)
  351. ++ii;
  352. endwhile
  353. # Excel can't move it beyond the current last one, so we need a trick.
  354. # First move it to just before the last one....
  355. xls.workbook.Worksheets(ii).Move (before = xls.workbook.Worksheets(ws_cnt));
  356. # ....then move the last one before the new sheet.
  357. xls.workbook.Worksheets (ws_cnt).Move (before = xls.workbook.Worksheets(ws_cnt - 1));
  358. endif
  359. else
  360. # The easy case: a new Excel file. Workbook was created in xlsopen.
  361. # Delete empty non-used sheets, last one first
  362. xls.app.Application.DisplayAlerts = 0;
  363. ii = xls.workbook.Sheets.count;
  364. while (ii > 1)
  365. xls.workbook.Worksheets(ii).Delete();
  366. --ii;
  367. endwhile
  368. xls.app.Application.DisplayAlerts = 1;
  369. # Write to first worksheet:
  370. sh = xls.workbook.Worksheets (1);
  371. # Rename the sheet
  372. if (isnumeric (wsh))
  373. sh.Name = sprintf ("Sheet%i", wsh);
  374. else
  375. sh.Name = wsh;
  376. endif
  377. xls.changed = 2; # 3 => 2
  378. endif
  379. # MG's original part.
  380. # Save object in Excel sheet, starting at cell top_left_cell
  381. if (~isempty(obj))
  382. r = sh.Range (crange);
  383. try
  384. r.Value = obj;
  385. catch
  386. error (sprintf ("Cannot add data to worksheet %s in file %s\n", sh.Name, xls.filename));
  387. end_try_catch
  388. delete (r);
  389. endif
  390. # If we get here, all went OK
  391. status = 1;
  392. xls.changed = max (xls.changed, 1); # If it was 2, preserve it.
  393. endfunction
  394. #====================================================================================
  395. ## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net>
  396. ##
  397. ## This program is free software; you can redistribute it and/or modify it under
  398. ## the terms of the GNU General Public License as published by the Free Software
  399. ## Foundation; either version 3 of the License, or (at your option) any later
  400. ## version.
  401. ##
  402. ## This program is distributed in the hope that it will be useful, but WITHOUT
  403. ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  404. ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  405. ## details.
  406. ##
  407. ## You should have received a copy of the GNU General Public License along with
  408. ## this program; if not, see <http://www.gnu.org/licenses/>.
  409. ## -*- texinfo -*-
  410. ## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls ( @var{arr}, @var{xlsi})
  411. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh})
  412. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range})
  413. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jpoi2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}, @var{options})
  414. ##
  415. ## Add data in 1D/2D CELL array @var{arr} into a range with upper left
  416. ## cell equal to @var{topleft} in worksheet @var{wsh} in an Excel
  417. ## spreadsheet file pointed to in structure @var{range}.
  418. ## Return argument @var{xlso} equals supplied argument @var{xlsi} and is
  419. ## updated by oct2java2xls.
  420. ##
  421. ## oct2jpoi2xls should not be invoked directly but rather through oct2xls.
  422. ##
  423. ## Example:
  424. ##
  425. ## @example
  426. ## [xlso, status] = xls2jpoi2oct ('arr', xlsi, 'Third_sheet', 'AA31');
  427. ## @end example
  428. ##
  429. ## @seealso {oct2xls, xls2oct, xlsopen, xlsclose, xlsread, xlswrite}
  430. ##
  431. ## @end deftypefn
  432. ## Author: Philip Nienhuis
  433. ## Created: 2009-11-26
  434. ## Updates:
  435. ## 2010-01-03 Bugfixes
  436. ## 2010-01-12 Added xls.changed = 1 statement to signal successful write
  437. ## 2010-03-08 Dumped formula evaluator for booleans. Not being able to
  438. ## write booleans was due to a __java__.oct deficiency (see
  439. ## http://sourceforge.net/mailarchive/forum.php?thread_name=4B59A333.5060302%40net.in.tum.de&forum_name=octave-dev )
  440. ## 2010-07-27 Added formula writing support (based on patch by Benjamin Lindner)
  441. ## 2010-08-01 Improved try-catch for formulas to enter wrong formulas as text strings
  442. ## 2010-08-01 Added range vs. array size vs. capacity checks
  443. ## 2010-08-03 Moved range checks and type array parsingto separate functions
  444. ## 2010-10-21 Improved logic for tracking file changes
  445. ## 2010-10-27 File change tracking again refined, internal var 'changed' dropped
  446. ## 2010-11-12 Moved ptr struct check into main func
  447. ## 2011-11-19 Try-catch added to allow for changed method name for nr of worksheets
  448. ## 2012-01-26 Fixed "seealso" help string
  449. ## 2012-02-27 Copyright strings updated
  450. function [ xls, rstatus ] = oct2jpoi2xls (obj, xls, wsh, crange, spsh_opts)
  451. # Preliminary sanity checks
  452. if (~strmatch (tolower (xls.filename(end-4:end)), '.xls'))
  453. error ("oct2jpoi2xls can only write to Excel .xls or .xlsx files")
  454. endif
  455. persistent ctype;
  456. if (isempty (ctype))
  457. # Get cell types. Beware as they start at 0 not 1
  458. ctype(1) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_NUMERIC'); # 0
  459. ctype(2) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BOOLEAN'); # 4
  460. ctype(3) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_STRING'); # 1
  461. ctype(4) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_FORMULA'); # 2
  462. ctype(5) = java_get ('org.apache.poi.ss.usermodel.Cell', 'CELL_TYPE_BLANK'); # 3
  463. endif
  464. # scratch vars
  465. rstatus = 0; f_errs = 0;
  466. # Check if requested worksheet exists in the file & if so, get pointer
  467. try
  468. nr_of_sheets = xls.workbook.getNumWorkSheets ();
  469. catch
  470. nr_of_sheets = xls.workbook.getNumberOfSheets ();
  471. end_try_catch
  472. if (isnumeric (wsh))
  473. if (wsh > nr_of_sheets)
  474. # Watch out as a sheet called Sheet%d can exist with a lower index...
  475. strng = sprintf ("Sheet%d", wsh);
  476. ii = 1;
  477. while (~isempty (xls.workbook.getSheet (strng)) && (ii < 5))
  478. strng = ['_' strng];
  479. ++ii;
  480. endwhile
  481. if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif
  482. sh = xls.workbook.createSheet (strng);
  483. xls.changed = min (xls.changed, 2); # Keep 2 for new files
  484. else
  485. sh = xls.workbook.getSheetAt (wsh - 1); # POI sheet count 0-based
  486. endif
  487. printf ("(Writing to worksheet %s)\n", sh.getSheetName ());
  488. else
  489. sh = xls.workbook.getSheet (wsh);
  490. if (isempty (sh))
  491. # Sheet not found, just create it
  492. sh = xls.workbook.createSheet (wsh);
  493. xls.changed = min (xls.changed, 2); # Keep 2 or 3 f. new files
  494. endif
  495. endif
  496. # Parse date ranges
  497. [nr, nc] = size (obj);
  498. [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename);
  499. if (nrows < nr || ncols < nc)
  500. warning ("Array truncated to fit in range");
  501. obj = obj(1:nrows, 1:ncols);
  502. endif
  503. # Prepare type array
  504. typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts);
  505. if ~(spsh_opts.formulas_as_text)
  506. # Remove leading '=' from formula strings
  507. # FIXME should be easier using typearr<4> info
  508. fptr = ~(2 * (ones (size (typearr))) .- typearr);
  509. obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false);
  510. endif
  511. # Create formula evaluator
  512. frm_eval = xls.workbook.getCreationHelper ().createFormulaEvaluator ();
  513. for ii=1:nrows
  514. ll = ii + trow - 2; # Java POI's row count = 0-based
  515. row = sh.getRow (ll);
  516. if (isempty (row)) row = sh.createRow (ll); endif
  517. for jj=1:ncols
  518. kk = jj + lcol - 2; # POI's column count is also 0-based
  519. if (typearr(ii, jj) == ctype(5)) # Empty cells
  520. cell = row.createCell (kk, ctype(5));
  521. elseif (typearr(ii, jj) == ctype(4)) # Formulas
  522. # Try-catch needed as there's no guarantee for formula correctness
  523. try
  524. cell = row.createCell (kk, ctype(4));
  525. cell.setCellFormula (obj{ii,jj});
  526. catch
  527. ++f_errs;
  528. cell.setCellType (ctype (3)); # Enter formula as text
  529. cell.setCellValue (obj{ii, jj});
  530. end_try_catch
  531. else
  532. cell = row.createCell (kk, typearr(ii,jj));
  533. cell.setCellValue (obj{ii, jj});
  534. endif
  535. endfor
  536. endfor
  537. if (f_errs)
  538. printf ("%d formula errors encountered - please check input array\n", f_errs);
  539. endif
  540. xls.changed = max (xls.changed, 1); # Preserve a "2"
  541. rstatus = 1;
  542. endfunction
  543. #====================================================================================
  544. ## Copyright (C) 2009,2010,2011,2012 Philip Nienhuis <prnienhuis at users.sf.net>
  545. ##
  546. ## This program is free software; you can redistribute it and/or modify it under
  547. ## the terms of the GNU General Public License as published by the Free Software
  548. ## Foundation; either version 3 of the License, or (at your option) any later
  549. ## version.
  550. ##
  551. ## This program is distributed in the hope that it will be useful, but WITHOUT
  552. ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  553. ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  554. ## details.
  555. ##
  556. ## You should have received a copy of the GNU General Public License along with
  557. ## this program; if not, see <http://www.gnu.org/licenses/>.
  558. ## -*- texinfo -*-
  559. ## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls ( @var{arr}, @var{xlsi})
  560. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh})
  561. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range})
  562. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2jxla2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}, @var{options})
  563. ##
  564. ## Add data in 1D/2D CELL array @var{arr} into spreadsheet cell range @var{range}
  565. ## in worksheet @var{wsh} in an Excel spreadsheet file pointed to in structure
  566. ## @var{range}.
  567. ## Return argument @var{xlso} equals supplied argument @var{xlsi} and is
  568. ## updated by oct2jxla2xls.
  569. ##
  570. ## oct2jxla2xls should not be invoked directly but rather through oct2xls.
  571. ##
  572. ## Example:
  573. ##
  574. ## @example
  575. ## [xlso, status] = oct2jxla2oct ('arr', xlsi, 'Third_sheet', 'AA31');
  576. ## @end example
  577. ##
  578. ## @seealso {oct2xls, xls2oct, xlsopen, xlsclose, xlsread, xlswrite, xls2jxla2oct}
  579. ##
  580. ## @end deftypefn
  581. ## Author: Philip Nienhuis
  582. ## Created: 2009-12-04
  583. ## Updates:
  584. ## 2009-12-11
  585. ## 2010-01-12 Fixed skipping empty array values (now Excel-conformant => cell cleared)
  586. ## Added xls.changed = 1 statement to signal successful write
  587. ## 2010-07-27 Added formula writing support (based on POI patch by Benjamin Lindner)
  588. ## Added check for valid file pointer struct
  589. ## 2010-08-01 Improved try-catch for formulas to enter wrong formulas as text strings
  590. ## 2010-08-01 Added range vs. array size vs. capacity checks
  591. ## '' Code cleanup
  592. ## '' Changed topleft arg into range arg (topleft version still recognized)
  593. ## 2010-08-03 Moved range checks and cell type parsing to separate routines
  594. ## 2010-08-11 Moved addcell() into try-catch as it is addCell which throws fatal errors
  595. ## 2010-10-20 Improved logic for tracking file changes (xls.changed 2 or 3); dropped
  596. ## '' internal variable 'changed'
  597. ## 2010-10-27 File change tracking again refined
  598. ## 2010-11-12 Moved ptr struct check into main func
  599. ## 2012-01-26 Fixed "seealso" help string
  600. ## 2012-02-27 Copyright strings updated
  601. function [ xls, rstatus ] = oct2jxla2xls (obj, xls, wsh, crange, spsh_opts)
  602. # Preliminary sanity checks
  603. if (~strmatch (tolower (xls.filename(end-4:end-1)), '.xls')) # No OOXML in JXL
  604. error ("JExcelAPI can only write to Excel .xls files")
  605. endif
  606. persistent ctype;
  607. if (isempty (ctype))
  608. ctype = [1, 2, 3, 4, 5];
  609. # Number, Boolean, String, Formula, Empty
  610. endif
  611. # scratch vars
  612. rstatus = 0; f_errs = 0;
  613. # Prepare workbook pointer if needed
  614. if (xls.changed == 0) # Only for 1st call of octxls after xlsopen
  615. # Create writable copy of workbook. If >2 a writable wb was made in xlsopen
  616. xlsout = java_new ('java.io.File', xls.filename);
  617. wb = java_invoke ('jxl.Workbook', 'createWorkbook', xlsout, xls.workbook);
  618. # Catch JExcelAPI bug/"feature": when switching to write mode, the file on disk
  619. # is affected and the memory file MUST be written to disk to save earlier data
  620. xls.changed = 1;
  621. xls.workbook = wb;
  622. else
  623. wb = xls.workbook;
  624. endif
  625. # Check if requested worksheet exists in the file & if so, get pointer
  626. nr_of_sheets = xls.workbook.getNumberOfSheets (); # 1 based !!
  627. if (isnumeric (wsh))
  628. if (wsh > nr_of_sheets)
  629. # Watch out as a sheet called Sheet%d can exist with a lower index...
  630. strng = sprintf ("Sheet%d", wsh);
  631. ii = 1;
  632. while (~isempty (wb.getSheet (strng)) && (ii < 5))
  633. strng = ['_' strng];
  634. ++ii;
  635. endwhile
  636. if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif
  637. sh = wb.createSheet (strng, nr_of_sheets); ++nr_of_sheets;
  638. xls.changed = min (xls.changed, 2); # Keep a 2 in case of new file
  639. else
  640. sh = wb.getSheet (wsh - 1); # JXL sheet count 0-based
  641. endif
  642. shnames = char (wb.getSheetNames ());
  643. printf ("(Writing to worksheet %s)\n", shnames {nr_of_sheets, 1});
  644. else
  645. sh = wb.getSheet (wsh);
  646. if (isempty(sh))
  647. # Sheet not found, just create it
  648. sh = wb.createSheet (wsh, nr_of_sheets);
  649. ++nr_of_sheets;
  650. xls.changed = min (xls.changed, 2); # Keep a 2 for new file
  651. endif
  652. endif
  653. # Parse date ranges
  654. [nr, nc] = size (obj);
  655. [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename);
  656. if (nrows < nr || ncols < nc)
  657. warning ("Array truncated to fit in range");
  658. obj = obj(1:nrows, 1:ncols);
  659. endif
  660. # Prepare type array
  661. typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts);
  662. if ~(spsh_opts.formulas_as_text)
  663. # Remove leading '=' from formula strings
  664. fptr = ~(4 * (ones (size (typearr))) .- typearr);
  665. obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false);
  666. endif
  667. clear fptr
  668. # Write date to worksheet
  669. for ii=1:nrows
  670. ll = ii + trow - 2; # Java JExcelAPI's row count = 0-based
  671. for jj=1:ncols
  672. kk = jj + lcol - 2; # JExcelAPI's column count is also 0-based
  673. switch typearr(ii, jj)
  674. case 1 # Numerical
  675. tmp = java_new ('jxl.write.Number', kk, ll, obj{ii, jj});
  676. sh.addCell (tmp);
  677. case 2 # Boolean
  678. tmp = java_new ('jxl.write.Boolean', kk, ll, obj{ii, jj});
  679. sh.addCell (tmp);
  680. case 3 # String
  681. tmp = java_new ('jxl.write.Label', kk, ll, obj{ii, jj});
  682. sh.addCell (tmp);
  683. case 4 # Formula
  684. # First make sure formula functions are all uppercase
  685. obj{ii, jj} = toupper (obj{ii, jj});
  686. # There's no guarantee for formula correctness, so....
  687. try # Actually JExcelAPI flags formula errors as mere warnings :-(
  688. tmp = java_new ('jxl.write.Formula', kk, ll, obj{ii, jj});
  689. # ... while errors are actually detected in addCell(), so
  690. # that should be within the try-catch
  691. sh.addCell (tmp);
  692. catch
  693. ++f_errs;
  694. # Formula error. Enter formula as text string instead
  695. tmp = java_new ('jxl.write.Label', kk, ll, obj{ii, jj});
  696. sh.addCell (tmp);
  697. end_try_catch
  698. case 5 # Empty or NaN
  699. tmp = java_new ('jxl.write.Blank', kk, ll);
  700. sh.addCell (tmp);
  701. otherwise
  702. # Just skip
  703. endswitch
  704. endfor
  705. endfor
  706. if (f_errs)
  707. printf ("%d formula errors encountered - please check input array\n", f_errs);
  708. endif
  709. xls.changed = max (xls.changed, 1); # Preserve 2 for new files
  710. rstatus = 1;
  711. endfunction
  712. ## Copyright (C) 2011 Philip Nienhuis <prnienhuis@users.sf.net>
  713. ##
  714. ## This program is free software; you can redistribute it and/or modify it under
  715. ## the terms of the GNU General Public License as published by the Free Software
  716. ## Foundation; either version 3 of the License, or (at your option) any later
  717. ## version.
  718. ##
  719. ## This program is distributed in the hope that it will be useful, but WITHOUT
  720. ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  721. ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  722. ## details.
  723. ##
  724. ## You should have received a copy of the GNU General Public License along with
  725. ## this program; if not, see <http://www.gnu.org/licenses/>.
  726. ## -*- texinfo -*-
  727. ## @deftypefn {Function File} [ @var{xlso}, @var{rstatus} ] = oct2oxs2xls ( @var{arr}, @var{xlsi})
  728. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2oxs2xls (@var{arr}, @var{xlsi}, @var{wsh})
  729. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2oxs2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range})
  730. ## @deftypefnx {Function File} [ @var{xlso}, @var{rstatus} ] = oct2oxs2xls (@var{arr}, @var{xlsi}, @var{wsh}, @var{range}, @var{options})
  731. ##
  732. ## Add data in 1D/2D CELL array @var{arr} into spreadsheet cell range @var{range}
  733. ## in worksheet @var{wsh} in an Excel spreadsheet file pointed to in structure
  734. ## @var{range}.
  735. ## Return argument @var{xlso} equals supplied argument @var{xlsi} and is
  736. ## updated by oct2oxs2xls.
  737. ##
  738. ## oct2oxs2xls should not be invoked directly but rather through oct2xls.
  739. ##
  740. ## @end deftypefn
  741. ## Author: Philip Nienhuis <prnienhuis@users.sf.net>
  742. ## Created: 2011-03-29
  743. ## Updates:
  744. ##
  745. function [ xls, rstatus ] = oct2oxs2xls (obj, xls, wsh, crange, spsh_opts)
  746. # Preliminary sanity checks
  747. if (~strmatch (tolower (xls.filename(end-4:end-1)), '.xls')) # No OOXML in OXS
  748. error ("OXS can only write to Excel .xls files")
  749. endif
  750. changed = 0;
  751. persistent ctype;
  752. if (isempty (ctype))
  753. ctype = [1, 2, 3, 4, 5];
  754. # Number, Boolean, String, Formula, Empty
  755. endif
  756. # scratch vars
  757. rstatus = 0; f_errs = 0;
  758. # Prepare workbook pointer if needed
  759. wb = xls.workbook;
  760. # Check if requested worksheet exists in the file & if so, get pointer
  761. nr_of_sheets = wb.getNumWorkSheets (); # 1 based !!
  762. if (isnumeric (wsh))
  763. if (wsh > nr_of_sheets)
  764. # Watch out as a sheet called Sheet%d can exist with a lower index...
  765. strng = sprintf ("Sheet%d", wsh);
  766. ii = 1;
  767. try
  768. # While loop should be inside try-catch
  769. while (ii < 5)
  770. sh = wb.getWorkSheet (strng)
  771. strng = ['_' strng];
  772. ++ii;
  773. endwhile
  774. catch
  775. # No worksheet named <strng> found => we can proceed
  776. end_try_catch
  777. if (ii >= 5) error (sprintf( " > 5 sheets named [_]Sheet%d already present!", wsh)); endif
  778. sh = wb.createWorkSheet (strng); ++nr_of_sheets;
  779. xls.changed = min (xls.changed, 2); # Keep a 2 in case of new file
  780. else
  781. sh = wb.getWorkSheet (wsh - 1); # OXS sheet count 0-based
  782. endif
  783. printf ("(Writing to worksheet %s)\n", sh.getSheetName ());
  784. else
  785. try
  786. sh = wb.getWorkSheet (wsh);
  787. catch
  788. # Sheet not found, just create it
  789. sh = wb.createWorkSheet (wsh); ++nr_of_sheets;
  790. xls.changed = min (xls.changed, 2); # Keep a 2 for new file
  791. end_try_catch
  792. endif
  793. # Parse date ranges
  794. [nr, nc] = size (obj);
  795. [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename);
  796. if (nrows < nr || ncols < nc)
  797. warning ("Array truncated to fit in range");
  798. obj = obj(1:nrows, 1:ncols);
  799. endif
  800. # Prepare type array
  801. typearr = spsh_prstype (obj, nrows, ncols, ctype, spsh_opts);
  802. if ~(spsh_opts.formulas_as_text)
  803. # Remove leading '=' from formula strings //FIXME needs updating
  804. fptr = ~(4 * (ones (size (typearr))) .- typearr);
  805. obj(fptr) = cellfun (@(x) x(2:end), obj(fptr), "Uniformoutput", false);
  806. endif
  807. clear fptr
  808. for ii=1:ncols
  809. for jj=1:nrows
  810. try
  811. # Set value
  812. sh.getCell(jj+trow-2, ii+lcol-2).setVal (obj{jj, ii}); # Addr.cnt = 0-based
  813. changed = 1;
  814. catch
  815. # Cell not existant. Add cell
  816. if ~(typearr(jj, ii) == 5)
  817. sh.add (obj{jj, ii}, jj+trow-2, ii+lcol-2);
  818. changed = 1;
  819. endif
  820. end_try_catch
  821. endfor
  822. endfor
  823. if (changed), xls.changed = max (xls.changed, 1); endif # Preserve 2 for new files
  824. rstatus = 1;
  825. endfunction
  826. ## Copyright (C) 2011,2012 Philip Nienhuis <prnienhuis@users.sf.net>
  827. ##
  828. ## This program is free software; you can redistribute it and/or modify it under
  829. ## the terms of the GNU General Public License as published by the Free Software
  830. ## Foundation; either version 3 of the License, or (at your option) any later
  831. ## version.
  832. ##
  833. ## This program is distributed in the hope that it will be useful, but WITHOUT
  834. ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  835. ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  836. ## details.
  837. ##
  838. ## You should have received a copy of the GNU General Public License along with
  839. ## this program; if not, see <http://www.gnu.org/licenses/>.
  840. ## oct2uno2xls
  841. ## Author: Philip Nienhuis <prnienhuis@users.sf.net>
  842. ## Created: 2011-05-18
  843. ## 2011-09-18 Adapted sh_names type to LO 3.4.1
  844. ## 2011-09-23 Removed stray debug statements
  845. ## 2012-02-25 Fixed wrong var name in L.933
  846. ## 2012-02-25 Catch stray Java RuntimeException when deleting sheets
  847. ## 2012-02-26 Bug fix when adding sheets near L.994 (wrong if-else-end construct).
  848. ## 2012-02-27 Copyright strings updated
  849. function [ xls, rstatus ] = oct2uno2xls (c_arr, xls, wsh, crange, spsh_opts)
  850. changed = 0;
  851. newsh = 0;
  852. ctype = [1, 2, 3, 4, 5]; # Float, Logical, String, Formula, Empty
  853. # Get handle to sheet, create a new one if needed
  854. sheets = xls.workbook.getSheets ();
  855. sh_names = sheets.getElementNames ();
  856. if (! iscell (sh_names))
  857. # Java array (LibreOffice 3.4.+); convert to cellstr
  858. sh_names = char (sh_names);
  859. else
  860. sh_names = {sh_names};
  861. endif
  862. # Clear default 2 last sheets in case of a new spreadsheet file
  863. if (xls.changed > 2)
  864. ii = numel (sh_names);
  865. while (ii > 1)
  866. shnm = sh_names{ii};
  867. try
  868. # Catch harmless Java RuntimeException "out of range" in LibreOffice 3.5rc1
  869. sheets.removeByName (shnm);
  870. end_try_catch
  871. --ii;
  872. endwhile
  873. # Give remaining sheet a name
  874. unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.sheet.XSpreadsheet');
  875. sh = sheets.getByName (sh_names{1}).getObject.queryInterface (unotmp);
  876. if (isnumeric (wsh)); wsh = sprintf ("Sheet%d", wsh); endif
  877. unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.container.XNamed');
  878. sh.queryInterface (unotmp).setName (wsh);
  879. else
  880. # Check sheet pointer
  881. # FIXME sheet capacity check needed
  882. if (isnumeric (wsh))
  883. if (wsh < 1)
  884. error ("Illegal sheet index: %d", wsh);
  885. elseif (wsh > numel (sh_names))
  886. # New sheet to be added. First create sheet name but check if it already exists
  887. shname = sprintf ("Sheet%d", numel (sh_names) + 1);
  888. jj = strmatch (wsh, sh_names);
  889. if (~isempty (jj))
  890. # New sheet name already in file, try to create a unique & reasonable one
  891. ii = 1; filler = ''; maxtry = 5;
  892. while (ii <= maxtry)
  893. shname = sprintf ("Sheet%s%d", [filler "_"], numel (sh_names + 1));
  894. if (isempty (strmatch (wsh, sh_names)))
  895. ii = 10;
  896. else
  897. ++ii;
  898. endif
  899. endwhile
  900. if (ii > maxtry + 1)
  901. error ("Could not add sheet with a unique name to file %s");
  902. endif
  903. endif
  904. wsh = shname;
  905. newsh = 1;
  906. else
  907. # turn wsh index into the associated sheet name
  908. wsh = sh_names (wsh);
  909. endif
  910. else
  911. # wsh is a sheet name. See if it exists already
  912. if (isempty (strmatch (wsh, sh_names)))
  913. # Not found. New sheet to be added
  914. newsh = 1;
  915. endif
  916. endif
  917. if (newsh)
  918. # Add a new sheet. Sheet index MUST be a Java Short object
  919. shptr = java_new ("java.lang.Short", sprintf ("%d", numel (sh_names) + 1));
  920. sh = sheets.insertNewByName (wsh, shptr);
  921. endif
  922. # At this point we have a valid sheet name. Use it to get a sheet handle
  923. unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.sheet.XSpreadsheet');
  924. sh = sheets.getByName (wsh).getObject.queryInterface (unotmp);
  925. endif
  926. # Check size of data array & range / capacity of worksheet & prepare vars
  927. [nr, nc] = size (c_arr);
  928. [topleft, nrows, ncols, trow, lcol] = spsh_chkrange (crange, nr, nc, xls.xtype, xls.filename);
  929. --trow; --lcol; # Zero-based row # & col #
  930. if (nrows < nr || ncols < nc)
  931. warning ("Array truncated to fit in range");
  932. c_arr = c_arr(1:nrows, 1:ncols);
  933. endif
  934. # Parse data array, setup typarr and throw out NaNs to speed up writing;
  935. typearr = spsh_prstype (c_arr, nrows, ncols, ctype, spsh_opts, 0);
  936. if ~(spsh_opts.formulas_as_text)
  937. # Find formulas (designated by a string starting with "=" and ending in ")")
  938. fptr = cellfun (@(x) ischar (x) && strncmp (x, "=", 1), c_arr);
  939. typearr(fptr) = ctype(4); # FORMULA
  940. endif
  941. # Transfer data to sheet
  942. for ii=1:nrows
  943. for jj=1:ncols
  944. try
  945. XCell = sh.getCellByPosition (lcol+jj-1, trow+ii-1);
  946. switch typearr(ii, jj)
  947. case 1 # Float
  948. XCell.setValue (c_arr{ii, jj});
  949. case 2 # Logical. Convert to float as OOo has no Boolean type
  950. XCell.setValue (double (c_arr{ii, jj}));
  951. case 3 # String
  952. unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.text.XText');
  953. XCell.queryInterface (unotmp).setString (c_arr{ii, jj});
  954. case 4 # Formula
  955. if (spsh_opts.formulas_as_text)
  956. unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.text.XText');
  957. XCell.queryInterface (unotmp).setString (c_arr{ii, jj});
  958. else
  959. XCell.setFormula (c_arr{ii, jj});
  960. endif
  961. otherwise
  962. # Empty cell
  963. endswitch
  964. changed = 1;
  965. catch
  966. printf ("Error writing cell %s (typearr() = %d)\n", calccelladdress(trow+ii, lcol+jj), typearr(ii, jj));
  967. end_try_catch
  968. endfor
  969. endfor
  970. if (changed)
  971. xls.changed = max (min (xls.changed, 2), changed); # Preserve 2 (new file), 1 (existing)
  972. rstatus = 1;
  973. endif
  974. endfunction