00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kexicsvexportwizard.h"
00021 #include "kexicsvwidgets.h"
00022 #include <main/startup/KexiStartupFileDialog.h>
00023 #include <kexidb/cursor.h>
00024 #include <kexidb/utils.h>
00025 #include <core/keximainwindow.h>
00026 #include <core/kexiproject.h>
00027 #include <core/kexipartinfo.h>
00028 #include <core/kexipartmanager.h>
00029 #include <core/kexiguimsghandler.h>
00030 #include <kexiutils/utils.h>
00031 #include <widget/kexicharencodingcombobox.h>
00032
00033 #include <qcheckbox.h>
00034 #include <qgroupbox.h>
00035 #include <qclipboard.h>
00036 #include <kapplication.h>
00037 #include <klocale.h>
00038 #include <kiconloader.h>
00039 #include <kactivelabel.h>
00040 #include <kpushbutton.h>
00041 #include <kapplication.h>
00042 #include <kdebug.h>
00043 #include <ksavefile.h>
00044
00045
00046
00047 KexiCSVExportWizard::Options::Options()
00048 : mode(File), itemId(0)
00049 {
00050 }
00051
00052
00053
00054 KexiCSVExportWizard::KexiCSVExportWizard( const Options& options,
00055 KexiMainWindow* mainWin, QWidget * parent, const char * name )
00056 : KWizard(parent, name)
00057 , m_options(options)
00058
00059
00060 , m_mainWin(mainWin)
00061 , m_fileSavePage(0)
00062 , m_defaultsBtn(0)
00063 , m_rowCountDetermined(false)
00064 , m_cancelled(false)
00065 {
00066 if (m_options.mode==Clipboard) {
00067 finishButton()->setText(i18n("Copy"));
00068 backButton()->hide();
00069 }
00070 else {
00071 finishButton()->setText(i18n("Export"));
00072 }
00073 helpButton()->hide();
00074
00075 QString infoLblFromText;
00076 KexiGUIMessageHandler msgh(this);
00077 m_tableOrQuery = new KexiDB::TableOrQuerySchema(
00078 m_mainWin->project()->dbConnection(), m_options.itemId);
00079 if (m_tableOrQuery->table()) {
00080 if (m_options.mode==Clipboard) {
00081 setCaption(i18n("Copy Data From Table to Clipboard"));
00082 infoLblFromText = i18n("Copying data from table:");
00083 }
00084 else {
00085 setCaption(i18n("Export Data From Table to CSV File"));
00086 infoLblFromText = i18n("Exporting data from table:");
00087 }
00088 }
00089 else if (m_tableOrQuery->query()) {
00090 if (m_options.mode==Clipboard) {
00091 setCaption(i18n("Copy Data From Query to Clipboard"));
00092 infoLblFromText = i18n("Copying data from table:");
00093 }
00094 else {
00095 setCaption(i18n("Export Data From Query to CSV File"));
00096 infoLblFromText = i18n("Exporting data from query:");
00097 }
00098 }
00099 else {
00100 msgh.showErrorMessage(m_mainWin->project()->dbConnection(),
00101 i18n("Could not open data for exporting."));
00102 m_cancelled = true;
00103 return;
00104 }
00105
00106
00107
00108
00109
00110 if (m_options.mode==File) {
00111 m_fileSavePage = new KexiStartupFileDialog(
00112 ":CSVImportExport",
00113 KexiStartupFileDialog::Custom | KexiStartupFileDialog::SavingFileBasedDB,
00114 this, "m_fileSavePage");
00115 m_fileSavePage->setMinimumHeight(kapp->desktop()->height()/2);
00116 m_fileSavePage->setAdditionalFilters( csvMimeTypes() );
00117 m_fileSavePage->setDefaultExtension("csv");
00118 m_fileSavePage->setLocationText( KexiUtils::stringToFileName(m_tableOrQuery->captionOrName()) );
00119 connect(m_fileSavePage, SIGNAL(rejected()), this, SLOT(reject()));
00120 addPage(m_fileSavePage, i18n("Enter the Name of the File You Want To Save the Data To"));
00121 }
00122
00123
00124 m_exportOptionsPage = new QWidget(this, "m_exportOptionsPage");
00125 QGridLayout *exportOptionsLyr = new QGridLayout( m_exportOptionsPage, 6, 3,
00126 KDialogBase::marginHint(), KDialogBase::spacingHint(), "exportOptionsLyr");
00127 m_infoLblFrom = new KexiCSVInfoLabel( infoLblFromText, m_exportOptionsPage );
00128 KexiPart::Info *partInfo = Kexi::partManager().infoForMimeType(
00129 m_tableOrQuery->table() ? "kexi/table" : "kexi/query");
00130 if (partInfo)
00131 m_infoLblFrom->setIcon(partInfo->itemIcon());
00132 m_infoLblFrom->separator()->hide();
00133 exportOptionsLyr->addMultiCellWidget(m_infoLblFrom, 0, 0, 0, 2);
00134
00135 m_infoLblTo = new KexiCSVInfoLabel(
00136 (m_options.mode==File) ? i18n("To CSV file:") : i18n("To clipboard:"),
00137 m_exportOptionsPage
00138 );
00139 if (m_options.mode==Clipboard)
00140 m_infoLblTo->setIcon("editpaste");
00141 exportOptionsLyr->addMultiCellWidget(m_infoLblTo, 1, 1, 0, 2);
00142
00143 m_showOptionsButton = new KPushButton(KGuiItem(i18n("Show Options >>"), "configure"),
00144 m_exportOptionsPage);
00145 connect(m_showOptionsButton, SIGNAL(clicked()), this, SLOT(slotShowOptionsButtonClicked()));
00146 exportOptionsLyr->addMultiCellWidget(m_showOptionsButton, 2, 2, 0, 0);
00147 m_showOptionsButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00148
00149
00150 m_exportOptionsSection = new QGroupBox(1, Vertical, i18n("Options"), m_exportOptionsPage,
00151 "m_exportOptionsSection");
00152 m_exportOptionsSection->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00153 exportOptionsLyr->addMultiCellWidget(m_exportOptionsSection, 3, 3, 0, 1);
00154 QWidget *exportOptionsSectionWidget
00155 = new QWidget(m_exportOptionsSection, "exportOptionsSectionWidget");
00156 QGridLayout *exportOptionsSectionLyr = new QGridLayout( exportOptionsSectionWidget, 5, 2,
00157 0, KDialogBase::spacingHint(), "exportOptionsLyr");
00158
00159
00160 m_delimiterWidget = new KexiCSVDelimiterWidget(false,
00161 exportOptionsSectionWidget);
00162 m_delimiterWidget->setDelimiter(defaultDelimiter());
00163 exportOptionsSectionLyr->addWidget( m_delimiterWidget, 0, 1 );
00164 QLabel *delimiterLabel = new QLabel(m_delimiterWidget, i18n("Delimiter:"), exportOptionsSectionWidget);
00165 exportOptionsSectionLyr->addWidget( delimiterLabel, 0, 0 );
00166
00167
00168 QWidget *textQuoteWidget = new QWidget(exportOptionsSectionWidget);
00169 QHBoxLayout *textQuoteLyr = new QHBoxLayout(textQuoteWidget);
00170 exportOptionsSectionLyr->addWidget(textQuoteWidget, 1, 1);
00171 m_textQuote = new KexiCSVTextQuoteComboBox( textQuoteWidget );
00172 m_textQuote->setTextQuote(defaultTextQuote());
00173 textQuoteLyr->addWidget( m_textQuote );
00174 textQuoteLyr->addStretch(0);
00175 QLabel *textQuoteLabel = new QLabel(m_textQuote, i18n("Text quote:"), exportOptionsSectionWidget);
00176 exportOptionsSectionLyr->addWidget( textQuoteLabel, 1, 0 );
00177
00178
00179 m_characterEncodingCombo = new KexiCharacterEncodingComboBox( exportOptionsSectionWidget );
00180 m_characterEncodingCombo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00181 exportOptionsSectionLyr->addWidget( m_characterEncodingCombo, 2, 1 );
00182 QLabel *characterEncodingLabel = new QLabel(m_characterEncodingCombo, i18n("Text encoding:"),
00183 exportOptionsSectionWidget);
00184 exportOptionsSectionLyr->addWidget( characterEncodingLabel, 2, 0 );
00185
00186
00187 m_addColumnNamesCheckBox = new QCheckBox(i18n("Add column names as the first row"),
00188 exportOptionsSectionWidget);
00189 m_addColumnNamesCheckBox->setChecked(true);
00190 exportOptionsSectionLyr->addWidget( m_addColumnNamesCheckBox, 3, 1 );
00192 m_alwaysUseCheckBox = new QCheckBox(i18n("Always use above options for exporting"),
00193 m_exportOptionsPage);
00194 exportOptionsLyr->addMultiCellWidget(m_alwaysUseCheckBox, 4, 4, 0, 1);
00195
00196 m_exportOptionsSection->hide();
00197 m_alwaysUseCheckBox->hide();
00198
00199
00200
00201 exportOptionsLyr->addMultiCell(
00202 new QSpacerItem( 0, 0, QSizePolicy::Preferred, QSizePolicy::MinimumExpanding), 5, 5, 0, 1 );
00203
00204
00205 addPage(m_exportOptionsPage, m_options.mode==Clipboard ? i18n("Copying") : i18n("Exporting"));
00206 setFinishEnabled(m_exportOptionsPage, true);
00207
00208
00209 kapp->config()->setGroup("ImportExport");
00210 if (m_options.mode!=Clipboard && readBoolEntry("ShowOptionsInCSVExportDialog", false)) {
00211 show();
00212 slotShowOptionsButtonClicked();
00213 }
00214 if (readBoolEntry("StoreOptionsForCSVExportDialog", false)) {
00215
00216 m_alwaysUseCheckBox->setChecked(true);
00217 QString s = readEntry("DefaultDelimiterForExportingCSVFiles", defaultDelimiter());
00218 if (!s.isEmpty())
00219 m_delimiterWidget->setDelimiter(s);
00220 s = readEntry("DefaultTextQuoteForExportingCSVFiles", defaultTextQuote());
00221 m_textQuote->setTextQuote(s);
00222 s = readEntry("DefaultEncodingForExportingCSVFiles");
00223 if (!s.isEmpty())
00224 m_characterEncodingCombo->setSelectedEncoding(s);
00225 m_addColumnNamesCheckBox->setChecked(
00226 readBoolEntry("AddColumnNamesForExportingCSVFiles", true) );
00227 }
00228
00229 updateGeometry();
00230
00231
00232 int width = QMAX( m_infoLblFrom->leftLabel()->sizeHint().width(),
00233 m_infoLblTo->leftLabel()->sizeHint().width());
00234 m_infoLblFrom->leftLabel()->setFixedWidth(width);
00235 m_infoLblTo->leftLabel()->setFixedWidth(width);
00236 }
00237
00238 KexiCSVExportWizard::~KexiCSVExportWizard()
00239 {
00240 delete m_tableOrQuery;
00241 }
00242
00243 bool KexiCSVExportWizard::cancelled() const
00244 {
00245 return m_cancelled;
00246 }
00247
00248 void KexiCSVExportWizard::showPage ( QWidget * page )
00249 {
00250 if (page == m_fileSavePage) {
00251 m_fileSavePage->setFocus();
00252 }
00253 else if (page==m_exportOptionsPage) {
00254 if (m_options.mode==File)
00255 m_infoLblTo->setFileName( m_fileSavePage->currentFileName() );
00256 QString text = m_tableOrQuery->captionOrName();
00257 if (!m_rowCountDetermined) {
00258
00259 m_rowCount = KexiDB::rowCount(*m_tableOrQuery);
00260 m_rowCountDetermined = true;
00261 }
00262 int columns = KexiDB::fieldCount(*m_tableOrQuery);
00263 text += "\n";
00264 if (m_rowCount>0)
00265 text += i18n("(rows: %1, columns: %2)").arg(m_rowCount).arg(columns);
00266 else
00267 text += i18n("(columns: %1)").arg(columns);
00268 m_infoLblFrom->setLabelText(text);
00269 m_infoLblFrom->fileNameLabel()->setFixedHeight(
00270 QFontMetrics(m_infoLblFrom->fileNameLabel()->font()).height() * 2 );
00271 if (m_defaultsBtn)
00272 m_defaultsBtn->show();
00273 }
00274
00275 if (page!=m_exportOptionsPage) {
00276 if (m_defaultsBtn)
00277 m_defaultsBtn->hide();
00278 }
00279
00280 KWizard::showPage(page);
00281 }
00282
00283 void KexiCSVExportWizard::next()
00284 {
00285 if (currentPage() == m_fileSavePage) {
00286 if (!m_fileSavePage->checkFileName())
00287 return;
00288 KWizard::next();
00289 finishButton()->setFocus();
00290 return;
00291 }
00292 KWizard::next();
00293 }
00294
00295 void KexiCSVExportWizard::done(int result)
00296 {
00297 if (QDialog::Accepted == result) {
00298
00299 if (!exportData())
00300 return;
00301 }
00302 else if (QDialog::Rejected == result) {
00303
00304 }
00305
00306
00307 kapp->config()->setGroup("ImportExport");
00308 if (m_options.mode!=Clipboard)
00309 writeEntry("ShowOptionsInCSVExportDialog", m_exportOptionsSection->isVisible());
00310 const bool store = m_alwaysUseCheckBox->isChecked();
00311 writeEntry("StoreOptionsForCSVExportDialog", store);
00312
00313
00314 if (store && m_delimiterWidget->delimiter()!=defaultDelimiter())
00315 writeEntry("DefaultDelimiterForExportingCSVFiles", m_delimiterWidget->delimiter());
00316 else
00317 deleteEntry("DefaultDelimiterForExportingCSVFiles");
00318 if (store && m_textQuote->textQuote()!=defaultTextQuote())
00319 writeEntry("DefaultTextQuoteForExportingCSVFiles", m_textQuote->textQuote());
00320 else
00321 deleteEntry("DefaultTextQuoteForExportingCSVFiles");
00322 if (store && !m_characterEncodingCombo->defaultEncodingSelected())
00323 writeEntry("DefaultEncodingForExportingCSVFiles", m_characterEncodingCombo->selectedEncoding());
00324 else
00325 deleteEntry("DefaultEncodingForExportingCSVFiles");
00326 if (store && !m_addColumnNamesCheckBox->isChecked())
00327 writeEntry("AddColumnNamesForExportingCSVFiles", m_addColumnNamesCheckBox->isChecked());
00328 else
00329 deleteEntry("AddColumnNamesForExportingCSVFiles");
00330
00331 KWizard::done(result);
00332 }
00333
00334 void KexiCSVExportWizard::slotShowOptionsButtonClicked()
00335 {
00336 if (m_exportOptionsSection->isVisible()) {
00337 m_showOptionsButton->setText(i18n("Show Options >>"));
00338 m_exportOptionsSection->hide();
00339 m_alwaysUseCheckBox->hide();
00340 if (m_defaultsBtn)
00341 m_defaultsBtn->hide();
00342 }
00343 else {
00344 m_showOptionsButton->setText(i18n("Hide Options <<"));
00345 m_exportOptionsSection->show();
00346 m_alwaysUseCheckBox->show();
00347 if (m_defaultsBtn)
00348 m_defaultsBtn->show();
00349 }
00350 }
00351
00352 void KexiCSVExportWizard::layOutButtonRow( QHBoxLayout * layout )
00353 {
00354 QWizard::layOutButtonRow( layout );
00355
00356
00357 QLayout *l = 0;
00358 for (QLayoutIterator lit( layout->iterator() ); lit.current(); ++lit)
00359 l = lit.current()->layout();
00360 if (dynamic_cast<QBoxLayout*>(l)) {
00361 if (!m_defaultsBtn) {
00362 m_defaultsBtn = new KPushButton(i18n("Defaults"), this);
00363 QWidget::setTabOrder(backButton(), m_defaultsBtn);
00364 connect(m_defaultsBtn, SIGNAL(clicked()), this, SLOT(slotDefaultsButtonClicked()));
00365 }
00366 if (!m_exportOptionsSection->isVisible())
00367 m_defaultsBtn->hide();
00368 dynamic_cast<QBoxLayout*>(l)->insertWidget(0, m_defaultsBtn);
00369 }
00370 }
00371
00372 void KexiCSVExportWizard::slotDefaultsButtonClicked()
00373 {
00374 m_delimiterWidget->setDelimiter(defaultDelimiter());
00375 m_textQuote->setTextQuote(defaultTextQuote());
00376 m_addColumnNamesCheckBox->setChecked(true);
00377 m_characterEncodingCombo->selectDefaultEncoding();
00378 }
00379
00380 bool KexiCSVExportWizard::exportData()
00381 {
00382 KexiDB::Connection *conn = m_mainWin->project()->dbConnection();
00383
00388
00391
00392 KexiDB::QuerySchema* query = m_tableOrQuery->query();
00393 if (!query)
00394 query = m_tableOrQuery->table()->query();
00395
00396 KexiDB::QueryColumnInfo::Vector fields( query->fieldsExpanded() );
00397 QString buffer;
00398
00399 KSaveFile *kSaveFile = 0;
00400 QTextStream *stream = 0;
00401
00402 const bool copyToClipboard = m_options.mode==Clipboard;
00403 if (copyToClipboard) {
00405 uint bufSize = QMIN((m_rowCount<0 ? 10 : m_rowCount) * fields.count() * 20, 128000);
00406 buffer.reserve( bufSize );
00407 if (buffer.capacity() < bufSize) {
00408 kdWarning() << "KexiCSVExportWizard::exportData() cannot allocate memory for " << bufSize
00409 << " characters" << endl;
00410 return false;
00411 }
00412 }
00413 else {
00414 QString fname( m_fileSavePage->currentFileName() );
00415 if (fname.isEmpty()) {
00416 kdWarning() << "KexiCSVExportWizard::exportData(): fname is empty" << endl;
00417 return false;
00418 }
00419 kSaveFile = new KSaveFile(m_fileSavePage->currentFileName());
00420 if (0 == kSaveFile->status())
00421 stream = kSaveFile->textStream();
00422 if (0 != kSaveFile->status() || !stream) {
00423 kdWarning() << "KexiCSVExportWizard::exportData(): status != 0 or stream == 0" << endl;
00424 delete kSaveFile;
00425 return false;
00426 }
00427 }
00428
00430
00431 #define _ERR \
00432 delete [] isText; \
00433 if (kSaveFile) { kSaveFile->abort(); delete kSaveFile; } \
00434 return false
00435
00436 #define APPEND(what) \
00437 if (copyToClipboard) buffer.append(what); else (*stream) << (what)
00438
00439
00440 #define CSV_EOLN "\r\n"
00441
00442
00443 const uint fieldsCount = fields.count();
00444 const QCString delimiter( m_delimiterWidget->delimiter().left(1).latin1() );
00445 const bool hasTextQuote = !m_textQuote->textQuote().isEmpty();
00446 const QCString textQuote( m_textQuote->textQuote().left(1).latin1() );
00447 const QCString escapedTextQuote( textQuote + textQuote );
00448
00449 bool *isText = new bool[fieldsCount];
00450 bool *isDateTime = new bool[fieldsCount];
00451
00452
00453 for (uint i=0; i<fieldsCount; i++) {
00454 isText[i] = fields[i]->field->isTextType();
00455 isDateTime[i] = fields[i]->field->type()==KexiDB::Field::DateTime;
00456
00457
00458
00459 }
00460
00461
00462 if (m_addColumnNamesCheckBox->isChecked()) {
00463 for (uint i=0; i<fieldsCount; i++) {
00464 if (i>0)
00465 APPEND( delimiter );
00466 if (hasTextQuote){
00467 APPEND( textQuote );
00468 APPEND( fields[i]->captionOrAliasOrName().replace(textQuote, escapedTextQuote) );
00469 APPEND( textQuote );
00470 }
00471 else {
00472 APPEND( fields[i]->captionOrAliasOrName() );
00473 }
00474 }
00475 APPEND(CSV_EOLN);
00476 }
00477
00478 KexiGUIMessageHandler handler;
00479 KexiDB::Cursor *cursor = conn->executeQuery(*query);
00480 if (!cursor) {
00481 handler.showErrorMessage(conn);
00482 _ERR;
00483 }
00484 for (cursor->moveFirst(); !cursor->eof() && !cursor->error(); cursor->moveNext()) {
00485 const uint realFieldCount = QMIN(cursor->fieldCount(), fieldsCount);
00486 for (uint i=0; i<realFieldCount; i++) {
00487 if (i>0)
00488 APPEND( delimiter );
00489 if (cursor->value(i).isNull())
00490 continue;
00491 if (hasTextQuote && isText[i]) {
00492 APPEND( textQuote );
00493 APPEND( QString(cursor->value(i).toString()).replace(textQuote, escapedTextQuote) );
00494 APPEND( textQuote );
00495 }
00496 else if (isDateTime[i]) {
00497 APPEND( cursor->value(i).toDateTime().date().toString(Qt::ISODate)+" "
00498 + cursor->value(i).toDateTime().time().toString(Qt::ISODate) );
00499 }
00500 else {
00501 APPEND( cursor->value(i).toString() );
00502 }
00503 }
00504 APPEND(CSV_EOLN);
00505 }
00506
00507 if (copyToClipboard)
00508 buffer.squeeze();
00509
00510 if (!conn->deleteCursor(cursor)) {
00511 handler.showErrorMessage(conn);
00512 _ERR;
00513 }
00514
00515 if (copyToClipboard)
00516 kapp->clipboard()->setText(buffer, QClipboard::Clipboard);
00517
00518 delete [] isText;
00519
00520 if (kSaveFile) {
00521 if (!kSaveFile->close()) {
00522 kdWarning() << "KexiCSVExportWizard::exportData(): error close(); status == "
00523 << kSaveFile->status() << endl;
00524 }
00525 delete kSaveFile;
00526 }
00527 return true;
00528 }
00529
00530 static QString convertKey(const char *key, KexiCSVExportWizard::Mode mode)
00531 {
00532 QString _key(QString::fromLatin1(key));
00533 if (mode == KexiCSVExportWizard::Clipboard) {
00534 _key.replace("Exporting", "Copying");
00535 _key.replace("Export", "Copy");
00536 _key.replace("CSVFiles", "CSVToClipboard");
00537 }
00538 return _key;
00539 }
00540
00541 bool KexiCSVExportWizard::readBoolEntry(const char *key, bool defaultValue)
00542 {
00543 return kapp->config()->readBoolEntry(convertKey(key, m_options.mode), defaultValue);
00544 }
00545
00546 QString KexiCSVExportWizard::readEntry(const char *key, const QString& defaultValue)
00547 {
00548 return kapp->config()->readEntry(convertKey(key, m_options.mode), defaultValue);
00549 }
00550
00551 void KexiCSVExportWizard::writeEntry(const char *key, const QString& value)
00552 {
00553 kapp->config()->writeEntry(convertKey(key, m_options.mode), value);
00554 }
00555
00556 void KexiCSVExportWizard::writeEntry(const char *key, bool value)
00557 {
00558 kapp->config()->writeEntry(convertKey(key, m_options.mode), value);
00559 }
00560
00561 void KexiCSVExportWizard::deleteEntry(const char *key)
00562 {
00563 kapp->config()->deleteEntry(convertKey(key, m_options.mode));
00564 }
00565
00566 QString KexiCSVExportWizard::defaultDelimiter() const
00567 {
00568 if (m_options.mode==Clipboard) {
00569 if (!m_options.forceDelimiter.isEmpty())
00570 return m_options.forceDelimiter;
00571 else
00572 return KEXICSV_DEFAULT_CLIPBOARD_DELIMITER;
00573 }
00574 return KEXICSV_DEFAULT_FILE_DELIMITER;
00575 }
00576
00577 QString KexiCSVExportWizard::defaultTextQuote() const
00578 {
00579 if (m_options.mode==Clipboard)
00580 return QString::null;
00581 return KEXICSV_DEFAULT_TEXT_QUOTE;
00582 }
00583
00584 #include "kexicsvexportwizard.moc"