[Ktutorial-commits] SF.net SVN: ktutorial:[164] trunk/ktutorial/ktutorial-editor
Status: Alpha
Brought to you by:
danxuliu
|
From: <dan...@us...> - 2010-03-19 04:46:23
|
Revision: 164
http://ktutorial.svn.sourceforge.net/ktutorial/?rev=164&view=rev
Author: danxuliu
Date: 2010-03-19 04:46:11 +0000 (Fri, 19 Mar 2010)
Log Message:
-----------
Add JavascriptExporter to write the Javascript code used by KTutorial to create a tutorial.
Modified Paths:
--------------
trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt
trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt
Added Paths:
-----------
trunk/ktutorial/ktutorial-editor/src/serialization/
trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt
trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp
trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h
trunk/ktutorial/ktutorial-editor/tests/unit/serialization/
trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt
trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp
Modified: trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-16 06:24:53 UTC (rev 163)
+++ trunk/ktutorial/ktutorial-editor/src/CMakeLists.txt 2010-03-19 04:46:11 UTC (rev 164)
@@ -2,6 +2,7 @@
# In order to work, they must be compiled using -fPIC
add_definitions("-fPIC")
+add_subdirectory(serialization)
add_subdirectory(view)
include_directories(${KDE4_INCLUDES})
@@ -24,7 +25,7 @@
# As everything but a tiny initialization code is in a library, the build system
# for the tests can be easily set up.
kde4_add_library(ktutorial_editor ${ktutorial_editor_SRCS})
-target_link_libraries(ktutorial_editor ktutorial_editor_view)
+target_link_libraries(ktutorial_editor ktutorial_editor_serialization ktutorial_editor_view)
kde4_add_executable(ktutorial-editor main.cpp)
target_link_libraries(ktutorial-editor ktutorial_editor ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS})
Added: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt 2010-03-19 04:46:11 UTC (rev 164)
@@ -0,0 +1,9 @@
+include_directories(${KDE4_INCLUDES})
+
+set(ktutorial_editor_serialization_SRCS
+ JavascriptExporter.cpp
+)
+
+kde4_add_library(ktutorial_editor_serialization ${ktutorial_editor_serialization_SRCS})
+
+target_link_libraries(ktutorial_editor_serialization ktutorial_editor ${KDE4_LIBS})
Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/CMakeLists.txt
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ native
Added: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp 2010-03-19 04:46:11 UTC (rev 164)
@@ -0,0 +1,455 @@
+/***************************************************************************
+ * Copyright (C) 2010 by Daniel Calviño Sánchez *
+ * dan...@gm... *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include "JavascriptExporter.h"
+
+#include <QRegExp>
+#include <QStringList>
+
+#include "../Reaction.h"
+#include "../Step.h"
+#include "../Tutorial.h"
+#include "../WaitForComposed.h"
+#include "../WaitForEvent.h"
+#include "../WaitForNot.h"
+#include "../WaitForSignal.h"
+
+//public:
+
+JavascriptExporter::JavascriptExporter(): mIndentationLevel(0) {
+}
+
+QString JavascriptExporter::exportTutorial(Tutorial* tutorial) {
+ QString code;
+ mOut.setString(&code);
+
+ writeLicense(tutorial);
+ out() << "t = Kross.module(\"kdetranslation\");\n\n";
+ writeInformation(tutorial);
+ writeSetup(tutorial);
+ writeTearDown(tutorial);
+
+ foreach (Step* step, tutorial->steps()) {
+ writeStep(step);
+ }
+
+ mOut.setString(0);
+ return code;
+}
+
+//private:
+
+void JavascriptExporter::writeLicense(Tutorial* tutorial) {
+ if (tutorial->licenseText().isEmpty()) {
+ return;
+ }
+
+ QStringList lines = tutorial->licenseText().split('\n');
+ int maximumLineLength = 0;
+ foreach (QString line, lines) {
+ if (line.size() > maximumLineLength) {
+ maximumLineLength = line.size();
+ }
+ }
+
+ out() << "/****" << QString('*').repeated(maximumLineLength) << "****\n";
+ foreach (QString line, lines) {
+ int numberOfSpaces = maximumLineLength - line.length();
+ QString filling = QString(' ').repeated(numberOfSpaces);
+ out() << " * " + line + filling + " *\n";
+ }
+ out() << " ****" << QString('*').repeated(maximumLineLength) << "****/\n\n";
+}
+
+void JavascriptExporter::writeInformation(Tutorial* tutorial) {
+ if (tutorial->name().isEmpty()) {
+ out() << "//Error: Tutorial without name!\n";
+ } else {
+ out() << "tutorial.tutorialInformationAsObject().setName(t.i18n(\""
+ << tutorial->name() <<"\"));\n";
+ }
+
+ if (tutorial->description().isEmpty()) {
+ out() << "//Error: Tutorial without description!\n";
+ } else {
+ out() << "tutorial.tutorialInformationAsObject().setDescription("
+ << "t.i18n(\"" << tutorial->description() <<"\"));\n";
+ }
+
+ mOut << "\n";
+}
+
+void JavascriptExporter::writeSetup(Tutorial* tutorial) {
+ if (tutorial->customSetupCode().isEmpty()) {
+ return;
+ }
+
+ out() << "function tutorialSetup(tutorial) {\n";
+ mIndentationLevel++;
+ mOut << toIndentedCode(tutorial->customSetupCode());
+ mIndentationLevel--;
+ out() << "}\n";
+ out() << "connect(tutorial, \"setup(QObject*)\",\n"
+ << " this, \"tutorialSetup(QObject*)\");\n\n";
+}
+
+void JavascriptExporter::writeTearDown(Tutorial* tutorial) {
+ if (tutorial->customTearDownCode().isEmpty()) {
+ return;
+ }
+
+ out() << "function tutorialTearDown(tutorial) {\n";
+ mIndentationLevel++;
+ mOut << toIndentedCode(tutorial->customTearDownCode());
+ mIndentationLevel--;
+ out() << "}\n";
+ out() << "connect(tutorial, \"tearDown(QObject*)\",\n"
+ << " this, \"tutorialTearDown(QObject*)\");\n\n";
+}
+
+void JavascriptExporter::writeStep(Step* step) {
+ if (step->id().isEmpty()) {
+ out() << "//Error: Step without id!\n\n";
+ return;
+ }
+
+ out() << "//Step " << step->id() << "\n";
+
+ QString stepVariable = toLowerCamelCase(step->id()) + "Step";
+ out() << stepVariable << " = ktutorial.newStep(\"" << step->id()
+ << "\");\n";
+
+ if (step->text().isEmpty()) {
+ out() << "//Error: Step without text!\n";
+ } else {
+ out() << stepVariable << ".setText(t.i18nc(\"@info\", \""
+ << step->text() << "\"));\n";
+ }
+ mOut << '\n';
+
+ writeSetup(step);
+ writeTearDown(step);
+
+ out() << "tutorial.addStep(" << stepVariable << ");\n\n";
+}
+
+void JavascriptExporter::writeSetup(Step* step) {
+ if (step->customSetupCode().isEmpty() && step->reactions().count() == 0) {
+ return;
+ }
+
+ QString stepVariable = toLowerCamelCase(step->id()) + "Step";
+ out() << "function " << stepVariable << "Setup(step) {\n";
+ mIndentationLevel++;
+
+ for (int i=0; i<step->reactions().count(); ++i) {
+ Reaction* reaction = step->reactions()[i];
+ writeReaction(step, reaction);
+
+ if (i<step->reactions().count() - 1 ||
+ !step->customSetupCode().isEmpty()) {
+ mOut << '\n';
+ }
+ }
+
+ mOut << toIndentedCode(step->customSetupCode());
+ mIndentationLevel--;
+ out() << "}\n";
+ out() << "connect(" << stepVariable << ", \"setup(QObject*)\",\n"
+ << " this, \"" << stepVariable << "Setup(QObject*)\");\n\n";
+
+ foreach (QString function, mPendingFunctions) {
+ mOut << function << '\n';
+ }
+ mPendingFunctions.clear();
+ mVariables.clear();
+}
+
+void JavascriptExporter::writeTearDown(Step* step) {
+ if (step->customTearDownCode().isEmpty()) {
+ return;
+ }
+
+ QString stepVariable = toLowerCamelCase(step->id()) + "Step";
+ out() << "function " << stepVariable << "TearDown(step) {\n";
+ mIndentationLevel++;
+ mOut << toIndentedCode(step->customTearDownCode());
+ mIndentationLevel--;
+ out() << "}\n";
+ out() << "connect(" << stepVariable << ", \"tearDown(QObject*)\",\n"
+ << " this, \"" << stepVariable << "TearDown(QObject*)\");\n\n";
+}
+
+void JavascriptExporter::writeReaction(Step* step, Reaction* reaction) {
+ if (reaction->triggerType() == Reaction::ConditionMet &&
+ !reaction->waitFor()) {
+ out() << "//Error: WaitFor not set!\n";
+ return;
+ }
+
+ if (reaction->triggerType() == Reaction::OptionSelected &&
+ reaction->optionName().isEmpty()) {
+ out() << "//Error: Option without name!\n";
+ return;
+ }
+
+ if (reaction->responseType() == Reaction::NextStep &&
+ reaction->nextStepId().isEmpty()) {
+ out() << "//Error: Next step id not set!\n";
+ return;
+ }
+
+ if (reaction->triggerType() == Reaction::OptionSelected &&
+ reaction->responseType() == Reaction::NextStep) {
+ out() << "step.addOption(ktutorial.newOption(\""
+ << reaction->optionName() << "\"), \"" << reaction->nextStepId()
+ << "\");\n";
+ return;
+ }
+
+ if (reaction->triggerType() == Reaction::OptionSelected &&
+ reaction->responseType() == Reaction::CustomCode) {
+ QString functionName = toLowerCamelCase(step->id()) + "Step" +
+ toUpperCamelCase(reaction->optionName()) +
+ "OptionSelected";
+ out() << "step.addOption(ktutorial.newOption(\""
+ << reaction->optionName() << "\"), self, \"" << functionName
+ << "()\");\n";
+ addFunction(functionName, reaction->customCode());
+ return;
+ }
+
+ QString variableName = writeWaitFor(reaction->waitFor());
+ if (variableName.isEmpty()) {
+ return;
+ }
+
+ if (reaction->responseType() == Reaction::NextStep) {
+ out() << "step.addWaitFor(" << variableName << ", \""
+ << reaction->nextStepId() << "\");\n";
+ return;
+ }
+
+ QString functionName = toLowerCamelCase(step->id()) + "Step" +
+ toUpperCamelCase(variableName) + "ConditionMet";
+ out() << "step.addWaitFor(" << variableName << ", self, \""
+ << functionName << "()\");\n";
+ addFunction(functionName, reaction->customCode());
+}
+
+QString JavascriptExporter::writeWaitFor(WaitFor* waitFor) {
+ if (qobject_cast<WaitForComposed*>(waitFor)) {
+ return writeWaitFor(static_cast<WaitForComposed*>(waitFor));
+ }
+ if (qobject_cast<WaitForEvent*>(waitFor)) {
+ return writeWaitFor(static_cast<WaitForEvent*>(waitFor));
+ }
+ if (qobject_cast<WaitForNot*>(waitFor)) {
+ return writeWaitFor(static_cast<WaitForNot*>(waitFor));
+ }
+ if (qobject_cast<WaitForSignal*>(waitFor)) {
+ return writeWaitFor(static_cast<WaitForSignal*>(waitFor));
+ }
+
+ return "";
+}
+
+QString JavascriptExporter::writeWaitFor(WaitForComposed* waitForComposed) {
+ QString type;
+ if (waitForComposed->compositionType() == WaitForComposed::And) {
+ type = "And";
+ } else if (waitForComposed->compositionType() == WaitForComposed::Or) {
+ type = "Or";
+ }
+
+ QStringList childVariables;
+ foreach (WaitFor* waitFor, waitForComposed->waitFors()) {
+ childVariables.append(writeWaitFor(waitFor));
+ mOut << '\n';
+ }
+
+ QString variable = addVariable("waitFor" + type);
+ out() << variable << " = ktutorial.newWaitFor(\"WaitFor" << type
+ << "\");\n";
+ foreach (QString childVariable, childVariables) {
+ if (!childVariable.isEmpty()) {
+ out() << variable << ".add(" << childVariable << ");\n";
+ }
+ }
+
+ return variable;
+}
+
+QString JavascriptExporter::writeWaitFor(WaitForEvent* waitForEvent) {
+ if (waitForEvent->receiverName().isEmpty()) {
+ out() << "//Error: WaitForEvent without receiver name!\n";
+ return "";
+ }
+
+ if (waitForEvent->eventName().isEmpty()) {
+ out() << "//Error: WaitForEvent without event name!\n";
+ return "";
+ }
+
+ QString variable = "waitFor" + toUpperCamelCase(waitForEvent->eventName()) +
+ "In" + toUpperCamelCase(waitForEvent->receiverName());
+ variable = addVariable(variable);
+
+ out() << variable << " = ktutorial.newWaitFor(\"WaitForEvent\");\n";
+ out() << variable << ".setEvent(ktutorial.findObject(\""
+ << waitForEvent->receiverName() << "\"), \""
+ << waitForEvent->eventName() << "\");\n";
+
+ return variable;
+}
+
+QString JavascriptExporter::writeWaitFor(WaitForNot* waitForNot) {
+ if (!waitForNot->negatedWaitFor()) {
+ out() << "//Error: WaitForNot without negated WaitFor!\n";
+ return "";
+ }
+
+ QString variable = addVariable("waitForNot");
+ QString negatedVariable = writeWaitFor(waitForNot->negatedWaitFor());
+
+ mOut << '\n';
+ out() << variable << " = ktutorial.newWaitFor(\"WaitForNot\");\n";
+ if (!negatedVariable.isEmpty()) {
+ out() << variable << ".setNegatedWaitFor(" << negatedVariable << ");\n";
+ }
+
+ return variable;
+}
+
+QString JavascriptExporter::writeWaitFor(WaitForSignal* waitForSignal) {
+ if (waitForSignal->emitterName().isEmpty()) {
+ out() << "//Error: WaitForSignal without emitter name!\n";
+ return "";
+ }
+
+ if (waitForSignal->signalName().isEmpty()) {
+ out() << "//Error: WaitForSignal without signal name!\n";
+ return "";
+ }
+
+ QString signalName = waitForSignal->signalName();
+ signalName.remove(QRegExp("\\(.*"));
+ QString variable = "waitFor" + toUpperCamelCase(signalName) +
+ "By" + toUpperCamelCase(waitForSignal->emitterName());
+ variable = addVariable(variable);
+
+ out() << variable << " = ktutorial.newWaitFor(\"WaitForSignal\");\n";
+ out() << variable << ".setSignal(ktutorial.findObject(\""
+ << waitForSignal->emitterName() << "\"), \""
+ << waitForSignal->signalName() << "\");\n";
+
+ return variable;
+}
+
+QTextStream& JavascriptExporter::out() {
+ mOut << indentation();
+ return mOut;
+}
+
+QString JavascriptExporter::indentation() {
+ QString text;
+ for (int i=0; i<mIndentationLevel; ++i) {
+ text += " ";
+ }
+
+ return text;
+}
+
+void JavascriptExporter::addFunction(const QString& functionName,
+ const QString& code) {
+ int previousIndentationLevel = mIndentationLevel;
+ mIndentationLevel = 0;
+
+ QString function;
+ function += "function " + functionName + "() {\n";
+ mIndentationLevel++;
+ if (code.isEmpty()) {
+ function += toIndentedCode("//Error: No code set!\n");
+ } else {
+ function += toIndentedCode(code);
+ }
+ mIndentationLevel--;
+ function += "}\n";
+
+ mPendingFunctions.append(function);
+
+ mIndentationLevel = previousIndentationLevel;
+}
+
+QString JavascriptExporter::addVariable(const QString& variable) {
+ if (!mVariables.contains(variable)) {
+ mVariables.insert(variable, 1);
+ return variable;
+ }
+
+ mVariables.insert(variable, mVariables.value(variable) + 1);
+ return variable + QString().setNum(mVariables.value(variable));
+}
+
+QString JavascriptExporter::toIndentedCode(const QString& code) {
+ if (code.isEmpty()) {
+ return "";
+ }
+
+ QString indentedCode;
+
+ QStringList lines = code.split('\n');
+ for (int i=0; i<lines.count()-1; ++i) {
+ indentedCode += indentation() + lines[i] + '\n';
+ }
+
+ //If the code ends with '\n', the splitted code will contain an empty end
+ //element that should be ignored
+ if (!code.endsWith('\n')) {
+ indentedCode += indentation() + lines[lines.count()-1] + '\n';
+ }
+
+ return indentedCode;
+}
+
+QString JavascriptExporter::toLowerCamelCase(const QString& text) const {
+ if (text.isEmpty()) {
+ return "";
+ }
+
+ QString lowerCamelCase = toUpperCamelCase(text);
+ lowerCamelCase[0] = lowerCamelCase[0].toLower();
+
+ return lowerCamelCase;
+}
+
+QString JavascriptExporter::toUpperCamelCase(const QString& text) const {
+ if (text.isEmpty()) {
+ return "";
+ }
+
+ QStringList words = text.split(' ', QString::SkipEmptyParts);
+
+ QString upperCamelCase;
+ for (int i=0; i<words.count(); ++i) {
+ words[i][0] = words[i][0].toUpper();
+ upperCamelCase += words[i];
+ }
+
+ return upperCamelCase;
+}
Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.cpp
___________________________________________________________________
Added: svn:eol-style
+ native
Added: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h
===================================================================
--- trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h (rev 0)
+++ trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h 2010-03-19 04:46:11 UTC (rev 164)
@@ -0,0 +1,292 @@
+/***************************************************************************
+ * Copyright (C) 2010 by Daniel Calviño Sánchez *
+ * dan...@gm... *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifndef JAVASCRIPTEXPORTER_H
+#define JAVASCRIPTEXPORTER_H
+
+#include <QHash>
+#include <QStringList>
+#include <QTextStream>
+
+class Reaction;
+class Step;
+class Tutorial;
+class WaitFor;
+class WaitForComposed;
+class WaitForEvent;
+class WaitForNot;
+class WaitForSignal;
+
+/**
+ * Exporter of tutorials to Javascript code.
+ * The generated Javascript code can be read by KTutorial from a tutorial script
+ * file to create and initialize a KTutorial::Tutorial from it.
+ *
+ * The general structure of the code is:
+ * -License (if any)
+ * -Tutorial information
+ * -Tutorial setup (if any)
+ * -Tutorial tear down (if any)
+ * -Steps
+ *
+ * For each step, the following structure is used:
+ * -Step initialization (id and text)
+ * -Step setup
+ * -Reactions (if any)
+ * -Custom setup code (if any)
+ * -Functions for each custom code response in the reactions (if any)
+ * -Step tear down (if any)
+ *
+ * If some necessary data is missing (for example, the id in a step), a comment
+ * explaining the error is written instead of the code for that element.
+ */
+class JavascriptExporter {
+public:
+
+ /**
+ * Creates a new JavascriptExporter.
+ */
+ JavascriptExporter();
+
+ /**
+ * Exports the tutorial to Javascript code.
+ *
+ * @param tutorial The tutorial to export.
+ * @return The Javascript code.
+ */
+ QString exportTutorial(Tutorial* tutorial);
+
+private:
+
+ /**
+ * The text stream to write the Javascript code to.
+ */
+ QTextStream mOut;
+
+ /**
+ * The full code for the functions pending to be written.
+ */
+ QStringList mPendingFunctions;
+
+ /**
+ * Register for variable names and the number of times that it was used.
+ */
+ QHash<QString, int> mVariables;
+
+ /**
+ * The curren indentation level.
+ * Increment and decrement it when entering and exiting a code block.
+ */
+ int mIndentationLevel;
+
+ /**
+ * Writes the commented license text.
+ * Nothing is written if there is no license.
+ *
+ * @param tutorial The tutorial to write its license.
+ */
+ void writeLicense(Tutorial* tutorial);
+
+ /**
+ * Writes the name and description code of a tutorial.
+ * An error message is written if the name or the tutorial is missing.
+ *
+ * @param tutorial The tutorial to write its name and description code.
+ */
+ void writeInformation(Tutorial* tutorial);
+
+ /**
+ * Writes the setup function of a tutorial and its custom code.
+ * Nothing is written if there is no setup code.
+ *
+ * @param tutorial The tutorial to write its setup function.
+ */
+ void writeSetup(Tutorial* tutorial);
+
+ /**
+ * Writes the tear down function of a tutorial and its custom code.
+ * Nothing is written if there is no tear down code.
+ *
+ * @param tutorial The tutorial to write its tear down function.
+ */
+ void writeTearDown(Tutorial* tutorial);
+
+ /**
+ * Writes the full code (step creation, setup, tear down and adding to the
+ * tutorial) of a step.
+ * If the step id isn't set, an error message is written instead.
+ *
+ * @param step The step to write its code.
+ */
+ void writeStep(Step* step);
+
+ /**
+ * Writes the setup code (including setting up reactions) of a Step.
+ * Nothing is written if there is no custom setup code and no reactions.
+ *
+ * After the setup code all the pending functions added by custom code
+ * responses in reactions are written.
+ *
+ * @param step The step to write its setup code.
+ */
+ void writeSetup(Step* step);
+
+ /**
+ * Writes the tear down code of a Step.
+ * Nothing is written if there is no tear down code.
+ *
+ * @param step The step to write its tear down code.
+ */
+ void writeTearDown(Step* step);
+
+ /**
+ * Writes the reaction code.
+ * An error message is written if the WaitFor, the option name or the next
+ * step id is not set (and the trigger/response type needed them).
+ *
+ * @param step The step that the reaction is part of.
+ * @param reaction The reaction to write its code.
+ */
+ void writeReaction(Step* step, Reaction* reaction);
+
+ /**
+ * Writes the code to create and set a WaitFor.
+ *
+ * @param waitFor The WaitFor.
+ * @return The name of the variable that holds the WaitFor, or an empty
+ * string if the WaitFor data is invalid.
+ */
+ QString writeWaitFor(WaitFor* waitFor);
+
+ /**
+ * Writes the code to create and set a WaitForComposed.
+ * The code for the child WaitFors is added before the code for the
+ * WaitForComposed.
+ *
+ * @param waitForComposed The WaitForComposed.
+ * @return The name of the variable that holds the WaitFor.
+ */
+ QString writeWaitFor(WaitForComposed* waitForComposed);
+
+ /**
+ * Writes the code to create and set a WaitForEvent.
+ * If the receiver name or the event name aren't set, an error message is
+ * written instead, and an empty string returned.
+ *
+ * @param waitForEvent The WaitForEvent.
+ * @return The name of the variable that holds the WaitFor.
+ */
+ QString writeWaitFor(WaitForEvent* waitForEvent);
+
+ /**
+ * Writes the code to create and set a WaitForNot.
+ * If the negated WaitFor isn't set, an error message is written instead,
+ * and an empty string returned.
+ *
+ * @param waitForNot The WaitForNot.
+ * @return The name of the variable that holds the WaitFor.
+ */
+ QString writeWaitFor(WaitForNot* waitForNot);
+
+ /**
+ * Writes the code to create and set a WaitForSignal.
+ * If the emitter name or the signal name aren't set, an error message is
+ * written instead, and an empty string returned.
+ *
+ * @param waitForSignal The WaitForSignal.
+ * @return The name of the variable that holds the WaitFor.
+ */
+ QString writeWaitFor(WaitForSignal* waitForSignal);
+
+ /**
+ * Returns the output stream after adding the identation text.
+ * It is used as a shortcut to "mOut << indentation()". Use it to output any
+ * line that has no previous indentation.
+ *
+ * Use mOut directly to output empty new lines, pending functions, or code
+ * returned by indentedText
+ *
+ * @return The output stream.
+ */
+ QTextStream& out();
+
+ /**
+ * Returns the current indentation text.
+ * Each level of indentation are four blank spaces.
+ *
+ @return The current indentation text.
+ */
+ QString indentation();
+
+ /**
+ * Adds a new function to mPendingFunctions.
+ * The body will be automatically indented.
+ *
+ * It is used to queue the writting of functions with custom code specified
+ * in reactions, as reactions are written into the setup function of its
+ * step.
+ *
+ * @param functionName The name of the function.
+ * @param code The body of the function.
+ */
+ void addFunction(const QString& functionName, const QString& code);
+
+ /**
+ * Returns a unique variable name for the given variable name.
+ * The same variable name may be used by several WaitFors in the same step
+ * setup (for example, two WaitForAnd would have the same variable name).
+ * When a variable is added, it is ensured that there are no other variables
+ * with the same name. If there are, a fixed unique variable name is
+ * returned.
+ *
+ * The register of variables must be cleared after exiting the step setup
+ * generation to avoid unneeded renaming of variables in other step setups.
+ *
+ * @param variable The variable to add.
+ * @return The unique variable name.
+ */
+ QString addVariable(const QString& variable);
+
+ /**
+ * Returns the same code, but with each line indented and ending in a new
+ * line.
+ *
+ * @param code The code to indent.
+ * @return The indented code.
+ */
+ QString toIndentedCode(const QString& code);
+
+ /**
+ * Returns the lowerCamelCase version of the given text.
+ *
+ * @param text The string to get its lowerCamelCase version.
+ * @return The lowerCamelCase version of the text.
+ */
+ QString toLowerCamelCase(const QString& text) const;
+
+ /**
+ * Returns the UpperCamelCase version of the given text.
+ *
+ * @param text The string to get its UpperCamelCase version.
+ * @return The UpperCamelCase version of the text.
+ */
+ QString toUpperCamelCase(const QString& text) const;
+
+};
+
+#endif
Property changes on: trunk/ktutorial/ktutorial-editor/src/serialization/JavascriptExporter.h
___________________________________________________________________
Added: svn:eol-style
+ native
Modified: trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt
===================================================================
--- trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-16 06:24:53 UTC (rev 163)
+++ trunk/ktutorial/ktutorial-editor/tests/unit/CMakeLists.txt 2010-03-19 04:46:11 UTC (rev 164)
@@ -1,3 +1,4 @@
+add_subdirectory(serialization)
add_subdirectory(view)
# Used by kde4_add_unit_test to set the full path to test executables
Added: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt
===================================================================
--- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt (rev 0)
+++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt 2010-03-19 04:46:11 UTC (rev 164)
@@ -0,0 +1,26 @@
+# Used by kde4_add_unit_test to set the full path to test executables
+set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${ktutorial-editor_SOURCE_DIR}/src/serialization ${ktutorial-editor_BINARY_DIR}/src/serialization ${KDE4_INCLUDES})
+
+MACRO(UNIT_TESTS)
+ FOREACH(_className ${ARGN})
+ set(_testName ${_className}Test)
+ kde4_add_unit_test(${_testName} TESTNAME ktutorial-editor-unit-${_testName} ${_testName}.cpp)
+ target_link_libraries(${_testName} ktutorial_editor ktutorial_editor_serialization ${QT_QTTEST_LIBRARY})
+ ENDFOREACH(_className)
+ENDMACRO(UNIT_TESTS)
+
+unit_tests(
+ JavascriptExporter
+)
+
+MACRO(MEM_TESTS)
+ FOREACH(_testname ${ARGN})
+ add_test(ktutorial-editor-unit-mem-${_testname} ${CMAKE_CURRENT_SOURCE_DIR}/../runMemcheck.py ${CMAKE_CURRENT_BINARY_DIR}/${_testname}Test ${CMAKE_CURRENT_BINARY_DIR})
+ ENDFOREACH(_testname)
+ENDMACRO(MEM_TESTS)
+
+mem_tests(
+ JavascriptExporter
+)
Property changes on: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/CMakeLists.txt
___________________________________________________________________
Added: svn:executable
+ *
Added: svn:eol-style
+ native
Added: trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp
===================================================================
--- trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp (rev 0)
+++ trunk/ktutorial/ktutorial-editor/tests/unit/serialization/JavascriptExporterTest.cpp 2010-03-19 04:46:11 UTC (rev 164)
@@ -0,0 +1,1167 @@
+/***************************************************************************
+ * Copyright (C) 2010 by Daniel Calviño Sánchez *
+ * dan...@gm... *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; If not, see <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#include <QtTest>
+
+#include "JavascriptExporter.h"
+
+#include "../Reaction.h"
+#include "../Step.h"
+#include "../Tutorial.h"
+#include "../WaitForComposed.h"
+#include "../WaitForEvent.h"
+#include "../WaitForNot.h"
+#include "../WaitForSignal.h"
+
+#define TUTORIAL_EMPTY_INFORMATION_CODE \
+"t = Kross.module(\"kdetranslation\");\n"\
+"\n"\
+"//Error: Tutorial without name!\n"\
+"//Error: Tutorial without description!\n"\
+"\n"
+
+#define STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE \
+"//Step The id\n"\
+"theIdStep = ktutorial.newStep(\"The id\");\n"\
+"//Error: Step without text!\n"\
+"\n"
+
+#define CONNECT_STEP_SETUP \
+"connect(theIdStep, \"setup(QObject*)\",\n"\
+" this, \"theIdStepSetup(QObject*)\");\n"\
+"\n"
+
+#define STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE \
+"tutorial.addStep(theIdStep);\n"\
+"\n"
+
+class JavascriptExporterTest: public QObject {
+Q_OBJECT
+
+private slots:
+
+ void testTutorialLicense();
+ void testTutorialInformation();
+ void testTutorialSetupCode();
+ void testTutorialTearDownCode();
+ void testTutorialWithSeveralSteps();
+
+ void testStep();
+ void testStepSetupCode();
+ void testStepSetupCodeWithReactions();
+ void testStepTearDownCode();
+ void testStepWithoutId();
+ void testStepWithSeveralReactions();
+
+ void testReactionOptionNextStep();
+ void testReactionOptionNextStepWithoutOptionNameOrStepId();
+ void testReactionOptionCustomCode();
+ void testReactionOptionCustomCodeWithoutOptionNameOrCustomCode();
+ void testReactionConditionNextStep();
+ void testReactionConditionNextStepWithoutConditionOrStepId();
+ void testReactionConditionCustomCode();
+ void testReactionConditionCustomCodeWithoutConditionOrCustomCode();
+
+ void testWaitForEvent();
+ void testWaitForEventWithoutReceiverNameOrEventName();
+ void testWaitForSignal();
+ void testWaitForSignalWithoutEmitterNameOrSignalName();
+ void testWaitForComposed();
+ void testWaitForComposedWithInvalidChildWaitFor();
+ void testWaitForNot();
+ void testWaitForNotWithInvalidNegatedWaitFor();
+ void testWaitForNotWithoutNegatedWaitFor();
+
+};
+
+void JavascriptExporterTest::testTutorialLicense() {
+ Tutorial tutorial;
+ tutorial.setLicenseText("The license text, which should be\nwrapped");
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+"/*****************************************\n"
+" * The license text, which should be *\n"
+" * wrapped *\n"
+" *****************************************/\n"
+"\n"
+TUTORIAL_EMPTY_INFORMATION_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testTutorialInformation() {
+ Tutorial tutorial;
+ tutorial.setName("The name");
+ tutorial.setDescription("The description");
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+"t = Kross.module(\"kdetranslation\");\n"
+"\n"
+"tutorial.tutorialInformationAsObject().setName(t.i18n(\"The name\"));\n"
+"tutorial.tutorialInformationAsObject().setDescription("
+ "t.i18n(\"The description\"));\n"
+"\n";
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testTutorialSetupCode() {
+ Tutorial tutorial;
+ tutorial.setCustomSetupCode("The custom setup\ncode");
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+"function tutorialSetup(tutorial) {\n"
+" The custom setup\n"
+" code\n"
+"}\n"
+"connect(tutorial, \"setup(QObject*)\",\n"
+" this, \"tutorialSetup(QObject*)\");\n"
+"\n";
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testTutorialTearDownCode() {
+ Tutorial tutorial;
+ tutorial.setCustomTearDownCode("The custom tear down\ncode");
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+"function tutorialTearDown(tutorial) {\n"
+" The custom tear down\n"
+" code\n"
+"}\n"
+"connect(tutorial, \"tearDown(QObject*)\",\n"
+" this, \"tutorialTearDown(QObject*)\");\n"
+"\n";
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testTutorialWithSeveralSteps() {
+ Tutorial tutorial;
+
+ Step* step1 = new Step();
+ step1->setId("The id1");
+ step1->setText("The text1");
+ tutorial.addStep(step1);
+
+ WaitForSignal* waitForSignal1 = new WaitForSignal();
+ waitForSignal1->setEmitterName("The emitter name");
+ waitForSignal1->setSignalName("theSignalName(Argument1Type)");
+
+ Reaction* reaction1 = new Reaction();
+ reaction1->setTriggerType(Reaction::ConditionMet);
+ reaction1->setWaitFor(waitForSignal1);
+ reaction1->setResponseType(Reaction::CustomCode);
+ reaction1->setCustomCode("The custom\ncode1");
+ step1->addReaction(reaction1);
+
+ Step* step2 = new Step();
+ step2->setId("The id2");
+ step2->setText("The text2");
+ tutorial.addStep(step2);
+
+ WaitForSignal* waitForSignal2 = new WaitForSignal();
+ waitForSignal2->setEmitterName("The emitter name");
+ waitForSignal2->setSignalName("theSignalName(Argument1Type)");
+
+ Reaction* reaction2 = new Reaction();
+ reaction2->setTriggerType(Reaction::ConditionMet);
+ reaction2->setWaitFor(waitForSignal2);
+ reaction2->setResponseType(Reaction::CustomCode);
+ reaction2->setCustomCode("The custom\ncode2");
+ step2->addReaction(reaction2);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+"//Step The id1\n"
+"theId1Step = ktutorial.newStep(\"The id1\");\n"
+"theId1Step.setText(t.i18nc(\"@info\", \"The text1\"));\n"
+"\n"
+"function theId1StepSetup(step) {\n"
+" waitForTheSignalNameByTheEmitterName = \
+ktutorial.newWaitFor(\"WaitForSignal\");\n"
+" waitForTheSignalNameByTheEmitterName.setSignal(\
+ktutorial.findObject(\"The emitter name\"), \
+\"theSignalName(Argument1Type)\");\n"
+" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \
+\"theId1StepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n"
+"}\n"
+"connect(theId1Step, \"setup(QObject*)\",\n"
+" this, \"theId1StepSetup(QObject*)\");\n"
+"\n"
+"function theId1StepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n"
+" The custom\n"
+" code1\n"
+"}\n"
+"\n"
+"tutorial.addStep(theId1Step);\n"
+"\n"
+"//Step The id2\n"
+"theId2Step = ktutorial.newStep(\"The id2\");\n"
+"theId2Step.setText(t.i18nc(\"@info\", \"The text2\"));\n"
+"\n"
+"function theId2StepSetup(step) {\n"
+" waitForTheSignalNameByTheEmitterName = \
+ktutorial.newWaitFor(\"WaitForSignal\");\n"
+" waitForTheSignalNameByTheEmitterName.setSignal(\
+ktutorial.findObject(\"The emitter name\"), \
+\"theSignalName(Argument1Type)\");\n"
+" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \
+\"theId2StepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n"
+"}\n"
+"connect(theId2Step, \"setup(QObject*)\",\n"
+" this, \"theId2StepSetup(QObject*)\");\n"
+"\n"
+"function theId2StepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n"
+" The custom\n"
+" code2\n"
+"}\n"
+"\n"
+"tutorial.addStep(theId2Step);\n"
+"\n";
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testStep() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ step->setText("The text");
+ tutorial.addStep(step);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+"//Step The id\n"
+"theIdStep = ktutorial.newStep(\"The id\");\n"
+"theIdStep.setText(t.i18nc(\"@info\", \"The text\"));\n"
+"\n"
+"tutorial.addStep(theIdStep);\n"
+"\n";
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testStepSetupCode() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ step->setCustomSetupCode("The custom setup\ncode");
+ tutorial.addStep(step);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" The custom setup\n"
+" code\n"
+"}\n"
+"connect(theIdStep, \"setup(QObject*)\",\n"
+" this, \"theIdStepSetup(QObject*)\");\n"
+"\n"
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testStepSetupCodeWithReactions() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ step->setCustomSetupCode("The custom setup\ncode");
+ tutorial.addStep(step);
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::OptionSelected);
+ reaction->setOptionName("The option name");
+ reaction->setResponseType(Reaction::NextStep);
+ reaction->setNextStepId("Another step");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" step.addOption(ktutorial.newOption(\"The option name\"), \
+\"Another step\");\n"
+"\n"
+" The custom setup\n"
+" code\n"
+"}\n"
+"connect(theIdStep, \"setup(QObject*)\",\n"
+" this, \"theIdStepSetup(QObject*)\");\n"
+"\n"
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testStepTearDownCode() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ step->setCustomTearDownCode("The custom tear down\ncode");
+ tutorial.addStep(step);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepTearDown(step) {\n"
+" The custom tear down\n"
+" code\n"
+"}\n"
+"connect(theIdStep, \"tearDown(QObject*)\",\n"
+" this, \"theIdStepTearDown(QObject*)\");\n"
+"\n"
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testStepWithoutId() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setText("The text");
+ step->setCustomSetupCode("The custom setup\ncode");
+ step->setCustomTearDownCode("The custom tear down\ncode");
+ tutorial.addStep(step);
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::OptionSelected);
+ reaction->setOptionName("The option name");
+ reaction->setResponseType(Reaction::NextStep);
+ reaction->setNextStepId("Another step");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+"//Error: Step without id!\n"
+"\n";
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testStepWithSeveralReactions() {
+ Tutorial tutorial;
+
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ WaitForSignal* waitForSignal = new WaitForSignal();
+ waitForSignal->setEmitterName("The emitter name");
+ waitForSignal->setSignalName("theSignalName(Argument1Type)");
+
+ Reaction* reaction1 = new Reaction();
+ reaction1->setTriggerType(Reaction::ConditionMet);
+ reaction1->setWaitFor(waitForSignal);
+ reaction1->setResponseType(Reaction::CustomCode);
+ reaction1->setCustomCode("The custom\ncode1");
+ step->addReaction(reaction1);
+
+ Reaction* reaction2 = new Reaction();
+ reaction2->setTriggerType(Reaction::OptionSelected);
+ reaction2->setOptionName("The option name");
+ reaction2->setResponseType(Reaction::CustomCode);
+ reaction2->setCustomCode("The custom\ncode2");
+ step->addReaction(reaction2);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" waitForTheSignalNameByTheEmitterName = \
+ktutorial.newWaitFor(\"WaitForSignal\");\n"
+" waitForTheSignalNameByTheEmitterName.setSignal(\
+ktutorial.findObject(\"The emitter name\"), \
+\"theSignalName(Argument1Type)\");\n"
+" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \
+\"theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n"
+"\n"
+" step.addOption(ktutorial.newOption(\"The option name\"), self, \
+\"theIdStepTheOptionNameOptionSelected()\");\n"
+"}\n"
+CONNECT_STEP_SETUP
+"function theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n"
+" The custom\n"
+" code1\n"
+"}\n"
+"\n"
+"function theIdStepTheOptionNameOptionSelected() {\n"
+" The custom\n"
+" code2\n"
+"}\n"
+"\n"
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testReactionOptionNextStep() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::OptionSelected);
+ reaction->setOptionName("The option name");
+ reaction->setResponseType(Reaction::NextStep);
+ reaction->setNextStepId("Another step");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" step.addOption(ktutorial.newOption(\"The option name\"), \
+\"Another step\");\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::
+ testReactionOptionNextStepWithoutOptionNameOrStepId() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::OptionSelected);
+ reaction->setResponseType(Reaction::NextStep);
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" //Error: Option without name!\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+
+ reaction->setOptionName("The option name");
+
+ exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" //Error: Next step id not set!\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testReactionOptionCustomCode() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::OptionSelected);
+ reaction->setOptionName("The option name");
+ reaction->setResponseType(Reaction::CustomCode);
+ reaction->setCustomCode("The custom\ncode");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" step.addOption(ktutorial.newOption(\"The option name\"), self, \
+\"theIdStepTheOptionNameOptionSelected()\");\n"
+"}\n"
+CONNECT_STEP_SETUP
+"function theIdStepTheOptionNameOptionSelected() {\n"
+" The custom\n"
+" code\n"
+"}\n"
+"\n"
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::
+ testReactionOptionCustomCodeWithoutOptionNameOrCustomCode() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::OptionSelected);
+ reaction->setResponseType(Reaction::CustomCode);
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" //Error: Option without name!\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+
+ reaction->setOptionName("The option name");
+
+ exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" step.addOption(ktutorial.newOption(\"The option name\"), self, \
+\"theIdStepTheOptionNameOptionSelected()\");\n"
+"}\n"
+CONNECT_STEP_SETUP
+"function theIdStepTheOptionNameOptionSelected() {\n"
+" //Error: No code set!\n"
+"}\n"
+"\n"
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testReactionConditionNextStep() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ WaitForSignal* waitForSignal = new WaitForSignal();
+ waitForSignal->setEmitterName("The emitter name");
+ waitForSignal->setSignalName("theSignalName(Argument1Type, Argument2Type)");
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::ConditionMet);
+ reaction->setWaitFor(waitForSignal);
+ reaction->setResponseType(Reaction::NextStep);
+ reaction->setNextStepId("Another step");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" waitForTheSignalNameByTheEmitterName = \
+ktutorial.newWaitFor(\"WaitForSignal\");\n"
+" waitForTheSignalNameByTheEmitterName.setSignal(\
+ktutorial.findObject(\"The emitter name\"), \
+\"theSignalName(Argument1Type, Argument2Type)\");\n"
+" step.addWaitFor(waitForTheSignalNameByTheEmitterName, \"Another step\");\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::
+ testReactionConditionNextStepWithoutConditionOrStepId() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::ConditionMet);
+ reaction->setResponseType(Reaction::NextStep);
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" //Error: WaitFor not set!\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+
+ WaitForSignal* waitForSignal = new WaitForSignal();
+ waitForSignal->setEmitterName("The emitter name");
+ waitForSignal->setSignalName("theSignalName(Argument1Type, Argument2Type)");
+ reaction->setWaitFor(waitForSignal);
+
+ exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" //Error: Next step id not set!\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testReactionConditionCustomCode() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ WaitForSignal* waitForSignal = new WaitForSignal();
+ waitForSignal->setEmitterName("The emitter name");
+ waitForSignal->setSignalName("theSignalName(Argument1Type, Argument2Type)");
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::ConditionMet);
+ reaction->setWaitFor(waitForSignal);
+ reaction->setResponseType(Reaction::CustomCode);
+ reaction->setCustomCode("The custom\ncode");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" waitForTheSignalNameByTheEmitterName = \
+ktutorial.newWaitFor(\"WaitForSignal\");\n"
+" waitForTheSignalNameByTheEmitterName.setSignal(\
+ktutorial.findObject(\"The emitter name\"), \
+\"theSignalName(Argument1Type, Argument2Type)\");\n"
+" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \
+\"theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n"
+"}\n"
+CONNECT_STEP_SETUP
+"function theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n"
+" The custom\n"
+" code\n"
+"}\n"
+"\n"
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::
+ testReactionConditionCustomCodeWithoutConditionOrCustomCode() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::ConditionMet);
+ reaction->setResponseType(Reaction::CustomCode);
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" //Error: WaitFor not set!\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+
+ WaitForSignal* waitForSignal = new WaitForSignal();
+ waitForSignal->setEmitterName("The emitter name");
+ waitForSignal->setSignalName("theSignalName(Argument1Type, Argument2Type)");
+ reaction->setWaitFor(waitForSignal);
+
+ exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" waitForTheSignalNameByTheEmitterName = \
+ktutorial.newWaitFor(\"WaitForSignal\");\n"
+" waitForTheSignalNameByTheEmitterName.setSignal(\
+ktutorial.findObject(\"The emitter name\"), \
+\"theSignalName(Argument1Type, Argument2Type)\");\n"
+" step.addWaitFor(waitForTheSignalNameByTheEmitterName, self, \
+\"theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet()\");\n"
+"}\n"
+CONNECT_STEP_SETUP
+"function theIdStepWaitForTheSignalNameByTheEmitterNameConditionMet() {\n"
+" //Error: No code set!\n"
+"}\n"
+"\n"
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testWaitForEvent() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ WaitForEvent* waitForEvent = new WaitForEvent();
+ waitForEvent->setReceiverName("The receiver name");
+ waitForEvent->setEventName("TheEventName");
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::ConditionMet);
+ reaction->setWaitFor(waitForEvent);
+ reaction->setResponseType(Reaction::NextStep);
+ reaction->setNextStepId("Another step");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" waitForTheEventNameInTheReceiverName = \
+ktutorial.newWaitFor(\"WaitForEvent\");\n"
+" waitForTheEventNameInTheReceiverName.setEvent(\
+ktutorial.findObject(\"The receiver name\"), \
+\"TheEventName\");\n"
+" step.addWaitFor(waitForTheEventNameInTheReceiverName, \"Another step\");\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testWaitForEventWithoutReceiverNameOrEventName() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ WaitForEvent* waitForEvent = new WaitForEvent();
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::ConditionMet);
+ reaction->setWaitFor(waitForEvent);
+ reaction->setResponseType(Reaction::NextStep);
+ reaction->setNextStepId("Another step");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ QString expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" //Error: WaitForEvent without receiver name!\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+
+ waitForEvent->setReceiverName("The receiver name");
+
+ exportedTutorial = exporter.exportTutorial(&tutorial);
+
+ expected =
+TUTORIAL_EMPTY_INFORMATION_CODE
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_START_CODE
+"function theIdStepSetup(step) {\n"
+" //Error: WaitForEvent without event name!\n"
+"}\n"
+CONNECT_STEP_SETUP
+STEP_WITH_ID_THE_ID_AND_EMPTY_TEXT_END_CODE;
+
+ QCOMPARE(exportedTutorial, expected);
+}
+
+void JavascriptExporterTest::testWaitForSignal() {
+ Tutorial tutorial;
+ Step* step = new Step();
+ step->setId("The id");
+ tutorial.addStep(step);
+
+ WaitForSignal* waitForSignal = new WaitForSignal();
+ waitForSignal->setEmitterName("The emitter name");
+ waitForSignal->setSignalName("theSignalName(Argument1Type, Argument2Type)");
+
+ Reaction* reaction = new Reaction();
+ reaction->setTriggerType(Reaction::ConditionMet);
+ reaction->setWaitFor(waitForSignal);
+ reaction->setResponseType(Reaction::NextStep);
+ reaction->setNextStepId("Another step");
+ step->addReaction(reaction);
+
+ JavascriptExporter exporter;
+ QString exportedTutorial = exporter.e...
[truncated message content] |