filters

csvimport.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1999 David Faure <faure@kde.org>
00003    Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <csvimport.h>
00022 
00023 #include <qfile.h>
00024 #include <qregexp.h>
00025 
00026 #include <kapplication.h>
00027 #include <kmessagebox.h>
00028 #include <kdebug.h>
00029 #include <kgenericfactory.h>
00030 
00031 #include <KoFilterChain.h>
00032 #include <KoFilterManager.h>
00033 #include <kspread_doc.h>
00034 #include <kspread_global.h>
00035 #include <kspread_map.h>
00036 #include <kspread_sheet.h>
00037 #include <kspread_style.h>
00038 #include <kspread_style_manager.h>
00039 #include <kspread_cell.h>
00040 
00041 #include <csvdialog.h>
00042 
00043 using namespace KSpread;
00044 
00045 // hehe >:->
00046 
00047 /*
00048  To generate a test CSV file:
00049 
00050  perl -e '$i=0;while($i<30000) { print rand().",".rand()."\n"; $i++ }' > file.csv
00051 */
00052 
00053 typedef KGenericFactory<CSVFilter, KoFilter> CSVImportFactory;
00054 K_EXPORT_COMPONENT_FACTORY( libcsvimport, CSVImportFactory( "kofficefilters" ) )
00055 
00056 CSVFilter::CSVFilter(KoFilter *, const char*, const QStringList&) :
00057                      KoFilter() {
00058 }
00059 
00060 KoFilter::ConversionStatus CSVFilter::convert( const QCString& from, const QCString& to )
00061 {
00062     QString file( m_chain->inputFile() );
00063     KoDocument* document = m_chain->outputDocument();
00064 
00065     if ( !document )
00066         return KoFilter::StupidError;
00067 
00068     kdDebug(30501) << "here we go... " << document->className() << endl;
00069 
00070     if ( !::qt_cast<const KSpread::Doc *>( document ) )
00071     {
00072       kdWarning(30501) << "document isn't a KSpread::Doc but a " << document->className() << endl;
00073         return KoFilter::NotImplemented;
00074     }
00075     if(from!="text/x-csv" && from!="text/plain" || to!="application/x-kspread")
00076     {
00077         kdWarning(30501) << "Invalid mimetypes " << from << " " << to << endl;
00078         return KoFilter::NotImplemented;
00079     }
00080 
00081     kdDebug(30501) << "...still here..." << endl;
00082 
00083     Doc *ksdoc = static_cast<Doc *>( document ); // type checked above
00084 
00085     if(ksdoc->mimeType()!="application/x-kspread")
00086     {
00087         kdWarning(30501) << "Invalid document mimetype " << ksdoc->mimeType() << endl;
00088         return KoFilter::NotImplemented;
00089     }
00090 
00091     QFile in(file);
00092     if(!in.open(IO_ReadOnly)) {
00093         KMessageBox::sorry( 0L, i18n("CSV filter cannot open input file - please report.") );
00094         in.close();
00095         return KoFilter::FileNotFound;
00096     }
00097 
00098     QString csv_delimiter;
00099     // ###### FIXME: disabled for now
00100     //if (!config.isNull())
00101     //    csv_delimiter = config[0];
00102 
00103     QByteArray inputFile( in.readAll() );
00104     in.close();
00105 
00106     CSVDialog *dialog = new CSVDialog(0L, inputFile, csv_delimiter );
00107     if (!m_chain->manager()->getBatchMode() && !dialog->exec())
00108       return KoFilter::UserCancelled;
00109     inputFile.resize( 0 ); // Release memory (input file content)
00110 
00111     ElapsedTime t( "Filling data into document" );
00112 
00113     Cell*cell;
00114     Sheet *sheet=ksdoc->map()->addNewSheet();
00115 
00116     int numRows = dialog->getRows();
00117     int numCols = dialog->getCols();
00118 
00119     if (numRows == 0)
00120       ++numRows;
00121 
00122     int step = 100 / numRows * numCols;
00123     int value = 0;
00124 
00125     emit sigProgress(value);
00126     QApplication::setOverrideCursor(Qt::waitCursor);
00127 
00128     int i;
00129     double init = sheet->nonDefaultColumnFormat( 1 )->dblWidth();
00130     QMemArray<double> widths( numCols );
00131     for ( i = 0; i < numCols; ++i )
00132       widths[i] = init;
00133 
00134     Cell* c = sheet->nonDefaultCell( 1, 1 );
00135     QFontMetrics fm( c->format()->textFont( 1, 1 ) );
00136 
00137     Style * s = ksdoc->styleManager()->defaultStyle();
00138 
00139     for ( int row = 0; row < numRows; ++row )
00140     {
00141         for (int col = 0; col < numCols; ++col)
00142         {
00143             value += step;
00144             emit sigProgress(value);
00145             const QString text( dialog->getText( row, col ) );
00146 
00147             // ### FIXME: how to calculate the width of numbers (as they might not be in the right format)
00148             const double len = fm.width( text );
00149             if ( len > widths[col] )
00150               widths[col] = len;
00151 
00152             switch (dialog->getHeader(col))
00153             {
00154              case CSVDialog::TEXT:
00155                //see CSVDialog::accept(), Tomas introduced the Generic format between KOffice 1.3 and 1.4
00156                //the Insert->External Data-> ... dialog uses the generic format for everything (see mentioned method)
00157                //I will use this approach only for the TEXT format in the CSV import filter... (raphael)
00158                //### FIXME: long term solution is to allow to select Generic format ("autodetect") in the dialog and make it the default
00159                
00160                cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00161                cell->setCellText( text );
00162                
00163                cell->format()->setFormatType (Generic_format);
00164                
00165                /* old code
00166               cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00167               cell->setCellText( text, true );
00168                */
00169               break;
00170              // ### TODO: put the code for the different numbers together (at least partially)
00171              case CSVDialog::NUMBER:
00172                 {
00173                     bool ok = false;
00174                     double d = ksdoc->locale()->readNumber( text, &ok );
00175                     // If not, try with the '.' as decimal separator
00176                     if ( !ok )
00177                         d = text.toDouble( &ok );
00178                     if ( !ok )
00179                     {
00180                         cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00181                         cell->setCellText( text, true );
00182                     }
00183                     else
00184                     {
00185                         cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00186                         cell->setNumber( d );
00187                     }
00188                     cell->format()->setPrecision( 2 );
00189                     break;
00190                 }
00191              case CSVDialog::COMMANUMBER:
00192                 {
00193                     bool ok = false;
00194                     QString tmp ( text );
00195                     tmp.remove ( QRegExp( "[^0-9,Ee+-]" ) ); // Keep only 0 to 9, comma, E, e, plus, minus
00196                     tmp.replace ( ',', '.' );
00197                     kdDebug(30501) << "Comma: " << text << " => " << tmp << endl;
00198                     const double d = tmp.toDouble( &ok );
00199                     if ( !ok )
00200                     {
00201                         cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00202                         cell->setCellText( text, true );
00203                     }
00204                     else
00205                     {
00206                         cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00207                         cell->setNumber( d );
00208                     }
00209                     cell->format()->setPrecision( 2 );
00210                     break;
00211                 }
00212              case CSVDialog::POINTNUMBER:
00213                 {
00214                     bool ok = false;
00215                     QString tmp ( text );
00216                     tmp.remove ( QRegExp( "[^0-9\\.EeD+-]" ) ); // Keep only 0 to 9, dot, E, e, D, plus, minus
00217                     tmp.replace ( 'D', 'E' ); // double from FORTRAN use D instead of E
00218                     kdDebug(30501) << "Point: " << text << " => " << tmp << endl;
00219                     const double d = tmp.toDouble( &ok );
00220                     if ( !ok )
00221                     {
00222                         cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00223                         cell->setCellText( text,  true );
00224                     }
00225                     else
00226                     {
00227                         cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00228                         cell->setNumber( d );
00229                     }
00230                     cell->format()->setPrecision( 2 );
00231                     break;
00232                 }
00233              case CSVDialog::DATE:
00234               cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00235               cell->setCellText( text );
00236               cell->format()->setFormatType( ShortDate_format );
00237               break;
00238              case CSVDialog::CURRENCY:
00239               cell = sheet->nonDefaultCell( col + 1, row + 1, false, s );
00240               cell->setCellText( text, false );
00241               cell->format()->setFormatType( Money_format );
00242               cell->format()->setPrecision( 2 );
00243               break;
00244             }
00245         }
00246     }
00247 
00248     emit sigProgress( 98 );
00249 
00250     ElapsedTime t2( "Resizing columns" );
00251     for ( i = 0; i < numCols; ++i )
00252     {
00253       ColumnFormat * c  = sheet->nonDefaultColumnFormat( i + 1 );
00254       c->setDblWidth( widths[i] );
00255     }
00256 
00257     emit sigProgress( 100 );
00258     QApplication::restoreOverrideCursor();
00259     delete dialog;
00260 
00261     return KoFilter::OK;
00262 }
00263 
00264 #include <csvimport.moc>
KDE Home | KDE Accessibility Home | Description of Access Keys