summaryrefslogtreecommitdiffstats
path: root/kexi/plugins/importexport
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/plugins/importexport
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/plugins/importexport')
-rw-r--r--kexi/plugins/importexport/Makefile.am1
-rw-r--r--kexi/plugins/importexport/csv/Makefile.am21
-rw-r--r--kexi/plugins/importexport/csv/kexicsv_importexporthandler.desktop51
-rw-r--r--kexi/plugins/importexport/csv/kexicsv_importexportpart.cpp87
-rw-r--r--kexi/plugins/importexport/csv/kexicsv_importexportpart.h44
-rw-r--r--kexi/plugins/importexport/csv/kexicsvexport.cpp271
-rw-r--r--kexi/plugins/importexport/csv/kexicsvexport.h58
-rw-r--r--kexi/plugins/importexport/csv/kexicsvexportwizard.cpp431
-rw-r--r--kexi/plugins/importexport/csv/kexicsvexportwizard.h113
-rw-r--r--kexi/plugins/importexport/csv/kexicsvimportdialog.cpp1662
-rw-r--r--kexi/plugins/importexport/csv/kexicsvimportdialog.h231
-rw-r--r--kexi/plugins/importexport/csv/kexicsvimportoptionsdlg.cpp140
-rw-r--r--kexi/plugins/importexport/csv/kexicsvimportoptionsdlg.h62
-rw-r--r--kexi/plugins/importexport/csv/kexicsvwidgets.cpp233
-rw-r--r--kexi/plugins/importexport/csv/kexicsvwidgets.h116
15 files changed, 3521 insertions, 0 deletions
diff --git a/kexi/plugins/importexport/Makefile.am b/kexi/plugins/importexport/Makefile.am
new file mode 100644
index 00000000..02d8b733
--- /dev/null
+++ b/kexi/plugins/importexport/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = csv
diff --git a/kexi/plugins/importexport/csv/Makefile.am b/kexi/plugins/importexport/csv/Makefile.am
new file mode 100644
index 00000000..7ad16495
--- /dev/null
+++ b/kexi/plugins/importexport/csv/Makefile.am
@@ -0,0 +1,21 @@
+include $(top_srcdir)/kexi/Makefile.global
+
+kde_module_LTLIBRARIES = kexihandler_csv_importexport.la
+
+kexihandler_csv_importexport_la_SOURCES = kexicsv_importexportpart.cpp kexicsvimportdialog.cpp \
+ kexicsvimportoptionsdlg.cpp kexicsvwidgets.cpp kexicsvexport.cpp kexicsvexportwizard.cpp
+
+kexihandler_csv_importexport_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) $(VER_INFO) -module
+kexihandler_csv_importexport_la_LIBADD = ../../../core/libkexicore.la \
+ ../../../migration/libkeximigrate.la
+
+INCLUDES= -I$(top_srcdir)/kexi/core -I$(top_srcdir)/kexi \
+ -I$(top_srcdir)/kexi/widget -I$(top_srcdir)/kexi/migration \
+ -I$(top_srcdir)/kexi/kexiDB $(all_includes)
+
+METASOURCES = AUTO
+
+servicesdir=$(kde_servicesdir)/kexi
+services_DATA=kexicsv_importexporthandler.desktop
+
+include ../../Makefile.common
diff --git a/kexi/plugins/importexport/csv/kexicsv_importexporthandler.desktop b/kexi/plugins/importexport/csv/kexicsv_importexporthandler.desktop
new file mode 100644
index 00000000..1c2a383a
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsv_importexporthandler.desktop
@@ -0,0 +1,51 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=Kexi/Handler
+
+Name=Kexi CSV Data Import/Export Plugin
+Name[bg]=Приставка за импортиране/експортиране от CSV в Kexi
+Name[ca]=Connector d'importació/Exportació de dades CVS per a Kexi
+Name[da]=Kexi CSV data-import/eksport plugin
+Name[de]=Kexi CSV-Daten Import-/Export-Modul
+Name[el]=Πρόσθετο εισαγωγής/εξαγωγής CSV δεδομένων του Kexi
+Name[eo]=Kexi CSV-datuma import-eksport-kromaĵo
+Name[es]=Complemento de Kexi para importar y exportar datos CSV
+Name[et]=Kexi CSV-andmete impordi/ekspordifilter
+Name[fa]=وصلۀ واردات/صادرات دادۀ Kexi CSV
+Name[fr]=Module d'importation / exportation de données CSV de Kexi
+Name[fy]=Kexi ymport/eksport Plugin foar CSV-gegevens
+Name[gl]=Importación de Datos CSV de Kexi
+Name[he]=תוסף של Kexi ליבוא/יצוא של מידע מסוג CSV
+Name[hu]=Kexi CSV adatimportáló és -exportáló modul
+Name[is]=Kexi CSV gagna inn/útflutnings íforrit
+Name[it]=Importazione ed esportazione di dati CSV di Kexi
+Name[ja]=Kexi CSV データ インポート/エクスポートプラグイン
+Name[km]=កម្មវិធី​ជំនួយ​ក្នុង​ការ​នាំចេញ និង​នាំចូល​ទិន្នន័យ CSV សម្រាប់ Kexi
+Name[lv]=Kexi CSV datu importa/eksporta spraudnis
+Name[nb]=CSV-data import/eksportfilter for Kexi
+Name[nds]=CSV-Datenimport-/exportmoduul för Kexi
+Name[ne]=केक्सी CSV डेटा आयात/निर्यात प्लगइन
+Name[nl]=Kexi import/exportplugin voor CSV-gegevens
+Name[pl]=Wtyczka importu/eksportu danych CSV dla Kexi
+Name[pt]=Importação de Dados CSV do Kexi
+Name[pt_BR]=Plugin de Importação/Exportação de Dados CSV do Kexi
+Name[ru]=Модуль импорта/экспорта CSV (значения через запятую) для Kexi
+Name[se]=Kexi CSV-dáhta sisa-/olggosfievrridan lassemoduvla
+Name[sk]=Modul Kexi pre import a export CSV dát
+Name[sl]=Vstavek za uvoz/izvoz podatkov CVS za Kexi
+Name[sr]=Kexi-јев прикључак за увоз и извоз из CSV-а
+Name[sr@Latn]=Kexi-jev priključak za uvoz i izvoz iz CSV-a
+Name[sv]=Kexi insticksprogram för import/export av CSV-data
+Name[uk]=Втулок імпорту/експорту CSV-даних для Kexi
+Name[uz]=Kexi CSV maʼlumot import/eksport plagini
+Name[uz@cyrillic]=Kexi CSV маълумот импорт/экспорт плагини
+Name[zh_CN]=Kexi CSV 数据导入/导出插件
+Name[zh_TW]=Kexi CSV 資料匯入/匯出外掛程式
+
+X-KDE-Library=kexihandler_csv_importexport
+X-KDE-ParentApp=kexi
+X-Kexi-PartVersion=2
+X-Kexi-TypeName=csv_importexport
+X-Kexi-GroupIcon=csv_importexport
+X-Kexi-ItemIcon=csv_importexport
+X-Kexi-NoObject=true
diff --git a/kexi/plugins/importexport/csv/kexicsv_importexportpart.cpp b/kexi/plugins/importexport/csv/kexicsv_importexportpart.cpp
new file mode 100644
index 00000000..caa8640d
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsv_importexportpart.cpp
@@ -0,0 +1,87 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexicsv_importexportpart.h"
+#include "kexicsvimportdialog.h"
+#include "kexicsvexportwizard.h"
+#include <core/keximainwindow.h>
+#include <core/kexiproject.h>
+#include <kexiutils/utils.h>
+
+#include <kgenericfactory.h>
+
+KexiCSVImportExportPart::KexiCSVImportExportPart(QObject *parent, const char *name, const QStringList &args)
+ : KexiInternalPart(parent, name, args)
+{
+}
+
+KexiCSVImportExportPart::~KexiCSVImportExportPart()
+{
+}
+
+QWidget *KexiCSVImportExportPart::createWidget(const char* widgetClass, KexiMainWindow* mainWin,
+ QWidget *parent, const char *objName, QMap<QString,QString>* args )
+{
+ if (0==qstrcmp(widgetClass, "KexiCSVImportDialog")) {
+ KexiCSVImportDialog::Mode mode = (args && (*args)["sourceType"]=="file")
+ ? KexiCSVImportDialog::File : KexiCSVImportDialog::Clipboard;
+ KexiCSVImportDialog *dlg = new KexiCSVImportDialog( mode, mainWin, parent, objName );
+ m_cancelled = dlg->cancelled();
+ if (m_cancelled) {
+ delete dlg;
+ return 0;
+ }
+ return dlg;
+ }
+ else if (0==qstrcmp(widgetClass, "KexiCSVExportWizard")) {
+ if (!args)
+ return 0;
+ KexiCSVExport::Options options;
+ if (!options.assign( *args ))
+ return 0;
+ KexiCSVExportWizard *dlg = new KexiCSVExportWizard( options, mainWin, parent, objName);
+ m_cancelled = dlg->cancelled();
+ if (m_cancelled) {
+ delete dlg;
+ return 0;
+ }
+ return dlg;
+ }
+ return 0;
+}
+
+bool KexiCSVImportExportPart::executeCommand(KexiMainWindow* mainWin, const char* commandName,
+ QMap<QString,QString>* args)
+{
+ if (0==qstrcmp(commandName, "KexiCSVExport")) {
+ KexiCSVExport::Options options;
+ if (!options.assign( *args ))
+ return false;
+ KexiDB::TableOrQuerySchema tableOrQuery(
+ mainWin->project()->dbConnection(), options.itemId);
+ QTextStream *stream = 0;
+ if (args->contains("textStream"))
+ stream = KexiUtils::stringToPtr<QTextStream>( (*args)["textStream"] );
+ return KexiCSVExport::exportData(tableOrQuery, options, -1, stream);
+ }
+ return false;
+}
+
+K_EXPORT_COMPONENT_FACTORY( kexihandler_csv_importexport,
+ KGenericFactory<KexiCSVImportExportPart>("kexihandler_csv_importexport") )
diff --git a/kexi/plugins/importexport/csv/kexicsv_importexportpart.h b/kexi/plugins/importexport/csv/kexicsv_importexportpart.h
new file mode 100644
index 00000000..8ee8e8cd
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsv_importexportpart.h
@@ -0,0 +1,44 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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.
+*/
+
+#ifndef KEXI_MIGRATION_PART_H
+#define KEXI_MIGRATION_PART_H
+
+#include <core/kexiinternalpart.h>
+#include "kexicsvexportwizard.h"
+
+/*! Internal part for CSV data import/export dialogs. */
+class KexiCSVImportExportPart : public KexiInternalPart
+{
+ public:
+ KexiCSVImportExportPart(QObject *parent, const char *name, const QStringList &args);
+ virtual ~KexiCSVImportExportPart();
+
+ /*! Reimplemented to return wizard object. */
+ virtual QWidget *createWidget(const char* widgetClass, KexiMainWindow* mainWin,
+ QWidget *parent, const char *objName = 0, QMap<QString,QString>* args = 0);
+
+ /*! Reimplemented to execute a command \a commandName (nonvisual). The result are put into the \a args. */
+ virtual bool executeCommand(KexiMainWindow* mainWin, const char* commandName,
+ QMap<QString,QString>* args = 0);
+
+ protected:
+};
+
+#endif
diff --git a/kexi/plugins/importexport/csv/kexicsvexport.cpp b/kexi/plugins/importexport/csv/kexicsvexport.cpp
new file mode 100644
index 00000000..b83f85a7
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvexport.cpp
@@ -0,0 +1,271 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005,2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexicsvexport.h"
+#include "kexicsvwidgets.h"
+#include <main/startup/KexiStartupFileDialog.h>
+#include <kexidb/cursor.h>
+#include <kexidb/utils.h>
+#include <core/keximainwindow.h>
+#include <core/kexiproject.h>
+#include <core/kexipartinfo.h>
+#include <core/kexipartmanager.h>
+#include <core/kexiguimsghandler.h>
+#include <kexiutils/utils.h>
+#include <widget/kexicharencodingcombobox.h>
+
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qclipboard.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kactivelabel.h>
+#include <kpushbutton.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <ksavefile.h>
+
+
+using namespace KexiCSVExport;
+
+Options::Options()
+ : mode(File), itemId(0), addColumnNames(true)
+{
+}
+
+bool Options::assign( QMap<QString,QString>& args )
+{
+ mode = (args["destinationType"]=="file")
+ ? KexiCSVExport::File : KexiCSVExport::Clipboard;
+
+ if (args.contains("delimiter"))
+ delimiter = args["delimiter"];
+ else
+ delimiter = (mode==File) ? KEXICSV_DEFAULT_FILE_DELIMITER : KEXICSV_DEFAULT_CLIPBOARD_DELIMITER;
+
+ if (args.contains("textQuote"))
+ textQuote = args["textQuote"];
+ else
+ textQuote = (mode==File) ? KEXICSV_DEFAULT_FILE_TEXT_QUOTE : KEXICSV_DEFAULT_CLIPBOARD_TEXT_QUOTE;
+
+ bool ok;
+ itemId = args["itemId"].toInt(&ok);
+ if (!ok || itemId<=0)
+ return false;
+ if (args.contains("forceDelimiter"))
+ forceDelimiter = args["forceDelimiter"];
+ if (args.contains("addColumnNames"))
+ addColumnNames = (args["addColumnNames"]=="1");
+ return true;
+}
+
+//------------------------------------
+
+bool KexiCSVExport::exportData(KexiDB::TableOrQuerySchema& tableOrQuery,
+ const Options& options, int rowCount, QTextStream *predefinedTextStream)
+{
+ KexiDB::Connection* conn = tableOrQuery.connection();
+ if (!conn)
+ return false;
+
+ if (rowCount == -1)
+ rowCount = KexiDB::rowCount(tableOrQuery);
+ if (rowCount == -1)
+ return false;
+
+//! @todo move this to non-GUI location so it can be also used via command line
+//! @todo add a "finish" page with a progressbar.
+//! @todo look at rowCount whether the data is really large;
+//! if so: avoid copying to clipboard (or ask user) because of system memory
+
+//! @todo OPTIMIZATION: use fieldsExpanded(true /*UNIQUE*/)
+//! @todo OPTIMIZATION? (avoid multiple data retrieving) look for already fetched data within KexiProject..
+
+ KexiDB::QuerySchema* query = tableOrQuery.query();
+ if (!query)
+ query = tableOrQuery.table()->query();
+
+ KexiDB::QueryColumnInfo::Vector fields( query->fieldsExpanded( KexiDB::QuerySchema::WithInternalFields ) );
+ QString buffer;
+
+ KSaveFile *kSaveFile = 0;
+ QTextStream *stream = 0;
+
+ const bool copyToClipboard = options.mode==Clipboard;
+ if (copyToClipboard) {
+//! @todo (during exporting): enlarge bufSize by factor of 2 when it became too small
+ uint bufSize = QMIN((rowCount<0 ? 10 : rowCount) * fields.count() * 20, 128000);
+ buffer.reserve( bufSize );
+ if (buffer.capacity() < bufSize) {
+ kdWarning() << "KexiCSVExportWizard::exportData() cannot allocate memory for " << bufSize
+ << " characters" << endl;
+ return false;
+ }
+ }
+ else {
+ if (predefinedTextStream) {
+ stream = predefinedTextStream;
+ }
+ else {
+ if (options.fileName.isEmpty()) {//sanity
+ kdWarning() << "KexiCSVExportWizard::exportData(): fname is empty" << endl;
+ return false;
+ }
+ kSaveFile = new KSaveFile(options.fileName);
+ if (0 == kSaveFile->status())
+ stream = kSaveFile->textStream();
+ if (0 != kSaveFile->status() || !stream) {//sanity
+ kdWarning() << "KexiCSVExportWizard::exportData(): status != 0 or stream == 0" << endl;
+ delete kSaveFile;
+ return false;
+ }
+ }
+ }
+
+//! @todo escape strings
+
+#define _ERR \
+ delete [] isText; \
+ if (kSaveFile) { kSaveFile->abort(); delete kSaveFile; } \
+ return false
+
+#define APPEND(what) \
+ if (copyToClipboard) buffer.append(what); else (*stream) << (what)
+
+// line endings should be as in RFC 4180
+#define CSV_EOLN "\r\n"
+
+ // 0. Cache information
+ const uint fieldsCount = query->fieldsExpanded().count(); //real fields count without internals
+ const QCString delimiter( options.delimiter.left(1).latin1() );
+ const bool hasTextQuote = !options.textQuote.isEmpty();
+ const QString textQuote( options.textQuote.left(1) );
+ const QCString escapedTextQuote( (textQuote + textQuote).latin1() ); //ok?
+ //cache for faster checks
+ bool *isText = new bool[fieldsCount];
+ bool *isDateTime = new bool[fieldsCount];
+ bool *isTime = new bool[fieldsCount];
+ bool *isBLOB = new bool[fieldsCount];
+ uint *visibleFieldIndex = new uint[fieldsCount];
+// bool isInteger[fieldsCount]; //cache for faster checks
+// bool isFloatingPoint[fieldsCount]; //cache for faster checks
+ for (uint i=0; i<fieldsCount; i++) {
+ KexiDB::QueryColumnInfo* ci;
+ const int indexForVisibleLookupValue = fields[i]->indexForVisibleLookupValue();
+ if (-1 != indexForVisibleLookupValue) {
+ ci = query->expandedOrInternalField( indexForVisibleLookupValue );
+ visibleFieldIndex[i] = indexForVisibleLookupValue;
+ }
+ else {
+ ci = fields[i];
+ visibleFieldIndex[i] = i;
+ }
+
+ isText[i] = ci->field->isTextType();
+ isDateTime[i] = ci->field->type()==KexiDB::Field::DateTime;
+ isTime[i] = ci->field->type()==KexiDB::Field::Time;
+ isBLOB[i] = ci->field->type()==KexiDB::Field::BLOB;
+// isInteger[i] = fields[i]->field->isIntegerType()
+// || fields[i]->field->type()==KexiDB::Field::Boolean;
+// isFloatingPoint[i] = fields[i]->field->isFPNumericType();
+ }
+
+ // 1. Output column names
+ if (options.addColumnNames) {
+ for (uint i=0; i<fieldsCount; i++) {
+ if (i>0)
+ APPEND( delimiter );
+ if (hasTextQuote){
+ APPEND( textQuote + fields[i]->captionOrAliasOrName().replace(textQuote, escapedTextQuote) + textQuote );
+ }
+ else {
+ APPEND( fields[i]->captionOrAliasOrName() );
+ }
+ }
+ APPEND(CSV_EOLN);
+ }
+
+ KexiGUIMessageHandler handler;
+ KexiDB::Cursor *cursor = conn->executeQuery(*query);
+ if (!cursor) {
+ handler.showErrorMessage(conn);
+ _ERR;
+ }
+ for (cursor->moveFirst(); !cursor->eof() && !cursor->error(); cursor->moveNext()) {
+ const uint realFieldCount = QMIN(cursor->fieldCount(), fieldsCount);
+ for (uint i=0; i<realFieldCount; i++) {
+ const uint real_i = visibleFieldIndex[i];
+ if (i>0)
+ APPEND( delimiter );
+ if (cursor->value(real_i).isNull())
+ continue;
+ if (isText[real_i]) {
+ if (hasTextQuote)
+ APPEND( textQuote + QString(cursor->value(real_i).toString()).replace(textQuote, escapedTextQuote) + textQuote );
+ else
+ APPEND( cursor->value(real_i).toString() );
+ }
+ else if (isDateTime[real_i]) { //avoid "T" in ISO DateTime
+ APPEND( cursor->value(real_i).toDateTime().date().toString(Qt::ISODate)+" "
+ + cursor->value(real_i).toDateTime().time().toString(Qt::ISODate) );
+ }
+ else if (isTime[real_i]) { //time is temporarily stored as null date + time...
+ APPEND( cursor->value(real_i).toTime().toString(Qt::ISODate) );
+ }
+ else if (isBLOB[real_i]) { //BLOB is escaped in a special way
+ if (hasTextQuote)
+//! @todo add options to suppport other types from KexiDB::BLOBEscapingType enum...
+ APPEND( textQuote + KexiDB::escapeBLOB(cursor->value(real_i).toByteArray(), KexiDB::BLOBEscapeHex) + textQuote );
+ else
+ APPEND( KexiDB::escapeBLOB(cursor->value(real_i).toByteArray(), KexiDB::BLOBEscapeHex) );
+ }
+ else {//other types
+ APPEND( cursor->value(real_i).toString() );
+ }
+ }
+ APPEND(CSV_EOLN);
+ }
+
+ if (copyToClipboard)
+ buffer.squeeze();
+
+ if (!conn->deleteCursor(cursor)) {
+ handler.showErrorMessage(conn);
+ _ERR;
+ }
+
+ if (copyToClipboard)
+ kapp->clipboard()->setText(buffer, QClipboard::Clipboard);
+
+ delete [] isText;
+ delete [] isDateTime;
+ delete [] isTime;
+ delete [] isBLOB;
+ delete [] visibleFieldIndex;
+
+ if (kSaveFile) {
+ if (!kSaveFile->close()) {
+ kdWarning() << "KexiCSVExportWizard::exportData(): error close(); status == "
+ << kSaveFile->status() << endl;
+ }
+ delete kSaveFile;
+ }
+ return true;
+}
diff --git a/kexi/plugins/importexport/csv/kexicsvexport.h b/kexi/plugins/importexport/csv/kexicsvexport.h
new file mode 100644
index 00000000..7c8138fe
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvexport.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005,2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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.
+*/
+
+#ifndef KEXI_CSVEXPORT_H
+#define KEXI_CSVEXPORT_H
+
+#include <kexidb/utils.h>
+
+namespace KexiCSVExport
+{
+
+//! Exporting mode: a file or clipboard
+enum Mode { Clipboard, File };
+
+//! Options used in KexiCSVExportWizard contructor.
+class Options {
+ public:
+ Options();
+
+ //! Assigns \a args. \return false on failure.
+ bool assign( QMap<QString,QString>& args );
+
+ Mode mode;
+ int itemId; //!< Table or query ID
+ QString fileName;
+ QString delimiter;
+ QString forceDelimiter; //!< Used for "clipboard" mode
+ QString textQuote;
+ bool addColumnNames : 1;
+};
+
+/*! Exports data. \return false on failure.
+ @param options options for the export
+ @param rowCount row count of the input data or -1 if the row cound has not yet been computed
+ @param predefinedTextStream text stream that should be used instead of writing to a file
+*/
+bool exportData(KexiDB::TableOrQuerySchema& tableOrQuery, const Options& options, int rowCount = -1,
+ QTextStream *predefinedTextStream = 0);
+
+}
+
+#endif
diff --git a/kexi/plugins/importexport/csv/kexicsvexportwizard.cpp b/kexi/plugins/importexport/csv/kexicsvexportwizard.cpp
new file mode 100644
index 00000000..11c0cff0
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvexportwizard.cpp
@@ -0,0 +1,431 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005,2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexicsvexportwizard.h"
+#include "kexicsvwidgets.h"
+#include <main/startup/KexiStartupFileDialog.h>
+#include <kexidb/cursor.h>
+#include <kexidb/utils.h>
+#include <core/keximainwindow.h>
+#include <core/kexiproject.h>
+#include <core/kexipartinfo.h>
+#include <core/kexipartmanager.h>
+#include <core/kexiguimsghandler.h>
+#include <kexiutils/utils.h>
+#include <widget/kexicharencodingcombobox.h>
+
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qclipboard.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kactivelabel.h>
+#include <kpushbutton.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <ksavefile.h>
+
+
+KexiCSVExportWizard::KexiCSVExportWizard( const KexiCSVExport::Options& options,
+ KexiMainWindow* mainWin, QWidget * parent, const char * name )
+ : KWizard(parent, name)
+ , m_options(options)
+// , m_mode(mode)
+// , m_itemId(itemId)
+ , m_mainWin(mainWin)
+ , m_fileSavePage(0)
+ , m_defaultsBtn(0)
+ , m_rowCount(-1)
+ , m_rowCountDetermined(false)
+ , m_cancelled(false)
+{
+ if (m_options.mode==KexiCSVExport::Clipboard) {
+ finishButton()->setText(i18n("Copy"));
+ backButton()->hide();
+ }
+ else {
+ finishButton()->setText(i18n("Export"));
+ }
+ helpButton()->hide();
+
+ QString infoLblFromText;
+ KexiGUIMessageHandler msgh(this);
+ m_tableOrQuery = new KexiDB::TableOrQuerySchema(
+ m_mainWin->project()->dbConnection(), m_options.itemId);
+ if (m_tableOrQuery->table()) {
+ if (m_options.mode==KexiCSVExport::Clipboard) {
+ setCaption(i18n("Copy Data From Table to Clipboard"));
+ infoLblFromText = i18n("Copying data from table:");
+ }
+ else {
+ setCaption(i18n("Export Data From Table to CSV File"));
+ infoLblFromText = i18n("Exporting data from table:");
+ }
+ }
+ else if (m_tableOrQuery->query()) {
+ if (m_options.mode==KexiCSVExport::Clipboard) {
+ setCaption(i18n("Copy Data From Query to Clipboard"));
+ infoLblFromText = i18n("Copying data from table:");
+ }
+ else {
+ setCaption(i18n("Export Data From Query to CSV File"));
+ infoLblFromText = i18n("Exporting data from query:");
+ }
+ }
+ else {
+ msgh.showErrorMessage(m_mainWin->project()->dbConnection(),
+ i18n("Could not open data for exporting."));
+ m_cancelled = true;
+ return;
+ }
+ // OK, source data found.
+
+ // Setup pages
+
+ // 1. File Save Page
+ if (m_options.mode==KexiCSVExport::File) {
+ m_fileSavePage = new KexiStartupFileDialog(
+ ":CSVImportExport", //startDir
+ KexiStartupFileDialog::Custom | KexiStartupFileDialog::SavingFileBasedDB,
+ this, "m_fileSavePage");
+ m_fileSavePage->setMinimumHeight(kapp->desktop()->height()/2);
+ m_fileSavePage->setAdditionalFilters( csvMimeTypes() );
+ m_fileSavePage->setDefaultExtension("csv");
+ m_fileSavePage->setLocationText( KexiUtils::stringToFileName(m_tableOrQuery->captionOrName()) );
+ connect(m_fileSavePage, SIGNAL(rejected()), this, SLOT(reject()));
+ addPage(m_fileSavePage, i18n("Enter Name of File You Want to Save Data To"));
+ }
+
+ // 2. Export options
+ m_exportOptionsPage = new QWidget(this, "m_exportOptionsPage");
+ QGridLayout *exportOptionsLyr = new QGridLayout( m_exportOptionsPage, 6, 3,
+ KDialogBase::marginHint(), KDialogBase::spacingHint(), "exportOptionsLyr");
+ m_infoLblFrom = new KexiCSVInfoLabel( infoLblFromText, m_exportOptionsPage );
+ KexiPart::Info *partInfo = Kexi::partManager().infoForMimeType(
+ m_tableOrQuery->table() ? "kexi/table" : "kexi/query");
+ if (partInfo)
+ m_infoLblFrom->setIcon(partInfo->itemIcon());
+ m_infoLblFrom->separator()->hide();
+ exportOptionsLyr->addMultiCellWidget(m_infoLblFrom, 0, 0, 0, 2);
+
+ m_infoLblTo = new KexiCSVInfoLabel(
+ (m_options.mode==KexiCSVExport::File) ? i18n("To CSV file:") : i18n("To clipboard:"),
+ m_exportOptionsPage
+ );
+ if (m_options.mode==KexiCSVExport::Clipboard)
+ m_infoLblTo->setIcon("editpaste");
+ exportOptionsLyr->addMultiCellWidget(m_infoLblTo, 1, 1, 0, 2);
+
+ m_showOptionsButton = new KPushButton(KGuiItem(i18n("Show Options >>"), "configure"),
+ m_exportOptionsPage);
+ connect(m_showOptionsButton, SIGNAL(clicked()), this, SLOT(slotShowOptionsButtonClicked()));
+ exportOptionsLyr->addMultiCellWidget(m_showOptionsButton, 2, 2, 0, 0);
+ m_showOptionsButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ // -<options section>
+ m_exportOptionsSection = new QGroupBox(1, Vertical, i18n("Options"), m_exportOptionsPage,
+ "m_exportOptionsSection");
+ m_exportOptionsSection->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ exportOptionsLyr->addMultiCellWidget(m_exportOptionsSection, 3, 3, 0, 1);
+ QWidget *exportOptionsSectionWidget
+ = new QWidget(m_exportOptionsSection, "exportOptionsSectionWidget");
+ QGridLayout *exportOptionsSectionLyr = new QGridLayout( exportOptionsSectionWidget, 5, 2,
+ 0, KDialogBase::spacingHint(), "exportOptionsLyr");
+
+ // -delimiter
+ m_delimiterWidget = new KexiCSVDelimiterWidget(false, //!lineEditOnBottom
+ exportOptionsSectionWidget);
+ m_delimiterWidget->setDelimiter(defaultDelimiter());
+ exportOptionsSectionLyr->addWidget( m_delimiterWidget, 0, 1 );
+ QLabel *delimiterLabel = new QLabel(m_delimiterWidget, i18n("Delimiter:"), exportOptionsSectionWidget);
+ exportOptionsSectionLyr->addWidget( delimiterLabel, 0, 0 );
+
+ // -text quote
+ QWidget *textQuoteWidget = new QWidget(exportOptionsSectionWidget);
+ QHBoxLayout *textQuoteLyr = new QHBoxLayout(textQuoteWidget);
+ exportOptionsSectionLyr->addWidget(textQuoteWidget, 1, 1);
+ m_textQuote = new KexiCSVTextQuoteComboBox( textQuoteWidget );
+ m_textQuote->setTextQuote(defaultTextQuote());
+ textQuoteLyr->addWidget( m_textQuote );
+ textQuoteLyr->addStretch(0);
+ QLabel *textQuoteLabel = new QLabel(m_textQuote, i18n("Text quote:"), exportOptionsSectionWidget);
+ exportOptionsSectionLyr->addWidget( textQuoteLabel, 1, 0 );
+
+ // - character encoding
+ m_characterEncodingCombo = new KexiCharacterEncodingComboBox( exportOptionsSectionWidget );
+ m_characterEncodingCombo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ exportOptionsSectionLyr->addWidget( m_characterEncodingCombo, 2, 1 );
+ QLabel *characterEncodingLabel = new QLabel(m_characterEncodingCombo, i18n("Text encoding:"),
+ exportOptionsSectionWidget);
+ exportOptionsSectionLyr->addWidget( characterEncodingLabel, 2, 0 );
+
+ // - checkboxes
+ m_addColumnNamesCheckBox = new QCheckBox(i18n("Add column names as the first row"),
+ exportOptionsSectionWidget);
+ m_addColumnNamesCheckBox->setChecked(true);
+ exportOptionsSectionLyr->addWidget( m_addColumnNamesCheckBox, 3, 1 );
+//! @todo 1.1: for copying use "Always use above options for copying" string
+ m_alwaysUseCheckBox = new QCheckBox(i18n("Always use above options for exporting"),
+ m_exportOptionsPage);
+ exportOptionsLyr->addMultiCellWidget(m_alwaysUseCheckBox, 4, 4, 0, 1);
+// exportOptionsSectionLyr->addWidget( m_alwaysUseCheckBox, 4, 1 );
+ m_exportOptionsSection->hide();
+ m_alwaysUseCheckBox->hide();
+ // -</options section>
+
+// exportOptionsLyr->setColStretch(3, 1);
+ exportOptionsLyr->addMultiCell(
+ new QSpacerItem( 0, 0, QSizePolicy::Preferred, QSizePolicy::MinimumExpanding), 5, 5, 0, 1 );
+
+// addPage(m_exportOptionsPage, i18n("Set Export Options"));
+ addPage(m_exportOptionsPage, m_options.mode==KexiCSVExport::Clipboard ? i18n("Copying") : i18n("Exporting"));
+ setFinishEnabled(m_exportOptionsPage, true);
+
+ // load settings
+ kapp->config()->setGroup("ImportExport");
+ if (m_options.mode!=KexiCSVExport::Clipboard && readBoolEntry("ShowOptionsInCSVExportDialog", false)) {
+ show();
+ slotShowOptionsButtonClicked();
+ }
+ if (readBoolEntry("StoreOptionsForCSVExportDialog", false)) {
+ // load defaults:
+ m_alwaysUseCheckBox->setChecked(true);
+ QString s = readEntry("DefaultDelimiterForExportingCSVFiles", defaultDelimiter());
+ if (!s.isEmpty())
+ m_delimiterWidget->setDelimiter(s);
+ s = readEntry("DefaultTextQuoteForExportingCSVFiles", defaultTextQuote());
+ m_textQuote->setTextQuote(s); //will be invaliudated here, so not a problem
+ s = readEntry("DefaultEncodingForExportingCSVFiles");
+ if (!s.isEmpty())
+ m_characterEncodingCombo->setSelectedEncoding(s);
+ m_addColumnNamesCheckBox->setChecked(
+ readBoolEntry("AddColumnNamesForExportingCSVFiles", true) );
+ }
+
+ updateGeometry();
+
+ // -keep widths equal on page #2:
+ int width = QMAX( m_infoLblFrom->leftLabel()->sizeHint().width(),
+ m_infoLblTo->leftLabel()->sizeHint().width());
+ m_infoLblFrom->leftLabel()->setFixedWidth(width);
+ m_infoLblTo->leftLabel()->setFixedWidth(width);
+}
+
+KexiCSVExportWizard::~KexiCSVExportWizard()
+{
+ delete m_tableOrQuery;
+}
+
+bool KexiCSVExportWizard::cancelled() const
+{
+ return m_cancelled;
+}
+
+void KexiCSVExportWizard::showPage ( QWidget * page )
+{
+ if (page == m_fileSavePage) {
+ m_fileSavePage->setFocus();
+ }
+ else if (page==m_exportOptionsPage) {
+ if (m_options.mode==KexiCSVExport::File)
+ m_infoLblTo->setFileName( m_fileSavePage->currentFileName() );
+ QString text = m_tableOrQuery->captionOrName();
+ if (!m_rowCountDetermined) {
+ //do this costly operation only once
+ m_rowCount = KexiDB::rowCount(*m_tableOrQuery);
+ m_rowCountDetermined = true;
+ }
+ int columns = KexiDB::fieldCount(*m_tableOrQuery);
+ text += "\n";
+ if (m_rowCount>0)
+ text += i18n("(rows: %1, columns: %2)").arg(m_rowCount).arg(columns);
+ else
+ text += i18n("(columns: %1)").arg(columns);
+ m_infoLblFrom->setLabelText(text);
+ QFontMetrics fm(m_infoLblFrom->fileNameLabel()->font());
+ m_infoLblFrom->fileNameLabel()->setFixedHeight( fm.height() * 2 + fm.lineSpacing() );
+ if (m_defaultsBtn)
+ m_defaultsBtn->show();
+ }
+
+ if (page!=m_exportOptionsPage) {
+ if (m_defaultsBtn)
+ m_defaultsBtn->hide();
+ }
+
+ KWizard::showPage(page);
+}
+
+void KexiCSVExportWizard::next()
+{
+ if (currentPage() == m_fileSavePage) {
+ if (!m_fileSavePage->checkFileName())
+ return;
+ KWizard::next();
+ finishButton()->setFocus();
+ return;
+ }
+ KWizard::next();
+}
+
+void KexiCSVExportWizard::done(int result)
+{
+ if (QDialog::Accepted == result) {
+ if (m_fileSavePage)
+ m_options.fileName = m_fileSavePage->currentFileName();
+ m_options.delimiter = m_delimiterWidget->delimiter();
+ m_options.textQuote = m_textQuote->textQuote();
+ m_options.addColumnNames = m_addColumnNamesCheckBox->isChecked();
+ if (!KexiCSVExport::exportData(*m_tableOrQuery, m_options))
+ return;
+ }
+ else if (QDialog::Rejected == result) {
+ //nothing to do
+ }
+
+ //store options
+ kapp->config()->setGroup("ImportExport");
+ if (m_options.mode!=KexiCSVExport::Clipboard)
+ writeEntry("ShowOptionsInCSVExportDialog", m_exportOptionsSection->isVisible());
+ const bool store = m_alwaysUseCheckBox->isChecked();
+ writeEntry("StoreOptionsForCSVExportDialog", store);
+ // only save if an option differs from default
+
+ if (store && m_delimiterWidget->delimiter()!=defaultDelimiter())
+ writeEntry("DefaultDelimiterForExportingCSVFiles", m_delimiterWidget->delimiter());
+ else
+ deleteEntry("DefaultDelimiterForExportingCSVFiles");
+ if (store && m_textQuote->textQuote()!=defaultTextQuote())
+ writeEntry("DefaultTextQuoteForExportingCSVFiles", m_textQuote->textQuote());
+ else
+ deleteEntry("DefaultTextQuoteForExportingCSVFiles");
+ if (store && !m_characterEncodingCombo->defaultEncodingSelected())
+ writeEntry("DefaultEncodingForExportingCSVFiles", m_characterEncodingCombo->selectedEncoding());
+ else
+ deleteEntry("DefaultEncodingForExportingCSVFiles");
+ if (store && !m_addColumnNamesCheckBox->isChecked())
+ writeEntry("AddColumnNamesForExportingCSVFiles", m_addColumnNamesCheckBox->isChecked());
+ else
+ deleteEntry("AddColumnNamesForExportingCSVFiles");
+
+ KWizard::done(result);
+}
+
+void KexiCSVExportWizard::slotShowOptionsButtonClicked()
+{
+ if (m_exportOptionsSection->isVisible()) {
+ m_showOptionsButton->setText(i18n("Show Options >>"));
+ m_exportOptionsSection->hide();
+ m_alwaysUseCheckBox->hide();
+ if (m_defaultsBtn)
+ m_defaultsBtn->hide();
+ }
+ else {
+ m_showOptionsButton->setText(i18n("Hide Options <<"));
+ m_exportOptionsSection->show();
+ m_alwaysUseCheckBox->show();
+ if (m_defaultsBtn)
+ m_defaultsBtn->show();
+ }
+}
+
+void KexiCSVExportWizard::layOutButtonRow( QHBoxLayout * layout )
+{
+ QWizard::layOutButtonRow( layout );
+
+ //find the last sublayout
+ QLayout *l = 0;
+ for (QLayoutIterator lit( layout->iterator() ); lit.current(); ++lit)
+ l = lit.current()->layout();
+ if (dynamic_cast<QBoxLayout*>(l)) {
+ if (!m_defaultsBtn) {
+ m_defaultsBtn = new KPushButton(i18n("Defaults"), this);
+ QWidget::setTabOrder(backButton(), m_defaultsBtn);
+ connect(m_defaultsBtn, SIGNAL(clicked()), this, SLOT(slotDefaultsButtonClicked()));
+ }
+ if (!m_exportOptionsSection->isVisible())
+ m_defaultsBtn->hide();
+ dynamic_cast<QBoxLayout*>(l)->insertWidget(0, m_defaultsBtn);
+ }
+}
+
+void KexiCSVExportWizard::slotDefaultsButtonClicked()
+{
+ m_delimiterWidget->setDelimiter(defaultDelimiter());
+ m_textQuote->setTextQuote(defaultTextQuote());
+ m_addColumnNamesCheckBox->setChecked(true);
+ m_characterEncodingCombo->selectDefaultEncoding();
+}
+
+static QString convertKey(const char *key, KexiCSVExport::Mode mode)
+{
+ QString _key(QString::fromLatin1(key));
+ if (mode == KexiCSVExport::Clipboard) {
+ _key.replace("Exporting", "Copying");
+ _key.replace("Export", "Copy");
+ _key.replace("CSVFiles", "CSVToClipboard");
+ }
+ return _key;
+}
+
+bool KexiCSVExportWizard::readBoolEntry(const char *key, bool defaultValue)
+{
+ return kapp->config()->readBoolEntry(convertKey(key, m_options.mode), defaultValue);
+}
+
+QString KexiCSVExportWizard::readEntry(const char *key, const QString& defaultValue)
+{
+ return kapp->config()->readEntry(convertKey(key, m_options.mode), defaultValue);
+}
+
+void KexiCSVExportWizard::writeEntry(const char *key, const QString& value)
+{
+ kapp->config()->writeEntry(convertKey(key, m_options.mode), value);
+}
+
+void KexiCSVExportWizard::writeEntry(const char *key, bool value)
+{
+ kapp->config()->writeEntry(convertKey(key, m_options.mode), value);
+}
+
+void KexiCSVExportWizard::deleteEntry(const char *key)
+{
+ kapp->config()->deleteEntry(convertKey(key, m_options.mode));
+}
+
+QString KexiCSVExportWizard::defaultDelimiter() const
+{
+ if (m_options.mode==KexiCSVExport::Clipboard) {
+ if (!m_options.forceDelimiter.isEmpty())
+ return m_options.forceDelimiter;
+ else
+ return KEXICSV_DEFAULT_CLIPBOARD_DELIMITER;
+ }
+ return KEXICSV_DEFAULT_FILE_DELIMITER;
+}
+
+QString KexiCSVExportWizard::defaultTextQuote() const
+{
+ if (m_options.mode==KexiCSVExport::Clipboard)
+ return KEXICSV_DEFAULT_CLIPBOARD_TEXT_QUOTE;
+ return KEXICSV_DEFAULT_FILE_TEXT_QUOTE;
+}
+
+#include "kexicsvexportwizard.moc"
diff --git a/kexi/plugins/importexport/csv/kexicsvexportwizard.h b/kexi/plugins/importexport/csv/kexicsvexportwizard.h
new file mode 100644
index 00000000..8fdaecd0
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvexportwizard.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005,2006 Jaroslaw Staniek <js@iidea.pl>
+
+ 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.
+*/
+
+#ifndef KEXI_CSVEXPORTWIZARD_H
+#define KEXI_CSVEXPORTWIZARD_H
+
+#include <kwizard.h>
+
+#include "kexicsvexport.h"
+
+class QCheckBox;
+class QGroupBox;
+class KPushButton;
+class KexiMainWindow;
+class KexiStartupFileDialog;
+class KexiCSVDelimiterWidget;
+class KexiCSVTextQuoteComboBox;
+class KexiCSVInfoLabel;
+class KexiCharacterEncodingComboBox;
+namespace KexiDB {
+ class TableOrQuerySchema;
+}
+
+/*! @short Kexi CSV export wizard
+ Supports exporting to a file and to a clipboard. */
+class KexiCSVExportWizard : public KWizard
+{
+ Q_OBJECT
+
+ public:
+ KexiCSVExportWizard( const KexiCSVExport::Options& options, KexiMainWindow* mainWin,
+ QWidget * parent = 0, const char * name = 0 );
+
+ virtual ~KexiCSVExportWizard();
+
+ bool cancelled() const;
+
+ virtual void showPage ( QWidget * page );
+
+ protected slots:
+ virtual void next();
+ virtual void done(int result);
+ void slotShowOptionsButtonClicked();
+ void slotDefaultsButtonClicked();
+
+ protected:
+ //! reimplemented to add "Defaults" button on the left hand
+ virtual void layOutButtonRow( QHBoxLayout * layout );
+
+ //! \return default delimiter depending on mode.
+ QString defaultDelimiter() const;
+
+ //! \return default text quote depending on mode.
+ QString defaultTextQuote() const;
+
+ //! Helper, works like kapp->config()->readBoolEntry(const char*, bool) but if mode is Clipboard,
+ //! "Exporting" is replaced with "Copying" and "Export" is replaced with "Copy"
+ //! and "CSVFiles" is replaced with "CSVToClipboard"
+ //! in \a key, to keep the setting separate.
+ bool readBoolEntry(const char *key, bool defaultValue);
+
+ //! Helper like \ref readBoolEntry(const char *, bool), but for QString values.
+ QString readEntry(const char *key, const QString& defaultValue = QString::null);
+
+ //! Helper, works like kapp->config()->writeEntry(const char*,bool) but if mode is Clipboard,
+ //! "Exporting" is replaced with "Copying" and "Export" is replaced with "Copy"
+ //! and "CSVFiles" is replaced with "CSVToClipboard"
+ //! in \a key, to keep the setting separate.
+ void writeEntry(const char *key, bool value);
+
+ //! Helper like \ref writeEntry(const char *, bool), but for QString values.
+ void writeEntry(const char *key, const QString& value);
+
+ //! Helper like \ref writeEntry(const char *, bool), but for deleting config entry.
+ void deleteEntry(const char *key);
+
+ KexiCSVExport::Options m_options;
+// Mode m_mode;
+// int m_itemId;
+ KexiMainWindow* m_mainWin;
+ KexiStartupFileDialog* m_fileSavePage;
+ QWidget* m_exportOptionsPage;
+ KPushButton *m_showOptionsButton;
+ KPushButton *m_defaultsBtn;
+ QGroupBox* m_exportOptionsSection;
+ KexiCSVInfoLabel *m_infoLblFrom, *m_infoLblTo;
+ KexiCSVDelimiterWidget* m_delimiterWidget;
+ KexiCSVTextQuoteComboBox* m_textQuote;
+ KexiCharacterEncodingComboBox *m_characterEncodingCombo;
+ QCheckBox* m_addColumnNamesCheckBox, *m_alwaysUseCheckBox;
+ KexiDB::TableOrQuerySchema* m_tableOrQuery;
+ int m_rowCount; //!< Cached row count for a table/query.
+ bool m_rowCountDetermined : 1;
+ bool m_cancelled : 1;
+};
+
+#endif
diff --git a/kexi/plugins/importexport/csv/kexicsvimportdialog.cpp b/kexi/plugins/importexport/csv/kexicsvimportdialog.cpp
new file mode 100644
index 00000000..16a9d416
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvimportdialog.cpp
@@ -0,0 +1,1662 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This work is based on kspread/dialogs/kspread_dlg_csv.cc
+ and will be merged back with KOffice libraries.
+
+ Copyright (C) 2002-2003 Norbert Andres <nandres@web.de>
+ Copyright (C) 2002-2003 Ariya Hidayat <ariya@kde.org>
+ Copyright (C) 2002 Laurent Montel <montel@kde.org>
+ Copyright (C) 1999 David Faure <faure@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 <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qclipboard.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qmime.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qtable.h>
+#include <qlayout.h>
+#include <qfiledialog.h>
+#include <qpainter.h>
+#include <qtextcodec.h>
+#include <qtimer.h>
+#include <qfontmetrics.h>
+#include <qtooltip.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kcharsets.h>
+#include <knuminput.h>
+#include <kprogress.h>
+#include <kactivelabel.h>
+
+#include <kexiutils/identifier.h>
+#include <kexiutils/utils.h>
+#include <core/kexi.h>
+#include <core/kexiproject.h>
+#include <core/kexipart.h>
+#include <core/kexipartinfo.h>
+#include <core/keximainwindow.h>
+#include <core/kexiguimsghandler.h>
+#include <kexidb/connection.h>
+#include <kexidb/tableschema.h>
+#include <kexidb/transaction.h>
+#include <widget/kexicharencodingcombobox.h>
+
+#include "kexicsvimportdialog.h"
+#include "kexicsvwidgets.h"
+
+#ifdef Q_WS_WIN
+#include <krecentdirs.h>
+#include <windows.h>
+#endif
+
+#if 0
+#include <kspread_cell.h>
+#include <kspread_doc.h>
+#include <kspread_sheet.h>
+#include <kspread_undo.h>
+#include <kspread_view.h>
+#endif
+
+#define _IMPORT_ICON "table" /*todo: change to "file_import" or so*/
+#define _TEXT_TYPE 0
+#define _NUMBER_TYPE 1
+#define _DATE_TYPE 2
+#define _TIME_TYPE 3
+#define _DATETIME_TYPE 4
+#define _PK_FLAG 5
+
+//extra:
+#define _NO_TYPE_YET -1 //allows to accept a number of empty cells, before something non-empty
+#define _FP_NUMBER_TYPE 255 //_NUMBER_TYPE variant
+#define MAX_ROWS_TO_PREVIEW 100 //max 100 rows is reasonable
+#define MAX_BYTES_TO_PREVIEW 10240 //max 10KB is reasonable
+#define MAX_CHARS_TO_SCAN_WHILE_DETECTING_DELIMITER 4096
+
+class KexiCSVImportDialogTable : public QTable
+{
+public:
+ KexiCSVImportDialogTable( QWidget * parent = 0, const char * name = 0 )
+ : QTable(parent, name) {
+ f = font();
+ f.setBold(true);
+ }
+ virtual void paintCell( QPainter * p, int row, int col, const QRect & cr, bool selected, const QColorGroup & cg ) {
+ if (row==0)
+ p->setFont(f);
+ else
+ p->setFont(font());
+ QTable::paintCell(p, row, col, cr, selected, cg);
+ }
+ virtual void setColumnWidth( int col, int w ) {
+ //make columns a bit wider
+ QTable::setColumnWidth( col, w + 16 );
+ }
+ QFont f;
+};
+
+//! Helper used to temporary disable keyboard and mouse events
+void installRecursiveEventFilter(QObject *filter, QObject *object)
+{
+ object->installEventFilter(filter);
+
+ if (!object->children())
+ return;
+
+ QObjectList list = *object->children();
+ for(QObject *obj = list.first(); obj; obj = list.next())
+ installRecursiveEventFilter(filter, obj);
+}
+
+KexiCSVImportDialog::KexiCSVImportDialog( Mode mode, KexiMainWindow* mainWin,
+ QWidget * parent, const char * name
+)
+ : KDialogBase(
+ KDialogBase::Plain,
+ i18n( "Import CSV Data File" )
+//! @todo use "Paste CSV Data From Clipboard" caption for mode==Clipboard
+ ,
+ (mode==File ? User1 : (ButtonCode)0) |Ok|Cancel,
+ Ok,
+ parent,
+ name ? name : "KexiCSVImportDialog",
+ true,
+ false,
+ KGuiItem( i18n("&Options"))
+ ),
+ m_mainWin(mainWin),
+ m_cancelled( false ),
+ m_adjustRows( true ),
+ m_startline( 0 ),
+ m_textquote( QString(KEXICSV_DEFAULT_FILE_TEXT_QUOTE)[0] ),
+ m_mode(mode),
+ m_prevSelectedCol(-1),
+ m_columnsAdjusted(false),
+ m_1stRowForFieldNamesDetected(false),
+ m_firstFillTableCall(true),
+ m_blockUserEvents(false),
+ m_primaryKeyColumn(-1),
+ m_dialogCancelled(false),
+ m_conn(0),
+ m_destinationTableSchema(0),
+ m_allRowsLoadedInPreview(false),
+ m_stoppedAt_MAX_BYTES_TO_PREVIEW(false)
+{
+ setWFlags(getWFlags() | Qt::WStyle_Maximize | Qt::WStyle_SysMenu);
+ hide();
+ setButtonOK(KGuiItem( i18n("&Import..."), _IMPORT_ICON));
+
+ m_typeNames.resize(5);
+ m_typeNames[0] = i18n("text");
+ m_typeNames[1] = i18n("number");
+ m_typeNames[2] = i18n("date");
+ m_typeNames[3] = i18n("time");
+ m_typeNames[4] = i18n("date/time");
+
+ kapp->config()->setGroup("ImportExport");
+ m_maximumRowsForPreview = kapp->config()->readNumEntry("MaximumRowsForPreviewInImportDialog", MAX_ROWS_TO_PREVIEW);
+ m_maximumBytesForPreview = kapp->config()->readNumEntry("MaximumBytesForPreviewInImportDialog", MAX_BYTES_TO_PREVIEW);
+
+ m_pkIcon = SmallIcon("key");
+
+ m_uniquenessTest.setAutoDelete(true);
+
+ setIcon(DesktopIcon(_IMPORT_ICON));
+ setSizeGripEnabled( TRUE );
+
+// m_encoding = QString::fromLatin1(KGlobal::locale()->encoding());
+// m_stripWhiteSpaceInTextValuesChecked = true;
+ m_file = 0;
+ m_inputStream = 0;
+
+ QVBoxLayout *lyr = new QVBoxLayout(plainPage(), 0, KDialogBase::spacingHint(), "lyr");
+
+ m_infoLbl = new KexiCSVInfoLabel(
+ m_mode==File ? i18n("Preview of data from file:")
+ : i18n("Preview of data from clipboard:"),
+ plainPage()
+ );
+ lyr->addWidget( m_infoLbl );
+
+ QWidget* page = new QFrame( plainPage(), "page" );
+ QGridLayout *glyr= new QGridLayout( page, 4, 5, 0, KDialogBase::spacingHint(), "glyr");
+ lyr->addWidget( page );
+
+ // Delimiter: comma, semicolon, tab, space, other
+ m_delimiterWidget = new KexiCSVDelimiterWidget(true /*lineEditOnBottom*/, page);
+ m_detectDelimiter = true;
+ glyr->addMultiCellWidget( m_delimiterWidget, 1, 2, 0, 0 );
+
+ QLabel *delimiterLabel = new QLabel(m_delimiterWidget, i18n("Delimiter:"), page);
+ delimiterLabel->setAlignment(Qt::AlignAuto | Qt::AlignBottom);
+ glyr->addMultiCellWidget( delimiterLabel, 0, 0, 0, 0 );
+
+ // Format: number, text, currency,
+ m_formatComboText = i18n( "Format for column %1:" );
+ m_formatCombo = new KComboBox(page, "m_formatCombo");
+ m_formatCombo->insertItem(i18n("Text"));
+ m_formatCombo->insertItem(i18n("Number"));
+ m_formatCombo->insertItem(i18n("Date"));
+ m_formatCombo->insertItem(i18n("Time"));
+ m_formatCombo->insertItem(i18n("Date/Time"));
+ glyr->addMultiCellWidget( m_formatCombo, 1, 1, 1, 1 );
+
+ m_formatLabel = new QLabel(m_formatCombo, "", page);
+ m_formatLabel->setAlignment(Qt::AlignAuto | Qt::AlignBottom);
+ glyr->addWidget( m_formatLabel, 0, 1 );
+
+ m_primaryKeyField = new QCheckBox( i18n( "Primary key" ), page, "m_primaryKeyField" );
+ glyr->addWidget( m_primaryKeyField, 2, 1 );
+ connect(m_primaryKeyField, SIGNAL(toggled(bool)), this, SLOT(slotPrimaryKeyFieldToggled(bool)));
+
+ m_comboQuote = new KexiCSVTextQuoteComboBox( page );
+ glyr->addWidget( m_comboQuote, 1, 2 );
+
+ TextLabel2 = new QLabel( m_comboQuote, i18n( "Text quote:" ), page, "TextLabel2" );
+ TextLabel2->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
+ TextLabel2->setAlignment(Qt::AlignAuto | Qt::AlignBottom);
+ glyr->addWidget( TextLabel2, 0, 2 );
+
+ m_startAtLineSpinBox = new KIntSpinBox( page, "m_startAtLineSpinBox" );
+ m_startAtLineSpinBox->setMinValue(1);
+ m_startAtLineSpinBox->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
+ m_startAtLineSpinBox->setMinimumWidth(QFontMetrics(m_startAtLineSpinBox->font()).width("8888888"));
+ glyr->addWidget( m_startAtLineSpinBox, 1, 3 );
+
+ m_startAtLineLabel = new QLabel( m_startAtLineSpinBox, "",
+ page, "TextLabel3" );
+ m_startAtLineLabel->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
+ m_startAtLineLabel->setAlignment(Qt::AlignAuto | Qt::AlignBottom);
+ glyr->addWidget( m_startAtLineLabel, 0, 3 );
+
+ QSpacerItem* spacer_2 = new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Preferred );
+ glyr->addItem( spacer_2, 0, 4 );
+
+ m_ignoreDuplicates = new QCheckBox( page, "m_ignoreDuplicates" );
+ m_ignoreDuplicates->setText( i18n( "Ignore duplicated delimiters" ) );
+ glyr->addMultiCellWidget( m_ignoreDuplicates, 2, 2, 2, 4 );
+
+ m_1stRowForFieldNames = new QCheckBox( page, "m_1stRowForFieldNames" );
+ m_1stRowForFieldNames->setText( i18n( "First row contains column names" ) );
+ glyr->addMultiCellWidget( m_1stRowForFieldNames, 3, 3, 2, 4 );
+
+ m_table = new KexiCSVImportDialogTable( plainPage(), "m_table" );
+ lyr->addWidget( m_table );
+
+ m_table->setSizePolicy( QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding, 1, 1) );
+ m_table->setNumRows( 0 );
+ m_table->setNumCols( 0 );
+
+/** @todo reuse Clipboard too! */
+/*
+if ( m_mode == Clipboard )
+ {
+ setCaption( i18n( "Inserting From Clipboard" ) );
+ QMimeSource * mime = QApplication::clipboard()->data();
+ if ( !mime )
+ {
+ KMessageBox::information( this, i18n("There is no data in the clipboard.") );
+ m_cancelled = true;
+ return;
+ }
+
+ if ( !mime->provides( "text/plain" ) )
+ {
+ KMessageBox::information( this, i18n("There is no usable data in the clipboard.") );
+ m_cancelled = true;
+ return;
+ }
+ m_fileArray = QByteArray(mime->encodedData( "text/plain" ) );
+ }
+ else if ( mode == File )
+ {*/
+ m_dateRegExp = QRegExp("(\\d{1,4})([/\\-\\.])(\\d{1,2})([/\\-\\.])(\\d{1,4})");
+ m_timeRegExp1 = QRegExp("(\\d{1,2}):(\\d{1,2}):(\\d{1,2})");
+ m_timeRegExp2 = QRegExp("(\\d{1,2}):(\\d{1,2})");
+ m_fpNumberRegExp = QRegExp("[\\-]{0,1}\\d*[,\\.]\\d+");
+ QString caption( i18n("Open CSV Data File") );
+
+ if (m_mode == File) {
+ QStringList mimetypes( csvMimeTypes() );
+#ifdef Q_WS_WIN
+ //! @todo remove
+ QString recentDir = KGlobalSettings::documentPath();
+ m_fname = QFileDialog::getOpenFileName(
+ KFileDialog::getStartURL(":CSVImportExport", recentDir).path(),
+ KexiUtils::fileDialogFilterStrings(mimetypes, false),
+ page, "KexiCSVImportDialog", caption);
+ if ( !m_fname.isEmpty() ) {
+ //save last visited path
+ KURL url;
+ url.setPath( m_fname );
+ if (url.isLocalFile())
+ KRecentDirs::add(":CSVImportExport", url.directory());
+ }
+#else
+ m_fname = KFileDialog::getOpenFileName(":CSVImportExport", mimetypes.join(" "),
+ this, caption);
+#endif
+ //cancel action !
+ if ( m_fname.isEmpty() )
+ {
+ actionButton( Ok )->setEnabled( false );
+ m_cancelled = true;
+ if (parentWidget())
+ parentWidget()->raise();
+ return;
+ }
+ }
+ else if (m_mode == Clipboard) {
+ QCString subtype("plain");
+ m_clipboardData = QApplication::clipboard()->text(subtype, QClipboard::Clipboard);
+/* debug
+ for (int i=0;QApplication::clipboard()->data(QClipboard::Clipboard)->format(i);i++)
+ kdDebug() << i << ": "
+ << QApplication::clipboard()->data(QClipboard::Clipboard)->format(i) << endl;
+*/
+ }
+ else {
+ return;
+ }
+
+ m_loadingProgressDlg = 0;
+ m_importingProgressDlg = 0;
+ if (m_mode == File) {
+ m_loadingProgressDlg = new KProgressDialog(
+ this, "m_loadingProgressDlg", i18n("Loading CSV Data"), i18n("Loading CSV Data from \"%1\"...")
+ .arg(QDir::convertSeparators(m_fname)), true);
+ m_loadingProgressDlg->progressBar()->setTotalSteps( m_maximumRowsForPreview+1 );
+ m_loadingProgressDlg->show();
+ }
+
+ if (m_mode==Clipboard) {
+ m_infoLbl->setIcon("editpaste");
+ }
+ //updateRowCountInfo();
+
+ m_table->setSelectionMode(QTable::NoSelection);
+
+ connect(m_formatCombo, SIGNAL(activated(int)),
+ this, SLOT(formatChanged(int)));
+ connect(m_delimiterWidget, SIGNAL(delimiterChanged(const QString&)),
+ this, SLOT(delimiterChanged(const QString&)));
+ connect(m_startAtLineSpinBox, SIGNAL(valueChanged ( int )),
+ this, SLOT(startlineSelected(int)));
+ connect(m_comboQuote, SIGNAL(activated(int)),
+ this, SLOT(textquoteSelected(int)));
+ connect(m_table, SIGNAL(currentChanged(int, int)),
+ this, SLOT(currentCellChanged(int, int)));
+ connect(m_table, SIGNAL(valueChanged(int,int)),
+ this, SLOT(cellValueChanged(int,int)));
+ connect(m_ignoreDuplicates, SIGNAL(stateChanged(int)),
+ this, SLOT(ignoreDuplicatesChanged(int)));
+ connect(m_1stRowForFieldNames, SIGNAL(stateChanged(int)),
+ this, SLOT(slot1stRowForFieldNamesChanged(int)));
+
+ connect(this, SIGNAL(user1Clicked()), this, SLOT(optionsButtonClicked()));
+
+ installRecursiveEventFilter(this, this);
+
+ initLater();
+}
+
+KexiCSVImportDialog::~KexiCSVImportDialog()
+{
+ delete m_file;
+}
+
+void KexiCSVImportDialog::initLater()
+{
+ if (!openData())
+ return;
+
+// delimiterChanged(detectedDelimiter); // this will cause fillTable()
+ m_columnsAdjusted = false;
+ fillTable();
+ delete m_loadingProgressDlg;
+ m_loadingProgressDlg = 0;
+ if (m_dialogCancelled) {
+// m_loadingProgressDlg->hide();
+ // m_loadingProgressDlg->close();
+ QTimer::singleShot(0, this, SLOT(reject()));
+ return;
+ }
+
+ currentCellChanged(0, 0);
+
+// updateGeometry();
+ adjustSize();
+ KDialog::centerOnScreen( this );
+
+ if (m_loadingProgressDlg)
+ m_loadingProgressDlg->hide();
+ show();
+ m_table->setFocus();
+}
+
+bool KexiCSVImportDialog::openData()
+{
+ if (m_mode!=File) //data already loaded, no encoding stuff needed
+ return true;
+
+ delete m_inputStream;
+ m_inputStream = 0;
+ if (m_file) {
+ m_file->close();
+ delete m_file;
+ }
+ m_file = new QFile(m_fname);
+ if (!m_file->open(IO_ReadOnly))
+ {
+ m_file->close();
+ delete m_file;
+ m_file = 0;
+ KMessageBox::sorry( this, i18n("Cannot open input file <nobr>\"%1\"</nobr>.")
+ .arg(QDir::convertSeparators(m_fname)) );
+ actionButton( Ok )->setEnabled( false );
+ m_cancelled = true;
+ if (parentWidget())
+ parentWidget()->raise();
+ return false;
+ }
+ return true;
+}
+
+bool KexiCSVImportDialog::cancelled() const
+{
+ return m_cancelled;
+}
+
+void KexiCSVImportDialog::fillTable()
+{
+ KexiUtils::WaitCursor wc(true);
+ repaint();
+ m_blockUserEvents = true;
+ QPushButton *pb = actionButton(KDialogBase::Cancel);
+ if (pb)
+ pb->setEnabled(true); //allow to cancel
+ KexiUtils::WaitCursor wait;
+
+ if (m_table->numRows()>0) //to accept editor
+ m_table->setCurrentCell(0,0);
+
+ int row, column, maxColumn;
+ QString field = QString::null;
+
+ for (row = 0; row < m_table->numRows(); ++row)
+ for (column = 0; column < m_table->numCols(); ++column)
+ m_table->clearCell(row, column);
+
+ m_detectedTypes.clear();
+ m_detectedTypes.resize(1024, _NO_TYPE_YET);//_TEXT_TYPE);
+ m_uniquenessTest.clear();
+ m_uniquenessTest.resize(1024);
+ m_1stRowForFieldNamesDetected = true;
+
+ if (true != loadRows(field, row, column, maxColumn, true))
+ return;
+
+ m_1stRowForFieldNamesDetected = false;
+
+ // file with only one line without '\n'
+ if (field.length() > 0)
+ {
+ setText(row - m_startline, column, field, true);
+ ++row;
+ field = QString::null;
+ }
+
+ adjustRows( row - m_startline - (m_1stRowForFieldNames->isChecked()?1:0) );
+
+ maxColumn = QMAX( maxColumn, column );
+ m_table->setNumCols(maxColumn);
+
+ for (column = 0; column < m_table->numCols(); ++column)
+ {
+// QString header = m_table->horizontalHeader()->label(column);
+// if (header != i18n("Text") && header != i18n("Number") &&
+// header != i18n("Date") && header != i18n("Currency"))
+// const int detectedType = m_detectedTypes[column+1];
+// m_table->horizontalHeader()->setLabel(column, m_typeNames[ detectedType ]); //i18n("Text"));
+ updateColumnText(column);
+ if (!m_columnsAdjusted)
+ m_table->adjustColumn(column);
+ }
+ m_columnsAdjusted = true;
+
+ if (m_primaryKeyColumn>=0 && m_primaryKeyColumn<m_table->numCols()) {
+ if (_NUMBER_TYPE != m_detectedTypes[ m_primaryKeyColumn ]) {
+ m_primaryKeyColumn = -1;
+ }
+ }
+
+ m_prevSelectedCol = -1;
+ m_table->setCurrentCell(0,0);
+ currentCellChanged(0, 0);
+ if (m_primaryKeyColumn != -1)
+ m_table->setPixmap(0, m_primaryKeyColumn, m_pkIcon);
+
+ const int count = QMAX(0, m_table->numRows()-1+m_startline);
+ m_allRowsLoadedInPreview = count < m_maximumRowsForPreview && !m_stoppedAt_MAX_BYTES_TO_PREVIEW;
+ if (m_allRowsLoadedInPreview) {
+ m_startAtLineSpinBox->setMaxValue(count);
+ m_startAtLineSpinBox->setValue(m_startline+1);
+ }
+ m_startAtLineLabel->setText(i18n( "Start at line%1:").arg(
+ m_allRowsLoadedInPreview ? QString(" (1-%1)").arg(count)
+ : QString::null //we do not know what's real count
+ ));
+ updateRowCountInfo();
+
+ m_blockUserEvents = false;
+ repaint();
+ m_table->verticalScrollBar()->repaint();//avoid missing repaint
+ m_table->horizontalScrollBar()->repaint();//avoid missing repaint
+}
+
+QString KexiCSVImportDialog::detectDelimiterByLookingAtFirstBytesOfFile(QTextStream& inputStream)
+{
+ m_file->at(0);
+
+ // try to detect delimiter
+ // \t has priority, then ; then ,
+ const QIODevice::Offset origOffset = inputStream.device()->at();
+ QChar c, prevChar=0;
+ int detectedDelimiter = 0;
+ bool insideQuote = false;
+
+ //characters by priority
+ const int CH_TAB_AFTER_QUOTE = 500;
+ const int CH_SEMICOLON_AFTER_QUOTE = 499;
+ const int CH_COMMA_AFTER_QUOTE = 498;
+ const int CH_TAB = 200; // \t
+ const int CH_SEMICOLON = 199; // ;
+ const int CH_COMMA = 198; // ,
+
+ QValueList<int> tabsPerLine, semicolonsPerLine, commasPerLine;
+ int tabs = 0, semicolons = 0, commas = 0;
+ int line = 0;
+ for (uint i=0; !inputStream.atEnd() && i < MAX_CHARS_TO_SCAN_WHILE_DETECTING_DELIMITER; i++) {
+ (*m_inputStream) >> c; // read one char
+ if (prevChar=='"') {
+ if (c!='"') //real quote (not double "")
+ insideQuote = !insideQuote;
+ }
+ if (insideQuote) {
+ prevChar = c;
+ continue;
+ }
+ if (c==' ')
+ continue;
+ if (c=='\n') {//end of line
+ //remember # of tabs/semicolons/commas in this line
+ tabsPerLine += tabs;
+ tabs = 0;
+ semicolonsPerLine += semicolons;
+ semicolons = 0;
+ commasPerLine += commas;
+ commas = 0;
+ line++;
+ }
+ else if (c=='\t') {
+ tabs++;
+ detectedDelimiter = QMAX( prevChar=='"' ? CH_TAB_AFTER_QUOTE : CH_TAB, detectedDelimiter );
+ }
+ else if (c==';') {
+ semicolons++;
+ detectedDelimiter = QMAX( prevChar=='"' ? CH_SEMICOLON_AFTER_QUOTE : CH_SEMICOLON, detectedDelimiter );
+ }
+ else if (c==',') {
+ commas++;
+ detectedDelimiter = QMAX( prevChar=='"' ? CH_COMMA_AFTER_QUOTE : CH_COMMA, detectedDelimiter );
+ }
+ prevChar = c;
+ }
+
+ inputStream.device()->at(origOffset); //restore orig. offset
+
+ //now, try to find a delimiter character that exists the same number of times in all the checked lines
+ //this detection method has priority over others
+ QValueList<int>::ConstIterator it;
+ if (tabsPerLine.count()>1) {
+ tabs = tabsPerLine.isEmpty() ? 0 : tabsPerLine.first();
+ for (it=tabsPerLine.constBegin(); it!=tabsPerLine.constEnd(); ++it) {
+ if (tabs != *it)
+ break;
+ }
+ if (tabs>0 && it==tabsPerLine.constEnd())
+ return "\t";
+ }
+ if (semicolonsPerLine.count()>1) {
+ semicolons = semicolonsPerLine.isEmpty() ? 0 : semicolonsPerLine.first();
+ for (it=semicolonsPerLine.constBegin(); it!=semicolonsPerLine.constEnd(); ++it) {
+ if (semicolons != *it)
+ break;
+ }
+ if (semicolons > 0 && it==semicolonsPerLine.constEnd())
+ return ";";
+ }
+ if (commasPerLine.count()>1) {
+ commas = commasPerLine.first();
+ for (it=commasPerLine.constBegin(); it!=commasPerLine.constEnd(); ++it) {
+ if (commas != *it)
+ break;
+ }
+ if (commas > 0 && it==commasPerLine.constEnd())
+ return ",";
+ }
+ //now return the winning character by looking at CH_* symbol
+ if (detectedDelimiter == CH_TAB_AFTER_QUOTE || detectedDelimiter == CH_TAB)
+ return "\t";
+ if (detectedDelimiter == CH_SEMICOLON_AFTER_QUOTE || detectedDelimiter == CH_SEMICOLON)
+ return ";";
+ if (detectedDelimiter == CH_COMMA_AFTER_QUOTE || detectedDelimiter == CH_COMMA)
+ return ",";
+
+ return KEXICSV_DEFAULT_FILE_DELIMITER; //<-- default
+}
+
+tristate KexiCSVImportDialog::loadRows(QString &field, int &row, int &column, int &maxColumn,
+ bool inGUI)
+{
+ 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;
+ field = QString::null;
+ const bool ignoreDups = m_ignoreDuplicates->isChecked();
+ bool lastCharDelimiter = false;
+ bool nextRow = false;
+ row = column = 1;
+ maxColumn = 0;
+ QChar x;
+ const bool hadInputStream = m_inputStream!=0;
+ delete m_inputStream;
+ if ( m_mode == Clipboard ) {
+ m_inputStream = new QTextStream(m_clipboardData, IO_ReadOnly);
+ if (!hadInputStream)
+ m_delimiterWidget->setDelimiter(KEXICSV_DEFAULT_CLIPBOARD_DELIMITER);
+ }
+ else {
+ m_file->at(0); //always seek at 0 because loadRows() is called many times
+ m_inputStream = new QTextStream(m_file);
+ if (m_options.defaultEncodingExplicitySet) {
+ QTextCodec *codec = KGlobal::charsets()->codecForName(m_options.encoding);
+ if (codec)
+ m_inputStream->setCodec(codec); //QTextCodec::codecForName("CP1250"));
+ }
+ if (m_detectDelimiter) {
+ const QString delimiter( detectDelimiterByLookingAtFirstBytesOfFile(*m_inputStream) );
+ if (m_delimiterWidget->delimiter() != delimiter)
+ m_delimiterWidget->setDelimiter( delimiter );
+ }
+ }
+ const QChar delimiter(m_delimiterWidget->delimiter()[0]);
+ m_stoppedAt_MAX_BYTES_TO_PREVIEW = false;
+ int progressStep = 0;
+ if (m_importingProgressDlg)
+ progressStep = QMAX( 1, m_importingProgressDlg->progressBar()->totalSteps()/200 );
+ int offset = 0;
+ for (;!m_inputStream->atEnd(); offset++)
+ {
+//disabled: this breaks wide spreadsheets
+// if (column >= m_maximumRowsForPreview)
+// return true;
+
+ if (m_importingProgressDlg && ((offset % progressStep) < 5)) {
+ //update progr. bar dlg on final exporting
+ m_importingProgressDlg->progressBar()->setValue(offset);
+ qApp->processEvents();
+ if (m_importingProgressDlg->wasCancelled()) {
+ delete m_importingProgressDlg;
+ m_importingProgressDlg = 0;
+ return ::cancelled;
+ }
+ }
+
+ (*m_inputStream) >> x; // read one char
+
+ if (x == '\r') {
+ continue; // eat '\r', to handle RFC-compliant files
+ }
+ if (offset==0 && x.unicode()==0xfeff) {
+ // Ignore BOM, the "Byte Order Mark"
+ // (http://en.wikipedia.org/wiki/Byte_Order_Mark, // http://www.unicode.org/charts/PDF/UFFF0.pdf)
+ // Probably fixed in Qt4.
+ continue;
+ }
+
+ switch (state)
+ {
+ case S_START :
+ if (x == m_textquote)
+ {
+ state = S_QUOTED_FIELD;
+ }
+ else if (x == delimiter)
+ {
+ setText(row - m_startline, column, field, inGUI);
+ field = QString::null;
+ if ((ignoreDups == false) || (lastCharDelimiter == false))
+ ++column;
+ lastCharDelimiter = true;
+ }
+ else if (x == '\n')
+ {
+ if (!inGUI) {
+ //fill remaining empty fields (database wants them explicitly)
+ for (int additionalColumn = column; additionalColumn <= maxColumn; additionalColumn++) {
+ setText(row - m_startline, additionalColumn, QString::null, inGUI);
+ }
+ }
+ nextRow = true;
+ maxColumn = QMAX( maxColumn, column );
+ column = 1;
+ }
+ else
+ {
+ field += x;
+ state = S_MAYBE_NORMAL_FIELD;
+ }
+ break;
+ case S_QUOTED_FIELD :
+ if (x == m_textquote)
+ {
+ state = S_MAYBE_END_OF_QUOTED_FIELD;
+ }
+/*allow \n inside quoted fields
+ else if (x == '\n')
+ {
+ setText(row - m_startline, column, field, inGUI);
+ field = "";
+ if (x == '\n')
+ {
+ nextRow = true;
+ maxColumn = QMAX( maxColumn, column );
+ column = 1;
+ }
+ else
+ {
+ if ((ignoreDups == false) || (lastCharDelimiter == false))
+ ++column;
+ lastCharDelimiter = true;
+ }
+ state = S_START;
+ }*/
+ else
+ {
+ field += x;
+ }
+ break;
+ case S_MAYBE_END_OF_QUOTED_FIELD :
+ if (x == m_textquote)
+ {
+ field += x; //no, this was just escaped quote character
+ state = S_QUOTED_FIELD;
+ }
+ else if (x == delimiter || x == '\n')
+ {
+ setText(row - m_startline, column, field, inGUI);
+ field = QString::null;
+ if (x == '\n')
+ {
+ nextRow = true;
+ maxColumn = QMAX( maxColumn, column );
+ column = 1;
+ }
+ else
+ {
+ if ((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 == delimiter || x == '\n')
+ {
+ setText(row - m_startline, column, field, inGUI);
+ field = QString::null;
+ if (x == '\n')
+ {
+ nextRow = true;
+ maxColumn = QMAX( maxColumn, column );
+ column = 1;
+ }
+ else
+ {
+ if ((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 = QString::null;
+ state = S_QUOTED_FIELD;
+ break;
+ }
+ case S_NORMAL_FIELD :
+ if (x == delimiter || x == '\n')
+ {
+ setText(row - m_startline, column, field, inGUI);
+ field = QString::null;
+ if (x == '\n')
+ {
+ nextRow = true;
+ maxColumn = QMAX( maxColumn, column );
+ column = 1;
+ }
+ else
+ {
+ if ((ignoreDups == false) || (lastCharDelimiter == false))
+ ++column;
+ lastCharDelimiter = true;
+ }
+ state = S_START;
+ }
+ else
+ {
+ field += x;
+ }
+ }
+ if (x != delimiter)
+ lastCharDelimiter = false;
+
+ if (nextRow) {
+ if (!inGUI && row==1 && m_1stRowForFieldNames->isChecked()) {
+ // do not save to the database 1st row if it contains column names
+ m_importingStatement->clearArguments();
+ }
+ else if (!saveRow(inGUI))
+ return false;
+
+ ++row;
+ }
+
+ if (m_firstFillTableCall && row==2
+ && !m_1stRowForFieldNames->isChecked() && m_1stRowForFieldNamesDetected)
+ {
+ //'1st row for field name' flag detected: reload table
+ m_1stRowForFieldNamesDetected = false;
+ m_table->setNumRows( 0 );
+ m_firstFillTableCall = false; //this trick is allowed only once, on startup
+ m_1stRowForFieldNames->setChecked(true); //this will reload table
+ //slot1stRowForFieldNamesChanged(1);
+ m_blockUserEvents = false;
+ repaint();
+ return false;
+ }
+
+ if (!m_importingProgressDlg && row % 20 == 0) {
+ qApp->processEvents();
+ //only for GUI mode:
+ if (!m_firstFillTableCall && m_loadingProgressDlg && m_loadingProgressDlg->wasCancelled()) {
+ delete m_loadingProgressDlg;
+ m_loadingProgressDlg = 0;
+ m_dialogCancelled = true;
+ reject();
+ return false;
+ }
+ }
+
+ if (!m_firstFillTableCall && m_loadingProgressDlg) {
+ m_loadingProgressDlg->progressBar()->setValue(QMIN(m_maximumRowsForPreview, row));
+ }
+
+ if ( inGUI && row > (m_maximumRowsForPreview + (m_1stRowForFieldNamesDetected?1:0)) ) {
+ kexipluginsdbg << "KexiCSVImportDialog::fillTable() loading stopped at row #"
+ << m_maximumRowsForPreview << endl;
+ break;
+ }
+ if (nextRow) {
+ nextRow = false;
+ //additional speedup: stop processing now if too many bytes were loaded for preview
+ kexipluginsdbg << offset << endl;
+ if (inGUI && offset >= m_maximumBytesForPreview && row >= 2) {
+ m_stoppedAt_MAX_BYTES_TO_PREVIEW = true;
+ return true;
+ }
+ }
+ }
+ return true;
+}
+
+void KexiCSVImportDialog::updateColumnText(int col)
+{
+ QString colName;
+ if (col<(int)m_columnNames.count() && (m_1stRowForFieldNames->isChecked() || m_changedColumnNames[col]))
+ colName = m_columnNames[ col ];
+ if (colName.isEmpty()) {
+ colName = i18n("Column %1").arg(col+1); //will be changed to a valid identifier on import
+ m_changedColumnNames[ col ] = false;
+ }
+ int detectedType = m_detectedTypes[col];
+ if (detectedType==_FP_NUMBER_TYPE)
+ detectedType=_NUMBER_TYPE; //we're simplifying that for now
+ else if (detectedType==_NO_TYPE_YET) {
+ m_detectedTypes[col]=_TEXT_TYPE; //entirely empty column
+ detectedType=_TEXT_TYPE;
+ }
+ m_table->horizontalHeader()->setLabel(col,
+ i18n("Column %1").arg(col+1) + " \n(" + m_typeNames[ detectedType ] + ") ");
+ m_table->setText(0, col, colName);
+ m_table->horizontalHeader()->adjustHeaderSize();
+
+ //check uniqueness
+ QValueList<int> *list = m_uniquenessTest[col];
+ if (m_primaryKeyColumn==-1 && list && !list->isEmpty()) {
+ qHeapSort(*list);
+ QValueList<int>::ConstIterator it=list->constBegin();
+ int prevValue = *it;
+ ++it;
+ for(; it!=list->constEnd() && prevValue!=(*it); ++it)
+ prevValue=(*it);
+ if (it!=list->constEnd()) {
+ //duplicates:
+ list->clear();
+ }
+ else {
+ //a candidate for PK (autodetected)!
+ if (-1==m_primaryKeyColumn) {
+ m_primaryKeyColumn=col;
+ }
+ }
+ }
+ if (list) //not needed now: conserve memory
+ list->clear();
+}
+
+void KexiCSVImportDialog::detectTypeAndUniqueness(int row, int col, const QString& text)
+{
+ int intValue;
+ const int type = m_detectedTypes[col];
+ if (row==1 || type!=_TEXT_TYPE) {
+ bool found = false;
+ if (text.isEmpty() && type==_NO_TYPE_YET)
+ found = true; //real type should be found later
+ //detect type because it's 1st row or all prev. rows were not text
+ //-FP number? (trying before "number" type is a must)
+ if (!found && (row==1 || type==_NUMBER_TYPE || type==_FP_NUMBER_TYPE || type==_NO_TYPE_YET)) {
+ bool ok = text.isEmpty() || m_fpNumberRegExp.exactMatch(text);
+ //if (!ok)
+ // text.toDouble(&ok);
+ if (ok && (row==1 || type==_NUMBER_TYPE || type==_FP_NUMBER_TYPE || type==_NO_TYPE_YET)) {
+ m_detectedTypes[col]=_FP_NUMBER_TYPE;
+ found = true; //yes
+ }
+ }
+ //-number?
+ if (!found && (row==1 || type==_NUMBER_TYPE || type==_NO_TYPE_YET)) {
+ bool ok = text.isEmpty();//empty values allowed
+ if (!ok)
+ intValue = text.toInt(&ok);
+ if (ok && (row==1 || type==_NO_TYPE_YET)) {
+ m_detectedTypes[col]=_NUMBER_TYPE;
+ found = true; //yes
+ }
+ }
+ //-date?
+ if (!found && (row==1 || type==_DATE_TYPE || type==_NO_TYPE_YET)) {
+ if ((row==1 || type==_NO_TYPE_YET)
+ && (text.isEmpty() || m_dateRegExp.exactMatch(text)))
+ {
+ m_detectedTypes[col]=_DATE_TYPE;
+ found = true; //yes
+ }
+ }
+ //-time?
+ if (!found && (row==1 || type==_TIME_TYPE || type==_NO_TYPE_YET)) {
+ if ((row==1 || type==_NO_TYPE_YET)
+ && (text.isEmpty() || m_timeRegExp1.exactMatch(text) || m_timeRegExp2.exactMatch(text)))
+ {
+ m_detectedTypes[col]=_TIME_TYPE;
+ found = true; //yes
+ }
+ }
+ //-date/time?
+ if (!found && (row==1 || type==_TIME_TYPE || type==_NO_TYPE_YET)) {
+ if (row==1 || type==_NO_TYPE_YET) {
+ bool detected = text.isEmpty();
+ if (!detected) {
+ const QStringList dateTimeList( QStringList::split(" ", text) );
+ bool ok = dateTimeList.count()>=2;
+//! @todo also support ISODateTime's "T" separator?
+//! @todo also support timezones?
+ if (ok) {
+ //try all combinations
+ QString datePart( dateTimeList[0].stripWhiteSpace() );
+ QString timePart( dateTimeList[1].stripWhiteSpace() );
+ ok = m_dateRegExp.exactMatch(datePart)
+ && (m_timeRegExp1.exactMatch(timePart) || m_timeRegExp2.exactMatch(timePart));
+ }
+ detected = ok;
+ }
+ if (detected) {
+ m_detectedTypes[col]=_DATETIME_TYPE;
+ found = true; //yes
+ }
+ }
+ }
+ if (!found && type==_NO_TYPE_YET && !text.isEmpty()) {
+ //eventually, a non-emptytext after a while
+ m_detectedTypes[col]=_TEXT_TYPE;
+ found = true; //yes
+ }
+ //default: text type (already set)
+ }
+ //check uniqueness for this value
+ QValueList<int> *list = m_uniquenessTest[col];
+ if (row==1 && (!list || !list->isEmpty()) && !text.isEmpty() && _NUMBER_TYPE == m_detectedTypes[col]) {
+ if (!list) {
+ list = new QValueList<int>();
+ m_uniquenessTest.insert(col, list);
+ }
+ list->append( intValue );
+ }
+ else {
+ //the value is empty or uniqueness test failed in the past
+ if (list && !list->isEmpty())
+ list->clear(); //indicate that uniqueness test failed
+ }
+}
+
+bool KexiCSVImportDialog::parseDate(const QString& text, QDate& date)
+{
+ if (!m_dateRegExp.exactMatch(text))
+ return false;
+ //dddd - dd - dddd
+ //1 2 3 4 5 <- pos
+ const int d1 = m_dateRegExp.cap(1).toInt(), d3 = m_dateRegExp.cap(3).toInt(), d5 = m_dateRegExp.cap(5).toInt();
+ if (m_dateRegExp.cap(2)=="/") //probably separator for american format mm/dd/yyyy
+ date = QDate(d5, d1, d3);
+ else {
+ if (d5 > 31) //d5 == year
+ date = QDate(d5, d3, d1);
+ else //d1 == year
+ date = QDate(d1, d3, d5);
+ }
+ return date.isValid();
+}
+
+bool KexiCSVImportDialog::parseTime(const QString& text, QTime& time)
+{
+ time = QTime::fromString(text, Qt::ISODate); //same as m_timeRegExp1
+ if (time.isValid())
+ return true;
+ if (m_timeRegExp2.exactMatch(text)) { //hh:mm:ss
+ time = QTime(m_timeRegExp2.cap(1).toInt(), m_timeRegExp2.cap(3).toInt(), m_timeRegExp2.cap(5).toInt());
+ return true;
+ }
+ return false;
+}
+
+void KexiCSVImportDialog::setText(int row, int col, const QString& text, bool inGUI)
+{
+ if (!inGUI) {
+ //save text directly to database buffer
+ if (col==1) { //1st col
+ m_importingStatement->clearArguments();
+ if (m_implicitPrimaryKeyAdded)
+ *m_importingStatement << QVariant(); //id will be autogenerated here
+ }
+ const int detectedType = m_detectedTypes[col-1];
+ if (detectedType==_NUMBER_TYPE) {
+ *m_importingStatement << ( text.isEmpty() ? QVariant() : text.toInt() );
+//! @todo what about time and float/double types and different integer subtypes?
+ }
+ else if (detectedType==_FP_NUMBER_TYPE) {
+ //replace ',' with '.'
+ QCString t(text.latin1());
+ const int textLen = t.length();
+ for (int i=0; i<textLen; i++) {
+ if (t.at(i)==',') {
+ t.at(i) = '.';
+ break;
+ }
+ }
+ *m_importingStatement << ( t.isEmpty() ? QVariant() : t.toDouble() );
+ }
+ else if (detectedType==_DATE_TYPE) {
+ QDate date;
+ if (parseDate(text, date))
+ *m_importingStatement << date;
+ }
+ else if (detectedType==_TIME_TYPE) {
+ QTime time;
+ if (parseTime(text, time))
+ *m_importingStatement << time;
+ }
+ else if (detectedType==_DATETIME_TYPE) {
+ QStringList dateTimeList( QStringList::split(" ", text) );
+ if (dateTimeList.count()<2)
+ dateTimeList = QStringList::split("T", text); //also support ISODateTime's "T" separator
+//! @todo also support timezones?
+ if (dateTimeList.count()>=2) {
+ QString datePart( dateTimeList[0].stripWhiteSpace() );
+ QDate date;
+ if (parseDate(datePart, date)) {
+ QString timePart( dateTimeList[1].stripWhiteSpace() );
+ QTime time;
+ if (parseTime(timePart, time))
+ *m_importingStatement << QDateTime(date, time);
+ }
+ }
+ }
+ else //_TEXT_TYPE and the rest
+ *m_importingStatement << (m_options.stripWhiteSpaceInTextValuesChecked ? text.stripWhiteSpace() : text);
+ return;
+ }
+ //save text to GUI (table view)
+ if (m_table->numCols() < col) {
+ m_table->setNumCols(col);
+ if ((int)m_columnNames.size() < m_table->numCols()) {
+ m_columnNames.resize(m_table->numCols()+10);
+ m_changedColumnNames.resize(m_table->numCols()+10);
+ }
+ }
+
+ if (m_1stRowForFieldNames->isChecked()) {
+ if ((row+m_startline)==1) {//this is for column name
+ if ((col-1) < (int)m_changedColumnNames.size() && false==m_changedColumnNames[col-1]) {
+ //this column has no custom name entered by a user
+ //-get the name from the data cell
+ QString colName(text.simplifyWhiteSpace());
+ if (!colName.isEmpty()) {
+ if (colName.left(1)>="0" && colName.left(1)<="9")
+ colName.prepend(i18n("Column")+" ");
+ m_columnNames[ col-1 ] = colName;
+ }
+ }
+ return;
+ }
+ }
+ else {
+ if ((row+m_startline)==1) {//this row is for column name
+ if (m_1stRowForFieldNamesDetected && !m_1stRowForFieldNames->isChecked()) {
+ QString f( text.simplifyWhiteSpace() );
+ if (f.isEmpty() || !f[0].isLetter())
+ m_1stRowForFieldNamesDetected = false; //this couldn't be a column name
+ }
+ }
+ row++; //1st row was for column names
+ }
+
+ if (row < 2) // skipped by the user
+ return;
+
+ if (m_table->numRows() < row) {
+// if (m_maximumRowsForPreview >= row+100)
+ m_table->setNumRows(row+100); /* We add more rows at a time to limit recalculations */
+ //else
+// m_table->setNumRows(m_maximumRowsForPreview);
+ m_table->verticalHeader()->setLabel(0, i18n("Column name")+" ");
+ m_adjustRows=true;
+ }
+
+ m_table->setText(row - 1, col - 1, (m_options.stripWhiteSpaceInTextValuesChecked ? text.stripWhiteSpace() : text));
+ m_table->verticalHeader()->setLabel(row-1, QString::number(row-1));
+
+ detectTypeAndUniqueness(row-1, col-1, text);
+}
+
+bool KexiCSVImportDialog::saveRow(bool inGUI)
+{
+ if (inGUI) {
+ //nothing to do
+ return true;
+ }
+ //save db buffer
+ bool res = m_importingStatement->execute();
+//todo: move
+ m_importingStatement->clearArguments();
+ return res;
+// return m_conn->insertRecord(*m_destinationTableSchema, m_dbRowBuffer);
+}
+
+void KexiCSVImportDialog::adjustRows(int iRows)
+{
+ if (m_adjustRows)
+ {
+ m_table->setNumRows( iRows );
+ m_adjustRows=false;
+ for (int i = 0; i<iRows; i++)
+ m_table->adjustRow(i);
+ }
+}
+
+void KexiCSVImportDialog::formatChanged(int id)
+{
+ if (id==_PK_FLAG) {
+ if (m_primaryKeyColumn>=0 && m_primaryKeyColumn<m_table->numCols()) {
+ m_table->setPixmap(0, m_primaryKeyColumn, QPixmap());
+ }
+ if (m_primaryKeyField->isChecked()) {
+ m_primaryKeyColumn = m_table->currentColumn();
+ m_table->setPixmap(0, m_primaryKeyColumn, m_pkIcon);
+ }
+ else
+ m_primaryKeyColumn = -1;
+ return;
+ }
+ else {
+ m_detectedTypes[m_table->currentColumn()]=id;
+ m_primaryKeyField->setEnabled( _NUMBER_TYPE == id );
+ m_primaryKeyField->setChecked( m_primaryKeyColumn == m_table->currentColumn() && m_primaryKeyField->isEnabled() );
+ }
+ updateColumnText(m_table->currentColumn());
+}
+
+void KexiCSVImportDialog::delimiterChanged(const QString& delimiter)
+{
+ Q_UNUSED(delimiter);
+ m_columnsAdjusted = false;
+ m_detectDelimiter = false; //selected by hand: do not detect in the future
+ //delayed, otherwise combobox won't be repainted
+ fillTableLater();
+}
+
+void KexiCSVImportDialog::textquoteSelected(int)
+{
+ const QString tq(m_comboQuote->textQuote());
+ if (tq.isEmpty())
+ m_textquote = 0;
+ else
+ m_textquote = tq[0];
+
+ kexipluginsdbg << "KexiCSVImportDialog::textquoteSelected(): " << m_textquote << endl;
+
+ //delayed, otherwise combobox won't be repainted
+ fillTableLater();
+}
+
+void KexiCSVImportDialog::fillTableLater()
+{
+ m_table->setNumRows( 0 );
+ QTimer::singleShot(10, this, SLOT(fillTable()));
+}
+
+void KexiCSVImportDialog::startlineSelected(int startline)
+{
+// const int startline = line.toInt() - 1;
+ if (m_startline == (startline-1))
+ return;
+ m_startline = startline-1;
+ m_adjustRows=true;
+ fillTable();
+ m_table->setFocus();
+}
+
+void KexiCSVImportDialog::currentCellChanged(int, int col)
+{
+ if (m_prevSelectedCol==col)
+ return;
+ m_prevSelectedCol = col;
+ int type = m_detectedTypes[col];
+ if (type==_FP_NUMBER_TYPE)
+ type=_NUMBER_TYPE; //we're simplifying that for now
+
+ m_formatCombo->setCurrentItem( type );
+ m_formatLabel->setText( m_formatComboText.arg(col+1) );
+ m_primaryKeyField->setEnabled( _NUMBER_TYPE == m_detectedTypes[col]);
+ m_primaryKeyField->blockSignals(true); //block to disable executing slotPrimaryKeyFieldToggled()
+ m_primaryKeyField->setChecked( m_primaryKeyColumn == col );
+ m_primaryKeyField->blockSignals(false);
+}
+
+void KexiCSVImportDialog::cellValueChanged(int row,int col)
+{
+ if (row==0) {//column name has changed
+ m_columnNames[ col ] = m_table->text(row, col);
+ m_changedColumnNames.setBit( col );
+ }
+}
+
+void KexiCSVImportDialog::accept()
+{
+//! @todo MOVE MOST OF THIS TO CORE/ (KexiProject?) after KexiDialogBase code is moved to non-gui place
+
+ KexiGUIMessageHandler msg; //! @todo make it better integrated with main window
+
+ const uint numRows( m_table->numRows() );
+ if (numRows == 0)
+ return; //impossible
+
+ if (numRows == 1) {
+ if (KMessageBox::No == KMessageBox::questionYesNo(this,
+ i18n("Data set contains no rows. Do you want to import empty table?")))
+ return;
+ }
+
+ KexiProject* project = m_mainWin->project();
+ if (!project) {
+ msg.showErrorMessage(i18n("No project available."));
+ return;
+ }
+ m_conn = project->dbConnection(); //cache this pointer
+ if (!m_conn) {
+ msg.showErrorMessage(i18n("No database connection available."));
+ return;
+ }
+ KexiPart::Part *part = Kexi::partManager().partForMimeType("kexi/table");
+ if (!part) {
+ msg.showErrorMessage(&Kexi::partManager());
+ return;
+ }
+
+ //get suggested name based on the file name
+ QString suggestedName;
+ if (m_mode==File) {
+ suggestedName = KURL::fromPathOrURL(m_fname).fileName();
+ //remove extension
+ if (!suggestedName.isEmpty()) {
+ const int idx = suggestedName.findRev(".");
+ if (idx!=-1)
+ suggestedName = suggestedName.mid(0, idx ).simplifyWhiteSpace();
+ }
+ }
+
+ //-new part item
+ KexiPart::Item* partItemForSavedTable = project->createPartItem(part->info(), suggestedName);
+ if (!partItemForSavedTable) {
+ // msg.showErrorMessage(project);
+ return;
+ }
+
+#define _ERR \
+ { project->deleteUnstoredItem(partItemForSavedTable); \
+ m_conn = 0; \
+ delete m_destinationTableSchema; \
+ m_destinationTableSchema = 0; \
+ return; }
+
+ //-ask for table name/title
+ // (THIS IS FROM KexiMainWindowImpl::saveObject())
+ bool allowOverwriting = true;
+ tristate res = m_mainWin->getNewObjectInfo( partItemForSavedTable, part, allowOverwriting );
+ if (~res || !res) {
+ //! @todo: err
+ _ERR;
+ }
+ //(allowOverwriting is now set to true, if user accepts overwriting,
+ // and overwriting will be needed)
+
+// KexiDB::SchemaData sdata(part->info()->projectPartID());
+// sdata.setName( partItem->name() );
+
+ //-create table schema (and thus schema object)
+ //-assign information (THIS IS FROM KexiDialogBase::storeNewData())
+ m_destinationTableSchema = new KexiDB::TableSchema(partItemForSavedTable->name());
+ m_destinationTableSchema->setCaption( partItemForSavedTable->caption() );
+ m_destinationTableSchema->setDescription( partItemForSavedTable->description() );
+ const uint numCols( m_table->numCols() );
+
+ m_implicitPrimaryKeyAdded = false;
+ //add PK if user wanted it
+ int msgboxResult;
+ if (m_primaryKeyColumn==-1
+ && KMessageBox::No != (msgboxResult = KMessageBox::questionYesNoCancel(this,
+ i18n("No Primary Key (autonumber) has been defined.\n"
+ "Should it be automatically defined on import (recommended)?\n\n"
+ "Note: An imported table without a Primary Key may not be editable (depending on database type)."),
+ QString::null, KGuiItem(i18n("Add Database Primary Key to a Table", "Add Primary Key"), "key"),
+ KGuiItem(i18n("Do Not Add Database Primary Key to a Table", "Do Not Add")))))
+ {
+ if (msgboxResult == KMessageBox::Cancel)
+ _ERR; //cancel accepting
+
+ //add implicit PK field
+//! @todo make this field hidden (what about e.g. pgsql?)
+ m_implicitPrimaryKeyAdded = true;
+
+ QString fieldName("id");
+ QString fieldCaption("Id");
+
+ QStringList colnames;
+ for (uint col = 0; col < numCols; col++)
+ colnames.append( m_table->text(0, col).lower().simplifyWhiteSpace() );
+
+ if (colnames.find(fieldName)!=colnames.end()) {
+ int num = 1;
+ while (colnames.find(fieldName+QString::number(num))!=colnames.end())
+ num++;
+ fieldName += QString::number(num);
+ fieldCaption += QString::number(num);
+ }
+ KexiDB::Field *field = new KexiDB::Field(
+ fieldName,
+ KexiDB::Field::Integer,
+ KexiDB::Field::NoConstraints,
+ KexiDB::Field::NoOptions,
+ 0,0, //uint length=0, uint precision=0,
+ QVariant(), //QVariant defaultValue=QVariant(),
+ fieldCaption
+ ); //no description and width for now
+ field->setPrimaryKey(true);
+ field->setAutoIncrement(true);
+ m_destinationTableSchema->addField( field );
+ }
+
+ for (uint col = 0; col < numCols; col++) {
+ QString fieldCaption( m_table->text(0, col).simplifyWhiteSpace() );
+ QString fieldName( KexiUtils::string2Identifier( fieldCaption ) );
+ if (m_destinationTableSchema->field(fieldName)) {
+ QString fixedFieldName;
+ uint i = 2; //"apple 2, apple 3, etc. if there're many "apple" names
+ do {
+ fixedFieldName = fieldName + "_" + QString::number(i);
+ if (!m_destinationTableSchema->field(fixedFieldName))
+ break;
+ i++;
+ } while (true);
+ fieldName = fixedFieldName;
+ fieldCaption += (" " + QString::number(i));
+ }
+ const int detectedType = m_detectedTypes[col];
+ KexiDB::Field::Type fieldType;
+ if (detectedType==_DATE_TYPE)
+ fieldType = KexiDB::Field::Date;
+ if (detectedType==_TIME_TYPE)
+ fieldType = KexiDB::Field::Time;
+ if (detectedType==_DATETIME_TYPE)
+ fieldType = KexiDB::Field::DateTime;
+ else if (detectedType==_NUMBER_TYPE)
+ fieldType = KexiDB::Field::Integer;
+ else if (detectedType==_FP_NUMBER_TYPE)
+ fieldType = KexiDB::Field::Double;
+//! @todo what about time and float/double types and different integer subtypes?
+ else //_TEXT_TYPE and the rest
+ fieldType = KexiDB::Field::Text;
+//! @todo what about long text?
+
+ KexiDB::Field *field = new KexiDB::Field(
+ fieldName,
+ fieldType,
+ KexiDB::Field::NoConstraints,
+ KexiDB::Field::NoOptions,
+ 0,0, //uint length=0, uint precision=0,
+ QVariant(), //QVariant defaultValue=QVariant(),
+ fieldCaption
+ ); //no description and width for now
+
+ if ((int)col == m_primaryKeyColumn) {
+ field->setPrimaryKey(true);
+ field->setAutoIncrement(true);
+ }
+ m_destinationTableSchema->addField( field );
+ }
+
+ KexiDB::Transaction transaction = m_conn->beginTransaction();
+ if (transaction.isNull()) {
+ msg.showErrorMessage(m_conn);
+ _ERR;
+ }
+ KexiDB::TransactionGuard tg(transaction);
+
+ //-create physical table
+ if (!m_conn->createTable(m_destinationTableSchema, allowOverwriting)) {
+ msg.showErrorMessage(m_conn);
+ _ERR;
+ }
+
+#define _DROP_DEST_TABLE_AND_RETURN \
+ { \
+ if (m_importingProgressDlg) \
+ m_importingProgressDlg->hide(); \
+ project->deleteUnstoredItem(partItemForSavedTable); \
+ m_conn->dropTable(m_destinationTableSchema); /*alsoRemoveSchema*/ \
+ m_destinationTableSchema = 0; \
+ m_conn = 0; \
+ return; \
+ }
+
+ m_importingStatement = m_conn->prepareStatement(
+ KexiDB::PreparedStatement::InsertStatement, *m_destinationTableSchema);
+ if (!m_importingStatement) {
+ msg.showErrorMessage(m_conn);
+ _DROP_DEST_TABLE_AND_RETURN;
+ }
+
+ if (m_file) {
+ if (!m_importingProgressDlg) {
+ m_importingProgressDlg = new KProgressDialog( this, "m_importingProgressDlg",
+ i18n("Importing CSV Data"), QString::null, true );
+ }
+ m_importingProgressDlg->setLabel(
+ i18n("Importing CSV Data from <nobr>\"%1\"</nobr> into \"%2\" table...")
+ .arg(QDir::convertSeparators(m_fname)).arg(m_destinationTableSchema->name()) );
+ m_importingProgressDlg->progressBar()->setTotalSteps( QFileInfo(*m_file).size() );
+ m_importingProgressDlg->show();
+ }
+
+ int row, column, maxColumn;
+ QString field = QString::null;
+
+ // main job
+ res = loadRows(field, row, column, maxColumn, false /*!gui*/ );
+
+ delete m_importingProgressDlg;
+ m_importingProgressDlg = 0;
+ if (true != res) {
+ //importing cancelled or failed
+ if (!res) //do not display err msg when res == cancelled
+ msg.showErrorMessage(m_conn);
+ _DROP_DEST_TABLE_AND_RETURN;
+ }
+
+ // file with only one line without '\n'
+ if (field.length() > 0)
+ {
+ setText(row - m_startline, column, field, false /*!gui*/);
+ //fill remaining empty fields (database wants them explicitly)
+ for (int additionalColumn = column; additionalColumn <= maxColumn; additionalColumn++) {
+ setText(row - m_startline, additionalColumn, QString::null, false /*!gui*/);
+ }
+ if (!saveRow(false /*!gui*/)) {
+ msg.showErrorMessage(m_conn);
+ _DROP_DEST_TABLE_AND_RETURN;
+ }
+ ++row;
+ field = QString::null;
+ }
+
+ if (!tg.commit()) {
+ msg.showErrorMessage(m_conn);
+ _DROP_DEST_TABLE_AND_RETURN;
+ }
+
+ //-now we can store the item
+ partItemForSavedTable->setIdentifier( m_destinationTableSchema->id() );
+ project->addStoredItem( part->info(), partItemForSavedTable );
+
+ QDialog::accept();
+ KMessageBox::information(this, i18n("Data has been successfully imported to table \"%1\".")
+ .arg(m_destinationTableSchema->name()));
+ parentWidget()->raise();
+ m_conn = 0;
+}
+
+int KexiCSVImportDialog::getHeader(int col)
+{
+ QString header = m_table->horizontalHeader()->label(col);
+
+ if (header == i18n("Text type for column", "Text"))
+ return TEXT;
+ else if (header == i18n("Numeric type for column", "Number"))
+ return NUMBER;
+ else if (header == i18n("Currency type for column", "Currency"))
+ return CURRENCY;
+ else
+ return DATE;
+}
+
+QString KexiCSVImportDialog::getText(int row, int col)
+{
+ return m_table->text(row, col);
+}
+
+void KexiCSVImportDialog::ignoreDuplicatesChanged(int)
+{
+ fillTable();
+}
+
+void KexiCSVImportDialog::slot1stRowForFieldNamesChanged(int)
+{
+ m_adjustRows=true;
+ if (m_1stRowForFieldNames->isChecked() && m_startline>0 && m_startline>=(m_startAtLineSpinBox->maxValue()-1))
+ m_startline--;
+ fillTable();
+}
+
+void KexiCSVImportDialog::optionsButtonClicked()
+{
+ KexiCSVImportOptionsDialog dlg(m_options, this);
+ if (QDialog::Accepted != dlg.exec())
+ return;
+
+ KexiCSVImportOptions newOptions( dlg.options() );
+ if (m_options != newOptions) {
+ m_options = newOptions;
+ if (!openData())
+ return;
+ fillTable();
+ }
+}
+
+bool KexiCSVImportDialog::eventFilter ( QObject * watched, QEvent * e )
+{
+ QEvent::Type t = e->type();
+ // temporary disable keyboard and mouse events for time-consuming tasks
+ if (m_blockUserEvents && (t==QEvent::KeyPress || t==QEvent::KeyRelease
+ || t==QEvent::MouseButtonPress || t==QEvent::MouseButtonDblClick
+ || t==QEvent::Paint ))
+ return true;
+
+ if (watched == m_startAtLineSpinBox && t==QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ if (ke->key()==Qt::Key_Enter || ke->key()==Qt::Key_Return) {
+ m_table->setFocus();
+ return true;
+ }
+ }
+ return QDialog::eventFilter( watched, e );
+}
+
+void KexiCSVImportDialog::slotPrimaryKeyFieldToggled(bool on)
+{
+ Q_UNUSED(on);
+ formatChanged(_PK_FLAG);
+}
+
+void KexiCSVImportDialog::updateRowCountInfo()
+{
+ m_infoLbl->setFileName( m_fname );
+ if (m_allRowsLoadedInPreview) {
+ m_infoLbl->setCommentText(
+ i18n("row count", "(rows: %1)").arg( m_table->numRows()-1+m_startline ) );
+ QToolTip::remove( m_infoLbl );
+ }
+ else {
+ m_infoLbl->setCommentText(
+ i18n("row count", "(rows: more than %1)").arg( m_table->numRows()-1+m_startline ) );
+ QToolTip::add( m_infoLbl->commentLabel(), i18n("Not all rows are visible on this preview") );
+ }
+}
+
+#include "kexicsvimportdialog.moc"
diff --git a/kexi/plugins/importexport/csv/kexicsvimportdialog.h b/kexi/plugins/importexport/csv/kexicsvimportdialog.h
new file mode 100644
index 00000000..1f7b159e
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvimportdialog.h
@@ -0,0 +1,231 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This work is based on kspread/dialogs/kspread_dlg_csv.cc
+ and will be merged back with KOffice libraries.
+
+ Copyright (C) 2002-2003 Norbert Andres <nandres@web.de>
+ Copyright (C) 2002-2003 Ariya Hidayat <ariya@kde.org>
+ Copyright (C) 2002 Laurent Montel <montel@kde.org>
+ Copyright (C) 1999 David Faure <faure@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.
+*/
+
+#ifndef KEXI_CSVDIALOG_H
+#define KEXI_CSVDIALOG_H
+
+#include <qvaluevector.h>
+#include <qvaluelist.h>
+#include <qptrvector.h>
+#include <qregexp.h>
+#include <qbitarray.h>
+
+#include <kdialogbase.h>
+
+#include <kexiutils/tristate.h>
+#include <kexidb/connection.h>
+
+#include "kexicsvimportoptionsdlg.h"
+
+class QVBoxLayout;
+class QHBoxLayout;
+class QGridLayout;
+class QButtonGroup;
+class QCheckBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QRadioButton;
+class QTable;
+class QFile;
+class KComboBox;
+class KIntSpinBox;
+class KProgressDialog;
+
+class KexiMainWindow;
+class KexiCSVDelimiterWidget;
+class KexiCSVTextQuoteComboBox;
+class KexiCSVInfoLabel;
+
+/**
+ * @short Kexi CSV import dialog
+ *
+ * This is temporary solution for Kexi CSV import,
+ * based on kspread/dialogs/kspread_dlg_csv.h, cc.
+ *
+ * Provides dialog for managing CSV (comma separated value) data.
+ *
+ * Currently KexiCSVImportDialog is used for converting text into columns,
+ * inserting text file and pasting text from clipboard, where conversion
+ * from CSV (comma separated value) data is is all required.
+ * The different purposed mentioned above is determined
+ * using mode, which can be Column, File, or Clipboard respectively.
+*/
+class KexiCSVImportDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ enum Mode { Clipboard, File /*, Column*/ };
+ enum Header { TEXT, NUMBER, DATE, CURRENCY };
+
+ //! @todo what about making it kexidb-independent?
+ KexiCSVImportDialog( Mode mode, KexiMainWindow* mainWin, QWidget * parent,
+ const char * name = 0/*, QRect const & rect*/);
+
+ virtual ~KexiCSVImportDialog();
+
+ bool cancelled() const;
+ virtual bool eventFilter ( QObject * watched, QEvent * e );
+
+ protected:
+ bool openData();
+ virtual void accept();
+
+ private:
+ QGridLayout* MyDialogLayout;
+ QHBoxLayout* Layout1;
+ QTable* m_table;
+ KexiCSVDelimiterWidget* m_delimiterWidget;
+ bool m_detectDelimiter; //!< true if delimiter should be detected
+ //!< (true by default, set to false if user sets delimiter)
+ QString m_formatComboText;
+ QLabel* m_formatLabel;
+ KComboBox* m_formatCombo;
+ KIntSpinBox *m_startAtLineSpinBox;
+ KexiCSVTextQuoteComboBox* m_comboQuote;
+ QLabel* m_startAtLineLabel;
+ QLabel* TextLabel2;
+ QCheckBox* m_ignoreDuplicates;
+ QCheckBox* m_1stRowForFieldNames;
+ QCheckBox* m_primaryKeyField;
+
+ KexiMainWindow* m_mainWin;
+
+ void detectTypeAndUniqueness(int row, int col, const QString& text);
+ void setText(int row, int col, const QString& text, bool inGUI);
+
+ /*! Parses date from \a text and stores into \a date.
+ m_dateRegExp is used for clever detection;
+ if '/' separated is found, it's assumed the format is american mm/dd/yyyy.
+ This function supports omitted zeros, so 1/2/2006 is parsed properly too.
+ \return true on success. */
+ bool parseDate(const QString& text, QDate& date);
+
+ /*! Parses time from \a text and stores into \a date.
+ m_timeRegExp1 and m_timeRegExp2 are used for clever detection;
+ both hh:mm:ss and hh:mm are supported.
+ This function supports omitted zeros, so 1:2:3 is parsed properly too.
+ \return true on success. */
+ bool parseTime(const QString& text, QTime& time);
+
+ /*! Called after the first fillTable() when number of rows is unknown. */
+ void adjustRows(int iRows);
+
+ int getHeader(int col);
+ QString getText(int row, int col);
+ void updateColumnText(int col);
+ void updateRowCountInfo();
+ tristate loadRows(QString &field, int &row, int &columnm, int &maxColumn, bool inGUI);
+
+ /*! Detects delimiter by looking at first 4K bytes of the data. Used by loadRows().
+ The used algorithm:
+ 1. Look byte by byte and locate special characters that can be delimiters.
+ Special fact is taken into account: if there are '"' quotes used for text values,
+ delimiters that follow directly the closing quote has higher priority than the one
+ that follows other character. We do not assume that every text value is quoted.
+ Summing up, there is following hierarchy (from highest to lowest):
+ quote+tab, quote+semicolon, quote+comma, tab, semicolon, comma.
+ Space characters are skipped. Text inside quotes is skipped, as well as double
+ (escaped) quotes.
+ 2. While scanning the data, for every row following number of tabs, semicolons and commas
+ (only these outside of the quotes) are computed. On every line the values are appended
+ to a separate list (QValueList<int>).
+ 3. After scanning, all the values are checked on the QValueList<int> of tabs.
+ If the list has more one element (so there was more than one row) and all the values
+ (numbers of tabs) are equal, it's very probable the tab is a delimiter.
+ So, this character is returned as a delimiter.
+ 3a. The same algorithm as in 3. is performed for semicolon character.
+ 3b. The same algorithm as in 3. is performed for comma character.
+ 4. If the step 3. did not return a delimiter, a character found in step 1. with
+ the highest priority is retured as delimiter. */
+ QString detectDelimiterByLookingAtFirstBytesOfFile(QTextStream& inputStream);
+
+ /*! Callback, called whenever row is loaded in loadRows(). When inGUI is true,
+ nothing is performed, else database buffer is written back to the database. */
+ bool saveRow(bool inGUI);
+
+ bool m_cancelled;
+ bool m_adjustRows;
+ int m_startline;
+ QChar m_textquote;
+ QString m_clipboardData;
+ QByteArray m_fileArray;
+ Mode m_mode;
+ int m_prevSelectedCol;
+
+ //! vector of detected types, 0==text (the default), 1==number, 2==date
+//! @todo more types
+ QValueVector<int> m_detectedTypes;
+
+ //! m_detectedUniqueColumns[i]==true means that i-th column has unique values
+ //! (only for numeric type)
+ QPtrVector< QValueList<int> > m_uniquenessTest;
+
+ QRegExp m_dateRegExp, m_timeRegExp1, m_timeRegExp2, m_fpNumberRegExp;
+ QValueVector<QString> m_typeNames, m_columnNames;
+ QBitArray m_changedColumnNames;
+ bool m_columnsAdjusted : 1; //!< to call adjustColumn() only once
+ bool m_1stRowForFieldNamesDetected : 1; //!< used to force rerun fillTable() after 1st row
+ bool m_firstFillTableCall : 1; //!< used to know whether it's 1st fillTable() call
+ bool m_blockUserEvents : 1;
+ int m_primaryKeyColumn; //!< index of column with PK assigned (-1 if none)
+ int m_maximumRowsForPreview;
+ int m_maximumBytesForPreview;
+ QPixmap m_pkIcon;
+ QString m_fname;
+ QFile* m_file;
+ QTextStream *m_inputStream; //!< used in loadData()
+ KexiCSVImportOptions m_options;
+ KProgressDialog *m_loadingProgressDlg, *m_importingProgressDlg;
+ bool m_dialogCancelled;
+ KexiCSVInfoLabel *m_infoLbl;
+ KexiDB::Connection *m_conn; //!< (temp) database connection used for importing
+ KexiDB::TableSchema *m_destinationTableSchema; //!< (temp) dest. table schema used for importing
+ KexiDB::PreparedStatement::Ptr m_importingStatement;
+ QValueList<QVariant> m_dbRowBuffer; //!< (temp) used for importing
+ bool m_implicitPrimaryKeyAdded; //!< (temp) used for importing
+ bool m_allRowsLoadedInPreview; //!< we need to know whether all rows were loaded or it's just a partial data preview
+ bool m_stoppedAt_MAX_BYTES_TO_PREVIEW; //!< used to compute m_allRowsLoadedInPreview
+
+ private slots:
+ void fillTable();
+ void fillTableLater();
+ void initLater();
+ void formatChanged(int id);
+ void delimiterChanged(const QString& delimiter);
+ void startlineSelected(int line);
+ void textquoteSelected(int);
+ void currentCellChanged(int, int col);
+ void ignoreDuplicatesChanged(int);
+ void slot1stRowForFieldNamesChanged(int);
+ void cellValueChanged(int row,int col);
+ void optionsButtonClicked();
+ void slotPrimaryKeyFieldToggled(bool on);
+};
+
+#endif
diff --git a/kexi/plugins/importexport/csv/kexicsvimportoptionsdlg.cpp b/kexi/plugins/importexport/csv/kexicsvimportoptionsdlg.cpp
new file mode 100644
index 00000000..b381dde3
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvimportoptionsdlg.cpp
@@ -0,0 +1,140 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program 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 program 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "kexicsvimportoptionsdlg.h"
+#include <widget/kexicharencodingcombobox.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtextcodec.h>
+#include <qcheckbox.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcombobox.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kcharsets.h>
+
+KexiCSVImportOptions::KexiCSVImportOptions()
+{
+ kapp->config()->setGroup("ImportExport");
+ encoding = kapp->config()->readEntry("DefaultEncodingForImportingCSVFiles");
+ if (encoding.isEmpty()) {
+ encoding = QString::fromLatin1(KGlobal::locale()->encoding());
+ defaultEncodingExplicitySet = false;
+ }
+ else
+ defaultEncodingExplicitySet = true;
+
+ stripWhiteSpaceInTextValuesChecked
+ = kapp->config()->readBoolEntry("StripBlanksOffOfTextValuesWhenImportingCSVFiles", true);
+}
+
+KexiCSVImportOptions::~KexiCSVImportOptions()
+{
+}
+
+bool KexiCSVImportOptions::operator== ( const KexiCSVImportOptions & opt ) const
+{
+ return defaultEncodingExplicitySet==opt.defaultEncodingExplicitySet
+ && stripWhiteSpaceInTextValuesChecked==opt.stripWhiteSpaceInTextValuesChecked
+ && encoding==opt.encoding;
+}
+
+bool KexiCSVImportOptions::operator!= ( const KexiCSVImportOptions & opt ) const
+{
+ return !( *this==opt );
+}
+
+//----------------------------------
+
+KexiCSVImportOptionsDialog::KexiCSVImportOptionsDialog(
+ const KexiCSVImportOptions& options, QWidget* parent )
+ : KDialogBase(
+ KDialogBase::Plain,
+ i18n( "CSV Import Options" ),
+ Ok|Cancel,
+ Ok,
+ parent,
+ "KexiCSVImportOptionsDialog",
+ true,
+ false
+ )
+{
+ QGridLayout *lyr = new QGridLayout( plainPage(), 5, 3,
+ KDialogBase::marginHint(), KDialogBase::spacingHint());
+
+ m_encodingComboBox = new KexiCharacterEncodingComboBox(plainPage(), options.encoding);
+ lyr->addWidget( m_encodingComboBox, 0, 1 );
+
+ QLabel* lbl = new QLabel( m_encodingComboBox, i18n("Text encoding:"), plainPage());
+ lyr->addWidget( lbl, 0, 0 );
+
+ lyr->addItem( new QSpacerItem( 20, KDialogBase::spacingHint(), QSizePolicy::Fixed, QSizePolicy::Fixed ), 2, 1 );
+ lyr->addItem( new QSpacerItem( 121, KDialogBase::spacingHint(), QSizePolicy::Expanding, QSizePolicy::Minimum ), 0, 2 );
+
+ m_chkAlwaysUseThisEncoding = new QCheckBox(
+ i18n("Always use this encoding when importing CSV data files"), plainPage());
+ lyr->addWidget( m_chkAlwaysUseThisEncoding, 1, 1 );
+
+ m_chkStripWhiteSpaceInTextValues = new QCheckBox(
+ i18n("Strip leading and trailing blanks off of text values"), plainPage());
+ lyr->addWidget( m_chkStripWhiteSpaceInTextValues, 3, 1 );
+ lyr->addItem( new QSpacerItem( 20, KDialogBase::spacingHint(), QSizePolicy::Minimum, QSizePolicy::Expanding ), 4, 1 );
+
+ //update widgets
+ if (options.defaultEncodingExplicitySet) {
+ m_encodingComboBox->setSelectedEncoding(options.encoding);
+ m_chkAlwaysUseThisEncoding->setChecked(true);
+ }
+ m_chkStripWhiteSpaceInTextValues->setChecked(options.stripWhiteSpaceInTextValuesChecked);
+
+ adjustSize();
+ m_encodingComboBox->setFocus();
+}
+
+KexiCSVImportOptionsDialog::~KexiCSVImportOptionsDialog()
+{
+}
+
+KexiCSVImportOptions KexiCSVImportOptionsDialog::options() const
+{
+ KexiCSVImportOptions opt;
+ opt.encoding = m_encodingComboBox->selectedEncoding();
+ opt.stripWhiteSpaceInTextValuesChecked = m_chkStripWhiteSpaceInTextValues->isChecked();
+ return opt;
+}
+
+void KexiCSVImportOptionsDialog::accept()
+{
+ kapp->config()->setGroup("ImportExport");
+ if (m_chkAlwaysUseThisEncoding->isChecked())
+ kapp->config()->writeEntry("DefaultEncodingForImportingCSVFiles",
+ m_encodingComboBox->selectedEncoding());
+ else
+ kapp->config()->deleteEntry("DefaultEncodingForImportingCSVFiles");
+
+ kapp->config()->writeEntry("StripBlanksOffOfTextValuesWhenImportingCSVFiles",
+ m_chkStripWhiteSpaceInTextValues->isChecked());
+
+ KDialogBase::accept();
+}
+
+#include "kexicsvimportoptionsdlg.moc"
diff --git a/kexi/plugins/importexport/csv/kexicsvimportoptionsdlg.h b/kexi/plugins/importexport/csv/kexicsvimportoptionsdlg.h
new file mode 100644
index 00000000..e0567c9c
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvimportoptionsdlg.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ This program 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 program 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 program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KEXICSVOPTIONSDIALOG_H
+#define KEXICSVOPTIONSDIALOG_H
+
+#include <kdialogbase.h>
+#include <qcheckbox.h>
+
+class KexiCharacterEncodingComboBox;
+
+//! @short CSV Options
+class KexiCSVImportOptions
+{
+ public:
+ KexiCSVImportOptions();
+ ~KexiCSVImportOptions();
+
+ bool operator== ( const KexiCSVImportOptions & opt ) const;
+ bool operator!= ( const KexiCSVImportOptions & opt ) const;
+
+ QString encoding;
+ bool defaultEncodingExplicitySet;
+ bool stripWhiteSpaceInTextValuesChecked;
+};
+
+//! @short CSV Options dialog
+class KexiCSVImportOptionsDialog : public KDialogBase
+{
+ Q_OBJECT
+ public:
+ KexiCSVImportOptionsDialog( const KexiCSVImportOptions& options, QWidget* parent = 0 );
+ virtual ~KexiCSVImportOptionsDialog();
+
+ KexiCSVImportOptions options() const;
+
+ protected slots:
+ virtual void accept();
+
+ protected:
+ KexiCharacterEncodingComboBox *m_encodingComboBox;
+ QCheckBox *m_chkAlwaysUseThisEncoding;
+ QCheckBox *m_chkStripWhiteSpaceInTextValues;
+};
+
+#endif
diff --git a/kexi/plugins/importexport/csv/kexicsvwidgets.cpp b/kexi/plugins/importexport/csv/kexicsvwidgets.cpp
new file mode 100644
index 00000000..8e3cf4c2
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvwidgets.cpp
@@ -0,0 +1,233 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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 "kexicsvwidgets.h"
+
+#include <qdir.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <klineedit.h>
+#include <kdialogbase.h>
+#include <kactivelabel.h>
+#include <kiconloader.h>
+#include <kmimetype.h>
+
+#define KEXICSV_OTHER_DELIMITER_INDEX 4
+
+KexiCSVDelimiterWidget::KexiCSVDelimiterWidget( bool lineEditOnBottom, QWidget * parent )
+ : QWidget(parent, "KexiCSVDelimiterWidget")
+ , m_availableDelimiters(KEXICSV_OTHER_DELIMITER_INDEX)
+
+{
+ QBoxLayout *lyr =
+ lineEditOnBottom ?
+ (QBoxLayout *)new QVBoxLayout( this, 0, KDialogBase::spacingHint() )
+ : (QBoxLayout *)new QHBoxLayout( this, 0, KDialogBase::spacingHint() );
+
+ m_availableDelimiters[0]=KEXICSV_DEFAULT_FILE_DELIMITER;
+ m_availableDelimiters[1]=";";
+ m_availableDelimiters[2]="\t";
+ m_availableDelimiters[3]=" ";
+
+ m_combo = new KComboBox(this, "KexiCSVDelimiterComboBox");
+ m_combo->insertItem( i18n("Comma \",\"") ); //<-- KEXICSV_DEFAULT_FILE_DELIMITER
+ m_combo->insertItem( i18n( "Semicolon \";\"" ) );
+ m_combo->insertItem( i18n( "Tabulator" ) );
+ m_combo->insertItem( i18n( "Space \" \"" ) );
+ m_combo->insertItem( i18n( "Other" ) );
+ lyr->addWidget(m_combo);
+ setFocusProxy(m_combo);
+
+ m_delimiterEdit = new KLineEdit( this, "m_delimiterEdit" );
+// m_delimiterEdit->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, m_delimiterEdit->sizePolicy().hasHeightForWidth() ) );
+ m_delimiterEdit->setMaximumSize( QSize( 30, 32767 ) );
+ m_delimiterEdit->setMaxLength(1);
+ lyr->addWidget( m_delimiterEdit );
+ if (!lineEditOnBottom)
+ lyr->addStretch(2);
+
+ slotDelimiterChangedInternal(KEXICSV_DEFAULT_FILE_DELIMITER_INDEX); //this will init m_delimiter
+ connect(m_combo, SIGNAL(activated(int)),
+ this, SLOT(slotDelimiterChanged(int)));
+ connect(m_delimiterEdit, SIGNAL(returnPressed()),
+ this, SLOT(slotDelimiterLineEditReturnPressed()));
+ connect(m_delimiterEdit, SIGNAL(textChanged( const QString & )),
+ this, SLOT(slotDelimiterLineEditTextChanged( const QString & ) ));
+}
+
+void KexiCSVDelimiterWidget::slotDelimiterChanged(int index)
+{
+ slotDelimiterChangedInternal(index);
+ if (index==KEXICSV_OTHER_DELIMITER_INDEX)
+ m_delimiterEdit->setFocus();
+}
+
+void KexiCSVDelimiterWidget::slotDelimiterChangedInternal(int index)
+{
+ bool changed = false;
+ if (index > KEXICSV_OTHER_DELIMITER_INDEX)
+ return;
+ else if (index == KEXICSV_OTHER_DELIMITER_INDEX) {
+ changed = m_delimiter != m_delimiterEdit->text();
+ m_delimiter = m_delimiterEdit->text();
+ }
+ else {
+ changed = m_delimiter != m_availableDelimiters[index];
+ m_delimiter = m_availableDelimiters[index];
+ }
+ m_delimiterEdit->setEnabled(index == KEXICSV_OTHER_DELIMITER_INDEX);
+ if (changed)
+ emit delimiterChanged(m_delimiter);
+}
+
+void KexiCSVDelimiterWidget::slotDelimiterLineEditReturnPressed()
+{
+ if (m_combo->currentItem() != KEXICSV_OTHER_DELIMITER_INDEX)
+ return;
+ slotDelimiterChangedInternal(KEXICSV_OTHER_DELIMITER_INDEX);
+}
+
+void KexiCSVDelimiterWidget::slotDelimiterLineEditTextChanged( const QString & )
+{
+ slotDelimiterChangedInternal(KEXICSV_OTHER_DELIMITER_INDEX);
+}
+
+void KexiCSVDelimiterWidget::setDelimiter(const QString& delimiter)
+{
+ QValueVector<QString>::ConstIterator it = m_availableDelimiters.constBegin();
+ int index = 0;
+ for (; it != m_availableDelimiters.constEnd(); ++it, index++) {
+ if (*it == delimiter) {
+ m_combo->setCurrentItem(index);
+ slotDelimiterChangedInternal(index);
+ return;
+ }
+ }
+ //else: set other (custom) delimiter
+ m_delimiterEdit->setText(delimiter);
+ m_combo->setCurrentItem(KEXICSV_OTHER_DELIMITER_INDEX);
+ slotDelimiterChangedInternal(KEXICSV_OTHER_DELIMITER_INDEX);
+}
+
+//----------------------------------------------------
+
+KexiCSVTextQuoteComboBox::KexiCSVTextQuoteComboBox( QWidget * parent )
+ : KComboBox(parent, "KexiCSVTextQuoteComboBox")
+{
+ insertItem( "\"" );
+ insertItem( "'" );
+ insertItem( i18n( "None" ) );
+}
+
+QString KexiCSVTextQuoteComboBox::textQuote() const
+{
+ if (currentItem()==2)
+ return QString::null;
+ return currentText();
+}
+
+void KexiCSVTextQuoteComboBox::setTextQuote(const QString& textQuote)
+{
+ if (textQuote=="\"" || textQuote=="'")
+ setCurrentText(textQuote);
+ else if (textQuote.isEmpty())
+ setCurrentText(i18n( "None" ));
+}
+
+//----------------------------------------------------
+
+KexiCSVInfoLabel::KexiCSVInfoLabel( const QString& labelText, QWidget* parent )
+ : QWidget(parent, "KexiCSVInfoLabel")
+{
+ QVBoxLayout *vbox = new QVBoxLayout( this, 0, KDialogBase::spacingHint() );
+ QHBoxLayout *hbox = new QHBoxLayout( this );
+ vbox->addLayout(hbox);
+ m_leftLabel = new QLabel(labelText, this);
+ m_leftLabel->setMinimumWidth(130);
+ m_leftLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ m_leftLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft | Qt::WordBreak);
+ hbox->addWidget(m_leftLabel);
+ m_iconLbl = new QLabel(this);
+ m_iconLbl->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ m_iconLbl->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
+ m_fnameLbl = new KActiveLabel(this);
+ m_fnameLbl->setFocusPolicy(NoFocus);
+ m_fnameLbl->setTextFormat(Qt::PlainText);
+ m_fnameLbl->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding,1,0));
+ m_fnameLbl->setLineWidth(1);
+ m_fnameLbl->setFrameStyle(QFrame::Box);
+ m_fnameLbl->setAlignment(Qt::AlignVCenter | Qt::AlignLeft | Qt::WordBreak);
+ hbox->addSpacing(5);
+ hbox->addWidget(m_iconLbl);
+ hbox->addWidget(m_fnameLbl, 1, Qt::AlignVCenter | Qt::AlignLeft | Qt::WordBreak);
+ hbox->addSpacing(10);
+ m_commentLbl = new KActiveLabel(this);
+ m_commentLbl->setFocusPolicy(NoFocus);
+ m_commentLbl->setTextFormat(Qt::PlainText);
+ m_commentLbl->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+ m_commentLbl->setLineWidth(1);
+ m_commentLbl->setFrameStyle(QFrame::Box);
+ m_commentLbl->setAlignment(Qt::AlignVCenter | Qt::AlignLeft | Qt::WordBreak);
+ hbox->addWidget(m_commentLbl, 0, Qt::AlignVCenter | Qt::AlignRight | Qt::WordBreak);
+
+ m_separator = new QFrame(this);
+ m_separator->setFrameShape(QFrame::HLine);
+ m_separator->setFrameShadow(QFrame::Sunken);
+ vbox->addWidget(m_separator);
+}
+
+void KexiCSVInfoLabel::setFileName( const QString& fileName )
+{
+ m_fnameLbl->setText( QDir::convertSeparators(fileName) );
+ if (!fileName.isEmpty()) {
+ m_iconLbl->setPixmap(
+ KMimeType::pixmapForURL(KURL::fromPathOrURL(fileName), 0, KIcon::Desktop) );
+ }
+}
+
+void KexiCSVInfoLabel::setLabelText( const QString& text )
+{
+ m_fnameLbl->setText( text );
+// int lines = m_fnameLbl->lines();
+// m_fnameLbl->setFixedHeight(
+// QFontMetrics(m_fnameLbl->currentFont()).height() * lines );
+}
+
+void KexiCSVInfoLabel::setIcon(const QString& iconName)
+{
+ m_iconLbl->setPixmap( DesktopIcon(iconName) );
+}
+
+void KexiCSVInfoLabel::setCommentText( const QString& text )
+{
+ m_commentLbl->setText(text);
+}
+
+//----------------------------------------------------
+
+QStringList csvMimeTypes()
+{
+ QStringList mimetypes;
+ mimetypes << "text/x-csv" << "text/plain" << "all/allfiles";
+ return mimetypes;
+}
+
+#include "kexicsvwidgets.moc"
diff --git a/kexi/plugins/importexport/csv/kexicsvwidgets.h b/kexi/plugins/importexport/csv/kexicsvwidgets.h
new file mode 100644
index 00000000..f128b658
--- /dev/null
+++ b/kexi/plugins/importexport/csv/kexicsvwidgets.h
@@ -0,0 +1,116 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
+
+ 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.
+*/
+
+#ifndef KEXI_CSVWIDGETS_H
+#define KEXI_CSVWIDGETS_H
+
+#include <qvaluevector.h>
+#include <kcombobox.h>
+
+class KLineEdit;
+class KActiveLabel;
+class QLabel;
+
+#define KEXICSV_DEFAULT_FILE_TEXT_QUOTE "\""
+#define KEXICSV_DEFAULT_CLIPBOARD_TEXT_QUOTE ""
+#define KEXICSV_DEFAULT_FILE_DELIMITER ","
+#define KEXICSV_DEFAULT_CLIPBOARD_DELIMITER "\t"
+#define KEXICSV_DEFAULT_FILE_DELIMITER_INDEX 0
+
+//! \return a list of mimetypes usable for handling CSV format handling
+QStringList csvMimeTypes();
+
+/*! @short A helper widget showing a short text information with an icon.
+ See ctor for details.
+ Used by CSV import and export dialogs. */
+class KexiCSVInfoLabel : public QWidget
+{
+ public:
+ /* Sets up a new info label \a labelText label with text like "Preview of data from file:".
+ setFileName() can be used to display filename and setCommentAfterFileName() to display
+ additional comment.
+
+ The widget's layout can look like this:
+
+ \pre [icon] [labeltext] [filename] [comment]
+ */
+ KexiCSVInfoLabel( const QString& labelText, QWidget* parent );
+
+ void setFileName( const QString& fileName );
+ void setLabelText( const QString& text );
+ void setCommentText( const QString& text );
+// void setIconForFileName();
+
+ //! sets icon pixmap to \a iconName. Used wher setIconForFilename was false in ctor.
+ void setIcon(const QString& iconName);
+
+ QLabel* leftLabel() const { return m_leftLabel; }
+ KActiveLabel* fileNameLabel() const { return m_fnameLbl; }
+ KActiveLabel* commentLabel() const { return m_commentLbl; }
+ QFrame* separator() const { return m_separator; }
+
+ protected:
+ QLabel *m_leftLabel, *m_iconLbl;
+ KActiveLabel *m_fnameLbl, *m_commentLbl;
+ QFrame* m_separator;
+};
+
+//! @short A combo box widget providing a list of possible delimiters
+//! Used by CSV import and export dialogs
+class KexiCSVDelimiterWidget : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ KexiCSVDelimiterWidget( bool lineEditOnBottom, QWidget * parent = 0 );
+
+ QString delimiter() const { return m_delimiter; }
+ void setDelimiter(const QString& delimiter);
+
+ signals:
+ void delimiterChanged(const QString& delimiter);
+
+ protected slots:
+ //! only called when a delimiter was set by user directly
+ void slotDelimiterChanged(int idx);
+ void slotDelimiterChangedInternal(int idx);
+ void slotDelimiterLineEditTextChanged( const QString & );
+ void slotDelimiterLineEditReturnPressed();
+
+ protected:
+ QString m_delimiter;
+ QValueVector<QString> m_availableDelimiters;
+ KComboBox* m_combo;
+ KLineEdit* m_delimiterEdit;
+};
+
+//! @short A combo box widget providing a list of possible quote characters
+//! Used by CSV import and export dialogs
+class KexiCSVTextQuoteComboBox : public KComboBox
+{
+ public:
+ KexiCSVTextQuoteComboBox( QWidget * parent = 0 );
+
+ QString textQuote() const;
+
+ //! Sets text quote. Only available are: ", ', and empty string.
+ void setTextQuote(const QString& textQuote);
+};
+
+#endif