]> Creatis software - CreaPhase.git/blobdiff - octave_packages/io-1.0.19/xlsclose.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / io-1.0.19 / xlsclose.m
diff --git a/octave_packages/io-1.0.19/xlsclose.m b/octave_packages/io-1.0.19/xlsclose.m
new file mode 100644 (file)
index 0000000..c38fd80
--- /dev/null
@@ -0,0 +1,278 @@
+## 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
+## Foundation; either version 3 of the License, or (at your option) any later
+## version.
+##
+## This program is distributed in the hope that it will be useful, but WITHOUT
+## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} [@var{xls}] = xlsclose (@var{xls})
+## @deftypefnx {Function File} [@var{xls}] = xlsclose (@var{xls}, @var{filename})
+## @deftypefnx {Function File} [@var{xls}] = xlsclose (@var{xls}, "FORCE")
+## Close the Excel spreadsheet pointed to in struct @var{xls}, if needed
+## write the file to disk. Based on information contained in @var{xls},
+## xlsclose will determine if the file should be written to disk.
+##
+## If no errors occured during writing, the xls file pointer struct will be
+## reset and -if COM interface was used- ActiveX/Excel will be closed.
+## However if errors occurred, the file pinter will be untouched so you can
+## clean up before a next try with xlsclose().
+## Be warned that until xlsopen is called again with the same @var{xls} pointer
+## struct, hidden Excel or Java applications with associated (possibly large)
+## memory chunks are kept in memory, taking up resources.
+## If (string) argument "FORCE" is supplied, the file pointer will be reset 
+## regardless, whether the possibly modified file has been saved successfully
+## or not. Hidden Excel (COM) or OpenOffice.org (UNO) invocations may live on,
+## possibly even impeding proper shutdown of Octave.
+##
+## @var{filename} can be used to write changed spreadsheet files to
+## an other file than opened with xlsopen(); unfortunately this doesn't work
+## with JXL (JExcelAPI) interface.
+##
+## You need MS-Excel (95 - 2010), and/or the Java package => 1.2.8 plus Apache
+## POI > 3.5 and/or JExcelAPI and/or OpenXLS and/or OpenOffice.org or clones
+## installed on your computer + proper javaclasspath set, to make this
+## function work at all.
+##
+## @var{xls} must be a valid pointer struct made by xlsopen() in the same
+## octave session.
+##
+## Examples:
+##
+## @example
+##   xls1 = xlsclose (xls1);
+##   (Close spreadsheet file pointed to in pointer struct xls1; xls1 is reset)
+## @end example
+##
+## @seealso {xlsopen, xlsread, xlswrite, xls2oct, oct2xls, xlsfinfo}
+##
+## @end deftypefn
+
+## Author: Philip Nienhuis
+## Created: 2009-11-29
+## Updates: 
+## 2010-01-03 (checked OOXML support)
+## 2010-08-25 See also: xlsopen (instead of xlsclose)
+## 2010-10-20 Improved tracking of file changes and need to write it to disk
+## 2010-10-27 Various changes to catch errors when writing to disk;
+##     "      Added input arg "keepxls" for use with xlswrite.m to save the
+##     "      untouched file ptr struct in case of errors rather than wipe it
+## 2010-11-12 Replaced 'keepxls' by new filename arg; catch write errors and
+##            always keep file pointer in case of write errors
+## 2011-03-26 Added OpenXLS support
+## 2011-05-18 Added experimental UNO support, incl. saving newly created files
+## 2011-09-08 Bug fix in check for filename input arg
+## 2012-01-26 Fixed "seealso" help string
+
+function [ xls ] = xlsclose (xls, varargs)
+
+       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}), '.')))
+                               # Apparently a file name
+                               if (xls.changed == 0 || xls.changed > 2)
+                                       printf ("File %s wasn't changed, new filename ignored.", xls.filename);
+                               elseif (strcmp (xls.xtype, 'JXL'))
+                                       error ("JXL doesn't support changing filename, new filename ignored.");
+                               elseif ~((strcmp (xls.xtype, 'COM') || strcmp (xls.xtype, 'UNO')) && isempty (strfind ( lower (filename), '.xls')))
+                                       # Excel/ActiveX && OOo (UNO bridge) will write any valid filetype; POI/JXL/OXS need .xls[x]
+                                       error ('.xls or .xlsx extension lacking in filename %s', filename);
+                               else
+                                       ### For multi-user environments, uncomment below AND relevant stanza in xlsopen
+                                       # In case of COM, be sure to first close the open workbook
+                                       #if (strcmp (xls.xtype, 'COM'))
+                                       #        xls.app.Application.DisplayAlerts = 0;
+                                       #        xls.workbook.close();
+                                       #        xls.app.Application.DisplayAlerts = 0;
+                                       #endif
+                                       if (strcmp (xls.xtype, 'UNO'))
+                                               # If needed, turn filename into URL
+                                               if (~isempty (strmatch ("file:///", filename)) || ~isempty (strmatch ("http:///", filename))...
+                                                       || ~isempty (strmatch ("ftp:///", filename)) || ~isempty (strmatch ("www:///", filename)))
+                                                       # Seems in proper shape for OOo (at first sight)
+                                               else
+                                                       # Transform into URL form
+                                                       fname = canonicalize_file_name (strsplit (filename, filesep){end});
+                                                       # On Windows, change backslash file separator into forward slash
+                                                       if (strcmp (filesep, "\\"))
+                                                               tmp = strsplit (fname, filesep);
+                                                               flen = numel (tmp);
+                                                               tmp(2:2:2*flen) = tmp;
+                                                               tmp(1:2:2*flen) = '/';
+                                                               filename = [ 'file://' tmp{:} ];
+                                                       endif
+                                               endif
+                                       endif
+          # Preprocessing / -checking ready. Assign filename arg to file ptr struct
+                                       xls.filename = filename;
+                               endif
+                       endif
+               endfor
+       endif
+
+       if (strcmp (xls.xtype, 'COM'))
+               # If file has been changed, write it out to disk.
+               #
+               # Note: COM / VB supports other Excel file formats as FileFormatNum:
+               # 4 = .wks - Lotus 1-2-3 / Microsoft Works
+               # 6 = .csv
+               # -4158 = .txt 
+               # 36 = .prn
+               # 50 = .xlsb - xlExcel12 (Excel Binary Workbook in 2007 with or without macro's)
+               # 51 = .xlsx - xlOpenXMLWorkbook (without macro's in 2007)
+               # 52 = .xlsm - xlOpenXMLWorkbookMacroEnabled (with or without macro's in 2007)
+               # 56 = .xls  - xlExcel8 (97-2003 format in Excel 2007)
+               # (see Excel Help, VB reference, Enumerations, xlFileType)
+               
+               # xls.changed = 0: no changes: just close;
+               #               1: existing file with changes: save, close.
+               #               2: new file with data added: save, close
+               #               3: new file, no added added (empty): close & delete on disk
+
+               xls.app.Application.DisplayAlerts = 0;
+               try
+                       if (xls.changed > 0 && xls.changed < 3)
+                               if (xls.changed == 2)
+                                       # Probably a newly created, or renamed, Excel file
+                                       printf ("Saving file %s ...\n", xls.filename);
+                                       xls.workbook.SaveAs (canonicalize_file_name (xls.filename));
+                               elseif (xls.changed == 1)
+                                       # Just updated existing Excel file
+                                       xls.workbook.Save ();
+                               endif
+                               xls.changed = 0;
+                               xls.workbook.Close (canonicalize_file_name (xls.filename));
+                       endif
+                       xls.app.Quit ();
+                       delete (xls.workbook);  # This statement actually closes the workbook
+                       delete (xls.app);               # This statement actually closes down Excel
+               catch
+                       xls.app.Application.DisplayAlerts = 1;
+               end_try_catch
+               
+       elseif (strcmp (xls.xtype, 'POI'))
+               if (xls.changed > 0 && xls.changed < 3)
+                       try
+                               xlsout = java_new ("java.io.FileOutputStream", xls.filename);
+                               bufout = java_new ("java.io.BufferedOutputStream", xlsout);
+                               if (xls.changed == 2) printf ("Saving file %s...\n", xls.filename); endif
+                               xls.workbook.write (bufout);
+                               bufout.flush ();
+                               bufout.close ();
+                               xlsout.close ();
+                               xls.changed = 0;
+                       catch
+#                              xlsout.close ();
+                       end_try_catch
+               endif
+
+       elseif (strcmp (xls.xtype, 'JXL'))
+               if (xls.changed > 0 && xls.changed < 3)
+                       try
+                               if (xls.changed == 2) printf ("Saving file %s...\n", xls.filename); endif
+                               xls.workbook.write ();
+                               xls.workbook.close ();
+                               if (xls.changed == 3)
+                                       # Upon entering write mode, JExcelAPI always makes a disk file
+                                       # Incomplete new files (no data added) had better be deleted.
+                                       xls.workbook.close ();
+                                       delete (xls.filename); 
+                               endif
+                               xls.changed = 0;
+                       catch
+                       end_try_catch
+               endif
+
+       elseif (strcmp (xls.xtype, 'OXS'))
+               if (xls.changed > 0 && xls.changed < 3)
+                       try
+                               xlsout = java_new ("java.io.FileOutputStream", xls.filename);
+                               bufout = java_new ("java.io.BufferedOutputStream", xlsout);
+                               if (xls.changed == 2) printf ("Saving file %s...\n", xls.filename); endif
+                               xls.workbook.writeBytes (bufout);
+                               xls.workbook.close ();
+                               bufout.flush ();
+                               bufout.close ();
+                               xlsout.close ();
+                               xls.changed = 0;
+                       catch
+#                              xlsout.close ();
+                       end_try_catch
+               else
+                       xls.workbook.close ();
+               endif
+
+       elseif (strcmp (xls.xtype, 'UNO'))
+               # Java & UNO bridge
+               try
+                       if (xls.changed && xls.changed < 3)
+                               # Workaround:
+                               unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XModel');
+                               xModel = xls.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 = xls.app.xComp.queryInterface (unotmp);
+                                       if (xls.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, store file
+                                               xStore.storeAsURL (xls.filename, lProps);
+                                       else
+                                               xStore.store ();
+                                       endif
+                               endif
+                       endif
+                       xls.changed = -1;               # Needed for check on properly shutting down OOo
+                       # Workaround:
+                       unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XModel');
+                       xModel = xls.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 = xls.app.aLoader.queryInterface (unotmp);
+                       xDesk.terminate();
+                       xls.changed = 0;
+               catch
+                       if (force)
+                               # Force closing OOo
+                               unotmp = java_new ('com.sun.star.uno.Type', 'com.sun.star.frame.XDesktop');
+                               xDesk = xls.app.aLoader.queryInterface (unotmp);
+                               xDesk.terminate();
+                       else
+                               warning ("Error closing xls pointer (UNO)");
+                       endif
+                       return
+               end_try_catch
+
+#      elseif   <other interfaces here>
+               
+       endif
+
+       if (xls.changed && xls.changed < 3)
+               warning (sprintf ("File %s could not be saved. Read-only or in use elsewhere?\nFile pointer preserved.", xls.filename));
+               if (force)
+                       xls = [];
+               endif
+       else
+               xls = [];
+       endif
+
+endfunction