QStringList OtamaGenerator::generateViews(const QString &dstDir) const
{
    QStringList files;

    if (primaryKeyIndex < 0) {
        qWarning("Primary key not found. [view name: %s]", qPrintable(viewName));
        return files;
    }

    QDir dir(dstDir);
    FileWriter fw;
    QString output;
    QString caption = enumNameToCaption(viewName);
    QString varName = enumNameToVariableName(viewName);
    const QPair<QString, QVariant::Type> &pkFld = fieldList[primaryKeyIndex];

    // Generates index.html
    QString th ,td, indexOtm, showColumn, showOtm, entryColumn, editColumn, entryOtm, editOtm;
    for (int i = 0; i < fieldList.count(); ++i) {
        const QPair<QString, QVariant::Type> &p = fieldList[i];
        QString cap = fieldNameToCaption(p.first);
        QString var = fieldNameToVariableName(p.first);
        QString mrk = p.first.toLower();
        QString readonly;

        if (!excludedColumn.contains(var, Qt::CaseInsensitive)) {
            th += "    <th>";
            th += cap;
            th += "</th>\n";

            td += "    <td data-tf=\"@";
            td += mrk;
            td += "\"></td>\n";

            indexOtm += QString("@%1 ~= i.%2()\n\n").arg(mrk, var);

            if (i != autoValueIndex) {  // case of not auto-value field
                entryColumn += QString("  <p>\n    <label>%1<br /><input data-tf=\"@%2\" /></label>\n  </p>\n").arg(cap, mrk);
                entryOtm += QString("@%1 |== inputTextTag(\"%2[%3]\", %2[\"%3\"].toString())\n\n").arg(mrk, varName, var);
            }

            editColumn += QString("  <p>\n    <label>%1<br /><input data-tf=\"@%2\" /></label>\n  </p>\n").arg(cap, mrk);
            if  (p.first == pkFld.first) {
                readonly = QLatin1String(", a(\"readonly\", \"readonly\")");
            }
            editOtm += QString("@%1 |== inputTextTag(\"%2[%3]\", %2[\"%3\"].toString()%4);\n\n").arg(mrk, varName, var, readonly);
        }
        showColumn += QString("<dt>%1</dt><dd data-tf=\"@%2\">(%3)</dd><br />\n").arg(cap, mrk, var);
        showOtm += QString("@%1 ~= %2.%3()\n\n").arg(mrk, varName, var);
    }

    output = QString(INDEX_HTML_TEMPLATE).arg(caption, th, td);
    fw.setFilePath(dir.filePath("index.html"));
    if (fw.write(output, false)) {
        files << fw.fileName();
    }

    // Generates index.otm
    QString pkVarName = fieldNameToVariableName(pkFld.first);
    output = QString(INDEX_OTM_TEMPLATE).arg(varName.toLower(), viewName, varName, indexOtm, pkVarName);
    fw.setFilePath(dir.filePath("index.otm"));
    if (fw.write(output, false)) {
        files << fw.fileName();
    }

    // Generates show.html
    output = QString(SHOW_HTML_TEMPLATE).arg(caption, showColumn);
    fw.setFilePath(dir.filePath("show.html"));
    if (fw.write(output, false)) {
        files << fw.fileName();
    }

    // Generates show.otm
    output = QString(SHOW_OTM_TEMPLATE).arg(varName.toLower(), viewName, varName, showOtm, pkVarName);
    fw.setFilePath(dir.filePath("show.otm"));
    if (fw.write(output, false)) {
        files << fw.fileName();
    }

    // Generates entry.html
    output = QString(ENTRY_HTML_TEMPLATE).arg(caption, entryColumn);
    fw.setFilePath(dir.filePath("entry.html"));
    if (fw.write(output, false)) {
        files << fw.fileName();
    }

    // Generates entry.otm
    output = QString(ENTRY_OTM_TEMPLATE).arg(varName.toLower(), varName, entryOtm);
    fw.setFilePath(dir.filePath("entry.otm"));
    if (fw.write(output, false)) {
        files << fw.fileName();
    }

    // Generates edit.html
    output = QString(EDIT_HTML_TEMPLATE).arg(caption, editColumn);
    fw.setFilePath(dir.filePath("edit.html"));
    if (fw.write(output, false)) {
        files << fw.fileName();
    }

    // Generates edit.otm
    output = QString(EDIT_OTM_TEMPLATE).arg(varName.toLower(), varName, pkVarName, editOtm);
    fw.setFilePath(dir.filePath("edit.otm"));
    if (fw.write(output, false)) {
        files << fw.fileName();
    }

    return files;
}
bool ControllerGenerator::generate(const QString &dstDir) const
{
    // Reserved word check
    if (ngCtlrName()->contains(tableName.toLower())) {
        qCritical("Reserved word error. Please use another word.  Controller name: %s", qPrintable(tableName));
        return false;
    }

    QDir dir(dstDir);
    QStringList files;
    FileWriter fwh(dir.filePath(controllerName.toLower() + "controller.h"));
    FileWriter fws(dir.filePath(controllerName.toLower() + "controller.cpp"));

    if (actionList.isEmpty()) {
        if (fieldList.isEmpty()) {
            qCritical("Incorrect parameters.");
            return false;
        }

        QPair<QString, QVariant::Type> pair;
        if (primaryKeyIndex >= 0)
            pair = fieldList[primaryKeyIndex];

        // Generates a controller source code
        QString sessInsertStr;
        QString sessGetStr;
        QString revStr;
        QString varName = enumNameToVariableName(controllerName);

        // Generates a controller header file
        QString code = QString(CONTROLLER_HEADER_FILE_TEMPLATE).arg(controllerName.toUpper(), controllerName, fieldNameToVariableName(pair.first));
        fwh.write(code, false);
        files << fwh.fileName();

        if (lockRevIndex >= 0) {
            sessInsertStr = QString("            session().insert(\"%1_lockRevision\", model.lockRevision());\n").arg(varName);
            sessGetStr = QString("        int rev = session().value(\"%1_lockRevision\").toInt();\n").arg(varName);
            revStr = QLatin1String(", rev");
        }

        code = QString(CONTROLLER_SOURCE_FILE_TEMPLATE).arg(controllerName.toLower(), controllerName, varName, convMethod()->value(pair.second).arg(fieldNameToVariableName(pair.first)), sessInsertStr, sessGetStr, revStr, fieldNameToVariableName(pair.first));
        fws.write(code, false);
        files << fws.fileName();

    } else {
        // Generates a controller header file
        QString actions;
        for (QStringListIterator i(actionList); i.hasNext(); ) {
            actions.append("    void ").append(i.next()).append("();\n");
        }

        QString code = QString(CONTROLLER_TINY_HEADER_FILE_TEMPLATE).arg(controllerName.toUpper(), controllerName, actions);
        fwh.write(code, false);
        files << fwh.fileName();

        // Generates a controller source code
        QString actimpl;
        for (QStringListIterator i(actionList); i.hasNext(); ) {
            actimpl.append("void ").append(controllerName).append("Controller::").append(i.next()).append("()\n{\n    // write code\n}\n\n");
        }
        code = QString(CONTROLLER_TINY_SOURCE_FILE_TEMPLATE).arg(controllerName.toLower(), controllerName, actimpl);
        fws.write(code, false);
        files << fws.fileName();
    }

    // Generates a project file
    ProjectFileGenerator progen(dir.filePath("controllers.pro"));
    return progen.add(files);
}