summaryrefslogtreecommitdiffstats
path: root/filters/kspread
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /filters/kspread
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'filters/kspread')
-rw-r--r--filters/kspread/Makefile.am4
-rw-r--r--filters/kspread/applixspread/Makefile.am17
-rw-r--r--filters/kspread/applixspread/applixspreadimport.cc1326
-rw-r--r--filters/kspread/applixspread/applixspreadimport.h79
-rw-r--r--filters/kspread/applixspread/kspread_applixspread_import.desktop68
-rw-r--r--filters/kspread/applixspread/status.html755
-rw-r--r--filters/kspread/csv/DESIGN37
-rw-r--r--filters/kspread/csv/Makefile.am22
-rw-r--r--filters/kspread/csv/README10
-rw-r--r--filters/kspread/csv/TODO5
-rw-r--r--filters/kspread/csv/csvdialog.cpp635
-rw-r--r--filters/kspread/csv/csvdialog.h89
-rw-r--r--filters/kspread/csv/csvexport.cc382
-rw-r--r--filters/kspread/csv/csvexport.h49
-rw-r--r--filters/kspread/csv/csvexportdialog.cpp332
-rw-r--r--filters/kspread/csv/csvexportdialog.h72
-rw-r--r--filters/kspread/csv/csvimport.cc264
-rw-r--r--filters/kspread/csv/csvimport.h35
-rw-r--r--filters/kspread/csv/dialogui.ui554
-rw-r--r--filters/kspread/csv/exportdialogui.ui510
-rw-r--r--filters/kspread/csv/kspread_csv_export.desktop73
-rw-r--r--filters/kspread/csv/kspread_csv_import.desktop72
-rw-r--r--filters/kspread/csv/status.html202
-rw-r--r--filters/kspread/csv/xmltree.cc154
-rw-r--r--filters/kspread/csv/xmltree.h53
-rw-r--r--filters/kspread/dbase/Makefile.am17
-rw-r--r--filters/kspread/dbase/dbase.cpp251
-rw-r--r--filters/kspread/dbase/dbase.h67
-rw-r--r--filters/kspread/dbase/dbaseimport.cc181
-rw-r--r--filters/kspread/dbase/dbaseimport.h38
-rw-r--r--filters/kspread/dbase/kspread_dbase_import.desktop65
-rw-r--r--filters/kspread/dbase/status.html164
-rwxr-xr-xfilters/kspread/dbase/test/birth.dbfbin0 -> 134 bytes
-rw-r--r--filters/kspread/dbase/test/browser.dbfbin0 -> 167 bytes
-rwxr-xr-xfilters/kspread/dbase/test/stability.dbfbin0 -> 161 bytes
-rw-r--r--filters/kspread/excel/Makefile.am15
-rw-r--r--filters/kspread/excel/excelexport.cc66
-rw-r--r--filters/kspread/excel/excelexport.h34
-rw-r--r--filters/kspread/excel/import/Makefile.am17
-rw-r--r--filters/kspread/excel/import/README61
-rw-r--r--filters/kspread/excel/import/excelimport.cc2132
-rw-r--r--filters/kspread/excel/import/excelimport.h45
-rw-r--r--filters/kspread/excel/import/kspread_excel_import.desktop61
-rw-r--r--filters/kspread/excel/kspread_excel_export.desktop61
-rw-r--r--filters/kspread/excel/sidewinder/Makefile.am5
-rw-r--r--filters/kspread/excel/sidewinder/README.Sidewinder28
-rw-r--r--filters/kspread/excel/sidewinder/cell.cpp220
-rw-r--r--filters/kspread/excel/sidewinder/cell.h94
-rw-r--r--filters/kspread/excel/sidewinder/excel.cpp6428
-rw-r--r--filters/kspread/excel/sidewinder/excel.h3250
-rw-r--r--filters/kspread/excel/sidewinder/format.cpp717
-rw-r--r--filters/kspread/excel/sidewinder/format.h761
-rw-r--r--filters/kspread/excel/sidewinder/pole.cpp1354
-rw-r--r--filters/kspread/excel/sidewinder/pole.h177
-rw-r--r--filters/kspread/excel/sidewinder/sheet.cpp450
-rw-r--r--filters/kspread/excel/sidewinder/sheet.h216
-rw-r--r--filters/kspread/excel/sidewinder/swinder.h11
-rw-r--r--filters/kspread/excel/sidewinder/ustring.cpp611
-rw-r--r--filters/kspread/excel/sidewinder/ustring.h385
-rw-r--r--filters/kspread/excel/sidewinder/value.cpp391
-rw-r--r--filters/kspread/excel/sidewinder/value.h290
-rw-r--r--filters/kspread/excel/sidewinder/workbook.cpp135
-rw-r--r--filters/kspread/excel/sidewinder/workbook.h109
-rw-r--r--filters/kspread/gnumeric/Makefile.am21
-rw-r--r--filters/kspread/gnumeric/README30
-rw-r--r--filters/kspread/gnumeric/gnumeric.xsd898
-rw-r--r--filters/kspread/gnumeric/gnumericexport.cc1574
-rw-r--r--filters/kspread/gnumeric/gnumericexport.h63
-rw-r--r--filters/kspread/gnumeric/gnumericimport.cc2207
-rw-r--r--filters/kspread/gnumeric/gnumericimport.h66
-rw-r--r--filters/kspread/gnumeric/kspread_gnumeric_export.desktop73
-rw-r--r--filters/kspread/gnumeric/kspread_gnumeric_import.desktop74
-rw-r--r--filters/kspread/gnumeric/status.html304
-rw-r--r--filters/kspread/html/CHANGELOG11
-rw-r--r--filters/kspread/html/Makefile.am18
-rw-r--r--filters/kspread/html/exportdialog.cc113
-rw-r--r--filters/kspread/html/exportdialog.h63
-rw-r--r--filters/kspread/html/exportwidget.ui310
-rw-r--r--filters/kspread/html/htmlexport.cc475
-rw-r--r--filters/kspread/html/htmlexport.h81
-rw-r--r--filters/kspread/html/kspread_html_export.desktop72
-rw-r--r--filters/kspread/html/status.html173
-rw-r--r--filters/kspread/kexi/Makefile.am22
-rw-r--r--filters/kspread/kexi/kspread_kexi_import.desktop45
-rw-r--r--filters/kspread/kexi/kspread_kexiimport.cc249
-rw-r--r--filters/kspread/kexi/kspread_kexiimport.h85
-rw-r--r--filters/kspread/kexi/kspread_kexiimportdialog.cc236
-rw-r--r--filters/kspread/kexi/kspread_kexiimportdialog.h127
-rw-r--r--filters/kspread/kexi/kspread_kexiimportdialogbase.ui244
-rw-r--r--filters/kspread/latex/BUGS16
-rw-r--r--filters/kspread/latex/Makefile.am2
-rw-r--r--filters/kspread/latex/TODO24
-rw-r--r--filters/kspread/latex/export/Changelog36
-rw-r--r--filters/kspread/latex/export/Makefile.am30
-rw-r--r--filters/kspread/latex/export/cell.cc132
-rw-r--r--filters/kspread/latex/export/cell.h107
-rw-r--r--filters/kspread/latex/export/column.cc66
-rw-r--r--filters/kspread/latex/export/column.h87
-rw-r--r--filters/kspread/latex/export/config.cc92
-rw-r--r--filters/kspread/latex/export/config.h147
-rw-r--r--filters/kspread/latex/export/document.cc66
-rw-r--r--filters/kspread/latex/export/document.h65
-rw-r--r--filters/kspread/latex/export/fileheader.cc320
-rw-r--r--filters/kspread/latex/export/fileheader.h161
-rw-r--r--filters/kspread/latex/export/format.cc203
-rw-r--r--filters/kspread/latex/export/format.h186
-rw-r--r--filters/kspread/latex/export/formula.cc168
-rw-r--r--filters/kspread/latex/export/formula.h111
-rw-r--r--filters/kspread/latex/export/kspread_latex_export.desktop65
-rw-r--r--filters/kspread/latex/export/kspreadlatexexportdiaImpl.cc246
-rw-r--r--filters/kspread/latex/export/kspreadlatexexportdiaImpl.h56
-rw-r--r--filters/kspread/latex/export/latexexport.cc63
-rw-r--r--filters/kspread/latex/export/latexexport.h43
-rw-r--r--filters/kspread/latex/export/latexexportIface.cc45
-rw-r--r--filters/kspread/latex/export/latexexportIface.h43
-rw-r--r--filters/kspread/latex/export/latexexportdia.ui674
-rw-r--r--filters/kspread/latex/export/map.cc79
-rw-r--r--filters/kspread/latex/export/map.h90
-rw-r--r--filters/kspread/latex/export/pen.cc45
-rw-r--r--filters/kspread/latex/export/pen.h86
-rw-r--r--filters/kspread/latex/export/row.cc65
-rw-r--r--filters/kspread/latex/export/row.h87
-rw-r--r--filters/kspread/latex/export/spreadsheet.cc221
-rw-r--r--filters/kspread/latex/export/spreadsheet.h95
-rw-r--r--filters/kspread/latex/export/table.cc414
-rw-r--r--filters/kspread/latex/export/table.h186
-rw-r--r--filters/kspread/latex/export/xmlparser.cc139
-rw-r--r--filters/kspread/latex/export/xmlparser.h79
-rw-r--r--filters/kspread/latex/status.html188
-rw-r--r--filters/kspread/libkspreadexport/KSpreadBaseWorker.cc94
-rw-r--r--filters/kspread/libkspreadexport/KSpreadBaseWorker.h45
-rw-r--r--filters/kspread/libkspreadexport/KSpreadLeader.cc359
-rw-r--r--filters/kspread/libkspreadexport/KSpreadLeader.h105
-rw-r--r--filters/kspread/libkspreadexport/Makefile.am18
-rw-r--r--filters/kspread/opencalc/Makefile.am21
-rw-r--r--filters/kspread/opencalc/kspread_opencalc_export.desktop59
-rw-r--r--filters/kspread/opencalc/kspread_opencalc_import.desktop62
-rw-r--r--filters/kspread/opencalc/opencalcexport.cc1329
-rw-r--r--filters/kspread/opencalc/opencalcexport.h89
-rw-r--r--filters/kspread/opencalc/opencalcimport.cc2826
-rw-r--r--filters/kspread/opencalc/opencalcimport.h119
-rw-r--r--filters/kspread/opencalc/opencalcstyleexport.cc546
-rw-r--r--filters/kspread/opencalc/opencalcstyleexport.h167
-rw-r--r--filters/kspread/opencalc/status.html208
-rw-r--r--filters/kspread/qpro/Makefile.am22
-rw-r--r--filters/kspread/qpro/kspread_qpro_import.desktop74
-rw-r--r--filters/kspread/qpro/libqpro/AUTHORS3
-rw-r--r--filters/kspread/qpro/libqpro/COPYING340
-rw-r--r--filters/kspread/qpro/libqpro/ChangeLog119
-rw-r--r--filters/kspread/qpro/libqpro/INSTALL182
-rw-r--r--filters/kspread/qpro/libqpro/Makefile.am3
-rw-r--r--filters/kspread/qpro/libqpro/NEWS0
-rw-r--r--filters/kspread/qpro/libqpro/README31
-rw-r--r--filters/kspread/qpro/libqpro/TODO11
-rw-r--r--filters/kspread/qpro/libqpro/libqpro.lsm23
-rw-r--r--filters/kspread/qpro/libqpro/qpro/Makefile.am1
-rw-r--r--filters/kspread/qpro/libqpro/qpro/common.h11
-rw-r--r--filters/kspread/qpro/libqpro/qpro/formula.h128
-rw-r--r--filters/kspread/qpro/libqpro/qpro/record.h280
-rw-r--r--filters/kspread/qpro/libqpro/qpro/record_factory.h19
-rw-r--r--filters/kspread/qpro/libqpro/qpro/stream.h72
-rw-r--r--filters/kspread/qpro/libqpro/qpro/tablenames.h23
-rw-r--r--filters/kspread/qpro/libqpro/src/Makefile.am5
-rw-r--r--filters/kspread/qpro/libqpro/src/formula.cc550
-rw-r--r--filters/kspread/qpro/libqpro/src/record.cc665
-rw-r--r--filters/kspread/qpro/libqpro/src/record_factory.cc83
-rw-r--r--filters/kspread/qpro/libqpro/src/stream.cc226
-rw-r--r--filters/kspread/qpro/libqpro/src/tablenames.cc72
-rw-r--r--filters/kspread/qpro/qproformula.cc64
-rw-r--r--filters/kspread/qpro/qproformula.h18
-rw-r--r--filters/kspread/qpro/qproimport.cc263
-rw-r--r--filters/kspread/qpro/qproimport.h55
-rw-r--r--filters/kspread/qpro/status.html178
173 files changed, 46936 insertions, 0 deletions
diff --git a/filters/kspread/Makefile.am b/filters/kspread/Makefile.am
new file mode 100644
index 000000000..4fdcc43f6
--- /dev/null
+++ b/filters/kspread/Makefile.am
@@ -0,0 +1,4 @@
+if compile_filter_KEXI
+KEXIDIR = kexi
+endif
+SUBDIRS = applixspread csv dbase gnumeric latex opencalc html qpro excel $(KEXIDIR)
diff --git a/filters/kspread/applixspread/Makefile.am b/filters/kspread/applixspread/Makefile.am
new file mode 100644
index 000000000..944bdd1bf
--- /dev/null
+++ b/filters/kspread/applixspread/Makefile.am
@@ -0,0 +1,17 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) $(KOFFICE_INCLUDES) $(all_includes)
+
+####### Files
+
+kde_module_LTLIBRARIES = libapplixspreadimport.la
+
+libapplixspreadimport_la_SOURCES = applixspreadimport.cc
+libapplixspreadimport_la_LIBADD = $(KOFFICE_LIBS)
+libapplixspreadimport_la_LDFLAGS = -module $(KDE_PLUGIN)
+noinst_HEADERS = applixspreadimport.h
+
+METASOURCES = AUTO
+
+service_DATA = kspread_applixspread_import.desktop
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/applixspread/applixspreadimport.cc b/filters/kspread/applixspread/applixspreadimport.cc
new file mode 100644
index 000000000..57baedeb9
--- /dev/null
+++ b/filters/kspread/applixspread/applixspreadimport.cc
@@ -0,0 +1,1326 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Enno Bartels <ebartels@nwn.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <qmessagebox.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qptrlist.h>
+#include <applixspreadimport.h>
+#include <kdebug.h>
+#include <math.h>
+#include <KoFilterChain.h>
+#include <kgenericfactory.h>
+
+typedef KGenericFactory<APPLIXSPREADImport, KoFilter> APPLIXSPREADImportFactory;
+K_EXPORT_COMPONENT_FACTORY( libapplixspreadimport, APPLIXSPREADImportFactory( "kofficefilters" ) )
+
+
+APPLIXSPREADImport::APPLIXSPREADImport ( QObject */*parent*/, const char* /*name*/, const QStringList& )
+ : KoFilter()
+{
+}
+
+QString APPLIXSPREADImport::nextLine( QTextStream & stream )
+{
+ QString s = stream.readLine();
+ m_instep += s.length();
+ if (m_instep > m_stepsize)
+ {
+ m_instep = 0;
+ m_progress += 2;
+ emit sigProgress( m_progress );
+ }
+ return s;
+}
+
+KoFilter::ConversionStatus APPLIXSPREADImport::convert( const QCString& from, const QCString& to )
+{
+
+ if (to != "application/x-kspread" || from != "application/x-applixspread")
+ return KoFilter::NotImplemented;
+
+ QFile in (m_chain->inputFile());
+ if (!in.open(IO_ReadOnly))
+ {
+ kdError(30502) << "Unable to open input file!" << endl;
+ in.close();
+ return KoFilter::FileNotFound;
+ }
+
+ QString str;
+ QPtrList<t_mycolor> mcol;
+
+ str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ str += "<!DOCTYPE spreadsheet>\n";
+ str += "<spreadsheet mime=\"application/x-kspread\" editor=\"KSpread\" >\n";
+ str += " <paper format=\"A4\" orientation=\"Portrait\" >\n";
+ str += " <borders right=\"20\" left=\"20\" bottom=\"20\" top=\"20\" />\n";
+ str += " <head/>\n";
+ str += " <foot/>\n";
+ str += " </paper>\n";
+ str += " <locale positivePrefixCurrencySymbol=\"True\" negativeMonetarySignPosition=\"1\" negativePrefixCurrencySymbol=\"True\" fracDigits=\"2\" thousandsSeparator=\" \" dateFormat=\"%A, %e. %B %Y\" timeFormat=\"%H:%M:%S\" monetaryDecimalSymbol=\",\" weekStartsMonday=\"True\" currencySymbol=\"DM\" negativeSign=\"-\" positiveSign=\"\" positiveMonetarySignPosition=\"1\" decimalSymbol=\",\" monetaryThousandsSeparator=\" \" dateFormatShort=\"%d.%m.%Y\" />\n";
+ str += " <map markerColumn=\"1\" activeTable=\"Table1\" markerRow=\"1\" >\n";
+// str += " <table columnnumber=\"0\" borders=\"0\" hide=\"0\" hidezero=\"0\" firstletterupper=\"0\" grid=\"1\" formular=\"0\" lcmode=\"0\" name=\"Tabelle1\" >\n";
+
+
+ // QTextStream
+ QTextStream stream (&in);
+ m_stepsize = in.size()/50;
+ m_instep = 0;
+ m_progress = 0;
+ int pos;
+ char ccol;
+ int irow, icol;
+ QString tabctr ; // Tab control
+ QString mystr, typestr, cellnostr, tabnostr;
+ QStringList typefacetab;
+
+ // QStringList rclist;
+ t_rc my_rc;
+
+
+
+ /**************************************************************************
+ * Read header *
+ **************************************************************************/
+ if (! readHeader (stream)) return KoFilter::StupidError;
+
+
+ while (!stream.atEnd ())
+ {
+ // Read one line
+ mystr = nextLine( stream );
+
+ kdDebug()<<"INPUT : "<<mystr<<endl;
+
+
+ /**********************************************************************
+ * Looking for the colormap *
+ **********************************************************************/
+ if (mystr.startsWith ("COLORMAP") )
+ {
+ readColormap (stream, mcol);
+ }
+
+ /**********************************************************************
+ * Looking for the typeface table *
+ **********************************************************************/
+ else if (mystr.startsWith ("TYPEFACE TABLE") )
+ {
+ readTypefaceTable (stream, typefacetab);
+ }
+
+ /**********************************************************************
+ * Looking for some View-Informations *
+ **********************************************************************/
+ else if (mystr.startsWith ("View Start, Name:") )
+ {
+ readView (stream, mystr, my_rc);
+ }
+
+
+ /**********************************************************************
+ * Detect ( at the first place of the Linie *
+ **********************************************************************/
+ else if (mystr[0] == '(')
+ {
+ int fg=-1; // fg = foregound
+
+ // Delete '('
+ mystr.remove (0, 1);
+
+ int alllenght;
+ QString mystrn;
+
+ // Remember lenght of the string
+ alllenght = mystr.length ();
+ if (alllenght >= 80-1)
+ {
+ kdDebug()<< " Line >= 80 chars \n";
+ int ok = true;
+ do
+ {
+ pos = in.at ();
+ mystrn = nextLine( stream );
+ if (mystrn[0] == ' ')
+ {
+ mystrn.remove (0, 1);
+ mystr += mystrn;
+ }
+ else
+ {
+ in.at (pos);
+ ok = false;
+ }
+ }
+ while (ok == true);
+
+ }
+
+
+ // Search for ')'
+ pos = mystr.find (')');
+ typestr = mystr.left (pos);
+
+
+ // Delete typeformat infos incl. Space
+ mystr.remove (0, pos+1);
+ // alllenght = alllenght - pos - 1;
+
+ // Search for ':'
+ pos = mystr.find (':');
+
+ // Copy cellnumber informations
+ cellnostr = mystr.left (pos);
+
+ // Delete cellnumber informations
+ mystr.remove (0, pos+1);
+ // alllenght = alllenght - pos - 1;
+
+
+ // Split Table and Cell Number
+ pos = cellnostr.find ('!');
+
+ // Copy tabnumber informations
+ tabnostr = cellnostr.left (pos);
+
+ // Delete cellnumber informations
+ cellnostr.remove (0, pos+1);
+
+ int len = cellnostr.length ();
+ char tmp[300], tmp1[300];
+ int leni;
+
+
+
+ pos = cellnostr.find (QRegExp ("[0-9]"));
+ kdDebug()<<" findpos :"<<pos<<endl;
+
+
+
+ QString rowstr;
+ bool ok;
+ int bla;
+ rowstr = cellnostr.mid (pos, cellnostr.length()-pos);
+ irow = rowstr.toInt(&ok);
+
+ kdDebug()<<" findpos :"<< rowstr<<" "<<irow<<endl;
+ sscanf (cellnostr.latin1(), "%299s%d",tmp, &bla);
+ sprintf (tmp1, "%d", irow);
+ leni = strlen (tmp1);
+ QString cellcolstr;
+ cellcolstr = cellnostr;
+ cellcolstr.remove (cellcolstr.length()-leni, leni);
+
+ kdDebug()<<" Info: length :"<<len<<" cellnostr :"<<cellnostr<<" tmp :"<<tmp<<" irow :"<<irow<<" cellcolstr :"<<cellcolstr<<endl;
+
+ // Transformat ascii column to int column
+ icol = translateColumnNumber (cellcolstr);
+
+
+ // sscanf (cellnostr.latin1(), "%c%d",&ccol, &irow);
+
+ // Transformat ascii column to int column
+ // icol = ccol - 64;
+
+ // Remove first whitespace
+ mystr.remove (0, 1);
+ tabnostr.remove (0, 1);
+
+
+ // Replace part for this characters: <, >, &
+ mystr.replace (QRegExp ("&"), "&amp;");
+ mystr.replace (QRegExp ("<"), "&lt;");
+ mystr.replace (QRegExp (">"), "&gt;");
+
+
+ // Replace part for Applix Characters
+ int foundSpecialCharakter;
+ QChar newchar;
+
+ do
+ {
+ // initialize
+ foundSpecialCharakter = false;
+
+ pos = mystr.find ("^");
+
+ // is there a special character ?
+ if (pos > -1 )
+ {
+ // i have found a special character !
+ foundSpecialCharakter = true;
+
+ // translate the applix special character
+ newchar = specCharfind (mystr[pos+1], mystr[pos+2]);
+
+ // replace the character
+ mystr.replace (pos, 3, newchar);
+ }
+
+ }
+ while (foundSpecialCharakter == true);
+
+
+ // examine the typestring
+ // splitt typestring in 3 parts by an |
+ QString typeFormStr;
+ QString typeCharStr;
+ QString typeCellStr;
+
+ int pos1 = typestr.find ("|");
+ int pos2 = typestr.findRev ("|");
+
+
+ typeFormStr = typestr.left (pos1);
+
+ typeCharStr = typestr.mid (pos1+1, pos2 - pos1 - 1);
+
+ typeCellStr = typestr.right (typestr.length() - pos2 - 1);
+
+ // Is it a new table
+ if (tabctr != tabnostr)
+ {
+ // is it not the first table
+ if (!(tabctr.isNull())) str += " </table>\n";
+
+ str += " <table columnnumber=\"0\" borders=\"0\" hide=\"0\" hidezero=\"0\" firstletterupper=\"0\" grid=\"1\" formular=\"0\" lcmode=\"0\" name=\"";
+ str += tabnostr;
+ str += "\" >\n";
+
+ tabctr = tabnostr;
+
+ // Searching for the rowcol part and adding to the hole string
+ pos = my_rc.tabname.findIndex (tabnostr);
+ if (pos > -1) str += my_rc.rc[pos];
+ }
+
+ kdDebug()<<" Data : Text :"<<mystr<<" tab :"<<tabnostr<<" "<< cellnostr <<" " <<ccol<<" " << irow<<" "<< typeFormStr<<" " <<typeCharStr<<" " <<typeCellStr<<endl;
+
+
+ /********************************************************************
+ * examine charakter format String, splitt it up in basic parts *
+ ********************************************************************/
+ QStringList typeCharList;
+ int bold=0, italic=0, underline=0, nn=0, fontsize=12, fontnr=-1;
+
+ typeCharList = QStringList::split (',', typeCharStr);
+
+ for (QStringList::Iterator it = typeCharList.begin();
+ it != typeCharList.end(); ++it )
+ {
+ // Output
+ kdDebug()<<" Char ("<<nn<<" ) >"<<*it<<"< "<<endl;
+ nn++;
+
+ if ((*it) == "B")
+ {
+ kdDebug()<<" bold\n";
+ bold = 1;
+ }
+ else if ((*it) == "I")
+ {
+
+ kdDebug()<<" = italic\n";
+ italic = 1;
+ }
+ else if ((*it) == "U")
+ {
+ kdDebug()<<" = underline\n";
+ underline = 1;
+ }
+ else if ((*it).startsWith("FG") )
+ {
+ sscanf ((*it).latin1(), "FG%d", &fg);
+ kdDebug()<<" = Colornr "<< fg<<endl;
+ }
+ else if ((*it).startsWith("TF") )
+ {
+ sscanf ((*it).latin1(), "TF%d", &fontnr);
+ kdDebug()<<" = Font :"<<fontnr<<" "<<typefacetab[fontnr]<<endl;
+ }
+ else if ((*it).startsWith("P") )
+ {
+ sscanf ((*it).latin1(), "P%d", &fontsize);
+ kdDebug()<<" = Fontsize "<<fontsize<<endl;
+ }
+ else
+ {
+
+ kdDebug()<<" = ???\n";
+ }
+ }
+ kdDebug()<<""<<endl;
+
+
+
+ /********************************************************************
+ * examine pos format String, splitt it up in basic parts *
+ ********************************************************************/
+ QStringList typeFormList;
+ int align = 0, valign=0;
+
+ typeFormList = QStringList::split (',', typeFormStr);
+ nn=0;
+ for (QStringList::Iterator it = typeFormList.begin(); it != typeFormList.end(); ++it )
+ {
+ // Output
+ //kdDebug()<< " Type (%2d) >%s< ",
+ // nn, (*it).latin1() );
+ nn++;
+ // Grep horizontal alignment
+ if ( (*it) == "1")
+ {
+ kdDebug()<< " = left align\n";
+ align = 1; // left
+ }
+ else if ( (*it) == "2")
+ {
+ kdDebug()<< " = right align\n";
+ align = 3; // right
+ }
+ else if ( (*it) == "3")
+ {
+ kdDebug()<< " = center align\n";
+ align = 2; // center
+ }
+
+ // Grep verticale alignment
+ else if ( (*it) == "VT")
+ {
+ kdDebug()<<" = top valign\n";
+ valign = 1; // top
+ }
+ else if ( (*it) == "VC")
+ {
+ kdDebug()<<" = center valign\n";
+ valign = 0; // center - default (2)
+ }
+ else if ( (*it) == "VB")
+ {
+ kdDebug()<<" = bottom valign\n";
+ valign = 3; // bottom
+ }
+ else
+ {
+ kdDebug()<<" = ???\n";
+ }
+ }
+
+
+ /********************************************************************
+ * examine cell format String, splitt it up in basic parts *
+ ********************************************************************/
+ QStringList typeCellList;
+ int topPenWidth=0, bottomPenWidth=0, leftPenWidth = 0, rightPenWidth = 0, fg_bg=-1;
+ int topPenStyle=0, bottomPenStyle=0, leftPenStyle = 0, rightPenStyle = 0;
+ int brushstyle=0, brushcolor=1;
+ int topbrushstyle=0, topbrushcolor=1, topfg_bg=1;
+ int leftbrushstyle=0, leftbrushcolor=1, leftfg_bg=1;
+ int rightbrushstyle=0, rightbrushcolor=1, rightfg_bg=1;
+ int bottombrushstyle=0, bottombrushcolor=1, bottomfg_bg=1;
+
+ typeCellList = QStringList::split (',', typeCellStr);
+ nn=0;
+ for ( QStringList::Iterator it = typeCellList.begin(); it != typeCellList.end(); ++it )
+ {
+ // Output
+ printf (" Cell (%2d) >%s< ",
+ nn, (*it).latin1() );
+ nn++;
+
+ if ((*it)[0] == 'T')
+ {
+ kdDebug()<<" = top \n";
+ transPenFormat ((*it), &topPenWidth, &topPenStyle);
+
+ if ((*it).length() > 2)
+ {
+ (*it).remove (0, 2);
+ filterSHFGBG ((*it), &topbrushstyle, &topbrushcolor, &topfg_bg);
+ }
+
+ }
+
+ else if ( (*it)[0] == 'B')
+ {
+ kdDebug()<<" = bottom \n";
+ transPenFormat ((*it), &bottomPenWidth, &bottomPenStyle);
+
+ if ((*it).length() > 2)
+ {
+ (*it).remove (0, 2);
+ filterSHFGBG ((*it), &bottombrushstyle, &bottombrushcolor, &bottomfg_bg);
+ }
+ }
+
+ else if ( (*it)[0] == 'L')
+ {
+ kdDebug()<<" = left \n";
+ transPenFormat ((*it), &leftPenWidth, &leftPenStyle);
+
+ if ((*it).length() > 2)
+ {
+ (*it).remove (0, 2);
+ filterSHFGBG ((*it), &leftbrushstyle, &leftbrushcolor, &leftfg_bg);
+ }
+ }
+
+ else if ( (*it)[0] == 'R')
+ {
+ kdDebug()<<" = right \n";
+ transPenFormat ((*it), &rightPenWidth, &rightPenStyle);
+
+ if ((*it).length() > 2)
+ {
+ (*it).remove (0, 2);
+ filterSHFGBG ((*it), &rightbrushstyle, &rightbrushcolor, &rightfg_bg);
+ }
+ }
+
+ else if ( ((*it).startsWith ("SH")) || ((*it).startsWith ("FG")) ||
+ ((*it).startsWith ("BG")) )
+ {
+ kdDebug()<<" = \n";
+ filterSHFGBG ((*it), &brushstyle, &fg_bg, &brushcolor);
+ }
+
+ else
+ {
+ kdDebug()<<" = ???\n";
+ }
+
+ }
+
+
+
+
+
+ QString col;
+
+ // create kspread fileformat output
+ str += " <cell row=\"" + QString::number (irow) + "\"";
+ str += " column=\"" + QString::number (icol) + "\">\n";
+ if (bold == 1 || italic == 1 || underline == 1 ||
+ align != 0 || valign != 0 ||
+ topPenStyle != 0 || bottomPenStyle != 0 ||
+ leftPenStyle != 0 || rightPenStyle != 0 || fg !=-1 || fg_bg != -1 ||
+ fontsize != 12 || brushstyle != 0 || fontnr != -1)
+ {
+ str += " <format";
+ if (brushstyle != 0)
+ {
+ str += " brushstyle=\"" + QString::number(brushstyle) + "\" ";
+ str += " brushcolor=\"";
+ str += writeColor (mcol.at(brushcolor));
+ str += "\"";
+ }
+
+ if (align != 0) str += " align=\"" + QString::number(align) + "\" ";
+ if (valign != 0) str += " alignY=\"" + QString::number(valign) + "\" ";
+ if (fg_bg != -1)
+ {
+ str += " bgcolor=\"";
+ str += writeColor (mcol.at(fg_bg));
+ str += "\" ";
+ }
+ str += ">\n";
+
+ // Font color
+ if (fg != -1)
+ {
+ str += " <pen width=\"0\" style=\"1\" color=\"";
+ str += writeColor (mcol.at(fg));
+ str += "\" />\n";
+ }
+
+ // Left border
+ if (leftPenWidth > 0)
+ {
+ str += " <left-border>\n";
+ col = writeColor (mcol.at(leftfg_bg));
+ writePen (str, leftPenWidth, leftPenStyle, col);
+ str += " </left-border>\n";
+ }
+
+ // Right border
+ if (rightPenWidth > 0)
+ {
+ str += " <right-border>\n";
+ col = writeColor (mcol.at(rightfg_bg));
+ writePen (str, rightPenWidth, rightPenStyle, col);
+ str += " </right-border>\n";
+ }
+
+ // Bottom border
+ if (bottomPenWidth > 0)
+ {
+ str += " <bottom-border>\n";
+ col = writeColor (mcol.at(bottomfg_bg));
+ writePen (str, bottomPenWidth, bottomPenStyle, col);
+ str += " </bottom-border>\n";
+ }
+
+ // Top border
+ if (topPenWidth > 0)
+ {
+ str += " <top-border>\n";
+ col = writeColor (mcol.at(topfg_bg));
+ writePen (str, topPenWidth, topPenStyle, col);
+ str += " </top-border>\n";
+ }
+
+ // Font (size and family)
+ if ((fontsize != 12) || (fontnr != -1))
+ {
+ str += " <font ";
+ // Fontsize
+ if (fontsize != 12)
+ {
+ str += "size=\"";
+ str += QString::number (fontsize);
+ str += "\" ";
+ }
+ // Fontfamily
+ if (fontnr != -1)
+ {
+ str += "family=\"";
+ str += typefacetab[fontnr].latin1();
+ str += "\" ";
+ }
+ str += "weight=\"0\"";
+
+ if (italic == 1) str += " italic=\"yes\"";
+ if (bold == 1) str += " bold=\"yes\"";
+ if (underline == 1) str += " underline=\"yes\"";
+
+ str +=" />\n";
+ }
+ str += " </format>\n";
+ }
+ str += " <text>" + mystr + "</text>\n";
+ str += " </cell>\n";
+ }
+
+ }
+ emit sigProgress(100);
+
+ str += " </table>\n";
+ str += " </map>\n";
+ str += "</spreadsheet>\n";
+// str += "</DOC>\n";
+
+ kdDebug ()<<"Text "<< str<<endl;
+
+ KoStoreDevice* out=m_chain->storageFile( "root", KoStore::Write );
+
+ if (!out)
+ {
+ kdError(38000/*30502*/) << "Unable to open output file!" << endl;
+ in.close ();
+ return KoFilter::StorageCreationError;
+ }
+
+ QCString cstring = str.utf8();
+ out->writeBlock ( cstring, cstring.length() );
+
+ in.close ();
+ return KoFilter::OK;
+}
+
+
+
+
+/******************************************************************************
+ * function: specCharfind *
+ ******************************************************************************/
+QChar
+APPLIXSPREADImport::specCharfind (QChar a, QChar b)
+{
+ QChar chr;
+
+ if ( (a == 'n') && (b == 'p') ) chr = '';
+
+
+ else if ( (a == 'n') && (b == 'c') ) chr = '';
+ else if ( (a == 'p') && (b == 'c') ) chr = '';
+
+ else if ( (a == 'n') && (b == 'd') ) chr = '';
+ else if ( (a == 'p') && (b == 'd') ) chr = '';
+
+ else if ( (a == 'n') && (b == 'e') ) chr = '';
+ else if ( (a == 'p') && (b == 'e') ) chr = '';
+
+ else if ( (a == 'n') && (b == 'f') ) chr = '';
+ else if ( (a == 'p') && (b == 'f') ) chr = '';
+
+ else if ( (a == 'p') && (b == 'g') ) chr = '';
+ else if ( (a == 'n') && (b == 'g') ) chr = '';
+
+
+
+ else if ( (a == 'n') && (b == 'j') ) chr = '';
+ else if ( (a == 'p') && (b == 'j') ) chr = '';
+
+ else if ( (a == 'n') && (b == 'k') ) chr = '';
+ else if ( (a == 'p') && (b == 'k') ) chr = '';
+
+ else if ( (a == 'n') && (b == 'l') ) chr = '';
+ else if ( (a == 'p') && (b == 'l') ) chr = '';
+
+ else if ( (a == 'p') && (b == 'm') ) chr = '';
+ else if ( (a == 'n') && (b == 'm') ) chr = '';
+
+
+
+ else if ( (a == 'm') && (b == 'a') ) chr = '';
+ else if ( (a == 'o') && (b == 'a') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'b') ) chr = '';
+ else if ( (a == 'o') && (b == 'b') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'c') ) chr = '';
+ else if ( (a == 'o') && (b == 'c') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'd') ) chr = '';
+ else if ( (a == 'o') && (b == 'd') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'e') ) chr = '';
+ else if ( (a == 'o') && (b == 'e') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'f') ) chr = '';
+ else if ( (a == 'o') && (b == 'f') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'g') ) chr = '';
+ else if ( (a == 'o') && (b == 'g') ) chr = '';
+
+
+
+ else if ( (a == 'm') && (b == 'i') ) chr = '';
+ else if ( (a == 'o') && (b == 'i') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'j') ) chr = '';
+ else if ( (a == 'o') && (b == 'j') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'k') ) chr = '';
+ else if ( (a == 'o') && (b == 'k') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'l') ) chr = '';
+ else if ( (a == 'o') && (b == 'l') ) chr = '';
+
+
+
+
+
+
+ else if ( (a == 'm') && (b == 'm') ) chr = '';
+ else if ( (a == 'o') && (b == 'm') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'n') ) chr = '';
+ else if ( (a == 'o') && (b == 'n') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'o') ) chr = '';
+ else if ( (a == 'o') && (b == 'o') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'p') ) chr = '';
+ else if ( (a == 'o') && (b == 'p') ) chr = '';
+
+
+ else if ( (a == 'n') && (b == 'b') ) chr = '';
+ else if ( (a == 'p') && (b == 'b') ) chr = '';
+
+
+ else if ( (a == 'k') && (b == 'c') ) chr = '';
+ else if ( (a == 'k') && (b == 'j') ) chr = '';
+ else if ( (a == 'l') && (b == 'f') ) chr = '';
+ else if ( (a == 'n') && (b == 'i') ) chr = '';
+ else if ( (a == 'p') && (b == 'i') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'j') ) chr = '';
+ else if ( (a == 'l') && (b == 'c') ) chr = '';
+ else if ( (a == 'l') && (b == 'd') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'm') ) chr = '';
+ else if ( (a == 'l') && (b == 'n') ) chr = '';
+ else if ( (a == 'l') && (b == 'o') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'a') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'o') ) chr = '';
+ else if ( (a == 'k') && (b == 'h') ) chr = '';
+ else if ( (a == 'k') && (b == 'd') ) chr = '';
+
+ else if ( (a == 'p') && (b == 'a') ) chr = '';
+ else if ( (a == 'n') && (b == 'a') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'l') ) chr = '';
+ else if ( (a == 'k') && (b == 'l') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'k') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'h') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'b') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'e') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'b') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'p') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'f') ) chr = '';
+
+ else if ( (a == 'p') && (b == 'o') ) chr = '';
+ else if ( (a == 'n') && (b == 'o') ) chr = '';
+
+ else if ( (a == 'n') && (b == 'n') ) chr = '';
+ else if ( (a == 'p') && (b == 'n') ) chr = '';
+ else if ( (a == 'p') && (b == 'p') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'k') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'm') ) chr = '';
+ else if ( (a == 'p') && (b == 'h') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'g') ) chr = '|';
+
+ else if ( (a == 'l') && (b == 'e') ) chr = '\'';
+
+ else if ( (a == 'k') && (b == 'i') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'n') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'p') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'g') ) chr = '';
+
+ else if ( (a == 'l') && (b == 'i') ) chr = '';
+
+ else if ( (a == 'm') && (b == 'h') ) chr = '';
+ else if ( (a == 'o') && (b == 'h') ) chr = '';
+
+ else if ( (a == 'n') && (b == 'h') ) chr = '';
+
+ else if ( (a == 'k') && (b == 'a') ) chr = '';
+
+ else if ( (a == 'a') && (b == 'j') ) chr = '!';
+
+ else chr = '#';
+
+ return chr;
+}
+
+
+
+/******************************************************************************
+ * function: writePen *
+ ******************************************************************************/
+void
+APPLIXSPREADImport::writePen (QString &str, int penwidth, int penstyle, QString framecolor)
+{
+ str += " <pen width=\"";
+
+ // width of the pen
+ str += QString::number (penwidth);
+ str += "\" style=\"";
+
+ // style of the pen
+ str += QString::number (penstyle);
+ str += "\" color=\"";
+
+ // color of the pen
+ str += framecolor;
+ str += "\" />\n";
+
+}
+
+
+
+/******************************************************************************
+ * function: writeColor *
+ ******************************************************************************/
+QString
+APPLIXSPREADImport::writeColor (t_mycolor *mc)
+{
+ char rgb[20];
+
+// printf (" WriteColor: <%d>-<%d>-<%d> <%d>-<%d>-<%d>-<%d>\n",
+// mc->r, mc->g, mc->b,
+// mc->c, mc->m, mc->y, mc->k);
+
+ sprintf (rgb, "#%02X%02X%02X", mc->r, mc->g, mc->b);
+ QString bla = rgb;
+
+
+ return bla;
+}
+
+
+
+
+/******************************************************************************
+ * function: readTypefaceTable *
+ ******************************************************************************/
+void
+APPLIXSPREADImport::readTypefaceTable (QTextStream &stream, QStringList &typefacetab)
+{
+ int tftabCounter=0, ok;
+ QString mystr;
+
+ // Read the colormap
+ kdDebug()<<"Reading typeface table: \n";
+
+ ok = true;
+ do
+ {
+ mystr = nextLine( stream );
+ if (mystr == "END TYPEFACE TABLE" ) ok = false;
+ else
+ {
+ //printf (" %2d: <%s>\n", tftabCounter, mystr.latin1());
+ typefacetab.append(mystr);
+ tftabCounter++;
+ }
+ }
+ while (ok == true );
+
+ kdDebug()<<"... done \n";
+}
+
+
+
+/******************************************************************************
+ * function: readColormap *
+ ******************************************************************************/
+void
+APPLIXSPREADImport::readColormap (QTextStream &stream, QPtrList<t_mycolor> &mcol)
+{
+ int contcount, ok, pos;
+
+ QString colstr, mystr;
+ kdDebug ()<<"Reading colormap: \n";
+
+ ok = true;
+
+ do
+ {
+
+ mystr = nextLine( stream );
+ mystr.stripWhiteSpace ();
+
+ if (mystr == "END COLORMAP") ok = false;
+ else
+ {
+ kdDebug()<<" -> "<< mystr<<endl;
+
+ // Count the number of whitespaces
+ contcount = mystr.contains (' ');
+ kdDebug()<< "contcount: "<< contcount<<endl;
+ contcount -= 5;
+
+ // Begin off interest
+ pos = mystr.find (" 0 ");
+
+ // get colorname
+ colstr = mystr.left (pos);
+ mystr.remove (0, pos+1);
+ mystr.stripWhiteSpace ();
+
+ t_mycolor *tmc = new t_mycolor;
+
+ // get sub colors
+ pos = sscanf (mystr.latin1(), "0 %d %d %d %d 0",
+ &tmc->c, &tmc->m, &tmc->y, &tmc->k);
+
+ printf (" - <%-20s> <%-15s> <%3d> <%3d> <%3d> <%3d> pos: %d\n",
+ mystr.latin1(),
+ colstr.latin1(),
+ tmc->c, tmc->m, tmc->y, tmc->k, pos);
+
+ // Color transformation cmyk -> rgb
+ tmc->r = 255 - (tmc->c + tmc->k);
+ if (tmc->r < 0) tmc->r = 0;
+
+ tmc->g = 255 - (tmc->m + tmc->k);
+ if (tmc->g < 0) tmc->g = 0;
+
+ tmc->b = 255 - (tmc->y + tmc->k);
+ if (tmc->b < 0) tmc->b = 0;
+
+ mcol.append (tmc);
+ }
+
+ }
+ while (ok == true );
+
+ kdDebug()<< "... done "<< mcol.count()<<endl;
+
+
+ t_mycolor *emp;
+ for (emp=mcol.first(); emp != 0; emp=mcol.next() )
+ {
+ printf (" c:%3d m:%3d y:%3d k:%3d r:%3d g:%3d b:%3d\n",
+ emp->c, emp->m, emp->y, emp->k, emp->r, emp->g, emp->b);
+ }
+}
+
+
+
+
+/******************************************************************************
+ * function: readColormap *
+ ******************************************************************************/
+void
+APPLIXSPREADImport::readView (QTextStream &stream, QString instr, t_rc &rc)
+{
+ QString rowcolstr;
+ QString mystr, tabname;
+ int ok;
+
+ kdDebug()<<"Reading View\n";
+
+ tabname = instr;
+
+ tabname.remove (0, 19);
+ tabname.remove (tabname.length()-2, 2);
+ kdDebug()<< " - Table name: "<< tabname<<endl;
+
+ ok = true;
+ do
+ {
+ mystr = nextLine( stream );
+
+ kdDebug()<<" "<< mystr<<endl;
+ if (mystr.startsWith ("View End, Name:")) ok = false;
+ else
+ {
+ // COLUMN Widths
+ if (mystr.startsWith ("View Column Widths"))
+ {
+ kdDebug()<< " - Column Widths\n";
+ mystr.remove (0, 20);
+ kdDebug()<< " "<<mystr<<endl;
+
+ int colwidth, icolumn;
+ char ccolumn;
+
+ // loop
+ QStringList ColumnList;
+ ColumnList = QStringList::split (' ', mystr);
+
+ for ( QStringList::Iterator it = ColumnList.begin(); it != ColumnList.end(); ++it )
+ {
+
+ sscanf ((*it).latin1(), "%c:%d", &ccolumn, &colwidth);
+ int len = (*it).length ();
+ int pos = (*it).find (":");
+ (*it).remove (pos, len-pos);
+
+ printf( " >%s<- -<%c><%d> \n", (*it).latin1(), ccolumn, colwidth);
+
+ // Transformat ascii column to int column
+ icolumn = translateColumnNumber (*it);
+
+ //icolumn = ccolumn - 64;
+ // Translate the column width right from applix to kspread
+ icolumn = icolumn * 5;
+
+
+ rowcolstr += " <column width=\"";
+ rowcolstr += QString::number (colwidth);
+ rowcolstr += "\" column=\"";
+ rowcolstr += QString::number (icolumn);
+ rowcolstr += "\" >\n";
+ rowcolstr += " <format/>\n";
+ rowcolstr += " </column>\n";
+ }
+ }
+
+ // ROW Heights
+ else if (mystr.startsWith ("View Row Heights"))
+ {
+ kdDebug()<< " - Row Heights\n";
+ mystr.remove (0, 17);
+ kdDebug()<<" "<< mystr<<endl;
+
+ int irow, rowheight;
+
+ // loop
+ QStringList RowList;
+ RowList = QStringList::split (' ', mystr);
+
+ for ( QStringList::Iterator it = RowList.begin(); it != RowList.end(); ++it )
+ {
+ sscanf ((*it).latin1(), " %d:%d",
+ &irow, &rowheight);
+ printf (" row: %2d height: %2d\n", irow, rowheight);
+ if (rowheight > 32768) rowheight -= 32768;
+ printf (" height: %2d\n", rowheight);
+ rowcolstr += " <row row=\"";
+ rowcolstr += QString::number (irow);
+ rowcolstr += "\" height=\"";
+ rowcolstr += QString::number (rowheight);
+ rowcolstr += "\" >\n";
+ rowcolstr += " <format/>\n";
+ rowcolstr += " </row>\n";
+ }
+
+
+ }
+ } // else != END COLORMAP
+ }
+ while (ok == true );
+
+ // tabname append to my list
+ // tabname append to my list
+ rc.tabname.append (tabname);
+ rc.rc.append (rowcolstr);
+
+ printf ("%s %s\n", tabname.latin1(),
+ rowcolstr.latin1());
+
+ printf ("...done \n\n");
+}
+
+
+
+
+
+/******************************************************************************
+ * function: filterSHFGBG *
+ ******************************************************************************/
+void
+APPLIXSPREADImport::filterSHFGBG (QString it, int *style, int *bgcolor,
+ int *fgcolor)
+{
+ QString tmpstr;
+ int pos;
+ int m2=0, m3=0;
+
+ // filter SH = Brushstyle Background
+ pos = it.find ("SH");
+ if (pos > -1)
+ {
+ tmpstr = it;
+ if (pos > 0) tmpstr.remove(0, pos);
+ pos = sscanf (tmpstr.latin1(), "SH%d",
+ style);
+
+ printf ("style: %d(%d) ",
+ *style, pos);
+ }
+
+
+ // filter FG = FGCOLOR
+ pos = it.find ("FG");
+ if (pos > -1)
+ {
+ tmpstr = it;
+ if (pos > 0) tmpstr.remove(0, pos);
+ pos = sscanf (tmpstr.latin1(), "FG%d",
+ fgcolor);
+ printf ("fg: %d(%d) ",
+ *fgcolor, pos);
+ m2=1;
+ }
+
+
+ // filter BG = BGCOLOR
+ pos = it.find ("BG");
+ if (pos > -1)
+ {
+ tmpstr = it;
+ if (pos > 0) tmpstr.remove(0, pos);
+ pos = sscanf (tmpstr.latin1(), "BG%d",
+ bgcolor);
+ printf ("bgcolor: %d(%d) ",
+ *bgcolor, pos);
+ m3=1;
+ }
+
+
+ printf ("\n");
+
+
+ // corrent the bgcolor to the fgcolor if the background is plain
+ if ((*style == 8) && (m2 == 1) && (m3 == 0))
+ {
+ *bgcolor = *fgcolor;
+ }
+
+
+ // Translate brushstyle to kspread brushstyle
+ if (*style != 0)
+ {
+ if (*style == 1) *style = 0;
+ else if (*style == 2) *style = 7;
+ else if (*style == 3) *style = 0;
+ else if (*style == 4) *style = 4;
+ else if (*style == 5) *style = 3;
+ else if (*style == 6) *style = 2;
+ else if (*style == 7) *style = 0;
+ else if (*style == 8) *style = 0;
+ else if (*style == 9) *style = 10;
+ else if (*style == 10) *style = 9;
+ else if (*style == 11) *style = 11;
+ else if (*style == 12) *style = 12;
+ else if (*style == 13) *style = 13;
+ else if (*style == 14) *style = 14;
+ else if (*style == 15) *style = 0;
+ else if (*style == 16) *style = 0;
+ else if (*style == 17) *style = 0;
+ else if (*style == 18) *style = 0;
+ else if (*style == 19) *style = 0;
+ }
+}
+
+
+
+/******************************************************************************
+ * function: filterSHFGBG *
+ ******************************************************************************/
+void
+APPLIXSPREADImport::transPenFormat (QString it, int *PenWidth, int *PenStyle)
+{
+
+ if ( it[1] == '1' )
+ {
+ *PenWidth = 1;
+ *PenStyle = 1;
+ }
+
+ else if ( it[1] == '2' )
+ {
+ *PenWidth = 2;
+ *PenStyle = 1;
+ }
+
+ else if ( it[1] == '3' )
+ {
+ *PenWidth = 3;
+ *PenStyle = 1;
+ }
+
+ else if ( it[1] == '4' )
+ {
+ *PenWidth = 1;
+ *PenStyle = 3;
+ }
+
+ else if ( it[1] == '5' )
+ {
+ *PenWidth = 5;
+ *PenStyle = 1;
+ }
+
+ printf ("frame (w:%d - s:%d) \n", *PenWidth, *PenStyle);
+}
+
+
+
+
+/******************************************************************************
+ * function: readHeader *
+ ******************************************************************************/
+int
+APPLIXSPREADImport::readHeader (QTextStream &stream)
+{
+ QString mystr;
+ int vers[3] = { 0, 0, 0 };
+ int rueck;
+
+
+ // Read Headline
+ mystr = nextLine (stream);
+ rueck = sscanf (mystr.latin1(),
+ "*BEGIN SPREADSHEETS VERSION=%d/%d ENCODING=%dBIT",
+ &vers[0], &vers[1], &vers[2]);
+ printf ("Versions info: %d %d %d\n", vers[0], vers[1], vers[2]);
+
+ // Check the headline
+ if (rueck <= 0)
+ {
+ printf ("Header not correkt - May be it is not an applixspreadsheet file\n");
+ printf ("Headerline: <%s>\n", mystr.latin1());
+
+ QMessageBox::critical (0L, "Applix spreadsheet header problem",
+ QString ("The Applix Spreadsheet header is not correct. "
+ "May be it is not an applix spreadsheet file! <BR>"
+ "This is the header line I did read:<BR><B>%1</B>").arg(mystr.latin1()),
+ "Okay");
+
+
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+
+
+/******************************************************************************
+ * function: translateRowNumber *
+ ******************************************************************************/
+int
+APPLIXSPREADImport::translateColumnNumber (QString colstr)
+{
+ int icol=0;
+ int p, x, len;
+
+
+ len = colstr.length ();
+ p = len-1;
+ x = 1;
+
+ printf ("HI 0 len:%d\n", len );
+ while ((p >= 0))
+ {
+ printf ("HI 1 x:%d p:%d char:<%c>\n", x, p, colstr[p].latin1());
+ // Upper chars
+ if ((colstr[p] >= 'A') && (colstr[p] <= 'Z'))
+ {
+ kdDebug ()<<" UPPER\n";
+ icol = icol + ((int)pow ((double)x, 26) * (colstr[p].latin1() - 'A' + 1) );
+ x++;
+ }
+ // lower chars
+ else if ((colstr[p] >= 'a') && (colstr[p] <= 'z'))
+ {
+ kdDebug()<<" lower\n";
+ icol = icol + ((int)pow ((double)x, 26) * (colstr[p].latin1() - 'a' + 1) );
+ x++;
+ }
+ p--;
+ kdDebug ()<< "HI 2\n";
+
+ }
+
+ printf ("translateColumnNumber : <%s> -> %d\n", colstr.latin1(), icol);
+ return icol;
+}
+
+#include <applixspreadimport.moc>
diff --git a/filters/kspread/applixspread/applixspreadimport.h b/filters/kspread/applixspread/applixspreadimport.h
new file mode 100644
index 000000000..31452e00f
--- /dev/null
+++ b/filters/kspread/applixspread/applixspreadimport.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Enno Bartels <ebartels@nwn.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef APPLIXSPREADIMPORT_H
+#define APPLIXSPREADIMPORT_H
+
+#include <qstring.h>
+#include <qfile.h>
+#include <qobject.h>
+#include <qtextstream.h>
+#include <qptrlist.h>
+
+#include <KoFilter.h>
+#include <KoStore.h>
+
+typedef struct
+{
+ int r;
+ int g;
+ int b;
+
+ int c;
+ int m;
+ int y;
+ int k;
+} t_mycolor;
+
+typedef struct
+{
+ QStringList tabname;
+ QStringList rc;
+} t_rc;
+
+
+class APPLIXSPREADImport : public KoFilter {
+
+ Q_OBJECT
+
+public:
+ APPLIXSPREADImport ( QObject *parent, const char* name, const QStringList& );
+ virtual ~APPLIXSPREADImport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+
+protected:
+ QString nextLine (QTextStream &);
+ QChar specCharfind (QChar , QChar );
+ void writePen (QString &, int, int, QString);
+ QString writeColor (t_mycolor *);
+ void readTypefaceTable (QTextStream &, QStringList &);
+ void readColormap (QTextStream &, QPtrList<t_mycolor> &);
+ void readView (QTextStream &, QString, t_rc &);
+ void filterSHFGBG (QString, int *, int *, int *);
+ void transPenFormat (QString, int *, int *);
+ int readHeader (QTextStream &);
+ int translateColumnNumber (QString);
+
+private:
+ int m_stepsize;
+ int m_instep;
+ int m_progress;
+};
+#endif // APPLIXSPREADIMPORT_H
diff --git a/filters/kspread/applixspread/kspread_applixspread_import.desktop b/filters/kspread/applixspread/kspread_applixspread_import.desktop
new file mode 100644
index 000000000..5d829d39c
--- /dev/null
+++ b/filters/kspread/applixspread/kspread_applixspread_import.desktop
@@ -0,0 +1,68 @@
+[Desktop Entry]
+Type=Service
+Name=KSpread Applix Spreadsheet Import Filter
+Name[af]=Kspread Applix Spreiblad In voer Filter
+Name[az]=KSpread Applix Hesab Cədvəli Alma Süzgəci
+Name[bg]=Филтър за импортиране от Applix Spreadsheet в KSpread
+Name[br]=Sil enporzh al loger Applix evit KSpread
+Name[ca]=Filtre d'importació per a fulls per a càlcul Applix per a KSpread
+Name[cs]=KSpread Applix Spreadsheet importní filtr
+Name[cy]=Hidlen Fewnforio Taenlen Applix KSpread
+Name[da]=KSpread Applix regnearks-importfilter
+Name[de]=KSpread Applix-Spreadsheet-Importfilter
+Name[el]=Φίλτρο εισαγωγής λογιστικού φύλλου Applix του KSpread
+Name[eo]=Appliks-tabelo-import-filtrilo por KSpread
+Name[es]=Filtro de importación de KSpread para hoja de cálculo de Applix
+Name[et]=KSpreadi Applix'i tabelite impordifilter
+Name[eu]=KSpread-en Applix-en kalkulu-orriaren inportaziorako iragazkia
+Name[fa]=پالایۀ واردات صفحه گستردۀ KSpread Applix
+Name[fi]=KSpread Applix taulukkolaskenta -tuontisuodin
+Name[fr]=Filtre d'importation Applix Spreadsheet de KSpread
+Name[fy]=KSpread Applix Spreadsheet Ymportfilter
+Name[gl]=Filtro de Importación de Applix Spreadsheet para KSpread
+Name[he]=מסנן לייבוא גיליונות אלקטרוניים של Applix ל־KSpread
+Name[hi]=के-स्प्रेड एप्लिक्स स्प्रेडशीट आयात छननी
+Name[hr]=KSpread Applix Spreadsheet filtar uvoza
+Name[hu]=KSpread Applix Spreadsheets importszűrő
+Name[is]=KSpread Applix töflureiknis innflutningssía
+Name[it]=Filtro di importazione Applix Spreadsheet per KSpread
+Name[ja]=KSpread Applix スプレッドシート インポートフィルタ
+Name[km]=តម្រង​នាំចូល​សៀវភៅបញ្ជី Applix សម្រាប់ KSpread
+Name[lo]= ຕົວຕອງການນຳເຂົ້າຕາຕະລາງງານ Apllix ຂອງກະດາດຄຳນວນ K
+Name[lt]=KWord Applix elektroninės lentelės importo filtras
+Name[lv]=KSpread Applix elektroniskās tabulas importa filtrs
+Name[ms]=Penapis Import KSpread Applix Spreadsheet
+Name[mt]=Filtru għall-importazzjoni ta' Spreadsheet Applix ġo KSpread
+Name[nb]=Applix-regnearkimportfilter for KSpread
+Name[nds]="Applix-Tabellenutreken"-Importfilter för KSpread
+Name[ne]=केडीई स्प्रिेड एप्लिक्स स्प्रिेडसिट आयात फिल्टर
+Name[nl]=KSpread Applix Spreadsheet Importfilter
+Name[nn]=Applix Spreadsheet-importfilter for KSpread
+Name[pl]=Filtr importu formatu arkusza kalkulacyjnego Applix do KSpread
+Name[pt]=Filtro de Importação de Applix Spreadsheet para o KSpread
+Name[pt_BR]=Filtro de importação de Planilhas para o KSpread
+Name[ro]=Filtru importare KSpread pentru Applix
+Name[ru]=Фильтр импорта таблиц Applix Spreadsheet в KSpread
+Name[se]=KSpread:a Applix Spreadsheet-sisafievrridansilli
+Name[sk]=Applix Spreadsheet filter pre import pre KSpread
+Name[sl]=Uvozni filter Applix Spreadsheet za KSpread
+Name[sr]=KSpread-ов филтер за увоз Applix-ових прорачунских листова
+Name[sr@Latn]=KSpread-ov filter za uvoz Applix-ovih proračunskih listova
+Name[sv]=Kspread-importfilter för Applix-kalkylark
+Name[ta]=KSpread Applix Spreadsheet இறக்குமதி வடிகட்டி
+Name[tg]=Филтри Воридоти KSpread Applix Spreadsheet
+Name[th]=ตัวกรองการนำเข้าตารางงาน Apllix ของกระดาษคำนวณ K
+Name[tr]=KSpread Applix Hesap Tablosu Alma Filtresi
+Name[uk]=Фільтр імпорту Applix Spreadsheet для KSpread
+Name[uz]=KSpread Applix elektron jadval import filteri
+Name[uz@cyrillic]=KSpread Applix электрон жадвал импорт филтери
+Name[ven]=U phadaladza ha K Applix filithara ya u dzhenisa nga ngomu ya siatari lo phadalalho
+Name[wa]=Passete tåvleu Applix d' intrêye po KSpread
+Name[xh]=Isihluzi Sokurhweba se KSpread Applix Spreadsheet
+Name[zh_CN]=KSpread Applix 电子表格导入过滤器
+Name[zh_TW]=KSpread Applix 電子表單匯入過濾程式
+X-KDE-Export=application/x-kspread
+X-KDE-Import=application/x-applixspread
+X-KDE-Weight=1
+X-KDE-Library=libapplixspreadimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/applixspread/status.html b/filters/kspread/applixspread/status.html
new file mode 100644
index 000000000..c944ef5c0
--- /dev/null
+++ b/filters/kspread/applixspread/status.html
@@ -0,0 +1,755 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>KOffice filters status: Applix Spreadsheet FILTER</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<A NAME="START">&nbsp;</A>
+
+<BR>
+<center>
+ <h1>
+ KOffice filters status: &nbsp;&nbsp;<i>Applix Spreadsheet FILTER</i>
+ </h1>
+</center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%">
+
+<font size="-1"><b>
+ <A HREF="#import">Import</A> |
+ <A HREF="#export">Export</A>
+</b></font>
+
+<BR><BR><BR>
+<center><a NAME="import"></a></center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+
+ <tr BGCOLOR="#DDFFDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>
+ Import Applix Spreadsheet for kspread<BR>
+ <BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>03 mar 2001</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>
+ - can import simple and complex Applix Spreadsheet documents<br>
+ - tests the headline of the document<br>
+ - converts &lt;, &gt;, &amp;, to &amp;lt; &amp;gt; &amp;amp;<br>
+ - converts all applix special characters<br>
+ - converts fontsize, fontcolor, horizontal and vertical alignment, bold, italic, underline<br>
+ - eats long text strings (more than one row in inputfile)<br>
+ - converts different tables inside of one document<br>
+ - cellformat: background color, brushstyles, brushcolor<br>
+ - cellframe: linewidth, linetype, linecolor<br>
+ - row height and column width<br>
+ - converting the fontfamily (incl. reading the typeface table)<br>
+ - correct process bar value emiting (procent)<br>
+ - rows A-Z and greater Z (AA-ZZ) are right translate into integer values<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>
+ - cellframes: double lines are not supported in kspread till now. So they can't translated correct.<br>
+ - check the row height and column width - they are not right sometimes<br>
+ - grouped row and column formats<br>
+ - add endoffile checking with dialog in do-while loops<br>
+ - detect valueline (can only do textlines)<br>
+ - convert a formular, date or something else right with cell references<br>
+ - change the printf output to debug (xxxxx) output<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>
+
+
+ <table border="0" cellspacing="0">
+ <tr valign=top>
+ <td align=right>17 mar 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>The fontfamily in support (incl. bugfix)<BR>
+ Longnamed columns like AA are right supported now- for cell elements and column width elements<BR>
+ Corrected the row width values. They start with 32768!<BR>
+ Little code cleanup. Updated the fileformat description.
+ </td>
+ </tr>
+ <tr>
+ <td align=right>13 mar 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>Added the progress bar value emiting (<A HREF="faure@kde.org">David Faure</A>)</td>
+ </tr>
+ <tr>
+ <td align=right>11 mar 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>Added fileformat description.</td>
+ </tr>
+ <tr>
+ <td align=right>10 mar 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>Checked in this version after discussion with David Faure. He told me that he just tried to begin with a applix spreadsheet import filter too.</td>
+ </tr>
+ <tr>
+ <td align=right>09 mar 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>Read the row height and column width.</td>
+ </tr>
+ <tr>
+ <td align=right>03 mar 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>Reads the typefont and the colortable, converts cmyk to rgb, added some style information (cell and string)</td>
+ </tr>
+ <tr>
+ <td align=right>24 feb 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>Add &lt;, &gt;, &amp; and applix character convertation</td>
+ </tr>
+ <tr>
+ <td align=right>11 feb 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>Written a filter that only can filter simple applix files</td>
+ </tr>
+ </table>
+
+
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors&nbsp;</font></b></td>
+ <td><A HREF="mailto:ebartels@nwn.de">Enno Bartels</A></td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td><A HREF="http://home.nordwest.net/ebartels/applixinfo/as/index.html">Applixword example</A></td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td><B><U><font size="+1">Fileformat:</font></U></B><BR>
+ <BR>
+ <B><U>Main Structure:</U></B><BR>
+ <spacer size="20">1. Header<BR>
+ <spacer size="20">2. Colortable<BR>
+ <spacer size="20">3. Fonttable<BR>
+ <spacer size="20">...<BR>
+ <spacer size="20">4. View<BR>
+ <spacer size="20">...<BR>
+ <spacer size="20">5. Headers and footers<BR>
+ <spacer size="20">6. Cellvalues<BR>
+ <spacer size="20">7. End<BR><BR><BR>
+
+
+ <B><U>1. Header:</U></B><BR>
+ <spacer size="10">The headerline looks like that:<BR>
+ <spacer size="20"><B><I>*BEGIN SPREADSHEETS VERSION=430/430 ENCODING=7BIT</I></B><BR><BR><BR>
+
+
+ <B><U>2. Colormap:</U></B><BR>
+ <spacer size="10">The colormap has 3 parts<BR>
+ <spacer size="10">2.1. Starting line<BR>
+ <spacer size="10">2.2. Value lines<BR>
+ <spacer size="10">2.3. Ending line<BR>
+ <BR>
+
+ <spacer size="10"><U>2.1. Colormap start:</U><BR>
+ <spacer size="20">The colormap begins with this line<BR>
+ <spacer size="20"><B><I>COLORMAP</I></B><BR>
+ <BR>
+
+ <spacer size="10"><U>2.2. Colormap value:</U><BR>
+ <spacer size="20">A color value line has the following parts (cmyk - colorsystem)<BR>
+ <spacer size="20"><B>Text 0 c m y k 0</B><BR>
+ <BR>
+
+ <spacer size="20">
+ <TABLE CELLPADDING="0" BORDER="0">
+ <TR>
+ <TD>2.2.1.</TD>
+ <TD>Text</TD>
+ <TD>= Textstring</TD>
+ <TD>-</TD>
+ </TR>
+ <TR>
+ <TD>2.2.2.</TD>
+ <TD>0</TD>
+ <TD>= NULL</TD>
+ <TD>-</TD>
+ </TR>
+ <TR>
+ <TD>2.2.3.</TD>
+ <TD>c</TD>
+ <TD>= cyan</TD>
+ <TD>0-255</TD>
+ </TR>
+ <TR>
+ <TD>2.2.4.</TD>
+ <TD>m</TD>
+ <TD>= magenta</TD>
+ <TD>0-255</TD>
+ </TR>
+ <TR>
+ <TD>2.2.5.</TD>
+ <TD>y</TD>
+ <TD>= yellow</TD>
+ <TD>0-255</TD>
+ </TR>
+ <TR>
+ <TD>2.2.6.</TD>
+ <TD>k</TD>
+ <TD>= black (key)</TD>
+ <TD>0-255</TD>
+ </TR>
+ <TR>
+ <TD>2.2.7.</TD>
+ <TD>0</TD>
+ <TD>= NULL</TD>
+ <TD>-</TD>
+ </TR>
+ </TABLE>
+ <BR><BR>
+
+ <spacer size="20">Color converting is very simple cmyk to rgb:<BR>
+ <spacer size="20">r = 255 - (c+k)<BR>
+ <spacer size="20">g = 255 - (m+k)<BR>
+ <spacer size="20">b = 255 - (y+k)<BR>
+ <spacer size="20">If the value of r, g or b if less then 0 you must set it to 0 .<BR>
+ <BR>
+ <spacer size="20">For examples inside koffice look a this files too<br>
+ <spacer size="20"><I>koffice/kimageshop/core/kis_color.cc and kis_color.h</I><BR>
+ <BR><BR>
+
+ <spacer size="10"><U>2.3. Colormap end:</U><BR>
+ <spacer size="20">The colormap ends with this line:<BR>
+ <spacer size="20"><B><I>END COLORMAP</I></B>
+ <BR><BR>
+
+
+ <B><U>3. Fonttable:</U></B><BR>
+ <spacer size="10">The fonttable has 3 parts<BR>
+ <spacer size="10">3.1. Starting line<BR>
+ <spacer size="10">3.2. Value lines<BR>
+ <spacer size="10">3.3. Ending line<BR>
+ <BR>
+
+ <spacer size="10"><U>3.1. Starting line</U><BR>
+ <spacer size="20">The fonttable begins with this line:<BR>
+ <spacer size="20"><B><I>TYPEFACE TABLE</I></B><BR>
+ <BR>
+
+ <spacer size="10"><U>3.2. Value line</U><BR>
+ <spacer size="20">The fonttable value line looks like that:<BR>
+ <spacer size="20"><B>Helvetica</B><BR>
+ <BR>
+
+ <spacer size="10"><U>3.3. Ending line</U><BR>
+ <spacer size="20">The colormap ends with this line ends with<BR>
+ <spacer size="20"><B><I>END TYPEFACE TABLE</I></B><BR>
+ <BR><BR>
+
+
+ <B><U>4. View:</U></B><BR>
+ <spacer size="10">Each table has its own view section and everyone has 3 parts<br>
+ <spacer size="10">4.1. Starting line<BR>
+ <spacer size="10">4.2. Value lines<BR>
+ <spacer size="10">4.3. Ending line<BR>
+ <spacer size="10">This is an example with the table name <B>A</B><BR>
+ <BR>
+
+ <spacer size="10"><U>4.1. Starting line</U><BR>
+ <spacer size="20">The view of table <B>A</B> begins with this line:<BR>
+ <spacer size="20"><B><I>View Start, Name: ~A:~</I></B><br>
+ <BR>
+
+ <spacer size="10"><U>4.2. Value lines</U><BR>
+ <spacer size="20">There are different value lines, but all of them start with <B>view</B><BR>
+ <spacer size="20">There are following important value lines:<BR>
+
+ <spacer size="20">4.2.1. Column width <BR>
+ <spacer size="20">4.2.2. Row heights<BR>
+ <BR>
+
+ <spacer size="20"><U>4.2.1. Column width</U><BR>
+ <spacer size="30">In the view of an table block is for example the width of a column:<br>
+ <spacer size="30"><B><I>View Column Widths: A:3 B:3 C:3 D:3 E:3 F:3 G:4 H:4</I></B><br>
+ <BR>
+
+ <spacer size="20"><U>4.2.1. Row height</U><BR>
+ <spacer size="30">or the height of a row<br>
+ <spacer size="30"><B><I>View Row Heights: 3:18 4:24 8:32804 </I></B><br>
+ <spacer size="30">Attention: If the row value is greater then 32768 you have to calc rowHeight = rowHeight - 32768 to get the right value!
+ <br><br>
+
+ <spacer size="10"><U>4.3. Ending line</U><BR>
+ <spacer size="20">The view of table <B>A</B> ends with this line:<BR>
+ <spacer size="20"><B><I>View End, Name: ~A:~</I></B><BR>
+ <br><br>
+
+
+ <B><U>5. Headers and footers:</U></B><BR>
+ <spacer size="10">The headers and footers section has 3 parts<BR>
+ <spacer size="10">5.1. Starting line<BR>
+ <spacer size="10">5.2. Value lines<BR>
+ <spacer size="10">5.3. Ending line<BR>
+ <BR>
+
+ <spacer size="10"><U>5.1. Starting line</U><BR>
+ <spacer size="20">The headers and footers section begins with this line:<BR>
+ <spacer size="20"><B><I>Headers And Footers</I></B><BR>
+ <BR>
+
+ <spacer size="10"><U>5.2. Value lines</U><BR>
+ <spacer size="20">-<BR>
+ <spacer size="20">-<BR>
+ <BR>
+
+ <spacer size="10"><U>5.3. Ending line</U><BR>
+ <spacer size="20">The headers and footers section end with<BR>
+ <spacer size="20"><B><I>Headers And Footers End</I></B><BR>
+ <BR><BR>
+
+
+
+ <B><U>6. Cellvalue:</U></B><BR>
+ <spacer size="10">This is a cellvalue line<BR>
+ <spacer size="10"><B><I>('DN|B,I,U,TF1,P18|T4) A!D11: Hello everybody</I></B><BR> <BR>
+ <spacer size="10">a cellvalue line has 3 parts:<BR>
+ <spacer size="10">6.1. Formatpart<BR>
+ <spacer size="10">6.2. Location part<BR>
+ <spacer size="10">6.3. Text String, formular, value, link, etc.<BR>
+ <BR>
+
+
+ <spacer size="10"><U>6.1. Formatpart:</U><BR>
+ <spacer size="20">The format part looks like that:<BR>
+ <spacer size="20"><B>('DN|B,I,U,TF1,P18|T4)</B><BR>
+ <spacer size="20">There are 3 formatsubparts divided by <B>|</B>:<BR>
+ <spacer size="20"><B>(Part1|Part2|Part3)</B><BR>
+ <spacer size="20">5.1.1. Part 1 - Alignment format<BR>
+ <spacer size="20">5.1.2. Part 2 - Text format<BR>
+ <spacer size="20">5.1.3. Part 3 - Cell format<BR>
+ <BR>
+
+
+ <spacer size="20"><U>6.1.1. Part 1 - Alignment format</U><BR>
+ <spacer size="30">This is the alignment format for vertical, horizontal alignment<BR>
+ <spacer size="30">
+ <TABLE CELLPADDING="0" BORDER="0">
+ <TR>
+ <TD>6.1.1.1&nbsp;&nbsp;</TD>
+ <TD><B>1</B></TD>
+ <TD>horizontal alignment</TD>
+ <TD>left</TD>
+ </TR>
+ <TR>
+ <TD>6.1.1.2&nbsp;&nbsp;</TD>
+ <TD><B>2</B></TD>
+ <TD>horizontal alignment</TD>
+ <TD>right</TD>
+ </TR>
+ <TR>
+ <TD>6.1.1.3&nbsp;&nbsp;</TD>
+ <TD><B>3</B></TD>
+ <TD>horizontal alignment</TD>
+ <TD>center</TD>
+ </TR>
+ <TR>
+ <TD>6.1.1.4&nbsp;&nbsp;</TD>
+ <TD><B>VT</B></TD>
+ <TD>vertical alignment</TD>
+ <TD>top</TD>
+ </TR>
+ <TR>
+ <TD>6.1.1.5&nbsp;&nbsp;</TD>
+ <TD><B>VC</B></TD>
+ <TD>vertical alignment</TD>
+ <TD>center</TD>
+ </TR>
+ <TR>
+ <TD>6.1.1.5&nbsp;&nbsp;</TD>
+ <TD><B>VB</B></TD>
+ <TD>vertical alignment</TD>
+ <TD>bottom</TD>
+ </TR>
+ <TR>
+ <TD>6.1.1.6&nbsp;&nbsp;</TD>
+ <TD><B>DN</B></TD>
+ <TD>??</TD>
+ <TD>??</TD>
+ </TR>
+ </TABLE>
+ <BR>
+
+
+ <spacer size="20"><U>6.1.2. Part 2 - Text format</U><BR>
+ <spacer size="30">This is the alignment format for the text<BR>
+ <spacer size="30">
+ <TABLE CELLPADDING="0" BORDER="0">
+ <TR>
+ <TD>6.1.2.1.&nbsp;&nbsp;</TD>
+ <TD><B>B</B></TD>
+ <TD>bold</TD>
+ <TD>-</TD>
+ </TR>
+ <TR>
+ <TD>6.1.2.2.&nbsp;&nbsp;</TD>
+ <TD><B>I</B></TD>
+ <TD>italic</TD>
+ <TD>-</TD>
+ </TR>
+ <TR>
+ <TD>6.1.2.3.&nbsp;&nbsp;</TD>
+ <TD><B>U</B></TD>
+ <TD>underline</TD>
+ <TD>-</TD>
+ </TR>
+ <TR>
+ <TD>6.1.2.4.&nbsp;&nbsp;</TD>
+ <TD><B>TFx</B></TD>
+ <TD>fontfamily</TD>
+ <TD>x is the number in the fonttable.</TD>
+ </TR>
+ <TR>
+ <TD>6.1.2.5.&nbsp;&nbsp;</TD>
+ <TD><B>Px</B></TD>
+ <TD>fontsize</TD>
+ <TD>x is the fontsize.</TD>
+ </TR>
+ </TABLE>
+ <BR>
+
+
+
+ <spacer size="20"><U>6.1.3. Part 3 - Cell format</U><BR>
+ <spacer size="30">This is the alignment format for the text<BR>
+ <spacer size="30">
+ <TABLE CELLPADDING="0" BORDER="0">
+ <TR>
+ <TD>6.1.3.1.&nbsp;&nbsp;</TD>
+ <TD><B>Txy</B></TD>
+ <TD>Frame at the top</TD>
+ </TR>
+ <TR>
+ <TD>6.1.3.2.&nbsp;&nbsp;</TD>
+ <TD><B>Bxy</B></TD>
+ <TD>Frame at the bottom</TD>
+ </TR>
+ <TR>
+ <TD>6.1.3.3.&nbsp;&nbsp;</TD>
+ <TD><B>Lxy</B></TD>
+ <TD>Frame at the left side</TD>
+ </TR>
+ <TR>
+ <TD>6.1.3.4.&nbsp;&nbsp;</TD>
+ <TD><B>Rxy</B></TD>
+ <TD>Frame at the right side</TD>
+ </TR>
+ </TABLE>
+ <BR>
+
+ <spacer size="30">x = number describes the penwidth and penstyle of the frame line<BR>
+ <spacer size="30">
+ <TABLE CELLPADDING="0" BORDER="1">
+ <TR>
+ <TD ALIGN=CENTER colspan=2>applix</TD>
+ <TD ALIGN=CENTER>&nbsp;</TD>
+ <TD ALIGN=CENTER colspan=2> kspread</TD>
+ </TR>
+ <TR>
+ <TD ALIGN=CENTER>number x</TD>
+ <TD ALIGN=CENTER>info</TD>
+ <TD ALIGN=CENTER>&nbsp;</TD>
+ <TD ALIGN=CENTER>penwidth</TD>
+ <TD ALIGN=CENTER>penstyle</TD>
+ </TR>
+ <TR>
+ <TD>1</TD>
+ <TD>-</TD>
+ <TD>&nbsp;=&nbsp;</TD>
+ <TD>1</TD>
+ <TD>1</TD>
+ </TR>
+ <TR>
+ <TD>2</TD>
+ <TD>-</TD>
+ <TD>&nbsp;=&nbsp;</TD>
+ <TD>2</TD>
+ <TD>1</TD>
+ </TR>
+ <TR>
+ <TD>3</TD>
+ <TD>-</TD>
+ <TD>&nbsp;=&nbsp;</TD>
+ <TD>3</TD>
+ <TD>1</TD>
+ </TR>
+ <TR>
+ <TD>4</TD>
+ <TD>dashed</TD>
+ <TD>&nbsp;=&nbsp;</TD>
+ <TD>1</TD>
+ <TD>3</TD>
+ </TR>
+ <TR>
+ <TD>5</TD>
+ <TD>double line</TD>
+ <TD>&nbsp;=&nbsp;</TD>
+ <TD>5</TD>
+ <TD>1</TD>
+ </TR>
+ </TABLE>
+ <BR>
+
+
+ <spacer size="30">y = examples <B>FG7</B> &nbsp;&nbsp; <B>SH11FG18</B> &nbsp;&nbsp; <B>SH11FG18BG4</B><BR>
+ <spacer size="30">it has max 3 Parts:<BR>
+ <spacer size="30">6.1.3.4.1. Foreground color.<BR>
+ <spacer size="30">6.1.3.4.2. Background shade type.<BR>
+ <spacer size="30">6.1.3.4.3. Background color.<BR>
+ <BR>
+
+ <spacer size="30"><U>6.1.3.4.1. Foreground color:</U><BR>
+ <spacer size="40">FGx = Foreground color. - x is the number in the colortable<BR>
+ <BR>
+
+ <spacer size="30"><U>6.1.3.4.2. Background shade type:</U><BR>
+ <spacer size="40">SHx = Background shade type. x is the shadetypenumber<BR>
+ <spacer size="40">Not all can be translate !<BR>
+ <BR>
+ <spacer size="40">
+ <TABLE CELLPADDING="0" BORDER="1">
+ <TR>
+ <TD ALIGN=CENTER>applix</TD>
+ <TD ALIGN=CENTER>&nbsp;</TD>
+ <TD ALIGN=CENTER>kspread</TD>
+ </TR>
+ <TR>
+ <TD ALIGN=CENTER>shadetype number </TD>
+ <TD ALIGN=CENTER>&nbsp;</TD>
+ <TD ALIGN=CENTER>shadetype number</TD>
+ </TR>
+ <TR>
+ <TD>1</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ <TR>
+ <TD>2</TD>
+ <TD>=</TD>
+ <TD>7</TD>
+ </TR>
+ <TR>
+ <TD>3</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ <TR>
+ <TD>4</TD>
+ <TD>=</TD>
+ <TD>4</TD>
+ </TR>
+ <TR>
+ <TD>5</TD>
+ <TD>=</TD>
+ <TD>3</TD>
+ </TR>
+ <TR>
+ <TD>6</TD>
+ <TD>=</TD>
+ <TD>2</TD>
+ </TR>
+ <TR>
+ <TD>7</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ <TR>
+ <TD>8</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ <TR>
+ <TD>9</TD>
+ <TD>=</TD>
+ <TD>10</TD>
+ </TR>
+ <TR>
+ <TD>10</TD>
+ <TD>=</TD>
+ <TD>9</TD>
+ </TR>
+ <TR>
+ <TD>11</TD>
+ <TD>=</TD>
+ <TD>11</TD>
+ </TR>
+ <TR>
+ <TD>12</TD>
+ <TD>=</TD>
+ <TD>12</TD>
+ </TR>
+ <TR>
+ <TD>13</TD>
+ <TD>=</TD>
+ <TD>13</TD>
+ </TR>
+ <TR>
+ <TD>14</TD>
+ <TD>=</TD>
+ <TD>14</TD>
+ </TR>
+ <TR>
+ <TD>15</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ <TR>
+ <TD>16</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ <TR>
+ <TD>17</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ <TR>
+ <TD>18</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ <TR>
+ <TD>19</TD>
+ <TD>=</TD>
+ <TD>0</TD>
+ </TR>
+ </TABLE>
+ <BR>
+
+ <spacer size="30"><U>6.1.3.4.3. Background color:</U> <BR>
+ <spacer size="40">BGx = Background color. x is the number in the colortable<BR>
+ <BR><BR>
+
+
+ <spacer size="10"><U>6.2. Location part:</U> <BR>
+ <spacer size="20">The location part looks like that:<BR>
+ <spacer size="20"><B>A!D11:</B><BR>
+ <spacer size="20">A = table <BR>
+ <spacer size="20">D11 = cellnumber<BR>
+ <spacer size="30">D = columnnumber<BR>
+ <spacer size="30">11 = rownumber<BR>
+ <spacer size="30">:=textstring, ;=formular, .=value<BR>
+ <BR>
+
+ <spacer size="10"><U>6.3. Text String etc:</U><BR>
+ <spacer size="20">The text string part looks like that:<BR>
+ <spacer size="20"><B>Hello everybody</B><BR>
+ <BR>
+
+
+
+
+
+
+ <B><U>7. End</U></B><BR>
+ The end looks like that:<BR>
+ <B><I></I>*END SPREADSHEETS</B><BR>
+ <BR><BR>
+
+
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+<br><br><br>
+
+<hr NOSHADE SIZE=1>
+<br><br><br>
+
+
+<center>
+ <a NAME="export"></a>
+</center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+ <tr BGCOLOR="#FFDDDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>Export kspread to Applix Spreadsheet<BR><BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>None</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>Everything</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td><!a href="mailto:null@kde.org">-</a></td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td><!a href="http://www.koffice.org">-</a></td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>---</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+</body>
+</html>
diff --git a/filters/kspread/csv/DESIGN b/filters/kspread/csv/DESIGN
new file mode 100644
index 000000000..9c6c4c909
--- /dev/null
+++ b/filters/kspread/csv/DESIGN
@@ -0,0 +1,37 @@
+The CSV import filter uses a hand-made state machine to parse the CSV file.
+This allows to handle quoted fields (such as those containing the CSV delimiter),
+as well as the double-quote character itself (which then appears twice, and
+always in a quoted field).
+Just to make sure about the vocabulary, I call a quoted field a field
+starting with " and finishing with ".
+
+Let's try to draw the graph of the state machine using ascii-art.
+
+
+ DEL or EOL
+ /--\
+ | |
+ | v "
+ /--[START]-------->[QUOTED_FIELD] (**)
+ other| ^ ^ | ^
+ (*) | | | DEL or | " | " (*)
+ | | | EOL v |
+ | | \----[MAYBE_END_OF_QUOTED_FIELD]
+ | | |
+ | | DEL or |
+ | | EOL | other
+ | | |
+ v | /------<-------|
+ [NORMAL_FIELD] (**)
+
+DEL : CSV delimiter (depends on locale !). Often comma, sometimes semicolon.
+EOL : End Of Line.
+(*) : added to the current field
+(**) : implicit loop on itself, labeled "other (*)"
+
+
+Ugly isn't it ? :) One can't be good in drawings AND in hacking :)
+
+That's all. For the rest, see csvfilter.cc
+
+David Faure <faure@kde.org>, 1999
diff --git a/filters/kspread/csv/Makefile.am b/filters/kspread/csv/Makefile.am
new file mode 100644
index 000000000..32c8408a5
--- /dev/null
+++ b/filters/kspread/csv/Makefile.am
@@ -0,0 +1,22 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) -I$(top_srcdir)/kspread $(KOFFICE_INCLUDES) \
+ $(KOTEXT_INCLUDES) $(all_includes)
+
+####### Files
+
+kde_module_LTLIBRARIES = libcsvimport.la libcsvexport.la
+
+libcsvimport_la_SOURCES = csvimport.cc xmltree.cc csvdialog.cpp dialogui.ui
+libcsvimport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libcsvimport_la_LIBADD = $(KOFFICE_LIBS) ../../../kspread/libkspreadcommon.la
+
+libcsvexport_la_SOURCES = csvexport.cc csvexportdialog.cpp exportdialogui.ui
+libcsvexport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libcsvexport_la_LIBADD = $(KOFFICE_LIBS) ../../../kspread/libkspreadcommon.la
+
+METASOURCES = AUTO
+
+service_DATA = kspread_csv_import.desktop kspread_csv_export.desktop
+
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/csv/README b/filters/kspread/csv/README
new file mode 100644
index 000000000..77921a289
--- /dev/null
+++ b/filters/kspread/csv/README
@@ -0,0 +1,10 @@
+This is a CSV filter for kspread.
+
+At first it was only an input filter, hence the files named "csvfilter*".
+Then I added an export filter and named it csvexport*
+
+Read DESIGN for the gory details, TODO for how to help, the source for why
+it screwed up your data.
+
+David Faure <faure@kde.org> ( CSV import and export )
+Werner Trobin <wtrobin@carinthia.com> ( CSV filter dialogs )
diff --git a/filters/kspread/csv/TODO b/filters/kspread/csv/TODO
new file mode 100644
index 000000000..4e61c3eb5
--- /dev/null
+++ b/filters/kspread/csv/TODO
@@ -0,0 +1,5 @@
+* Automatically adjust the columns width to their contents.
+ Will be difficult, as we don't know the font used...
+ Solution ? Set a default font _in_ the filter, and use it to compute
+ the width...
+
diff --git a/filters/kspread/csv/csvdialog.cpp b/filters/kspread/csv/csvdialog.cpp
new file mode 100644
index 000000000..2757e72b2
--- /dev/null
+++ b/filters/kspread/csv/csvdialog.cpp
@@ -0,0 +1,635 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+ Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <dialogui.h>
+#include <csvdialog.h>
+
+#include <qtable.h>
+#include <qcheckbox.h>
+#include <qcursor.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qspinbox.h>
+#include <qtextstream.h>
+#include <qbuttongroup.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qtextcodec.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kmessagebox.h>
+#include <kcharsets.h>
+
+CSVDialog::CSVDialog(QWidget* parent, QByteArray& fileArray, const QString /*seperator*/)
+ : KDialogBase(parent, 0, true, QString::null, Ok|Cancel, No, true),
+ m_adjustRows(false),
+ m_adjustCols(false),
+ m_startRow(0),
+ m_startCol(0),
+ m_endRow(-1),
+ m_endCol(-1),
+ m_textquote('"'),
+ m_delimiter(","),
+ m_ignoreDups(false),
+ m_fileArray(fileArray),
+ m_dialog(new DialogUI(this)),
+ m_codec( QTextCodec::codecForName( "UTF-8" ) )
+{
+ setCaption( i18n( "Import" ) );
+ kapp->restoreOverrideCursor();
+
+ QStringList encodings;
+ encodings << i18n( "Descriptive encoding name", "Recommended ( %1 )" ).arg( "UTF-8" );
+ encodings << i18n( "Descriptive encoding name", "Locale ( %1 )" ).arg( QTextCodec::codecForLocale()->name() );
+ encodings += KGlobal::charsets()->descriptiveEncodingNames();
+ // Add a few non-standard encodings, which might be useful for text files
+ const QString description(i18n("Descriptive encoding name","Other ( %1 )"));
+ encodings << description.arg("Apple Roman"); // Apple
+ encodings << description.arg("IBM 850") << description.arg("IBM 866"); // MS DOS
+ encodings << description.arg("CP 1258"); // Windows
+ m_dialog->comboBoxEncoding->insertStringList(encodings);
+
+ m_formatList << i18n( "Text" );
+ m_formatList << i18n( "Number" );
+ m_formatList << i18n( "Currency" );
+ m_formatList << i18n( "Date" );
+ m_formatList << i18n( "Decimal Comma Number" );
+ m_formatList << i18n( "Decimal Point Number" );
+ m_dialog->m_formatComboBox->insertStringList( m_formatList );
+
+ m_dialog->m_sheet->setReadOnly( true );
+
+ loadSettings();
+
+ fillTable();
+
+ //resize(sizeHint());
+ resize( 600, 400 ); // Try to show as much as possible of the table view
+ setMainWidget(m_dialog);
+
+ m_dialog->m_sheet->setSelectionMode( QTable::Multi );
+
+ connect(m_dialog->m_formatComboBox, SIGNAL(activated( const QString& )),
+ this, SLOT(formatChanged( const QString& )));
+ connect(m_dialog->m_delimiterBox, SIGNAL(clicked(int)),
+ this, SLOT(delimiterClicked(int)));
+ connect(m_dialog->m_delimiterEdit, SIGNAL(returnPressed()),
+ this, SLOT(returnPressed()));
+ connect(m_dialog->m_delimiterEdit, SIGNAL(textChanged ( const QString & )),
+ this, SLOT(formatChanged ( const QString & ) ));
+ connect(m_dialog->m_comboQuote, SIGNAL(activated(const QString &)),
+ this, SLOT(textquoteSelected(const QString &)));
+ connect(m_dialog->m_sheet, SIGNAL(currentChanged(int, int)),
+ this, SLOT(currentCellChanged(int, int)));
+ connect(m_dialog->m_ignoreDuplicates, SIGNAL(stateChanged(int)),
+ this, SLOT(ignoreDuplicatesChanged(int)));
+ connect(m_dialog->m_updateButton, SIGNAL(clicked()),
+ this, SLOT(updateClicked()));
+ connect(m_dialog->comboBoxEncoding, SIGNAL(textChanged ( const QString & )),
+ this, SLOT(encodingChanged ( const QString & ) ));
+}
+
+CSVDialog::~CSVDialog()
+{
+ saveSettings();
+ kapp->setOverrideCursor(Qt::waitCursor);
+}
+
+void CSVDialog::loadSettings()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("CSVDialog Settings");
+ m_textquote = config->readEntry("textquote", "\"")[0];
+ m_delimiter = config->readEntry("delimiter", ",");
+ m_ignoreDups = config->readBoolEntry("ignoreDups", false);
+ const QString codecText = config->readEntry("codec", "");
+
+ // update widgets
+ if (!codecText.isEmpty()) {
+ m_dialog->comboBoxEncoding->setCurrentText(codecText);
+ m_codec = getCodec();
+ }
+ if (m_delimiter == ",") m_dialog->m_radioComma->setChecked(true);
+ else if (m_delimiter == "\t") m_dialog->m_radioTab->setChecked(true);
+ else if (m_delimiter == " ") m_dialog->m_radioSpace->setChecked(true);
+ else if (m_delimiter == ";") m_dialog->m_radioSemicolon->setChecked(true);
+ else {
+ m_dialog->m_radioOther->setChecked(true);
+ m_dialog->m_delimiterEdit->setText(m_delimiter);
+ }
+ m_dialog->m_ignoreDuplicates->setChecked(m_ignoreDups);
+ m_dialog->m_comboQuote->setCurrentItem(m_textquote == '\'' ? 1
+ : m_textquote == '"' ? 0 : 2);
+}
+
+void CSVDialog::saveSettings()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("CSVDialog Settings");
+ QString q = m_textquote;
+ config->writeEntry("textquote", q);
+ config->writeEntry("delimiter", m_delimiter);
+ config->writeEntry("ignoreDups", m_ignoreDups);
+ config->writeEntry("codec", m_dialog->comboBoxEncoding->currentText());
+ config->sync();
+}
+
+void CSVDialog::fillTable( )
+{
+ int row, column;
+ bool lastCharDelimiter = false;
+ enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
+ S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
+
+ QChar x;
+ QString field;
+
+ kapp->setOverrideCursor(Qt::waitCursor);
+
+ for (row = 0; row < m_dialog->m_sheet->numRows(); ++row)
+ for (column = 0; column < m_dialog->m_sheet->numCols(); ++column)
+ m_dialog->m_sheet->clearCell(row, column);
+
+ int maxColumn = 1;
+ row = column = 1;
+ QTextStream inputStream(m_fileArray, IO_ReadOnly);
+ kdDebug(30501) << "Encoding: " << m_codec->name() << endl;
+ inputStream.setCodec( m_codec );
+
+ bool lastCharWasCr = false; // Last character was a Carriage Return
+ while (!inputStream.atEnd())
+ {
+ inputStream >> x; // read one char
+
+ // ### TODO: we should perhaps skip all other control characters
+ if ( x == '\r' )
+ {
+ // We have a Carriage Return, assume that its role is the one of a LineFeed
+ lastCharWasCr = true;
+ x = '\n'; // Replace by Line Feed
+ }
+ else if ( x == '\n' && lastCharWasCr )
+ {
+ // The end of line was already handled by the Carriage Return, so do nothing for this character
+ lastCharWasCr = false;
+ continue;
+ }
+ else if ( x == QChar( 0xc ) )
+ {
+ // We have a FormFeed, skip it
+ lastCharWasCr = false;
+ continue;
+ }
+ else
+ {
+ lastCharWasCr = false;
+ }
+
+ if ( column > maxColumn )
+ maxColumn = column;
+
+ switch (state)
+ {
+ case S_START :
+ if (x == m_textquote)
+ {
+ state = S_QUOTED_FIELD;
+ }
+ else if (x == m_delimiter)
+ {
+ if ((m_ignoreDups == false) || (lastCharDelimiter == false))
+ ++column;
+ lastCharDelimiter = true;
+ }
+ else if (x == '\n')
+ {
+ ++row;
+ column = 1;
+ if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
+ break;
+ }
+ else
+ {
+ field += x;
+ state = S_MAYBE_NORMAL_FIELD;
+ }
+ break;
+ case S_QUOTED_FIELD :
+ if (x == m_textquote)
+ {
+ state = S_MAYBE_END_OF_QUOTED_FIELD;
+ }
+ else
+ {
+ field += x;
+ }
+ break;
+ case S_MAYBE_END_OF_QUOTED_FIELD :
+ if (x == m_textquote)
+ {
+ field += x;
+ state = S_QUOTED_FIELD;
+ }
+ else if (x == m_delimiter || x == '\n')
+ {
+ setText(row - m_startRow, column - m_startCol, field);
+ field = QString::null;
+ if (x == '\n')
+ {
+ ++row;
+ column = 1;
+ if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
+ break;
+ }
+ else
+ {
+ if ((m_ignoreDups == false) || (lastCharDelimiter == false))
+ ++column;
+ lastCharDelimiter = true;
+ }
+ state = S_START;
+ }
+ else
+ {
+ state = S_END_OF_QUOTED_FIELD;
+ }
+ break;
+ case S_END_OF_QUOTED_FIELD :
+ if (x == m_delimiter || x == '\n')
+ {
+ setText(row - m_startRow, column - m_startCol, field);
+ field = QString::null;
+ if (x == '\n')
+ {
+ ++row;
+ column = 1;
+ if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
+ break;
+ }
+ else
+ {
+ if ((m_ignoreDups == false) || (lastCharDelimiter == false))
+ ++column;
+ lastCharDelimiter = true;
+ }
+ state = S_START;
+ }
+ break;
+ case S_MAYBE_NORMAL_FIELD :
+ if (x == m_textquote)
+ {
+ field = QString::null;
+ state = S_QUOTED_FIELD;
+ break;
+ }
+ case S_NORMAL_FIELD :
+ if (x == m_delimiter || x == '\n')
+ {
+ setText(row - m_startRow, column - m_startCol, field);
+ field = QString::null;
+ if (x == '\n')
+ {
+ ++row;
+ column = 1;
+ if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
+ break;
+ }
+ else
+ {
+ if ((m_ignoreDups == false) || (lastCharDelimiter == false))
+ ++column;
+ lastCharDelimiter = true;
+ }
+ state = S_START;
+ }
+ else
+ {
+ field += x;
+ }
+ }
+ if (x != m_delimiter)
+ lastCharDelimiter = false;
+ }
+
+ if ( !field.isEmpty() )
+ {
+ // the last line of the file had not any line end
+ setText(row - m_startRow, column - m_startCol, field);
+ ++row;
+ field = QString::null;
+ }
+
+ m_adjustCols = true;
+ adjustRows( row - m_startRow );
+ adjustCols( maxColumn - m_startCol );
+ m_dialog->m_colEnd->setMaxValue( maxColumn );
+ if ( m_endCol == -1 )
+ m_dialog->m_colEnd->setValue( maxColumn );
+
+
+ for (column = 0; column < m_dialog->m_sheet->numCols(); ++column)
+ {
+ const QString header = m_dialog->m_sheet->horizontalHeader()->label(column);
+ if ( m_formatList.find( header ) == m_formatList.end() )
+ m_dialog->m_sheet->horizontalHeader()->setLabel(column, i18n("Text"));
+
+ m_dialog->m_sheet->adjustColumn(column);
+ }
+ fillComboBox();
+
+ kapp->restoreOverrideCursor();
+}
+
+void CSVDialog::fillComboBox()
+{
+ if ( m_endRow == -1 )
+ m_dialog->m_rowEnd->setValue( m_dialog->m_sheet->numRows() );
+ else
+ m_dialog->m_rowEnd->setValue( m_endRow );
+
+ if ( m_endCol == -1 )
+ m_dialog->m_colEnd->setValue( m_dialog->m_sheet->numCols() );
+ else
+ m_dialog->m_colEnd->setValue( m_endCol );
+
+ m_dialog->m_rowEnd->setMinValue( 1 );
+ m_dialog->m_colEnd->setMinValue( 1 );
+ m_dialog->m_rowEnd->setMaxValue( m_dialog->m_sheet->numRows() );
+ m_dialog->m_colEnd->setMaxValue( m_dialog->m_sheet->numCols() );
+
+ m_dialog->m_rowStart->setMinValue( 1 );
+ m_dialog->m_colStart->setMinValue( 1 );
+ m_dialog->m_rowStart->setMaxValue( m_dialog->m_sheet->numRows() );
+ m_dialog->m_colStart->setMaxValue( m_dialog->m_sheet->numCols() );
+}
+
+int CSVDialog::getRows()
+{
+ int rows = m_dialog->m_sheet->numRows();
+ if ( m_endRow >= 0 )
+ {
+ if ( rows > ( m_startRow + m_endRow ) )
+ rows = m_startRow + m_endRow;
+ }
+
+ return rows;
+}
+
+int CSVDialog::getCols()
+{
+ int cols = m_dialog->m_sheet->numCols();
+ if ( m_endCol >= 0 )
+ {
+ if ( cols > ( m_startCol + m_endCol ) )
+ cols = m_startCol + m_endCol;
+ }
+
+ return cols;
+}
+
+int CSVDialog::getHeader(int col)
+{
+ QString header = m_dialog->m_sheet->horizontalHeader()->label(col);
+
+ if (header == i18n("Text"))
+ return TEXT;
+ else if (header == i18n("Number"))
+ return NUMBER;
+ else if (header == i18n("Currency"))
+ return CURRENCY;
+ else if ( header == i18n( "Date" ) )
+ return DATE;
+ else if ( header == i18n( "Decimal Comma Number" ) )
+ return COMMANUMBER;
+ else if ( header == i18n( "Decimal Point Number" ) )
+ return POINTNUMBER;
+ else
+ return TEXT; // Should not happen
+}
+
+QString CSVDialog::getText(int row, int col)
+{
+ return m_dialog->m_sheet->text( row, col );
+}
+
+void CSVDialog::setText(int row, int col, const QString& text)
+{
+ if ( row < 1 || col < 1 ) // skipped by the user
+ return;
+
+ if ( ( row > ( m_endRow - m_startRow ) && m_endRow > 0 ) || ( col > ( m_endCol - m_startCol ) && m_endCol > 0 ) )
+ return;
+
+ if ( m_dialog->m_sheet->numRows() < row )
+ {
+ m_dialog->m_sheet->setNumRows( row + 5000 ); /* We add 5000 at a time to limit recalculations */
+ m_adjustRows = true;
+ }
+
+ if ( m_dialog->m_sheet->numCols() < col )
+ {
+ m_dialog->m_sheet->setNumCols( col );
+ m_adjustCols = true;
+ }
+
+ m_dialog->m_sheet->setText( row - 1, col - 1, text );
+}
+
+/*
+ * Called after the first fillTable() when number of rows are unknown.
+ */
+void CSVDialog::adjustRows(int iRows)
+{
+ if (m_adjustRows)
+ {
+ m_dialog->m_sheet->setNumRows( iRows );
+ m_adjustRows = false;
+ }
+}
+
+void CSVDialog::adjustCols(int iCols)
+{
+ if (m_adjustCols)
+ {
+ m_dialog->m_sheet->setNumCols( iCols );
+ m_adjustCols = false;
+
+ if ( m_endCol == -1 )
+ {
+ if ( iCols > ( m_endCol - m_startCol ) )
+ iCols = m_endCol - m_startCol;
+
+ m_dialog->m_sheet->setNumCols( iCols );
+ }
+ }
+}
+
+void CSVDialog::returnPressed()
+{
+ if (m_dialog->m_delimiterBox->id(m_dialog->m_delimiterBox->selected()) != 4)
+ return;
+
+ m_delimiter = m_dialog->m_delimiterEdit->text();
+ fillTable();
+}
+
+void CSVDialog::textChanged ( const QString & )
+{
+ m_dialog->m_radioOther->setChecked ( true );
+ delimiterClicked(4); // other
+}
+
+void CSVDialog::formatChanged( const QString& newValue )
+{
+ //kdDebug(30501) << "CSVDialog::formatChanged:" << newValue << endl;
+ for ( int i = 0; i < m_dialog->m_sheet->numSelections(); ++i )
+ {
+ QTableSelection select ( m_dialog->m_sheet->selection( i ) );
+ for ( int j = select.leftCol(); j <= select.rightCol() ; ++j )
+ {
+ m_dialog->m_sheet->horizontalHeader()->setLabel( j, newValue );
+
+ }
+ }
+}
+
+void CSVDialog::delimiterClicked(int id)
+{
+ switch (id)
+ {
+ case 0: // comma
+ m_delimiter = ",";
+ break;
+ case 4: // other
+ m_delimiter = m_dialog->m_delimiterEdit->text();
+ break;
+ case 2: // tab
+ m_delimiter = "\t";
+ break;
+ case 3: // space
+ m_delimiter = " ";
+ break;
+ case 1: // semicolon
+ m_delimiter = ";";
+ break;
+ }
+
+ fillTable();
+}
+
+void CSVDialog::textquoteSelected(const QString& mark)
+{
+ if (mark == i18n("None"))
+ m_textquote = 0;
+ else
+ m_textquote = mark[0];
+
+ fillTable();
+}
+
+void CSVDialog::updateClicked()
+{
+ if ( !checkUpdateRange() )
+ return;
+
+ m_startRow = m_dialog->m_rowStart->value() - 1;
+ m_endRow = m_dialog->m_rowEnd->value();
+
+ m_startCol = m_dialog->m_colStart->value() - 1;
+ m_endCol = m_dialog->m_colEnd->value();
+
+ fillTable();
+}
+
+bool CSVDialog::checkUpdateRange()
+{
+ if ( ( m_dialog->m_rowStart->value() > m_dialog->m_rowEnd->value() )
+ || ( m_dialog->m_colStart->value() > m_dialog->m_colEnd->value() ) )
+ {
+ KMessageBox::error( this, i18n( "Please check the ranges you specified. The start value must be lower than the end value." ) );
+ return false;
+ }
+
+ return true;
+}
+
+void CSVDialog::currentCellChanged(int, int col)
+{
+ const QString header = m_dialog->m_sheet->horizontalHeader()->label(col);
+ m_dialog->m_formatComboBox->setCurrentText( header );
+}
+
+void CSVDialog::ignoreDuplicatesChanged(int)
+{
+ if (m_dialog->m_ignoreDuplicates->isChecked())
+ m_ignoreDups = true;
+ else
+ m_ignoreDups = false;
+ fillTable();
+}
+
+QTextCodec* CSVDialog::getCodec(void) const
+{
+ const QString strCodec( KGlobal::charsets()->encodingForName( m_dialog->comboBoxEncoding->currentText() ) );
+ kdDebug(30502) << "Encoding: " << strCodec << endl;
+
+ bool ok = false;
+ QTextCodec* codec = QTextCodec::codecForName( strCodec.utf8() );
+
+ // If QTextCodec has not found a valid encoding, so try with KCharsets.
+ if ( codec )
+ {
+ ok = true;
+ }
+ else
+ {
+ codec = KGlobal::charsets()->codecForName( strCodec, ok );
+ }
+
+ // Still nothing?
+ if ( !codec || !ok )
+ {
+ // Default: UTF-8
+ kdWarning(30502) << "Cannot find encoding:" << strCodec << endl;
+ // ### TODO: what parent to use?
+ KMessageBox::error( 0, i18n("Cannot find encoding: %1").arg( strCodec ) );
+ return 0;
+ }
+
+ return codec;
+}
+
+void CSVDialog::encodingChanged ( const QString & )
+{
+ QTextCodec* codec = getCodec();
+
+ if ( codec )
+ {
+ m_codec = codec;
+ fillTable();
+ }
+}
+
+
+#include <csvdialog.moc>
diff --git a/filters/kspread/csv/csvdialog.h b/filters/kspread/csv/csvdialog.h
new file mode 100644
index 000000000..e73976e62
--- /dev/null
+++ b/filters/kspread/csv/csvdialog.h
@@ -0,0 +1,89 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+ Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CSVDIALOG_H
+#define CSVDIALOG_H
+
+#include <qstringlist.h>
+
+#include <kdialogbase.h>
+
+class DialogUI;
+
+class CSVDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ enum Header
+ {
+ TEXT, ///< Normal text
+ NUMBER, ///< Number (either like locale or like C)
+ DATE, ///< Date \todo What type exactly?
+ CURRENCY, ///< Currency
+ COMMANUMBER,///< Number, which decimal symbol is a comma
+ POINTNUMBER ///< Number, which decimal symbol is a point/dot
+ };
+
+ CSVDialog(QWidget* parent, QByteArray& fileArray, const QString seperator);
+ ~CSVDialog();
+
+ int getRows();
+ int getCols();
+ int getHeader(int col);
+ QString getText(int row, int col);
+
+private:
+ void loadSettings();
+ void saveSettings();
+ void fillTable();
+ void fillComboBox();
+ void setText(int row, int col, const QString& text);
+ void adjustRows(int iRows);
+ void adjustCols(int iCols);
+ bool checkUpdateRange();
+ QTextCodec* getCodec(void) const;
+
+ bool m_adjustRows;
+ bool m_adjustCols;
+ int m_startRow;
+ int m_startCol;
+ int m_endRow;
+ int m_endCol;
+ QChar m_textquote;
+ QString m_delimiter;
+ bool m_ignoreDups;
+ QByteArray m_fileArray;
+ DialogUI * m_dialog;
+ QTextCodec* m_codec;
+ QStringList m_formatList; ///< List of the column formats
+
+private slots:
+ void returnPressed();
+ void formatChanged( const QString& );
+ void delimiterClicked(int id);
+ void textquoteSelected(const QString& mark);
+ void currentCellChanged(int, int col);
+ void textChanged ( const QString & );
+ void ignoreDuplicatesChanged( int );
+ void updateClicked();
+ void encodingChanged ( const QString & );
+};
+
+#endif
diff --git a/filters/kspread/csv/csvexport.cc b/filters/kspread/csv/csvexport.cc
new file mode 100644
index 000000000..c2b99c2b7
--- /dev/null
+++ b/filters/kspread/csv/csvexport.cc
@@ -0,0 +1,382 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <csvexport.h>
+
+#include <qfile.h>
+#include <qtextcodec.h>
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kgenericfactory.h>
+#include <KoFilterChain.h>
+#include <KoFilterManager.h>
+
+#include <kspread_map.h>
+#include <kspread_sheet.h>
+#include <kspread_doc.h>
+#include <kspread_view.h>
+#include <selection.h>
+
+#include <csvexportdialog.h>
+
+using namespace KSpread;
+
+typedef KGenericFactory<CSVExport, KoFilter> CSVExportFactory;
+K_EXPORT_COMPONENT_FACTORY( libcsvexport, CSVExportFactory( "kofficefilters" ) )
+
+class Cell
+{
+ public:
+ int row, col;
+ QString text;
+
+ bool operator < ( const Cell & c ) const
+ {
+ return row < c.row || ( row == c.row && col < c.col );
+ }
+ bool operator == ( const Cell & c ) const
+ {
+ return row == c.row && col == c.col;
+ }
+};
+
+
+CSVExport::CSVExport( KoFilter *, const char *, const QStringList & )
+ : KoFilter(), m_eol("\n")
+{
+}
+
+QString CSVExport::exportCSVCell( Sheet const * const sheet, int col, int row, QChar const & textQuote, QChar csvDelimiter )
+{
+ // This function, given a cell, returns a string corresponding to its export in CSV format
+ // It proceeds by:
+ // - getting the value of the cell, if any
+ // - protecting quote characters within cells, if any
+ // - enclosing the cell in quotes if the cell is non empty
+
+ KSpread::Cell const * const cell = sheet->cellAt( col, row );
+ QString text;
+
+ if ( !cell->isDefault() && !cell->isEmpty() )
+ {
+ if ( cell->isFormula() )
+ text = cell->strOutText();
+ else if ( !cell->link().isEmpty() )
+ text = cell->text(); // untested
+ else if( cell->isTime() )
+ text = cell->value().asTime().toString("hh:mm:ss");
+ else if( cell->isDate() )
+ text = cell->value().asDate().toString("yyyy-MM-dd");
+ else
+ text = cell->strOutText();
+ }
+
+ // quote only when needed (try to mimic excel)
+ bool quote = false;
+ if ( !text.isEmpty() )
+ {
+ if ( text.find( textQuote ) != -1 )
+ {
+ QString doubleTextQuote(textQuote);
+ doubleTextQuote.append(textQuote);
+ text.replace(textQuote, doubleTextQuote);
+ quote = true;
+
+ } else if ( text[0].isSpace() || text[text.length()-1].isSpace() )
+ quote = true;
+ else if ( text.find( csvDelimiter ) != -1 )
+ quote = true;
+ else if ( text.find( "\n" ) != -1 || text.find( "\r" ) != -1 )
+ quote = true;
+ }
+
+ if ( quote ) {
+ text.prepend(textQuote);
+ text.append(textQuote);
+ }
+
+ return text;
+}
+
+// The reason why we use the KoDocument* approach and not the QDomDocument
+// approach is because we don't want to export formulas but values !
+KoFilter::ConversionStatus CSVExport::convert( const QCString & from, const QCString & to )
+{
+ kdDebug(30501) << "CSVExport::convert" << endl;
+ KoDocument* document = m_chain->inputDocument();
+
+ if ( !document )
+ return KoFilter::StupidError;
+
+ if ( !::qt_cast<const KSpread::Doc *>( document ) )
+ {
+ kdWarning(30501) << "document isn't a KSpread::Doc but a " << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+ if ( ( to != "text/x-csv" && to != "text/plain" ) || from != "application/x-kspread" )
+ {
+ kdWarning(30501) << "Invalid mimetypes " << to << " " << from << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ Doc const * const ksdoc = static_cast<const Doc *>(document);
+
+ if ( ksdoc->mimeType() != "application/x-kspread" )
+ {
+ kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ CSVExportDialog *expDialog = 0;
+ if (!m_chain->manager()->getBatchMode())
+ {
+ expDialog= new CSVExportDialog( 0 );
+
+ if (!expDialog)
+ {
+ kdError(30501) << "Dialog has not been created! Aborting!" << endl;
+ return KoFilter::StupidError;
+ }
+ expDialog->fillSheet( ksdoc->map() );
+
+ if ( !expDialog->exec() )
+ {
+ delete expDialog;
+ return KoFilter::UserCancelled;
+ }
+ }
+
+ QTextCodec* codec = 0;
+ QChar csvDelimiter;
+ if (expDialog)
+ {
+ codec = expDialog->getCodec();
+ if ( !codec )
+ {
+ delete expDialog;
+ return KoFilter::StupidError;
+ }
+ csvDelimiter = expDialog->getDelimiter();
+ m_eol = expDialog->getEndOfLine();
+ }
+ else
+ {
+ codec = QTextCodec::codecForName("UTF-8");
+ csvDelimiter = ',';
+ }
+
+
+ // Now get hold of the sheet to export
+ // (Hey, this could be part of the dialog too, choosing which sheet to export....
+ // It's great to have parametrable filters... IIRC even MSOffice doesn't have that)
+ // Ok, for now we'll use the first sheet - my document has only one sheet anyway ;-)))
+
+ bool first = true;
+ QString str;
+ QChar textQuote;
+ if (expDialog)
+ textQuote = expDialog->getTextQuote();
+ else
+ textQuote = '"';
+
+ if ( expDialog && expDialog->exportSelectionOnly() )
+ {
+ kdDebug(30501) << "Export as selection mode" << endl;
+ View const * const view = static_cast<View*>(ksdoc->views().getFirst());
+
+ if ( !view ) // no view if embedded document
+ {
+ delete expDialog;
+ return KoFilter::StupidError;
+ }
+
+ Sheet const * const sheet = view->activeSheet();
+
+ QRect selection = view->selectionInfo()->lastRange();
+ // Compute the highest row and column indexes (within the selection)
+ // containing non-empty cells, respectively called CSVMaxRow CSVMaxCol.
+ // The CSV will have CSVMaxRow rows, all with CSVMaxCol columns
+ int right = selection.right();
+ int bottom = selection.bottom();
+ int CSVMaxRow = 0;
+ int CSVMaxCol = 0;
+
+ for ( int idxRow = 1, row = selection.top(); row <= bottom; ++row, ++idxRow )
+ {
+ for ( int idxCol = 1, col = selection.left(); col <= right; ++col, ++idxCol )
+ {
+ if( ! sheet->cellAt( col, row )->isEmpty() )
+ {
+ if ( idxRow > CSVMaxRow )
+ CSVMaxRow = idxRow;
+
+ if ( idxCol > CSVMaxCol )
+ CSVMaxCol = idxCol;
+ }
+ }
+ }
+
+ for ( int idxRow = 1, row = selection.top();
+ row <= bottom && idxRow <= CSVMaxRow; ++row, ++idxRow )
+ {
+ int idxCol = 1;
+ for ( int col = selection.left();
+ col <= right && idxCol <= CSVMaxCol; ++col, ++idxCol )
+ {
+ str += exportCSVCell( sheet, col, row, textQuote, csvDelimiter );
+
+ if ( idxCol < CSVMaxCol )
+ str += csvDelimiter;
+ }
+
+ // This is to deal with the case of non-rectangular selections
+ for ( ; idxCol < CSVMaxCol; ++idxCol )
+ str += csvDelimiter;
+
+ str += m_eol;
+ }
+ }
+ else
+ {
+ kdDebug(30501) << "Export as full mode" << endl;
+ QPtrListIterator<Sheet> it( ksdoc->map()->sheetList() );
+ for( ; it.current(); ++it )
+ {
+ Sheet const * const sheet = it.current();
+
+ if (expDialog && !expDialog->exportSheet( sheet->sheetName() ) )
+ {
+ continue;
+ }
+
+ // Compute the highest row and column indexes containing non-empty cells,
+ // respectively called CSVMaxRow CSVMaxCol.
+ // The CSV will have CSVMaxRow rows, all with CSVMaxCol columns
+ int sheetMaxRow = sheet->maxRow();
+ int sheetMaxCol = sheet->maxColumn();
+ int CSVMaxRow = 0;
+ int CSVMaxCol = 0;
+
+ for ( int row = 1 ; row <= sheetMaxRow ; ++row)
+ {
+ for ( int col = 1 ; col <= sheetMaxCol ; col++ )
+ {
+ if( ! sheet->cellAt( col, row )->isEmpty() )
+ {
+ if ( row > CSVMaxRow )
+ CSVMaxRow = row;
+
+ if ( col > CSVMaxCol )
+ CSVMaxCol = col;
+ }
+ }
+ }
+
+ // Skip the sheet altogether if it is empty
+ if ( CSVMaxRow + CSVMaxCol == 0)
+ continue;
+
+ kdDebug(30501) << "Max row x column: " << CSVMaxRow << " x " << CSVMaxCol << endl;
+
+ // Print sheet separators, except for the first sheet
+ if ( !first || ( expDialog && expDialog->printAlwaysSheetDelimiter() ) )
+ {
+ if ( !first)
+ str += m_eol;
+
+ QString name;
+ if (expDialog)
+ name = expDialog->getSheetDelimiter();
+ else
+ name = "********<SHEETNAME>********";
+ const QString tname( i18n("<SHEETNAME>") );
+ int pos = name.find( tname );
+ if ( pos != -1 )
+ {
+ name.replace( pos, tname.length(), sheet->sheetName() );
+ }
+ str += name;
+ str += m_eol;
+ str += m_eol;
+ }
+
+ first = false;
+
+
+ // this is just a bad approximation which fails for documents with less than 50 rows, but
+ // we don't need any progress stuff there anyway :) (Werner)
+ int value = 0;
+ int step = CSVMaxRow > 50 ? CSVMaxRow/50 : 1;
+
+ // Print the CSV for the sheet data
+ for ( int row = 1, i = 1 ; row <= CSVMaxRow ; ++row, ++i )
+ {
+ if ( i > step )
+ {
+ value += 2;
+ emit sigProgress(value);
+ i = 0;
+ }
+
+ QString collect; // buffer delimiters while reading empty cells
+
+ for ( int col = 1 ; col <= CSVMaxCol ; col++ )
+ {
+ const QString txt = exportCSVCell( sheet, col, row, textQuote, csvDelimiter );
+
+ // if we encounter a non-empty cell, commit the buffered delimiters
+ if (!txt.isEmpty()) {
+ str += collect + txt;
+ collect = QString();
+ }
+
+ collect += csvDelimiter;
+ }
+ // Here, throw away buffered delimiters. They're trailing and therefore
+ // superfluous.
+
+ str += m_eol;
+ }
+ }
+ }
+
+ emit sigProgress(100);
+
+ QFile out(m_chain->outputFile());
+ if ( !out.open( IO_WriteOnly ) )
+ {
+ kdError(30501) << "Unable to open output file!" << endl;
+ out.close();
+ delete expDialog;
+ return KoFilter::StupidError;
+ }
+
+ QTextStream outStream( &out );
+ outStream.setCodec( codec );
+
+ outStream << str;
+
+ out.close();
+ delete expDialog;
+ return KoFilter::OK;
+}
+
+#include <csvexport.moc>
diff --git a/filters/kspread/csv/csvexport.h b/filters/kspread/csv/csvexport.h
new file mode 100644
index 000000000..05ce65a01
--- /dev/null
+++ b/filters/kspread/csv/csvexport.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CSVEXPORT_H
+#define CSVEXPORT_H
+
+#include <qstring.h>
+#include <KoFilter.h>
+
+namespace KSpread
+{
+class Sheet;
+}
+
+class CSVExport : public KoFilter
+{
+ Q_OBJECT
+
+ public:
+ CSVExport(KoFilter * parent, const char * name, const QStringList &);
+ virtual ~CSVExport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString & from, const QCString & to );
+
+ private:
+ QString exportCSVCell( KSpread::Sheet const * const sheet, int col, int row, QChar const & textQuote, QChar delimiter );
+
+ private:
+ QString m_eol; ///< End of line (LF, CR or CRLF)
+};
+
+#endif // CSVEXPORT_H
diff --git a/filters/kspread/csv/csvexportdialog.cpp b/filters/kspread/csv/csvexportdialog.cpp
new file mode 100644
index 000000000..d095a9af2
--- /dev/null
+++ b/filters/kspread/csv/csvexportdialog.cpp
@@ -0,0 +1,332 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+ Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <csvexportdialog.h>
+#include <exportdialogui.h>
+
+#include <kspread_map.h>
+#include <kspread_sheet.h>
+
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qcursor.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qlistview.h>
+#include <qptrlist.h>
+#include <qradiobutton.h>
+#include <qtextstream.h>
+#include <qtabwidget.h>
+#include <qtextcodec.h>
+#include <qvalidator.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kcombobox.h>
+#include <kmessagebox.h>
+#include <kcharsets.h>
+
+using namespace KSpread;
+
+CSVExportDialog::CSVExportDialog( QWidget * parent )
+ : KDialogBase( parent, 0, true, QString::null, Ok | Cancel, No, true ),
+ m_dialog( new ExportDialogUI( this ) ),
+ m_delimiter( "," ),
+ m_textquote('"')
+{
+ kapp->restoreOverrideCursor();
+
+ QStringList encodings;
+ encodings << i18n( "Descriptive encoding name", "Recommended ( %1 )" ).arg( "UTF-8" );
+ encodings << i18n( "Descriptive encoding name", "Locale ( %1 )" ).arg( QTextCodec::codecForLocale()->name() );
+ encodings += KGlobal::charsets()->descriptiveEncodingNames();
+ // Add a few non-standard encodings, which might be useful for text files
+ const QString description(i18n("Descriptive encoding name","Other ( %1 )"));
+ encodings << description.arg("Apple Roman"); // Apple
+ encodings << description.arg("IBM 850") << description.arg("IBM 866"); // MS DOS
+ encodings << description.arg("CP 1258"); // Windows
+
+ m_dialog->comboBoxEncoding->insertStringList(encodings);
+
+ setButtonBoxOrientation ( Vertical );
+
+ setMainWidget(m_dialog);
+
+ // Invalid 'Other' delimiters
+ // - Quotes
+ // - CR,LF,Vetical-tab,Formfeed,ASCII bel
+ QRegExp rx( "^[^\"'\r\n\v\f\a]{0,1}$" );
+ m_delimiterValidator = new QRegExpValidator( rx, m_dialog->m_delimiterBox );
+ m_dialog->m_delimiterEdit->setValidator( m_delimiterValidator );
+
+ connect( m_dialog->m_delimiterBox, SIGNAL( clicked(int) ),
+ this, SLOT( delimiterClicked( int ) ) );
+ connect( m_dialog->m_delimiterEdit, SIGNAL( returnPressed() ),
+ this, SLOT( returnPressed() ) );
+ connect( m_dialog->m_delimiterEdit, SIGNAL( textChanged ( const QString & ) ),
+ this, SLOT(textChanged ( const QString & ) ) );
+ connect( m_dialog->m_comboQuote, SIGNAL( activated( const QString & ) ),
+ this, SLOT( textquoteSelected( const QString & ) ) );
+ connect( m_dialog->m_selectionOnly, SIGNAL( toggled( bool ) ),
+ this, SLOT( selectionOnlyChanged( bool ) ) );
+
+ loadSettings();
+}
+
+CSVExportDialog::~CSVExportDialog()
+{
+ saveSettings();
+ kapp->setOverrideCursor(Qt::waitCursor);
+ delete m_delimiterValidator;
+}
+
+void CSVExportDialog::loadSettings()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("CSVDialog Settings");
+ m_textquote = config->readEntry("textquote", "\"")[0];
+ m_delimiter = config->readEntry("delimiter", ",");
+ const QString codecText = config->readEntry("codec", "");
+ bool selectionOnly = config->readBoolEntry("selectionOnly", false);
+ const QString sheetDelim = config->readEntry("sheetDelimiter", m_dialog->m_sheetDelimiter->text());
+ bool delimAbove = config->readBoolEntry("sheetDelimiterAbove", false);
+ const QString eol = config->readEntry("eol", "\r\n");
+
+ // update widgets
+ if (!codecText.isEmpty()) {
+ m_dialog->comboBoxEncoding->setCurrentText(codecText);
+ }
+ if (m_delimiter == ",") m_dialog->m_radioComma->setChecked(true);
+ else if (m_delimiter == "\t") m_dialog->m_radioTab->setChecked(true);
+ else if (m_delimiter == " ") m_dialog->m_radioSpace->setChecked(true);
+ else if (m_delimiter == ";") m_dialog->m_radioSemicolon->setChecked(true);
+ else {
+ m_dialog->m_radioOther->setChecked(true);
+ m_dialog->m_delimiterEdit->setText(m_delimiter);
+ }
+ m_dialog->m_comboQuote->setCurrentItem(m_textquote == '\'' ? 1
+ : m_textquote == '"' ? 0 : 2);
+ m_dialog->m_selectionOnly->setChecked(selectionOnly);
+ m_dialog->m_sheetDelimiter->setText(sheetDelim);
+ m_dialog->m_delimiterAboveAll->setChecked(delimAbove);
+ if (eol == "\r\n") m_dialog->radioEndOfLineCRLF->setChecked(true);
+ else if (eol == "\r") m_dialog->radioEndOfLineCR->setChecked(true);
+ else m_dialog->radioEndOfLineLF->setChecked(true);
+}
+
+void CSVExportDialog::saveSettings()
+{
+ KConfig *config = kapp->config();
+ config->setGroup("CSVDialog Settings");
+ QString q = m_textquote;
+ config->writeEntry("textquote", q);
+ config->writeEntry("delimiter", m_delimiter);
+ config->writeEntry("codec", m_dialog->comboBoxEncoding->currentText());
+ config->writeEntry("selectionOnly", exportSelectionOnly());
+ config->writeEntry("sheetDelimiter", getSheetDelimiter());
+ config->writeEntry("sheetDelimiterAbove", printAlwaysSheetDelimiter());
+ config->writeEntry("eol", getEndOfLine());
+ config->sync();
+}
+
+void CSVExportDialog::fillSheet( Map * map )
+{
+ m_dialog->m_sheetList->clear();
+ QCheckListItem * item;
+
+ QPtrListIterator<Sheet> it( map->sheetList() );
+ for( ; it.current(); ++it )
+ {
+ item = new QCheckListItem( m_dialog->m_sheetList,
+ it.current()->sheetName(),
+ QCheckListItem::CheckBox );
+ item->setOn(true);
+ m_dialog->m_sheetList->insertItem( item );
+ }
+
+ m_dialog->m_sheetList->setSorting(0, true);
+ m_dialog->m_sheetList->sort();
+ m_dialog->m_sheetList->setSorting( -1 );
+}
+
+QChar CSVExportDialog::getDelimiter() const
+{
+ return m_delimiter[0];
+}
+
+QChar CSVExportDialog::getTextQuote() const
+{
+ return m_textquote;
+}
+
+bool CSVExportDialog::printAlwaysSheetDelimiter() const
+{
+ return m_dialog->m_delimiterAboveAll->isChecked();
+}
+
+QString CSVExportDialog::getSheetDelimiter() const
+{
+ return m_dialog->m_sheetDelimiter->text();
+}
+
+bool CSVExportDialog::exportSheet(QString const & sheetName) const
+{
+ for (QListViewItem * item = m_dialog->m_sheetList->firstChild(); item; item = item->nextSibling())
+ {
+ if (((QCheckListItem * ) item)->isOn())
+ {
+ if ( ((QCheckListItem * ) item)->text() == sheetName )
+ return true;
+ }
+ }
+ return false;
+}
+
+void CSVExportDialog::slotOk()
+{
+ accept();
+}
+
+void CSVExportDialog::slotCancel()
+{
+ reject();
+}
+
+void CSVExportDialog::returnPressed()
+{
+ if ( m_dialog->m_delimiterBox->id( m_dialog->m_delimiterBox->selected() ) != 4 )
+ return;
+
+ m_delimiter = m_dialog->m_delimiterEdit->text();
+}
+
+void CSVExportDialog::textChanged ( const QString & )
+{
+
+ if ( m_dialog->m_delimiterEdit->text().isEmpty() )
+ {
+ enableButtonOK( ! m_dialog->m_radioOther->isChecked() );
+ return;
+ }
+
+ m_dialog->m_radioOther->setChecked ( true );
+ delimiterClicked(4);
+}
+
+void CSVExportDialog::delimiterClicked( int id )
+{
+ enableButtonOK( true );
+
+ //Erase "Other Delimiter" text box if the user has selected one of
+ //the standard options instead (comma, semicolon, tab or space)
+ if (id != 4)
+ m_dialog->m_delimiterEdit->setText("");
+
+ switch (id)
+ {
+ case 0: // comma
+ m_delimiter = ",";
+ break;
+ case 1: // semicolon
+ m_delimiter = ";";
+ break;
+ case 2: // tab
+ m_delimiter = "\t";
+ break;
+ case 3: // space
+ m_delimiter = " ";
+ break;
+ case 4: // other
+ enableButtonOK( ! m_dialog->m_delimiterEdit->text().isEmpty() );
+ m_delimiter = m_dialog->m_delimiterEdit->text();
+ break;
+ }
+}
+
+void CSVExportDialog::textquoteSelected( const QString & mark )
+{
+ m_textquote = mark[0];
+}
+
+void CSVExportDialog::selectionOnlyChanged( bool on )
+{
+ m_dialog->m_sheetList->setEnabled( !on );
+ m_dialog->m_delimiterLineBox->setEnabled( !on );
+
+ if ( on )
+ m_dialog->m_tabWidget->setCurrentPage( 1 );
+}
+
+bool CSVExportDialog::exportSelectionOnly() const
+{
+ return m_dialog->m_selectionOnly->isChecked();
+}
+
+QTextCodec* CSVExportDialog::getCodec(void) const
+{
+ const QString strCodec( KGlobal::charsets()->encodingForName( m_dialog->comboBoxEncoding->currentText() ) );
+ kdDebug(30502) << "Encoding: " << strCodec << endl;
+
+ bool ok = false;
+ QTextCodec* codec = QTextCodec::codecForName( strCodec.utf8() );
+
+ // If QTextCodec has not found a valid encoding, so try with KCharsets.
+ if ( codec )
+ {
+ ok = true;
+ }
+ else
+ {
+ codec = KGlobal::charsets()->codecForName( strCodec, ok );
+ }
+
+ // Still nothing?
+ if ( !codec || !ok )
+ {
+ // Default: UTF-8
+ kdWarning(30502) << "Cannot find encoding:" << strCodec << endl;
+ // ### TODO: what parent to use?
+ KMessageBox::error( 0, i18n("Cannot find encoding: %1").arg( strCodec ) );
+ return 0;
+ }
+
+ return codec;
+}
+
+QString CSVExportDialog::getEndOfLine(void) const
+{
+ QString strReturn;
+ if (m_dialog->radioEndOfLineLF==m_dialog->buttonGroupEndOfLine->selected())
+ strReturn="\n";
+ else if (m_dialog->radioEndOfLineCRLF==m_dialog->buttonGroupEndOfLine->selected())
+ strReturn="\r\n";
+ else if (m_dialog->radioEndOfLineCR==m_dialog->buttonGroupEndOfLine->selected())
+ strReturn="\r";
+ else
+ strReturn="\n";
+
+ return strReturn;
+}
+
+#include "csvexportdialog.moc"
+
diff --git a/filters/kspread/csv/csvexportdialog.h b/filters/kspread/csv/csvexportdialog.h
new file mode 100644
index 000000000..0ca1f5ba9
--- /dev/null
+++ b/filters/kspread/csv/csvexportdialog.h
@@ -0,0 +1,72 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+ Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CSVEXPORTDIALOG_H
+#define CSVEXPORTDIALOG_H
+
+#include <kdialogbase.h>
+
+class ExportDialogUI;
+class QValidator;
+
+namespace KSpread
+{
+class Map;
+}
+
+class CSVExportDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ CSVExportDialog(QWidget * parent);
+ ~CSVExportDialog();
+
+ QChar getDelimiter() const;
+ QChar getTextQuote() const;
+ bool exportSheet( QString const & sheetName ) const;
+ bool printAlwaysSheetDelimiter() const;
+ QString getSheetDelimiter() const;
+ bool exportSelectionOnly() const;
+
+ void fillSheet( KSpread::Map * map );
+ QString getEndOfLine(void) const;
+ QTextCodec* getCodec(void) const;
+
+ private:
+ void loadSettings();
+ void saveSettings();
+ ExportDialogUI * m_dialog;
+
+ QValidator* m_delimiterValidator;
+ QString m_delimiter;
+ QChar m_textquote;
+
+ private slots:
+ void slotOk();
+ void slotCancel();
+
+ void returnPressed();
+ void delimiterClicked( int id );
+ void textChanged ( const QString & );
+ void textquoteSelected( const QString & mark );
+ void selectionOnlyChanged( bool );
+};
+
+#endif
diff --git a/filters/kspread/csv/csvimport.cc b/filters/kspread/csv/csvimport.cc
new file mode 100644
index 000000000..49792406d
--- /dev/null
+++ b/filters/kspread/csv/csvimport.cc
@@ -0,0 +1,264 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+ Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <csvimport.h>
+
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+#include <KoFilterChain.h>
+#include <KoFilterManager.h>
+#include <kspread_doc.h>
+#include <kspread_global.h>
+#include <kspread_map.h>
+#include <kspread_sheet.h>
+#include <kspread_style.h>
+#include <kspread_style_manager.h>
+#include <kspread_cell.h>
+
+#include <csvdialog.h>
+
+using namespace KSpread;
+
+// hehe >:->
+
+/*
+ To generate a test CSV file:
+
+ perl -e '$i=0;while($i<30000) { print rand().",".rand()."\n"; $i++ }' > file.csv
+*/
+
+typedef KGenericFactory<CSVFilter, KoFilter> CSVImportFactory;
+K_EXPORT_COMPONENT_FACTORY( libcsvimport, CSVImportFactory( "kofficefilters" ) )
+
+CSVFilter::CSVFilter(KoFilter *, const char*, const QStringList&) :
+ KoFilter() {
+}
+
+KoFilter::ConversionStatus CSVFilter::convert( const QCString& from, const QCString& to )
+{
+ QString file( m_chain->inputFile() );
+ KoDocument* document = m_chain->outputDocument();
+
+ if ( !document )
+ return KoFilter::StupidError;
+
+ kdDebug(30501) << "here we go... " << document->className() << endl;
+
+ if ( !::qt_cast<const KSpread::Doc *>( document ) )
+ {
+ kdWarning(30501) << "document isn't a KSpread::Doc but a " << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+ if(from!="text/x-csv" && from!="text/plain" || to!="application/x-kspread")
+ {
+ kdWarning(30501) << "Invalid mimetypes " << from << " " << to << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ kdDebug(30501) << "...still here..." << endl;
+
+ Doc *ksdoc = static_cast<Doc *>( document ); // type checked above
+
+ if(ksdoc->mimeType()!="application/x-kspread")
+ {
+ kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ QFile in(file);
+ if(!in.open(IO_ReadOnly)) {
+ KMessageBox::sorry( 0L, i18n("CSV filter cannot open input file - please report.") );
+ in.close();
+ return KoFilter::FileNotFound;
+ }
+
+ QString csv_delimiter;
+ // ###### FIXME: disabled for now
+ //if (!config.isNull())
+ // csv_delimiter = config[0];
+
+ QByteArray inputFile( in.readAll() );
+ in.close();
+
+ CSVDialog *dialog = new CSVDialog(0L, inputFile, csv_delimiter );
+ if (!m_chain->manager()->getBatchMode() && !dialog->exec())
+ return KoFilter::UserCancelled;
+ inputFile.resize( 0 ); // Release memory (input file content)
+
+ ElapsedTime t( "Filling data into document" );
+
+ Cell*cell;
+ Sheet *sheet=ksdoc->map()->addNewSheet();
+
+ int numRows = dialog->getRows();
+ int numCols = dialog->getCols();
+
+ if (numRows == 0)
+ ++numRows;
+
+ int step = 100 / numRows * numCols;
+ int value = 0;
+
+ emit sigProgress(value);
+ QApplication::setOverrideCursor(Qt::waitCursor);
+
+ int i;
+ double init = sheet->nonDefaultColumnFormat( 1 )->dblWidth();
+ QMemArray<double> widths( numCols );
+ for ( i = 0; i < numCols; ++i )
+ widths[i] = init;
+
+ Cell* c = sheet->nonDefaultCell( 1, 1 );
+ QFontMetrics fm( c->format()->textFont( 1, 1 ) );
+
+ Style * s = ksdoc->styleManager()->defaultStyle();
+
+ for ( int row = 0; row < numRows; ++row )
+ {
+ for (int col = 0; col < numCols; ++col)
+ {
+ value += step;
+ emit sigProgress(value);
+ const QString text( dialog->getText( row, col ) );
+
+ // ### FIXME: how to calculate the width of numbers (as they might not be in the right format)
+ const double len = fm.width( text );
+ if ( len > widths[col] )
+ widths[col] = len;
+
+ switch (dialog->getHeader(col))
+ {
+ case CSVDialog::TEXT:
+ //see CSVDialog::accept(), Tomas introduced the Generic format between KOffice 1.3 and 1.4
+ //the Insert->External Data-> ... dialog uses the generic format for everything (see mentioned method)
+ //I will use this approach only for the TEXT format in the CSV import filter... (raphael)
+ //### FIXME: long term solution is to allow to select Generic format ("autodetect") in the dialog and make it the default
+
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setCellText( text );
+
+ cell->format()->setFormatType (Generic_format);
+
+ /* old code
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setCellText( text, true );
+ */
+ break;
+ // ### TODO: put the code for the different numbers together (at least partially)
+ case CSVDialog::NUMBER:
+ {
+ bool ok = false;
+ double d = ksdoc->locale()->readNumber( text, &ok );
+ // If not, try with the '.' as decimal separator
+ if ( !ok )
+ d = text.toDouble( &ok );
+ if ( !ok )
+ {
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setCellText( text, true );
+ }
+ else
+ {
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setNumber( d );
+ }
+ cell->format()->setPrecision( 2 );
+ break;
+ }
+ case CSVDialog::COMMANUMBER:
+ {
+ bool ok = false;
+ QString tmp ( text );
+ tmp.remove ( QRegExp( "[^0-9,Ee+-]" ) ); // Keep only 0 to 9, comma, E, e, plus, minus
+ tmp.replace ( ',', '.' );
+ kdDebug(30501) << "Comma: " << text << " => " << tmp << endl;
+ const double d = tmp.toDouble( &ok );
+ if ( !ok )
+ {
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setCellText( text, true );
+ }
+ else
+ {
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setNumber( d );
+ }
+ cell->format()->setPrecision( 2 );
+ break;
+ }
+ case CSVDialog::POINTNUMBER:
+ {
+ bool ok = false;
+ QString tmp ( text );
+ tmp.remove ( QRegExp( "[^0-9\\.EeD+-]" ) ); // Keep only 0 to 9, dot, E, e, D, plus, minus
+ tmp.replace ( 'D', 'E' ); // double from FORTRAN use D instead of E
+ kdDebug(30501) << "Point: " << text << " => " << tmp << endl;
+ const double d = tmp.toDouble( &ok );
+ if ( !ok )
+ {
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setCellText( text, true );
+ }
+ else
+ {
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setNumber( d );
+ }
+ cell->format()->setPrecision( 2 );
+ break;
+ }
+ case CSVDialog::DATE:
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setCellText( text );
+ cell->format()->setFormatType( ShortDate_format );
+ break;
+ case CSVDialog::CURRENCY:
+ cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
+ cell->setCellText( text, false );
+ cell->format()->setFormatType( Money_format );
+ cell->format()->setPrecision( 2 );
+ break;
+ }
+ }
+ }
+
+ emit sigProgress( 98 );
+
+ ElapsedTime t2( "Resizing columns" );
+ for ( i = 0; i < numCols; ++i )
+ {
+ ColumnFormat * c = sheet->nonDefaultColumnFormat( i + 1 );
+ c->setDblWidth( widths[i] );
+ }
+
+ emit sigProgress( 100 );
+ QApplication::restoreOverrideCursor();
+ delete dialog;
+
+ return KoFilter::OK;
+}
+
+#include <csvimport.moc>
diff --git a/filters/kspread/csv/csvimport.h b/filters/kspread/csv/csvimport.h
new file mode 100644
index 000000000..f89f16e60
--- /dev/null
+++ b/filters/kspread/csv/csvimport.h
@@ -0,0 +1,35 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CSVFILTER_H
+#define CSVFILTER_H
+
+#include <KoFilter.h>
+
+class CSVFilter : public KoFilter {
+
+ Q_OBJECT
+
+public:
+ CSVFilter(KoFilter *parent, const char *name, const QStringList&);
+ virtual ~CSVFilter() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+};
+#endif // CSVFILTER_H
diff --git a/filters/kspread/csv/dialogui.ui b/filters/kspread/csv/dialogui.ui
new file mode 100644
index 000000000..9381676cc
--- /dev/null
+++ b/filters/kspread/csv/dialogui.ui
@@ -0,0 +1,554 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>DialogUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DialogUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>577</width>
+ <height>410</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTable" row="1" column="0">
+ <property name="name">
+ <cstring>m_sheet</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="numRows">
+ <number>0</number>
+ </property>
+ <property name="numCols">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>tabWidget2</cstring>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Encoding</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;ncoding:</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comboBoxEncoding</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>comboBoxEncoding</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>106</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>60</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Common</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup" row="0" column="0" rowspan="2" colspan="1">
+ <property name="name">
+ <cstring>m_delimiterBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Delimiter</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>m_radioComma</cstring>
+ </property>
+ <property name="text">
+ <string>Comma</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="1">
+ <property name="name">
+ <cstring>m_radioSemicolon</cstring>
+ </property>
+ <property name="text">
+ <string>Semicolon</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>m_radioTab</cstring>
+ </property>
+ <property name="text">
+ <string>Tabulator</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="1">
+ <property name="name">
+ <cstring>m_radioSpace</cstring>
+ </property>
+ <property name="text">
+ <string>Space</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_radioOther</cstring>
+ </property>
+ <property name="text">
+ <string>Other</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="2">
+ <property name="name">
+ <cstring>m_delimiterEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>m_ignoreDuplicates</cstring>
+ </property>
+ <property name="text">
+ <string>Ignore duplicate delimiters</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Text&amp;quote:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_comboQuote</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Format:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_formatComboBox</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="2">
+ <property name="name">
+ <cstring>m_formatComboBox</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="2">
+ <item>
+ <property name="text">
+ <string>"</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>'</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_comboQuote</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="0" column="3">
+ <property name="name">
+ <cstring>spacer19</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="3">
+ <property name="name">
+ <cstring>spacer20</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Ranges</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QFrame" row="0" column="0">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox" row="0" column="3">
+ <property name="name">
+ <cstring>m_rowEnd</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>to</string>
+ </property>
+ <property name="textFormat">
+ <enum>AutoText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>Import lines:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="3">
+ <property name="name">
+ <cstring>m_colEnd</cstring>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_colStart</cstring>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>to</string>
+ </property>
+ <property name="textFormat">
+ <enum>AutoText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_rowStart</cstring>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel3_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>Import columns:</string>
+ </property>
+ </widget>
+ <spacer row="1" column="4" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>468</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="0" column="4" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>468</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="0" rowspan="1" colspan="5">
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>611</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="2" column="5">
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>71</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="2" column="6">
+ <property name="name">
+ <cstring>m_updateButton</cstring>
+ </property>
+ <property name="text">
+ <string>Update</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kcombobox.h</includehint>
+</includehints>
+</UI>
diff --git a/filters/kspread/csv/exportdialogui.ui b/filters/kspread/csv/exportdialogui.ui
new file mode 100644
index 000000000..5bb78dea4
--- /dev/null
+++ b/filters/kspread/csv/exportdialogui.ui
@@ -0,0 +1,510 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>ExportDialogUI</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ExportDialogUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>520</width>
+ <height>496</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="1" column="0">
+ <property name="name">
+ <cstring>m_tabWidget</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>encodingPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Encoding</string>
+ </attribute>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;ncoding:</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comboBoxEncoding</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>comboBoxEncoding</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>106</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroupEndOfLine</cstring>
+ </property>
+ <property name="title">
+ <string>End of Line</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioEndOfLineLF</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;UNIX style (recommended; line feed only)</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioEndOfLineCRLF</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Windows style (carriage return and line feed)</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioEndOfLineCR</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;MacOS style (carriage return only)</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>96</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Sheets</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QListView" row="2" column="0">
+ <column>
+ <property name="text">
+ <string>Available Sheets</string>
+ </property>
+ <property name="clickable">
+ <bool>false</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_sheetList</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Select sheets to export:</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_delimiterLineBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Delimiter Line</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLineEdit" row="0" column="0">
+ <property name="name">
+ <cstring>m_sheetDelimiter</cstring>
+ </property>
+ <property name="text">
+ <string>********&lt;SHEETNAME&gt;********</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel6</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;SHEETNAME&gt; gets replaced by the name of the next sheet.</string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>m_delimiterAboveAll</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Print delimiter line above every sheet</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab2</cstring>
+ </property>
+ <attribute name="title">
+ <string>Cells</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>m_delimiterBox</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Delimiter</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>m_radioComma</cstring>
+ </property>
+ <property name="text">
+ <string>Comma</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="1">
+ <property name="name">
+ <cstring>m_radioSemicolon</cstring>
+ </property>
+ <property name="text">
+ <string>Semicolon</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>m_radioTab</cstring>
+ </property>
+ <property name="text">
+ <string>Tabulator</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="1">
+ <property name="name">
+ <cstring>m_radioSpace</cstring>
+ </property>
+ <property name="text">
+ <string>Space</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="2">
+ <property name="name">
+ <cstring>m_radioOther</cstring>
+ </property>
+ <property name="text">
+ <string>Other:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="2">
+ <property name="name">
+ <cstring>m_delimiterEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>32767</height>
+ </size>
+ </property>
+ <property name="maxLength">
+ <number>1</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Cells</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>m_quotesLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Quotes:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>"</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>'</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>m_comboQuote</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>Spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>81</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_selectionOnly</cstring>
+ </property>
+ <property name="text">
+ <string>Export selection only</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/filters/kspread/csv/kspread_csv_export.desktop b/filters/kspread/csv/kspread_csv_export.desktop
new file mode 100644
index 000000000..c41582342
--- /dev/null
+++ b/filters/kspread/csv/kspread_csv_export.desktop
@@ -0,0 +1,73 @@
+[Desktop Entry]
+Type=Service
+Name=CSV Export Filter for KSpread
+Name[af]=Cvs Voer uit Filter vir Kspread
+Name[az]=KSpread üçün CSV Vermə Süzgəci
+Name[bg]=Филтър за експортиране от KSpread в CSV
+Name[br]=Sil ezporzh CSV evit KSpread
+Name[bs]=CSV Export Filter za KSpread
+Name[ca]=Filtre d'exportació CSV per a KSpread
+Name[cs]=CSV exportní filtr pro KSpread
+Name[cy]=Hidlen Allforio CSV i Kontour
+Name[da]=CSV-eksportfilter for KSpread
+Name[de]=KSpread CSV-Exportfilter
+Name[el]=Φίλτρο εξαγωγής CSV για το KSpread
+Name[eo]=CSV-Eksportfiltrilo por KSpread
+Name[es]=Filtro de exportación CSV para KSpread
+Name[et]=KSpreadi CSV ekspordifilter
+Name[eu]=KSpread-en CSV esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات CSV برای KSpread
+Name[fi]=CSV-vientisuodin KSpeadiin
+Name[fo]=CSV-útflyting til KRokni
+Name[fr]=Filtre d'exportation CSV de KSpread
+Name[fy]=CSV-Eksportfilter foar KSpread
+Name[gl]=Filtro de Exportación de CSV para KSpread
+Name[he]=מסנן ייצוא מ־KSpread ל־CSV
+Name[hi]=के-स्प्रेड के लिए सीएसवी निर्यात छननी
+Name[hr]=CSV filtar izvoza za KSpread
+Name[hu]=CSV exportszűrő a KSpreadhez
+Name[id]=Filter Ekspor CSV untuk K Spread
+Name[is]=CSV útflutningssía fyrir KSpread
+Name[it]=Filtro di esportazione CSV per KSpread
+Name[ja]=KSpread CSV エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ CSV សម្រាប់ KSpread
+Name[lo]= ຕົວຕອງການສົ່ງອອກ CSV ຂອງກະດາດຄຳນວນ K
+Name[lt]=KSpread eksporto filtras CSV
+Name[lv]=CSV eksporta filtrs priekš KSpread
+Name[mk]=CSV извозен филтер за KSpread
+Name[ms]=Penapis Eksport CSV bagi KSpread
+Name[mt]=Filtru għall-esportazzjoni ta' files CSV minn ġo KSpread
+Name[nb]=CSV-eksportfilter for KSpread
+Name[nds]=CSV-Exportfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि CSV निर्यात फिल्टर
+Name[nl]=CSV-Exportfilter voor KSpread
+Name[nn]=CSV-eksportfilter for KSpread
+Name[pl]=Filtr eksportu do formatu CSV dla KSpread
+Name[pt]=Filtro de Exportação de CSV para o KSpread
+Name[pt_BR]=Filtro de exportação CSV para o KSpread
+Name[ro]=Filtru de exportare KSpread pentru CSV
+Name[ru]=Фильтр экспорта таблиц KSpread в CSV
+Name[se]=KSpread:a CSV-olggosfievrridansilli
+Name[sk]=CSV filter pre export z KSpread
+Name[sl]=Izvozni filter CSV za KSpread
+Name[sr]=KSpread-ов филтер за извоз у CSV
+Name[sr@Latn]=KSpread-ov filter za izvoz u CSV
+Name[sv]=CSV-exportfilter för Kspread
+Name[ta]=KSpread க்கான CSV ஏற்றுமதி வடிகட்டி
+Name[tg]=CSV Филтри Содирот барои KSpread
+Name[th]=ตัวกรองการส่งออก CSV ของกระดาษคำนวณ K
+Name[tr]=KSpread CSV Aktarma Filtresi
+Name[uk]=Фільтр експорту CSV для KSpread
+Name[uz]=KSpread uchun CSV eksport filteri
+Name[uz@cyrillic]=KSpread учун CSV экспорт филтери
+Name[ven]=Filithara yau bvisela nnda ya CSV yau phadaladza ha K
+Name[wa]=Passete CSV di rexhowe po KSpread
+Name[xh]=CSV Yesihluzi Sokurhweba ngaphandle se KSpread
+Name[zh_CN]=KSpread 的 CSV 导出过滤器
+Name[zh_TW]=KSpread 的 CSV 匯出過濾程式
+Name[zu]=CSV ICSV Export Filter for KSpread
+X-KDE-Export=text/x-csv,text/plain
+X-KDE-Import=application/x-kspread
+X-KDE-Weight=50
+X-KDE-Library=libcsvexport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/csv/kspread_csv_import.desktop b/filters/kspread/csv/kspread_csv_import.desktop
new file mode 100644
index 000000000..0b87e54a1
--- /dev/null
+++ b/filters/kspread/csv/kspread_csv_import.desktop
@@ -0,0 +1,72 @@
+[Desktop Entry]
+Type=Service
+Name=CSV Import Filter for KSpread
+Name[af]=Cvs In voer Filter vir Kspread
+Name[az]=KSpread üçün CSV Alma Süzgəci
+Name[bg]=Филтър за импортиране от CSV в KSpread
+Name[br]=Sil enporzh CSV evit KSpread
+Name[bs]=CSV Import Filter za KSpread
+Name[ca]=Filtre d'importació CSV per a KSpread
+Name[cs]=CSV importní filtr pro KSpread
+Name[cy]=Hidlen Fewnforio CSV i Kontour
+Name[da]=CSV-importfilter for KSpread
+Name[de]=KSpread CSV-Importfilter
+Name[el]=Φίλτρο εισαγωγής CSV για το KSpread
+Name[eo]=CSV-importfiltrilo por KSpread
+Name[es]=Filtro de importación CSV para KSpread
+Name[et]=KSpreadi CSV impordifilter
+Name[eu]=KSpread-en CSV inportaziorako iragazkia
+Name[fa]=پالایۀ واردات CSV برای KSpread
+Name[fi]=CSV-tuontisuodin KSpeadiin
+Name[fr]=Filtre d'importation CSV de KSpread
+Name[fy]=CSV-Ymportfilter foar KSpread
+Name[ga]=Scagaire Iompórtála CSV le haghaidh KSpread
+Name[gl]=Filtro de Importación de CSV para KSpread
+Name[he]=מסנן ייבוא מ־CSV ל־KSpread
+Name[hi]=के-स्प्रेड के लिए सीएसवी आयात छननी
+Name[hr]=CSV filtar uvoza za KSpread
+Name[hu]=CSV importszűrő a KSpreadhez
+Name[id]=Filter Impor CSV untuk KSpread
+Name[is]=CSV innflutningssía fyrir KSpread
+Name[it]=Filtro di importazione CSV per KSpread
+Name[ja]=KSpread CSV インポートフィルタ
+Name[km]=តម្រង​នាំចូល CSV សម្រាប់ KSpread
+Name[lo]= ຕົວຕອງການນຳເຂົ້າ CSV ຂອງກະດາດຄຳນວນ K
+Name[lt]=CSV importo filtras skirtas KSpread
+Name[lv]=CSV importa filtrs priekš KSpread
+Name[mk]=CSV увозен филтер за KSpread
+Name[ms]=Penapis Import CSV bagi KSpread
+Name[mt]=Filtru għall-importazzjoni ta' CSV ġo KSpread
+Name[nb]=CSV-importfilter for KSpread
+Name[nds]=CSV-Importfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि CSV आयात फिल्टर
+Name[nl]=CSV-Importfilter voor KSpread
+Name[nn]=CSV-importfilter for KSpread
+Name[pl]=Filtr importu formatu CSV dla KSpread
+Name[pt]=Filtro de Importação de CSV para o KSpread
+Name[pt_BR]=Filtro de importação CSV para o KSpread
+Name[ro]=Filtru de importare KSpread pentru CSV
+Name[ru]=Фильтр импорта файлов CSV в KSpread
+Name[se]=KSpread:a CSV-sisafievrridansilli
+Name[sk]=Filter pre import CVS pre KSpread
+Name[sl]=Uvozni filter CSV za KSpread
+Name[sr]=KSpread-ов филтер за увоз из CSV-а
+Name[sr@Latn]=KSpread-ov filter za uvoz iz CSV-a
+Name[sv]=CSV-importfilter för Kspread
+Name[ta]=KSpread க்கான CSV இறக்குமதி வடிகட்டி
+Name[tg]=CSV Филтри Воридот барои KSpread
+Name[th]=ตัวกรองการนำเข้า CSV ของกระดาษคำนวณ K
+Name[tr]=KSpread CSV Alma Filtresi
+Name[uk]=Фільтр імпорту CSV для KSpread
+Name[uz]=KSpread uchun CSV import filteri
+Name[uz@cyrillic]=KSpread учун CSV импорт филтери
+Name[ven]=Filithara yau u dzhenisa nga ngomu ya CSV ya u phadaladzhwa ha K
+Name[wa]=Passete CSV d' intrêye po KSpread
+Name[xh]=CSV Yesihluzi Sokurhweba se KSpread
+Name[zh_CN]=KSpread 的 CSV 导入过滤器
+Name[zh_TW]=KSpread 的 CSV 匯入過濾程式
+X-KDE-Export=application/x-kspread
+X-KDE-Import=text/x-csv,text/plain
+X-KDE-Weight=50
+X-KDE-Library=libcsvimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/csv/status.html b/filters/kspread/csv/status.html
new file mode 100644
index 000000000..c4379ade8
--- /dev/null
+++ b/filters/kspread/csv/status.html
@@ -0,0 +1,202 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>KOffice filters status: CSV FILTER</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<A NAME="START">&nbsp;</A>
+
+<BR>
+<center>
+ <h1>
+ KOffice filters status: &nbsp;&nbsp;<i>CSV - Comma Separated Values</i>
+ </h1>
+</center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%">
+
+<font size="-1"><b>
+ <A HREF="#import">Import</A> |
+ <A HREF="#export">Export</A>
+</b></font>
+
+<BR><BR><BR>
+<center><a NAME="import"></a></center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+
+ <tr BGCOLOR="#DDFFDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>
+ Import CSV for KSpread<BR>
+ <BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>9 jan 2001</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>- Can import CVS documents</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>
+ - Automatically adjust the columns width to their contents.<BR>
+ Will be difficult, as we don't know the font used...<BR>
+ Solution ? Set a default font _in_ the filter, and use it to <BR>
+ compute the width...
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td>
+ <A HREF="mailto:faure@kde.org">David Faure</A>&nbsp;&nbsp;
+ <A HREF="mailto:trobin@kde.org">Werner Trobin</A>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>
+ <H2>Design</H2>
+<PRE>
+The CSV import filter uses a hand-made state machine to parse the CSV file.
+This allows to handle quoted fields (such as those containing the CSV delimiter),
+as well as the double-quote character itself (which then appears twice, and
+always in a quoted field).
+Just to make sure about the vocabulary, I call a quoted field a field
+starting with " and finishing with ".
+
+Let's try to draw the graph of the state machine using ascii-art.
+
+
+ DEL or EOL
+ /--\
+ | |
+ | v &quot;
+ /--[START]-------->[QUOTED_FIELD] (**)
+ other| ^ ^ | ^
+ (*) | | | DEL or | &quot; | &quot; (*)
+ | | | EOL v | other
+ | | \----[MAYBE_END_OF_QUOTED_FIELD]--------> Error
+ | |
+ | | DEL or
+ | | EOL
+ v |
+ [NORMAL_FIELD] (**)
+
+DEL : CSV delimiter (depends on locale !). Often comma, sometimes semicolon.
+EOL : End Of Line.
+(*) : added to the current field
+(**) : implicit loop on itself, labeled &quot;other (*)&quot;
+
+
+Ugly isn't it ? :) One can't be good in drawings AND in hacking :)
+
+That's all. For the rest, see csvfilter.cc
+
+David Faure &lt;faure@kde.org&gt;, 1999
+</PRE>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+<br><br><br>
+
+<hr NOSHADE SIZE=1>
+<br><br><br>
+
+
+<center>
+ <a NAME="export"></a>
+</center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+ <tr BGCOLOR="#FFDDDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>Export KSpread to CSV<BR><BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td>
+ <A HREF="mailto:faure@kde.org">David Faure</A>&nbsp;&nbsp;
+ <A HREF="mailto:trobin@kde.org">Werner Trobin</A>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>---</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+</body>
+</html>
diff --git a/filters/kspread/csv/xmltree.cc b/filters/kspread/csv/xmltree.cc
new file mode 100644
index 000000000..e6fdf124d
--- /dev/null
+++ b/filters/kspread/csv/xmltree.cc
@@ -0,0 +1,154 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <xmltree.h>
+
+#include <qdatetime.h>
+#include <kdebug.h>
+
+
+XMLTree::XMLTree(QDomDocument &qdoc) : root(qdoc)
+{
+ root=QDomDocument("spreadsheet");
+ root.appendChild( root.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
+ doc = root.createElement( "spreadsheet" );
+
+ doc.setAttribute("editor", "KSpread CSV Filter");
+ doc.setAttribute("mime", "application/x-kspread");
+ root.appendChild(doc);
+
+ QDomElement paper = root.createElement("paper");
+ paper.setAttribute("format", "A4");
+ paper.setAttribute("orientation", "Portrait");
+ QDomElement borders = root.createElement( "borders" );
+ borders.setAttribute( "left", 20 );
+ borders.setAttribute( "top", 20 );
+ borders.setAttribute( "right", 20 );
+ borders.setAttribute( "bottom", 20 );
+ paper.appendChild( borders );
+ doc.appendChild(paper);
+
+ map = root.createElement("map");
+ doc.appendChild(map);
+
+ sheet = root.createElement("table");
+
+ sheet.setAttribute("name", "foobar");
+ map.appendChild(sheet);
+
+ row = 1;
+ column = 1;
+}
+
+XMLTree::~XMLTree()
+{
+ //if(root) // We're using fancy references, now! (Werner)
+ //delete root;
+}
+
+// Not needed anymore (Werner)
+//const QString XMLTree::part()
+//{
+// QString s;
+// QTextStream t(s, IO_WriteOnly);
+
+// QTime tmr;
+// tmr.start();
+// kdDebug(30501) << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" << endl;
+
+// root.save(t); // Why does this take sooooo long (approx. 8s on my Athlon 500 with a
+ // quite small file :( )
+
+// David: gdb says that QString::replace calls itself recursively an enormous amount of time
+// This is called by QStringBuffer::writeBlock (), called by QTextStream::writeBlock ()
+// called by QTextStream::operator<< () in QDOM_AttrPrivate::save ().
+//
+// And this looks related to the UTF 8 encoding ...
+
+// kdDebug(30501) << (const char*)QString::number((int)tmr.elapsed()) << endl;
+// kdDebug(30501) << "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" << endl;
+
+// t << '\0';
+
+// return s;
+//}
+
+bool XMLTree::cell( const QString & contents )
+{
+ QDomElement e = root.createElement("cell");
+ //e.appendChild(getFormat(xf));
+ //e.appendChild(getFont(xf));
+
+ e.setAttribute("row", row);
+ e.setAttribute("column", column++);
+
+ QDomElement format=root.createElement("format");
+ format.setAttribute("float", "3");
+ format.setAttribute("alignY", "2");
+ format.setAttribute("floatcolor", "2");
+ format.setAttribute("faktor", "1");
+ format.setAttribute("precision", "-1");
+ format.setAttribute("align", "4");
+
+ QDomElement pen=root.createElement("pen");
+ pen.setAttribute("width", "1");
+ pen.setAttribute("style", "0");
+ pen.setAttribute("color", "#000000");
+
+ QDomElement lborder=root.createElement("left-border");
+ lborder.appendChild(pen);
+ format.appendChild(lborder);
+
+ pen=root.createElement("pen");
+ pen.setAttribute("width", "1");
+ pen.setAttribute("style", "0");
+ pen.setAttribute("color", "#000000");
+
+ QDomElement tborder=root.createElement("top-border");
+ tborder.appendChild(pen);
+ format.appendChild(tborder);
+
+ pen=root.createElement("pen");
+ pen.setAttribute("width", "1");
+ pen.setAttribute("style", "0");
+ pen.setAttribute("color", "#000000");
+
+ QDomElement fdia=root.createElement("fall-diagonal");
+ fdia.appendChild(pen);
+ format.appendChild(fdia);
+
+ pen=root.createElement("pen");
+ pen.setAttribute("width", "1");
+ pen.setAttribute("style", "0");
+ pen.setAttribute("color", "#000000");
+
+ QDomElement udia=root.createElement("up-diagonal");
+ udia.appendChild(pen);
+ format.appendChild(udia);
+
+ e.appendChild(format);
+
+ QDomElement text=root.createElement("text");
+ text.appendChild(root.createTextNode(contents));
+ e.appendChild(text);
+
+ sheet.appendChild(e);
+
+ return true;
+}
diff --git a/filters/kspread/csv/xmltree.h b/filters/kspread/csv/xmltree.h
new file mode 100644
index 000000000..919acc8f3
--- /dev/null
+++ b/filters/kspread/csv/xmltree.h
@@ -0,0 +1,53 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef XMLTREE_H
+#define XMLTREE_H
+
+#include <qdom.h>
+#include <qmemarray.h>
+#include <qtextstream.h>
+
+class XMLTree
+{
+
+public:
+ // Create a tree.
+ // inputFileName is only used in order to name the sheet
+ XMLTree(QDomDocument &qdoc);
+ ~XMLTree();
+
+ // Return the whole XML as QString
+ //const QString part();
+
+ // Create a new cell
+ bool cell( const QString & contents );
+
+ // Tell about an empty cell (doesn't create it, just skips)
+ void emptycell() { column ++; } // easy heh ? ;)
+
+ // Go to new line
+ void newline() { row ++; column = 1; }
+
+private:
+ int row, column;
+ QDomDocument &root;
+ QDomElement doc, map, sheet;
+};
+#endif // XMLTREE_H
diff --git a/filters/kspread/dbase/Makefile.am b/filters/kspread/dbase/Makefile.am
new file mode 100644
index 000000000..29322ab43
--- /dev/null
+++ b/filters/kspread/dbase/Makefile.am
@@ -0,0 +1,17 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) $(KOFFICE_INCLUDES) $(all_includes)
+
+####### Files
+
+kde_module_LTLIBRARIES = libdbaseimport.la
+
+libdbaseimport_la_SOURCES = dbaseimport.cc dbase.cpp
+libdbaseimport_la_LIBADD = $(KOFFICE_LIBS)
+libdbaseimport_la_LDFLAGS = -module $(KDE_PLUGIN)
+noinst_HEADERS = dbaseimport.h dbase.h
+
+METASOURCES = AUTO
+
+service_DATA = kspread_dbase_import.desktop
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/dbase/dbase.cpp b/filters/kspread/dbase/dbase.cpp
new file mode 100644
index 000000000..67780f335
--- /dev/null
+++ b/filters/kspread/dbase/dbase.cpp
@@ -0,0 +1,251 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 by Thomas Franke and Andreas Pietzowski <andreas@pietzowski.de>
+ Ariya Hidayat <ariyahidayat@yahoo.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+
+#include <qdatetime.h>
+#include <qdatastream.h>
+#include <qfile.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+
+#include <dbase.h>
+
+DBase::DBase(): m_recordCount( 0 )
+{
+ fields.setAutoDelete( true );
+}
+
+DBase::~DBase()
+{
+ fields.clear();
+ close();
+}
+
+ // Headerdefinition in dBASE
+ //
+ // Type char Content
+ //
+ // unsigned char version 0 dBASE-Version (3)
+ // unsigned char last_update[3] 1-3 Date of last update
+ // unsigned long records 4-7 Number of records
+ // unsigned short header_length 8-9 headerlength
+ // unsigned short record_length 10-11 recordlength
+ // unsigned char reserved[20] 12-31 reserverd info from dBase
+ //
+
+bool DBase::load( const QString& filename )
+{
+
+ m_file.setName( filename );
+ if( !m_file.open(IO_ReadOnly) )
+ return false;
+
+ m_stream.setDevice( &m_file );
+ m_stream.setByteOrder( QDataStream::LittleEndian );
+
+ unsigned filesize = m_file.size();
+
+ // read dBASE version
+ Q_UINT8 ver;
+ m_stream >> ver;
+ m_version = ver & 0x7f; // bit 7: has memo ?
+
+ // only dBASE V.3 is supported
+ if ( m_version != 3 )
+ return false;
+
+ // date of last update
+ Q_UINT8 y, m, d;
+ m_stream >> y >> m >> d;
+ // because dBASE saves 102 instead of 2002 (very Y2K-save ;-)
+ m_lastUpdate.setYMD( y+1900, m, d );
+
+ // check for valid date
+ if( !m_lastUpdate.isValid() ) return false;
+
+ // number of records
+ Q_UINT32 norec;
+ m_stream >> norec;
+ m_recordCount = norec;
+
+ // header-length
+ Q_UINT16 header_length;
+ m_stream >> header_length;
+ m_headerLength = header_length;
+
+ // record-length
+ Q_UINT16 record_length;
+ m_stream >> record_length;
+ m_recordLength = record_length;
+
+ // read the remaining chars
+ Q_UINT8 dummy;
+ for (int foo = 0; foo < 20; ++foo)
+ m_stream >> dummy;
+
+ // size of file must match
+ if( filesize < m_headerLength + m_recordLength * m_recordCount )
+ return false;
+
+ // Now read the headers of the columns and their type
+
+ // Type char Content
+ //
+ // unsigned char field_name[11] 0-10 Fieldname
+ // unsigned char field_type 11 Fieldtype
+ // unsigned long field_address 12-15 Fielddataaddress
+ // unsigned char field_length 16 Fieldlength
+ // unsigned char field_decimals 17 decimals
+ // unsigned char reserved[14] 18-31 reserved for internal dBASE-stuff
+
+ fields.clear();
+ for( unsigned i = 1; i < m_headerLength/32; ++i )
+ {
+ DBaseField* field = new DBaseField;
+
+ // columnn-name
+ Q_UINT8 colname[12];
+ for ( int j = 0; j < 11; ++j)
+ m_stream >> colname[j];
+ colname[11] = '\0';
+ field->name = QString( (const char*) &colname[0] );
+
+ // type of column
+ Q_UINT8 coltype;
+ m_stream >> coltype;
+ switch( coltype )
+ {
+ case 'C': field->type = DBaseField::Character; break;
+ case 'N': field->type = DBaseField::Numeric; break;
+ case 'D': field->type = DBaseField::Date; break;
+ case 'M': field->type = DBaseField::Memo; break;
+ case 'L': field->type = DBaseField::Logical; break;
+ default: field->type = DBaseField::Unknown; break;
+ }
+
+ // fileddataaddress
+ Q_UINT32 addr;
+ m_stream >> addr;
+
+ // columnlength
+ Q_UINT8 colsize;
+ m_stream >> colsize;
+ field->length = colsize;
+
+ // decimals
+ Q_UINT8 decimals;
+ m_stream >> decimals;
+ field->decimals = decimals;
+
+ // read remaining chars
+ Q_UINT8 dummy;
+ for ( int foo = 0; foo < 14; ++foo )
+ m_stream >> dummy;
+
+ // now append
+ fields.append( field );
+ }
+
+ // set the index to the first record
+ m_stream.device()->at( m_headerLength );
+
+ return true;
+}
+
+QStringList DBase::readRecord( unsigned recno )
+{
+ QStringList result;
+
+ // out of range ? return empty strings
+ if( recno >= m_recordCount )
+ {
+ for( unsigned i=0; i<fields.count(); i++)
+ result.append( "" );
+ return result;
+ }
+
+ // seek to where the record is
+ unsigned filepos = m_headerLength + recno * m_recordLength;
+ m_stream.device()->at( filepos );
+
+ // first char == '*' means the record is deleted
+ // so we just skip it
+ Q_UINT8 delmarker;
+ m_stream >> delmarker;
+ if( delmarker == 0x2a )
+ return result;
+
+ // load it
+ for( unsigned i=0; i<fields.count(); i++ )
+ switch( fields.at(i)->type )
+ {
+ // Numeric or Character
+ case DBaseField::Numeric:
+ case DBaseField::Character:
+ {
+ QString str;
+ Q_UINT8 ch;
+ for( unsigned j=0; j<fields.at(i)->length; j++ )
+ { m_stream >> ch; str += QChar(ch); }
+ result.append( str );
+ } break;
+
+ // Logical
+ case DBaseField::Logical:
+ {
+ Q_UINT8 ch;
+ m_stream >> ch;
+ switch( ch )
+ {
+ case 'Y': case 'y': case 'T': case 't': result.append( "True" ); break;
+ case 'N': case 'n': case 'F': case 'f': result.append( "False" ); break;
+ default: result.append( "" ); break;
+ }
+ } break;
+
+ // Date, stored as YYYYMMDD
+ // Note: convert it to YYYY-MM-DD
+ case DBaseField::Date:
+ {
+ QString str;
+ Q_UINT8 ch;
+ for( unsigned j=0; j<fields.at(i)->length; j++ )
+ { m_stream >> ch; str += QChar(ch); }
+ str.insert( 6, '-' );
+ str.insert( 4, '-' );
+ result.append( str );
+ } break;
+
+ // Unknown/Unimplemented
+ case DBaseField::Unknown:
+ case DBaseField::Memo:
+ default:
+ result.append( "" ); // unknown
+ break;
+ }
+
+ return result;
+}
+
+void DBase::close()
+{
+ if( m_file.isOpen() ) m_file.close();
+}
diff --git a/filters/kspread/dbase/dbase.h b/filters/kspread/dbase/dbase.h
new file mode 100644
index 000000000..022d2ba10
--- /dev/null
+++ b/filters/kspread/dbase/dbase.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 by Thomas Franke and Andreas Pietzowski <andreas@pietzowski.de>
+ Ariya Hidayat <ariyahidayat@yahoo.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DBASE_H
+#define DBASE_H
+
+#include <qdatastream.h>
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+class DBaseField
+{
+ public:
+ QString name;
+ enum { Unknown, Character, Date, Numeric, Logical, Memo } type;
+ unsigned length;
+ unsigned decimals;
+};
+
+class DBase
+{
+
+ public:
+ DBase();
+ ~DBase();
+
+ QPtrList<DBaseField> fields;
+
+ bool load( const QString& filename );
+ QStringList readRecord( unsigned recno );
+ void close();
+
+ unsigned recordCount(){ return m_recordCount; }
+ int version(){ return m_version; }
+ QDate lastUpdate(){ return m_lastUpdate; }
+
+ private:
+
+ QFile m_file;
+ QDataStream m_stream;
+ int m_version;
+ QDate m_lastUpdate;
+ unsigned m_recordCount;
+ unsigned m_headerLength;
+ unsigned m_recordLength;
+};
+
+#endif
diff --git a/filters/kspread/dbase/dbaseimport.cc b/filters/kspread/dbase/dbaseimport.cc
new file mode 100644
index 000000000..1c167cd0d
--- /dev/null
+++ b/filters/kspread/dbase/dbaseimport.cc
@@ -0,0 +1,181 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Ariya Hidayat <ariyahidayat@yahoo.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <dbaseimport.h>
+#include <dbaseimport.moc>
+#include <dbase.h>
+
+#include <qfile.h>
+#include <qfont.h>
+#include <qfontmetrics.h>
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <KoFilterChain.h>
+#include <KoGlobal.h>
+#include <KoUnit.h>
+#include <kgenericfactory.h>
+#include <kmessagebox.h>
+
+typedef KGenericFactory<DBaseImport, KoFilter> DBaseImportFactory;
+K_EXPORT_COMPONENT_FACTORY( libdbaseimport, DBaseImportFactory( "kofficefilters" ) )
+
+
+DBaseImport::DBaseImport ( QObject*, const char*, const QStringList& )
+ : KoFilter()
+{
+}
+
+KoFilter::ConversionStatus DBaseImport::convert( const QCString& from, const QCString& to )
+{
+ if (to != "application/x-kspread" || from != "application/x-dbase")
+ return KoFilter::NotImplemented;
+
+ QString inputFile = m_chain->inputFile();
+
+ DBase dbase;
+ bool result = dbase.load( inputFile );
+
+ if( dbase.version() !=3 )
+ {
+ KMessageBox::sorry( 0, i18n("File format is not supported.") );
+ return KoFilter::NotImplemented;
+ }
+
+ if( !result )
+ {
+ KMessageBox::sorry( 0, i18n("Could not read from file." ) );
+ return KoFilter::StupidError;
+ }
+
+ QString root, documentInfo;
+
+ root = "<!DOCTYPE spreadsheet >\n";
+ root += "<spreadsheet mime=\"application/x-kspread\" editor=\"KSpread\" >\n";
+ root += "<paper format=\"A4\" orientation=\"Portrait\" >\n";
+ root += "<borders right=\"20\" left=\"20\" bottom=\"20\" top=\"20\" />\n";
+ root += "<head/>\n";
+ root += "<foot/>\n";
+ root += "</paper>\n";
+ root += "<map activeTable=\"Table1\" >\n";
+
+ root += "<locale positivePrefixCurrencySymbol=\"True\"";
+ root += " negativeMonetarySignPosition=\"0\"";
+ root += " negativePrefixCurrencySymbol=\"True\" fracDigits=\"2\"";
+ root += " thousandsSeparator=\",\" dateFormat=\"%A %d %B %Y\"";
+ root += " timeFormat=\"%H:%M:%S\" monetaryDecimalSymbol=\".\"";
+ root += " weekStartsMonday=\"True\" currencySymbol=\"$\"";
+ root += " negativeSign=\"-\" positiveSign=\"\"";
+ root += " positiveMonetarySignPosition=\"1\" decimalSymbol=\".\"";
+ root += " monetaryThousandsSeparator=\",\" dateFormatShort=\"%Y-%m-%d\" />\n";
+
+ root += "<table name=\"Table1\" columnnumber=\"0\" borders=\"0\"";
+ root += " hide=\"0\" hidezero=\"0\" firstletterupper=\"0\" grid=\"1\"";
+ root += " formular=\"0\" lcmode=\"0\" >\n";
+
+ // KOffice default font
+ QFont font = KoGlobal::defaultFont();
+
+ // define columns
+ QFontMetrics fm( font );
+ for( unsigned i=0; i<dbase.fields.count(); i++ )
+ {
+ int mw = QMAX( dbase.fields.at(i)->length, dbase.fields.at(i)->name.length());
+ double w = POINT_TO_MM( fm.maxWidth() * mw );
+ root += "<column column=\"" + QString::number(i+1) + "\"";
+ root += " width=\"" + QString::number( w ) + "\"><format/></column>\n";
+ }
+
+ // define rows
+ double h = POINT_TO_MM( 5 + fm.height() + fm.leading() );
+ for( unsigned j=0; j<dbase.recordCount(); j++ )
+ {
+ root += "<row row=\"" + QString::number(j+1) + "\"";
+ root += " height=\"" + QString::number( h ) + "\" ><format/></row>\n";
+ }
+
+ // field names come as first row
+ for( unsigned i=0; i<dbase.fields.count(); i++ )
+ {
+ root += "<cell row=\"1\" column=\"" + QString::number(i+1) + "\" >\n";
+ root += "<format><pen width=\"0\" style=\"1\" color=\"#000000\" />";
+ root += "<font family=\"" + font.family() + "\"" +
+ " size=\"" + QString::number(font.pointSizeFloat()) + "\"" +
+ " weight=\"50\" />";
+ root += "</format>\n";
+ root += "<text>" + dbase.fields.at(i)->name + "</text></cell>\n";
+ }
+
+ // process all records
+ unsigned row = 1;
+ for( unsigned j=0; j<dbase.recordCount(); j++ )
+ {
+ QStringList rec = dbase.readRecord( j );
+ if( rec.count() )
+ {
+ row++;
+ for( unsigned i=0; i<rec.count(); i++ )
+ {
+ root += "<cell row=\"" + QString::number(row) + "\"" +
+ "column=\"" + QString::number(i+1) + "\" >\n";
+ root += "<format><pen width=\"0\" style=\"1\" color=\"#000000\" />";
+ root += "<font family=\"" + font.family() + "\"" +
+ " size=\"" + QString::number(font.pointSizeFloat()) + "\"" +
+ " weight=\"50\" />";
+ root += "</format>\n";
+ root += "<text>" + rec[i] + "</text></cell>\n";
+ }
+ }
+ }
+
+ dbase.close();
+
+ root += "</table>\n";
+ root += "</map>\n";
+ root += "</spreadsheet>";
+
+ // prepare storage
+ KoStoreDevice* out=m_chain->storageFile( "root", KoStore::Write );
+
+ // store output document
+ if( out )
+ {
+ QCString cstring = root.utf8();
+ cstring.prepend( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
+ out->writeBlock( (const char*) cstring, cstring.length() );
+ }
+
+ // store document info
+ out = m_chain->storageFile( "documentinfo.xml", KoStore::Write );
+ if ( out )
+ {
+ QCString cstring = documentInfo.utf8();
+ cstring.prepend( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
+
+ out->writeBlock( (const char*) cstring, cstring.length() );
+ }
+
+ return KoFilter::OK;
+}
diff --git a/filters/kspread/dbase/dbaseimport.h b/filters/kspread/dbase/dbaseimport.h
new file mode 100644
index 000000000..b51a7138a
--- /dev/null
+++ b/filters/kspread/dbase/dbaseimport.h
@@ -0,0 +1,38 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Ariya Hidayat <ariyahidayat@yahoo.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __DBASEIMPORT_H
+#define __DBASEIMPORT_H
+
+#include <KoFilter.h>
+#include <KoStore.h>
+
+class DBaseImport : public KoFilter {
+
+ Q_OBJECT
+
+public:
+
+ DBaseImport ( QObject *parent, const char* name, const QStringList& );
+ virtual ~DBaseImport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+};
+
+#endif // __DBASEIMPORT_H
diff --git a/filters/kspread/dbase/kspread_dbase_import.desktop b/filters/kspread/dbase/kspread_dbase_import.desktop
new file mode 100644
index 000000000..610edd2fa
--- /dev/null
+++ b/filters/kspread/dbase/kspread_dbase_import.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+Type=Service
+Name=KSpread dBASE Import Filter
+Name[bg]=Филтър за импортиране от dBASE в KSpread
+Name[br]=Sil enporzh dBASE evit KSpread
+Name[ca]=Filtre d'importació dBASE per a KSpread
+Name[cs]=Importní filtr dBASE pro KSpread
+Name[cy]=Hidlen Fewnforio dBASE Kspread
+Name[da]=KSpread dBASE-importfilter
+Name[de]=KSpread dBASE-Importfilter
+Name[el]=Φίλτρο εισαγωγής dBASE του KSpread
+Name[eo]=dBASE-importfiltrilo por KSpread
+Name[es]=Filtro de importación de dBase para KSpread
+Name[et]=KSpreadi dBASE'i impordifilter
+Name[eu]=KSpread-en dBASE inportaziorako iragazkia
+Name[fa]=پالایۀ واردات KSpread dBASE
+Name[fi]=KSpread dBASE tuontisuodin
+Name[fr]=Filtre d'importation dBASE de Kspread
+Name[fy]=KSpread dBASE Ymportfilter
+Name[ga]=Scagaire Iompórtála dBASE le haghaidh KSpread
+Name[gl]=Filtro de Importación de dBASE para KSpread
+Name[he]=מסנן ייבוא מ־dBASE ל־KSpread
+Name[hi]=के-स्प्रेड डीबेस आयात छननी
+Name[hr]=KSpread dBASE filtar uvoza
+Name[hu]=KSpread dBASE importszűrő
+Name[is]=KSpread dBASE innflutningssía
+Name[it]=Filtro di importazione dBASE per KSpread
+Name[ja]=KSpread dBASE インポートフィルタ
+Name[km]=តម្រង​នាំចូល dBASE សម្រាប់ KSpread
+Name[lo]= ຕົວຕອງການນຳເຂົ້າ dBase ຂອງກະດາດຄຳນວນ K
+Name[lt]=KSpread dBASE importavimo filtras
+Name[lv]=KSpread dBASE importa filtrs
+Name[ms]=Penapis Import KSpread dBASE
+Name[mt]=Filtru għall-importazzjoni ta' dBase ġo KSpread
+Name[nb]=dBASE-importfilter for KSpread
+Name[nds]=dBASE-Importfilter för KSpread
+Name[ne]=केडीई स्प्रिेड डिबेस आयात फिल्टर
+Name[nl]=KSpread dBASE Importfilter
+Name[nn]=dBASE-importfilter for KSpread
+Name[pl]=Filtr importu formatu dBASE do KSpread
+Name[pt]=Filtro de Importação de dBase para o KSpread
+Name[pt_BR]=Filtro de importação KSpread - dBASE
+Name[ru]=Фильтр импорта файлов dBASE в KSpread
+Name[se]=KSpread:a dBASE-sisafievrridansilli
+Name[sk]=dBase filter pre import do KSpread
+Name[sl]=Uvozni filter dBASE za KSpread
+Name[sr]=KSpread-ов филтер за увоз из dBASE-а
+Name[sr@Latn]=KSpread-ov filter za uvoz iz dBASE-a
+Name[sv]=Kspread dBASE-importfilter
+Name[ta]=Kspread dbase இறக்குமதி வடிகட்டி
+Name[tg]=Филтри Воридоти KSpread dBASE
+Name[th]=ตัวกรองการนำเข้า dBase ของกระดาษคำนวณ K
+Name[tr]=KSpread dBASE Alma Filtresi
+Name[uk]=Фільтр імпорту dBASE для KSpread
+Name[uz]=KSpread dBASE import filteri
+Name[uz@cyrillic]=KSpread dBASE импорт филтери
+Name[wa]=Passete dBASE d' intrêye po KSpread
+Name[xh]=Isihluzi Sokurhweba se KSpread dBASE
+Name[zh_CN]=KSpread dBASE 导入过滤器
+Name[zh_TW]=KSpread dBASE 匯入過濾程式
+X-KDE-Export=application/x-kspread
+X-KDE-Import=application/x-dbase
+X-KDE-Weight=1
+X-KDE-Library=libdbaseimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/dbase/status.html b/filters/kspread/dbase/status.html
new file mode 100644
index 000000000..561cf26ef
--- /dev/null
+++ b/filters/kspread/dbase/status.html
@@ -0,0 +1,164 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>KOffice filters status: dBASE</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<A NAME="START">&nbsp;</A>
+
+<BR>
+<center>
+ <h1>
+ KOffice filters status: &nbsp;&nbsp;<i>dBASE</i>
+ </h1>
+</center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%">
+
+<font size="-1"><b>
+ <A HREF="#import">Import</A> |
+ <A HREF="#export">Export</A>
+</b></font>
+
+<BR><BR><BR>
+<center><a NAME="import"></a></center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+
+ <tr BGCOLOR="#DDFFDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>
+ Import dBASE for KSpread<BR>
+ <BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>27 Mar 2002</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>Can import dBASE document<br>
+ Only support dBASE 3</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>
+ Support for Memo field
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td>
+ <A HREF="mailto:ariyahidayat@yahoo.de">Ariya Hidayat</A>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td>
+ <a href="http://community.borland.com/article/0,1410,15838,00.html">http://community.borland.com/article/0,1410,15838,00.html</a><br>
+ <a href="http://www.apptools.com/dbase/faq/qformt.htm">dBASE DBF file format</a><br>
+ <a href="http://www.geocities.com/SiliconValley/Pines/2563/xbase.htm">XBase
+file format description</a><br>
+ <a href="http://www.hdk-berlin.de/~rasca/dbflib/">dbflib: another xbase library</a><br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>-</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+<br><br><br>
+
+<hr NOSHADE SIZE=1>
+<br><br><br>
+
+
+<center>
+ <a NAME="export"></a>
+</center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+ <tr BGCOLOR="#FFDDDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>Export KSpread to dBASE<BR><BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td>
+ <A HREF="mailto:ariyahidayat@yahoo.de">Ariya Hidayat</A>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>---</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+</body>
+</html>
diff --git a/filters/kspread/dbase/test/birth.dbf b/filters/kspread/dbase/test/birth.dbf
new file mode 100755
index 000000000..f836c7a40
--- /dev/null
+++ b/filters/kspread/dbase/test/birth.dbf
Binary files differ
diff --git a/filters/kspread/dbase/test/browser.dbf b/filters/kspread/dbase/test/browser.dbf
new file mode 100644
index 000000000..38aab8263
--- /dev/null
+++ b/filters/kspread/dbase/test/browser.dbf
Binary files differ
diff --git a/filters/kspread/dbase/test/stability.dbf b/filters/kspread/dbase/test/stability.dbf
new file mode 100755
index 000000000..d4d3554dc
--- /dev/null
+++ b/filters/kspread/dbase/test/stability.dbf
Binary files differ
diff --git a/filters/kspread/excel/Makefile.am b/filters/kspread/excel/Makefile.am
new file mode 100644
index 000000000..73d5db56a
--- /dev/null
+++ b/filters/kspread/excel/Makefile.am
@@ -0,0 +1,15 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) -I$(top_srcdir)/kspread $(KOFFICE_INCLUDES) \
+ $(KOTEXT_INCLUDES) $(all_includes)
+
+SUBDIRS = sidewinder import
+
+####### Files
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+
+messages: rc.cpp
+ $(XGETTEXT) *.cc *.cpp -o $(podir)/kspreadexcelfilter.pot
diff --git a/filters/kspread/excel/excelexport.cc b/filters/kspread/excel/excelexport.cc
new file mode 100644
index 000000000..74ad77581
--- /dev/null
+++ b/filters/kspread/excel/excelexport.cc
@@ -0,0 +1,66 @@
+/* insert your license here */
+
+#include <excelexport.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+
+typedef KGenericFactory<ExcelExport, KoFilter> ExcelExportFactory;
+//K_EXPORT_COMPONENT_FACTORY(libkspreadexcelexport, ExcelExportFactory("excelexport"))
+
+
+ExcelExport::ExcelExport(KoFilter *, const char *, const QStringList&) : KoFilter() {
+}
+
+
+KoFilter::ConversionStatus ExcelExport::convert(const QCString& from, const QCString& to) {
+ // Double check that's we really what we want to do
+ if ( ( (to != "application/excel") && (to != "application/msexcel") ) || from != "application/x-kspread") {
+ kdWarning(0) << "Invalid mimetypes " << to << ", " << from << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ KSpreadLeader *leader = new KSpreadLeader(m_chain);
+ ExcelWorker *worker = new ExcelWorker();
+ leader->setWorker(worker);
+ return leader->convert();
+}
+
+
+/*
+KoFilter::ConversionStatus ExcelWorker::startDocument(KSpreadFilterProperty property) {
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus ExcelWorker::startInfoLog(KSpreadFilterProperty property) {
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus ExcelWorker::startInfoAuthor(KSpreadFilterProperty property) {
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus ExcelWorker::startInfoAbout(KSpreadFilterProperty property) {
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus ExcelWorker::startSpreadBook(KSpreadFilterProperty property) {
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus ExcelWorker::startSpreadSheet(KSpreadFilterProperty property) {
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus ExcelWorker::startSpreadCell(KSpreadFilterProperty property) {
+ return KoFilter::OK;
+}
+*/
+
+#include <excelexport.moc>
diff --git a/filters/kspread/excel/excelexport.h b/filters/kspread/excel/excelexport.h
new file mode 100644
index 000000000..28e1b41ea
--- /dev/null
+++ b/filters/kspread/excel/excelexport.h
@@ -0,0 +1,34 @@
+/* insert your license here */
+
+#ifndef EXCELEXPORT_TEST_H
+#define EXCELEXPORT_TEST_H
+
+#include <KoFilter.h>
+#include <KSpreadLeader.h>
+#include <KSpreadBaseWorker.h>
+
+
+class ExcelExport : public KoFilter {
+ Q_OBJECT
+
+public:
+ ExcelExport(KoFilter *parent, const char*name, const QStringList&);
+ virtual ~ExcelExport() {}
+
+ virtual KoFilter::ConversionStatus convert(const QCString& from, const QCString& to);
+};
+
+
+class ExcelWorker : public KSpreadBaseWorker {
+public:
+ // Implement those
+ //KoFilter::ConversionStatus startDocument(KSpreadFilterProperty property);
+ //KoFilter::ConversionStatus startInfoLog(KSpreadFilterProperty property);
+ //KoFilter::ConversionStatus startInfoAuthor(KSpreadFilterProperty property);
+ //KoFilter::ConversionStatus startInfoAbout(KSpreadFilterProperty property);
+ //KoFilter::ConversionStatus startSpreadBook(KSpreadFilterProperty property);
+ //KoFilter::ConversionStatus startSpreadSheet(KSpreadFilterProperty property);
+ //KoFilter::ConversionStatus startSpreadCell(KSpreadFilterProperty property);
+};
+
+#endif
diff --git a/filters/kspread/excel/import/Makefile.am b/filters/kspread/excel/import/Makefile.am
new file mode 100644
index 000000000..8aed76773
--- /dev/null
+++ b/filters/kspread/excel/import/Makefile.am
@@ -0,0 +1,17 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) -I$(srcdir)/../sidewinder $(KOFFICE_INCLUDES) $(all_includes)
+
+####### Files
+
+kde_module_LTLIBRARIES = libexcelimport.la
+
+libexcelimport_la_SOURCES = excelimport.cc
+libexcelimport_la_LIBADD = $(KOFFICE_LIBS) ../sidewinder/libsidewinder.la
+libexcelimport_la_LDFLAGS = -module $(KDE_PLUGIN)
+noinst_HEADERS = excelimport.h
+
+METASOURCES = AUTO
+
+service_DATA = kspread_excel_import.desktop
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/excel/import/README b/filters/kspread/excel/import/README
new file mode 100644
index 000000000..6fa693326
--- /dev/null
+++ b/filters/kspread/excel/import/README
@@ -0,0 +1,61 @@
+IMPLEMENTED
+===========
+
+Workbook:
+
+Sheet:
+ name
+ visibility
+ margins (left, right, top, bottom)
+ header (left, center, right)
+ footer (left, center, right)
+
+Cell:
+ value (string, number, boolean)
+ merged cells (column and row spans)
+ formatting attributes
+
+Row:
+ height
+ visibility
+ formatting attributes
+
+Column:
+ width
+ visibility
+ formatting attributes
+
+Format:
+ horizontal alignment
+ vertical alignment
+ font (name, color, bold, italic, underline, strike)
+ borders
+ background (pattern, color)
+ text wrapping
+
+
+
+TODO
+====
+
+Sheet:
+ better parsing of header/footer
+ margins (header, footer)
+ page size, orientation
+
+Cell:
+ formula (!)
+ error code
+ hyperlink
+
+Format:
+ rotation angle
+ style
+
+
+INCOMPATIBLE
+============
+- exact width of column
+- border style: double, medium, slanted
+- alignment: repeat, justified, filled, distributed
+- header/footer fields, e.g &Z, font
diff --git a/filters/kspread/excel/import/excelimport.cc b/filters/kspread/excel/import/excelimport.cc
new file mode 100644
index 000000000..3ff38717c
--- /dev/null
+++ b/filters/kspread/excel/import/excelimport.cc
@@ -0,0 +1,2132 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2006 Ariya Hidayat <ariya@kde.org>
+ Copyright (C) 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <excelimport.h>
+#include <excelimport.moc>
+
+#include <qbuffer.h>
+#include <qcstring.h>
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qtextstream.h>
+
+#include <kdebug.h>
+#include <KoFilterChain.h>
+#include <KoGlobal.h>
+#include <KoUnit.h>
+#include <kgenericfactory.h>
+
+#include <KoXmlWriter.h>
+#include <KoOasisStore.h>
+
+#include "swinder.h"
+#include <iostream>
+
+typedef KGenericFactory<ExcelImport, KoFilter> ExcelImportFactory;
+K_EXPORT_COMPONENT_FACTORY( libexcelimport, ExcelImportFactory( "kofficefilters" ) )
+
+
+// UString -> QConstString conversion. Use .string() to get the QString.
+// Always store the QConstString into a variable first, to avoid a deep copy.
+inline QConstString string( const Swinder::UString& str ) {
+ // Let's hope there's no copying of the QConstString happening...
+ return QConstString( reinterpret_cast<const QChar*>( str.data() ), str.length() );
+}
+
+using namespace Swinder;
+
+class ExcelImport::Private
+{
+public:
+ QString inputFile;
+ QString outputFile;
+
+ Workbook *workbook;
+
+ bool createStyles( KoOasisStore* store );
+ bool createContent( KoOasisStore* store );
+ bool createManifest( KoOasisStore* store );
+
+ int sheetFormatIndex;
+ int columnFormatIndex;
+ int rowFormatIndex;
+
+ QMap<int,bool> styleFormats;
+ QMap<int,bool> isPercentageStyle;
+ QMap<int,bool> isDateStyle;
+ QMap<int,bool> isTimeStyle;
+
+ void processWorkbookForBody( Workbook* workbook, KoXmlWriter* xmlWriter );
+ void processWorkbookForStyle( Workbook* workbook, KoXmlWriter* xmlWriter );
+ void processSheetForBody( Sheet* sheet, KoXmlWriter* xmlWriter );
+ void processSheetForStyle( Sheet* sheet, KoXmlWriter* xmlWriter );
+ void processColumnForBody( Column* column, int repeat, KoXmlWriter* xmlWriter );
+ void processColumnForStyle( Column* column, int repeat, KoXmlWriter* xmlWriter );
+ void processRowForBody( Row* row, int repeat, KoXmlWriter* xmlWriter );
+ void processRowForStyle( Row* row, int repeat, KoXmlWriter* xmlWriter );
+ void processCellForBody( Cell* cell, KoXmlWriter* xmlWriter );
+ void processCellForStyle( Cell* cell, KoXmlWriter* xmlWriter );
+ void processFormat( const Format* format, KoXmlWriter* xmlWriter );
+ void processValueFormat( QString valueFormat, QString refName, KoXmlWriter* xmlWriter );
+};
+
+
+ExcelImport::ExcelImport ( QObject*, const char*, const QStringList& )
+ : KoFilter()
+{
+ d = new Private;
+}
+
+ExcelImport::~ExcelImport()
+{
+ delete d;
+}
+
+KoFilter::ConversionStatus ExcelImport::convert( const QCString& from, const QCString& to )
+{
+ if ( from != "application/msexcel" )
+ return KoFilter::NotImplemented;
+
+ if ( to != "application/vnd.oasis.opendocument.spreadsheet" )
+ return KoFilter::NotImplemented;
+
+ d->inputFile = m_chain->inputFile();
+ d->outputFile = m_chain->outputFile();
+
+ QTime time;
+ time.start();
+
+ // open inputFile
+ d->workbook = new Swinder::Workbook;
+ if( !d->workbook->load( d->inputFile.local8Bit() ) )
+ {
+ delete d->workbook;
+ d->workbook = 0;
+ return KoFilter::StupidError;
+ }
+
+ if( d->workbook->isPasswordProtected() )
+ {
+ delete d->workbook;
+ d->workbook = 0;
+ return KoFilter::PasswordProtected;
+ }
+
+ kdDebug(30511) << "File " << d->inputFile << " loaded. Time: " << time.elapsed() << " ms " << endl;
+ time.restart();
+
+ // create output store
+ KoStore* storeout;
+ storeout = KoStore::createStore( d->outputFile, KoStore::Write,
+ "application/vnd.oasis.opendocument.spreadsheet", KoStore::Zip );
+
+ if ( !storeout )
+ {
+ kdWarning() << "Couldn't open the requested file." << endl;
+ delete d->workbook;
+ return KoFilter::FileNotFound;
+ }
+
+ // Tell KoStore not to touch the file names
+ storeout->disallowNameExpansion();
+ KoOasisStore oasisStore( storeout );
+
+ // store document styles
+ d->sheetFormatIndex = 1;
+ d->columnFormatIndex = 1;
+ d->rowFormatIndex = 1;
+ if ( !d->createStyles( &oasisStore ) )
+ {
+ kdWarning() << "Couldn't open the file 'styles.xml'." << endl;
+ delete d->workbook;
+ delete storeout;
+ return KoFilter::CreationError;
+ }
+
+ // store document content
+ d->sheetFormatIndex = 1;
+ d->columnFormatIndex = 1;
+ d->rowFormatIndex = 1;
+ if ( !d->createContent( &oasisStore ) )
+ {
+ kdWarning() << "Couldn't open the file 'content.xml'." << endl;
+ delete d->workbook;
+ delete storeout;
+ return KoFilter::CreationError;
+ }
+
+ // store document manifest
+ if ( !d->createManifest( &oasisStore ) )
+ {
+ kdWarning() << "Couldn't open the file 'META-INF/manifest.xml'." << endl;
+ delete d->workbook;
+ delete storeout;
+ return KoFilter::CreationError;
+ }
+
+ kdDebug(30511) << "Converted to " << d->outputFile << ". Time: " << time.elapsed() << " ms " << endl;
+
+ // we are done!
+ delete d->workbook;
+ delete storeout;
+ d->inputFile = QString::null;
+ d->outputFile = QString::null;
+ d->workbook = 0;
+
+
+ return KoFilter::OK;
+}
+
+bool ExcelImport::Private::createContent( KoOasisStore* store )
+{
+ KoXmlWriter* bodyWriter = store->bodyWriter();
+ KoXmlWriter* contentWriter = store->contentWriter();
+ if ( !bodyWriter || !contentWriter )
+ return false;
+
+ // FIXME this is dummy and hardcoded, replace with real font names
+ contentWriter->startElement( "office:font-face-decls" );
+ contentWriter->startElement( "style:font-face" );
+ contentWriter->addAttribute( "style:name", "Arial" );
+ contentWriter->addAttribute( "svg:font-family", "Arial" );
+ contentWriter->endElement(); // style:font-face
+ contentWriter->startElement( "style:font-face" );
+ contentWriter->addAttribute( "style:name", "Times New Roman" );
+ contentWriter->addAttribute( "svg:font-family", "&apos;Times New Roman&apos;" );
+ contentWriter->endElement(); // style:font-face
+ contentWriter->endElement(); // office:font-face-decls
+
+ // important: reset all indexes
+ sheetFormatIndex = 1;
+ columnFormatIndex = 1;
+ rowFormatIndex = 1;
+
+ // office:automatic-styles
+ contentWriter->startElement( "office:automatic-styles" );
+ processWorkbookForStyle( workbook, contentWriter );
+ contentWriter->endElement(); // office:automatic-style
+
+ // important: reset all indexes
+ sheetFormatIndex = 1;
+ columnFormatIndex = 1;
+ rowFormatIndex = 1;
+
+ // office:body
+ bodyWriter->startElement( "office:body" );
+ processWorkbookForBody( workbook, bodyWriter );
+ bodyWriter->endElement(); // office:body
+
+ return store->closeContentWriter();
+}
+
+bool ExcelImport::Private::createStyles( KoOasisStore* store )
+{
+ if ( !store->store()->open( "styles.xml" ) )
+ return false;
+ KoStoreDevice dev( store->store() );
+ KoXmlWriter* stylesWriter = new KoXmlWriter( &dev );
+
+ // FIXME this is dummy default, replace if necessary
+ stylesWriter->startDocument( "office:document-styles" );
+ stylesWriter->startElement( "office:document-styles" );
+ stylesWriter->addAttribute( "xmlns:office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0" );
+ stylesWriter->addAttribute( "xmlns:style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0" );
+ stylesWriter->addAttribute( "xmlns:text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0" );
+ stylesWriter->addAttribute( "xmlns:table", "urn:oasis:names:tc:opendocument:xmlns:table:1.0" );
+ stylesWriter->addAttribute( "xmlns:draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" );
+ stylesWriter->addAttribute( "xmlns:fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" );
+ stylesWriter->addAttribute( "xmlns:svg","urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" );
+ stylesWriter->addAttribute( "office:version","1.0" );
+ stylesWriter->startElement( "office:styles" );
+ stylesWriter->startElement( "style:default-style" );
+ stylesWriter->addAttribute( "style:family", "table-cell" );
+ stylesWriter->startElement( "style:table-cell-properties" );
+ stylesWriter->addAttribute( "style:decimal-places", "2" );
+ stylesWriter->endElement(); // style:table-cell-properties
+ stylesWriter->startElement( "style:paragraph-properties" );
+ stylesWriter->addAttribute( "style:tab-stop-distance", "0.5in" );
+ stylesWriter->endElement(); // style:paragraph-properties
+ stylesWriter->startElement( "style:text-properties" );
+ stylesWriter->addAttribute( "style:font-name", "Albany AMT" );
+ stylesWriter->addAttribute( "fo:language", "en" );
+ stylesWriter->addAttribute( "fo:country", "US" );
+ stylesWriter->addAttribute( "style:font-name-asian", "Albany AMT1" );
+ stylesWriter->addAttribute( "style:country-asian", "none" );
+ stylesWriter->addAttribute( "style:font-name-complex", "Lucidasans" );
+ stylesWriter->addAttribute( "style:language-complex", "none" );
+ stylesWriter->addAttribute( "style:country-complex", "none" );
+ stylesWriter->endElement(); // style:text-properties
+ stylesWriter->endElement(); // style:default-style
+ stylesWriter->startElement( "style:style" );
+ stylesWriter->addAttribute( "style:name", "Default" );
+ stylesWriter->addAttribute( "style:family", "table-cell" );
+ stylesWriter->endElement(); // style:style
+ stylesWriter->endElement(); // office:styles
+
+ // office:automatic-styles
+ stylesWriter->startElement( "office:automatic-styles" );
+ stylesWriter->endElement(); // office:automatic-styles
+
+ stylesWriter->endElement(); // office:document-styles
+ stylesWriter->endDocument();
+
+ delete stylesWriter;
+
+ return store->store()->close();
+}
+
+bool ExcelImport::Private::createManifest( KoOasisStore* store )
+{
+ KoXmlWriter* manifestWriter = store->manifestWriter( "application/vnd.oasis.opendocument.spreadsheet" );
+
+ manifestWriter->addManifestEntry( "styles.xml", "text/xml" );
+ manifestWriter->addManifestEntry( "content.xml", "text/xml" );
+
+ return store->closeManifestWriter();
+}
+
+void ExcelImport::Private::processWorkbookForBody( Workbook* workbook, KoXmlWriter* xmlWriter )
+{
+ if( !workbook ) return;
+ if( !xmlWriter ) return;
+
+ xmlWriter->startElement( "office:spreadsheet" );
+
+ for( unsigned i=0; i < workbook->sheetCount(); i++ )
+ {
+ Sheet* sheet = workbook->sheet( i );
+ processSheetForBody( sheet, xmlWriter );
+ }
+
+ xmlWriter->endElement(); // office:spreadsheet
+}
+
+void ExcelImport::Private::processWorkbookForStyle( Workbook* workbook, KoXmlWriter* xmlWriter )
+{
+ if( !workbook ) return;
+ if( !xmlWriter ) return;
+
+ for( unsigned i=0; i < workbook->sheetCount(); i++ )
+ {
+ Sheet* sheet = workbook->sheet( i );
+ processSheetForStyle( sheet, xmlWriter );
+ }
+}
+
+void ExcelImport::Private::processSheetForBody( Sheet* sheet, KoXmlWriter* xmlWriter )
+{
+ if( !sheet ) return;
+ if( !xmlWriter ) return;
+
+ xmlWriter->startElement( "table:table" );
+
+ xmlWriter->addAttribute( "table:name", string( sheet->name() ).string() );
+ xmlWriter->addAttribute( "table:print", "false" );
+ xmlWriter->addAttribute( "table:protected", "false" );
+ xmlWriter->addAttribute( "table:style-name", QString("ta%1").arg(sheetFormatIndex));
+ sheetFormatIndex++;
+
+ unsigned ci = 0;
+ while( ci <= sheet->maxColumn() )
+ {
+ Column* column = sheet->column( ci, false );
+ if( column )
+ {
+ // forward search for columns with same properties
+ unsigned cj = ci + 1;
+ while( cj <= sheet->maxColumn() )
+ {
+ const Column* nextColumn = sheet->column( cj, false );
+ if( !nextColumn ) break;
+ if( column->width() != nextColumn->width() ) break;
+ if( column->visible() != nextColumn->visible() ) break;
+ if( column->formatIndex() != nextColumn->formatIndex() ) break;
+ cj++;
+ }
+
+ int repeated = cj - ci;
+ processColumnForBody( column, repeated, xmlWriter );
+ ci += repeated;
+ }
+ else {
+ ci++;
+ xmlWriter->startElement( "table:table-column" );
+ xmlWriter->endElement();
+ }
+ }
+
+ for( unsigned i = 0; i <= sheet->maxRow(); i++ )
+ {
+ // FIXME optimized this when operator== in Swinder::Format is implemented
+ processRowForBody( sheet->row( i, false ), 1, xmlWriter );
+ }
+
+ xmlWriter->endElement(); // table:table
+}
+
+void ExcelImport::Private::processSheetForStyle( Sheet* sheet, KoXmlWriter* xmlWriter )
+{
+ if( !sheet ) return;
+ if( !xmlWriter ) return;
+
+ xmlWriter->startElement( "style:style" );
+ xmlWriter->addAttribute( "style:family", "table" );
+ xmlWriter->addAttribute( "style:master-page-name", "Default" );
+ xmlWriter->addAttribute( "style:name", QString("ta%1").arg(sheetFormatIndex) );
+ sheetFormatIndex++;
+
+ xmlWriter->startElement( "style:table-properties" );
+ xmlWriter->addAttribute( "table:display", sheet->visible() ? "true" : "false" );
+ xmlWriter->addAttribute( "table:writing-mode", "lr-tb" );
+ xmlWriter->endElement(); // style:table-properties
+
+ xmlWriter->endElement(); // style:style
+
+ unsigned ci = 0;
+ while( ci <= sheet->maxColumn() )
+ {
+ Column* column = sheet->column( ci, false );
+ if( column )
+ {
+ // forward search for similar column
+ unsigned cj = ci + 1;
+ while( cj <= sheet->maxColumn() )
+ {
+ Column* nextColumn = sheet->column( cj, false );
+ if( !nextColumn ) break;
+ if( column->width() != nextColumn->width() ) break;
+ if( column->visible() != nextColumn->visible() ) break;
+ if( column->formatIndex() != nextColumn->formatIndex() ) break;
+ cj++;
+ }
+
+ int repeated = cj - ci;
+ processColumnForStyle( column, repeated, xmlWriter );
+ ci += repeated;
+ }
+ else
+ ci++;
+ }
+
+ for( unsigned i = 0; i <= sheet->maxRow(); i++ )
+ {
+ Row* row = sheet->row( i, false );
+ // FIXME optimized this when operator== in Swinder::Format is implemented
+ processRowForStyle( row, 1, xmlWriter );
+ }
+}
+
+void ExcelImport::Private::processColumnForBody( Column* column, int repeat, KoXmlWriter* xmlWriter )
+{
+ if( !column ) return;
+ if( !xmlWriter ) return;
+
+ xmlWriter->startElement( "table:table-column" );
+ xmlWriter->addAttribute( "table:default-style-name", "Default" );
+ xmlWriter->addAttribute( "table:visibility", column->visible() ? "visible" : "collapse" );
+ if(repeat > 1) xmlWriter->addAttribute( "table:number-columns-repeated", repeat );
+ xmlWriter->addAttribute( "table:style-name", QString("co%1").arg(columnFormatIndex) );
+ columnFormatIndex++;
+
+ xmlWriter->endElement(); // table:table-column
+}
+
+void ExcelImport::Private::processColumnForStyle( Column* column, int /*repeat*/, KoXmlWriter* xmlWriter )
+{
+ if( !column ) return;
+ if( !xmlWriter ) return;
+
+ xmlWriter->startElement( "style:style" );
+ xmlWriter->addAttribute( "style:family", "table-column" );
+ xmlWriter->addAttribute( "style:name", QString("co%1").arg(columnFormatIndex) );
+ columnFormatIndex++;
+
+ xmlWriter->startElement( "style:table-column-properties" );
+ xmlWriter->addAttribute( "fo:break-before", "auto" );
+ xmlWriter->addAttribute( "style:column-width", QString("%1in").arg(column->width()/27) );
+ xmlWriter->endElement(); // style:table-column-properties
+
+ xmlWriter->endElement(); // style:style
+}
+
+void ExcelImport::Private::processRowForBody( Row* row, int /*repeat*/, KoXmlWriter* xmlWriter )
+{
+ if( !xmlWriter ) return;
+ if( !row ) {
+ xmlWriter->startElement( "table:table-row" );
+ xmlWriter->endElement();
+ return;
+ }
+ if( !row->sheet() ) return;
+
+ // find the column of the rightmost cell (if any)
+ int lastCol = -1;
+ Sheet* sheet= row->sheet();
+ unsigned rowIndex = row->index();
+ for( unsigned i = 0; i <= sheet->maxColumn(); i++ )
+ if( sheet->cell( i, rowIndex, false ) )
+ lastCol = i;
+
+ xmlWriter->startElement( "table:table-row" );
+ xmlWriter->addAttribute( "table:visibility", row->visible() ? "visible" : "collapse" );
+ xmlWriter->addAttribute( "table:style-name", QString("ro%1").arg(rowFormatIndex) );
+ rowFormatIndex++;
+
+ for( int i = 0; i <= lastCol; i++ )
+ {
+ Cell* cell = sheet->cell( i, rowIndex, false );
+ if( cell )
+ processCellForBody( cell, xmlWriter );
+ else
+ {
+ // empty cell
+ xmlWriter->startElement( "table:table-cell" );
+ xmlWriter->endElement();
+ }
+ }
+
+ xmlWriter->endElement(); // table:table-row
+}
+
+void ExcelImport::Private::processRowForStyle( Row* row, int repeat, KoXmlWriter* xmlWriter )
+{
+ if( !row ) return;
+ if( !row->sheet() ) return;
+ if( !xmlWriter ) return;
+
+ // find the column of the rightmost cell (if any)
+ int lastCol = -1;
+ Sheet* sheet= row->sheet();
+ unsigned rowIndex = row->index();
+ for( unsigned i = 0; i <= sheet->maxColumn(); i++ )
+ if( sheet->cell( i, rowIndex, false ) )
+ lastCol = i;
+
+ xmlWriter->startElement( "style:style" );
+ xmlWriter->addAttribute( "style:family", "table-row" );
+ if(repeat > 1) xmlWriter->addAttribute( "table:number-rows-repeated", repeat );
+ xmlWriter->addAttribute( "style:name", QString("ro%1").arg(rowFormatIndex) );
+ rowFormatIndex++;
+
+ xmlWriter->startElement( "style:table-row-properties" );
+ xmlWriter->addAttribute( "fo:break-before", "auto" );
+ xmlWriter->addAttribute( "style:row-height", QString("%1pt").arg(row->height()) );
+ xmlWriter->endElement(); // style:table-row-properties
+
+ xmlWriter->endElement(); // style:style
+
+ for( int i = 0; i <= lastCol; i++ )
+ {
+ Cell* cell = sheet->cell( i, rowIndex, false );
+ if( cell )
+ processCellForStyle( cell, xmlWriter );
+ }
+}
+
+static bool isPercentageFormat( const QString& valueFormat )
+{
+ if( valueFormat.isEmpty() ) return false;
+ if( valueFormat.length() < 1 ) return false;
+ return valueFormat[valueFormat.length()-1] == QChar('%');
+}
+
+static bool isDateFormat( const QString& valueFormat )
+{
+ QString vfu = valueFormat.upper();
+
+ if( vfu == "M/D/YY" ) return true;
+ if( vfu == "M/D/YYYY" ) return true;
+ if( vfu == "MM/DD/YY" ) return true;
+ if( vfu == "MM/DD/YYYY" ) return true;
+ if( vfu == "D-MMM-YY" ) return true;
+ if( vfu == "D\\-MMM\\-YY" ) return true;
+ if( vfu == "D-MMM-YYYY" ) return true;
+ if( vfu == "D\\-MMM\\-YYYY" ) return true;
+ if( vfu == "D-MMM" ) return true;
+ if( vfu == "D\\-MMM" ) return true;
+ if( vfu == "D-MM" ) return true;
+ if( vfu == "D\\-MM" ) return true;
+ if( vfu == "MMM/DD" ) return true;
+ if( vfu == "MMM/D" ) return true;
+ if( vfu == "MM/DD" ) return true;
+ if( vfu == "MM/D" ) return true;
+ if( vfu == "MM/DD/YY" ) return true;
+ if( vfu == "MM/DD/YYYY" ) return true;
+ if( vfu == "YYYY/MM/D" ) return true;
+ if( vfu == "YYYY/MM/DD" ) return true;
+ if( vfu == "YYYY-MM-D" ) return true;
+ if( vfu == "YYYY\\-MM\\-D" ) return true;
+ if( vfu == "YYYY-MM-DD" ) return true;
+ if( vfu == "YYYY\\-MM\\-DD" ) return true;
+
+ return false;
+}
+
+static bool isTimeFormat( const QString& valueFormat )
+{
+ QString vf = valueFormat;
+
+ if( vf == "h:mm AM/PM" ) return true;
+ if( vf == "h:mm:ss AM/PM" ) return true;
+ if( vf == "h:mm" ) return true;
+ if( vf == "h:mm:ss" ) return true;
+ if( vf == "[h]:mm:ss" ) return true;
+ if( vf == "[h]:mm" ) return true;
+ if( vf == "[mm]:ss" ) return true;
+ if( vf == "M/D/YY h:mm" ) return true;
+ if( vf == "[ss]" ) return true;
+ if( vf == "mm:ss" ) return true;
+ if( vf == "mm:ss.0" ) return true;
+ if( vf == "[mm]:ss" ) return true;
+ if( vf == "[ss]" ) return true;
+
+ return false;
+}
+
+static QString convertDate( double serialNo )
+{
+ // reference is midnight 30 Dec 1899
+ QDate dd( 1899, 12, 30 );
+ dd = dd.addDays( (int) serialNo );
+ return dd.toString( "yyyy-MM-dd" );
+}
+
+static QString convertTime( double serialNo )
+{
+ // reference is midnight 30 Dec 1899
+ QTime tt;
+ tt = tt.addMSecs( qRound( (serialNo-(int)serialNo) * 86400 * 1000 ) );
+ return tt.toString( "PThhHmmMss,zzz0S" );
+}
+
+void ExcelImport::Private::processCellForBody( Cell* cell, KoXmlWriter* xmlWriter )
+{
+ if( !cell ) return;
+ if( !xmlWriter ) return;
+
+ int formatIndex = cell->formatIndex();
+
+ QString styleName("ce");
+ styleName.append( QString::number( formatIndex ) );
+ xmlWriter->startElement( "table:table-cell" );
+ xmlWriter->addAttribute( "table:style-name", styleName );
+
+ if( !cell->formula().isEmpty() )
+ {
+ QString formula = string( cell->formula() ).string();
+ xmlWriter->addAttribute( "table:formula", formula.prepend("=") );
+ }
+
+ const Value& value = cell->value();
+
+ if( value.isBoolean() )
+ {
+ xmlWriter->addAttribute( "office:value-type", "boolean" );
+ xmlWriter->addAttribute( "office:boolean-value", value.asBoolean() ? "true" : "false" );
+ }
+ else if( value.isFloat() || value.isInteger() )
+ {
+ if( isPercentageStyle[formatIndex] )
+ {
+ xmlWriter->addAttribute( "office:value-type", "percentage" );
+ xmlWriter->addAttribute( "office:value", QString::number( value.asFloat(), 'g', 15 ) );
+ }
+ else if( isDateStyle[formatIndex] )
+ {
+ xmlWriter->addAttribute( "office:value-type", "date" );
+ xmlWriter->addAttribute( "office:date-value", convertDate( value.asFloat() ) );
+ }
+ else if( isTimeStyle[formatIndex] )
+ {
+ xmlWriter->addAttribute( "office:value-type", "time" );
+ xmlWriter->addAttribute( "office:time-value", convertTime( value.asFloat() ) );
+ }
+ else
+ {
+ // fallback, just write as normal number
+ xmlWriter->addAttribute( "office:value-type", "float" );
+ xmlWriter->addAttribute( "office:value", QString::number( value.asFloat(), 'g', 15 ) );
+ }
+ }
+ else if( value.isString() )
+ {
+ QString str = string( value.asString() ).string();
+ xmlWriter->addAttribute( "office:value-type", "string" );
+ xmlWriter->addAttribute( "office:string-value", str );
+ xmlWriter->startElement( "text:p" );
+ xmlWriter->addTextNode( str );
+ xmlWriter->endElement(); // text:p
+ }
+
+ xmlWriter->endElement(); // table:table-cell
+}
+
+void ExcelImport::Private::processCellForStyle( Cell* cell, KoXmlWriter* xmlWriter )
+{
+ if( !cell ) return;
+ if( !xmlWriter ) return;
+
+ // only IF automatic style for this format has not been already created yet
+ if( !styleFormats.contains( cell->formatIndex() ) )
+ {
+ styleFormats[ cell->formatIndex() ] = true;
+
+ const Format& format = cell->sheet()->workbook()->format( cell->formatIndex() );
+
+ // handle data format, e.g. number style
+ QString refName;
+ const UString& valueFormat = format.valueFormat();
+ if( !valueFormat.isEmpty() )
+ {
+ refName = QString("N%1").arg(cell->formatIndex());
+ QString numformat = string( valueFormat ).string();
+ processValueFormat( numformat, refName, xmlWriter );
+ }
+
+ // later for writing the value
+ QString numformat = string( valueFormat ).string();
+ isPercentageStyle[ cell->formatIndex() ] = isPercentageFormat( numformat );
+ isDateStyle[ cell->formatIndex() ] = isDateFormat( numformat );
+ isTimeStyle[ cell->formatIndex() ] = isTimeFormat( numformat );
+
+ // now the real table-cell
+ xmlWriter->startElement( "style:style" );
+ xmlWriter->addAttribute( "style:family", "table-cell" );
+ xmlWriter->addAttribute( "style:name", QString("ce%1").arg( cell->formatIndex() ) );
+ if( !refName.isEmpty() )
+ xmlWriter->addAttribute( "style:data-style-name", refName );
+
+ processFormat( &format, xmlWriter );
+
+ xmlWriter->endElement(); // style:style
+ }
+}
+
+QString convertColor( const Color& color )
+{
+ char buf[8];
+ sprintf( buf, "#%02x%02x%02x", color.red, color.green, color.blue );
+ return QString( buf );
+}
+
+QString convertBorder( const Pen& pen )
+{
+ if( pen.style == Pen::NoLine || pen.width == 0 ) return "none";
+
+ QString result = QString::number( pen.width );
+ result += "pt ";
+
+ switch( pen.style )
+ {
+ case Pen::SolidLine: result += "solid "; break;
+ case Pen::DashLine: result += "dashed "; break;
+ case Pen::DotLine: result += "dotted "; break;
+ case Pen::DashDotLine: result += "dot-dash "; break;
+ case Pen::DashDotDotLine: result += "dot-dot-dash "; break;
+ }
+
+ return result + convertColor( pen.color );
+}
+
+void ExcelImport::Private::processFormat( const Format* format, KoXmlWriter* xmlWriter )
+{
+ if( !format ) return;
+ if( !xmlWriter ) return;
+
+ const FormatFont& font = format->font();
+ const FormatAlignment& align = format->alignment();
+ const FormatBackground& back = format->background();
+ const FormatBorders& borders = format->borders();
+
+ if( !font.isNull() )
+ {
+ xmlWriter->startElement( "style:text-properties" );
+
+ if( font.bold() )
+ xmlWriter->addAttribute( "fo:font-weight", "bold" );
+
+ if( font.italic() )
+ xmlWriter->addAttribute( "fo:font-style", "italic" );
+
+ if( font.underline() )
+ {
+ xmlWriter->addAttribute( "style:text-underline-style", "solid" );
+ xmlWriter->addAttribute( "style:text-underline-width", "auto" );
+ xmlWriter->addAttribute( "style:text-underline-color", "font-color" );
+ }
+
+ if( font.strikeout() )
+ xmlWriter->addAttribute( "style:text-line-through-style", "solid" );
+
+ if( font.subscript() )
+ xmlWriter->addAttribute( "style:text-position", "sub" );
+
+ if( font.superscript() )
+ xmlWriter->addAttribute( "style:text-position", "super" );
+
+ if( !font.fontFamily().isEmpty() )
+ xmlWriter->addAttribute( "style:font-name", string(font.fontFamily()).string() );
+
+ xmlWriter->addAttribute( "fo:font-size", QString("%1pt").arg(font.fontSize()) );
+
+ xmlWriter->addAttribute( "fo:color", convertColor( font.color() ) );
+
+ xmlWriter->endElement(); // style:text-properties
+ }
+
+ xmlWriter->startElement( "style:table-cell-properties" );
+ if( !align.isNull() )
+ {
+ switch( align.alignY() ) {
+ case Format::Top: xmlWriter->addAttribute( "style:vertical-align", "top" ); break;
+ case Format::Middle: xmlWriter->addAttribute( "style:vertical-align", "middle" ); break;
+ case Format::Bottom: xmlWriter->addAttribute( "style:vertical-align", "bottom" ); break;
+ }
+
+ xmlWriter->addAttribute( "fo:wrap-option", align.wrap() ? "wrap" : "no-wrap" );
+ //TODO rotation
+ //TODO stacked letters
+ }
+
+ if( !borders.isNull() )
+ {
+ xmlWriter->addAttribute( "fo:border-left", convertBorder( borders.leftBorder() ) );
+ xmlWriter->addAttribute( "fo:border-right", convertBorder( borders.rightBorder() ) );
+ xmlWriter->addAttribute( "fo:border-top", convertBorder( borders.topBorder() ) );
+ xmlWriter->addAttribute( "fo:border-bottom", convertBorder( borders.bottomBorder() ) );
+ //TODO diagonal 'borders'
+ }
+
+ if( !back.isNull() && back.pattern() != FormatBackground::EmptyPattern )
+ {
+ Color backColor = back.backgroundColor();
+ if( back.pattern() == FormatBackground::SolidPattern )
+ backColor = back.foregroundColor();
+
+ xmlWriter->addAttribute( "fo:background-color", convertColor( backColor ) );
+
+ //TODO patterns
+ }
+ xmlWriter->endElement(); // style:table-cell-properties
+
+ xmlWriter->startElement( "style:paragraph-properties" );
+ if( !align.isNull() )
+ {
+ switch( align.alignX() ) {
+ case Format::Left: xmlWriter->addAttribute( "fo:text-align", "start" ); break;
+ case Format::Center: xmlWriter->addAttribute( "fo:text-align", "center" ); break;
+ case Format::Right: xmlWriter->addAttribute( "fo:text-align", "end" ); break;
+ }
+
+ if( align.indentLevel() != 0 )
+ xmlWriter->addAttribute( "fo:margin-left", QString::number( align.indentLevel() ) + "0pt" );
+ }
+ xmlWriter->endElement(); // style:paragraph-properties
+}
+
+void ExcelImport::Private::processValueFormat( QString valueFormat, QString refName,
+KoXmlWriter* xmlWriter )
+{
+ /*int decimalPlaces = 2;
+ int leadingZeroes = 1;
+ int exponentDigits = -1;
+ bool percentage = false;*/
+
+ // TODO: someday we need a real MS Excel to OpenDocument format paraser
+ // this just catches the most common format, not covers all possible cases
+
+ if( valueFormat == "0")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 0 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 1 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 2 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 3 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 4 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 5 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 6 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 7 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 8 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 9 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 10 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00000000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 11 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000000000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 12 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000000000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 13 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00000000000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 14 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000000000000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 15 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000000000000000")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 16 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 0 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 1 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 2 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 3 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 4 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 5 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 6 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 7 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 8 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 9 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 10 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00000000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 11 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000000000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 12 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000000000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 13 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.00000000000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 14 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.000000000000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 16 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0.0000000000000000E+00")
+ {
+ xmlWriter->startElement( "number:number-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->startElement( "number:scientific-number" );
+ xmlWriter->addAttribute( "number:decimal-places", 17 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->addAttribute( "number:min-exponent-digits", 2 );
+ xmlWriter->endElement(); // number:scientific-number
+ xmlWriter->endElement(); // number:number-style
+ }
+ else if( valueFormat == "0%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 0 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.0%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 1 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.00%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 2 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 3 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.0000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 4 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.00000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 5 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 6 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.0000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 7 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.00000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 8 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.000000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 9 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.0000000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 10 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.00000000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 11 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.000000000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 12 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.0000000000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 13 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.00000000000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 14 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.000000000000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 15 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat == "0.0000000000000000%")
+ {
+ xmlWriter->startElement( "number:percentage-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->startElement( "number:number" );
+ xmlWriter->addAttribute( "number:decimal-places", 16 );
+ xmlWriter->addAttribute( "number:min-integer-digits", 1 );
+ xmlWriter->endElement(); // number:number
+ xmlWriter->startElement( "number:text" );
+ xmlWriter->addTextNode( "%" );
+ xmlWriter->endElement(); // number:text
+ xmlWriter->endElement(); // number:percentage-style
+ }
+ else if( valueFormat.lower() == "m/d/yy")
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "m/d/yyyy")
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( (valueFormat.lower() == "d-mmm-yy") || (valueFormat.lower() == "d\\-mmm\\-yy") )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "true" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( (valueFormat.lower() == "d-mmm-yyyy") || (valueFormat.lower() == "d\\-mmm\\-yyyy") )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "true" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( (valueFormat.lower() == "d-mmm") || (valueFormat.lower() == "d\\-mmm") )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "true" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( (valueFormat.lower() == "d-mm") || (valueFormat.lower() == "d\\-mm") )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "mmm/d" )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "true" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "mmm/dd" )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "true" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "mm/d" )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "mm/dd" )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "mm/dd/yy" )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "mm/dd/yyyy" )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "yyyy/mm/dd" )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( valueFormat.lower() == "yyyy/mm/d" )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "/" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( (valueFormat.lower() == "yyyy-mm-dd") || (valueFormat.lower() == "yyyy\\-mm\\-dd") )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->endElement(); // number:date-style
+ }
+ else if( (valueFormat.lower() == "yyyy-mm-d") || (valueFormat.lower() == "yyyy\\-mm\\-d") )
+ {
+ xmlWriter->startElement( "number:date-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:year" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:year
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:month" );
+ xmlWriter->addAttribute( "number:textual", "false" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:month
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( "-" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:day" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:day
+
+ xmlWriter->endElement(); // number:date-style
+ }
+
+ else if( valueFormat == "h:mm AM/PM" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:hours" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:hour
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( " " );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:am-pm" );
+ xmlWriter->endElement(); // number:am-pm
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "h:mm:ss AM/PM" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:hours" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:hour
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:seconds" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( " " );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:am-pm" );
+ xmlWriter->endElement(); // number:am-pm
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "h:mm" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:hours" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:hour
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "h:mm:ss" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:hours" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:hour
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:seconds" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "[h]:mm" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->addAttribute( "number:truncate-on-overflow", "false" );
+
+ xmlWriter->startElement( "number:hours" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:hour
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "[h]:mm:ss" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->addAttribute( "number:truncate-on-overflow", "false" );
+
+ xmlWriter->startElement( "number:hours" );
+ xmlWriter->addAttribute( "number:style", "short" );
+ xmlWriter->endElement(); // number:hour
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:seconds" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "mm:ss" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:seconds" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "mm:ss.0" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:seconds" );
+ xmlWriter->addAttribute( "number:style", "long" );
+
+ xmlWriter->endElement(); // number:minutes
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ".0" );
+ xmlWriter->endElement(); // number:text
+
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "[mm]:ss" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->addAttribute( "number:truncate-on-overflow", "false" );
+
+ xmlWriter->startElement( "number:minutes" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->startElement( "number:text");
+ xmlWriter->addTextNode( ":" );
+ xmlWriter->endElement(); // number:text
+
+ xmlWriter->startElement( "number:seconds" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->endElement(); // number:time-style
+ }
+ else if( valueFormat == "[ss]" )
+ {
+ xmlWriter->startElement( "number:time-style" );
+ xmlWriter->addAttribute( "style:name", refName );
+ xmlWriter->addAttribute( "style:family", "data-style" );
+ xmlWriter->addAttribute( "number:truncate-on-overflow", "false" );
+
+ xmlWriter->startElement( "number:seconds" );
+ xmlWriter->addAttribute( "number:style", "long" );
+ xmlWriter->endElement(); // number:minutes
+
+ xmlWriter->endElement(); // number:time-style
+ }
+
+}
diff --git a/filters/kspread/excel/import/excelimport.h b/filters/kspread/excel/import/excelimport.h
new file mode 100644
index 000000000..e3cc3f0ec
--- /dev/null
+++ b/filters/kspread/excel/import/excelimport.h
@@ -0,0 +1,45 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003-2006 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef EXCELIMPORT_H
+#define EXCELIMPORT_H
+
+#include <KoFilter.h>
+#include <KoStore.h>
+
+#include <qcstring.h>
+
+class ExcelImport : public KoFilter {
+
+ Q_OBJECT
+
+public:
+
+ ExcelImport ( QObject *parent, const char* name, const QStringList& );
+ virtual ~ExcelImport();
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+
+private:
+ class Private;
+ Private* d;
+
+};
+
+#endif // EXCELIMPORT_H
diff --git a/filters/kspread/excel/import/kspread_excel_import.desktop b/filters/kspread/excel/import/kspread_excel_import.desktop
new file mode 100644
index 000000000..71682e5d2
--- /dev/null
+++ b/filters/kspread/excel/import/kspread_excel_import.desktop
@@ -0,0 +1,61 @@
+[Desktop Entry]
+Type=Service
+Name=KSpread Microsoft Excel Import Filter
+Name[bg]=Филтър за импортиране от Microsoft Excel в KSpread
+Name[br]=Sil enporzh Microsoft Excel evit KSpread
+Name[ca]=Filtre d'importació Microsoft Excel per a KSpread
+Name[cs]=Importní filtr Microsoft Excel pro KSpread
+Name[cy]=Hidlen Fewnforio Microsoft Excel KSpread
+Name[da]=KSpread Microsoft Excel import-filter
+Name[de]=KSpread Microsoft Excel-Importfilter
+Name[el]=Φίλτρο εισαγωγής Microsoft Excel του KSpread
+Name[eo]=KSpread MS-Excel-importfiltrilo
+Name[es]=Filtro de importación a Microsoft Excel de KSpread
+Name[et]=KSpreadi Microsoft Excel'i impordifilter
+Name[eu]=KSpread-en Microsoft Excel inportaziorako iragazkia
+Name[fa]=پالایۀ واردات KSpread Microsoft Excel
+Name[fi]=KSpread Microsoft Excel -tuontisuodin
+Name[fr]=Filtre d'importation Microsoft Excel de KSpread
+Name[fy]=KSpread Microsoft Excel Ymportfilter
+Name[ga]=Scagaire Iompórtála Microsoft Excel le haghaidh KSpread
+Name[gl]=Filtro de Importación de Microsoft Excel para KSpread
+Name[he]=מסנן ייבוא מ־Microsoft Excel ל־KSpread
+Name[hi]=के-स्प्रेड माइक्रोसॉफ़्ट एक्सेल आयात छननी
+Name[hr]=KSpread Microsoft Excel filtar uvoza
+Name[hu]=KWord Microsoft Excel importszűrő
+Name[is]=KSpread Microsoft Excel innflutningssía
+Name[it]=Filtro di importazione Microsoft Excel per KSpread
+Name[ja]=KSpread Microsoft Excel インポートフィルタ
+Name[km]=តម្រង​នាំចេញ Microsoft Excel សម្រាប់ KSpread
+Name[lt]=KSpread Microsoft Excel importavimo filtras
+Name[lv]=KSpread Microsoft Excel importa filtrs
+Name[ms]=Penapis Import KSpread Microsoft Excel
+Name[nb]=Microsoft Excel-importfilter for KSpread
+Name[nds]=Microsoft Excel-Importfilter för KSpread
+Name[ne]=केडीई स्प्रिेड माइक्रोसफ्ट एक्सेल आयात फिल्टर
+Name[nl]=KSpread Microsoft Excell Importfilter
+Name[nn]=Microsoft Excel-importfilter for KSpread
+Name[pl]=Filtr importu formatu Microsoft Excel do KSpread
+Name[pt]=Filtro de Importação de Microsoft Excel para o KSpread
+Name[pt_BR]=Filtro de importação Microsoft Excel para o KSpread
+Name[ru]=Фильтр импорта таблиц Microsoft Excel в KSpread
+Name[se]=KWord:a Microsoft Writer-sisafievrridansilli
+Name[sk]=Microsoft Excel filter pre import do KSpread
+Name[sl]=Uvozni filter Microsoft Excell za KSpread
+Name[sr]=KSpread-ов филтер за увоз из Microsoft-овог Excel-а
+Name[sr@Latn]=KSpread-ov filter za uvoz iz Microsoft-ovog Excel-a
+Name[sv]=Microsoft Excel-importfilter för Kspread
+Name[ta]=Kspread Microsoft excel இறக்குமதி வடிகட்டி
+Name[tg]=Филтри Воридоти KSpread Microsoft Excel
+Name[tr]=KSpread Microsoft Excel Alma Filtresi
+Name[uk]=Фільтр імпорту Microsoft Excel для KSpread
+Name[uz]=KSpread Microsoft Excel import filteri
+Name[uz@cyrillic]=KSpread Microsoft Excel импорт филтери
+Name[wa]=Passete MS-Excel d' intrêye po KSpread
+Name[zh_CN]=KSpread Microsoft Excel 导入过滤器
+Name[zh_TW]=KSpread Microsoft Excel 匯入過濾程式
+X-KDE-Export=application/vnd.oasis.opendocument.spreadsheet
+X-KDE-Import=application/msexcel
+X-KDE-Weight=1
+X-KDE-Library=libexcelimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/excel/kspread_excel_export.desktop b/filters/kspread/excel/kspread_excel_export.desktop
new file mode 100644
index 000000000..7a4eb20df
--- /dev/null
+++ b/filters/kspread/excel/kspread_excel_export.desktop
@@ -0,0 +1,61 @@
+[Desktop Entry]
+Type=Service
+Name=Excel Export Filter for KSpread
+Name[bg]=Филтър за експортиране от KSpread в Excel
+Name[br]=Sil ezporzh Excel evit KSpread
+Name[ca]=Filtre d'exportació Excel per a KSpread
+Name[cs]=Exportní filtr Excel pro KSpread
+Name[cy]=Hidlen Allforio Excel i KSpread
+Name[da]=Excel-eksportfilter for KSpread
+Name[de]=KSpread Microsoft Excel-Exportfilter
+Name[el]=Φίλτρο εξαγωγής Excel για το KSpread
+Name[eo]=Excel-eksportfiltrilo por KSpread
+Name[es]=Filtro de exportación de Excel para KSpread
+Name[et]=KSpreadi Excel'i ekspordifilter
+Name[eu]=KSpread-en Excel esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات Excel برای KSpread
+Name[fi]=KSpread Microsoft Excel -vientisuodin
+Name[fr]=Filtre d'exportation Excel de KSpread
+Name[fy]=Excel-Eksportfilter foar KSpread
+Name[ga]=Scagaire Easpórtála Microsoft Excel le haghaidh KSpread
+Name[gl]=Filtro de Exportación de Excel para KSpread
+Name[he]=מסנן ייצוא מ־KSpread ל־Excel
+Name[hi]=के-स्प्रेड के लिए एक्सेल निर्यात छननी
+Name[hr]=Excel filtar izvoza za KSpread
+Name[hu]=Excel exportszűrő a KSpreadhez
+Name[is]=Excel útflutningssía fyrir KSpread
+Name[it]=Filtro di esportazione Microsoft Excel per KSpread
+Name[ja]=KSpread Excel エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ Excel សម្រាប់ KSpread
+Name[lo]= ຕົວຕອງການສົ່ງອອກ CSV ຂອງກະດາດຄຳນວນ K
+Name[lt]=Excel eksportavimo filtras skirtas KSpread
+Name[lv]=Excel eksporta filtrs priekš KSpread
+Name[ms]=Penapis Eksport Excel bagi KSpread
+Name[nb]=Excel-eksportfilter for KSpread
+Name[nds]=Microsoft Excel-Exportfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि एक्सेल निर्यात
+Name[nl]=Excel Exportfilter voor KSpread
+Name[nn]=Excel-eksportfilter for KSpread
+Name[pl]=Filtr eksportu do formatu Excela dla KSpread
+Name[pt]=Filtro de Exportação de Excel para o KSpread
+Name[pt_BR]=Filtro de Exportação Excel para o KSpread
+Name[ru]=Фильтр экспорта таблиц KSpread в Excel
+Name[se]=KSpread:a Excel-olggosfievrridansilli
+Name[sk]=Excel filter pre export z KSpread
+Name[sl]=Izvozni filter Excel za KSpread
+Name[sr]=KSpread-ов филтер за извоз у Excel
+Name[sr@Latn]=KSpread-ov filter za izvoz u Excel
+Name[sv]=Excel-exportfilter för Kspread
+Name[ta]=excel ஏற்றுமதி வடிகட்டி kspread
+Name[tg]=Филтри Содироти Excel барои KSpread
+Name[tr]=KSpread Excel Aktarma Filtresi
+Name[uk]=Фільтр експорту Microsoft Excel для KSpread
+Name[uz]=KSpread uchun Excel eksport filteri
+Name[uz@cyrillic]=KSpread учун Excel экспорт филтери
+Name[zh_CN]=KSpread 的 Excel 导出过滤器
+Name[zh_TW]=KSpread 的 Excel 匯出過濾程式
+#X-KDE-Export=application/msexcel
+#X-KDE-Import=application/x-kspread
+#X-KDE-Weight=1
+#X-KDE-Library=libkspreadexcelexport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/excel/sidewinder/Makefile.am b/filters/kspread/excel/sidewinder/Makefile.am
new file mode 100644
index 000000000..99f157bbb
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES= -I$(srcdir) -I$(srcdir)/.. $(all_includes)
+
+noinst_LTLIBRARIES = libsidewinder.la
+libsidewinder_la_SOURCES = cell.cpp excel.cpp format.cpp pole.cpp sheet.cpp ustring.cpp value.cpp workbook.cpp
+
diff --git a/filters/kspread/excel/sidewinder/README.Sidewinder b/filters/kspread/excel/sidewinder/README.Sidewinder
new file mode 100644
index 000000000..14405f819
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/README.Sidewinder
@@ -0,0 +1,28 @@
+README for Sidewinder
+
+Goal: C++ library to access spreadsheet documents, especially Microsoft
+Excel workbook.
+
+
+The experimental Excel import filter based on Sidewinder resides in
+koffice/filters/kspread/excel/import. If you compile it, here's a step to
+resolve conflict with the current Excel import filter: put the following
+uninstall.desktop in koffice/filters/olefilters/excel97 to disable the it.
+
+[Desktop Entry]
+Encoding=UTF-8
+Hidden=true
+
+
+References and Links
+===============
+Excel file format documentation from OpenOffice.org
+http://sc.openoffice.org/excelfileformat.pdf
+
+Excel import filter for KSpread (koffice/filters/olefilters/excel97)
+
+Jakarta POI Project
+http://jakarta.apache.org/poi/
+
+Excel plug-in for Gnumeric (gnumeric/plugins/excel)
+
diff --git a/filters/kspread/excel/sidewinder/cell.cpp b/filters/kspread/excel/sidewinder/cell.cpp
new file mode 100644
index 000000000..b9000ba37
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/cell.cpp
@@ -0,0 +1,220 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#include "cell.h"
+
+#include "ustring.h"
+#include "format.h"
+#include "value.h"
+
+#include <iostream>
+
+namespace Swinder
+{
+
+class CellPrivate
+{
+public:
+ Sheet* sheet;
+ unsigned column;
+ unsigned row;
+ UString formula;
+ Value value;
+ Format* format;
+ int formatIndex;
+ unsigned columnSpan;
+ unsigned rowSpan;
+
+ static UString columnNames[256];
+
+ CellPrivate(Sheet* s, unsigned column, unsigned row);
+ ~CellPrivate() { delete format; }
+};
+
+}
+
+using namespace Swinder;
+
+UString CellPrivate::columnNames[256];
+
+
+CellPrivate::CellPrivate(Sheet* s, unsigned c, unsigned r):
+sheet(s), column(c), row(r), format(0), formatIndex(-1), columnSpan(0), rowSpan(0)
+{
+}
+
+Cell::Cell( Sheet* sheet, unsigned column, unsigned row )
+{
+ d = new CellPrivate(sheet, column, row);
+}
+
+Cell::~Cell()
+{
+ delete d;
+}
+
+Sheet* Cell::sheet()
+{
+ return d->sheet;
+}
+
+unsigned Cell::column() const
+{
+ return d->column;
+}
+
+unsigned Cell::row() const
+{
+ return d->row;
+}
+
+UString Cell::name() const
+{
+ return name( column(), row() );
+}
+
+UString Cell::name( unsigned column, unsigned row )
+{
+ // column=0, row=0 is "A1"
+ return columnLabel( column ) + UString::number( row + 1 );
+}
+
+UString Cell::columnLabel() const
+{
+ return columnLabel( column() );
+}
+
+
+UString Cell::columnLabel( unsigned column )
+{
+ UString label;
+
+ // Excel has only up to 256 columns, so we cache those
+ if(column < 256 )
+ {
+ label = CellPrivate::columnNames[column];
+
+ // cache is not ready, so construct it first
+ if(label.isEmpty())
+ {
+ for(unsigned c = 0; c < 26; c++)
+ CellPrivate::columnNames[c] = UString(UChar((char)'A'+c));
+ for(unsigned d = 0; d < 256-26; d++)
+ {
+ char buf[3] = { 'A'+(d/26), 'A'+(d%26), 0};
+ CellPrivate::columnNames[d+26] = UString(buf);
+ }
+
+ label = CellPrivate::columnNames[column];
+ }
+ }
+ else
+ {
+ // otherwise, find with slower method
+
+ // how many characters for the column name?
+ unsigned digits = 1;
+ unsigned offset = 0;
+ for( unsigned limit = 26; column-offset >= limit; limit *= 26, digits++ )
+ offset += limit;
+
+ // extreme case e.g. column 4294967295 is "AATYHWUR" (8 characters)
+ if(digits < 9)
+ {
+ char ref[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ // from the last character
+ char* colp = ref + 9 - 1;
+ for( unsigned c = column - offset; digits; --digits, c/=26, colp-- )
+ *colp = char('A' + (c%26));
+
+ label = UString((const char*)(colp+1));
+ }
+ }
+
+ return label;
+}
+
+const Value& Cell::value() const
+{
+ return d->value;
+}
+
+void Cell::setValue( const Value& value )
+{
+ d->value = value;
+}
+
+const UString& Cell::formula() const
+{
+ return d->formula;
+}
+
+void Cell::setFormula( const UString& formula )
+{
+ d->formula = formula;
+}
+
+int Cell::formatIndex() const
+{
+ return d->formatIndex;
+}
+
+void Cell::setFormatIndex( int index )
+{
+ d->formatIndex = index;
+}
+
+Format Cell::format() const
+{
+ if(!d->format)
+ d->format = new Format();
+
+ return Format(*d->format);
+}
+
+void Cell::setFormat( const Format& format )
+{
+ if(!d->format)
+ d->format = new Format();
+
+ (*d->format) = format;
+}
+
+unsigned Cell::columnSpan() const
+{
+ return d->columnSpan;
+}
+
+void Cell::setColumnSpan( unsigned span )
+{
+ if( span < 1 ) return;
+ d->columnSpan = span;
+}
+
+unsigned Cell::rowSpan() const
+{
+ return d->rowSpan;
+}
+
+void Cell::setRowSpan( unsigned span )
+{
+ if( span < 1 ) return;
+ d->rowSpan = span;
+}
diff --git a/filters/kspread/excel/sidewinder/cell.h b/filters/kspread/excel/sidewinder/cell.h
new file mode 100644
index 000000000..80ad92a15
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/cell.h
@@ -0,0 +1,94 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#ifndef SWINDER_CELL_H
+#define SWINDER_CELL_H
+
+#include "ustring.h"
+#include "format.h"
+#include "value.h"
+
+namespace Swinder
+{
+
+class Workbook;
+class Sheet;
+
+// don't export this private class
+class CellPrivate;
+
+class Cell
+{
+public:
+
+ Cell( Sheet* sheet, unsigned column, unsigned row );
+
+ virtual ~Cell();
+
+ Sheet* sheet();
+
+ unsigned column() const;
+
+ unsigned row() const;
+
+ UString name() const;
+
+ static UString name( unsigned column, unsigned row );
+
+ UString columnLabel() const;
+
+ static UString columnLabel( unsigned column );
+
+ const Value& value() const;
+
+ void setValue( const Value& value );
+
+ const UString& formula() const;
+
+ void setFormula( const UString& formula );
+
+ Format format() const;
+
+ void setFormat( const Format& format );
+
+ void setFormatIndex( int index );
+
+ int formatIndex() const;
+
+ unsigned columnSpan() const;
+
+ void setColumnSpan( unsigned span );
+
+ unsigned rowSpan() const;
+
+ void setRowSpan( unsigned span );
+
+private:
+ // no copy or assign
+ Cell( const Cell& );
+ Cell& operator=( const Cell& );
+
+ CellPrivate *d;
+};
+
+} // namespace Swinder
+
+
+#endif // SWINDER_CELL_H
+
diff --git a/filters/kspread/excel/sidewinder/excel.cpp b/filters/kspread/excel/sidewinder/excel.cpp
new file mode 100644
index 000000000..e7c579724
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/excel.cpp
@@ -0,0 +1,6428 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003-2006 Ariya Hidayat <ariya@kde.org>
+ Copyright (C) 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#include "excel.h"
+
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <string>
+#include <map>
+#include <stdio.h> // memcpy
+#include <string.h>
+#include <stdlib.h>
+
+#include "pole.h"
+#include "swinder.h"
+
+// Use anonymous namespace to cover following functions
+namespace{
+
+static inline unsigned long readU16( const void* p )
+{
+ const unsigned char* ptr = (const unsigned char*) p;
+ return ptr[0]+(ptr[1]<<8);
+}
+
+static inline int readI16( const void* p )
+{
+ const unsigned char* ptr = (const unsigned char*) p;
+ unsigned int v = ptr[0]+(ptr[1]<<8);
+ if(v > 32768) v -= 65536;
+ return v;
+}
+
+static inline unsigned long readU32( const void* p )
+{
+ const unsigned char* ptr = (const unsigned char*) p;
+ return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
+}
+
+typedef double& data_64;
+inline void convert_64 (data_64 convert)
+{
+ register unsigned char temp;
+ register unsigned int u_int_temp;
+ temp = ((unsigned char*)&convert)[0];
+ ((unsigned char*)&convert)[0] = ((unsigned char*)&convert)[3];
+ ((unsigned char*)&convert)[3] = temp;
+ temp = ((unsigned char*)&convert)[1];
+ ((unsigned char*)&convert)[1] = ((unsigned char*)&convert)[2];
+ ((unsigned char*)&convert)[2] = temp;
+ temp = ((unsigned char*)&convert)[4];
+ ((unsigned char*)&convert)[4] = ((unsigned char*)&convert)[7];
+ ((unsigned char*)&convert)[7] = temp;
+ temp = ((unsigned char*)&convert)[5];
+ ((unsigned char*)&convert)[5] = ((unsigned char*)&convert)[6];
+ ((unsigned char*)&convert)[6] = temp;
+
+ u_int_temp = ((unsigned int *)&convert)[0];
+ ((unsigned int *)&convert)[0] = ((unsigned int *)&convert)[1];
+ ((unsigned int *)&convert)[1] = u_int_temp;
+}
+
+inline bool isLittleEndian(void)
+{
+ long i = 0x44332211;
+ unsigned char* a = (unsigned char*) &i;
+ return ( *a == 0x11 );
+}
+
+
+// FIXME check that double is 64 bits
+static inline double readFloat64( const void*p )
+{
+ const double* ptr = (const double*) p;
+ double num = 0.0;
+ num = *ptr;
+
+ if( !isLittleEndian() )
+ convert_64( num );
+
+ return num;
+}
+
+// RK value is special encoded integer or floating-point
+// see any documentation of Excel file format for detail description
+static inline void decodeRK( unsigned rkvalue, bool& isInteger,
+ int& intResult, double& floatResult )
+{
+ bool div100 = rkvalue & 0x01;
+ isInteger = rkvalue & 0x02;
+
+ if( isInteger )
+ {
+ // FIXME check that int is 32 bits ?
+ intResult = *((int*) &rkvalue) >> 2;
+
+ // divide by 100, fall to floating-point
+ if(div100)
+ {
+ isInteger = false;
+ floatResult = (double)intResult / 100.0;
+ }
+ }
+ else
+ {
+ // TODO ensure double takes 8 bytes
+ unsigned char* s = (unsigned char*) &rkvalue;
+ unsigned char* r = (unsigned char*) &floatResult;
+ if( isLittleEndian() )
+ {
+ r[0] = r[1] = r[2] = r[3] = 0;
+ r[4] = s[0] & 0xfc;
+ r[5] = s[1]; r[6] = s[2]; r[7] = s[3];
+ }
+ else
+ {
+ r[0] = r[1] = r[2] = r[3] = 0;
+ r[4] = s[0] & 0xfc;
+ r[5] = s[1]; r[6] = s[2]; r[7] = s[3];
+ }
+ memcpy( &floatResult, r, 8 );
+
+ if( div100 )
+ floatResult *= 0.01;
+ }
+}
+
+}
+
+namespace Swinder
+{
+std::ostream& operator<<( std::ostream& s, Swinder::UString ustring )
+{
+ char* str = ustring.ascii();
+ s << str;
+ return s;
+}
+
+}
+
+using namespace Swinder;
+
+static Value errorAsValue( int errorCode )
+{
+ Value result( Value::Error );
+
+ switch( errorCode )
+ {
+ case 0x00: result = Value::errorNULL(); break;
+ case 0x07: result = Value::errorDIV0(); break;
+ case 0x0f: result = Value::errorVALUE(); break;
+ case 0x17: result = Value::errorREF(); break;
+ case 0x1d: result = Value::errorNAME(); break;
+ case 0x24: result = Value::errorNUM(); break;
+ case 0x2A: result = Value::errorNA(); break;
+ default: break;
+ };
+
+ return result;
+}
+
+//=============================================
+// EString
+//=============================================
+
+
+class EString::Private
+{
+public:
+ bool unicode;
+ bool richText;
+ UString str;
+ unsigned size;
+};
+
+EString::EString()
+{
+ d = new EString::Private();
+ d->unicode = false;
+ d->richText = false;
+ d->str = UString::null;
+ d->size = 0;
+}
+
+EString::EString( const EString& es )
+{
+ d = new EString::Private();
+ operator=( es );
+}
+
+EString& EString::operator=( const EString& es )
+{
+ d->unicode = es.d->unicode;
+ d->richText = es.d->richText;
+ d->size = es.d->size;
+ d->str = es.d->str;
+ return *this;
+}
+
+EString::~EString()
+{
+ delete d;
+}
+
+bool EString::unicode() const
+{
+ return d->unicode;
+}
+
+void EString::setUnicode( bool u )
+{
+ d->unicode = u;
+}
+
+bool EString::richText() const
+{
+ return d->richText;
+}
+
+void EString::setRichText( bool r )
+{
+ d->richText = r;
+}
+
+UString EString::str() const
+{
+ return d->str;
+}
+
+void EString::setStr( const UString& str )
+{
+ d->str = str;
+}
+
+unsigned EString::size() const
+{
+ return d->size;
+}
+
+void EString::setSize( unsigned s )
+{
+ d->size = s;
+}
+
+// FIXME use maxsize for sanity check
+EString EString::fromUnicodeString( const void* p, bool longString, unsigned /* maxsize */ )
+{
+ const unsigned char* data = (const unsigned char*) p;
+ UString str = UString::null;
+
+ unsigned offset = longString ? 2 : 1;
+ unsigned len = longString ? readU16( data ): data[0];
+ unsigned char flag = data[ offset ];
+ offset++; // for flag (1 byte)
+
+ bool unicode = flag & 0x01;
+ bool richText = flag & 0x08;
+ unsigned formatRuns = 0;
+
+ if( richText )
+ {
+ formatRuns = readU16( data + offset );
+ offset += 2;
+ }
+
+ // find out total bytes used in this string
+ unsigned size = offset + len; // string data
+ if( unicode ) size += len; // because unicode takes 2-bytes char
+ if( richText ) size += (formatRuns*4);
+
+ if( !unicode )
+ {
+ char* buffer = new char[ len+1 ];
+ memcpy( buffer, data + offset, len );
+ buffer[ len ] = 0;
+ str = UString( buffer );
+ delete[] buffer;
+ }
+ else
+ {
+ str = UString();
+ str.reserve(len);
+ for( unsigned k=0; k<len; k++ )
+ str.append( readU16( data + offset + k*2 ) );
+ }
+
+ EString result;
+ result.setUnicode( unicode );
+ result.setRichText( richText );
+ result.setSize( size );
+ result.setStr( str );
+
+ return result;
+}
+
+// FIXME use maxsize for sanity check
+EString EString::fromByteString( const void* p, bool longString,
+ unsigned /* maxsize */ )
+{
+ const unsigned char* data = (const unsigned char*) p;
+ UString str = UString::null;
+
+ unsigned offset = longString ? 2 : 1;
+ unsigned len = longString ? readU16( data ): data[0];
+
+ char* buffer = new char[ len+1 ];
+ memcpy( buffer, data + offset, len );
+ buffer[ len ] = 0;
+ str = UString( buffer );
+ delete[] buffer;
+
+ unsigned size = offset + len;
+
+ EString result;
+ result.setUnicode( false );
+ result.setRichText( false );
+ result.setSize( size );
+ result.setStr( str );
+
+ return result;
+}
+
+
+
+// why different ? see BoundSheetRecord
+EString EString::fromSheetName( const void* p, unsigned datasize )
+{
+ const unsigned char* data = (const unsigned char*) p;
+ UString str = UString::null;
+
+ bool richText = false;
+ // unsigned formatRuns = 0;
+
+ unsigned len = data[0];
+ unsigned flag = data[1];
+ bool unicode = flag & 1;
+
+ if( len > datasize-2 ) len = datasize-2;
+ if( len == 0 ) return EString();
+
+ unsigned offset = 2;
+
+ if( !unicode )
+ {
+ char* buffer = new char[ len+1 ];
+ memcpy( buffer, data + offset, len );
+ buffer[ len ] = 0;
+ str = UString( buffer );
+ delete[] buffer;
+ }
+ else
+ {
+ for( unsigned k=0; k<len; k++ )
+ {
+ unsigned uch = readU16( data + offset + k*2 );
+ str.append( UChar(uch) );
+ }
+ }
+
+ EString result;
+ result.setUnicode( unicode );
+ result.setRichText( richText );
+ result.setSize( datasize );
+ result.setStr( str );
+
+ return result;
+}
+
+//=============================================
+// FormulaToken
+//=============================================
+
+class FormulaToken::Private
+{
+public:
+ unsigned ver;
+ unsigned id;
+ std::vector<unsigned char> data;
+};
+
+FormulaToken::FormulaToken()
+{
+ d = new Private;
+ d->ver = Excel97;
+ d->id = Unused;
+}
+
+FormulaToken::FormulaToken( unsigned t )
+{
+ d = new Private;
+ d->ver = Excel97;
+ d->id = t;
+}
+
+FormulaToken::FormulaToken( const FormulaToken& token )
+{
+ d = new Private;
+ d->ver = token.d->ver;
+ d->id = token.id();
+
+ d->data.resize( token.d->data.size() );
+ for( unsigned i = 0; i < d->data.size(); i++ )
+ d->data[i] = token.d->data[i];
+}
+
+FormulaToken::~FormulaToken()
+{
+ delete d;
+}
+
+unsigned FormulaToken::version() const
+{
+ return d->ver;
+}
+
+void FormulaToken::setVersion( unsigned v )
+{
+ d->ver = v;
+}
+
+unsigned FormulaToken::id() const
+{
+ return d->id;
+}
+
+const char* FormulaToken::idAsString() const
+{
+ const char* s = 0;
+
+ switch( d->id )
+ {
+ case Matrix: s = "Matrix"; break;
+ case Table: s = "Table"; break;
+ case Add: s = "Add"; break;
+ case Sub: s = "Sub"; break;
+ case Mul: s = "Mul"; break;
+ case Div: s = "Div"; break;
+ case Power: s = "Power"; break;
+ case Concat: s = "Concat"; break;
+ case LT: s = "LT"; break;
+ case LE: s = "LE"; break;
+ case EQ: s = "EQ"; break;
+ case GE: s = "GE"; break;
+ case GT: s = "GT"; break;
+ case NE: s = "NE"; break;
+ case Intersect: s = "Intersect"; break;
+ case List: s = "List"; break;
+ case Range: s = "Range"; break;
+ case UPlus: s = "UPlus"; break;
+ case UMinus: s = "UMinus"; break;
+ case Percent: s = "Percent"; break;
+ case Paren: s = "Paren"; break;
+ case String: s = "String"; break;
+ case MissArg: s = "MissArg"; break;
+ case ErrorCode: s = "ErrorCode"; break;
+ case Bool: s = "Bool"; break;
+ case Integer: s = "Integer"; break;
+ case Array: s = "Array"; break;
+ case Function: s = "Function"; break;
+ case FunctionVar: s = "FunctionVar"; break;
+ case Name: s = "Name"; break;
+ case Ref: s = "Ref"; break;
+ case RefErr: s = "RefErr"; break;
+ case RefN: s = "RefN"; break;
+ case Area: s = "Area"; break;
+ case AreaErr: s = "AreaErr"; break;
+ case AreaN: s = "AreaN"; break;
+ case NameX: s = "NameX"; break;
+ case Ref3d: s = "Ref3d"; break;
+ case RefErr3d: s = "RefErr3d"; break;
+ case Float: s = "Float"; break;
+ case Area3d: s = "Area3d"; break;
+ case AreaErr3d: s = "AreaErr3d"; break;
+ default: s = "Unknown"; break;
+ };
+
+ return s;
+}
+
+
+unsigned FormulaToken::size() const
+{
+ unsigned s = 0; // on most cases no data
+
+ switch( d->id )
+ {
+ case Add:
+ case Sub:
+ case Mul:
+ case Div:
+ case Power:
+ case Concat:
+ case LT:
+ case LE:
+ case EQ:
+ case GE:
+ case GT:
+ case NE:
+ case Intersect:
+ case List:
+ case Range:
+ case UPlus:
+ case UMinus:
+ case Percent:
+ case Paren:
+ case MissArg:
+ s = 0; break;
+
+ case Attr:
+ s = 3; break;
+
+ case ErrorCode:
+ case Bool:
+ s = 1; break;
+
+ case Integer:
+ s = 2; break;
+
+ case Array:
+ s = 7; break;
+
+ case Function:
+ s = 2;
+ break;
+
+ case FunctionVar:
+ s = 3;
+ break;
+
+ case Matrix:
+ case Table:
+ s = (d->ver == Excel97) ? 4 : 3;
+ break;
+
+ case Name:
+ s = (d->ver == Excel97) ? 4 : 14;
+ break;
+
+ case Ref:
+ case RefErr:
+ case RefN:
+ s = (d->ver == Excel97) ? 4 : 3;
+ break;
+
+ case Area:
+ case AreaErr:
+ case AreaN:
+ s = (d->ver == Excel97) ? 8 : 6;
+ break;
+
+ case NameX:
+ s = (d->ver == Excel97) ? 6 : 24;
+ break;
+
+ case Ref3d:
+ case RefErr3d:
+ s = (d->ver == Excel97) ? 6 : 17;
+ break;
+
+ case Float:
+ s = 8; break;
+
+ case Area3d:
+ case AreaErr3d:
+ s = (d->ver == Excel97) ? 10 : 20;
+ break;
+
+ default:
+ // WARNING this is unhandled case
+ break;
+ };
+
+ return s;
+}
+
+void FormulaToken::setData( unsigned size, const unsigned char* data )
+{
+ d->data.resize( size );
+ for( unsigned i = 0; i < size; i++ )
+ d->data[i] = data[i];
+}
+
+Value FormulaToken::value() const
+{
+ // sentinel
+ if(d->data.size() == 0)
+ return Value::empty();
+
+ Value result;
+
+ unsigned char* buf;
+ buf = new unsigned char[d->data.size()];
+ for( unsigned k=0; k<d->data.size(); k++ )
+ buf[k] = d->data[k];
+
+ // FIXME sanity check: verify size of data
+ switch( d->id )
+ {
+ case ErrorCode:
+ result = errorAsValue( buf[0] );
+ break;
+
+ case Bool:
+ result = Value( buf[0]!=0 );
+ break;
+
+ case Integer:
+ result = Value( (int)readU16( buf ) );
+ break;
+
+ case Float:
+ result = Value( readFloat64( buf ) );
+ break;
+
+ case String:
+ {
+ EString estr = (version()==Excel97) ?
+ EString::fromUnicodeString( buf, false, d->data.size() ) :
+ EString::fromByteString( buf, false, d->data.size() );
+ result = Value( estr.str() );
+ }
+ break;
+
+ default: break;
+ }
+
+ delete [] buf;
+
+ return result;
+}
+
+unsigned FormulaToken::functionIndex() const
+{
+ // FIXME check data size
+ unsigned index = 0;
+ unsigned char buf[2];
+
+ if( d->id == Function )
+ {
+ buf[0] = d->data[0];
+ buf[1] = d->data[1];
+ index = readU16( buf );
+ }
+
+ if( d->id == FunctionVar )
+ {
+ buf[0] = d->data[1];
+ buf[1] = d->data[2];
+ index = readU16( buf );
+ }
+
+ return index;
+}
+
+struct FunctionEntry
+{
+ const char *name;
+ int params;
+};
+
+static const FunctionEntry FunctionEntries[] =
+{
+ { "COUNT", 1 }, // 0
+ { "IF", 0 }, // 1
+ { "ISNV", 1 }, // 2
+ { "ISERROR", 1 }, // 3
+ { "SUM", 0 }, // 4
+ { "AVERAGE", 0 }, // 5
+ { "MIN", 0 }, // 6
+ { "MAX", 0 }, // 7
+ { "ROW", 0 }, // 8
+ { "COLUMN", 0 }, // 9
+ { "NOVALUE", 0 }, // 10
+ { "NPV", 0 }, // 11
+ { "STDEV", 0 }, // 12
+ { "DOLLAR", 0 }, // 13
+ { "FIXED", 0 }, // 14
+ { "SIN", 1 }, // 15
+ { "COS", 1 }, // 16
+ { "TAN", 1 }, // 17
+ { "ATAN", 1 }, // 18
+ { "PI", 0 }, // 19
+ { "SQRT", 1 }, // 20
+ { "EXP", 1 }, // 21
+ { "LN", 1 }, // 22
+ { "LOG10", 1 }, // 23
+ { "ABS", 1 }, // 24
+ { "INT", 1 }, // 25
+ { "SIGN", 1 }, // 26
+ { "ROUND", 2 }, // 27
+ { "LOOKUP", 0 }, // 28
+ { "INDEX", 0 }, // 29
+ { "REPT", 2 }, // 30
+ { "MID", 3 }, // 31
+ { "LEN", 1 }, // 32
+ { "VALUE", 1 }, // 33
+ { "TRUE", 0 }, // 34
+ { "FALSE", 0 }, // 35
+ { "AND", 0 }, // 36
+ { "OR", 0 }, // 37
+ { "NOT", 1 }, // 38
+ { "MOD", 2 }, // 39
+ { "DCOUNT", 3 }, // 40
+ { "DSUM", 3 }, // 41
+ { "DAVERAGE", 3 }, // 42
+ { "DMIN", 3 }, // 43
+ { "DMAX", 3 }, // 44
+ { "DSTDEV", 3 }, // 45
+ { "VAR", 0 }, // 46
+ { "DVAR", 3 }, // 47
+ { "TEXT", 2 }, // 48
+ { "LINEST", 0 }, // 49
+ { "TREND", 0 }, // 50
+ { "LOGEST", 0 }, // 51
+ { "GROWTH", 0 }, // 52
+ { "GOTO", 0 }, // 53
+ { "HALT", 0 }, // 54
+ { "Unknown55", 0 }, // 55
+ { "PV", 0 }, // 56
+ { "FV", 0 }, // 57
+ { "NPER", 0 }, // 58
+ { "PMT", 0 }, // 59
+ { "RATE", 0 }, // 60
+ { "MIRR", 3 }, // 61
+ { "IRR", 0 }, // 62
+ { "RAND", 0 }, // 63
+ { "MATCH", 0 }, // 64
+ { "DATE", 3 }, // 65
+ { "TIME", 3 }, // 66
+ { "DAY", 1 }, // 67
+ { "MONTH", 1 }, // 68
+ { "YEAR", 1 }, // 69
+ { "DAYOFWEEK", 0 }, // 70
+ { "HOUR", 1 }, // 71
+ { "MIN", 1 }, // 72
+ { "SEC", 1 }, // 73
+ { "NOW", 0 }, // 74
+ { "AREAS", 1 }, // 75
+ { "ROWS", 1 }, // 76
+ { "COLUMNS", 1 }, // 77
+ { "OFFSET", 0 }, // 78
+ { "ABSREF", 2 }, // 79
+ { "RELREF", 0 }, // 80
+ { "ARGUMENT", 0 }, // 81
+ { "SEARCH", 0 }, // 82
+ { "TRANSPOSE", 1 }, // 83
+ { "ERROR", 0 }, // 84
+ { "STEP", 0 }, // 85
+ { "TYPE", 1 }, // 86
+ { "ECHO", 0 },
+ { "SETNAME", 0 },
+ { "CALLER", 0 },
+ { "DEREF", 0 },
+ { "WINDOWS", 0 },
+ { "SERIES", 4 },
+ { "DOCUMENTS", 0 },
+ { "ACTIVECELL", 0 },
+ { "SELECTION", 0 },
+ { "RESULT", 0 },
+ { "ATAN2", 2 }, // 97
+ { "ASIN", 1 }, // 98
+ { "ACOS", 1 }, // 99
+ { "CHOOSE", 0 }, // 100
+ { "HLOOKUP", 0 }, // 101
+ { "VLOOKUP", 0 }, // 102
+ { "LINKS", 0 },
+ { "INPUT", 0 },
+ { "ISREF", 1 }, // 105
+ { "GETFORMULA", 0 },
+ { "GETNAME", 0 },
+ { "SETVALUE", 0 },
+ { "LOG", 0 }, // 109
+ { "EXEC", 0 },
+ { "CHAR", 1 }, // 111
+ { "LOWER", 1 }, // 112
+ { "UPPER", 1 }, // 113
+ { "PROPER", 1 }, // 114
+ { "LEFT", 0 }, // 115
+ { "RIGHT", 0 }, // 116
+ { "EXACT", 2 }, // 117
+ { "TRIM", 1 }, // 118
+ { "REPLACE", 4 }, // 119
+ { "SUBSTITUTE", 0 }, // 120
+ { "CODE", 1 }, // 121
+ { "NAMES", 0 },
+ { "DIRECTORY", 0 },
+ { "FIND", 0 }, // 124
+ { "CELL", 0 }, // 125
+ { "ISERR", 1 }, // 126
+ { "ISTEXT", 1 }, // 127
+ { "ISNUMBER", 1 }, // 128
+ { "ISBLANK", 1 }, // 129
+ { "T", 1 }, // 130
+ { "N", 1 }, // 131
+ { "FOPEN", 0 },
+ { "FCLOSE", 0 },
+ { "FSIZE", 0 },
+ { "FREADLN", 0 },
+ { "FREAD", 0 },
+ { "FWRITELN", 0 },
+ { "FWRITE", 0 },
+ { "FPOS", 0 },
+ { "DATEVALUE", 1 }, // 140
+ { "TIMEVALUE", 1 }, // 141
+ { "SLN", 3 }, // 142
+ { "SYD", 4 }, // 143
+ { "DDB", 0 }, // 144
+ { "GETDEF", 0 },
+ { "REFTEXT", 0 },
+ { "TEXTREF", 0 },
+ { "INDIRECT", 0 }, // 148
+ { "REGISTER", 0 },
+ { "CALL", 0 },
+ { "ADDBAR", 0 },
+ { "ADDMENU", 0 },
+ { "ADDCOMMAND", 0 },
+ { "ENABLECOMMAND", 0 },
+ { "CHECKCOMMAND", 0 },
+ { "RENAMECOMMAND", 0 },
+ { "SHOWBAR", 0 },
+ { "DELETEMENU", 0 },
+ { "DELETECOMMAND", 0 },
+ { "GETCHARTITEM", 0 },
+ { "DIALOGBOX", 0 },
+ { "CLEAN", 1 }, // 162
+ { "MDETERM", 1 }, // 163
+ { "MINVERSE", 1 }, // 164
+ { "MMULT", 2 }, // 165
+ { "FILES", 0 },
+ { "IPMT", 0 }, // 167
+ { "PPMT", 0 }, // 168
+ { "COUNTA", 0 }, // 169
+ { "CANCELKEY", 1 },
+ { "Unknown171", 0 },
+ { "Unknown172", 0 },
+ { "Unknown173", 0 },
+ { "Unknown174", 0 },
+ { "INITIATE", 0 },
+ { "REQUEST", 0 },
+ { "POKE", 0 },
+ { "EXECUTE", 0 },
+ { "TERMINATE", 0 },
+ { "RESTART", 0 },
+ { "HELP", 0 },
+ { "GETBAR", 0 },
+ { "PRODUCT", 0 }, // 183
+ { "FACT", 1 }, // 184
+ { "GETCELL", 0 },
+ { "GETWORKSPACE", 0 },
+ { "GETWINDOW", 0 },
+ { "GETDOCUMENT", 0 },
+ { "DPRODUCT", 3 }, // 189
+ { "ISNONTEXT", 1 }, // 190
+ { "GETNOTE", 0 },
+ { "NOTE", 0 },
+ { "STDEVP", 0 }, // 193
+ { "VARP", 0 }, // 194
+ { "DSTDEVP", 3 }, // 195
+ { "DVARP", 3 }, // 196
+ { "TRUNC", 0 }, // 197
+ { "ISLOGICAL", 1 }, // 198
+ { "DCOUNTA", 3 }, // 199
+ { "DELETEBAR", 0 },
+ { "UNREGISTER", 0 },
+ { "Unknown202", 0 },
+ { "Unknown203", 0 },
+ { "USDOLLAR", 0 },
+ { "FINDB", 0 },
+ { "SEARCHB", 0 },
+ { "REPLACEB", 0 },
+ { "LEFTB", 0 },
+ { "RIGHTB", 0 },
+ { "MIDB", 0 },
+ { "LENB", 0 },
+ { "ROUNDUP", 2 }, // 212
+ { "ROUNDDOWN", 2 }, // 213
+ { "ASC", 0 },
+ { "DBCS", 0 },
+ { "RANK", 0 }, // 216
+ { "Unknown217", 0 },
+ { "Unknown218", 0 },
+ { "ADDRESS", 0 }, // 219
+ { "GETDIFFDATE360", 0 }, // 220
+ { "CURRENTDATE", 0 }, // 221
+ { "VBD", 0 }, // 222
+ { "Unknown223", 0 },
+ { "Unknown224", 0 },
+ { "Unknown225", 0 },
+ { "Unknown226", 0 },
+ { "MEDIAN", 0 }, // 227
+ { "SUMPRODUCT", 0 }, // 228
+ { "SINH", 1 }, // 229
+ { "COSH", 1 }, // 230
+ { "TANH", 1 }, // 231
+ { "ASINH", 1 }, // 232
+ { "ACOSH", 1 }, // 233
+ { "ATANH", 1 }, // 234
+ { "DGET", 3 }, // 235
+ { "CREATEOBJECT", 0 },
+ { "VOLATILE", 0 },
+ { "LASTERROR", 0 },
+ { "CUSTOMUNDO", 0 },
+ { "CUSTOMREPEAT", 0 },
+ { "FORMULACONVERT", 0 },
+ { "GETLINKINFO", 0 },
+ { "TEXTBOX", 0 },
+ { "INFO", 1 }, // 244
+ { "GROUP", 0 },
+ { "GETOBJECT", 0 },
+ { "DB", 0 }, // 247
+ { "PAUSE", 0 },
+ { "Unknown249", 0 },
+ { "Unknown250", 0 },
+ { "RESUME", 0 },
+ { "FREQUENCY", 2 }, // 252
+ { "ADDTOOLBAR", 0 },
+ { "DELETETOOLBAR", 0 },
+ { "Unknown255", 0 },
+ { "RESETTOOLBAR", 0 },
+ { "EVALUATE", 0 },
+ { "GETTOOLBAR", 0 },
+ { "GETTOOL", 0 },
+ { "SPELLINGCHECK", 0 },
+ { "ERRORTYPE", 1 }, // 261
+ { "APPTITLE", 0 },
+ { "WINDOWTITLE", 0 },
+ { "SAVETOOLBAR", 0 },
+ { "ENABLETOOL", 0 },
+ { "PRESSTOOL", 0 },
+ { "REGISTERID", 0 },
+ { "GETWORKBOOK", 0 },
+ { "AVEDEV", 0 }, // 269
+ { "BETADIST", 0 }, // 270
+ { "GAMMALN", 1 }, // 271
+ { "BETAINV", 0 }, // 272
+ { "BINOMDIST", 4 }, // 273
+ { "CHIDIST", 2 }, // 274
+ { "CHIINV", 2 }, // 275
+ { "COMBIN", 2 }, // 276
+ { "CONFIDENCE", 3 }, // 277
+ { "CRITBINOM", 3 }, // 278
+ { "EVEN", 1 }, // 279
+ { "EXPONDIST", 3 }, // 280
+ { "FDIST", 3 }, // 281
+ { "FINV", 3 }, // 282
+ { "FISHER", 1 }, // 283
+ { "FISHERINV", 1 }, // 284
+ { "FLOOR", 2 }, // 285
+ { "GAMMADIST", 4 }, // 286
+ { "GAMMAINV", 3 }, // 287
+ { "CEIL", 2 }, // 288
+ { "HYPGEOMDIST", 4 }, // 289
+ { "LOGNORMDIST", 3 }, // 290
+ { "LOGINV", 3 }, // 291
+ { "NEGBINOMDIST", 3 }, // 292
+ { "NORMDIST", 4 }, // 293
+ { "NORMSDIST", 1 }, // 294
+ { "NORMINV", 3 }, // 295
+ { "NORMSINV", 1 }, // 296
+ { "STANDARDIZE", 3 }, // 297
+ { "ODD", 1 }, // 298
+ { "PERMUT", 2 }, // 299
+ { "POISSON", 3 }, // 300
+ { "TDIST", 3 }, // 301
+ { "WEIBULL", 4 }, // 302
+ { "SUMXMY2", 2 }, // 303
+ { "SUMX2MY2", 2 }, // 304
+ { "SUMX2DY2", 2 }, // 305
+ { "CHITEST", 2 }, // 306
+ { "CORREL", 2 }, // 307
+ { "COVAR", 2 }, // 308
+ { "FORECAST", 3 }, // 309
+ { "FTEST", 2 }, // 310
+ { "INTERCEPT", 2 }, // 311
+ { "PEARSON", 2 }, // 312
+ { "RSQ", 2 }, // 313
+ { "STEYX", 2 }, // 314
+ { "SLOPE", 2 }, // 315
+ { "TTEST", 4 }, // 316
+ { "PROB", 0 }, // 317
+ { "DEVSQ", 0 }, // 318
+ { "GEOMEAN", 0 }, // 319
+ { "HARMEAN", 0 }, // 320
+ { "SUMSQ", 0 }, // 321
+ { "KURT", 0 }, // 322
+ { "SKEW", 0 }, // 323
+ { "ZTEST", 0 }, // 324
+ { "LARGE", 2 }, // 325
+ { "SMALL", 2 }, // 326
+ { "QUARTILE", 2 }, // 327
+ { "PERCENTILE", 2 }, // 328
+ { "PERCENTRANK", 0 }, // 329
+ { "MODALVALUE", 0 }, // 330
+ { "TRIMMEAN", 2 }, // 331
+ { "TINV", 2 }, // 332
+ { "Unknown333", 0 },
+ { "MOVIECOMMAND", 0 },
+ { "GETMOVIE", 0 },
+ { "CONCATENATE", 0 }, // 336
+ { "POWER", 2 }, // 337
+ { "PIVOTADDDATA", 0 },
+ { "GETPIVOTTABLE", 0 },
+ { "GETPIVOTFIELD", 0 },
+ { "GETPIVOTITEM", 0 },
+ { "RADIANS", 1 }, // 342
+ { "DEGREES", 1 }, // 343
+ { "SUBTOTAL", 0 }, // 344
+ { "SUMIF", 0 }, // 345
+ { "COUNTIF", 2 }, // 346
+ { "COUNTBLANK", 1 }, // 347
+ { "SCENARIOGET", 0 },
+ { "OPTIONSLISTSGET", 0 },
+ { "ISPMT", 4 },
+ { "DATEDIF", 3 },
+ { "DATESTRING", 0 },
+ { "NUMBERSTRING", 0 },
+ { "ROMAN", 0 }, // 354
+ { "OPENDIALOG", 0 },
+ { "SAVEDIALOG", 0 },
+ { "VIEWGET", 0 },
+ { "GETPIVOTDATA", 2 }, // 358
+ { "HYPERLINK", 1 },
+ { "PHONETIC", 0 },
+ { "AVERAGEA", 0 }, // 361
+ { "MAXA", 0 }, // 362
+ { "MINA", 0 }, // 363
+ { "STDEVPA", 0 }, // 364
+ { "VARPA", 0 }, // 365
+ { "STDEVA", 0 }, // 366
+ { "VARA", 0 }, // 367
+};
+
+const char* FormulaToken::functionName() const
+{
+ if( functionIndex() > 367 ) return 0;
+ return FunctionEntries[ functionIndex() ].name;
+}
+
+unsigned FormulaToken::functionParams() const
+{
+ unsigned params = 0;
+
+ if( d->id == Function )
+ {
+ if( functionIndex() > 367 ) return 0;
+ params = FunctionEntries[ functionIndex() ].params;
+ }
+
+ if( d->id == FunctionVar )
+ {
+ params = (unsigned)d->data[0];
+ params &= 0x7f;
+ }
+
+ return params;
+}
+
+unsigned FormulaToken::attr() const
+{
+ unsigned attr = 0;
+ if( d->id == Attr )
+ {
+ attr = (unsigned) d->data[0];
+ }
+ return attr;
+}
+
+unsigned FormulaToken::nameIndex() const
+{
+ // FIXME check data size !
+ unsigned ni = 0;
+ unsigned char buf[2];
+
+ if( d->id == NameX )
+ if( d->ver == Excel97 )
+ {
+ buf[0] = d->data[2];
+ buf[1] = d->data[3];
+ ni = readU16( buf );
+ }
+
+ if( d->id == NameX )
+ if( d->ver == Excel95 )
+ {
+ buf[0] = d->data[10];
+ buf[1] = d->data[11];
+ ni = readU16( buf );
+ }
+
+ return ni;
+}
+
+
+UString FormulaToken::area( unsigned row, unsigned col ) const
+{
+ // sanity check
+ if(id() != Area)
+ if(id() != Area3d)
+ return UString::null;
+
+ // check data size
+ int minsize = 0;
+ if((id() == Area3d))
+ minsize = (version() == Excel97) ? 10 : 20;
+ else if(id() == Area)
+ minsize = (version() == Excel97) ? 8 : 6;
+ if(d->data.size() < minsize)
+ return UString::null;
+
+ unsigned char buf[2];
+ int row1Ref, row2Ref, col1Ref, col2Ref;
+ bool row1Relative, col1Relative;
+ bool row2Relative, col2Relative;
+
+ if( version() == Excel97 )
+ {
+ int ofs = (id() == Area) ? 0 : 2;
+
+ buf[0] = d->data[ofs];
+ buf[1] = d->data[ofs+1];
+ row1Ref = readU16( buf );
+
+ buf[0] = d->data[ofs+2];
+ buf[1] = d->data[ofs+3];
+ row2Ref = readU16( buf );
+
+ buf[0] = d->data[ofs+4];
+ buf[1] = d->data[ofs+5];
+ col1Ref = readU16( buf );
+
+ buf[0] = d->data[ofs+6];
+ buf[1] = d->data[ofs+7];
+ col2Ref = readU16( buf );
+
+ row1Relative = col1Ref & 0x8000;
+ col1Relative = col1Ref & 0x4000;
+ col1Ref &= 0x3fff;
+
+ row2Relative = col2Ref & 0x8000;
+ col2Relative = col2Ref & 0x4000;
+ col2Ref &= 0x3fff;
+ }
+ else
+ {
+ int ofs = (id() == Area) ? 0 : 14;
+
+ buf[0] = d->data[ofs];
+ buf[1] = d->data[ofs+1];
+ row1Ref = readU16( buf );
+
+ buf[0] = d->data[ofs+2];
+ buf[1] = d->data[ofs+3];
+ row2Ref = readU16( buf );
+
+ buf[0] = d->data[ofs+4];
+ buf[1] = 0;
+ col1Ref = readU16( buf );
+
+ buf[0] = d->data[ofs+5];
+ buf[1] = 0;
+ col2Ref = readU16( buf );
+
+ row1Relative = row2Ref & 0x8000;
+ col1Relative = row2Ref & 0x4000;
+ row1Ref &= 0x3fff;
+
+ row2Relative = row2Ref & 0x8000;
+ col2Relative = row2Ref & 0x4000;
+ row2Ref &= 0x3fff;
+ }
+
+ UString result;
+
+ // not critical, just to improve performace
+ // see also ref() function below
+ result.reserve(40);
+
+ // normal use
+ if( !col1Relative )
+ result.append( '$' );
+ result.append( Cell::columnLabel( col1Ref ) );
+ if( !row1Relative )
+ result.append( '$' );
+ result.append( UString::number( row1Ref+1 ) );
+ result.append( ':' );
+ if( !col2Relative )
+ result.append( '$' );
+ result.append( Cell::columnLabel( col2Ref ) );
+ if( !row2Relative )
+ result.append( '$' );
+ result.append( UString::number( row2Ref+1 ) );
+
+ return result;
+}
+
+UString FormulaToken::ref( unsigned row, unsigned col ) const
+{
+ // sanity check
+ if(id() != Ref)
+ if(id() != Ref3d)
+ return UString::null;
+
+ // FIXME check data size !
+ // FIXME handle shared formula
+ unsigned char buf[2];
+ int rowRef, colRef;
+ bool rowRelative, colRelative;
+
+ if( version() == Excel97 )
+ {
+ int ofs = (id() == Ref) ? 0 : 2;
+ buf[0] = d->data[ofs];
+ buf[1] = d->data[ofs+1];
+ rowRef = readU16( buf );
+
+ buf[0] = d->data[ofs+2];
+ buf[1] = d->data[ofs+3];
+ colRef = readU16( buf );
+
+ rowRelative = colRef & 0x8000;
+ colRelative = colRef & 0x4000;
+ colRef &= 0x3fff;
+ }
+ else
+ {
+ int ofs = (id() == Ref) ? 0 : 14;
+ buf[0] = d->data[ofs];
+ buf[1] = d->data[ofs+1];
+ rowRef = readU16( buf );
+
+ buf[0] = d->data[ofs+2];
+ buf[1] = 0;
+ colRef = readU16( buf );
+
+ rowRelative = rowRef & 0x8000;
+ colRelative = rowRef & 0x4000;
+ rowRef &= 0x3fff;
+ }
+
+ UString result;
+
+ // not critical, just to improve performace
+ // absolute column 4294967295, row 4294967295 is "$AATYHWUR$4294967295"
+ // (20 characters)
+ result.reserve(20);
+
+ if( !colRelative )
+ result.append('$');
+ result.append( Cell::columnLabel( colRef ) );
+ if( !rowRelative )
+ result.append('$');
+ result.append( UString::number( rowRef+1 ) );
+
+ return result;
+}
+
+// only when id is Ref3d or Area3d
+unsigned FormulaToken::externSheetRef() const
+{
+ if(version() >= Excel97)
+ {
+ unsigned char buf[2];
+ buf[0] = d->data[0];
+ buf[1] = d->data[1];
+ return readU16(buf);
+ }
+ else
+ {
+ unsigned char buf[2];
+ buf[0] = d->data[0];
+ buf[1] = d->data[1];
+ int index = readI16(buf);
+
+ // negative index means own workbook
+ if(index < 0)
+ {
+ // the real index (absolute value) is one-based
+ unsigned ref = -index - 1;
+ return ref;
+ }
+ }
+
+ return 0; // FIXME is this safe?
+}
+
+// only when id is Matrix
+unsigned FormulaToken::refRow() const
+{
+ // FIXME check data size !
+ unsigned char buf[2];
+
+ buf[0] = d->data[0];
+ buf[1] = d->data[1];
+ unsigned ref = readU16(buf);
+
+ return ref;
+}
+
+// only when id is Matrix
+unsigned FormulaToken::refColumn() const
+{
+ // FIXME check data size !
+ unsigned char buf[2];
+
+ buf[0] = d->data[2];
+ buf[1] = d->data[3];
+ unsigned ref = readU16(buf);
+
+ return ref;
+}
+
+
+std::ostream& Swinder::operator<<( std::ostream& s, Swinder::FormulaToken token )
+{
+ s << std::setw(2) << std::hex << token.id() << std::dec;
+ // s << " Size: " << std::dec << token.size();
+ s << " ";
+
+ switch( token.id() )
+ {
+ case FormulaToken::ErrorCode:
+ case FormulaToken::Bool:
+ case FormulaToken::Integer:
+ case FormulaToken::Float:
+ case FormulaToken::String:
+ {
+ Value v = token.value();
+ s << v;
+ }
+ break;
+
+ case FormulaToken::Function:
+ s << "Function " << token.functionName();
+ break;
+
+ default:
+ s << token.idAsString();
+ break;
+ }
+
+ return s;
+}
+
+//=============================================
+// CellInfo
+//=============================================
+
+class CellInfo::Private
+{
+public:
+ unsigned row;
+ unsigned column;
+ unsigned xfIndex;
+};
+
+CellInfo::CellInfo()
+{
+ info = new CellInfo::Private();
+ info->row = 0;
+ info->column = 0;
+ info->xfIndex = 0;
+}
+
+CellInfo::~CellInfo()
+{
+ delete info;
+}
+
+unsigned CellInfo::row() const
+{
+ return info->row;
+}
+
+void CellInfo::setRow( unsigned r )
+{
+ info->row = r;
+}
+
+unsigned CellInfo::column() const
+{
+ return info->column;
+}
+
+void CellInfo::setColumn( unsigned c )
+{
+ info->column = c;
+}
+
+unsigned CellInfo::xfIndex() const
+{
+ return info->xfIndex;
+}
+
+void CellInfo::setXfIndex( unsigned i )
+{
+ info->xfIndex = i;
+}
+
+//=============================================
+// ColumnSpanInfo
+//=============================================
+
+class ColumnSpanInfo::Private
+{
+public:
+ unsigned firstColumn;
+ unsigned lastColumn;
+};
+
+ColumnSpanInfo::ColumnSpanInfo()
+{
+ spaninfo = new ColumnSpanInfo::Private();
+ spaninfo->firstColumn = 0;
+ spaninfo->lastColumn = 0;
+}
+
+ColumnSpanInfo::~ColumnSpanInfo()
+{
+ delete spaninfo;
+}
+
+unsigned ColumnSpanInfo::firstColumn() const
+{
+ return spaninfo->firstColumn;
+}
+
+void ColumnSpanInfo::setFirstColumn( unsigned c )
+{
+ spaninfo->firstColumn = c;
+}
+
+unsigned ColumnSpanInfo::lastColumn() const
+{
+ return spaninfo->lastColumn;
+}
+
+void ColumnSpanInfo::setLastColumn( unsigned c )
+{
+ spaninfo->lastColumn = c;
+}
+
+// ========== base record ==========
+
+const unsigned int Record::id = 0; // invalid of-course
+
+Record::Record()
+{
+ stream_position = 0;
+ ver = Excel97;
+}
+
+Record::~Record()
+{
+}
+
+Record* Record::create( unsigned type )
+{
+ Record* record = 0;
+
+ if( type == BOFRecord::id )
+ record = new BOFRecord();
+
+ else if( type == EOFRecord::id )
+ record = new EOFRecord();
+
+ if( type == BackupRecord::id )
+ record = new BackupRecord();
+
+ if( type == BlankRecord::id )
+ record = new BlankRecord();
+
+ if( type == BoolErrRecord::id )
+ record = new BoolErrRecord();
+
+ if( type == BottomMarginRecord::id )
+ record = new BottomMarginRecord();
+
+ if( type == BoundSheetRecord::id )
+ record = new BoundSheetRecord();
+
+ if( type == CalcModeRecord::id )
+ record = new CalcModeRecord();
+
+ if( type == ColInfoRecord::id )
+ record = new ColInfoRecord();
+
+ if( type == DateModeRecord::id )
+ record = new DateModeRecord();
+
+ if( type == DimensionRecord::id )
+ record = new DimensionRecord();
+
+ if( type == ExternNameRecord::id )
+ record = new ExternNameRecord();
+
+ if( type == ExternSheetRecord::id )
+ record = new ExternSheetRecord();
+
+ else if( type == FilepassRecord::id )
+ record = new FilepassRecord();
+
+ else if( type == FontRecord::id )
+ record = new FontRecord();
+
+ else if( type == FooterRecord::id )
+ record = new FooterRecord();
+
+ else if( type == FormatRecord::id )
+ record = new FormatRecord();
+
+ else if( type == FormulaRecord::id )
+ record = new FormulaRecord();
+
+ else if( type == FormulaRecord::idOld )
+ record = new FormulaRecord();
+
+ else if( type == HeaderRecord::id )
+ record = new HeaderRecord();
+
+ else if( type == LabelRecord::id )
+ record = new LabelRecord();
+
+ else if( type == LabelSSTRecord::id )
+ record = new LabelSSTRecord();
+
+ if( type == LeftMarginRecord::id )
+ record = new LeftMarginRecord();
+
+ else if( type == MergedCellsRecord::id )
+ record = new MergedCellsRecord();
+
+ else if( type == MulBlankRecord::id )
+ record = new MulBlankRecord();
+
+ else if( type == MulRKRecord::id )
+ record = new MulRKRecord();
+
+ if( type == NameRecord::id )
+ record = new NameRecord();
+
+ else if( type == NumberRecord::id )
+ record = new NumberRecord();
+
+ else if( type == PaletteRecord::id )
+ record = new PaletteRecord();
+
+ if( type == RightMarginRecord::id )
+ record = new RightMarginRecord();
+
+ else if( type == RKRecord::id )
+ record = new RKRecord();
+
+ else if( type == RowRecord::id )
+ record = new RowRecord();
+
+ else if( type == RStringRecord::id )
+ record = new RStringRecord();
+
+ else if( type == SSTRecord::id )
+ record = new SSTRecord();
+
+ else if( type == StringRecord::id )
+ record = new StringRecord();
+
+ else if( type == SupbookRecord::id )
+ record = new SupbookRecord();
+
+ else if( type == XFRecord::id )
+ record = new XFRecord();
+
+ else if( type == TopMarginRecord::id )
+ record = new TopMarginRecord();
+
+ return record;
+}
+
+void Record::setPosition( unsigned pos )
+{
+ stream_position = pos;
+}
+
+unsigned Record::position() const
+{
+ return stream_position;
+}
+
+void Record::setData( unsigned, const unsigned char* )
+{
+}
+
+void Record::dump( std::ostream& ) const
+{
+ // nothing to dump
+}
+
+// ========== BACKUP ==========
+
+const unsigned int BackupRecord::id = 0x0040;
+
+class BackupRecord::Private
+{
+public:
+ bool backup;
+};
+
+BackupRecord::BackupRecord():
+ Record()
+{
+ d = new BackupRecord::Private();
+ d->backup = false;
+}
+
+BackupRecord::~BackupRecord()
+{
+ delete d;
+}
+
+bool BackupRecord::backup() const
+{
+ return d->backup;
+}
+
+void BackupRecord::setBackup( bool b )
+{
+ d->backup = b;
+}
+
+void BackupRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 2 ) return;
+
+ unsigned flag = readU16( data );
+ d->backup = flag != 0;
+}
+
+void BackupRecord::dump( std::ostream& out ) const
+{
+ out << "BACKUP" << std::endl;
+ out << " Backup on save : " << (backup() ? "Yes" : "No") << std::endl;
+}
+
+// ========== BLANK ==========
+
+const unsigned int BlankRecord::id = 0x0201;
+
+BlankRecord::BlankRecord():
+ Record(), CellInfo()
+{
+}
+
+void BlankRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 6 ) return;
+
+ setRow( readU16( data ) );
+ setColumn( readU16( data+2 ) );
+ setXfIndex( readU16( data+4 ) );
+}
+
+void BlankRecord::dump( std::ostream& out ) const
+{
+ out << "BLANK" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " Column : " << column() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+}
+
+
+// ========== BOF ==========
+
+const unsigned int BOFRecord::id = 0x0809;
+
+// helper class for BOFRecord
+class BOFRecord::Private
+{
+public:
+ unsigned version; // 0x0500=Excel95, 0x0600=Excel97, and so on
+ unsigned type;
+ unsigned build;
+ unsigned year;
+ unsigned history;
+ unsigned rversion;
+};
+
+// constructor of BOFRecord
+BOFRecord::BOFRecord():
+ Record()
+{
+ d = new BOFRecord::Private();
+ d->version = 0x600; // BIFF8;
+ d->type = 0;
+ d->build = 0;
+ d->year = 0;
+ d->history = 0;
+ d->rversion = 0;
+}
+
+// destructor of BOFRecord
+BOFRecord::~BOFRecord()
+{
+ delete d;
+}
+
+void BOFRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 4 ) return;
+
+ d->version = readU16( data );
+ d->type = readU16( data+2 );
+ if( size > 6 )
+ {
+ d->build = readU16( data+4 );
+ d->year = readU16( data+6);
+ if( size > 12 )
+ {
+ d->history = readU32( data+8 );
+ d->rversion = readU32( data+12 );
+ }
+ }
+}
+
+unsigned BOFRecord::version() const
+{
+ unsigned ver = UnknownExcel;
+ switch( d->version )
+ {
+ case 0x0500 : ver = Excel95; break;
+ case 0x0600 : ver = Excel97; break;
+ default: break;
+ }
+ return ver;
+}
+
+const char* BOFRecord::versionAsString() const
+{
+ const char *result = "Unknown";
+ switch( version() )
+ {
+ case Excel95 : result = "Excel95"; break;
+ case Excel97 : result = "Excel97"; break;
+ default: break;
+ }
+ return result;
+}
+
+unsigned BOFRecord::type() const
+{
+ unsigned result = UnknownType;
+ switch( d->type )
+ {
+ case 0x005 : result = Workbook; break;
+ case 0x006 : result = VBModule; break;
+ case 0x010 : result = Worksheet; break;
+ case 0x020 : result = Chart; break;
+ case 0x040 : result = MacroSheet; break;
+ case 0x100 : result = Workspace; break;
+ default: break;
+ }
+ return result;
+}
+
+const char* BOFRecord::typeAsString() const
+{
+ const char *result = "Unknown";
+ switch( type() )
+ {
+ case Workbook : result = "Workbook"; break;
+ case VBModule : result = "Visual Basic Module"; break;
+ case Worksheet : result = "Worksheet"; break;
+ case Chart : result = "Chart"; break;
+ case MacroSheet : result = "Macro Sheet"; break;
+ case Workspace : result = "Workspace File"; break;
+ default: break;
+ }
+ return result;
+}
+
+void BOFRecord::dump( std::ostream& out ) const
+{
+ out << "BOF" << std::endl;
+ out << " Version : 0x" << std::hex << d->version << " (" << versionAsString() << ")" << std::endl;
+ out << " Type : 0x" << d->type << " (" << typeAsString() << ")" << std::endl;
+ out << " Build : 0x" << d->build << std::endl;
+ out << " Year : " << std::dec << d->year << std::endl;
+ out << " History : 0x" << std::hex << d->history << std::endl;
+ out << " RVersion : 0x" << d->rversion << std::endl;
+ out << std::dec;
+}
+
+// ========== BOOLERR ==========
+
+const unsigned int BoolErrRecord::id = 0x0205;
+
+class BoolErrRecord::Private
+{
+public:
+ Value value;
+};
+
+BoolErrRecord::BoolErrRecord():
+ Record(), CellInfo()
+{
+ d = new BoolErrRecord::Private();
+ d->value = Value( false );
+}
+
+BoolErrRecord::~BoolErrRecord()
+{
+ delete d;
+}
+
+void BoolErrRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size != 8 ) return;
+
+ setRow( readU16( data ) );
+ setColumn( readU16( data+2 ) );
+ setXfIndex( readU16( data+4 ) );
+
+ switch( data[7] )
+ {
+ case 0 :
+ d->value = Value( data[6] ? true : false );
+ break;
+ case 1 :
+ d->value = errorAsValue( data[6] );
+ break;
+ default:
+ // bad bad bad
+ std::cerr << "Warning: bad BOOLERR record" << std::endl;
+ break;
+ }
+}
+
+Value BoolErrRecord::value() const
+{
+ return d->value;
+}
+
+void BoolErrRecord::dump( std::ostream& out ) const
+{
+ out << "BOOLERR" << std::endl;
+ out << " Column : " << column() << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " XFIndex : " << xfIndex() << std::endl;
+ out << " Value : " << value() << std::endl;
+}
+
+// ========== BOTTOMMARGIN ==========
+
+const unsigned int BottomMarginRecord::id = 0x0029;
+
+class BottomMarginRecord::Private
+{
+public:
+ double bottomMargin;
+};
+
+BottomMarginRecord::BottomMarginRecord():
+ Record()
+{
+ d = new BottomMarginRecord::Private();
+ d->bottomMargin = 1.0;
+}
+
+BottomMarginRecord::~BottomMarginRecord()
+{
+ delete d;
+}
+
+double BottomMarginRecord::bottomMargin() const
+{
+ return d->bottomMargin;
+}
+
+void BottomMarginRecord::setBottomMargin( double m )
+{
+ d->bottomMargin = m;
+}
+
+void BottomMarginRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 8 ) return;
+ setBottomMargin( readFloat64( data ) );
+}
+
+void BottomMarginRecord::dump( std::ostream& out ) const
+{
+ out << "BOTTOMMARGIN" << std::endl;
+ out << " Bottom Margin : " << bottomMargin() << " inches" << std::endl;
+}
+
+
+// ========== BOUNDSHEET ==========
+
+const unsigned int BoundSheetRecord::id = 0x0085;
+
+// helper class for BoundSheetRecord
+class BoundSheetRecord::Private
+{
+public:
+ unsigned type; // 0=Worksheet, 2=Chart, 6=VB Module
+ unsigned visibility; // 0=visible, 1=hidden, 2=strong hidden
+ UString name;
+ unsigned bofPosition;
+};
+
+BoundSheetRecord::BoundSheetRecord():
+ Record()
+{
+ d = new BoundSheetRecord::Private();
+ d->type = 0;
+ d->visibility = 0;
+ d->name = "Sheet";
+}
+
+void BoundSheetRecord::setType( unsigned t )
+{
+ switch( t )
+ {
+ case Worksheet: d->type = 0; break;
+ case Chart: d->type = 2; break;
+ case VBModule: d->type = 6; break;
+ default: d->type = 0; break; // fallback
+ };
+}
+
+unsigned BoundSheetRecord::type() const
+{
+ unsigned t = Worksheet;
+ switch( d->type )
+ {
+ case 0: t = Worksheet; break;
+ case 2: t = Chart; break;
+ case 6: t = VBModule; break;
+ default: break;
+ };
+ return t;
+}
+
+const char* BoundSheetRecord::typeAsString() const
+{
+ const char *result = "Unknown";
+ switch( type() )
+ {
+ case Worksheet: result = "Worksheet"; break;
+ case Chart: result = "Chart"; break;
+ case VBModule: result = "Visual Basic Module"; break;
+ default: break;
+ }
+ return result;
+}
+
+void BoundSheetRecord::setVisible( bool v )
+{
+ d->visibility = v ? 0 : 1;
+}
+
+bool BoundSheetRecord::visible() const
+{
+ return d->visibility == 0;
+}
+
+void BoundSheetRecord::setSheetName( const UString& n )
+{
+ d->name = n;
+}
+
+UString BoundSheetRecord::sheetName() const
+{
+ return d->name;
+}
+
+void BoundSheetRecord::setBofPosition( unsigned pos )
+{
+ d->bofPosition = pos;
+}
+
+unsigned BoundSheetRecord::bofPosition() const
+{
+ return d->bofPosition;
+}
+
+BoundSheetRecord::~BoundSheetRecord()
+{
+ delete d;
+}
+
+void BoundSheetRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 6 ) return;
+
+ d->bofPosition = readU32( data );
+ d->visibility = data[4];
+ d->type = data[5];
+
+ /* FIXME: it turned out that sheet name is not normal unicode string
+ where the first two bytes specifies string length, but instead
+ only the first specifies it.
+ the next byte could be correctly interpreted as flag.
+ */
+
+ UString name = ( version() >= Excel97 ) ?
+ EString::fromSheetName( data+6, size-6 ).str() :
+ EString::fromByteString( data+6, false, size-6 ).str();
+ setSheetName( name );
+}
+
+void BoundSheetRecord::dump( std::ostream& out ) const
+{
+ out << "BOUNDSHEET" << std::endl;
+ out << " Name : " << d->name << std::endl;
+ out << " Type : " << d->type << " (" << typeAsString() << ")" << std::endl;
+ out << " Visibility : " << d->visibility << " (";
+ if( visible() ) out << "Visible"; else out << "Hidden"; out << ")" << std::endl;
+ out << " BOF pos : " << d->bofPosition << std::endl;
+}
+
+// ========== CALCMODE ==========
+
+const unsigned int CalcModeRecord::id = 0x000d;
+
+class CalcModeRecord::Private
+{
+public:
+ bool autoCalc;
+};
+
+CalcModeRecord::CalcModeRecord():
+ Record()
+{
+ d = new CalcModeRecord::Private();
+ d->autoCalc = false;
+}
+
+CalcModeRecord::~CalcModeRecord()
+{
+ delete d;
+}
+
+bool CalcModeRecord::autoCalc() const
+{
+ return d->autoCalc;
+}
+
+void CalcModeRecord::setAutoCalc( bool b )
+{
+ d->autoCalc = b;
+}
+
+void CalcModeRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 2 ) return;
+
+ unsigned flag = readU16( data );
+ d->autoCalc = flag != 0;
+}
+
+void CalcModeRecord::dump( std::ostream& out ) const
+{
+ out << "CALCMODE" << std::endl;
+ out << " Auto Calc : " << (autoCalc() ? "Yes" : "No") << std::endl;
+}
+
+// ========== COLINFO ==========
+
+const unsigned int ColInfoRecord::id = 0x007d;
+
+class ColInfoRecord::Private
+{
+public:
+ unsigned width;
+ unsigned xfIndex;
+ bool hidden;
+ bool collapsed;
+ unsigned outlineLevel;
+};
+
+ColInfoRecord::ColInfoRecord():
+ Record(), ColumnSpanInfo()
+{
+ d = new ColInfoRecord::Private();
+ d->width = 2340;
+ d->xfIndex = 0;
+ d->hidden = false;
+ d->collapsed = false;
+ d->outlineLevel = 0;
+}
+
+ColInfoRecord::~ColInfoRecord()
+{
+ delete d;
+}
+
+// FIXME how to find the real width (in pt/mm/inch) ?
+unsigned ColInfoRecord::width() const
+{
+ return d->width;
+}
+
+void ColInfoRecord::setWidth( unsigned w )
+{
+ d->width = w;
+}
+
+unsigned ColInfoRecord::xfIndex() const
+{
+ return d->xfIndex;
+}
+
+void ColInfoRecord::setXfIndex( unsigned i )
+{
+ d->xfIndex = i;
+}
+
+bool ColInfoRecord::hidden() const
+{
+ return d->hidden;
+}
+
+void ColInfoRecord::setHidden( bool h )
+{
+ d->hidden = h;
+}
+
+bool ColInfoRecord::collapsed() const
+{
+ return d->collapsed;
+}
+
+void ColInfoRecord::setCollapsed( bool c )
+{
+ d->collapsed = c;
+}
+
+unsigned ColInfoRecord::outlineLevel() const
+{
+ return d->outlineLevel;
+}
+
+void ColInfoRecord::setOutlineLevel( unsigned l )
+{
+ d->outlineLevel = l;
+}
+
+void ColInfoRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 10 ) return;
+
+ setFirstColumn( readU16( data ) );
+ setLastColumn( readU16( data+2 ) );
+ setWidth( readU16( data+4 ) );
+ setXfIndex( readU16( data+6 ) );
+
+ unsigned options = readU16( data+8 );
+ setHidden ( options & 1 );
+ setCollapsed ( options & 0x1000 );
+ setOutlineLevel( ( options >> 8 ) & 7 );
+}
+
+void ColInfoRecord::dump( std::ostream& out ) const
+{
+ out << "COLINFO" << std::endl;
+ out << " First Column : " << firstColumn() << std::endl;
+ out << " Last Column : " << lastColumn() << std::endl;
+ out << " Width : " << width() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+ out << " Hidden : " << ( hidden() ? "Yes" : "No" ) << std::endl;
+ out << " Collapsed : " << ( collapsed() ? "Yes" : "No" ) << std::endl;
+ out << " Outline Level : " << outlineLevel() << std::endl;
+}
+
+// ========== DATEMODE ==========
+
+const unsigned int DateModeRecord::id = 0x0022;
+
+class DateModeRecord::Private
+{
+public:
+ bool base1904;
+};
+
+DateModeRecord::DateModeRecord():
+ Record()
+{
+ d = new DateModeRecord::Private();
+ d->base1904 = false;
+}
+
+DateModeRecord::~DateModeRecord()
+{
+ delete d;
+}
+
+bool DateModeRecord::base1904() const
+{
+ return d->base1904;
+}
+
+void DateModeRecord::setBase1904( bool r )
+{
+ d->base1904 = r;
+}
+
+void DateModeRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 2 ) return;
+
+ unsigned flag = readU16( data );
+ d->base1904 = flag != 0;
+}
+
+void DateModeRecord::dump( std::ostream& out ) const
+{
+ out << "DATEMODE" << std::endl;
+ out << " 1904 base : " << (base1904() ? "Yes" : "No") << std::endl;
+}
+
+
+// ========== DIMENSION ==========
+
+const unsigned int DimensionRecord::id = 0x0200;
+
+class DimensionRecord::Private
+{
+public:
+ unsigned firstRow;
+ unsigned lastRow;
+ unsigned firstColumn;
+ unsigned lastColumn;
+};
+
+DimensionRecord::DimensionRecord():
+ Record()
+{
+ d = new DimensionRecord::Private;
+ d->firstRow = 0;
+ d->lastRow = 0;
+ d->firstColumn = 0;
+ d->lastColumn = 0;
+}
+
+DimensionRecord::~DimensionRecord()
+{
+ delete d;
+}
+
+unsigned DimensionRecord::firstRow() const
+{
+ return d->firstRow;
+}
+
+void DimensionRecord::setFirstRow( unsigned r )
+{
+ d->firstRow = r;
+}
+
+unsigned DimensionRecord::lastRow() const
+{
+ return d->lastRow;
+}
+
+void DimensionRecord::setLastRow( unsigned r )
+{
+ d->lastRow = r;
+}
+
+unsigned DimensionRecord::firstColumn() const
+{
+ return d->firstColumn;
+}
+
+void DimensionRecord::setFirstColumn( unsigned r )
+{
+ d->firstColumn = r;
+}
+
+unsigned DimensionRecord::lastColumn() const
+{
+ return d->lastColumn;
+}
+
+void DimensionRecord::setLastColumn( unsigned r )
+{
+ d->lastColumn = r;
+}
+
+void DimensionRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 14 ) return;
+
+ setFirstRow( readU32( data ) );
+ setLastRow( readU32( data+4 ) - 1 );
+ setFirstColumn( readU16( data + 8 ) );
+ setLastColumn( readU16( data + 10 ) - 1 );
+}
+
+void DimensionRecord::dump( std::ostream& out ) const
+{
+ out << "DIMENSION" << std::endl;
+ out << " First Row : " << firstRow() << std::endl;
+ out << " Last Row : " << lastRow() << std::endl;
+ out << " First Column : " << firstColumn() << std::endl;
+ out << " Last Column : " << lastColumn() << std::endl;
+}
+
+// ========== EOF ==========
+
+const unsigned int EOFRecord::id = 0x000a;
+
+EOFRecord::EOFRecord():
+ Record()
+{
+}
+
+EOFRecord::~EOFRecord()
+{
+}
+
+void EOFRecord::setData( unsigned, const unsigned char* )
+{
+ // no data associated with EOF record
+}
+
+void EOFRecord::dump( std::ostream& out ) const
+{
+ out << "EOF" << std::endl;
+}
+
+// ========== EXTERNNAME ==========
+
+const unsigned int ExternNameRecord::id = 0x0023;
+
+class ExternNameRecord::Private
+{
+public:
+ unsigned optionFlags;
+ unsigned sheetIndex; // one-based, not zero-based
+ UString externName;
+};
+
+
+ExternNameRecord::ExternNameRecord()
+{
+ d = new Private;
+ d->optionFlags = 0;
+ d->sheetIndex = 0;
+}
+
+ExternNameRecord::~ExternNameRecord()
+{
+ delete d;
+}
+
+void ExternNameRecord::setSheetIndex( unsigned sheetIndex )
+{
+ d->sheetIndex = sheetIndex;
+}
+
+unsigned ExternNameRecord::sheetIndex() const
+{
+ return d->sheetIndex;
+}
+
+void ExternNameRecord::setExternName( const UString& name )
+{
+ d->externName = name;
+}
+
+UString ExternNameRecord::externName() const
+{
+ return d->externName;
+}
+
+void ExternNameRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 6 ) return;
+
+ if ( version() == Excel97 )
+ {
+ d->optionFlags = readU16( data );
+ d->sheetIndex = readU16( data+2 );
+ d->externName = EString::fromUnicodeString( data+6, false, size ).str();
+ }
+
+ if ( version() == Excel95 )
+ {
+ d->optionFlags = 0;
+ d->sheetIndex = 0;
+ d->externName = EString::fromByteString( data+6, false, size ).str();
+ }
+}
+
+void ExternNameRecord::dump( std::ostream& out ) const
+{
+}
+
+// ========== EXTERNSHEET ==========
+
+const unsigned int ExternSheetRecord::id = 0x0017;
+
+class ExternSheetRecord::Private
+{
+public:
+ typedef struct
+ {
+ unsigned index;
+ unsigned first;
+ unsigned last ;
+ } ExternSheetRef;
+ std::vector<ExternSheetRef> refs;
+ UString refName;
+};
+
+ExternSheetRecord::ExternSheetRecord()
+{
+ d = new Private;
+}
+
+ExternSheetRecord::~ExternSheetRecord()
+{
+ delete d;
+}
+
+unsigned ExternSheetRecord::count() const
+{
+ return d->refs.size();
+}
+
+unsigned ExternSheetRecord::refIndex(unsigned i) const
+{
+ if(i >= d->refs.size()) return 0;
+ return d->refs[i].index;
+}
+
+unsigned ExternSheetRecord::firstSheet(unsigned i) const
+{
+ if(i >= d->refs.size()) return 0;
+ return d->refs[i].first;
+}
+
+unsigned ExternSheetRecord::lastSheet(unsigned i) const
+{
+ if(i >= d->refs.size()) return 0;
+ return d->refs[i].last;
+}
+
+UString ExternSheetRecord::refName() const
+{
+ return d->refName;
+}
+
+void ExternSheetRecord::setData( unsigned size, const unsigned char* data )
+{
+ d->refs.clear();
+ d->refName = UString::null;
+
+ // sanity
+ if(size < 2) return;
+
+ if(version() >= Excel97)
+ {
+ // don't really trust this
+ unsigned c = readU16(data);
+
+ unsigned ofs = 2;
+ for(unsigned i = 0; i < c; i++, ofs+=6)
+ {
+ // sanity check
+ if(ofs + 6 > size) break;
+
+ ExternSheetRecord::Private::ExternSheetRef ref;
+ ref.index = readU16(data+ofs);
+ ref.first = readU16(data+ofs+2);
+ ref.last = readU16(data+ofs+4);
+
+ d->refs.push_back(ref);
+ }
+ }
+ else
+ {
+ unsigned char dtype = data[1];
+ unsigned dlen = (unsigned) data[0];
+
+ if(dtype == 3)
+ {
+ UString url;
+ url.reserve(dlen);
+ for(int i = 0; i < dlen; i++)
+ {
+ if(i + 2 > size) break;
+ char ch = data[i + 2];
+ if(ch >= 32)
+ url.append(ch);
+ }
+ d->refName = url;
+ }
+ }
+}
+
+void ExternSheetRecord::dump( std::ostream& out ) const
+{
+ out << "EXTERNSHEET" << std::endl;
+}
+
+// ========== FILEPASS ==========
+
+const unsigned int FilepassRecord::id = 0x002f;
+
+FilepassRecord::FilepassRecord():
+ Record()
+{
+}
+
+FilepassRecord::~FilepassRecord()
+{
+}
+
+void FilepassRecord::setData( unsigned, const unsigned char* )
+{
+ // TODO
+}
+
+void FilepassRecord::dump( std::ostream& out ) const
+{
+ out << "FILEPASS" << std::endl;
+}
+
+// ========== FONT ==========
+
+const unsigned int FontRecord::id = 0x0031;
+
+class FontRecord::Private
+{
+public:
+ unsigned height;
+ UString fontName;
+ unsigned fontFamily;
+ unsigned characterSet;
+ unsigned colorIndex;
+ unsigned boldness;
+ bool italic;
+ bool strikeout;
+ unsigned escapement;
+ unsigned underline;
+};
+
+FontRecord::FontRecord(): Record()
+{
+ d = new FontRecord::Private;
+ d->height = 11;
+ d->fontName = "Arial";
+ d->fontFamily = 0;
+ d->characterSet = 0;
+ d->colorIndex = 0;
+ d->boldness = 400;
+ d->italic = false;
+ d->strikeout = false;
+ d->escapement = Normal;
+ d->underline = None;
+}
+
+FontRecord::~FontRecord()
+{
+ delete d;
+}
+
+FontRecord::FontRecord( const FontRecord& ef ): Record()
+{
+ d = new FontRecord::Private;
+ operator=( ef );
+}
+
+FontRecord& FontRecord::operator=( const FontRecord& ef )
+{
+ d->height = ef.height();
+ d->fontName = ef.fontName();
+ d->fontFamily = ef.fontFamily();
+ d->characterSet = ef.characterSet();
+ d->boldness = ef.boldness();
+ d->italic = ef.italic();
+ d->strikeout = ef.strikeout();
+ d->escapement = ef.escapement();
+ d->underline = ef.underline();
+ d->colorIndex = ef.colorIndex();
+ return *this;
+}
+
+unsigned FontRecord::height() const
+{
+ return d->height;
+}
+
+void FontRecord::setHeight( unsigned h )
+{
+ d->height = h;
+}
+
+UString FontRecord::fontName() const
+{
+ return d->fontName;
+}
+
+void FontRecord::setFontName( const UString& fn )
+{
+ d->fontName = fn;
+}
+
+unsigned FontRecord::fontFamily() const
+{
+ return d->fontFamily;
+}
+
+void FontRecord::setFontFamily( unsigned f )
+{
+ d->fontFamily = f;
+}
+
+unsigned FontRecord::characterSet() const
+{
+ return d->characterSet;
+}
+
+void FontRecord::setCharacterSet( unsigned cs )
+{
+ d->characterSet = cs;
+}
+
+unsigned FontRecord::colorIndex() const
+{
+ return d->colorIndex;
+}
+
+void FontRecord::setColorIndex( unsigned ci )
+{
+ d->colorIndex = ci;
+}
+
+unsigned FontRecord::boldness() const
+{
+ return d->boldness;
+}
+
+void FontRecord::setBoldness( unsigned b )
+{
+ d->boldness = b;
+}
+
+bool FontRecord::italic() const
+{
+ return d->italic;
+}
+
+void FontRecord::setItalic( bool i )
+{
+ d->italic = i;
+}
+
+bool FontRecord::strikeout() const
+{
+ return d->strikeout;
+}
+
+void FontRecord::setStrikeout( bool s )
+{
+ d->strikeout = s;
+}
+
+unsigned FontRecord::escapement() const
+{
+ return d->escapement;
+}
+
+void FontRecord::setEscapement( unsigned s )
+{
+ d->escapement = s;
+}
+
+unsigned FontRecord::underline() const
+{
+ return d->underline;
+}
+
+void FontRecord::setUnderline( unsigned u )
+{
+ d->underline = u;
+}
+
+
+void FontRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 14 ) return;
+
+ setHeight( readU16( data ) );
+ unsigned flag = readU16( data+2 );
+ setItalic( flag & 2 );
+ setStrikeout( flag & 8 );
+ setStrikeout( flag & 8 );
+
+ setColorIndex( readU16( data+4 ) );
+
+ setBoldness( readU16( data+6 ) );
+ setEscapement( readU16( data+8 ) );
+ setUnderline( data[10] );
+
+ setFontFamily( data[11] );
+ setCharacterSet( data[12] );
+
+ UString fn = ( version() >= Excel97 ) ?
+ EString::fromSheetName( data+14, size-14 ).str() :
+ EString::fromByteString( data+14, false, size-14 ).str();
+ setFontName( fn );
+}
+
+
+void FontRecord::dump( std::ostream& out ) const
+{
+ out << "FONT" << std::endl;
+ out << " Height : " << height() << " twips" << std::endl;
+ out << " Font Name : " << fontName() << std::endl;
+ out << " Color Index : " << colorIndex() << std::endl;
+ out << " Boldness : " << boldness() << std::endl;
+ out << " Italic : " << (italic()?"Yes":"No") << std::endl;
+ out << " Strikeout : " << (strikeout()?"Yes":"No") << std::endl;
+ out << " Escapement : ";
+ switch( escapement() )
+ {
+ case Normal: out << "Normal" << std::endl; break;
+ case Subscript: out << "Subscript" << std::endl; break;
+ case Superscript: out << "Superscript" << std::endl; break;
+ default: out << "Unkown " << escapement() << std::endl; break;
+ };
+}
+
+// ========== FOOTER ==========
+
+const unsigned int FooterRecord::id = 0x0015;
+
+class FooterRecord::Private
+{
+public:
+ UString footer;
+};
+
+FooterRecord::FooterRecord():
+ Record()
+{
+ d = new FooterRecord::Private();
+}
+
+FooterRecord::~FooterRecord()
+{
+ delete d;
+}
+
+UString FooterRecord::footer() const
+{
+ return d->footer;
+}
+
+void FooterRecord::setFooter( const UString& footer )
+{
+ d->footer = footer;
+}
+
+void FooterRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 2 ) return;
+
+ UString footer = ( version() >= Excel97 ) ?
+ EString::fromUnicodeString( data, true, size ).str() :
+ EString::fromByteString( data, false, size ).str();
+ setFooter( footer );
+}
+
+void FooterRecord::dump( std::ostream& out ) const
+{
+ out << "FOOTER" << std::endl;
+ out << " Footer : " << footer() << std::endl;
+}
+
+// ========== FORMAT ==========
+
+const unsigned int FormatRecord::id = 0x041e;
+
+class FormatRecord::Private
+{
+public:
+ unsigned index;
+ UString formatString;
+};
+
+FormatRecord::FormatRecord():
+ Record()
+{
+ d = new FormatRecord::Private;
+ d->index = 0;
+}
+
+FormatRecord::~FormatRecord()
+{
+ delete d;
+}
+
+FormatRecord::FormatRecord( const FormatRecord& fr ):
+ Record()
+{
+ d = new FormatRecord::Private;
+ operator=( fr );
+}
+
+FormatRecord& FormatRecord::operator=( const FormatRecord& fr )
+{
+ d->index = fr.index();
+ d->formatString = fr.formatString();
+ return *this;
+}
+
+unsigned FormatRecord::index() const
+{
+ return d->index;
+}
+
+void FormatRecord::setIndex( unsigned i )
+{
+ d->index = i;
+}
+
+UString FormatRecord::formatString() const
+{
+ return d->formatString;
+}
+
+void FormatRecord::setFormatString( const UString& fs )
+{
+ d->formatString = fs;
+}
+
+void FormatRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 3 ) return;
+
+ setIndex( readU16( data ) );
+
+ UString fs = ( version() >= Excel97 ) ?
+ EString::fromUnicodeString( data+2, true, size-2 ).str() :
+ EString::fromByteString( data+2, false, size-2 ).str();
+ setFormatString( fs );
+}
+
+void FormatRecord::dump( std::ostream& out ) const
+{
+ out << "FORMAT" << std::endl;
+ out << " Index : " << index() << std::endl;
+ out << " Format String : " << formatString() << std::endl;
+}
+
+
+// ========== FORMULA ==========
+
+const unsigned int FormulaRecord::id = 0x0006;
+const unsigned int FormulaRecord::idOld = 0x0206; // BIFF3, BIFF4
+
+class FormulaRecord::Private
+{
+public:
+ Value result;
+ FormulaTokens tokens;
+};
+
+FormulaRecord::FormulaRecord():
+ Record()
+{
+ d = new FormulaRecord::Private();
+}
+
+FormulaRecord::~FormulaRecord()
+{
+ delete d;
+}
+
+Value FormulaRecord::result() const
+{
+ return d->result;
+}
+
+void FormulaRecord::setResult( const Value& r )
+{
+ d->result = r;
+}
+
+FormulaTokens FormulaRecord::tokens() const
+{
+ return d->tokens;
+}
+
+void FormulaRecord::setData( unsigned size, const unsigned char* data )
+{
+ int formula_ofs = 20;
+
+ // sanity check
+ if( size < formula_ofs ) return;
+
+ setRow( readU16( data ) );
+ setColumn( readU16( data+2 ) );
+
+ setXfIndex( readU16( data+4 ) );
+ if( readU16( data+12 ) != 0xffff )
+ {
+ // Floating-point
+ setResult( Value( readFloat64( data+6 ) ) );
+ }
+ else
+ {
+ switch( data[6] )
+ {
+ case 0: // string, real value in subsequent string record
+ setResult( Value( Value::String ) );
+ break;
+ case 1: // boolean
+ setResult( Value( data[8] ? true : false ) );
+ break;
+ case 2: // error code
+ setResult( errorAsValue( data[8] ) );
+ break;
+ case 3: // empty
+ setResult( Value::empty() );
+ break;
+ default: // fallback
+ setResult( Value::empty() );
+ break;
+ };
+ }
+
+ unsigned formula_len = readU16( data+formula_ofs );
+
+ // reconstruct all tokens
+ d->tokens.clear();
+ for( unsigned j = formula_ofs+2; j < size; )
+ {
+ unsigned ptg = data[j++];
+ ptg = ((ptg & 0x40) ? (ptg | 0x20) : ptg) & 0x3F;
+ FormulaToken token( ptg );
+ token.setVersion( version() );
+
+ if( token.id() == FormulaToken::String )
+ {
+ // find bytes taken to represent the string
+ EString estr = (version()==Excel97) ?
+ EString::fromUnicodeString( data+j, false, formula_len ) :
+ EString::fromByteString( data+j, false, formula_len );
+ token.setData( estr.size(), data+j );
+ j += estr.size();
+ }
+ else
+ {
+ // normal, fixed-size token
+ if( token.size() > 1 )
+ {
+ token.setData( token.size(), data+j );
+ j += token.size();
+ }
+ }
+
+ d->tokens.push_back( token );
+ }
+}
+
+void FormulaRecord::dump( std::ostream& out ) const
+{
+ out << "FORMULA" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " Column : " << column() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+ out << " Result : " << result() << std::endl;
+
+ FormulaTokens ts = tokens();
+ out << " Tokens : " << ts.size() << std::endl;
+ for( unsigned i = 0; i < ts.size(); i++ )
+ out << " " << ts[i] << std::endl;
+
+}
+
+// ========== LABEL ==========
+
+const unsigned int LabelRecord::id = 0x0204;
+
+class LabelRecord::Private
+{
+public:
+ UString label;
+};
+
+LabelRecord::LabelRecord():
+ Record(), CellInfo()
+{
+ d = new LabelRecord::Private();
+ d->label = UString::null;
+}
+
+LabelRecord::~LabelRecord()
+{
+ delete d;
+}
+
+UString LabelRecord::label() const
+{
+ return d->label;
+}
+
+void LabelRecord::setLabel( const UString& l )
+{
+ d->label = l;
+}
+
+void LabelRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 6 ) return;
+
+ setRow( readU16( data ) );
+ setColumn( readU16( data+2 ) );
+ setXfIndex( readU16( data+4 ) );
+
+ UString label = ( version() >= Excel97 ) ?
+ EString::fromUnicodeString( data+6, true, size-6 ).str() :
+ EString::fromByteString( data+6, true, size-6 ).str();
+ setLabel( label );
+}
+
+void LabelRecord::dump( std::ostream& out ) const
+{
+ out << "LABEL" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " Column : " << column() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+ out << " Label : " << label() << std::endl;
+}
+
+// ========== HEADER ==========
+
+const unsigned int HeaderRecord::id = 0x0014;
+
+class HeaderRecord::Private
+{
+public:
+ UString header;
+};
+
+HeaderRecord::HeaderRecord():
+ Record()
+{
+ d = new HeaderRecord::Private();
+}
+
+HeaderRecord::~HeaderRecord()
+{
+ delete d;
+}
+
+UString HeaderRecord::header() const
+{
+ return d->header;
+}
+
+void HeaderRecord::setHeader( const UString& header )
+{
+ d->header = header;
+}
+
+void HeaderRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 2 ) return;
+
+ UString header = ( version() >= Excel97 ) ?
+ EString::fromUnicodeString( data, true, size ).str() :
+ EString::fromByteString( data, false, size ).str();
+ setHeader( header );
+}
+
+void HeaderRecord::dump( std::ostream& out ) const
+{
+ out << "HEADER" << std::endl;
+ out << " Header: " << header() << std::endl;
+}
+
+// ========== LABELSST ==========
+
+const unsigned int LabelSSTRecord::id = 0x00fd;
+
+class LabelSSTRecord::Private
+{
+public:
+ unsigned sstIndex;
+};
+
+LabelSSTRecord::LabelSSTRecord():
+ Record(), CellInfo()
+{
+ d = new LabelSSTRecord::Private();
+ d->sstIndex = 0;
+}
+
+LabelSSTRecord::~LabelSSTRecord()
+{
+ delete d;
+}
+
+unsigned LabelSSTRecord::sstIndex() const
+{
+ return d->sstIndex;
+}
+
+void LabelSSTRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 10 ) return;
+
+ setRow( readU16( data ) );
+ setColumn( readU16( data+2 ) );
+ setXfIndex( readU16( data+4 ) );
+
+ d->sstIndex = readU32( data+6 );
+}
+
+void LabelSSTRecord::dump( std::ostream& out ) const
+{
+ out << "LABELSST" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " Column : " << column() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+ out << " SST Index : " << d->sstIndex << std::endl;
+}
+
+// ========== LEFTMARGIN ==========
+
+const unsigned int LeftMarginRecord::id = 0x0026;
+
+class LeftMarginRecord::Private
+{
+public:
+ double leftMargin;
+};
+
+LeftMarginRecord::LeftMarginRecord():
+ Record()
+{
+ d = new LeftMarginRecord::Private();
+ d->leftMargin = 1.0;
+}
+
+LeftMarginRecord::~LeftMarginRecord()
+{
+ delete d;
+}
+
+double LeftMarginRecord::leftMargin() const
+{
+ return d->leftMargin;
+}
+
+void LeftMarginRecord::setLeftMargin( double m )
+{
+ d->leftMargin = m;
+}
+
+void LeftMarginRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 8 ) return;
+ setLeftMargin( readFloat64( data ) );
+}
+
+void LeftMarginRecord::dump( std::ostream& out ) const
+{
+ out << "LEFTMARGIN" << std::endl;
+ out << " Left Margin : " << leftMargin() << " inches" << std::endl;
+}
+
+// ========== MERGEDCELLS ==========
+
+const unsigned int MergedCellsRecord::id = 0x00e5;
+
+class MergedInfo
+{
+public:
+ unsigned firstRow, lastRow, firstColumn, lastColumn;
+};
+
+class MergedCellsRecord::Private
+{
+public:
+ std::vector<MergedInfo> mergedCells;
+};
+
+MergedCellsRecord::MergedCellsRecord():
+ Record()
+{
+ d = new MergedCellsRecord::Private();
+}
+
+MergedCellsRecord::~MergedCellsRecord()
+{
+ delete d;
+}
+
+unsigned MergedCellsRecord::count() const
+{
+ return d->mergedCells.size();
+}
+
+unsigned MergedCellsRecord::firstRow( unsigned i ) const
+{
+ if( i >= d->mergedCells.size() ) return 0;
+ MergedInfo info = d->mergedCells[ i ];
+ return info.firstRow;
+}
+
+unsigned MergedCellsRecord::lastRow( unsigned i ) const
+{
+ if( i >= d->mergedCells.size() ) return 0;
+ MergedInfo info = d->mergedCells[ i ];
+ return info.lastRow;
+}
+
+unsigned MergedCellsRecord::firstColumn( unsigned i ) const
+{
+ if( i >= d->mergedCells.size() ) return 0;
+ MergedInfo info = d->mergedCells[ i ];
+ return info.firstColumn;
+}
+
+unsigned MergedCellsRecord::lastColumn( unsigned i ) const
+{
+ if( i >= d->mergedCells.size() ) return 0;
+ MergedInfo info = d->mergedCells[ i ];
+ return info.lastColumn;
+}
+
+void MergedCellsRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 2 ) return;
+
+ unsigned num = readU16( data );
+
+ // sanity check
+ if( size < 2 + num*4 ) return;
+
+ unsigned p = 2;
+ for( unsigned i = 0; i < num; i++ )
+ {
+ MergedInfo info;
+ info.firstRow = readU16( data + p );
+ info.lastRow = readU16( data + p + 2 );
+ info.firstColumn = readU16( data + p + 4 );
+ info.lastColumn = readU16( data + p + 6 );
+ p += 8;
+ d->mergedCells.push_back( info );
+ }
+}
+
+void MergedCellsRecord::dump( std::ostream& out ) const
+{
+ out << "MERGEDCELLS" << std::endl;
+ out << " Count : " << count() << std::endl;
+ for( unsigned c = 0; c < count(); c++ )
+ {
+ out << " Merged Cell #" << c << " : ";
+ out << "Column " << firstColumn(c) << "-" << lastColumn(c);
+ out << " Row " << firstRow(c) << "-" << lastRow(c);
+ out << std::endl;
+ }
+}
+
+// ========== MULBLANK ==========
+
+const unsigned int MulBlankRecord::id = 0x00be;
+
+class MulBlankRecord::Private
+{
+public:
+ std::vector<unsigned> xfIndexes;
+};
+
+MulBlankRecord::MulBlankRecord():
+ Record(), CellInfo(), ColumnSpanInfo()
+{
+ d = new MulBlankRecord::Private();
+}
+
+MulBlankRecord::~MulBlankRecord()
+{
+ delete d;
+}
+
+void MulBlankRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 6 ) return;
+
+ setRow( readU16( data ) );
+
+ setFirstColumn( readU16( data+2 ) );
+ setLastColumn( readU16( data+size-2 ) );
+
+ d->xfIndexes.clear();
+ for( unsigned i = 4; i < size-2; i+= 2 )
+ d->xfIndexes.push_back( readU16( data+i ) );
+
+ // FIXME sentinel !
+}
+
+unsigned MulBlankRecord::xfIndex( unsigned i ) const
+{
+ if( i >= d->xfIndexes.size() ) return 0;
+ return d->xfIndexes[ i ];
+}
+
+void MulBlankRecord::dump( std::ostream& out ) const
+{
+ out << "MULBLANK" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " First Column : " << firstColumn() << std::endl;
+ out << " Last Column : " << lastColumn() << std::endl;
+}
+
+// ========== MULRK ==========
+
+const unsigned int MulRKRecord::id = 0x00bd;
+
+class MulRKRecord::Private
+{
+public:
+ std::vector<unsigned> xfIndexes;
+ std::vector<bool> isIntegers;
+ std::vector<int> intValues;
+ std::vector<double> floatValues;
+ std::vector<unsigned> rkValues;
+};
+
+MulRKRecord::MulRKRecord():
+ Record(), CellInfo(), ColumnSpanInfo()
+{
+ d = new MulRKRecord::Private();
+}
+
+MulRKRecord::~MulRKRecord()
+{
+ delete d;
+}
+
+unsigned MulRKRecord::xfIndex( unsigned i ) const
+{
+ if( i >= d->xfIndexes.size() ) return 0;
+ return d->xfIndexes[ i ];
+}
+
+bool MulRKRecord::isInteger( unsigned i ) const
+{
+ if( i >= d->isIntegers.size() ) return true;
+ return d->isIntegers[ i ];
+}
+
+int MulRKRecord::asInteger( unsigned i ) const
+{
+ if( i >= d->intValues.size() ) return 0;
+ return d->intValues[ i ];
+}
+
+double MulRKRecord::asFloat( unsigned i ) const
+{
+ if( i >= d->floatValues.size() ) return 0.0;
+ return d->floatValues[ i ];
+}
+
+unsigned MulRKRecord::encodedRK( unsigned i ) const
+{
+ if( i >= d->rkValues.size() ) return 0;
+ return d->rkValues[ i ];
+}
+
+void MulRKRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 6 ) return;
+
+ setRow( readU16( data ) );
+
+ setFirstColumn( readU16( data+2 ) );
+ setLastColumn( readU16( data+size-2 ) );
+
+ d->xfIndexes.clear();
+ d->isIntegers.clear();
+ d->intValues.clear();
+ d->floatValues.clear();
+ for( unsigned i = 4; i < size-2; i+= 6 )
+ {
+ d->xfIndexes.push_back( readU16( data+i ) );
+ unsigned rk = readU32( data+i+2 );
+ d->rkValues.push_back( rk );
+ bool isInteger = true; int iv = 0; double fv = 0.0;
+ decodeRK( rk, isInteger, iv, fv );
+
+ d->isIntegers.push_back( isInteger );
+ d->intValues.push_back( isInteger ? iv : (int)fv );
+ d->floatValues.push_back( !isInteger ? fv : (double)iv );
+ }
+
+ // FIXME sentinel !
+}
+
+void MulRKRecord::dump( std::ostream& out ) const
+{
+ out << "MULRK" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " First Column : " << firstColumn() << std::endl;
+ out << " Last Column : " << lastColumn() << std::endl;
+ for( unsigned c = firstColumn(); c <= lastColumn(); c++ )
+ {
+ out << " Column " << c << " : " << asFloat( c-firstColumn() );
+ out << " Encoded: " << std::hex << encodedRK( c-firstColumn() );
+ out << std::endl;
+ }
+}
+
+// ========== NAME ==========
+
+const unsigned int NameRecord::id = 0x0018;
+
+class NameRecord::Private
+{
+public:
+ unsigned optionFlags;
+ UString definedName;
+};
+
+
+NameRecord::NameRecord()
+{
+ d = new Private;
+ d->optionFlags = 0;
+}
+
+NameRecord::~NameRecord()
+{
+ delete d;
+}
+
+void NameRecord::setDefinedName( const UString& name )
+{
+ d->definedName = name;
+}
+
+UString NameRecord::definedName() const
+{
+ return d->definedName;
+}
+
+void NameRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 14 ) return;
+
+ d->optionFlags = readU16( data );
+ unsigned len = data[3];
+
+ if ( version() == Excel95 )
+ {
+ char* buffer = new char[ len+1 ];
+ memcpy( buffer, data + 14, len );
+ buffer[ len ] = 0;
+ d->definedName = UString( buffer );
+ delete[] buffer;
+ }
+
+ if ( version() == Excel97 )
+ {
+ UString str = UString();
+ for( unsigned k=0; k<len; k++ )
+ {
+ unsigned uch = readU16( data + 14 + k*2 );
+ str.append( UChar(uch) );
+ }
+ d->definedName = str;
+ }
+}
+
+void NameRecord::dump( std::ostream& out ) const
+{
+}
+
+// ========== Number ==========
+
+const unsigned int NumberRecord::id = 0x0203;
+
+class NumberRecord::Private
+{
+public:
+ double number;
+};
+
+NumberRecord::NumberRecord():
+ Record(), CellInfo()
+{
+ d = new NumberRecord::Private();
+ d->number = 0.0;
+}
+
+NumberRecord::~NumberRecord()
+{
+ delete d;
+}
+
+double NumberRecord::number() const
+{
+ return d->number;
+}
+
+void NumberRecord::setNumber( double f )
+{
+ d->number = f;
+}
+
+// FIXME check that sizeof(double) is 64
+void NumberRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 14 ) return;
+
+ setRow( readU16( data ) );
+ setColumn( readU16( data+2 ) );
+ setXfIndex( readU16( data+4 ) );
+ setNumber( readFloat64( data+6 ) );
+}
+
+void NumberRecord::dump( std::ostream& out ) const
+{
+ out << "NUMBER" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " Column : " << column() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+ out << " Value : " << number() << std::endl;
+}
+
+// ========== PALETTE ==========
+
+const unsigned int PaletteRecord::id = 0x0092;
+
+class PaletteRecord::Private
+{
+public:
+ std::vector<Color> colors;
+};
+
+PaletteRecord::PaletteRecord():
+ Record()
+{
+ d = new PaletteRecord::Private();
+}
+
+PaletteRecord::~PaletteRecord()
+{
+ delete d;
+}
+
+Color PaletteRecord::color( unsigned i ) const
+{
+ return d->colors[ i ];
+}
+
+unsigned PaletteRecord::count() const
+{
+ return d->colors.size();
+}
+
+void PaletteRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 14 ) return;
+
+ unsigned num = readU16( data );
+
+ unsigned p = 2;
+ for( unsigned i = 0; i < num; i++, p+=4 )
+ {
+ unsigned red = data[ p ];
+ unsigned green = data[ p+1 ];
+ unsigned blue = data[ p+2 ];
+ d->colors.push_back( Color( red, green, blue ) );
+ }
+}
+
+void PaletteRecord::dump( std::ostream& out ) const
+{
+ out << "PALETTE" << std::endl;
+ out << " Count : " << count() << std::endl;
+ for( unsigned i = 0; i < count(); i++ )
+ {
+ out << " Color #" << std::setw(2) << i << " : ";
+ Color c = color( i );
+ out << "R:" << std::setw(3) << c.red;
+ out << " G:" << std::setw(3) << c.green;
+ out << " B:" << std::setw(3) << c.blue << std::endl;
+ }
+}
+
+// ========== RIGHTMARGIN ==========
+
+const unsigned int RightMarginRecord::id = 0x0027;
+
+class RightMarginRecord::Private
+{
+public:
+ double rightMargin;
+};
+
+RightMarginRecord::RightMarginRecord():
+ Record()
+{
+ d = new RightMarginRecord::Private();
+ d->rightMargin = 1.0;
+}
+
+RightMarginRecord::~RightMarginRecord()
+{
+ delete d;
+}
+
+double RightMarginRecord::rightMargin() const
+{
+ return d->rightMargin;
+}
+
+void RightMarginRecord::setRightMargin( double m )
+{
+ d->rightMargin = m;
+}
+
+void RightMarginRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 8 ) return;
+ setRightMargin( readFloat64( data ) );
+}
+
+void RightMarginRecord::dump( std::ostream& out ) const
+{
+ out << "RIGHTMARGIN" << std::endl;
+ out << " Right Margin : " << rightMargin() << " inches " << std::endl;
+}
+
+// ========== RK ==========
+
+const unsigned int RKRecord::id = 0x027e;
+
+class RKRecord::Private
+{
+public:
+ bool integer;
+ unsigned rk;
+ int i;
+ double f;
+};
+
+RKRecord::RKRecord():
+ Record(), CellInfo()
+{
+ d = new RKRecord::Private();
+ d->integer = true;
+ d->rk = 0;
+ d->i = 0;
+ d->f = 0.0;
+}
+
+RKRecord::~RKRecord()
+{
+ delete d;
+}
+
+bool RKRecord::isInteger() const
+{
+ return d->integer;
+}
+
+bool RKRecord::isFloat() const
+{
+ return !d->integer;
+}
+
+int RKRecord::asInteger() const
+{
+ if( d->integer )
+ return d->i;
+ else
+ return (int)d->f;
+}
+
+double RKRecord::asFloat() const
+{
+ if( !d->integer )
+ return d->f;
+ else
+ return (double)d->i;
+}
+
+void RKRecord::setInteger( int i )
+{
+ d->integer = true;
+ d->i = i;
+ d->f = (double)i;
+}
+
+void RKRecord::setFloat( double f )
+{
+ d->integer = false;
+ d->i = (int)f;
+ d->f = f;
+}
+
+unsigned RKRecord::encodedRK() const
+{
+ return d->rk;
+}
+
+// FIXME check sizeof(int) is 32
+// big vs little endian problem
+void RKRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 10 ) return;
+
+ setRow( readU16( data ) );
+ setColumn( readU16( data+2 ) );
+ setXfIndex( readU16( data+4 ) );
+
+ int i = 0; double f = 0.0;
+ d->rk = readU32( data+6 );
+ decodeRK( d->rk, d->integer, i, f );
+ if( d->integer ) setInteger( i );
+ else setFloat( f );
+}
+
+void RKRecord::dump( std::ostream& out ) const
+{
+ out << "RK" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " Column : " << column() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+ out << " Value : " << asFloat() << std::endl;
+ out << " Encoded RK : 0x" << std::hex << encodedRK() << std::endl;
+ out << std::dec;
+}
+
+// ========== Row ==========
+
+const unsigned int RowRecord::id = 0x0208;
+
+class RowRecord::Private
+{
+public:
+ unsigned row;
+ unsigned height;
+ unsigned xfIndex;
+ bool hidden;
+};
+
+RowRecord::RowRecord():
+ Record(), ColumnSpanInfo()
+{
+ d = new RowRecord::Private();
+ d->row = 0;
+ d->height = 50;
+ d->xfIndex = 0;
+ d->hidden = false;
+}
+
+RowRecord::~RowRecord()
+{
+ delete d;
+}
+
+unsigned RowRecord::row() const
+{
+ return d->row;
+}
+
+void RowRecord::setRow( unsigned r )
+{
+ d->row = r;
+}
+
+unsigned RowRecord::height() const
+{
+ return d->height;
+}
+
+void RowRecord::setHeight( unsigned h )
+{
+ d->height = h;
+}
+
+unsigned RowRecord::xfIndex() const
+{
+ return d->xfIndex;
+}
+
+void RowRecord::setXfIndex( unsigned i )
+{
+ d->xfIndex = i;
+}
+
+bool RowRecord::hidden() const
+{
+ return d->hidden;
+}
+
+void RowRecord::setHidden( bool h )
+{
+ d->hidden = h;
+}
+
+void RowRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 16 ) return;
+
+ setRow( readU16( data ) );
+ setFirstColumn( readU16( data+2 ) );
+ setLastColumn( readU16( data+4 ) );
+ setHeight( readU16( data+6 ) & 0x7fff );
+ setXfIndex( readU16( data+14 ) & 0xfff );
+
+ unsigned options = readU16( data+12 );
+ setHidden ( options & 0x20 );
+}
+
+void RowRecord::dump( std::ostream& out ) const
+{
+ out << "ROW" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " First Column : " << firstColumn() << std::endl;
+ out << " Last Column : " << lastColumn() << std::endl;
+ out << " Height : " << height() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+ out << " Hidden : " << ( hidden() ? "Yes" : "No" ) << std::endl;
+}
+
+// ========== RSTRING ==========
+
+const unsigned int RStringRecord::id = 0x00d6;
+
+class RStringRecord::Private
+{
+public:
+ UString label;
+};
+
+RStringRecord::RStringRecord():
+ Record(), CellInfo()
+{
+ d = new RStringRecord::Private();
+ d->label = UString::null;
+}
+
+RStringRecord::~RStringRecord()
+{
+ delete d;
+}
+
+UString RStringRecord::label() const
+{
+ return d->label;
+}
+
+void RStringRecord::setLabel( const UString& l )
+{
+ d->label = l;
+}
+
+// FIXME formatting runs ? in EString perhaps ?
+void RStringRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 6 ) return;
+
+ setRow( readU16( data ) );
+ setColumn( readU16( data+2 ) );
+ setXfIndex( readU16( data+4 ) );
+
+ // FIXME check Excel97
+ UString label = ( version() >= Excel97 ) ?
+ EString::fromUnicodeString( data+6, true, size-6 ).str() :
+ EString::fromByteString( data+6, true, size-6 ).str();
+ setLabel( label );
+}
+
+void RStringRecord::dump( std::ostream& out ) const
+{
+ out << "RSTRING" << std::endl;
+ out << " Row : " << row() << std::endl;
+ out << " Column : " << column() << std::endl;
+ out << " XF Index : " << xfIndex() << std::endl;
+ out << " Label : " << label() << std::endl;
+}
+
+// ========== SST ==========
+
+const unsigned int SSTRecord::id = 0x00fc;
+
+class SSTRecord::Private
+{
+public:
+ unsigned total;
+ unsigned count;
+ std::vector<UString> strings;
+};
+
+SSTRecord::SSTRecord():
+ Record()
+{
+ d = new SSTRecord::Private();
+ d->total = 0;
+ d->count = 0;
+}
+
+SSTRecord::~SSTRecord()
+{
+ delete d;
+}
+
+UString sstrecord_get_plain_string( const unsigned char* data, unsigned length )
+{
+ char* buffer = new char[ length+1 ];
+ memcpy( buffer, data, length );
+ buffer[ length ] = 0;
+ UString str = UString( buffer );
+ delete[] buffer;
+ return str;
+}
+
+void SSTRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 8 ) return;
+
+ d->total = readU32( data );
+ d->count = readU32( data+4 );
+
+ unsigned offset = 8;
+ d->strings.clear();
+
+ for( unsigned i = 0; i < d->count; i++ )
+ {
+ // check against size
+ if (offset >= size) {
+ std::cerr << "Warning: reached end of SST record, but not all strings have been read!" << std::endl;
+ break;
+ }
+
+ EString es = EString::fromUnicodeString( data+offset, true, size - offset );
+ d->strings.push_back( es.str() );
+ offset += es.size();
+ }
+
+ // safety, add null string if we can't read all of the rest
+ while( d->strings.size() < d->count )
+ d->strings.push_back( UString() );
+
+
+ // sanity check, adjust to safer condition
+ if( d->count < d->strings.size() )
+ {
+ std::cerr << "Warning: mismatch number of string in SST record!" << std::endl;
+ d->count = d->strings.size();
+ }
+}
+
+unsigned SSTRecord::count() const
+{
+ return d->count;
+}
+
+// why not just string() ? to avoid easy confusion with std::string
+UString SSTRecord::stringAt( unsigned index ) const
+{
+ if( index >= count()) return UString::null;
+ return d->strings[ index ];
+}
+
+void SSTRecord::dump( std::ostream& out ) const
+{
+ out << "SST" << std::endl;
+ out << " Occurences : " << d->total << std::endl;
+ out << " Count : " << count() << std::endl;
+ for( unsigned i = 0; i < count(); i++ )
+ out << " String #" << std::setw(2) << i << " : " <<
+ stringAt( i ) << std::endl;
+}
+
+// ========== STRING ==========
+
+const unsigned int StringRecord::id = 0x0207;
+
+class StringRecord::Private
+{
+public:
+ UString string;
+};
+
+StringRecord::StringRecord():
+ Record()
+{
+ d = new StringRecord::Private();
+}
+
+StringRecord::~StringRecord()
+{
+ delete d;
+}
+
+void StringRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 3 ) return;
+
+ // TODO simple string for BIFF7
+
+ EString es = EString::fromUnicodeString( data, true, size );
+ d->string = es.str();
+}
+
+UString StringRecord::ustring() const
+{
+ return d->string;
+}
+
+Value StringRecord::value() const
+{
+ return Value( d->string );
+}
+
+void StringRecord::dump( std::ostream& out ) const
+{
+ out << "STRING" << std::endl;
+ out << " String : " << ustring() << std::endl;
+}
+
+// ========== SUPBOOK ==========
+
+const unsigned int SupbookRecord::id = 0x01ae;
+
+class SupbookRecord::Private
+{
+public:
+ SupbookRecord::ReferenceType type;
+};
+
+SupbookRecord::SupbookRecord()
+{
+ d = new Private;
+ d->type = UnknownRef;
+}
+
+SupbookRecord::~SupbookRecord()
+{
+ delete d;
+}
+
+SupbookRecord::ReferenceType SupbookRecord::referenceType() const
+{
+ return d->type;
+}
+
+void SupbookRecord::setReferenceType(SupbookRecord::ReferenceType type)
+{
+ d->type = type;
+}
+
+void SupbookRecord::setData( unsigned size, const unsigned char* data )
+{
+ setReferenceType(UnknownRef);
+
+ if( version() >= Excel97 )
+ {
+ // check for add-in function or internal ref first
+ if(size == 4)
+ {
+ unsigned id1 = readU16(data);
+ unsigned id2 = readU16(data+2);
+ if((id1 == 1) && (id2 == 0x3a01))
+ setReferenceType(AddInRef);
+
+ // check for internal reference
+ if((id1 > 0) && (id2 == 0x0401))
+ setReferenceType(InternalRef);
+ }
+
+ // check for object (DDE/OLE) link
+ if(referenceType() == UnknownRef)
+ if(size > 2)
+ {
+ unsigned id1 = readU16(data);
+ if(id1 == 0)
+ setReferenceType(ObjectLink);
+ }
+
+ // no match, must be external ref
+ if(referenceType() == UnknownRef)
+ setReferenceType(ExternalRef);
+ }
+}
+
+void SupbookRecord::dump( std::ostream& out ) const
+{
+ out << "SUPBOOK" << std::endl;
+}
+
+
+// ========== TOPMARGIN ==========
+
+const unsigned int TopMarginRecord::id = 0x0028;
+
+class TopMarginRecord::Private
+{
+public:
+ double topMargin;
+};
+
+TopMarginRecord::TopMarginRecord():
+ Record()
+{
+ d = new TopMarginRecord::Private();
+ d->topMargin = 1.0;
+}
+
+TopMarginRecord::~TopMarginRecord()
+{
+ delete d;
+}
+
+double TopMarginRecord::topMargin() const
+{
+ return d->topMargin;
+}
+
+void TopMarginRecord::setTopMargin( double m )
+{
+ d->topMargin = m;
+}
+
+void TopMarginRecord::setData( unsigned size, const unsigned char* data )
+{
+ if( size < 8 ) return;
+ setTopMargin( readFloat64( data ) );
+}
+
+void TopMarginRecord::dump( std::ostream& out ) const
+{
+ out << "TOPMARGIN" << std::endl;
+ out << " Top Margin : " << topMargin() << " inches " << std::endl;
+}
+
+// ========== XF ==========
+
+const unsigned int XFRecord::id = 0x00e0;
+
+class XFRecord::Private
+{
+public:
+ unsigned fontIndex;
+ unsigned formatIndex;
+ bool locked;
+ bool formulaHidden;
+ unsigned parentStyle;
+ unsigned horizontalAlignment;
+ unsigned verticalAlignment;
+ bool textWrap;
+ unsigned rotationAngle;
+ bool stackedLetters;
+ unsigned indentLevel;
+ bool shrinkContent;
+ unsigned leftBorderStyle;
+ unsigned leftBorderColor;
+ unsigned rightBorderStyle;
+ unsigned rightBorderColor;
+ unsigned topBorderStyle;
+ unsigned topBorderColor;
+ unsigned bottomBorderStyle;
+ unsigned bottomBorderColor;
+ bool diagonalTopLeft;
+ bool diagonalBottomLeft;
+ unsigned diagonalStyle;
+ unsigned diagonalColor;
+ unsigned fillPattern;
+ unsigned patternForeColor;
+ unsigned patternBackColor;
+};
+
+XFRecord::XFRecord(): Record()
+{
+ d = new XFRecord::Private();
+ d->fontIndex = 0;
+ d->formatIndex = 0;
+ d->locked = false;
+ d->formulaHidden = false;
+ d->parentStyle = 0;
+ d->horizontalAlignment = Left;
+ d->verticalAlignment = VCentered;
+ d->textWrap = false;
+ d->rotationAngle = 0;
+ d->stackedLetters = 0;
+ d->indentLevel = 0;
+ d->shrinkContent = 0;
+ d->leftBorderStyle = 0;
+ d->leftBorderColor = 0;
+ d->rightBorderStyle = 0;
+ d->rightBorderColor = 0;
+ d->topBorderStyle = 0;
+ d->topBorderColor = 0;
+ d->bottomBorderStyle = 0;
+ d->bottomBorderColor = 0;
+ d->diagonalTopLeft = false;
+ d->diagonalBottomLeft = false;
+ d->diagonalStyle = 0;
+ d->diagonalColor = 0;
+ d->fillPattern = 0;
+ d->patternForeColor = 0;
+ d->patternBackColor = 0;
+}
+
+XFRecord::~XFRecord()
+{
+ delete d;
+}
+
+XFRecord::XFRecord( const XFRecord& xf ): Record()
+{
+ d = new XFRecord::Private();
+ operator=( xf );
+}
+
+XFRecord& XFRecord::operator=( const XFRecord& xf )
+{
+ d->fontIndex = xf.fontIndex();
+ d->formatIndex = xf.formatIndex();
+ d->locked = xf.locked();
+ d->formulaHidden = xf.formulaHidden();
+ d->parentStyle = xf.parentStyle();
+ d->horizontalAlignment = xf.horizontalAlignment();
+ d->verticalAlignment = xf.verticalAlignment();
+ d->textWrap = xf.textWrap();
+ d->rotationAngle = xf.rotationAngle();
+ d->stackedLetters = xf.stackedLetters();
+ d->indentLevel = xf.indentLevel();
+ d->shrinkContent = xf.shrinkContent();
+ d->leftBorderStyle = xf.leftBorderStyle();
+ d->leftBorderColor = xf.leftBorderColor();
+ d->rightBorderStyle = xf.rightBorderStyle();
+ d->rightBorderColor = xf.rightBorderColor();
+ d->topBorderStyle = xf.topBorderStyle();
+ d->topBorderColor = xf.topBorderColor();
+ d->bottomBorderStyle = xf.bottomBorderStyle();
+ d->bottomBorderColor = xf.bottomBorderColor();
+ d->diagonalTopLeft = xf.diagonalTopLeft();
+ d->diagonalBottomLeft = xf.diagonalBottomLeft();
+ d->diagonalStyle = xf.diagonalStyle();
+ d->diagonalColor = xf.diagonalColor();
+ d->fillPattern = xf.fillPattern();
+ d->patternForeColor = xf.patternForeColor();
+ d->patternBackColor = xf.patternBackColor();
+ return *this;
+}
+
+unsigned XFRecord::fontIndex() const
+{
+ return d->fontIndex;
+}
+
+void XFRecord::setFontIndex( unsigned fi )
+{
+ d->fontIndex = fi;
+}
+
+unsigned XFRecord::formatIndex() const
+{
+ return d->formatIndex;
+}
+
+void XFRecord::setFormatIndex( unsigned fi )
+{
+ d->formatIndex = fi;
+}
+
+bool XFRecord::locked() const
+{
+ return d->locked;
+}
+
+void XFRecord::setLocked( bool l )
+{
+ d->locked = l;
+}
+
+bool XFRecord::formulaHidden() const
+{
+ return d->formulaHidden;
+}
+
+void XFRecord::setFormulaHidden( bool f )
+{
+ d->formulaHidden = f;
+}
+
+unsigned XFRecord::parentStyle() const
+{
+ return d->parentStyle;
+}
+
+void XFRecord::setParentStyle( unsigned p )
+{
+ d->parentStyle = p;
+}
+
+unsigned XFRecord::horizontalAlignment() const
+{
+ return d->horizontalAlignment;
+}
+
+void XFRecord::setHorizontalAlignment( unsigned ha )
+{
+ d->horizontalAlignment = ha;
+}
+
+const char* XFRecord::horizontalAlignmentAsString() const
+{
+ const char *result = "Unknown";
+ switch( horizontalAlignment() )
+ {
+ case General: result = "General"; break;
+ case Left: result = "Left"; break;
+ case Centered: result = "Centered"; break;
+ case Right: result = "Right"; break;
+ case Justified: result = "Justified"; break;
+ case Filled: result = "Filled"; break;
+ default: break;
+ }
+ return result;
+}
+
+unsigned XFRecord::verticalAlignment() const
+{
+ return d->verticalAlignment;
+}
+
+void XFRecord::setVerticalAlignment( unsigned va )
+{
+ d->verticalAlignment = va;
+}
+
+const char* XFRecord::verticalAlignmentAsString() const
+{
+ const char *result = "Unknown";
+ switch( verticalAlignment() )
+ {
+ case Top: result = "Top"; break;
+ case VCentered: result = "Centered"; break;
+ case Bottom: result = "Bottom"; break;
+ case VJustified: result = "Justified"; break;
+ case VDistributed: result = "Distributed"; break;
+ default: break;
+ }
+ return result;
+}
+
+bool XFRecord::textWrap() const
+{
+ return d->textWrap;
+}
+
+void XFRecord::setTextWrap( bool wrap )
+{
+ d->textWrap = wrap;
+}
+
+unsigned XFRecord::rotationAngle() const
+{
+ return d->rotationAngle;
+}
+
+void XFRecord::setRotationAngle( unsigned angle )
+{
+ d->rotationAngle = angle;
+}
+
+bool XFRecord::stackedLetters() const
+{
+ return d->stackedLetters;
+}
+
+void XFRecord::setStackedLetters( bool stacked )
+{
+ d->stackedLetters = stacked;
+}
+
+unsigned XFRecord::indentLevel() const
+{
+ return d->indentLevel;
+}
+
+void XFRecord::setIndentLevel( unsigned i )
+{
+ d->indentLevel = i;
+}
+
+bool XFRecord::shrinkContent() const
+{
+ return d->shrinkContent;
+}
+
+void XFRecord::setShrinkContent( bool s )
+{
+ d->shrinkContent = s;
+}
+
+unsigned XFRecord::leftBorderStyle() const
+{
+ return d->leftBorderStyle;
+}
+
+void XFRecord::setLeftBorderStyle( unsigned style )
+{
+ d->leftBorderStyle = style;
+}
+
+unsigned XFRecord::leftBorderColor() const
+{
+ return d->leftBorderColor;
+}
+
+void XFRecord::setLeftBorderColor( unsigned color )
+{
+ d->leftBorderColor = color;
+}
+
+unsigned XFRecord::rightBorderStyle() const
+{
+ return d->rightBorderStyle;
+}
+
+void XFRecord::setRightBorderStyle( unsigned style )
+{
+ d->rightBorderStyle = style;
+}
+
+unsigned XFRecord::rightBorderColor() const
+{
+ return d->rightBorderColor;
+}
+
+void XFRecord::setRightBorderColor( unsigned color )
+{
+ d->rightBorderColor = color;
+}
+
+unsigned XFRecord::topBorderStyle() const
+{
+ return d->topBorderStyle;
+}
+
+void XFRecord::setTopBorderStyle( unsigned style )
+{
+ d->topBorderStyle = style;
+}
+
+unsigned XFRecord::topBorderColor() const
+{
+ return d->topBorderColor;
+}
+
+void XFRecord::setTopBorderColor( unsigned color )
+{
+ d->topBorderColor = color;
+}
+
+unsigned XFRecord::bottomBorderStyle() const
+{
+ return d->bottomBorderStyle;
+}
+
+void XFRecord::setBottomBorderStyle( unsigned style )
+{
+ d->bottomBorderStyle = style;
+}
+
+unsigned XFRecord::bottomBorderColor() const
+{
+ return d->bottomBorderColor;
+}
+
+void XFRecord::setBottomBorderColor( unsigned color )
+{
+ d->bottomBorderColor = color;
+}
+
+bool XFRecord::diagonalTopLeft() const
+{
+ return d->diagonalTopLeft;
+}
+
+void XFRecord::setDiagonalTopLeft( bool dd )
+{
+ d->diagonalTopLeft = dd;
+}
+
+bool XFRecord::diagonalBottomLeft() const
+{
+ return d->diagonalBottomLeft;
+}
+
+void XFRecord::setDiagonalBottomLeft( bool dd )
+{
+ d->diagonalBottomLeft = dd;
+}
+
+unsigned XFRecord::diagonalStyle() const
+{
+ return d->diagonalStyle;
+}
+
+void XFRecord::setDiagonalStyle( unsigned style )
+{
+ d->diagonalStyle = style;
+}
+
+unsigned XFRecord::diagonalColor() const
+{
+ return d->diagonalColor;
+}
+
+void XFRecord::setDiagonalColor( unsigned color )
+{
+ d->diagonalColor = color;
+}
+
+unsigned XFRecord::fillPattern() const
+{
+ return d->fillPattern;
+}
+
+void XFRecord::setFillPattern( unsigned pattern )
+{
+ d->fillPattern = pattern;
+}
+
+unsigned XFRecord::patternForeColor() const
+{
+ return d->patternForeColor;
+}
+
+void XFRecord::setPatternForeColor( unsigned color )
+{
+ d->patternForeColor = color;
+}
+
+unsigned XFRecord::patternBackColor() const
+{
+ return d->patternBackColor;
+}
+
+void XFRecord::setPatternBackColor( unsigned color )
+{
+ d->patternBackColor = color;
+}
+
+void XFRecord::setData( unsigned size, const unsigned char* data )
+{
+ unsigned recordSize = ( version() == Excel97 ) ? 20: 16;
+ if( size < recordSize ) return;
+
+ setFontIndex( readU16( data ) );
+ setFormatIndex( readU16( data+2 ) );
+
+ unsigned protection = readU16( data+4 ) & 7;
+ setLocked( protection & 1 );
+ setFormulaHidden( protection & 2 );
+
+ setParentStyle( readU16( data+4 ) >> 4 );
+
+ unsigned align = data[6];
+ setHorizontalAlignment( align & 0x07 );
+ setVerticalAlignment( align >> 4 );
+ setTextWrap( align & 0x08 );
+
+ unsigned angle = data[7];
+ setRotationAngle( ( angle != 255 ) ? ( angle & 0x7f ) : 0 );
+ setStackedLetters( angle == 255 );
+
+ if( version() == Excel97 )
+ {
+ unsigned options = data[8];
+ unsigned attributes = data[9];
+
+ setIndentLevel( options & 0x0f );
+ setShrinkContent( options & 0x10 );
+
+ unsigned linestyle = readU16( data + 10 );
+ unsigned color1 = readU16( data + 12 );
+ // unsigned color2 = readU16( data + 14 );
+ unsigned flag = readU16( data + 16 );
+ unsigned fill = readU16( data + 18 );
+
+ setLeftBorderStyle( linestyle & 0xf );
+ setRightBorderStyle( ( linestyle >> 4 ) & 0xf );
+ setTopBorderStyle( ( linestyle >> 8 ) & 0xf );
+ setBottomBorderStyle( ( linestyle >> 12 ) & 0xf );
+
+ setLeftBorderColor( color1 & 0x7f );
+ setRightBorderColor( ( color1 >> 7 ) & 0x7f );
+ setTopBorderColor( color1 & 0x7f );
+ setBottomBorderColor( ( color1 >> 7 ) & 0x7f );
+
+ setDiagonalTopLeft( color1 & 0x40 );
+ setDiagonalBottomLeft( color1 & 0x40 );
+ setDiagonalStyle( ( flag >> 4 ) & 0x1e );
+ setDiagonalColor( ( ( flag & 0x1f ) << 2 ) + ( ( color1 >> 14 ) & 3 ));
+
+ setFillPattern( ( flag >> 10 ) & 0x3f );
+ setPatternForeColor( fill & 0x7f );
+ setPatternBackColor( ( fill >> 7 ) & 0x7f );
+ }
+ else
+ {
+ unsigned data1 = readU32( data + 8 );
+ unsigned data2 = readU32( data + 12 );
+
+ setPatternForeColor( data1 & 0x7f );
+ setPatternBackColor( ( data1 >> 7 ) & 0x7f );
+ setFillPattern( ( data1 >> 16 ) & 0x3f );
+
+ setBottomBorderStyle( ( data1 >> 22 ) & 0x07 );
+ setBottomBorderColor( ( data1 >> 25 ) & 0x7f );
+
+ setTopBorderStyle( data2 & 0x07 );
+ setLeftBorderStyle( ( data2 >> 3 ) & 0x07 );
+ setRightBorderStyle( ( data2 >> 6 ) & 0x07 );
+
+ setTopBorderColor( ( data2 >> 9 ) & 0x7f );
+ setLeftBorderColor( ( data2 >> 16 ) & 0x7f );
+ setRightBorderColor( ( data2 >> 23 ) & 0x7f );
+ }
+}
+
+void XFRecord::dump( std::ostream& out ) const
+{
+ out << "XF" << std::endl;
+ out << " Parent Style : " << parentStyle() << std::endl;
+ out << " Font Index : " << fontIndex() << std::endl;
+ out << " Format Index : " << formatIndex() << std::endl;
+ out << " Locked : " << (locked()?"Yes":"No") << std::endl;
+ out << " Formula Visibility : " << (formulaHidden()?"Hidden":"Visible") << std::endl;
+ out << " Horizontal Align : " << horizontalAlignmentAsString() << std::endl;
+ out << " Vertical Align : " << verticalAlignmentAsString() << std::endl;
+ out << " Text Wrap : " << ( textWrap() ? "yes" : "no" ) << std::endl;
+ out << " Rotation : " << rotationAngle() << std::endl;
+ out << " Stacked Letters : " << ( stackedLetters() ? "yes" : "no" ) << std::endl;
+ out << " Indent Level : " << indentLevel() << std::endl;
+ out << " Shrink To Fit : " << ( shrinkContent() ? "yes" : "no" ) << std::endl;
+ out << " Left Border : Style " << leftBorderStyle();
+ out << " Color: " << leftBorderColor() << std::endl;
+ out << " Right Border : Style " << rightBorderStyle();
+ out << " Color: " << rightBorderColor() << std::endl;
+ out << " Top Border : Style " << topBorderStyle();
+ out << " Color: " << topBorderColor() << std::endl;
+ out << " Bottom Border : Style " << bottomBorderStyle();
+ out << " Color: " << bottomBorderColor() << std::endl;
+ out << " Diagonal Lines : " ;
+ if ( diagonalTopLeft() ) out << "TopLeft ";
+ if ( diagonalBottomLeft() ) out << "BottomLeft ";
+ out << "Style " << diagonalStyle() << " Color: " << diagonalColor() << std::endl;
+ out << " Fill Pattern : " << fillPattern() << std::endl;
+ out << " Fill Color : Fore " << patternForeColor() << " Back: "
+ << patternBackColor() << std::endl;
+}
+
+//=============================================
+// ExcelReader
+//=============================================
+
+struct ExcelReaderExternalWorkbook
+{
+ bool addin;
+ bool external;
+ bool internal;
+ bool objectLink;
+};
+
+class ExcelReader::Private
+{
+public:
+
+ // the workbook
+ Workbook* workbook;
+
+ // password protection flag
+ // TODO: password hash for record decryption
+ bool passwordProtected;
+
+ // active sheet, all cell records will be stored here
+ Sheet* activeSheet;
+
+ // for FORMULA+STRING record pair
+ Cell* formulaCell;
+
+ // mapping from BOF pos to actual Sheet
+ std::map<unsigned,Sheet*> bofMap;
+
+ // shared-string table
+ std::vector<UString> stringTable;
+
+ // table of format
+ std::map<unsigned,FormatRecord> formatTable;
+ std::map<unsigned,UString> formatsTable;
+
+ // table of font
+ std::vector<FontRecord> fontTable;
+
+ // table of Xformat
+ std::vector<XFRecord> xfTable;
+
+ // color table (from Palette record)
+ std::vector<Color> colorTable;
+
+ // mapping from font index to Swinder::FormatFont
+ std::map<unsigned,FormatFont> fontCache;
+
+ // for NAME and EXTERNNAME
+ std::vector<UString> nameTable;
+
+ // for SUPBOOK
+ std::vector<ExcelReaderExternalWorkbook> externalWorkbooks;
+
+ // for EXTERNSHEET
+ std::vector<UString> sheetRefs;
+
+ // for mergeToken functions
+ UString mergedTokens;
+};
+
+ExcelReader::ExcelReader()
+{
+ d = new ExcelReader::Private();
+
+ d->workbook = 0;
+ d->activeSheet = 0;
+ d->formulaCell = 0;
+
+ d->passwordProtected = false;
+
+ d->mergedTokens.reserve(1024);
+
+ // initialize palette
+ // default palette for all but the first 8 colors
+ static const char *const default_palette[64-8] =
+ {
+ "#000000", "#ffffff", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff",
+ "#00ffff", "#800000", "#008000", "#000080", "#808000", "#800080", "#008080",
+ "#c0c0c0", "#808080", "#9999ff", "#993366", "#ffffcc", "#ccffff", "#660066",
+ "#ff8080", "#0066cc", "#ccccff", "#000080", "#ff00ff", "#ffff00", "#00ffff",
+ "#800080", "#800000", "#008080", "#0000ff", "#00ccff", "#ccffff", "#ccffcc",
+ "#ffff99", "#99ccff", "#ff99cc", "#cc99ff", "#ffcc99", "#3366ff", "#33cccc",
+ "#99cc00", "#ffcc00", "#ff9900", "#ff6600", "#666699", "#969696", "#003366",
+ "#339966", "#003300", "#333300", "#993300", "#993366", "#333399", "#333333",
+ };
+ for( int i = 0; i < 64-8; i++ ) {
+ d->colorTable.push_back(Color(default_palette[i]));
+ }
+
+ // default number formats
+ for( int format = 0; format < 50; format++)
+ {
+ UString valueFormat;
+ switch(format)
+ {
+ case 0: break;
+ case 1: valueFormat = "0"; break;
+ case 2: valueFormat = "0.00"; break;
+ case 3: valueFormat = "#,##0"; break;
+ case 4: valueFormat = "#,##0.00"; break;
+ case 5: valueFormat = "\"$\"#,##0_);(\"S\"#,##0)"; break;
+ case 6: valueFormat = "\"$\"#,##0_);[Red](\"S\"#,##0)"; break;
+ case 7: valueFormat = "\"$\"#,##0.00_);(\"S\"#,##0.00)"; break;
+ case 8: valueFormat = "\"$\"#,##0.00_);[Red](\"S\"#,##0.00)"; break;
+ case 9: valueFormat = "0%"; break;
+ case 10: valueFormat = "0.00%"; break;
+ case 11: valueFormat = "0.00E+00"; break;
+ case 12: valueFormat = "#?/?"; break;
+ case 13: valueFormat = "#\?\?/\?\?"; break;
+ case 14: valueFormat = "M/D/YY"; break;
+ case 15: valueFormat = "D-MMM-YY"; break;
+ case 16: valueFormat = "D-MMM"; break;
+ case 17: valueFormat = "MMM-YY"; break;
+ case 18: valueFormat = "h:mm AM/PM"; break;
+ case 19: valueFormat = "h:mm:ss AM/PM"; break;
+ case 20: valueFormat = "h:mm"; break;
+ case 21: valueFormat = "h:mm:ss"; break;
+ case 22: valueFormat = "M/D/YY h:mm"; break;
+ case 37: valueFormat = "_(#,##0_);(#,##0)"; break;
+ case 38: valueFormat = "_(#,##0_);[Red](#,##0)"; break;
+ case 39: valueFormat = "_(#,##0.00_);(#,##0)"; break;
+ case 40: valueFormat = "_(#,##0.00_);[Red](#,##0)"; break;
+ case 41: valueFormat = "_(\"$\"*#,##0_);_(\"$\"*#,##0_);_(\"$\"*\"-\");(@_)"; break;
+ case 42: valueFormat = "_(*#,##0_);(*(#,##0);_(*\"-\");_(@_)"; break;
+ case 43: valueFormat = "_(\"$\"*#,##0.00_);_(\"$\"*#,##0.00_);_(\"$\"*\"-\");(@_)"; break;
+ case 44: valueFormat = "_(\"$\"*#,##0.00_);_(\"$\"*#,##0.00_);_(\"$\"*\"-\");(@_)"; break;
+ case 45: valueFormat = "mm:ss"; break;
+ case 46: valueFormat = "[h]:mm:ss"; break;
+ case 47: valueFormat = "mm:ss.0"; break;
+ case 48: valueFormat = "##0.0E+0"; break;
+ case 49: valueFormat = "@"; break;
+ }
+ d->formatsTable[format] = valueFormat;
+ }
+}
+
+ExcelReader::~ExcelReader()
+{
+ delete d;
+}
+
+
+// convert border style, e.g MediumDashed to a Pen
+static Pen convertBorderStyle( unsigned style )
+{
+ Pen pen;
+ switch( style )
+ {
+ case XFRecord::NoLine:
+ pen.width = 0;
+ pen.style = Pen::NoLine;
+ break;
+ case XFRecord::Thin:
+ pen.width = 1;
+ pen.style = Pen::SolidLine;
+ break;
+ case XFRecord::Medium:
+ pen.width = 3;
+ pen.style = Pen::SolidLine;
+ break;
+ case XFRecord::Dashed:
+ pen.width = 1;
+ pen.style = Pen::DashLine;
+ break;
+ case XFRecord::Dotted:
+ pen.width = 1;
+ pen.style = Pen::DotLine;
+ break;
+ case XFRecord::Thick:
+ pen.width = 4;
+ pen.style = Pen::SolidLine;
+ break;
+ case XFRecord::Double:
+ // FIXME no equivalent ?
+ pen.width = 4;
+ pen.style = Pen::SolidLine;
+ break;
+ case XFRecord::Hair:
+ // FIXME no equivalent ?
+ pen.width = 1;
+ pen.style = Pen::DotLine;
+ break;
+ case XFRecord::MediumDashed:
+ pen.width = 3;
+ pen.style = Pen::DashLine;
+ break;
+ case XFRecord::ThinDashDotted:
+ pen.width = 1;
+ pen.style = Pen::DashDotLine;
+ break;
+ case XFRecord::MediumDashDotted:
+ pen.width = 3;
+ pen.style = Pen::DashDotLine;
+ break;
+ case XFRecord::ThinDashDotDotted:
+ pen.width = 1;
+ pen.style = Pen::DashDotDotLine;
+ break;
+ case XFRecord::MediumDashDotDotted:
+ pen.width = 3;
+ pen.style = Pen::DashDotDotLine;
+ break;
+ case XFRecord::SlantedMediumDashDotted:
+ // FIXME no equivalent ?
+ pen.width = 3;
+ pen.style = Pen::DashDotLine;
+ break;
+ default:
+ // fallback, simple solid line
+ pen.width = 1;
+ pen.style = Pen::SolidLine;
+ break;
+ };
+
+ return pen;
+}
+
+unsigned convertPatternStyle( unsigned pattern )
+{
+ switch ( pattern )
+ {
+ case 0x00: return FormatBackground::EmptyPattern;
+ case 0x01: return FormatBackground::SolidPattern;
+ case 0x02: return FormatBackground::Dense4Pattern;
+ case 0x03: return FormatBackground::Dense3Pattern;
+ case 0x04: return FormatBackground::Dense5Pattern;
+ case 0x05: return FormatBackground::HorPattern;
+ case 0x06: return FormatBackground::VerPattern;
+ case 0x07: return FormatBackground::FDiagPattern;
+ case 0x08: return FormatBackground::BDiagPattern;
+ case 0x09: return FormatBackground::Dense1Pattern;
+ case 0x0A: return FormatBackground::Dense2Pattern;
+ case 0x0B: return FormatBackground::HorPattern;
+ case 0x0C: return FormatBackground::VerPattern;
+ case 0x0D: return FormatBackground::FDiagPattern;
+ case 0x0E: return FormatBackground::BDiagPattern;
+ case 0x0F: return FormatBackground::CrossPattern;
+ case 0x10: return FormatBackground::DiagCrossPattern;
+ case 0x11: return FormatBackground::Dense6Pattern;
+ case 0x12: return FormatBackground::Dense7Pattern;
+ default: return FormatBackground::SolidPattern; // fallback
+ }
+}
+
+
+bool ExcelReader::load( Workbook* workbook, const char* filename )
+{
+ POLE::Storage storage( filename );
+ if( !storage.open() )
+ {
+ //std::cerr << "Cannot open " << filename << std::endl;
+ return false;
+ }
+
+ unsigned version = Swinder::Excel97;
+ POLE::Stream* stream;
+ stream = new POLE::Stream( &storage, "/Workbook" );
+ if( stream->fail() )
+ {
+ delete stream;
+ stream = new POLE::Stream( &storage, "/Book" );
+ version = Swinder::Excel95;
+ }
+
+ if( stream->fail() )
+ {
+ //std::cerr << filename << " is not Excel workbook" << std::endl;
+ delete stream;
+ return false;
+ }
+
+ unsigned long stream_size = stream->size();
+
+ unsigned int buffer_size = 65536; // current size of the buffer
+ unsigned char *buffer = (unsigned char *) malloc(buffer_size);
+ unsigned char small_buffer[128]; // small, fixed size buffer
+
+ workbook->clear();
+ d->workbook = workbook;
+
+ d->passwordProtected = false;
+
+ // assume
+
+ while( stream->tell() < stream_size )
+ {
+
+ // this is set by FILEPASS record
+ // subsequent records will need to be decrypted
+ // since we do not support it yet, we have to bail out
+ if(d->passwordProtected)
+ {
+ d->workbook->setPasswordProtected( true );
+ break;
+ }
+
+ // get record type and data size
+ unsigned long pos = stream->tell();
+ unsigned bytes_read = stream->read( buffer, 4 );
+ if( bytes_read != 4 ) break;
+
+ unsigned long type = readU16( buffer );
+ unsigned long size = readU16( buffer + 2 );
+
+ // verify buffer is large enough to hold the record data
+ if (size > buffer_size) {
+ buffer = (unsigned char *) realloc(buffer, size);
+ buffer_size = size;
+ }
+
+ // load actual record data
+ bytes_read = stream->read( buffer, size );
+ if( bytes_read != size ) break;
+
+ // save current position in stream, to be able to restore the position later on
+ unsigned long saved_pos;
+ // repeatedly check if the next record is type 0x3C, a continuation record
+ unsigned long next_type; // the type of the next record
+ do {
+ saved_pos = stream->tell();
+
+ bytes_read = stream->read( small_buffer, 4 );
+ if (bytes_read != 4) break;
+
+ next_type = readU16( small_buffer );
+ unsigned long next_size = readU16( small_buffer + 2 );
+
+ if (next_type == 0x3C) {
+ // type of next record is 0x3C, so go ahead and append the contents of the next record to the buffer
+
+ // first verify the buffer is large enough to hold all the data
+ if ( (size + next_size) > buffer_size) {
+ buffer = (unsigned char *) realloc(buffer, size + next_size);
+ buffer_size = size + next_size;
+ }
+
+ // next read the data of the record
+ bytes_read = stream->read( buffer + size, next_size );
+ if (bytes_read != next_size) {
+ std::cout << "ERROR!" << std::endl;
+ break;
+ }
+
+ // if the first read byte is a zero, remove it (at least that is what the old excel97 filter did...)
+ if (buffer[size] == 0) {
+ memmove( buffer + size, buffer + size + 1, --next_size );
+ }
+
+ // and finally update size
+ size += next_size;
+ }
+ } while (next_type == 0x3C);
+
+ // restore position in stream to the beginning of the next record
+ stream->seek( saved_pos );
+
+ // skip record type 0, this is just for filler
+ if( type == 0 ) continue;
+
+ // create the record using the factory
+ Record* record = Record::create( type );
+
+ if( record )
+ {
+ // setup the record and invoke handler
+ record->setVersion( version );
+ record->setData( size, buffer );
+ record->setPosition( pos );
+
+ handleRecord( record );
+
+ // special handling to find Excel version
+ if ( record->rtti() == BOFRecord::id )
+ {
+ BOFRecord* bof = static_cast<BOFRecord*>(record);
+ if( bof ) if( bof->type() == BOFRecord::Workbook )
+ version = bof->version();
+ }
+
+#ifdef SWINDER_XLS2RAW
+ std::cout << "Record 0x";
+ std::cout << std::setfill('0') << std::setw(4) << std::hex << record->rtti();
+ std::cout << " ";
+ std::cout << std::dec;
+ std::cout << "(Pos: " << record->position() << ") ";
+ record->dump( std::cout );
+ std::cout << std::endl;
+#endif
+
+ delete record;
+ }
+
+#ifdef SWINDER_XLS2RAW
+ if( !record )
+ {
+ std::cout << "Record 0x";
+ std::cout << std::setfill('0') << std::setw(4) << std::hex << type;
+ std::cout << std::dec;
+ std::cout << "(Pos: " << pos << ") ";
+ std::cout << std::endl;
+ std::cout << std::endl;
+ }
+#endif
+
+ }
+
+ free(buffer);
+
+ delete stream;
+
+ storage.close();
+
+ // for each XF, create the corresponding format
+ for(int i = 0; i < d->xfTable.size(); i++ )
+ {
+ Format format;
+ const XFRecord& xf = d->xfTable[i];
+
+ UString valueFormat = d->formatsTable[xf.formatIndex()];
+ format.setValueFormat( valueFormat );
+
+ format.setFont( convertFont( xf.fontIndex() ) );
+
+ FormatAlignment alignment;
+ switch( xf.horizontalAlignment() )
+ {
+ case XFRecord::Left:
+ alignment.setAlignX( Format::Left ); break;
+ case XFRecord::Right:
+ alignment.setAlignX( Format::Right ); break;
+ case XFRecord::Centered:
+ alignment.setAlignX( Format::Center ); break;
+ default: break;
+ // FIXME still unsupported: Repeat, Justified, Filled, Distributed
+ };
+ switch( xf.verticalAlignment() )
+ {
+ case XFRecord::Top:
+ alignment.setAlignY( Format::Top ); break;
+ case XFRecord::VCentered:
+ alignment.setAlignY( Format::Middle ); break;
+ case XFRecord::Bottom:
+ alignment.setAlignY( Format::Bottom ); break;
+ default: break;
+ // FIXME still unsupported: Justified, Distributed
+ }
+ alignment.setWrap( xf.textWrap() );
+ format.setAlignment( alignment );
+
+ FormatBorders borders;
+
+ Pen pen;
+ pen = convertBorderStyle( xf.leftBorderStyle() );
+ pen.color = convertColor( xf.leftBorderColor() );
+ borders.setLeftBorder( pen );
+
+ pen = convertBorderStyle( xf.rightBorderStyle() );
+ pen.color = convertColor( xf.rightBorderColor() );
+ borders.setRightBorder( pen );
+
+ pen = convertBorderStyle( xf.topBorderStyle() );
+ pen.color = convertColor( xf.topBorderColor() );
+ borders.setTopBorder( pen );
+
+ pen = convertBorderStyle( xf.bottomBorderStyle() );
+ pen.color = convertColor( xf.bottomBorderColor() );
+ borders.setBottomBorder( pen );
+
+ format.setBorders( borders );
+
+ FormatBackground background;
+ background.setForegroundColor( convertColor( xf.patternForeColor() ) );
+ background.setBackgroundColor( convertColor( xf.patternBackColor() ) );
+ background.setPattern( convertPatternStyle( xf.fillPattern() ) );
+ format.setBackground( background );
+
+ d->workbook->setFormat( i, format );
+
+ }
+
+ return true;
+}
+
+void ExcelReader::handleRecord( Record* record )
+{
+ if( !record ) return;
+
+ unsigned type = record->rtti();
+ switch( type )
+ {
+ case BottomMarginRecord::id:
+ handleBottomMargin( static_cast<BottomMarginRecord*>( record ) ); break;
+ case BoundSheetRecord::id:
+ handleBoundSheet( static_cast<BoundSheetRecord*>( record ) ); break;
+ case BOFRecord::id:
+ handleBOF( static_cast<BOFRecord*>( record ) ); break;
+ case BoolErrRecord::id:
+ handleBoolErr( static_cast<BoolErrRecord*>( record ) ); break;
+ case BlankRecord::id:
+ handleBlank( static_cast<BlankRecord*>( record ) ); break;
+ case CalcModeRecord::id:
+ handleCalcMode( static_cast<CalcModeRecord*>( record ) ); break;
+ case ColInfoRecord::id:
+ handleColInfo( static_cast<ColInfoRecord*>( record ) ); break;
+ case ExternNameRecord::id:
+ handleExternName( static_cast<ExternNameRecord*>( record ) ); break;
+ case ExternSheetRecord::id:
+ handleExternSheet( static_cast<ExternSheetRecord*>( record ) ); break;
+ case FilepassRecord::id:
+ handleFilepass( static_cast<FilepassRecord*>( record ) ); break;
+ case FormatRecord::id:
+ handleFormat( static_cast<FormatRecord*>( record ) ); break;
+ case FormulaRecord::id:
+ handleFormula( static_cast<FormulaRecord*>( record ) ); break;
+ case FontRecord::id:
+ handleFont( static_cast<FontRecord*>( record ) ); break;
+ case FooterRecord::id:
+ handleFooter( static_cast<FooterRecord*>( record ) ); break;
+ case HeaderRecord::id:
+ handleHeader( static_cast<HeaderRecord*>( record ) ); break;
+ case LabelRecord::id:
+ handleLabel( static_cast<LabelRecord*>( record ) ); break;
+ case LabelSSTRecord::id:
+ handleLabelSST( static_cast<LabelSSTRecord*>( record ) ); break;
+ case LeftMarginRecord::id:
+ handleLeftMargin( static_cast<LeftMarginRecord*>( record ) ); break;
+ case MergedCellsRecord::id:
+ handleMergedCells( static_cast<MergedCellsRecord*>( record ) ); break;
+ case MulBlankRecord::id:
+ handleMulBlank( static_cast<MulBlankRecord*>( record ) ); break;
+ case MulRKRecord::id:
+ handleMulRK( static_cast<MulRKRecord*>( record ) ); break;
+ case NameRecord::id:
+ handleName( static_cast<NameRecord*>( record ) ); break;
+ case NumberRecord::id:
+ handleNumber( static_cast<NumberRecord*>( record ) ); break;
+ case PaletteRecord::id:
+ handlePalette( static_cast<PaletteRecord*>( record ) ); break;
+ case RightMarginRecord::id:
+ handleRightMargin( static_cast<RightMarginRecord*>( record ) ); break;
+ case RKRecord::id:
+ handleRK( static_cast<RKRecord*>( record ) ); break;
+ case RowRecord::id:
+ handleRow( static_cast<RowRecord*>( record ) ); break;
+ case RStringRecord::id:
+ handleRString( static_cast<RStringRecord*>( record ) ); break;
+ case SSTRecord::id:
+ handleSST( static_cast<SSTRecord*>( record ) ); break;
+ case StringRecord::id:
+ handleString( static_cast<StringRecord*>( record ) ); break;
+ case SupbookRecord::id:
+ handleSupbook( static_cast<SupbookRecord*>( record ) ); break;
+ case TopMarginRecord::id:
+ handleTopMargin( static_cast<TopMarginRecord*>( record ) ); break;
+ case XFRecord::id:
+ handleXF( static_cast<XFRecord*>( record ) ); break;
+ default:
+ break;
+ }
+}
+
+void ExcelReader::handleBottomMargin( BottomMarginRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ // convert from inches to points
+ double margin = record->bottomMargin() * 72.0;
+ d->activeSheet->setBottomMargin( margin );
+}
+
+// FIXME does the order of sheet follow BOUNDSHEET of BOF(Worksheet) ?
+// for now, assume BOUNDSHEET, hence we should create the sheet here
+void ExcelReader::handleBoundSheet( BoundSheetRecord* record )
+{
+ if( !record ) return;
+
+ // only care for Worksheet, forget everything else
+ if( record->type() == BoundSheetRecord::Worksheet )
+ {
+ // create a new sheet
+ Sheet* sheet = new Sheet( d->workbook );
+ sheet->setName( record->sheetName() );
+ sheet->setVisible( record->visible() );
+
+ d->workbook->appendSheet( sheet );
+
+ // update bof position map
+ unsigned bofPos = record->bofPosition();
+ d->bofMap[ bofPos ] = sheet;
+ }
+}
+
+void ExcelReader::handleBOF( BOFRecord* record )
+{
+ if( !record ) return;
+
+ if( record->type() == BOFRecord::Worksheet )
+ {
+ // find the sheet and make it active
+ // which sheet ? look from from previous BoundSheet
+ Sheet* sheet = d->bofMap[ record->position() ];
+ if( sheet ) d->activeSheet = sheet;
+ }
+}
+
+void ExcelReader::handleBoolErr( BoolErrRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned column = record->column();
+ unsigned row = record->row();
+ unsigned xfIndex = record->xfIndex();
+
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setValue( record->value() );
+ cell->setFormatIndex( xfIndex );
+ }
+}
+
+void ExcelReader::handleBlank( BlankRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned column = record->column();
+ unsigned row = record->row();
+ unsigned xfIndex = record->xfIndex();
+
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setFormatIndex( xfIndex );
+ }
+}
+
+void ExcelReader::handleCalcMode( CalcModeRecord* record )
+{
+ if( !record ) return;
+
+ d->workbook->setAutoCalc( record->autoCalc() );
+}
+
+void ExcelReader::handleColInfo( ColInfoRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned firstColumn = record->firstColumn();
+ unsigned lastColumn = record->lastColumn();
+ unsigned xfIndex = record->xfIndex();
+ unsigned width = record->width();
+ bool hidden = record->hidden();
+
+ for( unsigned i = firstColumn; i <= lastColumn; i++ )
+ {
+ Column* column = d->activeSheet->column( i, true );
+ if( column )
+ {
+ column->setWidth( width / 120 );
+ column->setFormatIndex( xfIndex );
+ column->setVisible( !hidden );
+ }
+ }
+}
+
+void ExcelReader::handleDateMode( DateModeRecord* record )
+{
+ if( !record ) return;
+
+ // FIXME FIXME what to do ??
+ std::cerr << "WARNING: Workbook uses unsupported 1904 Date System " << std::endl;
+}
+
+void ExcelReader::handleDimension( DimensionRecord* record )
+{
+ if( !record ) return;
+
+ // in the mean time we don't need to handle this because we don't care
+ // about the used range of the sheet
+}
+
+void ExcelReader::handleLabel( LabelRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned column = record->column();
+ unsigned row = record->row();
+ unsigned xfIndex = record->xfIndex();
+ UString label = record->label();
+
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setValue( Value( label ) );
+ cell->setFormatIndex( xfIndex );
+ }
+}
+
+void ExcelReader::handleLeftMargin( LeftMarginRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ // convert from inches to points
+ double margin = record->leftMargin() * 72.0;
+ d->activeSheet->setLeftMargin( margin );
+}
+
+void ExcelReader::handleFormat( FormatRecord* record )
+{
+ if( !record ) return;
+
+ d->formatTable[ record->index() ] = *record;
+ d->formatsTable[ record->index() ] = record->formatString();
+}
+
+void ExcelReader::handleFormula( FormulaRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned column = record->column();
+ unsigned row = record->row();
+ unsigned xfIndex = record->xfIndex();
+ Value value = record->result();
+
+#if 1
+ // this gives the formula in OpenDocument format, e.g. "=SUM([A1]; [A2])
+ UString formula = decodeFormula( row, column, record->tokens(), true );
+#else
+ // this gives the formula in standard Excel format, e.g. "=SUM(A1, A2)
+ UString formula = decodeFormula( row, column, record->tokens(), true );
+#endif
+
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setValue( value );
+ if( !formula.isEmpty() )
+ cell->setFormula( formula );
+ cell->setFormatIndex( xfIndex );
+
+ // if value is string, real value is in subsequent String record
+ if( value.isString() )
+ d->formulaCell = cell;
+ }
+}
+
+void ExcelReader::handleExternName( ExternNameRecord* record )
+{
+ if( !record ) return;
+
+ d->nameTable.push_back( record->externName() );
+}
+
+void ExcelReader::handleExternSheet( ExternSheetRecord* record )
+{
+ if( !record ) return;
+
+ if(record->version() >= Excel97)
+ for(unsigned i = 0; i < record->count(); i++)
+ {
+ UString decodedRef("#REF");
+
+ unsigned index = record->refIndex(i);
+ unsigned first = record->firstSheet(i);
+ unsigned last = record->lastSheet(i);
+
+ if(index < d->externalWorkbooks.size())
+ {
+ // handle reference to own workbook
+ if(d->externalWorkbooks[index].internal)
+ if(first < d->workbook->sheetCount())
+ decodedRef = d->workbook->sheet(first)->name();
+
+ // add-in? let's (re)use # marker as in Excel 95
+ if(d->externalWorkbooks[index].addin)
+ decodedRef = UString("#");
+ }
+
+ d->sheetRefs.push_back(decodedRef);
+ }
+ else
+ {
+ UString ref = record->refName();
+ d->sheetRefs.push_back(ref);
+ }
+}
+
+void ExcelReader::handleFilepass( FilepassRecord* record )
+{
+ if( !record ) return;
+
+ d->passwordProtected = true;
+}
+
+void ExcelReader::handleFont( FontRecord* record )
+{
+ if( !record ) return;
+
+ d->fontTable.push_back( *record );
+
+ // font #4 is never used, so add a dummy one
+ if( d->fontTable.size() == 4 )
+ d->fontTable.push_back( FontRecord() );
+}
+
+void ExcelReader::handleFooter( FooterRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ UString footer = record->footer();
+ UString left, center, right;
+ int pos = -1, len = 0;
+
+ // left part
+ pos = footer.find( UString("&L") );
+ if( pos >= 0 )
+ {
+ pos += 2;
+ len = footer.find( UString("&C") ) - pos;
+ if( len > 0 )
+ {
+ left = footer.substr( pos, len );
+ footer = footer.substr( pos+len, footer.length() );
+ }
+ }
+
+ // center part
+ pos = footer.find( UString("&C") );
+ if( pos >= 0 )
+ {
+ pos += 2;
+ len = footer.find( UString("&R") ) - pos;
+ if( len > 0 )
+ {
+ center = footer.substr( pos, len );
+ footer = footer.substr( pos+len, footer.length() );
+ }
+ }
+
+ // right part
+ pos = footer.find( UString("&R") );
+ if( pos >= 0 )
+ {
+ pos += 2;
+ right = footer.substr( pos, footer.length() - pos );
+ }
+
+ d->activeSheet->setLeftFooter( left );
+ d->activeSheet->setCenterFooter( center );
+ d->activeSheet->setRightFooter( right );
+}
+
+void ExcelReader::handleHeader( HeaderRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ UString header = record->header();
+ UString left, center, right;
+ int pos = -1, len = 0;
+
+ // left part of the header
+ pos = header.find( UString("&L") );
+ if( pos >= 0 )
+ {
+ pos += 2;
+ len = header.find( UString("&C") ) - pos;
+ if( len > 0 )
+ {
+ left = header.substr( pos, len );
+ header = header.substr( pos+len, header.length() );
+ }
+ }
+
+ // center part of the header
+ pos = header.find( UString("&C") );
+ if( pos >= 0 )
+ {
+ pos += 2;
+ len = header.find( UString("&R") ) - pos;
+ if( len > 0 )
+ {
+ center = header.substr( pos, len );
+ header = header.substr( pos+len, header.length() );
+ }
+ }
+
+ // right part of the header
+ pos = header.find( UString("&R") );
+ if( pos >= 0 )
+ {
+ pos += 2;
+ right = header.substr( pos, header.length() - pos );
+ }
+
+ d->activeSheet->setLeftHeader( left );
+ d->activeSheet->setCenterHeader( center );
+ d->activeSheet->setRightHeader( right );
+}
+
+void ExcelReader::handleLabelSST( LabelSSTRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned column = record->column();
+ unsigned row = record->row();
+ unsigned index = record->sstIndex();
+ unsigned xfIndex = record->xfIndex();
+
+ UString str;
+ if( index < d->stringTable.size() )
+ str = d->stringTable[ index ];
+
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setValue( Value( str ) );
+ cell->setFormatIndex( xfIndex );
+ }
+}
+
+void ExcelReader::handleMergedCells( MergedCellsRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ for( unsigned i = 0; i < record->count(); i++ )
+ {
+ unsigned firstRow = record->firstRow( i );
+ unsigned lastRow = record->lastRow( i );
+ unsigned firstColumn = record->firstColumn( i );
+ unsigned lastColumn = record->lastColumn( i );
+
+ Cell* cell = d->activeSheet->cell( firstColumn, firstRow, true );
+ if( cell )
+ {
+ cell->setColumnSpan( lastColumn - firstColumn + 1 );
+ cell->setRowSpan( lastRow - firstRow + 1 );
+ }
+ }
+}
+
+void ExcelReader::handleMulBlank( MulBlankRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned firstColumn = record->firstColumn();
+ unsigned lastColumn = record->lastColumn();
+ unsigned row = record->row();
+
+ for( unsigned column = firstColumn; column <= lastColumn; column++ )
+ {
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setFormatIndex( record->xfIndex( column - firstColumn ) );
+ }
+ }
+}
+
+void ExcelReader::handleMulRK( MulRKRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned firstColumn = record->firstColumn();
+ unsigned lastColumn = record->lastColumn();
+ unsigned row = record->row();
+
+ for( unsigned column = firstColumn; column <= lastColumn; column++ )
+ {
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ unsigned i = column - firstColumn;
+ Value value;
+ if( record->isInteger( i ) )
+ value.setValue( record->asInteger( i ) );
+ else
+ value.setValue( record->asFloat( i ) );
+ cell->setValue( value );
+ cell->setFormatIndex( record->xfIndex( column-firstColumn ) );
+ }
+ }
+}
+
+void ExcelReader::handleName( NameRecord* record )
+{
+ if( !record ) return;
+
+ d->nameTable.push_back( record->definedName() );
+}
+
+void ExcelReader::handleNumber( NumberRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned column = record->column();
+ unsigned row = record->row();
+ unsigned xfIndex = record->xfIndex();
+ double number = record->number();
+
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setValue( Value( number ) );
+ cell->setFormatIndex( xfIndex );
+ }
+}
+
+void ExcelReader::handlePalette( PaletteRecord* record )
+{
+ if( !record ) return;
+
+ d->colorTable.clear();
+ for( unsigned i = 0; i < record->count(); i++ )
+ d->colorTable.push_back( record->color( i ) );
+}
+
+void ExcelReader::handleRightMargin( RightMarginRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ // convert from inches to points
+ double margin = record->rightMargin() * 72.0;
+ d->activeSheet->setRightMargin( margin );
+}
+
+void ExcelReader::handleRK( RKRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned column = record->column();
+ unsigned row = record->row();
+ unsigned xfIndex = record->xfIndex();
+
+ Value value;
+ if( record->isInteger() )
+ value.setValue( record->asInteger() );
+ else
+ value.setValue( record->asFloat() );
+
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setValue( value );
+ cell->setFormatIndex( xfIndex );
+ }
+}
+
+void ExcelReader::handleRow( RowRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned index = record->row();
+ unsigned xfIndex = record->xfIndex();
+ unsigned height = record->height();
+ bool hidden = record->hidden();
+
+ Row* row = d->activeSheet->row( index, true );
+ if( row )
+ {
+ row->setHeight( height / 20.0 );
+ row->setFormatIndex( xfIndex );
+ row->setVisible( !hidden );
+ }
+}
+
+void ExcelReader::handleRString( RStringRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+ unsigned column = record->column();
+ unsigned row = record->row();
+ unsigned xfIndex = record->xfIndex();
+ UString label = record->label();
+
+ Cell* cell = d->activeSheet->cell( column, row, true );
+ if( cell )
+ {
+ cell->setValue( Value( label ) );
+ cell->setFormatIndex( xfIndex );
+ }
+}
+
+void ExcelReader::handleSST( SSTRecord* record )
+{
+ if( !record ) return;
+
+ d->stringTable.clear();
+ for( unsigned i = 0; i < record->count();i++ )
+ {
+ UString str = record->stringAt( i );
+ d->stringTable.push_back( str );
+ }
+}
+
+void ExcelReader::handleString( StringRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+ if( !d->formulaCell ) return;
+
+ d->formulaCell->setValue( record->value() );
+
+ d->formulaCell = 0;
+}
+
+void ExcelReader::handleSupbook( SupbookRecord* record )
+{
+ if( !record ) return;
+
+ ExcelReaderExternalWorkbook ext;
+ ext.addin = record->referenceType() == SupbookRecord::AddInRef;
+ ext.internal = record->referenceType() == SupbookRecord::InternalRef;
+ ext.external = record->referenceType() == SupbookRecord::ExternalRef;
+ ext.objectLink = record->referenceType() == SupbookRecord::ObjectLink;
+ d->externalWorkbooks.push_back(ext);
+}
+
+void ExcelReader::handleTopMargin( TopMarginRecord* record )
+{
+ if( !record ) return;
+
+ if( !d->activeSheet ) return;
+
+
+ // convert from inches to points
+ double margin = record->topMargin() * 72.0;
+ d->activeSheet->setTopMargin( margin );
+}
+
+FormatFont ExcelReader::convertFont( unsigned fontIndex )
+{
+ // speed-up trick: check in the cache first
+ FormatFont font = d->fontCache[ fontIndex ];
+ if( font.isNull() && ( fontIndex < d->fontTable.size() ))
+ {
+ FontRecord fr = d->fontTable[ fontIndex ];
+ font.setFontSize( fr.height() / 20.0 );
+ font.setFontFamily( fr.fontName() );
+ font.setColor( convertColor( fr.colorIndex() ) );
+ font.setBold( fr.boldness() > 500 );
+ font.setItalic( fr.italic() );
+ font.setStrikeout( fr.strikeout() );
+ font.setSubscript( fr.escapement() == FontRecord::Subscript );
+ font.setSuperscript( fr.escapement() == FontRecord::Superscript );
+ font.setUnderline( fr.underline() != FontRecord::None );
+
+ // put in the cache for further use
+ d->fontCache[ fontIndex ] = font;
+ }
+
+ return font;
+}
+
+Color ExcelReader::convertColor( unsigned colorIndex )
+{
+ if( ( colorIndex >= 8 ) && ( colorIndex < 0x40 ) )
+ if( colorIndex-8 < d->colorTable.size() )
+ return d->colorTable[ colorIndex-8 ];
+
+ // FIXME the following colors depend on system color settings
+ // 0x0040 system window text colour for border lines
+ // 0x0041 system window background colour for pattern background
+ // 0x7fff system window text colour for fonts
+ if( colorIndex == 0x40 ) return Color( 0, 0, 0 );
+ if( colorIndex == 0x41 ) return Color( 255, 255, 255 );
+ if( colorIndex == 0x7fff ) return Color( 0, 0, 0 );
+
+ // fallback: just "black"
+ Color color;
+
+ // standard colors: black, white, red, green, blue,
+ // yellow, magenta, cyan
+ switch( colorIndex )
+ {
+ case 0: color = Color( 0, 0, 0 ); break;
+ case 1: color = Color( 255, 255, 255 ); break;
+ case 2: color = Color( 255, 0, 0 ); break;
+ case 3: color = Color( 0, 255, 0 ); break;
+ case 4: color = Color( 0, 0, 255 ); break;
+ case 5: color = Color( 255, 255, 0 ); break;
+ case 6: color = Color( 255, 0, 255 ); break;
+ case 7: color = Color( 0, 255, 255 ); break;
+ default: break;
+ }
+
+ return color;
+}
+
+// big task: convert Excel XFormat into Swinder::Format
+Format ExcelReader::convertFormat( unsigned xfIndex )
+{
+ Format format;
+
+ if( xfIndex >= d->xfTable.size() ) return format;
+
+ XFRecord xf = d->xfTable[ xfIndex ];
+
+ UString valueFormat = d->formatsTable[xf.formatIndex()];
+ format.setValueFormat( valueFormat );
+
+ format.setFont( convertFont( xf.fontIndex() ) );
+
+ FormatAlignment alignment;
+ switch( xf.horizontalAlignment() )
+ {
+ case XFRecord::Left:
+ alignment.setAlignX( Format::Left ); break;
+ case XFRecord::Right:
+ alignment.setAlignX( Format::Right ); break;
+ case XFRecord::Centered:
+ alignment.setAlignX( Format::Center ); break;
+ default: break;
+ // FIXME still unsupported: Repeat, Justified, Filled, Distributed
+ };
+ switch( xf.verticalAlignment() )
+ {
+ case XFRecord::Top:
+ alignment.setAlignY( Format::Top ); break;
+ case XFRecord::VCentered:
+ alignment.setAlignY( Format::Middle ); break;
+ case XFRecord::Bottom:
+ alignment.setAlignY( Format::Bottom ); break;
+ default: break;
+ // FIXME still unsupported: Justified, Distributed
+ }
+ alignment.setWrap( xf.textWrap() );
+ format.setAlignment( alignment );
+
+ FormatBorders borders;
+
+ Pen pen;
+ pen = convertBorderStyle( xf.leftBorderStyle() );
+ pen.color = convertColor( xf.leftBorderColor() );
+ borders.setLeftBorder( pen );
+
+ pen = convertBorderStyle( xf.rightBorderStyle() );
+ pen.color = convertColor( xf.rightBorderColor() );
+ borders.setRightBorder( pen );
+
+ pen = convertBorderStyle( xf.topBorderStyle() );
+ pen.color = convertColor( xf.topBorderColor() );
+ borders.setTopBorder( pen );
+
+ pen = convertBorderStyle( xf.bottomBorderStyle() );
+ pen.color = convertColor( xf.bottomBorderColor() );
+ borders.setBottomBorder( pen );
+
+ format.setBorders( borders );
+
+ FormatBackground background;
+ background.setForegroundColor( convertColor( xf.patternForeColor() ) );
+ background.setBackgroundColor( convertColor( xf.patternBackColor() ) );
+ background.setPattern( convertPatternStyle( xf.fillPattern() ) );
+ format.setBackground( background );
+
+ return format;
+}
+
+void ExcelReader::handleXF( XFRecord* record )
+{
+ if( !record ) return;
+
+ d->xfTable.push_back( *record );
+}
+
+
+void ExcelReader::mergeTokens( UStringStack* stack, int count, const char* mergeString )
+{
+ if( !stack ) return;
+ if( !stack->size() ) return;
+ if( count < 1 ) return;
+
+ d->mergedTokens.truncate(0);
+ while(count)
+ {
+ count--;
+
+ // sanity check
+ if(stack->size() == 0) break;
+
+ d->mergedTokens.prepend((*stack)[ stack->size()-1 ]);
+ if( count )
+ d->mergedTokens.prepend(mergeString);
+ stack->resize( stack->size()-1 );
+ }
+
+ stack->push_back( d->mergedTokens );
+}
+
+void ExcelReader::mergeTokens( UStringStack* stack, int count, const char mergeChar )
+{
+ if( !stack ) return;
+ if( !stack->size() ) return;
+ if( count < 1 ) return;
+
+ d->mergedTokens.truncate(0);
+ while(count)
+ {
+ count--;
+
+ // sanity check
+ if(stack->size() == 0) break;
+
+ d->mergedTokens.prepend((*stack)[ stack->size()-1 ]);
+ if( count )
+ d->mergedTokens.prepend(mergeChar);
+ stack->resize( stack->size()-1 );
+ }
+
+ stack->push_back( d->mergedTokens );
+}
+
+#ifdef SWINDER_XLS2RAW
+void dumpStack( std::vector<UString> stack )
+{
+ std::cout << std::endl;
+ std::cout << "Stack now is: " ;
+ if( !stack.size() )
+ std::cout << "(empty)" ;
+
+ for( unsigned i = 0; i < stack.size(); i++ )
+ std::cout << " " << i << ": " << stack[i].ascii() << std::endl;
+ std::cout << std::endl;
+}
+#endif
+
+UString ExcelReader::decodeFormula( unsigned row, unsigned col,
+ const FormulaTokens& tokens, bool openDocumentFormat )
+{
+ UStringStack stack;
+
+ char argumentSeparator = ',';
+ if( openDocumentFormat )
+ argumentSeparator = ';';
+
+ for( unsigned c=0; c < tokens.size(); c++ )
+ {
+ FormulaToken token = tokens[c];
+
+#ifdef SWINDER_XLS2RAW
+ std::cout << "Token " << c << ": ";
+ std::cout << token.id() << " ";
+ std::cout << token.idAsString() << std::endl;
+#endif
+
+ switch( token.id() )
+ {
+ case FormulaToken::Add:
+ mergeTokens( &stack, 2, '+' );
+ break;
+
+ case FormulaToken::Sub:
+ mergeTokens( &stack, 2, '-' );
+ break;
+
+ case FormulaToken::Mul:
+ mergeTokens( &stack, 2, '*' );
+ break;
+
+ case FormulaToken::Div:
+ mergeTokens( &stack, 2, '/' );
+ break;
+
+ case FormulaToken::Power:
+ mergeTokens( &stack, 2, '^' );
+ break;
+
+ case FormulaToken::Concat:
+ mergeTokens( &stack, 2, '&' );
+ break;
+
+ case FormulaToken::LT:
+ mergeTokens( &stack, 2, '<' );
+ break;
+
+ case FormulaToken::LE:
+ mergeTokens( &stack, 2, "<=" );
+ break;
+
+ case FormulaToken::EQ:
+ mergeTokens( &stack, 2, '=' );
+ break;
+
+ case FormulaToken::GE:
+ mergeTokens( &stack, 2, ">=" );
+ break;
+
+ case FormulaToken::GT:
+ mergeTokens( &stack, 2, '>' );
+ break;
+
+ case FormulaToken::NE:
+ mergeTokens( &stack, 2, "<>" );
+ break;
+
+ case FormulaToken::Intersect:
+ mergeTokens( &stack, 2, ' ' );
+ break;
+
+ case FormulaToken::List:
+ mergeTokens( &stack, 2, ';' );
+ break;
+
+ case FormulaToken::Range:
+ mergeTokens( &stack, 2, ';' );
+ break;
+
+ case FormulaToken::UPlus:
+ if(stack.size() > 1)
+ stack[ stack.size()-1 ].prepend('+');
+ break;
+
+ case FormulaToken::UMinus:
+ if(stack.size() > 1)
+ stack[ stack.size()-1 ].prepend('-');
+ break;
+
+ case FormulaToken::Percent:
+ stack[ stack.size()-1 ].append('%');
+ break;
+
+ case FormulaToken::Paren:
+ {
+ UString str(stack[ stack.size()-1 ]);
+ str.prepend('(');
+ str.append(')');
+ stack[ stack.size()-1 ] = str;
+ }
+ break;
+
+ case FormulaToken::MissArg:
+ // just ignore
+ stack.push_back( UString(" ") );
+ break;
+
+ case FormulaToken::String:
+ {
+ UString str(token.value().asString());
+ str.prepend('\"');
+ str.append('\"');
+ stack.push_back( str );
+ }
+ break;
+
+ case FormulaToken::Bool:
+ if( token.value().asBoolean() )
+ stack.push_back( UString( "TRUE" ) );
+ else
+ stack.push_back( UString( "FALSE" ) );
+ break;
+
+ case FormulaToken::Integer:
+ stack.push_back( UString::number( token.value().asInteger() ) );
+ break;
+
+ case FormulaToken::Float:
+ stack.push_back( UString::number( token.value().asFloat() ) );
+ break;
+
+ case FormulaToken::Array:
+ // FIXME handle this !
+ break;
+
+ case FormulaToken::Ref:
+ {
+ UString refName(token.ref( row, col ));
+ if( openDocumentFormat )
+ {
+ refName.prepend('[');
+ refName.append(']');
+ }
+ stack.push_back( refName );
+ }
+ break;
+
+ case FormulaToken::Ref3d:
+ {
+ UString refName("#REF");
+ refName.reserve(32);
+
+ unsigned sheetIndex = token.externSheetRef();
+ if(sheetIndex < d->sheetRefs.size())
+ {
+ UString cellName = token.ref(row, col);
+ UString sheetName = d->sheetRefs[sheetIndex];
+
+ // OpenDocument example: [Sheet1.B1]
+ if( openDocumentFormat )
+ {
+ refName = UString("[");
+ refName.append( sheetName );
+ if(!sheetName.isEmpty())
+ refName.append(UString("."));
+ refName.append( cellName );
+ refName.append(UString("]"));
+ }
+ else
+ {
+ refName = sheetName;
+ if(!sheetName.isEmpty())
+ refName.append(UString("."));
+ refName.append(UString("!"));
+ refName.append(cellName);
+ }
+ }
+
+ stack.push_back( refName );
+ }
+ break;
+
+ case FormulaToken::Area:
+ {
+ UString areaName( token.area( row, col ) );
+ if( openDocumentFormat )
+ {
+ areaName.prepend('[');
+ areaName.append(']');
+ }
+ stack.push_back( areaName);
+ }
+ break;
+
+ case FormulaToken::Area3d:
+ {
+ UString areaName("#REF");
+ areaName.reserve(32);
+
+ unsigned sheetIndex = token.externSheetRef();
+ if(sheetIndex < d->sheetRefs.size())
+ {
+ UString rangeName = token.area(row, col);
+ UString sheetName = d->sheetRefs[sheetIndex];
+
+ // OpenDocument example: [Sheet1.B1:B3]
+ if( openDocumentFormat )
+ {
+ areaName = UString("[");
+ areaName.append( sheetName );
+ if(!sheetName.isEmpty())
+ areaName.append('.');
+ areaName.append( rangeName );
+ areaName.append(']');
+ }
+ else
+ {
+ areaName = sheetName;
+ if(!sheetName.isEmpty())
+ {
+ areaName.append('.');
+ areaName.append('!');
+ }
+ areaName.append(rangeName);
+ }
+ }
+ stack.push_back( areaName);
+ }
+ break;
+
+ case FormulaToken::Function:
+ {
+ mergeTokens( &stack, token.functionParams(), argumentSeparator );
+ if( stack.size() )
+ {
+ UString str( token.functionName() ? token.functionName() : "??" );
+ str.reserve(256);
+ str.append( '(' );
+ str.append( stack[ stack.size()-1 ] );
+ str.append( ')' );
+ stack[ stack.size()-1 ] = str;
+ }
+ }
+ break;
+
+ case FormulaToken::FunctionVar:
+ if( token.functionIndex() != 255 )
+ {
+ mergeTokens( &stack, token.functionParams(), argumentSeparator );
+ if( stack.size() )
+ {
+ UString str;
+ if( token.functionIndex() != 255 )
+ str = token.functionName() ? token.functionName() : "??";
+ str.reserve(256);
+ str.append( '(' );
+ str.append( stack[ stack.size()-1 ] );
+ str.append( ')' );
+ stack[ stack.size()-1 ] = str;
+ }
+ }
+ else
+ {
+ unsigned count = token.functionParams()-1;
+ mergeTokens( &stack, count, argumentSeparator );
+ if( stack.size() )
+ {
+ UString str;
+ str.append( '(' );
+ str.append( stack[ stack.size()-1 ] );
+ str.append( ')' );
+ stack[ stack.size()-1 ] = str;
+ }
+ }
+ break;
+
+ case FormulaToken::Attr:
+ if( token.attr() & 0x10 ) // SUM
+ {
+ mergeTokens( &stack, 1, argumentSeparator );
+ if( stack.size() )
+ {
+ UString str( "SUM" );
+ str.append( '(' );
+ str.append( stack[ stack.size()-1 ] );
+ str.append( ')' );
+ stack[ stack.size()-1 ] = str;
+ }
+ }
+ break;
+
+ case FormulaToken::NameX:
+ if( token.nameIndex() > 0 )
+ if( token.nameIndex() <= d->nameTable.size() )
+ stack.push_back( d->nameTable[ token.nameIndex()-1 ] );
+ break;
+
+ case FormulaToken::Matrix:
+ {
+ int row = token.refRow();
+ int col = token.refColumn();
+ //std::cout << "row is " << row << " col is " << col << std::endl;
+ }
+ break;
+
+ case FormulaToken::NatFormula:
+ case FormulaToken::Sheet:
+ case FormulaToken::EndSheet:
+ case FormulaToken::ErrorCode:
+ case FormulaToken::Name:
+ case FormulaToken::MemArea:
+ case FormulaToken::MemErr:
+ case FormulaToken::MemNoMem:
+ case FormulaToken::MemFunc:
+ case FormulaToken::RefErr:
+ case FormulaToken::AreaErr:
+ case FormulaToken::RefN:
+ case FormulaToken::AreaN:
+ case FormulaToken::MemAreaN:
+ case FormulaToken::MemNoMemN:
+ case FormulaToken::RefErr3d:
+ case FormulaToken::AreaErr3d:
+ default:
+ // FIXME handle this !
+ stack.push_back( UString("UnknownToken") );
+ //std::cout << "UnknownToken ID=" << token.id() << std::endl;
+ break;
+ };
+
+#ifdef SWINDER_XLS2RAW
+ dumpStack( stack );
+#endif
+
+ }
+
+ UString result;
+ for( unsigned i = 0; i < stack.size(); i++ )
+ result.append( stack[i] );
+
+#ifdef SWINDER_XLS2RAW
+ std::cout << "FORMULA Result: " << result << std::endl;
+#endif
+ return result;
+}
+
+
+#ifdef SWINDER_XLS2RAW
+
+#include <iostream>
+
+int main( int argc, char ** argv )
+{
+ if( argc < 2 )
+ {
+ std::cout << "Usage: xls2raw filename" << std::endl;
+ return 0;
+ }
+
+ char* filename = argv[1];
+ std::cout << "Checking " << filename << std::endl;
+
+ Workbook* workbook = new Workbook();
+ ExcelReader* reader = new ExcelReader();
+ reader->load( workbook, filename );
+ delete reader;
+ delete workbook;
+
+ return 0;
+}
+
+#endif // XLS2RAW
diff --git a/filters/kspread/excel/sidewinder/excel.h b/filters/kspread/excel/sidewinder/excel.h
new file mode 100644
index 000000000..5221b518c
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/excel.h
@@ -0,0 +1,3250 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003-2006 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#ifndef SWINDER_EXCEL_H
+#define SWINDER_EXCEL_H
+
+#include <string>
+#include <iostream>
+#include <vector>
+
+#include "swinder.h"
+
+namespace Swinder
+{
+
+/**
+ Supported Excel document version.
+*/
+enum { UnknownExcel = 0, Excel95, Excel97, Excel2000 };
+
+class Record;
+
+// rich-text, unicode, far-east support Excel string
+
+class EString
+{
+public:
+
+ EString();
+
+ EString( const EString& );
+
+ EString& operator=( const EString& );
+
+ ~EString();
+
+ bool unicode() const;
+
+ void setUnicode( bool u );
+
+ bool richText() const;
+
+ void setRichText( bool r );
+
+ UString str() const;
+
+ void setStr( const UString& str );
+
+ // space allocate for the string, not length (use string.length() for that)
+ unsigned size() const;
+ void setSize( unsigned size ); // HACKS
+
+
+ static EString fromUnicodeString( const void* p, bool longString, unsigned maxsize = 0 );
+
+ static EString fromSheetName( const void* p, unsigned maxsize = 0 );
+
+ // from the buffer
+ // longstring means 16-bit string length, usually for label
+ // longstring=false is normally for sheet name
+ static EString fromByteString( const void* p, bool longString, unsigned maxsize = 0 );
+
+private:
+ class Private;
+ Private* d;
+};
+
+class FormulaToken
+{
+public:
+
+ enum
+ {
+ // should match Excel's PTG
+ Unused = 0x00,
+ Matrix = 0x01,
+ Table = 0x02,
+ Add = 0x03,
+ Sub = 0x04,
+ Mul = 0x05,
+ Div = 0x06,
+ Power = 0x07,
+ Concat = 0x08,
+ LT = 0x09,
+ LE = 0x0a,
+ EQ = 0x0b,
+ GE = 0x0c,
+ GT = 0x0d,
+ NE = 0x0e,
+ Intersect = 0x0f,
+ List = 0x10,
+ Range = 0x11,
+ UPlus = 0x12,
+ UMinus = 0x13,
+ Percent = 0x14,
+ Paren = 0x15,
+ MissArg = 0x16,
+ String = 0x17,
+ NatFormula = 0x18,
+ Attr = 0x19,
+ Sheet = 0x1a,
+ EndSheet = 0x1b,
+ ErrorCode = 0x1c,
+ Bool = 0x1d,
+ Integer = 0x1e,
+ Float = 0x1f,
+ Array = 0x20,
+ Function = 0x21,
+ FunctionVar = 0x22,
+ Name = 0x23,
+ Ref = 0x24,
+ Area = 0x25,
+ MemArea = 0x26,
+ MemErr = 0x27,
+ MemNoMem = 0x28,
+ MemFunc = 0x29,
+ RefErr = 0x2a,
+ AreaErr = 0x2b,
+ RefN = 0x2c,
+ AreaN = 0x2d,
+ MemAreaN = 0x2e,
+ MemNoMemN = 0x2f,
+ NameX = 0x39,
+ Ref3d = 0x3a,
+ Area3d = 0x3b,
+ RefErr3d = 0x3c,
+ AreaErr3d = 0x3d
+ };
+
+ FormulaToken();
+ FormulaToken( unsigned id );
+ FormulaToken( const FormulaToken& );
+ ~FormulaToken();
+
+ // token id, excluding token class
+ unsigned id() const;
+ const char* idAsString() const;
+
+ // Excel version
+ unsigned version() const;
+ void setVersion( unsigned version ); // Excel version
+
+ // size of data, EXCLUDING the byte for token id
+ unsigned size() const;
+ void setData( unsigned size, const unsigned char* data );
+
+ // only when id returns ErrorCode, Bool, Integer, Float, or String
+ Value value() const;
+
+ // only when id is Function or FunctionVar
+ unsigned functionIndex() const;
+ const char* functionName() const; // for non external function
+ unsigned functionParams() const;
+
+ // only when id is Ref or Ref3d
+ UString ref( unsigned row, unsigned col ) const;
+
+ // only when id is Area or Area3d
+ UString area( unsigned row, unsigned col ) const;
+
+ // only when id is Ref3d or Area3d
+ unsigned externSheetRef() const;
+
+ // only when id is Attr
+ unsigned attr() const;
+
+ // only when id is NameX
+ unsigned nameIndex() const;
+
+ // only when id is Matrix
+ unsigned refRow() const;
+ unsigned refColumn() const;
+
+private:
+ class Private;
+ Private *d;
+};
+
+typedef std::vector<FormulaToken> FormulaTokens;
+
+std::ostream& operator<<( std::ostream& s, FormulaToken token );
+
+/**
+ Class Record represents a base class for all other type record,
+ hence do not use this class in real life.
+
+ */
+class Record
+{
+public:
+
+ /**
+ Static ID of the record. Subclasses should override this value
+ with the id of the record they handle.
+ */
+ static const unsigned int id;
+
+ virtual unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ Creates a new generic record.
+ */
+ Record();
+
+ /**
+ Destroys the record.
+ */
+ virtual ~Record();
+
+ /**
+ * Record factory, create a new record of specified type.
+ */
+ static Record* create( unsigned type );
+
+ void setVersion( unsigned v ){ ver = v; };
+
+ unsigned version(){ return ver; };
+
+ /**
+ Sets the data for this record.
+ */
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ /**
+ Sets the position of the record in the OLE stream. Somehow this is
+ required to process BoundSheet and BOF(Worksheet) properly.
+ */
+ void setPosition( unsigned pos );
+
+ /**
+ Gets the position of this record in the OLE stream.
+ */
+ unsigned position() const;
+
+ /**
+ Returns the name of the record. For debugging only.
+ */
+ virtual const char* name(){ return "Unknown"; }
+
+ /**
+ Dumps record information to output stream. For debugging only.
+ */
+ virtual void dump( std::ostream& out ) const;
+
+protected:
+
+ // position of this record in the OLE stream
+ unsigned stream_position;
+
+ // in which version does this record denote ?
+ unsigned ver;
+
+private:
+ // no copy or assign
+ Record( const Record& );
+ Record& operator=( const Record& );
+
+};
+
+/**
+ Class CellInfo represents a base class for records which provide information
+ about cells. Some important records like BlankRecord, LabelRecord, and others
+ inherit this class.
+ */
+class CellInfo
+{
+public:
+
+ /**
+ * Creates a new cell information.
+ */
+ CellInfo();
+
+ /**
+ * Destroys the cell information.
+ */
+ virtual ~CellInfo();
+
+ /**
+ * Returns the row associated with the cell information. It is zero based,
+ * so the first row is 0.
+ *
+ * \sa setRow, column
+ */
+ virtual unsigned row() const;
+
+ /**
+ * Returns the column associated with the cell information. It is zero based,
+ * so the first column is 0.
+ *
+ * \sa setColumn, row
+ */
+ virtual unsigned column() const;
+
+ /**
+ * Returns the XF index for formatting of the cell.
+ *
+ * \sa setXfIndex
+ */
+ virtual unsigned xfIndex() const;
+
+ /**
+ * Sets the row associated with the cell information. It is zero based,
+ * so the first row is 0.
+ *
+ * \sa setColumn, row
+ */
+ virtual void setRow( unsigned r );
+
+ /**
+ * Sets the column associated with the cell information. It is zero based,
+ * so the first column is 0.
+ *
+ * \sa setRow, column
+ */
+ virtual void setColumn( unsigned c );
+
+ /**
+ * Sets the XF index for formatting of the cell.
+ *
+ * \sa xfIndex
+ */
+ virtual void setXfIndex( unsigned i );
+
+private:
+ // no copy or assign
+ CellInfo( const CellInfo& );
+ CellInfo& operator=( const CellInfo& );
+
+ class Private;
+ Private* info;
+};
+
+/**
+ Class CellInfo represents a base class for records which provide information
+ about a span of columns. The information, like formatting index, should
+ apply to columns (as specified) from firstColumn and lastColumn.
+ */
+class ColumnSpanInfo
+{
+public:
+
+ /**
+ * Creates a new column span information.
+ */
+ ColumnSpanInfo();
+
+ /**
+ * Destroys the column span information.
+ */
+ virtual ~ColumnSpanInfo();
+
+ /**
+ * Returns the first column associated with the span information.
+ * Column index is zero based, so the first column is 0.
+ *
+ * \sa lastColumn, setFirstColumn
+ */
+ virtual unsigned firstColumn() const;
+
+ /**
+ * Returns the last column associated with the span information.
+ * Column index is zero based, so the first column is 0.
+ *
+ * \sa firstColumn, setLastColumn
+ */
+ virtual unsigned lastColumn() const;
+
+ /**
+ * Sets the first column associated with the span information.
+ * Column index is zero based, so the first column is 0.
+ *
+ * \sa setLastColumn, firstColumn
+ */
+ virtual void setFirstColumn( unsigned c );
+
+ /**
+ * Sets the last column associated with the span information.
+ * Column index is zero based, so the first column is 0.
+ *
+ * \sa setFirstColumn, lastColumn
+ */
+ virtual void setLastColumn( unsigned c );
+
+private:
+ // no copy or assign
+ ColumnSpanInfo( const ColumnSpanInfo& );
+ ColumnSpanInfo& operator=( const ColumnSpanInfo& );
+
+ class Private;
+ Private* spaninfo;
+};
+
+/**
+ \brief Backup upon save.
+
+ Class BackupRecord represents Backup record, which determines whether
+ Microsoft Excel makes a backup of the file while saving.
+ */
+class BackupRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ /**
+ * Creates a new Backup record.
+ */
+ BackupRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~BackupRecord();
+
+ unsigned int rtti(){
+ return this->id;
+ }
+ /**
+ * Returns true if a backup is made when saving the file.
+ *
+ * \sa setBackup
+ */
+ bool backup() const;
+
+ /**
+ * If r is true, a backup will be made when saving the file.
+ *
+ * \sa backup
+ */
+ void setBackup( bool r );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "BACKUP"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ BackupRecord( const BackupRecord& );
+ BackupRecord& operator=( const BackupRecord& );
+
+ class Private;
+ Private* d;
+};
+
+
+/**
+ \brief Beginning of file/set of records.
+
+ Class BOFRecord represents BOF (Beginning of File) record, which
+ is used to mark beginning of a set of records (following the BOF record).
+ For each BOF record, there should also be one corresponding EOF record.
+
+ Note that the name "BOF" is rather misleading. This is because of
+ historical reason only.
+
+ \sa EOFRecord
+
+ */
+class BOFRecord : public Record
+{
+public:
+
+ /**
+ Static ID of the BOF record.
+ */
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ Supported BOF type.
+ */
+ enum { UnknownType = 0, Workbook, Worksheet, Chart, VBModule, MacroSheet, Workspace };
+
+ /**
+ * Creates a new BOF record.
+ */
+ BOFRecord();
+
+ /**
+ Destroys the record.
+ */
+ virtual ~BOFRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ /**
+ Returns the version, like Excel95, Excel97, and so on.
+
+ Note that it is possible to use expression like 'version() >= Excel97'
+ but always do that carefully.
+ */
+ unsigned version() const;
+
+ /**
+ Returns the version as string, something like "Excel97".
+ */
+ const char* versionAsString() const;
+
+ /**
+ Returns type of the BOF record, like Workbook, Chart, and so on.
+ */
+ unsigned type() const;
+
+ /**
+ Returns BOF type as string, something like "Worksheet".
+ */
+ const char* typeAsString() const;
+
+ virtual const char* name(){ return "BOF"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ BOFRecord( const BOFRecord& );
+ BOFRecord& operator=( const BOFRecord& );
+
+ class Private;
+ Private *d;
+};
+
+/**
+ \brief Blank cell.
+
+ Class BlankRecord represents a blank cell. It contains information
+ about cell address and formatting.
+ */
+class BlankRecord : public Record, public CellInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Blank record.
+ */
+ BlankRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "BLANK"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ BlankRecord( const BlankRecord& );
+ BlankRecord& operator=( const BlankRecord& );
+};
+
+/**
+ \brief Boolean value or error code.
+
+ Class BOFRecord represents BoolErr record, which
+ is used to store boolean value or error code of a cell.
+ */
+class BoolErrRecord : public Record, public CellInfo
+{
+public:
+
+ /**
+ Static ID of the BoolErr record.
+ */
+ static const unsigned int id;
+
+ unsigned int rtti(){ return this->id; }
+
+ /**
+ * Creates a new BoolErr record.
+ */
+ BoolErrRecord();
+
+ /**
+ * Destroys the BoolErr record.
+ */
+ virtual ~BoolErrRecord();
+
+ /**
+ * Returns value of the cell, could be either boolean or error.
+ */
+ Value value() const;
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "BOOLERR"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ BoolErrRecord( const BoolErrRecord& );
+ BoolErrRecord& operator=( const BoolErrRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ \brief Bottom margin.
+
+ Class BottomMarginRecord holds information about bottom margin
+ (in inches).
+ */
+class BottomMarginRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+ /**
+ * Creates a new BottomMargin record.
+ */
+ BottomMarginRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~BottomMarginRecord();
+
+ /**
+ * Gets the bottom margin (in inches).
+ */
+ double bottomMargin() const;
+
+ /**
+ * Sets the new bottom margin (in inches).
+ */
+ void setBottomMargin( double m );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "BOTTOMMARGIN"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ BottomMarginRecord( const BottomMarginRecord& );
+ BottomMarginRecord& operator=( const BottomMarginRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ \brief Sheet information.
+
+ Class BoundSheetRecord represents BoundSheet record, which defines a sheet
+ within the workbook. There must be exactly one BoundSheet record for
+ each sheet.
+
+ BoundSheet record stores information about sheet type, sheet name, and
+ the corresponding BOF record.
+
+ \sa BOFRecord
+ */
+
+// TODO support for strong visible
+
+class BoundSheetRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new BoundSheet record.
+ */
+ BoundSheetRecord();
+
+ /**
+ * Destroys the BoundSheet record.
+ */
+ virtual ~BoundSheetRecord();
+
+ /**
+ * Type of the sheet.
+ */
+ enum { Worksheet=0, Chart=2, VBModule=6 };
+
+ /**
+ * Sets the type of the BoundSheet. Possible values are
+ * BoundSheet::Worksheet, BoundSheet::Chart and BoundSheet::VBModule.
+ */
+ void setType( unsigned type );
+
+ /**
+ * Returns the type of the BoundSheet. Possible values are
+ * BoundSheet::Worksheet, BoundSheet::Chart and BoundSheet::VBModule.
+ */
+ unsigned type() const;
+
+ /**
+ * Returns the type of the BoundSheet as string. For example, if
+ * type of BoundSheet is BoundSheet::Chart, then this function returns
+ * "Chart".
+ */
+ const char* typeAsString() const;
+
+ /**
+ * Sets the visibility of the sheet.
+ */
+ void setVisible( bool visible );
+
+ /**
+ * Returns true if the sheet is visible.
+ */
+ bool visible() const;
+
+ /**
+ * Sets the name of the sheet.
+ */
+ void setSheetName( const UString& name );
+
+ /**
+ * Returns the name of the sheet.
+ */
+ UString sheetName() const;
+
+ /**
+ * Sets the position of the BOF record associated with this BoundSheet.
+ */
+ void setBofPosition( unsigned pos );
+
+ /**
+ * Returns the position of the BOF record associated with this BoundSheet.
+ */
+ unsigned bofPosition() const;
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "BOUNDSHEET"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ BoundSheetRecord( const BoundSheetRecord& );
+ BoundSheetRecord& operator=( const BoundSheetRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ \brief Automatic recalculation mode.
+
+ Class CalcModeRecord represents CalcMode record, which specifies whether
+ to (re)calculate formulas manually or automatically.
+ */
+class CalcModeRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new CalcMode record.
+ */
+ CalcModeRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~CalcModeRecord();
+
+ /**
+ * Returns true if formulas calculation is performed automatically.
+ *
+ * \sa setAutoCalc
+ */
+ bool autoCalc() const;
+
+ /**
+ * If r is true, formulas calculation will be performed automatically.
+ *
+ * \sa autoCalc
+ */
+ void setAutoCalc( bool r );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "CALCMODE"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ CalcModeRecord( const CalcModeRecord& );
+ CalcModeRecord& operator=( const CalcModeRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ \brief Columns width and format.
+
+ Class ColInfoRecord represents ColInfo record, which provides information
+ (such as column width and formatting) for a span of columns.
+ */
+class ColInfoRecord : public Record, public ColumnSpanInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new ColInfo record.
+ */
+ ColInfoRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~ColInfoRecord();
+
+ /**
+ * Returns the XF index for the formatting of the column(s).
+ *
+ * \sa setXfIndex
+ */
+ unsigned xfIndex() const;
+
+ /**
+ * Sets the XF index for the formatting of the column(s).
+ *
+ * \sa xfIndex
+ */
+ void setXfIndex( unsigned i );
+
+ /**
+ * Returns the width of the column(s), specified in 1/256 of
+ * a character width. The exact width (in pt or inch) could only be
+ * calculated given the base character width for the column format.
+ *
+ * \sa setWidth
+ */
+ unsigned width() const;
+
+ /**
+ * Sets the width of the column(s), specified in 1/256 of
+ * a character width. The exact width (in pt or inch) could only be
+ * calculated given the base character width for the column format.
+ *
+ * \sa width
+ */
+ void setWidth( unsigned w );
+
+ /**
+ * Returns true if the columns should be hidden, i.e not visible.
+ *
+ * \sa setHidden
+ */
+ bool hidden() const;
+
+ /**
+ * Sets whether columns should be hidden or visible.
+ *
+ * \sa hidden
+ */
+ void setHidden( bool h );
+
+ /**
+ * Returns true if the columns should be collapsed.
+ *
+ * \sa setCollapsed
+ */
+ bool collapsed() const;
+
+ /**
+ * Sets whether columns should be collapsed or not.
+ *
+ * \sa collapsed
+ */
+ void setCollapsed( bool c );
+
+ /**
+ * Returns the outline level of the columns. If it is 0, then
+ * the columns are not outlined.
+ *
+ * \sa setOutlineLevel
+ */
+ unsigned outlineLevel() const;
+
+ /**
+ * Sets the outline level of the columns. If it is 0, then
+ * the columns are not outlined.
+ *
+ * \sa outlineLevel
+ */
+ void setOutlineLevel( unsigned l );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "COLINFO"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ ColInfoRecord( const ColInfoRecord& );
+ ColInfoRecord& operator=( const ColInfoRecord& );
+
+ class Private;
+ Private *d;
+};
+
+/**
+ \brief Date reference.
+
+ Class DateModeRecord represents DateMode record, which specifies
+ reference date for displaying date value of given serial number.
+ If base1904 is true, the reference date is 1st of January, 1904 (in which
+ serial number 1 means 2nd of January, 1904). Otherwise, the reference
+ date is 31st of December, 1899 (in which serial number 1 means
+ 1st of January, 1900).
+ */
+class DateModeRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new DateMode record.
+ */
+ DateModeRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~DateModeRecord();
+
+ /**
+ * Returns true if the reference date is 1st of January, 1904 or false
+ * if the reference date is 31st of December, 1899.
+ *
+ * \sa setBase1904
+ */
+ bool base1904() const;
+
+ /**
+ * If r is true, sets the reference date to 1st of January, 1904. Else,
+ * sets the reference date to 31st of December, 1899.
+ *
+ * \sa base1904
+ */
+ void setBase1904( bool r );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "DATEMODE"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ DateModeRecord( const DateModeRecord& );
+ DateModeRecord& operator=( const DateModeRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ \brief Range of used area.
+
+ Class DimensionRecord represents Dimension record, which contains the
+ range address of the used area in the current sheet.
+ */
+class DimensionRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Dimension record.
+ */
+ DimensionRecord();
+
+ /**
+ * Destroys the record.
+ */
+ ~DimensionRecord();
+
+ /**
+ * Returns index to the first used row.
+ *
+ * \sa setFirstRow, lastRow
+ */
+ unsigned firstRow() const;
+
+ /**
+ * Sets index to the first used row.
+ *
+ * \sa firstRow, setLastRow
+ */
+ void setFirstRow( unsigned r );
+
+ /**
+ * Returns index to the last used row.
+ *
+ * \sa setLastRow, firstRow
+ */
+ unsigned lastRow() const;
+
+ /**
+ * Sets index to the last used row.
+ *
+ * \sa lastRow, setFirstRow
+ */
+ void setLastRow( unsigned r );
+
+ /**
+ * Returns index to the first used column.
+ *
+ * \sa setFirstColumn, lastColumn
+ */
+ unsigned firstColumn() const;
+
+ /**
+ * Sets index to the first used column.
+ *
+ * \sa firstColumn, setLastColumn
+ */
+ void setFirstColumn( unsigned r );
+
+ /**
+ * Returns index to the last used column.
+ *
+ * \sa setLastColumn, firstColumn
+ */
+ unsigned lastColumn() const;
+
+ /**
+ * Sets index to the last used column.
+ *
+ * \sa lastColumn, setFirstColumn
+ */
+ void setLastColumn( unsigned r );
+
+ virtual const char* name(){ return "DIMENSION"; }
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ DimensionRecord( const DimensionRecord& );
+ DimensionRecord& operator=( const DimensionRecord& );
+
+ class Private;
+ Private *d;
+};
+
+class ExternNameRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ ExternNameRecord();
+
+ ~ExternNameRecord();
+
+ // one-based sheet index
+ // if 0 means AddIn function
+ unsigned sheetIndex() const;
+
+ void setSheetIndex( unsigned sheetIndex );
+
+ UString externName() const;
+
+ void setExternName( const UString& name );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+
+
+ virtual const char* name(){ return "EXTERNNAME"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ ExternNameRecord( const ExternNameRecord& );
+ ExternNameRecord& operator=( const ExternNameRecord& );
+
+ class Private;
+ Private *d;
+};
+
+class ExternSheetRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ ExternSheetRecord();
+
+ ~ExternSheetRecord();
+
+ unsigned count() const;
+
+ unsigned refIndex(unsigned i) const;
+ unsigned firstSheet(unsigned i) const;
+ unsigned lastSheet(unsigned i) const;
+
+ UString refName() const;
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "EXTERNSHEET"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ ExternSheetRecord( const ExternNameRecord& );
+ ExternSheetRecord& operator=( const ExternNameRecord& );
+
+ class Private;
+ Private *d;
+};
+
+
+/**
+ \brief End of record set.
+
+ Class EOFRecord represents EOF record, which marks the end of records
+ for a specific object. EOF record should be always in pair with BOF Record.
+
+ \sa BOFRecord
+
+ */
+class EOFRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new EOF record.
+ */
+ EOFRecord();
+
+ /**
+ * Destroy the record.
+ */
+ virtual ~EOFRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "EOF"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ EOFRecord( const EOFRecord& );
+ EOFRecord& operator=( const EOFRecord& );
+};
+
+class FilepassRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new FILEPASS record.
+ */
+ FilepassRecord();
+
+ /**
+ * Destroy the record.
+ */
+ virtual ~FilepassRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "FILEPASS"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ FilepassRecord( const FilepassRecord& );
+ FilepassRecord& operator=( const FilepassRecord& );
+};
+
+/**
+ \brief Font information.
+
+ Class FontRecord represents Font record, which has the information
+ about specific font used in the document. Several Font records creates
+ a font table, whose index will be referred in XFormat records.
+
+ A note about weirdness: font index #4 is never used. Hence, the first Font
+ record will be index #0, the second is #1, the third is #2, the fourth is
+ #3, but the fourth will be index #5.
+
+ \sa XFRecord
+
+ */
+class FontRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Font record.
+ */
+ FontRecord();
+
+ /**
+ * Creates a copy of another Font record.
+ */
+ FontRecord( const FontRecord& fr );
+
+ /**
+ * Assigns from another Font record.
+ */
+ FontRecord& operator=( const FontRecord& fr );
+
+ /**
+ * Destroy the record.
+ */
+ virtual ~FontRecord();
+
+ enum {
+ Normal = 0,
+ Superscript = 1,
+ Subscript = 2 };
+
+ enum {
+ None = 0,
+ Single = 1,
+ Double = 2,
+ SingleAccounting = 0x21,
+ DoubleAccounting = 0x22 };
+
+ unsigned height() const;
+ void setHeight( unsigned h );
+
+ /**
+ * Returns the name of font, e.g "Arial".
+ *
+ * \sa setFontName
+ */
+ UString fontName() const;
+
+ /**
+ * Sets the name of the font.
+ *
+ * \sa fontName
+ */
+ void setFontName( const UString& fn );
+
+ // FIXME what is this font family ? index ?
+ unsigned fontFamily() const;
+ void setFontFamily( unsigned f );
+
+ // FIXME and character set index ?
+ unsigned characterSet() const;
+ void setCharacterSet( unsigned s );
+
+ /**
+ * Returns index of the color of the font.
+ *
+ * \sa setColorIndex
+ */
+ unsigned colorIndex() const;
+
+ /**
+ * Sets the index of the color of the font.
+ *
+ * \sa colorIndex
+ */
+ void setColorIndex( unsigned c );
+
+ /**
+ * Returns the boldness of the font. Standard values are 400 for normal
+ * and 700 for bold.
+ *
+ * \sa setBoldness
+ */
+ unsigned boldness() const;
+
+ /**
+ * Sets the boldness of the font. Standard values are 400 for normal
+ * and 700 for bold.
+ *
+ * \sa boldness
+ */
+ void setBoldness( unsigned b );
+
+ /**
+ * Returns true if italic has been set.
+ *
+ * \sa setItalic
+ */
+ bool italic() const;
+
+ /**
+ * If i is true, italic is set on; otherwise italic is set off.
+ *
+ * \sa italic
+ */
+ void setItalic( bool i );
+
+ /**
+ * Returns true if strikeout has been set.
+ *
+ * \sa setStrikeout
+ */
+ bool strikeout() const;
+
+ /**
+ * If s is true, strikeout is set on; otherwise strikeout is set off.
+ *
+ * \sa strikeout
+ */
+ void setStrikeout( bool s );
+
+ /**
+ * Returns Font::Superscript if superscript is set, or Font::Subscript
+ * if subscript is set, or Font::Normal in other case.
+ *
+ * \sa setEscapement
+ */
+ unsigned escapement() const;
+
+ /**
+ * Sets the superscript or subscript. If s is Font::Superscript, then
+ * superscript is set. If s is Font::Subscript, then subscript is set.
+ *
+ * \sa escapement
+ */
+ void setEscapement( unsigned s );
+
+ /**
+ * Returns the underline style of the font. Possible values are
+ * Font::None, Font::Single, Font::Double, Font::SingleAccounting and
+ * Font::DoubleAccounting.
+ *
+ * \sa setUnderline
+ */
+ unsigned underline() const;
+
+ /**
+ * Sets the underline style of the font. Possible values are
+ * Font::None, Font::Single, Font::Double, Font::SingleAccounting and
+ * Font::DoubleAccounting.
+ *
+ * \sa underline
+ */
+ void setUnderline( unsigned u );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "FONT"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ class Private;
+ Private *d;
+};
+
+/**
+ \brief Sheet footer.
+
+ Class FooterRecord holds information about sheet footer.
+
+ */
+class FooterRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Footer record.
+ */
+ FooterRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~FooterRecord();
+
+ /**
+ * Gets the footer.
+ */
+ UString footer() const;
+
+ /**
+ * Sets the footer.
+ */
+ void setFooter( const UString& f );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "FOOTER"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ FooterRecord( const FooterRecord& );
+ FooterRecord& operator=( const FooterRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ \brief Number formatting string.
+
+ Class FormatRecord contains information about a number format.
+ All Format records occur together in a sequential list.
+ An XFRecord might refer to the specific Format record using
+ an index to that list.
+
+ \sa XFRecord
+
+ */
+class FormatRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Format record.
+ */
+ FormatRecord();
+
+ /**
+ * Destroys the Format record.
+ */
+ ~FormatRecord();
+
+ /**
+ * Creates a copy of Format record.
+ */
+ FormatRecord( const FormatRecord& fr );
+
+ /**
+ * Assigns from another Format record.
+ */
+ FormatRecord& operator=( const FormatRecord& fr );
+
+ /**
+ * Returns the index of the format. Each format specified by Format record
+ * has unique index which will be referred by XF Record.
+ *
+ * \sa setIndex
+ */
+ unsigned index() const;
+
+ /**
+ * Sets the index of the format. Each format specified by Format record
+ * has unique index which will be referred by XF Record.
+ *
+ * \sa index
+ */
+ void setIndex( unsigned i );
+
+ /**
+ * Returns the formatting string of the format, e.g "0.00" for 2 decimal
+ * places number formatting.
+ *
+ * \sa setFormatString
+ */
+ UString formatString() const;
+
+ /**
+ * Sets the formatting string of the format.
+ *
+ * \sa formatString
+ */
+ void setFormatString( const UString& fs );
+
+ virtual const char* name(){ return "FORMAT"; }
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ class Private;
+ Private *d;
+};
+
+/**
+ \brief Formula.
+
+ Class FormulaRecord holds Formula record.
+
+ */
+class FormulaRecord : public Record, public CellInfo
+{
+public:
+
+ static const unsigned int id;
+ static const unsigned int idOld; // for Pocket Excel support
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new formula record.
+ */
+ FormulaRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~FormulaRecord();
+
+ /**
+ * Gets the result of the formula.
+ */
+ Value result() const;
+
+ /**
+ * Sets the result of the formula.
+ */
+ void setResult( const Value& v );
+
+ FormulaTokens tokens() const;
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "FORMULA"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ FormulaRecord( const FormulaRecord& );
+ FormulaRecord& operator=( const FormulaRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ \brief Sheet header.
+
+ Class HeaderRecord holds information about sheet header.
+ */
+
+class HeaderRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Header record.
+ */
+ HeaderRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~HeaderRecord();
+
+ /**
+ * Gets the header.
+ */
+ UString header() const;
+
+ /**
+ * Sets the header.
+ */
+ void setHeader( const UString& h );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "HEADER"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ HeaderRecord( const HeaderRecord& );
+ HeaderRecord& operator=( const HeaderRecord& );
+
+ class Private;
+ Private* d;
+};
+
+
+/**
+ Class LabelRecord represents a cell that contains a string.
+
+ In Excel 97 and later version, it is replaced by LabelSSTRecord. However,
+ Excel 97 can still load LabelRecord.
+
+ \sa LabelSSTRecord
+
+ */
+class LabelRecord : public Record, public CellInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Label record.
+ */
+ LabelRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~LabelRecord();
+
+ /**
+ * Returns the label string.
+ */
+ UString label() const;
+
+ /**
+ * Sets the label string.
+ */
+ void setLabel( const UString& l );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "LABEL"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ LabelRecord( const LabelRecord& );
+ LabelRecord& operator=( const LabelRecord& );
+
+ class Private;
+ Private *d;
+};
+
+/**
+ Class LabelSSTRecord represents a cell that contains a string. The actual
+ string is store in a global SST (Shared String Table), see SSTRecord for
+ details. This record only provide an index, which should be used to get
+ the string in the corresponding SST.
+
+ \sa SSTRecord
+
+ */
+class LabelSSTRecord : public Record, public CellInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new LabelSST record.
+ */
+ LabelSSTRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~LabelSSTRecord();
+
+ /**
+ * Returns the SST index. This is the index to the global SST which hold
+ * every label strings used in SST record.
+ */
+ unsigned sstIndex() const;
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "LABELSST"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ LabelSSTRecord( const LabelSSTRecord& );
+ LabelSSTRecord& operator=( const LabelSSTRecord& );
+
+ class Private;
+ Private *d;
+};
+
+/**
+ Class LeftMarginRecord holds information about left margin.
+
+ */
+class LeftMarginRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new LeftMargin record.
+ */
+ LeftMarginRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~LeftMarginRecord();
+
+ /**
+ * Gets the left margin (in inches).
+ */
+ double leftMargin() const;
+
+ /**
+ * Sets the new left margin (in inches).
+ */
+ void setLeftMargin( double m );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "LEFTMARGIN"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ LeftMarginRecord( const LeftMarginRecord& );
+ LeftMarginRecord& operator=( const LeftMarginRecord& );
+
+ class Private;
+ Private* d;
+};
+
+
+/**
+ Class MergedCellsRecord represents MergedCells record, which contains
+ a list of all merged cells in the current sheets. Each entry in this list
+ define the range of cells that should be merged, namely firstRow, lastRow,
+ firstColumn and lastColumn.
+ */
+
+class MergedCellsRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new MergedCells record.
+ */
+ MergedCellsRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~MergedCellsRecord();
+
+ /**
+ * Returns the total number of merged cells in the list.
+ */
+ unsigned count() const;
+
+ /**
+ * Returns the index to first row in the i-th position in the list.
+ */
+ unsigned firstRow( unsigned i ) const;
+
+ /**
+ * Returns the index to last row in the i-th position in the list.
+ */
+ unsigned lastRow( unsigned i ) const;
+
+ /**
+ * Returns the index to first column in the i-th position in the list.
+ */
+ unsigned firstColumn( unsigned i ) const;
+
+ /**
+ * Returns the index to last column in the i-th position in the list.
+ */
+ unsigned lastColumn( unsigned i ) const;
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "MERGEDCELLS"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ MergedCellsRecord( const MergedCellsRecord& );
+ MergedCellsRecord& operator=( const MergedCellsRecord& );
+
+ class Private;
+ Private *d;
+};
+
+/**
+ Class MulBlankRecord represents a cell range containing blank cells.
+ All cells are located in the same row.
+
+ \sa BlankRecord
+ */
+
+class MulBlankRecord : public Record, public CellInfo, public ColumnSpanInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new MulBlank record.
+ */
+ MulBlankRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~MulBlankRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ /**
+ * Returns XF index of ith column.
+ */
+ unsigned xfIndex( unsigned i ) const;
+
+ virtual const char* name(){ return "MULBLANK"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ MulBlankRecord( const MulBlankRecord& );
+ MulBlankRecord& operator=( const MulBlankRecord& );
+
+ class Private;
+ Private *d;
+
+ // from CellInfo, we don't need it
+ // mark as private so nobody can call them
+ virtual unsigned column() const { return CellInfo::column(); }
+ virtual unsigned xfIndex() const { return CellInfo::xfIndex(); }
+};
+
+/**
+ Class MulRKRecord represents a cell range containing RK value cells.
+ These cells are located in the same row.
+
+ \sa RKRecord
+ */
+
+class MulRKRecord : public Record, public CellInfo, public ColumnSpanInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new MulRK record.
+ */
+ MulRKRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~MulRKRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ /**
+ Returns XF index of ith column.
+ */
+ unsigned xfIndex( unsigned i ) const;
+
+ /**
+ * Returns true if the record holds an integer value.
+ *
+ * \sa asInteger
+ */
+ bool isInteger( unsigned i ) const;
+
+ /**
+ * Returns the integer value specified by the record. It is only valid
+ * when isInteger returns true.
+ *
+ * \sa isInteger, asFloat
+ */
+ int asInteger( unsigned i ) const;
+
+ /**
+ * Returns the floating-point value specified by the record. It is only valid
+ * when isInteger returns false.
+ *
+ * \sa asInteger
+ */
+ double asFloat( unsigned i ) const;
+
+ unsigned encodedRK( unsigned i ) const;
+
+ virtual const char* name(){ return "MULRK"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ MulRKRecord( const MulRKRecord& );
+ MulRKRecord& operator=( const MulRKRecord& );
+
+ class Private;
+ Private *d;
+
+ // from CellInfo, we don't need it
+ // mark as private so nobody can call them
+ virtual unsigned column() const { return CellInfo::column(); }
+ virtual unsigned xfIndex() const { return CellInfo::xfIndex(); }
+};
+
+
+class NameRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ NameRecord();
+
+ ~NameRecord();
+
+ UString definedName() const;
+
+ void setDefinedName( const UString& name );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "NAME"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ NameRecord( const NameRecord& );
+ NameRecord& operator=( const NameRecord& );
+
+ class Private;
+ Private *d;
+};
+
+
+/**
+ Class NumberRecord represents a cell that contains a floating point value.
+
+ */
+class NumberRecord : public Record, public CellInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Number record.
+ */
+ NumberRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~NumberRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ /**
+ * Returns the floating-point value specified by the record.
+ *
+ * \sa setNumber
+ */
+ double number() const;
+
+ /**
+ * Sets the floating-point value specified by the record.
+ *
+ * \sa number
+ */
+ void setNumber( double f );
+
+ virtual const char* name(){ return "NUMBER"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ NumberRecord( const NumberRecord& );
+ NumberRecord& operator=( const NumberRecord& );
+
+ class Private;
+ Private *d;
+};
+
+/**
+ Class PaletteRecord lists colors.
+
+ */
+class PaletteRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Palette record.
+ */
+ PaletteRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~PaletteRecord();
+
+ /**
+ * Gets the n-th color.
+ */
+ Color color( unsigned i ) const;
+
+ /**
+ * Returns the number of colors in the palette.
+ */
+ unsigned count() const;
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "PALETTE"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ PaletteRecord( const PaletteRecord& );
+ PaletteRecord& operator=( const PaletteRecord& );
+
+ class Private;
+ Private* d;
+};
+
+
+
+/**
+ Class RightMarginRecord holds information about right margin.
+
+ */
+class RightMarginRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new RightMargin record.
+ */
+ RightMarginRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~RightMarginRecord();
+
+ /**
+ * Gets the right margin (in inches).
+ */
+ double rightMargin() const;
+
+ /**
+ * Sets the new right margin (in inches).
+ */
+ void setRightMargin( double m );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "RIGHTMARGIN"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ RightMarginRecord( const RightMarginRecord& );
+ RightMarginRecord& operator=( const RightMarginRecord& );
+
+ class Private;
+ Private* d;
+};
+
+
+
+/**
+ Class RKRecord represents a cell that contains an RK value,
+ i.e encoded integer or floating-point value.
+
+ */
+class RKRecord : public Record, public CellInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new RK record.
+ */
+ RKRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~RKRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ /**
+ * Returns true if the record holds an integer value.
+ *
+ * \sa asInteger, isFloat
+ */
+ bool isInteger() const;
+
+ /**
+ * Returns true if the record holds a floating-point value.
+ *
+ * \sa asFloat, isInteger
+ */
+ bool isFloat() const;
+
+ /**
+ * Returns the integer value specified by the record. It is only valid
+ * when isInteger returns true.
+ *
+ * \sa isInteger, asFloat
+ */
+ int asInteger() const;
+
+ /**
+ * Returns the floating-point value specified by the record. It is only valid
+ * when isFloat returns true.
+ *
+ * \sa isFloat, asInteger
+ */
+ double asFloat() const;
+
+ /**
+ * Sets the integer value to be specified by the record.
+ *
+ * \sa setFloat
+ */
+ void setInteger( int i );
+
+ /**
+ * Sets the floating-point value to be specified by the record.
+ *
+ * \sa setFloat
+ */
+ void setFloat( double f );
+
+ unsigned encodedRK() const;
+
+ virtual const char* name(){ return "RK"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ RKRecord( const RKRecord& );
+ RKRecord& operator=( const RKRecord& );
+
+ class Private;
+ Private *d;
+};
+
+/**
+ Class RowRecord represents Row record, which provides information
+ (such as row height and formatting) for a span of columns.
+ */
+class RowRecord : public Record, public ColumnSpanInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Row record.
+ */
+ RowRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~RowRecord();
+
+ /**
+ * Returns the index of the row.
+ *
+ * \sa setRow
+ */
+ unsigned row() const;
+
+ /**
+ * Sets the index of the row.
+ *
+ * \sa row
+ */
+ void setRow( unsigned r );
+
+ /**
+ * Returns the XF index for the formatting of the cells.
+ *
+ * \sa setXfIndex
+ */
+ unsigned xfIndex() const;
+
+ /**
+ * Sets the XF index for the formatting of the cells.
+ *
+ * \sa xfIndex
+ */
+ void setXfIndex( unsigned i );
+
+ /**
+ * Returns the height of the row, specified in twips (1/20 pt).
+ *
+ * \sa setHeight
+ */
+ unsigned height() const;
+
+ /**
+ * Sets the height of the row, specified in twips (1/20 pt).
+ *
+ * \sa height
+ */
+ void setHeight( unsigned h );
+
+ /**
+ * Returns true if the row should be hidden, i.e not visible.
+ *
+ * \sa setHidden
+ */
+ bool hidden() const;
+
+ /**
+ * Sets whether row should be hidden or visible.
+ *
+ * \sa hidden
+ */
+ void setHidden( bool h );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "ROW"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ RowRecord( const RowRecord& );
+ RowRecord& operator=( const RowRecord& );
+
+ class Private;
+ Private *d;
+};
+
+
+/**
+ Class RStringRecord represents a cell that contains rich-text string.
+
+ In Excel 97 and later version, it is replaced by LabelSSTRecord. However,
+ Excel 97 is still able to load RStringRecord.
+
+ \sa LabelRecord
+ \sa LabelSSTRecord
+
+ */
+class RStringRecord : public Record, public CellInfo
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Label record.
+ */
+ RStringRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~RStringRecord();
+
+ /**
+ * Returns the label string.
+ *
+ * \sa setLabel
+ */
+ UString label() const;
+
+ /**
+ * Sets the label string.
+ *
+ * \sa label
+ */
+ void setLabel( const UString& l );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "RSTRING"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ RStringRecord( const RStringRecord& );
+ RStringRecord& operator=( const RStringRecord& );
+
+ class Private;
+ Private *d;
+};
+
+
+/**
+ Class SSTRecord represents SST record, which holds the shared string
+ table of the workbook.
+
+ \sa LabelSSTRecord
+
+ */
+class SSTRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new SST record.
+ */
+ SSTRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~SSTRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ /**
+ Returns the number of available string in this string table.
+ */
+ unsigned count() const;
+
+ /**
+ Returns the string at specified index.
+ Note that index must be less than count().
+ If index is not valid, this will return UString::null.
+ */
+ UString stringAt( unsigned index ) const;
+
+ virtual const char* name(){ return "SST"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ SSTRecord( const SSTRecord& );
+ SSTRecord& operator=( const SSTRecord& );
+
+ class Private;
+ Private *d;
+};
+
+
+/**
+ Class String represents a string record, which holds the value of
+ calculation if a formula returns a string. This record must appear
+ right after the associated formula record.
+
+ \sa FormulaRecord
+
+ */
+class StringRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){ return this->id; }
+
+ /**
+ * Creates a new string record.
+ */
+ StringRecord();
+
+ /**
+ * Destroys the record.
+ */
+ virtual ~StringRecord();
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ /**
+ Returns the string (in Unicode).
+ */
+ UString ustring() const;
+
+ /**
+ Returns the string as a value.
+ */
+ Value value() const;
+
+ virtual const char* name(){ return "STRING"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ StringRecord( const SSTRecord& );
+ StringRecord& operator=( const SSTRecord& );
+
+ class Private;
+ Private *d;
+};
+
+/**
+ Class SupbookRecord stores references to external workbook.
+
+ */
+class SupbookRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ typedef enum
+ {
+ UnknownRef,
+ ExternalRef,
+ InternalRef,
+ AddInRef,
+ ObjectLink
+ } ReferenceType;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new Supbook record.
+ */
+ SupbookRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~SupbookRecord();
+
+ /**
+ * Returns the type of the reference.
+ */
+ ReferenceType referenceType() const;
+
+ /**
+ * Sets the type of the reference.
+ */
+ void setReferenceType(ReferenceType type);
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "SUPBOOK"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ SupbookRecord( const SupbookRecord& );
+ SupbookRecord& operator=( const SupbookRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ Class TopMarginRecord holds information about top margin.
+
+ */
+class TopMarginRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new TopMargin record.
+ */
+ TopMarginRecord();
+
+ /**
+ * Destroy the record.
+ */
+ ~TopMarginRecord();
+
+ /**
+ * Gets the top margin (in inches).
+ */
+ double topMargin() const;
+
+ /**
+ * Sets the new top margin (in inches).
+ */
+ void setTopMargin( double m );
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual const char* name(){ return "TOPMARGIN"; }
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ // no copy or assign
+ TopMarginRecord( const TopMarginRecord& );
+ TopMarginRecord& operator=( const TopMarginRecord& );
+
+ class Private;
+ Private* d;
+};
+
+/**
+ Class XFRecord holds information of XF (eXtended Format) which specifies
+ many kind of properties of a specific cell. It will be referred
+ by record derived from CellInfo, in the member function xfIndex().
+
+ */
+class XFRecord : public Record
+{
+public:
+
+ static const unsigned int id;
+
+ unsigned int rtti(){
+ return this->id;
+ }
+
+ /**
+ * Creates a new XF record.
+ */
+ XFRecord();
+
+ /**
+ * Creates a copy of XF record.
+ */
+ XFRecord( const XFRecord& xf );
+
+ /**
+ * Assigns from another XF record.
+ */
+ XFRecord& operator=( const XFRecord& xf );
+
+ /**
+ * Destroy the record.
+ */
+ ~XFRecord();
+
+ /**
+ * Gets the index of the font for use in this XFormat. The index
+ * refers to the font table.
+ *
+ * \sa setFontIndex, FontRecord
+ */
+ unsigned fontIndex() const;
+
+ /**
+ * Sets the index of the font for use in this XFormat. The index
+ * refers to the font table.
+ *
+ * \sa fontIndex, FontRecord
+ */
+ void setFontIndex( unsigned fi );
+
+ /**
+ * Gets the index of the number format for use in this XFormat. The index
+ * refers to the format table.
+ *
+ * \sa setFormatIndex, FormatRecord
+ */
+ unsigned formatIndex() const;
+
+ /**
+ * Sets the index of the number format for use in this XFormat. The index
+ * refers to the format table.
+ *
+ * \sa formatIndex, FormatRecord
+ */
+ void setFormatIndex( unsigned fi );
+
+ /**
+ * Returns true if the cells using this format should be locked.
+ *
+ * \sa setLocked
+ */
+ bool locked() const;
+
+ /**
+ * Sets whether the cells using this format should be locked or not.
+ *
+ * \sa locked
+ */
+ void setLocked( bool l );
+
+ /**
+ * Returns true if the formula of the cells using this format
+ * should be hidden from user.
+ *
+ * \sa setFormulaHidden
+ */
+ bool formulaHidden() const;
+
+ /**
+ * Sets whether the formula of the cells using this format
+ * should be hidden or should be visible.
+ *
+ * \sa formulaHidden
+ */
+ void setFormulaHidden( bool f );
+
+ /**
+ * Returns the index of the parent stlye of this format.
+ * This refers to the index of the XFormat table which is constructed
+ * from a series of XFormat records.
+ *
+ * \sa setParentStyle
+ */
+ unsigned parentStyle() const;
+
+ /**
+ * Sets the index of the parent stlye of this format.
+ * This refers to the index of the XFormat table which is constructed
+ * from a series of XFormat records.
+ *
+ * \sa parentStyle
+ */
+ void setParentStyle( unsigned ps );
+
+ enum {
+ General = 0,
+ Left,
+ Centered,
+ Right,
+ Filled,
+ Justified,
+ CenteredSelection,
+ Distributed };
+
+ /**
+ * Gets the horizontal alignment, e.g Left.
+ */
+ unsigned horizontalAlignment() const;
+
+ /**
+ * Sets the horizontal alignment, e.g Left.
+ */
+ void setHorizontalAlignment( unsigned ha );
+
+ /**
+ * Returns human-readable string representation of the horizontal alignment.
+ For example, XFRecord::Left will return "Left".
+ */
+ const char* horizontalAlignmentAsString() const;
+
+ enum {
+ Top = 0,
+ VCentered = 1,
+ Bottom = 2,
+ VJustified = 3,
+ VDistributed = 4 };
+
+ /**
+ * Gets the vertical alignment, e.g Bottom.
+ *
+ * \sa setVerticalAlignment
+ */
+ unsigned verticalAlignment() const;
+
+ /**
+ * Sets the vertical alignment, e.g Top.
+ *
+ * \sa verticalAlignment
+ */
+ void setVerticalAlignment( unsigned va );
+
+ /**
+ * Returns human-readable string representation of the vertical alignment.
+ For example, XFRecord::Top will return "Top".
+ */
+ const char* verticalAlignmentAsString() const;
+
+ /**
+ * Returns true if text is wrapped at right border.
+ *
+ * \sa setTextWrap
+ */
+ bool textWrap() const;
+
+ /**
+ * Sets whether text should be wrapped at right border.
+ *
+ * \sa textWrap
+ */
+ void setTextWrap( bool wrap );
+
+ /**
+ * Returns the rotation angle of the text. If it is between 1 to 90,
+ * the text is rotated 1 to 90 degrees counterclockwise. If it is between
+ * 91 to 180, the text is rotated 1 to 90 degrees clockwise.
+ *
+ * \sa setRotationAngle
+ */
+ unsigned rotationAngle() const;
+
+ /**
+ * Sets the rotation angle of the text. If it is between 1 to 90,
+ * the text is rotated 1 to 90 degrees counterclockwise. If it is between
+ * 91 to 180, the text is rotated 1 to 90 degrees clockwise.
+ *
+ * \sa setRotationAngle
+ */
+ void setRotationAngle( unsigned angle );
+
+ /**
+ * Returns true if the letters for text are not rotated, but
+ * instead stacked top-to-bottom.
+ *
+ * \sa setStackedLetters
+ */
+ bool stackedLetters() const;
+
+ /**
+ * Sets whether the letters for text should be stacked top-to-bottom.
+ *
+ * \sa stackedLetters
+ */
+ void setStackedLetters( bool stacked );
+
+ /**
+ * Returns indent level.
+ *
+ * \sa indentLevel
+ */
+ unsigned indentLevel() const;
+
+ /**
+ * Sets indent level.
+ *
+ * \sa indentLevel
+ */
+ void setIndentLevel( unsigned i );
+
+ /**
+ * Returns true if content should be shrunk to fit into cell.
+ *
+ * \sa setShrinkContent
+ */
+ bool shrinkContent() const;
+
+ /**
+ * Sets whether content should be shrunk to fit into cell.
+ *
+ * \sa shrinkContent
+ */
+ void setShrinkContent( bool s );
+
+ enum
+ {
+ NoLine = 0,
+ Thin = 1,
+ Medium = 2,
+ Dashed = 3,
+ Dotted = 4,
+ Thick = 5,
+ Double = 6,
+ Hair = 7,
+ MediumDashed = 8,
+ ThinDashDotted = 9,
+ MediumDashDotted = 10,
+ ThinDashDotDotted = 11,
+ MediumDashDotDotted = 12,
+ SlantedMediumDashDotted = 13
+ };
+
+ /**
+ * Returns the line style for left border.
+ *
+ * \sa setLeftBorderStyle, leftBorderColor
+ */
+ unsigned leftBorderStyle() const;
+
+ /**
+ * Sets the line style for left border.
+ *
+ * \sa leftBorderStyle, setLeftBorderColor
+ */
+ void setLeftBorderStyle( unsigned style );
+
+ /**
+ * Returns the color for left border. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa setLeftBorderColor, leftBorderStyle
+ */
+ unsigned leftBorderColor() const;
+
+ /**
+ * Sets the color for left border. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa leftBorderColor, setLeftBorderStyle
+ */
+ void setLeftBorderColor( unsigned color );
+
+ /**
+ * Returns the line style for right border.
+ *
+ * \sa setRightBorderStyle, rightBorderColor
+ */
+ unsigned rightBorderStyle() const;
+
+ /**
+ * Sets the line style for right border.
+ *
+ * \sa rightBorderStyle, setRightBorderColor
+ */
+ void setRightBorderStyle( unsigned style );
+
+ /**
+ * Returns the color for right border. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa setRightBorderColor, rightBorderStyle
+ */
+ unsigned rightBorderColor() const;
+
+ /**
+ * Sets the color for right border. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa rightBorderColor, setRightBorderStyle
+ */
+ void setRightBorderColor( unsigned color );
+
+ /**
+ * Returns the line style for top border.
+ *
+ * \sa setTopBorderStyle, topBorderColor
+ */
+ unsigned topBorderStyle() const;
+
+ /**
+ * Sets the line style for top border.
+ *
+ * \sa topBorderStyle, setTopBorderColor
+ */
+ void setTopBorderStyle( unsigned style );
+
+ /**
+ * Returns the color for top border. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa setTopBorderColor, topBorderStyle
+ */
+ unsigned topBorderColor() const;
+
+ /**
+ * Sets the color for top border. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa topBorderColor, setTopBorderStyle
+ */
+ void setTopBorderColor( unsigned color );
+
+ /**
+ * Returns the line style for bottom border.
+ *
+ * \sa setBottomBorderStyle, bottomBorderColor
+ */
+ unsigned bottomBorderStyle() const;
+
+ /**
+ * Sets the line style for bottom border.
+ *
+ * \sa bottomBorderStyle, setBottomBorderColor
+ */
+ void setBottomBorderStyle( unsigned style );
+
+ /**
+ * Returns the color for bottom border. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa setBottomBorderColor, bottomBorderStyle
+ */
+ unsigned bottomBorderColor() const;
+
+ /**
+ * Sets the color for bottom border. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa bottomBorderColor, setBottomBorderStyle
+ */
+ void setBottomBorderColor( unsigned color );
+
+ /**
+ * Returns true if there is a diagonal line from top left to right bottom.
+ *
+ * \sa diagonalStyle, diagonalColor, setDiagonalTopLeft
+ */
+ bool diagonalTopLeft() const;
+
+ /**
+ * Sets whether there should be a diagonal line from top left to right bottom.
+ *
+ * \sa diagonalTopLeft, setDiagonalStlye, setDiagonalColor
+ */
+ void setDiagonalTopLeft( bool d );
+
+ /**
+ * Returns true if there is a diagonal line from bottom left to right top.
+ *
+ * \sa diagonalStyle, diagonalColor, setDiagonalBottomLeft
+ */
+ bool diagonalBottomLeft() const;
+
+ /**
+ * Sets whether there should be a diagonal line from bottom left to right top.
+ *
+ * \sa diagonalBottomLeft, setDiagonalStlye, setDiagonalColor
+ */
+ void setDiagonalBottomLeft( bool d );
+
+ /**
+ * Returns the diagonal line style.
+ *
+ * \sa diagonalTopLeft, diagonalBottomLeft, setDiagonalStyle
+ */
+ unsigned diagonalStyle() const;
+
+ /**
+ * Sets the line style for diagonal line.
+ *
+ * \sa diagonalBorderStyle, setDiagonalTopLeft, setDiagonalBottomLeft
+ */
+ void setDiagonalStyle( unsigned style );
+
+ /**
+ * Returns the color for diagonal line. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa setDiagonalColor, diagonalStyle
+ */
+ unsigned diagonalColor() const;
+
+ /**
+ * Sets the color for diagonal line. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa diagonalColor, setDiagonalStyle
+ */
+ void setDiagonalColor( unsigned color );
+
+ /**
+ * Returns fill pattern.
+ *
+ * \sa setFillPattern
+ */
+ unsigned fillPattern() const;
+
+ /**
+ * Sets fill pattern.
+ *
+ * \sa fillPattern
+ */
+ void setFillPattern( unsigned pattern );
+
+ /**
+ * Returns the fill foreground color. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa setPatternForeColor, patternBackColor
+ */
+ unsigned patternForeColor() const;
+
+ /**
+ * Sets the fill foreground color. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa patternForeColor, setPatternBackColor
+ */
+ void setPatternForeColor( unsigned color );
+
+ /**
+ * Returns the fill background color. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa setPatternBackColor, patternForeColor
+ */
+ unsigned patternBackColor() const;
+
+ /**
+ * Sets the fill background color. This is an index to color palette
+ * specified in Palette record.
+ *
+ * \sa patternBackColor, setPatternForeColor
+ */
+ void setPatternBackColor( unsigned color );
+
+ virtual const char* name(){ return "XF"; }
+
+ virtual void setData( unsigned size, const unsigned char* data );
+
+ virtual void dump( std::ostream& out ) const;
+
+private:
+ class Private;
+ Private* d;
+};
+
+typedef std::vector<UString> UStringStack;
+
+
+class ExcelReader
+{
+public:
+ ExcelReader();
+ virtual ~ExcelReader();
+ bool load( Workbook* workbook, const char* filename );
+
+protected:
+ virtual void handleRecord( Record* record );
+
+private:
+ void handleBoundSheet( BoundSheetRecord* record );
+ void handleBOF( BOFRecord* record );
+ void handleBoolErr( BoolErrRecord* record );
+ void handleBottomMargin( BottomMarginRecord* record );
+ void handleBlank( BlankRecord* record );
+ void handleCalcMode( CalcModeRecord* record );
+ void handleColInfo( ColInfoRecord* record );
+ void handleDateMode( DateModeRecord* record );
+ void handleDimension( DimensionRecord* record );
+ void handleExternName( ExternNameRecord* record );
+ void handleExternSheet( ExternSheetRecord* record );
+ void handleFilepass( FilepassRecord* record );
+ void handleFormat( FormatRecord* record );
+ void handleFormula( FormulaRecord* record );
+ void handleFont( FontRecord* record );
+ void handleFooter( FooterRecord* record );
+ void handleHeader( HeaderRecord* record );
+ void handleLabel( LabelRecord* record );
+ void handleLabelSST( LabelSSTRecord* record );
+ void handleLeftMargin( LeftMarginRecord* record );
+ void handleMergedCells( MergedCellsRecord* record );
+ void handleMulBlank( MulBlankRecord* record );
+ void handleMulRK( MulRKRecord* record );
+ void handleName( NameRecord* record );
+ void handleNumber( NumberRecord* record );
+ void handlePalette( PaletteRecord* record );
+ void handleRightMargin( RightMarginRecord* record );
+ void handleRString( RStringRecord* record );
+ void handleRK( RKRecord* record );
+ void handleRow( RowRecord* record );
+ void handleSST( SSTRecord* record );
+ void handleString( StringRecord* record );
+ void handleSupbook( SupbookRecord* record );
+ void handleTopMargin( TopMarginRecord* record );
+ void handleXF( XFRecord* record );
+
+ Color convertColor( unsigned colorIndex );
+ FormatFont convertFont( unsigned fontIndex );
+ Format convertFormat( unsigned xfIndex );
+ UString decodeFormula( unsigned row, unsigned col,
+ const FormulaTokens& tokens, bool openDocumentFormat=false );
+
+ void mergeTokens( UStringStack* stack, int count, char mergeChar );
+ void mergeTokens( UStringStack* stack, int count, const char* mergeString );
+
+ // no copy or assign
+ ExcelReader( const ExcelReader& );
+ ExcelReader& operator=( const ExcelReader& );
+
+ class Private;
+ Private* d;
+};
+
+
+} // namespace Swinder
+
+
+
+#endif // SWINDER_EXCEL_H
diff --git a/filters/kspread/excel/sidewinder/format.cpp b/filters/kspread/excel/sidewinder/format.cpp
new file mode 100644
index 000000000..8ce69f248
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/format.cpp
@@ -0,0 +1,717 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003-2006 Ariya Hidayat <ariya@kde.org>
+ Copyright (C) 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA
+*/
+
+#include "format.h"
+
+#include "ustring.h"
+
+
+using namespace Swinder;
+
+class FormatFont::Private
+{
+public:
+ bool null : 1 ;
+ bool bold : 1;
+ bool italic : 1;
+ bool underline : 1;
+ bool strikeout : 1;
+ bool subscript : 1;
+ bool superscript : 1;
+ UString fontFamily;
+ double fontSize;
+ Color color;
+
+ static UString defaultFont;
+};
+
+UString FormatFont::Private::defaultFont("Arial");
+
+FormatFont::FormatFont()
+{
+ d = new FormatFont::Private();
+ d->null = true;
+ d->fontFamily = Private::defaultFont;
+ d->fontSize = 11;
+ d->bold = false;
+ d->italic = false;
+ d->underline = false;
+ d->strikeout = false;
+ d->subscript = false;
+ d->superscript = false;
+}
+
+FormatFont::~FormatFont()
+{
+ delete d;
+}
+
+FormatFont::FormatFont( const FormatFont& f )
+{
+ d = new FormatFont::Private();
+ assign( f );
+}
+
+FormatFont& FormatFont::operator=( const FormatFont& f )
+{
+ return assign( f );
+}
+
+FormatFont& FormatFont::assign( const FormatFont& f )
+{
+ d->null = f.isNull();
+ d->fontFamily = f.fontFamily();
+ d->fontSize = f.fontSize();
+ d->color = f.color();
+ d->bold = f.bold();
+ d->italic = f.italic();
+ d->underline = f.underline();
+ d->strikeout = f.strikeout();
+ d->subscript = f.subscript();
+ d->superscript = f.superscript();
+
+ return *this;
+}
+
+bool FormatFont::isNull() const
+{
+ return d->null;
+}
+
+const UString& FormatFont::fontFamily() const
+{
+ return d->fontFamily;
+}
+
+void FormatFont::setFontFamily( const UString& fontFamily )
+{
+ d->fontFamily = fontFamily;
+ d->null = false;
+}
+
+double FormatFont::fontSize() const
+{
+ return d->fontSize;
+}
+
+void FormatFont::setFontSize( double fs )
+{
+ d->fontSize = fs;
+ d->null = false;
+}
+
+Color FormatFont::color() const
+{
+ return d->color;
+}
+
+void FormatFont::setColor( const Color& c )
+{
+ d->color = c;
+ d->null = false;
+}
+
+bool FormatFont::bold() const
+{
+ return d->bold;
+}
+
+void FormatFont::setBold( bool b )
+{
+ d->bold = b;
+ d->null = false;
+}
+
+bool FormatFont::italic() const
+{
+ return d->italic;
+}
+
+void FormatFont::setItalic( bool b )
+{
+ d->italic = b;
+ d->null = false;
+}
+
+bool FormatFont::underline() const
+{
+ return d->underline;
+}
+
+void FormatFont::setUnderline( bool b )
+{
+ d->underline = b;
+ d->null = false;
+}
+
+bool FormatFont::strikeout() const
+{
+ return d->strikeout;
+}
+
+void FormatFont::setStrikeout( bool s )
+{
+ d->strikeout = s;
+ d->null = false;
+}
+
+bool FormatFont::subscript() const
+{
+ return d->subscript;
+}
+
+void FormatFont::setSubscript( bool s )
+{
+ d->subscript = s;
+ d->null = false;
+
+ // mutually exclusive
+ if( d->subscript && d->superscript )
+ d->superscript = false;
+}
+
+bool FormatFont::superscript() const
+{
+ return d->superscript;
+}
+
+void FormatFont::setSuperscript( bool s )
+{
+ d->superscript = s;
+ d->null = false;
+
+ // mutually exclusive
+ if( d->superscript && d->subscript )
+ d->subscript = false;
+}
+
+bool FormatFont::operator==(const FormatFont& font) const
+{
+ return
+ d->bold == font.d->bold &&
+ d->italic == font.d->italic &&
+ d->underline == font.d->underline &&
+ d->strikeout == font.d->strikeout &&
+ d->subscript == font.d->subscript &&
+ d->superscript == font.d->superscript &&
+ d->fontFamily == font.d->fontFamily &&
+ d->fontSize == font.d->fontSize &&
+ d->color == font.d->color;
+}
+
+bool FormatFont::operator!=(const FormatFont& font) const
+{
+ return
+ d->bold != font.d->bold ||
+ d->italic != font.d->italic ||
+ d->underline != font.d->underline ||
+ d->strikeout != font.d->strikeout ||
+ d->subscript != font.d->subscript ||
+ d->superscript != font.d->superscript ||
+ d->fontFamily != font.d->fontFamily ||
+ d->fontSize != font.d->fontSize ||
+ d->color != font.d->color;
+}
+
+class FormatAlignment::Private
+{
+public:
+ bool null;
+ unsigned alignX;
+ unsigned alignY;
+ bool wrap;
+ unsigned indentLevel;
+ unsigned rotationAngle;
+};
+
+FormatAlignment::FormatAlignment()
+{
+ d = new FormatAlignment::Private;
+ d->null = true;
+ d->alignX = Format::Left;
+ d->alignY = Format::Middle;
+ d->wrap = false;
+ d->indentLevel = 0;
+ d->rotationAngle = 0;
+}
+
+// destructor
+FormatAlignment::~FormatAlignment()
+{
+ delete d;
+}
+
+// copy constructor
+FormatAlignment::FormatAlignment( const FormatAlignment& align )
+{
+ d = new FormatAlignment::Private;
+ assign( align );
+}
+
+// assignment operator
+FormatAlignment& FormatAlignment::operator=( const FormatAlignment& align )
+{
+ return assign( align );
+}
+
+// assign from another alignment
+FormatAlignment& FormatAlignment::assign( const FormatAlignment& align )
+{
+ d->null = align.isNull();
+ d->alignX = align.alignX();
+ d->alignY = align.alignY();
+ d->wrap = align.wrap();
+ d->indentLevel = align.indentLevel();
+ d->rotationAngle = align.rotationAngle();
+ return *this;
+}
+
+bool FormatAlignment::isNull() const
+{
+ return d->null;
+}
+
+unsigned FormatAlignment::alignX() const
+{
+ return d->alignX;
+}
+
+void FormatAlignment::setAlignX( unsigned xa )
+{
+ d->alignX = xa;
+ d->null = false;
+}
+
+unsigned FormatAlignment::alignY() const
+{
+ return d->alignY;
+}
+
+void FormatAlignment::setAlignY( unsigned ya )
+{
+ d->alignY = ya;
+ d->null = false;
+}
+
+bool FormatAlignment::wrap() const
+{
+ return d->wrap;
+}
+
+void FormatAlignment::setWrap( bool w )
+{
+ d->wrap = w;
+ d->null = false;
+}
+
+unsigned FormatAlignment::indentLevel() const
+{
+ return d->indentLevel;
+}
+
+void FormatAlignment::setIndentLevel( unsigned i )
+{
+ d->indentLevel = i;
+ d->null = false;
+}
+
+unsigned FormatAlignment::rotationAngle() const
+{
+ return d->rotationAngle;
+}
+
+void FormatAlignment::setRotationAngle( unsigned r )
+{
+ d->rotationAngle = r;
+ d->null = false;
+}
+
+bool FormatAlignment::operator==(const FormatAlignment& font) const
+{
+ return
+ d->alignX == font.d->alignX &&
+ d->alignY == font.d->alignY &&
+ d->wrap == font.d->wrap &&
+ d->indentLevel == font.d->indentLevel &&
+ d->rotationAngle == font.d->rotationAngle;
+}
+
+bool FormatAlignment::operator!=(const FormatAlignment& font) const
+{
+ return
+ d->alignX != font.d->alignX ||
+ d->alignY != font.d->alignY ||
+ d->wrap != font.d->wrap ||
+ d->indentLevel != font.d->indentLevel ||
+ d->rotationAngle != font.d->rotationAngle;
+}
+
+class FormatBackground::Private
+{
+public:
+ bool null;
+ unsigned pattern;
+ Color background;
+ Color foreground;
+};
+
+// constructor
+FormatBackground::FormatBackground()
+{
+ d = new FormatBackground::Private();
+ d->null = true;
+}
+
+// destructor
+FormatBackground::~FormatBackground()
+{
+ delete d;
+}
+
+// copy constructor
+FormatBackground::FormatBackground( const FormatBackground& background )
+{
+ d = new FormatBackground::Private;
+ assign( background );
+}
+
+// assignment operator
+FormatBackground& FormatBackground::operator=( const FormatBackground& background )
+{
+ return assign( background );
+}
+
+// assign from another alignment
+FormatBackground& FormatBackground::assign( const FormatBackground& background )
+{
+ d->null = background.isNull();
+ d->pattern = background.pattern();
+ d->background = background.backgroundColor();
+ d->foreground = background.foregroundColor();
+ return *this;
+}
+
+bool FormatBackground::isNull() const
+{
+ return d->null;
+}
+
+unsigned FormatBackground::pattern() const
+{
+ return d->pattern;
+}
+
+void FormatBackground::setPattern( unsigned pattern )
+{
+ d->pattern = pattern;
+ d->null = false;
+}
+
+Color FormatBackground::backgroundColor() const
+{
+ return d->background;
+}
+
+void FormatBackground::setBackgroundColor( const Color& color )
+{
+ d->background = color;
+ d->null = false;
+}
+
+Color FormatBackground::foregroundColor() const
+{
+ return d->foreground;
+}
+
+void FormatBackground::setForegroundColor( const Color& color )
+{
+ d->foreground = color;
+ d->null = false;
+}
+
+bool FormatBackground::operator==(const FormatBackground& font) const
+{
+ return
+ d->pattern == font.d->pattern &&
+ d->background == font.d->background &&
+ d->foreground == font.d->foreground;
+}
+
+bool FormatBackground::operator!=(const FormatBackground& font) const
+{
+ return
+ d->pattern != font.d->pattern ||
+ d->background != font.d->background ||
+ d->foreground != font.d->foreground;
+}
+
+class FormatBorders::Private
+{
+public:
+ bool null;
+ Pen leftBorder;
+ Pen rightBorder;
+ Pen topBorder;
+ Pen bottomBorder;
+};
+
+// constructor
+FormatBorders::FormatBorders()
+{
+ d = new FormatBorders::Private;
+ d->null = true;
+}
+
+// destructor
+FormatBorders::~FormatBorders()
+{
+ delete d;
+}
+
+// copy constructor
+FormatBorders::FormatBorders( const FormatBorders& border )
+{
+ d = new FormatBorders::Private;
+ assign( border );
+}
+
+// assignment operator
+FormatBorders& FormatBorders::operator=( const FormatBorders& border )
+{
+ return assign( border );
+}
+
+// assign from another alignment
+FormatBorders& FormatBorders::assign( const FormatBorders& border )
+{
+ d->null = border.isNull();
+ d->leftBorder = border.leftBorder();
+ d->rightBorder = border.rightBorder();
+ d->topBorder = border.topBorder();
+ d->bottomBorder = border.bottomBorder();
+ return *this;
+}
+
+bool FormatBorders::isNull() const
+{
+ return d->null;
+}
+
+const Pen& FormatBorders::leftBorder() const
+{
+ return d->leftBorder;
+}
+
+void FormatBorders::setLeftBorder( const Pen& pen )
+{
+ d->leftBorder = pen;
+ d->null = false;
+}
+
+const Pen& FormatBorders::rightBorder() const
+{
+ return d->rightBorder;
+}
+
+void FormatBorders::setRightBorder( const Pen& pen )
+{
+ d->rightBorder = pen;
+ d->null = false;
+}
+
+const Pen& FormatBorders::topBorder() const
+{
+ return d->topBorder;
+}
+
+void FormatBorders::setTopBorder( const Pen& pen )
+{
+ d->topBorder = pen;
+ d->null = false;
+}
+
+const Pen& FormatBorders::bottomBorder() const
+{
+ return d->bottomBorder;
+}
+
+void FormatBorders::setBottomBorder( const Pen& pen )
+{
+ d->bottomBorder = pen;
+ d->null = false;
+}
+
+bool FormatBorders::operator==(const FormatBorders& font) const
+{
+ return
+ d->leftBorder == font.d->leftBorder &&
+ d->rightBorder == font.d->rightBorder &&
+ d->topBorder == font.d->topBorder &&
+ d->bottomBorder == font.d->bottomBorder;
+}
+
+bool FormatBorders::operator!=(const FormatBorders& font) const
+{
+ return
+ d->leftBorder != font.d->leftBorder ||
+ d->rightBorder != font.d->rightBorder ||
+ d->topBorder != font.d->topBorder ||
+ d->bottomBorder != font.d->bottomBorder;
+}
+
+// helper class for Format class
+class Format::Private
+{
+public:
+ FormatFont font;
+ FormatAlignment alignment;
+ FormatBorders borders;
+ FormatBackground background;
+ UString valueFormat;
+};
+
+// create an empty format
+Format::Format()
+{
+ d = new Format::Private;
+ d->valueFormat = "General";
+}
+
+// destructor
+Format::~Format()
+{
+ delete d;
+}
+
+// copy constructor
+Format::Format( const Format& f )
+{
+ d = new Format::Private;
+ assign( f );
+}
+
+// assignment operator
+Format& Format::operator=( const Format& f )
+{
+ return assign( f );
+}
+
+// assign from another format
+Format& Format::assign( const Format& f )
+{
+ d->font = f.font();
+ d->alignment = f.alignment();
+ d->borders = f.borders();
+ d->valueFormat = f.valueFormat();
+ d->background = f.background();
+ return *this;
+}
+
+bool Format::isNull() const
+{
+ return d->font.isNull() && d->alignment.isNull() && d->borders.isNull();
+}
+
+FormatFont& Format::font() const
+{
+ return d->font;
+}
+
+void Format::setFont( const FormatFont& font )
+{
+ d->font = font;
+}
+
+FormatAlignment& Format::alignment() const
+{
+ return d->alignment;
+}
+
+void Format::setAlignment( const FormatAlignment& alignment )
+{
+ d->alignment = alignment;
+}
+
+FormatBorders& Format::borders() const
+{
+ return d->borders;
+}
+
+void Format::setBorders( const FormatBorders& borders )
+{
+ d->borders = borders;
+}
+
+FormatBackground& Format::background() const
+{
+ return d->background;
+}
+
+void Format::setBackground( const FormatBackground& background )
+{
+ d->background = background;
+}
+
+const UString& Format::valueFormat() const
+{
+ return d->valueFormat;
+}
+
+void Format::setValueFormat( const UString& valueFormat )
+{
+ d->valueFormat = valueFormat;
+}
+
+// merge f into current format
+Format& Format::apply( const Format& f )
+{
+ if( !f.alignment().isNull() )
+ alignment() = f.alignment();
+ if( !f.font().isNull() )
+ font() = f.font();
+ if( !f.borders().isNull() )
+ borders() = f.borders();
+ if( f.valueFormat().isEmpty() || f.valueFormat() == "General" )
+ setValueFormat( f.valueFormat() );
+ if (!f.background().isNull() )
+ background() = f.background();
+
+ return *this;
+}
+
+bool Format::operator==(const Format& format) const
+{
+ return
+ d->font == format.d->font &&
+ d->alignment == format.d->alignment &&
+ d->borders == format.d->borders &&
+ d->background == format.d->background &&
+ d->valueFormat == format.d->valueFormat;
+}
+
+bool Format::operator!=(const Format& format) const
+{
+ return
+ d->font != format.d->font ||
+ d->alignment != format.d->alignment ||
+ d->borders != format.d->borders ||
+ d->background != format.d->background ||
+ d->valueFormat != format.d->valueFormat;
+}
diff --git a/filters/kspread/excel/sidewinder/format.h b/filters/kspread/excel/sidewinder/format.h
new file mode 100644
index 000000000..55fab7624
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/format.h
@@ -0,0 +1,761 @@
+/* Sidewinder - Portable library for spreadsheet
+ Copyright (C) 2003-2006 Ariya Hidayat <ariya@kde.org>
+ Copyright (C) 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#ifndef SWINDER_FORMAT_H
+#define SWINDER_FORMAT_H
+
+#include "ustring.h"
+#include <cstdio> // for sscanf
+
+namespace Swinder
+{
+
+/**
+ * @short Provides color based on RGB values.
+ *
+ * Class Color provides color based on terms of RGB (red, green and blue)
+ * components.
+ *
+ */
+class Color
+{
+public:
+
+ unsigned red, green, blue;
+
+ /**
+ * Constructs a default color with the RGB value (0, 0, 0), i.e black.
+ */
+ Color(){ red = green = blue = 0; };
+
+ /**
+ * Creates a copy of another color.
+ */
+ Color( const Color& c )
+ { red = c.red; green = c.green; blue = c.blue; }
+
+ /**
+ * Creates a color based on given red, green and blue values.
+ */
+ Color( unsigned r, unsigned g, unsigned b )
+ { red = r; green = g; blue = b; }
+
+ /**
+ * Creates a color based on given red, green and blue values, encoded as #RRGGBB in a string.
+ */
+ Color( const char* c )
+ { std::sscanf(c, "#%2x%2x%2x", &red, &green, &blue); }
+
+ friend inline bool operator==(const Color&, const Color&);
+ friend inline bool operator!=(const Color&, const Color&);
+};
+
+/**
+ Returns true if c1 is equal to c2; otherwise returns false.
+*/
+inline bool operator==(const Color& c1, const Color& c2)
+{ return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue; }
+
+/**
+ Returns true if c1 is not equal to c2; otherwise returns false.
+*/
+inline bool operator!=(const Color& c1, const Color& c2)
+{ return c1.red != c2.red || c1.green != c2.green || c1.blue != c2.blue; }
+
+class Pen
+{
+public:
+
+ unsigned style;
+
+ unsigned width;
+
+ Color color;
+
+ enum {
+ NoLine, // no line at all
+ SolidLine, // a simple solid line
+ DashLine, // dashes separated by a few pixels
+ DotLine, // dots separated by a few pixels
+ DashDotLine, // alternate dots and dashes
+ DashDotDotLine // one dash, two dots, one dash, two dots
+ };
+
+ Pen(): style( SolidLine ), width( 0 ){}
+
+ friend inline bool operator==(const Pen&, const Pen&);
+ friend inline bool operator!=(const Pen&, const Pen&);
+};
+
+/**
+ Returns true if p1 is equal to p2; otherwise returns false.
+*/
+inline bool operator==(const Pen& p1, const Pen& p2)
+{ return p1.style == p2.style && p1.width == p1.width && p1.color == p2.color; }
+
+/**
+ Returns true if p1 is not equal to p2; otherwise returns false.
+*/
+inline bool operator!=(const Pen& p1, const Pen& p2)
+{ return p1.style != p2.style || p1.width != p1.width || p1.color != p2.color; }
+
+
+/**
+ * Defines font information for cell format.
+ *
+ * Class FormatFont defines the font family, size and other attributes
+ * for use in cell format.
+ *
+ */
+
+class FormatFont
+{
+public:
+
+ /**
+ * Creates a default font information.
+ */
+ FormatFont();
+
+ /**
+ * Destroys the font information
+ */
+ ~FormatFont();
+
+ /**
+ * Creates a copy of font information.
+ */
+ FormatFont( const FormatFont& );
+
+ /**
+ * Assigns from another font information.
+ */
+ FormatFont& operator=( const FormatFont& );
+
+ /**
+ * Assigns from another font information.
+ */
+ FormatFont& assign( const FormatFont& );
+
+ /**
+ * Returns true if it is a default font information.
+ */
+ bool isNull() const;
+
+ /**
+ * Returns the name of font family, e.g "Helvetica".
+ */
+ const UString& fontFamily() const;
+
+ /**
+ * Sets a new family for the font information.
+ */
+ void setFontFamily( const UString& fontFamily );
+
+ /**
+ * Returns the size of font (in points).
+ */
+ double fontSize() const;
+
+ /**
+ * Sets the size of font (in points).
+ */
+ void setFontSize( double fs );
+
+ /**
+ * Returns the color of the font.
+ */
+ Color color() const;
+
+ /**
+ * Sets the color of the font.
+ */
+ void setColor( const Color& color );
+
+ /**
+ * Returns true if bold has been set.
+ */
+ bool bold() const;
+
+ /**
+ * If b is true, bold is set on; otherwise bold is set off.
+ */
+ void setBold( bool b );
+
+ /**
+ * Returns true if italic has been set.
+ */
+ bool italic() const;
+
+ /**
+ * If i is true, italic is set on; otherwise italic is set off.
+ */
+ void setItalic( bool i );
+
+ /**
+ * Returns true if underline has been set.
+ */
+ bool underline() const;
+
+ /**
+ * If u is true, underline is set on; otherwise underline is set off.
+ */
+ void setUnderline( bool u );
+
+ /**
+ * Returns true if strikeout has been set.
+ */
+ bool strikeout() const;
+
+ /**
+ * If s is true, strikeout is set on; otherwise strikeout is set off.
+ */
+ void setStrikeout( bool s );
+
+ /**
+ * Returns true if subscript has been set.
+ */
+ bool subscript() const;
+
+ /**
+ * If s is true, subscript is set on; otherwise subscript is set off.
+ */
+ void setSubscript( bool s );
+
+ /**
+ * Returns true if superscript has been set.
+ */
+ bool superscript() const;
+
+ /**
+ * If s is true, superscript is set on; otherwise superscript is set off.
+ */
+ void setSuperscript( bool s );
+
+ /**
+ * Returns true if this font is equal to f; otherwise returns false.
+ */
+ bool operator==(const FormatFont& f) const;
+
+ /**
+ * Returns true if this font is not equal to f; otherwise returns false.
+ */
+ bool operator!=(const FormatFont& f) const;
+
+private:
+ class Private;
+ Private *d;
+};
+
+
+/**
+ * Defines alignment information for cell format.
+ *
+ * Class FormatAlignment defines the horizontal and vertical alignment
+ * for the text inside a cell.
+ *
+ */
+
+class FormatAlignment
+{
+public:
+
+ /**
+ * Creates a default alignment information.
+ */
+ FormatAlignment();
+
+ /**
+ * Destroys the alignment information
+ */
+ ~FormatAlignment();
+
+ /**
+ * Creates a copy of alignment information.
+ */
+ FormatAlignment( const FormatAlignment& );
+
+ /**
+ * Assigns from another alignment information.
+ */
+ FormatAlignment& operator=( const FormatAlignment& );
+
+ /**
+ * Assigns from another alignment information.
+ */
+ FormatAlignment& assign( const FormatAlignment& );
+
+ /**
+ * Returns true if it is a default alignment information.
+ */
+ bool isNull() const;
+
+ /**
+ * Returns horizontal alignment. Possible values are
+ * Format::Left, Format::Right and Format::Center.
+ *
+ * \sa setAlignX
+ */
+ unsigned alignX() const;
+
+ /**
+ * Sets the horizontal alignment.
+ *
+ * \sa alignX
+ */
+ void setAlignX( unsigned xa );
+
+ /**
+ * Returns horizontal alignment. Possible values are
+ * Format::Top, Format::Middle and Format::Bottom.
+ *
+ * \sa setAlignY
+ */
+ unsigned alignY() const;
+
+ /**
+ * Sets the horizontal alignment.
+ *
+ * \sa alignY
+ */
+ void setAlignY( unsigned xa );
+
+ /**
+ * Returns true if the text should be wrapped at right border.
+ *
+ * \sa setWrap
+ */
+ bool wrap() const;
+
+ /**
+ * Sets whether the text should be wrapped at right border.
+ *
+ * \sa setWrap
+ */
+ void setWrap( bool w );
+
+ /**
+ * Returns the indentation level.
+ *
+ * \sa setIndentLevel
+ */
+ unsigned indentLevel() const;
+
+ /**
+ * Sets the indentation level.
+ *
+ * \sa indentLevel
+ */
+ void setIndentLevel( unsigned i );
+
+ /**
+ * Returns the text rotation angle.
+ *
+ * \sa setRotationAngle
+ */
+ unsigned rotationAngle() const;
+
+ /**
+ * Sets the text rotation angle.
+ *
+ * \sa rotationAngle
+ */
+ void setRotationAngle( unsigned r );
+
+ /**
+ * Returns true if this alignment is equal to f; otherwise returns false.
+ */
+ bool operator==(const FormatAlignment& f) const;
+
+ /**
+ * Returns true if this alignment is not equal to f; otherwise returns false.
+ */
+ bool operator!=(const FormatAlignment& f) const;
+
+private:
+ class Private;
+ Private *d;
+};
+
+/**
+ * Defines background information for cell.
+ *
+ */
+class FormatBackground
+{
+public:
+ /**
+ * Creates a default background information.
+ */
+ FormatBackground();
+
+ /**
+ * Destroys the background information.
+ */
+ ~FormatBackground();
+
+ /**
+ * Creates a copy of background information.
+ */
+ FormatBackground( const FormatBackground& );
+
+ /**
+ * Assigns from another background information.
+ */
+ FormatBackground& operator=( const FormatBackground& );
+
+ /**
+ * Assigns from another background information.
+ */
+ FormatBackground& assign( const FormatBackground& );
+
+ /**
+ * Returns true if it is a default background information.
+ */
+ bool isNull() const;
+
+ enum {
+ SolidPattern,
+ Dense1Pattern,
+ Dense2Pattern,
+ Dense3Pattern,
+ Dense4Pattern,
+ Dense5Pattern,
+ Dense6Pattern,
+ Dense7Pattern,
+ HorPattern, // Horizonatal lines
+ VerPattern, // Vertical lines
+ CrossPattern, // Horizontal and Vertical lines
+ BDiagPattern, // Left-bottom to right-top diagonal lines
+ FDiagPattern, // Left-top to right-bottom diagonal lines
+ DiagCrossPattern, // Crossing diagonal lines
+ EmptyPattern
+ };
+
+ /**
+ * Returns pattern for this background.
+ *
+ * \sa setPattern
+ */
+ unsigned pattern() const;
+
+ /**
+ * Set the pattern for this background.
+ *
+ * \sa pattern
+ */
+ void setPattern( unsigned );
+
+ /**
+ * Returns the background color of the background area.
+ *
+ * \sa setBackgroundColor
+ */
+ Color backgroundColor() const;
+
+ /**
+ * Set the background color.
+ *
+ * \sa backgroundColor
+ */
+ void setBackgroundColor( const Color& );
+
+ /**
+ * Returns the foreground color of the background area.
+ *
+ * \sa setForegroundColor
+ */
+ Color foregroundColor() const;
+
+ /**
+ * Sets the foreground color.
+ *
+ * \sa foregroundColor
+ */
+ void setForegroundColor( const Color& );
+
+ /**
+ * Returns true if this background is equal to f; otherwise returns false.
+ */
+ bool operator==(const FormatBackground& f) const;
+
+ /**
+ * Returns true if this background is not equal to f; otherwise returns false.
+ */
+ bool operator!=(const FormatBackground& f) const;
+
+private:
+ class Private;
+ Private *d;
+};
+
+/**
+ * Defines borders information for cell.
+ *
+ */
+
+class FormatBorders
+{
+public:
+
+ /**
+ * Creates a default border information.
+ */
+ FormatBorders();
+
+ /**
+ * Destroys the border information
+ */
+ ~FormatBorders();
+
+ /**
+ * Creates a copy of border information.
+ */
+ FormatBorders( const FormatBorders& );
+
+ /**
+ * Assigns from another border information.
+ */
+ FormatBorders& operator=( const FormatBorders& );
+
+ /**
+ * Assigns from another border information.
+ */
+ FormatBorders& assign( const FormatBorders& );
+
+ /**
+ * Returns true if it is a default border information.
+ */
+ bool isNull() const;
+
+ /**
+ * Returns pen style, width and color for left border.
+ *
+ * \sa setLeftBorder
+ */
+ const Pen& leftBorder() const;
+
+ /**
+ * Sets pen style, width and color for left border.
+ *
+ * \sa leftBorder
+ */
+ void setLeftBorder( const Pen& pen );
+
+ /**
+ * Returns pen style, width and color for right border.
+ *
+ * \sa setRightBorder
+ */
+ const Pen& rightBorder() const;
+
+ /**
+ * Sets pen style, width and color for right border.
+ *
+ * \sa rightBorder
+ */
+ void setRightBorder( const Pen& pen );
+
+ /**
+ * Returns pen style, width and color for top border.
+ *
+ * \sa setTopBorder
+ */
+ const Pen& topBorder() const;
+
+ /**
+ * Sets pen style, width and color for top border.
+ *
+ * \sa topBorder
+ */
+ void setTopBorder( const Pen& pen );
+
+ /**
+ * Returns pen style, width and color for bottom border.
+ *
+ * \sa setBottomBorder
+ */
+ const Pen& bottomBorder() const;
+
+ /**
+ * Sets pen style, width and color for bottom border.
+ *
+ * \sa bottomBorder
+ */
+ void setBottomBorder( const Pen& pen );
+
+ /**
+ * Returns true if this background is equal to f; otherwise returns false.
+ */
+ bool operator==(const FormatBorders& f) const;
+
+ /**
+ * Returns true if this background is not equal to f; otherwise returns false.
+ */
+ bool operator!=(const FormatBorders& f) const;
+
+private:
+ class Private;
+ Private *d;
+};
+
+/**
+ * Defines format of cell.
+ *
+ * Class Format defines possible formatting for use in cells or ranges.
+ * Basically, Format might consist of one or more "pieces". Each piece
+ * specifies only one type of formatting, e.g whether the text should
+ * be shown in bold or not, which borders should the cells/ranges have,
+ * and so on.
+ *
+ * A complex formatting can be decomposed into different pieces. For example,
+ * formatting like "Font is Arial 10 pt, background color is blue,
+ " formula is hidden" could be a combination of three simple formatting pieces
+ * as: (1) font is "Arial 10pt", (2) background pattern is 100%, blue
+ * and (3) cell is protected, formula is hidden. This also means
+ * that one format might be applied to another format. An example of this is
+ * "Font is Helvetica" format and "Left border, 1pt, blue" format will yields
+ * something like "Font is Helvetica, with left border of blue 1pt".
+ * Use Format::apply to do such format merging.
+ *
+ */
+
+
+class Format
+{
+public:
+
+ /**
+ * Creates a default format.
+ */
+ Format();
+
+ /**
+ * Destroys the format.
+ */
+ ~Format();
+
+ /**
+ * Creates a copy from another format.
+ */
+ Format( const Format& f );
+
+ /**
+ * Assigns from another format.
+ */
+ Format& operator= ( const Format& f );
+
+ /**
+ * Assigns from another value.
+ */
+ Format& assign( const Format& f );
+
+ /**
+ * Returns true if it is a default format information.
+ */
+ bool isNull() const;
+
+ /**
+ * Returns a constant reference to the formatting information of this format.
+ */
+ FormatFont& font() const;
+
+ /**
+ * Sets new font information for this format.
+ */
+ void setFont( const FormatFont& font );
+
+ /**
+ * Returns a constant reference to the alignment information of this format.
+ */
+ FormatAlignment& alignment() const;
+
+ /**
+ * Sets new alignment information for this format.
+ */
+ void setAlignment( const FormatAlignment& alignment );
+
+ /**
+ * Returns a reference to the borders information of this format.
+ */
+ FormatBorders& borders() const;
+
+ /**
+ * Sets new borders information for this format.
+ */
+ void setBorders( const FormatBorders& border );
+
+ /**
+ * Returns a reference to the background information of this format.
+ */
+ FormatBackground& background() const;
+
+ /**
+ * Sets new background information for this format.
+ */
+ void setBackground( const FormatBackground& );
+
+ /**
+ * Returns the formatting string to display the value of this format.
+ */
+ const UString& valueFormat() const;
+
+ /**
+ * Sets the new formatting string to display the value of this format.
+ */
+ void setValueFormat( const UString& valueFormat );
+
+ enum { Left, Center, Right };
+
+ enum { Top, Middle, Bottom };
+
+ /**
+ * Applies another format to this format. Basically this will merge
+ * the formatting information of f into the current format.
+ * For example, if current format is "Bold, Italic" and f is
+ * "Left border", the current format would become "Bold, Italic, left border".
+ *
+ * If parts of the formatting information in f are already specified in the
+ * current format, then it will override the current format.
+ * For example, if current format is "Bold, right-aligned" and f is "Italic",
+ * the result is "Italic, right-aligned".
+ *
+ */
+ Format& apply( const Format& f );
+
+ /**
+ * Returns true if this format is equal to f; otherwise returns false.
+ */
+ bool operator==(const Format& f) const;
+
+ /**
+ * Returns true if this format is not equal to f; otherwise returns false.
+ */
+ bool operator!=(const Format& f) const;
+
+private:
+ class Private;
+ Private* d; // can't never be 0
+};
+
+}
+
+#endif // SWINDER_FORMAT_H
+
diff --git a/filters/kspread/excel/sidewinder/pole.cpp b/filters/kspread/excel/sidewinder/pole.cpp
new file mode 100644
index 000000000..e4090cd90
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/pole.cpp
@@ -0,0 +1,1354 @@
+/* POLE - Portable C++ library to access OLE Storage
+ Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the authors nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <fstream>
+#include <iostream>
+#include <list>
+#include <string>
+#include <vector>
+#include <string.h>
+
+#include "pole.h"
+
+// enable to activate debugging output
+// #define POLE_DEBUG
+
+namespace POLE
+{
+
+class Header
+{
+ public:
+ unsigned char id[8]; // signature, or magic identifier
+ unsigned b_shift; // bbat->blockSize = 1 << b_shift
+ unsigned s_shift; // sbat->blockSize = 1 << s_shift
+ unsigned num_bat; // blocks allocated for big bat
+ unsigned dirent_start; // starting block for directory info
+ unsigned threshold; // switch from small to big file (usually 4K)
+ unsigned sbat_start; // starting block index to store small bat
+ unsigned num_sbat; // blocks allocated for small bat
+ unsigned mbat_start; // starting block to store meta bat
+ unsigned num_mbat; // blocks allocated for meta bat
+ unsigned long bb_blocks[109];
+
+ Header();
+ bool valid();
+ void load( const unsigned char* buffer );
+ void save( unsigned char* buffer );
+ void debug();
+};
+
+class AllocTable
+{
+ public:
+ static const unsigned Eof;
+ static const unsigned Avail;
+ static const unsigned Bat;
+ static const unsigned MetaBat;
+ unsigned blockSize;
+ AllocTable();
+ void clear();
+ unsigned long count();
+ void resize( unsigned long newsize );
+ void preserve( unsigned long n );
+ void set( unsigned long index, unsigned long val );
+ unsigned unused();
+ void setChain( std::vector<unsigned long> );
+ std::vector<unsigned long> follow( unsigned long start );
+ unsigned long operator[](unsigned long index );
+ void load( const unsigned char* buffer, unsigned len );
+ void save( unsigned char* buffer );
+ unsigned size();
+ void debug();
+ private:
+ std::vector<unsigned long> data;
+ AllocTable( const AllocTable& );
+ AllocTable& operator=( const AllocTable& );
+};
+
+class DirEntry
+{
+ public:
+ bool valid; // false if invalid (should be skipped)
+ std::string name; // the name, not in unicode anymore
+ bool dir; // true if directory
+ unsigned long size; // size (not valid if directory)
+ unsigned long start; // starting block
+ unsigned prev; // previous sibling
+ unsigned next; // next sibling
+ unsigned child; // first child
+};
+
+class DirTree
+{
+ public:
+ static const unsigned End;
+ DirTree();
+ void clear();
+ unsigned entryCount();
+ DirEntry* entry( unsigned index );
+ DirEntry* entry( const std::string& name, bool create=false );
+ int indexOf( DirEntry* e );
+ int parent( unsigned index );
+ std::string fullName( unsigned index );
+ std::vector<unsigned> children( unsigned index );
+ void load( unsigned char* buffer, unsigned len );
+ void save( unsigned char* buffer );
+ unsigned size();
+ void debug();
+ private:
+ std::vector<DirEntry> entries;
+ DirTree( const DirTree& );
+ DirTree& operator=( const DirTree& );
+};
+
+class StorageIO
+{
+ public:
+ Storage* storage; // owner
+ std::string filename; // filename
+ std::fstream file; // associated with above name
+ int result; // result of operation
+ bool opened; // true if file is opened
+ unsigned long filesize; // size of the file
+
+ Header* header; // storage header
+ DirTree* dirtree; // directory tree
+ AllocTable* bbat; // allocation table for big blocks
+ AllocTable* sbat; // allocation table for small blocks
+
+ unsigned long lastBlockIndex; // last read, for simple caching
+ unsigned char* lastBlockData;
+
+ std::vector<unsigned long> sb_blocks; // blocks for "small" files
+
+ std::list<Stream*> streams;
+
+ StorageIO( Storage* storage, const char* filename );
+ ~StorageIO();
+
+ bool open();
+ void close();
+ void flush();
+ void load();
+ void create();
+
+ unsigned long loadBigBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
+
+ unsigned long loadBigBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
+
+ unsigned long loadSmallBlocks( std::vector<unsigned long> blocks, unsigned char* buffer, unsigned long maxlen );
+
+ unsigned long loadSmallBlock( unsigned long block, unsigned char* buffer, unsigned long maxlen );
+
+ StreamIO* streamIO( const std::string& name );
+
+ private:
+ // no copy or assign
+ StorageIO( const StorageIO& );
+ StorageIO& operator=( const StorageIO& );
+
+};
+
+class StreamIO
+{
+ public:
+ StorageIO* io;
+ DirEntry* entry;
+ std::string fullName;
+ bool eof;
+ bool fail;
+
+ StreamIO( StorageIO* io, DirEntry* entry );
+ ~StreamIO();
+ unsigned long size();
+ void seek( unsigned long pos );
+ unsigned long tell();
+ int getch();
+ unsigned long read( unsigned char* data, unsigned long maxlen );
+ unsigned long read( unsigned long pos, unsigned char* data, unsigned long maxlen );
+
+
+ private:
+ std::vector<unsigned long> blocks;
+
+ // no copy or assign
+ StreamIO( const StreamIO& );
+ StreamIO& operator=( const StreamIO& );
+
+ // pointer for read
+ unsigned long m_pos;
+
+ // simple cache system to speed-up getch()
+ unsigned char* cache_data;
+ unsigned long cache_size;
+ unsigned long cache_pos;
+ void updateCache();
+};
+
+} // namespace POLE
+
+using namespace POLE;
+
+static inline unsigned long readU16( const unsigned char* ptr )
+{
+ return ptr[0]+(ptr[1]<<8);
+}
+
+static inline unsigned long readU32( const unsigned char* ptr )
+{
+ return ptr[0]+(ptr[1]<<8)+(ptr[2]<<16)+(ptr[3]<<24);
+}
+
+static inline void writeU16( unsigned char* ptr, unsigned long data )
+{
+ ptr[0] = (unsigned char)(data & 0xff);
+ ptr[1] = (unsigned char)((data >> 8) & 0xff);
+}
+
+static inline void writeU32( unsigned char* ptr, unsigned long data )
+{
+ ptr[0] = (unsigned char)(data & 0xff);
+ ptr[1] = (unsigned char)((data >> 8) & 0xff);
+ ptr[2] = (unsigned char)((data >> 16) & 0xff);
+ ptr[3] = (unsigned char)((data >> 24) & 0xff);
+}
+
+static const unsigned char pole_magic[] =
+ { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
+
+// =========== Header ==========
+
+Header::Header()
+{
+ b_shift = 9;
+ s_shift = 6;
+ num_bat = 0;
+ dirent_start = 0;
+ threshold = 4096;
+ sbat_start = 0;
+ num_sbat = 0;
+ mbat_start = 0;
+ num_mbat = 0;
+
+ for( unsigned i = 0; i < 8; i++ )
+ id[i] = pole_magic[i];
+ for( unsigned i=0; i<109; i++ )
+ bb_blocks[i] = AllocTable::Avail;
+}
+
+bool Header::valid()
+{
+ if( threshold != 4096 ) return false;
+ if( num_bat == 0 ) return false;
+ if( (num_bat > 109) && (num_bat > (num_mbat * 127) + 109)) return false;
+ if( (num_bat < 109) && (num_mbat != 0) ) return false;
+ if( s_shift > b_shift ) return false;
+ if( b_shift <= 6 ) return false;
+ if( b_shift >=31 ) return false;
+
+ return true;
+}
+
+void Header::load( const unsigned char* buffer )
+{
+ b_shift = readU16( buffer + 0x1e );
+ s_shift = readU16( buffer + 0x20 );
+ num_bat = readU32( buffer + 0x2c );
+ dirent_start = readU32( buffer + 0x30 );
+ threshold = readU32( buffer + 0x38 );
+ sbat_start = readU32( buffer + 0x3c );
+ num_sbat = readU32( buffer + 0x40 );
+ mbat_start = readU32( buffer + 0x44 );
+ num_mbat = readU32( buffer + 0x48 );
+
+ for( unsigned i = 0; i < 8; i++ )
+ id[i] = buffer[i];
+ for( unsigned i=0; i<109; i++ )
+ bb_blocks[i] = readU32( buffer + 0x4C+i*4 );
+}
+
+void Header::save( unsigned char* buffer )
+{
+ memset( buffer, 0, 0x4c );
+ memcpy( buffer, pole_magic, 8 ); // ole signature
+ writeU32( buffer + 8, 0 ); // unknown
+ writeU32( buffer + 12, 0 ); // unknown
+ writeU32( buffer + 16, 0 ); // unknown
+ writeU16( buffer + 24, 0x003e ); // revision ?
+ writeU16( buffer + 26, 3 ); // version ?
+ writeU16( buffer + 28, 0xfffe ); // unknown
+ writeU16( buffer + 0x1e, b_shift );
+ writeU16( buffer + 0x20, s_shift );
+ writeU32( buffer + 0x2c, num_bat );
+ writeU32( buffer + 0x30, dirent_start );
+ writeU32( buffer + 0x38, threshold );
+ writeU32( buffer + 0x3c, sbat_start );
+ writeU32( buffer + 0x40, num_sbat );
+ writeU32( buffer + 0x44, mbat_start );
+ writeU32( buffer + 0x48, num_mbat );
+
+ for( unsigned i=0; i<109; i++ )
+ writeU32( buffer + 0x4C+i*4, bb_blocks[i] );
+}
+
+void Header::debug()
+{
+ std::cout << std::endl;
+ std::cout << "b_shift " << b_shift << std::endl;
+ std::cout << "s_shift " << s_shift << std::endl;
+ std::cout << "num_bat " << num_bat << std::endl;
+ std::cout << "dirent_start " << dirent_start << std::endl;
+ std::cout << "threshold " << threshold << std::endl;
+ std::cout << "sbat_start " << sbat_start << std::endl;
+ std::cout << "num_sbat " << num_sbat << std::endl;
+ std::cout << "mbat_start " << mbat_start << std::endl;
+ std::cout << "num_mbat " << num_mbat << std::endl;
+
+ unsigned s = (num_bat<=109) ? num_bat : 109;
+ std::cout << "bat blocks: ";
+ for( unsigned i = 0; i < s; i++ )
+ std::cout << bb_blocks[i] << " ";
+ std::cout << std::endl;
+}
+
+// =========== AllocTable ==========
+
+const unsigned AllocTable::Avail = 0xffffffff;
+const unsigned AllocTable::Eof = 0xfffffffe;
+const unsigned AllocTable::Bat = 0xfffffffd;
+const unsigned AllocTable::MetaBat = 0xfffffffc;
+
+AllocTable::AllocTable()
+{
+ blockSize = 4096;
+ // initial size
+ resize( 128 );
+}
+
+unsigned long AllocTable::count()
+{
+ return data.size();
+}
+
+void AllocTable::resize( unsigned long newsize )
+{
+ unsigned oldsize = data.size();
+ data.resize( newsize );
+ if( newsize > oldsize )
+ for( unsigned i = oldsize; i<newsize; i++ )
+ data[i] = Avail;
+}
+
+// make sure there're still free blocks
+void AllocTable::preserve( unsigned long n )
+{
+ std::vector<unsigned long> pre;
+ for( unsigned i=0; i < n; i++ )
+ pre.push_back( unused() );
+}
+
+unsigned long AllocTable::operator[]( unsigned long index )
+{
+ unsigned long result;
+ result = data[index];
+ return result;
+}
+
+void AllocTable::set( unsigned long index, unsigned long value )
+{
+ if( index >= count() ) resize( index + 1);
+ data[ index ] = value;
+}
+
+void AllocTable::setChain( std::vector<unsigned long> chain )
+{
+ if( chain.size() )
+ {
+ for( unsigned i=0; i<chain.size()-1; i++ )
+ set( chain[i], chain[i+1] );
+ set( chain[ chain.size()-1 ], AllocTable::Eof );
+ }
+}
+
+// follow
+std::vector<unsigned long> AllocTable::follow( unsigned long start )
+{
+ std::vector<unsigned long> chain;
+
+ if( start >= count() ) return chain;
+
+ unsigned long p = start;
+ while( p < count() )
+ {
+ if( p == (unsigned long)Eof ) break;
+ if( p == (unsigned long)Bat ) break;
+ if( p == (unsigned long)MetaBat ) break;
+ if( p >= count() ) break;
+ chain.push_back( p );
+ if( data[p] >= count() ) break;
+ p = data[ p ];
+ }
+
+ return chain;
+}
+
+unsigned AllocTable::unused()
+{
+ // find first available block
+ for( unsigned i = 0; i < data.size(); i++ )
+ if( data[i] == Avail )
+ return i;
+
+ // completely full, so enlarge the table
+ unsigned block = data.size();
+ resize( data.size()+10 );
+ return block;
+}
+
+void AllocTable::load( const unsigned char* buffer, unsigned len )
+{
+ resize( len / 4 );
+ for( unsigned i = 0; i < count(); i++ )
+ set( i, readU32( buffer + i*4 ) );
+}
+
+// return space required to save this dirtree
+unsigned AllocTable::size()
+{
+ return count() * 4;
+}
+
+void AllocTable::save( unsigned char* buffer )
+{
+ for( unsigned i = 0; i < count(); i++ )
+ writeU32( buffer + i*4, data[i] );
+}
+
+void AllocTable::debug()
+{
+ std::cout << "block size " << data.size() << std::endl;
+ for( unsigned i=0; i< data.size(); i++ )
+ {
+ if( data[i] == Avail ) continue;
+ std::cout << i << ": ";
+ if( data[i] == Eof ) std::cout << "[eof]";
+ else if( data[i] == Bat ) std::cout << "[bat]";
+ else if( data[i] == MetaBat ) std::cout << "[metabat]";
+ else std::cout << data[i];
+ std::cout << std::endl;
+ }
+}
+
+// =========== DirTree ==========
+
+const unsigned DirTree::End = 0xffffffff;
+
+DirTree::DirTree()
+{
+ clear();
+}
+
+void DirTree::clear()
+{
+ // leave only root entry
+ entries.resize( 1 );
+ entries[0].valid = true;
+ entries[0].name = "Root Entry";
+ entries[0].dir = true;
+ entries[0].size = 0;
+ entries[0].start = End;
+ entries[0].prev = End;
+ entries[0].next = End;
+ entries[0].child = End;
+}
+
+unsigned DirTree::entryCount()
+{
+ return entries.size();
+}
+
+DirEntry* DirTree::entry( unsigned index )
+{
+ if( index >= entryCount() ) return (DirEntry*) 0;
+ return &entries[ index ];
+}
+
+int DirTree::indexOf( DirEntry* e )
+{
+ for( unsigned i = 0; i < entryCount(); i++ )
+ if( entry( i ) == e ) return i;
+
+ return -1;
+}
+
+int DirTree::parent( unsigned index )
+{
+ // brute-force, basically we iterate for each entries, find its children
+ // and check if one of the children is 'index'
+ for( unsigned j=0; j<entryCount(); j++ )
+ {
+ std::vector<unsigned> chi = children( j );
+ for( unsigned i=0; i<chi.size();i++ )
+ if( chi[i] == index )
+ return j;
+ }
+
+ return -1;
+}
+
+std::string DirTree::fullName( unsigned index )
+{
+ // don't use root name ("Root Entry"), just give "/"
+ if( index == 0 ) return "/";
+
+ std::string result = entry( index )->name;
+ result.insert( 0, "/" );
+ int p = parent( index );
+ DirEntry * _entry = 0;
+ while( p > 0 )
+ {
+ _entry = entry( p );
+ if (_entry->dir && _entry->valid)
+ {
+ result.insert( 0, _entry->name);
+ result.insert( 0, "/" );
+ }
+ --p;
+ index = p;
+ if( index <= 0 ) break;
+ }
+ return result;
+}
+
+// given a fullname (e.g "/ObjectPool/_1020961869"), find the entry
+// if not found and create is false, return 0
+// if create is true, a new entry is returned
+DirEntry* DirTree::entry( const std::string& name, bool create )
+{
+ if( !name.length() ) return (DirEntry*)0;
+
+ // quick check for "/" (that's root)
+ if( name == "/" ) return entry( 0 );
+
+ // split the names, e.g "/ObjectPool/_1020961869" will become:
+ // "ObjectPool" and "_1020961869"
+ std::list<std::string> names;
+ std::string::size_type start = 0, end = 0;
+ if( name[0] == '/' ) start++;
+ while( start < name.length() )
+ {
+ end = name.find_first_of( '/', start );
+ if( end == std::string::npos ) end = name.length();
+ names.push_back( name.substr( start, end-start ) );
+ start = end+1;
+ }
+
+ // start from root
+ int index = 0 ;
+
+ // trace one by one
+ std::list<std::string>::iterator it;
+
+ for( it = names.begin(); it != names.end(); ++it )
+ {
+ // find among the children of index
+ std::vector<unsigned> chi = children( index );
+ unsigned child = 0;
+ for( unsigned i = 0; i < chi.size(); i++ )
+ {
+ DirEntry* ce = entry( chi[i] );
+ if( ce )
+ if( ce->valid && ( ce->name.length()>1 ) )
+ if( ce->name == *it )
+ child = chi[i];
+ }
+
+ // traverse to the child
+ if( child > 0 ) index = child;
+ else
+ {
+ // not found among children
+ if( !create ) return (DirEntry*)0;
+
+ // create a new entry
+ unsigned parent = index;
+ entries.push_back( DirEntry() );
+ index = entryCount()-1;
+ DirEntry* e = entry( index );
+ e->valid = true;
+ e->name = *it;
+ e->dir = false;
+ e->size = 0;
+ e->start = 0;
+ e->child = End;
+ e->prev = End;
+ e->next = entry(parent)->child;
+ entry(parent)->child = index;
+ }
+ }
+
+ return entry( index );
+}
+
+// helper function: recursively find siblings of index
+void dirtree_find_siblings( DirTree* dirtree, std::vector<unsigned>& result,
+ unsigned index )
+{
+ DirEntry* e = dirtree->entry( index );
+ if( !e ) return;
+ if( !e->valid ) return;
+
+ // prevent infinite loop
+ for( unsigned i = 0; i < result.size(); i++ )
+ if( result[i] == index ) return;
+
+ // add myself
+ result.push_back( index );
+
+ // visit previous sibling, don't go infinitely
+ unsigned prev = e->prev;
+ if( ( prev > 0 ) && ( prev < dirtree->entryCount() ) )
+ {
+ for( unsigned i = 0; i < result.size(); i++ )
+ if( result[i] == prev ) prev = 0;
+ if( prev ) dirtree_find_siblings( dirtree, result, prev );
+ }
+
+ // visit next sibling, don't go infinitely
+ unsigned next = e->next;
+ if( ( next > 0 ) && ( next < dirtree->entryCount() ) )
+ {
+ for( unsigned i = 0; i < result.size(); i++ )
+ if( result[i] == next ) next = 0;
+ if( next ) dirtree_find_siblings( dirtree, result, next );
+ }
+}
+
+std::vector<unsigned> DirTree::children( unsigned index )
+{
+ std::vector<unsigned> result;
+
+ DirEntry* e = entry( index );
+ if( e ) if( e->valid && e->child < entryCount() )
+ dirtree_find_siblings( this, result, e->child );
+
+ return result;
+}
+
+void DirTree::load( unsigned char* buffer, unsigned size )
+{
+ entries.clear();
+
+ for( unsigned i = 0; i < size/128; i++ )
+ {
+ unsigned p = i * 128;
+
+ // would be < 32 if first char in the name isn't printable
+ unsigned prefix = 32;
+
+ // parse name of this entry, which stored as Unicode 16-bit
+ std::string name;
+ int name_len = readU16( buffer + 0x40+p );
+ if( name_len > 64 ) name_len = 64;
+ for( int j=0; ( buffer[j+p]) && (j<name_len); j+= 2 )
+ name.append( 1, buffer[j+p] );
+
+ // first char isn't printable ? remove it...
+ if( buffer[p] < 32 )
+ {
+ prefix = buffer[0];
+ name.erase( 0,1 );
+ }
+
+ // 2 = file (aka stream), 1 = directory (aka storage), 5 = root
+ unsigned type = buffer[ 0x42 + p];
+
+ DirEntry e;
+ e.valid = true;
+ e.name = name;
+ e.start = readU32( buffer + 0x74+p );
+ e.size = readU32( buffer + 0x78+p );
+ e.prev = readU32( buffer + 0x44+p );
+ e.next = readU32( buffer + 0x48+p );
+ e.child = readU32( buffer + 0x4C+p );
+ e.dir = ( type!=2 );
+
+ // sanity checks
+ if( (type != 2) && (type != 1 ) && (type != 5 ) ) e.valid = false;
+ if( name_len < 1 ) e.valid = false;
+
+ entries.push_back( e );
+ }
+}
+
+// return space required to save this dirtree
+unsigned DirTree::size()
+{
+ return entryCount() * 128;
+}
+
+void DirTree::save( unsigned char* buffer )
+{
+ memset( buffer, 0, size() );
+
+ // root is fixed as "Root Entry"
+ DirEntry* root = entry( 0 );
+ std::string name = "Root Entry";
+ for( unsigned j = 0; j < name.length(); j++ )
+ buffer[ j*2 ] = name[j];
+ writeU16( buffer + 0x40, name.length()*2 + 2 );
+ writeU32( buffer + 0x74, 0xffffffff );
+ writeU32( buffer + 0x78, 0 );
+ writeU32( buffer + 0x44, 0xffffffff );
+ writeU32( buffer + 0x48, 0xffffffff );
+ writeU32( buffer + 0x4c, root->child );
+ buffer[ 0x42 ] = 5;
+ buffer[ 0x43 ] = 1;
+
+ for( unsigned i = 1; i < entryCount(); i++ )
+ {
+ DirEntry* e = entry( i );
+ if( !e ) continue;
+ if( e->dir )
+ {
+ e->start = 0xffffffff;
+ e->size = 0;
+ }
+
+ // max length for name is 32 chars
+ std::string name = e->name;
+ if( name.length() > 32 )
+ name.erase( 32, name.length() );
+
+ // write name as Unicode 16-bit
+ for( unsigned j = 0; j < name.length(); j++ )
+ buffer[ i*128 + j*2 ] = name[j];
+
+ writeU16( buffer + i*128 + 0x40, name.length()*2 + 2 );
+ writeU32( buffer + i*128 + 0x74, e->start );
+ writeU32( buffer + i*128 + 0x78, e->size );
+ writeU32( buffer + i*128 + 0x44, e->prev );
+ writeU32( buffer + i*128 + 0x48, e->next );
+ writeU32( buffer + i*128 + 0x4c, e->child );
+ buffer[ i*128 + 0x42 ] = e->dir ? 1 : 2;
+ buffer[ i*128 + 0x43 ] = 1; // always black
+ }
+}
+
+void DirTree::debug()
+{
+ for( unsigned i = 0; i < entryCount(); i++ )
+ {
+ DirEntry* e = entry( i );
+ if( !e ) continue;
+ std::cout << i << ": ";
+ if( !e->valid ) std::cout << "INVALID ";
+ std::cout << e->name << " ";
+ if( e->dir ) std::cout << "(Dir) ";
+ else std::cout << "(File) ";
+ std::cout << e->size << " ";
+ std::cout << "s:" << e->start << " ";
+ std::cout << "(";
+ if( e->child == End ) std::cout << "-"; else std::cout << e->child;
+ std::cout << " ";
+ if( e->prev == End ) std::cout << "-"; else std::cout << e->prev;
+ std::cout << ":";
+ if( e->next == End ) std::cout << "-"; else std::cout << e->next;
+ std::cout << ")";
+ std::cout << std::endl;
+ }
+}
+
+// =========== StorageIO ==========
+
+StorageIO::StorageIO( Storage* st, const char* fname )
+{
+ storage = st;
+ filename = fname;
+ result = Storage::Ok;
+ opened = false;
+
+ header = new Header();
+ dirtree = new DirTree();
+ bbat = new AllocTable();
+ sbat = new AllocTable();
+
+ lastBlockIndex = 0;
+ lastBlockData = 0;
+
+ filesize = 0;
+ bbat->blockSize = 1 << header->b_shift;
+ sbat->blockSize = 1 << header->s_shift;
+}
+
+StorageIO::~StorageIO()
+{
+ if( opened ) close();
+
+ delete [] lastBlockData;
+ delete sbat;
+ delete bbat;
+ delete dirtree;
+ delete header;
+}
+
+bool StorageIO::open()
+{
+ // already opened ? close first
+ if( opened ) close();
+
+ load();
+
+ return result == Storage::Ok;
+}
+
+void StorageIO::load()
+{
+ unsigned char* buffer = 0;
+ unsigned long buflen = 0;
+ std::vector<unsigned long> blocks;
+
+ // open the file, check for error
+ result = Storage::OpenFailed;
+ file.open( filename.c_str(), std::ios::binary | std::ios::in );
+ if( !file.good() ) return;
+
+ // find size of input file
+ file.seekg( 0, std::ios::end );
+ filesize = file.tellg();
+
+ // load header
+ buffer = new unsigned char[512];
+ file.seekg( 0 );
+ file.read( (char*)buffer, 512 );
+ header->load( buffer );
+ delete[] buffer;
+
+ // check OLE magic id
+ result = Storage::NotOLE;
+ for( unsigned i=0; i<8; i++ )
+ if( header->id[i] != pole_magic[i] )
+ return;
+
+ // sanity checks
+ result = Storage::BadOLE;
+ if( !header->valid() ) return;
+ if( header->threshold != 4096 ) return;
+
+ // important block size
+ bbat->blockSize = 1 << header->b_shift;
+ sbat->blockSize = 1 << header->s_shift;
+
+ // find blocks allocated to store big bat
+ // the first 109 blocks are in header, the rest in meta bat
+ blocks.clear();
+ blocks.resize( header->num_bat );
+ for( unsigned i = 0; i < 109; i++ )
+ if( i >= header->num_bat ) break;
+ else blocks[i] = header->bb_blocks[i];
+ if( (header->num_bat > 109) && (header->num_mbat > 0) )
+ {
+ unsigned char* buffer2 = new unsigned char[ bbat->blockSize ];
+ unsigned k = 109;
+ unsigned mblock = header->mbat_start;
+ for( unsigned r = 0; r < header->num_mbat; r++ )
+ {
+ loadBigBlock( mblock, buffer2, bbat->blockSize );
+ for( unsigned s=0; s < bbat->blockSize-4; s+=4 )
+ {
+ if( k >= header->num_bat ) break;
+ else blocks[k++] = readU32( buffer2 + s );
+ }
+ mblock = readU32( buffer2 + bbat->blockSize-4 );
+ }
+ delete[] buffer2;
+ }
+
+ // load big bat
+ buflen = blocks.size()*bbat->blockSize;
+ if( buflen > 0 )
+ {
+ buffer = new unsigned char[ buflen ];
+ loadBigBlocks( blocks, buffer, buflen );
+ bbat->load( buffer, buflen );
+ delete[] buffer;
+ }
+
+ // load small bat
+ blocks.clear();
+ blocks = bbat->follow( header->sbat_start );
+ buflen = blocks.size()*bbat->blockSize;
+ if( buflen > 0 )
+ {
+ buffer = new unsigned char[ buflen ];
+ loadBigBlocks( blocks, buffer, buflen );
+ sbat->load( buffer, buflen );
+ delete[] buffer;
+ }
+
+ // load directory tree
+ blocks.clear();
+ blocks = bbat->follow( header->dirent_start );
+ buflen = blocks.size()*bbat->blockSize;
+ buffer = new unsigned char[ buflen ];
+ loadBigBlocks( blocks, buffer, buflen );
+ dirtree->load( buffer, buflen );
+ unsigned sb_start = readU32( buffer + 0x74 );
+ delete[] buffer;
+
+ // fetch block chain as data for small-files
+ sb_blocks = bbat->follow( sb_start ); // small files
+
+ // for troubleshooting, just enable this block
+#if 0
+ header->debug();
+ sbat->debug();
+ bbat->debug();
+ dirtree->debug();
+#endif
+
+ // so far so good
+ result = Storage::Ok;
+ opened = true;
+}
+
+void StorageIO::create()
+{
+ // std::cout << "Creating " << filename << std::endl;
+
+ file.open( filename.c_str(), std::ios::out|std::ios::binary );
+ if( !file.good() )
+ {
+ std::cerr << "Can't create " << filename << std::endl;
+ result = Storage::OpenFailed;
+ return;
+ }
+
+ // so far so good
+ opened = true;
+ result = Storage::Ok;
+}
+
+void StorageIO::flush()
+{
+ /* Note on Microsoft implementation:
+ - directory entries are stored in the last block(s)
+ - BATs are as second to the last
+ - Meta BATs are third to the last
+ */
+}
+
+void StorageIO::close()
+{
+ if( !opened ) return;
+
+ file.close();
+ opened = false;
+
+ std::list<Stream*>::iterator it;
+ for( it = streams.begin(); it != streams.end(); ++it )
+ delete *it;
+}
+
+StreamIO* StorageIO::streamIO( const std::string& name )
+{
+ // sanity check
+ if( !name.length() ) return (StreamIO*)0;
+
+ // search in the entries
+ DirEntry* entry = dirtree->entry( name );
+ //if( entry) std::cout << "FOUND\n";
+ if( !entry ) return (StreamIO*)0;
+ //if( !entry->dir ) std::cout << " NOT DIR\n";
+ if( entry->dir ) return (StreamIO*)0;
+
+ StreamIO* result = new StreamIO( this, entry );
+ result->fullName = name;
+
+ return result;
+}
+
+unsigned long StorageIO::loadBigBlocks( std::vector<unsigned long> blocks,
+ unsigned char* data, unsigned long maxlen )
+{
+ // sentinel
+ if( !data ) return 0;
+ if( !file.good() ) return 0;
+ if( blocks.size() < 1 ) return 0;
+ if( maxlen == 0 ) return 0;
+
+ // read block one by one, seems fast enough
+ unsigned long bytes = 0;
+ for( unsigned long i=0; (i < blocks.size() ) && ( bytes<maxlen ); i++ )
+ {
+ unsigned long block = blocks[i];
+ unsigned long pos = bbat->blockSize * ( block+1 );
+ unsigned long p = (bbat->blockSize < maxlen-bytes) ? bbat->blockSize : maxlen-bytes;
+ if( pos + p > filesize ) p = filesize - pos;
+ file.seekg( pos );
+ file.read( (char*)data + bytes, p );
+ bytes += p;
+ }
+
+ return bytes;
+}
+
+// this will avoid reading the same big block from the disk
+#define POLE_CACHE_BLOCK
+
+unsigned long StorageIO::loadBigBlock( unsigned long block,
+ unsigned char* data, unsigned long maxlen )
+{
+ // sentinel
+ if( !data ) return 0;
+ if( !file.good() ) return 0;
+
+#ifdef POLE_CACHE_BLOCK
+ // just before, we also did read this block
+ // so just reuse from cached data
+ if( block == lastBlockIndex )
+ if( lastBlockData) if( maxlen <= bbat->blockSize )
+ {
+ memcpy( data, lastBlockData, maxlen );
+ return maxlen;
+ }
+#endif
+
+ // wraps call for loadBigBlocks
+ std::vector<unsigned long> blocks;
+ blocks.resize( 1 );
+ blocks[0] = block;
+
+ unsigned long result = loadBigBlocks( blocks, data, maxlen );
+
+#ifdef POLE_CACHE_BLOCK
+ // save cached data for future use
+ if(maxlen == bbat->blockSize )
+ {
+ if( !lastBlockData )
+ lastBlockData = new unsigned char[bbat->blockSize];
+ memcpy(lastBlockData, data, bbat->blockSize);
+ lastBlockIndex = block;
+ }
+#endif
+
+ return result;
+}
+
+// return number of bytes which has been read
+unsigned long StorageIO::loadSmallBlocks( std::vector<unsigned long> blocks,
+ unsigned char* data, unsigned long maxlen )
+{
+ // sentinel
+ if( !data ) return 0;
+ if( !file.good() ) return 0;
+ if( blocks.size() < 1 ) return 0;
+ if( maxlen == 0 ) return 0;
+
+ // our own local buffer
+ unsigned char* buf = new unsigned char[ bbat->blockSize ];
+
+ // read small block one by one
+ unsigned long bytes = 0;
+ for( unsigned long i=0; ( i<blocks.size() ) && ( bytes<maxlen ); i++ )
+ {
+ unsigned long block = blocks[i];
+
+ // find where the small-block exactly is
+ unsigned long pos = block * sbat->blockSize;
+ unsigned long bbindex = pos / bbat->blockSize;
+ if( bbindex >= sb_blocks.size() ) break;
+
+ loadBigBlock( sb_blocks[ bbindex ], buf, bbat->blockSize );
+
+ // copy the data
+ unsigned offset = pos % bbat->blockSize;
+ unsigned long p = (maxlen-bytes < bbat->blockSize-offset ) ? maxlen-bytes : bbat->blockSize-offset;
+ p = (sbat->blockSize<p ) ? sbat->blockSize : p;
+ memcpy( data + bytes, buf + offset, p );
+ bytes += p;
+ }
+
+ delete[] buf;
+
+ return bytes;
+}
+
+unsigned long StorageIO::loadSmallBlock( unsigned long block,
+ unsigned char* data, unsigned long maxlen )
+{
+ // sentinel
+ if( !data ) return 0;
+ if( !file.good() ) return 0;
+
+ // wraps call for loadSmallBlocks
+ std::vector<unsigned long> blocks;
+ blocks.resize( 1 );
+ blocks.assign( 1, block );
+
+ return loadSmallBlocks( blocks, data, maxlen );
+}
+
+// =========== StreamIO ==========
+
+StreamIO::StreamIO( StorageIO* s, DirEntry* e)
+{
+ io = s;
+ entry = e;
+ eof = false;
+ fail = false;
+
+ m_pos = 0;
+
+ if( entry->size >= io->header->threshold )
+ blocks = io->bbat->follow( entry->start );
+ else
+ blocks = io->sbat->follow( entry->start );
+
+ // prepare cache
+ cache_pos = 0;
+ cache_size = 4096; // optimal ?
+ cache_data = new unsigned char[cache_size];
+ updateCache();
+}
+
+// FIXME tell parent we're gone
+StreamIO::~StreamIO()
+{
+ delete[] cache_data;
+}
+
+void StreamIO::seek( unsigned long pos )
+{
+ m_pos = pos;
+}
+
+unsigned long StreamIO::tell()
+{
+ return m_pos;
+}
+
+int StreamIO::getch()
+{
+ // past end-of-file ?
+ if( m_pos > entry->size ) return -1;
+
+ // need to update cache ?
+ if( !cache_size || ( m_pos < cache_pos ) ||
+ ( m_pos >= cache_pos + cache_size ) )
+ updateCache();
+
+ // something bad if we don't get good cache
+ if( !cache_size ) return -1;
+
+ int data = cache_data[m_pos - cache_pos];
+ m_pos++;
+
+ return data;
+}
+
+unsigned long StreamIO::read( unsigned long pos, unsigned char* data, unsigned long maxlen )
+{
+ // sanity checks
+ if( !data ) return 0;
+ if( maxlen == 0 ) return 0;
+
+ unsigned long totalbytes = 0;
+
+ if ( entry->size < io->header->threshold )
+ {
+ // small file
+ unsigned long index = pos / io->sbat->blockSize;
+
+ if( index >= blocks.size() ) return 0;
+
+ unsigned char* buf = new unsigned char[ io->sbat->blockSize ];
+ unsigned long offset = pos % io->sbat->blockSize;
+ while( totalbytes < maxlen )
+ {
+ if( index >= blocks.size() ) break;
+ io->loadSmallBlock( blocks[index], buf, io->bbat->blockSize );
+ unsigned long count = io->sbat->blockSize - offset;
+ if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
+ memcpy( data+totalbytes, buf + offset, count );
+ totalbytes += count;
+ offset = 0;
+ index++;
+ }
+ delete[] buf;
+
+ }
+ else
+ {
+ // big file
+ unsigned long index = pos / io->bbat->blockSize;
+
+ // sanity check
+ if( index >= blocks.size() ) return 0;
+
+ unsigned char* buf = new unsigned char[ io->bbat->blockSize ];
+ unsigned long offset = pos % io->bbat->blockSize;
+ while( totalbytes < maxlen )
+ {
+ if( index >= blocks.size() ) break;
+ io->loadBigBlock( blocks[index], buf, io->bbat->blockSize );
+ unsigned long count = io->bbat->blockSize - offset;
+ if( count > maxlen-totalbytes ) count = maxlen-totalbytes;
+ memcpy( data+totalbytes, buf + offset, count );
+ totalbytes += count;
+ index++;
+ offset = 0;
+ }
+ delete [] buf;
+
+ }
+
+ return totalbytes;
+}
+
+unsigned long StreamIO::read( unsigned char* data, unsigned long maxlen )
+{
+ unsigned long bytes = read( tell(), data, maxlen );
+ m_pos += bytes;
+ return bytes;
+}
+
+void StreamIO::updateCache()
+{
+ // sanity check
+ if( !cache_data ) return;
+
+ cache_pos = m_pos - ( m_pos % cache_size );
+ unsigned long bytes = cache_size;
+ if( cache_pos + bytes > entry->size ) bytes = entry->size - cache_pos;
+ cache_size = read( cache_pos, cache_data, bytes );
+}
+
+
+// =========== Storage ==========
+
+Storage::Storage( const char* filename )
+{
+ io = new StorageIO( this, filename );
+}
+
+Storage::~Storage()
+{
+ delete io;
+}
+
+int Storage::result()
+{
+ return io->result;
+}
+
+bool Storage::open()
+{
+ return io->open();
+}
+
+void Storage::close()
+{
+ io->close();
+}
+
+std::list<std::string> Storage::entries( const std::string& path )
+{
+ std::list<std::string> result;
+ DirTree* dt = io->dirtree;
+ DirEntry* e = dt->entry( path, false );
+ if( e && e->dir )
+ {
+ unsigned parent = dt->indexOf( e );
+ std::vector<unsigned> children = dt->children( parent );
+ for( unsigned i = 0; i < children.size(); i++ )
+ result.push_back( dt->entry( children[i] )->name );
+ }
+
+ return result;
+}
+
+bool Storage::isDirectory( const std::string& name )
+{
+ DirEntry* e = io->dirtree->entry( name, false );
+ return e ? e->dir : false;
+}
+
+// =========== Stream ==========
+
+Stream::Stream( Storage* storage, const std::string& name )
+{
+ io = storage->io->streamIO( name );
+}
+
+// FIXME tell parent we're gone
+Stream::~Stream()
+{
+ delete io;
+}
+
+std::string Stream::fullName()
+{
+ return io ? io->fullName : std::string();
+}
+
+unsigned long Stream::tell()
+{
+ return io ? io->tell() : 0;
+}
+
+void Stream::seek( unsigned long newpos )
+{
+ if( io ) io->seek( newpos );
+}
+
+unsigned long Stream::size()
+{
+ return io ? io->entry->size : 0;
+}
+
+int Stream::getch()
+{
+ return io ? io->getch() : 0;
+}
+
+unsigned long Stream::read( unsigned char* data, unsigned long maxlen )
+{
+ return io ? io->read( data, maxlen ) : 0;
+}
+
+bool Stream::eof()
+{
+ return io ? io->eof : false;
+}
+
+bool Stream::fail()
+{
+ return io ? io->fail : true;
+}
diff --git a/filters/kspread/excel/sidewinder/pole.h b/filters/kspread/excel/sidewinder/pole.h
new file mode 100644
index 000000000..61256b8f0
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/pole.h
@@ -0,0 +1,177 @@
+/* POLE - Portable C++ library to access OLE Storage
+ Copyright (C) 2002-2005 Ariya Hidayat <ariya@kde.org>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the authors nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef POLE_H
+#define POLE_H
+
+#include <string>
+#include <list>
+
+namespace POLE
+{
+
+class StorageIO;
+class Stream;
+class StreamIO;
+
+class Storage
+{
+ friend class Stream;
+ friend class StreamOut;
+
+public:
+
+ // for Storage::result()
+ enum { Ok, OpenFailed, NotOLE, BadOLE, UnknownError };
+
+ /**
+ * Constructs a storage with name filename.
+ **/
+ Storage( const char* filename );
+
+ /**
+ * Destroys the storage.
+ **/
+ ~Storage();
+
+ /**
+ * Opens the storage. Returns true if no error occurs.
+ **/
+ bool open();
+
+ /**
+ * Closes the storage.
+ **/
+ void close();
+
+ /**
+ * Returns the error code of last operation.
+ **/
+ int result();
+
+ /**
+ * Finds all stream and directories in given path.
+ **/
+ std::list<std::string> entries( const std::string& path = "/" );
+
+ /**
+ * Returns true if specified entry name is a directory.
+ */
+ bool isDirectory( const std::string& name );
+
+ /**
+ * Finds and returns a stream with the specified name.
+ * If reuse is true, this function returns the already created stream
+ * (if any). Otherwise it will create the stream.
+ *
+ * When errors occur, this function returns NULL.
+ *
+ * You do not need to delete the created stream, it will be handled
+ * automatically.
+ **/
+ Stream* stream( const std::string& name, bool reuse = true );
+ //Stream* stream( const std::string& name, int mode = Stream::ReadOnly, bool reuse = true );
+
+private:
+ StorageIO* io;
+
+ // no copy or assign
+ Storage( const Storage& );
+ Storage& operator=( const Storage& );
+
+};
+
+class Stream
+{
+ friend class Storage;
+ friend class StorageIO;
+
+public:
+
+ /**
+ * Creates a new stream.
+ */
+ // name must be absolute, e.g "/Workbook"
+ Stream( Storage* storage, const std::string& name );
+
+ /**
+ * Destroys the stream.
+ */
+ ~Stream();
+
+ /**
+ * Returns the full stream name.
+ */
+ std::string fullName();
+
+ /**
+ * Returns the stream size.
+ **/
+ unsigned long size();
+
+ /**
+ * Returns the current read/write position.
+ **/
+ unsigned long tell();
+
+ /**
+ * Sets the read/write position.
+ **/
+ void seek( unsigned long pos );
+
+ /**
+ * Reads a byte.
+ **/
+ int getch();
+
+ /**
+ * Reads a block of data.
+ **/
+ unsigned long read( unsigned char* data, unsigned long maxlen );
+
+ /**
+ * Returns true if the read/write position is past the file.
+ **/
+ bool eof();
+
+ /**
+ * Returns true whenever error occurs.
+ **/
+ bool fail();
+
+private:
+ StreamIO* io;
+
+ // no copy or assign
+ Stream( const Stream& );
+ Stream& operator=( const Stream& );
+};
+
+}
+
+#endif // POLE_H
diff --git a/filters/kspread/excel/sidewinder/sheet.cpp b/filters/kspread/excel/sidewinder/sheet.cpp
new file mode 100644
index 000000000..a0f757f8c
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/sheet.cpp
@@ -0,0 +1,450 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#include "cell.h"
+#include "sheet.h"
+#include "workbook.h"
+#include "ustring.h"
+
+#include <iostream>
+#include <map>
+
+namespace Swinder
+{
+
+class Sheet::Private
+{
+public:
+ Workbook* workbook;
+ UString name;
+
+ // hash to store cell, FIXME replace with quad-tree
+ std::map<unsigned,Cell*> cells;
+ unsigned maxRow;
+ unsigned maxColumn;
+ std::map<unsigned,Column*> columns;
+ std::map<unsigned,Row*> rows;
+
+ bool visible;
+ bool protect;
+
+ UString leftHeader;
+ UString centerHeader;
+ UString rightHeader;
+ UString leftFooter;
+ UString centerFooter;
+ UString rightFooter;
+
+ double leftMargin;
+ double rightMargin;
+ double topMargin;
+ double bottomMargin;
+};
+
+}
+
+using namespace Swinder;
+
+Sheet::Sheet( Workbook* wb )
+{
+ d = new Sheet::Private();
+ d->workbook = wb;
+ d->name = "Sheet"; // FIXME better name ?
+ d->maxRow = 0;
+ d->maxColumn = 0;
+ d->visible = true;
+ d->protect = false;
+ d->leftMargin = 54; // 0.75 inch
+ d->rightMargin = 54; // 0.75 inch
+ d->topMargin = 72; // 1 inch
+ d->bottomMargin = 72; // 1 inch
+}
+
+Sheet::~Sheet()
+{
+ clear();
+ delete d;
+}
+
+Workbook* Sheet::workbook()
+{
+ return d->workbook;
+}
+
+void Sheet::clear()
+{
+ // delete all cells
+ std::map<unsigned,Cell*>::iterator cell_it;
+ for( cell_it = d->cells.begin(); cell_it != d->cells.end(); ++cell_it )
+ delete cell_it->second;
+
+ // delete all columns
+ std::map<unsigned,Column*>::iterator col_it;
+ for( col_it = d->columns.begin(); col_it != d->columns.end(); ++col_it )
+ delete col_it->second;
+
+ // delete all rows
+ std::map<unsigned,Row*>::iterator row_it;
+ for( row_it = d->rows.begin(); row_it != d->rows.end(); ++row_it )
+ delete row_it->second;
+}
+
+UString Sheet::name() const
+{
+ return d->name;
+}
+
+void Sheet::setName( const UString& name )
+{
+ d->name = name;
+}
+
+Cell* Sheet::cell( unsigned columnIndex, unsigned rowIndex, bool autoCreate )
+{
+ unsigned hashed = (rowIndex+1)*1024 + columnIndex + 1;
+ Cell* c = d->cells[ hashed ];
+
+ // create cell if necessary
+ if( !c && autoCreate )
+ {
+ c = new Cell( this, columnIndex, rowIndex );
+ d->cells[ hashed ] = c;
+
+ // force creating the column and row
+ this->column( columnIndex, true );
+ this->row( rowIndex, true );
+
+ if( rowIndex > d->maxRow ) d->maxRow = rowIndex;
+ if( columnIndex > d->maxColumn ) d->maxColumn = columnIndex;
+ }
+
+ return c;
+}
+
+Column* Sheet::column( unsigned index, bool autoCreate )
+{
+ Column* c = d->columns[ index ];
+
+ // create column if necessary
+ if( !c && autoCreate )
+ {
+ c = new Column( this, index );
+ d->columns[ index ] = c;
+ if( index > d->maxColumn ) d->maxColumn = index;
+ }
+
+ return c;
+}
+
+Row* Sheet::row( unsigned index, bool autoCreate )
+{
+ Row* r = d->rows[ index ];
+
+ // create row if necessary
+ if( !r && autoCreate )
+ {
+ r = new Row( this, index );
+ d->rows[ index ] = r;
+ if( index > d->maxRow ) d->maxRow = index;
+ }
+
+ return r;
+}
+
+unsigned Sheet::maxRow() const
+{
+ return d->maxRow;
+}
+
+unsigned Sheet::maxColumn() const
+{
+ return d->maxColumn;
+}
+
+bool Sheet::visible() const
+{
+ return d->visible;
+}
+
+void Sheet::setVisible( bool v )
+{
+ d->visible = v;
+}
+
+bool Sheet::protect() const
+{
+ return d->protect;
+}
+
+void Sheet::setProtect( bool p )
+{
+ d->protect = p;
+}
+
+UString Sheet::leftHeader() const
+{
+ return d->leftHeader;
+}
+
+void Sheet::setLeftHeader( const UString& h )
+{
+ d->leftHeader = h;
+}
+
+UString Sheet::centerHeader() const
+{
+ return d->centerHeader;
+}
+
+void Sheet::setCenterHeader( const UString& h )
+{
+ d->centerHeader = h;
+}
+
+UString Sheet::rightHeader() const
+{
+ return d->rightHeader;
+}
+
+void Sheet::setRightHeader( const UString& h )
+{
+ d->rightHeader = h;
+}
+
+UString Sheet::leftFooter() const
+{
+ return d->leftFooter;
+}
+
+void Sheet::setLeftFooter( const UString& h )
+{
+ d->leftFooter = h;
+}
+
+UString Sheet::centerFooter() const
+{
+ return d->centerFooter;
+}
+
+void Sheet::setCenterFooter( const UString& h )
+{
+ d->centerFooter = h;
+}
+
+UString Sheet::rightFooter() const
+{
+ return d->rightFooter;
+}
+
+void Sheet::setRightFooter( const UString& h )
+{
+ d->rightFooter = h;
+}
+
+double Sheet::leftMargin() const
+{
+ return d->leftMargin;
+}
+
+void Sheet::setLeftMargin( double m )
+{
+ d->leftMargin = m;
+}
+
+double Sheet::rightMargin() const
+{
+ return d->rightMargin;
+}
+
+void Sheet::setRightMargin( double m )
+{
+ d->rightMargin = m;
+}
+
+double Sheet::topMargin() const
+{
+ return d->topMargin;
+}
+
+void Sheet::setTopMargin( double m )
+{
+ d->topMargin = m;
+}
+
+double Sheet::bottomMargin() const
+{
+ return d->bottomMargin;
+}
+
+void Sheet::setBottomMargin( double m )
+{
+ d->bottomMargin = m;
+}
+
+class Column::Private
+{
+public:
+ Sheet* sheet;
+ unsigned index;
+ double width;
+ Format format;
+ bool visible;
+ int formatIndex;
+};
+
+Column::Column( Sheet* sheet, unsigned index )
+{
+ d = new Column::Private;
+ d->sheet = sheet;
+ d->index = index;
+ d->width = 10;
+ d->visible = true;
+ d->formatIndex = -1;
+}
+
+Column::~Column()
+{
+ delete d;
+}
+
+Sheet* Column::sheet() const
+{
+ return d->sheet;
+}
+
+unsigned Column::index() const
+{
+ return d->index;
+}
+
+double Column::width() const
+{
+ return d->width;
+}
+
+void Column::setWidth( double w )
+{
+ d->width = w;
+}
+
+int Column::formatIndex() const
+{
+ return d->formatIndex;
+}
+
+void Column::setFormatIndex( int index )
+{
+ d->formatIndex = index;
+}
+
+
+const Format& Column::format() const
+{
+ return d->format;
+}
+
+void Column::setFormat( const Format& f )
+{
+ d->format = f;
+}
+
+bool Column::visible() const
+{
+ return d->visible;
+}
+
+void Column::setVisible( bool b )
+{
+ d->visible = b;
+}
+
+class Row::Private
+{
+public:
+ Sheet* sheet;
+ unsigned index;
+ double height;
+ Format format;
+ bool visible;
+ int formatIndex;
+};
+
+Row::Row( Sheet* sheet, unsigned index )
+{
+ d = new Row::Private;
+ d->sheet = sheet;
+ d->index = index;
+ d->height = 10;
+ d->visible = true;
+}
+
+Row::~Row()
+{
+ delete d;
+}
+
+Sheet* Row::sheet() const
+{
+ return d->sheet;
+}
+
+unsigned Row::index() const
+{
+ return d->index;
+}
+
+double Row::height() const
+{
+ return d->height;
+}
+
+void Row::setHeight( double w )
+{
+ d->height = w;
+}
+
+int Row::formatIndex() const
+{
+ return d->formatIndex;
+}
+
+void Row::setFormatIndex( int index )
+{
+ d->formatIndex = index;
+}
+
+const Format& Row::format() const
+{
+ return d->format;
+}
+
+void Row::setFormat( const Format& f )
+{
+ d->format = f;
+}
+
+bool Row::visible() const
+{
+ return d->visible;
+}
+
+void Row::setVisible( bool b )
+{
+ d->visible = b;
+}
diff --git a/filters/kspread/excel/sidewinder/sheet.h b/filters/kspread/excel/sidewinder/sheet.h
new file mode 100644
index 000000000..f3f621725
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/sheet.h
@@ -0,0 +1,216 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#ifndef SWINDER_SHEET_H
+#define SWINDER_SHEET_H
+
+#include "ustring.h"
+#include "format.h"
+
+namespace Swinder
+{
+
+class Workbook;
+class Cell;
+class Column;
+class Row;
+
+class Sheet
+{
+public:
+
+ Sheet( Workbook* workbook );
+
+ virtual ~Sheet();
+
+ // get workbook that owns this sheet
+ Workbook* workbook();
+
+ /*
+ * Clears the sheet, i.e. makes it as if it is just constructed.
+ */
+ void clear();
+
+ void setName( const UString& name );
+
+ UString name() const;
+
+ // return cell at specified column and row
+ // automatically create the cell if previously there is no cell there
+ // return NULL if no cell there _and_ autoCreate is false
+ // first column (A) is 0, first row is 0
+ Cell* cell( unsigned column, unsigned row, bool autoCreate = true );
+
+ Column* column( unsigned index, bool autoCreate = true );
+
+ Row* row( unsigned index, bool autoCreate = true );
+
+ bool visible() const;
+ void setVisible( bool v );
+
+ bool protect() const;
+ void setProtect( bool p );
+
+ /*
+ * &P current page number
+ * &D current date
+ * &T current time
+ * &A sheet name
+ * &F file name without path
+ * &Z file path without file name
+ * &G picture
+ * &B bold on/off
+ * &I italic on/off
+ * &U underlining on/off
+ * &E double underlining on/off
+ * &S strikeout on/off
+ * &X superscript on/off
+ * &Y subscript on/off
+ *
+ * &"<fontname>" set font name
+ * &"<fontname>,<fontstyle>" set font name and style
+ * &<fontheight> set font height
+
+ */
+
+ UString leftHeader() const;
+ void setLeftHeader( const UString& h );
+ UString centerHeader() const;
+ void setCenterHeader( const UString& h );
+ UString rightHeader() const;
+ void setRightHeader( const UString& h );
+
+ UString leftFooter() const;
+ void setLeftFooter( const UString& f );
+ UString centerFooter() const;
+ void setCenterFooter( const UString& f );
+ UString rightFooter() const;
+ void setRightFooter( const UString& f );
+
+ // left margin, in points (pt)
+ double leftMargin() const;
+ void setLeftMargin( double m );
+
+ // right margin, in points (pt)
+ double rightMargin() const;
+ void setRightMargin( double m );
+
+ // top margin, in points (pt)
+ double topMargin() const;
+ void setTopMargin( double m );
+
+ // bottom margin, in points (pt)
+ double bottomMargin() const;
+ void setBottomMargin( double m );
+
+ unsigned maxRow() const;
+ unsigned maxColumn() const;
+
+private:
+ // no copy or assign
+ Sheet( const Sheet& );
+ Sheet& operator=( const Sheet& );
+
+ class Private;
+ Private *d;
+};
+
+class Column
+{
+public:
+
+ Column( Sheet* sheet, unsigned index );
+
+ virtual ~Column();
+
+ Sheet* sheet() const;
+
+ unsigned index() const;
+
+ // width of column, in pt
+ double width() const;
+
+ // set the width of column, in pt
+ void setWidth( double w );
+
+ const Format& format() const;
+
+ void setFormat( const Format& f );
+
+ void setFormatIndex( int index );
+
+ int formatIndex() const;
+
+ bool visible() const;
+
+ void setVisible( bool v );
+
+private:
+ // no copy or assign
+ Column( const Column& );
+ Column& operator=( const Column& );
+
+ class Private;
+ Private *d;
+};
+
+class Row
+{
+public:
+
+ Row( Sheet* sheet, unsigned index );
+
+ virtual ~Row();
+
+ Sheet* sheet() const;
+
+ unsigned index() const;
+
+ // height of row, in pt
+ double height() const;
+
+ // set the height of row, in pt
+ void setHeight( double w );
+
+ const Format& format() const;
+
+ void setFormat( const Format& f );
+
+ void setFormatIndex( int index );
+
+ int formatIndex() const;
+
+ bool visible() const;
+
+ void setVisible( bool v );
+
+private:
+ // no copy or assign
+ Row( const Row& );
+ Row& operator=( const Row& );
+
+ class Private;
+ Private *d;
+};
+
+
+}
+
+#endif // SWINDER_SHEET_H
+
diff --git a/filters/kspread/excel/sidewinder/swinder.h b/filters/kspread/excel/sidewinder/swinder.h
new file mode 100644
index 000000000..4fd314b4f
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/swinder.h
@@ -0,0 +1,11 @@
+#ifndef SWINDER_H
+#define SWINDER_H
+
+#include "ustring.h"
+#include "format.h"
+#include "value.h"
+#include "cell.h"
+#include "sheet.h"
+#include "workbook.h"
+
+#endif // SWINDER_H
diff --git a/filters/kspread/excel/sidewinder/ustring.cpp b/filters/kspread/excel/sidewinder/ustring.cpp
new file mode 100644
index 000000000..304fed18d
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/ustring.cpp
@@ -0,0 +1,611 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "ustring.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+using namespace Swinder;
+
+UChar UChar::null;
+UString::Rep UString::Rep::null = { 0, 0, 1, 0 };
+UString UString::null;
+static char *statBuffer = 0L;
+
+UChar::UChar(const UCharReference &c)
+ : uc( c.unicode() )
+{
+}
+
+UCharReference& UCharReference::operator=(UChar c)
+{
+ str->detach();
+ if (offset < str->rep->len)
+ *(str->rep->dat + offset) = c;
+ /* TODO: lengthen string ? */
+ return *this;
+}
+
+UChar& UCharReference::ref() const
+{
+ if (offset < str->rep->len)
+ return *(str->rep->dat + offset);
+ else
+ {
+ static UChar nullRef('\0');
+ return nullRef;
+ }
+}
+
+namespace {
+ // return an uninitialized UChar array of size s
+ static inline UChar* allocateChars(int s)
+ {
+ // work around default UChar constructor code
+ return reinterpret_cast<UChar*>(new short[s]);
+ }
+}
+
+
+UString::Rep *UString::Rep::create(UChar *d, int l)
+{
+ Rep *r = new Rep;
+ r->dat = d;
+ r->len = l;
+ r->cap = l;
+ r->rc = 1;
+
+ return r;
+}
+
+UString::Rep *UString::Rep::create(UChar *d, int l, int c)
+{
+ Rep *r = new Rep;
+ r->dat = d;
+ r->len = l;
+ r->cap = c;
+ r->rc = 1;
+
+ return r;
+}
+
+UString::UString()
+{
+ null.rep = &Rep::null;
+ attach(&Rep::null);
+}
+
+UString::UString(char c)
+{
+ UChar *d = allocateChars( 1 );
+ d[0] = UChar(0, c);
+ rep = Rep::create(d, 1);
+}
+
+UString::UString(UChar c)
+{
+ UChar *d = allocateChars( 1 );
+ d[0] = c;
+ rep = Rep::create(d, 1);
+}
+
+UString::UString(const char *c)
+{
+ attach(&Rep::null);
+ operator=(c);
+}
+
+UString::UString(const UChar *c, int length)
+{
+ UChar *d = allocateChars( length );
+ memcpy(d, c, length * sizeof(UChar));
+ rep = Rep::create(d, length);
+}
+
+UString::UString(UChar *c, int length, bool copy)
+{
+ UChar *d;
+ if (copy) {
+ d = allocateChars( length );
+ memcpy(d, c, length * sizeof(UChar));
+ } else
+ d = c;
+ rep = Rep::create(d, length);
+}
+
+UString::UString(const UString &b)
+{
+ attach(b.rep);
+}
+
+// NOTE: this is private, be careful when using it !
+UString::UString(Rep *r): rep(r)
+{
+}
+
+
+UString::~UString()
+{
+ release();
+}
+
+UString UString::number(int i)
+{
+#if 0
+ // standard and safe way
+ char buf[1+sizeof(int)*3];
+ snprintf(buf, sizeof(int)*3, "%d", i);
+ buf[sizeof(int)*3] = '\0';
+ return UString(buf);
+#else
+ // micro-optimized version
+ static unsigned short digits[] =
+ { '9', '8', '7', '6', '5', '4', '3', '2', '1',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
+
+ UString::Rep* rep = 0;
+
+ if(i == 0)
+ {
+ UChar* buf = allocateChars(1);
+ buf[0] = '0';
+ rep = Rep::create(buf, 1);
+ }
+ else
+ {
+ bool neg = (i < 0);
+ int ndig = 1 + sizeof(int)*3;
+
+ UChar* buf = allocateChars(ndig);
+ UChar* ptr = buf + ndig - 1;
+ int len = (neg) ? 1 : 0;
+
+ // construct all the digits
+ for(; i != 0; i/=10, len++)
+ *ptr-- = digits[9+i%10];
+
+ if(neg)
+ *ptr-- = '-';
+
+ // shift, don't use memcpy because overlapping area
+ memmove(buf, ptr+1, len*sizeof(unsigned short));
+
+ rep = Rep::create(buf, len, ndig);
+ }
+
+ return UString(rep);
+#endif
+}
+
+UString UString::number(unsigned int u)
+{
+#if 0
+ // standard and safe way
+ char buf[1+sizeof(unsigned int)*3];
+ snprintf(buf, sizeof(unsigned int)*3, "%d", u);
+ buf[sizeof(int)*3] = '\0';
+ return UString(buf);
+#else
+ // micro-optimized version
+ static unsigned short digits[] =
+ { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
+
+ UString::Rep* rep = 0;
+
+ if(u < 10)
+ {
+ UChar* buf = allocateChars(1);
+ buf[0] = digits[u];
+ rep = Rep::create(buf, 1);
+ }
+ else
+ {
+ int ndig = 1 + sizeof(int)*3;
+ UChar* buf = allocateChars(ndig);
+ UChar* ptr = buf + ndig - 1;
+ int len = 0;
+
+ // construct all the digits
+ for(; u != 0; u/=10, len++)
+ *ptr-- = digits[u%10];
+
+ // shift, don't use memcpy because overlapping area
+ memmove(buf, ptr+1, len*sizeof(unsigned short));
+
+ rep = Rep::create(buf, len, ndig);
+ }
+
+ return UString(rep);
+#endif
+}
+
+UString UString::number(double d)
+{
+ char buf[40];
+ snprintf(buf, 39, "%.16g", d);
+ buf[sizeof(int)*3] = '\0';
+ return UString(buf);
+}
+
+void UString::truncate(int n)
+{
+ if((n >= 0) && (n < length()))
+ {
+ detach();
+ rep->len = n;
+ }
+}
+
+void UString::reserve(int r)
+{
+ if(r > length())
+ {
+ int l = length();
+ UChar* n = allocateChars( r );
+ memcpy(n, data(), l * sizeof(UChar));
+ release();
+ rep = Rep::create(n, l, r);
+ }
+}
+
+UString &UString::append(const UString &t)
+{
+ int tl = t.length();
+ if(tl > 0)
+ {
+ detach();
+ int l = length();
+
+ // no space, we have to reallocate first
+ if(capacity() < tl + l)
+ reserve(tl +l);
+
+ UChar *dd = rep->data();
+ memcpy(dd+l, t.data(), tl * sizeof(UChar));
+ rep->len += tl;
+ }
+
+ return *this;
+}
+
+UString &UString::append(const char* s)
+{
+ int tl = strlen(s);
+ if(tl > 0)
+ {
+ detach();
+ int l = length();
+
+ // no space, we have to reallocate first
+ if(capacity() < tl + l)
+ reserve(tl +l);
+
+ // copy each character
+ UChar *dd = rep->data();
+ for (int i = 0; i < tl; i++)
+ dd[l+i].uc = static_cast<unsigned char>( s[i] );
+ rep->len += tl;
+ }
+
+ return *this;
+}
+
+UString &UString::append(UChar c)
+{
+ detach();
+ int l = length();
+
+ // we need to reallocate
+ // in case another append follows, so let's reserve()
+ // this avoids subsequent expensive reallocation
+ if(capacity() < l + 1)
+ reserve(l + 8);
+
+ UChar *dd = rep->data();
+ dd[l] = c;
+ rep->len++;
+
+ return *this;
+}
+
+UString &UString::append(char c)
+{
+ return append( UChar((unsigned short)c) );
+}
+
+
+UString &UString::prepend(const UString &t)
+{
+ int tl = t.length();
+ if(tl > 0)
+ {
+ int l = length();
+
+ // no space, we have to reallocate first
+ if(capacity() < tl + l)
+ reserve(tl +l);
+
+ // shift the string, then place the new string
+ UChar *dd = rep->data();
+ for(int i = l-1; i >= 0; i--)
+ dd[i+tl] = dd[i];
+ memcpy(dd, t.data(), tl * sizeof(UChar));
+ rep->len += tl;
+ }
+
+ return *this;
+}
+
+UString &UString::prepend(const char* s)
+{
+ int tl = strlen(s);
+ if(tl > 0)
+ {
+ int l = length();
+
+ // no space, we have to reallocate first
+ if(capacity() < tl + l)
+ reserve(tl +l);
+
+ // shift the string, then copy each new character
+ UChar *dd = rep->data();
+ for(int i = l-1; i >= 0; i--)
+ dd[i+tl] = dd[i];
+ for(int j = 0; j < tl; j++)
+ dd[j].uc = static_cast<unsigned char>( s[j] );
+ rep->len += tl;
+ }
+
+ return *this;
+}
+
+UString &UString::prepend(UChar c)
+{
+ int l = length();
+
+ // we need to reallocate and reserve
+ // see also append(UChar c) function
+ if(capacity() < l + 1)
+ reserve(l + 8);
+
+ UChar *dd = rep->data();
+ for(int i = l-1; i >= 0; i--)
+ dd[i+1] = dd[i];
+ dd[0] = c;
+ rep->len++;
+
+ return *this;
+}
+
+UString &UString::prepend(char c)
+{
+ return prepend( UChar((unsigned short)c) );
+}
+
+char *UString::ascii() const
+{
+ if (statBuffer)
+ delete [] statBuffer;
+
+ statBuffer = new char[length()+1];
+ for(int i = 0; i < length(); i++)
+ statBuffer[i] = data()[i].low();
+ statBuffer[length()] = '\0';
+
+ return statBuffer;
+}
+
+UString &UString::operator=(const char *c)
+{
+ release();
+ int l = c ? strlen(c) : 0;
+ UChar *d = allocateChars( l );
+ for (int i = 0; i < l; i++)
+ d[i].uc = static_cast<unsigned char>( c[i] );
+ rep = Rep::create(d, l);
+
+ return *this;
+}
+
+UString &UString::operator=(const UString &str)
+{
+ str.rep->ref();
+ release();
+ rep=str.rep;
+
+ return *this;
+}
+
+UString &UString::operator+=(const UString &s)
+{
+ return append(s);
+}
+
+bool UString::is8Bit() const
+{
+ const UChar *u = data();
+ for(int i = 0; i < length(); i++, u++)
+ if (u->uc > 0xFF)
+ return false;
+
+ return true;
+}
+
+UChar UString::operator[](int pos) const
+{
+ if (pos >= length())
+ return UChar::null;
+
+ return static_cast<const UChar *>( data() )[pos];
+}
+
+UCharReference UString::operator[](int pos)
+{
+ /* TODO: boundary check */
+ return UCharReference(this, pos);
+}
+
+UString UString::substr(int pos, int len) const
+{
+ if (isNull())
+ return UString();
+ if (pos < 0)
+ pos = 0;
+ else if (pos >= static_cast<int>( length() ))
+ pos = length();
+ if (len < 0)
+ len = length();
+ if (pos + len >= static_cast<int>( length() ))
+ len = length() - pos;
+
+ UChar *tmp = allocateChars( len );
+ memcpy(tmp, data()+pos, len * sizeof(UChar));
+ UString result(tmp, len);
+ delete [] tmp;
+
+ return result;
+}
+
+int UString::find(const UString &f, int pos) const
+{
+ if (isNull())
+ return -1;
+ long fsize = f.length() * sizeof(UChar);
+ if (pos < 0)
+ pos = 0;
+ const UChar *end = data() + length() - f.length();
+ for (const UChar *c = data() + pos; c <= end; c++)
+ if (!memcmp(c, f.data(), fsize))
+ return (c-data());
+
+ return -1;
+}
+
+void UString::attach(Rep *r)
+{
+ rep = r;
+ rep->ref();
+}
+
+void UString::detach()
+{
+ if (rep->rc > 1)
+ {
+ int c = capacity();
+ int l = length();
+ UChar *n = allocateChars( c );
+ memcpy(n, data(), l * sizeof(UChar));
+ release();
+ rep = Rep::create(n, l, c);
+ }
+}
+
+void UString::release()
+{
+ if (!rep->deref())
+ {
+ delete [] rep->dat;
+ delete rep;
+ }
+}
+
+bool Swinder::operator==(const UString& s1, const UString& s2)
+{
+ if (s1.rep->len != s2.rep->len)
+ return false;
+
+ return (memcmp(s1.rep->dat, s2.rep->dat,
+ s1.rep->len * sizeof(UChar)) == 0);
+}
+
+bool Swinder::operator==(const UString& s1, const char *s2)
+{
+ if (s2 == 0L)
+ return s1.isEmpty();
+
+ if (s1.length() != static_cast<int>( strlen(s2) ))
+ return false;
+
+ const UChar *u = s1.data();
+ while (*s2)
+ {
+ if (u->uc != *s2 )
+ return false;
+ s2++;
+ u++;
+ }
+
+ return true;
+}
+
+bool Swinder::operator<(const UString& s1, const UString& s2)
+{
+ const int l1 = s1.length();
+ const int l2 = s2.length();
+ const int lmin = l1 < l2 ? l1 : l2;
+ const UChar *c1 = s1.data();
+ const UChar *c2 = s2.data();
+ int l = 0;
+ while (l < lmin && *c1 == *c2)
+ {
+ c1++;
+ c2++;
+ l++;
+ }
+ if (l < lmin)
+ return (c1->unicode() < c2->unicode());
+
+ return (l1 < l2);
+}
+
+UString Swinder::operator+(const UString& s1, const UString& s2)
+{
+ UString tmp(s1);
+ tmp.append(s2);
+
+ return tmp;
+}
+
+
+UConstString::UConstString( UChar* data, unsigned int length ) :
+UString( data, length, false )
+{
+}
+
+UConstString::~UConstString()
+{
+ if ( rep->rc > 1 ) {
+ int l = length();
+ UChar* n = allocateChars( l );
+ memcpy( n, data(), l * sizeof( UChar ) );
+ rep->dat = n;
+ }
+ else
+ rep->dat = 0;
+}
diff --git a/filters/kspread/excel/sidewinder/ustring.h b/filters/kspread/excel/sidewinder/ustring.h
new file mode 100644
index 000000000..04600003a
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/ustring.h
@@ -0,0 +1,385 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SWINDER_USTRING_H_
+#define SWINDER_USTRING_H_
+
+namespace Swinder {
+
+ class UCharReference;
+ class UString;
+ class UConstString;
+
+ /**
+ * @short Unicode character.
+ *
+ * UChar represents a 16 bit Unicode character. It's internal data
+ * representation is compatible to XChar2b and QChar. It's therefore
+ * possible to exchange data with X and Qt with shallow copies.
+ */
+ struct UChar {
+ /**
+ * Construct a character with value 0.
+ */
+ UChar();
+ /**
+ * Construct a character with the value denoted by the arguments.
+ * @param h higher byte
+ * @param l lower byte
+ */
+ UChar(unsigned char h , unsigned char l);
+ /**
+ * Construct a character with the given value.
+ * @param u 16 bit Unicode value
+ */
+ UChar(unsigned short u);
+
+ UChar(unsigned char u);
+ UChar(char u);
+ UChar(unsigned int u);
+
+ UChar(const UCharReference &c);
+ /**
+ * @return The higher byte of the character.
+ */
+ unsigned char high() const { return uc >> 8; }
+ /**
+ * @return The lower byte of the character.
+ */
+ unsigned char low() const { return uc & 0xFF; }
+ /**
+ * @return the 16 bit Unicode value of the character
+ */
+ unsigned short unicode() const { return uc; }
+ public:
+ /**
+ * A static instance of UChar(0).
+ */
+ static UChar null;
+ private:
+ friend class UCharReference;
+ friend class UString;
+ friend bool operator==(const UChar &c1, const UChar &c2);
+ friend bool operator==(const UString& s1, const char *s2);
+ friend bool operator<(const UString& s1, const UString& s2);
+
+ unsigned short uc;
+ };
+
+ inline UChar::UChar() : uc(0) { }
+ inline UChar::UChar(unsigned char h , unsigned char l) : uc(h << 8 | l) { }
+ inline UChar::UChar(unsigned short u) : uc(u) { }
+ inline UChar::UChar(unsigned int u) : uc(u) { }
+ inline UChar::UChar(unsigned char u) : uc(u) { }
+ inline UChar::UChar(char u) : uc((unsigned char)u) { }
+
+ /**
+ * @short Dynamic reference to a string character.
+ *
+ * UCharReference is the dynamic counterpart of UChar. It's used when
+ * characters retrieved via index from a UString are used in an
+ * assignment expression (and therefore can't be treated as being const):
+ * \code
+ * UString s("hello world");
+ * s[0] = 'H';
+ * \endcode
+ *
+ * If that sounds confusing your best bet is to simply forget about the
+ * existence of this class and treat is as being identical to UChar.
+ */
+ class UCharReference {
+ friend class UString;
+ UCharReference(UString *s, unsigned int off) : str(s), offset(off) { }
+ public:
+ /**
+ * Set the referenced character to c.
+ */
+ UCharReference& operator=(UChar c);
+ /**
+ * Same operator as above except the argument that it takes.
+ */
+ UCharReference& operator=(char c) { return operator=(UChar(c)); }
+ /**
+ * @return Unicode value.
+ */
+ unsigned short unicode() const { return ref().uc; }
+ /**
+ * @return Lower byte.
+ */
+ unsigned char low() const { return ref().uc & 0xFF; }
+ /**
+ * @return Higher byte.
+ */
+ unsigned char high() const { return ref().uc >> 8; }
+ private:
+ // not implemented, can only be constructed from UString
+ UCharReference();
+
+ UChar& ref() const;
+ UString *str;
+ int offset;
+ };
+
+
+ /**
+ * @short Unicode string class
+ */
+ class UString {
+ friend bool operator==(const UString&, const UString&);
+ friend class UCharReference;
+ friend class UConstString;
+ /**
+ * @internal
+ */
+ struct Rep {
+ friend class UString;
+ friend bool operator==(const UString&, const UString&);
+ static Rep *create(UChar *d, int l);
+ static Rep *create(UChar *d, int l, int c);
+ inline UChar *data() const { return dat; }
+ inline int length() const { return len; }
+ inline int capacity() const { return cap; }
+
+ inline void ref() { rc++; }
+ inline int deref() { return --rc; }
+
+ UChar *dat;
+ int len;
+ int rc;
+ int cap;
+ static Rep null;
+ };
+
+ public:
+ /**
+ * Constructs a null string.
+ */
+ UString();
+ /**
+ * Constructs a string from the single character c.
+ */
+ explicit UString(char c);
+ /**
+ * Constructs a string from the single character c.
+ */
+ explicit UString(UChar c);
+ /**
+ * Constructs a string from a classical zero determined char string.
+ */
+ explicit UString(const char *c);
+ /**
+ * Constructs a string from an array of Unicode characters of the specified
+ * length.
+ */
+ UString(const UChar *c, int length);
+ /**
+ * If copy is false a shallow copy of the string will be created. That
+ * means that the data will NOT be copied and you'll have to guarantee that
+ * it doesn't get deleted during the lifetime of the UString object.
+ */
+ UString(UChar *c, int length, bool copy);
+ /**
+ * Copy constructor. Makes a shallow copy only.
+ */
+ UString(const UString &);
+ /**
+ * Destructor. If this handle was the only one holding a reference to the
+ * string the data will be freed.
+ */
+ ~UString();
+
+ /**
+ * Constructs a string from an int.
+ */
+ static UString number(int i);
+ /**
+ * Constructs a string from an unsigned int.
+ */
+ static UString number(unsigned int u);
+ /**
+ * Constructs a string from a floating-point value
+ */
+ static UString number(double d);
+
+ /**
+ * Append another string.
+ */
+ UString &append(const UString &);
+ /**
+ * Append a character
+ */
+ UString &append(UChar c);
+ /**
+ * Append zero-terminated string.
+ */
+ UString &append(const char*);
+ /**
+ * Append a single character
+ */
+ UString &append(char c);
+
+ /**
+ * Prepend another string.
+ */
+ UString &prepend(const UString &);
+ /**
+ * Prepend a character
+ */
+ UString &prepend(UChar c);
+ /**
+ * Prepend zero-terminated string.
+ */
+ UString &prepend(const char*);
+ /**
+ * Prepend a single character
+ */
+ UString &prepend(char c);
+
+ /**
+ * Convert the Unicode string to plain ASCII chars chopping of any higher
+ * bytes. This method should only be used for *debugging* purposes as it
+ * is neither Unicode safe nor free from side effects. In order not to
+ * waste any memory the char buffer is static and *shared* by all UString
+ * instances.
+ */
+ char *ascii() const;
+
+ /**
+ * Assignment operator.
+ */
+ UString &operator=(const char *c);
+ /**
+ * Assignment operator.
+ */
+ UString &operator=(const UString &);
+ /**
+ * Appends the specified string.
+ */
+ UString &operator+=(const UString &s);
+
+ /**
+ * @return A pointer to the internal Unicode data.
+ */
+ const UChar* data() const { return rep->data(); }
+ /**
+ * @return True if null.
+ */
+ bool isNull() const { return (rep == &Rep::null); }
+ /**
+ * @return True if null or zero length.
+ */
+ bool isEmpty() const { return (!rep->len); }
+ /**
+ * Use this if you want to make sure that this string is a plain ASCII
+ * string. For example, if you don't want to lose any information when
+ * using ascii().
+ *
+ * @return True if the string doesn't contain any non-ASCII characters.
+ */
+ bool is8Bit() const;
+ /**
+ * @return The length of the string.
+ */
+ int length() const { return rep->length(); }
+
+ /**
+ * Truncates the string to n. Nothing happens if n > length().
+ */
+ void truncate(int n);
+
+ /**
+ * @return The reserved capacity of the string.
+ */
+ int capacity() const { return rep->capacity(); }
+ /**
+ * Reserves room for the string, useful to speed up append().
+ */
+ void reserve(int r);
+
+ /**
+ * Const character at specified position.
+ */
+ UChar operator[](int pos) const;
+ /**
+ * Writable reference to character at specified position.
+ */
+ UCharReference operator[](int pos);
+
+
+ /**
+ * @return The sub string starting at position pos and length len.
+ */
+ UString substr(int pos = 0, int len = -1) const;
+
+ /**
+ * @return Position of first occurence of f starting at position pos.
+ * -1 if the search was not successful.
+ */
+ int find(const UString &f, int pos = 0) const;
+
+ /**
+ * Static instance of a null string.
+ */
+ static UString null;
+
+ private:
+ UString(Rep* r);
+ void attach(Rep *r);
+ void detach();
+ void release();
+ Rep *rep;
+ };
+
+ inline bool operator==(const UChar &c1, const UChar &c2) {
+ return (c1.uc == c2.uc);
+ }
+ inline bool operator!=(const UChar &c1, const UChar &c2) {
+ return !(c1 == c2);
+ }
+ bool operator==(const UString& s1, const UString& s2);
+ inline bool operator!=(const UString& s1, const UString& s2) {
+ return !Swinder::operator==(s1, s2);
+ }
+ bool operator<(const UString& s1, const UString& s2);
+ bool operator==(const UString& s1, const char *s2);
+ inline bool operator!=(const UString& s1, const char *s2) {
+ return !Swinder::operator==(s1, s2);
+ }
+ inline bool operator==(const char *s1, const UString& s2) {
+ return operator==(s2, s1);
+ }
+ inline bool operator!=(const char *s1, const UString& s2) {
+ return !Swinder::operator==(s1, s2);
+ }
+ UString operator+(const UString& s1, const UString& s2);
+
+
+ class UConstString : private UString {
+ public:
+ UConstString( UChar* data, unsigned int length );
+ ~UConstString();
+
+ const UString& string() const { return *this; }
+ };
+
+} // namespace SWINDER_USTRING_H
+
+#endif
diff --git a/filters/kspread/excel/sidewinder/value.cpp b/filters/kspread/excel/sidewinder/value.cpp
new file mode 100644
index 000000000..39aa6d53f
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/value.cpp
@@ -0,0 +1,391 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#include "value.h"
+#include "ustring.h"
+
+#include <iostream>
+
+namespace Swinder
+{
+
+// helper class for Value
+class ValueData
+{
+ public:
+
+ Value::Type type;
+
+ // someday move to use union to reduce memory consumption
+ bool b;
+ int i;
+ double f;
+ UString s;
+
+ // create empty data
+ ValueData(){
+ count = 0;
+ b = false;
+ i = 0;
+ f = 0.0;
+ s = UString::null;
+ type = Value::Empty;
+ ref();
+ };
+
+ // destroys data
+ ~ValueData(){
+ if( this == s_null ) s_null = 0;
+ }
+
+ void ref(){ count++; }
+
+ // static empty data to be shared
+ static ValueData* null()
+ { if( !s_null) s_null = new ValueData; else s_null->ref(); return s_null; }
+
+ // decrease reference count
+ void unref()
+ { --count; if( !count ) delete this; }
+
+ // true if it's null (which is shared)
+ bool isNull(){ return this == s_null; }
+
+ unsigned count; // reference count
+
+ private:
+
+ static ValueData* s_null;
+
+};
+
+}
+
+using namespace Swinder;
+
+// to be shared between all empty value
+ValueData* ValueData::s_null = 0;
+
+// static things
+Value ks_value_empty;
+Value ks_error_div0;
+Value ks_error_na;
+Value ks_error_name;
+Value ks_error_null;
+Value ks_error_num;
+Value ks_error_ref;
+Value ks_error_value;
+
+// create an empty value
+Value::Value()
+{
+ d = ValueData::null();
+}
+
+// destructor
+Value::~Value()
+{
+ d->unref();
+}
+
+// create value of certain type
+Value::Value( Value::Type _type )
+{
+ d = new ValueData;
+ d->type = _type;
+}
+
+// copy constructor
+Value::Value( const Value& _value )
+{
+ d = ValueData::null();
+ assign( _value );
+}
+
+// assignment operator
+Value& Value::operator=( const Value& _value )
+{
+ return assign( _value );
+}
+
+// create a boolean value
+Value::Value( bool b )
+{
+ d = ValueData::null();
+ setValue( b );
+}
+
+// create an integer value
+Value::Value( int i )
+{
+ d = ValueData::null();
+ setValue ( i );
+}
+
+// create a floating-point value
+Value::Value( double f )
+{
+ d = ValueData::null();
+ setValue( f );
+}
+
+// create a string value
+Value::Value( const UString& s )
+{
+ d = ValueData::null();
+ setValue( s );
+}
+
+// assign value from other
+// shallow copy: only copy the data pointer
+Value& Value::assign( const Value& _value )
+{
+ d->unref();
+ d = _value.d;
+ d->ref();
+ return *this;
+}
+
+// return type of the value
+Value::Type Value::type() const
+{
+ return d ? d->type : Empty;
+}
+
+// set the value to boolean
+void Value::setValue( bool b )
+{
+ detach();
+ d->type = Boolean;
+ d->b = b;
+}
+
+// get the value as boolean
+bool Value::asBoolean() const
+{
+ bool result = false;
+
+ if( type() == Value::Boolean )
+ result = d->b;
+
+ return result;
+}
+
+// set the value to integer
+void Value::setValue( int i )
+{
+ detach();
+ d->type = Integer;
+ d->i = i;
+}
+
+// get the value as integer
+int Value::asInteger() const
+{
+ int result = 0;
+
+ if( type() == Value::Integer )
+ result = d->i;
+
+ if( type() == Value::Float )
+ result = static_cast<int>(d->f);
+
+ return result;
+}
+
+void Value::setValue( const Value& v )
+{
+ assign( v );
+}
+
+// set the value as floating-point
+void Value::setValue( double f )
+{
+ detach();
+ d->type = Float;
+ d->f = f;
+}
+
+// get the value as floating-point
+double Value::asFloat() const
+{
+ double result = 0.0;
+
+ if( type() == Value::Float )
+ result = d->f;
+
+ if( type() == Value::Integer )
+ result = static_cast<double>(d->i);
+
+ return result;
+}
+
+// set the value as string
+void Value::setValue( const UString& s )
+{
+ detach();
+ d->type = String;
+ d->s = s;
+}
+
+// get the value as string
+UString Value::asString() const
+{
+ UString result;
+
+ if( type() == Value::String )
+ result = d->s;
+
+ return result;
+}
+
+// set error message
+void Value::setError( const UString& msg )
+{
+ detach();
+ d->type = Error;
+ d->s = msg;
+}
+
+// get error message
+UString Value::errorMessage() const
+{
+ UString result;
+
+ if( type() == Value::Error )
+ result = d->s;
+
+ return result;
+}
+
+// reference to empty value
+const Value& Value::empty()
+{
+ return ks_value_empty;
+}
+
+// reference to #DIV/0! error
+const Value& Value::errorDIV0()
+{
+ if( !ks_error_div0.isError() )
+ ks_error_div0.setError( UString("#DIV/0!") );
+ return ks_error_div0;
+}
+
+// reference to #N/A error
+const Value& Value::errorNA()
+{
+ if( !ks_error_na.isError() )
+ ks_error_na.setError( UString("#N/A") );
+ return ks_error_na;
+}
+
+// reference to #NAME? error
+const Value& Value::errorNAME()
+{
+ if( !ks_error_name.isError() )
+ ks_error_name.setError( UString("#NAME?") );
+ return ks_error_name;
+}
+
+// reference to #NUM! error
+const Value& Value::errorNUM()
+{
+ if( !ks_error_num.isError() )
+ ks_error_num.setError( UString("#NUM!") );
+ return ks_error_num;
+}
+
+// reference to #NULL! error
+const Value& Value::errorNULL()
+{
+ if( !ks_error_null.isError() )
+ ks_error_null.setError( UString("#NULL!") );
+ return ks_error_null;
+}
+
+// reference to #REF! error
+const Value& Value::errorREF()
+{
+ if( !ks_error_ref.isError() )
+ ks_error_ref.setError( UString("#REF!") );
+ return ks_error_ref;
+}
+
+// reference to #VALUE! error
+const Value& Value::errorVALUE()
+{
+ if( !ks_error_value.isError() )
+ ks_error_value.setError( UString("#VALUE!") );
+ return ks_error_value;
+}
+
+// detach, create deep copy of ValueData
+void Value::detach()
+{
+ if( d->isNull() || ( d->count > 1 ) )
+ {
+ ValueData* n;
+ n = new ValueData;
+
+ n->type = d->type;
+ switch( n->type )
+ {
+ case Empty: break;
+ case Boolean: n->b = d->b; break;
+ case Integer: n->i = d->i; break;
+ case Float: n->f = d->f; break;
+ case String: n->s = d->s; break;
+ case Error: n->s = d->s; break;
+ default: break;
+ }
+
+ d->unref();
+ d = n;
+ }
+}
+
+std::ostream& Swinder::operator<<( std::ostream& s, Swinder::Value value )
+{
+ switch( value.type() )
+ {
+ case Value::Empty:
+ s << "Empty";
+ break;
+ case Value::Boolean:
+ s << "Boolean: " << (value.asBoolean()?"True":"False");
+ break;
+ case Value::Integer:
+ s << "Integer: " << value.asInteger();
+ break;
+ case Value::Float:
+ s << "Float: " << value.asFloat();
+ break;
+ case Value::String:
+ s << "String: " << value.asString().ascii();
+ break;
+ case Value::Error:
+ s << "Error: " << value.errorMessage().ascii();
+ break;
+ default:
+ break;
+ };
+
+ return s;
+}
diff --git a/filters/kspread/excel/sidewinder/value.h b/filters/kspread/excel/sidewinder/value.h
new file mode 100644
index 000000000..5c9c2dbbd
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/value.h
@@ -0,0 +1,290 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#ifndef SWINDER_VALUE_H
+#define SWINDER_VALUE_H
+
+#include <iostream>
+#include "ustring.h"
+
+namespace Swinder
+{
+
+class ValueData;
+
+
+
+/**
+ * Provides a wrapper for cell value.
+ *
+ * Each cell in a worksheet must hold a value, either as enterred by user
+ * or as a result of formula evaluation. Default cell holds empty value.
+ *
+ * Value uses implicit data sharing to reduce memory usage.
+ */
+
+class Value
+{
+
+ public:
+
+ typedef enum {
+ Empty,
+ Boolean,
+ Integer,
+ Float,
+ String,
+ CellRange, // not used yet
+ Array, // not used yet
+ Error
+ } Type;
+
+ /**
+ * Creates an empty value, i.e holds nothing.
+ */
+ Value();
+
+ /**
+ * Creates a value of certain type.
+ */
+ Value( Type _type );
+
+ /**
+ * Destroys the value.
+ */
+ virtual ~Value();
+
+ /**
+ * Creates a copy from another value.
+ */
+ Value( const Value& _value );
+
+ /**
+ * Assigns from another value.
+ *
+ * Because the data is implicitly shared, such assignment is very fast and
+ * doesn't consume additional memory.
+ */
+ Value& operator= ( const Value& _value );
+
+ /**
+ * Assigns from another value. Same as above.
+ */
+ Value& assign( const Value& _value );
+
+ /**
+ * Creates a boolean value.
+ */
+ Value( bool b );
+
+ /**
+ * Creates an integer value.
+ */
+ Value( int i );
+
+ /**
+ * Create a floating-point value.
+ */
+ Value( double f );
+
+ /**
+ * Create a string value.
+ */
+ Value( const UString& s );
+
+ /**
+ * Returns the type of the value.
+ */
+ Type type() const;
+
+ /**
+ * Returns true if empty.
+ */
+ bool isEmpty() const { return type() == Empty; }
+
+ /**
+ * Returns true if the type of this value is Boolean.
+ */
+ bool isBoolean() const { return type() == Boolean; }
+
+ /**
+ * Returns true if the type of this value is integer.
+ */
+ bool isInteger() const { return type() == Integer; }
+
+ /**
+ * Returns true if the type of this value is floating-point.
+ */
+ bool isFloat() const { return type() == Float; }
+
+ /**
+ * Returns true if the type of this value is either
+ * integer or floating-point.
+ */
+ bool isNumber() const { return (type() == Integer) || (type() == Float); }
+
+ /**
+ * Returns true if the type of this value is string.
+ */
+ bool isString() const { return type() == String; }
+
+ /**
+ * Returns true if this value holds error information.
+ */
+ bool isError() const { return type() == Error; }
+
+ void setValue( const Value& v );
+
+ /**
+ * Sets this value to boolean value.
+ */
+ void setValue( bool b );
+
+ /**
+ * Sets this value to integer value.
+ */
+ void setValue( int i );
+
+ /**
+ * Sets this value to floating-point value.
+ */
+ void setValue( double f );
+
+ /**
+ * Sets this value to string value.
+ */
+ void setValue( const UString& s );
+
+ /**
+ * Sets this value to hold error message.
+ */
+ void setError( const UString& msg );
+
+ /**
+ * Returns the boolean value of this value.
+ *
+ * Call this function only if isBoolean() returns true.
+ */
+ bool asBoolean() const;
+
+ /**
+ * Returns the integer value of this value.
+ *
+ * Call this function only if isNumber() returns true.
+ */
+ int asInteger() const;
+
+ /**
+ * Returns the floating-point value of this value.
+ *
+ * Call this function only if isNumber() returns true.
+ */
+ double asFloat() const;
+
+ /**
+ * Returns the string value of this value.
+ *
+ * Call this function only if isString() returns true.
+ */
+ UString asString() const;
+
+ /**
+ * Returns error message associated with this value.
+ *
+ * Call this function only if isError() returns true.
+ */
+ UString errorMessage() const;
+
+ /**
+ * Detaches itself from shared value data, i.e make a private, deep copy
+ * of the data. Usually this function is called automatically so you
+ * don't have to care about it.
+ */
+ void detach();
+
+ /**
+ * Returns constant reference to empty value.
+ */
+ static const Value& empty();
+
+ /**
+ * Returns constant reference to #DIV/0! error.
+ *
+ * This is used to indicate that a formula divides by 0 (zero).
+ */
+ static const Value& errorDIV0();
+
+ /**
+ * Returns constant reference to #N/A error.
+ *
+ * This is to indicate that a value is not available to a function.
+ */
+ static const Value& errorNA();
+
+ /**
+ * Returns constant reference to #NAME? error.
+ *
+ * This is to indicate that certain text inside formula is not
+ * recognized, possibly a misspelled name or name that
+ * does not exist.
+ */
+ static const Value& errorNAME();
+
+ /**
+ * Returns constant reference to #NUM! error.
+ *
+ * This is to indicate a problem with a number in a formula.
+ */
+ static const Value& errorNUM();
+
+ /**
+ * Returns constant reference to #NULL! error.
+ *
+ * This is to indicate that two area do not intersect.
+ */
+ static const Value& errorNULL();
+
+ /**
+ * Returns constant reference to #REF! error.
+ *
+ * This is used to indicate an invalid cell reference.
+ */
+ static const Value& errorREF();
+
+ /**
+ * Returns constant reference to #VALUE! error.
+ *
+ * This is to indicate that wrong type of argument or operand
+ * is used, usually within a function call, e.g SIN("some text").
+ */
+ static const Value& errorVALUE();
+
+ protected:
+
+ ValueData* d; // can't never be 0
+};
+
+/**
+ * Dumps value to output stream, useful for debugging.
+ */
+std::ostream& operator<<( std::ostream& s, Value value );
+
+} // namespace Swinder
+
+#endif // SWINDER_VALUE_H
diff --git a/filters/kspread/excel/sidewinder/workbook.cpp b/filters/kspread/excel/sidewinder/workbook.cpp
new file mode 100644
index 000000000..2abddf08f
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/workbook.cpp
@@ -0,0 +1,135 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#include "workbook.h"
+#include "sheet.h"
+#include "excel.h"
+#include "format.h"
+
+#include <iostream>
+#include <vector>
+#include <map>
+
+using namespace Swinder;
+
+class Workbook::Private
+{
+public:
+ std::vector<Sheet*> sheets;
+ bool autoCalc;
+ bool passwordProtected;
+ std::map<int,Format> formats;
+ int maxFormatIndex;
+};
+
+Workbook::Workbook()
+{
+ d = new Workbook::Private();
+ d->autoCalc = true;
+ d->passwordProtected = false;
+ d->maxFormatIndex = 0;
+}
+
+Workbook::~Workbook()
+{
+ clear();
+ delete d;
+}
+
+void Workbook::clear()
+{
+ // FIXME use iterator
+ for( unsigned i=0; i<sheetCount(); i++ )
+ {
+ Sheet* s = sheet( i );
+ delete s;
+ }
+ d->sheets.clear();
+}
+
+bool Workbook::load( const char* filename )
+{
+ ExcelReader* reader = new ExcelReader;
+ bool result = reader->load( this, filename );
+ delete reader;
+ return result;
+}
+
+void Workbook::appendSheet( Sheet* sheet )
+{
+ d->sheets.push_back( sheet );
+}
+
+unsigned Workbook::sheetCount() const
+{
+ return d->sheets.size();
+}
+
+Sheet* Workbook::sheet( unsigned index )
+{
+ if( index >= sheetCount() ) return (Sheet*)0;
+ return d->sheets[index];
+}
+
+int Workbook::indexOf( Sheet *s )
+{
+ if( s )
+ for( unsigned i = 0; i < sheetCount(); i++ )
+ if( d->sheets[i] == s )
+ return i;
+
+ return -1;
+}
+
+bool Workbook::autoCalc() const
+{
+ return d->autoCalc;
+}
+
+void Workbook::setAutoCalc( bool a )
+{
+ d->autoCalc = a;
+}
+
+void Workbook::setFormat( int index, const Format& format )
+{
+ d->formats[index] = format;
+ if (index > d->maxFormatIndex)
+ d->maxFormatIndex = index;
+}
+
+const Format& Workbook::format( int index ) const
+{
+ return d->formats[index];
+}
+
+const int Workbook::maxFormatIndex() const
+{
+ return d->maxFormatIndex;
+}
+
+bool Workbook::isPasswordProtected() const
+{
+ return d->passwordProtected;
+}
+
+void Workbook::setPasswordProtected( bool p )
+{
+ d->passwordProtected = p;
+}
diff --git a/filters/kspread/excel/sidewinder/workbook.h b/filters/kspread/excel/sidewinder/workbook.h
new file mode 100644
index 000000000..22431e834
--- /dev/null
+++ b/filters/kspread/excel/sidewinder/workbook.h
@@ -0,0 +1,109 @@
+/* Swinder - Portable library for spreadsheet
+ Copyright (C) 2003-2005 Ariya Hidayat <ariya@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+*/
+
+#ifndef SWINDER_WORKBOOK_H
+#define SWINDER_WORKBOOK_H
+
+#include "format.h"
+
+namespace Swinder
+{
+
+class Sheet;
+
+class Workbook
+{
+public:
+
+ /*
+ * Constructs a new workbook.
+ */
+
+ Workbook();
+
+ /*
+ * Destroys the workbook.
+ */
+
+ virtual ~Workbook();
+
+ /*
+ * Clears the workbook, i.e. makes it as if it is just constructed.
+ */
+ void clear();
+
+ /*
+ * Loads the workbook from file. Returns false if error occurred.
+ */
+ bool load( const char* filename );
+
+ /*
+ * Appends a new sheet.
+ */
+ void appendSheet( Sheet* sheet );
+
+ /*
+ * Returns the number of worksheet in this workbook. A newly created
+ * workbook has no sheet, i.e. sheetCount() returns 0.
+ */
+ unsigned sheetCount() const;
+
+ /*
+ * Returns a worksheet at given index. If index is invalid (e.g. larger
+ * than total number of worksheet), this function returns NULL.
+ */
+ Sheet* sheet( unsigned index );
+
+ /*
+ * Returns the index (zero-based) of the specified sheet, or -1 if
+ * the sheet is not inside the workbook.
+ */
+ int indexOf(Sheet *sheet);
+
+ /*
+ * Returns true if automatic calculation is enabled.
+ */
+ bool autoCalc() const;
+
+ /*
+ * Sets the automatic calculation.
+ */
+ void setAutoCalc( bool a );
+
+
+ bool isPasswordProtected() const;
+ void setPasswordProtected( bool p );
+
+ void setFormat(int index, const Format& format);
+ const Format& format(int index) const;
+ const int maxFormatIndex() const;
+
+private:
+ // no copy or assign
+ Workbook( const Workbook& );
+ Workbook& operator=( const Workbook& );
+
+ class Private;
+ Private* d;
+};
+
+}
+
+
+#endif // SWINDER_WORKBOOK_H
diff --git a/filters/kspread/gnumeric/Makefile.am b/filters/kspread/gnumeric/Makefile.am
new file mode 100644
index 000000000..6bb9608ed
--- /dev/null
+++ b/filters/kspread/gnumeric/Makefile.am
@@ -0,0 +1,21 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) -I$(top_srcdir)/kspread $(KOFFICE_INCLUDES) \
+ $(KOTEXT_INCLUDES) $(all_includes)
+
+####### Files
+kde_module_LTLIBRARIES = libgnumericexport.la libgnumericimport.la
+
+libgnumericexport_la_SOURCES = gnumericexport.cc
+libgnumericexport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libgnumericexport_la_LIBADD = $(KOFFICE_LIBS) ../../../kspread/libkspreadcommon.la
+
+libgnumericimport_la_SOURCES = gnumericimport.cc
+libgnumericimport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libgnumericimport_la_LIBADD = $(KOFFICE_LIBS) ../../../kspread/libkspreadcommon.la
+
+METASOURCES = AUTO
+
+service_DATA = kspread_gnumeric_export.desktop kspread_gnumeric_import.desktop
+
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/gnumeric/README b/filters/kspread/gnumeric/README
new file mode 100644
index 000000000..f6fca4317
--- /dev/null
+++ b/filters/kspread/gnumeric/README
@@ -0,0 +1,30 @@
+This is a GNUmeric import and export filter for kspread.
+
+This is heavily based on the kspread CSV import and export filters.
+
+It has been tested with Gnumeric v0.61 and kspread v1.0.
+
+The file format is mainly based on reading output of gnumeric. It
+requires the zlib library to read the compressed gnumeric output.
+
+It does not change behavior based on the version of the gnumeric file.
+This will have to be done in the future to maintain maximum compatibilit
+
+I will have to go back with a fine tooth comb and implement
+
+Wouldn't it be nice to have a generic library used by all opensource
+spreadsheets to import and export files.. Someday.
+
+Phillip Ezolt (phillipezolt@hotmail.com) (GNUmeric import and export)
+
+No idea if it is usefull; but it is a sin to let a good URL get lost...
+ More info on gnumeric:
+ http://www.object-refinery.com/jworkbook/
+
+
+cvs page for file format: (url gave by Jody Goldberg <jody@gnome.org>)
+http://cvs.gnome.org/viewcvs/gnumeric/gnumeric.xsd?rev=1.11&view=markup
+http://cvs.gnome.org/viewcvs/gnumeric/plugins/xml_sax/xml-sax-read.c?rev=1.132&view=markup
+
+Last test with gnumeric -1.4.2 and pango 1.8.1
+
diff --git a/filters/kspread/gnumeric/gnumeric.xsd b/filters/kspread/gnumeric/gnumeric.xsd
new file mode 100644
index 000000000..3ff04ff1d
--- /dev/null
+++ b/filters/kspread/gnumeric/gnumeric.xsd
@@ -0,0 +1,898 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:gmr="http://www.gnumeric.org/v10.dtd"
+ targetNamespace="http://www.gnumeric.org/v10.dtd"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <xsd:annotation>
+ <xsd:documentation xml:lang="en">
+ Schema for gnumeric spreadsheet documents
+ Assumes Gnumeric 1.2.2, updated for 1.4.2 in Feb 2005
+ Based on gnumeric source code and sample gnumeric documents
+ Author: Marc Johnson (marc_johnson27591@hotmail.com)
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:element name="Workbook" type="gmr:Workbook"/>
+
+ <xsd:complexType name="Version">
+ <xsd:attribute name="Epoch" type="xsd:positiveInteger" use="required"/>
+ <xsd:attribute name="Major" type="xsd:positiveInteger" use="required"/>
+ <xsd:attribute name="Minor" type="xsd:positiveInteger" use="required"/>
+ <xsd:attribute name="Full" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="Workbook">
+ <xsd:sequence>
+ <xsd:element name="Version" type="gmr:Version" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="Attributes" type="gmr:Attributes"/>
+ <xsd:element name="Summary" type="gmr:Summary"/>
+
+ <!-- ancient files lack this, modern files require it -->
+ <xsd:element name="SheetNameIndex" type="gmr:SheetNameIndex" minOccurs="0" maxOccurs="1"/>
+
+ <xsd:element name="Names" type="gmr:Names" minOccurs="0" maxOccurs="1"/>
+ <!-- preferred height and width -->
+ <xsd:element name="Geometry">
+ <xsd:complexType>
+ <xsd:attribute name="Width" type="xsd:positiveInteger" use="required"/>
+ <xsd:attribute name="Height" type="xsd:positiveInteger" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Sheets" type="gmr:Sheets"/>
+ <!-- which sheet was selected when the spreadsheet was saved? -->
+ <xsd:element name="UIData">
+ <xsd:complexType>
+ <xsd:attribute name="SelectedTab" type="xsd:nonNegativeInteger" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Calculation" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:attribute name="ManualRecalc" type="xsd:boolean"/>
+ <xsd:attribute name="EnableIteration" type="xsd:boolean"/>
+ <xsd:attribute name="MaxIterations" type="xsd:nonNegativeInteger"/>
+ <xsd:attribute name="IterationTolerance" type="xsd:double"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <!-- version number should be v10 - - &gt;
+ <xsd:attribute name="gmr" type="gmr:namespace" use="required"/> -->
+ </xsd:complexType>
+<!--
+ <xsd:simpleType name="namespace">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="http://www.gnome.org/gnumeric/v\d+"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+-->
+
+ <xsd:complexType name="Attributes">
+ <xsd:sequence>
+ <xsd:element name="Attribute" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <!-- typical values of name include
+ WorkbookView::show_horizontal_scrollbar
+ WorkbookView::show_vertical_scrollbar
+ WorkbookView::show_notebook_tabs
+ -->
+ <xsd:element name="type" type="gmr:GtkType"/>
+ <xsd:element name="name" type="xsd:string"/>
+ <xsd:element name="value" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="Names">
+ <xsd:sequence>
+ <xsd:element name="Name" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <!-- an oversight in the sax exporter (fixed in 1.4.3)
+ leaves off the namespace. Handle both formats.
+ -->
+ <xsd:choice>
+ <xsd:element name="name" type="xsd:string"/>
+ <xsd:element name="name" type="xsd:string" form="unqualified"/>
+ </xsd:choice>
+ <xsd:choice>
+ <xsd:element name="value" type="xsd:string"/>
+ <xsd:element name="value" type="xsd:string" form="unqualified"/>
+ </xsd:choice>
+ <xsd:choice>
+ <xsd:element name="position" type="xsd:string"/>
+ <xsd:element name="position" type="xsd:string" form="unqualified"/>
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+
+ <xsd:simpleType name="GtkType">
+ <!-- values of GtkType come from the GTK library; here is a list of known values:
+ 0 = INVALID
+ 1 = NONE
+ 2 = CHAR
+ 3 = UCHAR
+ 4 = BOOL
+ 5 = INT
+ 6 = UINT
+ 7 = LONG
+ 8 = ULONG
+ 9 = FLOAT
+ 10 = DOUBLE
+ 11 = STRING
+ 12 = ENUM
+ 13 = FLAGS
+ 14 = BOXED
+ 15 = POINTER
+ 16 = SIGNAL
+ 17 = ARGS
+ 18 = CALLBACK
+ 19 = C_CALLBACK
+ 20 = FOREIGN
+ 21 = OBJECT
+ -->
+ <xsd:restriction base="xsd:integer">
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="21"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="Summary">
+ <xsd:sequence>
+ <xsd:element name="Item" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <!-- typical values of name include
+ application
+ author
+ -->
+ <xsd:element name="name" type="xsd:string"/>
+ <!-- val-string for name="application" is always "gnumeric" -->
+ <xsd:element name="val-string" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <!-- this element may go away some day; the code documents it as an
+ artifact, a work-around for a problem with the SAX-based parser
+ -->
+ <xsd:complexType name="SheetNameIndex">
+ <xsd:sequence>
+ <xsd:element name="SheetName" minOccurs="0" maxOccurs="unbounded" type="xsd:string"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="Sheets">
+ <xsd:sequence>
+ <xsd:element name="Sheet" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <!-- name of the sheet -->
+ <xsd:element name="Name" type="xsd:string"/>
+ <!-- maximum column used -->
+ <xsd:element name="MaxCol" type="xsd:positiveInteger" minOccurs="0" maxOccurs="1"/>
+ <!-- maximum row used -->
+ <xsd:element name="MaxRow" type="xsd:positiveInteger" minOccurs="0" maxOccurs="1"/>
+ <!-- most recently used zoom factor -->
+ <xsd:element name="Zoom" type="xsd:double"/>
+ <xsd:element name="Names" type="gmr:Names" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="PrintInformation" type="gmr:PrintInformation"/>
+ <xsd:element name="Styles" type="gmr:Styles"/>
+ <xsd:element name="Cols">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="ColInfo" type="gmr:Col_Row" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="DefaultSizePts" type="xsd:double" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Rows">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="RowInfo" type="gmr:Col_Row" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="DefaultSizePts" type="xsd:double" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Selections" type="gmr:Selections"/>
+ <xsd:element name="Objects" type="gmr:Objects" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="Cells" type="gmr:Cells"/>
+ <xsd:element name="MergedRegions" type="gmr:MergedRegions" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="SheetLayout" type="gmr:SheetLayout"/>
+ <xsd:element name="Solver" type="gmr:Solver"/>
+ </xsd:sequence>
+ <!-- note: xsd:boolean values can be true, false, 1, 0;
+ gnumeric, in this element, always generates 'true' or
+ 'false' for its attributes
+ -->
+ <xsd:attribute name="DisplayFormulas" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="HideZero" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="HideGrid" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="HideColHeader" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="HideRowHeader" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="DisplayOutlines" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="OutlineSymbolsBelow" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="OutlineSymbolsRight" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="TabColor" type="gmr:color" use="optional"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="PrintInformation">
+ <xsd:sequence>
+ <xsd:element name="Margins">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="top" type="gmr:margin"/>
+ <xsd:element name="bottom" type="gmr:margin"/>
+ <xsd:element name="left" type="gmr:margin"/>
+ <xsd:element name="right" type="gmr:margin"/>
+ <xsd:element name="header" type="gmr:margin"/>
+ <xsd:element name="footer" type="gmr:margin"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Scale">
+ <xsd:complexType>
+ <xsd:attribute name="type" type="xsd:string" use="required"/>
+ <xsd:attribute name="percentage" type="xsd:double" use="optional"/>
+ <xsd:attribute name="cols" type="xsd:integer" />
+ <xsd:attribute name="rows" type="xsd:integer" />
+ </xsd:complexType>
+ </xsd:element>
+ <!-- center vertically? -->
+ <xsd:element name="vcenter">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:boolean" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- center horizontally? -->
+ <xsd:element name="hcenter">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:boolean" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- print grid lines? -->
+ <xsd:element name="grid">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:boolean" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- print even if only styles? -->
+ <xsd:element name="even_if_only_styles">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:boolean" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- print in monochrome? -->
+ <xsd:element name="monochrome">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:boolean" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- print in draft mode? -->
+ <xsd:element name="draft">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:boolean" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- print titles? -->
+ <xsd:element name="titles">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:boolean" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <!-- repeat range -->
+ <xsd:element name="repeat_top" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- repeat range -->
+ <xsd:element name="repeat_left" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:attribute name="value" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="order" type="gmr:print_ordering"/>
+ <xsd:element name="orientation" type="gmr:print_orientation"/>
+ <xsd:element name="Header">
+ <xsd:complexType>
+ <xsd:attribute name="Left" type="xsd:string" use="required"/>
+ <xsd:attribute name="Middle" type="xsd:string" use="required"/>
+ <xsd:attribute name="Right" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Footer">
+ <xsd:complexType>
+ <xsd:attribute name="Left" type="xsd:string" use="required"/>
+ <xsd:attribute name="Middle" type="xsd:string" use="required"/>
+ <xsd:attribute name="Right" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <!-- typical values are A4, US-Letter -->
+ <xsd:element name="paper" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="margin">
+ <xsd:attribute name="Points" type="xsd:double"/>
+ <xsd:attribute name="PrefUnit" type="gmr:print_units"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="print_units">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="mm"/>
+ <xsd:enumeration value="cm"/>
+ <xsd:enumeration value="in"/>
+ <xsd:enumeration value="Pt"/>
+ <xsd:enumeration value="Px"/>
+ <xsd:enumeration value="points"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="print_ordering">
+ <xsd:restriction base="xsd:string">
+ <!-- right, then down -->
+ <xsd:enumeration value="r_then_d"/>
+ <!-- down, then right -->
+ <xsd:enumeration value="d_then_r"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="print_orientation">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="landscape"/>
+ <xsd:enumeration value="portrait"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="Styles">
+ <xsd:sequence>
+ <xsd:element name="StyleRegion" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="Style" type="gmr:Style" minOccurs="1" maxOccurs="1"/>
+ </xsd:sequence>
+ <xsd:attribute name="startCol" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="startRow" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="endCol" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="endRow" type="xsd:nonNegativeInteger" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="Style">
+ <xsd:sequence>
+ <xsd:element name="Font" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="Unit" type="xsd:double" use="required"/>
+ <xsd:attribute name="Bold" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="Italic" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="Underline" type="gmr:underline" use="required"/>
+ <xsd:attribute name="StrikeThrough" type="xsd:boolean" use="required"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="HyperLink" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:attribute name="type" type="xsd:string" use="required"/>
+ <xsd:attribute name="target" type="xsd:string" use="optional"/>
+ <xsd:attribute name="tip" type="xsd:string" use="optional"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="StyleBorder" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="Top" type="gmr:StyleBorderElement"/>
+ <xsd:element name="Bottom" type="gmr:StyleBorderElement"/>
+ <xsd:element name="Left" type="gmr:StyleBorderElement"/>
+ <xsd:element name="Right" type="gmr:StyleBorderElement"/>
+ <xsd:element name="Diagonal" type="gmr:StyleBorderElement"/>
+ <xsd:element name="Rev-Diagonal" type="gmr:StyleBorderElement"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="Validation" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="Style" type="xsd:integer" use="required"/>
+ <xsd:attribute name="Type" type="xsd:integer" use="required"/>
+ <xsd:attribute name="Operator" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="AllowBlank" type="xsd:boolean" use="optional"/>
+ <xsd:attribute name="UseDropdown" type="xsd:boolean" use="optional"/>
+ <xsd:attribute name="Title" type="xsd:string" use="optional"/>
+ <xsd:attribute name="Message" type="xsd:string" use="optional"/>
+ <xsd:attribute name="Expression0" type="xsd:string" use="optional"/>
+ <xsd:attribute name="Expression1" type="xsd:string" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="HAlign" type="gmr:horizontal_alignment"/>
+ <xsd:attribute name="VAlign" type="gmr:vertical_alignment" />
+ <xsd:attribute name="WrapText" type="xsd:boolean" />
+ <xsd:attribute name="ShrinkToFit" type="xsd:integer" /> <!-- should be bool, but some files have odd truth values -->
+ <xsd:attribute name="Rotation" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="Orient" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="Shade" type="gmr:style_shading" />
+ <xsd:attribute name="Indent" type="xsd:integer" />
+ <xsd:attribute name="Locked" type="xsd:boolean" />
+ <xsd:attribute name="Hidden" type="xsd:boolean" />
+ <xsd:attribute name="Fore" type="gmr:color" />
+ <xsd:attribute name="Back" type="gmr:color" />
+ <xsd:attribute name="PatternColor" type="gmr:color" />
+ <!-- the most common value of the Format attribute, by far, is
+ General. Here are some other values:
+ #,##0.00
+ $0.00_);[Red]($0.00)
+ "$"#,##0.00_);[Red]\("$"#,##0.00\)
+ [Blue][<1000];[Red][<100];[Yellow][<0];[Green][=0];[Blue][>10];[Red][>100];[Yellow][>1000]
+ [Blue][>=1000];[Red][>=100];[Yellow][>0];[Green][=0];[Yellow][>-100];[Red][>-1000];[Blue];[Cyan]
+ [>100]"bigger than 100:" 0.00;[>1000]"bigger than 1000": 0.00
+ [Blue];[Red];[Yellow];[Green]
+ -->
+ <xsd:attribute name="Format" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="StyleBorderElement">
+ <xsd:attribute name="Style" type="gmr:border_style" use="required"/>
+ <!-- Color is present when Style is not 0 -->
+ <xsd:attribute name="Color" type="gmr:color" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="border_style">
+ <xsd:restriction base="xsd:integer">
+ <!-- 0 = NONE
+ 1 = THIN
+ 2 = MEDIUM
+ 3 = DASHED
+ 4 = DOTTED
+ 5 = THICK
+ 6 = DOUBLE
+ 7 = HAIR
+ 8 = MEDIUM_DASH
+ 9 = DASH_DOT
+ 10 = MEDIUM_DASH_DOT
+ 11 = DASH_DOT_DOT
+ 12 = MEDIUM_DASH_DOT_DOT
+ 13 = SLANTED_DASH_DOT
+ -->
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="13"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="underline">
+ <xsd:restriction base="xsd:integer">
+ <!-- 0 = NONE
+ 1 = SINGLE
+ 2 = DOUBLE
+ -->
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="2"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="horizontal_alignment">
+ <xsd:restriction base="xsd:integer">
+ <!-- this is a bit map as follows:
+ 1 = GENERAL
+ 2 = LEFT
+ 4 = RIGHT
+ 8 = CENTER
+ 16 = FILL
+ 32 = JUSTIFY
+ 64 = CENTER ACROSS SELECTION
+ -->
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="127"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="vertical_alignment">
+ <xsd:restriction base="xsd:integer">
+ <!-- this is a bit map as follows:
+ 1 = TOP
+ 2 = BOTTOM
+ 4 = CENTER
+ 8 = JUSTIFY
+ -->
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="15"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="style_shading">
+ <xsd:restriction base="xsd:integer">
+ <!-- the values are defined as follows:
+ 0 = NONE
+ 1 = Solid
+ 2 = 75%
+ 3 = 50%
+ 4 = 25%
+ 5 = 12.5%
+ 6 = 6.25%
+ 7 = Horizontal Stripe
+ 8 = Vertical Stripe
+ 9 = Reverse Diagonal Stripe
+ 10 = Diagonal Stripe
+ 11 = Diagonal Crosshatch
+ 12 = Thick Diagonal Crosshatch
+ 13 = Thin Horizontal Stripe
+ 14 = Thin Vertical Stripe
+ 15 = Thin Reverse Diagonal Stripe
+ 16 = Thin Diagonal Stripe
+ 17 = Thin Crosshatch
+ 18 = Thin Diagonal Crosshatch
+ 19 = Applix small circle
+ 20 = Applix semicircle
+ 21 = Applix small thatch
+ 22 = Applix round thatch
+ 23 = Applix Brick
+ 24 = 100%
+ 25 = 87.5%
+ -->
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="25"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="color">
+ <xsd:restriction base="xsd:string">
+ <!-- colors in hex, 16 bits red, green, then blue -->
+ <xsd:pattern value="[0-9A-F]{1,4}:[0-9A-F]{1,4}:[0-9A-F]{1,4}"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="Col_Row">
+ <!-- column/row number -->
+ <xsd:attribute name="No" type="xsd:nonNegativeInteger" use="required"/>
+ <!-- size in points -->
+ <xsd:attribute name="Unit" type="xsd:double" use="required"/>
+ <!-- top/left margin, in points -->
+ <xsd:attribute name="MarginA" type="gmr:col_row_margin" use="required"/>
+ <!-- bottom/right margin, in points -->
+ <xsd:attribute name="MarginB" type="gmr:col_row_margin" use="required"/>
+ <!-- true if size is explicitly set -->
+ <xsd:attribute name="HardSize" type="xsd:boolean" use="optional" default="0"/>
+ <xsd:attribute name="Hidden" type="xsd:boolean" use="optional" default="0"/>
+ <xsd:attribute name="Collapsed" type="xsd:boolean" use="optional" default="0"/>
+ <xsd:attribute name="OutlineLevel" type="xsd:integer" use="optional" default="0"/>
+ <!-- The number of consequitive identically sized cols/rows -->
+ <xsd:attribute name="Count" type="xsd:integer" use="optional" default="1"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="col_row_margin">
+ <xsd:restriction base="xsd:integer">
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="7"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="Selections">
+ <xsd:sequence>
+ <xsd:element name="Selection" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attribute name="startCol" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="startRow" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="endCol" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="endRow" type="xsd:nonNegativeInteger" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="CursorCol" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="CursorRow" type="xsd:nonNegativeInteger" use="required"/>
+ </xsd:complexType>
+
+ <xsd:attributeGroup name="ObjectAnchor">
+ <xsd:attribute name="ObjectBound" type="xsd:string" use="required"/>
+ <xsd:attribute name="ObjectOffset" type="gmr:offsets" use="required"/>
+ <xsd:attribute name="ObjectAnchorType" type="gmr:anchor_type" use="required"/>
+ <xsd:attribute name="Direction" type="gmr:direction" use="required"/>
+ </xsd:attributeGroup>
+
+ <xsd:attributeGroup name="ObjectAdjustmentProps">
+ <xsd:attribute name="Min" type="xsd:double" use="required"/>
+ <xsd:attribute name="Max" type="xsd:double" use="required"/>
+ <xsd:attribute name="Inc" type="xsd:double" use="required"/>
+ <xsd:attribute name="Page" type="xsd:double" use="required"/>
+ <xsd:attribute name="Value" type="xsd:double" use="required"/>
+ <xsd:attribute name="Input" type="xsd:string" use="required"/>
+ </xsd:attributeGroup>
+
+ <xsd:complexType name="Objects">
+ <!-- little is known about this, as I have no current sample code that
+ uses this element, and the code that generates these elements is
+ pretty convoluted
+ -->
+ <xsd:sequence>
+ <xsd:element name="SheetObjectBonobo" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="CellComment" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attribute name="Author" type="xsd:string" use="required"/>
+ <xsd:attribute name="Text" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SheetObjectFilled" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attribute name="OutlineColor" type="gmr:color" use="required"/>
+ <xsd:attribute name="FillColor" type="gmr:color" use="required"/>
+ <xsd:attribute name="Type" type="gmr:objectfilled" use="required"/>
+ <xsd:attribute name="Width" type="xsd:positiveInteger" use="required"/>
+ <!-- the arrow shape attributes are only used if the type is
+ arrow (type="gmr:2")
+ -->
+ <xsd:attribute name="ArrowShapeA" type="xsd:double" use="optional"/>
+ <xsd:attribute name="ArrowShapeB" type="xsd:double" use="optional"/>
+ <xsd:attribute name="ArrowShapeC" type="xsd:double" use="optional"/>
+ </xsd:complexType>
+ </xsd:element>
+
+<!-- widgets -->
+ <xsd:element name="SheetWidgetButton" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attribute name="Label" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SheetWidgetCheckbox" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attribute name="Label" type="xsd:string" use="required"/>
+ <xsd:attribute name="Value" type="xsd:integer" use="required"/>
+ <xsd:attribute name="Input" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SheetWidgetToggleButton" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attribute name="Label" type="xsd:string" use="required"/>
+ <xsd:attribute name="Value" type="xsd:integer" use="required"/>
+ <xsd:attribute name="Input" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="SheetWidgetScrollbar" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attributeGroup ref="gmr:ObjectAdjustmentProps"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SheetWidgetSpinbutton" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attributeGroup ref="gmr:ObjectAdjustmentProps"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SheetWidgetSlider" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attributeGroup ref="gmr:ObjectAdjustmentProps"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="SheetObjectImage" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="Content" form="unqualified">
+ <xsd:complexType mixed="true">
+ <xsd:attribute name="image-type" type="xsd:string" use="required"/>
+ <xsd:attribute name="size-bytes" type="xsd:int" use="optional"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ <xsd:attribute name="crop-top" type="xsd:double" use="required"/>
+ <xsd:attribute name="crop-bottom" type="xsd:double" use="required"/>
+ <xsd:attribute name="crop-left" type="xsd:double" use="required"/>
+ <xsd:attribute name="crop-right" type="xsd:double" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SheetObjectGraph" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SheetWidgetFrame" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="SheetWidgetLabel" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attributeGroup ref="gmr:ObjectAnchor"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:simpleType name="offsets">
+ <xsd:restriction base="xsd:string">
+ <!-- if this seems hard to read, it purportedly describes 4
+ space-separated doubles
+ -->
+ <xsd:pattern value="[+\-]?\d+(.\d+)?([Ee]([+\-])?\d+)? [+\-]?\d+(.\d+)?([Ee]([+\-])?\d+)? [+\-]?\d+(.\d+)?([Ee]([+\-])?\d+)? [+\-]?\d+(.\d+)?([Ee]([+\-])?\d+)?"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="anchor_type">
+ <xsd:restriction base="xsd:string">
+ <!-- if this seems hard to read, it purportedly describes 4
+ space-separated positive numbers
+
+ each number needs to be one of the following:
+ 0 = UNKNOWN
+ 16 = PERCENTAGE_FROM_COLROW_START
+ 17 = PERCENTAGE_FROM_COLROW_END
+ 32 = PTS_FROM_COLROW_START
+ 33 = PTS_FROM_COLROW_END
+ 48 = PTS_ABSOLUTE
+ -->
+ <xsd:pattern value="\d+ \d+ \d+ \d+"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="direction">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="-1"/> <!-- unknown -->
+ <xsd:enumeration value="0"/> <!-- up right -->
+ <xsd:enumeration value="1"/> <!-- up left -->
+ <xsd:enumeration value="16"/> <!-- down right -->
+ <xsd:enumeration value="17"/> <!-- down left -->
+ <xsd:enumeration value="255"/> <!-- unknown -->
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="objectfilled">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="1"/> <!-- line -->
+ <xsd:enumeration value="2"/> <!-- arrow -->
+ <xsd:enumeration value="101"/> <!-- box -->
+ <xsd:enumeration value="102"/> <!-- oval -->
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="Cells">
+ <xsd:sequence>
+ <xsd:element name="Cell" minOccurs="0" maxOccurs="unbounded">
+ <!-- expressions are stored as entered, with a leading '='.
+ Once a shared expression has been defined, subsequent
+ Cell elements using that same shared expression simply
+ use the "ExprID" attribute to indicate which shared
+ expression is used, and no Content element is included
+ -->
+ <xsd:complexType mixed="true">
+ <!-- Compatibility for ancient 0.x format -->
+ <xsd:sequence>
+ <xsd:element name="Content" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+
+ <!-- Col and Row are sufficient for a cell that is an element of
+ an array of cells as long as it's not the top left cell
+ -->
+ <xsd:attribute name="Col" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="Row" type="xsd:nonNegativeInteger" use="required"/>
+ <!-- ExprID is only used to refer to a shared expression -->
+ <xsd:attribute name="ExprID" type="xsd:positiveInteger" use="optional"/>
+ <!-- ValueType is not used if the cell contains an expression -->
+ <xsd:attribute name="ValueType" type="gmr:cell_type" use="optional"/>
+ <!-- ValueFormat is apparently used only for cell-by-cell format
+ overrides
+ -->
+ <xsd:attribute name="ValueFormat" type="xsd:string" use="optional"/>
+ <!-- Cols and Rows are used to define an array of cells -->
+ <xsd:attribute name="Cols" type="xsd:positiveInteger" use="optional"/>
+ <xsd:attribute name="Rows" type="xsd:positiveInteger" use="optional"/>
+
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:simpleType name="cell_type">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="10"/> <!-- empty -->
+ <xsd:enumeration value="20"/> <!-- boolean -->
+ <xsd:enumeration value="30"/> <!-- integer -->
+ <xsd:enumeration value="40"/> <!-- float -->
+ <xsd:enumeration value="50"/> <!-- error -->
+ <xsd:enumeration value="60"/> <!-- string -->
+ <xsd:enumeration value="70"/> <!-- cellrange -->
+ <xsd:enumeration value="80"/> <!-- array -->
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="MergedRegions">
+ <xsd:sequence>
+ <xsd:element name="Merge" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="Solver">
+ <xsd:sequence>
+ <xsd:element name="Constr" minOccurs="0" maxOccurs="unbounded">
+ <xsd:complexType>
+ <xsd:attribute name="Lcol" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="Lrow" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="Rcol" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="Rrow" type="xsd:nonNegativeInteger" use="required"/>
+ <xsd:attribute name="Cols" type="xsd:positiveInteger" use="required"/>
+ <xsd:attribute name="Rows" type="xsd:positiveInteger" use="required"/>
+ <xsd:attribute name="Type" type="gmr:solver_contraint_t" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="TargetCol" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="TargetRow" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="ProblemType" type="gmr:solver_problem_t" use="required"/>
+ <xsd:attribute name="Inputs" type="xsd:string" use="required"/>
+ <xsd:attribute name="MaxTime" type="xsd:integer" use="required"/>
+ <xsd:attribute name="MaxIter" type="xsd:integer" use="required"/>
+ <xsd:attribute name="NonNeg" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="Discr" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="AutoScale" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="ShowIter" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="AnswerR" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="SensitivityR" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="LimitsR" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="PerformR" type="xsd:boolean" use="required"/>
+ <xsd:attribute name="ProgramR" type="xsd:boolean" use="required"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="solver_contraint_t">
+ <xsd:restriction base="xsd:integer">
+ <xsd:enumeration value="0" /> <!-- none -->
+ <xsd:enumeration value="1" /> <!-- &lt;= -->
+ <xsd:enumeration value="2" /> <!-- &gt;= -->
+ <xsd:enumeration value="4" /> <!-- = -->
+ <xsd:enumeration value="8" /> <!-- Int -->
+ <xsd:enumeration value="16"/> <!-- boolean -->
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="solver_problem_t">
+ <xsd:restriction base="xsd:integer">
+ <xsd:enumeration value="0" /> <!-- SolverMinimize -->
+ <xsd:enumeration value="1" /> <!-- SolverMaximize -->
+ <xsd:enumeration value="2" /> <!-- SolverEqualTo -->
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="SheetLayout">
+ <xsd:sequence>
+ <xsd:element name="FreezePanes" minOccurs="0" maxOccurs="1">
+ <xsd:complexType>
+ <xsd:attribute name="FrozenTopLeft" type="xsd:string" use="required"/>
+ <xsd:attribute name="UnfrozenTopLeft" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:sequence>
+ <xsd:attribute name="TopLeft" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+</xsd:schema>
diff --git a/filters/kspread/gnumeric/gnumericexport.cc b/filters/kspread/gnumeric/gnumericexport.cc
new file mode 100644
index 000000000..443353f45
--- /dev/null
+++ b/filters/kspread/gnumeric/gnumericexport.cc
@@ -0,0 +1,1574 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2005 Laurent Montel <montel@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+/* Gnumeric export filter by Phillip Ezolt (phillipezolt@hotmail.com)
+ 2004 - Some updates by Tim Beaulen (tbscope@gmail.com) */
+
+#include <gnumericexport.h>
+#include <kdebug.h>
+#include <kfilterdev.h>
+#include <kmessagebox.h>
+#include <kgenericfactory.h>
+#include <KoFilterChain.h>
+#include <qapplication.h>
+#include <qptrlist.h>
+#include <qsortedlist.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <kspread_map.h>
+#include <kspread_sheet.h>
+#include <kspread_doc.h>
+#include <kspread_view.h>
+#include <kspread_canvas.h>
+#include <kspread_sheetprint.h>
+#include <KoDocumentInfo.h>
+
+using namespace KSpread;
+
+typedef KGenericFactory<GNUMERICExport, KoFilter> GNUMERICExportFactory;
+K_EXPORT_COMPONENT_FACTORY( libgnumericexport, GNUMERICExportFactory( "kofficefilters" ) )
+
+GNUMERICExport::GNUMERICExport(KoFilter *, const char *, const QStringList&) :
+KoFilter()
+{
+ isLink = false;
+ isLinkBold = false;
+ isLinkItalic = false;
+}
+
+/**
+ * This function will check if a cell has any type of border.
+ */
+bool GNUMERICExport::hasBorder(Cell *cell, int currentcolumn, int currentrow)
+{
+ if ( ( (cell->format()->leftBorderWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->leftBorderStyle(currentcolumn, currentrow) != Qt::NoPen ) ) ||
+ ( (cell->format()->rightBorderWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->rightBorderStyle(currentcolumn, currentrow) != Qt::NoPen ) ) ||
+ ( (cell->format()->topBorderWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->topBorderStyle(currentcolumn, currentrow) != Qt::NoPen ) ) ||
+ ( (cell->format()->bottomBorderWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->bottomBorderStyle(currentcolumn, currentrow) != Qt::NoPen ) ) ||
+ ( (cell->format()->fallDiagonalWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->fallDiagonalStyle(currentcolumn, currentrow) != Qt::NoPen ) ) ||
+ ( (cell->format()->goUpDiagonalWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->goUpDiagonalStyle(currentcolumn, currentrow) != Qt::NoPen ) ) )
+ return true;
+ else
+ return false;
+}
+
+const QString GNUMERICExport::ColorToString(int red, int green, int blue)
+{
+ return QString::number(red,16)+":"+QString::number(green,16)+":"+QString::number(blue,16);
+}
+
+QDomElement GNUMERICExport::GetBorderStyle(QDomDocument gnumeric_doc,Cell * cell, int currentcolumn, int currentrow)
+{
+ QDomElement border_style;
+ QDomElement border;
+
+ int red, green, blue;
+ QColor color;
+
+ border_style = gnumeric_doc.createElement("gmr:StyleBorder");
+
+ if ( (cell->format()->leftBorderWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->leftBorderStyle(currentcolumn, currentrow) != Qt::NoPen ) )
+ {
+ border = gnumeric_doc.createElement("gmr:Left");
+ border.setAttribute("Style","1");
+
+ color = cell->format()->leftBorderColor(currentcolumn, currentrow);
+ red = color.red()<<8;
+ green = color.green()<<8;
+ blue = color.blue()<<8;
+
+ border.setAttribute("Color", QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16));
+ }
+ else
+ {
+ border = gnumeric_doc.createElement("gmr:Left");
+ border.setAttribute("Style","0");
+ }
+
+ border_style.appendChild(border);
+
+ if ( (cell->format()->rightBorderWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->rightBorderStyle(currentcolumn, currentrow) != Qt::NoPen ) )
+ {
+ border = gnumeric_doc.createElement("gmr:Right");
+ border.setAttribute("Style","1");
+
+ color = cell->format()->rightBorderColor(currentcolumn, currentrow);
+ red = color.red()<<8;
+ green = color.green()<<8;
+ blue = color.blue()<<8;
+
+ border.setAttribute("Color", QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16));
+ }
+ else
+ {
+ border = gnumeric_doc.createElement("gmr:Right");
+ border.setAttribute("Style","0");
+ }
+
+ border_style.appendChild(border);
+
+ if ( (cell->format()->topBorderWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->topBorderStyle(currentcolumn, currentrow) != Qt::NoPen ) )
+ {
+ border = gnumeric_doc.createElement("gmr:Top");
+ border.setAttribute("Style","1");
+
+ color = cell->format()->topBorderColor(currentcolumn, currentrow);
+ red = color.red()<<8;
+ green = color.green()<<8;
+ blue = color.blue()<<8;
+
+ border.setAttribute("Color", QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16));
+ }
+ else
+ {
+ border = gnumeric_doc.createElement("gmr:Top");
+ border.setAttribute("Style","0");
+ }
+
+ border_style.appendChild(border);
+
+ if ( (cell->format()->bottomBorderWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->bottomBorderStyle(currentcolumn, currentrow) != Qt::NoPen ) )
+ {
+ border = gnumeric_doc.createElement("gmr:Bottom");
+ border.setAttribute("Style","1");
+
+ color = cell->format()->bottomBorderColor(currentcolumn, currentrow);
+ red = color.red()<<8;
+ green = color.green()<<8;
+ blue = color.blue()<<8;
+
+ border.setAttribute("Color", QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16));
+ }
+ else
+ {
+ border = gnumeric_doc.createElement("gmr:Bottom");
+ border.setAttribute("Style","0");
+ }
+
+ border_style.appendChild(border);
+
+ if ( (cell->format()->fallDiagonalWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->fallDiagonalStyle(currentcolumn, currentrow) != Qt::NoPen ) )
+ {
+ border = gnumeric_doc.createElement("gmr:Diagonal");
+ border.setAttribute("Style","1");
+
+ color = cell->format()->fallDiagonalColor(currentcolumn, currentrow);
+ red = color.red()<<8;
+ green = color.green()<<8;
+ blue = color.blue()<<8;
+
+ border.setAttribute("Color", QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16));
+ }
+ else
+ {
+ border = gnumeric_doc.createElement("gmr:Diagonal");
+ border.setAttribute("Style","0");
+ }
+
+ border_style.appendChild(border);
+
+ if ( (cell->format()->goUpDiagonalWidth(currentcolumn, currentrow) != 0) &&
+ (cell->format()->goUpDiagonalStyle(currentcolumn, currentrow) != Qt::NoPen ) )
+ {
+ border = gnumeric_doc.createElement("gmr:Rev-Diagonal");
+ border.setAttribute("Style","1");
+
+ color = cell->format()->goUpDiagonalColor(currentcolumn, currentrow);
+ red = color.red()<<8;
+ green = color.green()<<8;
+ blue = color.blue()<<8;
+
+ border.setAttribute("Color", QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16));
+ }
+ else
+ {
+ border = gnumeric_doc.createElement("gmr:Rev-Diagonal");
+ border.setAttribute("Style","0");
+ }
+
+ border_style.appendChild(border);
+
+ return border_style;
+}
+
+QDomElement GNUMERICExport::GetValidity( QDomDocument gnumeric_doc, Cell * cell )
+{
+ //<gmr:Validation Style="1" Type="1" Operator="7" AllowBlank="true" UseDropdown="false" Title="ghhg" Message="ghghhhjfhfghjfghj&#10;fg&#10;hjgf&#10;hj">
+ // <gmr:Expression0>45</gmr:Expression0>
+ // </gmr:Validation>
+ Validity *kspread_validity = cell->getValidity();
+ QDomElement val = gnumeric_doc.createElement( "gmr:Validation" );
+ val.setAttribute( "Title", kspread_validity->title );
+ val.setAttribute( "Message", kspread_validity->message );
+ val.setAttribute( "AllowBlank", kspread_validity->allowEmptyCell ? "true":"false" );
+ if ( !kspread_validity->displayMessage )
+ {
+ val.setAttribute("Style", "0" );
+ }
+ else
+ {
+ switch( kspread_validity->m_action )
+ {
+ case Action::Stop:
+ val.setAttribute("Style", "1" );
+ break;
+ case Action::Warning:
+ val.setAttribute("Style", "2" );
+ break;
+ case Action::Information:
+ val.setAttribute("Style", "3" );
+ break;
+ }
+ }
+
+ switch( kspread_validity->m_cond )
+ {
+ case Conditional::None:
+ //Nothing
+ break;
+ case Conditional::Equal:
+ val.setAttribute("Operator", "2" );
+ break;
+ case Conditional::Superior:
+ val.setAttribute("Operator", "4" );
+ break;
+ case Conditional::Inferior:
+ val.setAttribute("Operator", "5" );
+ break;
+ case Conditional::SuperiorEqual:
+ val.setAttribute("Operator", "6" );
+ break;
+ case Conditional::InferiorEqual:
+ val.setAttribute("Operator", "7" );
+ break;
+ case Conditional::Between:
+ val.setAttribute("Operator", "0" );
+ break;
+ case Conditional::Different:
+ val.setAttribute("Operator", "3" );
+ break;
+ case Conditional::DifferentTo:
+ val.setAttribute("Operator", "1" );
+ break;
+ }
+ switch( kspread_validity->m_restriction )
+ {
+ case Restriction::None:
+ val.setAttribute("Type", "0" );
+ break;
+ case Restriction::Number:
+ {
+ val.setAttribute("Type", "2" );
+ switch( kspread_validity->m_cond )
+ {
+ case Conditional::None:
+ //Nothing
+ break;
+ case Conditional::Equal:
+ case Conditional::Superior:
+ case Conditional::Inferior:
+ case Conditional::SuperiorEqual:
+ case Conditional::InferiorEqual:
+ case Conditional::Different:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number( kspread_validity->valMin ) ) );
+ val.appendChild( tmp );
+ }
+ break;
+ case Conditional::Between:
+ case Conditional::DifferentTo:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number(kspread_validity->valMin ) ) );
+ val.appendChild( tmp );
+ tmp = gnumeric_doc.createElement( "gmr:Expression1" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number(kspread_validity->valMax ) ) );
+ val.appendChild( tmp );
+ }
+ break;
+ }
+
+ break;
+ }
+ case Restriction::Text:
+ //Not supported into gnumeric
+ //val.setAttribute("Type", "1" );
+ break;
+ case Restriction::Time:
+ val.setAttribute("Type", "5" );
+ switch( kspread_validity->m_cond )
+ {
+ case Conditional::None:
+ //Nothing
+ break;
+ case Conditional::Equal:
+ case Conditional::Superior:
+ case Conditional::Inferior:
+ case Conditional::SuperiorEqual:
+ case Conditional::InferiorEqual:
+ case Conditional::Different:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( kspread_validity->timeMin.toString() ) );
+ val.appendChild( tmp );
+ }
+ break;
+ case Conditional::Between:
+ case Conditional::DifferentTo:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( kspread_validity->timeMin.toString() ) );
+ val.appendChild( tmp );
+ tmp = gnumeric_doc.createElement( "gmr:Expression1" );
+ tmp.appendChild( gnumeric_doc.createTextNode( kspread_validity->timeMax.toString() ) );
+ val.appendChild( tmp );
+ }
+ break;
+ }
+
+ break;
+ case Restriction::Date:
+ val.setAttribute("Type", "4" );
+ switch( kspread_validity->m_cond )
+ {
+ case Conditional::None:
+ //Nothing
+ break;
+ case Conditional::Equal:
+ case Conditional::Superior:
+ case Conditional::Inferior:
+ case Conditional::SuperiorEqual:
+ case Conditional::InferiorEqual:
+ case Conditional::Different:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( kspread_validity->dateMin.toString() ) );
+ val.appendChild( tmp );
+ }
+ break;
+ case Conditional::Between:
+ case Conditional::DifferentTo:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( kspread_validity->dateMin.toString() ) );
+ val.appendChild( tmp );
+ tmp = gnumeric_doc.createElement( "gmr:Expression1" );
+ tmp.appendChild( gnumeric_doc.createTextNode( kspread_validity->dateMax.toString() ) );
+ val.appendChild( tmp );
+ }
+ break;
+ }
+
+ break;
+ case Restriction::Integer:
+ val.setAttribute("Type", "1" );
+ switch( kspread_validity->m_cond )
+ {
+ case Conditional::None:
+ //Nothing
+ break;
+ case Conditional::Equal:
+ case Conditional::Superior:
+ case Conditional::Inferior:
+ case Conditional::SuperiorEqual:
+ case Conditional::InferiorEqual:
+ case Conditional::Different:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number(kspread_validity->valMin ) ) );
+ val.appendChild( tmp );
+ }
+ break;
+ case Conditional::Between:
+ case Conditional::DifferentTo:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number(kspread_validity->valMin ) ) );
+ val.appendChild( tmp );
+ tmp = gnumeric_doc.createElement( "gmr:Expression1" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number(kspread_validity->valMax ) ) );
+ val.appendChild( tmp );
+ }
+ break;
+ }
+ break;
+ case Restriction::TextLength:
+ val.setAttribute("Type", "6" );
+ switch( kspread_validity->m_cond )
+ {
+ case Conditional::None:
+ //Nothing
+ break;
+ case Conditional::Equal:
+ case Conditional::Superior:
+ case Conditional::Inferior:
+ case Conditional::SuperiorEqual:
+ case Conditional::InferiorEqual:
+ case Conditional::Different:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number(kspread_validity->valMin ) ) );
+ val.appendChild( tmp );
+ }
+ break;
+ case Conditional::Between:
+ case Conditional::DifferentTo:
+ {
+ QDomElement tmp = gnumeric_doc.createElement( "gmr:Expression0" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number(kspread_validity->valMin ) ) );
+ val.appendChild( tmp );
+ tmp = gnumeric_doc.createElement( "gmr:Expression1" );
+ tmp.appendChild( gnumeric_doc.createTextNode( QString::number(kspread_validity->valMax ) ) );
+ val.appendChild( tmp );
+ }
+ break;
+ }
+ break;
+ case Restriction::List:
+ val.setAttribute("Type", "3" );
+ switch( kspread_validity->m_cond )
+ {
+ case Conditional::None:
+ //Nothing
+ break;
+ case Conditional::Equal:
+ case Conditional::Superior:
+ case Conditional::Inferior:
+ case Conditional::SuperiorEqual:
+ case Conditional::InferiorEqual:
+ case Conditional::Different:
+ break;
+ case Conditional::Between:
+ case Conditional::DifferentTo:
+ break;
+ }
+ break;
+ }
+
+ return val;
+}
+
+QDomElement GNUMERICExport::GetFontStyle( QDomDocument gnumeric_doc,Cell * cell, int currentcolumn, int currentrow)
+{
+ QDomElement font_style;
+ kdDebug()<<" currentcolumn :"<<currentcolumn<<" currentrow :"<<currentrow<<endl;
+ font_style = gnumeric_doc.createElement("gmr:Font");
+ font_style.appendChild(gnumeric_doc.createTextNode(cell->format()->textFontFamily(currentcolumn, currentrow)));
+
+ if (cell->format()->textFontItalic(currentcolumn,currentrow) || (isLink && isLinkItalic))
+ {
+ font_style.setAttribute("Italic","1");
+ }
+ if (cell->format()->textFontBold(currentcolumn,currentrow) || (isLink && isLinkBold))
+ {
+ font_style.setAttribute("Bold","1");
+ }
+ if (cell->format()->textFontUnderline(currentcolumn,currentrow))
+ {
+ font_style.setAttribute("Underline","1");
+ }
+ if (cell->format()->textFontStrike(currentcolumn,currentrow))
+ {
+ font_style.setAttribute("StrikeThrough","1");
+ }
+ if (cell->format()->textFontSize(currentcolumn,currentrow))
+ {
+ font_style.setAttribute("Unit",QString::number(cell->format()->textFontSize(currentcolumn,currentrow)));
+ }
+
+ return font_style;
+}
+
+QDomElement GNUMERICExport::GetLinkStyle(QDomDocument gnumeric_doc)
+{
+ QDomElement link_style;
+
+ link_style = gnumeric_doc.createElement("gmr:HyperLink");
+
+ QString path;
+
+ path = linkUrl;
+
+ if (path.section(":",0,0).lower() == "http")
+ link_style.setAttribute("type","GnmHLinkURL");
+ else if (path.section(":",0,0).lower() == "mailto")
+ link_style.setAttribute("type","GnmHLinkEMail");
+ else if (path.section(":",0,0).lower() == "file")
+ link_style.setAttribute("type","GnmHLinkExternal");
+ else if (path.left(5).lower() == "sheet")
+ link_style.setAttribute("type","GnmHLinkCurWB");
+ else
+ link_style.setAttribute("type","");
+
+ link_style.setAttribute("target",path);
+
+ // KSpread doesn't support link tips.
+ link_style.setAttribute("tip","");
+
+ return link_style;
+}
+
+QDomElement GNUMERICExport::GetCellStyle(QDomDocument gnumeric_doc,Cell * cell, int currentcolumn, int currentrow)
+{
+ QColorGroup defaultColorGroup = QApplication::palette().active();
+
+ QDomElement cell_style;
+
+ cell_style = gnumeric_doc.createElement("gmr:Style");
+
+ int red, green, blue;
+
+ QColor bgColor = cell->bgColor(currentcolumn, currentrow);
+ red = bgColor.red()<<8;
+ green = bgColor.green()<<8;
+ blue = bgColor.blue()<<8;
+
+ switch (cell->format()->backGroundBrushStyle(currentcolumn, currentrow))
+ {
+ case Qt::NoBrush:
+ cell_style.setAttribute("Shade","0");
+ break;
+ case Qt::SolidPattern:
+ // 100%
+ cell_style.setAttribute("Shade","1");
+ break;
+ case Qt::Dense1Pattern:
+ // 87.5%
+ cell_style.setAttribute("Shade","25");
+ break;
+ case Qt::Dense2Pattern:
+ // 75%
+ cell_style.setAttribute("Shade","2");
+ break;
+ case Qt::Dense3Pattern:
+ // 62.5%
+ // Not supported by GNumeric
+ // Fall back to 50%
+ cell_style.setAttribute("Shade","3");
+ break;
+ case Qt::Dense4Pattern:
+ // 50%
+ cell_style.setAttribute("Shade","3");
+ break;
+ case Qt::Dense5Pattern:
+ // 25%
+ cell_style.setAttribute("Shade","4");
+ break;
+ case Qt::Dense6Pattern:
+ // 12.5%
+ cell_style.setAttribute("Shade","5");
+ break;
+ case Qt::Dense7Pattern:
+ // 6.25%
+ cell_style.setAttribute("Shade","6");
+ break;
+ case Qt::HorPattern:
+ cell_style.setAttribute("Shade","13");
+ break;
+ case Qt::VerPattern:
+ cell_style.setAttribute("Shade","14");
+ break;
+ case Qt::CrossPattern:
+ cell_style.setAttribute("Shade","17");
+ break;
+ case Qt::BDiagPattern:
+ cell_style.setAttribute("Shade","16");
+ break;
+ case Qt::FDiagPattern:
+ cell_style.setAttribute("Shade","15");
+ break;
+ case Qt::DiagCrossPattern:
+ cell_style.setAttribute("Shade","18");
+ break;
+ case Qt::CustomPattern:
+ // Not supported by Gnumeric
+ cell_style.setAttribute("Shade","0");
+ break;
+ }
+
+ cell_style.setAttribute("Back",QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16) );
+
+
+ QColor textColor = cell->format()->textColor(currentcolumn, currentrow);
+ red = textColor.red()<<8;
+ green = textColor.green()<<8;
+ blue = textColor.blue()<<8;
+
+ cell_style.setAttribute("Fore",QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16) );
+
+ if (cell->format()->align(currentcolumn,currentrow) == Format::Undefined)
+ {
+ cell_style.setAttribute("HAlign","1");
+ }
+ else if (cell->format()->align(currentcolumn,currentrow) == Format::Left)
+ {
+ cell_style.setAttribute("HAlign","2");
+ }
+ else if (cell->format()->align(currentcolumn,currentrow) == Format::Right)
+ {
+ cell_style.setAttribute("HAlign","4");
+ }
+ else if (cell->format()->align(currentcolumn,currentrow) == Format::Center)
+ {
+ cell_style.setAttribute("HAlign","8");
+ }
+
+ if (cell->format()->alignY(currentcolumn,currentrow) == Format::Top)
+ {
+ cell_style.setAttribute("VAlign","1");
+ }
+ else if (cell->format()->alignY(currentcolumn,currentrow) == Format::Bottom)
+ {
+ cell_style.setAttribute("VAlign","2");
+ }
+ else if (cell->format()->alignY(currentcolumn,currentrow) == Format::Middle)
+ {
+ cell_style.setAttribute("VAlign","4");
+ }
+
+ if (cell->format()->multiRow(currentcolumn,currentrow))
+ cell_style.setAttribute("WrapText","1");
+ else
+ cell_style.setAttribute("WrapText","0");
+
+ // ShrinkToFit not supported by KSpread (?)
+ cell_style.setAttribute("ShrinkToFit","0");
+
+ // I'm not sure about the rotation values.
+ // I never got it to work in GNumeric.
+ cell_style.setAttribute("Rotation", QString::number(-1*cell->format()->getAngle(currentcolumn,currentrow)));
+
+ // The indentation in GNumeric is an integer value. In KSpread, it's a double.
+ // Save the double anyway, makes it even better when importing the document back in KSpread.
+ // TODO verify if it's correct, in import we "* 10.0"
+ cell_style.setAttribute("Indent", QString::number(cell->format()->getIndent(currentcolumn,currentrow)));
+
+ cell_style.setAttribute("Locked", !cell->format()->notProtected(currentcolumn,currentrow));
+
+ // A KSpread cell can have two options to hide: only formula hidden, or everything hidden.
+ // I only consider a cell with everything hidden as hidden.
+ // Gnumeric hides everything or nothing.
+ cell_style.setAttribute("Hidden", cell->format()->isHideAll(currentcolumn,currentrow));
+
+ QColor patColor = cell->format()->backGroundBrushColor(currentcolumn, currentrow);
+ red = patColor.red()<<8;
+ green = patColor.green()<<8;
+ blue = patColor.blue()<<8;
+
+ cell_style.setAttribute("PatternColor", QString::number(red,16)+":"+QString::number(green,16) +":"+QString::number(blue,16));
+
+ if (isLink)
+ cell_style.appendChild(GetLinkStyle(gnumeric_doc));
+
+ cell_style.appendChild(GetFontStyle(gnumeric_doc, cell, currentcolumn, currentrow));
+
+ if ( cell->getValidity() )
+ {
+ cell_style.appendChild( GetValidity( gnumeric_doc, cell ) );
+ }
+
+ QString stringFormat;
+
+ Format::Currency c;
+ Currency currency;
+
+ switch( cell->format()->getFormatType(currentcolumn, currentrow))
+ {
+ case Number_format:
+ stringFormat="0.00";
+ break;
+ case Text_format:
+ stringFormat="general";
+ break;
+ case Money_format:
+
+ if (!cell->format()->currencyInfo(c))
+ {
+ stringFormat = "0.00";
+ break;
+ }
+
+ if (currency.getCurrencyCode(c.type).isEmpty())
+ stringFormat = "0.00";
+ else if (currency.getCurrencyCode(c.type) == "$")
+ stringFormat = "$0.00";
+ else if (currency.getCurrencyCode(c.type) == QString::fromUtf8("€"))
+ stringFormat = "[$€-2]0.00";
+ else if (currency.getCurrencyCode(c.type) == QString::fromUtf8("£"))
+ stringFormat = "£0.00";
+ else if (currency.getCurrencyCode(c.type) == QString::fromUtf8("¥"))
+ stringFormat = "¥0.00";
+ else
+ stringFormat="[$" + currency.getCurrencyCode(c.type) + "]0.00";
+
+ break;
+ case Percentage_format:
+ stringFormat="0.00%";
+ break;
+ case Scientific_format:
+ stringFormat="0.00E+00";
+ break;
+ case ShortDate_format:
+ stringFormat=cell->locale()->dateFormatShort();
+ break;
+ case TextDate_format:
+ stringFormat=cell->locale()->dateFormat();
+ break;
+ case date_format1:
+ stringFormat="dd-mmm-yy";
+ break;
+ case date_format2:
+ stringFormat="dd-mmm-yyyy";
+ break;
+ case date_format3:
+ stringFormat="dd-mmm";
+ break;
+ case date_format4:
+ stringFormat="dd-mm";
+ break;
+ case date_format5:
+ stringFormat="dd/mm/yy";
+ break;
+ case date_format6:
+ stringFormat="dd/mm/yyyy";
+ break;
+ case date_format7:
+ stringFormat="mmm-yy";
+ break;
+ case date_format8:
+ stringFormat="mmmm-yy";
+ break;
+ case date_format9:
+ stringFormat="mmmm-yyyy";
+ break;
+ case date_format10:
+ stringFormat="m-yy";
+ break;
+ case date_format11:
+ stringFormat="dd/mmm";
+ break;
+ case date_format12:
+ stringFormat="dd/mm";
+ break;
+ case date_format13:
+ stringFormat="dd/mmm/yyyy";
+ break;
+ case date_format14:
+ stringFormat="yyyy/mmm/dd";
+ break;
+ case date_format15:
+ stringFormat="yyyy-mmm-dd";
+ break;
+ case date_format16:
+ stringFormat="yyyy-mm-dd";
+ break;
+ case date_format17:
+ stringFormat="d mmmm yyyy";
+ break;
+ case date_format18:
+ stringFormat="mm/dd/yyyy";
+ break;
+ case date_format19:
+ stringFormat="mm/dd/yy";
+ break;
+ case date_format20:
+ stringFormat="mmm/dd/yy";
+ break;
+ case date_format21:
+ stringFormat="mmm/dd/yyyy";
+ break;
+ case date_format22:
+ stringFormat="mmm-yyyy";
+ break;
+ case date_format23:
+ stringFormat="yyyy";
+ break;
+ case date_format24:
+ stringFormat="yy";
+ break;
+ case date_format25:
+ stringFormat="yyyy/mm/dd";
+ break;
+ case date_format26:
+ stringFormat="yyyy/mmm/dd";
+ break;
+ case Time_format:
+ case SecondeTime_format:
+ stringFormat=cell->locale()->timeFormat();
+ break;
+ case Time_format1:
+ stringFormat = "h:mm AM/PM";
+ break;
+ case Time_format2:
+ stringFormat = "h:mm:ss AM/PM";
+ break;
+ case Time_format3:
+ stringFormat = "h \"h\" mm \"min\" ss \"s\"";
+ break;
+ case Time_format4:
+ stringFormat = "h:mm";
+ break;
+ case Time_format5:
+ stringFormat = "h:mm:ss";
+ break;
+ case Time_format6:
+ stringFormat = "mm:ss";
+ break;
+ case Time_format7:
+ stringFormat = "[h]:mm:ss";
+ break;
+ case Time_format8:
+ stringFormat = "[h]:mm";
+ break;
+ case fraction_half:
+ stringFormat="# ?/2";
+ break;
+ case fraction_quarter:
+ stringFormat="# ?/4";
+ break;
+ case fraction_eighth:
+ stringFormat="# ?/8";
+ break;
+ case fraction_sixteenth:
+ stringFormat="# ?/16";
+ break;
+ case fraction_tenth:
+ stringFormat="# ?/10";
+ break;
+ case fraction_hundredth:
+ stringFormat="# ?/100";
+ break;
+ case fraction_one_digit:
+ stringFormat="# ?/?";
+ break;
+ case fraction_two_digits:
+ stringFormat="# ?\?/?\?";
+ break;
+ case fraction_three_digits:
+ stringFormat="# ?\?\?/?\?\?";
+ break;
+ case Custom_format:
+ stringFormat = cell->format()->getFormatString(currentcolumn,currentrow);
+ break;
+ default:
+ break;
+ }
+ cell_style.setAttribute("Format",stringFormat);
+
+ if(hasBorder(cell, currentcolumn, currentrow))
+ cell_style.appendChild(GetBorderStyle(gnumeric_doc, cell, currentcolumn, currentrow));
+
+ return cell_style;
+}
+
+
+void GNUMERICExport::addAttributeItem(QDomDocument gnumeric_doc, QDomElement attributes, const QString& type, const QString& name, bool value)
+{
+ QDomElement gmr_attribute, gmr_type, gmr_name, gmr_value;
+
+ gmr_attribute = gnumeric_doc.createElement("gmr:Attribute");
+ attributes.appendChild(gmr_attribute);
+
+ gmr_type = gnumeric_doc.createElement("gmr:type");
+ gmr_type.appendChild(gnumeric_doc.createTextNode(type));
+ gmr_attribute.appendChild(gmr_type);
+
+ gmr_name = gnumeric_doc.createElement("gmr:name");
+ gmr_name.appendChild(gnumeric_doc.createTextNode(name));
+ gmr_attribute.appendChild(gmr_name);
+
+ QString txtValue;
+ if (value)
+ txtValue = "true";
+ else
+ txtValue = "false";
+
+ gmr_value = gnumeric_doc.createElement("gmr:value");
+ gmr_value.appendChild(gnumeric_doc.createTextNode(txtValue));
+ gmr_attribute.appendChild(gmr_value);
+}
+
+void GNUMERICExport::addSummaryItem(QDomDocument gnumeric_doc, QDomElement summary, const QString& name, const QString& value)
+{
+ if ( value.isEmpty() )
+ return;
+ QDomElement gmr_item, gmr_name, gmr_val_string;
+
+ gmr_item = gnumeric_doc.createElement("gmr:Item");
+ summary.appendChild(gmr_item);
+
+ gmr_name = gnumeric_doc.createElement("gmr:name");
+ gmr_name.appendChild(gnumeric_doc.createTextNode(name));
+ gmr_item.appendChild(gmr_name);
+
+ gmr_val_string = gnumeric_doc.createElement("gmr:val-string");
+ gmr_val_string.appendChild(gnumeric_doc.createTextNode(value));
+ gmr_item.appendChild(gmr_val_string);
+}
+
+// The reason why we use the KoDocument* approach and not the QDomDocument
+// approach is because we don't want to export formulas but values !
+KoFilter::ConversionStatus GNUMERICExport::convert( const QCString& from, const QCString& to )
+{
+ kdDebug(30521) << "Exporting GNUmeric" << endl;
+
+ QDomDocument gnumeric_doc=QDomDocument();
+
+ Sheet* table;
+ KoDocument* document = m_chain->inputDocument();
+
+ if (!document)
+ return KoFilter::StupidError;
+
+ if ( !::qt_cast<const KSpread::Doc *>( document ) ) // it's safer that way :)
+ {
+ kdWarning(30521) << "document isn't a KSpread::Doc but a " << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+ if (to != "application/x-gnumeric" || from != "application/x-kspread")
+ {
+ kdWarning(30521) << "Invalid mimetypes " << to << " " << from << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ Doc* ksdoc = (Doc*)document;
+
+ if (ksdoc->mimeType() != "application/x-kspread")
+ {
+ kdWarning(30521) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ /* This could be Made into a function */
+
+ gnumeric_doc.appendChild( gnumeric_doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
+
+ QDomElement workbook = gnumeric_doc.createElement("gmr:Workbook");
+ workbook.setAttribute("xmlns:gmr","http://www.gnumeric.org/v10.dtd");
+ workbook.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
+ workbook.setAttribute("xmlns:schemaLocation", "http://www.gnumeric.org/v8.xsd");
+ gnumeric_doc.appendChild(workbook);
+
+ /* End Made into a function */
+
+ QDomElement sheets,sheet,tmp,cells,selections, cols,rows,styles,merged, margins, top, left, bottom, right, orientation, paper, header, footer, customSize, cellComment, objects, repeatColumns, repeatRows;
+
+ KoDocumentInfo *DocumentInfo = document->documentInfo();
+ KoDocumentInfoAbout *aboutPage = static_cast<KoDocumentInfoAbout *>(DocumentInfo->page( "about" ));
+
+ KoDocumentInfoAuthor *authorPage = static_cast<KoDocumentInfoAuthor*>(DocumentInfo->page( "author" ));
+
+ /*
+ * Attributes
+ */
+ QDomElement attributes = gnumeric_doc.createElement("gmr:Attributes");
+ workbook.appendChild(attributes);
+
+ addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::show_horizontal_scrollbar", ksdoc->showHorizontalScrollBar());
+ addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::show_vertical_scrollbar", ksdoc->showVerticalScrollBar());
+ addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::show_notebook_tabs", ksdoc->showTabBar());
+ if (ksdoc->completionMode() == KGlobalSettings::CompletionAuto)
+ addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::do_auto_completion", "true");
+ else
+ addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::do_auto_completion", "false");
+ addAttributeItem(gnumeric_doc, attributes, "4", "WorkbookView::is_protected", ksdoc->map()->isProtected());
+
+ /*
+ * Doccument summary
+ */
+ QDomElement summary = gnumeric_doc.createElement("gmr:Summary");
+ workbook.appendChild(summary);
+
+ addSummaryItem(gnumeric_doc, summary, "title", aboutPage->title());
+ addSummaryItem(gnumeric_doc, summary, "company", authorPage->company());
+ addSummaryItem(gnumeric_doc, summary, "author", authorPage->fullName());
+ addSummaryItem(gnumeric_doc, summary, "comments", aboutPage->abstract());
+ addSummaryItem(gnumeric_doc, summary, "keywords", aboutPage->keywords());
+
+ addSummaryItem(gnumeric_doc, summary, "application", "KSpread");
+
+ /*
+ * Sheet name index (necessary for the gnumeric xml_sax importer)
+ */
+ QDomElement sheetNameIndex = gnumeric_doc.createElement("gmr:SheetNameIndex");
+ workbook.appendChild(sheetNameIndex);
+
+ for (table = ksdoc->map()->firstSheet(); table != 0L; table =ksdoc->map()->nextSheet())
+ {
+ QDomElement sheetName = gnumeric_doc.createElement("gmr:SheetName");
+ sheetName.appendChild(gnumeric_doc.createTextNode(table->tableName()));
+ sheetNameIndex.appendChild(sheetName);
+ }
+
+ /*
+ * Area Names
+ */
+ /*
+ <gmr:Names>
+ <gmr:Name>
+ <gmr:name>test</gmr:name>
+ <gmr:value>Sheet2!$A$2:$D$10</gmr:value>
+ <gmr:position>A1</gmr:position>
+ </gmr:Name>
+ <gmr:Name>
+ <gmr:name>voiture</gmr:name>
+ <gmr:value>Sheet2!$A$2:$D$8</gmr:value>
+ <gmr:position>A1</gmr:position>
+ </gmr:Name>
+ </gmr:Names>
+ */
+ if ( ksdoc->listArea().count()>0 )
+ {
+ QDomElement areaNames = gnumeric_doc.createElement("gmr:Names");
+ const QValueList<Reference> &area = ksdoc->listArea(); // copying by value is slow!
+ QValueList<Reference>::ConstIterator it = area.begin();
+ QValueList<Reference>::ConstIterator end = area.end();
+ for ( ; it != end; ++it )
+ {
+ QDomElement areaName = gnumeric_doc.createElement("gmr:Name");
+ QDomElement areaNameElement = gnumeric_doc.createElement("gmr:name");
+ areaNameElement.appendChild(gnumeric_doc.createTextNode(( *it ).ref_name) );
+ areaName.appendChild( areaNameElement );
+ QDomElement areaNameValue = gnumeric_doc.createElement("gmr:value");
+ areaNameValue.appendChild(gnumeric_doc.createTextNode( convertRefToRange( ( *it ).sheet_name, ( *it ).rect ) ) );
+ areaName.appendChild( areaNameValue );
+ areaNames.appendChild( areaName );
+ //TODO <gmr:position>A1</gmr:position> I don't know what is it.
+ }
+ workbook.appendChild(areaNames);
+ }
+
+
+ /*
+ * Sheets
+ */
+ sheets = gnumeric_doc.createElement("gmr:Sheets");
+ workbook.appendChild(sheets);
+
+ QString str;
+
+ View * view = static_cast<View*>( ksdoc->views().getFirst());
+ Canvas * canvas=0L;
+ QString activeTableName;
+ if (view)
+ {
+ canvas = view->canvasWidget();
+ activeTableName = canvas->activeSheet()->sheetName();
+ }
+ int i = 0;
+ int indexActiveTable=0;
+ for (table = ksdoc->map()->firstSheet(); table != 0L; table =ksdoc->map()->nextSheet(), i++)
+ {
+ if ( table->print()->paperFormat()==PG_CUSTOM )
+ {
+ customSize = gnumeric_doc.createElement( "gmr:Geometry" );
+ customSize.setAttribute( "Width", POINT_TO_MM ( table->print()->paperWidth() ));
+ customSize.setAttribute( "Height", POINT_TO_MM (table->print()->paperWidth() ));
+ sheets.appendChild(customSize);
+ //<gmr:Geometry Width="768" Height="365"/>
+ }
+
+ sheet = gnumeric_doc.createElement("gmr:Sheet");
+ sheets.appendChild(sheet);
+
+ sheet.setAttribute("DisplayFormulas", table->getShowFormula() ? "true" : "false" );
+ sheet.setAttribute("HideZero", table->getHideZero()? "true" : "false");
+ sheet.setAttribute("HideGrid", !table->getShowGrid()? "true" : "false");
+ sheet.setAttribute("HideColHeader", ( !ksdoc->showColumnHeader() ? "true" : "false" ));
+ sheet.setAttribute("HideRowHeader", ( !ksdoc->showRowHeader()? "true" : "false" ));
+ /* Not available in KSpread ?
+ * sheet.setAttribute("DisplayOutlines", "true");
+ * sheet.setAttribute("OutlineSymbolsBelow", "true");
+ * sheet.setAttribute("OutlineSymbolsRight", "true");
+ * sheet.setAttribute("TabColor", "");
+ * sheet.setAttribute("TabTextColor", "");
+ */
+
+ tmp = gnumeric_doc.createElement("gmr:Name");
+ if ( table->tableName()==activeTableName )
+ indexActiveTable = i;
+
+ tmp.appendChild(gnumeric_doc.createTextNode(table->tableName()));
+
+ sheet.appendChild(tmp);
+
+ tmp = gnumeric_doc.createElement("gmr:MaxCol");
+ tmp.appendChild(gnumeric_doc.createTextNode(QString::number(table->maxColumn())));
+ sheet.appendChild(tmp);
+
+ tmp = gnumeric_doc.createElement("gmr:MaxRow");
+
+ tmp.appendChild(gnumeric_doc.createTextNode(QString::number(table->maxRow())));
+ sheet.appendChild(tmp);
+
+ // Zoom value doesn't appear to be correct
+ // KSpread 200% gives zoom() = 2.5, this in GNumeric = 250%
+ tmp = gnumeric_doc.createElement("gmr:Zoom");
+ if (view)
+ tmp.appendChild(gnumeric_doc.createTextNode(QString::number(canvas->zoom())));
+ else
+ tmp.appendChild(gnumeric_doc.createTextNode("1.0"));
+ sheet.appendChild(tmp);
+
+ //Print Info
+ tmp = gnumeric_doc.createElement( "gmr:PrintInformation" );
+ margins = gnumeric_doc.createElement( "gmr:Margins" );
+
+ top = gnumeric_doc.createElement( "gmr:top" );
+ top.setAttribute("Points", table->print()->topBorder());
+ top.setAttribute("PrefUnit", "mm");
+ margins.appendChild( top );
+
+ bottom = gnumeric_doc.createElement( "gmr:bottom" );
+ bottom.setAttribute("Points", table->print()->bottomBorder());
+ bottom.setAttribute("PrefUnit", "mm");
+ margins.appendChild( bottom );
+
+ left = gnumeric_doc.createElement( "gmr:left" );
+ left.setAttribute("Points", table->print()->leftBorder());
+ left.setAttribute("PrefUnit", "mm");
+ margins.appendChild( left );
+
+ right = gnumeric_doc.createElement( "gmr:right" );
+ right.setAttribute("Points", table->print()->rightBorder());
+ right.setAttribute("PrefUnit", "mm");
+ margins.appendChild( right );
+
+ tmp.appendChild( margins );
+ sheet.appendChild(tmp);
+
+ orientation = gnumeric_doc.createElement( "gmr:orientation" );
+ QString orientString = table->print()->orientation() == PG_LANDSCAPE ? "landscape" : "portrait";
+ orientation.appendChild( gnumeric_doc.createTextNode(orientString) );
+ tmp.appendChild( orientation );
+
+ //TODO for future
+ //<gmr:repeat_top value="A1:IV5"/>
+ //<gmr:repeat_left value="B1:D65536"/>
+
+ int _tmpRepeatColumnStart = table->print()->printRepeatColumns().first;
+ int _tmpRepeatColumnEnd = table->print()->printRepeatColumns().second;
+ if ( _tmpRepeatColumnStart!=0 )
+ {
+ repeatColumns = gnumeric_doc.createElement( "gmr:repeat_left" );
+ QString value = Cell::columnName( _tmpRepeatColumnStart )+"1:"+Cell::columnName(_tmpRepeatColumnEnd )+"65536";
+ repeatColumns.setAttribute( "value", value );
+ tmp.appendChild( repeatColumns );
+ }
+ int _tmpRepeatRowStart = table->print()->printRepeatRows().first;
+ int _tmpRepeatRowEnd = table->print()->printRepeatRows().second;
+ if ( _tmpRepeatRowStart!=0 )
+ {
+ repeatRows = gnumeric_doc.createElement( "gmr:repeat_top" );
+ QString value = "A"+ QString::number(_tmpRepeatRowStart ) +":IV"+QString::number( _tmpRepeatRowEnd );
+ repeatRows.setAttribute( "value", value );
+ tmp.appendChild( repeatRows );
+ }
+
+ header = gnumeric_doc.createElement( "gmr:Header" );
+ header.setAttribute( "Left", convertVariable(table->print()->headLeft() ) );
+ header.setAttribute( "Middle", convertVariable(table->print()->headMid() ) );
+ header.setAttribute( "Right", convertVariable(table->print()->headRight() ) );
+ tmp.appendChild( header );
+
+ footer = gnumeric_doc.createElement( "gmr:Footer" );
+ footer.setAttribute( "Left", convertVariable( table->print()->footLeft() ) );
+ footer.setAttribute( "Middle", convertVariable( table->print()->footMid() ) );
+ footer.setAttribute( "Right", convertVariable( table->print()->footRight() ));
+ tmp.appendChild( footer );
+
+ paper = gnumeric_doc.createElement( "gmr:paper" );
+ paper.appendChild( gnumeric_doc.createTextNode( table->print()->paperFormatString() ) );
+ tmp.appendChild( paper );
+
+ styles = gnumeric_doc.createElement("gmr:Styles");
+ sheet.appendChild(styles);
+
+ cells = gnumeric_doc.createElement("gmr:Cells");
+ sheet.appendChild(cells);
+
+ objects = gnumeric_doc.createElement("gmr:Objects");
+ sheet.appendChild(objects);
+
+ merged = gnumeric_doc.createElement("gmr:MergedRegions");
+ bool mergedCells = false; // if there are no merged cells in this sheet, don't write an
+ // empty mergedRegions to the file.
+ // So, depending on the value of mergedCells,
+ // the merged dom element is added or not.
+
+ cols = gnumeric_doc.createElement("gmr:Cols");
+ sheet.appendChild(cols);
+
+ rows = gnumeric_doc.createElement("gmr:Rows");
+ sheet.appendChild(rows);
+
+ /*
+ selections = gnumeric_doc.createElement("gmr:Selections");
+ sheet.appendChild(selections);
+ */
+ // Ah ah ah - the document is const, but the map and table aren't. Safety: 0.
+ // Either we get hold of Sheet::m_dctCells and apply the old method below
+ // (for sorting) or, cleaner and already sorted, we use Sheet's API
+ // (slower probably, though)
+ int iMaxColumn = table->maxColumn();
+ int iMaxRow = table->maxRow();
+
+ // this is just a bad approximation which fails for documents with less than 50 rows, but
+ // we don't need any progress stuff there anyway :) (Werner)
+ int value=0;
+ int step=iMaxRow > 50 ? iMaxRow/50 : 1;
+ int i=1;
+
+ QString emptyLines;
+
+ /* Save selection info. */
+
+ /* can't save selection anymore -- part of the view, not table */
+ /*
+ QDomElement selection = gnumeric_doc.createElement("gmr:Selection");
+ QRect table_selection(table->selection());
+
+ selections.appendChild(selection);
+ */
+ /* <gmr:Selection startCol="3" startRow="2" endCol="3" endRow="2"/>*/
+ /*
+ selection.setAttribute("startCol", QString::number(table_selection.left()-1));
+ selection.setAttribute("startRow", QString::number(table_selection.top()-1));
+
+ selection.setAttribute("endCol", QString::number(table_selection.right()-1));
+ selection.setAttribute("endRow", QString::number(table_selection.bottom()-1));
+ */
+ /* End selection info. */
+
+
+ /* Start COLS */
+ ColumnFormat *cl=table->firstCol();
+ while (cl)
+ {
+ QDomElement colinfo = gnumeric_doc.createElement("gmr:ColInfo");
+ cols.appendChild(colinfo);
+ colinfo.setAttribute("No", QString::number(cl->column()-1));
+ colinfo.setAttribute("Hidden", QString::number(cl->isHide()));
+ colinfo.setAttribute("Unit", QString::number(cl->dblWidth()));
+
+ cl=cl->next();
+ }
+
+ /* End COLS */
+
+ // RowFormat *rl=table->m_cells.firstCell;
+ // <gmr:ColInfo No="1" Unit="96.75" MarginA="2" MarginB="2" HardSize="-1" Hidden="0"/>
+
+ /* Start ROWS */
+ RowFormat *rl=table->firstRow();
+ while (rl)
+ {
+ QDomElement rowinfo = gnumeric_doc.createElement("gmr:RowInfo");
+ rows.appendChild(rowinfo);
+ rowinfo.setAttribute("No", QString::number(rl->row()-1));
+ rowinfo.setAttribute("Hidden", QString::number(rl->isHide()));
+ rowinfo.setAttribute("Unit", QString::number(rl->dblHeight()));
+
+ rl=rl->next();
+ }
+
+ /* End ROWS */
+
+ //rl->setHeight
+ // colinfo.info();
+ /*
+ <gmr:ColInfo No="1" Unit="96.75" MarginA="2" MarginB="2" HardSize="-1" Hidden="0"/>
+ <gmr:ColInfo No="3" Unit="113.25" MarginA="2" MarginB="2" HardSize="-1"
+ Hidden="0"/>
+ */
+
+ /* End COLS */
+
+ for (int currentrow = 1; currentrow <= iMaxRow; ++currentrow, ++i)
+ {
+ if(i>step)
+ {
+ value+=2;
+ emit sigProgress(value);
+ i=0;
+ }
+
+ QString line;
+ for (int currentcolumn = 1; currentcolumn <= iMaxColumn; currentcolumn++)
+ {
+ QDomElement cell_contents;
+ Cell * cell = table->cellAt( currentcolumn, currentrow, false );
+
+ QString text, style;
+ QDomDocument domLink;
+ QDomElement domRoot;
+ QDomNode domNode;
+ QDomNodeList childNodes;
+
+ if (!cell->isDefault() && !cell->isEmpty())
+ {
+ if ( cell->isFormula() )
+ {
+ QString tmp = cell->text();
+ if ( tmp.contains( "==" ) )
+ tmp=tmp.replace( "==", "=" );
+ text = tmp;
+ isLink = false;
+ }
+ else if ( !cell->link().isEmpty() )
+ {
+ isLink = true;
+ isLinkBold = false;
+ isLinkItalic = false;
+ //TODO FIXME
+ linkUrl = cell->link();
+ linkText = cell->text();
+
+ }
+ else
+ {
+ text = cell->text();
+ isLink = false;
+ }
+#if 0
+ switch (cell->content())
+ {
+ case Cell::Text:
+ text = cell->text();
+ isLink = false;
+ break;
+ case Cell::RichText:
+ // hyperlinks
+ // Extract the cell text
+ isLink = true;
+ isLinkBold = false;
+ isLinkItalic = false;
+ domLink.setContent(cell->text().section("!",1,1));
+
+ domNode = domLink.firstChild();
+ domRoot = domNode.toElement();
+ text = domNode.toElement().text();
+
+ while (!domNode.isNull())
+ {
+ style = domNode.toElement().tagName();
+
+ if (style == "b")
+ isLinkBold = true;
+
+ if (style == "i")
+ isLinkItalic = true;
+
+ domNode = domNode.firstChild();
+ }
+
+ //kdDebug(30521) << "---> link, text = " << text << endl;
+
+ linkUrl = domRoot.attribute("href");
+ linkText = text;
+
+ break;
+ case Cell::VisualFormula:
+ isLink = false;
+ text = cell->text(); // untested
+ break;
+ case Cell::Formula:
+ isLink = false;
+ QString tmp = cell->text();
+ if ( tmp =="==" )
+ tmp=replace( "==", "=" );
+ /* cell->calc( TRUE ); // Incredible, cells are not calculated if the document was just opened text = cell->valueString(); */
+ text = tmp;
+ break;
+ }
+#endif
+ }
+
+ if (!cell->isDefault())
+ {
+
+ // Check if the cell is merged
+ // Only cells with content are interesting?
+ // Otherwise it can take a while to parse a large sheet
+
+ if (cell->doesMergeCells())
+ {
+ // The cell is forced to occupy other cells
+ QDomElement merge = gnumeric_doc.createElement("gmr:Merge");
+
+ // Set up the range
+ QString fromCol, toCol, fromRow, toRow;
+ fromCol = cell->columnName(currentcolumn);
+ fromRow = QString::number(currentrow);
+ toCol = cell->columnName(currentcolumn + cell->mergedXCells());
+ toRow = QString::number(currentrow + cell->mergedYCells());
+
+ merge.appendChild(gnumeric_doc.createTextNode(fromCol + fromRow + ":" + toCol + toRow));
+ mergedCells = true;
+ merged.appendChild(merge);
+ }
+ // ---
+ if ( !cell->format()->comment( currentcolumn, currentrow ).isEmpty() )
+ {
+ //<gmr:CellComment Author="" Text="cvbcvbxcvb&#10;cb&#10;xc&#10;vbxcv&#10;" ObjectBound="A1" ObjectOffset="0 0 0 0" ObjectAnchorType="17 16 17 16" Direction="17"/>
+ cellComment = gnumeric_doc.createElement("gmr:CellComment");
+ cellComment.setAttribute( "Text", cell->format()->comment( currentcolumn, currentrow ) );
+ QString sCell=QString( "%1%2" ).arg( Cell::columnName(currentcolumn ) ).arg( currentrow );
+
+ cellComment.setAttribute("ObjectBound", sCell );
+ objects.appendChild(cellComment);
+
+ }
+ QDomElement gnumeric_cell = gnumeric_doc.createElement("gmr:Cell");
+ QDomElement cell_style;
+
+ QDomElement style_region = gnumeric_doc.createElement("gmr:StyleRegion");
+
+ cells.appendChild(gnumeric_cell);
+
+ gnumeric_cell.setAttribute("Col", QString::number(currentcolumn-1));
+ gnumeric_cell.setAttribute("Row", QString::number(currentrow-1));
+
+ /* Right now, we create a single region for each cell.. This is inefficient,
+ * but the implementation is quicker.. Probably later we will have to
+ * consolidate styles into style regions.
+ */
+
+ style_region.setAttribute("startCol", QString::number(currentcolumn-1));
+ style_region.setAttribute("startRow", QString::number(currentrow-1));
+ style_region.setAttribute("endCol", QString::number(currentcolumn-1));
+ style_region.setAttribute("endRow", QString::number(currentrow-1));
+
+ cell_style = GetCellStyle(gnumeric_doc,cell,currentcolumn,currentrow);
+
+ style_region.appendChild(cell_style);
+
+ styles.appendChild(style_region);
+
+ //cell_contents = gnumeric_doc.createElement("gmr:Content");
+ gnumeric_cell.appendChild(gnumeric_doc.createTextNode(text));
+ //gnumeric_cell.appendChild(cell_contents);
+ }
+
+ // Append a delimiter, but in a temp string -> if no other real cell in this line,
+ // then those will be dropped
+ }
+ }
+
+ if (mergedCells)
+ sheet.appendChild(merged);
+ }
+ QDomElement uidata = gnumeric_doc.createElement("gmr:UIData");
+ uidata.setAttribute( "SelectedTab", indexActiveTable );
+ workbook.appendChild(uidata);
+
+ str = gnumeric_doc.toString ();
+
+ emit sigProgress(100);
+
+ // Ok, now write to export file
+
+ QIODevice* out = KFilterDev::deviceForFile(m_chain->outputFile(),"application/x-gzip");
+
+ if (!out)
+ {
+ kdError(30521) << "No output file! Aborting!" << endl;
+ return KoFilter::FileNotFound;
+ }
+
+ if (!out->open(IO_WriteOnly))
+ {
+ kdError(30521) << "Unable to open output file! Aborting!" << endl;
+ delete out;
+ return KoFilter::FileNotFound;
+ }
+
+ QTextStream streamOut(out);
+
+ streamOut << str;
+
+ out->close();
+ delete out;
+
+ return KoFilter::OK;
+}
+
+
+QString GNUMERICExport::convertRefToRange( const QString & table, const QRect & rect )
+{
+ QPoint topLeft( rect.topLeft() );
+ QPoint bottomRight( rect.bottomRight() );
+ if ( topLeft == bottomRight )
+ return convertRefToBase( table, rect );
+ QString s;
+ s += table;
+ s += "!$";
+ s += Cell::columnName( topLeft.x() );
+ s += '$';
+ s += QString::number( topLeft.y() );
+ s += ":$";
+ s += Cell::columnName( bottomRight.x() );
+ s += '$';
+ s += QString::number( bottomRight.y() );
+
+ return s;
+}
+
+
+QString GNUMERICExport::convertRefToBase( const QString & table, const QRect & rect )
+{
+ QPoint bottomRight( rect.bottomRight() );
+
+ QString s;
+ s = table;
+ s += "!$";
+ s += Cell::columnName( bottomRight.x() );
+ s += '$';
+ s += QString::number( bottomRight.y() );
+
+ return s;
+}
+
+QString GNUMERICExport::convertVariable( QString headerFooter )
+{
+ headerFooter = headerFooter.replace( "<sheet>", "&[TAB]" );
+ headerFooter = headerFooter.replace( "<date>", "&[DATE]" );
+ headerFooter = headerFooter.replace( "<page>", "&[PAGE]" );
+ headerFooter = headerFooter.replace( "<pages>", "&[PAGES]" );
+ headerFooter = headerFooter.replace( "<time>", "&[TIME]" );
+ headerFooter = headerFooter.replace( "<file>", "&[FILE]" );
+
+ return headerFooter;
+}
+
+#include "gnumericexport.moc"
diff --git a/filters/kspread/gnumeric/gnumericexport.h b/filters/kspread/gnumeric/gnumericexport.h
new file mode 100644
index 000000000..a56c6482f
--- /dev/null
+++ b/filters/kspread/gnumeric/gnumericexport.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef GNUMERICEXPORT_TEST_H
+#define GNUMERICEXPORT_TEST_H
+
+#include <KoFilter.h>
+#include <qdom.h>
+
+namespace KSpread
+{
+ class Cell;
+}
+
+class GNUMERICExport : public KoFilter {
+
+ Q_OBJECT
+
+public:
+ GNUMERICExport(KoFilter *parent, const char*name, const QStringList&);
+ virtual ~GNUMERICExport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+
+private:
+ QDomElement GetCellStyle(QDomDocument gnumeric_doc, KSpread::Cell* cell, int currentcolumn, int currentrow);
+ QDomElement GetBorderStyle(QDomDocument gnumeric_doc, KSpread::Cell* cell, int currentcolumn, int currentrow);
+ QDomElement GetFontStyle(QDomDocument gnumeric_doc, KSpread::Cell* cell, int currentcolumn, int currentrow);
+ QDomElement GetLinkStyle(QDomDocument gnumeric_doc );
+ QDomElement GetValidity( QDomDocument gnumeric_doc, KSpread::Cell* cell );
+
+ void addAttributeItem(QDomDocument gnumeric_doc, QDomElement attributes, const QString& type, const QString& name, bool value);
+ void addSummaryItem(QDomDocument gnumeric_doc, QDomElement summary, const QString& name, const QString& value);
+ bool hasBorder(KSpread::Cell*cell, int currentcolumn, int currentrow);
+ const QString ColorToString(int red, int green, int blue);
+ QString convertVariable( QString headerFooter );
+ QString convertRefToRange( const QString & table, const QRect & rect );
+ QString convertRefToBase( const QString & table, const QRect & rect );
+ bool isLink;
+ QString linkText;
+ QString linkUrl;
+ bool isLinkBold;
+ bool isLinkItalic;
+
+};
+#endif
+
diff --git a/filters/kspread/gnumeric/gnumericimport.cc b/filters/kspread/gnumeric/gnumericimport.cc
new file mode 100644
index 000000000..6e114f37e
--- /dev/null
+++ b/filters/kspread/gnumeric/gnumericimport.cc
@@ -0,0 +1,2207 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+ Copyright (C) 2005 Laurent Montel <montel@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+/* GNUmeric import filter by Phillip Ezolt 6-2-2001 */
+/* phillipezolt@hotmail.com */
+/* additions: Norbert Andres nandres@web.de */
+
+#include <qdict.h>
+#include <qfile.h>
+#include <qstringlist.h>
+
+#include <gnumericimport.h>
+#include <kmessagebox.h>
+#include <kfilterdev.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <KoFilterChain.h>
+#include <KoGlobal.h>
+
+// hehe >:->
+#include <kspread_doc.h>
+#include <kspread_map.h>
+#include <kspread_sheet.h>
+#include <kspread_sheetprint.h>
+#include <kspread_cell.h>
+#include <kspread_util.h>
+#include <KoDocumentInfo.h>
+
+#include <math.h>
+
+#define SECS_PER_DAY 86400
+#define HALF_SEC (0.5 / SECS_PER_DAY)
+
+using namespace KSpread;
+
+// copied from gnumeric: src/format.c:
+static const int g_dateSerial_19000228 = 59;
+/* One less that the Julian day number of 19000101. */
+static int g_dateOrigin = 0;
+
+// copied from gnumeric: src/formats.c:
+static char const * cell_format_date [] = {
+ "m/d/yy", /* 0 Cell::date_format5*/
+ "m/d/yyyy", /* 1 Cell::date_format6*/
+ "d-mmm-yy", /* 2 Cell::date_format1 18-Feb-99 */
+ "d-mmm-yyyy", /* 3 Cell::date_format2 18-Feb-1999 */
+ "d-mmm", /* 4 Cell::date_format3 18-Feb */
+ "d-mm", /* 5 Cell::date_format4 18-05 */
+ "mmm/d", /* 6 Cell::date_format11*/
+ "mm/d", /* 7 Cell::date_format12*/
+ "mm/dd/yy", /* 8 Cell::date_format19*/
+ "mm/dd/yyyy", /* 9 Cell::date_format18*/
+ "mmm/dd/yy", /* 10 Cell::date_format20*/
+ "mmm/dd/yyyy", /* 11 Cell::date_format21*/
+ "mmm/ddd/yy", /* 12 */
+ "mmm/ddd/yyyy", /* 13 */
+ "mm/ddd/yy", /* 14 */
+ "mm/ddd/yyyy", /* 15 */
+ "mmm-yy", /* 16 Cell::date_format7*/
+ "mmm-yyyy", /* 17 Cell::date_format22*/
+ "mmmm-yy", /* 18 Cell::date_format8*/
+ "mmmm-yyyy", /* 19 Cell::date_format9*/
+ "m/d/yy h:mm", /* 20 */
+ "m/d/yyyy h:mm", /* 21 */
+ "yyyy/mm/d", /* 22 Cell::date_format25*/
+ "yyyy/mmm/d", /* 23 Cell::date_format14*/
+ "yyyy/mm/dd", /* 24 Cell::date_format25*/
+ "yyyy/mmm/dd", /* 25 Cell::date_format26*/
+ "yyyy-mm-d", /* 26 Cell::date_format16*/
+ "yyyy-mmm-d", /* 27 Cell::date_format15*/
+ "yyyy-mm-dd", /* 28 Cell::date_format16*/
+ "yyyy-mmm-dd", /* 29 Cell::date_format15*/
+ "yy", /* 30 Cell::date_format24*/
+ "yyyy", /* 31 Cell::date_format23*/
+ NULL
+};
+
+// copied from gnumeric: src/formats.c:
+static char const * cell_format_time [] = {
+ "h:mm AM/PM", // Cell::Time_format1 9 : 01 AM
+ "h:mm:ss AM/PM", // Cell::Time_format2 9:01:05 AM
+ "h:mm", // Cell::Time_format4 9:01
+ "h:mm:ss", // Cell::Time_format5 9:01:12
+ "m/d/yy h:mm",
+ "mm:ss", // Cell::Time_format6 01:12
+ "mm:ss.0", // Cell::Time_format6 01:12
+ "[h]:mm:ss",
+ "[h]:mm",
+ "[mm]:ss",
+ "[ss]",
+ NULL
+};
+
+namespace gnumeric_import_LNS
+{
+ QStringList list1;
+ QStringList list2;
+}
+
+using namespace gnumeric_import_LNS;
+
+void GNUMERICFilter::dateInit()
+{
+ // idea copied form gnumeric src/format.c:
+ /* Day 1 means 1st of January of 1900 */
+ g_dateOrigin = GnumericDate::greg2jul( 1900, 1, 1 ) - 1;
+}
+
+uint GNUMERICFilter::GnumericDate::greg2jul( int y, int m, int d )
+{
+ return QDate::gregorianToJulian( y, m, d );
+}
+
+void GNUMERICFilter::GnumericDate::jul2greg( double num, int & y, int & m, int & d )
+{
+ int i = (int) floor( num + HALF_SEC );
+ if (i > g_dateSerial_19000228)
+ --i;
+ else if (i == g_dateSerial_19000228 + 1)
+ kdWarning(30521) << "Request for date 02/29/1900." << endl;
+
+ kdDebug(30521) << "***** Num: " << num << ", i: " << i << endl;
+
+ QDate::julianToGregorian( i + g_dateOrigin, y, m, d );
+ kdDebug(30521) << "y: " << y << ", m: " << m << ", d: " << d << endl;
+}
+
+QTime GNUMERICFilter::GnumericDate::getTime( double num )
+{
+ // idea copied from gnumeric: src/datetime.c
+ num += HALF_SEC;
+ int secs = qRound( (num - floor(num)) * SECS_PER_DAY );
+
+ kdDebug(30521) << "***** Num: " << num << ", secs " << secs << endl;
+
+ const int h = secs / 3600;
+ secs -= h * 3600;
+ const int m = secs / 60;
+ secs -= h * 60;
+
+ kdDebug(30521) << "****** h: " << h << ", m: " << m << ", secs: " << secs << endl;
+ const QTime time( h, m, ( secs < 0 || secs > 59 ? 0 : secs ) );
+
+ return time;
+}
+
+typedef KGenericFactory<GNUMERICFilter, KoFilter> GNUMERICFilterFactory;
+K_EXPORT_COMPONENT_FACTORY( libgnumericimport, GNUMERICFilterFactory( "kofficefilters" ) )
+
+GNUMERICFilter::GNUMERICFilter( KoFilter *, const char *, const QStringList & )
+ : KoFilter()
+{
+}
+
+/* This converts GNUmeric's color string "0:0:0" to a QColor. */
+void convert_string_to_qcolor(QString color_string, QColor * color)
+{
+ int red, green, blue, first_col_pos, second_col_pos;
+
+ bool number_ok;
+
+ first_col_pos = color_string.find(":", 0);
+ second_col_pos = color_string.find(":", first_col_pos + 1);
+
+ /* Fore="0:0:FF00" */
+ /* If GNUmeric kicks out some invalid colors, we could crash. */
+ /* GNUmeric gives us two bytes of color data per element. */
+ /* We only care about the top byte. */
+
+ red = color_string.mid( 0, first_col_pos).toInt( &number_ok, 16 ) >> 8;
+ green = color_string.mid(first_col_pos + 1,
+ (second_col_pos-first_col_pos) - 1).toInt( &number_ok, 16) >> 8;
+ blue = color_string.mid(second_col_pos + 1,
+ (color_string.length() - first_col_pos) - 1).toInt( &number_ok, 16) >> 8;
+ color->setRgb(red, green, blue);
+}
+
+void areaNames( Doc * ksdoc, const QString &_name, QString _zone )
+{
+//Sheet2!$A$2:$D$8
+ QString tableName;
+ int pos = _zone.find( '!' );
+ if ( pos != -1 )
+ {
+ tableName = _zone.left( pos );
+ _zone = _zone.right( _zone.length()-pos-1 );
+ pos = _zone.find( ':' );
+ QRect rect;
+ if ( pos != -1 )
+ {
+ QString left = _zone.mid( 1, pos-1 );
+ QString right = _zone.mid( pos+2, _zone.length()-pos-2 );
+ int pos = left.find( '$' );
+
+ rect.setLeft( util_decodeColumnLabelText(left.left(pos ) ) );
+ rect.setTop( left.right( left.length()-pos-1 ).toInt() );
+
+ pos = right.find( '$' );
+ rect.setRight( util_decodeColumnLabelText(right.left(pos ) ) );
+ rect.setBottom( right.right( right.length()-pos-1 ).toInt() );
+ }
+ else
+ {
+ QString left = _zone;
+ int pos = left.find( '$' );
+ int leftPos = util_decodeColumnLabelText(left.left(pos ) );
+ rect.setLeft( leftPos );
+ rect.setRight( leftPos );
+
+ int top = left.right( left.length()-pos-1 ).toInt();
+ rect.setTop( top );
+ rect.setBottom( top );
+ }
+ ksdoc->addAreaName( rect, _name ,tableName);
+ }
+}
+
+
+void set_document_area_names( Doc * ksdoc, QDomElement * docElem )
+{
+ QDomNode areaNamesElement = docElem->namedItem( "gmr:Names" );
+ if ( areaNamesElement.isNull() )
+ return;
+ QDomNode areaNameItem = areaNamesElement.namedItem( "gmr:Name" );
+ while ( !areaNameItem.isNull() )
+ {
+ QDomNode gmr_name = areaNameItem.namedItem("gmr:name");
+ QDomNode gmr_value = areaNameItem.namedItem("gmr:value");
+ QString name = gmr_name.toElement().text();
+ areaNames( ksdoc, name, gmr_value.toElement().text() );
+ areaNameItem = areaNameItem.nextSibling();
+ }
+}
+
+
+
+void set_document_attributes( Doc * ksdoc, QDomElement * docElem)
+{
+ ksdoc->loadConfigFromFile();
+ QDomNode attributes = docElem->namedItem("gmr:Attributes");
+ if ( attributes.isNull() )
+ return;
+
+ QDomNode attributeItem = attributes.namedItem("gmr:Attribute");
+ while( !attributeItem.isNull() )
+ {
+ QDomNode gmr_name = attributeItem.namedItem("gmr:name");
+ QDomNode gmr_value = attributeItem.namedItem("gmr:value");
+ if (gmr_name.toElement().text() == "WorkbookView::show_horizontal_scrollbar")
+ {
+ ksdoc->setShowHorizontalScrollBar( gmr_value.toElement().text().lower()=="true"? true : false );
+ }
+ else if ( gmr_name.toElement().text() == "WorkbookView::show_vertical_scrollbar")
+ {
+ ksdoc->setShowVerticalScrollBar( gmr_value.toElement().text().lower()=="true"? true : false );
+ }
+ else if ( gmr_name.toElement().text() == "WorkbookView::show_notebook_tabs")
+ {
+ ksdoc->setShowTabBar(gmr_value.toElement().text().lower()=="true"? true : false );
+ }
+ else if ( gmr_name.toElement().text() == "WorkbookView::do_auto_completion")
+ {
+ ksdoc->setCompletionMode( KGlobalSettings::CompletionAuto);
+ }
+ else if ( gmr_name.toElement().text() == "WorkbookView::is_protected")
+ {
+ //TODO protect document ???
+ //ksdoc->map()->isProtected()
+ }
+
+ attributeItem = attributeItem.nextSibling();
+ }
+}
+
+/* This sets the documentation information from the information stored in
+ the GNUmeric file. Particularly in the "gmr:Summary" subcategory.
+*/
+void set_document_info(KoDocument * document, QDomElement * docElem)
+{
+ /* Summary Handling START */
+ QDomNode summary = docElem->namedItem("gmr:Summary");
+ QDomNode gmr_item = summary.namedItem("gmr:Item");
+
+ while( !gmr_item.isNull() )
+ {
+ QDomNode gmr_name = gmr_item.namedItem("gmr:name");
+ QDomNode gmr_value = gmr_item.namedItem("gmr:val-string");
+
+ KoDocumentInfo * DocumentInfo = document->documentInfo();
+ KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(DocumentInfo->page( "about" ));
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>(DocumentInfo->page( "author" ));
+
+
+ if (gmr_name.toElement().text() == "title")
+ {
+ aboutPage->setTitle(gmr_value.toElement().text());
+ }
+ else if (gmr_name.toElement().text() == "keywords")
+ {
+ aboutPage->setKeywords( gmr_value.toElement().text());
+ }
+ else if (gmr_name.toElement().text() == "comments")
+ {
+ aboutPage->setAbstract(gmr_value.toElement().text());
+ }
+ else if (gmr_name.toElement().text() == "category")
+ {
+ /* Not supported by KSpread */
+ }
+ else if (gmr_name.toElement().text() == "manager")
+ {
+ /* Not supported by KSpread */
+ }
+ else if (gmr_name.toElement().text() == "application")
+ {
+ /* Not supported by KSpread */
+ }
+ else if (gmr_name.toElement().text() == "author")
+ {
+ authorPage->setFullName(gmr_value.toElement().text());
+ }
+ else if (gmr_name.toElement().text() == "company")
+ {
+ authorPage->setCompany(gmr_value.toElement().text());
+ }
+
+ gmr_item = gmr_item.nextSibling();
+ }
+
+ /* Summany Handling STOP */
+}
+
+
+void setColInfo(QDomNode * sheet, Sheet * table)
+{
+ QDomNode columns = sheet->namedItem("gmr:Cols");
+ QDomNode columninfo = columns.namedItem("gmr:ColInfo");
+
+ QDomElement def = columns.toElement();
+ if ( def.hasAttribute( "DefaultSizePts" ) )
+ {
+ bool ok = false;
+ double d = def.attribute( "DefaultSizePts" ).toDouble( &ok );
+ if ( ok )
+ {
+ Format::setGlobalColWidth( d );
+ table->setDefaultWidth( d );
+ }
+ }
+
+ while( !columninfo.isNull() )
+ {
+ QDomElement e = columninfo.toElement(); // try to convert the node to an element.
+ int column_number;
+
+ column_number = e.attribute("No").toInt()+1;
+ ColumnFormat *cl = new ColumnFormat(table, column_number);
+ if (e.hasAttribute("Hidden"))
+ {
+ if (e.attribute("Hidden")=="1")
+ {
+ cl->setHide(true);
+ }
+ }
+ if (e.hasAttribute("Unit"))
+ {
+ // xmm = (x_points) * (1 inch / 72 points) * (25.4 mm/ 1 inch)
+ cl->setDblWidth(e.attribute("Unit").toDouble());
+ //cl->setWidth(e.attribute("Unit").toInt());
+ }
+ table->insertColumnFormat(cl);
+ columninfo = columninfo.nextSibling();
+ }
+}
+
+void setRowInfo(QDomNode *sheet, Sheet *table)
+{
+ QDomNode rows = sheet->namedItem("gmr:Rows");
+ QDomNode rowinfo = rows.namedItem("gmr:RowInfo");
+
+ double d;
+ bool ok = false;
+
+ QDomElement def = rows.toElement();
+ if ( def.hasAttribute( "DefaultSizePts" ) )
+ {
+ d = def.attribute( "DefaultSizePts" ).toDouble( &ok );
+ if ( ok )
+ {
+ Format::setGlobalRowHeight( d );
+ table->setDefaultHeight( d );
+ }
+ }
+
+ while( !rowinfo.isNull() )
+ {
+ QDomElement e = rowinfo.toElement(); // try to convert the node to an element.
+ int row_number;
+ row_number = e.attribute("No").toInt() + 1;
+ RowFormat *rl = new RowFormat(table, row_number);
+
+ if (e.hasAttribute("Hidden"))
+ {
+ if (e.attribute("Hidden") == "1")
+ {
+ rl->setHide(true);
+ }
+ }
+ if (e.hasAttribute("Unit"))
+ {
+ double dbl = e.attribute( "Unit" ).toDouble( &ok );
+ if ( ok )
+ rl->setDblHeight( dbl );
+ }
+ table->insertRowFormat(rl);
+ rowinfo = rowinfo.nextSibling();
+ }
+}
+
+void setSelectionInfo( QDomNode * sheet, Sheet * /* table */ )
+{
+ QDomNode selections = sheet->namedItem("gmr:Selections");
+ QDomNode selection = selections.namedItem("gmr:Selection");
+
+ /* Kspread does not support mutiple selections.. */
+ /* This code will set the selection to the last one GNUmeric's multiple
+ selections. */
+ while( !selection.isNull() )
+ {
+ QDomElement e = selection.toElement(); // try to convert the node to an element.
+ QRect kspread_selection;
+
+ kspread_selection.setLeft((e.attribute("startCol").toInt() + 1));
+ kspread_selection.setTop((e.attribute("startRow").toInt() + 1));
+ kspread_selection.setRight((e.attribute("endCol").toInt() + 1));
+ kspread_selection.setBottom((e.attribute("endRow").toInt() + 1));
+
+ /* can't set it in the table -- must set it to a view */
+ // table->setSelection(kspread_selection);
+
+ selection = selection.nextSibling();
+ }
+}
+
+
+void setObjectInfo(QDomNode * sheet, Sheet * table)
+{
+ QDomNode gmr_objects = sheet->namedItem("gmr:Objects");
+ QDomNode gmr_cellcomment = gmr_objects.namedItem("gmr:CellComment");
+ while( !gmr_cellcomment.isNull() )
+ {
+ QDomElement e = gmr_cellcomment.toElement(); // try to convert the node to an element.
+ if (e.hasAttribute("Text"))
+ {
+ if (e.hasAttribute("ObjectBound"))
+ {
+ Point point(e.attribute("ObjectBound"));
+ Cell * cell = table->nonDefaultCell( point.pos().x(), point.pos().y() );
+ cell->format()->setComment(e.attribute("Text"));
+ }
+ }
+
+ gmr_cellcomment = gmr_cellcomment.nextSibling();
+ }
+}
+
+void convertToPen( QPen & pen, int style )
+{
+ switch( style )
+ {
+ case 0:
+ break;
+ case 1:
+ pen.setStyle( Qt::SolidLine );
+ pen.setWidth( 1 );
+ break;
+ case 2:
+ pen.setStyle( Qt::SolidLine );
+ pen.setWidth( 2 );
+ break;
+ case 3:
+ pen.setStyle( Qt::DashLine );
+ pen.setWidth( 1 );
+ break;
+ case 4:
+ // width should be 1 but otherwise it would be the same as 7
+ pen.setStyle( Qt::DotLine );
+ pen.setWidth( 2 );
+ break;
+ case 5:
+ pen.setStyle( Qt::SolidLine );
+ pen.setWidth( 3 );
+ break;
+ case 6:
+ // TODO should be double
+ pen.setStyle( Qt::SolidLine );
+ pen.setWidth( 1 );
+ break;
+ case 7:
+ // very thin dots => no match in KSpread
+ pen.setStyle( Qt::DotLine );
+ pen.setWidth( 1 );
+ break;
+ case 8:
+ pen.setStyle( Qt::DashLine );
+ pen.setWidth( 2 );
+ break;
+ case 9:
+ pen.setStyle( Qt::DashDotLine );
+ pen.setWidth( 1 );
+ break;
+ case 10:
+ pen.setStyle( Qt::DashDotLine );
+ pen.setWidth( 2 );
+ break;
+ case 11:
+ pen.setStyle( Qt::DashDotDotLine );
+ pen.setWidth( 1 );
+ break;
+ case 12:
+ pen.setStyle( Qt::DashDotDotLine );
+ pen.setWidth( 2 );
+ break;
+ case 13:
+ // TODO: long dash, short dash, long dash,...
+ pen.setStyle( Qt::DashDotLine );
+ pen.setWidth( 3 );
+ break;
+ default:
+ pen.setStyle( Qt::SolidLine );
+ pen.setWidth( 1 );
+ }
+}
+
+void GNUMERICFilter::ParseBorder( QDomElement & gmr_styleborder, Cell * kspread_cell )
+{
+ QDomNode gmr_diagonal = gmr_styleborder.namedItem("gmr:Diagonal");
+ QDomNode gmr_rev_diagonal = gmr_styleborder.namedItem("gmr:Rev-Diagonal");
+ QDomNode gmr_top = gmr_styleborder.namedItem("gmr:Top");
+ QDomNode gmr_bottom = gmr_styleborder.namedItem("gmr:Bottom");
+ QDomNode gmr_left = gmr_styleborder.namedItem("gmr:Left");
+ QDomNode gmr_right = gmr_styleborder.namedItem("gmr:Right");
+
+ // NoPen - no line at all. For example,
+ // QPainter::drawRect() fills but does not
+ // draw any explicit boundary
+ // line. SolidLine - a simple line. DashLine
+ // - dashes, separated by a few
+ // pixels. DotLine - dots, separated by a
+ // few pixels. DashDotLine - alternately
+ // dots and dashes. DashDotDotLine - one dash, two dots, one dash, two dots...
+
+ if ( !gmr_left.isNull() )
+ {
+ QDomElement e = gmr_left.toElement(); // try to convert the node to an element.
+ importBorder( e, Left, kspread_cell);
+ }
+
+ if ( !gmr_right.isNull() )
+ {
+ QDomElement e = gmr_right.toElement(); // try to convert the node to an element.
+ importBorder( e, Right, kspread_cell);
+ }
+
+ if ( !gmr_top.isNull() )
+ {
+ QDomElement e = gmr_top.toElement(); // try to convert the node to an element.
+ importBorder( e, Top, kspread_cell);
+ }
+
+ if ( !gmr_bottom.isNull() )
+ {
+ QDomElement e = gmr_bottom.toElement(); // try to convert the node to an element.
+ importBorder( e, Bottom, kspread_cell);
+ }
+
+ if ( !gmr_diagonal.isNull() )
+ {
+ QDomElement e = gmr_diagonal.toElement(); // try to convert the node to an element.
+ importBorder( e, Diagonal, kspread_cell);
+ }
+
+ if ( !gmr_rev_diagonal.isNull() )
+ {
+ QDomElement e = gmr_rev_diagonal.toElement(); // try to convert the node to an element.
+ importBorder( e, Revdiagonal, kspread_cell);
+ }
+
+ // QDomElement gmr_styleborder_element = gmr_styleborder.toElement();
+}
+
+
+void GNUMERICFilter::importBorder( QDomElement border, borderStyle _style, Cell *cell)
+{
+ if ( !border.isNull() )
+ {
+ QDomElement e = border.toElement(); // try to convert the node to an element.
+ if ( e.hasAttribute( "Style" ) )
+ {
+ int style = e.attribute( "Style" ).toInt();
+
+ QPen pen;
+ convertToPen( pen, style );
+
+ if ( style > 0 )
+ {
+ switch( _style )
+ {
+ case Left:
+ cell->setLeftBorderPen( pen );
+ break;
+ case Right:
+ cell->setRightBorderPen( pen );
+ break;
+ case Top:
+ cell->setTopBorderPen( pen );
+ break;
+ case Bottom:
+ cell->setBottomBorderPen( pen );
+ break;
+ case Diagonal:
+ cell->format()->setFallDiagonalPen( pen ); // check if this is really Fall border
+ break;
+ case Revdiagonal:
+ cell->format()->setGoUpDiagonalPen( pen ); // check if this is really GoUp
+ break;
+ }
+ }
+ if ( e.hasAttribute( "Color" ) )
+ {
+ QColor color;
+ QString colorString = e.attribute( "Color" );
+ convert_string_to_qcolor( colorString, &color );
+ {
+ switch( _style )
+ {
+ case Left:
+ cell->format()->setLeftBorderColor( color );
+ break;
+ case Right:
+ cell->format()->setRightBorderColor( color );
+ break;
+ case Top:
+ cell->format()->setTopBorderColor( color );
+ break;
+ case Bottom:
+ cell->format()->setBottomBorderColor( color );
+ break;
+ case Diagonal:
+ cell->format()->setFallDiagonalColor( color );
+ break;
+ case Revdiagonal:
+ cell->format()->setGoUpDiagonalPen( color );
+ break;
+ }
+ }
+ }
+ }
+ }
+
+}
+
+bool GNUMERICFilter::setType( Cell * kspread_cell,
+ QString const & formatString,
+ QString & cell_content )
+{
+ int i = 0;
+ for ( i = 0; cell_format_date[i] ; ++i )
+ {
+ kdDebug(30521) << "Cell_format: " << cell_format_date[i] << ", FormatString: " << formatString << endl;
+ if ( ( formatString == "d/m/yy" ) || ( formatString == cell_format_date[i] ) )
+ {
+ kdDebug(30521) << " FormatString: Date: " << formatString << ", CellContent: " << cell_content << endl;
+ QDate date;
+ if ( !kspread_cell->isDate() )
+ {
+ // convert cell_content to date
+ int y, m, d;
+ bool ok = true;
+ int val = cell_content.toInt( &ok );
+
+ kdDebug(30521) << "!!! FormatString: Date: " << formatString << ", CellContent: " << cell_content
+ << ", Double: " << val << endl;
+ if ( !ok )
+ return false;
+
+ GnumericDate::jul2greg( val, y, m, d );
+ kdDebug(30521) << " num: " << val << ", y: " << y << ", m: " << m << ", d: " << d << endl;
+
+ date.setYMD( y, m, d );
+ }
+ else
+ date = kspread_cell->value().asDate();
+
+ FormatType type;
+ switch( i )
+ {
+ case 0: type = date_format5; break;
+ case 1: type = date_format6; break;
+ case 2: type = date_format1; break;
+ case 3: type = date_format2; break;
+ case 4: type = date_format3; break;
+ case 5: type = date_format4; break;
+ case 6: type = date_format11; break;
+ case 7: type = date_format12; break;
+ case 8: type = date_format19; break;
+ case 9: type = date_format18; break;
+ case 10: type = date_format20; break;
+ case 11: type = date_format21; break;
+ case 16: type = date_format7; break;
+ case 17: type = date_format22; break;
+ case 18: type = date_format8; break;
+ case 19: type = date_format9; break;
+ case 22: type = date_format25; break;
+ case 23: type = date_format14; break;
+ case 24: type = date_format25; break;
+ case 25: type = date_format26; break;
+ case 26: type = date_format16; break;
+ case 27: type = date_format15; break;
+ case 28: type = date_format16; break;
+ case 29: type = date_format15; break;
+ case 30: type = date_format24; break;
+ case 31: type = date_format23; break;
+ default:
+ type = ShortDate_format;
+ break;
+ /* 12, 13, 14, 15, 20, 21 */
+ }
+
+ kdDebug(30521) << "i: " << i << ", Type: " << type << ", Date: " << date.toString() << endl;
+
+ kspread_cell->setValue( date );
+ kspread_cell->format()->setFormatType( type );
+
+ return true;
+ }
+ }
+
+ for ( i = 0; cell_format_time[i] ; ++i )
+ {
+ if (formatString == cell_format_time[i])
+ {
+ QTime time;
+
+ if ( !kspread_cell->isTime() )
+ {
+ bool ok = true;
+ double content = cell_content.toDouble( &ok );
+
+ kdDebug(30521) << " FormatString: Time: " << formatString << ", CellContent: " << cell_content
+ << ", Double: " << content << endl;
+
+ if ( !ok )
+ return false;
+
+ time = GnumericDate::getTime( content );
+ }
+ else
+ time = kspread_cell->value().asTime();
+
+ FormatType type;
+ switch( i )
+ {
+ case 0: type = Time_format1; break;
+ case 1: type = Time_format2; break;
+ case 2: type = Time_format4; break;
+ case 3: type = Time_format5; break;
+ case 5: type = Time_format6; break;
+ case 6: type = Time_format6; break;
+ default:
+ type = Time_format1; break;
+ }
+
+ kdDebug(30521) << "i: " << i << ", Type: " << type << endl;
+ kspread_cell->setValue( time );
+ kspread_cell->format()->setFormatType( type );
+
+ return true;
+ }
+ }
+
+ return false; // no date or time
+}
+
+QString GNUMERICFilter::convertVars( QString const & str, Sheet * table ) const
+{
+ QString result( str );
+ uint count = list1.count();
+ if ( count == 0 )
+ {
+ list1 << "&[TAB]" << "&[DATE]" << "&[PAGE]"
+ << "&[PAGES]"<<"&[TIME]" << "&[FILE]";
+ list2 << "<sheet>" << "<date>" << "<page>"
+ << "<pages>" << "<time>" << "<file>";
+ count = list1.count();
+ }
+
+ for ( uint i = 0; i < count; ++i )
+ {
+ int n = result.find( list1[i] );
+
+ if ( n != -1 )
+ {
+ kdDebug(30521) << "Found var: " << list1[i] << endl;
+ if ( i == 0 )
+ result = result.replace( list1[i], table->tableName() );
+ else
+ result = result.replace( list1[i], list2[i] );
+ }
+ }
+
+ return result;
+}
+
+double GNUMERICFilter::parseAttribute( const QDomElement &_element )
+{
+ QString unit = _element.attribute( "PrefUnit" );
+ bool ok;
+ double value = _element.attribute("Points").toFloat( &ok );
+ if ( !ok )
+ value = 2.0;
+ if ( unit == "mm" )
+ return value;
+ else if ( unit == "cm" )
+ return ( value/10.0 );
+ else if ( unit == "in" )
+ return MM_TO_INCH( value );
+ else if ( unit == "Pt" || unit == "Px" || unit == "points" )
+ return MM_TO_POINT( value );
+ else
+ return value;
+}
+
+void GNUMERICFilter::ParsePrintInfo( QDomNode const & printInfo, Sheet * table )
+{
+ kdDebug(30521) << "Parsing print info " << endl;
+
+ float fleft = 2.0;
+ float fright = 2.0;
+ float ftop = 2.0;
+ float fbottom = 2.0;
+
+ QString paperSize("A4");
+ QString orientation("Portrait");
+ QString footLeft, footMiddle, footRight;
+ QString headLeft, headMiddle, headRight; // no we are zombies :-)
+
+ QDomNode margins( printInfo.namedItem("gmr:Margins") );
+ if ( !margins.isNull() )
+ {
+ QDomElement top( margins.namedItem( "gmr:top" ).toElement() );
+ if ( !top.isNull() )
+ ftop = parseAttribute( top );
+
+ QDomElement bottom( margins.namedItem( "gmr:bottom" ).toElement() );
+ if ( !bottom.isNull() )
+ fbottom= parseAttribute( bottom );
+
+ QDomElement left( margins.namedItem( "gmr:left" ).toElement() );
+ if ( !left.isNull() )
+ fleft = parseAttribute( left );
+
+ QDomElement right( margins.namedItem( "gmr:right" ).toElement() );
+ if ( !right.isNull() )
+ fright = parseAttribute( right );
+ }
+
+ QDomElement foot( printInfo.namedItem("gmr:Footer").toElement() );
+ if ( !foot.isNull() )
+ {
+ kdDebug(30521) << "Parsing footer: " << foot.attribute("Left") << ", " << foot.attribute("Middle") << ", "
+ << foot.attribute("Right") << ", " <<endl;
+ if ( foot.hasAttribute("Left") )
+ footLeft = convertVars( foot.attribute("Left"), table );
+ if ( foot.hasAttribute("Middle") )
+ footMiddle = convertVars( foot.attribute("Middle"), table );
+ if ( foot.hasAttribute("Right") )
+ footRight = convertVars( foot.attribute("Right"), table );
+ }
+
+ QDomElement head( printInfo.namedItem("gmr:Header").toElement() );
+ if ( !head.isNull() )
+ {
+ kdDebug(30521) << "Parsing header: " << head.attribute("Left") << ", " << head.attribute("Middle") << ", " << head.attribute("Right") << ", "<< endl;
+ if ( head.hasAttribute("Left") )
+ headLeft = convertVars( head.attribute("Left"), table );
+ if ( head.hasAttribute("Middle") )
+ headMiddle = convertVars( head.attribute("Middle"), table );
+ if ( head.hasAttribute("Right") )
+ headRight = convertVars( head.attribute("Right"), table );
+ }
+
+ QDomElement repeateColumn( printInfo.namedItem("gmr:repeat_top").toElement() );
+ if ( !repeateColumn.isNull() )
+ {
+ QString repeate = repeateColumn.attribute( "value" );
+ if ( !repeate.isEmpty() )
+ {
+ Range range(repeate);
+ //kdDebug()<<" repeate :"<<repeate<<"range. ::start row : "<<range.startRow ()<<" start col :"<<range.startCol ()<<" end row :"<<range.endRow ()<<" end col :"<<range.endCol ()<<endl;
+ table->print()->setPrintRepeatRows( qMakePair( range.startRow (),range.endRow ()) );
+ }
+ }
+
+ QDomElement repeateRow( printInfo.namedItem("gmr:repeat_left").toElement() );
+ if ( !repeateRow.isNull() )
+ {
+ QString repeate = repeateRow.attribute( "value" );
+ if ( !repeate.isEmpty() )
+ {
+ //fix row too high
+ repeate = repeate.replace( "65536", "32500" );
+ Range range(repeate);
+ //kdDebug()<<" repeate :"<<repeate<<"range. ::start row : "<<range.startRow ()<<" start col :"<<range.startCol ()<<" end row :"<<range.endRow ()<<" end col :"<<range.endCol ()<<endl;
+ table->print()->setPrintRepeatColumns( qMakePair( range.startCol (),range.endCol ()) );
+ }
+ }
+
+ QDomElement orient( printInfo.namedItem("gmr:orientation").toElement() );
+ if ( !orient.isNull() )
+ orientation = orient.text();
+
+ QDomElement size( printInfo.namedItem("gmr:paper").toElement() );
+ if ( !size.isNull() )
+ paperSize = size.text();
+
+ table->print()->setPaperLayout( fleft, ftop, fright, fbottom,
+ paperSize, orientation );
+
+ table->print()->setHeadFootLine( headLeft, headMiddle, headRight,
+ footLeft, footMiddle, footRight );
+}
+
+void GNUMERICFilter::ParseFormat(QString const & formatString, Cell * kspread_cell)
+{
+ int l = formatString.length();
+ int lastPos = 0;
+
+ if (formatString[l - 1] == '%')
+ kspread_cell->format()->setFormatType(Percentage_format);
+ else if (formatString[0] == '$')
+ {
+ kspread_cell->format()->setFormatType(Money_format);
+ kspread_cell->format()->setCurrency( 1, "$" );
+ lastPos = 1;
+ }
+ else if (formatString[0] == '')
+ {
+ kspread_cell->format()->setFormatType(Money_format);
+ kspread_cell->format()->setCurrency( 1, "" );
+ lastPos = 1;
+ }
+ else if (formatString[0] == '')
+ {
+ kspread_cell->format()->setFormatType(Money_format);
+ kspread_cell->format()->setCurrency( 1, "" );
+ lastPos = 1;
+ }
+ else if (formatString[0] == '')
+ {
+ kspread_cell->format()->setFormatType(Money_format);
+ kspread_cell->format()->setCurrency( 1, "" );
+ lastPos = 1;
+ }
+ else if (l > 1)
+ {
+ if ((formatString[0] == '[') && (formatString[1] == '$'))
+ {
+ int n = formatString.find(']');
+ if (n != -1)
+ {
+ QString currency = formatString.mid(2, n - 2);
+ kspread_cell->format()->setFormatType(Money_format);
+ kspread_cell->format()->setCurrency( 1, currency );
+ }
+ lastPos = ++n;
+ }
+ else if (formatString.find("E+0") != -1)
+ {
+ kspread_cell->format()->setFormatType(Scientific_format);
+ }
+ else
+ {
+ // do pattern matching with gnumeric formats
+ QString content(kspread_cell->value().asString());
+
+ if ( setType(kspread_cell, formatString, content) )
+ return;
+
+ if (formatString.find("?/?") != -1)
+ {
+ // TODO: fixme!
+ kspread_cell->format()->setFormatType( fraction_three_digits );
+ return;
+ }
+ // so it's nothing we want to understand:-)
+ return;
+ }
+ }
+
+ while (formatString[lastPos] == ' ')
+ ++lastPos;
+
+ // GetPrecision and decimal point, format of negative items...
+
+ // thousands separator
+ if (formatString[lastPos] == '#')
+ {
+ bool sep = true;
+ if (formatString[lastPos + 1] == ',')
+ lastPos += 2;
+ else
+ sep = false;
+ // since KSpread 1.3
+ // kspread_cell->setThousandsSeparator( sep );
+ }
+
+ while (formatString[lastPos] == ' ')
+ ++lastPos;
+
+ int n = formatString.find( '.', lastPos );
+ if ( n != -1)
+ {
+ lastPos = n + 1;
+ int precision = lastPos;
+ while (formatString[precision] == '0')
+ ++precision;
+
+ int tmp = lastPos;
+ lastPos = precision;
+ precision -= tmp;
+
+ kspread_cell->format()->setPrecision( precision );
+ }
+
+ bool red = false;
+ if (formatString.find("[RED]", lastPos) != -1)
+ {
+ red = true;
+ kspread_cell->format()->setFloatColor( Format::NegRed );
+ }
+ if ( formatString.find('(', lastPos) != -1 )
+ {
+ if ( red )
+ kspread_cell->format()->setFloatColor( Format::NegRedBrackets );
+ else
+ kspread_cell->format()->setFloatColor( Format::NegBrackets );
+ }
+}
+
+void GNUMERICFilter::convertFormula( QString & formula ) const
+{
+ int n = formula.find( '=', 1 );
+
+ // TODO: check if we do not screw something up here...
+ if ( n != -1 )
+ formula = formula.replace( n, 1, "==" );
+
+ bool inQuote1 = false;
+ bool inQuote2 = false;
+ int l = formula.length();
+ for ( int i = 0; i < l; ++i )
+ {
+ if ( formula[i] == '\'' )
+ inQuote1 = !inQuote1;
+ else if ( formula[i] == '"' )
+ inQuote2 = !inQuote2;
+ else if ( formula[i] == ',' && !inQuote1 && !inQuote2 )
+ formula = formula.replace( i, 1, ";" );
+ }
+}
+
+void GNUMERICFilter::setStyleInfo(QDomNode * sheet, Sheet * table)
+{
+ kdDebug(30521) << "SetStyleInfo entered " << endl;
+
+ int row, column;
+ QDomNode styles = sheet->namedItem( "gmr:Styles" );
+ if ( !styles.isNull() )
+ {
+ // Get a style region within that sheet.
+ QDomNode style_region = styles.namedItem( "gmr:StyleRegion" );
+
+ while ( !style_region.isNull() )
+ {
+ QDomElement e = style_region.toElement(); // try to convert the node to an element.
+
+ QDomNode style = style_region.namedItem( "gmr:Style" );
+ QDomNode font = style.namedItem( "gmr:Font" );
+ QDomNode validation = style.namedItem( "gmr:Validation" );
+ QDomNode gmr_styleborder = style.namedItem( "gmr:StyleBorder" );
+ QDomNode hyperlink = style.namedItem( "gmr:HyperLink" );
+ int startCol = e.attribute( "startCol" ).toInt() + 1;
+ int endCol = e.attribute( "endCol" ).toInt() + 1;
+ int startRow = e.attribute( "startRow" ).toInt() + 1;
+ int endRow = e.attribute( "endRow" ).toInt() + 1;
+
+ kdDebug(30521) << "------Style: " << startCol << ", "
+ << startRow << " - " << endCol << ", " << endRow << endl;
+
+ if ( endCol - startCol > 200 || endRow - startRow > 200 )
+ {
+ style_region = style_region.nextSibling();
+ continue;
+ }
+
+ for ( column = startCol; column <= endCol; ++column )
+ {
+ for ( row = startRow; row <= endRow; ++row )
+ {
+ kdDebug(30521) << "Cell: " << column << ", " << row << endl;
+ Cell * kspread_cell = table->cellAt( column, row, false );
+
+ // don't create new cells -> don't apply format on empty cells, if bigger region
+ if ( ( kspread_cell->isDefault() || kspread_cell->isEmpty() )
+ && ( ( endCol - startCol > 2 ) || ( endRow - startRow > 2 ) ) )
+ {
+ kdDebug(30521) << "CELL EMPTY OR RANGE TOO BIG " << endl;
+ continue;
+ }
+
+ QDomElement style_element = style.toElement(); // try to convert the node to an element.
+
+ kdDebug(30521) << "Style valid for kspread" << endl;
+ kspread_cell = table->nonDefaultCell( column, row, false );
+
+ if (style_element.hasAttribute("Fore"))
+ {
+ QString color_string = style_element.attribute("Fore");
+ QColor color;
+ convert_string_to_qcolor(color_string, &color);
+ kspread_cell->format()->setTextColor(color);
+ }
+
+ if (style_element.hasAttribute("Back"))
+ {
+ QString color_string = style_element.attribute("Back");
+ QColor color;
+ convert_string_to_qcolor(color_string, &color);
+ kspread_cell->format()->setBgColor(color);
+ }
+
+ if (style_element.hasAttribute("PatternColor"))
+ {
+ QString color_string = style_element.attribute("PatternColor");
+ QColor color;
+ convert_string_to_qcolor(color_string, &color);
+ kspread_cell->format()->setBackGroundBrushColor( color );
+ }
+
+ if (style_element.hasAttribute("Shade"))
+ {
+ /* Pattern's taken from: gnumeric's pattern.c */
+ /* if "TODO" added: doesn't match exactly the gnumeric one */
+
+ QString shade = style_element.attribute("Shade");
+ if (shade == "0")
+ {
+ // nothing to do
+ }
+ else if (shade == "1")
+ {
+ /* 1 Solid */
+ //kspread_cell->format()->setBackGroundBrushStyle(Qt::SolidPattern);
+ //This is as empty
+ /* What should this be? */
+
+ }
+ else if (shade == "2")
+ {
+ /* 2 75% */
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::Dense2Pattern);
+ }
+ else if (shade == "3")
+ {
+ /* 3 50% */
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::Dense4Pattern);
+ }
+ else if (shade == "4")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::Dense5Pattern);
+ /* This should be 25%... All qt has is 37% */
+
+ /* 4 25% */
+ }
+ else if (shade == "5")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::Dense6Pattern);
+ /* 5 12.5% */
+ }
+ else if (shade == "6")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::Dense7Pattern);
+ /* 6 6.25% */
+
+ }
+ else if (shade == "7")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::HorPattern);
+ /* 7 Horizontal Stripe */
+ }
+ else if (shade == "8")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::VerPattern);
+ /* 8 Vertical Stripe */
+ }
+ else if (shade == "9")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::BDiagPattern);
+ /* 9 Reverse Diagonal Stripe */
+ }
+ else if (shade == "10")
+ {
+ /* 10 Diagonal Stripe */
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::FDiagPattern);
+ }
+ else if (shade == "11")
+ {
+ /* 11 Diagonal Crosshatch */
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::DiagCrossPattern);
+ }
+ else if (shade == "12")
+ {
+ /* 12 Thick Diagonal Crosshatch TODO!*/
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::DiagCrossPattern);
+ }
+ else if (shade == "13")
+ {
+ /* 13 Thin Horizontal Stripe TODO: wrong: this is thick!*/
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::HorPattern);
+ }
+ else if (shade == "14")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::VerPattern);
+ }
+ else if (shade == "15")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::FDiagPattern);
+ }
+ else if (shade == "16")
+ {
+ /* 16 Thick Reverse Stripe TODO:*/
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::BDiagPattern);
+ }
+ else if (shade == "17")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::DiagCrossPattern);
+ }
+ else if (shade == "18")
+ {
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::DiagCrossPattern);
+ }
+ else if (shade == "19")
+ {
+ /* 19 Applix small circle */
+ }
+ else if (shade == "20")
+ {
+ /* 20 Applix semicircle */
+ }
+ else if (shade == "21")
+ {
+ /* 21 Applix small thatch */
+ }
+ else if (shade == "22")
+ {
+ /* 22 Applix round thatch */
+ }
+ else if (shade == "23")
+ {
+ /* 23 Applix Brick */
+ }
+ else if (shade == "24")
+ {
+ /* 24 100% */
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::SolidPattern);
+ }
+ else if (shade == "25")
+ {
+ /* 25 87.5% */
+ kspread_cell->format()->setBackGroundBrushStyle(Qt::Dense2Pattern);
+ }
+ }
+
+ if ( style_element.hasAttribute( "Rotation" ) )
+ {
+ int rot = style_element.attribute( "Rotation" ).toInt();
+ kspread_cell->format()->setAngle( -1* rot );
+ }
+ if (style_element.hasAttribute("Indent"))
+ {
+ double indent = style_element.attribute("Indent").toDouble();
+ // gnumeric saves indent in characters, we in points:
+ kspread_cell->format()->setIndent( indent * 10.0 );
+ }
+
+ if (style_element.hasAttribute("HAlign"))
+ {
+ QString halign_string=style_element.attribute("HAlign");
+
+ if (halign_string == "1")
+ {
+ /* General: No equivalent in Kspread. */
+ }
+ else if (halign_string == "2")
+ {
+ kspread_cell->format()->setAlign(Format::Left);
+ }
+ else if (halign_string == "4")
+ {
+ kspread_cell->format()->setAlign(Format::Right);
+ }
+ else if (halign_string == "8")
+ {
+ kspread_cell->format()->setAlign(Format::Center);
+ }
+ else if (halign_string == "16")
+ {
+ /* Fill: No equivalent in Kspread. */
+ }
+ else if (halign_string == "32")
+ {
+ /* Justify: No equivalent in Kspread */
+ }
+ else if (halign_string == "64")
+ {
+ /* Centered across selection*/
+ }
+
+ }
+
+ if (style_element.hasAttribute("VAlign"))
+ {
+ QString valign_string=style_element.attribute("VAlign");
+
+ if (valign_string == "1")
+ {
+ /* General: No equivalent in Kspread. */
+ kspread_cell->format()->setAlignY(Format::Top);
+ }
+ else if (valign_string == "2")
+ {
+ kspread_cell->format()->setAlignY(Format::Bottom);
+ }
+ else if (valign_string == "4")
+ {
+ kspread_cell->format()->setAlignY(Format::Middle);
+ }
+ else if (valign_string == "8")
+ {
+ /* Justify: No equivalent in Kspread */
+ }
+ }
+
+ if (style_element.hasAttribute("WrapText"))
+ {
+ QString multiRow = style_element.attribute("WrapText");
+
+ if ( multiRow == "1" )
+ kspread_cell->format()->setMultiRow( true );
+ }
+
+ if (style_element.hasAttribute("Format"))
+ {
+ QString formatString = style_element.attribute("Format");
+
+ kdDebug(30521) << "Format: " << formatString << endl;
+ ParseFormat(formatString, kspread_cell);
+
+ } // End "Format"
+
+ if (!gmr_styleborder.isNull())
+ {
+ QDomElement style_element = gmr_styleborder.toElement(); // try to convert the node to an element.
+ ParseBorder( style_element, kspread_cell );
+ }
+ if ( !validation.isNull() )
+ {
+ QDomElement validation_element = validation.toElement();
+ if ( !validation_element.isNull() )
+ {
+ kdDebug(30521)<<" Cell validation \n";
+ Validity* kspread_validity = kspread_cell->getValidity();
+ if ( validation_element.hasAttribute( "AllowBlank" ) && validation_element.attribute( "AllowBlank" )=="true" )
+ {
+ kspread_validity->allowEmptyCell=true;
+ }
+ if ( validation_element.hasAttribute( "Title" ))
+ {
+ kspread_validity->title=validation_element.attribute( "Title" );
+ }
+ if ( validation_element.hasAttribute( "Message" ))
+ {
+ kspread_validity->message=validation_element.attribute( "Message" );
+ }
+ if ( validation_element.hasAttribute( "Style" ) )
+ {
+ int value = validation_element.attribute( "Style" ).toInt();
+ switch( value )
+ {
+ case 0:
+ kspread_validity->displayMessage=false;
+ break;
+ case 1:
+ kspread_validity->m_action=Action::Stop;
+ break;
+ case 2:
+ kspread_validity->m_action=Action::Warning;
+ break;
+ case 3:
+ kspread_validity->m_action=Action::Information;
+ break;
+ default:
+ kdDebug()<<" Error in validation style :"<<value<<endl;
+ break;
+ }
+ }
+ QDomNode expression0 = validation_element.namedItem( "gmr:Expression0" );
+ QDomNode expression1 = validation_element.namedItem( "gmr:Expression1" );
+ //kdDebug()<<" expression0.isNull() "<<expression0.isNull()<<endl;
+ //kdDebug()<<" expression1.isNull() "<<expression1.isNull()<<endl;
+ if ( validation_element.hasAttribute( "Type" ) )
+ {
+ int valueOp = validation_element.attribute( "Type" ).toInt();
+ switch( valueOp )
+ {
+ case 0:
+ kspread_validity->m_restriction=Restriction::None;
+ break;
+ case 1:
+ {
+ kspread_validity->m_restriction=Restriction::Integer;
+ if ( validation_element.hasAttribute( "Operator" ) )
+ {
+ int value = validation_element.attribute( "Operator" ).toInt();
+
+ switch( value )
+ {
+ case 0:
+ kspread_validity->m_cond=Conditional::Between;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ if ( !expression1.isNull() )
+ kspread_validity->valMax=expression1.toElement().text().toInt();
+ break;
+ case 1:
+ kspread_validity->m_cond=Conditional::DifferentTo;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ if ( !expression1.isNull() )
+ kspread_validity->valMax=expression1.toElement().text().toInt();
+ break;
+ case 2:
+ kspread_validity->m_cond=Conditional::Equal;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 3:
+ kspread_validity->m_cond=Conditional::Different;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 4:
+ kspread_validity->m_cond=Conditional::Superior;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 5:
+ kspread_validity->m_cond=Conditional::Inferior;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 6:
+ kspread_validity->m_cond=Conditional::SuperiorEqual;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 7:
+ kspread_validity->m_cond=Conditional::InferiorEqual;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ default:
+ kdDebug()<<" Error in validation Operator :"<<value<<endl;
+ break;
+ }
+ }
+ }
+ break;
+ case 2:
+ kspread_validity->m_restriction=Restriction::Number;
+ if ( validation_element.hasAttribute( "Operator" ) )
+ {
+ int value = validation_element.attribute( "Operator" ).toInt();
+ switch( value )
+ {
+ case 0:
+ kspread_validity->m_cond=Conditional::Between;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ if ( !expression1.isNull() )
+ kspread_validity->valMax=expression1.toElement().text().toInt();
+ break;
+ case 1:
+ kspread_validity->m_cond=Conditional::DifferentTo;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ if ( !expression1.isNull() )
+ kspread_validity->valMax=expression1.toElement().text().toInt();
+ break;
+ case 2:
+ kspread_validity->m_cond=Conditional::Equal;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 3:
+ kspread_validity->m_cond=Conditional::Different;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 4:
+ kspread_validity->m_cond=Conditional::Superior;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 5:
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ kspread_validity->m_cond=Conditional::Inferior;
+ break;
+ case 6:
+ kspread_validity->m_cond=Conditional::SuperiorEqual;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 7:
+ kspread_validity->m_cond=Conditional::InferiorEqual;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ default:
+ kdDebug()<<" Error in validation Operator :"<<value<<endl;
+ break;
+ }
+ }
+ break;
+ case 3:
+ kspread_validity->m_restriction=Restriction::List;
+ break;
+ case 4:
+ kspread_validity->m_restriction=Restriction::Date;
+ if ( validation_element.hasAttribute( "Operator" ) )
+ {
+ int value = validation_element.attribute( "Operator" ).toInt();
+ switch( value )
+ {
+ case 0:
+ kspread_validity->m_cond=Conditional::Between;
+ if ( !expression0.isNull() )
+ kspread_validity->dateMin=QDate::fromString( expression0.toElement().text() );
+ if ( !expression1.isNull() )
+ kspread_validity->dateMax=QDate::fromString( expression1.toElement().text() );
+
+ break;
+ case 1:
+ if ( !expression0.isNull() )
+ kspread_validity->dateMin=QDate::fromString( expression0.toElement().text() );
+ if ( !expression1.isNull() )
+ kspread_validity->dateMax=QDate::fromString( expression1.toElement().text() );
+ kspread_validity->m_cond=Conditional::DifferentTo;
+ break;
+ case 2:
+ if ( !expression0.isNull() )
+ kspread_validity->dateMin=QDate::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::Equal;
+ break;
+ case 3:
+ if ( !expression0.isNull() )
+ kspread_validity->dateMin=QDate::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::Different;
+ break;
+ case 4:
+ if ( !expression0.isNull() )
+ kspread_validity->dateMin=QDate::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::Superior;
+ break;
+ case 5:
+ if ( !expression0.isNull() )
+ kspread_validity->dateMin=QDate::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::Inferior;
+ break;
+ case 6:
+ if ( !expression0.isNull() )
+ kspread_validity->dateMin=QDate::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::SuperiorEqual;
+ break;
+ case 7:
+ if ( !expression0.isNull() )
+ kspread_validity->dateMin=QDate::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::InferiorEqual;
+ break;
+ default:
+ kdDebug()<<" Error in validation Operator :"<<value<<endl;
+ break;
+ }
+ }
+ break;
+ case 5:
+ kspread_validity->m_restriction=Restriction::Time;
+ if ( validation_element.hasAttribute( "Operator" ) )
+ {
+ int value = validation_element.attribute( "Operator" ).toInt();
+ switch( value )
+ {
+ case 0:
+ kspread_validity->m_cond=Conditional::Between;
+ if ( !expression0.isNull() )
+ kspread_validity->timeMin=QTime::fromString( expression0.toElement().text() );
+ if ( !expression1.isNull() )
+ kspread_validity->timeMax=QTime::fromString( expression1.toElement().text() );
+ break;
+ case 1:
+ if ( !expression0.isNull() )
+ kspread_validity->timeMin=QTime::fromString( expression0.toElement().text() );
+ if ( !expression1.isNull() )
+ kspread_validity->timeMax=QTime::fromString( expression1.toElement().text() );
+ kspread_validity->m_cond=Conditional::DifferentTo;
+ break;
+ case 2:
+ if ( !expression0.isNull() )
+ kspread_validity->timeMin=QTime::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::Equal;
+ break;
+ case 3:
+ kspread_validity->m_cond=Conditional::Different;
+ break;
+ case 4:
+ if ( !expression0.isNull() )
+ kspread_validity->timeMin=QTime::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::Superior;
+ break;
+ case 5:
+ kspread_validity->m_cond=Conditional::Inferior;
+ if ( !expression0.isNull() )
+ kspread_validity->timeMin=QTime::fromString( expression0.toElement().text() );
+ break;
+ case 6:
+ kspread_validity->m_cond=Conditional::SuperiorEqual;
+ if ( !expression0.isNull() )
+ kspread_validity->timeMin=QTime::fromString( expression0.toElement().text() );
+ break;
+ case 7:
+ if ( !expression0.isNull() )
+ kspread_validity->timeMin=QTime::fromString( expression0.toElement().text() );
+ kspread_validity->m_cond=Conditional::InferiorEqual;
+ break;
+ default:
+ kdDebug()<<" Error in validation Operator :"<<value<<endl;
+ break;
+ }
+ }
+ break;
+ case 6:
+ kspread_validity->m_restriction=Restriction::TextLength;
+ if ( validation_element.hasAttribute( "Operator" ) )
+ {
+ int value = validation_element.attribute( "Operator" ).toInt();
+ switch( value )
+ {
+ case 0:
+ kspread_validity->m_cond=Conditional::Between;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ if ( !expression1.isNull() )
+ kspread_validity->valMax=expression1.toElement().text().toInt();
+ break;
+ case 1:
+ kspread_validity->m_cond=Conditional::DifferentTo;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ if ( !expression1.isNull() )
+ kspread_validity->valMax=expression1.toElement().text().toInt();
+ break;
+ case 2:
+ kspread_validity->m_cond=Conditional::Equal;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 3:
+ kspread_validity->m_cond=Conditional::Different;
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ break;
+ case 4:
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ kspread_validity->m_cond=Conditional::Superior;
+ break;
+ case 5:
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ kspread_validity->m_cond=Conditional::Inferior;
+ break;
+ case 6:
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ kspread_validity->m_cond=Conditional::SuperiorEqual;
+ break;
+ case 7:
+ if ( !expression0.isNull() )
+ kspread_validity->valMin=expression0.toElement().text().toInt();
+ kspread_validity->m_cond=Conditional::InferiorEqual;
+ break;
+ default:
+ kdDebug()<<" Error in validation Operator :"<<value<<endl;
+ break;
+ }
+ }
+ break;
+ default:
+ kdDebug()<<" Error in Type element : "<<valueOp<<endl;
+ }
+
+ }
+ //<gmr:Validation Style="0" Type="1" Operator="0" AllowBlank="true" UseDropdown="false">
+ //<gmr:Expression0>745</gmr:Expression0>
+ //<gmr:Expression1>4546</gmr:Expression1>
+ }
+ }
+ if (!font.isNull())
+ {
+ QDomElement font_element = font.toElement();
+
+ kspread_cell->format()->setTextFontFamily( font_element.text() );
+
+ if (!font_element.isNull())
+ {
+ if (font_element.attribute("Italic") == "1")
+ { kspread_cell->format()->setTextFontItalic(true); }
+
+ if (font_element.attribute("Bold") == "1")
+ { kspread_cell->format()->setTextFontBold(true); }
+
+ if (font_element.hasAttribute("Underline") && ( font_element.attribute("Underline") != "0") )
+ { kspread_cell->format()->setTextFontUnderline(true); }
+
+ if (font_element.hasAttribute("StrikeThrough" ) && ( font_element.attribute("StrikeThrough") != "0") )
+ { kspread_cell->format()->setTextFontStrike(true); }
+
+ if (font_element.hasAttribute("Unit"))
+ { kspread_cell->format()->setTextFontSize(font_element.attribute("Unit").toInt()); }
+
+ }
+ if ( !hyperlink.isNull() )
+ {
+ //<gmr:HyperLink type="GnmHLinkURL" target="www.kde.org"/>
+ if ( hyperlink.toElement().hasAttribute( "type" ) )
+ {
+ QString linkType= hyperlink.toElement().attribute( "type" );
+ QString target = hyperlink.toElement().attribute( "target" );
+ QString tip = hyperlink.toElement().attribute( "tip" );
+ if ( !tip.isEmpty() )
+ kspread_cell->setCellText( tip );
+ if ( linkType=="GnmHLinkURL" )
+ {
+ if ( !target.startsWith( "http://" ) )
+ target="http://"+target;
+ kspread_cell->setLink( target );
+ }
+ else if ( linkType=="GnmHLinkEMail" )
+ {
+ if ( !target.startsWith( "mailto:/" ) )
+ target="mailto:/"+target;
+ kspread_cell->setLink( target );
+ }
+ else if ( linkType=="GnmHLinkExternal" )
+ {
+ if ( !target.startsWith( "file://" ) )
+ target="file://"+target;
+
+ kspread_cell->setLink( target );
+ }
+ else if ( linkType=="GnmHLinkCurWB" )
+ {
+ kspread_cell->setLink( target );
+ }
+ else
+ kdDebug()<<" linkType not defined : "<<linkType<<endl;
+ }
+ }
+ }
+ }
+ }
+ style_region = style_region.nextSibling();
+ }
+
+ }
+}
+
+/* NOTE: As of now everything is in a single huge function. This is
+ very ugly. It should all be broken up into smaller
+ functions, probably one for each GNUMeric section. It kind
+ of grew out of control. It could probably be cleaned up in
+ an hour or so. --PGE
+ */
+
+
+KoFilter::ConversionStatus GNUMERICFilter::convert( const QCString & from, const QCString & to )
+{
+ dateInit();
+ bool bSuccess=true;
+
+ kdDebug(30521) << "Entering GNUmeric Import filter." << endl;
+
+ KoDocument * document = m_chain->outputDocument();
+ if ( !document )
+ return KoFilter::StupidError;
+
+ kdDebug(30521) << "here we go... " << document->className() << endl;
+
+ if ( !::qt_cast<const KSpread::Doc *>( document ) ) // it's safer that way :)
+ {
+ kdWarning(30521) << "document isn't a KSpread::Doc but a " << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+ if ( from != "application/x-gnumeric" || to != "application/x-kspread" )
+ {
+ kdWarning(30521) << "Invalid mimetypes " << from << " " << to << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ kdDebug(30521) << "...still here..." << endl;
+
+ // No need for a dynamic cast here, since we use Qt's moc magic
+ Doc * ksdoc = ( Doc * ) document;
+
+ if ( ksdoc->mimeType() != "application/x-kspread" )
+ {
+ kdWarning(30521) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+
+ QIODevice* in = KFilterDev::deviceForFile(m_chain->inputFile(),"application/x-gzip");
+
+ if ( !in )
+ {
+ kdError(30521) << "Cannot create device for uncompressing! Aborting!" << endl;
+ return KoFilter::FileNotFound;
+ }
+
+ if (!in->open(IO_ReadOnly))
+ {
+ kdError(30521) << "Cannot open file for uncompressing! Aborting!" << endl;
+ delete in;
+ return KoFilter::FileNotFound;
+ }
+
+ QDomDocument doc;
+ QString errorMsg;
+ int errorLine, errorColumn;
+ if ( !doc.setContent(in, &errorMsg, &errorLine, &errorColumn) )
+ {
+ kdError(30521) << "Parsing error in " << from << "! Aborting!" << endl
+ << " In line: " << errorLine << ", column: " << errorColumn << endl
+ << " Error message: " << errorMsg << endl;
+ in->close();
+ return KoFilter::ParsingError;
+ }
+
+ in->close();
+ delete in;
+
+ int row, column;
+ int value = 0;
+ int currentTab = -1;
+ int selectedTab = 0;
+ Sheet * selTable = 0;
+
+ QDomElement docElem = doc.documentElement();
+ QDomElement uiData = docElem.namedItem("gmr:UIData").toElement();
+ if ( !uiData.isNull() )
+ {
+ if ( uiData.hasAttribute( "SelectedTab" ) )
+ {
+ bool ok = false;
+ int n = uiData.attribute( "SelectedTab" ).toInt( &ok );
+ if ( ok )
+ {
+ selectedTab = n;
+ }
+ }
+ }
+ QDomNode sheets = docElem.namedItem("gmr:Sheets");
+ if ( sheets.isNull() )
+ {
+ //avoid crash with new file format.
+ //TODO allow to load new file format
+ return KoFilter::ParsingError;
+ }
+ QDomNode sheet = sheets.namedItem("gmr:Sheet");
+
+ /* This sets the Document information. */
+ set_document_info( document, &docElem );
+
+ /* This sets the Document attributes */
+ set_document_attributes( ksdoc, &docElem );
+
+ /* This sets the Area Names */
+ set_document_area_names( ksdoc, &docElem );
+
+ Sheet * table;
+
+ // This is a mapping of exprID to expressions.
+
+ QDict<char> exprID_dict( 17, FALSE );
+ int num = 1;
+
+ while (!sheet.isNull())
+ {
+ ++currentTab;
+ table = ksdoc->map()->addNewSheet();
+
+ if ( currentTab == selectedTab )
+ selTable = table;
+
+ QDomElement name = sheet.namedItem( "gmr:Name" ).toElement();
+ QDomElement sheetElement = sheet.toElement();
+
+ if ( !name.isNull() )
+ table->setSheetName( name.text(), false, false );
+ else
+ table->setSheetName( "Sheet" + QString::number( num ), false, false );
+ table->enableScrollBarUpdates( false );
+
+ //kdDebug()<<" sheetElement.hasAttribute( DisplayFormulas ) :"<<sheetElement.hasAttribute( "DisplayFormulas" )<<endl;
+ QString tmp;
+ if ( sheetElement.hasAttribute( "DisplayFormulas" ) )
+ {
+ tmp=sheetElement.attribute( "DisplayFormulas");
+ table->setShowFormula( ( tmp=="true" )||( tmp=="1" ) );
+ }
+ if ( sheetElement.hasAttribute( "HideZero" ) )
+ {
+ tmp = sheetElement.attribute( "HideZero" );
+ table->setHideZero( ( tmp=="true" )||( tmp=="1" ) );
+ }
+ if ( sheetElement.hasAttribute( "HideGrid" ) )
+ {
+ tmp = sheetElement.attribute( "HideGrid" );
+ table->setShowGrid( ( tmp=="false" )||( tmp=="0" ) );
+ }
+ if ( sheetElement.hasAttribute( "HideColHeader" ) )
+ {
+ tmp = sheetElement.attribute( "HideColHeader" );
+ ksdoc->setShowColumnHeader( ( tmp=="false" )||( tmp=="0" ) );
+ }
+ if ( sheetElement.hasAttribute( "HideRowHeader" ) )
+ {
+ tmp =sheetElement.attribute( "HideRowHeader" );
+ ksdoc->setShowRowHeader( ( tmp=="false" )||( tmp=="0" ) );
+ }
+
+
+ setObjectInfo(&sheet, table);
+ setColInfo(&sheet, table);
+ setRowInfo(&sheet, table);
+ setSelectionInfo(&sheet, table);
+
+ /* handling print information */
+ QDomNode printInfo = sheet.namedItem("gmr:PrintInformation");
+ if ( !printInfo.isNull() )
+ ParsePrintInfo( printInfo, table );
+
+ kdDebug(30521) << "Reading in cells" << endl;
+
+ /* CELL handling START */
+ QDomNode cells = sheet.namedItem( "gmr:Cells" );
+ QDomNode cell = cells.namedItem( "gmr:Cell" );
+ QDomNode mergedCells = sheet.namedItem( "gmr:MergedRegions" );
+ QDomNode mergedRegion = mergedCells.namedItem( "gmr:Merge" );
+ if ( cell.isNull() )
+ {
+ kdWarning(30521) << "No cells" << endl;
+ }
+
+ while ( !cell.isNull() )
+ {
+ value += 2;
+ emit sigProgress(value);
+
+ QDomElement e = cell.toElement(); // try to convert the node to an element.
+ if ( !e.isNull() )
+ { // the node was really an element.
+ kdDebug(30521) << "New Cell " << endl;
+ QDomNode content_node = cell.namedItem("gmr:Content");
+
+ if (!content_node.isNull())
+ {
+ QDomElement content = content_node.toElement();
+
+ if( !content.isNull() )
+ { // the node was really an element.
+ column = e.attribute( "Col" ).toInt() + 1;
+ row = e.attribute( "Row" ).toInt() + 1;
+
+ QString cell_content( content.text() );
+ //kdDebug()<<"cell_content :!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! :"<<cell_content<<endl;
+ if ( cell_content[0] == '=' )
+ convertFormula( cell_content );
+
+ Cell * kspread_cell = table->nonDefaultCell( column, row );
+
+ if (e.hasAttribute("ValueType"))
+ {
+ // TODO: what is this for?
+ // <xsd:enumeration value="10"/> <!-- empty -->
+ // <xsd:enumeration value="20"/> <!-- boolean -->
+ // <xsd:enumeration value="30"/> <!-- integer -->
+ // <xsd:enumeration value="40"/> <!-- float -->
+ // <xsd:enumeration value="50"/> <!-- error -->
+ // <xsd:enumeration value="60"/> <!-- string -->
+ // <xsd:enumeration value="70"/> <!-- cellrange -->
+ // <xsd:enumeration value="80"/> <!-- array -->
+ QString valuetype = e.attribute( "ValueType" );
+ if ( valuetype == "40" )//percentage
+ {
+ kspread_cell->format()->setFormatType( Percentage_format );
+ kspread_cell->setValue( cell_content );
+ }
+ else if ( valuetype =="60" )//string
+ {
+ kspread_cell->format()->setFormatType( Text_format );
+ kspread_cell->setValue( cell_content );
+ }
+ }
+
+ if (e.hasAttribute( "ValueFormat" ))
+ {
+ QString formatString = e.attribute( "ValueFormat" );
+ if ( !setType( kspread_cell, formatString, cell_content ) )
+ table->setText(row, column, cell_content, false);
+ }
+ else
+ table->setText(row, column, cell_content, false);
+
+ if (e.hasAttribute("ExprID"))
+ {
+ // QString encoded_string(table->cellAt( column, row, false)->encodeFormula( row, column ).utf8());
+ QString encoded_string(table->cellAt( column, row, false )->encodeFormula().latin1());
+
+
+ char * tmp_string = ( char * ) malloc( strlen( encoded_string.latin1() ) );
+ strcpy( tmp_string, encoded_string.latin1() );
+
+ kdDebug(30521) << encoded_string.latin1() << endl;
+
+ exprID_dict.insert(e.attribute("ExprID"), tmp_string);
+
+ kdDebug(30521) << exprID_dict[e.attribute("ExprID")] << endl;
+ kdDebug(30521) << exprID_dict[QString("1")] << endl;
+ kdDebug(30521) << e.attribute("ExprID") << endl;
+
+ }
+ }
+ }
+ else
+ {
+
+ column = e.attribute( "Col" ).toInt() + 1;
+ row = e.attribute( "Row" ).toInt() + 1;
+
+ QString cell_content( e.text() );
+ //kdDebug()<<"cell_content :!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! :"<<cell_content<<endl;
+ if ( cell_content[0] == '=' )
+ convertFormula( cell_content );
+
+ Cell * kspread_cell = table->nonDefaultCell( column, row );
+
+ if (e.hasAttribute("ValueType"))
+ {
+ // TODO: Defined type of cell
+ //<xsd:enumeration value="10"/> <!-- empty -->
+ //<xsd:enumeration value="20"/> <!-- boolean -->
+ //<xsd:enumeration value="30"/> <!-- integer -->
+ //<xsd:enumeration value="40"/> <!-- float -->
+ //<xsd:enumeration value="50"/> <!-- error -->
+ //<xsd:enumeration value="60"/> <!-- string -->
+ //<xsd:enumeration value="70"/> <!-- cellrange -->
+ //<xsd:enumeration value="80"/> <!-- array -->
+ //kspread_cell->setValue( date );
+ //kspread_cell->format()->setFormatType( type );
+ QString valuetype = e.attribute( "ValueType" );
+ if ( valuetype == "40" )//percentage
+ {
+ kspread_cell->format()->setFormatType( Percentage_format );
+ kspread_cell->setValue( cell_content );
+ }
+ else if ( valuetype =="60" )//string
+ {
+ kspread_cell->format()->setFormatType( Text_format );
+ kspread_cell->setValue( cell_content );
+ }
+
+ }
+
+ if (e.hasAttribute( "ValueFormat" ))
+ {
+ QString formatString = e.attribute( "ValueFormat" );
+ if ( !setType( kspread_cell, formatString, cell_content ) )
+ table->setText(row, column, cell_content, false);
+ }
+ else
+ table->setText(row, column, cell_content, false);
+
+
+ if (e.hasAttribute("ExprID"))
+ {
+ column = e.attribute("Col").toInt() + 1;
+ row = e.attribute("Row").toInt() + 1;
+ char * expr;
+ expr = exprID_dict[e.attribute("ExprID")];
+ // expr = exprID_dict[QString("1")];
+
+ kdDebug(30521) << "FOO:" << column << row << endl;
+ kdDebug(30521) <<
+ table->cellAt( column, row, false )->decodeFormula( expr, column, row ).latin1() << endl;
+ kdDebug(30521) << expr << endl;
+
+ table->setText(row, column,
+ table->cellAt( column, row, false )->decodeFormula( expr, column, row ),
+ false);
+ }
+ }
+ }
+ cell = cell.nextSibling();
+ }
+
+ kdDebug(30521) << "Reading in cells done" << endl;
+
+ if ( mergedRegion.isNull() )
+ {
+ kdWarning(30521) << "No cells merged !" << endl;
+ }
+ while ( !mergedRegion.isNull() )
+ {
+ QDomElement e = mergedRegion.toElement(); // try to convert the node to an element.
+ QString cell_merge_area( e.text() );
+ Range range(cell_merge_area);
+ //kdDebug()<<"text !!! :"<<cell_merge_area<< "range :start row : "<<range.startRow ()<<" start col :"<<range.startCol ()<<" end row :"<<range.endRow ()<<" end col :"<<range.endCol ()<<endl;
+ Cell * cell = table->nonDefaultCell( range.startCol (), range.startRow () );
+ cell->mergeCells( range.startCol (), range.startRow (), range.endCol ()-range.startCol (), range.endRow ()-range.startRow ());
+ mergedRegion = mergedRegion.nextSibling();
+ }
+ /* There is a memory leak here...
+ * The strings in the exprID_dict have been allocated, but they have not been freed.
+ */
+
+ /* exprID_dict.statistics(); */
+
+ /* CELL handling STOP */
+
+ /* STYLE handling START */
+ //Laurent - 2001-12-07 desactivate this code : otherwise we
+ //create 65535*255 cells (Styleregion is define for a area and
+ //not for cell, so gnumeric define a style as : col start=0 col end=255
+ //rowstart=0 rowend=255 => we create 255*255 cells
+ //and gnumeric stocke all area and not just modify area
+ //=> not good for kspread.
+ // Norbert: activated again, only cells with texts get modified, nothing else created
+ setStyleInfo(&sheet, table);
+
+ /* STYLE handling STOP */
+ table->enableScrollBarUpdates( true );
+
+ sheet = sheet.nextSibling();
+ ++num;
+ }
+
+ if ( selTable )
+ ksdoc->setDisplaySheet( selTable );
+
+ emit sigProgress(100);
+ if ( bSuccess )
+ return KoFilter::OK;
+ else
+ return KoFilter::StupidError;
+}
+
+#include <gnumericimport.moc>
diff --git a/filters/kspread/gnumeric/gnumericimport.h b/filters/kspread/gnumeric/gnumericimport.h
new file mode 100644
index 000000000..fedd23687
--- /dev/null
+++ b/filters/kspread/gnumeric/gnumericimport.h
@@ -0,0 +1,66 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef GNUMERICFILTER_H
+#define GNUMERICFILTER_H
+
+#include <KoFilter.h>
+
+#include <qdatetime.h>
+#include <qdom.h>
+
+namespace KSpread
+{
+class Cell;
+class Sheet;
+}
+
+class GNUMERICFilter : public KoFilter
+{
+ Q_OBJECT
+ public:
+ GNUMERICFilter(KoFilter *parent, const char *name, const QStringList&);
+ virtual ~GNUMERICFilter() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+
+enum borderStyle { Left, Right, Top, Bottom, Diagonal, Revdiagonal};
+ private:
+ class GnumericDate : public QDate
+ {
+ public:
+ static uint greg2jul( int y, int m, int d );
+ static void jul2greg( double num, int & y, int & m, int & d );
+ static QTime getTime( double num );
+
+ };
+
+ void dateInit();
+ QString convertVars( QString const & str, KSpread::Sheet * table ) const;
+ void ParsePrintInfo( QDomNode const & printInfo, KSpread::Sheet * table );
+ void ParseFormat(QString const & formatString, KSpread::Cell* kspread_cell);
+ void setStyleInfo(QDomNode * sheet, KSpread::Sheet * table);
+ bool setType( KSpread::Cell* kspread_cell, QString const & formatString, QString & cell_content );
+ void convertFormula( QString & formula ) const;
+ void importBorder( QDomElement border, borderStyle _style, KSpread::Cell*cell);
+ void ParseBorder( QDomElement & gmr_styleborder, KSpread::Cell* kspread_cell );
+ double parseAttribute( const QDomElement &_element );
+
+};
+#endif // GNUMERICFILTER_H
diff --git a/filters/kspread/gnumeric/kspread_gnumeric_export.desktop b/filters/kspread/gnumeric/kspread_gnumeric_export.desktop
new file mode 100644
index 000000000..ace284e0e
--- /dev/null
+++ b/filters/kspread/gnumeric/kspread_gnumeric_export.desktop
@@ -0,0 +1,73 @@
+[Desktop Entry]
+Type=Service
+Name=GNUmeric Export Filter for KSpread
+Name[af]=Gnumeric Voer uit Filter vir Kspread
+Name[ar]=مِرْشَح تصدير GNUmeric لدى KSpread
+Name[az]=KSpread üçün GNUmeric Vermə Süzgəci
+Name[bg]=Филтър за експортиране от KSpread в GNUmeric
+Name[br]=Sil ezporzh GNUMERIC evit KSpread
+Name[bs]=GNUmeric Export Filter za KSpread
+Name[ca]=Filtre d'exportació GNUmeric per a KSpread
+Name[cs]=Gnumeric exportní filtr pro KSpread
+Name[cy]=Hidlen Allforio GNUmeric i KSpread
+Name[da]=GNUmeric-eksportfilter for KSpread
+Name[de]=KSpread GNUmeric-Exportfilter
+Name[el]=Φίλτρο εξαγωγής GNUmeric για το KSpread
+Name[eo]=GNUmeric-eksportfiltrilo por KSpread
+Name[es]=Filtro de exportación GNUmeric para KSpread
+Name[et]=KSpreadi GNUmeric'i ekspordifilter
+Name[eu]=KSpread-en GNUmeric esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات GNUmeric برای KSpread
+Name[fi]=Gnumeric-vientisuodin KSpeadiin
+Name[fr]=Filtre d'exportation GNUmeric de KSpread
+Name[fy]=GNUmeric-Eksportfilter foar KSpread
+Name[ga]=Scagaire Easpórtála GNUmeric le haghaidh KSpread
+Name[gl]=Filtro de Exportación de GNUmeric para KSpread
+Name[he]=מסנן ייצוא מ־KSpread ל־GNUmeric
+Name[hi]=के-स्प्रेड के लिए ग्नूमेरिक निर्यात छननी
+Name[hr]=GNUmeric filtar izvoza za KSpread
+Name[hu]=Gnumeric exportszűrő a KSpreadhez
+Name[is]=GNUmeric útflutningssía fyrir KSpread
+Name[it]=Filtro di esportazione GNUmeric per KSpread
+Name[ja]=KSpread GNUmeric エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ GNUmeric សម្រាប់ KSpread
+Name[lo]= ຕົວຕອງການສົ່ງອອກ GNUmeric ຂອງກະດາດຄຳນວນ K
+Name[lt]=GNUmeric eksporto filtras skirtas KSpread
+Name[lv]=GNUmeric eksporta filtrs priekš KSpread
+Name[ms]=Penapis Eksport GNUmeric bagi KSpread
+Name[mt]=Filtru għall-esportazzjoni ta' files GNUmeric minn ġo KSpread
+Name[nb]=GNUmeric-eksportfilter for KSpread
+Name[nds]=GNUmeric-Exportfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि जिन्यूमेरिक निर्यात फिल्टर
+Name[nl]=GNUmeric-Exportfilter voor KSpread
+Name[nn]=GNUmeric-eksportfilter for KSpread
+Name[pl]=Filtr eksportu do formatu GNUmeric dla KSpread
+Name[pt]=Filtro de Exportação de GNUmeric para o KSpread
+Name[pt_BR]=Filtro de exportação do Gnumeric para o KSpread
+Name[ro]=Filtru exportare KSpread pentru GNUMERIC
+Name[ru]=Фильтр экспорта таблиц KSpread в GNUmeric
+Name[se]=KSpread:a GNUmeric-olggosfievrridansilli
+Name[sk]=Gnumeric filter pre export z KSpread
+Name[sl]=Izvozni filter GNUmeric za KSpread
+Name[sr]=KSpread-ов филтер за извоз у GNUmeric
+Name[sr@Latn]=KSpread-ov filter za izvoz u GNUmeric
+Name[sv]=Gnumeric-exportfilter för Kspread
+Name[tg]=Филтри Содироти GNUmeric барои KSpread
+Name[th]=ตัวกรองการส่งออก GNUmeric ของกระดาษคำนวณ K
+Name[tr]=KSpread için GNUmeric Aktarma Filtresi
+Name[uk]=Фільтр експорту GNUmeric для KSpread
+Name[uz]=KSpread uchun GNUmeric eksport filteri
+Name[uz@cyrillic]=KSpread учун GNUmeric экспорт филтери
+Name[ven]=Filithara ya u bvisela nnda ya GNUmeric ya u phadaladza ha K
+Name[wa]=Passete Gnumeric di rexhowe po KSpread
+Name[xh]=GNUmeric Yesihluzi Sorhweba ngaphandle se KSpread
+Name[zh_CN]=KSpread 的 GNUmeric 导出过滤器
+Name[zh_TW]=KSpread 的 GNUmeric 匯出過濾程式
+X-KDE-Export=application/x-gnumeric
+X-KDE-Import=application/x-kspread
+X-KDE-Weight=1
+X-KDE-Library=libgnumericexport
+X-KDE-LibraryMajor=1
+X-KDE-LibraryMinor=0
+X-KDE-LibraryDependencies=
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/gnumeric/kspread_gnumeric_import.desktop b/filters/kspread/gnumeric/kspread_gnumeric_import.desktop
new file mode 100644
index 000000000..5b7717eeb
--- /dev/null
+++ b/filters/kspread/gnumeric/kspread_gnumeric_import.desktop
@@ -0,0 +1,74 @@
+[Desktop Entry]
+Type=Service
+Name=GNUMERIC Import Filter for KSpread
+Name[af]=Gnumeric In voer Filter vir Kspread
+Name[ar]=مِرْشَح استيراد GNUMERIC لدى KSpread
+Name[az]=KSpread üçün GNUMERİC Alma Süzgəci
+Name[bg]=Филтър за импортиране от GNUmeric в KSpread
+Name[br]=Sil enporzh GNUMERIC evit KSpread
+Name[bs]=GNUMERIC Import Filter za KSpread
+Name[ca]=Filtre d'importació GNUmeric per a KSpread
+Name[cs]=Gnumeric importní filtr pro KSpread
+Name[cy]=Hidlen Fewnforio GNUmeric i Kspread
+Name[da]=GNUmeric-importfilter for KSpread
+Name[de]=KSpread GNUmeric-Importfilter
+Name[el]=Φίλτρο εισαγωγής GNUMERIC για το KSpread
+Name[en_GB]=GNUmeric Import Filter for KSpread
+Name[eo]=GNUmeric-importfiltrilo por KSpread
+Name[es]=Filtro de importación GNUmeric para KSpread
+Name[et]=KSpreadi GNUmeric'i impordifilter
+Name[eu]=KSpread-en GNUmerci inportaziorako iragazkia
+Name[fa]=پالایۀ واردات GNUMERIC برای KSpread
+Name[fi]=Gnumeric tuontisuodin KSpeadiin
+Name[fr]=Filtre d'importation GNUmeric de KSpread
+Name[fy]=GNUMERIC-Ymportfilter foar KSpread
+Name[ga]=Scagaire Iompórtála GNUmeric le haghaidh KSpread
+Name[gl]=Filtro de Importación de GNUMERIC para KSpread
+Name[he]=מסנן ייבוא מ־GNUmeric ל־KSpread
+Name[hi]=के-स्प्रेड के लिए ग्नूमेरिक आयात छननी
+Name[hr]=GNUmeric filtar uvoza za KSpread
+Name[hu]=Gnumeric importszűrő a KSpreadhez
+Name[is]=GNUMERIC innflutningssía fyrir KSpread
+Name[it]=Filtro di importazione GNUmeric per KSpread
+Name[ja]=KSpread GNUmeric インポートフィルタ
+Name[km]=តម្រង​នាំចូល GNUMERIC សម្រាប់ KSpread
+Name[lo]=ຕົວຕອງການນຳເຂົ້າ GNUmeric ຂອງກະດາດຄຳນວນ K
+Name[lt]=GNUMERIC importo filtras skirtas KSpread
+Name[lv]=GNUMERIC importa filtrs priekš KSpread
+Name[ms]=Penapis Import GNUMERIC bagi KSpread
+Name[mt]=Filtru għall-importazzjoni ta' GNUmeric ġo KSpread
+Name[nb]=GNUmeric-importfilter for KSpread
+Name[nds]=GNUmeric-Importfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि GNUMERIC आयात फिल्टर
+Name[nl]=GNUmeric-Importfilter voor KSpread
+Name[nn]=GNUmeric-importfilter for KSpread
+Name[pl]=Filtr importu formatu GNUmeric dla KSpread
+Name[pt]=Filtro de Importação de GNUMERIC para o KSpread
+Name[pt_BR]=Filtro de importação Gnumeric para o KSpread
+Name[ro]=Filtru importare KSpread pentru GNUMERIC
+Name[ru]=Фильтр импорта таблиц GNUmeric в KSpread
+Name[se]=KSpread:a GNUmeric-sisafievrridansilli
+Name[sk]=Filter pre import Gnumeric pre KSpread
+Name[sl]=Uvozni filter GNUmeric za KSpread
+Name[sr]=KSpread-ов филтер за увоз из GNUmeric-а
+Name[sr@Latn]=KSpread-ov filter za uvoz iz GNUmeric-a
+Name[sv]=Gnumeric-importfilter för Kspread
+Name[tg]=Филтри Воридоти GNUMERIC барои KSpread
+Name[th]=ตัวกรองการนำเข้า GNUmeric ของกระดาษคำนวณ K
+Name[tr]=KSpread için GNUMERIC Alma Filtresi
+Name[uk]=Фільтр імпорту GNUMERIC для KSpread
+Name[uz]=KSpread uchun GNUmeric import filteri
+Name[uz@cyrillic]=KSpread учун GNUmeric импорт филтери
+Name[ven]=Filithara ya u bvisela nnda ya GNUMERIC yau phadaladza ha K
+Name[wa]=Passete Gnumeric d' intrêye po KSpread
+Name[xh]=GNUMERIC Yesihluzi Sorhwebo se KSpread
+Name[zh_CN]=KSpread 的 GNUmeric 导入过滤器
+Name[zh_TW]=KSpread 的 GNUmeric 匯入過濾程式
+X-KDE-Export=application/x-kspread
+X-KDE-Import=application/x-gnumeric
+X-KDE-Weight=1
+X-KDE-Library=libgnumericimport
+X-KDE-LibraryMajor=1
+X-KDE-LibraryMinor=0
+X-KDE-LibraryDependencies=
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/gnumeric/status.html b/filters/kspread/gnumeric/status.html
new file mode 100644
index 000000000..3c92af2e8
--- /dev/null
+++ b/filters/kspread/gnumeric/status.html
@@ -0,0 +1,304 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.76 [en] (X11; U; Linux 2.4.2-2 i686) [Netscape]">
+ <title>KOffice filters status: HTML FILTER</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<a NAME="START"></a>
+<center>
+<h1>
+KOffice filters status:&nbsp;&nbsp; GNUmeric (GNOME spreadsheet)</h1></center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%"><b><font size="-1"><a href="#import">Import</a>
+| <a href="#export">Export</a></font></b>
+<br>&nbsp;
+<br>&nbsp;
+<br>
+<br>
+<center>
+<p><a NAME="import"></a></center>
+<b><font size="-1"><a href="#START">Up</a></font></b>
+<center><table BORDER=0 CELLSPACING=0 WIDTH="100%" BGCOLOR="#000000" >
+<tr>
+<td>
+<table BORDER=0 CELLPADDING=2 WIDTH="100%" BGCOLOR="#FFFFFF" >
+<tr BGCOLOR="#DDFFDD">
+<td COLSPAN="2">
+<center><b><i><font size="+1">Import GNUmeric for Kspread</font></i></b></center>
+</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP NOWRAP WIDTH="1%"><b><font size="+1">Last update</font></b></td>
+
+<td>February 6, 2005</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+
+<td>Vertical &amp; Horizontal Alignment, text wrapping, indention
+<br>Background, Patter &amp; Foreground color
+<br>Fonts:
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Size
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Underline
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Italic
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Bold
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Family
+<br>Multiple Sheets (Tables)
+<br>Formulas!!! (ExprID)
+<br>Selections: selected cells, last selected table
+<br>Cell Formats (e.g. Date, Time, Percent, different currencies ...)
+<br>Number formating (in brackets, red colored)
+<br>Comments
+<br>Page: size, orientation, borders, header and footer
+<br>Border: color, style, width for all 6 types
+<br>Background pattern: style, color
+<br>Cell Size: Horizontal &amp; Vertical&nbsp;
+<br>Hidden Columns
+<br>Default row heights and column widths
+<br>Area name
+<br>Links
+<br>merge cells
+<br>Text Rotation
+<br>Print repeate col/row
+<br>Cell validation
+<br>Document Information
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Author
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Company
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Comments
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Title
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Keywords</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+
+<td>Cell Size: Horizontal &amp; Vertical (Export) (kspread&nbsp; doesn't
+support retriving the first "rowFormat" and colFormat".)
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+19 Applix small circle
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+20 Applix semicircle
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+21 Applix small thatch
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+22 Applix round thatch
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+23 Applix Brick => all unsupported by KSpread
+<br>(a=b) for gnumeric vs. (a==b) for kspread
+<br>if(a,b,c) for gnumeric vs. if(a;b;c) for kspread
+<br>GNUmeric version differentiation
+<br>border style: double, hair (KSpread doesn't support them)
+<br>charts
+<br>exact number, time and date formats (need the upcoming style engine)
+<br>pictures (unsupported by KSpread)
+<br>Alignment: fill, justify, center across selection (not supported by kspread)
+<br>Accurate progress bar
+<p>Document Information
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Application
+(kspread&nbsp; doesn't support it.)
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Category (kspread&nbsp;
+doesn't support it.)
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Manager (kspread&nbsp;
+doesn't support it.)
+<p>Vertical Text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (gnumeric doesn't
+support it.)
+<br>Zoom&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+(kspread&nbsp; doesn't support it.)
+<br>Multiple Selections (kspread&nbsp; doesn't support it.)
+<br>Double Underline&nbsp;&nbsp;&nbsp; (kspread&nbsp; doesn't support it.)
+</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">History</font></b></td>
+
+<td>Jun/Jul 2001 - Initial Revision
+<br>Jul 10, 2001 - Support for hidden columns
+<br>Jul 12, 2001 - Support for Document Information
+<br>Jul 15, 2001 - Preliminary support for background patterns.
+<br>Aug 21, 2002 - text/number formats, border, patters, page/print info, comments
+<br>Aug 21, 2002 - font family, wrap text, number formating, precisions
+<br>Sep 05, 2002 - bugfixes, default sizes, row and column layouts
+<br>Sep 07, 2002 - bugfixes, preliminery date/time support
+<br>Feb 03, 2005 - export area name
+<br>Feb 06, 2005 - cells merged
+<br>Feb 08, 2005 - Text Rotation
+<br>Feb 19, 2005 - Cell validation
+</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+
+<td><a href="mailto:phillipezolt@hotmail.com">Phillip Ezolt</a>
+<br><a href="mailto:nandres@web.de">Norbert Andres</a>
+<br><a href="mailto:montel@kde.org">Laurent Montel</a>
+<br>This filter is based on the CSV filter by <a href="mailto:faure@kde.org">David
+Faure</a>&nbsp;&nbsp; <a href="mailto:trobin@kde.org">Werner Trobin</a></td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+
+<td>www.koffice.org&nbsp;
+<br>www.gnumeric.org</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Progress report&nbsp;</font></b></td>
+
+<td>This has been tested against GNUmeric v0.70 and koffice v1.3-alpha.&nbsp;
+<p>I've tried to keep the import/export filters pretty much in sync.&nbsp;</td>
+</tr>
+</table>
+</td>
+</tr>
+</table></center>
+<b><font size="-1"><a href="#START">Up</a></font></b>
+<br>&nbsp;
+<p>
+<hr NOSHADE SIZE=1>
+<br>&nbsp;
+<br>&nbsp;
+<br>
+<br>
+<center>
+<p><a NAME="export"></a></center>
+<b><font size="-1"><a href="#START">Up</a></font></b>
+<center><table BORDER=0 CELLSPACING=0 WIDTH="100%" BGCOLOR="#000000" >
+<tr>
+<td>
+<table BORDER=0 CELLPADDING=2 WIDTH="100%" BGCOLOR="#FFFFFF" >
+<tr BGCOLOR="#FFDDDD">
+<td COLSPAN="2">
+<center><b><i><font size="+1">Export Kspread to GNUmeric</font></i></b></center>
+</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP NOWRAP WIDTH="1%"><b><font size="+1">Last update</font></b></td>
+
+<td>February 14, 2005</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+
+<td>Vertical &amp; Horizontal Alignment
+<br>Background &amp; Foreground color
+<br>Fonts:
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Size
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Underline
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Italic
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Bold
+<br>Multiple Sheets (Tables)
+<br>Formulas!!! (ExprID)
+<br>Selections
+<br>Cell Size: Horizontal &amp; Vertical
+<br>Hidden columns/rows&nbsp;
+<br>Selected Tab
+<br>Paper layout
+<br>area name
+<br>Cell comment
+<br>Text Rotation
+<br>Borders
+<br>Repeate print column/row
+<br>Cell validation
+<br>(a=b) for gnumeric vs. (a==b) for kspread
+<br>Document Information
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Author
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Company
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Comments
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Title
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Keywords</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+<td>
+Formats:
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Percentages
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Money
+<br>Background patterns &amp; Colors
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+If color is the default color do NOT set it in the export file.&nbsp;
+<br>Font:
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Face Name
+<br>if(a,b,c) for gnumeric vs. if(a;b;c) for kspread
+<br>GNUmeric version differentiation
+<br>Accurate progress bar
+<p>Document Information
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Application
+(kspread&nbsp; doesn't support it.)
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Category (kspread&nbsp;
+doesn't support it.)
+<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Manager (kspread&nbsp;
+doesn't support it.)
+<br>Vertical Text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (gnumeric doesn't
+support it.)
+<br>Zoom&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+(kspread&nbsp; doesn't support it.)
+<br>Multiple Selections (kspread&nbsp; doesn't support it.)
+<br>Double Underline&nbsp;&nbsp;&nbsp; (kspread&nbsp; doesn't support it.)
+</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">History</font></b></td>
+
+<td>Jun/Jul 2001 - Initial Revision
+<br>Jul 10, 2001 - Support for hidden columns
+<br>Jul 12, 2001 - Document Information
+<br>Feb 5, 2005 - Cell comment
+<br>Feb 8, 2005 - Text Rotation
+<br>Feb 10, 2005 - Repeate print col/row
+<br>Feb 14, 2005 - Cell Validation
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+
+<td><a href="mailto:phillipezolt@hotmail.com">Phillip Ezolt</a>
+ <br><a href="mailto:montel@kde.org">Laurent Montel</a>
+ <br>This filter is based on the CSV filter by <a href="mailto:faure@kde.org">David
+Faure</a>&nbsp;&nbsp; <a href="mailto:trobin@kde.org">Werner Trobin</a></td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+
+<td>www.koffice.org
+<br>www.gnumeric.org</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Progress report&nbsp;</font></b></td>
+
+<td>This has been tested against GNUmeric v1.4.2 and koffice v1.4cvs.
+<p>I've tried to keep the import/export filters pretty much in sync.&nbsp;</td>
+</tr>
+</table>
+</td>
+</tr>
+</table></center>
+<b><font size="-1"><a href="#START">Up</a></font></b>
+
+</body>
+</html>
diff --git a/filters/kspread/html/CHANGELOG b/filters/kspread/html/CHANGELOG
new file mode 100644
index 000000000..0147160fb
--- /dev/null
+++ b/filters/kspread/html/CHANGELOG
@@ -0,0 +1,11 @@
+=== KOffice 1.4 ===
+- New configuration dialog to tweak HTML export
+- Make borders optional
+- Ability to select which sheets to be exported.
+- Ability to write each table to a new page.
+- A Table Of Contents is generated on top of each page.
+- Choose the number of pixels between cells.
+- Don't add one column and row too much.
+- Don't export empty sheets.
+- Let the user choose encoding.
+- Linkage of external stylesheets. \ No newline at end of file
diff --git a/filters/kspread/html/Makefile.am b/filters/kspread/html/Makefile.am
new file mode 100644
index 000000000..87018febd
--- /dev/null
+++ b/filters/kspread/html/Makefile.am
@@ -0,0 +1,18 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) -I$(top_srcdir)/kspread $(KOFFICE_INCLUDES) \
+ $(KOTEXT_INCLUDES) $(all_includes)
+
+####### Files
+
+kde_module_LTLIBRARIES = libkspreadhtmlexport.la
+
+libkspreadhtmlexport_la_SOURCES = htmlexport.cc exportdialog.cc exportwidget.ui
+libkspreadhtmlexport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libkspreadhtmlexport_la_LIBADD = $(KOFFICE_LIBS) ../../../kspread/libkspreadcommon.la
+
+METASOURCES = AUTO
+
+service_DATA = kspread_html_export.desktop
+
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/html/exportdialog.cc b/filters/kspread/html/exportdialog.cc
new file mode 100644
index 000000000..78276defe
--- /dev/null
+++ b/filters/kspread/html/exportdialog.cc
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Bram Schoenmakers <bramschoenmakers@kde.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlistbox.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qtextcodec.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kurlrequester.h>
+
+#include <exportdialog.h>
+#include <exportwidget.h>
+
+ExportDialog::ExportDialog( QWidget *parent, const char *name )
+ : KDialogBase( parent, name, true, i18n("Export Sheet to HTML"), Ok|Cancel, No, true ), m_mainwidget( new ExportWidget( this ) )
+{
+ kapp->restoreOverrideCursor();
+
+ connect( m_mainwidget->mCustomButton, SIGNAL( toggled( bool ) ),
+ m_mainwidget->mCustomURL, SLOT( setEnabled( bool ) ) );
+ connect( m_mainwidget->mSelectAllButton, SIGNAL( clicked() ), SLOT( selectAll() ) );
+ connect( m_mainwidget->mDeselectAllButton, SIGNAL( clicked() ),
+ m_mainwidget->mSheets, SLOT( clearSelection() ) );
+
+ m_mainwidget->mEncodingBox->insertItem( i18n( "Recommended: UTF-8" ) );
+ m_mainwidget->mEncodingBox->insertItem( i18n( "Locale (%1)" ).arg( KGlobal::locale()->codecForEncoding()->name() ) );
+
+ m_mainwidget->mCustomURL->setMode( KFile::ExistingOnly );
+
+ setMainWidget( m_mainwidget );
+}
+
+void ExportDialog::selectAll()
+{
+ m_mainwidget->mSheets->selectAll( true );
+}
+
+ExportDialog::~ExportDialog()
+{
+ kapp->setOverrideCursor(Qt::waitCursor);
+}
+
+QTextCodec *ExportDialog::encoding() const
+{
+ if( m_mainwidget->mEncodingBox->currentItem() == 1 ) // locale selected
+ return KGlobal::locale()->codecForEncoding();
+
+ return QTextCodec::codecForName( "utf8" ); // utf8 is default
+}
+
+bool ExportDialog::useBorders() const
+{
+ return m_mainwidget->mUseBorders->isChecked();
+}
+
+bool ExportDialog::separateFiles() const
+{
+ return m_mainwidget->mSeparateFiles->isChecked();
+}
+
+QString ExportDialog::customStyleURL() const
+{
+ QString url = m_mainwidget->mCustomURL->url();
+ if( m_mainwidget->mCustomButton->isChecked() && KURL( url ).isValid() )
+ return url;
+
+ return QString::null;
+}
+
+void ExportDialog::setSheets( const QStringList &list )
+{
+ m_mainwidget->mSheets->insertStringList( list );
+ selectAll();
+}
+
+QStringList ExportDialog::sheets() const
+{
+ QStringList list;
+ for( uint i = 0; i < m_mainwidget->mSheets->count() ; i++ )
+ {
+ if( m_mainwidget->mSheets->isSelected( i ) )
+ list.append( m_mainwidget->mSheets->text( i ) );
+ }
+ return list;
+}
+
+int ExportDialog::pixelsBetweenCells() const
+{
+ return m_mainwidget->mPixelsBetweenCells->value();
+}
+
+#include <exportdialog.moc>
diff --git a/filters/kspread/html/exportdialog.h b/filters/kspread/html/exportdialog.h
new file mode 100644
index 000000000..4a4605548
--- /dev/null
+++ b/filters/kspread/html/exportdialog.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Bram Schoenmakers <bramschoenmakers@kde.nl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef EXPORTDIALOG_H
+#define EXPORTDIALOG_H
+
+#include <kdialogbase.h>
+
+class ExportWidget;
+
+class ExportDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ ExportDialog( QWidget *parent = 0, const char *name = 0 );
+ ~ExportDialog();
+
+ void setSheets( const QStringList & );
+ QStringList sheets() const;
+
+ /**
+ Returns preferred encoding. Defaults to UTF-8.
+ */
+ QTextCodec *encoding() const;
+
+ /**
+ Returns a valid URL if the custom button was selected.
+ Else, it will return QString::null.
+ */
+ QString customStyleURL() const;
+
+ /**
+ Returns true if borders should be shown, false if borders
+ should be hidden.
+ */
+ bool useBorders() const;
+
+ bool separateFiles() const;
+
+ int pixelsBetweenCells() const;
+ protected slots:
+ void selectAll();
+ private:
+ ExportWidget *m_mainwidget;
+};
+
+#endif
diff --git a/filters/kspread/html/exportwidget.ui b/filters/kspread/html/exportwidget.ui
new file mode 100644
index 000000000..d81ef40b4
--- /dev/null
+++ b/filters/kspread/html/exportwidget.ui
@@ -0,0 +1,310 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>ExportWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ExportWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>256</width>
+ <height>413</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>En&amp;coding:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mEncodingBox</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>mEncodingBox</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>With this option you can define the encoding of the HTML file. The recommended encoding (UTF8) is selected as default.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>Sheet Selection</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox">
+ <property name="name">
+ <cstring>mSheets</cstring>
+ </property>
+ <property name="selectionMode">
+ <enum>Multi</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>mSelectAllButton</cstring>
+ </property>
+ <property name="text">
+ <string>Select &amp;All</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click here to select all sheets in the list.</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>mDeselectAllButton</cstring>
+ </property>
+ <property name="text">
+ <string>Desele&amp;ct All</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click here to select all sheets in the list.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>330</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>mSeparateFiles</cstring>
+ </property>
+ <property name="text">
+ <string>Use &amp;separate files for each table</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This option will make the HTML export filter generate a new page for each sheet. If you disable this option, all sheets are written on one page.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup4</cstring>
+ </property>
+ <property name="title">
+ <string>Style</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>mDefaultButton</cstring>
+ </property>
+ <property name="text">
+ <string>Use &amp;default style</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select this option to use the default fonts and colors for the HTML page.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>mCustomButton</cstring>
+ </property>
+ <property name="text">
+ <string>Use &amp;external stylesheet:</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Select this option to specify a separate stylesheet for the HTML page. You can select or type on in the field below.</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>mCustomURL</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>In this field you can enter an URL for your stylesheet. It is possible to point to a stylesheet on disk, or to somewhere on the Internet.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Layout</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>mUseBorders</cstring>
+ </property>
+ <property name="text">
+ <string>Use &amp;borders</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Use this option to enable or disable borders around the cells.</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Pi&amp;xels between cells:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>mPixelsBetweenCells</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Use this option to define how many pixels there should be between the cells. This effect is better visible if you check &lt;b&gt;Use borders&lt;/b&gt; too.</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>mPixelsBetweenCells</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maxValue">
+ <number>25</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Use this option to define how many pixels there should be between the cells. This effect is better visible if you check &lt;b&gt;Use borders&lt;/b&gt; too.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/filters/kspread/html/htmlexport.cc b/filters/kspread/html/htmlexport.cc
new file mode 100644
index 000000000..76c6ee83e
--- /dev/null
+++ b/filters/kspread/html/htmlexport.cc
@@ -0,0 +1,475 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Eva Brucherseifer <eva@kde.org>
+ Copyright (C) 2005 Bram Schoenmakers <bramschoenmakers@kde.nl>
+ based on kspread csv export filter by David Faure
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <htmlexport.h>
+#include <exportdialog.h>
+
+#include <qfile.h>
+#include <qtextcodec.h>
+
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <KoFilterChain.h>
+#include <KoDocumentInfo.h>
+#include <kofficeversion.h>
+
+#include <kspread_map.h>
+#include <kspread_sheet.h>
+#include <kspread_doc.h>
+#include <kspread_util.h>
+
+using namespace KSpread;
+
+typedef KGenericFactory<HTMLExport, KoFilter> HTMLExportFactory;
+K_EXPORT_COMPONENT_FACTORY( libkspreadhtmlexport, HTMLExportFactory( "kofficefilters" ) )
+
+const QString html_table_tag = "table";
+const QString html_table_options = QString(" border=\"%1\" cellspacing=\"%2\"");
+const QString html_row_tag = "tr";
+const QString html_row_options = "";
+const QString html_cell_tag = "td";
+const QString html_cell_options = "";
+const QString html_bold = "b";
+const QString html_italic = "i";
+const QString html_underline = "u";
+const QString html_right= "right";
+const QString html_left= "left";
+const QString html_center= "center";
+const QString html_top="top";
+const QString html_bottom="bottom";
+const QString html_middle="middle";
+const QString html_h1="h1";
+
+HTMLExport::HTMLExport(KoFilter *, const char *, const QStringList&) :
+ KoFilter(), m_dialog( new ExportDialog() )
+{
+}
+
+HTMLExport::~HTMLExport()
+{
+ delete m_dialog;
+}
+
+// HTML enitities, AFAIK we don't need to escape " to &quot; (dnaber):
+const QString strAmp ("&amp;");
+const QString nbsp ("&nbsp;");
+const QString strLt ("&lt;");
+const QString strGt ("&gt;");
+
+// The reason why we use the KoDocument* approach and not the QDomDocument
+// approach is because we don't want to export formulas but values !
+KoFilter::ConversionStatus HTMLExport::convert( const QCString& from, const QCString& to )
+{
+ if(to!="text/html" || from!="application/x-kspread")
+ {
+ kdWarning(30501) << "Invalid mimetypes " << to << " " << from << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ KoDocument* document = m_chain->inputDocument();
+
+ if ( !document )
+ return KoFilter::StupidError;
+
+ if( !::qt_cast<const KSpread::Doc *>( document ) ) // it's safer that way :)
+ {
+ kdWarning(30501) << "document isn't a KSpread::Doc but a " << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ const Doc * ksdoc=static_cast<const Doc *>(document);
+
+ if( ksdoc->mimeType() != "application/x-kspread" )
+ {
+ kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ Sheet *sheet = ksdoc->map()->firstSheet();
+ QString filenameBase = m_chain->outputFile();
+ filenameBase = filenameBase.left( filenameBase.findRev( '.' ) );
+
+ QStringList sheets;
+ while( sheet != 0 )
+ {
+ int rows = 0;
+ int columns = 0;
+ detectFilledCells( sheet, rows, columns );
+ m_rowmap[ sheet->sheetName() ] = rows;
+ m_columnmap[ sheet->sheetName() ] = columns;
+
+ if( rows > 0 && columns > 0 )
+ {
+ sheets.append( sheet->sheetName() );
+ }
+ sheet = ksdoc->map()->nextSheet();
+ }
+ m_dialog->setSheets( sheets );
+
+ if( m_dialog->exec() == QDialog::Rejected )
+ return KoFilter::UserCancelled;
+
+ sheets = m_dialog->sheets();
+ QString str;
+ for( uint i = 0; i < sheets.count() ; ++i )
+ {
+ sheet = ksdoc->map()->findSheet( sheets[i] );
+
+ QString file = fileName( filenameBase, sheet->sheetName(), sheets.count() > 1 );
+
+ if( m_dialog->separateFiles() || sheets[i] == sheets.first() )
+ {
+ str = QString::null;
+ openPage( sheet, document, str );
+ writeTOC( sheets, filenameBase, str );
+ }
+
+ convertSheet( sheet, str, m_rowmap[ sheet->sheetName() ], m_columnmap[ sheet->sheetName() ] );
+
+ if( m_dialog->separateFiles() || sheets[i] == sheets.last() )
+ {
+ closePage( str );
+ QFile out(file);
+ if(!out.open(IO_WriteOnly)) {
+ kdError(30501) << "Unable to open output file!" << endl;
+ out.close();
+ return KoFilter::FileNotFound;
+ }
+ QTextStream streamOut(&out);
+ streamOut.setCodec( m_dialog->encoding() );
+ streamOut << str << endl;
+ out.close();
+ }
+
+ if( !m_dialog->separateFiles() )
+ {
+ createSheetSeparator( str );
+ }
+
+ }
+
+ emit sigProgress(100);
+ return KoFilter::OK;
+}
+
+void HTMLExport::openPage( Sheet *sheet, KoDocument *document, QString &str )
+{
+ QString title;
+ KoDocumentInfo *info = document->documentInfo();
+ KoDocumentInfoAbout *aboutPage = static_cast<KoDocumentInfoAbout *>(info->page( "about" ));
+ if ( aboutPage && !aboutPage->title().isEmpty() )
+ title = aboutPage->title() + " - ";
+
+ title += sheet->sheetName();
+
+ // header
+ str = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" ";
+ str += " \"http://www.w3.org/TR/html4/loose.dtd\"> \n";
+ str += "<html>\n";
+ str += "<head>\n";
+ str += "<meta http-equiv=\"Content-Type\" ";
+ str += QString("content=\"text/html; charset=%1\">\n").arg( m_dialog->encoding()->mimeName() );
+ str += "<meta name=\"Generator\" ";
+ str += "content=\"KSpread HTML Export Filter Version = ";
+ str += KOFFICE_VERSION_STRING;
+ str += "\">\n";
+
+ // Insert stylesheet
+ if( !m_dialog->customStyleURL().isEmpty() )
+ {
+ str += "<link ref=\"stylesheet\" type=\"text/css\" href=\"";
+ str += m_dialog->customStyleURL();
+ str += "\" title=\"Style\" >\n";
+ }
+
+ str += "<title>" + title + "</title>\n";
+ str += "</head>\n";
+ str += QString("<body bgcolor=\"#FFFFFF\" dir=\"%1\">\n").arg(
+ sheet->isRightToLeft()?"rtl":"ltr");
+
+ str += "<a name=\"__top\">\n";
+}
+
+void HTMLExport::closePage( QString &str )
+{
+ str += "<p align=\"" + html_center + "\"><a href=\"#__top\">" + i18n("Top") + "</a></p>\n";
+ str += "</body>\n";
+ str += "</html>\n\n";
+}
+
+void HTMLExport::convertSheet( Sheet *sheet, QString &str, int iMaxUsedRow, int iMaxUsedColumn )
+{
+ QString emptyLines;
+
+ // Either we get hold of KSpreadTable::m_dctCells and apply the old method below (for sorting)
+ // or, cleaner and already sorted, we use KSpreadTable's API (slower probably, though)
+ int iMaxRow = sheet->maxRow();
+
+ if( !m_dialog->separateFiles() )
+ str += "<a name=\"" + sheet->sheetName().lower().stripWhiteSpace() + "\">\n";
+
+ str += ("<h1>" + sheet->sheetName() + "</h1><br>\n");
+
+ // this is just a bad approximation which fails for documents with less than 50 rows, but
+ // we don't need any progress stuff there anyway :) (Werner)
+ int value=0;
+ int step=iMaxRow > 50 ? iMaxRow/50 : 1;
+ int i=1;
+
+ str += "<" + html_table_tag + html_table_options.arg( m_dialog->useBorders() ? "1" : "0" ).arg( m_dialog->pixelsBetweenCells() ) +
+ QString("dir=\"%1\">\n").arg(sheet->isRightToLeft()?"rtl":"ltr");
+
+ unsigned int nonempty_cells_prev=0;
+
+ for ( int currentrow = 1 ; currentrow <= iMaxUsedRow ; ++currentrow, ++i )
+ {
+ if(i>step) {
+ value+=2;
+ emit sigProgress(value);
+ i=0;
+ }
+
+ QString separators;
+ QString line;
+ unsigned int nonempty_cells=0;
+ unsigned int colspan_cells=0;
+
+ for ( int currentcolumn = 1 ; currentcolumn <= iMaxUsedColumn ; currentcolumn++ )
+ {
+ Cell * cell = sheet->cellAt( currentcolumn, currentrow, false );
+ colspan_cells=cell->extraXCells();
+ if (cell->needsPrinting())
+ nonempty_cells++;
+ QString text;
+ QColor bgcolor = cell->bgColor(currentcolumn,currentrow);
+ // FIXME: some formatting seems to be missing with cell->text(), e.g.
+ // "208.00" in KSpread will be "208" in HTML (not always?!)
+ bool link = false;
+
+ if ( !cell->link().isEmpty() )
+ {
+ if ( localReferenceAnchor(cell->link()) )
+ {
+ text = cell->text();
+ }
+ else
+ {
+ text = " <A href=\"" + cell->link() + "\">" + cell->text() + "</A>";
+ link = true;
+ }
+ }
+ else
+ text=cell->strOutText();
+#if 0
+ switch( cell->content() ) {
+ case Cell::Text:
+ text = cell->text();
+ break;
+ case Cell::RichText:
+ case Cell::VisualFormula:
+ text = cell->text(); // untested
+ break;
+ case Cell::Formula:
+ cell->calc( TRUE ); // Incredible, cells are not calculated if the document was just opened
+ text = cell->valueString();
+ break;
+ }
+ text = cell->prefix(currentrow, currentcolumn) + " " + text + " "
+ + cell->postfix(currentrow, currentcolumn);
+#endif
+ line += " <" + html_cell_tag + html_cell_options;
+ if (text.isRightToLeft() != sheet->isRightToLeft())
+ line += QString(" dir=\"%1\" ").arg(text.isRightToLeft()?"rtl":"ltr");
+ if (bgcolor.isValid() && bgcolor.name()!="#ffffff") // change color only for non-white cells
+ line += " bgcolor=\"" + bgcolor.name() + "\"";
+
+ switch((Format::Align)cell->defineAlignX())
+ {
+ case Format::Left:
+ line+=" align=\"" + html_left +"\"";
+ break;
+ case Format::Right:
+ line+=" align=\"" + html_right +"\"";
+ break;
+ case Format::Center:
+ line+=" align=\"" + html_center +"\"";
+ break;
+ case Format::Undefined:
+ break;
+ }
+ switch((Format::AlignY)cell-> format()->alignY(currentrow, currentcolumn))
+ {
+ case Format::Top:
+ line+=" valign=\"" + html_top +"\"";
+ break;
+ case Format::Middle:
+ line+=" valign=\"" + html_middle +"\"";
+ break;
+ case Format::Bottom:
+ line+=" valign=\"" + html_bottom +"\"";
+ break;
+ case Format::UndefinedY:
+ break;
+ }
+ line+=" width=\""+QString::number(cell->width())+"\"";
+ line+=" height=\""+QString::number(cell->height())+"\"";
+
+ if (cell->extraXCells()>0)
+ {
+ QString tmp;
+ int extra_cells=cell->extraXCells();
+ line += " colspan=\"" + tmp.setNum(extra_cells+1) + "\"";
+ currentcolumn += extra_cells;
+ }
+ text = text.stripWhiteSpace();
+ if( text.at(0) == '!' ) {
+ // this is supposed to be markup, just remove the '!':
+ text = text.right(text.length()-1);
+ } else if ( !link ) {
+ // Escape HTML characters.
+ text.replace ('&' , strAmp)
+ .replace ('<' , strLt)
+ .replace ('>' , strGt)
+ .replace (' ' , nbsp);
+ }
+ line += ">\n";
+
+ if (cell->format()->textFontBold(currentcolumn,currentrow))
+ {
+ text.insert(0, "<" + html_bold + ">");
+ text.append("</" + html_bold + ">");
+ }
+ if (cell->format()->textFontItalic(currentcolumn,currentrow))
+ {
+ text.insert(0, "<" + html_italic + ">");
+ text.append("</" + html_italic + ">");
+ }
+ if (cell->format()->textFontUnderline(currentcolumn,currentrow))
+ {
+ text.insert(0, "<" + html_underline + ">");
+ text.append("</" + html_underline + ">");
+ }
+ QColor textColor = cell->format()->textColor(currentcolumn,currentrow);
+ if (textColor.isValid() && textColor.name()!="#000000") // change color only for non-default text
+ {
+ text.insert(0, "<font color=\"" + textColor.name() + "\">");
+ text.append("</font>");
+ }
+ line += " " + text;
+ line += "\n </" + html_cell_tag + ">\n";
+ }
+
+ if (nonempty_cells == 0 && nonempty_cells_prev == 0) {
+ nonempty_cells_prev = nonempty_cells;
+ // skip line if there's more than one empty line
+ continue;
+ } else {
+ nonempty_cells_prev = nonempty_cells;
+ str += emptyLines;
+ str += "<" + html_row_tag + html_row_options + ">\n";
+ str += line;
+ str += "</" + html_row_tag + ">";
+ emptyLines = QString::null;
+ // Append a CR, but in a temp string -> if no other real line,
+ // then those will be dropped
+ emptyLines += "\n";
+ }
+ }
+ str += "\n</" + html_table_tag + ">\n<br>\n";
+}
+
+void HTMLExport::createSheetSeparator( QString &str )
+{
+ str += ("<p align=\"" + html_center + "\"><a href=\"#__top\">" + i18n("Top") + "</a></p>\n" );
+ str += "<hr width=\"80%\">\n";
+}
+
+void HTMLExport::writeTOC( const QStringList &sheets, const QString &base, QString &str )
+{
+ // don't create TOC for 1 sheet
+ if( sheets.count() == 1 )
+ return;
+
+ str += "<p align=\"" + html_center + "\">\n";
+
+ for( uint i = 0 ; i < sheets.count() ; ++i )
+ {
+ str += "<a href=\"";
+
+ if( m_dialog->separateFiles() )
+ {
+ str += fileName( base, sheets[i], sheets.count() > 1 );
+ }
+ else
+ {
+ str += "#" + sheets[i].lower().stripWhiteSpace();
+ }
+
+ str += "\">" + sheets[i] + "</a>\n";
+ if( i != sheets.count() -1 )
+ str += " - ";
+ }
+
+ str += "</p><hr width=\"80%\">\n";
+}
+
+QString HTMLExport::fileName( const QString &base, const QString &sheetName, bool multipleFiles )
+{
+ QString fileName = base;
+ if( m_dialog->separateFiles() && multipleFiles )
+ {
+ fileName += "-" + sheetName;
+ }
+ fileName += ".html";
+
+ return fileName;
+}
+
+void HTMLExport::detectFilledCells( Sheet *sheet, int &rows, int &columns )
+{
+ int iMaxColumn = sheet->maxColumn();
+ int iMaxRow = sheet->maxRow();
+ rows = 0;
+ columns = 0;
+
+ for ( int currentrow = 1 ; currentrow <= iMaxRow ; ++currentrow)
+ {
+ Cell * cell = 0L;
+ int iUsedColumn=0;
+ for ( int currentcolumn = 1 ; currentcolumn <= iMaxColumn ; currentcolumn++ )
+ {
+ cell = sheet->cellAt( currentcolumn, currentrow, false );
+ QString text;
+ if ( !cell->isDefault() && !cell->isEmpty() )
+ {
+ iUsedColumn = currentcolumn;
+ }
+ }
+ if (cell)
+ iUsedColumn += cell->extraXCells();
+ if (iUsedColumn > columns)
+ columns = iUsedColumn;
+ if ( iUsedColumn > 0 )
+ rows = currentrow;
+ }
+}
+
+#include <htmlexport.moc>
diff --git a/filters/kspread/html/htmlexport.h b/filters/kspread/html/htmlexport.h
new file mode 100644
index 000000000..1952c9af7
--- /dev/null
+++ b/filters/kspread/html/htmlexport.h
@@ -0,0 +1,81 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Eva Brucherseifer <eva@kde.org>
+ Copyright (C) 2005 Bram Schoenmakers <bramschoenmakers@kde.nl>
+ based on kspread csv export filter by David Faure
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef HTMLEXPORT_TEST_H
+#define HTMLEXPORT_TEST_H
+
+#include <KoFilter.h>
+
+class ExportDialog;
+class KoDocument;
+
+namespace KSpread
+{
+class Sheet;
+}
+
+class HTMLExport : public KoFilter {
+ Q_OBJECT
+public:
+ HTMLExport(KoFilter *parent, const char*name, const QStringList&);
+ virtual ~HTMLExport();
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+ private:
+ /** Writes the top of the page in HTML to @par str */
+ void openPage( KSpread::Sheet *sheet,KoDocument *document, QString &str);
+
+ /** Closes a page in HTML */
+ void closePage( QString &);
+
+ /**
+ Converts @par sheet to HTML and writes to @par str.
+ */
+ void convertSheet( KSpread::Sheet *sheet, QString &str, int, int);
+
+ /** Writes a bar and a link to the top to @par str. */
+ void createSheetSeparator( QString & );
+
+ /** Writes the table of contents */
+ void writeTOC( const QStringList &, const QString &, QString & );
+
+ /**
+ Returns a filename based on the @par base filename and the options
+ defined in the dialog.
+ */
+ QString fileName( const QString &base, const QString &, bool );
+
+ /**
+ Detects which rows and columsn of the given @par sheet are used and
+ writes the number of them to @par row and @par column.
+ */
+ void detectFilledCells( KSpread::Sheet *sheet, int &rows, int &colums );
+ private:
+ ExportDialog *m_dialog;
+
+ typedef QMap<QString,int> Rows;
+ Rows m_rowmap;
+ typedef QMap<QString,int> Columns;
+ Columns m_columnmap;
+};
+
+#endif
+
diff --git a/filters/kspread/html/kspread_html_export.desktop b/filters/kspread/html/kspread_html_export.desktop
new file mode 100644
index 000000000..7164cf9a4
--- /dev/null
+++ b/filters/kspread/html/kspread_html_export.desktop
@@ -0,0 +1,72 @@
+[Desktop Entry]
+Type=Service
+Name=HTML Export Filter for KSpread
+Name[af]=Html Voer uit Filter vir Kspread
+Name[ar]=مِرْشَح تصدير HTML لدى KSpread
+Name[az]=KSpread üçün HTML Vermə Süzgəci
+Name[bg]=Филтър за експортиране от KSpread в HTML
+Name[br]=Sil ezporzh HTML evit KSpread
+Name[bs]=HTML Export Filter za KSpread
+Name[ca]=Filtre d'exportació HTML per a KSpread
+Name[cs]=HTML exportní filtr pro KSpread
+Name[cy]=Hidlen Allforio HTML i KSpread
+Name[da]=HTML-eksportfilter for KSpread
+Name[de]=KSpread HTML-Exportfilter
+Name[el]=Φίλτρο εξαγωγής HTML για το KSpread
+Name[eo]=HTML-eksportfiltrilo por KSpread
+Name[es]=Filtro de exportación HTML para KSpread
+Name[et]=KSpreadi HTML-i ekspordifilter
+Name[eu]=KSpread-en HTML esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات زنگام برای KSpread
+Name[fi]=HTML-vientisuodin KSpeadiin
+Name[fr]=Filtre d'exportation HTML de KSpread
+Name[fy]=HTML-Eksportfilter foar KSpread
+Name[ga]=Scagaire Easpórtála HTML le haghaidh KSpread
+Name[gl]=Filtro de Exportación de HTML para KSpread
+Name[he]=מסנן ייצוא מ־KSpread ל־HTML
+Name[hi]=के-स्प्रेड के लिए एचटीएमएल निर्यात छननी
+Name[hr]=HTML filtar izvoza za KSpread
+Name[hu]=HTML exportszűrő a KSpreadhez
+Name[is]=HTML útflutningssía fyrir KSpread
+Name[it]=Filtro di esportazione HTML per KSpread
+Name[ja]=KSpread HTML エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ HTML សម្រាប់ KSpread
+Name[lo]= ຕົວຕອງການສົ່ງອອກ HTML ຂອງກະດາດຄຳນວນ K
+Name[lt]=HTML eksporto filtras skirtas KSpread
+Name[lv]=HTML eksporta filtrs priekš KSpread
+Name[ms]=Penapis Eksport HTML bagi KSpread
+Name[mt]=Filtru għall-esportazzjoni ta' fajls HTML minn ġo KSpread
+Name[nb]=HTML-eksportfilter for KSpread
+Name[nds]=HTML-Exportfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि एचटीएमएल निर्यात फिल्टर
+Name[nl]=HTML-Exportfilter voor KSpread
+Name[nn]=HTML-eksportfilter for KSpread
+Name[pl]=Filtr eksportu do formatu HTML dla KSpread
+Name[pt]=Filtro de Exportação de HTML para o KSpread
+Name[pt_BR]=Filtro de Exportação HTML para o KSpread
+Name[ro]=Filtru exportare KSpread pentru HTML
+Name[ru]=Фильтр экспорта таблиц KSpread в HTML
+Name[se]=KSpread:a HTML-olggosfievrridansilli
+Name[sk]=HTML filter pre export z KSpread
+Name[sl]=Izvozni filter HTML za Kspread
+Name[sr]=KSpread-ов филтер за извоз у HTML
+Name[sr@Latn]=KSpread-ov filter za izvoz u HTML
+Name[sv]=HTML-exportfilter för Kspread
+Name[ta]=KSpread HTML ஏற்றுமதி வடிகட்டி
+Name[tg]=Филтри Содироти HTML барои KSpread
+Name[th]=ตัวกรองการส่งออก HTML ของกระดาษคำนวณ K
+Name[tr]=KSpread için HTML Aktarma Filtresi
+Name[uk]=Фільтр експорту HTML для KSpread
+Name[uz]=KSpread uchun HTML eksport filteri
+Name[uz@cyrillic]=KSpread учун HTML экспорт филтери
+Name[ven]=Filithara yau u bvisela nga nnda ya HTML ya u phadaladza ha K
+Name[wa]=Passete HTML di rexhowe po KSpread
+Name[xh]=HTML Yesihluzi Sokurhweba ngaphandle se KSpread
+Name[zh_CN]=KSpread 的 HTML 导出过滤器
+Name[zh_TW]=KSpread 的 HTML 匯出過濾程式
+Name[zu]=HTML IceboExport Filter for KSpread
+X-KDE-Export=text/html
+X-KDE-Import=application/x-kspread
+X-KDE-Weight=50
+X-KDE-Library=libkspreadhtmlexport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/html/status.html b/filters/kspread/html/status.html
new file mode 100644
index 000000000..a625bfd2f
--- /dev/null
+++ b/filters/kspread/html/status.html
@@ -0,0 +1,173 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>KOffice filters status: HTML FILTER</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<A NAME="START">&nbsp;</A>
+
+<BR>
+<center>
+ <h1>
+ KOffice filters status: &nbsp;&nbsp;<i>HTML - Hypertext Markup Language</i>
+ </h1>
+</center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%">
+
+<font size="-1"><b>
+ <A HREF="#import">Import</A> |
+ <A HREF="#export">Export</A>
+</b></font>
+
+<BR><BR><BR>
+<center><a NAME="import"></a></center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+
+ <tr BGCOLOR="#DDFFDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>
+ Import HTML for kspread<BR>
+ <BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>? </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>
+ ?
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td>?</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>?</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+<br><br><br>
+
+<hr NOSHADE SIZE=1>
+<br><br><br>
+
+
+<center>
+ <a NAME="export"></a>
+</center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+ <tr BGCOLOR="#FFDDDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>Export kspread to HTML<BR><BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>7 April 2005 by Bram Schoenmakers</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>
+ <ul>
+ <li> User can select which sheet(s) to export</li>
+ <li>Borders are optional</li>
+ <li>Cell spacing is configurable</li>
+ <li>Background color cells</li>
+ <li>Cell width/height</li>
+ <li>Option between all-in-one page or one sheet per page</li>
+ <li>User can select encoding</li>
+ </ul>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td> <ul>
+ <li>Text fonts</li>
+ <li>Row-/colspan cells</li>
+ </ul>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td>
+ <A HREF="mailto:eva@kde.org">Eva Brucherseifer</A>&nbsp;&nbsp;<br>
+ <A HREF="mailto:bramschoenmakers@kde.nl">Bram Schoenmakers</A><br>
+ This filter is based on the CSV filter by
+ <A HREF="mailto:faure@kde.org">David Faure</A> and
+ <A HREF="mailto:trobin@kde.org">Werner Trobin.</A>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>---</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+</body>
+</html>
diff --git a/filters/kspread/kexi/Makefile.am b/filters/kspread/kexi/Makefile.am
new file mode 100644
index 000000000..6f76a2969
--- /dev/null
+++ b/filters/kspread/kexi/Makefile.am
@@ -0,0 +1,22 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) -I$(top_srcdir)/kspread -I$(top_srcdir)/kexi $(KOFFICE_INCLUDES) \
+ $(KOTEXT_INCLUDES) $(all_includes)
+
+####### Files
+
+kde_module_LTLIBRARIES = libkspreadkexiimport.la
+
+libkspreadkexiimport_la_SOURCES = kspread_kexiimport.cc \
+ kspread_kexiimportdialogbase.ui \
+ kspread_kexiimportdialog.cc
+libkspreadkexiimport_la_LDFLAGS = -avoid-version -module -no-undefined \
+ $(all_libraries)
+libkspreadkexiimport_la_LIBADD = ../../../kexi/kexidb/libkexidb.la \
+ ../../../kexi/kexidb/parser/libkexidbparser.la \
+ ../../../kspread/libkspreadcommon.la
+
+METASOURCES = AUTO
+
+service_DATA = kspread_kexi_import.desktop
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/kexi/kspread_kexi_import.desktop b/filters/kspread/kexi/kspread_kexi_import.desktop
new file mode 100644
index 000000000..a18cc29da
--- /dev/null
+++ b/filters/kspread/kexi/kspread_kexi_import.desktop
@@ -0,0 +1,45 @@
+[Desktop Entry]
+Icon=
+Name=Kexi Import Filter for KSpread
+Name[bg]=Филтър за импортиране от Kexi в KSpread
+Name[ca]=Filtre d'importació de Kexi per a KSpread
+Name[da]=Kexi-importfilter for KSpread
+Name[de]=Kexi-Importfilter für KSpread
+Name[el]=Φίλτρο εισαγωγής Kexi για το KSpread
+Name[eo]=Kexi-importfiltrilo por KSpread
+Name[es]=Filtro de importación de Kexi para KSpread
+Name[et]=KSpreadi Kexi impordifilter
+Name[fa]=پالایۀ واردات Kexi برای KSpread
+Name[fr]=Filtre d'importation Kexi de KSpread
+Name[fy]=Kexi Ymportfilter foar KSpread
+Name[hr]=Kexi filtar uvoza za KSpread
+Name[hu]=Kexi importszűrő a KSpreadhez
+Name[it]=Filtro di importazione Kexi per KSpread
+Name[ja]=KSpread Kexi インポートフィルタ
+Name[km]=តម្រង​នាំចូល Kexi សម្រាប់ KSpread
+Name[lt]=Kexi importavimo filtras skirtas KSpread
+Name[lv]=Kexi importa filtrs priekš KSpread
+Name[nb]=Kexi-importfilter for KSpread
+Name[nds]=Kexi-Importfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि केक्सी आयात फिल्टर
+Name[nl]=Kexi-importfilter voor KSpread
+Name[pl]=Filtr importu formatu Kexi dla KSpread
+Name[pt]=Filtro de Importação do Kexi para o KSpread
+Name[pt_BR]=Filtro de importação do Kexi para o KSpread
+Name[ru]=Фильтр импорта файлов Kexi в KSpread
+Name[se]=KSpread Kexi-sisafievrridansilli
+Name[sk]=Kexi filter pre import do KSpread
+Name[sl]=Uvozni filter Kexi za KSpread
+Name[sr]=KSpread-ов филтер за увоз из Kexi-ја
+Name[sr@Latn]=KSpread-ov filter za uvoz iz Kexi-ja
+Name[sv]=Kexi-importfilter för Kspread
+Name[uk]=Фільтр імпорту Kexi для KSpread
+Name[uz]=KSpread uchun Kexi import filteri
+Name[uz@cyrillic]=KSpread учун Kexi импорт филтери
+Name[zh_TW]=Kexi 的 KSpread 匯入過濾程式
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Export=application/x-kspread
+X-KDE-Import=application/x-kexiproject-sqlite3
+X-KDE-Library=libkspreadkexiimport
+X-KDE-Weight=50
diff --git a/filters/kspread/kexi/kspread_kexiimport.cc b/filters/kspread/kexi/kspread_kexiimport.cc
new file mode 100644
index 000000000..11feea719
--- /dev/null
+++ b/filters/kspread/kexi/kspread_kexiimport.cc
@@ -0,0 +1,249 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Adam Pigg *
+ * adam@piggz.co.uk *
+ * *
+ * Based on insert calendar code: *
+ * Copyright (C) 2005 by Raphael Langerhorst *
+ * raphael-langerhorst@gmx.at *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining *
+ * a copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, sublicense, and/or sell copies of the Software, and to *
+ * permit persons to whom the Software is furnished to do so, subject to *
+ * the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be *
+ * included in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
+ * OTHER DEALINGS IN THE SOFTWARE. *
+ ***************************************************************************/
+
+#include "kspread_kexiimport.h"
+
+#include "kspread_kexiimportdialog.h"
+
+//KSpread Includes
+#include <kspread_view.h>
+#include <kspread_doc.h>
+//#include <selection.h>
+#include <kspread_sheet.h>
+#include <kspread_map.h>
+#include <kspread_style.h>
+
+//Koffice Includes
+#include <KoFilterChain.h>
+#include <KoFilterManager.h>
+#include <kofficeversion.h>
+
+//Kexi Includes
+#include <kexidb/cursor.h>
+#include <kexidb/connection.h>
+#include <kexidb/parser/parser.h>
+
+//KDE Includes
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <klistview.h>
+#include <qcolor.h>
+
+typedef KGenericFactory<KSpreadKexiImport, KoFilter> KSpreadKexiImportFactory;
+K_EXPORT_COMPONENT_FACTORY( libkspreadkexiimport, KSpreadKexiImportFactory( "kofficefilters" ) )
+
+
+//=============================================================================
+
+KSpreadKexiImport::KSpreadKexiImport(KoFilter *parent, const char *name, const QStringList&)
+{
+}
+
+//=============================================================================
+
+KSpreadKexiImport::~KSpreadKexiImport()
+{
+ delete m_dialog;
+}
+
+//=============================================================================
+
+KoFilter::ConversionStatus KSpreadKexiImport::convert( const QCString& from, const QCString& to )
+{
+ QPtrList<QListViewItem> objects;
+ QString file( m_chain->inputFile() );
+
+ //Create dialog
+ m_dialog = new KSpreadKexiImportDialog();
+
+ m_dialog->openDatabase( file, 0);
+ if (!m_dialog->exec())
+ {
+ return KoFilter::UserCancelled;
+ }
+
+ objects = m_dialog->selectedItems();
+
+ kdDebug() << "Getting Documents..." << endl;
+
+ KoDocument* document = m_chain->outputDocument();
+
+ if ( !document )
+ return KoFilter::StupidError;
+
+ kdDebug() << "here we go... " << document->className() << endl;
+
+ if ( !::qt_cast<const KSpread::Doc *>( document ) )
+ {
+ kdWarning() << "document isn't a KSpread::Doc but a " << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+ if(from!="application/x-kexiproject-sqlite3" || to!="application/x-kspread")
+ {
+ kdWarning() << "Invalid mimetypes " << from << " " << to << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ ksdoc = static_cast<KSpread::Doc *>( document ); // type checked above
+
+ if(ksdoc->mimeType()!="application/x-kspread")
+ {
+ kdWarning() << "Invalid document mimetype " << ksdoc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ document->emitBeginOperation();
+
+ QListViewItem *itm;
+ for(itm = objects.first(); itm ; itm = objects.next())
+ {
+ if (!insertObject(itm->text(1), itm->text(0)))
+ {
+ return KoFilter::StupidError;
+ }
+ }
+ if (m_dialog->customQuery())
+ {
+ if (!insertObject(m_dialog->customQueryString(), "Custom"))
+ {
+ return KoFilter::StupidError;
+ }
+ }
+
+ document->emitEndOperation();
+ kdDebug() << "inserting kexi data completed" << endl;
+ return KoFilter::OK;
+}
+
+bool KSpreadKexiImport::insertObject(const QString& object, const QString& type)
+{
+ QStringList fieldNames;
+ KSpread::Sheet *sheet;
+ KexiDB::Parser *parser;
+ KexiDB::QuerySchema *query;
+
+ sheet = ksdoc->map()->addNewSheet();
+ if (!sheet)
+ {
+ KMessageBox::error(NULL, i18n("Cant find sheet"), i18n("Error"));
+ return false;
+ }
+
+ if (type == "Custom")
+ {
+ sheet->setSheetName("Custom");
+ }
+ else
+ {
+ sheet->setSheetName(object);
+ }
+
+ //Get the field names
+ if (type == "Table")
+ {
+ fieldNames = m_dialog->connection()->tableSchema(object)->names();
+ }
+ else if (type == "Query")
+ {
+ //Note....for queries such as select * from....field names are not available
+ fieldNames = m_dialog->connection()->querySchema(object)->names();
+ }
+ else if (type == "Custom") //Custom Query
+ {
+ parser = new KexiDB::Parser(m_dialog->connection());
+ parser->parse( object );
+
+ if (parser->operation() != KexiDB::Parser::OP_Select)
+ {
+ KMessageBox::error(NULL, i18n("Your query was invalid or not a SELECT query"), i18n("Error"));
+ return false;
+ }
+ query = parser->query();
+ fieldNames = query->names();
+ }
+
+ //Insert the field headings
+ QStringList::iterator it;
+ int i = 1;
+ for (it = fieldNames.begin(); it != fieldNames.end(); ++it, ++i)
+ {
+ KSpread::Cell *c = sheet->nonDefaultCell(i ,1);
+ c->setCellText(*it, true);
+ c->format()->setBgColor(QColor(200,200,200));
+ c->format()->setTextFontBold(true);
+ }
+
+ //Insert the data
+ KexiDB::Cursor *cur;
+ if (type == "Table") //Table
+ {
+ cur = m_dialog->connection()->executeQuery( *(m_dialog->connection()->tableSchema(object)));
+ }
+ else if (type == "Query") //Query
+ {
+ cur = m_dialog->connection()->executeQuery( *(m_dialog->connection()->querySchema(object)));
+ }
+ else if (type == "Custom") //Custom Query
+ {
+ cur = m_dialog->connection()->executeQuery( *query );
+ }
+ else
+ {
+ cur = 0;
+ }
+
+ if (!cur)
+ {
+ KMessageBox::error(NULL, i18n("Error executing query"), i18n("Error"));
+ return false;
+ }
+
+ cur->moveFirst();
+ int j = cur->fieldCount();
+
+ unsigned int k = 2; //start on row 2
+ bool asText = false;
+
+ if(m_dialog->conversion() == 2)
+ asText = true;
+
+ while (!cur->eof())
+ {
+ for (i = 0; i < j; ++i)
+ {
+ sheet->nonDefaultCell(i+1 ,k)->setCellText(cur->value(i).toString(), asText);
+ }
+
+ kdDebug() << k << endl;
+ cur->moveNext();
+ ++k;
+ }
+ return true;
+}
+#include "kspread_kexiimport.moc"
diff --git a/filters/kspread/kexi/kspread_kexiimport.h b/filters/kspread/kexi/kspread_kexiimport.h
new file mode 100644
index 000000000..8c03473fc
--- /dev/null
+++ b/filters/kspread/kexi/kspread_kexiimport.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Adam Pigg *
+ * adam@piggz.co.uk *
+ * *
+ * Based on insert calendar code: *
+ * Copyright (C) 2005 by Raphael Langerhorst *
+ * raphael-langerhorst@gmx.at *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining *
+ * a copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, sublicense, and/or sell copies of the Software, and to *
+ * permit persons to whom the Software is furnished to do so, subject to *
+ * the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be *
+ * included in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
+ * OTHER DEALINGS IN THE SOFTWARE. *
+ ***************************************************************************/
+
+#ifndef KSPREAD_KEXIIMPORT_H
+#define KSPREAD_KEXIIMPORT_H
+
+#include <KoFilter.h>
+
+class KAboutData;
+
+namespace KexiDB
+{
+ class Connection;
+}
+
+namespace KSpread
+{
+ class Doc;
+}
+
+class KSpreadKexiImportDialog;
+
+/**
+ * \class PluginInsertKexi kspread_plugininsertkexi.h
+ * \brief Plugin for inserting a kexi table/query into a spreadsheet.
+ * @author Adam Pigg
+ *
+ * The plugin class for the Insert Kexi plugin.
+ * This plugin is designed to work in KSpread and
+ * makes it possible to insert kexi tables/queries into
+ * the spreadsheet.
+ */
+class KSpreadKexiImport : public KoFilter
+{
+ Q_OBJECT
+
+ protected:
+
+ KSpreadKexiImportDialog* m_dialog;
+
+ public:
+
+ /**
+ * Constructor. This constructor is usable with KGenericFactory.
+ */
+ KSpreadKexiImport(KoFilter *parent, const char *name, const QStringList&);
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~KSpreadKexiImport();
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+
+ private:
+ KSpread::Doc *ksdoc;
+ bool insertObject(const QString&,const QString&);
+};
+
+#endif
diff --git a/filters/kspread/kexi/kspread_kexiimportdialog.cc b/filters/kspread/kexi/kspread_kexiimportdialog.cc
new file mode 100644
index 000000000..1c2a912af
--- /dev/null
+++ b/filters/kspread/kexi/kspread_kexiimportdialog.cc
@@ -0,0 +1,236 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Adam Pigg *
+ * adam@piggz.co.uk *
+ * *
+ * Based on insert calendar code: *
+ * Copyright (C) 2005 by Raphael Langerhorst *
+ * raphael-langerhorst@gmx.at *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining *
+ * a copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, sublicense, and/or sell copies of the Software, and to *
+ * permit persons to whom the Software is furnished to do so, subject to *
+ * the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be *
+ * included in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
+ * OTHER DEALINGS IN THE SOFTWARE. *
+ ***************************************************************************/
+
+#include "kspread_kexiimportdialog.h"
+
+//KDE Includes
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kpushbutton.h>
+#include <klistview.h>
+#include <kcombobox.h>
+#include <qradiobutton.h>
+#include <qtextedit.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+//Kexi Includes
+#include <kexidb/global.h>
+#include <kexidb/kexidb_export.h>
+#include <kexidb/connectiondata.h>
+#include <kexidb/connection.h>
+#include <kexidb/drivermanager.h>
+#include <kexidb/driver.h>
+
+//KSpread includes
+#include <kspread_view.h>
+#include <kspread_doc.h>
+#include <kspread_map.h>
+
+/**
+ * Constructor
+ * @param parent Pointer to kspread view
+ * @param name Name of the dialog
+ * @return None
+ */
+ KSpreadKexiImportDialog::KSpreadKexiImportDialog(QWidget* parent, const char* name)
+ : KSpreadKexiImportDialogBase(parent,name)
+{
+ connect(this->m_insertButton,SIGNAL(clicked()),this,SLOT(accept()));
+ connect(this->m_cancelButton,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+/**
+ * Destructor
+ * @return None
+ */
+KSpreadKexiImportDialog::~KSpreadKexiImportDialog()
+{}
+
+/**
+ * Accepts the dialog and start the import process
+ */
+void KSpreadKexiImportDialog::accept()
+{
+ kdDebug() << "insert kexi data dialog accepted (insert button clicked)" << endl;
+ done(QDialog::Accepted);
+ emit insertKexi();
+}
+
+/**
+ * Cancels the dialog
+ */
+void KSpreadKexiImportDialog::reject()
+{
+ kdDebug() << "insert kexi data dialog rejected (cancel button clicked)" << endl;
+ done(QDialog::Rejected);
+}
+
+/**
+ * Opens a database given either a filename or connection data
+ * @param fileName name of file to open if cdata is null
+ * @param cdata connection data to server based database...not implemented though
+ */
+void KSpreadKexiImportDialog::openDatabase( QString fileName , KexiDB::ConnectionData *cdata)
+{
+ kdDebug() << "openDatabase" << endl;
+ KexiDB::Driver *dr;
+ KexiDB::DriverManager *dm;
+ KexiDB::ConnectionData cd;
+
+ //Open file db
+ dm = new KexiDB::DriverManager();
+ dr = dm->driver("sqlite3");
+ if (!dr)
+ {
+ kdDebug() << "Unable to create driver" << endl;
+ return;
+ }
+
+ if (cdata)
+ {
+ //Open server db
+ cd = *cdata;
+ }
+ else
+ {
+ if (!fileName.isEmpty())
+ {
+ cd.setFileName(fileName);
+ }
+ else
+ {
+ kdDebug() << "No file name" << endl;
+ KMessageBox::error(NULL, i18n("No file specified"), i18n("Error"));
+ return;
+ }
+ }
+
+ conn = dr->createConnection(cd);
+
+ if (!conn)
+ {
+ KMessageBox::error(NULL, i18n("Error creating connection"), i18n("Error"));
+ return;
+ }
+
+ if(!conn->connect())
+ {
+ KMessageBox::error(NULL, i18n("Error connecting to database"), i18n("Error"));
+ conn->debugError();
+ return;
+ }
+
+ if (!conn->useDatabase( fileName ))
+ {
+ KMessageBox::error(NULL, i18n("Error using database"), i18n("Error"));
+ conn->debugError();
+ return;
+ }
+
+ populateTables();
+
+}
+
+/**
+ * Gets all the tables and queries from the database
+ * and adds them to m_sourceList
+ */
+void KSpreadKexiImportDialog::populateTables()
+{
+ QValueList<int> tids;
+ QValueList<int> qids;
+
+ kdDebug() << "Getting Tables and Queries" << endl;
+ tids = conn->objectIds(KexiDB::TableObjectType);
+ qids = conn->objectIds(KexiDB::QueryObjectType);
+
+ kdDebug() << qids.count() << " queries " << tids.count() << " tables" << endl;
+
+ QValueList<int>::iterator it;
+
+ for ( it = tids.begin(); it != tids.end(); ++it )
+ {
+ (void) new KListViewItem(m_sourceList,"Table", conn->tableSchema(*it)->name());
+ kdDebug() << "Table ID:" << (*it) << " " << conn->tableSchema(*it)->name()<< endl;
+ }
+
+ for ( it = qids.begin(); it != qids.end(); ++it )
+ {
+ (void) new KListViewItem(m_sourceList,"Query", conn->querySchema(*it)->name());
+ kdDebug() << "Query ID:" << (*it) << " " << conn->querySchema(*it)->name() << endl;
+ }
+
+ //Select the first item
+ if(m_sourceList->firstChild())
+ {
+ m_sourceList->setSelected(m_sourceList->firstChild(), true);
+ }
+
+}
+
+/**
+ *
+ * @return the custom query that has been entered
+ */
+QString KSpreadKexiImportDialog::customQueryString()
+{
+ return m_CustomQueryText->text();
+}
+
+QPtrList<QListViewItem> KSpreadKexiImportDialog::selectedItems()
+{
+ QPtrList<QListViewItem> lst;
+ QListViewItemIterator it( m_sourceList );
+ while ( it.current() )
+ {
+ if ( it.current()->isSelected() )
+ lst.append( it.current() );
+ ++it;
+ }
+ return lst;
+}
+
+bool KSpreadKexiImportDialog::customQuery()
+{
+ return m_customQueryCheck->isChecked();
+}
+/**
+ * Returns the user specified option for data conversion
+ * @return integer stating the type of cenverion to make
+ */
+int KSpreadKexiImportDialog::conversion()
+{
+ if ( m_convKSRadio->isChecked())
+ return 1;
+ else if ( m_convTextRadio->isChecked())
+ return 2;
+ else
+ return -1;
+}
+
diff --git a/filters/kspread/kexi/kspread_kexiimportdialog.h b/filters/kspread/kexi/kspread_kexiimportdialog.h
new file mode 100644
index 000000000..12b7a740f
--- /dev/null
+++ b/filters/kspread/kexi/kspread_kexiimportdialog.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Adam Pigg *
+ * adam@piggz.co.uk *
+ * *
+ * Based on insert calendar code: *
+ * Copyright (C) 2005 by Raphael Langerhorst *
+ * raphael-langerhorst@gmx.at *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining *
+ * a copy of this software and associated documentation files (the *
+ * "Software"), to deal in the Software without restriction, including *
+ * without limitation the rights to use, copy, modify, merge, publish, *
+ * distribute, sublicense, and/or sell copies of the Software, and to *
+ * permit persons to whom the Software is furnished to do so, subject to *
+ * the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be *
+ * included in all copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
+ * OTHER DEALINGS IN THE SOFTWARE. *
+ ***************************************************************************/
+
+#ifndef KSPREAD_KEXIIMPORTDIALOG_H
+#define KSPREAD_KEXIIMPORTDIALOG_H
+
+#include "kspread_kexiimportdialogbase.h"
+#include <koffice_export.h>
+
+namespace KexiDB
+{
+class Connection;
+class ConnectionData;
+class DriverManager;
+class Driver;
+class TableOrQuerySchema;
+}
+
+namespace KSpread
+{
+class View;
+}
+
+class KListViewItem;
+
+class KSpreadKexiImportDialog : public KSpreadKexiImportDialogBase
+{
+ Q_OBJECT
+
+private:
+
+ void populateTables();
+ void populateSheets();
+ KexiDB::Connection *conn;
+ KexiDB::DriverManager *dm;
+
+ KSpread::View *m_kspreadView;
+public:
+
+ /**
+ * Constructor, initializes functionality.
+ * The dates in the dialog initialize to a complete calendar for the
+ * current month.
+ */
+ KSpreadKexiImportDialog(QWidget* parent = 0, const char* name = 0);
+
+ /**
+ * Virtual destructor.
+ */
+ virtual ~KSpreadKexiImportDialog();
+
+ void openDatabase(QString,KexiDB::ConnectionData *cdata);
+ KexiDB::Connection *connection()
+ {
+ return conn;
+ };
+
+ bool customQuery();
+ QString customQueryString();
+ int conversion(); //1: kspread 2: text ..... possibly add more option
+ QPtrList<QListViewItem> selectedItems();
+
+protected slots:
+
+ /**
+ * This slot is reimplemented from QDialog and
+ * is connected to the insert button.
+ * It also emits a insertCalendar signal.
+ *
+ * The dialog is closed (not deleted) when
+ * this slot is called.
+ *
+ * @see insertCalendar, reject, QDialog::done
+ */
+ virtual void accept();
+
+ /**
+ * This slot is reimplemented from QDialog and
+ * is connected to the cancel button.
+ *
+ * The dialog is closed (not deleted) when
+ * this slot is called.
+ *
+ * @see accept, QDialog::done
+ */
+ virtual void reject();
+
+signals:
+
+ /**
+ * This signal is emitted when the dialog is
+ * accepted - that is, when the Insert button
+ * is clicked.
+ * This signal is meant to tell the
+ * insert calendar plugin to actually insert
+ * the calendar with the selected dates.
+ */
+ void insertKexi();
+};
+
+
+#endif
diff --git a/filters/kspread/kexi/kspread_kexiimportdialogbase.ui b/filters/kspread/kexi/kspread_kexiimportdialogbase.ui
new file mode 100644
index 000000000..ad9756ef5
--- /dev/null
+++ b/filters/kspread/kexi/kspread_kexiimportdialogbase.ui
@@ -0,0 +1,244 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSpreadKexiImportDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>KSpreadKexiImportDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>598</width>
+ <height>491</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KSpread Kexi Import Filter</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The Insert Calendar dialog lets you set the dates of the calendar you want to insert. When you have choosen the desired dates, simply press the Insert button to insert the calendar into the spreadsheet, starting at the cell you have currently selected.</string>
+ <comment>This what's this help applies for the entire dialog.</comment>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSplitter">
+ <property name="name">
+ <cstring>splitter4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Table/Query</string>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Type</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_sourceList</cstring>
+ </property>
+ <property name="selectionMode" stdset="0">
+ <enum>Multi</enum>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_customQueryCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Custom quer&amp;y</string>
+ </property>
+ </widget>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>m_CustomQueryText</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Data Conversion</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>m_convGroup</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_convKSRadio</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Let KSpread choose</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>m_convTextRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Text (faster)</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>145</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_insertButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Open</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Insert the calendar at the currently selected cell.</string>
+ <comment>Tooltip for the insert button of the insert calendar plugin</comment>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>A new calendar will be inserted starting at the currently selected cell.</string>
+ <comment>What's this for the insert button of the insert calendar plugin</comment>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_cancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Don't insert a calendar.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Quits the dialog and does not insert a calendar. Use this to cancel this operation.</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klistview.h</includehint>
+</includehints>
+</UI>
diff --git a/filters/kspread/latex/BUGS b/filters/kspread/latex/BUGS
new file mode 100644
index 000000000..9febd4373
--- /dev/null
+++ b/filters/kspread/latex/BUGS
@@ -0,0 +1,16 @@
+Send bugs to Robert Jacolin <rjacolin@ifrance.com>. Thank you.
+
+EXPORT FILTER :
+
+ - problems with headers/footers
+
+ - problems with footnotes
+
+ - problems with table :
+
+ - problem with code :
+ o latex code are not very well indented.
+ o latex code generated in minipage from header contains empty line don't accepted by latex.
+
+IMPORT FILTER :
+
diff --git a/filters/kspread/latex/Makefile.am b/filters/kspread/latex/Makefile.am
new file mode 100644
index 000000000..63b64eaa7
--- /dev/null
+++ b/filters/kspread/latex/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = export
+
diff --git a/filters/kspread/latex/TODO b/filters/kspread/latex/TODO
new file mode 100644
index 000000000..db9bc6638
--- /dev/null
+++ b/filters/kspread/latex/TODO
@@ -0,0 +1,24 @@
+
+EXPORT FILTER :
+
+VERSION 1
+ - border DONE
+ - multirow DONE
+ - column color DONE
+ - row color
+ - nb col and row with column and row
+ - cell color DONE
+ - text font
+ - use params from the dialog
+ - inherit row and column
+ format for cell format. Make
+ a Format(Format, Format) constructor.
+VERSION 2
+ - formula
+ - column format
+ - row format
+
+IMPORT FILTER :
+ - lexical parser DONE
+ - syntax. parser DONE
+ - import filter in kspread
diff --git a/filters/kspread/latex/export/Changelog b/filters/kspread/latex/export/Changelog
new file mode 100644
index 000000000..cb512c3d0
--- /dev/null
+++ b/filters/kspread/latex/export/Changelog
@@ -0,0 +1,36 @@
+- 18 April 2003
+ o fix the dcop interface
+
+- 22 march 2003
+-features
+ o row color;
+ o text color.
+
+-bugs
+ o don't generate border if no style defined.
+
+-internal
+ o clean code;
+ o add comments;
+ o don't add the maindoc.xml at the end of tex file anymore.
+
+- 16 march 2003
+- features
+ o cell color
+ o support param from the dialog box : language, encoding, quality,
+ default font, document class, document type.
+ Document style, picture and contents tabs are not supported.
+
+- bugs
+ o bad format for column when no format exists;
+ o include package which are needed.
+
+- 02 march 2003
+- features
+ o column color.
+
+- bugs
+ o fix bug when a cell was not defined but needed.
+
+- 18 January 2003
+ Implements cell borders, multirow.
diff --git a/filters/kspread/latex/export/Makefile.am b/filters/kspread/latex/export/Makefile.am
new file mode 100644
index 000000000..a6bebb61f
--- /dev/null
+++ b/filters/kspread/latex/export/Makefile.am
@@ -0,0 +1,30 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) $(KOFFICE_INCLUDES) $(KFORMULA_INCLUDES) $(all_includes)
+libkspreadlatexexport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libkspreadlatexexport_la_LIBADD = $(KOFFICE_LIBS) $(LIB_KFORMULA)
+
+####### Files
+
+kde_module_LTLIBRARIES = libkspreadlatexexport.la
+
+libkspreadlatexexport_la_SOURCES = cell.cc column.cc config.cc document.cc fileheader.cc \
+ format.cc latexexportdia.ui kspreadlatexexportdiaImpl.cc \
+ latexexport.cc latexexportIface.cc latexexportIface.skel \
+ map.cc pen.cc row.cc spreadsheet.cc table.cc \
+ xmlparser.cc
+
+noinst_HEADERS = cell.h column.h config.h document.h fileheader.h format.h \
+ kspreadlatexexportdiaImpl.h latexexport.h latexexportIface.h \
+ map.h pen.h row.h spreadsheet.h table.h xmlparser.h
+
+######## Debug
+#check_PROGRAMS = texlauncher
+#texlauncher_SOURCES = texlauncher.cc
+#texlauncher_LDADD = liblatexexport.la
+#texlauncher_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+
+METASOURCES = AUTO
+
+service_DATA = kspread_latex_export.desktop
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/latex/export/cell.cc b/filters/kspread/latex/export/cell.cc
new file mode 100644
index 000000000..81e2e7fdb
--- /dev/null
+++ b/filters/kspread/latex/export/cell.cc
@@ -0,0 +1,132 @@
+/*
+** A program to convert the XML rendered by KSpread into LATEX.
+**
+** Copyright (C) 2002, 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <kdebug.h> /* for kdDebug stream */
+
+#include "cell.h"
+#include "table.h"
+#include "column.h"
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+Cell::Cell(): Format()
+{
+ setCol(0);
+ setRow(0);
+ setText("");
+ setTextDataType("none");
+ setResultDataType("none");
+}
+
+/*******************************************/
+/* Destructor */
+/*******************************************/
+Cell::~Cell()
+{
+}
+
+void Cell::analyse(const QDomNode balise)
+{
+ _row = getAttr(balise, "row").toLong();
+ _col = getAttr(balise, "column").toLong();
+ kdDebug(30522) << getRow() << "-" << getCol() << endl;
+ Format::analyse(getChild(balise, "format"));
+ analyseText(balise);
+}
+
+void Cell::analyseText(const QDomNode balise)
+{
+ setTextDataType( getAttr(getChild(balise, "text"), "dataType"));
+ setText(getData(balise, "text"));
+ kdDebug(30522) << "text(" << getTextDataType() << "): " << getText() << endl;
+}
+
+/*******************************************/
+/* generate */
+/*******************************************/
+void Cell::generate(QTextStream& out, Table* table)
+{
+ /*if(getMulticol() > 0)
+ out << "\\multicol{" << getMulticol() << "}{";
+ else*/ if (getMultirow() > 0)
+ out << "\\multirow{" << getMultirow() << "}{";
+ kdDebug(30522) << "Generate cell..." << endl;
+
+ out << "\\multicolumn{1}{";
+ Format::generate(out, table->searchColumn(_col));
+ out << "}{" << endl;
+
+ if(getTextDataType() == "Str")
+ {
+ generateTextFormat(out, getText());
+ //out << getText();
+ }
+
+ out << "}" << endl;
+
+ /*if(getColSpan() > 0)
+ out << "}" << endl;
+ else*/ if (getMultirow() > 0)
+ out << "}" << endl;
+
+ /*Element* elt = 0;
+ kdDebug(30522) << "GENERATION OF A TABLE " << count() << endl;
+ out << endl << "\\begin{tabular}";
+ generateCellHeader(out);
+ out << endl;
+ indent();
+
+ int row= 0;
+ while(row <= getMaxRow())
+ {
+ generateTopLineBorder(out, row);
+ for(int col= 0; col <= getMaxCol(); col++)
+ {
+ writeIndent(out);
+ */
+ /* Search the cell in the list */
+ /* elt = searchCell(row, col);
+
+ out << "\\multicolumn{1}{";
+ if(elt->hasLeftBorder())
+ out << "|";
+ out << "m{" << getCellSize(col) << "pt}";
+
+ if(elt->hasRightBorder())
+ out << "|";
+ out << "}{" << endl;
+
+ generateCell(out, row, col);
+ out << "}" << endl;
+ if(col < getMaxCol())
+ out << "&" << endl;
+ }
+ out << "\\\\" << endl;
+ writeIndent(out);
+ row = row + 1;
+ }
+ generateBottomLineBorder(out, row - 1);
+ out << "\\end{tabular}" << endl << endl;
+ desindent();*/
+ kdDebug(30522) << "END OF GENERATINO OF A CELL" << endl;
+}
+
diff --git a/filters/kspread/latex/export/cell.h b/filters/kspread/latex/export/cell.h
new file mode 100644
index 000000000..96482978b
--- /dev/null
+++ b/filters/kspread/latex/export/cell.h
@@ -0,0 +1,107 @@
+/*
+**
+** Copyright (C) 2002 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_CELL_H__
+#define __KSPREAD_LATEX_CELL_H__
+
+#include <qstring.h>
+
+#include "config.h"
+#include "format.h"
+#include "xmlparser.h"
+
+/***********************************************************************/
+/* Class: Cell */
+/***********************************************************************/
+
+class Table;
+class Column;
+
+/**
+ * This class hold a cell.
+ */
+class Cell: public Format
+{
+
+ /* USEFULL DATA */
+ long _row;
+ long _col;
+ QString _text;
+ QString _textDataType;
+ QString _result;
+ QString _resultDataType;
+
+
+ public:
+ /**
+ * Constructors
+ *
+ */
+
+ /**
+ * Creates a new instance of Cell.
+ */
+ Cell();
+
+ Cell(long row, long col)
+ {
+ _row = row;
+ _col = col;
+ }
+
+ /*
+ * Destructor
+ *
+ * The destructor must remove the list of frames.
+ */
+
+ virtual ~Cell();
+
+ /* ==== getters ==== */
+
+ long getRow() const { return _row; }
+ long getCol() const { return _col; }
+ QString getText() const { return _text; }
+ QString getTextDataType() const { return _textDataType; }
+ QString getResult() const { return _result; }
+ QString getResultDataType() const { return _resultDataType; }
+
+ /* ==== setters ==== */
+ void setRow(int r) { _row = r; }
+ void setCol(int c) { _col = c; }
+ void setText(QString text) { _text = text; }
+ void setTextDataType(QString dt) { _textDataType = dt; }
+ void setResult(QString result) { _result = result; }
+ void setResultDataType(QString dt) { _resultDataType = dt; }
+
+ /**
+ * Helpfull functions
+ */
+ void analyse (const QDomNode);
+ void analyseText (const QDomNode);
+ void analyseResult (const QDomNode);
+ void generate (QTextStream&, Table*);
+
+ private:
+
+};
+
+#endif /* __KSPREAD_LATEX_CELL_H__ */
+
diff --git a/filters/kspread/latex/export/column.cc b/filters/kspread/latex/export/column.cc
new file mode 100644
index 000000000..198f7595e
--- /dev/null
+++ b/filters/kspread/latex/export/column.cc
@@ -0,0 +1,66 @@
+/*
+** A program to convert the XML rendered by KSpread into LATEX.
+**
+** Copyright (C) 2002 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <kdebug.h> /* for kdDebug stream */
+
+#include "column.h"
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+Column::Column(): Format()
+{
+ setCol(0);
+}
+
+/*******************************************/
+/* Destructor */
+/*******************************************/
+Column::~Column()
+{
+}
+
+void Column::analyse(const QDomNode balise)
+{
+ _col = getAttr(balise, "column").toLong();
+ _width = getAttr(balise, "width").toDouble();
+ Format::analyse(getChild(balise, "format"));
+}
+
+/*******************************************/
+/* generate */
+/*******************************************/
+void Column::generate(QTextStream& out)
+{
+ //generateLeftBorder(out);
+ if(getBrushStyle() >= 1)
+ {
+ out << ">{\\columncolor";
+ generateColor(out);
+ out << "}";
+ }
+ //generateRightBorder(out);
+
+ out << "m{" << getWidth() << "pt}";
+
+}
+
+
diff --git a/filters/kspread/latex/export/column.h b/filters/kspread/latex/export/column.h
new file mode 100644
index 000000000..41b6386bc
--- /dev/null
+++ b/filters/kspread/latex/export/column.h
@@ -0,0 +1,87 @@
+/*
+**
+** Copyright (C) 2002 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_COLUMN_H__
+#define __KSPREAD_LATEX_COLUMN_H__
+
+#include <qstring.h>
+
+#include "config.h"
+#include "format.h"
+#include "xmlparser.h"
+
+/***********************************************************************/
+/* Class: Column */
+/***********************************************************************/
+
+/**
+ * This class hold a column.
+ */
+class Column: public Format
+{
+
+ /* USEFULL DATA */
+ long _col;
+ double _width;
+
+ public:
+ /**
+ * Constructors
+ *
+ */
+
+ /**
+ * Creates a new instance of Column.
+ */
+ Column();
+
+ /*
+ * Destructor
+ *
+ * The destructor must remove the list of frames.
+ */
+
+ virtual ~Column();
+
+ /**
+ * getters
+ */
+
+ long getCol() const { return _col; }
+ double getWidth() const { return _width; }
+
+ /**
+ * setters
+ */
+ void setCol(int c) { _col = c; }
+ void setWidth(double w) { _width = w; }
+
+ /**
+ * Helpfull functions
+ */
+ void analyse (const QDomNode);
+ void generate (QTextStream&);
+
+ private:
+
+};
+
+#endif /* __KSPREAD_LATEX_COLUMN_H__ */
+
diff --git a/filters/kspread/latex/export/config.cc b/filters/kspread/latex/export/config.cc
new file mode 100644
index 000000000..a79296caa
--- /dev/null
+++ b/filters/kspread/latex/export/config.cc
@@ -0,0 +1,92 @@
+/*
+** A program to convert the XML rendered by KWord into LATEX.
+**
+** Copyright (C) 2002-2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <kdebug.h> /* for kdDebug() stream */
+#include "config.h"
+
+/* Static variable */
+const char Config::SPACE_CHAR = ' ';
+Config* Config::_instance = 0;
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+Config::Config()
+{
+ _tabSize = 4;
+ _tabulation = 0;
+ _useLatexStyle = true;
+ _isEmbeded = false;
+ _convertPictures = false;
+}
+
+Config::Config(const Config &config)
+{
+ setTabSize(config.getTabSize());
+ setIndentation(config.getIndentation());
+ setClass(config.getClass());
+ setEmbeded(config.isEmbeded());
+
+ setEncoding(config.getEncoding());
+ if(config.isKwordStyleUsed()) useKwordStyle();
+}
+
+/*******************************************/
+/* Destructor */
+/*******************************************/
+Config::~Config()
+{
+}
+
+void Config::indent()
+{
+ kdDebug(30522) << "Indent tab = " << (_tabulation + getTabSize()) << endl;
+ _tabulation = _tabulation + getTabSize();
+}
+
+void Config::desindent()
+{
+ if ((_tabulation - getTabSize()) > 0)
+ {
+ kdDebug(30522) << "Desindent tab = " << (_tabulation - getTabSize()) << endl;
+ _tabulation = _tabulation - getTabSize();
+ }
+ else
+ {
+ kdDebug(30522) << "Desindent tab = 0" << endl;
+ _tabulation = 0;
+ }
+}
+
+void Config::writeIndent(QTextStream& out)
+{
+ for(int index = 0; index < _tabulation; index++)
+ {
+ out << " ";
+ }
+}
+
+Config* Config::instance()
+{
+ if(_instance == 0)
+ _instance = new Config();
+ return _instance;
+}
diff --git a/filters/kspread/latex/export/config.h b/filters/kspread/latex/export/config.h
new file mode 100644
index 000000000..05eba575e
--- /dev/null
+++ b/filters/kspread/latex/export/config.h
@@ -0,0 +1,147 @@
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2002 - 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __LATEX_CONFIG_H__
+#define __LATEX_CONFIG_H__
+
+#include <qtextstream.h>
+#include <qstringlist.h>
+
+/***********************************************************************/
+/* Class: Config */
+/***********************************************************************/
+
+/**
+ * This class hold all parameters and configuration from a file or from
+ * the filter configuration dialog box. it's a singleton, so you may use
+ * the instance() method to get this instance.
+ */
+class Config
+{
+ /* Document tab */
+ bool _useLatexStyle;
+ bool _isEmbeded;
+ QString _class;
+ QString _quality;
+ unsigned int _defaultFontSize;
+
+ /* Pictures tab */
+ bool _convertPictures;
+ QString _picturesDir;
+
+ /* Language tab */
+ //bool _useUnicode;
+ //bool _useLatin1;
+ QString _encoding;
+ QStringList _languagesList;
+ QString _defaultLanguage;
+
+ int _tabSize; /* Size of the para indentation. */
+ int _tabulation; /* Total size of the indentation. */
+
+ public:
+
+ static const char SPACE_CHAR;
+
+ static Config* instance(void);
+
+ Config(const Config&);
+
+ /*
+ * Destructor
+ */
+ virtual ~Config();
+
+ /* ==== Getters ==== */
+
+ /**
+ * Return the value of a tabulation.
+ */
+ bool isKwordStyleUsed() const { return (_useLatexStyle == false); }
+ bool isEmbeded() const { return _isEmbeded; }
+ QString getClass() const { return _class; }
+ QString getQuality() const { return _quality; }
+ unsigned int getDefaultFontSize() const { return _defaultFontSize; }
+
+ bool convertPictures() const { return _convertPictures; }
+ QString getPicturesDir() const { return _picturesDir; }
+
+ bool mustUseUnicode() const { return (_encoding == "unicode"); }
+ bool mustUseLatin1() const { return (_encoding != "unicode"); }
+ QString getEncoding() const { return _encoding; }
+ QStringList getLanguagesList() const { return _languagesList; }
+ QString getDefaultLanguage() const { return _defaultLanguage; }
+
+ int getTabSize() const { return _tabSize; }
+ int getIndentation() const { return _tabulation; }
+
+ /* ==== Setters ==== */
+
+ /**
+ * Initialise the tab size.
+ * @param size New size. Must be superior or eguals to 0.
+ */
+ void setTabSize(int size)
+ {
+ if(size >= 0)
+ _tabSize = size;
+ }
+
+ void useLatexStyle() { _useLatexStyle = true; }
+ void useKwordStyle() { _useLatexStyle = false; }
+ void setEmbeded(bool emb) { _isEmbeded = emb; }
+ /** The class can be article, book, letter, report or slides. It's the type of the
+ * latex document. */
+ void setClass(const QString &lclass) { _class = lclass; }
+ void setQuality(const QString &quality) { _quality = quality; }
+ void setDefaultFontSize(int size) { _defaultFontSize = size; }
+
+ void convertPictures(bool state) { _convertPictures = state; }
+ void setPicturesDir(const QString &dir) { _picturesDir = dir; }
+
+ void setEncoding(const QString &enc) { _encoding = enc; }
+ void addLanguage( const QString &l) { _languagesList.append(l); }
+ void setDefaultLanguage(const QString &l) { _defaultLanguage = l; }
+
+ void setIndentation(int indent) { _tabulation = indent; }
+
+ /* ==== Helpfull functions ==== */
+ void indent();
+ void desindent();
+
+ void writeIndent(QTextStream& out);
+
+ protected:
+ /**
+ * Constructors
+ *
+ * Creates a new instance of Config.
+ * Initialise param. at default value.
+ */
+ Config(); /* Ensure singleton */
+
+ static Config* _instance; /* Singleton */
+
+ private:
+
+};
+
+#endif /* __LATEX_CONFIG_H__ */
diff --git a/filters/kspread/latex/export/document.cc b/filters/kspread/latex/export/document.cc
new file mode 100644
index 000000000..a992af2ba
--- /dev/null
+++ b/filters/kspread/latex/export/document.cc
@@ -0,0 +1,66 @@
+/* TODO : Manage File problems !
+ */
+/*
+** A program to convert the XML rendered by KWord into LATEX.
+**
+** Copyright (C) 2000, 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <kdebug.h>
+
+#include "document.h"
+
+Document::Document(const KoStore* in, QString fileOut):
+ XmlParser(in), _file(fileOut), _in( in )
+{
+ //kdDebug(30522) << fileIn.latin1() << endl;
+ kdDebug(30522) << fileOut.latin1() << endl;
+ _filename = fileOut;
+ //setFileHeader(_fileHeader);
+ //setRoot(&_document);
+ Config::instance()->setEmbeded(false);
+ //analyse_config(config);
+}
+
+Document::~Document()
+{
+
+}
+
+void Document::analyse()
+{
+ QDomNode balise;
+ balise = init();
+ kdDebug(30522) << "ANALYSE A DOC" << endl;
+ _document.analyse(balise);
+ kdDebug(30522) << "END ANALYSE" << endl;
+}
+
+void Document::generate()
+{
+ if(_file.open(IO_WriteOnly))
+ {
+ kdDebug(30522) << "GENERATION" << endl;
+ _out.setDevice(&_file);
+ _document.generate(_out, !isEmbeded());
+ //_out << getDocument();
+ _file.close();
+ }
+ else
+ kdDebug(30522) << "Can't use the file ..." << endl;
+}
diff --git a/filters/kspread/latex/export/document.h b/filters/kspread/latex/export/document.h
new file mode 100644
index 000000000..cbe53087c
--- /dev/null
+++ b/filters/kspread/latex/export/document.h
@@ -0,0 +1,65 @@
+
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2000, 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_DOCUMENT_H__
+#define __KSPREAD_LATEX_DOCUMENT_H__
+
+#include <qfile.h> /* for QFile class */
+#include <qtextstream.h> /* for QTextStream class */
+#include <qstring.h> /* for QString class */
+
+#include "xmlparser.h"
+#include "config.h"
+#include "spreadsheet.h"
+
+class Document : public XmlParser, Config
+{
+ QFile _file;
+ QTextStream _out;
+ QString _filename;
+ const KoStore* _in;
+
+ //FileHeader _header;
+ Spreadsheet _document;
+
+ /* Options */
+
+
+ public:
+ /**
+ * @param in tar file.
+ * @param fileOut Output latex filename.
+ */
+ Document(const KoStore* in, QString fileOut);
+
+ virtual ~Document();
+
+ /* Accesors */
+
+ void analyse();
+ void generate();
+
+ private:
+
+};
+
+#endif /* __KSPREAD_LATEX_DOCUMENT_H__ */
diff --git a/filters/kspread/latex/export/fileheader.cc b/filters/kspread/latex/export/fileheader.cc
new file mode 100644
index 000000000..57d30fed6
--- /dev/null
+++ b/filters/kspread/latex/export/fileheader.cc
@@ -0,0 +1,320 @@
+/*
+** A program to convert the XML rendered by KWord into LATEX.
+**
+** Copyright (C) 2000, 2002, 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <stdlib.h>
+
+#include <kdebug.h>
+
+#include "fileheader.h"
+#include "config.h"
+
+FileHeader* FileHeader::_instance = 0;
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+FileHeader::FileHeader()
+{
+ _hasHeader = false;
+ _hasFooter = false;
+ _hasColor = false;
+ _hasUnderline = false;
+ _hasEnumerate = false;
+ _hasGraphics = false;
+ _hasTable = false;
+ _standardPage = 0;
+ _processing = TP_NORMAL;
+ //setFileHeader(this); /* for xmlParser class. */
+}
+
+/*******************************************/
+/* Destructor */
+/*******************************************/
+FileHeader::~FileHeader()
+{
+ kdDebug(30522) << "FileHeader Destructor" << endl;
+}
+
+/*******************************************/
+/* AnalysePaperParam */
+/*******************************************/
+void FileHeader::analysePaperParam(const QDomNode balise)
+{
+ setFormat(getAttr(balise, "format").toInt());
+ _width = getAttr(balise, "width").toInt();
+ _height = getAttr(balise, "height").toInt();
+ setOrientation(getAttr(balise, "orientation").toInt());
+ setColumns(getAttr(balise, "columns").toInt());
+ _columnSpacing = getAttr(balise, "columnspacing").toInt();
+ setHeadType(getAttr(balise, "hType").toInt());
+ setFootType(getAttr(balise, "fType").toInt());
+ _headBody = getAttr(balise, "spHeadBody").toInt();
+ _footBody = getAttr(balise, "spFootBody").toInt();
+ //getAttr(balise, "zoom").toInt();
+}
+
+/*******************************************/
+/* AnalysePaper */
+/*******************************************/
+void FileHeader::analysePaper(const QDomNode balise)
+{
+ analysePaperParam(balise);
+
+ //setTokenCurrent(balise_initiale->pContent);
+ // Analyse children markups --> PAPERBORDERS
+ QDomNode fils = getChild(balise, "PAPERSBORDERS");
+ _leftBorder = getAttr(fils, "left").toInt();
+ _rightBorder = getAttr(fils, "right").toInt();
+ _bottomBorder = getAttr(fils, "bottom").toInt();
+ _topBorder = getAttr(fils, "top").toInt();
+}
+
+/*******************************************/
+/* AnalyseAttributs */
+/*******************************************/
+void FileHeader::analyseAttributs(const QDomNode balise)
+{
+ setProcessing(getAttr(balise, "processing").toInt());
+ setStandardPge(getAttr(balise, "standardpage").toInt());
+ setTOC(getAttr(balise, "hasTOC").toInt());
+ _hasHeader = getAttr(balise, "hasHeader").toInt();
+ _hasFooter = getAttr(balise, "hasFooter").toInt();
+ setUnit(getAttr(balise, "unit").toInt());
+}
+
+/*******************************************/
+/* Generate */
+/*******************************************/
+void FileHeader::generate(QTextStream &out)
+{
+ kdDebug(30522) << "GENERATION OF THE FILE HEADER" << endl;
+ if(Config::instance()->mustUseLatin1())
+ generateLatinPreambule(out);
+ else if(Config::instance()->mustUseUnicode())
+ generateUnicodePreambule(out);
+
+ generatePackage(out);
+ if(getFormat() == TF_CUSTOM)
+ generatePaper(out);
+ out << "%%%%%%%%%%%%%%%%%% END OF PREAMBLE %%%%%%%%%%%%%%%%%%" << endl << endl;
+}
+
+/*******************************************/
+/* GeneratePaper */
+/*******************************************/
+void FileHeader::generatePaper(QTextStream &out)
+{
+ QString unit;
+
+ out << "% Format of paper" << endl;
+ kdDebug(30522) << "Generate custom size paper" << endl;
+ /* paper size */
+ out << "\\setlength{\\paperwidth}{" << _width << "pt}" << endl;
+ out << "\\setlength{\\paperheight}{" << _height << "pt}" << endl;
+ /* FileHeader and footer */
+ out << "\\setlength{\\headsep}{" << _headBody << "pt}" << endl;
+ out << "\\setlength{\\footskip}{" << _footBody + _bottomBorder << "pt}" << endl;
+ /* Margin */
+ out << "\\setlength{\\topmargin}{" << _topBorder << "pt}" << endl;
+ out << "\\setlength{\\textwidth}{" << _width - _rightBorder - _leftBorder << "pt}" << endl;
+ out << endl;
+}
+
+/*******************************************/
+/* GenerateLatinPreambule */
+/*******************************************/
+void FileHeader::generateLatinPreambule(QTextStream &out)
+{
+ out << "%% Generated by KSpread. Don't modify this file but the file *.ksp." << endl;
+ out << "%% Send an email to rjacolin@ifrance.com for bugs, wishes, .... Thank you." << endl;
+ out << "%% Compile this file with : latex filename.tex" << endl;
+ out << "%% a dvi file will be generated." << endl;
+ out << "%% The file uses the latex style (not the kword style). " << endl;
+ out << "\\documentclass[";
+ switch(getFormat())
+ {
+ case TF_A3:
+ out << "";
+ break;
+ case TF_A4:
+ out << "a4paper, ";
+ break;
+ case TF_A5:
+ out << "a5paper, ";
+ break;
+ case TF_USLETTER:
+ out << "letterpaper, ";
+ break;
+ case TF_USLEGAL:
+ out << "legalpaper, ";
+ break;
+ case TF_SCREEN:
+ out << "";
+ break;
+ case TF_CUSTOM:
+ out << "";
+ break;
+ case TF_B3:
+ out << "";
+ break;
+ case TF_USEXECUTIVE:
+ out << "executivepaper, ";
+ break;
+ }
+ if(getOrientation() == TO_LANDSCAPE)
+ out << "landscape, ";
+ /* To change : will use a special latexcommand to able to
+ * obtain more than one column :))
+ */
+ switch(getColumns())
+ {
+ case TC_1:
+ //out << "onecolumn, ";
+ break;
+ case TC_2:
+ out << "twocolumn, ";
+ break;
+ case TC_MORE:
+ out << "";
+ }
+
+ out << Config::instance()->getDefaultFontSize() << "pt";
+ if(Config::instance()->getQuality() == "draft")
+ out << ", draft";
+ out << "]{";
+ out << Config::instance()->getClass() << "}" << endl;
+ out << "\\usepackage[" << Config::instance()->getEncoding() << "]{inputenc}" << endl << endl;
+}
+
+/*******************************************/
+/* GenerateUnicodePreambule */
+/*******************************************/
+void FileHeader::generateUnicodePreambule(QTextStream &out)
+{
+ out << "%% Generated by KSpread. Don't modify this file but the file *.ksp." << endl;
+ out << "%% Send an email to rjacolin@ifrance.com for bugs, wishes, .... Thank you." << endl;
+ out << "%% Compile this file with : lambda filename.tex" << endl;
+ out << "%% a dvi file will be generated." << endl;
+ out << "%% Use odvips to convert it and to see it with gv" << endl;
+ out << "%% The file uses the latex style (not the kword style). " << endl;
+ out << "\\ocp\\TexUTF=inutf8" << endl;
+ out << "\\InputTranslation currentfile \\TexUTF" << endl;
+ out << "\\documentclass[";
+ switch(getFormat())
+ {
+ case TF_A3:
+ out << "";
+ break;
+ case TF_A4:
+ out << "a4paper, ";
+ break;
+ case TF_A5:
+ out << "a5paper, ";
+ break;
+ case TF_USLETTER:
+ out << "letterpaper, ";
+ break;
+ case TF_USLEGAL:
+ out << "legalpaper, ";
+ break;
+ case TF_SCREEN:
+ out << "";
+ break;
+ case TF_CUSTOM:
+ out << "";
+ break;
+ case TF_B3:
+ out << "";
+ break;
+ case TF_USEXECUTIVE:
+ out << "executivepaper, ";
+ break;
+ }
+ if(getOrientation() == TO_LANDSCAPE)
+ out << "landscape, ";
+ /* To change : will use a special latexcommand to able to
+ * obtain more than one column :))
+ */
+ switch(getColumns())
+ {
+ case TC_1:
+ //out << "onecolumn, ";
+ break;
+ case TC_2:
+ out << "twocolumn, ";
+ break;
+ case TC_MORE:
+ out << "";
+ }
+
+ out << Config::instance()->getDefaultFontSize() << "pt";
+ if(Config::instance()->getQuality() == "draft")
+ out << ", draft";
+ out << "]{";
+ out << Config::instance()->getClass() << "}" << endl;
+}
+
+
+/*******************************************/
+/* GeneratePackage */
+/*******************************************/
+void FileHeader::generatePackage(QTextStream &out)
+{
+ out << "% Package(s) to include" << endl;
+ if(Config::instance()->mustUseUnicode())
+ out << "\\usepackage{omega}" << endl;
+ if(getFormat() == TF_A4)
+ out << "\\usepackage[a4paper]{geometry}" << endl;
+ if(hasFooter() || hasHeader())
+ out << "\\usepackage{fancyhdr}" << endl;
+ if(hasColor())
+ out << "\\usepackage{colortbl}" << endl;
+ if(hasUnderline())
+ out << "\\usepackage{ulem}" << endl;
+ if(hasEnumerate())
+ out << "\\usepackage{enumerate}" << endl;
+ if(hasGraphics())
+ out << "\\usepackage{graphics}" << endl;
+ out << "\\usepackage{array}" << endl;
+ out << "\\usepackage{multirow}" << endl;
+ out << "\\usepackage{textcomp}" << endl;
+ out << "\\usepackage{rotating}" << endl;
+ out << endl;
+ QStringList langs = Config::instance()->getLanguagesList();
+ if(langs.count() > 0)
+ {
+ out << "\\usepackage[" << langs.join( ", " ) << "]{babel}" << endl;
+ }
+ out << "\\usepackage{textcomp}" << endl;
+ out << endl;
+
+ if(langs.count() > 1)
+ out <<"\\selectlanguage{" << Config::instance()->getDefaultLanguage()
+ << "}" << endl << endl;
+}
+
+FileHeader* FileHeader::instance()
+{
+ if(_instance == 0)
+ _instance = new FileHeader();
+ return _instance;
+}
+
diff --git a/filters/kspread/latex/export/fileheader.h b/filters/kspread/latex/export/fileheader.h
new file mode 100644
index 000000000..e5f5b51a8
--- /dev/null
+++ b/filters/kspread/latex/export/fileheader.h
@@ -0,0 +1,161 @@
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2000, 2002 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_FILEHEADER_H__
+#define __KSPREAD_LATEX_FILEHEADER_H__
+
+#include <qtextstream.h>
+
+#include "xmlparser.h"
+
+/***********************************************************************/
+/* Class: FileHeader */
+/***********************************************************************/
+
+/**
+ * This class hold all general information about the doc : does it use a color markup, ... ?
+ * paper size, ... and generate the information about the doc (packages and extensions
+ * to include, ...). It's the configuration latex file used to include the needed packages,
+ * define the paper format, ...
+ */
+class FileHeader: public XmlParser
+{
+ public:
+ enum TFormat { TF_A3, TF_A4, TF_A5, TF_USLETTER, TF_USLEGAL, TF_SCREEN,
+ TF_CUSTOM, TF_B3, TF_USEXECUTIVE };
+ enum TUnit { TU_MM, TU_CM, TU_PT, TU_INCH };
+ enum TOrient { TO_PORTRAIT, TO_LANDSCAPE };
+ enum TColonne { TC_NONE, TC_1, TC_2, TC_MORE };
+ enum THeadfoot { TH_ALL = 0, TH_XXX = 1, TH_FIRST = 2, TH_EVODD = 3 };
+ enum TProcType { TP_NORMAL, TP_DTP };
+
+ static FileHeader* instance(void);
+
+ private:
+ /* PAPER */
+ TFormat _format;
+ double _width,
+ _height;
+ TOrient _orientation;
+ TColonne _colonne;
+ double _columnSpacing;
+ THeadfoot _headType;
+ THeadfoot _footType;
+ TProcType _processing;
+ int _standardPage;
+ double _footBody;
+ double _headBody;
+
+ /* PAPERBORDERS */
+ double _leftBorder,
+ _rightBorder,
+ _bottomBorder,
+ _topBorder;
+
+ /* ATTRIBUTES */
+ TUnit _unite;
+ bool _hasHeader;
+ bool _hasFooter;
+ bool _hasTOC;
+
+ /* FOOTNOTEMGR */
+
+ /* DIVERSE */
+ /* for special packages to include */
+ bool _hasColor;
+ bool _hasUnderline;
+ bool _hasEnumerate;
+ bool _hasGraphics;
+ bool _hasTable;
+
+ public:
+
+ /**
+ * Destructor
+ */
+ virtual ~FileHeader();
+
+ /**
+ * Accessors
+ */
+ TFormat getFormat () const { return _format; }
+ TOrient getOrientation () const { return _orientation; }
+ TColonne getColumns () const { return _colonne; }
+ THeadfoot getHeadType () const { return _headType; }
+ THeadfoot getFootType () const { return _footType; }
+ TUnit getUnit () const { return _unite; }
+ TProcType getProcessing () const { return _processing; }
+ int getStandardPge () const { return _standardPage; }
+ bool hasHeader () const { return _hasHeader; }
+ bool hasFooter () const { return _hasFooter; }
+ bool hasTOC () const { return _hasTOC; }
+ bool hasColor () const { return _hasColor; }
+ bool hasUnderline () const { return _hasUnderline; }
+ bool hasEnumerate () const { return _hasEnumerate; }
+ bool hasGraphics () const { return _hasGraphics; }
+ bool hasTable () const { return _hasTable; }
+
+ /**
+ * Modifiors
+ */
+ void setFormat (TFormat f) { _format = f; }
+ void setFormat (int f) { _format = (TFormat) f; }
+ void setOrientation(TOrient o) { _orientation = o; }
+ void setOrientation(int o) { _orientation = (TOrient) o; }
+ void setColumns (TColonne c) { _colonne = c; }
+ void setColumns (int c) { _colonne = (TColonne) c; }
+ void setUnit (int u) { _unite = (TUnit) u; }
+ void setProcessing (int p) { _processing = (TProcType) p; }
+ void setStandardPge(int s) { _standardPage = s; }
+ void setTOC (int t) { _hasTOC = t; }
+ void setHeadType (int ht) { _headType = (THeadfoot) ht; }
+ void setFootType (int ft) { _footType = (THeadfoot) ft; }
+ void useColor () { _hasColor = true; }
+ void useUnderline () { _hasUnderline = true; }
+ void useEnumerate () { _hasEnumerate = true; }
+ void useGraphics () { _hasGraphics = true; }
+ void useTable () { _hasTable = true; }
+
+ void analysePaper (const QDomNode);
+ void analyseAttributs (const QDomNode);
+
+ void generate (QTextStream &);
+
+ protected:
+ /**
+ * Constructor
+ */
+ FileHeader(); /* Ensure singleton */
+
+ static FileHeader* _instance; /* singleton */
+
+ private:
+
+ void analysePaperParam(const QDomNode);
+
+ void generatePaper (QTextStream&);
+ void generateLatinPreambule(QTextStream&);
+ void generateUnicodePreambule(QTextStream&);
+ void generatePackage (QTextStream&);
+
+};
+
+#endif /* __KSPREAD_LATEX_FILEHEADER_H__ */
diff --git a/filters/kspread/latex/export/format.cc b/filters/kspread/latex/export/format.cc
new file mode 100644
index 000000000..473c63b47
--- /dev/null
+++ b/filters/kspread/latex/export/format.cc
@@ -0,0 +1,203 @@
+/*
+** A program to convert the XML rendered by KWord into LATEX.
+**
+** Copyright (C) 2002, 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <stdlib.h>
+
+#include <kdebug.h>
+
+#include "column.h"
+#include "fileheader.h" /* for the use of _header (color and underlined) */
+#include "format.h"
+#include "row.h"
+
+Format::Format()
+{
+ _multirow = -1;
+ _brushStyle = -1;
+ _isValidFormat = false;
+ _bottomBorder = NULL;
+ _topBorder = NULL;
+ _rightBorder = NULL;
+ _leftBorder = NULL;
+}
+
+Format::~Format()
+{
+ delete _bottomBorder;
+ delete _topBorder;
+ delete _leftBorder;
+ delete _rightBorder;
+}
+
+bool Format::hasTopBorder() const
+{
+ if(_topBorder == NULL)
+ return false;
+ else
+ return (_topBorder->getStyle() > 0);
+}
+
+bool Format::hasBottomBorder() const
+{
+ if(_bottomBorder == NULL)
+ return false;
+ else
+ return (_bottomBorder->getStyle() > 0);
+}
+
+bool Format::hasLeftBorder() const
+{
+ if(_leftBorder == NULL)
+ return false;
+ else
+ return (_leftBorder->getStyle() > 0);
+}
+
+bool Format::hasRightBorder() const
+{
+ if(_rightBorder == NULL)
+ return false;
+ else
+ return (_rightBorder->getStyle() > 0);
+}
+
+/* Get the set of info. about a text format */
+void Format::analyse(const QDomNode balise)
+{
+ /* <format brushstyle="5" brushcolor="#a70bc3" bgcolor="#ffffff" alignY="2" align="4" > */
+ if( !getAttr(balise, "brushstyle").isEmpty() )
+ {
+ _isValidFormat = true;
+ setBrushStyle(getAttr(balise, "brushstyle").toInt());
+ FileHeader::instance()->useColor();
+ setBrushColor(getAttr(balise, "brushcolor"));
+ setBgColor(getAttr(balise, "bgcolor"));
+ setAlignY(getAttr(balise, "alignY").toLong());
+ setAlign(getAttr(balise, "align").toLong());
+ }
+ if(isChild(balise, "pen"))
+ analysePen(getChild(balise, "pen"));
+ if(isChild(balise, "bottom-border"))
+ {
+ kdDebug(30522) << "bottom-border" << endl;
+ _isValidFormat = true;
+ _bottomBorder = new Pen();
+ _bottomBorder->analyse(getChild(getChild(balise, "bottom-border"), "pen"));
+ }
+ if(isChild(balise, "top-border"))
+ {
+ kdDebug(30522) << "top-border" << endl;
+ _isValidFormat = true;
+ _topBorder = new Pen();
+ _topBorder->analyse(getChild(getChild(balise, "top-border"), "pen"));
+ }
+ if(isChild(balise, "left-border"))
+ {
+ kdDebug(30522) << "left-border" << endl;
+ _isValidFormat = true;
+ _leftBorder = new Pen();
+ _leftBorder->analyse(getChild(getChild(balise, "left-border"), "pen"));
+ }
+ if(isChild(balise, "right-border"))
+ {
+ kdDebug(30522) << "right-border" << endl;
+ _isValidFormat = true;
+ _rightBorder = new Pen();
+ _rightBorder->analyse(getChild(getChild(balise, "right-border"), "pen"));
+ }
+}
+
+void Format::analysePen(const QDomNode balise)
+{
+ /* <pen width="0" style="1" color="#000000" /> */
+ _isValidFormat = true;
+ setPenWidth(getAttr(balise, "width").toDouble());
+ setPenStyle(getAttr(balise, "style").toInt());
+ setPenColor(getAttr(balise, "color"));
+}
+
+void Format::analyseFont(const QDomNode balise)
+{
+ /* <font size="18" family="Helvetica" weight="50" /> */
+ setFontSize(getAttr(balise, "size").toInt());
+ setFontFamily(getAttr(balise, "family"));
+ setFontWeight(getAttr(balise, "weight").toInt());
+}
+
+void Format::generate(QTextStream& out, Column* col, Row* row)
+{
+ if(hasLeftBorder())
+ out << "|";
+ if(isValidFormat() && getBrushStyle() >= 1)
+ {
+ out << ">{\\columncolor";
+ generateColor(out);
+ out << "}";
+ }
+ else if(col != NULL)
+ {
+ if(col->getBrushStyle() >= 1)
+ {
+ out << ">{\\columncolor";
+ col->generateColor(out);
+ out << "}";
+ }
+ }
+ else if(row != NULL)
+ {
+ if(row->getBrushStyle() >= 1)
+ {
+ out << ">{\\columncolor";
+ row->generateColor(out);
+ out << "}";
+ }
+ }
+ if ( col != NULL )
+ out << "m{" << col->getWidth() << "pt}";
+ if(hasRightBorder())
+ out << "|";
+}
+
+void Format::generateTextFormat(QTextStream& out, QString text)
+{
+ if(getPenStyle() > 0)
+ {
+ float red = ((float) getPenColor().red()) / 255;
+ float green = ((float) getPenColor().green()) / 255;
+ float blue = ((float) getPenColor().blue()) / 255;
+
+ out << "\\textcolor[rgb]{"<< red << ", " << green <<
+ ", " << blue << "}{" << text << "}" << endl;
+ }
+}
+
+void Format::generateColor(QTextStream& out)
+{
+ if(getBrushStyle() >= 1)
+ {
+ float red = ((float) getBrushColor().red()) / 255;
+ float green = ((float) getBrushColor().green()) / 255;
+ float blue = ((float) getBrushColor().blue()) / 255;
+
+ out << "[rgb]{" << red << ", " << green <<
+ ", " << blue << "}%" << endl;
+ }
+}
diff --git a/filters/kspread/latex/export/format.h b/filters/kspread/latex/export/format.h
new file mode 100644
index 000000000..5eb94eefc
--- /dev/null
+++ b/filters/kspread/latex/export/format.h
@@ -0,0 +1,186 @@
+
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2002 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_FORMAT_H__
+#define __KSPREAD_LATEX_FORMAT_H__
+
+#include <qtextstream.h>
+#include <qstring.h>
+#include <qcolor.h>
+#include "xmlparser.h"
+#include "pen.h"
+
+/***********************************************************************/
+/* Class: Format */
+/***********************************************************************/
+
+class Column;
+class Row;
+
+/**
+ * This class describe a cell, row or column format.
+ */
+class Format: public XmlParser
+{
+ long _align;
+ long _alignY;
+ QColor _bgColor;
+ long _multirow;
+ bool _verticalText;
+ double _angle;
+ QColor _brushColor;
+ int _brushStyle;
+ int _indent;
+ bool _dontprinttext;
+
+ /* pen */
+ double _penWidth;
+ int _penStyle;
+ QColor _penColor;
+
+ /* font */
+ int _size;
+ QString _family;
+ int _weight;
+
+ /* borders */
+ Pen *_bottomBorder;
+ Pen *_topBorder;
+ Pen *_leftBorder;
+ Pen *_rightBorder;
+
+ /* */
+ bool _isValidFormat;
+
+ public:
+ /**
+ * Constructors
+ *
+ * Creates a new instance of Format.
+ *
+ * @param Para the parent class of the format.
+ */
+ Format();
+
+ /*
+ * Destructor
+ *
+ * Nothing to do
+ */
+ virtual ~Format();
+
+ /**
+ * getters
+ */
+ long getMultirow() const { return _multirow; }
+ long getAlign() const { return _align; }
+ long getAlignY() const { return _alignY; }
+ QColor getBgColor() const { return _bgColor; }
+ bool getVerticalText() const { return _verticalText; }
+ double getAngle() const { return _angle; }
+ QColor getBrushColor() const { return _brushColor; }
+ int getBrushStyle() const { return _brushStyle; }
+ int getIndent() const { return _indent; }
+ bool getDontPrintText() const { return _dontprinttext; }
+
+ bool hasBorder() const { return (hasTopBorder() || hasBottomBorder() || hasLeftBorder() || hasRightBorder()); }
+ bool hasTopBorder() const;
+ //Pen* getTopBorder() const { return _topBorder; }
+ bool hasBottomBorder() const;
+ //Pen* getBottomBorder() const { return _bottomBorder; }
+ bool hasLeftBorder() const;
+ //Pen* getLeftBorder() const { return _leftBorder; }
+ bool hasRightBorder() const;
+ //Pen* getRightBorder() const { return _rightBorder; }
+
+ /* pen */
+ double getPenWidth() const { return _penWidth; }
+ int getPenStyle() const { return _penStyle; }
+ QColor getPenColor() const { return _penColor; }
+
+ /* font */
+ int getFontSize() const { return _size; }
+ QString getFontFamily() const { return _family; }
+ int getFontWeight() const { return _weight; }
+ bool isValidFormat() const { return _isValidFormat; }
+
+ /**
+ * setters
+ */
+ void setAlign(long a) { _align = a; }
+ void setAlignY(long a) { _alignY = a; }
+ void setBgColor(QColor b) { _bgColor = b; }
+ void setMultirow(long mr) { _multirow = mr; }
+ void setVerticalText(bool vt) { _verticalText = vt; }
+ void setAngle(double a) { _angle = a; }
+ void setBrushColor(QString bc) { _brushColor.setNamedColor(bc); }
+ void setBrushStyle(int bs) { _brushStyle = bs; }
+ void setIndent(int indent) { _indent = indent; }
+ void setDontPrintText(bool dpt) { _dontprinttext = dpt; }
+
+ /* pen */
+ void setPenWidth(double pw) { _penWidth = pw; }
+ void setPenStyle(int ps) { _penStyle = ps; }
+ void setPenColor(QString pc) { _penColor.setNamedColor(pc); }
+
+ /* font */
+ void setFontSize(int s) { _size = s; }
+ void setFontFamily(QString f) { _family = f; }
+ void setFontWeight(int w) { _weight = w; }
+
+ /**
+ * Helpfull functions
+ */
+
+ /**
+ * Get informations from a markup tree (only param of a format).
+ */
+ virtual void analyse(const QDomNode);
+ virtual void analysePen(const QDomNode);
+ virtual void analyseFont(const QDomNode);
+
+ /**
+ * Generate the cell format inherited from the row or the colum format or
+ * use its own format.
+ *
+ * @param out The output stream.
+ * @param col The column of this cell.
+ * @param row The row of this cell.
+ */
+ void generate(QTextStream& out, Column* col = NULL, Row* row = NULL);
+
+ /**
+ * Generate the text cell format (color and font).
+ */
+ void generateTextFormat(QTextStream& out, QString text);
+
+ /**
+ * Generate the color format for a column or a row.
+ *
+ * The command can be either columncolor or rowcolor.
+ *
+ * @param out The output stream
+ */
+ void generateColor(QTextStream& out);
+};
+
+#endif /* __KSPREAD_LATEX_FORMAT_H__ */
diff --git a/filters/kspread/latex/export/formula.cc b/filters/kspread/latex/export/formula.cc
new file mode 100644
index 000000000..15a0af93b
--- /dev/null
+++ b/filters/kspread/latex/export/formula.cc
@@ -0,0 +1,168 @@
+/*
+** A program to convert the XML rendered by KWord into LATEX.
+**
+** Copyright (C) 2000 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <stdlib.h> /* for atoi function */
+#include <kdebug.h> /* for kdDebug() stream */
+#include <qptrstack.h> /* for getFormula() */
+#include <qdom.h>
+#include "formula.h"
+#include <kapplication.h>
+
+#include <kformuladocument.h>
+#include <kformulamimesource.h>
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+Formula::Formula()
+{
+ _left = 0;
+ _right = 0;
+ _top = 0;
+ _bottom = 0;
+ _runaround = TA_NONE;
+ _runaroundGap = 0;
+ _autoCreate = TC_EXTEND;
+ _newFrameBehaviour = TF_RECONNECT;
+
+}
+
+/*******************************************/
+/* analyse */
+/*******************************************/
+void Formula::analyse(const QDomNode balise)
+{
+
+ /* MARKUP TYPE : FRAMESET INFO = TEXTE, ENTETE CONNUE */
+
+ /* Parameters Analyse */
+ Element::analyse(balise);
+
+ kdDebug(30522) << "FRAME ANALYSE (Formula)" << endl;
+
+ /* Chlidren markups Analyse */
+ for(int index= 0; index < getNbChild(balise); index++)
+ {
+ if(getChildName(balise, index).compare("FRAME")== 0)
+ {
+ analyseParamFrame(balise);
+ }
+ else if(getChildName(balise, index).compare("FORMULA")== 0)
+ {
+ getFormula(getChild(getChild(balise, "FORMULA"), "FORMULA"), 0);
+ kdDebug(30522) << _formula << endl;
+ }
+
+ }
+ kdDebug(30522) << "END OF A FRAME" << endl;
+}
+
+/*******************************************/
+/* getFormula */
+/*******************************************/
+/* Get back the xml markup tree. */
+/*******************************************/
+void Formula::getFormula(QDomNode p, int indent)
+{
+/* while( p.)
+ {*/
+ switch( p.nodeType() )
+ {
+ case QDomNode::TextNode:
+ _formula = _formula + QString(p.toText().data()) + " ";
+ break;
+ /* case TT_Space:
+ _formula = _formula + p->zText;
+ //printf("%*s\"%s\"\n", indent, "", p->zText);
+ break;
+ case TT_EOL:
+ _formula = _formula + "\n";
+ //printf("%*s\n", indent, "");
+ break;*/
+ case QDomNode::ElementNode:
+ _formula = _formula + "<" + p.nodeName();
+ QDomNamedNodeMap attr = p.attributes();
+ for(unsigned int index = 0; index < attr.length(); index++)
+ { // The attributes
+ _formula = _formula + " " + attr.item(index).nodeName();
+ _formula = _formula + "=\"" + attr.item(index).nodeValue() + "\"";
+ }
+ if(p.childNodes().length() == 0)
+ _formula = _formula + "/>\n";
+ else
+ {
+ _formula = _formula + ">\n";
+ QDomNodeList child = p.childNodes();
+ for(unsigned int index = 0; index < child.length(); index++)
+ {
+ getFormula(child.item(index), indent+3); // The child elements
+ }
+ _formula = _formula + "</" + p.nodeName() + ">\n";
+ }
+ break;
+ /*default:
+ kdError(30522) << "Can't happen" << endl;
+ break;*/
+ }
+ /* p = p.nextSibling();
+ }*/
+}
+
+/*******************************************/
+/* analyseParamFrame */
+/*******************************************/
+void Formula::analyseParamFrame(const QDomNode balise)
+{
+ /*<FRAME left="28" top="42" right="566" bottom="798" runaround="1" />*/
+
+ _left = getAttr(balise, "left").toInt();
+ _top = getAttr(balise, "top").toInt();
+ _right = getAttr(balise, "right").toInt();
+ _bottom = getAttr(balise, "bottom").toInt();
+ setRunAround(getAttr(balise, "runaround").toInt());
+ setAroundGap(getAttr(balise, "runaroundGap").toInt());
+ setAutoCreate(getAttr(balise, "autoCreateNewFrame").toInt());
+ setNewFrame(getAttr(balise, "newFrameBehaviour").toInt());
+ setSheetSide(getAttr(balise, "sheetside").toInt());
+}
+
+/*******************************************/
+/* generate */
+/*******************************************/
+void Formula::generate(QTextStream &out)
+{
+ kdDebug(30522) << "FORMULA GENERATION" << endl;
+ QDomDocument doc;
+ doc.setContent(_formula);
+
+ // a new KFormula::Document for every formula is not the best idea.
+ // better to have only one such beast for the whole document.
+ KFormula::Document formulaDoc( kapp->sessionConfig() );
+
+ KFormula::Container* formula = new KFormula::Container( &formulaDoc );
+ if ( !formula->load( doc ) ) {
+ kdError(30522) << "Failed." << endl;
+ }
+
+ out << "$" << formula->texString() << "$";
+ delete formula;
+}
+
diff --git a/filters/kspread/latex/export/formula.h b/filters/kspread/latex/export/formula.h
new file mode 100644
index 000000000..bc6dcfedf
--- /dev/null
+++ b/filters/kspread/latex/export/formula.h
@@ -0,0 +1,111 @@
+/* A TEXT IS A SET OF TITLES, A (SET OF) PARAGRAPHS OR LISTS */
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2000 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KWORD_LATEXFORMULA__
+#define __KWORD_LATEXFORMULA__
+
+#include "element.h"
+#include <qstring.h>
+#include <qtextstream.h>
+
+/***********************************************************************/
+/* Class: Formula */
+/***********************************************************************/
+
+/**
+ * This class hold a formula. The formula must be generated not for this
+ * filter but from the kformula lib. So I keep only a string of the formula.
+ */
+class Formula: public Element
+{
+ /* DATA MARKUP */
+ int _left,
+ _top,
+ _right,
+ _bottom;
+ TAround _runaround;
+ double _runaroundGap;
+ TCreate _autoCreate;
+ TNFrame _newFrameBehaviour;
+ TSide _sheetSide;
+
+ /* CHILDREN MARKUPS */
+ QString _formula;
+
+ public:
+ /**
+ * Constructors
+ *
+ * Creates a new instance of Formula.
+ */
+ Formula();
+
+ /*
+ * Destructor
+ *
+ * Nothing to do.
+ */
+ virtual ~Formula() {
+ kdDebug(30522) << "Destruction of a formula" << endl; }
+
+ /**
+ * Accessors
+ */
+ /*bool hasColor () const;
+ bool hasUline () const;*/
+ TAround getRunAround () const { return _runaround; }
+ double getAroundGap () const { return _runaroundGap; }
+ TCreate getAutoCreate () const { return _autoCreate; }
+ TNFrame getNewFrame () const { return _newFrameBehaviour; }
+ TSide getSheetSide () const { return _sheetSide; }
+
+ void getFormula(QDomNode, int);
+
+ /**
+ * Modifiers
+ */
+ void setRunAround (const int a) { _runaround = (TAround) a; }
+ void setAroundGap (const double r) { _runaroundGap = r; }
+ void setAutoCreate(const int a) { _autoCreate = (TCreate) a; }
+ void setNewFrame (const int n) { _newFrameBehaviour = (TNFrame) n; }
+ void setSheetSide (const int s) { _sheetSide = (TSide) s; }
+
+ /**
+ * Helpfull functions
+ */
+
+ /**
+ * Get informations from a markup tree and put the formula
+ * in a QString.
+ */
+ void analyse(const QDomNode);
+
+ /**
+ * Write the formula in a file.
+ */
+ void generate(QTextStream&);
+
+ private:
+ void analyseParamFrame(const QDomNode);
+};
+
+#endif /* __KWORD_LATEXFORMULA_H__ */
diff --git a/filters/kspread/latex/export/kspread_latex_export.desktop b/filters/kspread/latex/export/kspread_latex_export.desktop
new file mode 100644
index 000000000..b29da68ca
--- /dev/null
+++ b/filters/kspread/latex/export/kspread_latex_export.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+X-KDE-Export=text/x-tex
+ExportDescription=LATEX
+Icon=
+X-KDE-Import=application/x-kspread
+X-KDE-Weight=1
+ImportDescription=KSpread
+Name=KSpread LATEX Export Filter
+Name[ar]=مِرْشَح تصدير LATEX لدى KSpread
+Name[bg]=Филтър за експортиране от KSpread в LATEX
+Name[br]=Sil ezporzh LATEX evit KSpread
+Name[ca]=Filtre d'exportació LATEX per a KSpread
+Name[cs]=KSpread LaTeX exportní filtr
+Name[cy]=Hidlen Allforio LATEX KSpread
+Name[da]=KSpread LaTeX-eksportfilter
+Name[de]=KSpread LaTeX-Exportfilter
+Name[el]=Φίλτρο εξαγωγής LATEX του KSpread
+Name[eo]=KSpread LaTeX-eksportfiltrilo
+Name[es]=Filtro de exportación LATEX de KSpread
+Name[et]=KSpreadi LaTeX'i ekspordifilter
+Name[eu]=KSpread-en LaTeX esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات KSpread LATEX
+Name[fi]=KSpread LATEX-vientisuodin
+Name[fr]=Filtre d'exportation LaTeX de Kspread
+Name[fy]=KSpread LATEX Eksportfilter
+Name[ga]=Scagaire Easpórtála LaTeX le haghaidh KSpread
+Name[gl]=Filtro de Exportación de LATEX para KSpread
+Name[he]=מסנן ייצוא מ־KSpread ל־LATEX
+Name[hi]=के-स्प्रेड लेटेक्स निर्यात छननी
+Name[hr]=KSpread LaTeX filtar izvoza
+Name[hu]=KSpread LaTeX exportszűrő
+Name[is]=KSpread LATEX útflutningssía
+Name[it]=Filtro di esportazione LaTeX per KSpread
+Name[ja]=KSpread LATEX エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ LATEX សម្រាប់ KSpread
+Name[lt]=KSpread LATEX eksportavimo filtras
+Name[lv]=KSpread LATEX eksporta filtrs
+Name[ms]=Penapis Eksport KSpread LATEX
+Name[nb]=LaTeX-eksportfilter for KSpread
+Name[nds]=LaTeX-Exportfilter för KSpread
+Name[ne]=केडीई स्प्रिेड LATEX निर्यात फिल्टर
+Name[nl]=KSpread LATEX Exportfilter
+Name[nn]=LaTeX-eksportfilter for KSpread
+Name[pl]=Filtr eksportu do formatu LaTeX z KSpread
+Name[pt]=Filtro de Exportação de LATEX para o KSpread
+Name[pt_BR]=Filtro de exportação LATEX do KSpread
+Name[ru]=Фильтр экспорта таблиц KSpread в LaTeX
+Name[se]=KSpread:a LaTeX-olggosfievrridansilli
+Name[sk]=LATEX filter pre export z KSpread
+Name[sl]=Izvozni filter LaTeX za KSpread
+Name[sr]=KSpread-ов филтер за извоз у LaTeX
+Name[sr@Latn]=KSpread-ov filter za izvoz u LaTeX
+Name[sv]=Kspread Latex-exportfilter
+Name[ta]=Kspread latex ஏற்றுமதி வடிகட்டி
+Name[tg]=Филтри Содироти KSpread LATEX
+Name[tr]=KSpread LATEX Aktarma Filtresi
+Name[uk]=Фільтр експорту LATEX для KSpread
+Name[uz]=KSpread uchun LaTeX eksport filteri
+Name[uz@cyrillic]=KSpread учун LaTeX экспорт филтери
+Name[wa]=Passete LaTeX di rexhowe po KSpread
+Name[zh_CN]=KSpread LATEX 导出过滤器
+Name[zh_TW]=KSpread LATEX 匯出過濾程式
+ServiceTypes=KOfficeFilter
+Type=Service
+X-KDE-Library=libkspreadlatexexport
diff --git a/filters/kspread/latex/export/kspreadlatexexportdiaImpl.cc b/filters/kspread/latex/export/kspreadlatexexportdiaImpl.cc
new file mode 100644
index 000000000..050c86ba9
--- /dev/null
+++ b/filters/kspread/latex/export/kspreadlatexexportdiaImpl.cc
@@ -0,0 +1,246 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Robert JACOLIN <rjacolin@ifrance.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ This file use code from koTemplateOpenDia for the method chooseSlot.
+*/
+
+#include <kspreadlatexexportdiaImpl.h>
+
+#include <qdir.h>
+#include <qcombobox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qcheckbox.h>
+
+#include <kapplication.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <krecentdocument.h>
+#include <ktempfile.h>
+#include <kurlrequester.h>
+#include <kfiledialog.h>
+#include <kdebug.h>
+#include <KoFilterManager.h>
+#include <kcombobox.h>
+#include <knuminput.h>
+
+#include <dcopclient.h>
+
+#include "document.h"
+
+/*#ifdef __FreeBSD__
+#include <unistd.h>
+#endif*/
+
+/*
+ * Constructs a KSpreadLatexExportDiaImpl which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'.
+ *
+ * The dialog will by default be modeless, unless you set 'modal' to
+ * TRUE to construct a modal dialog.
+ */
+KSpreadLatexExportDiaImpl::KSpreadLatexExportDiaImpl(KoStore* in, QWidget* parent,
+ const char* name_, bool modal, WFlags fl )
+ : LatexExportDia( parent, name_, modal, fl ), _in( in )
+{
+ int i = 0;
+
+ kapp->restoreOverrideCursor();
+
+ /* Recent files */
+ _config = new KConfig("kspreadlatexexportdialog");
+ _config->setGroup( "KSpread latex export filter" );
+ QString value;
+ while(i < 10)
+ {
+ /*value = _config->readPathEntry( QString("Recent%1").arg(i) );
+ kdDebug(30522) << "recent : " << value << endl;
+ if(!value.isEmpty())
+ {
+ _recentList.append( value );
+ recentBox->insertItem(value);
+ }
+ else
+ i = 10;*/
+ i = i + 1;
+ }
+
+ _iface = new LatexExportIface(this);
+ if(!kapp->dcopClient()->isRegistered() )
+ {
+ kapp->dcopClient()->registerAs("FilterConfigDia");
+ kapp->dcopClient()->setDefaultObject(_iface->objId());
+ }
+
+ /* All these items inserted must not be translated so they are inserted here
+ * without i18n() method. */
+ /*qualityComboBox->insertItem("final");
+ qualityComboBox->insertItem("draft");*/
+
+ classComboBox->insertItem("article");
+ classComboBox->insertItem("book");
+ classComboBox->insertItem("letter");
+ classComboBox->insertItem("report");
+ classComboBox->insertItem("slides");
+
+ encodingComboBox->insertItem("unicode");
+ encodingComboBox->insertItem("ansinew");
+ encodingComboBox->insertItem("applemac");
+ encodingComboBox->insertItem("ascii");
+ encodingComboBox->insertItem("latin1");
+ encodingComboBox->insertItem("latin2");
+ encodingComboBox->insertItem("latin3");
+ encodingComboBox->insertItem("latin5");
+ encodingComboBox->insertItem("cp437");
+ encodingComboBox->insertItem("cp437de");
+ encodingComboBox->insertItem("cp850");
+ encodingComboBox->insertItem("cp852");
+ encodingComboBox->insertItem("cp865");
+ encodingComboBox->insertItem("cp1250");
+ encodingComboBox->insertItem("cp1252");
+ encodingComboBox->insertItem("decmulti");
+ encodingComboBox->insertItem("next");
+
+ languagesList->insertItem("american");
+ languagesList->insertItem("austrian");
+ languagesList->insertItem("bahasa");
+ languagesList->insertItem("brazil");
+ languagesList->insertItem("breton");
+ languagesList->insertItem("catalan");
+ languagesList->insertItem("croatian");
+ languagesList->insertItem("czech");
+ languagesList->insertItem("danish");
+ languagesList->insertItem("dutch");
+ languagesList->insertItem("english");
+ languagesList->insertItem("esperanto");
+ languagesList->insertItem("finnish");
+ languagesList->insertItem("francais");
+ languagesList->insertItem("french");
+ languagesList->insertItem("galician");
+ languagesList->insertItem("german");
+ languagesList->insertItem("germanb");
+ languagesList->insertItem("hungarian");
+ languagesList->insertItem("magyar");
+ languagesList->insertItem("italian");
+ languagesList->insertItem("norsk");
+ languagesList->insertItem("nynorsk");
+ languagesList->insertItem("polish");
+ languagesList->insertItem("portuges");
+ languagesList->insertItem("romanian");
+ languagesList->insertItem("russian");
+ languagesList->insertItem("spanish");
+ languagesList->insertItem("slovak" );
+ languagesList->insertItem("slovene");
+ languagesList->insertItem("swedish");
+ languagesList->insertItem("turkish");
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+KSpreadLatexExportDiaImpl::~KSpreadLatexExportDiaImpl()
+{
+ delete _config;
+}
+
+/**
+ * Called when thecancel button is clicked.
+ * Close the dialog box.
+ */
+void KSpreadLatexExportDiaImpl::reject()
+{
+ kdDebug(30522) << "Export cancelled" << endl;
+ QDialog::reject();
+}
+
+/**
+ * Called when the user clic on the ok button. The xslt sheet is put on the recent list which is
+ * saved, then export the document.
+ */
+void KSpreadLatexExportDiaImpl::accept()
+{
+ hide();
+ kdDebug(30522) << "KSPREAD LATEX EXPORT FILTER --> BEGIN" << endl;
+ Config* config = Config::instance();
+
+ /* Document tab */
+ if(embededButton == typeGroup->selected())
+ config->setEmbeded(true);
+ else
+ config->setEmbeded(false);
+ if(kwordStyleButton == styleGroup->selected())
+ config->useKwordStyle();
+ else
+ config-> useLatexStyle();
+ /* class names are not translated */
+ config->setClass(classComboBox->currentText());
+
+ if(qualityComboBox->currentItem() == 0)
+ config->setQuality("final");
+ else
+ config->setQuality("draft");
+ config->setDefaultFontSize(defaultFontSize->value());
+
+ /* Pictures tab */
+ if(pictureCheckBox->isChecked())
+ config->convertPictures();
+ config->setPicturesDir(pathPictures->url());
+
+ /* Language tab */
+ config->setEncoding(encodingComboBox->currentText());
+ for(unsigned int index = 0; index < langUsedList->count(); index++)
+ {
+ kdDebug(30522) << "lang. : " << langUsedList->item(index)->text() << endl;
+ config->addLanguage(langUsedList->item(index)->text());
+ }
+
+ /* The default language is the first language in the list */
+ if(langUsedList->item(0) != NULL)
+ config->setDefaultLanguage(langUsedList->item(0)->text());
+ if( !(langUsedList->currentText().isEmpty()) )
+ {
+ kdDebug(30522) << "default lang. : " << langUsedList->currentText() << endl;
+ config->setDefaultLanguage(langUsedList->currentText());
+ }
+
+ Document doc(_in, _fileOut);
+ kdDebug(30522) << "---------- analyse file -------------" << endl;
+ doc.analyse();
+ kdDebug(30522) << "---------- generate file -------------" << endl;
+ doc.generate();
+ kdDebug(30522) << "KSPREAD LATEX EXPORT FILTER --> END" << endl;
+}
+
+void KSpreadLatexExportDiaImpl::addLanguage()
+{
+ kdDebug(30522) << "add a new language supported" << languagesList->currentText() << endl;
+ QString text = languagesList->currentText();
+ languagesList->removeItem(languagesList->currentItem());
+ langUsedList->insertItem(text);
+}
+
+void KSpreadLatexExportDiaImpl::removeLanguage()
+{
+ kdDebug(30522) << "remove a lanugage" << langUsedList->currentText() << endl;
+ QString text = langUsedList->currentText();
+ langUsedList->removeItem(langUsedList->currentItem());
+ languagesList->insertItem(text);
+}
+
+#include <kspreadlatexexportdiaImpl.moc>
diff --git a/filters/kspread/latex/export/kspreadlatexexportdiaImpl.h b/filters/kspread/latex/export/kspreadlatexexportdiaImpl.h
new file mode 100644
index 000000000..4073c2ca3
--- /dev/null
+++ b/filters/kspread/latex/export/kspreadlatexexportdiaImpl.h
@@ -0,0 +1,56 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 Robert JACOLIN <rjacolin@ifrance.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KSPREADLATEXEXPORTDIA_H__
+#define __KSPREADLATEXEXPORTDIA_H__
+
+#include <latexexportdia.h>
+#include <qstringlist.h>
+#include <kurl.h>
+
+#include "latexexportIface.h"
+
+class KoStore;
+class KConfig;
+
+class KSpreadLatexExportDiaImpl : public LatexExportDia
+{
+ Q_OBJECT
+
+ private:
+ QString _fileOut;
+ KoStore* _in;
+ KConfig* _config;
+ LatexExportIface* _iface;
+
+ public:
+ KSpreadLatexExportDiaImpl( KoStore*, QWidget* parent = 0,
+ const char* name = 0, bool modal = FALSE, WFlags fl = 0 );
+ virtual ~KSpreadLatexExportDiaImpl();
+
+ void setOutputFile(QString file) { _fileOut = file; }
+
+ public slots:
+ virtual void reject();
+ virtual void accept();
+ virtual void addLanguage();
+ virtual void removeLanguage();
+};
+
+#endif /* __KSPREADLATEXEXPORTDIA_H__ */
diff --git a/filters/kspread/latex/export/latexexport.cc b/filters/kspread/latex/export/latexexport.cc
new file mode 100644
index 000000000..37fb56d91
--- /dev/null
+++ b/filters/kspread/latex/export/latexexport.cc
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <latexexport.h>
+#include <latexexport.moc>
+#include <kdebug.h>
+#include <KoFilterChain.h>
+#include <kgenericfactory.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <qtextcodec.h>
+#include "kspreadlatexexportdiaImpl.h"
+
+typedef KGenericFactory<LATEXExport, KoFilter> LATEXExportFactory;
+K_EXPORT_COMPONENT_FACTORY( libkspreadlatexexport, LATEXExportFactory( "kofficefilters" ) )
+
+
+LATEXExport::LATEXExport(KoFilter *, const char *, const QStringList&) :
+ KoFilter() {
+}
+
+KoFilter::ConversionStatus LATEXExport::convert( const QCString& from, const QCString& to )
+{
+ QString config;
+
+ if(to != "text/x-tex" || from != "application/x-kspread")
+ return KoFilter::NotImplemented;
+
+ KoStore* in = KoStore::createStore(m_chain->inputFile(), KoStore::Read);
+ if(!in || !in->open("root")) {
+ kdError(30503) << "Unable to open input file!" << endl;
+ delete in;
+ return KoFilter::FileNotFound;
+ }
+ kdDebug(30522) << "In the kspread latex export filter..." << endl;
+ /* input file Reading */
+ in->close();
+
+ KSpreadLatexExportDiaImpl* dialog = new KSpreadLatexExportDiaImpl(in);
+ dialog->setOutputFile(m_chain->outputFile());
+
+ dialog->exec();
+ delete dialog;
+ delete in;
+
+ return KoFilter::OK;
+}
diff --git a/filters/kspread/latex/export/latexexport.h b/filters/kspread/latex/export/latexexport.h
new file mode 100644
index 000000000..3b7430007
--- /dev/null
+++ b/filters/kspread/latex/export/latexexport.h
@@ -0,0 +1,43 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 Robert JACOLIN <rjacolin@ifrance.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __LATEXEXPORT_H__
+#define __LATEXEXPORT_H__
+
+#include <qstring.h>
+#include <qtextstream.h>
+#include <qfile.h>
+#include <qobject.h>
+
+#include <KoFilter.h>
+#include <KoStore.h>
+
+class LATEXExport : public KoFilter
+{
+
+ Q_OBJECT
+
+ public:
+ LATEXExport(KoFilter *parent, const char *name, const QStringList&);
+ virtual ~LATEXExport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+};
+
+#endif /* __LATEXExport_H__ */
diff --git a/filters/kspread/latex/export/latexexportIface.cc b/filters/kspread/latex/export/latexexportIface.cc
new file mode 100644
index 000000000..f99e6745b
--- /dev/null
+++ b/filters/kspread/latex/export/latexexportIface.cc
@@ -0,0 +1,45 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Robert JACOLIN <rjacolin@ifrance.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ This file use code from koTemplateOpenDia for the method chooseSlot.
+*/
+
+#include <latexexportIface.h>
+#include "kspreadlatexexportdiaImpl.h"
+
+/*
+ * Constructs a KWordLatexExportDia which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'.
+ *
+ * The dialog will by default be modeless, unless you set 'modal' to
+ * TRUE to construct a modal dialog.
+ */
+LatexExportIface::LatexExportIface(KSpreadLatexExportDiaImpl* dia)
+ : DCOPObject("FilterConfigDia")
+{
+ _dialog = dia;
+}
+
+LatexExportIface::~LatexExportIface()
+{
+}
+
+void LatexExportIface::useDefaultConfig()
+{
+ _dialog->accept();
+}
+
diff --git a/filters/kspread/latex/export/latexexportIface.h b/filters/kspread/latex/export/latexexportIface.h
new file mode 100644
index 000000000..1f656f060
--- /dev/null
+++ b/filters/kspread/latex/export/latexexportIface.h
@@ -0,0 +1,43 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Robert JACOLIN <rjacolin@ifrance.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __LATEXEXPORTIFACE_H__
+#define __LATEXEXPORTIFACE_H__
+
+#include <dcopobject.h>
+
+class KSpreadLatexExportDiaImpl;
+
+class LatexExportIface: public DCOPObject
+{
+ K_DCOP
+
+ public:
+ LatexExportIface(KSpreadLatexExportDiaImpl* dia);
+
+ ~LatexExportIface();
+
+ k_dcop:
+ void useDefaultConfig();
+
+ private:
+ KSpreadLatexExportDiaImpl* _dialog;
+};
+
+#endif /* __LATEXEXPORTIFACE_H__ */
diff --git a/filters/kspread/latex/export/latexexportdia.ui b/filters/kspread/latex/export/latexexportdia.ui
new file mode 100644
index 000000000..3e62df55e
--- /dev/null
+++ b/filters/kspread/latex/export/latexexportdia.ui
@@ -0,0 +1,674 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>LatexExportDia</class>
+<comment>This dialog box is used for all latex filter in koffice.</comment>
+<author>Robert Jacolin &lt;rjacolin@ifrance.com&gt;</author>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>LatexExportDia</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>471</width>
+ <height>364</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Latex Export Filter Configuration</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QTabWidget" row="0" column="1">
+ <property name="name">
+ <cstring>_tab</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget2</cstring>
+ </property>
+ <attribute name="title">
+ <string>Document</string>
+ </attribute>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>defaultFontSize</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>241</x>
+ <y>236</y>
+ <width>125</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="value">
+ <number>12</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>1000</number>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>styleGroup</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>13</x>
+ <y>9</y>
+ <width>378</width>
+ <height>73</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Document Style</string>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>kwordStyleButton</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>43</y>
+ <width>354</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>KWord style</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>latexStyleButton</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>11</x>
+ <y>20</y>
+ <width>354</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Latex style</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>typeGroup</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>12</x>
+ <y>86</y>
+ <width>378</width>
+ <height>75</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Document Type</string>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>fullDocButton</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>14</x>
+ <y>21</y>
+ <width>349</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Independent document</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>The document will be able to be compiled alone.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The document will be generated as a full latex document since all the include will be generated before the \begin[document} and \end{document} commands.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>embededButton</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>14</x>
+ <y>45</y>
+ <width>351</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Document to include</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Do not generate either the latex header or the document environment.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The document will be generated as a latex document which will have to be included in a main latex document. It will allow you to generate several little files for each chapter of your document.</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>38</x>
+ <y>174</y>
+ <width>187</width>
+ <height>18</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Document class:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>39</x>
+ <y>208</y>
+ <width>186</width>
+ <height>18</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Quality:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>defaultFontSizeTextZone</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>39</x>
+ <y>241</y>
+ <width>186</width>
+ <height>18</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Default font size:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>classComboBox</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>240</x>
+ <y>168</y>
+ <width>125</width>
+ <height>27</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="KComboBox">
+ <item>
+ <property name="text">
+ <string>Final</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Draft</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>qualityComboBox</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>241</x>
+ <y>201</y>
+ <width>125</width>
+ <height>28</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>Widget3</cstring>
+ </property>
+ <attribute name="title">
+ <string>Pictures</string>
+ </attribute>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>pathPictures</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>22</x>
+ <y>80</y>
+ <width>263</width>
+ <height>42</height>
+ </rect>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>This directory will contains the eps pictures of your document.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>pictureCheckBox</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>21</x>
+ <y>21</y>
+ <width>262</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Convert the pictures</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>24</x>
+ <y>58</y>
+ <width>255</width>
+ <height>18</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Pictures directory:</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Language</string>
+ </attribute>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>ButtonGroup3</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>18</x>
+ <y>17</y>
+ <width>359</width>
+ <height>73</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Encoding</string>
+ </property>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>encodingComboBox</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>25</x>
+ <y>31</y>
+ <width>157</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox4</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>19</x>
+ <y>102</y>
+ <width>359</width>
+ <height>150</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Language</string>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>rmLanguageBtn</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>147</x>
+ <y>83</y>
+ <width>92</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>addLanguageBtn</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>147</x>
+ <y>48</y>
+ <width>92</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ <widget class="KListBox">
+ <property name="name">
+ <cstring>langUsedList</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>246</x>
+ <y>30</y>
+ <width>96</width>
+ <height>101</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="KListBox">
+ <property name="name">
+ <cstring>languagesList</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>16</x>
+ <y>30</y>
+ <width>122</width>
+ <height>105</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ <widget class="QWidget">
+ <property name="name">
+ <cstring>tab</cstring>
+ </property>
+ <attribute name="title">
+ <string>Contents</string>
+ </attribute>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>exportAuthor</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>26</x>
+ <y>14</y>
+ <width>376</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Export informations about author</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>tableContents</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>26</x>
+ <y>49</y>
+ <width>377</width>
+ <height>39</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Add a table of content</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>note</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>91</y>
+ <width>272</width>
+ <height>103</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Notes</string>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>RadioButton7</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>16</x>
+ <y>19</y>
+ <width>251</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Don't export</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>RadioButton6</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>17</x>
+ <y>64</y>
+ <width>251</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Export notes in comments</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>RadioButton5</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>17</x>
+ <y>40</y>
+ <width>248</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Export notes in margin notes</string>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonHelp</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Help</string>
+ </property>
+ <property name="accel">
+ <string>F1</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>LatexExportDia</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>LatexExportDia</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>addLanguageBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>LatexExportDia</receiver>
+ <slot>addLanguage()</slot>
+ </connection>
+ <connection>
+ <sender>rmLanguageBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>LatexExportDia</receiver>
+ <slot>removeLanguage()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>addLanguage()</slot>
+ <slot>removeLanguage()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klistbox.h</includehint>
+ <includehint>klistbox.h</includehint>
+</includehints>
+</UI>
diff --git a/filters/kspread/latex/export/map.cc b/filters/kspread/latex/export/map.cc
new file mode 100644
index 000000000..d0252d858
--- /dev/null
+++ b/filters/kspread/latex/export/map.cc
@@ -0,0 +1,79 @@
+/*
+** A program to convert the XML rendered by KWord into LATEX.
+**
+** Copyright (C) 2000, 2001, 2002 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <stdlib.h> /* for atoi function */
+#include <kdebug.h> /* for kdDebug() stream */
+#include "map.h"
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+Map::Map()
+{
+}
+
+/*******************************************/
+/* Destructor */
+/*******************************************/
+Map::~Map()
+{
+ kdDebug(30522) << "Destruction of a map." << endl;
+}
+
+/*******************************************/
+/* Analyse */
+/*******************************************/
+void Map::analyse(const QDomNode balise)
+{
+ /* Analyse of the parameters */
+ kdDebug(30522) << "ANALYSE A MAP" << endl;
+
+ /* Analyse of the children markups */
+ for(int index = 0; index < getNbChild(balise); index++)
+ {
+ // Only tables
+ Table* table = new Table();
+ table->analyse(getChild(balise, index));
+ _tables.append(table);
+ }
+ kdDebug(30522) << "END OF MAP" << endl;
+}
+
+/*******************************************/
+/* Generate */
+/*******************************************/
+/* Generate each text zone with the parag. */
+/* markup. */
+/*******************************************/
+void Map::generate(QTextStream &out)
+{
+ Table *table = NULL;
+ kdDebug(30522) << " MAP GENERATION" << endl;
+ QPtrListIterator<Table> it(_tables);
+ while ( (table = it.current()) != 0 )
+ {
+ ++it;
+ table->generate(out);
+ }
+
+ kdDebug(30522) << "MAP GENERATED" << endl;
+}
+
diff --git a/filters/kspread/latex/export/map.h b/filters/kspread/latex/export/map.h
new file mode 100644
index 000000000..5f6a38c0a
--- /dev/null
+++ b/filters/kspread/latex/export/map.h
@@ -0,0 +1,90 @@
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2000 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_MAP_H__
+#define __KSPREAD_LATEX_MAP_H__
+
+#include <qstring.h>
+#include <qptrstack.h> /* historic list */
+#include <qptrlist.h> /* for list of format */
+
+#include "xmlparser.h"
+#include "config.h"
+#include "table.h"
+
+/***********************************************************************/
+/* Class: Map */
+/***********************************************************************/
+
+/**
+ * This class hold a real paragraph. It tells about the text in this
+ * paragraph, its format, etc. The complete text is a list of Map instances.
+ * A footnote is a list of paragraph instances (now but not in the "futur").
+ */
+class Map: public XmlParser, Config
+{
+ QPtrList<Table> _tables;
+
+ public:
+ /**
+ * Constructors
+ *
+ * Creates a new instance of Map.
+ *
+ * @param Texte the text this paragraph is belonging to.
+ */
+ Map();
+
+ /*
+ * Destructor
+ *
+ * The destructor must remove the list of little zones.
+ */
+ virtual ~Map();
+
+ /**
+ * Accessors
+ */
+
+ /**
+ * Modifiers
+ */
+
+ /**
+ * Helpfull functions
+ */
+
+ /**
+ * Get informations from a markup tree.
+ */
+ void analyse (const QDomNode);
+
+ /**
+ * Write the paragraph in a file.
+ */
+ void generate (QTextStream&);
+
+
+ private:
+
+};
+
+#endif /* __KSPREAD_LATEX_MAP_H__ */
diff --git a/filters/kspread/latex/export/pen.cc b/filters/kspread/latex/export/pen.cc
new file mode 100644
index 000000000..e005c31c3
--- /dev/null
+++ b/filters/kspread/latex/export/pen.cc
@@ -0,0 +1,45 @@
+/*
+** A program to convert the XML rendered by KSpread into LATEX.
+**
+** Copyright (C) 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <stdlib.h>
+
+#include <kdebug.h>
+
+//#include "fileheader.h" /* for the use of _header (color and underlined) */
+#include "pen.h"
+
+Pen::Pen()
+{
+}
+
+/* Get the set of info. about a text format */
+void Pen::analyse(const QDomNode balise)
+{
+ /* <pen width="0" style="1" color="#000000" /> */
+ setWidth(getAttr(balise, "width").toDouble());
+ setStyle(getAttr(balise, "style").toInt());
+ setColor(getAttr(balise, "color"));
+}
+
+void Pen::generate(QTextStream&)
+{
+
+}
diff --git a/filters/kspread/latex/export/pen.h b/filters/kspread/latex/export/pen.h
new file mode 100644
index 000000000..d1fa8de69
--- /dev/null
+++ b/filters/kspread/latex/export/pen.h
@@ -0,0 +1,86 @@
+
+/*
+** Header file for inclusion with kspread_xml2latex.c
+**
+** Copyright (C) 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_PEN_H__
+#define __KSPREAD_LATEX_PEN_H__
+
+#include <qtextstream.h>
+#include <qstring.h>
+#include <qcolor.h>
+#include "xmlparser.h"
+
+/***********************************************************************/
+/* Class: Pen */
+/***********************************************************************/
+
+/**
+ * This class describe a pen which is used to draw borders.
+ */
+class Pen: public XmlParser
+{
+ double _width;
+ int _style;
+ QColor _color;
+
+ public:
+ /**
+ * Constructors
+ *
+ * Creates a new instance of Format.
+ */
+ Pen();
+
+ /*
+ * Destructor
+ *
+ * Nothing to do
+ */
+ virtual ~Pen() {}
+
+ /**
+ * getters
+ */
+ double getWidth() const { return _width; }
+ int getStyle() const { return _style; }
+ QColor getColor() const { return _color; }
+
+ /**
+ * setters
+ */
+ void setWidth(double w) { _width = w; }
+ void setStyle(int s) { _style = s; }
+ void setColor(QString color) { _color.setNamedColor(color); }
+
+ /**
+ * Helpfull functions
+ */
+
+ /**
+ * Get informations from a markup tree (only param of a format).
+ */
+ virtual void analyse(const QDomNode);
+
+ virtual void generate(QTextStream&);
+
+};
+
+#endif /* __KSPREAD_LATEX_PEN_H__ */
diff --git a/filters/kspread/latex/export/row.cc b/filters/kspread/latex/export/row.cc
new file mode 100644
index 000000000..2ee05ac02
--- /dev/null
+++ b/filters/kspread/latex/export/row.cc
@@ -0,0 +1,65 @@
+/*
+** A program to convert the XML rendered by KSpread into LATEX.
+**
+** Copyright (C) 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <kdebug.h> /* for kdDebug stream */
+
+#include "row.h"
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+Row::Row(): Format()
+{
+ setRow(0);
+}
+
+/*******************************************/
+/* Destructor */
+/*******************************************/
+Row::~Row()
+{
+}
+
+void Row::analyse(const QDomNode balise)
+{
+ _row = getAttr(balise, "row").toLong();
+ _height = getAttr(balise, "height").toDouble();
+ Format::analyse(getChild(balise, "format"));
+}
+
+/*******************************************/
+/* generate */
+/*******************************************/
+void Row::generate(QTextStream& out)
+{
+ //generateTopBorder(out);
+ if(getBrushStyle() >= 1)
+ {
+ out << "\\rowcolor";
+ generateColor(out);
+ }
+ //generateBottomBorder(out);
+
+ //out << "m{" << getHeight() << "pt}";
+
+}
+
+
diff --git a/filters/kspread/latex/export/row.h b/filters/kspread/latex/export/row.h
new file mode 100644
index 000000000..1d6bf28e3
--- /dev/null
+++ b/filters/kspread/latex/export/row.h
@@ -0,0 +1,87 @@
+/*
+**
+** Copyright (C) 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_ROW_H__
+#define __KSPREAD_LATEX_ROW_H__
+
+#include <qstring.h>
+
+#include "config.h"
+#include "format.h"
+#include "xmlparser.h"
+
+/***********************************************************************/
+/* Class: Row */
+/***********************************************************************/
+
+/**
+ * This class hold a row.
+ */
+class Row: public Format
+{
+
+ /* USEFULL DATA */
+ long _row;
+ double _height;
+
+ public:
+ /**
+ * Constructors
+ *
+ */
+
+ /**
+ * Creates a new instance of Row.
+ */
+ Row();
+
+ /*
+ * Destructor
+ *
+ * The destructor must remove the list of frames.
+ */
+
+ virtual ~Row();
+
+ /**
+ * getters
+ */
+
+ long getRow() const { return _row; }
+ double getHeight() const { return _height; }
+
+ /**
+ * setters
+ */
+ void setRow(int r) { _row = r; }
+ void setHeight(double h) { _height = h; }
+
+ /**
+ * Helpfull functions
+ */
+ void analyse (const QDomNode);
+ void generate (QTextStream&);
+
+ private:
+
+};
+
+#endif /* __KSPREAD_LATEX_ROW_H__ */
+
diff --git a/filters/kspread/latex/export/spreadsheet.cc b/filters/kspread/latex/export/spreadsheet.cc
new file mode 100644
index 000000000..d40998fce
--- /dev/null
+++ b/filters/kspread/latex/export/spreadsheet.cc
@@ -0,0 +1,221 @@
+/*
+** A program to convert the XML rendered by KWord into LATEX.
+**
+** Copyright (C) 2000, 2001, 2002, 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <stdlib.h> /* for atoi function */
+
+#include <kdebug.h>
+
+#include "fileheader.h"
+//#include "paper.h"
+#include "spreadsheet.h"
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+Spreadsheet::Spreadsheet()
+{
+}
+
+/*******************************************/
+/* Destructor */
+/*******************************************/
+Spreadsheet::~Spreadsheet()
+{
+ kdDebug(30522) << "Corps Destructor" << endl;
+}
+
+/*******************************************/
+/* Analyse */
+/*******************************************/
+void Spreadsheet::analyse(const QDomNode balise)
+{
+ kdDebug(30522) << getChildName(balise, 0) << endl;
+ analyse_attr(balise);
+ //_paper.analyse(getChild(balise, "paper"));
+ _map.analyse(getChild(balise, "map"));
+ //_locale.analyse(getChild(balise, "locale"));
+ //_areaname.analyse(getChild(balise, "areaname"));
+
+ kdDebug(30522) << "SPREADSHEET END" << endl;
+}
+
+/*******************************************/
+/* AnalysePixmaps */
+/*******************************************/
+void Spreadsheet::analyse_attr(const QDomNode balise)
+{
+
+}
+
+/*******************************************/
+/* Generate */
+/*******************************************/
+void Spreadsheet::generate(QTextStream &out, bool hasPreambule)
+{
+ kdDebug(30522) << "DOC. GENERATION." << endl;
+
+ if(!Config::instance()->isEmbeded())
+ generatePreambule(out);
+ kdDebug(30522) << "preambule : " << hasPreambule << endl;
+
+ /* Body */
+ if(hasPreambule)
+ {
+ out << "\\begin{document}" << endl;
+ indent();
+ }
+
+ _map.generate(out);
+
+ if(hasPreambule)
+ out << "\\end{document}" << endl;
+ desindent();
+ if(getIndentation() != 0)
+ kdError(30522) << "Error : indent != 0 at the end ! " << endl;
+}
+
+/*******************************************/
+/* GeneratePreambule */
+/*******************************************/
+void Spreadsheet::generatePreambule(QTextStream &out)
+{
+ FileHeader::instance()->generate(out);
+ /* For each header */
+ //if(getFileHeader()->hasHeader())
+ //{
+ // kdDebug(30522) << "header : " << _headers.count() << endl;
+
+ /* default : no rule */
+ // out << "\\renewcommand{\\headrulewidth}{0pt}" << endl;
+ // for(header = _headers.first(); header != 0; header = _headers.next())
+ // {
+ // generateTypeHeader(out, header);
+ // }
+ //}
+
+ /* For each footer */
+ /*if(getFileHeader()->hasFooter())
+ {
+ kdDebug(30522) << "footer : " << _footers.count() << endl;
+*/
+ /* default : no rule */
+ /* out << "\\renewcommand{\\footrulewidth}{0pt}" << endl;
+ for(footer = _footers.first(); footer != 0; footer = _footers.next())
+ {
+ generateTypeFooter(out, footer);
+ }
+ }*/
+ /* Specify what header/footer style to use */
+ /*if(getFileHeader()->hasHeader() || getFileHeader()->hasFooter())
+ out << "\\pagestyle{fancy}" << endl;
+ else
+ {
+ out << "\\pagestyle{empty}" << endl;
+ }*/
+}
+
+/*******************************************/
+/* GenerateTypeHeader */
+/*******************************************/
+void Spreadsheet::generateTypeHeader(QTextStream &out)
+{
+ /*kdDebug(30522) << "generate header" << endl;
+ if((_fileHeader->getHeadType() == TH_ALL ||
+ _fileHeader->getHeadType() == TH_FIRST) && header->getInfo() == SI_EVEN)
+ {
+ out << "\\fancyhead[L]{}" << endl;
+ out << "\\fancyhead[C]{";
+ header->generate(out);
+ out << "}" << endl;
+ out << "\\fancyhead[R]{}" << endl;
+ }
+
+ switch(header->getInfo())
+ {
+ case SI_NONE:
+ case SI_FIRST:
+ break;
+ case SI_ODD:
+ out << "\\fancyhead[RO]{}" << endl;
+ out << "\\fancyhead[CO]{";
+ header->generate(out);
+ out << "}" << endl;
+ out << "\\fancyhead[LO]{}" << endl;
+ break;
+ case SI_EVEN:
+ out << "\\fancyhead[RE]{}" << endl;
+ out << "\\fancyhead[CE]{";
+ header->generate(out);
+ out << "}" << endl;
+ out << "\\fancyhead[LE]{}" << endl;
+ break;
+ }
+
+ if(header->getInfo() == SI_FIRST)
+ {
+ out << "\\fancyhead{";
+ header->generate(out);
+ out << "}" << endl;
+ out << "\\thispagestyle{fancy}" << endl;
+ }*/
+}
+
+/*******************************************/
+/* GenerateTypeFooter */
+/*******************************************/
+void Spreadsheet::generateTypeFooter(QTextStream &out)
+{
+ /*if(_fileHeader->getFootType() == TH_ALL && footer->getInfo() == SI_EVEN)
+ {
+ out << "\\fancyfoot[L]{}" << endl;
+ out << "\\fancyfoot[C]{";
+ footer->generate(out);
+ out << "}" << endl;
+ out << "\\fancyfoot[R]{}" << endl;
+ }
+ else if(_fileHeader->getFootType() == TH_EVODD)
+ {
+ switch(footer->getInfo())
+ {
+ case SI_NONE:
+ case SI_FIRST:
+ break;
+ case SI_ODD:
+ out << "\\fancyfoot[CO]{";
+ footer->generate(out);
+ out << "}";
+ break;
+ case SI_EVEN:
+ out << "\\fancyfoot[CE]{";
+ footer->generate(out);
+ out << "}";
+ break;
+ }
+ }
+ else if(_fileHeader->getFootType() == TH_FIRST && footer->getInfo() == SI_FIRST)
+ {
+ out << "\\fanycfoot{";
+ footer->generate(out);
+ out << "}" << endl;
+ out << "\\thispagestyle{fancy}" << endl;
+ }*/
+}
+
diff --git a/filters/kspread/latex/export/spreadsheet.h b/filters/kspread/latex/export/spreadsheet.h
new file mode 100644
index 000000000..1a8b8f62b
--- /dev/null
+++ b/filters/kspread/latex/export/spreadsheet.h
@@ -0,0 +1,95 @@
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2002, 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_SPREADSHEET_H__
+#define __KSPREAD_LATEX_SPREADSHEET_H__
+
+#include <qptrlist.h>
+#include <qtextstream.h>
+
+#include "map.h"
+#include "config.h"
+
+enum EGenerate
+{
+ E_LATEX,
+ E_KWORD,
+ E_CONFIG
+};
+
+/***********************************************************************/
+/* Class: Spreadsheet */
+/***********************************************************************/
+
+/**
+ * This class hold a whole document with its headers, footers, footnotes, endnotes,
+ * content, ... It can generate a latex file.
+ */
+class Spreadsheet: public XmlParser, Config
+{
+
+ //Paper _paper;
+ Map _map;
+ //Locale _locale;
+ //AreaName _areaname;
+
+ public:
+ /**
+ * Constructor
+ *
+ * Creates a new instance of Spreadsheet.
+ */
+ Spreadsheet();
+
+ /**
+ * Destructor
+ *
+ * Remove the list of headers, footers and the body.
+ */
+ virtual ~Spreadsheet();
+
+ /**
+ * Accessors
+ */
+
+ void analyse(const QDomNode);
+ void analyse_attr(const QDomNode);
+
+ void generate(QTextStream&, bool);
+
+ private:
+ /**
+ * Generate the second part of the preambule
+ */
+ void generatePreambule(QTextStream&);
+
+ /**
+ * Generate the header
+ */
+ void generateTypeHeader(QTextStream&);
+
+ /**
+ * Generate the footer
+ */
+ void generateTypeFooter(QTextStream&);
+};
+
+#endif /* __KSPREAD_LATEX_SPREADSHEET_H__ */
diff --git a/filters/kspread/latex/export/table.cc b/filters/kspread/latex/export/table.cc
new file mode 100644
index 000000000..e7bcc14b6
--- /dev/null
+++ b/filters/kspread/latex/export/table.cc
@@ -0,0 +1,414 @@
+/*
+** A program to convert the XML rendered by KWord into LATEX.
+**
+** Copyright (C) 2000 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <kdebug.h> /* for kdDebug stream */
+#include <qbitarray.h>
+#include "cell.h"
+#include "column.h"
+#include "row.h"
+#include "table.h"
+
+/*******************************************/
+/* Constructor */
+/*******************************************/
+Table::Table()
+{
+ _maxCol = 0;
+ _maxRow = 0;
+}
+
+/*******************************************/
+/* Destructor */
+/*******************************************/
+Table::~Table()
+{
+}
+
+void Table::setMaxColumn(int col)
+{
+ if(_maxCol < col) _maxCol = col;
+}
+
+void Table::setMaxRow(int row)
+{
+ if(_maxRow < row) _maxRow = row;
+}
+
+void Table::analyse(const QDomNode balise)
+{
+ kdDebug(30522) << "New table" << endl;
+ if(getAttr(balise, "columnnumber") == "1")
+ setColumnNumber();
+ if(getAttr(balise, "borders") == "1")
+ setBorders();
+ if(getAttr(balise, "hide") == "1")
+ setHide();
+ if(getAttr(balise, "hidezero") == "1")
+ setHideZero();
+ if(getAttr(balise, "firstletterupper") == "1")
+ setFirstletterupper();
+ if(getAttr(balise, "grid") == "1")
+ setGrid();
+ if(getAttr(balise, "printgrid") == "1")
+ setPrintGrid();
+ if(getAttr(balise, "printCommentIndicator") == "1")
+ setPrintCommentIndicator();
+ if(getAttr(balise, "printFormulaIndicator") == "1")
+ setPrintFormulaIndicator();
+ if(getAttr(balise, "showFormula") == "1")
+ setShowFormula();
+ if(getAttr(balise, "showFormulaIndicator") == "1")
+ setShowFormulaIndicator();
+ if(getAttr(balise, "lcmode") == "1")
+ setLCMode();
+ setName(getAttr(balise, "name"));
+
+ analysePaper(getChild(balise, "paper"));
+
+ int max = getNbChild(balise);
+ for(int index = 0; index < max; index++)
+ {
+ QString name = getChildName(balise, index);
+ if(name == "cell")
+ {
+ kdDebug(30522) << "----- cell -----" << endl;
+ Cell* cell = new Cell();
+ cell->analyse(getChild(balise, index));
+ _cells.append(cell);
+ setMaxColumn(cell->getCol());
+ setMaxRow(cell->getRow());
+ }
+ else if(name == "column")
+ {
+ kdDebug(30522) << "----- column -----" << endl;
+ Column* column = new Column();
+ column->analyse(getChild(balise, index));
+ _columns.append(column);
+ }
+ else if(name == "row")
+ {
+ kdDebug(30522) << "----- row -----" << endl;
+ Row* row = new Row();
+ row->analyse(getChild(balise, index));
+ _rows.append(row);
+ }
+ else
+ kdDebug(30522) << "name : " << name << endl;
+ }
+}
+
+void Table::analysePaper(const QDomNode balise)
+{
+ setFormat(getAttr(balise, "format"));
+ setOrientation(getAttr(balise, "orientation"));
+
+ /* borders */
+ QDomNode border = getChild(balise, "borders");
+ setBorderRight(getAttr(balise, "right").toLong());
+ setBorderLeft(getAttr(balise, "left").toLong());
+ setBorderBottom(getAttr(balise, "bottom").toLong());
+ setBorderTop(getAttr(balise, "top").toLong());
+}
+
+Cell* Table::searchCell(int col, int row)
+{
+ QPtrListIterator<Cell> it(_cells);
+
+ kdDebug(30522) << "search in list of " << _cells.count() << " cells" << endl;
+ Cell *cell = 0;
+ while ( (cell = it.current()) != 0 )
+ {
+ ++it;
+ kdDebug(30522) << "cell: " << cell->getRow() << "-" << cell->getCol() << endl;
+ if(cell->getCol() == col && cell->getRow() == row)
+ return cell;
+ }
+ return NULL;
+}
+
+Column* Table::searchColumn(int col)
+{
+ QPtrListIterator<Column> it(_columns);
+
+ Column *column;
+ while ( (column = it.current()) != 0 )
+ {
+ ++it;
+ if(column->getCol() == col)
+ return column;
+ }
+ return NULL;
+}
+
+Row* Table::searchRow(int rowNumber)
+{
+ QPtrListIterator<Row> it(_rows);
+
+ Row *row;
+ while ( (row = it.current()) != 0 )
+ {
+ ++it;
+ if(row->getRow() == rowNumber)
+ return row;
+ }
+ return NULL;
+}
+
+/*******************************************/
+/* generate */
+/*******************************************/
+void Table::generate(QTextStream& out)
+{
+ kdDebug(30522) << "GENERATION OF A TABLE " << getMaxRow() << " - " << getMaxColumn()
+ << endl;
+ out << endl << "%% " << getName() << endl;
+ if(getOrientation() == "Portrait")
+ {
+ out << "\\begin{sidewaystable}" << endl << endl;
+ indent();
+ writeIndent(out);
+ }
+
+ out << "\\begin{tabular}";
+ generateTableHeader(out);
+ out << endl;
+ indent();
+ int rowNumber = 1;
+ while(rowNumber <= getMaxRow())
+ {
+ generateTopLineBorder(out, rowNumber);
+ Row* row = searchRow(rowNumber);
+ if(row != NULL)
+ row->generate(out);
+
+ for(int col = 1; col <= getMaxColumn(); col++)
+ {
+ writeIndent(out);
+ generateCell(out, rowNumber, col);
+
+ if(col < getMaxColumn())
+ out << " & "<< endl;
+ }
+ out << "\\\\" << endl;
+ rowNumber++;
+ }
+ generateBottomLineBorder(out, rowNumber - 1);
+ desindent();
+ writeIndent(out);
+ out << "\\end{tabular}" << endl << endl;
+ desindent();
+
+ if(getOrientation() == "Portrait")
+ {
+ out << "\\end{sidewaystable}" << endl;
+ desindent();
+ }
+ /*Element* elt = 0;
+ kdDebug(30522) << "GENERATION OF A TABLE " << count() << endl;
+ out << endl << "\\begin{tabular}";
+ generateTableHeader(out);
+ out << endl;
+ indent();
+
+ int row= 0;
+ while(row <= getMaxRow())
+ {
+ generateTopLineBorder(out, row);
+ for(int col= 0; col <= getMaxCol(); col++)
+ {
+ writeIndent(out);
+ */
+ /* Search the cell in the list */
+ /* elt = searchCell(row, col);
+
+ out << "\\multicolumn{1}{";
+ if(elt->hasLeftBorder())
+ out << "|";
+ out << "m{" << getCellSize(col) << "pt}";
+
+ if(elt->hasRightBorder())
+ out << "|";
+ out << "}{" << endl;
+
+ generateCell(out, row, col);
+ out << "}" << endl;
+ if(col < getMaxCol())
+ out << "&" << endl;
+ }
+ out << "\\\\" << endl;
+ writeIndent(out);
+ row = row + 1;
+ }
+ generateBottomLineBorder(out, row - 1);
+ out << "\\end{tabular}" << endl << endl;
+ desindent();*/
+ kdDebug(30522) << "END OF GENERATINO OF A TABLE" << endl;
+}
+
+/*******************************************/
+/* generateTopLineBorder */
+/*******************************************/
+void Table::generateTopLineBorder(QTextStream& out, int row)
+{
+
+ Cell* cell = 0;
+ QBitArray border( getMaxColumn() );
+ bool fullLine = true;
+ for(int index = 1; index <= getMaxColumn(); index++)
+ {
+ /* Search the cell in the list */
+ kdDebug(30522) << "search " << row << ", " << index << endl;
+ cell = searchCell(index, row);
+
+ if(cell == NULL)
+ cell = new Cell(row, index);
+
+ /* If the element has a border display it here */
+ border[ index ] = cell->hasTopBorder();
+ if( ! cell->hasTopBorder() )
+ fullLine = false;
+ }
+
+ if(fullLine)
+ {
+ /* All column have a top border */
+ writeIndent(out);
+ out << "\\hline" << endl;
+ }
+ else
+ {
+ int index = 0;
+ while(index < getMaxColumn())
+ {
+ if(border[index])
+ {
+ int begin = index;
+ int end;
+ index = index + 1;
+ while(border[index] && index < getMaxColumn())
+ {
+ index = index + 1;
+ }
+ end = index - 1;
+ out << "\\cline{" << begin << "-" << end << "} " << endl;
+ }
+ index = index + 1;
+ }
+ }
+
+ /*Row * row;
+ row = searchRow(row);
+ if(row != NULL)
+ row->generate(out);*/
+}
+
+/*******************************************/
+/* generateBottomLineBorder */
+/*******************************************/
+void Table::generateBottomLineBorder(QTextStream& out, int row)
+{
+ Cell* cell = 0;
+ QBitArray border( getMaxColumn() );
+ bool fullLine = true;
+
+ for(int index = 1; index <= getMaxColumn(); index++)
+ {
+ /* Search the cell in the list */
+ cell = searchCell(index, row);
+
+ if(cell == NULL)
+ cell = new Cell(row, index);
+
+ /* If the element has a border display it here */
+ border[ index ] = cell->hasBottomBorder();
+ if( ! cell->hasBottomBorder() )
+ fullLine = false;
+ }
+
+ if(fullLine)
+ {
+ /* All column have a bottom border */
+ writeIndent(out);
+ out << "\\hline" << endl;
+ }
+ else
+ {
+ int index = 0;
+ while(index < getMaxColumn())
+ {
+ if(border[index])
+ {
+ int begin = index;
+ int end;
+ index = index + 1;
+ while(border[index] && index < getMaxColumn())
+ {
+ index = index + 1;
+ }
+ end = index - 1;
+ out << "\\cline{" << begin << "-" << end << "} " << endl;
+ }
+ index = index + 1;
+ }
+ }
+}
+
+/*******************************************/
+/* generateCell */
+/*******************************************/
+void Table::generateCell(QTextStream& out, int row, int col)
+{
+ kdDebug(30522) << "GENERATE CELL : " << row << "," << col << endl;
+
+ /* Search the cell in the list */
+ Cell *cell = searchCell(col, row);
+ if(cell != NULL)
+ {
+ kdDebug(30522) << "generate cell with text: " << cell->getText() << endl;
+ cell->generate(out, this);
+ }
+
+ kdDebug(30522) << "END OF A CELL" << endl;
+}
+
+/*******************************************/
+/* generateTableHeader */
+/*******************************************/
+void Table::generateTableHeader(QTextStream& out)
+{
+ Column* column = 0;
+
+ out << "{";
+
+ for(int col = 1; col <= getMaxColumn(); col++)
+ {
+ column = searchColumn(col);
+ if(column != NULL)
+ column->generate(out);
+ else
+ {
+ out << "m{20pt}";
+ }
+ }
+ out << "}";
+
+}
+
diff --git a/filters/kspread/latex/export/table.h b/filters/kspread/latex/export/table.h
new file mode 100644
index 000000000..3f1fa53ed
--- /dev/null
+++ b/filters/kspread/latex/export/table.h
@@ -0,0 +1,186 @@
+
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2002, 2003 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __KSPREAD_LATEX_TABLE_H__
+#define __KSPREAD_LATEX_TABLE_H__
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include "xmlparser.h"
+#include "config.h"
+//#include "cell.h"
+
+class Cell;
+class Column;
+class Row;
+
+/***********************************************************************/
+/* Class: Table */
+/***********************************************************************/
+
+/**
+ * This class hold a table. That is a table of frame (text frame, picture
+ * frame, ...). It use a special latex package.
+ * The color table and the border of the tables is not yet supported.
+ */
+class Table: public XmlParser, Config
+{
+ QPtrList<Row> _rows;
+ QPtrList<Column> _columns;
+ QPtrList<Cell> _cells;
+
+ /* USEFULL DATA */
+ int _maxRow, _maxCol; /* Size of the table (nb of cell) */
+ bool _columnNumber;
+ bool _borders;
+ bool _hide;
+ bool _hideZero;
+ bool _firstletterupper;
+ bool _grid;
+ bool _printGrid;
+ bool _printCommentIndicator;
+ bool _printFormulaIndicator;
+ bool _showFormula;
+ bool _showFormulaIndicator;
+ bool _lcMode;
+ QString _name;
+
+ /** PAPER DATA */
+ QString _format;
+ QString _orientation;
+ long _borderRight;
+ long _borderLeft;
+ long _borderBottom;
+ long _borderTop;
+
+ public:
+ /**
+ * Constructors
+ *
+ */
+
+ /**
+ * Creates a new instance of Table.
+ */
+ Table();
+
+ /*
+ * Destructor
+ *
+ * The destructor must remove the list of frames.
+ */
+
+ virtual ~Table();
+
+ /**
+ * getters
+ */
+
+ int getMaxRow() const { return _maxRow; }
+ int getMaxColumn() const { return _maxCol; }
+ QString getName() const { return _name; }
+ QString getFormat() const { return _format; }
+ QString getOrientation() const { return _orientation; }
+ long getBorderRight() const { return _borderRight; }
+ long getBorderLeft() const { return _borderLeft; }
+ long getBorderBottom() const { return _borderBottom; }
+ long getBorderTop() const { return _borderTop; }
+
+ bool isColumnNumber() const { return _columnNumber; }
+ bool isBorders() const { return _borders; }
+ bool isHide() const { return _hide; }
+ bool isHideZero() const { return _hideZero; }
+ bool isFirstletterupper() const { return _firstletterupper; }
+ bool isGrid() const { return _grid; }
+ bool isPrintGrid() const { return _printGrid; }
+ bool isPrintCommentIndicator() const { return _printCommentIndicator; }
+ bool isPrintFormulaIndicator() const { return _printFormulaIndicator; }
+ bool isShowFormula() const { return _showFormula; }
+ bool isShowFormulaIndicator() const { return _showFormulaIndicator; }
+ bool isLCMode() const { return _lcMode; }
+
+ /**
+ * setters
+ */
+ void setMaxRow(int r);
+ void setMaxColumn(int c);
+ void setName(QString name) { _name = name; }
+ void setFormat(QString format) { _format = format; }
+ void setOrientation(QString orient) { _orientation = orient; }
+ void setBorderRight(long br) { _borderRight = br; }
+ void setBorderLeft(long bl) { _borderLeft = bl; }
+ void setBorderBottom(long bb) { _borderBottom = bb; }
+ void setBorderTop(long bt) { _borderTop = bt; }
+
+ void setColumnNumber() { _columnNumber = true; }
+ void setBorders() { _borders = true; }
+ void setHide() { _hide = true; }
+ void setHideZero() { _hideZero = true; }
+ void setFirstletterupper() { _firstletterupper = true; }
+ void setGrid() { _grid = true; }
+ void setPrintGrid() { _printGrid = true; }
+ void setPrintCommentIndicator() { _printCommentIndicator = true; }
+ void setPrintFormulaIndicator() { _printFormulaIndicator = true; }
+ void setShowFormula() { _showFormula = true; }
+ void setShowFormulaIndicator() { _showFormulaIndicator = true; }
+ void setLCMode() { _lcMode = true; }
+
+ /**
+ * Helpfull functions
+ */
+
+ /**
+ * Return one specific cell.
+ *
+ * @param col Cell column.
+ * @param row Row cell.
+ */
+ Cell* searchCell(int col,int row);
+
+ /**
+ * Return one specific column which describe the format of the column.
+ *
+ * @param col the column.
+ */
+ Column* searchColumn(int col);
+
+ /**
+ * Return one specific row which describe the format of the row.
+ *
+ * @param row The row number.
+ */
+ Row* searchRow(int row);
+
+ void analyse (const QDomNode);
+ void analysePaper (const QDomNode);
+ void generate (QTextStream&);
+
+ private:
+ void generateCell(QTextStream&, int, int);
+ void generateTableHeader(QTextStream&);
+ void generateTopLineBorder(QTextStream&, int);
+ void generateBottomLineBorder(QTextStream&, int);
+};
+
+#endif /* __KSPREAD_LATEX_TABLE_H__ */
+
diff --git a/filters/kspread/latex/export/xmlparser.cc b/filters/kspread/latex/export/xmlparser.cc
new file mode 100644
index 000000000..e93160e6e
--- /dev/null
+++ b/filters/kspread/latex/export/xmlparser.cc
@@ -0,0 +1,139 @@
+/*
+** A program to convert the XML rendered by KOffice into LATEX.
+**
+** Copyright (C) 2000-2002 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#include <kdebug.h>
+#include <KoStore.h>
+
+#include "xmlparser.h"
+#include "qfile.h"
+
+/* Init static data */
+FileHeader* XmlParser::_fileHeader = 0;
+Document* XmlParser::_root = 0;
+KoStore* XmlParser::_in = NULL;
+
+XmlParser::XmlParser(QString filename): _filename(filename)
+{
+ QFile f(filename);
+ if(!f.open(IO_ReadOnly))
+ return;
+ if(!_document.setContent(&f))
+ {
+ f.close();
+ return;
+ }
+ f.close();
+ //_eltCurrent = _document.documentElement();
+}
+
+XmlParser::XmlParser(QByteArray in)
+{
+ _document.setContent(in);
+}
+
+XmlParser::XmlParser(const KoStore* in)
+{
+ _in = const_cast<KoStore*>(in);
+ if(!_in->open("root"))
+ {
+ kdError(30522) << "Unable to open input file!" << endl;
+ return;
+ }
+ /* input file Reading */
+ QByteArray array = _in->read(_in->size());
+ _document.setContent(array);
+}
+
+XmlParser::XmlParser()
+{
+}
+
+XmlParser::~XmlParser()
+{
+ if(_in != NULL)
+ _in->close();
+}
+
+QDomNode XmlParser::getChild(QDomNode balise, QString name)
+{
+ QDomNode node = getChild(balise, name, 0);
+ kdDebug(30522) << node.nodeName() << endl;
+ return node;
+}
+
+bool XmlParser::isChild(QDomNode balise, QString name)
+{
+ if(balise.isElement())
+ return balise.toElement().elementsByTagName(name).count();
+ return false;
+}
+
+QDomNode XmlParser::getChild(QDomNode balise, QString name, int index)
+{
+ if(balise.isElement()) {
+ QDomNodeList children = balise.toElement().elementsByTagName(name);
+ if ( children.count() )
+ return children.item(index);
+ }
+ return QDomNode();
+}
+
+QDomNode XmlParser::getChild(QDomNode balise, int index)
+{
+ QDomNodeList children = balise.childNodes();
+ if ( children.count() )
+ return children.item(index);
+ return QDomNode();
+}
+
+QString XmlParser::getData(QDomNode balise, int index)
+{
+ return getChild(getChild(balise, index), 0).nodeValue();
+}
+
+QString XmlParser::getData(QDomNode balise, QString name)
+{
+ return getChild(getChild(balise, name), 0).nodeValue();
+}
+
+int XmlParser::getNbChild(QDomNode balise)
+{
+ return balise.childNodes().count();
+}
+
+int XmlParser::getNbChild(QDomNode balise, QString name)
+{
+ if(balise.isElement())
+ return balise.toElement().elementsByTagName(name).count();
+ return -1;
+}
+
+QString XmlParser::getChildName(QDomNode balise, int index)
+{
+ return balise.childNodes().item(index).nodeName();
+}
+
+QString XmlParser::getAttr(QDomNode balise, QString name) const
+{
+ if(balise.isElement())
+ return balise.toElement().attributeNode(name).value();
+ return QString();
+}
diff --git a/filters/kspread/latex/export/xmlparser.h b/filters/kspread/latex/export/xmlparser.h
new file mode 100644
index 000000000..10e2609d9
--- /dev/null
+++ b/filters/kspread/latex/export/xmlparser.h
@@ -0,0 +1,79 @@
+
+/*
+** Header file for inclusion with kword_xml2latex.c
+**
+** Copyright (C) 2000-2002 Robert JACOLIN
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** To receive a copy of the GNU Library General Public License, write to the
+** Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+**
+*/
+
+#ifndef __LATEX_XMLPARSER_H__
+#define __LATEX_XMLPARSER_H__
+
+#include "qstring.h"
+#include "qdom.h"
+
+class FileHeader;
+class Document;
+class KoStore;
+
+class XmlParser
+{
+ /** Latex output file */
+ QString _filename;
+ /** The Koffice app document stored in a XML DOM Tree. */
+ QDomDocument _document;
+ /** The koffice document (maindoc, picture, ...). */
+ static KoStore* _in;
+
+ protected:
+ /* All the inherit class must be have a link with
+ * the header to specify to use special package
+ */
+ static FileHeader *_fileHeader;
+ static Document *_root;
+
+ public:
+ XmlParser(QString);
+ XmlParser(QByteArray); /* deprecated */
+ XmlParser(const KoStore*);
+ XmlParser();
+ virtual ~XmlParser();
+
+ QString getFilename () const { return _filename; }
+ QString getDocument () const { return _document.toString(); }
+ Document* getRoot () const { return _root; }
+ FileHeader* getFileHeader () const { return _fileHeader; }
+ QString getChildName(QDomNode, int);
+ QDomNode getChild(QDomNode, QString);
+ QDomNode getChild(QDomNode, QString, int);
+ QDomNode getChild(QDomNode, int);
+ QString getData(QDomNode, int);
+ QString getData(QDomNode, QString);
+ int getNbChild(QDomNode, QString);
+ int getNbChild(QDomNode);
+ QString getAttr(QDomNode, QString) const;
+ bool isChild(QDomNode, QString);
+
+ void setFileHeader(FileHeader* h) { _fileHeader = h; }
+ void setRoot (Document* r) { _root = r; }
+
+ QDomNode init() { return _document.documentElement(); }
+
+};
+
+#endif /* __LATEX_XMLPARSER_H__ */
+
diff --git a/filters/kspread/latex/status.html b/filters/kspread/latex/status.html
new file mode 100644
index 000000000..8dca195f4
--- /dev/null
+++ b/filters/kspread/latex/status.html
@@ -0,0 +1,188 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>KOffice filters status: LaTeX FILTER</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<A NAME="START">&nbsp;</A>
+
+<BR>
+<center>
+ <h1>
+ KOffice filters status: &nbsp;&nbsp;<i>LaTeX FILTER</i>
+ </h1>
+</center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%">
+
+<font size="-1"><b>
+ <A HREF="#import">Import</A> |
+ <A HREF="#export">Export</A>
+</b></font>
+
+<BR><BR><BR>
+<center><a NAME="import"></a></center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+
+ <tr BGCOLOR="#DDFFDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>
+ Import LaTeX for kspread<BR>
+ <BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>None</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>Everything</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors&nbsp;</font></b></td>
+ <td><a href="mailto:null@kde.org">-</a></td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td><a href="http://www.koffice.org">-</a></td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>---</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+<br><br><br>
+
+<hr NOSHADE SIZE=1>
+<br><br><br>
+
+
+<center>
+ <a NAME="export"></a>
+</center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+ <tr BGCOLOR="#FFDDDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>Export kspread to LaTeX <BR><BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>03 November 2002</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+
+ <td>
+ <ul>
+ <li>22 March 2003
+ <ul>
+ <li>Support row color</li>
+ <li>Support text color</li>
+ </ul>
+ </li>
+
+ <li>16 March 2003
+ <ul>
+ <li>Support cell color</li>
+ <li>Support param from the dialog box.</li>
+ </ul>
+ </li>
+
+ <li>02 March 2003
+ <ul>
+ <li>Support column color</li>
+ </ul>
+ </li>
+ <li>18 January 2003: first version (doesn't work)
+ <ul>
+ <li>Generate cell border, multirow</li>
+ </ul>
+ </li>
+ </ul>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td><a href="mailto:rjacolin@ifrance.com">Robert JACOLIN</a></td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td><a href="http://elbobby.free.fr/kspread/index.html">Des copies d'crans (commentaires en franais)</a><br>
+ <a href="http://elbobby.free.fr/kspread/index-en.html">Some Screenshots (comments in poor english)</a>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>
+
+ </td>
+ </tr>
+
+
+
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+</body>
+</html>
diff --git a/filters/kspread/libkspreadexport/KSpreadBaseWorker.cc b/filters/kspread/libkspreadexport/KSpreadBaseWorker.cc
new file mode 100644
index 000000000..cc7b2b462
--- /dev/null
+++ b/filters/kspread/libkspreadexport/KSpreadBaseWorker.cc
@@ -0,0 +1,94 @@
+/*
+This file is part of the KDE project
+Copyright (C) 2002 Fred Malabre <fmalabre@yahoo.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "KSpreadBaseWorker.h"
+
+#include <kdebug.h>
+
+
+KSpreadBaseWorker::KSpreadBaseWorker() {
+}
+
+
+KSpreadBaseWorker::~KSpreadBaseWorker() {
+}
+
+
+KoFilter::ConversionStatus KSpreadBaseWorker::startDocument(KSpreadFilterProperty property) {
+ KSpreadFilterProperty::Iterator it;
+ for (it = property.begin(); it != property.end(); ++it) {
+ kdDebug(30508) << "startDocument: " << it.key() << "->" << it.data() << endl;
+ }
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus KSpreadBaseWorker::startInfoLog(KSpreadFilterProperty property) {
+ KSpreadFilterProperty::Iterator it;
+ for (it = property.begin(); it != property.end(); ++it) {
+ kdDebug(30508) << "startInfoLog: " << it.key() << "->" << it.data() << endl;
+ }
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus KSpreadBaseWorker::startInfoAuthor(KSpreadFilterProperty property) {
+ KSpreadFilterProperty::Iterator it;
+ for (it = property.begin(); it != property.end(); ++it) {
+ kdDebug(30508) << "startInfoAuthor: " << it.key() << "->" << it.data() << endl;
+ }
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus KSpreadBaseWorker::startInfoAbout(KSpreadFilterProperty property) {
+ KSpreadFilterProperty::Iterator it;
+ for (it = property.begin(); it != property.end(); ++it) {
+ kdDebug(30508) << "startInfoAbout: " << it.key() << "->" << it.data() << endl;
+ }
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus KSpreadBaseWorker::startSpreadBook(KSpreadFilterProperty property) {
+ KSpreadFilterProperty::Iterator it;
+ for (it = property.begin(); it != property.end(); ++it) {
+ kdDebug(30508) << "startSpreadBook: " << it.key() << "->" << it.data() << endl;
+ }
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus KSpreadBaseWorker::startSpreadSheet(KSpreadFilterProperty property) {
+ KSpreadFilterProperty::Iterator it;
+ for (it = property.begin(); it != property.end(); ++it) {
+ kdDebug(30508) << "startSpreadSheet: " << it.key() << "->" << it.data() << endl;
+ }
+ return KoFilter::OK;
+}
+
+
+KoFilter::ConversionStatus KSpreadBaseWorker::startSpreadCell(KSpreadFilterProperty property) {
+ KSpreadFilterProperty::Iterator it;
+ for (it = property.begin(); it != property.end(); ++it) {
+ kdDebug(30508) << "startSpreadCell: " << it.key() << "->" << it.data() << endl;
+ }
+ return KoFilter::OK;
+}
diff --git a/filters/kspread/libkspreadexport/KSpreadBaseWorker.h b/filters/kspread/libkspreadexport/KSpreadBaseWorker.h
new file mode 100644
index 000000000..d23224029
--- /dev/null
+++ b/filters/kspread/libkspreadexport/KSpreadBaseWorker.h
@@ -0,0 +1,45 @@
+/*
+This file is part of the KDE project
+Copyright (C) 2002 Fred Malabre <fmalabre@yahoo.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSPREAD_BASE_WORKER_H
+#define KSPREAD_BASE_WORKER_H
+
+#include <KoFilter.h>
+#include <qmap.h>
+
+
+typedef QMap<QString, QString> KSpreadFilterProperty;
+
+class KSpreadBaseWorker
+{
+public:
+ KSpreadBaseWorker();
+ virtual ~KSpreadBaseWorker();
+
+ virtual KoFilter::ConversionStatus startDocument(KSpreadFilterProperty property);
+ virtual KoFilter::ConversionStatus startInfoLog(KSpreadFilterProperty property);
+ virtual KoFilter::ConversionStatus startInfoAuthor(KSpreadFilterProperty property);
+ virtual KoFilter::ConversionStatus startInfoAbout(KSpreadFilterProperty property);
+ virtual KoFilter::ConversionStatus startSpreadBook(KSpreadFilterProperty property);
+ virtual KoFilter::ConversionStatus startSpreadSheet(KSpreadFilterProperty property);
+ virtual KoFilter::ConversionStatus startSpreadCell(KSpreadFilterProperty property);
+};
+
+#endif /* KSPREAD_BASE_WORKER_H */
diff --git a/filters/kspread/libkspreadexport/KSpreadLeader.cc b/filters/kspread/libkspreadexport/KSpreadLeader.cc
new file mode 100644
index 000000000..c321a515f
--- /dev/null
+++ b/filters/kspread/libkspreadexport/KSpreadLeader.cc
@@ -0,0 +1,359 @@
+/*
+This file is part of the KDE project
+Copyright (C) 2002 Fred Malabre <fmalabre@yahoo.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "KSpreadLeader.h"
+
+using namespace KSpread;
+
+Leader::Leader(KoFilterChain *filterChain) {
+ m_worker = NULL;
+ m_filterChain = filterChain;
+}
+
+
+Leader::Leader(KoFilterChain *filterChain, KSpreadBaseWorker *newWorker) {
+ m_worker = newWorker;
+ m_filterChain = filterChain;
+}
+
+
+Leader::~Leader() {
+}
+
+
+KSpreadBaseWorker *Leader::getWorker() const {
+ return m_worker;
+}
+
+
+void Leader::setWorker(KSpreadBaseWorker *newWorker) {
+ m_worker = newWorker;
+}
+
+
+KoFilter::ConversionStatus Leader::convert() {
+ KoFilter::ConversionStatus status;
+
+ // Validate the filter chain and the worker
+ if (!m_filterChain) {
+ kdWarning(30508) << "koFilterChain is NULL!" << endl;
+ return KoFilter::StupidError;
+ }
+ if (!m_worker) {
+ kdWarning(30508) << "the KSpreadWorker is NULL!" << endl;
+ return KoFilter::StupidError;
+ }
+
+ // Gather data about the filter itself
+ KSpreadFilterProperty docProperty;
+ docProperty["outputfile"] = m_filterChain->outputFile();
+ status = m_worker->startDocument(docProperty);
+ if (status != KoFilter::OK)
+ return status;
+
+ // Get the document in memory
+ KSpreadDoc *document = (KSpreadDoc *) m_filterChain->inputDocument();
+ if (!document) {
+ kdWarning(30508) << "the KSpreadDoc is NULL!" << endl;
+ return KoFilter::StupidError;
+ }
+ if ( !::qt_cast<const KSpread::Doc *>( document ) ) {
+ kdWarning(30508) << "the document is not a KSpreadDoc!" << endl;
+ return KoFilter::StupidError;
+ }
+ if (document->mimeType() != "application/x-kspread") {
+ kdWarning(30508) << "the mime type document is not application/x-kspread!" << endl;
+ return KoFilter::StupidError;
+ }
+ KoDocumentInfo *info = document->documentInfo();
+ if (!document) {
+ kdWarning(30508) << "the KoDocumentInfo is NULL!" << endl;
+ return KoFilter::StupidError;
+ }
+
+ // Gather data about the document info
+ status = doInfo(info);
+ if (status != KoFilter::OK)
+ return status;
+
+ // Gather data about the spread book
+ status = doSpreadBook(document);
+ if (status != KoFilter::OK)
+ return status;
+
+ // Gather data about the spread sheet
+ KSpreadSheet *spreadSheet = document->map()->firstTable();
+ while (spreadSheet != 0) {
+ status = doSpreadSheet(spreadSheet);
+ if (status != KoFilter::OK)
+ return status;
+
+ // Gather data about the cell
+ for (int row = 1; row <= m_maxCellRow; ++row) {
+ for (int column = 1; column <= m_maxCellColumn; ++column) {
+ Cell*spreadCell = spreadSheet->cellAt(column, row);
+ status = doSpreadCell(spreadCell, column, row);
+ if (status != KoFilter::OK)
+ return status;
+ }
+ }
+
+ spreadSheet = document->map()->nextTable();
+ }
+
+ return status;
+}
+
+
+KoFilter::ConversionStatus Leader::doInfo(KoDocumentInfo *info) {
+ KoFilter::ConversionStatus status;
+
+#if 0 // this was never used, it's been removed now
+ // Gather data about the document log
+ KSpreadFilterProperty docInfoLogProperty;
+ KoDocumentInfoLog *infoLog = (KoDocumentInfoLog *) info->page("log");
+ docInfoLogProperty["oldlog"] = infoLog->oldLog();
+ docInfoLogProperty["newlog"] = infoLog->newLog();
+ status = m_worker->startInfoLog(docInfoLogProperty);
+ if (status != KoFilter::OK)
+ return status;
+#endif
+
+ // Gather data about the document author
+ KSpreadFilterProperty docInfoAuthorProperty;
+ KoDocumentInfoAuthor *infoAuthor = (KoDocumentInfoAuthor *) info->page("author");
+ docInfoAuthorProperty["fullname"] = infoAuthor->fullName();
+ docInfoAuthorProperty["initial"] = infoAuthor->initial();
+ docInfoAuthorProperty["title"] = infoAuthor->title();
+ docInfoAuthorProperty["company"] = infoAuthor->company();
+ docInfoAuthorProperty["email"] = infoAuthor->email();
+ docInfoAuthorProperty["telephone"] = infoAuthor->telephone();
+ docInfoAuthorProperty["fax"] = infoAuthor->fax();
+ docInfoAuthorProperty["country"] = infoAuthor->country();
+ docInfoAuthorProperty["postalcode"] = infoAuthor->postalCode();
+ docInfoAuthorProperty["city"] = infoAuthor->city();
+ docInfoAuthorProperty["street"] = infoAuthor->street();
+ status = m_worker->startInfoAuthor(docInfoAuthorProperty);
+ if (status != KoFilter::OK)
+ return status;
+
+ // Gather data about the document about
+ KSpreadFilterProperty docInfoAboutProperty;
+ KoDocumentInfoAbout *infoAbout = (KoDocumentInfoAbout *) info->page("about");
+ docInfoAboutProperty["title"] = infoAbout->title();
+ docInfoAboutProperty["author"] = infoAbout->abstract();
+ status = m_worker->startInfoAbout(docInfoAboutProperty);
+ return status;
+}
+
+
+KoFilter::ConversionStatus Leader::doSpreadBook(KSpreadDoc *document) {
+ KSpreadFilterProperty docSpreadBookProperty;
+ docSpreadBookProperty["spreadsheetcount"] = QString::number(document->map()->count());
+ docSpreadBookProperty["decimalsymbol"] = document->locale()->decimalSymbol();
+ docSpreadBookProperty["thousandsseparator"] = document->locale()->thousandsSeparator();
+ docSpreadBookProperty["currencysymbol"] = document->locale()->currencySymbol();
+ docSpreadBookProperty["monetarydecimalsymbol"] = document->locale()->monetaryDecimalSymbol();
+ docSpreadBookProperty["monetarythousandsseparator"] = document->locale()->monetaryThousandsSeparator();
+ docSpreadBookProperty["positivesign"] = document->locale()->positiveSign();
+ docSpreadBookProperty["negativesign"] = document->locale()->negativeSign();
+ docSpreadBookProperty["fracdigits"] = QString::number(document->locale()->fracDigits());
+ docSpreadBookProperty["positiveprefixcurrencysymbol"] = (document->locale()->positivePrefixCurrencySymbol()==0?"false":"true");
+ docSpreadBookProperty["negativeprefixcurrencysymbol"] = (document->locale()->negativePrefixCurrencySymbol()==0?"false":"true");
+ docSpreadBookProperty["use12clock"] = (document->locale()->use12Clock()==0?"false":"true");
+ docSpreadBookProperty["weekstartsmonday"] = (document->locale()->weekStartsMonday()==0?"false":"true");
+ docSpreadBookProperty["weekstartday"] = QString::number(document->locale()->weekStartDay());
+ docSpreadBookProperty["language"] = document->locale()->language();
+ docSpreadBookProperty["country"] = document->locale()->country();
+ docSpreadBookProperty["encoding"] = document->locale()->encoding();
+ docSpreadBookProperty["dateformat"] = document->locale()->dateFormat();
+ docSpreadBookProperty["dateformatshort"] = document->locale()->dateFormatShort();
+ docSpreadBookProperty["timeformat"] = document->locale()->timeFormat();
+ docSpreadBookProperty["defaultlanguage"] = KLocale::defaultLanguage();
+ docSpreadBookProperty["defaultcountry"] = KLocale::defaultCountry();
+ docSpreadBookProperty["defaultgridpencolorname"] = document->defaultGridPen().color().name();
+ docSpreadBookProperty["defaultgridpencolorred"] = QString::number(document->defaultGridPen().color().red());
+ docSpreadBookProperty["defaultgridpencolorgreen"] = QString::number(document->defaultGridPen().color().green());
+ docSpreadBookProperty["defaultgridpencolorblue"] = QString::number(document->defaultGridPen().color().blue());
+ docSpreadBookProperty["defaultgridpenwidth"] = QString::number(document->defaultGridPen().width());
+ docSpreadBookProperty["showverticalscrollbar"] = (document->getShowVerticalScrollBar()==0?"false":"true");
+ docSpreadBookProperty["showhorizontalscrollbar"] = (document->getShowHorizontalScrollBar()==0?"false":"true");
+ docSpreadBookProperty["showcolheader"] = (document->getShowColHeader()==0?"false":"true");
+ docSpreadBookProperty["showrowheader"] = (document->getShowRowHeader()==0?"false":"true");
+ docSpreadBookProperty["indentvalue"] = QString::number(document->getIndentValue());
+ docSpreadBookProperty["movetovalue"] = QString::number(document->getMoveToValue());
+ docSpreadBookProperty["showmessageerror"] = (document->getShowMessageError()==0?"false":"true");
+ docSpreadBookProperty["showtabbar"] = (document->getShowTabBar()==0?"false":"true");
+ docSpreadBookProperty["pagebordercolorname"] = document->pageBorderColor().name();
+ docSpreadBookProperty["pagebordercolorred"] = QString::number(document->pageBorderColor().red());
+ docSpreadBookProperty["pagebordercolorgreen"] = QString::number(document->pageBorderColor().green());
+ docSpreadBookProperty["pagebordercolorblue"] = QString::number(document->pageBorderColor().blue());
+ docSpreadBookProperty["showcommentindicator"] = (document->getShowCommentIndicator()==0?"false":"true");
+ docSpreadBookProperty["showformulabar"] = (document->getShowFormulaBar()==0?"false":"true");
+ docSpreadBookProperty["dontcheckupperword"] = (document->dontCheckUpperWord()==0?"false":"true");
+ docSpreadBookProperty["dontchecktitlecase"] = (document->dontCheckTitleCase()==0?"false":"true");
+ docSpreadBookProperty["showstatusbar"] = (document->getShowStatusBar()==0?"false":"true");
+ docSpreadBookProperty["unitname"] = document->getUnitName();
+ docSpreadBookProperty["syntaxversion"] = QString::number(document->syntaxVersion());
+ return m_worker->startSpreadBook(docSpreadBookProperty);
+}
+
+
+KoFilter::ConversionStatus Leader::doSpreadSheet(KSpreadSheet *spreadSheet) {
+ KSpreadFilterProperty docSpreadSheetProperty;
+ docSpreadSheetProperty["name"] = spreadSheet->tableName();
+ docSpreadSheetProperty["sizemaxx"] = QString::number(spreadSheet->sizeMaxX());
+ docSpreadSheetProperty["sizemaxy"] = QString::number(spreadSheet->sizeMaxY());
+ docSpreadSheetProperty["showgrid"] = (spreadSheet->getShowGrid()==0?"false":"true");
+ docSpreadSheetProperty["showformula"] = (spreadSheet->getShowFormula()==0?"false":"true");
+ docSpreadSheetProperty["showformulaindicator"] = (spreadSheet->getShowFormulaIndicator()==0?"false":"true");
+ docSpreadSheetProperty["lcmode"] = (spreadSheet->getLcMode()==0?"false":"true");
+ docSpreadSheetProperty["autocalc"] = (spreadSheet->getAutoCalc()==0?"false":"true");
+ docSpreadSheetProperty["showcolumnnumber"] = (spreadSheet->getShowColumnNumber()==0?"false":"true");
+ docSpreadSheetProperty["hidezero"] = (spreadSheet->getHideZero()==0?"false":"true");
+ docSpreadSheetProperty["firstletterupper"] = (spreadSheet->getFirstLetterUpper()==0?"false":"true");
+ docSpreadSheetProperty["ishidden"] = (spreadSheet->isHidden()==0?"false":"true");
+ docSpreadSheetProperty["showpageborders"] = (spreadSheet->isShowPageBorders()==0?"false":"true");
+ docSpreadSheetProperty["printablewidth"] = QString::number(spreadSheet->printableWidth());
+ docSpreadSheetProperty["printableheight"] = QString::number(spreadSheet->printableHeight());
+ docSpreadSheetProperty["paperwidth"] = QString::number(spreadSheet->paperWidth());
+ docSpreadSheetProperty["paperheight"] = QString::number(spreadSheet->paperHeight());
+ docSpreadSheetProperty["leftborder"] = QString::number(spreadSheet->leftBorder());
+ docSpreadSheetProperty["rightborder"] = QString::number(spreadSheet->rightBorder());
+ docSpreadSheetProperty["topborder"] = QString::number(spreadSheet->topBorder());
+ docSpreadSheetProperty["bottomborder"] = QString::number(spreadSheet->bottomBorder());
+ docSpreadSheetProperty["headleft"] = spreadSheet->headLeft();
+ docSpreadSheetProperty["headmid"] = spreadSheet->headMid();
+ docSpreadSheetProperty["headright"] = spreadSheet->headRight();
+ docSpreadSheetProperty["footleft"] = spreadSheet->footLeft();
+ docSpreadSheetProperty["footmid"] = spreadSheet->footMid();
+ docSpreadSheetProperty["footright"] = spreadSheet->footRight();
+ docSpreadSheetProperty["orientation"] = spreadSheet->orientationString();
+ docSpreadSheetProperty["paperformat"] = spreadSheet->paperFormatString();
+ docSpreadSheetProperty["printgrid"] = (spreadSheet->getPrintGrid()==0?"false":"true");
+ docSpreadSheetProperty["printcomment"] = (spreadSheet->getPrintCommentIndicator()==0?"false":"true");
+ docSpreadSheetProperty["printformula"] = (spreadSheet->getPrintFormulaIndicator()==0?"false":"true");
+ updateMaxCells(spreadSheet);
+ docSpreadSheetProperty["maxcellrow"] = QString::number(m_maxCellRow);
+ docSpreadSheetProperty["maxcellcolumn"] = QString::number(m_maxCellColumn);
+ return m_worker->startSpreadSheet(docSpreadSheetProperty);
+}
+
+
+KoFilter::ConversionStatus Leader::doSpreadCell(Cell*spreadCell, int column, int row) {
+ KSpreadFilterProperty docSpreadCellProperty;
+ docSpreadCellProperty["column"] = QString::number(column);
+ docSpreadCellProperty["row"] = QString::number(row);
+ docSpreadCellProperty["width"] = QString::number(spreadCell->dblWidth());
+ docSpreadCellProperty["height"] = QString::number(spreadCell->dblHeight());
+ docSpreadCellProperty["empty"] = (spreadCell->isEmpty()==0?"false":"true");
+ if (!spreadCell->isEmpty()) {
+ docSpreadCellProperty["text"] = spreadCell->text();
+ docSpreadCellProperty["strouttext"] = spreadCell->strOutText();
+ docSpreadCellProperty["action"] = spreadCell->action();
+ docSpreadCellProperty["date"] = (spreadCell->isDate()==0?"false":"true");
+ docSpreadCellProperty["time"] = (spreadCell->isTime()==0?"false":"true");
+ docSpreadCellProperty["textwidth"] = QString::number(spreadCell->textWidth());
+ docSpreadCellProperty["textheight"] = QString::number(spreadCell->textHeight());
+ docSpreadCellProperty["forceextracells"] = (spreadCell->isForceExtraCells()==0?"false":"true");
+ docSpreadCellProperty["mergedxcells"] = QString::number(spreadCell->mergedXCells());
+ docSpreadCellProperty["mergedycells"] = QString::number(spreadCell->mergedYCells());
+ docSpreadCellProperty["extraxcells"] = QString::number(spreadCell->extraXCells());
+ docSpreadCellProperty["extraycells"] = QString::number(spreadCell->extraYCells());
+ docSpreadCellProperty["extrawidth"] = QString::number(spreadCell->extraWidth());
+ docSpreadCellProperty["extraheight"] = QString::number(spreadCell->extraHeight());
+ docSpreadCellProperty["formula"] = (spreadCell->isFormula()==0?"false":"true");
+ docSpreadCellProperty["haserror"] = (spreadCell->hasError()==0?"false":"true");
+ docSpreadCellProperty["alignx"] = QString::number(spreadCell->defineAlignX());
+ docSpreadCellProperty["name"] = spreadCell->name();
+ docSpreadCellProperty["fullname"] = spreadCell->fullName();
+ docSpreadCellProperty["content"] = QString::number(spreadCell->content());
+ docSpreadCellProperty["style"] = QString::number(spreadCell->style());
+ docSpreadCellProperty["valuedate"] = spreadCell->valueDate().toString();
+ docSpreadCellProperty["valuetime"] = spreadCell->valueTime().toString();
+ docSpreadCellProperty["leftborderwidth"] = QString::number(spreadCell->leftBorderPen(column, row).width());
+ docSpreadCellProperty["leftbordercolorname"] = spreadCell->leftBorderPen(column, row).color().name();
+ docSpreadCellProperty["leftbordercolorred"] = QString::number(spreadCell->leftBorderPen(column, row).color().red());
+ docSpreadCellProperty["leftbordercolorgreen"] = QString::number(spreadCell->leftBorderPen(column, row).color().green());
+ docSpreadCellProperty["leftbordercolorblue"] = QString::number(spreadCell->leftBorderPen(column, row).color().blue());
+ docSpreadCellProperty["topborderwidth"] = QString::number(spreadCell->topBorderPen(column, row).width());
+ docSpreadCellProperty["topbordercolorname"] = spreadCell->topBorderPen(column, row).color().name();
+ docSpreadCellProperty["topbordercolorred"] = QString::number(spreadCell->topBorderPen(column, row).color().red());
+ docSpreadCellProperty["topbordercolorgreen"] = QString::number(spreadCell->topBorderPen(column, row).color().green());
+ docSpreadCellProperty["topbordercolorblue"] = QString::number(spreadCell->topBorderPen(column, row).color().blue());
+ docSpreadCellProperty["rightborderwidth"] = QString::number(spreadCell->rightBorderPen(column, row).width());
+ docSpreadCellProperty["rightbordercolorname"] = spreadCell->rightBorderPen(column, row).color().name();
+ docSpreadCellProperty["rightbordercolorred"] = QString::number(spreadCell->rightBorderPen(column, row).color().red());
+ docSpreadCellProperty["rightbordercolorgreen"] = QString::number(spreadCell->rightBorderPen(column, row).color().green());
+ docSpreadCellProperty["rightbordercolorblue"] = QString::number(spreadCell->rightBorderPen(column, row).color().blue());
+ docSpreadCellProperty["bottomborderwidth"] = QString::number(spreadCell->bottomBorderPen(column, row).width());
+ docSpreadCellProperty["bottombordercolorname"] = spreadCell->bottomBorderPen(column, row).color().name();
+ docSpreadCellProperty["bottombordercolorred"] = QString::number(spreadCell->bottomBorderPen(column, row).color().red());
+ docSpreadCellProperty["bottombordercolorgreen"] = QString::number(spreadCell->bottomBorderPen(column, row).color().green());
+ docSpreadCellProperty["bottombordercolorblue"] = QString::number(spreadCell->bottomBorderPen(column, row).color().blue());
+ docSpreadCellProperty["bgcolorname"] = spreadCell->bgColor(column, row).name();
+ docSpreadCellProperty["bgcolorred"] = QString::number(spreadCell->bgColor(column, row).red());
+ docSpreadCellProperty["bgcolorgreen"] = QString::number(spreadCell->bgColor(column, row).green());
+ docSpreadCellProperty["bgcolorblue"] = QString::number(spreadCell->bgColor(column, row).blue());
+ docSpreadCellProperty["bgbrushstyle"] = QString::number(spreadCell->backGroundBrush(column, row).style());
+ docSpreadCellProperty["valueempty"] = (spreadCell->value().isEmpty()==0?"false":"true");
+ docSpreadCellProperty["valueboolean"] = (spreadCell->value().isBoolean()==0?"false":"true");
+ docSpreadCellProperty["valueinteger"] = (spreadCell->value().isInteger()==0?"false":"true");
+ docSpreadCellProperty["valuefloat"] = (spreadCell->value().isFloat()==0?"false":"true");
+ docSpreadCellProperty["valuenumber"] = (spreadCell->value().isNumber()==0?"false":"true");
+ docSpreadCellProperty["valuestring"] = (spreadCell->value().isString()==0?"false":"true");
+ docSpreadCellProperty["valueerror"] = (spreadCell->value().isError()==0?"false":"true");
+ docSpreadCellProperty["valueasboolean"] = (spreadCell->value().asBoolean()==0?"false":"true");
+ docSpreadCellProperty["valueasinteger"] = QString::number(spreadCell->value().asInteger());
+ docSpreadCellProperty["valueasfloat"] = QString::number(spreadCell->value().asFloat());
+ docSpreadCellProperty["valueasstring"] = spreadCell->value().asString();
+ docSpreadCellProperty["valueasdatetime"] = spreadCell->value().asDateTime().toString();
+ docSpreadCellProperty["valueaserror"] = spreadCell->value().errorMessage();
+ }
+ return m_worker->startSpreadCell(docSpreadCellProperty);
+}
+
+
+void Leader::updateMaxCells(KSpreadSheet *spreadSheet) {
+ m_maxCellColumn = 0;
+ m_maxCellRow = 0;
+
+ int maxColumn = spreadSheet->maxColumn();
+ int maxRow = spreadSheet->maxRow();
+
+ // Go through all the SpreadSheet to find out the minimum rectangle of cells
+ // Maybe we should have something which does that in the KSpreadSheet class,
+ // it would be easy to keep track of this each time a new Cellis instanciated.
+ for (int row = 1; row < maxRow; ++row) {
+ bool usedColumn = FALSE;
+ for (int column = 1; column < maxColumn; ++column) {
+ Cell*cell = spreadSheet->cellAt(column, row);
+ if (!cell->isDefault() && !cell->isEmpty()) {
+ if (column > m_maxCellColumn) {
+ m_maxCellColumn = column;
+ }
+ usedColumn = TRUE;
+ }
+ }
+ if (usedColumn) {
+ m_maxCellRow = row;
+ }
+ }
+}
diff --git a/filters/kspread/libkspreadexport/KSpreadLeader.h b/filters/kspread/libkspreadexport/KSpreadLeader.h
new file mode 100644
index 000000000..eee950b92
--- /dev/null
+++ b/filters/kspread/libkspreadexport/KSpreadLeader.h
@@ -0,0 +1,105 @@
+/*
+This file is part of the KDE project
+Copyright (C) 2002 Fred Malabre <fmalabre@yahoo.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; see the file COPYING.LIB. If not, write to
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSPREAD_LEADER_H
+#define KSPREAD_LEADER_H
+
+#include <KSpreadBaseWorker.h>
+#include <KoFilterChain.h>
+#include <kdebug.h>
+#include <kspread_doc.h>
+#include <KoDocumentInfo.h>
+#include <kspread_map.h>
+
+namespace KSpread
+{
+
+/**
+* This class is a leader which will call the callbacks
+* to the worker with your own implementation for your export filter.
+*
+* To write an export filter, just instanciate a leader and
+* implement you own worker based on the BaseWorker.
+*
+* @short A Leader for an KSpread export filter
+* @author Fred Malabre
+* @see KSpreadBaseWorker
+* @see KoFilter
+*/
+class Leader
+{
+public:
+ /**
+ * Default constructor.
+ * Call setWorker() before starting to convert the KSpread document.
+ *
+ * @param the filter chain of the filter using the lib.
+ */
+ Leader(KoFilterChain *filterChain);
+
+ /**
+ * This constructor set up the Worker at initialization.
+ * convert can be called right away after instanciation of the Leader.
+ *
+ * @param the filter chain of the filter using the lib.
+ * @param implementation of a class derived from KSpreadWorker.
+ */
+ Leader(KoFilterChain *filterChain, KSpreadBaseWorker *newWorker);
+
+ /**
+ * Default destructor.
+ * It does nothing.
+ */
+ virtual ~Leader();
+
+private:
+ KSpreadBaseWorker *m_worker;
+ KoFilterChain *m_filterChain;
+ int m_maxCellColumn;
+ int m_maxCellRow;
+ void updateMaxCells(KSpreadSheet *spreadSheet);
+
+protected:
+ KSpreadBaseWorker *getWorker() const;
+ KoFilter::ConversionStatus doSpreadCell(Cell *spreadCell, int column, int row);
+ KoFilter::ConversionStatus doSpreadSheet(Sheet *spreadSheet);
+ KoFilter::ConversionStatus doSpreadBook(Doc *document);
+ KoFilter::ConversionStatus doInfo(KoDocumentInfo *info);
+
+public:
+ /**
+ * Set your own implementation of the Worker.
+ *
+ * @param implementation of a class derived from KSpreadWorker.
+ */
+ void setWorker(KSpreadBaseWorker *newWorker);
+
+ /**
+ * Start the conversion process.
+ * The callbacks of your Worker will be called at this time.
+ *
+ * @return status of the conversion.
+ */
+ KoFilter::ConversionStatus convert();
+};
+
+} // namespace KSpread
+
+#endif /* KSPREAD_LEADER_H */
diff --git a/filters/kspread/libkspreadexport/Makefile.am b/filters/kspread/libkspreadexport/Makefile.am
new file mode 100644
index 000000000..a36b3ad92
--- /dev/null
+++ b/filters/kspread/libkspreadexport/Makefile.am
@@ -0,0 +1,18 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) -I$(top_srcdir)/kspread -I$(srcdir)/../libkspreadexport $(KOFFICE_INCLUDES) \
+ $(KOTEXT_INCLUDES) $(all_includes)
+
+libkspreadexport_la_LDFLAGS = $(all_libraries) -module -version-info 1:0:0 -no-undefined
+
+libkspreadexport_la_LIBADD = $(KOFFICE_LIBS) ../../../kspread/libkspreadcommon.la
+
+####### Files
+
+lib_LTLIBRARIES = libkspreadexport.la
+
+libkspreadexport_la_SOURCES = KSpreadLeader.cc KSpreadBaseWorker.cc
+
+noinst_HEADERS = KSpreadLeader.h KSpreadBaseWorker.h
+
+METASOURCES = AUTO
diff --git a/filters/kspread/opencalc/Makefile.am b/filters/kspread/opencalc/Makefile.am
new file mode 100644
index 000000000..65741b1d7
--- /dev/null
+++ b/filters/kspread/opencalc/Makefile.am
@@ -0,0 +1,21 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir)/../../liboofilter -I$(srcdir) -I$(top_srcdir)/kspread $(KOFFICE_INCLUDES) \
+ $(KOTEXT_INCLUDES) $(all_includes)
+
+####### Files
+kde_module_LTLIBRARIES = libopencalcimport.la libopencalcexport.la
+
+libopencalcexport_la_SOURCES = opencalcexport.cc opencalcstyleexport.cc
+libopencalcexport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libopencalcexport_la_LIBADD = ../../../kspread/libkspreadcommon.la ../../liboofilter/liboofilter.la $(KOFFICE_LIBS)
+
+libopencalcimport_la_SOURCES = opencalcimport.cc
+libopencalcimport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libopencalcimport_la_LIBADD = ../../../kspread/libkspreadcommon.la ../../liboofilter/liboofilter.la $(KOFFICE_LIBS)
+
+METASOURCES = AUTO
+
+service_DATA = kspread_opencalc_import.desktop kspread_opencalc_export.desktop
+
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/opencalc/kspread_opencalc_export.desktop b/filters/kspread/opencalc/kspread_opencalc_export.desktop
new file mode 100644
index 000000000..d120960b8
--- /dev/null
+++ b/filters/kspread/opencalc/kspread_opencalc_export.desktop
@@ -0,0 +1,59 @@
+[Desktop Entry]
+Type=Service
+Name=OpenOffice.org Calc Export Filter for KSpread
+Name[bg]=Филтър за експортиране от KSpread в OpenOffice.org Calc
+Name[br]=Sil ezporzh OpenOffice.org Calc evit KSpread
+Name[ca]=Filtre d'exportació OpenOffice.org Calc per a KSpread
+Name[cs]=OpenOffice.org Calc exportní filtr pro KSpread
+Name[cy]=Hidlen Allforio OpenOffice.org Calc ar gyfer KSpread
+Name[da]=OpenOffice.rog-Calc eksportfilter for KSpread
+Name[de]=KSpread OpenOffice.org Calc-Exportfilter
+Name[el]=Φίλτρο εξαγωγής OpenOffice.org Calc για το KSpread
+Name[eo]=OpenOffice.org Calc-eksportfiltrilo por KSpread
+Name[es]=Filtro de exportación de OpenOffice.org Calc para KSpread
+Name[et]=KSpreadi OpenOffice.org Calc'i ekspordifilter
+Name[eu]=KSpread-en OpenOffice.org Calc esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات OpenOffice.org Calc برای KSpread
+Name[fi]=OpenOffice.org Calc -vientisuodin KSpreadille
+Name[fr]=Filtre d'exportation OpenOffice.org Calc pour KSpread
+Name[fy]=OpenOffice.org Calc Eksportfilter foar KSpread
+Name[ga]=Scagaire Easpórtála OpenOffice.org Calc le haghaidh KSpread
+Name[gl]=Filtro de Exportación de OpenOffice.org Calc para KSpread
+Name[he]=מסנן ייצוא מ־KSpread ל־OpenOffice.org Calc
+Name[hi]=के-स्प्रेड के लिए ओपन-ऑफ़िस.ऑर्ग केल्क निर्यात छननी
+Name[hr]=OpenOffice.org Calc filtar izvoza za KSpread
+Name[hu]=OpenOffice.org Calc exportszűrő a KSpreadhez
+Name[is]=OpenOffice.org Calc útflutningssía fyrir KSpread
+Name[it]=Filtro di esportazione OpenOffice.org Calc per KSpread
+Name[ja]=KSpread OpenOffice.org Calc エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ OpenOffice.org Calc សម្រាប់ KSpread
+Name[lt]=OpenOffice.org Calc eksportavimo filtras skirtas KSpread
+Name[lv]=OpenOffice.org Calc eksporta filtrs priekš KSpread
+Name[ms]=Penapis Eksport OpenOffice.org Calc bagi KSpread
+Name[nb]=OpenOffice.org Calc-eksportfilter for KSpread
+Name[nds]="OpenOffice.org Calc"-Exportfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि OpenOffice.org क्याल्क निर्यात फिल्टर
+Name[nl]=OpenOffice.org Calc Exportfilter voor KSpread
+Name[nn]=OpenOffice.org Calc-eksportfilter for KSpread
+Name[pl]=Filtr eksportu do formatu OpenOffice.org Calc dla KSpread
+Name[pt]=Filtro de Exportação de OpenOffice.org Calc para o KSpread
+Name[pt_BR]=Filtro de Exportação OpenOffice.org Calc do KSpread
+Name[ru]=Фильтр экспорта таблиц KSpread в OpenOffice.org Calc
+Name[se]=KSpread:a OpenOffice.org Calc-olggosfievrridansilli
+Name[sk]=OpenCalc filter pre export do KSpread
+Name[sl]=Izvozni filter OpenOffice.org Calc za KSpread
+Name[sr]=KSpread-ов филтер за извоз у OpenOffice.org-ов Calc
+Name[sr@Latn]=KSpread-ov filter za izvoz u OpenOffice.org-ov Calc
+Name[sv]=OpenOffice.org Calc-exportfilter för Kspread
+Name[ta]=கேஸ்பெரெட்டுக்கான OpenOffice.org கால்க் ஏற்றும் அலங்காரம்
+Name[tr]=KSpread için OpenOffice.org Calc Aktarma Filtresi
+Name[uk]=Фільтр експорту OpenOffice.org Calc для KSpread
+Name[uz]=KSpread uchun OpenOffice.org Calc eksport filteri
+Name[uz@cyrillic]=KSpread учун OpenOffice.org Calc экспорт филтери
+Name[zh_CN]=KSpread 的 OpenOffice.org Calc 导出过滤器
+Name[zh_TW]=KSpread 的 OpenOffice.org Calc 匯出過濾程式
+X-KDE-Export=application/vnd.sun.xml.calc
+X-KDE-Import=application/x-kspread
+X-KDE-Weight=1
+X-KDE-Library=libopencalcexport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/opencalc/kspread_opencalc_import.desktop b/filters/kspread/opencalc/kspread_opencalc_import.desktop
new file mode 100644
index 000000000..c7dde5ef5
--- /dev/null
+++ b/filters/kspread/opencalc/kspread_opencalc_import.desktop
@@ -0,0 +1,62 @@
+[Desktop Entry]
+Type=Service
+Name=OpenOffice.org Calc Import Filter for KSpread
+Name[bg]=Филтър за импортиране от OpenOffice.org Calc в KSpread
+Name[br]=Sil enporzh OpenOffice.org Calc evit KSpread
+Name[ca]=Filtre d'importació OpenOffice.org Calc per a KSpread
+Name[cs]=OpenOffice.org Calc importní filtr pro KSpread
+Name[cy]=Hidl Mewnforio OpenOffice.org Calc ar gyfer KSpread
+Name[da]=OpenOffice.org-Calc importfilter for KSpread
+Name[de]=KSpread OpenOffice.org Calc-Importfilter
+Name[el]=Φίλτρο εισαγωγής OpenOffice.org Calc για το KSpread
+Name[eo]=OpenOffice.org Calc-importfiltrilo por KSpread
+Name[es]=Filtro de importación de OpenOffice.org Calc para KSpread
+Name[et]=KSpreadi OpenOffice.org Calc'i impordifilter
+Name[eu]=KSpread-en OpenOffice.org Calc inportaziorako iragazkia
+Name[fa]=پالایۀ واردات OpenOffice.org Calc برای KSpread
+Name[fi]=OpenOffice.org Calc -tuontisuodin KSpreadille
+Name[fr]=Filtre d'importation OpenOffice.org Calc pour KSpread
+Name[fy]=OpenOffice.org Calc Ymportfilter foar KSpread
+Name[ga]=Scagaire Iompórtála OpenOffice.org Calc le haghaidh KSpread
+Name[gl]=Filtro de Importación de OpenOffice.org Calc para KSpread
+Name[he]=מסנן ייבוא מ־OpenOffice.org Calc ל־KSpread
+Name[hi]=के-स्प्रेड के लिए ओपन-ऑफ़िस.ऑर्ग केल्क आयात छननी
+Name[hr]=OpenOffice.org Calc filtar uvoza za KSpread
+Name[hu]=OpenOffice.org importszűrő a KSpreadhez
+Name[is]=OpenOffice.org Calc innflutningssía fyrir KSpread
+Name[it]=Filtro di importazione OpenOffice.org Calc per KSpread
+Name[ja]=KSpread OpenOffice.org Calc インポートフィルタ
+Name[km]=តម្រង​នាំចូល OpenOffice.org Calc សម្រាប់ KSpread
+Name[lt]=OpenOffice.org Calc importavimo filtras skirtas KSpread
+Name[lv]=OpenOffice.org Calc importa filtrs priekš KSpread
+Name[ms]=Penapis Import OpenOffice.org Calc bagi KSpread
+Name[nb]=OpenOffice.org Calc-importfilter for KSpread
+Name[nds]="OpenOffice.org Calc"-Importfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि OpenOffice.org क्याल्क आयात फिल्टर
+Name[nl]=OpenOffice.org Calc Importfilter voor KSpread
+Name[nn]=OpenOffice.org Calc-importfilter for KSpread
+Name[pl]=Filtr importu formatu OpenOffice.org dla KSpread
+Name[pt]=Filtro de Importação de OpenOffice.org Calc para o KSpread
+Name[pt_BR]=Filtro de Importação OpenOffice.org Calc do KSpread
+Name[ru]=Фильтр импорта таблиц OpenOffice.org Calc в KSpread
+Name[se]=KSpread:a OpenOffice.org Calc-sisafievrridansilli
+Name[sk]=OpenCalc filter pre import z KSpread
+Name[sl]=Uvozni filter OpenOffice.org Calc za KSpread
+Name[sr]=KSpread-ов филтер за увоз из OpenOffice.org-овог Calc-а
+Name[sr@Latn]=KSpread-ov filter za uvoz iz OpenOffice.org-ovog Calc-a
+Name[sv]=OpenOffice.org Calc-importfilter för Kspread
+Name[ta]=கேஸ்பெரெட்டுக்கான OpenOffice.org கால்க் இறக்கும் அலங்காரம்
+Name[tr]=KSpread için OpenOffice.org Calc Alma Filtresi
+Name[uk]=Фільтр імпорту OpenOffice.org Calc для KSpread
+Name[uz]=KSpread uchun OpenOffice.org Calc import filteri
+Name[uz@cyrillic]=KSpread учун OpenOffice.org Calc импорт филтери
+Name[zh_CN]=KSpread 的 OpenOffice.org Calc 导入过滤器
+Name[zh_TW]=KSpread 的 OpenOffice.org Calc 匯入過濾程式
+X-KDE-Export=application/x-kspread
+X-KDE-Import=application/vnd.sun.xml.calc,application/vnd.sun.xml.calc.template
+X-KDE-Weight=1
+X-KDE-Library=libopencalcimport
+X-KDE-LibraryMajor=1
+X-KDE-LibraryMinor=0
+X-KDE-LibraryDependencies=
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/opencalc/opencalcexport.cc b/filters/kspread/opencalc/opencalcexport.cc
new file mode 100644
index 000000000..20915b516
--- /dev/null
+++ b/filters/kspread/opencalc/opencalcexport.cc
@@ -0,0 +1,1329 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 David Faure <faure@kde.org>
+ Copyright (C) 2000 Norbert Andres <nandres@web.de>
+ Copyright (C) 2005 Laurent Montel <montel@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <float.h>
+#include <math.h>
+
+#include <opencalcexport.h>
+
+#include <qdatetime.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qvaluelist.h>
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kmdcodec.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+
+#include <KoDocumentInfo.h>
+#include <KoFilterChain.h>
+#include <KoGlobal.h>
+
+#include <kspread_aboutdata.h>
+#include <kspread_cell.h>
+#include <kspread_doc.h>
+#include <kspread_format.h>
+#include <kspread_map.h>
+#include <kspread_view.h>
+#include <kspread_canvas.h>
+#include <kspread_sheet.h>
+#include <kspread_sheetprint.h>
+#include <kspread_style.h>
+#include <kspread_style_manager.h>
+#include <kspread_util.h>
+
+using namespace KSpread;
+
+typedef QValueList<Reference> AreaList;
+
+class OpenCalcExportFactory : KGenericFactory<OpenCalcExport, KoFilter>
+{
+public:
+ OpenCalcExportFactory(void) : KGenericFactory<OpenCalcExport, KoFilter> ("kspreadopencalcexport")
+ {}
+protected:
+ virtual void setupTranslations( void )
+ {
+ KGlobal::locale()->insertCatalogue( "kofficefilters" );
+ }
+};
+
+K_EXPORT_COMPONENT_FACTORY( libopencalcexport, OpenCalcExportFactory() )
+
+#define STOPEXPORT \
+ do \
+ { \
+ delete store; \
+ return false; \
+ } while(0)
+
+OpenCalcExport::OpenCalcExport( KoFilter *, const char *, const QStringList & )
+ : KoFilter(), m_locale( 0 )
+{
+}
+
+KoFilter::ConversionStatus OpenCalcExport::convert( const QCString & from,
+ const QCString & to )
+{
+ /* later...
+ KSpreadLeader * leader = new KSpreadLeader( m_chain );
+ OpenCalcWorker * worker = new OpenCalcWorker();
+ leader->setWorker( worker );
+
+ KoFilter::ConversionStatus status = leader->convert();
+
+ delete worker;
+ delete leader;
+
+ return status;
+ */
+
+ KoDocument * document = m_chain->inputDocument();
+
+ if ( !document )
+ return KoFilter::StupidError;
+
+ if ( !::qt_cast<const KSpread::Doc *>( document ) )
+ {
+ kdWarning(30518) << "document isn't a KSpread::Doc but a "
+ << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ if ( ( to != "application/vnd.sun.xml.calc") || (from != "application/x-kspread" ) )
+ {
+ kdWarning(30518) << "Invalid mimetypes " << to << " " << from << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ const Doc * ksdoc = static_cast<const Doc *>(document);
+
+ if ( ksdoc->mimeType() != "application/x-kspread" )
+ {
+ kdWarning(30518) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ m_locale = static_cast<Doc*>(document)->locale();
+ if ( !writeFile( ksdoc ) )
+ return KoFilter::CreationError;
+
+ emit sigProgress( 100 );
+
+ return KoFilter::OK;
+}
+
+bool OpenCalcExport::writeFile( const Doc * ksdoc )
+{
+ KoStore * store = KoStore::createStore( m_chain->outputFile(), KoStore::Write, "", KoStore::Zip );
+
+ if ( !store )
+ return false;
+
+ uint filesWritten = 0;
+
+ if ( !exportContent( store, ksdoc ) )
+ STOPEXPORT;
+ else
+ filesWritten |= contentXML;
+
+ // TODO: pass sheet number and cell number
+ if ( !exportDocInfo( store, ksdoc ) )
+ STOPEXPORT;
+ else
+ filesWritten |= metaXML;
+
+ if ( !exportStyles( store, ksdoc ) )
+ STOPEXPORT;
+ else
+ filesWritten |= stylesXML;
+
+ if ( !exportSettings( store, ksdoc ) )
+ STOPEXPORT;
+ else
+ filesWritten |= settingsXML;
+
+ if ( !writeMetaFile( store, filesWritten ) )
+ STOPEXPORT;
+
+ // writes zip file to disc
+ delete store;
+ store = 0;
+
+ return true;
+}
+
+bool OpenCalcExport::exportDocInfo( KoStore * store, const Doc* ksdoc )
+{
+ if ( !store->open( "meta.xml" ) )
+ return false;
+
+ KoDocumentInfo * docInfo = ksdoc->documentInfo();
+ KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>( docInfo->page( "about" ) );
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
+
+ QDomDocument meta;
+ meta.appendChild( meta.createProcessingInstruction( "xml","version=\"1.0\" encoding=\"UTF-8\"" ) );
+
+ QDomElement content = meta.createElement( "office:document-meta" );
+ content.setAttribute( "xmlns:office", "http://openoffice.org/2000/office");
+ content.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
+ content.setAttribute( "xmlns:dc", "http://purl.org/dc/elements/1.1/" );
+ content.setAttribute( "xmlns:meta", "http://openoffice.org/2000/meta" );
+ content.setAttribute( "office:version", "1.0" );
+
+ QDomNode officeMeta = meta.createElement( "office:meta" );
+
+ QDomElement data = meta.createElement( "meta:generator" );
+ QString app( "KSpread " );
+ app += KSpread::version;
+ data.appendChild( meta.createTextNode( app ) );
+ officeMeta.appendChild( data );
+
+ data = meta.createElement( "meta:initial-creator" );
+ data.appendChild( meta.createTextNode( authorPage->fullName() ) );
+ officeMeta.appendChild( data );
+
+ data = meta.createElement( "meta:creator" );
+ data.appendChild( meta.createTextNode( authorPage->fullName() ) );
+ officeMeta.appendChild( data );
+
+ data = meta.createElement( "dc:description" );
+ data.appendChild( meta.createTextNode( aboutPage->abstract() ) );
+ officeMeta.appendChild( data );
+
+ data = meta.createElement( "meta:keywords" );
+ QDomElement dataItem = meta.createElement( "meta:keyword" );
+ dataItem.appendChild( meta.createTextNode( aboutPage->keywords() ) );
+ data.appendChild( dataItem );
+ officeMeta.appendChild( data );
+
+ data = meta.createElement( "dc:title" );
+ data.appendChild( meta.createTextNode( aboutPage->title() ) );
+ officeMeta.appendChild( data );
+
+ data = meta.createElement( "dc:subject" );
+ data.appendChild( meta.createTextNode( aboutPage->subject() ) );
+ officeMeta.appendChild( data );
+
+ const QDateTime dt ( QDateTime::currentDateTime() );
+ if ( dt.isValid() )
+ {
+ data = meta.createElement( "dc:date" );
+ data.appendChild( meta.createTextNode( dt.toString( Qt::ISODate ) ) );
+ officeMeta.appendChild( data );
+ }
+
+ /* TODO:
+ <meta:creation-date>2003-01-08T23:57:31</meta:creation-date>
+ <dc:language>en-US</dc:language>
+ <meta:editing-cycles>2</meta:editing-cycles>
+ <meta:editing-duration>PT38S</meta:editing-duration>
+ <meta:user-defined meta:name="Info 3"/>
+ <meta:user-defined meta:name="Info 4"/>
+ */
+
+ data = meta.createElement( "meta:document-statistic" );
+ data.setAttribute( "meta:table-count", QString::number( ksdoc->map()->count() ) );
+ // TODO: data.setAttribute( "meta:cell-count", );
+ officeMeta.appendChild( data );
+
+ content.appendChild( officeMeta );
+ meta.appendChild( content );
+
+ QCString doc( meta.toCString() );
+ kdDebug(30518) << "Meta: " << doc << endl;
+
+ store->write( doc, doc.length() );
+
+ if ( !store->close() )
+ return false;
+
+ return true;
+}
+
+bool OpenCalcExport::exportSettings( KoStore * store, const Doc * ksdoc )
+{
+ if ( !store->open( "settings.xml" ) )
+ return false;
+
+ QDomDocument doc;
+ doc.appendChild( doc.createProcessingInstruction( "xml","version=\"1.0\" encoding=\"UTF-8\"" ) );
+
+ QDomElement settings = doc.createElement( "office:document-settings" );
+ settings.setAttribute( "xmlns:office", "http://openoffice.org/2000/office");
+ settings.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
+ settings.setAttribute( "xmlns:config", "http://openoffice.org/2001/config" );
+ settings.setAttribute( "office:version", "1.0" );
+
+ QDomElement begin = doc.createElement( "office:settings" );
+
+ QDomElement configItem = doc.createElement("config:config-item-set" );
+ configItem.setAttribute( "config:name", "view-settings" );
+
+ QDomElement mapIndexed = doc.createElement( "config:config-item-map-indexed" );
+ mapIndexed.setAttribute("config:name", "Views" );
+ configItem.appendChild( mapIndexed );
+
+ QDomElement mapItem = doc.createElement("config:config-item-map-entry" );
+
+ QDomElement attribute = doc.createElement("config:config-item" );
+ attribute.setAttribute( "config:name", "ActiveTable" );
+ attribute.setAttribute( "config:type", "string" );
+
+ View * view = static_cast<View*>( ksdoc->views().getFirst());
+ QString activeTable;
+ if ( view ) // no view if embedded document
+ {
+ Canvas * canvas = view->canvasWidget();
+ activeTable = canvas->activeSheet()->sheetName();
+ // save current sheet selection before to save marker, otherwise current pos is not saved
+ view->saveCurrentSheetSelection();
+ }
+ attribute.appendChild( doc.createTextNode( activeTable ) );
+ mapItem.appendChild( attribute );
+
+ QDomElement configmaped = doc.createElement( "config:config-item-map-named" );
+ configmaped.setAttribute( "config:name","Tables" );
+
+ QPtrListIterator<Sheet> it( ksdoc->map()->sheetList() );
+ for( ; it.current(); ++it )
+ {
+ QPoint marker;
+ if ( view )
+ {
+ marker = view->markerFromSheet( *it );
+ }
+ QDomElement tmpItemMapNamed = doc.createElement( "config:config-item-map-entry" );
+ tmpItemMapNamed.setAttribute( "config:name", ( *it )->tableName() );
+
+ QDomElement sheetAttribute = doc.createElement( "config:config-item" );
+ sheetAttribute.setAttribute( "config:name", "CursorPositionX" );
+ sheetAttribute.setAttribute( "config:type", "int" );
+ sheetAttribute.appendChild( doc.createTextNode( QString::number(marker.x() ) ) );
+ tmpItemMapNamed.appendChild( sheetAttribute );
+
+ sheetAttribute = doc.createElement( "config:config-item" );
+ sheetAttribute.setAttribute( "config:name", "CursorPositionY" );
+ sheetAttribute.setAttribute( "config:type", "int" );
+ sheetAttribute.appendChild( doc.createTextNode( QString::number(marker.y() ) ) );
+ tmpItemMapNamed.appendChild( sheetAttribute );
+
+ configmaped.appendChild( tmpItemMapNamed );
+ }
+ mapItem.appendChild( configmaped );
+
+
+
+ mapIndexed.appendChild( mapItem );
+
+ begin.appendChild( configItem );
+
+ settings.appendChild( begin );
+
+ doc.appendChild( settings );
+
+ QCString f( doc.toCString() );
+ kdDebug(30518) << "Settings: " << (char const * ) f << endl;
+
+ store->write( f, f.length() );
+
+ if ( !store->close() )
+ return false;
+
+ return true;
+}
+
+bool OpenCalcExport::exportContent( KoStore * store, const Doc * ksdoc )
+{
+ if ( !store->open( "content.xml" ) )
+ return false;
+
+ createDefaultStyles();
+
+ QDomDocument doc;
+ doc.appendChild( doc.createProcessingInstruction( "xml","version=\"1.0\" encoding=\"UTF-8\"" ) );
+
+ QDomElement content = doc.createElement( "office:document-content" );
+ content.setAttribute( "xmlns:office", "http://openoffice.org/2000/office");
+ content.setAttribute( "xmlns:style", "http://openoffice.org/2000/style" );
+ content.setAttribute( "xmlns:text", "http://openoffice.org/2000/text" );
+ content.setAttribute( "xmlns:table", "http://openoffice.org/2000/table" );
+ content.setAttribute( "xmlns:draw", "http://openoffice.org/2000/drawing" );
+ content.setAttribute( "xmlns:fo", "http://www.w3.org/1999/XSL/Format" );
+ content.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
+ content.setAttribute( "xmlns:number", "http://openoffice.org/2000/datastyle" );
+ content.setAttribute( "xmlns:svg", "http://www.w3.org/2000/svg" );
+ content.setAttribute( "xmlns:chart", "http://openoffice.org/2000/chart" );
+ content.setAttribute( "xmlns:dr3d", "http://openoffice.org/2000/dr3d" );
+ content.setAttribute( "xmlns:math", "http://www.w3.org/1998/Math/MathML" );
+ content.setAttribute( "xmlns:form", "http://openoffice.org/2000/form" );
+ content.setAttribute( "xmlns:script", "http://openoffice.org/2000/script" );
+ content.setAttribute( "office:class", "spreadsheet" );
+ content.setAttribute( "office:version", "1.0" );
+
+ QDomElement data = doc.createElement( "office:script" );
+ content.appendChild( data );
+
+ if ( !exportBody( doc, content, ksdoc ) )
+ return false;
+
+ doc.appendChild( content );
+
+ QCString f( doc.toCString() );
+ kdDebug(30518) << "Content: " << (char const * ) f << endl;
+
+ store->write( f, f.length() );
+
+ if ( !store->close() )
+ return false;
+
+ return true;
+}
+
+void exportNamedExpr( QDomDocument & doc, QDomElement & parent,
+ AreaList const & namedAreas )
+{
+ AreaList::const_iterator it = namedAreas.begin();
+ AreaList::const_iterator end = namedAreas.end();
+
+ while ( it != end )
+ {
+ QDomElement namedRange = doc.createElement( "table:named-range" );
+
+ Reference ref = *it;
+
+ namedRange.setAttribute( "table:name", ref.ref_name );
+ namedRange.setAttribute( "table:base-cell-address", convertRefToBase( ref.sheet_name, ref.rect ) );
+ namedRange.setAttribute( "table:cell-range-address", convertRefToRange( ref.sheet_name, ref.rect ) );
+
+ parent.appendChild( namedRange );
+
+ ++it;
+ }
+}
+
+bool OpenCalcExport::exportBody( QDomDocument & doc, QDomElement & content, const Doc * ksdoc )
+{
+ QDomElement fontDecls = doc.createElement( "office:font-decls" );
+ QDomElement autoStyles = doc.createElement( "office:automatic-styles" );
+ QDomElement body = doc.createElement( "office:body" );
+
+ if ( ksdoc->map()->isProtected() )
+ {
+ body.setAttribute( "table:structure-protected", "true" );
+
+ QCString passwd;
+ ksdoc->map()->password( passwd );
+ if ( passwd.length() > 0 )
+ {
+ QCString str( KCodecs::base64Encode( passwd ) );
+ body.setAttribute( "table:protection-key", QString( str.data() ) );
+ }
+ }
+
+
+
+ QPtrListIterator<Sheet> it( ksdoc->map()->sheetList() );
+
+ for( it.toFirst(); it.current(); ++it )
+ {
+ SheetStyle ts;
+ int maxCols = 1;
+ int maxRows = 1;
+ Sheet * sheet = it.current();
+
+ ts.visible = !sheet->isHidden();
+
+ QDomElement tabElem = doc.createElement( "table:table" );
+ tabElem.setAttribute( "table:style-name", m_styles.sheetStyle( ts ) );
+
+ if ( sheet->isProtected() )
+ {
+ tabElem.setAttribute( "table:protected", "true" );
+
+ QCString passwd;
+ sheet->password( passwd );
+ if ( passwd.length() > 0 )
+ {
+ QCString str( KCodecs::base64Encode( passwd ) );
+ tabElem.setAttribute( "table:protection-key", QString( str.data() ) );
+ }
+ }
+
+ QString name( sheet->tableName() );
+
+ int n = name.find( ' ' );
+ if ( n != -1 )
+ {
+ kdDebug(30518) << "Sheet name converting: " << name << endl;
+ name[n] == '_';
+ kdDebug(30518) << "Sheet name converted: " << name << endl;
+ }
+ name = name.replace( ' ', "_" );
+
+ QRect _printRange = sheet->print()->printRange();
+ if ( _printRange != ( QRect( QPoint( 1, 1 ), QPoint( KS_colMax, KS_rowMax ) ) ) )
+ {
+ QString range= convertRangeToRef( name, _printRange );
+ //kdDebug(30518)<<" range : "<<range<<endl;
+ tabElem.setAttribute( "table:print-ranges", range );
+ }
+
+
+ tabElem.setAttribute( "table:name", name );
+
+ maxRowCols( sheet, maxCols, maxRows );
+
+ exportSheet( doc, tabElem, sheet, maxCols, maxRows );
+
+ body.appendChild( tabElem );
+ }
+
+ KoDocument * document = m_chain->inputDocument();
+ Doc * kspreadDoc = static_cast<Doc *>( document );
+
+ AreaList namedAreas = kspreadDoc->listArea();
+ if ( namedAreas.count() > 0 )
+ {
+ QDomElement namedExpr = doc.createElement( "table:named-expressions" );
+ exportNamedExpr( doc, namedExpr, namedAreas );
+
+ body.appendChild( namedExpr );
+ }
+
+ m_styles.writeStyles( doc, autoStyles );
+ m_styles.writeFontDecl( doc, fontDecls );
+
+ content.appendChild( fontDecls );
+ content.appendChild( autoStyles );
+ content.appendChild( body );
+
+ return true;
+}
+
+void OpenCalcExport::exportSheet( QDomDocument & doc, QDomElement & tabElem,
+ const Sheet * sheet, int maxCols, int maxRows )
+{
+ kdDebug(30518) << "exportSheet: " << sheet->tableName() << endl;
+ int i = 1;
+
+ while ( i <= maxCols )
+ {
+ const ColumnFormat * column = sheet->columnFormat( i );
+ ColumnStyle cs;
+ cs.breakB = ::Style::automatic;
+ cs.size = column->mmWidth() / 10;
+ bool hide = column->isHide();
+
+ int j = i + 1;
+ int repeated = 1;
+ while ( j <= maxCols )
+ {
+ const ColumnFormat *c = sheet->columnFormat( j );
+ ColumnStyle cs1;
+ cs1.breakB = ::Style::automatic;
+ cs1.size = c->mmWidth() / 10;
+
+ if ( ColumnStyle::isEqual( &cs, cs1 ) && ( hide == c->isHide() ) )
+ ++repeated;
+ else
+ break;
+ ++j;
+ }
+
+ QDomElement colElem = doc.createElement( "table:table-column" );
+ colElem.setAttribute( "table:style-name", m_styles.columnStyle( cs ) );
+ colElem.setAttribute( "table:default-cell-style-name", "Default" );//todo fixme create style from cell
+ if ( hide )
+ colElem.setAttribute( "table:visibility", "collapse" );
+
+ if ( repeated > 1 )
+ colElem.setAttribute( "table:number-columns-repeated", QString::number( repeated ) );
+
+ tabElem.appendChild( colElem );
+ i += repeated;
+ }
+
+ for ( i = 1; i <= maxRows; ++i )
+ {
+ const RowFormat * row = sheet->rowFormat( i );
+ RowStyle rs;
+ rs.breakB = ::Style::automatic;
+ rs.size = row->mmHeight() / 10;
+
+ QDomElement rowElem = doc.createElement( "table:table-row" );
+ rowElem.setAttribute( "table:style-name", m_styles.rowStyle( rs ) );
+ if ( row->isHide() )
+ rowElem.setAttribute( "table:visibility", "collapse" );
+
+ exportCells( doc, rowElem, sheet, i, maxCols );
+
+ tabElem.appendChild( rowElem );
+ }
+}
+
+void OpenCalcExport::exportCells( QDomDocument & doc, QDomElement & rowElem,
+ const Sheet *sheet, int row, int maxCols )
+{
+ int i = 1;
+ while ( i <= maxCols )
+ {
+ int repeated = 1;
+ bool hasComment = false;
+ const Cell* cell = sheet->cellAt( i, row );
+ QDomElement cellElem;
+
+ if ( !cell->isPartOfMerged() )
+ cellElem = doc.createElement( "table:table-cell" );
+ else
+ cellElem = doc.createElement( "table:covered-table-cell" );
+
+ QFont font;
+ Value const value( cell->value() );
+ if ( !cell->isDefault() )
+ {
+ font = cell->format()->textFont( i, row );
+ m_styles.addFont( font );
+
+ if ( cell->format()->hasProperty( Format::PComment ) )
+ hasComment = true;
+ }
+
+ CellStyle c;
+ CellStyle::loadData( c, cell ); // TODO: number style
+
+ cellElem.setAttribute( "table:style-name", m_styles.cellStyle( c ) );
+
+ // group empty cells with the same style
+ if ( cell->isEmpty() && !hasComment && !cell->isPartOfMerged() && !cell->doesMergeCells() )
+ {
+ int j = i + 1;
+ while ( j <= maxCols )
+ {
+ const Cell *cell1 = sheet->cellAt( j, row );
+
+ CellStyle c1;
+ CellStyle::loadData( c1, cell1 ); // TODO: number style
+
+ if ( cell1->isEmpty() && !cell->format()->hasProperty( Format::PComment )
+ && CellStyle::isEqual( &c, c1 ) && !cell->isPartOfMerged() && !cell->doesMergeCells() )
+ ++repeated;
+ else
+ break;
+ ++j;
+ }
+ if ( repeated > 1 )
+ cellElem.setAttribute( "table:number-columns-repeated", QString::number( repeated ) );
+ }
+
+ if ( value.isBoolean() )
+ {
+ kdDebug(30518) << "Type: Boolean" << endl;
+ cellElem.setAttribute( "table:value-type", "boolean" );
+ cellElem.setAttribute( "table:boolean-value", ( value.asBoolean() ? "true" : "false" ) );
+ }
+ else if ( value.isNumber() )
+ {
+ kdDebug(30518) << "Type: Number" << endl;
+ FormatType type = cell->format()->getFormatType( i, row );
+
+ if ( type == Percentage_format )
+ cellElem.setAttribute( "table:value-type", "percentage" );
+ else
+ cellElem.setAttribute( "table:value-type", "float" );
+
+ cellElem.setAttribute( "table:value", QString::number( value.asFloat() ) );
+ }
+ else
+ {
+ kdDebug(30518) << "Type: " << value.type() << endl;
+ }
+
+ if ( cell->isFormula() )
+ {
+ kdDebug(30518) << "Formula found" << endl;
+
+ QString formula( convertFormula( cell->text() ) );
+ cellElem.setAttribute( "table:formula", formula );
+ }
+ else if ( !cell->link().isEmpty() )
+ {
+ QDomElement link = doc.createElement( "text:p" );
+ QDomElement linkref = doc.createElement( "text:a" );
+
+ QString tmp = cell->link();
+ if ( localReferenceAnchor( tmp ) )
+ linkref.setAttribute( "xlink:href", ( "#"+tmp ) );
+ else
+ linkref.setAttribute( "xlink:href", tmp );
+
+ linkref.appendChild( doc.createTextNode( cell->text() ) );
+
+ link.appendChild( linkref );
+ cellElem.appendChild( link );
+ }
+ else if ( !cell->isEmpty() )
+ {
+ QDomElement textElem = doc.createElement( "text:p" );
+ textElem.appendChild( doc.createTextNode( cell->strOutText() ) );
+
+ cellElem.appendChild( textElem );
+ kdDebug(30518) << "Cell StrOut: " << cell->strOutText() << endl;
+ }
+
+ if ( cell->doesMergeCells() )
+ {
+ int colSpan = cell->mergedXCells() + 1;
+ int rowSpan = cell->mergedYCells() + 1;
+
+ if ( colSpan > 1 )
+ cellElem.setAttribute( "table:number-columns-spanned", QString::number( colSpan ) );
+
+ if ( rowSpan > 1 )
+ cellElem.setAttribute( "table:number-rows-spanned", QString::number( rowSpan ) );
+ }
+
+ if ( hasComment )
+ {
+ QString comment( cell->format()->comment( i, row ) );
+ QDomElement annotation = doc.createElement( "office:annotation" );
+ QDomElement text = doc.createElement( "text:p" );
+ text.appendChild( doc.createTextNode( comment ) );
+
+ annotation.appendChild( text );
+ cellElem.appendChild( annotation );
+ }
+
+ rowElem.appendChild( cellElem );
+
+ i += repeated;
+ }
+}
+
+void OpenCalcExport::maxRowCols( const Sheet *sheet,
+ int & maxCols, int & maxRows )
+{
+ Cell const * cell = sheet->firstCell();
+
+ while ( cell )
+ {
+ if ( cell->column() > maxCols )
+ maxCols = cell->column();
+
+ if ( cell->row() > maxRows )
+ maxRows = cell->row();
+
+ cell = cell->nextCell();
+ }
+
+ RowFormat const * row = sheet->firstRow();
+
+ while ( row )
+ {
+ if ( row->row() > maxRows )
+ maxRows = row->row();
+
+ row = row->next();
+ }
+
+ ColumnFormat const * col = sheet->firstCol();
+ while ( col )
+ {
+ if ( col->column() > maxCols )
+ maxCols = col->column();
+
+ col = col->next();
+ }
+
+}
+
+bool OpenCalcExport::exportStyles( KoStore * store, const Doc *ksdoc )
+{
+ if ( !store->open( "styles.xml" ) )
+ return false;
+
+ QDomDocument doc;
+ doc.appendChild( doc.createProcessingInstruction( "xml","version=\"1.0\" encoding=\"UTF-8\"" ) );
+
+ QDomElement content = doc.createElement( "office:document-styles" );
+ content.setAttribute( "xmlns:office", "http://openoffice.org/2000/office" );
+ content.setAttribute( "xmlns:style", "http://openoffice.org/2000/style" );
+ content.setAttribute( "xmlns:text", "http://openoffice.org/2000/text" );
+ content.setAttribute( "xmlns:table", "http://openoffice.org/2000/table" );
+ content.setAttribute( "xmlns:draw", "http://openoffice.org/2000/drawing" );
+ content.setAttribute( "xmlns:fo", "http://www.w3.org/1999/XSL/Format" );
+ content.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
+ content.setAttribute( "xmlns:number", "http://openoffice.org/2000/datastyle" );
+ content.setAttribute( "xmlns:svg", "http://www.w3.org/2000/svg" );
+ content.setAttribute( "xmlns:chart", "http://openoffice.org/2000/chart" );
+ content.setAttribute( "xmlns:dr3d", "http://openoffice.org/2000/dr3d" );
+ content.setAttribute( "xmlns:math", "http://www.w3.org/1998/Math/MathML" );
+ content.setAttribute( "xmlns:form", "http://openoffice.org/2000/form" );
+ content.setAttribute( "xmlns:script", "http://openoffice.org/2000/script" );
+ content.setAttribute( "office:version", "1.0" );
+
+ // order important here!
+ QDomElement officeStyles = doc.createElement( "office:styles" );
+ exportDefaultCellStyle( doc, officeStyles );
+
+ QDomElement fontDecls = doc.createElement( "office:font-decls" );
+ m_styles.writeFontDecl( doc, fontDecls );
+
+ // TODO: needs in new number/date/time parser...
+ // exportDefaultNumberStyles( doc, officeStyles );
+
+ QDomElement defaultStyle = doc.createElement( "style:style" );
+ defaultStyle.setAttribute( "style:name", "Default" );
+ defaultStyle.setAttribute( "style:family", "table-cell" );
+ officeStyles.appendChild( defaultStyle );
+
+ QDomElement autoStyles = doc.createElement( "office:automatic-styles" );
+ exportPageAutoStyles( doc, autoStyles, ksdoc );
+
+ QDomElement masterStyles = doc.createElement( "office:master-styles" );
+ exportMasterStyles( doc, masterStyles, ksdoc );
+
+ content.appendChild( fontDecls );
+ content.appendChild( officeStyles );
+ content.appendChild( autoStyles );
+ content.appendChild( masterStyles );
+
+ doc.appendChild( content );
+
+ QCString f( doc.toCString() );
+ kdDebug(30518) << "Content: " << (char const * ) f << endl;
+
+ store->write( f, f.length() );
+
+ if ( !store->close() )
+ return false;
+
+ return true;
+}
+
+void OpenCalcExport::exportDefaultCellStyle( QDomDocument & doc, QDomElement & officeStyles )
+{
+ QDomElement defStyle = doc.createElement( "style:default-style" );
+ defStyle.setAttribute( "style:family", "table-cell" );
+
+ KoDocument * document = m_chain->inputDocument();
+ Doc * ksdoc = static_cast<Doc *>(document);
+
+ Format * format = new Format( 0, ksdoc->styleManager()->defaultStyle() );
+ const KLocale *locale = ksdoc->locale();
+ QString language;
+ QString country;
+ QString charSet;
+
+ QString l( locale->language() );
+ KLocale::splitLocale( l, language, country, charSet );
+ QFont font( format->font() );
+ m_styles.addFont( font, true );
+
+ QDomElement style = doc.createElement( "style:properties" );
+ style.setAttribute( "style:font-name", font.family() );
+ style.setAttribute( "fo:font-size", QString( "%1pt" ).arg( font.pointSize() ) );
+ style.setAttribute( "style:decimal-places", QString::number( locale->fracDigits() ) );
+ style.setAttribute( "fo:language", language );
+ style.setAttribute( "fo:country", country );
+ style.setAttribute( "style:font-name-asian", "HG Mincho Light J" );
+ style.setAttribute( "style:language-asian", "none" );
+ style.setAttribute( "style:country-asian", "none" );
+ style.setAttribute( "style:font-name-complex", "Arial Unicode MS" );
+ style.setAttribute( "style:language-complex", "none" );
+ style.setAttribute( "style:country-complex", "none" );
+ style.setAttribute( "style:tab-stop-distance", "1.25cm" );
+
+ defStyle.appendChild( style );
+ officeStyles.appendChild( defStyle );
+ delete format;
+}
+
+void OpenCalcExport::createDefaultStyles()
+{
+ // TODO: default number styles, currency styles,...
+}
+
+void OpenCalcExport::exportPageAutoStyles( QDomDocument & doc, QDomElement & autoStyles,
+ const Doc *ksdoc )
+{
+ QPtrListIterator<Sheet> it( ksdoc->map()->sheetList() );
+ const Sheet * sheet = it.toFirst();
+
+ float width = 20.999;
+ float height = 29.699;
+
+ if ( sheet )
+ {
+ width = sheet->print()->paperWidth() / 10;
+ height = sheet->print()->paperHeight() / 10;
+ }
+
+ QString sWidth = QString( "%1cm" ).arg( width );
+ QString sHeight = QString( "%1cm" ).arg( height );
+
+ QDomElement pageMaster = doc.createElement( "style:page-master" );
+ pageMaster.setAttribute( "style:name", "pm1" );
+
+ QDomElement properties = doc.createElement( "style:properties" );
+ properties.setAttribute( "fo:page-width", sWidth );
+ properties.setAttribute( "fo:page-height", sHeight );
+ properties.setAttribute( "fo:border", "0.002cm solid #000000" );
+ properties.setAttribute( "fo:padding", "0cm" );
+ properties.setAttribute( "fo:background-color", "transparent" );
+
+ pageMaster.appendChild( properties );
+
+ QDomElement header = doc.createElement( "style:header-style" );
+ properties = doc.createElement( "style:properties" );
+ properties.setAttribute( "fo:min-height", "0.75cm" );
+ properties.setAttribute( "fo:margin-left", "0cm" );
+ properties.setAttribute( "fo:margin-right", "0cm" );
+ properties.setAttribute( "fo:margin-bottom", "0.25cm" );
+
+ header.appendChild( properties );
+
+ QDomElement footer = doc.createElement( "style:header-style" );
+ properties = doc.createElement( "style:properties" );
+ properties.setAttribute( "fo:min-height", "0.75cm" );
+ properties.setAttribute( "fo:margin-left", "0cm" );
+ properties.setAttribute( "fo:margin-right", "0cm" );
+ properties.setAttribute( "fo:margin-bottom", "0.25cm" );
+
+ footer.appendChild( properties );
+
+ pageMaster.appendChild( header );
+ pageMaster.appendChild( footer );
+
+ autoStyles.appendChild( pageMaster );
+}
+
+void OpenCalcExport::exportMasterStyles( QDomDocument & doc, QDomElement & masterStyles,
+ const Doc * ksdoc )
+{
+ QDomElement masterPage = doc.createElement( "style:master-page" );
+ masterPage.setAttribute( "style:name", "Default" );
+ masterPage.setAttribute( "style:page-master-name", "pm1" );
+
+ QPtrListIterator<Sheet> it( ksdoc->map()->sheetList() );
+ const Sheet * sheet = it.toFirst();
+
+ QString headerLeft;
+ QString headerCenter;
+ QString headerRight;
+ QString footerLeft;
+ QString footerCenter;
+ QString footerRight;
+
+ if ( sheet )
+ {
+ headerLeft = sheet->print()->headLeft();
+ headerCenter = sheet->print()->headMid();
+ headerRight = sheet->print()->headRight();
+ footerLeft = sheet->print()->footLeft();
+ footerCenter = sheet->print()->footMid();
+ footerRight = sheet->print()->footRight();
+ }
+
+ if ( ( headerLeft.length() > 0 ) || ( headerCenter.length() > 0 )
+ || ( headerRight.length() > 0 ) )
+ {
+ QDomElement header = doc.createElement( "style:header" );
+ QDomElement left = doc.createElement( "style:region-left" );
+ QDomElement text = doc.createElement( "text:p" );
+ convertPart( headerLeft, doc, text, ksdoc );
+ left.appendChild( text );
+
+ QDomElement center = doc.createElement( "style:region-center" );
+ QDomElement text1 = doc.createElement( "text:p" );
+ convertPart( headerCenter, doc, text1, ksdoc );
+ center.appendChild( text1 );
+
+ QDomElement right = doc.createElement( "style:region-right" );
+ QDomElement text2 = doc.createElement( "text:p" );
+ convertPart( headerRight, doc, text2, ksdoc );
+ right.appendChild( text2 );
+
+ header.appendChild( left );
+ header.appendChild( center );
+ header.appendChild( right );
+
+ masterPage.appendChild( header );
+ }
+ else
+ {
+ QDomElement header = doc.createElement( "style:header" );
+ QDomElement text = doc.createElement( "text:p" );
+ QDomElement name = doc.createElement( "text:sheet-name" );
+ name.appendChild( doc.createTextNode( "???" ) );
+ text.appendChild( name );
+ header.appendChild( text );
+
+ masterPage.appendChild( header );
+ }
+
+ if ( ( footerLeft.length() > 0 ) || ( footerCenter.length() > 0 )
+ || ( footerRight.length() > 0 ) )
+ {
+ QDomElement footer = doc.createElement( "style:footer" );
+ QDomElement left = doc.createElement( "style:region-left" );
+ QDomElement text = doc.createElement( "text:p" );
+ convertPart( footerLeft, doc, text, ksdoc );
+ left.appendChild( text );
+
+ QDomElement center = doc.createElement( "style:region-center" );
+ QDomElement text1 = doc.createElement( "text:p" );
+ convertPart( footerCenter, doc, text1, ksdoc );
+ center.appendChild( text1 );
+
+ QDomElement right = doc.createElement( "style:region-right" );
+ QDomElement text2 = doc.createElement( "text:p" );
+ convertPart( footerRight, doc, text2, ksdoc );
+ right.appendChild( text2 );
+
+ footer.appendChild( left );
+ footer.appendChild( center );
+ footer.appendChild( right );
+
+ masterPage.appendChild( footer );
+ }
+ else
+ {
+ QDomElement footer = doc.createElement( "style:footer" );
+ QDomElement text = doc.createElement( "text:p" );
+ text.appendChild( doc.createTextNode( i18n( "Page " ) ) );
+ QDomElement number = doc.createElement( "text:page-number" );
+ number.appendChild( doc.createTextNode( "1" ) );
+ text.appendChild( number );
+ footer.appendChild( text );
+
+ masterPage.appendChild( footer );
+ }
+
+ masterStyles.appendChild( masterPage );
+}
+
+void OpenCalcExport::addText( QString const & text, QDomDocument & doc,
+ QDomElement & parent )
+{
+ if (text.length() > 0 )
+ parent.appendChild( doc.createTextNode( text ) );
+}
+
+void OpenCalcExport::convertPart( QString const & part, QDomDocument & doc,
+ QDomElement & parent, const Doc * ksdoc )
+{
+ QString text;
+ QString var;
+
+ bool inVar = false;
+ uint i = 0;
+ uint l = part.length();
+ while ( i < l )
+ {
+ if ( inVar || part[i] == '<' )
+ {
+ inVar = true;
+ var += part[i];
+ if ( part[i] == '>' )
+ {
+ inVar = false;
+ if ( var == "<page>" )
+ {
+ addText( text, doc, parent );
+
+ QDomElement page = doc.createElement( "text:page-number" );
+ page.appendChild( doc.createTextNode( "1" ) );
+ parent.appendChild( page );
+ }
+ else if ( var == "<pages>" )
+ {
+ addText( text, doc, parent );
+
+ QDomElement page = doc.createElement( "text:page-count" );
+ page.appendChild( doc.createTextNode( "99" ) );
+ parent.appendChild( page );
+ }
+ else if ( var == "<date>" )
+ {
+ addText( text, doc, parent );
+
+ QDomElement t = doc.createElement( "text:date" );
+ t.setAttribute( "text:date-value", "0-00-00" );
+ // todo: "style:data-style-name", "N2"
+ t.appendChild( doc.createTextNode( QDate::currentDate().toString() ) );
+ parent.appendChild( t );
+ }
+ else if ( var == "<time>" )
+ {
+ addText( text, doc, parent );
+
+ QDomElement t = doc.createElement( "text:time" );
+ t.appendChild( doc.createTextNode( QTime::currentTime().toString() ) );
+ parent.appendChild( t );
+ }
+ else if ( var == "<file>" ) // filepath + name
+ {
+ addText( text, doc, parent );
+
+ QDomElement t = doc.createElement( "text:file-name" );
+ t.setAttribute( "text:display", "full" );
+ t.appendChild( doc.createTextNode( "???" ) );
+ parent.appendChild( t );
+ }
+ else if ( var == "<name>" ) // filename
+ {
+ addText( text, doc, parent );
+
+ QDomElement t = doc.createElement( "text:title" );
+ t.appendChild( doc.createTextNode( "???" ) );
+ parent.appendChild( t );
+ }
+ else if ( var == "<author>" )
+ {
+ KoDocumentInfo * docInfo = ksdoc->documentInfo();
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
+
+ text += authorPage->fullName();
+
+ addText( text, doc, parent );
+ }
+ else if ( var == "<email>" )
+ {
+ KoDocumentInfo * docInfo = ksdoc->documentInfo();
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
+
+ text += authorPage->email();
+
+ addText( text, doc, parent );
+ }
+ else if ( var == "<org>" )
+ {
+ KoDocumentInfo * docInfo = ksdoc->documentInfo();
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>( docInfo->page( "author" ) );
+
+ text += authorPage->company();
+
+ addText( text, doc, parent );
+ }
+ else if ( var == "<sheet>" )
+ {
+ addText( text, doc, parent );
+
+ QDomElement s = doc.createElement( "text:sheet-name" );
+ s.appendChild( doc.createTextNode( "???" ) );
+ parent.appendChild( s );
+ }
+ else
+ {
+ // no known variable:
+ text += var;
+ addText( text, doc, parent );
+ }
+
+ text = "";
+ var = "";
+ }
+ }
+ else
+ {
+ text += part[i];
+ }
+ ++i;
+ }
+ if ( !text.isEmpty() || !var.isEmpty() )
+ {
+ //we don't have var at the end =>store it
+ addText( text+var, doc, parent );
+ }
+}
+
+QString OpenCalcExport::convertFormula( QString const & formula ) const
+{
+ QChar decimalSymbol( '.' );
+ if ( m_locale )
+ {
+ const QString decimal ( m_locale->decimalSymbol() );
+ if ( !decimal.isEmpty() )
+ {
+ decimalSymbol = decimal.at( 0 );
+ }
+ }
+
+ QString s;
+ QRegExp exp("(\\$?)([a-zA-Z]+)(\\$?)([0-9]+)");
+ int n = exp.search( formula, 0 );
+ kdDebug(30518) << "Exp: " << formula << ", n: " << n << ", Length: " << formula.length()
+ << ", Matched length: " << exp.matchedLength() << endl;
+
+ bool inQuote1 = false;
+ bool inQuote2 = false;
+ int i = 0;
+ int l = (int) formula.length();
+ if ( l <= 0 )
+ return formula;
+ while ( i < l )
+ {
+ if ( ( n != -1 ) && ( n < i ) )
+ {
+ n = exp.search( formula, i );
+ kdDebug(30518) << "Exp: " << formula.right( l - i ) << ", n: " << n << endl;
+ }
+ if ( formula[i] == '"' )
+ {
+ inQuote1 = !inQuote1;
+ s += formula[i];
+ ++i;
+ continue;
+ }
+ if ( formula[i] == '\'' )
+ {
+ // named area
+ inQuote2 = !inQuote2;
+ ++i;
+ continue;
+ }
+ if ( inQuote1 || inQuote2 )
+ {
+ s += formula[i];
+ ++i;
+ continue;
+ }
+ if ( ( formula[i] == '=' ) && ( formula[i + 1] == '=' ) )
+ {
+ s += '=';
+ ++i;++i;
+ continue;
+ }
+ if ( formula[i] == '!' )
+ {
+ insertBracket( s );
+ s += '.';
+ ++i;
+ continue;
+ }
+ else if ( formula[i] == decimalSymbol )
+ {
+ s += '.'; // decimal point
+ ++i;
+ continue;
+ }
+ if ( n == i )
+ {
+ int ml = exp.matchedLength();
+ if ( formula[ i + ml ] == '!' )
+ {
+ kdDebug(30518) << "No cell ref but sheet name" << endl;
+ s += formula[i];
+ ++i;
+ continue;
+ }
+ if ( ( i > 0 ) && ( formula[i - 1] != '!' ) )
+ s += "[.";
+ for ( int j = 0; j < ml; ++j )
+ {
+ s += formula[i];
+ ++i;
+ }
+ s += ']';
+ continue;
+ }
+
+ s += formula[i];
+ ++i;
+ }
+
+ return s;
+}
+
+bool OpenCalcExport::writeMetaFile( KoStore * store, uint filesWritten )
+{
+ store->enterDirectory( "META-INF" );
+ if ( !store->open( "manifest.xml" ) )
+ return false;
+
+ QDomImplementation impl;
+ QDomDocumentType type( impl.createDocumentType( "manifest:manifest", "-//OpenOffice.org//DTD Manifest 1.0//EN", "Manifest.dtd" ) );
+
+ QDomDocument meta( type );
+ meta.appendChild( meta.createProcessingInstruction( "xml","version=\"1.0\" encoding=\"UTF-8\"" ) );
+
+ QDomElement content = meta.createElement( "manifest:manifest" );
+ content.setAttribute( "xmlns:manifest", "http://openoffice.org/2001/manifest" );
+
+ QDomElement entry = meta.createElement( "manifest:file-entry" );
+ entry.setAttribute( "manifest:media-type", "application/vnd.sun.xml.calc" );
+ entry.setAttribute( "manifest:full-path", "/" );
+ content.appendChild( entry );
+
+ entry = meta.createElement( "manifest:file-entry" );
+ content.appendChild( entry );
+
+ if ( filesWritten & contentXML )
+ {
+ entry = meta.createElement( "manifest:file-entry" );
+ entry.setAttribute( "manifest:media-type", "text/xml" );
+ entry.setAttribute( "manifest:full-path", "content.xml" );
+ content.appendChild( entry );
+ }
+
+ if ( filesWritten & stylesXML )
+ {
+ entry = meta.createElement( "manifest:file-entry" );
+ entry.setAttribute( "manifest:media-type", "text/xml" );
+ entry.setAttribute( "manifest:full-path", "styles.xml" );
+ content.appendChild( entry );
+ }
+
+ if ( filesWritten & metaXML )
+ {
+ entry = meta.createElement( "manifest:file-entry" );
+ entry.setAttribute( "manifest:media-type", "text/xml" );
+ entry.setAttribute( "manifest:full-path", "meta.xml" );
+ content.appendChild( entry );
+ }
+
+ if ( filesWritten & settingsXML )
+ {
+ entry = meta.createElement( "manifest:file-entry" );
+ entry.setAttribute( "manifest:media-type", "text/xml" );
+ entry.setAttribute( "manifest:full-path", "settings.xml" );
+ content.appendChild( entry );
+ }
+
+ meta.appendChild( content );
+
+ QCString doc( meta.toCString() );
+ kdDebug(30518) << "Manifest: " << doc << endl;
+
+ store->write( doc, doc.length() );
+
+ if ( !store->close() )
+ return false;
+
+ return true;
+}
+
+#include <opencalcexport.moc>
diff --git a/filters/kspread/opencalc/opencalcexport.h b/filters/kspread/opencalc/opencalcexport.h
new file mode 100644
index 000000000..6a265fce5
--- /dev/null
+++ b/filters/kspread/opencalc/opencalcexport.h
@@ -0,0 +1,89 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000 - 2003 David Faure <faure@kde.org>
+ Copyright (C) 2003 Norbert Andres <nandres@web.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef OPENCALCEXPORT_H
+#define OPENCALCEXPORT_H
+
+#include "opencalcstyleexport.h"
+
+#include <KoFilter.h>
+#include <qptrlist.h>
+
+class QDomDocument;
+class QDomElement;
+class KLocale;
+class KoStore;
+
+namespace KSpread
+{
+class Doc;
+class Sheet;
+}
+
+class OpenCalcExport : public KoFilter
+{
+ Q_OBJECT
+
+ public:
+ OpenCalcExport( KoFilter * parent, const char * name, const QStringList & );
+ virtual ~OpenCalcExport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString & from,
+ const QCString & to );
+
+ private:
+ enum files { metaXML = 0x01, contentXML = 0x02, stylesXML = 0x04, settingsXML = 0x08 };
+ OpenCalcStyles m_styles;
+
+ bool writeFile( const KSpread::Doc * ksdoc );
+
+ bool exportDocInfo( KoStore * store, const KSpread::Doc * ksdoc );
+ bool exportStyles ( KoStore * store, const KSpread::Doc * ksdoc );
+ bool exportContent( KoStore * store, const KSpread::Doc * ksdoc );
+ bool exportSettings( KoStore * store, const KSpread::Doc * ksdoc );
+
+ bool exportBody( QDomDocument & doc, QDomElement & content, const KSpread::Doc * ksdoc );
+ void exportSheet( QDomDocument & doc, QDomElement & tabElem,
+ const KSpread::Sheet * sheet, int maxCols, int maxRows );
+ void exportCells( QDomDocument & doc, QDomElement & rowElem,
+ const KSpread::Sheet * sheet, int row, int maxCols );
+ void exportDefaultCellStyle( QDomDocument & doc, QDomElement & officeStyles );
+ void exportPageAutoStyles( QDomDocument & doc, QDomElement & autoStyles,
+ const KSpread::Doc * ksdoc );
+ void exportMasterStyles( QDomDocument & doc, QDomElement & masterStyles,
+ const KSpread::Doc *ksdoc );
+
+ bool writeMetaFile( KoStore * store, uint filesWritten );
+
+ void maxRowCols( const KSpread::Sheet * sheet,
+ int & maxCols, int & maxRows );
+ void convertPart( QString const & part, QDomDocument & doc,
+ QDomElement & parent, const KSpread::Doc * ksdoc );
+ void addText( QString const & text, QDomDocument & doc,
+ QDomElement & parent );
+
+ void createDefaultStyles();
+ QString convertFormula( QString const & formula ) const;
+private:
+ /// Pointer to the KSpread locale
+ KLocale* m_locale;
+};
+
+#endif
diff --git a/filters/kspread/opencalc/opencalcimport.cc b/filters/kspread/opencalc/opencalcimport.cc
new file mode 100644
index 000000000..8330519f1
--- /dev/null
+++ b/filters/kspread/opencalc/opencalcimport.cc
@@ -0,0 +1,2826 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Norbert Andres <nandres@web.de>
+ Copyright (C) 2004 - 2005 Laurent Montel <montel@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <float.h>
+#include <math.h>
+
+#include <qcolor.h>
+#include <qfile.h>
+#include <qfont.h>
+#include <qpen.h>
+#include <qxml.h>
+
+#include "opencalcimport.h"
+
+#include <kdebug.h>
+#include <KoDocumentInfo.h>
+#include <kgenericfactory.h>
+#include <kmessagebox.h>
+#include <kmdcodec.h>
+#include <KoFilterChain.h>
+#include <KoGlobal.h>
+#include <KoUnit.h>
+#include <KoStyleStack.h>
+#include <KoDom.h>
+#include <ooutils.h>
+
+#include <kspread_cell.h>
+#include <kspread_condition.h>
+#include <kspread_doc.h>
+#include <kspread_global.h>
+#include <kspread_map.h>
+#include <kspread_sheet.h>
+#include <kspread_sheetprint.h>
+#include <kspread_style.h>
+#include <kspread_style_manager.h>
+#include <kspread_util.h>
+#include <kspread_value.h>
+
+#define SECSPERDAY (24 * 60 * 60)
+
+using namespace KSpread;
+
+class OpenCalcImportFactory : KGenericFactory<OpenCalcImport, KoFilter>
+{
+public:
+ OpenCalcImportFactory(void) : KGenericFactory<OpenCalcImport, KoFilter> ("kspreadopencalcimport")
+ {}
+protected:
+ virtual void setupTranslations( void )
+ {
+ KGlobal::locale()->insertCatalogue( "kofficefilters" );
+ }
+};
+
+K_EXPORT_COMPONENT_FACTORY( libopencalcimport, OpenCalcImportFactory() )
+
+OpenCalcImport::OpenCalcPoint::OpenCalcPoint( QString const & str )
+ : isRange( false )
+{
+ bool inQuote = false;
+
+ int l = str.length();
+ int colonPos = -1;
+ QString range;
+
+ // replace '.' with '!'
+ for ( int i = 0; i < l; ++i )
+ {
+ if ( str[i] == '$' )
+ continue;
+ if ( str[i] == '\'' )
+ {
+ inQuote = !inQuote;
+ }
+ else if ( str[i] == '.' )
+ {
+ if ( !inQuote )
+ {
+ if ( i != 0 && i != (colonPos + 1) ) // no empty table names
+ range += '!';
+ }
+ else
+ range += '.';
+ }
+ else if ( str[i] == ':' )
+ {
+ if ( !inQuote )
+ {
+ isRange = true;
+ colonPos = i;
+ }
+ range += ':';
+ }
+ else
+ range += str[i];
+ }
+
+ translation = range;
+
+ if ( isRange )
+ {
+ KSpread::Range newRange( range );
+ table = newRange.sheetName();
+ topLeft = newRange.range().topLeft();
+ botRight = newRange.range().bottomRight();
+ }
+ else
+ {
+ Point newPoint( range );
+ table = newPoint.sheetName();
+ topLeft = newPoint.pos();
+ botRight = newPoint.pos();
+ }
+}
+
+
+OpenCalcImport::OpenCalcImport( KoFilter *, const char *, const QStringList & )
+ : KoFilter(),
+ m_styles( 17, true ),
+ m_defaultStyles( 17, true ),
+ m_formats( 17, true )
+{
+ m_styles.setAutoDelete( true );
+ m_defaultStyles.setAutoDelete( true );
+ m_formats.setAutoDelete( true );
+}
+
+OpenCalcImport::~OpenCalcImport()
+{
+}
+
+double timeToNum( int h, int m, int s )
+{
+ int secs = h * 3600 + m * 60 + s;
+ return (double) secs / (double) SECSPERDAY;
+}
+
+bool OpenCalcImport::readRowFormat( QDomElement & rowNode, QDomElement * rowStyle,
+ Sheet * table, int & row, int & number,
+ bool isLast )
+{
+ if ( rowNode.isNull() )
+ return false;
+
+ QDomNode node;
+ if ( rowStyle )
+ {
+ node = rowStyle->firstChild();
+ kdDebug(30518) << "RowStyle: " << rowStyle << ", " << rowStyle->tagName() << endl;
+ }
+
+ double height = -1.0;
+ bool insertPageBreak = false;
+ Format layout( table, table->doc()->styleManager()->defaultStyle() );
+
+ while( !node.isNull() )
+ {
+ QDomElement property = node.toElement();
+
+ kdDebug(30518) << "Row: Child exists: " << property.tagName() << endl;
+ if ( !property.isNull() && property.localName() == "properties" && property.namespaceURI() == ooNS::style )
+ {
+ if ( property.hasAttributeNS( ooNS::style, "row-height" ) )
+ {
+ height = KoUnit::parseValue( property.attributeNS( ooNS::style, "row-height", QString::null ) , -1 );
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "break-before" ) )
+ {
+ if ( property.attributeNS( ooNS::fo, "break-before", QString::null ) == "page" )
+ {
+ insertPageBreak = true;
+ }
+ }
+
+ loadStyleProperties( &layout, property );
+ }
+
+ node = node.nextSibling();
+ }
+
+ if ( rowNode.hasAttributeNS( ooNS::table, "number-rows-repeated" ) )
+ {
+ bool ok = true;
+ int n = rowNode.attributeNS( ooNS::table, "number-rows-repeated", QString::null ).toInt( &ok );
+ if ( ok )
+ number = n;
+ kdDebug(30518) << "Row repeated: " << number << endl;
+ }
+
+ if ( isLast )
+ {
+ if ( number > 30 )
+ number = 30;
+ }
+ else
+ {
+ if ( number > 256 )
+ number = 256;
+ }
+
+ for ( int i = 0; i < number; ++i )
+ {
+ RowFormat * rowL = table->nonDefaultRowFormat( row );
+ rowL->copy( layout );
+
+ if ( height != -1 )
+ {
+ kdDebug(30518) << "Setting row height to " << height << endl;
+ rowL->setHeight( int( height ) );
+ }
+
+ // if ( insertPageBreak ) TODO:
+ // rowL->setPageBreak( true )
+
+ // kdDebug(30518) << "Added RowFormat: " << row << endl;
+ ++row;
+ }
+
+ return true;
+}
+
+QString OpenCalcImport::translatePar( QString & par ) const
+{
+ OpenCalcPoint point( par );
+ kdDebug(30518) << " Parameter: " << par << ", Translation: " << point.translation << endl;
+
+ return point.translation;
+}
+
+void OpenCalcImport::checkForNamedAreas( QString & formula ) const
+{
+ int l = formula.length();
+ int i = 0;
+ QString word;
+ int start = 0;
+ while ( i < l )
+ {
+ if ( formula[i].isLetterOrNumber() )
+ {
+ word += formula[i];
+ ++i;
+ continue;
+ }
+ if ( word.length() > 0 )
+ {
+ if ( m_namedAreas.find( word ) != m_namedAreas.end() )
+ {
+ formula = formula.replace( start, word.length(), "'" + word + "'" );
+ l = formula.length();
+ ++i;
+ kdDebug(30518) << "Formula: " << formula << ", L: " << l << ", i: " << i + 1 <<endl;
+ }
+ }
+
+ ++i;
+ word = "";
+ start = i;
+ }
+ if ( word.length() > 0 )
+ {
+ if ( m_namedAreas.find( word ) != m_namedAreas.end() )
+ {
+ formula = formula.replace( start, word.length(), "'" + word + "'" );
+ l = formula.length();
+ ++i;
+ kdDebug(30518) << "Formula: " << formula << ", L: " << l << ", i: " << i + 1 <<endl;
+ }
+ }
+}
+
+void OpenCalcImport::convertFormula( QString & text, QString const & f ) const
+{
+ kdDebug(30518) << "Parsing formula: " << f << endl;
+
+ QString formula;
+ QString parameter;
+
+ int l = f.length();
+ int p = 0;
+
+ while ( p < l )
+ {
+ if ( f[p] == '(' || f[p] == '[' )
+ {
+ break;
+ }
+
+ formula += f[p];
+ ++p;
+ }
+
+ if ( parameter.isEmpty() )
+ {
+ checkForNamedAreas( formula );
+ }
+
+ kdDebug(30518) << "Formula: " << formula << ", Parameter: " << parameter << ", P: " << p << endl;
+
+
+ // replace formula names here
+ if ( formula == "=MULTIPLE.OPERATIONS" )
+ formula = "=MULTIPLEOPERATIONS";
+
+ QString par;
+ bool isPar = false;
+ bool inQuote = false;
+
+ while ( p < l )
+ {
+ if ( f[p] == '"' )
+ {
+ inQuote = !inQuote;
+ parameter += '"';
+ }
+ else if ( f[p] == '[' )
+ {
+ if ( !inQuote )
+ isPar = true;
+ else
+ parameter += '[';
+ }
+ else if ( f[p] == ']' )
+ {
+ if ( inQuote )
+ {
+ parameter += ']';
+ continue;
+ }
+
+ isPar = false;
+ parameter += translatePar( par );
+ par = "";
+ }
+ else if ( isPar )
+ {
+ par += f[p];
+ }
+ else if ( f[p] == '=' ) // TODO: check if StarCalc has a '==' sometimes
+ {
+ if ( inQuote )
+ parameter += '=';
+ else
+ parameter += "==";
+ }
+ else if ( f[p] == ')' )
+ {
+ if ( !inQuote )
+ parameter += ")";
+ }
+ else
+ parameter += f[p];
+
+ ++p;
+ if ( p == l )
+ checkForNamedAreas( parameter );
+ }
+
+ text = formula + parameter;
+ kdDebug(30518) << "New formula: " << text << endl;
+}
+
+bool OpenCalcImport::readCells( QDomElement & rowNode, Sheet * table, int row, int & columns )
+{
+ bool ok = true;
+ int spanC = 1;
+ int spanR = 1;
+ //Cell* defCell = table->defaultCell();
+
+ QDomNode cellNode = KoDom::namedItemNS( rowNode, ooNS::table, "table-cell" );
+
+ while ( !cellNode.isNull() )
+ {
+ spanR = 1; spanC = 1;
+
+ QDomElement e = cellNode.toElement();
+ if ( e.isNull() )
+ {
+ ++columns;
+
+ cellNode = cellNode.nextSibling();
+ continue;
+ }
+
+ Cell* cell = 0;
+
+ kdDebug(30518) << " Cell: " << columns << ", " << row << endl;
+
+ // ="3" table:number-rows-spanned="1"
+ if ( e.hasAttributeNS( ooNS::table, "number-columns-spanned" ) )
+ {
+ int span = e.attributeNS( ooNS::table, "number-columns-spanned", QString::null ).toInt( &ok );
+ if ( ok )
+ spanC = span;
+ }
+ if ( e.hasAttributeNS( ooNS::table, "number-rows-spanned" ) )
+ {
+ int span = e.attributeNS( ooNS::table, "number-rows-spanned", QString::null ).toInt( &ok );
+ if ( ok )
+ spanR = span;
+ }
+
+ QString text;
+ QDomElement textP = KoDom::namedItemNS( e, ooNS::text, "p" );
+ if ( !textP.isNull() )
+ {
+ QDomElement subText = textP.firstChild().toElement(); // ## wrong
+ if ( !subText.isNull() )
+ {
+ // something in <text:p>, e.g. links
+ text = subText.text();
+
+ if ( subText.hasAttributeNS( ooNS::xlink, "href" ) )
+ {
+ QString link = subText.attributeNS( ooNS::xlink, "href", QString::null );
+ if ( link[0]=='#' )
+ link=link.remove( 0, 1 );
+ if ( !cell )
+ cell = table->nonDefaultCell( columns, row );
+ cell->setLink( link );
+ }
+ }
+ else
+ text = textP.text(); // our text, could contain formating for value or result of formula
+ }
+ QDomElement annotation = KoDom::namedItemNS( e, ooNS::office, "annotation" );
+ if ( !annotation.isNull() )
+ {
+ QString comment;
+ QDomNode node = annotation.firstChild();
+ while( !node.isNull() )
+ {
+ QDomElement commentElement = node.toElement();
+ if( !commentElement.isNull() )
+ if ( commentElement.localName() == "p" && e.namespaceURI()==ooNS::text)
+ {
+ if( !comment.isEmpty() ) comment.append( '\n' );
+ comment.append( commentElement.text() );
+ }
+
+ node = node.nextSibling();
+ }
+
+ if( !comment.isEmpty() )
+ {
+ if ( !cell )
+ cell = table->nonDefaultCell( columns, row );
+ kdDebug(30518)<<" columns :"<<columns<<" row :"<<row<<endl;
+ cell->format()->setComment( comment );
+ }
+ }
+
+ kdDebug(30518) << "Contains: " << text << endl;
+ bool isFormula = false;
+
+ if ( e.hasAttributeNS( ooNS::table, "style-name" ) )
+ {
+ if ( !cell )
+ cell = table->nonDefaultCell( columns, row );
+
+ QString psName( "Default" );
+ if ( e.hasAttributeNS( ooNS::style, "parent-style-name" ) )
+ psName = e.attributeNS( ooNS::style, "parent-style-name", QString::null );
+
+ kdDebug(30518) << "Default style: " << psName << endl;
+ Format * layout = m_defaultStyles[psName];
+
+ if ( layout )
+ cell->format()->copy( *layout );
+
+ QDomElement * st = 0;
+ if ( e.hasAttributeNS( ooNS::table, "style-name" ) )
+ {
+ kdDebug(30518) << "Style: " << e.attributeNS( ooNS::table, "style-name", QString::null ) << endl;
+ st = m_styles[ e.attributeNS( ooNS::table, "style-name", QString::null ) ];
+ }
+ if ( st )
+ {
+ kdDebug(30518) << "Style: adapting " << endl;
+ QDomNode node = st->firstChild();
+ bool foundValidation = false;
+ while( !node.isNull() )
+ {
+ QDomElement property = node.toElement();
+ if ( !property.isNull() )
+ {
+ kdDebug(30518)<<"property.tagName() :"<<property.tagName()<<endl;
+ if ( property.localName()=="map" && property.namespaceURI() == ooNS::style && !foundValidation)
+ {
+ loadCondition( cell, property );
+ foundValidation = true;
+ }
+ if ( property.localName() == "properties" && property.namespaceURI() == ooNS::style )
+ {
+ loadStyleProperties( cell->format(), property );
+ if ( cell->format()->getAngle( columns, row ) != 0 )
+ {
+ QFontMetrics fm( cell->format()->textFont( columns, row ) );
+ int tmpAngle = cell->format()->getAngle( columns, row );
+ int textHeight = static_cast<int>( cos( tmpAngle * M_PI / 180 )
+ * ( fm.ascent() + fm.descent() )
+ + abs ( ( int )( fm.width( cell->strOutText() )
+ * sin( tmpAngle * M_PI / 180 ) ) ) );
+ /*
+ int textWidth = static_cast<int>( abs ( ( int ) ( sin( tmpAngle * M_PI / 180 )
+ * ( fm.ascent() + fm.descent() ) ) )
+ + fm.width( cell->strOutText() )
+ * cos( tmpAngle * M_PI / 180 ) );
+ */
+ kdDebug(30518) << "Rotation: height: " << textHeight << endl;
+
+ RowFormat * l = table->rowFormat( row );
+ if ( l->height() < textHeight )
+ {
+ if ( l->isDefault() )
+ l = table->nonDefaultRowFormat( row );
+
+ l->setHeight( textHeight + 2 );
+ }
+ }
+ }
+ }
+ node = node.nextSibling();
+ }
+ }
+ }
+ else
+ {
+ if ( !cell )
+ cell = table->nonDefaultCell( columns, row );
+
+ QString psName( "Default" );
+ kdDebug(30518) << "Default style: " << psName << endl;
+ Format * layout = m_defaultStyles[psName];
+
+ if ( layout )
+ cell->format()->copy( *layout );
+ }
+ if ( e.hasAttributeNS( ooNS::table, "formula" ) )
+ {
+ isFormula = true;
+ QString formula;
+ convertFormula( formula, e.attributeNS( ooNS::table, "formula", QString::null ) );
+
+ if ( !cell )
+ cell = table->nonDefaultCell( columns, row );
+ cell->setCellText( formula );
+ }
+ if ( e.hasAttributeNS( ooNS::table, "validation-name" ) )
+ {
+ kdDebug(30518)<<" Celle has a validation :"<<e.attributeNS( ooNS::table, "validation-name", QString::null )<<endl;
+ loadOasisValidation( cell->getValidity(), e.attributeNS( ooNS::table, "validation-name", QString::null ) );
+ }
+ if ( e.hasAttributeNS( ooNS::table, "value-type" ) )
+ {
+ if ( !cell )
+ cell = table->nonDefaultCell( columns, row );
+
+ cell->setCellText( text );
+
+ QString value = e.attributeNS( ooNS::table, "value", QString::null );
+ QString type = e.attributeNS( ooNS::table, "value-type", QString::null );
+
+ kdDebug(30518) << "Value: " << value << ", type: " << type << endl;
+
+ bool ok = false;
+ double dv = 0.0;
+
+ if ( ( type == "float" ) || ( type == "currency" ) )
+ {
+ dv = value.toDouble( &ok );
+ if ( ok )
+ {
+ if ( !isFormula )
+ cell->setValue( dv );
+
+ if ( type == "currency" )
+ {
+ cell->format()->setCurrency( 1, e.attributeNS( ooNS::table, "currency", QString::null ) );
+ cell->format()->setFormatType( Money_format );
+ }
+ }
+ }
+ else
+ if ( type == "percentage" )
+ {
+ dv = value.toDouble( &ok );
+ if ( ok )
+ {
+ if ( !isFormula )
+ cell->setValue( dv );
+ //TODO fixme
+ //cell->setFactor( 100 );
+ // TODO: replace with custom...
+ cell->format()->setFormatType( Percentage_format );
+ }
+ }
+ else if ( type == "boolean" )
+ {
+ if ( value.isEmpty() )
+ value = e.attributeNS( ooNS::table, "boolean-value", QString::null );
+
+ kdDebug(30518) << "Type: boolean" << endl;
+ if ( value == "true" )
+ cell->setValue( true );
+ else
+ cell->setValue( false );
+ ok = true;
+ cell->format()->setFormatType( Custom_format );
+ }
+ else if ( type == "date" )
+ {
+ if ( value.isEmpty() )
+ value = e.attributeNS( ooNS::table, "date-value", QString::null );
+ kdDebug(30518) << "Type: date, value: " << value << endl;
+
+ // "1980-10-15"
+ int year=0, month=0, day=0;
+ ok = false;
+
+ int p1 = value.find( '-' );
+ if ( p1 > 0 )
+ year = value.left( p1 ).toInt( &ok );
+
+ kdDebug(30518) << "year: " << value.left( p1 ) << endl;
+
+ int p2 = value.find( '-', ++p1 );
+
+ if ( ok )
+ month = value.mid( p1, p2 - p1 ).toInt( &ok );
+
+ kdDebug(30518) << "month: " << value.mid( p1, p2 - p1 ) << endl;
+
+ if ( ok )
+ day = value.right( value.length() - p2 - 1 ).toInt( &ok );
+
+ kdDebug(30518) << "day: " << value.right( value.length() - p2 ) << endl;
+
+ if ( ok )
+ {
+ QDateTime dt( QDate( year, month, day ) );
+ // KSpreadValue kval( dt );
+ // cell->setValue( kval );
+ cell->setValue( QDate( year, month, day ) );
+ kdDebug(30518) << "Set QDate: " << year << " - " << month << " - " << day << endl;
+ }
+ }
+ else if ( type == "time" )
+ {
+ if ( value.isEmpty() )
+ value = e.attributeNS( ooNS::table, "time-value", QString::null );
+
+ kdDebug(30518) << "Type: time: " << value << endl;
+ // "PT15H10M12S"
+ int hours=0, minutes=0, seconds=0;
+ int l = value.length();
+ QString num;
+
+ for ( int i = 0; i < l; ++i )
+ {
+ if ( value[i].isNumber() )
+ {
+ num += value[i];
+ continue;
+ }
+ else if ( value[i] == 'H' )
+ hours = num.toInt( &ok );
+ else if ( value[i] == 'M' )
+ minutes = num.toInt( &ok );
+ else if ( value[i] == 'S' )
+ seconds = num.toInt( &ok );
+ else
+ continue;
+
+ kdDebug(30518) << "Num: " << num << endl;
+
+ num = "";
+ if ( !ok )
+ break;
+ }
+
+ kdDebug(30518) << "Hours: " << hours << ", " << minutes << ", " << seconds << endl;
+
+ if ( ok )
+ {
+ // KSpreadValue kval( timeToNum( hours, minutes, seconds ) );
+ // cell->setValue( kval );
+ cell->setValue( QTime( hours % 24, minutes, seconds ) );
+ cell->format()->setFormatType( Custom_format );
+ }
+ }
+
+
+ if ( !ok ) // just in case we couldn't set the value directly
+ cell->setCellText( text );
+ }
+ else if ( !text.isEmpty() )
+ {
+ if ( !cell )
+ cell = table->nonDefaultCell( columns, row );
+ cell->setCellText( text );
+ }
+
+ if ( spanR > 1 || spanC > 1 )
+ {
+ if ( !cell )
+ cell = table->nonDefaultCell( columns, row );
+ cell->mergeCells( columns, row, spanC - 1, spanR - 1 );
+ }
+
+ cellNode = cellNode.nextSibling();
+
+ if ( e.hasAttributeNS( ooNS::table, "number-columns-repeated" ) )
+ {
+ // copy cell from left
+ bool ok = false;
+ int number = e.attributeNS( ooNS::table, "number-columns-repeated", QString::null ).toInt( &ok );
+ Cell* cellDest = 0;
+
+ // don't repeat more than 10 if it is the last cell and empty
+ if ( !ok || cellNode.isNull() )
+ {
+ if ( number > 10 )
+ number = 10;
+ }
+
+ for ( int i = 1; i < number; ++i )
+ {
+ ++columns;
+
+ if ( cell )
+ {
+ cellDest = table->nonDefaultCell( columns, row );
+ cellDest->copyAll( cell );
+ }
+ }
+ }
+
+ ++columns;
+ }
+
+ return true;
+}
+
+
+void OpenCalcImport::loadCondition( Cell*cell,const QDomElement &property )
+{
+ kdDebug(30518)<<"void OpenCalcImport::loadCondition( Cell*cell,const QDomElement &property )*******\n";
+ loadOasisCondition( cell, property );
+}
+
+void OpenCalcImport::loadOasisCondition(Cell*cell,const QDomElement &property )
+{
+ QDomElement elementItem( property );
+ StyleManager * manager = cell->sheet()->doc()->styleManager();
+
+ QValueList<Conditional> cond;
+ while ( !elementItem.isNull() )
+ {
+ kdDebug(30518)<<"elementItem.tagName() :"<<elementItem.tagName()<<endl;
+
+ if ( elementItem.localName()== "map" && property.namespaceURI() == ooNS::style )
+ {
+ bool ok = true;
+ kdDebug(30518)<<"elementItem.attribute(style:condition ) :"<<elementItem.attributeNS( ooNS::style, "condition", QString::null )<<endl;
+ Conditional newCondition;
+ loadOasisConditionValue( elementItem.attributeNS( ooNS::style, "condition", QString::null ), newCondition );
+ if ( elementItem.hasAttributeNS( ooNS::style, "apply-style-name" ) )
+ {
+ kdDebug(30518)<<"elementItem.attribute( style:apply-style-name ) :"<<elementItem.attributeNS( ooNS::style, "apply-style-name", QString::null )<<endl;
+ newCondition.styleName = new QString( elementItem.attributeNS( ooNS::style, "apply-style-name", QString::null ) );
+ newCondition.style = manager->style( *newCondition.styleName );
+ if ( !newCondition.style )
+ ok = false;
+ else
+ ok = true;
+ }
+
+ if ( ok )
+ cond.append( newCondition );
+ else
+ kdDebug(30518) << "Error loading condition " << elementItem.nodeName()<< endl;
+ }
+ elementItem = elementItem.nextSibling().toElement();
+ }
+ if ( !cond.isEmpty() )
+ cell->setConditionList( cond );
+}
+
+void OpenCalcImport::loadOasisConditionValue( const QString &styleCondition, Conditional &newCondition )
+{
+ QString val( styleCondition );
+ if ( val.contains( "cell-content()" ) )
+ {
+ val = val.remove( "cell-content()" );
+ loadOasisCondition( val,newCondition );
+ }
+ //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
+ //for the moment we support just int/double value, not text/date/time :(
+ if ( val.contains( "cell-content-is-between(" ) )
+ {
+ val = val.remove( "cell-content-is-between(" );
+ val = val.remove( ")" );
+ QStringList listVal = QStringList::split( "," , val );
+ loadOasisValidationValue( listVal, newCondition );
+ newCondition.cond = Conditional::Between;
+ }
+ if ( val.contains( "cell-content-is-not-between(" ) )
+ {
+ val = val.remove( "cell-content-is-not-between(" );
+ val = val.remove( ")" );
+ QStringList listVal = QStringList::split( ",", val );
+ loadOasisValidationValue( listVal,newCondition );
+ newCondition.cond = Conditional::Different;
+ }
+
+}
+
+
+void OpenCalcImport::loadOasisCondition( QString &valExpression, Conditional &newCondition )
+{
+ QString value;
+ if (valExpression.find( "<=" )==0 )
+ {
+ value = valExpression.remove( 0,2 );
+ newCondition.cond = Conditional::InferiorEqual;
+ }
+ else if (valExpression.find( ">=" )==0 )
+ {
+ value = valExpression.remove( 0,2 );
+ newCondition.cond = Conditional::SuperiorEqual;
+ }
+ else if (valExpression.find( "!=" )==0 )
+ {
+ //add Differentto attribute
+ value = valExpression.remove( 0,2 );
+ newCondition.cond = Conditional::DifferentTo;
+ }
+ else if ( valExpression.find( "<" )==0 )
+ {
+ value = valExpression.remove( 0,1 );
+ newCondition.cond = Conditional::Inferior;
+ }
+ else if(valExpression.find( ">" )==0 )
+ {
+ value = valExpression.remove( 0,1 );
+ newCondition.cond = Conditional::Superior;
+ }
+ else if (valExpression.find( "=" )==0 )
+ {
+ value = valExpression.remove( 0,1 );
+ newCondition.cond = Conditional::Equal;
+ }
+ else
+ kdDebug(30518)<<" I don't know how to parse it :"<<valExpression<<endl;
+ kdDebug(30518)<<" value :"<<value<<endl;
+ bool ok = false;
+ newCondition.val1 = value.toDouble(&ok);
+ if ( !ok )
+ {
+ newCondition.val1 = value.toInt(&ok);
+ if ( !ok )
+ {
+ newCondition.strVal1 = new QString( value );
+ kdDebug(30518)<<" Try to parse this value :"<<value<<endl;
+ }
+
+ }
+}
+
+
+void OpenCalcImport::loadOasisValidationValue( const QStringList &listVal, Conditional &newCondition )
+{
+ bool ok = false;
+ kdDebug(30518)<<" listVal[0] :"<<listVal[0]<<" listVal[1] :"<<listVal[1]<<endl;
+
+ newCondition.val1 = listVal[0].toDouble(&ok);
+ if ( !ok )
+ {
+ newCondition.val1 = listVal[0].toInt(&ok);
+ if ( !ok )
+ {
+ newCondition.strVal1 = new QString( listVal[0] );
+ kdDebug(30518)<<" Try to parse this value :"<<listVal[0]<<endl;
+ }
+ }
+ ok=false;
+ newCondition.val2 = listVal[1].toDouble(&ok);
+ if ( !ok )
+ {
+ newCondition.val2 = listVal[1].toInt(&ok);
+ if ( !ok )
+ {
+ newCondition.strVal2 = new QString( listVal[1] );
+ kdDebug(30518)<<" Try to parse this value :"<<listVal[1]<<endl;
+ }
+ }
+}
+
+
+bool OpenCalcImport::readRowsAndCells( QDomElement & content, Sheet * table )
+{
+ kdDebug(30518) << endl << "Reading in rows " << endl;
+
+ int i = 1;
+ int row = 1;
+ int columns = 1;
+ int backupRow = 1;
+ QDomElement * rowStyle = 0;
+ //Cell* cell = 0;
+ //Cell* cellDest = 0;
+ //Cell* defCell = table->defaultCell();
+ QDomNode rowNode = KoDom::namedItemNS( content, ooNS::table, "table-row" );
+
+ while ( !rowNode.isNull() )
+ {
+ bool collapsed = false;
+
+ int number = 1;
+ QDomElement r = rowNode.toElement();
+
+ if ( r.isNull() )
+ return false;
+
+ if ( r.hasAttributeNS( ooNS::table, "style-name" ) )
+ {
+ QString style = r.attributeNS( ooNS::table, "style-name", QString::null );
+ rowStyle = m_styles[ style ];
+ kdDebug(30518) << "Row style: " << style << endl;
+ }
+
+ collapsed = ( r.attributeNS( ooNS::table, "visibility", QString::null ) == "collapse" );
+
+ backupRow = row;
+
+ rowNode = rowNode.nextSibling();
+
+ if ( !readRowFormat( r, rowStyle, table, row, number, rowNode.isNull() ) ) // updates "row"
+ return false;
+
+ if ( !readCells( r, table, backupRow, columns ) )
+ return false;
+
+ RowFormat * srcLayout = table->nonDefaultRowFormat( backupRow );
+ RowFormat * layout = 0;
+
+ if ( collapsed )
+ srcLayout->setHide( true );
+
+ for ( i = 1; i < number; ++i )
+ {
+ layout = table->nonDefaultRowFormat( backupRow + i );
+
+ layout->copy( *srcLayout );
+
+ /*
+ * TODO: Test: do we need to copy the cells, too?
+ * if so we will probably also need to copy them for repeated col layouts.
+ for ( j = 1; j <= columns; ++j )
+ {
+ Cell* cell = table->cellAt( j, backupRow );
+
+ kdDebug(30518) << "Cell: " << cell << "DefCell: " << defCell << endl;
+ if ( cell && (cell != defCell) )
+ {
+ cellDest = table->nonDefaultCell( j, backupRow + i );
+ cellDest->copyAll( cell );
+ }
+ }
+ */
+ }
+
+ rowStyle = 0;
+ columns = 1;
+ }
+
+ kdDebug(30518) << "Reading in rows done" << endl << endl;
+
+ return true;
+}
+
+bool OpenCalcImport::readColLayouts( QDomElement & content, Sheet * table )
+{
+ kdDebug(30518) << endl << "Reading in columns..." << endl;
+
+ QDomNode colLayout = KoDom::namedItemNS( content, ooNS::table, "table-column" );
+ int column = 1;
+
+ while ( !colLayout.isNull() )
+ {
+ if ( colLayout.nodeName() != "table:table-column" )
+ return true; // all cols read in.
+
+ QDomElement e = colLayout.toElement();
+
+ if ( e.isNull() )
+ return false; // error, that's it...
+
+ kdDebug(30518) << "New column: " << column << endl;
+
+ int number = 1;
+ double width = -1.0;
+ bool collapsed = ( e.attributeNS( ooNS::table, "visibility", QString::null ) == "collapse" );
+ bool insertPageBreak = false;
+ Format styleLayout( table, table->doc()->styleManager()->defaultStyle() );
+
+ kdDebug(30518) << "Check table:number-columns-repeated" << endl;
+ if ( e.hasAttributeNS( ooNS::table, "number-columns-repeated" ) )
+ {
+ bool ok = true;
+ number = e.attributeNS( ooNS::table, "number-columns-repeated", QString::null ).toInt( &ok );
+ if ( !ok )
+ number = 1;
+
+ kdDebug(30518) << "Repeated: " << number << endl;
+ }
+
+ kdDebug(30518) << "Checking table:default-cell-style-name" << endl;
+ if ( e.hasAttributeNS( ooNS::table, "default-cell-style-name" ) )
+ {
+ QString n( e.attributeNS( ooNS::table, "default-cell-style-name", QString::null ) );
+ kdDebug(30518) << "Has attribute default-cell-style-name: " << n << endl;
+ Format * defaultStyle = m_defaultStyles[ n ];
+ if ( !defaultStyle )
+ {
+ QString name = e.attributeNS( ooNS::table, "default-cell-style-name", QString::null );
+ QDomElement * st = m_styles[ name ];
+
+ kdDebug(30518) << "Default cell style: " << name << endl;
+
+ if ( st && !st->isNull() )
+ {
+ Format * layout = new Format( 0, m_doc->styleManager()->defaultStyle() );
+
+ readInStyle( layout, *st );
+
+ m_defaultStyles.insert( name, layout );
+ kdDebug(30518) << "Insert default cell style: " << name << endl;
+
+ defaultStyle = layout;
+ }
+ }
+
+ if ( defaultStyle )
+ {
+ // kdDebug(30518) << "Copying default style, Font: " << defaultStyle->font().toString() << endl;
+ styleLayout.copy( *defaultStyle );
+ }
+ }
+
+ QDomElement * colStyle = 0;
+ if ( e.hasAttributeNS( ooNS::table, "style-name" ) )
+ {
+ QString style = e.attributeNS( ooNS::table, "style-name", QString::null );
+ colStyle = m_styles[ style ];
+
+ kdDebug(30518) << "Col Style: " << style << endl;
+ }
+
+ QDomNode node;
+
+ if ( colStyle )
+ node = colStyle->firstChild();
+
+ while( !node.isNull() )
+ {
+ QDomElement property = node.toElement();
+ if ( !property.isNull() && property.localName() == "properties" && property.namespaceURI() == ooNS::style )
+ {
+ if ( property.hasAttributeNS( ooNS::style, "column-width" ) )
+ {
+ QString sWidth = property.attributeNS( ooNS::style, "column-width", QString::null );
+ width = KoUnit::parseValue( property.attributeNS( ooNS::style, "column-width", QString::null ), width );
+ kdDebug(30518) << "Col Width: " << sWidth << endl;
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "break-before" ) )
+ {
+ if ( property.attributeNS( ooNS::fo, "break-before", QString::null ) == "page" )
+ {
+ insertPageBreak = true;
+ }
+ }
+
+ loadStyleProperties( &styleLayout, property );
+ }
+
+ node = node.nextSibling();
+ }
+
+ colLayout = colLayout.nextSibling();
+
+ if ( colLayout.isNull() && ( number > 30 ) )
+ number = 30;
+
+ for ( int i = 0; i < number; ++i )
+ {
+ kdDebug(30518) << "Inserting colLayout: " << column << endl;
+
+ ColumnFormat * col = new ColumnFormat( table, column );
+ col->copy( styleLayout );
+ if ( width != -1.0 )
+ col->setWidth( int( width ) );
+
+ // if ( insertPageBreak )
+ // col->setPageBreak( true )
+
+ if ( collapsed )
+ col->setHide( true );
+
+ table->insertColumnFormat( col );
+ ++column;
+ }
+ }
+
+ return true;
+}
+
+void replaceMacro( QString & text, QString const & old, QString const & newS )
+{
+ int n = text.find( old );
+ if ( n != -1 )
+ text = text.replace( n, old.length(), newS );
+}
+
+QString getPart( QDomNode const & part )
+{
+ QString result;
+ QDomElement e = KoDom::namedItemNS( part, ooNS::text, "p" );
+ while ( !e.isNull() )
+ {
+ QString text = e.text();
+ kdDebug(30518) << "PART: " << text << endl;
+
+ QDomElement macro = KoDom::namedItemNS( e, ooNS::text, "time" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<time>" );
+
+ macro = KoDom::namedItemNS( e, ooNS::text, "date" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<date>" );
+
+ macro = KoDom::namedItemNS( e, ooNS::text, "page-number" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<page>" );
+
+ macro = KoDom::namedItemNS( e, ooNS::text, "page-count" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<pages>" );
+
+ macro = KoDom::namedItemNS( e, ooNS::text, "sheet-name" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<sheet>" );
+
+ macro = KoDom::namedItemNS( e, ooNS::text, "title" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<name>" );
+
+ macro = KoDom::namedItemNS( e, ooNS::text, "file-name" );
+ if ( !macro.isNull() )
+ replaceMacro( text, macro.text(), "<file>" );
+
+ if ( !result.isEmpty() )
+ result += '\n';
+ result += text;
+ e = e.nextSibling().toElement();
+ }
+
+ return result;
+}
+
+void OpenCalcImport::loadTableMasterStyle( Sheet * table,
+ QString const & stylename )
+{
+ kdDebug(30518) << "Loading table master style: " << stylename << endl;
+
+ QDomElement * style = m_styles[ stylename ];
+
+ if ( !style )
+ {
+ kdDebug(30518) << "Master style not found! " << endl;
+ return;
+ }
+
+ QDomNode header = KoDom::namedItemNS( *style, ooNS::style, "header" );
+ kdDebug(30518) << "Style header " << endl;
+
+ QString hleft, hmiddle, hright;
+ QString fleft, fmiddle, fright;
+
+ if ( !header.isNull() )
+ {
+ kdDebug(30518) << "Header exists" << endl;
+ QDomNode part = KoDom::namedItemNS( header, ooNS::style, "region-left" );
+ if ( !part.isNull() )
+ {
+ hleft = getPart( part );
+ kdDebug(30518) << "Header left: " << hleft << endl;
+ }
+ else
+ kdDebug(30518) << "Style:region:left doesn't exist!" << endl;
+ part = KoDom::namedItemNS( header, ooNS::style, "region-center" );
+ if ( !part.isNull() )
+ {
+ hmiddle = getPart( part );
+ kdDebug(30518) << "Header middle: " << hmiddle << endl;
+ }
+ part = KoDom::namedItemNS( header, ooNS::style, "region-right" );
+ if ( !part.isNull() )
+ {
+ hright = getPart( part );
+ kdDebug(30518) << "Header right: " << hright << endl;
+ }
+ }
+
+ QDomNode footer = KoDom::namedItemNS( *style, ooNS::style, "footer" );
+
+ if ( !footer.isNull() )
+ {
+ QDomNode part = KoDom::namedItemNS( footer, ooNS::style, "region-left" );
+ if ( !part.isNull() )
+ {
+ fleft = getPart( part );
+ kdDebug(30518) << "Footer left: " << fleft << endl;
+ }
+ part = KoDom::namedItemNS( footer, ooNS::style, "region-center" );
+ if ( !part.isNull() )
+ {
+ fmiddle = getPart( part );
+ kdDebug(30518) << "Footer middle: " << fmiddle << endl;
+ }
+ part = KoDom::namedItemNS( footer, ooNS::style, "region-right" );
+ if ( !part.isNull() )
+ {
+ fright = getPart( part );
+ kdDebug(30518) << "Footer right: " << fright << endl;
+ }
+ }
+
+ table->print()->setHeadFootLine( hleft, hmiddle, hright,
+ fleft, fmiddle, fright );
+ if ( style->hasAttributeNS( ooNS::style, "page-master-name" ) )
+ {
+ QString masterPageLayoutStyleName=style->attributeNS( ooNS::style, "page-master-name", QString::null );
+ kdDebug(30518)<<"masterPageLayoutStyleName :"<<masterPageLayoutStyleName<<endl;
+ QDomElement *masterLayoutStyle = m_styles[masterPageLayoutStyleName];
+ kdDebug(30518)<<"masterLayoutStyle :"<<masterLayoutStyle<<endl;
+ if ( !masterLayoutStyle )
+ return;
+ KoStyleStack styleStack( ooNS::style, ooNS::fo );
+ styleStack.push( *masterLayoutStyle );
+ loadOasisMasterLayoutPage( table, styleStack );
+ }
+}
+
+void OpenCalcImport::loadOasisMasterLayoutPage( Sheet * table,KoStyleStack &styleStack )
+{
+ float left = 0.0;
+ float right = 0.0;
+ float top = 0.0;
+ float bottom = 0.0;
+ float width = 0.0;
+ float height = 0.0;
+ QString orientation = "Portrait";
+ QString format;
+
+ // Laurent : Why we stored layout information as Millimeter ?!!!!!
+ // kspread used point for all other attribute
+ // I don't understand :(
+ if ( styleStack.hasAttributeNS( ooNS::fo, "page-width" ) )
+ {
+ width = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "page-width" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( ooNS::fo, "page-height" ) )
+ {
+ height = KoUnit::toMM( KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "page-height" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( ooNS::fo, "margin-top" ) )
+ {
+ top = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "margin-top" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( ooNS::fo, "margin-bottom" ) )
+ {
+ bottom = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "margin-bottom" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( ooNS::fo, "margin-left" ) )
+ {
+ left = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "margin-left" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( ooNS::fo, "margin-right" ) )
+ {
+ right = KoUnit::toMM(KoUnit::parseValue( styleStack.attributeNS( ooNS::fo, "margin-right" ) ) );
+ }
+ if ( styleStack.hasAttributeNS( ooNS::style, "writing-mode" ) )
+ {
+ kdDebug(30518)<<"styleStack.hasAttribute( style:writing-mode ) :"<<styleStack.hasAttributeNS( ooNS::style, "writing-mode" )<<endl;
+ }
+ if ( styleStack.hasAttributeNS( ooNS::style, "print-orientation" ) )
+ {
+ orientation = ( styleStack.attributeNS( ooNS::style, "print-orientation" )=="landscape" ) ? "Landscape" : "Portrait" ;
+ }
+ if ( styleStack.hasAttributeNS( ooNS::style, "num-format" ) )
+ {
+ kdDebug(30518)<<" num-format :"<<styleStack.attributeNS( ooNS::style, "num-format" )<<endl;
+ //todo fixme
+ }
+ if ( styleStack.hasAttributeNS( ooNS::fo, "background-color" ) )
+ {
+ //todo
+ kdDebug(30518)<<" fo:background-color :"<<styleStack.attributeNS( ooNS::fo, "background-color" )<<endl;
+ }
+ if ( styleStack.hasAttributeNS( ooNS::style, "print" ) )
+ {
+ //todo parsing
+ QString str = styleStack.attributeNS( ooNS::style, "print" );
+ kdDebug(30518)<<" style:print :"<<str<<endl;
+
+ if (str.contains( "headers" ) )
+ {
+ //todo implement it into kspread
+ }
+ if ( str.contains( "grid" ) )
+ {
+ table->print()->setPrintGrid( true );
+ }
+ if ( str.contains( "annotations" ) )
+ {
+ //todo it's not implemented
+ }
+ if ( str.contains( "objects" ) )
+ {
+ //todo it's not implemented
+ }
+ if ( str.contains( "charts" ) )
+ {
+ //todo it's not implemented
+ }
+ if ( str.contains( "drawings" ) )
+ {
+ //todo it's not implemented
+ }
+ if ( str.contains( "formulas" ) )
+ {
+ table->setShowFormula(true);
+ }
+ if ( str.contains( "zero-values" ) )
+ {
+ //todo it's not implemented
+ }
+ }
+ if ( styleStack.hasAttributeNS( ooNS::style, "table-centering" ) )
+ {
+ QString str = styleStack.attributeNS( ooNS::style, "table-centering" );
+ //not implemented into kspread
+ kdDebug(30518)<<" styleStack.attribute( style:table-centering ) :"<<str<<endl;
+#if 0
+ if ( str == "horizontal" )
+ {
+ }
+ else if ( str == "vertical" )
+ {
+ }
+ else if ( str == "both" )
+ {
+ }
+ else if ( str == "none" )
+ {
+ }
+ else
+ kdDebug(30518)<<" table-centering unknown :"<<str<<endl;
+#endif
+ }
+ format = QString( "%1x%2" ).arg( width ).arg( height );
+ kdDebug(30518)<<" format : "<<format<<endl;
+ table->print()->setPaperLayout( left, top, right, bottom, format, orientation );
+
+ kdDebug(30518)<<" left margin :"<<left<<" right :"<<right<<" top :"<<top<<" bottom :"<<bottom<<endl;
+//<style:properties fo:page-width="21.8cm" fo:page-height="28.801cm" fo:margin-top="2cm" fo:margin-bottom="2.799cm" fo:margin-left="1.3cm" fo:margin-right="1.3cm" style:writing-mode="lr-tb"/>
+// QString format = paper.attribute( "format" );
+// QString orientation = paper.attribute( "orientation" );
+// m_pPrint->setPaperLayout( left, top, right, bottom, format, orientation );
+// }
+}
+
+
+bool OpenCalcImport::parseBody( int numOfTables )
+{
+ QDomElement content = m_content.documentElement();
+ QDomNode body = KoDom::namedItemNS( content, ooNS::office, "body" );
+
+ if ( body.isNull() )
+ return false;
+
+ loadOasisAreaName( body.toElement() );
+ loadOasisCellValidation( body.toElement() );
+
+ Sheet * table;
+ QDomNode sheet = KoDom::namedItemNS( body, ooNS::table, "table" );
+
+ kdDebug()<<" sheet :"<<sheet.isNull()<<endl;
+ if ( sheet.isNull() )
+ return false;
+
+ while ( !sheet.isNull() )
+ {
+ QDomElement t = sheet.toElement();
+ if ( t.isNull() )
+ {
+ sheet = sheet.nextSibling();
+ continue;
+ }
+ if ( t.nodeName() != "table:table" )
+ {
+ sheet = sheet.nextSibling();
+ continue;
+ }
+
+ table = m_doc->map()->addNewSheet();
+
+ table->setSheetName( t.attributeNS( ooNS::table, "name", QString::null ), true, false );
+ kdDebug()<<" table->name()"<<table->name()<<endl;
+ sheet = sheet.nextSibling();
+ }
+
+ sheet = body.firstChild();
+
+ int step = (int) ( 80 / numOfTables );
+ int progress = 15;
+
+ Format::setGlobalColWidth( MM_TO_POINT( 22.7 ) );
+ Format::setGlobalRowHeight( MM_TO_POINT( 4.3 ) );
+ kdDebug(30518) << "Global Height: " << MM_TO_POINT( 4.3 ) << ", Global width: " << MM_TO_POINT( 22.7) << endl;
+
+ while ( !sheet.isNull() )
+ {
+ QDomElement t = sheet.toElement();
+ if ( t.isNull() )
+ {
+ KMessageBox::sorry( 0, i18n( "The file seems to be corrupt. Skipping a table." ) );
+ sheet = sheet.nextSibling();
+ continue;
+ }
+ if ( t.nodeName() != "table:table" )
+ {
+ sheet = sheet.nextSibling();
+ continue;
+ }
+
+ table = m_doc->map()->findSheet( t.attributeNS( ooNS::table, "name", QString::null ) );
+ if ( !table )
+ {
+ KMessageBox::sorry( 0, i18n( "Skipping a table." ) );
+ sheet = sheet.nextSibling();
+ continue;
+ }
+
+ Format * defaultStyle = m_defaultStyles[ "Default" ];
+ if ( defaultStyle )
+ {
+ Cell* defaultCell = table->defaultCell();
+ kdDebug(30518) << "Copy default style to default cell" << endl;
+ defaultCell->format()->copy( *defaultStyle );
+ }
+ table->setDefaultHeight( MM_TO_POINT( 4.3 ) );
+ table->setDefaultWidth( MM_TO_POINT( 22.7 ) );
+
+ kdDebug(30518) << "Added table: " << t.attributeNS( ooNS::table, "name", QString::null ) << endl;
+
+ if ( t.hasAttributeNS( ooNS::table, "style-name" ) )
+ {
+ QString style = t.attributeNS( ooNS::table, "style-name", QString::null );
+ QDomElement * tableStyle = m_styles[ style ];
+
+ QDomNode node;
+
+ if ( tableStyle )
+ node = tableStyle->firstChild();
+
+ while( !node.isNull() )
+ {
+ QDomElement property = node.toElement();
+ if ( property.localName() == "properties" && property.namespaceURI() == ooNS::style )
+ {
+ if ( property.hasAttributeNS( ooNS::table, "display" ) )
+ {
+ bool visible = (property.attributeNS( ooNS::table, "display", QString::null ) == "true" ? true : false );
+ table->hideSheet( !visible );
+ kdDebug(30518) << "Table: " << table->tableName() << ", hidden: " << !visible << endl;
+ }
+ }
+
+ node = node.nextSibling();
+ }
+
+ if ( tableStyle && tableStyle->hasAttributeNS( ooNS::style, "master-page-name" ) )
+ {
+ QString stylename = "pm" + tableStyle->attributeNS( ooNS::style, "master-page-name", QString::null );
+
+ loadTableMasterStyle( table, stylename );
+
+ }
+ }
+ if ( t.hasAttributeNS( ooNS::table, "print-ranges" ) )
+ {
+ // e.g.: Sheet4.A1:Sheet4.E28
+ QString range = t.attributeNS( ooNS::table, "print-ranges", QString::null );
+ OpenCalcPoint point( range );
+
+ kdDebug(30518) << "Print range: " << point.translation << endl;
+ KSpread::Range p( point.translation );
+
+ kdDebug(30518) << "Print table: " << p.sheetName() << endl;
+
+ if ( table->sheetName() == p.sheetName() )
+ table->print()->setPrintRange( p.range() );
+ }
+
+ if ( !readColLayouts( t, table ) )
+ return false;
+
+ if ( !readRowsAndCells( t, table ) )
+ return false;
+
+ if ( t.hasAttributeNS( ooNS::table, "protected" ) )
+ {
+ QCString passwd( "" );
+ if ( t.hasAttributeNS( ooNS::table, "protection-key" ) )
+ {
+ QString p = t.attributeNS( ooNS::table, "protection-key", QString::null );
+ QCString str( p.latin1() );
+ kdDebug(30518) << "Decoding password: " << str << endl;
+ passwd = KCodecs::base64Decode( str );
+ }
+ kdDebug(30518) << "Password hash: '" << passwd << "'" << endl;
+ table->setProtected( passwd );
+ }
+
+ progress += step;
+ emit sigProgress( progress );
+ sheet = sheet.nextSibling();
+ }
+
+ QDomElement b = body.toElement();
+ if ( b.hasAttributeNS( ooNS::table, "structure-protected" ) )
+ {
+ QCString passwd( "" );
+ if ( b.hasAttributeNS( ooNS::table, "protection-key" ) )
+ {
+ QString p = b.attributeNS( ooNS::table, "protection-key", QString::null );
+ QCString str( p.latin1() );
+ kdDebug(30518) << "Decoding password: " << str << endl;
+ passwd = KCodecs::base64Decode( str );
+ }
+ kdDebug(30518) << "Password hash: '" << passwd << "'" << endl;
+
+ m_doc->map()->setProtected( passwd );
+ }
+
+ emit sigProgress( 98 );
+
+ return true;
+}
+
+void OpenCalcImport::insertStyles( QDomElement const & element )
+{
+ if ( element.isNull() )
+ return;
+
+ QDomElement e;
+ forEachElement( e, element )
+ {
+ if ( e.isNull() || !e.hasAttributeNS( ooNS::style, "name" ) )
+ {
+ continue;
+ }
+
+ QString name = e.attributeNS( ooNS::style, "name", QString::null );
+ kdDebug(30518) << "Style: '" << name << "' loaded " << endl;
+ m_styles.insert( name, new QDomElement( e ) );
+ }
+}
+
+
+void OpenCalcImport::loadOasisAreaName( const QDomElement&body )
+{
+ QDomNode namedAreas = KoDom::namedItemNS( body, ooNS::table, "named-expressions" );
+ if ( !namedAreas.isNull() )
+ {
+ QDomElement e;
+ forEachElement( e, namedAreas )
+ {
+ if ( e.isNull() || !e.hasAttributeNS( ooNS::table, "name" ) || !e.hasAttributeNS( ooNS::table, "cell-range-address" ) )
+ {
+ kdDebug(30518) << "Reading in named area failed" << endl;
+ continue;
+ }
+
+ // TODO: what is: table:base-cell-address
+ QString name = e.attributeNS( ooNS::table, "name", QString::null );
+ QString areaPoint = e.attributeNS( ooNS::table, "cell-range-address", QString::null );
+
+ m_namedAreas.append( name );
+ kdDebug(30518) << "Reading in named area, name: " << name << ", area: " << areaPoint << endl;
+
+ OpenCalcPoint point( areaPoint );
+ kdDebug(30518) << "Area: " << point.translation << endl;
+
+ QString range( point.translation );
+
+ if ( point.translation.find( ':' ) == -1 )
+ {
+ Point p( point.translation );
+
+ int n = range.find( '!' );
+ if ( n > 0 )
+ range = range + ":" + range.right( range.length() - n - 1);
+
+ kdDebug(30518) << "=> Area: " << range << endl;
+ }
+
+ KSpread::Range p( range );
+
+ m_doc->addAreaName( p.range(), name, p.sheetName() );
+ kdDebug(30518) << "Area range: " << p.sheetName() << endl;
+ }
+ }
+}
+
+void OpenCalcImport::loadOasisCellValidation( const QDomElement&body )
+{
+ QDomNode validation = KoDom::namedItemNS( body, ooNS::table, "content-validations" );
+ if ( !validation.isNull() )
+ {
+ QDomElement element;
+ forEachElement( element, validation )
+ {
+ if ( element.localName() == "content-validation" ) {
+ m_validationList.insert( element.attributeNS( ooNS::table, "name", QString::null ), element);
+ kdDebug(30518)<<" validation found :"<<element.attributeNS( ooNS::table, "name", QString::null )<<endl;
+ }
+ else {
+ kdDebug(30518)<<" Tag not recognize :"<<element.tagName()<<endl;
+ }
+ }
+ }
+}
+
+
+QString * OpenCalcImport::loadFormat( QDomElement * element,
+ FormatType & formatType,
+ QString name )
+{
+ if ( !element )
+ return 0;
+
+ int i;
+ bool ok;
+
+ QString * format = 0;
+ QDomElement e = element->firstChild( ).toElement();
+ int precision = 0;
+ int leadingZ = 1;
+ bool thousandsSep = false;
+ bool negRed = false;
+
+ if ( element->localName() == "time-style" )
+ formatType = Custom_format;
+ else if ( element->localName() == "date-style" )
+ formatType = Custom_format;
+ else if ( element->localName() == "percentage-style" )
+ formatType = Custom_format;
+ else if ( element->localName() == "number-style" )
+ formatType = Custom_format;
+ else if ( element->localName() == "currency-style" )
+ formatType = Custom_format;
+ else if ( element->localName() == "boolean-style" )
+ formatType = Custom_format;
+
+ if ( !e.isNull() )
+ format = new QString();
+
+ // TODO (element):
+ // number:automatic-order="true"
+ // number:truncate-on-overflow="false"
+ // style:volatile="true"
+
+ while ( !e.isNull() )
+ {
+ if ( e.localName() == "properties" && e.namespaceURI() == ooNS::style )
+ {
+ if ( e.hasAttributeNS( ooNS::fo, "color" ) )
+ negRed = true; // we only support red...
+ }
+ else if ( e.localName() == "text" && e.namespaceURI()==ooNS::number)
+ {
+ if ( negRed && ( e.text() == "-" ) )
+ ;
+ else
+ format->append( e.text() );
+ }
+ else if ( e.localName() == "currency-symbol" && e.namespaceURI()==ooNS::number)
+ {
+ QString sym( e.text() );
+ kdDebug(30518) << "Currency: " << sym << endl;
+ format->append( sym );
+ // number:language="de" number:country="DE">€</number:currency-symbol>
+ }
+ else if ( e.localName() == "day-of-week" && e.namespaceURI()==ooNS::number)
+ {
+ if ( e.hasAttributeNS( ooNS::number, "style" ) )
+ {
+ if ( e.attributeNS( ooNS::number, "style", QString::null ) == "long" )
+ format->append( "dddd" );
+ else
+ format->append( "ddd" );
+ }
+ else
+ format->append( "ddd" );
+ }
+ else if ( e.localName() == "day" && e.namespaceURI()==ooNS::number)
+ {
+ if ( e.hasAttributeNS( ooNS::number, "style" ) )
+ {
+ if ( e.attributeNS( ooNS::number, "style", QString::null ) == "long" )
+ format->append( "dd" );
+ else
+ format->append( "d" );
+ }
+ else
+ format->append( "d" );
+ }
+ else if ( e.localName() == "month" && e.namespaceURI()==ooNS::number)
+ {
+ if ( e.hasAttributeNS( ooNS::number, "textual" ) )
+ {
+ if ( e.attributeNS( ooNS::number, "textual", QString::null ) == "true" )
+ format->append( "mm" );
+ }
+
+ if ( e.hasAttributeNS( ooNS::number, "style" ) )
+ {
+ if ( e.attributeNS( ooNS::number, "style", QString::null ) == "long" )
+ format->append( "mm" );
+ else
+ format->append( "m" );
+ }
+ else
+ format->append( "m" );
+ }
+ else if ( e.localName() == "year" && e.namespaceURI()==ooNS::number)
+ {
+ if ( e.hasAttributeNS( ooNS::number, "style" ) )
+ {
+ if ( e.attributeNS( ooNS::number, "style", QString::null ) == "long" )
+ format->append( "yyyy" );
+ else
+ format->append( "yy" );
+ }
+ else
+ format->append( "yy" );
+ }
+ else if ( e.localName() == "hours" && e.namespaceURI()==ooNS::number)
+ {
+ if ( e.hasAttributeNS( ooNS::number, "style" ) )
+ {
+ if ( e.attributeNS( ooNS::number, "style", QString::null ) == "long" )
+ format->append( "hh" );
+ else
+ format->append( "h" );
+ }
+ else
+ format->append( "h" );
+ }
+ else if ( e.localName() == "minutes" && e.namespaceURI()==ooNS::number)
+ {
+ if ( e.hasAttributeNS( ooNS::number, "style" ) )
+ {
+ if ( e.attributeNS( ooNS::number, "style", QString::null ) == "long" )
+ format->append( "mm" );
+ else
+ format->append( "m" );
+ }
+ else
+ format->append( "m" );
+ }
+ else if ( e.localName() == "seconds" && e.namespaceURI()==ooNS::number)
+ {
+ if ( e.hasAttributeNS( ooNS::number, "style" ) )
+ {
+ if ( e.attributeNS( ooNS::number, "style", QString::null ) == "long" )
+ format->append( "ss" );
+ else
+ format->append( "s" );
+ }
+ else
+ format->append( "s" );
+ }
+ else if ( e.localName() == "am-pm" && e.namespaceURI()==ooNS::number)
+ {
+ format->append( "AM/PM" );
+ }
+ else if ( e.localName() == "number" && e.namespaceURI()==ooNS::number)
+ {
+ // TODO: number:grouping="true"
+
+ if ( e.hasAttributeNS( ooNS::number, "decimal-places" ) )
+ {
+ int d = e.attributeNS( ooNS::number, "decimal-places", QString::null ).toInt( &ok );
+ if ( ok )
+ precision = d;
+ }
+
+ if ( e.hasAttributeNS( ooNS::number, "min-integer-digits" ) )
+ {
+ int d = e.attributeNS( ooNS::number, "min-integer-digits", QString::null ).toInt( &ok );
+ if ( ok )
+ leadingZ = d;
+ }
+
+ if ( thousandsSep && leadingZ <= 3 )
+ {
+ format->append( "#," );
+ for ( i = leadingZ; i <= 3; ++i )
+ format->append( '#' );
+ }
+
+ for ( i = 1; i <= leadingZ; ++i )
+ {
+ format->append( '0' );
+ if ( ( i % 3 == 0 ) && thousandsSep )
+ format->append( ',' );
+ }
+
+ format->append( '.' );
+ for ( i = 0; i < precision; ++i )
+ format->append( '0' );
+ }
+ else if ( e.localName() == "scientific-number" && e.namespaceURI()==ooNS::number)
+ {
+ int exp = 2;
+
+ if ( e.hasAttributeNS( ooNS::number, "decimal-places" ) )
+ {
+ int d = e.attributeNS( ooNS::number, "decimal-places", QString::null ).toInt( &ok );
+ if ( ok )
+ precision = d;
+ }
+
+ if ( e.hasAttributeNS( ooNS::number, "min-integer-digits" ) )
+ {
+ int d = e.attributeNS( ooNS::number, "min-integer-digits", QString::null ).toInt( &ok );
+ if ( ok )
+ leadingZ = d;
+ }
+
+ if ( e.hasAttributeNS( ooNS::number, "min-exponent-digits" ) )
+ {
+ int d = e.attributeNS( ooNS::number, "min-exponent-digits", QString::null ).toInt( &ok );
+ if ( ok )
+ exp = d;
+ if ( exp <= 0 )
+ exp = 1;
+ }
+
+ if ( thousandsSep && leadingZ <= 3 )
+ {
+ format->append( "#," );
+ for ( i = leadingZ; i <= 3; ++i )
+ format->append( '#' );
+ }
+
+ for ( i = 1; i <= leadingZ; ++i )
+ {
+ format->append( '0' );
+ if ( ( i % 3 == 0 ) && thousandsSep )
+ format->append( ',' );
+ }
+
+ format->append( '.' );
+ for ( i = 0; i < precision; ++i )
+ format->append( '0' );
+
+ format->append( "E+" );
+ for ( i = 0; i < exp; ++i )
+ format->append( '0' );
+
+ formatType = Custom_format;
+ }
+ else if ( e.localName() == "fraction" && e.namespaceURI()==ooNS::number)
+ {
+ int integer = 0;
+ int numerator = 1;
+ int denominator = 1;
+
+ if ( e.hasAttributeNS( ooNS::number, "min-integer-digits" ) )
+ {
+ int d = e.attributeNS( ooNS::number, "min-integer-digits", QString::null ).toInt( &ok );
+ if ( ok )
+ integer = d;
+ }
+ if ( e.hasAttributeNS( ooNS::number, "min-numerator-digits" ) )
+ {
+ int d = e.attributeNS( ooNS::number, "min-numerator-digits", QString::null ).toInt( &ok );
+ if ( ok )
+ numerator = d;
+ }
+ if ( e.hasAttributeNS( ooNS::number, "min-denominator-digits" ) )
+ {
+ int d = e.attributeNS( ooNS::number, "min-denominator-digits", QString::null ).toInt( &ok );
+ if ( ok )
+ denominator = d;
+ }
+
+ for ( i = 0; i <= integer; ++i )
+ format->append( '#' );
+
+ format->append( ' ' );
+
+ for ( i = 0; i <= numerator; ++i )
+ format->append( '?' );
+
+ format->append( '/' );
+
+ for ( i = 0; i <= denominator; ++i )
+ format->append( '?' );
+ }
+ // Not needed:
+ // <style:map style:condition="value()&gt;=0" style:apply-style-name="N106P0"/>
+ // we handle painting negative numbers in red differently
+
+ e = e.nextSibling().toElement();
+ }
+
+ if ( negRed )
+ {
+ QString f( *format );
+ format->append( ";[Red]" );
+ format->append( f );
+ }
+
+ kdDebug(30518) << "*** New FormatString: " << *format << endl << endl;
+
+ m_formats.insert( name, format );
+
+ return format;
+}
+
+void OpenCalcImport::loadFontStyle( Format * layout, QDomElement const * font ) const
+{
+ if ( !font || !layout )
+ return;
+
+ kdDebug(30518) << "Copy font style from the layout " << font->tagName() << ", " << font->nodeName() << endl;
+
+ if ( font->hasAttributeNS( ooNS::fo, "font-family" ) )
+ layout->setTextFontFamily( font->attributeNS( ooNS::fo, "font-family", QString::null ) );
+ if ( font->hasAttributeNS( ooNS::fo, "color" ) )
+ layout->setTextColor( QColor( font->attributeNS( ooNS::fo, "color", QString::null ) ) );
+ if ( font->hasAttributeNS( ooNS::fo, "font-size" ) )
+ layout->setTextFontSize( int( KoUnit::parseValue( font->attributeNS( ooNS::fo, "font-size", QString::null ), 10 ) ) );
+ else
+ layout->setTextFontSize( 10 );
+ if ( font->hasAttributeNS( ooNS::fo, "font-style" ) )
+ {
+ kdDebug(30518) << "italic" << endl;
+ layout->setTextFontItalic( true ); // only thing we support
+ }
+ if ( font->hasAttributeNS( ooNS::fo, "font-weight" ) )
+ layout->setTextFontBold( true ); // only thing we support
+ if ( font->hasAttributeNS( ooNS::fo, "text-underline" ) || font->hasAttributeNS( ooNS::style, "text-underline" ) )
+ layout->setTextFontUnderline( true ); // only thing we support
+ if ( font->hasAttributeNS( ooNS::style, "text-crossing-out" ) )
+ layout->setTextFontStrike( true ); // only thing we support
+ if ( font->hasAttributeNS( ooNS::style, "font-pitch" ) )
+ {
+ // TODO: possible values: fixed, variable
+ }
+ // TODO:
+ // text-underline-color
+}
+
+void OpenCalcImport::loadBorder( Format * layout, QString const & borderDef, bPos pos ) const
+{
+ if ( borderDef == "none" )
+ return;
+
+ int p = borderDef.find( ' ' );
+ if ( p < 0 )
+ return;
+
+ QPen pen;
+ QString w = borderDef.left( p );
+ pen.setWidth( (int) KoUnit::parseValue( w ) );
+
+
+ ++p;
+ int p2 = borderDef.find( ' ', p );
+ QString s = borderDef.mid( p, p2 - p );
+
+ kdDebug(30518) << "Borderstyle: " << s << endl;
+
+ if ( s == "solid" || s == "double" )
+ pen.setStyle( Qt::SolidLine );
+ else
+ {
+#if 0
+ // TODO: not supported by oocalc
+ pen.setStyle( Qt::DashLine );
+ pen.setStyle( Qt::DotLine );
+ pen.setStyle( Qt::DashDotLine );
+ pen.setStyle( Qt::DashDotDotLine );
+#endif
+ pen.setStyle( Qt::SolidLine ); //default.
+ }
+
+ ++p2;
+ p = borderDef.find( ' ', p2 );
+ if ( p == -1 )
+ p = borderDef.length();
+
+ pen.setColor( QColor( borderDef.right( p - p2 ) ) );
+
+ if ( pos == Left )
+ layout->setLeftBorderPen( pen );
+ else if ( pos == Top )
+ layout->setTopBorderPen( pen );
+ else if ( pos == Right )
+ layout->setRightBorderPen( pen );
+ else if ( pos == Bottom )
+ layout->setBottomBorderPen( pen );
+ else if ( pos == Border )
+ {
+ layout->setLeftBorderPen( pen );
+ layout->setTopBorderPen( pen );
+ layout->setRightBorderPen( pen );
+ layout->setBottomBorderPen( pen );
+ }
+ // TODO Diagonals not supported by oocalc
+}
+
+void OpenCalcImport::loadStyleProperties( Format * layout, QDomElement const & property ) const
+{
+ kdDebug(30518) << "*** Loading style properties *****" << endl;
+
+ if ( property.hasAttributeNS( ooNS::style, "decimal-places" ) )
+ {
+ bool ok = false;
+ int p = property.attributeNS( ooNS::style, "decimal-places", QString::null ).toInt( &ok );
+ if (ok )
+ layout->setPrecision( p );
+ }
+
+ if ( property.hasAttributeNS( ooNS::style, "font-name" ) )
+ {
+ QDomElement * font = m_styles[ property.attributeNS( ooNS::style, "font-name", QString::null ) ];
+ loadFontStyle( layout, font ); // generell font style
+ }
+
+ loadFontStyle( layout, &property ); // specific font style
+
+ // TODO:
+ // diagonal: fall + goup
+ // fo:direction="ltr"
+ // style:text-align-source ("fix")
+ // style:shadow
+ // style:text-outline
+ // indents from right, top, bottom
+ // style:condition="cell-content()=15"
+ // => style:apply-style-name="Result" style:base-cell-address="Sheet6.A5"/>
+
+ if ( property.hasAttributeNS( ooNS::style, "rotation-angle" ) )
+ {
+ bool ok = false;
+ int a = property.attributeNS( ooNS::style, "rotation-angle", QString::null ).toInt( &ok );
+ if ( ok )
+ layout->setAngle( -a + 1 );
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "direction" ) )
+ {
+ layout->setVerticalText( true );
+ }
+ if ( property.hasAttributeNS( ooNS::fo, "text-align" ) )
+ {
+ QString s = property.attributeNS( ooNS::fo, "text-align", QString::null );
+ if ( s == "center" )
+ layout->setAlign( Format::Center );
+ else if ( s == "end" )
+ layout->setAlign( Format::Right );
+ else if ( s == "start" )
+ layout->setAlign( Format::Left );
+ else if ( s == "justify" ) // TODO in KSpread!
+ layout->setAlign( Format::Center );
+ }
+ if ( property.hasAttributeNS( ooNS::fo, "margin-left" ) )
+ {
+ kdDebug(30518)<<"margin-left :"<<KoUnit::parseValue( property.attributeNS( ooNS::fo, "margin-left", QString::null ),0.0 )<<endl;
+ layout->setIndent( KoUnit::parseValue( property.attributeNS( ooNS::fo, "margin-left", QString::null ),0.0 ) );
+ }
+ if ( property.hasAttributeNS( ooNS::fo, "background-color" ) )
+ layout->setBgColor( QColor( property.attributeNS( ooNS::fo, "background-color", QString::null ) ) );
+
+ if ( property.hasAttributeNS( ooNS::style, "print-content" ) )
+ {
+ if ( property.attributeNS( ooNS::style, "print-content", QString::null ) == "false" )
+ layout->setDontPrintText( false );
+ }
+ if ( property.hasAttributeNS( ooNS::style, "cell-protect" ) )
+ {
+ QString prot( property.attributeNS( ooNS::style, "cell-protect", QString::null ) );
+ if ( prot == "none" )
+ {
+ layout->setNotProtected( true );
+ layout->setHideFormula( false );
+ layout->setHideAll( false );
+ }
+ else if ( prot == "formula-hidden" )
+ {
+ layout->setNotProtected( true );
+ layout->setHideFormula( true );
+ layout->setHideAll( false );
+ }
+ else if ( prot == "protected formula-hidden" )
+ {
+ layout->setNotProtected( false );
+ layout->setHideFormula( true );
+ layout->setHideAll( false );
+ }
+ else if ( prot == "hidden-and-protected" )
+ {
+ layout->setNotProtected( false );
+ layout->setHideFormula( false );
+ layout->setHideAll( true );
+ }
+ else if ( prot == "protected" )
+ {
+ layout->setNotProtected( false );
+ layout->setHideFormula( false );
+ layout->setHideAll( false );
+ }
+ kdDebug(30518) << "Cell " << prot << endl;
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "padding-left" ) )
+ layout->setIndent( KoUnit::parseValue(property.attributeNS( ooNS::fo, "padding-left", QString::null ) ) );
+
+ if ( property.hasAttributeNS( ooNS::fo, "vertical-align" ) )
+ {
+ QString s = property.attributeNS( ooNS::fo, "vertical-align", QString::null );
+ if ( s == "middle" )
+ layout->setAlignY( Format::Middle );
+ else if ( s == "bottom" )
+ layout->setAlignY( Format::Bottom );
+ else
+ layout->setAlignY( Format::Top );
+ }
+ else
+ layout->setAlignY( Format::Bottom );
+
+ if ( property.hasAttributeNS( ooNS::fo, "wrap-option" ) )
+ {
+ layout->setMultiRow( true );
+
+ /* we do not support anything else yet
+ QString s = property.attributeNS( ooNS::fo, "wrap-option", QString::null );
+ if ( s == "wrap" )
+ layout->setMultiRow( true );
+ */
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "border-bottom" ) )
+ {
+ loadBorder( layout, property.attributeNS( ooNS::fo, "border-bottom", QString::null ), Bottom );
+ // TODO: style:border-line-width-bottom if double!
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "border-right" ) )
+ {
+ loadBorder( layout, property.attributeNS( ooNS::fo, "border-right", QString::null ), Right );
+ // TODO: style:border-line-width-right
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "border-top" ) )
+ {
+ loadBorder( layout, property.attributeNS( ooNS::fo, "border-top", QString::null ), Top );
+ // TODO: style:border-line-width-top
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "border-left" ) )
+ {
+ loadBorder( layout, property.attributeNS( ooNS::fo, "border-left", QString::null ), Left );
+ // TODO: style:border-line-width-left
+ }
+
+ if ( property.hasAttributeNS( ooNS::fo, "border" ) )
+ {
+ loadBorder( layout, property.attributeNS( ooNS::fo, "border", QString::null ), Border );
+ // TODO: style:border-line-width-left
+ }
+}
+
+void OpenCalcImport::readInStyle( Format * layout, QDomElement const & style )
+{
+ kdDebug(30518) << "** Reading Style: " << style.tagName() << "; " << style.attributeNS( ooNS::style, "name", QString::null) << endl;
+ if ( style.localName() == "style" && style.namespaceURI()==ooNS::style)
+ {
+ if ( style.hasAttributeNS( ooNS::style, "parent-style-name" ) )
+ {
+ Format * cp
+ = m_defaultStyles.find( style.attributeNS( ooNS::style, "parent-style-name", QString::null ) );
+ kdDebug(30518) << "Copying layout from " << style.attributeNS( ooNS::style, "parent-style-name", QString::null ) << endl;
+
+ if ( cp != 0 )
+ layout->copy( *cp );
+ }
+ else if ( style.hasAttributeNS( ooNS::style, "family") )
+ {
+ QString name = style.attribute( "style-family" ) + "default";
+ Format * cp = m_defaultStyles.find( name );
+
+ kdDebug(30518) << "Copying layout from " << name << ", " << !cp << endl;
+
+ if ( cp != 0 )
+ layout->copy( *cp );
+ }
+
+ if ( style.hasAttributeNS( ooNS::style, "data-style-name" ) )
+ {
+ QString * format = m_formats[ style.attributeNS( ooNS::style, "data-style-name", QString::null ) ];
+ FormatType formatType;
+
+ if ( !format )
+ {
+ // load and convert it
+ QString name( style.attributeNS( ooNS::style, "data-style-name", QString::null ) );
+ format = loadFormat( m_styles[ name ], formatType, name );
+ }
+
+ if ( format )
+ {
+ layout->setFormatString( *format );
+ layout->setFormatType( formatType );
+ }
+
+ // <number:currency-symbol number:language="de" number:country="DE">€</number:currency-symbol>
+ }
+ }
+
+ QDomElement property;
+ forEachElement( property, style )
+ {
+ if ( property.localName() == "properties" && property.namespaceURI() == ooNS::style )
+ loadStyleProperties( layout, property );
+
+ kdDebug(30518) << layout->textFontFamily( 0, 0 ) << endl;
+ }
+}
+
+bool OpenCalcImport::createStyleMap( QDomDocument const & styles )
+{
+ QDomElement content = styles.documentElement();
+ QDomNode docStyles = KoDom::namedItemNS( content, ooNS::office, "document-styles" );
+
+ if ( content.hasAttributeNS( ooNS::office, "version" ) )
+ {
+ bool ok = true;
+ double d = content.attributeNS( ooNS::office, "version", QString::null ).toDouble( &ok );
+
+ if ( ok )
+ {
+ kdDebug(30518) << "OpenCalc version: " << d << endl;
+ if ( d > 1.0 )
+ {
+ QString message( i18n("This document was created with OpenOffice.org version '%1'. This filter was written for version 1.0. Reading this file could cause strange behavior, crashes or incorrect display of the data. Do you want to continue converting the document?") );
+ message.arg( content.attributeNS( ooNS::office, "version", QString::null ) );
+ if ( KMessageBox::warningYesNo( 0, message, i18n( "Unsupported document version" ) ) == KMessageBox::No )
+ return false;
+ }
+ }
+ }
+
+ QDomNode fontStyles = KoDom::namedItemNS( content, ooNS::office, "font-decls" );
+
+ if ( !fontStyles.isNull() )
+ {
+ kdDebug(30518) << "Starting reading in font-decl..." << endl;
+
+ insertStyles( fontStyles.toElement() );
+ }
+ else
+ kdDebug(30518) << "No items found" << endl;
+
+ kdDebug(30518) << "Starting reading in auto:styles" << endl;
+
+ QDomNode autoStyles = KoDom::namedItemNS( content, ooNS::office, "automatic-styles" );
+ if ( !autoStyles.isNull() )
+ insertStyles( autoStyles.toElement() );
+ else
+ kdDebug(30518) << "No items found" << endl;
+
+
+ kdDebug(30518) << "Reading in master styles" << endl;
+
+ QDomNode masterStyles = KoDom::namedItemNS( content, ooNS::office, "master-styles" );
+
+ if ( masterStyles.isNull() )
+ {
+ kdDebug(30518) << "Nothing found " << endl;
+ }
+
+ QDomElement master = KoDom::namedItemNS( masterStyles, ooNS::style, "master-page");
+ if ( !master.isNull() )
+ {
+ QString name( "pm" );
+ name += master.attributeNS( ooNS::style, "name", QString::null );
+ kdDebug(30518) << "Master style: '" << name << "' loaded " << endl;
+ m_styles.insert( name, new QDomElement( master ) );
+
+ master = master.nextSibling().toElement();
+ }
+
+
+ kdDebug(30518) << "Starting reading in office:styles" << endl;
+
+ QDomNode fixedStyles = KoDom::namedItemNS( content, ooNS::office, "styles" );
+
+ kdDebug(30518) << "Reading in default styles" << endl;
+
+ QDomNode def = KoDom::namedItemNS( fixedStyles, ooNS::style, "default-style" );
+ kdDebug()<<" def !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! :"<<def.isNull()<<endl;
+ while ( !def.isNull() )
+ {
+ QDomElement e = def.toElement();
+ kdDebug(30518) << "Style found " << e.nodeName() << ", tag: " << e.tagName() << endl;
+
+ if ( e.nodeName() != "style:default-style" )
+ {
+ def = def.nextSibling();
+ continue;
+ }
+
+ if ( !e.isNull() )
+ {
+ Format * layout = new Format( 0, m_doc->styleManager()->defaultStyle() );
+
+ readInStyle( layout, e );
+ kdDebug(30518) << "Default style " << e.attributeNS( ooNS::style, "family", QString::null ) << "default" << " loaded " << endl;
+
+ m_defaultStyles.insert( e.attributeNS( ooNS::style, "family", QString::null ) + "default", layout );
+ // QFont font = layout->font();
+ // kdDebug(30518) << "Font: " << font.family() << ", " << font.toString() << endl;
+ }
+
+ def = def.nextSibling();
+ }
+
+ QDomElement defs = KoDom::namedItemNS( fixedStyles, ooNS::style, "style" );
+ while ( !defs.isNull() )
+ {
+ if ( defs.nodeName() != "style:style" )
+ break; // done
+
+ if ( !defs.hasAttributeNS( ooNS::style, "name" ) )
+ {
+ // ups...
+ defs = defs.nextSibling().toElement();
+ continue;
+ }
+
+ Format * layout = new Format( 0, m_doc->styleManager()->defaultStyle() );
+ readInStyle( layout, defs );
+ kdDebug(30518) << "Default style " << defs.attributeNS( ooNS::style, "name", QString::null ) << " loaded " << endl;
+
+ m_defaultStyles.insert( defs.attributeNS( ooNS::style, "name", QString::null ), layout );
+ // kdDebug(30518) << "Font: " << layout->font().family() << ", " << layout->font().toString() << endl;
+
+ defs = defs.nextSibling().toElement();
+ }
+
+ if ( !fixedStyles.isNull() )
+ insertStyles( fixedStyles.toElement() );
+
+ kdDebug(30518) << "Starting reading in automatic styles" << endl;
+
+ content = m_content.documentElement();
+ autoStyles = KoDom::namedItemNS( content, ooNS::office, "automatic-styles" );
+
+ if ( !autoStyles.isNull() )
+ insertStyles( autoStyles.toElement() );
+
+ fontStyles = KoDom::namedItemNS( content, ooNS::office, "font-decls" );
+
+ if ( !fontStyles.isNull() )
+ {
+ kdDebug(30518) << "Starting reading in special font decl" << endl;
+
+ insertStyles( fontStyles.toElement() );
+ }
+
+ kdDebug(30518) << "Styles read in." << endl;
+
+ return true;
+}
+
+void OpenCalcImport::loadOasisValidation( Validity* val, const QString& validationName )
+{
+ kdDebug(30518)<<"validationName:"<<validationName<<endl;
+ QDomElement element = m_validationList[validationName];
+ if ( element.hasAttributeNS( ooNS::table, "condition" ) )
+ {
+ QString valExpression = element.attributeNS( ooNS::table, "condition", QString::null );
+ kdDebug(30518)<<" element.attribute( table:condition ) "<<valExpression<<endl;
+ //Condition ::= ExtendedTrueCondition | TrueFunction 'and' TrueCondition
+ //TrueFunction ::= cell-content-is-whole-number() | cell-content-is-decimal-number() | cell-content-is-date() | cell-content-is-time()
+ //ExtendedTrueCondition ::= ExtendedGetFunction | cell-content-text-length() Operator Value
+ //TrueCondition ::= GetFunction | cell-content() Operator Value
+ //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
+ //ExtendedGetFunction ::= cell-content-text-length-is-between(Value, Value) | cell-content-text-length-is-not-between(Value, Value)
+ //Operator ::= '<' | '>' | '<=' | '>=' | '=' | '!='
+ //Value ::= NumberValue | String | Formula
+ //A Formula is a formula without an equals (=) sign at the beginning. See section 8.1.3 for more information.
+ //A String comprises one or more characters surrounded by quotation marks.
+ //A NumberValue is a whole or decimal number. It must not contain comma separators for numbers of 1000 or greater.
+
+ //ExtendedTrueCondition
+ if ( valExpression.contains( "cell-content-text-length()" ) )
+ {
+ //"cell-content-text-length()>45"
+ valExpression = valExpression.remove("cell-content-text-length()" );
+ kdDebug(30518)<<" valExpression = :"<<valExpression<<endl;
+ val->m_restriction = Restriction::TextLength;
+
+ loadOasisValidationCondition( val, valExpression );
+ }
+ //cell-content-text-length-is-between(Value, Value) | cell-content-text-length-is-not-between(Value, Value)
+ else if ( valExpression.contains( "cell-content-text-length-is-between" ) )
+ {
+ val->m_restriction = Restriction::TextLength;
+ val->m_cond = Conditional::Between;
+ valExpression = valExpression.remove( "cell-content-text-length-is-between(" );
+ kdDebug(30518)<<" valExpression :"<<valExpression<<endl;
+ valExpression = valExpression.remove( ")" );
+ QStringList listVal = QStringList::split( ",", valExpression );
+ loadOasisValidationValue( val, listVal );
+ }
+ else if ( valExpression.contains( "cell-content-text-length-is-not-between" ) )
+ {
+ val->m_restriction = Restriction::TextLength;
+ val->m_cond = Conditional::Different;
+ valExpression = valExpression.remove( "cell-content-text-length-is-not-between(" );
+ kdDebug(30518)<<" valExpression :"<<valExpression<<endl;
+ valExpression = valExpression.remove( ")" );
+ kdDebug(30518)<<" valExpression :"<<valExpression<<endl;
+ QStringList listVal = QStringList::split( ",", valExpression );
+ loadOasisValidationValue( val, listVal );
+
+ }
+ //TrueFunction ::= cell-content-is-whole-number() | cell-content-is-decimal-number() | cell-content-is-date() | cell-content-is-time()
+ else
+ {
+ if (valExpression.contains( "cell-content-is-whole-number()" ) )
+ {
+ val->m_restriction = Restriction::Number;
+ valExpression = valExpression.remove( "cell-content-is-whole-number() and " );
+ }
+ else if (valExpression.contains( "cell-content-is-decimal-number()" ) )
+ {
+ val->m_restriction = Restriction::Integer;
+ valExpression = valExpression.remove( "cell-content-is-decimal-number() and " );
+ }
+ else if (valExpression.contains( "cell-content-is-date()" ) )
+ {
+ val->m_restriction = Restriction::Date;
+ valExpression = valExpression.remove( "cell-content-is-date() and " );
+ }
+ else if (valExpression.contains( "cell-content-is-time()" ) )
+ {
+ val->m_restriction = Restriction::Time;
+ valExpression = valExpression.remove( "cell-content-is-time() and " );
+ }
+ kdDebug(30518)<<"valExpression :"<<valExpression<<endl;
+
+ if ( valExpression.contains( "cell-content()" ) )
+ {
+ valExpression = valExpression.remove( "cell-content()" );
+ loadOasisValidationCondition( val, valExpression );
+ }
+ //GetFunction ::= cell-content-is-between(Value, Value) | cell-content-is-not-between(Value, Value)
+ //for the moment we support just int/double value, not text/date/time :(
+ if ( valExpression.contains( "cell-content-is-between(" ) )
+ {
+ valExpression = valExpression.remove( "cell-content-is-between(" );
+ valExpression = valExpression.remove( ")" );
+ QStringList listVal = QStringList::split( "," , valExpression );
+ loadOasisValidationValue( val, listVal );
+
+ val->m_cond = Conditional::Between;
+ }
+ if ( valExpression.contains( "cell-content-is-not-between(" ) )
+ {
+ valExpression = valExpression.remove( "cell-content-is-not-between(" );
+ valExpression = valExpression.remove( ")" );
+ QStringList listVal = QStringList::split( ",", valExpression );
+ loadOasisValidationValue( val, listVal );
+ val->m_cond = Conditional::Different;
+ }
+ }
+ }
+ if ( element.hasAttributeNS( ooNS::table, "allow-empty-cell" ) )
+ {
+ val->allowEmptyCell = ( ( element.attributeNS( ooNS::table, "allow-empty-cell", QString::null )=="true" ) ? true : false );
+
+ }
+ if ( element.hasAttributeNS( ooNS::table, "base-cell-address" ) )
+ {
+ //todo what is it ?
+ }
+
+ QDomElement help = KoDom::namedItemNS( element, ooNS::table, "help-message" );
+ if ( !help.isNull() )
+ {
+ if ( help.hasAttributeNS( ooNS::table, "title" ) )
+ val->titleInfo = help.attributeNS( ooNS::table, "title", QString::null );
+ if ( help.hasAttributeNS( ooNS::table, "display" ) )
+ val->displayValidationInformation = ( ( help.attributeNS( ooNS::table, "display", QString::null )=="true" ) ? true : false );
+ QDomElement attrText = KoDom::namedItemNS( help, ooNS::text, "p" );
+ if ( !attrText.isNull() )
+ val->messageInfo = attrText.text();
+ }
+
+ QDomElement error = KoDom::namedItemNS( element, ooNS::table, "error-message" );
+ if ( !error.isNull() )
+ {
+ if ( error.hasAttributeNS( ooNS::table, "title" ) )
+ val->title = error.attributeNS( ooNS::table, "title", QString::null );
+ if ( error.hasAttributeNS( ooNS::table, "message-type" ) )
+ {
+ QString str = error.attributeNS( ooNS::table, "message-type", QString::null );
+ if ( str == "warning" )
+ val->m_action = Action::Warning;
+ else if ( str == "information" )
+ val->m_action = Action::Information;
+ else if ( str == "stop" )
+ val->m_action = Action::Stop;
+ else
+ kdDebug(30518)<<"validation : message type unknown :"<<str<<endl;
+ }
+
+ if ( error.hasAttributeNS( ooNS::table, "display" ) )
+ {
+ kdDebug(30518)<<" display message :"<<error.attributeNS( ooNS::table, "display", QString::null )<<endl;
+ val->displayMessage = (error.attributeNS( ooNS::table, "display", QString::null )=="true");
+ }
+ QDomElement attrText = KoDom::namedItemNS( error, ooNS::text, "p" );
+ if ( !attrText.isNull() )
+ val->message = attrText.text();
+ }
+}
+
+void OpenCalcImport::loadOasisValidationValue( Validity* val, const QStringList &listVal )
+{
+ bool ok = false;
+ kdDebug(30518)<<" listVal[0] :"<<listVal[0]<<" listVal[1] :"<<listVal[1]<<endl;
+
+ if ( val->m_restriction == Restriction::Date )
+ {
+ val->dateMin = QDate::fromString( listVal[0] );
+ val->dateMax = QDate::fromString( listVal[1] );
+ }
+ else if ( val->m_restriction == Restriction::Time )
+ {
+ val->timeMin = QTime::fromString( listVal[0] );
+ val->timeMax = QTime::fromString( listVal[1] );
+ }
+ else
+ {
+ val->valMin = listVal[0].toDouble(&ok);
+ if ( !ok )
+ {
+ val->valMin = listVal[0].toInt(&ok);
+ if ( !ok )
+ kdDebug(30518)<<" Try to parse this value :"<<listVal[0]<<endl;
+
+#if 0
+ if ( !ok )
+ val->valMin = listVal[0];
+#endif
+ }
+ ok=false;
+ val->valMax = listVal[1].toDouble(&ok);
+ if ( !ok )
+ {
+ val->valMax = listVal[1].toInt(&ok);
+ if ( !ok )
+ kdDebug(30518)<<" Try to parse this value :"<<listVal[1]<<endl;
+
+#if 0
+ if ( !ok )
+ val->valMax = listVal[1];
+#endif
+ }
+ }
+}
+
+
+void OpenCalcImport::loadOasisValidationCondition( Validity* val,QString &valExpression )
+{
+ QString value;
+ if (valExpression.contains( "<=" ) )
+ {
+ value = valExpression.remove( "<=" );
+ val->m_cond = Conditional::InferiorEqual;
+ }
+ else if (valExpression.contains( ">=" ) )
+ {
+ value = valExpression.remove( ">=" );
+ val->m_cond = Conditional::SuperiorEqual;
+ }
+ else if (valExpression.contains( "!=" ) )
+ {
+ //add Differentto attribute
+ value = valExpression.remove( "!=" );
+ val->m_cond = Conditional::DifferentTo;
+ }
+ else if ( valExpression.contains( "<" ) )
+ {
+ value = valExpression.remove( "<" );
+ val->m_cond = Conditional::Inferior;
+ }
+ else if(valExpression.contains( ">" ) )
+ {
+ value = valExpression.remove( ">" );
+ val->m_cond = Conditional::Superior;
+ }
+ else if (valExpression.contains( "=" ) )
+ {
+ value = valExpression.remove( "=" );
+ val->m_cond = Conditional::Equal;
+ }
+ else
+ kdDebug(30518)<<" I don't know how to parse it :"<<valExpression<<endl;
+ kdDebug(30518)<<" value :"<<value<<endl;
+ if ( val->m_restriction == Restriction::Date )
+ {
+ val->dateMin = QDate::fromString( value );
+ }
+ else if ( val->m_restriction == Restriction::Date )
+ {
+ val->timeMin = QTime::fromString( value );
+ }
+ else
+ {
+ bool ok = false;
+ val->valMin = value.toDouble(&ok);
+ if ( !ok )
+ {
+ val->valMin = value.toInt(&ok);
+ if ( !ok )
+ kdDebug(30518)<<" Try to parse this value :"<<value<<endl;
+
+#if 0
+ if ( !ok )
+ val->valMin = value;
+#endif
+ }
+ }
+}
+
+
+int OpenCalcImport::readMetaData()
+{
+ int result = 5;
+ KoDocumentInfo * docInfo = m_doc->documentInfo();
+ KoDocumentInfoAbout * aboutPage = static_cast<KoDocumentInfoAbout *>(docInfo->page( "about" ));
+ KoDocumentInfoAuthor * authorPage = static_cast<KoDocumentInfoAuthor*>(docInfo->page( "author" ));
+
+ QDomNode meta = KoDom::namedItemNS( m_meta, ooNS::office, "document-meta" );
+ QDomNode office = KoDom::namedItemNS( meta, ooNS::office, "meta" );
+
+ if ( office.isNull() )
+ return 2;
+
+ QDomElement e = KoDom::namedItemNS( office, ooNS::dc, "creator" );
+ if ( !e.isNull() && !e.text().isEmpty() )
+ authorPage->setFullName( e.text() );
+
+ e = KoDom::namedItemNS( office, ooNS::dc, "title" );
+ if ( !e.isNull() && !e.text().isEmpty() )
+ aboutPage->setTitle( e.text() );
+
+ e = KoDom::namedItemNS( office, ooNS::dc, "description" );
+ if ( !e.isNull() && !e.text().isEmpty() )
+ aboutPage->setAbstract( e.text() );
+
+ e = KoDom::namedItemNS( office, ooNS::dc, "subject" );
+ if ( !e.isNull() && !e.text().isEmpty() )
+ aboutPage->setSubject( e.text() );
+
+ e= KoDom::namedItemNS( office, ooNS::meta, "keywords" );
+ if ( !e.isNull() )
+ {
+ e = KoDom::namedItemNS( e, ooNS::meta, "keyword" );
+ if ( !e.isNull() && !e.text().isEmpty() )
+ aboutPage->setKeywords( e.text() );
+ }
+
+ e = KoDom::namedItemNS( office, ooNS::meta, "document-statistic" );
+ if ( !e.isNull() && e.hasAttributeNS( ooNS::meta, "table-count" ) )
+ {
+ bool ok = false;
+ result = e.attributeNS( ooNS::meta, "table-count", QString::null ).toInt( &ok );
+ if ( !ok )
+ result = 5;
+ }
+
+ m_meta.clear(); // not needed anymore
+
+ return result;
+}
+
+KoFilter::ConversionStatus OpenCalcImport::convert( QCString const & from, QCString const & to )
+{
+ kdDebug(30518) << "Entering OpenCalc Import filter: " << from << " - " << to << endl;
+
+ KoDocument * document = m_chain->outputDocument();
+ if ( !document )
+ return KoFilter::StupidError;
+
+ if ( !::qt_cast<const KSpread::Doc *>( document ) ) // it's safer that way :)
+ {
+ kdWarning(30518) << "document isn't a KSpread::Doc but a " << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ if ( ( from != "application/vnd.sun.xml.calc" && from != "application/vnd.sun.xml.calc.template") || to != "application/x-kspread" )
+ {
+ kdWarning(30518) << "Invalid mimetypes " << from << " " << to << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ m_doc = ( Doc * ) document;
+
+ if ( m_doc->mimeType() != "application/x-kspread" )
+ {
+ kdWarning(30518) << "Invalid document mimetype " << m_doc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ kdDebug(30518) << "Opening file " << endl;
+
+ KoFilter::ConversionStatus preStatus = openFile();
+
+ if ( preStatus != KoFilter::OK )
+ return preStatus;
+
+ emit sigProgress( 13 );
+ int tables = readMetaData();
+
+ emit sigProgress( 15 );
+
+ if ( !parseBody( tables ) )
+ return KoFilter::StupidError;
+
+ emit sigProgress( 100 );
+ return KoFilter::OK;
+}
+
+KoFilter::ConversionStatus OpenCalcImport::openFile()
+{
+ KoStore * store = KoStore::createStore( m_chain->inputFile(), KoStore::Read);
+
+ kdDebug(30518) << "Store created" << endl;
+
+ if ( !store )
+ {
+ kdWarning(30518) << "Couldn't open the requested file." << endl;
+ return KoFilter::FileNotFound;
+ }
+
+ kdDebug(30518) << "Trying to open content.xml" << endl;
+ QString messageError;
+ loadAndParse( m_content, "content.xml", store);
+ kdDebug(30518) << "Opened" << endl;
+
+ QDomDocument styles;
+ kdDebug(30518) << "file content.xml loaded " << endl;
+
+ loadAndParse( styles, "styles.xml", store);
+
+ loadAndParse( m_meta, "meta.xml", store);
+ loadAndParse( m_settings, "settings.xml", store);
+
+ delete store;
+
+ emit sigProgress( 10 );
+
+ if ( !createStyleMap( styles ) )
+ return KoFilter::UserCancelled;
+
+ return KoFilter::OK;
+}
+
+KoFilter::ConversionStatus OpenCalcImport::loadAndParse( QDomDocument& doc, const QString& fileName,KoStore *m_store )
+{
+ return OoUtils::loadAndParse( fileName, doc, m_store);
+}
+
+#include "opencalcimport.moc"
+
diff --git a/filters/kspread/opencalc/opencalcimport.h b/filters/kspread/opencalc/opencalcimport.h
new file mode 100644
index 000000000..57379796a
--- /dev/null
+++ b/filters/kspread/opencalc/opencalcimport.h
@@ -0,0 +1,119 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Norbert Andres <nandres@web.de>
+ Copyright (C) 2004 Montel Laurent <montel@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef OpenCalc_IMPORT_H__
+#define OpenCalc_IMPORT_H__
+
+#include <KoFilter.h>
+#include "kspread_format.h"
+
+#include <qdict.h>
+#include <qdom.h>
+
+class KoStyleStack;
+class KoStore;
+
+namespace KSpread
+{
+class Cell;
+class Conditional;
+class Doc;
+class Sheet;
+class Validity;
+}
+
+class OpenCalcImport : public KoFilter
+{
+ Q_OBJECT
+ public:
+ OpenCalcImport( KoFilter * parent, const char * name, const QStringList & );
+ virtual ~OpenCalcImport();
+
+ virtual KoFilter::ConversionStatus convert( QCString const & from, QCString const & to );
+
+
+ private:
+
+ class OpenCalcPoint
+ {
+ public:
+ OpenCalcPoint( QString const & str );
+
+ QString table;
+ QString translation;
+ QPoint topLeft;
+ QPoint botRight;
+ bool isRange;
+ };
+
+ enum bPos { Left, Top, Right, Bottom, Fall, GoUp, Border };
+
+ KSpread::Doc * m_doc;
+ KSpread::Format * m_defaultLayout;
+
+ QDomDocument m_content;
+ QDomDocument m_meta;
+ QDomDocument m_settings;
+
+ QDict<QDomElement> m_styles;
+ QDict<KSpread::Format> m_defaultStyles;
+ QDict<QString> m_formats;
+ QMap<QString,QDomElement> m_validationList;
+
+ QStringList m_namedAreas;
+
+ int readMetaData();
+ bool parseBody( int numOfTables );
+ void insertStyles( QDomElement const & element );
+ bool createStyleMap( QDomDocument const & styles );
+ bool readRowFormat( QDomElement & rowNode, QDomElement * rowStyle,
+ KSpread::Sheet * table, int & row, int & number, bool last );
+ bool readColLayouts( QDomElement & content, KSpread::Sheet * table );
+ bool readRowsAndCells( QDomElement & content, KSpread::Sheet * table );
+ bool readCells( QDomElement & rowNode, KSpread::Sheet * table, int row, int & columns );
+ void convertFormula( QString & text, QString const & f ) const;
+ void loadFontStyle( KSpread::Format * layout, QDomElement const * font ) const;
+ void readInStyle( KSpread::Format * layout, QDomElement const & style );
+ void loadStyleProperties( KSpread::Format * layout, QDomElement const & property ) const;
+ void loadBorder( KSpread::Format * layout, QString const & borderDef, bPos pos ) const;
+ void loadTableMasterStyle( KSpread::Sheet * table, QString const & stylename );
+ QString * loadFormat( QDomElement * element,
+ KSpread::FormatType & formatType,
+ QString name );
+ void checkForNamedAreas( QString & formula ) const;
+ void loadOasisCellValidation( const QDomElement&body );
+ void loadOasisValidation( KSpread::Validity* val, const QString& validationName );
+ void loadOasisValidationCondition( KSpread::Validity* val,QString &valExpression );
+ void loadOasisAreaName( const QDomElement&body );
+ void loadOasisMasterLayoutPage( KSpread::Sheet * table,KoStyleStack &styleStack );
+ void loadOasisValidationValue( KSpread::Validity* val, const QStringList &listVal );
+ QString translatePar( QString & par ) const;
+ void loadCondition( KSpread::Cell*cell,const QDomElement &property );
+ void loadOasisCondition(KSpread::Cell*cell,const QDomElement &property );
+ void loadOasisConditionValue( const QString &styleCondition, KSpread::Conditional &newCondition );
+ void loadOasisCondition( QString &valExpression, KSpread::Conditional &newCondition );
+ void loadOasisValidationValue( const QStringList &listVal, KSpread::Conditional &newCondition );
+ KoFilter::ConversionStatus loadAndParse( QDomDocument& doc, const QString& fileName,KoStore *m_store );
+
+ KoFilter::ConversionStatus openFile();
+};
+
+#endif // OpenCalc_IMPORT_H__
+
diff --git a/filters/kspread/opencalc/opencalcstyleexport.cc b/filters/kspread/opencalc/opencalcstyleexport.cc
new file mode 100644
index 000000000..34d574beb
--- /dev/null
+++ b/filters/kspread/opencalc/opencalcstyleexport.cc
@@ -0,0 +1,546 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Norbert Andres <nandres@web.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <opencalcstyleexport.h>
+
+#include <KoGlobal.h>
+
+#include <kspread_cell.h>
+#include <kspread_doc.h>
+#include <kspread_format.h>
+#include <kspread_sheet.h>
+#include <kspread_style.h>
+#include <kspread_style_manager.h>
+
+#include <qdom.h>
+
+using namespace KSpread;
+
+OpenCalcStyles::OpenCalcStyles()
+{
+ m_cellStyles.setAutoDelete( true );
+ m_columnStyles.setAutoDelete( true );
+ m_numberStyles.setAutoDelete( true );
+ m_rowStyles.setAutoDelete( true );
+ m_sheetStyles.setAutoDelete( true );
+
+ m_fontList.setAutoDelete( true );
+}
+
+OpenCalcStyles::~OpenCalcStyles()
+{
+}
+
+void OpenCalcStyles::writeStyles( QDomDocument & doc, QDomElement & autoStyles )
+{
+ addColumnStyles( doc, autoStyles );
+ addRowStyles( doc, autoStyles );
+ addSheetStyles( doc, autoStyles );
+ addNumberStyles( doc, autoStyles );
+ addCellStyles( doc, autoStyles );
+}
+
+void OpenCalcStyles::writeFontDecl( QDomDocument & doc, QDomElement & fontDecls )
+{
+ QFont * f = m_fontList.first();
+ while ( f )
+ {
+ QDomElement fontDecl = doc.createElement( "style:font-decl" );
+
+ fontDecl.setAttribute( "style:name", f->family() );
+ fontDecl.setAttribute( "fo:font-family", f->family() );
+ fontDecl.setAttribute( "style:font-pitch", ( f->fixedPitch() ? "fixed" : "variable" ) );
+
+ // missing:
+ // style:font-charset="x-symbol" style:font-family-generic="swiss"
+ // style:font-style-name= "Bold/Standard/Regular"
+
+ fontDecls.appendChild( fontDecl );
+
+ f = m_fontList.next();
+ }
+}
+
+void OpenCalcStyles::addFont( QFont const & font, bool def )
+{
+ if ( def )
+ m_defaultFont = font;
+
+ QFont * f = m_fontList.first();
+ while ( f )
+ {
+ if ( f->family() == font.family() )
+ return;
+
+ f = m_fontList.next();
+ }
+
+ f = new QFont( font );
+ m_fontList.append( f );
+}
+
+QString OpenCalcStyles::cellStyle( CellStyle const & cs )
+{
+ CellStyle * t = m_cellStyles.first();
+ while ( t )
+ {
+ if ( CellStyle::isEqual( t, cs ) )
+ return t->name;
+
+ t = m_cellStyles.next();
+ }
+
+ t = new CellStyle();
+ t->copyData( cs );
+
+ m_cellStyles.append( t );
+
+ t->name = QString( "ce%1" ).arg( m_cellStyles.count() );
+
+ return t->name;
+}
+
+QString OpenCalcStyles::columnStyle( ColumnStyle const & cs )
+{
+ ColumnStyle * t = m_columnStyles.first();
+ while ( t )
+ {
+ if ( ColumnStyle::isEqual( t, cs ) )
+ return t->name;
+
+ t = m_columnStyles.next();
+ }
+
+ t = new ColumnStyle();
+ t->copyData( cs );
+
+ m_columnStyles.append( t );
+
+ t->name = QString( "co%1" ).arg( m_columnStyles.count() );
+
+ return t->name;
+}
+
+QString OpenCalcStyles::numberStyle( NumberStyle const & )
+{
+ return "";
+}
+
+QString OpenCalcStyles::rowStyle( RowStyle const & rs )
+{
+ RowStyle * t = m_rowStyles.first();
+ while ( t )
+ {
+ if ( RowStyle::isEqual( t, rs ) )
+ return t->name;
+
+ t = m_rowStyles.next();
+ }
+
+ t = new RowStyle();
+ t->copyData( rs );
+
+ m_rowStyles.append( t );
+
+ t->name = QString( "ro%1" ).arg( m_rowStyles.count() );
+
+ return t->name;
+}
+
+QString OpenCalcStyles::sheetStyle( SheetStyle const & ts )
+{
+ SheetStyle * t = m_sheetStyles.first();
+ while ( t )
+ {
+ if ( SheetStyle::isEqual( t, ts ) )
+ return t->name;
+
+ t = m_sheetStyles.next();
+ }
+
+ t = new SheetStyle();
+ t->copyData( ts );
+
+ m_sheetStyles.append( t );
+
+ t->name = QString( "ta%1" ).arg( m_sheetStyles.count() );
+
+ return t->name;
+}
+
+QString convertPenToString( QPen const & pen )
+{
+ QString s( QString( "%1cm solid " ).arg( pen.width() * 0.035 ) );
+ s += pen.color().name();
+
+ return s;
+}
+
+void OpenCalcStyles::addCellStyles( QDomDocument & doc, QDomElement & autoStyles )
+{
+ CellStyle * t = m_cellStyles.first();
+ while ( t )
+ {
+ QDomElement ts = doc.createElement( "style:style" );
+ ts.setAttribute( "style:name", t->name );
+ ts.setAttribute( "style:family", "table-cell" );
+ ts.setAttribute( "style:parent-style-name", "Default" );
+ if ( t->numberStyle.length() > 0 )
+ ts.setAttribute( "style:data-style-name", t->numberStyle );
+
+ QDomElement prop = doc.createElement( "style:properties" );
+
+ if ( t->font.family() != m_defaultFont.family() )
+ prop.setAttribute( "style:font-name", t->font.family() );
+
+ if ( t->font.bold() != m_defaultFont.bold() )
+ prop.setAttribute( "fo:font-weight", ( t->font.bold() ? "bold" : "light" ) );
+
+ prop.setAttribute( "fo:font-size", QString( "%1pt" ).arg( t->font.pointSize() ) );
+
+ if ( t->font.underline() != m_defaultFont.underline() )
+ {
+ prop.setAttribute( "style:text-underline", ( t->font.underline() ? "single" : "none" ) );
+ if ( t->font.underline() )
+ prop.setAttribute( "style:text-underline-color", "font-color" );
+ }
+
+ if ( t->font.italic() != m_defaultFont.italic() )
+ prop.setAttribute( "fo:font-style", ( t->font.italic() ? "italic" : "none" ) );
+
+ if ( t->font.strikeOut() != m_defaultFont.strikeOut() )
+ prop.setAttribute( "style:text-crossing-out", ( t->font.strikeOut() ? "single-line" : "none" ) );
+
+ if ( t->color.name() != "#000000" )
+ prop.setAttribute( "fo:color", t->color.name() );
+
+ if ( t->bgColor.name() != "#ffffff" )
+ prop.setAttribute( "fo:background-color", t->bgColor.name() );
+
+ if ( t->alignX != Format::Undefined )
+ {
+ QString value;
+ if ( t->alignX == Format::Center )
+ value = "center";
+ else if ( t->alignX == Format::Right )
+ value = "end";
+ else if ( t->alignX == Format::Left )
+ value = "start";
+ prop.setAttribute( "fo:text-align", value );
+ }
+
+ if ( t->alignY != Format::Bottom ) // default in OpenCalc
+ prop.setAttribute( "fo:vertical-align", ( t->alignY == Format::Middle ? "middle" : "top" ) );
+
+ if ( t->indent > 0.0 )
+ {
+ prop.setAttribute( "fo:margin-left", QString( "%1pt" ).arg( t->indent ) );
+ if ( t->alignX == Format::Undefined )
+ prop.setAttribute( "fo:text-align", "start" );
+ }
+
+ if ( t->wrap )
+ prop.setAttribute( "fo:wrap-option", "wrap" );
+
+ if ( t->vertical )
+ {
+ prop.setAttribute( "fo:direction", "ttb" );
+ prop.setAttribute( "style:rotation-angle", "0" );
+ }
+
+ if ( t->angle != 0 )
+ prop.setAttribute( "style:rotation-angle", QString::number( t->angle ) );
+
+ if ( !t->print )
+ prop.setAttribute( "style:print-content", "false" );
+
+ if ( t->hideAll )
+ prop.setAttribute( "style:cell-protect", "hidden-and-protected" );
+ else
+ if ( t->notProtected && !t->hideFormula )
+ prop.setAttribute( "style:cell-protect", "none" );
+ else
+ if ( t->notProtected && t->hideFormula )
+ prop.setAttribute( "style:cell-protect", "formula-hidden" );
+ else if ( t->hideFormula )
+ prop.setAttribute( "style:cell-protect", "protected formula-hidden" );
+ else if ( !t->notProtected )
+ prop.setAttribute( "style:cell-protect", "protected" );
+
+
+ if ( ( t->left == t->right ) && ( t->left == t->top ) && ( t->left == t->bottom ) )
+ {
+ if ( ( t->left.width() != 0 ) && ( t->left.style() != Qt::NoPen ) )
+ prop.setAttribute( "fo:border", convertPenToString( t->left ) );
+ }
+ else
+ {
+ if ( ( t->left.width() != 0 ) && ( t->left.style() != Qt::NoPen ) )
+ prop.setAttribute( "fo:border-left", convertPenToString( t->left ) );
+
+ if ( ( t->right.width() != 0 ) && ( t->right.style() != Qt::NoPen ) )
+ prop.setAttribute( "fo:border-right", convertPenToString( t->right ) );
+
+ if ( ( t->top.width() != 0 ) && ( t->top.style() != Qt::NoPen ) )
+ prop.setAttribute( "fo:border-top", convertPenToString( t->top ) );
+
+ if ( ( t->bottom.width() != 0 ) && ( t->bottom.style() != Qt::NoPen ) )
+ prop.setAttribute( "fo:border-bottom", convertPenToString( t->bottom ) );
+ }
+
+ ts.appendChild( prop );
+ autoStyles.appendChild( ts );
+
+ t = m_cellStyles.next();
+ }
+}
+
+void OpenCalcStyles::addColumnStyles( QDomDocument & doc, QDomElement & autoStyles )
+{
+ ColumnStyle * t = m_columnStyles.first();
+ while ( t )
+ {
+ QDomElement ts = doc.createElement( "style:style" );
+ ts.setAttribute( "style:name", t->name );
+ ts.setAttribute( "style:family", "table-column" );
+
+ QDomElement prop = doc.createElement( "style:properties" );
+ if ( t->breakB != ::Style::none )
+ prop.setAttribute( "fo:break-before", ( t->breakB == ::Style::automatic ? "auto" : "page" ) );
+ prop.setAttribute( "style:column-width", QString( "%1cm" ).arg( t->size ) );
+
+ ts.appendChild( prop );
+ autoStyles.appendChild( ts );
+
+ t = m_columnStyles.next();
+ }
+}
+
+void OpenCalcStyles::addNumberStyles( QDomDocument & /*doc*/, QDomElement & /*autoStyles*/ )
+{
+}
+
+void OpenCalcStyles::addRowStyles( QDomDocument & doc, QDomElement & autoStyles )
+{
+ RowStyle * t = m_rowStyles.first();
+ while ( t )
+ {
+ QDomElement ts = doc.createElement( "style:style" );
+ ts.setAttribute( "style:name", t->name );
+ ts.setAttribute( "style:family", "table-row" );
+
+ QDomElement prop = doc.createElement( "style:properties" );
+ prop.setAttribute( "style:row-height", QString( "%1cm" ).arg( t->size ) );
+ if ( t->breakB != ::Style::none )
+ prop.setAttribute( "fo:break-before", ( t->breakB == ::Style::automatic ? "auto" : "page" ) );
+
+ ts.appendChild( prop );
+ autoStyles.appendChild( ts );
+
+ t = m_rowStyles.next();
+ }
+}
+
+void OpenCalcStyles::addSheetStyles( QDomDocument & doc, QDomElement & autoStyles )
+{
+ SheetStyle * t = m_sheetStyles.first();
+ while ( t )
+ {
+ QDomElement ts = doc.createElement( "style:style" );
+ ts.setAttribute( "style:name", t->name );
+ ts.setAttribute( "style:family", "table" );
+ ts.setAttribute( "style:master-page-name", "Default" );
+
+ QDomElement prop = doc.createElement( "style:properties" );
+ prop.setAttribute( "table:display", ( t->visible ? "true" : "false" ) );
+
+ ts.appendChild( prop );
+ autoStyles.appendChild( ts );
+
+ t = m_sheetStyles.next();
+ }
+}
+
+bool SheetStyle::isEqual( SheetStyle const * const t1, SheetStyle const & t2 )
+{
+ if ( t1->visible == t2.visible )
+ return true;
+
+ return false;
+}
+
+CellStyle::CellStyle()
+ : color( Qt::black ),
+ bgColor( Qt::white ),
+ indent( -1.0 ),
+ wrap( false ),
+ vertical( false ),
+ angle( 0 ),
+ print( true ),
+ left ( Qt::black, 0, Qt::NoPen ),
+ right( Qt::black, 0, Qt::NoPen ),
+ top ( Qt::black, 0, Qt::NoPen ),
+ bottom( Qt::black, 0, Qt::NoPen ),
+ hideAll( false ),
+ hideFormula( false ),
+ notProtected ( false ),
+ alignX( Format::Undefined ),
+ alignY( Format::Middle )
+{
+}
+
+void CellStyle::copyData( CellStyle const & ts )
+{
+ font = ts.font;
+ numberStyle = ts.numberStyle;
+ color = ts.color;
+ bgColor = ts.bgColor;
+ indent = ts.indent;
+ wrap = ts.wrap;
+ vertical = ts.vertical;
+ angle = ts.angle;
+ print = ts.print;
+ left = ts.left;
+ right = ts.right;
+ top = ts.top;
+ bottom = ts.bottom;
+ hideAll = ts.hideAll;
+ hideFormula = ts.hideFormula;
+ notProtected = ts.notProtected;
+ alignX = ts.alignX;
+ alignY = ts.alignY;
+}
+
+bool CellStyle::isEqual( CellStyle const * const t1, CellStyle const & t2 )
+{
+ if ( ( t1->font == t2.font ) && ( t1->numberStyle == t2.numberStyle )
+ && ( t1->color == t2.color ) && ( t1->bgColor == t2.bgColor )
+ && ( t1->alignX == t2.alignX ) && ( t1->alignY == t2.alignY )
+ && ( t1->indent == t2.indent ) && ( t1->wrap == t2.wrap )
+ && ( t1->vertical == t2.vertical ) && ( t1->angle == t2.angle )
+ && ( t1->print == t2.print ) && ( t1->left == t2.left )
+ && ( t1->right == t2.right ) && ( t1->top == t2.top )
+ && ( t1->bottom == t2.bottom ) && ( t1->hideAll == t2.hideAll )
+ && ( t1->hideFormula == t2.hideFormula ) && ( t1->notProtected == t2.notProtected )
+ )
+ return true;
+
+ return false;
+}
+
+// all except the number style
+void CellStyle::loadData( CellStyle & cs, Cell const * const cell )
+{
+ int col = cell->column();
+ int row = cell->row();
+
+ Format * f = new Format( 0, cell->sheet()->doc()->styleManager()->defaultStyle() );
+
+ QFont font = cell->format()->textFont( col, row );
+ if ( font != f->font() )
+ cs.font = font;
+
+ QColor color = cell->format()->textColor( col, row );
+ if ( color != f->textColor( col, row ) )
+ cs.color = color;
+
+ QColor bgColor = cell->bgColor( col, row );
+ if ( bgColor != f->bgColor( col, row ) )
+ cs.bgColor = bgColor;
+
+ if ( cell->format()->hasProperty( Format::PAlign ) || !cell->format()->hasNoFallBackProperties( Format::PAlign ) )
+ cs.alignX = cell->format()->align( col, row );
+
+ if ( cell->format()->hasProperty( Format::PAlignY ) || !cell->format()->hasNoFallBackProperties( Format::PAlignY ) )
+ cs.alignY = cell->format()->alignY( col, row );
+
+ if ( cell->format()->hasProperty( Format::PIndent ) || !cell->format()->hasNoFallBackProperties( Format::PIndent ) )
+ cs.indent = cell->format()->getIndent( col, row );
+
+ if ( cell->format()->hasProperty( Format::PAngle ) || !cell->format()->hasNoFallBackProperties( Format::PAngle ) )
+ cs.angle = -cell->format()->getAngle( col, row );
+
+ if ( cell->format()->hasProperty( Format::PMultiRow ) || !cell->format()->hasNoFallBackProperties( Format::PMultiRow ) )
+ cs.wrap = cell->format()->multiRow( col, row );
+
+ if ( cell->format()->hasProperty( Format::PVerticalText )
+ || !cell->format()->hasNoFallBackProperties( Format::PVerticalText ) )
+ cs.vertical = cell->format()->verticalText( col, row );
+
+ if ( cell->format()->hasProperty( Format::PDontPrintText )
+ || !cell->format()->hasNoFallBackProperties( Format::PDontPrintText ) )
+ cs.print = !cell->format()->getDontprintText( col, row );
+
+ if ( cell->format()->hasProperty( Format::PLeftBorder ) || !cell->format()->hasNoFallBackProperties( Format::PLeftBorder ) )
+ cs.left = cell->leftBorderPen( col, row );
+
+ if ( cell->format()->hasProperty( Format::PRightBorder ) || !cell->format()->hasNoFallBackProperties( Format::PRightBorder ) )
+ cs.right = cell->rightBorderPen( col, row );
+
+ if ( cell->format()->hasProperty( Format::PTopBorder ) || !cell->format()->hasNoFallBackProperties( Format::PTopBorder ) )
+ cs.top = cell->topBorderPen( col, row );
+
+ if ( cell->format()->hasProperty( Format::PBottomBorder ) || !cell->format()->hasNoFallBackProperties( Format::PBottomBorder ) )
+ cs.bottom = cell->bottomBorderPen( col, row );
+
+ if ( cell->format()->hasProperty( Format::PNotProtected ) || !cell->format()->hasNoFallBackProperties( Format::PNotProtected ) )
+ cs.notProtected = cell->format()->notProtected( col, row );
+
+ if ( cell->format()->hasProperty( Format::PHideAll ) || !cell->format()->hasNoFallBackProperties( Format::PHideAll ) )
+ cs.hideAll = cell->format()->isHideAll( col, row );
+
+ if ( cell->format()->hasProperty( Format::PHideFormula ) || !cell->format()->hasNoFallBackProperties( Format::PHideFormula ) )
+ cs.hideFormula = cell->format()->isHideFormula( col, row );
+}
+
+bool NumberStyle::isEqual( NumberStyle const * const t1, NumberStyle const & t2 )
+{
+ if ( ( t1->type == t2.type ) && ( t1->pattern == t2.pattern ) )
+ return true;
+
+ return false;
+}
+
+void ColumnStyle::copyData( ColumnStyle const & cs )
+{
+ breakB = cs.breakB;
+ size = cs.size;
+}
+
+bool ColumnStyle::isEqual( ColumnStyle const * const c1, ColumnStyle const & c2 )
+{
+ if ( ( c1->breakB == c2.breakB ) && ( c1->size == c2.size ) )
+ return true;
+
+ return false;
+}
+
+void RowStyle::copyData( RowStyle const & cs )
+{
+ breakB = cs.breakB;
+ size = cs.size;
+}
+
+bool RowStyle::isEqual( RowStyle const * const c1, RowStyle const & c2 )
+{
+ if ( ( c1->breakB == c2.breakB ) && ( c1->size == c2.size ) )
+ return true;
+
+ return false;
+}
diff --git a/filters/kspread/opencalc/opencalcstyleexport.h b/filters/kspread/opencalc/opencalcstyleexport.h
new file mode 100644
index 000000000..2321b5290
--- /dev/null
+++ b/filters/kspread/opencalc/opencalcstyleexport.h
@@ -0,0 +1,167 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Norbert Andres <nandres@web.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef OPENCALCSTYLEEXPORT_H
+#define OPENCALCSTYLEEXPORT_H
+
+#include "kspread_format.h"
+
+#include <qcolor.h>
+#include <qfont.h>
+#include <qptrlist.h>
+#include <qstring.h>
+
+namespace KSpread
+{
+ class Cell;
+}
+
+class QDomDocument;
+class QDomElement;
+
+typedef enum T1 { Boolean, Date, Number, Percentage, Time } NumberType;
+
+class Style
+{
+ public:
+ enum breakBefore { none, automatic, page };
+
+ Style() : breakB( none ), size( 0.0 ) {}
+
+ QString name;
+ uint breakB;
+ double size;
+};
+
+class SheetStyle
+{
+ public:
+ SheetStyle() : visible( true ) {}
+
+ void copyData( SheetStyle const & ts ) { visible = ts.visible; }
+ static bool isEqual( SheetStyle const * const t1, SheetStyle const & t2 );
+
+ QString name;
+ bool visible;
+};
+
+class NumberStyle
+{
+ public:
+ NumberStyle() {}
+
+ void copyData( NumberStyle const & ts ) { type = ts.type; }
+ static bool isEqual( NumberStyle const * const t1, NumberStyle const & t2 );
+
+ QString name;
+
+ NumberType type;
+ QString pattern;
+};
+
+class CellStyle
+{
+ public:
+ CellStyle();
+
+ void copyData( CellStyle const & ts );
+ static bool isEqual( CellStyle const * const t1, CellStyle const & t2 );
+
+ // all except the number style
+ static void loadData( CellStyle & cs, KSpread::Cell const * const cell );
+
+ QString name;
+
+ QFont font;
+ QString numberStyle;
+ QColor color;
+ QColor bgColor;
+ double indent;
+ bool wrap;
+ bool vertical;
+ int angle;
+ bool print;
+ QPen left;
+ QPen right;
+ QPen top;
+ QPen bottom;
+ bool hideAll;
+ bool hideFormula;
+ bool notProtected;
+
+ KSpread::Format::Align alignX;
+ KSpread::Format::AlignY alignY;
+};
+
+class ColumnStyle : public Style
+{
+ public:
+ ColumnStyle() : Style() {}
+
+ void copyData( ColumnStyle const & cs );
+ static bool isEqual( ColumnStyle const * const c1, ColumnStyle const & c2 );
+};
+
+class RowStyle : public Style
+{
+ public:
+ RowStyle() : Style() {}
+
+ void copyData( RowStyle const & cs );
+ static bool isEqual( RowStyle const * const c1, RowStyle const & c2 );
+};
+
+class OpenCalcStyles
+{
+ public:
+ OpenCalcStyles();
+ ~OpenCalcStyles();
+
+ void writeStyles ( QDomDocument & doc, QDomElement & autoStyles );
+ void writeFontDecl( QDomDocument & doc, QDomElement & content );
+
+ void addFont( QFont const & font, bool def = false );
+
+ QString cellStyle( CellStyle const & cs );
+ QString columnStyle( ColumnStyle const & cs );
+ QString numberStyle( NumberStyle const & ns );
+ QString rowStyle( RowStyle const & rs );
+ QString sheetStyle( SheetStyle const & ts );
+
+ private:
+ QPtrList<CellStyle> m_cellStyles;
+ QPtrList<ColumnStyle> m_columnStyles;
+ QPtrList<NumberStyle> m_numberStyles;
+ QPtrList<RowStyle> m_rowStyles;
+ QPtrList<SheetStyle> m_sheetStyles;
+ QPtrList<QFont> m_fontList;
+
+ QFont m_defaultFont;
+
+ void addCellStyles( QDomDocument & doc, QDomElement & autoStyles );
+ void addColumnStyles( QDomDocument & doc, QDomElement & autoStyles );
+ void addNumberStyles( QDomDocument & doc, QDomElement & autoStyles );
+ void addRowStyles( QDomDocument & doc, QDomElement & autoStyles );
+ void addSheetStyles( QDomDocument & doc, QDomElement & autoStyles );
+};
+
+
+
+#endif
diff --git a/filters/kspread/opencalc/status.html b/filters/kspread/opencalc/status.html
new file mode 100644
index 000000000..b23f6ae90
--- /dev/null
+++ b/filters/kspread/opencalc/status.html
@@ -0,0 +1,208 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>KOffice filters status: OpenOffice.org Calc filter</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<a NAME="START"></a>
+<center>
+<h1>
+KOffice filters status:&nbsp;&nbsp; OpenOffice.org Calc</h1></center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%"><b><font size="-1"><a href="#import">Import</a>
+| <a href="#export">Export</a></font></b>
+<br>&nbsp;
+<br>&nbsp;
+<br>
+<br>
+<center>
+<p><a NAME="import"></a></center>
+<b><font size="-1"><a href="#START">Up</a></font></b>
+<center><table BORDER=0 CELLSPACING=0 WIDTH="100%" BGCOLOR="#000000" >
+<tr>
+<td>
+<table BORDER=0 CELLPADDING=2 WIDTH="100%" BGCOLOR="#FFFFFF" >
+<tr BGCOLOR="#DDFFDD">
+<td COLSPAN="2">
+<center><b><i><font size="+1">Import OpenOffice.org Calc for Kspread</font></i></b></center>
+</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP NOWRAP WIDTH="1%"><b><font size="+1">Last update</font></b></td>
+
+<td>April 22, 2004</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>
+ Loading tables, hidden tables, print ranges<br>
+ Named areas<br>
+ hidden columns<br>
+ hidden rows<br>
+ Comments<br>
+ Formulas<br>
+ Links (e-mail, files, web)<br>
+ cell content<br>
+ Datatypes: float, percentage, (date), times, booleans (miss some kspread support) <br>
+ Formating: indents, bold, italic, alignments, colors...<br>
+ Borders, background colors<br>
+ column width, row width<br>
+ column layouts, row layouts<br>
+ page layout (size, border)<br>
+ OpenCalc style import, default style<br>
+ format string translating (not supported by KSpread yet, but this filter produces these strings => needs enhancements in KSpread)<br>
+ header, footer (including macros)<br>
+ protected maps, tables, unprotected cells, hidden cells, hidden formulas<br>
+ validation<br>
+ not printed cells
+ </td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+<td>
+ Page breaks (for Columns &amp; Rows)(not supported by KSpread)<br>
+ leading zeros (not supported by KSpread)<br>
+ embedded objects (Charts!)<br>
+ conditional cell attributes<br>
+ real format string usage(KSpread feature not implemented yet - as soon as it exists this filter will benefit automatically)
+ check Table names in "'", like 'This is my name'<br>
+ Settings<br>
+</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">History</font></b></td>
+
+<td>
+ Sep 26, 2002 - Initial Revision<br>
+</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+<td>
+ <a href="mailto:nandres@web.de">Norbert Andres</a>
+</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+<td><a href="http://xml.openoffice.org">OpenOffice.org XML Web Site</a></td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Progress report&nbsp;</font></b></td>
+<td></td>
+</tr>
+</table>
+</td>
+</tr>
+</table></center>
+<b><font size="-1"><a href="#START">Up</a></font></b>
+<br>&nbsp;
+<p>
+<hr NOSHADE SIZE=1>
+<br>&nbsp;
+<br>&nbsp;
+<br>
+<br>
+<center>
+<p><a NAME="export"></a></center>
+<b><font size="-1"><a href="#START">Up</a></font></b>
+<center><table BORDER=0 CELLSPACING=0 WIDTH="100%" BGCOLOR="#000000" >
+<tr>
+<td>
+<table BORDER=0 CELLPADDING=2 WIDTH="100%" BGCOLOR="#FFFFFF" >
+<tr BGCOLOR="#FFDDDD">
+<td COLSPAN="2">
+<center><b><i><font size="+1">Export Kspread to OpenOffice.org Calc</font></i></b></center>
+</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP NOWRAP WIDTH="1%"><b><font size="+1">Last update</font></b></td>
+
+<td>Octo 20, 2004</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+<td>
+ Saves sheets (supported: hidden sheets, names)<br>
+ Saves columns and row (supported: widths/heights, page breaks, hidden)<br>
+ Saves cell contents (including formula conversion)<br>
+ Document information<br>
+ Page sizes, header and footer (including variable converting)<br>
+ Font (sizes, attributes, color)<br>
+ Background color<br>
+ Text alignment, angle, vertical text, text wrap and indents<br>
+ Merged Cells<br>
+ DontPrint flag<br>
+ Comments<br>
+ Named Areas<br>
+ Cell borders<br>
+ Link<br>
+ protected maps, tables, unprotected cells, hidden cells, hidden formulas<br>
+ not printed cells<br>
+ Print ranges<br>
+ Export document settings (active table, cursor position)<br>
+ Settings<br>
+ Validation<br>
+</td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+<td>
+ Number formats (needs some new features in KSpread)<br>
+ Embedded objects (charts,...)<br>
+ Conditions<br>
+</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">History</font></b></td>
+
+<td>
+ Jan 12, 2003 - Initial Revision<br>
+ Jan 18, 2003 - page layout, header, footer<br>
+ Jan 19, 2003 - Added support for fonts, text color, background color, formula
+conversion<br>
+ Jan 19, 2003 - text alignment, indents, comments, NoPrint, Merged Cells<br>
+ Jan 19, 2003 - angle, vertical text, text wrap<br>
+ Jan 19, 2003 - named area, hidden columns and rows<br>
+ Jan 20, 2003 - cell borders<br>
+ Jan 29, 2003 - protected stuff<br>
+ Mar 13, 2005 - link<br>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+
+<td>
+ <a href="mailto:nandres@web.de">Norbert Andres</a>
+</td>
+</tr>
+
+<tr BGCOLOR="#CCCCFF">
+<td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+
+<td><a href="http://xml.openoffice.org">OpenOffice.org XML Web Site</a></td>
+</tr>
+
+<tr BGCOLOR="#EEEEFF">
+<td VALIGN=TOP><b><font size="+1">Progress report</font></b></td>
+<td></td>
+</tr>
+</table>
+</td>
+</tr>
+</table></center>
+<b><font size="-1"><a href="#START">Up</a></font></b>
+
+</body>
+</html>
diff --git a/filters/kspread/qpro/Makefile.am b/filters/kspread/qpro/Makefile.am
new file mode 100644
index 000000000..9f34af473
--- /dev/null
+++ b/filters/kspread/qpro/Makefile.am
@@ -0,0 +1,22 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) -I$(srcdir)/libqpro -I$(top_srcdir)/kspread \
+ $(KOFFICE_INCLUDES) \
+ $(KOTEXT_INCLUDES) $(all_includes)
+
+####### Files
+
+SUBDIRS = libqpro
+
+kde_module_LTLIBRARIES = libqproimport.la
+
+libqproimport_la_SOURCES = qproimport.cc qproformula.cc
+
+libqproimport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libqproimport_la_LIBADD = $(KOFFICE_LIBS) ../../../kspread/libkspreadcommon.la \
+ libqpro/src/libqpro.la
+
+METASOURCES = AUTO
+
+service_DATA = kspread_qpro_import.desktop
+servicedir = $(kde_servicesdir)
diff --git a/filters/kspread/qpro/kspread_qpro_import.desktop b/filters/kspread/qpro/kspread_qpro_import.desktop
new file mode 100644
index 000000000..386a948ef
--- /dev/null
+++ b/filters/kspread/qpro/kspread_qpro_import.desktop
@@ -0,0 +1,74 @@
+[Desktop Entry]
+Type=Service
+Name=Quattro Pro Import Filter for KSpread
+Name[af]=Quattro Pro In voer Filter vir Kspread
+Name[ar]=مِرْشَح استيراد Quattro Pro لدى KSpread
+Name[az]=KSpread üçün Quattro Pro Alma Süzgəci
+Name[bg]=Филтър за импортиране от Quattro Pro в KSpread
+Name[br]=Sil enporzh Quattro Pro evit KSpread
+Name[bs]=Quattro Pro Import Filter za KSpread
+Name[ca]=Filtre d'importació Quattro Pro per a KSpread
+Name[cs]=Quattro Pro importní filtr pro KSpread
+Name[cy]=Hidlen Fewnforio Quattro Pro i KSpread
+Name[da]=Quattro Pro-importfilter for KSpread
+Name[de]=KSpread Quattro Pro-Importfilter
+Name[el]=Φίλτρο εισαγωγής Quattro Pro για το KSpread
+Name[eo]=Quattro Pro - importfiltrilo por KSpread
+Name[es]=Filtro de importación Quattro Pro para KSpread
+Name[et]=KSpreadi Quattro Pro impordifilter
+Name[eu]=KSpread-en Quattro Pro inportaziorako iragazkia
+Name[fa]=پالایۀ واردات Quattro Pro برای KSpread
+Name[fi]=Quattro Pro tuontisuodin KSpeadiin
+Name[fr]=Filtre d'importation Quattro Pro pour KSpread
+Name[fy]=Quattro Pro Ymportfilter foar KSpread
+Name[ga]=Scagaire Iompórtála Quattro Pro le haghaidh KSpread
+Name[gl]=Filtro de Importación de Quattro Pro para KSpread
+Name[he]=מסנן ייבוא מ־Quattro Pro ל־KSpread
+Name[hi]=के-स्प्रेड के लिए क्वात्रो प्रो आयात छननी
+Name[hr]=Quattro Pro filtar uvoza za KSpread
+Name[hu]=Quattro Pro importszűrő a KSpreadhez
+Name[is]=Quattro Pro innflutningssía fyrir KSpread
+Name[it]=Filtro di importazione Quattro Pro per KSpread
+Name[ja]=KSpread Quattro Pro インポートフィルタ
+Name[km]=តម្រង​នាំចូល Quattro Pro សម្រាប់ KSpread
+Name[lo]= ຕົວຕອງການນຳເຂົ້າQuattro Pro ຂອງກະດາດຄຳນວນ K
+Name[lt]=Quattro Pro importo filtras skirtas KSpread
+Name[lv]=Quattro Pro importa filtrs priekš KSpread
+Name[ms]=Penapis Import Quattro Pro bagi KSpread
+Name[mt]=Filtru għall-importazzjoni ta' Quattro Pro ġo KSpread
+Name[nb]=Quattro Pro-importfilter for KSpread
+Name[nds]="Quattro Pro"-Importfilter för KSpread
+Name[ne]=केडीई स्प्रिेडका लागि क्वाट्रो प्रो आयात फिल्टर
+Name[nl]=Quattro Pro-importfilter voor KSpread
+Name[nn]=Quattro Pro-importfilter for KSpread
+Name[pl]=Filtr importu formatu Quattro Pro dla KSpread
+Name[pt]=Filtro de Importação de Quattro Pro para o KSpread
+Name[pt_BR]=Filtro de importação Quattro Pro para o KSpread
+Name[ro]=Filtru importare KWord pentru Quattro Pro
+Name[ru]=Фильтр импорта таблиц Quattro Pro в KSpread
+Name[se]=KSpread:a Quattro Pro-sisafievrridansilli
+Name[sk]=Filter pre import Quattro Pro do KSpread
+Name[sl]=Uvozni filter Quattro Pro za KSpread
+Name[sr]=KSpread-ов филтер за увоз из Quattro Pro-а
+Name[sr@Latn]=KSpread-ov filter za uvoz iz Quattro Pro-a
+Name[sv]=Quattro Pro-importfilter för Kspread
+Name[ta]=KSpread Quattro Pro இறக்குமதி வடிகட்டி
+Name[tg]=Филтри Воридоти Quattro Pro барои KSpread
+Name[th]=ตัวกรองการนำเข้า Quattro Pro ของกระดาษคำนวณ K
+Name[tr]=KSpread için Quattro Pro Alma Filtresi
+Name[uk]=Фільтр імпорту Quattro Pro для KSpread
+Name[uz]=KSpread uchun Quattro Pro import filteri
+Name[uz@cyrillic]=KSpread учун Quattro Pro импорт филтери
+Name[ven]=Filithara yau u dzhenisa nga ngomu yau phadaladza ha K ya Quattro Pro
+Name[wa]=Passete Quattro Pro d' intrêye po KSpread
+Name[xh]=Quattro Pro Yesihluzi Sokurhweba se KSpread
+Name[zh_CN]=KSpread 的 Quattro Pro 导入过滤器
+Name[zh_TW]=KSpread 的 Quattro Pro 匯入過濾程式
+X-KDE-Export=application/x-kspread
+X-KDE-Import=application/x-quattropro
+X-KDE-Weight=1
+X-KDE-Library=libqproimport
+X-KDE-LibraryMajor=1
+X-KDE-LibraryMinor=0
+X-KDE-LibraryDependencies=
+ServiceTypes=KOfficeFilter
diff --git a/filters/kspread/qpro/libqpro/AUTHORS b/filters/kspread/qpro/libqpro/AUTHORS
new file mode 100644
index 000000000..5edadb53f
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/AUTHORS
@@ -0,0 +1,3 @@
+This package was written by Graham Short.
+
+email - grahshrt@netscape.net
diff --git a/filters/kspread/qpro/libqpro/COPYING b/filters/kspread/qpro/libqpro/COPYING
new file mode 100644
index 000000000..623b6258a
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/filters/kspread/qpro/libqpro/ChangeLog b/filters/kspread/qpro/libqpro/ChangeLog
new file mode 100644
index 000000000..35dbf4c2f
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/ChangeLog
@@ -0,0 +1,119 @@
+2001-04-30 gshort <gshort@playroom.ssl.co.uk>
+
+ * /cvsroot/libqpro/libqpro/libqpro.lsm: Added QP_DEBUG macro
+
+2001-04-22 gshort <gshort@playroom.ssl.co.uk>
+
+ * /cvsroot/libqpro/libqpro/Makefile.in: Update version number to 0.2
+
+ * /cvsroot/libqpro/libqpro/src/record.cc, /cvsroot/libqpro/libqpro/src/record_factory.cc, /cvsroot/libqpro/libqpro/src/stream.cc, /cvsroot/libqpro/libqpro/src/tablenames.cc:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/src/record.cc, /cvsroot/libqpro/libqpro/src/record_factory.cc, /cvsroot/libqpro/libqpro/src/stream.cc, /cvsroot/libqpro/libqpro/src/tablenames.cc:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/src/formula.cc:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/src/formula.cc: New file.
+
+ * /cvsroot/libqpro/libqpro/src/Makefile.am, /cvsroot/libqpro/libqpro/src/Makefile.in:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/src/Makefile.am, /cvsroot/libqpro/libqpro/src/Makefile.in:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/qpro/stream.h, /cvsroot/libqpro/libqpro/qpro/tablenames.h:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/qpro/stream.h, /cvsroot/libqpro/libqpro/qpro/tablenames.h:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/qpro/record_factory.h, /cvsroot/libqpro/libqpro/qpro/record.h:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/qpro/record_factory.h, /cvsroot/libqpro/libqpro/qpro/record.h:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/qpro/formula.h:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/qpro/formula.h: New file.
+
+ * /cvsroot/libqpro/libqpro/qpro/Makefile.am, /cvsroot/libqpro/libqpro/qpro/Makefile.in:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/qpro/Makefile.am, /cvsroot/libqpro/libqpro/qpro/Makefile.in:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/config/missing, /cvsroot/libqpro/libqpro/config/mkinstalldirs:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/config/missing, /cvsroot/libqpro/libqpro/config/mkinstalldirs:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/config/ltmain.sh:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/config/ltmain.sh: New file.
+
+ * /cvsroot/libqpro/libqpro/config/ltconfig:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/config/ltconfig: New file.
+
+ * /cvsroot/libqpro/libqpro/config/install-sh:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/config/install-sh: New file.
+
+ * /cvsroot/libqpro/libqpro/config/config.sub:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/config/config.sub: New file.
+
+ * /cvsroot/libqpro/libqpro/config/config.guess:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/config/config.guess: New file.
+
+ * /cvsroot/libqpro/libqpro/bootstrap, /cvsroot/libqpro/libqpro/configure, /cvsroot/libqpro/libqpro/configure.in, /cvsroot/libqpro/libqpro/libqpro.lsm:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/bootstrap, /cvsroot/libqpro/libqpro/configure, /cvsroot/libqpro/libqpro/configure.in, /cvsroot/libqpro/libqpro/libqpro.lsm:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/aclocal.m4, /cvsroot/libqpro/libqpro/config.h.in:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/aclocal.m4, /cvsroot/libqpro/libqpro/config.h.in:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/acinclude.m4:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/acinclude.m4: New file.
+
+ * /cvsroot/libqpro/libqpro/INSTALL, /cvsroot/libqpro/libqpro/Makefile.am, /cvsroot/libqpro/libqpro/NEWS, /cvsroot/libqpro/libqpro/TODO:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/INSTALL, /cvsroot/libqpro/libqpro/Makefile.am, /cvsroot/libqpro/libqpro/NEWS, /cvsroot/libqpro/libqpro/TODO:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/ChangeLog, /cvsroot/libqpro/libqpro/COPYING:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/ChangeLog, /cvsroot/libqpro/libqpro/COPYING:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/AUTHORS, /cvsroot/libqpro/libqpro/README, /cvsroot/libqpro/libqpro/stamp-h.in:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/AUTHORS, /cvsroot/libqpro/libqpro/README, /cvsroot/libqpro/libqpro/stamp-h.in:
+ New file.
+
+ * /cvsroot/libqpro/libqpro/Makefile.in:
+ libqpro library. C++ libray for reading & writing Quattro Pro spreadsheet files.
+
+ * /cvsroot/libqpro/libqpro/Makefile.in: New file.
+
diff --git a/filters/kspread/qpro/libqpro/INSTALL b/filters/kspread/qpro/libqpro/INSTALL
new file mode 100644
index 000000000..b42a17ac4
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/filters/kspread/qpro/libqpro/Makefile.am b/filters/kspread/qpro/libqpro/Makefile.am
new file mode 100644
index 000000000..1cc5e3cd6
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = qpro src
+
+EXTRA_DIST = libqpro.lsm
diff --git a/filters/kspread/qpro/libqpro/NEWS b/filters/kspread/qpro/libqpro/NEWS
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/NEWS
diff --git a/filters/kspread/qpro/libqpro/README b/filters/kspread/qpro/libqpro/README
new file mode 100644
index 000000000..d8c76ef3a
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/README
@@ -0,0 +1,31 @@
+libqpro library
+===============
+
+Purpose
+-------
+This C++ library provides functionality for reading and (eventually) writing
+Quattro Pro spreadsheet files.
+
+The library is designed as a tool for developers and does not provide any
+(useful) programs itself.
+
+The library was originally designed and written for the KSpread KDE
+spreadsheet program as part of the Quattro Pro filter. I have tried to write
+it as a reusable set of classes so that it may used by other people,
+particularly those writing spreadsheet filters.
+
+KOffice programs rely heavily on the QT set of classes. A QT interface to
+the library provides a lot of advantages. However I realise that not everyone
+wants to include QT in their code and so the package produces either one or
+two libraries. If QT is installed on the build machine then both libraries
+are built, otherwise only the non-QT library is produced.
+
+Installation
+------------
+To compile and install enter the usual:
+ ./configure
+ make
+ make install
+
+
+
diff --git a/filters/kspread/qpro/libqpro/TODO b/filters/kspread/qpro/libqpro/TODO
new file mode 100644
index 000000000..ae0cbb8cf
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/TODO
@@ -0,0 +1,11 @@
+1. Add USE_QT option to build a QT version of the library
+2. Add options to FormulaAsText function. e.g. optionRemoveAt to
+make removal of leading @ on functions optional.
+3. Split classes into individual files
+4. Add missing functions to FormulaAsText
+5. Add dmalloc option
+6. Add more record types
+7. Add output functionality so that Quattro Pro files can be created
+as well as read.
+8. Add test program
+9. Port to other platforms?
diff --git a/filters/kspread/qpro/libqpro/libqpro.lsm b/filters/kspread/qpro/libqpro/libqpro.lsm
new file mode 100644
index 000000000..096541504
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/libqpro.lsm
@@ -0,0 +1,23 @@
+Begin4
+Title: libqpro
+Version: 0.3
+Entered-date: 2001-04-22
+Description: This C++ library provides functionality for reading and (eventually) writing
+ Quattro Pro spreadsheet files.
+
+ The library is designed as a tool for developers and does not provide any
+ (useful) programs itself.
+
+ The library was originally designed and written for the KSpread KDE
+ spreadsheet program as part of the Quattro Pro filter. I have tried to write
+ it as a reusable set of classes so that it may used by other people,
+ particularly those writing spreadsheet filters.
+Keywords: quattro pro, spreadsheet
+Author: gshort@users.sourceforge.net (Graham Short)
+Maintained-by: gshort@users.sourceforge.net
+Primary-site: http://libqpro.sourceforge.net
+Alternate-site:
+Original-site:
+Platforms: linux, Compiled on various Unix but not tested.
+Copying-policy: GPL
+End
diff --git a/filters/kspread/qpro/libqpro/qpro/Makefile.am b/filters/kspread/qpro/libqpro/qpro/Makefile.am
new file mode 100644
index 000000000..d389104c6
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/qpro/Makefile.am
@@ -0,0 +1 @@
+noinst_HEADERS = common.h formula.h record.h record_factory.h stream.h tablenames.h
diff --git a/filters/kspread/qpro/libqpro/qpro/common.h b/filters/kspread/qpro/libqpro/qpro/common.h
new file mode 100644
index 000000000..a312d6322
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/qpro/common.h
@@ -0,0 +1,11 @@
+#ifndef QPRO_COMMON_H
+#define QPRO_COMMON_H
+
+#ifdef QP_TRACE
+#define QP_DEBUG(x) cerr << x
+#else
+#define QP_DEBUG(x)
+#endif
+
+#endif // QPRO_COMMON_H
+
diff --git a/filters/kspread/qpro/libqpro/qpro/formula.h b/filters/kspread/qpro/libqpro/qpro/formula.h
new file mode 100644
index 000000000..6edd52b53
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/qpro/formula.h
@@ -0,0 +1,128 @@
+#ifndef QPRO_FORMULA_H
+#define QPRO_FORMULA_H
+
+#include <qpro/tablenames.h>
+#include <qpro/stream.h>
+#include <qpro/record.h>
+
+class QpFormula;
+
+// --------------------------------------------------------------------
+
+class QpFormulaStack
+{
+public:
+ QpFormulaStack();
+ ~QpFormulaStack();
+
+ void bracket(const char* pBefore="(", const char* pAfter=")");
+ void push(const char* pString);
+ void pop(int pCnt=1);
+ void join(int pCnt, const char* pSeparator=",");
+ const char* top();
+
+ const char* operator [] (int pIdx);
+
+protected:
+ int cIdx;
+ int cMax;
+
+ char** cStack;
+};
+
+
+// --------------------------------------------------------------------
+
+struct QpFormulaConv
+{
+ QP_INT8 cOperand;
+ void (*cFunc)(QpFormula& pThis, const char* pArg);
+ const char* cArg;
+};
+
+// --------------------------------------------------------------------
+
+class QpFormula
+{
+public:
+ QpFormula(QpRecFormulaCell& pCell, QpTableNames& pTable);
+ ~QpFormula();
+
+ void argSeparator(const char* pArg);
+
+ char* formula();
+
+
+ static void binaryOperand(QpFormula& pThis, const char* pOper)
+ {pThis.binaryOperandReal(pOper);}
+
+ static void floatFunc(QpFormula& pThis, const char* pFunc)
+ {pThis.floatFuncReal(pFunc);}
+
+ void formulaStart(const char* pFirstChar);
+
+ static void absKludge(QpFormula& pThis, const char* pFunc)
+ {pThis.absKludgeReal(pFunc);}
+
+ static void func0(QpFormula& pThis, const char* pFunc)
+ {pThis.func0Real(pFunc);}
+
+ static void func1(QpFormula& pThis, const char* pFunc)
+ {pThis.func1Real(pFunc);}
+
+ static void func2(QpFormula& pThis, const char* pFunc)
+ {pThis.func2Real(pFunc);}
+
+ static void func3(QpFormula& pThis, const char* pFunc)
+ {pThis.func3Real(pFunc);}
+
+ static void func4(QpFormula& pThis, const char* pFunc)
+ {pThis.func4Real(pFunc);}
+
+ static void funcV(QpFormula& pThis, const char* pFunc)
+ {pThis.funcVReal(pFunc);}
+
+ static void intFunc(QpFormula& pThis, const char* pFunc)
+ {pThis.intFuncReal(pFunc);}
+
+ void dropLeadingAt(int pBool=-1);
+
+ static void ref(QpFormula& pThis, const char* pFunc)
+ {pThis.refReal(pFunc);}
+
+ void replaceFunc(QpFormulaConv* pFuncEntry);
+
+ static void stringFunc(QpFormula& pThis, const char* pFunc)
+ {pThis.stringFuncReal(pFunc);}
+
+ static void unaryOperand(QpFormula& pThis, const char* pOper)
+ {pThis.unaryOperandReal(pOper);}
+
+protected:
+ char* cArgSeparator;
+ QpRecFormulaCell& cCell;
+ QpIStream cFormula;
+ QpIStream cFormulaRefs;
+ QpFormulaConv* cReplaceFunc;
+ char* cFormulaStart;
+ int cIdx;
+ QpFormulaStack cStack;
+ int cDropLeadingAt;
+ QpTableNames& cTable;
+
+ void absKludgeReal(const char* pOper);
+ void binaryOperandReal(const char* pOper);
+ void floatFuncReal(const char* pFunc);
+ void func0Real(const char* pFunc);
+ void func1Real(const char* pFunc);
+ void func2Real(const char* pFunc);
+ void func3Real(const char* pFunc);
+ void func4Real(const char* pFunc);
+ void funcVReal(const char* pFunc);
+ void intFuncReal(const char* pFunc);
+ void refReal(const char* pFunc);
+ void stringFuncReal(const char* pFunc);
+ void unaryOperandReal(const char* pOper);
+};
+
+#endif // QPRO_FORMULA_H
diff --git a/filters/kspread/qpro/libqpro/qpro/record.h b/filters/kspread/qpro/libqpro/qpro/record.h
new file mode 100644
index 000000000..a7aeb5058
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/qpro/record.h
@@ -0,0 +1,280 @@
+#ifndef QPRO_RECORD_H
+#define QPRO_RECORD_H
+
+#include <qpro/tablenames.h>
+#include <qpro/stream.h>
+
+enum QpRecType
+{
+ QpBof = 0,
+ QpEof = 1,
+ QpRecalcMode = 2,
+ QpRecalcOrder = 3,
+ QpEmptyCell = 12,
+ QpIntegerCell = 13,
+ QpFloatingPointCell = 14,
+ QpLabelCell = 15,
+ QpFormulaCell = 16,
+ QpPassword = 75,
+ QpBop = 202,
+ QpPageName = 204,
+ QpUnknown = -1
+};
+
+// -----------------------------------------------------------------------
+
+class QpRec
+{
+public:
+ QpRec(QpRecType pType);
+ ~QpRec();
+
+ QP_INT16 type();
+
+protected:
+ QP_INT16 cType;
+};
+
+// -----------------------------------------------------------------------
+
+//class QP_CELL_REF
+//{
+//public:
+// QP_CELL_REF(QpIStream& pIn);
+// ~QP_CELL_REF();
+//
+// QP_UINT8 Column();
+// QP_INT16 Row();
+//
+//protected:
+// QP_UINT8 cColumn;
+// QP_INT16 cNoteBook;
+// QP_INT8 cPage;
+// QP_INT16 cRow;
+//};
+
+// -----------------------------------------------------------------------
+
+class QpRecCell : public QpRec
+{
+public:
+ QpRecCell(QpRecType pType);
+ ~QpRecCell();
+
+ void attributes(QP_INT16 pAttributes);
+ QP_INT16 attributes();
+
+// const char* cellRef();
+ void cellRef(char* pText, QpTableNames& pTable, QP_INT16 pNoteBook, QP_UINT8 pPage, QP_UINT8 pColumn, QP_INT16 pRow);
+ void cellRef(char* pText, QpTableNames& pTable, QpIStream& pFormulaRef);
+
+ void column(QP_UINT8 pColumn);
+ QP_UINT8 column();
+
+ void row(QP_INT16 pRow);
+ QP_INT16 row();
+
+protected:
+ int loadCellInfo(QpIStream& pIn);
+
+ QP_INT16 cAttributes;
+ QP_UINT8 cColumn;
+ QP_UINT8 cPage;
+ QP_INT16 cRow;
+ char* cCellRef;
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecBof : public QpRec
+{
+public:
+ QpRecBof(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecBof();
+
+ void fileFormat(QP_INT16 pFileFormat);
+ QP_INT16 fileFormat();
+
+protected:
+ QP_INT16 cFileFormat;
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecEof : public QpRec
+{
+public:
+ QpRecEof(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecEof();
+};
+
+
+// -----------------------------------------------------------------------
+
+class QpRecRecalcMode : public QpRec
+{
+public:
+ enum MODE{Manual=0, Background=1, Automatic=255};
+
+ QpRecRecalcMode(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecRecalcMode();
+
+ void mode(MODE pMode);
+ MODE mode();
+
+protected:
+ MODE cMode;
+};
+
+
+// -----------------------------------------------------------------------
+
+class QpRecRecalcOrder : public QpRec
+{
+public:
+ enum ORDER { Natural=0, Column=1, Row=255 };
+
+ QpRecRecalcOrder(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecRecalcOrder();
+
+ void order(ORDER pOrder);
+ ORDER order();
+
+protected:
+ ORDER cOrder;
+};
+
+
+// -----------------------------------------------------------------------
+
+// QpRecDimension
+// -----------------------------------------------------------------------
+
+// QpRecName
+
+// -----------------------------------------------------------------------
+
+class QpRecEmptyCell : public QpRecCell
+{
+public:
+ QpRecEmptyCell(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecEmptyCell();
+};
+
+
+// -----------------------------------------------------------------------
+
+class QpRecIntegerCell : public QpRecCell
+{
+public:
+ QpRecIntegerCell(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecIntegerCell();
+
+
+ QP_INT16 integer();
+protected:
+ QP_INT16 cInt;
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecFloatingPointCell : public QpRecCell
+{
+public:
+ QpRecFloatingPointCell(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecFloatingPointCell();
+
+ QP_INT64 value();
+protected:
+ QP_INT64 cValue;
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecFormulaCell : public QpRecCell
+{
+public:
+ QpRecFormulaCell(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecFormulaCell();
+
+ const char* formula();
+ QP_INT16 formulaReferences();
+ QP_INT16 formulaLen();
+
+protected:
+ QP_INT16 cCellRef;
+ char* cFormula;
+ QP_INT64 cLastValue;
+ QP_INT16 cLen;
+ QP_INT16 cState;
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecLabelCell : public QpRecCell
+{
+public:
+ QpRecLabelCell(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecLabelCell();
+
+ char labelPrefix();
+ const char* label();
+
+protected:
+ char cLabelPrefix;
+ char* cLabel;
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecUnknown : public QpRec
+{
+public:
+ QpRecUnknown(QP_INT16 pType, QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecUnknown();
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecBop : public QpRec
+{
+public:
+ QpRecBop(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecBop();
+
+ QP_UINT8 pageIndex();
+
+protected:
+ QP_UINT8 cPageIndex;
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecPageName : public QpRec
+{
+public:
+ QpRecPageName(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecPageName();
+
+ const char* pageName();
+
+protected:
+ char* cPageName;
+};
+
+// -----------------------------------------------------------------------
+
+class QpRecPassword : public QpRec
+{
+public:
+ QpRecPassword(QP_INT16 pLen, QpIStream& pIn);
+ ~QpRecPassword();
+
+ const QP_UINT8* password();
+
+protected:
+ QP_UINT8* cPassword;
+};
+
+#endif // QPRO_RECORD_H
+
diff --git a/filters/kspread/qpro/libqpro/qpro/record_factory.h b/filters/kspread/qpro/libqpro/qpro/record_factory.h
new file mode 100644
index 000000000..b6f9cc233
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/qpro/record_factory.h
@@ -0,0 +1,19 @@
+#ifndef QPRO_RECORD_FACTORY_H
+#define QPRO_RECORD_FACTORY_H
+
+#include <qpro/stream.h>
+#include <qpro/record.h>
+
+class QpRecFactory
+{
+public:
+ QpRecFactory(QpIStream& pIn);
+ ~QpRecFactory();
+
+ QpRec* nextRecord();
+protected:
+ QpIStream& cIn;
+};
+
+#endif // QPRO_RECORD_FACTORY_H
+
diff --git a/filters/kspread/qpro/libqpro/qpro/stream.h b/filters/kspread/qpro/libqpro/qpro/stream.h
new file mode 100644
index 000000000..a112bdb6d
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/qpro/stream.h
@@ -0,0 +1,72 @@
+#ifndef QPRO_STREAM_H
+#define QPRO_STREAM_H
+
+//#define USE_QT
+
+#ifdef USE_QT
+
+#include <qdatastream.h>
+#include <qbuffer.h>
+
+typedef Q_UINT8 QP_UINT8;
+typedef Q_INT8 QP_INT8;
+typedef Q_INT16 QP_INT16;
+typedef Q_INT32 QP_INT32;
+
+class QpStream : public QDataStream
+{
+public:
+ QpStream(unsigned char* pBuffer, unsigned int pLen);
+ ~QpStream();
+
+protected:
+ QBuffer cBuf;
+ QByteArray cByteArray;
+
+ unsigned char* cBuffer;
+ unsigned int cLen;
+};
+
+#else
+
+#include <iostream>
+using namespace std;
+
+// ??? sort out how to do sizes
+
+typedef char QP_INT8 ;
+typedef unsigned char QP_UINT8 ;
+typedef short QP_INT16 ;
+typedef int QP_INT32 ;
+typedef double QP_INT64 ;
+
+class QpIStream
+{
+public:
+ QpIStream(const char* pFileName);
+ QpIStream(unsigned char* pBuffer, unsigned int pLen);
+ ~QpIStream();
+
+ int get();
+
+ QpIStream& read(char* pBuf, QP_INT16 pLen);
+
+ operator void* ();
+ int operator !();
+
+ QpIStream& operator >> (QP_INT8 &pI8);
+ QpIStream& operator >> (QP_UINT8 &pI8);
+ QpIStream& operator >> (QP_INT16 &pI16);
+ QpIStream& operator >> (QP_INT32 &pI32);
+ QpIStream& operator >> (QP_INT64 &pI64);
+ QpIStream& operator >> (char*& pStr);
+
+protected:
+ istream* cIn;
+ long cOffset;
+ streambuf* cStreamBuf;
+};
+
+#endif
+
+#endif // QPRO_STREAM_H
diff --git a/filters/kspread/qpro/libqpro/qpro/tablenames.h b/filters/kspread/qpro/libqpro/qpro/tablenames.h
new file mode 100644
index 000000000..286cbb641
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/qpro/tablenames.h
@@ -0,0 +1,23 @@
+#ifndef QPRO_TABLENAMES_H
+#define QPRO_TABLENAMES_H
+
+// -----------------------------------------------------------------------
+
+class QpTableNames
+{
+public:
+ enum {cNameCnt=256};
+
+ QpTableNames();
+ ~QpTableNames();
+
+ void name(unsigned pIdx, const char* pName);
+ const char* name(unsigned pIdx);
+
+ int allocated(unsigned pIdx);
+protected:
+ char* cName[cNameCnt];
+};
+
+#endif // QPRO_TABLENAMES_H
+
diff --git a/filters/kspread/qpro/libqpro/src/Makefile.am b/filters/kspread/qpro/libqpro/src/Makefile.am
new file mode 100644
index 000000000..9eac256cd
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/src/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES= -I$(srcdir) -I$(srcdir)/.. $(all_includes)
+
+noinst_LTLIBRARIES = libqpro.la
+libqpro_la_SOURCES = formula.cc record.cc record_factory.cc stream.cc tablenames.cc
+
diff --git a/filters/kspread/qpro/libqpro/src/formula.cc b/filters/kspread/qpro/libqpro/src/formula.cc
new file mode 100644
index 000000000..14630a502
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/src/formula.cc
@@ -0,0 +1,550 @@
+#include <qpro/common.h>
+
+#include <iostream>
+#include <strstream>
+
+#include <string.h>
+
+#include <qpro/formula.h>
+#include <qpro/stream.h>
+
+// ------------------------------------------------------------------
+
+
+QpFormulaStack::QpFormulaStack()
+ : cIdx(-1)
+ , cMax(3)
+{
+ cStack = new char*[cMax];
+}
+
+QpFormulaStack::~QpFormulaStack()
+{
+}
+
+void
+QpFormulaStack::bracket(const char* pBefore, const char* pAfter)
+{
+ if( cIdx >= 0 )
+ {
+ int lLen = strlen(cStack[cIdx]) + 1;
+
+ if( pBefore ) lLen += strlen(pBefore);
+
+ if( pAfter ) lLen += strlen(pAfter);
+
+ char* lNew = new char[ lLen ];
+
+ lNew[0] = '\0';
+
+ if( pBefore ) strcpy( lNew, pBefore );
+
+ strcat( lNew, cStack[cIdx] );
+
+ if( pAfter ) strcat( lNew, pAfter );
+
+ delete [] cStack[cIdx];
+ cStack[cIdx] = lNew;
+ }
+}
+
+void
+QpFormulaStack::join(int pCnt, const char* pSeparator)
+{
+ int lFirstIdx = 1 - pCnt; // really 0 - pCnt +1
+
+ if( pCnt > 0 && (cIdx-lFirstIdx) >=0 )
+ {
+ int lSepLen = strlen(pSeparator);
+ int lLen = lSepLen * (pCnt-1) +1; // +1 for null terminator
+
+ for(int lIdx=lFirstIdx; lIdx <= 0; ++lIdx)
+ {
+ lLen += strlen( cStack[cIdx + lIdx] );
+ }
+
+ char* lNew = new char[lLen];
+
+ lNew[0] = '\0';
+
+ for(int lIdx=lFirstIdx; lIdx <= 0; ++lIdx)
+ {
+ strcat( lNew, cStack[cIdx + lIdx] );
+ if( lIdx != 0 )
+ {
+ strcat( lNew, pSeparator );
+ }
+ }
+
+ pop(pCnt);
+
+ push(lNew);
+
+ delete [] lNew;
+ }
+}
+
+void
+QpFormulaStack::pop(int pCnt)
+{
+ while( cIdx >= 0 && pCnt-- )
+ {
+ delete [] cStack[cIdx--];
+ }
+}
+
+void
+QpFormulaStack::push(const char* pString)
+{
+ ++cIdx;
+
+ if(cIdx == cMax)
+ {
+ cMax += 10;
+
+ char** cTemp = new char*[cMax];
+
+ for(int lIdx=0; lIdx<cIdx; ++lIdx)
+ {
+ cTemp[lIdx] = cStack[lIdx];
+ }
+
+ delete [] cStack;
+ cStack = cTemp;
+ }
+
+ cStack[cIdx] = strcpy(new char[strlen(pString)+1], pString);
+}
+
+const char*
+QpFormulaStack::top()
+{
+ return (cIdx >=0 ? cStack[cIdx] : 0);
+}
+
+const char*
+QpFormulaStack::operator [] (int pIdx)
+{
+ char* lResult = 0;
+
+ if( pIdx <= 0 && (cIdx + pIdx) >= 0 )
+ {
+ lResult = cStack[cIdx + pIdx];
+ }
+
+ return lResult;
+}
+
+// ------------------------------------------------------------------
+
+static const QpFormulaConv gConv[] =
+{
+ {0, QpFormula::floatFunc, 0},
+ {1, QpFormula::ref, 0},
+ {2, QpFormula::ref, 0},
+ {4, QpFormula::func1, "("},
+ {5, QpFormula::intFunc, 0},
+ {6, QpFormula::stringFunc, 0},
+// {7, default ??? don't know what this is ???
+ {8, QpFormula::unaryOperand, "-"},
+ {9, QpFormula::binaryOperand, "+"},
+ {10, QpFormula::binaryOperand, "-"},
+ {11, QpFormula::binaryOperand, "*"},
+ {12, QpFormula::binaryOperand, "/"},
+ {13, QpFormula::binaryOperand, "^"},
+ {14, QpFormula::binaryOperand, "="},
+ {15, QpFormula::binaryOperand, "<>"},
+ {16, QpFormula::binaryOperand, "<="},
+ {17, QpFormula::binaryOperand, ">="},
+ {18, QpFormula::binaryOperand, "<"},
+ {19, QpFormula::binaryOperand, ">"},
+ {20, QpFormula::binaryOperand, "#AND#"},
+ {21, QpFormula::binaryOperand, "#OR#"},
+ {22, QpFormula::unaryOperand, "#NOT#"},
+ {23, QpFormula::unaryOperand, "+"},
+ {24, QpFormula::binaryOperand, "&"},
+// {25, Halt ??? don't know what this is ???
+// {26, dll ??? don't know what this is ???
+// {27, extended no operands ??? don't know what this is ???
+// {28, extended operands ??? don't know what this is ???
+// {29, Reserved
+// {30, Reserved
+// {31, NA
+ {32, QpFormula::func0, "@err"},
+ {33, QpFormula::func1, "@abs("},
+ {34, QpFormula::func1, "@int("},
+ {35, QpFormula::func1, "@sqrt("},
+ {36, QpFormula::func1, "@log("},
+ {37, QpFormula::func1, "@ln("},
+ {38, QpFormula::func0, "@pi"},
+ {39, QpFormula::func1, "@sin("},
+ {40, QpFormula::func1, "@cos("},
+ {41, QpFormula::func1, "@tan("},
+ {42, QpFormula::func2, "@atan2("},
+ {43, QpFormula::func1, "@atan("},
+ {44, QpFormula::func1, "@asin("},
+ {45, QpFormula::func1, "@acos("},
+ {46, QpFormula::func1, "@exp("},
+ {47, QpFormula::func2, "@mod("},
+ {48, QpFormula::funcV, "@choose("},
+ {49, QpFormula::func1, "@isna("},
+ {50, QpFormula::func1, "@iserr("},
+ {51, QpFormula::func0, "@false"},
+ {52, QpFormula::func0, "@true"},
+ {53, QpFormula::func0, "@rand"},
+ {54, QpFormula::func3, "@date("},
+ {55, QpFormula::func0, "@now"},
+ {56, QpFormula::func3, "@pmt("},
+ {57, QpFormula::func3, "@pv("},
+ {58, QpFormula::func3, "@fv("},
+ {59, QpFormula::func3, "@if("},
+ {60, QpFormula::func1, "@day("},
+ {61, QpFormula::func1, "@month("},
+ {62, QpFormula::func1, "@year("},
+ {63, QpFormula::func2, "@round("},
+ {64, QpFormula::func3, "@time("},
+ {65, QpFormula::func1, "@hour("},
+ {66, QpFormula::func1, "@minute("},
+ {67, QpFormula::func1, "@second("},
+ {68, QpFormula::func1, "@isnumber("},
+ {69, QpFormula::func1, "@isstring("},
+ {70, QpFormula::func1, "@length("},
+ {71, QpFormula::func1, "@value("},
+ {72, QpFormula::func2, "@string("},
+ {73, QpFormula::func3, "@mid("},
+ {74, QpFormula::func1, "@char("},
+ {75, QpFormula::func1, "@code("},
+ {76, QpFormula::func3, "@find("},
+ {77, QpFormula::func1, "@dateVal("},
+ {78, QpFormula::func1, "@timeVal("},
+ {79, QpFormula::func1, "@cellPtr("},
+ {80, QpFormula::funcV, "@sum("},
+ {81, QpFormula::funcV, "@avg("},
+ {82, QpFormula::funcV, "@count("},
+ {83, QpFormula::funcV, "@min("},
+ {84, QpFormula::funcV, "@max("},
+ {85, QpFormula::func3, "@vlookup("}, // would have expected func4 ???
+ {86, QpFormula::func2, "@npv("},
+ {87, QpFormula::funcV, "@var("},
+ {88, QpFormula::funcV, "@std("},
+ {89, QpFormula::func2, "@irr("},
+ {90, QpFormula::func3, "@hlookup("}, // would have expected func4 ???
+ {91, QpFormula::func3, "@dsum("},
+ {92, QpFormula::func3, "@davg("},
+ {93, QpFormula::func3, "@dcount("},
+ {94, QpFormula::func3, "@dmin("},
+ {95, QpFormula::func3, "@dmax("},
+ {96, QpFormula::func3, "@dvar("},
+ {97, QpFormula::func3, "@dstd("},
+ {98, QpFormula::func3, "@index("},
+ {99, QpFormula::func1, "@cols("},
+ {100, QpFormula::func1, "@rows("},
+ {101, QpFormula::func2, "@repeat("},
+ {102, QpFormula::func1, "@upper("},
+ {103, QpFormula::func1, "@lower("},
+ {104, QpFormula::func2, "@left("},
+ {105, QpFormula::func2, "@right("},
+ {106, QpFormula::func4, "@replace("},
+ {107, QpFormula::func1, "@proper("},
+ {108, QpFormula::func2, "@cell("},
+ {109, QpFormula::func1, "@trim("},
+ {110, QpFormula::func1, "@clean("},
+ {111, QpFormula::func1, "@s("},
+ {112, QpFormula::func1, "@n("},
+ {113, QpFormula::func1, "@exact("},
+// {114, QpFormula::func1, "@call("},
+ {115, QpFormula::func1, "@@("},
+ {116, QpFormula::func3, "@rate("},
+ {117, QpFormula::func3, "@term("},
+ {118, QpFormula::func3, "@cterm("},
+ {119, QpFormula::func3, "@sln("},
+ {120, QpFormula::func4, "@syd("},
+ {121, QpFormula::func4, "@ddb("},
+ {122, QpFormula::funcV, "@stds("},
+ {123, QpFormula::funcV, "@vars("},
+ {124, QpFormula::func1, "@dstds("},
+ {125, QpFormula::func1, "@dvars("},
+ {126, QpFormula::func1, "@pval("},
+ {127, QpFormula::func1, "@paymt("},
+ {128, QpFormula::func1, "@fval("},
+ {129, QpFormula::func1, "@nper("},
+ {130, QpFormula::func1, "@irate("},
+ {131, QpFormula::func1, "@ipaymt("},
+ {132, QpFormula::func1, "@ppaymt("},
+ {133, QpFormula::func1, "@sumproduct("},
+ {134, QpFormula::func1, "@memavail("},
+ {135, QpFormula::func1, "@mememsavail("},
+ {136, QpFormula::func1, "@fileexists("},
+ {137, QpFormula::func1, "@curval("},
+ {138, QpFormula::func1, "@degrees("},
+ {139, QpFormula::func1, "@radians("},
+ {140, QpFormula::func1, "@hextonum("},
+ {141, QpFormula::func1, "@numtohex("},
+ {142, QpFormula::func1, "@today("},
+ {143, QpFormula::func3, "@npv("},
+ {144, QpFormula::func1, "@cellindex2d("},
+ {145, QpFormula::func1, "@version("},
+ {154, QpFormula::func1, "@sheets("},
+ {157, QpFormula::func1, "@index3d("},
+ {158, QpFormula::func1, "@cellindex3d("},
+ {159, QpFormula::func1, "@property("},
+ {160, QpFormula::func1, "@ddelink("},
+ {161, QpFormula::func1, "@command("},
+ {0, 0, 0}
+};
+
+QpFormula::QpFormula(QpRecFormulaCell& pCell, QpTableNames& pTable)
+ : cArgSeparator(strcpy(new char[2],","))
+ , cCell(pCell)
+ , cFormula( (unsigned char*)pCell.formula(), (unsigned int)pCell.formulaLen() )
+ , cFormulaRefs( (unsigned char*)&pCell.formula()[pCell.formulaReferences()]
+ , (unsigned)(pCell.formulaLen()-pCell.formulaReferences())
+ )
+ , cReplaceFunc(0)
+ , cFormulaStart(strcpy(new char[2],"+"))
+ , cIdx(0)
+ , cDropLeadingAt(0)
+ , cTable(pTable)
+{
+}
+
+QpFormula::~QpFormula()
+{
+ delete [] cArgSeparator;
+ cArgSeparator = 0;
+
+ delete [] cFormulaStart;
+ cFormulaStart = 0;
+
+ cReplaceFunc = 0;
+}
+
+void
+QpFormula::argSeparator(const char* pArg)
+{
+ delete [] cArgSeparator;
+ cArgSeparator = strcpy(new char[strlen(pArg)+1], pArg);
+}
+
+char*
+QpFormula::formula()
+{
+ QP_INT8 lOperand;
+
+ cStack.push(cFormulaStart);
+
+ while( cFormula >> lOperand, cFormula && lOperand != 3 )
+ {
+ int lFound = 0;
+ int lIdx;
+
+ if(cReplaceFunc != 0)
+ {
+ // search through override list for this function/operand
+ for( lIdx=0
+ ; !lFound && cReplaceFunc[lIdx].cFunc != 0
+ ; ++lIdx
+ )
+ {
+ if( cReplaceFunc[lIdx].cOperand == lOperand )
+ {
+ lFound = -1;
+ QP_DEBUG("Processing " << (int)lOperand << endl);
+ (*cReplaceFunc[lIdx].cFunc)(*this, cReplaceFunc[lIdx].cArg);
+ }
+ }
+ }
+
+ // if no override then find the default
+ for( lIdx=0
+ ; !lFound && gConv[lIdx].cFunc != 0
+ ; ++lIdx
+ )
+ {
+ if( gConv[lIdx].cOperand == lOperand )
+ {
+ lFound = -1;
+ QP_DEBUG("Processing " << (int)lOperand << endl);
+ (*gConv[lIdx].cFunc)(*this, gConv[lIdx].cArg);
+ }
+ }
+
+ QP_DEBUG("Top = " << cStack.top() << endl);
+ }
+
+ cStack.join(2, "");
+
+ QP_DEBUG("Formula = " << cStack.top() << endl);
+ return strcpy(new char[strlen(cStack.top())+1], cStack.top());
+}
+
+void
+QpFormula::formulaStart(const char* pFirstChar)
+{
+ delete [] cFormulaStart;
+ cFormulaStart = strcpy(new char[strlen(pFirstChar)+1], pFirstChar);
+}
+
+void
+QpFormula::binaryOperandReal(const char* pOper)
+{
+ cStack.join( 2, pOper );
+}
+
+void
+QpFormula::absKludgeReal(const char*/*pOper*/)
+{
+ // kspread doesn't (yet) have the abs function so do it ourselves
+ // using 'if( (arg) < 0, -(arg), arg )'
+
+ cStack.bracket();
+
+ char* lArg = strcpy(new char[strlen(cStack.top())+1], cStack.top());
+
+ cStack.bracket("", "<0");
+
+ cStack.push(lArg);
+ cStack.bracket("-", "");
+
+ cStack.push(lArg);
+
+ cStack.join(3, cArgSeparator);
+
+ cStack.bracket("if(");
+
+ delete [] lArg;
+}
+
+void
+QpFormula::func0Real(const char* pFunc)
+{
+ const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
+
+ cStack.push( lFunc );
+}
+
+void
+QpFormula::func1Real(const char* pFunc)
+{
+ const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
+
+ cStack.bracket( lFunc );
+}
+
+void
+QpFormula::func2Real(const char* pFunc)
+{
+ const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
+
+ cStack.join( 2, cArgSeparator );
+ cStack.bracket( lFunc );
+}
+
+void
+QpFormula::func3Real(const char* pFunc)
+{
+ const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
+
+ cStack.join( 3, cArgSeparator );
+ cStack.bracket( lFunc );
+}
+
+void
+QpFormula::func4Real(const char* pFunc)
+{
+ const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
+
+ cStack.join( 4, cArgSeparator );
+ cStack.bracket( lFunc );
+}
+
+void
+QpFormula::funcVReal(const char* pFunc)
+{
+ QP_INT8 lCnt;
+ const char* lFunc = (cDropLeadingAt && pFunc[0] == '@' ? &pFunc[1] : pFunc);
+
+ cFormula >> lCnt;
+
+ cStack.join( lCnt, cArgSeparator );
+ cStack.bracket( lFunc );
+}
+
+void
+QpFormula::floatFuncReal(const char*)
+{
+ QP_INT64 lFloat;
+ std::ostrstream lNum;
+
+ cFormula >> lFloat;
+
+ lNum << lFloat << ends;
+
+ cStack.push( lNum.str() );
+
+ lNum.rdbuf()->freeze(0);
+}
+
+void
+QpFormula::intFuncReal(const char*)
+{
+ QP_INT16 lInt;
+ std::ostrstream lNum;
+
+ cFormula >> lInt;
+
+ lNum << lInt << ends;
+
+ cStack.push( lNum.str() );
+
+ lNum.rdbuf()->freeze(0);
+}
+
+void
+QpFormula::dropLeadingAt(int pBool)
+{
+ cDropLeadingAt = pBool;
+}
+
+void
+QpFormula::refReal(const char*)
+{
+ char lRef[100]; // ??? hard coded length
+
+ cCell.cellRef( lRef, cTable, cFormulaRefs );
+
+ cStack.push( lRef );
+}
+
+void
+QpFormula::replaceFunc(QpFormulaConv* pFuncEntry)
+{
+ cReplaceFunc = pFuncEntry;
+}
+
+void
+QpFormula::stringFuncReal(const char*)
+{
+ char* lString = 0;
+
+ cFormula >> lString;
+
+ char* lQuoteString = new char[strlen(lString)+3];
+
+ lQuoteString[0] = '"';
+ strcpy(&lQuoteString[1], lString);
+ strcat(lQuoteString, "\"");
+
+ cStack.push( lQuoteString );
+
+ delete [] lString;
+ delete [] lQuoteString;
+}
+
+void
+QpFormula::unaryOperandReal(const char* pOper)
+{
+ cStack.bracket( pOper, "" );
+}
+
+
diff --git a/filters/kspread/qpro/libqpro/src/record.cc b/filters/kspread/qpro/libqpro/src/record.cc
new file mode 100644
index 000000000..5d26df7bc
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/src/record.cc
@@ -0,0 +1,665 @@
+#include <qpro/common.h>
+
+#include <string.h>
+
+#include <iostream>
+
+#include <qpro/record.h>
+#include <qpro/formula.h>
+
+// -----------------------------------------------------------------------
+
+#include <iomanip>
+#include <strstream>
+
+void
+Charout(ostream& pOut, unsigned char pChar)
+{
+ pOut << ( (pChar<32) || (pChar>126) ? '.' : (char)pChar);
+}
+
+void
+Hexout(ostream& pOut, unsigned char pChar)
+{
+ pOut << setiosflags(ios::uppercase)
+ << setfill('0')
+ << setw(2)
+ << hex
+ << (int)pChar
+ << dec;
+}
+
+int
+Hexout(char* pChar, int pLen)
+{
+ std::ostrstream* lOStr = new std::ostrstream;
+
+ while( pLen )
+ {
+ int lIdx = 0;
+
+ for( lIdx=0; lIdx < 16; ++lIdx )
+ {
+ if( pLen )
+ {
+ Hexout(cerr, *pChar);
+ cerr << (lIdx==8 ? "-" : " ");
+ Charout(*lOStr, (unsigned char)*pChar);
+ ++pChar;
+ --pLen;
+ }
+ else
+ {
+ cerr << " ";
+ }
+ }
+
+ cerr << lOStr->rdbuf() << endl;
+
+ delete lOStr;
+ lOStr = new std::ostrstream;
+ }
+
+ delete lOStr;
+ lOStr = 0;
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+QpRec::QpRec(QpRecType pType)
+ : cType( pType )
+{
+}
+
+QpRec::~QpRec()
+{
+}
+
+QP_INT16
+QpRec::type()
+{
+ return cType;
+}
+
+// -----------------------------------------------------------------------
+//
+//
+//QpCellRef::QpCellRef(QpIStream& pIn)
+//{
+// pIn >> cNoteBook >> cColumn >> cPage >> cRow;
+//
+//QP_DEBUG("CellRef: NoteBook" << cNoteBook << ", col "
+// << cColumn << ", Page " << (int)cPage << ", Row "
+// << cRow << endl
+// );
+//}
+//
+//QpCellRef::~QpCellRef()
+//{
+//}
+//
+//QP_UINT8
+//QpCellRef::column()
+//{
+// return cColumn;
+//}
+//
+//QP_INT16
+//QpCellRef::row()
+//{
+// return cRow;
+//}
+//
+// -----------------------------------------------------------------------
+
+QpRecCell::QpRecCell(QpRecType pType)
+ : QpRec(pType)
+ , cAttributes(0)
+ , cColumn(0)
+ , cPage(0)
+ , cRow(0)
+ , cCellRef(0)
+{
+}
+
+QpRecCell::~QpRecCell()
+{
+ delete [] cCellRef;
+ cCellRef = 0;
+}
+
+
+void
+QpRecCell::attributes(QP_INT16 pAttributes)
+{
+ cAttributes = pAttributes;
+}
+
+QP_INT16
+QpRecCell::attributes()
+{
+ return cAttributes;
+}
+
+void
+QpRecCell::column(QP_UINT8 pColumn)
+{
+ cColumn = pColumn;
+}
+
+QP_UINT8
+QpRecCell::column()
+{
+ return cColumn;
+}
+
+void
+QpRecCell::row(QP_INT16 pRow)
+{
+ cRow = pRow;
+}
+
+QP_INT16
+QpRecCell::row()
+{
+ return cRow;
+}
+
+int
+QpRecCell::loadCellInfo(QpIStream& pIn)
+{
+ pIn >> cColumn >> cPage >> cRow >> cAttributes;
+
+ QP_DEBUG(" col " << (unsigned)cColumn << ", Page " << (unsigned)cPage
+ << ", Row " << cRow << ", Ref "
+ << /*???cellRef()
+ <<*/ ", Attr " << cAttributes
+ );
+
+ return 6; // number of bytes consumed
+}
+
+//const char*
+//QpRecCell::cellRef()
+//{
+// if( cCellRef == 0 )
+// {
+// cCellRef = new char[20]; // hardcoded len???
+//
+/// ??? what value should notebook param be?
+// cellRef( cCellRef, 0, 0, cColumn, cRow ); //hardcoded page no. ?????
+// }
+//
+// return cCellRef;
+//
+
+void
+QpRecCell::cellRef(char* pText, QpTableNames& pTable, QP_INT16 /*pNoteBook*/, QP_UINT8 pPage, QP_UINT8 pColumn, QP_INT16 pRow)
+{
+//??? cope with relative/absolute references
+
+ std::strstream lOut(pText, 20, ios::out); // ??? ard coded len
+ int lPageRelative = pRow & 0x8000;
+ int lColRelative = pRow & 0x4000;
+ int lRowRelative = pRow & 0x2000;
+ QP_UINT8 lCol = (lColRelative ? cColumn + pColumn : pColumn);
+
+ // Sign bit for row is in bit 0x1000, so either set all top bits or lose all top bits
+ QP_INT16 lRow = (lRowRelative ? cRow + (pRow & 0x1000 ? pRow | 0xE000 : pRow & 0x1FFF)
+ : pRow & 0x1FFF
+ );
+
+ // Are we referencing a different page ?
+
+ if( lPageRelative && (pPage == 0) )
+ {
+ // no - page is zero relative to this one
+ }
+ else
+ if( pPage != cPage )
+ {
+ // yes - not relative & page is a different one
+
+ QP_UINT8 lPage = ( lPageRelative ? pPage + cPage : pPage );
+
+ QP_DEBUG("pTable.name((unsigned)lPage) = " << pTable.name((unsigned)lPage) << endl);
+
+ lOut << pTable.name((unsigned)lPage) << '!'; // is '!' compat with QPRO???
+ }
+
+ if( !lColRelative )
+ {
+ lOut << '$';
+ }
+ if( lCol < 26 )
+ {
+ lOut << (char)('A' + lCol);
+ }
+ else
+ {
+ lOut << (char)('A' -1 + lCol / 26)
+ << (char)('A' + lCol % 26);
+ }
+
+ if( !lRowRelative )
+ {
+ lOut << '$';
+ }
+
+ lOut << (lRow & 0x1FFF) +1 << ends;
+}
+
+void
+QpRecCell::cellRef(char* pText, QpTableNames& pTable, QpIStream& pFormulaRef)
+{
+ QP_INT16 lNoteBook;
+ pFormulaRef >> lNoteBook;
+
+ // block references (eg. A1..A9) have bit 0x1000 set
+
+ if( lNoteBook & 0x1000 )
+ {
+ QP_UINT8 lFirstColumn;
+ QP_UINT8 lFirstPage;
+ QP_INT16 lFirstRow;
+ QP_UINT8 lLastColumn;
+ QP_UINT8 lLastPage;
+ QP_INT16 lLastRow;
+
+ pFormulaRef >> lFirstColumn
+ >> lFirstPage
+ >> lFirstRow
+ >> lLastColumn
+ >> lLastPage
+ >> lLastRow;
+
+ QP_DEBUG("BlockRef: NoteBook " << lNoteBook
+ << ", 1st col " << lFirstColumn
+ << ", 1st page " << (unsigned)lFirstPage
+ << ", 1st row " << lFirstRow
+ << ", last col " << lLastColumn
+ << ", last page " << (unsigned)lLastPage
+ << ", last row " << lLastRow
+ << endl
+ );
+// ??? next few lines shouldn't just add rows together
+ cellRef( pText, pTable, lNoteBook, lFirstPage, lFirstColumn, lFirstRow );
+// ?? temp next line strcat( pText, ".." );
+ strcat( pText, ":" );
+ cellRef( &pText[strlen(pText)], pTable, lNoteBook, lLastPage, lLastColumn, lLastRow );
+ }
+ else
+ {
+ QP_UINT8 lColumn;
+ QP_UINT8 lPage;
+ QP_INT16 lRow;
+
+ pFormulaRef >> lColumn >> lPage >> lRow;
+
+ QP_DEBUG("FormulaRef: NoteBook " << lNoteBook << ", Col " << (unsigned)lColumn
+ << ", Page " << (unsigned)lPage << ", Row " << lRow << endl
+ );
+
+// ??? sort out what to do about lNotebook
+// ??? next few lines shouldn't just add rows together
+ cellRef( pText, pTable, lNoteBook, lPage, lColumn, lRow );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+QpRecBof::QpRecBof(QP_INT16, QpIStream& pIn)
+ : QpRec( QpBof )
+{
+ pIn >> cFileFormat;
+
+ QP_DEBUG("BOF fileformat=" << cFileFormat << endl);
+}
+
+QpRecBof::~QpRecBof()
+{
+}
+
+// -----------------------------------------------------------------------
+
+QpRecEof::QpRecEof(QP_INT16, QpIStream&)
+ : QpRec( QpEof )
+{
+ QP_DEBUG("EOF" << endl);
+}
+
+QpRecEof::~QpRecEof()
+{
+}
+
+
+// -----------------------------------------------------------------------
+
+QpRecRecalcMode::QpRecRecalcMode(QP_INT16, QpIStream& pIn)
+ : QpRec( QpRecalcMode )
+{
+ QP_INT8 lMode;
+
+ pIn >> lMode;
+
+ cMode = (MODE)(unsigned char) lMode;
+
+ QP_DEBUG("Recalc Mode = "
+ << (int)lMode << ( cMode == Manual ? " (Manual)"
+ : cMode == Background ? " (Background)"
+ : cMode == Automatic ? " (Automatic)"
+ : " (Unknown)"
+ )
+ << endl
+ );
+}
+
+QpRecRecalcMode::~QpRecRecalcMode()
+{
+}
+
+
+void
+QpRecRecalcMode::mode(MODE pMode)
+{
+ cMode = pMode;
+}
+
+QpRecRecalcMode::MODE
+QpRecRecalcMode::mode()
+{
+ return cMode;
+}
+
+
+// -----------------------------------------------------------------------
+
+QpRecRecalcOrder::QpRecRecalcOrder(QP_INT16, QpIStream& pIn)
+ : QpRec( QpRecalcOrder )
+{
+ QP_INT8 lOrder;
+
+ pIn >> lOrder;
+
+ cOrder = (ORDER)(unsigned char) lOrder;
+
+ QP_DEBUG("Recalc Order = "
+ << (int)lOrder << ( cOrder == Natural ? " (Natural)"
+ : cOrder == Column ? " (Column)"
+ : cOrder == Row ? " (Row)"
+ : " (Unknown)"
+ )
+ << endl
+ );
+}
+
+QpRecRecalcOrder::~QpRecRecalcOrder()
+{
+}
+
+
+void
+QpRecRecalcOrder::order(ORDER pOrder)
+{
+ cOrder = pOrder;
+}
+
+QpRecRecalcOrder::ORDER
+QpRecRecalcOrder::order()
+{
+ return cOrder;
+}
+
+
+// -----------------------------------------------------------------------
+
+QpRecEmptyCell::QpRecEmptyCell(QP_INT16, QpIStream& pIn)
+ : QpRecCell( QpEmptyCell )
+{
+ QP_DEBUG("Empty Cell - ");
+
+ loadCellInfo(pIn);
+
+ QP_DEBUG(endl);
+}
+
+QpRecEmptyCell::~QpRecEmptyCell()
+{
+}
+
+
+// -----------------------------------------------------------------------
+
+QpRecIntegerCell::QpRecIntegerCell(QP_INT16, QpIStream& pIn)
+ : QpRecCell( QpIntegerCell )
+{
+ QP_DEBUG("Integer Cell - ");
+
+ loadCellInfo(pIn);
+
+ pIn >> cInt;
+
+ QP_DEBUG(", Int " << cInt << endl);
+}
+
+QpRecIntegerCell::~QpRecIntegerCell()
+{
+}
+
+QP_INT16
+QpRecIntegerCell::integer()
+{
+ return cInt;
+}
+
+// -----------------------------------------------------------------------
+
+QpRecFloatingPointCell::QpRecFloatingPointCell(QP_INT16, QpIStream& pIn)
+ : QpRecCell( QpFloatingPointCell )
+{
+ QP_DEBUG("Float Cell - ");
+
+ loadCellInfo(pIn);
+
+ pIn >> cValue;
+
+ QP_DEBUG(", Value " << cValue << endl);
+}
+
+QpRecFloatingPointCell::~QpRecFloatingPointCell()
+{
+}
+
+QP_INT64
+QpRecFloatingPointCell::value()
+{
+ return cValue;
+}
+
+// -----------------------------------------------------------------------
+
+QpRecLabelCell::QpRecLabelCell(QP_INT16 pLen, QpIStream& pIn)
+ : QpRecCell( QpLabelCell )
+{
+ QP_DEBUG("Label Cell - ");
+ int lLabelLen = pLen - loadCellInfo(pIn) - 1;
+
+ pIn >> cLabelPrefix;
+
+ cLabel = new char[lLabelLen];
+
+ pIn.read( cLabel, lLabelLen );
+
+ QP_DEBUG(", Prefix " << cLabelPrefix << ", Label " << cLabel << endl);
+}
+
+QpRecLabelCell::~QpRecLabelCell()
+{
+ delete [] cLabel;
+ cLabel = 0;
+}
+
+char
+QpRecLabelCell::labelPrefix()
+{
+ return cLabelPrefix;
+}
+
+const char*
+QpRecLabelCell::label()
+{
+ return cLabel;
+}
+
+// -----------------------------------------------------------------------
+
+QpRecFormulaCell::QpRecFormulaCell(QP_INT16 pLen, QpIStream& pIn)
+ : QpRecCell( QpFormulaCell )
+ , cFormula(0)
+{
+ QP_DEBUG("Formula Cell - ");
+
+ int lFormulaLen = pLen - loadCellInfo(pIn);
+
+ pIn >> cLastValue;
+ lFormulaLen -= 8;
+
+ pIn >> cState;
+ lFormulaLen -= 2;
+
+ pIn >> cLen;
+ lFormulaLen -= 2;
+
+ pIn >> cCellRef;
+ lFormulaLen -= 2;
+
+ cFormula = new char[lFormulaLen];
+
+ pIn.read( cFormula, lFormulaLen );
+
+ QP_DEBUG(", LastValue " << cLastValue << ", State " << cState << endl);
+ QP_DEBUG(" FormulaLen " << cLen << ", CellRef " << cCellRef << ", Formula" << endl);
+#ifdef QP_TRACE
+ Hexout( cFormula, lFormulaLen );
+#endif
+ QP_DEBUG(endl);
+}
+
+QpRecFormulaCell::~QpRecFormulaCell()
+{
+ delete [] cFormula;
+ cFormula = 0;
+}
+
+const char*
+QpRecFormulaCell::formula()
+{
+ return cFormula;
+}
+
+QP_INT16
+QpRecFormulaCell::formulaLen()
+{
+ return cLen;
+}
+
+QP_INT16
+QpRecFormulaCell::formulaReferences()
+{
+ return cCellRef;
+}
+
+// -----------------------------------------------------------------------
+
+QpRecUnknown::QpRecUnknown(QP_INT16 /*pType*/, QP_INT16 pLen, QpIStream& pIn)
+ : QpRec( QpUnknown )
+{
+ QP_DEBUG("Unknown Type " << pType << ", len " << pLen << endl);
+
+ if( pLen > 0 )
+ {
+ char* lBuf = new char[pLen];
+
+ pIn.read(lBuf, pLen);
+
+ delete [] lBuf;
+ lBuf = 0;
+ }
+}
+
+QpRecUnknown::~QpRecUnknown()
+{
+}
+
+// -----------------------------------------------------------------------
+
+QpRecBop::QpRecBop(QP_INT16, QpIStream& pIn)
+ : QpRec( QpBop )
+{
+ pIn >> cPageIndex;
+ QP_DEBUG("BOP: " << (unsigned)cPageIndex << endl);
+}
+
+QpRecBop::~QpRecBop()
+{
+}
+
+
+QP_UINT8
+QpRecBop::pageIndex()
+{
+ return cPageIndex;
+}
+
+
+// -----------------------------------------------------------------------
+
+QpRecPageName::QpRecPageName(QP_INT16, QpIStream& pIn)
+ : QpRec( QpPageName )
+{
+ pIn >> cPageName;
+
+ QP_DEBUG("Page Name: " << cPageName << endl);
+}
+
+QpRecPageName::~QpRecPageName()
+{
+}
+
+const char*
+QpRecPageName::pageName()
+{
+ return cPageName;
+}
+// -----------------------------------------------------------------------
+
+QpRecPassword::QpRecPassword(QP_INT16 pLen, QpIStream& pIn)
+ : QpRec( QpPassword )
+{
+ QP_DEBUG("Password len = " << pLen << endl);
+
+ cPassword = new QP_UINT8[pLen];
+
+ pIn.read( (char*)cPassword, pLen );
+
+ QP_DEBUG("Password(Hex) = ");
+#ifdef QP_TRACE
+ Hexout( (char*)cPassword, pLen );
+#endif
+ QP_DEBUG(endl);
+}
+
+QpRecPassword::~QpRecPassword()
+{
+ delete [] cPassword;
+ cPassword = 0;
+}
+
+const QP_UINT8*
+QpRecPassword::password()
+{
+ return cPassword;
+}
+
diff --git a/filters/kspread/qpro/libqpro/src/record_factory.cc b/filters/kspread/qpro/libqpro/src/record_factory.cc
new file mode 100644
index 000000000..cec01dd41
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/src/record_factory.cc
@@ -0,0 +1,83 @@
+#include <qpro/common.h>
+
+#include <iostream>
+
+#include <qpro/record_factory.h>
+
+#define NEWFUNC(x) static QpRec* NEW_##x (QP_INT16 pLen, QpIStream& pIn) { return new x (pLen, pIn); }
+
+NEWFUNC(QpRecBof)
+NEWFUNC(QpRecBop)
+NEWFUNC(QpRecEof)
+NEWFUNC(QpRecEmptyCell)
+NEWFUNC(QpRecFloatingPointCell)
+NEWFUNC(QpRecFormulaCell)
+NEWFUNC(QpRecIntegerCell)
+NEWFUNC(QpRecLabelCell)
+NEWFUNC(QpRecPageName)
+NEWFUNC(QpRecPassword)
+NEWFUNC(QpRecRecalcMode)
+NEWFUNC(QpRecRecalcOrder)
+
+struct Record
+{
+ QP_INT16 Type;
+ QP_INT16 Len;
+ QpRec* (*Func)(QP_INT16, QpIStream&);
+};
+
+
+// The functions in the Record table below (NEW_QpRecBof etc.)
+// come from the NEWFUNC #define above
+
+static Record gRecord[] =
+{
+ {QpBof, 2, NEW_QpRecBof},
+ {QpEof, 0, NEW_QpRecEof},
+ {QpRecalcMode, 1, NEW_QpRecRecalcMode},
+ {QpRecalcOrder, 1, NEW_QpRecRecalcOrder},
+ {QpEmptyCell, 6, NEW_QpRecEmptyCell},
+ {QpIntegerCell, 8, NEW_QpRecIntegerCell},
+ {QpFloatingPointCell, 14, NEW_QpRecFloatingPointCell},
+ {QpLabelCell, 0, NEW_QpRecLabelCell},
+ {QpFormulaCell, 0, NEW_QpRecFormulaCell},
+ {QpBop, 0, NEW_QpRecBop},
+ {QpPageName, 0, NEW_QpRecPageName},
+ {QpPassword, 0, NEW_QpRecPassword},
+ {0, 0, 0}
+};
+
+QpRecFactory::QpRecFactory(QpIStream& pIn)
+ : cIn(pIn)
+{
+}
+
+QpRecFactory::~QpRecFactory()
+{
+}
+
+QpRec*
+QpRecFactory::nextRecord()
+{
+ QP_INT16 lType;
+ QP_INT16 lLen;
+ QpRec* lResult=0;
+
+ cIn >> lType >> lLen;
+
+ for( Record* lRecord=gRecord; lResult == 0 ; ++lRecord )
+ {
+ if( lRecord->Func == 0 )
+ {
+ lResult = new QpRecUnknown( lType, lLen, cIn );
+ }
+ else
+ if( lRecord->Type == lType )
+ {
+ // ??? check length
+ lResult = lRecord->Func(lLen, cIn);
+ }
+ }
+
+ return lResult;
+}
diff --git a/filters/kspread/qpro/libqpro/src/stream.cc b/filters/kspread/qpro/libqpro/src/stream.cc
new file mode 100644
index 000000000..3142a272a
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/src/stream.cc
@@ -0,0 +1,226 @@
+#include <qpro/common.h>
+
+
+#include "qpro/stream.h"
+
+#ifdef __DECCXX
+#include <fstream.h> // needed for filebuf
+#endif
+#include <string.h>
+
+#ifdef USE_QT
+
+#include <qbuffer.h>
+
+QpIStream::QpIStream(unsigned char* pBuffer, unsigned int pLen)
+ : cBuffer(pBuffer), cLen(pLen)
+{
+ cByteArray.setRawData( (char*)cBuffer, (int) cLen );
+
+ cBuf.setBuffer( cByteArray );
+ cBuf.open( IO_ReadOnly );
+
+ setDevice( &cBuf );
+ setByteOrder(QDataStream::LittleEndian);
+}
+
+QpIStream::~QpIStream()
+{
+ cByteArray.resetRawData( (char*)cBuffer, (int) cLen );
+}
+
+#else
+#include <string>
+#include <fstream>
+#include <strstream>
+
+// For IRIX
+namespace std {}
+
+using namespace std;
+
+QpIStream::QpIStream(const char* pFileName)
+ : cIn(0)
+ , cOffset(0L)
+ , cStreamBuf(0)
+{
+ filebuf* lFileBuf = new filebuf;
+
+ cStreamBuf = lFileBuf;
+
+ lFileBuf->open(pFileName, ios::in);
+
+ if( lFileBuf->is_open())
+ {
+ cIn = new istream(cStreamBuf);
+ }
+}
+
+QpIStream::QpIStream(unsigned char* pBuffer, unsigned int pLen)
+ : cIn(0)
+ , cOffset(0L)
+ , cStreamBuf(0)
+{
+ cStreamBuf = new std::strstreambuf (pBuffer, pLen);
+
+ cIn = new istream(cStreamBuf);
+}
+
+QpIStream::~QpIStream()
+{
+ delete cIn;
+ cIn = 0;
+
+ delete cStreamBuf;
+ cStreamBuf = 0;
+}
+
+int
+QpIStream::get()
+{
+ int lResult;
+
+ if( (cIn==0) || cIn->rdstate())
+ {
+ lResult = EOF;
+ }
+ else
+ if((lResult=cIn->get()) == EOF)
+ {
+ // note - clear() sets bits! not clears them
+ cIn->clear(ios::eofbit|ios::failbit);
+ }
+ else
+ {
+ ++cOffset;
+ }
+
+ return lResult;
+}
+
+QpIStream&
+QpIStream::read(char* pBuf, QP_INT16 pLen)
+{
+ if( cIn )
+ {
+ cIn->read(pBuf, pLen);
+ }
+
+ return *this;
+}
+
+QpIStream::operator void* ()
+{
+ if( cIn == 0 )
+ return 0;
+ else
+ return *cIn;
+}
+
+int
+QpIStream::operator !()
+{
+ return ( cIn ? !*cIn : -1 );
+}
+
+
+QpIStream&
+QpIStream::operator >> (QP_INT8 &pI8)
+{
+ pI8 = get();
+
+ return *this;
+}
+
+QpIStream&
+QpIStream::operator >> (QP_UINT8 &pI8)
+{
+ pI8 = get();
+
+ return *this;
+}
+
+QpIStream&
+QpIStream::operator >> (QP_INT16 &pI16)
+{
+ pI16 = get();
+ pI16 = pI16 | (get() << 8);
+
+ return *this;
+}
+
+QpIStream&
+QpIStream::operator >> (QP_INT32 &pI32)
+{
+ pI32 = get();
+ pI32 = pI32 | (get() << 8);
+ pI32 = pI32 | (get() << 16);
+ pI32 = pI32 | (get() << 24);
+
+ return *this;
+}
+
+QpIStream&
+QpIStream::operator >> (QP_INT64 &pI64)
+{
+// ??? sort out this
+/******
+ pI64 = get();
+ pI64 = pI64 | (get() << 8);
+ pI64 = pI64 | (get() << 16);
+ pI64 = pI64 | (get() << 24);
+ pI64 = pI64 | (get() << 32);
+ pI64 = pI64 | (get() << 40);
+ pI64 = pI64 | (get() << 48);
+ pI64 = pI64 | (get() << 56);
+***/
+
+ union
+ {
+ char lChar[8];
+ double lDble;
+ };
+
+ lDble = 0.0; // HACK: prevent gcc internal compiler error
+ lChar[0] = get();
+ lChar[1] = get();
+ lChar[2] = get();
+ lChar[3] = get();
+ lChar[4] = get();
+ lChar[5] = get();
+ lChar[6] = get();
+ lChar[7] = get();
+
+ pI64 = lDble;
+
+ return *this;
+}
+
+QpIStream&
+QpIStream::operator >> (char*& pStr)
+{
+ int lIdx=0;
+ int lMax=10;
+
+ char* lStr = new char[lMax];
+
+ while( cIn->get(lStr[lIdx]), lStr[lIdx] != '\0' && cIn->good() )
+ {
+ if( ++lIdx == lMax )
+ {
+ lMax += 10;
+ char* lNew = new char[lMax];
+
+ memcpy(lNew, lStr, lIdx);
+ delete [] lStr;
+ lStr = lNew;
+ }
+ }
+
+ pStr = lStr;
+
+ return *this;
+}
+
+#endif // USE_QT
+
diff --git a/filters/kspread/qpro/libqpro/src/tablenames.cc b/filters/kspread/qpro/libqpro/src/tablenames.cc
new file mode 100644
index 000000000..4b9b7248c
--- /dev/null
+++ b/filters/kspread/qpro/libqpro/src/tablenames.cc
@@ -0,0 +1,72 @@
+#include <qpro/common.h>
+
+#include <string.h>
+
+#include "qpro/tablenames.h"
+
+
+// ------------------------------------------------------------------
+
+QpTableNames::QpTableNames()
+{
+ for( int lIdx=0; lIdx<cNameCnt; ++lIdx )
+ {
+ cName[lIdx] = 0;
+ }
+}
+
+QpTableNames::~QpTableNames()
+{
+ for( int lIdx=0; lIdx<cNameCnt; ++lIdx )
+ {
+ delete [] cName[lIdx];
+ cName[lIdx] = 0;
+ }
+}
+
+
+void
+QpTableNames::name(unsigned pIdx, const char* pName)
+{
+ if(pIdx < cNameCnt)
+ {
+ delete [] cName[pIdx];
+ cName[pIdx] = strcpy( new char[strlen(pName)+1], pName);
+ }
+}
+
+const char*
+QpTableNames::name(unsigned pIdx)
+{
+ char* lResult = 0;
+
+ if(pIdx < cNameCnt)
+ {
+ if( (lResult = cName[pIdx]) == 0 )
+ {
+ if( pIdx < 26 )
+ {
+ lResult = cName[pIdx] = new char[2];
+ lResult[0] = (char)('A' + pIdx);
+ lResult[1] = '\0';
+ }
+ else
+ {
+ lResult = cName[pIdx] = new char[2];
+ lResult[0] = (char)('A' -1 + pIdx / 26);
+ lResult[1] = (char)('A' + pIdx % 26);
+ lResult[2] = '\0';
+ }
+ }
+ }
+
+ return lResult;
+}
+
+
+int
+QpTableNames::allocated(unsigned pIdx)
+{
+ return (pIdx >= cNameCnt ? 0 : (cName[pIdx] != 0));
+}
+
diff --git a/filters/kspread/qpro/qproformula.cc b/filters/kspread/qpro/qproformula.cc
new file mode 100644
index 000000000..4f437cb16
--- /dev/null
+++ b/filters/kspread/qpro/qproformula.cc
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Graham Short <grahshrt@netscape.net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qproformula.h>
+
+static QpFormulaConv gOverride[] =
+{
+ {14, QpFormula::binaryOperand, "=="}, // '=' => '=='
+ {15, QpFormula::binaryOperand, "!="}, // '<>' => '!='
+ {20, QpFormula::func2, "AND("}, // (e.g.) 2 #AND# 3 => AND(2;3)
+ {21, QpFormula::func2, "OR("}, // (e.g.) 2 #OR# 3 => OR(2;3)
+ {22, QpFormula::func1, "NOT("}, // (e.g.) #NOT# 3 => NOT(3)
+ {24, QpFormula::binaryOperand, "+"}, // string concat "&" => "+"
+ {32, QpFormula::func0, "ERR()"}, // @err => ERR()
+ {33, QpFormula::absKludge, 0}, // @abs => if( (arg)<0; -(arg); (arg))
+ {34, QpFormula::func1, "INT("}, // @int => INT
+ {38, QpFormula::func0, "PI()"}, // @pi => PI()
+ {47, QpFormula::func2, "MOD("}, // @mod => MOD
+ {51, QpFormula::func0, "(1==0)"}, // @false => (1==0)
+ {52, QpFormula::func0, "(1==1)"}, // @true => (1==1)
+ {53, QpFormula::func0, "rand()"}, // @rand => rand()
+ {68, QpFormula::func1, "ISNUM("}, // @isnumber => ISNUM
+ {69, QpFormula::func1, "ISTEXT("}, // @isstring => ISTEXT
+ {70, QpFormula::func1, "len("}, // @length => len
+ {81, QpFormula::funcV, "average("}, // @avg => average
+ {87, QpFormula::funcV, "variance("},// @var => variance
+ {88, QpFormula::funcV, "stddev("}, // @std => stddev
+ {101, QpFormula::func2, "REPT("}, // @repeat => REPT
+ {0, 0, 0}
+};
+
+KSpread::Formula::Formula(QpRecFormulaCell& pCell, QpTableNames& pTable)
+ : QpFormula(pCell, pTable)
+{
+ formulaStart("="); // quattro pro starts formulas with "+"
+ // kspread uses "="
+ dropLeadingAt(); // quattro pro starts it's functions with '@'
+ // kspread doesn't like this
+ argSeparator(";"); // quattro pro separates function arguments with ","
+ // kspread likes ";"
+
+ // override some of the default conversions
+ replaceFunc(gOverride);
+}
+
+KSpread::Formula::~Formula()
+{
+}
diff --git a/filters/kspread/qpro/qproformula.h b/filters/kspread/qpro/qproformula.h
new file mode 100644
index 000000000..bc115a80f
--- /dev/null
+++ b/filters/kspread/qpro/qproformula.h
@@ -0,0 +1,18 @@
+#ifndef QPROFORMULA_H
+#define QPROFORMULA_H
+
+#include <qpro/formula.h>
+
+namespace KSpread
+{
+
+class Formula : public QpFormula
+{
+public:
+ Formula(QpRecFormulaCell& pCell, QpTableNames& pTable);
+ ~Formula();
+};
+
+}
+
+#endif // QPROFORMULA_H
diff --git a/filters/kspread/qpro/qproimport.cc b/filters/kspread/qpro/qproimport.cc
new file mode 100644
index 000000000..72309275f
--- /dev/null
+++ b/filters/kspread/qpro/qproimport.cc
@@ -0,0 +1,263 @@
+
+/* This file is part of the KDE project
+ Copyright (C) 2001 Graham Short <grahshrt@netscape.net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kgenericfactory.h>
+#include <KoFilterChain.h>
+
+#include <kspread_doc.h>
+#include <kspread_sheet.h>
+#include <kspread_cell.h>
+#include <kspread_map.h>
+
+#include <qproimport.h>
+
+#include <qproformula.h>
+#include <qpro/stream.h>
+#include <qpro/record_factory.h>
+#include <qfile.h>
+
+using namespace KSpread;
+
+typedef KGenericFactory<QpImport, KoFilter> QPROImportFactory;
+K_EXPORT_COMPONENT_FACTORY( libqproimport, QPROImportFactory( "kofficefilters" ) )
+
+// ---------------------------------------------------------------
+
+QpTableList::QpTableList()
+{
+ for( int lIdx=0; lIdx<cNameCnt; ++lIdx )
+ {
+ cTable[lIdx] = 0;
+ }
+}
+
+QpTableList::~QpTableList()
+{
+ // don't delete the list of tables
+}
+
+
+void
+QpTableList::table(unsigned pIdx, Sheet* pTable)
+{
+ if(pIdx < cNameCnt)
+ {
+ cTable[pIdx] = pTable;
+ }
+}
+
+Sheet*
+QpTableList::table(unsigned pIdx)
+{
+ return (pIdx < cNameCnt ? cTable[pIdx] : 0);
+}
+
+
+// ---------------------------------------------------------------
+
+QpImport::QpImport( KoFilter*, const char*, const QStringList& )
+ : KoFilter()
+{
+//cout << "Hooray - in QpImport::QpImport" << endl; // ???
+}
+
+void
+QpImport::InitTableName(int pIdx, QString& pResult)
+{
+ if( pIdx < 26 )
+ {
+ pResult = (char)('A' + pIdx);
+ }
+ else
+ {
+ pResult = (char)('A' -1 + pIdx / 26);
+ pResult += (char)('A' + pIdx % 26);
+ }
+}
+
+KoFilter::ConversionStatus QpImport::convert( const QCString& from, const QCString& to )
+{
+ bool bSuccess=true;
+
+ KoDocument* document = m_chain->outputDocument();
+ if ( !document )
+ return KoFilter::StupidError;
+
+ kdDebug(30523) << "here we go... " << document->className() << endl;
+
+ if( !::qt_cast<const KSpread::Doc *>( document ) ) // it's safer that way :)
+ {
+ kdWarning(30501) << "document isn't a KSpread::Doc but a " << document->className() << endl;
+ return KoFilter::NotImplemented;
+ }
+ if(from!="application/x-quattropro" || to!="application/x-kspread")
+ {
+ kdWarning(30501) << "Invalid mimetypes " << from << " " << to << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ kdDebug(30523) << "...still here..." << endl;
+
+ // No need for a dynamic cast here, since we use Qt's moc magic
+ Doc *ksdoc=(Doc*)document;
+
+ if(ksdoc->mimeType()!="application/x-kspread")
+ {
+ kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
+ return KoFilter::NotImplemented;
+ }
+
+ QpIStream lIn( QFile::encodeName(m_chain->inputFile()) );
+
+ if( !lIn )
+ {
+ KMessageBox::sorry( 0L, i18n("QPRO filter cannot open input file - please report.") );
+ return KoFilter::FileNotFound;
+ }
+
+ Sheet *table=0;
+
+ QString field;
+ int value=0;
+ emit sigProgress(value);
+
+ QpRecFactory lFactory(lIn);
+ QpTableList lTableNames;
+ QP_UINT8 lPageIdx = 0;
+
+ QpRec* lRec = 0;
+ QpRecBop* lRecBop = 0;
+ QpRecIntegerCell* lRecInt = 0;
+ QpRecFloatingPointCell* lRecFloat = 0;
+ QpRecFormulaCell* lRecFormula = 0;
+ QpRecLabelCell* lRecLabel = 0;
+ QpRecPageName* lRecPageName = 0;
+
+ do
+ {
+ field = "";
+ lRec = lFactory.nextRecord();
+
+ switch( lRec->type() )
+ {
+ case QpBop:
+ lRecBop = (QpRecBop*)lRec;
+ lPageIdx = lRecBop->pageIndex();
+
+ // find out if we know about this table already, if not create it
+ table=lTableNames.table(lPageIdx);
+
+ if( table == 0 )
+ {
+ table=ksdoc->map()->addNewSheet();
+ // set up a default name for the table
+ table->setSheetName( lTableNames.name(lPageIdx)
+ , TRUE
+ );
+ lTableNames.table(lPageIdx, table);
+ }
+ break;
+
+ case QpIntegerCell:
+ lRecInt = (QpRecIntegerCell*)lRec;
+ field.setNum( lRecInt->integer() );
+//cout << "Setting R " << lRecInt->row()+1 << ", C " << ((unsigned)lRecInt->column()) << endl;
+ table->setText( lRecInt->row()+1, ((unsigned)lRecInt->column())+1, field, false );
+ break;
+
+ case QpFormulaCell:
+ lRecFormula = (QpRecFormulaCell*)lRec;
+ {
+ Formula lAnswer(*lRecFormula, lTableNames);
+
+ char* lFormula = lAnswer.formula();
+
+ field = lFormula;
+
+ delete [] lFormula;
+ }
+
+ // check for referenced tables that haven't been created yet
+ for(unsigned lIdx=0; lIdx<lTableNames.cNameCnt; ++lIdx)
+ {
+ if(lTableNames.allocated(lIdx) && (lTableNames.table(lIdx) == 0) )
+ {
+ // we're about to reference a table that hasn't been created yet.
+ // setText gets upset about this, so create a blank table
+
+ Sheet* lNewTable=ksdoc->map()->addNewSheet();
+
+ // set up a default name for the table
+ lNewTable->setSheetName( lTableNames.name(lIdx)
+ , TRUE
+ );
+ lTableNames.table(lIdx, lNewTable);
+ }
+ }
+
+ table->setText( lRecFormula->row()+1, lRecFormula->column()+1, field, false );
+ break;
+
+ case QpFloatingPointCell:
+ lRecFloat = (QpRecFloatingPointCell*)lRec;
+ field.setNum( lRecFloat->value() );
+ table->setText( lRecFloat->row()+1, lRecFloat->column()+1, field, false );
+ break;
+
+ case QpLabelCell:
+ lRecLabel = (QpRecLabelCell*)lRec;
+ field = "'";
+ field += lRecLabel->label();
+ table->setText( lRecLabel->row()+1, lRecLabel->column()+1, field, false );
+ break;
+
+ case QpPageName:
+ lRecPageName = (QpRecPageName*)lRec;
+
+ if( lTableNames.allocated(lPageIdx) && lTableNames.table(lPageIdx) )
+ {
+ lTableNames.table(lPageIdx)->setSheetName( lRecPageName->pageName()
+// , TRUE
+ );
+ lTableNames.name(lPageIdx, lRecPageName->pageName());
+ }
+ break;
+
+ case QpPassword:
+ KMessageBox::sorry( 0L, i18n("Unable to open password protected files.\n"
+ "The password algorithm has not been published")
+ );
+ return KoFilter::NotImplemented;
+ }
+
+ delete lRec;
+ lRec = 0;
+ } while( lIn );
+
+ emit sigProgress(100);
+ if ( bSuccess )
+ return KoFilter::OK;
+ else
+ return KoFilter::StupidError;
+}
+
+#include <qproimport.moc>
diff --git a/filters/kspread/qpro/qproimport.h b/filters/kspread/qpro/qproimport.h
new file mode 100644
index 000000000..b0ba0fc81
--- /dev/null
+++ b/filters/kspread/qpro/qproimport.h
@@ -0,0 +1,55 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 David Faure <faure@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#ifndef QPROIMPORT_H
+#define QPROIMPORT_H
+
+#include <KoFilter.h>
+#include <qpro/tablenames.h>
+
+namespace KSpread
+{
+class Sheet;
+}
+
+class QpImport : public KoFilter {
+
+ Q_OBJECT
+
+public:
+ QpImport(KoFilter* parent, const char* name, const QStringList&);
+ virtual ~QpImport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+ void InitTableName(int pIdx, QString& pResult);
+};
+
+class QpTableList : public QpTableNames
+{
+public:
+ QpTableList();
+ ~QpTableList();
+
+ void table(unsigned pIdx, KSpread::Sheet* pTable);
+ KSpread::Sheet* table(unsigned pIdx);
+protected:
+ KSpread::Sheet* cTable[cNameCnt];
+};
+
+#endif // QPROIMPORT_H
diff --git a/filters/kspread/qpro/status.html b/filters/kspread/qpro/status.html
new file mode 100644
index 000000000..ff53bb40d
--- /dev/null
+++ b/filters/kspread/qpro/status.html
@@ -0,0 +1,178 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <title>KOffice filters status: Quattro Pro Spreadsheet FILTER</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<A NAME="START">&nbsp;</A>
+
+<BR>
+<center>
+ <h1>
+ KOffice filters status: &nbsp;&nbsp;<i>Quattro Pro FILTER</i>
+ </h1>
+</center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%">
+
+<font size="-1"><b>
+ <A HREF="#import">Import</A> |
+ <A HREF="#export">Export</A>
+</b></font>
+
+<BR><BR><BR>
+<center><a NAME="import"></a></center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+
+ <tr BGCOLOR="#DDFFDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>
+ Import Quattro Pro (Spreadsheet) for kspread<BR>
+ <BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>27 june 2001</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>
+ -Currently supports only older type Quattro Pro files (*.wb?).<br>
+ -Translation is at the basic level (i.e. without regard to fonts, colours e.t.c.).<br>
+ -Supports multi-page spreadsheets.<br>
+ -Some Quattro Pro functions may cause the filter to crash.<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>
+ -Handle all functions without crashing.<br>
+ -Support later file types (*.qpw).<br>
+ -Handle attibutes (fonts, colours, line drawing e.t.c).<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>
+
+
+ <table border="0" cellspacing="0">
+ <tr valign=top>
+ <td align=right>17 may 2001</td>
+ <td>&nbsp;:&nbsp;&nbsp;</td>
+ <td>Added my first filter version (alpha)</td>
+ </tr>
+ </table>
+
+
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors&nbsp;</font></b></td>
+ <td><A HREF="mailto:GrahShrt@netscape.net">Graham Short</A></td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td><A HREF="http://-">-</A></td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>Quattro Pro has about 160 functions. I am currently working my way through these,
+testing and checking for equivalent kspread functions.<br>
+I am currently up to STDS which is number 122.
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+<br><br><br>
+
+<hr NOSHADE SIZE=1>
+<br><br><br>
+
+
+<center>
+ <a NAME="export"></a>
+</center>
+
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+ <tr BGCOLOR="#FFDDDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ <BR>Export kspread to Quattro Pro (Spreadsheet)<BR><BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>None</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>Everything</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>-</td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td><a href="mailto:null@kde.org">-</a></td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td><a href="http://www.koffice.org">-</a></td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Progress report </font></b></td>
+ <td>Once I have coded the import filter to user take note of the
+cell attributes (fonts, colours etc.) then I will have a more complete understanding
+of Quattro Pro file format. This knowledge will enable me to
+produce the export filter.</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<A HREF="#START"><font size="-1"><b>Up</b></font></A>
+
+</body>
+</html>