void WdgAddStation::OnSave()
{
	QString Str = ui.leComment->text();
	if(Str.capacity()<1)
		return;
	if(ui.sbFreq->value() > 100000 && ui.sbFreq->value() < 440000000)
	{
		emit Station(ui.leComment->text(), ui.sbFreq->value(), ui.comboBox->currentIndex());
		close();
	}
}
示例#2
0
QString KexiDB::escapeBLOB(const QByteArray& array, BLOBEscapingType type)
{
    const int size = array.size();
    if (size == 0)
        return QString();
    int escaped_length = size * 2;
    if (type == BLOBEscape0xHex || type == BLOBEscapeOctal)
        escaped_length += 2/*0x or X'*/;
    else if (type == BLOBEscapeXHex)
        escaped_length += 3; //X' + '
    QString str;
    str.reserve(escaped_length);
    if (str.capacity() < escaped_length) {
        KexiDBWarn << "KexiDB::Driver::escapeBLOB(): no enough memory (cannot allocate " <<
        escaped_length << " chars)";
        return QString();
    }
    if (type == BLOBEscapeXHex)
        str = QString::fromLatin1("X'");
    else if (type == BLOBEscape0xHex)
        str = QString::fromLatin1("0x");
    else if (type == BLOBEscapeOctal)
        str = QString::fromLatin1("'");

    int new_length = str.length(); //after X' or 0x, etc.
    if (type == BLOBEscapeOctal) {
        // only escape nonprintable characters as in Table 8-7:
        // http://www.postgresql.org/docs/8.1/interactive/datatype-binary.html
        // i.e. escape for bytes: < 32, >= 127, 39 ('), 92(\).
        for (int i = 0; i < size; i++) {
            const unsigned char val = array[i];
            if (val < 32 || val >= 127 || val == 39 || val == 92) {
                str[new_length++] = '\\';
                str[new_length++] = '\\';
                str[new_length++] = '0' + val / 64;
                str[new_length++] = '0' + (val % 64) / 8;
                str[new_length++] = '0' + val % 8;
            } else {
                str[new_length++] = val;
            }
        }
    } else {
        for (int i = 0; i < size; i++) {
            const unsigned char val = array[i];
            str[new_length++] = (val / 16) < 10 ? ('0' + (val / 16)) : ('A' + (val / 16) - 10);
            str[new_length++] = (val % 16) < 10 ? ('0' + (val % 16)) : ('A' + (val % 16) - 10);
        }
    }
    if (type == BLOBEscapeXHex || type == BLOBEscapeOctal)
        str[new_length++] = '\'';
    return str;
}
示例#3
0
void MainWindow::on_pushButton_4_clicked()
{
     QTextDocument doc;
     QString txt;
     txt = ::textAt(h3,65,"ASAP Film Order") %
                  ::textAt(h3,40,"From C&C Special Products Co. 952-881-0073") %
                  ::textAt(h3,67,"Mark &nbsp;Robin") %
                  ::textAt(h3,6,"Attn: Customer Service") % ::nbsp(63) % "Rip Settings:"%
                  ::textAt(h3,103,"1) Film Positives") %
                  ::textAt(h3,103,"2) DO NOT TRAP") %
                  ::textAt(h3,103,"3) Send Pre Separated") %
                  ::textAt(h3,6,"Date: " % ui->dateEdit->text()) %
                  ::textAt(h3,6,"File Name: " % ui->lineEdit_2->text());

qDebug() << "The memory used is: " << txt.capacity();

     doc.setHtml(txt);


     #if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG)
         QPrinter printer(QPrinter::HighResolution);
         QPrintDialog *dlg = new QPrintDialog(&printer, this);
         dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);
         dlg->setWindowTitle(tr("Print Document"));
         if (dlg->exec() == QDialog::Accepted)
            {
             QPrinter printer;
       //      printer.setOutputFileName("c:\\temp\\filenew.pdf");
       //      printer.setOutputFormat(QPrinter::PdfFormat);
             qDebug() <<  "Sending to printer";

             doc.print(&printer);
             printer.newPage();
             printer.setOutputFileName("c:\\temp\\faxASAP.pdf");
             printer.setOutputFormat(QPrinter::PdfFormat);
             qDebug() <<  "Creating PDF";
            doc.print(&printer);
             printer.newPage();

           }

         delete dlg;
     #endif

}
示例#4
0
bool QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar)
{
    m_proFile = pro;
    m_lineNo = line;

    // Final precompiled token stream buffer
    QString tokBuff;
    // Worst-case size calculations:
    // - line marker adds 1 (2-nl) to 1st token of each line
    // - empty assignment "A=":2 =>
    //   TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + 0(1) +
    //   TokValueTerminator(1) == 8 (9)
    // - non-empty assignment "A=B C":5 =>
    //   TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + 2(1) +
    //   TokLiteral(1) + len(1) + "B"(1) +
    //   TokLiteral(1) + len(1) + "C"(1) + TokValueTerminator(1) == 14 (15)
    // - variable expansion: "$$f":3 =>
    //   TokVariable(1) + hash(2) + len(1) + "f"(1) = 5
    // - function expansion: "$$f()":5 =>
    //   TokFuncName(1) + hash(2) + len(1) + "f"(1) + TokFuncTerminator(1) = 6
    // - scope: "X:":2 =>
    //   TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) +
    //   TokBranch(1) + len(2) + ... + len(2) + ... == 10
    // - test: "X():":4 =>
    //   TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokTestCall(1) + TokFuncTerminator(1) +
    //   TokBranch(1) + len(2) + ... + len(2) + ... == 11
    // - "for(A,B):":9 =>
    //   TokForLoop(1) + hash(2) + len(1) + "A"(1) +
    //   len(2) + TokLiteral(1) + len(1) + "B"(1) + TokValueTerminator(1) +
    //   len(2) + ... + TokTerminator(1) == 14 (15)
    tokBuff.reserve((in.size() + 1) * 5);
    ushort *tokPtr = (ushort *)tokBuff.constData(); // Current writing position

    // Expression precompiler buffer.
    QString xprBuff;
    xprBuff.reserve(tokBuff.capacity()); // Excessive, but simple
    ushort *buf = (ushort *)xprBuff.constData();

    // Parser state
    m_blockstack.clear();
    m_blockstack.resize(1);

    QStack<ParseCtx> xprStack;
    xprStack.reserve(10);

    // We rely on QStrings being null-terminated, so don't maintain a global end pointer.
    const ushort *cur = (const ushort *)in.unicode();
    m_canElse = false;
  freshLine:
    m_state = StNew;
    m_invert = false;
    m_operator = NoOperator;
    m_markLine = m_lineNo;
    m_inError = false;
    int parens = 0; // Braces in value context
    int argc = 0;
    int wordCount = 0; // Number of words in currently accumulated expression
    int lastIndent = 0; // Previous line's indentation, to detect accidental continuation abuse
    bool lineMarked = true; // For in-expression markers
    ushort needSep = TokNewStr; // Met unquoted whitespace
    ushort quote = 0;
    ushort term = 0;

    Context context;
    ushort *ptr;
    if (grammar == ValueGrammar) {
        context = CtxPureValue;
        ptr = tokPtr + 2;
    } else {
        context = CtxTest;
        ptr = buf + 4;
    }
    ushort *xprPtr = ptr;

#define FLUSH_LHS_LITERAL() \
    do { \
        if ((tlen = ptr - xprPtr)) { \
            finalizeHashStr(xprPtr, tlen); \
            if (needSep) { \
                wordCount++; \
                needSep = 0; \
            } \
        } else { \
            ptr -= 4; \
        } \
    } while (0)

#define FLUSH_RHS_LITERAL() \
    do { \
        if ((tlen = ptr - xprPtr)) { \
            xprPtr[-2] = TokLiteral | needSep; \
            xprPtr[-1] = tlen; \
            if (needSep) { \
                wordCount++; \
                needSep = 0; \
            } \
        } else { \
            ptr -= 2; \
        } \
    } while (0)

#define FLUSH_LITERAL() \
    do { \
        if (context == CtxTest) \
            FLUSH_LHS_LITERAL(); \
        else \
            FLUSH_RHS_LITERAL(); \
    } while (0)

#define FLUSH_VALUE_LIST() \
    do { \
        if (wordCount > 1) { \
            xprPtr = tokPtr; \
            if (*xprPtr == TokLine) \
                xprPtr += 2; \
            tokPtr[-1] = ((*xprPtr & TokMask) == TokLiteral) ? wordCount : 0; \
        } else { \
            tokPtr[-1] = 0; \
        } \
        tokPtr = ptr; \
        putTok(tokPtr, TokValueTerminator); \
    } while (0)

    const ushort *end; // End of this line
    const ushort *cptr; // Start of next line
    bool lineCont;
    int indent;

    if (context == CtxPureValue) {
        end = (const ushort *)in.unicode() + in.length();
        cptr = 0;
        lineCont = false;
        indent = 0; // just gcc being stupid
        goto nextChr;
    }

    forever {
        ushort c;

        // First, skip leading whitespace
        for (indent = 0; ; ++cur, ++indent) {
            c = *cur;
            if (c == '\n') {
                ++cur;
                goto flushLine;
            } else if (!c) {
                cur = 0;
                goto flushLine;
            } else if (c != ' ' && c != '\t' && c != '\r') {
                break;
            }
        }

        // Then strip comments. Yep - no escaping is possible.
        for (cptr = cur;; ++cptr) {
            c = *cptr;
            if (c == '#') {
                for (end = cptr; (c = *++cptr);) {
                    if (c == '\n') {
                        ++cptr;
                        break;
                    }
                }
                if (end == cur) { // Line with only a comment (sans whitespace)
                    if (m_markLine == m_lineNo)
                        m_markLine++;
                    // Qmake bizarreness: such lines do not affect line continuations
                    goto ignore;
                }
                break;
            }
            if (!c) {
                end = cptr;
                break;
            }
            if (c == '\n') {
                end = cptr++;
                break;
            }
        }

        // Then look for line continuations. Yep - no escaping here as well.
        forever {
            // We don't have to check for underrun here, as we already determined
            // that the line is non-empty.
            ushort ec = *(end - 1);
            if (ec == '\\') {
                --end;
                lineCont = true;
                break;
            }
            if (ec != ' ' && ec != '\t' && ec != '\r') {
                lineCont = false;
                break;
            }
            --end;
        }

            // Finally, do the tokenization
            ushort tok, rtok;
            int tlen;
          newWord:
            do {
                if (cur == end)
                    goto lineEnd;
                c = *cur++;
            } while (c == ' ' || c == '\t');
            forever {
                if (c == '$') {
                    if (*cur == '$') { // may be EOF, EOL, WS, '#' or '\\' if past end
                        cur++;
                        FLUSH_LITERAL();
                        if (!lineMarked) {
                            lineMarked = true;
                            *ptr++ = TokLine;
                            *ptr++ = (ushort)m_lineNo;
                        }
                        term = 0;
                        tok = TokVariable;
                        c = *cur;
                        if (c == '[') {
                            ptr += 4;
                            tok = TokProperty;
                            term = ']';
                            c = *++cur;
                        } else if (c == '{') {
                            ptr += 4;
                            term = '}';
                            c = *++cur;
                        } else if (c == '(') {
                            ptr += 2;
                            tok = TokEnvVar;
                            term = ')';
                            c = *++cur;
                        } else {
                            ptr += 4;
                        }
                        xprPtr = ptr;
                        rtok = tok;
                        while ((c & 0xFF00) || c == '.' || c == '_' ||
                               (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
                               (c >= '0' && c <= '9') || (c == '/' && term)) {
                            *ptr++ = c;
                            if (++cur == end) {
                                c = 0;
                                goto notfunc;
                            }
                            c = *cur;
                        }
                        if (tok == TokVariable && c == '(')
                            tok = TokFuncName;
                      notfunc:
                        if (ptr == xprPtr)
                            languageWarning(fL1S("Missing name in expansion"));
                        if (quote)
                            tok |= TokQuoted;
                        if (needSep) {
                            tok |= needSep;
                            wordCount++;
                        }
                        tlen = ptr - xprPtr;
                        if (rtok != TokVariable
                            || !resolveVariable(xprPtr, tlen, needSep, &ptr,
                                                &buf, &xprBuff, &tokPtr, &tokBuff, cur, in)) {
                            if (rtok == TokVariable || rtok == TokProperty) {
                                xprPtr[-4] = tok;
                                uint hash = ProString::hash((const QChar *)xprPtr, tlen);
                                xprPtr[-3] = (ushort)hash;
                                xprPtr[-2] = (ushort)(hash >> 16);
                                xprPtr[-1] = tlen;
                            } else {
                                xprPtr[-2] = tok;
                                xprPtr[-1] = tlen;
                            }
                        }
                        if ((tok & TokMask) == TokFuncName) {
                            cur++;
                          funcCall:
                            {
                                xprStack.resize(xprStack.size() + 1);
                                ParseCtx &top = xprStack.top();
                                top.parens = parens;
                                top.quote = quote;
                                top.terminator = term;
                                top.context = context;
                                top.argc = argc;
                                top.wordCount = wordCount;
                            }
                            parens = 0;
                            quote = 0;
                            term = 0;
                            argc = 1;
                            context = CtxArgs;
                          nextToken:
                            wordCount = 0;
                          nextWord:
                            ptr += (context == CtxTest) ? 4 : 2;
                            xprPtr = ptr;
                            needSep = TokNewStr;
                            goto newWord;
                        }
                        if (term) {
                          checkTerm:
                            if (c != term) {
                                parseError(fL1S("Missing %1 terminator [found %2]")
                                    .arg(QChar(term))
                                    .arg(c ? QString(c) : QString::fromLatin1("end-of-line")));
                                pro->setOk(false);
                                m_inError = true;
                                // Just parse on, as if there was a terminator ...
                            } else {
                                cur++;
                            }
                        }
                      joinToken:
                        ptr += (context == CtxTest) ? 4 : 2;
                        xprPtr = ptr;
                        needSep = 0;
                        goto nextChr;
                    }
                } else if (c == '\\') {
示例#5
0
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;
}
示例#6
0
bool KexiCSVExport::exportData(KDbTableOrQuerySchema *tableOrQuery,
                               const Options& options, int recordCount, QTextStream *predefinedTextStream)
{
    KDbConnection* conn = tableOrQuery->connection();
    if (!conn)
        return false;

    KDbQuerySchema* query = tableOrQuery->query();
    QList<QVariant> queryParams;
    if (!query) {
        query = tableOrQuery->table()->query();
    }
    else {
        queryParams = KexiMainWindowIface::global()->currentParametersForQuery(query->id());
    }

    if (recordCount == -1)
        recordCount = KDb::recordCount(tableOrQuery, queryParams);
    if (recordCount == -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 recordCount 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..

    KDbQueryColumnInfo::Vector fields(query->fieldsExpanded(KDbQuerySchema::WithInternalFields));
    QString buffer;

    QScopedPointer<QSaveFile> kSaveFile;
    QTextStream *stream = 0;
    QScopedPointer<QTextStream> kSaveFileTextStream;

    const bool copyToClipboard = options.mode == Clipboard;
    if (copyToClipboard) {
//! @todo (during exporting): enlarge bufSize by factor of 2 when it became too small
        int bufSize = qMin((recordCount < 0 ? 10 : recordCount) * fields.count() * 20, 128000);
        buffer.reserve(bufSize);
        if (buffer.capacity() < bufSize) {
            qWarning() << "Cannot allocate memory for " << bufSize
            << " characters";
            return false;
        }
    } else {
        if (predefinedTextStream) {
            stream = predefinedTextStream;
        } else {
            if (options.fileName.isEmpty()) {//sanity
                qWarning() << "Fname is empty";
                return false;
            }
            kSaveFile.reset(new QSaveFile(options.fileName));

            qDebug() << "QSaveFile Filename:" << kSaveFile->fileName();

            if (kSaveFile->open(QIODevice::WriteOnly)) {
                kSaveFileTextStream.reset(new QTextStream(kSaveFile.data()));
                stream = kSaveFileTextStream.data();
                qDebug() << "have a stream";
            }
            if (QFileDevice::NoError != kSaveFile->error() || !stream) {//sanity
                qWarning() << "Status != 0 or stream == 0";
//! @todo show error
                return false;
            }
        }
    }

//! @todo escape strings

#define _ERR \
    if (kSaveFile) { kSaveFile->cancelWriting(); } \
    return false

#define APPEND(what) \
    if (copyToClipboard) buffer.append(what); else (*stream) << (what)

// use native line ending for copying, RFC 4180 one for saving to file
#define APPEND_EOLN \
    if (copyToClipboard) { APPEND('\n'); } else { APPEND("\r\n"); }

    qDebug() << 0 << "Columns: " << query->fieldsExpanded().count();
    // 0. Cache information
    const int fieldsCount = query->fieldsExpanded().count(); //real fields count without internals
    const QByteArray delimiter(options.delimiter.left(1).toLatin1());
    const bool hasTextQuote = !options.textQuote.isEmpty();
    const QString textQuote(options.textQuote.left(1));
    const QByteArray escapedTextQuote((textQuote + textQuote).toLatin1());   //ok?
    //cache for faster checks
    QScopedArrayPointer<bool> isText(new bool[fieldsCount]);
    QScopedArrayPointer<bool> isDateTime(new bool[fieldsCount]);
    QScopedArrayPointer<bool> isTime(new bool[fieldsCount]);
    QScopedArrayPointer<bool> isBLOB(new bool[fieldsCount]);
    QScopedArrayPointer<int> visibleFieldIndex(new int[fieldsCount]);
// bool isInteger[fieldsCount]; //cache for faster checks
// bool isFloatingPoint[fieldsCount]; //cache for faster checks
    for (int i = 0; i < fieldsCount; i++) {
        KDbQueryColumnInfo* ci;
        const int indexForVisibleLookupValue = fields[i]->indexForVisibleLookupValue();
        if (-1 != indexForVisibleLookupValue) {
            ci = query->expandedOrInternalField(indexForVisibleLookupValue);
            visibleFieldIndex[i] = indexForVisibleLookupValue;
        } else {
            ci = fields[i];
            visibleFieldIndex[i] = i;
        }

        const KDbField::Type t = ci->field->type(); // cache: evaluating type of expressions can be expensive
        isText[i] = KDbField::isTextType(t);
        isDateTime[i] = t == KDbField::DateTime;
        isTime[i] = t == KDbField::Time;
        isBLOB[i] = t == KDbField::BLOB;
//  isInteger[i] = KDbField::isIntegerType(t)
//   || t == KDbField::Boolean;
//  isFloatingPoint[i] = KDbField::isFPNumericType(t);
    }

    // 1. Output column names
    if (options.addColumnNames) {
        for (int i = 0; i < fieldsCount; i++) {
            //qDebug() << "Adding column names";
            if (i > 0) {
                APPEND(delimiter);
            }

            if (hasTextQuote) {
                APPEND(textQuote + fields[i]->captionOrAliasOrName().replace(textQuote, escapedTextQuote) + textQuote);
            } else {
                APPEND(fields[i]->captionOrAliasOrName());
            }
        }
        APPEND_EOLN
    }

    KexiGUIMessageHandler handler;
    KDbCursor *cursor = conn->executeQuery(query, queryParams);
    if (!cursor) {
        handler.showErrorMessage(conn->result());
        _ERR;
    }
    for (cursor->moveFirst(); !cursor->eof() && !cursor->result().isError(); cursor->moveNext()) {
        //qDebug() << "Adding records";
        const int realFieldCount = qMin(cursor->fieldCount(), fieldsCount);
        for (int i = 0; i < realFieldCount; i++) {
            const int 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 KDbBLOBEscapingType enum...
                    APPEND(textQuote + KDb::escapeBLOB(cursor->value(real_i).toByteArray(), KDb::BLOBEscapeHex) + textQuote);
                else
                    APPEND(KDb::escapeBLOB(cursor->value(real_i).toByteArray(), KDb::BLOBEscapeHex));
            } else {//other types
                APPEND(cursor->value(real_i).toString());
            }
        }
        APPEND_EOLN
    }

    if (copyToClipboard)
        buffer.squeeze();

    if (!conn->deleteCursor(cursor)) {
        handler.showErrorMessage(conn->result());
        _ERR;
    }

    if (copyToClipboard)
        QApplication::clipboard()->setText(buffer, QClipboard::Clipboard);

    qDebug() << "Done";

    if (kSaveFile) {
        stream->flush();
        if (!kSaveFile->commit()) {
            qWarning() << "Error commiting the file" << kSaveFile->fileName();
        }
    }
    return true;
}