1
/* This file is part of the KDE project
2
Copyright (C) 2002 Norbert Andres (nandres@web.de)
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
Boston, MA 02111-1307, USA.
20
#include <qbuttongroup.h>
21
#include <qcheckbox.h>
22
#include <qclipboard.h>
23
#include <qcombobox.h>
25
#include <qlineedit.h>
27
#include <qpushbutton.h>
28
#include <qradiobutton.h>
32
#include <kapplication.h>
34
#include <kdialogbase.h>
35
#include <kfiledialog.h>
37
#include <kmessagebox.h>
39
#include <kspread_dlg_csv.h>
40
#include <kspread_cell.h>
41
#include <kspread_doc.h>
42
#include <kspread_sheet.h>
43
#include <kspread_undo.h>
44
#include <kspread_view.h>
46
KSpreadCSVDialog::KSpreadCSVDialog( KSpreadView * parent, const char * name, QRect const & rect, Mode mode)
47
: KDialogBase( parent, name, true, QString::null, Ok|Cancel ),
58
setName( "KSpreadCSVDialog" );
60
setSizeGripEnabled( TRUE );
62
QWidget* page = new QWidget( this );
63
setMainWidget( page );
64
// MyDialogLayout = new QGridLayout( page, 4, 4, marginHint(), spacingHint(), "MyDialogLayout");
65
MyDialogLayout = new QGridLayout( page, 1, 1, 11, 6, "MyDialogLayout");
68
int column = m_targetRect.left();
69
KSpreadCell* lastCell = m_pView->activeTable()->getLastCellColumn( column );
71
if( m_targetRect.bottom() > lastCell->row() )
72
m_targetRect.setBottom( lastCell->row() );
74
m_table = new QTable( page, "m_table" );
75
//m_table->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)7, 0, 0, m_table->sizePolicy().hasHeightForWidth() ) );
76
m_table->setNumRows( 0 );
77
m_table->setNumCols( 0 );
79
MyDialogLayout->addMultiCellWidget( m_table, 3, 3, 0, 3 );
81
// Delimiter: comma, semicolon, tab, space, other
82
m_delimiterBox = new QButtonGroup( page, "m_delimiterBox" );
83
m_delimiterBox->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)1, 0, 0, m_delimiterBox->sizePolicy().hasHeightForWidth() ) );
84
m_delimiterBox->setTitle( i18n( "Delimiter" ) );
85
m_delimiterBox->setColumnLayout(0, Qt::Vertical );
86
m_delimiterBox->layout()->setSpacing( KDialog::spacingHint() );
87
m_delimiterBox->layout()->setMargin( KDialog::marginHint() );
88
m_delimiterBoxLayout = new QGridLayout( m_delimiterBox->layout() );
89
m_delimiterBoxLayout->setAlignment( Qt::AlignTop );
90
MyDialogLayout->addMultiCellWidget( m_delimiterBox, 0, 2, 0, 0 );
92
m_ignoreDuplicates = new QCheckBox( page, "m_ignoreDuplicates" );
93
m_ignoreDuplicates->setText( i18n( "Ignore duplicate delimiters" ) );
95
MyDialogLayout->addMultiCellWidget( m_ignoreDuplicates, 2, 2, 2, 3 );
97
m_radioComma = new QRadioButton( m_delimiterBox, "m_radioComma" );
98
m_radioComma->setText( i18n( "Comma" ) );
99
m_radioComma->setChecked( TRUE );
100
m_delimiterBoxLayout->addWidget( m_radioComma, 0, 0 );
102
m_radioSemicolon = new QRadioButton( m_delimiterBox, "m_radioSemicolon" );
103
m_radioSemicolon->setText( i18n( "Semicolon" ) );
104
m_delimiterBoxLayout->addWidget( m_radioSemicolon, 0, 1 );
106
m_radioTab = new QRadioButton( m_delimiterBox, "m_radioTab" );
107
m_radioTab->setText( i18n( "Tabulator" ) );
108
m_delimiterBoxLayout->addWidget( m_radioTab, 1, 0 );
110
m_radioSpace = new QRadioButton( m_delimiterBox, "m_radioSpace" );
111
m_radioSpace->setText( i18n( "Space" ) );
112
m_delimiterBoxLayout->addWidget( m_radioSpace, 1, 1 );
114
m_radioOther = new QRadioButton( m_delimiterBox, "m_radioOther" );
115
m_radioOther->setText( i18n( "Other" ) );
116
m_delimiterBoxLayout->addWidget( m_radioOther, 0, 2 );
118
m_delimiterEdit = new QLineEdit( m_delimiterBox, "m_delimiterEdit" );
119
m_delimiterEdit->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, m_delimiterEdit->sizePolicy().hasHeightForWidth() ) );
120
m_delimiterEdit->setMaximumSize( QSize( 30, 32767 ) );
121
m_delimiterBoxLayout->addWidget( m_delimiterEdit, 1, 2 );
124
// Format: number, text, currency,
125
m_formatBox = new QButtonGroup( page, "m_formatBox" );
126
m_formatBox->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)1, 0, 0, m_formatBox->sizePolicy().hasHeightForWidth() ) );
127
m_formatBox->setTitle( i18n( "Format" ) );
128
m_formatBox->setColumnLayout(0, Qt::Vertical );
129
m_formatBox->layout()->setSpacing( KDialog::spacingHint() );
130
m_formatBox->layout()->setMargin( KDialog::marginHint() );
131
m_formatBoxLayout = new QGridLayout( m_formatBox->layout() );
132
m_formatBoxLayout->setAlignment( Qt::AlignTop );
133
MyDialogLayout->addMultiCellWidget( m_formatBox, 0, 2, 1, 1 );
135
m_radioNumber = new QRadioButton( m_formatBox, "m_radioNumber" );
136
m_radioNumber->setText( i18n( "Number" ) );
137
m_formatBoxLayout->addMultiCellWidget( m_radioNumber, 1, 1, 0, 1 );
139
m_radioText = new QRadioButton( m_formatBox, "m_radioText" );
140
m_radioText->setText( i18n( "Text" ) );
141
m_radioText->setChecked( TRUE );
142
m_formatBoxLayout->addWidget( m_radioText, 0, 0 );
144
m_radioCurrency = new QRadioButton( m_formatBox, "m_radioCurrency" );
145
m_radioCurrency->setText( i18n( "Currency" ) );
146
m_formatBoxLayout->addMultiCellWidget( m_radioCurrency, 0, 0, 1, 2 );
148
m_radioDate = new QRadioButton( m_formatBox, "m_radioDate" );
149
m_radioDate->setText( i18n( "Date" ) );
150
m_formatBoxLayout->addWidget( m_radioDate, 1, 2 );
152
m_comboLine = new QComboBox( FALSE, page, "m_comboLine" );
153
m_comboLine->insertItem( i18n( "1" ) );
154
m_comboLine->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)0, 0, 0, m_comboLine->sizePolicy().hasHeightForWidth() ) );
156
MyDialogLayout->addWidget( m_comboLine, 1, 3 );
158
m_comboQuote = new QComboBox( FALSE, page, "m_comboQuote" );
159
m_comboQuote->insertItem( i18n( "\"" ) );
160
m_comboQuote->insertItem( i18n( "'" ) );
161
m_comboQuote->insertItem( i18n( "None" ) );
162
m_comboQuote->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)0, 0, 0, m_comboQuote->sizePolicy().hasHeightForWidth() ) );
164
MyDialogLayout->addWidget( m_comboQuote, 1, 2 );
165
QSpacerItem* spacer_2 = new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Preferred );
166
MyDialogLayout->addItem( spacer_2, 2, 3 );
168
TextLabel3 = new QLabel( page, "TextLabel3" );
169
TextLabel3->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)0, 0, 0, TextLabel3->sizePolicy().hasHeightForWidth() ) );
170
TextLabel3->setText( i18n( "Start at line:" ) );
172
MyDialogLayout->addWidget( TextLabel3, 0, 3 );
174
TextLabel2 = new QLabel( page, "TextLabel2" );
175
TextLabel2->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)0, 0, 0, TextLabel2->sizePolicy().hasHeightForWidth() ) );
176
TextLabel2->setText( i18n( "Textquote:" ) );
178
MyDialogLayout->addWidget( TextLabel2, 0, 2 );
180
if ( m_mode == Clipboard )
182
setCaption( i18n( "Inserting From Clipboard" ) );
183
QMimeSource * mime = QApplication::clipboard()->data();
186
KMessageBox::information( this, i18n("There is no data in the clipboard.") );
191
if ( !mime->provides( "text/plain" ) )
193
KMessageBox::information( this, i18n("There is no usable data in the clipboard.") );
197
m_fileArray = QByteArray(mime->encodedData( "text/plain" ) );
199
else if ( mode == File )
201
setCaption( i18n( "Inserting Text File" ) );
202
QString file = KFileDialog::getOpenFileName(":",
206
if ( file.isEmpty() )
208
actionButton( Ok )->setEnabled( false );
213
if (!in.open(IO_ReadOnly))
215
KMessageBox::sorry( this, i18n("Cannot open input file!") );
217
actionButton( Ok )->setEnabled( false );
221
m_fileArray = QByteArray(in.size());
222
in.readBlock(m_fileArray.data(), in.size());
227
setCaption( i18n( "Text to Columns" ) );
230
KSpreadSheet * table = m_pView->activeTable();
231
int col = m_targetRect.left();
232
for (int i = m_targetRect.top(); i <= m_targetRect.bottom(); ++i)
234
cell = table->cellAt( col, i );
235
if ( !cell->isEmpty() && !cell->isDefault() )
237
m_data += cell->strOutText();
248
m_table->setSelectionMode(QTable::NoSelection);
250
connect(m_formatBox, SIGNAL(clicked(int)),
251
this, SLOT(formatClicked(int)));
252
connect(m_delimiterBox, SIGNAL(clicked(int)),
253
this, SLOT(delimiterClicked(int)));
254
connect(m_delimiterEdit, SIGNAL(returnPressed()),
255
this, SLOT(returnPressed()));
256
connect(m_delimiterEdit, SIGNAL(textChanged ( const QString & )),
257
this, SLOT(textChanged ( const QString & ) ));
258
connect(m_comboLine, SIGNAL(activated(const QString&)),
259
this, SLOT(lineSelected(const QString&)));
260
connect(m_comboQuote, SIGNAL(activated(const QString&)),
261
this, SLOT(textquoteSelected(const QString&)));
262
connect(m_table, SIGNAL(currentChanged(int, int)),
263
this, SLOT(currentCellChanged(int, int)));
264
connect(m_ignoreDuplicates, SIGNAL(stateChanged(int)),
265
this, SLOT(ignoreDuplicatesChanged(int)));
268
KSpreadCSVDialog::~KSpreadCSVDialog()
270
// no need to delete child widgets, Qt does it all for us
273
bool KSpreadCSVDialog::cancelled()
278
void KSpreadCSVDialog::fillTable()
281
bool lastCharDelimiter = false;
282
bool ignoreDups = m_ignoreDuplicates->isChecked();
283
enum { S_START, S_QUOTED_FIELD, S_MAYBE_END_OF_QUOTED_FIELD, S_END_OF_QUOTED_FIELD,
284
S_MAYBE_NORMAL_FIELD, S_NORMAL_FIELD } state = S_START;
289
for (row = 0; row < m_table->numRows(); ++row)
290
for (column = 0; column < m_table->numCols(); ++column)
291
m_table->clearCell(row, column);
294
if (m_mode != Column)
297
m_data = QString(m_fileArray);
298
m_fileArray.resize(0);
301
QTextStream inputStream(m_data, IO_ReadOnly);
302
inputStream.setEncoding(QTextStream::Locale);
304
while (!inputStream.atEnd())
306
inputStream >> x; // read one char
308
if (x == '\r') inputStream >> x; // eat '\r', to handle DOS/LOSEDOWS files correctly
313
if (x == m_textquote)
315
state = S_QUOTED_FIELD;
317
else if (x == m_delimiter)
319
if ((ignoreDups == false) || (lastCharDelimiter == false))
321
lastCharDelimiter = true;
331
state = S_MAYBE_NORMAL_FIELD;
334
case S_QUOTED_FIELD :
335
if (x == m_textquote)
337
state = S_MAYBE_END_OF_QUOTED_FIELD;
341
setText(row - m_startline, column, field);
350
if ((ignoreDups == false) || (lastCharDelimiter == false))
352
lastCharDelimiter = true;
361
case S_MAYBE_END_OF_QUOTED_FIELD :
362
if (x == m_textquote)
365
state = S_QUOTED_FIELD;
367
else if (x == m_delimiter || x == '\n')
369
setText(row - m_startline, column, field);
378
if ((ignoreDups == false) || (lastCharDelimiter == false))
380
lastCharDelimiter = true;
386
state = S_END_OF_QUOTED_FIELD;
389
case S_END_OF_QUOTED_FIELD :
390
if (x == m_delimiter || x == '\n')
392
setText(row - m_startline, column, field);
401
if ((ignoreDups == false) || (lastCharDelimiter == false))
403
lastCharDelimiter = true;
409
state = S_END_OF_QUOTED_FIELD;
412
case S_MAYBE_NORMAL_FIELD :
413
if (x == m_textquote)
416
state = S_QUOTED_FIELD;
419
case S_NORMAL_FIELD :
420
if (x == m_delimiter || x == '\n')
422
setText(row - m_startline, column, field);
431
if ((ignoreDups == false) || (lastCharDelimiter == false))
433
lastCharDelimiter = true;
442
if (x != m_delimiter)
443
lastCharDelimiter = false;
446
// file with only one line without '\n'
447
if (field.length() > 0)
449
setText(row - m_startline, column, field);
454
adjustRows( row - m_startline );
456
for (column = 0; column < m_table->numCols(); ++column)
458
QString header = m_table->horizontalHeader()->label(column);
459
if (header != i18n("Text") && header != i18n("Number") &&
460
header != i18n("Date") && header != i18n("Currency"))
461
m_table->horizontalHeader()->setLabel(column, i18n("Text"));
463
m_table->adjustColumn(column);
467
void KSpreadCSVDialog::fillComboBox()
469
m_comboLine->clear();
470
for (int row = 0; row < m_table->numRows(); ++row)
471
m_comboLine->insertItem(QString::number(row + 1), row);
474
void KSpreadCSVDialog::setText(int row, int col, const QString& text)
476
if (row < 1) // skipped by the user
479
if (m_table->numRows() < row) {
480
m_table->setNumRows(row+5000); /* We add 5000 at a time to limit recalculations */
484
if (m_table->numCols() < col)
485
m_table->setNumCols(col);
487
m_table->setText(row - 1, col - 1, text);
491
* Called after the first fillTable() when number of rows are unknown.
493
void KSpreadCSVDialog::adjustRows(int iRows)
497
m_table->setNumRows( iRows );
502
void KSpreadCSVDialog::returnPressed()
504
if (m_delimiterBox->id(m_delimiterBox->selected()) != 4)
507
m_delimiter = m_delimiterEdit->text();
511
void KSpreadCSVDialog::textChanged ( const QString & )
513
m_radioOther->setChecked ( true );
514
delimiterClicked(4); // other
517
void KSpreadCSVDialog::formatClicked(int id)
524
header = i18n("Text");
527
header = i18n("Number");
530
header = i18n("Date");
533
header = i18n("Currency");
537
m_table->horizontalHeader()->setLabel(m_table->currentColumn(), header);
540
void KSpreadCSVDialog::delimiterClicked(int id)
548
m_delimiter = m_delimiterEdit->text();
564
void KSpreadCSVDialog::textquoteSelected(const QString& mark)
566
if (mark == i18n("none"))
569
m_textquote = mark[0];
574
void KSpreadCSVDialog::lineSelected(const QString& line)
576
m_startline = line.toInt() - 1;
580
void KSpreadCSVDialog::currentCellChanged(int, int col)
583
QString header = m_table->horizontalHeader()->label(col);
585
if (header == i18n("Text"))
587
else if (header == i18n("Number"))
589
else if (header == i18n("Date"))
594
m_formatBox->setButton(id);
597
void KSpreadCSVDialog::accept()
599
KSpreadSheet * table = m_pView->activeTable();
600
QString csv_delimiter = QString::null;
603
int numRows = m_table->numRows();
604
int numCols = m_table->numCols();
609
if ( (numCols > m_targetRect.width()) && (m_targetRect.width() > 1) )
611
numCols = m_targetRect.width();
614
m_targetRect.setRight( m_targetRect.left() + numCols );
616
if ( (numRows > m_targetRect.height()) && (m_targetRect.height() > 1) )
617
numRows = m_targetRect.height();
619
m_targetRect.setBottom( m_targetRect.top() + numRows );
621
if ( numRows == 1 && numCols == 1)
623
KSpreadDoc * doc = m_pView->doc();
624
cell = table->nonDefaultCell( m_targetRect.left(), m_targetRect.top() );
625
if ( !doc->undoBuffer()->isLocked() )
627
KSpreadUndoSetText * undo = new KSpreadUndoSetText( doc, table , cell->text(), m_targetRect.left(),
628
m_targetRect.top(), cell->formatType() );
629
doc->undoBuffer()->appendUndo( undo );
634
KSpreadUndoChangeAreaTextCell * undo = new KSpreadUndoChangeAreaTextCell( m_pView->doc(), table , m_targetRect );
635
m_pView->doc()->undoBuffer()->appendUndo( undo );
638
m_pView->doc()->emitBeginOperation();
641
int left = m_targetRect.left();
642
int top = m_targetRect.top();
644
QMemArray<double> widths( numCols );
645
for ( i = 0; i < numCols; ++i )
647
ColumnFormat * c = table->nonDefaultColumnFormat( left + i );
648
widths[i] = c->dblWidth();
651
for (int row = 0; row < numRows; ++row)
653
for (int col = 0; col < numCols; ++col)
655
cell = table->nonDefaultCell( left + col, top + row );
656
cell->setCellText( getText( row, col ) );
658
QFontMetrics fm = table->painter().fontMetrics();
659
double w = fm.width( cell->strOutText() );
662
QFontMetrics fm( cell->textFont( left + col, top + row ) );
663
w = fm.width('x') * (double) getText( row, col ).length();
666
if ( w > widths[col] )
669
switch (getHeader(col))
674
cell->setFormatType(KSpreadCell::Number);
675
cell->setPrecision(2);
678
cell->setFormatType(KSpreadCell::ShortDate);
681
cell->setFormatType(KSpreadCell::Money);
687
for ( i = 0; i < numCols; ++i )
689
ColumnFormat * c = table->nonDefaultColumnFormat( left + i );
690
c->setDblWidth( widths[i] );
691
table->emit_updateColumn( c, left + i );
694
m_pView->slotUpdateView( table );
698
int KSpreadCSVDialog::getHeader(int col)
700
QString header = m_table->horizontalHeader()->label(col);
702
if (header == i18n("Text"))
704
else if (header == i18n("Number"))
706
else if (header == i18n("Currency"))
712
QString KSpreadCSVDialog::getText(int row, int col)
714
return m_table->text(row, col);
717
void KSpreadCSVDialog::ignoreDuplicatesChanged(int)
722
#include <kspread_dlg_csv.moc>