You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/filters/kspread/csv/csvimport.cc

265 lines
9.2 KiB

/* 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 <tqfile.h>
#include <tqregexp.h>
#include <tdeapplication.h>
#include <tdemessagebox.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 TQStringList&) :
KoFilter() {
}
KoFilter::ConversionStatus CSVFilter::convert( const TQCString& from, const TQCString& to )
{
TQString file( m_chain->inputFile() );
KoDocument* document = m_chain->outputDocument();
if ( !document )
return KoFilter::StupidError;
kdDebug(30501) << "here we go... " << document->className() << endl;
if ( !::tqqt_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;
}
TQFile in(file);
if(!in.open(IO_ReadOnly)) {
KMessageBox::sorry( 0L, i18n("CSV filter cannot open input file - please report.") );
in.close();
return KoFilter::FileNotFound;
}
TQString csv_delimiter;
// ###### FIXME: disabled for now
//if (!config.isNull())
// csv_delimiter = config[0];
TQByteArray 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);
TQApplication::setOverrideCursor(TQt::waitCursor);
int i;
double init = sheet->nonDefaultColumnFormat( 1 )->dblWidth();
TQMemArray<double> widths( numCols );
for ( i = 0; i < numCols; ++i )
widths[i] = init;
Cell* c = sheet->nonDefaultCell( 1, 1 );
TQFontMetrics 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 TQString 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;
TQString tmp ( text );
tmp.remove ( TQRegExp( "[^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;
TQString tmp ( text );
tmp.remove ( TQRegExp( "[^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 );
TQApplication::restoreOverrideCursor();
delete dialog;
return KoFilter::OK;
}
#include <csvimport.moc>