7
0
Fork 0
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
koffice/filters/kspread/csv/csvdialog.cpp

636 Zeilen
18 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 <dialogui.h>
#include <csvdialog.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 <kapplication.h>
#include <tdeconfig.h>
#include <kdebug.h>
#include <klocale.h>
#include <kcombobox.h>
#include <kmessagebox.h>
#include <kcharsets.h>
CSVDialog::CSVDialog(TQWidget* parent, TQByteArray& fileArray, const TQString /*seperator*/)
: KDialogBase(parent, 0, true, TQString(), 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( TQTextCodec::codecForName( "UTF-8" ) )
{
setCaption( i18n( "Import" ) );
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 );
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( 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 & ) ));
}
CSVDialog::~CSVDialog()
{
saveSettings();
kapp->setOverrideCursor(TQt::waitCursor);
}
void CSVDialog::loadSettings()
{
TDEConfig *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 TQString 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()
{
TDEConfig *config = kapp->config();
config->setGroup("CSVDialog Settings");
TQString 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;
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
{
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;
}
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 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)
{
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
}
TQString CSVDialog::getText(int row, int col)
{
return m_dialog->m_sheet->text( row, col );
}
void CSVDialog::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 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 TQString & )
{
m_dialog->m_radioOther->setChecked ( true );
delimiterClicked(4); // other
}
void CSVDialog::formatChanged( const TQString& newValue )
{
//kdDebug(30501) << "CSVDialog::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 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 TQString& 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 TQString 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();
}
TQTextCodec* CSVDialog::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 CSVDialog::encodingChanged ( const TQString & )
{
TQTextCodec* codec = getCodec();
if ( codec )
{
m_codec = codec;
fillTable();
}
}
#include <csvdialog.moc>