kexi
kexicsvexport.cpp00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kexicsvexport.h"
00021 #include "kexicsvwidgets.h"
00022 #include <main/startup/KexiStartupFileDialog.h>
00023 #include <kexidb/cursor.h>
00024 #include <kexidb/utils.h>
00025 #include <core/keximainwindow.h>
00026 #include <core/kexiproject.h>
00027 #include <core/kexipartinfo.h>
00028 #include <core/kexipartmanager.h>
00029 #include <core/kexiguimsghandler.h>
00030 #include <kexiutils/utils.h>
00031 #include <widget/kexicharencodingcombobox.h>
00032
00033 #include <qcheckbox.h>
00034 #include <qgroupbox.h>
00035 #include <qclipboard.h>
00036 #include <kapplication.h>
00037 #include <klocale.h>
00038 #include <kiconloader.h>
00039 #include <kactivelabel.h>
00040 #include <kpushbutton.h>
00041 #include <kapplication.h>
00042 #include <kdebug.h>
00043 #include <ksavefile.h>
00044
00045
00046 using namespace KexiCSVExport;
00047
00048 Options::Options()
00049 : mode(File), itemId(0), addColumnNames(true)
00050 {
00051 }
00052
00053 bool Options::assign( QMap<QString,QString>& args )
00054 {
00055 mode = (args["destinationType"]=="file")
00056 ? KexiCSVExport::File : KexiCSVExport::Clipboard;
00057
00058 if (args.contains("delimiter"))
00059 delimiter = args["delimiter"];
00060 else
00061 delimiter = (mode==File) ? KEXICSV_DEFAULT_FILE_DELIMITER : KEXICSV_DEFAULT_CLIPBOARD_DELIMITER;
00062
00063 if (args.contains("textQuote"))
00064 textQuote = args["textQuote"];
00065 else
00066 textQuote = (mode==File) ? KEXICSV_DEFAULT_FILE_TEXT_QUOTE : KEXICSV_DEFAULT_CLIPBOARD_TEXT_QUOTE;
00067
00068 bool ok;
00069 itemId = args["itemId"].toInt(&ok);
00070 if (!ok || itemId<=0)
00071 return false;
00072 if (args.contains("forceDelimiter"))
00073 forceDelimiter = args["forceDelimiter"];
00074 if (args.contains("addColumnNames"))
00075 addColumnNames = (args["addColumnNames"]=="1");
00076 return true;
00077 }
00078
00079
00080
00081 bool KexiCSVExport::exportData(KexiDB::TableOrQuerySchema& tableOrQuery,
00082 const Options& options, int rowCount, QTextStream *predefinedTextStream)
00083 {
00084 KexiDB::Connection* conn = tableOrQuery.connection();
00085 if (!conn)
00086 return false;
00087
00088 if (rowCount == -1)
00089 rowCount = KexiDB::rowCount(tableOrQuery);
00090 if (rowCount == -1)
00091 return false;
00092
00097
00100
00101 KexiDB::QuerySchema* query = tableOrQuery.query();
00102 if (!query)
00103 query = tableOrQuery.table()->query();
00104
00105 KexiDB::QueryColumnInfo::Vector fields( query->fieldsExpanded( KexiDB::QuerySchema::WithInternalFields ) );
00106 QString buffer;
00107
00108 KSaveFile *kSaveFile = 0;
00109 QTextStream *stream = 0;
00110
00111 const bool copyToClipboard = options.mode==Clipboard;
00112 if (copyToClipboard) {
00114 uint bufSize = QMIN((rowCount<0 ? 10 : rowCount) * fields.count() * 20, 128000);
00115 buffer.reserve( bufSize );
00116 if (buffer.capacity() < bufSize) {
00117 kdWarning() << "KexiCSVExportWizard::exportData() cannot allocate memory for " << bufSize
00118 << " characters" << endl;
00119 return false;
00120 }
00121 }
00122 else {
00123 if (predefinedTextStream) {
00124 stream = predefinedTextStream;
00125 }
00126 else {
00127 if (options.fileName.isEmpty()) {
00128 kdWarning() << "KexiCSVExportWizard::exportData(): fname is empty" << endl;
00129 return false;
00130 }
00131 kSaveFile = new KSaveFile(options.fileName);
00132 if (0 == kSaveFile->status())
00133 stream = kSaveFile->textStream();
00134 if (0 != kSaveFile->status() || !stream) {
00135 kdWarning() << "KexiCSVExportWizard::exportData(): status != 0 or stream == 0" << endl;
00136 delete kSaveFile;
00137 return false;
00138 }
00139 }
00140 }
00141
00143
00144 #define _ERR \
00145 delete [] isText; \
00146 if (kSaveFile) { kSaveFile->abort(); delete kSaveFile; } \
00147 return false
00148
00149 #define APPEND(what) \
00150 if (copyToClipboard) buffer.append(what); else (*stream) << (what)
00151
00152
00153 #define CSV_EOLN "\r\n"
00154
00155
00156 const uint fieldsCount = query->fieldsExpanded().count();
00157 const QCString delimiter( options.delimiter.left(1).latin1() );
00158 const bool hasTextQuote = !options.textQuote.isEmpty();
00159 const QString textQuote( options.textQuote.left(1) );
00160 const QCString escapedTextQuote( (textQuote + textQuote).latin1() );
00161
00162 bool *isText = new bool[fieldsCount];
00163 bool *isDateTime = new bool[fieldsCount];
00164 bool *isTime = new bool[fieldsCount];
00165 bool *isBLOB = new bool[fieldsCount];
00166 uint *visibleFieldIndex = new uint[fieldsCount];
00167
00168
00169 for (uint i=0; i<fieldsCount; i++) {
00170 KexiDB::QueryColumnInfo* ci;
00171 const int indexForVisibleLookupValue = fields[i]->indexForVisibleLookupValue();
00172 if (-1 != indexForVisibleLookupValue) {
00173 ci = query->expandedOrInternalField( indexForVisibleLookupValue );
00174 visibleFieldIndex[i] = indexForVisibleLookupValue;
00175 }
00176 else {
00177 ci = fields[i];
00178 visibleFieldIndex[i] = i;
00179 }
00180
00181 isText[i] = ci->field->isTextType();
00182 isDateTime[i] = ci->field->type()==KexiDB::Field::DateTime;
00183 isTime[i] = ci->field->type()==KexiDB::Field::Time;
00184 isBLOB[i] = ci->field->type()==KexiDB::Field::BLOB;
00185
00186
00187
00188 }
00189
00190
00191 if (options.addColumnNames) {
00192 for (uint i=0; i<fieldsCount; i++) {
00193 if (i>0)
00194 APPEND( delimiter );
00195 if (hasTextQuote){
00196 APPEND( textQuote + fields[i]->captionOrAliasOrName().replace(textQuote, escapedTextQuote) + textQuote );
00197 }
00198 else {
00199 APPEND( fields[i]->captionOrAliasOrName() );
00200 }
00201 }
00202 APPEND(CSV_EOLN);
00203 }
00204
00205 KexiGUIMessageHandler handler;
00206 KexiDB::Cursor *cursor = conn->executeQuery(*query);
00207 if (!cursor) {
00208 handler.showErrorMessage(conn);
00209 _ERR;
00210 }
00211 for (cursor->moveFirst(); !cursor->eof() && !cursor->error(); cursor->moveNext()) {
00212 const uint realFieldCount = QMIN(cursor->fieldCount(), fieldsCount);
00213 for (uint i=0; i<realFieldCount; i++) {
00214 const uint real_i = visibleFieldIndex[i];
00215 if (i>0)
00216 APPEND( delimiter );
00217 if (cursor->value(real_i).isNull())
00218 continue;
00219 if (isText[real_i]) {
00220 if (hasTextQuote)
00221 APPEND( textQuote + QString(cursor->value(real_i).toString()).replace(textQuote, escapedTextQuote) + textQuote );
00222 else
00223 APPEND( cursor->value(real_i).toString() );
00224 }
00225 else if (isDateTime[real_i]) {
00226 APPEND( cursor->value(real_i).toDateTime().date().toString(Qt::ISODate)+" "
00227 + cursor->value(real_i).toDateTime().time().toString(Qt::ISODate) );
00228 }
00229 else if (isTime[real_i]) {
00230 APPEND( cursor->value(real_i).toTime().toString(Qt::ISODate) );
00231 }
00232 else if (isBLOB[real_i]) {
00233 if (hasTextQuote)
00235 APPEND( textQuote + KexiDB::escapeBLOB(cursor->value(real_i).toByteArray(), KexiDB::BLOBEscapeHex) + textQuote );
00236 else
00237 APPEND( KexiDB::escapeBLOB(cursor->value(real_i).toByteArray(), KexiDB::BLOBEscapeHex) );
00238 }
00239 else {
00240 APPEND( cursor->value(real_i).toString() );
00241 }
00242 }
00243 APPEND(CSV_EOLN);
00244 }
00245
00246 if (copyToClipboard)
00247 buffer.squeeze();
00248
00249 if (!conn->deleteCursor(cursor)) {
00250 handler.showErrorMessage(conn);
00251 _ERR;
00252 }
00253
00254 if (copyToClipboard)
00255 kapp->clipboard()->setText(buffer, QClipboard::Clipboard);
00256
00257 delete [] isText;
00258 delete [] isDateTime;
00259 delete [] isTime;
00260 delete [] isBLOB;
00261 delete [] visibleFieldIndex;
00262
00263 if (kSaveFile) {
00264 if (!kSaveFile->close()) {
00265 kdWarning() << "KexiCSVExportWizard::exportData(): error close(); status == "
00266 << kSaveFile->status() << endl;
00267 }
00268 delete kSaveFile;
00269 }
00270 return true;
00271 }
|