Beispiel #1
0
void SettingsTest::testMerge_data(){
  // Key names state which file(s) a key is set in (master, foo or bar). Value
  // is always in form "<file>-value" based on which file it is taken from.

  const QScopedPointer<QTemporaryFile> masterFile(
    QTemporaryFile::createLocalFile(":/testdata/merge/settings.ini"));
  QSettings master(masterFile->fileName(), QSettings::IniFormat);

  const QStringList settingsFiles = QStringList()
    << ":/testdata/merge/settings.d/bar.ini"
    << ":/testdata/merge/settings.d/foo.ini";

  SsuSettings::merge(&master, settingsFiles);

  QSettings expected(":/testdata/merge/merged.ini", QSettings::IniFormat);

  const QSet<QString> masterKeys = master.allKeys().toSet();
  const QSet<QString> expectedKeys = expected.allKeys().toSet();

  QTest::addColumn<bool>("keyIsMerged");
  QTest::addColumn<bool>("keyShouldBeMerged");
  QTest::addColumn<QString>("actualValue");
  QTest::addColumn<QString>("expectedValue");

  foreach (const QString &key, masterKeys + expectedKeys){
    QTest::newRow(qPrintable(key))
      << masterKeys.contains(key)
      << expectedKeys.contains(key)
      << master.value(key).toString()
      << expected.value(key).toString();
  }
}
void StateListener::slotStateChanged()
{
    // Get the current file. Are we on a temporary submit editor indicated by
    // temporary path prefix or does the file contains a hash, indicating a project
    // folder?
    State state;
    IDocument *currentDocument = EditorManager::currentDocument();
    if (!currentDocument) {
        state.currentFile.clear();
    } else {
        state.currentFile = currentDocument->filePath().toString();
        if (state.currentFile.isEmpty() || currentDocument->isTemporary())
            state.currentFile = VcsBasePlugin::source(currentDocument);
    }
    QScopedPointer<QFileInfo> currentFileInfo; // Instantiate QFileInfo only once if required.
    if (!state.currentFile.isEmpty()) {
        const bool isTempFile = state.currentFile.startsWith(QDir::tempPath());
        // Quick check: Does it look like a patch?
        const bool isPatch = state.currentFile.endsWith(QLatin1String(".patch"))
                             || state.currentFile.endsWith(QLatin1String(".diff"));
        if (isPatch) {
            // Patch: Figure out a name to display. If it is a temp file, it could be
            // Codepaster. Use the display name of the editor.
            state.currentPatchFile = state.currentFile;
            if (isTempFile)
                state.currentPatchFileDisplayName = displayNameOfEditor(state.currentPatchFile);
            if (state.currentPatchFileDisplayName.isEmpty()) {
                currentFileInfo.reset(new QFileInfo(state.currentFile));
                state.currentPatchFileDisplayName = currentFileInfo->fileName();
            }
        }
        // For actual version control operations on it:
        // Do not show temporary files and project folders ('#')
        if (isTempFile || state.currentFile.contains(QLatin1Char('#')))
            state.currentFile.clear();
    }

    // Get the file and its control. Do not use the file unless we find one
    IVersionControl *fileControl = 0;
    if (!state.currentFile.isEmpty()) {
        if (currentFileInfo.isNull())
            currentFileInfo.reset(new QFileInfo(state.currentFile));
        if (currentFileInfo->isDir()) {
            state.currentFile.clear();
            state.currentFileDirectory = currentFileInfo->absoluteFilePath();
        } else {
            state.currentFileDirectory = currentFileInfo->absolutePath();
            state.currentFileName = currentFileInfo->fileName();
        }
        fileControl = VcsManager::findVersionControlForDirectory(
                    state.currentFileDirectory,
                    &state.currentFileTopLevel);
        if (!fileControl)
            state.clearFile();
    }
    // Check for project, find the control
    IVersionControl *projectControl = 0;
    Project *currentProject = ProjectTree::currentProject();
    if (!currentProject)
        currentProject = SessionManager::startupProject();
    if (currentProject) {
        state.currentProjectPath = currentProject->projectDirectory().toString();
        state.currentProjectName = currentProject->displayName();
        projectControl = VcsManager::findVersionControlForDirectory(state.currentProjectPath,
                                                                    &state.currentProjectTopLevel);
        if (projectControl) {
            // If we have both, let the file's one take preference
            if (fileControl && projectControl != fileControl)
                state.clearProject();
        } else {
            state.clearProject(); // No control found
        }
    }
    // Assemble state and emit signal.
    IVersionControl *vc = fileControl;
    if (!vc)
        vc = projectControl;
    if (!vc)
        state.clearPatchFile(); // Need a repository to patch
    if (debug)
        qDebug() << state << (vc ? vc->displayName() : QLatin1String("No version control"));
    EditorManager::updateWindowTitles();
    emit stateChanged(state, vc);
}
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;
}