summaryrefslogtreecommitdiffstats
path: root/kchart/csvimportdialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kchart/csvimportdialog.cpp')
-rw-r--r--kchart/csvimportdialog.cpp633
1 files changed, 633 insertions, 0 deletions
diff --git a/kchart/csvimportdialog.cpp b/kchart/csvimportdialog.cpp
new file mode 100644
index 000000000..cf13c1b5e
--- /dev/null
+++ b/kchart/csvimportdialog.cpp
@@ -0,0 +1,633 @@
+/* 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 <csvimportdialogui.h>
+#include <csvimportdialog.h>
+
+#include <tqtable.h>
+#include <tqcheckbox.h>
+#include <tqcursor.h>
+#include <tqlineedit.h>
+#include <tqcombobox.h>
+#include <tqspinbox.h>
+#include <tqtextstream.h>
+#include <tqbuttongroup.h>
+#include <tqpushbutton.h>
+#include <tqradiobutton.h>
+#include <tqtextcodec.h>
+
+#include <tdeapplication.h>
+#include <kdebug.h>
+#include <tdelocale.h>
+#include <kcombobox.h>
+#include <tdemessagebox.h>
+#include <kcharsets.h>
+
+
+CSVImportDialog::CSVImportDialog(TQWidget* parent, TQByteArray& fileArray)
+ : KDialogBase(parent, 0, true, TQString(), Ok|Cancel, No, true),
+ m_dialog(new DialogUI(this)),
+ 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_codec( TQTextCodec::codecForName( "UTF-8" ) )
+{
+ setCaption( i18n( "Import Data" ) );
+ kapp->restoreOverrideCursor();
+
+ TQStringList encodings;
+ encodings << i18n( "Descriptive encoding name", "Recommended ( %1 )" ).arg( "UTF-8" );
+ encodings << i18n( "Descriptive encoding name", "Locale ( %1 )" ).arg( TQTextCodec::codecForLocale()->name() );
+ encodings += TDEGlobal::charsets()->descriptiveEncodingNames();
+ // Add a few non-standard encodings, which might be useful for text files
+ const TQString 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 );
+
+ 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( TQTable::Multi );
+
+ connect(m_dialog->m_formatComboBox, TQT_SIGNAL(activated( const TQString& )),
+ this, TQT_SLOT(formatChanged( const TQString& )));
+ connect(m_dialog->m_delimiterBox, TQT_SIGNAL(clicked(int)),
+ this, TQT_SLOT(delimiterClicked(int)));
+ connect(m_dialog->m_delimiterEdit, TQT_SIGNAL(returnPressed()),
+ this, TQT_SLOT(returnPressed()));
+ connect(m_dialog->m_delimiterEdit, TQT_SIGNAL(textChanged ( const TQString & )),
+ this, TQT_SLOT(formatChanged ( const TQString & ) ));
+ connect(m_dialog->m_comboQuote, TQT_SIGNAL(activated(const TQString &)),
+ this, TQT_SLOT(textquoteSelected(const TQString &)));
+ connect(m_dialog->m_sheet, TQT_SIGNAL(currentChanged(int, int)),
+ this, TQT_SLOT(currentCellChanged(int, int)));
+ connect(m_dialog->m_ignoreDuplicates, TQT_SIGNAL(stateChanged(int)),
+ this, TQT_SLOT(ignoreDuplicatesChanged(int)));
+ connect(m_dialog->m_updateButton, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(updateClicked()));
+ connect(m_dialog->comboBoxEncoding, TQT_SIGNAL(textChanged ( const TQString & )),
+ this, TQT_SLOT(encodingChanged ( const TQString & ) ));
+}
+
+
+CSVImportDialog::~CSVImportDialog()
+{
+ kapp->setOverrideCursor(TQt::waitCursor);
+}
+
+
+// ----------------------------------------------------------------
+// public methods
+
+
+bool CSVImportDialog::firstRowContainHeaders()
+{
+ return m_dialog->m_firstRowHeader->isChecked();
+}
+
+
+bool CSVImportDialog::firstColContainHeaders()
+{
+ return m_dialog->m_firstColHeader->isChecked();
+}
+
+
+int CSVImportDialog::rows()
+{
+ int rows = m_dialog->m_sheet->numRows();
+
+ if ( m_endRow >= 0 )
+ rows = m_endRow - m_startRow + 1;
+
+ return rows;
+}
+
+
+int CSVImportDialog::cols()
+{
+ int cols = m_dialog->m_sheet->numCols();
+
+ if ( m_endCol >= 0 )
+ cols = m_endCol - m_startCol + 1;
+
+ return cols;
+}
+
+
+TQString CSVImportDialog::text(int row, int col)
+{
+ // Check for overflow.
+ if ( row >= rows() || col >= cols())
+ return TQString();
+
+ return m_dialog->m_sheet->text( row - m_startRow, col - m_startCol );
+}
+
+
+// ----------------------------------------------------------------
+
+
+void CSVImportDialog::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;
+
+ TQChar x;
+ TQString field;
+
+ kapp->setOverrideCursor(TQt::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;
+ TQTextStream 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 == TQChar( 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 if (x == '\n')
+ {
+ setText(row - m_startRow, column - m_startCol, field);
+ field = TQString();
+
+ ++row;
+ column = 1;
+ if ( row > ( m_endRow - m_startRow ) && m_endRow >= 0 )
+ break;
+
+ state = S_START;
+ }
+ 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 = TQString();
+ 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 = TQString();
+ 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_MAYBE_NORMAL_FIELD :
+ if (x == m_textquote)
+ {
+ field = TQString();
+ state = S_QUOTED_FIELD;
+ break;
+ }
+ case S_NORMAL_FIELD :
+ if (x == m_delimiter || x == '\n')
+ {
+ setText(row - m_startRow, column - m_startCol, field);
+ field = TQString();
+ 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 = TQString();
+ }
+
+ 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 TQString 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 CSVImportDialog::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 CSVImportDialog::headerType(int col)
+{
+ TQString 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
+}
+
+void CSVImportDialog::setText(int row, int col, const TQString& 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 CSVImportDialog::adjustRows(int iRows)
+{
+ if (m_adjustRows)
+ {
+ m_dialog->m_sheet->setNumRows( iRows );
+ m_adjustRows = false;
+ }
+}
+
+void CSVImportDialog::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 CSVImportDialog::returnPressed()
+{
+ if (m_dialog->m_delimiterBox->id(m_dialog->m_delimiterBox->selected()) != 4)
+ return;
+
+ m_delimiter = m_dialog->m_delimiterEdit->text();
+ fillTable();
+}
+
+void CSVImportDialog::textChanged ( const TQString & )
+{
+ m_dialog->m_radioOther->setChecked ( true );
+ delimiterClicked(4); // other
+}
+
+void CSVImportDialog::formatChanged( const TQString& newValue )
+{
+ //kdDebug(30501) << "CSVImportDialog::formatChanged:" << newValue << endl;
+ for ( int i = 0; i < m_dialog->m_sheet->numSelections(); ++i )
+ {
+ TQTableSelection 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 CSVImportDialog::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 CSVImportDialog::textquoteSelected(const TQString& mark)
+{
+ if (mark == i18n("None"))
+ m_textquote = 0;
+ else
+ m_textquote = mark[0];
+
+ fillTable();
+}
+
+void CSVImportDialog::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 CSVImportDialog::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 CSVImportDialog::currentCellChanged(int, int col)
+{
+ const TQString header = m_dialog->m_sheet->horizontalHeader()->label(col);
+ m_dialog->m_formatComboBox->setCurrentText( header );
+}
+
+void CSVImportDialog::ignoreDuplicatesChanged(int)
+{
+ if (m_dialog->m_ignoreDuplicates->isChecked())
+ m_ignoreDups = true;
+ else
+ m_ignoreDups = false;
+ fillTable();
+}
+
+TQTextCodec* CSVImportDialog::getCodec(void) const
+{
+ const TQString strCodec( TDEGlobal::charsets()->encodingForName( m_dialog->comboBoxEncoding->currentText() ) );
+ kdDebug(30502) << "Encoding: " << strCodec << endl;
+
+ bool ok = false;
+ TQTextCodec* codec = TQTextCodec::codecForName( strCodec.utf8() );
+
+ // If TQTextCodec has not found a valid encoding, so try with KCharsets.
+ if ( codec )
+ {
+ ok = true;
+ }
+ else
+ {
+ codec = TDEGlobal::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 CSVImportDialog::encodingChanged ( const TQString & )
+{
+ TQTextCodec* codec = getCodec();
+
+ if ( codec )
+ {
+ m_codec = codec;
+ fillTable();
+ }
+}
+
+
+#include <csvimportdialog.moc>